# This is a BitKeeper generated patch for the following project: # Project Name: Linux kernel tree # This patch format is intended for GNU patch command version 2.5 or higher. # This patch includes the following deltas: # ChangeSet v2.5.70 -> 1.1316 # drivers/i2c/chips/w83781d.c 1.7 -> 1.9 # drivers/base/sys.c 1.16 -> 1.17 # drivers/net/8139too.c 1.55 -> 1.57 # drivers/hotplug/cpqphp_core.c 1.17 -> 1.19 drivers/pci/hotplug/cpqphp_core.c (moved) # arch/ppc/boot/prep/vreset.c 1.7 -> 1.8 # include/asm-ppc64/smp.h 1.7 -> 1.8 # arch/m68k/lib/Makefile 1.4 -> 1.5 # drivers/hotplug/acpiphp_pci.c 1.4 -> 1.6 drivers/pci/hotplug/acpiphp_pci.c (moved) # include/linux/rocket.h 1.1 -> 1.2 drivers/char/rocket.h (moved) # include/asm-alpha/agp_backend.h 1.2 -> 1.3 # drivers/net/defxx.c 1.17 -> 1.18 # drivers/scsi/arm/oak.c 1.18 -> 1.19 # net/ipv4/netfilter/ip_conntrack_core.c 1.29 -> 1.30 # include/asm-i386/mpspec.h 1.12 -> 1.13 # drivers/mtd/maps/Makefile 1.8 -> 1.9 # drivers/hotplug/ibmphp_pci.c 1.6 -> 1.7 drivers/pci/hotplug/ibmphp_pci.c (moved) # drivers/mtd/devices/slram.c 1.6 -> 1.7 # include/linux/proc_fs.h 1.18 -> 1.22 # drivers/scsi/megaraid.c 1.45 -> 1.47 # Documentation/DocBook/kernel-api.tmpl 1.25 -> 1.26 # include/pcmcia/ds.h 1.10 -> 1.11 # arch/ppc64/kernel/signal.c 1.27 -> 1.28 # drivers/pci/search.c 1.3 -> 1.6 # fs/jffs2/compr_zlib.c 1.7 -> 1.8 # include/linux/mtd/cfi_endian.h 1.2 -> 1.3 # drivers/net/irda/nsc-ircc.c 1.23 -> 1.25 # include/linux/kernel.h 1.37 -> 1.38 # drivers/scsi/dpti.h 1.9 -> 1.10 # drivers/scsi/aic7xxx/aic79xx_core.c 1.24 -> 1.28 # include/asm-x86_64/smp.h 1.6 -> 1.8 # drivers/char/specialix_io8.h 1.2 -> 1.3 # drivers/mtd/devices/doc2000.c 1.5 -> 1.6 # drivers/scsi/imm.h 1.8 -> 1.10 # drivers/scsi/in2000.h 1.10 -> 1.11 # include/net/route.h 1.21 -> 1.22 # drivers/mtd/maps/cfi_flagadm.c 1.3 -> 1.4 # arch/ppc64/lib/Makefile 1.8 -> 1.9 # arch/arm/mach-sa1100/pfs168.c 1.12 -> 1.13 # arch/ppc/kernel/align.c 1.6 -> 1.7 # arch/alpha/kernel/head.S 1.2 -> 1.3 # include/asm-ppc/hardirq.h 1.19 -> 1.20 # arch/ppc/xmon/xmon.c 1.12 -> 1.13 # arch/ppc/8260_io/enet.c 1.8 -> 1.11 # drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped 1.10 -> 1.12 # include/asm-h8300/bug.h 1.1 -> 1.2 # drivers/usb/input/hid.h 1.24 -> 1.26 # drivers/mtd/devices/Makefile 1.4 -> 1.5 # drivers/char/esp.c 1.19 -> 1.20 # drivers/usb/media/konicawc.c 1.21 -> 1.22 # drivers/video/matrox/matroxfb_maven.c 1.12 -> 1.13 # net/ipv4/syncookies.c 1.13 -> 1.14 # net/llc/af_llc.c 1.41 -> 1.42 # drivers/scsi/ips.c 1.57 -> 1.58 # drivers/usb/misc/usblcd.c 1.8 -> 1.9 # arch/sparc64/boot/Makefile 1.8 -> 1.9 # net/ipx/ipx_proc.c 1.6 -> 1.7 # net/bluetooth/rfcomm/core.c 1.21 -> 1.22 # include/asm-ppc/processor.h 1.29 -> 1.31 # drivers/usb/input/kbtab.c 1.2 -> 1.3 # fs/jffs2/background.c 1.18 -> 1.19 # drivers/net/irda/toshoboe.c 1.17 -> 1.19 # kernel/rcupdate.c 1.4 -> 1.5 # arch/ppc/4xx_io/serial_sicc.c 1.9 -> 1.10 # include/sound/initval.h 1.9 -> 1.10 # sound/i2c/cs8427.c 1.6 -> 1.7 # drivers/usb/storage/protocol.c 1.9 -> 1.10 # fs/libfs.c 1.19 -> 1.20 # drivers/char/vme_scc.c 1.18 -> 1.20 # arch/x86_64/kernel/traps.c 1.21 -> 1.22 # fs/reiserfs/file.c 1.19 -> 1.20 # drivers/ide/ide-taskfile.c 1.18 -> 1.19 # drivers/scsi/fcal.h 1.7 -> 1.8 # drivers/media/video/cpia_usb.c 1.20 -> 1.21 # arch/um/drivers/daemon_kern.c 1.3 -> 1.4 # arch/x86_64/mm/fault.c 1.12 -> 1.13 # drivers/scsi/aic7xxx/aic7xxx_proc.c 1.10 -> 1.11 # sound/drivers/opl3/Makefile 1.12 -> 1.14 # drivers/net/ptifddi.c 1.4 -> (deleted) # arch/um/drivers/mcast_kern.c 1.4 -> 1.5 # sound/pci/Makefile 1.12 -> 1.14 # arch/arm/mach-sa1100/adsbitsy.c 1.16 -> 1.17 # net/ipv4/tcp_diag.c 1.8 -> 1.9 # kernel/ksyms.c 1.200 -> 1.201 # drivers/scsi/scsi_devinfo.h 1.1 -> 1.2 # arch/ppc/xmon/start.c 1.12 -> 1.14 # sound/pci/korg1212/korg1212.c 1.22 -> 1.23 # drivers/video/matrox/matroxfb_Ti3026.c 1.6 -> 1.7 # drivers/isdn/hardware/avm/avm_cs.c 1.7.1.1 -> 1.9 # sound/pci/ac97/ac97_patch.h 1.6 -> 1.7 # include/asm-ppc/uaccess.h 1.7 -> 1.8 # drivers/char/watchdog/i810-tco.c 1.16 -> 1.17 # drivers/mtd/nand/Makefile 1.6 -> 1.7 # include/linux/jffs2_fs_sb.h 1.9 -> 1.10 # arch/i386/kernel/cpu/cpufreq/powernow-k7.c 1.13 -> 1.14 # sound/ppc/tumbler.c 1.10 -> 1.12 # scripts/kconfig/lkc.h 1.3 -> 1.5 # arch/ppc/xmon/ppc-opc.c 1.3 -> 1.4 # drivers/mtd/nftlcore.c 1.43 -> 1.44 # drivers/net/pci-skeleton.c 1.21 -> 1.22 # drivers/scsi/g_NCR5380.h 1.8 -> 1.10 # include/asm-arm/dma-mapping.h 1.5 -> 1.6 # include/asm-arm/bug.h 1.2 -> 1.3 # arch/alpha/kernel/sys_sio.c 1.6 -> 1.7 # include/linux/aio.h 1.9 -> 1.10 # arch/ppc/mm/mem_pieces.c 1.5 -> 1.6 # include/asm-ia64/bug.h 1.1 -> 1.2 # arch/mips64/sgi-ip22/Makefile 1.6 -> 1.7 # include/linux/mtd/mtd.h 1.5 -> 1.6 # drivers/usb/class/usb-midi.c 1.17 -> 1.18 # drivers/char/isicom.c 1.18 -> 1.19 # drivers/char/Kconfig 1.13 -> 1.14 # drivers/scsi/scsi_pc98.c 1.2 -> 1.3 # drivers/video/Kconfig 1.22 -> 1.23 # drivers/net/bmac.c 1.15 -> 1.16 # include/linux/kobject.h 1.20 -> 1.21 # Documentation/sound/alsa/CMIPCI.txt 1.4 -> 1.5 # fs/jffs2/readinode.c 1.8 -> 1.9 # drivers/usb/storage/jumpshot.c 1.17 -> 1.18 # fs/jffs2/malloc.c 1.6 -> 1.7 # net/core/flow.c 1.2 -> 1.5 # drivers/atm/Makefile 1.19 -> 1.20 # net/sctp/associola.c 1.45 -> 1.46 # drivers/net/3c509.c 1.36 -> 1.37 # include/linux/timex.h 1.5 -> 1.6 # drivers/usb/net/cdc-ether.c 1.28 -> 1.30 # scripts/kconfig/qconf.cc 1.5 -> 1.7 # drivers/hotplug/cpcihp_zt5550.h 1.1 -> 1.2 drivers/pci/hotplug/cpcihp_zt5550.h (moved) # drivers/mtd/devices/mtdram.c 1.4 -> 1.5 # include/asm-arm/hardware.h 1.1 -> 1.2 # arch/x86_64/kernel/setup.c 1.14 -> 1.16 # sound/sparc/cs4231.c 1.10 -> 1.11 # arch/um/os-Linux/drivers/ethertap_kern.c 1.3 -> 1.4 # arch/ia64/sn/io/pciba.c 1.7 -> 1.8 # include/linux/mtd/pmc551.h 1.2 -> 1.3 # include/linux/matroxfb.h 1.1 -> 1.2 # drivers/net/net_init.c 1.12 -> 1.17 # drivers/scsi/fcal.c 1.10 -> 1.11 # drivers/block/ioctl.c 1.54 -> 1.55 # drivers/scsi/aha152x.c 1.30 -> 1.31 # drivers/serial/8250.c 1.28.1.8 -> 1.32 # sound/pci/ice1712/ice1712.h 1.7 -> 1.9 # drivers/scsi/hosts.c 1.64.1.1 -> 1.70 # lib/Makefile 1.22 -> 1.23 # drivers/usb/input/wacom.c 1.27 -> 1.28 # sound/core/hwdep.c 1.13 -> 1.14 # arch/i386/mach-generic/default.c 1.2 -> 1.3 # include/linux/i2c-id.h 1.11 -> 1.12 # drivers/net/skfp/skfddi.c 1.12 -> 1.13 # arch/i386/mach-visws/visws_apic.c 1.8 -> 1.9 # net/sctp/input.c 1.28 -> 1.29 # sound/arm/sa11xx-uda1341.c 1.11 -> 1.12 # arch/i386/lib/Makefile 1.11 -> 1.12 # fs/fat/dir.c 1.15 -> 1.17 # arch/arm/mach-sa1100/dma.c 1.3 -> 1.4 # sound/isa/sb/sb8_midi.c 1.5 -> 1.7 # arch/ppc/kernel/ppc_htab.c 1.13 -> 1.14 # drivers/base/core.c 1.68 -> 1.70 # net/ipv6/ip6_output.c 1.26 -> 1.30 # drivers/net/sb1000.c 1.19 -> 1.20 # drivers/scsi/aic7xxx/aic7xxx_pci.c 1.14 -> 1.17 # drivers/scsi/cpqfcTSinit.c 1.37 -> 1.38 # net/ipv4/ip_input.c 1.15 -> 1.16 # drivers/net/sk98lin/skproc.c 1.6 -> 1.7 # drivers/scsi/atp870u.h 1.9 -> 1.10 # net/llc/llc_conn.c 1.26 -> 1.28 # drivers/usb/serial/io_edgeport.c 1.44 -> 1.45 # drivers/scsi/aic7xxx/aiclib.h 1.8 -> 1.9 # arch/sparc64/lib/Makefile 1.10 -> 1.11 # drivers/base/init.c 1.3 -> 1.4 # arch/x86_64/lib/usercopy.c 1.5 -> 1.6 # arch/i386/kernel/irq.c 1.36 -> 1.37 # include/linux/raid/md.h 1.27 -> 1.29 # net/sctp/sm_statefuns.c 1.48 -> 1.49 # arch/s390/lib/Makefile 1.9 -> 1.10 # include/asm-i386/stat.h 1.3 -> 1.4 # arch/ppc/syslib/Makefile 1.5 -> 1.6 # Documentation/usb/proc_usb_info.txt 1.4 -> 1.5 # drivers/net/wireless/hermes.h 1.13 -> 1.14 # drivers/video/matrox/matroxfb_misc.h 1.2 -> 1.3 # drivers/scsi/aic7xxx/aic7xxx_osm.c 1.36.1.1 -> 1.42 # mm/page_alloc.c 1.158 -> 1.161 # drivers/scsi/scsi_proc.c 1.22 -> 1.25 # arch/ppc/8260_io/uart.c 1.18 -> 1.20 # arch/alpha/kernel/pci.c 1.31 -> 1.32 # include/asm-ppc64/pci-bridge.h 1.6 -> 1.7 # arch/ppc/syslib/prom.c 1.19 -> 1.20 # sound/pci/cs46xx/cs46xx_lib.c 1.33 -> 1.34 # net/ipv6/ipv6_sockglue.c 1.19 -> 1.20 # arch/arm/mm/init.c 1.21 -> 1.22 # drivers/scsi/sun3_scsi.h 1.6 -> 1.7 # include/linux/if_ec.h 1.4 -> 1.5 # drivers/char/dz.c 1.20 -> 1.22 # net/x25/x25_timer.c 1.10 -> 1.12 # net/ipv6/sysctl_net_ipv6.c 1.5 -> 1.6 # arch/mips/lib/Makefile 1.6 -> 1.7 # include/net/ipx.h 1.10 -> 1.11 # arch/i386/kernel/smp.c 1.31 -> 1.32 # arch/m68knommu/platform/68328/entry.S 1.4 -> 1.5 # drivers/serial/mcfserial.h 1.2 -> 1.3 # drivers/base/interface.c 1.14 -> 1.15 # net/ipv6/datagram.c 1.10 -> 1.11 # arch/alpha/kernel/core_marvel.c 1.11 -> 1.12 # drivers/scsi/arm/cumana_1.c 1.17 -> 1.18 # net/llc/llc_proc.c 1.10 -> 1.11 # drivers/macintosh/via-cuda.c 1.8 -> 1.9 # arch/ia64/sn/io/sn2/pci_bus_cvlink.c 1.2 -> 1.3 # Documentation/sound/alsa/ALSA-Configuration.txt 1.5 -> 1.9 # drivers/acorn/char/Makefile 1.13 -> 1.14 # net/x25/x25_out.c 1.8 -> 1.9 # include/linux/init_task.h 1.25 -> 1.26 # drivers/scsi/sun3_NCR5380.c 1.15.1.1 -> 1.17 # include/linux/serialP.h 1.8 -> 1.9 # arch/mips64/mips-boards/generic/pci.c 1.5 -> 1.6 # drivers/net/tokenring/skisa.c 1.9 -> 1.10 # fs/jffs2/erase.c 1.10 -> 1.11 # include/linux/sched.h 1.148 -> 1.150 # kernel/fork.c 1.122 -> 1.123 # net/sunrpc/svcsock.c 1.48 -> 1.50 # include/linux/ptrace.h 1.9 -> 1.10 # sound/isa/als100.c 1.13 -> 1.14 # arch/i386/kernel/cpu/cpufreq/acpi.c 1.6 -> 1.7 # sound/pci/ice1712/delta.c 1.8 -> 1.9 # drivers/macintosh/nvram.c 1.6 -> 1.7 # drivers/net/Space.c 1.20 -> 1.21 # drivers/block/ll_rw_blk.c 1.170 -> 1.173 # kernel/sysctl.c 1.42 -> 1.45 # drivers/scsi/ibmmca.c 1.18 -> 1.19 # sound/core/seq/seq_memory.c 1.7 -> 1.8 # fs/jffs2/os-linux.h 1.9 -> 1.10 # net/atm/mpc.h 1.1 -> 1.2 # net/ipv4/xfrm4_tunnel.c 1.6 -> 1.7 # include/linux/writeback.h 1.20 -> 1.21 # drivers/hotplug/ibmphp.h 1.7 -> 1.8 drivers/pci/hotplug/ibmphp.h (moved) # include/linux/mtd/nand_ids.h 1.1 -> (deleted) # drivers/video/Makefile 1.84 -> 1.85 # drivers/usb/image/hpusbscsi.h 1.11 -> 1.12 # include/asm-ppc64/thread_info.h 1.7 -> 1.8 # arch/v850/kernel/rte_cb_leds.c 1.3 -> 1.4 # include/net/tcp.h 1.39 -> 1.44 # drivers/scsi/dtc.h 1.8 -> 1.9 # drivers/mtd/maps/pcmciamtd.c 1.3 -> 1.5 # include/linux/serial_core.h 1.23 -> 1.24 # net/ipv4/xfrm4_input.c 1.5 -> 1.6 # arch/arm/mach-sa1100/badge4.c 1.12 -> 1.13 # drivers/base/platform.c 1.9 -> 1.10 # arch/v850/kernel/head.S 1.2 -> 1.3 # lib/zlib_deflate/deflate.c 1.1 -> 1.13 # drivers/s390/net/lcs.c 1.14 -> 1.15 # sound/core/seq/seq_clientmgr.c 1.17 -> 1.18 # drivers/serial/amba.c 1.15.1.6 -> 1.20 # sound/isa/cs423x/cs4236.c 1.14 -> 1.17 # drivers/net/amd8111e.h 1.1 -> 1.2 # scripts/docproc.c 1.3 -> 1.4 # drivers/net/tlan.c 1.22 -> 1.24 # sound/oss/esssolo1.c 1.27 -> 1.28 # fs/dcache.c 1.56 -> 1.57 # drivers/ieee1394/sbp2.c 1.31 -> 1.34 # net/sctp/endpointola.c 1.23 -> 1.24 # fs/attr.c 1.15 -> 1.17 # Documentation/vm/hugetlbpage.txt 1.5 -> 1.6 # include/asm-i386/thread_info.h 1.11 -> 1.12 # net/ipv4/af_inet.c 1.50 -> 1.54 # mm/vmscan.c 1.158 -> 1.159 # fs/smbfs/proc.c 1.29 -> 1.30 # sound/pci/rme9652/hammerfall_mem.c 1.13 -> 1.15 # arch/i386/kernel/cpu/cpufreq/powernow-k6.c 1.14 -> 1.15 # include/net/llc_c_ev.h 1.7 -> 1.8 # include/net/rose.h 1.2 -> 1.3 # drivers/scsi/NCR_D700.c 1.10 -> 1.12 # fs/proc/proc_misc.c 1.77 -> 1.78 # drivers/macintosh/via-pmu68k.c 1.9 -> 1.10 # drivers/serial/sa1100.c 1.16.1.9 -> 1.21 # sound/isa/cmi8330.c 1.14 -> 1.15 # arch/mips/kernel/irq.c 1.9 -> 1.10 # include/asm-ppc64/bug.h 1.2 -> 1.3 # lib/zlib_inflate/inffast.h 1.1 -> 1.2 # net/sctp/sm_make_chunk.c 1.46 -> 1.47 # drivers/scsi/dc395x.c 1.2 -> 1.6 # net/ax25/ax25_dev.c 1.7 -> 1.8 # drivers/i2c/i2c-core.c 1.38 -> 1.39 # arch/x86_64/kernel/apic.c 1.17 -> 1.18 # drivers/net/sk98lin/skge.c 1.17 -> 1.19 # arch/ia64/hp/common/sba_iommu.c 1.20 -> 1.21 # include/asm-i386/bug.h 1.2 -> 1.3 # sound/core/rawmidi.c 1.24 -> 1.25 # include/linux/genhd.h 1.53 -> 1.55 # drivers/cpufreq/proc_intf.c 1.2 -> 1.3 # arch/i386/Kconfig 1.57 -> 1.58 # drivers/sbus/char/aurora.c 1.24 -> 1.26 # drivers/video/matrox/matroxfb_crtc2.h 1.3 -> 1.4 # sound/core/control.c 1.20.1.1 -> 1.23 # drivers/base/node.c 1.11 -> 1.12 # drivers/scsi/53c700.c 1.29 -> 1.33 # arch/v850/kernel/ma.c 1.2 -> 1.3 # drivers/hotplug/ibmphp_ebda.c 1.9 -> 1.10 drivers/pci/hotplug/ibmphp_ebda.c (moved) # drivers/hotplug/cpci_hotplug.h 1.1 -> 1.2 drivers/pci/hotplug/cpci_hotplug.h (moved) # arch/x86_64/kernel/x8664_ksyms.c 1.14 -> 1.15 # drivers/atm/he.c 1.7 -> 1.12 # net/x25/x25_proc.c 1.3 -> 1.4 # include/linux/if_pppox.h 1.9 -> 1.10 # drivers/sbus/char/envctrl.c 1.14 -> 1.15 # net/ax25/ax25_in.c 1.9 -> 1.11 # drivers/mtd/maps/cstm_mips_ixx.c 1.4 -> 1.5 # include/asm-um/processor-ppc.h 1.1 -> 1.2 # net/ipv4/udp.c 1.40 -> 1.42 # net/ipx/af_ipx.c 1.34 -> 1.36 # sound/isa/opti9xx/opti92x-ad1848.c 1.13.1.2 -> 1.18 # fs/jbd/journal.c 1.32 -> 1.33 # arch/v850/kernel/process.c 1.5 -> 1.7 # drivers/mtd/maps/octagon-5066.c 1.6 -> 1.7 # drivers/char/rocket_int.h 1.4 -> 1.6 # arch/x86_64/lib/Makefile 1.10 -> 1.11 # arch/ppc64/boot/zlib.c 1.2 -> 1.4 # fs/devfs/base.c 1.90 -> 1.91 # init/main.c 1.99 -> 1.102 # drivers/scsi/fd_mcs.h 1.7 -> 1.8 # arch/ppc/boot/simple/misc-embedded.c 1.7 -> 1.8 # drivers/net/wireless/hermes.c 1.12 -> 1.13 # arch/i386/kernel/Makefile 1.41 -> 1.42 # drivers/scsi/g_NCR5380.c 1.18 -> 1.19 # drivers/usb/media/ultracam.c 1.12 -> 1.13 # sound/core/init.c 1.16.1.1 -> 1.20 # include/linux/signal.h 1.11 -> 1.13 # include/net/bluetooth/l2cap.h 1.7 -> 1.8 # drivers/mtd/maps/tqm8xxl.c 1.2 -> 1.3 # net/bluetooth/af_bluetooth.c 1.18 -> 1.19 # drivers/scsi/dc390.h 1.6 -> 1.7 # arch/ppc/mm/pgtable.c 1.11 -> 1.12 # fs/jffs2/nodemgmt.c 1.8 -> 1.9 # arch/sparc64/kernel/Makefile 1.24 -> 1.25 # drivers/mtd/maps/impa7.c 1.2 -> 1.3 # drivers/mtd/Kconfig 1.1 -> 1.2 # drivers/net/ixgb/ixgb_main.c 1.5 -> 1.6 # drivers/scsi/scsi_sysfs.c 1.16 -> 1.21 # net/sctp/transport.c 1.20 -> 1.21 # arch/m68knommu/kernel/ints.c 1.3 -> (deleted) # include/asm-v850/bug.h 1.1 -> 1.2 # include/asm-alpha/ptrace.h 1.1 -> 1.3 # include/linux/cpu.h 1.6 -> 1.7 # drivers/serial/sunsu.c 1.30.1.6 -> 1.35 # drivers/md/raid5.c 1.67 -> 1.73 # include/asm-v850/sim.h 1.3 -> 1.4 # arch/ppc/platforms/residual.c 1.9 -> 1.10 # include/net/bluetooth/sco.h 1.1 -> 1.2 # fs/partitions/mac.c 1.4 -> 1.5 # sound/drivers/opl3/opl3_lib.c 1.8 -> 1.9 # include/asm-m68knommu/bug.h 1.1 -> 1.2 # lib/zlib_inflate/inffixed.h 1.1 -> 1.2 # net/sctp/output.c 1.30 -> 1.31 # arch/ppc/kernel/traps.c 1.19 -> 1.23 # drivers/char/synclinkmp.c 1.13 -> 1.14 # drivers/serial/anakin.c 1.12.1.4 -> 1.15 # kernel/cpufreq.c 1.32 -> 1.34 # net/atm/atm_misc.c 1.3 -> 1.4 # drivers/char/cyclades.c 1.22 -> 1.23 # sound/isa/cs423x/cs4231_lib.c 1.15 -> 1.16 # drivers/i2c/Kconfig 1.8 -> 1.9 # drivers/usb/image/microtek.h 1.7 -> 1.8 # drivers/char/dz.h 1.1 -> 1.3 # include/linux/xfrm.h 1.9 -> 1.11 # drivers/char/watchdog/amd7xx_tco.c 1.5 -> 1.6 # arch/m68knommu/kernel/process.c 1.2 -> 1.3 # include/asm-ppc/thread_info.h 1.7 -> 1.8 # include/linux/istallion.h 1.2 -> 1.3 # arch/ppc/mm/init.c 1.29 -> 1.30 # net/ipv6/xfrm6_policy.c 1.6 -> 1.7 # drivers/net/fc/iph5526.c 1.22 -> 1.24 # include/linux/blkdev.h 1.105 -> 1.108 # include/net/ip6_route.h 1.8 -> 1.9 # drivers/scsi/NCR53C9x.c 1.22 -> 1.23 # include/video/edid.h 1.1 -> 1.2 # kernel/time.c 1.11 -> 1.12 # drivers/mtd/maps/fortunet.c 1.2 -> 1.3 # drivers/block/cciss_scsi.c 1.14 -> 1.15 # include/asm-ppc/ocp.h 1.2 -> 1.3 # drivers/message/fusion/mptbase.c 1.10 -> 1.12 # drivers/block/nbd.c 1.55 -> 1.56 # include/linux/udp.h 1.6 -> 1.7 # drivers/scsi/wd33c93.h 1.5 -> 1.6 # drivers/usb/serial/safe_serial.c 1.13 -> 1.14 # sound/isa/Makefile 1.11 -> 1.12 # drivers/acorn/char/defkeymap-acorn.map 1.1 -> (deleted) # drivers/serial/core.c 1.61 -> 1.62 # drivers/scsi/3w-xxxx.h 1.21 -> 1.22 # drivers/ieee1394/ieee1394_core.c 1.30 -> 1.32 # sound/isa/ad1816a/ad1816a.c 1.8 -> 1.9 # sound/pci/ice1712/ews.c 1.8 -> 1.9 # scripts/kconfig/mconf.c 1.5 -> 1.6 # lib/zlib_deflate/defutil.h 1.1 -> 1.3 # arch/m68knommu/platform/68VZ328/de2/config.c 1.3 -> 1.4 # drivers/base/bus.c 1.47 -> 1.48 # drivers/net/rrunner.c 1.16 -> 1.17 # drivers/media/video/bw-qcam.c 1.11 -> 1.12 # Documentation/00-INDEX 1.8 -> 1.9 # drivers/net/ethertap.c 1.7 -> 1.8 # drivers/scsi/NCR5380.c 1.17 -> 1.18 # net/bluetooth/sco.c 1.17 -> 1.19 # drivers/net/wireless/Kconfig 1.6 -> 1.9 # kernel/softirq.c 1.39 -> 1.40 # net/ipv4/Makefile 1.18 -> 1.19 # scripts/kconfig/symbol.c 1.4 -> 1.12 # net/x25/x25_subr.c 1.9 -> 1.11 # net/key/af_key.c 1.37 -> 1.41 # drivers/mtd/maps/sa1100-flash.c 1.10 -> 1.12 # drivers/scsi/sr.c 1.78 -> 1.80 # drivers/scsi/aha1740.c 1.15 -> 1.16 # arch/x86_64/kernel/smp.c 1.15 -> 1.16 # arch/i386/pci/i386.c 1.14 -> 1.15 # include/asm-x86_64/uaccess.h 1.9 -> 1.10 # include/linux/ethtool.h 1.14 -> 1.16 # lib/zlib_deflate/deftree.c 1.1 -> 1.6 # drivers/net/irda/irtty.c 1.18 -> 1.20 # net/bridge/br_input.c 1.12 -> 1.13 # drivers/scsi/scsi.h 1.79 -> 1.83 # arch/v850/kernel/rte_mb_a_pci.c 1.6 -> 1.7 # fs/jffs2/wbuf.c 1.6 -> 1.7 # include/asm-generic/percpu.h 1.6 -> 1.7 # drivers/pcmcia/cs.c 1.28 -> 1.29 # include/linux/fs.h 1.248 -> 1.250 # drivers/video/sa1100fb.c 1.28 -> 1.29 # drivers/usb/storage/usb.c 1.60 -> 1.64 # drivers/net/tokenring/abyss.c 1.8 -> 1.9 # fs/fat/file.c 1.19 -> 1.20 # arch/ppc/kernel/module.c 1.8 -> 1.9 # drivers/scsi/t128.h 1.7 -> 1.8 # arch/i386/kernel/entry.S 1.62 -> 1.63 # Documentation/kobject.txt 1.6 -> 1.7 # drivers/usb/media/ibmcam.c 1.18 -> 1.19 # net/ax25/ax25_std_timer.c 1.5 -> 1.7 # drivers/mtd/chips/Makefile 1.6 -> 1.7 # include/linux/trdevice.h 1.3 -> 1.4 # include/asm-x86_64/apicdef.h 1.2 -> 1.3 # drivers/md/dm-ioctl.c 1.22 -> 1.23 # drivers/sgi/char/sgiserial.c 1.14 -> 1.15 # drivers/usb/image/scanner.c 1.59 -> 1.62 # drivers/hotplug/ibmphp_hpc.c 1.10 -> 1.11 drivers/pci/hotplug/ibmphp_hpc.c (moved) # arch/ppc64/defconfig 1.27 -> 1.28 # arch/mips/arc/Makefile 1.4 -> 1.5 # fs/jffs2/gc.c 1.12 -> 1.13 # include/net/sctp/sctp.h 1.37 -> 1.38 # drivers/scsi/aic7xxx/aic79xx_osm_pci.c 1.7 -> 1.8 # arch/arm/mach-sa1100/generic.c 1.18 -> 1.19 # drivers/mtd/chips/amd_flash.c 1.5 -> 1.6 # include/asm-i386/node.h 1.3 -> 1.4 # drivers/char/ser_a2232.c 1.10 -> 1.12 # drivers/net/pcnet32.c 1.34 -> 1.35 # net/ipv4/tcp.c 1.40 -> 1.43 # drivers/char/n_hdlc.c 1.15 -> 1.16 # Documentation/scsi/aic7xxx.txt 1.7 -> 1.8 # lib/zlib_inflate/infcodes.h 1.1 -> 1.3 # net/ipv6/netfilter/ip6_queue.c 1.10 -> 1.12 # Documentation/filesystems/proc.txt 1.14 -> 1.15 # drivers/pci/pci.c 1.53 -> 1.55 # arch/m68knommu/kernel/Makefile 1.4 -> 1.5 # arch/m68knommu/lib/Makefile 1.2 -> 1.3 # arch/ppc/8xx_io/enet.c 1.10 -> 1.13 # drivers/net/Makefile 1.61 -> 1.63 # arch/alpha/kernel/smp.c 1.35 -> 1.36 # drivers/mtd/chips/cfi_cmdset_0001.c 1.7 -> 1.8 # include/linux/fcdevice.h 1.3 -> 1.4 # net/ipv4/ip_fragment.c 1.8 -> 1.10 # drivers/mtd/nand/nand_ecc.c 1.4 -> 1.5 # drivers/ide/ide.c 1.66 -> 1.71 # drivers/md/md.c 1.169 -> 1.173 # arch/x86_64/ia32/Makefile 1.14 -> 1.16 # arch/alpha/kernel/core_titan.c 1.16 -> 1.17 # net/atm/proc.c 1.15 -> 1.17 # sound/oss/via82cxxx_audio.c 1.27 -> 1.28 # drivers/serial/clps711x.c 1.12.1.5 -> 1.15 # net/unix/garbage.c 1.7 -> 1.8 # drivers/mtd/chips/Kconfig 1.1 -> 1.3 # drivers/scsi/ncr53c8xx.c 1.27.1.1 -> 1.29 # sound/Makefile 1.16 -> 1.17 # net/ipv4/ip_sockglue.c 1.16 -> 1.17 # drivers/scsi/advansys.c 1.33 -> 1.34 # drivers/ieee1394/ieee1394.h 1.6 -> 1.7 # drivers/scsi/aic7xxx/aic7xxx_osm_pci.c 1.8 -> 1.9 # drivers/mtd/maps/vmax301.c 1.6 -> 1.7 # include/asm-ppc/module.h 1.7 -> 1.8 # arch/ppc/boot/lib/zlib.c 1.4 -> 1.6 # drivers/mtd/devices/doc2001.c 1.4 -> 1.5 # net/ipv6/icmp.c 1.32 -> 1.34 # kernel/kmod.c 1.27 -> 1.28 # drivers/net/wireless/orinoco.h 1.12 -> 1.13 # Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl 1.8 -> 1.10 # sound/usb/usbmixer.c 1.12.1.1 -> 1.15 # include/linux/wanrouter.h 1.7 -> 1.8 # drivers/usb/media/se401.c 1.36 -> 1.37 # include/asm-ia64/pgtable.h 1.18 -> 1.19 # arch/ppc/platforms/gemini_pci.c 1.7 -> 1.8 # mm/bootmem.c 1.16 -> 1.17 # arch/mips/au1000/common/serial.c 1.16 -> 1.18 # drivers/usb/serial/visor.c 1.61 -> 1.62 # drivers/net/wan/lmc/lmc_debug.c 1.3 -> 1.4 # arch/i386/kernel/mpparse.c 1.42 -> 1.43 # net/ipv6/reassembly.c 1.12 -> 1.16 # drivers/isdn/hisax/sedlbauer_cs.c 1.8 -> 1.9 # include/sound/sndmagic.h 1.11 -> 1.12 # drivers/mtd/chips/map_ram.c 1.5 -> 1.6 # include/asm-parisc/thread_info.h 1.2 -> 1.3 # fs/jffs2/read.c 1.6 -> 1.7 # fs/jffs2/compr.c 1.4 -> 1.5 # net/irda/ircomm/ircomm_tty.c 1.21 -> 1.22 # net/irda/af_irda.c 1.43 -> 1.45 # drivers/usb/media/ov511.c 1.44 -> 1.45 # drivers/net/wan/lmc/lmc_main.c 1.14 -> 1.16 # drivers/scsi/hosts.h 1.63 -> 1.67 # drivers/base/cpu.c 1.11 -> 1.13 # drivers/scsi/NCR53C9x.h 1.7 -> 1.8 # drivers/char/pty.c 1.17 -> 1.18 # arch/v850/kernel/rte_cb_multi.c 1.5 -> 1.6 # drivers/usb/misc/emi26.c 1.7 -> 1.8 # net/sctp/outqueue.c 1.34 -> 1.35 # drivers/video/i810/i810_main.c 1.9 -> 1.10 # arch/ppc/boot/common/mpc10x_memory.c 1.3 -> 1.4 # include/linux/serial167.h 1.3 -> 1.4 # drivers/tc/zs.h 1.3 -> 1.4 # net/ipv4/tcp_ipv4.c 1.57 -> 1.59 # fs/reiserfs/inode.c 1.77 -> 1.78 # drivers/ieee1394/ieee1394_transactions.c 1.11 -> 1.12 # drivers/message/fusion/linux_compat.h 1.8 -> 1.9 # include/asm-um/thread_info.h 1.3 -> 1.4 # fs/jffs2/super.c 1.23 -> 1.24 # fs/char_dev.c 1.18 -> 1.20 # drivers/hotplug/acpiphp_glue.c 1.10 -> 1.13 drivers/pci/hotplug/acpiphp_glue.c (moved) # arch/i386/kernel/io_apic.c 1.67 -> 1.69 # net/core/filter.c 1.4 -> 1.6 # net/atm/lec.h 1.5 -> 1.6 # sound/core/pcm_native.c 1.30.1.1 -> 1.36 # arch/sparc64/defconfig 1.86 -> 1.87 # drivers/usb/media/vicam.c 1.36 -> 1.37 # drivers/scsi/scsi_devinfo.c 1.1 -> 1.2 # sound/pci/ice1712/ice1712.c 1.13 -> 1.16 # sound/pci/rme9652/hdsp.c 1.17 -> 1.18 # scripts/kconfig/lkc_proto.h 1.1 -> 1.3 # mm/filemap.c 1.193 -> 1.197 # include/asm-h8300/thread_info.h 1.1 -> 1.2 # drivers/char/ip2/i2lib.h 1.4 -> 1.5 # arch/m68knommu/platform/5206e/config.c 1.3 -> 1.4 # net/ipv4/netfilter/ipt_ULOG.c 1.8 -> 1.9 # fs/namei.c 1.72 -> 1.74 # net/decnet/dn_nsp_in.c 1.10 -> 1.12 # drivers/usb/serial/whiteheat.c 1.37 -> 1.38 # Documentation/kbuild/kconfig-language.txt 1.2 -> 1.3 # sound/isa/sb/emu8000.c 1.9 -> 1.10 # net/ax25/ax25_ip.c 1.7 -> 1.8 # arch/sparc/prom/console.c 1.4 -> 1.5 # drivers/char/agp/generic.c 1.51 -> 1.52 # drivers/mtd/chips/chipreg.c 1.5 -> 1.6 # drivers/char/pcmcia/synclink_cs.c 1.16 -> 1.18 # drivers/pci/pci.h 1.4 -> 1.8 # drivers/hotplug/cpqphp_ctrl.c 1.11 -> 1.12 drivers/pci/hotplug/cpqphp_ctrl.c (moved) # arch/h8300/lib/Makefile 1.1 -> 1.2 # drivers/mtd/maps/ceiva.c 1.3 -> 1.4 # drivers/ide/pci/cs5530.c 1.11 -> 1.12 # drivers/acorn/char/keyb_arc.c 1.5 -> (deleted) # include/linux/fddidevice.h 1.2 -> 1.3 # net/socket.c 1.64 -> 1.65 # include/asm-i386/mach-generic/mach_apic.h 1.2 -> 1.3 # sound/pci/Kconfig 1.5 -> 1.7 # drivers/usb/media/dsbr100.c 1.16 -> 1.17 # arch/sh/kernel/irq.c 1.11 -> 1.12 # drivers/char/synclink.c 1.35 -> 1.36 # drivers/scsi/gdth.h 1.12 -> 1.13 # fs/smbfs/sock.c 1.14 -> 1.15 # include/asm-alpha/string.h 1.1 -> 1.2 # drivers/scsi/aic7xxx/aic7xxx_osm.h 1.44 -> 1.49 # arch/mips/ddb5476/pci.c 1.8 -> 1.9 # net/netrom/nr_in.c 1.5 -> 1.7 # drivers/scsi/sr.h 1.9 -> 1.10 # scripts/kconfig/expr.c 1.1 -> 1.4 # drivers/net/e1000/e1000_main.c 1.70 -> 1.71 # arch/arm/mach-pxa/lubbock.c 1.10 -> 1.11 # ipc/sem.c 1.18 -> 1.19 # drivers/net/sunqe.c 1.14 -> 1.17 # drivers/char/hw_random.c 1.10 -> 1.11 # sound/pci/ac97/ac97_codec.c 1.35 -> 1.40 # include/sound/version.h 1.53 -> 1.59 # fs/ncpfs/sock.c 1.14 -> 1.15 # drivers/hotplug/pci_hotplug.h 1.7 -> 1.8 drivers/pci/hotplug/pci_hotplug.h (moved) # arch/v850/as85ep1-rom.ld 1.1 -> 1.2 # drivers/net/irda/sa1100_ir.c 1.11 -> 1.13 # drivers/net/irda/w83977af_ir.c 1.19 -> 1.21 # drivers/base/base.h 1.26 -> 1.27 # arch/i386/kernel/dmi_scan.c 1.34 -> 1.35 # drivers/scsi/fd_mcs.c 1.13 -> 1.14 # sound/drivers/mpu401/mpu401_uart.c 1.16 -> 1.17 # fs/proc/proc_tty.c 1.6 -> 1.7 # include/linux/sysfs.h 1.26 -> 1.27 # arch/mips/dec/prom/Makefile 1.6 -> 1.7 # include/linux/ide.h 1.53 -> 1.56 # fs/exec.c 1.84 -> 1.85 # drivers/scsi/nsp32.c 1.11 -> 1.13 # drivers/mtd/mtdblock.c 1.43 -> 1.44 # arch/cris/drivers/lpslave/e100lpslavenet.c 1.5 -> 1.6 # include/asm-v850/thread_info.h 1.2 -> 1.3 # drivers/usb/storage/transport.c 1.71 -> 1.76 # drivers/scsi/aacraid/linit.c 1.18 -> 1.19 # drivers/serial/sunsab.c 1.27 -> 1.29 # sound/pci/ice1712/Makefile 1.5 -> 1.8 # drivers/mtd/maps/pci.c 1.2 -> 1.3 # include/linux/isicom.h 1.3 -> 1.4 # fs/eventpoll.c 1.19 -> 1.21 # net/llc/llc_main.c 1.28 -> 1.29 # include/net/snmp.h 1.7 -> 1.8 # arch/mips/mips-boards/generic/pci.c 1.7 -> 1.8 # include/linux/mtd/map.h 1.6 -> 1.7 # drivers/hotplug/acpiphp_res.c 1.2 -> 1.3 drivers/pci/hotplug/acpiphp_res.c (moved) # include/linux/mtd/cfi.h 1.6 -> 1.8 # net/ipv6/raw.c 1.29 -> 1.30 # arch/arm/kernel/bios32.c 1.22 -> 1.23 # include/asm-alpha/unaligned.h 1.1 -> 1.2 # kernel/signal.c 1.85 -> 1.86 # drivers/usb/storage/transport.h 1.23 -> 1.26 # drivers/usb/image/scanner.h 1.35 -> 1.36 # drivers/scsi/cpqfcTS.h 1.8 -> 1.9 # arch/sparc64/solaris/timod.c 1.14 -> 1.15 # drivers/scsi/pcmcia/nsp_cs.h 1.9 -> 1.10 # drivers/usb/storage/initializers.c 1.5 -> 1.6 # include/net/irda/ircomm_tty.h 1.7 -> 1.8 # include/asm-ppc64/paca.h 1.7 -> 1.8 # drivers/char/pcxx.h 1.2 -> 1.3 # net/ipv6/proc.c 1.14 -> 1.16 # drivers/net/irda/ali-ircc.c 1.19 -> 1.21 # drivers/usb/misc/auerswald.c 1.31 -> 1.32 # net/atm/br2684.c 1.2 -> 1.3 # drivers/message/fusion/mptscsih.c 1.23 -> 1.24 # drivers/scsi/atp870u.c 1.20 -> 1.21 # sound/isa/dt019x.c 1.13 -> 1.14 # sound/oss/awe_wave.c 1.12 -> 1.13 # drivers/mtd/devices/Kconfig 1.1 -> 1.3 # drivers/char/sx.c 1.30 -> 1.32 # net/netsyms.c 1.77 -> 1.80 # net/ipv4/netfilter/ipfwadm_core.c 1.16 -> 1.17 # drivers/mtd/maps/dc21285.c 1.5 -> 1.6 # drivers/ide/setup-pci.c 1.13 -> 1.15 # drivers/ide/ide-disk.c 1.44 -> 1.46 # include/linux/pci_ids.h 1.101 -> 1.102 # drivers/usb/serial/usb-serial.c 1.78 -> 1.80 # drivers/hotplug/Kconfig 1.7 -> 1.8 drivers/pci/hotplug/Kconfig (moved) # include/linux/irq.h 1.6 -> 1.7 # sound/core/pcm_lib.c 1.19 -> 1.21 # sound/pci/ymfpci/ymfpci.c 1.11 -> 1.12 # drivers/macintosh/macserial.h 1.6 -> 1.7 # sound/pci/trident/trident_synth.c 1.5 -> 1.6 # drivers/sbus/char/bbc_envctrl.c 1.4 -> 1.5 # include/scsi/sg.h 1.11 -> 1.12 # drivers/net/ptifddi_asm.h 1.1 -> (deleted) # arch/m68knommu/vmlinux.lds.S 1.8 -> 1.9 # include/asm-i386/mach-numaq/mach_apic.h 1.17 -> 1.18 # drivers/usb/input/hid-input.c 1.17 -> 1.19 # include/asm-ppc/system.h 1.18 -> 1.19 # include/asm-alpha/unistd.h 1.18 -> 1.20 # scripts/kconfig/qconf.h 1.3 -> 1.4 # arch/arm/mach-sa1100/graphicsmaster.c 1.17 -> 1.18 # include/asm-ppc64/signal.h 1.4.1.1 -> 1.6 # sound/isa/es18xx.c 1.16.1.2 -> 1.18 # sound/usb/usbquirks.h 1.13 -> 1.14 # drivers/md/linear.c 1.30 -> 1.33 # drivers/net/ptifddi.h 1.1 -> (deleted) # drivers/usb/input/hiddev.c 1.33 -> 1.34 # arch/ia64/mm/init.c 1.35 -> 1.36 # arch/ia64/kernel/module.c 1.4 -> 1.5 # include/asm-m68knommu/thread_info.h 1.2 -> 1.3 # drivers/sgi/char/sgiserial.h 1.2 -> 1.3 # drivers/serial/mcfserial.c 1.10 -> 1.11 # arch/x86_64/kernel/irq.c 1.15 -> 1.16 # Documentation/networking/ip-sysctl.txt 1.16 -> 1.17 # drivers/mtd/chips/cfi_cmdset_0002.c 1.8 -> 1.9 # arch/sparc64/kernel/systbls.S 1.38 -> 1.39 # drivers/mtd/Makefile 1.10 -> 1.11 # lib/zlib_inflate/infcodes.c 1.1 -> 1.4 # drivers/char/serial167.c 1.23 -> 1.25 # arch/x86_64/kernel/pci-gart.c 1.10 -> 1.11 # drivers/net/sis900.c 1.36 -> 1.37 # drivers/net/hamradio/dmascc.c 1.13 -> 1.16 # include/asm-i386/mach-summit/mach_mpparse.h 1.6 -> 1.8 # include/linux/usb.h 1.77 -> 1.78 # arch/ppc64/kernel/irq.c 1.25 -> 1.28 # drivers/hotplug/cpci_hotplug_core.c 1.5 -> 1.6 drivers/pci/hotplug/cpci_hotplug_core.c (moved) # arch/arm/common/Makefile 1.2 -> 1.3 # drivers/mtd/devices/lart.c 1.1 -> 1.2 # drivers/net/irda/donauboe.c 1.8 -> 1.10 # drivers/media/radio/radio-cadet.c 1.13 -> 1.14 # fs/jffs2/fs.c 1.11 -> 1.12 # arch/sparc/prom/Makefile 1.3 -> 1.4 # drivers/net/wan/pc300_tty.c 1.10 -> 1.11 # sound/isa/sb/sb8_main.c 1.5 -> 1.6 # fs/fat/inode.c 1.65 -> 1.68 # drivers/net/tun.c 1.17 -> 1.18 # drivers/ide/ide-cd.c 1.45 -> 1.49 # sound/pci/rme9652/rme9652.c 1.18 -> 1.19 # arch/cris/drivers/ethernet.c 1.11 -> 1.12 # scripts/kernel-doc 1.11 -> 1.12 # fs/reiserfs/super.c 1.63 -> 1.65 # net/core/dv.c 1.6 -> 1.7 # fs/binfmt_elf.c 1.45 -> 1.46 # drivers/acpi/pci_irq.c 1.16 -> 1.17 # drivers/net/wan/lmc/lmc_var.h 1.4 -> 1.5 # sound/pci/ice1712/ice1724.c 1.3 -> 1.6 # include/sound/sb.h 1.7 -> 1.9 # drivers/md/multipath.c 1.48 -> 1.51 # drivers/video/matrox/matroxfb_DAC1064.c 1.14 -> 1.15 # fs/jfs/super.c 1.33.1.2 -> 1.35 # drivers/scsi/sg.c 1.56 -> 1.58 # drivers/usb/serial/pl2303.c 1.40 -> 1.41 # net/sched/sch_atm.c 1.10 -> 1.11 # drivers/char/riscom8.c 1.15 -> 1.17 # drivers/scsi/BusLogic.h 1.14 -> 1.15 # arch/ppc/8260_io/fcc_enet.c 1.9 -> 1.13 # arch/v850/Kconfig 1.10 -> 1.11 # fs/aio.c 1.31 -> 1.32 # drivers/scsi/aic7xxx/aic7xxx_core.c 1.28 -> 1.31 # arch/x86_64/kernel/nmi.c 1.10 -> 1.11 # drivers/usb/usb-skeleton.c 1.36 -> 1.37 # drivers/usb/serial/ir-usb.c 1.28 -> 1.29 # drivers/usb/serial/digi_acceleport.c 1.33 -> 1.34 # drivers/md/dm.h 1.3 -> 1.6 # drivers/ide/Kconfig 1.11 -> 1.13 # drivers/net/arcnet/rfc1201.c 1.5 -> 1.6 # drivers/net/8139cp.c 1.38 -> 1.39 # drivers/usb/core/hub.c 1.63 -> 1.67 # net/core/netfilter.c 1.20 -> 1.21 # drivers/usb/net/catc.c 1.23 -> 1.25 # drivers/video/matrox/i2c-matroxfb.c 1.8 -> 1.9 # arch/ppc/kernel/pci.c 1.26 -> 1.29 # drivers/mtd/maps/pnc2000.c 1.4 -> 1.5 # drivers/pci/setup-irq.c 1.3 -> 1.4 # drivers/block/genhd.c 1.88 -> 1.89 # arch/ppc64/kernel/setup.c 1.24.1.2 -> 1.28 # drivers/net/e100/e100_main.c 1.72 -> 1.76 # include/linux/pci.h 1.77 -> 1.85 # arch/um/drivers/net_kern.c 1.11 -> 1.14 # drivers/scsi/aic7xxx/aic79xx_inline.h 1.10 -> 1.12 # drivers/scsi/aic7xxx/aic79xx_pci.c 1.10 -> 1.12 # include/asm-arm/thread_info.h 1.6 -> 1.7 # fs/jffs2/write.c 1.10 -> 1.11 # drivers/scsi/osst.c 1.45 -> 1.46 # arch/i386/kernel/setup.c 1.82 -> 1.84 # net/wanrouter/wanproc.c 1.19 -> 1.20 # drivers/isdn/hisax/elsa_cs.c 1.5 -> 1.6 # include/linux/tcp.h 1.10 -> 1.11 # drivers/md/dm-stripe.c 1.5 -> 1.6 # Documentation/DocBook/Makefile 1.39 -> 1.41 # arch/alpha/kernel/signal.c 1.18 -> 1.19 # include/asm-um/bug.h 1.1 -> 1.2 # arch/um/sys-ppc/Makefile 1.3 -> 1.4 # drivers/mtd/mtdcore.c 1.4 -> 1.5 # arch/ppc/kernel/process.c 1.34 -> 1.36 # drivers/atm/idt77252.c 1.13 -> 1.14 # drivers/scsi/scsi_debug.h 1.15 -> 1.16 # drivers/video/aty/aty128fb.c 1.37 -> 1.38 # drivers/scsi/gdth_proc.c 1.13 -> 1.14 # include/sound/pcm.h 1.14 -> 1.16 # arch/mips/ddb5074/pci.c 1.9 -> 1.10 # arch/arm/mach-sa1100/neponset.c 1.18 -> 1.19 # drivers/mtd/devices/docecc.c 1.6 -> 1.7 # net/ipv4/ipmr.c 1.19 -> 1.20 # drivers/scsi/AM53C974.c 1.13 -> 1.14 # arch/i386/kernel/cpu/cpufreq/gx-suspmod.c 1.8 -> 1.9 # drivers/mtd/mtdblock_ro.c 1.26 -> 1.27 # arch/arm/mach-sa1100/xp860.c 1.10 -> 1.11 # arch/sh/lib/Makefile 1.6 -> 1.7 # arch/ia64/hp/sim/simserial.c 1.16 -> 1.17 # arch/x86_64/kernel/suspend.c 1.5 -> 1.6 # include/asm-ia64/smp.h 1.9 -> 1.10 # drivers/mtd/maps/elan-104nc.c 1.5 -> 1.6 # arch/ppc/boot/common/misc-common.c 1.9 -> 1.10 # include/linux/hugetlb.h 1.16 -> 1.17 # net/ipx/ipx_route.c 1.1 -> 1.2 # drivers/net/tokenring/smctr.c 1.20 -> 1.21 # sound/isa/sb/es968.c 1.12.1.1 -> 1.16 # include/asm-v850/nb85e_cache.h 1.3 -> 1.4 # include/linux/msdos_fs_sb.h 1.9 -> 1.10 # arch/alpha/lib/csum_partial_copy.c 1.3 -> 1.4 # drivers/net/wan/sdla_chdlc.c 1.27 -> 1.28 # include/linux/spinlock.h 1.23 -> 1.24 # drivers/scsi/scsi_syms.c 1.36 -> 1.38 # net/econet/af_econet.c 1.18 -> 1.20 # drivers/ide/ide-floppy.c 1.27 -> 1.28 # drivers/usb/storage/isd200.c 1.29 -> 1.30 # drivers/media/video/zr36120.c 1.18 -> 1.19 # arch/ppc/boot/of1275/Makefile 1.3 -> 1.4 # sound/oss/dmasound/Kconfig 1.1 -> 1.2 # net/netrom/nr_out.c 1.5 -> 1.6 # include/net/dn_fib.h 1.6 -> 1.7 # drivers/scsi/scsi_lib.c 1.90 -> 1.92 # net/rose/af_rose.c 1.23 -> 1.26 # net/netrom/af_netrom.c 1.25 -> 1.27 # net/llc/llc_if.c 1.21 -> 1.22 # fs/sysfs/bin.c 1.5 -> 1.6 # include/asm-alpha/bitops.h 1.10 -> 1.11 # sound/core/ioctl32/rawmidi32.c 1.11 -> 1.13 # sound/i2c/l3/uda1341.c 1.8 -> 1.9 # drivers/usb/storage/scsiglue.c 1.42 -> 1.45 # scripts/Makefile.lib 1.18 -> 1.19 # drivers/message/fusion/mptlan.c 1.9 -> 1.10 # drivers/usb/core/devio.c 1.47 -> 1.48 # arch/mips/ddb5xxx/ddb5477/pci.c 1.1 -> 1.2 # arch/alpha/lib/memmove.S 1.1 -> 1.2 # drivers/usb/input/xpad.c 1.14 -> 1.15 # drivers/video/matrox/matroxfb_base.h 1.19 -> 1.22 # net/netlink/af_netlink.c 1.25 -> 1.27 # fs/coda/inode.c 1.25 -> 1.26 # fs/ncpfs/inode.c 1.42 -> 1.43 # net/ipv6/ipcomp6.c 1.3 -> 1.4 # drivers/scsi/dmx3191d.h 1.6 -> 1.7 # net/core/dev.c 1.83 -> 1.84 # kernel/compat.c 1.14 -> 1.15 # drivers/ide/legacy/pdc4030.c 1.9 -> 1.10 # net/xfrm/xfrm_policy.c 1.27 -> 1.34 # drivers/net/irda/irda-usb.c 1.38 -> 1.40 # net/ipv6/Kconfig 1.4 -> 1.6 # net/decnet/netfilter/dn_rtmsg.c 1.2 -> 1.3 # drivers/char/generic_serial.c 1.10 -> 1.11 # fs/jffs2/build.c 1.5 -> 1.6 # drivers/char/mem.c 1.38 -> 1.40 # arch/ppc64/kernel/traps.c 1.16.1.1 -> 1.18 # drivers/scsi/scsi.c 1.112 -> 1.113 # drivers/usb/core/usb.c 1.123 -> 1.125 # arch/ppc/platforms/pmac_pci.c 1.15 -> 1.16 # drivers/usb/storage/initializers.h 1.4 -> 1.5 # include/linux/reiserfs_fs_sb.h 1.22 -> 1.23 # drivers/net/r8169.c 1.10 -> 1.11 # kernel/posix-timers.c 1.16 -> 1.17 # arch/ppc64/kernel/head.S 1.31 -> 1.35 # drivers/isdn/hardware/eicon/divamnt.c 1.6 -> 1.7 # sound/ppc/awacs.c 1.10 -> 1.12 # drivers/scsi/atari_scsi.h 1.5 -> 1.6 # arch/v850/kernel/ptrace.c 1.1 -> 1.2 # lib/zlib_inflate/inflate.c 1.3 -> 1.7 # drivers/scsi/arm/arxescsi.c 1.19 -> 1.20 # drivers/scsi/arm/acornscsi.c 1.30 -> 1.31 # include/asm-ppc/ptrace.h 1.6 -> 1.7 # drivers/hotplug/cpcihp_generic.c 1.2 -> 1.3 drivers/pci/hotplug/cpcihp_generic.c (moved) # arch/x86_64/ia32/ia32_ioctl.c 1.27 -> 1.28 # sound/pci/emu10k1/emufx.c 1.20 -> 1.21 # drivers/pci/pci.ids 1.44 -> 1.45 # net/decnet/af_decnet.c 1.25 -> 1.26 # include/asm-ppc64/uaccess.h 1.6 -> 1.7 # include/linux/mtd/nand_ecc.h 1.1 -> 1.2 # drivers/char/serial_tx3912.c 1.13 -> 1.14 # drivers/scsi/megaraid.h 1.18 -> 1.19 # drivers/scsi/NCR5380.h 1.7 -> 1.8 # sound/isa/gus/gus_synth.c 1.6 -> 1.7 # include/asm-ppc/semaphore.h 1.9 -> 1.10 # drivers/net/pcmcia/ibmtr_cs.c 1.13 -> 1.14 # include/net/bluetooth/hci_core.h 1.12 -> 1.13 # Documentation/DMA-mapping.txt 1.14 -> 1.15 # drivers/net/wireless/ieee802_11.h 1.2 -> 1.3 # sound/oss/cmpci.c 1.22 -> 1.23 # include/asm-x86_64/suspend.h 1.5 -> 1.6 # include/sound/ac97_codec.h 1.18 -> 1.19 # drivers/ide/ide-proc.c 1.10 -> 1.13 # drivers/scsi/aic7xxx/aic7xxx.h 1.13 -> 1.15 # arch/m68k/atari/hades-pci.c 1.6 -> 1.7 # include/linux/mtd/doc2000.h 1.4 -> 1.5 # drivers/usb/net/usbnet.c 1.52 -> 1.54 # net/bluetooth/rfcomm/tty.c 1.20 -> 1.22 # sound/isa/gus/interwave.c 1.12.1.1 -> 1.14 # drivers/md/raid1.c 1.62 -> 1.67 # drivers/base/firmware.c 1.6 -> 1.7 # fs/proc/kcore.c 1.7 -> 1.8 # include/asm-x86_64/cpufeature.h 1.3 -> 1.4 # include/net/netrom.h 1.2 -> 1.3 # arch/x86_64/kernel/asm-offsets.c 1.3 -> 1.4 # fs/jffs2/nodelist.c 1.8 -> 1.9 # fs/cifs/cifsfs.c 1.14.1.2 -> 1.16 # arch/ppc64/Kconfig 1.15 -> 1.18 # drivers/md/raid0.c 1.26 -> 1.32 # arch/parisc/lib/Makefile 1.6 -> 1.7 # drivers/hotplug/pcihp_skeleton.c 1.2 -> 1.3 drivers/pci/hotplug/pcihp_skeleton.c (moved) # arch/ppc64/kernel/xics.c 1.22.1.2 -> 1.24 # include/linux/sysctl.h 1.44 -> 1.47 # arch/ppc/kernel/head.S 1.31 -> 1.32 # include/pcmcia/driver_ops.h 1.4 -> (deleted) # drivers/md/dm-linear.c 1.4 -> 1.5 # include/asm-ppc/mmu_context.h 1.12 -> 1.13 # include/linux/zlib.h 1.2 -> 1.8 # drivers/s390/net/ctctty.c 1.12 -> 1.14 # drivers/net/tg3.c 1.69 -> 1.71 # include/linux/smp.h 1.23 -> 1.25 # sound/core/ioctl32/timer32.c 1.11 -> 1.13 # arch/sparc64/kernel/sys_sparc.c 1.19 -> 1.21 # include/asm-i386/memblk.h 1.3 -> 1.4 # arch/v850/lib/Makefile 1.2 -> 1.3 # drivers/net/wan/lmc/lmc_proto.c 1.7 -> 1.8 # include/linux/mmzone.h 1.37 -> 1.39 # net/ipv4/raw.c 1.31 -> 1.33 # drivers/scsi/aic7xxx/aic79xx_osm.c 1.42 -> 1.46 # include/linux/list.h 1.29 -> 1.30 # include/asm-v850/bitops.h 1.2 -> 1.3 # net/ipv6/af_inet6.c 1.44 -> 1.51 # net/ipv6/tcp_ipv6.c 1.56 -> 1.59 # drivers/net/sungem.h 1.11 -> 1.12 # net/bluetooth/hci_sock.c 1.21 -> 1.22 # drivers/usb/serial/kl5kusb105.c 1.22 -> 1.23 # sound/pci/ice1712/ak4524.c 1.9 -> (deleted) # sound/i2c/Makefile 1.9 -> 1.10 # drivers/net/wireless/wavelan_cs.c 1.22.1.1 -> 1.24 # drivers/scsi/mac_scsi.h 1.4 -> 1.5 # arch/ppc/boot/common/Makefile 1.5 -> 1.7 # net/xfrm/xfrm_user.c 1.21 -> 1.26 # drivers/ide/pci/hpt366.c 1.18 -> 1.19 # fs/Kconfig 1.26 -> 1.27 # drivers/net/amd8111e.c 1.4 -> 1.5 # drivers/mtd/chips/sharp.c 1.6 -> 1.8 # drivers/usb/media/dabusb.c 1.28 -> 1.29 # drivers/video/matrox/matroxfb_accel.c 1.8 -> 1.9 # drivers/char/epca.h 1.3 -> 1.4 # drivers/mtd/redboot.c 1.3 -> 1.4 # drivers/block/loop.c 1.88 -> 1.89 # drivers/char/agp/Kconfig 1.21 -> 1.22 # fs/buffer.c 1.200 -> 1.202 # drivers/pnp/resource.c 1.12 -> 1.13 # drivers/mtd/maps/iq80321.c 1.2 -> (deleted) # net/decnet/dn_timer.c 1.4 -> 1.5 # drivers/pci/proc.c 1.24 -> 1.26 # include/sound/trident.h 1.7.1.1 -> 1.9 # arch/m68knommu/platform/5206/config.c 1.3 -> 1.4 # drivers/scsi/atari_NCR5380.c 1.12.1.1 -> 1.14 # net/ipv4/esp.c 1.29 -> 1.31 net/ipv4/esp4.c (moved) # drivers/usb/core/hcd.c 1.63 -> 1.64 # drivers/usb/input/hid-core.c 1.56 -> 1.58 # include/pcmcia/bus_ops.h 1.4 -> (deleted) # arch/ppc64/mm/init.c 1.43 -> 1.44 # drivers/usb/serial/belkin_sa.c 1.35 -> 1.36 # drivers/scsi/aha1740.h 1.6 -> 1.7 # drivers/char/epca.c 1.22 -> 1.23 # include/linux/raid/raid1.h 1.16 -> 1.17 # net/rose/rose_in.c 1.6 -> 1.8 # Documentation/sound/alsa/OSS-Emulation.txt 1.2 -> 1.3 # arch/mips/baget/prom/Makefile 1.4 -> 1.5 # include/asm-i386/smp.h 1.25 -> 1.26 # drivers/scsi/ppa.c 1.21 -> 1.23 # drivers/mtd/nand/spia.c 1.5 -> 1.6 # lib/zlib_inflate/infblock.h 1.1 -> 1.3 # drivers/char/tty_io.c 1.101 -> 1.106 # drivers/mtd/chips/jedec.c 1.9 -> 1.11 # arch/x86_64/pci/irq.c 1.8 -> 1.9 # drivers/mtd/maps/sbc_gxx.c 1.4 -> 1.5 # drivers/usb/input/powermate.c 1.13 -> 1.14 # fs/bio.c 1.44 -> 1.47 # net/ipv6/ndisc.c 1.38 -> 1.42 # arch/ppc/boot/Makefile 1.16 -> 1.17 # arch/ppc64/kernel/process.c 1.32 -> 1.34 # drivers/char/pcxx.c 1.11 -> 1.12 # sound/pci/maestro3.c 1.20 -> 1.22 # include/sound/asequencer.h 1.3 -> 1.4 # drivers/hotplug/cpqphp_nvram.h 1.1 -> 1.2 drivers/pci/hotplug/cpqphp_nvram.h (moved) # MAINTAINERS 1.140 -> 1.145 # net/sctp/ipv6.c 1.41 -> 1.43 # drivers/net/sundance.c 1.42 -> 1.44 # net/sctp/protocol.c 1.48 -> 1.51 # drivers/usb/net/rtl8150.c 1.24 -> 1.26 # fs/reiserfs/journal.c 1.68 -> 1.69 # sound/pci/intel8x0.c 1.33 -> 1.35 # sound/pci/ice1712/revo.c 1.1 -> 1.3 # include/linux/zutil.h 1.2 -> 1.7 # net/core/dst.c 1.12 -> 1.13 # kernel/exec_domain.c 1.14 -> 1.15 # arch/ppc64/kernel/pci_dma.c 1.14 -> 1.16 # fs/reiserfs/prints.c 1.22 -> 1.23 # drivers/scsi/scsi_debug.c 1.37 -> 1.38 # drivers/char/rio/rio_linux.c 1.20 -> 1.22 # sound/core/ioctl32/pcm32.c 1.13 -> 1.15 # net/core/datagram.c 1.9 -> 1.10 # drivers/hotplug/cpcihp_zt5550.c 1.1 -> 1.2 drivers/pci/hotplug/cpcihp_zt5550.c (moved) # net/atm/lec.c 1.22 -> 1.25 # drivers/scsi/aic7xxx/aic79xx_osm.h 1.29 -> 1.33 # drivers/char/istallion.c 1.22 -> 1.24 # drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped 1.11 -> 1.12 # mm/mmap.c 1.84 -> 1.85 # fs/proc/base.c 1.47 -> 1.48 # drivers/ieee1394/eth1394.c 1.13 -> 1.15 # arch/ia64/hp/sim/simeth.c 1.7 -> 1.8 # drivers/video/i810/i810_main.h 1.5 -> 1.6 # sound/usb/usbaudio.h 1.14 -> 1.15 # scripts/kconfig/expr.h 1.4 -> 1.10 # drivers/mtd/maps/physmap.c 1.4 -> 1.7 # drivers/mtd/chips/map_rom.c 1.5 -> 1.6 # sound/pci/ac97/Makefile 1.11 -> 1.12 # drivers/hotplug/acpiphp_core.c 1.2 -> 1.3 drivers/pci/hotplug/acpiphp_core.c (moved) # sound/core/timer.c 1.17 -> 1.18 # include/sound/cs8427.h 1.1 -> 1.2 # drivers/message/i2o/i2o_core.c 1.20 -> 1.22 # net/unix/af_unix.c 1.44 -> 1.46 # arch/alpha/kernel/systbls.S 1.6 -> 1.8 # Documentation/filesystems/jfs.txt 1.4 -> 1.5 # include/asm-sparc64/bug.h 1.2 -> 1.3 # arch/um/os-Linux/drivers/tuntap_kern.c 1.3 -> 1.4 # include/net/x25.h 1.7 -> 1.8 # include/linux/tty_driver.h 1.7 -> 1.8 # net/ipv6/esp6.c 1.16 -> 1.17 # drivers/net/tokenring/ibmtr.c 1.14 -> 1.15 # arch/v850/vmlinux.lds.S 1.8 -> 1.9 # include/asm-arm/uaccess.h 1.10 -> 1.11 # include/asm-i386/mach-summit/mach_apic.h 1.26 -> 1.27 # drivers/net/arcnet/rfc1051.c 1.4 -> 1.5 # drivers/usb/class/cdc-acm.c 1.40 -> 1.41 # drivers/usb/input/hid-tmff.c 1.2 -> 1.3 # drivers/usb/misc/rio500.c 1.21 -> 1.23 # drivers/net/pppoe.c 1.25 -> 1.28 # sound/pci/trident/trident_main.c 1.19 -> 1.20 # drivers/scsi/osst.h 1.9 -> 1.10 # drivers/hotplug/cpci_hotplug_pci.c 1.7 -> 1.10 drivers/pci/hotplug/cpci_hotplug_pci.c (moved) # arch/ppc/boot/ld.script 1.4 -> 1.6 # drivers/base/power.c 1.18 -> 1.19 # arch/mips/baget/vacserial.c 1.13 -> 1.14 # drivers/scsi/ide-scsi.c 1.24 -> 1.25 # drivers/scsi/st.c 1.62 -> 1.63 # net/bluetooth/rfcomm/sock.c 1.17 -> 1.20 # net/rose/rose_timer.c 1.8 -> 1.10 # fs/vfat/namei.c 1.31 -> 1.32 # drivers/scsi/eata_pio.c 1.17.1.1 -> 1.19 # sound/core/oss/mixer_oss.c 1.17 -> 1.18 # sound/isa/sb/sb8.c 1.11 -> 1.12 # sound/ppc/pmac.h 1.4 -> 1.5 # drivers/usb/storage/usb.h 1.25 -> 1.27 # drivers/isdn/i4l/isdn_tty.h 1.16 -> 1.17 # fs/cifs/smberr.h 1.1 -> 1.2 # arch/m68knommu/kernel/setup.c 1.3 -> 1.4 # fs/namespace.c 1.45 -> 1.46 # drivers/scsi/arm/powertec.c 1.25 -> 1.26 # net/atm/svc.c 1.9 -> 1.10 # arch/x86_64/kernel/sys_x86_64.c 1.8 -> 1.9 # drivers/usb/serial/keyspan_pda.c 1.30 -> 1.31 # include/asm-ia64/ptrace.h 1.10 -> 1.11 # drivers/video/matrox/matroxfb_misc.c 1.9 -> 1.10 # include/net/ax25.h 1.10 -> 1.12 # net/atm/pppoatm.c 1.6 -> 1.7 # net/sctp/sm_sideeffect.c 1.43 -> 1.44 # kernel/resource.c 1.10 -> 1.11 # arch/arm/lib/Makefile 1.16 -> 1.17 # fs/jfs/resize.c 1.8 -> 1.9 # include/asm-m68k/thread_info.h 1.4 -> 1.5 # Makefile 1.408 -> 1.411 # drivers/isdn/hisax/avma1_cs.c 1.4.1.1 -> 1.6 # fs/fcntl.c 1.26 -> 1.28 # sound/pci/cmipci.c 1.23 -> 1.24 # include/net/dn.h 1.7 -> 1.8 # drivers/mtd/nftlmount.c 1.7 -> 1.8 # fs/jffs2/compr_rtime.c 1.4 -> 1.5 # drivers/usb/serial/mct_u232.c 1.37 -> 1.38 # fs/ext3/inode.c 1.67 -> 1.68 # include/asm-ppc/prep_nvram.h 1.4 -> 1.5 # drivers/scsi/sym53c8xx.c 1.34.1.1 -> 1.36 # net/packet/af_packet.c 1.27 -> 1.29 # drivers/char/agp/amd-k8-agp.c 1.41 -> 1.42 # drivers/net/irda/irport.c 1.18 -> 1.20 # drivers/net/pcmcia/fmvj18x_cs.c 1.20 -> 1.21 # drivers/scsi/aic7xxx/aic79xx.h 1.11 -> 1.12 # arch/cris/drivers/serial.c 1.17 -> 1.18 # include/asm-i386/cpu.h 1.3 -> 1.4 # drivers/scsi/ibmmca.h 1.8 -> 1.9 # drivers/usb/media/stv680.c 1.26 -> 1.27 # include/asm-s390/thread_info.h 1.4 -> 1.5 # drivers/mtd/maps/sun_uflash.c 1.3 -> 1.4 # fs/dquot.c 1.62 -> 1.63 # sound/core/sound.c 1.27 -> 1.30 # mm/page-writeback.c 1.64 -> 1.68 # net/sunrpc/xprt.c 1.59 -> 1.61 # drivers/scsi/wd33c93.c 1.13 -> 1.14 # arch/sh/kernel/pci-sh7751.c 1.7 -> 1.8 # drivers/net/wireless/orinoco_pci.c 1.5 -> 1.6 # drivers/net/arcnet/arcnet.c 1.12 -> 1.13 # sound/core/sgbuf.c 1.4.1.1 -> 1.6 # arch/x86_64/defconfig 1.20 -> 1.21 # include/net/ip.h 1.21 -> 1.22 # net/bluetooth/bnep/core.c 1.17 -> 1.18 # drivers/char/mxser.c 1.22 -> 1.23 # net/ipv4/tcp_output.c 1.27 -> 1.30 # drivers/video/sis/sis_main.c 1.21 -> 1.23 # arch/ppc64/mm/numa.c 1.4 -> 1.5 # drivers/usb/serial/keyspan.h 1.18 -> 1.19 # drivers/acpi/processor.c 1.38 -> 1.39 # arch/cris/lib/Makefile 1.5 -> 1.6 # net/ax25/ax25_route.c 1.10 -> 1.11 # drivers/video/matrox/matroxfb_base.c 1.35 -> 1.37 # drivers/scsi/scsi_priv.h 1.6 -> 1.13 # net/bluetooth/l2cap.c 1.28 -> 1.30 # drivers/mtd/mtdchar.c 1.13 -> 1.14 # drivers/scsi/pas16.h 1.7 -> 1.8 # include/linux/device-mapper.h 1.2 -> 1.4 # drivers/char/rocket.c 1.20 -> 1.24 # drivers/ide/legacy/ide-cs.c 1.9 -> 1.10 # net/ax25/ax25_ds_in.c 1.5 -> 1.7 # security/Kconfig 1.5 -> 1.6 # arch/m68knommu/Kconfig 1.11 -> 1.12 # sound/core/Makefile 1.26 -> 1.30 # arch/ppc64/kernel/syscalls.c 1.10 -> 1.11 # drivers/mtd/maps/nora.c 1.4 -> (deleted) # include/sound/uda1341.h 1.3 -> 1.4 # drivers/mtd/maps/scx200_docflash.c 1.1 -> 1.2 # include/asm-x86_64/thread_info.h 1.11 -> 1.12 # drivers/scsi/gdth_proc.h 1.4 -> 1.5 # drivers/mtd/devices/docprobe.c 1.5 -> 1.6 # arch/ppc64/kernel/sys_ppc32.c 1.61 -> 1.62 # drivers/pci/pci-driver.c 1.26 -> 1.29 # include/linux/ipv6.h 1.8 -> 1.9 # sound/drivers/Makefile 1.8 -> 1.9 # arch/arm/mach-integrator/arch.c 1.8 -> 1.10 arch/arm/mach-integrator/core.c (moved) # drivers/mtd/cmdline.c 1.3 -> 1.5 drivers/mtd/cmdlinepart.c (moved) # drivers/pci/probe.c 1.39 -> 1.42 # drivers/video/riva/fbdev.c 1.46 -> 1.47 # drivers/scsi/fdomain.c 1.21 -> 1.22 # sound/pci/sonicvibes.c 1.16 -> 1.17 # drivers/hotplug/Makefile 1.14 -> 1.15 drivers/pci/hotplug/Makefile (moved) # include/net/tcp_ecn.h 1.4 -> 1.5 # include/asm-sparc64/thread_info.h 1.10 -> 1.11 # drivers/isdn/i4l/isdn_tty.c 1.47 -> 1.49 # arch/i386/kernel/cpu/cpufreq/longrun.c 1.13 -> 1.14 # arch/arm/mach-integrator/pci_v3.c 1.15 -> 1.16 # Documentation/filesystems/fat_cvf.txt 1.2 -> (deleted) # drivers/usb/net/kaweth.c 1.41 -> 1.42 # arch/ppc64/kernel/prom.c 1.25.1.1 -> 1.28 # drivers/scsi/arm/cumana_2.c 1.27 -> 1.28 # net/ipv6/ipv6_syms.c 1.13 -> 1.15 # drivers/net/wan/z85230.h 1.4 -> 1.5 # drivers/mtd/chips/map_absent.c 1.2 -> 1.3 # include/asm-mips/bug.h 1.1 -> 1.2 # arch/m68knommu/platform/5206/ARNEWSH/crt0_ram.S 1.1 -> 1.2 # kernel/module.c 1.82 -> 1.85 # net/xfrm/xfrm_state.c 1.26 -> 1.28 # sound/pci/emu10k1/irq.c 1.6 -> 1.7 # drivers/scsi/in2000.c 1.19.1.1 -> 1.21 # sound/usb/usbaudio.c 1.34.1.1 -> 1.39 # include/net/sock.h 1.40 -> 1.43 # include/asm-ppc64/elf.h 1.10 -> 1.12 # arch/ppc/8xx_io/uart.c 1.24 -> 1.26 # arch/ppc64/kernel/iSeries_setup.c 1.12 -> 1.13 # include/asm-parisc/bug.h 1.3 -> 1.4 # net/netrom/nr_timer.c 1.7 -> 1.9 # drivers/usb/serial/Kconfig 1.7 -> 1.8 # net/rxrpc/transport.c 1.2 -> 1.3 # drivers/mtd/mtdconcat.c 1.1 -> 1.2 # drivers/acorn/char/defkeymap-acorn.c_shipped 1.3 -> (deleted) # lib/zlib_inflate/infblock.c 1.1 -> 1.6 # net/ipv4/sysctl_net_ipv4.c 1.10 -> 1.11 # net/core/sock.c 1.25 -> 1.27 # include/net/af_unix.h 1.4 -> 1.5 # Documentation/sysctl/vm.txt 1.9 -> 1.10 # arch/ppc64/kernel/smp.c 1.35 -> 1.37 # drivers/net/ppp_async.c 1.10 -> 1.11 # drivers/net/eepro.c 1.17 -> 1.18 # drivers/ide/pci/pdc202xx_new.c 1.15 -> 1.16 # scripts/kconfig/zconf.l 1.6 -> 1.7 # include/asm-m68k/bug.h 1.1 -> 1.2 # include/asm-s390/bug.h 1.1 -> 1.2 # net/bluetooth/bnep/netdev.c 1.3 -> 1.4 # net/ipv6/ip6_input.c 1.12 -> 1.13 # include/asm-ppc/bug.h 1.2 -> 1.4 # drivers/mtd/mtdpart.c 1.4 -> 1.5 # include/net/ip6_fib.h 1.5 -> 1.7 # Documentation/kbuild/makefiles.txt 1.8 -> 1.9 # include/linux/raid/multipath.h 1.15 -> 1.17 # lib/zlib_inflate/infutil.h 1.2 -> 1.4 # net/ipv6/route.c 1.40 -> 1.45 # drivers/serial/21285.c 1.13.1.6 -> 1.17 # include/asm-ia64/percpu.h 1.7 -> 1.8 # drivers/char/stallion.c 1.23 -> 1.26 # drivers/usb/class/bluetty.c 1.41 -> 1.42 # net/ipv4/tcp_input.c 1.36 -> 1.39 # sound/isa/wavefront/wavefront.c 1.11.1.1 -> 1.14 # include/sound/info.h 1.8 -> 1.9 # include/linux/zconf.h 1.2 -> 1.9 # drivers/scsi/sd.c 1.113 -> 1.117 # drivers/mtd/maps/epxa10db-flash.c 1.3 -> 1.4 # net/ax25/ax25_std_in.c 1.5 -> 1.7 # drivers/acorn/char/mouse_ps2.c 1.6 -> (deleted) # net/ipv4/tcp_minisocks.c 1.33 -> 1.35 # drivers/usb/input/aiptek.c 1.15 -> 1.16 # drivers/video/matrox/matroxfb_accel.h 1.3 -> 1.4 # drivers/pcmcia/ds.c 1.27.1.1 -> 1.29 # net/ipv6/Makefile 1.13 -> 1.14 # drivers/usb/input/hid-lgff.c 1.4 -> 1.5 # include/net/dn_nsp.h 1.4 -> 1.5 # arch/ppc64/kernel/pacaData.c 1.6 -> 1.7 # drivers/net/bonding/bond_3ad.c 1.1 -> 1.2 # net/ipv4/Kconfig 1.7 -> 1.8 # drivers/block/DAC960.c 1.59 -> 1.60 # drivers/usb/media/pwc-if.c 1.34 -> 1.36 # drivers/scsi/aic7xxx/aic79xx_proc.c 1.9 -> 1.10 # arch/ppc64/kernel/stab.c 1.10 -> 1.11 # drivers/mtd/chips/cfi_probe.c 1.5 -> 1.6 # drivers/sbus/char/aurora.h 1.2 -> 1.3 # net/atm/signaling.c 1.8 -> 1.9 # drivers/usb/storage/unusual_devs.h 1.38 -> 1.40 # net/llc/llc_sap.c 1.18 -> 1.19 # drivers/net/tokenring/olympic.c 1.21 -> 1.22 # arch/ia64/sn/io/pci_bus_cvlink.c 1.6 -> 1.7 # Documentation/scsi/scsi_mid_low_api.txt 1.12 -> 1.13 # arch/v850/kernel/irq.c 1.6 -> 1.9 # drivers/mtd/devices/pmc551.c 1.10 -> 1.11 # arch/arm/mach-footbridge/isa-irq.c 1.6 -> 1.7 # drivers/mtd/nand/Kconfig 1.1 -> 1.2 # include/linux/hayesesp.h 1.2 -> 1.3 # include/asm-x86_64/bootsetup.h 1.2 -> 1.3 # include/linux/bio.h 1.30 -> 1.31 # mm/slab.c 1.81 -> 1.86 # include/linux/module.h 1.63 -> 1.65 # arch/i386/kernel/suspend.c 1.16 -> 1.17 # arch/alpha/kernel/irq.c 1.21 -> 1.22 # net/sched/sch_ingress.c 1.13 -> 1.14 # drivers/md/dm.c 1.18 -> 1.22 # include/asm-alpha/uaccess.h 1.5 -> 1.6 # include/sound/pcm_sgbuf.h 1.7 -> (deleted) # drivers/mtd/maps/integrator-flash.c 1.3 -> 1.4 # drivers/mtd/maps/netsc520.c 1.3 -> 1.4 # include/net/bluetooth/rfcomm.h 1.8 -> 1.9 # arch/arm/mm/consistent.c 1.11 -> 1.12 # drivers/usb/serial/ftdi_sio.c 1.42 -> 1.43 # drivers/sbus/char/bbc_i2c.c 1.3 -> 1.4 # include/net/udp.h 1.10 -> 1.11 # arch/x86_64/Kconfig 1.19 -> 1.20 # include/linux/rtnetlink.h 1.15 -> 1.17 # fs/filesystems.c 1.16 -> 1.17 # include/linux/msdos_fs.h 1.23 -> 1.25 # drivers/scsi/scsi_scan.c 1.85 -> 1.87 # sound/pci/fm801.c 1.17 -> 1.18 # drivers/scsi/aic7xxx/aic7xxx.seq 1.9 -> 1.11 # sound/core/seq/oss/seq_oss.c 1.4 -> 1.5 # kernel/sched.c 1.186 -> 1.189 # fs/jffs2/dir.c 1.25 -> 1.26 # include/linux/atalk.h 1.5 -> 1.6 # arch/m68knommu/platform/5307/Makefile 1.5 -> 1.6 # drivers/scsi/mac_NCR5380.c 1.8.1.1 -> 1.10 # drivers/block/deadline-iosched.c 1.20 -> 1.21 # drivers/Makefile 1.33 -> 1.35 # net/ipv6/netfilter/ip6t_owner.c 1.4 -> 1.5 # sound/isa/sb/sb16.c 1.15 -> 1.17 # net/ipv6/ip6_fib.c 1.18 -> 1.20 # include/linux/mtd/nftl.h 1.3 -> 1.4 # net/llc/llc_mac.c 1.21 -> 1.22 # include/linux/if_arp.h 1.9 -> 1.10 # include/net/ipv6.h 1.14 -> 1.19 # drivers/ieee1394/iso.c 1.5 -> 1.6 # arch/um/kernel/irq.c 1.8 -> 1.9 # scripts/Makefile.build 1.36 -> 1.38 # drivers/scsi/st.h 1.13 -> 1.14 # arch/v850/kernel/rte_ma1_cb.c 1.3 -> 1.4 # net/atm/mpc.c 1.15 -> 1.17 # drivers/scsi/dpt_i2o.c 1.29 -> 1.30 # arch/ppc/kernel/irq.c 1.26 -> 1.29 # sound/pci/ens1370.c 1.29 -> 1.32 # arch/ppc/boot/lib/Makefile 1.4 -> 1.5 # drivers/video/matrox/matroxfb_g450.c 1.12 -> 1.13 # drivers/hotplug/pci_hotplug_core.c 1.38 -> 1.39 drivers/pci/hotplug/pci_hotplug_core.c (moved) # net/ipv6/udp.c 1.36 -> 1.38 # include/linux/atmdev.h 1.13 -> 1.14 # drivers/hotplug/cpqphp.h 1.9 -> 1.10 drivers/pci/hotplug/cpqphp.h (moved) # drivers/usb/serial/ipaq.c 1.29 -> 1.30 # drivers/mtd/ftl.c 1.46 -> 1.47 # arch/sparc64/prom/Makefile 1.10 -> 1.11 # arch/alpha/kernel/traps.c 1.24 -> 1.25 # sound/core/seq/instr/Makefile 1.14 -> 1.15 # include/asm-ppc/io.h 1.12 -> 1.13 # lib/zlib_inflate/infutil.c 1.1 -> 1.4 # arch/sparc64/kernel/sparc64_ksyms.c 1.48 -> 1.49 # drivers/mtd/maps/l440gx.c 1.2 -> 1.3 # include/asm-alpha/bug.h 1.1 -> 1.2 # fs/fat/cache.c 1.16 -> 1.19 # arch/x86_64/kernel/reboot.c 1.5 -> 1.7 # include/net/xfrm.h 1.39 -> 1.43 # kernel/timer.c 1.53 -> 1.57 # sound/pci/via82xx.c 1.31 -> 1.33 # drivers/video/matrox/matroxfb_crtc2.c 1.23 -> 1.24 # scripts/kconfig/zconf.tab.c_shipped 1.6 -> 1.12 # fs/sysfs/inode.c 1.85 -> 1.86 # drivers/tc/zs.c 1.16 -> 1.18 # drivers/net/pcmcia/pcnet_cs.c 1.18 -> 1.19 # drivers/serial/nb85e_uart.c 1.11 -> 1.12 # include/linux/raid/raid5.h 1.15 -> 1.17 # arch/ppc64/kernel/sys32.S 1.13 -> (deleted) # net/ipv4/netfilter/ipchains_core.c 1.15 -> 1.16 # drivers/scsi/ppa.h 1.8 -> 1.9 # drivers/scsi/aic7xxx/aic79xx.seq 1.10 -> 1.13 # include/linux/mtd/compatmac.h 1.5 -> 1.6 # arch/mips64/lib/Makefile 1.5 -> 1.6 # drivers/ieee1394/ohci1394.c 1.36 -> 1.38 # fs/fat/misc.c 1.14 -> 1.16 # drivers/char/vt.c 1.45 -> 1.48 # sound/isa/cs423x/Makefile 1.9 -> 1.10 # include/linux/generic_serial.h 1.4 -> 1.5 # drivers/net/Kconfig 1.28 -> 1.29 # arch/ppc64/kernel/pci.c 1.30 -> 1.32 # arch/ppc64/boot/Makefile 1.13 -> 1.14 # arch/arm/mach-sa1100/system3.c 1.17 -> 1.18 # drivers/hotplug/ibmphp_res.c 1.6 -> 1.7 drivers/pci/hotplug/ibmphp_res.c (moved) # include/linux/jffs2.h 1.5 -> 1.6 # net/ipv4/ipcomp.c 1.10 -> 1.11 # net/ipv6/mcast.c 1.20 -> 1.21 # sound/pci/nm256/nm256.c 1.16 -> 1.19 # include/sound/mpu401.h 1.10 -> 1.11 # sound/core/oss/pcm_oss.c 1.22 -> 1.24 # sound/isa/Kconfig 1.3 -> 1.5 # drivers/pci/setup-res.c 1.17 -> 1.18 # include/net/llc_conn.h 1.13 -> 1.14 # drivers/base/driver.c 1.21 -> 1.22 # sound/pci/ymfpci/ymfpci_main.c 1.19 -> 1.20 # drivers/usb/serial/kobil_sct.c 1.8 -> 1.10 # drivers/net/tokenring/tmspci.c 1.11 -> 1.12 # include/linux/stallion.h 1.2 -> 1.3 # arch/ppc64/kernel/misc.S 1.58 -> 1.59 # drivers/video/cirrusfb.c 1.23 -> 1.24 # sound/oss/maestro.c 1.29 -> 1.30 # arch/ia64/kernel/irq.c 1.23 -> 1.24 # drivers/ieee1394/eth1394.h 1.6 -> 1.8 # net/ipv4/ah.c 1.23 -> 1.24 net/ipv4/ah4.c (moved) # drivers/usb/serial/omninet.c 1.29 -> 1.30 # lib/zlib_inflate/inftrees.c 1.1 -> 1.8 # arch/ppc/kernel/entry.S 1.27 -> 1.29 # include/asm-x86_64/apic.h 1.6 -> 1.7 # include/net/flow.h 1.7 -> 1.8 # drivers/usb/input/pid.c 1.7 -> 1.8 # drivers/video/fbmon.c 1.8 -> 1.9 # include/net/irda/af_irda.h 1.3 -> 1.4 # include/asm-x86_64/proto.h 1.9 -> 1.10 # drivers/char/ser_a2232.h 1.1 -> 1.3 # include/linux/reiserfs_fs.h 1.48 -> 1.49 # drivers/char/specialix.c 1.15 -> 1.17 # arch/arm/mach-integrator/Makefile 1.7 -> 1.8 # fs/cifs/netmisc.c 1.6 -> 1.7 # drivers/hotplug/cpqphp_nvram.c 1.7 -> 1.8 drivers/pci/hotplug/cpqphp_nvram.c (moved) # include/asm-ppc/types.h 1.7 -> 1.8 # drivers/media/video/zoran_procfs.c 1.2 -> 1.3 # include/asm-ppc/dma.h 1.5 -> 1.6 # drivers/mtd/chips/gen_probe.c 1.1 -> 1.2 # include/linux/mtd/flashchip.h 1.2 -> 1.3 # arch/x86_64/kernel/bluesmoke.c 1.10 -> 1.11 # arch/alpha/kernel/ptrace.c 1.14 -> 1.15 # include/asm-sh/bug.h 1.1 -> 1.2 # kernel/cpu.c 1.3 -> 1.4 # arch/arm/lib/putuser.S 1.3 -> 1.4 # include/linux/mtd/nand.h 1.1 -> 1.2 # net/core/net-sysfs.c 1.2 -> 1.4 # fs/hugetlbfs/inode.c 1.24 -> 1.26 # fs/proc/inode.c 1.22 -> 1.23 # arch/sparc64/kernel/ioctl32.c 1.63 -> 1.65 # net/appletalk/atalk_proc.c 1.3 -> 1.4 # drivers/scsi/aic7xxx_old/aic7xxx_proc.c 1.8 -> 1.9 # arch/cris/drivers/serial.h 1.6 -> 1.7 # drivers/net/wireless/orinoco_cs.c 1.19.1.1 -> 1.22 # scripts/kconfig/menu.c 1.5 -> 1.11 # drivers/scsi/Kconfig 1.21 -> 1.22 # sound/core/seq/Makefile 1.24 -> 1.27 # drivers/net/wan/lmc/lmc_media.c 1.5 -> 1.6 # fs/cifs/connect.c 1.17 -> 1.18 # include/linux/device.h 1.91 -> 1.98 # drivers/net/pppox.c 1.13 -> 1.14 # drivers/macintosh/via-pmu.c 1.19 -> 1.21 # arch/arm/kernel/process.c 1.28 -> 1.29 # sound/drivers/dummy.c 1.15 -> 1.17 # include/linux/percpu.h 1.5 -> 1.7 # drivers/net/dl2k.h 1.11 -> 1.12 # scripts/kconfig/conf.c 1.5 -> 1.9 # arch/ppc/kernel/ppc_ksyms.c 1.39 -> 1.41 # drivers/usb/serial/cyberjack.c 1.27 -> 1.28 # lib/kobject.c 1.21 -> 1.24 # drivers/pci/Makefile 1.28 -> 1.29 # arch/ppc64/kernel/signal32.c 1.39 -> 1.40 # scripts/kconfig/zconf.y 1.5 -> 1.11 # include/asm-alpha/thread_info.h 1.5 -> 1.6 # sound/Kconfig 1.2 -> 1.3 # arch/ppc/kernel/misc.S 1.43 -> 1.44 # arch/arm/common/sa1111.c 1.25 -> 1.26 # drivers/net/ppp_deflate.c 1.10 -> 1.11 # scripts/kconfig/lex.zconf.c_shipped 1.6 -> 1.7 # drivers/mtd/maps/iq80310.c 1.4 -> 1.5 # net/ax25/af_ax25.c 1.22 -> 1.24 # drivers/pci/hotplug.c 1.14 -> 1.15 # sound/isa/gus/gus_irq.c 1.5 -> 1.6 # drivers/video/i810/i810.h 1.6 -> 1.7 # arch/v850/kernel/entry.S 1.7 -> 1.11 # drivers/serial/68328serial.h 1.3 -> 1.4 # net/ax25/ax25_ds_timer.c 1.9 -> 1.11 # arch/m68knommu/mm/memory.c 1.1 -> 1.2 # drivers/mtd/afs.c 1.2 -> 1.3 # drivers/net/setup.c 1.13 -> (deleted) # drivers/scsi/aic7xxx/aic79xx.reg 1.10 -> 1.12 # sound/pci/ac97/ac97_patch.c 1.10 -> 1.13 # net/ipv4/tcp_timer.c 1.13 -> 1.15 # drivers/mtd/maps/uclinux.c 1.2 -> 1.3 # drivers/media/video/Kconfig 1.6 -> 1.7 # include/linux/mtd/partitions.h 1.2 -> 1.3 # drivers/net/bonding/bond_main.c 1.22 -> 1.23 # net/atm/raw.c 1.3 -> 1.4 # drivers/usb/core/Kconfig 1.2 -> 1.3 # fs/jffs2/scan.c 1.9 -> 1.10 # drivers/pci/pool.c 1.12 -> 1.13 # net/ipv4/netfilter/ipt_owner.c 1.8 -> 1.9 # net/ipv6/addrconf.c 1.45 -> 1.50 # drivers/char/agp/isoch.c 1.7 -> 1.8 # crypto/Kconfig 1.14 -> 1.16 # drivers/bluetooth/hci_usb.c 1.28 -> 1.29 # drivers/char/moxa.c 1.18 -> 1.19 # drivers/hotplug/cpqphp_pci.c 1.18 -> 1.21 drivers/pci/hotplug/cpqphp_pci.c (moved) # drivers/scsi/3w-xxxx.c 1.32 -> 1.33 # drivers/usb/input/usbmouse.c 1.25 -> 1.26 # sound/pci/ali5451/ali5451.c 1.26 -> 1.28 # net/ax25/ax25_subr.c 1.6 -> 1.8 # drivers/mtd/maps/autcpu12-nvram.c 1.2 -> 1.3 # drivers/mtd/maps/sc520cdp.c 1.3 -> 1.4 # net/ipv4/icmp.c 1.30 -> 1.31 # drivers/net/ppp_generic.c 1.30 -> 1.32 # net/sctp/ulpqueue.c 1.22 -> 1.24 # sound/core/pcm_sgbuf.c 1.11 -> (deleted) # arch/ppc/8xx_io/fec.c 1.13 -> 1.16 # arch/sparc64/prom/console.c 1.1 -> 1.2 # arch/ppc/kernel/setup.c 1.38 -> 1.39 # include/linux/netdevice.h 1.38 -> 1.40 # drivers/net/tokenring/madgemc.c 1.14 -> 1.15 # drivers/isdn/hisax/st5481_init.c 1.8 -> 1.9 # drivers/macintosh/apm_emu.c 1.6 -> 1.7 # drivers/usb/Makefile 1.43 -> 1.45 # scripts/kconfig/gconf.c 1.3 -> 1.4 # sound/isa/azt2320.c 1.10 -> 1.12 # crypto/sha512.c 1.1 -> 1.2 # fs/nfs/unlink.c 1.7 -> 1.8 # arch/ia64/Kconfig 1.21 -> 1.22 # drivers/scsi/BusLogic.c 1.19 -> 1.20 # drivers/mtd/maps/solutionengine.c 1.2 -> 1.3 # drivers/hotplug/cpqphp_sysfs.c 1.8 -> 1.9 drivers/pci/hotplug/cpqphp_sysfs.c (moved) # net/x25/af_x25.c 1.25 -> 1.27 # include/asm-ppc64/mmzone.h 1.10 -> 1.11 # arch/ia64/lib/Makefile 1.16 -> 1.17 # include/asm-sparc/thread_info.h 1.4 -> 1.5 # arch/ppc/kernel/syscalls.c 1.9 -> 1.11 # drivers/scsi/arm/ecoscsi.c 1.16 -> 1.18 # drivers/atm/iphase.c 1.21 -> 1.22 # drivers/pnp/pnpbios/proc.c 1.8 -> 1.9 # sound/usb/usbmixer_maps.c 1.2 -> 1.3 # sound/core/sound_oss.c 1.5 -> 1.6 # drivers/pci/bus.c 1.4 -> 1.6 # sound/core/info.c 1.26 -> 1.28 # drivers/usb/input/usbkbd.c 1.29 -> 1.30 # drivers/char/sh-sci.c 1.19 -> 1.21 # sound/ppc/keywest.c 1.8 -> 1.9 # include/asm-cris/bug.h 1.1 -> 1.2 # drivers/char/selection.c 1.4 -> 1.5 # net/appletalk/aarp.c 1.10 -> 1.11 # include/linux/raid/linear.h 1.4 -> 1.5 # include/linux/compat_ioctl.h 1.3 -> 1.4 # drivers/net/arcnet/arc-rawmode.c 1.4 -> 1.5 # drivers/net/sungem.c 1.36 -> 1.37 # drivers/serial/68360serial.c 1.12 -> 1.13 # arch/x86_64/pci/x86-64.c 1.6 -> 1.7 # arch/alpha/lib/Makefile 1.14 -> 1.15 # drivers/net/tokenring/proteon.c 1.2 -> 1.3 # arch/sparc/lib/Makefile 1.5 -> 1.6 # include/linux/bitops.h 1.3 -> 1.4 # drivers/video/radeonfb.c 1.28 -> 1.29 # drivers/net/ns83820.c 1.25 -> 1.26 # drivers/block/cciss.c 1.81 -> 1.82 # arch/um/drivers/pcap_kern.c 1.2 -> 1.3 # arch/ppc/platforms/prep_pci.c 1.19 -> 1.20 # drivers/net/wireless/orinoco_plx.c 1.10 -> 1.11 # lib/zlib_inflate/inffast.c 1.1 -> 1.4 # drivers/net/wireless/airport.c 1.13 -> 1.14 # drivers/usb/serial/io_ti.c 1.17 -> 1.18 # drivers/macintosh/macserial.c 1.21 -> 1.24 # drivers/parport/parport_pc.c 1.38 -> 1.39 # drivers/mtd/maps/dbox2-flash.c 1.3 -> 1.4 # security/root_plug.c 1.2 -> 1.3 # drivers/net/wireless/netwave_cs.c 1.16.1.1 -> 1.18 # drivers/usb/gadget/ether.c 1.4 -> 1.5 # drivers/net/hamradio/mkiss.c 1.10 -> 1.11 # drivers/serial/68328serial.c 1.8 -> 1.9 # net/rose/rose_route.c 1.7 -> 1.9 # net/atm/clip.c 1.12 -> 1.13 # drivers/net/tokenring/lanstreamer.c 1.17 -> 1.19 # include/asm-ppc64/topology.h 1.7 -> 1.8 # drivers/mtd/maps/Kconfig 1.4 -> 1.6 # net/rose/rose_subr.c 1.7 -> 1.9 # arch/m68knommu/platform/68328/pilot/crt0_rom.S 1.2 -> 1.3 # include/asm-mips64/bug.h 1.1 -> 1.2 # net/wanrouter/af_wanpipe.c 1.24 -> 1.26 # sound/core/memalloc.c 1.4.1.1 -> 1.8 # include/linux/if_wanpipe.h 1.5 -> 1.6 # net/decnet/dn_nsp_out.c 1.8 -> 1.10 # net/llc/llc_c_ac.c 1.20 -> 1.21 # sound/isa/opl3sa2.c 1.16.1.2 -> 1.19 # drivers/usb/class/audio.c 1.36 -> 1.37 # kernel/kallsyms.c 1.9 -> 1.10 # drivers/usb/net/pegasus.h 1.24 -> 1.25 # arch/ppc64/kernel/Makefile 1.23 -> 1.24 # net/x25/x25_in.c 1.10 -> 1.12 # drivers/mtd/maps/ocelot.c 1.3 -> 1.4 # arch/ppc64/lib/copyuser.S 1.3 -> 1.4 # include/linux/msdos_fs_i.h 1.4 -> 1.6 # include/linux/mtd/jedec.h 1.2 -> 1.3 # drivers/usb/serial/empeg.c 1.37 -> 1.39 # drivers/md/dm-table.c 1.14 -> 1.19 # arch/ppc/kernel/signal.c 1.22 -> 1.23 # arch/ppc/kernel/head_4xx.S 1.13 -> 1.14 # include/asm-x86_64/bug.h 1.1 -> 1.2 # scripts/kconfig/confdata.c 1.4 -> 1.9 # drivers/usb/net/pegasus.c 1.46 -> 1.48 # arch/ppc/Kconfig 1.21 -> 1.22 # drivers/scsi/esp.c 1.26 -> 1.27 # drivers/md/dm-target.c 1.8 -> 1.10 # net/ipv4/ip_output.c 1.36 -> 1.37 # drivers/scsi/pcmcia/nsp_cs.c 1.21 -> 1.22 # drivers/net/tokenring/3c359.c 1.8 -> 1.9 # drivers/scsi/aic7xxx/aic79xx_seq.h_shipped 1.10 -> 1.13 # include/linux/raid/raid0.h 1.2 -> 1.4 # drivers/scsi/wd7000.c 1.24 -> 1.25 # drivers/scsi/advansys.h 1.10 -> 1.11 # drivers/parport/parport_cs.c 1.7 -> 1.8 # arch/ppc64/kernel/iSeries_pci.c 1.10 -> 1.11 # arch/mips64/arc/Makefile 1.5 -> 1.6 # drivers/usb/storage/datafab.c 1.15 -> 1.16 # drivers/pcmcia/pci_socket.c 1.17 -> 1.18 # net/bridge/br_if.c 1.15 -> 1.16 # fs/inode.c 1.96 -> 1.97 # drivers/scsi/arm/eesox.c 1.27 -> 1.28 # arch/ia64/kernel/smp.c 1.24 -> 1.25 # drivers/serial/sunzilog.c 1.30 -> 1.31 # drivers/hotplug/acpiphp.h 1.4 -> 1.5 drivers/pci/hotplug/acpiphp.h (moved) # drivers/base/class.c 1.28.1.1 -> 1.35 # net/ipv4/route.c 1.61 -> 1.62 # drivers/scsi/imm.c 1.20 -> 1.22 # drivers/scsi/aic7xxx/aic79xx_reg.h_shipped 1.10 -> 1.13 # drivers/usb/image/hpusbscsi.c 1.26 -> 1.29 # drivers/mtd/maps/rpxlite.c 1.5 -> 1.6 # drivers/net/sk98lin/h/skdrv2nd.h 1.3 -> 1.4 # drivers/scsi/aic7xxx/aic7xxx.reg 1.9 -> 1.10 # arch/v850/kernel/mach.h 1.2 -> 1.3 # drivers/block/acsi.c 1.50 -> 1.51 # include/asm-ppc64/system.h 1.17 -> 1.18 # drivers/char/ip2/i2lib.c 1.6 -> 1.7 # include/linux/hippidevice.h 1.2 -> 1.3 # drivers/usb/storage/freecom.c 1.25 -> 1.26 # drivers/block/scsi_ioctl.c 1.27 -> 1.29 # drivers/scsi/qla1280.h 1.15 -> 1.18 # drivers/base/memblk.c 1.7 -> 1.8 # include/sound/core.h 1.22 -> 1.25 # drivers/mtd/chips/jedec_probe.c 1.5 -> 1.7 # fs/jffs2/file.c 1.19 -> 1.20 # net/appletalk/ddp.c 1.23 -> 1.25 # arch/i386/pci/irq.c 1.23 -> 1.24 # arch/alpha/kernel/asm-offsets.c 1.9 -> 1.10 # include/linux/isdn.h 1.81 -> 1.83 # arch/ppc64/kernel/ioctl32.c 1.32 -> 1.33 # drivers/char/amiserial.c 1.21 -> 1.22 # drivers/message/fusion/mptscsih.h 1.16 -> 1.17 # drivers/scsi/qla1280.c 1.33 -> 1.37 # arch/arm/mach-integrator/irq.c 1.4 -> (deleted) # include/linux/cyclades.h 1.5 -> 1.6 # sound/drivers/mpu401/Makefile 1.12 -> 1.15 # arch/mips64/sgi-ip32/ip32-pci.c 1.6 -> 1.7 # arch/ppc/platforms/chrp_pci.c 1.12 -> 1.13 # sound/core/pcm.c 1.13.1.1 -> 1.15 # drivers/scsi/aic7xxx/aic7xxx_inline.h 1.10 -> 1.11 # drivers/pci/access.c 1.5 -> 1.6 # drivers/char/riscom8.h 1.1 -> 1.2 # drivers/net/wan/sdla.c 1.10 -> 1.12 # drivers/macintosh/adb.c 1.19 -> 1.20 # arch/ppc/platforms/Makefile 1.17 -> 1.18 # drivers/mtd/maps/cdb89712.c 1.2 -> 1.3 # drivers/video/pm2fb.c 1.20 -> 1.21 # include/asm-sparc/bug.h 1.2 -> 1.3 # sound/ppc/pmac.c 1.13 -> 1.15 # drivers/net/wireless/orinoco.c 1.23 -> 1.24 # fs/msdos/namei.c 1.27 -> 1.28 # net/rose/rose_out.c 1.4 -> 1.5 # drivers/hotplug/ibmphp_core.c 1.26 -> 1.32 drivers/pci/hotplug/ibmphp_core.c (moved) # Documentation/scsi/dc395x.txt 1.1 -> 1.2 # sound/pci/ice1712/envy24ht.h 1.2 -> 1.3 # drivers/mtd/maps/edb7312.c 1.2 -> 1.3 # drivers/usb/image/microtek.c 1.29 -> 1.31 # arch/arm/mach-sa1100/jornada720.c 1.11 -> 1.12 # include/asm-ppc/ipc.h 1.3 -> 1.4 # lib/zlib_inflate/inftrees.h 1.1 -> 1.3 # net/core/iovec.c 1.5 -> 1.9 # arch/arm/mach-integrator/mm.c 1.4 -> (deleted) # drivers/char/ip2main.c 1.31 -> 1.33 # arch/ppc64/boot/main.c 1.6 -> 1.7 # fs/jffs2/nodelist.h 1.8 -> 1.9 # Documentation/kernel-parameters.txt 1.21 -> 1.23 # net/core/rtnetlink.c 1.14 -> 1.15 # net/bluetooth/bnep/sock.c 1.10 -> 1.11 # net/ipv4/netfilter/ip_queue.c 1.13 -> 1.14 # arch/ppc64/kernel/pSeries_pci.c 1.23 -> 1.24 # net/netrom/nr_subr.c 1.6 -> 1.8 # drivers/mtd/nand/nand.c 1.2 -> 1.3 # drivers/scsi/sym53c8xx_2/sym_glue.c 1.20.1.1 -> 1.22 # net/atm/common.c 1.25 -> 1.27 # net/sctp/socket.c 1.69 -> 1.71 # drivers/scsi/tmscsim.c 1.19 -> 1.20 # arch/ppc/vmlinux.lds.S 1.19 -> 1.20 # arch/mips/sni/pci.c 1.7 -> 1.8 # drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped 1.11 -> 1.12 # drivers/net/wireless/Makefile 1.10 -> 1.12 # (new) -> 1.1 arch/arm26/boot/compressed/hw-bse.c # (new) -> 1.1 sound/pcmcia/Makefile # (new) -> 1.2 sound/pci/ice1712/ak4xxx.c # (new) -> 1.1 drivers/mtd/devices/doc2001plus.c # (new) -> 1.1 include/asm-arm26/socket.h # (new) -> 1.1 arch/arm26/lib/strchr.S # (new) -> 1.1 include/asm-arm26/ipcbuf.h # (new) -> 1.1 include/asm-arm26/memory.h # (new) -> 1.1 include/asm-arm26/mmu_context.h # (new) -> 1.1 arch/arm26/lib/gcclib.h # (new) -> 1.1 include/asm-arm26/parport.h # (new) -> 1.1 include/asm-arm26/types.h # (new) -> 1.1 sound/pci/vx222/vx222_ops.c # (new) -> 1.1 include/linux/ip6_tunnel.h # (new) -> 1.1 arch/arm26/machine/small_page.c # (new) -> 1.1 include/asm-arm26/linkage.h # (new) -> 1.1 include/asm-arm26/calls.h # (new) -> 1.1 include/asm-arm26/resource.h # (new) -> 1.1 drivers/mtd/mtd_blkdevs.c # (new) -> 1.1 include/asm-arm26/fpstate.h # (new) -> 1.1 sound/pcmcia/vx/vxp_mixer.c # (new) -> 1.1 include/asm-arm26/delay.h # (new) -> 1.1 arch/arm26/lib/setbit.S # (new) -> 1.1 arch/arm26/nwfpe/softfloat-specialize # (new) -> 1.1 include/asm-arm26/mach-types.h # (new) -> 1.2 drivers/mtd/maps/map_funcs.c # (new) -> 1.1 arch/arm26/boot/compressed/ll_char_wr.S # (new) -> 1.1 include/asm-arm26/mman.h # (new) -> 1.1 sound/pcmcia/vx/vx_entry.c # (new) -> 1.1 drivers/mtd/devices/ms02-nv.c # (new) -> 1.1 include/asm-arm26/unaligned.h # (new) -> 1.1 arch/arm26/lib/io-readsw-armv3.S # (new) -> 1.1 arch/arm/common/platform.c # (new) -> 1.1 sound/pcmcia/vx/Makefile # (new) -> 1.1 include/sound/vx_core.h # (new) -> 1.1 include/asm-arm26/softirq.h # (new) -> 1.1 arch/arm26/lib/kbd.c # (new) -> 1.1 drivers/mtd/inftlmount.c # (new) -> 1.1 include/asm-arm26/statfs.h # (new) -> 1.1 net/ipv6/ip6_tunnel.c # (new) -> 1.1 include/asm-arm26/current.h # (new) -> 1.1 arch/arm26/lib/floppydma.S # (new) -> 1.1 sound/drivers/vx/vx_pcm.c # (new) -> 1.1 arch/arm26/lib/io-writesw-armv3.S # (new) -> 1.1 include/asm-arm26/siginfo.h # (new) -> 1.1 drivers/mtd/inftlcore.c # (new) -> 1.1 arch/arm26/vmlinux-armo.lds.in # (new) -> 1.1 arch/arm26/lib/copy_page.S # (new) -> 1.1 include/asm-arm26/pgtable.h # (new) -> 1.1 include/asm-arm26/sembuf.h # (new) -> 1.1 sound/drivers/vx/Makefile # (new) -> 1.1 arch/arm26/lib/clearbit.S # (new) -> 1.1 include/asm-arm26/limits.h # (new) -> 1.1 include/asm-arm26/string.h # (new) -> 1.2 sound/isa/sscape.c # (new) -> 1.1 arch/arm26/boot/compressed/vmlinux.lds.in # (new) -> 1.1 include/asm-arm26/uaccess.h # (new) -> 1.1 include/asm-arm26/signal.h # (new) -> 1.1 arch/arm26/kernel/entry.S # (new) -> 1.1 arch/arm26/lib/csumpartial.S # (new) -> 1.1 include/asm-arm26/user.h # (new) -> 1.1 drivers/net/wireless/orinoco_tmd.c # (new) -> 1.1 drivers/mtd/nand/autcpu12.c # (new) -> 1.1 include/asm-arm26/elf.h # (new) -> 1.1 drivers/mtd/maps/lasat.c # (new) -> 1.1 include/asm-arm26/serial.h # (new) -> 1.1 arch/arm26/nwfpe/entry.S # (new) -> 1.1 sound/pcmcia/vx/vxpocket.c # (new) -> 1.1 drivers/mtd/maps/h720x-flash.c # (new) -> 1.1 arch/arm26/nwfpe/fpa11.c # (new) -> 1.1 include/asm-arm26/div64.h # (new) -> 1.1 arch/arm26/kernel/setup.c # (new) -> 1.1 include/asm-arm26/hardware.h # (new) -> 1.1 include/asm-arm26/ucontext.h # (new) -> 1.1 arch/arm26/machine/irq.c # (new) -> 1.1 arch/arm26/kernel/time-acorn.c # (new) -> 1.1 sound/pcmcia/vx/vxp440.c # (new) -> 1.1 drivers/mtd/maps/dilnetpc.c # (new) -> 1.1 arch/arm26/kernel/asm-offsets.c # (new) -> 1.1 arch/arm26/nwfpe/single_cpdo.c # (new) -> 1.1 sound/i2c/other/Makefile # (new) -> 1.1 arch/arm26/boot/compressed/Makefile # (new) -> 1.1 arch/arm26/mm/Makefile # (new) -> 1.1 include/asm-arm26/ptrace.h # (new) -> 1.1 include/asm-arm26/setup.h # (new) -> 1.1 include/asm-arm26/bugs.h # (new) -> 1.1 include/asm-arm26/hdreg.h # (new) -> 1.1 sound/pcmcia/vx/vxp_ops.c # (new) -> 1.1 arch/arm26/machine/arch.c # (new) -> 1.1 include/asm-arm26/smp.h # (new) -> 1.1 include/asm-arm26/sockios.h # (new) -> 1.1 arch/arm26/nwfpe/fpmodule.inl # (new) -> 1.1 include/asm-arm26/thread_info.h # (new) -> 1.1 sound/drivers/vx/vx_mixer.c # (new) -> 1.2 drivers/mtd/maps/amd76xrom.c # (new) -> 1.1 drivers/mtd/maps/nettel.c # (new) -> 1.1 arch/arm26/kernel/init_task.c # (new) -> 1.1 drivers/net/wireless/atmel.c # (new) -> 1.1 sound/drivers/opl4/opl4_mixer.c # (new) -> 1.1 arch/arm26/kernel/signal.c # (new) -> 1.1 arch/arm26/lib/udivdi3.c # (new) -> 1.1 arch/arm26/defconfig # (new) -> 1.1 arch/arm26/boot/compressed/misc.c # (new) -> 1.1 arch/arm26/kernel/semaphore.c # (new) -> 1.1 drivers/mtd/mtdblock.h # (new) -> 1.1 arch/arm26/nwfpe/Makefile # (new) -> 1.1 sound/pcmcia/vx/vxpocket.h # (new) -> 1.1 sound/drivers/vx/vx_uer.c # (new) -> 1.1 drivers/mtd/maps/mbx860.c # (new) -> 1.1 arch/arm26/mm/fault.c # (new) -> 1.1 arch/arm26/lib/testchangebit.S # (new) -> 1.1 arch/arm26/nwfpe/softfloat-macros # (new) -> 1.1 arch/m68knommu/platform/5307/ints.c # (new) -> 1.1 include/asm-arm26/ioc.h # (new) -> 1.1 arch/arm26/lib/io-writesb.S # (new) -> 1.1 arch/arm26/machine/oldlatches.c # (new) -> 1.1 include/asm-arm26/tlbflush.h # (new) -> 1.1 include/asm-arm26/sizes.h # (new) -> 1.1 drivers/mtd/chips/cfi_cmdset_0020.c # (new) -> 1.1 sound/pci/ice1712/aureon.c # (new) -> 1.1 sound/drivers/vx/vx_hwdep.c # (new) -> 1.1 drivers/mtd/maps/arctic-mtd.c # (new) -> 1.1 include/asm-arm26/uncompress.h # (new) -> 1.1 arch/arm26/lib/ashldi3.c # (new) -> 1.1 drivers/mtd/nand/nand_ids.c # (new) -> 1.1 arch/arm26/kernel/armksyms.c # (new) -> 1.1 include/asm-arm26/hardirq.h # (new) -> 1.1 include/asm-arm26/xor.h # (new) -> 1.1 sound/drivers/vx/vx_cmd.h # (new) -> 1.1 include/net/ip6_tunnel.h # (new) -> 1.1 sound/parisc/harmony.c # (new) -> 1.1 arch/arm26/nwfpe/fpa11_cprt.c # (new) -> 1.1 include/asm-arm26/kmap_types.h # (new) -> 1.1 arch/arm26/mm/extable.c # (new) -> 1.1 include/asm-arm26/checksum.h # (new) -> 1.1 include/asm-arm26/fiq.h # (new) -> 1.1 include/asm-arm26/rmap.h # (new) -> 1.1 arch/arm26/Makefile # (new) -> 1.1 include/asm-arm26/namei.h # (new) -> 1.1 include/asm-arm26/atomic.h # (new) -> 1.1 arch/arm26/nwfpe/ARM-gcc.h # (new) -> 1.1 arch/arm26/machine/Makefile # (new) -> 1.1 arch/arm26/nwfpe/softfloat.c # (new) -> 1.1 include/asm-arm26/ecard.h # (new) -> 1.1 include/asm-arm26/keyboard.h.old # (new) -> 1.1 arch/arm26/lib/memzero.S # (new) -> 1.1 arch/arm26/kernel/Makefile # (new) -> 1.1 arch/arm26/lib/findbit.S # (new) -> 1.1 include/asm-arm26/msgbuf.h # (new) -> 1.1 arch/arm26/boot/compressed/ofw-shark.c # (new) -> 1.1 arch/arm26/boot/compressed/uncompress.h # (new) -> 1.1 sound/drivers/opl4/opl4_local.h # (new) -> 1.1 sound/drivers/opl4/opl4_synth.c # (new) -> 1.1 arch/arm26/lib/csumpartialcopy.S # (new) -> 1.1 arch/arm26/nwfpe/fpopcode.c # (new) -> 1.1 arch/i386/kernel/summit.c # (new) -> 1.1 Documentation/DocBook/gadget.tmpl # (new) -> 1.1 include/sound/opl4.h # (new) -> 1.1 drivers/net/wireless/atmel_cs.c # (new) -> 1.1 drivers/mtd/devices/ms02-nv.h # (new) -> 1.1 sound/drivers/opl4/opl4_seq.c # (new) -> 1.1 sound/pcmcia/Kconfig # (new) -> 1.1 include/asm-arm26/scatterlist.h # (new) -> 1.1 arch/arm26/kernel/ptrace.c # (new) -> 1.1 Documentation/rocket.txt # (new) -> 1.1 arch/arm26/nwfpe/extended_cpdo.c # (new) -> 1.1 arch/arm26/nwfpe/double_cpdo.c # (new) -> 1.1 sound/pci/vx222/vx222.c # (new) -> 1.1 arch/arm26/lib/testsetbit.S # (new) -> 1.1 drivers/mtd/maps/scb2_flash.c # (new) -> 1.1 include/asm-arm26/module.h # (new) -> 1.1 arch/arm26/lib/csumpartialcopyuser.S # (new) -> 1.1 include/asm-arm26/suspend.h # (new) -> 1.1 arch/arm26/lib/csumpartialcopygeneric.S # (new) -> 1.1 arch/arm26/kernel/arch.c # (new) -> 1.1 arch/arm26/machine/head.S # (new) -> 1.1 arch/arm26/lib/putuser.S # (new) -> 1.1 sound/parisc/Kconfig # (new) -> 1.1 arch/arm26/Kconfig # (new) -> 1.1 include/asm-arm26/processor.h # (new) -> 1.1 arch/arm26/kernel/sys_arm.c # (new) -> 1.1 arch/arm26/nwfpe/fpa11_cpdo.c # (new) -> 1.1 sound/pci/azt3328.c # (new) -> 1.1 arch/arm26/nwfpe/ChangeLog # (new) -> 1.1 include/asm-arm26/sysirq.h # (new) -> 1.1 include/asm-arm26/segment.h # (new) -> 1.1 arch/arm26/lib/uaccess-user.S # (new) -> 1.1 include/asm-arm26/ioctls.h # (new) -> 1.1 include/asm-arm26/io.h # (new) -> 1.1 arch/arm26/kernel/traps.c # (new) -> 1.1 include/asm-arm26/termbits.h # (new) -> 1.1 include/asm-arm26/a.out.h # (new) -> 1.1 include/asm-arm26/sigcontext.h # (new) -> 1.1 arch/arm26/lib/ecard.S # (new) -> 1.1 arch/arm26/lib/ucmpdi2.c # (new) -> 1.1 include/linux/mtd/blktrans.h # (new) -> 1.1 drivers/mtd/maps/beech-mtd.c # (new) -> 1.1 arch/arm26/nwfpe/fpa11_cpdt.c # (new) -> 1.1 include/asm-arm26/posix_types.h # (new) -> 1.1 arch/arm26/nwfpe/fpmodule.h # (new) -> 1.1 include/asm-arm26/mc146818rtc.h # (new) -> 1.1 include/asm-arm26/stat.h # (new) -> 1.1 arch/arm26/lib/memset.S # (new) -> 1.1 arch/arm26/kernel/time.c # (new) -> 1.1 include/asm-arm26/ipc.h # (new) -> 1.1 include/asm-arm26/poll.h # (new) -> 1.1 arch/arm26/lib/Makefile # (new) -> 1.1 include/asm-arm26/timex.h # (new) -> 1.1 include/asm-arm26/ioctl.h # (new) -> 1.1 drivers/mtd/maps/lubbock-flash.c # (new) -> 1.1 arch/arm26/config.in # (new) -> 1.1 arch/arm26/lib/io-readsl-armv3.S # (new) -> 1.1 include/asm-arm26/page.h # (new) -> 1.1 include/asm-arm26/pci.h # (new) -> 1.1 include/asm-arm26/floppy.h # (new) -> 1.2 include/linux/topology.h # (new) -> 1.1 include/asm-i386/mach-generic/mach_apicdef.h # (new) -> 1.1 drivers/mtd/maps/redwood.c # (new) -> 1.1 arch/arm26/machine/dma.c # (new) -> 1.1 arch/arm26/vmlinux.lds.S # (new) -> 1.1 sound/drivers/vx/vx_cmd.c # (new) -> 1.1 arch/arm26/lib/changebit.S # (new) -> 1.1 include/asm-arm26/cacheflush.h # (new) -> 1.1 arch/arm26/lib/backtrace.S # (new) -> 1.1 include/asm-arm26/mmu.h # (new) -> 1.1 arch/arm26/lib/io-readsb.S # (new) -> 1.2 include/sound/ak4xxx-adda.h # (new) -> 1.1 include/asm-arm26/fcntl.h # (new) -> 1.1 include/asm-arm26/byteorder.h # (new) -> 1.1 include/asm-arm26/irq.h # (new) -> 1.1 arch/arm26/kernel/fiq.c # (new) -> 1.1 arch/arm26/lib/lshrdi3.c # (new) -> 1.1 include/asm-arm26/termios.h # (new) -> 1.1 arch/arm26/kernel/dma.c # (new) -> 1.1 arch/arm26/boot/compressed/head.S # (new) -> 1.1 arch/arm26/kernel/compat.c # (new) -> 1.1 include/asm-arm26/procinfo.h # (new) -> 1.1 arch/arm26/lib/lib1funcs.S # (new) -> 1.1 arch/arm26/nwfpe/fpmodule.c # (new) -> 1.1 arch/arm26/nwfpe/fpopcode.h # (new) -> 1.1 arch/arm26/lib/strrchr.S # (new) -> 1.1 arch/arm26/nwfpe/fpsr.h # (new) -> 1.1 include/asm-arm26/percpu.h # (new) -> 1.1 include/asm-arm26/topology.h # (new) -> 1.1 arch/arm26/lib/memcpy.S # (new) -> 1.1 drivers/mtd/maps/ebony.c # (new) -> 1.1 sound/pci/vx222/Makefile # (new) -> 1.1 arch/arm26/lib/csumipv6.S # (new) -> 1.1 include/asm-arm26/assembler.h # (new) -> 1.1 sound/drivers/opl4/Makefile # (new) -> 1.1 include/asm-arm26/constants.h # (new) -> 1.1 arch/arm26/nwfpe/milieu.h # (new) -> 1.1 arch/arm26/boot/install.sh # (new) -> 1.1 include/asm-arm26/linux_logo.h # (new) -> 1.1 arch/arm26/lib/testclearbit.S # (new) -> 1.1 arch/arm26/kernel/process.c # (new) -> 1.1 arch/arm26/lib/io-writesl.S # (new) -> 1.1 arch/arm26/mm/proc-funcs.S # (new) -> 1.1 include/asm-arm26/dma.h # (new) -> 1.1 include/asm-arm26/irqchip.h # (new) -> 1.1 include/asm-arm26/proc-fns.h # (new) -> 1.1 arch/arm26/kernel/irq.c # (new) -> 1.1 include/asm-arm26/locks.h # (new) -> 1.2 sound/drivers/vx/vx_core.c # (new) -> 1.1 arch/arm26/mm/fault.h # (new) -> 1.1 include/linux/mtd/inftl.h # (new) -> 1.1 arch/arm26/lib/longlong.h # (new) -> 1.1 arch/arm26/Config.help # (new) -> 1.1 arch/arm26/lib/memchr.S # (new) -> 1.1 include/asm-arm26/oldlatches.h # (new) -> 1.1 include/asm-arm26/uaccess-asm.h # (new) -> 1.1 drivers/mtd/maps/tsunami_flash.c # (new) -> 1.1 sound/drivers/opl4/opl4_lib.c # (new) -> 1.1 sound/drivers/opl4/opl4_proc.c # (new) -> 1.1 arch/arm26/kernel/ptrace.h # (new) -> 1.1 arch/arm26/nwfpe/fpa11.inl # (new) -> 1.1 include/asm-arm26/ian_char.h # (new) -> 1.1 arch/arm26/mm/init.c # (new) -> 1.2 sound/i2c/other/ak4xxx-adda.c # (new) -> 1.1 include/asm-arm26/bitops.h # (new) -> 1.1 fs/compat_ioctl.c # (new) -> 1.1 sound/pci/vx222/vx222.h # (new) -> 1.1 include/asm-arm26/arch.h # (new) -> 1.1 arch/arm26/lib/io-acorn.S # (new) -> 1.1 arch/arm26/lib/muldi3.c # (new) -> 1.1 sound/parisc/Makefile # (new) -> 1.1 arch/arm26/lib/delay.S # (new) -> 1.1 arch/arm26/lib/ashrdi3.c # (new) -> 1.1 include/asm-arm26/map.h # (new) -> 1.1 include/asm-arm26/param.h # (new) -> 1.1 include/asm-arm26/errno.h # (new) -> 1.1 include/asm-arm26/semaphore-helper.h # (new) -> 1.1 arch/arm26/mm/mm-memc.c # (new) -> 1.1 include/asm-arm26/bug.h # (new) -> 1.1 arch/arm26/lib/getuser.S # (new) -> 1.1 include/asm-arm26/shmparam.h # (new) -> 1.1 include/asm-arm26/semaphore.h # (new) -> 1.1 include/asm-arm26/spinlock.h # (new) -> 1.1 drivers/mtd/nand/edb7312.c # (new) -> 1.1 sound/pci/ice1712/aureon.h # (new) -> 1.1 include/asm-arm26/system.h # (new) -> 1.1 arch/arm26/nwfpe/fpa11.h # (new) -> 1.1 include/asm-arm26/leds.h # (new) -> 1.1 drivers/mtd/maps/pb1xxx-flash.c # (new) -> 1.1 include/asm-arm26/shmbuf.h # (new) -> 1.1 include/asm-arm26/tlb.h # (new) -> 1.1 arch/arm26/ACKNOWLEDGEMENTS # (new) -> 1.1 sound/pci/azt3328.h # (new) -> 1.1 drivers/mtd/maps/ich2rom.c # (new) -> 1.1 include/asm-arm26/ide.h # (new) -> 1.1 include/asm-arm26/pgalloc.h # (new) -> 1.1 include/asm-arm26/unistd.h # (new) -> 1.1 sound/drivers/opl4/yrw801.c # (new) -> 1.1 arch/arm26/boot/Makefile # (new) -> 1.1 arch/arm26/kernel/ecard.c # (new) -> 1.1 include/asm-arm26/cache.h # (new) -> 1.1 arch/arm26/lib/uaccess-kernel.S # (new) -> 1.1 arch/arm26/nwfpe/softfloat.h # # The following is the BitKeeper ChangeSet Log # -------------------------------------------- # 03/05/26 torvalds@home.transmeta.com 1.1229.8.33 # Linux v2.5.70 # -------------------------------------------- # 03/05/27 davej@codemonkey.org.uk 1.1229.9.1 # [AGPGART] Compilation fix. # Death of a typedef in an earlier cset broke i810fb # -------------------------------------------- # 03/05/27 davej@codemonkey.org.uk 1.1229.9.2 # [AGPGART] Remove useless early agp_init() from i810fb # agp_init() just printk's a banner. This is unnecessary at this early stage. # -------------------------------------------- # 03/05/26 jejb@raven.il.steeleye.com 1.1229.10.1 # Automerge # -------------------------------------------- # 03/05/26 jejb@raven.il.steeleye.com 1.1229.8.34 # Merge raven.il.steeleye.com:/home/jejb/BK/scsi-misc-2.5 # into raven.il.steeleye.com:/home/jejb/BK/scsi-for-linus-2.5 # -------------------------------------------- # 03/05/27 davej@tetrachloride.(none) 1.1229.11.1 # Merge tetrachloride.(none):/mnt/raid/src/kernel/2.5/bk-linus # into tetrachloride.(none):/mnt/raid/src/kernel/2.5/agpgart # -------------------------------------------- # 03/05/26 jejb@raven.il.steeleye.com 1.1229.8.35 # Merge raven.il.steeleye.com:/mnt1/jejb/BK/scsi-aic-2.5 # into raven.il.steeleye.com:/home/jejb/BK/scsi-for-linus-2.5 # -------------------------------------------- # 03/05/26 akpm@digeo.com 1.1229.12.1 # [PATCH] truncate and timestamps # # This patch will put us back to the 2.4 behaviour while preserving the # truncation speedup. It's a bit dopey (why do the timestamp update in # the fs at all?) but changing this stuff tends to cause subtle # problems. # -------------------------------------------- # 03/05/27 paulus@samba.org 1.1241 # Merge samba.org:/home/paulus/kernel/linux-2.5 # into samba.org:/home/paulus/kernel/for-linus-ppc # -------------------------------------------- # 03/05/26 acme@conectiva.com.br 1.1229.13.1 # o wanrouter: fix bug introduced by latest namespace fix # # Thanks to Adrian Bunk for reporting. # -------------------------------------------- # 03/05/26 torvalds@home.transmeta.com 1.1229.8.36 # Merge bk://linux-scsi.bkbits.net/scsi-for-linus-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/05/26 bcollins@debian.org 1.1229.8.37 # [PATCH] Update IEEE1394 (r939) # # - Adds fragementation support to eth1394 # - Fix race conditition in packet completion task call # - Fix lack of proper logic in tlabel allocation # - Fix brokeness introduced by "stanford checker fixes for memset" in # ohci1394 # - Add trivial PM resume callback in ohci1394 to support sleep/resume. # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.38 # [PATCH] callout removal: ircomm_tty # # callout removal: ircomm_tty # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.39 # [PATCH] callout removal: mcfserial # # callout removal: mcfserial # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.40 # [PATCH] callout removal: 68360 # # callout removal: 68360 # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.41 # [PATCH] callout removal: tc_zs # # callout removal: tc_zs # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.42 # [PATCH] callout removal: sgiserial # # callout removal: sgiserial # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.43 # [PATCH] callout removal: aurora # # callout removal: aurora # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.44 # [PATCH] callout removal: stallion # # callout removal: stallion # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.45 # [PATCH] callout removal: rio # # callout removal: rio # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.46 # [PATCH] callout removal: sx # # callout removal: sx # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.47 # [PATCH] callout removal: specialix # # callout removal: specialix # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.48 # [PATCH] callout removal: a2232 # # callout removal: a2232 # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.49 # [PATCH] callout removal: riscom8 # # callout removal: riscom8 # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.50 # [PATCH] callout removal: istallion # # callout removal: istallion # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.51 # [PATCH] callout removal: sci # # callout removal: sci # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.52 # [PATCH] callout removal: vme # # callout removal: vme # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.53 # [PATCH] callout removal: tx3912 # # callout removal: tx3912 # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.54 # [PATCH] callout removal: generic_serial # # callout removal: generic_serial # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.55 # [PATCH] callout removal: isicom # # callout removal: isicom # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.56 # [PATCH] callout removal: 68328 # # callout removal: 68328 # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.57 # [PATCH] callout removal: chdlc # # callout removal: chdlc # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.58 # [PATCH] callout removal: pc300 # # callout removal: pc300 # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.59 # [PATCH] callout removal: macserial # # callout removal: macserial # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.60 # [PATCH] callout removal: synclink_cs # # callout removal: synclink_cs # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.61 # [PATCH] callout removal: synclinkmp # # callout removal: synclinkmp # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.62 # [PATCH] callout removal: synclink # # callout removal: synclink # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.63 # [PATCH] callout removal: serial167 # # callout removal: serial167 # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.64 # [PATCH] callout removal: rocket # # callout removal: rocket # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.65 # [PATCH] callout removal: pcxx # # callout removal: pcxx # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.66 # [PATCH] callout removal: mxser # # callout removal: mxser # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.67 # [PATCH] callout removal: moxa # # callout removal: moxa # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.68 # [PATCH] callout removal: ip2 # # callout removal: ip2 # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.69 # [PATCH] callout removal: esp # # callout removal: esp # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.70 # [PATCH] callout removal: epca # # callout removal: epca # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.71 # [PATCH] callout removal: dz # # callout removal: dz # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.72 # [PATCH] callout removal: cyclades # # callout removal: cyclades # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.73 # [PATCH] callout removal: amiserial # # callout removal: amiserial # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.74 # [PATCH] callout removal: 8xx_uart # # callout removal: 8xx_uart # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.75 # [PATCH] callout removal: 8260_uart # # callout removal: 8260_uart # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.76 # [PATCH] callout removal: sicc # # callout removal: sicc # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.77 # [PATCH] callout removal: vacserial # # callout removal: vacserial # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.78 # [PATCH] callout removal: mips # # callout removal: mips # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.79 # [PATCH] callout removal: simserial # # callout removal: simserial # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.80 # [PATCH] callout removal: cris # # callout removal: cris # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.81 # [PATCH] callout removal: isdn # # callout removal: isdn # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.82 # [PATCH] callout removal: cleanup # # misc cleanup - switched to standard constant names for .subtype in the # drivers that had private equivalents, removed unused ->callout_termios # and friends from the last places where they were defined. # -------------------------------------------- # 03/05/26 viro@www.linux.org.uk 1.1229.8.83 # [PATCH] callout removal: callout is gone # # OK, that's it - no callout drivers left, so we drop the warning from # tty_open() and kill the code that handles them in /proc/tty/drivers. # -------------------------------------------- # 03/05/26 neilb@cse.unsw.edu.au 1.1229.8.84 # [PATCH] md: Export bio_split_pool for md to use. # -------------------------------------------- # 03/05/26 neilb@cse.unsw.edu.au 1.1229.8.85 # [PATCH] md: Use new single page bio splitting for raid0 and linear # # Sometimes raid0 and linear are required to take a single page bio that # spans two devices. We use bio_split to split such a bio into two. # # The the same time, bio.h is included by linux/raid/md.h so # we don't included it elsewhere anymore. # # We also modify the mergeable_bvec functions to allow a bvec # that doesn't fit if it is the first bvec to be added to # the bio, and be careful never to return a negative length from a # bvec_mergable funciton. # -------------------------------------------- # 03/05/26 neilb@cse.unsw.edu.au 1.1229.8.86 # [PATCH] md: Handle concurrent failure of two drives in raid5 # # If two drives both fail during a write request, raid5 doesn't # cope properly and will eventually oops. # # With this patch, blocks that have already been 'written' # are failed when double drive failure is noticed, as well as # blocks that are about to be written. # -------------------------------------------- # 03/05/26 neilb@cse.unsw.edu.au 1.1229.8.87 # [PATCH] md: Improve test for which raid1 device doesn't need to be written to. # # Instead of testing last_used (which could change in unusual circumstances) we # test against the bdev that we read frmo, and don't write back to there. # -------------------------------------------- # 03/05/26 neilb@cse.unsw.edu.au 1.1229.8.88 # [PATCH] md: Fix simple off-by-one error in md driver. # -------------------------------------------- # 03/05/26 neilb@cse.unsw.edu.au 1.1229.8.89 # [PATCH] md: Get rid of vmalloc/vfree from raid0 # # raid0 currently uses vmalloc instead of kmalloc. This patch # changes to kmalloc. # There is one allocation that can occasionally be very large - the hash_table. # A subsequent patch will address this issue. # -------------------------------------------- # 03/05/26 neilb@cse.unsw.edu.au 1.1229.8.90 # [PATCH] md: Always allow a half-built md array to be stopped. # # When starting an array fails, we have to tear it down, but # in some circumstances (particularly autostart_array) the # reference count will be 3, so do_md_stop will fail. # # With this patch we only worry about the number of users # is the array has been fully started. # -------------------------------------------- # 03/05/26 neilb@cse.unsw.edu.au 1.1229.8.91 # [PATCH] md: Improve raid0 mapping code to simplify and reduce mem usage. # # To cope with a raid0 array with differing sized devices, # raid0 divides an array into "strip zones". # The first zone covers the start of all devices, upto an offset # equal to the size of the smallest device. # # The second strip zone covers the remaining devices upto the size of the # next smallest size, etc. # # In order to determing which strip zone a given address is in, # the array is logically divided into slices the size of the smallest # zone, and a 'hash' table is created listing the first and, if relevant, # second zone in each slice. # # As the smallest slice can be very small (imagine an array with a # 76G drive and a 75.5G drive) this hash table can be rather large. # # With this patch, we limit the size of the hash table to one page, # at the possible cost of making several probes into the zone list # before we find the correct zone. # # We also cope with the possibility that a zone could be larger than # a 32bit sector address would allow. # -------------------------------------------- # 03/05/26 neilb@cse.unsw.edu.au 1.1229.8.92 # [PATCH] md: Remove dependancy on MD_SB_DISKS from multipath # # Multipath has a dependancy on MD_SB_DISKS which is no # longer authoritative. We change it to use a separately # allocated array. # -------------------------------------------- # 03/05/26 neilb@cse.unsw.edu.au 1.1229.8.93 # [PATCH] md: Remove dependancy on MD_SB_DISKS from raid5 # # One embeded array gets moved to end of structure and # sized dynamically. # -------------------------------------------- # 03/05/26 neilb@cse.unsw.edu.au 1.1229.8.94 # [PATCH] md: Remove dependancy on MD_SB_DISKS from raid0 # # Arrays with type-1 superblock can have more than # MD_SB_DISKS, so we remove the dependancy on that number from # raid0, replacing several fixed sized arrays with one # dynamically allocated array. # -------------------------------------------- # 03/05/26 neilb@cse.unsw.edu.au 1.1229.8.95 # [PATCH] md: Remove MD_SB_DISKS limits from raid1 # # raid1 uses MD_SB_DISKS to size two data structures, # but the new version-1 superblock allows for more than # this number of disks (and most actual arrays use many # fewer). # This patch sizes to two arrays dynamically. # One becomes a separate kmalloced array. # The other is moved to the end of the containing structure # and appropriate extra space is allocated. # # Also, change r1buf_pool_alloc (which allocates buffers for # a mempool for doing re-sync) to not get r1bio structures # from the r1bio pool (which could exhaust the pool) but instead # to allocate them separately. # -------------------------------------------- # 03/05/26 neilb@cse.unsw.edu.au 1.1229.8.96 # [PATCH] md: Remove dependance on MD_SB_DISKS in linear personality # # Linear uses one array sized by MD_SB_DISKS inside a structure. # We move it to the end of the structure, declare it as size 0, # and arrange for approprate extra space to be allocated on # structure allocation. # -------------------------------------------- # 03/05/26 neilb@cse.unsw.edu.au 1.1229.8.97 # [PATCH] md: Replace bdev_partition_name with calls to bdevname # -------------------------------------------- # 03/05/26 gerg@snapgear.com 1.1229.8.98 # [PATCH] create m68knommu/coldfire specific ints.c # # Create a m68knommu/ColdFire specific ints.c. It is just simpler to # have one for each sub-architecture (which means we currently need 3 # for the 3 prominant m68knommu families). Each can handle the hardware # setup differences, and there is a few at this level. # -------------------------------------------- # 03/05/26 gerg@snapgear.com 1.1229.8.99 # [PATCH] remove common m68knommu ints.c # # Remove the m68knommu common ints.c. No longer needed with each # sub-architecture now having its own. # -------------------------------------------- # 03/05/26 gerg@snapgear.com 1.1229.8.100 # [PATCH] don't compile m68knommu/kernel ints.c # # Modify m68knommu/kernel Makefile to no longer compile removed # common ints.c. # -------------------------------------------- # 03/05/26 gerg@snapgear.com 1.1229.8.101 # [PATCH] compile m68knommu/ColdFire ints.c # # Add the m68knommu/Coldfire specific ints.c to build list. # -------------------------------------------- # 03/05/27 shmulik.hen@intel.com 1.1229.14.1 # [netdrvr bonding] fix long failover in 802.3ad mode # # This patch fixes the bug reported by Jay on April 3rd regarding long # failover time when releasing the last slave in the active aggregator. The # fix, as suggested by Jay, is to follow the spec recommendation and send a # LACPDU to the partner saying this port is no longer aggregatable and # therefore trigger an immediate re-selection of a new aggregator instead of # waiting the entire expiration timeout. # -------------------------------------------- # 03/05/27 shmulik.hen@intel.com 1.1229.14.2 # [netdrvr bonding] fix ABI version control problem # # This fix makes bonding not commit to a specific ABI version if the ioctl # command is not supported by bonding. # # (It also removes the '\n' in the continuous printk reporting the link down # event in bond_mii_monitor - it got in there by mistake in our previous # patch set and caused log messages to appear funny in some situations). # -------------------------------------------- # 03/05/27 bunk@fs.tum.de 1.1229.14.3 # [wan lmc] remove 2.0.x-era code # # The patch below removes obsolete #if'd code for kernel 2.0 and 2.2 from # drivers/net/wan/lmc/* (this includes the expansion of some #define's # that were definded differently for different kernel versions). # -------------------------------------------- # 03/05/27 edward_peng@dlink.com.tw 1.1229.14.4 # [netdrvr sundance] fix flow control bug # -------------------------------------------- # 03/05/27 edward_peng@dlink.com.tw 1.1229.14.5 # [netdrvr sundance] fix another flow control bug # -------------------------------------------- # 03/05/27 jgarzik@redhat.com 1.1229.14.6 # [netdrvr eepro] update MODULE_AUTHOR per old-author request # -------------------------------------------- # 03/05/27 engebret@us.ibm.com 1.1229.14.7 # [netdrvr pcnet32] bug fixes # # I would like to see a couple of the pcnet32 changes that I think we can # agree on be put into the trees so a couple of the potential defects can be # avoided. The following patch contains just these pieces. The only # controversial one is an arbitrary change in the number of iterations in a # while loop spinning on hardware state. No matter how this is done, I am # not especially fond of this bit of code as it has no reasonable error # recovery path -- however, as a half-way, incremental solution, increasing # the polling time should help as the 100 value was certainly found to be # insufficient. 1000 may not be sufficient either, but it is certainly no # worse. # # Both of the other changes were hit in testing (and I belive the wmb() at a # customer even), so it would help reduce some debug if these go in. Any # feedback is appreciated - thanks. # -------------------------------------------- # 03/05/27 paulus@samba.org 1.1242 # Merge samba.org:/home/paulus/kernel/linux-2.5 # into samba.org:/home/paulus/kernel/for-linus-ppc # -------------------------------------------- # 03/05/26 torvalds@home.transmeta.com 1.1229.8.102 # Merge bk://kernel.bkbits.net/jgarzik/net-drivers-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/05/26 torvalds@home.transmeta.com 1.1229.8.103 # Remove a few zero-sized files, as noted by David Gibson. # -------------------------------------------- # 03/05/26 davem@nuts.ninka.net 1.1229.7.27 # Merge nuts.ninka.net:/home/davem/src/BK/network-2.5 # into nuts.ninka.net:/home/davem/src/BK/net-2.5 # -------------------------------------------- # 03/05/27 davem@nuts.ninka.net 1.1229.7.28 # Merge bk://kernel.bkbits.net/acme/net-2.5 # into nuts.ninka.net:/home/davem/src/BK/net-2.5 # -------------------------------------------- # 03/05/27 yoshfuji@linux-ipv6.org 1.1229.7.29 # [CRYPTO]: Fix compiler warnings in sha512.c # -------------------------------------------- # 03/05/27 yoshfuji@linux-ipv6.org 1.1229.7.30 # [IPV6]: Fix possible idev leakage in icmp.c # -------------------------------------------- # 03/05/27 davem@nuts.ninka.net 1.1229.7.31 # [NET]: One too many IRQ_HANDLED added to sunqe.c driver. # -------------------------------------------- # 03/05/27 yoshfuji@linux-ipv6.org 1.1229.7.32 # [IPV6]: Fix possible oops in ndisc_send_na. # -------------------------------------------- # 03/05/27 herbert@gondor.apana.org.au 1.1229.7.33 # [IPSEC]: Order SPD using priority. # -------------------------------------------- # 03/05/27 paulus@samba.org 1.1243 # Merge samba.org:/stuff/paulus/kernel/linux-2.5 # into samba.org:/stuff/paulus/kernel/for-linus-ppc # -------------------------------------------- # 03/05/27 davej@codemonkey.org.uk 1.1229.11.2 # [AGPGART] Yet another missed typedef compile fix. # -------------------------------------------- # 03/05/27 davej@tetrachloride.(none) 1.1229.8.104 # Merge tetrachloride.(none):/mnt/raid/src/kernel/2.5/bk-linus # into tetrachloride.(none):/mnt/raid/src/kernel/2.5/agpgart # -------------------------------------------- # 03/05/27 oliver@vermuden.neukum.org 1.1164.11.1 # 01-debug-cleanup.patch # -------------------------------------------- # 03/05/27 shaggy@shaggy.austin.ibm.com 1.1229.15.1 # Merge jfs@jfs.bkbits.net:linux-2.5 # into shaggy.austin.ibm.com:/shaggy/bk/jfs-2.5 # -------------------------------------------- # 03/05/27 axboe@suse.de 1.1229.16.1 # [PATCH] remove buggy BUG_ON in ide-cd # # Alan (or someone else) added a buggy BUG_ON() in ide-cd. We can address > # 32-bit just fine with 2kb block size. People are hitting this, just got # one more report today... # -------------------------------------------- # 03/05/27 torvalds@home.transmeta.com 1.1229.17.1 # Merge bk://kernel.bkbits.net/davem/net-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/05/27 cifs.adm@hostme.bitkeeper.com 1.1229.18.1 # Merge bk://linux.bkbits.net/linux-2.5 # into hostme.bitkeeper.com:/ua/repos/c/cifs/linux-2.5cifs # -------------------------------------------- # 03/05/27 stevef@smfhome1.austin.rr.com 1.1229.18.2 # adjust for change of devname to const char (new mount format) # -------------------------------------------- # 03/05/27 torvalds@penguin.transmeta.com 1.1229.8.105 # Merge bk://cifs.bkbits.net/linux-2.5cifs # into penguin.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/05/27 viro@parcelfarce.linux.theplanet.co.uk 1.1229.8.106 # [PATCH] Fix sound lockup - missing chardev init # # Argh. Missing initialization in char_dev.c - it's definitely # responsible for crap on unload. Load side appears to be something else, # though... # -------------------------------------------- # 03/05/27 axboe@suse.de 1.1229.8.107 # [PATCH] blk layer tag resize # # This allows drivers to resize their tag depth at run-time. # -------------------------------------------- # 03/05/27 torvalds@home.transmeta.com 1.1229.17.2 # Merge bk://linus@bkbits.net/linux-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/05/28 anton@samba.org 1.1229.19.1 # ppc64: merge some conflicts # -------------------------------------------- # 03/05/28 anton@samba.org 1.1229.19.2 # ppc64: merge conflicts # -------------------------------------------- # 03/05/27 viro@parcelfarce.linux.theplanet.co.uk 1.1229.17.3 # [PATCH] procfs bug exposed by cdev changes # # fs/inode.c assumes that any ->delete_inode() will call clear_inode(). # procfs instance doesn't. It had passed unpunished for a while; cdev changes # combined with ALSA creating character devices in procfs made it fatal. # # Patch follows. It had fixed ALSA-triggered memory corruption here - # what happens in vanilla 2.5.70 is that clear_inode() is not called when # procfs character device inodes are freed. That leaves a freed inode on # a cyclic list, with obvious unpleasantness following when we try to traverse # it (e.g. when unregistering a device). # -------------------------------------------- # 03/05/27 miles@lsi.nec.co.jp 1.1229.17.4 # [PATCH] Remove some unneeded register saving on the v850 # # These registers are now saved in a difference place, but the old code # was inadvertently left in. # -------------------------------------------- # 03/05/27 miles@lsi.nec.co.jp 1.1229.17.5 # [PATCH] Include <linux/fs.h> in arch/v850/kernel/rte_cb_leds.c # # This is to define `struct file'; apparently some include-file change # removed a previous implicit include. # -------------------------------------------- # 03/05/27 miles@lsi.nec.co.jp 1.1229.17.6 # [PATCH] Miscellaneous v850 whitespace and comment cleanups # -------------------------------------------- # 03/05/27 miles@lsi.nec.co.jp 1.1229.17.7 # [PATCH] Handle new do_fork return value on v850 # -------------------------------------------- # 03/05/27 miles@lsi.nec.co.jp 1.1229.17.8 # [PATCH] Add __KERNEL__ guard to nb85e_cache.h on v850 # # This header ends up getting included by uClibc (though nothing in it is # used), so this protection is necessary to avoid problems with kernel-only # typedefs. # -------------------------------------------- # 03/05/27 miles@lsi.nec.co.jp 1.1229.17.9 # [PATCH] Add leading underline to new linker-script symbols on the v850 # # This is needed to match the output of the C compiler. # -------------------------------------------- # 03/05/27 miles@lsi.nec.co.jp 1.1229.17.10 # [PATCH] Whitespace and comment cleanups for v850 entry.S # -------------------------------------------- # 03/05/27 miles@lsi.nec.co.jp 1.1229.17.11 # [PATCH] Add v850 support for hardware single-step (via ptrace) # -------------------------------------------- # 03/05/27 miles@lsi.nec.co.jp 1.1229.17.12 # [PATCH] Update irq.c on v850 to use irqreturn_t # -------------------------------------------- # 03/05/27 miles@lsi.nec.co.jp 1.1229.17.13 # [PATCH] const-qualify memory arg in v850's __test_bit # # This silences at least one compile-time warning... :-) # -------------------------------------------- # 03/05/28 anton@samba.org 1.1229.20.1 # Merge samba.org:/scratch/anton/linux-2.5 # into samba.org:/scratch/anton/tmp3 # -------------------------------------------- # 03/05/27 hirofumi@mail.parknet.co.jp 1.1229.17.14 # [PATCH] Adds the large partition (> 128GB) support to FAT (1/5) # # This adds large partition (> 128GB) support to FAT. # -------------------------------------------- # 03/05/27 hirofumi@mail.parknet.co.jp 1.1229.17.15 # [PATCH] Fix VFAT_IOCTL_READDIR_BOTH/_SHORT ioctl (2/5) # # This fixes the return value of ioctl() for enables using the same way as # readdir(). # # put/get_user() return code check patch from John R R Leavitt # <jrrl@steampunk.com> # -------------------------------------------- # 03/05/27 hirofumi@mail.parknet.co.jp 1.1229.17.16 # [PATCH] Remove Documentation/filesystems/fat_cvf.txt (3/5) # # This removes the obsolete Documentation/filesystems/fat_cvf.txt. # -------------------------------------------- # 03/05/27 hirofumi@mail.parknet.co.jp 1.1229.17.17 # [PATCH] FAT cluster chain cache per superblock (4/5) # # This shifts the data position caches from module to per-superblock, and # cleanups. # -------------------------------------------- # 03/05/27 hirofumi@mail.parknet.co.jp 1.1229.17.18 # [PATCH] FAT cluster chain cache per inode (5/5) # # This adds a cache of lastest accessed cluster to inode for sequential # access. # # The following is 500M file of FAT-to-FAT copy test, this may be a most # different case in usual operations, because maximum readahead window # flush the all caches. # # 512 bytes blocksize, 4096 bytes cluster size. # # linux-2.5.69-bk12 # root@devron (a)[1232]# time cp file file1 # # real 7m58.900s # user 0m0.267s # sys 6m44.258s # # linux-2.5.69-bk12+patch # root@devron (a)[1576]# time cp file file1 # # real 2m44.309s # user 0m0.270s # sys 0m28.631s # -------------------------------------------- # 03/05/27 ink@jurassic.park.msu.ru 1.1229.17.19 # [PATCH] alpha: compile warning fix # # Make the "addr" arg to test_bit "const" to prevent flood of compile # warnings in networking code. # -------------------------------------------- # 03/05/27 ink@jurassic.park.msu.ru 1.1229.17.20 # [PATCH] alpha: fix panic on smp boot (fork_by_hand) # -------------------------------------------- # 03/05/27 ink@jurassic.park.msu.ru 1.1229.17.21 # [PATCH] alpha: typo in EISA bridge detection # -------------------------------------------- # 03/05/27 ink@jurassic.park.msu.ru 1.1229.17.22 # [PATCH] alpha: single-step breakpoints - updated fix # # Restore 2.4 behavior when setting the single step breakpoints. # -------------------------------------------- # 03/05/27 elenstev@mesatop.com 1.1229.17.23 # [PATCH] Use '#ifdef' to test for CONFIG options # -------------------------------------------- # 03/05/27 herbert@gondor.apana.org.au 1.1229.7.34 # [NET]: Missing refcount bump in flow cache. # -------------------------------------------- # 03/05/27 davem@nuts.ninka.net 1.1229.7.35 # [IPV4/IPV6]: Use Jenkins hash for fragment reassembly handling. # -------------------------------------------- # 03/05/27 davem@nuts.ninka.net 1.1229.7.36 # [IPV6]: Input full addresses into TCP_SYNQ hash function. # -------------------------------------------- # 03/05/28 davem@nuts.ninka.net 1.1229.7.37 # [IPV4]: Add sysctl to control ipfrag_secret_interval. # -------------------------------------------- # 03/05/28 acme@conectiva.com.br 1.1229.17.24 # o net: abstract access to struct sock ->flags # # This makes: # # 1. simpler primitive to access struct sock flags, shorter # 2. we check if the flag is valid by using enum sock_flags # 3. we can change the implementation to an open coded bit operations # if it proves to be faster than the more general bit manipulation # routines now used, i.e. we only have to change sock.h, not the # whole net tree like now # -------------------------------------------- # 03/05/28 paulus@samba.org 1.1244 # Merge samba.org:/stuff/paulus/kernel/linux-2.5 # into samba.org:/stuff/paulus/kernel/for-linus-ppc # -------------------------------------------- # 03/05/28 yoshfuji@linux-ipv6.org 1.1229.7.38 # [IPV6]: Clean up ip6_dst_alloc() calls. # -------------------------------------------- # 03/05/28 bdschuym@pandora.be 1.1229.7.39 # [BRIDGE]: Remove unnecessary code in br_input. # -------------------------------------------- # 03/05/28 yoshfuji@linux-ipv6.org 1.1229.7.40 # [IPV6]: Always remove fragment header. # -------------------------------------------- # 03/05/28 yoshfuji@linux-ipv6.org 1.1229.7.41 # [IPV6]: Fix possible dst leakage in ndisc_send_redirect. # -------------------------------------------- # 03/05/28 davem@nuts.ninka.net 1.1229.7.42 # [IPV6]: Fix typo in defragmentation changes. # -------------------------------------------- # 03/05/28 oliver@vermuden.neukum.org 1.1164.11.2 # - major cleanup of the module code # -------------------------------------------- # 03/05/28 rmk@flint.arm.linux.org.uk 1.1229.21.1 # [ARM] Fix GCC3.3 build error # # GCC 3.3 complains that r2 overlaps input operands when a u64 pointer # is passed into __put_user(). Fix this by using ip as a temporary # register instead. # -------------------------------------------- # 03/05/28 shaggy@shaggy.austin.ibm.com 1.1229.22.1 # Merge jfs@jfs.bkbits.net:linux-2.5 # into shaggy.austin.ibm.com:/shaggy/bk/jfs-2.5 # -------------------------------------------- # 03/05/28 rmk@flint.arm.linux.org.uk 1.1229.21.2 # [ARM] Remove old 26-bit ARM keyboard drivers # # Also remove mouse_ps2.c which was never referenced from the Makefile. # -------------------------------------------- # 03/05/28 rmk@flint.arm.linux.org.uk 1.1229.21.3 # [ARM] Declare mmu_gathers using DEFINE_PER_CPU. # -------------------------------------------- # 03/05/28 perex@suse.cz 1.1229.1.145 # Merge suse.cz:/home/perex/bk/linux-sound/linux-2.5 # into suse.cz:/home/perex/bk/linux-sound/linux-sound # -------------------------------------------- # 03/05/28 proski@org.rmk.(none) 1.1127.7.2 # [PATCH] Fix crash when unloading yenta_socket in Linux 2.5.69 # # socket->base is unmapped in yenta_close(), which is called by # cardbus_remove(). The value of socket->base is not changed to # NULL, so it becomes invalid. # # Then cardbus_remove() calls class_device_unregister(), which calls # pcmcia_unregister_socket(), which it turn tries to access memory # space of the socket. # -------------------------------------------- # 03/05/28 rmk@flint.arm.linux.org.uk 1.1229.23.1 # Merge flint.arm.linux.org.uk:/usr/src/linux-bk-2.5/linux-2.5 # into flint.arm.linux.org.uk:/usr/src/linux-bk-2.5/linux-2.5-pcmcia # -------------------------------------------- # 03/05/28 dwmw2@infradead.org 1.1229.24.1 # MTD and JFFS2 update. # # - JFFS2 bugfixes and performance improvements # - Support for 64-bit flash arrangements # - Optimise for linear mappings of flash, without out-of-line access functions # - New map drivers # - Updated NAND flash support, new board drivers # - Support for DiskOnChip Millennium Plus and INFTL translation layer # - Clean up all translation layers with a single blkdev helper library. # - Fix races in MTD device registration/deregistration # - Add support for new flash chips # - Clean up partition parsing code # # More detailed comments in per-file changelogs. # -------------------------------------------- # 03/05/28 dwmw2@infradead.org 1.1229.24.2 # Final cleanups for MTD merge. # -------------------------------------------- # 03/05/28 torvalds@home.transmeta.com 1.1229.23.2 # Make zlib_inflate look more like ANSI C code. # # Anybody who still thinks K&R makes sense should just be shot. # -------------------------------------------- # 03/05/28 torvalds@home.transmeta.com 1.1229.23.3 # Merge master.kernel.org:/home/dwmw2/BK/mtd-forlinus-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/05/28 Matt_Domsch@dell.com 1.1229.25.1 # dynids: use list_add_tail # # instead of list_add, such that later entries come later in the scanned list. # -------------------------------------------- # 03/05/28 Matt_Domsch@dell.com 1.1229.25.2 # dynids: free dynids on driver unload # -------------------------------------------- # 03/05/28 torvalds@home.transmeta.com 1.1229.21.4 # Merge bk://bk.arm.linux.org.uk/linux-2.5-rmk # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/05/28 torvalds@home.transmeta.com 1.1243.1.1 # Merge bk://ppc.bkbits.net/for-linus-ppc # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/05/28 davem@nuts.ninka.net 1.1229.7.43 # [TCP]: Do not access inet_sk() of a time-wait bucket. # # Bug discovered by Mandred Spraul. # -------------------------------------------- # 03/05/28 davem@nuts.ninka.net 1.1243.1.2 # Merge nuts.ninka.net:/home/davem/src/BK/network-2.5 # into nuts.ninka.net:/home/davem/src/BK/net-2.5 # -------------------------------------------- # 03/05/28 jgarzik@redhat.com 1.1229.23.4 # [netdrvr tlan] cleanup # # * use pci_{request,release}_regions for PCI devices # * use alloc_etherdev (fixes race) # * propagate error returns from pci_xxx function errors # -------------------------------------------- # 03/05/28 david@gibson.dropbear.id.au 1.1243.1.3 # [PATCH] Update orinoco driver to 0.13e # # This updates the orinoco driver, fixing many bugs and adding some minor # features. It also adds a new module, orinoco_tmd for devices based on # the TMD7168 PCI<->PCMCIA adaptor. # -------------------------------------------- # 03/05/28 jgarzik@redhat.com 1.1229.23.5 # [netdrvr] s/init_etherdev/alloc_etherdev/ in code comments, # in 8139too and pci-skeleton drivers. # -------------------------------------------- # 03/05/29 jgarzik@redhat.com 1.1229.23.6 # [netdrvr 8139too] respond to "isn't this racy?" comment # -------------------------------------------- # 03/05/29 jgarzik@redhat.com 1.1229.23.7 # Merge redhat.com:/garz/repo/init-etherdev-2.5 # into redhat.com:/garz/repo/net-drivers-2.5 # -------------------------------------------- # 03/05/28 anton@samba.org 1.1243.1.4 # [PATCH] compat_wait4 fix # # sys_wait4 can return a pid and in this case we want to copy the struct # rusage out to userspace. # -------------------------------------------- # 03/05/29 jgarzik@redhat.com 1.1229.23.8 # [netdrvr r8169] use alloc_etherdev, pci_disable_device # -------------------------------------------- # 03/05/28 davem@nuts.ninka.net 1.1243.2.1 # [SPARC64]: Fix probe error handling in envctrl.c driver. # -------------------------------------------- # 03/05/28 davem@nuts.ninka.net 1.1243.2.2 # [SPARC64]: Fix probe error handling in bbc_{envctrl,i2c}.c driver. # -------------------------------------------- # 03/05/29 anton@samba.org 1.1229.20.2 # ppc64: Always pass non segment faults on the 0xc region up to do_page_fault # -------------------------------------------- # 03/05/29 dwmw2@infradead.org 1.1243.1.5 # Merge master.kernel.org:/home/torvalds/BK/linux-2.5 # into infradead.org:/inst/bk/linus-2.5 # -------------------------------------------- # 03/05/29 yoshfuji@linux-ipv6.org 1.1243.3.1 # [IPV6]: Fix default router selection in some cases. # -------------------------------------------- # 03/05/29 davem@nuts.ninka.net 1.1243.2.3 # [SPARC64]: Do not export {un,}register_ioctl32_converstion twice. # -------------------------------------------- # 03/05/29 davem@nuts.ninka.net 1.1243.3.2 # Merge bk://kernel.bkbits.net/acme/net-2.5 # into nuts.ninka.net:/home/davem/src/BK/net-2.5 # -------------------------------------------- # 03/05/29 hch@lst.de 1.1243.3.3 # [NET]: Remove sdla from setup.c # -------------------------------------------- # 03/05/29 hch@lst.de 1.1243.2.4 # [SPARC64]: Kill sys_aplib. # -------------------------------------------- # 03/05/29 chas@cmf.nrl.navy.mil 1.1243.3.4 # [ATM]: lane and mpoa module refcounting and locking cleanup. # -------------------------------------------- # 03/05/29 jgarzik@redhat.com 1.1243.3.5 # [ROSE]: Kill kfree of net_device->name. # -------------------------------------------- # 03/05/29 yoshfuji@linux-ipv6.org 1.1243.3.6 # [IPV6]: Add ip6frag sysctls. # -------------------------------------------- # 03/05/29 dwmw2@infradead.org 1.1243.1.6 # Fix some accidental regressions which slipped in with the MTD merge. # # - Unrevert strncpy->strlcpy change in JEDEC chip driver # - Fix partition handling in physmap map driver # - Switch sa1100-flash map driver back to rmk's version. # -------------------------------------------- # 03/05/29 paulus@samba.org 1.1245 # Merge samba.org:/stuff/paulus/kernel/linux-2.5 # into samba.org:/stuff/paulus/kernel/for-linus-ppc # -------------------------------------------- # 03/05/29 davem@nuts.ninka.net 1.1243.3.7 # [NET}: Fix typo in sock_set_flag changes. # -------------------------------------------- # 03/05/30 anton@samba.org 1.1243.4.1 # Merge samba.org:/scratch/anton/linux-2.5 # into samba.org:/scratch/anton/tmp3 # -------------------------------------------- # 03/05/29 gerg@snapgear.com 1.1243.1.7 # [PATCH] fix calls to do_fork() # # Change the m68knommu specific calls to do_fork() to match # its pid return vlue. # -------------------------------------------- # 03/05/29 gerg@snapgear.com 1.1243.1.8 # [PATCH] remove obsolete BLKMEM driver reference # -------------------------------------------- # 03/05/29 gerg@snapgear.com 1.1243.1.9 # [PATCH] cleanup is_in_rom() checker # # Clean up the dodgy is_in_rom() code for m68knommu targets. # # Now that all the m68knommu sub-architectures (68x328, 68360 # and ColdFire) have the same memory setup support we can # make this code the same for all targets. # -------------------------------------------- # 03/05/29 gerg@snapgear.com 1.1243.1.10 # [PATCH] fix broken trace flag check in 68328 system call entry # -------------------------------------------- # 03/05/29 gerg@snapgear.com 1.1243.1.11 # [PATCH] security init call support in linker script # # Linker script updates for m68knommu architecture: # # - fix _ramend for DragonEngine2 board # - add security init call support # -------------------------------------------- # 03/05/29 shaggy@shaggy.austin.ibm.com 1.1229.22.2 # JFS: resize fixes # # Bmap control page was not always being updated. # Superblock's s_size field was incorrectly set on big-endian hardware. # -------------------------------------------- # 03/05/29 shaggy@shaggy.austin.ibm.com 1.1243.5.1 # Merge jfs@jfs.bkbits.net:linux-2.5 # into shaggy.austin.ibm.com:/shaggy/bk/jfs-2.5 # -------------------------------------------- # 03/05/29 alan@lxorguk.ukuu.org.uk 1.1229.23.9 # [netdrvr tlan] fix 64-bit issues # -------------------------------------------- # 03/05/29 perex@suse.cz 1.1243.1.12 # Merge suse.cz:/home/perex/bk/linux-sound/linux-2.5 # into suse.cz:/home/perex/bk/linux-sound/linux-sound # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.1 # o drivers/bluetooth/hci_usb: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.2 # o drivers/isdn/hisax/st5481: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.3 # o drivers/media/video/cpia_usb: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.4 # o drivers/net/irda/irda-usb: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.5 # o drivers/class/audio: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.6 # o drivers/class/bluetty: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.7 # o drivers/class/cdc-acm: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.8 # o drivers/class/usb-midi: initialize struct usb_driver ->owner field # # And remove MOD_{INC,DEC}_USE_COUNT # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.9 # o drivers/usb/core/devio: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.10 # o drivers/usb/core/hub: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.11 # o drivers/usb/image/hpusbscsi: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.12 # o drivers/usb/image/microtek: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.13 # o drivers/usb/image/scanner: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.14 # o drivers/usb/input/aiptek: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.15 # o drivers/usb/input/hid-core: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.16 # o drivers/usb/input/hiddev: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.17 # o drivers/usb/input/kbtab: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.18 # o drivers/usb/input/powermate: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.19 # o drivers/usb/input/usbkbd: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.20 # o drivers/usb/input/usbmouse: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.21 # o drivers/usb/input/wacom: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.22 # o drivers/usb/input/xpad: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.23 # o drivers/usb/media/dabusb: initialize struct usb_driver ->owner field # # Also remove MOD_{INC,DEC}_USE_COUNT # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.24 # o drivers/usb/media/dsbr100: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.25 # o drivers/usb/media/ibmcam: remove MOD_{INC,DEC}_USE_COUNT # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.26 # o drivers/usb/media/konicawc: remove MOD_{DEC,INC}_USE_COUNT # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.27 # o drivers/usb/media/ov511: initialize struct usb_driver ->owner field # # Also remove MOD_{INC,DEC}_USE_COUNT # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.28 # o drivers/usb/media/pwc-if: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.29 # o drivers/usb/media/se401: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.30 # o drivers/usb/media/stv680: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.31 # o drivers/usb/media/ultracam: remove MOD_{INC,DEC}_USE_COUNT # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.32 # o drivers/usb/media/vicam: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.33 # o drivers/usb/misc/auerswald: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.34 # o drivers/usb/misc/emi26: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.35 # o drivers/usb/misc/rio500: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.36 # o drivers/usb/misc/usblcd: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.37 # o drivers/usb/net/catc: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.38 # o drivers/usb/net/cdc-ether: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.39 # o drivers/usb/net/pegasus: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.40 # o drivers/usb/net/rtl8150: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.41 # o drivers/usb/net/usbnet: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.42 # o drivers/usb/serial/belkin_sa: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 reeja.john@amd.com 1.1229.23.10 # [netdrvr amd8111e] interrupt coalescing, libmii, bug fixes # # * Dynamic interrupt coalescing # * mii lib support # * dynamic IPG support (disabled by default) # * jumbo frame fix # * vlan fix # * rx irq coalescing fix # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.43 # o drivers/usb/serial/cyberjack: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.44 # o drivers/usb/serial/digi_acceleport: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.45 # o drivers/usb/serial/empeg: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.46 # o drivers/usb/serial/ftdi_sio: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.47 # o drivers/usb/serial/io_edgeport: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 shemminger@osdl.org 1.1229.23.11 # [netdrvr e100] initialize callbacks before registering netdev # # Ouch. # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.48 # o drivers/usb/serial/io_ti: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/30 anton@samba.org 1.1243.4.2 # ppc64: Add some branch prediction # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.49 # o drivers/usb/serial/ipaq: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.50 # o drivers/usb/serial/ir-usb: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.51 # o drivers/usb/serial/keyspan: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.52 # o drivers/usb/serial/kl5kusb105: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.53 # o drivers/usb/serial/mct_u232: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/30 anton@samba.org 1.1243.7.1 # Merge samba.org:/scratch/anton/linux-2.5 # into samba.org:/scratch/anton/tmp3 # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.54 # o drivers/usb/serial/omninet: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.55 # o drivers/usb/serial/pl2303: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.56 # o drivers/usb/serial/safe_serial: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 greg@kroah.com 1.1243.8.1 # USB: build gadget drivers if they are built into the kernel. # # Somehow this got merged away... # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.57 # o drivers/usb/serial/usb-serial: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.58 # o drivers/usb/serial/visor: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.59 # o drivers/usb/serial/whiteheat: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.60 # o drivers/usb/storage/usb: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/29 acme@conectiva.com.br 1.1243.6.61 # o drivers/usb/usb-skeleton: initialize struct usb_driver ->owner field # -------------------------------------------- # 03/05/30 anton@samba.org 1.1243.7.2 # ppc64: remove ioperm # -------------------------------------------- # 03/05/29 greg@kroah.com 1.1243.8.2 # USB: fix up unusual_devs.h merge mess # # Thanks to Per Winkvist for the info and patches to do this. # -------------------------------------------- # 03/05/29 greg@kroah.com 1.1243.9.1 # Merge http://mdomsch.bkbits.net/linux-2.5-dynids # into kroah.com:/home/greg/linux/BK/pci-2.5 # -------------------------------------------- # 03/05/29 oliver@neukum.org 1.1243.8.3 # [PATCH] USB: allocate memory for reset earlier # # if we fail with -ENOMEM, we should do it before the device must be # reparsed. # -------------------------------------------- # 03/05/29 mdharm-usb@one-eyed-alien.net 1.1243.8.4 # [PATCH] USB: storage: abort and disconnect handling. # # This patch re-organizes abort handling and enhances disconnect handling. # # Not only do we keep track of the state (ABORTING, IDLE, etc.), but during # an abort we now introduce the idea of 'okay to send' or not. The idea is # that we can now implement reset-after-abort properly. # # We also track if we're disconnecting, and use that data to determine if we # can submit URBs or not. Which means we can now disconnect during an abort. # # This patch is from Alan Stern. # -------------------------------------------- # 03/05/29 mdharm-usb@one-eyed-alien.net 1.1243.8.5 # [PATCH] USB: storage: collapse one-use functions # # This patch collapses some one-use functions into their callers. It also # clones some code for control transfers so we can implement abortable # control transfers with timeout. # # This patch is from Alan Stern. # # Remove usb_stor_bulk_msg() and usb_stor_interrupt_msg(). Move their # functionality into usb_stor_bulk_transfer_buf() and # usb_stor_intr_transfer(). # # Move the functionality of usb_stor_control_msg() into # usb_stor_ctrl_transfer(). # # Remove the unused act_len parameter from usb_stor_intr_transfer(). # -------------------------------------------- # 03/05/29 hch@lst.de 1.1243.8.6 # [PATCH] use second arg to scsi_add_host in usb storage # # That way we don't need the addition scsi_set_device call. # -------------------------------------------- # 03/05/29 hch@lst.de 1.1243.8.7 # [PATCH] fix scsi_register_host abuse in usb scanner drivers # # They should be using scsi_add_host directly. I had to rewrite # half of the drivers, though to fix horrible braindamage like # leaving dangling scsi structures around after ->disconnect. # # Gettig rid of the remaining scsi_register_host callers is required # for the scsi stack to move forward so please try to forward this # to Linus in a timely mannor, thanks! # -------------------------------------------- # 03/05/29 torvalds@home.transmeta.com 1.1243.10.1 # Merge bk://kernel.bkbits.net/jgarzik/net-drivers-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/05/29 elenstev@mesatop.com 1.1243.10.2 # [PATCH] K&R to ANSI C conversions for zlib # # Here are some more K&R to ANSI C conversions. # -------------------------------------------- # 03/05/29 elenstev@mesatop.com 1.1243.10.3 # [PATCH] Yet more K&R to ANSI C conversions # # More K&R to ANSI C conversions for lib/zlib_deflate. # -------------------------------------------- # 03/05/29 jgarzik@redhat.com 1.1229.23.12 # Cset exclude: shemminger@osdl.org|ChangeSet|20030529205634|46794 # # The needed fix winds up breaking SG, checksumming, and other stuff # in the process. # -------------------------------------------- # 03/05/29 jgarzik@redhat.com 1.1243.10.4 # Merge redhat.com:/garz/repo/linus-2.5 # into redhat.com:/garz/repo/net-drivers-2.5 # -------------------------------------------- # 03/05/29 scott.feldman@intel.com 1.1243.10.5 # [netdrvr e100] move register_netdev below netdev struct init # # (i.e. the better fix) # -------------------------------------------- # 03/05/29 chas@cmf.nrl.navy.mil 1.1243.3.8 # [ATM]: HE driver coding style conformance. # -------------------------------------------- # 03/05/29 chas@cmf.nrl.navy.mil 1.1243.3.9 # [ATM]: HE driver misc irq handler cleanups. # -------------------------------------------- # 03/05/29 chas@cmf.nrl.navy.mil 1.1243.3.10 # [ATM]: Move rategrid off stack in HE driver. # -------------------------------------------- # 03/05/29 shemminger@osdl.org 1.1243.3.11 # [BRIDGE]: Make delete bridge work with current unregister semantics. # -------------------------------------------- # 03/05/29 shemminger@osdl.org 1.1243.3.12 # [NET]: Sysfs netdev cleanup and bugfix. # # A couple of bugs in netdev_unregister_sysfs; still working on the harder # refcount issues. # - if driver sets get_stats after register then unregister # will attempt to delete kobject that has not be initialized. # - unregister should call kobject_unregister not kobject_del. # # cleanup's: # - use strlcpy instead of snprintf # - don't need to memset the stats kobject # -------------------------------------------- # 03/05/29 jmm@informatik.uni-bremen.de 1.1243.3.13 # [CRYPTO]: Default CRYPTO and MD5 to y if IPV6_PRIVACY is enabled. # -------------------------------------------- # 03/05/29 shemminger@osdl.org 1.1243.3.14 # [NET]: Kill deprecated if_port_text and users. # -------------------------------------------- # 03/05/29 davem@nuts.ninka.net 1.1243.3.15 # [ATM]: Fix driver Makefile clean-files. # -------------------------------------------- # 03/05/29 greg@kroah.com 1.1243.6.62 # Merge bk://kernel.bkbits.net/acme/usb-2.5 # into kroah.com:/home/greg/linux/BK/gregkh-2.5 # -------------------------------------------- # 03/05/29 davem@kernel.bkbits.net 1.1243.11.1 # Merge davem@nuts.ninka.net:/home/davem/src/BK/net-2.5 # into kernel.bkbits.net:/home/davem/net-2.5 # -------------------------------------------- # 03/05/29 gerg@snapgear.com 1.1243.10.6 # [PATCH] conditional ROMfs copy for ARNEWSH/5206 setup # # Make the ROMfs copy in the startup code for ARNEWSH/5260 board # conditional on actually using a ROMfs setup. # -------------------------------------------- # 03/05/29 gerg@snapgear.com 1.1243.10.7 # [PATCH] support BOOTPARAM's on m68knommu/5206 targets # # Support pre-configured boot arguments on m68knommu/5206 targets. # -------------------------------------------- # 03/05/29 gerg@snapgear.com 1.1243.10.8 # [PATCH] support BOOTPARAM's on m68knommu/5206e targets # # Support pre-configured boot arguments on m68knommu/5206e targets. # -------------------------------------------- # 03/05/29 gerg@snapgear.com 1.1243.10.9 # [PATCH] m68knommu/pilot startup copy init segment to RAM # # The m68knommu/pilot startup code is not copying the init segment to # RAM currently. Fix it to copy all of the data and init sections to RAM. # -------------------------------------------- # 03/05/29 davem@kernel.bkbits.net 1.1243.10.10 # Merge davem@nuts.ninka.net:/home/davem/src/BK/sparc-2.5 # into kernel.bkbits.net:/home/davem/sparc-2.5 # -------------------------------------------- # 03/05/29 bcollins@debian.org 1.1243.6.63 # [PATCH] USB Multi-input quirk # -------------------------------------------- # 03/05/29 david-b@pacbell.net 1.1243.6.64 # [PATCH] USB: ethernet "gadget", rx overflows happen # # I tightened up rx overflow logic in the net2280 driver # a while back, and it broke MTU size packets in this # driver (host pads them out). This patch accomodates it # by allocating a slightly larger buffer (almost 3*512). # -------------------------------------------- # 03/05/29 hwahl@hwahl.de 1.1243.6.65 # [PATCH] USB: Patch for Samsung Digimax 410 # # *** a/drivers/usb/storage/unusual_devs.h 2003-05-22 20:54:26.000000000 +0200 # -------------------------------------------- # 03/05/29 akpm@digeo.com 1.1243.12.1 # [PATCH] fix typo in coda # # We want an "|" in there, not "||". # -------------------------------------------- # 03/05/29 akpm@digeo.com 1.1243.12.2 # [PATCH] Fix suspend with pccardd running # # From: Pavel Machek <pavel@ucw.cz> # # This fixes suspend when pccards are used... # -------------------------------------------- # 03/05/29 akpm@digeo.com 1.1243.12.3 # [PATCH] fix oops on resume from apm bios initiated suspend # # From: Milton Miller <miltonm@bga.com> # # mm is NULL for kernel threads without their own context. active_mm is # maintained the one we lazly switch from. # # Without this patch, apm bios initiated suspend events (eg panel close) # cause an oops on resume in the LDT restore, killing kapmd, which causes # further events to not be polled. # -------------------------------------------- # 03/05/29 akpm@digeo.com 1.1243.12.4 # [PATCH] export mmu_cr4_features to modules # # From: Jan Marek <linux@hazard.jcu.cz> # # The DRM modules (i810) need this symbol. # # As this is a special-case for one particular in-kernel module I changed Jan's # patch from EXPORT_SYMBOL to EXPORT_SYMBOL_GPL. # -------------------------------------------- # 03/05/29 akpm@digeo.com 1.1243.12.5 # [PATCH] [VISWS] irqreturn_t conversion # # From: Andrey Panin <pazke@donpac.ru> # # This small patch (against 2.5.70) updates visws_apic.c in accordance # with linux irq handling changes. # -------------------------------------------- # 03/05/29 akpm@digeo.com 1.1243.12.6 # [PATCH] Fix CONFIG_PROCFS=n # # From: Manfred Spraul <manfred@colorfullife.com> # # three build fixes for CONFIG_PROC_FS=n: # # include/linux/procfs.h: # # - add missing proc_pid_unhash, proc_pid_flush declarations. static # inline functions that do nothing. # # - move semicolons around for kclist_{add,del}. gcc-3.2.2 doesn't like # the current syntax. # # drivers/net/pppoe.c: # # - proc_net doesn't exist if CONFIG_PROC_FS=n. # # drivers/scsi/scsi_priv.h: # # - add missing brackets to macro definition. # -------------------------------------------- # 03/05/29 akpm@digeo.com 1.1243.12.7 # [PATCH] zoran user-pointer fix # # From: Hollis Blanchard <hollis@austin.ibm.com> # # Fix a user pointer deref, found by the Stanford checker. # -------------------------------------------- # 03/05/29 akpm@digeo.com 1.1243.12.8 # [PATCH] irq balance logic fix # # From: Andi Kleen <ak@suse.de> # # The logic is: the global variable is set to the magic value # IRQBALANCE_CHECK_ARCH. It can be overwritten by a __setup function. If # the magic value is still set when the irq balancer is started it asks the # subarchitecture using the NO_BALANCE_IRQ macro. This is defined to a # genapic field in the generic architecture, otherwise constant. Then the # global variable is set and when it is true no balancing happens. # # Previously I had this wrong in that it always disabled it. # # This part should be correct, but it still doesn't seem to work. # # (I left the printk in there until the problem is debugged, could be removed # of course) # -------------------------------------------- # 03/05/29 akpm@digeo.com 1.1243.12.9 # [PATCH] kill lock_kernel() in inode_setattr() # # All we're doing in there is writing things into the inode. I see no need for # the lock_kernel(). # # And holding lock_kernel() across mark_inode_dirty() hurts on big SMP. # -------------------------------------------- # 03/05/29 akpm@digeo.com 1.1243.12.10 # [PATCH] i2o memleak comment # # From: Andy Whitcroft <apw@shadowen.org> # # There's a spot in i2o where we deliberately leak some memory when the # hardware plays up. The alternative is to let the hardware scribble on it at # some unknown time in the future. # # Things like the Stanford checker keep alleging that this is a bug. So shut # them up with a comment # -------------------------------------------- # 03/05/29 akpm@digeo.com 1.1243.12.11 # [PATCH] write_one_page() fixlets # # - set the number of pages to be written to "1". # # - Don't test PG_writeback twice. # -------------------------------------------- # 03/05/29 akpm@digeo.com 1.1243.12.12 # [PATCH] speed up the unlink speedup # # I'm not sure why I used igrab() in unlink(). igrab takes the oft-taken # inode_lock. # # The caller has a ref, so a simple increment of i_count will suffice. # -------------------------------------------- # 03/05/29 akpm@digeo.com 1.1243.12.13 # [PATCH] Remove unneeded fcntl check # # The NR_OPEN check in F_DUPFD is unneeded. viro says: # # "We check the limits in locate_fd() (called by dupfd()). Check for NR_OPEN # can (and should) be dropped - locate_fd() will never go beyond that # (expand_fd() will check it and refuse to go). # # "IOW, simply lose the check. We _might_ want to check signedness, but that's # it (IOW, check that arg will fit into 0..MAX_INT; second argument of dupfd() # is an int). OTOH, we might actually make dupfd() et.al. take unsigned long # and kill that crap completely." # # And indeed, the signedness is suspicious, so make various things in there # unsigned too. # -------------------------------------------- # 03/05/29 akpm@digeo.com 1.1243.12.14 # [PATCH] unregister_netdev cleanups # # Replace # # rtnl_lock(); # register_netdevice(dev); # rtnl_unlock(); # # with the equivalent # # register_netdev(); # # in numerous places. # -------------------------------------------- # 03/05/29 akpm@digeo.com 1.1243.12.15 # [PATCH] support 64 bit pci_alloc_consistent # # From: Jes Sorensen <jes@wildopensource.com> # # This is patch which provides support for 64 bit address allocations from # pci_alloc_consistent(), based on the address mask set through # pci_set_consistent_dma_mask(). This is necessary on some platforms which # are unable to provide physical memory in the lower 4GB block and do not # provide IOMMU support for cards operating in certain bus modes, such as # PCI-X on the SGI SN2. # # The default mask for pci_alloc_consistent() is still 32 bit as there are 64 # bit capable hardware out there that doesn't support 64 bit addresses for # descripters etc. Likewise, platforms which provide IOMMU support in all # bus modes can ignore struct pci_dev->consistent_dma_mask and just return a # 32 bit address as before. # # The patch also includes changes to tg3.c to make it use the new api as well # as a documentation update. I have done my best on the documentation part, # if anyone feel the can make my scribbles clearer, please do. # # Thanks to Dave Miller, Grant Grundler, James Bottomley, Colin Ngam, and # Jeremy Higdon for input and code/documentation portions. # -------------------------------------------- # 03/05/29 akpm@digeo.com 1.1243.12.16 # [PATCH] svcsock use-after-free fix # # From: Neil Brown <neilb@cse.unsw.edu.au> # # Extract ->stamp from skb *before* freeing it in svcsock.c # # As we sometime copy and free an skb, and sometime us it in-place, we must # be careful to extract information from it *before* it might be freed, not # after. # # Manfred's page-unmapping debug patch found this one. # -------------------------------------------- # 03/05/29 akpm@digeo.com 1.1243.12.17 # [PATCH] Fix writev when a segment generates EFAULT # # From: Martin Schwidefsky <schwidefsky@de.ibm.com> # # If writev() is passed a vector in which the second or later segment generates # a fault it will currently return -EFAULT. # # It shouldn't. It should write what it can and return the number of bytes # which were successfully copied. # # Fix that up by writing the partial result and then returning the right value. # -------------------------------------------- # 03/05/29 akpm@digeo.com 1.1243.12.18 # [PATCH] Fixes trivial error in # # From: Herbert Xu <herbert@gondor.apana.org.au> # # This patch adds a pair of missing quotes. # -------------------------------------------- # 03/05/29 akpm@digeo.com 1.1243.3.16 # [NET]: Convert rtnl_lock/register_netdevice/rtnl_unlock to register_netdev. # -------------------------------------------- # 03/05/29 davem@kernel.bkbits.net 1.1243.11.2 # Merge davem@nuts.ninka.net:/home/davem/src/BK/net-2.5 # into kernel.bkbits.net:/home/davem/net-2.5 # -------------------------------------------- # 03/05/29 torvalds@home.transmeta.com 1.1243.12.19 # Merge bk://kernel.bkbits.net/davem/net-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/05/29 torvalds@home.transmeta.com 1.1243.10.11 # Merge bk://kernel.bkbits.net/davem/sparc-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/05/30 paulus@samba.org 1.1246 # Merge samba.org:/home/paulus/kernel/linux-2.5 # into samba.org:/home/paulus/kernel/for-linus-ppc # -------------------------------------------- # 03/05/30 shaggy@shaggy.austin.ibm.com 1.1243.10.12 # Merge jfs@jfs.bkbits.net:linux-2.5 # into shaggy.austin.ibm.com:/shaggy/bk/jfs-2.5 # -------------------------------------------- # 03/05/30 greg@kroah.com 1.1243.6.66 # [PATCH] USB: remove some old references to /proc/bus/usb/drivers # # This is needed, as the file was deleted over a year ago... # -------------------------------------------- # 03/05/30 stern@rowland.harvard.edu 1.1243.6.67 # [PATCH] USB: fix address assignment after device reset # # Until my ambitious project gets going, this patch at least fixes the # problem of assigning a device's new address following a device reset. # The only change needed to David's original suggestion was to handle the # pathway involved in registering root hubs. # -------------------------------------------- # 03/05/30 proski@gnu.org 1.1243.6.68 # [PATCH] USB: name uninitialized in scanner.c # # Linux 2.5.69-bk18 prints something strange to the kernel log when the USB # scanner is attached. It turns out drivers/usb/image/scanner.c uses # uninitialized variable "name" in probe_scanner() in the printk() call. # That means that random memory is read and output to the kernel log. # -------------------------------------------- # 03/05/30 hch@lst.de 1.1243.13.1 # [PATCH] driver model for scsi upper drivers, take 2 # # On Tue, May 27, 2003 at 09:32:18AM +0200, Christoph Hellwig wrote: # > - removed the tape sysfs pseudodevice crap that caused hangs # > - switched sg to a class_interface. This means sg can be used # > on devices already claimed be an upper driver again. This # > also means I had to remove the sg sysfs attributes temporarily # > because the old mechanism is gone, but I'll restore them # > differently in a followon patch. # # Yikes, this was the old patch again. Here's the right one: # -------------------------------------------- # 03/05/30 jejb@raven.il.steeleye.com 1.1243.13.2 # Fix __exit routine of NCR_D700 # -------------------------------------------- # 03/05/30 greg@kroah.com 1.1243.6.69 # Merge kroah.com:/home/greg/linux/BK/bleed-2.5 # into kroah.com:/home/greg/linux/BK/gregkh-2.5 # -------------------------------------------- # 03/05/30 hch@lst.de 1.1243.13.3 # [PATCH] LDM-based scsi host lookup # # Replace scsi_host_hn_get with scsi_host_lookup that walks # through the shost class and gets a proper reference to the # host. This should fix the OOPS that Douglas saw last week. # -------------------------------------------- # 03/05/30 hch@lst.de 1.1243.13.4 # [PATCH] switch /proc/scsi/scsi to seq_file and proper device model # -------------------------------------------- # 03/05/30 hch@lst.de 1.1243.13.5 # [PATCH] kill scsi_host_get_next # # The only reamining user was a horrible hack with a big XXX: # in scsi_pc98.c. Remove it and add an even bigger XXX there, # we don't want to keep this function (and the scsi hostlist) # around just for this. # -------------------------------------------- # 03/05/30 B.Zolnierkiewicz@elka.pw.edu.pl 1.1243.14.1 # [PATCH] allow "hdX=scsi" for modular scsi/ide-scsi # # Allow a user to mark a device as for scsi # emulation at boot even with modular scsi/ide-scsi. # (from 2.4 patch by Matan Ziv-Av) # -------------------------------------------- # 03/05/30 B.Zolnierkiewicz@elka.pw.edu.pl 1.1243.14.2 # [PATCH] kill "hdX=noremap" # # Since Andries killed ide-geometry, remove "hdX=noremap" # parameter as it is no longer needed. # -------------------------------------------- # 03/05/30 B.Zolnierkiewicz@elka.pw.edu.pl 1.1243.14.3 # [PATCH] fix two IDE list_head problems # # Fix two problems related to list_head's (there are more, wip). # Second bug was uncovered by wli's list_head debugging patch, thanks wli! # # - Remove ata_unused list and use &idedefault_driver->drives only, # fixes list corruption (ata_unused will be later ressurected for hotplug). # # - Do not add same device twice to &idedefault_driver->drives, triggered # by first calling ide_unregister_subdriver() and later ata_attach(). # -------------------------------------------- # 03/05/30 hch@lst.de 1.1243.13.6 # [PATCH] kill remaining direct uses of scsi_register_host # # Together with a patch for the usb imaging drivers I just sent to # Greg this will allow us to get rid of scsi_register_host as exported # API, leaving it only for use of scsi_module.c. # -------------------------------------------- # 03/05/30 axboe@suse.de 1.1243.14.4 # [PATCH] copy the tag_map # # From: Milton Miller <miltonm@bga.com> # -------------------------------------------- # 03/05/30 axboe@suse.de 1.1243.14.5 # [PATCH] ide-cd buglets # # Assorted small ide-cd fixes, found and fixed by Andy Polyakov # <appro@fy.chalmers.se>. # # - CHECK_CONDITION really wants to be SAM_STAT_CHECK_CONDITION, the damn # bit shift by one bit again # # - Set sense_len correctly # # - Do post_transform() on the right buffer. # -------------------------------------------- # 03/05/30 axboe@suse.de 1.1243.14.6 # [PATCH] scsi_ioctl HZ fixes # # According to http://www.torque.net/sg/p/sg_v3_ho.html, SG HOWTO, # SG_[GET|SET]_TIMEOUTs are measured in "jiffies," while timeout field # of SG_IO structure - in milliseconds. Inconsistent? Yes. Yet it's no # excuse to disregard the specification. "Jiffies" are USER_HZ, 10ms on # IA-32 platforms and has to be scaled to kernel "jiffies," as suggested # below. As for "(jiffies - start_time) * (1000 / HZ)" vs. # "((jiffies - start_time) * 1000) / HZ." Just think that HZ is 1024 on # some platforms... # -------------------------------------------- # 03/05/30 jejb@raven.il.steeleye.com 1.1243.13.7 # Automerge # -------------------------------------------- # 03/05/30 axboe@suse.de 1.1243.15.1 # [PATCH] ide-cd/scsi/block fixups for SG_IO # # - Kill the bogus ret transformation in block/ioctl.c if we return # -EINVAL, doesn't make any sense. # # - Don't allow sg_reserved_size to be set bigger than a request we can # deal with... # # - timeout fixes. # # - Cleanup of user access. # # - Set SAM_STAT_CHECK_CONDITION, not CHECK_CONDITION which needs to be # bit shifted 1 up. # # - Set sense_len correctly. # # - Account sense_len correctly, don't just increment by 1... # # - Use the correct pointer in post transform. # # - Fix oops in bio_map_user(), it must get the extra reference prior to # calling bio_unmap_user() itself too. # -------------------------------------------- # 03/05/30 torvalds@home.transmeta.com 1.1243.14.7 # Heh. Jens clashes with himself. # -------------------------------------------- # 03/05/30 torvalds@home.transmeta.com 1.1243.10.13 # Merge http://jfs.bkbits.net/linux-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/05/30 akpm@digeo.com 1.1243.10.14 # [PATCH] fix generic_file_write() # # The recent writev() fix broke the invariant that ->commit_write _must_ be # called after a successful ->prepare_write(). It leaves ext3 with a # transaction stuck open and the filesystem locks up. # -------------------------------------------- # 03/05/30 greg@kroah.com 1.1243.6.70 # Merge kroah.com:/home/greg/linux/BK/bleed-2.5 # into kroah.com:/home/greg/linux/BK/gregkh-2.5 # -------------------------------------------- # 03/05/30 henning@meier-geinitz.de 1.1243.6.71 # [PATCH] USB: new vendor/product ids for scanner driver # # This patch adds some new vendor/product ids for the USB scanner # driver. # -------------------------------------------- # 03/05/30 paulkf@microgate.com 1.1243.10.15 # [PATCH] tty_register_driver # # This patch reinstates the ability of tty devices to use dynamically # allocated major numbers yet specify the minor numbers statically. # # The synclink drivers do this. # -------------------------------------------- # 03/05/30 torvalds@penguin.transmeta.com 1.1243.6.72 # Merge bk://kernel.bkbits.net/gregkh/linux/linus-2.5 # into penguin.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/05/30 bellucda@tiscali.it 1.1243.16.1 # [PATCH] USB: replaced BKL in rio500.c # -------------------------------------------- # 03/05/31 anton@samba.org 1.1243.6.73 # Merge samba.org:/scratch/anton/linux-2.5 # into samba.org:/scratch/anton/tmp3 # -------------------------------------------- # 03/05/30 mochel@osdl.org 1.1229.26.1 # Merge bk://ldm.bkbits.net/linux-2.5-core # into osdl.org:/home/mochel/src/kernel/devel/linux-2.5-core # -------------------------------------------- # 03/05/30 dougg@torque.net 1.1243.17.1 # [PATCH] sg driver for lk 2.5.70 # # This is a bug fix for a flawed patch I put in lk 2.4.19 # (sg version 3.1.24) and has been carried through into # the 2.5 series. Thanks to Andy Polyakov # <appro@fy.chalmers.se> for pointing this out (more than once). # # The sg.h header didn't get updated last time I submitted # an sg patch so this patch also addresses that. # -------------------------------------------- # 03/05/30 greg@kroah.com 1.1243.18.1 # Merge kroah.com:/home/greg/linux/BK/bleed-2.5 # into kroah.com:/home/greg/linux/BK/gregkh-2.5 # -------------------------------------------- # 03/05/30 jejb@raven.il.steeleye.com 1.1243.13.8 # Automerge # -------------------------------------------- # 03/05/30 jejb@raven.il.steeleye.com 1.1243.13.9 # Merge raven.il.steeleye.com:/home/jejb/BK/scsi-sg-2.5 # into raven.il.steeleye.com:/home/jejb/BK/scsi-misc-2.5 # -------------------------------------------- # 03/05/31 paulus@samba.org 1.1247 # Merge samba.org:/home/paulus/kernel/linux-2.5 # into samba.org:/home/paulus/kernel/for-linus-ppc # -------------------------------------------- # 03/05/30 acme@conectiva.com.br 1.1243.19.1 # o n_hdlc: CodingStyle cleanups and removal of old stuff # # - remove include kerneld.h, long gone # - some 80 column reformatting # - removal of typedefs # - c99 style documentation, using the existing function documentation # - add MODULE_AUTHOR # - remove GET_USER, COPY_TO_USER and friends # - remove ssize_t typedef, already in the kernel headers # - remove rw_count_t and rw_ret_t, use simple int and size_t as in the # tty ops prototypes and avoiding casts for return # - make strings in printk in init/exit module routines __initdata/__exitdata # saving some bytes after module init and for the case where this driver is # statically linked in the kernel (__exitdata is trown away) # # This makes this driver comply with parts of CodingStyle (more to be done) and # makes it looks more like the rest of the kernel, making it easier to read/debug. # # Have been using this modifications with ADSL/syncppp for some time, working well. # -------------------------------------------- # 03/05/31 davem@nuts.ninka.net 1.1243.20.1 # [SPARC64]: Fix sys_shmat handling for 64-bit binaries. # -------------------------------------------- # 03/05/31 herbert@gondor.apana.org.au 1.1243.21.1 # [XFRM]: u64 --> __u64 in linux/xfrm.h # -------------------------------------------- # 03/05/31 perex@suse.cz 1.1243.1.13 # Merge suse.cz:/home/perex/bk/linux-sound/linux-2.5 # into suse.cz:/home/perex/bk/linux-sound/linux-sound # -------------------------------------------- # 03/05/31 vandrove@vc.cvut.cz 1.1243.20.2 # [PATCH] matroxfb update to new API # # This updates the matroxfb driver to the new framebuffer API. # # I'm sorry that it is quite large, but due to completely changed # underlying API there is no reasonable way how to split it into smaller # pieces. # # - Removed support for text mode. No way for it with current API. # - Removed support for hardware cursor. Generic cursor code has enough # troubles as is, in software mode. # - No reasonable fbset support... It is especially annoying on multihead # system, as 'stty cols XXX rows YYY' does not change pixclock... # - Removed fastfont support. No way for it with current API. # # (Mis)features inherited from generic fbdev API: # - Cursor on other framebuffers than primary one does not blink. # - Contents of visible, but not foreground, display is not updated. # -------------------------------------------- # 03/05/31 elenstev@mesatop.com 1.1243.20.3 # [PATCH] More ANSI C cleanup of zlib # # More zlib K&R to ANSI C function header conversions. # -------------------------------------------- # 03/05/31 manfred@colorfullife.com 1.1243.20.4 # [PATCH] Prepare for page unmapper # # Avoid touching the next page in the NMI handler stack validity check. # # That way, we can start unmapping pages that aren't in use, without # triggering this case. # -------------------------------------------- # 03/05/31 acme@conectiva.com.br 1.1243.20.5 # o net: reduce the data dependency of struct sock/struct tcp_tw_bucket # # With this the area that is shared among struct sock and struct tcp_tw_bucket # is exact, i.e. there is no fields that are in struct sock and only reused # for other reasons in tcp_tw_bucket, while keeping both struct free of holes. # -------------------------------------------- # 03/06/01 anton@samba.org 1.1243.6.74 # ppc64: threaded coredump support # -------------------------------------------- # 03/06/01 anton@samba.org 1.1243.6.75 # ppc64: fix copy_from_user leak, from Milton Miller # -------------------------------------------- # 03/06/01 anton@samba.org 1.1243.6.76 # ppc64: Add warning for unhandled irqs # -------------------------------------------- # 03/05/31 davem@nuts.ninka.net 1.1243.22.1 # Merge nuts.ninka.net:/home/davem/src/BK/network-2.5 # into nuts.ninka.net:/home/davem/src/BK/net-2.5 # -------------------------------------------- # 03/05/31 herbert@gondor.apana.org.au 1.1243.22.2 # [XFRM_USER]: Fix xfrm_state_lookup args in xfrm_add_sa. # -------------------------------------------- # 03/05/31 herbert@gondor.apana.org.au 1.1243.22.3 # [XFRM_USER]: Rename confusing member of struct xfrm_usersa_id. # -------------------------------------------- # 03/05/31 kaber@trash.net 1.1243.22.4 # [PPP] fix memory leak in ioctl error path # -------------------------------------------- # 03/05/31 herbert@gondor.apana.org.au 1.1243.22.5 # [XFRM]: Too many reference drops of delpol in xfrm_policy_insert. # -------------------------------------------- # 03/06/01 davem@nuts.ninka.net 1.1243.20.6 # Merge bk://kernel.bkbits.net/acme/sock-2.5 # into nuts.ninka.net:/home/davem/src/BK/net-2.5 # -------------------------------------------- # 03/06/01 davem@nuts.ninka.net 1.1243.20.7 # [XFRM]: Handle use_time expiration properly. # -------------------------------------------- # 03/06/01 perex@suse.cz 1.1243.1.14 # ALSA update 0.9.4 # - added drivers for Digigram VXPocket V2, VXPocket 440 (pcmcia) # - added driver for Digigram VXP220 V2/Mic (PCI) # - added driver Harmony chipset (parisc) # - added OPL4 driver # - code cleanups - removed 2.2 and 2.4 code # - nm256 driver - added Dell Latitude LS workaround # - ac97 driver - fixes in intialization # - usb audio driver - strlcat() fixes # -------------------------------------------- # 03/06/02 paulus@samba.org 1.1248 # Merge samba.org:/stuff/paulus/kernel/linux-2.5 # into samba.org:/stuff/paulus/kernel/for-linus-ppc # -------------------------------------------- # 03/06/01 torvalds@home.transmeta.com 1.1243.1.15 # Merge http://linux-sound.bkbits.net/linux-sound # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/06/01 viro@parcelfarce.linux.theplanet.co.uk 1.1243.1.16 # [PATCH] Fix disk partitioning with multiple IDE disks # # Now that we use idedefault_driver.drives instead of ata_unused, the order # of drives on the driver->drives becomes significant; note that when we added # to ata_unused, we had done that to the end of list. # # So we should do the same with the "drives" list. # -------------------------------------------- # 03/06/01 greg@kroah.com 1.1243.18.2 # Cset exclude: greg@kroah.com|ChangeSet|20030529215347|05329 # -------------------------------------------- # 03/06/01 mdharm-usb@one-eyed-alien.net 1.1243.18.3 # [PATCH] USB: usb-storage: fix typo # # Typo fix. We need bitwise-OR here. # -------------------------------------------- # 03/06/01 mdharm-usb@one-eyed-alien.net 1.1243.18.4 # [PATCH] USB: usb-storage: timeouts and aborts # # This patch adds timeouts to usb_stor_control_msg(). Now we will no longer # have to use the usb_control_msg() routine in the usb core, so all our # control messages can be interrupted by scsi aborts or disconnects. # # This also includes the new serial-number for auto-REQUEST-SENSE change. # The new serial number has one bit toggled from the old, guaranteeing that # it is unique. # # Following a suggestion of David Brownell, this makes the transport-reset # function attempt to clear a halt condition on both bulk pipes even if one # of them fails. # -------------------------------------------- # 03/06/01 mdharm-usb@one-eyed-alien.net 1.1243.18.5 # [PATCH] USB: usb-storage: usb_stor_control_msg() and stuff # # This patch replaces usb_control_msg() with usb_stor_control_msg() everywhere, # which allows better abort/disconnect processing. # # Some comments are fixed-up. # # The GetMaxLUN function is moved later so URBs are initialized (now that it # uses the new control_msg() ). # # There is also some locking cleanup during reset. # -------------------------------------------- # 03/06/01 mdharm-usb@one-eyed-alien.net 1.1243.18.6 # [PATCH] USB: usb-storage: change result codes # # This patch changes to SAM_STAT_ result codes, which is (a) preferred, # according to the code comments, and (b) removes some odd-looking # bit-shifting. # -------------------------------------------- # 03/06/01 oliver@neukum.org 1.1243.18.7 # [PATCH] USB: return errors when disabling a port # # this allows us to learn about a port that cannot be disabled. It's needed # for a superrobust usb_reset_device(). # -------------------------------------------- # 03/06/01 mochel@osdl.org 1.1243.1.17 # Merge osdl.org:/home/mochel/src/kernel/devel/linux-2.5-virgin # into osdl.org:/home/mochel/src/kernel/devel/linux-2.5-core # -------------------------------------------- # 03/06/02 paulus@samba.org 1.1249 # Merge samba.org:/stuff/paulus/kernel/linux-2.5 # into samba.org:/stuff/paulus/kernel/for-linus-ppc # -------------------------------------------- # 03/06/02 davem@nuts.ninka.net 1.1243.23.1 # [SOUND]: Revert buggy ALSA merge ioctl32 changes. # -------------------------------------------- # 03/06/02 davem@nuts.ninka.net 1.1243.23.2 # [SOUND]: vx/vx_core.c needs linux/init.h # -------------------------------------------- # 03/06/02 davem@nuts.ninka.net 1.1243.23.3 # [SOUND]: Fix sparc cs4231 driver build due to pcm list changes. # -------------------------------------------- # 03/06/02 davem@nuts.ninka.net 1.1243.23.4 # [SPARC64]: Update defconfig. # -------------------------------------------- # 03/06/02 davidvh@cox.net 1.1243.13.10 # [PATCH] Fix compilation errors in ppa and imm modules # # This patch is a resend from LKML since it has yet to be applied in # either bk7. Patrick suggested I send it here. This patch fixes # compilation failures in ppa.c and imm.c that were introduced in 2.5.70-bk1. # # * Removes the 'int hostno' parameter from imm_proc_info(). # Parameter isn't used and breaks the pointer matching for Scsi_Host. # * Added the prototype for imm_proc_info() in imm.h # * Modified line 280 of ppa.c to match concept on line 263 of imm.c. # -------------------------------------------- # 03/06/03 anton@samba.org 1.1243.24.1 # Merge samba.org:/scratch/anton/linux-2.5 # into samba.org:/scratch/anton/tmp3 # -------------------------------------------- # 03/06/02 mhoffman@lightlink.com 1.1243.25.1 # [PATCH] I2C: fix oops w83781d during rmmod # # This fixes the oops during w83781d module removal by putting the # subclient registration back in. While I was in there, I split # w83781d_detect in half in an attempt to reduce the goto madness. # # So, the /sys tree looks like this, where 48 & 49 are the subclients. # There are no entries (besides name & power) for the subclients. # # /sys/bus/i2c/ # |-- devices # | |-- 0-002d -> ../../../devices/pci0/00:02.1/i2c-0/0-002d # | |-- 0-0048 -> ../../../devices/pci0/00:02.1/i2c-0/0-0048 # | `-- 0-0049 -> ../../../devices/pci0/00:02.1/i2c-0/0-0049 # `-- drivers # |-- i2c_adapter # `-- w83781d # |-- 0-002d -> ../../../../devices/pci0/00:02.1/i2c-0/0-002d # |-- 0-0048 -> ../../../../devices/pci0/00:02.1/i2c-0/0-0048 # `-- 0-0049 -> ../../../../devices/pci0/00:02.1/i2c-0/0-0049 # # Also, I fixed a bug where this driver would request and release an # ISA region, then poke around in that region, then finally request # it again. # # This patch against 2.5.70 works for me vs. an SMBus adapter. It needs # re-testing against an ISA adapter since my particular chip is SMBus only. # -------------------------------------------- # 03/06/02 bunk@fs.tum.de 1.1243.18.8 # [PATCH] SECURITY_ROOTPLUG must depend on USB # # The following patch lets SECURITY_ROOTPLUG depend on USB (otherwise # there are link errors since Root Plug Support needs # usb_bus_list{,_lock}): # -------------------------------------------- # 03/06/02 greg@kroah.com 1.1243.18.9 # [PATCH] USB: add usb_find_device() function to USB core. # -------------------------------------------- # 03/06/02 greg@kroah.com 1.1243.18.10 # [PATCH] Root plug: remove USB bus walking functions, now use usb_find_device(). # # Also fixed compiler warnings about the dbg() function. # -------------------------------------------- # 03/06/02 wahrenbruch@kobil.de 1.1243.18.11 # [PATCH] USB: kobil_sct.c added support for KAAN SIM Reader # # as promised - here is the patch for 2.5.70: # Added support for KAAN SIM in kobil_sct. # -------------------------------------------- # 03/06/02 greg@kroah.com 1.1243.18.12 # [PATCH] USB: added .owner to kobil_sct driver # -------------------------------------------- # 03/06/02 greg@kroah.com 1.1243.23.5 # Merge kroah.com:/home/greg/linux/BK/bleed-2.5 # into kroah.com:/home/greg/linux/BK/gregkh-2.5 # -------------------------------------------- # 03/06/03 anton@samba.org 1.1243.24.2 # ppc64: remove sys32.S # -------------------------------------------- # 03/06/02 davidel@xmailserver.org 1.1243.26.1 # [PATCH] epoll race fix # # The was a race triggered by heavy MT usage that could have caused # processes in D state. Bad Davide, bad ... # # Also, the semaphore is now per-epoll-fd and not global. Plus some comment # adjustment. # -------------------------------------------- # 03/06/02 bcollins@debian.org 1.1243.26.2 # [PATCH] Update IEEE1394 (r946) # # ETH1394: Use 64bit EUI as the hardware address. # ETH1394: Support broadcast packets. # SBP2 : Fix max_payload for > S400 # CORE : Fix iso.c compilation by including linux/sched.h directly. # -------------------------------------------- # 03/06/03 anton@samba.org 1.1243.27.1 # Merge samba.org:/scratch/anton/linux-2.5 # into samba.org:/scratch/anton/tmp3 # -------------------------------------------- # 03/06/02 zippel@linux-m68k.org 1.1243.26.3 # [PATCH] Remove old code and macros # # Remove old code and debugging macros which were used by the cml1->kconfig # converter. # -------------------------------------------- # 03/06/02 zippel@linux-m68k.org 1.1243.26.4 # [PATCH] Change P_ROOTMENU into a MENU_ROOT flag # # This changes P_ROOTMENU into a MENU_ROOT flag and also fixes some qconf # usability problems. # # Some gconf fixes by Romain Lievin <roms@tilp.info>. # -------------------------------------------- # 03/06/02 zippel@linux-m68k.org 1.1243.26.5 # [PATCH] add new keywords to parser # # Add the following new keywords: def_tristate, def_bool, def_boolean, # select, enable and range. # # Add support for def_tristate and def_bool, which combines default and # bool/tristate into a single statement and a allows simpler definition # of derived symbols. # -------------------------------------------- # 03/06/02 zippel@linux-m68k.org 1.1243.26.6 # [PATCH] expression support # # "default" accepts now not only a single symbol but also an expression # which can be assigned to boolean and tristate symbols. # -------------------------------------------- # 03/06/02 zippel@linux-m68k.org 1.1243.26.7 # [PATCH] reverse dependency support # # The 'select' keyword defines a lower limit for symbols and allows to # select other symbols when a symbol is selected, e.g.: # # config JOLIET # bool "Microsoft Joliet CDROM extensions" # select NLS # # This means when JOLIET is selected, NLS will be selected as well. # -------------------------------------------- # 03/06/02 zippel@linux-m68k.org 1.1243.26.8 # [PATCH] support for 'range' # # The 'range' keyword allows to define a lower and upper limit for integer # and hex symbols. # -------------------------------------------- # 03/06/02 zippel@linux-m68k.org 1.1243.26.9 # [PATCH] add more warnings # # Add a number of warnings to avoid misuse of the previously added features # (most important check for recursive dependencies). # -------------------------------------------- # 03/06/02 zippel@linux-m68k.org 1.1243.26.10 # [PATCH] front end updates # # conf: better choice interface # don't ask for unchangable symbols # # mconf: mark unchangable symbols with '---' # update exit text (from Sam Ravnborg <sam@ravnborg.org>) # # qconf: update debug output # -------------------------------------------- # 03/06/02 zippel@linux-m68k.org 1.1243.26.11 # [PATCH] create configuration in the destination directory # # This creates the configuration in the destination directory instead of # the current directory. # -------------------------------------------- # 03/06/02 zippel@linux-m68k.org 1.1243.26.12 # [PATCH] update kconfig documentation # # Fix various typos and and information about the new kconfig features. # -------------------------------------------- # 03/06/02 viro@parcelfarce.linux.theplanet.co.uk 1.1243.26.13 # [PATCH] ->minor_shift removal # # disk->minor_shift is not used anymore. Remove it. # -------------------------------------------- # 03/06/02 akpm@digeo.com 1.1243.26.14 # [PATCH] magazine layer for slab # # From: Manfred Spraul <manfred@colorfullife.com> # # slab.c is not very efficient for passing objects between cpus. Usually this # is a rare event, but with network routing and cpu-affine NICs it is possible # that nearly all allocation operations will occur on one cpu, and nearly all # free operations on another cpu. # # This causes slab memory to be returned to slab's free page list rather than # being cached on behalf of the particular slab cache. # # The attached patch solves that by adding an array of objects that is shared # by all cpus. Instead of multiple linked list operations per object, object # pointers are now passed to/from the shared array (and thus between cpus) with # memcopy operations. On uniprocessor, the default array size is 0, because # the shared array and the per-cpu head array are redundant. # # Additionally, the patch exports more statistics in /proc/slabinfo and make # the array sizes tunable by writing to /proc/slabinfo. Both changes break # backward compatibility, user space scripts must look at the slabinfo version # and act accordingly. # # The size of the new shared array may be altered at runtime, by writing to # /proc/slabinfo. # # The new parameters for writing to /proc/slabinfo are: # # #echo "cache-name limit batchcount shared" > /proc/slabinfo # # For example "size-4096 120 60 8" improves the slab efficiency for network # routing, because the default values (24 12 8) are too small for the large # series generated due to irq mitigation. Note that only root has write # permissions to /proc/slabinfo. # # These changes provided an overall 12% speedup in Robert Olson's gigE # packet-formwarding testing on 2-way. # -------------------------------------------- # 03/06/02 akpm@digeo.com 1.1243.26.15 # [PATCH] Additional fields in slabinfo # # From: Manfred Spraul <manfred@colorfullife.com> # # We need to present more information in /proc/slabinfo now the magazine # layer has been added. # # The slabinfo version has been updated to 2.0. # -------------------------------------------- # 03/06/02 akpm@digeo.com 1.1243.26.16 # [PATCH] initialise vma->vm_next in do_mmap_pgoff() # # We end up inspecting this field in zap_page_range(), on the mmap error path. # Best initialise it to something... # -------------------------------------------- # 03/06/02 akpm@digeo.com 1.1243.26.17 # [PATCH] More irq balance fixes # # From: Andi Kleen <ak@suse.de> # # John Stultz noticed that kirqd didn't start because of another logic error, # which broke irq balancing. This was still a fallout from the generic # subarchitecture changes. # # Actually it still refuses to balance anything on my test box, but perhaps # I'm just not able to generate enough interrupts. # # Anyways, with this patch the thread is running again at least. # -------------------------------------------- # 03/06/02 akpm@digeo.com 1.1243.26.18 # [PATCH] dirty_writeback_centisecs fixes # # This /proc tunable sets the kupdate interval. It has a couple of problems: # # - No way to turn it off completely (userspace dirty memory management # solutions require this). # # - If it has been set to one hour and then the user resets it to five # seconds, that resetting will not take effect for up to an hour. # # Fix that up by providing a sysctl handler. Setting the tunable to zero now # disables the kupdate function. # -------------------------------------------- # 03/06/02 akpm@digeo.com 1.1243.26.19 # [PATCH] Copy nanosecond stat values for i386 # # From: Andi Kleen <ak@suse.de> # # A brown paper bag bug, noticed by Ralf Baechle. # # i386 needs to define STAT_HAVE_NSEC too, otherwise it won't copy # the nanosecond values to user space. # -------------------------------------------- # 03/06/02 akpm@digeo.com 1.1243.26.20 # [PATCH] Some subarch warning fixes # # From: Andi Kleen <ak@suse.de> # # Some recent subarch interface changes caused macro redefinition warnings # for GET_APIC_ID and APIC_ID_MASK with the generic subarchitecture. Fixing # it properly required some reorganization by giving the generic arch a # mach_apicdef.h too. # -------------------------------------------- # 03/06/02 akpm@digeo.com 1.1243.26.21 # [PATCH] MTD build fix # # From: Adrian Bunk <bunk@fs.tum.de> # # Fix this: # # drivers/mtd/maps/map_funcs.c: In function `simple_map_read64': # drivers/mtd/maps/map_funcs.c:38: warning: implicit declaration of # function `__raw_readll' # -------------------------------------------- # 03/06/02 akpm@digeo.com 1.1243.26.22 # [PATCH] improved core support for time-interpolation # # From: David Mosberger <davidm@napali.hpl.hp.com> # # Basically, what the patch does is provide two hooks such that platforms # (and subplatforms) can provide time-interpolation in a way that guarantees # that two causally related gettimeofday() calls will never see time going # backwards (unless there is a settimeofday() call, of course). # # There is some evidence that the current scheme does work: we use it on ia64 # both for cycle-counter-based interpolation and the SGI folks use it with a # chipset-based high-performance counter. # # # It seems like enough platforms do this sort of thing to provide _some_ # support in the core, especially because it's rather tricky to guarantee # that time never goes backwards (short of a settimeofday, of course). # # This patch is based on something Jes Sorensen wrote for the SGI Itanium 2 # platform (which has a chipset-internal high-res clock). I adapted it so it # can be used for cycle-counter interpolation also. The net effect is that # "last_time_offset" can be removed completely from the kernel. # # The basic idea behind the patch is simply: every time you advance xtime by # N nanoseconds, you call update_wall_time_hook(NSEC). Every time the time # gets set (i.e., discontinuity is OK), reset_wall_time_hook() is called. # -------------------------------------------- # 03/06/02 akpm@digeo.com 1.1243.26.23 # [PATCH] ext3: fix for blocksize < PAGE_CACHE_SIZE # # If a buffer_head is outside i_size, block_write_full_page() will leave it # !buffer_mapped(). We shouldn't attach that buffer to the transaction for # writeout! # # This bug has been in 2.5 for some time. # -------------------------------------------- # 03/06/02 akpm@digeo.com 1.1243.26.24 # [PATCH] /proc/kcore fixes # # From: Tony Luck <tony.luck@intel.com> # # /proc/kcore has been broken on some architectures for a long time. Problems # surround the fact that some architectures allocate memory for vmalloc() and # thus modules at addresses below PAGE_OFFSET, which results in negative file # offsets in the virtual core file image provided by /proc/kcore. There are # also pending problems for discontig memory systems as /proc/kcore just # pretends that there are no holes between "PAGE_OFFSET" and "high_memory", so # an unwary user (ok super-user) can read non-existant memory which may do bad # things. There may also be kernel objects that would be nice to view in # /proc/kcore, but do not show up there. # # A pending change on ia64 to allow booting on machines that don't have # physical memory in any convenient pre-determined place will make things even # worse, because the kernel itself won't show up in the current implementation # of /proc/kcore! # # The patch attached provides enough hooks that each architecture should be # able to make /proc/kcore useful. The patch is INCOMPLETE in that *use* of # those hooks is ONLY PROVIDED FOR IA64. # # Here's how it works. The default code in fs/proc/kcore.c doesn't set up any # "elf_phdr" sections ... it is left to each architecture to make appropriate # calls to "kclist_add()" to specify a base address and size for each piece of # kernel virtual address space that needs to be made accessible through # /proc/kcore. To get the old functionality, you'll need two calls that look # something like: # # kclist_add(&kcore_mem, __va(0), # max_low_pfn * PAGE_SIZE); # kclist_add(&kcore_vmem, (void *)VMALLOC_START, # VMALLOC_END-VMALLOC_START); # # The first makes all of memory visible (__i386__, __mc68000__ and __x86_64__ # should use __va(PAGE_SIZE) to duplicate the original lack of access to page # 0). The second provides a single map for all "vmalloc" space (the code still # searches the vmlist to see what actually exists before accessing it). # # Other blocks of kernel virtual space can be added as needed, and removed # again (with kclist_del()). E.g. discontiguous memory machines can add an # entry for each block of memory. Architectures that allocate memory for # modules someplace outside of vmalloc-land can add/remove entries on module # insert and remove. # # The second piece of abstraction is the kc_vaddr_to_offset() and # kc_offset_to_vaddr() macros. These provide mappings from kernel virtual # addresses to offsets in the virtual file that /proc/kcore instantiates. I # hope they are sufficient to avoid negative offset problems that plagued the # old /proc/kcore. Default versions are provided for the old behaviour # (mapping simply adds/subtracts PAGE_OFFSET). For ia64 I just need to use a # different offset as all kernel virtual allocations are in the high 37.5% of # the 64-bit virtual address space. x86_64 was the other architecture with # this problem. I don't know enough (anything) about the kernel memory map on # x86_64, so I hope these provide a big enough hook. I'm hoping that you have # some low stuff, and some high stuff with a big hole in the middle ... in # which case the macros might look something like: # # #define kc_vaddr_to_offset(v) ((v) < 0x1000000000000000 ? (v) : \ # ((v) - 0xF000000000000000)) # # But if you have interesting stuff scattered across *every* part of the # unsigned address range, then you won't be able to squeeze it all into a # signed file offset. # # There are a couple of bug fixes too: # 1) get_kcore_size() didn't account for the elf_prstatus, elf_prpsinfo # and task_struct that are placed in the PT_NOTE section that is # part of the header. We were saved on most configurations by the # round-up to PAGE_SIZE ... but it's possible that some architectures # or machines corrupted memory beyond the space allocated for the # header. # # 2) The size of the PT_NOTES section was incorrectly set to the size # of the last note, rather than the sum of the sizes of all the notes. # -------------------------------------------- # 03/06/02 akpm@digeo.com 1.1243.26.25 # [PATCH] remove 16-bit pid assumption from ipc/sem.c # # From: Manfred Spraul <manfred@colorfullife.com> # # SysV sem operations that involve multiple semaphores can fail in the # middle, and then sempid (pid of the last successful operation) must be # restored. This happens with "sempid >>= 16" - broken due to the 32-bit pid # values. The attached patch fixes that by reordering the updates of the # semaphore fields. # # Additionally, the patch fixes the corruption of the sempid value that occurs # if a wait-for-zero operation fails. # # The patch is more than two years old, and was in -dj and -ak kernels. # -------------------------------------------- # 03/06/03 paulus@samba.org 1.1250 # Merge samba.org:/home/paulus/kernel/linux-2.5 # into samba.org:/home/paulus/kernel/for-linus-ppc # -------------------------------------------- # 03/06/02 jim.houston@attbi.com 1.1243.26.26 # [PATCH] preallocate signal queue resource - Posix timers # # This adds a new interface to kernel/signal.c which allows signals to be # sent using preallocated sigqueue structures. It also modifies # kernel/posix-timers.c to use this interface. # # The current timer code may fail to deliver a timer expiry signal if # there are no sigqueue structures available at the time of the expiry. # The Posix specification is clear that the signal queuing resource should # be allocated at timer_create time. This allows the error to be returned # to the application rather than silently losing the signal. # # This patch does not change the sigqueue structure allocation policy. I # hope to revisit that in another patch. # # Here is the definition for the new interface: # # struct sigqueue *sigqueue_alloc(void) # Preallocate a sigqueue structure for use with the functions # described below. # # void sigqueue_free(struct sigqueue *q) # Free a preallocated sigqueue structure. If the sigqueue # structure being freed is still queued, it will be removed # from the queue. I currently leave the signal pending. # It may be delivered without the siginfo structure. # # int send_sigqueue(int sig, struct sigqueue *q, struct task_struct *p) # This function is equivalent to send_sig_info(). It queues # a signal to the specified thread using the supplied sigqueue # structure. The caller is expected to fill in the siginfo_t # which is part of the sigqueue structure. # # int send_group_sigqueue(int sig, struct sigqueue *q, struct task_struct *p) # This function is equivalent to send_group_sig_info(). It queues # the signal to a process allowing the system to select which thread # will receive the signal in a multi-threaded process. # Again, the sigqueue structure is used to queue the signal. # # Both send_sigqueue() and send_group_sigqueue() return 0 if the signal # is queued. They return 1 if the signal was not queued because the # process is ignoring the signal. # # Both versions include code to increment the si_overrun count if the # sigqueue entry is for a Posix timer and they are called while the # sigqueue entry is still queued. Yes, I know that the current code # doesn't rearm the timer until the signal is delivered. Having this # extra bit of code doesn't do any harm, and I plan to use it. # # These routines do not check if there already is a legacy (non-realtime) # signal pending. They always queue the signal. This requires that # collect_signal() always checks if there is another matching siginfo # before clearing the signal bit. # -------------------------------------------- # 03/06/02 torvalds@home.transmeta.com 1.1243.23.6 # Merge penguin:v2.5/linux # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/06/02 viro@parcelfarce.linux.theplanet.co.uk 1.1243.28.1 # [NET]: Eliminate {init,register,unregister}_fcdev. # -------------------------------------------- # 03/06/02 viro@parcelfarce.linux.theplanet.co.uk 1.1243.28.2 # [NET]: Eliminate init_hippi_dev and {un,}register_hipdev. # -------------------------------------------- # 03/06/02 viro@parcelfarce.linux.theplanet.co.uk 1.1243.28.3 # [NET]: Convert most tokenring drivers away from {init,register,unregister}_trdev, only ibmtr remains. # -------------------------------------------- # 03/06/02 davem@nuts.ninka.net 1.1243.28.4 # [NET]: Kill PTI fddi driver, never completed and no plans to finish. # -------------------------------------------- # 03/06/02 viro@parcelfarce.linux.theplanet.co.uk 1.1243.28.5 # [NET]: Eliminate init_fddidev. # -------------------------------------------- # 03/06/03 anton@samba.org 1.1243.27.2 # ppc64: ppc64 update # -------------------------------------------- # 03/06/02 davem@nuts.ninka.net 1.1243.28.6 # [NET]: Fix CONFIG_HIPPI build. # -------------------------------------------- # 03/06/02 davem@nuts.ninka.net 1.1243.28.7 # [NET]: Fix typos in init_trdev changes to lanstreamer.c # -------------------------------------------- # 03/06/03 anton@samba.org 1.1243.23.7 # Merge samba.org:/scratch/anton/linux-2.5 # into samba.org:/scratch/anton/tmp3 # -------------------------------------------- # 03/06/03 anton@samba.org 1.1243.23.8 # ppc64: copy_tofrom_user exception handling fix from Paul Mackerras # -------------------------------------------- # 03/06/02 davem@nuts.ninka.net 1.1243.28.8 # [NET]: Eliminate {init,register,unregister}_trdev(). # -------------------------------------------- # 03/06/03 anton@samba.org 1.1243.23.9 # ppc64: kcore support # -------------------------------------------- # 03/06/03 anton@samba.org 1.1243.23.10 # ppc64: Increase maximum allocation size to 16MB for largepage support # -------------------------------------------- # 03/06/03 davem@nuts.ninka.net 1.1243.28.9 # [NET]: Eliminate init_etherdev usage from arch/um drivers. # -------------------------------------------- # 03/06/03 anton@samba.org 1.1243.23.11 # ppc64: FORCE_MAX_ZONEORDER is actually order + 1, from Dave Gibson # -------------------------------------------- # 03/06/03 anton@samba.org 1.1243.23.12 # ppc64: fix compile error introduced in threaded coredump patch # -------------------------------------------- # 03/06/03 davem@nuts.ninka.net 1.1243.28.10 # [IPV6]: In ipv6_add_dev dont call __ipv6_regen_rndid without initial reference held. # # Based upon a report from Andrew Morton. # -------------------------------------------- # 03/06/03 davem@nuts.ninka.net 1.1243.28.11 # [NET]: Use INIT_LIST_HEAD in arch/um/drivers/net_kern.c # -------------------------------------------- # 03/06/03 davem@kernel.bkbits.net 1.1243.29.1 # Merge davem@nuts.ninka.net:/home/davem/src/BK/net-2.5 # into kernel.bkbits.net:/home/davem/net-2.5 # -------------------------------------------- # 03/06/03 davem@nuts.ninka.net 1.1243.28.12 # [NET]: Typo in iph5527.c driver changes. # -------------------------------------------- # 03/06/03 davem@kernel.bkbits.net 1.1243.29.2 # Merge davem@nuts.ninka.net:/home/davem/src/BK/net-2.5 # into kernel.bkbits.net:/home/davem/net-2.5 # -------------------------------------------- # 03/06/03 herbert@gondor.apana.org.au 1.1243.29.3 # [PATCH] Fix ide-mod unload crash # # This patch fixes an unload crash when no PCI drivers are loaded. # -------------------------------------------- # 03/06/03 hch@lst.de 1.1243.29.4 # [PATCH] fix signal.h compilation on PPC # # signal.h uses spinlock_t now so it needs to include spinlock.h. # Without this compilation failes on PPC. # -------------------------------------------- # 03/06/03 torvalds@home.transmeta.com 1.1243.23.13 # Merge http://ppc.bkbits.net/for-linus-ppc64 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/06/03 davidm@napali.hpl.hp.com 1.1243.23.14 # [PATCH] fix TCP roundtrip time update code # # One of those very-hard-to-track-down, trivial-to-fix kind of problems: # without this patch, TCP roundtrip time measurements will corrupt the # routing cache's RTT estimates under heavy network load (the bug causes # RTAX_RTT to go negative, but since its type is u32, you end up with a # huge positive value...). From there on, later TCP connections quickly # will go south. # # The typo was introduced 8 months ago in v1.29 of the file by the patch # entitled "Cleanup DST metrics and abstrct MSS/PMTU further". # -------------------------------------------- # 03/06/03 anton@samba.org 1.1243.23.15 # [PATCH] fix matroxfb compile on ppc64] # # Here we really want CONFIG_ALL_PPC, since these headers are only valid # for PPC Mac machines (barf: badly named config option). # -------------------------------------------- # 03/06/03 markh@osdl.org 1.1243.23.16 # [PATCH] megaraid driver fix for 2.5.70 # # A recent change to the megaraid driver to fix some memset calls resulted # in overflowing the arrays being cleared and causing a system panic. # This patch fixes the problem by making sure that the arrays being # cleared are dimensioned to the correct size. The patch has been tested # on osdl's stp machines that have megaraid controllers. # -------------------------------------------- # 03/06/03 jejb@raven.il.steeleye.com 1.1243.23.17 # Merge raven.il.steeleye.com:/home/jejb/BK/scsi-misc-2.5 # into raven.il.steeleye.com:/home/jejb/BK/scsi-for-linus-2.5 # -------------------------------------------- # 03/06/03 mochel@osdl.org 1.1243.1.18 # Merge osdl.org:/home/mochel/src/kernel/devel/linux-2.5-virgin # into osdl.org:/home/mochel/src/kernel/devel/linux-2.5-core # -------------------------------------------- # 03/06/03 sam@mars.ravnborg.org 1.1243.30.1 # kbuild: Updated make help # # Patches originally by Adrian Bunk and Rudmer van Dijk. # Included "make V=0|1" and "make C=1" # -------------------------------------------- # 03/06/03 sam@mars.ravnborg.org 1.1243.30.2 # kbuild: Silence kbuild with make V=0 # # With make version 3.80 kbuild echo'ed the fixdep command # executed each time a c file was compiled. # This has been tracked down to a bug in version 3.80 of make. # Avoiding newlines in canned command sequences avoid this problem. # # At the same time consolidated similar code in Makefile.build, # and avoiding a few ifdef/endif pairs resulting in a more readable makefile. # -------------------------------------------- # 03/06/03 mochel@osdl.org 1.1243.1.19 # [driver model] Clean up CPU unregistration. # # From Dave Jones. # -------------------------------------------- # 03/06/03 sam@mars.ravnborg.org 1.1243.30.3 # kbuild: CROSS_COMPILE and ARCH definitions # # Patch originally by Jesse Barnes <jbarnes@sgi.com> # # Previously the user were required to supply CROSS_COMPILE and ARCH on the # commandline to make, alternatively they patched the Makefile direct. # The following patch allows the user to specify the value of these in # a variable assigned during init or similar. # # -------------------------------------------- # 03/06/03 mochel@osdl.org 1.1243.1.20 # Driver Class: don't call put_device() when we never called get_device() # # From Greg: # # This fixes a oops when unplugging pci network devices. # -------------------------------------------- # 03/06/04 paulus@samba.org 1.1251 # Merge samba.org:/stuff/paulus/kernel/linux-2.5 # into samba.org:/stuff/paulus/kernel/for-linus-ppc # -------------------------------------------- # 03/06/03 mochel@osdl.org 1.1243.1.21 # [driver model] Clean up class release handling. # # Based on a patch by Stephen Hemminger. # -------------------------------------------- # 03/06/03 mochel@osdl.org 1.1243.1.22 # [kobject] Update Documentation and licenses. # # - Make it very explicit that supplying an object desctructor is imperative # if using the interface for object reference counting. # # - Add GPL statement to the source files. # # - Add GFL (http://www.fsf.org/licenses/fdl.html) statement to documentation. # -------------------------------------------- # 03/06/03 mochel@osdl.org 1.1243.1.23 # [driver model] Update copyrights and license statements. # # It's a slow afternoon. # -------------------------------------------- # 03/06/03 mochel@osdl.org 1.1243.1.24 # [driver model] fix comment in device.h # -------------------------------------------- # 03/06/03 ldm.adm@hostme.bitkeeper.com 1.1243.31.1 # Merge hostme.bitkeeper.com:/ua/repos/l/ldm/linux-2.5 # into hostme.bitkeeper.com:/ua/repos/l/ldm/linux-2.5-core # -------------------------------------------- # 03/06/03 greg@kroah.com 1.1243.9.2 # [PATCH] PCI: make pci_setup_device(), pci_alloc_primary_bus() and pci_alloc_primary_bus_parented() static # # No one is calling these functions. # -------------------------------------------- # 03/06/03 greg@kroah.com 1.1243.9.3 # [PATCH] PCI: make pools_lock and pci_lock static. # # No one is using them outside the pci core. # -------------------------------------------- # 03/06/03 greg@kroah.com 1.1243.9.4 # [PATCH] ACPI PCI Hotplug: remove hand made pci_find_bus function # -------------------------------------------- # 03/06/03 greg@kroah.com 1.1243.9.5 # [PATCH] IBM PCI hotplug: remove hand made pci_find_bus function. # -------------------------------------------- # 03/06/03 B.Zolnierkiewicz@elka.pw.edu.pl 1.1243.23.18 # [PATCH] create /proc/ide/hdX/capacity only once # # In ide_register_subdriver() create drive->proc entries only if driver is # not idedefault_driver. # # [ There won't be /proc/ide/hdX/capacity for devices attached # to idedefault_driver now, it reported 0x7fffffff previously. ] # # Do not create drive->proc entries in create_proc_ide_drives(), they are # added later in ide_register_subdriver(). # -------------------------------------------- # 03/06/03 B.Zolnierkiewicz@elka.pw.edu.pl 1.1243.23.19 # [PATCH] kill recreate_proc_ide_device() # # It is unused and not needed # -------------------------------------------- # 03/06/03 hawkes@oss.sgi.com 1.1243.23.20 # [PATCH] 2.5.70 remove smp_send_reschedule() cruft # # smp_send_reschedule_all() is unused in 2.5 and can be eliminated. # -------------------------------------------- # 03/06/03 mochel@osdl.org 1.1243.1.25 # Merge osdl.org:/home/mochel/src/kernel/devel/linux-2.5-virgin # into osdl.org:/home/mochel/src/kernel/devel/linux-2.5-core # -------------------------------------------- # 03/06/03 mochel@osdl.org 1.1243.1.26 # Merge bk://ldm@bkbits.net/linux-2.5-core # into osdl.org:/home/mochel/src/kernel/devel/linux-2.5-core # -------------------------------------------- # 03/06/03 ahaas@airmail.net 1.1243.23.21 # [PATCH] C99 patches for fs/ # # Add C99 initializers to fs/bio.c and fs/dquot.c. And fs/libfs.c had an # obsolete GCC style initialzers that is converted to C99 style. # -------------------------------------------- # 03/06/03 ahaas@airmail.net 1.1243.23.22 # [PATCH] C99 struct initializers for kernel files # -------------------------------------------- # 03/06/03 torvalds@home.transmeta.com 1.1243.1.27 # Merge bk://ldm.bkbits.net/linux-2.5-core # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/06/03 greg@kroah.com 1.1243.9.6 # [PATCH] IBM PCI hotplug: remove direct access of pci_devices variable. # -------------------------------------------- # 03/06/03 greg@kroah.com 1.1243.9.7 # PCI Hotplug: move drivers/hotplug/* to drivers/pci/hotplug/* # # This will let include/linux/pci.h get smaller, and is what I should # have done in the first place 2 years ago... # -------------------------------------------- # 03/06/03 davem@nuts.ninka.net 1.1243.32.1 # Merge bk://kernel.bkbits.net/acme/net-2.5 # into nuts.ninka.net:/home/davem/src/BK/net-2.5 # -------------------------------------------- # 03/06/03 chas@cmf.nrl.navy.mil 1.1243.32.2 # [ATM]: more cleanup in HE driver # -------------------------------------------- # 03/06/03 davem@nuts.ninka.net 1.1243.32.3 # [NET]: Use INIT_LIST_HEAD correctly in arch/um/drivers/net_kern.c # -------------------------------------------- # 03/06/03 rddunlap@osdl.org 1.1243.32.4 # [NET]: add RFC references for Linux SNMP MIBs. # -------------------------------------------- # 03/06/03 rddunlap@osdl.org 1.1243.32.5 # [NET]: Typo corrections only. # -------------------------------------------- # 03/06/03 rddunlap@osdl.org 1.1243.32.6 # [IPV6]: Add IPv6 routing table statistic: fib_discarded_routes. # -------------------------------------------- # 03/06/03 yoshfuji@linux-ipv6.org 1.1243.32.7 # [NET]: Add ip-sysctl.txt entries for missing ip{,6}frag_* sysctls. # -------------------------------------------- # 03/06/03 hch@lst.de 1.1243.32.8 # [NET]: Move dmascc away from setup.c # -------------------------------------------- # 03/06/03 yoshfuji@linux-ipv6.org 1.1243.32.9 # [IPV6]: Set dead flag on idev if snmp6_register_dev() fails. # -------------------------------------------- # 03/06/03 davem@nuts.ninka.net 1.1243.32.10 # [IPSEC]: {esp,ah} --> {esp4,ah4}. # -------------------------------------------- # 03/06/03 hch@lst.de 1.1243.32.11 # [NET]: Fix non-modular sdla.c build. # -------------------------------------------- # 03/06/03 yoshfuji@linux-ipv6.org 1.1243.32.12 # [IPV6]: Fix several errors in udpv6_connect(). # # - Pointer within an automatic storage class variable fl was illegally # cached using ip6_dst_store() # - uninitialized saddr was copied to fl.fl6_src # - dont cache if ipv6_saddr_get() failed. # # Based upon patch from Ville Nuorvala (vnuorval@tcs.hut.fi) # -------------------------------------------- # 03/06/03 greg@kroah.com 1.1243.9.8 # [PATCH] PCI: Remove a lot of PCI core only functions from include/linux/pci.h # -------------------------------------------- # 03/06/03 jmorris@intercode.com.au 1.1243.32.13 # [CRYPTO]: Use "select" kconfig facility instead of fragile defaults. # -------------------------------------------- # 03/06/03 greg@kroah.com 1.1243.9.9 # [PATCH] PCI: remove CONFIG_PROC_FS checks in .c files. # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.10 # [PATCH] PCI: Move more functions out of include/linux/pci.h that don't need to be there. # -------------------------------------------- # 03/06/04 yoshfuji@linux-ipv6.org 1.1243.32.14 # [IPV6]: typo, unrequired #undef and bad operator precedence. # - no need to #undef CONFIG_IPV6_SUBTREE # - use parentheses around "&" and "|". # - fib_repair_tree() is typo. # -------------------------------------------- # 03/06/04 hch@lst.de 1.1243.32.15 # [NET]: Kill useless/wrong Version line from net/core/dv.c # -------------------------------------------- # 03/06/04 hch@lst.de 1.1243.32.16 # [NET]: net/core/dst.c typo. # -------------------------------------------- # 03/06/04 hch@lst.de 1.1243.32.17 # [NET]: Fix coding style in net/core/filter.c # -------------------------------------------- # 03/06/04 hch@lst.de 1.1243.32.18 # [NET]: Fix coding style in net/core/iovec.c # -------------------------------------------- # 03/06/04 viro@parcelfarce.linux.theplanet.co.uk 1.1243.32.19 # [NET]: Move sk98lin driver away from init_etherdev(). # -------------------------------------------- # 03/06/04 viro@parcelfarce.linux.theplanet.co.uk 1.1243.32.20 # [NET]: Move 3c509 driver away from init_etherdev(). # -------------------------------------------- # 03/06/04 davem@kernel.bkbits.net 1.1243.1.28 # Merge davem@nuts.ninka.net:/home/davem/src/BK/net-2.5 # into kernel.bkbits.net:/home/davem/net-2.5 # -------------------------------------------- # 03/06/04 rmk@flint.arm.linux.org.uk 1.1243.33.1 # [ARM] Fix more missing irqreturn_t and remove a static no_action func. # -------------------------------------------- # 03/06/04 herbert@gondor.apana.org.au 1.1243.32.21 # [IPSEC]: Include linux/slab.h where necessary. # -------------------------------------------- # 03/06/04 viro@parcelfarce.linux.theplanet.co.uk 1.1243.32.22 # [NET]: Move sunqe.c driver away from init_etherdev(). # -------------------------------------------- # 03/06/04 davem@nuts.ninka.net 1.1243.32.23 # [NET]: Move arch/cris drivers away from init_etherdev(). # -------------------------------------------- # 03/06/04 viro@parcelfarce.linux.theplanet.co.uk 1.1243.32.24 # [NET]: Move bmac.c away from init_etherdev(). # -------------------------------------------- # 03/06/04 davem@nuts.ninka.net 1.1243.32.25 # [NET]: Convert ia64 simeth.c away from init_etherdev(). # -------------------------------------------- # 03/06/04 davem@nuts.ninka.net 1.1243.32.26 # [NET]: Convert PPC 8260_io/enet.c away from init_etherdev(). # -------------------------------------------- # 03/06/04 davem@nuts.ninka.net 1.1243.32.27 # [NET]: Convert PPC 8260_io/fcc_enet.c away from init_etherdev(). # -------------------------------------------- # 03/06/04 davem@nuts.ninka.net 1.1243.32.28 # [NET]: Convert PPC 8xx_io/enet.c away from init_etherdev(). # -------------------------------------------- # 03/06/04 davem@nuts.ninka.net 1.1243.32.29 # [NET]: Convert PPC 8xx_io/fec.c away from init_etherdev(). # -------------------------------------------- # 03/06/04 davem@nuts.ninka.net 1.1243.32.30 # [NET]: Actually apply Al's sunqe.c changes. # -------------------------------------------- # 03/06/04 davem@nuts.ninka.net 1.1243.32.31 # [NET]: Fix thinkos in PPC 8260_io/fcc_enet.c changes. # -------------------------------------------- # 03/06/04 thomas@osterried.de 1.1243.32.32 # [AX25]: AX.25 bug fixes. # - Flxnet CRC handling fix for mkiss.c # - Use after free bug in ax25_ip.c # -------------------------------------------- # 03/06/04 torvalds@home.transmeta.com 1.1243.1.29 # Merge bk://linux-sam.bkbits.net/kbuild # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/06/04 rmk@flint.arm.linux.org.uk 1.1243.33.2 # [ARM] Move dma_alloc_coherent() to consistent.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.11 # [PATCH] PCI: Grab reference count on pci_dev if the pci driver binds to the device. # # And remember to decrement the count after remove() is called. # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.12 # [PATCH] PCI: remove usage of pci_for_each_dev() in sound/core/memalloc.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.13 # [PATCH] PCI: remove usage of pci_for_each_dev() in sound/oss/esssolo1.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.14 # [PATCH] PCI: remove usage of pci_for_each_dev() in sound/oss/maestro.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.15 # [PATCH] PCI: remove usage of pci_for_each_dev() in sound/oss/via82cxxx_audio.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.16 # [PATCH] PCI: remove usage of pci_for_each_dev() in sound/pci/rme9652/hammerfall_mem.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.17 # [PATCH] PCI: remove usage of pci_for_each_dev() in drivers/acpi/pci_irq.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.18 # [PATCH] PCI: remove usage of pci_for_each_dev() in drivers/char/agp/amd-k8-agp.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.19 # [PATCH] PCI: remove usage of pci_for_each_dev() in drivers/char/agp/generic.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.20 # [PATCH] PCI: remove usage of pci_for_each_dev() in drivers/char/agp/isoch.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.21 # [PATCH] PCI: remove usage of pci_for_each_dev() in drivers/char/hw_random.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.22 # [PATCH] PCI: remove usage of pci_for_each_dev() in drivers/char/watchdog/amd7xx_tco.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.23 # [PATCH] PCI: remove usage of pci_for_each_dev() in drivers/char/watchdog/i810-tco.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.24 # [PATCH] PCI: remove usage of pci_for_each_dev() in drivers/ide/pci/cs5530.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.25 # [PATCH] PCI: remove usage of pci_for_each_dev() in drivers/ide/pci/hp2366.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.26 # [PATCH] PCI: remove usage of pci_for_each_dev() in drivers/ide/pci/pdc202xx_new.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.27 # [PATCH] PCI: remove usage of pci_for_each_dev() in drivers/ide/setup-pci.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.28 # [PATCH] PCI: remove usage of pci_for_each_dev() in drivers/macintosh/via-pmu.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.29 # [PATCH] PCI: remove usage of pci_for_each_dev() in drivers/message/fusion/mptbase.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.30 # [PATCH] PCI: remove usage of pci_for_each_dev() in drivers/message/i2o/i2o_core.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.31 # [PATCH] PCI: remove usage of pci_for_each_dev() in drivers/net/e100/e100_main.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.32 # [PATCH] PCI: remove usage of pci_for_each_dev() in drivers/net/e1000/e1000_main.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.33 # [PATCH] PCI: remove usage of pci_for_each_dev() in drivers/net/ixgb/ixgb_main.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.34 # [PATCH] PCI: remove usage of pci_for_each_dev() in drivers/parport/parport_pc.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.35 # [PATCH] PCI: remove usage of pci_for_each_dev() in drivers/pci/hotplug/ibmphp_core.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.36 # [PATCH] PCI: remove usage of pci_for_each_dev() in drivers/pci/pci.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.37 # [PATCH] PCI: remove usage of pci_for_each_dev() in drivers/pci/proc.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.38 # [PATCH] PCI: remove usage of pci_for_each_dev() in drivers/pci/search.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.39 # [PATCH] PCI: remove usage of pci_for_each_dev() in drivers/pci/setup-irq.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.40 # [PATCH] PCI: remove usage of pci_for_each_dev() in drivers/pnp/resource.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.41 # [PATCH] PCI: remove usage of pci_for_each_dev() in drivers/video/pm2fb.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.42 # [PATCH] PCI: remove usage of pci_for_each_dev() in drivers/video/sis/sis_main.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.43 # [PATCH] PCI: remove usage of pci_for_each_dev() in arch/i386/pci/irq.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.44 # [PATCH] PCI: remove usage of pci_for_each_dev() in arch/i386/kernel/cpu/cpufreq/gx-suspmod.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.9.45 # [PATCH] PCI: remove usage of pci_for_each_dev() in arch/i386/pci/i386.c # -------------------------------------------- # 03/06/04 rmk@flint.arm.linux.org.uk 1.1243.33.3 # [ARM] Convert platform devices to use platform_device # # Since struct platform_device now has the ability to pass resources, # defined by the platform to the device driver, we can now use this # to handle platform specific devices. One such instance is the # StrongARM SA1111 companion chip, which can appear in various address # spaces, and connected to different IRQ lines depending on how many # cups of coffee the hardware designer had, the direction of the wind # outside the designers office that day. # # We also convert some of the other StrongARM peripheral on-chip # devices to use struct platform_device. # # ARM also provides a platform_add_devices() function which can be # used by platform code to bulk-register a tabular set of platform # devices. # -------------------------------------------- # 03/06/04 rmk@flint.arm.linux.org.uk 1.1243.33.4 # [ARM] Tidy up Integrator core support. # # This merges arch.c, irq.c and mm.c into one core file for this # platform; it's pointless keeping these separate. # -------------------------------------------- # 03/06/05 paulus@samba.org 1.1252 # Merge samba.org:/stuff/paulus/kernel/linux-2.5 # into samba.org:/stuff/paulus/kernel/for-linus-ppc # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.1.30 # Merge gregkh@kernel.bkbits.net:/home/gregkh/linux/pci-good-2.5 # into kroah.com:/home/greg/linux/BK/p-2.5 # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.1.31 # [PATCH] PCI: remove usage of pci_for_each_dev() in arch/alpha/kernel/sys_sio.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.1.32 # [PATCH] PCI: remove usage of pci_for_each_dev() in arch/arm/kernel/bios32.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.1.33 # [PATCH] PCI: remove usage of pci_for_each_dev() in arch/ia64/hp/common/sba_iommu.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.1.34 # [PATCH] PCI: remove usage of pci_for_each_dev() in arch/ia64/sn/io/pci_bus_cvlink.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.1.35 # [PATCH] PCI: remove usage of pci_for_each_dev() in arch/ia64/sn/io/pciba.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.1.36 # [PATCH] PCI: remove usage of pci_for_each_dev() in arch/ia64/sn/io/sn2/pci_bus_cvlink.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.1.37 # [PATCH] PCI: remove usage of pci_for_each_dev() in arch/mips/ddb5074/pci.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.1.38 # [PATCH] PCI: remove usage of pci_for_each_dev() in arch/mips/ddb5476/pci.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.1.39 # [PATCH] PCI: remove usage of pci_for_each_dev() in arch/mips/ddb5xxx/ddb5477/pci.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.1.40 # [PATCH] PCI: remove usage of pci_for_each_dev() in arch/mips/mips-boards/generic/pci.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.1.41 # [PATCH] PCI: remove usage of pci_for_each_dev() in arch/mips/sni/pci.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.1.42 # [PATCH] PCI: remove usage of pci_for_each_dev() in arch/mips64/mips-boards/generic/pci.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.1.43 # [PATCH] PCI: remove usage of pci_for_each_dev() in arch/mips64/sgi-ip32/ip32-pci.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.1.44 # [PATCH] PCI: remove usage of pci_for_each_dev() in arch/ppc/kernel/pci.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.1.45 # [PATCH] PCI: remove usage of pci_for_each_dev() in arch/ppc/platforms/chrp_pci.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.1.46 # [PATCH] PCI: remove usage of pci_for_each_dev() in arch/ppc/platforms/gemini_pci.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.1.47 # [PATCH] PCI: remove usage of pci_for_each_dev() in arch/ppc/platforms/pmac_pci.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.1.48 # [PATCH] PCI: remove usage of pci_for_each_dev() in arch/ppc/platforms/prep_pci.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.1.49 # [PATCH] PCI: remove usage of pci_for_each_dev() in arch/ppc64/kernel/iSeries_pci.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.1.50 # [PATCH] PCI: remove usage of pci_for_each_dev() in arch/ppc64/kernel/pSeries_pci.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.1.51 # [PATCH] PCI: remove usage of pci_for_each_dev() in arch/ppc64/kernel/pci_dma.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.1.52 # [PATCH] PCI: remove usage of pci_for_each_dev() in arch/sh/kernel/pci-sh7751.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.1.53 # [PATCH] PCI: remove usage of pci_for_each_dev() in arch/v850/kernel/rte_mb_a_pci.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.1.54 # [PATCH] PCI: remove usage of pci_for_each_dev() in arch/x86_64/kernel/bluesmoke.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.1.55 # [PATCH] PCI: remove usage of pci_for_each_dev() in arch/x86_64/kernel/pci-gart.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.1.56 # [PATCH] PCI: remove usage of pci_for_each_dev() in arch/x86_64/pci/irq.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.1.57 # [PATCH] PCI: remove usage of pci_for_each_dev() in arch/x86_64/pci/x86-64.c # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.1.58 # [PATCH] PCI: finally remove pci_for_each_dev() now that all users of it are gone. # -------------------------------------------- # 03/06/04 greg@kroah.com 1.1243.1.59 # PCI: remove usage of pci_for_each_dev() in arch/ppc64/kernel/pci.c # -------------------------------------------- # 03/06/04 acme@conectiva.com.br 1.1243.34.1 # o net: create struct sock_common and use in struct sock & tcp_tw_bucket # # With this the data dependency is reduced to just making sure that the first # member of both struct sock and struct tcp_tw_bucket are a struct sock_common. # # Also makes it easier to grep for struct sock and struct tcp_tw_bucket usage in # the tree as all the members in those structs are prefixed, respectively, with # sk_ and tw_, like struct inode (i_), struct block_device (bd_), etc. # # Checked namespace with make tags/ctags, just one colision with the macros for # the struct sock members, with a wanrouter struct, fixed that # s/sk_state/state_sk/g in the wanrouter struct. # # Checked as well if the names of the members in both structs collided with some # macro, none found. # -------------------------------------------- # 03/06/04 Jeff.Wiedemeier@hp.com 1.1243.35.1 # [PATCH] compile fix for agp_memory struct definitition change # # In 2.5.70, the agp_memory struct changed from: # typedef struct agp_memory # to: # struct agp_memory # # This patch propagates that change into include/asm-alpha/agp_backend.h and # arch/alpha/kernel/core_{titan,marvel}.c # # /jeff # -------------------------------------------- # 03/06/04 rth@kanga.twiddle.net 1.1243.35.2 # [ALPHA] Add posix timer and clock syscalls. # -------------------------------------------- # 03/06/04 torvalds@home.transmeta.com 1.1243.36.1 # Merge bk://bk.arm.linux.org.uk/linux-2.5-rmk # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/06/04 torvalds@home.transmeta.com 1.1243.1.60 # Merge bk://kernel.bkbits.net/gregkh/linux/pci-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/06/05 jgarzik@redhat.com 1.1243.1.61 # [netdrvr] gcc 3.3 cleanups # # Mostly adding 'ULL' modifier to 64-bit constants. # -------------------------------------------- # 03/06/05 jgarzik@redhat.com 1.1243.1.62 # [netdrvr skge] add ULL modifier to 64-bit constant # -------------------------------------------- # 03/06/05 reeja.john@amd.com 1.1243.1.63 # [netdrvr amd8111e] link against mii lib # -------------------------------------------- # 03/06/04 davem@nuts.ninka.net 1.1243.37.1 # Merge nuts.ninka.net:/home/davem/src/BK/network-2.5 # into nuts.ninka.net:/home/davem/src/BK/net-2.5 # -------------------------------------------- # 03/06/04 akpm@digeo.com 1.1243.38.1 # [PATCH] fix broken networking # # Fix broken "cleanup" # -------------------------------------------- # 03/06/04 akpm@digeo.com 1.1243.37.2 # [NET]: Fix broken cleanups in net/core/iovec.c # -------------------------------------------- # 03/06/04 akpm@digeo.com 1.1243.38.2 # [PATCH] aio: small cleanups # # - comment fixes # # - duplicated assignments # # - Remove a prototype which is in aio.h already # # - Some __user annotation # # - use the existing symbolic names, not magic numbers. # -------------------------------------------- # 03/06/04 akpm@digeo.com 1.1243.38.3 # [PATCH] clean up timer interpolation code # # From: Christoph Hellwig <hch@lst.de> # # - don't add one level of indentation when taking a lock # # - remove useless ti_global struct # -------------------------------------------- # 03/06/04 akpm@digeo.com 1.1243.38.4 # [PATCH] radio-cadet.c: remove unnecessary copy_to_user() # # From: Hollis Blanchard <hollisb@us.ibm.com> # # As pointed out by the Stanford checker, 'v' is not tainted. The driver # shouldn't be using copy_to_user() in cadet_do_ioctl() at all: # # cadet_do_ioctl() is being called by drivers/media/video/videodev.c: # video_usercopy(), which has already copied the buffer 'arg' (aka 'v') # into kernel space, and will copy it back after cadet_do_ioctl() # returns. So all the direct 'v' accesses are correct. # -------------------------------------------- # 03/06/04 akpm@digeo.com 1.1243.38.5 # [PATCH] cmpci: fix improper access to userspace # # From: Hollis Blanchard <hollisb@us.ibm.com> # # Fix a direct userspace access, found by the Stanford checker. # -------------------------------------------- # 03/06/04 akpm@digeo.com 1.1243.38.6 # [PATCH] zr36120: fix improper access to userspace # # From: Hollis Blanchard <hollisb@us.ibm.com> # # Fix a direct userspace access, found by the Stanford checker. # -------------------------------------------- # 03/06/04 akpm@digeo.com 1.1243.38.7 # [PATCH] remove unsafe BUG_ON() # # From: Hugh Dickins <hugh@veritas.com> # # PageDirty BUG_ON in __remove_inode_page is, and always has been, unsafe for # SMP or preemption: truncation may be racing against unmapping's # set_page_dirty in zap_pte_range (amongst a few other possibilities). # !PageUptodate error in __set_page_dirty_buffers is unsafe then too. # -------------------------------------------- # 03/06/04 akpm@digeo.com 1.1243.38.8 # [PATCH] pnpbios dereferencing user pointer # # From: Hollis Blanchard <hollisb@us.ibm.com> # # Another simple case of a memcpy that should be copy_from_user... # # Also fix some error-path memory leaks. # -------------------------------------------- # 03/06/04 akpm@digeo.com 1.1243.38.9 # [PATCH] fix bw-qcam.c bad copy_to_user # # From: Hollis Blanchard <hollisb@us.ibm.com> # # Like radio-cadet.c, bw-qcam.c is calling copy_to_user() where it shouldn't. # The user buffer is copied to/from kernel space by # drivers/media/video/videodev.c:video_usercopy(). # -------------------------------------------- # 03/06/04 akpm@digeo.com 1.1243.38.10 # [PATCH] Graceful failure in devfs_remove() # # From: Pavel Roskin <proski@gnu.org>, via Christoph Hellwig <hch@infradead.org> # # It's already the second time that I encounter a kernel panic in the same # place. When devfs_remove() is called on a non-existent file entry, the # kernel panics and I have to reboot the system. # # First time it was unregistering of pseudoterminals. This time it's # ide-floppy module that doesn't register devfs entries if the media is absent # but still tries to unregister them. The bug in ide-floppy will be reported # separately. # # The point of this message is that the failure in devfs_remove() is possible, # especially with rarely used drivers. Secondly, is not fatal enough to # justify an immediate panic and reboot. Thirdly, devfs misses a chance to # tell the user what's going wrong. # -------------------------------------------- # 03/06/04 akpm@digeo.com 1.1243.38.11 # [PATCH] Fix generic_file_write() again. # # From: "Milton D. Miller II" <miltonm@realtime.net> # # The code at present has a small problem: when a fault is encountered we will # run commit_write() to cover the amount of data which was successfully copied # in from userspace. # # But filemap_copy_from_user() may have zeroed out some more of the page. So # pagecache now has zeroes and the buffer_head which represents those zeroes is # not dirtied. So a subsequent eviction and re-read of the file in the window # beyond the faulting offset will return the file's old contents and not the # zeroes. # # So we change filemap_copy_from_user_iovec() to have the same behaviour as the # non-iovec filemap_copy_from_user(), and ensure that the commit_write() covers # the parts of the page which copy_from_user() zeroed out. # -------------------------------------------- # 03/06/04 akpm@digeo.com 1.1243.38.12 # [PATCH] reiserfs option parser fix and ability to pass # # From: Oleg Drokin <green@namesys.com> # # This patch adds support for remounting taking into account all extra options # you may want to pass it. (by Jeff Mahooney). # # Also it reworks the parser to correctly deal with mutually exclusive options. # Now whatever option was specified last will take an effect. # # - If you pass more than one jdev= option, the error will be reported and # mount/remount refused. # # - If you pass incorrect alloc= suboptions, the mount/remount will fail. # (it did not before). # # - nolargeio now actually looks at its argument. Argument is expected to be # numeric. If it is zero, default io size is set to 128k (default setting), # if it is non-zero, default io size is set to PAGE_SIZE. # -------------------------------------------- # 03/06/04 akpm@digeo.com 1.1243.38.13 # [PATCH] reiserfs support for blocksizes other than 4096 bytes # # From: Oleg Drokin <green@namesys.com> # # This patch allows reiserfs to support blocksizes from 1024 bytes and up to # PAGE_CACHE_SIZE. Also it fixes two glitches that prevent reiserfs from # working correctly in case if PAGE_CACHE_SIZE is bigger than blocksize. # # Originally this patch was created by Edward Shushkin and Vladimir Saveliev, # and then it was adapted to modern 2.4 and 2.5 by me. # # Also people should be aware that 1024 bytes blocksize is not very good thing # as tree grows very fast. mkreiserfs is able to create filesystems with # different blocksizes for quite a while already (-b switch). # -------------------------------------------- # 03/06/04 akpm@digeo.com 1.1243.38.14 # [PATCH] hugetlbfs: mount options and permissions # # From: "Seth, Rohit" <rohit.seth@intel.com> # # This patch enables system administrators to more flexibly assign read/write # permissions to files in hugetlbfs. Mount options are added which will # specify the uid, gid and mode of the filesystem's root directory. # # This patch also enables super users to do chown/chgrp on files in hugetlbfs. # # Also included in this patch is the support for uid, gid and mode command line # options for mount command for hugetlbfs. # # The following mount options are added to hugetlbfs: # # uid=value gid=value mode=value # # The values may be specified in hex (0xNNN), decimal or octal (0NNN). # -------------------------------------------- # 03/06/04 akpm@digeo.com 1.1243.38.15 # [PATCH] DEADLINE: hash removal fix # # From Jens: It fixes the occasional # # BUG_ON(list_empty(&req->queuelist)); # # which people have been hitting in include/linux/blkdev.h: # blkdev_dequeue_request() # -------------------------------------------- # 03/06/04 akpm@digeo.com 1.1243.38.16 # [PATCH] ext3: fix deadlock in journal_create() # # From: Mark Fasheh <mark.fasheh@oracle.com> # # journal_create() is called under down_write(s_umount) on the mount path. But # it calls fsync_bdev(), which wants down_write(s_umount). # # Change journal_create() to run sync_blockdev() instead. Just to write out # the new journal's blocks. # -------------------------------------------- # 03/06/04 davidm@napali.hpl.hp.com 1.1243.38.17 # [PATCH] allow thread_info to be allocated as part of task_struct # # This re-organizes the thread info allocations a bit, so that # architectures like ia64 that want to allocate the thread_info structure # as part of the task structure allocation can do so. # # The bulk of the patch is adding the "tsk" information to the thread # info allocator (ignored by all non-ia64 architectures), and switching # the order of the allocators to make this all possible. # -------------------------------------------- # 03/06/04 davem@nuts.ninka.net 1.1243.37.3 # [PCI]: Move pci_remove_bus_device back to include/linux/pci.h, discussed with greg@kroah.com # -------------------------------------------- # 03/06/04 neilb@cse.unsw.edu.au 1.1243.38.18 # [PATCH] Fix raid5 bug where wrong 'dev' is used. # -------------------------------------------- # 03/06/04 neilb@cse.unsw.edu.au 1.1243.38.19 # [PATCH] Fix raid1 handling of writing to multiple devices. # # When raid1 writes, it needs to schedule writes to some number # of devices, and when all writes have completed, the r1_bio # structure that holds it all together must be freed. # However we must make sure not to free it before all devices # have been considered for submitting writes to. # # This happens in two places: when submitting a normal write request # and when submiting a write as part of resync. # # This patch makes both these places: # the same # simpler # more correct. # -------------------------------------------- # 03/06/04 neilb@cse.unsw.edu.au 1.1243.38.20 # [PATCH] Fix up freeing of kmalloc structures # # Some paths free things twice, others free un-initialised values :-( # Not any more. # -------------------------------------------- # 03/06/04 neilb@cse.unsw.edu.au 1.1243.38.21 # [PATCH] Fix bug in /proc/mdstat # # If /proc/mdstat is large, or reads are for a small size, # then the last line of /proc/mdstat is repeated infinitely. # # This patch will fix it. # -------------------------------------------- # 03/06/04 zippel@linux-m68k.org 1.1243.38.22 # [PATCH] choice handling fixes # # A few choice handling fixes: # - only visible choice values define the new state of the complete choice # - improve handling of choices without visible value # - two new warnings # -------------------------------------------- # 03/06/04 shemminger@osdl.org 1.1243.37.4 # [NET]: Fix device unregister in TUN driver. # -------------------------------------------- # 03/06/04 davem@kernel.bkbits.net 1.1243.37.5 # Merge davem@nuts.ninka.net:/home/davem/src/BK/net-2.5 # into kernel.bkbits.net:/home/davem/net-2.5 # -------------------------------------------- # 03/06/05 davem@nuts.ninka.net 1.1243.39.1 # Merge nuts.ninka.net:/home/davem/src/BK/network-2.5 # into nuts.ninka.net:/home/davem/src/BK/net-2.5 # -------------------------------------------- # 03/06/05 viro@parcelfarce.linux.theplanet.co.uk 1.1243.39.2 # [NET]: Convert USB drivers away from init_etherdev(). # -------------------------------------------- # 03/06/05 bde@nwlink.com 1.1243.38.23 # [SPARC64]: Fix transmit handling in sunsab.c serial driver. # -------------------------------------------- # 03/06/05 steve@gw.chygwyn.com 1.1243.39.3 # [AX25]: Sanitize ax25 netdevice private handling. # -------------------------------------------- # 03/06/05 bcollins@debian.org 1.1243.38.24 # [SPARC64]: Final image strip not to strip too much. # -------------------------------------------- # 03/06/05 elenstev@mesatop.com 1.1243.38.25 # [SPARC]: Fix non-ansi parameter lists. # -------------------------------------------- # 03/06/05 bcollins@debian.org 1.1243.40.1 # [PATCH] USB: fix keyboard leds # # > Ben, it looks like your patch broke something for USB keyboards, any # > idea? # # Yep, my patch killed hid-input from scanning HID_OUTPUT_REPORT's. Fixed # with this patch for 2.5.70+bk. I'll send one for 2.4.x in a few minutes. # -------------------------------------------- # 03/06/05 david-b@pacbell.net 1.1243.40.2 # [PATCH] USB: kerneldoc for gadget API # # Here's the non-inlined doc for the gadget API. # -------------------------------------------- # 03/06/05 oliver@neukum.org 1.1243.40.3 # [PATCH] USB: cut usb_set_config from hpusbscsi # # this cuts out old cruft. # -------------------------------------------- # 03/06/05 oliver@neukum.org 1.1243.40.4 # [PATCH] USB: usb_set_configuration in empeg.c # # you should not drop errors. # - proper error detection during initialisation # -------------------------------------------- # 03/06/05 torvalds@home.transmeta.com 1.1243.41.1 # Merge bk://are.twiddle.net/axp-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/06/05 axboe@suse.de 1.1243.41.2 # [PATCH] kill old stuff # # and fix the start/stop thing as well. I think this is all of them. # -------------------------------------------- # 03/06/05 torvalds@home.transmeta.com 1.1243.37.6 # Merge bk://kernel.bkbits.net/davem/net-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/06/05 davej@codemonkey.org.uk 1.1243.42.1 # [CPUFREQ] Make powernow-k7 leap big buildings^Wranges. # When scaling upwards, we need to change the voltage before the frequency. # When scaling downwards, the opposite. # This may fix some of the hangs people have been seeing when jumping # from a low frequency to a very high frequency. # -------------------------------------------- # 03/06/05 paulus@samba.org 1.1243.37.7 # [PATCH] get rid of CONFIG_ALL_PPC # # This patch gets rid of CONFIG_ALL_PPC, which was a very confusing # option, since it didn't actually mean "ALL" at all, it was more a # "common set" thing. # # The primary replacement for CONFIG_ALL_PPC is CONFIG_PPC_MULTIPLATFORM. # I have also defined CONFIG_PPC_PMAC, CONFIG_PPC_PREP and CONFIG_PPC_CHRP # for selecting code which is only needed for one of the three platforms # that CONFIG_ALL_PPC represented. This is something that we (the PPC # community) have been talking about doing for some time. There is also a # CONFIG_PPC_OF which is for PPC machines with Open Firmware, which is # currently powermacs and CHRP machines. # # At the moment, CONFIG_PPC_{PMAC,PREP,CHRP,OF} get unconditionally # defined if CONFIG_PPC_MULTIPLATFORM is selected, but in future this # split will let us have more control over what gets included, so that # for example we don't necessarily have to include powermac bits in a # kernel for a PReP machine. # # I have gone through the uses of CONFIG_ALL_PPC one by one and decided # which of the new symbols best represents the set of machines that need # the code in question. In fact most of the uses of CONFIG_ALL_PPC in # the drivers have been replaced by CONFIG_PPC_PMAC. The other symbols # are mostly confined to the PPC architecture code. # -------------------------------------------- # 03/06/05 mochel@osdl.org 1.1243.43.1 # [fs] Remove kobject support for filesystems # # It was initially added for the immediate gain of being able to see what # filesystems were registered in the system. However, it was done without # proper analysis of the lifetime rules associated with them. # # Someday, we should convert struct filesystem_type and struct super_block to # use kobjects, though it will take sufficent time and effort to get it right. # Until then, we go without.. # -------------------------------------------- # 03/06/05 davej@codemonkey.org.uk 1.1243.42.2 # [CPUFREQ] kill cpufreq_driver export. # From Dominik Brodowski. # This removes the special export of cpufreq_driver for proc_intf.c. Instead, # the behaviour of /proc/cpufreq previous of Greg's class re-write is back: # the check whether cpufreq_driver is loaded is done within cpufreq_cpu_get # -------------------------------------------- # 03/06/05 davej@codemonkey.org.uk 1.1243.42.3 # [CPUFREQ] Kill unused variables. # -------------------------------------------- # 03/06/05 mochel@osdl.org 1.1243.43.2 # [kobject] Remove kobj_lock and use lockless refcounting. # # The only thing preventing this from happening earlier was the circular sysfs # registration dependency - it would need to be initialized before it was # registered, but needed to be registered before it was initialized. # # With kobjects gone from struct filesystem_type, the dependency no longer # exists and we don't have to special-case the possibility that a kobject will # be passed to kobject_get with a refcount == 0. # # Note that a kobject with a count of 0 in that function is still a bug, but # one in the subsystem making the call. We should add a debugging hook to dump # the stack if it does happen. # -------------------------------------------- # 03/06/05 davej@codemonkey.org.uk 1.1243.42.4 # [CPUFREQ] CodingStyle fixes # -------------------------------------------- # 03/06/05 davej@codemonkey.org.uk 1.1243.42.5 # [CPUFREQ] Fix ACPI P-State driver. # from Dmitry Torokhov. # # I have the following problems with ACPI P-States driver: # # - It crashes because it tries to switch CPU speed without registering cpufreq # driver first but acpi_processor_set_performance calls cpufreq_notify_transition. # # - When testing for capable CPUs it skips all online ones so for my single CPU # notebook it can't activate at all. # # - If a processor does not support throttling then it will say that "limit" # interface is not supported even after activating performance control. # # The patch below should fix these issues. It also adds some info messages since # /proc/acpi/processor/*/performance interface is marked obsolete but i still # would like to see if P-states were recognized during boot. # -------------------------------------------- # 03/06/05 greg@kroah.com 1.1243.37.8 # [PATCH] PCI: remove direct access of pci_devices from arch/m68k/atari/hades-pci.c # -------------------------------------------- # 03/06/05 greg@kroah.com 1.1243.37.9 # [PATCH] PCI: remove direct access of pci_devices from drivers/macintosh/via-pmu68k.c # # Yeah, this is commented out code, but just trying to be complete... # -------------------------------------------- # 03/06/05 greg@kroah.com 1.1243.37.10 # [PATCH] PCI: fix up previous fusion driver pci changes # # This makes the driver build properly now, and removes a direct access # of the pci_devices variable. # -------------------------------------------- # 03/06/05 greg@kroah.com 1.1243.37.11 # [PATCH] PCI: add pci_find_device_reverse() for users of pci_find_each_dev_reverse() to use # -------------------------------------------- # 03/06/05 greg@kroah.com 1.1243.37.12 # [PATCH] PCI: remove usage of pci_for_each_dev_reverse() in # -------------------------------------------- # 03/06/05 greg@kroah.com 1.1243.37.13 # [PATCH] PCI: remove pci_for_each_dev_reverse() now that all users of it are gone. # -------------------------------------------- # 03/06/05 greg@kroah.com 1.1243.37.14 # [PATCH] PCI: move pci_present() into drivers/pci/search.c # # This will let not have to export the pci_devices variable. # -------------------------------------------- # 03/06/05 greg@kroah.com 1.1243.37.15 # [PATCH] PCI: remove EXPORT_SYMBOL(pci_devices) # # Now the only users of this directly should be the pci core and arch specific # pci core code. # -------------------------------------------- # 03/06/05 torvalds@home.transmeta.com 1.1243.44.1 # Merge bk://kernel.bkbits.net/davem/sparc-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/06/05 mhoffman@lightlink.com 1.1243.25.2 # [PATCH] I2C: more w83781d fixes # # This patch fixes the various return values in the w83781d_detect() # error paths. It also cleans up some formatting here and there. # It should be applied on top of the previous one. # # It works for me; same caveat as above w.r.t. ISA. # -------------------------------------------- # 03/06/05 aschultz@warp10.net 1.1243.25.3 # [PATCH] I2C: fix unsafe usage of list_for_each in i2c-core # # i2c-core.c contains 2 loops that iterate over the list of the clients attached # to an adapter and detaches them. Detaching the clients will actually remove # them from the list the loop is iterating over. Therefore the # list_for_each_safe() method has to be used. # -------------------------------------------- # 03/06/05 shemminger@osdl.org 1.1243.44.2 # [PATCH] typo in new class_device_release # # There is a typo in the current 2.5.70 bk version of class_device_release that # was not there in my original patch. By confusing the class and the class_device, # the release function oops. cd->release is always the function itself (class_device_release), # cls->release is the one setup for the class (net_class in my case). # -------------------------------------------- # 03/06/05 greg@kroah.com 1.1243.25.4 # [PATCH] I2C: sync i2c-id.h with cvs version. # -------------------------------------------- # 03/06/05 Kurt.Robideau@comtrol.com 1.1243.45.1 # [PATCH] Rocketport driver against 2.5.70-bk7 # # Update the Rocketport driver # -------------------------------------------- # 03/06/05 greg@kroah.com 1.1243.44.3 # Merge kroah.com:/home/greg/linux/BK/bleed-2.5 # into kroah.com:/home/greg/linux/BK/i2c-2.5 # -------------------------------------------- # 03/06/05 mochel@osdl.org 1.1243.43.3 # [driver model] Add device_for_each_child iterator. # # From Mike Anderson: # # I have been using it on an outstanding patch for scsi_set_host_offline. It # appears to work fine in my testing. # -------------------------------------------- # 03/06/05 greg@kroah.com 1.1243.46.1 # Merge kroah.com:/home/greg/linux/BK/bleed-2.5 # into kroah.com:/home/greg/linux/BK/tty-2.5 # -------------------------------------------- # 03/06/05 greg@kroah.com 1.1243.47.1 # Merge kroah.com:/home/greg/linux/BK/bleed-2.5 # into kroah.com:/home/greg/linux/BK/gregkh-2.5 # -------------------------------------------- # 03/06/05 greg@kroah.com 1.1243.37.16 # Merge kroah.com:/home/greg/linux/BK/bleed-2.5 # into kroah.com:/home/greg/linux/BK/pci-2.5 # -------------------------------------------- # 03/06/05 mochel@osdl.org 1.1243.43.4 # [kobject] Add warning + back trace if kobject_get() is called with 0 refcount. # -------------------------------------------- # 03/06/05 greg@kroah.com 1.1243.46.2 # TTY: add a release function for tty_class devices. # # This fixes a race with looking at files in /sys/class/tty/ and removing a # tty device. # -------------------------------------------- # 03/06/05 mochel@osdl.org 1.1243.48.1 # Merge osdl.org:/home/mochel/src/kernel/devel/linux-2.5-virgin # into osdl.org:/home/mochel/src/kernel/devel/linux-2.5-core # -------------------------------------------- # 03/06/05 torvalds@home.transmeta.com 1.1243.37.17 # Merge bk://kernel.bkbits.net/gregkh/linux/pci-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/06/05 torvalds@home.transmeta.com 1.1243.37.18 # Merge bk://kernel.bkbits.net/gregkh/linux/i2c-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/06/05 mochel@osdl.org 1.1243.48.2 # [driver model] Remove extraneous class device release method. # # What happens when you get a patch that does something an applied patch # already does, but a little better, and merge it sloppily: You end up calling # the wrong function because you've defined equivalent methods in two places. # # Bad Pat, Bad. # -------------------------------------------- # 03/06/05 greg@kroah.com 1.1243.46.3 # TTY: release function should be set in the class, not the class_device. # -------------------------------------------- # 03/06/05 torvalds@home.transmeta.com 1.1243.37.19 # Merge bk://ldm.bkbits.net/linux-2.5-core # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/06/05 torvalds@home.transmeta.com 1.1243.37.20 # Merge bk://kernel.bkbits.net/gregkh/linux/tty-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/06/06 paulus@samba.org 1.1253 # Merge samba.org:/stuff/paulus/kernel/linux-2.5 # into samba.org:/stuff/paulus/kernel/for-linus-ppc # -------------------------------------------- # 03/06/05 joern@wohnheim.fh-wedel.de 1.1243.37.21 # [PATCH] zlib cleanup: remove FAR macro # # This removes FAR, the typedefs using FAR (Bytef and friends) and the # function prototypes for zalloc and zfree that should have gone earlier # already. # -------------------------------------------- # 03/06/05 joern@wohnheim.fh-wedel.de 1.1243.37.22 # [PATCH] zlib cleanup: __32BIT__ and STDC # # Remove unused __32BIT__ and STDC macros # -------------------------------------------- # 03/06/05 joern@wohnheim.fh-wedel.de 1.1243.37.23 # [PATCH] zlib cleanup: ZEXTERN # # This one was just simple s/ZEXTERN/extern/g. # -------------------------------------------- # 03/06/05 joern@wohnheim.fh-wedel.de 1.1243.37.24 # [PATCH] zlib cleanup: ZEXPORT # # Just a simple s/ZEXPORT//. # -------------------------------------------- # 03/06/05 joern@wohnheim.fh-wedel.de 1.1243.37.25 # [PATCH] zlib cleanup: z_off_t # # This nice macro must have been one of the good intentions on the road # to hell. Completely unused. :) # -------------------------------------------- # 03/06/05 joern@wohnheim.fh-wedel.de 1.1243.37.26 # [PATCH] zlib cleanup: OF # # Remove the stale support for K&R function declarations through the OF() # macro. # # This is the last patch to clean up zconf.h, at least for now. # -------------------------------------------- # 03/06/05 torvalds@home.transmeta.com 1.1243.37.27 # zlib cleanup: final fixups # # Jörn missed a few places of FAR conversion in inflate # -------------------------------------------- # 03/06/05 rth@kanga.twiddle.net 1.1243.35.3 # [ALPHA] Add semtimedop syscall. # -------------------------------------------- # 03/06/05 rth@kanga.twiddle.net 1.1243.49.1 # Merge kanga.twiddle.net:/home/rth/work/linux/linus-2.5 # into kanga.twiddle.net:/home/rth/work/linux/axp-2.5 # -------------------------------------------- # 03/06/05 hollisb@us.ibm.com 1.1243.37.28 # [PATCH] awe_wave.c user pointer dereference # # Two ioctl functions in sound/oss/awe_wave.c were directly dereferencing # a user-supplied pointer in a few places. # -------------------------------------------- # 03/06/06 paulus@samba.org 1.1254 # PPC32: Compile fix for array initialization from Christoph Hellwig. # -------------------------------------------- # 03/06/06 porter@cox.net 1.1255 # PPC32: Resolve colliding includes in boot wrappers. # -------------------------------------------- # 03/06/06 paulus@samba.org 1.1256 # PPC32: Cleanups from Christoph Hellwig and Tom Rini. # -------------------------------------------- # 03/06/06 shemminger@osdl.org 1.1243.1.64 # [PATCH] sb1000 driver bugs # # Inspecting the sb1000 driver showed some interesting bugs: # - net device pointer is used before the device is allocated; gcc # does catch this. # - unregister is called even though device not registered successfully # - net device is not freed on remove. # # Compiles but don't have hardware to test. Don't know how it ever worked though. # -------------------------------------------- # 03/06/06 srk@thekelleys.org.uk 1.1243.1.65 # [netdrvr] add atmel[_cs], new wireless driver # # Attached is a driver for Atmel at76c50x WiFi cards. This code started # out as a GPL release from Atmel of pretty horrible quality and I've # extensively re-worked it with the aim of making it acceptable in the # kernel. Please could you take a look and either pass it into the patch # stream or let me know what's wrong with it? # # The code has been tested on at least three different brand cards by # different people. Jean Tourrilhes took a look at an earlier version an # was positive. He's put incorporating this into 2.6 as a priority 1. # The patch works fine on 2.5.70. # # The firmware issue has been addressed now. The only firmware in the # driver is a small stub which reads the MAC address from NVRAM on the # card. The source for that is included so there are no GPL issues. The # main firmware is loaded from userspace using Manuel Estrada Sainz's # sysfs firmware class. I know that the patch for that has been # accepted but it hasn't turned up anywhere I can see yet. The # driver compiles fine even without the firmware class. I've made a # package of the firmware images which is available from my website. # # The remaining issues with the driver are migrating PCMCIA to the new # driver model and PCI support. I'm happy to produce followup patches as # the PCMCIA system gets evolved to the new driver model: the timing on # that is controlled by others. This set of chips includes a PCI version # and the driver should support that, but AFAIK there is no PCI hardware # available anywhere. If Atmel can provide me with some it will be # simple to add PCI support. # # The driver uses the CRC32 library module and the firmware loader. I've # not put in dependencies on those, but when the lastest set of patches # go into Kconfig I'll set it up so that selecting the Atmel driver # selects CRC32 and FW_LOADER too. # -------------------------------------------- # 03/06/06 jgarzik@redhat.com 1.1243.1.66 # [netdrvr] add MAINTAINERS entry for atmel wireless driver # -------------------------------------------- # 03/06/06 zwane@linuxpower.ca 1.1243.1.67 # [PATCH] cli/sti cleanup for fmvj18x # # This one should be safe as we're protected by the xmit_lock in all instances # -------------------------------------------- # 03/06/06 scott.feldman@intel.com 1.1243.1.68 # [PATCH] 10GbE ethtool support # # Add 10GbE support for ethtool. # -------------------------------------------- # 03/06/06 scott.feldman@intel.com 1.1243.1.69 # [PATCH] remove ethtool privileged references # # dev_ioctl already checks capable(CAP_NET_ADMIN) for SOICETHTOOL, so # privileged reference are not necessary. # -------------------------------------------- # 03/06/06 yoshfuji@linux-ipv6.org 1.1243.1.70 # [netdrvr] C99 initializers for arcnet # -------------------------------------------- # 03/06/06 jgarzik@redhat.com 1.1243.1.71 # Merge redhat.com:/garz/repo/linus-2.5 # into redhat.com:/garz/repo/net-drivers-2.5 # -------------------------------------------- # 03/06/06 davem@nuts.ninka.net 1.1243.37.29 # Merge nuts.ninka.net:/home/davem/src/BK/network-2.5 # into nuts.ninka.net:/home/davem/src/BK/net-2.5 # -------------------------------------------- # 03/06/06 hch@lst.de 1.1243.37.30 # [NET]: Convert ppc early-init drivers to initcalls. Ack'd by Paul Mackerras. # -------------------------------------------- # 03/06/06 davem@nuts.ninka.net 1.1243.37.31 # [NET]: Kill drivers/net/setup.c, it no longer does anything. # -------------------------------------------- # 03/06/06 kuznet@oops.inr.ac.ru 1.1243.37.32 # tcp_output.c, tcp.c, tcp.h: # reconciling TCP_CORK and TCP_NODELAY # -------------------------------------------- # 03/06/06 rth@kanga.twiddle.net 1.1243.1.72 # Merge kanga.twiddle.net:/home/rth/work/linux/linus-2.5 # into kanga.twiddle.net:/home/rth/work/linux/axp-2.5 # -------------------------------------------- # 03/06/06 davem@nuts.ninka.net 1.1243.37.33 # [IPSEC]: Implement xfrm type module autoloading. # -------------------------------------------- # 03/06/06 perex@suse.cz 1.1243.50.1 # ALSA update # - added AZT3328 driver # - added Terratec Aureon support to ICE1724 driver # - fixed possible PCI posting problems # - ENS1370, ENS1371, FM801, ICE1712, ICE1724, VIA82xx # - AC'97 code # - added new IDs # - fixed typo in S/PDIF code # - C-Media related fixes # - USB driver # - added nrpacks module option # - added hack for AudioTrak Optoplay # - removed OLD_USB stuff # -------------------------------------------- # 03/06/06 davem@nuts.ninka.net 1.1243.37.34 # Merge bk://kernel.bkbits.net/acme/sock-2.5 # into nuts.ninka.net:/home/davem/src/BK/sock-2.5 # -------------------------------------------- # 03/06/06 davem@nuts.ninka.net 1.1243.37.35 # [NET]: Some stuff missed during acme's struct sock cleanup. # -------------------------------------------- # 03/06/06 davem@kernel.bkbits.net 1.1243.51.1 # Merge davem@nuts.ninka.net:/home/davem/src/BK/net-2.5 # into kernel.bkbits.net:/home/davem/net-2.5 # -------------------------------------------- # 03/06/06 davem@nuts.ninka.net 1.1243.37.36 # [NET]: Missing __KERNEL__ ifdefs in linux/{tcp,udp}.h # -------------------------------------------- # 03/06/06 davem@kernel.bkbits.net 1.1243.51.2 # Merge davem@nuts.ninka.net:/home/davem/src/BK/net-2.5 # into kernel.bkbits.net:/home/davem/net-2.5 # -------------------------------------------- # 03/06/06 zippel@linux-m68k.org 1.1243.52.1 # [PATCH] boolean symbol state fix # # This is an important fix to allow changing boolean symbols, whose # dependency is 'm'. All internal symbol states must be converted from # the tristate into boolean the state. # # I missed this change while adding expression support for defaults, # please apply. # -------------------------------------------- # 03/06/06 zippel@linux-m68k.org 1.1243.52.2 # [PATCH] ignore attempts to change unchangable symbols # # This fixes a problem which can show up with the new select facility, e.g. # a symbol is forced to 'y', so we should never even try to change such # symbols. # -------------------------------------------- # 03/06/06 akpm@digeo.com 1.1243.52.3 # [PATCH] kmalloc_percpu: interface change # # From: Rusty Russell <rusty@rustcorp.com.au> # # Several tweaks to the kmalloc_percpu()/kfree_percpu() interface, to # allow future implementations to be more flexible, and make easier to # use now we can see how it's actually being used. # # 1) No flags argument: GFP_ATOMIC doesn't make much sense, # # 2) Explicit alignment argument, so we don't have to give SMP_CACHE_BYTES # alignment always, # # 3) Zeros memory, since most callers want that and it's not entirely # trivial, # # 4) Convenient type-safe wrapper which takes a typename, and # # 5) Rename to alloc_percpu/__alloc_percpu, since usage no longer matches # kmalloc. # -------------------------------------------- # 03/06/06 akpm@digeo.com 1.1243.52.4 # [PATCH] per-cpu support inside modules (minimal) # # From: Rusty Russell <rusty@rustcorp.com.au> # # OK, this does the *minimum* required to support DEFINE_PER_CPU inside # modules. If we decide to change kmalloc_percpu later, great, we can turf # this out. # # Basically, overallocates the amount of per-cpu data at boot to at least # PERCPU_ENOUGH_ROOM if CONFIG_MODULES=y (arch-specific by default 32k: I have # only 7744 bytes of percpu data in my kernel here, so makes sense), and a # special allocator in module.c dishes it out. # -------------------------------------------- # 03/06/06 akpm@digeo.com 1.1243.52.5 # [PATCH] IRQs: handle bad return values from handlers # # Attempt to do something intelligent with IRQ handlers which don't return # IRQ_HANDLED. # # - If they return neither IRQ_HANDLED nor IRQ_NONE, complain. # # - If they return IRQ_NONE more than 99900 times in 100000 interrupts, complain # and disable the IRQ. # # I did have it at 750-in-1000, but someone had an otherwise-functioning # system which triggered it. # # The 99.9% ratio is designed to address the problem wherein the babbling # device shares an IRQ with a good device. We don't want the good device's # trickle of IRQ_HANDLED callouts to defeat the lockup detector. (fat chance # os this working right). # # - Add a kernel boot parameter `noirqdebug' to turn the whole thing off. # -------------------------------------------- # 03/06/06 akpm@digeo.com 1.1243.52.6 # [PATCH] IRQs: fix up irq_desc initialisation for non-ia32 # # The addition of more fields to irq_desc_t may have broken compilation of # other architectures. Go through and C99ify them (was needed anyway). # -------------------------------------------- # 03/06/06 akpm@digeo.com 1.1243.52.7 # [PATCH] force_successful_syscall_return() # # From: David Mosberger <davidm@napali.hpl.hp.com>, Christoph Hellwig # # I believe this is the last outstanding piece that prevents ia64 from being # fully in sync with Linus' tree (yes, there are some minor ACPI changes # outstanding and a toolchain bug that's left to fix, but other than that, I # think we're clean). # # Many architectures (alpha, ia64, ppc, ppc64, sparc, and sparc64 at least) # use a syscall convention which provides for a return value and a separate # error flag. On those architectures, it can be beneficial if the kernel # provides a mechanism to signal that a syscall call has completed # successfully, even when the returned value is potentially a (small) # negative number. The patch below provides a hook for such a mechanism via # a macro called force_successful_syscall_return(). On x86, this would be # simply a no-op (because on x86, user-level has to be hacked to handle such # cases). On Alpha, it would be something along the lines of: # # #define force_successful_syscall_return() ptregs->r0 = 0 # # where "ptregs" is a pointer to the user's ptregs structure of the current # task. On ia64, we have been using this for a long time: # # static inline void force_successful_syscall_return (void) { # ia64_task_regs(current)->r8 = 0; # } # # The other architectures (ppc, ppc64, sparc, and sparc64) currently have no # mechanism to force a syscall return to be successful. But since the # syscall convention already provide for a separate error flag, the arch # maintainers could change this if they wanted to. # # There are only 3 places in the platform-independent portion of the kernel # that need this macro: # # - memory_lseek() in drivers/char/mem.c # - fs/fcntl.c for F_GETOWN # - lseek for /proc/mem in fs/proc/array.c # # Ideally, there are a couple of other places that could benefit from this # macro: # # - sys_getpriority() # - sys_shmat() # - sys_brk() # - do_mmap2() # - do_mremap() # # but these are not so critical, because the can be worked around in # platform-specific code (e.g., see arch/ia64/kernel/sys_ia64.c). # # Note that for the above 3 cases, handling them in user level is rather # suboptimal: # # - it would affect all lseek() syscalls, even though only /proc/mem and # /dev/mem need the special treatment (at least until there are # filesystems that can handle files >= 2^63 bytes) # # - all fcntl() calls would be affected, even though only F_GETOWN needs # the special treatment # # so I think handling these in the kernel for the platforms that can makes # tons of sense. # # The only limitation of force_successful_syscall_return() is that it doesn't # help with system calls performed by the kernel. But the kernel does that # so rarely and for such a limited set of syscalls that this is not a real # problem. # -------------------------------------------- # 03/06/06 akpm@digeo.com 1.1243.52.8 # [PATCH] fix wobbly /proc/stat:btime # # From: john stultz <johnstul@us.ibm.com> # # Since jiffies didn't necessarily start incrementing at a second boundary, # jiffies/HZ doesn't increment at the same moment as xtime.tv_sec. This # causes one second wobbles in the calculation of btime (xtime.tv_sec - # jiffies/HZ). # # This fix increases the precision of the calculation so the usec component # of xtime is used as well. Additionally it fixes some of the non-atomic # reading of time values. # -------------------------------------------- # 03/06/06 akpm@digeo.com 1.1243.52.9 # [PATCH] Console blanking fix # # From: Samuel Thibault <Samuel.Thibault@ens-lyon.fr> # # Some fixes for console blanking: on some laptops, doing VESA blanking after # the bios did an apm blanking because of a screen closure thrashes the # recovery (the video board doesn't seem to have synchronisation registers # correctly initialized, since the LCD panel progressively turns white, maybe # damaging it ?). # # I hence moved the schedule for vesa powerdown after the apm blank hook # call, so that if it succeeds, it won't be called. I also moved the apm # unblank & palette restoration after the vesa unblank, to have a more lifo # scheme (also required, or the screen remains black). # # Btw, why del_timer_sync was called twice in timer_do_blank_screen when # vesa_off_interval==0 ? # -------------------------------------------- # 03/06/06 akpm@digeo.com 1.1243.52.10 # [PATCH] Console privacy for braille users # # From: Samuel Thibault <Samuel.Thibault@ens-lyon.fr> # # Still working on kernel facilities for braille devices, the need for being # able to force blanking and unblanking raised: even when a key is pressed, the # screen must remain blank, for privacy of the blind user who is typing on the # keyboard and reading on its braille terminal. # # I merely added an ignore_poke variable which is set, and the screen blanked. # Then, poke_blanked_console returns immediatly. Upon real unblank (because of # an Oops or an explicit tioclinux), ignore_poke is reset to get back to normal # operation mode. # # I had to remove the (unnecessary ?) call to unblank_screen from set_selection # to prevent mouse selection unblanking the screen. # # I also added a way for processes to know whether the screen is blanked (the # blind user might hence know whether people can read the screen). # -------------------------------------------- # 03/06/06 akpm@digeo.com 1.1243.52.11 # [PATCH] Fix tty devfs mess # # From: Christoph Hellwig <hch@lst.de> # # Currently the tty code abuses tty_driver.name as the prefix for the devfs # names of the ttys. This is a very bad idea because it means the tty name # changes depending on whether devfs is enabled or not, leading to different # names in /proc/tty/ depending on whether we have devfs or not (and not # whether it actually is mounted!) and a huge amount of ifdefs. # # The patch below adds a .devfs_name member instead, similar to the block # device changes a few weeks ago. # -------------------------------------------- # 03/06/06 akpm@digeo.com 1.1243.52.12 # [PATCH] misc fixes # # - Add comment about slab ctor behaviour (Ingo Oeser) # # - mm/slab.c:fprob() shows up in profiles a lot. Rename it to something more # meaningful. # # - fatfs printk warning fix (Randy Dunlap) # # - give the the time interpolator list and lock file-static scope (hch) # -------------------------------------------- # 03/06/06 akpm@digeo.com 1.1243.52.13 # [PATCH] cs423x fixes # # From: Adam Belay <ambx1@neo.rr.com> # # - cs4236 doesn't check if the memory for the resource table was # successfully allocated. # -------------------------------------------- # 03/06/06 akpm@digeo.com 1.1243.52.14 # [PATCH] remove get_current_user() # # As "Dmitry A. Fedorov" <D.A.Fedorov@inp.nsk.su> points out, # get_current_user() has a local variable __user which conflicts with the # sparse tagging. But get_current_user() has no callers. # -------------------------------------------- # 03/06/06 akpm@digeo.com 1.1243.52.15 # [PATCH] remove triggerable BUG() from de_thread # # From: Ingo Molnar <mingo@elte.hu> # # Apparently this BUG is triggerable due to correct and expected events. # -------------------------------------------- # 03/06/06 akpm@digeo.com 1.1243.52.16 # [PATCH] Don't let processes be scheduled on CPU-less nodes (1/3) # # From: Matthew Dobson <colpatch@us.ibm.com> # # sched_best_cpu schedules processes on nodes based on node_nr_running. For # CPU-less nodes, this is always 0, and thus sched_best_cpu tends to migrate # tasks to these nodes, which eventually get remigrated elsewhere. # # This patch adds include/linux/topology.h, and modifies all includes of # asm/topology.h to linux/topology.h. A subsequent patch in this series adds # helper functions to linux/topology.h to ensure processes are only migrated # to nodes with CPUs. # # Test compiled and booted by Andrew Theurer (habanero@us.ibm.com) on both # x440 and ppc64. # -------------------------------------------- # 03/06/06 akpm@digeo.com 1.1243.52.17 # [PATCH] Don't let processes be scheduled on CPU-less nodes (2/3) # # From: Matthew Dobson <colpatch@us.ibm.com> # # This patch defines a topology macro for ppc64, nr_cpus_node(node) which # returns the number of CPUs on 'node'. This patch also adds code to compute # and store these values in an array for quick lookup. # # Test compiled and booted by Andrew Theurer (habanero@us.ibm.com) on both # x440 and ppc64. # -------------------------------------------- # 03/06/06 akpm@digeo.com 1.1243.52.18 # [PATCH] Don't let processes be scheduled on CPU-less nodes (3/3) # # From: Matthew Dobson <colpatch@us.ibm.com> # # This patch implements a generic version of the nr_cpus_node(node) macro # implemented for ppc64 by the previous patch. # # The generic version simply computes an hweight of the bitmask returned by # node_to_cpumask(node) topology macro. # # This patch also adds a generic_hweight64() function and an hweight_long() # function which are used as helpers for the generic nr_cpus_node() macro. # # This patch also adds a for_each_node_with_cpus() macro, which is used in # sched_best_cpu() in kernel/sched.c to fix the original problem of # scheduling processes on CPU-less nodes. This macro should also be used in # the future to avoid similar problems. # # Test compiled and booted by Andrew Theurer (habanero@us.ibm.com) on both # x440 and ppc64. # -------------------------------------------- # 03/06/06 akpm@digeo.com 1.1243.52.19 # [PATCH] DAC960 fix for fibre channel transfer rate # # From: Dave Olien <dmo@osdl.org> # # The change makes the transfer rate numbers come out right for the fibre # channel version of this controller. # # For 1G FC, the NegotiatedSynchronousMegaTransfers is 1000, and the # NegotiatedDataWidthBIts is 1. The old code assumed NegotiatedDataWidthBits # was always either 8 or 16. The new code is simpler, and does the # calculation correctly for all cases. # -------------------------------------------- # 03/06/06 akpm@digeo.com 1.1243.52.20 # [PATCH] /proc/sys/vm/min_free_kbytes # # From: Matthew Dobson <colpatch@us.ibm.com> # # This resurrects the old /proc/sys/vm/free_pages functionality: the ability to # tell page reclaim how much free memory to maintain. # # This may be needed for specialised networking applications, and it provides # an interesting way to stress the kernel: set it very low so atomic # allocations can easily fail. # # Also, a 16G ppc64 box currently cruises along at 1M free memory, which is # surely too little to supporthigh-speed networking. We have not changed that # setting here, but it is now possible to do so. # # The patch also reduces the amount of free memory which the VM will maintain # in ZONE_HIGHMEM, as it is almost always wasted memory. # -------------------------------------------- # 03/06/06 akpm@digeo.com 1.1243.52.21 # [PATCH] loop: remove the balance_dirty_pages() call # # The loop thread is getting permanently stuck in balance_dirty_pages() # (nr_writeback is exceeded) because the loop thread itself is responsible for # completing writeback on behalf of higher layers. # # So we need to take that out: don't throttle the loop thread. Throttle the # tasks which are generating all the dirty data instead. # -------------------------------------------- # 03/06/06 torvalds@home.transmeta.com 1.1243.52.22 # Remove half-deleted zero-sized sound file. # -------------------------------------------- # 03/06/06 torvalds@home.transmeta.com 1.1243.50.2 # Merge http://linux-sound.bkbits.net/linux-sound # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/06/07 paulus@samba.org 1.1257 # Merge samba.org:/stuff/paulus/kernel/linux-2.5 # into samba.org:/stuff/paulus/kernel/for-linus-ppc # -------------------------------------------- # 03/06/06 torvalds@home.transmeta.com 1.1243.50.3 # Merge bk://kernel.bkbits.net/davem/net-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/06/06 rusty@rustcorp.com.au 1.1243.50.4 # [PATCH] kallsyms in proc # # This adds a /proc/kallsyms if you have CONFIG_KALLSYMS in your # kernel. The output is nm-like, with symbols in caps (global) if # exported using EXPORT_SYMBOL, rather than the normal static # vs. non-static differentiation. # # This is useful for things like performance monitoring tools (profiling # etc) that want to match addresses to names in user space. # -------------------------------------------- # 03/06/06 rusty@rustcorp.com.au 1.1243.50.5 # [PATCH] Move cpu notifiers et al to cpu.h # # Trivial patch: when these were introduced cpu.h didn't exist. # -------------------------------------------- # 03/06/06 anton@samba.org 1.1243.50.6 # [PATCH] update ppc64 MAINTAINERS entry # # An update to the ppc64 MAINTAINERS entry. # -------------------------------------------- # 03/06/07 sam@mars.ravnborg.org 1.1243.53.1 # docbook/kernel-api: include files updated # # Path to pci_hotplug_core corrected. # Added !Eli/string.h to document strlcpy and friends # -------------------------------------------- # 03/06/07 sam@mars.ravnborg.org 1.1243.53.2 # docbook: Recognize sis900 functions # # Adapted comments to follow what kernel-doc (docbook) understands # -------------------------------------------- # 03/06/07 sam@mars.ravnborg.org 1.1243.53.3 # docbook: Warn about missing parameter definitions # # Previously kernel-doc silently ignored missing parameter descriptions # but sometimes 'make sgmldocs' failed with exit code > 0. # When kernel-doc encounter parameters where the description is missing # it now prints a warning. # docproc corrected so previously exit code are recorded. # docbook makefile cleaned up a bit # -------------------------------------------- # 03/06/07 sam@mars.ravnborg.org 1.1243.53.4 # docbook: Move definition of MODULENAME_SIZE # # The location between the comment and the prototype confused kernel-doc. # Kernel-doc requires the prototype to follow after the comment section. # -------------------------------------------- # 03/06/07 sam@mars.ravnborg.org 1.1243.50.7 # Merge bk://linux-sam.bkbits.net/main # into mars.ravnborg.org:/home/sam/src/linux/kernel/bk/v2.5 # -------------------------------------------- # 03/06/07 paulus@samba.org 1.1258 # PPC32: Start adding __user to mark pointers from userspace. # # This reduces the number of warnings from Linus' `check' program # for stuff in arch/ppc. # -------------------------------------------- # 03/06/07 hch@lst.de 1.1243.54.1 # [NET]: Fix accidental revert of init_etherdev killing in PPC net drivers. # -------------------------------------------- # 03/06/07 paulus@samba.org 1.1259 # PPC32: Fix irq_desc initialization. # -------------------------------------------- # 03/06/07 herbert@gondor.apana.org.au 1.1243.54.2 # [XFRM_USER]: Allow del policy by id and get policy by selector. # -------------------------------------------- # 03/06/07 paulus@samba.org 1.1260 # PPC32: Fix various minor problems pointed out by Linus' check program. # -------------------------------------------- # 03/06/07 paulus@samba.org 1.1261 # PPC32: Convert some K&R-style functions to ANSI-style. From Steven Cole. # -------------------------------------------- # 03/06/07 rddunlap@osdl.org 1.1243.54.3 # [IPV6]: Fix spelling/typos. # -------------------------------------------- # 03/06/07 mk@linux-ipv6.org 1.1243.54.4 # [IPV6]: Fix esp6 extension headers handling. # -------------------------------------------- # 03/06/07 sri@us.ibm.com 1.1243.54.5 # [IPV6]: Allow ipv6 fragmentation via ip6_xmit() when ipfragok is set. # -------------------------------------------- # 03/06/07 shemminger@osdl.org 1.1243.54.6 # [DECNET]: Fix build warnings. # -------------------------------------------- # 03/06/07 davem@nuts.ninka.net 1.1243.54.7 # [SCTP]: Kill unused local variable in init_sctp_mibs. # -------------------------------------------- # 03/06/07 davej@codemonkey.org.uk 1.1243.42.6 # [CPUFREQ] missing export # powernow-k7 needs dmi_broken # -------------------------------------------- # 03/06/07 acme@conectiva.com.br 1.1243.55.1 # o list.h: improve hlist # # This changeset: # # 1. Implements hlist_add_after # 2. uses prefetch in hlist_for_each, using a trick that ends up being # equivalent to having the prefetch instruction in the first block # of the hlist_for_each for block, the compiler optimizes the second # "test" away, as its result is constant # 3. implements hlist_for_each_entry and hlist_for_each_entry safe, # using a struct hlist_node as iterator to avoid the extra branches a # similar implementation to list_for_each_entry would have if used # a typed iterator, but while avoiding having to have the explicit # hlist_entry as in hlist_for_each. # # 4. Converts the hlist_for_each users that had explicit prefetches, i.e. # removed the explicit prefetch # # 5. fix a harmless list_entry use in a hlist_for_each in inode.c # # -------------------------------------------- # 03/06/07 torvalds@home.transmeta.com 1.1262 # Merge bk://ppc.bkbits.net/for-linus-ppc # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/06/07 torvalds@home.transmeta.com 1.1263 # Merge bk://kernel.bkbits.net/davem/net-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/06/07 l.s.r@web.de 1.1264 # [PATCH] hugetlbfs: fix error reporting in case of invalid mount # # hugetlbfs was unnecessarily verbose, and didn't even print out the right # thing if given invalid mount options. # # Just return EINVAL. # -------------------------------------------- # 03/06/07 ak@suse.de 1.1265 # [PATCH] Work around gcc 3.3 bug on amd64 in binfmt_elf.c # # This patch works around a gcc 3.3 bug on AMD64. On AMD64 the # get_current() function expands to a switch on sizeof which has to be # optimized away by the compiler, finally yielding an inline assembler # statement. In some cases it seems to get that wrong and forgets to # reference and use the argument. I have only seen it happen in # binfmt_elf so far. # # Work around by just computing "current" once. # -------------------------------------------- # 03/06/07 torvalds@home.transmeta.com 1.1266 # Merge bk://linux-dj.bkbits.net/cpufreq # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/06/07 torvalds@home.transmeta.com 1.1267 # Merge bk://kernel.bkbits.net/acme/hlist-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/06/07 l.s.r@web.de 1.1268 # [PATCH] Some more stuff missed during the struct sock cleanup # # The members of struct sock got a prefix of 'sk_' recently. # # This patch updates smbfs to match the new world order. # -------------------------------------------- # 03/06/07 elenstev@mesatop.com 1.1269 # [PATCH] Another final K&R to ANSI C cleanup of zlib # # Here is another final K&R to ANSI C cleanup patch for zlib. # -------------------------------------------- # 03/06/07 paulus@samba.org 1.1270 # [PATCH] fix check warnings in drivers/macintosh # # This patch removes the warnings that the `check' program came up with # in drivers/macintosh. This involves adding __user in various places # and fixing some non-ANSI function definitions for functions that take # no arguments. # -------------------------------------------- # 03/06/07 paulus@samba.org 1.1271 # [PATCH] Fix check warnings in PPP code # # This patch removes the warnings that the check program came up with in # the PPP code: ppp_async.c, ppp_deflate.c and ppp_generic.c. This # involved adding __user and converting K&R-style function definitions # to ANSI-style. I also took the time to add some extra comments to # ppp_deflate.c explaining in more detail what each function does and # what its arguments are. # -------------------------------------------- # 03/06/07 paulus@samba.org 1.1272 # [PATCH] Move BUG/BUG_ON/WARN_ON to asm headers # # This patch moves the definitions of BUG, BUG_ON and WARN_ON from # <linux/kernel.h> to <asm/bug.h> (which <linux/kernel.h> includes), and # supplies a new implementation for PPC which uses a conditional trap # instruction for BUG_ON and WARN_ON, thus avoiding a conditional # branch. This patch trims over 50kB from the size of the kernel that I # use on powermacs. # # With this patch, on PPC we have a __bug_table section in the vmlinux # binary, and also in modules if they use BUG, BUG_ON or WARN_ON. The # __bug_table section has one entry for each BUG/BUG_ON/WARN_ON, giving # the address of the trap instruction and the corresponding line number, # filename and function name. This information is used in the exception # handler for the exception that the trap instruction produces. The # arch-specific module code handles the __bug_table section so that # BUG/BUG_ON/WARN_ON work correctly in modules. # # Several architecture maintainers have acked this change. It should be # completely benign for all of the other architectures (though they may # decide to do something similar if they have a conditional trap # instruction available). # -------------------------------------------- # 03/06/07 ak@suse.de 1.1273 # [PATCH] Make spinlock debugging compile on x86-64 # # cpu_relax is on i386 and x86-64 in processor.h, not system.h # This makes CONFIG_DEBUG_SPINLOCK compile for x86-64 # -------------------------------------------- # 03/06/07 ak@suse.de 1.1274 # [PATCH] x86-64 merge # # This brings the x86-64 port uptodate for 2.5.70. Just various bugfixes # and a few merges with other people. # # Only changes architecture specific files. # # - Fix compiling with CONFIG_IA32_EMULATION on # - Readd lost apic power management patch from Pavel (fixes oprofile too) # - Increase max IOAPICs to 16 # - Fix compiling with CONFIG_IA32_EMULATION off # - Compile fix for suspend (Pavel Machek) # - Support boxes with APIC disabled # - Remove code to forcibly enable APIC # - Small fix for APIC timer calibration. # - Fix deadlock in SMP reboot # - Some warning fixes # - Save edid info at boot (Bryan O'Sullivan) # - Add better locking to oops printing and support it for page faults. # - Don't printk handled signals. # - Update defconfig # - Add copy_in_user # -------------------------------------------- # 03/06/07 azarah@gentoo.org 1.1275 # o ethertap: fix struct sock cleanup leftover # -------------------------------------------- # 03/06/07 sam@ravnborg.org 1.1276 # [PATCH] be more flexible about creating library archives # # New makefile variable introduced: lib-y # # The lib-y syntax allows you to do the usual tricks such as: # # lib-$(CONFIG_SMP) += percpu_counter.o # # A built-in.o is always present in a directory that list .o files in # either obj-* or lib-*. # # In contrast, lib.a is made only when lib-y is defined. # # I also updated lib/Makefile, so that crc32.o is now always built-in # if selected. # -------------------------------------------- # 03/06/07 akpm@digeo.com 1.1277 # [PATCH] Fix build for CONFIG_KALLSYMS=n # # From: "David S. Miller" <davem@redhat.com> # # add_kallsyms() doesn't exist if !CONFIG_KALLSYMS. # -------------------------------------------- # 03/06/07 akpm@digeo.com 1.1278 # [PATCH] ppc64: fixup for family/sk_family rename # # Fix the ppc64 build for the great socket member renaming. # -------------------------------------------- # 03/06/07 akpm@digeo.com 1.1279 # [PATCH] Fix the build with !CONFIG_PROC_FS # # From: Adrian Bunk <bunk@fs.tum.de> # -------------------------------------------- # 03/06/07 akpm@digeo.com 1.1280 # [PATCH] common 32-bit ioctl code # # From: Pavel Machek <pavel@suse.cz> # # Various 64-bit architectures are duplicating a ton of 32-bit compat code. # # Pavel's patch creates a generic 32-bit ioctl file in fs/compat_ioctl.c which # architectures will #include from within their arch/ layer. # # Has been reviewed by everyone and tested on sparc64, x86_64, ppc64 and ia32. # -------------------------------------------- # 03/06/07 akpm@digeo.com 1.1281 # [PATCH] ioctl32 cleanup: sparc64 # # From: Pavel Machek <pavel@suse.cz> # # Make sparc64 use generic ioctl32 code. # -------------------------------------------- # 03/06/07 akpm@digeo.com 1.1282 # [PATCH] x86_64: use common ioctl code # # From: Pavel Machek <pavel@suse.cz> # # Convert x86_64 to use the common ioctl code. # -------------------------------------------- # 03/06/07 akpm@digeo.com 1.1283 # [PATCH] remove_proc_entry() fix # # From Bartlomiej Zolnierkiewicz # # With !CONFIG_PROC_FS, ieee1394_core fails to compile because the argument to # this inline is still evaluated. But it doesn't exist. # # A general fix is to not evaluate the arg at all. # -------------------------------------------- # 03/06/07 akpm@digeo.com 1.1284 # [PATCH] JFFS_PROC_FS must depend on JFFS_FS # # From: Adrian Bunk <bunk@fs.tum.de> # # Compilation fails if JFFS_PROC_FS and !PROC. The following dependency in # the Kconfig file is needed. # -------------------------------------------- # 03/06/07 akpm@digeo.com 1.1285 # [PATCH] fix apic handling for NUMA-Q # # From: "Martin J. Bligh" <mbligh@aracnet.com> # # All this fancy stuff in cpu_mask_to_apicid doesn't work for NUMA-Q, because # it's based on logical apicids, and we use physical. Drop back to just # always returning 0xF instead, which is the broadcast physical ID, and has # been working fine since the dawn of time. # -------------------------------------------- # 03/06/07 akpm@digeo.com 1.1286 # [PATCH] cleanup conditionals in summit subarch # # From: "Martin J. Bligh" <mbligh@aracnet.com> # # The "magic" switching in subarch was ugly when I put it there, and nobody # liked it then (including me). It hasn't got any prettier since. Andi's # generic arch stuff is a cleaner solution for now, so we can remove the old # hacky stuff, and significantly simplify the code. All this does is replace # "(x86_summit ? A : B)" with "A" everywhere. # -------------------------------------------- # 03/06/07 akpm@digeo.com 1.1287 # [PATCH] provide bus to node mapping for Summit # # From: Matt Dobson, via Martin Bligh # # This parses the machine's BIOS tables to populate the # mp_bus_id_to_node[bus] array. Only affects Summit machines, safe, boring. # Has been in -mjb tree for ages, and works fine. # -------------------------------------------- # 03/06/07 akpm@digeo.com 1.1288 # [PATCH] rocket.c: devfs fix # # Christoph says this undef is not correct. # -------------------------------------------- # 03/06/07 akpm@digeo.com 1.1289 # [PATCH] add bootmem failure warning # # From: Dave Hansen <haveblue@us.ibm.com> # # __alloc_bootmem_core() has a couple of BUG_ON()'s. Since the handlers # aren't set up this early, if you hit it, you just get along stream of # "Unknown Interrupt" messages. It would be very nice to have a little # bit more information when something has decided to BUG() out this # early. # -------------------------------------------- # 03/06/07 akpm@digeo.com 1.1290 # [PATCH] eventpoll: fix possible use-after-free # # From: Davide Libenzi <davidel@xmailserver.org> # # After the ep_remove() the "epi" is given back to the cache, so "epi->ep" # might become invalid. It was not cought by my tests because the element # wasn't immediately reused (and because I was using a single epoll fd, so # the "ep" item remained the same). # -------------------------------------------- # 03/06/07 B.Zolnierkiewicz@elka.pw.edu.pl 1.1291 # [PATCH] switch ide to taskfile IO # # - rewrite taskfile PIO handlers # (they now comply with ide state machine and use bio walking) # - switch ide-disk.c to use *only* taskfile IO # - swicth pdc4030.c to use *only* taskfile IO (untested) # - remove old cruft (>600 lines) # -------------------------------------------- # 03/06/07 sam@ravnborg.org 1.1292 # [PATCH] all archs: Replace O_TARGET with lib-y # # lib-y is the new way to define what objects belongs to a library. The # implementation was not made backwards compatible and therefore an update # to all architectures are needed. # # This is a simple replacement of obj-* to lib-* and deletion of L_TARGET. # The new mechanish where lib.a can be mixed with built-in.o is not # utilised. # -------------------------------------------- # 03/06/08 spyro@f2s.com 1.1293 # [PATCH] ARM26 architecture # # The old 26-bit ARM support was long since dropped out of the regular ARM # support, since it was different enough to not make sense to maintain as # one port. # # This re-introduces arm26 as an architecture of its own. # -------------------------------------------- # 03/06/08 joern@wohnheim.fh-wedel.de 1.1294 # [PATCH] zlib cleanup: C++ workarounds # # We don't use any cplusplus in the kernel. # -------------------------------------------- # 03/06/08 joern@wohnheim.fh-wedel.de 1.1295 # [PATCH] zlib merge: turboc # # This is the first bit of the missing merge towards 1.1.4. Applies on # top of the previous cleanups. # # This one rips out an ugly #ifdef and seems to catch a theoretical # error possibility. Always thought that they fixed more than they # officially admitted. # -------------------------------------------- # 03/06/08 joern@wohnheim.fh-wedel.de 1.1296 # [PATCH] zlib merge: inffast.c # # Most of it is reformatting, but the functional bits should fix real # problems. A loop is introduced, just like in the turboc patch and one # of the three condition bodies has been expanded. # -------------------------------------------- # 03/06/08 joern@wohnheim.fh-wedel.de 1.1297 # [PATCH] Mark Compaq MAINTAINERS entries stale # # They may have some new HP address, unknown for now. # -------------------------------------------- # 03/06/08 joern@wohnheim.fh-wedel.de 1.1298 # [PATCH] zlib cleanup: local # # Simple s/local/static/. # -------------------------------------------- # 03/06/08 joern@wohnheim.fh-wedel.de 1.1299 # [PATCH] zlib cleanup: Z_NULL removal # # s/Z_NULL/NULL/g. # -------------------------------------------- # 03/06/08 joern@wohnheim.fh-wedel.de 1.1300 # [PATCH] zlib cleanup: unnecessary cast removal # # This removes unnecessary NULL casting. # -------------------------------------------- # 03/06/08 joern@wohnheim.fh-wedel.de 1.1301 # [PATCH] zlib merge: return code # # Don't think anyone actually bothers to check specific error codes, but # it shouldn't hurt either. # -------------------------------------------- # 03/06/08 joern@wohnheim.fh-wedel.de 1.1302 # [PATCH] zlib merge: avoid 8-bit window errors # # More merging from zlib-1.1.4 # # force windowBits > 8 to avoid a bug in the encoder for a window size # of 256 bytes. (A complete fix will be available in 1.1.5). # # James Carlson: # # The problem is that s->strstart gets set to a very large # positive integer when wsize (local copy of s->w_size) is # subtracted in deflate.c:fill_window(). This happens because # MAX_DIST(s) resolves as a negative number when the window size # is 8 -- MAX_DIST(s) is defined as s->w_size-MIN_LOOKAHEAD in # deflate.h. MIN_LOOKAHEAD is MAX_MATCH+MIN_MATCH+1, and that # is 258+3+1 or 262. Since a window size of 8 gives s->w_size # 256, MAX_DIST(s) is 256-262 or -6. # # This results in read_buf() writing over memory outside of # s->window, and a crash. # -------------------------------------------- # 03/06/08 sam@mars.ravnborg.org 1.1291.1.1 # Merge mars.ravnborg.org:/home/sam/src/linux/kernel/bk/linux-2.5 # into mars.ravnborg.org:/home/sam/src/linux/kernel/bk/docbook # -------------------------------------------- # 03/06/08 torvalds@home.transmeta.com 1.1303 # Quick response to de-listing the Compaq FC/RAID controllers # from the MAINTAINERS list. How they're HP, and maintained # by Stephen Cameron. # -------------------------------------------- # 03/06/08 rth@kanga.twiddle.net 1.1292.1.1 # Merge kanga.twiddle.net:/home/rth/work/linux/linus-2.5 # into kanga.twiddle.net:/home/rth/work/linux/axp-2.5 # -------------------------------------------- # 03/06/08 torvalds@home.transmeta.com 1.1304 # Merge http://linux-sam.bkbits.net/docbook # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/06/08 James.Bottomley@SteelEye.com 1.1305 # [PATCH] fix character subsystem initialisation # # chr_dev_init() should be a subsys_initcall(), since it needs to # initialize before any drivers that use the character device # infrastructure. # -------------------------------------------- # 03/06/08 sam@ravnborg.org 1.1306 # [PATCH] kbuild: Document newly added lib-y # -------------------------------------------- # 03/06/08 rth@kanga.twiddle.net 1.1292.1.2 # [ALPHA] Implement bcopy. # -------------------------------------------- # 03/06/08 rth@kanga.twiddle.net 1.1292.1.3 # [ALPHA] Avoid warning in asm/unaligned.h. # -------------------------------------------- # 03/06/08 rth@kanga.twiddle.net 1.1292.1.4 # [ALPHA] Fix missed __ex_table to conversion to pc-relative relocs. # -------------------------------------------- # 03/06/08 rth@kanga.twiddle.net 1.1292.1.5 # [ALPHA] Streamline calls to __copy_user and __do_clear_user. # -------------------------------------------- # 03/06/08 rth@kanga.twiddle.net 1.1292.1.6 # [ALPHA] Fixup fallout from force_successful_syscall_return change. # -------------------------------------------- # 03/06/08 torvalds@home.transmeta.com 1.1307 # Merge bk://are.twiddle.net/axp-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/06/08 joern@wohnheim.fh-wedel.de 1.1308 # [PATCH] zlib changes: memlevel # # Reduce MAX_MEM_LEVEL to 8. This reduces zlib memory consumption by # 128k (from ~400k to ~270k) at the theoretical cost of worse # compression. No code currently in the kernel actually uses the better # compression, so the practical cost is zero. # -------------------------------------------- # 03/06/09 vnuorval@tcs.hut.fi 1.1309 # [IPV6]: Add ip6ip6 tunnel driver. # -------------------------------------------- # 03/06/09 elenstev@mesatop.com 1.1308.1.1 # [PATCH] Two more sources of "non-ANSI parameter list" warnings # # This removes the last sources of "non-ANSI parameter list" warnings for # zlib_deflate. # -------------------------------------------- # 03/06/09 thornber@sistina.com 1.1308.1.2 # [PATCH] dm: Replace __HIGH() and __LOW() macros # # Replace __HIGH() and __LOW() with max() and min_not_zero(). # -------------------------------------------- # 03/06/09 thornber@sistina.com 1.1308.1.3 # [PATCH] dm: signed/unsigned audit # -------------------------------------------- # 03/06/09 thornber@sistina.com 1.1308.1.4 # [PATCH] dm: new suspend/resume target methods # # Some targets may perform io of their own volition, eg. a mirror # performing recovery, a cache target pulling in different chunks. We # cannot let them perform this io while the device is suspended. This # patch adds 2 new methods to the target type, which instruct the target # to suspend/resume itself. All targets start in the suspended state, # so should expect an initial resume call. Simple targets do not need # to implement these functions. # -------------------------------------------- # 03/06/09 thornber@sistina.com 1.1308.1.5 # [PATCH] dm: Lift dm_div_up() # # Pull dm_div_up() out of dm-table.c into dm.h # -------------------------------------------- # 03/06/09 thornber@sistina.com 1.1308.1.6 # [PATCH] dm: Fix memory leak in dm_register_target() # # [From Patrick Caulfield] # -------------------------------------------- # 03/06/09 thornber@sistina.com 1.1308.1.7 # [PATCH] dm: Remove some debug messages # -------------------------------------------- # 03/06/09 thornber@sistina.com 1.1308.1.8 # [PATCH] dm: Remove an old FIXME # -------------------------------------------- # 03/06/09 herbert@gondor.apana.org.au 1.1310 # [IPSEC]: Zap killed policies from the flow cache properly. # -------------------------------------------- # 03/06/09 yoshfuji@linux-ipv6.org 1.1311 # [IPV6]: dev_get_by_name("lo") --> dev_hold(&loopback_dev). # -------------------------------------------- # 03/06/09 yoshfuji@linux-ipv6.org 1.1312 # [IPV6]: ipv6_addr_prefix() cleanup, eliminate duplication. # -------------------------------------------- # 03/06/09 geert@linux-m68k.org 1.1313 # [NET]: asm/smp.h --> linux/smp.h in sch_ingress.c # -------------------------------------------- # 03/06/09 hch@lst.de 1.1314 # [NET]: Convert skfp over to initcalls, kill fddi cruft from Space.c # -------------------------------------------- # 03/06/09 torvalds@home.transmeta.com 1.1315 # Merge bk://kernel.bkbits.net/davem/net-2.5 # into home.transmeta.com:/home/torvalds/v2.5/linux # -------------------------------------------- # 03/06/09 fcusack@fcusack.com 1.1316 # [PATCH] nfs_unlink() problem fix # # When foo is unlinked, nfs_unlink() does a sillyrename, this puts the # dentry on nfs_delete_queue, and (in the VFS) unhashes it from the # dcache. This causes problems, since any later access to the # silly-renamed new .nfs file will create a NEW dentry that aliases the # one we originally created, but unhashed. # # This causes various confusion, especially if we want to try to delete it # again later. # # So fix this by not unhash the dentry after silly-renaming. In 2.2, each # fs was responsible for doing a d_delete(), in 2.4 and later it happens # in the VFS layer and I think it was just an oversight that the 2.4 VFS # doesn't consider sillyrename (considering the code and comments that are # cruft). # # Also fixed up some comments while debugging this. # -------------------------------------------- # diff -Nru a/Documentation/00-INDEX b/Documentation/00-INDEX --- a/Documentation/00-INDEX Mon Jun 9 23:16:08 2003 +++ b/Documentation/00-INDEX Mon Jun 9 23:16:08 2003 @@ -182,6 +182,8 @@ - short guide on how to set up and use the RAM disk. riscom8.txt - notes on using the RISCom/8 multi-port serial driver. +rocket.txt + - info on installing/using the Comtrol RocketPort multiport serial driver rtc.txt - notes on how to use the Real Time Clock (aka CMOS clock) driver. s390/ diff -Nru a/Documentation/DMA-mapping.txt b/Documentation/DMA-mapping.txt --- a/Documentation/DMA-mapping.txt Mon Jun 9 23:16:13 2003 +++ b/Documentation/DMA-mapping.txt Mon Jun 9 23:16:13 2003 @@ -83,6 +83,15 @@ to be increased. And for a device with limitations, as discussed in the previous paragraph, it needs to be decreased. +pci_alloc_consistent() by default will return 32-bit DMA addresses. +PCI-X specification requires PCI-X devices to support 64-bit +addressing (DAC) for all transactions. And at least one platform (SGI +SN2) requires 64-bit consistent allocations to operate correctly when +the IO bus is in PCI-X mode. Therefore, like with pci_set_dma_mask(), +it's good practice to call pci_set_consistent_dma_mask() to set the +appropriate mask even if your device only supports 32-bit DMA +(default) and especially if it's a PCI-X device. + For correct operation, you must interrogate the PCI layer in your device probe routine to see if the PCI controller on the machine can properly support the DMA addressing limitation your device has. It is @@ -94,6 +103,11 @@ int pci_set_dma_mask(struct pci_dev *pdev, u64 device_mask); +The query for consistent allocations is performed via a a call to +pci_set_consistent_dma_mask(): + + int pci_set_consistent_dma_mask(struct pci_dev *pdev, u64 device_mask); + Here, pdev is a pointer to the PCI device struct of your device, and device_mask is a bit mask describing which bits of a PCI address your device supports. It returns zero if your card can perform DMA @@ -133,7 +147,7 @@ Sparc64 is one platform which behaves in this way. Here is how you would handle a 64-bit capable device which can drive -all 64-bits during a DAC cycle: +all 64-bits when accessing streaming DMA: int using_dac; @@ -147,6 +161,30 @@ goto ignore_this_device; } +If a card is capable of using 64-bit consistent allocations as well, +the case would look like this: + + int using_dac, consistent_using_dac; + + if (!pci_set_dma_mask(pdev, 0xffffffffffffffff)) { + using_dac = 1; + consistent_using_dac = 1; + pci_set_consistent_dma_mask(pdev, 0xffffffffffffffff) + } else if (!pci_set_dma_mask(pdev, 0xffffffff)) { + using_dac = 0; + consistent_using_dac = 0; + pci_set_consistent_dma_mask(pdev, 0xffffffff) + } else { + printk(KERN_WARNING + "mydev: No suitable DMA available.\n"); + goto ignore_this_device; + } + +pci_set_consistent_dma_mask() will always be able to set the same or a +smaller mask as pci_set_dma_mask(). However for the rare case that a +device driver only uses consistent allocations, one would have to +check the return value from pci_set_consistent(). + If your 64-bit device is going to be an enormous consumer of DMA mappings, this can be problematic since the DMA mappings are a finite resource on many platforms. Please see the "DAC Addressing @@ -215,9 +253,10 @@ Think of "consistent" as "synchronous" or "coherent". - Consistent DMA mappings are always SAC addressable. That is - to say, consistent DMA addresses given to the driver will always - be in the low 32-bits of the PCI bus space. + The current default is to return consistent memory in the low 32 + bits of the PCI bus space. However, for future compatibility you + should set the consistent mask even if this default is fine for your + driver. Good examples of what to use consistent mappings for are: @@ -287,15 +326,14 @@ driver needs regions sized smaller than a page, you may prefer using the pci_pool interface, described below. -The consistent DMA mapping interfaces, for non-NULL dev, will always -return a DMA address which is SAC (Single Address Cycle) addressable. -Even if the device indicates (via PCI dma mask) that it may address -the upper 32-bits and thus perform DAC cycles, consistent allocation -will still only return 32-bit PCI addresses for DMA. This is true -of the pci_pool interface as well. - -In fact, as mentioned above, all consistent memory provided by the -kernel DMA APIs are always SAC addressable. +The consistent DMA mapping interfaces, for non-NULL dev, will by +default return a DMA address which is SAC (Single Address Cycle) +addressable. Even if the device indicates (via PCI dma mask) that it +may address the upper 32-bits and thus perform DAC cycles, consistent +allocation will only return > 32-bit PCI addresses for DMA if the +consistent dma mask has been explicitly changed via +pci_set_consistent_dma_mask(). This is true of the pci_pool interface +as well. pci_alloc_consistent returns two values: the virtual address which you can use to access it from the CPU and dma_handle which you pass to the diff -Nru a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile --- a/Documentation/DocBook/Makefile Mon Jun 9 23:16:12 2003 +++ b/Documentation/DocBook/Makefile Mon Jun 9 23:16:12 2003 @@ -11,7 +11,8 @@ kernel-locking.sgml via-audio.sgml mousedrivers.sgml \ deviceiobook.sgml procfs-guide.sgml tulip-user.sgml \ writing_usb_driver.sgml scsidrivers.sgml sis900.sgml \ - kernel-api.sgml journal-api.sgml lsm.sgml usb.sgml + kernel-api.sgml journal-api.sgml lsm.sgml usb.sgml \ + gadget.sgml ### # The build process is as follows (targets): @@ -38,8 +39,8 @@ ### #External programs used -KERNELDOC=$(objtree)/scripts/kernel-doc -DOCPROC=$(objtree)/scripts/docproc +KERNELDOC = scripts/kernel-doc +DOCPROC = scripts/docproc ### # DOCPROC is used for two purposes: @@ -49,14 +50,14 @@ # The following rules are used to generate the .sgml documentation # required to generate the final targets. (ps, pdf, html). quiet_cmd_docproc = DOCPROC $@ -cmd_docproc = $(DOCPROC) doc $< >$@ + cmd_docproc = $(DOCPROC) doc $< >$@ define rule_docproc - set -e - $(if $($(quiet)cmd_$(1)),echo ' $($(quiet)cmd_$(1))';) - $(cmd_$(1)); \ - ( \ - echo 'cmd_$@ := $(cmd_$(1))'; \ - echo $@: `$(DOCPROC) depend $<`; \ + set -e; \ + $(if $($(quiet)cmd_$(1)),echo ' $($(quiet)cmd_$(1))';) \ + $(cmd_$(1)); \ + ( \ + echo 'cmd_$@ := $(cmd_$(1))'; \ + echo $@: `$(DOCPROC) depend $<`; \ ) > $(dir $@).$(notdir $@).cmd endef @@ -95,41 +96,55 @@ ### # Rules to generate postscript, PDF and HTML # db2html creates a directory. Generate a html file used for timestamp + +quiet_cmd_db2ps = DB2PS $@ + cmd_db2ps = db2ps -o $(dir $@) $< %.ps : %.sgml @(which db2ps > /dev/null 2>&1) || \ (echo "*** You need to install DocBook stylesheets ***"; \ exit 1) - $(call do_cmd,DB2PS $@,db2ps -o $(dir $@) $<) + $(call cmd,db2ps) +quiet_cmd_db2pdf = DB2PDF $@ + cmd_db2pdf = db2pdf -o $(dir $@) $< %.pdf : %.sgml @(which db2pdf > /dev/null 2>&1) || \ (echo "*** You need to install DocBook stylesheets ***"; \ exit 1) - $(call do_cmd,DB2PDF $@,db2pdf -o $(dir $@) $<) + $(call cmd,db2pdf) + +quiet_cmd_db2html = DB2HTML $@ + cmd_db2html = db2html -o $(patsubst %.html,%,$@) $< && \ + echo '<a HREF="$(patsubst %.html,%,$(notdir $@))/book1.html"> \ + Goto $(patsubst %.html,%,$(notdir $@))</a><p>' > $@ %.html: %.sgml @(which db2html > /dev/null 2>&1) || \ (echo "*** You need to install DocBook stylesheets ***"; \ exit 1) @rm -rf $@ $(patsubst %.html,%,$@) - $(call do_cmd,DB2HTML $@,db2html -o $(patsubst %.html,%,$@) $< && \ - echo '<a HREF="$(patsubst %.html,%,$(notdir $@))/book1.html">\ - Goto $(patsubst %.html,%,$(notdir $@))</a><p>' > $@) + $(call cmd,db2html) @if [ ! -z "$(PNG-$(basename $(notdir $@)))" ]; then \ cp $(PNG-$(basename $(notdir $@))) $(patsubst %.html,%,$@); fi ### # Rules to generate postscripts and PNG imgages from .fig format files +quiet_cmd_fig2eps = FIG2EPS $@ + cmd_fig2eps = fig2dev -Leps $< $@ + %.eps: %.fig - $(call do_cmd,FIG2DEV -Leps $@,fig2dev -Leps $< $@) + $(call cmd,fig2eps) + +quiet_cmd_fig2png = FIG2PNG $@ + cmd_fig2png = fig2dev -Lpng $< $@ %.png: %.fig - $(call do_cmd,FIG2DEV -Lpng $@,fig2dev -Lpng $< $@) + $(call cmd,fig2png) ### # Rule to convert a .c file to inline SGML documentation %.sgml: %.c - @echo ' Generating $@' + @echo ' GEN $@' @( \ echo "<programlisting>"; \ expand --tabs=8 < $< | \ diff -Nru a/Documentation/DocBook/gadget.tmpl b/Documentation/DocBook/gadget.tmpl --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/DocBook/gadget.tmpl Mon Jun 9 23:16:20 2003 @@ -0,0 +1,966 @@ +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V3.1//EN"[]> +<book id="USB-Gadget-API"> + <bookinfo> + <title>USB Gadget API for Linux</title> + <date>02 June 2003</date> + <edition>02 June 2003</edition> + + <legalnotice> + <para>Permission is granted to copy, distribute, and/or modify + this document under the terms of the GNU Free Documentation + License, version 1.2, or any later version published by the + Free Software Foundation; with the Invariant Sections being + the "GNU Free Documentation License", + no Front-Cover Texts, + and + no Back-Cover Texts. + </para> + + <para>This documentation 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 Free Documentation License for more details. + </para> + + <para>Note that certain sections of this document are merged + into Linux kernel source code. + That content is the bulk of + <xref linkend="core" /> and + <xref linkend="utils" />, + where the "GNU Free Documentation License" is identified + as an alternate licence for its documentation. + </para> + + </legalnotice> + <copyright> + <year>2003</year> + <holder>David Brownell</holder> + </copyright> + + <author> + <firstname>David</firstname> + <surname>Brownell</surname> + <affiliation> + <address><email>dbrownell@users.sourceforge.net</email></address> + </affiliation> + </author> + </bookinfo> + +<toc></toc> + +<chapter><title>Introduction</title> + +<para>This document presents a Linux-USB "Gadget" +kernel mode +API, for use within peripherals and other USB devices +that embed Linux. +It provides an overview of the API structure, +and shows how that fits into a system development project. +This is the first such API released on Linux to address +a number of important problems, including: </para> + +<itemizedlist> + <listitem><para>Supports USB 2.0, for high speed devices which + can stream data at several dozen megabytes per second. + </para></listitem> + <listitem><para>Handles devices with dozens of endpoints just as + well as ones with just two fixed-function ones. Gadget drivers + can be written so they're easy to port to new hardware. + </para></listitem> + <listitem><para>Flexible enough to expose more complex USB device + capabilities such as multiple configurations, multiple interfaces, + composite devices, + and alternate interface settings. + </para></listitem> + <listitem><para>Sharing data structures and API models with the + Linux-USB host side API. This looks forward to USB "On-The-Go" + (OTG) and similar more-symmetric frameworks. + </para></listitem> + <listitem><para>Minimalist, so it's easier to support new device + controller hardware. I/O processing doesn't imply large + demands for memory or CPU resources. + </para></listitem> +</itemizedlist> + + +<para>Most Linux developers will not be able to use this API, since they +have USB "host" hardware in a PC, workstation, or server. +Linux users with embedded systems are more likely to +have USB peripheral hardware. +To distinguish drivers running inside such hardware from the +more familiar Linux "USB device drivers", +which are host side proxies for the real USB devices, +a different term is used: +the drivers inside the peripherals are "USB gadget drivers". +In USB protocol interactions, the device driver is the master +(or "client driver") +and the gadget driver is the slave (or "function driver"). +</para> + +<para>The gadget API resembles the host side Linux-USB API in that both +use queues of request objects to package I/O buffers, and those requests +may be submitted or canceled. +They share common definitions for the standard USB +<emphasis>Chapter 9</emphasis> messages, structures, and constants. +Also, both APIs bind and unbind drivers to devices. +The APIs differ in detail, since the host side's current +URB framework exposes a number of implementation details +and assumptions that are inappropriate for a gadget API. +While the model for control transfers and configuration +management is necessarily different (one side is a hardware-neutral master, +the other is a hardware-aware slave), the endpoint I/0 API used here +should also be usable for an overhead-reduced host side API. +</para> + +</chapter> + +<chapter id="structure"><title>Structure of Gadget Drivers</title> + +<para>A system running inside a USB peripheral +normally has at least three layers inside the kernel to handle +USB protocol processing, and may have additional layers in +user space code. +The "gadget" API is used by the middle layer to interact +with the lowest level (which directly handles hardware). +</para> + +<para>In Linux, from the bottom up, these layers are: +</para> + +<variablelist> + + <varlistentry> + <term><emphasis>USB Controller Driver</emphasis></term> + + <listitem> + <para>This is the lowest software level. + It is the only layer that talks to hardware, + through registers, fifos, dma, irqs, and the like. + The <filename><linux/usb_gadget.h></filename> API abstracts + the peripheral controller endpoint hardware. + That hardware is exposed through endpoint objects, which accept + streams of IN/OUT buffers, and through callbacks that interact + with gadget drivers. + Since normal USB devices only have one upstream + port, they only have one of these drivers. + The controller driver can support any number of different + gadget drivers, but only one of them can be used at a time. + </para> + + <para>Examples of such controller hardware include + the PCI-based NetChip 2280 USB 2.0 high speed controller, + the SA-11x0 or PXA-25x UDC (found within many PDAs), + and a variety of other products. + </para> + </listitem></varlistentry> + + <varlistentry> + <term><emphasis>Gadget Driver</emphasis></term> + + <listitem> + <para>The lower boundary of this driver implements hardware-neutral + USB functions, using calls to the controller driver. + Because such hardware varies widely in capabilities and restrictions, + the gadget driver is normally configured at compile time + to work with endpoints supported by one particular controller. + Gadget drivers may be portable to several different controllers, + using conditional compilation. + Gadget driver responsibilities include: + </para> + <itemizedlist> + <listitem><para>handling setup requests (ep0 protocol responses) + possibly including class-specific functionality + </para></listitem> + <listitem><para>returning configuration and string descriptors + </para></listitem> + <listitem><para>(re)setting configurations and interface + altsettings, including enabling and configuring endpoints + </para></listitem> + <listitem><para>handling life cycle events, such as managing + bindings + to hardware, and disconnection from the USB host. + </para></listitem> + <listitem><para>managing IN and OUT transfers on all currently + enabled endpoints + </para></listitem> + </itemizedlist> + + <para> + Such drivers may be modules of proprietary code, although + that approach is discouraged in the Linux community. + </para> + </listitem></varlistentry> + + <varlistentry> + <term><emphasis>Upper Level</emphasis></term> + + <listitem> + <para>Most gadget drivers have an upper boundary that connects + to some Linux driver or framework in Linux. + Through that boundary flows the data which the gadget driver + produces and/or consumes through protocol transfers over USB. + Examples include: + </para> + <itemizedlist> + <listitem><para>user mode code, using generic (gadgetfs) + or application specific files in + <filename>/dev</filename> + </para></listitem> + <listitem><para>networking subsystem (for network gadgets, + like the CDC Ethernet Model gadget driver) + </para></listitem> + <listitem><para>data capture drivers, perhaps video4Linux or + a scanner driver; or test and measurement hardware. + </para></listitem> + <listitem><para>input subsystem (for HID gadgets) + </para></listitem> + <listitem><para>sound subsystem (for audio gadgets) + </para></listitem> + <listitem><para>file system (for PTP gadgets) + </para></listitem> + <listitem><para>block i/o subsystem (for usb-storage gadgets) + </para></listitem> + <listitem><para>... and more </para></listitem> + </itemizedlist> + </listitem></varlistentry> + + <varlistentry> + <term><emphasis>Additional Layers</emphasis></term> + + <listitem> + <para>Other layers may exist. + These could include kernel layers, such as network protocol stacks, + as well as user mode applications building on standard POSIX + system call APIs such as + <emphasis>open()</emphasis>, <emphasis>close()</emphasis>, + <emphasis>read()</emphasis> and <emphasis>write()</emphasis>. + On newer systems, POSIX Async I/O calls may be an option. + Such user mode code will not necessarily be subject to + the GNU General Public License (GPL). + </para> + </listitem></varlistentry> + + +</variablelist> + +<para>Over time, reusable utilities should evolve to help make some +gadget driver tasks simpler. An example of particular interest +is code implementing standard USB-IF protocols for +HID, networking, storage, or audio classes. +Some developers are interested in KDB or KGDB hooks, to let +target hardware be remotely debugged. +Most such USB protocol code doesn't need to be hardware-specific, +any more than network protocols like X11, HTTP, or NFS are. +Such interface drivers might be combined, to support composite devices. +</para> + +</chapter> + + +<chapter id="api"><title>Kernel Mode Gadget API</title> + +<para>Gadget drivers declare themselves through a +<emphasis>struct usb_gadget_driver</emphasis>, which is responsible for +most parts of enumeration for a <emphasis>struct usb_gadget</emphasis>. +The response to a set_configuration usually involves +enabling one or more of the <emphasis>struct usb_ep</emphasis> objects +exposed by the gadget, and submitting one or more +<emphasis>struct usb_request</emphasis> buffers to transfer data. +Understand those four data types, and their operations, and +you will understand how this API works. +</para> + +<note><title>Incomplete Data Type Descriptions</title> + +<para>This documentation was prepared using the standard Linux +kernel <filename>docproc</filename> tool, which turns text +and in-code comments into SGML DocBook and then into usable +formats such as HTML or PDF. +Other than the "Chapter 9" data types, most of the significant +data types and functions are described here. +</para> + +<para>However, docproc does not understand all the C constructs +that are used, so some relevant information is likely omitted from +what you are reading. +One example of such information is several per-request flags. +You'll have to read the header file, and use example source +code (such as that for "Gadget Zero"), to fully understand the API. +</para> + +<para>The part of the API implementing some basic +driver capabilities is specific to the version of the +Linux kernel that's in use. +The 2.5 kernel includes a <emphasis>driver model</emphasis> +framework that has no analogue on earlier kernels; +so those parts of the gadget API are not fully portable. +(They are implemented on 2.4 kernels, but in a different way.) +The driver model state is another part of this API that is +ignored by the kerneldoc tools. +</para> +</note> + +<para>The core API does not expose +every possible hardware feature, only the most widely available ones. +There are significant hardware features, such as device-to-device DMA +(without temporary storage in a memory buffer) +that would be added using hardware-specific APIs. +</para> + +<para>This API expects drivers to use conditional compilation to handle +endpoint capabilities of different hardware. +Those tend to have arbitrary restrictions, relating to +transfer types, addressing, packet sizes, buffering, and availability. +As a rule, such differences only matter for "endpoint zero" logic +that handles device configuration and management. +The API only supports limited run-time +detection of capabilities, through naming conventions for endpoints. +Although a gadget driver could scan the endpoints available to it and +choose to map those capabilities onto driver functionality in some way, +few drivers will want to reconfigure themselves at run-time. +</para> + +<para>Like the Linux-USB host side API, this API exposes +the "chunky" nature of USB messages: I/O requests are in terms +of one or more "packets", and packet boundaries are visible to drivers. +Compared to RS-232 serial protocols, USB resembles +synchronous protocols like HDLC +(N bytes per frame, multipoint addressing from the host) +more than asynchronous ones +(tty style, like 8 bytes, no parity, one stop bit). +So for example the controller drivers won't buffer +two single byte writes into a single two-byte USB IN packet, +although gadget drivers may do so when they implement +protocols where packet boundaries (and "short packets") +are not significant. +</para> + +<sect1 id="lifecycle"><title>Driver Life Cycle</title> + +<para>Gadget drivers make endpoint I/O requests to hardware without +needing to know many details of the hardware, but driver +setup/configuration code needs to handle some differences. +Use the API like this: +</para> + +<orderedlist numeration='arabic'> + +<listitem><para>Register a driver for the particular device side +usb controller hardware, +such as the net2280 on PCI (USB 2.0), +sa11x0 or pxa25x as found in Linux PDAs, +and so on. +At this point the device is logically in the USB ch9 initial state +("attached"), drawing no power and not usable +(since it does not yet support enumeration). +</para></listitem> + +<listitem><para>Register a gadget driver that implements some higher level +device function. That will then bind() to a usb_gadget. +</para></listitem> + +<listitem><para>The hardware driver can now start enumerating. +The steps it handles are to accept USB power and set_address requests. +Other steps are handled by the gadget driver. +If the gadget driver module is unloaded before the host starts to +enumerate, steps before step 7 are skipped. +</para></listitem> + +<listitem><para>The gadget driver's setup() call returns usb descriptors, +based both on what the bus interface hardware provides and on the +functionality being implemented. +That can involve alternate settings or configurations, +unless the hardware prevents such operation. +</para></listitem> + +<listitem><para>The gadget driver handles the last step of enumeration, +when the USB host issues a set_configuration call. +It enables all endpoints used in that configuration, +with all interfaces in their default settings. +That involves using a list of the hardware's endpoints, enabling each +endpoint according to its descriptor. +</para></listitem> + +<listitem><para>Do real work and perform data transfers, possibly involving +changes to interface settings or switching to new configurations, until the +device is disconnect()ed from the host. +Queue any number of transfer requests to each endpoint. +The drivers then go back to step 3 (above). +</para></listitem> + +<listitem><para>When the gadget driver module is being unloaded, +the driver unbind() callback is issued. That lets the controller +driver be unloaded. +</para></listitem> + +</orderedlist> + +<para>Drivers will normally be arranged so that just loading the +gadget driver module (or statically linking it into a Linux kernel) +allows the peripheral device to be enumerated. +Note that at this lowest level there are no policies about how +ep0 configuration logic is implemented, +except that it should obey USB specifications. +Such issues are in the domain of gadget drivers, +including knowing about implementation constraints +imposed by some USB controllers +or understanding that composite devices might happen to +be built by integrating reusable components. +</para> + +</sect1> + +<sect1 id="ch9"><title>USB 2.0 Chapter 9 Types and Constants</title> + +<para>Gadget drivers +rely on common USB structures and constants +defined in the +<filename><linux/usb_ch9.h></filename> +header file, which is standard in Linux 2.5 kernels. +These are the same types and constants used by host +side drivers. +</para> + +!Iinclude/linux/usb_ch9.h +</sect1> + +<sect1 id="core"><title>Core Objects and Methods</title> + +<para>These are declared in +<filename><linux/usb_gadget.h></filename>, +and are used by gadget drivers to interact with +USB peripheral controller drivers. +</para> + + <!-- yeech, this is ugly in nsgmls PDF output. + + the PDF bookmark and refentry output nesting is wrong, + and the member/argument documentation indents ugly. + + plus something (docproc?) adds whitespace before the + descriptive paragraph text, so it can't line up right + unless the explanations are trivial. + --> + +!Iinclude/linux/usb_gadget.h +</sect1> + +<sect1 id="utils"><title>Optional Utilities</title> + +<para>The core API is sufficient for writing a USB Gadget Driver, +but some optional utilities are provided to simplify common tasks. +</para> + +!Edrivers/usb/gadget/usbstring.c +</sect1> + +</chapter> + +<chapter id="controllers"><title>Peripheral Controller Drivers</title> + +<para>The first hardware supporting this API is the NetChip 2280 +controller, which supports USB 2.0 high speed and is based on PCI. +This is the <filename>net2280</filename> driver module. +The driver supports Linux kernel versions 2.4 and 2.5; +contact NetChip Technologies for development boards and product +information. +</para> + +<!-- !Edrivers/usb/gadget/net2280.c --> + +<para>A partial USB simulator, +the <filename>dummy_hcd</filename> driver, is available. +It can act like a net2280, a pxa25x, or an sa11x0 in terms +of available endpoints and device speeds; and it simulates +control, bulk, and to some extent interrupt transfers. +That lets you develop some parts of a gadget driver on a normal PC, +without any special hardware, and perhaps with the assistance +of tools such as GDB running with User Mode Linux. +At least one person has expressed interest in adapting that +approach, hooking it up to a simulator for a microcontroller. +Such simulators can help debug subsystems where the runtime hardware +is unfriendly to software development, or is not yet available. +</para> + +<para>Support for other controllers is expected to be developed +and contributed +over time, as this driver framework evolves. +</para> + +</chapter> + +<chapter id="gadget"><title>Gadget Drivers</title> + +<para>In addition to <emphasis>Gadget Zero</emphasis> +(used primarily for testing and development with drivers +for usb controller hardware), other gadget drivers exist. +</para> + +<para>There's an <emphasis>ethernet</emphasis> gadget +driver, which implements one of the most useful +<emphasis>Communications Device Class</emphasis> models. +One of the standards for cable modem interoperability even +specifies the use of this ethernet model as one of two +mandatory options. +Gadgets using this code look to a USB host as if they're +an Ethernet adapter. +It provides access to a network where the gadget's CPU is one host, +which could easily be bridging, routing, or firewalling +access to other networks. +</para> + +<para>There is also support for user mode gadget drivers, +using <emphasis>gadgetfs</emphasis>. +This provides a <emphasis>User Mode API</emphasis> that presents +each endpoint as a single file descriptor. I/O is done using +normal <emphasis>read()</emphasis> and <emphasis>read()</emphasis> calls. +Familiar tools like GDB and pthreads can be used to +develop and debug user mode drivers, so that once a robust +controller driver is available many applications for it +won't require new kernel mode software. +</para> + +<para>Support for other kinds of gadget is expected to +be developed and contributed +over time, as this driver framework evolves. +</para> + +</chapter> + + +<appendix id="gfdl"> +<title>GNU Free Documentation License</title> +<subtitle>Version 1.2, November 2002</subtitle> + +<blockquote id="fsf-copyright"> + <para>Copyright (C) 2000,2001,2002 Free Software Foundation, Inc. +59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed.</para> +</blockquote> + +<sect1 id="gfdl-0"><title>PREAMBLE</title> + +<para>The purpose of this License is to make a manual, textbook, or +other functional and useful document "free" in the sense of freedom: to +assure everyone the effective freedom to copy and redistribute it, with +or without modifying it, either commercially or noncommercially. +Secondarily, this License preserves for the author and publisher a way +to get credit for their work, while not being considered responsible for +modifications made by others.</para> + +<para>This License is a kind of "copyleft", which means that derivative +works of the document must themselves be free in the same sense. It +complements the GNU General Public License, which is a copyleft license +designed for free software.</para> + +<para>We have designed this License in order to use it for manuals for +free software, because free software needs free documentation: a free +program should come with manuals providing the same freedoms that the +software does. But this License is not limited to software manuals; it +can be used for any textual work, regardless of subject matter or +whether it is published as a printed book. We recommend this License +principally for works whose purpose is instruction or reference.</para> +</sect1> + +<sect1 id="gfdl-1"><title>APPLICABILITY AND DEFINITIONS</title> + +<para id="gfdl-doc">This License applies to any manual or other work, in +any medium, that contains a notice placed by the copyright holder saying +it can be distributed under the terms of this License. Such a notice +grants a world-wide, royalty-free license, unlimited in duration, to use +that work under the conditions stated herein. The "Document", below, +refers to any such manual or work. Any member of the public is a +licensee, and is addressed as "you". You accept the license if you +copy, modify or distribute the work in a way requiring permission under +copyright law.</para> + +<para id="gfdl-mod-ver">A "Modified Version" of the Document means any +work containing the Document or a portion of it, either copied verbatim, +or with modifications and/or translated into another language.</para> + +<para id="gfdl-secnd-sect">A "Secondary Section" is a named appendix or +a front-matter section of the Document that deals exclusively with the +relationship of the publishers or authors of the Document to the +Document's overall subject (or to related matters) and contains nothing +that could fall directly within that overall subject. (Thus, if the +Document is in part a textbook of mathematics, a Secondary Section may +not explain any mathematics.) The relationship could be a matter of +historical connection with the subject or with related matters, or of +legal, commercial, philosophical, ethical or political position +regarding them.</para> + +<para id="gfdl-inv-sect">The "Invariant Sections" are certain Secondary +Sections whose titles are designated, as being those of Invariant +Sections, in the notice that says that the Document is released under +this License. If a section does not fit the above definition of +Secondary then it is not allowed to be designated as Invariant. The +Document may contain zero Invariant Sections. If the Document does not +identify any Invariant Sections then there are none.</para> + +<para id="gfdl-cov-text">The "Cover Texts" are certain short passages of +text that are listed, as Front-Cover Texts or Back-Cover Texts, in the +notice that says that the Document is released under this License. A +Front-Cover Text may be at most 5 words, and a Back-Cover Text may be at +most 25 words.</para> + +<para id="gfdl-transparent">A "Transparent" copy of the Document means a +machine-readable copy, represented in a format whose specification is +available to the general public, that is suitable for revising the +document straightforwardly with generic text editors or (for images +composed of pixels) generic paint programs or (for drawings) some widely +available drawing editor, and that is suitable for input to text +formatters or for automatic translation to a variety of formats suitable +for input to text formatters. A copy made in an otherwise Transparent +file format whose markup, or absence of markup, has been arranged to +thwart or discourage subsequent modification by readers is not +Transparent. An image format is not Transparent if used for any +substantial amount of text. A copy that is not "Transparent" is called +"Opaque".</para> + +<para>Examples of suitable formats for Transparent copies include plain +ASCII without markup, Texinfo input format, LaTeX input format, SGML or +XML using a publicly available DTD, and standard-conforming simple HTML, +PostScript or PDF designed for human modification. Examples of +transparent image formats include PNG, XCF and JPG. Opaque formats +include proprietary formats that can be read and edited only by +proprietary word processors, SGML or XML for which the DTD and/or +processing tools are not generally available, and the machine-generated +HTML, PostScript or PDF produced by some word processors for output +purposes only.</para> + +<para id="gfdl-title-page">The "Title Page" means, for a printed book, +the title page itself, plus such following pages as are needed to hold, +legibly, the material this License requires to appear in the title page. +For works in formats which do not have any title page as such, "Title +Page" means the text near the most prominent appearance of the work's +title, preceding the beginning of the body of the text.</para> + +<para id="gfdl-entitled">A section "Entitled XYZ" means a named subunit +of the Document whose title either is precisely XYZ or contains XYZ in +parentheses following text that translates XYZ in another language. +(Here XYZ stands for a specific section name mentioned below, such as +"Acknowledgements", "Dedications", "Endorsements", or "History".) To +"Preserve the Title" of such a section when you modify the Document +means that it remains a section "Entitled XYZ" according to this +definition.</para> + +<para>The Document may include Warranty Disclaimers next to the notice +which states that this License applies to the Document. These Warranty +Disclaimers are considered to be included by reference in this License, +but only as regards disclaiming warranties: any other implication that +these Warranty Disclaimers may have is void and has no effect on the +meaning of this License.</para> +</sect1> + +<sect1 id="gfdl-2"><title>VERBATIM COPYING</title> + +<para>You may copy and distribute the Document in any medium, either +commercially or noncommercially, provided that this License, the +copyright notices, and the license notice saying this License applies to +the Document are reproduced in all copies, and that you add no other +conditions whatsoever to those of this License. You may not use +technical measures to obstruct or control the reading or further copying +of the copies you make or distribute. However, you may accept +compensation in exchange for copies. If you distribute a large enough +number of copies you must also follow the conditions in section 3. +</para> + +<para>You may also lend copies, under the same conditions stated above, +and you may publicly display copies.</para> +</sect1> + +<sect1 id="gfdl-3"><title>COPYING IN QUANTITY</title> + +<para>If you publish printed copies (or copies in media that commonly +have printed covers) of the Document, numbering more than 100, and the +Document's license notice requires Cover Texts, you must enclose the +copies in covers that carry, clearly and legibly, all these Cover Texts: +Front-Cover Texts on the front cover, and Back-Cover Texts on the back +cover. Both covers must also clearly and legibly identify you as the +publisher of these copies. The front cover must present the full title +with all words of the title equally prominent and visible. You may add +other material on the covers in addition. Copying with changes limited +to the covers, as long as they preserve the title of the Document and +satisfy these conditions, can be treated as verbatim copying in other +respects.</para> + +<para>If the required texts for either cover are too voluminous to fit +legibly, you should put the first ones listed (as many as fit +reasonably) on the actual cover, and continue the rest onto adjacent +pages.</para> + +<para>If you publish or distribute Opaque copies of the Document +numbering more than 100, you must either include a machine-readable +Transparent copy along with each Opaque copy, or state in or with each +Opaque copy a computer-network location from which the general +network-using public has access to download using public-standard +network protocols a complete Transparent copy of the Document, free of +added material. If you use the latter option, you must take reasonably +prudent steps, when you begin distribution of Opaque copies in quantity, +to ensure that this Transparent copy will remain thus accessible at the +stated location until at least one year after the last time you +distribute an Opaque copy (directly or through your agents or retailers) +of that edition to the public.</para> + +<para>It is requested, but not required, that you contact the authors of +the Document well before redistributing any large number of copies, to +give them a chance to provide you with an updated version of the +Document.</para> +</sect1> + +<sect1 id="gfdl-4"><title>MODIFICATIONS</title> + +<para>You may copy and distribute a Modified Version of the Document +under the conditions of sections 2 and 3 above, provided that you +release the Modified Version under precisely this License, with the +Modified Version filling the role of the Document, thus licensing +distribution and modification of the Modified Version to whoever +possesses a copy of it. In addition, you must do these things in the +Modified Version:</para> + +<orderedlist id="gfdl-modif-cond" numeration="upperalpha"> +<listitem><simpara>Use in the Title Page (and on the covers, if any) a + title distinct from that of the Document, and from those of previous + versions (which should, if there were any, be listed in the History + section of the Document). You may use the same title as a previous + version if the original publisher of that version gives permission. +</simpara></listitem> +<listitem><simpara>List on the Title Page, as authors, one or more + persons or entities responsible for authorship of the modifications in + the Modified Version, together with at least five of the principal + authors of the Document (all of its principal authors, if it has fewer + than five), unless they release you from this requirement. +</simpara></listitem> +<listitem><simpara>State on the Title page the name of the publisher of + the Modified Version, as the publisher.</simpara></listitem> +<listitem><simpara>Preserve all the copyright notices of the Document. +</simpara></listitem> +<listitem><simpara>Add an appropriate copyright notice for your + modifications adjacent to the other copyright notices. +</simpara></listitem> +<listitem><simpara>Include, immediately after the copyright notices, a + license notice giving the public permission to use the Modified + Version under the terms of this License, in the form shown in the + <link linkend="gfdl-addendum">Addendum</link> below. +</simpara></listitem> +<listitem><simpara>Preserve in that license notice the full lists of + Invariant Sections and required Cover Texts given in the Document's + license notice.</simpara></listitem> +<listitem><simpara>Include an unaltered copy of this License. +</simpara></listitem> +<listitem><simpara>Preserve the section Entitled "History", Preserve its + Title, and add to it an item stating at least the title, year, new + authors, and publisher of the Modified Version as given on the Title + Page. If there is no section Entitled "History" in the Document, + create one stating the title, year, authors, and publisher of the + Document as given on its Title Page, then add an item describing the + Modified Version as stated in the previous sentence. +</simpara></listitem> +<listitem><simpara>Preserve the network location, if any, given in the + Document for public access to a Transparent copy of the Document, and + likewise the network locations given in the Document for previous + versions it was based on. These may be placed in the "History" + section. You may omit a network location for a work that was + published at least four years before the Document itself, or if the + original publisher of the version it refers to gives permission. +</simpara></listitem> +<listitem><simpara>For any section Entitled "Acknowledgements" or + "Dedications", Preserve the Title of the section, and preserve in the + section all the substance and tone of each of the contributor + acknowledgements and/or dedications given therein. +</simpara></listitem> +<listitem><simpara>Preserve all the Invariant Sections of the Document, + unaltered in their text and in their titles. Section numbers or the + equivalent are not considered part of the section titles. +</simpara></listitem> +<listitem><simpara>Delete any section Entitled "Endorsements". + Such a section may not be included in the Modified Version. +</simpara></listitem> +<listitem><simpara>Do not retitle any existing section to be Entitled + "Endorsements" or to conflict in title with any Invariant Section. +</simpara></listitem> +<listitem><simpara>Preserve any Warranty Disclaimers. +</simpara></listitem> +</orderedlist> + +<para>If the Modified Version includes new front-matter sections or +appendices that qualify as Secondary Sections and contain no material +copied from the Document, you may at your option designate some or all +of these sections as invariant. To do this, add their titles to the +list of Invariant Sections in the Modified Version's license notice. +These titles must be distinct from any other section titles.</para> + +<para>You may add a section Entitled "Endorsements", provided it +contains nothing but endorsements of your Modified Version by various +parties--for example, statements of peer review or that the text has +been approved by an organization as the authoritative definition of a +standard.</para> + +<para>You may add a passage of up to five words as a Front-Cover Text, +and a passage of up to 25 words as a Back-Cover Text, to the end of the +list of Cover Texts in the Modified Version. Only one passage of +Front-Cover Text and one of Back-Cover Text may be added by (or through +arrangements made by) any one entity. If the Document already includes +a cover text for the same cover, previously added by you or by +arrangement made by the same entity you are acting on behalf of, you may +not add another; but you may replace the old one, on explicit permission +from the previous publisher that added the old one.</para> + +<para>The author(s) and publisher(s) of the Document do not by this +License give permission to use their names for publicity for or to +assert or imply endorsement of any Modified Version.</para> +</sect1> + +<sect1 id="gfdl-5"><title>COMBINING DOCUMENTS</title> + +<para>You may combine the Document with other documents released under +this License, under the terms defined in <link linkend="gfdl-4">section +4</link> above for modified versions, provided that you include in the +combination all of the Invariant Sections of all of the original +documents, unmodified, and list them all as Invariant Sections of your +combined work in its license notice, and that you preserve all their +Warranty Disclaimers.</para> + +<para>The combined work need only contain one copy of this License, and +multiple identical Invariant Sections may be replaced with a single +copy. If there are multiple Invariant Sections with the same name but +different contents, make the title of each such section unique by adding +at the end of it, in parentheses, the name of the original author or +publisher of that section if known, or else a unique number. Make the +same adjustment to the section titles in the list of Invariant Sections +in the license notice of the combined work.</para> + +<para>In the combination, you must combine any sections Entitled +"History" in the various original documents, forming one section +Entitled "History"; likewise combine any sections Entitled +"Acknowledgements", and any sections Entitled "Dedications". You must +delete all sections Entitled "Endorsements".</para> +</sect1> + +<sect1 id="gfdl-6"><title>COLLECTIONS OF DOCUMENTS</title> + +<para>You may make a collection consisting of the Document and other +documents released under this License, and replace the individual copies +of this License in the various documents with a single copy that is +included in the collection, provided that you follow the rules of this +License for verbatim copying of each of the documents in all other +respects.</para> + +<para>You may extract a single document from such a collection, and +distribute it individually under this License, provided you insert a +copy of this License into the extracted document, and follow this +License in all other respects regarding verbatim copying of that +document.</para> +</sect1> + +<sect1 id="gfdl-7"><title>AGGREGATION WITH INDEPENDENT WORKS</title> + +<para>A compilation of the Document or its derivatives with other +separate and independent documents or works, in or on a volume of a +storage or distribution medium, is called an "aggregate" if the +copyright resulting from the compilation is not used to limit the legal +rights of the compilation's users beyond what the individual works +permit. When the Document is included an aggregate, this License does +not apply to the other works in the aggregate which are not themselves +derivative works of the Document.</para> + +<para>If the Cover Text requirement of section 3 is applicable to these +copies of the Document, then if the Document is less than one half of +the entire aggregate, the Document's Cover Texts may be placed on covers +that bracket the Document within the aggregate, or the electronic +equivalent of covers if the Document is in electronic form. Otherwise +they must appear on printed covers that bracket the whole +aggregate.</para> +</sect1> + +<sect1 id="gfdl-8"><title>TRANSLATION</title> + +<para>Translation is considered a kind of modification, so you may +distribute translations of the Document under the terms of section 4. +Replacing Invariant Sections with translations requires special +permission from their copyright holders, but you may include +translations of some or all Invariant Sections in addition to the +original versions of these Invariant Sections. You may include a +translation of this License, and all the license notices in the +Document, and any Warranty Disclaimers, provided that you also include +the original English version of this License and the original versions +of those notices and disclaimers. In case of a disagreement between the +translation and the original version of this License or a notice or +disclaimer, the original version will prevail.</para> + +<para>If a section in the Document is Entitled "Acknowledgements", +"Dedications", or "History", the requirement (section 4) to Preserve its +Title (section 1) will typically require changing the actual +title.</para> +</sect1> + +<sect1 id="gfdl-9"><title>TERMINATION</title> + +<para>You may not copy, modify, sublicense, or distribute the Document +except as expressly provided for under this License. Any other attempt +to copy, modify, sublicense or distribute the Document is void, and will +automatically terminate your rights under this License. However, +parties who have received copies, or rights, from you under this License +will not have their licenses terminated so long as such parties remain +in full compliance.</para> +</sect1> + +<sect1 id="gfdl-10"><title>FUTURE REVISIONS OF THIS LICENSE</title> + +<para>The Free Software Foundation may publish new, revised versions of +the GNU Free Documentation License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in +detail to address new problems or concerns. See +http://www.gnu.org/copyleft/.</para> + +<para>Each version of the License is given a distinguishing version +number. If the Document specifies that a particular numbered version of +this License "or any later version" applies to it, you have the option +of following the terms and conditions either of that specified version +or of any later version that has been published (not as a draft) by the +Free Software Foundation. If the Document does not specify a version +number of this License, you may choose any version ever published (not +as a draft) by the Free Software Foundation.</para> +</sect1> + +<sect1 id="gfdl-addendum"><title>ADDENDUM: How to use this License for + your documents</title> + +<para>To use this License in a document you have written, include a copy +of the License in the document and put the following copyright and +license notices just after the title page:</para> + +<blockquote id="copyright-sample"><para> + Copyright (c) YEAR YOUR NAME. + Permission is granted to copy, distribute and/or modify this document + under the terms of the GNU Free Documentation License, Version 1.2 + or any later version published by the Free Software Foundation; + with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. + A copy of the license is included in the section entitled "GNU + Free Documentation License". +</para></blockquote> + +<para>If you have Invariant Sections, Front-Cover Texts and Back-Cover +Texts, replace the "with...Texts." line with this:</para> + +<blockquote id="inv-cover-sample"><para> + with the Invariant Sections being LIST THEIR TITLES, with the + Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST. +</para></blockquote> + +<para>If you have Invariant Sections without Cover Texts, or some other +combination of the three, merge those two alternatives to suit the +situation.</para> + +<para>If your document contains nontrivial examples of program code, we +recommend releasing these examples in parallel under your choice of free +software license, such as the GNU General Public License, to permit +their use in free software.</para> +</sect1> +</appendix> + +</book> +<!-- + vim:syntax=sgml:sw=4 +--> diff -Nru a/Documentation/DocBook/kernel-api.tmpl b/Documentation/DocBook/kernel-api.tmpl --- a/Documentation/DocBook/kernel-api.tmpl Mon Jun 9 23:16:05 2003 +++ b/Documentation/DocBook/kernel-api.tmpl Mon Jun 9 23:16:05 2003 @@ -79,6 +79,7 @@ </sect1> <sect1><title>String Manipulation</title> !Ilib/string.c +!Elib/string.c </sect1> <sect1><title>Bit Operations</title> !Iinclude/asm-i386/bitops.h @@ -176,7 +177,7 @@ !Edrivers/pci/pci.c </sect1> <sect1><title>PCI Hotplug Support Library</title> -!Edrivers/hotplug/pci_hotplug_core.c +!Edrivers/pci/hotplug/pci_hotplug_core.c </sect1> <sect1><title>MCA Architecture</title> <sect2><title>MCA Device Functions</title> diff -Nru a/Documentation/filesystems/fat_cvf.txt b/Documentation/filesystems/fat_cvf.txt --- a/Documentation/filesystems/fat_cvf.txt Mon Jun 9 23:16:15 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,210 +0,0 @@ -This is the main documentation for the CVF-FAT filesystem extension. 18Nov1998 - - -Table of Contents: - -1. The idea of CVF-FAT -2. Restrictions -3. Mount options -4. Description of the CVF-FAT interface -5. CVF Modules - ------------------------------------------------------------------------------- - - -1. The idea of CVF-FAT ------------------------------------------------------------------------------- - -CVF-FAT is a FAT filesystem extension that provides a generic interface for -Compressed Volume Files in FAT partitions. Popular CVF software, for -example, are Microsoft's Doublespace/Drivespace and Stac's Stacker. -Using the CVF-FAT interface, it is possible to load a module that handles -all the low-level disk access that has to do with on-the-fly compression -and decompression. Any other part of FAT filesystem access is still handled -by the FAT, MSDOS or VFAT or even UMSDOS driver. - -CVF access works by redirecting certain low-level routines from the FAT -driver to a loadable, CVF-format specific module. This module must fake -a normal FAT filesystem to the FAT driver while doing all the extra stuff -like compression and decompression silently. - - -2. Restrictions ------------------------------------------------------------------------------- - -- BMAP problems - - CVF filesystems cannot do bmap. It's impossible in principle. Thus - all actions that require bmap do not work (swapping, writable mmapping). - Read-only mmapping works because the FAT driver has a hack for this - situation :) Well, writable mmapping should now work using the readpage - interface function which has been hacked into the FAT driver just for - CVF-FAT :) - -- attention, DOSEmu users - - You may have to unmount all CVF partitions before running DOSEmu depending - on your configuration. If DOSEmu is configured to use wholedisk or - partition access (this is often the case to let DOSEmu access - compressed partitions) there's a risk of destroying your compressed - partitions or crashing your system because of confused drivers. - - Note that it is always safe to redirect the compressed partitions with - lredir or emufs.sys. Refer to the DOSEmu documentation for details. - - -3. Mount options ------------------------------------------------------------------------------- - -The CVF-FAT extension currently adds the following options to the FAT -driver's standard options: - - cvf_format=xxx - Forces the driver to use the CVF module "xxx" instead of auto-detection. - Without this option, the CVF-FAT interface asks all currently loaded - CVF modules whether they recognize the CVF. Therefore, this option is - only necessary if the CVF format is not recognized correctly - because of bugs or incompatibilities in the CVF modules. (It skips - the detect_cvf call.) "xxx" may be the text "none" (without the quotes) - to inhibit using any of the loaded CVF modules, just in case a CVF - module insists on mounting plain FAT filesystems by misunderstanding. - "xxx" may also be the text "autoload", which has a special meaning for - a module loader, but does not skip auto-detection. - - If the kernel supports kmod, the cvf_format=xxx option also controls - on-demand CVF module loading. Without this option, nothing is loaded - on demand. With cvf_format=xxx, a module "xxx" is requested automatically - before mounting the compressed filesystem (unless "xxx" is "none"). In - case there is a difference between the CVF format name and the module - name, setup aliases in your modules configuration. If the string "xxx" - is "autoload", a non-existent module "cvf_autoload" is requested which - can be used together with a special modules configuration (alias and - pre-install statements) in order to load more than one CVF module, let - them detect automatically which kind of CVF is to be mounted, and only - keep the "right" module in memory. For examples please refer to the - dmsdos documentation (ftp and http addresses see below). - - cvf_options=yyy - Option string passed to the CVF module. I.e. only the "yyy" is passed - (without the quotes). The documentation for each CVF module should - explain it since it is interpreted only by the CVF module. Note that - the string must not contain a comma (",") - this would lead to - misinterpretation by the FAT driver, which would recognize the text - after a comma as a FAT driver option and might get confused or print - strange error messages. The documentation for the CVF module should - offer a different separation symbol, for example the dot "." or the - plus sign "+", which is only valid inside the string "yyy". - - -4. Description of the CVF-FAT interface ------------------------------------------------------------------------------- - -Assuming you want to write your own CVF module, you need to write a lot of -interface functions. Most of them are covered in the kernel documentation -you can find on the net, and thus won't be described here. They have been -marked with "[...]" :-) Take a look at include/linux/fat_cvf.h. - -struct cvf_format -{ int cvf_version; - char* cvf_version_text; - unsigned long int flags; - int (*detect_cvf) (struct super_block*sb); - int (*mount_cvf) (struct super_block*sb,char*options); - int (*unmount_cvf) (struct super_block*sb); - [...] - void (*zero_out_cluster) (struct inode*, int clusternr); -} - -This structure defines the capabilities of a CVF module. It must be filled -out completely by a CVF module. Consider it as a kind of form that is used -to introduce the module to the FAT/CVF-FAT driver. - -It contains... - - cvf_version: - A version id which must be unique. Choose one. - - cvf_version_text: - A human readable version string that should be one short word - describing the CVF format the module implements. This text is used - for the cvf_format option. This name must also be unique. - - flags: - Bit coded flags, currently only used for a readpage/mmap hack that - provides both mmap and readpage functionality. If CVF_USE_READPAGE - is set, mmap is set to generic_file_mmap and readpage is caught - and redirected to the cvf_readpage function. If it is not set, - readpage is set to generic_readpage and mmap is caught and redirected - to cvf_mmap. (If you want writable mmap use the readpage interface.) - - detect_cvf: - A function that is called to decide whether the filesystem is a CVF of - the type the module supports. The detect_cvf function must return 0 - for "NO, I DON'T KNOW THIS GARBAGE" or anything >0 for "YES, THIS IS - THE KIND OF CVF I SUPPORT". The function must maintain the module - usage counters for safety, i.e. do MOD_INC_USE_COUNT at the beginning - and MOD_DEC_USE_COUNT at the end. The function *must not* assume that - successful recognition would lead to a call of the mount_cvf function - later. - - mount_cvf: - A function that sets up some values or initializes something additional - to what has to be done when a CVF is mounted. This is called at the - end of fat_read_super and must return 0 on success. Definitely, this - function must increment the module usage counter by MOD_INC_USE_COUNT. - This mount_cvf function is also responsible for interpreting a CVF - module specific option string (the "yyy" from the FAT mount option - "cvf_options=yyy") which cannot contain a comma (use for example the - dot "." as option separator symbol). - - unmount_cvf: - A function that is called when the filesystem is unmounted. Most likely - it only frees up some memory and calls MOD_DEC_USE_COUNT. The return - value might be ignored (it currently is ignored). - - [...]: - All other interface functions are "caught" FAT driver functions, i.e. - are executed by the FAT driver *instead* of the original FAT driver - functions. NULL means use the original FAT driver functions instead. - If you really want "no action", write a function that does nothing and - hang it in instead. - - zero_out_cluster: - The zero_out_cluster function is called when the fat driver wants to - zero out a (new) cluster. This is important for directories (mkdir). - If it is NULL, the FAT driver defaults to overwriting the whole - cluster with zeros. Note that clusternr is absolute, not relative - to the provided inode. - -Notes: - 1. The cvf_bmap function should be ignored. It really should never - get called from somewhere. I recommend redirecting it to a panic - or fatal error message so bugs show up immediately. - 2. The cvf_writepage function is ignored. This is because the fat - driver doesn't support it. This might change in future. I recommend - setting it to NULL (i.e use default). - -int register_cvf_format(struct cvf_format*cvf_format); - If you have just set up a variable containing the above structure, - call this function to introduce your CVF format to the FAT/CVF-FAT - driver. This is usually done in init_module. Be sure to check the - return value. Zero means success, everything else causes a kernel - message printed in the syslog describing the error that occurred. - Typical errors are: - - a module with the same version id is already registered or - - too many CVF formats. Hack fs/fat/cvf.c if you need more. - -int unregister_cvf_format(struct cvf_format*cvf_format); - This is usually called in cleanup_module. Return value =0 means - success. An error only occurs if you try to unregister a CVF format - that has not been previously registered. The code uses the version id - to distinguish the modules, so be sure to keep it unique. - -5. CVF Modules ------------------------------------------------------------------------------- - -Refer to the dmsdos module (the successor of the dmsdos filesystem) for a -sample implementation. It can currently be found at - - ftp://fb9nt.uni-duisburg.de/pub/linux/dmsdos/dmsdos-x.y.z.tgz - ftp://sunsite.unc.edu/pub/Linux/system/Filesystems/dosfs/dmsdos-x.y.z.tgz - ftp://ftp.uni-stuttgart.de/pub/systems/linux/local/system/dmsdos-x.y.z.tgz - -(where x.y.z is to be replaced with the actual version number). Full -documentation about dmsdos is included in the dmsdos package, but can also -be found at - - http://fb9nt.uni-duisburg.de/mitarbeiter/gockel/software/dmsdos/index.html - http://www.yk.rim.or.jp/~takafumi/dmsdos/index.html (in Japanese). diff -Nru a/Documentation/filesystems/jfs.txt b/Documentation/filesystems/jfs.txt --- a/Documentation/filesystems/jfs.txt Mon Jun 9 23:16:14 2003 +++ b/Documentation/filesystems/jfs.txt Mon Jun 9 23:16:14 2003 @@ -4,10 +4,10 @@ Team members ------------ -Steve Best sbest@us.ibm.com Dave Kleikamp shaggy@austin.ibm.com +Dave Blaschke blaschke@us.ibm.com +Steve Best sbest@us.ibm.com Barry Arndt barndt@us.ibm.com -Christoph Hellwig hch@infradead.org The following mount options are supported: diff -Nru a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt --- a/Documentation/filesystems/proc.txt Mon Jun 9 23:16:09 2003 +++ b/Documentation/filesystems/proc.txt Mon Jun 9 23:16:09 2003 @@ -1068,6 +1068,8 @@ out to disk. This tunable expresses the interval between those wakeups, in 100'ths of a second. +Setting this to zero disables periodic writeback altogether. + dirty_expire_centisecs ---------------------- diff -Nru a/Documentation/kbuild/kconfig-language.txt b/Documentation/kbuild/kconfig-language.txt --- a/Documentation/kbuild/kconfig-language.txt Mon Jun 9 23:16:10 2003 +++ b/Documentation/kbuild/kconfig-language.txt Mon Jun 9 23:16:10 2003 @@ -18,7 +18,7 @@ +- ... Every entry has its own dependencies. These dependencies are used -to determine the visible of an entry. Any child entry is only +to determine the visibility of an entry. Any child entry is only visible if its parent entry is also visible. Menu entries @@ -50,7 +50,7 @@ - type definition: "bool"/"tristate"/"string"/"hex"/"integer" Every config option must have a type. There are only two basic types: - tristate and string, the other types base on these two. The type + tristate and string, the other types are based on these two. The type definition optionally accepts an input prompt, so these two examples are equivalent: @@ -64,7 +64,7 @@ to the user. Optionally dependencies only for this prompt can be added with "if". -- default value: "default" <symbol> ["if" <expr>] +- default value: "default" <expr> ["if" <expr>] A config option can have any number of default values. If multiple default values are visible, only the first defined one is active. Default values are not limited to the menu entry, where they are @@ -81,7 +81,7 @@ This defines a dependency for this menu entry. If multiple dependencies are defined they are connected with '&&'. Dependencies are applied to all other options within this menu entry (which also - accept "if" expression), so these two examples are equivalent: + accept an "if" expression), so these two examples are equivalent: bool "foo" if BAR default y if BAR @@ -90,9 +90,24 @@ bool "foo" default y +- reverse dependencies: "select" <symbol> ["if" <expr>] + While normal dependencies reduce the upper limit of a symbol (see + below), reverse dependencies can be used to force a lower limit of + another symbol. The value of the current menu symbol is used as the + minimal value <symbol> can be set to. If <symbol> is selected multiple + times, the limit is set to the largest selection. + Reverse dependencies can only be used with boolean or tristate + symbols. + +- numerical ranges: "range" <symbol> <symbol> ["if" <expr>] + This allows to limit the range of possible input values for integer + and hex symbols. The user can only input a value which is larger than + or equal to the first symbol and smaller than or equal to the second + symbol. + - help text: "help" This defines a help text. The end of the help text is determined by - the level indentation, this means it ends at the first line which has + the indentation level, this means it ends at the first line which has a smaller indentation than the first line of the help text. @@ -123,14 +138,14 @@ otherwise 'y'. (4) Returns the value of the expression. Used to override precedence. (5) Returns the result of (2-/expr/). -(6) Returns the result of min(/expr/, /expr/). -(7) Returns the result of max(/expr/, /expr/). +(6) Returns the result of max(/expr/, /expr/). +(7) Returns the result of min(/expr/, /expr/). An expression can have a value of 'n', 'm' or 'y' (or 0, 1, 2 respectively for calculations). A menu entry becomes visible when it's expression evaluates to 'm' or 'y'. -There are two type of symbols: constant and nonconstant symbols. +There are two types of symbols: constant and nonconstant symbols. Nonconstant symbols are the most common ones and are defined with the 'config' statement. Nonconstant symbols consist entirely of alphanumeric characters or underscores. @@ -159,8 +174,8 @@ The other way to generate the menu structure is done by analyzing the dependencies. If a menu entry somehow depends on the previous entry, it -can be made a submenu of it. First the the previous (parent) symbol must -be part of the dependency list and then one of these two condititions +can be made a submenu of it. First, the previous (parent) symbol must +be part of the dependency list and then one of these two conditions must be true: - the child entry must become invisible, if the parent is set to 'n' - the child entry must only be visible, if the parent is visible @@ -177,7 +192,7 @@ MODVERSIONS directly depends on MODULES, this means it's only visible if MODULES is different from 'n'. The comment on the other hand is always -visible when MODULES it's visible (the (empty) dependency of MODULES is +visible when MODULES is visible (the (empty) dependency of MODULES is also part of the comment dependencies). @@ -188,12 +203,13 @@ line starts with a keyword (except help texts). The following keywords end a menu entry: - config +- menuconfig - choice/endchoice - comment - menu/endmenu - if/endif - source -The first four also start the definition of a menu entry. +The first five also start the definition of a menu entry. config: @@ -202,6 +218,14 @@ This defines a config symbol <symbol> and accepts any of above attributes as options. + +menuconfig: + "menuconfig" <symbol> + <config options> + +This is similiar to the simple config entry above, but it also gives a +hint to front ends, that all suboptions should be displayed as a +separate list of options. choices: diff -Nru a/Documentation/kbuild/makefiles.txt b/Documentation/kbuild/makefiles.txt --- a/Documentation/kbuild/makefiles.txt Mon Jun 9 23:16:16 2003 +++ b/Documentation/kbuild/makefiles.txt Mon Jun 9 23:16:16 2003 @@ -11,7 +11,7 @@ --- 3.2 Built-in object goals - obj-y --- 3.3 Loadable module goals - obj-m --- 3.4 Objects which export symbols - --- 3.5 Library file goals - L_TARGET + --- 3.5 Library file goals - lib-y --- 3.6 Descending down in directories --- 3.7 Compilation flags --- 3.8 Command line dependency @@ -214,20 +214,33 @@ modules exporting symbols. See also Documentation/modules.txt. ---- 3.5 Library file goals - L_TARGET +--- 3.5 Library file goals - lib-y - Instead of building a built-in.o file, you may also - build an archive which again contains objects listed in $(obj-y). - This is normally not necessary and only used in lib/ and - arch/$(ARCH)/lib directories. - Only the name lib.a is allowed. + Objects listed with obj-* is used for modules or + are combined in a built-in.o for that specific directory. + There is also the possibility to list objects that will + be included in a library, lib.a. + All objects listed with lib-y are combined in a single + library for that directory. + Objects that are listed in obj-y and additional listed in + lib-y will not be included in the library, since they will anyway + be accessible. + For consistency objects listed in lib-m will be included in lib.a. + + Note that the same kbuild makefile may list files to be built-in + and to be part of a library. Therefore the same directory + may contain both a built-in.o and a lib.a file. Example: #arch/i386/lib/Makefile - L_TARGET := lib.a - obj-y := checksum.o delay.o + lib-y := checksum.o delay.o This will create a library lib.a based on checksum.o and delay.o. + For kbuild to actually recognize that there is a lib.a being build + the directory shall be listed in libs-y. + See also "6.3 List directories to visit when descending". + + Usage of lib-y is normally restricted to lib/ and arch/*/lib. --- 3.6 Descending down in directories @@ -727,7 +740,7 @@ head-y, init-y, core-y, libs-y, drivers-y, net-y $(head-y) list objects to be linked first in vmlinux. - $(libs-y) list directories where a libs.a archive can be located. + $(libs-y) list directories where a lib.a archive can be located. The rest list directories where a built-in.o object file can be located. $(init-y) objects will be located after $(head-y). diff -Nru a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt --- a/Documentation/kernel-parameters.txt Mon Jun 9 23:16:20 2003 +++ b/Documentation/kernel-parameters.txt Mon Jun 9 23:16:20 2003 @@ -540,8 +540,6 @@ [KNL,ACPI] Mark specific memory as reserved. Region of memory to be used, from ss to ss+nn. - memfrac= [KNL] - meye= [HW] Set MotionEye Camera parameters See Documentation/video4linux/meye.txt. @@ -616,6 +614,9 @@ use it. noht [SMP,IA-32] Disables P4 Xeon(tm) HyperThreading. + + noirqdebug [IA-32] Disables the code which attempts to detect and + disable unhandled interrupt sources. noisapnp [ISAPNP] Disables ISA PnP code. diff -Nru a/Documentation/kobject.txt b/Documentation/kobject.txt --- a/Documentation/kobject.txt Mon Jun 9 23:16:08 2003 +++ b/Documentation/kobject.txt Mon Jun 9 23:16:08 2003 @@ -2,7 +2,18 @@ Patrick Mochel <mochel@osdl.org> -7 January 2003 +Updated: 3 June 2003 + + +Copyright (c) Patrick Mochel +Copyright (c) Open Source Development Labs +Permission is granted to copy, distribute and/or modify this document +under the terms of the GNU Free Documentation License, Version 1.2 +or any later version published by the Free Software Foundation; +with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. +A copy of the license is included in the section entitled "GNU +Free Documentation License". + 0. Introduction @@ -100,6 +111,28 @@ When a kobject's reference count reaches 0, the method struct kobj_type::release() (which the kobject's kset points to) is called. This allows any memory allocated for the object to be freed. + + +NOTE!!! + +It is _imperative_ that you supply a desctructor for dynamically +allocated kobjects to free them if you are using kobject reference +counts. The reference count controls the duration of the lifetime of +the object. If it goes to 0, then it is assumed that the object will +be freed and cannot be used. + +More importantly, you must free the object there, and not immediately +after an unregister call. If someone else is referencing the object +(e.g. through a sysfs file), they will obtain a reference to the +object, assume it's valid and operate on it. If the object is +unregistered and freed in the meantime, the operation will then +reference freed memory and go boom. + +This can be prevented, in the simplest case, by defining a release +method and freeing the object from there only. Note that this will not +secure reference count/object management models that use a dual +reference count or do other wacky things with the reference count +(like the networking layer). 1.4 sysfs diff -Nru a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt --- a/Documentation/networking/ip-sysctl.txt Mon Jun 9 23:16:10 2003 +++ b/Documentation/networking/ip-sysctl.txt Mon Jun 9 23:16:10 2003 @@ -31,6 +31,11 @@ ipfrag_time - INTEGER Time in seconds to keep an IP fragment in memory. +ipfrag_secret_interval - INTEGER + Regeneration interval (in seconds) of the hash secret (or lifetime + for the hash secret) for IP fragments. + Default: 600 + INET peer storage: inet_peer_threshold - INTEGER @@ -514,6 +519,25 @@ FALSE: enable IPv4-mapped address feature Default: FALSE (as specified in RFC2553bis) + +IPv6 Fragmentation: + +ip6frag_high_thresh - INTEGER + Maximum memory used to reassemble IPv6 fragments. When + ip6frag_high_thresh bytes of memory is allocated for this purpose, + the fragment handler will toss packets until ip6frag_low_thresh + is reached. + +ip6frag_low_thresh - INTEGER + See ip6frag_high_thresh + +ip6frag_time - INTEGER + Time in seconds to keep an IPv6 fragment in memory. + +ip6frag_secret_interval - INTEGER + Regeneration interval (in seconds) of the hash secret (or lifetime + for the hash secret) for IPv6 fragments. + Default: 600 conf/default/*: Change the interface-specific default settings. diff -Nru a/Documentation/rocket.txt b/Documentation/rocket.txt --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/Documentation/rocket.txt Mon Jun 9 23:16:20 2003 @@ -0,0 +1,87 @@ +Comtrol(tm) RocketPort(R)/RocketModem(TM) Series +Device Driver for the Linux Operating System + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +PRODUCT OVERVIEW +---------------- + +This driver provides a loadable kernel driver for the Comtrol RocketPort +and RocketModem PCI boards. These boards provide, 2, 4, 8, 16, or 32 +high-speed serial ports or modems. This driver supports up to a combination +of four RocketPort or RocketModems boards in one machine simultaneously. +This file assumes that you are using the RocketPort driver which is +integrated into the kernel sources. + +The driver can also be installed as an external module using the usual +"make;make install" routine. This external module driver, obtainable +from the Comtrol website listed below, is useful for updating the driver +or installing it into kernels which do not have the driver configured +into them. Installations instructions for the external module +are in the included README and HW_INSTALL files. + +RocketPort ISA and RocketModem II PCI boards are also supported by this +driver, but must use the external module driver for configuration reasons. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +INSTALLATION PROCEDURES +----------------------- + +RocketPort/RocketModem PCI cards require no driver configuration, they are +automatically detected and configured. + +The RocketPort driver can be installed as a module (recommended) or built +into the kernel. This is selected, as for other drivers, through the `make config` +command from the root of the Linux source tree during the kernel build process. + +The RocketPort/RocketModem serial ports installed by this driver are assigned +device major number 46, and will be named /dev/ttyRx, where x is the port number +starting at zero (ex. /dev/ttyR0, /devttyR1, ...). If you have multiple cards +installed in the system, the mapping of port names to serial ports is displayed +in the system log at /var/log/messages. + +If installed as a module, the module must be loaded. This can be done +manually by entering "modprobe rocket". To have the module loaded automatically +upon system boot, edit the /etc/modules.conf file and add the line +"alias char-major-46 rocket". + +In order to use the ports, their device names (nodes) must be created with mknod. +This is only required once, the system will retain the names once created. To +create the RocketPort/RocketModem device names, use the command +"mknod /dev/ttyRx c 46 x" where x is the port number starting at zero. For example: + +>mknod /dev/ttyR0 c 46 0 +>mknod /dev/ttyR1 c 46 1 +>mknod /dev/ttyR2 c 46 2 + +The Linux script MAKEDEV will create the first 16 ttyRx device names (nodes) for you: + +>/dev/MAKEDEV ttyR + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +REPORTING BUGS +-------------- + +For technical support, please provide the following +information: Driver version, kernel release, distribution of +kernel, and type of board you are using. Error messages and log +printouts port configuration details are especially helpful. + +USA + Phone: (612) 494-4100 + FAX: (612) 494-4199 + email: support@comtrol.com + +Comtrol Europe + Phone: +44 (0) 1 869 323-220 + FAX: +44 (0) 1 869 323-211 + email: support@comtrol.co.uk + +Web: http://www.comtrol.com +FTP: ftp.comtrol.com + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + + diff -Nru a/Documentation/scsi/aic7xxx.txt b/Documentation/scsi/aic7xxx.txt --- a/Documentation/scsi/aic7xxx.txt Mon Jun 9 23:16:09 2003 +++ b/Documentation/scsi/aic7xxx.txt Mon Jun 9 23:16:09 2003 @@ -132,6 +132,11 @@ 2. Version History + 6.2.34 - Fix locking regression instroduced in 6.2.29 that + could cuase a lock order reversal between the io_request_lock + and our per-softc lock. This was only possible on RH9, + SuSE, and kernel.org 2.4.X kernels. + 6.2.33 - Dynamically disable PCI parity error reporting after 10 errors are reported to the user. These errors are the result of some other device issuing PCI transactions diff -Nru a/Documentation/scsi/dc395x.txt b/Documentation/scsi/dc395x.txt --- a/Documentation/scsi/dc395x.txt Mon Jun 9 23:16:20 2003 +++ b/Documentation/scsi/dc395x.txt Mon Jun 9 23:16:20 2003 @@ -23,40 +23,70 @@ Both can be overriden by command line parameters (module or kernel parameters). -The syntax is as follows: - dc395x = AdapterID, SpeedIdx, DevMode, AdaptMode, Tags, DelayReset +The following parameters are available: -AdapterID : Host Adapter SCSI ID -SpeedIdx : 0,1,...7 = 20,13.3,10,8,6.7,5.8,5,4 MHz [ 7] -DevMode : Bitmap for Dev Cfg [63] -AdaptMode : Bitmap for Adapter Cfg [47] -Tags : The number of tags is 1<<x, if x has been specified [ 4] -DelayReset: The seconds to not accept commands after a SCSI Reset [ 1] - -DevMode bit definition: - Bit Val(hex) Val(dec) Meaning - *0 0x01 1 Parity check - *1 0x02 2 Synchronous Negotiation - *2 0x04 4 Disconnection - *3 0x08 8 Send Start command on startup. (Not used) - *4 0x10 16 Tagged Command Queueing - *5 0x20 32 Wide Negotiation - -AdaptMode bit definition - Bit Val(hex) Val(dec) Meaning - *0 0x01 1 Support more than two drives. (Not used) - *1 0x02 2 Use DOS compatible mapping for HDs greater than 1GB. - *2 0x04 4 Reset SCSI Bus on startup. - *3 0x08 8 Active Negation: Improves SCSI Bus noise immunity. - 4 0x10 16 Immediate return on BIOS seek command. (Not used) - (*)5 0x20 32 Check for LUNs >= 1. - -If you set AdapterID to -1, the adapter will use conservative -("safe") default settings instead; more precisely, dc395x=-1 is a -shortcut for dc395x=7,4,9,15,2,10 + - safe + Default: 0, Acceptable values: 0 or 1 + + If safe is set to 1 then the adapter will use conservative + ("safe") default settings. This sets: + + shortcut for dc395x=7,4,9,15,2,10 + + - adapter_id + Default: 7, Acceptable values: 0 to 15 + + Sets the host adapter SCSI ID. + + - max_speed + Default: 1, Acceptable value: 0 to 7 + 0 = 20 Mhz + 1 = 12.2 Mhz + 2 = 10 Mhz + 3 = 8 Mhz + 4 = 6.7 Mhz + 5 = 5.8 Hhz + 6 = 5 Mhz + 7 = 4 Mhz + + - dev_mode + Bitmap for device configuration + + DevMode bit definition: + Bit Val(hex) Val(dec) Meaning + *0 0x01 1 Parity check + *1 0x02 2 Synchronous Negotiation + *2 0x04 4 Disconnection + *3 0x08 8 Send Start command on startup. (Not used) + *4 0x10 16 Tagged Command Queueing + *5 0x20 32 Wide Negotiation + + - adapter_mode + Bitmap for adapter configuration + + AdaptMode bit definition + Bit Val(hex) Val(dec) Meaning + *0 0x01 1 Support more than two drives. (Not used) + *1 0x02 2 Use DOS compatible mapping for HDs greater than 1GB. + *2 0x04 4 Reset SCSI Bus on startup. + *3 0x08 8 Active Negation: Improves SCSI Bus noise immunity. + 4 0x10 16 Immediate return on BIOS seek command. (Not used) + (*)5 0x20 32 Check for LUNs >= 1. + + - tags + Default: 3, Acceptable values: 0-5 + + The number of tags is 1<<x, if x has been specified + + - reset_delay + Default: 1, Acceptable values: 0-180 + + The seconds to not accept commands after a SCSI Reset + + +For the built in driver the parameters should be prefixed with +dc395x. (eg "dc395x.safe=1") -If you specify -2 for a value, it will be ignored. You don't need to -specify all six parameters. Copyright --------- diff -Nru a/Documentation/scsi/scsi_mid_low_api.txt b/Documentation/scsi/scsi_mid_low_api.txt --- a/Documentation/scsi/scsi_mid_low_api.txt Mon Jun 9 23:16:16 2003 +++ b/Documentation/scsi/scsi_mid_low_api.txt Mon Jun 9 23:16:16 2003 @@ -22,7 +22,10 @@ a SCSI host and a PCI device is common but not required (e.g. with ISA or MCA adapters).] -This version of the document roughly matches linux kernel version 2.5.67 . +This version of the document roughly matches linux kernel version 2.5.68 . +This document can be found in the Linux kernel source Documentation/scsi +directory and is called scsi_mid_low_api.txt . A more recent copy may +be found at http://www.torque.net/scsi/scsi_mid_low_api.txt.gz . Documentation ============= @@ -142,13 +145,14 @@ slave_configure() --> scsi_adjust_queue_depth() | slave_alloc() - slave_configure() --> scsi_adjust_queue_depth() + slave_configure() | slave_alloc() ** slave_destroy() ** -The invocation of scsi_adjust_queue_depth() by the LLD is required -if slave_configure() is supplied. +If the LLD wants to adjust the default queue settings, it can invoke +scsi_adjust_queue_depth() in its slave_configure() routine. + ** For scsi devices that the mid level tries to scan but do not respond, a slave_alloc(), slave_destroy() pair is called. @@ -179,7 +183,7 @@ scsi_add_device() ------+ | slave_alloc() - slave_configure() --> scsi_adjust_queue_depth() + slave_configure() [--> scsi_adjust_queue_depth()] [DEVICE unplug] LLD mid level LLD @@ -228,13 +232,14 @@ slave_destroy() ** | slave_alloc() - slave_configure() --> scsi_adjust_queue_depth() + slave_configure() slave_alloc() ** slave_destroy() ** -If the LLD does not supply a slave_configure() then the mid level invokes -scsi_adjust_queue_depth() itself with tagged queuing off and "cmd_per_lun" -for that host as the queue length. +The mid level invokes scsi_adjust_queue_depth() with tagged queuing off and +"cmd_per_lun" for that host as the queue length. These settings can be +overridden by a slave_configure() supplied by the LLD. + ** For scsi devices that the mid level tries to scan but do not respond, a slave_alloc(), slave_destroy() pair is called. @@ -1093,11 +1098,6 @@ * Notes: Allows the driver to inspect the response to the initial * INQUIRY done by the scanning code and take appropriate action. * For more details see the hosts.h file. - * If this function is not supplied, the mid level will call - * scsi_adjust_queue_depth() with the struct Scsi_Host::cmd_per_lun - * value on behalf of the given device. If this function is - * supplied then its implementation must call - * scsi_adjust_queue_depth(). * * Defined in: LLD **/ @@ -1277,8 +1277,9 @@ Patrick Mansfield <patmans@us.ibm.com> Christoph Hellwig <hch@infradead.org> Doug Ledford <dledford@redhat.com> + Andries Brouwer <Andries.Brouwer@cwi.nl> Douglas Gilbert dgilbert@interlog.com -19th April 2003 +29th April 2003 diff -Nru a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt --- a/Documentation/sound/alsa/ALSA-Configuration.txt Mon Jun 9 23:16:07 2003 +++ b/Documentation/sound/alsa/ALSA-Configuration.txt Mon Jun 9 23:16:07 2003 @@ -53,14 +53,9 @@ for soundcards which are not installed in your system device_mode - specifies permission mask for dynamic sound device filesystem + (available only when DEVFS is enabled) - default value = 0666 - for example 'device_mode=0660' - device_gid - - specifies GID number for dynamic sound device filesystem - - default value = 0 (root) - device_uid - - specifies UID number for dynamic sound device filesystem - - default value = 0 (root) Module snd-pcm-oss @@ -144,6 +139,7 @@ Module for ALi M5451 PCI chip. pcm_channels - Number of hardware channels assigned for PCM + spdif - Support SPDIF I/O (disabled by default) Module supports autoprobe and multiple chips (max 8). @@ -191,6 +187,13 @@ Module supports up to 8 cards, PnP and autoprobe. + Module snd-azt3328 + ------------------ + + Module for soundcards based on Aztech AZF3328 PCI chip. + + Module supports up to 8 cards. + Module snd-cmi8330 ------------------ @@ -846,6 +849,20 @@ Module supports up to 8 cards. + Module snd-sscape + ----------------- + + Module for ENSONIQ SoundScape PnP cards. + + port - Port # (PnP setup) + irq - IRQ # (PnP setup) + mpu_irq - MPU-401 IRQ # (PnP setup) + dma - DMA # (PnP setup) + + Module supports up to 8 cards. ISA PnP must be enabled. + You need sscape_ctl tool in alsa-tools package for loading + the microcode. + Module snd-sun-amd7930 (on sparc only) -------------------------------------- @@ -945,19 +962,34 @@ Module snd-via82xx ------------------ - Module for AC'97 motherboards based on VIA 82C686A/686B, 8233 - (south) bridge. + Module for AC'97 motherboards based on VIA 82C686A/686B, 8233, + 8233A, 8233C, 8235 (south) bridge. mpu_port - 0x300,0x310,0x320,0x330, otherwise obtain BIOS setup + [VIA686A/686B only] ac97_clock - AC'97 codec clock base (default 48000Hz) + dxs_support - support DXS channels, + 0 = auto (default), 1 = enable, 2 = disable, + 3 = 48k only + [VIA8233/C,8235 only] Module supports autoprobe and multiple bus-master chips (max 8). + Note: on some SMP motherboards like MSI 694D the interrupts might not be generated properly. In such a case, please try to set the SMP (or MPS) version on BIOS to 1.1 instead of default value 1.4. Then the interrupt number will be assigned under 15. You might also upgrade your BIOS. + Note: VIA8233/5 (not VIA8233A) can support DXS (direct sound) + channels as the first PCM. With this device, up to 4 + streams can be played at the same time. If the playback on + this PCM is noisy, try to specify dxs_channels option to 2 + or 3. + + Note: for the MPU401 on VIA823x, use snd-mpu401 driver + additonally. + Module snd-virmidi ------------------ @@ -968,6 +1000,53 @@ midi_devs - MIDI devices # (1-8, default=4) Module supports up to 8 cards. + + Module snd-vx222 + ---------------- + + Module for Digigram VX-Pocket VX222, V222 v2 and Mic cards. + + mic - Enable Microphone on V222 Mic (NYI) + + Module supports up to 8 cards. + + For loading the firmware, use vxloader utility in alsa-tools + package. You can load the firmware automatically by adding + the following to /etc/modules.conf + + post-install snd-vx222 "/usr/bin/vxload" + + Module snd-vxpocket + ------------------- + + Module for Digigram VX-Pocket VX2 PCMCIA card. + + irq_mask - IRQ bitmask, specifies the available IRQs as bits + + Module supports up to 8 cards. The module is compiled only when + PCMCIA is supported on kernel. + + To activate the driver via the card manager, you'll need to set + up /etc/pcmcia/vxpocket.conf. See the sound/pcmcia/vx/vxpocket.c. + + For loading the firmware, use vxloader utility in alsa-tools + package. + + Module snd-vxp440 + ----------------- + + Module for Digigram VX-Pocket 440 PCMCIA card. + + irq_mask - IRQ bitmask, specifies the available IRQs as bits + + Module supports up to 8 cards. The module is compiled only when + PCMCIA is supported on kernel. + + To activate the driver via the card manager, you'll need to set + up /etc/pcmcia/vxp440.conf. See the sound/pcmcia/vx/vxp440.c. + + For loading the firmware, use vxloader utility in alsa-tools + package. Module snd-ymfpci ----------------- diff -Nru a/Documentation/sound/alsa/CMIPCI.txt b/Documentation/sound/alsa/CMIPCI.txt --- a/Documentation/sound/alsa/CMIPCI.txt Mon Jun 9 23:16:05 2003 +++ b/Documentation/sound/alsa/CMIPCI.txt Mon Jun 9 23:16:06 2003 @@ -115,8 +115,7 @@ % aplay -Dspdif foo.wav -So far, only S16LE format is supported. Still no 24bit. Sorry, not -enough info for this. +24bit format is also supported experimentally. The playback and capture over SPDIF use normal DAC and ADC, respectively, so you cannot playback both analog and digital streams diff -Nru a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl --- a/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl Mon Jun 9 23:16:09 2003 +++ b/Documentation/sound/alsa/DocBook/writing-an-alsa-driver.tmpl Mon Jun 9 23:16:09 2003 @@ -1538,11 +1538,12 @@ <informalexample> <programlisting> <![CDATA[ - static void snd_mychip_interrupt(int irq, void *dev_id, - struct pt_regs *regs) + static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id, + struct pt_regs *regs) { mychip_t *chip = snd_magic_cast(mychip_t, dev_id, return); .... + return IRQ_HANDLED; } ]]> </programlisting> @@ -2905,7 +2906,8 @@ </para> <para> - This callback may be called multiple times, too. + This function is always called before the close callback is called. + Also, the callback may be called multiple times, too. Keep track whether the resource was already released. </para> </section> @@ -3006,14 +3008,16 @@ </para> <para> - When the pcm supports the suspend/resume operation, + When the pcm supports the suspend/resume operation + (i.e. <constant>SNDRV_PCM_INFO_RESUME</constant> flag is set), <constant>SUSPEND</constant> and <constant>RESUME</constant> - commands must be handled, too. Obviously it does suspend and - resume of the pcm substream. Usually, the - <constant>SUSPEND</constant> is identical with - <constant>STOP</constant> command and the - <constant>RESUME</constant> is identical with - <constant>START</constant> command. + commands must be handled, too. + These commands are issued when the power-management status is + changed. Obviously, the <constant>SUSPEND</constant> and + <constant>RESUME</constant> + do suspend and resume of the pcm substream, and usually, they + are identical with <constant>STOP</constant> and + <constant>START</constant> commands, respectively. </para> <para> @@ -3149,8 +3153,8 @@ <title>Interrupt Handler Case #1</title> <programlisting> <![CDATA[ - static void snd_mychip_interrupt(int irq, void *dev_id, - struct pt_regs *regs) + static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id, + struct pt_regs *regs) { mychip_t *chip = snd_magic_cast(mychip_t, dev_id, return); spin_lock(&chip->lock); @@ -3160,9 +3164,11 @@ spin_unlock(&chip->lock); snd_pcm_period_elapsed(chip->substream); spin_lock(&chip->lock); + // acknowledge the interrupt if necessary } .... spin_unlock(&chip->lock); + return IRQ_HANDLED; } ]]> </programlisting> @@ -3191,8 +3197,8 @@ <title>Interrupt Handler Case #2</title> <programlisting> <![CDATA[ - static void snd_mychip_interrupt(int irq, void *dev_id, - struct pt_regs *regs) + static irqreturn_t snd_mychip_interrupt(int irq, void *dev_id, + struct pt_regs *regs) { mychip_t *chip = snd_magic_cast(mychip_t, dev_id, return); spin_lock(&chip->lock); @@ -3221,9 +3227,11 @@ snd_pcm_period_elapsed(substream); spin_lock(&chip->lock); } + // acknowledge the interrupt if necessary } .... spin_unlock(&chip->lock); + return IRQ_HANDLED; } ]]> </programlisting> @@ -3326,9 +3334,96 @@ </para> <para> - There are many different constraints. You can even define your - own constraint rules. I won't explain the details here, rather I - would like to say, <quote>Luke, use the source.</quote> + There are many different constraints. + Look in <filename>sound/asound.h</filename> for a complete list. + You can even define your own constraint rules. + For example, let's suppose my_chip can manage a substream of 1 channel + if and only if the format is S16_LE, otherwise it supports any format + specified in the <type>snd_pcm_hardware_t</type> stucture (or in any + other constraint_list). You can build a rule like this: + + <example> + <title>Example of Hardware Constraints for Channels</title> + <programlisting> +<![CDATA[ + static int hw_rule_format_by_channels(snd_pcm_hw_params_t *params, + snd_pcm_hw_rule_t *rule) + { + snd_interval_t *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + snd_mask_t *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + snd_mask_t fmt; + + snd_mask_any(&fmt); // Init the struct + if (c->min < 2) { + fmt.bits[0] &= SNDRV_PCM_FMTBIT_S16_LE; + return snd_mask_refine(f, &fmt); + } + return 0; + } +]]> + </programlisting> + </example> + </para> + + <para> + Then you need to call this function to add your rule: + + <informalexample> + <programlisting> +<![CDATA[ + snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + hw_rule_channels_by_format, 0, SNDRV_PCM_HW_PARAM_FORMAT, + -1); +]]> + </programlisting> + </informalexample> + </para> + + <para> + The rule function is called when an application sets the number of + channels. But an application can set the format before the number of + channels. Thus you also need to define the inverse rule: + + <example> + <title>Example of Hardware Constraints for Channels</title> + <programlisting> +<![CDATA[ + static int hw_rule_channels_by_format(snd_pcm_hw_params_t *params, + snd_pcm_hw_rule_t *rule) + { + snd_interval_t *c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); + snd_mask_t *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); + snd_interval_t ch; + + snd_interval_any(&ch); + if (f->bits[0] == SNDRV_PCM_FMTBIT_S16_LE) { + ch.min = ch.max = 1; + ch.integer = 1; + return snd_interval_refine(c, &ch); + } + return 0; + } +]]> + </programlisting> + </example> + </para> + + <para> + ...and in the open callback: + <informalexample> + <programlisting> +<![CDATA[ + snd_pcm_hw_rule_add(substream->runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, + hw_rule_format_by_channels, 0, SNDRV_PCM_HW_PARAM_CHANNELS, + -1); +]]> + </programlisting> + </informalexample> + </para> + + <para> + I won't explain more details here, rather I + would like to say, <quote>Luke, use the source.</quote> </para> </section> @@ -5750,6 +5845,10 @@ <para> Kevin Conder reformatted the original plain-text to the DocBook format. + </para> + <para> + Giuliano Pochini corrected typos and contributed the example codes + in the hardware constraints section. </para> </chapter> diff -Nru a/Documentation/sound/alsa/OSS-Emulation.txt b/Documentation/sound/alsa/OSS-Emulation.txt --- a/Documentation/sound/alsa/OSS-Emulation.txt Mon Jun 9 23:16:14 2003 +++ b/Documentation/sound/alsa/OSS-Emulation.txt Mon Jun 9 23:16:14 2003 @@ -249,7 +249,7 @@ [Volume|Switch]" will be checked in addition. The current assignment of these mixer elements is listed in the proc -file, /proc/asound/cardX/mixer_oss, which will be like the following +file, /proc/asound/cardX/oss_mixer, which will be like the following VOLUME "Master" 0 BASS "" 0 @@ -267,7 +267,7 @@ proc file. For example, to map "Wave Playback" to the PCM volume, send the command like the following: - % echo 'VOLUME "Wave Playback" 0' > /proc/asound/card0/mixer_oss + % echo 'VOLUME "Wave Playback" 0' > /proc/asound/card0/oss_mixer The command is exactly as same as listed in the proc file. You can change one or more elements, one volume per line. In the last diff -Nru a/Documentation/sysctl/vm.txt b/Documentation/sysctl/vm.txt --- a/Documentation/sysctl/vm.txt Mon Jun 9 23:16:16 2003 +++ b/Documentation/sysctl/vm.txt Mon Jun 9 23:16:16 2003 @@ -22,6 +22,7 @@ - dirty_background_ratio - dirty_expire_centisecs - dirty_writeback_centisecs +- min_free_kbytes ============================================================== @@ -74,3 +75,11 @@ 2 ^ page-cluster. Values above 2 ^ 5 don't make much sense for swap because we only cluster swap data in 32-page groups. +============================================================== + +min_free_kbytes: + +This is used to force the Linux VM to keep a minimum number +of kilobytes free. The VM uses this number to compute a pages_min +value for each lowmem zone in the system. Each lowmem zone gets +a number of reserved free pages based proportionally on its size. diff -Nru a/Documentation/usb/proc_usb_info.txt b/Documentation/usb/proc_usb_info.txt --- a/Documentation/usb/proc_usb_info.txt Mon Jun 9 23:16:07 2003 +++ b/Documentation/usb/proc_usb_info.txt Mon Jun 9 23:16:07 2003 @@ -1,10 +1,11 @@ /proc/bus/usb filesystem output =============================== -(version 2002.03.19) +(version 2003.05.30) -The /proc filesystem for USB devices provides /proc/bus/usb/drivers -and /proc/bus/usb/devices, as well as /proc/bus/usb/BBB/DDD files. +The usbfs filesystem for USB devices is traditionally mounted at +/proc/bus/usb. It provides the /proc/bus/usb/devices file, as well as +the /proc/bus/usb/BBB/DDD files. **NOTE**: If /proc/bus/usb appears empty, and a host controller @@ -66,30 +67,6 @@ grant read/write permissions to other users by using "chmod". Also, usbfs mount options such as "devmode=0666" may be helpful. - - -THE /proc/bus/usb/drivers FILE: -------------------------------- -Each of the USB device drivers linked into your kernel (statically, -or dynamically using "modprobe") is listed in the "drivers" file. -Here's an example from one system: - - usbdevfs - hub - 0- 15: usblp - usbnet - serial - usb-storage - pegasus - -If you see this file, "usbdevfs" and "hub" will always be listed, -since those are part of the "usbcore" framework. - -Drivers that use the USB major number (180) to provide character devices -will include a range of minor numbers, as shown above for the "usblp" -(actually "printer.o") module. USB device drivers can of course use any -major number, but it's easy to use the USB range since there's explicit -support for subdividing it in the USB device driver framework. THE /proc/bus/usb/devices FILE: diff -Nru a/Documentation/vm/hugetlbpage.txt b/Documentation/vm/hugetlbpage.txt --- a/Documentation/vm/hugetlbpage.txt Mon Jun 9 23:16:07 2003 +++ b/Documentation/vm/hugetlbpage.txt Mon Jun 9 23:16:07 2003 @@ -67,14 +67,21 @@ call, then it is required that system administrator mount a file system of type hugetlbfs: - mount none /mnt/huge -t hugetlbfs + mount none /mnt/huge -t hugetlbfs <uid=value> <gid=value> <mode=value> This command mounts a (pseudo) filesystem of type hugetlbfs on the directory -/mnt/huge. Any files created on /mnt/huge uses hugepages. An example is -given at the end of this document. +/mnt/huge. Any files created on /mnt/huge uses hugepages. The uid and gid +options sets the owner and group of the root of the file system. By default +the uid and gid of the current process are taken. The mode option sets the +mode of root of file system to value & 0777. This value is given in octal. +By default the value 0755 is picked. An example is given at the end of this +document. read and write system calls are not supported on files that reside on hugetlb file systems. + +A regular chown, chgrp and chmod commands (with right permissions) could be +used to change the file attributes on hugetlbfs. Also, it is important to note that no such mount command is required if the applications are going to use only shmat/shmget system calls. It is possible diff -Nru a/MAINTAINERS b/MAINTAINERS --- a/MAINTAINERS Mon Jun 9 23:16:14 2003 +++ b/MAINTAINERS Mon Jun 9 23:16:14 2003 @@ -281,6 +281,13 @@ W: http://linux-atm.sourceforge.net S: Maintained +ATMEL WIRELESS DRIVER +P: Simon Kelley +M: simon@thekelleys.org.uk +W: http://www.thekelleys.org.uk/atmel +W: http://atmelwlandriver.sourceforge.net/ +S: Maintained + AX.25 NETWORK LAYER P: Ralf Baechle M: ralf@linux-mips.org @@ -388,27 +395,6 @@ L: pcihpd-discuss@lists.sourceforge.net S: Supported -COMPAQ FIBRE CHANNEL 64-bit/66MHz PCI non-intelligent HBA -P: Amy Vanzant-Hodge -M: Amy Vanzant-Hodge (fibrechannel@compaq.com) -L: compaqandlinux@cpqlin.van-dijk.net -W: ftp.compaq.com/pub/products/drivers/linux -S: Supported - -COMPAQ SMART2 RAID DRIVER -P: Charles White -M: Charles White <arrays@compaq.com> -L: compaqandlinux@cpqlin.van-dijk.net -W: ftp.compaq.com/pub/products/drivers/linux -S: Supported - -COMPAQ SMART CISS RAID DRIVER -P: Charles White -M: Charles White <arrays@compaq.com> -L: compaqandlinux@cpqlin.van-dijk.net -W: ftp.compaq.com/pub/products/drivers/linux -S: Supported - COMPUTONE INTELLIPORT MULTIPORT CARD P: Michael H. Warfield M: Michael H. Warfield <mhw@wittsend.com> @@ -785,6 +771,27 @@ L: linux-hippi@sunsite.dk S: Maintained +HP (was COMPAQ) FIBRE CHANNEL 64-bit/66MHz PCI non-intelligent HBA +P: Stephen Cameron +M: arrays@hp.com +M: steve.cameron@hp.com +L: cpqfc-discuss@lists.sourceforge.net +S: Odd Fixes + +HP (was COMPAQ) SMART2 RAID DRIVER +P: Stephen Cameron +M: arrays@hp.com +M: steve.cameron@hp.com +L: cpqarray-discuss@lists.sourceforge.net +S: Odd Fixes + +HP (was COMPAQ) SMART CISS RAID DRIVER +P: Stephen Cameron +M: arrays@hp.com +M: steve.cameron@hp.com +L: cciss-discuss@lists.sourceforge.net +S: Supported + HP100: Driver for HP 10/100 Mbit/s Voice Grade Network Adapter Series P: Jaroslav Kysela M: perex@suse.cz @@ -1111,8 +1118,10 @@ S: Maintained LINUX FOR 64BIT POWERPC -P: David Engebretsen +P: David Engebretsen (stable kernel) M: engebret@us.ibm.com +P: Anton Blanchard (development kernel) +M: anton@au.ibm.com W: http://linuxppc64.org L: linuxppc64-dev@lists.linuxppc.org S: Supported @@ -1523,6 +1532,12 @@ L: reiserfs-list@namesys.com W: http://www.namesys.com S: Supported + +ROCKETPORT DRIVER +P: Comtrol Corp. +M: support@comtrol.com +W: http://www.comtrol.com +S: Maintained ROSE NETWORK LAYER P: Ralf Baechle diff -Nru a/Makefile b/Makefile --- a/Makefile Mon Jun 9 23:16:15 2003 +++ b/Makefile Mon Jun 9 23:16:15 2003 @@ -36,13 +36,36 @@ SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ -e s/arm.*/arm/ -e s/sa110/arm/ \ -e s/s390x/s390/ ) -ARCH := $(SUBARCH) # Remove hyphens since they have special meaning in RPM filenames KERNELPATH=kernel-$(subst -,,$(KERNELRELEASE)) +# Cross compiling and selecting different set of gcc/bin-utils +# --------------------------------------------------------------------------- +# +# When performing cross compilation for other architectures ARCH shall be set +# to the target architecture. (See arch/* for the possibilities). +# ARCH can be set during invocation of make: +# make ARCH=ia64 +# Another way is to have ARCH set in the environment. +# The default ARCH is the host where make is executed. + +# CROSS_COMPILE specify the prefix used for all executables used +# during compilation. Only gcc and related bin-utils executables +# are prefixed with $(CROSS_COMPILE). +# CROSS_COMPILE can be set on the command line +# make CROSS_COMPILE=ia64-linux- +# Alternatively CROSS_COMPILE can be set in the environment. +# Default value for CROSS_COMPILE is not to prefix executables +# Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile + +ARCH ?= $(SUBARCH) +CROSS_COMPILE ?= + +# Architecture as present in compile.h UTS_MACHINE := $(ARCH) +# SHELL used by kbuild CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ else if [ -x /bin/bash ]; then echo /bin/bash; \ else echo sh; fi ; fi) @@ -53,7 +76,6 @@ HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer HOSTCXXFLAGS = -O2 -CROSS_COMPILE = # That's our default target when none is given on the command line # Note that 'modules' will be added as a prerequisite as well, @@ -266,7 +288,9 @@ core-y := $(patsubst %/, %/built-in.o, $(core-y)) drivers-y := $(patsubst %/, %/built-in.o, $(drivers-y)) net-y := $(patsubst %/, %/built-in.o, $(net-y)) -libs-y := $(patsubst %/, %/lib.a, $(libs-y)) +libs-y1 := $(patsubst %/, %/lib.a, $(libs-y)) +libs-y2 := $(patsubst %/, %/built-in.o, $(libs-y)) +libs-y := $(libs-y1) $(libs-y2) ifdef include_config @@ -783,25 +807,27 @@ help: @echo 'Cleaning targets:' - @echo ' clean - remove most generated files but keep the config' - @echo ' mrproper - remove all generated files + config + various backup files' + @echo ' clean - remove most generated files but keep the config' + @echo ' mrproper - remove all generated files + config + various backup files' @echo '' @echo 'Configuration targets:' - @echo ' oldconfig - Update current config utilising a line-oriented program' - @echo ' menuconfig - Update current config utilising a menu based program' - @echo ' xconfig - Update current config utilising a X-based program' - @echo ' defconfig - New config with default answer to all options' - @echo ' allmodconfig - New config selecting modules when possible' - @echo ' allyesconfig - New config where all options are accepted with yes' - @echo ' allnoconfig - New minimal config' + @echo ' oldconfig - Update current config utilising a line-oriented program' + @echo ' menuconfig - Update current config utilising a menu based program' + @echo ' xconfig - Update current config utilising a QT based front-end' + @echo ' gconfig - Update current config utilising a GTK based front-end' + @echo ' defconfig - New config with default answer to all options' + @echo ' allmodconfig - New config selecting modules when possible' + @echo ' allyesconfig - New config where all options are accepted with yes' + @echo ' allnoconfig - New minimal config' @echo '' @echo 'Other generic targets:' - @echo ' all - Build all targets marked with [*]' - @echo '* vmlinux - Build the bare kernel' - @echo '* modules - Build all modules' - @echo ' dir/file.[ois]- Build specified target only' - @echo ' rpm - Build a kernel as an RPM package' - @echo ' tags/TAGS - Generate tags file for editors' + @echo ' all - Build all targets marked with [*]' + @echo '* vmlinux - Build the bare kernel' + @echo '* modules - Build all modules' + @echo ' modules_install - Install all modules' + @echo ' dir/file.[ois] - Build specified target only' + @echo ' rpm - Build a kernel as an RPM package' + @echo ' tags/TAGS - Generate tags file for editors' @echo '' @echo 'Documentation targets:' @$(MAKE) --no-print-directory -f Documentation/DocBook/Makefile dochelp @@ -809,6 +835,9 @@ @echo 'Architecture specific targets ($(ARCH)):' @$(if $(archhelp),$(archhelp),\ echo ' No architecture specific help defined for $(ARCH)') + @echo '' + @echo ' make V=0|1 [targets] 0 => quiet build (default), 1 => verbose build' + @echo ' make C=1 [targets] Check all c source with checker tool' @echo '' @echo 'Execute "make" or "make all" to build all targets marked with [*] ' @echo 'For further info browse Documentation/kbuild/*' diff -Nru a/arch/alpha/kernel/asm-offsets.c b/arch/alpha/kernel/asm-offsets.c --- a/arch/alpha/kernel/asm-offsets.c Mon Jun 9 23:16:19 2003 +++ b/arch/alpha/kernel/asm-offsets.c Mon Jun 9 23:16:19 2003 @@ -31,6 +31,7 @@ DEFINE(TASK_TGID, offsetof(struct task_struct, tgid)); BLANK(); + DEFINE(SIZEOF_PT_REGS, sizeof(struct pt_regs)); DEFINE(PT_PTRACED, PT_PTRACED); DEFINE(CLONE_VM, CLONE_VM); DEFINE(CLONE_UNTRACED, CLONE_UNTRACED); diff -Nru a/arch/alpha/kernel/core_marvel.c b/arch/alpha/kernel/core_marvel.c --- a/arch/alpha/kernel/core_marvel.c Mon Jun 9 23:16:07 2003 +++ b/arch/alpha/kernel/core_marvel.c Mon Jun 9 23:16:07 2003 @@ -980,7 +980,7 @@ } static int -marvel_agp_bind_memory(alpha_agp_info *agp, off_t pg_start, agp_memory *mem) +marvel_agp_bind_memory(alpha_agp_info *agp, off_t pg_start, struct agp_memory *mem) { struct marvel_agp_aperture *aper = agp->aperture.sysdata; return iommu_bind(aper->arena, aper->pg_start + pg_start, @@ -988,7 +988,7 @@ } static int -marvel_agp_unbind_memory(alpha_agp_info *agp, off_t pg_start, agp_memory *mem) +marvel_agp_unbind_memory(alpha_agp_info *agp, off_t pg_start, struct agp_memory *mem) { struct marvel_agp_aperture *aper = agp->aperture.sysdata; return iommu_unbind(aper->arena, aper->pg_start + pg_start, diff -Nru a/arch/alpha/kernel/core_titan.c b/arch/alpha/kernel/core_titan.c --- a/arch/alpha/kernel/core_titan.c Mon Jun 9 23:16:09 2003 +++ b/arch/alpha/kernel/core_titan.c Mon Jun 9 23:16:09 2003 @@ -679,7 +679,7 @@ } static int -titan_agp_bind_memory(alpha_agp_info *agp, off_t pg_start, agp_memory *mem) +titan_agp_bind_memory(alpha_agp_info *agp, off_t pg_start, struct agp_memory *mem) { struct titan_agp_aperture *aper = agp->aperture.sysdata; return iommu_bind(aper->arena, aper->pg_start + pg_start, @@ -687,7 +687,7 @@ } static int -titan_agp_unbind_memory(alpha_agp_info *agp, off_t pg_start, agp_memory *mem) +titan_agp_unbind_memory(alpha_agp_info *agp, off_t pg_start, struct agp_memory *mem) { struct titan_agp_aperture *aper = agp->aperture.sysdata; return iommu_unbind(aper->arena, aper->pg_start + pg_start, diff -Nru a/arch/alpha/kernel/head.S b/arch/alpha/kernel/head.S --- a/arch/alpha/kernel/head.S Mon Jun 9 23:16:05 2003 +++ b/arch/alpha/kernel/head.S Mon Jun 9 23:16:05 2003 @@ -9,6 +9,7 @@ #include <linux/config.h> #include <asm/system.h> +#include <asm/asm_offsets.h> .globl swapper_pg_dir .globl _stext @@ -25,7 +26,7 @@ /* We need to get current_task_info loaded up... */ lda $8,init_thread_union /* ... and find our stack ... */ - lda $30,0x4000($8) + lda $30,0x4000 - SIZEOF_PT_REGS($8) /* ... and then we can start the kernel. */ jsr $26,start_kernel call_pal PAL_halt diff -Nru a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c --- a/arch/alpha/kernel/irq.c Mon Jun 9 23:16:16 2003 +++ b/arch/alpha/kernel/irq.c Mon Jun 9 23:16:16 2003 @@ -34,7 +34,10 @@ * Controller mappings for all interrupt sources: */ irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { - [0 ... NR_IRQS-1] = { 0, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED} + [0 ... NR_IRQS-1] = { + .handler = &no_irq_type, + .lock = SPIN_LOCK_UNLOCKED + } }; static void register_irq_proc(unsigned int irq); diff -Nru a/arch/alpha/kernel/pci.c b/arch/alpha/kernel/pci.c --- a/arch/alpha/kernel/pci.c Mon Jun 9 23:16:07 2003 +++ b/arch/alpha/kernel/pci.c Mon Jun 9 23:16:07 2003 @@ -102,7 +102,7 @@ { unsigned int class = dev->class >> 8; - if (class == PCI_CLASS_BRIDGE_ISA || class == PCI_CLASS_BRIDGE_ISA) { + if (class == PCI_CLASS_BRIDGE_ISA || class == PCI_CLASS_BRIDGE_EISA) { dev->dma_mask = MAX_ISA_DMA_ADDRESS - 1; isa_bridge = dev; } diff -Nru a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c --- a/arch/alpha/kernel/ptrace.c Mon Jun 9 23:16:18 2003 +++ b/arch/alpha/kernel/ptrace.c Mon Jun 9 23:16:18 2003 @@ -366,8 +366,8 @@ ret = -EIO; if ((unsigned long) data > _NSIG) break; - /* Set single stepping. */ - ptrace_set_bpt(child); + /* Mark single stepping. */ + child->thread_info->bpt_nsaved = -1; clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); wake_up_process(child); child->exit_code = data; diff -Nru a/arch/alpha/kernel/signal.c b/arch/alpha/kernel/signal.c --- a/arch/alpha/kernel/signal.c Mon Jun 9 23:16:12 2003 +++ b/arch/alpha/kernel/signal.c Mon Jun 9 23:16:12 2003 @@ -619,7 +619,10 @@ if (!oldset) oldset = ¤t->blocked; + /* This lets the debugger run, ... */ signr = get_signal_to_deliver(&info, regs, NULL); + /* ... so re-check the single stepping. */ + single_stepping |= ptrace_cancel_bpt(current); if (signr > 0) { /* Whee! Actually deliver the signal. */ diff -Nru a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c --- a/arch/alpha/kernel/smp.c Mon Jun 9 23:16:09 2003 +++ b/arch/alpha/kernel/smp.c Mon Jun 9 23:16:09 2003 @@ -417,12 +417,7 @@ /* Don't care about the contents of regs since we'll never reschedule the forked task. */ struct pt_regs regs; - int pid; - pid = do_fork(CLONE_VM|CLONE_IDLETASK, 0, ®s, 0, NULL, NULL); - if (pid < 0) - return NULL; - - return find_task_by_pid (pid); + return copy_process(CLONE_VM|CLONE_IDLETASK, 0, ®s, 0, NULL, NULL); } /* @@ -441,8 +436,10 @@ wish. We can't use kernel_thread since we must avoid rescheduling the child. */ idle = fork_by_hand(); - if (!idle) + if (IS_ERR(idle)) panic("failed fork for CPU %d", cpuid); + + wake_up_forked_process(idle); init_idle(idle, cpuid); unhash_process(idle); diff -Nru a/arch/alpha/kernel/sys_sio.c b/arch/alpha/kernel/sys_sio.c --- a/arch/alpha/kernel/sys_sio.c Mon Jun 9 23:16:05 2003 +++ b/arch/alpha/kernel/sys_sio.c Mon Jun 9 23:16:05 2003 @@ -85,10 +85,10 @@ sio_collect_irq_levels(void) { unsigned int level_bits = 0; - struct pci_dev *dev; + struct pci_dev *dev = NULL; /* Iterate through the devices, collecting IRQ levels. */ - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { if ((dev->class >> 16 == PCI_BASE_CLASS_BRIDGE) && (dev->class >> 8 != PCI_CLASS_BRIDGE_PCMCIA)) continue; diff -Nru a/arch/alpha/kernel/systbls.S b/arch/alpha/kernel/systbls.S --- a/arch/alpha/kernel/systbls.S Mon Jun 9 23:16:14 2003 +++ b/arch/alpha/kernel/systbls.S Mon Jun 9 23:16:14 2003 @@ -433,6 +433,16 @@ .quad sys_set_tid_address .quad sys_restart_syscall .quad sys_fadvise64 + .quad sys_timer_create + .quad sys_timer_settime /* 415 */ + .quad sys_timer_gettime + .quad sys_timer_getoverrun + .quad sys_timer_delete + .quad sys_clock_settime + .quad sys_clock_gettime /* 420 */ + .quad sys_clock_getres + .quad sys_clock_nanosleep + .quad sys_semtimedop .size sys_call_table, . - sys_call_table .type sys_call_table, @object diff -Nru a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c --- a/arch/alpha/kernel/traps.c Mon Jun 9 23:16:17 2003 +++ b/arch/alpha/kernel/traps.c Mon Jun 9 23:16:17 2003 @@ -485,9 +485,9 @@ " extwh %2,%3,%2\n" "3:\n" ".section __ex_table,\"a\"\n" - " .gprel32 1b\n" + " .long 1b - .\n" " lda %1,3b-1b(%0)\n" - " .gprel32 2b\n" + " .long 2b - .\n" " lda %2,3b-2b(%0)\n" ".previous" : "=r"(error), "=&r"(tmp1), "=&r"(tmp2) @@ -505,9 +505,9 @@ " extlh %2,%3,%2\n" "3:\n" ".section __ex_table,\"a\"\n" - " .gprel32 1b\n" + " .long 1b - .\n" " lda %1,3b-1b(%0)\n" - " .gprel32 2b\n" + " .long 2b - .\n" " lda %2,3b-2b(%0)\n" ".previous" : "=r"(error), "=&r"(tmp1), "=&r"(tmp2) @@ -525,9 +525,9 @@ " extqh %2,%3,%2\n" "3:\n" ".section __ex_table,\"a\"\n" - " .gprel32 1b\n" + " .long 1b - .\n" " lda %1,3b-1b(%0)\n" - " .gprel32 2b\n" + " .long 2b - .\n" " lda %2,3b-2b(%0)\n" ".previous" : "=r"(error), "=&r"(tmp1), "=&r"(tmp2) @@ -554,13 +554,13 @@ "4: stq_u %1,0(%5)\n" "5:\n" ".section __ex_table,\"a\"\n" - " .gprel32 1b\n" + " .long 1b - .\n" " lda %2,5b-1b(%0)\n" - " .gprel32 2b\n" + " .long 2b - .\n" " lda %1,5b-2b(%0)\n" - " .gprel32 3b\n" + " .long 3b - .\n" " lda $31,5b-3b(%0)\n" - " .gprel32 4b\n" + " .long 4b - .\n" " lda $31,5b-4b(%0)\n" ".previous" : "=r"(error), "=&r"(tmp1), "=&r"(tmp2), @@ -584,13 +584,13 @@ "4: stq_u %1,0(%5)\n" "5:\n" ".section __ex_table,\"a\"\n" - " .gprel32 1b\n" + " .long 1b - .\n" " lda %2,5b-1b(%0)\n" - " .gprel32 2b\n" + " .long 2b - .\n" " lda %1,5b-2b(%0)\n" - " .gprel32 3b\n" + " .long 3b - .\n" " lda $31,5b-3b(%0)\n" - " .gprel32 4b\n" + " .long 4b - .\n" " lda $31,5b-4b(%0)\n" ".previous" : "=r"(error), "=&r"(tmp1), "=&r"(tmp2), @@ -614,13 +614,13 @@ "4: stq_u %1,0(%5)\n" "5:\n" ".section __ex_table,\"a\"\n\t" - " .gprel32 1b\n" + " .long 1b - .\n" " lda %2,5b-1b(%0)\n" - " .gprel32 2b\n" + " .long 2b - .\n" " lda %1,5b-2b(%0)\n" - " .gprel32 3b\n" + " .long 3b - .\n" " lda $31,5b-3b(%0)\n" - " .gprel32 4b\n" + " .long 4b - .\n" " lda $31,5b-4b(%0)\n" ".previous" : "=r"(error), "=&r"(tmp1), "=&r"(tmp2), @@ -845,9 +845,9 @@ " extwh %2,%3,%2\n" "3:\n" ".section __ex_table,\"a\"\n" - " .gprel32 1b\n" + " .long 1b - .\n" " lda %1,3b-1b(%0)\n" - " .gprel32 2b\n" + " .long 2b - .\n" " lda %2,3b-2b(%0)\n" ".previous" : "=r"(error), "=&r"(tmp1), "=&r"(tmp2) @@ -865,9 +865,9 @@ " extlh %2,%3,%2\n" "3:\n" ".section __ex_table,\"a\"\n" - " .gprel32 1b\n" + " .long 1b - .\n" " lda %1,3b-1b(%0)\n" - " .gprel32 2b\n" + " .long 2b - .\n" " lda %2,3b-2b(%0)\n" ".previous" : "=r"(error), "=&r"(tmp1), "=&r"(tmp2) @@ -885,9 +885,9 @@ " extqh %2,%3,%2\n" "3:\n" ".section __ex_table,\"a\"\n" - " .gprel32 1b\n" + " .long 1b - .\n" " lda %1,3b-1b(%0)\n" - " .gprel32 2b\n" + " .long 2b - .\n" " lda %2,3b-2b(%0)\n" ".previous" : "=r"(error), "=&r"(tmp1), "=&r"(tmp2) @@ -905,9 +905,9 @@ " extlh %2,%3,%2\n" "3:\n" ".section __ex_table,\"a\"\n" - " .gprel32 1b\n" + " .long 1b - .\n" " lda %1,3b-1b(%0)\n" - " .gprel32 2b\n" + " .long 2b - .\n" " lda %2,3b-2b(%0)\n" ".previous" : "=r"(error), "=&r"(tmp1), "=&r"(tmp2) @@ -925,9 +925,9 @@ " extqh %2,%3,%2\n" "3:\n" ".section __ex_table,\"a\"\n" - " .gprel32 1b\n" + " .long 1b - .\n" " lda %1,3b-1b(%0)\n" - " .gprel32 2b\n" + " .long 2b - .\n" " lda %2,3b-2b(%0)\n" ".previous" : "=r"(error), "=&r"(tmp1), "=&r"(tmp2) @@ -954,13 +954,13 @@ "4: stq_u %1,0(%5)\n" "5:\n" ".section __ex_table,\"a\"\n" - " .gprel32 1b\n" + " .long 1b - .\n" " lda %2,5b-1b(%0)\n" - " .gprel32 2b\n" + " .long 2b - .\n" " lda %1,5b-2b(%0)\n" - " .gprel32 3b\n" + " .long 3b - .\n" " lda $31,5b-3b(%0)\n" - " .gprel32 4b\n" + " .long 4b - .\n" " lda $31,5b-4b(%0)\n" ".previous" : "=r"(error), "=&r"(tmp1), "=&r"(tmp2), @@ -988,13 +988,13 @@ "4: stq_u %1,0(%5)\n" "5:\n" ".section __ex_table,\"a\"\n" - " .gprel32 1b\n" + " .long 1b - .\n" " lda %2,5b-1b(%0)\n" - " .gprel32 2b\n" + " .long 2b - .\n" " lda %1,5b-2b(%0)\n" - " .gprel32 3b\n" + " .long 3b - .\n" " lda $31,5b-3b(%0)\n" - " .gprel32 4b\n" + " .long 4b - .\n" " lda $31,5b-4b(%0)\n" ".previous" : "=r"(error), "=&r"(tmp1), "=&r"(tmp2), @@ -1022,13 +1022,13 @@ "4: stq_u %1,0(%5)\n" "5:\n" ".section __ex_table,\"a\"\n\t" - " .gprel32 1b\n" + " .long 1b - .\n" " lda %2,5b-1b(%0)\n" - " .gprel32 2b\n" + " .long 2b - .\n" " lda %1,5b-2b(%0)\n" - " .gprel32 3b\n" + " .long 3b - .\n" " lda $31,5b-3b(%0)\n" - " .gprel32 4b\n" + " .long 4b - .\n" " lda $31,5b-4b(%0)\n" ".previous" : "=r"(error), "=&r"(tmp1), "=&r"(tmp2), diff -Nru a/arch/alpha/lib/Makefile b/arch/alpha/lib/Makefile --- a/arch/alpha/lib/Makefile Mon Jun 9 23:16:19 2003 +++ b/arch/alpha/lib/Makefile Mon Jun 9 23:16:19 2003 @@ -5,8 +5,6 @@ EXTRA_AFLAGS := $(CFLAGS) EXTRA_CFLAGS := -Werror -L_TARGET := lib.a - # Many of these routines have implementations tuned for ev6. # Choose them iff we're targeting ev6 specifically. ev6-$(CONFIG_ALPHA_EV6) := ev6- @@ -14,7 +12,7 @@ # Several make use of the cttz instruction introduced in ev67. ev67-$(CONFIG_ALPHA_EV67) := ev67- -obj-y = __divqu.o __remqu.o __divlu.o __remlu.o \ +lib-y = __divqu.o __remqu.o __divlu.o __remlu.o \ udelay.o \ $(ev6-y)memset.o \ $(ev6-y)memcpy.o \ @@ -43,7 +41,7 @@ fpreg.o \ callback_srm.o srm_puts.o srm_printk.o -obj-$(CONFIG_SMP) += dec_and_lock.o +lib-$(CONFIG_SMP) += dec_and_lock.o # The division routines are built from single source, with different defines. AFLAGS___divqu.o = -DDIV diff -Nru a/arch/alpha/lib/csum_partial_copy.c b/arch/alpha/lib/csum_partial_copy.c --- a/arch/alpha/lib/csum_partial_copy.c Mon Jun 9 23:16:12 2003 +++ b/arch/alpha/lib/csum_partial_copy.c Mon Jun 9 23:16:12 2003 @@ -46,7 +46,7 @@ "1: ldq_u %0,%2\n" \ "2:\n" \ ".section __ex_table,\"a\"\n" \ - " .gprel32 1b\n" \ + " .long 1b - .\n" \ " lda %0,2b-1b(%1)\n" \ ".previous" \ : "=r"(x), "=r"(__guu_err) \ @@ -61,7 +61,7 @@ "1: stq_u %2,%1\n" \ "2:\n" \ ".section __ex_table,\"a\"\n" \ - " .gprel32 1b" \ + " .long 1b - ." \ " lda $31,2b-1b(%0)\n" \ ".previous" \ : "=r"(__puu_err) \ diff -Nru a/arch/alpha/lib/memmove.S b/arch/alpha/lib/memmove.S --- a/arch/alpha/lib/memmove.S Mon Jun 9 23:16:12 2003 +++ b/arch/alpha/lib/memmove.S Mon Jun 9 23:16:12 2003 @@ -12,6 +12,15 @@ .text .align 4 + .globl bcopy + .ent bcopy +bcopy: + mov $16,$0 + mov $17,$16 + mov $0,$17 + .end bcopy + + .align 4 .globl memmove .ent memmove memmove: diff -Nru a/arch/arm/common/Makefile b/arch/arm/common/Makefile --- a/arch/arm/common/Makefile Mon Jun 9 23:16:10 2003 +++ b/arch/arm/common/Makefile Mon Jun 9 23:16:10 2003 @@ -2,7 +2,7 @@ # Makefile for the linux kernel. # -obj-$(CONFIG_SA1111) += sa1111.o sa1111-pcibuf.o sa1111-pcipool.o - +obj-y += platform.o +obj-$(CONFIG_SA1111) += sa1111.o sa1111-pcibuf.o sa1111-pcipool.o obj-$(CONFIG_PCI_HOST_PLX90X0) += plx90x0.o obj-$(CONFIG_PCI_HOST_VIA82C505) += via82c505.o diff -Nru a/arch/arm/common/platform.c b/arch/arm/common/platform.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/common/platform.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,35 @@ +#include <linux/ioport.h> +#include <linux/device.h> +#include <linux/init.h> + +int __init platform_add_device(struct platform_device *dev) +{ + int i; + + for (i = 0; i < dev->num_resources; i++) { + struct resource *r = &dev->resource[i]; + + r->name = dev->dev.name; + + if (r->flags & IORESOURCE_MEM && + request_resource(&iomem_resource, r)) { + printk(KERN_ERR + "%s%d: failed to claim resource %d\n", + dev->name, dev->id, i); + break; + } + } + if (i == dev->num_resources) + platform_device_register(dev); + return 0; +} + +int __init platform_add_devices(struct platform_device **devs, int num) +{ + int i; + + for (i = 0; i < num; i++) + platform_add_device(devs[i]); + + return 0; +} diff -Nru a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c --- a/arch/arm/common/sa1111.c Mon Jun 9 23:16:18 2003 +++ b/arch/arm/common/sa1111.c Mon Jun 9 23:16:18 2003 @@ -42,7 +42,7 @@ */ struct sa1111 { struct device *dev; - struct resource res; + unsigned long phys; int irq; spinlock_t lock; void *base; @@ -60,7 +60,6 @@ }, .skpcr_mask = SKPCR_UCLKEN, .devid = SA1111_DEVID_USB, - .dma_mask = 0xffffffffLL, .irq = { IRQ_USBPWR, IRQ_HCIM, @@ -470,6 +469,17 @@ #ifdef CONFIG_ARCH_SA1100 +static u32 sa1111_dma_mask[] = { + ~0, + ~(1 << 20), + ~(1 << 23), + ~(1 << 24), + ~(1 << 25), + ~(1 << 20), + ~(1 << 20), + 0, +}; + /* * Configure the SA1111 shared memory controller. */ @@ -483,26 +493,43 @@ smcr |= SMCR_CLAT; sa1111_writel(smcr, sachip->base + SA1111_SMCR); + + /* + * Now clear the bits in the DMA mask to work around the SA1111 + * DMA erratum (Intel StrongARM SA-1111 Microprocessor Companion + * Chip Specification Update, June 2000, Erratum #7). + */ + if (sachip->dev->dma_mask) + *sachip->dev->dma_mask &= sa1111_dma_mask[drac >> 2]; } #endif static void -sa1111_init_one_child(struct sa1111 *sachip, struct sa1111_dev *sadev, unsigned int offset) +sa1111_init_one_child(struct sa1111 *sachip, struct resource *parent, + struct sa1111_dev *sadev, unsigned int offset) { snprintf(sadev->dev.bus_id, sizeof(sadev->dev.bus_id), "%4.4x", offset); + /* + * If the parent device has a DMA mask associated with it, + * propagate it down to the children. + */ + if (sachip->dev->dma_mask) { + sadev->dma_mask = *sachip->dev->dma_mask; + sadev->dev.dma_mask = &sadev->dma_mask; + } + sadev->dev.parent = sachip->dev; sadev->dev.bus = &sa1111_bus_type; - sadev->dev.dma_mask = &sadev->dma_mask; - sadev->res.start = sachip->res.start + offset; + sadev->res.start = sachip->phys + offset; sadev->res.end = sadev->res.start + 511; sadev->res.name = sadev->dev.name; sadev->res.flags = IORESOURCE_MEM; sadev->mapbase = sachip->base + offset; - if (request_resource(&sachip->res, &sadev->res)) { + if (request_resource(parent, &sadev->res)) { printk("SA1111: failed to allocate resource for %s\n", sadev->res.name); return; @@ -524,7 +551,7 @@ * %0 successful. */ static int __init -__sa1111_probe(struct device *me, unsigned long phys_addr, int irq) +__sa1111_probe(struct device *me, struct resource *mem, int irq) { struct sa1111 *sachip; unsigned long id; @@ -542,24 +569,17 @@ sachip->dev = me; dev_set_drvdata(sachip->dev, sachip); - sachip->res.name = me->name; - sachip->res.start = phys_addr; - sachip->res.end = phys_addr + 0x2000; + sachip->phys = mem->start; sachip->irq = irq; - if (request_resource(&iomem_resource, &sachip->res)) { - ret = -EBUSY; - goto out; - } - /* * Map the whole region. This also maps the * registers for our children. */ - sachip->base = ioremap(phys_addr, PAGE_SIZE * 2); + sachip->base = ioremap(mem->start, PAGE_SIZE * 2); if (!sachip->base) { ret = -ENOMEM; - goto release; + goto out; } /* @@ -611,9 +631,11 @@ * The interrupt controller must be initialised before any * other device to ensure that the interrupts are available. */ - int_dev.irq[0] = irq; - sa1111_init_one_child(sachip, &int_dev, SA1111_INTC); - sa1111_init_irq(&int_dev); + if (irq != NO_IRQ) { + int_dev.irq[0] = irq; + sa1111_init_one_child(sachip, mem, &int_dev, SA1111_INTC); + sa1111_init_irq(&int_dev); + } g_sa1111 = sachip; @@ -626,14 +648,12 @@ for (i = 0; i < ARRAY_SIZE(devs); i++) if (has_devs & (1 << i)) - sa1111_init_one_child(sachip, devs[i], dev_offset[i]); + sa1111_init_one_child(sachip, mem, devs[i], dev_offset[i]); return 0; unmap: iounmap(sachip->base); - release: - release_resource(&sachip->res); out: kfree(sachip); return ret; @@ -649,7 +669,6 @@ } iounmap(sachip->base); - release_resource(&sachip->res); kfree(sachip); } @@ -874,7 +893,17 @@ static int sa1111_probe(struct device *dev) { - return -ENODEV; + struct platform_device *pdev = to_platform_device(dev); + struct resource *mem = NULL, *irq = NULL; + int i; + + for (i = 0; i < pdev->num_resources; i++) { + if (pdev->resource[i].flags & IORESOURCE_MEM) + mem = &pdev->resource[i]; + if (pdev->resource[i].flags & IORESOURCE_IRQ) + irq = &pdev->resource[i]; + } + return __sa1111_probe(dev, mem, irq ? irq->start : NO_IRQ); } static int sa1111_remove(struct device *dev) @@ -903,7 +932,7 @@ */ static struct device_driver sa1111_device_driver = { .name = "sa1111", - .bus = &system_bus_type, + .bus = &platform_bus_type, .probe = sa1111_probe, .remove = sa1111_remove, .suspend = sa1111_suspend, @@ -920,29 +949,6 @@ } arch_initcall(sa1111_driver_init); - -static struct sys_device sa1111_device = { - .name = "SA1111", - .id = 0, - .root = NULL, - .dev = { - .name = "Intel Corporation SA1111", - .driver = &sa1111_device_driver, - }, -}; - -int sa1111_init(unsigned long phys, unsigned int irq) -{ - int ret; - - snprintf(sa1111_device.dev.bus_id, sizeof(sa1111_device.dev.bus_id), "%8.8lx", phys); - - ret = sys_device_register(&sa1111_device); - if (ret) - printk("sa1111 device_register failed: %d\n", ret); - - return __sa1111_probe(&sa1111_device.dev, phys, irq); -} /* * Get the parent device driver (us) structure diff -Nru a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c --- a/arch/arm/kernel/bios32.c Mon Jun 9 23:16:10 2003 +++ b/arch/arm/kernel/bios32.c Mon Jun 9 23:16:10 2003 @@ -22,9 +22,9 @@ void pcibios_report_status(u_int status_mask, int warn) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { u16 status; /* diff -Nru a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c --- a/arch/arm/kernel/process.c Mon Jun 9 23:16:18 2003 +++ b/arch/arm/kernel/process.c Mon Jun 9 23:16:18 2003 @@ -239,7 +239,7 @@ #define ll_alloc_task_struct() ((struct thread_info *) __get_free_pages(GFP_KERNEL,1)) #define ll_free_task_struct(p) free_pages((unsigned long)(p),1) -struct thread_info *alloc_thread_info(void) +struct thread_info *alloc_thread_info(struct task_struct *task) { struct thread_info *thread = NULL; diff -Nru a/arch/arm/lib/Makefile b/arch/arm/lib/Makefile --- a/arch/arm/lib/Makefile Mon Jun 9 23:16:15 2003 +++ b/arch/arm/lib/Makefile Mon Jun 9 23:16:15 2003 @@ -4,9 +4,7 @@ # Copyright (C) 1995-2000 Russell King # -L_TARGET := lib.a - -obj-y := backtrace.o changebit.o csumipv6.o csumpartial.o \ +lib-y := backtrace.o changebit.o csumipv6.o csumpartial.o \ csumpartialcopy.o csumpartialcopyuser.o clearbit.o \ copy_page.o delay.o findbit.o memchr.o memcpy.o \ memset.o memzero.o setbit.o strncpy_from_user.o \ @@ -14,17 +12,15 @@ testclearbit.o testsetbit.o uaccess.o getuser.o \ putuser.o ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \ ucmpdi2.o udivdi3.o lib1funcs.o div64.o -obj-m := -obj-n := -obj-arc := ecard.o io-acorn.o floppydma.o -obj-rpc := ecard.o io-acorn.o floppydma.o -obj-clps7500 := io-acorn.o -obj-l7200 := io-acorn.o -obj-shark := io-shark.o -obj-edb7211 := io-acorn.o +lib-arc := ecard.o io-acorn.o floppydma.o +lib-rpc := ecard.o io-acorn.o floppydma.o +lib-clps7500 := io-acorn.o +lib-l7200 := io-acorn.o +lib-shark := io-shark.o +lib-edb7211 := io-acorn.o -obj-y += $(obj-$(MACHINE)) +lib-y += $(lib-$(MACHINE)) ifeq ($(CONFIG_CPU_32v3),y) v3 := y @@ -34,10 +30,10 @@ v4 := y endif -obj-y += io-readsb.o io-writesb.o -obj-$(v3) += io-readsw-armv3.o io-writesw-armv3.o io-readsl-armv3.o -obj-$(v4) += io-readsw-armv4.o io-writesw-armv4.o io-readsl-armv4.o -obj-y += io-writesl.o +lib-y += io-readsb.o io-writesb.o +lib-$(v3) += io-readsw-armv3.o io-writesw-armv3.o io-readsl-armv3.o +lib-$(v4) += io-readsw-armv4.o io-writesw-armv4.o io-readsl-armv4.o +lib-y += io-writesl.o $(obj)/csumpartialcopy.o: $(obj)/csumpartialcopygeneric.S $(obj)/csumpartialcopyuser.o: $(obj)/csumpartialcopygeneric.S diff -Nru a/arch/arm/lib/putuser.S b/arch/arm/lib/putuser.S --- a/arch/arm/lib/putuser.S Mon Jun 9 23:16:18 2003 +++ b/arch/arm/lib/putuser.S Mon Jun 9 23:16:18 2003 @@ -31,11 +31,11 @@ .global __put_user_1 __put_user_1: - bic r2, sp, #0x1f00 - bic r2, r2, #0x00ff - ldr r2, [r2, #TI_ADDR_LIMIT] - sub r2, r2, #1 - cmp r0, r2 + bic ip, sp, #0x1f00 + bic ip, ip, #0x00ff + ldr ip, [ip, #TI_ADDR_LIMIT] + sub ip, ip, #1 + cmp r0, ip 1: strlsbt r1, [r0] movls r0, #0 movls pc, lr @@ -43,17 +43,17 @@ .global __put_user_2 __put_user_2: - bic r2, sp, #0x1f00 - bic r2, r2, #0x00ff - ldr r2, [r2, #TI_ADDR_LIMIT] - sub r2, r2, #2 - cmp r0, r2 - movls r2, r1, lsr #8 + bic ip, sp, #0x1f00 + bic ip, ip, #0x00ff + ldr ip, [ip, #TI_ADDR_LIMIT] + sub ip, ip, #2 + cmp r0, ip + movls ip, r1, lsr #8 #ifndef __ARMEB__ 2: strlsbt r1, [r0], #1 -3: strlsbt r2, [r0] +3: strlsbt ip, [r0] #else -2: strlsbt r2, [r0], #1 +2: strlsbt ip, [r0], #1 3: strlsbt r1, [r0] #endif movls r0, #0 @@ -62,11 +62,11 @@ .global __put_user_4 __put_user_4: - bic r2, sp, #0x1f00 - bic r2, r2, #0x00ff - ldr r2, [r2, #TI_ADDR_LIMIT] - sub r2, r2, #4 - cmp r0, r2 + bic ip, sp, #0x1f00 + bic ip, ip, #0x00ff + ldr ip, [ip, #TI_ADDR_LIMIT] + sub ip, ip, #4 + cmp r0, ip 4: strlst r1, [r0] movls r0, #0 movls pc, lr diff -Nru a/arch/arm/mach-footbridge/isa-irq.c b/arch/arm/mach-footbridge/isa-irq.c --- a/arch/arm/mach-footbridge/isa-irq.c Mon Jun 9 23:16:16 2003 +++ b/arch/arm/mach-footbridge/isa-irq.c Mon Jun 9 23:16:16 2003 @@ -84,10 +84,6 @@ .unmask = isa_unmask_pic_hi_irq, }; -static void no_action(int irq, void *dev_id, struct pt_regs *regs) -{ -} - static void isa_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) { diff -Nru a/arch/arm/mach-integrator/Makefile b/arch/arm/mach-integrator/Makefile --- a/arch/arm/mach-integrator/Makefile Mon Jun 9 23:16:18 2003 +++ b/arch/arm/mach-integrator/Makefile Mon Jun 9 23:16:18 2003 @@ -4,10 +4,7 @@ # Object file lists. -obj-y := arch.o irq.o mm.o time.o -obj-m := -obj-n := -obj- := +obj-y := core.o time.o obj-$(CONFIG_LEDS) += leds.o obj-$(CONFIG_PCI) += pci_v3.o pci.o diff -Nru a/arch/arm/mach-integrator/arch.c b/arch/arm/mach-integrator/arch.c --- a/arch/arm/mach-integrator/arch.c Mon Jun 9 23:16:15 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,40 +0,0 @@ -/* - * linux/arch/arm/mach-integrator/arch.c - * - * Copyright (C) 2000 Deep Blue Solutions Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include <linux/config.h> -#include <linux/types.h> -#include <linux/init.h> - -#include <asm/hardware.h> -#include <asm/irq.h> -#include <asm/setup.h> -#include <asm/mach-types.h> - -#include <asm/mach/arch.h> - -extern void integrator_map_io(void); -extern void integrator_init_irq(void); - -MACHINE_START(INTEGRATOR, "ARM-Integrator") - MAINTAINER("ARM Ltd/Deep Blue Solutions Ltd") - BOOT_MEM(0x00000000, 0x16000000, 0xf1600000) - BOOT_PARAMS(0x00000100) - MAPIO(integrator_map_io) - INITIRQ(integrator_init_irq) -MACHINE_END diff -Nru a/arch/arm/mach-integrator/core.c b/arch/arm/mach-integrator/core.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm/mach-integrator/core.c Mon Jun 9 23:16:15 2003 @@ -0,0 +1,135 @@ +/* + * linux/arch/arm/mach-integrator/arch.c + * + * Copyright (C) 2000 Deep Blue Solutions Ltd + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/config.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/list.h> +#include <linux/device.h> +#include <linux/slab.h> +#include <linux/string.h> + +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/setup.h> +#include <asm/mach-types.h> + +#include <asm/mach/arch.h> +#include <asm/mach/irq.h> +#include <asm/mach/map.h> + +/* + * All IO addresses are mapped onto VA 0xFFFx.xxxx, where x.xxxx + * is the (PA >> 12). + * + * Setup a VA for the Integrator interrupt controller (for header #0, + * just for now). + */ +#define VA_IC_BASE IO_ADDRESS(INTEGRATOR_IC_BASE) +#define VA_CMIC_BASE IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_IC_OFFSET + +/* + * Logical Physical + * e8000000 40000000 PCI memory PHYS_PCI_MEM_BASE (max 512M) + * ec000000 61000000 PCI config space PHYS_PCI_CONFIG_BASE (max 16M) + * ed000000 62000000 PCI V3 regs PHYS_PCI_V3_BASE (max 64k) + * ee000000 60000000 PCI IO PHYS_PCI_IO_BASE (max 16M) + * ef000000 Cache flush + * f1000000 10000000 Core module registers + * f1100000 11000000 System controller registers + * f1200000 12000000 EBI registers + * f1300000 13000000 Counter/Timer + * f1400000 14000000 Interrupt controller + * f1500000 15000000 RTC + * f1600000 16000000 UART 0 + * f1700000 17000000 UART 1 + * f1a00000 1a000000 Debug LEDs + * f1b00000 1b000000 GPIO + */ + +static struct map_desc integrator_io_desc[] __initdata = { + { IO_ADDRESS(INTEGRATOR_HDR_BASE), INTEGRATOR_HDR_BASE, SZ_4K, MT_DEVICE }, + { IO_ADDRESS(INTEGRATOR_SC_BASE), INTEGRATOR_SC_BASE, SZ_4K, MT_DEVICE }, + { IO_ADDRESS(INTEGRATOR_EBI_BASE), INTEGRATOR_EBI_BASE, SZ_4K, MT_DEVICE }, + { IO_ADDRESS(INTEGRATOR_CT_BASE), INTEGRATOR_CT_BASE, SZ_4K, MT_DEVICE }, + { IO_ADDRESS(INTEGRATOR_IC_BASE), INTEGRATOR_IC_BASE, SZ_4K, MT_DEVICE }, + { IO_ADDRESS(INTEGRATOR_RTC_BASE), INTEGRATOR_RTC_BASE, SZ_4K, MT_DEVICE }, + { IO_ADDRESS(INTEGRATOR_UART0_BASE), INTEGRATOR_UART0_BASE, SZ_4K, MT_DEVICE }, + { IO_ADDRESS(INTEGRATOR_UART1_BASE), INTEGRATOR_UART1_BASE, SZ_4K, MT_DEVICE }, + { IO_ADDRESS(INTEGRATOR_DBG_BASE), INTEGRATOR_DBG_BASE, SZ_4K, MT_DEVICE }, + { IO_ADDRESS(INTEGRATOR_GPIO_BASE), INTEGRATOR_GPIO_BASE, SZ_4K, MT_DEVICE }, + { PCI_MEMORY_VADDR, PHYS_PCI_MEM_BASE, SZ_16M, MT_DEVICE }, + { PCI_CONFIG_VADDR, PHYS_PCI_CONFIG_BASE, SZ_16M, MT_DEVICE }, + { PCI_V3_VADDR, PHYS_PCI_V3_BASE, SZ_64K, MT_DEVICE }, + { PCI_IO_VADDR, PHYS_PCI_IO_BASE, SZ_64K, MT_DEVICE } +}; + +static void __init integrator_map_io(void) +{ + iotable_init(integrator_io_desc, ARRAY_SIZE(integrator_io_desc)); +} + +#define ALLPCI ( (1 << IRQ_PCIINT0) | (1 << IRQ_PCIINT1) | (1 << IRQ_PCIINT2) | (1 << IRQ_PCIINT3) ) + +static void sc_mask_irq(unsigned int irq) +{ + writel(1 << irq, VA_IC_BASE + IRQ_ENABLE_CLEAR); +} + +static void sc_unmask_irq(unsigned int irq) +{ + writel(1 << irq, VA_IC_BASE + IRQ_ENABLE_SET); +} + +static struct irqchip sc_chip = { + .ack = sc_mask_irq, + .mask = sc_mask_irq, + .unmask = sc_unmask_irq, +}; + +static void __init integrator_init_irq(void) +{ + unsigned int i; + + /* Disable all interrupts initially. */ + /* Do the core module ones */ + writel(-1, VA_CMIC_BASE + IRQ_ENABLE_CLEAR); + + /* do the header card stuff next */ + writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR); + writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR); + + for (i = 0; i < NR_IRQS; i++) { + if (((1 << i) && INTEGRATOR_SC_VALID_INT) != 0) { + set_irq_chip(i, &sc_chip); + set_irq_handler(i, do_level_IRQ); + set_irq_flags(i, IRQF_VALID | IRQF_PROBE); + } + } +} + +MACHINE_START(INTEGRATOR, "ARM-Integrator") + MAINTAINER("ARM Ltd/Deep Blue Solutions Ltd") + BOOT_MEM(0x00000000, 0x16000000, 0xf1600000) + BOOT_PARAMS(0x00000100) + MAPIO(integrator_map_io) + INITIRQ(integrator_init_irq) +MACHINE_END diff -Nru a/arch/arm/mach-integrator/irq.c b/arch/arm/mach-integrator/irq.c --- a/arch/arm/mach-integrator/irq.c Mon Jun 9 23:16:20 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,76 +0,0 @@ -/* - * linux/arch/arm/mach-integrator/irq.c - * - * Copyright (C) 1999 ARM Limited - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the 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/list.h> - -#include <asm/hardware.h> -#include <asm/irq.h> -#include <asm/io.h> - -#include <asm/mach/irq.h> - -/* - * All IO addresses are mapped onto VA 0xFFFx.xxxx, where x.xxxx - * is the (PA >> 12). - * - * Setup a VA for the Integrator interrupt controller (for header #0, - * just for now). - */ -#define VA_IC_BASE IO_ADDRESS(INTEGRATOR_IC_BASE) -#define VA_CMIC_BASE IO_ADDRESS(INTEGRATOR_HDR_BASE) + INTEGRATOR_HDR_IC_OFFSET - -#define ALLPCI ( (1 << IRQ_PCIINT0) | (1 << IRQ_PCIINT1) | (1 << IRQ_PCIINT2) | (1 << IRQ_PCIINT3) ) - -static void sc_mask_irq(unsigned int irq) -{ - __raw_writel(1 << irq, VA_IC_BASE + IRQ_ENABLE_CLEAR); -} - -static void sc_unmask_irq(unsigned int irq) -{ - __raw_writel(1 << irq, VA_IC_BASE + IRQ_ENABLE_SET); -} - -static struct irqchip sc_chip = { - .ack = sc_mask_irq, - .mask = sc_mask_irq, - .unmask = sc_unmask_irq, -}; - -void __init integrator_init_irq(void) -{ - unsigned int i; - - /* Disable all interrupts initially. */ - /* Do the core module ones */ - __raw_writel(-1, VA_CMIC_BASE + IRQ_ENABLE_CLEAR); - - /* do the header card stuff next */ - __raw_writel(-1, VA_IC_BASE + IRQ_ENABLE_CLEAR); - __raw_writel(-1, VA_IC_BASE + FIQ_ENABLE_CLEAR); - - for (i = 0; i < NR_IRQS; i++) { - if (((1 << i) && INTEGRATOR_SC_VALID_INT) != 0) { - set_irq_chip(i, &sc_chip); - set_irq_handler(i, do_level_IRQ); - set_irq_flags(i, IRQF_VALID | IRQF_PROBE); - } - } -} diff -Nru a/arch/arm/mach-integrator/mm.c b/arch/arm/mach-integrator/mm.c --- a/arch/arm/mach-integrator/mm.c Mon Jun 9 23:16:20 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,70 +0,0 @@ -/* - * linux/arch/arm/mach-integrator/mm.c - * - * Extra MM routines for the ARM Integrator board - * - * Copyright (C) 1999,2000 Arm Limited - * Copyright (C) 2000 Deep Blue Solutions Ltd - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ -#include <linux/kernel.h> -#include <linux/init.h> - -#include <asm/hardware.h> -#include <asm/io.h> - -#include <asm/mach/map.h> - -/* - * Logical Physical - * e8000000 40000000 PCI memory PHYS_PCI_MEM_BASE (max 512M) - * ec000000 61000000 PCI config space PHYS_PCI_CONFIG_BASE (max 16M) - * ed000000 62000000 PCI V3 regs PHYS_PCI_V3_BASE (max 64k) - * ee000000 60000000 PCI IO PHYS_PCI_IO_BASE (max 16M) - * ef000000 Cache flush - * f1000000 10000000 Core module registers - * f1100000 11000000 System controller registers - * f1200000 12000000 EBI registers - * f1300000 13000000 Counter/Timer - * f1400000 14000000 Interrupt controller - * f1500000 15000000 RTC - * f1600000 16000000 UART 0 - * f1700000 17000000 UART 1 - * f1a00000 1a000000 Debug LEDs - * f1b00000 1b000000 GPIO - */ - -static struct map_desc integrator_io_desc[] __initdata = { - { IO_ADDRESS(INTEGRATOR_HDR_BASE), INTEGRATOR_HDR_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_SC_BASE), INTEGRATOR_SC_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_EBI_BASE), INTEGRATOR_EBI_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_CT_BASE), INTEGRATOR_CT_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_IC_BASE), INTEGRATOR_IC_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_RTC_BASE), INTEGRATOR_RTC_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_UART0_BASE), INTEGRATOR_UART0_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_UART1_BASE), INTEGRATOR_UART1_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_DBG_BASE), INTEGRATOR_DBG_BASE, SZ_4K, MT_DEVICE }, - { IO_ADDRESS(INTEGRATOR_GPIO_BASE), INTEGRATOR_GPIO_BASE, SZ_4K, MT_DEVICE }, - { PCI_MEMORY_VADDR, PHYS_PCI_MEM_BASE, SZ_16M, MT_DEVICE }, - { PCI_CONFIG_VADDR, PHYS_PCI_CONFIG_BASE, SZ_16M, MT_DEVICE }, - { PCI_V3_VADDR, PHYS_PCI_V3_BASE, SZ_64K, MT_DEVICE }, - { PCI_IO_VADDR, PHYS_PCI_IO_BASE, SZ_64K, MT_DEVICE } -}; - -void __init integrator_map_io(void) -{ - iotable_init(integrator_io_desc, ARRAY_SIZE(integrator_io_desc)); -} diff -Nru a/arch/arm/mach-integrator/pci_v3.c b/arch/arm/mach-integrator/pci_v3.c --- a/arch/arm/mach-integrator/pci_v3.c Mon Jun 9 23:16:15 2003 +++ b/arch/arm/mach-integrator/pci_v3.c Mon Jun 9 23:16:15 2003 @@ -441,7 +441,7 @@ return 1; } -static void v3_irq(int irq, void *devid, struct pt_regs *regs) +static irqreturn_t v3_irq(int irq, void *devid, struct pt_regs *regs) { #ifdef CONFIG_DEBUG_LL unsigned long pc = instruction_pointer(regs); @@ -469,6 +469,7 @@ printascii(buf); } #endif + return IRQ_HANDLED; } int __init pci_v3_setup(int nr, struct pci_sys_data *sys) diff -Nru a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c --- a/arch/arm/mach-pxa/lubbock.c Mon Jun 9 23:16:10 2003 +++ b/arch/arm/mach-pxa/lubbock.c Mon Jun 9 23:16:10 2003 @@ -88,9 +88,36 @@ set_irq_type(IRQ_GPIO(0), IRQT_FALLING); } +static struct resource sa1111_resources[] = { + [0] = { + .start = 0x10000000, + .end = 0x10001fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = LUBBOCK_SA1111_IRQ, + .end = LUBBOCK_SA1111_IRQ, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device sa1111_device = { + .name = "sa1111", + .id = 0, + .dev = { + .name = "Intel Corporation SA1111", + }, + .num_resources = ARRAY_SIZE(sa1111_resources), + .resource = sa1111_resources, +}; + +static struct platform_device *devices[] __initdata = { + &sa1111_device, +}; + static int __init lubbock_init(void) { - return sa1111_init(0x10000000, LUBBOCK_SA1111_IRQ); + return platform_add_devices(devices, ARRAY_SIZE(devices)); } subsys_initcall(lubbock_init); diff -Nru a/arch/arm/mach-sa1100/adsbitsy.c b/arch/arm/mach-sa1100/adsbitsy.c --- a/arch/arm/mach-sa1100/adsbitsy.c Mon Jun 9 23:16:05 2003 +++ b/arch/arm/mach-sa1100/adsbitsy.c Mon Jun 9 23:16:05 2003 @@ -27,6 +27,36 @@ #include "generic.h" +static struct resource sa1111_resources[] = { + [0] = { + .start = 0x18000000, + .end = 0x18001fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_GPIO0, + .end = IRQ_GPIO0, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 sa1111_dmamask = 0xffffffffUL; + +static struct platform_device sa1111_device = { + .name = "sa1111", + .id = 0, + .dev = { + .name = "Intel Corporation SA1111", + .dma_mask = &sa1111_dmamask, + }, + .num_resources = ARRAY_SIZE(sa1111_resources), + .resource = sa1111_resources, +}; + +static struct platform_device *devices[] __initdata = { + &sa1111_device, +}; + static int __init adsbitsy_init(void) { int ret; @@ -50,7 +80,7 @@ /* * Probe for SA1111. */ - ret = sa1111_init(0x18000000, IRQ_GPIO0); + ret = platform_add_devices(devices, ARRAY_SIZE(devices)); if (ret < 0) return ret; diff -Nru a/arch/arm/mach-sa1100/badge4.c b/arch/arm/mach-sa1100/badge4.c --- a/arch/arm/mach-sa1100/badge4.c Mon Jun 9 23:16:07 2003 +++ b/arch/arm/mach-sa1100/badge4.c Mon Jun 9 23:16:07 2003 @@ -35,6 +35,36 @@ #include "generic.h" +static struct resource sa1111_resources[] = { + [0] = { + .start = BADGE4_SA1111_BASE, + .end = BADGE4_SA1111_BASE + 0x00001fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = BADGE4_IRQ_GPIO_SA1111, + .end = BADGE4_IRQ_GPIO_SA1111, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 sa1111_dmamask = 0xffffffffUL; + +static struct platform_device sa1111_device = { + .name = "sa1111", + .id = 0, + .dev = { + .name = "Intel Corporation SA1111", + .dma_mask = &sa1111_dmamask; + }, + .num_resources = ARRAY_SIZE(sa1111_resources), + .resource = sa1111_resources, +}; + +static struct platform_device *devices[] __initdata = { + &sa1111_device, +}; + static int __init badge4_sa1111_init(void) { /* @@ -46,7 +76,7 @@ /* * Probe for SA1111. */ - return sa1111_init(BADGE4_SA1111_BASE, BADGE4_IRQ_GPIO_SA1111); + return platform_add_devices(devices, ARRAY_SIZE(devices)); } diff -Nru a/arch/arm/mach-sa1100/dma.c b/arch/arm/mach-sa1100/dma.c --- a/arch/arm/mach-sa1100/dma.c Mon Jun 9 23:16:06 2003 +++ b/arch/arm/mach-sa1100/dma.c Mon Jun 9 23:16:06 2003 @@ -42,7 +42,7 @@ static spinlock_t dma_list_lock; -static void dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs) { dma_regs_t *dma_regs = dev_id; sa1100_dma_t *dma = dma_chan + (((u_int)dma_regs >> 5) & 7); @@ -60,6 +60,7 @@ if (status & DCSR_DONEB) dma->callback(dma->data); } + return IRQ_HANDLED; } diff -Nru a/arch/arm/mach-sa1100/generic.c b/arch/arm/mach-sa1100/generic.c --- a/arch/arm/mach-sa1100/generic.c Mon Jun 9 23:16:09 2003 +++ b/arch/arm/mach-sa1100/generic.c Mon Jun 9 23:16:09 2003 @@ -16,11 +16,13 @@ #include <linux/delay.h> #include <linux/pm.h> #include <linux/cpufreq.h> +#include <linux/ioport.h> #include <asm/hardware.h> #include <asm/system.h> #include <asm/pgtable.h> #include <asm/mach/map.h> +#include <asm/irq.h> #include "generic.h" @@ -128,13 +130,88 @@ PMCR = PMCR_SF; } +static struct resource sa11x0udc_resources[] = { + [0] = { + .start = 0x80000000, + .end = 0x8000ffff, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device sa11x0udc_device = { + .name = "sa11x0-udc", + .id = 0, + .dev = { + .name = "Intel Corporation SA11x0 [UDC]", + }, + .num_resources = ARRAY_SIZE(sa11x0udc_resources), + .resource = sa11x0udc_resources, +}; + +static struct resource sa11x0mcp_resources[] = { + [0] = { + .start = 0x80060000, + .end = 0x8006ffff, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device sa11x0mcp_device = { + .name = "sa11x0-mcp", + .id = 0, + .dev = { + .name = "Intel Corporation SA11x0 [MCP]", + }, + .num_resources = ARRAY_SIZE(sa11x0mcp_resources), + .resource = sa11x0mcp_resources, +}; + +static struct resource sa11x0fb_resources[] = { + [0] = { + .start = 0xb0100000, + .end = 0xb010ffff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_LCD, + .end = IRQ_LCD, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device sa11x0fb_device = { + .name = "sa11x0-fb", + .id = 0, + .dev = { + .name = "Intel Corporation SA11x0 [LCD]", + }, + .num_resources = ARRAY_SIZE(sa11x0fb_resources), + .resource = sa11x0fb_resources, +}; + +static struct platform_device sa11x0pcmcia_device = { + .name = "sa11x0-pcmcia", + .id = 0, + .dev = { + .name = "Intel Corporation SA11x0 [PCMCIA]", + }, +}; + +static struct platform_device *sa11x0_devices[] __initdata = { + &sa11x0udc_device, + &sa11x0mcp_device, + &sa11x0pcmcia_device, + &sa11x0fb_device, +}; + static int __init sa1100_init(void) { pm_power_off = sa1100_power_off; - return 0; + + return platform_add_devices(sa11x0_devices, ARRAY_SIZE(sa11x0_devices)); } -core_initcall(sa1100_init); +arch_initcall(sa1100_init); void (*sa1100fb_backlight_power)(int on); void (*sa1100fb_lcd_power)(int on); diff -Nru a/arch/arm/mach-sa1100/graphicsmaster.c b/arch/arm/mach-sa1100/graphicsmaster.c --- a/arch/arm/mach-sa1100/graphicsmaster.c Mon Jun 9 23:16:10 2003 +++ b/arch/arm/mach-sa1100/graphicsmaster.c Mon Jun 9 23:16:10 2003 @@ -24,6 +24,36 @@ #include "generic.h" +static struct resource sa1111_resources[] = { + [0] = { + .start = 0x18000000, + .end = 0x18001fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = ADS_EXT_IRQ(0), + .end = ADS_EXT_IRQ(0), + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 sa1111_dmamask = 0xffffffffUL; + +static struct platform_device sa1111_device = { + .name = "sa1111", + .id = 0, + .dev = { + .name = "Intel Corporation SA1111", + .dma_mask = &sa1111_dmamask, + }, + .num_resources = ARRAY_SIZE(sa1111_resources), + .resource = sa1111_resources, +}; + +static struct platform_device *devices[] __initdata = { + &sa1111_device, +}; + static int __init graphicsmaster_init(void) { int ret; @@ -40,7 +70,7 @@ /* * Probe for SA1111. */ - ret = sa1111_init(0x18000000, ADS_EXT_IRQ(0)); + ret = platform_add_devices(devices, ARRAY_SIZE(devices)); if (ret < 0) return ret; diff -Nru a/arch/arm/mach-sa1100/jornada720.c b/arch/arm/mach-sa1100/jornada720.c --- a/arch/arm/mach-sa1100/jornada720.c Mon Jun 9 23:16:20 2003 +++ b/arch/arm/mach-sa1100/jornada720.c Mon Jun 9 23:16:20 2003 @@ -24,6 +24,36 @@ #define JORTUCR_VAL 0x20000400 +static struct resource sa1111_resources[] = { + [0] = { + .start = 0x40000000, + .end = 0x40001fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_GPIO1, + .end = IRQ_GPIO1, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 sa1111_dmamask = 0xffffffffUL; + +static struct platform_device sa1111_device = { + .name = "sa1111", + .id = 0, + .dev = { + .name = "Intel Corporation SA1111", + .dma_mask = &sa1111_dmamask, + }, + .num_resources = ARRAY_SIZE(sa1111_resources), + .resource = sa1111_resources, +}; + +static struct platform_device *devices[] __initdata = { + &sa1111_device, +}; + static int __init jornada720_init(void) { int ret = -ENODEV; @@ -43,7 +73,7 @@ PPSR &= ~(PPC_LDD3 | PPC_LDD4); PPDR |= PPC_LDD3 | PPC_LDD4; - ret = sa1111_init(0x40000000, IRQ_GPIO1); + ret = platform_add_devices(devices, ARRAY_SIZE(devices)); } return ret; } diff -Nru a/arch/arm/mach-sa1100/neponset.c b/arch/arm/mach-sa1100/neponset.c --- a/arch/arm/mach-sa1100/neponset.c Mon Jun 9 23:16:12 2003 +++ b/arch/arm/mach-sa1100/neponset.c Mon Jun 9 23:16:12 2003 @@ -79,33 +79,6 @@ } } -static inline void __init neponset_init_irq(void) -{ - /* - * Install handler for GPIO25. - */ - set_irq_type(IRQ_GPIO25, IRQT_RISING); - set_irq_chained_handler(IRQ_GPIO25, neponset_irq_handler); - - /* - * We would set IRQ_GPIO25 to be a wake-up IRQ, but - * unfortunately something on the Neponset activates - * this IRQ on sleep (ethernet?) - */ -#if 0 - enable_irq_wake(IRQ_GPIO25); -#endif - - /* - * Setup other Neponset IRQs. SA1111 will be done by the - * generic SA1111 code. - */ - set_irq_handler(IRQ_NEPONSET_SMC9196, do_simple_IRQ); - set_irq_flags(IRQ_NEPONSET_SMC9196, IRQF_VALID | IRQF_PROBE); - set_irq_handler(IRQ_NEPONSET_USAR, do_simple_IRQ); - set_irq_flags(IRQ_NEPONSET_USAR, IRQF_VALID | IRQF_PROBE); -} - static void neponset_set_mctrl(struct uart_port *port, u_int mctrl) { u_int mdm_ctl0 = MDM_CTL_0; @@ -164,6 +137,42 @@ .get_mctrl = neponset_get_mctrl, }; +static int neponset_probe(struct device *dev) +{ + sa1100_register_uart_fns(&neponset_port_fns); + + /* + * Install handler for GPIO25. + */ + set_irq_type(IRQ_GPIO25, IRQT_RISING); + set_irq_chained_handler(IRQ_GPIO25, neponset_irq_handler); + + /* + * We would set IRQ_GPIO25 to be a wake-up IRQ, but + * unfortunately something on the Neponset activates + * this IRQ on sleep (ethernet?) + */ +#if 0 + enable_irq_wake(IRQ_GPIO25); +#endif + + /* + * Setup other Neponset IRQs. SA1111 will be done by the + * generic SA1111 code. + */ + set_irq_handler(IRQ_NEPONSET_SMC9196, do_simple_IRQ); + set_irq_flags(IRQ_NEPONSET_SMC9196, IRQF_VALID | IRQF_PROBE); + set_irq_handler(IRQ_NEPONSET_USAR, do_simple_IRQ); + set_irq_flags(IRQ_NEPONSET_USAR, IRQF_VALID | IRQF_PROBE); + + /* + * Disable GPIO 0/1 drivers so the buttons work on the module. + */ + NCR_0 = NCR_GP01_OFF; + + return 0; +} + /* * LDM power management. */ @@ -201,27 +210,63 @@ static struct device_driver neponset_device_driver = { .name = "neponset", - .bus = &system_bus_type, + .bus = &platform_bus_type, + .probe = neponset_probe, .suspend = neponset_suspend, .resume = neponset_resume, }; -static struct sys_device neponset_device = { - .name = "NEPONSET", +static struct resource neponset_resources[] = { + [0] = { + .start = 0x10000000, + .end = 0x17ffffff, + .flags = IORESOURCE_MEM, + }, +}; + +static struct platform_device neponset_device = { + .name = "neponset", .id = 0, - .root = NULL, .dev = { .name = "Neponset", - .bus_id = "neponset", - .bus = &system_bus_type, - .driver = &neponset_device_driver, + }, + .num_resources = ARRAY_SIZE(neponset_resources), + .resource = neponset_resources, +}; + +static struct resource sa1111_resources[] = { + [0] = { + .start = 0x40000000, + .end = 0x40001fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_NEPONSET_SA1111, + .end = IRQ_NEPONSET_SA1111, + .flags = IORESOURCE_IRQ, }, }; +static u64 sa1111_dmamask = 0xffffffffUL; + +static struct platform_device sa1111_device = { + .name = "sa1111", + .id = 0, + .dev = { + .name = "Intel Corporation SA1111", + .dma_mask = &sa1111_dmamask, + }, + .num_resources = ARRAY_SIZE(sa1111_resources), + .resource = sa1111_resources, +}; + +static struct platform_device *devices[] __initdata = { + &neponset_device, + &sa1111_device, +}; + static int __init neponset_init(void) { - int ret; - driver_register(&neponset_device_driver); /* @@ -248,29 +293,7 @@ return -ENODEV; } - ret = sys_device_register(&neponset_device); - if (ret) - return ret; - - sa1100_register_uart_fns(&neponset_port_fns); - - neponset_init_irq(); - - /* - * Disable GPIO 0/1 drivers so the buttons work on the module. - */ - NCR_0 = NCR_GP01_OFF; - - /* - * Neponset has SA1111 connected to CS4. We know that after - * reset the chip will be configured for variable latency IO. - */ - /* FIXME: setup MSC2 */ - - /* - * Probe and initialise the SA1111. - */ - return sa1111_init(0x40000000, IRQ_NEPONSET_SA1111); + return platform_add_devices(devices, ARRAY_SIZE(devices)); } subsys_initcall(neponset_init); diff -Nru a/arch/arm/mach-sa1100/pfs168.c b/arch/arm/mach-sa1100/pfs168.c --- a/arch/arm/mach-sa1100/pfs168.c Mon Jun 9 23:16:05 2003 +++ b/arch/arm/mach-sa1100/pfs168.c Mon Jun 9 23:16:05 2003 @@ -7,6 +7,7 @@ #include <linux/tty.h> #include <linux/errno.h> #include <linux/ioport.h> +#include <linux/device.h> #include <asm/hardware.h> #include <asm/mach-types.h> @@ -18,6 +19,35 @@ #include "generic.h" +static struct resource sa1111_resources[] = { + [0] = { + .start = 0x40000000, + .end = 0x40001fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_GPIO25, + .end = IRQ_GPIO25, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 sa1111_dmamask = 0xffffffffUL; + +static struct platform_device sa1111_device = { + .name = "sa1111", + .id = 0, + .dev = { + .name = "Intel Corporation SA1111", + .dma_mask = &sa1111_dmamask, + }, + .num_resources = ARRAY_SIZE(sa1111_resources), + .resource = sa1111_resources, +}; + +static struct platform_device *devices[] __initdata = { + &sa1111_device, +}; static int __init pfs168_init(void) { @@ -32,10 +62,7 @@ */ sa1110_mb_disable(); - /* - * Probe for SA1111. - */ - return sa1111_init(0x40000000, IRQ_GPIO25); + return platform_add_devices(devices, ARRAY_SIZE(devices)); } arch_initcall(pfs168_init); diff -Nru a/arch/arm/mach-sa1100/system3.c b/arch/arm/mach-sa1100/system3.c --- a/arch/arm/mach-sa1100/system3.c Mon Jun 9 23:16:17 2003 +++ b/arch/arm/mach-sa1100/system3.c Mon Jun 9 23:16:17 2003 @@ -373,6 +373,36 @@ } } +static struct resource sa1111_resources[] = { + [0] = { + .start = PT_SA1111_BASE, + .end = PT_SA1111_BASE + 0x00001fff, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_SYSTEM3_SA1111, + .end = IRQ_SYSTEM3_SA1111, + .flags = IORESOURCE_IRQ, + }, +}; + +static u64 sa1111_dmamask = 0xffffffffUL; + +static struct platform_device sa1111_device = { + .name = "sa1111", + .id = 0, + .dev = { + .name = "Intel Corporation SA1111", + .dma_mask = &sa1111_dmamask, + }, + .num_resources = ARRAY_SIZE(sa1111_resources), + .resource = sa1111_resources, +}; + +static struct platform_device *devices[] __initdata = { + &sa1111_device, +}; + static int __init system3_init(void) { int ret = 0; @@ -405,7 +435,7 @@ /* * Probe for a SA1111. */ - ret = sa1111_init(PT_SA1111_BASE, IRQ_SYSTEM3_SA1111); + ret = platform_add_devices(devices, ARRAY_SIZE(devices)); if (ret < 0) { printk( KERN_WARNING"PT Digital Board: no SA1111 found!\n" ); goto DONE; diff -Nru a/arch/arm/mach-sa1100/xp860.c b/arch/arm/mach-sa1100/xp860.c --- a/arch/arm/mach-sa1100/xp860.c Mon Jun 9 23:16:12 2003 +++ b/arch/arm/mach-sa1100/xp860.c Mon Jun 9 23:16:12 2003 @@ -30,6 +30,31 @@ while(1); } +static struct resource sa1111_resources[] = { + [0] = { + .start = 0x40000000, + .end = 0x40001fff, + .flags = IORESOURCE_MEM, + }, +}; + +static u64 sa1111_dmamask = 0xffffffffUL; + +static struct platform_device sa1111_device = { + .name = "sa1111", + .id = 0, + .dev = { + .name = "Intel Corporation SA1111", + .dma_mask = &sa1111_dmamask, + }, + .num_resources = ARRAY_SIZE(sa1111_resources), + .resource = sa1111_resources, +}; + +static struct platform_device *devices[] __initdata = { + &sa1111_device, +}; + /* * Note: I replaced the sa1111_init() without the full SA1111 initialisation * because this machine doesn't appear to use the DMA features. If this is @@ -39,19 +64,7 @@ { pm_power_off = xp860_power_off; - /* - * Probe for SA1111. - */ - ret = sa1111_probe(0x40000000); - if (ret < 0) - return ret; - - /* - * We found it. Wake the chip up. - */ - sa1111_wake(); - - return 0; + return platform_add_devices(devices, ARRAY_SIZE(devices)); } arch_initcall(xp860_init); diff -Nru a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c --- a/arch/arm/mm/consistent.c Mon Jun 9 23:16:16 2003 +++ b/arch/arm/mm/consistent.c Mon Jun 9 23:16:16 2003 @@ -10,7 +10,7 @@ * DMA uncached mapping support. */ #include <linux/config.h> -#include <linux/types.h> +#include <linux/module.h> #include <linux/mm.h> #include <linux/slab.h> #include <linux/string.h> @@ -145,6 +145,7 @@ struct vm_region *c; unsigned long order, flags; void *ret = NULL; + int res; if (!consistent_pte) { printk(KERN_ERR "consistent_alloc: not initialised\n"); @@ -177,14 +178,19 @@ if (!c) goto no_remap; - spin_lock_irqsave(&consistent_lock, flags); - vm_region_dump(&consistent_head, "before alloc"); - /* * Attempt to allocate a virtual address in the * consistent mapping region. */ - if (!vm_region_alloc(&consistent_head, c, size)) { + spin_lock_irqsave(&consistent_lock, flags); + vm_region_dump(&consistent_head, "before alloc"); + + res = vm_region_alloc(&consistent_head, c, size); + + vm_region_dump(&consistent_head, "after alloc"); + spin_unlock_irqrestore(&consistent_lock, flags); + + if (!res) { pte_t *pte = consistent_pte + CONSISTENT_OFFSET(c->vm_start); struct page *end = page + (1 << order); pgprot_t prot = __pgprot(L_PTE_PRESENT | L_PTE_YOUNG | @@ -218,9 +224,6 @@ ret = (void *)c->vm_start; } - vm_region_dump(&consistent_head, "after alloc"); - spin_unlock_irqrestore(&consistent_lock, flags); - no_remap: if (ret == NULL) { kfree(c); @@ -229,6 +232,22 @@ no_page: return ret; } + +/* + * Since we have the DMA mask available to us here, we could try to do + * a normal allocation, and only fall back to a "DMA" allocation if the + * resulting bus address does not satisfy the dma_mask requirements. + */ +void * +dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, int gfp) +{ + if (dev == NULL || *dev->dma_mask != 0xffffffff) + gfp |= GFP_DMA; + + return consistent_alloc(gfp, size, handle, 0); +} + +EXPORT_SYMBOL(dma_alloc_coherent); /* * free a page as defined by the above mapping. diff -Nru a/arch/arm/mm/init.c b/arch/arm/mm/init.c --- a/arch/arm/mm/init.c Mon Jun 9 23:16:07 2003 +++ b/arch/arm/mm/init.c Mon Jun 9 23:16:07 2003 @@ -47,7 +47,7 @@ #define TABLE_SIZE ((TABLE_OFFSET + PTRS_PER_PTE) * sizeof(pte_t)) -struct mmu_gather mmu_gathers[NR_CPUS]; +DEFINE_PER_CPU(struct mmu_gather, mmu_gathers); extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; extern char _stext, _text, _etext, _end, __init_begin, __init_end; diff -Nru a/arch/arm26/ACKNOWLEDGEMENTS b/arch/arm26/ACKNOWLEDGEMENTS --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/ACKNOWLEDGEMENTS Mon Jun 9 23:16:20 2003 @@ -0,0 +1,27 @@ +The work in this architecture (ARM26) is that of a great many people. + +This is what has happened: + +I [Ian Molton] have been trying to repair the ARM26 architecture support, but it has become an impossible task whilst it is still merged with the ARM32 (arch/arm) code. The ARM26 code is too different to be sensible to keep with the ARM32 code now, and Russell King really doesnt have the time to maintain the ARM26 code. Add to that that most ARM32 developers dont know about or care about ARM26 when writing patches, and you have a reall mess. + +As a result, I've split it off into a new architecture of its own. I've named it arm26 since these CPUs have only a 26 bit address space, unlike the other ARMs. + +The upheaval in moving around so many source files and chopping out vasty ammounts of cruft was enormous, and the copyright of many files is sometimes unclear. Because of this, I am writing this, in order that no-one is left out / misaccredited / blamed for any of the code. + +People I KNOW have made major contributions to the code: + +David Alan Gilbert (former maintainer of ARM26 bits) +Philip Blundell +Russell King +Keith Owens + +Currently maintaing the code are + +Ian Molton (Maintainer / Archimedes) +John Appleby (kernel / A5K) + +If anyone has a problem with attributions in header files / source files, please do contact me to straighten things out. + +Ian Molton (aka spyro) - ARM26 maintainer +spyro@f2s.com + diff -Nru a/arch/arm26/Config.help b/arch/arm26/Config.help --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/Config.help Mon Jun 9 23:16:20 2003 @@ -0,0 +1,387 @@ +CONFIG_ARM + The ARM series is a line of low-power-consumption RISC chip designs + licensed by ARM ltd and targeted at embedded applications. + +CONFIG_IDE + If you say Y here, your kernel will be able to manage low cost mass + storage units such as ATA/(E)IDE and ATAPI units. The most common + cases are IDE hard drives and ATAPI CD-ROM drives. + + If your system is pure SCSI and doesn't use these interfaces, you + can say N here. + + Integrated Disk Electronics (IDE aka ATA-1) is a connecting standard + for mass storage units such as hard disks. It was designed by + Western Digital and Compaq Computer in 1984. It was then named + ST506. Quite a number of disks use the IDE interface. + + AT Attachment (ATA) is the superset of the IDE specifications. + ST506 was also called ATA-1. + + Fast-IDE is ATA-2 (also named Fast ATA), Enhanced IDE (EIDE) is + ATA-3. It provides support for larger disks (up to 8.4GB by means of + the LBA standard), more disks (4 instead of 2) and for other mass + storage units such as tapes and cdrom. UDMA/33 (aka UltraDMA/33) is + ATA-4 and provides faster (and more CPU friendly) transfer modes + than previous PIO (Programmed processor Input/Output) from previous + ATA/IDE standards by means of fast DMA controllers. + + ATA Packet Interface (ATAPI) is a protocol used by EIDE tape and + CD-ROM drives, similar in many respects to the SCSI protocol. + + SMART IDE (Self Monitoring, Analysis and Reporting Technology) was + designed in order to prevent data corruption and disk crash by + detecting pre hardware failure conditions (heat, access time, and + the like...). Disks built since June 1995 may follow this standard. + The kernel itself don't manage this; however there are quite a + number of user programs such as smart that can query the status of + SMART parameters disk. + + If you want to compile this driver 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 ide.o. + + For further information, please read <file:Documentation/ide.txt>. + + If unsure, say Y. + +CONFIG_ISA + Find out whether you have ISA slots on your motherboard. ISA is the + name of a bus system, i.e. the way the CPU talks to the other stuff + inside your box. Other bus systems are PCI, EISA, MicroChannel + (MCA) or VESA. ISA is an older system, now being displaced by PCI; + newer boards don't support it. If you have ISA, say Y, otherwise N. + +CONFIG_PREEMPT + This option reduces the latency of the kernel when reacting to + real-time or interactive events by allowing a low priority process to + be preempted even if it is in kernel mode executing a system call. + This allows applications to run more reliably even when the system is + under load. + + Say Y here if you are building a kernel for a desktop, embedded + or real-time system. Say N if you are unsure. + +CONFIG_MCA + MicroChannel Architecture is found in some IBM PS/2 machines and + laptops. It is a bus system similar to PCI or ISA. See + <file:Documentation/mca.txt> (and especially the web page given + there) before attempting to build an MCA bus kernel. + +CONFIG_EISA + The Extended Industry Standard Architecture (EISA) bus was + developed as an open alternative to the IBM MicroChannel bus. + + The EISA bus provided some of the features of the IBM MicroChannel + bus while maintaining backward compatibility with cards made for + the older ISA bus. The EISA bus saw limited use between 1988 and + 1995 when it was made obsolete by the PCI bus. + + Say Y here if you are building a kernel for an EISA-based machine. + + Otherwise, say N. + +CONFIG_HOTPLUG + Say Y here if you want to plug devices into your computer while + the system is running, and be able to use them quickly. In many + cases, the devices can likewise be unplugged at any time too. + + One well known example of this is PCMCIA- or PC-cards, credit-card + size devices such as network cards, modems or hard drives which are + plugged into slots found on all modern laptop computers. Another + example, used on modern desktops as well as laptops, is USB. + + Enable HOTPLUG and KMOD, and build a modular kernel. Get agent + software (at <http://linux-hotplug.sourceforge.net/>) and install it. + Then your kernel will automatically call out to a user mode "policy + agent" (/sbin/hotplug) to load modules and set up software needed + to use devices as you hotplug them. + +CONFIG_KCORE_ELF + If you enabled support for /proc file system then the file + /proc/kcore will contain the kernel core image. This can be used + in gdb: + + $ cd /usr/src/linux ; gdb vmlinux /proc/kcore + + You have two choices here: ELF and A.OUT. Selecting ELF will make + /proc/kcore appear in ELF core format as defined by the Executable + and Linking Format specification. Selecting A.OUT will choose the + old "a.out" format which may be necessary for some old versions + of binutils or on some architectures. + + This is especially useful if you have compiled the kernel with the + "-g" option to preserve debugging information. It is mainly used + for examining kernel data structures on the live kernel so if you + don't understand what this means or are not a kernel hacker, just + leave it at its default value ELF. + +CONFIG_KCORE_AOUT + Not necessary unless you're using a very out-of-date binutils + version. You probably want KCORE_ELF. + +CONFIG_BINFMT_ELF + ELF (Executable and Linkable Format) is a format for libraries and + executables used across different architectures and operating + systems. Saying Y here will enable your kernel to run ELF binaries + and enlarge it by about 13 KB. ELF support under Linux has now all + but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC) + because it is portable (this does *not* mean that you will be able + to run executables from different architectures or operating systems + however) and makes building run-time libraries very easy. Many new + executables are distributed solely in ELF format. You definitely + want to say Y here. + + Information about ELF is contained in the ELF HOWTO available from + <http://www.linuxdoc.org/docs.html#howto>. + + If you find that after upgrading from Linux kernel 1.2 and saying Y + here, you still can't run any ELF binaries (they just crash), then + you'll have to install the newest ELF runtime libraries, including + ld.so (check the file <file:Documentation/Changes> for location and + latest version). + + 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 binfmt_elf.o. Saying M or N here is dangerous because + some crucial programs on your system might be in ELF format. + +CONFIG_BINFMT_AOUT + A.out (Assembler.OUTput) is a set of formats for libraries and + executables used in the earliest versions of UNIX. Linux used the + a.out formats QMAGIC and ZMAGIC until they were replaced with the + ELF format. + + As more and more programs are converted to ELF, the use for a.out + will gradually diminish. If you disable this option it will reduce + your kernel by one page. This is not much and by itself does not + 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 + 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. + +CONFIG_BINFMT_MISC + If you say Y here, it will be possible to plug wrapper-driven binary + formats into the kernel. You will like this especially when you use + programs that need an interpreter to run like Java, Python or + Emacs-Lisp. It's also useful if you often run DOS executables under + the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from + <http://www.linuxdoc.org/docs.html#howto>). Once you have + registered such a binary class with the kernel, you can start one of + those programs simply by typing in its name at a shell prompt; Linux + will automatically feed it to the correct interpreter. + + You can do other nice things, too. Read the file + <file:Documentation/binfmt_misc.txt> to learn how to use this + feature, and <file:Documentation/java.txt> for information about how + to include Java support. + + You must say Y to "/proc file system support" (CONFIG_PROC_FS) to + use this part of the kernel. + + You may say M here for module support and later load the module when + you have use for it; the module is called binfmt_misc.o. If you + don't know what to answer at this point, say Y. + +CONFIG_SCSI + If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or + any other SCSI device under Linux, say Y and make sure that you know + the name of your SCSI host adapter (the card inside your computer + that "speaks" the SCSI protocol, also called SCSI controller), + because you will be asked for it. + + You also need to say Y here if you want support for the parallel + port version of the 100 MB IOMEGA ZIP drive. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called scsi_mod.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt> and + <file:Documentation/scsi.txt>. However, do not compile this as a + module if your root file system (the one containing the directory /) + is located on a SCSI device. + +CONFIG_NETDEVICES + You can say N here if you don't intend to connect your Linux box to + any other computer at all or if all your connections will be over a + telephone line with a modem either via UUCP (UUCP is a protocol to + forward mail and news between unix hosts over telephone lines; read + the UUCP-HOWTO, available from + <http://www.linuxdoc.org/docs.html#howto>) or dialing up a shell + account or a BBS, even using term (term is a program which gives you + almost full Internet connectivity if you have a regular dial up + shell account on some Internet connected Unix computer. Read + <http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html>). + + You'll have to say Y if your computer contains a network card that + you want to use under Linux (make sure you know its name because you + will be asked for it and read the Ethernet-HOWTO (especially if you + plan to use more than one network card under Linux)) or if you want + to use SLIP (Serial Line Internet Protocol is the protocol used to + send Internet traffic over telephone lines or null modem cables) or + CSLIP (compressed SLIP) or PPP (Point to Point Protocol, a better + and newer replacement for SLIP) or PLIP (Parallel Line Internet + Protocol is mainly used to create a mini network by connecting the + parallel ports of two local machines) or AX.25/KISS (protocol for + sending Internet traffic over amateur radio links). + + Make sure to read the NET-3-HOWTO. Eventually, you will have to read + Olaf Kirch's excellent and free book "Network Administrator's + Guide", to be found in <http://www.linuxdoc.org/docs.html#guide>. If + unsure, say Y. + +CONFIG_MAGIC_SYSRQ + If you say Y here, you will have some control over the system even + if the system crashes for example during kernel debugging (e.g., you + will be able to flush the buffer cache to disk, reboot the system + immediately or dump some status information). This is accomplished + by pressing various keys while holding SysRq (Alt+PrintScreen). It + also works on a serial console (on PC hardware at least), if you + send a BREAK and then within 5 seconds a command keypress. The + keys are documented in <file:Documentation/sysrq.txt>. Don't say Y + unless you really know what this hack does. + +CONFIG_ARCH_ARCA5K + This selects support for 'ARM26' CPUs (ARM 2 and 3) + +CONFIG_ARCH_A5K + Say Y here to to support the Acorn A5000. Linux can support the + internal IDE disk and CD-ROM interface, serial and parallel port, + and the floppy drive. Note that on some A5000s the floppy is + plugged into the wrong socket on the motherboard. + +CONFIG_ARCH_ARC + The Acorn Archimedes was an personal computer based on an 8MHz ARM2 + processor, released in 1987. It supported 512K of RAM and 2 800K + floppy disks. Picture and more detailed specifications at + <http://www.computingmuseum.com/museum/archi.htm>. + +CONFIG_PAGESIZE_16 + Say Y here if your Archimedes or A5000 system has only 2MB of + memory, otherwise say N. The resulting kernel will not run on a + machine with 4MB of memory. + +CONFIG_FPE_NWFPE + Say Y to include the NWFPE floating point emulator in the kernel. + This is necessary to run most binaries. Linux does not currently + support floating point hardware so you need to say Y here even if + your machine has an FPA or floating point co-processor podule. + + It is also possible to say M to build the emulator as a module + (nwfpe.o) or indeed to leave it out altogether. However, unless you + know what you are doing this can easily render your machine + unbootable. Saying Y is the safe option. + + You may say N here if you are going to load the Acorn FPEmulator + early in the bootup. + +CONFIG_FPE_FASTFPE + Say Y here to include the FAST floating point emulator in the kernel. + This is an experimental much faster emulator which now also has full + precision for the mantissa. It does not support any exceptions. + It is very simple, and approximately 3-6 times faster than NWFPE. + + It should be sufficient for most programs. It may be not suitable + for scientific calculations, but you have to check this for yourself. + If you do not feel you need a faster FP emulation you should better + choose NWFPE. + + It is also possible to say M to build the emulator as a module + (fastfpe.o). But keep in mind that you should only load the FP + emulator early in the bootup. You should never change from NWFPE to + FASTFPE or vice versa in an active system! + +CONFIG_DEBUG_ERRORS + This option controls verbose debugging information which can be + printed when the kernel detects an internal error. This debugging + information is useful to kernel hackers when tracking down problems, + but mostly meaningless to other people. It's safe to say Y unless + you are concerned with the code size or don't want to see these + messages. + +CONFIG_NO_FRAME_POINTER + If you say Y here, the resulting kernel will be slightly smaller and + faster. However, when a problem occurs with the kernel, the + information that is reported is severely limited. Most people + should say N here. + +CONFIG_DEBUG_USER + When a user program crashes due to an exception, the kernel can + print a brief message explaining what the problem was. This is + sometimes helpful for debugging but serves no purpose on a + production system. Most people should say N here. + +CONFIG_DEBUG_INFO + Say Y here to include source-level debugging information in the + `vmlinux' binary image. This is handy if you want to use gdb or + addr2line to debug the kernel. It has no impact on the in-memory + footprint of the running kernel but it can increase the amount of + time and disk space needed for compilation of the kernel. If in + doubt say N. + +CONFIG_DEBUG_LL + Say Y here to include definitions of printascii, printchar, printhex + in the kernel. This is helpful if you are debugging code that + executes before the console is initialized. + +CONFIG_NO_PGT_CACHE + Normally the kernel maintains a `quicklist' of preallocated + pagetable structures in order to increase performance. On machines + with very few pages this may however be a loss. Say Y here to + disable the pgtable cache. + +CONFIG_ARTHUR + Say Y here to include the kernel code necessary if you want to run + Acorn RISC OS/Arthur binaries under Linux. This code is still very + experimental; if this sounds frightening, say N and sleep in peace. + You can also say M here to compile this support as a module (which + will be called arthur.o). + +CONFIG_CMDLINE + On some architectures (EBSA110 and CATS), there is currently no way + for the boot loader to pass arguments to the kernel. For these + architectures, you should supply some command-line options at build + time by entering them here. As a minimum, you should specify the + memory size and the root device (e.g., mem=64M root=/dev/nfs). + +CONFIG_DEBUG_KERNEL + Say Y here if you are developing drivers or trying to debug and + identify kernel problems. + +CONFIG_DEBUG_SLAB + Say Y here to have the kernel do limited verification on memory + allocation as well as poisoning memory on free to catch use of freed + memory. + +CONFIG_DEBUG_SPINLOCK + Say Y here and build SMP to catch missing spinlock initialization + and certain other kinds of spinlock errors commonly made. This is + best used in conjunction with the NMI watchdog so that spinlock + deadlocks are also debuggable. + +CONFIG_DEBUG_BUGVERBOSE + Say Y here to make BUG() panics output the file name and line number + of the BUG call as well as the EIP and oops trace. This aids + debugging but costs about 70-100K of memory. + +CONFIG_ZBOOT_ROM + Say Y here if you intend to execute your compressed kernel image (zImage) + directly from ROM or flash. If unsure, say N. + +CONFIG_ZBOOT_ROM_TEXT + The base address for zImage. Unless you have special requirements, you + should not change this value. + +CONFIG_ZBOOT_ROM_BSS + The base address of 64KiB of read/write memory, which must be available + while the decompressor is running. Unless you have special requirements, + you should not change this value. + diff -Nru a/arch/arm26/Kconfig b/arch/arm26/Kconfig --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/Kconfig Mon Jun 9 23:16:20 2003 @@ -0,0 +1,572 @@ +# +# For a description of the syntax of this configuration file, +# see Documentation/kbuild/kconfig-language.txt. +# + +mainmenu "Linux Kernel Configuration" + +config ARM + bool + default y + help + The ARM series is a line of low-power-consumption RISC chip designs + licensed by ARM ltd and targeted at embedded applications and + handhelds such as the Compaq IPAQ. ARM-based PCs are no longer + manufactured, but legacy ARM-based PC hardware remains popular in + Europe. There is an ARM Linux project with a web page at + <http://www.arm.linux.org.uk/>. + +config ARCH_ARCA5K + bool + default y + +config MMU + bool + default y + +config ARCH_ACORN + bool + default y + +config CPU_26 + bool + default y + +config FIQ + bool + default y + +# 9 = 512 pages 8 = 256 pages 7 = 128 pages +config FORCE_MAX_ZONEORDER + int + default 9 + +config UID16 + bool + default y + +config RWSEM_GENERIC_SPINLOCK + bool + default y + +config RWSEM_XCHGADD_ALGORITHM + bool + +config GENERIC_BUST_SPINLOCK + bool + +config GENERIC_ISA_DMA + bool + +source "init/Kconfig" + + +menu "System Type" + +comment "Archimedes/A5000 Implementations (select only ONE)" + +config ARCH_ARC + bool "Archimedes" + depends on ARCH_ARCA5K + help + The Acorn Archimedes was an personal computer based on an 8K ARM2 + processor, released in 1987. It supported 512K of RAM and 2 800K + floppy disks. Picture and more detailed specifications at + <http://www.computingmuseum.com/museum/archi.htm>. + +config ARCH_A5K + bool "A5000" + depends on ARCH_ARCA5K + help + Say Y here to to support the Acorn A5000. Linux can support the + internal IDE disk and CD-ROM interface, serial and parallel port, + and the floppy drive. Note that on some A5000s the floppy is + plugged into the wrong socket on the motherboard. + +config PAGESIZE_16 + bool "2MB physical memory" + depends on ARCH_ARCA5K + help + Say Y here if your Archimedes or A5000 system has only 2MB of + memory, otherwise say N. The resulting kernel will not run on a + machine with 4MB of memory. +endmenu + +menu "General setup" + +# Compressed boot loader in ROM. Yes, we really want to ask about +# TEXT and BSS so we preserve their values in the config files. +config ZBOOT_ROM + bool "Compressed boot loader in ROM/flash" + help + Say Y here if you intend to execute your compressed kernel image (zImage) + directly from ROM or flash. If unsure, say N. + +config ZBOOT_ROM_TEXT + hex "Compressed ROM boot loader base address" + default "0" + help + The base address for zImage. Unless you have special requirements, you + should not change this value. + +config ZBOOT_ROM_BSS + hex "Compressed ROM boot loader BSS address" + default "0" + help + The base address of 64KiB of read/write memory, which must be available + while the decompressor is running. Unless you have special requirements, + you should not change this value. + +config HOTPLUG + bool "Support for hot-pluggable devices" + ---help--- + Say Y here if you want to plug devices into your computer while + the system is running, and be able to use them quickly. In many + cases, the devices can likewise be unplugged at any time too. + + One well known example of this is PCMCIA- or PC-cards, credit-card + size devices such as network cards, modems or hard drives which are + plugged into slots found on all modern laptop computers. Another + example, used on modern desktops as well as laptops, is USB. + + Enable HOTPLUG and KMOD, and build a modular kernel. Get agent + software (at <http://linux-hotplug.sourceforge.net/>) and install it. + Then your kernel will automatically call out to a user mode "policy + agent" (/sbin/hotplug) to load modules and set up software needed + to use devices as you hotplug them. + +comment "At least one math emulation must be selected" + +config FPE_NWFPE + tristate "NWFPE math emulation" + ---help--- + Say Y to include the NWFPE floating point emulator in the kernel. + This is necessary to run most binaries. Linux does not currently + support floating point hardware so you need to say Y here even if + your machine has an FPA or floating point co-processor podule. + + It is also possible to say M to build the emulator as a module + (nwfpe) or indeed to leave it out altogether. However, unless you + know what you are doing this can easily render your machine + unbootable. Saying Y is the safe option. + + You may say N here if you are going to load the Acorn FPEmulator + early in the bootup. + +choice + prompt "Kernel core (/proc/kcore) format" + default KCORE_ELF + +config KCORE_ELF + bool "ELF" + ---help--- + If you enabled support for /proc file system then the file + /proc/kcore will contain the kernel core image. This can be used + in gdb: + + $ cd /usr/src/linux ; gdb vmlinux /proc/kcore + + You have two choices here: ELF and A.OUT. Selecting ELF will make + /proc/kcore appear in ELF core format as defined by the Executable + and Linking Format specification. Selecting A.OUT will choose the + old "a.out" format which may be necessary for some old versions + of binutils or on some architectures. + + This is especially useful if you have compiled the kernel with the + "-g" option to preserve debugging information. It is mainly used + for examining kernel data structures on the live kernel so if you + don't understand what this means or are not a kernel hacker, just + leave it at its default value ELF. + +config KCORE_AOUT + bool "A.OUT" + help + Not necessary unless you're using a very out-of-date binutils + version. You probably want KCORE_ELF. + +endchoice + +config BINFMT_AOUT + tristate "Kernel support for a.out binaries" + ---help--- + A.out (Assembler.OUTput) is a set of formats for libraries and + executables used in the earliest versions of UNIX. Linux used the + a.out formats QMAGIC and ZMAGIC until they were replaced with the + ELF format. + + As more and more programs are converted to ELF, the use for a.out + will gradually diminish. If you disable this option it will reduce + your kernel by one page. This is not much and by itself does not + 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 + 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. Saying M or N here is dangerous though, + because some crucial programs on your system might still be in A.OUT + format. + +config BINFMT_ELF + tristate "Kernel support for ELF binaries" + ---help--- + ELF (Executable and Linkable Format) is a format for libraries and + executables used across different architectures and operating + systems. Saying Y here will enable your kernel to run ELF binaries + and enlarge it by about 13 KB. ELF support under Linux has now all + but replaced the traditional Linux a.out formats (QMAGIC and ZMAGIC) + because it is portable (this does *not* mean that you will be able + to run executables from different architectures or operating systems + however) and makes building run-time libraries very easy. Many new + executables are distributed solely in ELF format. You definitely + want to say Y here. + + Information about ELF is contained in the ELF HOWTO available from + <http://www.linuxdoc.org/docs.html#howto>. + + If you find that after upgrading from Linux kernel 1.2 and saying Y + here, you still can't run any ELF binaries (they just crash), then + you'll have to install the newest ELF runtime libraries, including + ld.so (check the file <file:Documentation/Changes> for location and + latest version). + + 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 binfmt_elf. Saying M or N here is dangerous because + some crucial programs on your system might be in ELF format. + +config BINFMT_MISC + tristate "Kernel support for MISC binaries" + ---help--- + If you say Y here, it will be possible to plug wrapper-driven binary + formats into the kernel. You will like this especially when you use + programs that need an interpreter to run like Java, Python or + Emacs-Lisp. It's also useful if you often run DOS executables under + the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available from + <http://www.linuxdoc.org/docs.html#howto>). Once you have + registered such a binary class with the kernel, you can start one of + those programs simply by typing in its name at a shell prompt; Linux + will automatically feed it to the correct interpreter. + + You can do other nice things, too. Read the file + <file:Documentation/binfmt_misc.txt> to learn how to use this + feature, and <file:Documentation/java.txt> for information about how + to include Java support. + + You must say Y to "/proc file system support" (CONFIG_PROC_FS) to + use this part of the kernel. + + You may say M here for module support and later load the module when + you have use for it; the module is called binfmt_misc. If you + don't know what to answer at this point, say Y. + +config PREEMPT + bool "Preemptible Kernel (EXPERIMENTAL)" + depends on CPU_32 && EXPERIMENTAL + help + This option reduces the latency of the kernel when reacting to + real-time or interactive events by allowing a low priority process to + be preempted even if it is in kernel mode executing a system call. + This allows applications to run more reliably even when the system is + under load. + + Say Y here if you are building a kernel for a desktop, embedded + or real-time system. Say N if you are unsure. + +config ARTHUR + tristate "RISC OS personality" + depends on CPU_32 + help + Say Y here to include the kernel code necessary if you want to run + Acorn RISC OS/Arthur binaries under Linux. This code is still very + experimental; if this sounds frightening, say N and sleep in peace. + You can also say M here to compile this support as a module (which + will be called arthur). + +config CMDLINE + string "Default kernel command string" + default "" + help + On some architectures (EBSA110 and CATS), there is currently no way + for the boot loader to pass arguments to the kernel. For these + architectures, you should supply some command-line options at build + time by entering them here. As a minimum, you should specify the + memory size and the root device (e.g., mem=64M root=/dev/nfs). + +endmenu + +source "drivers/parport/Kconfig" + +source "drivers/pnp/Kconfig" + +source "drivers/block/Kconfig" + +source "drivers/md/Kconfig" + +source "net/Kconfig" + +source "net/irda/Kconfig" + +menu "ATA/ATAPI/MFM/RLL support" + +config IDE + tristate "ATA/ATAPI/MFM/RLL support" + ---help--- + If you say Y here, your kernel will be able to manage low cost mass + storage units such as ATA/(E)IDE and ATAPI units. The most common + cases are IDE hard drives and ATAPI CD-ROM drives. + + If your system is pure SCSI and doesn't use these interfaces, you + can say N here. + + Integrated Disk Electronics (IDE aka ATA-1) is a connecting standard + for mass storage units such as hard disks. It was designed by + Western Digital and Compaq Computer in 1984. It was then named + ST506. Quite a number of disks use the IDE interface. + + AT Attachment (ATA) is the superset of the IDE specifications. + ST506 was also called ATA-1. + + Fast-IDE is ATA-2 (also named Fast ATA), Enhanced IDE (EIDE) is + ATA-3. It provides support for larger disks (up to 8.4GB by means of + the LBA standard), more disks (4 instead of 2) and for other mass + storage units such as tapes and cdrom. UDMA/33 (aka UltraDMA/33) is + ATA-4 and provides faster (and more CPU friendly) transfer modes + than previous PIO (Programmed processor Input/Output) from previous + ATA/IDE standards by means of fast DMA controllers. + + ATA Packet Interface (ATAPI) is a protocol used by EIDE tape and + CD-ROM drives, similar in many respects to the SCSI protocol. + + SMART IDE (Self Monitoring, Analysis and Reporting Technology) was + designed in order to prevent data corruption and disk crash by + detecting pre hardware failure conditions (heat, access time, and + the like...). Disks built since June 1995 may follow this standard. + The kernel itself don't manage this; however there are quite a + number of user programs such as smart that can query the status of + SMART parameters disk. + + If you want to compile this driver 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 ide. + + For further information, please read <file:Documentation/ide.txt>. + + If unsure, say Y. + +source "drivers/ide/Kconfig" + +endmenu + + +menu "SCSI support" + +config SCSI + tristate "SCSI support" + ---help--- + If you want to use a SCSI hard disk, SCSI tape drive, SCSI CD-ROM or + any other SCSI device under Linux, say Y and make sure that you know + the name of your SCSI host adapter (the card inside your computer + that "speaks" the SCSI protocol, also called SCSI controller), + because you will be asked for it. + + You also need to say Y here if you want support for the parallel + port version of the 100 MB IOMEGA ZIP drive. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called scsi_mod. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt> and + <file:Documentation/scsi/scsi.txt>. However, do not compile this as a + module if your root file system (the one containing the directory /) + is located on a SCSI device. + +source "drivers/scsi/Kconfig" + +endmenu + +source "drivers/isdn/Kconfig" + +# +# input before char - char/joystick depends on it. As does USB. +# +source "drivers/input/Kconfig" + +source "drivers/char/Kconfig" + +config KBDMOUSE + bool + depends on ARCH_ACORN && BUSMOUSE=y + default y + +source "drivers/media/Kconfig" + +source "fs/Kconfig" + +source "drivers/video/Kconfig" + +menu "Sound" + depends on ARCH_ACORN + +config SOUND + tristate "Sound card support" + ---help--- + If you have a sound card in your computer, i.e. if it can say more + than an occasional beep, say Y. Be sure to have all the information + about your sound card and its configuration down (I/O port, + interrupt and DMA channel), because you will be asked for it. + + You want to read the Sound-HOWTO, available from + <http://www.linuxdoc.org/docs.html#howto>. General information about + the modular sound system is contained in the files + <file:Documentation/sound/Introduction>. The file + <file:Documentation/sound/README.OSS> contains some slightly + outdated but still useful information as well. + + If you have a PnP sound card and you want to configure it at boot + time using the ISA PnP tools (read + <http://www.roestock.demon.co.uk/isapnptools/>), then you need to + compile the sound card support as a module ( = code which can be + inserted in and removed from the running kernel whenever you want) + and load that module after the PnP configuration is finished. To do + this, say M here and read <file:Documentation/modules.txt> as well + as <file:Documentation/sound/README.modules>; the module will be + called soundcore. + + I'm told that even without a sound card, you can make your computer + say more than an occasional beep, by programming the PC speaker. + Kernel patches and supporting utilities to do that are in the pcsp + package, available at <ftp://ftp.infradead.org/pub/pcsp/>. + +source "sound/Kconfig" + +endmenu + +source "drivers/misc/Kconfig" + +source "drivers/usb/Kconfig" + +source "net/bluetooth/Kconfig" + + +menu "Kernel hacking" + +# RMK wants arm kernels compiled with frame pointers so hardwire this to y. +# If you know what you are doing and are willing to live without stack +# traces, you can get a slightly smaller kernel by setting this option to +# n, but then RMK will have to kill you ;). +config FRAME_POINTER + bool + default y + help + If you say N here, the resulting kernel will be slightly smaller and + faster. However, when a problem occurs with the kernel, the + information that is reported is severely limited. Most people + should say Y here. + +config DEBUG_USER + bool "Verbose user fault messages" + help + When a user program crashes due to an exception, the kernel can + print a brief message explaining what the problem was. This is + sometimes helpful for debugging but serves no purpose on a + production system. Most people should say N here. + +config DEBUG_INFO + bool "Include GDB debugging information in kernel binary" + help + Say Y here to include source-level debugging information in the + `vmlinux' binary image. This is handy if you want to use gdb or + addr2line to debug the kernel. It has no impact on the in-memory + footprint of the running kernel but it can increase the amount of + time and disk space needed for compilation of the kernel. If in + doubt say N. + +config DEBUG_KERNEL + bool "Kernel debugging" + help + Say Y here if you are developing drivers or trying to debug and + identify kernel problems. + +config DEBUG_SLAB + bool "Debug memory allocations" + depends on DEBUG_KERNEL + help + Say Y here to have the kernel do limited verification on memory + allocation as well as poisoning memory on free to catch use of freed + memory. + +config MAGIC_SYSRQ + bool "Magic SysRq key" + depends on DEBUG_KERNEL + help + If you say Y here, you will have some control over the system even + if the system crashes for example during kernel debugging (e.g., you + will be able to flush the buffer cache to disk, reboot the system + immediately or dump some status information). This is accomplished + by pressing various keys while holding SysRq (Alt+PrintScreen). It + also works on a serial console (on PC hardware at least), if you + send a BREAK and then within 5 seconds a command keypress. The + keys are documented in <file:Documentation/sysrq.txt>. Don't say Y + unless you really know what this hack does. + +config DEBUG_SPINLOCK + bool "Spinlock debugging" + depends on DEBUG_KERNEL + help + Say Y here and build SMP to catch missing spinlock initialization + and certain other kinds of spinlock errors commonly made. This is + best used in conjunction with the NMI watchdog so that spinlock + deadlocks are also debuggable. + +config DEBUG_WAITQ + bool "Wait queue debugging" + depends on DEBUG_KERNEL + +config DEBUG_BUGVERBOSE + bool "Verbose BUG() reporting (adds 70K)" + depends on DEBUG_KERNEL + help + Say Y here to make BUG() panics output the file name and line number + of the BUG call as well as the EIP and oops trace. This aids + debugging but costs about 70-100K of memory. + +config DEBUG_ERRORS + bool "Verbose kernel error messages" + depends on DEBUG_KERNEL + help + This option controls verbose debugging information which can be + printed when the kernel detects an internal error. This debugging + information is useful to kernel hackers when tracking down problems, + but mostly meaningless to other people. It's safe to say Y unless + you are concerned with the code size or don't want to see these + messages. + +config KALLSYMS + bool "Load all symbols for debugging/kksymoops" + depends on DEBUG_KERNEL + help + Say Y here to let the kernel print out symbolic crash information and + symbolic stack backtraces. This increases the size of the kernel + somewhat, as all symbols have to be loaded into the kernel image. + +# These options are only for real kernel hackers who want to get their hands dirty. +config DEBUG_LL + bool "Kernel low-level debugging functions" + depends on DEBUG_KERNEL + help + Say Y here to include definitions of printascii, printchar, printhex + in the kernel. This is helpful if you are debugging code that + executes before the console is initialized. + +endmenu + +source "security/Kconfig" + +source "crypto/Kconfig" + +source "lib/Kconfig" + diff -Nru a/arch/arm26/Makefile b/arch/arm26/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/Makefile Mon Jun 9 23:16:20 2003 @@ -0,0 +1,126 @@ +# +# arch/arm26/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) 1995-2001 by Russell King + +LDFLAGS_vmlinux :=-p -X +LDFLAGS_BLOB :=--format binary +AFLAGS_vmlinux.lds.o = -DTEXTADDR=$(TEXTADDR) -DDATAADDR=$(DATAADDR) +OBJCOPYFLAGS :=-O binary -R .note -R .comment -S +GZFLAGS :=-9 +#CFLAGS +=-pipe +CFLAGS :=$(CFLAGS:-O2=-Os) + +ifeq ($(CONFIG_FRAME_POINTER),y) +CFLAGS +=-fno-omit-frame-pointer -mno-sched-prolog +endif + +ifeq ($(CONFIG_DEBUG_INFO),y) +CFLAGS +=-g +endif + +# Force -mno-fpu to be passed to the assembler. Some versions of gcc don't +# do this with -msoft-float +CFLAGS_BOOT :=-mapcs-26 -mcpu=arm3 -mshort-load-bytes -msoft-float -Wa,-mno-fpu -Uarm +CFLAGS +=-mapcs-26 -mcpu=arm3 -mshort-load-bytes -msoft-float -Wa,-mno-fpu -Uarm +AFLAGS +=-mapcs-26 -mcpu=arm3 -mno-fpu -msoft-float -Wa,-mno-fpu + +#Default value +DATAADDR := . + +ifeq ($(CONFIG_CPU_26),y) +head-y := arch/arm26/machine/head.o arch/arm26/kernel/init_task.o +LDFLAGS_BLOB += --oformat elf32-littlearm + ifeq ($(CONFIG_ROM_KERNEL),y) + DATAADDR := 0x02080000 + textaddr-y := 0x03800000 + else + textaddr-y := 0x02080000 + endif +endif + +TEXTADDR := $(textaddr-y) +ifeq ($(incdir-y),) +incdir-y := +endif +INCDIR := + +export MACHINE TEXTADDR GZFLAGS CFLAGS_BOOT + +# If we have a machine-specific directory, then include it in the build. +core-y += arch/arm26/kernel/ arch/arm26/mm/ arch/arm26/machine/ +core-$(CONFIG_FPE_NWFPE) += arch/arm26/nwfpe/ + +libs-y += arch/arm26/lib/ + +# Default target when executing plain make +all: zImage + +boot := arch/arm26/boot + +prepare: include/asm-$(ARCH)/asm_offsets.h +CLEAN_FILES += include/asm-$(ARCH)/asm_offsets.h + + +.PHONY: maketools FORCE +maketools: FORCE + + +# Convert bzImage to zImage +bzImage: vmlinux + $(Q)$(MAKE) $(build)=$(boot) $(boot)/zImage + +zImage Image bootpImage: vmlinux + $(Q)$(MAKE) $(build)=$(boot) $(boot)/$@ + +zinstall install: vmlinux + $(Q)$(MAKE) $(build)=$(boot) $@ + +# We use MRPROPER_FILES and CLEAN_FILES now +archclean: + $(Q)$(MAKE) $(clean)=$(boot) + +# My testing targets (that short circuit a few dependencies) +zImg:; $(Q)$(MAKE) $(build)=$(boot) $(boot)/zImage +Img:; $(Q)$(MAKE) $(build)=$(boot) $(boot)/Image +bp:; $(Q)$(MAKE) $(build)=$(boot) $(boot)/bootpImage +i:; $(Q)$(MAKE) $(build)=$(boot) install +zi:; $(Q)$(MAKE) $(build)=$(boot) zinstall + +# +# Configuration targets. Use these to select a +# configuration for your architecture +%_config: + @( \ + CFG=$(@:_config=); \ + if [ -f arch/arm26/def-configs/$$CFG ]; then \ + [ -f .config ] && mv -f .config .config.old; \ + cp arch/arm26/def-configs/$$CFG .config; \ + echo "*** Default configuration for $$CFG installed"; \ + echo "*** Next, you may run 'make oldconfig'"; \ + else \ + echo "$$CFG does not exist"; \ + fi; \ + ) + +arch/$(ARCH)/kernel/asm-offsets.s: include/asm include/linux/version.h \ + include/config/MARKER + +include/asm-$(ARCH)/asm_offsets.h: arch/$(ARCH)/kernel/asm-offsets.s + $(call filechk,gen-asm-offsets) + +define archhelp + echo '* zImage - Compressed kernel image (arch/$(ARCH)/boot/zImage)' + echo ' Image - Uncompressed kernel image (arch/$(ARCH)/boot/Image)' + echo ' bootpImage - Combined zImage and initial RAM disk' + echo ' initrd - Create an initial image' + echo ' install - Install uncompressed kernel' + echo ' zinstall - Install compressed kernel' + echo ' Install using (your) ~/bin/installkernel or' + echo ' (distribution) /sbin/installkernel or' + echo ' install to $$(INSTALL_PATH) and run lilo' +endef diff -Nru a/arch/arm26/boot/Makefile b/arch/arm26/boot/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/boot/Makefile Mon Jun 9 23:16:20 2003 @@ -0,0 +1,69 @@ +# +# arch/arm/boot/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) 1995-2002 Russell King +# + +# Note: the following conditions must always be true: +# ZRELADDR == virt_to_phys(TEXTADDR) +# PARAMS_PHYS must be with 4MB of ZRELADDR +# INITRD_PHYS must be in RAM + + zreladdr-y := 0x02080000 +params_phys-y := 0x0207c000 +initrd_phys-y := 0x02180000 + +ZRELADDR := 0x02080000 +ZTEXTADDR := 0x0207c000 +PARAMS_PHYS := $(params_phys-y) +INITRD_PHYS := 0x02180000 + +# We now have a PIC decompressor implementation. Decompressors running +# from RAM should not define ZTEXTADDR. Decompressors running directly +# from ROM or Flash must define ZTEXTADDR (preferably via the config) +# FIXME: Previous assignment to ztextaddr-y is lost here. See SHARK +ifeq ($(CONFIG_ZBOOT_ROM),y) +ZTEXTADDR := $(CONFIG_ZBOOT_ROM_TEXT) +ZBSSADDR := $(CONFIG_ZBOOT_ROM_BSS) +else +ZTEXTADDR := 0 +ZBSSADDR := ALIGN(4) +endif + +export ZTEXTADDR ZBSSADDR ZRELADDR INITRD_PHYS PARAMS_PHYS + +targets := Image zImage bootpImage + +$(obj)/Image: vmlinux FORCE + $(call if_changed,objcopy) + @echo ' Kernel: $@ is ready' + +$(obj)/zImage: $(obj)/compressed/vmlinux FORCE + $(call if_changed,objcopy) + @echo ' Kernel: $@ is ready' + +$(obj)/compressed/vmlinux: vmlinux FORCE + $(Q)$(MAKE) $(build)=$(obj)/compressed $@ + +.PHONY: initrd +initrd: + @test "$(INITRD_PHYS)" != "" || \ + (echo This machine does not support INITRD; exit -1) + @test "$(INITRD)" != "" || \ + (echo You must specify INITRD; exit -1) + +install: $(obj)/Image + $(CONFIG_SHELL) $(obj)/install.sh \ + $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) \ + $(obj)/Image System.map "$(INSTALL_PATH)" + +zinstall: $(obj)/zImage + $(CONFIG_SHELL) $(obj)/install.sh \ + $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) \ + $(obj)/zImage System.map "$(INSTALL_PATH)" + +subdir- := compressed diff -Nru a/arch/arm26/boot/compressed/Makefile b/arch/arm26/boot/compressed/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/boot/compressed/Makefile Mon Jun 9 23:16:20 2003 @@ -0,0 +1,50 @@ +# +# linux/arch/arm26/boot/compressed/Makefile +# +# create a compressed vmlinuz image from the original vmlinux +# +# Note! ZTEXTADDR, ZBSSADDR and ZRELADDR are now exported +# from arch/arm26/boot/Makefile +# + +HEAD = head.o +OBJS = misc.o +FONTC = drivers/video/console/font_acorn_8x8.c + +OBJS += ll_char_wr.o font.o +CFLAGS_misc.o := -DPARAMS_PHYS=$(PARAMS_PHYS) + +targets := vmlinux vmlinux.lds piggy piggy.gz piggy.o font.o head.o $(OBJS) + +SEDFLAGS = s/TEXT_START/$(ZTEXTADDR)/;s/LOAD_ADDR/$(ZRELADDR)/;s/BSS_START/$(ZBSSADDR)/ + +EXTRA_CFLAGS := $(CFLAGS_BOOT) -fpic +EXTRA_AFLAGS := -traditional + +LDFLAGS_vmlinux := -p -X \ + $(shell $(CC) $(CFLAGS)) -T + +$(obj)/vmlinux: $(obj)/vmlinux.lds $(obj)/$(HEAD) $(obj)/piggy.o \ + $(addprefix $(obj)/, $(OBJS)) FORCE + $(call if_changed,ld) + @: + + +$(obj)/piggy: vmlinux FORCE + $(call if_changed,objcopy) + +$(obj)/piggy.gz: $(obj)/piggy FORCE + $(call if_changed,gzip) + +LDFLAGS_piggy.o := -r -b binary +$(obj)/piggy.o: $(obj)/piggy.gz FORCE + $(call if_changed,ld) + +$(obj)/font.o: $(FONTC) + $(CC) $(CFLAGS) -Dstatic= -c $(FONTC) -o $(obj)/font.o + +$(obj)/vmlinux.lds: $(obj)/vmlinux.lds.in Makefile arch/arm26/boot/Makefile .config + @sed "$(SEDFLAGS)" < $< > $@ + +$(obj)/misc.o: $(obj)/misc.c $(obj)/uncompress.h lib/inflate.c + diff -Nru a/arch/arm26/boot/compressed/head.S b/arch/arm26/boot/compressed/head.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/boot/compressed/head.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,517 @@ +/* + * linux/arch/arm/boot/compressed/head.S + * + * Copyright (C) 1996-2002 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/config.h> +#include <linux/linkage.h> + +/* + * Debugging stuff + * + * Note that these macros must not contain any code which is not + * 100% relocatable. Any attempt to do so will result in a crash. + * Please select one of the following when turning on debugging. + */ + + .macro kputc,val + mov r0, \val + bl putc + .endm + + .macro kphex,val,len + mov r0, \val + mov r1, #\len + bl phex + .endm + + .macro debug_reloc_start + .endm + + .macro debug_reloc_end + .endm + + .section ".start", #alloc, #execinstr +/* + * sort out different calling conventions + */ + .align +start: + .type start,#function + .rept 8 + mov r0, r0 + .endr + + b 1f + .word 0x016f2818 @ Magic numbers to help the loader + .word start @ absolute load/run zImage address + .word _edata @ zImage end address +1: mov r7, r1 @ save architecture ID + mov r8, #0 @ save r0 + teqp pc, #0x0c000003 @ turn off interrupts + + .text + adr r0, LC0 + ldmia r0, {r1, r2, r3, r4, r5, r6, ip, sp} + subs r0, r0, r1 @ calculate the delta offset + + teq r0, #0 @ if delta is zero, we're + beq not_relocated @ running at the address we + @ were linked at. + + add r2, r2, r0 @ different address, so we + add r3, r3, r0 @ need to fix up various + add r5, r5, r0 @ pointers. + add r6, r6, r0 + add ip, ip, r0 + add sp, sp, r0 + +1: ldr r1, [r6, #0] @ relocate entries in the GOT + add r1, r1, r0 @ table. This fixes up the + str r1, [r6], #4 @ C references. + cmp r6, ip + blo 1b + +not_relocated: mov r0, #0 +1: str r0, [r2], #4 @ clear bss + str r0, [r2], #4 + str r0, [r2], #4 + str r0, [r2], #4 + cmp r2, r3 + blo 1b + + bl cache_on + + mov r1, sp @ malloc space above stack + add r2, sp, #0x10000 @ 64k max + +/* + * Check to see if we will overwrite ourselves. + * r4 = final kernel address + * r5 = start of this image + * r2 = end of malloc space (and therefore this image) + * We basically want: + * r4 >= r2 -> OK + * r4 + image length <= r5 -> OK + */ + cmp r4, r2 + bhs wont_overwrite + add r0, r4, #4096*1024 @ 4MB largest kernel size + cmp r0, r5 + bls wont_overwrite + + mov r5, r2 @ decompress after malloc space + mov r0, r5 + mov r3, r7 + bl decompress_kernel + + add r0, r0, #127 + bic r0, r0, #127 @ align the kernel length +/* + * r0 = decompressed kernel length + * r1-r3 = unused + * r4 = kernel execution address + * r5 = decompressed kernel start + * r6 = processor ID + * r7 = architecture ID + * r8-r14 = unused + */ + add r1, r5, r0 @ end of decompressed kernel + adr r2, reloc_start + ldr r3, LC1 + add r3, r2, r3 +1: ldmia r2!, {r8 - r13} @ copy relocation code + stmia r1!, {r8 - r13} + ldmia r2!, {r8 - r13} + stmia r1!, {r8 - r13} + cmp r2, r3 + blo 1b + + bl cache_clean_flush + add pc, r5, r0 @ call relocation code + +/* + * We're not in danger of overwriting ourselves. Do this the simple way. + * + * r4 = kernel execution address + * r7 = architecture ID + */ +wont_overwrite: mov r0, r4 + mov r3, r7 + bl decompress_kernel + b call_kernel + + .type LC0, #object +LC0: .word LC0 @ r1 + .word __bss_start @ r2 + .word _end @ r3 + .word _load_addr @ r4 + .word _start @ r5 + .word _got_start @ r6 + .word _got_end @ ip + .word user_stack+4096 @ sp +LC1: .word reloc_end - reloc_start + .size LC0, . - LC0 + +/* + * Turn on the cache. We need to setup some page tables so that we + * can have both the I and D caches on. + * + * We place the page tables 16k down from the kernel execution address, + * and we hope that nothing else is using it. If we're using it, we + * will go pop! + * + * On entry, + * r4 = kernel execution address + * r6 = processor ID + * r7 = architecture number + * r8 = run-time address of "start" + * On exit, + * r1, r2, r3, r8, r9, r12 corrupted + * This routine must preserve: + * r4, r5, r6, r7 + */ + .align 5 +cache_on: mov r3, #8 @ cache_on function + b call_cache_fn + +__setup_mmu: sub r3, r4, #16384 @ Page directory size + bic r3, r3, #0xff @ Align the pointer + bic r3, r3, #0x3f00 +/* + * Initialise the page tables, turning on the cacheable and bufferable + * bits for the RAM area only. + */ + mov r0, r3 + mov r8, r0, lsr #18 + mov r8, r8, lsl #18 @ start of RAM + add r9, r8, #0x10000000 @ a reasonable RAM size + mov r1, #0x12 + orr r1, r1, #3 << 10 + add r2, r3, #16384 +1: cmp r1, r8 @ if virt > start of RAM + orrhs r1, r1, #0x0c @ set cacheable, bufferable + cmp r1, r9 @ if virt > end of RAM + bichs r1, r1, #0x0c @ clear cacheable, bufferable + str r1, [r0], #4 @ 1:1 mapping + add r1, r1, #1048576 + teq r0, r2 + bne 1b +/* + * If ever we are running from Flash, then we surely want the cache + * to be enabled also for our execution instance... We map 2MB of it + * so there is no map overlap problem for up to 1 MB compressed kernel. + * If the execution is in RAM then we would only be duplicating the above. + */ + mov r1, #0x1e + orr r1, r1, #3 << 10 + mov r2, pc, lsr #20 + orr r1, r1, r2, lsl #20 + add r0, r3, r2, lsl #2 + str r1, [r0], #4 + add r1, r1, #1048576 + str r1, [r0] + mov pc, lr + +__armv4_cache_on: + mov r12, lr + bl __setup_mmu + mov r0, #0 + mcr p15, 0, r0, c7, c10, 4 @ drain write buffer + mcr p15, 0, r0, c8, c7, 0 @ flush I,D TLBs + mrc p15, 0, r0, c1, c0, 0 @ read control reg + orr r0, r0, #0x1000 @ I-cache enable + orr r0, r0, #0x0030 + b __common_cache_on + +__arm6_cache_on: + mov r12, lr + bl __setup_mmu + mov r0, #0 + mcr p15, 0, r0, c7, c0, 0 @ invalidate whole cache v3 + mcr p15, 0, r0, c5, c0, 0 @ invalidate whole TLB v3 + mov r0, #0x30 +__common_cache_on: +#ifndef DEBUG + orr r0, r0, #0x000d @ Write buffer, mmu +#endif + mov r1, #-1 + mcr p15, 0, r3, c2, c0, 0 @ load page table pointer + mcr p15, 0, r1, c3, c0, 0 @ load domain access control + mcr p15, 0, r0, c1, c0, 0 @ load control register + mov pc, r12 + +/* + * All code following this line is relocatable. It is relocated by + * the above code to the end of the decompressed kernel image and + * executed there. During this time, we have no stacks. + * + * r0 = decompressed kernel length + * r1-r3 = unused + * r4 = kernel execution address + * r5 = decompressed kernel start + * r6 = processor ID + * r7 = architecture ID + * r8-r14 = unused + */ + .align 5 +reloc_start: add r8, r5, r0 + debug_reloc_start + mov r1, r4 +1: + .rept 4 + ldmia r5!, {r0, r2, r3, r9 - r13} @ relocate kernel + stmia r1!, {r0, r2, r3, r9 - r13} + .endr + + cmp r5, r8 + blo 1b + debug_reloc_end + +call_kernel: bl cache_clean_flush + bl cache_off + mov r0, #0 + mov r1, r7 @ restore architecture number + mov pc, r4 @ call kernel + +/* + * Here follow the relocatable cache support functions for the + * various processors. This is a generic hook for locating an + * entry and jumping to an instruction at the specified offset + * from the start of the block. Please note this is all position + * independent code. + * + * r1 = corrupted + * r2 = corrupted + * r3 = block offset + * r6 = corrupted + * r12 = corrupted + */ + +call_cache_fn: adr r12, proc_types + mrc p15, 0, r6, c0, c0 @ get processor ID +1: ldr r1, [r12, #0] @ get value + ldr r2, [r12, #4] @ get mask + eor r1, r1, r6 @ (real ^ match) + tst r1, r2 @ & mask + addeq pc, r12, r3 @ call cache function + add r12, r12, #4*5 + b 1b + +/* + * Table for cache operations. This is basically: + * - CPU ID match + * - CPU ID mask + * - 'cache on' method instruction + * - 'cache off' method instruction + * - 'cache flush' method instruction + * + * We match an entry using: ((real_id ^ match) & mask) == 0 + * + * Writethrough caches generally only need 'on' and 'off' + * methods. Writeback caches _must_ have the flush method + * defined. + */ + .type proc_types,#object +proc_types: + .word 0x41560600 @ ARM6/610 + .word 0xffffffe0 + b __arm6_cache_off @ works, but slow + b __arm6_cache_off + mov pc, lr +@ b __arm6_cache_on @ untested +@ b __arm6_cache_off +@ b __armv3_cache_flush + + .word 0x41007000 @ ARM7/710 + .word 0xfff8fe00 + b __arm7_cache_off + b __arm7_cache_off + mov pc, lr + + .word 0x41807200 @ ARM720T (writethrough) + .word 0xffffff00 + b __armv4_cache_on + b __armv4_cache_off + mov pc, lr + + .word 0x41129200 @ ARM920T + .word 0xff00fff0 + b __armv4_cache_on + b __armv4_cache_off + b __armv4_cache_flush + + .word 0x4401a100 @ sa110 / sa1100 + .word 0xffffffe0 + b __armv4_cache_on + b __armv4_cache_off + b __armv4_cache_flush + + .word 0x6901b110 @ sa1110 + .word 0xfffffff0 + b __armv4_cache_on + b __armv4_cache_off + b __armv4_cache_flush + + .word 0x69050000 @ xscale + .word 0xffff0000 + b __armv4_cache_on + b __armv4_cache_off + b __armv4_cache_flush + + .word 0 @ unrecognised type + .word 0 + mov pc, lr + mov pc, lr + mov pc, lr + + .size proc_types, . - proc_types + +/* + * Turn off the Cache and MMU. ARMv3 does not support + * reading the control register, but ARMv4 does. + * + * On entry, r6 = processor ID + * On exit, r0, r1, r2, r3, r12 corrupted + * This routine must preserve: r4, r6, r7 + */ + .align 5 +cache_off: mov r3, #12 @ cache_off function + b call_cache_fn + +__armv4_cache_off: + mrc p15, 0, r0, c1, c0 + bic r0, r0, #0x000d + mcr p15, 0, r0, c1, c0 @ turn MMU and cache off + mov r0, #0 + mcr p15, 0, r0, c7, c7 @ invalidate whole cache v4 + mcr p15, 0, r0, c8, c7 @ invalidate whole TLB v4 + mov pc, lr + +__arm6_cache_off: + mov r0, #0x00000030 @ ARM6 control reg. + b __armv3_cache_off + +__arm7_cache_off: + mov r0, #0x00000070 @ ARM7 control reg. + b __armv3_cache_off + +__armv3_cache_off: + mcr p15, 0, r0, c1, c0, 0 @ turn MMU and cache off + mov r0, #0 + mcr p15, 0, r0, c7, c0, 0 @ invalidate whole cache v3 + mcr p15, 0, r0, c5, c0, 0 @ invalidate whole TLB v3 + mov pc, lr + +/* + * Clean and flush the cache to maintain consistency. + * + * On entry, + * r6 = processor ID + * On exit, + * r1, r2, r3, r12 corrupted + * This routine must preserve: + * r0, r4, r5, r6, r7 + */ + .align 5 +cache_clean_flush: + mov r3, #16 + b call_cache_fn + +__armv4_cache_flush: + bic r1, pc, #31 + add r2, r1, #65536 @ 2x the largest dcache size +1: ldr r12, [r1], #32 @ s/w flush D cache + teq r1, r2 + bne 1b + + mcr p15, 0, r1, c7, c7, 0 @ flush I cache + mcr p15, 0, r1, c7, c10, 4 @ drain WB + mov pc, lr + +__armv3_cache_flush: + mov r1, #0 + mcr p15, 0, r0, c7, c0, 0 @ invalidate whole cache v3 + mov pc, lr + +/* + * Various debugging routines for printing hex characters and + * memory, which again must be relocatable. + */ +#ifdef DEBUG + .type phexbuf,#object +phexbuf: .space 12 + .size phexbuf, . - phexbuf + +phex: adr r3, phexbuf + mov r2, #0 + strb r2, [r3, r1] +1: subs r1, r1, #1 + movmi r0, r3 + bmi puts + and r2, r0, #15 + mov r0, r0, lsr #4 + cmp r2, #10 + addge r2, r2, #7 + add r2, r2, #'0' + strb r2, [r3, r1] + b 1b + +puts: loadsp r3 +1: ldrb r2, [r0], #1 + teq r2, #0 + moveq pc, lr +2: writeb r2 + mov r1, #0x00020000 +3: subs r1, r1, #1 + bne 3b + teq r2, #'\n' + moveq r2, #'\r' + beq 2b + teq r0, #0 + bne 1b + mov pc, lr +putc: + mov r2, r0 + mov r0, #0 + loadsp r3 + b 2b + +memdump: mov r12, r0 + mov r10, lr + mov r11, #0 +2: mov r0, r11, lsl #2 + add r0, r0, r12 + mov r1, #8 + bl phex + mov r0, #':' + bl putc +1: mov r0, #' ' + bl putc + ldr r0, [r12, r11, lsl #2] + mov r1, #8 + bl phex + and r0, r11, #7 + teq r0, #3 + moveq r0, #' ' + bleq putc + and r0, r11, #7 + add r11, r11, #1 + teq r0, #7 + bne 1b + mov r0, #'\n' + bl putc + cmp r11, #64 + blt 2b + mov pc, r10 +#endif + +reloc_end: + + .align + .section ".stack", "aw" +user_stack: .space 4096 diff -Nru a/arch/arm26/boot/compressed/hw-bse.c b/arch/arm26/boot/compressed/hw-bse.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/boot/compressed/hw-bse.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,74 @@ +/* + * Bright Star Engineering Inc. + * + * code for readng parameters from the + * parameter blocks of the boot block + * flash memory + * + */ + +static int strcmp(const char *s1, const char *s2) +{ + while (*s1 != '\0' && *s1 == *s2) + { + s1++; + s2++; + } + + return (*(unsigned char *) s1) - (*(unsigned char *) s2); +} + +struct pblk_t { + char type; + unsigned short size; +}; + +static char *bse_getflashparam(char *name) { + unsigned int esize; + char *q,*r; + unsigned char *p,*e; + struct pblk_t *thepb = (struct pblk_t *) 0x00004000; + struct pblk_t *altpb = (struct pblk_t *) 0x00006000; + if (thepb->type&1) { + if (altpb->type&1) { + /* no valid param block */ + return (char*)0; + } else { + /* altpb is valid */ + struct pblk_t *tmp; + tmp = thepb; + thepb = altpb; + altpb = tmp; + } + } + p = (char*)thepb + sizeof(struct pblk_t); + e = p + thepb->size; + while (p < e) { + q = p; + esize = *p; + if (esize == 0xFF) break; + if (esize == 0) break; + if (esize > 127) { + esize = (esize&0x7F)<<8 | p[1]; + q++; + } + q++; + r=q; + if (*r && ((name == 0) || (!strcmp(name,r)))) { + while (*q++) ; + return q; + } + p+=esize; + } + return (char*)0; +} + +void bse_setup(void) { + /* extract the linux cmdline from flash */ + char *name=bse_getflashparam("linuxboot"); + char *x = (char *)0xc0000100; + if (name) { + while (*name) *x++=*name++; + } + *x=0; +} diff -Nru a/arch/arm26/boot/compressed/ll_char_wr.S b/arch/arm26/boot/compressed/ll_char_wr.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/boot/compressed/ll_char_wr.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,162 @@ +/* + * linux/arch/arm/lib/ll_char_wr.S + * + * Copyright (C) 1995, 1996 Russell King. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Speedups & 1bpp code (C) 1996 Philip Blundell & Russell King. + * + * 10-04-96 RMK Various cleanups & reduced register usage. + * 08-04-98 RMK Shifts re-ordered + */ + +@ Regs: [] = corruptible +@ {} = used +@ () = do not use + +#include <linux/linkage.h> +#include <asm/assembler.h> + .text + +#define BOLD 0x01 +#define ITALIC 0x02 +#define UNDERLINE 0x04 +#define FLASH 0x08 +#define INVERSE 0x10 + +LC0: .word bytes_per_char_h + .word video_size_row + .word acorndata_8x8 + .word con_charconvtable + +ENTRY(ll_write_char) + stmfd sp!, {r4 - r7, lr} +@ +@ Smashable regs: {r0 - r3}, [r4 - r7], (r8 - fp), [ip], (sp), [lr], (pc) +@ + eor ip, r1, #UNDERLINE << 9 +/* + * calculate colours + */ + tst r1, #INVERSE << 9 + moveq r2, r1, lsr #16 + moveq r3, r1, lsr #24 + movne r2, r1, lsr #24 + movne r3, r1, lsr #16 + and r3, r3, #255 + and r2, r2, #255 +/* + * calculate offset into character table + */ + mov r1, r1, lsl #23 + mov r1, r1, lsr #20 +/* + * calculate offset required for each row [maybe I should make this an argument to this fn. + * Have to see what the register usage is like in the calling routines. + */ + adr r4, LC0 + ldmia r4, {r4, r5, r6, lr} + ldr r4, [r4] + ldr r5, [r5] +/* + * Go to resolution-dependent routine... + */ + cmp r4, #4 + blt Lrow1bpp + eor r2, r3, r2 @ Create eor mask to change colour from bg + orr r3, r3, r3, lsl #8 @ to fg. + orr r3, r3, r3, lsl #16 + add r0, r0, r5, lsl #3 @ Move to bottom of character + add r1, r1, #7 + ldrb r7, [r6, r1] + tst ip, #UNDERLINE << 9 + eoreq r7, r7, #255 + teq r4, #8 + beq Lrow8bpplp +@ +@ Smashable regs: {r0 - r3}, [r4], {r5 - r7}, (r8 - fp), [ip], (sp), {lr}, (pc) +@ + orr r3, r3, r3, lsl #4 +Lrow4bpplp: ldr r7, [lr, r7, lsl #2] + mul r7, r2, r7 + tst r1, #7 @ avoid using r7 directly after + eor ip, r3, r7 + str ip, [r0, -r5]! + LOADREGS(eqfd, sp!, {r4 - r7, pc}) + sub r1, r1, #1 + ldrb r7, [r6, r1] + ldr r7, [lr, r7, lsl #2] + mul r7, r2, r7 + tst r1, #7 @ avoid using r7 directly after + eor ip, r3, r7 + str ip, [r0, -r5]! + subne r1, r1, #1 + ldrneb r7, [r6, r1] + bne Lrow4bpplp + LOADREGS(fd, sp!, {r4 - r7, pc}) + +@ +@ Smashable regs: {r0 - r3}, [r4], {r5 - r7}, (r8 - fp), [ip], (sp), {lr}, (pc) +@ +Lrow8bpplp: mov ip, r7, lsr #4 + ldr ip, [lr, ip, lsl #2] + mul r4, r2, ip + and ip, r7, #15 @ avoid r4 + ldr ip, [lr, ip, lsl #2] @ avoid r4 + mul ip, r2, ip @ avoid r4 + eor r4, r3, r4 @ avoid ip + tst r1, #7 @ avoid ip + sub r0, r0, r5 @ avoid ip + eor ip, r3, ip + stmia r0, {r4, ip} + LOADREGS(eqfd, sp!, {r4 - r7, pc}) + sub r1, r1, #1 + ldrb r7, [r6, r1] + mov ip, r7, lsr #4 + ldr ip, [lr, ip, lsl #2] + mul r4, r2, ip + and ip, r7, #15 @ avoid r4 + ldr ip, [lr, ip, lsl #2] @ avoid r4 + mul ip, r2, ip @ avoid r4 + eor r4, r3, r4 @ avoid ip + tst r1, #7 @ avoid ip + sub r0, r0, r5 @ avoid ip + eor ip, r3, ip + stmia r0, {r4, ip} + subne r1, r1, #1 + ldrneb r7, [r6, r1] + bne Lrow8bpplp + LOADREGS(fd, sp!, {r4 - r7, pc}) + +@ +@ Smashable regs: {r0 - r3}, [r4], {r5, r6}, [r7], (r8 - fp), [ip], (sp), [lr], (pc) +@ +Lrow1bpp: add r6, r6, r1 + ldmia r6, {r4, r7} + tst ip, #INVERSE << 9 + mvnne r4, r4 + mvnne r7, r7 + strb r4, [r0], r5 + mov r4, r4, lsr #8 + strb r4, [r0], r5 + mov r4, r4, lsr #8 + strb r4, [r0], r5 + mov r4, r4, lsr #8 + strb r4, [r0], r5 + strb r7, [r0], r5 + mov r7, r7, lsr #8 + strb r7, [r0], r5 + mov r7, r7, lsr #8 + strb r7, [r0], r5 + mov r7, r7, lsr #8 + tst ip, #UNDERLINE << 9 + mvneq r7, r7 + strb r7, [r0], r5 + LOADREGS(fd, sp!, {r4 - r7, pc}) + + .bss +ENTRY(con_charconvtable) + .space 1024 diff -Nru a/arch/arm26/boot/compressed/misc.c b/arch/arm26/boot/compressed/misc.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/boot/compressed/misc.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,316 @@ +/* + * misc.c + * + * This is a collection of several routines from gzip-1.0.3 + * adapted for Linux. + * + * malloc by Hannu Savolainen 1993 and Matthias Urlichs 1994 + * + * Modified for ARM Linux by Russell King + * + * Nicolas Pitre <nico@visuaide.com> 1999/04/14 : + * For this code to run directly from Flash, all constant variables must + * be marked with 'const' and all other variables initialized at run-time + * only. This way all non constant variables will end up in the bss segment, + * which should point to addresses in RAM and cleared to 0 on start. + * This allows for a much quicker boot time. + */ + +unsigned int __machine_arch_type; + +#include <linux/kernel.h> + +#include <asm/uaccess.h> +#include "uncompress.h" + +#ifdef STANDALONE_DEBUG +#define puts printf +#endif + +#define __ptr_t void * + +/* + * Optimised C version of memzero for the ARM. + */ +void __memzero (__ptr_t s, size_t n) +{ + union { void *vp; unsigned long *ulp; unsigned char *ucp; } u; + int i; + + u.vp = s; + + for (i = n >> 5; i > 0; i--) { + *u.ulp++ = 0; + *u.ulp++ = 0; + *u.ulp++ = 0; + *u.ulp++ = 0; + *u.ulp++ = 0; + *u.ulp++ = 0; + *u.ulp++ = 0; + *u.ulp++ = 0; + } + + if (n & 1 << 4) { + *u.ulp++ = 0; + *u.ulp++ = 0; + *u.ulp++ = 0; + *u.ulp++ = 0; + } + + if (n & 1 << 3) { + *u.ulp++ = 0; + *u.ulp++ = 0; + } + + if (n & 1 << 2) + *u.ulp++ = 0; + + if (n & 1 << 1) { + *u.ucp++ = 0; + *u.ucp++ = 0; + } + + if (n & 1) + *u.ucp++ = 0; +} + +static inline __ptr_t memcpy(__ptr_t __dest, __const __ptr_t __src, + size_t __n) +{ + int i = 0; + unsigned char *d = (unsigned char *)__dest, *s = (unsigned char *)__src; + + for (i = __n >> 3; i > 0; i--) { + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + } + + if (__n & 1 << 2) { + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + } + + if (__n & 1 << 1) { + *d++ = *s++; + *d++ = *s++; + } + + if (__n & 1) + *d++ = *s++; + + return __dest; +} + +/* + * gzip delarations + */ +#define OF(args) args +#define STATIC static + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +#define WSIZE 0x8000 /* Window size must be at least 32k, */ + /* and a power of two */ + +static uch *inbuf; /* input buffer */ +static uch window[WSIZE]; /* Sliding window buffer */ + +static unsigned insize; /* valid bytes in inbuf */ +static unsigned inptr; /* index of next byte to be processed in inbuf */ +static unsigned outcnt; /* bytes in output buffer */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ +#define RESERVED 0xC0 /* bit 6,7: reserved */ + +#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) + +/* Diagnostic functions */ +#ifdef DEBUG +# define Assert(cond,msg) {if(!(cond)) error(msg);} +# define Trace(x) fprintf x +# define Tracev(x) {if (verbose) fprintf x ;} +# define Tracevv(x) {if (verbose>1) fprintf x ;} +# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} +# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + +static int fill_inbuf(void); +static void flush_window(void); +static void error(char *m); +static void gzip_mark(void **); +static void gzip_release(void **); + +extern char input_data[]; +extern char input_data_end[]; + +static uch *output_data; +static ulg output_ptr; +static ulg bytes_out; + +static void *malloc(int size); +static void free(void *where); +static void error(char *m); +static void gzip_mark(void **); +static void gzip_release(void **); + +static void puts(const char *); + +extern int end; +static ulg free_mem_ptr; +static ulg free_mem_ptr_end; + +#define HEAP_SIZE 0x2000 + +#include "../../../../lib/inflate.c" + +#ifndef STANDALONE_DEBUG +static void *malloc(int size) +{ + void *p; + + if (size <0) error("Malloc error\n"); + if (free_mem_ptr <= 0) error("Memory error\n"); + + free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */ + + p = (void *)free_mem_ptr; + free_mem_ptr += size; + + if (free_mem_ptr >= free_mem_ptr_end) + error("Out of memory"); + return p; +} + +static void free(void *where) +{ /* gzip_mark & gzip_release do the free */ +} + +static void gzip_mark(void **ptr) +{ + arch_decomp_wdog(); + *ptr = (void *) free_mem_ptr; +} + +static void gzip_release(void **ptr) +{ + arch_decomp_wdog(); + free_mem_ptr = (long) *ptr; +} +#else +static void gzip_mark(void **ptr) +{ +} + +static void gzip_release(void **ptr) +{ +} +#endif + +/* =========================================================================== + * Fill the input buffer. This is called only when the buffer is empty + * and at least one byte is really needed. + */ +int fill_inbuf(void) +{ + if (insize != 0) + error("ran out of input data\n"); + + inbuf = input_data; + insize = &input_data_end[0] - &input_data[0]; + + inptr = 1; + return inbuf[0]; +} + +/* =========================================================================== + * Write the output window window[0..outcnt-1] and update crc and bytes_out. + * (Used for the decompressed data only.) + */ +void flush_window(void) +{ + ulg c = crc; + unsigned n; + uch *in, *out, ch; + + in = window; + out = &output_data[output_ptr]; + for (n = 0; n < outcnt; n++) { + ch = *out++ = *in++; + c = crc_32_tab[((int)c ^ ch) & 0xff] ^ (c >> 8); + } + crc = c; + bytes_out += (ulg)outcnt; + output_ptr += (ulg)outcnt; + outcnt = 0; + puts("."); +} + +static void error(char *x) +{ + int ptr; + + puts("\n\n"); + puts(x); + puts("\n\n -- System halted"); + + while(1); /* Halt */ +} + +#ifndef STANDALONE_DEBUG + +ulg +decompress_kernel(ulg output_start, ulg free_mem_ptr_p, ulg free_mem_ptr_end_p, + int arch_id) +{ + output_data = (uch *)output_start; /* Points to kernel start */ + free_mem_ptr = free_mem_ptr_p; + free_mem_ptr_end = free_mem_ptr_end_p; + __machine_arch_type = arch_id; + + arch_decomp_setup(); + + makecrc(); + puts("Uncompressing Linux..."); + gunzip(); + puts(" done, booting the kernel.\n"); + return output_ptr; +} +#else + +char output_buffer[1500*1024]; + +int main() +{ + output_data = output_buffer; + + makecrc(); + puts("Uncompressing Linux..."); + gunzip(); + puts("done.\n"); + return 0; +} +#endif + diff -Nru a/arch/arm26/boot/compressed/ofw-shark.c b/arch/arm26/boot/compressed/ofw-shark.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/boot/compressed/ofw-shark.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,258 @@ +/* + * linux/arch/arm/boot/compressed/ofw-shark.c + * + * by Alexander Schulz + * + * This file is used to get some basic information + * about the memory layout of the shark we are running + * on. Memory is usually divided in blocks a 8 MB. + * And bootargs are copied from OpenFirmware. + */ + + +#include <linux/kernel.h> +#include <linux/types.h> +#include <asm/setup.h> +#include <asm/page.h> + + +asmlinkage void +create_params (unsigned long *buffer) +{ + /* Is there a better address? Also change in mach-shark/core.c */ + struct tag *tag = (struct tag *) 0x08003000; + int j,i,m,k,nr_banks,size; + unsigned char *c; + + /* Head of the taglist */ + tag->hdr.tag = ATAG_CORE; + tag->hdr.size = tag_size(tag_core); + tag->u.core.flags = FLAG_READONLY; + tag->u.core.pagesize = PAGE_SIZE; + tag->u.core.rootdev = 0; + + /* Build up one tagged block for each memory region */ + size=0; + nr_banks=(unsigned int) buffer[0]; + for (j=0;j<nr_banks;j++){ + /* search the lowest address and put it into the next entry */ + /* not a fast sort algorithm, but there are at most 8 entries */ + /* and this is used only once anyway */ + m=0xffffffff; + for (i=0;i<(unsigned int) buffer[0];i++){ + if (buffer[2*i+1]<m) { + m=buffer[2*i+1]; + k=i; + } + } + + tag = tag_next(tag); + tag->hdr.tag = ATAG_MEM; + tag->hdr.size = tag_size(tag_mem32); + tag->u.mem.size = buffer[2*k+2]; + tag->u.mem.start = buffer[2*k+1]; + + size += buffer[2*k+2]; + + buffer[2*k+1]=0xffffffff; /* mark as copied */ + } + + /* The command line */ + tag = tag_next(tag); + tag->hdr.tag = ATAG_CMDLINE; + + c=(unsigned char *)(&buffer[34]); + j=0; + while (*c) tag->u.cmdline.cmdline[j++]=*c++; + + tag->u.cmdline.cmdline[j]=0; + tag->hdr.size = (j + 7 + sizeof(struct tag_header)) >> 2; + + /* Hardware revision */ + tag = tag_next(tag); + tag->hdr.tag = ATAG_REVISION; + tag->hdr.size = tag_size(tag_revision); + tag->u.revision.rev = ((unsigned char) buffer[33])-'0'; + + /* End of the taglist */ + tag = tag_next(tag); + tag->hdr.tag = 0; + tag->hdr.size = 0; +} + + +typedef int (*ofw_handle_t)(void *); + +/* Everything below is called with a wrong MMU setting. + * This means: no string constants, no initialization of + * arrays, no global variables! This is ugly but I didn't + * want to write this in assembler :-) + */ + +int +of_decode_int(const unsigned char *p) +{ + unsigned int i = *p++ << 8; + i = (i + *p++) << 8; + i = (i + *p++) << 8; + return (i + *p); +} + +int +OF_finddevice(ofw_handle_t openfirmware, char *name) +{ + unsigned int args[8]; + char service[12]; + + service[0]='f'; + service[1]='i'; + service[2]='n'; + service[3]='d'; + service[4]='d'; + service[5]='e'; + service[6]='v'; + service[7]='i'; + service[8]='c'; + service[9]='e'; + service[10]='\0'; + + args[0]=(unsigned int)service; + args[1]=1; + args[2]=1; + args[3]=(unsigned int)name; + + if (openfirmware(args) == -1) + return -1; + return args[4]; +} + +int +OF_getproplen(ofw_handle_t openfirmware, int handle, char *prop) +{ + unsigned int args[8]; + char service[12]; + + service[0]='g'; + service[1]='e'; + service[2]='t'; + service[3]='p'; + service[4]='r'; + service[5]='o'; + service[6]='p'; + service[7]='l'; + service[8]='e'; + service[9]='n'; + service[10]='\0'; + + args[0] = (unsigned int)service; + args[1] = 2; + args[2] = 1; + args[3] = (unsigned int)handle; + args[4] = (unsigned int)prop; + + if (openfirmware(args) == -1) + return -1; + return args[5]; +} + +int +OF_getprop(ofw_handle_t openfirmware, int handle, char *prop, void *buf, unsigned int buflen) +{ + unsigned int args[8]; + char service[8]; + + service[0]='g'; + service[1]='e'; + service[2]='t'; + service[3]='p'; + service[4]='r'; + service[5]='o'; + service[6]='p'; + service[7]='\0'; + + args[0] = (unsigned int)service; + args[1] = 4; + args[2] = 1; + args[3] = (unsigned int)handle; + args[4] = (unsigned int)prop; + args[5] = (unsigned int)buf; + args[6] = buflen; + + if (openfirmware(args) == -1) + return -1; + return args[7]; +} + +asmlinkage void ofw_init(ofw_handle_t o, int *nomr, int *pointer) +{ + int phandle,i,mem_len,buffer[32]; + char temp[15]; + + temp[0]='/'; + temp[1]='m'; + temp[2]='e'; + temp[3]='m'; + temp[4]='o'; + temp[5]='r'; + temp[6]='y'; + temp[7]='\0'; + + phandle=OF_finddevice(o,temp); + + temp[0]='r'; + temp[1]='e'; + temp[2]='g'; + temp[3]='\0'; + + mem_len = OF_getproplen(o,phandle, temp); + OF_getprop(o,phandle, temp, buffer, mem_len); + *nomr=mem_len >> 3; + + for (i=0; i<=mem_len/4; i++) pointer[i]=of_decode_int((const unsigned char *)&buffer[i]); + + temp[0]='/'; + temp[1]='c'; + temp[2]='h'; + temp[3]='o'; + temp[4]='s'; + temp[5]='e'; + temp[6]='n'; + temp[7]='\0'; + + phandle=OF_finddevice(o,temp); + + temp[0]='b'; + temp[1]='o'; + temp[2]='o'; + temp[3]='t'; + temp[4]='a'; + temp[5]='r'; + temp[6]='g'; + temp[7]='s'; + temp[8]='\0'; + + mem_len = OF_getproplen(o,phandle, temp); + OF_getprop(o,phandle, temp, buffer, mem_len); + if (mem_len > 128) mem_len=128; + for (i=0; i<=mem_len/4; i++) pointer[i+33]=buffer[i]; + pointer[i+33]=0; + + temp[0]='/'; + temp[1]='\0'; + phandle=OF_finddevice(o,temp); + temp[0]='b'; + temp[1]='a'; + temp[2]='n'; + temp[3]='n'; + temp[4]='e'; + temp[5]='r'; + temp[6]='-'; + temp[7]='n'; + temp[8]='a'; + temp[9]='m'; + temp[10]='e'; + temp[11]='\0'; + mem_len = OF_getproplen(o,phandle, temp); + OF_getprop(o,phandle, temp, buffer, mem_len); + (unsigned char) pointer[32] = ((unsigned char *) buffer)[mem_len-2]; +} diff -Nru a/arch/arm26/boot/compressed/uncompress.h b/arch/arm26/boot/compressed/uncompress.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/boot/compressed/uncompress.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,111 @@ +/* + * linux/include/asm-arm/arch-arc/uncompress.h + * + * Copyright (C) 1996 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#define VIDMEM ((char *)0x02000000) + +int video_num_columns, video_num_lines, video_size_row; +int white, bytes_per_char_h; +extern unsigned long con_charconvtable[256]; + +struct param_struct { + unsigned long page_size; + unsigned long nr_pages; + unsigned long ramdisk_size; + unsigned long mountrootrdonly; + unsigned long rootdev; + unsigned long video_num_cols; + unsigned long video_num_rows; + unsigned long video_x; + unsigned long video_y; + unsigned long memc_control_reg; + unsigned char sounddefault; + unsigned char adfsdrives; + unsigned char bytes_per_char_h; + unsigned char bytes_per_char_v; + unsigned long unused[256/4-11]; +}; + +static struct param_struct *params = (struct param_struct *)0x0207c000; + +/* + * This does not append a newline + */ +static void puts(const char *s) +{ + extern void ll_write_char(char *, unsigned long); + int x,y; + unsigned char c; + char *ptr; + + x = params->video_x; + y = params->video_y; + + while ( ( c = *(unsigned char *)s++ ) != '\0' ) { + if ( c == '\n' ) { + x = 0; + if ( ++y >= video_num_lines ) { + y--; + } + } else { + ptr = VIDMEM + ((y*video_num_columns*params->bytes_per_char_v+x)*bytes_per_char_h); + ll_write_char(ptr, c|(white<<16)); + if ( ++x >= video_num_columns ) { + x = 0; + if ( ++y >= video_num_lines ) { + y--; + } + } + } + } + + params->video_x = x; + params->video_y = y; +} + +static void error(char *x); + +/* + * Setup for decompression + */ +static void arch_decomp_setup(void) +{ + int i; + + video_num_lines = params->video_num_rows; + video_num_columns = params->video_num_cols; + bytes_per_char_h = params->bytes_per_char_h; + video_size_row = video_num_columns * bytes_per_char_h; + if (bytes_per_char_h == 4) + for (i = 0; i < 256; i++) + con_charconvtable[i] = + (i & 128 ? 1 << 0 : 0) | + (i & 64 ? 1 << 4 : 0) | + (i & 32 ? 1 << 8 : 0) | + (i & 16 ? 1 << 12 : 0) | + (i & 8 ? 1 << 16 : 0) | + (i & 4 ? 1 << 20 : 0) | + (i & 2 ? 1 << 24 : 0) | + (i & 1 ? 1 << 28 : 0); + else + for (i = 0; i < 16; i++) + con_charconvtable[i] = + (i & 8 ? 1 << 0 : 0) | + (i & 4 ? 1 << 8 : 0) | + (i & 2 ? 1 << 16 : 0) | + (i & 1 ? 1 << 24 : 0); + + white = bytes_per_char_h == 8 ? 0xfc : 7; + + if (params->nr_pages * params->page_size < 4096*1024) error("<4M of mem\n"); +} + +/* + * nothing to do + */ +#define arch_decomp_wdog() diff -Nru a/arch/arm26/boot/compressed/vmlinux.lds.in b/arch/arm26/boot/compressed/vmlinux.lds.in --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/boot/compressed/vmlinux.lds.in Mon Jun 9 23:16:20 2003 @@ -0,0 +1,60 @@ +/* + * linux/arch/arm/boot/compressed/vmlinux.lds.in + * + * Copyright (C) 2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +OUTPUT_ARCH(arm) +ENTRY(_start) +SECTIONS +{ + . = LOAD_ADDR; + _load_addr = .; + + . = TEXT_START; + _text = .; + + .text : { + _start = .; + *(.start) + *(.text) + *(.fixup) + *(.gnu.warning) + *(.rodata) + *(.rodata.*) + *(.glue_7) + *(.glue_7t) + input_data = .; + arch/arm26/boot/compressed/piggy.o + input_data_end = .; + . = ALIGN(4); + } + + _etext = .; + + _got_start = .; + .got : { *(.got) } + _got_end = .; + .got.plt : { *(.got.plt) } + .data : { *(.data) } + _edata = .; + + . = BSS_START; + __bss_start = .; + .bss : { *(.bss) } + _end = .; + + .stack (NOLOAD) : { *(.stack) } + + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } +} + diff -Nru a/arch/arm26/boot/install.sh b/arch/arm26/boot/install.sh --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/boot/install.sh Mon Jun 9 23:16:20 2003 @@ -0,0 +1,62 @@ +#!/bin/sh +# +# arch/arm/boot/install.sh +# +# 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) 1995 by Linus Torvalds +# +# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin +# Adapted from code in arch/i386/boot/install.sh by Russell King +# Stolen from arch/arm/boot/install.sh by Ian Molton +# +# "make install" script for arm architecture +# +# Arguments: +# $1 - kernel version +# $2 - kernel image file +# $3 - kernel map file +# $4 - default install path (blank if root directory) +# + +# User may have a custom install script + +if [ -x /sbin/installkernel ]; then + exec /sbin/installkernel "$@" +fi + +if [ "$2" = "zImage" ]; then +# Compressed install + echo "Installing compressed kernel" + if [ -f $4/vmlinuz-$1 ]; then + mv $4/vmlinuz-$1 $4/vmlinuz.old + fi + + if [ -f $4/System.map-$1 ]; then + mv $4/System.map-$1 $4/System.old + fi + + cat $2 > $4/vmlinuz-$1 + cp $3 $4/System.map-$1 +else +# Normal install + echo "Installing normal kernel" + if [ -f $4/vmlinux-$1 ]; then + mv $4/vmlinux-$1 $4/vmlinux.old + fi + + if [ -f $4/System.map ]; then + mv $4/System.map $4/System.old + fi + + cat $2 > $4/vmlinux-$1 + cp $3 $4/System.map +fi + +if [ -x /sbin/loadmap ]; then + /sbin/loadmap --rdev /dev/ima +else + echo "You have to install it yourself" +fi diff -Nru a/arch/arm26/config.in b/arch/arm26/config.in --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/config.in Mon Jun 9 23:16:20 2003 @@ -0,0 +1,151 @@ +# +# For a description of the syntax of this configuration file, +# see Documentation/kbuild/config-language.txt. +# +mainmenu_name "Linux Kernel Configuration" + +define_bool CONFIG_ARM y +define_bool CONFIG_EISA n +define_bool CONFIG_SBUS n +define_bool CONFIG_MCA n +define_bool CONFIG_UID16 y +define_bool CONFIG_RWSEM_GENERIC_SPINLOCK y +define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM n +define_bool CONFIG_GENERIC_BUST_SPINLOCK n +define_bool CONFIG_GENERIC_ISA_DMA n + +source init/Config.in + +mainmenu_option next_comment +comment 'System Type' + +define_bool CONFIG_ARCH_ARCA5K +bool ' Archimedes' CONFIG_ARCH_ARC +bool ' A5000' CONFIG_ARCH_A5K + +# Definitions to make life easier +define_bool CONFIG_ARCH_ACORN y +define_bool CONFIG_CPU_32 n +define_bool CONFIG_CPU_26 y +bool '2MB physical memory' CONFIG_PAGESIZE_16 + +endmenu + +mainmenu_option next_comment +comment 'General setup' + +define_bool CONFIG_FIQ y + +# Compressed boot loader in ROM. Yes, we really want to ask about +# TEXT and BSS so we preserve their values in the config files. +bool 'Compressed boot loader in ROM/flash' CONFIG_ZBOOT_ROM +hex 'Compressed ROM boot loader base address' CONFIG_ZBOOT_ROM_TEXT 0 +hex 'Compressed ROM boot loader BSS address' CONFIG_ZBOOT_ROM_BSS 0 + +comment 'At least one math emulation must be selected' +define_bool CONFIG_FPE_NWFPE y +choice 'Kernel core (/proc/kcore) format' \ + "ELF CONFIG_KCORE_ELF \ + A.OUT CONFIG_KCORE_AOUT" ELF +tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT +tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF +tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC +string 'Default kernel command string' CONFIG_CMDLINE "" + +define_bool CONFIG_ALIGNMENT_TRAP n +endmenu + +source drivers/parport/Config.in +source drivers/pnp/Config.in +source drivers/block/Config.in +source drivers/md/Config.in +source drivers/acorn/block/Config.in + +if [ "$CONFIG_NET" = "y" ]; then + source net/Config.in + + mainmenu_option next_comment + comment 'Network device support' + + bool 'Network device support' CONFIG_NETDEVICES + if [ "$CONFIG_NETDEVICES" = "y" ]; then + source drivers/net/Config.in + fi + endmenu +fi + +mainmenu_option next_comment +comment 'ATA/ATAPI/MFM/RLL support' + +tristate 'ATA/ATAPI/MFM/RLL support' CONFIG_IDE + +if [ "$CONFIG_IDE" != "n" ]; then + source drivers/ide/Config.in +else + define_bool CONFIG_BLK_DEV_HD n +fi +endmenu + +mainmenu_option next_comment +comment 'SCSI support' + +tristate 'SCSI support' CONFIG_SCSI +endmenu + +source drivers/isdn/Config.in + +# +# input before char - char/joystick depends on it. As does USB. +# +source drivers/input/Config.in + +source drivers/char/Config.in +if [ "$CONFIG_BUSMOUSE" = "y" ]; then + define_bool CONFIG_KBDMOUSE y +fi + +source drivers/media/Config.in + +source fs/Config.in + +if [ "$CONFIG_VT" = "y" ]; then + mainmenu_option next_comment + comment 'Console drivers' + source drivers/video/Config.in + endmenu +fi + +mainmenu_option next_comment +comment 'Sound' + +tristate 'Sound card support' CONFIG_SOUND +if [ "$CONFIG_SOUND" != "n" ]; then + source sound/Config.in +fi +endmenu + +source drivers/misc/Config.in +source drivers/usb/Config.in + +mainmenu_option next_comment +comment 'Kernel hacking' + +# Always compile kernel with framepointer (until 2.4 real comes out) +# Bug reports aren't much use without this. +bool 'Compile kernel without frame pointer' CONFIG_NO_FRAME_POINTER +bool 'Verbose user fault messages' CONFIG_DEBUG_USER +bool 'Include debugging information in kernel binary' CONFIG_DEBUG_INFO + +bool 'Kernel debugging' CONFIG_DEBUG_KERNEL +dep_bool ' Debug memory allocations' CONFIG_DEBUG_SLAB $CONFIG_DEBUG_KERNEL +dep_bool ' Magic SysRq key' CONFIG_MAGIC_SYSRQ $CONFIG_DEBUG_KERNEL +dep_bool ' Spinlock debugging' CONFIG_DEBUG_SPINLOCK $CONFIG_DEBUG_KERNEL +dep_bool ' Wait queue debugging' CONFIG_DEBUG_WAITQ $CONFIG_DEBUG_KERNEL +dep_bool ' Verbose BUG() reporting (adds 70K)' CONFIG_DEBUG_BUGVERBOSE $CONFIG_DEBUG_KERNEL +dep_bool ' Verbose kernel error messages' CONFIG_DEBUG_ERRORS $CONFIG_DEBUG_KERNEL +# These options are only for real kernel hackers who want to get their hands dirty. +dep_bool ' Kernel low-level debugging functions' CONFIG_DEBUG_LL $CONFIG_DEBUG_KERNEL +endmenu + +source security/Config.in +source lib/Config.in diff -Nru a/arch/arm26/defconfig b/arch/arm26/defconfig --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/defconfig Mon Jun 9 23:16:20 2003 @@ -0,0 +1,367 @@ +# +# Automatically generated by make menuconfig: don't edit +# +CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y + +# +# General setup +# +# CONFIG_NET is not set +# CONFIG_SYSVIPC is not set +# CONFIG_BSD_PROCESS_ACCT is not set +# CONFIG_SYSCTL is not set + +# +# Loadable module support +# +# CONFIG_MODULES is not set + +# +# System Type +# +CONFIG_ARCH_ARC=y +# CONFIG_ARCH_A5K is not set +CONFIG_ARCH_ACORN=y +# CONFIG_CPU_32 is not set +CONFIG_CPU_26=y +# CONFIG_PAGESIZE_16 is not set + +# +# General setup +# +CONFIG_FIQ=y +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +CONFIG_FPE_NWFPE=y +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +# CONFIG_BINFMT_AOUT is not set +# CONFIG_BINFMT_ELF is not set +# CONFIG_BINFMT_MISC is not set +CONFIG_CMDLINE="" +# CONFIG_ALIGNMENT_TRAP 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 +# CONFIG_PNPBIOS is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +# CONFIG_BLK_DEV_RAM is not set +# CONFIG_BLK_DEV_INITRD is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Acorn-specific block devices +# +# CONFIG_BLK_DEV_FD1772 is not set +# CONFIG_BLK_DEV_MFM is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_HD is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# ISDN subsystem +# + +# +# Input device support +# +# CONFIG_INPUT is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_MOUSEDEV_PSAUX is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_TSDEV is not set +# CONFIG_INPUT_TSLIBDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_EVBUG is not set +# CONFIG_INPUT_UINPUT is not set +# CONFIG_GAMEPORT is not set +CONFIG_SOUND_GAMEPORT=y +# CONFIG_GAMEPORT_NS558 is not set +# CONFIG_GAMEPORT_L4 is not set +# CONFIG_GAMEPORT_EMU10K1 is not set +# CONFIG_GAMEPORT_VORTEX is not set +# CONFIG_GAMEPORT_FM801 is not set +# CONFIG_GAMEPORT_CS461x is not set +# CONFIG_SERIO is not set +# CONFIG_SERIO_I8042 is not set +# CONFIG_SERIO_SERPORT is not set +# CONFIG_SERIO_CT82C710 is not set +# CONFIG_SERIO_PARKBD is not set +# CONFIG_SERIO_ACORN is not set + +# +# Character devices +# +# CONFIG_VT is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_8250 is not set +# CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_SERIAL_8250_CS is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_RSA is not set +# CONFIG_ATOMWIDE_SERIAL is not set +# CONFIG_DUALSP_SERIAL is not set +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_AMBA is not set +# CONFIG_SERIAL_AMBA_CONSOLE is not set +# CONFIG_SERIAL_CLPS711X is not set +# CONFIG_SERIAL_CLPS711X_CONSOLE is not set +# CONFIG_SERIAL_CLPS711X_OLD_NAME is not set +# CONFIG_SERIAL_21285 is not set +# CONFIG_SERIAL_21285_OLD is not set +# CONFIG_SERIAL_21285_CONSOLE is not set +# CONFIG_SERIAL_UART00 is not set +# CONFIG_SERIAL_UART00_CONSOLE is not set +# CONFIG_SERIAL_SA1100 is not set +# CONFIG_SERIAL_SA1100_CONSOLE is not set +# CONFIG_UNIX98_PTYS is not set + +# +# I2C support +# +CONFIG_I2C=y +CONFIG_I2C_ALGOBIT=y +# CONFIG_I2C_PHILIPSPAR is not set +# CONFIG_I2C_ELV is not set +# CONFIG_I2C_VELLEMAN is not set +CONFIG_I2C_ALGOPCF=y +# CONFIG_I2C_ELEKTOR is not set +CONFIG_I2C_CHARDEV=y +# CONFIG_I2C_PROC is not set + +# +# L3 serial bus support +# +# CONFIG_L3 is not set +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set +# CONFIG_L3_SA1111 is not set +# CONFIG_BIT_SA1100_GPIO is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_PSMOUSE is not set +# CONFIG_QIC02_TAPE is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_NVRAM is not set +# CONFIG_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set +# CONFIG_RAW_DRIVER is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_QFMT_V1 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_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +# CONFIG_FAT_FS is not set +# CONFIG_MSDOS_FS is not set +# CONFIG_UMSDOS_FS is not set +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +CONFIG_RAMFS=y +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_JFS_FS is not set +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_DEBUG is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +# CONFIG_DEVPTS_FS is not set +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +# CONFIG_ROMFS_FS 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_NCPFS_NLS is not set +# CONFIG_SMB_FS is not set +# CONFIG_ZISOFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +CONFIG_ACORN_PARTITION=y +# CONFIG_ACORN_PARTITION_EESOX is not set +# CONFIG_ACORN_PARTITION_ICS is not set +CONFIG_ACORN_PARTITION_ADFS=y +# CONFIG_ACORN_PARTITION_POWERTEC is not set +CONFIG_ACORN_PARTITION_RISCIX=y +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +# CONFIG_MSDOS_PARTITION is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SMB_NLS is not set +# CONFIG_NLS is not set + +# +# Sound +# +# CONFIG_SOUND is not set + +# +# Multimedia Capabilities Port drivers +# +# CONFIG_MCP is not set +# CONFIG_MCP_SA1100 is not set +# CONFIG_MCP_UCB1200 is not set +# CONFIG_MCP_UCB1200_AUDIO is not set +# CONFIG_MCP_UCB1200_TS is not set + +# +# Console Switches +# +# CONFIG_SWITCHES is not set +# CONFIG_SWITCHES_SA1100 is not set +# CONFIG_SWITCHES_UCB1X00 is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Kernel hacking +# +# CONFIG_NO_FRAME_POINTER is not set +CONFIG_DEBUG_USER=y +CONFIG_DEBUG_INFO=y +CONFIG_DEBUG_KERNEL=y +CONFIG_DEBUG_SLAB=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_DEBUG_SPINLOCK=y +CONFIG_DEBUG_WAITQ=y +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_LL=y + +# +# Security options +# +CONFIG_SECURITY_CAPABILITIES=y + +# +# Library routines +# +CONFIG_CRC32=y +# CONFIG_ZLIB_INFLATE is not set +# CONFIG_ZLIB_DEFLATE is not set diff -Nru a/arch/arm26/kernel/Makefile b/arch/arm26/kernel/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/kernel/Makefile Mon Jun 9 23:16:20 2003 @@ -0,0 +1,18 @@ +# +# Makefile for the linux kernel. +# + +ENTRY_OBJ = entry.o + +# Object file lists. + +obj-y := arch.o compat.o dma.o entry.o irq.o \ + process.o ptrace.o semaphore.o setup.o signal.o sys_arm.o \ + time.o traps.o ecard.o time-acorn.o dma.o \ + ecard.o fiq.o time.o + +obj-$(CONFIG_FIQ) += fiq.o +obj-$(CONFIG_MODULES) += armksyms.o + +extra-y := init_task.o + diff -Nru a/arch/arm26/kernel/arch.c b/arch/arm26/kernel/arch.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/kernel/arch.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,30 @@ +/* + * linux/arch/arm/kernel/arch.c + * + * Architecture specific fixups. + */ +#include <linux/config.h> +#include <linux/init.h> +#include <linux/types.h> + +#include <asm/elf.h> +#include <asm/setup.h> +#include <asm/mach-types.h> +#include <asm/arch.h> +#include <asm/page.h> + +unsigned int vram_size; + + +unsigned int memc_ctrl_reg; +unsigned int number_mfm_drives; + +static int __init parse_tag_acorn(const struct tag *tag) +{ + memc_ctrl_reg = tag->u.acorn.memc_control_reg; + number_mfm_drives = tag->u.acorn.adfsdrives; + return 0; +} + +__tagtable(ATAG_ACORN, parse_tag_acorn); + diff -Nru a/arch/arm26/kernel/armksyms.c b/arch/arm26/kernel/armksyms.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/kernel/armksyms.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,233 @@ +/* + * linux/arch/arm26/kernel/armksyms.c + * + * Copyright (C) 2003 Ian Molton + * + * This program is free software; you can 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/user.h> +#include <linux/string.h> +#include <linux/fs.h> +#include <linux/mm.h> +#include <linux/mman.h> +#include <linux/delay.h> +#include <linux/in6.h> +#include <linux/interrupt.h> +#include <linux/pm.h> +#include <linux/tty.h> +#include <linux/vt_kern.h> +#include <linux/smp_lock.h> + +#include <asm/byteorder.h> +#include <asm/elf.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/pgalloc.h> +//#include <asm/proc-fns.h> +#include <asm/processor.h> +#include <asm/semaphore.h> +#include <asm/system.h> +#include <asm/uaccess.h> +#include <asm/checksum.h> +#include <asm/mach-types.h> + +extern void dump_thread(struct pt_regs *, struct user *); +extern int dump_fpu(struct pt_regs *, struct user_fp_struct *); +extern void inswb(unsigned int port, void *to, int len); +extern void outswb(unsigned int port, const void *to, int len); + +extern void __bad_xchg(volatile void *ptr, int size); + +/* + * syscalls + */ +extern int sys_write(int, const char *, int); +extern int sys_read(int, char *, int); +extern int sys_lseek(int, off_t, int); +extern int sys_exit(int); + +/* + * libgcc functions - functions that are used internally by the + * compiler... (prototypes are not correct though, but that + * doesn't really matter since they're not versioned). + */ +extern void __ashldi3(void); +extern void __ashrdi3(void); +extern void __divsi3(void); +extern void __lshrdi3(void); +extern void __modsi3(void); +extern void __muldi3(void); +extern void __ucmpdi2(void); +extern void __udivdi3(void); +extern void __umoddi3(void); +extern void __udivmoddi4(void); +extern void __udivsi3(void); +extern void __umodsi3(void); +extern void abort(void); + +extern void ret_from_exception(void); +extern void fpundefinstr(void); +extern void fp_enter(void); + +/* + * This has a special calling convention; it doesn't + * modify any of the usual registers, except for LR. + */ +extern void __do_softirq(void); + +#define EXPORT_SYMBOL_ALIAS(sym,orig) \ + const char __kstrtab_##sym[] \ + __attribute__((section(".kstrtab"))) = \ + __MODULE_STRING(sym); \ + const struct module_symbol __ksymtab_##sym \ + __attribute__((section("__ksymtab"))) = \ + { (unsigned long)&orig, __kstrtab_##sym }; + +/* + * floating point math emulator support. + * These symbols will never change their calling convention... + */ +EXPORT_SYMBOL_ALIAS(kern_fp_enter,fp_enter); +EXPORT_SYMBOL_ALIAS(fp_printk,printk); +EXPORT_SYMBOL_ALIAS(fp_send_sig,send_sig); + +EXPORT_SYMBOL(fpundefinstr); +EXPORT_SYMBOL(ret_from_exception); + +#ifdef CONFIG_VT +EXPORT_SYMBOL(kd_mksound); +#endif + +EXPORT_SYMBOL_NOVERS(__do_softirq); + + /* platform dependent support */ +EXPORT_SYMBOL(dump_thread); +EXPORT_SYMBOL(dump_fpu); +EXPORT_SYMBOL(udelay); +EXPORT_SYMBOL(kernel_thread); +EXPORT_SYMBOL(system_rev); +EXPORT_SYMBOL(system_serial_low); +EXPORT_SYMBOL(system_serial_high); +#ifdef CONFIG_DEBUG_BUGVERBOSE +EXPORT_SYMBOL(__bug); +#endif +EXPORT_SYMBOL(__bad_xchg); +EXPORT_SYMBOL(__readwrite_bug); +EXPORT_SYMBOL(enable_irq); +EXPORT_SYMBOL(disable_irq); +EXPORT_SYMBOL(set_irq_type); +EXPORT_SYMBOL(pm_idle); +EXPORT_SYMBOL(pm_power_off); + + /* processor dependencies */ +EXPORT_SYMBOL(__machine_arch_type); + + /* networking */ +EXPORT_SYMBOL(csum_partial_copy_nocheck); +EXPORT_SYMBOL(__csum_ipv6_magic); + + /* io */ +#ifndef __raw_readsb +EXPORT_SYMBOL_NOVERS(__raw_readsb); +#endif +#ifndef __raw_readsw +EXPORT_SYMBOL_NOVERS(__raw_readsw); +#endif +#ifndef __raw_readsl +EXPORT_SYMBOL_NOVERS(__raw_readsl); +#endif +#ifndef __raw_writesb +EXPORT_SYMBOL_NOVERS(__raw_writesb); +#endif +#ifndef __raw_writesw +EXPORT_SYMBOL_NOVERS(__raw_writesw); +#endif +#ifndef __raw_writesl +EXPORT_SYMBOL_NOVERS(__raw_writesl); +#endif + + /* string / mem functions */ +EXPORT_SYMBOL_NOVERS(strcpy); +EXPORT_SYMBOL_NOVERS(strncpy); +EXPORT_SYMBOL_NOVERS(strcat); +EXPORT_SYMBOL_NOVERS(strncat); +EXPORT_SYMBOL_NOVERS(strcmp); +EXPORT_SYMBOL_NOVERS(strncmp); +EXPORT_SYMBOL_NOVERS(strchr); +EXPORT_SYMBOL_NOVERS(strlen); +EXPORT_SYMBOL_NOVERS(strnlen); +EXPORT_SYMBOL_NOVERS(strpbrk); +EXPORT_SYMBOL_NOVERS(strrchr); +EXPORT_SYMBOL_NOVERS(strstr); +EXPORT_SYMBOL_NOVERS(memset); +EXPORT_SYMBOL_NOVERS(memcpy); +EXPORT_SYMBOL_NOVERS(memmove); +EXPORT_SYMBOL_NOVERS(memcmp); +EXPORT_SYMBOL_NOVERS(memscan); +EXPORT_SYMBOL_NOVERS(__memzero); + + /* user mem (segment) */ +EXPORT_SYMBOL(uaccess_kernel); +EXPORT_SYMBOL(uaccess_user); + +EXPORT_SYMBOL_NOVERS(__get_user_1); +EXPORT_SYMBOL_NOVERS(__get_user_2); +EXPORT_SYMBOL_NOVERS(__get_user_4); +EXPORT_SYMBOL_NOVERS(__get_user_8); + +EXPORT_SYMBOL_NOVERS(__put_user_1); +EXPORT_SYMBOL_NOVERS(__put_user_2); +EXPORT_SYMBOL_NOVERS(__put_user_4); +EXPORT_SYMBOL_NOVERS(__put_user_8); + + /* gcc lib functions */ +EXPORT_SYMBOL_NOVERS(__ashldi3); +EXPORT_SYMBOL_NOVERS(__ashrdi3); +EXPORT_SYMBOL_NOVERS(__divsi3); +EXPORT_SYMBOL_NOVERS(__lshrdi3); +EXPORT_SYMBOL_NOVERS(__modsi3); +EXPORT_SYMBOL_NOVERS(__muldi3); +EXPORT_SYMBOL_NOVERS(__ucmpdi2); +EXPORT_SYMBOL_NOVERS(__udivdi3); +EXPORT_SYMBOL_NOVERS(__umoddi3); +EXPORT_SYMBOL_NOVERS(__udivmoddi4); +EXPORT_SYMBOL_NOVERS(__udivsi3); +EXPORT_SYMBOL_NOVERS(__umodsi3); + + /* bitops */ +EXPORT_SYMBOL(_set_bit_le); +EXPORT_SYMBOL(_test_and_set_bit_le); +EXPORT_SYMBOL(_clear_bit_le); +EXPORT_SYMBOL(_test_and_clear_bit_le); +EXPORT_SYMBOL(_change_bit_le); +EXPORT_SYMBOL(_test_and_change_bit_le); +EXPORT_SYMBOL(_find_first_zero_bit_le); +EXPORT_SYMBOL(_find_next_zero_bit_le); + + /* elf */ +EXPORT_SYMBOL(elf_platform); +EXPORT_SYMBOL(elf_hwcap); + + /* syscalls */ +EXPORT_SYMBOL(sys_write); +EXPORT_SYMBOL(sys_read); +EXPORT_SYMBOL(sys_lseek); +EXPORT_SYMBOL(sys_open); +EXPORT_SYMBOL(sys_exit); +EXPORT_SYMBOL(sys_wait4); + + /* semaphores */ +EXPORT_SYMBOL_NOVERS(__down_failed); +EXPORT_SYMBOL_NOVERS(__down_interruptible_failed); +EXPORT_SYMBOL_NOVERS(__down_trylock_failed); +EXPORT_SYMBOL_NOVERS(__up_wakeup); + +EXPORT_SYMBOL(get_wchan); + +#ifdef CONFIG_PREEMPT +EXPORT_SYMBOL(kernel_flag); +#endif diff -Nru a/arch/arm26/kernel/asm-offsets.c b/arch/arm26/kernel/asm-offsets.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/kernel/asm-offsets.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,64 @@ +/* + * Copyright (C) 1995-2001 Russell King + * 2001-2002 Keith Owens + * 2003-? Ian Molton + * + * Generate definitions needed by assembly language modules. + * This code generates raw asm output which is post-processed to extract + * and format the required data. + * + * This program is free software; you can 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/sched.h> +#include <linux/mm.h> + +#include <asm/pgtable.h> +#include <asm/uaccess.h> + +/* + * Make sure that the compiler and target are compatible. + */ +#if defined(__APCS_32__) && defined(CONFIG_CPU_26) +#error Sorry, your compiler targets APCS-32 but this kernel requires APCS-26 +#endif +#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 95) +#error Sorry, your compiler is known to miscompile kernels. Only use gcc 2.95.3 and later. +#endif +#if __GNUC__ == 2 && __GNUC_MINOR__ == 95 +/* shame we can't detect the .1 or .2 releases */ +#warning GCC 2.95.2 and earlier miscompiles kernels. +#endif + +/* Use marker if you need to separate the values later */ + +#define DEFINE(sym, val) \ + asm volatile("\n->" #sym " %0 " #val : : "i" (val)) + +#define BLANK() asm volatile("\n->" : : ) + +int main(void) +{ + DEFINE(TSK_USED_MATH, offsetof(struct task_struct, used_math)); + DEFINE(TSK_ACTIVE_MM, offsetof(struct task_struct, active_mm)); + BLANK(); + DEFINE(VMA_VM_MM, offsetof(struct vm_area_struct, vm_mm)); + DEFINE(VMA_VM_FLAGS, offsetof(struct vm_area_struct, vm_flags)); + BLANK(); + DEFINE(VM_EXEC, VM_EXEC); + BLANK(); + BLANK(); + DEFINE(PAGE_PRESENT, _PAGE_PRESENT); + DEFINE(PAGE_READONLY, _PAGE_READONLY); + DEFINE(PAGE_NOT_USER, _PAGE_NOT_USER); + DEFINE(PAGE_OLD, _PAGE_OLD); + DEFINE(PAGE_CLEAN, _PAGE_CLEAN); + BLANK(); + DEFINE(PAGE_SZ, PAGE_SIZE); + BLANK(); + DEFINE(SYS_ERROR0, 0x9f0000); + return 0; +} diff -Nru a/arch/arm26/kernel/compat.c b/arch/arm26/kernel/compat.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/kernel/compat.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,174 @@ +/* + * linux/arch/arm/kernel/compat.c + * + * Copyright (C) 2001 Russell King + * 2003 Ian Molton + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * We keep the old params compatibility cruft in one place (here) + * so we don't end up with lots of mess around other places. + * + * NOTE: + * The old struct param_struct is deprecated, but it will be kept in + * the kernel for 5 years from now (2001). This will allow boot loaders + * to convert to the new struct tag way. + */ +#include <linux/config.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/init.h> + +#include <asm/setup.h> +#include <asm/mach-types.h> +#include <asm/page.h> + +#include <asm/arch.h> +//#include <asm/mach/irq.h> + +/* + * Usage: + * - do not go blindly adding fields, add them at the end + * - when adding fields, don't rely on the address until + * a patch from me has been released + * - unused fields should be zero (for future expansion) + * - this structure is relatively short-lived - only + * guaranteed to contain useful data in setup_arch() + * + * This is the old deprecated way to pass parameters to the kernel + */ +struct param_struct { + union { + struct { + unsigned long page_size; /* 0 */ + unsigned long nr_pages; /* 4 */ + unsigned long ramdisk_size; /* 8 */ + unsigned long flags; /* 12 */ +#define FLAG_READONLY 1 +#define FLAG_RDLOAD 4 +#define FLAG_RDPROMPT 8 + unsigned long rootdev; /* 16 */ + unsigned long video_num_cols; /* 20 */ + unsigned long video_num_rows; /* 24 */ + unsigned long video_x; /* 28 */ + unsigned long video_y; /* 32 */ + unsigned long memc_control_reg; /* 36 */ + unsigned char sounddefault; /* 40 */ + unsigned char adfsdrives; /* 41 */ + unsigned char bytes_per_char_h; /* 42 */ + unsigned char bytes_per_char_v; /* 43 */ + unsigned long pages_in_bank[4]; /* 44 */ + unsigned long pages_in_vram; /* 60 */ + unsigned long initrd_start; /* 64 */ + unsigned long initrd_size; /* 68 */ + unsigned long rd_start; /* 72 */ + unsigned long system_rev; /* 76 */ + unsigned long system_serial_low; /* 80 */ + unsigned long system_serial_high; /* 84 */ + unsigned long mem_fclk_21285; /* 88 */ + } s; + char unused[256]; + } u1; + union { + char paths[8][128]; + struct { + unsigned long magic; + char n[1024 - sizeof(unsigned long)]; + } s; + } u2; + char commandline[COMMAND_LINE_SIZE]; +}; + +static struct tag * __init memtag(struct tag *tag, unsigned long start, unsigned long size) +{ + tag = tag_next(tag); + tag->hdr.tag = ATAG_MEM; + tag->hdr.size = tag_size(tag_mem32); + tag->u.mem.size = size; + tag->u.mem.start = start; + + return tag; +} + +static void __init build_tag_list(struct param_struct *params, void *taglist) +{ + struct tag *tag = taglist; + + if (params->u1.s.page_size != PAGE_SIZE) { + printk(KERN_WARNING "Warning: bad configuration page, " + "trying to continue\n"); + return; + } + + printk(KERN_DEBUG "Converting old-style param struct to taglist\n"); + + tag->hdr.tag = ATAG_CORE; + tag->hdr.size = tag_size(tag_core); + tag->u.core.flags = params->u1.s.flags & FLAG_READONLY; + tag->u.core.pagesize = params->u1.s.page_size; + tag->u.core.rootdev = params->u1.s.rootdev; + + tag = tag_next(tag); + tag->hdr.tag = ATAG_RAMDISK; + tag->hdr.size = tag_size(tag_ramdisk); + tag->u.ramdisk.flags = (params->u1.s.flags & FLAG_RDLOAD ? 1 : 0) | + (params->u1.s.flags & FLAG_RDPROMPT ? 2 : 0); + tag->u.ramdisk.size = params->u1.s.ramdisk_size; + tag->u.ramdisk.start = params->u1.s.rd_start; + + tag = tag_next(tag); + tag->hdr.tag = ATAG_INITRD; + tag->hdr.size = tag_size(tag_initrd); + tag->u.initrd.start = params->u1.s.initrd_start; + tag->u.initrd.size = params->u1.s.initrd_size; + + tag = tag_next(tag); + tag->hdr.tag = ATAG_SERIAL; + tag->hdr.size = tag_size(tag_serialnr); + tag->u.serialnr.low = params->u1.s.system_serial_low; + tag->u.serialnr.high = params->u1.s.system_serial_high; + + tag = tag_next(tag); + tag->hdr.tag = ATAG_REVISION; + tag->hdr.size = tag_size(tag_revision); + tag->u.revision.rev = params->u1.s.system_rev; + + tag = memtag(tag, PHYS_OFFSET, params->u1.s.nr_pages * PAGE_SIZE); + + tag = tag_next(tag); + tag->hdr.tag = ATAG_ACORN; + tag->hdr.size = tag_size(tag_acorn); + tag->u.acorn.memc_control_reg = params->u1.s.memc_control_reg; + tag->u.acorn.vram_pages = params->u1.s.pages_in_vram; + tag->u.acorn.sounddefault = params->u1.s.sounddefault; + tag->u.acorn.adfsdrives = params->u1.s.adfsdrives; + + tag = tag_next(tag); + tag->hdr.tag = ATAG_CMDLINE; + tag->hdr.size = (strlen(params->commandline) + 3 + + sizeof(struct tag_header)) >> 2; + strcpy(tag->u.cmdline.cmdline, params->commandline); + + tag = tag_next(tag); + tag->hdr.tag = ATAG_NONE; + tag->hdr.size = 0; + + memmove(params, taglist, ((int)tag) - ((int)taglist) + + sizeof(struct tag_header)); +} + +void __init convert_to_tag_list(struct tag *tags) +{ + struct param_struct *params = (struct param_struct *)tags; + build_tag_list(params, ¶ms->u2); +} + +void __init squash_mem_tags(struct tag *tag) +{ + for (; tag->hdr.size; tag = tag_next(tag)) + if (tag->hdr.tag == ATAG_MEM) + tag->hdr.tag = ATAG_NONE; +} diff -Nru a/arch/arm26/kernel/dma.c b/arch/arm26/kernel/dma.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/kernel/dma.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,302 @@ +/* + * linux/arch/arm/kernel/dma.c + * + * Copyright (C) 1995-2000 Russell King + * 2003-? Ian Molton + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Front-end to the DMA handling. This handles the allocation/freeing + * of DMA channels, and provides a unified interface to the machines + * DMA facilities. + */ +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/sched.h> +#include <linux/mman.h> +#include <linux/init.h> +#include <linux/spinlock.h> +#include <linux/errno.h> + +#include <asm/dma.h> + +spinlock_t dma_spin_lock = SPIN_LOCK_UNLOCKED; + +#if MAX_DMA_CHANNELS > 0 + +static dma_t dma_chan[MAX_DMA_CHANNELS]; + +/* + * Get dma list for /proc/dma + */ +int get_dma_list(char *buf) +{ + dma_t *dma; + char *p = buf; + int i; + + for (i = 0, dma = dma_chan; i < MAX_DMA_CHANNELS; i++, dma++) + if (dma->lock) + p += sprintf(p, "%2d: %14s %s\n", i, + dma->d_ops->type, dma->device_id); + + return p - buf; +} + +/* + * Request DMA channel + * + * On certain platforms, we have to allocate an interrupt as well... + */ +int request_dma(dmach_t channel, const char *device_id) +{ + dma_t *dma = dma_chan + channel; + int ret; + + if (channel >= MAX_DMA_CHANNELS || !dma->d_ops) + goto bad_dma; + + if (xchg(&dma->lock, 1) != 0) + goto busy; + + dma->device_id = device_id; + dma->active = 0; + dma->invalid = 1; + + ret = 0; + if (dma->d_ops->request) + ret = dma->d_ops->request(channel, dma); + + if (ret) + xchg(&dma->lock, 0); + + return ret; + +bad_dma: + printk(KERN_ERR "dma: trying to allocate DMA%d\n", channel); + return -EINVAL; + +busy: + return -EBUSY; +} + +/* + * Free DMA channel + * + * On certain platforms, we have to free interrupt as well... + */ +void free_dma(dmach_t channel) +{ + dma_t *dma = dma_chan + channel; + + if (channel >= MAX_DMA_CHANNELS || !dma->d_ops) + goto bad_dma; + + if (dma->active) { + printk(KERN_ERR "dma%d: freeing active DMA\n", channel); + dma->d_ops->disable(channel, dma); + dma->active = 0; + } + + if (xchg(&dma->lock, 0) != 0) { + if (dma->d_ops->free) + dma->d_ops->free(channel, dma); + return; + } + + printk(KERN_ERR "dma%d: trying to free free DMA\n", channel); + return; + +bad_dma: + printk(KERN_ERR "dma: trying to free DMA%d\n", channel); +} + +/* Set DMA Scatter-Gather list + */ +void set_dma_sg (dmach_t channel, struct scatterlist *sg, int nr_sg) +{ + dma_t *dma = dma_chan + channel; + + if (dma->active) + printk(KERN_ERR "dma%d: altering DMA SG while " + "DMA active\n", channel); + + dma->sg = sg; + dma->sgcount = nr_sg; + dma->using_sg = 1; + dma->invalid = 1; +} + +/* Set DMA address + * + * Copy address to the structure, and set the invalid bit + */ +void set_dma_addr (dmach_t channel, unsigned long physaddr) +{ + dma_t *dma = dma_chan + channel; + + if (dma->active) + printk(KERN_ERR "dma%d: altering DMA address while " + "DMA active\n", channel); + + dma->sg = &dma->buf; + dma->sgcount = 1; + dma->buf.__address = (char *)physaddr;//FIXME - not pretty + dma->using_sg = 0; + dma->invalid = 1; +} + +/* Set DMA byte count + * + * Copy address to the structure, and set the invalid bit + */ +void set_dma_count (dmach_t channel, unsigned long count) +{ + dma_t *dma = dma_chan + channel; + + if (dma->active) + printk(KERN_ERR "dma%d: altering DMA count while " + "DMA active\n", channel); + + dma->sg = &dma->buf; + dma->sgcount = 1; + dma->buf.length = count; + dma->using_sg = 0; + dma->invalid = 1; +} + +/* Set DMA direction mode + */ +void set_dma_mode (dmach_t channel, dmamode_t mode) +{ + dma_t *dma = dma_chan + channel; + + if (dma->active) + printk(KERN_ERR "dma%d: altering DMA mode while " + "DMA active\n", channel); + + dma->dma_mode = mode; + dma->invalid = 1; +} + +/* Enable DMA channel + */ +void enable_dma (dmach_t channel) +{ + dma_t *dma = dma_chan + channel; + + if (!dma->lock) + goto free_dma; + + if (dma->active == 0) { + dma->active = 1; + dma->d_ops->enable(channel, dma); + } + return; + +free_dma: + printk(KERN_ERR "dma%d: trying to enable free DMA\n", channel); + BUG(); +} + +/* Disable DMA channel + */ +void disable_dma (dmach_t channel) +{ + dma_t *dma = dma_chan + channel; + + if (!dma->lock) + goto free_dma; + + if (dma->active == 1) { + dma->active = 0; + dma->d_ops->disable(channel, dma); + } + return; + +free_dma: + printk(KERN_ERR "dma%d: trying to disable free DMA\n", channel); + BUG(); +} + +/* + * Is the specified DMA channel active? + */ +int dma_channel_active(dmach_t channel) +{ + return dma_chan[channel].active; +} + +void set_dma_page(dmach_t channel, char pagenr) +{ + printk(KERN_ERR "dma%d: trying to set_dma_page\n", channel); +} + +void set_dma_speed(dmach_t channel, int cycle_ns) +{ + dma_t *dma = dma_chan + channel; + int ret = 0; + + if (dma->d_ops->setspeed) + ret = dma->d_ops->setspeed(channel, dma, cycle_ns); + dma->speed = ret; +} + +int get_dma_residue(dmach_t channel) +{ + dma_t *dma = dma_chan + channel; + int ret = 0; + + if (dma->d_ops->residue) + ret = dma->d_ops->residue(channel, dma); + + return ret; +} + +void __init init_dma(void) +{ + arch_dma_init(dma_chan); +} + +#else + +int request_dma(dmach_t channel, const char *device_id) +{ + return -EINVAL; +} + +int get_dma_residue(dmach_t channel) +{ + return 0; +} + +#define GLOBAL_ALIAS(_a,_b) asm (".set " #_a "," #_b "; .globl " #_a) +GLOBAL_ALIAS(disable_dma, get_dma_residue); +GLOBAL_ALIAS(enable_dma, get_dma_residue); +GLOBAL_ALIAS(free_dma, get_dma_residue); +GLOBAL_ALIAS(get_dma_list, get_dma_residue); +GLOBAL_ALIAS(set_dma_mode, get_dma_residue); +GLOBAL_ALIAS(set_dma_page, get_dma_residue); +GLOBAL_ALIAS(set_dma_count, get_dma_residue); +GLOBAL_ALIAS(set_dma_addr, get_dma_residue); +GLOBAL_ALIAS(set_dma_sg, get_dma_residue); +GLOBAL_ALIAS(set_dma_speed, get_dma_residue); +GLOBAL_ALIAS(init_dma, get_dma_residue); + +#endif + +EXPORT_SYMBOL(request_dma); +EXPORT_SYMBOL(free_dma); +EXPORT_SYMBOL(enable_dma); +EXPORT_SYMBOL(disable_dma); +EXPORT_SYMBOL(set_dma_addr); +EXPORT_SYMBOL(set_dma_count); +EXPORT_SYMBOL(set_dma_mode); +EXPORT_SYMBOL(set_dma_page); +EXPORT_SYMBOL(get_dma_residue); +EXPORT_SYMBOL(set_dma_sg); +EXPORT_SYMBOL(set_dma_speed); + +EXPORT_SYMBOL(dma_spin_lock); diff -Nru a/arch/arm26/kernel/ecard.c b/arch/arm26/kernel/ecard.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/kernel/ecard.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,899 @@ +/* + * linux/arch/arm26/kernel/ecard.c + * + * Copyright 1995-2001 Russell King + * Copyright 2003 Ian Molton + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Find all installed expansion cards, and handle interrupts from them. + * + * Created from information from Acorns RiscOS3 PRMs + * + * 08-Dec-1996 RMK Added code for the 9'th expansion card - the ether + * podule slot. + * 06-May-1997 RMK Added blacklist for cards whose loader doesn't work. + * 12-Sep-1997 RMK Created new handling of interrupt enables/disables + * - cards can now register their own routine to control + * interrupts (recommended). + * 29-Sep-1997 RMK Expansion card interrupt hardware not being re-enabled + * on reset from Linux. (Caused cards not to respond + * under RiscOS without hard reset). + * 15-Feb-1998 RMK Added DMA support + * 12-Sep-1998 RMK Added EASI support + * 10-Jan-1999 RMK Run loaders in a simulated RISC OS environment. + * 17-Apr-1999 RMK Support for EASI Type C cycles. + */ +#define ECARD_C + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/reboot.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/proc_fs.h> +#include <linux/device.h> +#include <linux/init.h> + +#include <asm/dma.h> +#include <asm/ecard.h> +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/pgalloc.h> +#include <asm/mmu_context.h> +#include <asm/irq.h> +#include <asm/irqchip.h> +#include <asm/tlbflush.h> + +enum req { + req_readbytes, + req_reset +}; + +struct ecard_request { + enum req req; + ecard_t *ec; + unsigned int address; + unsigned int length; + unsigned int use_loader; + void *buffer; +}; + +struct expcard_blacklist { + unsigned short manufacturer; + unsigned short product; + const char *type; +}; + +static ecard_t *cards; +static ecard_t *slot_to_expcard[MAX_ECARDS]; +static unsigned int ectcr; + +/* List of descriptions of cards which don't have an extended + * identification, or chunk directories containing a description. + */ +static struct expcard_blacklist __initdata blacklist[] = { + { MANU_ACORN, PROD_ACORN_ETHER1, "Acorn Ether1" } +}; + +asmlinkage extern int +ecard_loader_reset(volatile unsigned char *pa, loader_t loader); +asmlinkage extern int +ecard_loader_read(int off, volatile unsigned char *pa, loader_t loader); + +static const struct ecard_id * +ecard_match_device(const struct ecard_id *ids, struct expansion_card *ec); + +static inline unsigned short +ecard_getu16(unsigned char *v) +{ + return v[0] | v[1] << 8; +} + +static inline signed long +ecard_gets24(unsigned char *v) +{ + return v[0] | v[1] << 8 | v[2] << 16 | ((v[2] & 0x80) ? 0xff000000 : 0); +} + +static inline ecard_t * +slot_to_ecard(unsigned int slot) +{ + return slot < MAX_ECARDS ? slot_to_expcard[slot] : NULL; +} + +/* ===================== Expansion card daemon ======================== */ +/* + * Since the loader programs on the expansion cards need to be run + * in a specific environment, create a separate task with this + * environment up, and pass requests to this task as and when we + * need to. + * + * This should allow 99% of loaders to be called from Linux. + * + * From a security standpoint, we trust the card vendors. This + * may be a misplaced trust. + */ +#define BUS_ADDR(x) ((((unsigned long)(x)) << 2) + IO_BASE) +#define POD_INT_ADDR(x) ((volatile unsigned char *)\ + ((BUS_ADDR((x)) - IO_BASE) + IO_START)) + +static inline void ecard_task_reset(struct ecard_request *req) +{ + struct expansion_card *ec = req->ec; + if (ec->loader) + ecard_loader_reset(POD_INT_ADDR(ec->podaddr), ec->loader); +} + +static void +ecard_task_readbytes(struct ecard_request *req) +{ + unsigned char *buf = (unsigned char *)req->buffer; + volatile unsigned char *base_addr = + (volatile unsigned char *)POD_INT_ADDR(req->ec->podaddr); + unsigned int len = req->length; + unsigned int off = req->address; + + if (req->ec->slot_no == 8) { + /* + * The card maintains an index which increments the address + * into a 4096-byte page on each access. We need to keep + * track of the counter. + */ + static unsigned int index; + unsigned int page; + + page = (off >> 12) * 4; + if (page > 256 * 4) + return; + + off &= 4095; + + /* + * If we are reading offset 0, or our current index is + * greater than the offset, reset the hardware index counter. + */ + if (off == 0 || index > off) { + *base_addr = 0; + index = 0; + } + + /* + * Increment the hardware index counter until we get to the + * required offset. The read bytes are discarded. + */ + while (index < off) { + unsigned char byte; + byte = base_addr[page]; + index += 1; + } + + while (len--) { + *buf++ = base_addr[page]; + index += 1; + } + } else { + + if (!req->use_loader || !req->ec->loader) { + off *= 4; + while (len--) { + *buf++ = base_addr[off]; + off += 4; + } + } else { + while(len--) { + /* + * The following is required by some + * expansion card loader programs. + */ + *(unsigned long *)0x108 = 0; + *buf++ = ecard_loader_read(off++, base_addr, + req->ec->loader); + } + } + } + +} + +static void ecard_do_request(struct ecard_request *req) +{ + switch (req->req) { + case req_readbytes: + ecard_task_readbytes(req); + break; + + case req_reset: + ecard_task_reset(req); + break; + } +} + +/* + * On 26-bit processors, we don't need the kcardd thread to access the + * expansion card loaders. We do it directly. + */ +#define ecard_call(req) ecard_do_request(req) + +/* ======================= Mid-level card control ===================== */ + +static void +ecard_readbytes(void *addr, ecard_t *ec, int off, int len, int useld) +{ + struct ecard_request req; + + req.req = req_readbytes; + req.ec = ec; + req.address = off; + req.length = len; + req.use_loader = useld; + req.buffer = addr; + + ecard_call(&req); +} + +int ecard_readchunk(struct in_chunk_dir *cd, ecard_t *ec, int id, int num) +{ + struct ex_chunk_dir excd; + int index = 16; + int useld = 0; + + if (!ec->cid.cd) + return 0; + + while(1) { + ecard_readbytes(&excd, ec, index, 8, useld); + index += 8; + if (c_id(&excd) == 0) { + if (!useld && ec->loader) { + useld = 1; + index = 0; + continue; + } + return 0; + } + if (c_id(&excd) == 0xf0) { /* link */ + index = c_start(&excd); + continue; + } + if (c_id(&excd) == 0x80) { /* loader */ + if (!ec->loader) { + ec->loader = (loader_t)kmalloc(c_len(&excd), + GFP_KERNEL); + if (ec->loader) + ecard_readbytes(ec->loader, ec, + (int)c_start(&excd), + c_len(&excd), useld); + else + return 0; + } + continue; + } + if (c_id(&excd) == id && num-- == 0) + break; + } + + if (c_id(&excd) & 0x80) { + switch (c_id(&excd) & 0x70) { + case 0x70: + ecard_readbytes((unsigned char *)excd.d.string, ec, + (int)c_start(&excd), c_len(&excd), + useld); + break; + case 0x00: + break; + } + } + cd->start_offset = c_start(&excd); + memcpy(cd->d.string, excd.d.string, 256); + return 1; +} + +/* ======================= Interrupt control ============================ */ + +static void ecard_def_irq_enable(ecard_t *ec, int irqnr) +{ +} + +static void ecard_def_irq_disable(ecard_t *ec, int irqnr) +{ +} + +static int ecard_def_irq_pending(ecard_t *ec) +{ + return !ec->irqmask || ec->irqaddr[0] & ec->irqmask; +} + +static void ecard_def_fiq_enable(ecard_t *ec, int fiqnr) +{ + panic("ecard_def_fiq_enable called - impossible"); +} + +static void ecard_def_fiq_disable(ecard_t *ec, int fiqnr) +{ + panic("ecard_def_fiq_disable called - impossible"); +} + +static int ecard_def_fiq_pending(ecard_t *ec) +{ + return !ec->fiqmask || ec->fiqaddr[0] & ec->fiqmask; +} + +static expansioncard_ops_t ecard_default_ops = { + ecard_def_irq_enable, + ecard_def_irq_disable, + ecard_def_irq_pending, + ecard_def_fiq_enable, + ecard_def_fiq_disable, + ecard_def_fiq_pending +}; + +/* + * Enable and disable interrupts from expansion cards. + * (interrupts are disabled for these functions). + * + * They are not meant to be called directly, but via enable/disable_irq. + */ +static void ecard_irq_unmask(unsigned int irqnr) +{ + ecard_t *ec = slot_to_ecard(irqnr - 32); + + if (ec) { + if (!ec->ops) + ec->ops = &ecard_default_ops; + + if (ec->claimed && ec->ops->irqenable) + ec->ops->irqenable(ec, irqnr); + else + printk(KERN_ERR "ecard: rejecting request to " + "enable IRQs for %d\n", irqnr); + } +} + +static void ecard_irq_mask(unsigned int irqnr) +{ + ecard_t *ec = slot_to_ecard(irqnr - 32); + + if (ec) { + if (!ec->ops) + ec->ops = &ecard_default_ops; + + if (ec->ops && ec->ops->irqdisable) + ec->ops->irqdisable(ec, irqnr); + } +} + +static struct irqchip ecard_chip = { + .ack = ecard_irq_mask, + .mask = ecard_irq_mask, + .unmask = ecard_irq_unmask, +}; + +void ecard_enablefiq(unsigned int fiqnr) +{ + ecard_t *ec = slot_to_ecard(fiqnr); + + if (ec) { + if (!ec->ops) + ec->ops = &ecard_default_ops; + + if (ec->claimed && ec->ops->fiqenable) + ec->ops->fiqenable(ec, fiqnr); + else + printk(KERN_ERR "ecard: rejecting request to " + "enable FIQs for %d\n", fiqnr); + } +} + +void ecard_disablefiq(unsigned int fiqnr) +{ + ecard_t *ec = slot_to_ecard(fiqnr); + + if (ec) { + if (!ec->ops) + ec->ops = &ecard_default_ops; + + if (ec->ops->fiqdisable) + ec->ops->fiqdisable(ec, fiqnr); + } +} + +static void +ecard_dump_irq_state(ecard_t *ec) +{ + printk(" %d: %sclaimed, ", + ec->slot_no, + ec->claimed ? "" : "not "); + + if (ec->ops && ec->ops->irqpending && + ec->ops != &ecard_default_ops) + printk("irq %spending\n", + ec->ops->irqpending(ec) ? "" : "not "); + else + printk("irqaddr %p, mask = %02X, status = %02X\n", + ec->irqaddr, ec->irqmask, *ec->irqaddr); +} + +static void ecard_check_lockup(struct irqdesc *desc) +{ + static int last, lockup; + ecard_t *ec; + + /* + * If the timer interrupt has not run since the last million + * unrecognised expansion card interrupts, then there is + * something seriously wrong. Disable the expansion card + * interrupts so at least we can continue. + * + * Maybe we ought to start a timer to re-enable them some time + * later? + */ + if (last == jiffies) { + lockup += 1; + if (lockup > 1000000) { + printk(KERN_ERR "\nInterrupt lockup detected - " + "disabling all expansion card interrupts\n"); + + desc->chip->mask(IRQ_EXPANSIONCARD); + + printk("Expansion card IRQ state:\n"); + + for (ec = cards; ec; ec = ec->next) + ecard_dump_irq_state(ec); + } + } else + lockup = 0; + + /* + * If we did not recognise the source of this interrupt, + * warn the user, but don't flood the user with these messages. + */ + if (!last || time_after(jiffies, (unsigned long)(last + 5*HZ))) { + last = jiffies; + printk(KERN_WARNING "Unrecognised interrupt from backplane\n"); + } +} + +static void +ecard_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) +{ + ecard_t *ec; + int called = 0; + + desc->chip->mask(irq); + for (ec = cards; ec; ec = ec->next) { + int pending; + + if (!ec->claimed || ec->irq == NO_IRQ || ec->slot_no == 8) + continue; + + if (ec->ops && ec->ops->irqpending) + pending = ec->ops->irqpending(ec); + else + pending = ecard_default_ops.irqpending(ec); + + if (pending) { + struct irqdesc *d = irq_desc + ec->irq; + d->handle(ec->irq, d, regs); + called ++; + } + } + desc->chip->unmask(irq); + + if (called == 0) + ecard_check_lockup(desc); +} + +#define ecard_irqexp_handler NULL +#define ecard_probeirqhw() (0) + +unsigned int ecard_address(ecard_t *ec, card_type_t type, card_speed_t speed) +{ + unsigned long address = 0; + int slot = ec->slot_no; + + if (ec->slot_no == 8) + return 0; + + ectcr &= ~(1 << slot); + + switch (type) { + case ECARD_MEMC: + if (slot < 4) + address = IO_EC_MEMC_BASE + (slot << 12); + break; + + case ECARD_IOC: + if (slot < 4) + address = IO_EC_IOC_BASE + (slot << 12); + if (address) + address += speed << 17; + break; + + default: + break; + } + + return address; +} + +static int ecard_prints(char *buffer, ecard_t *ec) +{ + char *start = buffer; + + buffer += sprintf(buffer, " %d: %s ", ec->slot_no, + ec->type == ECARD_EASI ? "EASI" : " "); + + if (ec->cid.id == 0) { + struct in_chunk_dir incd; + + buffer += sprintf(buffer, "[%04X:%04X] ", + ec->cid.manufacturer, ec->cid.product); + + if (!ec->card_desc && ec->cid.cd && + ecard_readchunk(&incd, ec, 0xf5, 0)) { + ec->card_desc = kmalloc(strlen(incd.d.string)+1, GFP_KERNEL); + + if (ec->card_desc) + strcpy((char *)ec->card_desc, incd.d.string); + } + + buffer += sprintf(buffer, "%s\n", ec->card_desc ? ec->card_desc : "*unknown*"); + } else + buffer += sprintf(buffer, "Simple card %d\n", ec->cid.id); + + return buffer - start; +} + +static int get_ecard_dev_info(char *buf, char **start, off_t pos, int count) +{ + ecard_t *ec = cards; + off_t at = 0; + int len, cnt; + + cnt = 0; + while (ec && count > cnt) { + len = ecard_prints(buf, ec); + at += len; + if (at >= pos) { + if (!*start) { + *start = buf + (pos - (at - len)); + cnt = at - pos; + } else + cnt += len; + buf += len; + } + ec = ec->next; + } + return (count > cnt) ? cnt : count; +} + +static struct proc_dir_entry *proc_bus_ecard_dir = NULL; + +static void ecard_proc_init(void) +{ + proc_bus_ecard_dir = proc_mkdir("ecard", proc_bus); + create_proc_info_entry("devices", 0, proc_bus_ecard_dir, + get_ecard_dev_info); +} + +#define ec_set_resource(ec,nr,st,sz,flg) \ + do { \ + (ec)->resource[nr].name = ec->dev.name; \ + (ec)->resource[nr].start = st; \ + (ec)->resource[nr].end = (st) + (sz) - 1; \ + (ec)->resource[nr].flags = flg; \ + } while (0) + +static void __init ecard_init_resources(struct expansion_card *ec) +{ + unsigned long base = PODSLOT_IOC0_BASE; + unsigned int slot = ec->slot_no; + int i; + + if (slot < 4) { + ec_set_resource(ec, ECARD_RES_MEMC, + PODSLOT_MEMC_BASE + (slot << 14), + PODSLOT_MEMC_SIZE, IORESOURCE_MEM); + } + + for (i = 0; i < ECARD_RES_IOCSYNC - ECARD_RES_IOCSLOW; i++) { + ec_set_resource(ec, i + ECARD_RES_IOCSLOW, + base + (slot << 14) + (i << 19), + PODSLOT_IOC_SIZE, IORESOURCE_MEM); + } + + for (i = 0; i < ECARD_NUM_RESOURCES; i++) { + if (ec->resource[i].start && + request_resource(&iomem_resource, &ec->resource[i])) { + printk(KERN_ERR "%s: resource(s) not available\n", + ec->dev.bus_id); + ec->resource[i].end -= ec->resource[i].start; + ec->resource[i].start = 0; + } + } +} + +static ssize_t ecard_show_irq(struct device *dev, char *buf) +{ + struct expansion_card *ec = ECARD_DEV(dev); + return sprintf(buf, "%u\n", ec->irq); +} + +static DEVICE_ATTR(irq, S_IRUGO, ecard_show_irq, NULL); + +static ssize_t ecard_show_dma(struct device *dev, char *buf) +{ + struct expansion_card *ec = ECARD_DEV(dev); + return sprintf(buf, "%u\n", ec->dma); +} + +static DEVICE_ATTR(dma, S_IRUGO, ecard_show_dma, NULL); + +static ssize_t ecard_show_resources(struct device *dev, char *buf) +{ + struct expansion_card *ec = ECARD_DEV(dev); + char *str = buf; + int i; + + for (i = 0; i < ECARD_NUM_RESOURCES; i++) + str += sprintf(str, "%08lx %08lx %08lx\n", + ec->resource[i].start, + ec->resource[i].end, + ec->resource[i].flags); + + return str - buf; +} + +static DEVICE_ATTR(resource, S_IRUGO, ecard_show_resources, NULL); + +/* + * Probe for an expansion card. + * + * If bit 1 of the first byte of the card is set, then the + * card does not exist. + */ +static int __init +ecard_probe(int slot, card_type_t type) +{ + ecard_t **ecp; + ecard_t *ec; + struct ex_ecid cid; + int i, rc = -ENOMEM; + + ec = kmalloc(sizeof(ecard_t), GFP_KERNEL); + if (!ec) + goto nomem; + + memset(ec, 0, sizeof(ecard_t)); + + ec->slot_no = slot; + ec->type = type; + ec->irq = NO_IRQ; + ec->fiq = NO_IRQ; + ec->dma = NO_DMA; + ec->card_desc = NULL; + ec->ops = &ecard_default_ops; + + rc = -ENODEV; + if ((ec->podaddr = ecard_address(ec, type, ECARD_SYNC)) == 0) + goto nodev; + + cid.r_zero = 1; + ecard_readbytes(&cid, ec, 0, 16, 0); + if (cid.r_zero) + goto nodev; + + ec->cid.id = cid.r_id; + ec->cid.cd = cid.r_cd; + ec->cid.is = cid.r_is; + ec->cid.w = cid.r_w; + ec->cid.manufacturer = ecard_getu16(cid.r_manu); + ec->cid.product = ecard_getu16(cid.r_prod); + ec->cid.country = cid.r_country; + ec->cid.irqmask = cid.r_irqmask; + ec->cid.irqoff = ecard_gets24(cid.r_irqoff); + ec->cid.fiqmask = cid.r_fiqmask; + ec->cid.fiqoff = ecard_gets24(cid.r_fiqoff); + ec->fiqaddr = + ec->irqaddr = (unsigned char *)ioaddr(ec->podaddr); + + if (ec->cid.is) { + ec->irqmask = ec->cid.irqmask; + ec->irqaddr += ec->cid.irqoff; + ec->fiqmask = ec->cid.fiqmask; + ec->fiqaddr += ec->cid.fiqoff; + } else { + ec->irqmask = 1; + ec->fiqmask = 4; + } + + for (i = 0; i < sizeof(blacklist) / sizeof(*blacklist); i++) + if (blacklist[i].manufacturer == ec->cid.manufacturer && + blacklist[i].product == ec->cid.product) { + ec->card_desc = blacklist[i].type; + break; + } + + snprintf(ec->dev.bus_id, sizeof(ec->dev.bus_id), "ecard%d", slot); + snprintf(ec->dev.name, sizeof(ec->dev.name), "ecard %04x:%04x", + ec->cid.manufacturer, ec->cid.product); + ec->dev.parent = NULL; + ec->dev.bus = &ecard_bus_type; + ec->dev.dma_mask = &ec->dma_mask; + ec->dma_mask = (u64)0xffffffff; + + ecard_init_resources(ec); + + /* + * hook the interrupt handlers + */ + if (slot < 8) { + ec->irq = 32 + slot; + set_irq_chip(ec->irq, &ecard_chip); + set_irq_handler(ec->irq, do_level_IRQ); + set_irq_flags(ec->irq, IRQF_VALID); + } + + for (ecp = &cards; *ecp; ecp = &(*ecp)->next); + + *ecp = ec; + slot_to_expcard[slot] = ec; + + device_register(&ec->dev); + device_create_file(&ec->dev, &dev_attr_dma); + device_create_file(&ec->dev, &dev_attr_irq); + device_create_file(&ec->dev, &dev_attr_resource); + + return 0; + +nodev: + kfree(ec); +nomem: + return rc; +} + +/* + * Initialise the expansion card system. + * Locate all hardware - interrupt management and + * actual cards. + */ +static int __init ecard_init(void) +{ + int slot, irqhw; + + printk("Probing expansion cards\n"); + + for (slot = 0; slot < 8; slot ++) { + if (ecard_probe(slot, ECARD_EASI) == -ENODEV) + ecard_probe(slot, ECARD_IOC); + } + + irqhw = ecard_probeirqhw(); + + set_irq_chained_handler(IRQ_EXPANSIONCARD, + irqhw ? ecard_irqexp_handler : ecard_irq_handler); + + ecard_proc_init(); + + return 0; +} + +subsys_initcall(ecard_init); + +/* + * ECARD "bus" + */ +static const struct ecard_id * +ecard_match_device(const struct ecard_id *ids, struct expansion_card *ec) +{ + int i; + + for (i = 0; ids[i].manufacturer != 65535; i++) + if (ec->cid.manufacturer == ids[i].manufacturer && + ec->cid.product == ids[i].product) + return ids + i; + + return NULL; +} + +static int ecard_drv_probe(struct device *dev) +{ + struct expansion_card *ec = ECARD_DEV(dev); + struct ecard_driver *drv = ECARD_DRV(dev->driver); + const struct ecard_id *id; + int ret; + + id = ecard_match_device(drv->id_table, ec); + + ecard_claim(ec); + ret = drv->probe(ec, id); + if (ret) + ecard_release(ec); + return ret; +} + +static int ecard_drv_remove(struct device *dev) +{ + struct expansion_card *ec = ECARD_DEV(dev); + struct ecard_driver *drv = ECARD_DRV(dev->driver); + + drv->remove(ec); + ecard_release(ec); + + return 0; +} + +/* + * Before rebooting, we must make sure that the expansion card is in a + * sensible state, so it can be re-detected. This means that the first + * page of the ROM must be visible. We call the expansion cards reset + * handler, if any. + */ +static void ecard_drv_shutdown(struct device *dev) +{ + struct expansion_card *ec = ECARD_DEV(dev); + struct ecard_driver *drv = ECARD_DRV(dev->driver); + struct ecard_request req; + + if (drv->shutdown) + drv->shutdown(ec); + ecard_release(ec); + req.req = req_reset; + req.ec = ec; + ecard_call(&req); +} + +int ecard_register_driver(struct ecard_driver *drv) +{ + drv->drv.bus = &ecard_bus_type; + drv->drv.probe = ecard_drv_probe; + drv->drv.remove = ecard_drv_remove; + drv->drv.shutdown = ecard_drv_shutdown; + + return driver_register(&drv->drv); +} + +void ecard_remove_driver(struct ecard_driver *drv) +{ + driver_unregister(&drv->drv); +} + +static int ecard_match(struct device *_dev, struct device_driver *_drv) +{ + struct expansion_card *ec = ECARD_DEV(_dev); + struct ecard_driver *drv = ECARD_DRV(_drv); + int ret; + + if (drv->id_table) { + ret = ecard_match_device(drv->id_table, ec) != NULL; + } else { + ret = ec->cid.id == drv->id; + } + + return ret; +} + +struct bus_type ecard_bus_type = { + .name = "ecard", + .match = ecard_match, +}; + +static int ecard_bus_init(void) +{ + return bus_register(&ecard_bus_type); +} + +postcore_initcall(ecard_bus_init); + +EXPORT_SYMBOL(ecard_readchunk); +EXPORT_SYMBOL(ecard_address); +EXPORT_SYMBOL(ecard_register_driver); +EXPORT_SYMBOL(ecard_remove_driver); +EXPORT_SYMBOL(ecard_bus_type); diff -Nru a/arch/arm26/kernel/entry.S b/arch/arm26/kernel/entry.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/kernel/entry.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,982 @@ +/* arch/arm26/kernel/entry.S + * + * Assembled from chunks of code in arch/arm + * + * Copyright (C) 2003 Ian Molton + * + */ + +#include <linux/config.h> /* for CONFIG_ARCH_xxxx */ +#include <linux/linkage.h> + +#include <asm/assembler.h> +#include <asm/asm_offsets.h> +#include <asm/errno.h> +#include <asm/hardware.h> +#include <asm/sysirq.h> +#include <asm/thread_info.h> +#include <asm/page.h> +#include <asm/ptrace.h> + + .macro zero_fp +#ifndef CONFIG_NO_FRAME_POINTER + mov fp, #0 +#endif + .endm + + .text + +@ Bad Abort numbers +@ ----------------- +@ +#define BAD_PREFETCH 0 +#define BAD_DATA 1 +#define BAD_ADDREXCPTN 2 +#define BAD_IRQ 3 +#define BAD_UNDEFINSTR 4 + +#define PT_TRACESYS 0x00000002 + +@ OS version number used in SWIs +@ RISC OS is 0 +@ RISC iX is 8 +@ +#define OS_NUMBER 9 +#define ARMSWI_OFFSET 0x000f0000 + +@ +@ Stack format (ensured by USER_* and SVC_*) +@ +#define S_FRAME_SIZE 72 +#define S_OLD_R0 64 +#define S_PSR 60 +#define S_PC 60 +#define S_LR 56 +#define S_SP 52 +#define S_IP 48 +#define S_FP 44 +#define S_R10 40 +#define S_R9 36 +#define S_R8 32 +#define S_R7 28 +#define S_R6 24 +#define S_R5 20 +#define S_R4 16 +#define S_R3 12 +#define S_R2 8 +#define S_R1 4 +#define S_R0 0 +#define S_OFF 8 + + .macro save_user_regs + str r0, [sp, #-4]! + str lr, [sp, #-4]! + sub sp, sp, #15*4 + stmia sp, {r0 - lr}^ + mov r0, r0 + .endm + + .macro slow_restore_user_regs + ldmia sp, {r0 - lr}^ + mov r0, r0 + ldr lr, [sp, #15*4] + add sp, sp, #15*4+8 + movs pc, lr + .endm + + .macro fast_restore_user_regs + add sp, sp, #S_OFF + ldmib sp, {r1 - lr}^ + mov r0, r0 + ldr lr, [sp, #15*4] + add sp, sp, #15*4+8 + movs pc, lr + .endm + + .macro mask_pc, rd, rm + bic \rd, \rm, #PCMASK + .endm + + .macro disable_irqs, temp + mov \temp, pc + orr \temp, \temp, #PSR_I_BIT + teqp \temp, #0 + .endm + + .macro enable_irqs, temp + mov \temp, pc + and \temp, \temp, #~PSR_I_BIT + teqp \temp, #0 + .endm + + .macro initialise_traps_extra + .endm + + .macro get_thread_info, rd + mov \rd, sp, lsr #13 + mov \rd, \rd, lsl #13 + .endm + + /* + * Like adr, but force SVC mode (if required) + */ + .macro adrsvc, cond, reg, label + adr\cond \reg, \label + orr\cond \reg, \reg, #PSR_I_BIT | MODE_SVC26 + .endm + + +/* + * These are the registers used in the syscall handler, and allow us to + * have in theory up to 7 arguments to a function - r0 to r6. + * + * r7 is reserved for the system call number for thumb mode. + * + * Note that tbl == why is intentional. + * + * We must set at least "tsk" and "why" when calling ret_with_reschedule. + */ +scno .req r7 @ syscall number +tbl .req r8 @ syscall table pointer +why .req r8 @ Linux syscall (!= 0) +tsk .req r9 @ current thread_info + +/* + * Get the system call number. + */ + .macro get_scno + mask_pc lr, lr + ldr scno, [lr, #-4] @ get SWI instruction + .endm +/* + * ----------------------------------------------------------------------- + */ + +/* + * We rely on the fact that R0 is at the bottom of the stack (due to + * slow/fast restore user regs). + */ +#if S_R0 != 0 +#error "Please fix" +#endif + +/* + * Our do_softirq out of line code. See include/asm-arm/softirq.h for + * the calling assembly. + */ +ENTRY(__do_softirq) + stmfd sp!, {r0 - r3, ip, lr} + bl do_softirq + ldmfd sp!, {r0 - r3, ip, pc} + + .align 5 + +/* + * This is the fast syscall return path. We do as little as + * possible here, and this includes saving r0 back into the SVC + * stack. + */ +ret_fast_syscall: + disable_irqs r1 @ disable interrupts + ldr r1, [tsk, #TI_FLAGS] + tst r1, #_TIF_WORK_MASK + bne fast_work_pending + fast_restore_user_regs + +/* + * Ok, we need to do extra processing, enter the slow path. + */ +fast_work_pending: + str r0, [sp, #S_R0+S_OFF]! @ returned r0 +work_pending: + tst r1, #_TIF_NEED_RESCHED + bne work_resched + tst r1, #_TIF_NOTIFY_RESUME | _TIF_SIGPENDING + beq no_work_pending + mov r0, sp @ 'regs' + mov r2, why @ 'syscall' + bl do_notify_resume + disable_irqs r1 @ disable interrupts + b no_work_pending + +work_resched: + bl schedule +/* + * "slow" syscall return path. "why" tells us if this was a real syscall. + */ +ENTRY(ret_to_user) +ret_slow_syscall: + disable_irqs r1 @ disable interrupts + ldr r1, [tsk, #TI_FLAGS] + tst r1, #_TIF_WORK_MASK + bne work_pending +no_work_pending: + slow_restore_user_regs + +/* + * This is how we return from a fork. + */ +ENTRY(ret_from_fork) + bl schedule_tail + get_thread_info tsk + ldr r1, [tsk, #TI_FLAGS] @ check for syscall tracing + mov why, #1 + tst r1, #_TIF_SYSCALL_TRACE @ are we tracing syscalls? + beq ret_slow_syscall + mov r1, sp + mov r0, #1 @ trace exit [IP = 1] + bl syscall_trace + b ret_slow_syscall + +#include <asm/calls.h> + +/*============================================================================= + * SWI handler + *----------------------------------------------------------------------------- + */ + + .align 5 +ENTRY(vector_swi) + save_user_regs + zero_fp + get_scno + +#ifdef CONFIG_ALIGNMENT_TRAP + ldr ip, __cr_alignment + ldr ip, [ip] + mcr p15, 0, ip, c1, c0 @ update control register +#endif + enable_irqs ip + + str r4, [sp, #-S_OFF]! @ push fifth arg + + get_thread_info tsk + ldr ip, [tsk, #TI_FLAGS] @ check for syscall tracing + bic scno, scno, #0xff000000 @ mask off SWI op-code + eor scno, scno, #OS_NUMBER << 20 @ check OS number + adr tbl, sys_call_table @ load syscall table pointer + tst ip, #_TIF_SYSCALL_TRACE @ are we tracing syscalls? + bne __sys_trace + + adrsvc al, lr, ret_fast_syscall @ return address + cmp scno, #NR_syscalls @ check upper syscall limit + ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine + + add r1, sp, #S_OFF +2: mov why, #0 @ no longer a real syscall + cmp scno, #ARMSWI_OFFSET + eor r0, scno, #OS_NUMBER << 20 @ put OS number back + bcs arm_syscall + b sys_ni_syscall @ not private func + + /* + * This is the really slow path. We're going to be doing + * context switches, and waiting for our parent to respond. + */ +__sys_trace: + add r1, sp, #S_OFF + mov r0, #0 @ trace entry [IP = 0] + bl syscall_trace + + adrsvc al, lr, __sys_trace_return @ return address + add r1, sp, #S_R0 + S_OFF @ pointer to regs + cmp scno, #NR_syscalls @ check upper syscall limit + ldmccia r1, {r0 - r3} @ have to reload r0 - r3 + ldrcc pc, [tbl, scno, lsl #2] @ call sys_* routine + b 2b + +__sys_trace_return: + str r0, [sp, #S_R0 + S_OFF]! @ save returned r0 + mov r1, sp + mov r0, #1 @ trace exit [IP = 1] + bl syscall_trace + b ret_slow_syscall + + .align 5 +#ifdef CONFIG_ALIGNMENT_TRAP + .type __cr_alignment, #object +__cr_alignment: + .word cr_alignment +#endif + + .type sys_call_table, #object +ENTRY(sys_call_table) +#include <asm/calls.h> + +/*============================================================================ + * Special system call wrappers + */ +@ r0 = syscall number +@ r5 = syscall table + .type sys_syscall, #function +sys_syscall: + eor scno, r0, #OS_NUMBER << 20 + cmp scno, #NR_syscalls @ check range + stmleia sp, {r5, r6} @ shuffle args + movle r0, r1 + movle r1, r2 + movle r2, r3 + movle r3, r4 + ldrle pc, [tbl, scno, lsl #2] + b sys_ni_syscall + +sys_fork_wrapper: + add r0, sp, #S_OFF + b sys_fork + +sys_vfork_wrapper: + add r0, sp, #S_OFF + b sys_vfork + +sys_execve_wrapper: + add r3, sp, #S_OFF + b sys_execve + +sys_clone_wapper: + add r2, sp, #S_OFF + b sys_clone + +sys_sigsuspend_wrapper: + add r3, sp, #S_OFF + b sys_sigsuspend + +sys_rt_sigsuspend_wrapper: + add r2, sp, #S_OFF + b sys_rt_sigsuspend + +sys_sigreturn_wrapper: + add r0, sp, #S_OFF + b sys_sigreturn + +sys_rt_sigreturn_wrapper: + add r0, sp, #S_OFF + b sys_rt_sigreturn + +sys_sigaltstack_wrapper: + ldr r2, [sp, #S_OFF + S_SP] + b do_sigaltstack + +/* + * Note: off_4k (r5) is always units of 4K. If we can't do the requested + * offset, we return EINVAL. FIXME - this lost some stuff from arm32 to + * ifdefs. check it out. + */ +sys_mmap2: + tst r5, #((1 << (PAGE_SHIFT - 12)) - 1) + moveq r5, r5, lsr #PAGE_SHIFT - 12 + streq r5, [sp, #4] + beq do_mmap2 + mov r0, #-EINVAL + RETINSTR(mov,pc, lr) + +/* + * Design issues: + * - We have several modes that each vector can be called from, + * each with its own set of registers. On entry to any vector, + * we *must* save the registers used in *that* mode. + * + * - This code must be as fast as possible. + * + * There are a few restrictions on the vectors: + * - the SWI vector cannot be called from *any* non-user mode + * + * - the FP emulator is *never* called from *any* non-user mode undefined + * instruction. + * + */ + + .text + + .equ ioc_base_high, IOC_BASE & 0xff000000 + .equ ioc_base_low, IOC_BASE & 0x00ff0000 + .macro disable_fiq + mov r12, #ioc_base_high + .if ioc_base_low + orr r12, r12, #ioc_base_low + .endif + strb r12, [r12, #0x38] @ Disable FIQ register + .endm + + .macro get_irqnr_and_base, irqnr, base + mov r4, #ioc_base_high @ point at IOC + .if ioc_base_low + orr r4, r4, #ioc_base_low + .endif + ldrb \irqnr, [r4, #0x24] @ get high priority first + adr \base, irq_prio_h + teq \irqnr, #0 + ldreqb \irqnr, [r4, #0x14] @ get low priority + adreq \base, irq_prio_l + .endm + +/* + * Interrupt table (incorporates priority) + */ + .macro irq_prio_table +irq_prio_l: .byte 0, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 + .byte 4, 0, 1, 0, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 + .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + .byte 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3 + .byte 6, 6, 6, 6, 6, 6, 6, 6, 3, 3, 3, 3, 3, 3, 3, 3 + .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + .byte 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + .byte 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 +irq_prio_h: .byte 0, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 12, 8, 9, 8,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 14,14,14,14,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 15,15,15,15,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .byte 13,13,13,13,10,10,10,10,11,11,11,11,10,10,10,10 + .endm + +#if 1 +/* FIXME (well, ok, dont - but its easy to grep for :) */ +/* + * Uncomment these if you wish to get more debugging into about data aborts. + */ +#define FAULT_CODE_LDRSTRPOST 0x80 +#define FAULT_CODE_LDRSTRPRE 0x40 +#define FAULT_CODE_LDRSTRREG 0x20 +#define FAULT_CODE_LDMSTM 0x10 +#define FAULT_CODE_LDCSTC 0x08 +#endif +#define FAULT_CODE_PREFETCH 0x04 +#define FAULT_CODE_WRITE 0x02 +#define FAULT_CODE_FORCECOW 0x01 + +#define SVC_SAVE_ALL \ + str sp, [sp, #-16]! ;\ + str lr, [sp, #8] ;\ + str lr, [sp, #4] ;\ + stmfd sp!, {r0 - r12} ;\ + mov r0, #-1 ;\ + str r0, [sp, #S_OLD_R0] ;\ + zero_fp + +#define SVC_IRQ_SAVE_ALL \ + str sp, [sp, #-16]! ;\ + str lr, [sp, #4] ;\ + ldr lr, .LCirq ;\ + ldr lr, [lr] ;\ + str lr, [sp, #8] ;\ + stmfd sp!, {r0 - r12} ;\ + mov r0, #-1 ;\ + str r0, [sp, #S_OLD_R0] ;\ + zero_fp + +#define SVC_RESTORE_ALL \ + ldmfd sp, {r0 - pc}^ + +/*============================================================================= + * Undefined FIQs + *----------------------------------------------------------------------------- + */ +_unexp_fiq: ldr sp, .LCfiq + mov r12, #IOC_BASE + strb r12, [r12, #0x38] @ Disable FIQ register + teqp pc, #PSR_I_BIT | PSR_F_BIT | MODE_SVC26 + mov r0, r0 + stmfd sp!, {r0 - r3, ip, lr} + adr r0, Lfiqmsg + bl printk + ldmfd sp!, {r0 - r3, ip, lr} + teqp pc, #PSR_I_BIT | PSR_F_BIT | MODE_FIQ26 + mov r0, r0 + movs pc, lr + +Lfiqmsg: .ascii "*** Unexpected FIQ\n\0" + .align + +.LCfiq: .word __temp_fiq +.LCirq: .word __temp_irq + +/*============================================================================= + * Undefined instruction handler + *----------------------------------------------------------------------------- + * Handles floating point instructions + */ +vector_undefinstr: + tst lr,#3 + bne __und_svc + save_user_regs + zero_fp + teqp pc, #PSR_I_BIT | MODE_SVC26 +.Lbug_undef: + ldr r4, .LC2 + ldr pc, [r4] @ Call FP module USR entry point + + .globl fpundefinstr +fpundefinstr: @ Called by FP module on undefined instr + mov r0, lr + mov r1, sp + teqp pc, #MODE_SVC26 + bl do_undefinstr + b ret_from_exception @ Normal FP exit + +__und_svc: SVC_SAVE_ALL @ Non-user mode + mask_pc r0, lr + and r2, lr, #3 + sub r0, r0, #4 + mov r1, sp + bl do_undefinstr + SVC_RESTORE_ALL + +#if defined CONFIG_FPE_NWFPE || defined CONFIG_FPE_FASTFPE + /* The FPE is always present */ + .equ fpe_not_present, 0 +#else +/* We get here if an undefined instruction happens and the floating + * point emulator is not present. If the offending instruction was + * a WFS, we just perform a normal return as if we had emulated the + * operation. This is a hack to allow some basic userland binaries + * to run so that the emulator module proper can be loaded. --philb + */ +fpe_not_present: + adr r10, wfs_mask_data + ldmia r10, {r4, r5, r6, r7, r8} + ldr r10, [sp, #S_PC] @ Load PC + sub r10, r10, #4 + mask_pc r10, r10 + ldrt r10, [r10] @ get instruction + and r5, r10, r5 + teq r5, r4 @ Is it WFS? + beq ret_from_exception + and r5, r10, r8 + teq r5, r6 @ Is it LDF/STF on sp or fp? + teqne r5, r7 + bne fpundefinstr + tst r10, #0x00200000 @ Does it have WB + beq ret_from_exception + and r4, r10, #255 @ get offset + and r6, r10, #0x000f0000 + tst r10, #0x00800000 @ +/- + ldr r5, [sp, r6, lsr #14] @ Load reg + rsbeq r4, r4, #0 + add r5, r5, r4, lsl #2 + str r5, [sp, r6, lsr #14] @ Save reg + b ret_from_exception + +wfs_mask_data: .word 0x0e200110 @ WFS/RFS + .word 0x0fef0fff + .word 0x0d0d0100 @ LDF [sp]/STF [sp] + .word 0x0d0b0100 @ LDF [fp]/STF [fp] + .word 0x0f0f0f00 +#endif + +.LC2: .word fp_enter + +/*============================================================================= + * Prefetch abort handler + *----------------------------------------------------------------------------- + */ + +/* remember: lr = USR pc */ +vector_prefetch: + sub lr, lr, #4 + tst lr, #3 + bne __pabt_invalid + save_user_regs + teqp pc, #MODE_SVC26 + mask_pc r0, lr @ Address of abort + mov r1, sp @ Tasks registers + bl do_PrefetchAbort + teq r0, #0 @ If non-zero, we believe this abort.. + bne ret_from_exception +#ifdef DEBUG_UNDEF + adr r0, t + bl printk +#endif + ldr lr, [sp,#S_PC] @ program to test this on. I think its + b .Lbug_undef @ broken at the moment though!) + +__pabt_invalid: SVC_SAVE_ALL + mov r0, sp @ Prefetch aborts are definitely *not* + mov r1, #BAD_PREFETCH @ allowed in non-user modes. We cant + and r2, lr, #3 @ recover from this problem. + b bad_mode + +#ifdef DEBUG_UNDEF +t: .ascii "*** undef ***\r\n\0" + .align +#endif + +/*============================================================================= + * Address exception handler + *----------------------------------------------------------------------------- + * These aren't too critical. + * (they're not supposed to happen). + * In order to debug the reason for address exceptions in non-user modes, + * we have to obtain all the registers so that we can see what's going on. + */ + +vector_addrexcptn: + sub lr, lr, #8 + tst lr, #3 + bne Laddrexcptn_not_user + save_user_regs + teq pc, #MODE_SVC26 + mask_pc r0, lr @ Point to instruction + mov r1, sp @ Point to registers + mov r2, #0x400 + mov lr, pc + bl do_excpt + b ret_from_exception + +Laddrexcptn_not_user: + SVC_SAVE_ALL + and r2, lr, #3 + teq r2, #3 + bne Laddrexcptn_illegal_mode + teqp pc, #MODE_SVC26 + mask_pc r0, lr + mov r1, sp + orr r2, r2, #0x400 + bl do_excpt + ldmia sp, {r0 - lr} @ I cant remember the reason I changed this... + add sp, sp, #15*4 + movs pc, lr + +Laddrexcptn_illegal_mode: + mov r0, sp + str lr, [sp, #-4]! + orr r1, r2, #PSR_I_BIT | PSR_F_BIT + teqp r1, #0 @ change into mode (wont be user mode) + mov r0, r0 + mov r1, r8 @ Any register from r8 - r14 can be banked + mov r2, r9 + mov r3, r10 + mov r4, r11 + mov r5, r12 + mov r6, r13 + mov r7, r14 + teqp pc, #PSR_F_BIT | MODE_SVC26 @ back to svc + mov r0, r0 + stmfd sp!, {r1-r7} + ldmia r0, {r0-r7} + stmfd sp!, {r0-r7} + mov r0, sp + mov r1, #BAD_ADDREXCPTN + b bad_mode + +/*============================================================================= + * Interrupt (IRQ) handler + *----------------------------------------------------------------------------- + * Note: if in user mode, then *no* kernel routine is running, so do not have + * to save svc lr + * (r13 points to irq temp save area) + */ + +vector_IRQ: ldr r13, .LCirq @ I will leave this one in just in case... + sub lr, lr, #4 + str lr, [r13] + tst lr, #3 + bne __irq_svc + teqp pc, #PSR_I_BIT | MODE_SVC26 + mov r0, r0 + ldr lr, .LCirq + ldr lr, [lr] + save_user_regs + +1: get_irqnr_and_base r6, r5 + teq r6, #0 + ldrneb r0, [r5, r6] @ get IRQ number + movne r1, sp + @ + @ routine called with r0 = irq number, r1 = struct pt_regs * + @ + adr lr, 1b + orr lr, lr, #PSR_I_BIT | MODE_SVC26 @ Force SVC + bne asm_do_IRQ + + mov why, #0 + get_thread_info r5 + b ret_to_user + + irq_prio_table + +__irq_svc: teqp pc, #PSR_I_BIT | MODE_SVC26 + mov r0, r0 + SVC_IRQ_SAVE_ALL + and r2, lr, #3 + teq r2, #3 + bne __irq_invalid +1: get_irqnr_and_base r6, r5 + teq r6, #0 + ldrneb r0, [r5, r6] @ get IRQ number + movne r1, sp + @ + @ routine called with r0 = irq number, r1 = struct pt_regs * + @ + adr lr, 1b + orr lr, lr, #PSR_I_BIT | MODE_SVC26 @ Force SVC + bne asm_do_IRQ @ Returns to 1b + SVC_RESTORE_ALL + +__irq_invalid: mov r0, sp + mov r1, #BAD_IRQ + b bad_mode + +/*============================================================================= + * Data abort handler code + *----------------------------------------------------------------------------- + * + * This handles both exceptions from user and SVC modes, computes the address + * range of the problem, and does any correction that is required. It then + * calls the kernel data abort routine. + * + * This is where I wish that the ARM would tell you which address aborted. + */ + +vector_data: sub lr, lr, #8 @ Correct lr + tst lr, #3 + bne Ldata_not_user + save_user_regs + teqp pc, #MODE_SVC26 + mask_pc r0, lr + bl Ldata_do + b ret_from_exception + +Ldata_not_user: + SVC_SAVE_ALL + and r2, lr, #3 + teq r2, #3 + bne Ldata_illegal_mode + tst lr, #PSR_I_BIT + teqeqp pc, #MODE_SVC26 + mask_pc r0, lr + bl Ldata_do + SVC_RESTORE_ALL + +Ldata_illegal_mode: + mov r0, sp + mov r1, #BAD_DATA + b bad_mode + +Ldata_do: mov r3, sp + ldr r4, [r0] @ Get instruction + mov r2, #0 + tst r4, #1 << 20 @ Check to see if it is a write instruction + orreq r2, r2, #FAULT_CODE_WRITE @ Indicate write instruction + mov r1, r4, lsr #22 @ Now branch to the relevent processing routine + and r1, r1, #15 << 2 + add pc, pc, r1 + movs pc, lr + b Ldata_unknown + b Ldata_unknown + b Ldata_unknown + b Ldata_unknown + b Ldata_ldrstr_post @ ldr rd, [rn], #m + b Ldata_ldrstr_numindex @ ldr rd, [rn, #m] @ RegVal + b Ldata_ldrstr_post @ ldr rd, [rn], rm + b Ldata_ldrstr_regindex @ ldr rd, [rn, rm] + b Ldata_ldmstm @ ldm*a rn, <rlist> + b Ldata_ldmstm @ ldm*b rn, <rlist> + b Ldata_unknown + b Ldata_unknown + b Ldata_ldrstr_post @ ldc rd, [rn], #m @ Same as ldr rd, [rn], #m + b Ldata_ldcstc_pre @ ldc rd, [rn, #m] + b Ldata_unknown +Ldata_unknown: @ Part of jumptable + mov r0, r1 + mov r1, r4 + mov r2, r3 + b baddataabort + +Ldata_ldrstr_post: + mov r0, r4, lsr #14 @ Get Rn + and r0, r0, #15 << 2 @ Mask out reg. + teq r0, #15 << 2 + ldr r0, [r3, r0] @ Get register + biceq r0, r0, #PCMASK + mov r1, r0 +#ifdef FAULT_CODE_LDRSTRPOST + orr r2, r2, #FAULT_CODE_LDRSTRPOST +#endif + b do_DataAbort + +Ldata_ldrstr_numindex: + mov r0, r4, lsr #14 @ Get Rn + and r0, r0, #15 << 2 @ Mask out reg. + teq r0, #15 << 2 + ldr r0, [r3, r0] @ Get register + mov r1, r4, lsl #20 + biceq r0, r0, #PCMASK + tst r4, #1 << 23 + addne r0, r0, r1, lsr #20 + subeq r0, r0, r1, lsr #20 + mov r1, r0 +#ifdef FAULT_CODE_LDRSTRPRE + orr r2, r2, #FAULT_CODE_LDRSTRPRE +#endif + b do_DataAbort + +Ldata_ldrstr_regindex: + mov r0, r4, lsr #14 @ Get Rn + and r0, r0, #15 << 2 @ Mask out reg. + teq r0, #15 << 2 + ldr r0, [r3, r0] @ Get register + and r7, r4, #15 + biceq r0, r0, #PCMASK + teq r7, #15 @ Check for PC + ldr r7, [r3, r7, lsl #2] @ Get Rm + and r8, r4, #0x60 @ Get shift types + biceq r7, r7, #PCMASK + mov r9, r4, lsr #7 @ Get shift amount + and r9, r9, #31 + teq r8, #0 + moveq r7, r7, lsl r9 + teq r8, #0x20 @ LSR shift + moveq r7, r7, lsr r9 + teq r8, #0x40 @ ASR shift + moveq r7, r7, asr r9 + teq r8, #0x60 @ ROR shift + moveq r7, r7, ror r9 + tst r4, #1 << 23 + addne r0, r0, r7 + subeq r0, r0, r7 @ Apply correction + mov r1, r0 +#ifdef FAULT_CODE_LDRSTRREG + orr r2, r2, #FAULT_CODE_LDRSTRREG +#endif + b do_DataAbort + +Ldata_ldmstm: + mov r7, #0x11 + orr r7, r7, r7, lsl #8 + and r0, r4, r7 + and r1, r4, r7, lsl #1 + add r0, r0, r1, lsr #1 + and r1, r4, r7, lsl #2 + add r0, r0, r1, lsr #2 + and r1, r4, r7, lsl #3 + add r0, r0, r1, lsr #3 + add r0, r0, r0, lsr #8 + add r0, r0, r0, lsr #4 + and r7, r0, #15 @ r7 = no. of registers to transfer. + mov r5, r4, lsr #14 @ Get Rn + and r5, r5, #15 << 2 + ldr r0, [r3, r5] @ Get reg + eor r6, r4, r4, lsl #2 + tst r6, #1 << 23 @ Check inc/dec ^ writeback + rsbeq r7, r7, #0 + add r7, r0, r7, lsl #2 @ Do correction (signed) + subne r1, r7, #1 + subeq r1, r0, #1 + moveq r0, r7 + tst r4, #1 << 21 @ Check writeback + strne r7, [r3, r5] + eor r6, r4, r4, lsl #1 + tst r6, #1 << 24 @ Check Pre/Post ^ inc/dec + addeq r0, r0, #4 + addeq r1, r1, #4 + teq r5, #15*4 @ CHECK FOR PC + biceq r1, r1, #PCMASK + biceq r0, r0, #PCMASK +#ifdef FAULT_CODE_LDMSTM + orr r2, r2, #FAULT_CODE_LDMSTM +#endif + b do_DataAbort + +Ldata_ldcstc_pre: + mov r0, r4, lsr #14 @ Get Rn + and r0, r0, #15 << 2 @ Mask out reg. + teq r0, #15 << 2 + ldr r0, [r3, r0] @ Get register + mov r1, r4, lsl #24 @ Get offset + biceq r0, r0, #PCMASK + tst r4, #1 << 23 + addne r0, r0, r1, lsr #24 + subeq r0, r0, r1, lsr #24 + mov r1, r0 +#ifdef FAULT_CODE_LDCSTC + orr r2, r2, #FAULT_CODE_LDCSTC +#endif + b do_DataAbort + + +/* + * This is the return code to user mode for abort handlers + */ +ENTRY(ret_from_exception) + get_thread_info tsk + mov why, #0 + b ret_to_user + + .data +ENTRY(fp_enter) + .word fpe_not_present + .text +/* + * Register switch for older 26-bit only ARMs + */ +ENTRY(__switch_to) + add r0, r0, #TI_CPU_SAVE + stmia r0, {r4 - sl, fp, sp, lr} + add r1, r1, #TI_CPU_SAVE + ldmia r1, {r4 - sl, fp, sp, pc}^ + +/* + *============================================================================= + * Low-level interface code + *----------------------------------------------------------------------------- + * Trap initialisation + *----------------------------------------------------------------------------- + * + * Note - FIQ code has changed. The default is a couple of words in 0x1c, 0x20 + * that call _unexp_fiq. Nowever, we now copy the FIQ routine to 0x1c (removes + * some excess cycles). + * + * What we need to put into 0-0x1c are branches to branch to the kernel. + */ + + .section ".init.text",#alloc,#execinstr + +.Ljump_addresses: + swi SYS_ERROR0 + .word vector_undefinstr - 12 + .word vector_swi - 16 + .word vector_prefetch - 20 + .word vector_data - 24 + .word vector_addrexcptn - 28 + .word vector_IRQ - 32 + .word _unexp_fiq - 36 + b . + 8 +/* + * initialise the trap system + */ +ENTRY(__trap_init) + stmfd sp!, {r4 - r7, lr} + adr r1, .Ljump_addresses + ldmia r1, {r1 - r7, ip, lr} + orr r2, lr, r2, lsr #2 + orr r3, lr, r3, lsr #2 + orr r4, lr, r4, lsr #2 + orr r5, lr, r5, lsr #2 + orr r6, lr, r6, lsr #2 + orr r7, lr, r7, lsr #2 + orr ip, lr, ip, lsr #2 + mov r0, #0 + stmia r0, {r1 - r7, ip} + ldmfd sp!, {r4 - r7, pc}^ + + .bss +__temp_irq: .space 4 @ saved lr_irq +__temp_fiq: .space 128 diff -Nru a/arch/arm26/kernel/fiq.c b/arch/arm26/kernel/fiq.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/kernel/fiq.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,202 @@ +/* + * linux/arch/arm26/kernel/fiq.c + * + * Copyright (C) 1998 Russell King + * Copyright (C) 1998, 1999 Phil Blundell + * Copyright (C) 2003 Ian Molton + * + * FIQ support written by Philip Blundell <philb@gnu.org>, 1998. + * + * FIQ support re-written by Russell King to be more generic + * + * We now properly support a method by which the FIQ handlers can + * be stacked onto the vector. We still do not support sharing + * the FIQ vector itself. + * + * Operation is as follows: + * 1. Owner A claims FIQ: + * - default_fiq relinquishes control. + * 2. Owner A: + * - inserts code. + * - sets any registers, + * - enables FIQ. + * 3. Owner B claims FIQ: + * - if owner A has a relinquish function. + * - disable FIQs. + * - saves any registers. + * - returns zero. + * 4. Owner B: + * - inserts code. + * - sets any registers, + * - enables FIQ. + * 5. Owner B releases FIQ: + * - Owner A is asked to reacquire FIQ: + * - inserts code. + * - restores saved registers. + * - enables FIQ. + * 6. Goto 3 + */ +#include <linux/config.h> +#include <linux/module.h> +#include <linux/mm.h> +#include <linux/mman.h> +#include <linux/init.h> +#include <linux/seq_file.h> + +#include <asm/fiq.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/pgalloc.h> +#include <asm/system.h> +#include <asm/uaccess.h> + +#define FIQ_VECTOR (vectors_base() + 0x1c) + +static unsigned long no_fiq_insn; + +#define unprotect_page_0() +#define protect_page_0() + +/* Default reacquire function + * - we always relinquish FIQ control + * - we always reacquire FIQ control + */ +static int fiq_def_op(void *ref, int relinquish) +{ + if (!relinquish) { + unprotect_page_0(); + *(unsigned long *)FIQ_VECTOR = no_fiq_insn; + protect_page_0(); + } + + return 0; +} + +static struct fiq_handler default_owner = { + .name = "default", + .fiq_op = fiq_def_op, +}; + +static struct fiq_handler *current_fiq = &default_owner; + +int show_fiq_list(struct seq_file *p, void *v) +{ + if (current_fiq != &default_owner) + seq_printf(p, "FIQ: %s\n", current_fiq->name); + + return 0; +} + +void set_fiq_handler(void *start, unsigned int length) +{ + unprotect_page_0(); + + memcpy((void *)FIQ_VECTOR, start, length); + + protect_page_0(); +} + +/* + * Taking an interrupt in FIQ mode is death, so both these functions + * disable irqs for the duration. + */ +void set_fiq_regs(struct pt_regs *regs) +{ + register unsigned long tmp, tmp2; + __asm__ volatile ( + "mov %0, pc + bic %1, %0, #0x3 + orr %1, %1, %3 + teqp %1, #0 @ select FIQ mode + mov r0, r0 + ldmia %2, {r8 - r14} + teqp %0, #0 @ return to SVC mode + mov r0, r0" + : "=&r" (tmp), "=&r" (tmp2) + : "r" (®s->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | MODE_FIQ26) + /* These registers aren't modified by the above code in a way + visible to the compiler, but we mark them as clobbers anyway + so that GCC won't put any of the input or output operands in + them. */ + : "r8", "r9", "r10", "r11", "r12", "r13", "r14"); +} + +void get_fiq_regs(struct pt_regs *regs) +{ + register unsigned long tmp, tmp2; + __asm__ volatile ( + "mov %0, pc + bic %1, %0, #0x3 + orr %1, %1, %3 + teqp %1, #0 @ select FIQ mode + mov r0, r0 + stmia %2, {r8 - r14} + teqp %0, #0 @ return to SVC mode + mov r0, r0" + : "=&r" (tmp), "=&r" (tmp2) + : "r" (®s->ARM_r8), "I" (PSR_I_BIT | PSR_F_BIT | MODE_FIQ26) + /* These registers aren't modified by the above code in a way + visible to the compiler, but we mark them as clobbers anyway + so that GCC won't put any of the input or output operands in + them. */ + : "r8", "r9", "r10", "r11", "r12", "r13", "r14"); +} + +int claim_fiq(struct fiq_handler *f) +{ + int ret = 0; + + if (current_fiq) { + ret = -EBUSY; + + if (current_fiq->fiq_op != NULL) + ret = current_fiq->fiq_op(current_fiq->dev_id, 1); + } + + if (!ret) { + f->next = current_fiq; + current_fiq = f; + } + + return ret; +} + +void release_fiq(struct fiq_handler *f) +{ + if (current_fiq != f) { + printk(KERN_ERR "%s FIQ trying to release %s FIQ\n", + f->name, current_fiq->name); +#ifdef CONFIG_DEBUG_ERRORS + __backtrace(); +#endif + return; + } + + do + current_fiq = current_fiq->next; + while (current_fiq->fiq_op(current_fiq->dev_id, 0)); +} + +void enable_fiq(int fiq) +{ + enable_irq(fiq + FIQ_START); +} + +void disable_fiq(int fiq) +{ + disable_irq(fiq + FIQ_START); +} + +EXPORT_SYMBOL(set_fiq_handler); +EXPORT_SYMBOL(set_fiq_regs); +EXPORT_SYMBOL(get_fiq_regs); +EXPORT_SYMBOL(claim_fiq); +EXPORT_SYMBOL(release_fiq); +EXPORT_SYMBOL(enable_fiq); +EXPORT_SYMBOL(disable_fiq); + +void __init init_FIQ(void) +{ + no_fiq_insn = *(unsigned long *)FIQ_VECTOR; + set_fs(get_fs()); +} diff -Nru a/arch/arm26/kernel/init_task.c b/arch/arm26/kernel/init_task.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/kernel/init_task.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,41 @@ +/* + * linux/arch/arm/kernel/init_task.c + * + * Copyright (C) 2003 Ian Molton + * + */ +#include <linux/mm.h> +#include <linux/fs.h> +#include <linux/sched.h> +#include <linux/init.h> +#include <linux/init_task.h> + +#include <asm/uaccess.h> +#include <asm/pgtable.h> + +static struct fs_struct init_fs = INIT_FS; +static struct files_struct init_files = INIT_FILES; +static struct signal_struct init_signals = INIT_SIGNALS(init_signals); +static struct sighand_struct init_sighand = INIT_SIGHAND(init_sighand); +struct mm_struct init_mm = INIT_MM(init_mm); + +/* + * Initial thread structure. + * + * We need to make sure that this is 8192-byte aligned due to the + * way process stacks are handled. This is done by making sure + * the linker maps this in the .text segment right after head.S, + * and making head.S ensure the proper alignment. + * + * The things we do for performance... + */ +union thread_union init_thread_union + __attribute__((__section__(".init.task"))) = + { INIT_THREAD_INFO(init_task) }; + +/* + * Initial task structure. + * + * All other task structs will be allocated on slabs in fork.c + */ +struct task_struct init_task = INIT_TASK(init_task); diff -Nru a/arch/arm26/kernel/irq.c b/arch/arm26/kernel/irq.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/kernel/irq.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,705 @@ +/* + * linux/arch/arm/kernel/irq.c + * + * Copyright (C) 1992 Linus Torvalds + * Modifications for ARM processor Copyright (C) 1995-2000 Russell King. + * 'Borrowed' for ARM26 and (C) 2003 Ian Molton. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This file contains the code used by various IRQ handling routines: + * asking for different IRQ's should be done through these routines + * instead of just grabbing them. Thus setups with different IRQ numbers + * shouldn't result in any weird surprises, and installing new handlers + * should be easier. + * + * IRQ's are in fact implemented a bit like signal handlers for the kernel. + * Naturally it's not a 1:1 relation, but there are similarities. + */ +#include <linux/config.h> +#include <linux/ptrace.h> +#include <linux/kernel_stat.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/ioport.h> +#include <linux/interrupt.h> +#include <linux/slab.h> +#include <linux/random.h> +#include <linux/smp.h> +#include <linux/init.h> +#include <linux/seq_file.h> +#include <linux/errno.h> + +#include <asm/irq.h> +#include <asm/system.h> +#include <asm/irqchip.h> + +/* + * Maximum IRQ count. Currently, this is arbitary. However, it should + * not be set too low to prevent false triggering. Conversely, if it + * is set too high, then you could miss a stuck IRQ. + * + * Maybe we ought to set a timer and re-enable the IRQ at a later time? + */ +#define MAX_IRQ_CNT 100000 + +static volatile unsigned long irq_err_count; +static spinlock_t irq_controller_lock = SPIN_LOCK_UNLOCKED; + +struct irqdesc irq_desc[NR_IRQS]; +void (*init_arch_irq)(void) __initdata = NULL; + +/* + * Dummy mask/unmask handler + */ +void dummy_mask_unmask_irq(unsigned int irq) +{ +} + +void do_bad_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) +{ + irq_err_count += 1; + printk(KERN_ERR "IRQ: spurious interrupt %d\n", irq); +} + +static struct irqchip bad_chip = { + .ack = dummy_mask_unmask_irq, + .mask = dummy_mask_unmask_irq, + .unmask = dummy_mask_unmask_irq, +}; + +static struct irqdesc bad_irq_desc = { + .chip = &bad_chip, + .handle = do_bad_IRQ, + .depth = 1, +}; + +/** + * disable_irq - disable an irq and wait for completion + * @irq: Interrupt to disable + * + * Disable the selected interrupt line. We do this lazily. + * + * This function may be called from IRQ context. + */ +void disable_irq(unsigned int irq) +{ + struct irqdesc *desc = irq_desc + irq; + unsigned long flags; + + spin_lock_irqsave(&irq_controller_lock, flags); + if (!desc->depth++) + desc->enabled = 0; + spin_unlock_irqrestore(&irq_controller_lock, flags); +} + +/** + * enable_irq - enable interrupt handling on an irq + * @irq: Interrupt to enable + * + * Re-enables the processing of interrupts on this IRQ line. + * Note that this may call the interrupt handler, so you may + * get unexpected results if you hold IRQs disabled. + * + * This function may be called from IRQ context. + */ +void enable_irq(unsigned int irq) +{ + struct irqdesc *desc = irq_desc + irq; + unsigned long flags; + int pending = 0; + + spin_lock_irqsave(&irq_controller_lock, flags); + if (unlikely(!desc->depth)) { + printk("enable_irq(%u) unbalanced from %p\n", irq, + __builtin_return_address(0)); + } else if (!--desc->depth) { + desc->probing = 0; + desc->enabled = 1; + desc->chip->unmask(irq); + pending = desc->pending; + desc->pending = 0; + /* + * If the interrupt was waiting to be processed, + * retrigger it. + */ + if (pending) + desc->chip->rerun(irq); + } + spin_unlock_irqrestore(&irq_controller_lock, flags); +} + +int show_interrupts(struct seq_file *p, void *v) +{ + int i; + struct irqaction * action; + + for (i = 0 ; i < NR_IRQS ; i++) { + action = irq_desc[i].action; + if (!action) + continue; + seq_printf(p, "%3d: %10u ", i, kstat_irqs(i)); + seq_printf(p, " %s", action->name); + for (action = action->next; action; action = action->next) { + seq_printf(p, ", %s", action->name); + } + seq_putc(p, '\n'); + } + + show_fiq_list(p, v); + seq_printf(p, "Err: %10lu\n", irq_err_count); + return 0; +} + +/* + * IRQ lock detection. + * + * Hopefully, this should get us out of a few locked situations. + * However, it may take a while for this to happen, since we need + * a large number if IRQs to appear in the same jiffie with the + * same instruction pointer (or within 2 instructions). + */ +static int check_irq_lock(struct irqdesc *desc, int irq, struct pt_regs *regs) +{ + unsigned long instr_ptr = instruction_pointer(regs); + + if (desc->lck_jif == jiffies && + desc->lck_pc >= instr_ptr && desc->lck_pc < instr_ptr + 8) { + desc->lck_cnt += 1; + + if (desc->lck_cnt > MAX_IRQ_CNT) { + printk(KERN_ERR "IRQ LOCK: IRQ%d is locking the system, disabled\n", irq); + return 1; + } + } else { + desc->lck_cnt = 0; + desc->lck_pc = instruction_pointer(regs); + desc->lck_jif = jiffies; + } + return 0; +} + +static void +__do_irq(unsigned int irq, struct irqaction *action, struct pt_regs *regs) +{ + unsigned int status; + + spin_unlock(&irq_controller_lock); + + if (!(action->flags & SA_INTERRUPT)) + local_irq_enable(); + + status = 0; + do { + status |= action->flags; + action->handler(irq, action->dev_id, regs); + action = action->next; + } while (action); + + if (status & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); + + spin_lock_irq(&irq_controller_lock); +} + +/* + * This is for software-decoded IRQs. The caller is expected to + * handle the ack, clear, mask and unmask issues. + */ +void +do_simple_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) +{ + struct irqaction *action; + const int cpu = smp_processor_id(); + + desc->triggered = 1; + + kstat_cpu(cpu).irqs[irq]++; + + action = desc->action; + if (action) + __do_irq(irq, desc->action, regs); +} + +/* + * Most edge-triggered IRQ implementations seem to take a broken + * approach to this. Hence the complexity. + */ +void +do_edge_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) +{ + const int cpu = smp_processor_id(); + + desc->triggered = 1; + + /* + * If we're currently running this IRQ, or its disabled, + * we shouldn't process the IRQ. Instead, turn on the + * hardware masks. + */ + if (unlikely(desc->running || !desc->enabled)) + goto running; + + /* + * Acknowledge and clear the IRQ, but don't mask it. + */ + desc->chip->ack(irq); + + /* + * Mark the IRQ currently in progress. + */ + desc->running = 1; + + kstat_cpu(cpu).irqs[irq]++; + + do { + struct irqaction *action; + + action = desc->action; + if (!action) + break; + + if (desc->pending && desc->enabled) { + desc->pending = 0; + desc->chip->unmask(irq); + } + + __do_irq(irq, action, regs); + } while (desc->pending); + + desc->running = 0; + + /* + * If we were disabled or freed, shut down the handler. + */ + if (likely(desc->action && !check_irq_lock(desc, irq, regs))) + return; + + running: + /* + * We got another IRQ while this one was masked or + * currently running. Delay it. + */ + desc->pending = 1; + desc->chip->mask(irq); + desc->chip->ack(irq); +} + +/* + * Level-based IRQ handler. Nice and simple. + */ +void +do_level_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs) +{ + struct irqaction *action; + const int cpu = smp_processor_id(); + + desc->triggered = 1; + + /* + * Acknowledge, clear _AND_ disable the interrupt. + */ + desc->chip->ack(irq); + + if (likely(desc->enabled)) { + kstat_cpu(cpu).irqs[irq]++; + + /* + * Return with this interrupt masked if no action + */ + action = desc->action; + if (action) { + __do_irq(irq, desc->action, regs); + + if (likely(desc->enabled && + !check_irq_lock(desc, irq, regs))) + desc->chip->unmask(irq); + } + } +} + +/* + * do_IRQ handles all hardware IRQ's. Decoded IRQs should not + * come via this function. Instead, they should provide their + * own 'handler' + */ +asmlinkage void asm_do_IRQ(int irq, struct pt_regs *regs) +{ + struct irqdesc *desc = irq_desc + irq; + + /* + * Some hardware gives randomly wrong interrupts. Rather + * than crashing, do something sensible. + */ + if (irq >= NR_IRQS) + desc = &bad_irq_desc; + + irq_enter(); + spin_lock(&irq_controller_lock); + desc->handle(irq, desc, regs); + spin_unlock(&irq_controller_lock); + irq_exit(); +} + +void __set_irq_handler(unsigned int irq, irq_handler_t handle, int is_chained) +{ + struct irqdesc *desc; + unsigned long flags; + + if (irq >= NR_IRQS) { + printk(KERN_ERR "Trying to install handler for IRQ%d\n", irq); + return; + } + + if (handle == NULL) + handle = do_bad_IRQ; + + desc = irq_desc + irq; + + if (is_chained && desc->chip == &bad_chip) + printk(KERN_WARNING "Trying to install chained handler for IRQ%d\n", irq); + + spin_lock_irqsave(&irq_controller_lock, flags); + if (handle == do_bad_IRQ) { + desc->chip->mask(irq); + desc->chip->ack(irq); + desc->depth = 1; + desc->enabled = 0; + } + desc->handle = handle; + if (handle != do_bad_IRQ && is_chained) { + desc->valid = 0; + desc->probe_ok = 0; + desc->depth = 0; + desc->chip->unmask(irq); + } + spin_unlock_irqrestore(&irq_controller_lock, flags); +} + +void set_irq_chip(unsigned int irq, struct irqchip *chip) +{ + struct irqdesc *desc; + unsigned long flags; + + if (irq >= NR_IRQS) { + printk(KERN_ERR "Trying to install chip for IRQ%d\n", irq); + return; + } + + if (chip == NULL) + chip = &bad_chip; + + desc = irq_desc + irq; + spin_lock_irqsave(&irq_controller_lock, flags); + desc->chip = chip; + spin_unlock_irqrestore(&irq_controller_lock, flags); +} + +int set_irq_type(unsigned int irq, unsigned int type) +{ + struct irqdesc *desc; + unsigned long flags; + int ret = -ENXIO; + + if (irq >= NR_IRQS) { + printk(KERN_ERR "Trying to set irq type for IRQ%d\n", irq); + return -ENODEV; + } + + desc = irq_desc + irq; + if (desc->chip->type) { + spin_lock_irqsave(&irq_controller_lock, flags); + ret = desc->chip->type(irq, type); + spin_unlock_irqrestore(&irq_controller_lock, flags); + } + + return ret; +} + +void set_irq_flags(unsigned int irq, unsigned int iflags) +{ + struct irqdesc *desc; + unsigned long flags; + + if (irq >= NR_IRQS) { + printk(KERN_ERR "Trying to set irq flags for IRQ%d\n", irq); + return; + } + + desc = irq_desc + irq; + spin_lock_irqsave(&irq_controller_lock, flags); + desc->valid = (iflags & IRQF_VALID) != 0; + desc->probe_ok = (iflags & IRQF_PROBE) != 0; + desc->noautoenable = (iflags & IRQF_NOAUTOEN) != 0; + spin_unlock_irqrestore(&irq_controller_lock, flags); +} + +int setup_irq(unsigned int irq, struct irqaction *new) +{ + int shared = 0; + struct irqaction *old, **p; + unsigned long flags; + struct irqdesc *desc; + + /* + * Some drivers like serial.c use request_irq() heavily, + * so we have to be careful not to interfere with a + * running system. + */ + if (new->flags & SA_SAMPLE_RANDOM) { + /* + * This function might sleep, we want to call it first, + * outside of the atomic block. + * Yes, this might clear the entropy pool if the wrong + * driver is attempted to be loaded, without actually + * installing a new handler, but is this really a problem, + * only the sysadmin is able to do this. + */ + rand_initialize_irq(irq); + } + + /* + * The following block of code has to be executed atomically + */ + desc = irq_desc + irq; + spin_lock_irqsave(&irq_controller_lock, flags); + p = &desc->action; + if ((old = *p) != NULL) { + /* Can't share interrupts unless both agree to */ + if (!(old->flags & new->flags & SA_SHIRQ)) { + spin_unlock_irqrestore(&irq_controller_lock, flags); + return -EBUSY; + } + + /* add new interrupt at end of irq queue */ + do { + p = &old->next; + old = *p; + } while (old); + shared = 1; + } + + *p = new; + + if (!shared) { + desc->probing = 0; + desc->running = 0; + desc->pending = 0; + desc->depth = 1; + if (!desc->noautoenable) { + desc->depth = 0; + desc->enabled = 1; + desc->chip->unmask(irq); + } + } + + spin_unlock_irqrestore(&irq_controller_lock, flags); + return 0; +} + +/** + * request_irq - allocate an interrupt line + * @irq: Interrupt line to allocate + * @handler: Function to be called when the IRQ occurs + * @irqflags: Interrupt type flags + * @devname: An ascii name for the claiming device + * @dev_id: A cookie passed back to the handler function + * + * This call allocates interrupt resources and enables the + * interrupt line and IRQ handling. From the point this + * call is made your handler function may be invoked. Since + * your handler function must clear any interrupt the board + * raises, you must take care both to initialise your hardware + * and to set up the interrupt handler in the right order. + * + * Dev_id must be globally unique. Normally the address of the + * device data structure is used as the cookie. Since the handler + * receives this value it makes sense to use it. + * + * If your interrupt is shared you must pass a non NULL dev_id + * as this is required when freeing the interrupt. + * + * Flags: + * + * SA_SHIRQ Interrupt is shared + * + * SA_INTERRUPT Disable local interrupts while processing + * + * SA_SAMPLE_RANDOM The interrupt can be used for entropy + * + */ + +//FIXME - handler used to return void - whats the significance of the change? +int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *), + unsigned long irq_flags, const char * devname, void *dev_id) +{ + unsigned long retval; + struct irqaction *action; + + if (irq >= NR_IRQS || !irq_desc[irq].valid || !handler || + (irq_flags & SA_SHIRQ && !dev_id)) + return -EINVAL; + + action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL); + if (!action) + return -ENOMEM; + + action->handler = handler; + action->flags = irq_flags; + action->mask = 0; + action->name = devname; + action->next = NULL; + action->dev_id = dev_id; + + retval = setup_irq(irq, action); + + if (retval) + kfree(action); + return retval; +} + +/** + * free_irq - free an interrupt + * @irq: Interrupt line to free + * @dev_id: Device identity to free + * + * Remove an interrupt handler. The handler is removed and if the + * interrupt line is no longer in use by any driver it is disabled. + * On a shared IRQ the caller must ensure the interrupt is disabled + * on the card it drives before calling this function. + * + * This function may be called from interrupt context. + */ +void free_irq(unsigned int irq, void *dev_id) +{ + struct irqaction * action, **p; + unsigned long flags; + + if (irq >= NR_IRQS || !irq_desc[irq].valid) { + printk(KERN_ERR "Trying to free IRQ%d\n",irq); +#ifdef CONFIG_DEBUG_ERRORS + __backtrace(); +#endif + return; + } + + spin_lock_irqsave(&irq_controller_lock, flags); + for (p = &irq_desc[irq].action; (action = *p) != NULL; p = &action->next) { + if (action->dev_id != dev_id) + continue; + + /* Found it - now free it */ + *p = action->next; + kfree(action); + goto out; + } + printk(KERN_ERR "Trying to free free IRQ%d\n",irq); +#ifdef CONFIG_DEBUG_ERRORS + __backtrace(); +#endif +out: + spin_unlock_irqrestore(&irq_controller_lock, flags); +} + +/* Start the interrupt probing. Unlike other architectures, + * we don't return a mask of interrupts from probe_irq_on, + * but return the number of interrupts enabled for the probe. + * The interrupts which have been enabled for probing is + * instead recorded in the irq_desc structure. + */ +unsigned long probe_irq_on(void) +{ + unsigned int i, irqs = 0; + unsigned long delay; + + /* + * first snaffle up any unassigned but + * probe-able interrupts + */ + spin_lock_irq(&irq_controller_lock); + for (i = 0; i < NR_IRQS; i++) { + if (!irq_desc[i].probe_ok || irq_desc[i].action) + continue; + + irq_desc[i].probing = 1; + irq_desc[i].triggered = 0; + if (irq_desc[i].chip->type) + irq_desc[i].chip->type(i, IRQT_PROBE); + irq_desc[i].chip->unmask(i); + irqs += 1; + } + spin_unlock_irq(&irq_controller_lock); + + /* + * wait for spurious interrupts to mask themselves out again + */ + for (delay = jiffies + HZ/10; time_before(jiffies, delay); ) + /* min 100ms delay */; + + /* + * now filter out any obviously spurious interrupts + */ + spin_lock_irq(&irq_controller_lock); + for (i = 0; i < NR_IRQS; i++) { + if (irq_desc[i].probing && irq_desc[i].triggered) { + irq_desc[i].probing = 0; + irqs -= 1; + } + } + spin_unlock_irq(&irq_controller_lock); + + return irqs; +} + +/* + * Possible return values: + * >= 0 - interrupt number + * -1 - no interrupt/many interrupts + */ +int probe_irq_off(unsigned long irqs) +{ + unsigned int i; + int irq_found = NO_IRQ; + + /* + * look at the interrupts, and find exactly one + * that we were probing has been triggered + */ + spin_lock_irq(&irq_controller_lock); + for (i = 0; i < NR_IRQS; i++) { + if (irq_desc[i].probing && + irq_desc[i].triggered) { + if (irq_found != NO_IRQ) { + irq_found = NO_IRQ; + goto out; + } + irq_found = i; + } + } + + if (irq_found == -1) + irq_found = NO_IRQ; +out: + spin_unlock_irq(&irq_controller_lock); + + return irq_found; +} + +void __init init_irq_proc(void) +{ +} + +void __init init_IRQ(void) +{ + struct irqdesc *desc; + extern void init_dma(void); + int irq; + + for (irq = 0, desc = irq_desc; irq < NR_IRQS; irq++, desc++) + *desc = bad_irq_desc; + + init_arch_irq(); + init_dma(); +} diff -Nru a/arch/arm26/kernel/process.c b/arch/arm26/kernel/process.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/kernel/process.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,414 @@ +/* + * linux/arch/arm26/kernel/process.c + * + * Copyright (C) 2003 Ian Molton - adapted for ARM26 + * Copyright (C) 1996-2000 Russell King - Converted to ARM. + * Origional Copyright (C) 1995 Linus Torvalds + * + * This program is free software; you can 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 <stdarg.h> + +#include <linux/config.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/mm.h> +#include <linux/stddef.h> +#include <linux/unistd.h> +#include <linux/ptrace.h> +#include <linux/slab.h> +#include <linux/user.h> +#include <linux/a.out.h> +#include <linux/delay.h> +#include <linux/reboot.h> +#include <linux/interrupt.h> +#include <linux/init.h> + +#include <asm/system.h> +#include <asm/io.h> +#include <asm/leds.h> +#include <asm/processor.h> +#include <asm/uaccess.h> + +extern const char *processor_modes[]; +extern void setup_mm_for_reboot(char mode); + +static volatile int hlt_counter; + +void disable_hlt(void) +{ + hlt_counter++; +} + +void enable_hlt(void) +{ + hlt_counter--; +} + +static int __init nohlt_setup(char *__unused) +{ + hlt_counter = 1; + return 1; +} + +static int __init hlt_setup(char *__unused) +{ + hlt_counter = 0; + return 1; +} + +__setup("nohlt", nohlt_setup); +__setup("hlt", hlt_setup); + +/* + * The following aren't currently used. + */ +void (*pm_idle)(void); +void (*pm_power_off)(void); + +/* + * This is our default idle handler. We need to disable + * interrupts here to ensure we don't miss a wakeup call. + */ +void default_idle(void) +{ + local_irq_disable(); + if (!need_resched() && !hlt_counter) + local_irq_enable(); +} + +/* + * The idle thread. We try to conserve power, while trying to keep + * overall latency low. The architecture specific idle is passed + * a value to indicate the level of "idleness" of the system. + */ +void cpu_idle(void) +{ + /* endless idle loop with no priority at all */ + preempt_disable(); + while (1) { + void (*idle)(void) = pm_idle; + if (!idle) + idle = default_idle; + leds_event(led_idle_start); + while (!need_resched()) + idle(); + leds_event(led_idle_end); + schedule(); + } +} + +static char reboot_mode = 'h'; + +int __init reboot_setup(char *str) +{ + reboot_mode = str[0]; + return 1; +} + +__setup("reboot=", reboot_setup); + +void machine_halt(void) +{ + leds_event(led_halted); +} + +void machine_power_off(void) +{ + leds_event(led_halted); + if (pm_power_off) + pm_power_off(); +} + +void machine_restart(char * __unused) +{ + /* + * Clean and disable cache, and turn off interrupts + */ + cpu_proc_fin(); + + /* + * Tell the mm system that we are going to reboot - + * we may need it to insert some 1:1 mappings so that + * soft boot works. + */ + setup_mm_for_reboot(reboot_mode); + + /* + * copy branch instruction to reset location and call it + */ + + *(unsigned long *)0 = *(unsigned long *)0x03800000; + ((void(*)(void))0)(); + + /* + * Whoops - the architecture was unable to reboot. + * Tell the user! Should never happen... + */ + mdelay(1000); + printk("Reboot failed -- System halted\n"); + while (1); +} + +void show_regs(struct pt_regs * regs) +{ + unsigned long flags; + + flags = condition_codes(regs); + + printk("pc : [<%08lx>] lr : [<%08lx>] %s\n" + "sp : %08lx ip : %08lx fp : %08lx\n", + instruction_pointer(regs), + regs->ARM_lr, print_tainted(), regs->ARM_sp, + regs->ARM_ip, regs->ARM_fp); + printk("r10: %08lx r9 : %08lx r8 : %08lx\n", + regs->ARM_r10, regs->ARM_r9, + regs->ARM_r8); + printk("r7 : %08lx r6 : %08lx r5 : %08lx r4 : %08lx\n", + regs->ARM_r7, regs->ARM_r6, + regs->ARM_r5, regs->ARM_r4); + printk("r3 : %08lx r2 : %08lx r1 : %08lx r0 : %08lx\n", + regs->ARM_r3, regs->ARM_r2, + regs->ARM_r1, regs->ARM_r0); + printk("Flags: %c%c%c%c", + flags & PSR_N_BIT ? 'N' : 'n', + flags & PSR_Z_BIT ? 'Z' : 'z', + flags & PSR_C_BIT ? 'C' : 'c', + flags & PSR_V_BIT ? 'V' : 'v'); + printk(" IRQs o%s FIQs o%s Mode %s Segment %s\n", + interrupts_enabled(regs) ? "n" : "ff", + fast_interrupts_enabled(regs) ? "n" : "ff", + processor_modes[processor_mode(regs)], + get_fs() == get_ds() ? "kernel" : "user"); +} + +void show_fpregs(struct user_fp *regs) +{ + int i; + + for (i = 0; i < 8; i++) { + unsigned long *p; + char type; + + p = (unsigned long *)(regs->fpregs + i); + + switch (regs->ftype[i]) { + case 1: type = 'f'; break; + case 2: type = 'd'; break; + case 3: type = 'e'; break; + default: type = '?'; break; + } + if (regs->init_flag) + type = '?'; + + printk(" f%d(%c): %08lx %08lx %08lx%c", + i, type, p[0], p[1], p[2], i & 1 ? '\n' : ' '); + } + + + printk("FPSR: %08lx FPCR: %08lx\n", + (unsigned long)regs->fpsr, + (unsigned long)regs->fpcr); +} + +/* + * Task structure and kernel stack allocation. + */ +static unsigned long *thread_info_head; +static unsigned int nr_thread_info; + +extern unsigned long get_page_8k(int priority); +extern void free_page_8k(unsigned long page); + +// FIXME - is this valid? +#define EXTRA_TASK_STRUCT 0 +#define ll_alloc_task_struct() ((struct thread_info *)get_page_8k(GFP_KERNEL)) +#define ll_free_task_struct(p) free_page_8k((unsigned long)(p)) + +struct thread_info *alloc_thread_info(void) +{ + struct thread_info *thread = NULL; + + if (EXTRA_TASK_STRUCT) { + unsigned long *p = thread_info_head; + + if (p) { + thread_info_head = (unsigned long *)p[0]; + nr_thread_info -= 1; + } + thread = (struct thread_info *)p; + } + + if (!thread) + thread = ll_alloc_task_struct(); + +#ifdef CONFIG_SYSRQ + /* + * The stack must be cleared if you want SYSRQ-T to + * give sensible stack usage information + */ + if (thread) { + char *p = (char *)thread; + memzero(p+KERNEL_STACK_SIZE, KERNEL_STACK_SIZE); + } +#endif + return thread; +} + +void free_thread_info(struct thread_info *thread) +{ + if (EXTRA_TASK_STRUCT && nr_thread_info < EXTRA_TASK_STRUCT) { + unsigned long *p = (unsigned long *)thread; + p[0] = (unsigned long)thread_info_head; + thread_info_head = p; + nr_thread_info += 1; + } else + ll_free_task_struct(thread); +} + +/* + * Free current thread data structures etc.. + */ +void exit_thread(void) +{ +} + +void flush_thread(void) +{ + struct thread_info *thread = current_thread_info(); + struct task_struct *tsk = current; + + memset(&tsk->thread.debug, 0, sizeof(struct debug_info)); + memset(&thread->fpstate, 0, sizeof(union fp_state)); + + current->used_math = 0; +} + +void release_thread(struct task_struct *dead_task) +{ +} + +asmlinkage void ret_from_fork(void) __asm__("ret_from_fork"); + +int +copy_thread(int nr, unsigned long clone_flags, unsigned long esp, + unsigned long unused, struct task_struct *p, struct pt_regs *regs) +{ + struct thread_info *thread = p->thread_info; + struct pt_regs *childregs; + + childregs = __get_user_regs(thread); + *childregs = *regs; + childregs->ARM_r0 = 0; + childregs->ARM_sp = esp; + + memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save)); + thread->cpu_context.sp = (unsigned long)childregs; + thread->cpu_context.pc = (unsigned long)ret_from_fork | MODE_SVC26 | PSR_I_BIT; + + return 0; +} + +/* + * fill in the fpe structure for a core dump... + */ +int dump_fpu (struct pt_regs *regs, struct user_fp *fp) +{ + struct thread_info *thread = current_thread_info(); + int used_math = current->used_math; + + if (used_math) + memcpy(fp, &thread->fpstate.soft, sizeof (*fp)); + + return used_math; +} + +/* + * fill in the user structure for a core dump.. + */ +void dump_thread(struct pt_regs * regs, struct user * dump) +{ + struct task_struct *tsk = current; + + dump->magic = CMAGIC; + dump->start_code = tsk->mm->start_code; + dump->start_stack = regs->ARM_sp & ~(PAGE_SIZE - 1); + + dump->u_tsize = (tsk->mm->end_code - tsk->mm->start_code) >> PAGE_SHIFT; + dump->u_dsize = (tsk->mm->brk - tsk->mm->start_data + PAGE_SIZE - 1) >> PAGE_SHIFT; + dump->u_ssize = 0; + + dump->u_debugreg[0] = tsk->thread.debug.bp[0].address; + dump->u_debugreg[1] = tsk->thread.debug.bp[1].address; + dump->u_debugreg[2] = tsk->thread.debug.bp[0].insn; + dump->u_debugreg[3] = tsk->thread.debug.bp[1].insn; + dump->u_debugreg[4] = tsk->thread.debug.nsaved; + + if (dump->start_stack < 0x04000000) + dump->u_ssize = (0x04000000 - dump->start_stack) >> PAGE_SHIFT; + + dump->regs = *regs; + dump->u_fpvalid = dump_fpu (regs, &dump->u_fp); +} + +/* + * This is the mechanism for creating a new kernel thread. + * + * NOTE! Only a kernel-only process(ie the swapper or direct descendants + * who haven't done an "execve()") should use this: it will work within + * a system call from a "real" process, but the process memory space will + * not be free'd until both the parent and the child have exited. + * FIXME - taken from arm32 + */ +pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) +{ + register unsigned int r0 asm("r0") = flags | CLONE_VM | CLONE_UNTRACED; + register unsigned int r1 asm("r1") = 0; + register pid_t __ret asm("r0"); + + __asm__ __volatile__( + __syscall(clone)" @ kernel_thread sys_clone \n\ + movs %0, r0 @ if we are the child \n\ + bne 1f \n\ + mov fp, #0 @ ensure that fp is zero \n\ + mov r0, %4 \n\ + mov lr, pc \n\ + mov pc, %3 \n\ + b sys_exit \n\ +1: " + : "=r" (__ret) + : "0" (r0), "r" (r1), "r" (fn), "r" (arg) + : "lr"); + return __ret; +} + +/* + * These bracket the sleeping functions.. + */ +extern void scheduling_functions_start_here(void); +extern void scheduling_functions_end_here(void); +#define first_sched ((unsigned long) scheduling_functions_start_here) +#define last_sched ((unsigned long) scheduling_functions_end_here) + +unsigned long get_wchan(struct task_struct *p) +{ + unsigned long fp, lr; + unsigned long stack_page; + int count = 0; + if (!p || p == current || p->state == TASK_RUNNING) + return 0; + + stack_page = 4096 + (unsigned long)p; + fp = thread_saved_fp(p); + do { + if (fp < stack_page || fp > 4092+stack_page) + return 0; + lr = pc_pointer (((unsigned long *)fp)[-1]); + if (lr < first_sched || lr > last_sched) + return lr; + fp = *(unsigned long *) (fp - 12); + } while (count ++ < 16); + return 0; +} diff -Nru a/arch/arm26/kernel/ptrace.c b/arch/arm26/kernel/ptrace.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/kernel/ptrace.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,747 @@ +/* + * linux/arch/arm26/kernel/ptrace.c + * + * By Ross Biro 1/23/92 + * edited by Linus Torvalds + * ARM modifications Copyright (C) 2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> +#include <linux/ptrace.h> +#include <linux/user.h> +#include <linux/security.h> + +#include <asm/uaccess.h> +#include <asm/pgtable.h> +#include <asm/system.h> +//#include <asm/processor.h> + +#include "ptrace.h" + +#define REG_PC 15 +#define REG_PSR 15 +/* + * does not yet catch signals sent when the child dies. + * in exit.c or in signal.c. + */ + +/* + * Breakpoint SWI instruction: SWI &9F0001 + */ +#define BREAKINST_ARM 0xef9f0001 + +/* + * Get the address of the live pt_regs for the specified task. + * These are saved onto the top kernel stack when the process + * is not running. + * + * Note: if a user thread is execve'd from kernel space, the + * kernel stack will not be empty on entry to the kernel, so + * ptracing these tasks will fail. + */ +static inline struct pt_regs * +get_user_regs(struct task_struct *task) +{ + return __get_user_regs(task->thread_info); +} + +/* + * this routine will get a word off of the processes privileged stack. + * the offset is how far from the base addr as stored in the THREAD. + * this routine assumes that all the privileged stacks are in our + * data space. + */ +static inline long get_user_reg(struct task_struct *task, int offset) +{ + return get_user_regs(task)->uregs[offset]; +} + +/* + * this routine will put a word on the processes privileged stack. + * the offset is how far from the base addr as stored in the THREAD. + * this routine assumes that all the privileged stacks are in our + * data space. + */ +static inline int +put_user_reg(struct task_struct *task, int offset, long data) +{ + struct pt_regs newregs, *regs = get_user_regs(task); + int ret = -EINVAL; + + newregs = *regs; + newregs.uregs[offset] = data; + + if (valid_user_regs(&newregs)) { + regs->uregs[offset] = data; + ret = 0; + } + + return ret; +} + +static inline int +read_u32(struct task_struct *task, unsigned long addr, u32 *res) +{ + int ret; + + ret = access_process_vm(task, addr, res, sizeof(*res), 0); + + return ret == sizeof(*res) ? 0 : -EIO; +} + +static inline int +read_instr(struct task_struct *task, unsigned long addr, u32 *res) +{ + int ret; + u32 val; + ret = access_process_vm(task, addr & ~3, &val, sizeof(val), 0); + ret = ret == sizeof(val) ? 0 : -EIO; + *res = val; + return ret; +} + +/* + * Get value of register `rn' (in the instruction) + */ +static unsigned long +ptrace_getrn(struct task_struct *child, unsigned long insn) +{ + unsigned int reg = (insn >> 16) & 15; + unsigned long val; + + val = get_user_reg(child, reg); + if (reg == 15) + val = pc_pointer(val + 8); //FIXME - correct for arm26? + + return val; +} + +/* + * Get value of operand 2 (in an ALU instruction) + */ +static unsigned long +ptrace_getaluop2(struct task_struct *child, unsigned long insn) +{ + unsigned long val; + int shift; + int type; + + if (insn & 1 << 25) { + val = insn & 255; + shift = (insn >> 8) & 15; + type = 3; + } else { + val = get_user_reg (child, insn & 15); + + if (insn & (1 << 4)) + shift = (int)get_user_reg (child, (insn >> 8) & 15); + else + shift = (insn >> 7) & 31; + + type = (insn >> 5) & 3; + } + + switch (type) { + case 0: val <<= shift; break; + case 1: val >>= shift; break; + case 2: + val = (((signed long)val) >> shift); + break; + case 3: + val = (val >> shift) | (val << (32 - shift)); + break; + } + return val; +} + +/* + * Get value of operand 2 (in a LDR instruction) + */ +static unsigned long +ptrace_getldrop2(struct task_struct *child, unsigned long insn) +{ + unsigned long val; + int shift; + int type; + + val = get_user_reg(child, insn & 15); + shift = (insn >> 7) & 31; + type = (insn >> 5) & 3; + + switch (type) { + case 0: val <<= shift; break; + case 1: val >>= shift; break; + case 2: + val = (((signed long)val) >> shift); + break; + case 3: + val = (val >> shift) | (val << (32 - shift)); + break; + } + return val; +} + +#define OP_MASK 0x01e00000 +#define OP_AND 0x00000000 +#define OP_EOR 0x00200000 +#define OP_SUB 0x00400000 +#define OP_RSB 0x00600000 +#define OP_ADD 0x00800000 +#define OP_ADC 0x00a00000 +#define OP_SBC 0x00c00000 +#define OP_RSC 0x00e00000 +#define OP_ORR 0x01800000 +#define OP_MOV 0x01a00000 +#define OP_BIC 0x01c00000 +#define OP_MVN 0x01e00000 + +static unsigned long +get_branch_address(struct task_struct *child, unsigned long pc, unsigned long insn) +{ + u32 alt = 0; + + switch (insn & 0x0e000000) { + case 0x00000000: + case 0x02000000: { + /* + * data processing + */ + long aluop1, aluop2, ccbit; + + if ((insn & 0xf000) != 0xf000) + break; + + aluop1 = ptrace_getrn(child, insn); + aluop2 = ptrace_getaluop2(child, insn); + ccbit = get_user_reg(child, REG_PSR) & PSR_C_BIT ? 1 : 0; + + switch (insn & OP_MASK) { + case OP_AND: alt = aluop1 & aluop2; break; + case OP_EOR: alt = aluop1 ^ aluop2; break; + case OP_SUB: alt = aluop1 - aluop2; break; + case OP_RSB: alt = aluop2 - aluop1; break; + case OP_ADD: alt = aluop1 + aluop2; break; + case OP_ADC: alt = aluop1 + aluop2 + ccbit; break; + case OP_SBC: alt = aluop1 - aluop2 + ccbit; break; + case OP_RSC: alt = aluop2 - aluop1 + ccbit; break; + case OP_ORR: alt = aluop1 | aluop2; break; + case OP_MOV: alt = aluop2; break; + case OP_BIC: alt = aluop1 & ~aluop2; break; + case OP_MVN: alt = ~aluop2; break; + } + break; + } + + case 0x04000000: + case 0x06000000: + /* + * ldr + */ + if ((insn & 0x0010f000) == 0x0010f000) { + unsigned long base; + + base = ptrace_getrn(child, insn); + if (insn & 1 << 24) { + long aluop2; + + if (insn & 0x02000000) + aluop2 = ptrace_getldrop2(child, insn); + else + aluop2 = insn & 0xfff; + + if (insn & 1 << 23) + base += aluop2; + else + base -= aluop2; + } + if (read_u32(child, base, &alt) == 0) + alt = pc_pointer(alt); + } + break; + + case 0x08000000: + /* + * ldm + */ + if ((insn & 0x00108000) == 0x00108000) { + unsigned long base; + unsigned int nr_regs; + + if (insn & (1 << 23)) { + nr_regs = hweight16(insn & 65535) << 2; + + if (!(insn & (1 << 24))) + nr_regs -= 4; + } else { + if (insn & (1 << 24)) + nr_regs = -4; + else + nr_regs = 0; + } + + base = ptrace_getrn(child, insn); + + if (read_u32(child, base + nr_regs, &alt) == 0) + alt = pc_pointer(alt); + break; + } + break; + + case 0x0a000000: { + /* + * bl or b + */ + signed long displ; + /* It's a branch/branch link: instead of trying to + * figure out whether the branch will be taken or not, + * we'll put a breakpoint at both locations. This is + * simpler, more reliable, and probably not a whole lot + * slower than the alternative approach of emulating the + * branch. + */ + displ = (insn & 0x00ffffff) << 8; + displ = (displ >> 6) + 8; + if (displ != 0 && displ != 4) + alt = pc + displ; + } + break; + } + + return alt; +} + +static int +swap_insn(struct task_struct *task, unsigned long addr, + void *old_insn, void *new_insn, int size) +{ + int ret; + + ret = access_process_vm(task, addr, old_insn, size, 0); + if (ret == size) + ret = access_process_vm(task, addr, new_insn, size, 1); + return ret; +} + +static void +add_breakpoint(struct task_struct *task, struct debug_info *dbg, unsigned long addr) +{ + int nr = dbg->nsaved; + + if (nr < 2) { + u32 new_insn = BREAKINST_ARM; + int res; + + res = swap_insn(task, addr, &dbg->bp[nr].insn, &new_insn, 4); + + if (res == 4) { + dbg->bp[nr].address = addr; + dbg->nsaved += 1; + } + } else + printk(KERN_ERR "ptrace: too many breakpoints\n"); +} + +/* + * Clear one breakpoint in the user program. We copy what the hardware + * does and use bit 0 of the address to indicate whether this is a Thumb + * breakpoint or an ARM breakpoint. + */ +static void clear_breakpoint(struct task_struct *task, struct debug_entry *bp) +{ + unsigned long addr = bp->address; + u32 old_insn; + int ret; + + ret = swap_insn(task, addr & ~3, &old_insn, + &bp->insn, 4); + + if (ret != 4 || old_insn != BREAKINST_ARM) + printk(KERN_ERR "%s:%d: corrupted ARM breakpoint at " + "0x%08lx (0x%08x)\n", task->comm, task->pid, + addr, old_insn); +} + +void ptrace_set_bpt(struct task_struct *child) +{ + struct pt_regs *regs; + unsigned long pc; + u32 insn; + int res; + + regs = get_user_regs(child); + pc = instruction_pointer(regs); + + res = read_instr(child, pc, &insn); + if (!res) { + struct debug_info *dbg = &child->thread.debug; + unsigned long alt; + + dbg->nsaved = 0; + + alt = get_branch_address(child, pc, insn); + if (alt) + add_breakpoint(child, dbg, alt); + + /* + * Note that we ignore the result of setting the above + * breakpoint since it may fail. When it does, this is + * not so much an error, but a forewarning that we may + * be receiving a prefetch abort shortly. + * + * If we don't set this breakpoint here, then we can + * lose control of the thread during single stepping. + */ + if (!alt || predicate(insn) != PREDICATE_ALWAYS) + add_breakpoint(child, dbg, pc + 4); + } +} + +/* + * Ensure no single-step breakpoint is pending. Returns non-zero + * value if child was being single-stepped. + */ +void ptrace_cancel_bpt(struct task_struct *child) +{ + int i, nsaved = child->thread.debug.nsaved; + + child->thread.debug.nsaved = 0; + + if (nsaved > 2) { + printk("ptrace_cancel_bpt: bogus nsaved: %d!\n", nsaved); + nsaved = 2; + } + + for (i = 0; i < nsaved; i++) + clear_breakpoint(child, &child->thread.debug.bp[i]); +} + +/* + * Called by kernel/ptrace.c when detaching.. + * + * Make sure the single step bit is not set. + */ +void ptrace_disable(struct task_struct *child) +{ + child->ptrace &= ~PT_SINGLESTEP; + ptrace_cancel_bpt(child); +} + +/* + * Handle hitting a breakpoint. + */ +void ptrace_break(struct task_struct *tsk, struct pt_regs *regs) +{ + siginfo_t info; + + /* + * The PC is always left pointing at the next instruction. Fix this. + */ + regs->ARM_pc -= 4; + + if (tsk->thread.debug.nsaved == 0) + printk(KERN_ERR "ptrace: bogus breakpoint trap\n"); + + ptrace_cancel_bpt(tsk); + + info.si_signo = SIGTRAP; + info.si_errno = 0; + info.si_code = TRAP_BRKPT; + info.si_addr = (void *)instruction_pointer(regs) - 4; + + force_sig_info(SIGTRAP, &info, tsk); +} + +/* + * Read the word at offset "off" into the "struct user". We + * actually access the pt_regs stored on the kernel stack. + */ +static int ptrace_read_user(struct task_struct *tsk, unsigned long off, + unsigned long *ret) +{ + unsigned long tmp; + + if (off & 3 || off >= sizeof(struct user)) + return -EIO; + + tmp = 0; + if (off < sizeof(struct pt_regs)) + tmp = get_user_reg(tsk, off >> 2); + + return put_user(tmp, ret); +} + +/* + * Write the word at offset "off" into "struct user". We + * actually access the pt_regs stored on the kernel stack. + */ +static int ptrace_write_user(struct task_struct *tsk, unsigned long off, + unsigned long val) +{ + if (off & 3 || off >= sizeof(struct user)) + return -EIO; + + if (off >= sizeof(struct pt_regs)) + return 0; + + return put_user_reg(tsk, off >> 2, val); +} + +/* + * Get all user integer registers. + */ +static int ptrace_getregs(struct task_struct *tsk, void *uregs) +{ + struct pt_regs *regs = get_user_regs(tsk); + + return copy_to_user(uregs, regs, sizeof(struct pt_regs)) ? -EFAULT : 0; +} + +/* + * Set all user integer registers. + */ +static int ptrace_setregs(struct task_struct *tsk, void *uregs) +{ + struct pt_regs newregs; + int ret; + + ret = -EFAULT; + if (copy_from_user(&newregs, uregs, sizeof(struct pt_regs)) == 0) { + struct pt_regs *regs = get_user_regs(tsk); + + ret = -EINVAL; + if (valid_user_regs(&newregs)) { + *regs = newregs; + ret = 0; + } + } + + return ret; +} + +/* + * Get the child FPU state. + */ +static int ptrace_getfpregs(struct task_struct *tsk, void *ufp) +{ + return copy_to_user(ufp, &tsk->thread_info->fpstate, + sizeof(struct user_fp)) ? -EFAULT : 0; +} + +/* + * Set the child FPU state. + */ +static int ptrace_setfpregs(struct task_struct *tsk, void *ufp) +{ + tsk->used_math = 1; + return copy_from_user(&tsk->thread_info->fpstate, ufp, + sizeof(struct user_fp)) ? -EFAULT : 0; +} + +static int do_ptrace(int request, struct task_struct *child, long addr, long data) +{ + unsigned long tmp; + int ret; + + switch (request) { + /* + * read word at location "addr" in the child process. + */ + case PTRACE_PEEKTEXT: + case PTRACE_PEEKDATA: + ret = access_process_vm(child, addr, &tmp, + sizeof(unsigned long), 0); + if (ret == sizeof(unsigned long)) + ret = put_user(tmp, (unsigned long *) data); + else + ret = -EIO; + break; + + case PTRACE_PEEKUSR: + ret = ptrace_read_user(child, addr, (unsigned long *)data); + break; + + /* + * write the word at location addr. + */ + case PTRACE_POKETEXT: + case PTRACE_POKEDATA: + ret = access_process_vm(child, addr, &data, + sizeof(unsigned long), 1); + if (ret == sizeof(unsigned long)) + ret = 0; + else + ret = -EIO; + break; + + case PTRACE_POKEUSR: + ret = ptrace_write_user(child, addr, data); + break; + + /* + * continue/restart and stop at next (return from) syscall + */ + case PTRACE_SYSCALL: + case PTRACE_CONT: + ret = -EIO; + if ((unsigned long) data > _NSIG) + break; + if (request == PTRACE_SYSCALL) + set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + else + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + child->exit_code = data; + /* make sure single-step breakpoint is gone. */ + child->ptrace &= ~PT_SINGLESTEP; + ptrace_cancel_bpt(child); + wake_up_process(child); + ret = 0; + break; + + /* + * make the child exit. Best I can do is send it a sigkill. + * perhaps it should be put in the status that it wants to + * exit. + */ + case PTRACE_KILL: + /* make sure single-step breakpoint is gone. */ + child->ptrace &= ~PT_SINGLESTEP; + ptrace_cancel_bpt(child); + if (child->state != TASK_ZOMBIE) { + child->exit_code = SIGKILL; + wake_up_process(child); + } + ret = 0; + break; + + /* + * execute single instruction. + */ + case PTRACE_SINGLESTEP: + ret = -EIO; + if ((unsigned long) data > _NSIG) + break; + child->ptrace |= PT_SINGLESTEP; + clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + child->exit_code = data; + /* give it a chance to run. */ + wake_up_process(child); + ret = 0; + break; + + case PTRACE_DETACH: + ret = ptrace_detach(child, data); + break; + + case PTRACE_GETREGS: + ret = ptrace_getregs(child, (void *)data); + break; + + case PTRACE_SETREGS: + ret = ptrace_setregs(child, (void *)data); + break; + + case PTRACE_GETFPREGS: + ret = ptrace_getfpregs(child, (void *)data); + break; + + case PTRACE_SETFPREGS: + ret = ptrace_setfpregs(child, (void *)data); + break; + + default: + ret = ptrace_request(child, request, addr, data); + break; + } + + return ret; +} + +asmlinkage int sys_ptrace(long request, long pid, long addr, long data) +{ + struct task_struct *child; + int ret; + + lock_kernel(); + ret = -EPERM; + if (request == PTRACE_TRACEME) { + /* are we already being traced? */ + if (current->ptrace & PT_PTRACED) + goto out; + ret = security_ptrace(current->parent, current); + if (ret) + goto out; + /* set the ptrace bit in the process flags. */ + current->ptrace |= PT_PTRACED; + ret = 0; + goto out; + } + ret = -ESRCH; + read_lock(&tasklist_lock); + child = find_task_by_pid(pid); + if (child) + get_task_struct(child); + read_unlock(&tasklist_lock); + if (!child) + goto out; + + ret = -EPERM; + if (pid == 1) /* you may not mess with init */ + goto out_tsk; + + if (request == PTRACE_ATTACH) { + ret = ptrace_attach(child); + goto out_tsk; + } + ret = ptrace_check_attach(child, request == PTRACE_KILL); + if (ret == 0) + ret = do_ptrace(request, child, addr, data); + +out_tsk: + put_task_struct(child); +out: + unlock_kernel(); + return ret; +} + +asmlinkage void syscall_trace(int why, struct pt_regs *regs) +{ + unsigned long ip; + + if (!test_thread_flag(TIF_SYSCALL_TRACE)) + return; + if (!(current->ptrace & PT_PTRACED)) + return; + + /* + * Save IP. IP is used to denote syscall entry/exit: + * IP = 0 -> entry, = 1 -> exit + */ + ip = regs->ARM_ip; + regs->ARM_ip = why; + + /* the 0x80 provides a way for the tracing parent to distinguish + between a syscall stop and SIGTRAP delivery */ + current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) + ? 0x80 : 0); + current->state = TASK_STOPPED; + notify_parent(current, SIGCHLD); + schedule(); + /* + * this isn't the same as continuing with a signal, but it will do + * for normal use. strace only continues with a signal if the + * stopping signal is not SIGTRAP. -brl + */ + if (current->exit_code) { + send_sig(current->exit_code, current, 1); + current->exit_code = 0; + } + regs->ARM_ip = ip; +} diff -Nru a/arch/arm26/kernel/ptrace.h b/arch/arm26/kernel/ptrace.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/kernel/ptrace.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,13 @@ +/* + * linux/arch/arm26/kernel/ptrace.h + * + * Copyright (C) 2000-2003 Russell King + * Copyright (C) 2003 Ian Molton + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +extern void ptrace_cancel_bpt(struct task_struct *); +extern void ptrace_set_bpt(struct task_struct *); +extern void ptrace_break(struct task_struct *, struct pt_regs *); diff -Nru a/arch/arm26/kernel/semaphore.c b/arch/arm26/kernel/semaphore.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/kernel/semaphore.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,215 @@ +/* + * ARM semaphore implementation, taken from + * + * i386 semaphore implementation. + * + * (C) Copyright 1999 Linus Torvalds + * (C) Copyright 2003 Ian Molton (ARM26 mods) + * + * Modified for ARM by Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/config.h> +#include <linux/sched.h> +#include <linux/errno.h> + +#include <asm/semaphore.h> + +/* + * Semaphores are implemented using a two-way counter: + * The "count" variable is decremented for each process + * that tries to acquire the semaphore, while the "sleeping" + * variable is a count of such acquires. + * + * Notably, the inline "up()" and "down()" functions can + * efficiently test if they need to do any extra work (up + * needs to do something only if count was negative before + * the increment operation. + * + * "sleeping" and the contention routine ordering is + * protected by the semaphore spinlock. + * + * Note that these functions are only called when there is + * contention on the lock, and as such all this is the + * "non-critical" part of the whole semaphore business. The + * critical part is the inline stuff in <asm/semaphore.h> + * where we want to avoid any extra jumps and calls. + */ + +/* + * Logic: + * - only on a boundary condition do we need to care. When we go + * from a negative count to a non-negative, we wake people up. + * - when we go from a non-negative count to a negative do we + * (a) synchronize with the "sleeper" count and (b) make sure + * that we're on the wakeup list before we synchronize so that + * we cannot lose wakeup events. + */ + +void __up(struct semaphore *sem) +{ + wake_up(&sem->wait); +} + +static spinlock_t semaphore_lock = SPIN_LOCK_UNLOCKED; + +void __down(struct semaphore * sem) +{ + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + tsk->state = TASK_UNINTERRUPTIBLE; + add_wait_queue_exclusive(&sem->wait, &wait); + + spin_lock_irq(&semaphore_lock); + sem->sleepers++; + for (;;) { + int sleepers = sem->sleepers; + + /* + * Add "everybody else" into it. They aren't + * playing, because we own the spinlock. + */ + if (!atomic_add_negative(sleepers - 1, &sem->count)) { + sem->sleepers = 0; + break; + } + sem->sleepers = 1; /* us - see -1 above */ + spin_unlock_irq(&semaphore_lock); + + schedule(); + tsk->state = TASK_UNINTERRUPTIBLE; + spin_lock_irq(&semaphore_lock); + } + spin_unlock_irq(&semaphore_lock); + remove_wait_queue(&sem->wait, &wait); + tsk->state = TASK_RUNNING; + wake_up(&sem->wait); +} + +int __down_interruptible(struct semaphore * sem) +{ + int retval = 0; + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + tsk->state = TASK_INTERRUPTIBLE; + add_wait_queue_exclusive(&sem->wait, &wait); + + spin_lock_irq(&semaphore_lock); + sem->sleepers ++; + for (;;) { + int sleepers = sem->sleepers; + + /* + * With signals pending, this turns into + * the trylock failure case - we won't be + * sleeping, and we* can't get the lock as + * it has contention. Just correct the count + * and exit. + */ + if (signal_pending(current)) { + retval = -EINTR; + sem->sleepers = 0; + atomic_add(sleepers, &sem->count); + break; + } + + /* + * Add "everybody else" into it. They aren't + * playing, because we own the spinlock. The + * "-1" is because we're still hoping to get + * the lock. + */ + if (!atomic_add_negative(sleepers - 1, &sem->count)) { + sem->sleepers = 0; + break; + } + sem->sleepers = 1; /* us - see -1 above */ + spin_unlock_irq(&semaphore_lock); + + schedule(); + tsk->state = TASK_INTERRUPTIBLE; + spin_lock_irq(&semaphore_lock); + } + spin_unlock_irq(&semaphore_lock); + tsk->state = TASK_RUNNING; + remove_wait_queue(&sem->wait, &wait); + wake_up(&sem->wait); + return retval; +} + +/* + * Trylock failed - make sure we correct for + * having decremented the count. + * + * We could have done the trylock with a + * single "cmpxchg" without failure cases, + * but then it wouldn't work on a 386. + */ +int __down_trylock(struct semaphore * sem) +{ + int sleepers; + unsigned long flags; + + spin_lock_irqsave(&semaphore_lock, flags); + sleepers = sem->sleepers + 1; + sem->sleepers = 0; + + /* + * Add "everybody else" and us into it. They aren't + * playing, because we own the spinlock. + */ + if (!atomic_add_negative(sleepers, &sem->count)) + wake_up(&sem->wait); + + spin_unlock_irqrestore(&semaphore_lock, flags); + return 1; +} + +/* + * The semaphore operations have a special calling sequence that + * allow us to do a simpler in-line version of them. These routines + * need to convert that sequence back into the C sequence when + * there is contention on the semaphore. + * + * ip contains the semaphore pointer on entry. Save the C-clobbered + * registers (r0 to r3 and lr), but not ip, as we use it as a return + * value in some cases.. + */ +asm(" .align 5 \n\ + .globl __down_failed \n\ +__down_failed: \n\ + stmfd sp!, {r0 - r3, lr} \n\ + mov r0, ip \n\ + bl __down \n\ + ldmfd sp!, {r0 - r3, pc}^ \n\ + \n\ + .align 5 \n\ + .globl __down_interruptible_failed \n\ +__down_interruptible_failed: \n\ + stmfd sp!, {r0 - r3, lr} \n\ + mov r0, ip \n\ + bl __down_interruptible \n\ + mov ip, r0 \n\ + ldmfd sp!, {r0 - r3, pc}^ \n\ + \n\ + .align 5 \n\ + .globl __down_trylock_failed \n\ +__down_trylock_failed: \n\ + stmfd sp!, {r0 - r3, lr} \n\ + mov r0, ip \n\ + bl __down_trylock \n\ + mov ip, r0 \n\ + ldmfd sp!, {r0 - r3, pc}^ \n\ + \n\ + .align 5 \n\ + .globl __up_wakeup \n\ +__up_wakeup: \n\ + stmfd sp!, {r0 - r3, lr} \n\ + mov r0, ip \n\ + bl __up \n\ + ldmfd sp!, {r0 - r3, pc}^ \n\ + "); + diff -Nru a/arch/arm26/kernel/setup.c b/arch/arm26/kernel/setup.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/kernel/setup.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,581 @@ +/* + * linux/arch/arm/kernel/setup.c + * + * Copyright (C) 1995-2001 Russell King + * Copyright (C) 2003 Ian Molton + * + * This program is free software; you can 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/kernel.h> +#include <linux/stddef.h> +#include <linux/ioport.h> +#include <linux/delay.h> +#include <linux/utsname.h> +#include <linux/blk.h> +#include <linux/console.h> +#include <linux/bootmem.h> +#include <linux/seq_file.h> +#include <linux/tty.h> +#include <linux/init.h> +#include <linux/root_dev.h> + +#include <asm/elf.h> +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/procinfo.h> +#include <asm/setup.h> +#include <asm/mach-types.h> +#include <asm/tlbflush.h> + +#include <asm/arch.h> +#include <asm/irqchip.h> + +#ifndef MEM_SIZE +#define MEM_SIZE (16*1024*1024) +#endif + +#ifdef CONFIG_PREEMPT +spinlock_t kernel_flag = SPIN_LOCK_UNLOCKED; +#endif + +#if defined(CONFIG_FPE_NWFPE) +char fpe_type[8]; + +static int __init fpe_setup(char *line) +{ + memcpy(fpe_type, line, 8); + return 1; +} + +__setup("fpe=", fpe_setup); +#endif + +extern void paging_init(struct meminfo *); +extern void convert_to_tag_list(struct tag *tags); +extern void squash_mem_tags(struct tag *tag); +extern void bootmem_init(struct meminfo *); +extern int root_mountflags; +extern int _stext, _text, _etext, _edata, _end; + +unsigned int processor_id; +unsigned int __machine_arch_type; +unsigned int system_rev; +unsigned int system_serial_low; +unsigned int system_serial_high; +unsigned int elf_hwcap; + +struct processor processor; + +unsigned char aux_device_present; +char elf_platform[ELF_PLATFORM_SIZE]; +char saved_command_line[COMMAND_LINE_SIZE]; + +unsigned long phys_initrd_start __initdata = 0; +unsigned long phys_initrd_size __initdata = 0; +static struct meminfo meminfo __initdata = { 0, }; +static struct proc_info_item proc_info; +static const char *machine_name; +static char command_line[COMMAND_LINE_SIZE]; + +static char default_command_line[COMMAND_LINE_SIZE] __initdata = CONFIG_CMDLINE; + +/* + * Standard memory resources + */ +static struct resource mem_res[] = { + { "Video RAM", 0, 0, IORESOURCE_MEM }, + { "Kernel code", 0, 0, IORESOURCE_MEM }, + { "Kernel data", 0, 0, IORESOURCE_MEM } +}; + +#define video_ram mem_res[0] +#define kernel_code mem_res[1] +#define kernel_data mem_res[2] + +static struct resource io_res[] = { + { "reserved", 0x3bc, 0x3be, IORESOURCE_IO | IORESOURCE_BUSY }, + { "reserved", 0x378, 0x37f, IORESOURCE_IO | IORESOURCE_BUSY }, + { "reserved", 0x278, 0x27f, IORESOURCE_IO | IORESOURCE_BUSY } +}; + +#define lp0 io_res[0] +#define lp1 io_res[1] +#define lp2 io_res[2] + +#define dump_cpu_info() do { } while (0) + +static void __init setup_processor(void) +{ + extern struct proc_info_list __proc_info_begin, __proc_info_end; + struct proc_info_list *list; + + /* + * locate processor in the list of supported processor + * types. The linker builds this table for us from the + * entries in arch/arm/mm/proc-*.S + */ + for (list = &__proc_info_begin; list < &__proc_info_end ; list++) + if ((processor_id & list->cpu_mask) == list->cpu_val) + break; + /* + * If processor type is unrecognised, then we + * can do nothing... + */ + if (list >= &__proc_info_end) { + printk("CPU configuration botched (ID %08x), unable " + "to continue.\n", processor_id); + while (1); + } + + proc_info = *list->info; + processor = *list->proc; + + + printk("CPU: %s %s revision %d\n", + proc_info.manufacturer, proc_info.cpu_name, + (int)processor_id & 15); + + dump_cpu_info(); + + sprintf(system_utsname.machine, "%s", list->arch_name); + sprintf(elf_platform, "%s", list->elf_name); + elf_hwcap = list->elf_hwcap; + + cpu_proc_init(); +} + +static struct machine_desc * __init setup_machine(unsigned int nr) +{ + extern struct machine_desc __arch_info_begin, __arch_info_end; + struct machine_desc *list; + + /* + * locate architecture in the list of supported architectures. + */ + for (list = &__arch_info_begin; list < &__arch_info_end; list++) + if (list->nr == nr) + break; + + /* + * If the architecture type is not recognised, then we + * can co nothing... + */ + if (list >= &__arch_info_end) { + printk("Architecture configuration botched (nr %d), unable " + "to continue.\n", nr); + while (1); + } + + printk("Machine: %s\n", list->name); + + return list; +} + +/* + * Initial parsing of the command line. We need to pick out the + * memory size. We look for mem=size@start, where start and size + * are "size[KkMm]" + */ +static void __init +parse_cmdline(struct meminfo *mi, char **cmdline_p, char *from) +{ + char c = ' ', *to = command_line; + int usermem = 0, len = 0; + + for (;;) { + if (c == ' ' && !memcmp(from, "mem=", 4)) { + unsigned long size, start; + + if (to != command_line) + to -= 1; + + /* + * If the user specifies memory size, we + * blow away any automatically generated + * size. + */ + if (usermem == 0) { + usermem = 1; + mi->nr_banks = 0; + } + + start = PHYS_OFFSET; + size = memparse(from + 4, &from); + if (*from == '@') + start = memparse(from + 1, &from); + + mi->bank[mi->nr_banks].start = start; + mi->bank[mi->nr_banks].size = size; + mi->bank[mi->nr_banks].node = PHYS_TO_NID(start); + mi->nr_banks += 1; + } + c = *from++; + if (!c) + break; + if (COMMAND_LINE_SIZE <= ++len) + break; + *to++ = c; + } + *to = '\0'; + *cmdline_p = command_line; +} + +static void __init +setup_ramdisk(int doload, int prompt, int image_start, unsigned int rd_sz) +{ +#ifdef CONFIG_BLK_DEV_RAM + extern int rd_size, rd_image_start, rd_prompt, rd_doload; + + rd_image_start = image_start; + rd_prompt = prompt; + rd_doload = doload; + + if (rd_sz) + rd_size = rd_sz; +#endif +} + +static void __init +request_standard_resources(struct meminfo *mi, struct machine_desc *mdesc) +{ + struct resource *res; + int i; + + kernel_code.start = init_mm.start_code; + kernel_code.end = init_mm.end_code - 1; + kernel_data.start = init_mm.end_code; + kernel_data.end = init_mm.brk - 1; + + for (i = 0; i < mi->nr_banks; i++) { + unsigned long virt_start, virt_end; + + if (mi->bank[i].size == 0) + continue; + + virt_start = mi->bank[i].start; + virt_end = virt_start + mi->bank[i].size - 1; + + res = alloc_bootmem_low(sizeof(*res)); + res->name = "System RAM"; + res->start = virt_start; + res->end = virt_end; + res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; + + request_resource(&iomem_resource, res); + + if (kernel_code.start >= res->start && + kernel_code.end <= res->end) + request_resource(res, &kernel_code); + if (kernel_data.start >= res->start && + kernel_data.end <= res->end) + request_resource(res, &kernel_data); + } + + if (mdesc->video_start) { + video_ram.start = mdesc->video_start; + video_ram.end = mdesc->video_end; + request_resource(&iomem_resource, &video_ram); + } + + /* + * Some machines don't have the possibility of ever + * possessing lp0, lp1 or lp2 + */ + if (mdesc->reserve_lp0) + request_resource(&ioport_resource, &lp0); + if (mdesc->reserve_lp1) + request_resource(&ioport_resource, &lp1); + if (mdesc->reserve_lp2) + request_resource(&ioport_resource, &lp2); +} + +/* + * Tag parsing. + * + * This is the new way of passing data to the kernel at boot time. Rather + * than passing a fixed inflexible structure to the kernel, we pass a list + * of variable-sized tags to the kernel. The first tag must be a ATAG_CORE + * tag for the list to be recognised (to distinguish the tagged list from + * a param_struct). The list is terminated with a zero-length tag (this tag + * is not parsed in any way). + */ +static int __init parse_tag_core(const struct tag *tag) +{ + if (tag->hdr.size > 2) { + if ((tag->u.core.flags & 1) == 0) + root_mountflags &= ~MS_RDONLY; + ROOT_DEV = tag->u.core.rootdev; + } + return 0; +} + +__tagtable(ATAG_CORE, parse_tag_core); + +static int __init parse_tag_mem32(const struct tag *tag) +{ + if (meminfo.nr_banks >= NR_BANKS) { + printk(KERN_WARNING + "Ignoring memory bank 0x%08x size %dKB\n", + tag->u.mem.start, tag->u.mem.size / 1024); + return -EINVAL; + } + meminfo.bank[meminfo.nr_banks].start = tag->u.mem.start; + meminfo.bank[meminfo.nr_banks].size = tag->u.mem.size; + meminfo.bank[meminfo.nr_banks].node = PHYS_TO_NID(tag->u.mem.start); + meminfo.nr_banks += 1; + + return 0; +} + +__tagtable(ATAG_MEM, parse_tag_mem32); + +#if defined(CONFIG_DUMMY_CONSOLE) +struct screen_info screen_info = { + orig_video_lines: 30, + orig_video_cols: 80, + orig_video_mode: 0, + orig_video_ega_bx: 0, + orig_video_isVGA: 1, + orig_video_points: 8 +}; + +static int __init parse_tag_videotext(const struct tag *tag) +{ + screen_info.orig_x = tag->u.videotext.x; + screen_info.orig_y = tag->u.videotext.y; + screen_info.orig_video_page = tag->u.videotext.video_page; + screen_info.orig_video_mode = tag->u.videotext.video_mode; + screen_info.orig_video_cols = tag->u.videotext.video_cols; + screen_info.orig_video_ega_bx = tag->u.videotext.video_ega_bx; + screen_info.orig_video_lines = tag->u.videotext.video_lines; + screen_info.orig_video_isVGA = tag->u.videotext.video_isvga; + screen_info.orig_video_points = tag->u.videotext.video_points; + return 0; +} + +__tagtable(ATAG_VIDEOTEXT, parse_tag_videotext); +#endif + +static int __init parse_tag_ramdisk(const struct tag *tag) +{ + setup_ramdisk((tag->u.ramdisk.flags & 1) == 0, + (tag->u.ramdisk.flags & 2) == 0, + tag->u.ramdisk.start, tag->u.ramdisk.size); + return 0; +} + +__tagtable(ATAG_RAMDISK, parse_tag_ramdisk); + +static int __init parse_tag_initrd(const struct tag *tag) +{ + printk(KERN_WARNING "ATAG_INITRD is deprecated; please update your bootloader. \n"); + phys_initrd_start = (unsigned long)tag->u.initrd.start; + phys_initrd_size = (unsigned long)tag->u.initrd.size; + return 0; +} + +__tagtable(ATAG_INITRD, parse_tag_initrd); + +static int __init parse_tag_initrd2(const struct tag *tag) +{ + printk(KERN_WARNING "ATAG_INITRD is deprecated; please update your bootloader. \n"); + phys_initrd_start = (unsigned long)tag->u.initrd.start; + phys_initrd_size = (unsigned long)tag->u.initrd.size; + return 0; +} + +__tagtable(ATAG_INITRD2, parse_tag_initrd2); + +static int __init parse_tag_serialnr(const struct tag *tag) +{ + system_serial_low = tag->u.serialnr.low; + system_serial_high = tag->u.serialnr.high; + return 0; +} + +__tagtable(ATAG_SERIAL, parse_tag_serialnr); + +static int __init parse_tag_revision(const struct tag *tag) +{ + system_rev = tag->u.revision.rev; + return 0; +} + +__tagtable(ATAG_REVISION, parse_tag_revision); + +static int __init parse_tag_cmdline(const struct tag *tag) +{ + strncpy(default_command_line, tag->u.cmdline.cmdline, COMMAND_LINE_SIZE); + default_command_line[COMMAND_LINE_SIZE - 1] = '\0'; + return 0; +} + +__tagtable(ATAG_CMDLINE, parse_tag_cmdline); + +/* + * Scan the tag table for this tag, and call its parse function. + * The tag table is built by the linker from all the __tagtable + * declarations. + */ +static int __init parse_tag(const struct tag *tag) +{ + extern struct tagtable __tagtable_begin, __tagtable_end; + struct tagtable *t; + + for (t = &__tagtable_begin; t < &__tagtable_end; t++) + if (tag->hdr.tag == t->tag) { + t->parse(tag); + break; + } + + return t < &__tagtable_end; +} + +/* + * Parse all tags in the list, checking both the global and architecture + * specific tag tables. + */ +static void __init parse_tags(const struct tag *t) +{ + for (; t->hdr.size; t = tag_next(t)) + if (!parse_tag(t)) + printk(KERN_WARNING + "Ignoring unrecognised tag 0x%08x\n", + t->hdr.tag); +} + +/* + * This holds our defaults. + */ +static struct init_tags { + struct tag_header hdr1; + struct tag_core core; + struct tag_header hdr2; + struct tag_mem32 mem; + struct tag_header hdr3; +} init_tags __initdata = { + { tag_size(tag_core), ATAG_CORE }, + { 1, PAGE_SIZE, 0xff }, + { tag_size(tag_mem32), ATAG_MEM }, + { MEM_SIZE, PHYS_OFFSET }, + { 0, ATAG_NONE } +}; + +void __init setup_arch(char **cmdline_p) +{ + struct tag *tags = (struct tag *)&init_tags; + struct machine_desc *mdesc; + char *from = default_command_line; + + setup_processor(); + mdesc = setup_machine(machine_arch_type); + machine_name = mdesc->name; + + if (mdesc->param_offset) + tags = (struct tag *)mdesc->param_offset; //FIXME - ugly? + + /* + * If we have the old style parameters, convert them to + * a tag list. + */ + if (tags->hdr.tag != ATAG_CORE) + convert_to_tag_list(tags); + if (tags->hdr.tag != ATAG_CORE) + tags = (struct tag *)&init_tags; + if (tags->hdr.tag == ATAG_CORE) { + if (meminfo.nr_banks != 0) + squash_mem_tags(tags); + parse_tags(tags); + } + + init_mm.start_code = (unsigned long) &_text; + init_mm.end_code = (unsigned long) &_etext; + init_mm.end_data = (unsigned long) &_edata; + init_mm.brk = (unsigned long) &_end; + + memcpy(saved_command_line, from, COMMAND_LINE_SIZE); + saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; + parse_cmdline(&meminfo, cmdline_p, from); + bootmem_init(&meminfo); + paging_init(&meminfo); + request_standard_resources(&meminfo, mdesc); + + /* + * Set up various architecture-specific pointers + */ + init_arch_irq = mdesc->init_irq; + +#ifdef CONFIG_VT +#if defined(CONFIG_DUMMY_CONSOLE) + conswitchp = &dummy_con; +#endif +#endif +} + +static const char *hwcap_str[] = { + "swp", + "half", + "thumb", + "26bit", + "fastmult", + "fpa", + "vfp", + "edsp", + NULL +}; + +static int c_show(struct seq_file *m, void *v) +{ + int i; + + seq_printf(m, "Processor\t: %s %s rev %d (%s)\n", + proc_info.manufacturer, proc_info.cpu_name, + (int)processor_id & 15, elf_platform); + + seq_printf(m, "BogoMIPS\t: %lu.%02lu\n", + loops_per_jiffy / (500000/HZ), + (loops_per_jiffy / (5000/HZ)) % 100); + + /* dump out the processor features */ + seq_puts(m, "Features\t: "); + + for (i = 0; hwcap_str[i]; i++) + if (elf_hwcap & (1 << i)) + seq_printf(m, "%s ", hwcap_str[i]); + + seq_puts(m, "\n"); + + seq_printf(m, "CPU part\t\t: %07x\n", processor_id >> 4); + seq_printf(m, "CPU revision\t: %d\n\n", processor_id & 15); + seq_printf(m, "Hardware\t: %s\n", machine_name); + seq_printf(m, "Revision\t: %04x\n", system_rev); + seq_printf(m, "Serial\t\t: %08x%08x\n", + system_serial_high, system_serial_low); + + return 0; +} + +static void *c_start(struct seq_file *m, loff_t *pos) +{ + return *pos < 1 ? (void *)1 : NULL; +} + +static void *c_next(struct seq_file *m, void *v, loff_t *pos) +{ + ++*pos; + return NULL; +} + +static void c_stop(struct seq_file *m, void *v) +{ +} + +struct seq_operations cpuinfo_op = { + .start = c_start, + .next = c_next, + .stop = c_stop, + .show = c_show +}; diff -Nru a/arch/arm26/kernel/signal.c b/arch/arm26/kernel/signal.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/kernel/signal.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,542 @@ +/* + * linux/arch/arm26/kernel/signal.c + * + * Copyright (C) 1995-2002 Russell King + * Copyright (C) 2003 Ian Molton (ARM26) + * + * FIXME!!! This is probably very broken (13/05/2003) + * + * This program is free software; you can 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/sched.h> +#include <linux/mm.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/signal.h> +#include <linux/wait.h> +#include <linux/ptrace.h> +#include <linux/personality.h> +#include <linux/tty.h> +#include <linux/binfmts.h> +#include <linux/elf.h> + +#include <asm/pgalloc.h> +#include <asm/ucontext.h> +#include <asm/uaccess.h> +#include <asm/unistd.h> + +#include "ptrace.h" + +#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) + +/* + * For ARM syscalls, we encode the syscall number into the instruction. + */ +#define SWI_SYS_SIGRETURN (0xef000000|(__NR_sigreturn)) +#define SWI_SYS_RT_SIGRETURN (0xef000000|(__NR_rt_sigreturn)) + +static int do_signal(sigset_t *oldset, struct pt_regs * regs, int syscall); + +/* + * atomically swap in the new signal mask, and wait for a signal. + */ +asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, old_sigset_t mask, struct pt_regs *regs) +{ + sigset_t saveset; + + mask &= _BLOCKABLE; + spin_lock_irq(¤t->sighand->siglock); + saveset = current->blocked; + siginitset(¤t->blocked, mask); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + regs->ARM_r0 = -EINTR; + + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(&saveset, regs, 0)) + return regs->ARM_r0; + } +} + +asmlinkage int +sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, struct pt_regs *regs) +{ + sigset_t saveset, newset; + + /* XXX: Don't preclude handling different sized sigset_t's. */ + if (sigsetsize != sizeof(sigset_t)) + return -EINVAL; + + if (copy_from_user(&newset, unewset, sizeof(newset))) + return -EFAULT; + sigdelsetmask(&newset, ~_BLOCKABLE); + + spin_lock_irq(¤t->sighand->siglock); + saveset = current->blocked; + current->blocked = newset; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + regs->ARM_r0 = -EINTR; + + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(&saveset, regs, 0)) + return regs->ARM_r0; + } +} + +asmlinkage int +sys_sigaction(int sig, const struct old_sigaction *act, + struct old_sigaction *oact) +{ + struct k_sigaction new_ka, old_ka; + int ret; + + if (act) { + old_sigset_t mask; + if (verify_area(VERIFY_READ, act, sizeof(*act)) || + __get_user(new_ka.sa.sa_handler, &act->sa_handler) || + __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) + return -EFAULT; + __get_user(new_ka.sa.sa_flags, &act->sa_flags); + __get_user(mask, &act->sa_mask); + siginitset(&new_ka.sa.sa_mask, mask); + } + + ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); + + if (!ret && oact) { + if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || + __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || + __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) + return -EFAULT; + __put_user(old_ka.sa.sa_flags, &oact->sa_flags); + __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); + } + + return ret; +} + +/* + * Do a signal return; undo the signal stack. + */ +struct sigframe +{ + struct sigcontext sc; + unsigned long extramask[_NSIG_WORDS-1]; + unsigned long retcode; +}; + +struct rt_sigframe +{ + struct siginfo *pinfo; + void *puc; + struct siginfo info; + struct ucontext uc; + unsigned long retcode; +}; + +static int +restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc) +{ + int err = 0; + + __get_user_error(regs->ARM_r0, &sc->arm_r0, err); + __get_user_error(regs->ARM_r1, &sc->arm_r1, err); + __get_user_error(regs->ARM_r2, &sc->arm_r2, err); + __get_user_error(regs->ARM_r3, &sc->arm_r3, err); + __get_user_error(regs->ARM_r4, &sc->arm_r4, err); + __get_user_error(regs->ARM_r5, &sc->arm_r5, err); + __get_user_error(regs->ARM_r6, &sc->arm_r6, err); + __get_user_error(regs->ARM_r7, &sc->arm_r7, err); + __get_user_error(regs->ARM_r8, &sc->arm_r8, err); + __get_user_error(regs->ARM_r9, &sc->arm_r9, err); + __get_user_error(regs->ARM_r10, &sc->arm_r10, err); + __get_user_error(regs->ARM_fp, &sc->arm_fp, err); + __get_user_error(regs->ARM_ip, &sc->arm_ip, err); + __get_user_error(regs->ARM_sp, &sc->arm_sp, err); + __get_user_error(regs->ARM_lr, &sc->arm_lr, err); + __get_user_error(regs->ARM_pc, &sc->arm_pc, err); + + err |= !valid_user_regs(regs); + + return err; +} + +asmlinkage int sys_sigreturn(struct pt_regs *regs) +{ + struct sigframe *frame; + sigset_t set; + + /* + * Since we stacked the signal on a 64-bit boundary, + * then 'sp' should be word aligned here. If it's + * not, then the user is trying to mess with us. + */ + if (regs->ARM_sp & 7) + goto badframe; + + frame = (struct sigframe *)regs->ARM_sp; + + if (verify_area(VERIFY_READ, frame, sizeof (*frame))) + goto badframe; + if (__get_user(set.sig[0], &frame->sc.oldmask) + || (_NSIG_WORDS > 1 + && __copy_from_user(&set.sig[1], &frame->extramask, + sizeof(frame->extramask)))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sighand->siglock); + current->blocked = set; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + if (restore_sigcontext(regs, &frame->sc)) + goto badframe; + + /* Send SIGTRAP if we're single-stepping */ + if (current->ptrace & PT_SINGLESTEP) { + ptrace_cancel_bpt(current); + send_sig(SIGTRAP, current, 1); + } + + return regs->ARM_r0; + +badframe: + force_sig(SIGSEGV, current); + return 0; +} + +asmlinkage int sys_rt_sigreturn(struct pt_regs *regs) +{ + struct rt_sigframe *frame; + sigset_t set; + + /* + * Since we stacked the signal on a 64-bit boundary, + * then 'sp' should be word aligned here. If it's + * not, then the user is trying to mess with us. + */ + if (regs->ARM_sp & 7) + goto badframe; + + frame = (struct rt_sigframe *)regs->ARM_sp; + + if (verify_area(VERIFY_READ, frame, sizeof (*frame))) + goto badframe; + if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set))) + goto badframe; + + sigdelsetmask(&set, ~_BLOCKABLE); + spin_lock_irq(¤t->sighand->siglock); + current->blocked = set; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + if (restore_sigcontext(regs, &frame->uc.uc_mcontext)) + goto badframe; + + /* Send SIGTRAP if we're single-stepping */ + if (current->ptrace & PT_SINGLESTEP) { + ptrace_cancel_bpt(current); + send_sig(SIGTRAP, current, 1); + } + + return regs->ARM_r0; + +badframe: + force_sig(SIGSEGV, current); + return 0; +} + +static int +setup_sigcontext(struct sigcontext *sc, /*struct _fpstate *fpstate,*/ + struct pt_regs *regs, unsigned long mask) +{ + int err = 0; + + __put_user_error(regs->ARM_r0, &sc->arm_r0, err); + __put_user_error(regs->ARM_r1, &sc->arm_r1, err); + __put_user_error(regs->ARM_r2, &sc->arm_r2, err); + __put_user_error(regs->ARM_r3, &sc->arm_r3, err); + __put_user_error(regs->ARM_r4, &sc->arm_r4, err); + __put_user_error(regs->ARM_r5, &sc->arm_r5, err); + __put_user_error(regs->ARM_r6, &sc->arm_r6, err); + __put_user_error(regs->ARM_r7, &sc->arm_r7, err); + __put_user_error(regs->ARM_r8, &sc->arm_r8, err); + __put_user_error(regs->ARM_r9, &sc->arm_r9, err); + __put_user_error(regs->ARM_r10, &sc->arm_r10, err); + __put_user_error(regs->ARM_fp, &sc->arm_fp, err); + __put_user_error(regs->ARM_ip, &sc->arm_ip, err); + __put_user_error(regs->ARM_sp, &sc->arm_sp, err); + __put_user_error(regs->ARM_lr, &sc->arm_lr, err); + __put_user_error(regs->ARM_pc, &sc->arm_pc, err); + + __put_user_error(current->thread.trap_no, &sc->trap_no, err); + __put_user_error(current->thread.error_code, &sc->error_code, err); + __put_user_error(current->thread.address, &sc->fault_address, err); + __put_user_error(mask, &sc->oldmask, err); + + return err; +} + +static inline void * +get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, int framesize) +{ + unsigned long sp = regs->ARM_sp; + + /* + * This is the X/Open sanctioned signal stack switching. + */ + if ((ka->sa.sa_flags & SA_ONSTACK) && !sas_ss_flags(sp)) + sp = current->sas_ss_sp + current->sas_ss_size; + + /* + * ATPCS B01 mandates 8-byte alignment + */ + return (void *)((sp - framesize) & ~7); +} + +static int +setup_return(struct pt_regs *regs, struct k_sigaction *ka, + unsigned long *rc, void *frame, int usig) +{ + unsigned long handler = (unsigned long)ka->sa.sa_handler; + unsigned long retcode; + + if (ka->sa.sa_flags & SA_RESTORER) { + retcode = (unsigned long)ka->sa.sa_restorer; + } else { + + if (__put_user((ka->sa.sa_flags & SA_SIGINFO)?SWI_SYS_RT_SIGRETURN:SWI_SYS_SIGRETURN, rc)) + return 1; + + retcode = ((unsigned long)rc); + } + + regs->ARM_r0 = usig; + regs->ARM_sp = (unsigned long)frame; + regs->ARM_lr = retcode; + regs->ARM_pc = handler & ~3; + + return 0; +} + +static int +setup_frame(int usig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *regs) +{ + struct sigframe *frame = get_sigframe(ka, regs, sizeof(*frame)); + int err = 0; + + if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) + return 1; + + err |= setup_sigcontext(&frame->sc, /*&frame->fpstate,*/ regs, set->sig[0]); + + if (_NSIG_WORDS > 1) { + err |= __copy_to_user(frame->extramask, &set->sig[1], + sizeof(frame->extramask)); + } + + if (err == 0) + err = setup_return(regs, ka, &frame->retcode, frame, usig); + + return err; +} + +static int +setup_rt_frame(int usig, struct k_sigaction *ka, siginfo_t *info, + sigset_t *set, struct pt_regs *regs) +{ + struct rt_sigframe *frame = get_sigframe(ka, regs, sizeof(*frame)); + int err = 0; + + if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) + return 1; + + __put_user_error(&frame->info, &frame->pinfo, err); + __put_user_error(&frame->uc, &frame->puc, err); + err |= copy_siginfo_to_user(&frame->info, info); + + /* Clear all the bits of the ucontext we don't use. */ + err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext)); + + err |= setup_sigcontext(&frame->uc.uc_mcontext, /*&frame->fpstate,*/ + regs, set->sig[0]); + err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); + + if (err == 0) + err = setup_return(regs, ka, &frame->retcode, frame, usig); + + if (err == 0) { + /* + * For realtime signals we must also set the second and third + * arguments for the signal handler. + * -- Peter Maydell <pmaydell@chiark.greenend.org.uk> 2000-12-06 + */ + regs->ARM_r1 = (unsigned long)frame->pinfo; + regs->ARM_r2 = (unsigned long)frame->puc; + } + + return err; +} + +static inline void restart_syscall(struct pt_regs *regs) +{ + regs->ARM_r0 = regs->ARM_ORIG_r0; + regs->ARM_pc -= 4; +} + +/* + * OK, we're invoking a handler + */ +static void +handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset, + struct pt_regs * regs, int syscall) +{ + struct thread_info *thread = current_thread_info(); + struct task_struct *tsk = current; + struct k_sigaction *ka = &tsk->sighand->action[sig-1]; + int usig = sig; + int ret; + + /* + * If we were from a system call, check for system call restarting... + */ + if (syscall) { + switch (regs->ARM_r0) { + case -ERESTART_RESTARTBLOCK: + current_thread_info()->restart_block.fn = + do_no_restart_syscall; + case -ERESTARTNOHAND: + regs->ARM_r0 = -EINTR; + break; + case -ERESTARTSYS: + if (!(ka->sa.sa_flags & SA_RESTART)) { + regs->ARM_r0 = -EINTR; + break; + } + /* fallthrough */ + case -ERESTARTNOINTR: + restart_syscall(regs); + } + } + + /* + * translate the signal + */ + if (usig < 32 && thread->exec_domain && thread->exec_domain->signal_invmap) + usig = thread->exec_domain->signal_invmap[usig]; + + /* + * Set up the stack frame + */ + if (ka->sa.sa_flags & SA_SIGINFO) + ret = setup_rt_frame(usig, ka, info, oldset, regs); + else + ret = setup_frame(usig, ka, oldset, regs); + + /* + * Check that the resulting registers are actually sane. + */ + ret |= !valid_user_regs(regs); + + if (ret == 0) { + if (ka->sa.sa_flags & SA_ONESHOT) + ka->sa.sa_handler = SIG_DFL; + + if (!(ka->sa.sa_flags & SA_NODEFER)) { + spin_lock_irq(&tsk->sighand->siglock); + sigorsets(&tsk->blocked, &tsk->blocked, + &ka->sa.sa_mask); + sigaddset(&tsk->blocked, sig); + recalc_sigpending(); + spin_unlock_irq(&tsk->sighand->siglock); + } + return; + } + + if (sig == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + force_sig(SIGSEGV, tsk); +} + +/* + * Note that 'init' is a special process: it doesn't get signals it doesn't + * want to handle. Thus you cannot kill init even with a SIGKILL even by + * mistake. + * + * Note that we go through the signals twice: once to check the signals that + * the kernel can handle, and then we build all the user-level signal handling + * stack-frames in one go after that. + */ +static int do_signal(sigset_t *oldset, struct pt_regs *regs, int syscall) +{ + siginfo_t info; + int signr; + + /* + * We want the common case to go fast, which + * is why we may in certain cases get here from + * kernel mode. Just return without doing anything + * if so. + */ + if (!user_mode(regs)) + return 0; + + if (current->ptrace & PT_SINGLESTEP) + ptrace_cancel_bpt(current); + + signr = get_signal_to_deliver(&info, regs, NULL); + if (signr > 0) { + handle_signal(signr, &info, oldset, regs, syscall); + if (current->ptrace & PT_SINGLESTEP) + ptrace_set_bpt(current); + return 1; + } + + /* + * No signal to deliver to the process - restart the syscall. + */ + if (syscall) { + if (regs->ARM_r0 == -ERESTART_RESTARTBLOCK) { + u32 *usp; + + regs->ARM_sp -= 12; + usp = (u32 *)regs->ARM_sp; + + put_user(regs->ARM_pc, &usp[0]); + /* swi __NR_restart_syscall */ + put_user(0xef000000 | __NR_restart_syscall, &usp[1]); + /* ldr pc, [sp], #12 */ +// FIXME!!! is #12 correct there? + put_user(0xe49df00c, &usp[2]); + + regs->ARM_pc = regs->ARM_sp + 4; + } + if (regs->ARM_r0 == -ERESTARTNOHAND || + regs->ARM_r0 == -ERESTARTSYS || + regs->ARM_r0 == -ERESTARTNOINTR) { + restart_syscall(regs); + } + } + if (current->ptrace & PT_SINGLESTEP) + ptrace_set_bpt(current); + return 0; +} + +asmlinkage void +do_notify_resume(struct pt_regs *regs, unsigned int thread_flags, int syscall) +{ + if (thread_flags & _TIF_SIGPENDING) + do_signal(¤t->blocked, regs, syscall); +} diff -Nru a/arch/arm26/kernel/sys_arm.c b/arch/arm26/kernel/sys_arm.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/kernel/sys_arm.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,283 @@ +/* + * linux/arch/arm26/kernel/sys_arm.c + * + * Copyright (C) People who wrote linux/arch/i386/kernel/sys_i386.c + * Copyright (C) 1995, 1996 Russell King. + * Copyright (C) 2003 Ian Molton. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This file contains various random system calls that + * have a non-standard calling sequence on the Linux/arm + * platform. + */ +#include <linux/errno.h> +#include <linux/sched.h> +#include <linux/slab.h> +#include <linux/mm.h> +#include <linux/sem.h> +#include <linux/msg.h> +#include <linux/shm.h> +#include <linux/stat.h> +#include <linux/mman.h> +#include <linux/fs.h> +#include <linux/file.h> +#include <linux/utsname.h> + +#include <asm/uaccess.h> +#include <asm/ipc.h> + +extern unsigned long do_mremap(unsigned long addr, unsigned long old_len, + unsigned long new_len, unsigned long flags, + unsigned long new_addr); + +/* + * sys_pipe() is the normal C calling standard for creating + * a pipe. It's not the way unix traditionally does this, though. + */ +asmlinkage int sys_pipe(unsigned long * fildes) +{ + int fd[2]; + int error; + + error = do_pipe(fd); + if (!error) { + if (copy_to_user(fildes, fd, 2*sizeof(int))) + error = -EFAULT; + } + return error; +} + +/* common code for old and new mmaps */ +inline long do_mmap2( + unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, unsigned long pgoff) +{ + int error = -EINVAL; + struct file * file = NULL; + + flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); + + /* + * If we are doing a fixed mapping, and address < PAGE_SIZE, + * then deny it. + */ + if (flags & MAP_FIXED && addr < PAGE_SIZE && vectors_base() == 0) + goto out; + + error = -EBADF; + if (!(flags & MAP_ANONYMOUS)) { + file = fget(fd); + if (!file) + goto out; + } + + down_write(¤t->mm->mmap_sem); + error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff); + up_write(¤t->mm->mmap_sem); + + if (file) + fput(file); +out: + return error; +} + +struct mmap_arg_struct { + unsigned long addr; + unsigned long len; + unsigned long prot; + unsigned long flags; + unsigned long fd; + unsigned long offset; +}; + +asmlinkage int old_mmap(struct mmap_arg_struct *arg) +{ + int error = -EFAULT; + struct mmap_arg_struct a; + + if (copy_from_user(&a, arg, sizeof(a))) + goto out;; + + error = -EINVAL; + if (a.offset & ~PAGE_MASK) + goto out; + + error = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT); +out: + return error; +} + +asmlinkage unsigned long +sys_arm_mremap(unsigned long addr, unsigned long old_len, + unsigned long new_len, unsigned long flags, + unsigned long new_addr) +{ + unsigned long ret = -EINVAL; + + /* + * If we are doing a fixed mapping, and address < PAGE_SIZE, + * then deny it. + */ + if (flags & MREMAP_FIXED && new_addr < PAGE_SIZE && + vectors_base() == 0) + goto out; + + down_write(¤t->mm->mmap_sem); + ret = do_mremap(addr, old_len, new_len, flags, new_addr); + up_write(¤t->mm->mmap_sem); + +out: + return ret; +} + +/* + * Perform the select(nd, in, out, ex, tv) and mmap() system + * calls. + */ +extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); + +struct sel_arg_struct { + unsigned long n; + fd_set *inp, *outp, *exp; + struct timeval *tvp; +}; + +asmlinkage int old_select(struct sel_arg_struct *arg) +{ + struct sel_arg_struct a; + + if (copy_from_user(&a, arg, sizeof(a))) + return -EFAULT; + /* sys_select() does the appropriate kernel locking */ + return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); +} + +/* + * sys_ipc() is the de-multiplexer for the SysV IPC calls.. + * + * This is really horribly ugly. + */ +asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth) +{ + int version, ret; + + version = call >> 16; /* hack for backward compatibility */ + call &= 0xffff; + + switch (call) { + case SEMOP: + return sys_semop (first, (struct sembuf *)ptr, second); + case SEMGET: + return sys_semget (first, second, third); + case SEMCTL: { + union semun fourth; + if (!ptr) + return -EINVAL; + if (get_user(fourth.__pad, (void **) ptr)) + return -EFAULT; + return sys_semctl (first, second, third, fourth); + } + + case MSGSND: + return sys_msgsnd (first, (struct msgbuf *) ptr, + second, third); + case MSGRCV: + switch (version) { + case 0: { + struct ipc_kludge tmp; + if (!ptr) + return -EINVAL; + if (copy_from_user(&tmp,(struct ipc_kludge *) ptr, + sizeof (tmp))) + return -EFAULT; + return sys_msgrcv (first, tmp.msgp, second, + tmp.msgtyp, third); + } + default: + return sys_msgrcv (first, + (struct msgbuf *) ptr, + second, fifth, third); + } + case MSGGET: + return sys_msgget ((key_t) first, second); + case MSGCTL: + return sys_msgctl (first, second, (struct msqid_ds *) ptr); + + case SHMAT: + switch (version) { + default: { + ulong raddr; + ret = sys_shmat (first, (char *) ptr, second, &raddr); + if (ret) + return ret; + return put_user (raddr, (ulong *) third); + } + case 1: /* iBCS2 emulator entry point */ + if (!segment_eq(get_fs(), get_ds())) + return -EINVAL; + return sys_shmat (first, (char *) ptr, + second, (ulong *) third); + } + case SHMDT: + return sys_shmdt ((char *)ptr); + case SHMGET: + return sys_shmget (first, second, third); + case SHMCTL: + return sys_shmctl (first, second, + (struct shmid_ds *) ptr); + default: + return -EINVAL; + } +} + +/* Fork a new task - this creates a new program thread. + * This is called indirectly via a small wrapper + */ +asmlinkage int sys_fork(struct pt_regs *regs) +{ + return do_fork(SIGCHLD, regs->ARM_sp, regs, 0, NULL, NULL); +} + +/* Clone a task - this clones the calling program thread. + * This is called indirectly via a small wrapper + */ +asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, struct pt_regs *regs) +{ + /* + * We don't support SETTID / CLEARTID (FIXME!!! (nicked from arm32)) + */ + if (clone_flags & (CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID)) + return -EINVAL; + + if (!newsp) + newsp = regs->ARM_sp; + + return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, regs, 0, NULL, NULL); +} + +asmlinkage int sys_vfork(struct pt_regs *regs) +{ + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->ARM_sp, regs, 0, NULL, NULL); +} + +/* sys_execve() executes a new program. + * This is called indirectly via a small wrapper + */ +asmlinkage int sys_execve(char *filenamei, char **argv, char **envp, struct pt_regs *regs) +{ + int error; + char * filename; + + filename = getname(filenamei); + error = PTR_ERR(filename); + if (IS_ERR(filename)) + goto out; + error = do_execve(filename, argv, envp, regs); + putname(filename); +out: + return error; +} diff -Nru a/arch/arm26/kernel/time-acorn.c b/arch/arm26/kernel/time-acorn.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/kernel/time-acorn.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,69 @@ +/* + * linux/arch/arm/kernel/time-acorn.c + * + * Copyright (c) 1996-2000 Russell King. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Changelog: + * 24-Sep-1996 RMK Created + * 10-Oct-1996 RMK Brought up to date with arch-sa110eval + * 04-Dec-1997 RMK Updated for new arch/arm/time.c + * 13-May-2003 IM Brought over to ARM26 + */ +#include <linux/sched.h> +#include <linux/interrupt.h> +#include <linux/init.h> + +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/ioc.h> + +extern unsigned long (*gettimeoffset)(void); + +static unsigned long ioctime_gettimeoffset(void) +{ + unsigned int count1, count2, status; + long offset; + + ioc_writeb (0, IOC_T0LATCH); + barrier (); + count1 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8); + barrier (); + status = ioc_readb(IOC_IRQREQA); + barrier (); + ioc_writeb (0, IOC_T0LATCH); + barrier (); + count2 = ioc_readb(IOC_T0CNTL) | (ioc_readb(IOC_T0CNTH) << 8); + + offset = count2; + if (count2 < count1) { + /* + * We have not had an interrupt between reading count1 + * and count2. + */ + if (status & (1 << 5)) + offset -= LATCH; + } else if (count2 > count1) { + /* + * We have just had another interrupt between reading + * count1 and count2. + */ + offset -= LATCH; + } + + offset = (LATCH - offset) * (tick_nsec / 1000); + return (offset + LATCH/2) / LATCH; +} + +void __init ioctime_init(void) +{ + ioc_writeb(LATCH & 255, IOC_T0LTCHL); + ioc_writeb(LATCH >> 8, IOC_T0LTCHH); + ioc_writeb(0, IOC_T0GO); + + gettimeoffset = ioctime_gettimeoffset; +} diff -Nru a/arch/arm26/kernel/time.c b/arch/arm26/kernel/time.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/kernel/time.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,202 @@ +/* + * linux/arch/arm26/kernel/time.c + * + * Copyright (C) 1991, 1992, 1995 Linus Torvalds + * Modifications for ARM (C) 1994-2001 Russell King + * Mods for ARM26 (C) 2003 Ian Molton + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This file contains the ARM-specific time handling details: + * reading the RTC at bootup, etc... + * + * 1994-07-02 Alan Modra + * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime + * 1998-12-20 Updated NTP code according to technical memorandum Jan '96 + * "A Kernel Model for Precision Timekeeping" by Dave Mills + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/interrupt.h> +#include <linux/time.h> +#include <linux/init.h> +#include <linux/smp.h> +#include <linux/timex.h> +#include <linux/errno.h> +#include <linux/profile.h> + +#include <asm/hardware.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/leds.h> + +u64 jiffies_64 = INITIAL_JIFFIES; + +extern unsigned long wall_jiffies; + +/* this needs a better home */ +spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; + +/* change this if you have some constant time drift */ +#define USECS_PER_JIFFY (1000000/HZ) + +static int dummy_set_rtc(void) +{ + return 0; +} + +/* + * hook for setting the RTC's idea of the current time. + */ +int (*set_rtc)(void) = dummy_set_rtc; + +static unsigned long dummy_gettimeoffset(void) +{ + return 0; +} + +/* + * hook for getting the time offset. Note that it is + * always called with interrupts disabled. + */ +unsigned long (*gettimeoffset)(void) = dummy_gettimeoffset; + +/* + * Handle kernel profile stuff... + */ +static inline void do_profile(struct pt_regs *regs) +{ + if (!user_mode(regs) && + prof_buffer && + current->pid) { + unsigned long pc = instruction_pointer(regs); + extern int _stext; + + pc -= (unsigned long)&_stext; + + pc >>= prof_shift; + + if (pc >= prof_len) + pc = prof_len - 1; + + prof_buffer[pc] += 1; + } +} + +static unsigned long next_rtc_update; + +/* + * If we have an externally synchronized linux clock, then update + * CMOS clock accordingly every ~11 minutes. set_rtc() has to be + * called as close as possible to 500 ms before the new second + * starts. + */ +static inline void do_set_rtc(void) +{ + if (time_status & STA_UNSYNC || set_rtc == NULL) + return; + +//FIXME - timespec.tv_sec is a time_t not unsigned long + if (next_rtc_update && + time_before((unsigned long)xtime.tv_sec, next_rtc_update)) + return; + + if (xtime.tv_nsec < 500000000 - ((unsigned) tick_nsec >> 1) && + xtime.tv_nsec >= 500000000 + ((unsigned) tick_nsec >> 1)) + return; + + if (set_rtc()) + /* + * rtc update failed. Try again in 60s + */ + next_rtc_update = xtime.tv_sec + 60; + else + next_rtc_update = xtime.tv_sec + 660; +} + +#define do_leds() + +void do_gettimeofday(struct timeval *tv) +{ + unsigned long flags; + unsigned long seq; + unsigned long usec, sec, lost; + + do { + seq = read_seqbegin_irqsave(&xtime_lock, flags); + usec = gettimeoffset(); + + lost = jiffies - wall_jiffies; + if (lost) + usec += lost * USECS_PER_JIFFY; + + sec = xtime.tv_sec; + usec += xtime.tv_nsec / 1000; + } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); + + /* usec may have gone up a lot: be safe */ + while (usec >= 1000000) { + usec -= 1000000; + sec++; + } + + tv->tv_sec = sec; + tv->tv_usec = usec; +} + +void do_settimeofday(struct timeval *tv) +{ + write_seqlock_irq(&xtime_lock); + /* + * This is revolting. We need to set "xtime" correctly. However, the + * value in this location is the value at the most recent update of + * wall time. Discover what correction gettimeofday() would have + * done, and then undo it! + */ + tv->tv_usec -= gettimeoffset(); + tv->tv_usec -= (jiffies - wall_jiffies) * USECS_PER_JIFFY; + + while (tv->tv_usec < 0) { + tv->tv_usec += 1000000; + tv->tv_sec--; + } + + xtime.tv_sec = tv->tv_sec; + xtime.tv_nsec = tv->tv_usec * 1000; + time_adjust = 0; /* stop active adjtime() */ + time_status |= STA_UNSYNC; + time_maxerror = NTP_PHASE_LIMIT; + time_esterror = NTP_PHASE_LIMIT; + write_sequnlock_irq(&xtime_lock); +} + +static irqreturn_t timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + do_timer(regs); + do_set_rtc(); //FIME - EVERY timer IRQ? + do_profile(regs); + return IRQ_HANDLED; //FIXME - is this right? +} + +static struct irqaction timer_irq = { + .name = "timer", + .flags = SA_INTERRUPT, + .handler = timer_interrupt, +}; + +extern void ioctime_init(void); + +/* + * Set up timer interrupt. + */ +void __init time_init(void) +{ + ioctime_init(); + + setup_irq(IRQ_TIMER, &timer_irq); +} + diff -Nru a/arch/arm26/kernel/traps.c b/arch/arm26/kernel/traps.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/kernel/traps.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,553 @@ +/* + * linux/arch/arm/kernel/traps.c + * + * Copyright (C) 1995-2002 Russell King + * Fragments that appear the same as linux/arch/i386/kernel/traps.c (C) Linus Torvalds + * Copyright (C) 2003 Ian Molton (ARM26) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 'traps.c' handles hardware exceptions after we have saved some state in + * 'linux/arch/arm/lib/traps.S'. Mostly a debugging aid, but will probably + * kill the offending process. + */ +#include <linux/config.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/spinlock.h> +#include <linux/personality.h> +#include <linux/ptrace.h> +#include <linux/elf.h> +#include <linux/interrupt.h> +#include <linux/init.h> + +#include <asm/atomic.h> +#include <asm/io.h> +#include <asm/pgalloc.h> +#include <asm/pgtable.h> +#include <asm/system.h> +#include <asm/uaccess.h> +#include <asm/unistd.h> +#include <asm/semaphore.h> + +#include "ptrace.h" + +extern void c_backtrace (unsigned long fp, int pmode); +extern void show_pte(struct mm_struct *mm, unsigned long addr); + +const char *processor_modes[] = { "USER_26", "FIQ_26" , "IRQ_26" , "SVC_26" }; + +static const char *handler[]= { "prefetch abort", "data abort", "address exception", "interrupt" "*bad reason*"}; + +/* + * Stack pointers should always be within the kernels view of + * physical memory. If it is not there, then we can't dump + * out any information relating to the stack. + */ +static int verify_stack(unsigned long sp) +{ + if (sp < PAGE_OFFSET || (sp > (unsigned long)high_memory && high_memory != 0)) + return -EFAULT; + + return 0; +} + +/* + * Dump out the contents of some memory nicely... + */ +static void dump_mem(const char *str, unsigned long bottom, unsigned long top) +{ + unsigned long p = bottom & ~31; + mm_segment_t fs; + int i; + + /* + * We need to switch to kernel mode so that we can use __get_user + * to safely read from kernel space. Note that we now dump the + * code first, just in case the backtrace kills us. + */ + fs = get_fs(); + set_fs(KERNEL_DS); + + printk("%s", str); + printk("(0x%08lx to 0x%08lx)\n", bottom, top); + + for (p = bottom & ~31; p < top;) { + printk("%04lx: ", p & 0xffff); + + for (i = 0; i < 8; i++, p += 4) { + unsigned int val; + + if (p < bottom || p >= top) + printk(" "); + else { + __get_user(val, (unsigned long *)p); + printk("%08x ", val); + } + } + printk ("\n"); + } + + set_fs(fs); +} + +static void dump_instr(struct pt_regs *regs) +{ + unsigned long addr = instruction_pointer(regs); + const int width = 8; + mm_segment_t fs; + int i; + + /* + * We need to switch to kernel mode so that we can use __get_user + * to safely read from kernel space. Note that we now dump the + * code first, just in case the backtrace kills us. + */ + fs = get_fs(); + set_fs(KERNEL_DS); + + printk("Code: "); + for (i = -4; i < 1; i++) { + unsigned int val, bad; + + bad = __get_user(val, &((u32 *)addr)[i]); + + if (!bad) + printk(i == 0 ? "(%0*x) " : "%0*x ", width, val); + else { + printk("bad PC value."); + break; + } + } + printk("\n"); + + set_fs(fs); +} + +/*static*/ void __dump_stack(struct task_struct *tsk, unsigned long sp) +{ + dump_mem("Stack: ", sp, 8192+(unsigned long)tsk->thread_info); +} + +void dump_stack(void) +{ +#ifdef CONFIG_DEBUG_ERRORS + __backtrace(); +#endif +} + +//FIXME - was a static fn +void dump_backtrace(struct pt_regs *regs, struct task_struct *tsk) +{ + unsigned int fp; + int ok = 1; + + printk("Backtrace: "); + fp = regs->ARM_fp; + if (!fp) { + printk("no frame pointer"); + ok = 0; + } else if (verify_stack(fp)) { + printk("invalid frame pointer 0x%08x", fp); + ok = 0; + } else if (fp < (unsigned long)(tsk->thread_info + 1)) + printk("frame pointer underflow"); + printk("\n"); + + if (ok) + c_backtrace(fp, processor_mode(regs)); +} + +/* + * This is called from SysRq-T (show_task) to display the current + * call trace for each process. Very useful. + */ +void show_trace_task(struct task_struct *tsk) +{ + if (tsk != current) { + unsigned int fp = thread_saved_fp(tsk); + c_backtrace(fp, 0x10); + } +} + +spinlock_t die_lock = SPIN_LOCK_UNLOCKED; + +/* + * This function is protected against re-entrancy. + */ +NORET_TYPE void die(const char *str, struct pt_regs *regs, int err) +{ + struct task_struct *tsk = current; + + console_verbose(); + spin_lock_irq(&die_lock); + + printk("Internal error: %s: %x\n", str, err); + printk("CPU: %d\n", smp_processor_id()); + show_regs(regs); + printk("Process %s (pid: %d, stack limit = 0x%p)\n", + current->comm, current->pid, tsk->thread_info + 1); + + if (!user_mode(regs) || in_interrupt()) { + __dump_stack(tsk, (unsigned long)(regs + 1)); + dump_backtrace(regs, tsk); + dump_instr(regs); + } +while(1); + spin_unlock_irq(&die_lock); + do_exit(SIGSEGV); +} + +void die_if_kernel(const char *str, struct pt_regs *regs, int err) +{ + if (user_mode(regs)) + return; + + die(str, regs, err); +} + +static DECLARE_MUTEX(undef_sem); +static int (*undef_hook)(struct pt_regs *); + +int request_undef_hook(int (*fn)(struct pt_regs *)) +{ + int ret = -EBUSY; + + down(&undef_sem); + if (undef_hook == NULL) { + undef_hook = fn; + ret = 0; + } + up(&undef_sem); + + return ret; +} + +int release_undef_hook(int (*fn)(struct pt_regs *)) +{ + int ret = -EINVAL; + + down(&undef_sem); + if (undef_hook == fn) { + undef_hook = NULL; + ret = 0; + } + up(&undef_sem); + + return ret; +} + +static int undefined_extension(struct pt_regs *regs, unsigned int op) +{ + switch (op) { + case 1: /* 0xde01 / 0x?7f001f0 */ + ptrace_break(current, regs); + return 0; + } + return 1; +} + +asmlinkage void do_undefinstr(struct pt_regs *regs) +{ + siginfo_t info; + void *pc; + + regs->ARM_pc -= 4; + + pc = (unsigned long *)instruction_pointer(regs); /* strip PSR */ + + if (user_mode(regs)) { + u32 instr; + + get_user(instr, (u32 *)pc); + + if ((instr & 0x0fff00ff) == 0x07f000f0 && + undefined_extension(regs, (instr >> 8) & 255) == 0) { + regs->ARM_pc += 4; + return; + } + } else { + if (undef_hook && undef_hook(regs) == 0) { + regs->ARM_pc += 4; + return; + } + } + +#ifdef CONFIG_DEBUG_USER + printk(KERN_INFO "%s (%d): undefined instruction: pc=%p\n", + current->comm, current->pid, pc); + dump_instr(regs); +#endif + + current->thread.error_code = 0; + current->thread.trap_no = 6; + + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_code = ILL_ILLOPC; + info.si_addr = pc; + + force_sig_info(SIGILL, &info, current); + + die_if_kernel("Oops - undefined instruction", regs, 0); +} + +asmlinkage void do_excpt(unsigned long address, struct pt_regs *regs, int mode) +{ + siginfo_t info; + +#ifdef CONFIG_DEBUG_USER + printk(KERN_INFO "%s (%d): address exception: pc=%08lx\n", + current->comm, current->pid, instruction_pointer(regs)); + dump_instr(regs); +#endif + + current->thread.error_code = 0; + current->thread.trap_no = 11; + + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_ADRERR; + info.si_addr = (void *)address; + + force_sig_info(SIGBUS, &info, current); + + die_if_kernel("Oops - address exception", regs, mode); +} + +asmlinkage void do_unexp_fiq (struct pt_regs *regs) +{ +#ifndef CONFIG_IGNORE_FIQ + printk("Hmm. Unexpected FIQ received, but trying to continue\n"); + printk("You may have a hardware problem...\n"); +#endif +} + +/* + * bad_mode handles the impossible case in the vectors. If you see one of + * these, then it's extremely serious, and could mean you have buggy hardware. + * It never returns, and never tries to sync. We hope that we can at least + * dump out some state information... + */ +asmlinkage void bad_mode(struct pt_regs *regs, int reason, int proc_mode) +{ + unsigned int vectors = vectors_base(); + + console_verbose(); + + printk(KERN_CRIT "Bad mode in %s handler detected: mode %s\n", + handler[reason<5?reason:4], processor_modes[proc_mode]); + + /* + * Dump out the vectors and stub routines. Maybe a better solution + * would be to dump them out only if we detect that they are corrupted. + */ + dump_mem(KERN_CRIT "Vectors: ", vectors, vectors + 0x40); + dump_mem(KERN_CRIT "Stubs: ", vectors + 0x200, vectors + 0x4b8); + + die("Oops", regs, 0); + local_irq_disable(); + panic("bad mode"); +} + +static int bad_syscall(int n, struct pt_regs *regs) +{ + struct thread_info *thread = current_thread_info(); + siginfo_t info; + + if (current->personality != PER_LINUX && thread->exec_domain->handler) { + thread->exec_domain->handler(n, regs); + return regs->ARM_r0; + } + +#ifdef CONFIG_DEBUG_USER + printk(KERN_ERR "[%d] %s: obsolete system call %08x.\n", + current->pid, current->comm, n); + dump_instr(regs); +#endif + + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_code = ILL_ILLTRP; + info.si_addr = (void *)instruction_pointer(regs) - 4; + + force_sig_info(SIGILL, &info, current); + die_if_kernel("Oops", regs, n); + return regs->ARM_r0; +} + +static inline void +do_cache_op(unsigned long start, unsigned long end, int flags) +{ + struct vm_area_struct *vma; + + if (end < start) + return; + + vma = find_vma(current->active_mm, start); + if (vma && vma->vm_start < end) { + if (start < vma->vm_start) + start = vma->vm_start; + if (end > vma->vm_end) + end = vma->vm_end; + } +} + +/* + * Handle all unrecognised system calls. + * 0x9f0000 - 0x9fffff are some more esoteric system calls + */ +#define NR(x) ((__ARM_NR_##x) - __ARM_NR_BASE) +asmlinkage int arm_syscall(int no, struct pt_regs *regs) +{ + siginfo_t info; + + if ((no >> 16) != 0x9f) + return bad_syscall(no, regs); + + switch (no & 0xffff) { + case 0: /* branch through 0 */ + info.si_signo = SIGSEGV; + info.si_errno = 0; + info.si_code = SEGV_MAPERR; + info.si_addr = NULL; + + force_sig_info(SIGSEGV, &info, current); + + die_if_kernel("branch through zero", regs, 0); + return 0; + + case NR(breakpoint): /* SWI BREAK_POINT */ + ptrace_break(current, regs); + return regs->ARM_r0; + + case NR(cacheflush): + return 0; + + case NR(usr26): + case NR(usr32): + break; + + default: + /* Calls 9f00xx..9f07ff are defined to return -ENOSYS + if not implemented, rather than raising SIGILL. This + way the calling program can gracefully determine whether + a feature is supported. */ + if (no <= 0x7ff) + return -ENOSYS; + break; + } +#ifdef CONFIG_DEBUG_USER + /* + * experience shows that these seem to indicate that + * something catastrophic has happened + */ + printk("[%d] %s: arm syscall %d\n", current->pid, current->comm, no); + dump_instr(regs); + if (user_mode(regs)) { + show_regs(regs); + c_backtrace(regs->ARM_fp, processor_mode(regs)); + } +#endif + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_code = ILL_ILLTRP; + info.si_addr = (void *)instruction_pointer(regs) - 4; + + force_sig_info(SIGILL, &info, current); + die_if_kernel("Oops", regs, no); + return 0; +} + +void __bad_xchg(volatile void *ptr, int size) +{ + printk("xchg: bad data size: pc 0x%p, ptr 0x%p, size %d\n", + __builtin_return_address(0), ptr, size); + BUG(); +} + +/* + * A data abort trap was taken, but we did not handle the instruction. + * Try to abort the user program, or panic if it was the kernel. + */ +asmlinkage void +baddataabort(int code, unsigned long instr, struct pt_regs *regs) +{ + unsigned long addr = instruction_pointer(regs); + siginfo_t info; + +#ifdef CONFIG_DEBUG_USER + printk(KERN_ERR "[%d] %s: bad data abort: code %d instr 0x%08lx\n", + current->pid, current->comm, code, instr); + dump_instr(regs); + show_pte(current->mm, addr); +#endif + + info.si_signo = SIGILL; + info.si_errno = 0; + info.si_code = ILL_ILLOPC; + info.si_addr = (void *)addr; + + force_sig_info(SIGILL, &info, current); + die_if_kernel("unknown data abort code", regs, instr); +} + +void __bug(const char *file, int line, void *data) +{ + printk(KERN_CRIT"kernel BUG at %s:%d!", file, line); + if (data) + printk(KERN_CRIT" - extra data = %p", data); + printk("\n"); + *(int *)0 = 0; +} + +void __readwrite_bug(const char *fn) +{ + printk("%s called, but not implemented", fn); + BUG(); +} + +void __pte_error(const char *file, int line, unsigned long val) +{ + printk("%s:%d: bad pte %08lx.\n", file, line, val); +} + +void __pmd_error(const char *file, int line, unsigned long val) +{ + printk("%s:%d: bad pmd %08lx.\n", file, line, val); +} + +void __pgd_error(const char *file, int line, unsigned long val) +{ + printk("%s:%d: bad pgd %08lx.\n", file, line, val); +} + +asmlinkage void __div0(void) +{ + printk("Division by zero in kernel.\n"); + dump_stack(); +} + +void abort(void) +{ + BUG(); + + /* if that doesn't kill us, halt */ + panic("Oops failed to kill thread"); +} + +void __init trap_init(void) +{ + extern void __trap_init(unsigned long); + unsigned long base = vectors_base(); + + __trap_init(base); + if (base != 0) + printk(KERN_DEBUG "Relocating machine vectors to 0x%08lx\n", + base); +} diff -Nru a/arch/arm26/lib/Makefile b/arch/arm26/lib/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/Makefile Mon Jun 9 23:16:20 2003 @@ -0,0 +1,31 @@ +# +# linux/arch/arm/lib/Makefile +# +# Copyright (C) 1995-2000 Russell King +# + +L_TARGET := lib.a + +obj-y := backtrace.o changebit.o csumipv6.o csumpartial.o \ + csumpartialcopy.o csumpartialcopyuser.o clearbit.o \ + copy_page.o delay.o findbit.o memchr.o memcpy.o \ + memset.o memzero.o setbit.o \ + strchr.o strrchr.o testchangebit.o \ + testclearbit.o testsetbit.o getuser.o \ + putuser.o ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \ + ucmpdi2.o udivdi3.o lib1funcs.o ecard.o io-acorn.o \ + floppydma.o io-readsb.o io-writesb.o io-writesl.o \ + uaccess-kernel.o uaccess-user.o io-readsw-armv3.o \ + io-writesw-armv3.o io-readsl-armv3.o + +obj-m := +obj-n := + +obj-$(CONFIG_VT)+= kbd.o + +obj-y += ecard.o io-acorn.o floppydma.o + + +csumpartialcopy.o: csumpartialcopygeneric.S +csumpartialcopyuser.o: csumpartialcopygeneric.S + diff -Nru a/arch/arm26/lib/ashldi3.c b/arch/arm26/lib/ashldi3.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/ashldi3.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,61 @@ +/* More subroutines needed by GCC output code on some machines. */ +/* Compile this one with gcc. */ +/* 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. */ + +/* As a special exception, if you link this library with other files, + some of which are compiled with GCC, to produce an executable, + this library does not by itself cause the resulting executable + to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. + */ +/* support functions required by the kernel. based on code from gcc-2.95.3 */ +/* I Molton 29/07/01 */ + +#include "gcclib.h" + +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 -Nru a/arch/arm26/lib/ashrdi3.c b/arch/arm26/lib/ashrdi3.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/ashrdi3.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,61 @@ +/* More subroutines needed by GCC output code on some machines. */ +/* Compile this one with gcc. */ +/* 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. */ + +/* As a special exception, if you link this library with other files, + some of which are compiled with GCC, to produce an executable, + this library does not by itself cause the resulting executable + to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. + */ +/* support functions required by the kernel. based on code from gcc-2.95.3 */ +/* I Molton 29/07/01 */ + +#include "gcclib.h" + +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 -Nru a/arch/arm26/lib/backtrace.S b/arch/arm26/lib/backtrace.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/backtrace.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,145 @@ +/* + * linux/arch/arm/lib/backtrace.S + * + * Copyright (C) 1995, 1996 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/config.h> +#include <linux/linkage.h> +#include <asm/assembler.h> + .text + +@ fp is 0 or stack frame + +#define frame r4 +#define next r5 +#define save r6 +#define mask r7 +#define offset r8 + +ENTRY(__backtrace) + mov r1, #0x10 + mov r0, fp + +ENTRY(c_backtrace) + +#ifdef CONFIG_NO_FRAME_POINTER + mov pc, lr +#else + + stmfd sp!, {r4 - r8, lr} @ Save an extra register so we have a location... + mov mask, #0xfc000003 + tst mask, r0 + movne r0, #0 + movs frame, r0 +1: moveq r0, #-2 + LOADREGS(eqfd, sp!, {r4 - r8, pc}) + +2: stmfd sp!, {pc} @ calculate offset of PC in STMIA instruction + ldr r0, [sp], #4 + adr r1, 2b - 4 + sub offset, r0, r1 + +3: tst frame, mask @ Check for address exceptions... + bne 1b + +1001: ldr next, [frame, #-12] @ get fp +1002: ldr r2, [frame, #-4] @ get lr +1003: ldr r3, [frame, #0] @ get pc + sub save, r3, offset @ Correct PC for prefetching + bic save, save, mask +1004: ldr r1, [save, #0] @ get instruction at function + mov r1, r1, lsr #10 + ldr r3, .Ldsi+4 + teq r1, r3 + subeq save, save, #4 + adr r0, .Lfe + mov r1, save + bic r2, r2, mask + bl printk @ print pc and link register + + ldr r0, [frame, #-8] @ get sp + sub r0, r0, #4 +1005: ldr r1, [save, #4] @ get instruction at function+4 + mov r3, r1, lsr #10 + ldr r2, .Ldsi+4 + teq r3, r2 @ Check for stmia sp!, {args} + addeq save, save, #4 @ next instruction + bleq .Ldumpstm + + sub r0, frame, #16 +1006: ldr r1, [save, #4] @ Get 'stmia sp!, {rlist, fp, ip, lr, pc}' instruction + mov r3, r1, lsr #10 + ldr r2, .Ldsi + teq r3, r2 + bleq .Ldumpstm + + teq frame, next + movne frame, next + teqne frame, #0 + bne 3b + LOADREGS(fd, sp!, {r4 - r8, pc}) + +/* + * Fixup for LDMDB + */ + .section .fixup,"ax" + .align 0 +1007: ldr r0, =.Lbad + mov r1, frame + bl printk + LOADREGS(fd, sp!, {r4 - r8, pc}) + .ltorg + .previous + + .section __ex_table,"a" + .align 3 + .long 1001b, 1007b + .long 1002b, 1007b + .long 1003b, 1007b + .long 1004b, 1007b + .long 1005b, 1007b + .long 1006b, 1007b + .previous + +#define instr r4 +#define reg r5 +#define stack r6 + +.Ldumpstm: stmfd sp!, {instr, reg, stack, r7, lr} + mov stack, r0 + mov instr, r1 + mov reg, #9 + mov r7, #0 +1: mov r3, #1 + tst instr, r3, lsl reg + beq 2f + add r7, r7, #1 + teq r7, #4 + moveq r7, #0 + moveq r3, #'\n' + movne r3, #' ' + ldr r2, [stack], #-4 + mov r1, reg + adr r0, .Lfp + bl printk +2: subs reg, reg, #1 + bpl 1b + teq r7, #0 + adrne r0, .Lcr + blne printk + mov r0, stack + LOADREGS(fd, sp!, {instr, reg, stack, r7, pc}) + +.Lfe: .asciz "Function entered at [<%p>] from [<%p>]\n" +.Lfp: .asciz " r%d = %08X%c" +.Lcr: .asciz "\n" +.Lbad: .asciz "Backtrace aborted due to bad frame pointer <%p>\n" + .align +.Ldsi: .word 0x00e92dd8 >> 2 + .word 0x00e92d00 >> 2 + +#endif diff -Nru a/arch/arm26/lib/changebit.S b/arch/arm26/lib/changebit.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/changebit.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,28 @@ +/* + * linux/arch/arm/lib/changebit.S + * + * Copyright (C) 1995-1996 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> + .text + +/* Purpose : Function to change a bit + * Prototype: int change_bit(int bit, void *addr) + */ +ENTRY(_change_bit_be) + eor r0, r0, #0x18 @ big endian byte ordering +ENTRY(_change_bit_le) + and r2, r0, #7 + mov r3, #1 + mov r3, r3, lsl r2 + save_and_disable_irqs ip, r2 + ldrb r2, [r1, r0, lsr #3] + eor r2, r2, r3 + strb r2, [r1, r0, lsr #3] + restore_irqs ip + RETINSTR(mov,pc,lr) diff -Nru a/arch/arm26/lib/clearbit.S b/arch/arm26/lib/clearbit.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/clearbit.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,31 @@ +/* + * linux/arch/arm/lib/clearbit.S + * + * Copyright (C) 1995-1996 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> + .text + +/* + * Purpose : Function to clear a bit + * Prototype: int clear_bit(int bit, void *addr) + */ +ENTRY(_clear_bit_be) + eor r0, r0, #0x18 @ big endian byte ordering +ENTRY(_clear_bit_le) + and r2, r0, #7 + mov r3, #1 + mov r3, r3, lsl r2 + save_and_disable_irqs ip, r2 + ldrb r2, [r1, r0, lsr #3] + bic r2, r2, r3 + strb r2, [r1, r0, lsr #3] + restore_irqs ip + RETINSTR(mov,pc,lr) + + diff -Nru a/arch/arm26/lib/copy_page.S b/arch/arm26/lib/copy_page.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/copy_page.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,62 @@ +/* + * linux/arch/arm/lib/copypage.S + * + * Copyright (C) 1995-1999 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ASM optimised string functions + */ +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/asm_offsets.h> + + .text + .align 5 +/* + * ARMv3 optimised copy_user_page + * + * FIXME: rmk do we need to handle cache stuff... + * FIXME: im is this right on ARM26? + */ +ENTRY(__copy_user_page) + stmfd sp!, {r4, lr} @ 2 + mov r2, #PAGE_SZ/64 @ 1 + ldmia r1!, {r3, r4, ip, lr} @ 4+1 +1: stmia r0!, {r3, r4, ip, lr} @ 4 + ldmia r1!, {r3, r4, ip, lr} @ 4+1 + stmia r0!, {r3, r4, ip, lr} @ 4 + ldmia r1!, {r3, r4, ip, lr} @ 4+1 + stmia r0!, {r3, r4, ip, lr} @ 4 + ldmia r1!, {r3, r4, ip, lr} @ 4 + subs r2, r2, #1 @ 1 + stmia r0!, {r3, r4, ip, lr} @ 4 + ldmneia r1!, {r3, r4, ip, lr} @ 4 + bne 1b @ 1 + LOADREGS(fd, sp!, {r4, pc}) @ 3 + + .align 5 +/* + * ARMv3 optimised clear_user_page + * + * FIXME: rmk do we need to handle cache stuff... + */ +ENTRY(__clear_user_page) + str lr, [sp, #-4]! + mov r1, #PAGE_SZ/64 @ 1 + mov r2, #0 @ 1 + mov r3, #0 @ 1 + mov ip, #0 @ 1 + mov lr, #0 @ 1 +1: stmia r0!, {r2, r3, ip, lr} @ 4 + stmia r0!, {r2, r3, ip, lr} @ 4 + stmia r0!, {r2, r3, ip, lr} @ 4 + stmia r0!, {r2, r3, ip, lr} @ 4 + subs r1, r1, #1 @ 1 + bne 1b @ 1 + ldr pc, [sp], #4 + + .section ".init.text", #alloc, #execinstr + diff -Nru a/arch/arm26/lib/csumipv6.S b/arch/arm26/lib/csumipv6.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/csumipv6.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,32 @@ +/* + * linux/arch/arm/lib/csumipv6.S + * + * Copyright (C) 1995-1998 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> + + .text + +ENTRY(__csum_ipv6_magic) + str lr, [sp, #-4]! + adds ip, r2, r3 + ldmia r1, {r1 - r3, lr} + adcs ip, ip, r1 + adcs ip, ip, r2 + adcs ip, ip, r3 + adcs ip, ip, lr + ldmia r0, {r0 - r3} + adcs r0, ip, r0 + adcs r0, r0, r1 + adcs r0, r0, r2 + ldr r2, [sp, #4] + adcs r0, r0, r3 + adcs r0, r0, r2 + adcs r0, r0, #0 + LOADREGS(fd, sp!, {pc}) + diff -Nru a/arch/arm26/lib/csumpartial.S b/arch/arm26/lib/csumpartial.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/csumpartial.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,130 @@ +/* + * linux/arch/arm/lib/csumpartial.S + * + * Copyright (C) 1995-1998 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> + + .text + +/* + * Function: __u32 csum_partial(const char *src, int len, __u32 sum) + * Params : r0 = buffer, r1 = len, r2 = checksum + * Returns : r0 = new checksum + */ + +buf .req r0 +len .req r1 +sum .req r2 +td0 .req r3 +td1 .req r4 @ save before use +td2 .req r5 @ save before use +td3 .req lr + +.zero: mov r0, sum + add sp, sp, #4 + ldr pc, [sp], #4 + + /* + * Handle 0 to 7 bytes, with any alignment of source and + * destination pointers. Note that when we get here, C = 0 + */ +.less8: teq len, #0 @ check for zero count + beq .zero + + /* we must have at least one byte. */ + tst buf, #1 @ odd address? + ldrneb td0, [buf], #1 + subne len, len, #1 + adcnes sum, sum, td0, lsl #byte(1) + +.less4: tst len, #6 + beq .less8_byte + + /* we are now half-word aligned */ + +.less8_wordlp: +#if __LINUX_ARM_ARCH__ >= 4 + ldrh td0, [buf], #2 + sub len, len, #2 +#else + ldrb td0, [buf], #1 + ldrb td3, [buf], #1 + sub len, len, #2 + orr td0, td0, td3, lsl #8 +#endif + adcs sum, sum, td0 + tst len, #6 + bne .less8_wordlp + +.less8_byte: tst len, #1 @ odd number of bytes + ldrneb td0, [buf], #1 @ include last byte + adcnes sum, sum, td0, lsl #byte(0) @ update checksum + +.done: adc r0, sum, #0 @ collect up the last carry + ldr td0, [sp], #4 + tst td0, #1 @ check buffer alignment + movne td0, r0, lsl #8 @ rotate checksum by 8 bits + orrne r0, td0, r0, lsr #24 + ldr pc, [sp], #4 @ return + +.not_aligned: tst buf, #1 @ odd address + ldrneb td0, [buf], #1 @ make even + subne len, len, #1 + adcnes sum, sum, td0, lsl #byte(1) @ update checksum + + tst buf, #2 @ 32-bit aligned? +#if __LINUX_ARM_ARCH__ >= 4 + ldrneh td0, [buf], #2 @ make 32-bit aligned + subne len, len, #2 +#else + ldrneb td0, [buf], #1 + ldrneb ip, [buf], #1 + subne len, len, #2 + orrne td0, td0, ip, lsl #8 +#endif + adcnes sum, sum, td0 @ update checksum + mov pc, lr + +ENTRY(csum_partial) + stmfd sp!, {buf, lr} + cmp len, #8 @ Ensure that we have at least + blo .less8 @ 8 bytes to copy. + + adds sum, sum, #0 @ C = 0 + tst buf, #3 @ Test destination alignment + blne .not_aligned @ aligh destination, return here + +1: bics ip, len, #31 + beq 3f + + stmfd sp!, {r4 - r5} +2: ldmia buf!, {td0, td1, td2, td3} + adcs sum, sum, td0 + adcs sum, sum, td1 + adcs sum, sum, td2 + adcs sum, sum, td3 + ldmia buf!, {td0, td1, td2, td3} + adcs sum, sum, td0 + adcs sum, sum, td1 + adcs sum, sum, td2 + adcs sum, sum, td3 + sub ip, ip, #32 + teq ip, #0 + bne 2b + ldmfd sp!, {r4 - r5} + +3: tst len, #0x1c @ should not change C + beq .less4 + +4: ldr td0, [buf], #4 + sub len, len, #4 + adcs sum, sum, td0 + tst len, #0x1c + bne 4b + b .less4 diff -Nru a/arch/arm26/lib/csumpartialcopy.S b/arch/arm26/lib/csumpartialcopy.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/csumpartialcopy.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,52 @@ +/* + * linux/arch/arm/lib/csumpartialcopy.S + * + * Copyright (C) 1995-1998 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> + + .text + +/* Function: __u32 csum_partial_copy_nocheck(const char *src, char *dst, int len, __u32 sum) + * Params : r0 = src, r1 = dst, r2 = len, r3 = checksum + * Returns : r0 = new checksum + */ + + .macro save_regs + stmfd sp!, {r1, r4 - r8, fp, ip, lr, pc} + .endm + + .macro load_regs,flags + LOADREGS(\flags,fp,{r1, r4 - r8, fp, sp, pc}) + .endm + + .macro load1b, reg1 + ldrb \reg1, [r0], #1 + .endm + + .macro load2b, reg1, reg2 + ldrb \reg1, [r0], #1 + ldrb \reg2, [r0], #1 + .endm + + .macro load1l, reg1 + ldr \reg1, [r0], #4 + .endm + + .macro load2l, reg1, reg2 + ldr \reg1, [r0], #4 + ldr \reg2, [r0], #4 + .endm + + .macro load4l, reg1, reg2, reg3, reg4 + ldmia r0!, {\reg1, \reg2, \reg3, \reg4} + .endm + +#define FN_ENTRY ENTRY(csum_partial_copy_nocheck) + +#include "csumpartialcopygeneric.S" diff -Nru a/arch/arm26/lib/csumpartialcopygeneric.S b/arch/arm26/lib/csumpartialcopygeneric.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/csumpartialcopygeneric.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,352 @@ +/* + * linux/arch/arm/lib/csumpartialcopygeneric.S + * + * Copyright (C) 1995-2001 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * JMA 01/06/03 Commented out some shl0s; probobly irrelevant to arm26 + * + */ + +/* + * unsigned int + * csum_partial_copy_xxx(const char *src, char *dst, int len, int sum, ) + * r0 = src, r1 = dst, r2 = len, r3 = sum + * Returns : r0 = checksum + * + * Note that 'tst' and 'teq' preserve the carry flag. + */ + +/* Quick hack */ + .macro save_regs + stmfd sp!, {r1, r4 - r8, fp, ip, lr, pc} + .endm + +/* end Quick Hack */ + +src .req r0 +dst .req r1 +len .req r2 +sum .req r3 + +.zero: mov r0, sum + load_regs ea + + /* + * Align an unaligned destination pointer. We know that + * we have >= 8 bytes here, so we don't need to check + * the length. Note that the source pointer hasn't been + * aligned yet. + */ +.dst_unaligned: tst dst, #1 + beq .dst_16bit + + load1b ip + sub len, len, #1 + adcs sum, sum, ip, lsl #byte(1) @ update checksum + strb ip, [dst], #1 + tst dst, #2 + moveq pc, lr @ dst is now 32bit aligned + +.dst_16bit: load2b r8, ip + sub len, len, #2 + adcs sum, sum, r8, lsl #byte(0) + strb r8, [dst], #1 + adcs sum, sum, ip, lsl #byte(1) + strb ip, [dst], #1 + mov pc, lr @ dst is now 32bit aligned + + /* + * Handle 0 to 7 bytes, with any alignment of source and + * destination pointers. Note that when we get here, C = 0 + */ +.less8: teq len, #0 @ check for zero count + beq .zero + + /* we must have at least one byte. */ + tst dst, #1 @ dst 16-bit aligned + beq .less8_aligned + + /* Align dst */ + load1b ip + sub len, len, #1 + adcs sum, sum, ip, lsl #byte(1) @ update checksum + strb ip, [dst], #1 + tst len, #6 + beq .less8_byteonly + +1: load2b r8, ip + sub len, len, #2 + adcs sum, sum, r8, lsl #byte(0) + strb r8, [dst], #1 + adcs sum, sum, ip, lsl #byte(1) + strb ip, [dst], #1 +.less8_aligned: tst len, #6 + bne 1b +.less8_byteonly: + tst len, #1 + beq .done + load1b r8 + adcs sum, sum, r8, lsl #byte(0) @ update checksum + strb r8, [dst], #1 + b .done + +FN_ENTRY + mov ip, sp + save_regs + sub fp, ip, #4 + + cmp len, #8 @ Ensure that we have at least + blo .less8 @ 8 bytes to copy. + + adds sum, sum, #0 @ C = 0 + tst dst, #3 @ Test destination alignment + blne .dst_unaligned @ align destination, return here + + /* + * Ok, the dst pointer is now 32bit aligned, and we know + * that we must have more than 4 bytes to copy. Note + * that C contains the carry from the dst alignment above. + */ + + tst src, #3 @ Test source alignment + bne .src_not_aligned + + /* Routine for src & dst aligned */ + + bics ip, len, #15 + beq 2f + +1: load4l r4, r5, r6, r7 + stmia dst!, {r4, r5, r6, r7} + adcs sum, sum, r4 + adcs sum, sum, r5 + adcs sum, sum, r6 + adcs sum, sum, r7 + sub ip, ip, #16 + teq ip, #0 + bne 1b + +2: ands ip, len, #12 + beq 4f + tst ip, #8 + beq 3f + load2l r4, r5 + stmia dst!, {r4, r5} + adcs sum, sum, r4 + adcs sum, sum, r5 + tst ip, #4 + beq 4f + +3: load1l r4 + str r4, [dst], #4 + adcs sum, sum, r4 + +4: ands len, len, #3 + beq .done + load1l r4 + tst len, #2 +/* mov r5, r4, lsr #byte(0) +FIXME? 0 Shift anyhow! +*/ + beq .exit + adcs sum, sum, r4, push #16 + strb r5, [dst], #1 + mov r5, r4, lsr #byte(1) + strb r5, [dst], #1 + mov r5, r4, lsr #byte(2) +.exit: tst len, #1 + strneb r5, [dst], #1 + andne r5, r5, #255 + adcnes sum, sum, r5, lsl #byte(0) + + /* + * If the dst pointer was not 16-bit aligned, we + * need to rotate the checksum here to get around + * the inefficient byte manipulations in the + * architecture independent code. + */ +.done: adc r0, sum, #0 + ldr sum, [sp, #0] @ dst + tst sum, #1 + movne sum, r0, lsl #8 + orrne r0, sum, r0, lsr #24 + load_regs ea + +.src_not_aligned: + adc sum, sum, #0 @ include C from dst alignment + and ip, src, #3 + bic src, src, #3 + load1l r5 + cmp ip, #2 + beq .src2_aligned + bhi .src3_aligned + mov r4, r5, pull #8 @ C = 0 + bics ip, len, #15 + beq 2f +1: load4l r5, r6, r7, r8 + orr r4, r4, r5, push #24 + mov r5, r5, pull #8 + orr r5, r5, r6, push #24 + mov r6, r6, pull #8 + orr r6, r6, r7, push #24 + mov r7, r7, pull #8 + orr r7, r7, r8, push #24 + stmia dst!, {r4, r5, r6, r7} + adcs sum, sum, r4 + adcs sum, sum, r5 + adcs sum, sum, r6 + adcs sum, sum, r7 + mov r4, r8, pull #8 + sub ip, ip, #16 + teq ip, #0 + bne 1b +2: ands ip, len, #12 + beq 4f + tst ip, #8 + beq 3f + load2l r5, r6 + orr r4, r4, r5, push #24 + mov r5, r5, pull #8 + orr r5, r5, r6, push #24 + stmia dst!, {r4, r5} + adcs sum, sum, r4 + adcs sum, sum, r5 + mov r4, r6, pull #8 + tst ip, #4 + beq 4f +3: load1l r5 + orr r4, r4, r5, push #24 + str r4, [dst], #4 + adcs sum, sum, r4 + mov r4, r5, pull #8 +4: ands len, len, #3 + beq .done +/* mov r5, r4, lsr #byte(0) +FIXME? 0 Shift anyhow +*/ + tst len, #2 + beq .exit + adcs sum, sum, r4, push #16 + strb r5, [dst], #1 + mov r5, r4, lsr #byte(1) + strb r5, [dst], #1 + mov r5, r4, lsr #byte(2) + b .exit + +.src2_aligned: mov r4, r5, pull #16 + adds sum, sum, #0 + bics ip, len, #15 + beq 2f +1: load4l r5, r6, r7, r8 + orr r4, r4, r5, push #16 + mov r5, r5, pull #16 + orr r5, r5, r6, push #16 + mov r6, r6, pull #16 + orr r6, r6, r7, push #16 + mov r7, r7, pull #16 + orr r7, r7, r8, push #16 + stmia dst!, {r4, r5, r6, r7} + adcs sum, sum, r4 + adcs sum, sum, r5 + adcs sum, sum, r6 + adcs sum, sum, r7 + mov r4, r8, pull #16 + sub ip, ip, #16 + teq ip, #0 + bne 1b +2: ands ip, len, #12 + beq 4f + tst ip, #8 + beq 3f + load2l r5, r6 + orr r4, r4, r5, push #16 + mov r5, r5, pull #16 + orr r5, r5, r6, push #16 + stmia dst!, {r4, r5} + adcs sum, sum, r4 + adcs sum, sum, r5 + mov r4, r6, pull #16 + tst ip, #4 + beq 4f +3: load1l r5 + orr r4, r4, r5, push #16 + str r4, [dst], #4 + adcs sum, sum, r4 + mov r4, r5, pull #16 +4: ands len, len, #3 + beq .done +/* mov r5, r4, lsr #byte(0) +FIXME? 0 Shift anyhow +*/ + tst len, #2 + beq .exit + adcs sum, sum, r4 + strb r5, [dst], #1 + mov r5, r4, lsr #byte(1) + strb r5, [dst], #1 + tst len, #1 + beq .done + load1b r5 + b .exit + +.src3_aligned: mov r4, r5, pull #24 + adds sum, sum, #0 + bics ip, len, #15 + beq 2f +1: load4l r5, r6, r7, r8 + orr r4, r4, r5, push #8 + mov r5, r5, pull #24 + orr r5, r5, r6, push #8 + mov r6, r6, pull #24 + orr r6, r6, r7, push #8 + mov r7, r7, pull #24 + orr r7, r7, r8, push #8 + stmia dst!, {r4, r5, r6, r7} + adcs sum, sum, r4 + adcs sum, sum, r5 + adcs sum, sum, r6 + adcs sum, sum, r7 + mov r4, r8, pull #24 + sub ip, ip, #16 + teq ip, #0 + bne 1b +2: ands ip, len, #12 + beq 4f + tst ip, #8 + beq 3f + load2l r5, r6 + orr r4, r4, r5, push #8 + mov r5, r5, pull #24 + orr r5, r5, r6, push #8 + stmia dst!, {r4, r5} + adcs sum, sum, r4 + adcs sum, sum, r5 + mov r4, r6, pull #24 + tst ip, #4 + beq 4f +3: load1l r5 + orr r4, r4, r5, push #8 + str r4, [dst], #4 + adcs sum, sum, r4 + mov r4, r5, pull #24 +4: ands len, len, #3 + beq .done +/* mov r5, r4, lsr #byte(0) +FIXME? 0 Shift anyhow +*/ + tst len, #2 + beq .exit + strb r5, [dst], #1 + adcs sum, sum, r4 + load1l r4 +/* mov r5, r4, lsr #byte(0) +FIXME? 0 Shift anyhow +*/ + strb r5, [dst], #1 + adcs sum, sum, r4, push #24 + mov r5, r4, lsr #byte(1) + b .exit diff -Nru a/arch/arm26/lib/csumpartialcopyuser.S b/arch/arm26/lib/csumpartialcopyuser.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/csumpartialcopyuser.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,115 @@ +/* + * linux/arch/arm26/lib/csumpartialcopyuser.S + * + * Copyright (C) 1995-1998 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/config.h> +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/errno.h> +#include <asm/asm_offsets.h> + + .text + + .macro save_regs + stmfd sp!, {r1 - r2, r4 - r9, fp, ip, lr, pc} + mov r9, sp, lsr #13 + mov r9, r9, lsl #13 + ldr r9, [r9, #TSK_ADDR_LIMIT] + mov r9, r9, lsr #24 + .endm + + .macro load_regs,flags + ldm\flags fp, {r1, r2, r4-r9, fp, sp, pc}^ + .endm + + .macro load1b, reg1 + tst r9, #0x01 +9999: ldreqbt \reg1, [r0], #1 + ldrneb \reg1, [r0], #1 + .section __ex_table, "a" + .align 3 + .long 9999b, 6001f + .previous + .endm + + .macro load2b, reg1, reg2 + tst r9, #0x01 +9999: ldreqbt \reg1, [r0], #1 + ldrneb \reg1, [r0], #1 +9998: ldreqbt \reg2, [r0], #1 + ldrneb \reg2, [r0], #1 + .section __ex_table, "a" + .long 9999b, 6001f + .long 9998b, 6001f + .previous + .endm + + .macro load1l, reg1 + tst r9, #0x01 +9999: ldreqt \reg1, [r0], #4 + ldrne \reg1, [r0], #4 + .section __ex_table, "a" + .align 3 + .long 9999b, 6001f + .previous + .endm + + .macro load2l, reg1, reg2 + tst r9, #0x01 + ldmneia r0!, {\reg1, \reg2} +9999: ldreqt \reg1, [r0], #4 +9998: ldreqt \reg2, [r0], #4 + .section __ex_table, "a" + .long 9999b, 6001f + .long 9998b, 6001f + .previous + .endm + + .macro load4l, reg1, reg2, reg3, reg4 + tst r9, #0x01 + ldmneia r0!, {\reg1, \reg2, \reg3, \reg4} +9999: ldreqt \reg1, [r0], #4 +9998: ldreqt \reg2, [r0], #4 +9997: ldreqt \reg3, [r0], #4 +9996: ldreqt \reg4, [r0], #4 + .section __ex_table, "a" + .long 9999b, 6001f + .long 9998b, 6001f + .long 9997b, 6001f + .long 9996b, 6001f + .previous + .endm + +/* + * unsigned int + * csum_partial_copy_from_user(const char *src, char *dst, int len, int sum, int *err_ptr) + * r0 = src, r1 = dst, r2 = len, r3 = sum, [sp] = *err_ptr + * Returns : r0 = checksum, [[sp, #0], #0] = 0 or -EFAULT + */ + +#define FN_ENTRY ENTRY(csum_partial_copy_from_user) + +#include "csumpartialcopygeneric.S" + +/* + * FIXME: minor buglet here + * We don't return the checksum for the data present in the buffer. To do + * so properly, we would have to add in whatever registers were loaded before + * the fault, which, with the current asm above is not predictable. + */ + .align 4 +6001: mov r4, #-EFAULT + ldr r5, [fp, #4] @ *err_ptr + str r4, [r5] + ldmia sp, {r1, r2} @ retrieve dst, len + add r2, r2, r1 + mov r0, #0 @ zero the buffer +6002: teq r2, r1 + strneb r0, [r1], #1 + bne 6002b + load_regs ea diff -Nru a/arch/arm26/lib/delay.S b/arch/arm26/lib/delay.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/delay.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,57 @@ +/* + * linux/arch/arm/lib/delay.S + * + * Copyright (C) 1995, 1996 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> + .text + +LC0: .word loops_per_jiffy + +/* + * 0 <= r0 <= 2000 + */ +ENTRY(udelay) + mov r2, #0x6800 + orr r2, r2, #0x00db + mul r1, r0, r2 + ldr r2, LC0 + ldr r2, [r2] + mov r1, r1, lsr #11 + mov r2, r2, lsr #11 + mul r0, r1, r2 + movs r0, r0, lsr #6 + RETINSTR(moveq,pc,lr) + +/* + * loops = (r0 * 0x10c6 * 100 * loops_per_jiffy) / 2^32 + * + * Oh, if only we had a cycle counter... + */ + +@ Delay routine +ENTRY(__delay) + subs r0, r0, #1 +#if 0 + RETINSTR(movls,pc,lr) + subs r0, r0, #1 + RETINSTR(movls,pc,lr) + subs r0, r0, #1 + RETINSTR(movls,pc,lr) + subs r0, r0, #1 + RETINSTR(movls,pc,lr) + subs r0, r0, #1 + RETINSTR(movls,pc,lr) + subs r0, r0, #1 + RETINSTR(movls,pc,lr) + subs r0, r0, #1 + RETINSTR(movls,pc,lr) + subs r0, r0, #1 +#endif + bhi __delay + RETINSTR(mov,pc,lr) diff -Nru a/arch/arm26/lib/ecard.S b/arch/arm26/lib/ecard.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/ecard.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,41 @@ +/* + * linux/arch/arm/lib/ecard.S + * + * Copyright (C) 1995, 1996 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/config.h> /* for CONFIG_CPU_nn */ +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/hardware.h> + +#define CPSR2SPSR(rt) + +@ Purpose: call an expansion card loader to read bytes. +@ Proto : char read_loader(int offset, char *card_base, char *loader); +@ Returns: byte read + +ENTRY(ecard_loader_read) + stmfd sp!, {r4 - r12, lr} + mov r11, r1 + mov r1, r0 + CPSR2SPSR(r0) + mov lr, pc + mov pc, r2 + LOADREGS(fd, sp!, {r4 - r12, pc}) + +@ Purpose: call an expansion card loader to reset the card +@ Proto : void read_loader(int card_base, char *loader); +@ Returns: byte read + +ENTRY(ecard_loader_reset) + stmfd sp!, {r4 - r12, lr} + mov r11, r0 + CPSR2SPSR(r0) + mov lr, pc + add pc, r1, #8 + LOADREGS(fd, sp!, {r4 - r12, pc}) + diff -Nru a/arch/arm26/lib/findbit.S b/arch/arm26/lib/findbit.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/findbit.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,67 @@ +/* + * linux/arch/arm/lib/findbit.S + * + * Copyright (C) 1995-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 16th March 2001 - John Ripley <jripley@sonicblue.com> + * Fixed so that "size" is an exclusive not an inclusive quantity. + * All users of these functions expect exclusive sizes, and may + * also call with zero size. + * Reworked by rmk. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> + .text + +/* + * Purpose : Find a 'zero' bit + * Prototype: int find_first_zero_bit(void *addr, unsigned int maxbit); + */ +ENTRY(_find_first_zero_bit_le) + teq r1, #0 + beq 3f + mov r2, #0 +1: ldrb r3, [r0, r2, lsr #3] + eors r3, r3, #0xff @ invert bits + bne .found @ any now set - found zero bit + add r2, r2, #8 @ next bit pointer +2: cmp r2, r1 @ any more? + blo 1b +3: mov r0, r1 @ no free bits + RETINSTR(mov,pc,lr) + +/* + * Purpose : Find next 'zero' bit + * Prototype: int find_next_zero_bit(void *addr, unsigned int maxbit, int offset) + */ +ENTRY(_find_next_zero_bit_le) + teq r1, #0 + beq 2b + ands ip, r2, #7 + beq 1b @ If new byte, goto old routine + ldrb r3, [r0, r2, lsr #3] + eor r3, r3, #0xff @ now looking for a 1 bit + movs r3, r3, lsr ip @ shift off unused bits + bne .found + orr r2, r2, #7 @ if zero, then no bits here + add r2, r2, #1 @ align bit pointer + b 2b @ loop for next bit + +/* + * One or more bits in the LSB of r3 are assumed to be set. + */ +.found: tst r3, #0x0f + addeq r2, r2, #4 + movne r3, r3, lsl #4 + tst r3, #0x30 + addeq r2, r2, #2 + movne r3, r3, lsl #2 + tst r3, #0x40 + addeq r2, r2, #1 + mov r0, r2 + RETINSTR(mov,pc,lr) + diff -Nru a/arch/arm26/lib/floppydma.S b/arch/arm26/lib/floppydma.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/floppydma.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,32 @@ +/* + * linux/arch/arm/lib/floppydma.S + * + * Copyright (C) 1995, 1996 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> + .text + + .global floppy_fiqin_end +ENTRY(floppy_fiqin_start) + subs r9, r9, #1 + ldrgtb r12, [r11, #-4] + ldrleb r12, [r11], #0 + strb r12, [r10], #1 + subs pc, lr, #4 +floppy_fiqin_end: + + .global floppy_fiqout_end +ENTRY(floppy_fiqout_start) + subs r9, r9, #1 + ldrgeb r12, [r10], #1 + movlt r12, #0 + strleb r12, [r11], #0 + subles pc, lr, #4 + strb r12, [r11, #-4] + subs pc, lr, #4 +floppy_fiqout_end: diff -Nru a/arch/arm26/lib/gcclib.h b/arch/arm26/lib/gcclib.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/gcclib.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,21 @@ +/* gcclib.h -- definitions for various functions 'borrowed' from gcc-2.95.3 */ +/* I Molton 29/07/01 */ + +#define BITS_PER_UNIT 8 +#define SI_TYPE_SIZE (sizeof (SItype) * BITS_PER_UNIT) + +typedef unsigned int UQItype __attribute__ ((mode (QI))); +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__))); +typedef unsigned int UDItype __attribute__ ((mode (DI))); + +struct DIstruct {SItype low, high;}; + +typedef union +{ + struct DIstruct s; + DItype ll; +} DIunion; + diff -Nru a/arch/arm26/lib/getuser.S b/arch/arm26/lib/getuser.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/getuser.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,111 @@ +/* + * linux/arch/arm/lib/getuser.S + * + * Copyright (C) 2001 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Idea from x86 version, (C) Copyright 1998 Linus Torvalds + * + * These functions have a non-standard call interface to make them more + * efficient, especially as they return an error value in addition to + * the "real" return value. + * + * __get_user_X + * + * Inputs: r0 contains the address + * Outputs: r0 is the error code + * r1, r2 contains the zero-extended value + * lr corrupted + * + * No other registers must be altered. (see include/asm-arm/uaccess.h + * for specific ASM register usage). + * + * Note that ADDR_LIMIT is either 0 or 0xc0000000. + * Note also that it is intended that __get_user_bad is not global. + */ +#include <asm/asm_offsets.h> +#include <asm/thread_info.h> + + .global __get_user_1 +__get_user_1: + bic r1, sp, #0x1f00 + bic r1, r1, #0x00ff + str lr, [sp, #-4]! + ldr r1, [r1, #TI_ADDR_LIMIT] + sub r1, r1, #1 + cmp r0, r1 + bge __get_user_bad + cmp r0, #0x02000000 +1: ldrlsbt r1, [r0] + ldrgeb r1, [r0] + mov r0, #0 + ldmfd sp!, {pc}^ + + .global __get_user_2 +__get_user_2: + bic r2, sp, #0x1f00 + bic r2, r2, #0x00ff + str lr, [sp, #-4]! + ldr r2, [r2, #TI_ADDR_LIMIT] + sub r2, r2, #2 + cmp r0, r2 + bge __get_user_bad + cmp r0, #0x02000000 +2: ldrlsbt r1, [r0], #1 +3: ldrlsbt r2, [r0] + ldrgeb r1, [r0], #1 + ldrgeb r2, [r0] + orr r1, r1, r2, lsl #8 + mov r0, #0 + ldmfd sp!, {pc}^ + + .global __get_user_4 +__get_user_4: + bic r1, sp, #0x1f00 + bic r1, r1, #0x00ff + str lr, [sp, #-4]! + ldr r1, [r1, #TI_ADDR_LIMIT] + sub r1, r1, #4 + cmp r0, r1 + bge __get_user_bad + cmp r0, #0x02000000 +4: ldrlst r1, [r0] + ldrge r1, [r0] + mov r0, #0 + ldmfd sp!, {pc}^ + + .global __get_user_8 +__get_user_8: + bic r2, sp, #0x1f00 + bic r2, r2, #0x00ff + str lr, [sp, #-4]! + ldr r2, [r2, #TI_ADDR_LIMIT] + sub r2, r2, #8 + cmp r0, r2 + bge __get_user_bad_8 + cmp r0, #0x02000000 +5: ldrlst r1, [r0], #4 +6: ldrlst r2, [r0] + ldrge r1, [r0], #4 + ldrge r2, [r0] + mov r0, #0 + ldmfd sp!, {pc}^ + +__get_user_bad_8: + mov r2, #0 +__get_user_bad: + mov r1, #0 + mov r0, #-14 + ldmfd sp!, {pc}^ + +.section __ex_table, "a" + .long 1b, __get_user_bad + .long 2b, __get_user_bad + .long 3b, __get_user_bad + .long 4b, __get_user_bad + .long 5b, __get_user_bad_8 + .long 6b, __get_user_bad_8 +.previous diff -Nru a/arch/arm26/lib/io-acorn.S b/arch/arm26/lib/io-acorn.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/io-acorn.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,71 @@ +/* + * linux/arch/arm/lib/io-acorn.S + * + * Copyright (C) 1995, 1996 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/config.h> /* for CONFIG_CPU_nn */ +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/hardware.h> + + .text + .align + + .equ diff_pcio_base, PCIO_BASE - IO_BASE + + .macro outw2 rd + mov r8, \rd, lsl #16 + orr r8, r8, r8, lsr #16 + str r8, [r3, r0, lsl #2] + mov r8, \rd, lsr #16 + orr r8, r8, r8, lsl #16 + str r8, [r3, r0, lsl #2] + .endm + + .macro inw2 rd, mask, temp + ldr \rd, [r0] + and \rd, \rd, \mask + ldr \temp, [r0] + orr \rd, \rd, \temp, lsl #16 + .endm + + .macro addr rd + tst \rd, #0x80000000 + mov \rd, \rd, lsl #2 + add \rd, \rd, #IO_BASE + addeq \rd, \rd, #diff_pcio_base + .endm + +.iosl_warning: + .ascii "<4>insl/outsl not implemented, called from %08lX\0" + .align + +/* + * These make no sense on Acorn machines. + * Print a warning message. + */ +ENTRY(insl) +ENTRY(outsl) + adr r0, .iosl_warning + mov r1, lr + b printk + +@ Purpose: write a memc register +@ Proto : void memc_write(int register, int value); +@ Returns: nothing + +ENTRY(memc_write) + cmp r0, #7 + RETINSTR(movgt,pc,lr) + mov r0, r0, lsl #17 + mov r1, r1, lsl #15 + mov r1, r1, lsr #17 + orr r0, r0, r1, lsl #2 + add r0, r0, #0x03600000 + strb r0, [r0] + RETINSTR(mov,pc,lr) + diff -Nru a/arch/arm26/lib/io-readsb.S b/arch/arm26/lib/io-readsb.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/io-readsb.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,116 @@ +/* + * linux/arch/arm/lib/io-readsb.S + * + * Copyright (C) 1995-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/hardware.h> + +.insb_align: rsb ip, ip, #4 + cmp ip, r2 + movgt ip, r2 + cmp ip, #2 + ldrb r3, [r0] + strb r3, [r1], #1 + ldrgeb r3, [r0] + strgeb r3, [r1], #1 + ldrgtb r3, [r0] + strgtb r3, [r1], #1 + subs r2, r2, ip + bne .insb_aligned + +ENTRY(__raw_readsb) + teq r2, #0 @ do we have to check for the zero len? + moveq pc, lr + ands ip, r1, #3 + bne .insb_align + +.insb_aligned: stmfd sp!, {r4 - r6, lr} + + subs r2, r2, #16 + bmi .insb_no_16 + +.insb_16_lp: ldrb r3, [r0] + ldrb r4, [r0] + orr r3, r3, r4, lsl #8 + ldrb r4, [r0] + orr r3, r3, r4, lsl #16 + ldrb r4, [r0] + orr r3, r3, r4, lsl #24 + ldrb r4, [r0] + ldrb r5, [r0] + orr r4, r4, r5, lsl #8 + ldrb r5, [r0] + orr r4, r4, r5, lsl #16 + ldrb r5, [r0] + orr r4, r4, r5, lsl #24 + ldrb r5, [r0] + ldrb r6, [r0] + orr r5, r5, r6, lsl #8 + ldrb r6, [r0] + orr r5, r5, r6, lsl #16 + ldrb r6, [r0] + orr r5, r5, r6, lsl #24 + ldrb r6, [r0] + ldrb ip, [r0] + orr r6, r6, ip, lsl #8 + ldrb ip, [r0] + orr r6, r6, ip, lsl #16 + ldrb ip, [r0] + orr r6, r6, ip, lsl #24 + stmia r1!, {r3 - r6} + + subs r2, r2, #16 + bpl .insb_16_lp + + tst r2, #15 + LOADREGS(eqfd, sp!, {r4 - r6, pc}) + +.insb_no_16: tst r2, #8 + beq .insb_no_8 + + ldrb r3, [r0] + ldrb r4, [r0] + orr r3, r3, r4, lsl #8 + ldrb r4, [r0] + orr r3, r3, r4, lsl #16 + ldrb r4, [r0] + orr r3, r3, r4, lsl #24 + ldrb r4, [r0] + ldrb r5, [r0] + orr r4, r4, r5, lsl #8 + ldrb r5, [r0] + orr r4, r4, r5, lsl #16 + ldrb r5, [r0] + orr r4, r4, r5, lsl #24 + stmia r1!, {r3, r4} + +.insb_no_8: tst r2, #4 + beq .insb_no_4 + + ldrb r3, [r0] + ldrb r4, [r0] + orr r3, r3, r4, lsl #8 + ldrb r4, [r0] + orr r3, r3, r4, lsl #16 + ldrb r4, [r0] + orr r3, r3, r4, lsl #24 + str r3, [r1], #4 + +.insb_no_4: ands r2, r2, #3 + LOADREGS(eqfd, sp!, {r4 - r6, pc}) + + cmp r2, #2 + ldrb r3, [r0] + strb r3, [r1], #1 + ldrgeb r3, [r0] + strgeb r3, [r1], #1 + ldrgtb r3, [r0] + strgtb r3, [r1] + + LOADREGS(fd, sp!, {r4 - r6, pc}) diff -Nru a/arch/arm26/lib/io-readsl-armv3.S b/arch/arm26/lib/io-readsl-armv3.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/io-readsl-armv3.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,78 @@ +/* + * linux/arch/arm/lib/io-readsl-armv3.S + * + * Copyright (C) 1995-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/hardware.h> + +/* + * Note that some reads can be aligned on half-word boundaries. + */ +ENTRY(__raw_readsl) + teq r2, #0 @ do we have to check for the zero len? + moveq pc, lr + ands ip, r1, #3 + bne 2f + +1: ldr r3, [r0] + str r3, [r1], #4 + subs r2, r2, #1 + bne 1b + mov pc, lr + +2: cmp ip, #2 + ldr ip, [r0] + blt 4f + bgt 6f + + strb ip, [r1], #1 + mov ip, ip, lsr #8 + strb ip, [r1], #1 + mov ip, ip, lsr #8 +3: subs r2, r2, #1 + ldrne r3, [r0] + orrne ip, ip, r3, lsl #16 + strne ip, [r1], #4 + movne ip, r3, lsr #16 + bne 3b + strb ip, [r1], #1 + mov ip, ip, lsr #8 + strb ip, [r1], #1 + mov pc, lr + +4: strb ip, [r1], #1 + mov ip, ip, lsr #8 + strb ip, [r1], #1 + mov ip, ip, lsr #8 + strb ip, [r1], #1 + mov ip, ip, lsr #8 +5: subs r2, r2, #1 + ldrne r3, [r0] + orrne ip, ip, r3, lsl #8 + strne ip, [r1], #4 + movne ip, r3, lsr #24 + bne 5b + strb ip, [r1], #1 + mov pc, lr + +6: strb ip, [r1], #1 + mov ip, ip, lsr #8 +7: subs r2, r2, #1 + ldrne r3, [r0] + orrne ip, ip, r3, lsl #24 + strne ip, [r1], #4 + movne ip, r3, lsr #8 + bne 7b + strb ip, [r1], #1 + mov ip, ip, lsr #8 + strb ip, [r1], #1 + mov ip, ip, lsr #8 + strb ip, [r1], #1 + mov pc, lr + diff -Nru a/arch/arm26/lib/io-readsw-armv3.S b/arch/arm26/lib/io-readsw-armv3.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/io-readsw-armv3.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,107 @@ +/* + * linux/arch/arm/lib/io-readsw-armv3.S + * + * Copyright (C) 1995-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/hardware.h> + +.insw_bad_alignment: + adr r0, .insw_bad_align_msg + mov r2, lr + b panic +.insw_bad_align_msg: + .asciz "insw: bad buffer alignment (0x%p, lr=0x%08lX)\n" + .align + +.insw_align: tst r1, #1 + bne .insw_bad_alignment + + ldr r3, [r0] + strb r3, [r1], #1 + mov r3, r3, lsr #8 + strb r3, [r1], #1 + + subs r2, r2, #1 + RETINSTR(moveq, pc, lr) + +ENTRY(__raw_readsw) + teq r2, #0 @ do we have to check for the zero len? + moveq pc, lr + tst r1, #3 + bne .insw_align + +.insw_aligned: mov ip, #0xff + orr ip, ip, ip, lsl #8 + stmfd sp!, {r4, r5, r6, lr} + + subs r2, r2, #8 + bmi .no_insw_8 + +.insw_8_lp: ldr r3, [r0] + and r3, r3, ip + ldr r4, [r0] + orr r3, r3, r4, lsl #16 + + ldr r4, [r0] + and r4, r4, ip + ldr r5, [r0] + orr r4, r4, r5, lsl #16 + + ldr r5, [r0] + and r5, r5, ip + ldr r6, [r0] + orr r5, r5, r6, lsl #16 + + ldr r6, [r0] + and r6, r6, ip + ldr lr, [r0] + orr r6, r6, lr, lsl #16 + + stmia r1!, {r3 - r6} + + subs r2, r2, #8 + bpl .insw_8_lp + + tst r2, #7 + LOADREGS(eqfd, sp!, {r4, r5, r6, pc}) + +.no_insw_8: tst r2, #4 + beq .no_insw_4 + + ldr r3, [r0] + and r3, r3, ip + ldr r4, [r0] + orr r3, r3, r4, lsl #16 + + ldr r4, [r0] + and r4, r4, ip + ldr r5, [r0] + orr r4, r4, r5, lsl #16 + + stmia r1!, {r3, r4} + +.no_insw_4: tst r2, #2 + beq .no_insw_2 + + ldr r3, [r0] + and r3, r3, ip + ldr r4, [r0] + orr r3, r3, r4, lsl #16 + + str r3, [r1], #4 + +.no_insw_2: tst r2, #1 + ldrne r3, [r0] + strneb r3, [r1], #1 + movne r3, r3, lsr #8 + strneb r3, [r1] + + LOADREGS(fd, sp!, {r4, r5, r6, pc}) + + diff -Nru a/arch/arm26/lib/io-writesb.S b/arch/arm26/lib/io-writesb.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/io-writesb.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,122 @@ +/* + * linux/arch/arm/lib/io-writesb.S + * + * Copyright (C) 1995-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/hardware.h> + +.outsb_align: rsb ip, ip, #4 + cmp ip, r2 + movgt ip, r2 + cmp ip, #2 + ldrb r3, [r1], #1 + strb r3, [r0] + ldrgeb r3, [r1], #1 + strgeb r3, [r0] + ldrgtb r3, [r1], #1 + strgtb r3, [r0] + subs r2, r2, ip + bne .outsb_aligned + +ENTRY(__raw_writesb) + teq r2, #0 @ do we have to check for the zero len? + moveq pc, lr + ands ip, r1, #3 + bne .outsb_align + +.outsb_aligned: stmfd sp!, {r4 - r6, lr} + + subs r2, r2, #16 + bmi .outsb_no_16 + +.outsb_16_lp: ldmia r1!, {r3 - r6} + + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + + strb r4, [r0] + mov r4, r4, lsr #8 + strb r4, [r0] + mov r4, r4, lsr #8 + strb r4, [r0] + mov r4, r4, lsr #8 + strb r4, [r0] + + strb r5, [r0] + mov r5, r5, lsr #8 + strb r5, [r0] + mov r5, r5, lsr #8 + strb r5, [r0] + mov r5, r5, lsr #8 + strb r5, [r0] + + strb r6, [r0] + mov r6, r6, lsr #8 + strb r6, [r0] + mov r6, r6, lsr #8 + strb r6, [r0] + mov r6, r6, lsr #8 + strb r6, [r0] + + subs r2, r2, #16 + bpl .outsb_16_lp + + tst r2, #15 + LOADREGS(eqfd, sp!, {r4 - r6, pc}) + +.outsb_no_16: tst r2, #8 + beq .outsb_no_8 + + ldmia r1!, {r3, r4} + + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + + strb r4, [r0] + mov r4, r4, lsr #8 + strb r4, [r0] + mov r4, r4, lsr #8 + strb r4, [r0] + mov r4, r4, lsr #8 + strb r4, [r0] + +.outsb_no_8: tst r2, #4 + beq .outsb_no_4 + + ldr r3, [r1], #4 + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + mov r3, r3, lsr #8 + strb r3, [r0] + +.outsb_no_4: ands r2, r2, #3 + LOADREGS(eqfd, sp!, {r4 - r6, pc}) + + cmp r2, #2 + ldrb r3, [r1], #1 + strb r3, [r0] + ldrgeb r3, [r1], #1 + strgeb r3, [r0] + ldrgtb r3, [r1] + strgtb r3, [r0] + + LOADREGS(fd, sp!, {r4 - r6, pc}) diff -Nru a/arch/arm26/lib/io-writesl.S b/arch/arm26/lib/io-writesl.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/io-writesl.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,56 @@ +/* + * linux/arch/arm/lib/io-writesl.S + * + * Copyright (C) 1995-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/hardware.h> + +ENTRY(__raw_writesl) + teq r2, #0 @ do we have to check for the zero len? + moveq pc, lr + ands ip, r1, #3 + bne 2f + +1: ldr r3, [r1], #4 + str r3, [r0] + subs r2, r2, #1 + bne 1b + mov pc, lr + +2: bic r1, r1, #3 + cmp ip, #2 + ldr r3, [r1], #4 + bgt 4f + blt 5f + +3: mov ip, r3, lsr #16 + ldr r3, [r1], #4 + orr ip, ip, r3, lsl #16 + str ip, [r0] + subs r2, r2, #1 + bne 3b + mov pc, lr + +4: mov ip, r3, lsr #24 + ldr r3, [r1], #4 + orr ip, ip, r3, lsl #8 + str ip, [r0] + subs r2, r2, #1 + bne 4b + mov pc, lr + +5: mov ip, r3, lsr #8 + ldr r3, [r1], #4 + orr ip, ip, r3, lsl #24 + str ip, [r0] + subs r2, r2, #1 + bne 5b + mov pc, lr + + diff -Nru a/arch/arm26/lib/io-writesw-armv3.S b/arch/arm26/lib/io-writesw-armv3.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/io-writesw-armv3.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,127 @@ +/* + * linux/arch/arm/lib/io-writesw-armv3.S + * + * Copyright (C) 1995-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/hardware.h> + +.outsw_bad_alignment: + adr r0, .outsw_bad_align_msg + mov r2, lr + b panic +.outsw_bad_align_msg: + .asciz "outsw: bad buffer alignment (0x%p, lr=0x%08lX)\n" + .align + +.outsw_align: tst r1, #1 + bne .outsw_bad_alignment + + add r1, r1, #2 + + ldr r3, [r1, #-4] + mov r3, r3, lsr #16 + orr r3, r3, r3, lsl #16 + str r3, [r0] + subs r2, r2, #1 + RETINSTR(moveq, pc, lr) + +ENTRY(__raw_writesw) + teq r2, #0 @ do we have to check for the zero len? + moveq pc, lr + tst r1, #3 + bne .outsw_align + +.outsw_aligned: stmfd sp!, {r4, r5, r6, lr} + + subs r2, r2, #8 + bmi .no_outsw_8 + +.outsw_8_lp: ldmia r1!, {r3, r4, r5, r6} + + mov ip, r3, lsl #16 + orr ip, ip, ip, lsr #16 + str ip, [r0] + + mov ip, r3, lsr #16 + orr ip, ip, ip, lsl #16 + str ip, [r0] + + mov ip, r4, lsl #16 + orr ip, ip, ip, lsr #16 + str ip, [r0] + + mov ip, r4, lsr #16 + orr ip, ip, ip, lsl #16 + str ip, [r0] + + mov ip, r5, lsl #16 + orr ip, ip, ip, lsr #16 + str ip, [r0] + + mov ip, r5, lsr #16 + orr ip, ip, ip, lsl #16 + str ip, [r0] + + mov ip, r6, lsl #16 + orr ip, ip, ip, lsr #16 + str ip, [r0] + + mov ip, r6, lsr #16 + orr ip, ip, ip, lsl #16 + str ip, [r0] + + subs r2, r2, #8 + bpl .outsw_8_lp + + tst r2, #7 + LOADREGS(eqfd, sp!, {r4, r5, r6, pc}) + +.no_outsw_8: tst r2, #4 + beq .no_outsw_4 + + ldmia r1!, {r3, r4} + + mov ip, r3, lsl #16 + orr ip, ip, ip, lsr #16 + str ip, [r0] + + mov ip, r3, lsr #16 + orr ip, ip, ip, lsl #16 + str ip, [r0] + + mov ip, r4, lsl #16 + orr ip, ip, ip, lsr #16 + str ip, [r0] + + mov ip, r4, lsr #16 + orr ip, ip, ip, lsl #16 + str ip, [r0] + +.no_outsw_4: tst r2, #2 + beq .no_outsw_2 + + ldr r3, [r1], #4 + + mov ip, r3, lsl #16 + orr ip, ip, ip, lsr #16 + str ip, [r0] + + mov ip, r3, lsr #16 + orr ip, ip, ip, lsl #16 + str ip, [r0] + +.no_outsw_2: tst r2, #1 + + ldrne r3, [r1] + + movne ip, r3, lsl #16 + orrne ip, ip, ip, lsr #16 + strne ip, [r0] + + LOADREGS(fd, sp!, {r4, r5, r6, pc}) diff -Nru a/arch/arm26/lib/kbd.c b/arch/arm26/lib/kbd.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/kbd.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,279 @@ +#include <linux/config.h> +#include <linux/kd.h> +//#include <linux/kbd_ll.h> +#include <linux/kbd_kern.h> + +/* + * Translation of escaped scancodes to keycodes. + * This is now user-settable. + * The keycodes 1-88,96-111,119 are fairly standard, and + * should probably not be changed - changing might confuse X. + * X also interprets scancode 0x5d (KEY_Begin). + * + * For 1-88 keycode equals scancode. + */ + +#define E0_KPENTER 96 +#define E0_RCTRL 97 +#define E0_KPSLASH 98 +#define E0_PRSCR 99 +#define E0_RALT 100 +#define E0_BREAK 101 /* (control-pause) */ +#define E0_HOME 102 +#define E0_UP 103 +#define E0_PGUP 104 +#define E0_LEFT 105 +#define E0_RIGHT 106 +#define E0_END 107 +#define E0_DOWN 108 +#define E0_PGDN 109 +#define E0_INS 110 +#define E0_DEL 111 + +/* for USB 106 keyboard */ +#define E0_YEN 124 +#define E0_BACKSLASH 89 + + +#define E1_PAUSE 119 + +/* + * The keycodes below are randomly located in 89-95,112-118,120-127. + * They could be thrown away (and all occurrences below replaced by 0), + * but that would force many users to use the `setkeycodes' utility, where + * they needed not before. It does not matter that there are duplicates, as + * long as no duplication occurs for any single keyboard. + */ +#define SC_LIM 89 + +#define FOCUS_PF1 85 /* actual code! */ +#define FOCUS_PF2 89 +#define FOCUS_PF3 90 +#define FOCUS_PF4 91 +#define FOCUS_PF5 92 +#define FOCUS_PF6 93 +#define FOCUS_PF7 94 +#define FOCUS_PF8 95 +#define FOCUS_PF9 120 +#define FOCUS_PF10 121 +#define FOCUS_PF11 122 +#define FOCUS_PF12 123 + +#define JAP_86 124 +/* tfj@olivia.ping.dk: + * The four keys are located over the numeric keypad, and are + * labelled A1-A4. It's an rc930 keyboard, from + * Regnecentralen/RC International, Now ICL. + * Scancodes: 59, 5a, 5b, 5c. + */ +#define RGN1 124 +#define RGN2 125 +#define RGN3 126 +#define RGN4 127 + +static unsigned char high_keys[128 - SC_LIM] = { + RGN1, RGN2, RGN3, RGN4, 0, 0, 0, /* 0x59-0x5f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ + 0, 0, 0, 0, 0, FOCUS_PF11, 0, FOCUS_PF12, /* 0x68-0x6f */ + 0, 0, 0, FOCUS_PF2, FOCUS_PF9, 0, 0, FOCUS_PF3, /* 0x70-0x77 */ + FOCUS_PF4, FOCUS_PF5, FOCUS_PF6, FOCUS_PF7, /* 0x78-0x7b */ + FOCUS_PF8, JAP_86, FOCUS_PF10, 0 /* 0x7c-0x7f */ +}; + +/* BTC */ +#define E0_MACRO 112 +/* LK450 */ +#define E0_F13 113 +#define E0_F14 114 +#define E0_HELP 115 +#define E0_DO 116 +#define E0_F17 117 +#define E0_KPMINPLUS 118 +/* + * My OmniKey generates e0 4c for the "OMNI" key and the + * right alt key does nada. [kkoller@nyx10.cs.du.edu] + */ +#define E0_OK 124 +/* + * New microsoft keyboard is rumoured to have + * e0 5b (left window button), e0 5c (right window button), + * e0 5d (menu button). [or: LBANNER, RBANNER, RMENU] + * [or: Windows_L, Windows_R, TaskMan] + */ +#define E0_MSLW 125 +#define E0_MSRW 126 +#define E0_MSTM 127 + +static unsigned char e0_keys[128] = { + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x07 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x08-0x0f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */ + 0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0, /* 0x18-0x1f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */ + 0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR, /* 0x30-0x37 */ + E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP, /* 0x38-0x3f */ + E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME, /* 0x40-0x47 */ + E0_UP, E0_PGUP, 0, E0_LEFT, E0_OK, E0_RIGHT, E0_KPMINPLUS, E0_END, /* 0x48-0x4f */ + E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0, /* 0x50-0x57 */ + 0, 0, 0, E0_MSLW, E0_MSRW, E0_MSTM, 0, 0, /* 0x58-0x5f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ + 0, 0, 0, 0, 0, 0, 0, E0_MACRO, /* 0x68-0x6f */ + //0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */ + 0, 0, 0, 0, 0, E0_BACKSLASH, 0, 0, /* 0x70-0x77 */ + 0, 0, 0, E0_YEN, 0, 0, 0, 0 /* 0x78-0x7f */ +}; + +static int gen_setkeycode(unsigned int scancode, unsigned int keycode) +{ + if (scancode < SC_LIM || scancode > 255 || keycode > 127) + return -EINVAL; + if (scancode < 128) + high_keys[scancode - SC_LIM] = keycode; + else + e0_keys[scancode - 128] = keycode; + return 0; +} + +static int gen_getkeycode(unsigned int scancode) +{ + return + (scancode < SC_LIM || scancode > 255) ? -EINVAL : + (scancode < + 128) ? high_keys[scancode - SC_LIM] : e0_keys[scancode - 128]; +} + +static int +gen_translate(unsigned char scancode, unsigned char *keycode, char raw_mode) +{ + static int prev_scancode = 0; + + /* special prefix scancodes.. */ + if (scancode == 0xe0 || scancode == 0xe1) { + prev_scancode = scancode; + return 0; + } + + /* 0xFF is sent by a few keyboards, ignore it. 0x00 is error */ + if (scancode == 0x00 || scancode == 0xff) { + prev_scancode = 0; + return 0; + } + + scancode &= 0x7f; + + if (prev_scancode) { + /* + * usually it will be 0xe0, but a Pause key generates + * e1 1d 45 e1 9d c5 when pressed, and nothing when released + */ + if (prev_scancode != 0xe0) { + if (prev_scancode == 0xe1 && scancode == 0x1d) { + prev_scancode = 0x100; + return 0; + } + else if (prev_scancode == 0x100 + && scancode == 0x45) { + *keycode = E1_PAUSE; + prev_scancode = 0; + } else { +#ifdef KBD_REPORT_UNKN + if (!raw_mode) + printk(KERN_INFO + "keyboard: unknown e1 escape sequence\n"); +#endif + prev_scancode = 0; + return 0; + } + } else { + prev_scancode = 0; + /* + * The keyboard maintains its own internal caps lock and + * num lock statuses. In caps lock mode E0 AA precedes make + * code and E0 2A follows break code. In num lock mode, + * E0 2A precedes make code and E0 AA follows break code. + * We do our own book-keeping, so we will just ignore these. + */ + /* + * For my keyboard there is no caps lock mode, but there are + * both Shift-L and Shift-R modes. The former mode generates + * E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs. + * So, we should also ignore the latter. - aeb@cwi.nl + */ + if (scancode == 0x2a || scancode == 0x36) + return 0; + + if (e0_keys[scancode]) + *keycode = e0_keys[scancode]; + else { +#ifdef KBD_REPORT_UNKN + if (!raw_mode) + printk(KERN_INFO + "keyboard: unknown scancode e0 %02x\n", + scancode); +#endif + return 0; + } + } + } else if (scancode >= SC_LIM) { + /* This happens with the FOCUS 9000 keyboard + Its keys PF1..PF12 are reported to generate + 55 73 77 78 79 7a 7b 7c 74 7e 6d 6f + Moreover, unless repeated, they do not generate + key-down events, so we have to zero up_flag below */ + /* Also, Japanese 86/106 keyboards are reported to + generate 0x73 and 0x7d for \ - and \ | respectively. */ + /* Also, some Brazilian keyboard is reported to produce + 0x73 and 0x7e for \ ? and KP-dot, respectively. */ + + *keycode = high_keys[scancode - SC_LIM]; + + if (!*keycode) { + if (!raw_mode) { +#ifdef KBD_REPORT_UNKN + printk(KERN_INFO + "keyboard: unrecognized scancode (%02x)" + " - ignored\n", scancode); +#endif + } + return 0; + } + } else + *keycode = scancode; + return 1; +} + +static char gen_unexpected_up(unsigned char keycode) +{ + /* unexpected, but this can happen: maybe this was a key release for a + FOCUS 9000 PF key; if we want to see it, we have to clear up_flag */ + if (keycode >= SC_LIM || keycode == 85) + return 0; + else + return 0200; +} + +/* + * These are the default mappings + */ +int (*k_setkeycode)(unsigned int, unsigned int) = gen_setkeycode; +int (*k_getkeycode)(unsigned int) = gen_getkeycode; +int (*k_translate)(unsigned char, unsigned char *, char) = gen_translate; +char (*k_unexpected_up)(unsigned char) = gen_unexpected_up; +void (*k_leds)(unsigned char); + +/* Simple translation table for the SysRq keys */ + +#ifdef CONFIG_MAGIC_SYSRQ +static unsigned char gen_sysrq_xlate[128] = + "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ + "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ + "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ + "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ + "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */ + "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ + "\r\000/"; /* 0x60 - 0x6f */ + +unsigned char *k_sysrq_xlate = gen_sysrq_xlate; +int k_sysrq_key = 0x54; +#endif diff -Nru a/arch/arm26/lib/lib1funcs.S b/arch/arm26/lib/lib1funcs.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/lib1funcs.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,314 @@ +@ libgcc1 routines for ARM cpu. +@ Division routines, written by Richard Earnshaw, (rearnsha@armltd.co.uk) + +/* Copyright (C) 1995, 1996, 1998 Free Software Foundation, Inc. + +This file is free software; you can redistribute 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. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file with other programs, and to distribute +those programs without any restriction coming from the use of this +file. (The General Public License restrictions do apply in other +respects; for example, they cover modification of the file, and +distribution when not linked into another program.) + +This file 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; see the file COPYING. If not, write to +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* As a special exception, if you link this library with other files, + some of which are compiled with GCC, to produce an executable, + this library does not by itself cause the resulting executable + to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. + */ +/* This code is derived from gcc 2.95.3 */ +/* I Molton 29/07/01 */ + +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/hardware.h> +#include <linux/config.h> + +#define RET movs +#define RETc(x) mov##x##s +#define RETCOND ^ + +dividend .req r0 +divisor .req r1 +result .req r2 +overdone .req r2 +curbit .req r3 +ip .req r12 +sp .req r13 +lr .req r14 +pc .req r15 + +ENTRY(__udivsi3) + cmp divisor, #0 + beq Ldiv0 + mov curbit, #1 + mov result, #0 + cmp dividend, divisor + bcc Lgot_result_udivsi3 +1: + @ Unless the divisor is very big, shift it up in multiples of + @ four bits, since this is the amount of unwinding in the main + @ division loop. Continue shifting until the divisor is + @ larger than the dividend. + cmp divisor, #0x10000000 + cmpcc divisor, dividend + movcc divisor, divisor, lsl #4 + movcc curbit, curbit, lsl #4 + bcc 1b + +2: + @ For very big divisors, we must shift it a bit at a time, or + @ we will be in danger of overflowing. + cmp divisor, #0x80000000 + cmpcc divisor, dividend + movcc divisor, divisor, lsl #1 + movcc curbit, curbit, lsl #1 + bcc 2b + +3: + @ Test for possible subtractions, and note which bits + @ are done in the result. On the final pass, this may subtract + @ too much from the dividend, but the result will be ok, since the + @ "bit" will have been shifted out at the bottom. + cmp dividend, divisor + subcs dividend, dividend, divisor + orrcs result, result, curbit + cmp dividend, divisor, lsr #1 + subcs dividend, dividend, divisor, lsr #1 + orrcs result, result, curbit, lsr #1 + cmp dividend, divisor, lsr #2 + subcs dividend, dividend, divisor, lsr #2 + orrcs result, result, curbit, lsr #2 + cmp dividend, divisor, lsr #3 + subcs dividend, dividend, divisor, lsr #3 + orrcs result, result, curbit, lsr #3 + cmp dividend, #0 @ Early termination? + movnes curbit, curbit, lsr #4 @ No, any more bits to do? + movne divisor, divisor, lsr #4 + bne 3b +Lgot_result_udivsi3: + mov r0, result + RET pc, lr + +Ldiv0: + str lr, [sp, #-4]! + bl __div0 + mov r0, #0 @ about as wrong as it could be + ldmia sp!, {pc}RETCOND + +/* __umodsi3 ----------------------- */ + +ENTRY(__umodsi3) + cmp divisor, #0 + beq Ldiv0 + mov curbit, #1 + cmp dividend, divisor + RETc(cc) pc, lr +1: + @ Unless the divisor is very big, shift it up in multiples of + @ four bits, since this is the amount of unwinding in the main + @ division loop. Continue shifting until the divisor is + @ larger than the dividend. + cmp divisor, #0x10000000 + cmpcc divisor, dividend + movcc divisor, divisor, lsl #4 + movcc curbit, curbit, lsl #4 + bcc 1b + +2: + @ For very big divisors, we must shift it a bit at a time, or + @ we will be in danger of overflowing. + cmp divisor, #0x80000000 + cmpcc divisor, dividend + movcc divisor, divisor, lsl #1 + movcc curbit, curbit, lsl #1 + bcc 2b + +3: + @ Test for possible subtractions. On the final pass, this may + @ subtract too much from the dividend, so keep track of which + @ subtractions are done, we can fix them up afterwards... + mov overdone, #0 + cmp dividend, divisor + subcs dividend, dividend, divisor + cmp dividend, divisor, lsr #1 + subcs dividend, dividend, divisor, lsr #1 + orrcs overdone, overdone, curbit, ror #1 + cmp dividend, divisor, lsr #2 + subcs dividend, dividend, divisor, lsr #2 + orrcs overdone, overdone, curbit, ror #2 + cmp dividend, divisor, lsr #3 + subcs dividend, dividend, divisor, lsr #3 + orrcs overdone, overdone, curbit, ror #3 + mov ip, curbit + cmp dividend, #0 @ Early termination? + movnes curbit, curbit, lsr #4 @ No, any more bits to do? + movne divisor, divisor, lsr #4 + bne 3b + + @ Any subtractions that we should not have done will be recorded in + @ the top three bits of "overdone". Exactly which were not needed + @ are governed by the position of the bit, stored in ip. + @ If we terminated early, because dividend became zero, + @ then none of the below will match, since the bit in ip will not be + @ in the bottom nibble. + ands overdone, overdone, #0xe0000000 + RETc(eq) pc, lr @ No fixups needed + tst overdone, ip, ror #3 + addne dividend, dividend, divisor, lsr #3 + tst overdone, ip, ror #2 + addne dividend, dividend, divisor, lsr #2 + tst overdone, ip, ror #1 + addne dividend, dividend, divisor, lsr #1 + RET pc, lr + +ENTRY(__divsi3) + eor ip, dividend, divisor @ Save the sign of the result. + mov curbit, #1 + mov result, #0 + cmp divisor, #0 + rsbmi divisor, divisor, #0 @ Loops below use unsigned. + beq Ldiv0 + cmp dividend, #0 + rsbmi dividend, dividend, #0 + cmp dividend, divisor + bcc Lgot_result_divsi3 + +1: + @ Unless the divisor is very big, shift it up in multiples of + @ four bits, since this is the amount of unwinding in the main + @ division loop. Continue shifting until the divisor is + @ larger than the dividend. + cmp divisor, #0x10000000 + cmpcc divisor, dividend + movcc divisor, divisor, lsl #4 + movcc curbit, curbit, lsl #4 + bcc 1b + +2: + @ For very big divisors, we must shift it a bit at a time, or + @ we will be in danger of overflowing. + cmp divisor, #0x80000000 + cmpcc divisor, dividend + movcc divisor, divisor, lsl #1 + movcc curbit, curbit, lsl #1 + bcc 2b + +3: + @ Test for possible subtractions, and note which bits + @ are done in the result. On the final pass, this may subtract + @ too much from the dividend, but the result will be ok, since the + @ "bit" will have been shifted out at the bottom. + cmp dividend, divisor + subcs dividend, dividend, divisor + orrcs result, result, curbit + cmp dividend, divisor, lsr #1 + subcs dividend, dividend, divisor, lsr #1 + orrcs result, result, curbit, lsr #1 + cmp dividend, divisor, lsr #2 + subcs dividend, dividend, divisor, lsr #2 + orrcs result, result, curbit, lsr #2 + cmp dividend, divisor, lsr #3 + subcs dividend, dividend, divisor, lsr #3 + orrcs result, result, curbit, lsr #3 + cmp dividend, #0 @ Early termination? + movnes curbit, curbit, lsr #4 @ No, any more bits to do? + movne divisor, divisor, lsr #4 + bne 3b +Lgot_result_divsi3: + mov r0, result + cmp ip, #0 + rsbmi r0, r0, #0 + RET pc, lr + +ENTRY(__modsi3) + mov curbit, #1 + cmp divisor, #0 + rsbmi divisor, divisor, #0 @ Loops below use unsigned. + beq Ldiv0 + @ Need to save the sign of the dividend, unfortunately, we need + @ ip later on; this is faster than pushing lr and using that. + str dividend, [sp, #-4]! + cmp dividend, #0 + rsbmi dividend, dividend, #0 + cmp dividend, divisor + bcc Lgot_result_modsi3 + +1: + @ Unless the divisor is very big, shift it up in multiples of + @ four bits, since this is the amount of unwinding in the main + @ division loop. Continue shifting until the divisor is + @ larger than the dividend. + cmp divisor, #0x10000000 + cmpcc divisor, dividend + movcc divisor, divisor, lsl #4 + movcc curbit, curbit, lsl #4 + bcc 1b + +2: + @ For very big divisors, we must shift it a bit at a time, or + @ we will be in danger of overflowing. + cmp divisor, #0x80000000 + cmpcc divisor, dividend + movcc divisor, divisor, lsl #1 + movcc curbit, curbit, lsl #1 + bcc 2b + +3: + @ Test for possible subtractions. On the final pass, this may + @ subtract too much from the dividend, so keep track of which + @ subtractions are done, we can fix them up afterwards... + mov overdone, #0 + cmp dividend, divisor + subcs dividend, dividend, divisor + cmp dividend, divisor, lsr #1 + subcs dividend, dividend, divisor, lsr #1 + orrcs overdone, overdone, curbit, ror #1 + cmp dividend, divisor, lsr #2 + subcs dividend, dividend, divisor, lsr #2 + orrcs overdone, overdone, curbit, ror #2 + cmp dividend, divisor, lsr #3 + subcs dividend, dividend, divisor, lsr #3 + orrcs overdone, overdone, curbit, ror #3 + mov ip, curbit + cmp dividend, #0 @ Early termination? + movnes curbit, curbit, lsr #4 @ No, any more bits to do? + movne divisor, divisor, lsr #4 + bne 3b + + @ Any subtractions that we should not have done will be recorded in + @ the top three bits of "overdone". Exactly which were not needed + @ are governed by the position of the bit, stored in ip. + @ If we terminated early, because dividend became zero, + @ then none of the below will match, since the bit in ip will not be + @ in the bottom nibble. + ands overdone, overdone, #0xe0000000 + beq Lgot_result_modsi3 + tst overdone, ip, ror #3 + addne dividend, dividend, divisor, lsr #3 + tst overdone, ip, ror #2 + addne dividend, dividend, divisor, lsr #2 + tst overdone, ip, ror #1 + addne dividend, dividend, divisor, lsr #1 +Lgot_result_modsi3: + ldr ip, [sp], #4 + cmp ip, #0 + rsbmi dividend, dividend, #0 + RET pc, lr diff -Nru a/arch/arm26/lib/longlong.h b/arch/arm26/lib/longlong.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/longlong.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,184 @@ +/* longlong.h -- based on code from gcc-2.95.3 + + definitions for mixed size 32/64 bit arithmetic. + Copyright (C) 1991, 92, 94, 95, 96, 1997, 1998 Free Software Foundation, Inc. + + This definition file is free software; you can redistribute 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 definition file 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. */ + +/* Borrowed from GCC 2.95.3, I Molton 29/07/01 */ + +#ifndef SI_TYPE_SIZE +#define SI_TYPE_SIZE 32 +#endif + +#define __BITS4 (SI_TYPE_SIZE / 4) +#define __ll_B (1L << (SI_TYPE_SIZE / 2)) +#define __ll_lowpart(t) ((USItype) (t) % __ll_B) +#define __ll_highpart(t) ((USItype) (t) / __ll_B) + +/* Define auxiliary asm macros. + + 1) umul_ppmm(high_prod, low_prod, multipler, multiplicand) + multiplies two USItype integers MULTIPLER and MULTIPLICAND, + and generates a two-part USItype product in HIGH_PROD and + LOW_PROD. + + 2) __umulsidi3(a,b) multiplies two USItype integers A and B, + and returns a UDItype product. This is just a variant of umul_ppmm. + + 3) udiv_qrnnd(quotient, remainder, high_numerator, low_numerator, + denominator) divides a two-word unsigned integer, composed by the + integers HIGH_NUMERATOR and LOW_NUMERATOR, by DENOMINATOR and + places the quotient in QUOTIENT and the remainder in REMAINDER. + HIGH_NUMERATOR must be less than DENOMINATOR for correct operation. + If, in addition, the most significant bit of DENOMINATOR must be 1, + then the pre-processor symbol UDIV_NEEDS_NORMALIZATION is defined to 1. + + 4) sdiv_qrnnd(quotient, remainder, high_numerator, low_numerator, + denominator). Like udiv_qrnnd but the numbers are signed. The + quotient is rounded towards 0. + + 5) count_leading_zeros(count, x) counts the number of zero-bits from + the msb to the first non-zero bit. This is the number of steps X + needs to be shifted left to set the msb. Undefined for X == 0. + + 6) add_ssaaaa(high_sum, low_sum, high_addend_1, low_addend_1, + high_addend_2, low_addend_2) adds two two-word unsigned integers, + composed by HIGH_ADDEND_1 and LOW_ADDEND_1, and HIGH_ADDEND_2 and + LOW_ADDEND_2 respectively. The result is placed in HIGH_SUM and + LOW_SUM. Overflow (i.e. carry out) is not stored anywhere, and is + lost. + + 7) sub_ddmmss(high_difference, low_difference, high_minuend, + low_minuend, high_subtrahend, low_subtrahend) subtracts two + two-word unsigned integers, composed by HIGH_MINUEND_1 and + LOW_MINUEND_1, and HIGH_SUBTRAHEND_2 and LOW_SUBTRAHEND_2 + respectively. The result is placed in HIGH_DIFFERENCE and + LOW_DIFFERENCE. Overflow (i.e. carry out) is not stored anywhere, + and is lost. + + If any of these macros are left undefined for a particular CPU, + C macros are used. */ + +#if defined (__arm__) +#define add_ssaaaa(sh, sl, ah, al, bh, bl) \ + __asm__ ("adds %1, %4, %5 \n\ + adc %0, %2, %3" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "%r" ((USItype) (ah)), \ + "rI" ((USItype) (bh)), \ + "%r" ((USItype) (al)), \ + "rI" ((USItype) (bl))) +#define sub_ddmmss(sh, sl, ah, al, bh, bl) \ + __asm__ ("subs %1, %4, %5 \n\ + sbc %0, %2, %3" \ + : "=r" ((USItype) (sh)), \ + "=&r" ((USItype) (sl)) \ + : "r" ((USItype) (ah)), \ + "rI" ((USItype) (bh)), \ + "r" ((USItype) (al)), \ + "rI" ((USItype) (bl))) +#define umul_ppmm(xh, xl, a, b) \ +{register USItype __t0, __t1, __t2; \ + __asm__ ("%@ Inlined umul_ppmm \n\ + mov %2, %5, lsr #16 \n\ + mov %0, %6, lsr #16 \n\ + bic %3, %5, %2, lsl #16 \n\ + bic %4, %6, %0, lsl #16 \n\ + mul %1, %3, %4 \n\ + mul %4, %2, %4 \n\ + mul %3, %0, %3 \n\ + mul %0, %2, %0 \n\ + adds %3, %4, %3 \n\ + addcs %0, %0, #65536 \n\ + adds %1, %1, %3, lsl #16 \n\ + adc %0, %0, %3, lsr #16" \ + : "=&r" ((USItype) (xh)), \ + "=r" ((USItype) (xl)), \ + "=&r" (__t0), "=&r" (__t1), "=r" (__t2) \ + : "r" ((USItype) (a)), \ + "r" ((USItype) (b)));} +#define UMUL_TIME 20 +#define UDIV_TIME 100 +#endif /* __arm__ */ + +#define __umulsidi3(u, v) \ + ({DIunion __w; \ + umul_ppmm (__w.s.high, __w.s.low, u, v); \ + __w.ll; }) + +#define __udiv_qrnnd_c(q, r, n1, n0, d) \ + do { \ + USItype __d1, __d0, __q1, __q0; \ + USItype __r1, __r0, __m; \ + __d1 = __ll_highpart (d); \ + __d0 = __ll_lowpart (d); \ + \ + __r1 = (n1) % __d1; \ + __q1 = (n1) / __d1; \ + __m = (USItype) __q1 * __d0; \ + __r1 = __r1 * __ll_B | __ll_highpart (n0); \ + if (__r1 < __m) \ + { \ + __q1--, __r1 += (d); \ + if (__r1 >= (d)) /* i.e. we didn't get carry when adding to __r1 */\ + if (__r1 < __m) \ + __q1--, __r1 += (d); \ + } \ + __r1 -= __m; \ + \ + __r0 = __r1 % __d1; \ + __q0 = __r1 / __d1; \ + __m = (USItype) __q0 * __d0; \ + __r0 = __r0 * __ll_B | __ll_lowpart (n0); \ + if (__r0 < __m) \ + { \ + __q0--, __r0 += (d); \ + if (__r0 >= (d)) \ + if (__r0 < __m) \ + __q0--, __r0 += (d); \ + } \ + __r0 -= __m; \ + \ + (q) = (USItype) __q1 * __ll_B | __q0; \ + (r) = __r0; \ + } while (0) + +#define UDIV_NEEDS_NORMALIZATION 1 +#define udiv_qrnnd __udiv_qrnnd_c + +extern const UQItype __clz_tab[]; +#define count_leading_zeros(count, x) \ + do { \ + USItype __xr = (x); \ + USItype __a; \ + \ + if (SI_TYPE_SIZE <= 32) \ + { \ + __a = __xr < ((USItype)1<<2*__BITS4) \ + ? (__xr < ((USItype)1<<__BITS4) ? 0 : __BITS4) \ + : (__xr < ((USItype)1<<3*__BITS4) ? 2*__BITS4 : 3*__BITS4); \ + } \ + else \ + { \ + for (__a = SI_TYPE_SIZE - 8; __a > 0; __a -= 8) \ + if (((__xr >> __a) & 0xff) != 0) \ + break; \ + } \ + \ + (count) = SI_TYPE_SIZE - (__clz_tab[__xr >> __a] + __a); \ + } while (0) diff -Nru a/arch/arm26/lib/lshrdi3.c b/arch/arm26/lib/lshrdi3.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/lshrdi3.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,61 @@ +/* More subroutines needed by GCC output code on some machines. */ +/* Compile this one with gcc. */ +/* 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. */ + +/* As a special exception, if you link this library with other files, + some of which are compiled with GCC, to produce an executable, + this library does not by itself cause the resulting executable + to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. + */ +/* support functions required by the kernel. based on code from gcc-2.95.3 */ +/* I Molton 29/07/01 */ + +#include "gcclib.h" + +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 -Nru a/arch/arm26/lib/memchr.S b/arch/arm26/lib/memchr.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/memchr.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,25 @@ +/* + * linux/arch/arm/lib/memchr.S + * + * Copyright (C) 1995-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ASM optimised string functions + */ +#include <linux/linkage.h> +#include <asm/assembler.h> + + .text + .align 5 +ENTRY(memchr) +1: subs r2, r2, #1 + bmi 2f + ldrb r3, [r0], #1 + teq r3, r1 + bne 1b + sub r0, r0, #1 +2: movne r0, #0 + RETINSTR(mov,pc,lr) diff -Nru a/arch/arm26/lib/memcpy.S b/arch/arm26/lib/memcpy.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/memcpy.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,318 @@ +/* + * linux/arch/arm/lib/memcpy.S + * + * Copyright (C) 1995-1999 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ASM optimised string functions + */ +#include <linux/linkage.h> +#include <asm/assembler.h> + + .text + +#define ENTER \ + mov ip,sp ;\ + stmfd sp!,{r4-r9,fp,ip,lr,pc} ;\ + sub fp,ip,#4 + +#define EXIT \ + LOADREGS(ea, fp, {r4 - r9, fp, sp, pc}) + +#define EXITEQ \ + LOADREGS(eqea, fp, {r4 - r9, fp, sp, pc}) + +/* + * Prototype: void memcpy(void *to,const void *from,unsigned long n); + * ARM3: cant use memcopy here!!! + */ +ENTRY(memcpy) +ENTRY(memmove) + ENTER + cmp r1, r0 + bcc 19f + subs r2, r2, #4 + blt 6f + ands ip, r0, #3 + bne 7f + ands ip, r1, #3 + bne 8f + +1: subs r2, r2, #8 + blt 5f + subs r2, r2, #0x14 + blt 3f +2: ldmia r1!,{r3 - r9, ip} + stmia r0!,{r3 - r9, ip} + subs r2, r2, #32 + bge 2b + cmn r2, #16 + ldmgeia r1!, {r3 - r6} + stmgeia r0!, {r3 - r6} + subge r2, r2, #0x10 +3: adds r2, r2, #0x14 +4: ldmgeia r1!, {r3 - r5} + stmgeia r0!, {r3 - r5} + subges r2, r2, #12 + bge 4b +5: adds r2, r2, #8 + blt 6f + subs r2, r2, #4 + ldrlt r3, [r1], #4 + ldmgeia r1!, {r4, r5} + strlt r3, [r0], #4 + stmgeia r0!, {r4, r5} + subge r2, r2, #4 + +6: adds r2, r2, #4 + EXITEQ + cmp r2, #2 + ldrb r3, [r1], #1 + ldrgeb r4, [r1], #1 + ldrgtb r5, [r1], #1 + strb r3, [r0], #1 + strgeb r4, [r0], #1 + strgtb r5, [r0], #1 + EXIT + +7: rsb ip, ip, #4 + cmp ip, #2 + ldrb r3, [r1], #1 + ldrgeb r4, [r1], #1 + ldrgtb r5, [r1], #1 + strb r3, [r0], #1 + strgeb r4, [r0], #1 + strgtb r5, [r0], #1 + subs r2, r2, ip + blt 6b + ands ip, r1, #3 + beq 1b + +8: bic r1, r1, #3 + ldr r7, [r1], #4 + cmp ip, #2 + bgt 15f + beq 11f + cmp r2, #12 + blt 10f + sub r2, r2, #12 +9: mov r3, r7, pull #8 + ldmia r1!, {r4 - r7} + orr r3, r3, r4, push #24 + mov r4, r4, pull #8 + orr r4, r4, r5, push #24 + mov r5, r5, pull #8 + orr r5, r5, r6, push #24 + mov r6, r6, pull #8 + orr r6, r6, r7, push #24 + stmia r0!, {r3 - r6} + subs r2, r2, #16 + bge 9b + adds r2, r2, #12 + blt 100f +10: mov r3, r7, pull #8 + ldr r7, [r1], #4 + subs r2, r2, #4 + orr r3, r3, r7, push #24 + str r3, [r0], #4 + bge 10b +100: sub r1, r1, #3 + b 6b + +11: cmp r2, #12 + blt 13f /* */ + sub r2, r2, #12 +12: mov r3, r7, pull #16 + ldmia r1!, {r4 - r7} + orr r3, r3, r4, push #16 + mov r4, r4, pull #16 + orr r4, r4, r5, push #16 + mov r5, r5, pull #16 + orr r5, r5, r6, push #16 + mov r6, r6, pull #16 + orr r6, r6, r7, push #16 + stmia r0!, {r3 - r6} + subs r2, r2, #16 + bge 12b + adds r2, r2, #12 + blt 14f +13: mov r3, r7, pull #16 + ldr r7, [r1], #4 + subs r2, r2, #4 + orr r3, r3, r7, push #16 + str r3, [r0], #4 + bge 13b +14: sub r1, r1, #2 + b 6b + +15: cmp r2, #12 + blt 17f + sub r2, r2, #12 +16: mov r3, r7, pull #24 + ldmia r1!, {r4 - r7} + orr r3, r3, r4, push #8 + mov r4, r4, pull #24 + orr r4, r4, r5, push #8 + mov r5, r5, pull #24 + orr r5, r5, r6, push #8 + mov r6, r6, pull #24 + orr r6, r6, r7, push #8 + stmia r0!, {r3 - r6} + subs r2, r2, #16 + bge 16b + adds r2, r2, #12 + blt 18f +17: mov r3, r7, pull #24 + ldr r7, [r1], #4 + subs r2, r2, #4 + orr r3, r3, r7, push #8 + str r3, [r0], #4 + bge 17b +18: sub r1, r1, #1 + b 6b + + +19: add r1, r1, r2 + add r0, r0, r2 + subs r2, r2, #4 + blt 24f + ands ip, r0, #3 + bne 25f + ands ip, r1, #3 + bne 26f + +20: subs r2, r2, #8 + blt 23f + subs r2, r2, #0x14 + blt 22f +21: ldmdb r1!, {r3 - r9, ip} + stmdb r0!, {r3 - r9, ip} + subs r2, r2, #32 + bge 21b +22: cmn r2, #16 + ldmgedb r1!, {r3 - r6} + stmgedb r0!, {r3 - r6} + subge r2, r2, #16 + adds r2, r2, #20 + ldmgedb r1!, {r3 - r5} + stmgedb r0!, {r3 - r5} + subge r2, r2, #12 +23: adds r2, r2, #8 + blt 24f + subs r2, r2, #4 + ldrlt r3, [r1, #-4]! + ldmgedb r1!, {r4, r5} + strlt r3, [r0, #-4]! + stmgedb r0!, {r4, r5} + subge r2, r2, #4 + +24: adds r2, r2, #4 + EXITEQ + cmp r2, #2 + ldrb r3, [r1, #-1]! + ldrgeb r4, [r1, #-1]! + ldrgtb r5, [r1, #-1]! + strb r3, [r0, #-1]! + strgeb r4, [r0, #-1]! + strgtb r5, [r0, #-1]! + EXIT + +25: cmp ip, #2 + ldrb r3, [r1, #-1]! + ldrgeb r4, [r1, #-1]! + ldrgtb r5, [r1, #-1]! + strb r3, [r0, #-1]! + strgeb r4, [r0, #-1]! + strgtb r5, [r0, #-1]! + subs r2, r2, ip + blt 24b + ands ip, r1, #3 + beq 20b + +26: bic r1, r1, #3 + ldr r3, [r1], #0 + cmp ip, #2 + blt 34f + beq 30f + cmp r2, #12 + blt 28f + sub r2, r2, #12 +27: mov r7, r3, push #8 + ldmdb r1!, {r3, r4, r5, r6} + orr r7, r7, r6, pull #24 + mov r6, r6, push #8 + orr r6, r6, r5, pull #24 + mov r5, r5, push #8 + orr r5, r5, r4, pull #24 + mov r4, r4, push #8 + orr r4, r4, r3, pull #24 + stmdb r0!, {r4, r5, r6, r7} + subs r2, r2, #16 + bge 27b + adds r2, r2, #12 + blt 29f +28: mov ip, r3, push #8 + ldr r3, [r1, #-4]! + subs r2, r2, #4 + orr ip, ip, r3, pull #24 + str ip, [r0, #-4]! + bge 28b +29: add r1, r1, #3 + b 24b + +30: cmp r2, #12 + blt 32f + sub r2, r2, #12 +31: mov r7, r3, push #16 + ldmdb r1!, {r3, r4, r5, r6} + orr r7, r7, r6, pull #16 + mov r6, r6, push #16 + orr r6, r6, r5, pull #16 + mov r5, r5, push #16 + orr r5, r5, r4, pull #16 + mov r4, r4, push #16 + orr r4, r4, r3, pull #16 + stmdb r0!, {r4, r5, r6, r7} + subs r2, r2, #16 + bge 31b + adds r2, r2, #12 + blt 33f +32: mov ip, r3, push #16 + ldr r3, [r1, #-4]! + subs r2, r2, #4 + orr ip, ip, r3, pull #16 + str ip, [r0, #-4]! + bge 32b +33: add r1, r1, #2 + b 24b + +34: cmp r2, #12 + blt 36f + sub r2, r2, #12 +35: mov r7, r3, push #24 + ldmdb r1!, {r3, r4, r5, r6} + orr r7, r7, r6, pull #8 + mov r6, r6, push #24 + orr r6, r6, r5, pull #8 + mov r5, r5, push #24 + orr r5, r5, r4, pull #8 + mov r4, r4, push #24 + orr r4, r4, r3, pull #8 + stmdb r0!, {r4, r5, r6, r7} + subs r2, r2, #16 + bge 35b + adds r2, r2, #12 + blt 37f +36: mov ip, r3, push #24 + ldr r3, [r1, #-4]! + subs r2, r2, #4 + orr ip, ip, r3, pull #8 + str ip, [r0, #-4]! + bge 36b +37: add r1, r1, #1 + b 24b + + .align diff -Nru a/arch/arm26/lib/memset.S b/arch/arm26/lib/memset.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/memset.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,80 @@ +/* + * linux/arch/arm/lib/memset.S + * + * Copyright (C) 1995-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ASM optimised string functions + */ +#include <linux/linkage.h> +#include <asm/assembler.h> + + .text + .align 5 + .word 0 + +1: subs r2, r2, #4 @ 1 do we have enough + blt 5f @ 1 bytes to align with? + cmp r3, #2 @ 1 + strltb r1, [r0], #1 @ 1 + strleb r1, [r0], #1 @ 1 + strb r1, [r0], #1 @ 1 + add r2, r2, r3 @ 1 (r2 = r2 - (4 - r3)) +/* + * The pointer is now aligned and the length is adjusted. Try doing the + * memzero again. + */ + +ENTRY(memset) + ands r3, r0, #3 @ 1 unaligned? + bne 1b @ 1 +/* + * we know that the pointer in r0 is aligned to a word boundary. + */ + orr r1, r1, r1, lsl #8 + orr r1, r1, r1, lsl #16 + mov r3, r1 + cmp r2, #16 + blt 4f +/* + * We need an extra register for this loop - save the return address and + * use the LR + */ + str lr, [sp, #-4]! + mov ip, r1 + mov lr, r1 + +2: subs r2, r2, #64 + stmgeia r0!, {r1, r3, ip, lr} @ 64 bytes at a time. + stmgeia r0!, {r1, r3, ip, lr} + stmgeia r0!, {r1, r3, ip, lr} + stmgeia r0!, {r1, r3, ip, lr} + bgt 2b + LOADREGS(eqfd, sp!, {pc}) @ Now <64 bytes to go. +/* + * No need to correct the count; we're only testing bits from now on + */ + tst r2, #32 + stmneia r0!, {r1, r3, ip, lr} + stmneia r0!, {r1, r3, ip, lr} + tst r2, #16 + stmneia r0!, {r1, r3, ip, lr} + ldr lr, [sp], #4 + +4: tst r2, #8 + stmneia r0!, {r1, r3} + tst r2, #4 + strne r1, [r0], #4 +/* + * When we get here, we've got less than 4 bytes to zero. We + * may have an unaligned pointer as well. + */ +5: tst r2, #2 + strneb r1, [r0], #1 + strneb r1, [r0], #1 + tst r2, #1 + strneb r1, [r0], #1 + RETINSTR(mov,pc,lr) diff -Nru a/arch/arm26/lib/memzero.S b/arch/arm26/lib/memzero.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/memzero.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,80 @@ +/* + * linux/arch/arm/lib/memzero.S + * + * Copyright (C) 1995-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> + + .text + .align 5 + .word 0 +/* + * Align the pointer in r0. r3 contains the number of bytes that we are + * mis-aligned by, and r1 is the number of bytes. If r1 < 4, then we + * don't bother; we use byte stores instead. + */ +1: subs r1, r1, #4 @ 1 do we have enough + blt 5f @ 1 bytes to align with? + cmp r3, #2 @ 1 + strltb r2, [r0], #1 @ 1 + strleb r2, [r0], #1 @ 1 + strb r2, [r0], #1 @ 1 + add r1, r1, r3 @ 1 (r1 = r1 - (4 - r3)) +/* + * The pointer is now aligned and the length is adjusted. Try doing the + * memzero again. + */ + +ENTRY(__memzero) + mov r2, #0 @ 1 + ands r3, r0, #3 @ 1 unaligned? + bne 1b @ 1 +/* + * r3 = 0, and we know that the pointer in r0 is aligned to a word boundary. + */ + cmp r1, #16 @ 1 we can skip this chunk if we + blt 4f @ 1 have < 16 bytes +/* + * We need an extra register for this loop - save the return address and + * use the LR + */ + str lr, [sp, #-4]! @ 1 + mov ip, r2 @ 1 + mov lr, r2 @ 1 + +3: subs r1, r1, #64 @ 1 write 32 bytes out per loop + stmgeia r0!, {r2, r3, ip, lr} @ 4 + stmgeia r0!, {r2, r3, ip, lr} @ 4 + stmgeia r0!, {r2, r3, ip, lr} @ 4 + stmgeia r0!, {r2, r3, ip, lr} @ 4 + bgt 3b @ 1 + LOADREGS(eqfd, sp!, {pc}) @ 1/2 quick exit +/* + * No need to correct the count; we're only testing bits from now on + */ + tst r1, #32 @ 1 + stmneia r0!, {r2, r3, ip, lr} @ 4 + stmneia r0!, {r2, r3, ip, lr} @ 4 + tst r1, #16 @ 1 16 bytes or more? + stmneia r0!, {r2, r3, ip, lr} @ 4 + ldr lr, [sp], #4 @ 1 + +4: tst r1, #8 @ 1 8 bytes or more? + stmneia r0!, {r2, r3} @ 2 + tst r1, #4 @ 1 4 bytes or more? + strne r2, [r0], #4 @ 1 +/* + * When we get here, we've got less than 4 bytes to zero. We + * may have an unaligned pointer as well. + */ +5: tst r1, #2 @ 1 2 bytes or more? + strneb r2, [r0], #1 @ 1 + strneb r2, [r0], #1 @ 1 + tst r1, #1 @ 1 a byte left over + strneb r2, [r0], #1 @ 1 + RETINSTR(mov,pc,lr) @ 1 diff -Nru a/arch/arm26/lib/muldi3.c b/arch/arm26/lib/muldi3.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/muldi3.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,77 @@ +/* More subroutines needed by GCC output code on some machines. */ +/* Compile this one with gcc. */ +/* 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. */ + +/* As a special exception, if you link this library with other files, + some of which are compiled with GCC, to produce an executable, + this library does not by itself cause the resulting executable + to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. + */ +/* support functions required by the kernel. based on code from gcc-2.95.3 */ +/* I Molton 29/07/01 */ + +#include "gcclib.h" + +#define umul_ppmm(xh, xl, a, b) \ +{register USItype __t0, __t1, __t2; \ + __asm__ ("%@ Inlined umul_ppmm \n\ + mov %2, %5, lsr #16 \n\ + mov %0, %6, lsr #16 \n\ + bic %3, %5, %2, lsl #16 \n\ + bic %4, %6, %0, lsl #16 \n\ + mul %1, %3, %4 \n\ + mul %4, %2, %4 \n\ + mul %3, %0, %3 \n\ + mul %0, %2, %0 \n\ + adds %3, %4, %3 \n\ + addcs %0, %0, #65536 \n\ + adds %1, %1, %3, lsl #16 \n\ + adc %0, %0, %3, lsr #16" \ + : "=&r" ((USItype) (xh)), \ + "=r" ((USItype) (xl)), \ + "=&r" (__t0), "=&r" (__t1), "=r" (__t2) \ + : "r" ((USItype) (a)), \ + "r" ((USItype) (b)));} + + +#define __umulsidi3(u, v) \ + ({DIunion __w; \ + umul_ppmm (__w.s.high, __w.s.low, u, v); \ + __w.ll; }) + + +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 -Nru a/arch/arm26/lib/putuser.S b/arch/arm26/lib/putuser.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/putuser.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,108 @@ +/* + * linux/arch/arm/lib/putuser.S + * + * Copyright (C) 2001 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Idea from x86 version, (C) Copyright 1998 Linus Torvalds + * + * These functions have a non-standard call interface to make + * them more efficient, especially as they return an error + * value in addition to the "real" return value. + * + * __put_user_X + * + * Inputs: r0 contains the address + * r1, r2 contains the value + * Outputs: r0 is the error code + * lr corrupted + * + * No other registers must be altered. (see include/asm-arm/uaccess.h + * for specific ASM register usage). + * + * Note that ADDR_LIMIT is either 0 or 0xc0000000 + * Note also that it is intended that __put_user_bad is not global. + */ +#include <asm/asm_offsets.h> +#include <asm/thread_info.h> + + .global __put_user_1 +__put_user_1: + bic r2, sp, #0x1f00 + bic r2, r2, #0x00ff + str lr, [sp, #-4]! + ldr r2, [r2, #TI_ADDR_LIMIT] + sub r2, r2, #1 + cmp r0, r2 + bge __put_user_bad +1: cmp r0, #0x02000000 + strlsbt r1, [r0] + strgeb r1, [r0] + mov r0, #0 + ldmfd sp!, {pc}^ + + .global __put_user_2 +__put_user_2: + bic r2, sp, #0x1f00 + bic r2, r2, #0x00ff + str lr, [sp, #-4]! + ldr r2, [r2, #TI_ADDR_LIMIT] + sub r2, r2, #2 + cmp r0, r2 + bge __put_user_bad +2: cmp r0, #0x02000000 + strlsbt r1, [r0], #1 + strgeb r1, [r0], #1 + mov r1, r1, lsr #8 +3: strlsbt r1, [r0] + strgeb r1, [r0] + mov r0, #0 + ldmfd sp!, {pc}^ + + .global __put_user_4 +__put_user_4: + bic r2, sp, #0x1f00 + bic r2, r2, #0x00ff + str lr, [sp, #-4]! + ldr r2, [r2, #TI_ADDR_LIMIT] + sub r2, r2, #4 + cmp r0, r2 +4: bge __put_user_bad + cmp r0, #0x02000000 + strlst r1, [r0] + strge r1, [r0] + mov r0, #0 + ldmfd sp!, {pc}^ + + .global __put_user_8 +__put_user_8: + bic ip, sp, #0x1f00 + bic ip, ip, #0x00ff + str lr, [sp, #-4]! + ldr ip, [ip, #TI_ADDR_LIMIT] + sub ip, ip, #8 + cmp r0, ip + bge __put_user_bad + cmp r0, #0x02000000 +5: strlst r1, [r0], #4 +6: strlst r2, [r0] + strge r1, [r0], #4 + strge r2, [r0] + mov r0, #0 + ldmfd sp!, {pc}^ + +__put_user_bad: + mov r0, #-14 + mov pc, lr + +.section __ex_table, "a" + .long 1b, __put_user_bad + .long 2b, __put_user_bad + .long 3b, __put_user_bad + .long 4b, __put_user_bad + .long 5b, __put_user_bad + .long 6b, __put_user_bad +.previous diff -Nru a/arch/arm26/lib/setbit.S b/arch/arm26/lib/setbit.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/setbit.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,29 @@ +/* + * linux/arch/arm/lib/setbit.S + * + * Copyright (C) 1995-1996 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> + .text + +/* + * Purpose : Function to set a bit + * Prototype: int set_bit(int bit, void *addr) + */ +ENTRY(_set_bit_be) + eor r0, r0, #0x18 @ big endian byte ordering +ENTRY(_set_bit_le) + and r2, r0, #7 + mov r3, #1 + mov r3, r3, lsl r2 + save_and_disable_irqs ip, r2 + ldrb r2, [r1, r0, lsr #3] + orr r2, r2, r3 + strb r2, [r1, r0, lsr #3] + restore_irqs ip + RETINSTR(mov,pc,lr) diff -Nru a/arch/arm26/lib/strchr.S b/arch/arm26/lib/strchr.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/strchr.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,25 @@ +/* + * linux/arch/arm/lib/strchr.S + * + * Copyright (C) 1995-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ASM optimised string functions + */ +#include <linux/linkage.h> +#include <asm/assembler.h> + + .text + .align 5 +ENTRY(strchr) +1: ldrb r2, [r0], #1 + teq r2, r1 + teqne r2, #0 + bne 1b + teq r2, #0 + moveq r0, #0 + subne r0, r0, #1 + RETINSTR(mov,pc,lr) diff -Nru a/arch/arm26/lib/strrchr.S b/arch/arm26/lib/strrchr.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/strrchr.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,25 @@ +/* + * linux/arch/arm/lib/strrchr.S + * + * Copyright (C) 1995-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ASM optimised string functions + */ +#include <linux/linkage.h> +#include <asm/assembler.h> + + .text + .align 5 +ENTRY(strrchr) + mov r3, #0 +1: ldrb r2, [r0], #1 + teq r2, r1 + subeq r3, r0, #1 + teq r2, #0 + bne 1b + mov r0, r3 + RETINSTR(mov,pc,lr) diff -Nru a/arch/arm26/lib/testchangebit.S b/arch/arm26/lib/testchangebit.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/testchangebit.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,29 @@ +/* + * linux/arch/arm/lib/testchangebit.S + * + * Copyright (C) 1995-1996 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> + .text + +ENTRY(_test_and_change_bit_be) + eor r0, r0, #0x18 @ big endian byte ordering +ENTRY(_test_and_change_bit_le) + add r1, r1, r0, lsr #3 + and r3, r0, #7 + mov r0, #1 + save_and_disable_irqs ip, r2 + ldrb r2, [r1] + tst r2, r0, lsl r3 + eor r2, r2, r0, lsl r3 + strb r2, [r1] + restore_irqs ip + moveq r0, #0 + RETINSTR(mov,pc,lr) + + diff -Nru a/arch/arm26/lib/testclearbit.S b/arch/arm26/lib/testclearbit.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/testclearbit.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,29 @@ +/* + * linux/arch/arm/lib/testclearbit.S + * + * Copyright (C) 1995-1996 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> + .text + +ENTRY(_test_and_clear_bit_be) + eor r0, r0, #0x18 @ big endian byte ordering +ENTRY(_test_and_clear_bit_le) + add r1, r1, r0, lsr #3 @ Get byte offset + and r3, r0, #7 @ Get bit offset + mov r0, #1 + save_and_disable_irqs ip, r2 + ldrb r2, [r1] + tst r2, r0, lsl r3 + bic r2, r2, r0, lsl r3 + strb r2, [r1] + restore_irqs ip + moveq r0, #0 + RETINSTR(mov,pc,lr) + + diff -Nru a/arch/arm26/lib/testsetbit.S b/arch/arm26/lib/testsetbit.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/testsetbit.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,29 @@ +/* + * linux/arch/arm/lib/testsetbit.S + * + * Copyright (C) 1995-1996 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> + .text + +ENTRY(_test_and_set_bit_be) + eor r0, r0, #0x18 @ big endian byte ordering +ENTRY(_test_and_set_bit_le) + add r1, r1, r0, lsr #3 @ Get byte offset + and r3, r0, #7 @ Get bit offset + mov r0, #1 + save_and_disable_irqs ip, r2 + ldrb r2, [r1] + tst r2, r0, lsl r3 + orr r2, r2, r0, lsl r3 + strb r2, [r1] + restore_irqs ip + moveq r0, #0 + RETINSTR(mov,pc,lr) + + diff -Nru a/arch/arm26/lib/uaccess-kernel.S b/arch/arm26/lib/uaccess-kernel.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/uaccess-kernel.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,173 @@ +/* + * linux/arch/arm26/lib/uaccess-kernel.S + * + * Copyright (C) 1998 Russell King + * + * Note! Some code fragments found in here have a special calling + * convention - they are not APCS compliant! + * + * This program is free software; you can 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/linkage.h> +#include <asm/assembler.h> + + .text + +//FIXME - surely this can be done in C not asm, removing the problem of keeping C and asm in sync? (this is a struct uaccess_t) + + .globl uaccess_kernel +uaccess_kernel: + .word uaccess_kernel_put_byte + .word uaccess_kernel_get_byte + .word uaccess_kernel_put_half + .word uaccess_kernel_get_half + .word uaccess_kernel_put_word + .word uaccess_kernel_get_word + .word uaccess_kernel_put_dword + .word uaccess_kernel_copy + .word uaccess_kernel_copy + .word uaccess_kernel_clear + .word uaccess_kernel_strncpy + .word uaccess_kernel_strnlen + +@ In : r0 = x, r1 = addr, r2 = error +@ Out: r2 = error +uaccess_kernel_put_byte: + stmfd sp!, {lr} + strb r0, [r1] + ldmfd sp!, {pc}^ + +@ In : r0 = x, r1 = addr, r2 = error +@ Out: r2 = error +uaccess_kernel_put_half: + stmfd sp!, {lr} + strb r0, [r1] + mov r0, r0, lsr #8 + strb r0, [r1, #1] + ldmfd sp!, {pc}^ + +@ In : r0 = x, r1 = addr, r2 = error +@ Out: r2 = error +uaccess_kernel_put_word: + stmfd sp!, {lr} + str r0, [r1] + ldmfd sp!, {pc}^ + +@ In : r0 = x, r1 = addr, r2 = error +@ Out: r2 = error +uaccess_kernel_put_dword: + stmfd sp!, {lr} + str r0, [r1], #4 + str r0, [r1], #0 + ldmfd sp!, {pc}^ + +@ In : r0 = addr, r1 = error +@ Out: r0 = x, r1 = error +uaccess_kernel_get_byte: + stmfd sp!, {lr} + ldrb r0, [r0] + ldmfd sp!, {pc}^ + +@ In : r0 = addr, r1 = error +@ Out: r0 = x, r1 = error +uaccess_kernel_get_half: + stmfd sp!, {lr} + ldr r0, [r0] + mov r0, r0, lsl #16 + mov r0, r0, lsr #16 + ldmfd sp!, {pc}^ + +@ In : r0 = addr, r1 = error +@ Out: r0 = x, r1 = error +uaccess_kernel_get_word: + stmfd sp!, {lr} + ldr r0, [r0] + ldmfd sp!, {pc}^ + + +/* Prototype: int uaccess_kernel_copy(void *to, const char *from, size_t n) + * Purpose : copy a block to kernel memory from kernel memory + * Params : to - kernel memory + * : from - kernel memory + * : n - number of bytes to copy + * Returns : Number of bytes NOT copied. + */ +uaccess_kernel_copy: + stmfd sp!, {lr} + bl memcpy + mov r0, #0 + ldmfd sp!, {pc}^ + +/* Prototype: int uaccess_kernel_clear(void *addr, size_t sz) + * Purpose : clear some kernel memory + * Params : addr - kernel memory address to clear + * : sz - number of bytes to clear + * Returns : number of bytes NOT cleared + */ +uaccess_kernel_clear: + stmfd sp!, {lr} + mov r2, #0 + cmp r1, #4 + blt 2f + ands ip, r0, #3 + beq 1f + cmp ip, #1 + strb r2, [r0], #1 + strleb r2, [r0], #1 + strltb r2, [r0], #1 + rsb ip, ip, #4 + sub r1, r1, ip @ 7 6 5 4 3 2 1 +1: subs r1, r1, #8 @ -1 -2 -3 -4 -5 -6 -7 + bmi 2f + str r2, [r0], #4 + str r2, [r0], #4 + b 1b +2: adds r1, r1, #4 @ 3 2 1 0 -1 -2 -3 + strpl r2, [r0], #4 + tst r1, #2 @ 1x 1x 0x 0x 1x 1x 0x + strneb r2, [r0], #1 + strneb r2, [r0], #1 + tst r1, #1 @ x1 x0 x1 x0 x1 x0 x1 + strneb r2, [r0], #1 + mov r0, #0 + ldmfd sp!, {pc}^ + +/* Prototype: size_t uaccess_kernel_strncpy(char *dst, char *src, size_t len) + * Purpose : copy a string from kernel memory to kernel memory + * Params : dst - kernel memory destination + * : src - kernel memory source + * : len - maximum length of string + * Returns : number of characters copied + */ +uaccess_kernel_strncpy: + stmfd sp!, {lr} + mov ip, r2 +1: subs r2, r2, #1 + bmi 2f + ldrb r3, [r1], #1 + strb r3, [r0], #1 + teq r3, #0 + bne 1b +2: subs r0, ip, r2 + ldmfd sp!, {pc}^ + +/* Prototype: int uaccess_kernel_strlen(char *str, long n) + * Purpose : get length of a string in kernel memory + * Params : str - address of string in kernel memory + * Returns : length of string *including terminator*, + * or zero on exception, or n + 1 if too long + */ +uaccess_kernel_strnlen: + stmfd sp!, {lr} + mov r2, r0 +1: ldrb r1, [r0], #1 + teq r1, #0 + beq 2f + subs r1, r1, #1 + bne 1b + add r0, r0, #1 +2: sub r0, r0, r2 + ldmfd sp!, {pc}^ + diff -Nru a/arch/arm26/lib/uaccess-user.S b/arch/arm26/lib/uaccess-user.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/uaccess-user.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,718 @@ +/* + * linux/arch/arm26/lib/uaccess-user.S + * + * Copyright (C) 1995, 1996,1997,1998 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Routines to block copy data to/from user memory + * These are highly optimised both for the 4k page size + * and for various alignments. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/errno.h> +#include <asm/page.h> + + .text + +//FIXME - surely this can be done in C not asm, removing the problem of keeping C and asm in sync? (this is a struct uaccess_t) + .globl uaccess_user +uaccess_user: + .word uaccess_user_put_byte + .word uaccess_user_get_byte + .word uaccess_user_put_half + .word uaccess_user_get_half + .word uaccess_user_put_word + .word uaccess_user_get_word + .word uaccess_user_put_dword + .word uaccess_user_copy_from_user + .word uaccess_user_copy_to_user + .word uaccess_user_clear_user + .word uaccess_user_strncpy_from_user + .word uaccess_user_strnlen_user + + +@ In : r0 = x, r1 = addr, r2 = error +@ Out: r2 = error +uaccess_user_put_byte: + stmfd sp!, {lr} +USER( strbt r0, [r1]) + ldmfd sp!, {pc}^ + +@ In : r0 = x, r1 = addr, r2 = error +@ Out: r2 = error +uaccess_user_put_half: + stmfd sp!, {lr} +USER( strbt r0, [r1], #1) + mov r0, r0, lsr #8 +USER( strbt r0, [r1]) + ldmfd sp!, {pc}^ + +@ In : r0 = x, r1 = addr, r2 = error +@ Out: r2 = error +uaccess_user_put_word: + stmfd sp!, {lr} +USER( strt r0, [r1]) + ldmfd sp!, {pc}^ + +@ In : r0 = x, r1 = addr, r2 = error +@ Out: r2 = error +uaccess_user_put_dword: + stmfd sp!, {lr} +USER( strt r0, [r1], #4) +USER( strt r0, [r1], #0) + ldmfd sp!, {pc}^ + +9001: mov r2, #-EFAULT + ldmfd sp!, {pc}^ + + +@ In : r0 = addr, r1 = error +@ Out: r0 = x, r1 = error +uaccess_user_get_byte: + stmfd sp!, {lr} +USER( ldrbt r0, [r0]) + ldmfd sp!, {pc}^ + +@ In : r0 = addr, r1 = error +@ Out: r0 = x, r1 = error +uaccess_user_get_half: + stmfd sp!, {lr} +USER( ldrt r0, [r0]) + mov r0, r0, lsl #16 + mov r0, r0, lsr #16 + ldmfd sp!, {pc}^ + +@ In : r0 = addr, r1 = error +@ Out: r0 = x, r1 = error +uaccess_user_get_word: + stmfd sp!, {lr} +USER( ldrt r0, [r0]) + ldmfd sp!, {pc}^ + +9001: mov r1, #-EFAULT + ldmfd sp!, {pc}^ + +/* Prototype: int uaccess_user_copy_to_user(void *to, const char *from, size_t n) + * Purpose : copy a block to user memory from kernel memory + * Params : to - user memory + * : from - kernel memory + * : n - number of bytes to copy + * Returns : Number of bytes NOT copied. + */ + +.c2u_dest_not_aligned: + rsb ip, ip, #4 + cmp ip, #2 + ldrb r3, [r1], #1 +USER( strbt r3, [r0], #1) @ May fault + ldrgeb r3, [r1], #1 +USER( strgebt r3, [r0], #1) @ May fault + ldrgtb r3, [r1], #1 +USER( strgtbt r3, [r0], #1) @ May fault + sub r2, r2, ip + b .c2u_dest_aligned + +ENTRY(uaccess_user_copy_to_user) + stmfd sp!, {r2, r4 - r7, lr} + cmp r2, #4 + blt .c2u_not_enough + ands ip, r0, #3 + bne .c2u_dest_not_aligned +.c2u_dest_aligned: + + ands ip, r1, #3 + bne .c2u_src_not_aligned +/* + * Seeing as there has to be at least 8 bytes to copy, we can + * copy one word, and force a user-mode page fault... + */ + +.c2u_0fupi: subs r2, r2, #4 + addmi ip, r2, #4 + bmi .c2u_0nowords + ldr r3, [r1], #4 +USER( strt r3, [r0], #4) @ May fault + mov ip, r0, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction + rsb ip, ip, #0 + movs ip, ip, lsr #32 - PAGE_SHIFT + beq .c2u_0fupi +/* + * ip = max no. of bytes to copy before needing another "strt" insn + */ + cmp r2, ip + movlt ip, r2 + sub r2, r2, ip + subs ip, ip, #32 + blt .c2u_0rem8lp + +.c2u_0cpy8lp: ldmia r1!, {r3 - r6} + stmia r0!, {r3 - r6} @ Shouldnt fault + ldmia r1!, {r3 - r6} + stmia r0!, {r3 - r6} @ Shouldnt fault + subs ip, ip, #32 + bpl .c2u_0cpy8lp +.c2u_0rem8lp: cmn ip, #16 + ldmgeia r1!, {r3 - r6} + stmgeia r0!, {r3 - r6} @ Shouldnt fault + tst ip, #8 + ldmneia r1!, {r3 - r4} + stmneia r0!, {r3 - r4} @ Shouldnt fault + tst ip, #4 + ldrne r3, [r1], #4 + strnet r3, [r0], #4 @ Shouldnt fault + ands ip, ip, #3 + beq .c2u_0fupi +.c2u_0nowords: teq ip, #0 + beq .c2u_finished +.c2u_nowords: cmp ip, #2 + ldrb r3, [r1], #1 +USER( strbt r3, [r0], #1) @ May fault + ldrgeb r3, [r1], #1 +USER( strgebt r3, [r0], #1) @ May fault + ldrgtb r3, [r1], #1 +USER( strgtbt r3, [r0], #1) @ May fault + b .c2u_finished + +.c2u_not_enough: + movs ip, r2 + bne .c2u_nowords +.c2u_finished: mov r0, #0 + LOADREGS(fd,sp!,{r2, r4 - r7, pc}) + +.c2u_src_not_aligned: + bic r1, r1, #3 + ldr r7, [r1], #4 + cmp ip, #2 + bgt .c2u_3fupi + beq .c2u_2fupi +.c2u_1fupi: subs r2, r2, #4 + addmi ip, r2, #4 + bmi .c2u_1nowords + mov r3, r7, pull #8 + ldr r7, [r1], #4 + orr r3, r3, r7, push #24 +USER( strt r3, [r0], #4) @ May fault + mov ip, r0, lsl #32 - PAGE_SHIFT + rsb ip, ip, #0 + movs ip, ip, lsr #32 - PAGE_SHIFT + beq .c2u_1fupi + cmp r2, ip + movlt ip, r2 + sub r2, r2, ip + subs ip, ip, #16 + blt .c2u_1rem8lp + +.c2u_1cpy8lp: mov r3, r7, pull #8 + ldmia r1!, {r4 - r7} + orr r3, r3, r4, push #24 + mov r4, r4, pull #8 + orr r4, r4, r5, push #24 + mov r5, r5, pull #8 + orr r5, r5, r6, push #24 + mov r6, r6, pull #8 + orr r6, r6, r7, push #24 + stmia r0!, {r3 - r6} @ Shouldnt fault + subs ip, ip, #16 + bpl .c2u_1cpy8lp +.c2u_1rem8lp: tst ip, #8 + movne r3, r7, pull #8 + ldmneia r1!, {r4, r7} + orrne r3, r3, r4, push #24 + movne r4, r4, pull #8 + orrne r4, r4, r7, push #24 + stmneia r0!, {r3 - r4} @ Shouldnt fault + tst ip, #4 + movne r3, r7, pull #8 + ldrne r7, [r1], #4 + orrne r3, r3, r7, push #24 + strnet r3, [r0], #4 @ Shouldnt fault + ands ip, ip, #3 + beq .c2u_1fupi +.c2u_1nowords: mov r3, r7, lsr #byte(1) + teq ip, #0 + beq .c2u_finished + cmp ip, #2 +USER( strbt r3, [r0], #1) @ May fault + movge r3, r7, lsr #byte(2) +USER( strgebt r3, [r0], #1) @ May fault + movgt r3, r7, lsr #byte(3) +USER( strgtbt r3, [r0], #1) @ May fault + b .c2u_finished + +.c2u_2fupi: subs r2, r2, #4 + addmi ip, r2, #4 + bmi .c2u_2nowords + mov r3, r7, pull #16 + ldr r7, [r1], #4 + orr r3, r3, r7, push #16 +USER( strt r3, [r0], #4) @ May fault + mov ip, r0, lsl #32 - PAGE_SHIFT + rsb ip, ip, #0 + movs ip, ip, lsr #32 - PAGE_SHIFT + beq .c2u_2fupi + cmp r2, ip + movlt ip, r2 + sub r2, r2, ip + subs ip, ip, #16 + blt .c2u_2rem8lp + +.c2u_2cpy8lp: mov r3, r7, pull #16 + ldmia r1!, {r4 - r7} + orr r3, r3, r4, push #16 + mov r4, r4, pull #16 + orr r4, r4, r5, push #16 + mov r5, r5, pull #16 + orr r5, r5, r6, push #16 + mov r6, r6, pull #16 + orr r6, r6, r7, push #16 + stmia r0!, {r3 - r6} @ Shouldnt fault + subs ip, ip, #16 + bpl .c2u_2cpy8lp +.c2u_2rem8lp: tst ip, #8 + movne r3, r7, pull #16 + ldmneia r1!, {r4, r7} + orrne r3, r3, r4, push #16 + movne r4, r4, pull #16 + orrne r4, r4, r7, push #16 + stmneia r0!, {r3 - r4} @ Shouldnt fault + tst ip, #4 + movne r3, r7, pull #16 + ldrne r7, [r1], #4 + orrne r3, r3, r7, push #16 + strnet r3, [r0], #4 @ Shouldnt fault + ands ip, ip, #3 + beq .c2u_2fupi +.c2u_2nowords: mov r3, r7, lsr #byte(2) + teq ip, #0 + beq .c2u_finished + cmp ip, #2 +USER( strbt r3, [r0], #1) @ May fault + movge r3, r7, lsr #byte(3) +USER( strgebt r3, [r0], #1) @ May fault + ldrgtb r3, [r1], #0 +USER( strgtbt r3, [r0], #1) @ May fault + b .c2u_finished + +.c2u_3fupi: subs r2, r2, #4 + addmi ip, r2, #4 + bmi .c2u_3nowords + mov r3, r7, pull #24 + ldr r7, [r1], #4 + orr r3, r3, r7, push #8 +USER( strt r3, [r0], #4) @ May fault + mov ip, r0, lsl #32 - PAGE_SHIFT + rsb ip, ip, #0 + movs ip, ip, lsr #32 - PAGE_SHIFT + beq .c2u_3fupi + cmp r2, ip + movlt ip, r2 + sub r2, r2, ip + subs ip, ip, #16 + blt .c2u_3rem8lp + +.c2u_3cpy8lp: mov r3, r7, pull #24 + ldmia r1!, {r4 - r7} + orr r3, r3, r4, push #8 + mov r4, r4, pull #24 + orr r4, r4, r5, push #8 + mov r5, r5, pull #24 + orr r5, r5, r6, push #8 + mov r6, r6, pull #24 + orr r6, r6, r7, push #8 + stmia r0!, {r3 - r6} @ Shouldnt fault + subs ip, ip, #16 + bpl .c2u_3cpy8lp +.c2u_3rem8lp: tst ip, #8 + movne r3, r7, pull #24 + ldmneia r1!, {r4, r7} + orrne r3, r3, r4, push #8 + movne r4, r4, pull #24 + orrne r4, r4, r7, push #8 + stmneia r0!, {r3 - r4} @ Shouldnt fault + tst ip, #4 + movne r3, r7, pull #24 + ldrne r7, [r1], #4 + orrne r3, r3, r7, push #8 + strnet r3, [r0], #4 @ Shouldnt fault + ands ip, ip, #3 + beq .c2u_3fupi +.c2u_3nowords: mov r3, r7, lsr #byte(3) + teq ip, #0 + beq .c2u_finished + cmp ip, #2 +USER( strbt r3, [r0], #1) @ May fault + ldrgeb r3, [r1], #1 +USER( strgebt r3, [r0], #1) @ May fault + ldrgtb r3, [r1], #0 +USER( strgtbt r3, [r0], #1) @ May fault + b .c2u_finished + + .section .fixup,"ax" + .align 0 +9001: LOADREGS(fd,sp!, {r0, r4 - r7, pc}) + .previous + +/* Prototype: unsigned long uaccess_user_copy_from_user(void *to,const void *from,unsigned long n); + * Purpose : copy a block from user memory to kernel memory + * Params : to - kernel memory + * : from - user memory + * : n - number of bytes to copy + * Returns : Number of bytes NOT copied. + */ +.cfu_dest_not_aligned: + rsb ip, ip, #4 + cmp ip, #2 +USER( ldrbt r3, [r1], #1) @ May fault + strb r3, [r0], #1 +USER( ldrgebt r3, [r1], #1) @ May fault + strgeb r3, [r0], #1 +USER( ldrgtbt r3, [r1], #1) @ May fault + strgtb r3, [r0], #1 + sub r2, r2, ip + b .cfu_dest_aligned + +ENTRY(uaccess_user_copy_from_user) + stmfd sp!, {r0, r2, r4 - r7, lr} + cmp r2, #4 + blt .cfu_not_enough + ands ip, r0, #3 + bne .cfu_dest_not_aligned +.cfu_dest_aligned: + ands ip, r1, #3 + bne .cfu_src_not_aligned +/* + * Seeing as there has to be at least 8 bytes to copy, we can + * copy one word, and force a user-mode page fault... + */ + +.cfu_0fupi: subs r2, r2, #4 + addmi ip, r2, #4 + bmi .cfu_0nowords +USER( ldrt r3, [r1], #4) + str r3, [r0], #4 + mov ip, r1, lsl #32 - PAGE_SHIFT @ On each page, use a ld/st??t instruction + rsb ip, ip, #0 + movs ip, ip, lsr #32 - PAGE_SHIFT + beq .cfu_0fupi +/* + * ip = max no. of bytes to copy before needing another "strt" insn + */ + cmp r2, ip + movlt ip, r2 + sub r2, r2, ip + subs ip, ip, #32 + blt .cfu_0rem8lp + +.cfu_0cpy8lp: ldmia r1!, {r3 - r6} @ Shouldnt fault + stmia r0!, {r3 - r6} + ldmia r1!, {r3 - r6} @ Shouldnt fault + stmia r0!, {r3 - r6} + subs ip, ip, #32 + bpl .cfu_0cpy8lp +.cfu_0rem8lp: cmn ip, #16 + ldmgeia r1!, {r3 - r6} @ Shouldnt fault + stmgeia r0!, {r3 - r6} + tst ip, #8 + ldmneia r1!, {r3 - r4} @ Shouldnt fault + stmneia r0!, {r3 - r4} + tst ip, #4 + ldrnet r3, [r1], #4 @ Shouldnt fault + strne r3, [r0], #4 + ands ip, ip, #3 + beq .cfu_0fupi +.cfu_0nowords: teq ip, #0 + beq .cfu_finished +.cfu_nowords: cmp ip, #2 +USER( ldrbt r3, [r1], #1) @ May fault + strb r3, [r0], #1 +USER( ldrgebt r3, [r1], #1) @ May fault + strgeb r3, [r0], #1 +USER( ldrgtbt r3, [r1], #1) @ May fault + strgtb r3, [r0], #1 + b .cfu_finished + +.cfu_not_enough: + movs ip, r2 + bne .cfu_nowords +.cfu_finished: mov r0, #0 + add sp, sp, #8 + LOADREGS(fd,sp!,{r4 - r7, pc}) + +.cfu_src_not_aligned: + bic r1, r1, #3 +USER( ldrt r7, [r1], #4) @ May fault + cmp ip, #2 + bgt .cfu_3fupi + beq .cfu_2fupi +.cfu_1fupi: subs r2, r2, #4 + addmi ip, r2, #4 + bmi .cfu_1nowords + mov r3, r7, pull #8 +USER( ldrt r7, [r1], #4) @ May fault + orr r3, r3, r7, push #24 + str r3, [r0], #4 + mov ip, r1, lsl #32 - PAGE_SHIFT + rsb ip, ip, #0 + movs ip, ip, lsr #32 - PAGE_SHIFT + beq .cfu_1fupi + cmp r2, ip + movlt ip, r2 + sub r2, r2, ip + subs ip, ip, #16 + blt .cfu_1rem8lp + +.cfu_1cpy8lp: mov r3, r7, pull #8 + ldmia r1!, {r4 - r7} @ Shouldnt fault + orr r3, r3, r4, push #24 + mov r4, r4, pull #8 + orr r4, r4, r5, push #24 + mov r5, r5, pull #8 + orr r5, r5, r6, push #24 + mov r6, r6, pull #8 + orr r6, r6, r7, push #24 + stmia r0!, {r3 - r6} + subs ip, ip, #16 + bpl .cfu_1cpy8lp +.cfu_1rem8lp: tst ip, #8 + movne r3, r7, pull #8 + ldmneia r1!, {r4, r7} @ Shouldnt fault + orrne r3, r3, r4, push #24 + movne r4, r4, pull #8 + orrne r4, r4, r7, push #24 + stmneia r0!, {r3 - r4} + tst ip, #4 + movne r3, r7, pull #8 +USER( ldrnet r7, [r1], #4) @ May fault + orrne r3, r3, r7, push #24 + strne r3, [r0], #4 + ands ip, ip, #3 + beq .cfu_1fupi +.cfu_1nowords: mov r3, r7, lsr #byte(1) + teq ip, #0 + beq .cfu_finished + cmp ip, #2 + strb r3, [r0], #1 + movge r3, r7, lsr #byte(2) + strgeb r3, [r0], #1 + movgt r3, r7, lsr #byte(3) + strgtb r3, [r0], #1 + b .cfu_finished + +.cfu_2fupi: subs r2, r2, #4 + addmi ip, r2, #4 + bmi .cfu_2nowords + mov r3, r7, pull #16 +USER( ldrt r7, [r1], #4) @ May fault + orr r3, r3, r7, push #16 + str r3, [r0], #4 + mov ip, r1, lsl #32 - PAGE_SHIFT + rsb ip, ip, #0 + movs ip, ip, lsr #32 - PAGE_SHIFT + beq .cfu_2fupi + cmp r2, ip + movlt ip, r2 + sub r2, r2, ip + subs ip, ip, #16 + blt .cfu_2rem8lp + +.cfu_2cpy8lp: mov r3, r7, pull #16 + ldmia r1!, {r4 - r7} @ Shouldnt fault + orr r3, r3, r4, push #16 + mov r4, r4, pull #16 + orr r4, r4, r5, push #16 + mov r5, r5, pull #16 + orr r5, r5, r6, push #16 + mov r6, r6, pull #16 + orr r6, r6, r7, push #16 + stmia r0!, {r3 - r6} + subs ip, ip, #16 + bpl .cfu_2cpy8lp +.cfu_2rem8lp: tst ip, #8 + movne r3, r7, pull #16 + ldmneia r1!, {r4, r7} @ Shouldnt fault + orrne r3, r3, r4, push #16 + movne r4, r4, pull #16 + orrne r4, r4, r7, push #16 + stmneia r0!, {r3 - r4} + tst ip, #4 + movne r3, r7, pull #16 +USER( ldrnet r7, [r1], #4) @ May fault + orrne r3, r3, r7, push #16 + strne r3, [r0], #4 + ands ip, ip, #3 + beq .cfu_2fupi +.cfu_2nowords: mov r3, r7, lsr #byte(2) + teq ip, #0 + beq .cfu_finished + cmp ip, #2 + strb r3, [r0], #1 + movge r3, r7, lsr #byte(3) + strgeb r3, [r0], #1 +USER( ldrgtbt r3, [r1], #0) @ May fault + strgtb r3, [r0], #1 + b .cfu_finished + +.cfu_3fupi: subs r2, r2, #4 + addmi ip, r2, #4 + bmi .cfu_3nowords + mov r3, r7, pull #24 +USER( ldrt r7, [r1], #4) @ May fault + orr r3, r3, r7, push #8 + str r3, [r0], #4 + mov ip, r1, lsl #32 - PAGE_SHIFT + rsb ip, ip, #0 + movs ip, ip, lsr #32 - PAGE_SHIFT + beq .cfu_3fupi + cmp r2, ip + movlt ip, r2 + sub r2, r2, ip + subs ip, ip, #16 + blt .cfu_3rem8lp + +.cfu_3cpy8lp: mov r3, r7, pull #24 + ldmia r1!, {r4 - r7} @ Shouldnt fault + orr r3, r3, r4, push #8 + mov r4, r4, pull #24 + orr r4, r4, r5, push #8 + mov r5, r5, pull #24 + orr r5, r5, r6, push #8 + mov r6, r6, pull #24 + orr r6, r6, r7, push #8 + stmia r0!, {r3 - r6} + subs ip, ip, #16 + bpl .cfu_3cpy8lp +.cfu_3rem8lp: tst ip, #8 + movne r3, r7, pull #24 + ldmneia r1!, {r4, r7} @ Shouldnt fault + orrne r3, r3, r4, push #8 + movne r4, r4, pull #24 + orrne r4, r4, r7, push #8 + stmneia r0!, {r3 - r4} + tst ip, #4 + movne r3, r7, pull #24 +USER( ldrnet r7, [r1], #4) @ May fault + orrne r3, r3, r7, push #8 + strne r3, [r0], #4 + ands ip, ip, #3 + beq .cfu_3fupi +.cfu_3nowords: mov r3, r7, lsr #byte(3) + teq ip, #0 + beq .cfu_finished + cmp ip, #2 + strb r3, [r0], #1 +USER( ldrgebt r3, [r1], #1) @ May fault + strgeb r3, [r0], #1 +USER( ldrgtbt r3, [r1], #1) @ May fault + strgtb r3, [r0], #1 + b .cfu_finished + + .section .fixup,"ax" + .align 0 + /* + * We took an exception. r0 contains a pointer to + * the byte not copied. + */ +9001: ldr r2, [sp], #4 @ void *to + sub r2, r0, r2 @ bytes copied + ldr r1, [sp], #4 @ unsigned long count + subs r4, r1, r2 @ bytes left to copy + movne r1, r4 + blne __memzero + mov r0, r4 + LOADREGS(fd,sp!, {r4 - r7, pc}) + .previous + +/* Prototype: int uaccess_user_clear_user(void *addr, size_t sz) + * Purpose : clear some user memory + * Params : addr - user memory address to clear + * : sz - number of bytes to clear + * Returns : number of bytes NOT cleared + */ +ENTRY(uaccess_user_clear_user) + stmfd sp!, {r1, lr} + mov r2, #0 + cmp r1, #4 + blt 2f + ands ip, r0, #3 + beq 1f + cmp ip, #2 +USER( strbt r2, [r0], #1) +USER( strlebt r2, [r0], #1) +USER( strltbt r2, [r0], #1) + rsb ip, ip, #4 + sub r1, r1, ip @ 7 6 5 4 3 2 1 +1: subs r1, r1, #8 @ -1 -2 -3 -4 -5 -6 -7 +USER( strplt r2, [r0], #4) +USER( strplt r2, [r0], #4) + bpl 1b + adds r1, r1, #4 @ 3 2 1 0 -1 -2 -3 +USER( strplt r2, [r0], #4) +2: tst r1, #2 @ 1x 1x 0x 0x 1x 1x 0x +USER( strnebt r2, [r0], #1) +USER( strnebt r2, [r0], #1) + tst r1, #1 @ x1 x0 x1 x0 x1 x0 x1 +USER( strnebt r2, [r0], #1) + mov r0, #0 + LOADREGS(fd,sp!, {r1, pc}) + + .section .fixup,"ax" + .align 0 +9001: LOADREGS(fd,sp!, {r0, pc}) + .previous + +/* + * Copy a string from user space to kernel space. + * r0 = dst, r1 = src, r2 = byte length + * returns the number of characters copied (strlen of copied string), + * -EFAULT on exception, or "len" if we fill the whole buffer + */ +ENTRY(uaccess_user_strncpy_from_user) + save_lr + mov ip, r1 +1: subs r2, r2, #1 +USER( ldrplbt r3, [r1], #1) + bmi 2f + strb r3, [r0], #1 + teq r3, #0 + bne 1b + sub r1, r1, #1 @ take NUL character out of count +2: sub r0, r1, ip + restore_pc + + .section .fixup,"ax" + .align 0 +9001: mov r3, #0 + strb r3, [r0, #0] @ null terminate + mov r0, #-EFAULT + restore_pc + .previous + +/* Prototype: unsigned long uaccess_user_strnlen_user(const char *str, long n) + * Purpose : get length of a string in user memory + * Params : str - address of string in user memory + * Returns : length of string *including terminator* + * or zero on exception, or n + 1 if too long + */ +ENTRY(uaccess_user_strnlen_user) + save_lr + mov r2, r0 +1: +USER( ldrbt r3, [r0], #1) + teq r3, #0 + beq 2f + subs r1, r1, #1 + bne 1b + add r0, r0, #1 +2: sub r0, r0, r2 + restore_pc + + .section .fixup,"ax" + .align 0 +9001: mov r0, #0 + restore_pc + .previous + diff -Nru a/arch/arm26/lib/ucmpdi2.c b/arch/arm26/lib/ucmpdi2.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/ucmpdi2.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,51 @@ +/* More subroutines needed by GCC output code on some machines. */ +/* Compile this one with gcc. */ +/* 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. */ + +/* As a special exception, if you link this library with other files, + some of which are compiled with GCC, to produce an executable, + this library does not by itself cause the resulting executable + to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. + */ +/* support functions required by the kernel. based on code from gcc-2.95.3 */ +/* I Molton 29/07/01 */ + +#include "gcclib.h" + +word_type +__ucmpdi2 (DItype a, DItype b) +{ + DIunion au, bu; + + au.ll = a, bu.ll = b; + + if ((USItype) au.s.high < (USItype) bu.s.high) + return 0; + else if ((USItype) au.s.high > (USItype) bu.s.high) + return 2; + if ((USItype) au.s.low < (USItype) bu.s.low) + return 0; + else if ((USItype) au.s.low > (USItype) bu.s.low) + return 2; + return 1; +} + diff -Nru a/arch/arm26/lib/udivdi3.c b/arch/arm26/lib/udivdi3.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/lib/udivdi3.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,242 @@ +/* More subroutines needed by GCC output code on some machines. */ +/* Compile this one with gcc. */ +/* 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. */ + +/* As a special exception, if you link this library with other files, + some of which are compiled with GCC, to produce an executable, + this library does not by itself cause the resulting executable + to be covered by the GNU General Public License. + This exception does not however invalidate any other reasons why + the executable file might be covered by the GNU General Public License. + */ +/* support functions required by the kernel. based on code from gcc-2.95.3 */ +/* I Molton 29/07/01 */ + +#include "gcclib.h" +#include "longlong.h" + +static const UQItype __clz_tab[] = +{ + 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, +}; + +UDItype +__udivmoddi4 (UDItype n, UDItype d, UDItype *rp) +{ + DIunion ww; + DIunion nn, dd; + DIunion rr; + USItype d0, d1, n0, n1, n2; + USItype q0, q1; + USItype b, bm; + + nn.ll = n; + dd.ll = d; + + d0 = dd.s.low; + d1 = dd.s.high; + n0 = nn.s.low; + n1 = nn.s.high; + + if (d1 == 0) + { + if (d0 > n1) + { + /* 0q = nn / 0D */ + + count_leading_zeros (bm, d0); + + if (bm != 0) + { + /* Normalize, i.e. make the most significant bit of the + denominator set. */ + + d0 = d0 << bm; + n1 = (n1 << bm) | (n0 >> (SI_TYPE_SIZE - bm)); + n0 = n0 << bm; + } + + udiv_qrnnd (q0, n0, n1, n0, d0); + q1 = 0; + + /* Remainder in n0 >> bm. */ + } + else + { + /* qq = NN / 0d */ + + if (d0 == 0) + d0 = 1 / d0; /* Divide intentionally by zero. */ + + count_leading_zeros (bm, d0); + + if (bm == 0) + { + /* From (n1 >= d0) /\ (the most significant bit of d0 is set), + conclude (the most significant bit of n1 is set) /\ (the + leading quotient digit q1 = 1). + + This special case is necessary, not an optimization. + (Shifts counts of SI_TYPE_SIZE are undefined.) */ + + n1 -= d0; + q1 = 1; + } + else + { + /* Normalize. */ + + b = SI_TYPE_SIZE - bm; + + d0 = d0 << bm; + n2 = n1 >> b; + n1 = (n1 << bm) | (n0 >> b); + n0 = n0 << bm; + + udiv_qrnnd (q1, n1, n2, n1, d0); + } + + /* n1 != d0... */ + + udiv_qrnnd (q0, n0, n1, n0, d0); + + /* Remainder in n0 >> bm. */ + } + + if (rp != 0) + { + rr.s.low = n0 >> bm; + rr.s.high = 0; + *rp = rr.ll; + } + } + else + { + if (d1 > n1) + { + /* 00 = nn / DD */ + + q0 = 0; + q1 = 0; + + /* Remainder in n1n0. */ + if (rp != 0) + { + rr.s.low = n0; + rr.s.high = n1; + *rp = rr.ll; + } + } + else + { + /* 0q = NN / dd */ + + count_leading_zeros (bm, d1); + if (bm == 0) + { + /* From (n1 >= d1) /\ (the most significant bit of d1 is set), + conclude (the most significant bit of n1 is set) /\ (the + quotient digit q0 = 0 or 1). + + This special case is necessary, not an optimization. */ + + /* The condition on the next line takes advantage of that + n1 >= d1 (true due to program flow). */ + if (n1 > d1 || n0 >= d0) + { + q0 = 1; + sub_ddmmss (n1, n0, n1, n0, d1, d0); + } + else + q0 = 0; + + q1 = 0; + + if (rp != 0) + { + rr.s.low = n0; + rr.s.high = n1; + *rp = rr.ll; + } + } + else + { + USItype m1, m0; + /* Normalize. */ + + b = SI_TYPE_SIZE - bm; + + d1 = (d1 << bm) | (d0 >> b); + d0 = d0 << bm; + n2 = n1 >> b; + n1 = (n1 << bm) | (n0 >> b); + n0 = n0 << bm; + + udiv_qrnnd (q0, n1, n2, n1, d1); + umul_ppmm (m1, m0, q0, d0); + + if (m1 > n1 || (m1 == n1 && m0 > n0)) + { + q0--; + sub_ddmmss (m1, m0, m1, m0, d1, d0); + } + + q1 = 0; + + /* Remainder in (n1n0 - m1m0) >> bm. */ + if (rp != 0) + { + sub_ddmmss (n1, n0, n1, n0, m1, m0); + rr.s.low = (n1 << b) | (n0 >> bm); + rr.s.high = n1 >> bm; + *rp = rr.ll; + } + } + } + } + + ww.s.low = q0; + ww.s.high = q1; + return ww.ll; +} + +UDItype +__udivdi3 (UDItype n, UDItype d) +{ + return __udivmoddi4 (n, d, (UDItype *) 0); +} + +UDItype +__umoddi3 (UDItype u, UDItype v) +{ + UDItype w; + + (void) __udivmoddi4 (u ,v, &w); + + return w; +} + diff -Nru a/arch/arm26/machine/Makefile b/arch/arm26/machine/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/machine/Makefile Mon Jun 9 23:16:20 2003 @@ -0,0 +1,12 @@ +# +# Makefile for the linux kernel. +# + +# Object file lists. + +obj-y := arch.o dma.o irq.o oldlatches.o \ + small_page.o + +extra-y := head.o + +AFLAGS_head.o := -DTEXTADDR=$(TEXTADDR) diff -Nru a/arch/arm26/machine/arch.c b/arch/arm26/machine/arch.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/machine/arch.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,36 @@ +/* + * linux/arch/arm26/mach-arc/arch.c + * + * Copyright (C) 1998-2001 Russell King + * Copyright (C) 2003 Ian Molton + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Architecture specific fixups. + */ +#include <linux/config.h> +#include <linux/tty.h> +#include <linux/init.h> + +#include <asm/mach-types.h> +#include <asm/hardware.h> +#include <asm/page.h> +#include <asm/setup.h> + +#include <asm/map.h> +#include <asm/arch.h> + +extern void arc_init_irq(void); + +#ifdef CONFIG_ARCH_ARC +MACHINE_START(ARCHIMEDES, "Acorn-Archimedes") +#elif defined(CONFIG_ARCH_A5K) +MACHINE_START(A5K, "Acorn-A5000") +#endif + MAINTAINER("Ian Molton") + BOOT_PARAMS(0x0207c000) + INITIRQ(arc_init_irq) +MACHINE_END + diff -Nru a/arch/arm26/machine/dma.c b/arch/arm26/machine/dma.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/machine/dma.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,215 @@ +/* + * linux/arch/arm/kernel/dma-arc.c + * + * Copyright (C) 1998-1999 Dave Gilbert / Russell King + * Copyright (C) 2003 Ian Molton + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * DMA functions specific to Archimedes and A5000 architecture + */ +#include <linux/config.h> +#include <linux/sched.h> +#include <linux/init.h> + +#include <asm/dma.h> +#include <asm/fiq.h> +#include <asm/irq.h> +#include <asm/io.h> +#include <asm/hardware.h> +#include <asm/mach-types.h> + +#define DPRINTK(x...) printk(KERN_DEBUG x) + +#if defined(CONFIG_BLK_DEV_FD1772) || defined(CONFIG_BLK_DEV_FD1772_MODULE) + +extern unsigned char fdc1772_dma_read, fdc1772_dma_read_end; +extern unsigned char fdc1772_dma_write, fdc1772_dma_write_end; +extern void fdc1772_setupdma(unsigned int count,unsigned int addr); + +static void arc_floppy_data_enable_dma(dmach_t channel, dma_t *dma) +{ + DPRINTK("arc_floppy_data_enable_dma\n"); + + if (dma->using_sg) + BUG(); + + switch (dma->dma_mode) { + case DMA_MODE_READ: { /* read */ + unsigned long flags; + DPRINTK("enable_dma fdc1772 data read\n"); + local_save_flags_cli(flags); + clf(); + + memcpy ((void *)0x1c, (void *)&fdc1772_dma_read, + &fdc1772_dma_read_end - &fdc1772_dma_read); + fdc1772_setupdma(dma->buf.length, dma->buf.__address); /* Sets data pointer up */ + enable_fiq(FIQ_FLOPPYDATA); + loacl_irq_restore(flags); + } + break; + + case DMA_MODE_WRITE: { /* write */ + unsigned long flags; + DPRINTK("enable_dma fdc1772 data write\n"); + local_save_flags_cli(flags); + clf(); + memcpy ((void *)0x1c, (void *)&fdc1772_dma_write, + &fdc1772_dma_write_end - &fdc1772_dma_write); + fdc1772_setupdma(dma->buf.length, dma->buf.__address); /* Sets data pointer up */ + enable_fiq(FIQ_FLOPPYDATA); + + local_irq_restore(flags); + } + break; + default: + printk ("enable_dma: dma%d not initialised\n", channel); + } +} + +static int arc_floppy_data_get_dma_residue(dmach_t channel, dma_t *dma) +{ + extern unsigned int fdc1772_bytestogo; + + /* 10/1/1999 DAG - I presume its the number of bytes left? */ + return fdc1772_bytestogo; +} + +static void arc_floppy_cmdend_enable_dma(dmach_t channel, dma_t *dma) +{ + /* Need to build a branch at the FIQ address */ + extern void fdc1772_comendhandler(void); + unsigned long flags; + + DPRINTK("arc_floppy_cmdend_enable_dma\n"); + /*printk("enable_dma fdc1772 command end FIQ\n");*/ + save_flags(flags); + clf(); + + /* B fdc1772_comendhandler */ + *((unsigned int *)0x1c)=0xea000000 | + (((unsigned int)fdc1772_comendhandler-(0x1c+8))/4); + + local_irq_restore(flags); +} + +static int arc_floppy_cmdend_get_dma_residue(dmach_t channel, dma_t *dma) +{ + /* 10/1/1999 DAG - Presume whether there is an outstanding command? */ + extern unsigned int fdc1772_fdc_int_done; + + /* Explicit! If the int done is 0 then 1 int to go */ + return (fdc1772_fdc_int_done==0)?1:0; +} + +static void arc_disable_dma(dmach_t channel, dma_t *dma) +{ + disable_fiq(dma->dma_irq); +} + +static struct dma_ops arc_floppy_data_dma_ops = { + .type = "FIQDMA", + .enable = arc_floppy_data_enable_dma, + .disable = arc_disable_dma, + .residue = arc_floppy_data_get_dma_residue, +}; + +static struct dma_ops arc_floppy_cmdend_dma_ops = { + .type = "FIQCMD", + .enable = arc_floppy_cmdend_enable_dma, + .disable = arc_disable_dma, + .residue = arc_floppy_cmdend_get_dma_residue, +}; +#endif + +#ifdef CONFIG_ARCH_A5K +static struct fiq_handler fh = { + .name = "floppydata" +}; + +static int a5k_floppy_get_dma_residue(dmach_t channel, dma_t *dma) +{ + struct pt_regs regs; + get_fiq_regs(®s); + return regs.ARM_r9; +} + +static void a5k_floppy_enable_dma(dmach_t channel, dma_t *dma) +{ + struct pt_regs regs; + void *fiqhandler_start; + unsigned int fiqhandler_length; + extern void floppy_fiqsetup(unsigned long len, unsigned long addr, + unsigned long port); + + if (dma->using_sg) + BUG(); + + if (dma->dma_mode == DMA_MODE_READ) { + extern unsigned char floppy_fiqin_start, floppy_fiqin_end; + fiqhandler_start = &floppy_fiqin_start; + fiqhandler_length = &floppy_fiqin_end - &floppy_fiqin_start; + } else { + extern unsigned char floppy_fiqout_start, floppy_fiqout_end; + fiqhandler_start = &floppy_fiqout_start; + fiqhandler_length = &floppy_fiqout_end - &floppy_fiqout_start; + } + if (claim_fiq(&fh)) { + printk("floppydma: couldn't claim FIQ.\n"); + return; + } + memcpy((void *)0x1c, fiqhandler_start, fiqhandler_length); + regs.ARM_r9 = dma->buf.length; + regs.ARM_r10 = (unsigned long)dma->buf.__address; + regs.ARM_fp = FLOPPYDMA_BASE; + set_fiq_regs(®s); + enable_fiq(dma->dma_irq); +} + +static void a5k_floppy_disable_dma(dmach_t channel, dma_t *dma) +{ + disable_fiq(dma->dma_irq); + release_fiq(&fh); +} + +static struct dma_ops a5k_floppy_dma_ops = { + .type = "FIQDMA", + .enable = a5k_floppy_enable_dma, + .disable = a5k_floppy_disable_dma, + .residue = a5k_floppy_get_dma_residue, +}; +#endif + +/* + * This is virtual DMA - we don't need anything here + */ +static void sound_enable_disable_dma(dmach_t channel, dma_t *dma) +{ +} + +static struct dma_ops sound_dma_ops = { + .type = "VIRTUAL", + .enable = sound_enable_disable_dma, + .disable = sound_enable_disable_dma, +}; + +void __init arch_dma_init(dma_t *dma) +{ +#if defined(CONFIG_BLK_DEV_FD1772) || defined(CONFIG_BLK_DEV_FD1772_MODULE) + if (machine_is_archimedes()) { + dma[DMA_VIRTUAL_FLOPPY0].dma_irq = FIQ_FLOPPYDATA; + dma[DMA_VIRTUAL_FLOPPY0].d_ops = &arc_floppy_data_dma_ops; + dma[DMA_VIRTUAL_FLOPPY1].dma_irq = 1; + dma[DMA_VIRTUAL_FLOPPY1].d_ops = &arc_floppy_cmdend_dma_ops; + } +#endif +#ifdef CONFIG_ARCH_A5K + if (machine_is_a5k()) { + dma[DMA_VIRTUAL_FLOPPY0].dma_irq = FIQ_FLOPPYDATA; + dma[DMA_VIRTUAL_FLOPPY0].d_ops = &a5k_floppy_dma_ops; + } +#endif + dma[DMA_VIRTUAL_SOUND].d_ops = &sound_dma_ops; +} diff -Nru a/arch/arm26/machine/head.S b/arch/arm26/machine/head.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/machine/head.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,93 @@ +/* + * linux/arch/arm/kernel/head-armo.S + * + * Copyright (C) 1994-2000 Russell King + * Copyright (C) 2003 Ian Molton + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * 26-bit kernel startup code + */ +#include <linux/config.h> +#include <linux/linkage.h> +#include <asm/mach-types.h> + + .globl swapper_pg_dir + .equ swapper_pg_dir, 0x0207d000 + +/* + * Entry point. + */ + .section ".init.text",#alloc,#execinstr +ENTRY(stext) +__entry: cmp pc, #0x02000000 + ldrlt pc, LC0 @ if 0x01800000, call at 0x02080000 + teq r0, #0 @ Check for old calling method + blne oldparams @ Move page if old + adr r0, LC0 + ldmib r0, {r2-r5, sp} @ Setup stack + mov r0, #0 +1: cmp r2, r3 @ Clear BSS + strcc r0, [r2], #4 + bcc 1b + + bl detect_proc_type + str r0, [r4] + bl detect_arch_type + str r0, [r5] + + mov fp, #0 + b start_kernel + +LC0: .word _stext + .word __bss_start @ r2 + .word _end @ r3 + .word processor_id @ r4 + .word __machine_arch_type @ r5 + .word init_thread_union+8192 @ sp +arm2_id: .long 0x41560200 +arm250_id: .long 0x41560250 + .align + +oldparams: mov r4, #0x02000000 + add r3, r4, #0x00080000 + add r4, r4, #0x0007c000 +1: ldmia r0!, {r5 - r12} + stmia r4!, {r5 - r12} + cmp r4, r3 + blt 1b + mov pc, lr + +/* + * We need some way to automatically detect the difference between + * these two machines. Unfortunately, it is not possible to detect + * the presence of the SuperIO chip, because that will hang the old + * Archimedes machines solid. + */ +/* DAG: Outdated, these have been combined !!!!!!! */ +detect_arch_type: +#if defined(CONFIG_ARCH_ARC) + mov r0, #MACH_TYPE_ARCHIMEDES +#elif defined(CONFIG_ARCH_A5K) + mov r0, #MACH_TYPE_A5K +#endif + mov pc, lr + +detect_proc_type: + mov ip, lr + mov r2, #0xea000000 @ Point undef instr to continuation + adr r0, continue - 12 + orr r0, r2, r0, lsr #2 + mov r1, #0 + str r0, [r1, #4] + ldr r0, arm2_id + swp r2, r2, [r1] @ check for swp (ARM2 cant) + ldr r0, arm250_id + mrc 15, 0, r3, c0, c0 @ check for CP#15 (ARM250 cant) + mov r0, r3 +continue: mov r2, #0xeb000000 @ Make undef vector loop + sub r2, r2, #2 + str r2, [r1, #4] + mov pc, ip diff -Nru a/arch/arm26/machine/irq.c b/arch/arm26/machine/irq.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/machine/irq.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,165 @@ +/* + * linux/arch/arm/mach-arc/irq.c + * + * Copyright (C) 1996 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Changelog: + * 24-09-1996 RMK Created + * 10-10-1996 RMK Brought up to date with arch-sa110eval + * 22-10-1996 RMK Changed interrupt numbers & uses new inb/outb macros + * 11-01-1998 RMK Added mask_and_ack_irq + * 22-08-1998 RMK Restructured IRQ routines + * 08-09-2002 IM Brought up to date for 2.5 + * 01-06-2003 JMA Removed arc_fiq_chip + */ +#include <linux/config.h> +#include <linux/init.h> + +#include <asm/irq.h> +#include <asm/irqchip.h> +#include <asm/ioc.h> +#include <asm/io.h> +#include <asm/system.h> + +extern void init_FIQ(void); + +#define a_clf() clf() +#define a_stf() stf() + +static void arc_ack_irq_a(unsigned int irq) +{ + unsigned int val, mask; + + mask = 1 << irq; + a_clf(); + val = ioc_readb(IOC_IRQMASKA); + ioc_writeb(val & ~mask, IOC_IRQMASKA); + ioc_writeb(mask, IOC_IRQCLRA); + a_stf(); +} + +static void arc_mask_irq_a(unsigned int irq) +{ + unsigned int val, mask; + + mask = 1 << irq; + a_clf(); + val = ioc_readb(IOC_IRQMASKA); + ioc_writeb(val & ~mask, IOC_IRQMASKA); + a_stf(); +} + +static void arc_unmask_irq_a(unsigned int irq) +{ + unsigned int val, mask; + + mask = 1 << irq; + a_clf(); + val = ioc_readb(IOC_IRQMASKA); + ioc_writeb(val | mask, IOC_IRQMASKA); + a_stf(); +} + +static struct irqchip arc_a_chip = { + .ack = arc_ack_irq_a, + .mask = arc_mask_irq_a, + .unmask = arc_unmask_irq_a, +}; + +static void arc_mask_irq_b(unsigned int irq) +{ + unsigned int val, mask; + + mask = 1 << (irq & 7); + val = ioc_readb(IOC_IRQMASKB); + ioc_writeb(val & ~mask, IOC_IRQMASKB); +} + +static void arc_unmask_irq_b(unsigned int irq) +{ + unsigned int val, mask; + + mask = 1 << (irq & 7); + val = ioc_readb(IOC_IRQMASKB); + ioc_writeb(val | mask, IOC_IRQMASKB); +} + +static struct irqchip arc_b_chip = { + .ack = arc_mask_irq_b, + .mask = arc_mask_irq_b, + .unmask = arc_unmask_irq_b, +}; + +/* FIXME - JMA none of these functions are used in arm26 +static void arc_mask_irq_fiq(unsigned int irq) +{ + unsigned int val, mask; + + mask = 1 << (irq & 7); + val = ioc_readb(IOC_FIQMASK); + ioc_writeb(val & ~mask, IOC_FIQMASK); +} + +static void arc_unmask_irq_fiq(unsigned int irq) +{ + unsigned int val, mask; + + mask = 1 << (irq & 7); + val = ioc_readb(IOC_FIQMASK); + ioc_writeb(val | mask, IOC_FIQMASK); +} + +static struct irqchip arc_fiq_chip = { + .ack = arc_mask_irq_fiq, + .mask = arc_mask_irq_fiq, + .unmask = arc_unmask_irq_fiq, +}; +*/ + +void __init arc_init_irq(void) +{ + unsigned int irq, flags; + + ioc_writeb(0, IOC_IRQMASKA); + ioc_writeb(0, IOC_IRQMASKB); + ioc_writeb(0, IOC_FIQMASK); + + for (irq = 0; irq < NR_IRQS; irq++) { + flags = IRQF_VALID; + + if (irq <= 6 || (irq >= 9 && irq <= 15)) + flags |= IRQF_PROBE; + + if (irq == IRQ_KEYBOARDTX) + flags |= IRQF_NOAUTOEN; + + switch (irq) { + case 0 ... 7: + set_irq_chip(irq, &arc_a_chip); + set_irq_handler(irq, do_level_IRQ); + set_irq_flags(irq, flags); + break; + + case 8 ... 15: + set_irq_chip(irq, &arc_b_chip); + set_irq_handler(irq, do_level_IRQ); + set_irq_flags(irq, flags); + +/* case 64 ... 72: + set_irq_chip(irq, &arc_fiq_chip); + set_irq_flags(irq, flags); + break; +*/ + + } + } + + irq_desc[IRQ_KEYBOARDTX].noautoenable = 1; + + init_FIQ(); +} + diff -Nru a/arch/arm26/machine/oldlatches.c b/arch/arm26/machine/oldlatches.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/machine/oldlatches.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,72 @@ +/* + * linux/arch/arm/kernel/oldlatches.c + * + * Copyright (C) David Alan Gilbert 1995/1996,2000 + * Copyright (C) Ian Molton 2003 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Support for the latches on the old Archimedes which control the floppy, + * hard disc and printer + */ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/sched.h> + +#include <asm/io.h> +#include <asm/hardware.h> +#include <asm/mach-types.h> +#include <asm/oldlatches.h> + +static unsigned char latch_a_copy; +static unsigned char latch_b_copy; + +/* newval=(oldval & ~mask)|newdata */ +void oldlatch_aupdate(unsigned char mask,unsigned char newdata) +{ + unsigned long flags; + + BUG_ON(!machine_is_archimedes()); + + local_irq_save(flags); //FIXME: was local_save_flags + latch_a_copy = (latch_a_copy & ~mask) | newdata; + __raw_writeb(latch_a_copy, LATCHA_BASE); + local_irq_restore(flags); + + printk("Latch: A = 0x%02x\n", latch_a_copy); +} + + +/* newval=(oldval & ~mask)|newdata */ +void oldlatch_bupdate(unsigned char mask,unsigned char newdata) +{ + unsigned long flags; + + BUG_ON(!machine_is_archimedes()); + + + local_irq_save(flags);//FIXME: was local_save_flags + latch_b_copy = (latch_b_copy & ~mask) | newdata; + __raw_writeb(latch_b_copy, LATCHB_BASE); + local_irq_restore(flags); + + printk("Latch: B = 0x%02x\n", latch_b_copy); +} + +static int __init oldlatch_init(void) +{ + if (machine_is_archimedes()) { + oldlatch_aupdate(0xff, 0xff); + /* Thats no FDC reset...*/ + oldlatch_bupdate(0xff, LATCHB_FDCRESET); + } + return 0; +} + +arch_initcall(oldlatch_init); + +EXPORT_SYMBOL(oldlatch_aupdate); +EXPORT_SYMBOL(oldlatch_bupdate); diff -Nru a/arch/arm26/machine/small_page.c b/arch/arm26/machine/small_page.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/machine/small_page.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,191 @@ +/* + * linux/arch/arm/mm/small_page.c + * + * Copyright (C) 1996 Russell King + * Copyright (C) 2003 Ian Molton + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Changelog: + * 26/01/1996 RMK Cleaned up various areas to make little more generic + * 07/02/1999 RMK Support added for 16K and 32K page sizes + * containing 8K blocks + */ +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/types.h> +#include <linux/ptrace.h> +#include <linux/mman.h> +#include <linux/mm.h> +#include <linux/swap.h> +#include <linux/smp.h> + +#include <asm/bitops.h> +#include <asm/pgtable.h> + +#define PEDANTIC + +/* + * Requirement: + * We need to be able to allocate naturally aligned memory of finer + * granularity than the page size. This is typically used for the + * second level page tables on 32-bit ARMs. + * + * Theory: + * We "misuse" the Linux memory management system. We use alloc_page + * to allocate a page and then mark it as reserved. The Linux memory + * management system will then ignore the "offset", "next_hash" and + * "pprev_hash" entries in the mem_map for this page. + * + * We then use a bitstring in the "offset" field to mark which segments + * of the page are in use, and manipulate this as required during the + * allocation and freeing of these small pages. + * + * We also maintain a queue of pages being used for this purpose using + * the "next_hash" and "pprev_hash" entries of mem_map; + */ + +struct order { + struct list_head queue; + unsigned int mask; /* (1 << shift) - 1 */ + unsigned int shift; /* (1 << shift) size of page */ + unsigned int block_mask; /* nr_blocks - 1 */ + unsigned int all_used; /* (1 << nr_blocks) - 1 */ +}; + + +static struct order orders[] = { +#if PAGE_SIZE == 32768 + { LIST_HEAD_INIT(orders[0].queue), 2047, 11, 15, 0x0000ffff }, + { LIST_HEAD_INIT(orders[1].queue), 8191, 13, 3, 0x0000000f } +#else +#error unsupported page size (ARGH!) +#endif +}; + +#define USED_MAP(pg) ((pg)->index) +#define TEST_AND_CLEAR_USED(pg,off) (test_and_clear_bit(off, &USED_MAP(pg))) +#define SET_USED(pg,off) (set_bit(off, &USED_MAP(pg))) + +static spinlock_t small_page_lock = SPIN_LOCK_UNLOCKED; + +static unsigned long __get_small_page(int priority, struct order *order) +{ + unsigned long flags; + struct page *page; + int offset; + + do { + spin_lock_irqsave(&small_page_lock, flags); + + if (list_empty(&order->queue)) + goto need_new_page; + + page = list_entry(order->queue.next, struct page, list); +again: +#ifdef PEDANTIC + if (USED_MAP(page) & ~order->all_used) + PAGE_BUG(page); +#endif + offset = ffz(USED_MAP(page)); + SET_USED(page, offset); + if (USED_MAP(page) == order->all_used) + list_del_init(&page->list); + spin_unlock_irqrestore(&small_page_lock, flags); + + return (unsigned long) page_address(page) + (offset << order->shift); + +need_new_page: + spin_unlock_irqrestore(&small_page_lock, flags); + page = alloc_page(priority); + spin_lock_irqsave(&small_page_lock, flags); + + if (list_empty(&order->queue)) { + if (!page) + goto no_page; + SetPageReserved(page); + USED_MAP(page) = 0; + list_add(&page->list, &order->queue); + goto again; + } + + spin_unlock_irqrestore(&small_page_lock, flags); + __free_page(page); + } while (1); + +no_page: + spin_unlock_irqrestore(&small_page_lock, flags); + return 0; +} + +static void __free_small_page(unsigned long spage, struct order *order) +{ + unsigned long flags; + struct page *page; + + if (virt_addr_valid(spage)) { + page = virt_to_page(spage); + + /* + * The container-page must be marked Reserved + */ + if (!PageReserved(page) || spage & order->mask) + goto non_small; + +#ifdef PEDANTIC + if (USED_MAP(page) & ~order->all_used) + PAGE_BUG(page); +#endif + + spage = spage >> order->shift; + spage &= order->block_mask; + + /* + * the following must be atomic wrt get_page + */ + spin_lock_irqsave(&small_page_lock, flags); + + if (USED_MAP(page) == order->all_used) + list_add(&page->list, &order->queue); + + if (!TEST_AND_CLEAR_USED(page, spage)) + goto already_free; + + if (USED_MAP(page) == 0) + goto free_page; + + spin_unlock_irqrestore(&small_page_lock, flags); + } + return; + +free_page: + /* + * unlink the page from the small page queue and free it + */ + list_del_init(&page->list); + spin_unlock_irqrestore(&small_page_lock, flags); + ClearPageReserved(page); + __free_page(page); + return; + +non_small: + printk("Trying to free non-small page from %p\n", __builtin_return_address(0)); + return; +already_free: + printk("Trying to free free small page from %p\n", __builtin_return_address(0)); +} + +unsigned long get_page_8k(int priority) +{ + return __get_small_page(priority, orders+1); +} + +void free_page_8k(unsigned long spage) +{ + __free_small_page(spage, orders+1); +} diff -Nru a/arch/arm26/mm/Makefile b/arch/arm26/mm/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/mm/Makefile Mon Jun 9 23:16:20 2003 @@ -0,0 +1,12 @@ +# +# Makefile for the linux arm26-specific parts of the memory manager. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definition is now in the main makefile... + +# Object file lists. + +obj-y := init.o extable.o proc-funcs.o mm-memc.o fault.o diff -Nru a/arch/arm26/mm/extable.c b/arch/arm26/mm/extable.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/mm/extable.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,40 @@ +/* + * linux/arch/arm/mm/extable.c + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <asm/uaccess.h> + +const struct exception_table_entry * +search_extable(const struct exception_table_entry *first, + const struct exception_table_entry *last, + unsigned long value) +{ + while (first <= last) { + const struct exception_table_entry *mid; + long diff; + + mid = (last - first) / 2 + first; + diff = mid->insn - value; + if (diff == 0) + return mid; + else if (diff < 0) + first = mid+1; + else + last = mid-1; + } + return NULL; +} + +int fixup_exception(struct pt_regs *regs) +{ + const struct exception_table_entry *fixup; + + fixup = search_exception_tables(instruction_pointer(regs)); + if (fixup) + regs->ARM_pc = fixup->fixup | PSR_I_BIT | MODE_SVC26; + + return fixup != NULL; +} + diff -Nru a/arch/arm26/mm/fault.c b/arch/arm26/mm/fault.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/mm/fault.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,318 @@ +/* + * linux/arch/arm/mm/fault-common.c + * + * Copyright (C) 1995 Linus Torvalds + * Modifications for ARM processor (c) 1995-2001 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/config.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/types.h> +#include <linux/ptrace.h> +#include <linux/mman.h> +#include <linux/mm.h> +#include <linux/interrupt.h> +#include <linux/proc_fs.h> +#include <linux/init.h> + +#include <asm/system.h> +#include <asm/pgtable.h> +#include <asm/uaccess.h> //FIXME this header may be bogusly included + +#include "fault.h" + +#define FAULT_CODE_LDRSTRPOST 0x80 +#define FAULT_CODE_LDRSTRPRE 0x40 +#define FAULT_CODE_LDRSTRREG 0x20 +#define FAULT_CODE_LDMSTM 0x10 +#define FAULT_CODE_LDCSTC 0x08 +#define FAULT_CODE_PREFETCH 0x04 +#define FAULT_CODE_WRITE 0x02 +#define FAULT_CODE_FORCECOW 0x01 + +#define DO_COW(m) ((m) & (FAULT_CODE_WRITE|FAULT_CODE_FORCECOW)) +#define READ_FAULT(m) (!((m) & FAULT_CODE_WRITE)) +#define DEBUG +/* + * This is useful to dump out the page tables associated with + * 'addr' in mm 'mm'. + */ +void show_pte(struct mm_struct *mm, unsigned long addr) +{ + pgd_t *pgd; + + if (!mm) + mm = &init_mm; + + printk(KERN_ALERT "pgd = %p\n", mm->pgd); + pgd = pgd_offset(mm, addr); + printk(KERN_ALERT "[%08lx] *pgd=%08lx", addr, pgd_val(*pgd)); + + do { + pmd_t *pmd; + pte_t *pte; + + pmd = pmd_offset(pgd, addr); + + if (pmd_none(*pmd)) + break; + + if (pmd_bad(*pmd)) { + printk("(bad)"); + break; + } + + /* We must not map this if we have highmem enabled */ + /* FIXME */ + pte = pte_offset_map(pmd, addr); + printk(", *pte=%08lx", pte_val(*pte)); + pte_unmap(pte); + } while(0); + + printk("\n"); +} + +/* + * Oops. The kernel tried to access some page that wasn't present. + */ +static void +__do_kernel_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr, + struct pt_regs *regs) +{ + /* + * Are we prepared to handle this kernel fault? + */ + if (fixup_exception(regs)) + return; + + /* + * No handler, we'll have to terminate things with extreme prejudice. + */ + bust_spinlocks(1); + printk(KERN_ALERT + "Unable to handle kernel %s at virtual address %08lx\n", + (addr < PAGE_SIZE) ? "NULL pointer dereference" : + "paging request", addr); + + show_pte(mm, addr); + die("Oops", regs, fsr); + bust_spinlocks(0); + do_exit(SIGKILL); +} + +/* + * Something tried to access memory that isn't in our memory map.. + * User mode accesses just cause a SIGSEGV + */ +static void +__do_user_fault(struct task_struct *tsk, unsigned long addr, + unsigned int fsr, int code, struct pt_regs *regs) +{ + struct siginfo si; + +#ifdef CONFIG_DEBUG_USER + printk("%s: unhandled page fault at 0x%08lx, code 0x%03x\n", + tsk->comm, addr, fsr); + show_pte(tsk->mm, addr); + show_regs(regs); + //dump_backtrace(regs, tsk); // FIXME ARM32 dropped this - why? + while(1); +#endif + + tsk->thread.address = addr; + tsk->thread.error_code = fsr; + tsk->thread.trap_no = 14; + si.si_signo = SIGSEGV; + si.si_errno = 0; + si.si_code = code; + si.si_addr = (void *)addr; + force_sig_info(SIGSEGV, &si, tsk); +} + +static int +__do_page_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr, + struct task_struct *tsk) +{ + struct vm_area_struct *vma; + int fault, mask; + + vma = find_vma(mm, addr); + fault = -2; /* bad map area */ + if (!vma) + goto out; + if (vma->vm_start > addr) + goto check_stack; + + /* + * Ok, we have a good vm_area for this + * memory access, so we can handle it. + */ +good_area: + if (READ_FAULT(fsr)) /* read? */ + mask = VM_READ|VM_EXEC; + else + mask = VM_WRITE; + + fault = -1; /* bad access type */ + if (!(vma->vm_flags & mask)) + goto out; + + /* + * If for any reason at all we couldn't handle + * the fault, make sure we exit gracefully rather + * than endlessly redo the fault. + */ +survive: + fault = handle_mm_fault(mm, vma, addr & PAGE_MASK, DO_COW(fsr)); + + /* + * Handle the "normal" cases first - successful and sigbus + */ + switch (fault) { + case 2: + tsk->maj_flt++; + return fault; + case 1: + tsk->min_flt++; + case 0: + return fault; + } + + fault = -3; /* out of memory */ + if (tsk->pid != 1) + goto out; + + /* + * If we are out of memory for pid1, + * sleep for a while and retry + */ + yield(); + goto survive; + +check_stack: + if (vma->vm_flags & VM_GROWSDOWN && !expand_stack(vma, addr)) + goto good_area; +out: + return fault; +} + +int do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) +{ + struct task_struct *tsk; + struct mm_struct *mm; + int fault; + + tsk = current; + mm = tsk->mm; + + printk("do_page_fault: pid: %d\n", tsk->pid); + /* + * If we're in an interrupt or have no user + * context, we must not take the fault.. + */ + if (in_interrupt() || !mm) + goto no_context; + + down_read(&mm->mmap_sem); + fault = __do_page_fault(mm, addr, fsr, tsk); + up_read(&mm->mmap_sem); + + /* + * Handle the "normal" case first + */ + if (fault > 0) + return 0; + + /* + * We had some memory, but were unable to + * successfully fix up this page fault. + */ + if (fault == 0){ + goto do_sigbus; + } + + /* + * If we are in kernel mode at this point, we + * have no context to handle this fault with. + */ + if (!user_mode(regs)){ + goto no_context; + } + + if (fault == -3) { + /* + * We ran out of memory, or some other thing happened to + * us that made us unable to handle the page fault gracefully. + */ + printk("VM: killing process %s\n", tsk->comm); + do_exit(SIGKILL); + } + else{ + __do_user_fault(tsk, addr, fsr, fault == -1 ? SEGV_ACCERR : SEGV_MAPERR, regs); + } + + return 0; + + +/* + * We ran out of memory, or some other thing happened to us that made + * us unable to handle the page fault gracefully. + */ +do_sigbus: + /* + * Send a sigbus, regardless of whether we were in kernel + * or user mode. + */ + tsk->thread.address = addr; //FIXME - need other bits setting? + tsk->thread.error_code = fsr; + tsk->thread.trap_no = 14; + force_sig(SIGBUS, tsk); +#ifdef CONFIG_DEBUG_USER + printk(KERN_DEBUG "%s: sigbus at 0x%08lx, pc=0x%08lx\n", + current->comm, addr, instruction_pointer(regs)); +#endif + + /* Kernel mode? Handle exceptions or die */ + if (user_mode(regs)) + return 0; + +no_context: + __do_kernel_fault(mm, addr, fsr, regs); + return 0; +} + +/* + * Handle a data abort. Note that we have to handle a range of addresses + * on ARM2/3 for ldm. If both pages are zero-mapped, then we have to force + * a copy-on-write. However, on the second page, we always force COW. + */ +asmlinkage void +do_DataAbort(unsigned long min_addr, unsigned long max_addr, int mode, struct pt_regs *regs) +{ + do_page_fault(min_addr, mode, regs); + + if ((min_addr ^ max_addr) >> PAGE_SHIFT){ + do_page_fault(max_addr, mode | FAULT_CODE_FORCECOW, regs); + } +} + +asmlinkage int +do_PrefetchAbort(unsigned long addr, struct pt_regs *regs) +{ +#if 0 + if (the memc mapping for this page exists) { + printk ("Page in, but got abort (undefined instruction?)\n"); + return 0; + } +#endif + do_page_fault(addr, FAULT_CODE_PREFETCH, regs); + return 1; +} + diff -Nru a/arch/arm26/mm/fault.h b/arch/arm26/mm/fault.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/mm/fault.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,5 @@ +void show_pte(struct mm_struct *mm, unsigned long addr); + +int do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs); + +unsigned long search_extable(unsigned long addr); //FIXME - is it right? diff -Nru a/arch/arm26/mm/init.c b/arch/arm26/mm/init.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/mm/init.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,401 @@ +/* + * linux/arch/arm/mm/init.c + * + * Copyright (C) 1995-2002 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <linux/config.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/types.h> +#include <linux/ptrace.h> +#include <linux/mman.h> +#include <linux/mm.h> +#include <linux/swap.h> +#include <linux/smp.h> +#include <linux/init.h> +#include <linux/initrd.h> +#include <linux/bootmem.h> +#include <linux/blk.h> + +#include <asm/segment.h> +#include <asm/mach-types.h> +#include <asm/pgalloc.h> +#include <asm/dma.h> +#include <asm/hardware.h> +#include <asm/setup.h> +#include <asm/tlb.h> + +#include <asm/arch.h> +#include <asm/map.h> + +#define TABLE_SIZE PTRS_PER_PTE * sizeof(pte_t)) + +struct mmu_gather mmu_gathers[NR_CPUS]; + +extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; +extern char _stext, _text, _etext, _end, __init_begin, __init_end; +extern unsigned long phys_initrd_start; +extern unsigned long phys_initrd_size; + +/* + * The sole use of this is to pass memory configuration + * data from paging_init to mem_init. + */ +static struct meminfo meminfo __initdata = { 0, }; + +/* + * empty_zero_page is a special page that is used for + * zero-initialized data and COW. + */ +struct page *empty_zero_page; + +void show_mem(void) +{ + int free = 0, total = 0, reserved = 0; + int shared = 0, cached = 0, slab = 0; + struct page *page, *end; + + printk("Mem-info:\n"); + show_free_areas(); + printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); + + + page = NODE_MEM_MAP(0); + end = page + NODE_DATA(0)->node_size; + + do { + total++; + if (PageReserved(page)) + reserved++; + else if (PageSwapCache(page)) + cached++; + else if (PageSlab(page)) + slab++; + else if (!page_count(page)) + free++; + else + shared += atomic_read(&page->count) - 1; + page++; + } while (page < end); + + printk("%d pages of RAM\n", total); + printk("%d free pages\n", free); + printk("%d reserved pages\n", reserved); + printk("%d slab pages\n", slab); + printk("%d pages shared\n", shared); + printk("%d pages swap cached\n", cached); +} + +struct node_info { + unsigned int start; + unsigned int end; + int bootmap_pages; +}; + +#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) +#define PFN_UP(x) (PAGE_ALIGN(x) >> PAGE_SHIFT) +#define PFN_SIZE(x) ((x) >> PAGE_SHIFT) +#define PFN_RANGE(s,e) PFN_SIZE(PAGE_ALIGN((unsigned long)(e)) - \ + (((unsigned long)(s)) & PAGE_MASK)) + +/* + * FIXME: We really want to avoid allocating the bootmap bitmap + * over the top of the initrd. Hopefully, this is located towards + * the start of a bank, so if we allocate the bootmap bitmap at + * the end, we won't clash. + */ +static unsigned int __init +find_bootmap_pfn(struct meminfo *mi, unsigned int bootmap_pages) +{ + unsigned int start_pfn, bootmap_pfn; + unsigned int start, end; + + start_pfn = PFN_UP((unsigned long)&_end); + bootmap_pfn = 0; + + /* ARM26 machines only have one node */ + if (mi->bank->node != 0) + BUG(); + + start = PFN_UP(mi->bank->start); + end = PFN_DOWN(mi->bank->size + mi->bank->start); + + if (start < start_pfn) + start = start_pfn; + + if (end <= start) + BUG(); + + if (end - start >= bootmap_pages) + bootmap_pfn = start; + else + BUG(); + + return bootmap_pfn; +} + +/* + * Scan the memory info structure and pull out: + * - the end of memory + * - the number of nodes + * - the pfn range of each node + * - the number of bootmem bitmap pages + */ +static void __init +find_memend_and_nodes(struct meminfo *mi, struct node_info *np) +{ + unsigned int memend_pfn = 0; + numnodes = 1; + + np->bootmap_pages = 0; + + if (mi->bank->size == 0) { + BUG(); + } + + /* + * Get the start and end pfns for this bank + */ + np->start = PFN_UP(mi->bank->start); + np->end = PFN_DOWN(mi->bank->start + mi->bank->size); + + if (memend_pfn < np->end) + memend_pfn = np->end; + + /* + * Calculate the number of pages we require to + * store the bootmem bitmaps. + */ + np->bootmap_pages = bootmem_bootmap_pages(np->end - np->start); + + /* + * This doesn't seem to be used by the Linux memory + * manager any more. If we can get rid of it, we + * also get rid of some of the stuff above as well. + */ + max_low_pfn = memend_pfn - PFN_DOWN(PHYS_OFFSET); + max_pfn = memend_pfn - PFN_DOWN(PHYS_OFFSET); + mi->end = memend_pfn << PAGE_SHIFT; + +} + +/* + * Reserve the various regions of node 0 + */ +static __init void reserve_node_zero(unsigned int bootmap_pfn, unsigned int bootmap_pages) +{ + pg_data_t *pgdat = NODE_DATA(0); + + /* + * Register the kernel text and data with bootmem. + * Note that this can only be in node 0. + */ + reserve_bootmem_node(pgdat, __pa(&_stext), &_end - &_stext); + + /* + * And don't forget to reserve the allocator bitmap, + * which will be freed later. + */ + reserve_bootmem_node(pgdat, bootmap_pfn << PAGE_SHIFT, + bootmap_pages << PAGE_SHIFT); + + /* + * These should likewise go elsewhere. They pre-reserve + * the screen memory region at the start of main system + * memory. + */ + reserve_bootmem_node(pgdat, 0x02000000, 0x00080000); + +#ifdef CONFIG_BLK_DEV_INITRD + initrd_start = phys_initrd_start; + initrd_end = initrd_start + phys_initrd_size; + + /* Achimedes machines only have one node, so initrd is in node 0 */ + reserve_bootmem_node(pgdat, __pa(initrd_start), + initrd_end - initrd_start); +#endif + +} + + +/* + * Initialise the bootmem allocator for all nodes. This is called + * early during the architecture specific initialisation. + */ +void __init bootmem_init(struct meminfo *mi) +{ + struct node_info node_info; + unsigned int bootmap_pfn; + + find_memend_and_nodes(mi, &node_info); + + bootmap_pfn = find_bootmap_pfn(mi, node_info.bootmap_pages); + + /* + * Note that node 0 must always have some pages. + */ + if (node_info.end == 0) + BUG(); + + /* + * Initialise the bootmem allocator. + */ + init_bootmem_node(NODE_DATA(node), bootmap_pfn, node_info.start, node_info.end); + + /* + * Register all available RAM in this node with the bootmem allocator. + */ + free_bootmem_node(NODE_DATA(node), mi->bank->start, mi->bank->size); + + /* + * Reserve ram for stuff like initrd, video, kernel, etc. + */ + + reserve_node_zero(bootmap_pfn, node_info.bootmap_pages); + +} + +/* + * paging_init() sets up the page tables, initialises the zone memory + * maps, and sets up the zero page, bad page and bad page tables. + */ +void __init paging_init(struct meminfo *mi) +{ + void *zero_page; + unsigned long zone_size[MAX_NR_ZONES]; + unsigned long zhole_size[MAX_NR_ZONES]; + struct bootmem_data *bdata; + pg_data_t *pgdat; + int i; + + memcpy(&meminfo, mi, sizeof(meminfo)); + + /* + * allocate the zero page. Note that we count on this going ok. + */ + zero_page = alloc_bootmem_low_pages(PAGE_SIZE); + + /* + * initialise the page tables. + */ + memtable_init(mi); + flush_tlb_all(); + + /* + * initialise the zones in node 0 (archimedes have only 1 node) + */ + + for (i = 0; i < MAX_NR_ZONES; i++) { + zone_size[i] = 0; + zhole_size[i] = 0; + } + + pgdat = NODE_DATA(0); + bdata = pgdat->bdata; + + zone_size[0] = bdata->node_low_pfn - + (bdata->node_boot_start >> PAGE_SHIFT); + if (!zone_size[0]) + BUG(); + + free_area_init_node(0, pgdat, 0, zone_size, + bdata->node_boot_start >> PAGE_SHIFT, 0); + + mem_map = contig_page_data.node_mem_map; + + /* + * finish off the bad pages once + * the mem_map is initialised + */ + memzero(zero_page, PAGE_SIZE); + empty_zero_page = virt_to_page(zero_page); +} + +static inline void free_area(unsigned long addr, unsigned long end, char *s) +{ + unsigned int size = (end - addr) >> 10; + + for (; addr < end; addr += PAGE_SIZE) { + struct page *page = virt_to_page(addr); + ClearPageReserved(page); + set_page_count(page, 1); + free_page(addr); + totalram_pages++; + } + + if (size && s) + printk(KERN_INFO "Freeing %s memory: %dK\n", s, size); +} + +/* + * mem_init() marks the free areas in the mem_map and tells us how much + * memory is free. This is done after various parts of the system have + * claimed their memory after the kernel image. + */ +void __init mem_init(void) +{ + unsigned int codepages, datapages, initpages; + pg_data_t *pgdat = NODE_DATA(0); + extern int sysctl_overcommit_memory; + + datapages = &_end - &_etext; + codepages = &_etext - &_text; + initpages = &__init_end - &__init_begin; + + high_memory = (void *)__va(meminfo.end); + max_mapnr = virt_to_page(high_memory) - mem_map; + + /* this will put all unused low memory onto the freelists */ + if (pgdat->node_size != 0) + totalram_pages += free_all_bootmem_node(pgdat); + + printk(KERN_INFO "Memory:"); + + num_physpages = meminfo.bank[0].size >> PAGE_SHIFT; + + printk(" = %luMB total\n", num_physpages >> (20 - PAGE_SHIFT)); + printk(KERN_NOTICE "Memory: %luKB available (%dK code, " + "%dK data, %dK init)\n", + (unsigned long) nr_free_pages() << (PAGE_SHIFT-10), + codepages >> 10, datapages >> 10, initpages >> 10); + /* + * Turn on overcommit on tiny machines + */ + if (PAGE_SIZE >= 16384 && num_physpages <= 128) { + sysctl_overcommit_memory = 1; + printk("Turning on overcommit\n"); + } +} + +void free_initmem(void) +{ + free_area((unsigned long)(&__init_begin), + (unsigned long)(&__init_end), + "init"); +} + +#ifdef CONFIG_BLK_DEV_INITRD + +static int keep_initrd; + +void free_initrd_mem(unsigned long start, unsigned long end) +{ + if (!keep_initrd) + free_area(start, end, "initrd"); +} + +static int __init keepinitrd_setup(char *__unused) +{ + keep_initrd = 1; + return 1; +} + +__setup("keepinitrd", keepinitrd_setup); +#endif diff -Nru a/arch/arm26/mm/mm-memc.c b/arch/arm26/mm/mm-memc.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/mm/mm-memc.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,204 @@ +/* + * linux/arch/arm/mm/mm-armo.c + * + * Copyright (C) 1998-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Page table sludge for older ARM processor architectures. + */ +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/init.h> +#include <linux/bootmem.h> + +#include <asm/pgtable.h> +#include <asm/pgalloc.h> +#include <asm/page.h> +#include <asm/memory.h> +#include <asm/hardware.h> + +#include <asm/map.h> + +#define MEMC_TABLE_SIZE (256*sizeof(unsigned long)) + +kmem_cache_t *pte_cache, *pgd_cache; +int page_nr; + +/* + * Allocate space for a page table and a MEMC table. + * Note that we place the MEMC + * table before the page directory. This means we can + * easily get to both tightly-associated data structures + * with a single pointer. + */ +static inline pgd_t *alloc_pgd_table(void) +{ + void *pg2k = kmem_cache_alloc(pgd_cache, GFP_KERNEL); + + if (pg2k) + pg2k += MEMC_TABLE_SIZE; + + return (pgd_t *)pg2k; +} + +/* + * Free a page table. this function is the counterpart to get_pgd_slow + * below, not alloc_pgd_table above. + */ +void free_pgd_slow(pgd_t *pgd) +{ + unsigned long tbl = (unsigned long)pgd; + + tbl -= MEMC_TABLE_SIZE; + + kmem_cache_free(pgd_cache, (void *)tbl); +} + +/* + * Allocate a new pgd and fill it in ready for use + * + * A new tasks pgd is completely empty (all pages !present) except for: + * + * o The machine vectors at virtual address 0x0 + * o The vmalloc region at the top of address space + * + */ +#define FIRST_KERNEL_PGD_NR (FIRST_USER_PGD_NR + USER_PTRS_PER_PGD) + +pgd_t *get_pgd_slow(struct mm_struct *mm) +{ + void *pg2k; + pgd_t *new_pgd, *init_pgd; + pmd_t *new_pmd, *init_pmd; + pte_t *new_pte, *init_pte; + struct mm_struct bob; + + new_pgd = alloc_pgd_table(); + if (!new_pgd) + goto no_pgd; + + /* + * This lock is here just to satisfy pmd_alloc and pte_lock + * FIXME: I bet we could avoid taking it pretty much altogether + */ + spin_lock(&mm->page_table_lock); + + /* + * On ARM, first page must always be allocated since it contains + * the machine vectors. + */ + new_pmd = pmd_alloc(mm, new_pgd, 0); + if (!new_pmd) + goto no_pmd; + + new_pte = pte_alloc_kernel(mm, new_pmd, 0); + if (!new_pte) + goto no_pte; + + init_pgd = pgd_offset(&init_mm, 0); + init_pmd = pmd_offset(init_pgd, 0); + init_pte = pte_offset(init_pmd, 0); + + set_pte(new_pte, *init_pte); + + /* + * the page table entries are zeroed + * when the table is created. (see the cache_ctor functions below) + * Now we need to plonk the kernel (vmalloc) area at the end of + * the address space. We copy this from the init thread, just like + * the init_pte we copied above... + */ + memcpy(new_pgd + FIRST_KERNEL_PGD_NR, init_pgd + FIRST_KERNEL_PGD_NR, + (PTRS_PER_PGD - FIRST_KERNEL_PGD_NR) * sizeof(pgd_t)); + + spin_unlock(&mm->page_table_lock); + + /* update MEMC tables */ + cpu_memc_update_all(new_pgd); + return new_pgd; + +no_pte: + spin_unlock(&mm->page_table_lock); + pmd_free(new_pmd); + free_pgd_slow(new_pgd); + return NULL; + +no_pmd: + spin_unlock(&mm->page_table_lock); + free_pgd_slow(new_pgd); + return NULL; + +no_pgd: + return NULL; +} + +/* + * No special code is required here. + */ +void setup_mm_for_reboot(char mode) +{ +} + +/* + * This contains the code to setup the memory map on an ARM2/ARM250/ARM3 + * o swapper_pg_dir = 0x0207d000 + * o kernel proper starts at 0x0208000 + * o create (allocate) a pte to contain the machine vectors + * o populate the pte (points to 0x02078000) (FIXME - is it zeroed?) + * o populate the init tasks page directory (pgd) with the new pte + * o zero the rest of the init tasks pgdir (FIXME - what about vmalloc?!) + */ +void __init memtable_init(struct meminfo *mi) +{ + pte_t *pte; + int i; + + page_nr = max_low_pfn; + + pte = alloc_bootmem_low_pages(PTRS_PER_PTE * sizeof(pte_t)); + pte[0] = mk_pte_phys(PAGE_OFFSET + SCREEN_SIZE, PAGE_READONLY); + pmd_populate(&init_mm, pmd_offset(swapper_pg_dir, 0), pte); + + for (i = 1; i < PTRS_PER_PGD; i++) + pgd_val(swapper_pg_dir[i]) = 0; +} + +void __init iotable_init(struct map_desc *io_desc) +{ + /* nothing to do */ +} + +/* + * We never have holes in the memmap + */ +void __init create_memmap_holes(struct meminfo *mi) +{ +} + +static void pte_cache_ctor(void *pte, kmem_cache_t *cache, unsigned long flags) +{ + memzero(pte, sizeof(pte_t) * PTRS_PER_PTE); +} + +static void pgd_cache_ctor(void *pgd, kmem_cache_t *cache, unsigned long flags) +{ + memzero(pgd + MEMC_TABLE_SIZE, USER_PTRS_PER_PGD * sizeof(pgd_t)); +} + +void __init pgtable_cache_init(void) +{ + pte_cache = kmem_cache_create("pte-cache", + sizeof(pte_t) * PTRS_PER_PTE, + 0, 0, pte_cache_ctor, NULL); + if (!pte_cache) + BUG(); + + pgd_cache = kmem_cache_create("pgd-cache", MEMC_TABLE_SIZE + + sizeof(pgd_t) * PTRS_PER_PGD, + 0, 0, pgd_cache_ctor, NULL); + if (!pgd_cache) + BUG(); +} diff -Nru a/arch/arm26/mm/proc-funcs.S b/arch/arm26/mm/proc-funcs.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/mm/proc-funcs.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,359 @@ +/* + * linux/arch/arm/mm/proc-arm2,3.S + * + * Copyright (C) 1997-1999 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * MMU functions for ARM2,3 + * + * These are the low level assembler for performing cache + * and memory functions on ARM2, ARM250 and ARM3 processors. + */ +#include <linux/linkage.h> +#include <asm/assembler.h> +#include <asm/asm_offsets.h> +#include <asm/procinfo.h> +#include <asm/ptrace.h> + +/* + * MEMC workhorse code. It's both a horse which things it's a pig. + */ +/* + * Function: cpu_memc_update_entry(pgd_t *pgd, unsigned long phys_pte, unsigned long addr) + * Params : pgd Page tables/MEMC mapping + * : phys_pte physical address, or PTE + * : addr virtual address + */ +ENTRY(cpu_memc_update_entry) + tst r1, #PAGE_PRESENT @ is the page present + orreq r1, r1, #PAGE_OLD | PAGE_CLEAN + moveq r2, #0x01f00000 + mov r3, r1, lsr #13 @ convert to physical page nr + and r3, r3, #0x3fc + adr ip, memc_phys_table_32 + ldr r3, [ip, r3] + tst r1, #PAGE_OLD | PAGE_NOT_USER + biceq r3, r3, #0x200 + tsteq r1, #PAGE_READONLY | PAGE_CLEAN + biceq r3, r3, #0x300 + mov r2, r2, lsr #15 @ virtual -> nr + orr r3, r3, r2, lsl #15 + and r2, r2, #0x300 + orr r3, r3, r2, lsl #2 + and r2, r3, #255 + sub r0, r0, #256 * 4 + str r3, [r0, r2, lsl #2] + strb r3, [r3] + movs pc, lr +/* + * Params : r0 = preserved + * : r1 = memc table base (preserved) + * : r2 = page table entry + * : r3 = preserved + * : r4 = unused + * : r5 = memc physical address translation table + * : ip = virtual address (preserved) + */ +update_pte: + mov r4, r2, lsr #13 + and r4, r4, #0x3fc + ldr r4, [r5, r4] @ covert to MEMC page + + tst r2, #PAGE_OLD | PAGE_NOT_USER @ check for MEMC read + biceq r4, r4, #0x200 + tsteq r2, #PAGE_READONLY | PAGE_CLEAN @ check for MEMC write + biceq r4, r4, #0x300 + + orr r4, r4, ip + and r2, ip, #0x01800000 + orr r4, r4, r2, lsr #13 + + and r2, r4, #255 + str r4, [r1, r2, lsl #2] + movs pc, lr + +/* + * Params : r0 = preserved + * : r1 = memc table base (preserved) + * : r2 = page table base + * : r3 = preserved + * : r4 = unused + * : r5 = memc physical address translation table + * : ip = virtual address (updated) + */ +update_pte_table: + stmfd sp!, {r0, lr} + bic r0, r2, #3 +1: ldr r2, [r0], #4 @ get entry + tst r2, #PAGE_PRESENT @ page present + blne update_pte @ process pte + add ip, ip, #32768 @ increment virt addr + ldr r2, [r0], #4 @ get entry + tst r2, #PAGE_PRESENT @ page present + blne update_pte @ process pte + add ip, ip, #32768 @ increment virt addr + ldr r2, [r0], #4 @ get entry + tst r2, #PAGE_PRESENT @ page present + blne update_pte @ process pte + add ip, ip, #32768 @ increment virt addr + ldr r2, [r0], #4 @ get entry + tst r2, #PAGE_PRESENT @ page present + blne update_pte @ process pte + add ip, ip, #32768 @ increment virt addr + tst ip, #32768 * 31 @ finished? + bne 1b + ldmfd sp!, {r0, pc}^ + +/* + * Function: cpu_memc_update_all(pgd_t *pgd) + * Params : pgd Page tables/MEMC mapping + * Notes : this is optimised for 32k pages + */ +ENTRY(cpu_memc_update_all) + stmfd sp!, {r4, r5, lr} + bl clear_tables + sub r1, r0, #256 * 4 @ start of MEMC tables + adr r5, memc_phys_table_32 @ Convert to logical page number + mov ip, #0 @ virtual address +1: ldmia r0!, {r2, r3} @ load two pgd entries + tst r2, #PAGE_PRESENT @ is pgd entry present? + addeq ip, ip, #1048576 @FIXME - PAGE_PRESENT is for PTEs technically... + blne update_pte_table + mov r2, r3 + tst r2, #PAGE_PRESENT @ is pgd entry present? + addeq ip, ip, #1048576 + blne update_pte_table + teq ip, #32 * 1048576 + bne 1b + ldmfd sp!, {r4, r5, pc}^ + +/* + * Build the table to map from physical page number to memc page number + */ + .type memc_phys_table_32, #object +memc_phys_table_32: + .irp b7, 0x00, 0x80 + .irp b6, 0x00, 0x02 + .irp b5, 0x00, 0x04 + .irp b4, 0x00, 0x01 + + .irp b3, 0x00, 0x40 + .irp b2, 0x00, 0x20 + .irp b1, 0x00, 0x10 + .irp b0, 0x00, 0x08 + .long 0x03800300 + \b7 + \b6 + \b5 + \b4 + \b3 + \b2 + \b1 + \b0 + .endr + .endr + .endr + .endr + + .endr + .endr + .endr + .endr + .size memc_phys_table_32, . - memc_phys_table_32 + +/* + * helper for cpu_memc_update_all, this clears out all + * mappings, setting them close to the top of memory, + * and inaccessible (0x01f00000). + * Params : r0 = page table pointer + */ +clear_tables: ldr r1, _arm3_set_pgd - 4 + ldr r2, [r1] + sub r1, r0, #256 * 4 @ start of MEMC tables + add r2, r1, r2, lsl #2 @ end of tables + mov r3, #0x03f00000 @ Default mapping (null mapping) + orr r3, r3, #0x00000f00 + orr r4, r3, #1 + orr r5, r3, #2 + orr ip, r3, #3 +1: stmia r1!, {r3, r4, r5, ip} + add r3, r3, #4 + add r4, r4, #4 + add r5, r5, #4 + add ip, ip, #4 + stmia r1!, {r3, r4, r5, ip} + add r3, r3, #4 + add r4, r4, #4 + add r5, r5, #4 + add ip, ip, #4 + teq r1, r2 + bne 1b + mov pc, lr + +/* + * Function: *_set_pgd(pgd_t *pgd) + * Params : pgd New page tables/MEMC mapping + * Purpose : update MEMC hardware with new mapping + */ + .word page_nr @ extern - declared in mm-memc.c +_arm3_set_pgd: mcr p15, 0, r1, c1, c0, 0 @ flush cache +_arm2_set_pgd: stmfd sp!, {lr} + ldr r1, _arm3_set_pgd - 4 + ldr r2, [r1] + sub r0, r0, #256 * 4 @ start of MEMC tables + add r1, r0, r2, lsl #2 @ end of tables +1: ldmia r0!, {r2, r3, ip, lr} + strb r2, [r2] + strb r3, [r3] + strb ip, [ip] + strb lr, [lr] + ldmia r0!, {r2, r3, ip, lr} + strb r2, [r2] + strb r3, [r3] + strb ip, [ip] + strb lr, [lr] + teq r0, r1 + bne 1b + ldmfd sp!, {pc}^ + +/* + * Function: *_proc_init (void) + * Purpose : Initialise the cache control registers + */ +_arm3_proc_init: + mov r0, #0x001f0000 + orr r0, r0, #0x0000ff00 + orr r0, r0, #0x000000ff + mcr p15, 0, r0, c3, c0 @ ARM3 Cacheable + mcr p15, 0, r0, c4, c0 @ ARM3 Updateable + mov r0, #0 + mcr p15, 0, r0, c5, c0 @ ARM3 Disruptive + mcr p15, 0, r0, c1, c0 @ ARM3 Flush + mov r0, #3 + mcr p15, 0, r0, c2, c0 @ ARM3 Control +_arm2_proc_init: + movs pc, lr + +/* + * Function: *_proc_fin (void) + * Purpose : Finalise processor (disable caches) + */ +_arm3_proc_fin: mov r0, #2 + mcr p15, 0, r0, c2, c0 +_arm2_proc_fin: orrs pc, lr, #PSR_I_BIT|PSR_F_BIT + +/* + * Function: *_xchg_1 (int new, volatile void *ptr) + * Params : new New value to store at... + * : ptr pointer to byte-wide location + * Purpose : Performs an exchange operation + * Returns : Original byte data at 'ptr' + */ +_arm2_xchg_1: mov r2, pc + orr r2, r2, #PSR_I_BIT + teqp r2, #0 + ldrb r2, [r1] + strb r0, [r1] + mov r0, r2 + movs pc, lr + +_arm3_xchg_1: swpb r0, r0, [r1] + movs pc, lr + +/* + * Function: *_xchg_4 (int new, volatile void *ptr) + * Params : new New value to store at... + * : ptr pointer to word-wide location + * Purpose : Performs an exchange operation + * Returns : Original word data at 'ptr' + */ +_arm2_xchg_4: mov r2, pc + orr r2, r2, #PSR_I_BIT + teqp r2, #0 + ldr r2, [r1] + str r0, [r1] + mov r0, r2 + movs pc, lr + +_arm3_xchg_4: swp r0, r0, [r1] + movs pc, lr + +_arm2_3_check_bugs: + bics pc, lr, #PSR_F_BIT @ Clear FIQ disable bit + +armvlsi_name: .asciz "ARM/VLSI" +_arm2_name: .asciz "ARM 2" +_arm250_name: .asciz "ARM 250" +_arm3_name: .asciz "ARM 3" + + .section ".init.text", #alloc, #execinstr +/* + * Purpose : Function pointers used to access above functions - all calls + * come through these + */ + .globl arm2_processor_functions +arm2_processor_functions: + .word _arm2_3_check_bugs + .word _arm2_proc_init + .word _arm2_proc_fin + .word _arm2_set_pgd + .word _arm2_xchg_1 + .word _arm2_xchg_4 + +cpu_arm2_info: + .long armvlsi_name + .long _arm2_name + + .globl arm250_processor_functions +arm250_processor_functions: + .word _arm2_3_check_bugs + .word _arm2_proc_init + .word _arm2_proc_fin + .word _arm2_set_pgd + .word _arm3_xchg_1 + .word _arm3_xchg_4 + +cpu_arm250_info: + .long armvlsi_name + .long _arm250_name + + .globl arm3_processor_functions +arm3_processor_functions: + .word _arm2_3_check_bugs + .word _arm3_proc_init + .word _arm3_proc_fin + .word _arm3_set_pgd + .word _arm3_xchg_1 + .word _arm3_xchg_4 + +cpu_arm3_info: + .long armvlsi_name + .long _arm3_name + +arm2_arch_name: .asciz "armv1" +arm3_arch_name: .asciz "armv2" +arm2_elf_name: .asciz "v1" +arm3_elf_name: .asciz "v2" + .align + + .section ".proc.info", #alloc, #execinstr + + .long 0x41560200 + .long 0xfffffff0 + .long arm2_arch_name + .long arm2_elf_name + .long 0 + .long cpu_arm2_info + .long arm2_processor_functions + + .long 0x41560250 + .long 0xfffffff0 + .long arm3_arch_name + .long arm3_elf_name + .long 0 + .long cpu_arm250_info + .long arm250_processor_functions + + .long 0x41560300 + .long 0xfffffff0 + .long arm3_arch_name + .long arm3_elf_name + .long 0 + .long cpu_arm3_info + .long arm3_processor_functions + diff -Nru a/arch/arm26/nwfpe/ARM-gcc.h b/arch/arm26/nwfpe/ARM-gcc.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/nwfpe/ARM-gcc.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,120 @@ +/* +------------------------------------------------------------------------------- +The macro `BITS64' can be defined to indicate that 64-bit integer types are +supported by the compiler. +------------------------------------------------------------------------------- +*/ +#define BITS64 + +/* +------------------------------------------------------------------------------- +Each of the following `typedef's defines the most convenient type that holds +integers of at least as many bits as specified. For example, `uint8' should +be the most convenient type that can hold unsigned integers of as many as +8 bits. The `flag' type must be able to hold either a 0 or 1. For most +implementations of C, `flag', `uint8', and `int8' should all be `typedef'ed +to the same as `int'. +------------------------------------------------------------------------------- +*/ +typedef char flag; +typedef unsigned char uint8; +typedef signed char int8; +typedef int uint16; +typedef int int16; +typedef unsigned int uint32; +typedef signed int int32; +#ifdef BITS64 +typedef unsigned long long int bits64; +typedef signed long long int sbits64; +#endif + +/* +------------------------------------------------------------------------------- +Each of the following `typedef's defines a type that holds integers +of _exactly_ the number of bits specified. For instance, for most +implementation of C, `bits16' and `sbits16' should be `typedef'ed to +`unsigned short int' and `signed short int' (or `short int'), respectively. +------------------------------------------------------------------------------- +*/ +typedef unsigned char bits8; +typedef signed char sbits8; +typedef unsigned short int bits16; +typedef signed short int sbits16; +typedef unsigned int bits32; +typedef signed int sbits32; +#ifdef BITS64 +typedef unsigned long long int uint64; +typedef signed long long int int64; +#endif + +#ifdef BITS64 +/* +------------------------------------------------------------------------------- +The `LIT64' macro takes as its argument a textual integer literal and if +necessary ``marks'' the literal as having a 64-bit integer type. For +example, the Gnu C Compiler (`gcc') requires that 64-bit literals be +appended with the letters `LL' standing for `long long', which is `gcc's +name for the 64-bit integer type. Some compilers may allow `LIT64' to be +defined as the identity macro: `#define LIT64( a ) a'. +------------------------------------------------------------------------------- +*/ +#define LIT64( a ) a##LL +#endif + +/* +------------------------------------------------------------------------------- +The macro `INLINE' can be used before functions that should be inlined. If +a compiler does not support explicit inlining, this macro should be defined +to be `static'. +------------------------------------------------------------------------------- +*/ +#define INLINE extern __inline__ + + +/* For use as a GCC soft-float library we need some special function names. */ + +#ifdef __LIBFLOAT__ + +/* Some 32-bit ops can be mapped straight across by just changing the name. */ +#define float32_add __addsf3 +#define float32_sub __subsf3 +#define float32_mul __mulsf3 +#define float32_div __divsf3 +#define int32_to_float32 __floatsisf +#define float32_to_int32_round_to_zero __fixsfsi +#define float32_to_uint32_round_to_zero __fixunssfsi + +/* These ones go through the glue code. To avoid namespace pollution + we rename the internal functions too. */ +#define float32_eq ___float32_eq +#define float32_le ___float32_le +#define float32_lt ___float32_lt + +/* All the 64-bit ops have to go through the glue, so we pull the same + trick. */ +#define float64_add ___float64_add +#define float64_sub ___float64_sub +#define float64_mul ___float64_mul +#define float64_div ___float64_div +#define int32_to_float64 ___int32_to_float64 +#define float64_to_int32_round_to_zero ___float64_to_int32_round_to_zero +#define float64_to_uint32_round_to_zero ___float64_to_uint32_round_to_zero +#define float64_to_float32 ___float64_to_float32 +#define float32_to_float64 ___float32_to_float64 +#define float64_eq ___float64_eq +#define float64_le ___float64_le +#define float64_lt ___float64_lt + +#if 0 +#define float64_add __adddf3 +#define float64_sub __subdf3 +#define float64_mul __muldf3 +#define float64_div __divdf3 +#define int32_to_float64 __floatsidf +#define float64_to_int32_round_to_zero __fixdfsi +#define float64_to_uint32_round_to_zero __fixunsdfsi +#define float64_to_float32 __truncdfsf2 +#define float32_to_float64 __extendsfdf2 +#endif + +#endif diff -Nru a/arch/arm26/nwfpe/ChangeLog b/arch/arm26/nwfpe/ChangeLog --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/nwfpe/ChangeLog Mon Jun 9 23:16:20 2003 @@ -0,0 +1,83 @@ +2002-01-19 Russell King <rmk@arm.linux.org.uk> + + * fpa11.h - Add documentation + - remove userRegisters pointer from this structure. + - add new method to obtain integer register values. + * softfloat.c - Remove float128 + * softfloat.h - Remove float128 + * softfloat-specialize - Remove float128 + + * The FPA11 structure is not a kernel-specific data structure. + It is used by users of ptrace to examine the values of the + floating point registers. Therefore, any changes to the + FPA11 structure (size or position of elements contained + within) have to be well thought out. + + * Since 128-bit float requires the FPA11 structure to change + size, it has been removed. 128-bit float is currently unused, + and needs various things to be re-worked so that we won't + overflow the available space in the task structure. + + * The changes are designed to break any patch that goes on top + of this code, so that the authors properly review their changes. + +1999-08-19 Scott Bambrough <scottb@netwinder.org> + + * fpmodule.c - Changed version number to 0.95 + * fpa11.h - modified FPA11, FPREG structures + * fpa11.c - Changes due to FPA11, FPREG structure alterations. + * fpa11_cpdo.c - Changes due to FPA11, FPREG structure alterations. + * fpa11_cpdt.c - Changes due to FPA11, FPREG structure alterations. + * fpa11_cprt.c - Changes due to FPA11, FPREG structure alterations. + * single_cpdo.c - Changes due to FPA11, FPREG structure alterations. + * double_cpdo.c - Changes due to FPA11, FPREG structure alterations. + * extended_cpdo.c - Changes due to FPA11, FPREG structure alterations. + + * I discovered several bugs. First and worst is that the kernel + passes in a pointer to the FPE's state area. This is defined + as a struct user_fp (see user.h). This pointer was cast to a + FPA11*. Unfortunately FPA11 and user_fp are of different sizes; + user_fp is smaller. This meant that the FPE scribbled on things + below its area, which is bad, as the area is in the thread_struct + embedded in the process task structure. Thus we were scribbling + over one of the most important structures in the entire OS. + + * user_fp and FPA11 have now been harmonized. Most of the changes + in the above code were dereferencing problems due to moving the + register type out of FPREG, and getting rid of the union variable + fpvalue. + + * Second I noticed resetFPA11 was not always being called for a + task. This should happen on the first floating point exception + that occurs. It is controlled by init_flag in FPA11. The + comment in the code beside init_flag state the kernel guarantees + this to be zero. Not so. I found that the kernel recycles task + structures, and that recycled ones may not have init_flag zeroed. + I couldn't even find anything that guarantees it is zeroed when + when the task structure is initially allocated. In any case + I now initialize the entire FPE state in the thread structure to + zero when allocated and recycled. See alloc_task_struct() and + flush_thread() in arch/arm/process.c. The change to + alloc_task_struct() may not be necessary, but I left it in for + completeness (better safe than sorry). + +1998-11-23 Scott Bambrough <scottb@netwinder.org> + + * README.FPE - fix typo in description of lfm/sfm instructions + * NOTES - Added file to describe known bugs/problems + * fpmodule.c - Changed version number to 0.94 + +1998-11-20 Scott Bambrough <scottb@netwinder.org> + + * README.FPE - fix description of URD, NRM instructions + * TODO - remove URD, NRM instructions from TODO list + * single_cpdo.c - implement URD, NRM + * double_cpdo.c - implement URD, NRM + * extended_cpdo.c - implement URD, NRM + +1998-11-19 Scott Bambrough <scottb@netwinder.org> + + * ChangeLog - Added this file to track changes made. + * fpa11.c - added code to initialize register types to typeNone + * fpa11_cpdt.c - fixed bug in storeExtended (typeExtended changed to + typeDouble in switch statement) diff -Nru a/arch/arm26/nwfpe/Makefile b/arch/arm26/nwfpe/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/nwfpe/Makefile Mon Jun 9 23:16:20 2003 @@ -0,0 +1,15 @@ +# +# Copyright (C) 1998, 1999, 2001 Philip Blundell +# + +obj-y := +obj-m := +obj-n := + +obj-$(CONFIG_FPE_NWFPE) += nwfpe.o + +nwfpe-objs := fpa11.o fpa11_cpdo.o fpa11_cpdt.o fpa11_cprt.o \ + fpmodule.o fpopcode.o softfloat.o \ + single_cpdo.o double_cpdo.o extended_cpdo.o \ + entry.o + diff -Nru a/arch/arm26/nwfpe/double_cpdo.c b/arch/arm26/nwfpe/double_cpdo.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/nwfpe/double_cpdo.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,288 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998,1999 + + Direct questions, comments to Scott Bambrough <scottb@netwinder.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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "fpa11.h" +#include "softfloat.h" +#include "fpopcode.h" + +float64 float64_exp(float64 Fm); +float64 float64_ln(float64 Fm); +float64 float64_sin(float64 rFm); +float64 float64_cos(float64 rFm); +float64 float64_arcsin(float64 rFm); +float64 float64_arctan(float64 rFm); +float64 float64_log(float64 rFm); +float64 float64_tan(float64 rFm); +float64 float64_arccos(float64 rFm); +float64 float64_pow(float64 rFn,float64 rFm); +float64 float64_pol(float64 rFn,float64 rFm); + +unsigned int DoubleCPDO(const unsigned int opcode) +{ + FPA11 *fpa11 = GET_FPA11(); + float64 rFm, rFn = 0; //FIXME - should be zero? + unsigned int Fd, Fm, Fn, nRc = 1; + + //printk("DoubleCPDO(0x%08x)\n",opcode); + + Fm = getFm(opcode); + if (CONSTANT_FM(opcode)) + { + rFm = getDoubleConstant(Fm); + } + else + { + switch (fpa11->fType[Fm]) + { + case typeSingle: + rFm = float32_to_float64(fpa11->fpreg[Fm].fSingle); + break; + + case typeDouble: + rFm = fpa11->fpreg[Fm].fDouble; + break; + + case typeExtended: + // !! patb + //printk("not implemented! why not?\n"); + //!! ScottB + // should never get here, if extended involved + // then other operand should be promoted then + // ExtendedCPDO called. + break; + + default: return 0; + } + } + + if (!MONADIC_INSTRUCTION(opcode)) + { + Fn = getFn(opcode); + switch (fpa11->fType[Fn]) + { + case typeSingle: + rFn = float32_to_float64(fpa11->fpreg[Fn].fSingle); + break; + + case typeDouble: + rFn = fpa11->fpreg[Fn].fDouble; + break; + + default: return 0; + } + } + + Fd = getFd(opcode); + /* !! this switch isn't optimized; better (opcode & MASK_ARITHMETIC_OPCODE)>>24, sort of */ + switch (opcode & MASK_ARITHMETIC_OPCODE) + { + /* dyadic opcodes */ + case ADF_CODE: + fpa11->fpreg[Fd].fDouble = float64_add(rFn,rFm); + break; + + case MUF_CODE: + case FML_CODE: + fpa11->fpreg[Fd].fDouble = float64_mul(rFn,rFm); + break; + + case SUF_CODE: + fpa11->fpreg[Fd].fDouble = float64_sub(rFn,rFm); + break; + + case RSF_CODE: + fpa11->fpreg[Fd].fDouble = float64_sub(rFm,rFn); + break; + + case DVF_CODE: + case FDV_CODE: + fpa11->fpreg[Fd].fDouble = float64_div(rFn,rFm); + break; + + case RDF_CODE: + case FRD_CODE: + fpa11->fpreg[Fd].fDouble = float64_div(rFm,rFn); + break; + +#if 0 + case POW_CODE: + fpa11->fpreg[Fd].fDouble = float64_pow(rFn,rFm); + break; + + case RPW_CODE: + fpa11->fpreg[Fd].fDouble = float64_pow(rFm,rFn); + break; +#endif + + case RMF_CODE: + fpa11->fpreg[Fd].fDouble = float64_rem(rFn,rFm); + break; + +#if 0 + case POL_CODE: + fpa11->fpreg[Fd].fDouble = float64_pol(rFn,rFm); + break; +#endif + + /* monadic opcodes */ + case MVF_CODE: + fpa11->fpreg[Fd].fDouble = rFm; + break; + + case MNF_CODE: + { + unsigned int *p = (unsigned int*)&rFm; + p[1] ^= 0x80000000; + fpa11->fpreg[Fd].fDouble = rFm; + } + break; + + case ABS_CODE: + { + unsigned int *p = (unsigned int*)&rFm; + p[1] &= 0x7fffffff; + fpa11->fpreg[Fd].fDouble = rFm; + } + break; + + case RND_CODE: + case URD_CODE: + fpa11->fpreg[Fd].fDouble = float64_round_to_int(rFm); + break; + + case SQT_CODE: + fpa11->fpreg[Fd].fDouble = float64_sqrt(rFm); + break; + +#if 0 + case LOG_CODE: + fpa11->fpreg[Fd].fDouble = float64_log(rFm); + break; + + case LGN_CODE: + fpa11->fpreg[Fd].fDouble = float64_ln(rFm); + break; + + case EXP_CODE: + fpa11->fpreg[Fd].fDouble = float64_exp(rFm); + break; + + case SIN_CODE: + fpa11->fpreg[Fd].fDouble = float64_sin(rFm); + break; + + case COS_CODE: + fpa11->fpreg[Fd].fDouble = float64_cos(rFm); + break; + + case TAN_CODE: + fpa11->fpreg[Fd].fDouble = float64_tan(rFm); + break; + + case ASN_CODE: + fpa11->fpreg[Fd].fDouble = float64_arcsin(rFm); + break; + + case ACS_CODE: + fpa11->fpreg[Fd].fDouble = float64_arccos(rFm); + break; + + case ATN_CODE: + fpa11->fpreg[Fd].fDouble = float64_arctan(rFm); + break; +#endif + + case NRM_CODE: + break; + + default: + { + nRc = 0; + } + } + + if (0 != nRc) fpa11->fType[Fd] = typeDouble; + return nRc; +} + +#if 0 +float64 float64_exp(float64 rFm) +{ + return rFm; +//series +} + +float64 float64_ln(float64 rFm) +{ + return rFm; +//series +} + +float64 float64_sin(float64 rFm) +{ + return rFm; +//series +} + +float64 float64_cos(float64 rFm) +{ + return rFm; + //series +} + +#if 0 +float64 float64_arcsin(float64 rFm) +{ +//series +} + +float64 float64_arctan(float64 rFm) +{ + //series +} +#endif + +float64 float64_log(float64 rFm) +{ + return float64_div(float64_ln(rFm),getDoubleConstant(7)); +} + +float64 float64_tan(float64 rFm) +{ + return float64_div(float64_sin(rFm),float64_cos(rFm)); +} + +float64 float64_arccos(float64 rFm) +{ +return rFm; + //return float64_sub(halfPi,float64_arcsin(rFm)); +} + +float64 float64_pow(float64 rFn,float64 rFm) +{ + return float64_exp(float64_mul(rFm,float64_ln(rFn))); +} + +float64 float64_pol(float64 rFn,float64 rFm) +{ + return float64_arctan(float64_div(rFn,rFm)); +} +#endif diff -Nru a/arch/arm26/nwfpe/entry.S b/arch/arm26/nwfpe/entry.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/nwfpe/entry.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,114 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998 + (c) Philip Blundell 1998-1999 + + Direct questions, comments to Scott Bambrough <scottb@netwinder.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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include <asm/asm_offsets.h> + +/* This is the kernel's entry point into the floating point emulator. +It is called from the kernel with code similar to this: + + mov fp, #0 + teqp pc, #PSR_I_BIT | MODE_SVC + ldr r4, .LC2 + ldr pc, [r4] @ Call FP module USR entry point + +The kernel expects the emulator to return via one of two possible +points of return it passes to the emulator. The emulator, if +successful in its emulation, jumps to ret_from_exception and the +kernel takes care of returning control from the trap to the user code. +If the emulator is unable to emulate the instruction, it returns to +fpundefinstr and the kernel halts the user program with a core dump. + +This routine does four things: + +1) It saves SP into a variable called userRegisters. The kernel has +created a struct pt_regs on the stack and saved the user registers +into it. See /usr/include/asm/proc/ptrace.h for details. The +emulator code uses userRegisters as the base of an array of words from +which the contents of the registers can be extracted. + +2) It locates the FP emulator work area within the TSS structure and +points `fpa11' to it. + +3) It calls EmulateAll to emulate a floating point instruction. +EmulateAll returns 1 if the emulation was successful, or 0 if not. + +4) If an instruction has been emulated successfully, it looks ahead at +the next instruction. If it is a floating point instruction, it +executes the instruction, without returning to user space. In this +way it repeatedly looks ahead and executes floating point instructions +until it encounters a non floating point instruction, at which time it +returns via _fpreturn. + +This is done to reduce the effect of the trap overhead on each +floating point instructions. GCC attempts to group floating point +instructions to allow the emulator to spread the cost of the trap over +several floating point instructions. */ + + .globl nwfpe_enter +nwfpe_enter: + mov sl, sp + bl FPA11_CheckInit @ check to see if we are initialised + + ldr r5, [sp, #60] @ get contents of PC + bic r5, r5, #0xfc000003 + ldr r0, [r5, #-4] @ get actual instruction into r0 + bl EmulateAll @ emulate the instruction +1: cmp r0, #0 @ was emulation successful + beq fpundefinstr @ no, return failure + +next: +.Lx1: ldrt r6, [r5], #4 @ get the next instruction and + @ increment PC + + and r2, r6, #0x0F000000 @ test for FP insns + teq r2, #0x0C000000 + teqne r2, #0x0D000000 + teqne r2, #0x0E000000 + bne ret_from_exception @ return ok if not a fp insn + + ldr r9, [sp, #60] @ get new condition codes + and r9, r9, #0xfc000003 + orr r7, r5, r9 + str r7, [sp, #60] @ update PC copy in regs + + mov r0, r6 @ save a copy + mov r1, r9 @ fetch the condition codes + bl checkCondition @ check the condition + cmp r0, #0 @ r0 = 0 ==> condition failed + + @ if condition code failed to match, next insn + beq next @ get the next instruction; + + mov r0, r6 @ prepare for EmulateAll() + adr lr, 1b + orr lr, lr, #3 + b EmulateAll @ if r0 != 0, goto EmulateAll + +.Lret: b ret_from_exception @ let the user eat segfaults + + @ We need to be prepared for the instruction at .Lx1 to fault. + @ Emit the appropriate exception gunk to fix things up. + .section __ex_table,"a" + .align 3 + .long .Lx1 + ldr lr, [lr, $(.Lret - .Lx1)/4] + .previous diff -Nru a/arch/arm26/nwfpe/extended_cpdo.c b/arch/arm26/nwfpe/extended_cpdo.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/nwfpe/extended_cpdo.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,273 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998,1999 + + Direct questions, comments to Scott Bambrough <scottb@netwinder.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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "fpa11.h" +#include "softfloat.h" +#include "fpopcode.h" + +floatx80 floatx80_exp(floatx80 Fm); +floatx80 floatx80_ln(floatx80 Fm); +floatx80 floatx80_sin(floatx80 rFm); +floatx80 floatx80_cos(floatx80 rFm); +floatx80 floatx80_arcsin(floatx80 rFm); +floatx80 floatx80_arctan(floatx80 rFm); +floatx80 floatx80_log(floatx80 rFm); +floatx80 floatx80_tan(floatx80 rFm); +floatx80 floatx80_arccos(floatx80 rFm); +floatx80 floatx80_pow(floatx80 rFn,floatx80 rFm); +floatx80 floatx80_pol(floatx80 rFn,floatx80 rFm); + +unsigned int ExtendedCPDO(const unsigned int opcode) +{ + FPA11 *fpa11 = GET_FPA11(); + floatx80 rFm, rFn; + unsigned int Fd, Fm, Fn, nRc = 1; + + //printk("ExtendedCPDO(0x%08x)\n",opcode); + + Fm = getFm(opcode); + if (CONSTANT_FM(opcode)) + { + rFm = getExtendedConstant(Fm); + } + else + { + switch (fpa11->fType[Fm]) + { + case typeSingle: + rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle); + break; + + case typeDouble: + rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble); + break; + + case typeExtended: + rFm = fpa11->fpreg[Fm].fExtended; + break; + + default: return 0; + } + } + + if (!MONADIC_INSTRUCTION(opcode)) + { + Fn = getFn(opcode); + switch (fpa11->fType[Fn]) + { + case typeSingle: + rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle); + break; + + case typeDouble: + rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble); + break; + + case typeExtended: + rFn = fpa11->fpreg[Fn].fExtended; + break; + + default: return 0; + } + } + + Fd = getFd(opcode); + switch (opcode & MASK_ARITHMETIC_OPCODE) + { + /* dyadic opcodes */ + case ADF_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_add(rFn,rFm); + break; + + case MUF_CODE: + case FML_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_mul(rFn,rFm); + break; + + case SUF_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_sub(rFn,rFm); + break; + + case RSF_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_sub(rFm,rFn); + break; + + case DVF_CODE: + case FDV_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_div(rFn,rFm); + break; + + case RDF_CODE: + case FRD_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_div(rFm,rFn); + break; + +#if 0 + case POW_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_pow(rFn,rFm); + break; + + case RPW_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_pow(rFm,rFn); + break; +#endif + + case RMF_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_rem(rFn,rFm); + break; + +#if 0 + case POL_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_pol(rFn,rFm); + break; +#endif + + /* monadic opcodes */ + case MVF_CODE: + fpa11->fpreg[Fd].fExtended = rFm; + break; + + case MNF_CODE: + rFm.high ^= 0x8000; + fpa11->fpreg[Fd].fExtended = rFm; + break; + + case ABS_CODE: + rFm.high &= 0x7fff; + fpa11->fpreg[Fd].fExtended = rFm; + break; + + case RND_CODE: + case URD_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_round_to_int(rFm); + break; + + case SQT_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_sqrt(rFm); + break; + +#if 0 + case LOG_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_log(rFm); + break; + + case LGN_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_ln(rFm); + break; + + case EXP_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_exp(rFm); + break; + + case SIN_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_sin(rFm); + break; + + case COS_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_cos(rFm); + break; + + case TAN_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_tan(rFm); + break; + + case ASN_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_arcsin(rFm); + break; + + case ACS_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_arccos(rFm); + break; + + case ATN_CODE: + fpa11->fpreg[Fd].fExtended = floatx80_arctan(rFm); + break; +#endif + + case NRM_CODE: + break; + + default: + { + nRc = 0; + } + } + + if (0 != nRc) fpa11->fType[Fd] = typeExtended; + return nRc; +} + +#if 0 +floatx80 floatx80_exp(floatx80 Fm) +{ +//series +} + +floatx80 floatx80_ln(floatx80 Fm) +{ +//series +} + +floatx80 floatx80_sin(floatx80 rFm) +{ +//series +} + +floatx80 floatx80_cos(floatx80 rFm) +{ +//series +} + +floatx80 floatx80_arcsin(floatx80 rFm) +{ +//series +} + +floatx80 floatx80_arctan(floatx80 rFm) +{ + //series +} + +floatx80 floatx80_log(floatx80 rFm) +{ + return floatx80_div(floatx80_ln(rFm),getExtendedConstant(7)); +} + +floatx80 floatx80_tan(floatx80 rFm) +{ + return floatx80_div(floatx80_sin(rFm),floatx80_cos(rFm)); +} + +floatx80 floatx80_arccos(floatx80 rFm) +{ + //return floatx80_sub(halfPi,floatx80_arcsin(rFm)); +} + +floatx80 floatx80_pow(floatx80 rFn,floatx80 rFm) +{ + return floatx80_exp(floatx80_mul(rFm,floatx80_ln(rFn))); +} + +floatx80 floatx80_pol(floatx80 rFn,floatx80 rFm) +{ + return floatx80_arctan(floatx80_div(rFn,rFm)); +} +#endif diff -Nru a/arch/arm26/nwfpe/fpa11.c b/arch/arm26/nwfpe/fpa11.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/nwfpe/fpa11.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,221 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998,1999 + + Direct questions, comments to Scott Bambrough <scottb@netwinder.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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "fpa11.h" +#include "fpopcode.h" + +#include "fpmodule.h" +#include "fpmodule.inl" + +#include <linux/compiler.h> +#include <asm/system.h> + +/* forward declarations */ +unsigned int EmulateCPDO(const unsigned int); +unsigned int EmulateCPDT(const unsigned int); +unsigned int EmulateCPRT(const unsigned int); + +/* Reset the FPA11 chip. Called to initialize and reset the emulator. */ +void resetFPA11(void) +{ + int i; + FPA11 *fpa11 = GET_FPA11(); + + /* initialize the register type array */ + for (i=0;i<=7;i++) + { + fpa11->fType[i] = typeNone; + } + + /* FPSR: set system id to FP_EMULATOR, set AC, clear all other bits */ + fpa11->fpsr = FP_EMULATOR | BIT_AC; + + /* FPCR: set SB, AB and DA bits, clear all others */ +#if MAINTAIN_FPCR + fpa11->fpcr = MASK_RESET; +#endif +} + +void SetRoundingMode(const unsigned int opcode) +{ +#if MAINTAIN_FPCR + FPA11 *fpa11 = GET_FPA11(); + fpa11->fpcr &= ~MASK_ROUNDING_MODE; +#endif + switch (opcode & MASK_ROUNDING_MODE) + { + default: + case ROUND_TO_NEAREST: + float_rounding_mode = float_round_nearest_even; +#if MAINTAIN_FPCR + fpa11->fpcr |= ROUND_TO_NEAREST; +#endif + break; + + case ROUND_TO_PLUS_INFINITY: + float_rounding_mode = float_round_up; +#if MAINTAIN_FPCR + fpa11->fpcr |= ROUND_TO_PLUS_INFINITY; +#endif + break; + + case ROUND_TO_MINUS_INFINITY: + float_rounding_mode = float_round_down; +#if MAINTAIN_FPCR + fpa11->fpcr |= ROUND_TO_MINUS_INFINITY; +#endif + break; + + case ROUND_TO_ZERO: + float_rounding_mode = float_round_to_zero; +#if MAINTAIN_FPCR + fpa11->fpcr |= ROUND_TO_ZERO; +#endif + break; + } +} + +void SetRoundingPrecision(const unsigned int opcode) +{ +#if MAINTAIN_FPCR + FPA11 *fpa11 = GET_FPA11(); + fpa11->fpcr &= ~MASK_ROUNDING_PRECISION; +#endif + switch (opcode & MASK_ROUNDING_PRECISION) + { + case ROUND_SINGLE: + floatx80_rounding_precision = 32; +#if MAINTAIN_FPCR + fpa11->fpcr |= ROUND_SINGLE; +#endif + break; + + case ROUND_DOUBLE: + floatx80_rounding_precision = 64; +#if MAINTAIN_FPCR + fpa11->fpcr |= ROUND_DOUBLE; +#endif + break; + + case ROUND_EXTENDED: + floatx80_rounding_precision = 80; +#if MAINTAIN_FPCR + fpa11->fpcr |= ROUND_EXTENDED; +#endif + break; + + default: floatx80_rounding_precision = 80; + } +} + +void FPA11_CheckInit(void) +{ + FPA11 *fpa11 = GET_FPA11(); + if (unlikely(fpa11->initflag == 0)) + { + resetFPA11(); + SetRoundingMode(ROUND_TO_NEAREST); + SetRoundingPrecision(ROUND_EXTENDED); + fpa11->initflag = 1; + } +} + +/* Emulate the instruction in the opcode. */ +unsigned int EmulateAll(unsigned int opcode) +{ + unsigned int nRc = 1, code; + + code = opcode & 0x00000f00; + if (code == 0x00000100 || code == 0x00000200) + { + /* For coprocessor 1 or 2 (FPA11) */ + code = opcode & 0x0e000000; + if (code == 0x0e000000) + { + if (opcode & 0x00000010) + { + /* Emulate conversion opcodes. */ + /* Emulate register transfer opcodes. */ + /* Emulate comparison opcodes. */ + nRc = EmulateCPRT(opcode); + } + else + { + /* Emulate monadic arithmetic opcodes. */ + /* Emulate dyadic arithmetic opcodes. */ + nRc = EmulateCPDO(opcode); + } + } + else if (code == 0x0c000000) + { + /* Emulate load/store opcodes. */ + /* Emulate load/store multiple opcodes. */ + nRc = EmulateCPDT(opcode); + } + else + { + /* Invalid instruction detected. Return FALSE. */ + nRc = 0; + } + } + + return(nRc); +} + +#if 0 +unsigned int EmulateAll1(unsigned int opcode) +{ + switch ((opcode >> 24) & 0xf) + { + case 0xc: + case 0xd: + if ((opcode >> 20) & 0x1) + { + switch ((opcode >> 8) & 0xf) + { + case 0x1: return PerformLDF(opcode); break; + case 0x2: return PerformLFM(opcode); break; + default: return 0; + } + } + else + { + switch ((opcode >> 8) & 0xf) + { + case 0x1: return PerformSTF(opcode); break; + case 0x2: return PerformSFM(opcode); break; + default: return 0; + } + } + break; + + case 0xe: + if (opcode & 0x10) + return EmulateCPDO(opcode); + else + return EmulateCPRT(opcode); + break; + + default: return 0; + } +} +#endif + diff -Nru a/arch/arm26/nwfpe/fpa11.h b/arch/arm26/nwfpe/fpa11.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/nwfpe/fpa11.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,87 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.com, 1998-1999 + + Direct questions, comments to Scott Bambrough <scottb@netwinder.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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __FPA11_H__ +#define __FPA11_H__ + +#define GET_FPA11() ((FPA11 *)(¤t_thread_info()->fpstate)) + +/* + * The processes registers are always at the very top of the 8K + * stack+task struct. Use the same method as 'current' uses to + * reach them. + */ +register unsigned int *user_registers asm("sl"); + +#define GET_USERREG() (user_registers) + +#include <linux/thread_info.h> + +/* includes */ +#include "fpsr.h" /* FP control and status register definitions */ +#include "softfloat.h" + +#define typeNone 0x00 +#define typeSingle 0x01 +#define typeDouble 0x02 +#define typeExtended 0x03 + +/* + * This must be no more and no less than 12 bytes. + */ +typedef union tagFPREG { + floatx80 fExtended; + float64 fDouble; + float32 fSingle; +} FPREG; + +/* + * FPA11 device model. + * + * This structure is exported to user space. Do not re-order. + * Only add new stuff to the end, and do not change the size of + * any element. Elements of this structure are used by user + * space, and must match struct user_fp in include/asm-arm/user.h. + * We include the byte offsets below for documentation purposes. + * + * The size of this structure and FPREG are checked by fpmodule.c + * on initialisation. If the rules have been broken, NWFPE will + * not initialise. + */ +typedef struct tagFPA11 { +/* 0 */ FPREG fpreg[8]; /* 8 floating point registers */ +/* 96 */ FPSR fpsr; /* floating point status register */ +/* 100 */ FPCR fpcr; /* floating point control register */ +/* 104 */ unsigned char fType[8]; /* type of floating point value held in + floating point registers. One of none + single, double or extended. */ +/* 112 */ int initflag; /* this is special. The kernel guarantees + to set it to 0 when a thread is launched, + so we can use it to detect whether this + instance of the emulator needs to be + initialised. */ +} FPA11; + +extern void resetFPA11(void); +extern void SetRoundingMode(const unsigned int); +extern void SetRoundingPrecision(const unsigned int); + +#endif diff -Nru a/arch/arm26/nwfpe/fpa11.inl b/arch/arm26/nwfpe/fpa11.inl --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/nwfpe/fpa11.inl Mon Jun 9 23:16:20 2003 @@ -0,0 +1,51 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998,1999 + + Direct questions, comments to Scott Bambrough <scottb@netwinder.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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "fpa11.h" + +/* Read and write floating point status register */ +extern __inline__ unsigned int readFPSR(void) +{ + FPA11 *fpa11 = GET_FPA11(); + return(fpa11->fpsr); +} + +extern __inline__ void writeFPSR(FPSR reg) +{ + FPA11 *fpa11 = GET_FPA11(); + /* the sysid byte in the status register is readonly */ + fpa11->fpsr = (fpa11->fpsr & MASK_SYSID) | (reg & ~MASK_SYSID); +} + +/* Read and write floating point control register */ +extern __inline__ FPCR readFPCR(void) +{ + FPA11 *fpa11 = GET_FPA11(); + /* clear SB, AB and DA bits before returning FPCR */ + return(fpa11->fpcr & ~MASK_RFC); +} + +extern __inline__ void writeFPCR(FPCR reg) +{ + FPA11 *fpa11 = GET_FPA11(); + fpa11->fpcr &= ~MASK_WFC; /* clear SB, AB and DA bits */ + fpa11->fpcr |= (reg & MASK_WFC); /* write SB, AB and DA bits */ +} diff -Nru a/arch/arm26/nwfpe/fpa11_cpdo.c b/arch/arm26/nwfpe/fpa11_cpdo.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/nwfpe/fpa11_cpdo.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,117 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998,1999 + + Direct questions, comments to Scott Bambrough <scottb@netwinder.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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "fpa11.h" +#include "fpopcode.h" + +unsigned int SingleCPDO(const unsigned int opcode); +unsigned int DoubleCPDO(const unsigned int opcode); +unsigned int ExtendedCPDO(const unsigned int opcode); + +unsigned int EmulateCPDO(const unsigned int opcode) +{ + FPA11 *fpa11 = GET_FPA11(); + unsigned int Fd, nType, nDest, nRc = 1; + + //printk("EmulateCPDO(0x%08x)\n",opcode); + + /* Get the destination size. If not valid let Linux perform + an invalid instruction trap. */ + nDest = getDestinationSize(opcode); + if (typeNone == nDest) return 0; + + SetRoundingMode(opcode); + + /* Compare the size of the operands in Fn and Fm. + Choose the largest size and perform operations in that size, + in order to make use of all the precision of the operands. + If Fm is a constant, we just grab a constant of a size + matching the size of the operand in Fn. */ + if (MONADIC_INSTRUCTION(opcode)) + nType = nDest; + else + nType = fpa11->fType[getFn(opcode)]; + + if (!CONSTANT_FM(opcode)) + { + register unsigned int Fm = getFm(opcode); + if (nType < fpa11->fType[Fm]) + { + nType = fpa11->fType[Fm]; + } + } + + switch (nType) + { + case typeSingle : nRc = SingleCPDO(opcode); break; + case typeDouble : nRc = DoubleCPDO(opcode); break; + case typeExtended : nRc = ExtendedCPDO(opcode); break; + default : nRc = 0; + } + + /* If the operation succeeded, check to see if the result in the + destination register is the correct size. If not force it + to be. */ + Fd = getFd(opcode); + nType = fpa11->fType[Fd]; + if ((0 != nRc) && (nDest != nType)) + { + switch (nDest) + { + case typeSingle: + { + if (typeDouble == nType) + fpa11->fpreg[Fd].fSingle = + float64_to_float32(fpa11->fpreg[Fd].fDouble); + else + fpa11->fpreg[Fd].fSingle = + floatx80_to_float32(fpa11->fpreg[Fd].fExtended); + } + break; + + case typeDouble: + { + if (typeSingle == nType) + fpa11->fpreg[Fd].fDouble = + float32_to_float64(fpa11->fpreg[Fd].fSingle); + else + fpa11->fpreg[Fd].fDouble = + floatx80_to_float64(fpa11->fpreg[Fd].fExtended); + } + break; + + case typeExtended: + { + if (typeSingle == nType) + fpa11->fpreg[Fd].fExtended = + float32_to_floatx80(fpa11->fpreg[Fd].fSingle); + else + fpa11->fpreg[Fd].fExtended = + float64_to_floatx80(fpa11->fpreg[Fd].fDouble); + } + break; + } + + fpa11->fType[Fd] = nDest; + } + + return nRc; +} diff -Nru a/arch/arm26/nwfpe/fpa11_cpdt.c b/arch/arm26/nwfpe/fpa11_cpdt.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/nwfpe/fpa11_cpdt.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,368 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.com, 1998-1999 + (c) Philip Blundell, 1998 + + Direct questions, comments to Scott Bambrough <scottb@netwinder.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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "fpa11.h" +#include "softfloat.h" +#include "fpopcode.h" +#include "fpmodule.h" +#include "fpmodule.inl" + +#include <asm/uaccess.h> + +static inline +void loadSingle(const unsigned int Fn,const unsigned int *pMem) +{ + FPA11 *fpa11 = GET_FPA11(); + fpa11->fType[Fn] = typeSingle; + get_user(fpa11->fpreg[Fn].fSingle, pMem); +} + +static inline +void loadDouble(const unsigned int Fn,const unsigned int *pMem) +{ + FPA11 *fpa11 = GET_FPA11(); + unsigned int *p; + p = (unsigned int*)&fpa11->fpreg[Fn].fDouble; + fpa11->fType[Fn] = typeDouble; + get_user(p[0], &pMem[1]); + get_user(p[1], &pMem[0]); /* sign & exponent */ +} + +static inline +void loadExtended(const unsigned int Fn,const unsigned int *pMem) +{ + FPA11 *fpa11 = GET_FPA11(); + unsigned int *p; + p = (unsigned int*)&fpa11->fpreg[Fn].fExtended; + fpa11->fType[Fn] = typeExtended; + get_user(p[0], &pMem[0]); /* sign & exponent */ + get_user(p[1], &pMem[2]); /* ls bits */ + get_user(p[2], &pMem[1]); /* ms bits */ +} + +static inline +void loadMultiple(const unsigned int Fn,const unsigned int *pMem) +{ + FPA11 *fpa11 = GET_FPA11(); + register unsigned int *p; + unsigned long x; + + p = (unsigned int*)&(fpa11->fpreg[Fn]); + get_user(x, &pMem[0]); + fpa11->fType[Fn] = (x >> 14) & 0x00000003; + + switch (fpa11->fType[Fn]) + { + case typeSingle: + case typeDouble: + { + get_user(p[0], &pMem[2]); /* Single */ + get_user(p[1], &pMem[1]); /* double msw */ + p[2] = 0; /* empty */ + } + break; + + case typeExtended: + { + get_user(p[1], &pMem[2]); + get_user(p[2], &pMem[1]); /* msw */ + p[0] = (x & 0x80003fff); + } + break; + } +} + +static inline +void storeSingle(const unsigned int Fn,unsigned int *pMem) +{ + FPA11 *fpa11 = GET_FPA11(); + union + { + float32 f; + unsigned int i[1]; + } val; + + switch (fpa11->fType[Fn]) + { + case typeDouble: + val.f = float64_to_float32(fpa11->fpreg[Fn].fDouble); + break; + + case typeExtended: + val.f = floatx80_to_float32(fpa11->fpreg[Fn].fExtended); + break; + + default: val.f = fpa11->fpreg[Fn].fSingle; + } + + put_user(val.i[0], pMem); +} + +static inline +void storeDouble(const unsigned int Fn,unsigned int *pMem) +{ + FPA11 *fpa11 = GET_FPA11(); + union + { + float64 f; + unsigned int i[2]; + } val; + + switch (fpa11->fType[Fn]) + { + case typeSingle: + val.f = float32_to_float64(fpa11->fpreg[Fn].fSingle); + break; + + case typeExtended: + val.f = floatx80_to_float64(fpa11->fpreg[Fn].fExtended); + break; + + default: val.f = fpa11->fpreg[Fn].fDouble; + } + + put_user(val.i[1], &pMem[0]); /* msw */ + put_user(val.i[0], &pMem[1]); /* lsw */ +} + +static inline +void storeExtended(const unsigned int Fn,unsigned int *pMem) +{ + FPA11 *fpa11 = GET_FPA11(); + union + { + floatx80 f; + unsigned int i[3]; + } val; + + switch (fpa11->fType[Fn]) + { + case typeSingle: + val.f = float32_to_floatx80(fpa11->fpreg[Fn].fSingle); + break; + + case typeDouble: + val.f = float64_to_floatx80(fpa11->fpreg[Fn].fDouble); + break; + + default: val.f = fpa11->fpreg[Fn].fExtended; + } + + put_user(val.i[0], &pMem[0]); /* sign & exp */ + put_user(val.i[1], &pMem[2]); + put_user(val.i[2], &pMem[1]); /* msw */ +} + +static inline +void storeMultiple(const unsigned int Fn,unsigned int *pMem) +{ + FPA11 *fpa11 = GET_FPA11(); + register unsigned int nType, *p; + + p = (unsigned int*)&(fpa11->fpreg[Fn]); + nType = fpa11->fType[Fn]; + + switch (nType) + { + case typeSingle: + case typeDouble: + { + put_user(p[0], &pMem[2]); /* single */ + put_user(p[1], &pMem[1]); /* double msw */ + put_user(nType << 14, &pMem[0]); + } + break; + + case typeExtended: + { + put_user(p[2], &pMem[1]); /* msw */ + put_user(p[1], &pMem[2]); + put_user((p[0] & 0x80003fff) | (nType << 14), &pMem[0]); + } + break; + } +} + +unsigned int PerformLDF(const unsigned int opcode) +{ + unsigned int *pBase, *pAddress, *pFinal, nRc = 1, + write_back = WRITE_BACK(opcode); + + //printk("PerformLDF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); + + pBase = (unsigned int*)readRegister(getRn(opcode)); + if (REG_PC == getRn(opcode)) + { + pBase += 2; + write_back = 0; + } + + pFinal = pBase; + if (BIT_UP_SET(opcode)) + pFinal += getOffset(opcode); + else + pFinal -= getOffset(opcode); + + if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; + + switch (opcode & MASK_TRANSFER_LENGTH) + { + case TRANSFER_SINGLE : loadSingle(getFd(opcode),pAddress); break; + case TRANSFER_DOUBLE : loadDouble(getFd(opcode),pAddress); break; + case TRANSFER_EXTENDED: loadExtended(getFd(opcode),pAddress); break; + default: nRc = 0; + } + + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); + return nRc; +} + +unsigned int PerformSTF(const unsigned int opcode) +{ + unsigned int *pBase, *pAddress, *pFinal, nRc = 1, + write_back = WRITE_BACK(opcode); + + //printk("PerformSTF(0x%08x), Fd = 0x%08x\n",opcode,getFd(opcode)); + SetRoundingMode(ROUND_TO_NEAREST); + + pBase = (unsigned int*)readRegister(getRn(opcode)); + if (REG_PC == getRn(opcode)) + { + pBase += 2; + write_back = 0; + } + + pFinal = pBase; + if (BIT_UP_SET(opcode)) + pFinal += getOffset(opcode); + else + pFinal -= getOffset(opcode); + + if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; + + switch (opcode & MASK_TRANSFER_LENGTH) + { + case TRANSFER_SINGLE : storeSingle(getFd(opcode),pAddress); break; + case TRANSFER_DOUBLE : storeDouble(getFd(opcode),pAddress); break; + case TRANSFER_EXTENDED: storeExtended(getFd(opcode),pAddress); break; + default: nRc = 0; + } + + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); + return nRc; +} + +unsigned int PerformLFM(const unsigned int opcode) +{ + unsigned int i, Fd, *pBase, *pAddress, *pFinal, + write_back = WRITE_BACK(opcode); + + pBase = (unsigned int*)readRegister(getRn(opcode)); + if (REG_PC == getRn(opcode)) + { + pBase += 2; + write_back = 0; + } + + pFinal = pBase; + if (BIT_UP_SET(opcode)) + pFinal += getOffset(opcode); + else + pFinal -= getOffset(opcode); + + if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; + + Fd = getFd(opcode); + for (i=getRegisterCount(opcode);i>0;i--) + { + loadMultiple(Fd,pAddress); + pAddress += 3; Fd++; + if (Fd == 8) Fd = 0; + } + + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); + return 1; +} + +unsigned int PerformSFM(const unsigned int opcode) +{ + unsigned int i, Fd, *pBase, *pAddress, *pFinal, + write_back = WRITE_BACK(opcode); + + pBase = (unsigned int*)readRegister(getRn(opcode)); + if (REG_PC == getRn(opcode)) + { + pBase += 2; + write_back = 0; + } + + pFinal = pBase; + if (BIT_UP_SET(opcode)) + pFinal += getOffset(opcode); + else + pFinal -= getOffset(opcode); + + if (PREINDEXED(opcode)) pAddress = pFinal; else pAddress = pBase; + + Fd = getFd(opcode); + for (i=getRegisterCount(opcode);i>0;i--) + { + storeMultiple(Fd,pAddress); + pAddress += 3; Fd++; + if (Fd == 8) Fd = 0; + } + + if (write_back) writeRegister(getRn(opcode),(unsigned int)pFinal); + return 1; +} + +#if 1 +unsigned int EmulateCPDT(const unsigned int opcode) +{ + unsigned int nRc = 0; + + //printk("EmulateCPDT(0x%08x)\n",opcode); + + if (LDF_OP(opcode)) + { + nRc = PerformLDF(opcode); + } + else if (LFM_OP(opcode)) + { + nRc = PerformLFM(opcode); + } + else if (STF_OP(opcode)) + { + nRc = PerformSTF(opcode); + } + else if (SFM_OP(opcode)) + { + nRc = PerformSFM(opcode); + } + else + { + nRc = 0; + } + + return nRc; +} +#endif diff -Nru a/arch/arm26/nwfpe/fpa11_cprt.c b/arch/arm26/nwfpe/fpa11_cprt.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/nwfpe/fpa11_cprt.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,289 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998,1999 + (c) Philip Blundell, 1999 + + Direct questions, comments to Scott Bambrough <scottb@netwinder.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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "fpa11.h" +#include "milieu.h" +#include "softfloat.h" +#include "fpopcode.h" +#include "fpa11.inl" +#include "fpmodule.h" +#include "fpmodule.inl" + +extern flag floatx80_is_nan(floatx80); +extern flag float64_is_nan( float64); +extern flag float32_is_nan( float32); + +void SetRoundingMode(const unsigned int opcode); + +unsigned int PerformFLT(const unsigned int opcode); +unsigned int PerformFIX(const unsigned int opcode); + +static unsigned int +PerformComparison(const unsigned int opcode); + +unsigned int EmulateCPRT(const unsigned int opcode) +{ + unsigned int nRc = 1; + + //printk("EmulateCPRT(0x%08x)\n",opcode); + + if (opcode & 0x800000) + { + /* This is some variant of a comparison (PerformComparison will + sort out which one). Since most of the other CPRT + instructions are oddball cases of some sort or other it makes + sense to pull this out into a fast path. */ + return PerformComparison(opcode); + } + + /* Hint to GCC that we'd like a jump table rather than a load of CMPs */ + switch ((opcode & 0x700000) >> 20) + { + case FLT_CODE >> 20: nRc = PerformFLT(opcode); break; + case FIX_CODE >> 20: nRc = PerformFIX(opcode); break; + + case WFS_CODE >> 20: writeFPSR(readRegister(getRd(opcode))); break; + case RFS_CODE >> 20: writeRegister(getRd(opcode),readFPSR()); break; + +#if 0 /* We currently have no use for the FPCR, so there's no point + in emulating it. */ + case WFC_CODE >> 20: writeFPCR(readRegister(getRd(opcode))); + case RFC_CODE >> 20: writeRegister(getRd(opcode),readFPCR()); break; +#endif + + default: nRc = 0; + } + + return nRc; +} + +unsigned int PerformFLT(const unsigned int opcode) +{ + FPA11 *fpa11 = GET_FPA11(); + + unsigned int nRc = 1; + SetRoundingMode(opcode); + + switch (opcode & MASK_ROUNDING_PRECISION) + { + case ROUND_SINGLE: + { + fpa11->fType[getFn(opcode)] = typeSingle; + fpa11->fpreg[getFn(opcode)].fSingle = + int32_to_float32(readRegister(getRd(opcode))); + } + break; + + case ROUND_DOUBLE: + { + fpa11->fType[getFn(opcode)] = typeDouble; + fpa11->fpreg[getFn(opcode)].fDouble = + int32_to_float64(readRegister(getRd(opcode))); + } + break; + + case ROUND_EXTENDED: + { + fpa11->fType[getFn(opcode)] = typeExtended; + fpa11->fpreg[getFn(opcode)].fExtended = + int32_to_floatx80(readRegister(getRd(opcode))); + } + break; + + default: nRc = 0; + } + + return nRc; +} + +unsigned int PerformFIX(const unsigned int opcode) +{ + FPA11 *fpa11 = GET_FPA11(); + unsigned int nRc = 1; + unsigned int Fn = getFm(opcode); + + SetRoundingMode(opcode); + + switch (fpa11->fType[Fn]) + { + case typeSingle: + { + writeRegister(getRd(opcode), + float32_to_int32(fpa11->fpreg[Fn].fSingle)); + } + break; + + case typeDouble: + { + writeRegister(getRd(opcode), + float64_to_int32(fpa11->fpreg[Fn].fDouble)); + } + break; + + case typeExtended: + { + writeRegister(getRd(opcode), + floatx80_to_int32(fpa11->fpreg[Fn].fExtended)); + } + break; + + default: nRc = 0; + } + + return nRc; +} + + +static unsigned int __inline__ +PerformComparisonOperation(floatx80 Fn, floatx80 Fm) +{ + unsigned int flags = 0; + + /* test for less than condition */ + if (floatx80_lt(Fn,Fm)) + { + flags |= CC_NEGATIVE; + } + + /* test for equal condition */ + if (floatx80_eq(Fn,Fm)) + { + flags |= CC_ZERO; + } + + /* test for greater than or equal condition */ + if (floatx80_lt(Fm,Fn)) + { + flags |= CC_CARRY; + } + + writeConditionCodes(flags); + return 1; +} + +/* This instruction sets the flags N, Z, C, V in the FPSR. */ + +static unsigned int PerformComparison(const unsigned int opcode) +{ + FPA11 *fpa11 = GET_FPA11(); + unsigned int Fn, Fm; + floatx80 rFn, rFm; + int e_flag = opcode & 0x400000; /* 1 if CxFE */ + int n_flag = opcode & 0x200000; /* 1 if CNxx */ + unsigned int flags = 0; + + //printk("PerformComparison(0x%08x)\n",opcode); + + Fn = getFn(opcode); + Fm = getFm(opcode); + + /* Check for unordered condition and convert all operands to 80-bit + format. + ?? Might be some mileage in avoiding this conversion if possible. + Eg, if both operands are 32-bit, detect this and do a 32-bit + comparison (cheaper than an 80-bit one). */ + switch (fpa11->fType[Fn]) + { + case typeSingle: + //printk("single.\n"); + if (float32_is_nan(fpa11->fpreg[Fn].fSingle)) + goto unordered; + rFn = float32_to_floatx80(fpa11->fpreg[Fn].fSingle); + break; + + case typeDouble: + //printk("double.\n"); + if (float64_is_nan(fpa11->fpreg[Fn].fDouble)) + goto unordered; + rFn = float64_to_floatx80(fpa11->fpreg[Fn].fDouble); + break; + + case typeExtended: + //printk("extended.\n"); + if (floatx80_is_nan(fpa11->fpreg[Fn].fExtended)) + goto unordered; + rFn = fpa11->fpreg[Fn].fExtended; + break; + + default: return 0; + } + + if (CONSTANT_FM(opcode)) + { + //printk("Fm is a constant: #%d.\n",Fm); + rFm = getExtendedConstant(Fm); + if (floatx80_is_nan(rFm)) + goto unordered; + } + else + { + //printk("Fm = r%d which contains a ",Fm); + switch (fpa11->fType[Fm]) + { + case typeSingle: + //printk("single.\n"); + if (float32_is_nan(fpa11->fpreg[Fm].fSingle)) + goto unordered; + rFm = float32_to_floatx80(fpa11->fpreg[Fm].fSingle); + break; + + case typeDouble: + //printk("double.\n"); + if (float64_is_nan(fpa11->fpreg[Fm].fDouble)) + goto unordered; + rFm = float64_to_floatx80(fpa11->fpreg[Fm].fDouble); + break; + + case typeExtended: + //printk("extended.\n"); + if (floatx80_is_nan(fpa11->fpreg[Fm].fExtended)) + goto unordered; + rFm = fpa11->fpreg[Fm].fExtended; + break; + + default: return 0; + } + } + + if (n_flag) + { + rFm.high ^= 0x8000; + } + + return PerformComparisonOperation(rFn,rFm); + + unordered: + /* ?? The FPA data sheet is pretty vague about this, in particular + about whether the non-E comparisons can ever raise exceptions. + This implementation is based on a combination of what it says in + the data sheet, observation of how the Acorn emulator actually + behaves (and how programs expect it to) and guesswork. */ + flags |= CC_OVERFLOW; + flags &= ~(CC_ZERO | CC_NEGATIVE); + + if (BIT_AC & readFPSR()) flags |= CC_CARRY; + + if (e_flag) float_raise(float_flag_invalid); + + writeConditionCodes(flags); + return 1; +} diff -Nru a/arch/arm26/nwfpe/fpmodule.c b/arch/arm26/nwfpe/fpmodule.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/nwfpe/fpmodule.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,182 @@ + +/* + NetWinder Floating Point Emulator + (c) Rebel.com, 1998-1999 + (c) Philip Blundell, 1998-1999 + + Direct questions, comments to Scott Bambrough <scottb@netwinder.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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "fpa11.h" + +#include <linux/module.h> +#include <linux/version.h> +#include <linux/config.h> + +/* XXX */ +#include <linux/errno.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/signal.h> +#include <linux/sched.h> +#include <linux/init.h> +/* XXX */ + +#include "softfloat.h" +#include "fpopcode.h" +#include "fpmodule.h" +#include "fpa11.inl" + +/* kernel symbols required for signal handling */ +typedef struct task_struct* PTASK; + +#ifdef MODULE +void fp_send_sig(unsigned long sig, PTASK p, int priv); +#if LINUX_VERSION_CODE > 0x20115 +MODULE_AUTHOR("Scott Bambrough <scottb@rebel.com>"); +MODULE_DESCRIPTION("NWFPE floating point emulator"); +#endif + +#else +#define fp_send_sig send_sig +#define kern_fp_enter fp_enter + +extern char fpe_type[]; +#endif + +/* kernel function prototypes required */ +void fp_setup(void); + +/* external declarations for saved kernel symbols */ +extern void (*kern_fp_enter)(void); + +/* Original value of fp_enter from kernel before patched by fpe_init. */ +static void (*orig_fp_enter)(void); + +/* forward declarations */ +extern void nwfpe_enter(void); + +#ifdef MODULE +/* + * Return 0 if we can be unloaded. This can only happen if + * kern_fp_enter is still pointing at nwfpe_enter + */ +static int fpe_unload(void) +{ + return (kern_fp_enter == nwfpe_enter) ? 0 : 1; +} +#endif + +static int __init fpe_init(void) +{ + if (sizeof(FPA11) > sizeof(union fp_state)) { + printk(KERN_ERR "nwfpe: bad structure size\n"); + return -EINVAL; + } + + if (sizeof(FPREG) != 12) { + printk(KERN_ERR "nwfpe: bad register size\n"); + return -EINVAL; + } + +#ifdef MODULE + if (!mod_member_present(&__this_module, can_unload)) + return -EINVAL; + __this_module.can_unload = fpe_unload; +#else + if (fpe_type[0] && strcmp(fpe_type, "nwfpe")) + return 0; +#endif + + /* Display title, version and copyright information. */ + printk(KERN_WARNING "NetWinder Floating Point Emulator V0.95 " + "(c) 1998-1999 Rebel.com\n"); + + /* Save pointer to the old FP handler and then patch ourselves in */ + orig_fp_enter = kern_fp_enter; + kern_fp_enter = nwfpe_enter; + + return 0; +} + +static void __exit fpe_exit(void) +{ + /* Restore the values we saved earlier. */ + kern_fp_enter = orig_fp_enter; +} + +/* +ScottB: November 4, 1998 + +Moved this function out of softfloat-specialize into fpmodule.c. +This effectively isolates all the changes required for integrating with the +Linux kernel into fpmodule.c. Porting to NetBSD should only require modifying +fpmodule.c to integrate with the NetBSD kernel (I hope!). + +[1/1/99: Not quite true any more unfortunately. There is Linux-specific +code to access data in user space in some other source files at the +moment (grep for get_user / put_user calls). --philb] + +float_exception_flags is a global variable in SoftFloat. + +This function is called by the SoftFloat routines to raise a floating +point exception. We check the trap enable byte in the FPSR, and raise +a SIGFPE exception if necessary. If not the relevant bits in the +cumulative exceptions flag byte are set and we return. +*/ + +void float_raise(signed char flags) +{ + register unsigned int fpsr, cumulativeTraps; + +#ifdef CONFIG_DEBUG_USER + printk(KERN_DEBUG "NWFPE: %s[%d] takes exception %08x at %p from %08x\n", + current->comm, current->pid, flags, + __builtin_return_address(0), GET_USERREG()[15]); +#endif + + /* Keep SoftFloat exception flags up to date. */ + float_exception_flags |= flags; + + /* Read fpsr and initialize the cumulativeTraps. */ + fpsr = readFPSR(); + cumulativeTraps = 0; + + /* For each type of exception, the cumulative trap exception bit is only + set if the corresponding trap enable bit is not set. */ + if ((!(fpsr & BIT_IXE)) && (flags & BIT_IXC)) + cumulativeTraps |= BIT_IXC; + if ((!(fpsr & BIT_UFE)) && (flags & BIT_UFC)) + cumulativeTraps |= BIT_UFC; + if ((!(fpsr & BIT_OFE)) && (flags & BIT_OFC)) + cumulativeTraps |= BIT_OFC; + if ((!(fpsr & BIT_DZE)) && (flags & BIT_DZC)) + cumulativeTraps |= BIT_DZC; + if ((!(fpsr & BIT_IOE)) && (flags & BIT_IOC)) + cumulativeTraps |= BIT_IOC; + + /* Set the cumulative exceptions flags. */ + if (cumulativeTraps) + writeFPSR(fpsr | cumulativeTraps); + + /* Raise an exception if necessary. */ + if (fpsr & (flags << 16)) + fp_send_sig(SIGFPE, current, 1); +} + +module_init(fpe_init); +module_exit(fpe_exit); diff -Nru a/arch/arm26/nwfpe/fpmodule.h b/arch/arm26/nwfpe/fpmodule.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/nwfpe/fpmodule.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,47 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.com, 1998-1999 + + Direct questions, comments to Scott Bambrough <scottb@netwinder.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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __FPMODULE_H__ +#define __FPMODULE_H__ + +#include <linux/config.h> + +#define REG_ORIG_R0 16 +#define REG_CPSR 15 +#define REG_PC 15 +#define REG_LR 14 +#define REG_SP 13 +#define REG_IP 12 +#define REG_FP 11 +#define REG_R10 10 +#define REG_R9 9 +#define REG_R9 9 +#define REG_R8 8 +#define REG_R7 7 +#define REG_R6 6 +#define REG_R5 5 +#define REG_R4 4 +#define REG_R3 3 +#define REG_R2 2 +#define REG_R1 1 +#define REG_R0 0 + +#endif diff -Nru a/arch/arm26/nwfpe/fpmodule.inl b/arch/arm26/nwfpe/fpmodule.inl --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/nwfpe/fpmodule.inl Mon Jun 9 23:16:20 2003 @@ -0,0 +1,84 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998,1999 + + Direct questions, comments to Scott Bambrough <scottb@netwinder.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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +extern __inline__ +unsigned int readRegister(const unsigned int nReg) +{ + /* Note: The CPU thinks it has dealt with the current instruction. As + a result the program counter has been advanced to the next + instruction, and points 4 bytes beyond the actual instruction + that caused the invalid instruction trap to occur. We adjust + for this in this routine. LDF/STF instructions with Rn = PC + depend on the PC being correct, as they use PC+8 in their + address calculations. */ + unsigned int *userRegisters = GET_USERREG(); + unsigned int val = userRegisters[nReg]; + if (REG_PC == nReg) val -= 4; + return val; +} + +extern __inline__ +void writeRegister(const unsigned int nReg, const unsigned int val) +{ + unsigned int *userRegisters = GET_USERREG(); + userRegisters[nReg] = val; +} + +extern __inline__ +unsigned int readCPSR(void) +{ + return(readRegister(REG_CPSR)); +} + +extern __inline__ +void writeCPSR(const unsigned int val) +{ + writeRegister(REG_CPSR,val); +} + +extern __inline__ +unsigned int readConditionCodes(void) +{ +#ifdef __FPEM_TEST__ + return(0); +#else + return(readCPSR() & CC_MASK); +#endif +} + +extern __inline__ +void writeConditionCodes(const unsigned int val) +{ + unsigned int *userRegisters = GET_USERREG(); + unsigned int rval; + /* + * Operate directly on userRegisters since + * the CPSR may be the PC register itself. + */ + rval = userRegisters[REG_CPSR] & ~CC_MASK; + userRegisters[REG_CPSR] = rval | (val & CC_MASK); +} + +extern __inline__ +unsigned int readMemoryInt(unsigned int *pMem) +{ + return *pMem; +} diff -Nru a/arch/arm26/nwfpe/fpopcode.c b/arch/arm26/nwfpe/fpopcode.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/nwfpe/fpopcode.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,148 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998,1999 + + Direct questions, comments to Scott Bambrough <scottb@netwinder.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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "fpa11.h" +#include "softfloat.h" +#include "fpopcode.h" +#include "fpsr.h" +#include "fpmodule.h" +#include "fpmodule.inl" + +const floatx80 floatx80Constant[] = { + { 0x0000, 0x0000000000000000ULL}, /* extended 0.0 */ + { 0x3fff, 0x8000000000000000ULL}, /* extended 1.0 */ + { 0x4000, 0x8000000000000000ULL}, /* extended 2.0 */ + { 0x4000, 0xc000000000000000ULL}, /* extended 3.0 */ + { 0x4001, 0x8000000000000000ULL}, /* extended 4.0 */ + { 0x4001, 0xa000000000000000ULL}, /* extended 5.0 */ + { 0x3ffe, 0x8000000000000000ULL}, /* extended 0.5 */ + { 0x4002, 0xa000000000000000ULL} /* extended 10.0 */ +}; + +const float64 float64Constant[] = { + 0x0000000000000000ULL, /* double 0.0 */ + 0x3ff0000000000000ULL, /* double 1.0 */ + 0x4000000000000000ULL, /* double 2.0 */ + 0x4008000000000000ULL, /* double 3.0 */ + 0x4010000000000000ULL, /* double 4.0 */ + 0x4014000000000000ULL, /* double 5.0 */ + 0x3fe0000000000000ULL, /* double 0.5 */ + 0x4024000000000000ULL /* double 10.0 */ +}; + +const float32 float32Constant[] = { + 0x00000000, /* single 0.0 */ + 0x3f800000, /* single 1.0 */ + 0x40000000, /* single 2.0 */ + 0x40400000, /* single 3.0 */ + 0x40800000, /* single 4.0 */ + 0x40a00000, /* single 5.0 */ + 0x3f000000, /* single 0.5 */ + 0x41200000 /* single 10.0 */ +}; + +unsigned int getTransferLength(const unsigned int opcode) +{ + unsigned int nRc; + + switch (opcode & MASK_TRANSFER_LENGTH) + { + case 0x00000000: nRc = 1; break; /* single precision */ + case 0x00008000: nRc = 2; break; /* double precision */ + case 0x00400000: nRc = 3; break; /* extended precision */ + default: nRc = 0; + } + + return(nRc); +} + +unsigned int getRegisterCount(const unsigned int opcode) +{ + unsigned int nRc; + + switch (opcode & MASK_REGISTER_COUNT) + { + case 0x00000000: nRc = 4; break; + case 0x00008000: nRc = 1; break; + case 0x00400000: nRc = 2; break; + case 0x00408000: nRc = 3; break; + default: nRc = 0; + } + + return(nRc); +} + +unsigned int getRoundingPrecision(const unsigned int opcode) +{ + unsigned int nRc; + + switch (opcode & MASK_ROUNDING_PRECISION) + { + case 0x00000000: nRc = 1; break; + case 0x00000080: nRc = 2; break; + case 0x00080000: nRc = 3; break; + default: nRc = 0; + } + + return(nRc); +} + +unsigned int getDestinationSize(const unsigned int opcode) +{ + unsigned int nRc; + + switch (opcode & MASK_DESTINATION_SIZE) + { + case 0x00000000: nRc = typeSingle; break; + case 0x00000080: nRc = typeDouble; break; + case 0x00080000: nRc = typeExtended; break; + default: nRc = typeNone; + } + + return(nRc); +} + +/* condition code lookup table + index into the table is test code: EQ, NE, ... LT, GT, AL, NV + bit position in short is condition code: NZCV */ +static const unsigned short aCC[16] = { + 0xF0F0, // EQ == Z set + 0x0F0F, // NE + 0xCCCC, // CS == C set + 0x3333, // CC + 0xFF00, // MI == N set + 0x00FF, // PL + 0xAAAA, // VS == V set + 0x5555, // VC + 0x0C0C, // HI == C set && Z clear + 0xF3F3, // LS == C clear || Z set + 0xAA55, // GE == (N==V) + 0x55AA, // LT == (N!=V) + 0x0A05, // GT == (!Z && (N==V)) + 0xF5FA, // LE == (Z || (N!=V)) + 0xFFFF, // AL always + 0 // NV +}; + +unsigned int checkCondition(const unsigned int opcode, const unsigned int ccodes) +{ + return (aCC[opcode>>28] >> (ccodes>>28)) & 1; +} diff -Nru a/arch/arm26/nwfpe/fpopcode.h b/arch/arm26/nwfpe/fpopcode.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/nwfpe/fpopcode.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,390 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998,1999 + + Direct questions, comments to Scott Bambrough <scottb@netwinder.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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __FPOPCODE_H__ +#define __FPOPCODE_H__ + +/* +ARM Floating Point Instruction Classes +| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +|c o n d|1 1 0 P|U|u|W|L| Rn |v| Fd |0|0|0|1| o f f s e t | CPDT +|c o n d|1 1 0 P|U|w|W|L| Rn |x| Fd |0|0|0|1| o f f s e t | CPDT +| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | +|c o n d|1 1 1 0|a|b|c|d|e| Fn |j| Fd |0|0|0|1|f|g|h|0|i| Fm | CPDO +|c o n d|1 1 1 0|a|b|c|L|e| Fn | Rd |0|0|0|1|f|g|h|1|i| Fm | CPRT +|c o n d|1 1 1 0|a|b|c|1|e| Fn |1|1|1|1|0|0|0|1|f|g|h|1|i| Fm | comparisons +| | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | + +CPDT data transfer instructions + LDF, STF, LFM, SFM + +CPDO dyadic arithmetic instructions + ADF, MUF, SUF, RSF, DVF, RDF, + POW, RPW, RMF, FML, FDV, FRD, POL + +CPDO monadic arithmetic instructions + MVF, MNF, ABS, RND, SQT, LOG, LGN, EXP, + SIN, COS, TAN, ASN, ACS, ATN, URD, NRM + +CPRT joint arithmetic/data transfer instructions + FIX (arithmetic followed by load/store) + FLT (load/store followed by arithmetic) + CMF, CNF CMFE, CNFE (comparisons) + WFS, RFS (write/read floating point status register) + WFC, RFC (write/read floating point control register) + +cond condition codes +P pre/post index bit: 0 = postindex, 1 = preindex +U up/down bit: 0 = stack grows down, 1 = stack grows up +W write back bit: 1 = update base register (Rn) +L load/store bit: 0 = store, 1 = load +Rn base register +Rd destination/source register +Fd floating point destination register +Fn floating point source register +Fm floating point source register or floating point constant + +uv transfer length (TABLE 1) +wx register count (TABLE 2) +abcd arithmetic opcode (TABLES 3 & 4) +ef destination size (rounding precision) (TABLE 5) +gh rounding mode (TABLE 6) +j dyadic/monadic bit: 0 = dyadic, 1 = monadic +i constant bit: 1 = constant (TABLE 6) +*/ + +/* +TABLE 1 ++-------------------------+---+---+---------+---------+ +| Precision | u | v | FPSR.EP | length | ++-------------------------+---+---+---------+---------+ +| Single | 0 ü 0 | x | 1 words | +| Double | 1 ü 1 | x | 2 words | +| Extended | 1 ü 1 | x | 3 words | +| Packed decimal | 1 ü 1 | 0 | 3 words | +| Expanded packed decimal | 1 ü 1 | 1 | 4 words | ++-------------------------+---+---+---------+---------+ +Note: x = don't care +*/ + +/* +TABLE 2 ++---+---+---------------------------------+ +| w | x | Number of registers to transfer | ++---+---+---------------------------------+ +| 0 ü 1 | 1 | +| 1 ü 0 | 2 | +| 1 ü 1 | 3 | +| 0 ü 0 | 4 | ++---+---+---------------------------------+ +*/ + +/* +TABLE 3: Dyadic Floating Point Opcodes ++---+---+---+---+----------+-----------------------+-----------------------+ +| a | b | c | d | Mnemonic | Description | Operation | ++---+---+---+---+----------+-----------------------+-----------------------+ +| 0 | 0 | 0 | 0 | ADF | Add | Fd := Fn + Fm | +| 0 | 0 | 0 | 1 | MUF | Multiply | Fd := Fn * Fm | +| 0 | 0 | 1 | 0 | SUF | Subtract | Fd := Fn - Fm | +| 0 | 0 | 1 | 1 | RSF | Reverse subtract | Fd := Fm - Fn | +| 0 | 1 | 0 | 0 | DVF | Divide | Fd := Fn / Fm | +| 0 | 1 | 0 | 1 | RDF | Reverse divide | Fd := Fm / Fn | +| 0 | 1 | 1 | 0 | POW | Power | Fd := Fn ^ Fm | +| 0 | 1 | 1 | 1 | RPW | Reverse power | Fd := Fm ^ Fn | +| 1 | 0 | 0 | 0 | RMF | Remainder | Fd := IEEE rem(Fn/Fm) | +| 1 | 0 | 0 | 1 | FML | Fast Multiply | Fd := Fn * Fm | +| 1 | 0 | 1 | 0 | FDV | Fast Divide | Fd := Fn / Fm | +| 1 | 0 | 1 | 1 | FRD | Fast reverse divide | Fd := Fm / Fn | +| 1 | 1 | 0 | 0 | POL | Polar angle (ArcTan2) | Fd := arctan2(Fn,Fm) | +| 1 | 1 | 0 | 1 | | undefined instruction | trap | +| 1 | 1 | 1 | 0 | | undefined instruction | trap | +| 1 | 1 | 1 | 1 | | undefined instruction | trap | ++---+---+---+---+----------+-----------------------+-----------------------+ +Note: POW, RPW, POL are deprecated, and are available for backwards + compatibility only. +*/ + +/* +TABLE 4: Monadic Floating Point Opcodes ++---+---+---+---+----------+-----------------------+-----------------------+ +| a | b | c | d | Mnemonic | Description | Operation | ++---+---+---+---+----------+-----------------------+-----------------------+ +| 0 | 0 | 0 | 0 | MVF | Move | Fd := Fm | +| 0 | 0 | 0 | 1 | MNF | Move negated | Fd := - Fm | +| 0 | 0 | 1 | 0 | ABS | Absolute value | Fd := abs(Fm) | +| 0 | 0 | 1 | 1 | RND | Round to integer | Fd := int(Fm) | +| 0 | 1 | 0 | 0 | SQT | Square root | Fd := sqrt(Fm) | +| 0 | 1 | 0 | 1 | LOG | Log base 10 | Fd := log10(Fm) | +| 0 | 1 | 1 | 0 | LGN | Log base e | Fd := ln(Fm) | +| 0 | 1 | 1 | 1 | EXP | Exponent | Fd := e ^ Fm | +| 1 | 0 | 0 | 0 | SIN | Sine | Fd := sin(Fm) | +| 1 | 0 | 0 | 1 | COS | Cosine | Fd := cos(Fm) | +| 1 | 0 | 1 | 0 | TAN | Tangent | Fd := tan(Fm) | +| 1 | 0 | 1 | 1 | ASN | Arc Sine | Fd := arcsin(Fm) | +| 1 | 1 | 0 | 0 | ACS | Arc Cosine | Fd := arccos(Fm) | +| 1 | 1 | 0 | 1 | ATN | Arc Tangent | Fd := arctan(Fm) | +| 1 | 1 | 1 | 0 | URD | Unnormalized round | Fd := int(Fm) | +| 1 | 1 | 1 | 1 | NRM | Normalize | Fd := norm(Fm) | ++---+---+---+---+----------+-----------------------+-----------------------+ +Note: LOG, LGN, EXP, SIN, COS, TAN, ASN, ACS, ATN are deprecated, and are + available for backwards compatibility only. +*/ + +/* +TABLE 5 ++-------------------------+---+---+ +| Rounding Precision | e | f | ++-------------------------+---+---+ +| IEEE Single precision | 0 ü 0 | +| IEEE Double precision | 0 ü 1 | +| IEEE Extended precision | 1 ü 0 | +| undefined (trap) | 1 ü 1 | ++-------------------------+---+---+ +*/ + +/* +TABLE 5 ++---------------------------------+---+---+ +| Rounding Mode | g | h | ++---------------------------------+---+---+ +| Round to nearest (default) | 0 ü 0 | +| Round toward plus infinity | 0 ü 1 | +| Round toward negative infinity | 1 ü 0 | +| Round toward zero | 1 ü 1 | ++---------------------------------+---+---+ +*/ + +/* +=== +=== Definitions for load and store instructions +=== +*/ + +/* bit masks */ +#define BIT_PREINDEX 0x01000000 +#define BIT_UP 0x00800000 +#define BIT_WRITE_BACK 0x00200000 +#define BIT_LOAD 0x00100000 + +/* masks for load/store */ +#define MASK_CPDT 0x0c000000 /* data processing opcode */ +#define MASK_OFFSET 0x000000ff +#define MASK_TRANSFER_LENGTH 0x00408000 +#define MASK_REGISTER_COUNT MASK_TRANSFER_LENGTH +#define MASK_COPROCESSOR 0x00000f00 + +/* Tests for transfer length */ +#define TRANSFER_SINGLE 0x00000000 +#define TRANSFER_DOUBLE 0x00008000 +#define TRANSFER_EXTENDED 0x00400000 +#define TRANSFER_PACKED MASK_TRANSFER_LENGTH + +/* Get the coprocessor number from the opcode. */ +#define getCoprocessorNumber(opcode) ((opcode & MASK_COPROCESSOR) >> 8) + +/* Get the offset from the opcode. */ +#define getOffset(opcode) (opcode & MASK_OFFSET) + +/* Tests for specific data transfer load/store opcodes. */ +#define TEST_OPCODE(opcode,mask) (((opcode) & (mask)) == (mask)) + +#define LOAD_OP(opcode) TEST_OPCODE((opcode),MASK_CPDT | BIT_LOAD) +#define STORE_OP(opcode) ((opcode & (MASK_CPDT | BIT_LOAD)) == MASK_CPDT) + +#define LDF_OP(opcode) (LOAD_OP(opcode) && (getCoprocessorNumber(opcode) == 1)) +#define LFM_OP(opcode) (LOAD_OP(opcode) && (getCoprocessorNumber(opcode) == 2)) +#define STF_OP(opcode) (STORE_OP(opcode) && (getCoprocessorNumber(opcode) == 1)) +#define SFM_OP(opcode) (STORE_OP(opcode) && (getCoprocessorNumber(opcode) == 2)) + +#define PREINDEXED(opcode) ((opcode & BIT_PREINDEX) != 0) +#define POSTINDEXED(opcode) ((opcode & BIT_PREINDEX) == 0) +#define BIT_UP_SET(opcode) ((opcode & BIT_UP) != 0) +#define BIT_UP_CLEAR(opcode) ((opcode & BIT_DOWN) == 0) +#define WRITE_BACK(opcode) ((opcode & BIT_WRITE_BACK) != 0) +#define LOAD(opcode) ((opcode & BIT_LOAD) != 0) +#define STORE(opcode) ((opcode & BIT_LOAD) == 0) + +/* +=== +=== Definitions for arithmetic instructions +=== +*/ +/* bit masks */ +#define BIT_MONADIC 0x00008000 +#define BIT_CONSTANT 0x00000008 + +#define CONSTANT_FM(opcode) ((opcode & BIT_CONSTANT) != 0) +#define MONADIC_INSTRUCTION(opcode) ((opcode & BIT_MONADIC) != 0) + +/* instruction identification masks */ +#define MASK_CPDO 0x0e000000 /* arithmetic opcode */ +#define MASK_ARITHMETIC_OPCODE 0x00f08000 +#define MASK_DESTINATION_SIZE 0x00080080 + +/* dyadic arithmetic opcodes. */ +#define ADF_CODE 0x00000000 +#define MUF_CODE 0x00100000 +#define SUF_CODE 0x00200000 +#define RSF_CODE 0x00300000 +#define DVF_CODE 0x00400000 +#define RDF_CODE 0x00500000 +#define POW_CODE 0x00600000 +#define RPW_CODE 0x00700000 +#define RMF_CODE 0x00800000 +#define FML_CODE 0x00900000 +#define FDV_CODE 0x00a00000 +#define FRD_CODE 0x00b00000 +#define POL_CODE 0x00c00000 +/* 0x00d00000 is an invalid dyadic arithmetic opcode */ +/* 0x00e00000 is an invalid dyadic arithmetic opcode */ +/* 0x00f00000 is an invalid dyadic arithmetic opcode */ + +/* monadic arithmetic opcodes. */ +#define MVF_CODE 0x00008000 +#define MNF_CODE 0x00108000 +#define ABS_CODE 0x00208000 +#define RND_CODE 0x00308000 +#define SQT_CODE 0x00408000 +#define LOG_CODE 0x00508000 +#define LGN_CODE 0x00608000 +#define EXP_CODE 0x00708000 +#define SIN_CODE 0x00808000 +#define COS_CODE 0x00908000 +#define TAN_CODE 0x00a08000 +#define ASN_CODE 0x00b08000 +#define ACS_CODE 0x00c08000 +#define ATN_CODE 0x00d08000 +#define URD_CODE 0x00e08000 +#define NRM_CODE 0x00f08000 + +/* +=== +=== Definitions for register transfer and comparison instructions +=== +*/ + +#define MASK_CPRT 0x0e000010 /* register transfer opcode */ +#define MASK_CPRT_CODE 0x00f00000 +#define FLT_CODE 0x00000000 +#define FIX_CODE 0x00100000 +#define WFS_CODE 0x00200000 +#define RFS_CODE 0x00300000 +#define WFC_CODE 0x00400000 +#define RFC_CODE 0x00500000 +#define CMF_CODE 0x00900000 +#define CNF_CODE 0x00b00000 +#define CMFE_CODE 0x00d00000 +#define CNFE_CODE 0x00f00000 + +/* +=== +=== Common definitions +=== +*/ + +/* register masks */ +#define MASK_Rd 0x0000f000 +#define MASK_Rn 0x000f0000 +#define MASK_Fd 0x00007000 +#define MASK_Fm 0x00000007 +#define MASK_Fn 0x00070000 + +/* condition code masks */ +#define CC_MASK 0xf0000000 +#define CC_NEGATIVE 0x80000000 +#define CC_ZERO 0x40000000 +#define CC_CARRY 0x20000000 +#define CC_OVERFLOW 0x10000000 +#define CC_EQ 0x00000000 +#define CC_NE 0x10000000 +#define CC_CS 0x20000000 +#define CC_HS CC_CS +#define CC_CC 0x30000000 +#define CC_LO CC_CC +#define CC_MI 0x40000000 +#define CC_PL 0x50000000 +#define CC_VS 0x60000000 +#define CC_VC 0x70000000 +#define CC_HI 0x80000000 +#define CC_LS 0x90000000 +#define CC_GE 0xa0000000 +#define CC_LT 0xb0000000 +#define CC_GT 0xc0000000 +#define CC_LE 0xd0000000 +#define CC_AL 0xe0000000 +#define CC_NV 0xf0000000 + +/* rounding masks/values */ +#define MASK_ROUNDING_MODE 0x00000060 +#define ROUND_TO_NEAREST 0x00000000 +#define ROUND_TO_PLUS_INFINITY 0x00000020 +#define ROUND_TO_MINUS_INFINITY 0x00000040 +#define ROUND_TO_ZERO 0x00000060 + +#define MASK_ROUNDING_PRECISION 0x00080080 +#define ROUND_SINGLE 0x00000000 +#define ROUND_DOUBLE 0x00000080 +#define ROUND_EXTENDED 0x00080000 + +/* Get the condition code from the opcode. */ +#define getCondition(opcode) (opcode >> 28) + +/* Get the source register from the opcode. */ +#define getRn(opcode) ((opcode & MASK_Rn) >> 16) + +/* Get the destination floating point register from the opcode. */ +#define getFd(opcode) ((opcode & MASK_Fd) >> 12) + +/* Get the first source floating point register from the opcode. */ +#define getFn(opcode) ((opcode & MASK_Fn) >> 16) + +/* Get the second source floating point register from the opcode. */ +#define getFm(opcode) (opcode & MASK_Fm) + +/* Get the destination register from the opcode. */ +#define getRd(opcode) ((opcode & MASK_Rd) >> 12) + +/* Get the rounding mode from the opcode. */ +#define getRoundingMode(opcode) ((opcode & MASK_ROUNDING_MODE) >> 5) + +static inline const floatx80 getExtendedConstant(const unsigned int nIndex) +{ + extern const floatx80 floatx80Constant[]; + return floatx80Constant[nIndex]; +} + +static inline const float64 getDoubleConstant(const unsigned int nIndex) +{ + extern const float64 float64Constant[]; + return float64Constant[nIndex]; +} + +static inline const float32 getSingleConstant(const unsigned int nIndex) +{ + extern const float32 float32Constant[]; + return float32Constant[nIndex]; +} + +extern unsigned int getRegisterCount(const unsigned int opcode); +extern unsigned int getDestinationSize(const unsigned int opcode); + +#endif diff -Nru a/arch/arm26/nwfpe/fpsr.h b/arch/arm26/nwfpe/fpsr.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/nwfpe/fpsr.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,108 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.com, 1998-1999 + + Direct questions, comments to Scott Bambrough <scottb@netwinder.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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __FPSR_H__ +#define __FPSR_H__ + +/* +The FPSR is a 32 bit register consisting of 4 parts, each exactly +one byte. + + SYSTEM ID + EXCEPTION TRAP ENABLE BYTE + SYSTEM CONTROL BYTE + CUMULATIVE EXCEPTION FLAGS BYTE + +The FPCR is a 32 bit register consisting of bit flags. +*/ + +/* SYSTEM ID +------------ +Note: the system id byte is read only */ + +typedef unsigned int FPSR; /* type for floating point status register */ +typedef unsigned int FPCR; /* type for floating point control register */ + +#define MASK_SYSID 0xff000000 +#define BIT_HARDWARE 0x80000000 +#define FP_EMULATOR 0x01000000 /* System ID for emulator */ +#define FP_ACCELERATOR 0x81000000 /* System ID for FPA11 */ + +/* EXCEPTION TRAP ENABLE BYTE +----------------------------- */ + +#define MASK_TRAP_ENABLE 0x00ff0000 +#define MASK_TRAP_ENABLE_STRICT 0x001f0000 +#define BIT_IXE 0x00100000 /* inexact exception enable */ +#define BIT_UFE 0x00080000 /* underflow exception enable */ +#define BIT_OFE 0x00040000 /* overflow exception enable */ +#define BIT_DZE 0x00020000 /* divide by zero exception enable */ +#define BIT_IOE 0x00010000 /* invalid operation exception enable */ + +/* SYSTEM CONTROL BYTE +---------------------- */ + +#define MASK_SYSTEM_CONTROL 0x0000ff00 +#define MASK_TRAP_STRICT 0x00001f00 + +#define BIT_AC 0x00001000 /* use alternative C-flag definition + for compares */ +#define BIT_EP 0x00000800 /* use expanded packed decimal format */ +#define BIT_SO 0x00000400 /* select synchronous operation of FPA */ +#define BIT_NE 0x00000200 /* NaN exception bit */ +#define BIT_ND 0x00000100 /* no denormalized numbers bit */ + +/* CUMULATIVE EXCEPTION FLAGS BYTE +---------------------------------- */ + +#define MASK_EXCEPTION_FLAGS 0x000000ff +#define MASK_EXCEPTION_FLAGS_STRICT 0x0000001f + +#define BIT_IXC 0x00000010 /* inexact exception flag */ +#define BIT_UFC 0x00000008 /* underflow exception flag */ +#define BIT_OFC 0x00000004 /* overfloat exception flag */ +#define BIT_DZC 0x00000002 /* divide by zero exception flag */ +#define BIT_IOC 0x00000001 /* invalid operation exception flag */ + +/* Floating Point Control Register +----------------------------------*/ + +#define BIT_RU 0x80000000 /* rounded up bit */ +#define BIT_IE 0x10000000 /* inexact bit */ +#define BIT_MO 0x08000000 /* mantissa overflow bit */ +#define BIT_EO 0x04000000 /* exponent overflow bit */ +#define BIT_SB 0x00000800 /* store bounce */ +#define BIT_AB 0x00000400 /* arithmetic bounce */ +#define BIT_RE 0x00000200 /* rounding exception */ +#define BIT_DA 0x00000100 /* disable FPA */ + +#define MASK_OP 0x00f08010 /* AU operation code */ +#define MASK_PR 0x00080080 /* AU precision */ +#define MASK_S1 0x00070000 /* AU source register 1 */ +#define MASK_S2 0x00000007 /* AU source register 2 */ +#define MASK_DS 0x00007000 /* AU destination register */ +#define MASK_RM 0x00000060 /* AU rounding mode */ +#define MASK_ALU 0x9cfff2ff /* only ALU can write these bits */ +#define MASK_RESET 0x00000d00 /* bits set on reset, all others cleared */ +#define MASK_WFC MASK_RESET +#define MASK_RFC ~MASK_RESET + +#endif diff -Nru a/arch/arm26/nwfpe/milieu.h b/arch/arm26/nwfpe/milieu.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/nwfpe/milieu.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,48 @@ + +/* +=============================================================================== + +This C header file is part of the SoftFloat IEC/IEEE Floating-point +Arithmetic Package, Release 2. + +Written by John R. Hauser. This work was made possible in part by the +International Computer Science Institute, located at Suite 600, 1947 Center +Street, Berkeley, California 94704. Funding was partially provided by the +National Science Foundation under grant MIP-9311980. The original version +of this code was written as part of a project to build a fixed-point vector +processor in collaboration with the University of California at Berkeley, +overseen by Profs. Nelson Morgan and John Wawrzynek. More information +is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ +arithmetic/softfloat.html'. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort +has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT +TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO +PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY +AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. + +Derivative works are acceptable, even for commercial purposes, so long as +(1) they include prominent notice that the work is derivative, and (2) they +include prominent notice akin to these three paragraphs for those parts of +this code that are retained. + +=============================================================================== +*/ + +/* +------------------------------------------------------------------------------- +Include common integer types and flags. +------------------------------------------------------------------------------- +*/ +#include "ARM-gcc.h" + +/* +------------------------------------------------------------------------------- +Symbolic Boolean literals. +------------------------------------------------------------------------------- +*/ +enum { + FALSE = 0, + TRUE = 1 +}; + diff -Nru a/arch/arm26/nwfpe/single_cpdo.c b/arch/arm26/nwfpe/single_cpdo.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/nwfpe/single_cpdo.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,255 @@ +/* + NetWinder Floating Point Emulator + (c) Rebel.COM, 1998,1999 + + Direct questions, comments to Scott Bambrough <scottb@netwinder.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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "fpa11.h" +#include "softfloat.h" +#include "fpopcode.h" + +float32 float32_exp(float32 Fm); +float32 float32_ln(float32 Fm); +float32 float32_sin(float32 rFm); +float32 float32_cos(float32 rFm); +float32 float32_arcsin(float32 rFm); +float32 float32_arctan(float32 rFm); +float32 float32_log(float32 rFm); +float32 float32_tan(float32 rFm); +float32 float32_arccos(float32 rFm); +float32 float32_pow(float32 rFn,float32 rFm); +float32 float32_pol(float32 rFn,float32 rFm); + +unsigned int SingleCPDO(const unsigned int opcode) +{ + FPA11 *fpa11 = GET_FPA11(); + float32 rFm, rFn = 0; //FIXME - should be zero? + unsigned int Fd, Fm, Fn, nRc = 1; + + Fm = getFm(opcode); + if (CONSTANT_FM(opcode)) + { + rFm = getSingleConstant(Fm); + } + else + { + switch (fpa11->fType[Fm]) + { + case typeSingle: + rFm = fpa11->fpreg[Fm].fSingle; + break; + + default: return 0; + } + } + + if (!MONADIC_INSTRUCTION(opcode)) + { + Fn = getFn(opcode); + switch (fpa11->fType[Fn]) + { + case typeSingle: + rFn = fpa11->fpreg[Fn].fSingle; + break; + + default: return 0; + } + } + + Fd = getFd(opcode); + switch (opcode & MASK_ARITHMETIC_OPCODE) + { + /* dyadic opcodes */ + case ADF_CODE: + fpa11->fpreg[Fd].fSingle = float32_add(rFn,rFm); + break; + + case MUF_CODE: + case FML_CODE: + fpa11->fpreg[Fd].fSingle = float32_mul(rFn,rFm); + break; + + case SUF_CODE: + fpa11->fpreg[Fd].fSingle = float32_sub(rFn,rFm); + break; + + case RSF_CODE: + fpa11->fpreg[Fd].fSingle = float32_sub(rFm,rFn); + break; + + case DVF_CODE: + case FDV_CODE: + fpa11->fpreg[Fd].fSingle = float32_div(rFn,rFm); + break; + + case RDF_CODE: + case FRD_CODE: + fpa11->fpreg[Fd].fSingle = float32_div(rFm,rFn); + break; + +#if 0 + case POW_CODE: + fpa11->fpreg[Fd].fSingle = float32_pow(rFn,rFm); + break; + + case RPW_CODE: + fpa11->fpreg[Fd].fSingle = float32_pow(rFm,rFn); + break; +#endif + + case RMF_CODE: + fpa11->fpreg[Fd].fSingle = float32_rem(rFn,rFm); + break; + +#if 0 + case POL_CODE: + fpa11->fpreg[Fd].fSingle = float32_pol(rFn,rFm); + break; +#endif + + /* monadic opcodes */ + case MVF_CODE: + fpa11->fpreg[Fd].fSingle = rFm; + break; + + case MNF_CODE: + rFm ^= 0x80000000; + fpa11->fpreg[Fd].fSingle = rFm; + break; + + case ABS_CODE: + rFm &= 0x7fffffff; + fpa11->fpreg[Fd].fSingle = rFm; + break; + + case RND_CODE: + case URD_CODE: + fpa11->fpreg[Fd].fSingle = float32_round_to_int(rFm); + break; + + case SQT_CODE: + fpa11->fpreg[Fd].fSingle = float32_sqrt(rFm); + break; + +#if 0 + case LOG_CODE: + fpa11->fpreg[Fd].fSingle = float32_log(rFm); + break; + + case LGN_CODE: + fpa11->fpreg[Fd].fSingle = float32_ln(rFm); + break; + + case EXP_CODE: + fpa11->fpreg[Fd].fSingle = float32_exp(rFm); + break; + + case SIN_CODE: + fpa11->fpreg[Fd].fSingle = float32_sin(rFm); + break; + + case COS_CODE: + fpa11->fpreg[Fd].fSingle = float32_cos(rFm); + break; + + case TAN_CODE: + fpa11->fpreg[Fd].fSingle = float32_tan(rFm); + break; + + case ASN_CODE: + fpa11->fpreg[Fd].fSingle = float32_arcsin(rFm); + break; + + case ACS_CODE: + fpa11->fpreg[Fd].fSingle = float32_arccos(rFm); + break; + + case ATN_CODE: + fpa11->fpreg[Fd].fSingle = float32_arctan(rFm); + break; +#endif + + case NRM_CODE: + break; + + default: + { + nRc = 0; + } + } + + if (0 != nRc) fpa11->fType[Fd] = typeSingle; + return nRc; +} + +#if 0 +float32 float32_exp(float32 Fm) +{ +//series +} + +float32 float32_ln(float32 Fm) +{ +//series +} + +float32 float32_sin(float32 rFm) +{ +//series +} + +float32 float32_cos(float32 rFm) +{ +//series +} + +float32 float32_arcsin(float32 rFm) +{ +//series +} + +float32 float32_arctan(float32 rFm) +{ + //series +} + +float32 float32_arccos(float32 rFm) +{ + //return float32_sub(halfPi,float32_arcsin(rFm)); +} + +float32 float32_log(float32 rFm) +{ + return float32_div(float32_ln(rFm),getSingleConstant(7)); +} + +float32 float32_tan(float32 rFm) +{ + return float32_div(float32_sin(rFm),float32_cos(rFm)); +} + +float32 float32_pow(float32 rFn,float32 rFm) +{ + return float32_exp(float32_mul(rFm,float32_ln(rFn))); +} + +float32 float32_pol(float32 rFn,float32 rFm) +{ + return float32_arctan(float32_div(rFn,rFm)); +} +#endif diff -Nru a/arch/arm26/nwfpe/softfloat-macros b/arch/arm26/nwfpe/softfloat-macros --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/nwfpe/softfloat-macros Mon Jun 9 23:16:20 2003 @@ -0,0 +1,740 @@ + +/* +=============================================================================== + +This C source fragment is part of the SoftFloat IEC/IEEE Floating-point +Arithmetic Package, Release 2. + +Written by John R. Hauser. This work was made possible in part by the +International Computer Science Institute, located at Suite 600, 1947 Center +Street, Berkeley, California 94704. Funding was partially provided by the +National Science Foundation under grant MIP-9311980. The original version +of this code was written as part of a project to build a fixed-point vector +processor in collaboration with the University of California at Berkeley, +overseen by Profs. Nelson Morgan and John Wawrzynek. More information +is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ +arithmetic/softfloat.html'. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort +has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT +TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO +PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY +AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. + +Derivative works are acceptable, even for commercial purposes, so long as +(1) they include prominent notice that the work is derivative, and (2) they +include prominent notice akin to these three paragraphs for those parts of +this code that are retained. + +=============================================================================== +*/ + +/* +------------------------------------------------------------------------------- +Shifts `a' right by the number of bits given in `count'. If any nonzero +bits are shifted off, they are ``jammed'' into the least significant bit of +the result by setting the least significant bit to 1. The value of `count' +can be arbitrarily large; in particular, if `count' is greater than 32, the +result will be either 0 or 1, depending on whether `a' is zero or nonzero. +The result is stored in the location pointed to by `zPtr'. +------------------------------------------------------------------------------- +*/ +INLINE void shift32RightJamming( bits32 a, int16 count, bits32 *zPtr ) +{ + bits32 z; + if ( count == 0 ) { + z = a; + } + else if ( count < 32 ) { + z = ( a>>count ) | ( ( a<<( ( - count ) & 31 ) ) != 0 ); + } + else { + z = ( a != 0 ); + } + *zPtr = z; +} + +/* +------------------------------------------------------------------------------- +Shifts `a' right by the number of bits given in `count'. If any nonzero +bits are shifted off, they are ``jammed'' into the least significant bit of +the result by setting the least significant bit to 1. The value of `count' +can be arbitrarily large; in particular, if `count' is greater than 64, the +result will be either 0 or 1, depending on whether `a' is zero or nonzero. +The result is stored in the location pointed to by `zPtr'. +------------------------------------------------------------------------------- +*/ +INLINE void shift64RightJamming( bits64 a, int16 count, bits64 *zPtr ) +{ + bits64 z; + + __asm__("@shift64RightJamming -- start"); + if ( count == 0 ) { + z = a; + } + else if ( count < 64 ) { + z = ( a>>count ) | ( ( a<<( ( - count ) & 63 ) ) != 0 ); + } + else { + z = ( a != 0 ); + } + __asm__("@shift64RightJamming -- end"); + *zPtr = z; +} + +/* +------------------------------------------------------------------------------- +Shifts the 128-bit value formed by concatenating `a0' and `a1' right by 64 +_plus_ the number of bits given in `count'. The shifted result is at most +64 nonzero bits; this is stored at the location pointed to by `z0Ptr'. The +bits shifted off form a second 64-bit result as follows: The _last_ bit +shifted off is the most-significant bit of the extra result, and the other +63 bits of the extra result are all zero if and only if _all_but_the_last_ +bits shifted off were all zero. This extra result is stored in the location +pointed to by `z1Ptr'. The value of `count' can be arbitrarily large. + (This routine makes more sense if `a0' and `a1' are considered to form a +fixed-point value with binary point between `a0' and `a1'. This fixed-point +value is shifted right by the number of bits given in `count', and the +integer part of the result is returned at the location pointed to by +`z0Ptr'. The fractional part of the result may be slightly corrupted as +described above, and is returned at the location pointed to by `z1Ptr'.) +------------------------------------------------------------------------------- +*/ +INLINE void + shift64ExtraRightJamming( + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits64 z0, z1; + int8 negCount = ( - count ) & 63; + + if ( count == 0 ) { + z1 = a1; + z0 = a0; + } + else if ( count < 64 ) { + z1 = ( a0<<negCount ) | ( a1 != 0 ); + z0 = a0>>count; + } + else { + if ( count == 64 ) { + z1 = a0 | ( a1 != 0 ); + } + else { + z1 = ( ( a0 | a1 ) != 0 ); + } + z0 = 0; + } + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the +number of bits given in `count'. Any bits shifted off are lost. The value +of `count' can be arbitrarily large; in particular, if `count' is greater +than 128, the result will be 0. The result is broken into two 64-bit pieces +which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + shift128Right( + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits64 z0, z1; + int8 negCount = ( - count ) & 63; + + if ( count == 0 ) { + z1 = a1; + z0 = a0; + } + else if ( count < 64 ) { + z1 = ( a0<<negCount ) | ( a1>>count ); + z0 = a0>>count; + } + else { + z1 = ( count < 64 ) ? ( a0>>( count & 63 ) ) : 0; + z0 = 0; + } + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Shifts the 128-bit value formed by concatenating `a0' and `a1' right by the +number of bits given in `count'. If any nonzero bits are shifted off, they +are ``jammed'' into the least significant bit of the result by setting the +least significant bit to 1. The value of `count' can be arbitrarily large; +in particular, if `count' is greater than 128, the result will be either 0 +or 1, depending on whether the concatenation of `a0' and `a1' is zero or +nonzero. The result is broken into two 64-bit pieces which are stored at +the locations pointed to by `z0Ptr' and `z1Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + shift128RightJamming( + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits64 z0, z1; + int8 negCount = ( - count ) & 63; + + if ( count == 0 ) { + z1 = a1; + z0 = a0; + } + else if ( count < 64 ) { + z1 = ( a0<<negCount ) | ( a1>>count ) | ( ( a1<<negCount ) != 0 ); + z0 = a0>>count; + } + else { + if ( count == 64 ) { + z1 = a0 | ( a1 != 0 ); + } + else if ( count < 128 ) { + z1 = ( a0>>( count & 63 ) ) | ( ( ( a0<<negCount ) | a1 ) != 0 ); + } + else { + z1 = ( ( a0 | a1 ) != 0 ); + } + z0 = 0; + } + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' right +by 64 _plus_ the number of bits given in `count'. The shifted result is +at most 128 nonzero bits; these are broken into two 64-bit pieces which are +stored at the locations pointed to by `z0Ptr' and `z1Ptr'. The bits shifted +off form a third 64-bit result as follows: The _last_ bit shifted off is +the most-significant bit of the extra result, and the other 63 bits of the +extra result are all zero if and only if _all_but_the_last_ bits shifted off +were all zero. This extra result is stored in the location pointed to by +`z2Ptr'. The value of `count' can be arbitrarily large. + (This routine makes more sense if `a0', `a1', and `a2' are considered +to form a fixed-point value with binary point between `a1' and `a2'. This +fixed-point value is shifted right by the number of bits given in `count', +and the integer part of the result is returned at the locations pointed to +by `z0Ptr' and `z1Ptr'. The fractional part of the result may be slightly +corrupted as described above, and is returned at the location pointed to by +`z2Ptr'.) +------------------------------------------------------------------------------- +*/ +INLINE void + shift128ExtraRightJamming( + bits64 a0, + bits64 a1, + bits64 a2, + int16 count, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr + ) +{ + bits64 z0, z1, z2; + int8 negCount = ( - count ) & 63; + + if ( count == 0 ) { + z2 = a2; + z1 = a1; + z0 = a0; + } + else { + if ( count < 64 ) { + z2 = a1<<negCount; + z1 = ( a0<<negCount ) | ( a1>>count ); + z0 = a0>>count; + } + else { + if ( count == 64 ) { + z2 = a1; + z1 = a0; + } + else { + a2 |= a1; + if ( count < 128 ) { + z2 = a0<<negCount; + z1 = a0>>( count & 63 ); + } + else { + z2 = ( count == 128 ) ? a0 : ( a0 != 0 ); + z1 = 0; + } + } + z0 = 0; + } + z2 |= ( a2 != 0 ); + } + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Shifts the 128-bit value formed by concatenating `a0' and `a1' left by the +number of bits given in `count'. Any bits shifted off are lost. The value +of `count' must be less than 64. The result is broken into two 64-bit +pieces which are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + shortShift128Left( + bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + + *z1Ptr = a1<<count; + *z0Ptr = + ( count == 0 ) ? a0 : ( a0<<count ) | ( a1>>( ( - count ) & 63 ) ); + +} + +/* +------------------------------------------------------------------------------- +Shifts the 192-bit value formed by concatenating `a0', `a1', and `a2' left +by the number of bits given in `count'. Any bits shifted off are lost. +The value of `count' must be less than 64. The result is broken into three +64-bit pieces which are stored at the locations pointed to by `z0Ptr', +`z1Ptr', and `z2Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + shortShift192Left( + bits64 a0, + bits64 a1, + bits64 a2, + int16 count, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr + ) +{ + bits64 z0, z1, z2; + int8 negCount; + + z2 = a2<<count; + z1 = a1<<count; + z0 = a0<<count; + if ( 0 < count ) { + negCount = ( ( - count ) & 63 ); + z1 |= a2>>negCount; + z0 |= a1>>negCount; + } + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Adds the 128-bit value formed by concatenating `a0' and `a1' to the 128-bit +value formed by concatenating `b0' and `b1'. Addition is modulo 2^128, so +any carry out is lost. The result is broken into two 64-bit pieces which +are stored at the locations pointed to by `z0Ptr' and `z1Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + add128( + bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits64 z1; + + z1 = a1 + b1; + *z1Ptr = z1; + *z0Ptr = a0 + b0 + ( z1 < a1 ); + +} + +/* +------------------------------------------------------------------------------- +Adds the 192-bit value formed by concatenating `a0', `a1', and `a2' to the +192-bit value formed by concatenating `b0', `b1', and `b2'. Addition is +modulo 2^192, so any carry out is lost. The result is broken into three +64-bit pieces which are stored at the locations pointed to by `z0Ptr', +`z1Ptr', and `z2Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + add192( + bits64 a0, + bits64 a1, + bits64 a2, + bits64 b0, + bits64 b1, + bits64 b2, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr + ) +{ + bits64 z0, z1, z2; + int8 carry0, carry1; + + z2 = a2 + b2; + carry1 = ( z2 < a2 ); + z1 = a1 + b1; + carry0 = ( z1 < a1 ); + z0 = a0 + b0; + z1 += carry1; + z0 += ( z1 < carry1 ); + z0 += carry0; + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Subtracts the 128-bit value formed by concatenating `b0' and `b1' from the +128-bit value formed by concatenating `a0' and `a1'. Subtraction is modulo +2^128, so any borrow out (carry out) is lost. The result is broken into two +64-bit pieces which are stored at the locations pointed to by `z0Ptr' and +`z1Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + sub128( + bits64 a0, bits64 a1, bits64 b0, bits64 b1, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + + *z1Ptr = a1 - b1; + *z0Ptr = a0 - b0 - ( a1 < b1 ); + +} + +/* +------------------------------------------------------------------------------- +Subtracts the 192-bit value formed by concatenating `b0', `b1', and `b2' +from the 192-bit value formed by concatenating `a0', `a1', and `a2'. +Subtraction is modulo 2^192, so any borrow out (carry out) is lost. The +result is broken into three 64-bit pieces which are stored at the locations +pointed to by `z0Ptr', `z1Ptr', and `z2Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + sub192( + bits64 a0, + bits64 a1, + bits64 a2, + bits64 b0, + bits64 b1, + bits64 b2, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr + ) +{ + bits64 z0, z1, z2; + int8 borrow0, borrow1; + + z2 = a2 - b2; + borrow1 = ( a2 < b2 ); + z1 = a1 - b1; + borrow0 = ( a1 < b1 ); + z0 = a0 - b0; + z0 -= ( z1 < borrow1 ); + z1 -= borrow1; + z0 -= borrow0; + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Multiplies `a' by `b' to obtain a 128-bit product. The product is broken +into two 64-bit pieces which are stored at the locations pointed to by +`z0Ptr' and `z1Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void mul64To128( bits64 a, bits64 b, bits64 *z0Ptr, bits64 *z1Ptr ) +{ + bits32 aHigh, aLow, bHigh, bLow; + bits64 z0, zMiddleA, zMiddleB, z1; + + aLow = a; + aHigh = a>>32; + bLow = b; + bHigh = b>>32; + z1 = ( (bits64) aLow ) * bLow; + zMiddleA = ( (bits64) aLow ) * bHigh; + zMiddleB = ( (bits64) aHigh ) * bLow; + z0 = ( (bits64) aHigh ) * bHigh; + zMiddleA += zMiddleB; + z0 += ( ( (bits64) ( zMiddleA < zMiddleB ) )<<32 ) + ( zMiddleA>>32 ); + zMiddleA <<= 32; + z1 += zMiddleA; + z0 += ( z1 < zMiddleA ); + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Multiplies the 128-bit value formed by concatenating `a0' and `a1' by `b' to +obtain a 192-bit product. The product is broken into three 64-bit pieces +which are stored at the locations pointed to by `z0Ptr', `z1Ptr', and +`z2Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + mul128By64To192( + bits64 a0, + bits64 a1, + bits64 b, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr + ) +{ + bits64 z0, z1, z2, more1; + + mul64To128( a1, b, &z1, &z2 ); + mul64To128( a0, b, &z0, &more1 ); + add128( z0, more1, 0, z1, &z0, &z1 ); + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Multiplies the 128-bit value formed by concatenating `a0' and `a1' to the +128-bit value formed by concatenating `b0' and `b1' to obtain a 256-bit +product. The product is broken into four 64-bit pieces which are stored at +the locations pointed to by `z0Ptr', `z1Ptr', `z2Ptr', and `z3Ptr'. +------------------------------------------------------------------------------- +*/ +INLINE void + mul128To256( + bits64 a0, + bits64 a1, + bits64 b0, + bits64 b1, + bits64 *z0Ptr, + bits64 *z1Ptr, + bits64 *z2Ptr, + bits64 *z3Ptr + ) +{ + bits64 z0, z1, z2, z3; + bits64 more1, more2; + + mul64To128( a1, b1, &z2, &z3 ); + mul64To128( a1, b0, &z1, &more2 ); + add128( z1, more2, 0, z2, &z1, &z2 ); + mul64To128( a0, b0, &z0, &more1 ); + add128( z0, more1, 0, z1, &z0, &z1 ); + mul64To128( a0, b1, &more1, &more2 ); + add128( more1, more2, 0, z2, &more1, &z2 ); + add128( z0, z1, 0, more1, &z0, &z1 ); + *z3Ptr = z3; + *z2Ptr = z2; + *z1Ptr = z1; + *z0Ptr = z0; + +} + +/* +------------------------------------------------------------------------------- +Returns an approximation to the 64-bit integer quotient obtained by dividing +`b' into the 128-bit value formed by concatenating `a0' and `a1'. The +divisor `b' must be at least 2^63. If q is the exact quotient truncated +toward zero, the approximation returned lies between q and q + 2 inclusive. +If the exact quotient q is larger than 64 bits, the maximum positive 64-bit +unsigned integer is returned. +------------------------------------------------------------------------------- +*/ +static bits64 estimateDiv128To64( bits64 a0, bits64 a1, bits64 b ) +{ + bits64 b0, b1; + bits64 rem0, rem1, term0, term1; + bits64 z; + if ( b <= a0 ) return LIT64( 0xFFFFFFFFFFFFFFFF ); + b0 = b>>32; + z = ( b0<<32 <= a0 ) ? LIT64( 0xFFFFFFFF00000000 ) : ( a0 / b0 )<<32; + mul64To128( b, z, &term0, &term1 ); + sub128( a0, a1, term0, term1, &rem0, &rem1 ); + while ( ( (sbits64) rem0 ) < 0 ) { + z -= LIT64( 0x100000000 ); + b1 = b<<32; + add128( rem0, rem1, b0, b1, &rem0, &rem1 ); + } + rem0 = ( rem0<<32 ) | ( rem1>>32 ); + z |= ( b0<<32 <= rem0 ) ? 0xFFFFFFFF : rem0 / b0; + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns an approximation to the square root of the 32-bit significand given +by `a'. Considered as an integer, `a' must be at least 2^31. If bit 0 of +`aExp' (the least significant bit) is 1, the integer returned approximates +2^31*sqrt(`a'/2^31), where `a' is considered an integer. If bit 0 of `aExp' +is 0, the integer returned approximates 2^31*sqrt(`a'/2^30). In either +case, the approximation returned lies strictly within +/-2 of the exact +value. +------------------------------------------------------------------------------- +*/ +static bits32 estimateSqrt32( int16 aExp, bits32 a ) +{ + static const bits16 sqrtOddAdjustments[] = { + 0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0, + 0x039C, 0x0468, 0x0545, 0x0631, 0x072B, 0x0832, 0x0946, 0x0A67 + }; + static const bits16 sqrtEvenAdjustments[] = { + 0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429, 0x0356, 0x029E, + 0x0200, 0x0179, 0x0109, 0x00AF, 0x0068, 0x0034, 0x0012, 0x0002 + }; + int8 index; + bits32 z; + + index = ( a>>27 ) & 15; + if ( aExp & 1 ) { + z = 0x4000 + ( a>>17 ) - sqrtOddAdjustments[ index ]; + z = ( ( a / z )<<14 ) + ( z<<15 ); + a >>= 1; + } + else { + z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ index ]; + z = a / z + z; + z = ( 0x20000 <= z ) ? 0xFFFF8000 : ( z<<15 ); + if ( z <= a ) return (bits32) ( ( (sbits32) a )>>1 ); + } + return ( (bits32) ( ( ( (bits64) a )<<31 ) / z ) ) + ( z>>1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the number of leading 0 bits before the most-significant 1 bit +of `a'. If `a' is zero, 32 is returned. +------------------------------------------------------------------------------- +*/ +static int8 countLeadingZeros32( bits32 a ) +{ + static const int8 countLeadingZerosHigh[] = { + 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 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, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + int8 shiftCount; + + shiftCount = 0; + if ( a < 0x10000 ) { + shiftCount += 16; + a <<= 16; + } + if ( a < 0x1000000 ) { + shiftCount += 8; + a <<= 8; + } + shiftCount += countLeadingZerosHigh[ a>>24 ]; + return shiftCount; + +} + +/* +------------------------------------------------------------------------------- +Returns the number of leading 0 bits before the most-significant 1 bit +of `a'. If `a' is zero, 64 is returned. +------------------------------------------------------------------------------- +*/ +static int8 countLeadingZeros64( bits64 a ) +{ + int8 shiftCount; + + shiftCount = 0; + if ( a < ( (bits64) 1 )<<32 ) { + shiftCount += 32; + } + else { + a >>= 32; + } + shiftCount += countLeadingZeros32( a ); + return shiftCount; + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' +is equal to the 128-bit value formed by concatenating `b0' and `b1'. +Otherwise, returns 0. +------------------------------------------------------------------------------- +*/ +INLINE flag eq128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) +{ + + return ( a0 == b0 ) && ( a1 == b1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less +than or equal to the 128-bit value formed by concatenating `b0' and `b1'. +Otherwise, returns 0. +------------------------------------------------------------------------------- +*/ +INLINE flag le128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) +{ + + return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 <= b1 ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is less +than the 128-bit value formed by concatenating `b0' and `b1'. Otherwise, +returns 0. +------------------------------------------------------------------------------- +*/ +INLINE flag lt128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) +{ + + return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 < b1 ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the 128-bit value formed by concatenating `a0' and `a1' is +not equal to the 128-bit value formed by concatenating `b0' and `b1'. +Otherwise, returns 0. +------------------------------------------------------------------------------- +*/ +INLINE flag ne128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) +{ + + return ( a0 != b0 ) || ( a1 != b1 ); + +} + diff -Nru a/arch/arm26/nwfpe/softfloat-specialize b/arch/arm26/nwfpe/softfloat-specialize --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/nwfpe/softfloat-specialize Mon Jun 9 23:16:20 2003 @@ -0,0 +1,366 @@ + +/* +=============================================================================== + +This C source fragment is part of the SoftFloat IEC/IEEE Floating-point +Arithmetic Package, Release 2. + +Written by John R. Hauser. This work was made possible in part by the +International Computer Science Institute, located at Suite 600, 1947 Center +Street, Berkeley, California 94704. Funding was partially provided by the +National Science Foundation under grant MIP-9311980. The original version +of this code was written as part of a project to build a fixed-point vector +processor in collaboration with the University of California at Berkeley, +overseen by Profs. Nelson Morgan and John Wawrzynek. More information +is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ +arithmetic/softfloat.html'. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort +has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT +TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO +PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY +AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. + +Derivative works are acceptable, even for commercial purposes, so long as +(1) they include prominent notice that the work is derivative, and (2) they +include prominent notice akin to these three paragraphs for those parts of +this code that are retained. + +=============================================================================== +*/ + +/* +------------------------------------------------------------------------------- +Underflow tininess-detection mode, statically initialized to default value. +(The declaration in `softfloat.h' must match the `int8' type here.) +------------------------------------------------------------------------------- +*/ +int8 float_detect_tininess = float_tininess_after_rounding; + +/* +------------------------------------------------------------------------------- +Raises the exceptions specified by `flags'. Floating-point traps can be +defined here if desired. It is currently not possible for such a trap to +substitute a result value. If traps are not implemented, this routine +should be simply `float_exception_flags |= flags;'. + +ScottB: November 4, 1998 +Moved this function out of softfloat-specialize into fpmodule.c. +This effectively isolates all the changes required for integrating with the +Linux kernel into fpmodule.c. Porting to NetBSD should only require modifying +fpmodule.c to integrate with the NetBSD kernel (I hope!). +------------------------------------------------------------------------------- +void float_raise( int8 flags ) +{ + float_exception_flags |= flags; +} +*/ + +/* +------------------------------------------------------------------------------- +Internal canonical NaN format. +------------------------------------------------------------------------------- +*/ +typedef struct { + flag sign; + bits64 high, low; +} commonNaNT; + +/* +------------------------------------------------------------------------------- +The pattern for a default generated single-precision NaN. +------------------------------------------------------------------------------- +*/ +#define float32_default_nan 0xFFFFFFFF + +/* +------------------------------------------------------------------------------- +Returns 1 if the single-precision floating-point value `a' is a NaN; +otherwise returns 0. +------------------------------------------------------------------------------- +*/ +flag float32_is_nan( float32 a ) +{ + + return ( 0xFF000000 < (bits32) ( a<<1 ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the single-precision floating-point value `a' is a signaling +NaN; otherwise returns 0. +------------------------------------------------------------------------------- +*/ +flag float32_is_signaling_nan( float32 a ) +{ + + return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the single-precision floating-point NaN +`a' to the canonical NaN format. If `a' is a signaling NaN, the invalid +exception is raised. +------------------------------------------------------------------------------- +*/ +static commonNaNT float32ToCommonNaN( float32 a ) +{ + commonNaNT z; + + if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid ); + z.sign = a>>31; + z.low = 0; + z.high = ( (bits64) a )<<41; + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the canonical NaN `a' to the single- +precision floating-point format. +------------------------------------------------------------------------------- +*/ +static float32 commonNaNToFloat32( commonNaNT a ) +{ + + return ( ( (bits32) a.sign )<<31 ) | 0x7FC00000 | ( a.high>>41 ); + +} + +/* +------------------------------------------------------------------------------- +Takes two single-precision floating-point values `a' and `b', one of which +is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a +signaling NaN, the invalid exception is raised. +------------------------------------------------------------------------------- +*/ +static float32 propagateFloat32NaN( float32 a, float32 b ) +{ + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + + aIsNaN = float32_is_nan( a ); + aIsSignalingNaN = float32_is_signaling_nan( a ); + bIsNaN = float32_is_nan( b ); + bIsSignalingNaN = float32_is_signaling_nan( b ); + a |= 0x00400000; + b |= 0x00400000; + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid ); + if ( aIsNaN ) { + return ( aIsSignalingNaN & bIsNaN ) ? b : a; + } + else { + return b; + } + +} + +/* +------------------------------------------------------------------------------- +The pattern for a default generated double-precision NaN. +------------------------------------------------------------------------------- +*/ +#define float64_default_nan LIT64( 0xFFFFFFFFFFFFFFFF ) + +/* +------------------------------------------------------------------------------- +Returns 1 if the double-precision floating-point value `a' is a NaN; +otherwise returns 0. +------------------------------------------------------------------------------- +*/ +flag float64_is_nan( float64 a ) +{ + + return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the double-precision floating-point value `a' is a signaling +NaN; otherwise returns 0. +------------------------------------------------------------------------------- +*/ +flag float64_is_signaling_nan( float64 a ) +{ + + return + ( ( ( a>>51 ) & 0xFFF ) == 0xFFE ) + && ( a & LIT64( 0x0007FFFFFFFFFFFF ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the double-precision floating-point NaN +`a' to the canonical NaN format. If `a' is a signaling NaN, the invalid +exception is raised. +------------------------------------------------------------------------------- +*/ +static commonNaNT float64ToCommonNaN( float64 a ) +{ + commonNaNT z; + + if ( float64_is_signaling_nan( a ) ) float_raise( float_flag_invalid ); + z.sign = a>>63; + z.low = 0; + z.high = a<<12; + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the canonical NaN `a' to the double- +precision floating-point format. +------------------------------------------------------------------------------- +*/ +static float64 commonNaNToFloat64( commonNaNT a ) +{ + + return + ( ( (bits64) a.sign )<<63 ) + | LIT64( 0x7FF8000000000000 ) + | ( a.high>>12 ); + +} + +/* +------------------------------------------------------------------------------- +Takes two double-precision floating-point values `a' and `b', one of which +is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a +signaling NaN, the invalid exception is raised. +------------------------------------------------------------------------------- +*/ +static float64 propagateFloat64NaN( float64 a, float64 b ) +{ + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + + aIsNaN = float64_is_nan( a ); + aIsSignalingNaN = float64_is_signaling_nan( a ); + bIsNaN = float64_is_nan( b ); + bIsSignalingNaN = float64_is_signaling_nan( b ); + a |= LIT64( 0x0008000000000000 ); + b |= LIT64( 0x0008000000000000 ); + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid ); + if ( aIsNaN ) { + return ( aIsSignalingNaN & bIsNaN ) ? b : a; + } + else { + return b; + } + +} + +#ifdef FLOATX80 + +/* +------------------------------------------------------------------------------- +The pattern for a default generated extended double-precision NaN. The +`high' and `low' values hold the most- and least-significant bits, +respectively. +------------------------------------------------------------------------------- +*/ +#define floatx80_default_nan_high 0xFFFF +#define floatx80_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF ) + +/* +------------------------------------------------------------------------------- +Returns 1 if the extended double-precision floating-point value `a' is a +NaN; otherwise returns 0. +------------------------------------------------------------------------------- +*/ +flag floatx80_is_nan( floatx80 a ) +{ + + return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the extended double-precision floating-point value `a' is a +signaling NaN; otherwise returns 0. +------------------------------------------------------------------------------- +*/ +flag floatx80_is_signaling_nan( floatx80 a ) +{ + //register int lr; + bits64 aLow; + + //__asm__("mov %0, lr" : : "g" (lr)); + //fp_printk("floatx80_is_signalling_nan() called from 0x%08x\n",lr); + aLow = a.low & ~ LIT64( 0x4000000000000000 ); + return + ( ( a.high & 0x7FFF ) == 0x7FFF ) + && (bits64) ( aLow<<1 ) + && ( a.low == aLow ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the extended double-precision floating- +point NaN `a' to the canonical NaN format. If `a' is a signaling NaN, the +invalid exception is raised. +------------------------------------------------------------------------------- +*/ +static commonNaNT floatx80ToCommonNaN( floatx80 a ) +{ + commonNaNT z; + + if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid ); + z.sign = a.high>>15; + z.low = 0; + z.high = a.low<<1; + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the canonical NaN `a' to the extended +double-precision floating-point format. +------------------------------------------------------------------------------- +*/ +static floatx80 commonNaNToFloatx80( commonNaNT a ) +{ + floatx80 z; + + z.low = LIT64( 0xC000000000000000 ) | ( a.high>>1 ); + z.high = ( ( (bits16) a.sign )<<15 ) | 0x7FFF; + return z; + +} + +/* +------------------------------------------------------------------------------- +Takes two extended double-precision floating-point values `a' and `b', one +of which is a NaN, and returns the appropriate NaN result. If either `a' or +`b' is a signaling NaN, the invalid exception is raised. +------------------------------------------------------------------------------- +*/ +static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b ) +{ + flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + + aIsNaN = floatx80_is_nan( a ); + aIsSignalingNaN = floatx80_is_signaling_nan( a ); + bIsNaN = floatx80_is_nan( b ); + bIsSignalingNaN = floatx80_is_signaling_nan( b ); + a.low |= LIT64( 0xC000000000000000 ); + b.low |= LIT64( 0xC000000000000000 ); + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid ); + if ( aIsNaN ) { + return ( aIsSignalingNaN & bIsNaN ) ? b : a; + } + else { + return b; + } + +} + +#endif diff -Nru a/arch/arm26/nwfpe/softfloat.c b/arch/arm26/nwfpe/softfloat.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/nwfpe/softfloat.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,3439 @@ +/* +=============================================================================== + +This C source file is part of the SoftFloat IEC/IEEE Floating-point +Arithmetic Package, Release 2. + +Written by John R. Hauser. This work was made possible in part by the +International Computer Science Institute, located at Suite 600, 1947 Center +Street, Berkeley, California 94704. Funding was partially provided by the +National Science Foundation under grant MIP-9311980. The original version +of this code was written as part of a project to build a fixed-point vector +processor in collaboration with the University of California at Berkeley, +overseen by Profs. Nelson Morgan and John Wawrzynek. More information +is available through the web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ +arithmetic/softfloat.html'. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort +has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT +TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO +PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY +AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. + +Derivative works are acceptable, even for commercial purposes, so long as +(1) they include prominent notice that the work is derivative, and (2) they +include prominent notice akin to these three paragraphs for those parts of +this code that are retained. + +=============================================================================== +*/ + +#include "fpa11.h" +#include "milieu.h" +#include "softfloat.h" + +/* +------------------------------------------------------------------------------- +Floating-point rounding mode, extended double-precision rounding precision, +and exception flags. +------------------------------------------------------------------------------- +*/ +int8 float_rounding_mode = float_round_nearest_even; +int8 floatx80_rounding_precision = 80; +int8 float_exception_flags; + +/* +------------------------------------------------------------------------------- +Primitive arithmetic functions, including multi-word arithmetic, and +division and square root approximations. (Can be specialized to target if +desired.) +------------------------------------------------------------------------------- +*/ +#include "softfloat-macros" + +/* +------------------------------------------------------------------------------- +Functions and definitions to determine: (1) whether tininess for underflow +is detected before or after rounding by default, (2) what (if anything) +happens when exceptions are raised, (3) how signaling NaNs are distinguished +from quiet NaNs, (4) the default generated quiet NaNs, and (5) how NaNs +are propagated from function inputs to output. These details are target- +specific. +------------------------------------------------------------------------------- +*/ +#include "softfloat-specialize" + +/* +------------------------------------------------------------------------------- +Takes a 64-bit fixed-point value `absZ' with binary point between bits 6 +and 7, and returns the properly rounded 32-bit integer corresponding to the +input. If `zSign' is nonzero, the input is negated before being converted +to an integer. Bit 63 of `absZ' must be zero. Ordinarily, the fixed-point +input is simply rounded to an integer, with the inexact exception raised if +the input cannot be represented exactly as an integer. If the fixed-point +input is too large, however, the invalid exception is raised and the largest +positive or negative integer is returned. +------------------------------------------------------------------------------- +*/ +static int32 roundAndPackInt32( flag zSign, bits64 absZ ) +{ + int8 roundingMode; + flag roundNearestEven; + int8 roundIncrement, roundBits; + int32 z; + + roundingMode = float_rounding_mode; + roundNearestEven = ( roundingMode == float_round_nearest_even ); + roundIncrement = 0x40; + if ( ! roundNearestEven ) { + if ( roundingMode == float_round_to_zero ) { + roundIncrement = 0; + } + else { + roundIncrement = 0x7F; + if ( zSign ) { + if ( roundingMode == float_round_up ) roundIncrement = 0; + } + else { + if ( roundingMode == float_round_down ) roundIncrement = 0; + } + } + } + roundBits = absZ & 0x7F; + absZ = ( absZ + roundIncrement )>>7; + absZ &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven ); + z = absZ; + if ( zSign ) z = - z; + if ( ( absZ>>32 ) || ( z && ( ( z < 0 ) ^ zSign ) ) ) { + float_exception_flags |= float_flag_invalid; + return zSign ? 0x80000000 : 0x7FFFFFFF; + } + if ( roundBits ) float_exception_flags |= float_flag_inexact; + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the fraction bits of the single-precision floating-point value `a'. +------------------------------------------------------------------------------- +*/ +INLINE bits32 extractFloat32Frac( float32 a ) +{ + + return a & 0x007FFFFF; + +} + +/* +------------------------------------------------------------------------------- +Returns the exponent bits of the single-precision floating-point value `a'. +------------------------------------------------------------------------------- +*/ +INLINE int16 extractFloat32Exp( float32 a ) +{ + + return ( a>>23 ) & 0xFF; + +} + +/* +------------------------------------------------------------------------------- +Returns the sign bit of the single-precision floating-point value `a'. +------------------------------------------------------------------------------- +*/ +INLINE flag extractFloat32Sign( float32 a ) +{ + + return a>>31; + +} + +/* +------------------------------------------------------------------------------- +Normalizes the subnormal single-precision floating-point value represented +by the denormalized significand `aSig'. The normalized exponent and +significand are stored at the locations pointed to by `zExpPtr' and +`zSigPtr', respectively. +------------------------------------------------------------------------------- +*/ +static void + normalizeFloat32Subnormal( bits32 aSig, int16 *zExpPtr, bits32 *zSigPtr ) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros32( aSig ) - 8; + *zSigPtr = aSig<<shiftCount; + *zExpPtr = 1 - shiftCount; + +} + +/* +------------------------------------------------------------------------------- +Packs the sign `zSign', exponent `zExp', and significand `zSig' into a +single-precision floating-point value, returning the result. After being +shifted into the proper positions, the three fields are simply added +together to form the result. This means that any integer portion of `zSig' +will be added into the exponent. Since a properly normalized significand +will have an integer portion equal to 1, the `zExp' input should be 1 less +than the desired result exponent whenever `zSig' is a complete, normalized +significand. +------------------------------------------------------------------------------- +*/ +INLINE float32 packFloat32( flag zSign, int16 zExp, bits32 zSig ) +{ +#if 0 + float32 f; + __asm__("@ packFloat32; \n\ + mov %0, %1, asl #31; \n\ + orr %0, %2, asl #23; \n\ + orr %0, %3" + : /* no outputs */ + : "g" (f), "g" (zSign), "g" (zExp), "g" (zSig) + : "cc"); + return f; +#else + return ( ( (bits32) zSign )<<31 ) + ( ( (bits32) zExp )<<23 ) + zSig; +#endif +} + +/* +------------------------------------------------------------------------------- +Takes an abstract floating-point value having sign `zSign', exponent `zExp', +and significand `zSig', and returns the proper single-precision floating- +point value corresponding to the abstract input. Ordinarily, the abstract +value is simply rounded and packed into the single-precision format, with +the inexact exception raised if the abstract input cannot be represented +exactly. If the abstract value is too large, however, the overflow and +inexact exceptions are raised and an infinity or maximal finite value is +returned. If the abstract value is too small, the input value is rounded to +a subnormal number, and the underflow and inexact exceptions are raised if +the abstract input cannot be represented exactly as a subnormal single- +precision floating-point number. + The input significand `zSig' has its binary point between bits 30 +and 29, which is 7 bits to the left of the usual location. This shifted +significand must be normalized or smaller. If `zSig' is not normalized, +`zExp' must be 0; in that case, the result returned is a subnormal number, +and it must not require rounding. In the usual case that `zSig' is +normalized, `zExp' must be 1 less than the ``true'' floating-point exponent. +The handling of underflow and overflow follows the IEC/IEEE Standard for +Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +static float32 roundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig ) +{ + int8 roundingMode; + flag roundNearestEven; + int8 roundIncrement, roundBits; + flag isTiny; + + roundingMode = float_rounding_mode; + roundNearestEven = ( roundingMode == float_round_nearest_even ); + roundIncrement = 0x40; + if ( ! roundNearestEven ) { + if ( roundingMode == float_round_to_zero ) { + roundIncrement = 0; + } + else { + roundIncrement = 0x7F; + if ( zSign ) { + if ( roundingMode == float_round_up ) roundIncrement = 0; + } + else { + if ( roundingMode == float_round_down ) roundIncrement = 0; + } + } + } + roundBits = zSig & 0x7F; + if ( 0xFD <= (bits16) zExp ) { + if ( ( 0xFD < zExp ) + || ( ( zExp == 0xFD ) + && ( (sbits32) ( zSig + roundIncrement ) < 0 ) ) + ) { + float_raise( float_flag_overflow | float_flag_inexact ); + return packFloat32( zSign, 0xFF, 0 ) - ( roundIncrement == 0 ); + } + if ( zExp < 0 ) { + isTiny = + ( float_detect_tininess == float_tininess_before_rounding ) + || ( zExp < -1 ) + || ( zSig + roundIncrement < 0x80000000 ); + shift32RightJamming( zSig, - zExp, &zSig ); + zExp = 0; + roundBits = zSig & 0x7F; + if ( isTiny && roundBits ) float_raise( float_flag_underflow ); + } + } + if ( roundBits ) float_exception_flags |= float_flag_inexact; + zSig = ( zSig + roundIncrement )>>7; + zSig &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven ); + if ( zSig == 0 ) zExp = 0; + return packFloat32( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Takes an abstract floating-point value having sign `zSign', exponent `zExp', +and significand `zSig', and returns the proper single-precision floating- +point value corresponding to the abstract input. This routine is just like +`roundAndPackFloat32' except that `zSig' does not have to be normalized in +any way. In all cases, `zExp' must be 1 less than the ``true'' floating- +point exponent. +------------------------------------------------------------------------------- +*/ +static float32 + normalizeRoundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig ) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros32( zSig ) - 1; + return roundAndPackFloat32( zSign, zExp - shiftCount, zSig<<shiftCount ); + +} + +/* +------------------------------------------------------------------------------- +Returns the fraction bits of the double-precision floating-point value `a'. +------------------------------------------------------------------------------- +*/ +INLINE bits64 extractFloat64Frac( float64 a ) +{ + + return a & LIT64( 0x000FFFFFFFFFFFFF ); + +} + +/* +------------------------------------------------------------------------------- +Returns the exponent bits of the double-precision floating-point value `a'. +------------------------------------------------------------------------------- +*/ +INLINE int16 extractFloat64Exp( float64 a ) +{ + + return ( a>>52 ) & 0x7FF; + +} + +/* +------------------------------------------------------------------------------- +Returns the sign bit of the double-precision floating-point value `a'. +------------------------------------------------------------------------------- +*/ +INLINE flag extractFloat64Sign( float64 a ) +{ + + return a>>63; + +} + +/* +------------------------------------------------------------------------------- +Normalizes the subnormal double-precision floating-point value represented +by the denormalized significand `aSig'. The normalized exponent and +significand are stored at the locations pointed to by `zExpPtr' and +`zSigPtr', respectively. +------------------------------------------------------------------------------- +*/ +static void + normalizeFloat64Subnormal( bits64 aSig, int16 *zExpPtr, bits64 *zSigPtr ) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros64( aSig ) - 11; + *zSigPtr = aSig<<shiftCount; + *zExpPtr = 1 - shiftCount; + +} + +/* +------------------------------------------------------------------------------- +Packs the sign `zSign', exponent `zExp', and significand `zSig' into a +double-precision floating-point value, returning the result. After being +shifted into the proper positions, the three fields are simply added +together to form the result. This means that any integer portion of `zSig' +will be added into the exponent. Since a properly normalized significand +will have an integer portion equal to 1, the `zExp' input should be 1 less +than the desired result exponent whenever `zSig' is a complete, normalized +significand. +------------------------------------------------------------------------------- +*/ +INLINE float64 packFloat64( flag zSign, int16 zExp, bits64 zSig ) +{ + + return ( ( (bits64) zSign )<<63 ) + ( ( (bits64) zExp )<<52 ) + zSig; + +} + +/* +------------------------------------------------------------------------------- +Takes an abstract floating-point value having sign `zSign', exponent `zExp', +and significand `zSig', and returns the proper double-precision floating- +point value corresponding to the abstract input. Ordinarily, the abstract +value is simply rounded and packed into the double-precision format, with +the inexact exception raised if the abstract input cannot be represented +exactly. If the abstract value is too large, however, the overflow and +inexact exceptions are raised and an infinity or maximal finite value is +returned. If the abstract value is too small, the input value is rounded to +a subnormal number, and the underflow and inexact exceptions are raised if +the abstract input cannot be represented exactly as a subnormal double- +precision floating-point number. + The input significand `zSig' has its binary point between bits 62 +and 61, which is 10 bits to the left of the usual location. This shifted +significand must be normalized or smaller. If `zSig' is not normalized, +`zExp' must be 0; in that case, the result returned is a subnormal number, +and it must not require rounding. In the usual case that `zSig' is +normalized, `zExp' must be 1 less than the ``true'' floating-point exponent. +The handling of underflow and overflow follows the IEC/IEEE Standard for +Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +static float64 roundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig ) +{ + int8 roundingMode; + flag roundNearestEven; + int16 roundIncrement, roundBits; + flag isTiny; + + roundingMode = float_rounding_mode; + roundNearestEven = ( roundingMode == float_round_nearest_even ); + roundIncrement = 0x200; + if ( ! roundNearestEven ) { + if ( roundingMode == float_round_to_zero ) { + roundIncrement = 0; + } + else { + roundIncrement = 0x3FF; + if ( zSign ) { + if ( roundingMode == float_round_up ) roundIncrement = 0; + } + else { + if ( roundingMode == float_round_down ) roundIncrement = 0; + } + } + } + roundBits = zSig & 0x3FF; + if ( 0x7FD <= (bits16) zExp ) { + if ( ( 0x7FD < zExp ) + || ( ( zExp == 0x7FD ) + && ( (sbits64) ( zSig + roundIncrement ) < 0 ) ) + ) { + //register int lr = __builtin_return_address(0); + //printk("roundAndPackFloat64 called from 0x%08x\n",lr); + float_raise( float_flag_overflow | float_flag_inexact ); + return packFloat64( zSign, 0x7FF, 0 ) - ( roundIncrement == 0 ); + } + if ( zExp < 0 ) { + isTiny = + ( float_detect_tininess == float_tininess_before_rounding ) + || ( zExp < -1 ) + || ( zSig + roundIncrement < LIT64( 0x8000000000000000 ) ); + shift64RightJamming( zSig, - zExp, &zSig ); + zExp = 0; + roundBits = zSig & 0x3FF; + if ( isTiny && roundBits ) float_raise( float_flag_underflow ); + } + } + if ( roundBits ) float_exception_flags |= float_flag_inexact; + zSig = ( zSig + roundIncrement )>>10; + zSig &= ~ ( ( ( roundBits ^ 0x200 ) == 0 ) & roundNearestEven ); + if ( zSig == 0 ) zExp = 0; + return packFloat64( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Takes an abstract floating-point value having sign `zSign', exponent `zExp', +and significand `zSig', and returns the proper double-precision floating- +point value corresponding to the abstract input. This routine is just like +`roundAndPackFloat64' except that `zSig' does not have to be normalized in +any way. In all cases, `zExp' must be 1 less than the ``true'' floating- +point exponent. +------------------------------------------------------------------------------- +*/ +static float64 + normalizeRoundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig ) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros64( zSig ) - 1; + return roundAndPackFloat64( zSign, zExp - shiftCount, zSig<<shiftCount ); + +} + +#ifdef FLOATX80 + +/* +------------------------------------------------------------------------------- +Returns the fraction bits of the extended double-precision floating-point +value `a'. +------------------------------------------------------------------------------- +*/ +INLINE bits64 extractFloatx80Frac( floatx80 a ) +{ + + return a.low; + +} + +/* +------------------------------------------------------------------------------- +Returns the exponent bits of the extended double-precision floating-point +value `a'. +------------------------------------------------------------------------------- +*/ +INLINE int32 extractFloatx80Exp( floatx80 a ) +{ + + return a.high & 0x7FFF; + +} + +/* +------------------------------------------------------------------------------- +Returns the sign bit of the extended double-precision floating-point value +`a'. +------------------------------------------------------------------------------- +*/ +INLINE flag extractFloatx80Sign( floatx80 a ) +{ + + return a.high>>15; + +} + +/* +------------------------------------------------------------------------------- +Normalizes the subnormal extended double-precision floating-point value +represented by the denormalized significand `aSig'. The normalized exponent +and significand are stored at the locations pointed to by `zExpPtr' and +`zSigPtr', respectively. +------------------------------------------------------------------------------- +*/ +static void + normalizeFloatx80Subnormal( bits64 aSig, int32 *zExpPtr, bits64 *zSigPtr ) +{ + int8 shiftCount; + + shiftCount = countLeadingZeros64( aSig ); + *zSigPtr = aSig<<shiftCount; + *zExpPtr = 1 - shiftCount; + +} + +/* +------------------------------------------------------------------------------- +Packs the sign `zSign', exponent `zExp', and significand `zSig' into an +extended double-precision floating-point value, returning the result. +------------------------------------------------------------------------------- +*/ +INLINE floatx80 packFloatx80( flag zSign, int32 zExp, bits64 zSig ) +{ + floatx80 z; + + z.low = zSig; + z.high = ( ( (bits16) zSign )<<15 ) + zExp; + return z; + +} + +/* +------------------------------------------------------------------------------- +Takes an abstract floating-point value having sign `zSign', exponent `zExp', +and extended significand formed by the concatenation of `zSig0' and `zSig1', +and returns the proper extended double-precision floating-point value +corresponding to the abstract input. Ordinarily, the abstract value is +rounded and packed into the extended double-precision format, with the +inexact exception raised if the abstract input cannot be represented +exactly. If the abstract value is too large, however, the overflow and +inexact exceptions are raised and an infinity or maximal finite value is +returned. If the abstract value is too small, the input value is rounded to +a subnormal number, and the underflow and inexact exceptions are raised if +the abstract input cannot be represented exactly as a subnormal extended +double-precision floating-point number. + If `roundingPrecision' is 32 or 64, the result is rounded to the same +number of bits as single or double precision, respectively. Otherwise, the +result is rounded to the full precision of the extended double-precision +format. + The input significand must be normalized or smaller. If the input +significand is not normalized, `zExp' must be 0; in that case, the result +returned is a subnormal number, and it must not require rounding. The +handling of underflow and overflow follows the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +static floatx80 + roundAndPackFloatx80( + int8 roundingPrecision, flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1 + ) +{ + int8 roundingMode; + flag roundNearestEven, increment, isTiny; + int64 roundIncrement, roundMask, roundBits; + + roundingMode = float_rounding_mode; + roundNearestEven = ( roundingMode == float_round_nearest_even ); + if ( roundingPrecision == 80 ) goto precision80; + if ( roundingPrecision == 64 ) { + roundIncrement = LIT64( 0x0000000000000400 ); + roundMask = LIT64( 0x00000000000007FF ); + } + else if ( roundingPrecision == 32 ) { + roundIncrement = LIT64( 0x0000008000000000 ); + roundMask = LIT64( 0x000000FFFFFFFFFF ); + } + else { + goto precision80; + } + zSig0 |= ( zSig1 != 0 ); + if ( ! roundNearestEven ) { + if ( roundingMode == float_round_to_zero ) { + roundIncrement = 0; + } + else { + roundIncrement = roundMask; + if ( zSign ) { + if ( roundingMode == float_round_up ) roundIncrement = 0; + } + else { + if ( roundingMode == float_round_down ) roundIncrement = 0; + } + } + } + roundBits = zSig0 & roundMask; + if ( 0x7FFD <= (bits32) ( zExp - 1 ) ) { + if ( ( 0x7FFE < zExp ) + || ( ( zExp == 0x7FFE ) && ( zSig0 + roundIncrement < zSig0 ) ) + ) { + goto overflow; + } + if ( zExp <= 0 ) { + isTiny = + ( float_detect_tininess == float_tininess_before_rounding ) + || ( zExp < 0 ) + || ( zSig0 <= zSig0 + roundIncrement ); + shift64RightJamming( zSig0, 1 - zExp, &zSig0 ); + zExp = 0; + roundBits = zSig0 & roundMask; + if ( isTiny && roundBits ) float_raise( float_flag_underflow ); + if ( roundBits ) float_exception_flags |= float_flag_inexact; + zSig0 += roundIncrement; + if ( (sbits64) zSig0 < 0 ) zExp = 1; + roundIncrement = roundMask + 1; + if ( roundNearestEven && ( roundBits<<1 == roundIncrement ) ) { + roundMask |= roundIncrement; + } + zSig0 &= ~ roundMask; + return packFloatx80( zSign, zExp, zSig0 ); + } + } + if ( roundBits ) float_exception_flags |= float_flag_inexact; + zSig0 += roundIncrement; + if ( zSig0 < roundIncrement ) { + ++zExp; + zSig0 = LIT64( 0x8000000000000000 ); + } + roundIncrement = roundMask + 1; + if ( roundNearestEven && ( roundBits<<1 == roundIncrement ) ) { + roundMask |= roundIncrement; + } + zSig0 &= ~ roundMask; + if ( zSig0 == 0 ) zExp = 0; + return packFloatx80( zSign, zExp, zSig0 ); + precision80: + increment = ( (sbits64) zSig1 < 0 ); + if ( ! roundNearestEven ) { + if ( roundingMode == float_round_to_zero ) { + increment = 0; + } + else { + if ( zSign ) { + increment = ( roundingMode == float_round_down ) && zSig1; + } + else { + increment = ( roundingMode == float_round_up ) && zSig1; + } + } + } + if ( 0x7FFD <= (bits32) ( zExp - 1 ) ) { + if ( ( 0x7FFE < zExp ) + || ( ( zExp == 0x7FFE ) + && ( zSig0 == LIT64( 0xFFFFFFFFFFFFFFFF ) ) + && increment + ) + ) { + roundMask = 0; + overflow: + float_raise( float_flag_overflow | float_flag_inexact ); + if ( ( roundingMode == float_round_to_zero ) + || ( zSign && ( roundingMode == float_round_up ) ) + || ( ! zSign && ( roundingMode == float_round_down ) ) + ) { + return packFloatx80( zSign, 0x7FFE, ~ roundMask ); + } + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( zExp <= 0 ) { + isTiny = + ( float_detect_tininess == float_tininess_before_rounding ) + || ( zExp < 0 ) + || ! increment + || ( zSig0 < LIT64( 0xFFFFFFFFFFFFFFFF ) ); + shift64ExtraRightJamming( zSig0, zSig1, 1 - zExp, &zSig0, &zSig1 ); + zExp = 0; + if ( isTiny && zSig1 ) float_raise( float_flag_underflow ); + if ( zSig1 ) float_exception_flags |= float_flag_inexact; + if ( roundNearestEven ) { + increment = ( (sbits64) zSig1 < 0 ); + } + else { + if ( zSign ) { + increment = ( roundingMode == float_round_down ) && zSig1; + } + else { + increment = ( roundingMode == float_round_up ) && zSig1; + } + } + if ( increment ) { + ++zSig0; + zSig0 &= ~ ( ( zSig1 + zSig1 == 0 ) & roundNearestEven ); + if ( (sbits64) zSig0 < 0 ) zExp = 1; + } + return packFloatx80( zSign, zExp, zSig0 ); + } + } + if ( zSig1 ) float_exception_flags |= float_flag_inexact; + if ( increment ) { + ++zSig0; + if ( zSig0 == 0 ) { + ++zExp; + zSig0 = LIT64( 0x8000000000000000 ); + } + else { + zSig0 &= ~ ( ( zSig1 + zSig1 == 0 ) & roundNearestEven ); + } + } + else { + if ( zSig0 == 0 ) zExp = 0; + } + + return packFloatx80( zSign, zExp, zSig0 ); +} + +/* +------------------------------------------------------------------------------- +Takes an abstract floating-point value having sign `zSign', exponent +`zExp', and significand formed by the concatenation of `zSig0' and `zSig1', +and returns the proper extended double-precision floating-point value +corresponding to the abstract input. This routine is just like +`roundAndPackFloatx80' except that the input significand does not have to be +normalized. +------------------------------------------------------------------------------- +*/ +static floatx80 + normalizeRoundAndPackFloatx80( + int8 roundingPrecision, flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1 + ) +{ + int8 shiftCount; + + if ( zSig0 == 0 ) { + zSig0 = zSig1; + zSig1 = 0; + zExp -= 64; + } + shiftCount = countLeadingZeros64( zSig0 ); + shortShift128Left( zSig0, zSig1, shiftCount, &zSig0, &zSig1 ); + zExp -= shiftCount; + return + roundAndPackFloatx80( roundingPrecision, zSign, zExp, zSig0, zSig1 ); + +} + +#endif + +/* +------------------------------------------------------------------------------- +Returns the result of converting the 32-bit two's complement integer `a' to +the single-precision floating-point format. The conversion is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float32 int32_to_float32( int32 a ) +{ + flag zSign; + + if ( a == 0 ) return 0; + if ( a == 0x80000000 ) return packFloat32( 1, 0x9E, 0 ); + zSign = ( a < 0 ); + return normalizeRoundAndPackFloat32( zSign, 0x9C, zSign ? - a : a ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the 32-bit two's complement integer `a' to +the double-precision floating-point format. The conversion is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float64 int32_to_float64( int32 a ) +{ + flag aSign; + uint32 absA; + int8 shiftCount; + bits64 zSig; + + if ( a == 0 ) return 0; + aSign = ( a < 0 ); + absA = aSign ? - a : a; + shiftCount = countLeadingZeros32( absA ) + 21; + zSig = absA; + return packFloat64( aSign, 0x432 - shiftCount, zSig<<shiftCount ); + +} + +#ifdef FLOATX80 + +/* +------------------------------------------------------------------------------- +Returns the result of converting the 32-bit two's complement integer `a' +to the extended double-precision floating-point format. The conversion +is performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic. +------------------------------------------------------------------------------- +*/ +floatx80 int32_to_floatx80( int32 a ) +{ + flag zSign; + uint32 absA; + int8 shiftCount; + bits64 zSig; + + if ( a == 0 ) return packFloatx80( 0, 0, 0 ); + zSign = ( a < 0 ); + absA = zSign ? - a : a; + shiftCount = countLeadingZeros32( absA ) + 32; + zSig = absA; + return packFloatx80( zSign, 0x403E - shiftCount, zSig<<shiftCount ); + +} + +#endif + +/* +------------------------------------------------------------------------------- +Returns the result of converting the single-precision floating-point value +`a' to the 32-bit two's complement integer format. The conversion is +performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic---which means in particular that the conversion is rounded +according to the current rounding mode. If `a' is a NaN, the largest +positive integer is returned. Otherwise, if the conversion overflows, the +largest integer with the same sign as `a' is returned. +------------------------------------------------------------------------------- +*/ +int32 float32_to_int32( float32 a ) +{ + flag aSign; + int16 aExp, shiftCount; + bits32 aSig; + bits64 zSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + if ( ( aExp == 0x7FF ) && aSig ) aSign = 0; + if ( aExp ) aSig |= 0x00800000; + shiftCount = 0xAF - aExp; + zSig = aSig; + zSig <<= 32; + if ( 0 < shiftCount ) shift64RightJamming( zSig, shiftCount, &zSig ); + return roundAndPackInt32( aSign, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the single-precision floating-point value +`a' to the 32-bit two's complement integer format. The conversion is +performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic, except that the conversion is always rounded toward zero. If +`a' is a NaN, the largest positive integer is returned. Otherwise, if the +conversion overflows, the largest integer with the same sign as `a' is +returned. +------------------------------------------------------------------------------- +*/ +int32 float32_to_int32_round_to_zero( float32 a ) +{ + flag aSign; + int16 aExp, shiftCount; + bits32 aSig; + int32 z; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + shiftCount = aExp - 0x9E; + if ( 0 <= shiftCount ) { + if ( a == 0xCF000000 ) return 0x80000000; + float_raise( float_flag_invalid ); + if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) return 0x7FFFFFFF; + return 0x80000000; + } + else if ( aExp <= 0x7E ) { + if ( aExp | aSig ) float_exception_flags |= float_flag_inexact; + return 0; + } + aSig = ( aSig | 0x00800000 )<<8; + z = aSig>>( - shiftCount ); + if ( (bits32) ( aSig<<( shiftCount & 31 ) ) ) { + float_exception_flags |= float_flag_inexact; + } + return aSign ? - z : z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the single-precision floating-point value +`a' to the double-precision floating-point format. The conversion is +performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic. +------------------------------------------------------------------------------- +*/ +float64 float32_to_float64( float32 a ) +{ + flag aSign; + int16 aExp; + bits32 aSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + if ( aExp == 0xFF ) { + if ( aSig ) return commonNaNToFloat64( float32ToCommonNaN( a ) ); + return packFloat64( aSign, 0x7FF, 0 ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat64( aSign, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + --aExp; + } + return packFloat64( aSign, aExp + 0x380, ( (bits64) aSig )<<29 ); + +} + +#ifdef FLOATX80 + +/* +------------------------------------------------------------------------------- +Returns the result of converting the single-precision floating-point value +`a' to the extended double-precision floating-point format. The conversion +is performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic. +------------------------------------------------------------------------------- +*/ +floatx80 float32_to_floatx80( float32 a ) +{ + flag aSign; + int16 aExp; + bits32 aSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + if ( aExp == 0xFF ) { + if ( aSig ) return commonNaNToFloatx80( float32ToCommonNaN( a ) ); + return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloatx80( aSign, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + aSig |= 0x00800000; + return packFloatx80( aSign, aExp + 0x3F80, ( (bits64) aSig )<<40 ); + +} + +#endif + +/* +------------------------------------------------------------------------------- +Rounds the single-precision floating-point value `a' to an integer, and +returns the result as a single-precision floating-point value. The +operation is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float32 float32_round_to_int( float32 a ) +{ + flag aSign; + int16 aExp; + bits32 lastBitMask, roundBitsMask; + int8 roundingMode; + float32 z; + + aExp = extractFloat32Exp( a ); + if ( 0x96 <= aExp ) { + if ( ( aExp == 0xFF ) && extractFloat32Frac( a ) ) { + return propagateFloat32NaN( a, a ); + } + return a; + } + if ( aExp <= 0x7E ) { + if ( (bits32) ( a<<1 ) == 0 ) return a; + float_exception_flags |= float_flag_inexact; + aSign = extractFloat32Sign( a ); + switch ( float_rounding_mode ) { + case float_round_nearest_even: + if ( ( aExp == 0x7E ) && extractFloat32Frac( a ) ) { + return packFloat32( aSign, 0x7F, 0 ); + } + break; + case float_round_down: + return aSign ? 0xBF800000 : 0; + case float_round_up: + return aSign ? 0x80000000 : 0x3F800000; + } + return packFloat32( aSign, 0, 0 ); + } + lastBitMask = 1; + lastBitMask <<= 0x96 - aExp; + roundBitsMask = lastBitMask - 1; + z = a; + roundingMode = float_rounding_mode; + if ( roundingMode == float_round_nearest_even ) { + z += lastBitMask>>1; + if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask; + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloat32Sign( z ) ^ ( roundingMode == float_round_up ) ) { + z += roundBitsMask; + } + } + z &= ~ roundBitsMask; + if ( z != a ) float_exception_flags |= float_flag_inexact; + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of adding the absolute values of the single-precision +floating-point values `a' and `b'. If `zSign' is true, the sum is negated +before being returned. `zSign' is ignored if the result is a NaN. The +addition is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +static float32 addFloat32Sigs( float32 a, float32 b, flag zSign ) +{ + int16 aExp, bExp, zExp; + bits32 aSig, bSig, zSig; + int16 expDiff; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + expDiff = aExp - bExp; + aSig <<= 6; + bSig <<= 6; + if ( 0 < expDiff ) { + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig |= 0x20000000; + } + shift32RightJamming( bSig, expDiff, &bSig ); + zExp = aExp; + } + else if ( expDiff < 0 ) { + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b ); + return packFloat32( zSign, 0xFF, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig |= 0x20000000; + } + shift32RightJamming( aSig, - expDiff, &aSig ); + zExp = bExp; + } + else { + if ( aExp == 0xFF ) { + if ( aSig | bSig ) return propagateFloat32NaN( a, b ); + return a; + } + if ( aExp == 0 ) return packFloat32( zSign, 0, ( aSig + bSig )>>6 ); + zSig = 0x40000000 + aSig + bSig; + zExp = aExp; + goto roundAndPack; + } + aSig |= 0x20000000; + zSig = ( aSig + bSig )<<1; + --zExp; + if ( (sbits32) zSig < 0 ) { + zSig = aSig + bSig; + ++zExp; + } + roundAndPack: + return roundAndPackFloat32( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of subtracting the absolute values of the single- +precision floating-point values `a' and `b'. If `zSign' is true, the +difference is negated before being returned. `zSign' is ignored if the +result is a NaN. The subtraction is performed according to the IEC/IEEE +Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +static float32 subFloat32Sigs( float32 a, float32 b, flag zSign ) +{ + int16 aExp, bExp, zExp; + bits32 aSig, bSig, zSig; + int16 expDiff; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + expDiff = aExp - bExp; + aSig <<= 7; + bSig <<= 7; + if ( 0 < expDiff ) goto aExpBigger; + if ( expDiff < 0 ) goto bExpBigger; + if ( aExp == 0xFF ) { + if ( aSig | bSig ) return propagateFloat32NaN( a, b ); + float_raise( float_flag_invalid ); + return float32_default_nan; + } + if ( aExp == 0 ) { + aExp = 1; + bExp = 1; + } + if ( bSig < aSig ) goto aBigger; + if ( aSig < bSig ) goto bBigger; + return packFloat32( float_rounding_mode == float_round_down, 0, 0 ); + bExpBigger: + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b ); + return packFloat32( zSign ^ 1, 0xFF, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig |= 0x40000000; + } + shift32RightJamming( aSig, - expDiff, &aSig ); + bSig |= 0x40000000; + bBigger: + zSig = bSig - aSig; + zExp = bExp; + zSign ^= 1; + goto normalizeRoundAndPack; + aExpBigger: + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig |= 0x40000000; + } + shift32RightJamming( bSig, expDiff, &bSig ); + aSig |= 0x40000000; + aBigger: + zSig = aSig - bSig; + zExp = aExp; + normalizeRoundAndPack: + --zExp; + return normalizeRoundAndPackFloat32( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of adding the single-precision floating-point values `a' +and `b'. The operation is performed according to the IEC/IEEE Standard for +Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float32 float32_add( float32 a, float32 b ) +{ + flag aSign, bSign; + + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign == bSign ) { + return addFloat32Sigs( a, b, aSign ); + } + else { + return subFloat32Sigs( a, b, aSign ); + } + +} + +/* +------------------------------------------------------------------------------- +Returns the result of subtracting the single-precision floating-point values +`a' and `b'. The operation is performed according to the IEC/IEEE Standard +for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float32 float32_sub( float32 a, float32 b ) +{ + flag aSign, bSign; + + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign == bSign ) { + return subFloat32Sigs( a, b, aSign ); + } + else { + return addFloat32Sigs( a, b, aSign ); + } + +} + +/* +------------------------------------------------------------------------------- +Returns the result of multiplying the single-precision floating-point values +`a' and `b'. The operation is performed according to the IEC/IEEE Standard +for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float32 float32_mul( float32 a, float32 b ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, zExp; + bits32 aSig, bSig; + bits64 zSig64; + bits32 zSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + bSign = extractFloat32Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0xFF ) { + if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) { + return propagateFloat32NaN( a, b ); + } + if ( ( bExp | bSig ) == 0 ) { + float_raise( float_flag_invalid ); + return float32_default_nan; + } + return packFloat32( zSign, 0xFF, 0 ); + } + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b ); + if ( ( aExp | aSig ) == 0 ) { + float_raise( float_flag_invalid ); + return float32_default_nan; + } + return packFloat32( zSign, 0xFF, 0 ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat32( zSign, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) return packFloat32( zSign, 0, 0 ); + normalizeFloat32Subnormal( bSig, &bExp, &bSig ); + } + zExp = aExp + bExp - 0x7F; + aSig = ( aSig | 0x00800000 )<<7; + bSig = ( bSig | 0x00800000 )<<8; + shift64RightJamming( ( (bits64) aSig ) * bSig, 32, &zSig64 ); + zSig = zSig64; + if ( 0 <= (sbits32) ( zSig<<1 ) ) { + zSig <<= 1; + --zExp; + } + return roundAndPackFloat32( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of dividing the single-precision floating-point value `a' +by the corresponding value `b'. The operation is performed according to the +IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float32 float32_div( float32 a, float32 b ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, zExp; + bits32 aSig, bSig, zSig; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + bSign = extractFloat32Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, b ); + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b ); + float_raise( float_flag_invalid ); + return float32_default_nan; + } + return packFloat32( zSign, 0xFF, 0 ); + } + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b ); + return packFloat32( zSign, 0, 0 ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + if ( ( aExp | aSig ) == 0 ) { + float_raise( float_flag_invalid ); + return float32_default_nan; + } + float_raise( float_flag_divbyzero ); + return packFloat32( zSign, 0xFF, 0 ); + } + normalizeFloat32Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat32( zSign, 0, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + zExp = aExp - bExp + 0x7D; + aSig = ( aSig | 0x00800000 )<<7; + bSig = ( bSig | 0x00800000 )<<8; + if ( bSig <= ( aSig + aSig ) ) { + aSig >>= 1; + ++zExp; + } + zSig = ( ( (bits64) aSig )<<32 ) / bSig; + if ( ( zSig & 0x3F ) == 0 ) { + zSig |= ( ( (bits64) bSig ) * zSig != ( (bits64) aSig )<<32 ); + } + return roundAndPackFloat32( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the remainder of the single-precision floating-point value `a' +with respect to the corresponding value `b'. The operation is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float32 float32_rem( float32 a, float32 b ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, expDiff; + bits32 aSig, bSig; + bits32 q; + bits64 aSig64, bSig64, q64; + bits32 alternateASig; + sbits32 sigMean; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + bSig = extractFloat32Frac( b ); + bExp = extractFloat32Exp( b ); + bSign = extractFloat32Sign( b ); + if ( aExp == 0xFF ) { + if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) { + return propagateFloat32NaN( a, b ); + } + float_raise( float_flag_invalid ); + return float32_default_nan; + } + if ( bExp == 0xFF ) { + if ( bSig ) return propagateFloat32NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + float_raise( float_flag_invalid ); + return float32_default_nan; + } + normalizeFloat32Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return a; + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + expDiff = aExp - bExp; + aSig |= 0x00800000; + bSig |= 0x00800000; + if ( expDiff < 32 ) { + aSig <<= 8; + bSig <<= 8; + if ( expDiff < 0 ) { + if ( expDiff < -1 ) return a; + aSig >>= 1; + } + q = ( bSig <= aSig ); + if ( q ) aSig -= bSig; + if ( 0 < expDiff ) { + q = ( ( (bits64) aSig )<<32 ) / bSig; + q >>= 32 - expDiff; + bSig >>= 2; + aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q; + } + else { + aSig >>= 2; + bSig >>= 2; + } + } + else { + if ( bSig <= aSig ) aSig -= bSig; + aSig64 = ( (bits64) aSig )<<40; + bSig64 = ( (bits64) bSig )<<40; + expDiff -= 64; + while ( 0 < expDiff ) { + q64 = estimateDiv128To64( aSig64, 0, bSig64 ); + q64 = ( 2 < q64 ) ? q64 - 2 : 0; + aSig64 = - ( ( bSig * q64 )<<38 ); + expDiff -= 62; + } + expDiff += 64; + q64 = estimateDiv128To64( aSig64, 0, bSig64 ); + q64 = ( 2 < q64 ) ? q64 - 2 : 0; + q = q64>>( 64 - expDiff ); + bSig <<= 6; + aSig = ( ( aSig64>>33 )<<( expDiff - 1 ) ) - bSig * q; + } + do { + alternateASig = aSig; + ++q; + aSig -= bSig; + } while ( 0 <= (sbits32) aSig ); + sigMean = aSig + alternateASig; + if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) { + aSig = alternateASig; + } + zSign = ( (sbits32) aSig < 0 ); + if ( zSign ) aSig = - aSig; + return normalizeRoundAndPackFloat32( aSign ^ zSign, bExp, aSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the square root of the single-precision floating-point value `a'. +The operation is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float32 float32_sqrt( float32 a ) +{ + flag aSign; + int16 aExp, zExp; + bits32 aSig, zSig; + bits64 rem, term; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, 0 ); + if ( ! aSign ) return a; + float_raise( float_flag_invalid ); + return float32_default_nan; + } + if ( aSign ) { + if ( ( aExp | aSig ) == 0 ) return a; + float_raise( float_flag_invalid ); + return float32_default_nan; + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return 0; + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + zExp = ( ( aExp - 0x7F )>>1 ) + 0x7E; + aSig = ( aSig | 0x00800000 )<<8; + zSig = estimateSqrt32( aExp, aSig ) + 2; + if ( ( zSig & 0x7F ) <= 5 ) { + if ( zSig < 2 ) { + zSig = 0xFFFFFFFF; + } + else { + aSig >>= aExp & 1; + term = ( (bits64) zSig ) * zSig; + rem = ( ( (bits64) aSig )<<32 ) - term; + while ( (sbits64) rem < 0 ) { + --zSig; + rem += ( ( (bits64) zSig )<<1 ) | 1; + } + zSig |= ( rem != 0 ); + } + } + shift32RightJamming( zSig, 1, &zSig ); + return roundAndPackFloat32( 0, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the single-precision floating-point value `a' is equal to the +corresponding value `b', and 0 otherwise. The comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float32_eq( float32 a, float32 b ) +{ + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the single-precision floating-point value `a' is less than or +equal to the corresponding value `b', and 0 otherwise. The comparison is +performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float32_le( float32 a, float32 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 ); + return ( a == b ) || ( aSign ^ ( a < b ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the single-precision floating-point value `a' is less than +the corresponding value `b', and 0 otherwise. The comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float32_lt( float32 a, float32 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 ); + return ( a != b ) && ( aSign ^ ( a < b ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the single-precision floating-point value `a' is equal to the +corresponding value `b', and 0 otherwise. The invalid exception is raised +if either operand is a NaN. Otherwise, the comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float32_eq_signaling( float32 a, float32 b ) +{ + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the single-precision floating-point value `a' is less than or +equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not +cause an exception. Otherwise, the comparison is performed according to the +IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float32_le_quiet( float32 a, float32 b ) +{ + flag aSign, bSign; + //int16 aExp, bExp; + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 ); + return ( a == b ) || ( aSign ^ ( a < b ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the single-precision floating-point value `a' is less than +the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an +exception. Otherwise, the comparison is performed according to the IEC/IEEE +Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float32_lt_quiet( float32 a, float32 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + aSign = extractFloat32Sign( a ); + bSign = extractFloat32Sign( b ); + if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 ); + return ( a != b ) && ( aSign ^ ( a < b ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the double-precision floating-point value +`a' to the 32-bit two's complement integer format. The conversion is +performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic---which means in particular that the conversion is rounded +according to the current rounding mode. If `a' is a NaN, the largest +positive integer is returned. Otherwise, if the conversion overflows, the +largest integer with the same sign as `a' is returned. +------------------------------------------------------------------------------- +*/ +int32 float64_to_int32( float64 a ) +{ + flag aSign; + int16 aExp, shiftCount; + bits64 aSig; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + if ( ( aExp == 0x7FF ) && aSig ) aSign = 0; + if ( aExp ) aSig |= LIT64( 0x0010000000000000 ); + shiftCount = 0x42C - aExp; + if ( 0 < shiftCount ) shift64RightJamming( aSig, shiftCount, &aSig ); + return roundAndPackInt32( aSign, aSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the double-precision floating-point value +`a' to the 32-bit two's complement integer format. The conversion is +performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic, except that the conversion is always rounded toward zero. If +`a' is a NaN, the largest positive integer is returned. Otherwise, if the +conversion overflows, the largest integer with the same sign as `a' is +returned. +------------------------------------------------------------------------------- +*/ +int32 float64_to_int32_round_to_zero( float64 a ) +{ + flag aSign; + int16 aExp, shiftCount; + bits64 aSig, savedASig; + int32 z; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + shiftCount = 0x433 - aExp; + if ( shiftCount < 21 ) { + if ( ( aExp == 0x7FF ) && aSig ) aSign = 0; + goto invalid; + } + else if ( 52 < shiftCount ) { + if ( aExp || aSig ) float_exception_flags |= float_flag_inexact; + return 0; + } + aSig |= LIT64( 0x0010000000000000 ); + savedASig = aSig; + aSig >>= shiftCount; + z = aSig; + if ( aSign ) z = - z; + if ( ( z < 0 ) ^ aSign ) { + invalid: + float_exception_flags |= float_flag_invalid; + return aSign ? 0x80000000 : 0x7FFFFFFF; + } + if ( ( aSig<<shiftCount ) != savedASig ) { + float_exception_flags |= float_flag_inexact; + } + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the double-precision floating-point value +`a' to the 32-bit two's complement unsigned integer format. The conversion +is performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic---which means in particular that the conversion is rounded +according to the current rounding mode. If `a' is a NaN, the largest +positive integer is returned. Otherwise, if the conversion overflows, the +largest positive integer is returned. +------------------------------------------------------------------------------- +*/ +int32 float64_to_uint32( float64 a ) +{ + flag aSign; + int16 aExp, shiftCount; + bits64 aSig; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = 0; //extractFloat64Sign( a ); + //if ( ( aExp == 0x7FF ) && aSig ) aSign = 0; + if ( aExp ) aSig |= LIT64( 0x0010000000000000 ); + shiftCount = 0x42C - aExp; + if ( 0 < shiftCount ) shift64RightJamming( aSig, shiftCount, &aSig ); + return roundAndPackInt32( aSign, aSig ); +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the double-precision floating-point value +`a' to the 32-bit two's complement integer format. The conversion is +performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic, except that the conversion is always rounded toward zero. If +`a' is a NaN, the largest positive integer is returned. Otherwise, if the +conversion overflows, the largest positive integer is returned. +------------------------------------------------------------------------------- +*/ +int32 float64_to_uint32_round_to_zero( float64 a ) +{ + flag aSign; + int16 aExp, shiftCount; + bits64 aSig, savedASig; + int32 z; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + shiftCount = 0x433 - aExp; + if ( shiftCount < 21 ) { + if ( ( aExp == 0x7FF ) && aSig ) aSign = 0; + goto invalid; + } + else if ( 52 < shiftCount ) { + if ( aExp || aSig ) float_exception_flags |= float_flag_inexact; + return 0; + } + aSig |= LIT64( 0x0010000000000000 ); + savedASig = aSig; + aSig >>= shiftCount; + z = aSig; + if ( aSign ) z = - z; + if ( ( z < 0 ) ^ aSign ) { + invalid: + float_exception_flags |= float_flag_invalid; + return aSign ? 0x80000000 : 0x7FFFFFFF; + } + if ( ( aSig<<shiftCount ) != savedASig ) { + float_exception_flags |= float_flag_inexact; + } + return z; +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the double-precision floating-point value +`a' to the single-precision floating-point format. The conversion is +performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic. +------------------------------------------------------------------------------- +*/ +float32 float64_to_float32( float64 a ) +{ + flag aSign; + int16 aExp; + bits64 aSig; + bits32 zSig; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + if ( aExp == 0x7FF ) { + if ( aSig ) return commonNaNToFloat32( float64ToCommonNaN( a ) ); + return packFloat32( aSign, 0xFF, 0 ); + } + shift64RightJamming( aSig, 22, &aSig ); + zSig = aSig; + if ( aExp || zSig ) { + zSig |= 0x40000000; + aExp -= 0x381; + } + return roundAndPackFloat32( aSign, aExp, zSig ); + +} + +#ifdef FLOATX80 + +/* +------------------------------------------------------------------------------- +Returns the result of converting the double-precision floating-point value +`a' to the extended double-precision floating-point format. The conversion +is performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic. +------------------------------------------------------------------------------- +*/ +floatx80 float64_to_floatx80( float64 a ) +{ + flag aSign; + int16 aExp; + bits64 aSig; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + if ( aExp == 0x7FF ) { + if ( aSig ) return commonNaNToFloatx80( float64ToCommonNaN( a ) ); + return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloatx80( aSign, 0, 0 ); + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + return + packFloatx80( + aSign, aExp + 0x3C00, ( aSig | LIT64( 0x0010000000000000 ) )<<11 ); + +} + +#endif + +/* +------------------------------------------------------------------------------- +Rounds the double-precision floating-point value `a' to an integer, and +returns the result as a double-precision floating-point value. The +operation is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float64 float64_round_to_int( float64 a ) +{ + flag aSign; + int16 aExp; + bits64 lastBitMask, roundBitsMask; + int8 roundingMode; + float64 z; + + aExp = extractFloat64Exp( a ); + if ( 0x433 <= aExp ) { + if ( ( aExp == 0x7FF ) && extractFloat64Frac( a ) ) { + return propagateFloat64NaN( a, a ); + } + return a; + } + if ( aExp <= 0x3FE ) { + if ( (bits64) ( a<<1 ) == 0 ) return a; + float_exception_flags |= float_flag_inexact; + aSign = extractFloat64Sign( a ); + switch ( float_rounding_mode ) { + case float_round_nearest_even: + if ( ( aExp == 0x3FE ) && extractFloat64Frac( a ) ) { + return packFloat64( aSign, 0x3FF, 0 ); + } + break; + case float_round_down: + return aSign ? LIT64( 0xBFF0000000000000 ) : 0; + case float_round_up: + return + aSign ? LIT64( 0x8000000000000000 ) : LIT64( 0x3FF0000000000000 ); + } + return packFloat64( aSign, 0, 0 ); + } + lastBitMask = 1; + lastBitMask <<= 0x433 - aExp; + roundBitsMask = lastBitMask - 1; + z = a; + roundingMode = float_rounding_mode; + if ( roundingMode == float_round_nearest_even ) { + z += lastBitMask>>1; + if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask; + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloat64Sign( z ) ^ ( roundingMode == float_round_up ) ) { + z += roundBitsMask; + } + } + z &= ~ roundBitsMask; + if ( z != a ) float_exception_flags |= float_flag_inexact; + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of adding the absolute values of the double-precision +floating-point values `a' and `b'. If `zSign' is true, the sum is negated +before being returned. `zSign' is ignored if the result is a NaN. The +addition is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +static float64 addFloat64Sigs( float64 a, float64 b, flag zSign ) +{ + int16 aExp, bExp, zExp; + bits64 aSig, bSig, zSig; + int16 expDiff; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + expDiff = aExp - bExp; + aSig <<= 9; + bSig <<= 9; + if ( 0 < expDiff ) { + if ( aExp == 0x7FF ) { + if ( aSig ) return propagateFloat64NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig |= LIT64( 0x2000000000000000 ); + } + shift64RightJamming( bSig, expDiff, &bSig ); + zExp = aExp; + } + else if ( expDiff < 0 ) { + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b ); + return packFloat64( zSign, 0x7FF, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig |= LIT64( 0x2000000000000000 ); + } + shift64RightJamming( aSig, - expDiff, &aSig ); + zExp = bExp; + } + else { + if ( aExp == 0x7FF ) { + if ( aSig | bSig ) return propagateFloat64NaN( a, b ); + return a; + } + if ( aExp == 0 ) return packFloat64( zSign, 0, ( aSig + bSig )>>9 ); + zSig = LIT64( 0x4000000000000000 ) + aSig + bSig; + zExp = aExp; + goto roundAndPack; + } + aSig |= LIT64( 0x2000000000000000 ); + zSig = ( aSig + bSig )<<1; + --zExp; + if ( (sbits64) zSig < 0 ) { + zSig = aSig + bSig; + ++zExp; + } + roundAndPack: + return roundAndPackFloat64( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of subtracting the absolute values of the double- +precision floating-point values `a' and `b'. If `zSign' is true, the +difference is negated before being returned. `zSign' is ignored if the +result is a NaN. The subtraction is performed according to the IEC/IEEE +Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +static float64 subFloat64Sigs( float64 a, float64 b, flag zSign ) +{ + int16 aExp, bExp, zExp; + bits64 aSig, bSig, zSig; + int16 expDiff; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + expDiff = aExp - bExp; + aSig <<= 10; + bSig <<= 10; + if ( 0 < expDiff ) goto aExpBigger; + if ( expDiff < 0 ) goto bExpBigger; + if ( aExp == 0x7FF ) { + if ( aSig | bSig ) return propagateFloat64NaN( a, b ); + float_raise( float_flag_invalid ); + return float64_default_nan; + } + if ( aExp == 0 ) { + aExp = 1; + bExp = 1; + } + if ( bSig < aSig ) goto aBigger; + if ( aSig < bSig ) goto bBigger; + return packFloat64( float_rounding_mode == float_round_down, 0, 0 ); + bExpBigger: + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b ); + return packFloat64( zSign ^ 1, 0x7FF, 0 ); + } + if ( aExp == 0 ) { + ++expDiff; + } + else { + aSig |= LIT64( 0x4000000000000000 ); + } + shift64RightJamming( aSig, - expDiff, &aSig ); + bSig |= LIT64( 0x4000000000000000 ); + bBigger: + zSig = bSig - aSig; + zExp = bExp; + zSign ^= 1; + goto normalizeRoundAndPack; + aExpBigger: + if ( aExp == 0x7FF ) { + if ( aSig ) return propagateFloat64NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + --expDiff; + } + else { + bSig |= LIT64( 0x4000000000000000 ); + } + shift64RightJamming( bSig, expDiff, &bSig ); + aSig |= LIT64( 0x4000000000000000 ); + aBigger: + zSig = aSig - bSig; + zExp = aExp; + normalizeRoundAndPack: + --zExp; + return normalizeRoundAndPackFloat64( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of adding the double-precision floating-point values `a' +and `b'. The operation is performed according to the IEC/IEEE Standard for +Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float64 float64_add( float64 a, float64 b ) +{ + flag aSign, bSign; + + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign == bSign ) { + return addFloat64Sigs( a, b, aSign ); + } + else { + return subFloat64Sigs( a, b, aSign ); + } + +} + +/* +------------------------------------------------------------------------------- +Returns the result of subtracting the double-precision floating-point values +`a' and `b'. The operation is performed according to the IEC/IEEE Standard +for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float64 float64_sub( float64 a, float64 b ) +{ + flag aSign, bSign; + + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign == bSign ) { + return subFloat64Sigs( a, b, aSign ); + } + else { + return addFloat64Sigs( a, b, aSign ); + } + +} + +/* +------------------------------------------------------------------------------- +Returns the result of multiplying the double-precision floating-point values +`a' and `b'. The operation is performed according to the IEC/IEEE Standard +for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float64 float64_mul( float64 a, float64 b ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + bSign = extractFloat64Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FF ) { + if ( aSig || ( ( bExp == 0x7FF ) && bSig ) ) { + return propagateFloat64NaN( a, b ); + } + if ( ( bExp | bSig ) == 0 ) { + float_raise( float_flag_invalid ); + return float64_default_nan; + } + return packFloat64( zSign, 0x7FF, 0 ); + } + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b ); + if ( ( aExp | aSig ) == 0 ) { + float_raise( float_flag_invalid ); + return float64_default_nan; + } + return packFloat64( zSign, 0x7FF, 0 ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat64( zSign, 0, 0 ); + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) return packFloat64( zSign, 0, 0 ); + normalizeFloat64Subnormal( bSig, &bExp, &bSig ); + } + zExp = aExp + bExp - 0x3FF; + aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<10; + bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11; + mul64To128( aSig, bSig, &zSig0, &zSig1 ); + zSig0 |= ( zSig1 != 0 ); + if ( 0 <= (sbits64) ( zSig0<<1 ) ) { + zSig0 <<= 1; + --zExp; + } + return roundAndPackFloat64( zSign, zExp, zSig0 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of dividing the double-precision floating-point value `a' +by the corresponding value `b'. The operation is performed according to +the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float64 float64_div( float64 a, float64 b ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, zExp; + bits64 aSig, bSig, zSig; + bits64 rem0, rem1; + bits64 term0, term1; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + bSign = extractFloat64Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FF ) { + if ( aSig ) return propagateFloat64NaN( a, b ); + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b ); + float_raise( float_flag_invalid ); + return float64_default_nan; + } + return packFloat64( zSign, 0x7FF, 0 ); + } + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b ); + return packFloat64( zSign, 0, 0 ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + if ( ( aExp | aSig ) == 0 ) { + float_raise( float_flag_invalid ); + return float64_default_nan; + } + float_raise( float_flag_divbyzero ); + return packFloat64( zSign, 0x7FF, 0 ); + } + normalizeFloat64Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat64( zSign, 0, 0 ); + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + zExp = aExp - bExp + 0x3FD; + aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<10; + bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11; + if ( bSig <= ( aSig + aSig ) ) { + aSig >>= 1; + ++zExp; + } + zSig = estimateDiv128To64( aSig, 0, bSig ); + if ( ( zSig & 0x1FF ) <= 2 ) { + mul64To128( bSig, zSig, &term0, &term1 ); + sub128( aSig, 0, term0, term1, &rem0, &rem1 ); + while ( (sbits64) rem0 < 0 ) { + --zSig; + add128( rem0, rem1, 0, bSig, &rem0, &rem1 ); + } + zSig |= ( rem1 != 0 ); + } + return roundAndPackFloat64( zSign, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the remainder of the double-precision floating-point value `a' +with respect to the corresponding value `b'. The operation is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float64 float64_rem( float64 a, float64 b ) +{ + flag aSign, bSign, zSign; + int16 aExp, bExp, expDiff; + bits64 aSig, bSig; + bits64 q, alternateASig; + sbits64 sigMean; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + bSig = extractFloat64Frac( b ); + bExp = extractFloat64Exp( b ); + bSign = extractFloat64Sign( b ); + if ( aExp == 0x7FF ) { + if ( aSig || ( ( bExp == 0x7FF ) && bSig ) ) { + return propagateFloat64NaN( a, b ); + } + float_raise( float_flag_invalid ); + return float64_default_nan; + } + if ( bExp == 0x7FF ) { + if ( bSig ) return propagateFloat64NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + float_raise( float_flag_invalid ); + return float64_default_nan; + } + normalizeFloat64Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return a; + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + expDiff = aExp - bExp; + aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<11; + bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11; + if ( expDiff < 0 ) { + if ( expDiff < -1 ) return a; + aSig >>= 1; + } + q = ( bSig <= aSig ); + if ( q ) aSig -= bSig; + expDiff -= 64; + while ( 0 < expDiff ) { + q = estimateDiv128To64( aSig, 0, bSig ); + q = ( 2 < q ) ? q - 2 : 0; + aSig = - ( ( bSig>>2 ) * q ); + expDiff -= 62; + } + expDiff += 64; + if ( 0 < expDiff ) { + q = estimateDiv128To64( aSig, 0, bSig ); + q = ( 2 < q ) ? q - 2 : 0; + q >>= 64 - expDiff; + bSig >>= 2; + aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q; + } + else { + aSig >>= 2; + bSig >>= 2; + } + do { + alternateASig = aSig; + ++q; + aSig -= bSig; + } while ( 0 <= (sbits64) aSig ); + sigMean = aSig + alternateASig; + if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) { + aSig = alternateASig; + } + zSign = ( (sbits64) aSig < 0 ); + if ( zSign ) aSig = - aSig; + return normalizeRoundAndPackFloat64( aSign ^ zSign, bExp, aSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the square root of the double-precision floating-point value `a'. +The operation is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float64 float64_sqrt( float64 a ) +{ + flag aSign; + int16 aExp, zExp; + bits64 aSig, zSig; + bits64 rem0, rem1, term0, term1; //, shiftedRem; + //float64 z; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + if ( aExp == 0x7FF ) { + if ( aSig ) return propagateFloat64NaN( a, a ); + if ( ! aSign ) return a; + float_raise( float_flag_invalid ); + return float64_default_nan; + } + if ( aSign ) { + if ( ( aExp | aSig ) == 0 ) return a; + float_raise( float_flag_invalid ); + return float64_default_nan; + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return 0; + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + zExp = ( ( aExp - 0x3FF )>>1 ) + 0x3FE; + aSig |= LIT64( 0x0010000000000000 ); + zSig = estimateSqrt32( aExp, aSig>>21 ); + zSig <<= 31; + aSig <<= 9 - ( aExp & 1 ); + zSig = estimateDiv128To64( aSig, 0, zSig ) + zSig + 2; + if ( ( zSig & 0x3FF ) <= 5 ) { + if ( zSig < 2 ) { + zSig = LIT64( 0xFFFFFFFFFFFFFFFF ); + } + else { + aSig <<= 2; + mul64To128( zSig, zSig, &term0, &term1 ); + sub128( aSig, 0, term0, term1, &rem0, &rem1 ); + while ( (sbits64) rem0 < 0 ) { + --zSig; + shortShift128Left( 0, zSig, 1, &term0, &term1 ); + term1 |= 1; + add128( rem0, rem1, term0, term1, &rem0, &rem1 ); + } + zSig |= ( ( rem0 | rem1 ) != 0 ); + } + } + shift64RightJamming( zSig, 1, &zSig ); + return roundAndPackFloat64( 0, zExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the double-precision floating-point value `a' is equal to the +corresponding value `b', and 0 otherwise. The comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float64_eq( float64 a, float64 b ) +{ + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + return ( a == b ) || ( (bits64) ( ( a | b )<<1 ) == 0 ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the double-precision floating-point value `a' is less than or +equal to the corresponding value `b', and 0 otherwise. The comparison is +performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float64_le( float64 a, float64 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign != bSign ) return aSign || ( (bits64) ( ( a | b )<<1 ) == 0 ); + return ( a == b ) || ( aSign ^ ( a < b ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the double-precision floating-point value `a' is less than +the corresponding value `b', and 0 otherwise. The comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float64_lt( float64 a, float64 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign != bSign ) return aSign && ( (bits64) ( ( a | b )<<1 ) != 0 ); + return ( a != b ) && ( aSign ^ ( a < b ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the double-precision floating-point value `a' is equal to the +corresponding value `b', and 0 otherwise. The invalid exception is raised +if either operand is a NaN. Otherwise, the comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float64_eq_signaling( float64 a, float64 b ) +{ + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + return ( a == b ) || ( (bits64) ( ( a | b )<<1 ) == 0 ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the double-precision floating-point value `a' is less than or +equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not +cause an exception. Otherwise, the comparison is performed according to the +IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float64_le_quiet( float64 a, float64 b ) +{ + flag aSign, bSign; + //int16 aExp, bExp; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign != bSign ) return aSign || ( (bits64) ( ( a | b )<<1 ) == 0 ); + return ( a == b ) || ( aSign ^ ( a < b ) ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the double-precision floating-point value `a' is less than +the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an +exception. Otherwise, the comparison is performed according to the IEC/IEEE +Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag float64_lt_quiet( float64 a, float64 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + aSign = extractFloat64Sign( a ); + bSign = extractFloat64Sign( b ); + if ( aSign != bSign ) return aSign && ( (bits64) ( ( a | b )<<1 ) != 0 ); + return ( a != b ) && ( aSign ^ ( a < b ) ); + +} + +#ifdef FLOATX80 + +/* +------------------------------------------------------------------------------- +Returns the result of converting the extended double-precision floating- +point value `a' to the 32-bit two's complement integer format. The +conversion is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic---which means in particular that the conversion +is rounded according to the current rounding mode. If `a' is a NaN, the +largest positive integer is returned. Otherwise, if the conversion +overflows, the largest integer with the same sign as `a' is returned. +------------------------------------------------------------------------------- +*/ +int32 floatx80_to_int32( floatx80 a ) +{ + flag aSign; + int32 aExp, shiftCount; + bits64 aSig; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) aSign = 0; + shiftCount = 0x4037 - aExp; + if ( shiftCount <= 0 ) shiftCount = 1; + shift64RightJamming( aSig, shiftCount, &aSig ); + return roundAndPackInt32( aSign, aSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the extended double-precision floating- +point value `a' to the 32-bit two's complement integer format. The +conversion is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic, except that the conversion is always rounded +toward zero. If `a' is a NaN, the largest positive integer is returned. +Otherwise, if the conversion overflows, the largest integer with the same +sign as `a' is returned. +------------------------------------------------------------------------------- +*/ +int32 floatx80_to_int32_round_to_zero( floatx80 a ) +{ + flag aSign; + int32 aExp, shiftCount; + bits64 aSig, savedASig; + int32 z; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + shiftCount = 0x403E - aExp; + if ( shiftCount < 32 ) { + if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) aSign = 0; + goto invalid; + } + else if ( 63 < shiftCount ) { + if ( aExp || aSig ) float_exception_flags |= float_flag_inexact; + return 0; + } + savedASig = aSig; + aSig >>= shiftCount; + z = aSig; + if ( aSign ) z = - z; + if ( ( z < 0 ) ^ aSign ) { + invalid: + float_exception_flags |= float_flag_invalid; + return aSign ? 0x80000000 : 0x7FFFFFFF; + } + if ( ( aSig<<shiftCount ) != savedASig ) { + float_exception_flags |= float_flag_inexact; + } + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the extended double-precision floating- +point value `a' to the single-precision floating-point format. The +conversion is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float32 floatx80_to_float32( floatx80 a ) +{ + flag aSign; + int32 aExp; + bits64 aSig; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) ) { + return commonNaNToFloat32( floatx80ToCommonNaN( a ) ); + } + return packFloat32( aSign, 0xFF, 0 ); + } + shift64RightJamming( aSig, 33, &aSig ); + if ( aExp || aSig ) aExp -= 0x3F81; + return roundAndPackFloat32( aSign, aExp, aSig ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of converting the extended double-precision floating- +point value `a' to the double-precision floating-point format. The +conversion is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +float64 floatx80_to_float64( floatx80 a ) +{ + flag aSign; + int32 aExp; + bits64 aSig, zSig; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) ) { + return commonNaNToFloat64( floatx80ToCommonNaN( a ) ); + } + return packFloat64( aSign, 0x7FF, 0 ); + } + shift64RightJamming( aSig, 1, &zSig ); + if ( aExp || aSig ) aExp -= 0x3C01; + return roundAndPackFloat64( aSign, aExp, zSig ); + +} + +/* +------------------------------------------------------------------------------- +Rounds the extended double-precision floating-point value `a' to an integer, +and returns the result as an extended quadruple-precision floating-point +value. The operation is performed according to the IEC/IEEE Standard for +Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +floatx80 floatx80_round_to_int( floatx80 a ) +{ + flag aSign; + int32 aExp; + bits64 lastBitMask, roundBitsMask; + int8 roundingMode; + floatx80 z; + + aExp = extractFloatx80Exp( a ); + if ( 0x403E <= aExp ) { + if ( ( aExp == 0x7FFF ) && (bits64) ( extractFloatx80Frac( a )<<1 ) ) { + return propagateFloatx80NaN( a, a ); + } + return a; + } + if ( aExp <= 0x3FFE ) { + if ( ( aExp == 0 ) + && ( (bits64) ( extractFloatx80Frac( a )<<1 ) == 0 ) ) { + return a; + } + float_exception_flags |= float_flag_inexact; + aSign = extractFloatx80Sign( a ); + switch ( float_rounding_mode ) { + case float_round_nearest_even: + if ( ( aExp == 0x3FFE ) && (bits64) ( extractFloatx80Frac( a )<<1 ) + ) { + return + packFloatx80( aSign, 0x3FFF, LIT64( 0x8000000000000000 ) ); + } + break; + case float_round_down: + return + aSign ? + packFloatx80( 1, 0x3FFF, LIT64( 0x8000000000000000 ) ) + : packFloatx80( 0, 0, 0 ); + case float_round_up: + return + aSign ? packFloatx80( 1, 0, 0 ) + : packFloatx80( 0, 0x3FFF, LIT64( 0x8000000000000000 ) ); + } + return packFloatx80( aSign, 0, 0 ); + } + lastBitMask = 1; + lastBitMask <<= 0x403E - aExp; + roundBitsMask = lastBitMask - 1; + z = a; + roundingMode = float_rounding_mode; + if ( roundingMode == float_round_nearest_even ) { + z.low += lastBitMask>>1; + if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask; + } + else if ( roundingMode != float_round_to_zero ) { + if ( extractFloatx80Sign( z ) ^ ( roundingMode == float_round_up ) ) { + z.low += roundBitsMask; + } + } + z.low &= ~ roundBitsMask; + if ( z.low == 0 ) { + ++z.high; + z.low = LIT64( 0x8000000000000000 ); + } + if ( z.low != a.low ) float_exception_flags |= float_flag_inexact; + return z; + +} + +/* +------------------------------------------------------------------------------- +Returns the result of adding the absolute values of the extended double- +precision floating-point values `a' and `b'. If `zSign' is true, the sum is +negated before being returned. `zSign' is ignored if the result is a NaN. +The addition is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +static floatx80 addFloatx80Sigs( floatx80 a, floatx80 b, flag zSign ) +{ + int32 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + int32 expDiff; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + expDiff = aExp - bExp; + if ( 0 < expDiff ) { + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b ); + return a; + } + if ( bExp == 0 ) --expDiff; + shift64ExtraRightJamming( bSig, 0, expDiff, &bSig, &zSig1 ); + zExp = aExp; + } + else if ( expDiff < 0 ) { + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) ++expDiff; + shift64ExtraRightJamming( aSig, 0, - expDiff, &aSig, &zSig1 ); + zExp = bExp; + } + else { + if ( aExp == 0x7FFF ) { + if ( (bits64) ( ( aSig | bSig )<<1 ) ) { + return propagateFloatx80NaN( a, b ); + } + return a; + } + zSig1 = 0; + zSig0 = aSig + bSig; + if ( aExp == 0 ) { + normalizeFloatx80Subnormal( zSig0, &zExp, &zSig0 ); + goto roundAndPack; + } + zExp = aExp; + goto shiftRight1; + } + + zSig0 = aSig + bSig; + + if ( (sbits64) zSig0 < 0 ) goto roundAndPack; + shiftRight1: + shift64ExtraRightJamming( zSig0, zSig1, 1, &zSig0, &zSig1 ); + zSig0 |= LIT64( 0x8000000000000000 ); + ++zExp; + roundAndPack: + return + roundAndPackFloatx80( + floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of subtracting the absolute values of the extended +double-precision floating-point values `a' and `b'. If `zSign' is true, +the difference is negated before being returned. `zSign' is ignored if the +result is a NaN. The subtraction is performed according to the IEC/IEEE +Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +static floatx80 subFloatx80Sigs( floatx80 a, floatx80 b, flag zSign ) +{ + int32 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + int32 expDiff; + floatx80 z; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + expDiff = aExp - bExp; + if ( 0 < expDiff ) goto aExpBigger; + if ( expDiff < 0 ) goto bExpBigger; + if ( aExp == 0x7FFF ) { + if ( (bits64) ( ( aSig | bSig )<<1 ) ) { + return propagateFloatx80NaN( a, b ); + } + float_raise( float_flag_invalid ); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + if ( aExp == 0 ) { + aExp = 1; + bExp = 1; + } + zSig1 = 0; + if ( bSig < aSig ) goto aBigger; + if ( aSig < bSig ) goto bBigger; + return packFloatx80( float_rounding_mode == float_round_down, 0, 0 ); + bExpBigger: + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); + return packFloatx80( zSign ^ 1, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) ++expDiff; + shift128RightJamming( aSig, 0, - expDiff, &aSig, &zSig1 ); + bBigger: + sub128( bSig, 0, aSig, zSig1, &zSig0, &zSig1 ); + zExp = bExp; + zSign ^= 1; + goto normalizeRoundAndPack; + aExpBigger: + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b ); + return a; + } + if ( bExp == 0 ) --expDiff; + shift128RightJamming( bSig, 0, expDiff, &bSig, &zSig1 ); + aBigger: + sub128( aSig, 0, bSig, zSig1, &zSig0, &zSig1 ); + zExp = aExp; + normalizeRoundAndPack: + return + normalizeRoundAndPackFloatx80( + floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of adding the extended double-precision floating-point +values `a' and `b'. The operation is performed according to the IEC/IEEE +Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +floatx80 floatx80_add( floatx80 a, floatx80 b ) +{ + flag aSign, bSign; + + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign == bSign ) { + return addFloatx80Sigs( a, b, aSign ); + } + else { + return subFloatx80Sigs( a, b, aSign ); + } + +} + +/* +------------------------------------------------------------------------------- +Returns the result of subtracting the extended double-precision floating- +point values `a' and `b'. The operation is performed according to the +IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +floatx80 floatx80_sub( floatx80 a, floatx80 b ) +{ + flag aSign, bSign; + + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign == bSign ) { + return subFloatx80Sigs( a, b, aSign ); + } + else { + return addFloatx80Sigs( a, b, aSign ); + } + +} + +/* +------------------------------------------------------------------------------- +Returns the result of multiplying the extended double-precision floating- +point values `a' and `b'. The operation is performed according to the +IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +floatx80 floatx80_mul( floatx80 a, floatx80 b ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + floatx80 z; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + bSign = extractFloatx80Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) + || ( ( bExp == 0x7FFF ) && (bits64) ( bSig<<1 ) ) ) { + return propagateFloatx80NaN( a, b ); + } + if ( ( bExp | bSig ) == 0 ) goto invalid; + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); + if ( ( aExp | aSig ) == 0 ) { + invalid: + float_raise( float_flag_invalid ); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 ); + normalizeFloatx80Subnormal( aSig, &aExp, &aSig ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) return packFloatx80( zSign, 0, 0 ); + normalizeFloatx80Subnormal( bSig, &bExp, &bSig ); + } + zExp = aExp + bExp - 0x3FFE; + mul64To128( aSig, bSig, &zSig0, &zSig1 ); + if ( 0 < (sbits64) zSig0 ) { + shortShift128Left( zSig0, zSig1, 1, &zSig0, &zSig1 ); + --zExp; + } + return + roundAndPackFloatx80( + floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the result of dividing the extended double-precision floating-point +value `a' by the corresponding value `b'. The operation is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +floatx80 floatx80_div( floatx80 a, floatx80 b ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, zExp; + bits64 aSig, bSig, zSig0, zSig1; + bits64 rem0, rem1, rem2, term0, term1, term2; + floatx80 z; + + aSig = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + bSign = extractFloatx80Sign( b ); + zSign = aSign ^ bSign; + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b ); + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); + goto invalid; + } + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); + return packFloatx80( zSign, 0, 0 ); + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + if ( ( aExp | aSig ) == 0 ) { + invalid: + float_raise( float_flag_invalid ); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + float_raise( float_flag_divbyzero ); + return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); + } + normalizeFloatx80Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 ); + normalizeFloatx80Subnormal( aSig, &aExp, &aSig ); + } + zExp = aExp - bExp + 0x3FFE; + rem1 = 0; + if ( bSig <= aSig ) { + shift128Right( aSig, 0, 1, &aSig, &rem1 ); + ++zExp; + } + zSig0 = estimateDiv128To64( aSig, rem1, bSig ); + mul64To128( bSig, zSig0, &term0, &term1 ); + sub128( aSig, rem1, term0, term1, &rem0, &rem1 ); + while ( (sbits64) rem0 < 0 ) { + --zSig0; + add128( rem0, rem1, 0, bSig, &rem0, &rem1 ); + } + zSig1 = estimateDiv128To64( rem1, 0, bSig ); + if ( (bits64) ( zSig1<<1 ) <= 8 ) { + mul64To128( bSig, zSig1, &term1, &term2 ); + sub128( rem1, 0, term1, term2, &rem1, &rem2 ); + while ( (sbits64) rem1 < 0 ) { + --zSig1; + add128( rem1, rem2, 0, bSig, &rem1, &rem2 ); + } + zSig1 |= ( ( rem1 | rem2 ) != 0 ); + } + return + roundAndPackFloatx80( + floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the remainder of the extended double-precision floating-point value +`a' with respect to the corresponding value `b'. The operation is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +floatx80 floatx80_rem( floatx80 a, floatx80 b ) +{ + flag aSign, bSign, zSign; + int32 aExp, bExp, expDiff; + bits64 aSig0, aSig1, bSig; + bits64 q, term0, term1, alternateASig0, alternateASig1; + floatx80 z; + + aSig0 = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + bSig = extractFloatx80Frac( b ); + bExp = extractFloatx80Exp( b ); + bSign = extractFloatx80Sign( b ); + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig0<<1 ) + || ( ( bExp == 0x7FFF ) && (bits64) ( bSig<<1 ) ) ) { + return propagateFloatx80NaN( a, b ); + } + goto invalid; + } + if ( bExp == 0x7FFF ) { + if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b ); + return a; + } + if ( bExp == 0 ) { + if ( bSig == 0 ) { + invalid: + float_raise( float_flag_invalid ); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + normalizeFloatx80Subnormal( bSig, &bExp, &bSig ); + } + if ( aExp == 0 ) { + if ( (bits64) ( aSig0<<1 ) == 0 ) return a; + normalizeFloatx80Subnormal( aSig0, &aExp, &aSig0 ); + } + bSig |= LIT64( 0x8000000000000000 ); + zSign = aSign; + expDiff = aExp - bExp; + aSig1 = 0; + if ( expDiff < 0 ) { + if ( expDiff < -1 ) return a; + shift128Right( aSig0, 0, 1, &aSig0, &aSig1 ); + expDiff = 0; + } + q = ( bSig <= aSig0 ); + if ( q ) aSig0 -= bSig; + expDiff -= 64; + while ( 0 < expDiff ) { + q = estimateDiv128To64( aSig0, aSig1, bSig ); + q = ( 2 < q ) ? q - 2 : 0; + mul64To128( bSig, q, &term0, &term1 ); + sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 ); + shortShift128Left( aSig0, aSig1, 62, &aSig0, &aSig1 ); + expDiff -= 62; + } + expDiff += 64; + if ( 0 < expDiff ) { + q = estimateDiv128To64( aSig0, aSig1, bSig ); + q = ( 2 < q ) ? q - 2 : 0; + q >>= 64 - expDiff; + mul64To128( bSig, q<<( 64 - expDiff ), &term0, &term1 ); + sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 ); + shortShift128Left( 0, bSig, 64 - expDiff, &term0, &term1 ); + while ( le128( term0, term1, aSig0, aSig1 ) ) { + ++q; + sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 ); + } + } + else { + term1 = 0; + term0 = bSig; + } + sub128( term0, term1, aSig0, aSig1, &alternateASig0, &alternateASig1 ); + if ( lt128( alternateASig0, alternateASig1, aSig0, aSig1 ) + || ( eq128( alternateASig0, alternateASig1, aSig0, aSig1 ) + && ( q & 1 ) ) + ) { + aSig0 = alternateASig0; + aSig1 = alternateASig1; + zSign = ! zSign; + } + return + normalizeRoundAndPackFloatx80( + 80, zSign, bExp + expDiff, aSig0, aSig1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns the square root of the extended double-precision floating-point +value `a'. The operation is performed according to the IEC/IEEE Standard +for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +floatx80 floatx80_sqrt( floatx80 a ) +{ + flag aSign; + int32 aExp, zExp; + bits64 aSig0, aSig1, zSig0, zSig1; + bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3; + bits64 shiftedRem0, shiftedRem1; + floatx80 z; + + aSig0 = extractFloatx80Frac( a ); + aExp = extractFloatx80Exp( a ); + aSign = extractFloatx80Sign( a ); + if ( aExp == 0x7FFF ) { + if ( (bits64) ( aSig0<<1 ) ) return propagateFloatx80NaN( a, a ); + if ( ! aSign ) return a; + goto invalid; + } + if ( aSign ) { + if ( ( aExp | aSig0 ) == 0 ) return a; + invalid: + float_raise( float_flag_invalid ); + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + return z; + } + if ( aExp == 0 ) { + if ( aSig0 == 0 ) return packFloatx80( 0, 0, 0 ); + normalizeFloatx80Subnormal( aSig0, &aExp, &aSig0 ); + } + zExp = ( ( aExp - 0x3FFF )>>1 ) + 0x3FFF; + zSig0 = estimateSqrt32( aExp, aSig0>>32 ); + zSig0 <<= 31; + aSig1 = 0; + shift128Right( aSig0, 0, ( aExp & 1 ) + 2, &aSig0, &aSig1 ); + zSig0 = estimateDiv128To64( aSig0, aSig1, zSig0 ) + zSig0 + 4; + if ( 0 <= (sbits64) zSig0 ) zSig0 = LIT64( 0xFFFFFFFFFFFFFFFF ); + shortShift128Left( aSig0, aSig1, 2, &aSig0, &aSig1 ); + mul64To128( zSig0, zSig0, &term0, &term1 ); + sub128( aSig0, aSig1, term0, term1, &rem0, &rem1 ); + while ( (sbits64) rem0 < 0 ) { + --zSig0; + shortShift128Left( 0, zSig0, 1, &term0, &term1 ); + term1 |= 1; + add128( rem0, rem1, term0, term1, &rem0, &rem1 ); + } + shortShift128Left( rem0, rem1, 63, &shiftedRem0, &shiftedRem1 ); + zSig1 = estimateDiv128To64( shiftedRem0, shiftedRem1, zSig0 ); + if ( (bits64) ( zSig1<<1 ) <= 10 ) { + if ( zSig1 == 0 ) zSig1 = 1; + mul64To128( zSig0, zSig1, &term1, &term2 ); + shortShift128Left( term1, term2, 1, &term1, &term2 ); + sub128( rem1, 0, term1, term2, &rem1, &rem2 ); + mul64To128( zSig1, zSig1, &term2, &term3 ); + sub192( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 ); + while ( (sbits64) rem1 < 0 ) { + --zSig1; + shortShift192Left( 0, zSig0, zSig1, 1, &term1, &term2, &term3 ); + term3 |= 1; + add192( + rem1, rem2, rem3, term1, term2, term3, &rem1, &rem2, &rem3 ); + } + zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 ); + } + return + roundAndPackFloatx80( + floatx80_rounding_precision, 0, zExp, zSig0, zSig1 ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the extended double-precision floating-point value `a' is +equal to the corresponding value `b', and 0 otherwise. The comparison is +performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic. +------------------------------------------------------------------------------- +*/ +flag floatx80_eq( floatx80 a, floatx80 b ) +{ + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + if ( floatx80_is_signaling_nan( a ) + || floatx80_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + return + ( a.low == b.low ) + && ( ( a.high == b.high ) + || ( ( a.low == 0 ) + && ( (bits16) ( ( a.high | b.high )<<1 ) == 0 ) ) + ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the extended double-precision floating-point value `a' is +less than or equal to the corresponding value `b', and 0 otherwise. The +comparison is performed according to the IEC/IEEE Standard for Binary +Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag floatx80_le( floatx80 a, floatx80 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign != bSign ) { + return + aSign + || ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + == 0 ); + } + return + aSign ? le128( b.high, b.low, a.high, a.low ) + : le128( a.high, a.low, b.high, b.low ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the extended double-precision floating-point value `a' is +less than the corresponding value `b', and 0 otherwise. The comparison +is performed according to the IEC/IEEE Standard for Binary Floating-point +Arithmetic. +------------------------------------------------------------------------------- +*/ +flag floatx80_lt( floatx80 a, floatx80 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign != bSign ) { + return + aSign + && ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + != 0 ); + } + return + aSign ? lt128( b.high, b.low, a.high, a.low ) + : lt128( a.high, a.low, b.high, b.low ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the extended double-precision floating-point value `a' is equal +to the corresponding value `b', and 0 otherwise. The invalid exception is +raised if either operand is a NaN. Otherwise, the comparison is performed +according to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag floatx80_eq_signaling( floatx80 a, floatx80 b ) +{ + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + float_raise( float_flag_invalid ); + return 0; + } + return + ( a.low == b.low ) + && ( ( a.high == b.high ) + || ( ( a.low == 0 ) + && ( (bits16) ( ( a.high | b.high )<<1 ) == 0 ) ) + ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the extended double-precision floating-point value `a' is less +than or equal to the corresponding value `b', and 0 otherwise. Quiet NaNs +do not cause an exception. Otherwise, the comparison is performed according +to the IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag floatx80_le_quiet( floatx80 a, floatx80 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + if ( floatx80_is_signaling_nan( a ) + || floatx80_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign != bSign ) { + return + aSign + || ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + == 0 ); + } + return + aSign ? le128( b.high, b.low, a.high, a.low ) + : le128( a.high, a.low, b.high, b.low ); + +} + +/* +------------------------------------------------------------------------------- +Returns 1 if the extended double-precision floating-point value `a' is less +than the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause +an exception. Otherwise, the comparison is performed according to the +IEC/IEEE Standard for Binary Floating-point Arithmetic. +------------------------------------------------------------------------------- +*/ +flag floatx80_lt_quiet( floatx80 a, floatx80 b ) +{ + flag aSign, bSign; + + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + ) { + if ( floatx80_is_signaling_nan( a ) + || floatx80_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid ); + } + return 0; + } + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign != bSign ) { + return + aSign + && ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + != 0 ); + } + return + aSign ? lt128( b.high, b.low, a.high, a.low ) + : lt128( a.high, a.low, b.high, b.low ); + +} + +#endif + diff -Nru a/arch/arm26/nwfpe/softfloat.h b/arch/arm26/nwfpe/softfloat.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/nwfpe/softfloat.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,232 @@ + +/* +=============================================================================== + +This C header file is part of the SoftFloat IEC/IEEE Floating-point +Arithmetic Package, Release 2. + +Written by John R. Hauser. This work was made possible in part by the +International Computer Science Institute, located at Suite 600, 1947 Center +Street, Berkeley, California 94704. Funding was partially provided by the +National Science Foundation under grant MIP-9311980. The original version +of this code was written as part of a project to build a fixed-point vector +processor in collaboration with the University of California at Berkeley, +overseen by Profs. Nelson Morgan and John Wawrzynek. More information +is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/ +arithmetic/softfloat.html'. + +THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort +has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT +TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO +PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY +AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE. + +Derivative works are acceptable, even for commercial purposes, so long as +(1) they include prominent notice that the work is derivative, and (2) they +include prominent notice akin to these three paragraphs for those parts of +this code that are retained. + +=============================================================================== +*/ + +#ifndef __SOFTFLOAT_H__ +#define __SOFTFLOAT_H__ + +/* +------------------------------------------------------------------------------- +The macro `FLOATX80' must be defined to enable the extended double-precision +floating-point format `floatx80'. If this macro is not defined, the +`floatx80' type will not be defined, and none of the functions that either +input or output the `floatx80' type will be defined. +------------------------------------------------------------------------------- +*/ +#define FLOATX80 + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE floating-point types. +------------------------------------------------------------------------------- +*/ +typedef unsigned long int float32; +typedef unsigned long long float64; +typedef struct { + unsigned short high; + unsigned long long low; +} floatx80; + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE floating-point underflow tininess-detection mode. +------------------------------------------------------------------------------- +*/ +extern signed char float_detect_tininess; +enum { + float_tininess_after_rounding = 0, + float_tininess_before_rounding = 1 +}; + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE floating-point rounding mode. +------------------------------------------------------------------------------- +*/ +extern signed char float_rounding_mode; +enum { + float_round_nearest_even = 0, + float_round_to_zero = 1, + float_round_down = 2, + float_round_up = 3 +}; + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE floating-point exception flags. +------------------------------------------------------------------------------- +extern signed char float_exception_flags; +enum { + float_flag_inexact = 1, + float_flag_underflow = 2, + float_flag_overflow = 4, + float_flag_divbyzero = 8, + float_flag_invalid = 16 +}; + +ScottB: November 4, 1998 +Changed the enumeration to match the bit order in the FPA11. +*/ + +extern signed char float_exception_flags; +enum { + float_flag_invalid = 1, + float_flag_divbyzero = 2, + float_flag_overflow = 4, + float_flag_underflow = 8, + float_flag_inexact = 16 +}; + +/* +------------------------------------------------------------------------------- +Routine to raise any or all of the software IEC/IEEE floating-point +exception flags. +------------------------------------------------------------------------------- +*/ +void float_raise( signed char ); + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE integer-to-floating-point conversion routines. +------------------------------------------------------------------------------- +*/ +float32 int32_to_float32( signed int ); +float64 int32_to_float64( signed int ); +#ifdef FLOATX80 +floatx80 int32_to_floatx80( signed int ); +#endif + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE single-precision conversion routines. +------------------------------------------------------------------------------- +*/ +signed int float32_to_int32( float32 ); +signed int float32_to_int32_round_to_zero( float32 ); +float64 float32_to_float64( float32 ); +#ifdef FLOATX80 +floatx80 float32_to_floatx80( float32 ); +#endif + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE single-precision operations. +------------------------------------------------------------------------------- +*/ +float32 float32_round_to_int( float32 ); +float32 float32_add( float32, float32 ); +float32 float32_sub( float32, float32 ); +float32 float32_mul( float32, float32 ); +float32 float32_div( float32, float32 ); +float32 float32_rem( float32, float32 ); +float32 float32_sqrt( float32 ); +char float32_eq( float32, float32 ); +char float32_le( float32, float32 ); +char float32_lt( float32, float32 ); +char float32_eq_signaling( float32, float32 ); +char float32_le_quiet( float32, float32 ); +char float32_lt_quiet( float32, float32 ); +char float32_is_signaling_nan( float32 ); + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE double-precision conversion routines. +------------------------------------------------------------------------------- +*/ +signed int float64_to_int32( float64 ); +signed int float64_to_int32_round_to_zero( float64 ); +float32 float64_to_float32( float64 ); +#ifdef FLOATX80 +floatx80 float64_to_floatx80( float64 ); +#endif + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE double-precision operations. +------------------------------------------------------------------------------- +*/ +float64 float64_round_to_int( float64 ); +float64 float64_add( float64, float64 ); +float64 float64_sub( float64, float64 ); +float64 float64_mul( float64, float64 ); +float64 float64_div( float64, float64 ); +float64 float64_rem( float64, float64 ); +float64 float64_sqrt( float64 ); +char float64_eq( float64, float64 ); +char float64_le( float64, float64 ); +char float64_lt( float64, float64 ); +char float64_eq_signaling( float64, float64 ); +char float64_le_quiet( float64, float64 ); +char float64_lt_quiet( float64, float64 ); +char float64_is_signaling_nan( float64 ); + +#ifdef FLOATX80 + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE extended double-precision conversion routines. +------------------------------------------------------------------------------- +*/ +signed int floatx80_to_int32( floatx80 ); +signed int floatx80_to_int32_round_to_zero( floatx80 ); +float32 floatx80_to_float32( floatx80 ); +float64 floatx80_to_float64( floatx80 ); + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE extended double-precision rounding precision. Valid +values are 32, 64, and 80. +------------------------------------------------------------------------------- +*/ +extern signed char floatx80_rounding_precision; + +/* +------------------------------------------------------------------------------- +Software IEC/IEEE extended double-precision operations. +------------------------------------------------------------------------------- +*/ +floatx80 floatx80_round_to_int( floatx80 ); +floatx80 floatx80_add( floatx80, floatx80 ); +floatx80 floatx80_sub( floatx80, floatx80 ); +floatx80 floatx80_mul( floatx80, floatx80 ); +floatx80 floatx80_div( floatx80, floatx80 ); +floatx80 floatx80_rem( floatx80, floatx80 ); +floatx80 floatx80_sqrt( floatx80 ); +char floatx80_eq( floatx80, floatx80 ); +char floatx80_le( floatx80, floatx80 ); +char floatx80_lt( floatx80, floatx80 ); +char floatx80_eq_signaling( floatx80, floatx80 ); +char floatx80_le_quiet( floatx80, floatx80 ); +char floatx80_lt_quiet( floatx80, floatx80 ); +char floatx80_is_signaling_nan( floatx80 ); + +#endif + +#endif diff -Nru a/arch/arm26/vmlinux-armo.lds.in b/arch/arm26/vmlinux-armo.lds.in --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/vmlinux-armo.lds.in Mon Jun 9 23:16:20 2003 @@ -0,0 +1,128 @@ +/* ld script to make ARM Linux kernel + * taken from the i386 version by Russell King + * Written by Martin Mares <mj@atrey.karlin.mff.cuni.cz> + * borrowed from Russels ARM port by Ian Molton + */ + +#include <asm-generic/vmlinux.lds.h> + +OUTPUT_ARCH(arm) +ENTRY(stext) +jiffies = jiffies_64; +SECTIONS +{ + . = TEXTADDR; + .init : { /* Init code and data */ + _stext = .; + __init_begin = .; + _sinittext = .; + *(.init.text) + _einittext = .; + __proc_info_begin = .; + *(.proc.info) + __proc_info_end = .; + __arch_info_begin = .; + *(.arch.info) + __arch_info_end = .; + __tagtable_begin = .; + *(.taglist) + __tagtable_end = .; + *(.init.data) + . = ALIGN(16); + __setup_start = .; + *(.init.setup) + __setup_end = .; + __early_begin = .; + *(__early_param) + __early_end = .; + __start___param = .; + *(__param) + __stop___param = .; + __initcall_start = .; + *(.initcall1.init) + *(.initcall2.init) + *(.initcall3.init) + *(.initcall4.init) + *(.initcall5.init) + *(.initcall6.init) + *(.initcall7.init) + __initcall_end = .; + __con_initcall_start = .; + *(.con_initcall.init) + __con_initcall_end = .; + . = ALIGN(32); + __initramfs_start = .; + usr/built-in.o(.init.ramfs) + __initramfs_end = .; + . = ALIGN(32768); + __init_end = .; + } + + /DISCARD/ : { /* Exit code and data */ + *(.exit.text) + *(.exit.data) + *(.exitcall.exit) + } + + .text : { /* Real text segment */ + _text = .; /* Text and read-only data */ + *(.text) + *(.fixup) + *(.gnu.warning) + *(.rodata) + *(.rodata.*) + *(.glue_7) + *(.glue_7t) + *(.got) /* Global offset table */ + + _etext = .; /* End of text section */ + } + + . = ALIGN(16); + __ex_table : { /* Exception table */ + __start___ex_table = .; + *(__ex_table) + __stop___ex_table = .; + } + + RODATA + + . = ALIGN(8192); + + .data : { + /* + * first, the init task union, aligned + * to an 8192 byte boundary. + */ + *(.init.task) + + /* + * The cacheline aligned data + */ + . = ALIGN(32); + *(.data.cacheline_aligned) + + /* + * and the usual data section + */ + *(.data) + CONSTRUCTORS + + _edata = .; + } + + .bss : { + __bss_start = .; /* BSS */ + *(.bss) + *(COMMON) + _end = . ; + } + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } +} diff -Nru a/arch/arm26/vmlinux.lds.S b/arch/arm26/vmlinux.lds.S --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/arm26/vmlinux.lds.S Mon Jun 9 23:16:20 2003 @@ -0,0 +1,12 @@ +#include <linux/config.h> + +#ifdef CONFIG_ROM_KERNEL + +#include "vmlinux-armo-rom.lds.in" + +#else + +#include "vmlinux-armo.lds.in" + +#endif + diff -Nru a/arch/cris/drivers/ethernet.c b/arch/cris/drivers/ethernet.c --- a/arch/cris/drivers/ethernet.c Mon Jun 9 23:16:11 2003 +++ b/arch/cris/drivers/ethernet.c Mon Jun 9 23:16:11 2003 @@ -292,37 +292,19 @@ */ static int __init -etrax_ethernet_init(struct net_device *dev) +etrax_ethernet_init(void) { - int i; + struct net_device *dev; + int i, err; int anOffset = 0; printk("ETRAX 100LX 10/100MBit ethernet v2.0 (c) 2000-2001 Axis Communications AB\n"); - dev->base_addr = (unsigned int)R_NETWORK_SA_0; /* just to have something to show */ - - printk("%s initialized\n", dev->name); - - /* make Linux aware of the new hardware */ - - if (!dev) { - printk(KERN_WARNING "%s: dev == NULL. Should this happen?\n", - cardname); - dev = init_etherdev(dev, sizeof(struct net_local)); - if (!dev) - panic("init_etherdev failed\n"); - } - - /* setup generic handlers and stuff in the dev struct */ - - ether_setup(dev); - - /* make room for the local structure containing stats etc */ - - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (dev->priv == NULL) + dev = alloc_etherdev(sizeof(struct net_local)); + if (!dev) return -ENOMEM; - memset(dev->priv, 0, sizeof(struct net_local)); + + dev->base_addr = (unsigned int)R_NETWORK_SA_0; /* just to have something to show */ /* now setup our etrax specific stuff */ @@ -340,10 +322,6 @@ dev->do_ioctl = e100_ioctl; dev->tx_timeout = e100_tx_timeout; - /* set the default MAC address */ - - e100_set_mac_address(dev, &default_mac); - /* Initialise the list of Etrax DMA-descriptors */ /* Initialise receive descriptors */ @@ -371,6 +349,16 @@ myLastRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; myPrevRxDesc = &RxDescList[NBR_OF_RX_DESC - 1]; + err = register_netdev(dev); + if (err) { + kfree(dev); + return err; + } + + /* set the default MAC address */ + + e100_set_mac_address(dev, &default_mac); + /* Initialize speed indicator stuff. */ current_speed = 10; @@ -1349,19 +1337,10 @@ } } -static struct net_device dev_etrax_ethernet; /* only got one */ - static int etrax_init_module(void) { - struct net_device *d = &dev_etrax_ethernet; - - d->init = etrax_ethernet_init; - - if (register_netdev(d) == 0) - return 0; - else - return -ENODEV; + return etrax_ethernet_init(); } module_init(etrax_init_module); diff -Nru a/arch/cris/drivers/lpslave/e100lpslavenet.c b/arch/cris/drivers/lpslave/e100lpslavenet.c --- a/arch/cris/drivers/lpslave/e100lpslavenet.c Mon Jun 9 23:16:10 2003 +++ b/arch/cris/drivers/lpslave/e100lpslavenet.c Mon Jun 9 23:16:10 2003 @@ -162,37 +162,19 @@ * (detachable devices only). */ static int __init -etrax_ethernet_lpslave_init(struct net_device *dev) +etrax_ethernet_lpslave_init(void) { - int i; + struct net_device *dev; + int i, err; int anOffset = 0; printk("Etrax/100 lpslave ethernet driver v0.3, (c) 1999 Axis Communications AB\n"); - dev->base_addr = 2; - - printk("%s initialized\n", dev->name); - - /* make Linux aware of the new hardware */ - - if (!dev) { - printk(KERN_WARNING "%s: dev == NULL. Should this happen?\n", - cardname); - dev = init_etherdev(dev, sizeof(struct net_local)); - if (!dev) - panic("init_etherdev failed\n"); - } - - /* setup generic handlers and stuff in the dev struct */ - - ether_setup(dev); - - /* make room for the local structure containing stats etc */ - - dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); - if (dev->priv == NULL) + dev = alloc_etherdev(sizeof(struct net_lock)); + if (!dev) return -ENOMEM; - memset(dev->priv, 0, sizeof(struct net_local)); + + dev->base_addr = 2; /* now setup our etrax specific stuff */ @@ -242,7 +224,11 @@ TxDescList[0].buf = virt_to_phys(&host_command); TxDescList[0].next = virt_to_phys(&TxDescList[1]); - return 0; + err = register_netdev(dev); + if (err) + kfree(dev); + + return err; } /* set MAC address of the interface. called from the core after a @@ -1017,19 +1003,10 @@ } #endif /* ETHDEBUG */ -static struct net_device dev_etrax_slave_ethernet; - static int etrax_init_module(void) { - struct net_device *d = &dev_etrax_slave_ethernet; - - d->init = etrax_ethernet_lpslave_init; - - if(register_netdev(d) == 0) - return 0; - else - return -ENODEV; + return etrax_ethernet_lpslave_init(); } module_init(etrax_init_module); diff -Nru a/arch/cris/drivers/serial.c b/arch/cris/drivers/serial.c --- a/arch/cris/drivers/serial.c Mon Jun 9 23:16:15 2003 +++ b/arch/cris/drivers/serial.c Mon Jun 9 23:16:15 2003 @@ -335,13 +335,12 @@ static DECLARE_TASK_QUEUE(tq_serial); -struct tty_driver serial_driver, callout_driver; +struct tty_driver serial_driver; static int serial_refcount; /* serial subtype definitions */ #ifndef SERIAL_TYPE_NORMAL #define SERIAL_TYPE_NORMAL 1 -#define SERIAL_TYPE_CALLOUT 2 #endif /* number of characters left in xmit buffer before we ask for more */ @@ -3017,8 +3016,6 @@ */ if (info->flags & ASYNC_NORMAL_ACTIVE) info->normal_termios = *tty->termios; - if (info->flags & ASYNC_CALLOUT_ACTIVE) - info->callout_termios = *tty->termios; /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. @@ -3063,8 +3060,7 @@ } wake_up_interruptible(&info->open_wait); } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| - ASYNC_CLOSING); + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); restore_flags(flags); @@ -3128,7 +3124,7 @@ shutdown(info); info->event = 0; info->count = 0; - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->flags &= ~ASYNC_NORMAL_ACTIVE; info->tty = 0; wake_up_interruptible(&info->open_wait); } @@ -3166,44 +3162,18 @@ } /* - * If this is a callout device, then just make sure the normal - * device isn't being used. - */ - if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) { - if (info->flags & ASYNC_NORMAL_ACTIVE) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_SESSION_LOCKOUT) && - (info->session != current->session)) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_PGRP_LOCKOUT) && - (info->pgrp != current->pgrp)) - return -EBUSY; - info->flags |= ASYNC_CALLOUT_ACTIVE; - return 0; - } - - /* * If non-blocking mode is set, or the port is not enabled, * then make the check up front and then exit. */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { - if (info->flags & ASYNC_CALLOUT_ACTIVE) - return -EBUSY; info->flags |= ASYNC_NORMAL_ACTIVE; return 0; } - if (info->flags & ASYNC_CALLOUT_ACTIVE) { - if (info->normal_termios.c_cflag & CLOCAL) - do_clocal = 1; - } else { - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - } - + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + /* * Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). While we are in @@ -3228,11 +3198,9 @@ while (1) { save_flags(flags); cli(); - if (!(info->flags & ASYNC_CALLOUT_ACTIVE)) { - /* assert RTS and DTR */ - e100_rts(info, 1); - e100_dtr(info, 1); - } + /* assert RTS and DTR */ + e100_rts(info, 1); + e100_dtr(info, 1); restore_flags(flags); set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || @@ -3247,8 +3215,7 @@ #endif break; } - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - !(info->flags & ASYNC_CLOSING) && do_clocal) + if (!(info->flags & ASYNC_CLOSING) && do_clocal) /* && (do_clocal || DCD_IS_ASSERTED) */ break; if (signal_pending(current)) { @@ -3358,16 +3325,10 @@ } if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver->subtype == SERIAL_TYPE_NORMAL) - *tty->termios = info->normal_termios; - else - *tty->termios = info->callout_termios; + *tty->termios = info->normal_termios; change_speed(info); } - info->session = current->session; - info->pgrp = current->pgrp; - #ifdef SERIAL_DEBUG_OPEN printk("rs_open ttyS%d successful...\n", info->line); #endif @@ -3538,23 +3499,8 @@ serial_driver.read_proc = rs_read_proc; #endif - /* - * The callout device is just like normal device except for - * major number and the subtype code. - */ - callout_driver = serial_driver; - callout_driver.name = "cua"; - callout_driver.major = TTYAUX_MAJOR; - callout_driver.subtype = SERIAL_TYPE_CALLOUT; -#if (LINUX_VERSION_CODE >= 131343) - callout_driver.read_proc = 0; - callout_driver.proc_entry = 0; -#endif - if (tty_register_driver(&serial_driver)) panic("Couldn't register serial driver\n"); - if (tty_register_driver(&callout_driver)) - panic("Couldn't register callout driver\n"); /* do some initializing for the separate ports */ @@ -3574,7 +3520,6 @@ info->blocked_open = 0; info->tqueue.routine = do_softint; info->tqueue.data = info; - info->callout_termios = callout_driver.init_termios; info->normal_termios = serial_driver.init_termios; init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); diff -Nru a/arch/cris/drivers/serial.h b/arch/cris/drivers/serial.h --- a/arch/cris/drivers/serial.h Mon Jun 9 23:16:18 2003 +++ b/arch/cris/drivers/serial.h Mon Jun 9 23:16:18 2003 @@ -78,8 +78,6 @@ int type; /* PORT_ETRAX */ int count; /* # of fd on device */ int blocked_open; /* # of blocked opens */ - long session; /* Session of opening process */ - long pgrp; /* pgrp of opening process */ struct circ_buf xmit; struct circ_buf recv; unsigned char *flag_buf; @@ -87,7 +85,6 @@ struct tq_struct tqueue; struct async_icount icount; /* error-statistics etc.*/ struct termios normal_termios; - struct termios callout_termios; #ifdef DECLARE_WAITQUEUE wait_queue_head_t open_wait; wait_queue_head_t close_wait; diff -Nru a/arch/cris/lib/Makefile b/arch/cris/lib/Makefile --- a/arch/cris/lib/Makefile Mon Jun 9 23:16:15 2003 +++ b/arch/cris/lib/Makefile Mon Jun 9 23:16:15 2003 @@ -2,8 +2,6 @@ # Makefile for Etrax-specific library files.. # -L_TARGET = lib.a - EXTRA_AFLAGS := -traditional -obj-y = checksum.o checksumcopy.o string.o usercopy.o memset.o csumcpfruser.o +lib-y = checksum.o checksumcopy.o string.o usercopy.o memset.o csumcpfruser.o diff -Nru a/arch/h8300/lib/Makefile b/arch/h8300/lib/Makefile --- a/arch/h8300/lib/Makefile Mon Jun 9 23:16:10 2003 +++ b/arch/h8300/lib/Makefile Mon Jun 9 23:16:10 2003 @@ -5,5 +5,4 @@ .S.o: $(CC) $(AFLAGS) -D__ASSEMBLY__ -c $< -o $@ -L_TARGET = lib.a -obj-y = ashrdi3.o checksum.o memcpy.o memset.o abs.o +lib-y = ashrdi3.o checksum.o memcpy.o memset.o abs.o diff -Nru a/arch/i386/Kconfig b/arch/i386/Kconfig --- a/arch/i386/Kconfig Mon Jun 9 23:16:07 2003 +++ b/arch/i386/Kconfig Mon Jun 9 23:16:07 2003 @@ -1135,7 +1135,7 @@ source "drivers/pcmcia/Kconfig" -source "drivers/hotplug/Kconfig" +source "drivers/pci/hotplug/Kconfig" endmenu diff -Nru a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile --- a/arch/i386/kernel/Makefile Mon Jun 9 23:16:08 2003 +++ b/arch/i386/kernel/Makefile Mon Jun 9 23:16:08 2003 @@ -26,6 +26,7 @@ obj-$(CONFIG_X86_IO_APIC) += io_apic.o obj-$(CONFIG_SOFTWARE_SUSPEND) += suspend.o suspend_asm.o obj-$(CONFIG_X86_NUMAQ) += numaq.o +obj-$(CONFIG_X86_SUMMIT) += summit.o obj-$(CONFIG_EDD) += edd.o obj-$(CONFIG_MODULES) += module.o obj-y += sysenter.o vsyscall.o diff -Nru a/arch/i386/kernel/cpu/cpufreq/acpi.c b/arch/i386/kernel/cpu/cpufreq/acpi.c --- a/arch/i386/kernel/cpu/cpufreq/acpi.c Mon Jun 9 23:16:07 2003 +++ b/arch/i386/kernel/cpu/cpufreq/acpi.c Mon Jun 9 23:16:07 2003 @@ -553,8 +553,9 @@ { unsigned int i; unsigned int cpu = policy->cpu; - struct acpi_processor *pr = NULL; + struct acpi_processor *pr = NULL; struct acpi_processor_performance *perf = &performance[policy->cpu]; + struct acpi_device *device; unsigned int result = 0; ACPI_FUNCTION_TRACE("acpi_cpufreq_cpu_init"); @@ -596,6 +597,17 @@ acpi_cpufreq_add_file(pr); + if (acpi_bus_get_device(pr->handle, &device)) + device = NULL; + + printk(KERN_INFO "cpufreq: %s - ACPI performance management activated.\n", + device ? acpi_device_bid(device) : "CPU??"); + for (i = 0; i < pr->performance->state_count; i++) + printk(KERN_INFO "cpufreq: %cP%d: %d MHz, %d mW, %d uS\n", + (i == pr->performance->state?'*':' '), i, + (u32) pr->performance->states[i].core_frequency, + (u32) pr->performance->states[i].power, + (u32) pr->performance->states[i].transition_latency); return_VALUE(result); } @@ -658,16 +670,21 @@ /* test it on one CPU */ for (i=0; i<NR_CPUS; i++) { - if (cpu_online(i)) + if (!cpu_online(i)) continue; pr = performance[i].pr; if (pr && pr->flags.performance) goto found_capable_cpu; } result = -ENODEV; - goto err; + goto err0; found_capable_cpu: + + result = cpufreq_register_driver(&acpi_cpufreq_driver); + if (result) + goto err0; + perf = pr->performance; current_state = perf->state; @@ -676,7 +693,7 @@ if (result) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Disabled P-States due to failure while switching.\n")); result = -ENODEV; - goto err; + goto err1; } } @@ -684,7 +701,7 @@ if (result) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Disabled P-States due to failure while switching.\n")); result = -ENODEV; - goto err; + goto err1; } if (current_state != 0) { @@ -692,18 +709,17 @@ if (result) { ACPI_DEBUG_PRINT((ACPI_DB_ERROR, "Disabled P-States due to failure while switching.\n")); result = -ENODEV; - goto err; + goto err1; } } - result = cpufreq_register_driver(&acpi_cpufreq_driver); - if (result) - goto err; - return_VALUE(0); /* error handling */ - err: + err1: + cpufreq_unregister_driver(&acpi_cpufreq_driver); + + err0: /* unregister struct acpi_processor_performance performance */ for (i=0; i<NR_CPUS; i++) { if (performance[i].pr) { @@ -713,6 +729,8 @@ } } kfree(performance); + + printk(KERN_INFO "cpufreq: No CPUs supporting ACPI performance management found.\n"); return_VALUE(result); } diff -Nru a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c --- a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c Mon Jun 9 23:16:12 2003 +++ b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c Mon Jun 9 23:16:12 2003 @@ -186,7 +186,7 @@ **/ static __init struct pci_dev *gx_detect_chipset(void) { - struct pci_dev *gx_pci; + struct pci_dev *gx_pci = NULL; /* check if CPU is a MediaGX or a Geode. */ if ((current_cpu_data.x86_vendor != X86_VENDOR_NSC) && @@ -196,7 +196,7 @@ } /* detect which companion chip is used */ - pci_for_each_dev(gx_pci) { + while ((gx_pci = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, gx_pci)) != NULL) { if ((pci_match_device (gx_chipset_tbl, gx_pci)) != NULL) { return gx_pci; } diff -Nru a/arch/i386/kernel/cpu/cpufreq/longrun.c b/arch/i386/kernel/cpu/cpufreq/longrun.c --- a/arch/i386/kernel/cpu/cpufreq/longrun.c Mon Jun 9 23:16:15 2003 +++ b/arch/i386/kernel/cpu/cpufreq/longrun.c Mon Jun 9 23:16:15 2003 @@ -224,7 +224,6 @@ static int longrun_cpu_init(struct cpufreq_policy *policy) { int result = 0; - struct cpuinfo_x86 *c = cpu_data; /* capability check */ if (policy->cpu != 0) diff -Nru a/arch/i386/kernel/cpu/cpufreq/powernow-k6.c b/arch/i386/kernel/cpu/cpufreq/powernow-k6.c --- a/arch/i386/kernel/cpu/cpufreq/powernow-k6.c Mon Jun 9 23:16:07 2003 +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k6.c Mon Jun 9 23:16:07 2003 @@ -142,7 +142,6 @@ static int powernow_k6_cpu_init(struct cpufreq_policy *policy) { - struct cpuinfo_x86 *c = cpu_data; unsigned int i; if (policy->cpu != 0) diff -Nru a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c --- a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c Mon Jun 9 23:16:05 2003 +++ b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c Mon Jun 9 23:16:05 2003 @@ -208,13 +208,38 @@ } +static void change_FID(int fid) +{ + union msr_fidvidctl fidvidctl; + + if (fidvidctl.bits.FID != fid) { + rdmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val); + fidvidctl.bits.SGTC = latency; + fidvidctl.bits.FID = fid; + fidvidctl.bits.FIDC = 1; + wrmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val); + } +} + + +static void change_VID(int vid) +{ + union msr_fidvidctl fidvidctl; + + if (fidvidctl.bits.VID != vid) { + rdmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val); + fidvidctl.bits.VID = vid; + fidvidctl.bits.VIDC = 1; + wrmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val); + } +} + + static void change_speed (unsigned int index) { u8 fid, vid; struct cpufreq_freqs freqs; union msr_fidvidstatus fidvidstatus; - union msr_fidvidctl fidvidctl; - /* fid are the lower 8 bits of the index we stored into * the cpufreq frequency table in powernow_decode_bios, @@ -228,7 +253,6 @@ rdmsrl (MSR_K7_FID_VID_STATUS, fidvidstatus.val); freqs.old = fsb * fid_codes[fidvidstatus.bits.CFID] * 100; - freqs.new = powernow_table[index].frequency; cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE); @@ -238,22 +262,16 @@ if (have_a0 == 1) /* A0 errata 5 */ __asm__("\tcli\n"); - /* First change the frequency. */ - if (fidvidctl.bits.FID != fid) { - rdmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val); - fidvidctl.bits.SGTC = latency; /* Stop grant timeout counter */ - fidvidctl.bits.FID = fid; - fidvidctl.bits.FIDC = 1; - wrmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val); - } - - /* Now change voltage. */ - if (fidvidctl.bits.VID != vid) { - rdmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val); - fidvidctl.bits.VID = vid; - fidvidctl.bits.VIDC = 1; - wrmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val); + if (freqs.old > freqs.new) { + /* Going down, so change FID first */ + change_FID(fid); + change_VID(vid); + } else { + /* Going up, so change VID first */ + change_VID(fid); + change_FID(vid); } + if (have_a0 == 1) __asm__("\tsti\n"); diff -Nru a/arch/i386/kernel/dmi_scan.c b/arch/i386/kernel/dmi_scan.c --- a/arch/i386/kernel/dmi_scan.c Mon Jun 9 23:16:10 2003 +++ b/arch/i386/kernel/dmi_scan.c Mon Jun 9 23:16:10 2003 @@ -12,6 +12,8 @@ #include <linux/bootmem.h> unsigned long dmi_broken; +EXPORT_SYMBOL(dmi_broken); + int is_sony_vaio_laptop; int is_unsafe_smbus; diff -Nru a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S --- a/arch/i386/kernel/entry.S Mon Jun 9 23:16:08 2003 +++ b/arch/i386/kernel/entry.S Mon Jun 9 23:16:08 2003 @@ -508,6 +508,15 @@ ENTRY(nmi) cmpl $sysenter_entry,(%esp) je nmi_stack_fixup + pushl %eax + movl %esp,%eax + /* Do not access memory above the end of our stack page, + * it might not exist. + */ + andl $0x1fff,%eax + cmpl $0x1fec,%eax + popl %eax + jae nmi_stack_correct cmpl $sysenter_entry,12(%esp) je nmi_debug_stack_check nmi_stack_correct: diff -Nru a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c --- a/arch/i386/kernel/io_apic.c Mon Jun 9 23:16:09 2003 +++ b/arch/i386/kernel/io_apic.c Mon Jun 9 23:16:09 2003 @@ -352,9 +352,7 @@ unsigned long allowed_mask; unsigned int new_cpu; - if (irqbalance_disabled == IRQBALANCE_CHECK_ARCH && NO_BALANCE_IRQ) - return; - else if (irqbalance_disabled) + if (irqbalance_disabled) return; allowed_mask = cpu_online_map & irq_affinity[irq]; @@ -614,6 +612,9 @@ struct cpuinfo_x86 *c; c = &boot_cpu_data; + /* When not overwritten by the command line ask subarchitecture. */ + if (irqbalance_disabled == IRQBALANCE_CHECK_ARCH) + irqbalance_disabled = NO_BALANCE_IRQ; if (irqbalance_disabled) return 0; diff -Nru a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c --- a/arch/i386/kernel/irq.c Mon Jun 9 23:16:06 2003 +++ b/arch/i386/kernel/irq.c Mon Jun 9 23:16:06 2003 @@ -66,8 +66,12 @@ /* * Controller mappings for all interrupt sources: */ -irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = - { [0 ... NR_IRQS-1] = { 0, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}}; +irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { + [0 ... NR_IRQS-1] = { + .handler = &no_irq_type, + .lock = SPIN_LOCK_UNLOCKED + } +}; static void register_irq_proc (unsigned int irq); @@ -209,7 +213,6 @@ { int status = 1; /* Force the "do bottom halves" bit */ int retval = 0; - struct irqaction *first_action = action; if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); @@ -222,30 +225,88 @@ if (status & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); local_irq_disable(); - if (retval != 1) { - static int count = 100; - if (count) { - count--; - if (retval) { - printk("irq event %d: bogus retval mask %x\n", - irq, retval); - } else { - printk("irq %d: nobody cared!\n", irq); - } - dump_stack(); - printk("handlers:\n"); - action = first_action; - do { - printk("[<%p>]", action->handler); - print_symbol(" (%s)", - (unsigned long)action->handler); - printk("\n"); - action = action->next; - } while (action); - } + return retval; +} + +static void __report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret) +{ + struct irqaction *action; + + if (action_ret != IRQ_HANDLED && action_ret != IRQ_NONE) { + printk(KERN_ERR "irq event %d: bogus return value %x\n", + irq, action_ret); + } else { + printk(KERN_ERR "irq %d: nobody cared!\n", irq); } + dump_stack(); + printk(KERN_ERR "handlers:\n"); + action = desc->action; + do { + printk(KERN_ERR "[<%p>]", action->handler); + print_symbol(" (%s)", + (unsigned long)action->handler); + printk("\n"); + action = action->next; + } while (action); +} + +static void report_bad_irq(int irq, irq_desc_t *desc, irqreturn_t action_ret) +{ + static int count = 100; - return status; + if (count) { + count--; + __report_bad_irq(irq, desc, action_ret); + } +} + +static int noirqdebug; + +static int __init noirqdebug_setup(char *str) +{ + noirqdebug = 1; + printk("IRQ lockup detection disabled\n"); + return 1; +} + +__setup("noirqdebug", noirqdebug_setup); + +/* + * If 99,900 of the previous 100,000 interrupts have not been handled then + * assume that the IRQ is stuck in some manner. Drop a diagnostic and try to + * turn the IRQ off. + * + * (The other 100-of-100,000 interrupts may have been a correctly-functioning + * device sharing an IRQ with the failing one) + * + * Called under desc->lock + */ +static void note_interrupt(int irq, irq_desc_t *desc, irqreturn_t action_ret) +{ + if (action_ret != IRQ_HANDLED) { + desc->irqs_unhandled++; + if (action_ret != IRQ_NONE) + report_bad_irq(irq, desc, action_ret); + } + + desc->irq_count++; + if (desc->irq_count < 100000) + return; + + desc->irq_count = 0; + if (desc->irqs_unhandled > 99900) { + /* + * The interrupt is stuck + */ + __report_bad_irq(irq, desc, action_ret); + /* + * Now kill the IRQ + */ + printk(KERN_EMERG "Disabling IRQ #%d\n", irq); + desc->status |= IRQ_DISABLED; + desc->handler->disable(irq); + } + desc->irqs_unhandled = 0; } /* @@ -418,10 +479,13 @@ * SMP environment. */ for (;;) { + irqreturn_t action_ret; + spin_unlock(&desc->lock); - handle_IRQ_event(irq, ®s, action); + action_ret = handle_IRQ_event(irq, ®s, action); spin_lock(&desc->lock); - + if (!noirqdebug) + note_interrupt(irq, desc, action_ret); if (likely(!(desc->status & IRQ_PENDING))) break; desc->status &= ~IRQ_PENDING; diff -Nru a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c --- a/arch/i386/kernel/mpparse.c Mon Jun 9 23:16:09 2003 +++ b/arch/i386/kernel/mpparse.c Mon Jun 9 23:16:09 2003 @@ -73,9 +73,6 @@ /* Bitmask of physically existing CPUs */ unsigned long phys_cpu_present_map; -#ifndef CONFIG_X86_GENERICARCH -int x86_summit = 0; -#endif u8 bios_cpu_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID }; /* diff -Nru a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c --- a/arch/i386/kernel/setup.c Mon Jun 9 23:16:11 2003 +++ b/arch/i386/kernel/setup.c Mon Jun 9 23:16:11 2003 @@ -35,6 +35,7 @@ #include <linux/console.h> #include <linux/root_dev.h> #include <linux/highmem.h> +#include <linux/module.h> #include <video/edid.h> #include <asm/e820.h> #include <asm/mpspec.h> @@ -58,6 +59,7 @@ struct cpuinfo_x86 boot_cpu_data = { 0, 0, 0, 0, -1, 1, 0, 0, -1 }; unsigned long mmu_cr4_features; +EXPORT_SYMBOL_GPL(mmu_cr4_features); int acpi_disabled __initdata = 0; @@ -977,6 +979,9 @@ #ifdef CONFIG_X86_LOCAL_APIC if (smp_found_config) get_smp_config(); +#endif +#ifdef CONFIG_X86_SUMMIT + setup_summit(); #endif register_memory(max_low_pfn); diff -Nru a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c --- a/arch/i386/kernel/smp.c Mon Jun 9 23:16:07 2003 +++ b/arch/i386/kernel/smp.c Mon Jun 9 23:16:07 2003 @@ -461,17 +461,6 @@ } /* - * this function sends a reschedule IPI to all (other) CPUs. - * This should only be used if some 'global' task became runnable, - * such as a RT task, that must be handled now. The first CPU - * that manages to grab the task will run it. - */ -void smp_send_reschedule_all(void) -{ - send_IPI_allbutself(RESCHEDULE_VECTOR); -} - -/* * Structure and data for smp_call_function(). This is designed to minimise * static memory requirements. It also looks cleaner. */ diff -Nru a/arch/i386/kernel/summit.c b/arch/i386/kernel/summit.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/i386/kernel/summit.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,162 @@ +/* + * arch/i386/kernel/summit.c - IBM Summit-Specific Code + * + * Written By: Matthew Dobson, IBM Corporation + * + * Copyright (c) 2003 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Send feedback to <colpatch@us.ibm.com> + * + */ + +#include <linux/mm.h> +#include <linux/init.h> +#include <asm/io.h> +#include <mach_mpparse.h> + +static void __init setup_pci_node_map_for_wpeg(int wpeg_num, struct rio_table_hdr *rth, + struct scal_detail **scal_nodes, struct rio_detail **rio_nodes){ + int twst_num = 0, node = 0, first_bus = 0; + int i, bus, num_busses; + + for(i = 0; i < rth->num_rio_dev; i++){ + if (rio_nodes[i]->node_id == rio_nodes[wpeg_num]->owner_id){ + twst_num = rio_nodes[i]->owner_id; + break; + } + } + if (i == rth->num_rio_dev){ + printk("%s: Couldn't find owner Cyclone for Winnipeg!\n", __FUNCTION__); + return; + } + + for(i = 0; i < rth->num_scal_dev; i++){ + if (scal_nodes[i]->node_id == twst_num){ + node = scal_nodes[i]->node_id; + break; + } + } + if (i == rth->num_scal_dev){ + printk("%s: Couldn't find owner Twister for Cyclone!\n", __FUNCTION__); + return; + } + + switch (rio_nodes[wpeg_num]->type){ + case CompatWPEG: + /* The Compatability Winnipeg controls the legacy busses + (busses 0 & 1), the 66MHz PCI bus [2 slots] (bus 2), + and the "extra" busses in case a PCI-PCI bridge card is + used in either slot (busses 3 & 4): total 5 busses. */ + num_busses = 5; + /* The BIOS numbers the busses starting at 1, and in a + slightly wierd manner. You'll have to trust that + the math used below to determine the number of the + first bus works. */ + first_bus = (rio_nodes[wpeg_num]->first_slot - 1) * 2; + break; + case AltWPEG: + /* The Alternate/Secondary Winnipeg controls the 1st 133MHz + bus [1 slot] & its "extra" bus (busses 0 & 1), the 2nd + 133MHz bus [1 slot] & its "extra" bus (busses 2 & 3), the + 100MHz bus [2 slots] (bus 4), and the "extra" busses for + the 2 100MHz slots (busses 5 & 6): total 7 busses. */ + num_busses = 7; + first_bus = (rio_nodes[wpeg_num]->first_slot * 2) - 1; + break; + case LookOutAWPEG: + case LookOutBWPEG: + printk("%s: LookOut Winnipegs not supported yet!\n", __FUNCTION__); + return; + default: + printk("%s: Unsupported Winnipeg type!\n", __FUNCTION__); + return; + } + + for(bus = first_bus; bus < first_bus + num_busses; bus++) + mp_bus_id_to_node[bus] = node; +} + +static void __init build_detail_arrays(struct rio_table_hdr *rth, + struct scal_detail **sd, struct rio_detail **rd){ + unsigned long ptr; + int i, scal_detail_size, rio_detail_size; + + switch (rth->version){ + default: + printk("%s: Bad Rio Grande Table Version: %d\n", __FUNCTION__, rth->version); + /* Fall through to default to version 2 spec */ + case 2: + scal_detail_size = 11; + rio_detail_size = 13; + break; + case 3: + scal_detail_size = 12; + rio_detail_size = 15; + break; + } + + ptr = (unsigned long)rth + 3; + for(i = 0; i < rth->num_scal_dev; i++) + sd[i] = (struct scal_detail *)(ptr + (scal_detail_size * i)); + + ptr += scal_detail_size * rth->num_scal_dev; + for(i = 0; i < rth->num_rio_dev; i++) + rd[i] = (struct rio_detail *)(ptr + (rio_detail_size * i)); +} + +void __init setup_summit(void) +{ + struct rio_table_hdr *rio_table_hdr = NULL; + struct scal_detail *scal_devs[MAX_NUMNODES]; + struct rio_detail *rio_devs[MAX_NUMNODES*2]; + unsigned long ptr; + unsigned short offset; + int i; + + memset(mp_bus_id_to_node, -1, sizeof(mp_bus_id_to_node)); + + /* The pointer to the EBDA is stored in the word @ phys 0x40E(40:0E) */ + ptr = *(unsigned short *)phys_to_virt(0x40Eul); + ptr = (unsigned long)phys_to_virt(ptr << 4); + + offset = 0x180; + while (offset){ + /* The block id is stored in the 2nd word */ + if (*((unsigned short *)(ptr + offset + 2)) == 0x4752){ + /* set the pointer past the offset & block id */ + rio_table_hdr = (struct rio_table_hdr *)(ptr + offset + 4); + break; + } + /* The next offset is stored in the 1st word. 0 means no more */ + offset = *((unsigned short *)(ptr + offset)); + } + if (!rio_table_hdr){ + printk("%s: Unable to locate Rio Grande Table in EBDA - bailing!\n", __FUNCTION__); + return; + } + + /* Deal with the ugly version 2/3 pointer arithmetic */ + build_detail_arrays(rio_table_hdr, scal_devs, rio_devs); + + for(i = 0; i < rio_table_hdr->num_rio_dev; i++) + if (is_WPEG(rio_devs[i]->type)) + /* It's a Winnipeg, it's got PCI Busses */ + setup_pci_node_map_for_wpeg(i, rio_table_hdr, scal_devs, rio_devs); +} diff -Nru a/arch/i386/kernel/suspend.c b/arch/i386/kernel/suspend.c --- a/arch/i386/kernel/suspend.c Mon Jun 9 23:16:16 2003 +++ b/arch/i386/kernel/suspend.c Mon Jun 9 23:16:16 2003 @@ -114,7 +114,7 @@ cpu_gdt_table[cpu][GDT_ENTRY_TSS].b &= 0xfffffdff; load_TR_desc(); /* This does ltr */ - load_LDT(¤t->mm->context); /* This does lldt */ + load_LDT(¤t->active_mm->context); /* This does lldt */ /* * Now maybe reload the debug registers diff -Nru a/arch/i386/lib/Makefile b/arch/i386/lib/Makefile --- a/arch/i386/lib/Makefile Mon Jun 9 23:16:06 2003 +++ b/arch/i386/lib/Makefile Mon Jun 9 23:16:06 2003 @@ -2,12 +2,11 @@ # Makefile for i386-specific library files.. # -L_TARGET = lib.a -obj-y = checksum.o delay.o \ +lib-y = checksum.o delay.o \ usercopy.o getuser.o \ memcpy.o strstr.o -obj-$(CONFIG_X86_USE_3DNOW) += mmx.o -obj-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o -obj-$(CONFIG_DEBUG_IOVIRT) += iodebug.o +lib-$(CONFIG_X86_USE_3DNOW) += mmx.o +lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o +lib-$(CONFIG_DEBUG_IOVIRT) += iodebug.o diff -Nru a/arch/i386/mach-generic/default.c b/arch/i386/mach-generic/default.c --- a/arch/i386/mach-generic/default.c Mon Jun 9 23:16:06 2003 +++ b/arch/i386/mach-generic/default.c Mon Jun 9 23:16:06 2003 @@ -2,6 +2,7 @@ * Default generic APIC driver. This handles upto 8 CPUs. */ #define APIC_DEFINITION 1 +#include <asm/mach-default/mach_apicdef.h> #include <asm/genapic.h> #include <asm/fixmap.h> #include <asm/apicdef.h> @@ -10,7 +11,6 @@ #include <linux/smp.h> #include <linux/init.h> #include <asm/mach-default/mach_apic.h> -#include <asm/mach-default/mach_apicdef.h> #include <asm/mach-default/mach_ipi.h> #include <asm/mach-default/mach_mpparse.h> diff -Nru a/arch/i386/mach-visws/visws_apic.c b/arch/i386/mach-visws/visws_apic.c --- a/arch/i386/mach-visws/visws_apic.c Mon Jun 9 23:16:06 2003 +++ b/arch/i386/mach-visws/visws_apic.c Mon Jun 9 23:16:06 2003 @@ -196,7 +196,7 @@ * enable_irq gets the right irq. This 'master' irq is never directly * manipulated by any driver. */ -static void piix4_master_intr(int irq, void *dev_id, struct pt_regs * regs) +static irqreturn_t piix4_master_intr(int irq, void *dev_id, struct pt_regs * regs) { int realirq; irq_desc_t *desc; @@ -254,11 +254,11 @@ if (!(desc->status & IRQ_DISABLED)) enable_8259A_irq(realirq); - return; + return IRQ_HANDLED; out_unlock: spin_unlock_irqrestore(&i8259A_lock, flags); - return; + return IRQ_NONE; } static struct irqaction master_action = { diff -Nru a/arch/i386/pci/i386.c b/arch/i386/pci/i386.c --- a/arch/i386/pci/i386.c Mon Jun 9 23:16:08 2003 +++ b/arch/i386/pci/i386.c Mon Jun 9 23:16:08 2003 @@ -121,12 +121,12 @@ static void __init pcibios_allocate_resources(int pass) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; int idx, disabled; u16 command; struct resource *r, *pr; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { pci_read_config_word(dev, PCI_COMMAND, &command); for(idx = 0; idx < 6; idx++) { r = &dev->resource[idx]; @@ -166,11 +166,11 @@ static void __init pcibios_assign_resources(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; int idx; struct resource *r; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { int class = dev->class >> 8; /* Don't touch classless devices and host bridges */ diff -Nru a/arch/i386/pci/irq.c b/arch/i386/pci/irq.c --- a/arch/i386/pci/irq.c Mon Jun 9 23:16:19 2003 +++ b/arch/i386/pci/irq.c Mon Jun 9 23:16:19 2003 @@ -573,7 +573,7 @@ int irq = 0; u32 mask; struct irq_router *r = pirq_router; - struct pci_dev *dev2; + struct pci_dev *dev2 = NULL; char *msg = NULL; /* Find IRQ pin */ @@ -665,7 +665,7 @@ printk(KERN_INFO "PCI: %s IRQ %d for device %s\n", msg, irq, dev->slot_name); /* Update IRQ for all devices with the same pirq value */ - pci_for_each_dev(dev2) { + while ((dev2 = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev2)) != NULL) { pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin); if (!pin) continue; @@ -693,11 +693,11 @@ static void __init pcibios_fixup_irqs(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; u8 pin; DBG("PCI: IRQ fixup\n"); - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { /* * If the BIOS has set an out of range IRQ number, just ignore it. * Also keep track of which IRQ's are already in use. @@ -712,7 +712,8 @@ pirq_penalty[dev->irq]++; } - pci_for_each_dev(dev) { + dev = NULL; + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); #ifdef CONFIG_X86_IO_APIC /* diff -Nru a/arch/ia64/Kconfig b/arch/ia64/Kconfig --- a/arch/ia64/Kconfig Mon Jun 9 23:16:19 2003 +++ b/arch/ia64/Kconfig Mon Jun 9 23:16:19 2003 @@ -563,7 +563,7 @@ agent" (/sbin/hotplug) to load modules and set up software needed to use devices as you hotplug them. -source "drivers/hotplug/Kconfig" +source "drivers/pci/hotplug/Kconfig" source "drivers/pcmcia/Kconfig" diff -Nru a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c --- a/arch/ia64/hp/common/sba_iommu.c Mon Jun 9 23:16:07 2003 +++ b/arch/ia64/hp/common/sba_iommu.c Mon Jun 9 23:16:07 2003 @@ -1413,7 +1413,7 @@ u32 iova_space_mask; int iov_order, tcnfg; int agp_found = 0; - struct pci_dev *device; + struct pci_dev *device = NULL; #ifdef FULL_VALID_PDIR unsigned long index; #endif @@ -1511,7 +1511,7 @@ ** We program the next pdir index after we stop w/ a key for ** the GART code to handshake on. */ - pci_for_each_dev(device) + while ((device = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, device)) != NULL) agp_found |= pci_find_capability(device, PCI_CAP_ID_AGP); if (agp_found && reserve_sba_gart) { diff -Nru a/arch/ia64/hp/sim/simeth.c b/arch/ia64/hp/sim/simeth.c --- a/arch/ia64/hp/sim/simeth.c Mon Jun 9 23:16:14 2003 +++ b/arch/ia64/hp/sim/simeth.c Mon Jun 9 23:16:14 2003 @@ -191,7 +191,7 @@ unsigned char mac_addr[ETH_ALEN]; struct simeth_local *local; struct net_device *dev; - int fd, i; + int fd, i, err; /* * XXX Fix me @@ -207,22 +207,12 @@ if (fd == -1) return -ENODEV; - dev = init_etherdev(NULL, sizeof(struct simeth_local)); + dev = alloc_etherdev(sizeof(struct simeth_local)); if (!dev) return -ENOMEM; memcpy(dev->dev_addr, mac_addr, sizeof(mac_addr)); - dev->irq = ia64_alloc_vector(); - - /* - * attach the interrupt in the simulator, this does enable interrupts - * until a netdev_attach() is called - */ - netdev_connect(dev->irq); - - memset(dev->priv, 0, sizeof(struct simeth_local)); - local = dev->priv; local->simfd = fd; /* keep track of underlying file descriptor */ @@ -232,8 +222,19 @@ dev->get_stats = simeth_get_stats; dev->set_multicast_list = set_multicast_list; /* no yet used */ - /* Fill in the fields of the device structure with ethernet-generic values. */ - ether_setup(dev); + err = register_netdev(dev); + if (dev) { + kfree(dev); + return err; + } + + dev->irq = ia64_alloc_vector(); + + /* + * attach the interrupt in the simulator, this does enable interrupts + * until a netdev_attach() is called + */ + netdev_connect(dev->irq); printk(KERN_INFO "%s: hosteth=%s simfd=%d, HwAddr", dev->name, simeth_device, local->simfd); @@ -242,7 +243,7 @@ } printk(", IRQ %d\n", dev->irq); - return 0; + return 0; } /* diff -Nru a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c --- a/arch/ia64/hp/sim/simserial.c Mon Jun 9 23:16:12 2003 +++ b/arch/ia64/hp/sim/simserial.c Mon Jun 9 23:16:12 2003 @@ -104,7 +104,6 @@ }; struct tty_driver hp_simserial_driver; -static struct tty_driver callout_driver; static int serial_refcount; static struct async_struct *IRQ_ports[NR_IRQS]; @@ -689,7 +688,7 @@ } wake_up_interruptible(&info->open_wait); } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|ASYNC_CLOSING); + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); MOD_DEC_USE_COUNT; } @@ -723,7 +722,7 @@ info->event = 0; state->count = 0; - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->flags &= ~ASYNC_NORMAL_ACTIVE; info->tty = 0; wake_up_interruptible(&info->open_wait); } @@ -937,10 +936,7 @@ if ((info->state->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver->subtype == SERIAL_TYPE_NORMAL) - *tty->termios = info->state->normal_termios; - else - *tty->termios = info->state->callout_termios; + *tty->termios = info->state->normal_termios; } /* @@ -952,9 +948,6 @@ console = console->next; } - info->session = current->session; - info->pgrp = current->pgrp; - #ifdef SIMSERIAL_DEBUG printk("rs_open ttys%d successful\n", info->line); #endif @@ -1084,22 +1077,9 @@ state->port, state->irq, uart_config[state->type].name); } - /* - * The callout device is just like normal device except for - * major number and the subtype code. - */ - callout_driver = hp_simserial_driver; - callout_driver.name = "cua"; - callout_driver.major = TTYAUX_MAJOR; - callout_driver.subtype = SERIAL_TYPE_CALLOUT; - callout_driver.read_proc = 0; - callout_driver.proc_entry = 0; if (tty_register_driver(&hp_simserial_driver)) panic("Couldn't register simserial driver\n"); - - if (tty_register_driver(&callout_driver)) - panic("Couldn't register callout driver\n"); return 0; } diff -Nru a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c --- a/arch/ia64/kernel/irq.c Mon Jun 9 23:16:18 2003 +++ b/arch/ia64/kernel/irq.c Mon Jun 9 23:16:18 2003 @@ -65,8 +65,13 @@ /* * Controller mappings for all interrupt sources: */ -irq_desc_t _irq_desc[NR_IRQS] __cacheline_aligned = - { [0 ... NR_IRQS-1] = { IRQ_DISABLED, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}}; +irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { + [0 ... NR_IRQS-1] = { + .status = IRQ_DISABLED, + .handler = &no_irq_type, + .lock = SPIN_LOCK_UNLOCKED + } +}; #ifdef CONFIG_IA64_GENERIC struct irq_desc * __ia64_irq_desc (unsigned int irq) diff -Nru a/arch/ia64/kernel/module.c b/arch/ia64/kernel/module.c --- a/arch/ia64/kernel/module.c Mon Jun 9 23:16:10 2003 +++ b/arch/ia64/kernel/module.c Mon Jun 9 23:16:10 2003 @@ -887,3 +887,13 @@ if (mod->arch.unwind) unw_remove_unwind_table(mod->arch.unw_table); } + +#ifdef CONFIG_SMP +void percpu_modcopy(void *pcpudst, const void *src, unsigned long size) +{ + unsigned int i; + for (i = 0; i < NR_CPUS; i++) + if (cpu_possible(i)) + memcpy(pcpudst + __per_cpu_offset[i], src, size); +} +#endif /* CONFIG_SMP */ diff -Nru a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c --- a/arch/ia64/kernel/smp.c Mon Jun 9 23:16:19 2003 +++ b/arch/ia64/kernel/smp.c Mon Jun 9 23:16:19 2003 @@ -205,24 +205,6 @@ platform_send_ipi(cpu, IA64_IPI_RESCHEDULE, IA64_IPI_DM_INT, 0); } -/* - * This function sends a reschedule IPI to all (other) CPUs. This should only be used if - * some 'global' task became runnable, such as a RT task, that must be handled now. The - * first CPU that manages to grab the task will run it. - */ -void -smp_send_reschedule_all (void) -{ - int i; - int cpu = get_cpu(); /* disable preemption */ - - for (i = 0; i < NR_CPUS; i++) - if (cpu_online(i) && i != cpu) - smp_send_reschedule(i); - put_cpu(); -} - - void smp_flush_tlb_all (void) { diff -Nru a/arch/ia64/lib/Makefile b/arch/ia64/lib/Makefile --- a/arch/ia64/lib/Makefile Mon Jun 9 23:16:19 2003 +++ b/arch/ia64/lib/Makefile Mon Jun 9 23:16:19 2003 @@ -2,18 +2,16 @@ # Makefile for ia64-specific library routines.. # -L_TARGET = lib.a - -obj-y := __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o \ +lib-y := __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o \ __divdi3.o __udivdi3.o __moddi3.o __umoddi3.o \ checksum.o clear_page.o csum_partial_copy.o copy_page.o \ clear_user.o strncpy_from_user.o strlen_user.o strnlen_user.o \ flush.o io.o ip_fast_csum.o do_csum.o \ memset.o strlen.o swiotlb.o -obj-$(CONFIG_ITANIUM) += copy_page.o copy_user.o memcpy.o -obj-$(CONFIG_MCKINLEY) += copy_page_mck.o memcpy_mck.o -obj-$(CONFIG_PERFMON) += carta_random.o +lib-$(CONFIG_ITANIUM) += copy_page.o copy_user.o memcpy.o +lib-$(CONFIG_MCKINLEY) += copy_page_mck.o memcpy_mck.o +lib-$(CONFIG_PERFMON) += carta_random.o IGNORE_FLAGS_OBJS = __divsi3.o __udivsi3.o __modsi3.o __umodsi3.o \ __divdi3.o __udivdi3.o __moddi3.o __umoddi3.o diff -Nru a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c --- a/arch/ia64/mm/init.c Mon Jun 9 23:16:10 2003 +++ b/arch/ia64/mm/init.c Mon Jun 9 23:16:10 2003 @@ -32,7 +32,7 @@ struct mmu_gather mmu_gathers[NR_CPUS]; /* References to section boundaries: */ -extern char _stext, _etext, _edata, __init_begin, __init_end; +extern char _stext, _etext, _edata, __init_begin, __init_end, _end; extern void ia64_tlb_init (void); @@ -583,6 +583,7 @@ long reserved_pages, codesize, datasize, initsize; unsigned long num_pgt_pages; pg_data_t *pgdat; + static struct kcore_list kcore_mem, kcore_vmem, kcore_kernel; #ifdef CONFIG_PCI /* @@ -600,6 +601,10 @@ #endif high_memory = __va(max_low_pfn * PAGE_SIZE); + + kclist_add(&kcore_mem, __va(0), max_low_pfn * PAGE_SIZE); + kclist_add(&kcore_vmem, (void *)VMALLOC_START, VMALLOC_END-VMALLOC_START); + kclist_add(&kcore_kernel, &_stext, &_end - &_stext); for_each_pgdat(pgdat) totalram_pages += free_all_bootmem_node(pgdat); diff -Nru a/arch/ia64/sn/io/pci_bus_cvlink.c b/arch/ia64/sn/io/pci_bus_cvlink.c --- a/arch/ia64/sn/io/pci_bus_cvlink.c Mon Jun 9 23:16:16 2003 +++ b/arch/ia64/sn/io/pci_bus_cvlink.c Mon Jun 9 23:16:16 2003 @@ -375,7 +375,7 @@ /* * Initialize the device vertex in the pci_dev struct. */ - pci_for_each_dev(device_dev) { + while ((device_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, device_dev)) != NULL) { unsigned int irq; int idx; u16 cmd; diff -Nru a/arch/ia64/sn/io/pciba.c b/arch/ia64/sn/io/pciba.c --- a/arch/ia64/sn/io/pciba.c Mon Jun 9 23:16:06 2003 +++ b/arch/ia64/sn/io/pciba.c Mon Jun 9 23:16:06 2003 @@ -286,7 +286,7 @@ static status __init register_with_devfs(void) { - struct pci_dev * dev; + struct pci_dev * dev = NULL; devfs_handle_t device_dir_handle; char devfs_path[40]; @@ -297,7 +297,7 @@ /* FIXME: don't forget /dev/pci/mem & /dev/pci/io */ - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { sprintf(devfs_path, "pci/%02x/%02x.%x", dev->bus->number, PCI_SLOT(dev->devfn), @@ -325,14 +325,14 @@ static status __init register_with_devfs(void) { - struct pci_dev * dev; + struct pci_dev * dev = NULL; devfs_handle_t device_dir_handle; TRACE(); /* FIXME: don't forget /dev/.../pci/mem & /dev/.../pci/io */ - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { device_dir_handle = devfn_to_vertex(dev->bus->number, dev->devfn); if (device_dir_handle == NULL) diff -Nru a/arch/ia64/sn/io/sn2/pci_bus_cvlink.c b/arch/ia64/sn/io/sn2/pci_bus_cvlink.c --- a/arch/ia64/sn/io/sn2/pci_bus_cvlink.c Mon Jun 9 23:16:07 2003 +++ b/arch/ia64/sn/io/sn2/pci_bus_cvlink.c Mon Jun 9 23:16:07 2003 @@ -325,7 +325,7 @@ /* * Initialize the device vertex in the pci_dev struct. */ - pci_for_each_dev(device_dev) { + while ((device_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, device_dev)) != NULL) { unsigned int irq; int idx; u16 cmd; diff -Nru a/arch/m68k/atari/hades-pci.c b/arch/m68k/atari/hades-pci.c --- a/arch/m68k/atari/hades-pci.c Mon Jun 9 23:16:13 2003 +++ b/arch/m68k/atari/hades-pci.c Mon Jun 9 23:16:13 2003 @@ -297,14 +297,14 @@ IRQ_TT_MFP_SCC, /* Slot 2. */ IRQ_TT_MFP_SCSIDMA /* Slot 3. */ }; - struct pci_dev *dev; + struct pci_dev *dev = NULL; unsigned char slot; /* * Go through all devices, fixing up irqs as we see fit: */ - for (dev = pci_devices; dev; dev = dev->next) + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { if (dev->class >> 16 != PCI_BASE_CLASS_BRIDGE) { diff -Nru a/arch/m68k/lib/Makefile b/arch/m68k/lib/Makefile --- a/arch/m68k/lib/Makefile Mon Jun 9 23:16:05 2003 +++ b/arch/m68k/lib/Makefile Mon Jun 9 23:16:05 2003 @@ -2,9 +2,7 @@ # Makefile for m68k-specific library files.. # -L_TARGET = lib.a - EXTRA_AFLAGS := -traditional -obj-y := ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \ +lib-y := ashldi3.o ashrdi3.o lshrdi3.o muldi3.o \ checksum.o memcmp.o memcpy.o memset.o semaphore.o diff -Nru a/arch/m68knommu/Kconfig b/arch/m68knommu/Kconfig --- a/arch/m68knommu/Kconfig Mon Jun 9 23:16:15 2003 +++ b/arch/m68knommu/Kconfig Mon Jun 9 23:16:15 2003 @@ -488,7 +488,7 @@ source "drivers/pcmcia/Kconfig" -source "drivers/hotplug/Kconfig" +source "drivers/pci/hotplug/Kconfig" endmenu diff -Nru a/arch/m68knommu/kernel/Makefile b/arch/m68knommu/kernel/Makefile --- a/arch/m68knommu/kernel/Makefile Mon Jun 9 23:16:09 2003 +++ b/arch/m68knommu/kernel/Makefile Mon Jun 9 23:16:09 2003 @@ -2,7 +2,7 @@ # Makefile for arch/m68knommu/kernel. # -obj-y += entry.o init_task.o ints.o m68k_ksyms.o process.o ptrace.o \ +obj-y += entry.o init_task.o m68k_ksyms.o process.o ptrace.o \ semaphore.o setup.o signal.o syscalltable.o sys_m68k.o time.o \ traps.o diff -Nru a/arch/m68knommu/kernel/ints.c b/arch/m68knommu/kernel/ints.c --- a/arch/m68knommu/kernel/ints.c Mon Jun 9 23:16:08 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,271 +0,0 @@ -/* - * linux/arch/m68knommu/kernel/ints.c -- General interrupt handling code - * - * Copyright (C) 1999-2002 Greg Ungerer (gerg@snapgear.com) - * Copyright (C) 1998 D. Jeff Dionne <jeff@lineo.ca>, - * Kenneth Albanowski <kjahds@kjahds.com>, - * Copyright (C) 2000 Lineo Inc. (www.lineo.com) - * - * Based on: - * - * linux/arch/m68k/kernel/ints.c -- Linux/m68k general interrupt handling code - * - * 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> -#include <linux/init.h> -#include <linux/sched.h> -#include <linux/kernel_stat.h> -#include <linux/errno.h> -#include <linux/config.h> -#include <linux/seq_file.h> - -#include <asm/system.h> -#include <asm/irq.h> -#include <asm/traps.h> -#include <asm/page.h> -#include <asm/machdep.h> - -/* - * This table stores the address info for each vector handler. - */ -irq_handler_t irq_list[SYS_IRQS]; - -#define NUM_IRQ_NODES 16 -static irq_node_t nodes[NUM_IRQ_NODES]; - -/* The number of spurious interrupts */ -volatile unsigned int num_spurious; - -unsigned int local_bh_count[NR_CPUS]; -unsigned int local_irq_count[NR_CPUS]; - -static void default_irq_handler(int irq, void *ptr, struct pt_regs *regs) -{ -#if 1 - printk("%s(%d): default irq handler vec=%d [0x%x]\n", - __FILE__, __LINE__, irq, irq); -#endif -} - -/* - * void init_IRQ(void) - * - * Parameters: None - * - * Returns: Nothing - * - * This function should be called during kernel startup to initialize - * the IRQ handling routines. - */ - -void __init init_IRQ(void) -{ - int i; - - for (i = 0; i < SYS_IRQS; i++) { - if (mach_default_handler) - irq_list[i].handler = (*mach_default_handler)[i]; - else - irq_list[i].handler = default_irq_handler; - irq_list[i].flags = IRQ_FLG_STD; - irq_list[i].dev_id = NULL; - irq_list[i].devname = NULL; - } - - for (i = 0; i < NUM_IRQ_NODES; i++) - nodes[i].handler = NULL; - - if (mach_init_IRQ) - mach_init_IRQ(); -} - -irq_node_t *new_irq_node(void) -{ - irq_node_t *node; - short i; - - for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--) - if (!node->handler) - return node; - - printk("new_irq_node: out of nodes\n"); - return NULL; -} - -int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), - unsigned long flags, const char *devname, void *dev_id) -{ - if (irq < 0 || irq >= NR_IRQS) { - printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, - irq, devname); - return -ENXIO; - } - - if (!(irq_list[irq].flags & IRQ_FLG_STD)) { - if (irq_list[irq].flags & IRQ_FLG_LOCK) { - printk("%s: IRQ %d from %s is not replaceable\n", - __FUNCTION__, irq, irq_list[irq].devname); - return -EBUSY; - } - if (flags & IRQ_FLG_REPLACE) { - printk("%s: %s can't replace IRQ %d from %s\n", - __FUNCTION__, devname, irq, irq_list[irq].devname); - return -EBUSY; - } - } - -#ifdef CONFIG_COLDFIRE - if (flags & IRQ_FLG_FAST) { - extern asmlinkage void fasthandler(void); - extern void set_evector(int vecnum, void (*handler)(void)); - set_evector(irq, fasthandler); - } -#endif - - irq_list[irq].handler = handler; - irq_list[irq].flags = flags; - irq_list[irq].dev_id = dev_id; - irq_list[irq].devname = devname; - return 0; -} - -void free_irq(unsigned int irq, void *dev_id) -{ - if (irq >= NR_IRQS) { - printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq); - return; - } - - if (irq_list[irq].dev_id != dev_id) - printk("%s: Removing probably wrong IRQ %d from %s\n", - __FUNCTION__, irq, irq_list[irq].devname); - -#ifdef CONFIG_COLDFIRE - if (irq_list[irq].flags & IRQ_FLG_FAST) { - extern asmlinkage void inthandler(void); - extern void set_evector(int vecnum, void (*handler)(void)); - set_evector(irq, inthandler); - } -#endif - - if (mach_default_handler) - irq_list[irq].handler = (*mach_default_handler)[irq]; - else - irq_list[irq].handler = default_irq_handler; - irq_list[irq].flags = IRQ_FLG_STD; - irq_list[irq].dev_id = NULL; - irq_list[irq].devname = NULL; -} - - -int sys_request_irq(unsigned int irq, - void (*handler)(int, void *, struct pt_regs *), - unsigned long flags, const char *devname, void *dev_id) -{ - if (irq > IRQ7) { - printk("%s: Incorrect IRQ %d from %s\n", - __FUNCTION__, irq, devname); - return -ENXIO; - } - -#if 0 - if (!(irq_list[irq].flags & IRQ_FLG_STD)) { - if (irq_list[irq].flags & IRQ_FLG_LOCK) { - printk("%s: IRQ %d from %s is not replaceable\n", - __FUNCTION__, irq, irq_list[irq].devname); - return -EBUSY; - } - if (!(flags & IRQ_FLG_REPLACE)) { - printk("%s: %s can't replace IRQ %d from %s\n", - __FUNCTION__, devname, irq, irq_list[irq].devname); - return -EBUSY; - } - } -#endif - - irq_list[irq].handler = handler; - irq_list[irq].flags = flags; - irq_list[irq].dev_id = dev_id; - irq_list[irq].devname = devname; - return 0; -} - -void sys_free_irq(unsigned int irq, void *dev_id) -{ - if (irq > IRQ7) { - printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq); - return; - } - - if (irq_list[irq].dev_id != dev_id) - printk("%s: Removing probably wrong IRQ %d from %s\n", - __FUNCTION__, irq, irq_list[irq].devname); - - irq_list[irq].handler = (*mach_default_handler)[irq]; - irq_list[irq].flags = 0; - irq_list[irq].dev_id = NULL; - irq_list[irq].devname = NULL; -} - -/* - * Do we need these probe functions on the m68k? - * - * ... may be useful with ISA devices - */ -unsigned long probe_irq_on (void) -{ - return 0; -} - -int probe_irq_off (unsigned long irqs) -{ - return 0; -} - -asmlinkage void process_int(unsigned long vec, struct pt_regs *fp) -{ - if (vec >= VEC_INT1 && vec <= VEC_INT7) { - vec -= VEC_SPUR; - kstat_cpu(0).irqs[vec]++; - irq_list[vec].handler(vec, irq_list[vec].dev_id, fp); - } else { - if (mach_process_int) - mach_process_int(vec, fp); - else - panic("Can't process interrupt vector %ld\n", vec); - return; - } -} - - -int show_interrupts(struct seq_file *p, void *v) -{ - int i; - - for (i = 0; i < NR_IRQS; i++) { - if (irq_list[i].flags & IRQ_FLG_STD) - continue; - - seq_printf(p, "%3d: %10u ", i, - (i ? kstat_cpu(0).irqs[i] : num_spurious)); - if (irq_list[i].flags & IRQ_FLG_LOCK) - seq_printf(p, "L "); - else - seq_printf(p, " "); - seq_printf(p, "%s\n", irq_list[i].devname); - } - - if (mach_get_irq_list) - mach_get_irq_list(p, v); - return(0); -} - -void init_irq_proc(void) -{ - /* Insert /proc/irq driver here */ -} - diff -Nru a/arch/m68knommu/kernel/process.c b/arch/m68knommu/kernel/process.c --- a/arch/m68knommu/kernel/process.c Mon Jun 9 23:16:08 2003 +++ b/arch/m68knommu/kernel/process.c Mon Jun 9 23:16:08 2003 @@ -167,24 +167,20 @@ asmlinkage int m68k_vfork(struct pt_regs *regs) { - struct task_struct *p; - p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL); - return IS_ERR(p) ? PTR_ERR(p) : p->pid; + return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(), regs, 0, NULL, NULL); } asmlinkage int m68k_clone(struct pt_regs *regs) { unsigned long clone_flags; unsigned long newsp; - struct task_struct *p; /* syscall2 puts clone_flags in d1 and usp in d2 */ clone_flags = regs->d1; newsp = regs->d2; if (!newsp) newsp = rdusp(); - p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, regs, 0, NULL, NULL); - return IS_ERR(p) ? PTR_ERR(p) : p->pid; + return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, regs, 0, NULL, NULL); } int copy_thread(int nr, unsigned long clone_flags, diff -Nru a/arch/m68knommu/kernel/setup.c b/arch/m68knommu/kernel/setup.c --- a/arch/m68knommu/kernel/setup.c Mon Jun 9 23:16:15 2003 +++ b/arch/m68knommu/kernel/setup.c Mon Jun 9 23:16:15 2003 @@ -225,10 +225,6 @@ (int) memory_end, (int) _ramend); #endif -#ifdef CONFIG_BLK_DEV_BLKMEM - ROOT_DEV = MKDEV(BLKMEM_MAJOR, 0); -#endif - /* Keep a copy of command line */ *cmdline_p = &command_line[0]; memcpy(saved_command_line, command_line, sizeof(saved_command_line)); diff -Nru a/arch/m68knommu/lib/Makefile b/arch/m68knommu/lib/Makefile --- a/arch/m68knommu/lib/Makefile Mon Jun 9 23:16:09 2003 +++ b/arch/m68knommu/lib/Makefile Mon Jun 9 23:16:09 2003 @@ -2,7 +2,6 @@ # Makefile for m68knommu specific library files.. # -L_TARGET = lib.a -obj-y := ashldi3.o ashrdi3.o lshrdi3.o \ +lib-y := ashldi3.o ashrdi3.o lshrdi3.o \ muldi3.o mulsi3.o divsi3.o udivsi3.o modsi3.o umodsi3.o \ checksum.o semaphore.o memcpy.o memset.o diff -Nru a/arch/m68knommu/mm/memory.c b/arch/m68knommu/mm/memory.c --- a/arch/m68knommu/mm/memory.c Mon Jun 9 23:16:18 2003 +++ b/arch/m68knommu/mm/memory.c Mon Jun 9 23:16:18 2003 @@ -114,51 +114,18 @@ int is_in_rom(unsigned long addr) { + extern unsigned long _ramstart, _ramend; -#ifdef CONFIG_COLDFIRE - { - extern unsigned long _ramstart, _ramend; - - /* Anything not in operational RAM is returned as in rom! */ - if (addr < _ramstart || addr >= _ramend) - return(1); - } -#endif - -#if defined(CONFIG_PILOT) || defined(CONFIG_UCSIMM) - if (addr >= 0x10c00000) - return 1; -#endif - -#ifdef CONFIG_M68EZ328ADS - if ( 0x00200000 <= addr && addr < 0x00400000) - return 1; -#endif - -#ifdef CONFIG_M68332 - extern char _etext; - - #ifdef SHGLCORE_ROM_BANK_0_ADDR - if ((addr >= SHGLCORE_ROM_BANK_0_ADDR) && - (addr < (SHGLCORE_ROM_BANK_0_ADDR+SHGLCORE_ROM_BANK_0_LENGTH))) - return 1; - #endif - #ifdef SHGLCORE_ROM_BANK_1_ADDR - else if ((addr >= SHGLCORE_ROM_BANK_1_ADDR) && - (addr < (SHGLCORE_ROM_BANK_1_ADDR+SHGLCORE_ROM_BANK_1_LENGTH))) - return 1; - #endif - #ifdef SHGLCORE_FLASH_BANK_0_ADDR - else if ((addr >= SHGLCORE_FLASH_BANK_0_ADDR) && - (addr < (SHGLCORE_FLASH_BANK_0_ADDR+SHGLCORE_FLASH_BANK_0_LENGTH))) - return 1; - #endif - #ifdef SHGLCORE_FLASH_BANK_1_ADDR - else if ((addr >= SHGLCORE_FLASH_BANK_1_ADDR) && - (addr < (SHGLCORE_FLASH_BANK_1_ADDR+SHGLCORE_FLASH_BANK_1_LENGTH))) - return 1; - #endif -#endif + /* + * What we are really trying to do is determine if addr is + * in an allocated kernel memory region. If not then assume + * we cannot free it or otherwise de-allocate it. Ideally + * we could restrict this to really being in a ROM or flash, + * but that would need to be done on a board by board basis, + * not globally. + */ + if ((addr < _ramstart) || (addr >= _ramend)) + return(1); /* Default case, not in ROM */ return(0); diff -Nru a/arch/m68knommu/platform/5206/ARNEWSH/crt0_ram.S b/arch/m68knommu/platform/5206/ARNEWSH/crt0_ram.S --- a/arch/m68knommu/platform/5206/ARNEWSH/crt0_ram.S Mon Jun 9 23:16:15 2003 +++ b/arch/m68knommu/platform/5206/ARNEWSH/crt0_ram.S Mon Jun 9 23:16:15 2003 @@ -157,6 +157,7 @@ movec %d0, %CACR /* Enable cache */ +#ifdef CONFIG_ROMFS_FS /* * Move ROM filesystem above bss :-) */ @@ -177,6 +178,12 @@ move.l %d0, -(%a1) cmp.l %a0, %a2 /* Check if at end */ bne _copy_romfs + +#else /* CONFIG_ROMFS_FS */ + lea.l _ebss, %a1 + move.l %a1, _ramstart +#endif /* CONFIG_ROMFS_FS */ + /* * Zero out the bss region. diff -Nru a/arch/m68knommu/platform/5206/config.c b/arch/m68knommu/platform/5206/config.c --- a/arch/m68knommu/platform/5206/config.c Mon Jun 9 23:16:14 2003 +++ b/arch/m68knommu/platform/5206/config.c Mon Jun 9 23:16:14 2003 @@ -96,7 +96,13 @@ void config_BSP(char *commandp, int size) { mcf_setimr(MCFSIM_IMR_MASKALL); + +#if defined(CONFIG_BOOTPARAM) + strncpy(commandp, CONFIG_BOOTPARAM_STRING, size); + commandp[size-1] = 0; +#else memset(commandp, 0, size); +#endif mach_sched_init = coldfire_timer_init; mach_tick = coldfire_tick; diff -Nru a/arch/m68knommu/platform/5206e/config.c b/arch/m68knommu/platform/5206e/config.c --- a/arch/m68knommu/platform/5206e/config.c Mon Jun 9 23:16:09 2003 +++ b/arch/m68knommu/platform/5206e/config.c Mon Jun 9 23:16:09 2003 @@ -97,7 +97,10 @@ { mcf_setimr(MCFSIM_IMR_MASKALL); -#ifdef CONFIG_NETtel +#if defined(CONFIG_BOOTPARAM) + strncpy(commandp, CONFIG_BOOTPARAM_STRING, size); + commandp[size-1] = 0; +#elif defined(CONFIG_NETtel) /* Copy command line from FLASH to local buffer... */ memcpy(commandp, (char *) 0xf0004000, size); commandp[size-1] = 0; diff -Nru a/arch/m68knommu/platform/5307/Makefile b/arch/m68knommu/platform/5307/Makefile --- a/arch/m68knommu/platform/5307/Makefile Mon Jun 9 23:16:17 2003 +++ b/arch/m68knommu/platform/5307/Makefile Mon Jun 9 23:16:17 2003 @@ -16,7 +16,7 @@ AFLAGS += -DDEBUGGER_COMPATIBLE_CACHE=1 endif -obj-$(CONFIG_COLDFIRE) += entry.o vectors.o +obj-$(CONFIG_COLDFIRE) += entry.o vectors.o ints.o obj-$(CONFIG_M5206) += timers.o obj-$(CONFIG_M5206e) += timers.o obj-$(CONFIG_M5249) += timers.o diff -Nru a/arch/m68knommu/platform/5307/ints.c b/arch/m68knommu/platform/5307/ints.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/arch/m68knommu/platform/5307/ints.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,267 @@ +/* + * linux/arch/m68knommu/kernel/ints.c -- General interrupt handling code + * + * Copyright (C) 1999-2002 Greg Ungerer (gerg@snapgear.com) + * Copyright (C) 1998 D. Jeff Dionne <jeff@lineo.ca>, + * Kenneth Albanowski <kjahds@kjahds.com>, + * Copyright (C) 2000 Lineo Inc. (www.lineo.com) + * + * Based on: + * + * linux/arch/m68k/kernel/ints.c -- Linux/m68k general interrupt handling code + * + * 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> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/kernel_stat.h> +#include <linux/errno.h> +#include <linux/config.h> +#include <linux/seq_file.h> + +#include <asm/system.h> +#include <asm/irq.h> +#include <asm/traps.h> +#include <asm/page.h> +#include <asm/machdep.h> + +/* + * This table stores the address info for each vector handler. + */ +irq_handler_t irq_list[SYS_IRQS]; + +#define NUM_IRQ_NODES 16 +static irq_node_t nodes[NUM_IRQ_NODES]; + +/* The number of spurious interrupts */ +volatile unsigned int num_spurious; + +unsigned int local_bh_count[NR_CPUS]; +unsigned int local_irq_count[NR_CPUS]; + +static void default_irq_handler(int irq, void *ptr, struct pt_regs *regs) +{ +#if 1 + printk("%s(%d): default irq handler vec=%d [0x%x]\n", + __FILE__, __LINE__, irq, irq); +#endif +} + +/* + * void init_IRQ(void) + * + * Parameters: None + * + * Returns: Nothing + * + * This function should be called during kernel startup to initialize + * the IRQ handling routines. + */ + +void __init init_IRQ(void) +{ + int i; + + for (i = 0; i < SYS_IRQS; i++) { + if (mach_default_handler) + irq_list[i].handler = (*mach_default_handler)[i]; + else + irq_list[i].handler = default_irq_handler; + irq_list[i].flags = IRQ_FLG_STD; + irq_list[i].dev_id = NULL; + irq_list[i].devname = NULL; + } + + for (i = 0; i < NUM_IRQ_NODES; i++) + nodes[i].handler = NULL; + + if (mach_init_IRQ) + mach_init_IRQ(); +} + +irq_node_t *new_irq_node(void) +{ + irq_node_t *node; + short i; + + for (node = nodes, i = NUM_IRQ_NODES-1; i >= 0; node++, i--) + if (!node->handler) + return node; + + printk("new_irq_node: out of nodes\n"); + return NULL; +} + +int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), + unsigned long flags, const char *devname, void *dev_id) +{ + if (irq < 0 || irq >= NR_IRQS) { + printk("%s: Incorrect IRQ %d from %s\n", __FUNCTION__, + irq, devname); + return -ENXIO; + } + + if (!(irq_list[irq].flags & IRQ_FLG_STD)) { + if (irq_list[irq].flags & IRQ_FLG_LOCK) { + printk("%s: IRQ %d from %s is not replaceable\n", + __FUNCTION__, irq, irq_list[irq].devname); + return -EBUSY; + } + if (flags & IRQ_FLG_REPLACE) { + printk("%s: %s can't replace IRQ %d from %s\n", + __FUNCTION__, devname, irq, irq_list[irq].devname); + return -EBUSY; + } + } + + if (flags & IRQ_FLG_FAST) { + extern asmlinkage void fasthandler(void); + extern void set_evector(int vecnum, void (*handler)(void)); + set_evector(irq, fasthandler); + } + + irq_list[irq].handler = handler; + irq_list[irq].flags = flags; + irq_list[irq].dev_id = dev_id; + irq_list[irq].devname = devname; + return 0; +} + +void free_irq(unsigned int irq, void *dev_id) +{ + if (irq >= NR_IRQS) { + printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq); + return; + } + + if (irq_list[irq].dev_id != dev_id) + printk("%s: Removing probably wrong IRQ %d from %s\n", + __FUNCTION__, irq, irq_list[irq].devname); + + if (irq_list[irq].flags & IRQ_FLG_FAST) { + extern asmlinkage void inthandler(void); + extern void set_evector(int vecnum, void (*handler)(void)); + set_evector(irq, inthandler); + } + + if (mach_default_handler) + irq_list[irq].handler = (*mach_default_handler)[irq]; + else + irq_list[irq].handler = default_irq_handler; + irq_list[irq].flags = IRQ_FLG_STD; + irq_list[irq].dev_id = NULL; + irq_list[irq].devname = NULL; +} + + +int sys_request_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long flags, const char *devname, void *dev_id) +{ + if (irq > IRQ7) { + printk("%s: Incorrect IRQ %d from %s\n", + __FUNCTION__, irq, devname); + return -ENXIO; + } + +#if 0 + if (!(irq_list[irq].flags & IRQ_FLG_STD)) { + if (irq_list[irq].flags & IRQ_FLG_LOCK) { + printk("%s: IRQ %d from %s is not replaceable\n", + __FUNCTION__, irq, irq_list[irq].devname); + return -EBUSY; + } + if (!(flags & IRQ_FLG_REPLACE)) { + printk("%s: %s can't replace IRQ %d from %s\n", + __FUNCTION__, devname, irq, irq_list[irq].devname); + return -EBUSY; + } + } +#endif + + irq_list[irq].handler = handler; + irq_list[irq].flags = flags; + irq_list[irq].dev_id = dev_id; + irq_list[irq].devname = devname; + return 0; +} + +void sys_free_irq(unsigned int irq, void *dev_id) +{ + if (irq > IRQ7) { + printk("%s: Incorrect IRQ %d\n", __FUNCTION__, irq); + return; + } + + if (irq_list[irq].dev_id != dev_id) + printk("%s: Removing probably wrong IRQ %d from %s\n", + __FUNCTION__, irq, irq_list[irq].devname); + + irq_list[irq].handler = (*mach_default_handler)[irq]; + irq_list[irq].flags = 0; + irq_list[irq].dev_id = NULL; + irq_list[irq].devname = NULL; +} + +/* + * Do we need these probe functions on the m68k? + * + * ... may be useful with ISA devices + */ +unsigned long probe_irq_on (void) +{ + return 0; +} + +int probe_irq_off (unsigned long irqs) +{ + return 0; +} + +asmlinkage void process_int(unsigned long vec, struct pt_regs *fp) +{ + if (vec >= VEC_INT1 && vec <= VEC_INT7) { + vec -= VEC_SPUR; + kstat_cpu(0).irqs[vec]++; + irq_list[vec].handler(vec, irq_list[vec].dev_id, fp); + } else { + if (mach_process_int) + mach_process_int(vec, fp); + else + panic("Can't process interrupt vector %ld\n", vec); + return; + } +} + + +int show_interrupts(struct seq_file *p, void *v) +{ + int i; + + for (i = 0; i < NR_IRQS; i++) { + if (irq_list[i].flags & IRQ_FLG_STD) + continue; + + seq_printf(p, "%3d: %10u ", i, + (i ? kstat_cpu(0).irqs[i] : num_spurious)); + if (irq_list[i].flags & IRQ_FLG_LOCK) + seq_printf(p, "L "); + else + seq_printf(p, " "); + seq_printf(p, "%s\n", irq_list[i].devname); + } + + if (mach_get_irq_list) + mach_get_irq_list(p, v); + return(0); +} + +void init_irq_proc(void) +{ + /* Insert /proc/irq driver here */ +} + diff -Nru a/arch/m68knommu/platform/68328/entry.S b/arch/m68knommu/platform/68328/entry.S --- a/arch/m68knommu/platform/68328/entry.S Mon Jun 9 23:16:07 2003 +++ b/arch/m68knommu/platform/68328/entry.S Mon Jun 9 23:16:07 2003 @@ -76,7 +76,12 @@ jbsr set_esp0 addql #4,%sp - btst #PF_TRACESYS_BIT,%a2@(TASK_FLAGS+PF_TRACESYS_OFF) + movel %sp@(PT_ORIG_D0),%d0 + + movel %sp,%d1 /* get thread_info pointer */ + andl #0xffffe000,%d1 + movel %d1,%a2 + btst #TIF_SYSCALL_TRACE,%a2@(TI_FLAGS) jne do_trace cmpl #NR_syscalls,%d0 jcc badsys diff -Nru a/arch/m68knommu/platform/68328/pilot/crt0_rom.S b/arch/m68knommu/platform/68328/pilot/crt0_rom.S --- a/arch/m68knommu/platform/68328/pilot/crt0_rom.S Mon Jun 9 23:16:19 2003 +++ b/arch/m68knommu/platform/68328/pilot/crt0_rom.S Mon Jun 9 23:16:19 2003 @@ -136,10 +136,10 @@ cmpal %a1, %a2 bhi L2 - /* Copy data segment from ROM to RAM */ + /* Copy data+init segment from ROM to RAM */ moveal #_etext, %a0 moveal #_sdata, %a1 - moveal #_edata, %a2 + moveal #__init_end, %a2 DBG_PUTC('D') diff -Nru a/arch/m68knommu/platform/68VZ328/de2/config.c b/arch/m68knommu/platform/68VZ328/de2/config.c --- a/arch/m68knommu/platform/68VZ328/de2/config.c Mon Jun 9 23:16:08 2003 +++ b/arch/m68knommu/platform/68VZ328/de2/config.c Mon Jun 9 23:16:08 2003 @@ -118,7 +118,7 @@ static void init_hardware(void) { -#if CONFIG_DIRECT_IO_ACCESS +#ifdef CONFIG_DIRECT_IO_ACCESS SCR = 0x10; /* allow user access to internal registers */ #endif diff -Nru a/arch/m68knommu/vmlinux.lds.S b/arch/m68knommu/vmlinux.lds.S --- a/arch/m68knommu/vmlinux.lds.S Mon Jun 9 23:16:10 2003 +++ b/arch/m68knommu/vmlinux.lds.S Mon Jun 9 23:16:10 2003 @@ -27,6 +27,7 @@ #define RAM_START 0x10000400 #define RAM_LENGTH 0xffc00 #define RAM_END 0x10100000 +#define _ramend _ram_end_notused #define DATA_ADDR RAM_START #endif @@ -276,6 +277,9 @@ __con_initcall_start = .; *(.con_initcall.init) __con_initcall_end = .; + __security_initcall_start = .; + *(.security_initcall.init) + __security_initcall_end = .; . = ALIGN(4); __initramfs_start = .; *(.init.ramfs) diff -Nru a/arch/mips/arc/Makefile b/arch/mips/arc/Makefile --- a/arch/mips/arc/Makefile Mon Jun 9 23:16:08 2003 +++ b/arch/mips/arc/Makefile Mon Jun 9 23:16:08 2003 @@ -3,9 +3,7 @@ # under Linux. # -L_TARGET = lib.a - -obj-y += console.o init.o memory.o tree.o env.o cmdline.o misc.o \ +lib-y += console.o init.o memory.o tree.o env.o cmdline.o misc.o \ time.o file.o identify.o -obj-$(CONFIG_ARC_CONSOLE) += arc_con.o +lib-$(CONFIG_ARC_CONSOLE) += arc_con.o diff -Nru a/arch/mips/au1000/common/serial.c b/arch/mips/au1000/common/serial.c --- a/arch/mips/au1000/common/serial.c Mon Jun 9 23:16:09 2003 +++ b/arch/mips/au1000/common/serial.c Mon Jun 9 23:16:09 2003 @@ -126,7 +126,7 @@ static DECLARE_TASK_QUEUE(tq_serial); -static struct tty_driver serial_driver, callout_driver; +static struct tty_driver serial_driver; static int serial_refcount; static struct timer_list serial_timer; @@ -136,7 +136,6 @@ /* serial subtype definitions */ #ifndef SERIAL_TYPE_NORMAL #define SERIAL_TYPE_NORMAL 1 -#define SERIAL_TYPE_CALLOUT 2 #endif /* number of characters left in xmit buffer before we ask for more */ @@ -529,8 +528,7 @@ #endif if (status & UART_MSR_DCD) wake_up_interruptible(&info->open_wait); - else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_CALLOUT_NOHUP))) { + else { #ifdef SERIAL_DEBUG_OPEN printk("doing serial hangup..."); #endif @@ -1935,8 +1933,6 @@ */ if (info->flags & ASYNC_NORMAL_ACTIVE) info->state->normal_termios = *tty->termios; - if (info->flags & ASYNC_CALLOUT_ACTIVE) - info->state->callout_termios = *tty->termios; /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. @@ -1976,8 +1972,7 @@ } wake_up_interruptible(&info->open_wait); } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| - ASYNC_CLOSING); + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); MOD_DEC_USE_COUNT; } @@ -2066,7 +2061,7 @@ shutdown(info); info->event = 0; state->count = 0; - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->flags &= ~ASYNC_NORMAL_ACTIVE; info->tty = 0; wake_up_interruptible(&info->open_wait); } @@ -2102,44 +2097,18 @@ } /* - * If this is a callout device, then just make sure the normal - * device isn't being used. - */ - if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) { - if (info->flags & ASYNC_NORMAL_ACTIVE) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_SESSION_LOCKOUT) && - (info->session != current->session)) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_PGRP_LOCKOUT) && - (info->pgrp != current->pgrp)) - return -EBUSY; - info->flags |= ASYNC_CALLOUT_ACTIVE; - return 0; - } - - /* * If non-blocking mode is set, or the port is not enabled, * then make the check up front and then exit. */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { - if (info->flags & ASYNC_CALLOUT_ACTIVE) - return -EBUSY; info->flags |= ASYNC_NORMAL_ACTIVE; return 0; } - if (info->flags & ASYNC_CALLOUT_ACTIVE) { - if (state->normal_termios.c_cflag & CLOCAL) - do_clocal = 1; - } else { - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - } - + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + /* * Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). While we are in @@ -2162,8 +2131,7 @@ info->blocked_open++; while (1) { save_flags(flags); cli(); - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - (tty->termios->c_cflag & CBAUD)) + if (tty->termios->c_cflag & CBAUD) serial_out(info, UART_MCR, serial_inp(info, UART_MCR) | (UART_MCR_DTR | UART_MCR_RTS)); @@ -2181,8 +2149,7 @@ #endif break; } - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - !(info->flags & ASYNC_CLOSING) && + if (!(info->flags & ASYNC_CLOSING) && (do_clocal || (serial_in(info, UART_MSR) & UART_MSR_DCD))) break; @@ -2335,10 +2302,7 @@ if ((info->state->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver->subtype == SERIAL_TYPE_NORMAL) - *tty->termios = info->state->normal_termios; - else - *tty->termios = info->state->callout_termios; + *tty->termios = info->state->normal_termios; change_speed(info, 0); } #ifdef CONFIG_AU1000_SERIAL_CONSOLE @@ -2348,8 +2312,6 @@ change_speed(info, 0); } #endif - info->session = current->session; - info->pgrp = current->pgrp; #ifdef SERIAL_DEBUG_OPEN printk("rs_open %s successful...", tty->name); @@ -2587,11 +2549,8 @@ memset(&serial_driver, 0, sizeof(struct tty_driver)); serial_driver.magic = TTY_DRIVER_MAGIC; serial_driver.driver_name = "serial"; -#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) - serial_driver.name = "tts/"; -#else + serial_driver.devfs_name = "tts/"; serial_driver.name = "ttyS"; -#endif serial_driver.major = TTY_MAJOR; serial_driver.minor_start = 64 + SERIAL_DEV_OFFSET; serial_driver.num = NR_PORTS; @@ -2626,26 +2585,9 @@ serial_driver.wait_until_sent = rs_wait_until_sent; serial_driver.read_proc = rs_read_proc; - /* - * The callout device is just like normal device except for - * major number and the subtype code. - */ - callout_driver = serial_driver; -#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) - callout_driver.name = "cua/"; -#else - callout_driver.name = "cua"; -#endif - callout_driver.major = TTYAUX_MAJOR; - callout_driver.subtype = SERIAL_TYPE_CALLOUT; - callout_driver.read_proc = 0; - callout_driver.proc_entry = 0; - if (tty_register_driver(&serial_driver)) panic("Couldn't register serial driver\n"); - if (tty_register_driver(&callout_driver)) - panic("Couldn't register callout driver\n"); - + for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { state->baud_base = get_au1000_uart_baud(); state->magic = SSTATE_MAGIC; @@ -2654,7 +2596,6 @@ state->custom_divisor = 0; state->close_delay = 5*HZ/10; state->closing_wait = 30*HZ; - state->callout_termios = callout_driver.init_termios; state->normal_termios = serial_driver.init_termios; state->icount.cts = state->icount.dsr = state->icount.rng = state->icount.dcd = 0; @@ -2682,7 +2623,6 @@ state->port, state->irq, uart_config[state->type].name); tty_register_device(&serial_driver, state->line, NULL); - tty_register_device(&callout_driver, state->line, NULL); } return 0; } @@ -2770,7 +2710,6 @@ state->iomem_base ? (unsigned long)state->iomem_base : state->port, state->irq, uart_config[state->type].name); tty_register_device(&serial_driver, state->line, NULL); - tty_register_device(&callout_driver, state->line, NULL); return state->line + SERIAL_DEV_OFFSET; } @@ -2815,9 +2754,6 @@ if ((e1 = tty_unregister_driver(&serial_driver))) printk("serial: failed to unregister serial driver (%d)\n", e1); - if ((e2 = tty_unregister_driver(&callout_driver))) - printk("serial: failed to unregister callout driver (%d)\n", - e2); restore_flags(flags); for (i = 0; i < NR_PORTS; i++) { diff -Nru a/arch/mips/baget/prom/Makefile b/arch/mips/baget/prom/Makefile --- a/arch/mips/baget/prom/Makefile Mon Jun 9 23:16:14 2003 +++ b/arch/mips/baget/prom/Makefile Mon Jun 9 23:16:14 2003 @@ -2,6 +2,4 @@ # Makefile for the Baget/MIPS prom emulator library routines. # -L_TARGET := lib.a - -obj-y := init.o +lib-y := init.o diff -Nru a/arch/mips/baget/vacserial.c b/arch/mips/baget/vacserial.c --- a/arch/mips/baget/vacserial.c Mon Jun 9 23:16:15 2003 +++ b/arch/mips/baget/vacserial.c Mon Jun 9 23:16:15 2003 @@ -95,7 +95,7 @@ static DECLARE_TASK_QUEUE(tq_serial); -static struct tty_driver serial_driver, callout_driver; +static struct tty_driver serial_driver; static int serial_refcount; /* number of characters left in xmit buffer before we ask for more */ @@ -1690,8 +1690,6 @@ */ if (info->flags & ASYNC_NORMAL_ACTIVE) info->state->normal_termios = *tty->termios; - if (info->flags & ASYNC_CALLOUT_ACTIVE) - info->state->callout_termios = *tty->termios; /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. @@ -1731,8 +1729,7 @@ } wake_up_interruptible(&info->open_wait); } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| - ASYNC_CLOSING); + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); MOD_DEC_USE_COUNT; restore_flags(flags); @@ -1811,7 +1808,7 @@ shutdown(info); info->event = 0; state->count = 0; - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->flags &= ~ASYNC_NORMAL_ACTIVE; info->tty = 0; wake_up_interruptible(&info->open_wait); } @@ -1847,44 +1844,18 @@ } /* - * If this is a callout device, then just make sure the normal - * device isn't being used. - */ - if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) { - if (info->flags & ASYNC_NORMAL_ACTIVE) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_SESSION_LOCKOUT) && - (info->session != current->session)) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_PGRP_LOCKOUT) && - (info->pgrp != current->pgrp)) - return -EBUSY; - info->flags |= ASYNC_CALLOUT_ACTIVE; - return 0; - } - - /* * If non-blocking mode is set, or the port is not enabled, * then make the check up front and then exit. */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { - if (info->flags & ASYNC_CALLOUT_ACTIVE) - return -EBUSY; info->flags |= ASYNC_NORMAL_ACTIVE; return 0; } - if (info->flags & ASYNC_CALLOUT_ACTIVE) { - if (state->normal_termios.c_cflag & CLOCAL) - do_clocal = 1; - } else { - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - } - + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + /* * Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). While we are in @@ -1919,8 +1890,7 @@ #endif break; } - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - !(info->flags & ASYNC_CLOSING)) + if (!(info->flags & ASYNC_CLOSING)) break; if (signal_pending(current)) { retval = -ERESTARTSYS; @@ -2070,10 +2040,7 @@ if ((info->state->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver->subtype == SERIAL_TYPE_NORMAL) - *tty->termios = info->state->normal_termios; - else - *tty->termios = info->state->callout_termios; + *tty->termios = info->state->normal_termios; change_speed(info); } #ifdef CONFIG_SERIAL_CONSOLE @@ -2083,8 +2050,6 @@ change_speed(info); } #endif - info->session = current->session; - info->pgrp = current->pgrp; #ifdef SERIAL_DEBUG_OPEN baget_printk("rs_open %s successful...", tty->name); @@ -2393,21 +2358,8 @@ serial_driver.wait_until_sent = rs_wait_until_sent; serial_driver.read_proc = rs_read_proc; - /* - * The callout device is just like normal device except for - * major number and the subtype code. - */ - callout_driver = serial_driver; - callout_driver.name = "cua"; - callout_driver.major = TTYAUX_MAJOR; - callout_driver.subtype = SERIAL_TYPE_CALLOUT; - callout_driver.read_proc = 0; - callout_driver.proc_entry = 0; - if (tty_register_driver(&serial_driver)) panic("Couldn't register serial driver\n"); - if (tty_register_driver(&callout_driver)) - panic("Couldn't register callout driver\n"); for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { state->magic = SSTATE_MAGIC; @@ -2416,7 +2368,6 @@ state->custom_divisor = 0; state->close_delay = 5*HZ/10; state->closing_wait = 30*HZ; - state->callout_termios = callout_driver.init_termios; state->normal_termios = serial_driver.init_termios; state->icount.cts = state->icount.dsr = state->icount.rng = state->icount.dcd = 0; @@ -2533,9 +2484,6 @@ if ((e1 = tty_unregister_driver(&serial_driver))) printk("SERIAL: failed to unregister serial driver (%d)\n", e1); - if ((e2 = tty_unregister_driver(&callout_driver))) - printk("SERIAL: failed to unregister callout driver (%d)\n", - e2); restore_flags(flags); for (i = 0; i < NR_PORTS; i++) { diff -Nru a/arch/mips/ddb5074/pci.c b/arch/mips/ddb5074/pci.c --- a/arch/mips/ddb5074/pci.c Mon Jun 9 23:16:12 2003 +++ b/arch/mips/ddb5074/pci.c Mon Jun 9 23:16:12 2003 @@ -181,9 +181,9 @@ static void __init ddb5074_pci_fixup(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { if (dev->vendor == PCI_VENDOR_ID_NEC && dev->device == PCI_DEVICE_ID_NEC_NILE4) { /* @@ -227,10 +227,10 @@ static void __init pcibios_fixup_irqs(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; int slot_num; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { slot_num = PCI_SLOT(dev->devfn); switch (slot_num) { case 0: diff -Nru a/arch/mips/ddb5476/pci.c b/arch/mips/ddb5476/pci.c --- a/arch/mips/ddb5476/pci.c Mon Jun 9 23:16:10 2003 +++ b/arch/mips/ddb5476/pci.c Mon Jun 9 23:16:10 2003 @@ -187,9 +187,9 @@ static void __init ddb5476_pci_fixup(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { if (dev->vendor == PCI_VENDOR_ID_NEC && dev->device == PCI_DEVICE_ID_NEC_VRC5476) { /* @@ -256,10 +256,10 @@ static void __init pcibios_fixup_irqs(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; int slot_num; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { slot_num = PCI_SLOT(dev->devfn); switch (slot_num) { case 3: /* re-programmed to USB */ diff -Nru a/arch/mips/ddb5xxx/ddb5477/pci.c b/arch/mips/ddb5xxx/ddb5477/pci.c --- a/arch/mips/ddb5xxx/ddb5477/pci.c Mon Jun 9 23:16:12 2003 +++ b/arch/mips/ddb5xxx/ddb5477/pci.c Mon Jun 9 23:16:12 2003 @@ -98,10 +98,10 @@ extern int vrc5477_irq_to_irq(int irq); void __init pcibios_fixup_irqs(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; int slot_num; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { slot_num = PCI_SLOT(dev->devfn); MIPS_ASSERT(slot_num < MAX_SLOT_NUM); MIPS_ASSERT(irq_map[slot_num] != 0xff); diff -Nru a/arch/mips/dec/prom/Makefile b/arch/mips/dec/prom/Makefile --- a/arch/mips/dec/prom/Makefile Mon Jun 9 23:16:10 2003 +++ b/arch/mips/dec/prom/Makefile Mon Jun 9 23:16:10 2003 @@ -3,9 +3,7 @@ # under Linux. # -L_TARGET := lib.a - -obj-y := init.o memory.o cmdline.o identify.o locore.o +lib-y := init.o memory.o cmdline.o identify.o locore.o EXTRA_AFLAGS := $(CFLAGS) diff -Nru a/arch/mips/kernel/irq.c b/arch/mips/kernel/irq.c --- a/arch/mips/kernel/irq.c Mon Jun 9 23:16:07 2003 +++ b/arch/mips/kernel/irq.c Mon Jun 9 23:16:07 2003 @@ -24,8 +24,12 @@ /* * Controller mappings for all interrupt sources: */ -irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = - { [0 ... NR_IRQS-1] = { 0, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}}; +irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { + [0 ... NR_IRQS-1] = { + .handler = &no_irq_type, + .lock = SPIN_LOCK_UNLOCKED + } +}; /* * Special irq handlers. diff -Nru a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile --- a/arch/mips/lib/Makefile Mon Jun 9 23:16:07 2003 +++ b/arch/mips/lib/Makefile Mon Jun 9 23:16:07 2003 @@ -2,21 +2,19 @@ # Makefile for MIPS-specific library files.. # -L_TARGET = lib.a - EXTRA_AFLAGS := $(CFLAGS) -obj-y += csum_partial.o csum_partial_copy.o \ +lib-y += csum_partial.o csum_partial_copy.o \ rtc-std.o rtc-no.o memcpy.o memset.o \ watch.o strlen_user.o strncpy_user.o \ strnlen_user.o ifdef CONFIG_CPU_R3000 - obj-y += r3k_dump_tlb.o + lib-y += r3k_dump_tlb.o else - obj-y += dump_tlb.o + lib-y += dump_tlb.o endif -obj-$(CONFIG_BLK_DEV_FD) += floppy-no.o floppy-std.o -obj-$(CONFIG_IDE) += ide-std.o ide-no.o -obj-$(CONFIG_PC_KEYB) += kbd-std.o kbd-no.o +lib-$(CONFIG_BLK_DEV_FD) += floppy-no.o floppy-std.o +lib-$(CONFIG_IDE) += ide-std.o ide-no.o +lib-$(CONFIG_PC_KEYB) += kbd-std.o kbd-no.o diff -Nru a/arch/mips/mips-boards/generic/pci.c b/arch/mips/mips-boards/generic/pci.c --- a/arch/mips/mips-boards/generic/pci.c Mon Jun 9 23:16:10 2003 +++ b/arch/mips/mips-boards/generic/pci.c Mon Jun 9 23:16:10 2003 @@ -154,7 +154,7 @@ void __init pcibios_init(void) { #ifdef CONFIG_MIPS_MALTA - struct pci_dev *pdev; + struct pci_dev *pdev = NULL; unsigned char reg_val; #endif @@ -178,7 +178,7 @@ GT_WRITE( GT_PCI0_CFGDATA_OFS, PHYSADDR(MIPS_GT_BASE)); #ifdef CONFIG_MIPS_MALTA - pci_for_each_dev(pdev) { + while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { if ((pdev->vendor == PCI_VENDOR_ID_INTEL) && (pdev->device == PCI_DEVICE_ID_INTEL_82371AB) && (PCI_SLOT(pdev->devfn) == 0x0a)) { diff -Nru a/arch/mips/sni/pci.c b/arch/mips/sni/pci.c --- a/arch/mips/sni/pci.c Mon Jun 9 23:16:20 2003 +++ b/arch/mips/sni/pci.c Mon Jun 9 23:16:20 2003 @@ -31,9 +31,9 @@ /* To do: Bring this uptodate ... */ static void pcimt_pcibios_fixup (void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { /* * TODO: Take care of RM300 revision D boards for where the * network slot became an ordinary PCI slot. diff -Nru a/arch/mips64/arc/Makefile b/arch/mips64/arc/Makefile --- a/arch/mips64/arc/Makefile Mon Jun 9 23:16:19 2003 +++ b/arch/mips64/arc/Makefile Mon Jun 9 23:16:19 2003 @@ -2,9 +2,8 @@ # Makefile for the ARC prom monitor library routines under Linux. # -L_TARGET = lib.a -obj-y := console.o init.o identify.o tree.o env.o cmdline.o misc.o time.o \ +lib-y := console.o init.o identify.o tree.o env.o cmdline.o misc.o time.o \ file.o -obj-$(CONFIG_ARC_MEMORY) += memory.o -obj-$(CONFIG_ARC_CONSOLE) += arc_con.o +lib-$(CONFIG_ARC_MEMORY) += memory.o +lib-$(CONFIG_ARC_CONSOLE) += arc_con.o diff -Nru a/arch/mips64/lib/Makefile b/arch/mips64/lib/Makefile --- a/arch/mips64/lib/Makefile Mon Jun 9 23:16:17 2003 +++ b/arch/mips64/lib/Makefile Mon Jun 9 23:16:17 2003 @@ -4,9 +4,7 @@ EXTRA_AFLAGS := $(CFLAGS) -L_TARGET = lib.a - -obj-y += csum_partial.o csum_partial_copy.o dump_tlb.o floppy-std.o \ +lib-y += csum_partial.o csum_partial_copy.o dump_tlb.o floppy-std.o \ floppy-no.o ide-std.o ide-no.o kbd-std.o kbd-no.o rtc-std.o \ rtc-no.o memset.o memcpy.o strlen_user.o strncpy_user.o \ strnlen_user.o watch.o diff -Nru a/arch/mips64/mips-boards/generic/pci.c b/arch/mips64/mips-boards/generic/pci.c --- a/arch/mips64/mips-boards/generic/pci.c Mon Jun 9 23:16:07 2003 +++ b/arch/mips64/mips-boards/generic/pci.c Mon Jun 9 23:16:07 2003 @@ -213,7 +213,7 @@ void __init pcibios_init(void) { #ifdef CONFIG_MIPS_MALTA - struct pci_dev *pdev; + struct pci_dev *pdev = NULL; unsigned char reg_val; #endif @@ -237,7 +237,7 @@ GT_WRITE( GT_PCI0_CFGDATA_OFS, CPHYSADDR(MIPS_GT_BASE)); #ifdef CONFIG_MIPS_MALTA - pci_for_each_dev(pdev) { + while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { if ((pdev->vendor == PCI_VENDOR_ID_INTEL) && (pdev->device == PCI_DEVICE_ID_INTEL_82371AB) && (PCI_SLOT(pdev->devfn) == 0x0a)) { diff -Nru a/arch/mips64/sgi-ip22/Makefile b/arch/mips64/sgi-ip22/Makefile --- a/arch/mips64/sgi-ip22/Makefile Mon Jun 9 23:16:05 2003 +++ b/arch/mips64/sgi-ip22/Makefile Mon Jun 9 23:16:05 2003 @@ -5,7 +5,5 @@ EXTRA_AFLAGS := $(CFLAGS) -L_TARGET = lib.a - -obj-y += ip22-berr.o ip22-mc.o ip22-sc.o ip22-hpc.o ip22-int.o ip22-rtc.o \ +lib-y += ip22-berr.o ip22-mc.o ip22-sc.o ip22-hpc.o ip22-int.o ip22-rtc.o \ ip22-setup.o system.o ip22-timer.o ip22-irq.o ip22-reset.o time.o diff -Nru a/arch/mips64/sgi-ip32/ip32-pci.c b/arch/mips64/sgi-ip32/ip32-pci.c --- a/arch/mips64/sgi-ip32/ip32-pci.c Mon Jun 9 23:16:20 2003 +++ b/arch/mips64/sgi-ip32/ip32-pci.c Mon Jun 9 23:16:20 2003 @@ -125,7 +125,7 @@ void __init pcibios_init (void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; u32 start, size; u16 cmd; u32 base_io = 0x3000; /* The first i/o address to assign after SCSI */ @@ -157,7 +157,7 @@ pci_scan_bus (0, &macepci_ops, NULL); #ifdef DEBUG_MACE_PCI - pci_for_each_dev (dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { printk ("Device: %d/%d/%d ARCS-assigned bus resource map\n", dev->bus->number, PCI_SLOT (dev->devfn), PCI_FUNC (dev->devfn)); @@ -176,7 +176,8 @@ * which we must assign, and a 1-page memory region which is * assigned by the system firmware. */ - pci_for_each_dev (dev) { + dev = NULL; + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { switch (PCI_SLOT (dev->devfn)) { case 1: /* SCSI bus 0 */ dev->resource[0].start = 0x1000UL; @@ -230,7 +231,8 @@ printk ("Triggering PCI bridge interrupt...\n"); mace_write_32 (MACEPCI_ERROR_FLAGS, MACEPCI_ERROR_INTERRUPT_TEST); - pci_for_each_dev (dev) { + dev = NULL; + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { printk ("Device: %d/%d/%d final bus resource map\n", dev->bus->number, PCI_SLOT (dev->devfn), PCI_FUNC (dev->devfn)); diff -Nru a/arch/parisc/lib/Makefile b/arch/parisc/lib/Makefile --- a/arch/parisc/lib/Makefile Mon Jun 9 23:16:13 2003 +++ b/arch/parisc/lib/Makefile Mon Jun 9 23:16:13 2003 @@ -2,5 +2,4 @@ # Makefile for parisc-specific library files # -L_TARGET := lib.a -obj-y := lusercopy.o bitops.o checksum.o io.o memset.o +lib-y := lusercopy.o bitops.o checksum.o io.o memset.o diff -Nru a/arch/ppc/4xx_io/serial_sicc.c b/arch/ppc/4xx_io/serial_sicc.c --- a/arch/ppc/4xx_io/serial_sicc.c Mon Jun 9 23:16:05 2003 +++ b/arch/ppc/4xx_io/serial_sicc.c Mon Jun 9 23:16:05 2003 @@ -183,11 +183,6 @@ #define SERIAL_SICC_MINOR 1 #define SERIAL_SICC_NR 1 -#define CALLOUT_SICC_NAME "cuasicc" -#define CALLOUT_SICC_MAJOR 151 -#define CALLOUT_SICC_MINOR 1 -#define CALLOUT_SICC_NR SERIAL_SICC_NR - #ifndef TRUE #define TRUE 1 #endif @@ -202,7 +197,7 @@ /* * Things needed by tty driver */ -static struct tty_driver siccnormal_driver, sicccallout_driver; +static struct tty_driver siccnormal_driver; static int siccuart_refcount; static struct tty_struct *siccuart_table[SERIAL_SICC_NR]; static struct termios *siccuart_termios[SERIAL_SICC_NR]; @@ -275,8 +270,6 @@ unsigned int custom_divisor; unsigned int flags; struct termios normal_termios; - struct termios callout_termios; - int count; struct SICC_info *info; }; @@ -304,8 +297,6 @@ unsigned int lcr_h; unsigned int mctrl; int blocked_open; - pid_t session; - pid_t pgrp; struct tasklet_struct tlet; @@ -1487,8 +1478,6 @@ */ if (info->flags & ASYNC_NORMAL_ACTIVE) info->state->normal_termios = *tty->termios; - if (info->flags & ASYNC_CALLOUT_ACTIVE) - info->state->callout_termios = *tty->termios; /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. @@ -1524,8 +1513,7 @@ } wake_up_interruptible(&info->open_wait); } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| - ASYNC_CLOSING); + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); MOD_DEC_USE_COUNT; } @@ -1594,7 +1582,7 @@ siccuart_shutdown(info); info->event = 0; state->count = 0; - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->flags &= ~ASYNC_NORMAL_ACTIVE; info->tty = NULL; wake_up_interruptible(&info->open_wait); } @@ -1620,43 +1608,17 @@ } /* - * If this is a callout device, then just make sure the normal - * device isn't being used. - */ - if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) { - if (info->flags & ASYNC_NORMAL_ACTIVE) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_SESSION_LOCKOUT) && - (info->session != current->session)) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_PGRP_LOCKOUT) && - (info->pgrp != current->pgrp)) - return -EBUSY; - info->flags |= ASYNC_CALLOUT_ACTIVE; - return 0; - } - - /* * If non-blocking mode is set, or the port is not enabled, * then make the check up front and then exit. */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { - if (info->flags & ASYNC_CALLOUT_ACTIVE) - return -EBUSY; info->flags |= ASYNC_NORMAL_ACTIVE; return 0; } - if (info->flags & ASYNC_CALLOUT_ACTIVE) { - if (state->normal_termios.c_cflag & CLOCAL) - do_clocal = 1; - } else { - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - } + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; /* * Block waiting for the carrier detect and the line to become @@ -1676,8 +1638,7 @@ info->blocked_open++; while (1) { save_flags(flags); cli(); - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - (tty->termios->c_cflag & CBAUD)) { + if (tty->termios->c_cflag & CBAUD) { info->mctrl = TIOCM_DTR | TIOCM_RTS; info->port->set_mctrl(info->port, info->mctrl); } @@ -1691,8 +1652,7 @@ retval = -ERESTARTSYS; break; } - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - !(info->flags & ASYNC_CLOSING) && + if (!(info->flags & ASYNC_CLOSING) && (do_clocal /*|| (UART_GET_FR(info->port) & SICC_UARTFR_DCD)*/)) break; if (signal_pending(current)) { @@ -1803,12 +1763,7 @@ if ((info->state->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver->subtype == SERIAL_TYPE_NORMAL) { - *tty->termios = info->state->normal_termios; - } - else { - *tty->termios = info->state->callout_termios; - } + *tty->termios = info->state->normal_termios; } #ifdef CONFIG_SERIAL_SICC_CONSOLE if (siccuart_cons.cflag && siccuart_cons.index == line) { @@ -1817,8 +1772,6 @@ siccuart_change_speed(info, NULL); } #endif - info->session = current->session; - info->pgrp = current->pgrp; return 0; } @@ -1862,28 +1815,14 @@ siccnormal_driver.wait_until_sent = siccuart_wait_until_sent; siccnormal_driver.read_proc = NULL; - /* - * The callout device is just like the normal device except for - * the major number and the subtype code. - */ - sicccallout_driver = siccnormal_driver; - sicccallout_driver.name = CALLOUT_SICC_NAME; - sicccallout_driver.major = CALLOUT_SICC_MAJOR; - sicccallout_driver.subtype = SERIAL_TYPE_CALLOUT; - sicccallout_driver.read_proc = NULL; - sicccallout_driver.proc_entry = NULL; - if (tty_register_driver(&siccnormal_driver)) panic("Couldn't register SICC serial driver\n"); - if (tty_register_driver(&sicccallout_driver)) - panic("Couldn't register SICC callout driver\n"); for (i = 0; i < SERIAL_SICC_NR; i++) { struct SICC_state *state = sicc_state + i; state->line = i; state->close_delay = 5 * HZ / 10; state->closing_wait = 30 * HZ; - state->callout_termios = sicccallout_driver.init_termios; state->normal_termios = siccnormal_driver.init_termios; } diff -Nru a/arch/ppc/8260_io/enet.c b/arch/ppc/8260_io/enet.c --- a/arch/ppc/8260_io/enet.c Mon Jun 9 23:16:05 2003 +++ b/arch/ppc/8260_io/enet.c Mon Jun 9 23:16:05 2003 @@ -608,7 +608,7 @@ /* Initialize the CPM Ethernet on SCC. */ -int __init scc_enet_init(void) +static int __init scc_enet_init(void) { struct net_device *dev; struct scc_enet_private *cep; @@ -630,19 +630,15 @@ bd = (bd_t *)__res; - /* Allocate some private information. + /* Create an Ethernet device instance. */ - cep = (struct scc_enet_private *)kmalloc(sizeof(*cep), GFP_KERNEL); - if (cep == NULL) + dev = alloc_etherdev(sizeof(*cep)); + if (!dev) return -ENOMEM; - __clear_user(cep,sizeof(*cep)); + cep = dev->priv; spin_lock_init(&cep->lock); - /* Create an Ethernet device instance. - */ - dev = init_etherdev(0, 0); - /* Get pointer to SCC area in parameter RAM. */ ep = (scc_enet_t *)(&immap->im_dprambase[PROFF_ENET]); @@ -771,6 +767,7 @@ /* Allocate a page. */ mem_addr = __get_free_page(GFP_KERNEL); + /* BUG: no check for failure */ /* Initialize the BD for every fragment in the page. */ @@ -808,6 +805,7 @@ /* Install our interrupt handler. */ request_irq(SIU_INT_ENET, scc_enet_interrupt, 0, "enet", dev); + /* BUG: no check for failure */ /* Set GSMR_H to enable all normal operating modes. * Set GSMR_L to enable Ethernet to MC68160. @@ -837,7 +835,6 @@ io->iop_pdatc |= PC_EST8260_ENET_NOTFD; dev->base_addr = (unsigned long)ep; - dev->priv = cep; /* The CPM Ethernet specific entries in the device structure. */ dev->open = scc_enet_open; @@ -852,6 +849,12 @@ */ sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); + err = register_netdev(dev); + if (err) { + kfree(dev); + return err; + } + printk("%s: SCC ENET Version 0.1, ", dev->name); for (i=0; i<5; i++) printk("%02x:", dev->dev_addr[i]); @@ -860,3 +863,4 @@ return 0; } +module_init(scc_enet_init); diff -Nru a/arch/ppc/8260_io/fcc_enet.c b/arch/ppc/8260_io/fcc_enet.c --- a/arch/ppc/8260_io/fcc_enet.c Mon Jun 9 23:16:11 2003 +++ b/arch/ppc/8260_io/fcc_enet.c Mon Jun 9 23:16:11 2003 @@ -1323,12 +1323,12 @@ /* Initialize the CPM Ethernet on FCC. */ -int __init fec_enet_init(void) +static int __init fec_enet_init(void) { struct net_device *dev; struct fcc_enet_private *cep; fcc_info_t *fip; - int i, np; + int i, np, err; volatile immap_t *immap; volatile iop8260_t *io; @@ -1339,23 +1339,16 @@ fip = fcc_ports; while (np-- > 0) { - - /* Allocate some private information. + /* Create an Ethernet device instance. */ - cep = (struct fcc_enet_private *) - kmalloc(sizeof(*cep), GFP_KERNEL); - if (cep == NULL) + dev = alloc_etherdev(sizeof(*cep)); + if (!dev) return -ENOMEM; - __clear_user(cep,sizeof(*cep)); + cep = dev->priv; spin_lock_init(&cep->lock); cep->fip = fip; - /* Create an Ethernet device instance. - */ - dev = init_etherdev(0, 0); - dev->priv = cep; - init_fcc_shutdown(fip, cep, immap); init_fcc_ioports(fip, io, immap); init_fcc_param(fip, dev, immap); @@ -1376,6 +1369,12 @@ init_fcc_startup(fip, dev); + err = register_netdev(dev); + if (err) { + kfree(dev); + return err; + } + printk("%s: FCC ENET Version 0.3, ", dev->name); for (i=0; i<5; i++) printk("%02x:", dev->dev_addr[i]); @@ -1394,6 +1393,7 @@ return 0; } +module_init(fec_enet_init); /* Make sure the device is shut down during initialization. */ diff -Nru a/arch/ppc/8260_io/uart.c b/arch/ppc/8260_io/uart.c --- a/arch/ppc/8260_io/uart.c Mon Jun 9 23:16:07 2003 +++ b/arch/ppc/8260_io/uart.c Mon Jun 9 23:16:07 2003 @@ -74,7 +74,7 @@ static char *serial_name = "CPM UART driver"; static char *serial_version = "0.02"; -static struct tty_driver serial_driver, callout_driver; +static struct tty_driver serial_driver; static int serial_refcount; static int serial_console_setup(struct console *co, char *options); @@ -200,8 +200,6 @@ unsigned long event; unsigned long last_active; int blocked_open; /* # of blocked opens */ - long session; /* Session of opening process */ - long pgrp; /* pgrp of opening process */ struct work_struct tqueue; struct work_struct tqueue_hangup; wait_queue_head_t open_wait; @@ -531,8 +529,7 @@ #endif if (status & UART_MSR_DCD) wake_up_interruptible(&info->open_wait); - else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_CALLOUT_NOHUP))) { + else { #ifdef SERIAL_DEBUG_OPEN printk("scheduling hangup..."); #endif @@ -1667,8 +1664,6 @@ */ if (info->flags & ASYNC_NORMAL_ACTIVE) info->state->normal_termios = *tty->termios; - if (info->flags & ASYNC_CALLOUT_ACTIVE) - info->state->callout_termios = *tty->termios; /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. @@ -1716,8 +1711,7 @@ } wake_up_interruptible(&info->open_wait); } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| - ASYNC_CLOSING); + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); MOD_DEC_USE_COUNT; restore_flags(flags); @@ -1799,7 +1793,7 @@ shutdown(info); info->event = 0; state->count = 0; - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->flags &= ~ASYNC_NORMAL_ACTIVE; info->tty = 0; wake_up_interruptible(&info->open_wait); } @@ -1838,25 +1832,6 @@ } /* - * If this is a callout device, then just make sure the normal - * device isn't being used. - */ - if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) { - if (info->flags & ASYNC_NORMAL_ACTIVE) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_SESSION_LOCKOUT) && - (info->session != current->session)) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_PGRP_LOCKOUT) && - (info->pgrp != current->pgrp)) - return -EBUSY; - info->flags |= ASYNC_CALLOUT_ACTIVE; - return 0; - } - - /* * If non-blocking mode is set, or the port is not enabled, * then make the check up front and then exit. * If this is an SMC port, we don't have modem control to wait @@ -1865,20 +1840,13 @@ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR)) || (info->state->smc_scc_num < SCC_NUM_BASE)) { - if (info->flags & ASYNC_CALLOUT_ACTIVE) - return -EBUSY; info->flags |= ASYNC_NORMAL_ACTIVE; return 0; } - if (info->flags & ASYNC_CALLOUT_ACTIVE) { - if (state->normal_termios.c_cflag & CLOCAL) - do_clocal = 1; - } else { - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - } - + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + /* * Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). While we are in @@ -1900,8 +1868,7 @@ info->blocked_open++; while (1) { cli(); - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - (tty->termios->c_cflag & CBAUD)) + if (tty->termios->c_cflag & CBAUD) serial_out(info, UART_MCR, serial_inp(info, UART_MCR) | (UART_MCR_DTR | UART_MCR_RTS)); @@ -1919,8 +1886,7 @@ #endif break; } - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - !(info->flags & ASYNC_CLOSING) && + if (!(info->flags & ASYNC_CLOSING) && (do_clocal || (serial_in(info, UART_MSR) & UART_MSR_DCD))) break; @@ -2010,16 +1976,10 @@ if ((info->state->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver->subtype == SERIAL_TYPE_NORMAL) - *tty->termios = info->state->normal_termios; - else - *tty->termios = info->state->callout_termios; + *tty->termios = info->state->normal_termios; change_speed(info); } - info->session = current->session; - info->pgrp = current->pgrp; - #ifdef SERIAL_DEBUG_OPEN printk("rs_open %s successful...", line); #endif @@ -2507,11 +2467,8 @@ __clear_user(&serial_driver,sizeof(struct tty_driver)); serial_driver.magic = TTY_DRIVER_MAGIC; serial_driver.driver_name = "serial"; -#ifdef CONFIG_DEVFS_FS - serial_driver.name = "tts/"; -#else + serial_driver.devfs_name = "tts/"; serial_driver.name = "ttyS"; -#endif serial_driver.major = TTY_MAJOR; serial_driver.minor_start = 64; serial_driver.num = NR_PORTS; @@ -2544,26 +2501,9 @@ serial_driver.wait_until_sent = rs_8xx_wait_until_sent; serial_driver.read_proc = rs_8xx_read_proc; - /* - * The callout device is just like normal device except for - * major number and the subtype code. - */ - callout_driver = serial_driver; -#ifdef CONFIG_DEVFS_FS - callout_driver.name = "cua/"; -#else - callout_driver.name = "cua"; -#endif - callout_driver.major = TTYAUX_MAJOR; - callout_driver.subtype = SERIAL_TYPE_CALLOUT; - callout_driver.read_proc = 0; - callout_driver.proc_entry = 0; - if (tty_register_driver(&serial_driver)) panic("Couldn't register serial driver\n"); - if (tty_register_driver(&callout_driver)) - panic("Couldn't register callout driver\n"); - + immap = immr; cp = &immap->im_cpm; io = &immap->im_ioport; @@ -2644,7 +2584,6 @@ state->custom_divisor = 0; state->close_delay = 5*HZ/10; state->closing_wait = 30*HZ; - state->callout_termios = callout_driver.init_termios; state->normal_termios = serial_driver.init_termios; state->icount.cts = state->icount.dsr = state->icount.rng = state->icount.dcd = 0; diff -Nru a/arch/ppc/8xx_io/enet.c b/arch/ppc/8xx_io/enet.c --- a/arch/ppc/8xx_io/enet.c Mon Jun 9 23:16:09 2003 +++ b/arch/ppc/8xx_io/enet.c Mon Jun 9 23:16:09 2003 @@ -639,11 +639,11 @@ * transmit and receive to make sure we don't catch the CPM with some * inconsistent control information. */ -int __init scc_enet_init(void) +static int __init scc_enet_init(void) { struct net_device *dev; struct scc_enet_private *cep; - int i, j, k; + int i, j, k, err; unsigned char *eap, *ba; dma_addr_t mem_addr; bd_t *bd; @@ -659,19 +659,13 @@ bd = (bd_t *)__res; - /* Allocate some private information. - */ - cep = (struct scc_enet_private *)kmalloc(sizeof(*cep), GFP_KERNEL); - if (cep == NULL) + dev = alloc_etherdev(sizeof(*cep)); + if (!dev) return -ENOMEM; - __clear_user(cep,sizeof(*cep)); + cep = dev->priv; spin_lock_init(&cep->lock); - /* Create an Ethernet device instance. - */ - dev = init_etherdev(0, 0); - /* Get pointer to SCC area in parameter RAM. */ ep = (scc_enet_t *)(&cp->cp_dparam[PROFF_ENET]); @@ -841,6 +835,7 @@ /* Allocate a page. */ ba = (unsigned char *)consistent_alloc(GFP_KERNEL, PAGE_SIZE, &mem_addr); + /* BUG: no check for failure */ /* Initialize the BD for every fragment in the page. */ @@ -939,7 +934,6 @@ #endif dev->base_addr = (unsigned long)ep; - dev->priv = cep; #if 0 dev->name = "CPM_ENET"; #endif @@ -953,6 +947,12 @@ dev->get_stats = scc_enet_get_stats; dev->set_multicast_list = set_multicast_list; + err = register_netdev(dev); + if (err) { + kfree(dev); + return err; + } + /* And last, enable the transmit and receive processing. */ sccp->scc_gsmrl |= (SCC_GSMRL_ENR | SCC_GSMRL_ENT); @@ -964,3 +964,5 @@ return 0; } + +module_init(scc_enet_init); diff -Nru a/arch/ppc/8xx_io/fec.c b/arch/ppc/8xx_io/fec.c --- a/arch/ppc/8xx_io/fec.c Mon Jun 9 23:16:19 2003 +++ b/arch/ppc/8xx_io/fec.c Mon Jun 9 23:16:19 2003 @@ -1566,11 +1566,11 @@ /* Initialize the FEC Ethernet on 860T. */ -int __init fec_enet_init(void) +static int __init fec_enet_init(void) { struct net_device *dev; struct fec_enet_private *fep; - int i, j, k; + int i, j, k, err; unsigned char *eap, *iap, *ba; unsigned long mem_addr; volatile cbd_t *bdp; @@ -1586,17 +1586,11 @@ bd = (bd_t *)__res; - /* Allocate some private information. - */ - fep = (struct fec_enet_private *)kmalloc(sizeof(*fep), GFP_KERNEL); - if (fep == NULL) + dev = alloc_etherdev(sizeof(*fep)); + if (!dev) return -ENOMEM; - __clear_user(fep,sizeof(*fep)); - - /* Create an Ethernet device instance. - */ - dev = init_etherdev(0, 0); + fep = dev->priv; fecp = &(immap->im_cpm.cp_fec); @@ -1661,6 +1655,7 @@ /* Allocate a page. */ ba = (unsigned char *)consistent_alloc(GFP_KERNEL, PAGE_SIZE, &mem_addr); + /* BUG: no check for failure */ /* Initialize the BD for every fragment in the page. */ @@ -1715,7 +1710,6 @@ #endif dev->base_addr = (unsigned long)fecp; - dev->priv = fep; /* The FEC Ethernet specific entries in the device structure. */ dev->open = fec_enet_open; @@ -1752,6 +1746,12 @@ fecp->fec_mii_speed = 0; /* turn off MDIO */ #endif /* CONFIG_USE_MDIO */ + err = register_netdev(dev); + if (err) { + kfree(dev); + return err; + } + printk ("%s: FEC ENET Version 0.2, FEC irq %d" #ifdef PHY_INTERRUPT ", MII irq %d" @@ -1782,6 +1782,7 @@ return 0; } +module_init(fec_enet_init); /* This function is called to start or restart the FEC during a link * change. This only happens when switching between half and full diff -Nru a/arch/ppc/8xx_io/uart.c b/arch/ppc/8xx_io/uart.c --- a/arch/ppc/8xx_io/uart.c Mon Jun 9 23:16:16 2003 +++ b/arch/ppc/8xx_io/uart.c Mon Jun 9 23:16:16 2003 @@ -85,7 +85,7 @@ static DECLARE_TASK_QUEUE(tq_serial); -static struct tty_driver serial_driver, callout_driver; +static struct tty_driver serial_driver; static int serial_refcount; static int serial_console_setup(struct console *co, char *options); @@ -199,8 +199,6 @@ unsigned long event; unsigned long last_active; int blocked_open; /* # of blocked opens */ - long session; /* Session of opening process */ - long pgrp; /* pgrp of opening process */ struct tq_struct tqueue; struct tq_struct tqueue_hangup; wait_queue_head_t open_wait; @@ -590,8 +588,7 @@ #endif if (status & UART_MSR_DCD) wake_up_interruptible(&info->open_wait); - else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_CALLOUT_NOHUP))) { + else { #ifdef SERIAL_DEBUG_OPEN printk("scheduling hangup..."); #endif @@ -1714,8 +1711,6 @@ */ if (info->flags & ASYNC_NORMAL_ACTIVE) info->state->normal_termios = *tty->termios; - if (info->flags & ASYNC_CALLOUT_ACTIVE) - info->state->callout_termios = *tty->termios; /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. @@ -1764,8 +1759,7 @@ } wake_up_interruptible(&info->open_wait); } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| - ASYNC_CLOSING); + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); MOD_DEC_USE_COUNT; restore_flags(flags); @@ -1858,7 +1852,7 @@ shutdown(info); info->event = 0; state->count = 0; - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->flags &= ~ASYNC_NORMAL_ACTIVE; info->tty = 0; wake_up_interruptible(&info->open_wait); } @@ -1897,25 +1891,6 @@ } /* - * If this is a callout device, then just make sure the normal - * device isn't being used. - */ - if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) { - if (info->flags & ASYNC_NORMAL_ACTIVE) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_SESSION_LOCKOUT) && - (info->session != current->session)) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_PGRP_LOCKOUT) && - (info->pgrp != current->pgrp)) - return -EBUSY; - info->flags |= ASYNC_CALLOUT_ACTIVE; - return 0; - } - - /* * If non-blocking mode is set, or the port is not enabled, * then make the check up front and then exit. * If this is an SMC port, we don't have modem control to wait @@ -1924,20 +1899,13 @@ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR)) || !(info->state->smc_scc_num & NUM_IS_SCC)) { - if (info->flags & ASYNC_CALLOUT_ACTIVE) - return -EBUSY; info->flags |= ASYNC_NORMAL_ACTIVE; return 0; } - if (info->flags & ASYNC_CALLOUT_ACTIVE) { - if (state->normal_termios.c_cflag & CLOCAL) - do_clocal = 1; - } else { - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - } - + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + /* * Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). While we are in @@ -1959,8 +1927,7 @@ info->blocked_open++; while (1) { cli(); - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - (tty->termios->c_cflag & CBAUD)) + if ((tty->termios->c_cflag & CBAUD)) serial_out(info, UART_MCR, serial_inp(info, UART_MCR) | (UART_MCR_DTR | UART_MCR_RTS)); @@ -1978,8 +1945,7 @@ #endif break; } - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - !(info->flags & ASYNC_CLOSING) && + if (!(info->flags & ASYNC_CLOSING) && (do_clocal || (serial_in(info, UART_MSR) & UART_MSR_DCD))) break; @@ -2070,16 +2036,10 @@ if ((info->state->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver->subtype == SERIAL_TYPE_NORMAL) - *tty->termios = info->state->normal_termios; - else - *tty->termios = info->state->callout_termios; + *tty->termios = info->state->normal_termios; change_speed(info); } - info->session = current->session; - info->pgrp = current->pgrp; - #ifdef SERIAL_DEBUG_OPEN printk("rs_open %s successful...", tty->name); #endif @@ -2560,11 +2520,8 @@ __clear_user(&serial_driver,sizeof(struct tty_driver)); serial_driver.magic = TTY_DRIVER_MAGIC; serial_driver.driver_name = "serial"; -#ifdef CONFIG_DEVFS_FS - serial_driver.name = "tts/"; -#else + serial_driver.devfs_name = "tts/"; serial_driver.name = "ttyS"; -#endif serial_driver.major = TTY_MAJOR; serial_driver.minor_start = 64; serial_driver.num = NR_PORTS; @@ -2597,25 +2554,8 @@ serial_driver.wait_until_sent = rs_8xx_wait_until_sent; serial_driver.read_proc = rs_8xx_read_proc; - /* - * The callout device is just like normal device except for - * major number and the subtype code. - */ - callout_driver = serial_driver; -#ifdef CONFIG_DEVFS_FS - callout_driver.name = "cua/"; -#else - callout_driver.name = "cua"; -#endif - callout_driver.major = TTYAUX_MAJOR; - callout_driver.subtype = SERIAL_TYPE_CALLOUT; - callout_driver.read_proc = 0; - callout_driver.proc_entry = 0; - if (tty_register_driver(&serial_driver)) panic("Couldn't register serial driver\n"); - if (tty_register_driver(&callout_driver)) - panic("Couldn't register callout driver\n"); cp = cpmp; /* Get pointer to Communication Processor */ immap = (immap_t *)IMAP_ADDR; /* and to internal registers */ @@ -2675,7 +2615,6 @@ state->custom_divisor = 0; state->close_delay = 5*HZ/10; state->closing_wait = 30*HZ; - state->callout_termios = callout_driver.init_termios; state->normal_termios = serial_driver.init_termios; state->icount.cts = state->icount.dsr = state->icount.rng = state->icount.dcd = 0; diff -Nru a/arch/ppc/Kconfig b/arch/ppc/Kconfig --- a/arch/ppc/Kconfig Mon Jun 9 23:16:19 2003 +++ b/arch/ppc/Kconfig Mon Jun 9 23:16:19 2003 @@ -97,32 +97,6 @@ depends on POWER3 default y -config ALL_PPC - bool - depends on ALL_PPC_CH || POWER3 - default y - ---help--- - Linux currently supports several different kinds of PowerPC-based - machines: Apple Power Macintoshes and clones (such as the Motorola - Starmax series), PReP (PowerPC Reference Platform) machines (such - as the Motorola PowerStacks, Motorola cPCI/VME embedded systems, - and some IBM RS/6000 systems), CHRP (Common Hardware Reference - Platform) machines (including all of the recent IBM RS/6000 and - pSeries machines), and several embedded PowerPC systems containing - 4xx, 6xx, 7xx, 8xx, 74xx, and 82xx processors. Currently, the - default option is to build a kernel which works on the first three. - - Select CHRP/PowerMac/PReP if configuring for an IBM RS/6000 or - pSeries machine, a Power Macintosh (including iMacs, iBooks and - Powerbooks), or a PReP machine. - - Select Gemini if configuring for a Synergy Microsystems' Gemini - series Single Board Computer. More information is available at: - <http://www.synergymicro.com/PressRel/97_10_15.html>. - - Select APUS if configuring for a PowerUP Amiga. More information is - available at: <http://linux-apus.sourceforge.net/>. - config PPC_STD_MMU bool depends on 6xx || POWER3 @@ -424,12 +398,34 @@ bool depends on 8xx || 8260 default y + choice prompt "Machine Type" - depends on 6xx && !8260 - default ALL_PPC_CH + depends on (6xx || POWER3) && !8260 + default PPC_MULTIPLATFORM + ---help--- + Linux currently supports several different kinds of PowerPC-based + machines: Apple Power Macintoshes and clones (such as the Motorola + Starmax series), PReP (PowerPC Reference Platform) machines (such + as the Motorola PowerStacks, Motorola cPCI/VME embedded systems, + and some IBM RS/6000 systems), CHRP (Common Hardware Reference + Platform) machines (including all of the recent IBM RS/6000 and + pSeries machines), and several embedded PowerPC systems containing + 4xx, 6xx, 7xx, 8xx, 74xx, and 82xx processors. Currently, the + default option is to build a kernel which works on the first three. -config ALL_PPC_CH + Select CHRP/PowerMac/PReP if configuring for an IBM RS/6000 or + pSeries machine, a Power Macintosh (including iMacs, iBooks and + Powerbooks), or a PReP machine. + + Select Gemini if configuring for a Synergy Microsystems' Gemini + series Single Board Computer. More information is available at: + <http://www.synergymicro.com/PressRel/97_10_15.html>. + + Select APUS if configuring for a PowerUP Amiga. More information is + available at: <http://linux-apus.sourceforge.net/>. + +config PPC_MULTIPLATFORM bool "CHRP/PowerMac/PReP" config APUS @@ -499,6 +495,26 @@ endchoice +config PPC_CHRP + bool + depends on PPC_MULTIPLATFORM + default y + +config PPC_PMAC + bool + depends on PPC_MULTIPLATFORM + default y + +config PPC_PREP + bool + depends on PPC_MULTIPLATFORM + default y + +config PPC_OF + bool + depends on PPC_PMAC || PPC_CHRP + default y + config SANDPOINT_X3 bool "Sandpoint X3" depends on SANDPOINT @@ -721,7 +737,7 @@ config ISA bool "Support for ISA-bus hardware" - depends on ALL_PPC + depends on PREP || CHRP help Find out whether you have ISA slots on your motherboard. ISA is the name of a bus system, i.e. the way the CPU talks to the other stuff @@ -851,7 +867,7 @@ config PPC601_SYNC_FIX bool "Workarounds for PPC601 bugs" - depends on ALL_PPC && !POWER3 + depends on 6xx && !POWER3 help Some versions of the PPC601 (the first PowerPC chip) have bugs which mean that extra synchronization instructions are required near @@ -865,7 +881,7 @@ config PROC_DEVICETREE bool "Support for Open Firmware device tree in /proc" - depends on ALL_PPC && PROC_FS + depends on PPC_OF && PROC_FS help This option adds a device-tree directory under /proc which contains an image of the device tree that the kernel copies from Open @@ -873,7 +889,7 @@ config PPC_RTAS bool "Support for RTAS (RunTime Abstraction Services) in /proc" - depends on ALL_PPC && PROC_FS + depends on PPC_OF && PROC_FS ---help--- When you use this option, you will be able to use RTAS from userspace. @@ -906,7 +922,7 @@ config PREP_RESIDUAL bool "Support for PReP Residual Data" - depends on ALL_PPC + depends on PPC_PREP help Some PReP systems have residual data passed to the kernel by the firmware. This allows detection of memory size, devices present and @@ -927,7 +943,7 @@ config PPCBUG_NVRAM bool "Enable reading PPCBUG NVRAM during boot" if PPLUS || LOPEC - default y if ALL_PPC + default y if PPC_PREP config CMDLINE_BOOL bool "Default bootloader kernel arguments" @@ -1156,7 +1172,7 @@ config BOOT_LOAD_BOOL bool "Set the boot link/load address" - depends on ADVANCED_OPTIONS && !ALL_PPC + depends on ADVANCED_OPTIONS && !PPC_MULTIPLATFORM help This option allows you to set the initial load address of the zImage or zImage.initrd file. This can be useful if you are on a board @@ -1292,7 +1308,7 @@ # we want to change this to something like CONFIG_SYSCTRL_CUDA/PMU config ADB_CUDA bool "Support for CUDA based PowerMacs" - depends on ALL_PPC + depends on PPC_PMAC help This provides support for CUDA based Power Macintosh systems. This includes most OldWorld PowerMacs, the first generation iMacs, the @@ -1304,7 +1320,7 @@ config ADB_PMU bool "Support for PMU based PowerMacs" - depends on ALL_PPC + depends on PPC_PMAC help On PowerBooks, iBooks, and recent iMacs and Power Macintoshes, the PMU is an embedded microprocessor whose primary function is to @@ -1336,7 +1352,7 @@ config PM bool - depends on ALL_PPC && ADB_PMU && PMAC_PBOOK + depends on PPC_PMAC && ADB_PMU && PMAC_PBOOK default y config PMAC_APM_EMU @@ -1357,14 +1373,14 @@ config MAC_FLOPPY bool "Support for PowerMac floppy" - depends on ALL_PPC + depends on PPC_PMAC help If you have a SWIM-3 (Super Woz Integrated Machine 3; from Apple) floppy controller, say Y here. Most commonly found in PowerMacs. config MAC_SERIAL tristate "Support for PowerMac serial ports" - depends on ALL_PPC + depends on PPC_PMAC help If you have Macintosh style serial ports (8 pin mini-DIN), say Y here. If you also have regular serial ports and enable the driver @@ -1372,11 +1388,11 @@ config SERIAL_CONSOLE bool "Support for console on serial port" - depends on ALL_PPC && MAC_SERIAL=y + depends on PPC_PMAC && MAC_SERIAL=y config ADB bool "Apple Desktop Bus (ADB) support" - depends on ALL_PPC + depends on PPC_PMAC help Apple Desktop Bus (ADB) support is for support of devices which are connected to an ADB port. ADB devices tend to have 4 pins. @@ -1610,7 +1626,7 @@ config BOOTX_TEXT bool "Support for early boot text console (BootX or OpenFirmware only)" - depends on ALL_PPC + depends PPC_OF help Say Y here to see progress messages from the boot firmware in text mode. Requires either BootX or Open Firmware. diff -Nru a/arch/ppc/boot/Makefile b/arch/ppc/boot/Makefile --- a/arch/ppc/boot/Makefile Mon Jun 9 23:16:14 2003 +++ b/arch/ppc/boot/Makefile Mon Jun 9 23:16:14 2003 @@ -16,9 +16,10 @@ BOOT_TARGETS = zImage zImage.initrd znetboot znetboot.initrd bootdir-y := simple -bootdir-$(CONFIG_ALL_PPC) := openfirmware prep +bootdir-$(CONFIG_PPC_OF) := openfirmware +bootdir-$(CONFIG_PPC_PREP) += prep subdir-y := lib/ common/ images/ -subdir-$(CONFIG_ALL_PPC) += of1275/ +subdir-$(CONFIG_PPC_OF) += of1275/ # for cleaning subdir- += simple/ openfirmware/ prep/ diff -Nru a/arch/ppc/boot/common/Makefile b/arch/ppc/boot/common/Makefile --- a/arch/ppc/boot/common/Makefile Mon Jun 9 23:16:14 2003 +++ b/arch/ppc/boot/common/Makefile Mon Jun 9 23:16:14 2003 @@ -8,10 +8,8 @@ # Tom Rini January 2001 # -L_TARGET := lib.a - -obj-y := string.o util.o misc-common.o -obj-$(CONFIG_ALL_PPC) += mpc10x_memory.o -obj-$(CONFIG_LOPEC) += mpc10x_memory.o -obj-$(CONFIG_PAL4) += cpc700_memory.o -obj-$(CONFIG_SERIAL_8250_CONSOLE) += ns16550.o +lib-y := string.o util.o misc-common.o +lib-$(CONFIG_PPC_PREP) += mpc10x_memory.o +lib-$(CONFIG_LOPEC) += mpc10x_memory.o +lib-$(CONFIG_PAL4) += cpc700_memory.o +lib-$(CONFIG_SERIAL_8250_CONSOLE) += ns16550.o diff -Nru a/arch/ppc/boot/common/misc-common.c b/arch/ppc/boot/common/misc-common.c --- a/arch/ppc/boot/common/misc-common.c Mon Jun 9 23:16:12 2003 +++ b/arch/ppc/boot/common/misc-common.c Mon Jun 9 23:16:12 2003 @@ -20,10 +20,10 @@ #include "zlib.h" #include "nonstdio.h" -/* If we're on a ALL_PPC, assume we have a keyboard controller - * Also note, if we're not ALL_PPC, we assume you are a serial +/* If we're on a PReP, assume we have a keyboard controller + * Also note, if we're not PReP, we assume you are a serial * console - Tom */ -#if defined(CONFIG_ALL_PPC) && defined(CONFIG_VGA_CONSOLE) +#if defined(CONFIG_PPC_PREP) && defined(CONFIG_VGA_CONSOLE) extern void cursor(int x, int y); extern void scroll(void); extern char *vidmem; diff -Nru a/arch/ppc/boot/common/mpc10x_memory.c b/arch/ppc/boot/common/mpc10x_memory.c --- a/arch/ppc/boot/common/mpc10x_memory.c Mon Jun 9 23:16:09 2003 +++ b/arch/ppc/boot/common/mpc10x_memory.c Mon Jun 9 23:16:09 2003 @@ -50,7 +50,7 @@ /* * Read the memory controller registers to determine the amount of memory in * the system. This assumes that the firmware has correctly set up the memory - * controller registers. On CONFIG_ALL_PPC, we know we are being called + * controller registers. On CONFIG_PPC_PREP, we know we are being called * under a PReP memory map. On all other machines, we assume we are under * a CHRP memory map. */ @@ -62,7 +62,7 @@ int i; unsigned char bank_enables; -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PREP config_addr = (unsigned int *)MPC10X_MAPA_CNFG_ADDR; config_data = (unsigned int *)MPC10X_MAPA_CNFG_DATA; #else diff -Nru a/arch/ppc/boot/ld.script b/arch/ppc/boot/ld.script --- a/arch/ppc/boot/ld.script Mon Jun 9 23:16:15 2003 +++ b/arch/ppc/boot/ld.script Mon Jun 9 23:16:15 2003 @@ -1,7 +1,4 @@ OUTPUT_ARCH(powerpc) -SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/local/powerpc-any-elf/lib); -/* Do we need any of these for elf? - __DYNAMIC = 0; */ SECTIONS { /* Read-only sections, merged into text segment: */ @@ -80,4 +77,11 @@ } _end = . ; PROVIDE (end = .); + + /DISCARD/ : { + *(__ksymtab) + *(__ksymtab_strings) + *(__bug_table) + } + } diff -Nru a/arch/ppc/boot/lib/Makefile b/arch/ppc/boot/lib/Makefile --- a/arch/ppc/boot/lib/Makefile Mon Jun 9 23:16:17 2003 +++ b/arch/ppc/boot/lib/Makefile Mon Jun 9 23:16:17 2003 @@ -2,6 +2,4 @@ # Makefile for some libs needed by zImage. # -L_TARGET := lib.a - -obj-y := zlib.o div64.o +lib-y := zlib.o div64.o diff -Nru a/arch/ppc/boot/lib/zlib.c b/arch/ppc/boot/lib/zlib.c --- a/arch/ppc/boot/lib/zlib.c Mon Jun 9 23:16:09 2003 +++ b/arch/ppc/boot/lib/zlib.c Mon Jun 9 23:16:09 2003 @@ -299,8 +299,9 @@ }; -int inflateReset(z) -z_stream *z; +int inflateReset( + z_stream *z +) { uLong c; @@ -315,8 +316,9 @@ } -int inflateEnd(z) -z_stream *z; +int inflateEnd( + z_stream *z +) { uLong c; @@ -331,9 +333,10 @@ } -int inflateInit2(z, w) -z_stream *z; -int w; +int inflateInit2( + z_stream *z, + int w +) { /* initialize state */ if (z == Z_NULL) @@ -377,8 +380,9 @@ } -int inflateInit(z) -z_stream *z; +int inflateInit( + z_stream *z +) { return inflateInit2(z, DEF_WBITS); } @@ -387,9 +391,10 @@ #define NEEDBYTE {if(z->avail_in==0)goto empty;r=Z_OK;} #define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) -int inflate(z, f) -z_stream *z; -int f; +int inflate( + z_stream *z, + int f +) { int r; uInt b; @@ -504,8 +509,9 @@ * will have been updated if need be. */ -int inflateIncomp(z) -z_stream *z; +int inflateIncomp( + z_stream *z +) { if (z->state->mode != BLOCKS) return Z_DATA_ERROR; @@ -513,8 +519,9 @@ } -int inflateSync(z) -z_stream *z; +int inflateSync( + z_stream *z +) { uInt n; /* number of bytes to look at */ Bytef *p; /* pointer to bytes */ @@ -737,10 +744,11 @@ */ -local void inflate_blocks_reset(s, z, c) -inflate_blocks_statef *s; -z_stream *z; -uLongf *c; +local void inflate_blocks_reset( + inflate_blocks_statef *s, + z_stream *z, + uLongf *c +) { if (s->checkfn != Z_NULL) *c = s->check; @@ -762,10 +770,11 @@ } -local inflate_blocks_statef *inflate_blocks_new(z, c, w) -z_stream *z; -check_func c; -uInt w; +local inflate_blocks_statef *inflate_blocks_new( + z_stream *z, + check_func c, + uInt w +) { inflate_blocks_statef *s; @@ -786,10 +795,11 @@ } -local int inflate_blocks(s, z, r) -inflate_blocks_statef *s; -z_stream *z; -int r; +local int inflate_blocks( + inflate_blocks_statef *s, + z_stream *z, + int r +) { uInt t; /* temporary storage */ uLong b; /* bit buffer */ @@ -1049,10 +1059,11 @@ } -local int inflate_blocks_free(s, z, c) -inflate_blocks_statef *s; -z_stream *z; -uLongf *c; +local int inflate_blocks_free( + inflate_blocks_statef *s, + z_stream *z, + uLongf *c +) { inflate_blocks_reset(s, z, c); ZFREE(z, s->window, s->end - s->window); @@ -1069,9 +1080,10 @@ * BLOCKS). On exit, the output will also be caught up, and the checksum * will have been updated if need be. */ -local int inflate_addhistory(s, z) -inflate_blocks_statef *s; -z_stream *z; +local int inflate_addhistory( + inflate_blocks_statef *s, + z_stream *z +) { uLong b; /* bit buffer */ /* NOT USED HERE */ uInt k; /* bits in bit buffer */ /* NOT USED HERE */ @@ -1119,8 +1131,9 @@ * At the end of a Deflate-compressed PPP packet, we expect to have seen * a `stored' block type value but not the (zero) length bytes. */ -local int inflate_packet_flush(s) - inflate_blocks_statef *s; +local int inflate_packet_flush( + inflate_blocks_statef *s +) { if (s->mode != LENS) return Z_DATA_ERROR; @@ -1220,15 +1233,16 @@ uInt inflate_hufts; #endif -local int huft_build(b, n, s, d, e, t, m, zs) -uIntf *b; /* code lengths in bits (all assumed <= BMAX) */ -uInt n; /* number of codes (assumed <= N_MAX) */ -uInt s; /* number of simple-valued codes (0..s-1) */ -uIntf *d; /* list of base values for non-simple codes */ -uIntf *e; /* list of extra bits for non-simple codes */ -inflate_huft * FAR *t; /* result: starting table */ -uIntf *m; /* maximum lookup bits, returns actual */ -z_stream *zs; /* for zalloc function */ +local int huft_build( + uIntf *b, /* code lengths in bits (all assumed <= BMAX) */ + uInt n, /* number of codes (assumed <= N_MAX) */ + uInt s, /* number of simple-valued codes (0..s-1) */ + uIntf *d, /* list of base values for non-simple codes */ + uIntf *e, /* list of extra bits for non-simple codes */ + inflate_huft * FAR *t, /* result: starting table */ + uIntf *m, /* maximum lookup bits, returns actual */ + z_stream *zs /* for zalloc function */ +) /* Given a list of code lengths and a maximum table size, make a set of tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR if the given code set is incomplete (the tables are still built in this @@ -1423,11 +1437,12 @@ } -local int inflate_trees_bits(c, bb, tb, z) -uIntf *c; /* 19 code lengths */ -uIntf *bb; /* bits tree desired/actual depth */ -inflate_huft * FAR *tb; /* bits tree result */ -z_stream *z; /* for zfree function */ +local int inflate_trees_bits( + uIntf *c, /* 19 code lengths */ + uIntf *bb, /* bits tree desired/actual depth */ + inflate_huft * FAR *tb, /* bits tree result */ + z_stream *z /* for zfree function */ +) { int r; @@ -1444,15 +1459,16 @@ } -local int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, z) -uInt nl; /* number of literal/length codes */ -uInt nd; /* number of distance codes */ -uIntf *c; /* that many (total) code lengths */ -uIntf *bl; /* literal desired/actual bit depth */ -uIntf *bd; /* distance desired/actual bit depth */ -inflate_huft * FAR *tl; /* literal/length tree result */ -inflate_huft * FAR *td; /* distance tree result */ -z_stream *z; /* for zfree function */ +local int inflate_trees_dynamic( + uInt nl, /* number of literal/length codes */ + uInt nd, /* number of distance codes */ + uIntf *c, /* that many (total) code lengths */ + uIntf *bl, /* literal desired/actual bit depth */ + uIntf *bd, /* distance desired/actual bit depth */ + inflate_huft * FAR *tl, /* literal/length tree result */ + inflate_huft * FAR *td, /* distance tree result */ + z_stream *z /* for zfree function */ +) { int r; @@ -1529,11 +1545,12 @@ } -local int inflate_trees_fixed(bl, bd, tl, td) -uIntf *bl; /* literal desired/actual bit depth */ -uIntf *bd; /* distance desired/actual bit depth */ -inflate_huft * FAR *tl; /* literal/length tree result */ -inflate_huft * FAR *td; /* distance tree result */ +local int inflate_trees_fixed( + uIntf *bl, /* literal desired/actual bit depth */ + uIntf *bd, /* distance desired/actual bit depth */ + inflate_huft * FAR *tl, /* literal/length tree result */ + inflate_huft * FAR *td /* distance tree result */ +) { /* build fixed tables if not built already--lock out other instances */ while (++fixed_lock > 1) @@ -1579,9 +1596,10 @@ } -local int inflate_trees_free(t, z) -inflate_huft *t; /* table to free */ -z_stream *z; /* for zfree function */ +local int inflate_trees_free( + inflate_huft *t, /* table to free */ + z_stream *z /* for zfree function */ +) /* Free the malloc'ed tables built by huft_build(), which makes a linked list of the tables it made, with the links in a dummy first entry of each table. */ @@ -1651,10 +1669,13 @@ }; -local inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z) -uInt bl, bd; -inflate_huft *tl, *td; -z_stream *z; +local inflate_codes_statef *inflate_codes_new( + uInt bl, + uInt bd, + inflate_huft *tl, + inflate_huft *td, + z_stream *z +) { inflate_codes_statef *c; @@ -1672,10 +1693,11 @@ } -local int inflate_codes(s, z, r) -inflate_blocks_statef *s; -z_stream *z; -int r; +local int inflate_codes( + inflate_blocks_statef *s, + z_stream *z, + int r +) { uInt j; /* temporary storage */ inflate_huft *t; /* temporary pointer */ @@ -1832,9 +1854,10 @@ } -local void inflate_codes_free(c, z) -inflate_codes_statef *c; -z_stream *z; +local void inflate_codes_free( + inflate_codes_statef *c, + z_stream *z +) { ZFREE(z, c, sizeof(struct inflate_codes_state)); Tracev((stderr, "inflate: codes free\n")); @@ -1847,10 +1870,11 @@ */ /* copy as much as possible from the sliding window to the output area */ -local int inflate_flush(s, z, r) -inflate_blocks_statef *s; -z_stream *z; -int r; +local int inflate_flush( + inflate_blocks_statef *s, + z_stream *z, + int r +) { uInt n; Bytef *p, *q; @@ -1934,11 +1958,14 @@ at least ten. The ten bytes are six bytes for the longest length/ distance pair plus four bytes for overloading the bit buffer. */ -local int inflate_fast(bl, bd, tl, td, s, z) -uInt bl, bd; -inflate_huft *tl, *td; -inflate_blocks_statef *s; -z_stream *z; +local int inflate_fast( + uInt bl, + uInt bd, + inflate_huft *tl, + inflate_huft *td, + inflate_blocks_statef *s, + z_stream *z +) { inflate_huft *t; /* temporary pointer */ uInt e; /* extra bits or operation */ diff -Nru a/arch/ppc/boot/of1275/Makefile b/arch/ppc/boot/of1275/Makefile --- a/arch/ppc/boot/of1275/Makefile Mon Jun 9 23:16:12 2003 +++ b/arch/ppc/boot/of1275/Makefile Mon Jun 9 23:16:12 2003 @@ -2,7 +2,5 @@ # Makefile of1275 stuff # -L_TARGET := lib.a - -obj-y := claim.o enter.o exit.o finddevice.o getprop.o ofinit.o \ +lib-y := claim.o enter.o exit.o finddevice.o getprop.o ofinit.o \ ofstdio.o read.o release.o write.o diff -Nru a/arch/ppc/boot/prep/vreset.c b/arch/ppc/boot/prep/vreset.c --- a/arch/ppc/boot/prep/vreset.c Mon Jun 9 23:16:05 2003 +++ b/arch/ppc/boot/prep/vreset.c Mon Jun 9 23:16:05 2003 @@ -691,14 +691,14 @@ unsigned long regs[NPCIREGS]; } PCI_slots [NSLOTS] = { - { (unsigned long *)0x80808000, 0xDEADBEEF }, /* onboard */ - { (unsigned long *)0x80800800, 0xDEADBEEF }, /* onboard */ - { (unsigned long *)0x80801000, 0xDEADBEEF }, /* onboard */ - { (unsigned long *)0x80802000, 0xDEADBEEF }, /* onboard */ - { (unsigned long *)0x80804000, 0xDEADBEEF }, /* onboard */ - { (unsigned long *)0x80810000, 0xDEADBEEF }, /* slot A/1 */ - { (unsigned long *)0x80820000, 0xDEADBEEF }, /* slot B/2 */ - { (unsigned long *)0x80840000, 0xDEADBEEF } /* slot C/3 */ + { (unsigned long *)0x80808000, {0xDEADBEEF,} }, /* onboard */ + { (unsigned long *)0x80800800, {0xDEADBEEF,} }, /* onboard */ + { (unsigned long *)0x80801000, {0xDEADBEEF,} }, /* onboard */ + { (unsigned long *)0x80802000, {0xDEADBEEF,} }, /* onboard */ + { (unsigned long *)0x80804000, {0xDEADBEEF,} }, /* onboard */ + { (unsigned long *)0x80810000, {0xDEADBEEF,} }, /* slot A/1 */ + { (unsigned long *)0x80820000, {0xDEADBEEF,} }, /* slot B/2 */ + { (unsigned long *)0x80840000, {0xDEADBEEF,} } /* slot C/3 */ }; diff -Nru a/arch/ppc/boot/simple/misc-embedded.c b/arch/ppc/boot/simple/misc-embedded.c --- a/arch/ppc/boot/simple/misc-embedded.c Mon Jun 9 23:16:08 2003 +++ b/arch/ppc/boot/simple/misc-embedded.c Mon Jun 9 23:16:08 2003 @@ -11,13 +11,17 @@ #include <linux/elf.h> #include <linux/string.h> #include <asm/bootinfo.h> -#include <asm/ibm4xx.h> #include <asm/mmu.h> -#include <asm/mpc8xx.h> -#include <asm/mpc8260.h> #include <asm/page.h> #include <asm/processor.h> #include <asm/residual.h> +#if defined(CONFIG_4xx) +#include <asm/ibm4xx.h> +#elif defined(CONFIG_8xx) +#include <asm/mpc8xx.h> +#elif defined(CONFIG_8260) +#include <asm/mpc8260.h> +#endif #include "nonstdio.h" #include "zlib.h" diff -Nru a/arch/ppc/kernel/align.c b/arch/ppc/kernel/align.c --- a/arch/ppc/kernel/align.c Mon Jun 9 23:16:05 2003 +++ b/arch/ppc/kernel/align.c Mon Jun 9 23:16:05 2003 @@ -189,7 +189,7 @@ #endif int i, t; int reg, areg; - unsigned char *addr; + unsigned char __user *addr; union { long l; float f; @@ -252,7 +252,7 @@ * pt_regs structure is overloaded and is really from the DEAR. */ - addr = (unsigned char *)regs->dar; + addr = (unsigned char __user *)regs->dar; /* Verify the address of the operand */ if (user_mode(regs)) { diff -Nru a/arch/ppc/kernel/entry.S b/arch/ppc/kernel/entry.S --- a/arch/ppc/kernel/entry.S Mon Jun 9 23:16:18 2003 +++ b/arch/ppc/kernel/entry.S Mon Jun 9 23:16:18 2003 @@ -507,7 +507,7 @@ MTMSRD(r10) /* disable interrupts */ lwz r3,_MSR(r1) /* Returning to user mode? */ - andi. r3,r3,MSR_PR + andi. r0,r3,MSR_PR beq resume_kernel user_exc_return: /* r10 contains MSR_KERNEL here */ @@ -528,6 +528,7 @@ #ifdef CONFIG_PREEMPT b restore +/* N.B. the only way to get here is from the beq following ret_from_except. */ resume_kernel: /* check current_thread_info->preempt_count */ rlwinm r9,r1,0,0,18 @@ -549,8 +550,10 @@ SYNC MTMSRD(r10) /* disable interrupts */ rlwinm r9,r1,0,0,18 - lwz r0,TI_FLAGS(r9) - andi. r0,r0,_TIF_NEED_RESCHED + li r0,0 + stw r0,TI_PREEMPT(r9) + lwz r3,TI_FLAGS(r9) + andi. r0,r3,_TIF_NEED_RESCHED bne- 1b #else resume_kernel: @@ -817,7 +820,7 @@ * here so it's easy to add arch-specific sections later. * -- Cort */ -#if defined(CONFIG_ALL_PPC) +#ifdef CONFIG_PPC_OF /* * On CHRP, the Run-Time Abstraction Services (RTAS) have to be * called with the MMU off. @@ -862,4 +865,4 @@ twi 31,0,0 /* XXX load up BATs and panic */ -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_OF */ diff -Nru a/arch/ppc/kernel/head.S b/arch/ppc/kernel/head.S --- a/arch/ppc/kernel/head.S Mon Jun 9 23:16:13 2003 +++ b/arch/ppc/kernel/head.S Mon Jun 9 23:16:13 2003 @@ -363,21 +363,21 @@ mtspr SPRG0,r10 mtspr SPRG1,r11 mfcr r10 -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_CHRP mfspr r11,SPRG2 cmpwi 0,r11,0 bne 7f -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_CHRP */ EXCEPTION_PROLOG_1 7: EXCEPTION_PROLOG_2 addi r3,r1,STACK_FRAME_OVERHEAD -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_CHRP mfspr r4,SPRG2 cmpwi cr1,r4,0 bne cr1,1f #endif EXC_XFER_STD(0x200, MachineCheckException) -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_CHRP 1: b machine_check_in_rtas #endif diff -Nru a/arch/ppc/kernel/head_4xx.S b/arch/ppc/kernel/head_4xx.S --- a/arch/ppc/kernel/head_4xx.S Mon Jun 9 23:16:19 2003 +++ b/arch/ppc/kernel/head_4xx.S Mon Jun 9 23:16:19 2003 @@ -447,7 +447,12 @@ EXC_XFER_EE(0x600, AlignmentException) /* 0x0700 - Program Exception */ - EXCEPTION(0x700, ProgramCheck, ProgramCheckException, EXC_XFER_EE) + START_EXCEPTION(0x0700, ProgramCheck) + NORMAL_EXCEPTION_PROLOG + mfspr r4,SPRN_ESR /* Grab the ESR and save it */ + stw r4,_ESR(r11) + addi r3,r1,STACK_FRAME_OVERHEAD + EXC_XFER_EE(0x700, ProgramCheckException) EXCEPTION(0x0800, Trap_08, UnknownException, EXC_XFER_EE) EXCEPTION(0x0900, Trap_09, UnknownException, EXC_XFER_EE) @@ -469,7 +474,7 @@ lis r0,TSR_PIS@h mtspr SPRN_TSR,r0 /* Clear the PIT exception */ addi r3,r1,STACK_FRAME_OVERHEAD - EXC_XFER_EE(0x1000, timer_interrupt) + EXC_XFER_LITE(0x1000, timer_interrupt) #if 0 /* NOTE: diff -Nru a/arch/ppc/kernel/irq.c b/arch/ppc/kernel/irq.c --- a/arch/ppc/kernel/irq.c Mon Jun 9 23:16:17 2003 +++ b/arch/ppc/kernel/irq.c Mon Jun 9 23:16:17 2003 @@ -66,8 +66,11 @@ #define MAXCOUNT 10000000 -irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = - { [0 ... NR_IRQS-1] = { 0, NULL, NULL, 0, SPIN_LOCK_UNLOCKED}}; +irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { + [0 ... NR_IRQS-1] = { + .lock = SPIN_LOCK_UNLOCKED + } +}; int ppc_spurious_interrupts = 0; struct irqaction *ppc_irq_action[NR_IRQS]; @@ -580,7 +583,7 @@ return sprintf (page, "%08x\n", irq_affinity[(int)data]); } -static unsigned int parse_hex_value (const char *buffer, +static unsigned int parse_hex_value (const char __user *buffer, unsigned long count, unsigned long *ret) { unsigned char hexnum [HEX_DIGITS]; @@ -617,7 +620,7 @@ return 0; } -static int irq_affinity_write_proc (struct file *file, const char *buffer, +static int irq_affinity_write_proc (struct file *file, const char __user *buffer, unsigned long count, void *data) { int irq = (int) data, full_count = count, err; @@ -656,7 +659,7 @@ return sprintf (page, "%08lx\n", *mask); } -static int prof_cpu_mask_write_proc (struct file *file, const char *buffer, +static int prof_cpu_mask_write_proc (struct file *file, const char __user *buffer, unsigned long count, void *data) { unsigned long *mask = (unsigned long *) data, full_count = count, err; diff -Nru a/arch/ppc/kernel/misc.S b/arch/ppc/kernel/misc.S --- a/arch/ppc/kernel/misc.S Mon Jun 9 23:16:18 2003 +++ b/arch/ppc/kernel/misc.S Mon Jun 9 23:16:18 2003 @@ -1227,7 +1227,7 @@ .long sys_ni_syscall /* old profil syscall holder */ .long sys_statfs .long sys_fstatfs /* 100 */ - .long sys_ioperm + .long sys_ni_syscall .long sys_socketcall .long sys_syslog .long sys_setitimer @@ -1236,10 +1236,10 @@ .long sys_newlstat .long sys_newfstat .long sys_uname - .long sys_iopl /* 110 */ + .long sys_ni_syscall /* 110 */ .long sys_vhangup .long sys_ni_syscall /* old 'idle' syscall */ - .long sys_vm86 + .long sys_ni_syscall .long sys_wait4 .long sys_swapoff /* 115 */ .long sys_sysinfo @@ -1249,7 +1249,7 @@ .long ppc_clone /* 120 */ .long sys_setdomainname .long sys_newuname - .long sys_modify_ldt + .long sys_ni_syscall .long sys_adjtimex .long sys_mprotect /* 125 */ .long sys_sigprocmask diff -Nru a/arch/ppc/kernel/module.c b/arch/ppc/kernel/module.c --- a/arch/ppc/kernel/module.c Mon Jun 9 23:16:08 2003 +++ b/arch/ppc/kernel/module.c Mon Jun 9 23:16:08 2003 @@ -16,6 +16,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/module.h> +#include <linux/moduleloader.h> #include <linux/elf.h> #include <linux/vmalloc.h> #include <linux/fs.h> @@ -29,6 +30,8 @@ #define DEBUGP(fmt , ...) #endif +LIST_HEAD(module_bug_list); + void *module_alloc(unsigned long size) { if (size == 0) @@ -267,9 +270,48 @@ const Elf_Shdr *sechdrs, struct module *me) { + char *secstrings; + unsigned int i; + + me->arch.bug_table = NULL; + me->arch.num_bugs = 0; + + /* Find the __bug_table section, if present */ + secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset; + for (i = 1; i < hdr->e_shnum; i++) { + if (strcmp(secstrings+sechdrs[i].sh_name, "__bug_table")) + continue; + me->arch.bug_table = (void *) sechdrs[i].sh_addr; + me->arch.num_bugs = sechdrs[i].sh_size / sizeof(struct bug_entry); + break; + } + + /* + * Strictly speaking this should have a spinlock to protect against + * traversals, but since we only traverse on BUG()s, a spinlock + * could potentially lead to deadlock and thus be counter-productive. + */ + list_add(&me->arch.bug_list, &module_bug_list); + return 0; } void module_arch_cleanup(struct module *mod) { + list_del(&mod->arch.bug_list); +} + +struct bug_entry *module_find_bug(unsigned long bugaddr) +{ + struct mod_arch_specific *mod; + unsigned int i; + struct bug_entry *bug; + + list_for_each_entry(mod, &module_bug_list, bug_list) { + bug = mod->bug_table; + for (i = 0; i < mod->num_bugs; ++i, ++bug) + if (bugaddr == bug->bug_addr) + return bug; + } + return NULL; } diff -Nru a/arch/ppc/kernel/pci.c b/arch/ppc/kernel/pci.c --- a/arch/ppc/kernel/pci.c Mon Jun 9 23:16:11 2003 +++ b/arch/ppc/kernel/pci.c Mon Jun 9 23:16:11 2003 @@ -44,8 +44,11 @@ static void fixup_broken_pcnet32(struct pci_dev* dev); static int reparent_resources(struct resource *parent, struct resource *res); static void fixup_rev1_53c810(struct pci_dev* dev); -#ifdef CONFIG_ALL_PPC +static void fixup_cpc710_pci64(struct pci_dev* dev); +#ifdef CONFIG_PPC_PMAC static void pcibios_fixup_cardbus(struct pci_dev* dev); +#endif +#ifdef CONFIG_PPC_OF static u8* pci_to_OF_bus_map; #endif @@ -62,11 +65,12 @@ struct pci_fixup pcibios_fixups[] = { { PCI_FIXUP_HEADER, PCI_VENDOR_ID_TRIDENT, PCI_ANY_ID, fixup_broken_pcnet32 }, { PCI_FIXUP_HEADER, PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, fixup_rev1_53c810 }, + { PCI_FIXUP_HEADER, PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CPC710_PCI64, fixup_cpc710_pci64}, { PCI_FIXUP_HEADER, PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources }, -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC /* We should add per-machine fixup support in xxx_setup.c or xxx_pci.c */ { PCI_FIXUP_FINAL, PCI_VENDOR_ID_TI, PCI_ANY_ID, pcibios_fixup_cardbus }, -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PMAC */ { 0 } }; @@ -94,6 +98,18 @@ } static void +fixup_cpc710_pci64(struct pci_dev* dev) +{ + /* Hide the PCI64 BARs from the kernel as their content doesn't + * fit well in the resource management + */ + dev->resource[0].start = dev->resource[0].end = 0; + dev->resource[0].flags = 0; + dev->resource[1].start = dev->resource[1].end = 0; + dev->resource[1].flags = 0; +} + +static void pcibios_fixup_resources(struct pci_dev *dev) { struct pci_controller* hose = (struct pci_controller *)dev->sysdata; @@ -139,7 +155,7 @@ ppc_md.pcibios_fixup_resources(dev); } -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC static void pcibios_fixup_cardbus(struct pci_dev* dev) { @@ -174,7 +190,7 @@ pci_write_config_byte(dev, 0x92, val & ~0x06); } } -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PMAC */ void pcibios_resource_to_bus(struct pci_dev *dev, struct pci_bus_region *region, @@ -534,12 +550,12 @@ static void __init pcibios_allocate_resources(int pass) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; int idx, disabled; u16 command; struct resource *r; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { pci_read_config_word(dev, PCI_COMMAND, &command); for (idx = 0; idx < 6; idx++) { r = &dev->resource[idx]; @@ -572,11 +588,11 @@ static void __init pcibios_assign_resources(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; int idx; struct resource *r; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { int class = dev->class >> 8; /* Don't touch classless devices and host bridges */ @@ -662,7 +678,7 @@ return hose; } -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_OF /* * Functions below are used on OpenFirmware machines. */ @@ -867,7 +883,7 @@ { unsigned int *reg; struct pci_controller* hose; - struct pci_dev* dev; + struct pci_dev* dev = NULL; if (!have_of) return -ENODEV; @@ -891,7 +907,7 @@ */ if (!pci_to_OF_bus_map) return 0; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { if (pci_to_OF_bus_map[dev->bus->number] != *bus) continue; if (dev->devfn != *devfn) @@ -1012,7 +1028,218 @@ prom_add_property(find_path_device("/"), of_prop); } } -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_OF */ + +#ifdef CONFIG_PPC_PMAC +/* + * This set of routines checks for PCI<->PCI bridges that have closed + * IO resources and have child devices. It tries to re-open an IO + * window on them. + * + * This is a _temporary_ fix to workaround a problem with Apple's OF + * closing IO windows on P2P bridges when the OF drivers of cards + * below this bridge don't claim any IO range (typically ATI or + * Adaptec). + * + * A more complete fix would be to use drivers/pci/setup-bus.c, which + * involves a working pcibios_fixup_pbus_ranges(), some more care about + * ordering when creating the host bus resources, and maybe a few more + * minor tweaks + */ + +/* Initialize bridges with base/limit values we have collected */ +static void __init +do_update_p2p_io_resource(struct pci_bus *bus, int enable_vga) +{ + struct pci_dev *bridge = bus->self; + struct pci_controller* hose = (struct pci_controller *)bridge->sysdata; + u32 l; + u16 w; + struct resource res; + + res = *(bus->resource[0]); + + DBG("Remapping Bus %d, bridge: %s\n", bus->number, bridge->name); + res.start -= ((unsigned long) hose->io_base_virt - isa_io_base); + res.end -= ((unsigned long) hose->io_base_virt - isa_io_base); + DBG(" IO window: %08lx-%08lx\n", res.start, res.end); + + /* Set up the top and bottom of the PCI I/O segment for this bus. */ + pci_read_config_dword(bridge, PCI_IO_BASE, &l); + l &= 0xffff000f; + l |= (res.start >> 8) & 0x00f0; + l |= res.end & 0xf000; + pci_write_config_dword(bridge, PCI_IO_BASE, l); + + if ((l & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) { + l = (res.start >> 16) | (res.end & 0xffff0000); + pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, l); + } + + pci_read_config_word(bridge, PCI_COMMAND, &w); + w |= PCI_COMMAND_IO; + pci_write_config_word(bridge, PCI_COMMAND, w); + +#if 0 /* Enabling this causes XFree 4.2.0 to hang during PCI probe */ + if (enable_vga) { + pci_read_config_word(bridge, PCI_BRIDGE_CONTROL, &w); + w |= PCI_BRIDGE_CTL_VGA; + pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, w); + } +#endif +} + +/* This function is pretty basic and actually quite broken for the + * general case, it's enough for us right now though. It's supposed + * to tell us if we need to open an IO range at all or not and what + * size. + */ +static int __init +check_for_io_childs(struct pci_bus *bus, struct resource* res, int *found_vga) +{ + struct list_head *ln; + int i; + int rc = 0; + +#define push_end(res, size) do { unsigned long __sz = (size) ; \ + res->end = ((res->end + __sz) / (__sz + 1)) * (__sz + 1) + __sz; \ + } while (0) + + for (ln=bus->devices.next; ln != &bus->devices; ln=ln->next) { + struct pci_dev *dev = pci_dev_b(ln); + u16 class = dev->class >> 8; + + if (class == PCI_CLASS_DISPLAY_VGA || + class == PCI_CLASS_NOT_DEFINED_VGA) + *found_vga = 1; + if (class >> 8 == PCI_BASE_CLASS_BRIDGE && dev->subordinate) + rc |= check_for_io_childs(dev->subordinate, res, found_vga); + if (class == PCI_CLASS_BRIDGE_CARDBUS) + push_end(res, 0xfff); + + for (i=0; i<PCI_NUM_RESOURCES; i++) { + struct resource *r; + unsigned long r_size; + + if (dev->class >> 8 == PCI_CLASS_BRIDGE_PCI + && i >= PCI_BRIDGE_RESOURCES) + continue; + r = &dev->resource[i]; + r_size = r->end - r->start; + if (r_size < 0xfff) + r_size = 0xfff; + if (r->flags & IORESOURCE_IO && (r_size) != 0) { + rc = 1; + push_end(res, r_size); + } + } + } + + return rc; +} + +/* Here we scan all P2P bridges of a given level that have a closed + * IO window. Note that the test for the presence of a VGA card should + * be improved to take into account already configured P2P bridges, + * currently, we don't see them and might end up configuring 2 bridges + * with VGA pass through enabled + */ +static void __init +do_fixup_p2p_level(struct pci_bus *bus) +{ + struct list_head *ln; + int i, parent_io; + int has_vga = 0; + + for (parent_io=0; parent_io<4; parent_io++) + if (bus->resource[parent_io]->flags & IORESOURCE_IO) + break; + if (parent_io >= 4) + return; + + for (ln=bus->children.next; ln != &bus->children; ln=ln->next) { + struct pci_bus *b = pci_bus_b(ln); + struct pci_dev *d = b->self; + struct pci_controller* hose = (struct pci_controller *)d->sysdata; + struct resource *res = b->resource[0]; + struct resource tmp_res; + unsigned long max; + int found_vga = 0; + + memset(&tmp_res, 0, sizeof(tmp_res)); + tmp_res.start = bus->resource[parent_io]->start; + + /* We don't let low addresses go through that closed P2P bridge, well, + * that may not be necessary but I feel safer that way + */ + if (tmp_res.start == 0) + tmp_res.start = 0x1000; + + if (!list_empty(&b->devices) && res && res->flags == 0 && + res != bus->resource[parent_io] && + (d->class >> 8) == PCI_CLASS_BRIDGE_PCI && + check_for_io_childs(b, &tmp_res, &found_vga)) { + u8 io_base_lo; + + printk(KERN_INFO "Fixing up IO bus %s\n", b->name); + + if (found_vga) { + if (has_vga) { + printk(KERN_WARNING "Skipping VGA, already active" + " on bus segment\n"); + found_vga = 0; + } else + has_vga = 1; + } + pci_read_config_byte(d, PCI_IO_BASE, &io_base_lo); + + if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) + max = ((unsigned long) hose->io_base_virt + - isa_io_base) + 0xffffffff; + else + max = ((unsigned long) hose->io_base_virt + - isa_io_base) + 0xffff; + + *res = tmp_res; + res->flags = IORESOURCE_IO; + res->name = b->name; + + /* Find a resource in the parent where we can allocate */ + for (i = 0 ; i < 4; i++) { + struct resource *r = bus->resource[i]; + if (!r) + continue; + if ((r->flags & IORESOURCE_IO) == 0) + continue; + DBG("Trying to allocate from %08lx, size %08lx from parent" + " res %d: %08lx -> %08lx\n", + res->start, res->end, i, r->start, r->end); + + if (allocate_resource(r, res, res->end + 1, res->start, max, + res->end + 1, NULL, NULL) < 0) { + DBG("Failed !\n"); + continue; + } + do_update_p2p_io_resource(b, found_vga); + break; + } + } + do_fixup_p2p_level(b); + } +} + +static void +pcibios_fixup_p2p_bridges(void) +{ + struct list_head *ln; + + for(ln=pci_root_buses.next; ln != &pci_root_buses; ln=ln->next) { + struct pci_bus *b = pci_bus_b(ln); + do_fixup_p2p_level(b); + } +} + +#endif /* CONFIG_PPC_PMAC */ static int __init pcibios_init(void) @@ -1054,6 +1281,9 @@ pcibios_allocate_bus_resources(&pci_root_buses); pcibios_allocate_resources(0); pcibios_allocate_resources(1); +#ifdef CONFIG_PPC_PMAC + pcibios_fixup_p2p_bridges(); +#endif /* CONFIG_PPC_PMAC */ pcibios_assign_resources(); /* Call machine dependent post-init code */ diff -Nru a/arch/ppc/kernel/ppc_htab.c b/arch/ppc/kernel/ppc_htab.c --- a/arch/ppc/kernel/ppc_htab.c Mon Jun 9 23:16:06 2003 +++ b/arch/ppc/kernel/ppc_htab.c Mon Jun 9 23:16:06 2003 @@ -30,13 +30,13 @@ #include <asm/cputable.h> #include <asm/system.h> -static ssize_t ppc_htab_read(struct file * file, char * buf, +static ssize_t ppc_htab_read(struct file * file, char __user * buf, size_t count, loff_t *ppos); -static ssize_t ppc_htab_write(struct file * file, const char * buffer, +static ssize_t ppc_htab_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos); static long long ppc_htab_lseek(struct file * file, loff_t offset, int orig); int proc_dol2crvec(ctl_table *table, int write, struct file *filp, - void *buffer, size_t *lenp); + void __user *buffer, size_t *lenp); extern PTE *Hash, *Hash_end; extern unsigned long Hash_size, Hash_mask; @@ -109,7 +109,7 @@ * is _REALLY_ slow (see the nested for loops below) but nothing * in here should be really timing critical. -- Cort */ -static ssize_t ppc_htab_read(struct file * file, char * buf, +static ssize_t ppc_htab_read(struct file * file, char __user * buf, size_t count, loff_t *ppos) { unsigned long mmcr0 = 0, pmc1 = 0, pmc2 = 0; @@ -211,13 +211,19 @@ /* * Allow user to define performance counters and resize the hash table */ -static ssize_t ppc_htab_write(struct file * file, const char * buffer, +static ssize_t ppc_htab_write(struct file * file, const char __user * ubuffer, size_t count, loff_t *ppos) { #ifdef CONFIG_PPC_STD_MMU unsigned long tmp; + char buffer[16]; + if ( current->uid != 0 ) return -EACCES; + if (strncpy_from_user(buffer, ubuffer, 15)) + return -EFAULT; + buffer[15] = 0; + /* don't set the htab size for now */ if ( !strncmp( buffer, "size ", 5) ) return -EBUSY; @@ -387,9 +393,10 @@ } int proc_dol2crvec(ctl_table *table, int write, struct file *filp, - void *buffer, size_t *lenp) + void __user *buffer_arg, size_t *lenp) { int vleft, first=1, len, left, val; + char __user *buffer = (char __user *) buffer_arg; #define TMPBUFLEN 256 char buf[TMPBUFLEN], *p; static const char *sizestrings[4] = { @@ -422,12 +429,12 @@ if (write) { while (left) { char c; - if(get_user(c,(char *) buffer)) + if(get_user(c, buffer)) return -EFAULT; if (!isspace(c)) break; left--; - ((char *) buffer)++; + buffer++; } if (!left) break; @@ -474,7 +481,7 @@ len = strlen(buf); if (len > left) len = left; - if(copy_to_user(buffer, buf, len)) + if (copy_to_user(buffer, buf, len)) return -EFAULT; left -= len; buffer += len; diff -Nru a/arch/ppc/kernel/ppc_ksyms.c b/arch/ppc/kernel/ppc_ksyms.c --- a/arch/ppc/kernel/ppc_ksyms.c Mon Jun 9 23:16:18 2003 +++ b/arch/ppc/kernel/ppc_ksyms.c Mon Jun 9 23:16:18 2003 @@ -94,12 +94,12 @@ EXPORT_SYMBOL(ISA_DMA_THRESHOLD); EXPORT_SYMBOL_NOVERS(DMA_MODE_READ); EXPORT_SYMBOL(DMA_MODE_WRITE); -#if defined(CONFIG_ALL_PPC) +#if defined(CONFIG_PPC_PREP) EXPORT_SYMBOL(_prep_type); EXPORT_SYMBOL(ucSystemType); #endif -#if !__INLINE_BITOPS +#if !defined(__INLINE_BITOPS) EXPORT_SYMBOL(set_bit); EXPORT_SYMBOL(clear_bit); EXPORT_SYMBOL(change_bit); @@ -238,9 +238,14 @@ EXPORT_SYMBOL(set_backlight_enable); EXPORT_SYMBOL(register_backlight_controller); #endif /* CONFIG_PMAC_BACKLIGHT */ -#if defined(CONFIG_ALL_PPC) +#ifdef CONFIG_PPC_MULTIPLATFORM EXPORT_SYMBOL(_machine); +#endif +#ifdef CONFIG_PPC_PMAC EXPORT_SYMBOL_NOVERS(sys_ctrler); +EXPORT_SYMBOL(pmac_newworld); +#endif +#ifdef CONFIG_PPC_OF EXPORT_SYMBOL(find_devices); EXPORT_SYMBOL(find_type_devices); EXPORT_SYMBOL(find_compatible_devices); @@ -254,12 +259,11 @@ EXPORT_SYMBOL(pci_busdev_to_OF_node); EXPORT_SYMBOL(pci_device_to_OF_node); EXPORT_SYMBOL(pci_device_from_OF_node); -EXPORT_SYMBOL(pmac_newworld); -#endif /* defined(CONFIG_ALL_PPC) */ +#endif /* CONFIG_PPC_OF */ #if defined(CONFIG_BOOTX_TEXT) EXPORT_SYMBOL(btext_update_display); #endif -#if defined(CONFIG_SCSI) && defined(CONFIG_ALL_PPC) +#if defined(CONFIG_SCSI) && defined(CONFIG_PPC_PMAC) EXPORT_SYMBOL(note_scsi_host); #endif #ifdef CONFIG_VT @@ -337,7 +341,7 @@ EXPORT_SYMBOL(cpm_install_handler); EXPORT_SYMBOL(cpm_free_handler); #endif /* CONFIG_8xx */ -#if defined(CONFIG_8xx) || defined(CONFIG_4xx) +#if defined(CONFIG_8xx) || defined(CONFIG_40x) EXPORT_SYMBOL(__res); #endif #if defined(CONFIG_8xx) @@ -354,7 +358,7 @@ EXPORT_SYMBOL(intercept_table); #endif EXPORT_SYMBOL(cur_cpu_spec); -#if defined(CONFIG_ALL_PPC) +#ifdef CONFIG_PPC_PMAC extern unsigned long agp_special_page; EXPORT_SYMBOL_NOVERS(agp_special_page); -#endif /* defined(CONFIG_ALL_PPC) */ +#endif diff -Nru a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c --- a/arch/ppc/kernel/process.c Mon Jun 9 23:16:12 2003 +++ b/arch/ppc/kernel/process.c Mon Jun 9 23:16:12 2003 @@ -205,7 +205,7 @@ struct task_struct *last; local_irq_save(s); -#if CHECK_STACK +#ifdef CHECK_STACK check_stack(prev); check_stack(new); #endif @@ -441,8 +441,9 @@ return put_user(val, (unsigned int *) adr); } -int sys_clone(unsigned long clone_flags, unsigned long usp, int *parent_tidp, - void *child_threadptr, int *child_tidp, int p6, +int sys_clone(unsigned long clone_flags, unsigned long usp, + int __user *parent_tidp, void __user *child_threadptr, + int __user *child_tidp, int p6, struct pt_regs *regs) { CHECK_FULL_REGS(regs); @@ -474,7 +475,7 @@ int error; char * filename; - filename = getname((char *) a0); + filename = getname((char __user *) a0); error = PTR_ERR(filename); if (IS_ERR(filename)) goto out; @@ -484,7 +485,8 @@ if (regs->msr & MSR_VEC) giveup_altivec(current); #endif /* CONFIG_ALTIVEC */ - error = do_execve(filename, (char **) a1, (char **) a2, regs); + error = do_execve(filename, (char __user *__user *) a1, + (char __user *__user *) a2, regs); if (error == 0) current->ptrace &= ~PT_DTRACE; putname(filename); diff -Nru a/arch/ppc/kernel/setup.c b/arch/ppc/kernel/setup.c --- a/arch/ppc/kernel/setup.c Mon Jun 9 23:16:19 2003 +++ b/arch/ppc/kernel/setup.c Mon Jun 9 23:16:19 2003 @@ -68,7 +68,7 @@ unsigned long ISA_DMA_THRESHOLD; unsigned long DMA_MODE_READ, DMA_MODE_WRITE; -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_MULTIPLATFORM int _machine = 0; extern void prep_init(unsigned long r3, unsigned long r4, @@ -77,7 +77,7 @@ unsigned long r5, unsigned long r6, unsigned long r7); extern void chrp_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7); -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_MULTIPLATFORM */ #ifdef CONFIG_MAGIC_SYSRQ unsigned long SYSRQ_KEY = 0x54; @@ -286,7 +286,7 @@ identify_cpu(offset, 0); do_cpu_ftr_fixups(offset); -#if defined(CONFIG_ALL_PPC) +#if defined(CONFIG_PPC_MULTIPLATFORM) reloc_got2(offset); /* If we came here from BootX, clear the screen, @@ -308,7 +308,7 @@ return phys; } -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_OF /* * Assume here that all clock rates are the same in a * smp system. -- Cort @@ -351,9 +351,11 @@ } } } +#endif +#ifdef CONFIG_PPC_MULTIPLATFORM /* - * The ALL_PPC version of platform_init... + * The PPC_MULTIPLATFORM version of platform_init... */ void __init platform_init(unsigned long r3, unsigned long r4, unsigned long r5, @@ -459,7 +461,7 @@ break; } } -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_MULTIPLATFORM */ struct bi_record *find_bootinfo(void) { @@ -501,11 +503,11 @@ initrd_end = data[0] + data[1] + KERNELBASE; break; #endif /* CONFIG_BLK_DEV_INITRD */ -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_MULTIPLATFORM case BI_MACHTYPE: _machine = data[0]; break; -#endif /* CONFIG_ALL_PPC */ +#endif case BI_MEMSIZE: boot_mem_size = data[0]; break; @@ -596,13 +598,13 @@ /* so udelay does something sensible, assume <= 1000 bogomips */ loops_per_jiffy = 500000000 / HZ; -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_MULTIPLATFORM /* This could be called "early setup arch", it must be done * now because xmon need it */ if (_machine == _MACH_Pmac) pmac_feature_init(); /* New cool way */ -#endif /* CONFIG_ALL_PPC */ +#endif #ifdef CONFIG_XMON xmon_map_scc(); diff -Nru a/arch/ppc/kernel/signal.c b/arch/ppc/kernel/signal.c --- a/arch/ppc/kernel/signal.c Mon Jun 9 23:16:19 2003 +++ b/arch/ppc/kernel/signal.c Mon Jun 9 23:16:19 2003 @@ -83,8 +83,8 @@ } int -sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, int p3, int p4, int p6, - int p7, struct pt_regs *regs) +sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, int p3, int p4, + int p6, int p7, struct pt_regs *regs) { sigset_t saveset, newset; @@ -115,15 +115,15 @@ int -sys_sigaltstack(const stack_t *uss, stack_t *uoss, int r5, int r6, - int r7, int r8, struct pt_regs *regs) +sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, int r5, + int r6, int r7, int r8, struct pt_regs *regs) { return do_sigaltstack(uss, uoss, regs->gpr[1]); } int -sys_sigaction(int sig, const struct old_sigaction *act, - struct old_sigaction *oact) +sys_sigaction(int sig, const struct old_sigaction __user *act, + struct old_sigaction __user *oact) { struct k_sigaction new_ka, old_ka; int ret; @@ -195,14 +195,14 @@ int sys_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8, struct pt_regs *regs) { - struct rt_sigframe *rt_sf; + struct rt_sigframe __user *rt_sf; struct sigcontext sigctx; - struct sigregs *sr; + struct sigregs __user *sr; elf_gregset_t saved_regs; /* an array of ELF_NGREG unsigned longs */ sigset_t set; stack_t st; - rt_sf = (struct rt_sigframe *)(regs->gpr[1] + __SIGNAL_FRAMESIZE); + rt_sf = (struct rt_sigframe __user *)(regs->gpr[1] + __SIGNAL_FRAMESIZE); if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx)) || copy_from_user(&set, &rt_sf->uc.uc_sigmask, sizeof(set)) || copy_from_user(&st, &rt_sf->uc.uc_stack, sizeof(st))) @@ -220,7 +220,7 @@ * preamble frame (where registers are stored) * see handle_signal() */ - sr = (struct sigregs *) sigctx.regs; + sr = (struct sigregs __user *) sigctx.regs; if (copy_from_user(saved_regs, &sr->gp_regs, sizeof(sr->gp_regs))) goto badframe; saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE) @@ -229,9 +229,6 @@ if (copy_from_user(current->thread.fpr, &sr->fp_regs, sizeof(sr->fp_regs))) goto badframe; - /* This function sets back the stack flags into - the current task structure. */ - sys_sigaltstack(&st, NULL, 0, 0, 0, 0, regs); sigreturn_exit(regs); /* doesn't return here */ return 0; @@ -241,10 +238,10 @@ } static void -setup_rt_frame(struct pt_regs *regs, struct sigregs *frame, +setup_rt_frame(struct pt_regs *regs, struct sigregs __user *frame, signed long newsp) { - struct rt_sigframe *rt_sf = (struct rt_sigframe *) newsp; + struct rt_sigframe __user *rt_sf = (struct rt_sigframe __user *) newsp; /* Set up preamble frame */ if (verify_area(VERIFY_WRITE, frame, sizeof(*frame))) @@ -270,11 +267,11 @@ set up registers for signal handler */ newsp -= __SIGNAL_FRAMESIZE; - if (put_user(regs->gpr[1], (unsigned long *)newsp) + if (put_user(regs->gpr[1], (unsigned long __user *)newsp) || get_user(regs->nip, &rt_sf->uc.uc_mcontext.handler) || get_user(regs->gpr[3], &rt_sf->uc.uc_mcontext.signal) - || get_user(regs->gpr[4], (unsigned long *)&rt_sf->pinfo) - || get_user(regs->gpr[5], (unsigned long *)&rt_sf->puc)) + || get_user(regs->gpr[4], (unsigned long __user *)&rt_sf->pinfo) + || get_user(regs->gpr[5], (unsigned long __user *)&rt_sf->puc)) goto badframe; regs->gpr[1] = newsp; @@ -297,12 +294,13 @@ int sys_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8, struct pt_regs *regs) { - struct sigcontext *sc, sigctx; - struct sigregs *sr; + struct sigcontext __user *sc; + struct sigcontext sigctx; + struct sigregs __user *sr; elf_gregset_t saved_regs; /* an array of ELF_NGREG unsigned longs */ sigset_t set; - sc = (struct sigcontext *)(regs->gpr[1] + __SIGNAL_FRAMESIZE); + sc = (struct sigcontext __user *)(regs->gpr[1] + __SIGNAL_FRAMESIZE); if (copy_from_user(&sigctx, sc, sizeof(sigctx))) goto badframe; @@ -319,7 +317,7 @@ giveup_fpu(current); /* restore registers */ - sr = (struct sigregs *) sigctx.regs; + sr = (struct sigregs __user *) sigctx.regs; if (copy_from_user(saved_regs, &sr->gp_regs, sizeof(sr->gp_regs))) goto badframe; saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE) @@ -341,10 +339,10 @@ * Set up a signal frame. */ static void -setup_frame(struct pt_regs *regs, struct sigregs *frame, +setup_frame(struct pt_regs *regs, struct sigregs __user *frame, unsigned long newsp) { - struct sigcontext *sc = (struct sigcontext *) newsp; + struct sigcontext __user *sc = (struct sigcontext __user *) newsp; if (verify_area(VERIFY_WRITE, frame, sizeof(*frame))) goto badframe; @@ -362,7 +360,7 @@ current->thread.fpscr = 0; /* turn off all fp exceptions */ newsp -= __SIGNAL_FRAMESIZE; - if (put_user(regs->gpr[1], (unsigned long *)newsp) + if (put_user(regs->gpr[1], (unsigned long __user *)newsp) || get_user(regs->nip, &sc->handler) || get_user(regs->gpr[3], &sc->signal)) goto badframe; @@ -387,8 +385,8 @@ handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset, struct pt_regs * regs, unsigned long *newspp, unsigned long frame) { - struct sigcontext *sc; - struct rt_sigframe *rt_sf; + struct sigcontext __user *sc; + struct rt_sigframe __user *rt_sf; struct k_sigaction *ka = ¤t->sighand->action[sig-1]; if (TRAP(regs) == 0x0C00 /* System Call! */ @@ -408,7 +406,7 @@ if (ka->sa.sa_flags & SA_SIGINFO) { /* Put a Real Time Context onto stack */ *newspp -= sizeof(*rt_sf); - rt_sf = (struct rt_sigframe *) *newspp; + rt_sf = (struct rt_sigframe __user *) *newspp; if (verify_area(VERIFY_WRITE, rt_sf, sizeof(*rt_sf))) goto badframe; @@ -432,7 +430,7 @@ } else { /* Put a sigcontext on the stack */ *newspp -= sizeof(*sc); - sc = (struct sigcontext *) *newspp; + sc = (struct sigcontext __user *) *newspp; if (verify_area(VERIFY_WRITE, sc, sizeof(*sc))) goto badframe; @@ -516,9 +514,9 @@ return 0; /* no signals delivered */ if (ka->sa.sa_flags & SA_SIGINFO) - setup_rt_frame(regs, (struct sigregs *) frame, newsp); + setup_rt_frame(regs, (struct sigregs __user *) frame, newsp); else - setup_frame(regs, (struct sigregs *) frame, newsp); + setup_frame(regs, (struct sigregs __user *) frame, newsp); return 1; } diff -Nru a/arch/ppc/kernel/syscalls.c b/arch/ppc/kernel/syscalls.c --- a/arch/ppc/kernel/syscalls.c Mon Jun 9 23:16:19 2003 +++ b/arch/ppc/kernel/syscalls.c Mon Jun 9 23:16:19 2003 @@ -35,6 +35,7 @@ #include <linux/ipc.h> #include <linux/utsname.h> #include <linux/file.h> +#include <linux/unistd.h> #include <asm/uaccess.h> #include <asm/ipc.h> @@ -45,37 +46,13 @@ { } -int sys_ioperm(unsigned long from, unsigned long num, int on) -{ - printk(KERN_ERR "sys_ioperm()\n"); - return -EIO; -} - -int sys_iopl(int a1, int a2, int a3, int a4) -{ - printk(KERN_ERR "sys_iopl(%x, %x, %x, %x)!\n", a1, a2, a3, a4); - return (-ENOSYS); -} - -int sys_vm86(int a1, int a2, int a3, int a4) -{ - printk(KERN_ERR "sys_vm86(%x, %x, %x, %x)!\n", a1, a2, a3, a4); - return (-ENOSYS); -} - -int sys_modify_ldt(int a1, int a2, int a3, int a4) -{ - printk(KERN_ERR "sys_modify_ldt(%x, %x, %x, %x)!\n", a1, a2, a3, a4); - return (-ENOSYS); -} - /* * sys_ipc() is the de-multiplexer for the SysV IPC calls.. * * This is really horribly ugly. */ int -sys_ipc (uint call, int first, int second, int third, void *ptr, long fifth) +sys_ipc (uint call, int first, int second, int third, void __user *ptr, long fifth) { int version, ret; @@ -85,7 +62,7 @@ ret = -EINVAL; switch (call) { case SEMOP: - ret = sys_semop (first, (struct sembuf *)ptr, second); + ret = sys_semop (first, (struct sembuf __user *)ptr, second); break; case SEMGET: ret = sys_semget (first, second, third); @@ -96,13 +73,13 @@ if (!ptr) break; if ((ret = verify_area (VERIFY_READ, ptr, sizeof(long))) - || (ret = get_user(fourth.__pad, (void **)ptr))) + || (ret = get_user(fourth.__pad, (void *__user *)ptr))) break; ret = sys_semctl (first, second, third, fourth); break; } case MSGSND: - ret = sys_msgsnd (first, (struct msgbuf *) ptr, second, third); + ret = sys_msgsnd (first, (struct msgbuf __user *) ptr, second, third); break; case MSGRCV: switch (version) { @@ -113,15 +90,15 @@ break; if ((ret = verify_area (VERIFY_READ, ptr, sizeof(tmp))) || (ret = copy_from_user(&tmp, - (struct ipc_kludge *) ptr, - sizeof (tmp)) ? -EFAULT : 0)) + (struct ipc_kludge __user *) ptr, + sizeof (tmp)) ? -EFAULT : 0)) break; ret = sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, third); break; } default: - ret = sys_msgrcv (first, (struct msgbuf *) ptr, + ret = sys_msgrcv (first, (struct msgbuf __user *) ptr, second, fifth, third); break; } @@ -130,38 +107,28 @@ ret = sys_msgget ((key_t) first, second); break; case MSGCTL: - ret = sys_msgctl (first, second, (struct msqid_ds *) ptr); + ret = sys_msgctl (first, second, (struct msqid_ds __user *) ptr); break; - case SHMAT: - switch (version) { - default: { - ulong raddr; + case SHMAT: { + ulong raddr; - if ((ret = verify_area(VERIFY_WRITE, (ulong*) third, - sizeof(ulong)))) - break; - ret = sys_shmat (first, (char *) ptr, second, &raddr); - if (ret) - break; - ret = put_user (raddr, (ulong *) third); + if ((ret = verify_area(VERIFY_WRITE, (ulong __user *) third, + sizeof(ulong)))) break; - } - case 1: /* iBCS2 emulator entry point */ - if (!segment_eq(get_fs(), get_ds())) - break; - ret = sys_shmat (first, (char *) ptr, second, - (ulong *) third); + ret = sys_shmat (first, (char __user *) ptr, second, &raddr); + if (ret) break; - } + ret = put_user (raddr, (ulong __user *) third); break; + } case SHMDT: - ret = sys_shmdt ((char *)ptr); + ret = sys_shmdt ((char __user *)ptr); break; case SHMGET: ret = sys_shmget (first, second, third); break; case SHMCTL: - ret = sys_shmctl (first, second, (struct shmid_ds *) ptr); + ret = sys_shmctl (first, second, (struct shmid_ds __user *) ptr); break; } @@ -172,7 +139,7 @@ * sys_pipe() is the normal C calling standard for creating * a pipe. It's not the way unix traditionally does this, though. */ -int sys_pipe(int *fildes) +int sys_pipe(int __user *fildes) { int fd[2]; int error; @@ -242,7 +209,7 @@ { if ( (unsigned long)n >= 4096 ) { - unsigned long *buffer = (unsigned long *)n; + unsigned long __user *buffer = (unsigned long __user *)n; if (verify_area(VERIFY_READ, buffer, 5*sizeof(unsigned long)) || __get_user(n, buffer) || __get_user(inp, ((fd_set **)(buffer+1))) @@ -254,7 +221,7 @@ return sys_select(n, inp, outp, exp, tvp); } -int sys_uname(struct old_utsname * name) +int sys_uname(struct old_utsname __user * name) { int err = -EFAULT; @@ -265,7 +232,7 @@ return err; } -int sys_olduname(struct oldold_utsname * name) +int sys_olduname(struct oldold_utsname __user * name) { int error; @@ -291,12 +258,6 @@ return error; } -#ifndef CONFIG_PCI -/* - * Those are normally defined in arch/ppc/kernel/pci.c. But when CONFIG_PCI is - * not defined, this file is not linked at all, so here are the "empty" versions - */ -int sys_pciconfig_read(void) { return -ENOSYS; } -int sys_pciconfig_write(void) { return -ENOSYS; } -long sys_pciconfig_iobase(void) { return -ENOSYS; } -#endif +cond_syscall(sys_pciconfig_read); +cond_syscall(sys_pciconfig_write); +cond_syscall(sys_pciconfig_iobase); diff -Nru a/arch/ppc/kernel/traps.c b/arch/ppc/kernel/traps.c --- a/arch/ppc/kernel/traps.c Mon Jun 9 23:16:08 2003 +++ b/arch/ppc/kernel/traps.c Mon Jun 9 23:16:08 2003 @@ -117,7 +117,7 @@ */ static inline int check_io_access(struct pt_regs *regs) { -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC unsigned long msr = regs->msr; const struct exception_table_entry *entry; unsigned int *nip = (unsigned int *)regs->nip; @@ -150,7 +150,7 @@ return 1; } } -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PMAC */ return 0; } @@ -281,7 +281,7 @@ return retval; CHECK_FULL_REGS(regs); - if (get_user(instword, (uint *)(regs->nip))) + if (get_user(instword, (uint __user *)(regs->nip))) return -EFAULT; /* Emulate the mfspr rD, PVR. @@ -296,13 +296,63 @@ return(retval); } +/* + * Look through the list of trap instructions that are used for BUG(), + * BUG_ON() and WARN_ON() and see if we hit one. At this point we know + * that the exception was caused by a trap instruction of some kind. + * Returns 1 if we should continue (i.e. it was a WARN_ON) or 0 + * otherwise. + */ +extern struct bug_entry __start___bug_table[], __stop___bug_table[]; + +#ifndef CONFIG_MODULES +#define module_find_bug(x) NULL +#endif + +static struct bug_entry *find_bug(unsigned long bugaddr) +{ + struct bug_entry *bug; + + for (bug = __start___bug_table; bug < __stop___bug_table; ++bug) + if (bugaddr == bug->bug_addr) + return bug; + return module_find_bug(bugaddr); +} + +int +check_bug_trap(struct pt_regs *regs) +{ + struct bug_entry *bug; + unsigned long addr; + + if (regs->msr & MSR_PR) + return 0; /* not in kernel */ + addr = regs->nip; /* address of trap instruction */ + if (addr < PAGE_OFFSET) + return 0; + bug = find_bug(regs->nip); + if (bug == NULL) + return 0; + if (bug->line & BUG_WARNING_TRAP) { + /* this is a WARN_ON rather than BUG/BUG_ON */ + printk(KERN_ERR "Badness in %s at %s:%d\n", + bug->function, bug->file, + bug->line & ~BUG_WARNING_TRAP); + dump_stack(); + return 1; + } + printk(KERN_CRIT "kernel BUG in %s at %s:%d!\n", + bug->function, bug->file, bug->line); + return 0; +} + void ProgramCheckException(struct pt_regs *regs) { int errcode; #if defined(CONFIG_4xx) - unsigned int esr = mfspr(SPRN_ESR); + unsigned int esr = regs->dsisr; int isbpt = esr & ESR_PTR; extern int do_mathemu(struct pt_regs *regs); @@ -325,6 +375,10 @@ /* trap exception */ if (debugger_bpt(regs)) return; + if (check_bug_trap(regs)) { + regs->nip += 4; + return; + } _exception(SIGTRAP, regs); return; } diff -Nru a/arch/ppc/mm/init.c b/arch/ppc/mm/init.c --- a/arch/ppc/mm/init.c Mon Jun 9 23:16:08 2003 +++ b/arch/ppc/mm/init.c Mon Jun 9 23:16:08 2003 @@ -64,7 +64,7 @@ int mem_init_done; int init_bootmem_done; int boot_mapsize; -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC unsigned long agp_special_page; #endif @@ -411,16 +411,18 @@ } #endif /* CONFIG_BLK_DEV_INITRD */ -#if defined(CONFIG_ALL_PPC) +#ifdef CONFIG_PPC_OF /* mark the RTAS pages as reserved */ if ( rtas_data ) for (addr = (ulong)__va(rtas_data); addr < PAGE_ALIGN((ulong)__va(rtas_data)+rtas_size) ; addr += PAGE_SIZE) SetPageReserved(virt_to_page(addr)); +#endif +#ifdef CONFIG_PPC_PMAC if (agp_special_page) SetPageReserved(virt_to_page(agp_special_page)); -#endif /* defined(CONFIG_ALL_PPC) */ +#endif if ( sysmap ) for (addr = (unsigned long)sysmap; addr < PAGE_ALIGN((unsigned long)sysmap+sysmap_size) ; @@ -465,10 +467,10 @@ if (sysmap) printk("System.map loaded at 0x%08x for debugger, size: %ld bytes\n", (unsigned int)sysmap, sysmap_size); -#if defined(CONFIG_ALL_PPC) +#ifdef CONFIG_PPC_PMAC if (agp_special_page) printk(KERN_INFO "AGP special page: 0x%08lx\n", agp_special_page); -#endif /* defined(CONFIG_ALL_PPC) */ +#endif /* Make sure all our pagetable pages have page->mapping and page->index set correctly. */ @@ -521,13 +523,15 @@ initrd_end - initrd_start, 1); } #endif /* CONFIG_BLK_DEV_INITRD */ -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_OF /* remove the RTAS pages from the available memory */ if (rtas_data) mem_pieces_remove(&phys_avail, rtas_data, rtas_size, 1); +#endif /* remove the sysmap pages from the available memory */ if (sysmap) mem_pieces_remove(&phys_avail, __pa(sysmap), sysmap_size, 1); +#ifdef CONFIG_PPC_PMAC /* Because of some uninorth weirdness, we need a page of * memory as high as possible (it must be outside of the * bus address seen as the AGP aperture). It will be used @@ -542,7 +546,7 @@ mem_pieces_remove(&phys_avail, agp_special_page, PAGE_SIZE, 0); agp_special_page = (unsigned long)__va(agp_special_page); } -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PMAC */ } /* Mark some memory as reserved by removing it from phys_avail. */ diff -Nru a/arch/ppc/mm/mem_pieces.c b/arch/ppc/mm/mem_pieces.c --- a/arch/ppc/mm/mem_pieces.c Mon Jun 9 23:16:05 2003 +++ b/arch/ppc/mm/mem_pieces.c Mon Jun 9 23:16:05 2003 @@ -120,7 +120,7 @@ printk("\n"); } -#if defined(CONFIG_APUS) || defined(CONFIG_ALL_PPC) +#if defined(CONFIG_APUS) || defined(CONFIG_PPC_OF) /* * Add some memory to an array of pieces */ @@ -135,7 +135,7 @@ rp->address = start; rp->size = size; } -#endif /* CONFIG_APUS || CONFIG_ALL_PPC */ +#endif /* CONFIG_APUS || CONFIG_PPC_OF */ void __init mem_pieces_sort(struct mem_pieces *mp) diff -Nru a/arch/ppc/mm/pgtable.c b/arch/ppc/mm/pgtable.c --- a/arch/ppc/mm/pgtable.c Mon Jun 9 23:16:08 2003 +++ b/arch/ppc/mm/pgtable.c Mon Jun 9 23:16:08 2003 @@ -74,7 +74,6 @@ pte_t *pte; extern int mem_init_done; extern void *early_get_page(void); - int timeout = 0; if (mem_init_done) pte = (pte_t *)__get_free_page(GFP_KERNEL|__GFP_REPEAT); diff -Nru a/arch/ppc/platforms/Makefile b/arch/ppc/platforms/Makefile --- a/arch/ppc/platforms/Makefile Mon Jun 9 23:16:20 2003 +++ b/arch/ppc/platforms/Makefile Mon Jun 9 23:16:20 2003 @@ -16,17 +16,15 @@ ifeq ($(CONFIG_APUS),y) obj-$(CONFIG_PCI) += apus_pci.o endif -obj-$(CONFIG_ALL_PPC) += pmac_pic.o pmac_setup.o pmac_time.o \ - pmac_feature.o pmac_pci.o chrp_setup.o\ - chrp_time.o chrp_pci.o prep_pci.o \ - prep_time.o prep_setup.o pmac_sleep.o -ifeq ($(CONFIG_ALL_PPC),y) +obj-$(CONFIG_PPC_PMAC) += pmac_pic.o pmac_setup.o pmac_time.o \ + pmac_feature.o pmac_pci.o pmac_sleep.o +obj-$(CONFIG_PPC_CHRP) += chrp_setup.o chrp_time.o chrp_pci.o +obj-$(CONFIG_PPC_PREP) += prep_pci.o prep_time.o prep_setup.o +ifeq ($(CONFIG_PPC_PMAC),y) obj-$(CONFIG_NVRAM) += pmac_nvram.o -endif -obj-$(CONFIG_PMAC_BACKLIGHT) += pmac_backlight.o -ifeq ($(CONFIG_ALL_PPC),y) obj-$(CONFIG_CPU_FREQ_PMAC) += pmac_cpufreq.o endif +obj-$(CONFIG_PMAC_BACKLIGHT) += pmac_backlight.o obj-$(CONFIG_PPC_RTAS) += error_log.o proc_rtas.o obj-$(CONFIG_PREP_RESIDUAL) += residual.o obj-$(CONFIG_ADIR) += adir_setup.o adir_pic.o adir_pci.o @@ -50,5 +48,6 @@ obj-$(CONFIG_ZX4500) += zx4500_setup.o zx4500_pci.o ifeq ($(CONFIG_SMP),y) -obj-$(CONFIG_ALL_PPC) += pmac_smp.o chrp_smp.o +obj-$(CONFIG_PPC_PMAC) += pmac_smp.o +obj-$(CONFIG_PPC_CHRP) += chrp_smp.o endif diff -Nru a/arch/ppc/platforms/chrp_pci.c b/arch/ppc/platforms/chrp_pci.c --- a/arch/ppc/platforms/chrp_pci.c Mon Jun 9 23:16:20 2003 +++ b/arch/ppc/platforms/chrp_pci.c Mon Jun 9 23:16:20 2003 @@ -154,11 +154,11 @@ void __init chrp_pcibios_fixup(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; struct device_node *np; /* PCI interrupts are controlled by the OpenPIC */ - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { np = pci_device_to_OF_node(dev); if ((np != 0) && (np->n_intrs > 0) && (np->intrs[0].line != 0)) dev->irq = np->intrs[0].line; diff -Nru a/arch/ppc/platforms/gemini_pci.c b/arch/ppc/platforms/gemini_pci.c --- a/arch/ppc/platforms/gemini_pci.c Mon Jun 9 23:16:09 2003 +++ b/arch/ppc/platforms/gemini_pci.c Mon Jun 9 23:16:09 2003 @@ -13,9 +13,9 @@ void __init gemini_pcibios_fixup(void) { int i; - struct pci_dev *dev; + struct pci_dev *dev = NULL; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { for(i = 0; i < 6; i++) { if (dev->resource[i].flags & IORESOURCE_IO) { dev->resource[i].start |= (0xfe << 24); diff -Nru a/arch/ppc/platforms/pmac_pci.c b/arch/ppc/platforms/pmac_pci.c --- a/arch/ppc/platforms/pmac_pci.c Mon Jun 9 23:16:12 2003 +++ b/arch/ppc/platforms/pmac_pci.c Mon Jun 9 23:16:12 2003 @@ -494,7 +494,7 @@ static void __init pcibios_fixup_OF_interrupts(void) { - struct pci_dev* dev; + struct pci_dev* dev = NULL; /* * Open Firmware often doesn't initialize the @@ -502,7 +502,7 @@ * should find the device node and apply the interrupt * obtained from the OF device-tree */ - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { struct device_node *node; node = pci_device_to_OF_node(dev); /* this is the node, see if it has interrupts */ @@ -590,7 +590,7 @@ struct device_node* nd; #ifdef CONFIG_BLK_DEV_IDE - struct pci_dev *dev; + struct pci_dev *dev = NULL; /* OF fails to initialize IDE controllers on macs * (and maybe other machines) @@ -602,7 +602,7 @@ * * -- BenH */ - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { if ((dev->class >> 16) == PCI_BASE_CLASS_STORAGE) pci_enable_device(dev); } diff -Nru a/arch/ppc/platforms/prep_pci.c b/arch/ppc/platforms/prep_pci.c --- a/arch/ppc/platforms/prep_pci.c Mon Jun 9 23:16:19 2003 +++ b/arch/ppc/platforms/prep_pci.c Mon Jun 9 23:16:19 2003 @@ -1171,7 +1171,7 @@ void __init prep_pcibios_fixup(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; extern unsigned char *Motherboard_map; extern unsigned char *Motherboard_routes; @@ -1180,7 +1180,7 @@ printk("Setting PCI interrupts for a \"%s\"\n", Motherboard_map_name); if (OpenPIC_Addr) { /* PCI interrupts are controlled by the OpenPIC */ - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { if (dev->bus->number == 0) { dev->irq = openpic_to_irq(Motherboard_map[PCI_SLOT(dev->devfn)]); pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); @@ -1196,7 +1196,8 @@ return; } - pci_for_each_dev(dev) { + dev = NULL; + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { /* * Use our old hard-coded kludge to figure out what * irq this device uses. This is necessary on things diff -Nru a/arch/ppc/platforms/residual.c b/arch/ppc/platforms/residual.c --- a/arch/ppc/platforms/residual.c Mon Jun 9 23:16:08 2003 +++ b/arch/ppc/platforms/residual.c Mon Jun 9 23:16:08 2003 @@ -476,7 +476,9 @@ break; } } -static void __init printpackets(PnP_TAG_PACKET * pkt, const char * cat) { + +static void __init printpackets(PnP_TAG_PACKET * pkt, const char * cat) +{ if (pkt->S1_Pack.Tag== END_TAG) { printk(" No packets describing %s resources.\n", cat); return; @@ -493,7 +495,7 @@ size=tag_small_count(pkt->S1_Pack.Tag)+1; printsmallpacket(pkt, size); } - (unsigned char *) pkt+=size; + pkt = (PnP_TAG_PACKET *)((unsigned char *) pkt + size); } while (pkt->S1_Pack.Tag != END_TAG); } diff -Nru a/arch/ppc/syslib/Makefile b/arch/ppc/syslib/Makefile --- a/arch/ppc/syslib/Makefile Mon Jun 9 23:16:07 2003 +++ b/arch/ppc/syslib/Makefile Mon Jun 9 23:16:07 2003 @@ -27,8 +27,10 @@ ifeq ($(CONFIG_8xx),y) obj-$(CONFIG_PCI) += qspan_pci.o i8259.o endif -obj-$(CONFIG_ALL_PPC) += prom_init.o prom.o open_pic.o \ - indirect_pci.o i8259.o +obj-$(CONFIG_PPC_OF) += prom_init.o prom.o +obj-$(CONFIG_PPC_PMAC) += open_pic.o indirect_pci.o +obj-$(CONFIG_PPC_CHRP) += open_pic.o indirect_pci.o i8259.o +obj-$(CONFIG_PPC_PREP) += open_pic.o indirect_pci.o i8259.o obj-$(CONFIG_ADIR) += i8259.o indirect_pci.o pci_auto.o \ todc_time.o obj-$(CONFIG_EV64260) += gt64260_common.o gt64260_pic.o \ diff -Nru a/arch/ppc/syslib/prom.c b/arch/ppc/syslib/prom.c --- a/arch/ppc/syslib/prom.c Mon Jun 9 23:16:07 2003 +++ b/arch/ppc/syslib/prom.c Mon Jun 9 23:16:07 2003 @@ -464,7 +464,7 @@ struct device_node *np; struct property *pp; -#define ADDBASE(x) (x = (x)? ((typeof (x))((unsigned long)(x) + base)): 0) +#define ADDBASE(x) (x = (typeof (x))((x)? ((unsigned long)(x) + base): 0)) base = (unsigned long) boot_infos + boot_infos->deviceTreeOffset; allnodes = (struct device_node *)(base + 4); diff -Nru a/arch/ppc/vmlinux.lds.S b/arch/ppc/vmlinux.lds.S --- a/arch/ppc/vmlinux.lds.S Mon Jun 9 23:16:20 2003 +++ b/arch/ppc/vmlinux.lds.S Mon Jun 9 23:16:20 2003 @@ -54,6 +54,10 @@ __ex_table : { *(__ex_table) } __stop___ex_table = .; + __start___bug_table = .; + __bug_table : { *(__bug_table) } + __stop___bug_table = .; + /* Read-write section, merged into data segment: */ . = ALIGN(4096); .data : diff -Nru a/arch/ppc/xmon/ppc-opc.c b/arch/ppc/xmon/ppc-opc.c --- a/arch/ppc/xmon/ppc-opc.c Mon Jun 9 23:16:05 2003 +++ b/arch/ppc/xmon/ppc-opc.c Mon Jun 9 23:16:05 2003 @@ -394,18 +394,13 @@ /*ARGSUSED*/ static unsigned long -insert_bat (insn, value, errmsg) - unsigned long insn; - long value; - const char **errmsg; +insert_bat(unsigned long insn, long value, const char **errmsg) { return insn | (((insn >> 21) & 0x1f) << 16); } static long -extract_bat (insn, invalid) - unsigned long insn; - int *invalid; +extract_bat(unsigned long insn, int *invalid) { if (invalid != (int *) NULL && ((insn >> 21) & 0x1f) != ((insn >> 16) & 0x1f)) @@ -421,18 +416,13 @@ /*ARGSUSED*/ static unsigned long -insert_bba (insn, value, errmsg) - unsigned long insn; - long value; - const char **errmsg; +insert_bba(unsigned long insn, long value, const char **errmsg) { return insn | (((insn >> 16) & 0x1f) << 11); } static long -extract_bba (insn, invalid) - unsigned long insn; - int *invalid; +extract_bba(unsigned long insn, int *invalid) { if (invalid != (int *) NULL && ((insn >> 16) & 0x1f) != ((insn >> 11) & 0x1f)) @@ -445,19 +435,14 @@ /*ARGSUSED*/ static unsigned long -insert_bd (insn, value, errmsg) - unsigned long insn; - long value; - const char **errmsg; +insert_bd(unsigned long insn, long value, const char **errmsg) { return insn | (value & 0xfffc); } /*ARGSUSED*/ static long -extract_bd (insn, invalid) - unsigned long insn; - int *invalid; +extract_bd(unsigned long insn, int *invalid) { if ((insn & 0x8000) != 0) return (insn & 0xfffc) - 0x10000; @@ -474,10 +459,7 @@ /*ARGSUSED*/ static unsigned long -insert_bdm (insn, value, errmsg) - unsigned long insn; - long value; - const char **errmsg; +insert_bdm(unsigned long insn, long value, const char **errmsg) { if ((value & 0x8000) != 0) insn |= 1 << 21; @@ -485,9 +467,7 @@ } static long -extract_bdm (insn, invalid) - unsigned long insn; - int *invalid; +extract_bdm(unsigned long insn, int *invalid) { if (invalid != (int *) NULL && ((insn & (1 << 21)) == 0 @@ -505,10 +485,7 @@ /*ARGSUSED*/ static unsigned long -insert_bdp (insn, value, errmsg) - unsigned long insn; - long value; - const char **errmsg; +insert_bdp(unsigned long insn, long value, const char **errmsg) { if ((value & 0x8000) == 0) insn |= 1 << 21; @@ -516,9 +493,7 @@ } static long -extract_bdp (insn, invalid) - unsigned long insn; - int *invalid; +extract_bdp(unsigned long insn, int *invalid) { if (invalid != (int *) NULL && ((insn & (1 << 21)) == 0 @@ -561,10 +536,7 @@ the field to an illegal value. */ static unsigned long -insert_bo (insn, value, errmsg) - unsigned long insn; - long value; - const char **errmsg; +insert_bo(unsigned long insn, long value, const char **errmsg) { if (errmsg != (const char **) NULL && ! valid_bo (value)) @@ -573,9 +545,7 @@ } static long -extract_bo (insn, invalid) - unsigned long insn; - int *invalid; +extract_bo(unsigned long insn, int *invalid) { long value; @@ -591,10 +561,7 @@ extracting it, we force it to be even. */ static unsigned long -insert_boe (insn, value, errmsg) - unsigned long insn; - long value; - const char **errmsg; +insert_boe(unsigned long insn, long value, const char **errmsg) { if (errmsg != (const char **) NULL) { @@ -607,9 +574,7 @@ } static long -extract_boe (insn, invalid) - unsigned long insn; - int *invalid; +extract_boe(unsigned long insn, int *invalid) { long value; @@ -625,19 +590,14 @@ /*ARGSUSED*/ static unsigned long -insert_ds (insn, value, errmsg) - unsigned long insn; - long value; - const char **errmsg; +insert_ds(unsigned long insn, long value, const char **errmsg) { return insn | (value & 0xfffc); } /*ARGSUSED*/ static long -extract_ds (insn, invalid) - unsigned long insn; - int *invalid; +extract_ds(unsigned long insn, int *invalid) { if ((insn & 0x8000) != 0) return (insn & 0xfffc) - 0x10000; @@ -650,19 +610,14 @@ /*ARGSUSED*/ static unsigned long -insert_li (insn, value, errmsg) - unsigned long insn; - long value; - const char **errmsg; +insert_li(unsigned long insn, long value, const char **errmsg) { return insn | (value & 0x3fffffc); } /*ARGSUSED*/ static long -extract_li (insn, invalid) - unsigned long insn; - int *invalid; +extract_li(unsigned long insn, int *invalid) { if ((insn & 0x2000000) != 0) return (insn & 0x3fffffc) - 0x4000000; @@ -676,10 +631,7 @@ instruction which uses a field of this type. */ static unsigned long -insert_mbe (insn, value, errmsg) - unsigned long insn; - long value; - const char **errmsg; +insert_mbe(unsigned long insn, long value, const char **errmsg) { unsigned long uval; int mb, me; @@ -718,9 +670,7 @@ } static long -extract_mbe (insn, invalid) - unsigned long insn; - int *invalid; +extract_mbe(unsigned long insn, int *invalid) { long ret; int mb, me; @@ -742,19 +692,14 @@ /*ARGSUSED*/ static unsigned long -insert_mb6 (insn, value, errmsg) - unsigned long insn; - long value; - const char **errmsg; +insert_mb6(unsigned long insn, long value, const char **errmsg) { return insn | ((value & 0x1f) << 6) | (value & 0x20); } /*ARGSUSED*/ static long -extract_mb6 (insn, invalid) - unsigned long insn; - int *invalid; +extract_mb6(unsigned long insn, int *invalid) { return ((insn >> 6) & 0x1f) | (insn & 0x20); } @@ -763,10 +708,7 @@ 0. */ static unsigned long -insert_nb (insn, value, errmsg) - unsigned long insn; - long value; - const char **errmsg; +insert_nb(unsigned long insn, long value, const char **errmsg) { if (value < 0 || value > 32) *errmsg = "value out of range"; @@ -777,9 +719,7 @@ /*ARGSUSED*/ static long -extract_nb (insn, invalid) - unsigned long insn; - int *invalid; +extract_nb(unsigned long insn, int *invalid) { long ret; @@ -796,18 +736,13 @@ /*ARGSUSED*/ static unsigned long -insert_nsi (insn, value, errmsg) - unsigned long insn; - long value; - const char **errmsg; +insert_nsi(unsigned long insn, long value, const char **errmsg) { return insn | ((- value) & 0xffff); } static long -extract_nsi (insn, invalid) - unsigned long insn; - int *invalid; +extract_nsi(unsigned long insn, int *invalid) { if (invalid != (int *) NULL) *invalid = 1; @@ -822,10 +757,7 @@ equal the RT field. */ static unsigned long -insert_ral (insn, value, errmsg) - unsigned long insn; - long value; - const char **errmsg; +insert_ral(unsigned long insn, long value, const char **errmsg) { if (value == 0 || value == ((insn >> 21) & 0x1f)) @@ -837,10 +769,7 @@ restrictions. */ static unsigned long -insert_ram (insn, value, errmsg) - unsigned long insn; - long value; - const char **errmsg; +insert_ram(unsigned long insn, long value, const char **errmsg) { if (value >= ((insn >> 21) & 0x1f)) *errmsg = "index register in load range"; @@ -852,10 +781,7 @@ field may not be zero. */ static unsigned long -insert_ras (insn, value, errmsg) - unsigned long insn; - long value; - const char **errmsg; +insert_ras(unsigned long insn, long value, const char **errmsg) { if (value == 0) *errmsg = "invalid register operand when updating"; @@ -870,18 +796,13 @@ /*ARGSUSED*/ static unsigned long -insert_rbs (insn, value, errmsg) - unsigned long insn; - long value; - const char **errmsg; +insert_rbs(unsigned long insn, long value, const char **errmsg) { return insn | (((insn >> 21) & 0x1f) << 11); } static long -extract_rbs (insn, invalid) - unsigned long insn; - int *invalid; +extract_rbs(unsigned long insn, int *invalid) { if (invalid != (int *) NULL && ((insn >> 21) & 0x1f) != ((insn >> 11) & 0x1f)) @@ -893,19 +814,14 @@ /*ARGSUSED*/ static unsigned long -insert_sh6 (insn, value, errmsg) - unsigned long insn; - long value; - const char **errmsg; +insert_sh6(unsigned long insn, long value, const char **errmsg) { return insn | ((value & 0x1f) << 11) | ((value & 0x20) >> 4); } /*ARGSUSED*/ static long -extract_sh6 (insn, invalid) - unsigned long insn; - int *invalid; +extract_sh6(unsigned long insn, int *invalid) { return ((insn >> 11) & 0x1f) | ((insn << 4) & 0x20); } @@ -914,18 +830,13 @@ lower 5 bits are stored in the upper 5 and vice- versa. */ static unsigned long -insert_spr (insn, value, errmsg) - unsigned long insn; - long value; - const char **errmsg; +insert_spr(unsigned long insn, long value, const char **errmsg) { return insn | ((value & 0x1f) << 16) | ((value & 0x3e0) << 6); } static long -extract_spr (insn, invalid) - unsigned long insn; - int *invalid; +extract_spr(unsigned long insn, int *invalid) { return ((insn >> 16) & 0x1f) | ((insn >> 6) & 0x3e0); } @@ -941,10 +852,7 @@ #define TB (268) static unsigned long -insert_tbr (insn, value, errmsg) - unsigned long insn; - long value; - const char **errmsg; +insert_tbr(unsigned long insn, long value, const char **errmsg) { if (value == 0) value = TB; @@ -952,9 +860,7 @@ } static long -extract_tbr (insn, invalid) - unsigned long insn; - int *invalid; +extract_tbr(unsigned long insn, int *invalid) { long ret; diff -Nru a/arch/ppc/xmon/start.c b/arch/ppc/xmon/start.c --- a/arch/ppc/xmon/start.c Mon Jun 9 23:16:05 2003 +++ b/arch/ppc/xmon/start.c Mon Jun 9 23:16:05 2003 @@ -12,6 +12,7 @@ #include <linux/kernel.h> #include <linux/errno.h> #include <linux/sysrq.h> +#include <asm/xmon.h> #include <asm/prom.h> #include <asm/bootx.h> #include <asm/machdep.h> @@ -52,7 +53,7 @@ extern int adb_init(void); -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_CHRP /* * This looks in the "ranges" property for the primary PCI host bridge * to find the physical address of the start of PCI/ISA I/O space. @@ -90,7 +91,7 @@ } return base; } -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_CHRP */ #ifdef CONFIG_MAGIC_SYSRQ static void sysrq_handle_xmon(int key, struct pt_regs *regs, @@ -110,7 +111,7 @@ void xmon_map_scc(void) { -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_MULTIPLATFORM volatile unsigned char *base; if (_machine == _MACH_Pmac) { @@ -397,7 +398,7 @@ }; void -xmon_init_scc() +xmon_init_scc(void) { if ( _machine == _MACH_chrp ) { diff -Nru a/arch/ppc/xmon/xmon.c b/arch/ppc/xmon/xmon.c --- a/arch/ppc/xmon/xmon.c Mon Jun 9 23:16:05 2003 +++ b/arch/ppc/xmon/xmon.c Mon Jun 9 23:16:05 2003 @@ -356,7 +356,7 @@ } static void -insert_bpts() +insert_bpts(void) { int i; struct bpt *bp; @@ -382,7 +382,7 @@ } static void -remove_bpts() +remove_bpts(void) { int i; struct bpt *bp; @@ -843,7 +843,7 @@ } int -getsp() +getsp(void) { int x; @@ -969,7 +969,7 @@ } void -super_regs() +super_regs(void) { int i, cmd; unsigned val; @@ -1019,7 +1019,7 @@ #ifndef CONFIG_PPC_STD_MMU static void -dump_hash_table() +dump_hash_table(void) { printf("This CPU doesn't have a hash table.\n"); } @@ -1149,7 +1149,7 @@ static unsigned hash_end; static void -dump_hash_table() +dump_hash_table(void) { int seg; unsigned seg_start, seg_end; @@ -1271,7 +1271,7 @@ static int mnoread; void -memex() +memex(void) { int cmd, inc, i, nslash; unsigned n; @@ -1408,7 +1408,7 @@ } int -bsesc() +bsesc(void) { int c; @@ -1423,7 +1423,7 @@ } void -dump() +dump(void) { int c; @@ -1522,8 +1522,7 @@ } void -print_address(addr) -unsigned addr; +print_address(unsigned addr) { printf("0x%x", addr); } @@ -1582,7 +1581,7 @@ static unsigned mask; void -memlocate() +memlocate(void) { unsigned a, n; unsigned char val[4]; @@ -1615,7 +1614,7 @@ static unsigned mlim = 0xffffffff; void -memzcan() +memzcan(void) { unsigned char v; unsigned a; @@ -1679,7 +1678,7 @@ /* Input scanning routines */ int -skipbl() +skipbl(void) { int c; @@ -1704,8 +1703,7 @@ }; int -scanhex(vp) -unsigned *vp; +scanhex(unsigned *vp) { int c, d; unsigned v; @@ -1776,7 +1774,7 @@ } void -scannl() +scannl(void) { int c; @@ -1786,8 +1784,7 @@ c = inchar(); } -int -hexdigit(c) +int hexdigit(int c) { if( '0' <= c && c <= '9' ) return c - '0'; @@ -1819,13 +1816,13 @@ static char *lineptr; void -flush_input() +flush_input(void) { lineptr = NULL; } int -inchar() +inchar(void) { if (lineptr == NULL || *lineptr == 0) { if (fgets(line, sizeof(line), stdin) == NULL) { @@ -1838,8 +1835,7 @@ } void -take_input(str) -char *str; +take_input(char *str) { lineptr = str; } diff -Nru a/arch/ppc64/Kconfig b/arch/ppc64/Kconfig --- a/arch/ppc64/Kconfig Mon Jun 9 23:16:13 2003 +++ b/arch/ppc64/Kconfig Mon Jun 9 23:16:13 2003 @@ -37,6 +37,13 @@ bool default y +# We optimistically allocate largepages from the VM, so make the limit +# large enough (16MB). This badly named config option is actually +# max order + 1 +config FORCE_MAX_ZONEORDER + int + default "13" + source "init/Kconfig" @@ -234,7 +241,7 @@ source "drivers/pcmcia/Kconfig" -source "drivers/hotplug/Kconfig" +source "drivers/pci/hotplug/Kconfig" config PROC_DEVICETREE bool "Support for Open Firmware device tree in /proc" diff -Nru a/arch/ppc64/boot/Makefile b/arch/ppc64/boot/Makefile --- a/arch/ppc64/boot/Makefile Mon Jun 9 23:16:17 2003 +++ b/arch/ppc64/boot/Makefile Mon Jun 9 23:16:17 2003 @@ -98,7 +98,7 @@ $(obj)/kernel-initrd.gz: $(obj)/ramdisk.image.gz cp -f $(obj)/ramdisk.image.gz $@ -$(call src-sec, $(required) $(initrd)): $(obj)/kernel-%.c: $(obj)/kernel-%.gz +$(call src-sec, $(required) $(initrd)): $(obj)/kernel-%.c: $(obj)/kernel-%.gz FORCE touch $@ $(call obj-sec, $(required) $(initrd)): $(obj)/kernel-%.o: $(obj)/kernel-%.c FORCE diff -Nru a/arch/ppc64/boot/main.c b/arch/ppc64/boot/main.c --- a/arch/ppc64/boot/main.c Mon Jun 9 23:16:20 2003 +++ b/arch/ppc64/boot/main.c Mon Jun 9 23:16:20 2003 @@ -8,7 +8,6 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ -#define __KERNEL__ #include "ppc32-types.h" #include "zlib.h" #include <linux/elf.h> @@ -27,6 +26,10 @@ void flush_cache(void *, unsigned long); void pause(void); extern void exit(void); + +unsigned long strlen(const char *s); +void *memmove(void *dest, const void *src, unsigned long n); +void *memcpy(void *dest, const void *src, unsigned long n); static struct bi_record *make_bi_recs(unsigned long); diff -Nru a/arch/ppc64/boot/zlib.c b/arch/ppc64/boot/zlib.c --- a/arch/ppc64/boot/zlib.c Mon Jun 9 23:16:08 2003 +++ b/arch/ppc64/boot/zlib.c Mon Jun 9 23:16:08 2003 @@ -322,8 +322,9 @@ }; -int inflateReset(z) -z_stream *z; +int inflateReset( + z_stream *z +) { uLong c; @@ -338,8 +339,9 @@ } -int inflateEnd(z) -z_stream *z; +int inflateEnd( + z_stream *z +) { uLong c; @@ -354,9 +356,10 @@ } -int inflateInit2(z, w) -z_stream *z; -int w; +int inflateInit2( + z_stream *z, + int w +) { /* initialize state */ if (z == Z_NULL) @@ -400,8 +403,9 @@ } -int inflateInit(z) -z_stream *z; +int inflateInit( + z_stream *z +) { return inflateInit2(z, DEF_WBITS); } @@ -410,9 +414,10 @@ #define NEEDBYTE {if(z->avail_in==0)goto empty;r=Z_OK;} #define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) -int inflate(z, f) -z_stream *z; -int f; +int inflate( + z_stream *z, + int f +) { int r; uInt b; @@ -527,8 +532,9 @@ * will have been updated if need be. */ -int inflateIncomp(z) -z_stream *z; +int inflateIncomp( + z_stream *z +) { if (z->state->mode != BLOCKS) return Z_DATA_ERROR; @@ -536,8 +542,9 @@ } -int inflateSync(z) -z_stream *z; +int inflateSync( + z_stream *z +) { uInt n; /* number of bytes to look at */ Bytef *p; /* pointer to bytes */ @@ -760,10 +767,11 @@ */ -local void inflate_blocks_reset(s, z, c) -inflate_blocks_statef *s; -z_stream *z; -uLongf *c; +local void inflate_blocks_reset( + inflate_blocks_statef *s, + z_stream *z, + uLongf *c +) { if (s->checkfn != Z_NULL) *c = s->check; @@ -785,10 +793,11 @@ } -local inflate_blocks_statef *inflate_blocks_new(z, c, w) -z_stream *z; -check_func c; -uInt w; +local inflate_blocks_statef *inflate_blocks_new( + z_stream *z, + check_func c, + uInt w +) { inflate_blocks_statef *s; @@ -809,10 +818,11 @@ } -local int inflate_blocks(s, z, r) -inflate_blocks_statef *s; -z_stream *z; -int r; +local int inflate_blocks( + inflate_blocks_statef *s, + z_stream *z, + int r +) { uInt t; /* temporary storage */ uLong b; /* bit buffer */ @@ -1072,10 +1082,11 @@ } -local int inflate_blocks_free(s, z, c) -inflate_blocks_statef *s; -z_stream *z; -uLongf *c; +local int inflate_blocks_free( + inflate_blocks_statef *s, + z_stream *z, + uLongf *c +) { inflate_blocks_reset(s, z, c); ZFREE(z, s->window, s->end - s->window); @@ -1092,9 +1103,10 @@ * BLOCKS). On exit, the output will also be caught up, and the checksum * will have been updated if need be. */ -local int inflate_addhistory(s, z) -inflate_blocks_statef *s; -z_stream *z; +local int inflate_addhistory( + inflate_blocks_statef *s, + z_stream *z +) { uLong b; /* bit buffer */ /* NOT USED HERE */ uInt k; /* bits in bit buffer */ /* NOT USED HERE */ @@ -1142,8 +1154,9 @@ * At the end of a Deflate-compressed PPP packet, we expect to have seen * a `stored' block type value but not the (zero) length bytes. */ -local int inflate_packet_flush(s) - inflate_blocks_statef *s; +local int inflate_packet_flush( + inflate_blocks_statef *s +) { if (s->mode != LENS) return Z_DATA_ERROR; @@ -1243,15 +1256,16 @@ uInt inflate_hufts; #endif -local int huft_build(b, n, s, d, e, t, m, zs) -uIntf *b; /* code lengths in bits (all assumed <= BMAX) */ -uInt n; /* number of codes (assumed <= N_MAX) */ -uInt s; /* number of simple-valued codes (0..s-1) */ -uIntf *d; /* list of base values for non-simple codes */ -uIntf *e; /* list of extra bits for non-simple codes */ -inflate_huft * FAR *t; /* result: starting table */ -uIntf *m; /* maximum lookup bits, returns actual */ -z_stream *zs; /* for zalloc function */ +local int huft_build( + uIntf *b, /* code lengths in bits (all assumed <= BMAX) */ + uInt n, /* number of codes (assumed <= N_MAX) */ + uInt s, /* number of simple-valued codes (0..s-1) */ + uIntf *d, /* list of base values for non-simple codes */ + uIntf *e, /* list of extra bits for non-simple codes */ + inflate_huft * FAR *t, /* result: starting table */ + uIntf *m, /* maximum lookup bits, returns actual */ + z_stream *zs /* for zalloc function */ +) /* Given a list of code lengths and a maximum table size, make a set of tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR if the given code set is incomplete (the tables are still built in this @@ -1446,11 +1460,12 @@ } -local int inflate_trees_bits(c, bb, tb, z) -uIntf *c; /* 19 code lengths */ -uIntf *bb; /* bits tree desired/actual depth */ -inflate_huft * FAR *tb; /* bits tree result */ -z_stream *z; /* for zfree function */ +local int inflate_trees_bits( + uIntf *c, /* 19 code lengths */ + uIntf *bb, /* bits tree desired/actual depth */ + inflate_huft * FAR *tb, /* bits tree result */ + z_stream *z /* for zfree function */ +) { int r; @@ -1467,15 +1482,16 @@ } -local int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, z) -uInt nl; /* number of literal/length codes */ -uInt nd; /* number of distance codes */ -uIntf *c; /* that many (total) code lengths */ -uIntf *bl; /* literal desired/actual bit depth */ -uIntf *bd; /* distance desired/actual bit depth */ -inflate_huft * FAR *tl; /* literal/length tree result */ -inflate_huft * FAR *td; /* distance tree result */ -z_stream *z; /* for zfree function */ +local int inflate_trees_dynamic( + uInt nl, /* number of literal/length codes */ + uInt nd, /* number of distance codes */ + uIntf *c, /* that many (total) code lengths */ + uIntf *bl, /* literal desired/actual bit depth */ + uIntf *bd, /* distance desired/actual bit depth */ + inflate_huft * FAR *tl, /* literal/length tree result */ + inflate_huft * FAR *td, /* distance tree result */ + z_stream *z /* for zfree function */ +) { int r; @@ -1552,11 +1568,12 @@ } -local int inflate_trees_fixed(bl, bd, tl, td) -uIntf *bl; /* literal desired/actual bit depth */ -uIntf *bd; /* distance desired/actual bit depth */ -inflate_huft * FAR *tl; /* literal/length tree result */ -inflate_huft * FAR *td; /* distance tree result */ +local int inflate_trees_fixed( + uIntf *bl, /* literal desired/actual bit depth */ + uIntf *bd, /* distance desired/actual bit depth */ + inflate_huft * FAR *tl, /* literal/length tree result */ + inflate_huft * FAR *td /* distance tree result */ +) { /* build fixed tables if not built already--lock out other instances */ while (++fixed_lock > 1) @@ -1602,9 +1619,10 @@ } -local int inflate_trees_free(t, z) -inflate_huft *t; /* table to free */ -z_stream *z; /* for zfree function */ +local int inflate_trees_free( + inflate_huft *t, /* table to free */ + z_stream *z /* for zfree function */ +) /* Free the malloc'ed tables built by huft_build(), which makes a linked list of the tables it made, with the links in a dummy first entry of each table. */ @@ -1674,10 +1692,13 @@ }; -local inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z) -uInt bl, bd; -inflate_huft *tl, *td; -z_stream *z; +local inflate_codes_statef *inflate_codes_new( + uInt bl, + uInt bd, + inflate_huft *tl, + inflate_huft *td, + z_stream *z +) { inflate_codes_statef *c; @@ -1695,10 +1716,11 @@ } -local int inflate_codes(s, z, r) -inflate_blocks_statef *s; -z_stream *z; -int r; +local int inflate_codes( + inflate_blocks_statef *s, + z_stream *z, + int r +) { uInt j; /* temporary storage */ inflate_huft *t; /* temporary pointer */ @@ -1855,9 +1877,10 @@ } -local void inflate_codes_free(c, z) -inflate_codes_statef *c; -z_stream *z; +local void inflate_codes_free( + inflate_codes_statef *c, + z_stream *z +) { ZFREE(z, c, sizeof(struct inflate_codes_state)); Tracev((stderr, "inflate: codes free\n")); @@ -1870,10 +1893,11 @@ */ /* copy as much as possible from the sliding window to the output area */ -local int inflate_flush(s, z, r) -inflate_blocks_statef *s; -z_stream *z; -int r; +local int inflate_flush( + inflate_blocks_statef *s, + z_stream *z, + int r +) { uInt n; Bytef *p, *q; @@ -1957,11 +1981,14 @@ at least ten. The ten bytes are six bytes for the longest length/ distance pair plus four bytes for overloading the bit buffer. */ -local int inflate_fast(bl, bd, tl, td, s, z) -uInt bl, bd; -inflate_huft *tl, *td; -inflate_blocks_statef *s; -z_stream *z; +local int inflate_fast( + uInt bl, + uInt bd, + inflate_huft *tl, + inflate_huft *td, + inflate_blocks_statef *s, + z_stream *z +) { inflate_huft *t; /* temporary pointer */ uInt e; /* extra bits or operation */ diff -Nru a/arch/ppc64/defconfig b/arch/ppc64/defconfig --- a/arch/ppc64/defconfig Mon Jun 9 23:16:08 2003 +++ b/arch/ppc64/defconfig Mon Jun 9 23:16:08 2003 @@ -2,7 +2,6 @@ # Automatically generated make config: don't edit # CONFIG_MMU=y -CONFIG_SWAP=y CONFIG_RWSEM_XCHGADD_ALGORITHM=y CONFIG_GENERIC_ISA_DMA=y CONFIG_HAVE_DEC_LOCK=y @@ -18,10 +17,14 @@ # # General setup # +CONFIG_SWAP=y CONFIG_SYSVIPC=y # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y CONFIG_LOG_BUF_SHIFT=15 +# CONFIG_EMBEDDED is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y # # Loadable module support @@ -155,6 +158,7 @@ # CONFIG_SCSI_QLOGIC_ISP is not set # CONFIG_SCSI_QLOGIC_FC is not set # CONFIG_SCSI_QLOGIC_1280 is not set +# CONFIG_SCSI_DC395x is not set # CONFIG_SCSI_DC390T is not set # CONFIG_SCSI_U14_34F is not set # CONFIG_SCSI_NSP32 is not set @@ -199,7 +203,6 @@ # CONFIG_PACKET_MMAP is not set # CONFIG_NETLINK_DEV is not set # CONFIG_NETFILTER is not set -CONFIG_FILTER=y CONFIG_UNIX=y # CONFIG_NET_KEY is not set CONFIG_INET=y @@ -214,8 +217,9 @@ CONFIG_SYN_COOKIES=y # CONFIG_INET_AH is not set # CONFIG_INET_ESP is not set +# CONFIG_INET_IPCOMP is not set +# CONFIG_IPV6 is not set # CONFIG_XFRM_USER is not set -CONFIG_IPV6=y # # SCTP Configuration (EXPERIMENTAL) @@ -306,6 +310,11 @@ # CONFIG_R8169 is not set # CONFIG_SK98LIN is not set # CONFIG_TIGON3 is not set + +# +# Ethernet (10000 Mbit) +# +# CONFIG_IXGB is not set # CONFIG_FDDI is not set # CONFIG_HIPPI is not set # CONFIG_PPP is not set @@ -428,6 +437,7 @@ # # I2C Hardware Sensors Chip support # +# CONFIG_I2C_SENSOR is not set # # Mice @@ -466,61 +476,81 @@ # CONFIG_VIDEO_DEV is not set # +# Digital Video Broadcasting Devices +# +# CONFIG_DVB is not set + +# # File systems # -# CONFIG_QUOTA is not set -CONFIG_AUTOFS_FS=y -# CONFIG_AUTOFS4_FS is not set -CONFIG_REISERFS_FS=y -# CONFIG_REISERFS_CHECK is not set -# CONFIG_REISERFS_PROC_INFO is not set -# CONFIG_ADFS_FS is not set -# CONFIG_AFFS_FS is not set -# CONFIG_HFS_FS is not set -# CONFIG_BEFS_FS is not set -# CONFIG_BFS_FS is not set +CONFIG_EXT2_FS=y +# CONFIG_EXT2_FS_XATTR is not set CONFIG_EXT3_FS=y # CONFIG_EXT3_FS_XATTR is not set CONFIG_JBD=y # CONFIG_JBD_DEBUG is not set -CONFIG_FAT_FS=y -CONFIG_MSDOS_FS=y -CONFIG_VFAT_FS=y -# CONFIG_EFS_FS is not set -# CONFIG_CRAMFS is not set -# CONFIG_TMPFS is not set -CONFIG_RAMFS=y -CONFIG_ISO9660_FS=y -# CONFIG_JOLIET is not set -# CONFIG_ZISOFS is not set +CONFIG_REISERFS_FS=y +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set CONFIG_JFS_FS=y # CONFIG_JFS_POSIX_ACL is not set # CONFIG_JFS_DEBUG is not set # CONFIG_JFS_STATISTICS is not set +CONFIG_XFS_FS=y +# CONFIG_XFS_RT is not set +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_POSIX_ACL is not set # CONFIG_MINIX_FS is not set -# CONFIG_VXFS_FS is not set +# CONFIG_ROMFS_FS is not set +# CONFIG_QUOTA is not set +CONFIG_AUTOFS_FS=y +# CONFIG_AUTOFS4_FS is not set + +# +# CD-ROM/DVD Filesystems +# +CONFIG_ISO9660_FS=y +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_UDF_FS is not set + +# +# DOS/FAT/NT Filesystems +# +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y # CONFIG_NTFS_FS is not set -# CONFIG_HPFS_FS is not set + +# +# Pseudo filesystems +# CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set CONFIG_DEVPTS_FS=y +# CONFIG_DEVPTS_FS_XATTR is not set +# CONFIG_TMPFS is not set +CONFIG_RAMFS=y + +# +# Miscellaneous filesystems +# +# CONFIG_ADFS_FS is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BFS_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_HPFS_FS is not set # CONFIG_QNX4FS_FS is not set -# CONFIG_ROMFS_FS is not set -CONFIG_EXT2_FS=y -# CONFIG_EXT2_FS_XATTR is not set # CONFIG_SYSV_FS is not set -# CONFIG_UDF_FS is not set # CONFIG_UFS_FS is not set -CONFIG_XFS_FS=y -# CONFIG_XFS_RT is not set -# CONFIG_XFS_QUOTA is not set -# CONFIG_XFS_POSIX_ACL 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_V4=y @@ -528,14 +558,16 @@ CONFIG_NFSD_V3=y # CONFIG_NFSD_V4 is not set CONFIG_NFSD_TCP=y -CONFIG_SUNRPC=y -# CONFIG_SUNRPC_GSS is not set CONFIG_LOCKD=y CONFIG_LOCKD_V4=y CONFIG_EXPORTFS=y -CONFIG_CIFS=y +CONFIG_SUNRPC=y +# CONFIG_SUNRPC_GSS is not set # CONFIG_SMB_FS is not set +CONFIG_CIFS=y # CONFIG_NCP_FS is not set +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set # CONFIG_AFS_FS is not set # @@ -591,7 +623,7 @@ # Graphics support # CONFIG_FB=y -# CONFIG_FB_CLGEN is not set +# CONFIG_FB_CIRRUS is not set # CONFIG_FB_PM2 is not set # CONFIG_FB_CYBER2000 is not set CONFIG_FB_OF=y @@ -600,7 +632,12 @@ # CONFIG_FB_S3TRIO is not set # CONFIG_FB_VGA16 is not set # CONFIG_FB_RIVA is not set -# CONFIG_FB_MATROX is not set +CONFIG_FB_MATROX=y +CONFIG_FB_MATROX_MILLENIUM=y +CONFIG_FB_MATROX_MYSTIQUE=y +CONFIG_FB_MATROX_G450=y +CONFIG_FB_MATROX_G100=y +CONFIG_FB_MATROX_MULTIHEAD=y # CONFIG_FB_RADEON is not set # CONFIG_FB_ATY128 is not set # CONFIG_FB_ATY is not set @@ -618,7 +655,19 @@ # CONFIG_VGA_CONSOLE is not set # CONFIG_MDA_CONSOLE is not set CONFIG_DUMMY_CONSOLE=y -# CONFIG_FRAMEBUFFER_CONSOLE is not set +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_PCI_CONSOLE=y +# CONFIG_FONTS is not set +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y + +# +# Logo configuration +# +CONFIG_LOGO=y +CONFIG_LOGO_LINUX_MONO=y +CONFIG_LOGO_LINUX_VGA16=y +CONFIG_LOGO_LINUX_CLUT224=y # # Sound @@ -629,6 +678,7 @@ # USB support # # CONFIG_USB is not set +# CONFIG_USB_GADGET is not set # # Bluetooth support diff -Nru a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile --- a/arch/ppc64/kernel/Makefile Mon Jun 9 23:16:19 2003 +++ b/arch/ppc64/kernel/Makefile Mon Jun 9 23:16:19 2003 @@ -7,7 +7,7 @@ obj-y := setup.o entry.o traps.o irq.o idle.o \ time.o process.o signal.o syscalls.o misc.o ptrace.o \ align.o semaphore.o bitops.o stab.o htab.o pacaData.o \ - udbg.o binfmt_elf32.o sys_ppc32.o sys32.o ioctl32.o \ + udbg.o binfmt_elf32.o sys_ppc32.o ioctl32.o \ ptrace32.o signal32.o pmc.o rtc.o init_task.o \ lmb.o pci.o pci_dn.o pci_dma.o diff -Nru a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S --- a/arch/ppc64/kernel/head.S Mon Jun 9 23:16:13 2003 +++ b/arch/ppc64/kernel/head.S Mon Jun 9 23:16:13 2003 @@ -596,7 +596,7 @@ cmpi 0,r22,0xc /* Segment fault on a bolted segment. Go off and map that segment. */ - beq .do_stab_bolted + beq- .do_stab_bolted stab_bolted_user_return: EXCEPTION_PROLOG_COMMON ld r3,_DSISR(r1) @@ -606,7 +606,7 @@ rlwinm r4,r3,32-23,29,29 /* DSISR_STORE -> _PAGE_RW */ ld r3,_DAR(r1) /* into the hash table */ - beq 2f /* If so handle it */ + beq+ 2f /* If so handle it */ li r4,0x300 /* Trap number */ bl .do_stab_SI b 1f @@ -658,7 +658,7 @@ EXCEPTION_PROLOG_COMMON andis. r0,r23,0x0020 /* no ste found? */ - beq 2f + beq+ 2f mr r3,r22 /* SRR0 at interrupt */ li r4,0x400 /* Trap number */ bl .do_stab_SI @@ -688,7 +688,7 @@ li r4,0x480 /* Exception vector */ bl .ste_allocate or. r3,r3,r3 /* Check return code */ - beq fast_exception_return /* Return if we succeeded */ + beq+ fast_exception_return /* Return if we succeeded */ addi r3,r1,STACK_FRAME_OVERHEAD #ifdef DO_SOFT_DISABLE @@ -897,18 +897,8 @@ mfspr r22,DSISR andis. r22,r22,0x0020 - bne+ 2f - ld r22,8(r21) /* get SRR1 */ - andi. r22,r22,MSR_PR /* check if from user */ - bne+ stab_bolted_user_return /* from user, send the error on up */ -#if 0 - li r3,0 -#ifdef CONFIG_XMON - bl .xmon -#endif -1: b 1b -#endif -2: + beq- stab_bolted_user_return + /* (((ea >> 28) & 0x1fff) << 15) | (ea >> 60) */ mfspr r21,DAR rldicl r20,r21,36,32 /* Permits a full 32b of ESID */ @@ -1106,9 +1096,11 @@ oris r21,r23,2048 /* valid bit */ rldimi r21,r22,0,52 /* Insert entry */ - isync + /* + * No need for an isync before or after this slbmte. The exception + * we enter with and the rfid we exit with are context synchronizing . + */ slbmte r20,r21 - isync /* All done -- return from exception. */ mfsprg r20,3 /* Load the PACA pointer */ @@ -1861,9 +1853,9 @@ li r5,0 std r0,PACAKSAVE(r13) - /* ptr to hardware interrupt stack for processor 0 */ + /* ptr to hardware interrupt stack for boot processor */ LOADADDR(r3, hardware_int_paca0) - li r5,0x1000 + li r5,PAGE_SIZE sldi r5,r5,3 subi r5,r5,STACK_FRAME_OVERHEAD @@ -1991,7 +1983,7 @@ .globl hardware_int_paca0 hardware_int_paca0: - .space 8*4096 + .space 8*PAGE_SIZE /* 1 page segment table per cpu (max 48, cpu0 allocated at STAB0_PHYS_ADDR) */ .globl stab_array diff -Nru a/arch/ppc64/kernel/iSeries_pci.c b/arch/ppc64/kernel/iSeries_pci.c --- a/arch/ppc64/kernel/iSeries_pci.c Mon Jun 9 23:16:19 2003 +++ b/arch/ppc64/kernel/iSeries_pci.c Mon Jun 9 23:16:19 2003 @@ -304,7 +304,7 @@ ***********************************************************************/ void __init pcibios_final_fixup(void) { - struct pci_dev* PciDev; + struct pci_dev* PciDev = NULL; struct iSeries_Device_Node* DeviceNode; char Buffer[256]; int DeviceCount = 0; @@ -315,7 +315,7 @@ /******************************************************/ mf_displaySrc(0xC9000100); - pci_for_each_dev(PciDev) { + while ((PciDev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, PciDev)) != NULL) { DeviceNode = find_Device_Node(PciDev); if(DeviceNode != NULL) { ++DeviceCount; diff -Nru a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c --- a/arch/ppc64/kernel/iSeries_setup.c Mon Jun 9 23:16:16 2003 +++ b/arch/ppc64/kernel/iSeries_setup.c Mon Jun 9 23:16:16 2003 @@ -864,7 +864,7 @@ { if ( dprof_buffer ) { unsigned i; - for (i=0; i<MAX_PACAS; ++i) { + for (i=0; i<NR_CPUS; ++i) { paca[i].prof_shift = dprof_shift; paca[i].prof_len = dprof_len-1; paca[i].prof_buffer = dprof_buffer; diff -Nru a/arch/ppc64/kernel/ioctl32.c b/arch/ppc64/kernel/ioctl32.c --- a/arch/ppc64/kernel/ioctl32.c Mon Jun 9 23:16:19 2003 +++ b/arch/ppc64/kernel/ioctl32.c Mon Jun 9 23:16:19 2003 @@ -801,7 +801,7 @@ struct socket *mysock = sockfd_lookup(fd, &ret); - if (mysock && mysock->sk && mysock->sk->family == AF_INET6) { /* ipv6 */ + if (mysock && mysock->sk && mysock->sk->sk_family == AF_INET6) { /* ipv6 */ ret = copy_from_user (&r6.rtmsg_dst, &(((struct in6_rtmsg32 *)arg)->rtmsg_dst), 3 * sizeof(struct in6_addr)); ret |= __get_user (r6.rtmsg_type, &(((struct in6_rtmsg32 *)arg)->rtmsg_type)); diff -Nru a/arch/ppc64/kernel/irq.c b/arch/ppc64/kernel/irq.c --- a/arch/ppc64/kernel/irq.c Mon Jun 9 23:16:10 2003 +++ b/arch/ppc64/kernel/irq.c Mon Jun 9 23:16:10 2003 @@ -63,8 +63,11 @@ volatile unsigned char *chrp_int_ack_special; static void register_irq_proc (unsigned int irq); -irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = - { [0 ... NR_IRQS-1] = { 0, NULL, NULL, 0, SPIN_LOCK_UNLOCKED}}; +irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { + [0 ... NR_IRQS-1] = { + .lock = SPIN_LOCK_UNLOCKED + } +}; int ppc_spurious_interrupts = 0; unsigned long lpEvent_count = 0; @@ -381,22 +384,48 @@ return 0; } -static inline void -handle_irq_event(int irq, struct pt_regs *regs, struct irqaction *action) +extern char *ppc_find_proc_name(unsigned *p, char *buf, unsigned buflen); + +static inline void handle_irq_event(int irq, struct pt_regs *regs, + struct irqaction *action) { int status = 0; + int retval = 0; + struct irqaction *first_action = action; if (!(action->flags & SA_INTERRUPT)) local_irq_enable(); do { status |= action->flags; - action->handler(irq, action->dev_id, regs); + retval |= action->handler(irq, action->dev_id, regs); action = action->next; } while (action); if (status & SA_SAMPLE_RANDOM) add_interrupt_randomness(irq); local_irq_disable(); + if (retval != 1) { + static int count = 100; + char name_buf[256]; + if (count) { + count--; + if (retval) { + printk("irq event %d: bogus retval mask %x\n", + irq, retval); + } else { + printk("irq %d: nobody cared!\n", irq); + } + dump_stack(); + printk("handlers:\n"); + action = first_action; + do { + printk("[<%p>]", action->handler); + printk(" (%s)\n", + ppc_find_proc_name((unsigned *)action->handler, name_buf, 256)); + action = action->next; + } while (action); + } + } } /* @@ -676,7 +705,7 @@ #ifdef CONFIG_PPC_ISERIES { unsigned i; - for (i=0; i<MAX_PACAS; ++i) { + for (i=0; i<NR_CPUS; ++i) { if ( paca[i].prof_buffer && (new_value & 1) ) paca[i].prof_enabled = 1; else diff -Nru a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S --- a/arch/ppc64/kernel/misc.S Mon Jun 9 23:16:18 2003 +++ b/arch/ppc64/kernel/misc.S Mon Jun 9 23:16:18 2003 @@ -609,7 +609,7 @@ .llong .sys_ni_syscall /* old profil syscall */ .llong .compat_sys_statfs .llong .compat_sys_fstatfs /* 100 */ - .llong .sys_ioperm + .llong .sys_ni_syscall /* old ioperm syscall */ .llong .compat_sys_socketcall .llong .sys32_syslog .llong .compat_sys_setitimer @@ -852,7 +852,7 @@ .llong .sys_ni_syscall /* old profil syscall holder */ .llong .sys_statfs .llong .sys_fstatfs /* 100 */ - .llong .sys_ioperm + .llong .sys_ni_syscall /* old ioperm syscall */ .llong .sys_socketcall .llong .sys_syslog .llong .sys_setitimer diff -Nru a/arch/ppc64/kernel/pSeries_pci.c b/arch/ppc64/kernel/pSeries_pci.c --- a/arch/ppc64/kernel/pSeries_pci.c Mon Jun 9 23:16:20 2003 +++ b/arch/ppc64/kernel/pSeries_pci.c Mon Jun 9 23:16:20 2003 @@ -533,11 +533,11 @@ void __init pcibios_final_fixup(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; check_s7a(); - pci_for_each_dev(dev) + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) pci_read_irq_line(dev); chrp_request_regions(); diff -Nru a/arch/ppc64/kernel/pacaData.c b/arch/ppc64/kernel/pacaData.c --- a/arch/ppc64/kernel/pacaData.c Mon Jun 9 23:16:16 2003 +++ b/arch/ppc64/kernel/pacaData.c Mon Jun 9 23:16:16 2003 @@ -64,7 +64,7 @@ (&paca[number].exception_stack[0]) - EXC_FRAME_SIZE, \ } -struct paca_struct paca[MAX_PACAS] __page_aligned = { +struct paca_struct paca[NR_CPUS] __page_aligned = { #ifdef CONFIG_PPC_ISERIES PACAINITDATA( 0, 1, &xItLpQueue, 0, STAB0_VIRT_ADDR), #else @@ -101,6 +101,7 @@ PACAINITDATA(29, 0, 0, 0, 0), PACAINITDATA(30, 0, 0, 0, 0), PACAINITDATA(31, 0, 0, 0, 0), +#if NR_CPUS > 32 PACAINITDATA(32, 0, 0, 0, 0), PACAINITDATA(33, 0, 0, 0, 0), PACAINITDATA(34, 0, 0, 0, 0), @@ -116,5 +117,22 @@ PACAINITDATA(44, 0, 0, 0, 0), PACAINITDATA(45, 0, 0, 0, 0), PACAINITDATA(46, 0, 0, 0, 0), - PACAINITDATA(47, 0, 0, 0, 0) + PACAINITDATA(47, 0, 0, 0, 0), + PACAINITDATA(48, 0, 0, 0, 0), + PACAINITDATA(49, 0, 0, 0, 0), + PACAINITDATA(50, 0, 0, 0, 0), + PACAINITDATA(51, 0, 0, 0, 0), + PACAINITDATA(52, 0, 0, 0, 0), + PACAINITDATA(53, 0, 0, 0, 0), + PACAINITDATA(54, 0, 0, 0, 0), + PACAINITDATA(55, 0, 0, 0, 0), + PACAINITDATA(56, 0, 0, 0, 0), + PACAINITDATA(57, 0, 0, 0, 0), + PACAINITDATA(58, 0, 0, 0, 0), + PACAINITDATA(59, 0, 0, 0, 0), + PACAINITDATA(60, 0, 0, 0, 0), + PACAINITDATA(61, 0, 0, 0, 0), + PACAINITDATA(62, 0, 0, 0, 0), + PACAINITDATA(63, 0, 0, 0, 0), +#endif }; diff -Nru a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c --- a/arch/ppc64/kernel/pci.c Mon Jun 9 23:16:17 2003 +++ b/arch/ppc64/kernel/pci.c Mon Jun 9 23:16:17 2003 @@ -117,14 +117,14 @@ */ struct pci_dev *pci_find_dev_by_addr(unsigned long addr) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; int i; unsigned long ioaddr; ioaddr = (addr > isa_io_base) ? addr - isa_io_base : 0; - pci_for_each_dev(dev) { - if ((dev->class >> 8) == PCI_BASE_CLASS_BRIDGE) + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { + if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE) continue; for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { unsigned long start = pci_resource_start(dev,i); diff -Nru a/arch/ppc64/kernel/pci_dma.c b/arch/ppc64/kernel/pci_dma.c --- a/arch/ppc64/kernel/pci_dma.c Mon Jun 9 23:16:14 2003 +++ b/arch/ppc64/kernel/pci_dma.c Mon Jun 9 23:16:14 2003 @@ -710,12 +710,6 @@ for (ln=bus_list->next; ln != bus_list; ln=ln->next) { bus = pci_bus_b(ln); busdn = PCI_GET_DN(bus); - /* NOTE: there should never be a window declared on a bus when - * child devices also have a window. If this should ever be - * architected, we probably want children to have priority. - * In reality, the PHB containing ISA has the property, but otherwise - * it is the pci-bridges that have the property. - */ dma_window = (u32 *)get_property(busdn, "ibm,dma-window", 0); if (dma_window) { /* Bussubno hasn't been copied yet. @@ -724,12 +718,13 @@ busdn->bussubno = bus->number; create_pci_bus_tce_table((unsigned long)busdn); } + /* look for a window on a bridge even if the PHB had one */ create_tce_tables_for_busesLP(&bus->children); } } void create_tce_tables(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; struct device_node *dn, *mydn; if (systemcfg->platform == PLATFORM_PSERIES_LPAR) { @@ -742,7 +737,7 @@ * pci device_node. This means get_tce_table() won't need to search * up the device tree to find it. */ - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { mydn = dn = PCI_GET_DN(dev); while (dn && dn->tce_table == NULL) dn = dn->parent; diff -Nru a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c --- a/arch/ppc64/kernel/process.c Mon Jun 9 23:16:14 2003 +++ b/arch/ppc64/kernel/process.c Mon Jun 9 23:16:14 2003 @@ -67,18 +67,34 @@ #endif /* CONFIG_SMP */ } -int -dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpregs) +#ifdef CONFIG_SMP +static void smp_unlazy_onefpu(void *arg) { - /* - * XXX temporary workaround until threaded coredumps for ppc64 - * are implemented - Anton - */ + struct pt_regs *regs = current->thread.regs; + if (!regs) - return 0; + return; if (regs->msr & MSR_FP) giveup_fpu(current); - memcpy(fpregs, ¤t->thread.fpr[0], sizeof(*fpregs)); +} + +void dump_smp_unlazy_fpu(void) +{ + smp_call_function(smp_unlazy_onefpu, NULL, 1, 1); +} +#endif + +int dump_task_fpu(struct task_struct *tsk, elf_fpregset_t *fpregs) +{ + struct pt_regs *regs = tsk->thread.regs; + + if (!regs) + return 0; + if (tsk == current && (regs->msr & MSR_FP)) + giveup_fpu(current); + + memcpy(fpregs, &tsk->thread.fpr[0], sizeof(*fpregs)); + return 1; } @@ -113,7 +129,7 @@ } static void show_tsk_stack(struct task_struct *p, unsigned long sp); -static char *ppc_find_proc_name(unsigned *p, char *buf, unsigned buflen); +char *ppc_find_proc_name(unsigned *p, char *buf, unsigned buflen); void show_regs(struct pt_regs * regs) { @@ -410,7 +426,7 @@ extern char _stext[], _etext[], __init_begin[], __init_end[]; -static char *ppc_find_proc_name(unsigned *p, char *buf, unsigned buflen) +char *ppc_find_proc_name(unsigned *p, char *buf, unsigned buflen) { unsigned long tb_flags; unsigned short name_len; diff -Nru a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c --- a/arch/ppc64/kernel/prom.c Mon Jun 9 23:16:15 2003 +++ b/arch/ppc64/kernel/prom.c Mon Jun 9 23:16:15 2003 @@ -1134,7 +1134,7 @@ _prom->cpu = (int)(unsigned long)getprop_rval; _xPaca[_prom->cpu].active = 1; #ifdef CONFIG_SMP - RELOC(cpu_online_map) = 1 << _prom->cpu; + RELOC(cpu_online_map) = 1UL << _prom->cpu; #endif RELOC(boot_cpuid) = _prom->cpu; diff -Nru a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c --- a/arch/ppc64/kernel/setup.c Mon Jun 9 23:16:11 2003 +++ b/arch/ppc64/kernel/setup.c Mon Jun 9 23:16:11 2003 @@ -194,7 +194,7 @@ printk("naca->pftSize = 0x%lx\n", naca->pftSize); printk("naca->debug_switch = 0x%lx\n", naca->debug_switch); printk("naca->interrupt_controller = 0x%ld\n", naca->interrupt_controller); - printk("systemcf = 0x%p\n", systemcfg); + printk("systemcfg = 0x%p\n", systemcfg); printk("systemcfg->processorCount = 0x%lx\n", systemcfg->processorCount); printk("systemcfg->physicalMemorySize = 0x%lx\n", systemcfg->physicalMemorySize); printk("systemcfg->dCacheL1LineSize = 0x%x\n", systemcfg->dCacheL1LineSize); @@ -256,7 +256,7 @@ return 0; } - if (!(cpu_online_map & (1<<cpu_id))) + if (!(cpu_online_map & (1UL << cpu_id))) return 0; #ifdef CONFIG_SMP @@ -584,7 +584,7 @@ /* The parameter is the number of processors to share in processing lp events */ unsigned long i; unsigned long val = simple_strtoul( str, NULL, 0 ); - if ( ( val > 0 ) && ( val <= MAX_PACAS ) ) { + if ( ( val > 0 ) && ( val <= NR_CPUS ) ) { for ( i=1; i<val; ++i ) paca[i].lpQueuePtr = paca[0].lpQueuePtr; printk("lpevent processing spread over %ld processors\n", val); diff -Nru a/arch/ppc64/kernel/signal.c b/arch/ppc64/kernel/signal.c --- a/arch/ppc64/kernel/signal.c Mon Jun 9 23:16:05 2003 +++ b/arch/ppc64/kernel/signal.c Mon Jun 9 23:16:05 2003 @@ -69,13 +69,11 @@ }; -extern int do_signal(sigset_t *oldset, struct pt_regs *regs); - /* * Atomically swap in the new signal mask, and wait for a signal. */ -long sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, int p3, int p4, int p6, - int p7, struct pt_regs *regs) +long sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, int p3, int p4, + int p6, int p7, struct pt_regs *regs) { sigset_t saveset, newset; @@ -390,8 +388,6 @@ * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. */ -extern int do_signal32(sigset_t *oldset, struct pt_regs *regs); - int do_signal(sigset_t *oldset, struct pt_regs *regs) { siginfo_t info; diff -Nru a/arch/ppc64/kernel/signal32.c b/arch/ppc64/kernel/signal32.c --- a/arch/ppc64/kernel/signal32.c Mon Jun 9 23:16:18 2003 +++ b/arch/ppc64/kernel/signal32.c Mon Jun 9 23:16:18 2003 @@ -563,10 +563,6 @@ return ret; } - -extern long sys_rt_sigprocmask(int how, sigset_t *set, - sigset_t *oset, size_t sigsetsize); - /* * Note: it is necessary to treat how as an unsigned int, with the * corresponding cast to a signed int to insure that the proper @@ -613,10 +609,6 @@ return 0; } - -extern long sys_rt_sigpending(sigset_t *set, size_t sigsetsize); - - long sys32_rt_sigpending(compat_sigset_t *set, compat_size_t sigsetsize) { sigset_t s; @@ -683,11 +675,6 @@ return err; } - -extern long sys_rt_sigtimedwait(const sigset_t *uthese, - siginfo_t *uinfo, const struct timespec *uts, - size_t sigsetsize); - long sys32_rt_sigtimedwait(compat_sigset_t *uthese, siginfo_t32 *uinfo, struct compat_timespec *uts, compat_size_t sigsetsize) { @@ -758,9 +745,6 @@ return d; } - -extern long sys_rt_sigqueueinfo(int pid, int sig, siginfo_t *uinfo); - /* * Note: it is necessary to treat pid and sig as unsigned ints, with the * corresponding cast to a signed int to insure that the proper conversion @@ -785,8 +769,6 @@ set_fs (old_fs); return ret; } - -extern int do_signal(sigset_t *oldset, struct pt_regs *regs); int sys32_rt_sigsuspend(compat_sigset_t* unewset, size_t sigsetsize, int p3, int p4, int p6, int p7, struct pt_regs *regs) diff -Nru a/arch/ppc64/kernel/smp.c b/arch/ppc64/kernel/smp.c --- a/arch/ppc64/kernel/smp.c Mon Jun 9 23:16:16 2003 +++ b/arch/ppc64/kernel/smp.c Mon Jun 9 23:16:16 2003 @@ -113,7 +113,7 @@ struct ItLpPaca * lpPaca; np = 0; - for (i=0; i < MAX_PACAS; ++i) { + for (i=0; i < NR_CPUS; ++i) { lpPaca = paca[i].xLpPacaPtr; if ( lpPaca->xDynProcStatus < 2 ) { ++np; @@ -128,7 +128,7 @@ unsigned np = 0; struct ItLpPaca *lpPaca; - for (i=0; i < MAX_PACAS; ++i) { + for (i=0; i < NR_CPUS; ++i) { lpPaca = paca[i].xLpPacaPtr; if (lpPaca->xDynProcStatus < 2) { paca[i].active = 1; @@ -144,7 +144,7 @@ struct ItLpPaca * lpPaca; /* Verify we have a Paca for processor nr */ if ( ( nr <= 0 ) || - ( nr >= MAX_PACAS ) ) + ( nr >= NR_CPUS ) ) return; /* Verify that our partition has a processor nr */ lpPaca = paca[nr].xLpPacaPtr; @@ -228,7 +228,7 @@ { /* Verify we have a Paca for processor nr */ if ( ( nr <= 0 ) || - ( nr >= MAX_PACAS ) ) + ( nr >= NR_CPUS ) ) return; /* The information for processor bringup must @@ -390,17 +390,6 @@ void smp_send_reschedule(int cpu) { smp_message_pass(cpu, PPC_MSG_RESCHEDULE, 0, 0); -} - -/* - * this function sends a reschedule IPI to all (other) CPUs. - * This should only be used if some 'global' task became runnable, - * such as a RT task, that must be handled now. The first CPU - * that manages to grab the task will run it. - */ -void smp_send_reschedule_all(void) -{ - smp_message_pass(MSG_ALL_BUT_SELF, PPC_MSG_RESCHEDULE, 0, 0); } #ifdef CONFIG_XMON diff -Nru a/arch/ppc64/kernel/stab.c b/arch/ppc64/kernel/stab.c --- a/arch/ppc64/kernel/stab.c Mon Jun 9 23:16:16 2003 +++ b/arch/ppc64/kernel/stab.c Mon Jun 9 23:16:16 2003 @@ -23,7 +23,8 @@ #include <asm/pmc.h> int make_ste(unsigned long stab, unsigned long esid, unsigned long vsid); -void make_slbe(unsigned long esid, unsigned long vsid, int large); +void make_slbe(unsigned long esid, unsigned long vsid, int large, + int kernel_segment); /* * Build an entry for the base kernel segment and put it into @@ -45,7 +46,8 @@ asm volatile("isync":::"memory"); asm volatile("slbmte %0,%0"::"r" (0) : "memory"); asm volatile("isync; slbia; isync":::"memory"); - make_slbe(esid, vsid, 0); + make_slbe(esid, vsid, 0, 1); + asm volatile("isync":::"memory"); #endif } else { asm volatile("isync; slbia; isync":::"memory"); @@ -139,10 +141,13 @@ /* * Create a segment buffer entry for the given esid/vsid pair. + * + * NOTE: A context syncronising instruction is required before and after + * this, in the common case we use exception entry and rfid. */ -void make_slbe(unsigned long esid, unsigned long vsid, int large) +void make_slbe(unsigned long esid, unsigned long vsid, int large, + int kernel_segment) { - int kernel_segment = 0; unsigned long entry, castout_entry; union { unsigned long word0; @@ -153,42 +158,15 @@ slb_dword1 data; } vsid_data; - if (REGION_ID(esid << SID_SHIFT) >= KERNEL_REGION_ID) - kernel_segment = 1; - /* - * Find an empty entry, if one exists. + * Find an empty entry, if one exists. Must start at 0 because + * we use this code to load SLB entry 0 at boot. */ for (entry = 0; entry < naca->slb_size; entry++) { asm volatile("slbmfee %0,%1" : "=r" (esid_data) : "r" (entry)); - if (!esid_data.data.v) { - /* - * Write the new SLB entry. - */ - vsid_data.word0 = 0; - vsid_data.data.vsid = vsid; - vsid_data.data.kp = 1; - if (large) - vsid_data.data.l = 1; - if (kernel_segment) - vsid_data.data.c = 1; - - esid_data.word0 = 0; - esid_data.data.esid = esid; - esid_data.data.v = 1; - esid_data.data.index = entry; - - /* slbie not needed as no previous mapping existed. */ - /* Order update */ - asm volatile("isync" : : : "memory"); - asm volatile("slbmte %0,%1" - : : "r" (vsid_data), - "r" (esid_data)); - /* Order update */ - asm volatile("isync" : : : "memory"); - return; - } + if (!esid_data.data.v) + goto write_entry; } /* @@ -211,13 +189,13 @@ if (castout_entry >= naca->slb_size) castout_entry = 1; asm volatile("slbmfee %0,%1" : "=r" (esid_data) : "r" (entry)); - } while (esid_data.data.esid == GET_ESID((unsigned long)_get_SP()) && - esid_data.data.v); + } while (esid_data.data.esid == GET_ESID((unsigned long)_get_SP())); get_paca()->xStab_data.next_round_robin = castout_entry; /* slbie not needed as the previous mapping is still valid. */ - + +write_entry: /* * Write the new SLB entry. */ @@ -234,10 +212,11 @@ esid_data.data.v = 1; esid_data.data.index = entry; - asm volatile("isync" : : : "memory"); /* Order update */ - asm volatile("slbmte %0,%1" - : : "r" (vsid_data), "r" (esid_data)); - asm volatile("isync" : : : "memory" ); /* Order update */ + /* + * No need for an isync before or after this slbmte. The exception + * we enter with and the rfid we exit with are context synchronizing. + */ + asm volatile("slbmte %0,%1" : : "r" (vsid_data), "r" (esid_data)); } static inline void __ste_allocate(unsigned long esid, unsigned long vsid, @@ -246,10 +225,10 @@ if (cpu_has_slb()) { #ifndef CONFIG_PPC_ISERIES if (REGION_ID(esid << SID_SHIFT) == KERNEL_REGION_ID) - make_slbe(esid, vsid, 1); + make_slbe(esid, vsid, 1, kernel_segment); else #endif - make_slbe(esid, vsid, 0); + make_slbe(esid, vsid, 0, kernel_segment); } else { unsigned char top_entry, stab_entry, *segments; diff -Nru a/arch/ppc64/kernel/sys32.S b/arch/ppc64/kernel/sys32.S --- a/arch/ppc64/kernel/sys32.S Mon Jun 9 23:16:17 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,27 +0,0 @@ -/* - * sys32.S: I-cache tricks for 32-bit compatibility layer simple - * conversions. - * - * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) - * Copyright (C) 1998 Jakub Jelinek (jj@ultra.linux.cz) - * Copyright (C) 2000 Ken Aaker (kdaaker@rchland.vnet.ibm.com) - * For PPC ABI convention is parms in Regs 3-10. - * The router in entry.S clears the high 32 bits in the first - * 4 arguments (R3-R6). - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the 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/ppc_asm.h> -#include <asm/errno.h> -#include <asm/processor.h> - - .text - -_GLOBAL(ppc32_lseek) - extsw r4,r4 /* sign extend off_t offset parm */ - b .sys_lseek - diff -Nru a/arch/ppc64/kernel/sys_ppc32.c b/arch/ppc64/kernel/sys_ppc32.c --- a/arch/ppc64/kernel/sys_ppc32.c Mon Jun 9 23:16:15 2003 +++ b/arch/ppc64/kernel/sys_ppc32.c Mon Jun 9 23:16:15 2003 @@ -2318,6 +2318,14 @@ return sys_nice((int)increment); } +extern off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin); + +off_t ppc32_lseek(unsigned int fd, u32 offset, unsigned int origin) +{ + /* sign extend n */ + return sys_lseek(fd, (int)offset, origin); +} + /* * This is just a version for 32-bit applications which does * not force O_LARGEFILE on. diff -Nru a/arch/ppc64/kernel/syscalls.c b/arch/ppc64/kernel/syscalls.c --- a/arch/ppc64/kernel/syscalls.c Mon Jun 9 23:16:15 2003 +++ b/arch/ppc64/kernel/syscalls.c Mon Jun 9 23:16:15 2003 @@ -50,11 +50,6 @@ { } -int sys_ioperm(unsigned long from, unsigned long num, int on) -{ - return -EIO; -} - /* * sys_ipc() is the de-multiplexer for the SysV IPC calls.. * diff -Nru a/arch/ppc64/kernel/traps.c b/arch/ppc64/kernel/traps.c --- a/arch/ppc64/kernel/traps.c Mon Jun 9 23:16:12 2003 +++ b/arch/ppc64/kernel/traps.c Mon Jun 9 23:16:12 2003 @@ -349,9 +349,8 @@ void KernelFPUnavailableException(struct pt_regs *regs) { - printk("Illegal floating point used in kernel " - "(task=0x%p, pc=0x%016lx, trap=0x%08lx)\n", - current, regs->nip, regs->trap); + printk("Illegal floating point used in kernel (task=0x%p, " + "pc=0x%016lx, trap=0x%lx)\n", current, regs->nip, regs->trap); panic("Unrecoverable FP Unavailable Exception in Kernel"); } diff -Nru a/arch/ppc64/lib/Makefile b/arch/ppc64/lib/Makefile --- a/arch/ppc64/lib/Makefile Mon Jun 9 23:16:05 2003 +++ b/arch/ppc64/lib/Makefile Mon Jun 9 23:16:05 2003 @@ -2,7 +2,5 @@ # Makefile for ppc64-specific library files.. # -L_TARGET = lib.a - -obj-y := checksum.o dec_and_lock.o string.o strcase.o -obj-y += copypage.o memcpy.o copyuser.o +lib-y := checksum.o dec_and_lock.o string.o strcase.o +lib-y += copypage.o memcpy.o copyuser.o diff -Nru a/arch/ppc64/lib/copyuser.S b/arch/ppc64/lib/copyuser.S --- a/arch/ppc64/lib/copyuser.S Mon Jun 9 23:16:19 2003 +++ b/arch/ppc64/lib/copyuser.S Mon Jun 9 23:16:19 2003 @@ -483,8 +483,20 @@ * on an exception, reset to the beginning and jump back into the * standard __copy_tofrom_user */ -100: ld r3,-24(r1) - ld r4,-24(r1) +100: ld r20,-120(1) + ld r21,-112(1) + ld r22,-104(1) + ld r23,-96(1) + ld r24,-88(1) + ld r25,-80(1) + ld r26,-72(1) + ld r27,-64(1) + ld r28,-56(1) + ld r29,-48(1) + ld r30,-40(1) + ld r31,-32(1) + ld r3,-24(r1) + ld r4,-16(r1) li r5,4096 b .Ldst_aligned diff -Nru a/arch/ppc64/mm/init.c b/arch/ppc64/mm/init.c --- a/arch/ppc64/mm/init.c Mon Jun 9 23:16:14 2003 +++ b/arch/ppc64/mm/init.c Mon Jun 9 23:16:14 2003 @@ -36,6 +36,7 @@ #include <linux/delay.h> #include <linux/bootmem.h> #include <linux/highmem.h> +#include <linux/proc_fs.h> #ifdef CONFIG_BLK_DEV_INITRD #include <linux/blk.h> /* for initrd_* */ #endif @@ -509,6 +510,34 @@ } #endif +static struct kcore_list kcore_vmem; + +static void setup_kcore(void) +{ + int i; + + for (i=0; i < lmb.memory.cnt; i++) { + unsigned long physbase, size; + unsigned long type = lmb.memory.region[i].type; + struct kcore_list *kcore_mem; + + if (type != LMB_MEMORY_AREA) + continue; + + physbase = lmb.memory.region[i].physbase; + size = lmb.memory.region[i].size; + + /* GFP_ATOMIC to avoid might_sleep warnings during boot */ + kcore_mem = kmalloc(sizeof(struct kcore_list), GFP_ATOMIC); + if (!kcore_mem) + panic("mem_init: kmalloc failed\n"); + + kclist_add(kcore_mem, __va(physbase), size); + } + + kclist_add(&kcore_vmem, (void *)VMALLOC_START, VMALLOC_END-VMALLOC_START); +} + void initialize_paca_hardware_interrupt_stack(void); void __init mem_init(void) @@ -576,6 +605,8 @@ PAGE_OFFSET, (unsigned long)__va(lmb_end_of_DRAM())); #endif mem_init_done = 1; + + setup_kcore(); /* set the last page of each hardware interrupt stack to be protected */ initialize_paca_hardware_interrupt_stack(); diff -Nru a/arch/ppc64/mm/numa.c b/arch/ppc64/mm/numa.c --- a/arch/ppc64/mm/numa.c Mon Jun 9 23:16:15 2003 +++ b/arch/ppc64/mm/numa.c Mon Jun 9 23:16:15 2003 @@ -25,6 +25,7 @@ int numa_memory_lookup_table[MAX_MEMORY >> MEMORY_INCREMENT_SHIFT] = { [ 0 ... ((MAX_MEMORY >> MEMORY_INCREMENT_SHIFT) - 1)] = -1}; unsigned long numa_cpumask_lookup_table[MAX_NUMNODES]; +int nr_cpus_in_node[MAX_NUMNODES] = { [0 ... (MAX_NUMNODES -1)] = 0}; struct pglist_data node_data[MAX_NUMNODES]; bootmem_data_t plat_node_bdata[MAX_NUMNODES]; @@ -33,7 +34,10 @@ { dbg("cpu %d maps to domain %d\n", cpu, node); numa_cpu_lookup_table[cpu] = node; - numa_cpumask_lookup_table[node] |= 1UL << cpu; + if (!(numa_cpumask_lookup_table[node] & 1UL << cpu)) { + numa_cpumask_lookup_table[node] |= 1UL << cpu; + nr_cpus_in_node[node]++; + } } static int __init parse_numa_properties(void) diff -Nru a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile --- a/arch/s390/lib/Makefile Mon Jun 9 23:16:07 2003 +++ b/arch/s390/lib/Makefile Mon Jun 9 23:16:07 2003 @@ -2,10 +2,8 @@ # Makefile for s390-specific library files.. # -L_TARGET = lib.a - EXTRA_AFLAGS := -traditional -obj-y += delay.o -obj-$(CONFIG_ARCH_S390_31) += memset.o strcmp.o strncpy.o uaccess.o -obj-$(CONFIG_ARCH_S390X) += memset64.o strcmp64.o strncpy64.o uaccess64.o +lib-y += delay.o +lib-$(CONFIG_ARCH_S390_31) += memset.o strcmp.o strncpy.o uaccess.o +lib-$(CONFIG_ARCH_S390X) += memset64.o strcmp64.o strncpy64.o uaccess64.o diff -Nru a/arch/sh/kernel/irq.c b/arch/sh/kernel/irq.c --- a/arch/sh/kernel/irq.c Mon Jun 9 23:16:10 2003 +++ b/arch/sh/kernel/irq.c Mon Jun 9 23:16:10 2003 @@ -41,8 +41,11 @@ /* * Controller mappings for all interrupt sources: */ -irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = - { [0 ... NR_IRQS-1] = { 0, &no_irq_type, }}; +irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { + [0 ... NR_IRQS-1] = { + .handler = &no_irq_type, + } +}; /* * Special irq handlers. diff -Nru a/arch/sh/kernel/pci-sh7751.c b/arch/sh/kernel/pci-sh7751.c --- a/arch/sh/kernel/pci-sh7751.c Mon Jun 9 23:16:15 2003 +++ b/arch/sh/kernel/pci-sh7751.c Mon Jun 9 23:16:15 2003 @@ -386,13 +386,13 @@ static void __init pcibios_allocate_resources(int pass) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; int idx, disabled; u16 command; struct resource *r, *pr; PCIDBG(2,"PCI: pcibios_allocate_resources pass %d called\n", pass); - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { pci_read_config_word(dev, PCI_COMMAND, &command); for(idx = 0; idx < 6; idx++) { r = &dev->resource[idx]; @@ -432,12 +432,12 @@ static void __init pcibios_assign_resources(void) { - struct pci_dev *dev; + struct pci_dev *devn = NULL; int idx; struct resource *r; PCIDBG(2,"PCI: pcibios_assign_resources called\n"); - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { int class = dev->class >> 8; /* Don't touch classless devices and host bridges */ diff -Nru a/arch/sh/lib/Makefile b/arch/sh/lib/Makefile --- a/arch/sh/lib/Makefile Mon Jun 9 23:16:12 2003 +++ b/arch/sh/lib/Makefile Mon Jun 9 23:16:12 2003 @@ -2,6 +2,5 @@ # Makefile for SuperH-specific library files.. # -L_TARGET = lib.a -obj-y = delay.o memcpy.o memset.o memmove.o memchr.o \ +lib-y = delay.o memcpy.o memset.o memmove.o memchr.o \ checksum.o strcasecmp.o strlen.o diff -Nru a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile --- a/arch/sparc/lib/Makefile Mon Jun 9 23:16:19 2003 +++ b/arch/sparc/lib/Makefile Mon Jun 9 23:16:19 2003 @@ -2,11 +2,9 @@ # Makefile for Sparc library files.. # -L_TARGET = lib.a - EXTRA_AFLAGS := -ansi -DST_DIV0=0x02 -obj-y := mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o memcpy.o memset.o \ +lib-y := mul.o rem.o sdiv.o udiv.o umul.o urem.o ashrdi3.o memcpy.o memset.o \ strlen.o checksum.o blockops.o memscan.o memcmp.o strncmp.o \ strncpy_from_user.o divdi3.o udivdi3.o strlen_user.o \ copy_user.o locks.o atomic.o bitops.o debuglocks.o lshrdi3.o \ diff -Nru a/arch/sparc/prom/Makefile b/arch/sparc/prom/Makefile --- a/arch/sparc/prom/Makefile Mon Jun 9 23:16:10 2003 +++ b/arch/sparc/prom/Makefile Mon Jun 9 23:16:10 2003 @@ -3,9 +3,7 @@ # Linux. # -L_TARGET = lib.a - -obj-y := bootstr.o devmap.o devops.o init.o memory.o misc.o mp.o \ +lib-y := bootstr.o devmap.o devops.o init.o memory.o misc.o mp.o \ palloc.o ranges.o segment.o console.o printf.o tree.o -obj-$(CONFIG_SUN4) += sun4prom.o +lib-$(CONFIG_SUN4) += sun4prom.o diff -Nru a/arch/sparc/prom/console.c b/arch/sparc/prom/console.c --- a/arch/sparc/prom/console.c Mon Jun 9 23:16:10 2003 +++ b/arch/sparc/prom/console.c Mon Jun 9 23:16:10 2003 @@ -105,7 +105,7 @@ /* Query for input device type */ enum prom_input_device -prom_query_input_device() +prom_query_input_device(void) { unsigned long flags; int st_p; @@ -155,7 +155,7 @@ /* Query for output device type */ enum prom_output_device -prom_query_output_device() +prom_query_output_device(void) { unsigned long flags; int st_p; diff -Nru a/arch/sparc64/boot/Makefile b/arch/sparc64/boot/Makefile --- a/arch/sparc64/boot/Makefile Mon Jun 9 23:16:05 2003 +++ b/arch/sparc64/boot/Makefile Mon Jun 9 23:16:05 2003 @@ -15,7 +15,7 @@ quiet_cmd_piggy = PIGGY $@ cmd_piggy = $(obj)/piggyback $@ System.map $(ROOT_IMG) quiet_cmd_strip = STRIP $@ - cmd_strip = $(STRIP) -R .comment -R .note vmlinux -o $@ + cmd_strip = $(STRIP) -R .comment -R .note -K sun4u_init -K _end -K _start vmlinux -o $@ # Actual linking diff -Nru a/arch/sparc64/defconfig b/arch/sparc64/defconfig --- a/arch/sparc64/defconfig Mon Jun 9 23:16:09 2003 +++ b/arch/sparc64/defconfig Mon Jun 9 23:16:09 2003 @@ -16,6 +16,9 @@ # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y CONFIG_LOG_BUF_SHIFT=15 +# CONFIG_EMBEDDED is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y # # Loadable module support @@ -795,6 +798,7 @@ # CONFIG_WINBOND_FIR is not set # CONFIG_TOSHIBA_OLD is not set # CONFIG_TOSHIBA_FIR is not set +# CONFIG_SMC_IRCC_OLD is not set # CONFIG_SMC_IRCC_FIR is not set # CONFIG_ALI_FIR is not set # CONFIG_VLSI_FIR is not set @@ -959,6 +963,8 @@ CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set CONFIG_DEVPTS_FS=y +CONFIG_DEVPTS_FS_XATTR=y +# CONFIG_DEVPTS_FS_SECURITY is not set # CONFIG_TMPFS is not set CONFIG_RAMFS=y @@ -1111,6 +1117,7 @@ CONFIG_SND_INTEL8X0=m CONFIG_SND_SONICVIBES=m # CONFIG_SND_VIA82XX is not set +CONFIG_SND_VX222=m # # ALSA USB devices diff -Nru a/arch/sparc64/kernel/Makefile b/arch/sparc64/kernel/Makefile --- a/arch/sparc64/kernel/Makefile Mon Jun 9 23:16:08 2003 +++ b/arch/sparc64/kernel/Makefile Mon Jun 9 23:16:08 2003 @@ -39,3 +39,5 @@ head.o: head.S ttable.S itlb_base.S dtlb_base.S dtlb_backend.S dtlb_prot.S \ etrap.S rtrap.S winfixup.S entry.S + +CFLAGS_ioctl32.o += -Ifs/ diff -Nru a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c --- a/arch/sparc64/kernel/ioctl32.c Mon Jun 9 23:16:18 2003 +++ b/arch/sparc64/kernel/ioctl32.c Mon Jun 9 23:16:18 2003 @@ -3,857 +3,42 @@ * * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com) * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 2003 Pavel Machek (pavel@suse.cz) * * These routines maintain argument size conversion between 32bit and 64bit * ioctls. */ -#include <linux/config.h> -#include <linux/types.h> -#include <linux/compat.h> -#include <linux/ioctl32.h> -#include <linux/kernel.h> -#include <linux/sched.h> -#include <linux/smp.h> -#include <linux/smp_lock.h> -#include <linux/ioctl.h> -#include <linux/if.h> -#include <linux/slab.h> -#include <linux/hdreg.h> -#include <linux/raid/md.h> -#include <linux/kd.h> -#include <linux/route.h> -#include <linux/in6.h> -#include <linux/ipv6_route.h> -#include <linux/skbuff.h> -#include <linux/netlink.h> -#include <linux/vt.h> -#include <linux/fs.h> -#include <linux/file.h> -#include <linux/fd.h> -#include <linux/ppp_defs.h> -#include <linux/if_ppp.h> -#include <linux/if_pppox.h> -#include <linux/if_tun.h> -#include <linux/mtio.h> -#include <linux/cdrom.h> -#include <linux/loop.h> -#include <linux/auto_fs.h> -#include <linux/auto_fs4.h> -#include <linux/devfs_fs.h> -#include <linux/tty.h> -#include <linux/vt_kern.h> -#include <linux/fb.h> -#include <linux/ext2_fs.h> -#include <linux/videodev.h> -#include <linux/netdevice.h> -#include <linux/raw.h> -#include <linux/smb_fs.h> +#define INCLUDES +#include "compat_ioctl.c" #include <linux/ncp_fs.h> -#include <linux/blkpg.h> -#include <linux/blk.h> -#include <linux/elevator.h> -#include <linux/rtc.h> -#include <linux/pci.h> -#include <linux/dm-ioctl.h> -#include <net/sock.h> /* siocdevprivate_ioctl */ - -#include <scsi/scsi.h> -/* Ugly hack. */ -#undef __KERNEL__ -#include <scsi/scsi_ioctl.h> -#define __KERNEL__ -#include <scsi/sg.h> - -#include <asm/types.h> -#include <asm/uaccess.h> #include <asm/fbio.h> #include <asm/kbio.h> #include <asm/vuid_event.h> -#include <asm/openpromio.h> #include <asm/envctrl.h> -#include <asm/audioio.h> -#include <linux/ethtool.h> -#include <linux/mii.h> -#include <linux/if_bonding.h> #include <asm/display7seg.h> +#include <asm/openpromio.h> +#include <asm/audioio.h> #include <asm/watchdog.h> -#include <asm/module.h> -#include <linux/soundcard.h> -#include <linux/lp.h> - -#include <linux/atm.h> -#include <linux/atmarp.h> -#include <linux/atmclip.h> -#include <linux/atmdev.h> -#include <linux/atmioc.h> -#include <linux/atmlec.h> -#include <linux/atmmpc.h> -#include <linux/atmsvc.h> -#include <linux/atm_tcp.h> -#include <linux/sonet.h> -#include <linux/atm_suni.h> -#include <linux/mtd/mtd.h> - -#include <net/bluetooth/bluetooth.h> -#include <net/bluetooth/hci.h> -#include <net/bluetooth/rfcomm.h> - -#include <linux/usb.h> -#include <linux/usbdevice_fs.h> -#include <linux/nbd.h> -#include <linux/random.h> -#include <linux/filter.h> /* Use this to get at 32-bit user passed pointers. * See sys_sparc32.c for description about it. */ #define A(__x) ((void __user *)(unsigned long)(__x)) -/* Aiee. Someone does not find a difference between int and long */ -#define EXT2_IOC32_GETFLAGS _IOR('f', 1, int) -#define EXT2_IOC32_SETFLAGS _IOW('f', 2, int) -#define EXT2_IOC32_GETVERSION _IOR('v', 1, int) -#define EXT2_IOC32_SETVERSION _IOW('v', 2, int) - - -static int w_long(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - int err; - unsigned long val; - - set_fs (KERNEL_DS); - err = sys_ioctl(fd, cmd, (unsigned long)&val); - set_fs (old_fs); - if (!err && put_user(val, (u32 *)arg)) - return -EFAULT; - return err; -} - -static int rw_long(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - int err; - unsigned long val; - - if(get_user(val, (u32 *)arg)) - return -EFAULT; - set_fs (KERNEL_DS); - err = sys_ioctl(fd, cmd, (unsigned long)&val); - set_fs (old_fs); - if (!err && put_user(val, (u32 *)arg)) - return -EFAULT; - return err; -} - -static int do_ext2_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - /* These are just misnamed, they actually get/put from/to user an int */ - switch (cmd) { - case EXT2_IOC32_GETFLAGS: cmd = EXT2_IOC_GETFLAGS; break; - case EXT2_IOC32_SETFLAGS: cmd = EXT2_IOC_SETFLAGS; break; - case EXT2_IOC32_GETVERSION: cmd = EXT2_IOC_GETVERSION; break; - case EXT2_IOC32_SETVERSION: cmd = EXT2_IOC_SETVERSION; break; - } - return sys_ioctl(fd, cmd, arg); -} - -struct video_tuner32 { - s32 tuner; - u8 name[32]; - u32 rangelow, rangehigh; - u32 flags; - u16 mode, signal; -}; - -static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 *up) -{ - int i; - - if(get_user(kp->tuner, &up->tuner)) - return -EFAULT; - for(i = 0; i < 32; i++) - __get_user(kp->name[i], &up->name[i]); - __get_user(kp->rangelow, &up->rangelow); - __get_user(kp->rangehigh, &up->rangehigh); - __get_user(kp->flags, &up->flags); - __get_user(kp->mode, &up->mode); - __get_user(kp->signal, &up->signal); - return 0; -} - -static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 *up) -{ - int i; - - if(put_user(kp->tuner, &up->tuner)) - return -EFAULT; - for(i = 0; i < 32; i++) - __put_user(kp->name[i], &up->name[i]); - __put_user(kp->rangelow, &up->rangelow); - __put_user(kp->rangehigh, &up->rangehigh); - __put_user(kp->flags, &up->flags); - __put_user(kp->mode, &up->mode); - __put_user(kp->signal, &up->signal); - return 0; -} - -struct video_buffer32 { - /* void * */ u32 base; - s32 height, width, depth, bytesperline; -}; - -static int get_video_buffer32(struct video_buffer *kp, struct video_buffer32 *up) -{ - u32 tmp; - - if(get_user(tmp, &up->base)) - return -EFAULT; - kp->base = (void *) ((unsigned long)tmp); - __get_user(kp->height, &up->height); - __get_user(kp->width, &up->width); - __get_user(kp->depth, &up->depth); - __get_user(kp->bytesperline, &up->bytesperline); - return 0; -} - -static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 *up) -{ - u32 tmp = (u32)((unsigned long)kp->base); - - if(put_user(tmp, &up->base)) - return -EFAULT; - __put_user(kp->height, &up->height); - __put_user(kp->width, &up->width); - __put_user(kp->depth, &up->depth); - __put_user(kp->bytesperline, &up->bytesperline); - return 0; -} - -struct video_clip32 { - s32 x, y, width, height; - /* struct video_clip32 * */ u32 next; -}; - -struct video_window32 { - u32 x, y, width, height, chromakey, flags; - /* struct video_clip32 * */ u32 clips; - s32 clipcount; -}; - -static void free_kvideo_clips(struct video_window *kp) -{ - struct video_clip *cp; - - cp = kp->clips; - if(cp != NULL) - kfree(cp); -} - -static int get_video_window32(struct video_window *kp, struct video_window32 *up) -{ - struct video_clip32 __user *ucp; - struct video_clip *kcp; - int nclips, err, i; - u32 tmp; - - if(get_user(kp->x, &up->x)) - return -EFAULT; - __get_user(kp->y, &up->y); - __get_user(kp->width, &up->width); - __get_user(kp->height, &up->height); - __get_user(kp->chromakey, &up->chromakey); - __get_user(kp->flags, &up->flags); - __get_user(kp->clipcount, &up->clipcount); - __get_user(tmp, &up->clips); - ucp = A(tmp); - kp->clips = NULL; - - nclips = kp->clipcount; - if(nclips == 0) - return 0; - - if(ucp == 0) - return -EINVAL; - - /* Peculiar interface... */ - if(nclips < 0) - nclips = VIDEO_CLIPMAP_SIZE; - - kcp = kmalloc(nclips * sizeof(struct video_clip), GFP_KERNEL); - err = -ENOMEM; - if(kcp == NULL) - goto cleanup_and_err; - - kp->clips = kcp; - for(i = 0; i < nclips; i++) { - __get_user(kcp[i].x, &ucp[i].x); - __get_user(kcp[i].y, &ucp[i].y); - __get_user(kcp[i].width, &ucp[i].width); - __get_user(kcp[i].height, &ucp[i].height); - kcp[nclips].next = NULL; - } - - return 0; - -cleanup_and_err: - free_kvideo_clips(kp); - return err; -} - -/* You get back everything except the clips... */ -static int put_video_window32(struct video_window *kp, struct video_window32 *up) -{ - if(put_user(kp->x, &up->x)) - return -EFAULT; - __put_user(kp->y, &up->y); - __put_user(kp->width, &up->width); - __put_user(kp->height, &up->height); - __put_user(kp->chromakey, &up->chromakey); - __put_user(kp->flags, &up->flags); - __put_user(kp->clipcount, &up->clipcount); - return 0; -} - -#define VIDIOCGTUNER32 _IOWR('v',4, struct video_tuner32) -#define VIDIOCSTUNER32 _IOW('v',5, struct video_tuner32) -#define VIDIOCGWIN32 _IOR('v',9, struct video_window32) -#define VIDIOCSWIN32 _IOW('v',10, struct video_window32) -#define VIDIOCGFBUF32 _IOR('v',11, struct video_buffer32) -#define VIDIOCSFBUF32 _IOW('v',12, struct video_buffer32) -#define VIDIOCGFREQ32 _IOR('v',14, u32) -#define VIDIOCSFREQ32 _IOW('v',15, u32) - -static int do_video_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - union { - struct video_tuner vt; - struct video_buffer vb; - struct video_window vw; - unsigned long vx; - } karg; - mm_segment_t old_fs = get_fs(); - void *up = (void *)arg; - int err = 0; - - /* First, convert the command. */ - switch(cmd) { - case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break; - case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break; - case VIDIOCGWIN32: cmd = VIDIOCGWIN; break; - case VIDIOCSWIN32: cmd = VIDIOCSWIN; break; - case VIDIOCGFBUF32: cmd = VIDIOCGFBUF; break; - case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break; - case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break; - case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break; - }; - - switch(cmd) { - case VIDIOCSTUNER: - case VIDIOCGTUNER: - err = get_video_tuner32(&karg.vt, up); - break; - - case VIDIOCSWIN: - err = get_video_window32(&karg.vw, up); - break; - - case VIDIOCSFBUF: - err = get_video_buffer32(&karg.vb, up); - break; - - case VIDIOCSFREQ: - err = get_user(karg.vx, (u32 *)up); - break; - }; - if(err) - goto out; - - set_fs(KERNEL_DS); - err = sys_ioctl(fd, cmd, (unsigned long)&karg); - set_fs(old_fs); - - if(cmd == VIDIOCSWIN) - free_kvideo_clips(&karg.vw); - - if(err == 0) { - switch(cmd) { - case VIDIOCGTUNER: - err = put_video_tuner32(&karg.vt, up); - break; - - case VIDIOCGWIN: - err = put_video_window32(&karg.vw, up); - break; - - case VIDIOCGFBUF: - err = put_video_buffer32(&karg.vb, up); - break; - - case VIDIOCGFREQ: - err = put_user(((u32)karg.vx), (u32 *)up); - break; - }; - } -out: - return err; -} - -static int do_siocgstamp(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct compat_timeval *up = (struct compat_timeval *)arg; - struct timeval ktv; - mm_segment_t old_fs = get_fs(); - int err; - - set_fs(KERNEL_DS); - err = sys_ioctl(fd, cmd, (unsigned long)&ktv); - set_fs(old_fs); - if(!err) { - err = put_user(ktv.tv_sec, &up->tv_sec); - err |= __put_user(ktv.tv_usec, &up->tv_usec); - } - return err; -} - -struct ifmap32 { - u32 mem_start; - u32 mem_end; - unsigned short base_addr; - unsigned char irq; - unsigned char dma; - unsigned char port; -}; - -struct ifreq32 { -#define IFHWADDRLEN 6 -#define IFNAMSIZ 16 - union { - char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ - } ifr_ifrn; - union { - struct sockaddr ifru_addr; - struct sockaddr ifru_dstaddr; - struct sockaddr ifru_broadaddr; - struct sockaddr ifru_netmask; - struct sockaddr ifru_hwaddr; - short ifru_flags; - int ifru_ivalue; - int ifru_mtu; - struct ifmap32 ifru_map; - char ifru_slave[IFNAMSIZ]; /* Just fits the size */ - char ifru_newname[IFNAMSIZ]; - compat_caddr_t ifru_data; - } ifr_ifru; -}; - -struct ifconf32 { - int ifc_len; /* size of buffer */ - compat_caddr_t ifcbuf; -}; - -#ifdef CONFIG_NET -static int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct net_device *dev; - struct ifreq32 ifr32; - int err; - - if (copy_from_user(&ifr32, (struct ifreq32 *)arg, sizeof(struct ifreq32))) - return -EFAULT; - - dev = dev_get_by_index(ifr32.ifr_ifindex); - if (!dev) - return -ENODEV; - - strcpy(ifr32.ifr_name, dev->name); - dev_put(dev); - - err = copy_to_user((struct ifreq32 *)arg, &ifr32, sizeof(struct ifreq32)); - return (err ? -EFAULT : 0); -} -#endif - -static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct ifconf32 ifc32; - struct ifconf ifc; - struct ifreq32 __user *ifr32; - struct ifreq *ifr; - mm_segment_t old_fs; - unsigned int i, j; - int err; - - if (copy_from_user(&ifc32, (struct ifconf32 *)arg, sizeof(struct ifconf32))) - return -EFAULT; - - if(ifc32.ifcbuf == 0) { - ifc32.ifc_len = 0; - ifc.ifc_len = 0; - ifc.ifc_buf = NULL; - } else { - ifc.ifc_len = ((ifc32.ifc_len / sizeof (struct ifreq32)) + 1) * - sizeof (struct ifreq); - ifc.ifc_buf = kmalloc (ifc.ifc_len, GFP_KERNEL); - if (!ifc.ifc_buf) - return -ENOMEM; - } - ifr = ifc.ifc_req; - ifr32 = A(ifc32.ifcbuf); - for (i = 0; i < ifc32.ifc_len; i += sizeof (struct ifreq32)) { - if (copy_from_user(ifr++, ifr32++, sizeof (struct ifreq32))) { - kfree (ifc.ifc_buf); - return -EFAULT; - } - } - old_fs = get_fs(); set_fs (KERNEL_DS); - err = sys_ioctl (fd, SIOCGIFCONF, (unsigned long)&ifc); - set_fs (old_fs); - if (!err) { - ifr = ifc.ifc_req; - ifr32 = A(ifc32.ifcbuf); - for (i = 0, j = 0; i < ifc32.ifc_len && j < ifc.ifc_len; - i += sizeof (struct ifreq32), j += sizeof (struct ifreq)) { - if (copy_to_user(ifr32++, ifr++, sizeof (struct ifreq32))) { - err = -EFAULT; - break; - } - } - if (!err) { - if (ifc32.ifcbuf == 0) { - /* Translate from 64-bit structure multiple to - * a 32-bit one. - */ - i = ifc.ifc_len; - i = ((i / sizeof(struct ifreq)) * sizeof(struct ifreq32)); - ifc32.ifc_len = i; - } else { - if (i <= ifc32.ifc_len) - ifc32.ifc_len = i; - else - ifc32.ifc_len = i - sizeof (struct ifreq32); - } - if (copy_to_user((struct ifconf32 *)arg, &ifc32, sizeof(struct ifconf32))) - err = -EFAULT; - } - } - if(ifc.ifc_buf != NULL) - kfree (ifc.ifc_buf); - return err; -} - -static int ethtool_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct ifreq ifr; - mm_segment_t old_fs; - int err, len; - u32 data, ethcmd; - - if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32))) - return -EFAULT; - ifr.ifr_data = (__kernel_caddr_t)get_zeroed_page(GFP_KERNEL); - if (!ifr.ifr_data) - return -EAGAIN; - - __get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data)); - - if (get_user(ethcmd, (u32 __user *) A(data))) { - err = -EFAULT; - goto out; - } - switch (ethcmd) { - case ETHTOOL_GDRVINFO: len = sizeof(struct ethtool_drvinfo); break; - case ETHTOOL_GMSGLVL: - case ETHTOOL_SMSGLVL: - case ETHTOOL_GLINK: - case ETHTOOL_NWAY_RST: len = sizeof(struct ethtool_value); break; - case ETHTOOL_GREGS: { - struct ethtool_regs __user *regaddr = A(data); - /* darned variable size arguments */ - if (get_user(len, (u32 *)®addr->len)) { - err = -EFAULT; - goto out; - } - len += sizeof(struct ethtool_regs); - break; - } - case ETHTOOL_GSET: - case ETHTOOL_SSET: len = sizeof(struct ethtool_cmd); break; - default: - err = -EOPNOTSUPP; - goto out; - } - - if (copy_from_user(ifr.ifr_data, A(data), len)) { - err = -EFAULT; - goto out; - } - - old_fs = get_fs(); - set_fs (KERNEL_DS); - err = sys_ioctl (fd, cmd, (unsigned long)&ifr); - set_fs (old_fs); - if (!err) { - u32 data; - - __get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data)); - len = copy_to_user(A(data), ifr.ifr_data, len); - if (len) - err = -EFAULT; - } - -out: - free_page((unsigned long)ifr.ifr_data); - return err; -} - -static int bond_ioctl(unsigned long fd, unsigned int cmd, unsigned long arg) -{ - struct ifreq ifr; - mm_segment_t old_fs; - int err, len; - u32 data; - - if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32))) - return -EFAULT; - ifr.ifr_data = (__kernel_caddr_t)get_zeroed_page(GFP_KERNEL); - if (!ifr.ifr_data) - return -EAGAIN; - - switch (cmd) { - case SIOCBONDENSLAVE: - case SIOCBONDRELEASE: - case SIOCBONDSETHWADDR: - case SIOCBONDCHANGEACTIVE: - len = IFNAMSIZ * sizeof(char); - break; - case SIOCBONDSLAVEINFOQUERY: - len = sizeof(struct ifslave); - break; - case SIOCBONDINFOQUERY: - len = sizeof(struct ifbond); - break; - default: - err = -EINVAL; - goto out; - }; - - __get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data)); - if (copy_from_user(ifr.ifr_data, A(data), len)) { - err = -EFAULT; - goto out; - } - - old_fs = get_fs(); - set_fs (KERNEL_DS); - err = sys_ioctl (fd, cmd, (unsigned long)&ifr); - set_fs (old_fs); - if (!err) { - len = copy_to_user(A(data), ifr.ifr_data, len); - if (len) - err = -EFAULT; - } - -out: - free_page((unsigned long)ifr.ifr_data); - return err; -} - -int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct ifreq *u_ifreq64; - struct ifreq32 *u_ifreq32 = (struct ifreq32 *) arg; - char tmp_buf[IFNAMSIZ]; - void __user *data64; - u32 data32; - - if (copy_from_user(&tmp_buf[0], &(u_ifreq32->ifr_ifrn.ifrn_name[0]), - IFNAMSIZ)) - return -EFAULT; - if (__get_user(data32, &u_ifreq32->ifr_ifru.ifru_data)) - return -EFAULT; - data64 = A(data32); - - u_ifreq64 = compat_alloc_user_space(sizeof(*u_ifreq64)); - - /* Don't check these user accesses, just let that get trapped - * in the ioctl handler instead. - */ - copy_to_user(&u_ifreq64->ifr_ifrn.ifrn_name[0], &tmp_buf[0], IFNAMSIZ); - __put_user(data64, &u_ifreq64->ifr_ifru.ifru_data); - - return sys_ioctl(fd, cmd, (unsigned long) u_ifreq64); -} - -static int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct ifreq ifr; - mm_segment_t old_fs; - int err; - - switch (cmd) { - case SIOCSIFMAP: - err = copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(ifr.ifr_name)); - err |= __get_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_start)); - err |= __get_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_end)); - err |= __get_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.base_addr)); - err |= __get_user(ifr.ifr_map.irq, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.irq)); - err |= __get_user(ifr.ifr_map.dma, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.dma)); - err |= __get_user(ifr.ifr_map.port, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.port)); - if (err) - return -EFAULT; - break; - default: - if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32))) - return -EFAULT; - break; - } - old_fs = get_fs(); - set_fs (KERNEL_DS); - err = sys_ioctl (fd, cmd, (unsigned long)&ifr); - set_fs (old_fs); - if (!err) { - switch (cmd) { - case SIOCGIFFLAGS: - case SIOCGIFMETRIC: - case SIOCGIFMTU: - case SIOCGIFMEM: - case SIOCGIFHWADDR: - case SIOCGIFINDEX: - case SIOCGIFADDR: - case SIOCGIFBRDADDR: - case SIOCGIFDSTADDR: - case SIOCGIFNETMASK: - case SIOCGIFTXQLEN: - if (copy_to_user((struct ifreq32 *)arg, &ifr, sizeof(struct ifreq32))) - return -EFAULT; - break; - case SIOCGIFMAP: - err = copy_to_user((struct ifreq32 *)arg, &ifr, sizeof(ifr.ifr_name)); - err |= __put_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_start)); - err |= __put_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_end)); - err |= __put_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.base_addr)); - err |= __put_user(ifr.ifr_map.irq, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.irq)); - err |= __put_user(ifr.ifr_map.dma, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.dma)); - err |= __put_user(ifr.ifr_map.port, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.port)); - if (err) - err = -EFAULT; - break; - } - } - return err; -} - -struct rtentry32 { - u32 rt_pad1; - struct sockaddr rt_dst; /* target address */ - struct sockaddr rt_gateway; /* gateway addr (RTF_GATEWAY) */ - struct sockaddr rt_genmask; /* target network mask (IP) */ - unsigned short rt_flags; - short rt_pad2; - u32 rt_pad3; - unsigned char rt_tos; - unsigned char rt_class; - short rt_pad4; - short rt_metric; /* +1 for binary compatibility! */ - /* char * */ u32 rt_dev; /* forcing the device at add */ - u32 rt_mtu; /* per route MTU/Window */ - u32 rt_window; /* Window clamping */ - unsigned short rt_irtt; /* Initial RTT */ - -}; - -struct in6_rtmsg32 { - struct in6_addr rtmsg_dst; - struct in6_addr rtmsg_src; - struct in6_addr rtmsg_gateway; - u32 rtmsg_type; - u16 rtmsg_dst_len; - u16 rtmsg_src_len; - u32 rtmsg_metric; - u32 rtmsg_info; - u32 rtmsg_flags; - s32 rtmsg_ifindex; -}; - -static int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +static __inline__ void *alloc_user_space(long len) { - int ret; - void *r = NULL; - struct in6_rtmsg r6; - struct rtentry r4; - char devname[16]; - u32 rtdev; - mm_segment_t old_fs = get_fs(); - - struct socket *mysock = sockfd_lookup(fd, &ret); - - if (mysock && mysock->sk && mysock->sk->family == AF_INET6) { /* ipv6 */ - ret = copy_from_user (&r6.rtmsg_dst, &(((struct in6_rtmsg32 *)arg)->rtmsg_dst), - 3 * sizeof(struct in6_addr)); - ret |= __get_user (r6.rtmsg_type, &(((struct in6_rtmsg32 *)arg)->rtmsg_type)); - ret |= __get_user (r6.rtmsg_dst_len, &(((struct in6_rtmsg32 *)arg)->rtmsg_dst_len)); - ret |= __get_user (r6.rtmsg_src_len, &(((struct in6_rtmsg32 *)arg)->rtmsg_src_len)); - ret |= __get_user (r6.rtmsg_metric, &(((struct in6_rtmsg32 *)arg)->rtmsg_metric)); - ret |= __get_user (r6.rtmsg_info, &(((struct in6_rtmsg32 *)arg)->rtmsg_info)); - ret |= __get_user (r6.rtmsg_flags, &(((struct in6_rtmsg32 *)arg)->rtmsg_flags)); - ret |= __get_user (r6.rtmsg_ifindex, &(((struct in6_rtmsg32 *)arg)->rtmsg_ifindex)); - - r = (void *) &r6; - } else { /* ipv4 */ - ret = copy_from_user (&r4.rt_dst, &(((struct rtentry32 *)arg)->rt_dst), 3 * sizeof(struct sockaddr)); - ret |= __get_user (r4.rt_flags, &(((struct rtentry32 *)arg)->rt_flags)); - ret |= __get_user (r4.rt_metric, &(((struct rtentry32 *)arg)->rt_metric)); - ret |= __get_user (r4.rt_mtu, &(((struct rtentry32 *)arg)->rt_mtu)); - ret |= __get_user (r4.rt_window, &(((struct rtentry32 *)arg)->rt_window)); - ret |= __get_user (r4.rt_irtt, &(((struct rtentry32 *)arg)->rt_irtt)); - ret |= __get_user (rtdev, &(((struct rtentry32 *)arg)->rt_dev)); - if (rtdev) { - ret |= copy_from_user (devname, A(rtdev), 15); - r4.rt_dev = devname; devname[15] = 0; - } else - r4.rt_dev = 0; - - r = (void *) &r4; - } + struct pt_regs *regs = current_thread_info()->kregs; + unsigned long usp = regs->u_regs[UREG_I6]; - if (ret) - return -EFAULT; - - set_fs (KERNEL_DS); - ret = sys_ioctl (fd, cmd, (long) r); - set_fs (old_fs); - - if (mysock) - sockfd_put(mysock); + if (!(test_thread_flag(TIF_32BIT))) + usp += STACK_BIAS; - return ret; + return (void *) (usp - len); } -struct hd_geometry32 { - unsigned char heads; - unsigned char sectors; - unsigned short cylinders; - u32 start; -}; - -static int hdio_getgeo(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - struct hd_geometry geo; - int err; - - set_fs (KERNEL_DS); - err = sys_ioctl(fd, HDIO_GETGEO, (unsigned long)&geo); - set_fs (old_fs); - if (!err) { - if (copy_to_user ((struct hd_geometry32 *)arg, &geo, 4) || - __put_user (geo.start, &(((struct hd_geometry32 *)arg)->start))) - err = -EFAULT; - } - return err; -} +#define CODE +#include "compat_ioctl.c" struct hd_big_geometry32 { unsigned char heads; @@ -990,1252 +175,6 @@ return ret; } -struct fb_fix_screeninfo32 { - char id[16]; - compat_caddr_t smem_start; - __u32 smem_len; - __u32 type; - __u32 type_aux; - __u32 visual; - __u16 xpanstep; - __u16 ypanstep; - __u16 ywrapstep; - __u32 line_length; - compat_caddr_t mmio_start; - __u32 mmio_len; - __u32 accel; - __u16 reserved[3]; -}; - -struct fb_cmap32 { - __u32 start; - __u32 len; - compat_caddr_t red; - compat_caddr_t green; - compat_caddr_t blue; - compat_caddr_t transp; -}; - -static int fb_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - u32 red = 0, green = 0, blue = 0, transp = 0; - struct fb_fix_screeninfo fix; - struct fb_cmap cmap; - void *karg; - int err = 0; - - memset(&cmap, 0, sizeof(cmap)); - switch (cmd) { - case FBIOGET_FSCREENINFO: - karg = &fix; - break; - case FBIOGETCMAP: - case FBIOPUTCMAP: - karg = &cmap; - err = __get_user(cmap.start, &((struct fb_cmap32 *)arg)->start); - err |= __get_user(cmap.len, &((struct fb_cmap32 *)arg)->len); - err |= __get_user(red, &((struct fb_cmap32 *)arg)->red); - err |= __get_user(green, &((struct fb_cmap32 *)arg)->green); - err |= __get_user(blue, &((struct fb_cmap32 *)arg)->blue); - err |= __get_user(transp, &((struct fb_cmap32 *)arg)->transp); - if (err) { - err = -EFAULT; - goto out; - } - err = -ENOMEM; - cmap.red = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL); - if (!cmap.red) - goto out; - cmap.green = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL); - if (!cmap.green) - goto out; - cmap.blue = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL); - if (!cmap.blue) - goto out; - if (transp) { - cmap.transp = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL); - if (!cmap.transp) - goto out; - } - - if (cmd == FBIOGETCMAP) - break; - - err = __copy_from_user(cmap.red, A(red), cmap.len * sizeof(__u16)); - err |= __copy_from_user(cmap.green, A(green), cmap.len * sizeof(__u16)); - err |= __copy_from_user(cmap.blue, A(blue), cmap.len * sizeof(__u16)); - if (cmap.transp) err |= __copy_from_user(cmap.transp, A(transp), cmap.len * sizeof(__u16)); - if (err) { - err = -EFAULT; - goto out; - } - break; - default: - do { - static int count; - if (++count <= 20) - printk("%s: Unknown fb ioctl cmd fd(%d) " - "cmd(%08x) arg(%08lx)\n", - __FUNCTION__, fd, cmd, arg); - } while(0); - return -ENOSYS; - } - set_fs(KERNEL_DS); - err = sys_ioctl(fd, cmd, (unsigned long)karg); - set_fs(old_fs); - if (err) - goto out; - switch (cmd) { - case FBIOGET_FSCREENINFO: - err = __copy_to_user((char *)((struct fb_fix_screeninfo32 *)arg)->id, (char *)fix.id, sizeof(fix.id)); - err |= __put_user((__u32)(unsigned long)fix.smem_start, &((struct fb_fix_screeninfo32 *)arg)->smem_start); - err |= __put_user(fix.smem_len, &((struct fb_fix_screeninfo32 *)arg)->smem_len); - err |= __put_user(fix.type, &((struct fb_fix_screeninfo32 *)arg)->type); - err |= __put_user(fix.type_aux, &((struct fb_fix_screeninfo32 *)arg)->type_aux); - err |= __put_user(fix.visual, &((struct fb_fix_screeninfo32 *)arg)->visual); - err |= __put_user(fix.xpanstep, &((struct fb_fix_screeninfo32 *)arg)->xpanstep); - err |= __put_user(fix.ypanstep, &((struct fb_fix_screeninfo32 *)arg)->ypanstep); - err |= __put_user(fix.ywrapstep, &((struct fb_fix_screeninfo32 *)arg)->ywrapstep); - err |= __put_user(fix.line_length, &((struct fb_fix_screeninfo32 *)arg)->line_length); - err |= __put_user((__u32)(unsigned long)fix.mmio_start, &((struct fb_fix_screeninfo32 *)arg)->mmio_start); - err |= __put_user(fix.mmio_len, &((struct fb_fix_screeninfo32 *)arg)->mmio_len); - err |= __put_user(fix.accel, &((struct fb_fix_screeninfo32 *)arg)->accel); - err |= __copy_to_user((char *)((struct fb_fix_screeninfo32 *)arg)->reserved, (char *)fix.reserved, sizeof(fix.reserved)); - break; - case FBIOGETCMAP: - err = __copy_to_user(A(red), cmap.red, cmap.len * sizeof(__u16)); - err |= __copy_to_user(A(green), cmap.blue, cmap.len * sizeof(__u16)); - err |= __copy_to_user(A(blue), cmap.blue, cmap.len * sizeof(__u16)); - if (cmap.transp) - err |= __copy_to_user(A(transp), cmap.transp, cmap.len * sizeof(__u16)); - break; - case FBIOPUTCMAP: - break; - } - if (err) - err = -EFAULT; - -out: if (cmap.red) kfree(cmap.red); - if (cmap.green) kfree(cmap.green); - if (cmap.blue) kfree(cmap.blue); - if (cmap.transp) kfree(cmap.transp); - return err; -} - -static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - unsigned long kval; - unsigned int *uvp; - int error; - - set_fs(KERNEL_DS); - error = sys_ioctl(fd, cmd, (long)&kval); - set_fs(old_fs); - - if(error == 0) { - uvp = (unsigned int *)arg; - if(put_user(kval, uvp)) - error = -EFAULT; - } - return error; -} - -struct floppy_struct32 { - unsigned int size; - unsigned int sect; - unsigned int head; - unsigned int track; - unsigned int stretch; - unsigned char gap; - unsigned char rate; - unsigned char spec1; - unsigned char fmt_gap; - const compat_caddr_t name; -}; - -struct floppy_drive_params32 { - char cmos; - u32 max_dtr; - u32 hlt; - u32 hut; - u32 srt; - u32 spinup; - u32 spindown; - unsigned char spindown_offset; - unsigned char select_delay; - unsigned char rps; - unsigned char tracks; - u32 timeout; - unsigned char interleave_sect; - struct floppy_max_errors max_errors; - char flags; - char read_track; - short autodetect[8]; - int checkfreq; - int native_format; -}; - -struct floppy_drive_struct32 { - signed char flags; - u32 spinup_date; - u32 select_date; - u32 first_read_date; - short probed_format; - short track; - short maxblock; - short maxtrack; - int generation; - int keep_data; - int fd_ref; - int fd_device; - int last_checked; - compat_caddr_t dmabuf; - int bufblocks; -}; - -struct floppy_fdc_state32 { - int spec1; - int spec2; - int dtr; - unsigned char version; - unsigned char dor; - u32 address; - unsigned int rawcmd:2; - unsigned int reset:1; - unsigned int need_configure:1; - unsigned int perp_mode:2; - unsigned int has_fifo:1; - unsigned int driver_version; - unsigned char track[4]; -}; - -struct floppy_write_errors32 { - unsigned int write_errors; - u32 first_error_sector; - int first_error_generation; - u32 last_error_sector; - int last_error_generation; - unsigned int badness; -}; - -#define FDSETPRM32 _IOW(2, 0x42, struct floppy_struct32) -#define FDDEFPRM32 _IOW(2, 0x43, struct floppy_struct32) -#define FDGETPRM32 _IOR(2, 0x04, struct floppy_struct32) -#define FDSETDRVPRM32 _IOW(2, 0x90, struct floppy_drive_params32) -#define FDGETDRVPRM32 _IOR(2, 0x11, struct floppy_drive_params32) -#define FDGETDRVSTAT32 _IOR(2, 0x12, struct floppy_drive_struct32) -#define FDPOLLDRVSTAT32 _IOR(2, 0x13, struct floppy_drive_struct32) -#define FDGETFDCSTAT32 _IOR(2, 0x15, struct floppy_fdc_state32) -#define FDWERRORGET32 _IOR(2, 0x17, struct floppy_write_errors32) - -static struct { - unsigned int cmd32; - unsigned int cmd; -} fd_ioctl_trans_table[] = { - { FDSETPRM32, FDSETPRM }, - { FDDEFPRM32, FDDEFPRM }, - { FDGETPRM32, FDGETPRM }, - { FDSETDRVPRM32, FDSETDRVPRM }, - { FDGETDRVPRM32, FDGETDRVPRM }, - { FDGETDRVSTAT32, FDGETDRVSTAT }, - { FDPOLLDRVSTAT32, FDPOLLDRVSTAT }, - { FDGETFDCSTAT32, FDGETFDCSTAT }, - { FDWERRORGET32, FDWERRORGET } -}; - -#define NR_FD_IOCTL_TRANS (sizeof(fd_ioctl_trans_table)/sizeof(fd_ioctl_trans_table[0])) - -static int fd_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - void *karg = NULL; - unsigned int kcmd = 0; - int i, err; - - for (i = 0; i < NR_FD_IOCTL_TRANS; i++) - if (cmd == fd_ioctl_trans_table[i].cmd32) { - kcmd = fd_ioctl_trans_table[i].cmd; - break; - } - if (!kcmd) - return -EINVAL; - - switch (cmd) { - case FDSETPRM32: - case FDDEFPRM32: - case FDGETPRM32: - { - struct floppy_struct *f; - - f = karg = kmalloc(sizeof(struct floppy_struct), GFP_KERNEL); - if (!karg) - return -ENOMEM; - if (cmd == FDGETPRM32) - break; - err = __get_user(f->size, &((struct floppy_struct32 *)arg)->size); - err |= __get_user(f->sect, &((struct floppy_struct32 *)arg)->sect); - err |= __get_user(f->head, &((struct floppy_struct32 *)arg)->head); - err |= __get_user(f->track, &((struct floppy_struct32 *)arg)->track); - err |= __get_user(f->stretch, &((struct floppy_struct32 *)arg)->stretch); - err |= __get_user(f->gap, &((struct floppy_struct32 *)arg)->gap); - err |= __get_user(f->rate, &((struct floppy_struct32 *)arg)->rate); - err |= __get_user(f->spec1, &((struct floppy_struct32 *)arg)->spec1); - err |= __get_user(f->fmt_gap, &((struct floppy_struct32 *)arg)->fmt_gap); - err |= __get_user((u64)f->name, &((struct floppy_struct32 *)arg)->name); - if (err) { - err = -EFAULT; - goto out; - } - break; - } - case FDSETDRVPRM32: - case FDGETDRVPRM32: - { - struct floppy_drive_params *f; - - f = karg = kmalloc(sizeof(struct floppy_drive_params), GFP_KERNEL); - if (!karg) - return -ENOMEM; - if (cmd == FDGETDRVPRM32) - break; - err = __get_user(f->cmos, &((struct floppy_drive_params32 *)arg)->cmos); - err |= __get_user(f->max_dtr, &((struct floppy_drive_params32 *)arg)->max_dtr); - err |= __get_user(f->hlt, &((struct floppy_drive_params32 *)arg)->hlt); - err |= __get_user(f->hut, &((struct floppy_drive_params32 *)arg)->hut); - err |= __get_user(f->srt, &((struct floppy_drive_params32 *)arg)->srt); - err |= __get_user(f->spinup, &((struct floppy_drive_params32 *)arg)->spinup); - err |= __get_user(f->spindown, &((struct floppy_drive_params32 *)arg)->spindown); - err |= __get_user(f->spindown_offset, &((struct floppy_drive_params32 *)arg)->spindown_offset); - err |= __get_user(f->select_delay, &((struct floppy_drive_params32 *)arg)->select_delay); - err |= __get_user(f->rps, &((struct floppy_drive_params32 *)arg)->rps); - err |= __get_user(f->tracks, &((struct floppy_drive_params32 *)arg)->tracks); - err |= __get_user(f->timeout, &((struct floppy_drive_params32 *)arg)->timeout); - err |= __get_user(f->interleave_sect, &((struct floppy_drive_params32 *)arg)->interleave_sect); - err |= __copy_from_user(&f->max_errors, &((struct floppy_drive_params32 *)arg)->max_errors, sizeof(f->max_errors)); - err |= __get_user(f->flags, &((struct floppy_drive_params32 *)arg)->flags); - err |= __get_user(f->read_track, &((struct floppy_drive_params32 *)arg)->read_track); - err |= __copy_from_user(f->autodetect, ((struct floppy_drive_params32 *)arg)->autodetect, sizeof(f->autodetect)); - err |= __get_user(f->checkfreq, &((struct floppy_drive_params32 *)arg)->checkfreq); - err |= __get_user(f->native_format, &((struct floppy_drive_params32 *)arg)->native_format); - if (err) { - err = -EFAULT; - goto out; - } - break; - } - case FDGETDRVSTAT32: - case FDPOLLDRVSTAT32: - karg = kmalloc(sizeof(struct floppy_drive_struct), GFP_KERNEL); - if (!karg) - return -ENOMEM; - break; - case FDGETFDCSTAT32: - karg = kmalloc(sizeof(struct floppy_fdc_state), GFP_KERNEL); - if (!karg) - return -ENOMEM; - break; - case FDWERRORGET32: - karg = kmalloc(sizeof(struct floppy_write_errors), GFP_KERNEL); - if (!karg) - return -ENOMEM; - break; - default: - return -EINVAL; - } - set_fs (KERNEL_DS); - err = sys_ioctl (fd, kcmd, (unsigned long)karg); - set_fs (old_fs); - if (err) - goto out; - switch (cmd) { - case FDGETPRM32: - { - struct floppy_struct *f = karg; - - err = __put_user(f->size, &((struct floppy_struct32 *)arg)->size); - err |= __put_user(f->sect, &((struct floppy_struct32 *)arg)->sect); - err |= __put_user(f->head, &((struct floppy_struct32 *)arg)->head); - err |= __put_user(f->track, &((struct floppy_struct32 *)arg)->track); - err |= __put_user(f->stretch, &((struct floppy_struct32 *)arg)->stretch); - err |= __put_user(f->gap, &((struct floppy_struct32 *)arg)->gap); - err |= __put_user(f->rate, &((struct floppy_struct32 *)arg)->rate); - err |= __put_user(f->spec1, &((struct floppy_struct32 *)arg)->spec1); - err |= __put_user(f->fmt_gap, &((struct floppy_struct32 *)arg)->fmt_gap); - err |= __put_user((u64)f->name, &((struct floppy_struct32 *)arg)->name); - break; - } - case FDGETDRVPRM32: - { - struct floppy_drive_params *f = karg; - - err = __put_user(f->cmos, &((struct floppy_drive_params32 *)arg)->cmos); - err |= __put_user(f->max_dtr, &((struct floppy_drive_params32 *)arg)->max_dtr); - err |= __put_user(f->hlt, &((struct floppy_drive_params32 *)arg)->hlt); - err |= __put_user(f->hut, &((struct floppy_drive_params32 *)arg)->hut); - err |= __put_user(f->srt, &((struct floppy_drive_params32 *)arg)->srt); - err |= __put_user(f->spinup, &((struct floppy_drive_params32 *)arg)->spinup); - err |= __put_user(f->spindown, &((struct floppy_drive_params32 *)arg)->spindown); - err |= __put_user(f->spindown_offset, &((struct floppy_drive_params32 *)arg)->spindown_offset); - err |= __put_user(f->select_delay, &((struct floppy_drive_params32 *)arg)->select_delay); - err |= __put_user(f->rps, &((struct floppy_drive_params32 *)arg)->rps); - err |= __put_user(f->tracks, &((struct floppy_drive_params32 *)arg)->tracks); - err |= __put_user(f->timeout, &((struct floppy_drive_params32 *)arg)->timeout); - err |= __put_user(f->interleave_sect, &((struct floppy_drive_params32 *)arg)->interleave_sect); - err |= __copy_to_user(&((struct floppy_drive_params32 *)arg)->max_errors, &f->max_errors, sizeof(f->max_errors)); - err |= __put_user(f->flags, &((struct floppy_drive_params32 *)arg)->flags); - err |= __put_user(f->read_track, &((struct floppy_drive_params32 *)arg)->read_track); - err |= __copy_to_user(((struct floppy_drive_params32 *)arg)->autodetect, f->autodetect, sizeof(f->autodetect)); - err |= __put_user(f->checkfreq, &((struct floppy_drive_params32 *)arg)->checkfreq); - err |= __put_user(f->native_format, &((struct floppy_drive_params32 *)arg)->native_format); - break; - } - case FDGETDRVSTAT32: - case FDPOLLDRVSTAT32: - { - struct floppy_drive_struct *f = karg; - - err = __put_user(f->flags, &((struct floppy_drive_struct32 *)arg)->flags); - err |= __put_user(f->spinup_date, &((struct floppy_drive_struct32 *)arg)->spinup_date); - err |= __put_user(f->select_date, &((struct floppy_drive_struct32 *)arg)->select_date); - err |= __put_user(f->first_read_date, &((struct floppy_drive_struct32 *)arg)->first_read_date); - err |= __put_user(f->probed_format, &((struct floppy_drive_struct32 *)arg)->probed_format); - err |= __put_user(f->track, &((struct floppy_drive_struct32 *)arg)->track); - err |= __put_user(f->maxblock, &((struct floppy_drive_struct32 *)arg)->maxblock); - err |= __put_user(f->maxtrack, &((struct floppy_drive_struct32 *)arg)->maxtrack); - err |= __put_user(f->generation, &((struct floppy_drive_struct32 *)arg)->generation); - err |= __put_user(f->keep_data, &((struct floppy_drive_struct32 *)arg)->keep_data); - err |= __put_user(f->fd_ref, &((struct floppy_drive_struct32 *)arg)->fd_ref); - err |= __put_user(f->fd_device, &((struct floppy_drive_struct32 *)arg)->fd_device); - err |= __put_user(f->last_checked, &((struct floppy_drive_struct32 *)arg)->last_checked); - err |= __put_user((u64)f->dmabuf, &((struct floppy_drive_struct32 *)arg)->dmabuf); - err |= __put_user((u64)f->bufblocks, &((struct floppy_drive_struct32 *)arg)->bufblocks); - break; - } - case FDGETFDCSTAT32: - { - struct floppy_fdc_state *f = karg; - - err = __put_user(f->spec1, &((struct floppy_fdc_state32 *)arg)->spec1); - err |= __put_user(f->spec2, &((struct floppy_fdc_state32 *)arg)->spec2); - err |= __put_user(f->dtr, &((struct floppy_fdc_state32 *)arg)->dtr); - err |= __put_user(f->version, &((struct floppy_fdc_state32 *)arg)->version); - err |= __put_user(f->dor, &((struct floppy_fdc_state32 *)arg)->dor); - err |= __put_user(f->address, &((struct floppy_fdc_state32 *)arg)->address); - err |= __copy_to_user((char *)&((struct floppy_fdc_state32 *)arg)->address - + sizeof(((struct floppy_fdc_state32 *)arg)->address), - (char *)&f->address + sizeof(f->address), sizeof(int)); - err |= __put_user(f->driver_version, &((struct floppy_fdc_state32 *)arg)->driver_version); - err |= __copy_to_user(((struct floppy_fdc_state32 *)arg)->track, f->track, sizeof(f->track)); - break; - } - case FDWERRORGET32: - { - struct floppy_write_errors *f = karg; - - err = __put_user(f->write_errors, &((struct floppy_write_errors32 *)arg)->write_errors); - err |= __put_user(f->first_error_sector, &((struct floppy_write_errors32 *)arg)->first_error_sector); - err |= __put_user(f->first_error_generation, &((struct floppy_write_errors32 *)arg)->first_error_generation); - err |= __put_user(f->last_error_sector, &((struct floppy_write_errors32 *)arg)->last_error_sector); - err |= __put_user(f->last_error_generation, &((struct floppy_write_errors32 *)arg)->last_error_generation); - err |= __put_user(f->badness, &((struct floppy_write_errors32 *)arg)->badness); - break; - } - default: - break; - } - if (err) - err = -EFAULT; - -out: if (karg) kfree(karg); - return err; -} - -typedef struct sg_io_hdr32 { - s32 interface_id; /* [i] 'S' for SCSI generic (required) */ - s32 dxfer_direction; /* [i] data transfer direction */ - u8 cmd_len; /* [i] SCSI command length ( <= 16 bytes) */ - u8 mx_sb_len; /* [i] max length to write to sbp */ - u16 iovec_count; /* [i] 0 implies no scatter gather */ - u32 dxfer_len; /* [i] byte count of data transfer */ - u32 dxferp; /* [i], [*io] points to data transfer memory - or scatter gather list */ - u32 cmdp; /* [i], [*i] points to command to perform */ - u32 sbp; /* [i], [*o] points to sense_buffer memory */ - u32 timeout; /* [i] MAX_UINT->no timeout (unit: millisec) */ - u32 flags; /* [i] 0 -> default, see SG_FLAG... */ - s32 pack_id; /* [i->o] unused internally (normally) */ - u32 usr_ptr; /* [i->o] unused internally */ - u8 status; /* [o] scsi status */ - u8 masked_status; /* [o] shifted, masked scsi status */ - u8 msg_status; /* [o] messaging level data (optional) */ - u8 sb_len_wr; /* [o] byte count actually written to sbp */ - u16 host_status; /* [o] errors from host adapter */ - u16 driver_status; /* [o] errors from software driver */ - s32 resid; /* [o] dxfer_len - actual_transferred */ - u32 duration; /* [o] time taken by cmd (unit: millisec) */ - u32 info; /* [o] auxiliary information */ -} sg_io_hdr32_t; /* 64 bytes long (on sparc32) */ - -typedef struct sg_iovec32 { - u32 iov_base; - u32 iov_len; -} sg_iovec32_t; - -static int alloc_sg_iovec(sg_io_hdr_t *sgp, u32 uptr32) -{ - sg_iovec32_t __user *uiov = A(uptr32); - sg_iovec_t *kiov; - int i; - - sgp->dxferp = kmalloc(sgp->iovec_count * - sizeof(sg_iovec_t), GFP_KERNEL); - if (!sgp->dxferp) - return -ENOMEM; - memset(sgp->dxferp, 0, - sgp->iovec_count * sizeof(sg_iovec_t)); - - kiov = (sg_iovec_t *) sgp->dxferp; - for (i = 0; i < sgp->iovec_count; i++) { - u32 iov_base32; - if (__get_user(iov_base32, &uiov->iov_base) || - __get_user(kiov->iov_len, &uiov->iov_len)) - return -EFAULT; - - kiov->iov_base = kmalloc(kiov->iov_len, GFP_KERNEL); - if (!kiov->iov_base) - return -ENOMEM; - if (copy_from_user(kiov->iov_base, - A(iov_base32), - kiov->iov_len)) - return -EFAULT; - - uiov++; - kiov++; - } - - return 0; -} - -static int copy_back_sg_iovec(sg_io_hdr_t *sgp, u32 uptr32) -{ - sg_iovec32_t __user *uiov = A(uptr32); - sg_iovec_t *kiov = (sg_iovec_t *) sgp->dxferp; - int i; - - for (i = 0; i < sgp->iovec_count; i++) { - u32 iov_base32; - - if (__get_user(iov_base32, &uiov->iov_base)) - return -EFAULT; - - if (copy_to_user(A(iov_base32), - kiov->iov_base, - kiov->iov_len)) - return -EFAULT; - - uiov++; - kiov++; - } - - return 0; -} - -static void free_sg_iovec(sg_io_hdr_t *sgp) -{ - sg_iovec_t *kiov = (sg_iovec_t *) sgp->dxferp; - int i; - - for (i = 0; i < sgp->iovec_count; i++) { - if (kiov->iov_base) { - kfree(kiov->iov_base); - kiov->iov_base = NULL; - } - kiov++; - } - kfree(sgp->dxferp); - sgp->dxferp = NULL; -} - -static int sg_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - sg_io_hdr32_t *sg_io32; - sg_io_hdr_t sg_io64; - u32 dxferp32, cmdp32, sbp32; - mm_segment_t old_fs; - int err = 0; - - sg_io32 = (sg_io_hdr32_t *)arg; - err = __get_user(sg_io64.interface_id, &sg_io32->interface_id); - err |= __get_user(sg_io64.dxfer_direction, &sg_io32->dxfer_direction); - err |= __get_user(sg_io64.cmd_len, &sg_io32->cmd_len); - err |= __get_user(sg_io64.mx_sb_len, &sg_io32->mx_sb_len); - err |= __get_user(sg_io64.iovec_count, &sg_io32->iovec_count); - err |= __get_user(sg_io64.dxfer_len, &sg_io32->dxfer_len); - err |= __get_user(sg_io64.timeout, &sg_io32->timeout); - err |= __get_user(sg_io64.flags, &sg_io32->flags); - err |= __get_user(sg_io64.pack_id, &sg_io32->pack_id); - - sg_io64.dxferp = NULL; - sg_io64.cmdp = NULL; - sg_io64.sbp = NULL; - - err |= __get_user(cmdp32, &sg_io32->cmdp); - sg_io64.cmdp = kmalloc(sg_io64.cmd_len, GFP_KERNEL); - if (!sg_io64.cmdp) { - err = -ENOMEM; - goto out; - } - if (copy_from_user(sg_io64.cmdp, - A(cmdp32), - sg_io64.cmd_len)) { - err = -EFAULT; - goto out; - } - - err |= __get_user(sbp32, &sg_io32->sbp); - sg_io64.sbp = kmalloc(sg_io64.mx_sb_len, GFP_KERNEL); - if (!sg_io64.sbp) { - err = -ENOMEM; - goto out; - } - if (copy_from_user(sg_io64.sbp, - A(sbp32), - sg_io64.mx_sb_len)) { - err = -EFAULT; - goto out; - } - - err |= __get_user(dxferp32, &sg_io32->dxferp); - if (sg_io64.iovec_count) { - int ret; - - if ((ret = alloc_sg_iovec(&sg_io64, dxferp32))) { - err = ret; - goto out; - } - } else { - sg_io64.dxferp = kmalloc(sg_io64.dxfer_len, GFP_KERNEL); - if (!sg_io64.dxferp) { - err = -ENOMEM; - goto out; - } - if (copy_from_user(sg_io64.dxferp, - A(dxferp32), - sg_io64.dxfer_len)) { - err = -EFAULT; - goto out; - } - } - - /* Unused internally, do not even bother to copy it over. */ - sg_io64.usr_ptr = NULL; - - if (err) - return -EFAULT; - - old_fs = get_fs(); - set_fs (KERNEL_DS); - err = sys_ioctl (fd, cmd, (unsigned long) &sg_io64); - set_fs (old_fs); - - if (err < 0) - goto out; - - err = __put_user(sg_io64.pack_id, &sg_io32->pack_id); - err |= __put_user(sg_io64.status, &sg_io32->status); - err |= __put_user(sg_io64.masked_status, &sg_io32->masked_status); - err |= __put_user(sg_io64.msg_status, &sg_io32->msg_status); - err |= __put_user(sg_io64.sb_len_wr, &sg_io32->sb_len_wr); - err |= __put_user(sg_io64.host_status, &sg_io32->host_status); - err |= __put_user(sg_io64.driver_status, &sg_io32->driver_status); - err |= __put_user(sg_io64.resid, &sg_io32->resid); - err |= __put_user(sg_io64.duration, &sg_io32->duration); - err |= __put_user(sg_io64.info, &sg_io32->info); - err |= copy_to_user(A(sbp32), sg_io64.sbp, sg_io64.mx_sb_len); - if (sg_io64.dxferp) { - if (sg_io64.iovec_count) - err |= copy_back_sg_iovec(&sg_io64, dxferp32); - else - err |= copy_to_user(A(dxferp32), - sg_io64.dxferp, - sg_io64.dxfer_len); - } - if (err) - err = -EFAULT; - -out: - if (sg_io64.cmdp) - kfree(sg_io64.cmdp); - if (sg_io64.sbp) - kfree(sg_io64.sbp); - if (sg_io64.dxferp) { - if (sg_io64.iovec_count) { - free_sg_iovec(&sg_io64); - } else { - kfree(sg_io64.dxferp); - } - } - return err; -} - -struct sock_fprog32 { - __u16 len; - __u32 filter; -}; - -#define PPPIOCSPASS32 _IOW('t', 71, struct sock_fprog32) -#define PPPIOCSACTIVE32 _IOW('t', 70, struct sock_fprog32) - -static int ppp_sock_fprog_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct sock_fprog32 *u_fprog32 = (struct sock_fprog32 *) arg; - struct sock_fprog *u_fprog64 = compat_alloc_user_space(sizeof(struct sock_fprog)); - void __user *fptr64; - u32 fptr32; - u16 flen; - - if (get_user(flen, &u_fprog32->len) || - get_user(fptr32, &u_fprog32->filter)) - return -EFAULT; - - fptr64 = A(fptr32); - - if (put_user(flen, &u_fprog64->len) || - put_user(fptr64, &u_fprog64->filter)) - return -EFAULT; - - if (cmd == PPPIOCSPASS32) - cmd = PPPIOCSPASS; - else - cmd = PPPIOCSACTIVE; - - return sys_ioctl(fd, cmd, (unsigned long) u_fprog64); -} - -struct ppp_option_data32 { - compat_caddr_t ptr; - __u32 length; - int transmit; -}; -#define PPPIOCSCOMPRESS32 _IOW('t', 77, struct ppp_option_data32) - -struct ppp_idle32 { - compat_time_t xmit_idle; - compat_time_t recv_idle; -}; -#define PPPIOCGIDLE32 _IOR('t', 63, struct ppp_idle32) - -static int ppp_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - struct ppp_option_data32 data32; - struct ppp_option_data data; - struct ppp_idle32 idle32; - struct ppp_idle idle; - unsigned int kcmd; - void *karg; - int err = 0; - - switch (cmd) { - case PPPIOCGIDLE32: - kcmd = PPPIOCGIDLE; - karg = &idle; - break; - case PPPIOCSCOMPRESS32: - if (copy_from_user(&data32, (struct ppp_option_data32 *)arg, sizeof(struct ppp_option_data32))) - return -EFAULT; - data.ptr = kmalloc (data32.length, GFP_KERNEL); - if (!data.ptr) - return -ENOMEM; - if (copy_from_user(data.ptr, A(data32.ptr), data32.length)) { - kfree(data.ptr); - return -EFAULT; - } - data.length = data32.length; - data.transmit = data32.transmit; - kcmd = PPPIOCSCOMPRESS; - karg = &data; - break; - default: - do { - static int count; - if (++count <= 20) - printk("ppp_ioctl: Unknown cmd fd(%d) " - "cmd(%08x) arg(%08x)\n", - (int)fd, (unsigned int)cmd, (unsigned int)arg); - } while(0); - return -EINVAL; - } - set_fs (KERNEL_DS); - err = sys_ioctl (fd, kcmd, (unsigned long)karg); - set_fs (old_fs); - switch (cmd) { - case PPPIOCGIDLE32: - if (err) - return err; - idle32.xmit_idle = idle.xmit_idle; - idle32.recv_idle = idle.recv_idle; - if (copy_to_user((struct ppp_idle32 *)arg, &idle32, sizeof(struct ppp_idle32))) - return -EFAULT; - break; - case PPPIOCSCOMPRESS32: - kfree(data.ptr); - break; - default: - break; - } - return err; -} - - -struct mtget32 { - __u32 mt_type; - __u32 mt_resid; - __u32 mt_dsreg; - __u32 mt_gstat; - __u32 mt_erreg; - compat_daddr_t mt_fileno; - compat_daddr_t mt_blkno; -}; -#define MTIOCGET32 _IOR('m', 2, struct mtget32) - -struct mtpos32 { - __u32 mt_blkno; -}; -#define MTIOCPOS32 _IOR('m', 3, struct mtpos32) - -struct mtconfiginfo32 { - __u32 mt_type; - __u32 ifc_type; - __u16 irqnr; - __u16 dmanr; - __u16 port; - __u32 debug; - __u32 have_dens:1; - __u32 have_bsf:1; - __u32 have_fsr:1; - __u32 have_bsr:1; - __u32 have_eod:1; - __u32 have_seek:1; - __u32 have_tell:1; - __u32 have_ras1:1; - __u32 have_ras2:1; - __u32 have_ras3:1; - __u32 have_qfa:1; - __u32 pad1:5; - char reserved[10]; -}; -#define MTIOCGETCONFIG32 _IOR('m', 4, struct mtconfiginfo32) -#define MTIOCSETCONFIG32 _IOW('m', 5, struct mtconfiginfo32) - -static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - struct mtconfiginfo info; - struct mtget get; - struct mtpos pos; - unsigned long kcmd; - void *karg; - int err = 0; - - switch(cmd) { - case MTIOCPOS32: - kcmd = MTIOCPOS; - karg = &pos; - break; - case MTIOCGET32: - kcmd = MTIOCGET; - karg = &get; - break; - case MTIOCGETCONFIG32: - kcmd = MTIOCGETCONFIG; - karg = &info; - break; - case MTIOCSETCONFIG32: - kcmd = MTIOCSETCONFIG; - karg = &info; - err = __get_user(info.mt_type, &((struct mtconfiginfo32 *)arg)->mt_type); - err |= __get_user(info.ifc_type, &((struct mtconfiginfo32 *)arg)->ifc_type); - err |= __get_user(info.irqnr, &((struct mtconfiginfo32 *)arg)->irqnr); - err |= __get_user(info.dmanr, &((struct mtconfiginfo32 *)arg)->dmanr); - err |= __get_user(info.port, &((struct mtconfiginfo32 *)arg)->port); - err |= __get_user(info.debug, &((struct mtconfiginfo32 *)arg)->debug); - err |= __copy_from_user((char *)&info.debug + sizeof(info.debug), - (char *)&((struct mtconfiginfo32 *)arg)->debug - + sizeof(((struct mtconfiginfo32 *)arg)->debug), sizeof(__u32)); - if (err) - return -EFAULT; - break; - default: - do { - static int count; - if (++count <= 20) - printk("mt_ioctl: Unknown cmd fd(%d) " - "cmd(%08x) arg(%08x)\n", - (int)fd, (unsigned int)cmd, (unsigned int)arg); - } while(0); - return -EINVAL; - } - set_fs (KERNEL_DS); - err = sys_ioctl (fd, kcmd, (unsigned long)karg); - set_fs (old_fs); - if (err) - return err; - switch (cmd) { - case MTIOCPOS32: - err = __put_user(pos.mt_blkno, &((struct mtpos32 *)arg)->mt_blkno); - break; - case MTIOCGET32: - err = __put_user(get.mt_type, &((struct mtget32 *)arg)->mt_type); - err |= __put_user(get.mt_resid, &((struct mtget32 *)arg)->mt_resid); - err |= __put_user(get.mt_dsreg, &((struct mtget32 *)arg)->mt_dsreg); - err |= __put_user(get.mt_gstat, &((struct mtget32 *)arg)->mt_gstat); - err |= __put_user(get.mt_erreg, &((struct mtget32 *)arg)->mt_erreg); - err |= __put_user(get.mt_fileno, &((struct mtget32 *)arg)->mt_fileno); - err |= __put_user(get.mt_blkno, &((struct mtget32 *)arg)->mt_blkno); - break; - case MTIOCGETCONFIG32: - err = __put_user(info.mt_type, &((struct mtconfiginfo32 *)arg)->mt_type); - err |= __put_user(info.ifc_type, &((struct mtconfiginfo32 *)arg)->ifc_type); - err |= __put_user(info.irqnr, &((struct mtconfiginfo32 *)arg)->irqnr); - err |= __put_user(info.dmanr, &((struct mtconfiginfo32 *)arg)->dmanr); - err |= __put_user(info.port, &((struct mtconfiginfo32 *)arg)->port); - err |= __put_user(info.debug, &((struct mtconfiginfo32 *)arg)->debug); - err |= __copy_to_user((char *)&((struct mtconfiginfo32 *)arg)->debug - + sizeof(((struct mtconfiginfo32 *)arg)->debug), - (char *)&info.debug + sizeof(info.debug), sizeof(__u32)); - break; - case MTIOCSETCONFIG32: - break; - } - return err ? -EFAULT: 0; -} - -struct cdrom_read32 { - int cdread_lba; - compat_caddr_t cdread_bufaddr; - int cdread_buflen; -}; - -struct cdrom_read_audio32 { - union cdrom_addr addr; - u_char addr_format; - int nframes; - compat_caddr_t buf; -}; - -struct cdrom_generic_command32 { - unsigned char cmd[CDROM_PACKET_SIZE]; - compat_caddr_t buffer; - unsigned int buflen; - int stat; - compat_caddr_t sense; - compat_caddr_t reserved[3]; -}; - -static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - struct cdrom_read cdread; - struct cdrom_read_audio cdreadaudio; - struct cdrom_generic_command cgc; - compat_caddr_t addr; - char *data = 0; - void *karg; - int err = 0; - - switch(cmd) { - case CDROMREADMODE2: - case CDROMREADMODE1: - case CDROMREADRAW: - case CDROMREADCOOKED: - karg = &cdread; - err = __get_user(cdread.cdread_lba, &((struct cdrom_read32 *)arg)->cdread_lba); - err |= __get_user(addr, &((struct cdrom_read32 *)arg)->cdread_bufaddr); - err |= __get_user(cdread.cdread_buflen, &((struct cdrom_read32 *)arg)->cdread_buflen); - if (err) - return -EFAULT; - data = kmalloc(cdread.cdread_buflen, GFP_KERNEL); - if (!data) - return -ENOMEM; - cdread.cdread_bufaddr = data; - break; - case CDROMREADAUDIO: - karg = &cdreadaudio; - err = copy_from_user(&cdreadaudio.addr, &((struct cdrom_read_audio32 *)arg)->addr, sizeof(cdreadaudio.addr)); - err |= __get_user(cdreadaudio.addr_format, &((struct cdrom_read_audio32 *)arg)->addr_format); - err |= __get_user(cdreadaudio.nframes, &((struct cdrom_read_audio32 *)arg)->nframes); - err |= __get_user(addr, &((struct cdrom_read_audio32 *)arg)->buf); - if (err) - return -EFAULT; - data = kmalloc(cdreadaudio.nframes * 2352, GFP_KERNEL); - if (!data) - return -ENOMEM; - cdreadaudio.buf = data; - break; - case CDROM_SEND_PACKET: - karg = &cgc; - err = copy_from_user(cgc.cmd, &((struct cdrom_generic_command32 *)arg)->cmd, sizeof(cgc.cmd)); - err |= __get_user(addr, &((struct cdrom_generic_command32 *)arg)->buffer); - err |= __get_user(cgc.buflen, &((struct cdrom_generic_command32 *)arg)->buflen); - if (err) - return -EFAULT; - if ((data = kmalloc(cgc.buflen, GFP_KERNEL)) == NULL) - return -ENOMEM; - cgc.buffer = data; - break; - default: - do { - static int count; - if (++count <= 20) - printk("cdrom_ioctl: Unknown cmd fd(%d) " - "cmd(%08x) arg(%08x)\n", - (int)fd, (unsigned int)cmd, (unsigned int)arg); - } while(0); - return -EINVAL; - } - set_fs (KERNEL_DS); - err = sys_ioctl (fd, cmd, (unsigned long)karg); - set_fs (old_fs); - if (err) - goto out; - switch (cmd) { - case CDROMREADMODE2: - case CDROMREADMODE1: - case CDROMREADRAW: - case CDROMREADCOOKED: - err = copy_to_user(A(addr), data, cdread.cdread_buflen); - break; - case CDROMREADAUDIO: - err = copy_to_user(A(addr), data, cdreadaudio.nframes * 2352); - break; - case CDROM_SEND_PACKET: - err = copy_to_user(A(addr), data, cgc.buflen); - break; - default: - break; - } -out: if (data) - kfree(data); - return err ? -EFAULT : 0; -} - -struct loop_info32 { - int lo_number; /* ioctl r/o */ - compat_dev_t lo_device; /* ioctl r/o */ - unsigned int lo_inode; /* ioctl r/o */ - compat_dev_t lo_rdevice; /* ioctl r/o */ - int lo_offset; - int lo_encrypt_type; - int lo_encrypt_key_size; /* ioctl w/o */ - int lo_flags; /* ioctl r/o */ - char lo_name[LO_NAME_SIZE]; - unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */ - unsigned int lo_init[2]; - char reserved[4]; -}; - -static int loop_status(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - struct loop_info l; - int err = -EINVAL; - - switch(cmd) { - case LOOP_SET_STATUS: - err = get_user(l.lo_number, &((struct loop_info32 *)arg)->lo_number); - err |= __get_user(l.lo_device, &((struct loop_info32 *)arg)->lo_device); - err |= __get_user(l.lo_inode, &((struct loop_info32 *)arg)->lo_inode); - err |= __get_user(l.lo_rdevice, &((struct loop_info32 *)arg)->lo_rdevice); - err |= __copy_from_user((char *)&l.lo_offset, (char *)&((struct loop_info32 *)arg)->lo_offset, - 8 + (unsigned long)l.lo_init - (unsigned long)&l.lo_offset); - if (err) { - err = -EFAULT; - } else { - set_fs (KERNEL_DS); - err = sys_ioctl (fd, cmd, (unsigned long)&l); - set_fs (old_fs); - } - break; - case LOOP_GET_STATUS: - set_fs (KERNEL_DS); - err = sys_ioctl (fd, cmd, (unsigned long)&l); - set_fs (old_fs); - if (!err) { - err = put_user(l.lo_number, &((struct loop_info32 *)arg)->lo_number); - err |= __put_user(l.lo_device, &((struct loop_info32 *)arg)->lo_device); - err |= __put_user(l.lo_inode, &((struct loop_info32 *)arg)->lo_inode); - err |= __put_user(l.lo_rdevice, &((struct loop_info32 *)arg)->lo_rdevice); - err |= __copy_to_user((char *)&((struct loop_info32 *)arg)->lo_offset, - (char *)&l.lo_offset, (unsigned long)l.lo_init - (unsigned long)&l.lo_offset); - if (err) - err = -EFAULT; - } - break; - default: { - static int count; - if (++count <= 20) - printk("%s: Unknown loop ioctl cmd, fd(%d) " - "cmd(%08x) arg(%08lx)\n", - __FUNCTION__, fd, cmd, arg); - } - } - return err; -} - -extern int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg); - -static int vt_check(struct file *file) -{ - struct tty_struct *tty; - struct inode *inode = file->f_dentry->d_inode; - - if (file->f_op->ioctl != tty_ioctl) - return -EINVAL; - - tty = (struct tty_struct *)file->private_data; - if (tty_paranoia_check(tty, inode->i_rdev, "tty_ioctl")) - return -EINVAL; - - if (tty->driver->ioctl != vt_ioctl) - return -EINVAL; - - /* - * To have permissions to do most of the vt ioctls, we either have - * to be the owner of the tty, or have CAP_SYS_TTY_CONFIG. - */ - if (current->tty == tty || capable(CAP_SYS_TTY_CONFIG)) - return 1; - return 0; -} - -struct consolefontdesc32 { - unsigned short charcount; /* characters in font (256 or 512) */ - unsigned short charheight; /* scan lines per character (1-32) */ - u32 chardata; /* font data in expanded form */ -}; - -static int do_fontx_ioctl(unsigned int fd, int cmd, struct consolefontdesc32 *user_cfd, struct file *file) -{ - struct consolefontdesc cfdarg; - struct console_font_op op; - int i, perm; - - perm = vt_check(file); - if (perm < 0) return perm; - - if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc32))) - return -EFAULT; - - cfdarg.chardata = A(((struct consolefontdesc32 *)&cfdarg)->chardata); - - switch (cmd) { - case PIO_FONTX: - if (!perm) - return -EPERM; - op.op = KD_FONT_OP_SET; - op.flags = 0; - op.width = 8; - op.height = cfdarg.charheight; - op.charcount = cfdarg.charcount; - op.data = cfdarg.chardata; - return con_font_op(fg_console, &op); - case GIO_FONTX: - if (!cfdarg.chardata) - return 0; - op.op = KD_FONT_OP_GET; - op.flags = 0; - op.width = 8; - op.height = cfdarg.charheight; - op.charcount = cfdarg.charcount; - op.data = cfdarg.chardata; - i = con_font_op(fg_console, &op); - if (i) - return i; - cfdarg.charheight = op.height; - cfdarg.charcount = op.charcount; - ((struct consolefontdesc32 *)&cfdarg)->chardata = (unsigned long)cfdarg.chardata; - if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc32))) - return -EFAULT; - return 0; - } - return -EINVAL; -} - -struct console_font_op32 { - unsigned int op; /* operation code KD_FONT_OP_* */ - unsigned int flags; /* KD_FONT_FLAG_* */ - unsigned int width, height; /* font size */ - unsigned int charcount; - u32 data; /* font data with height fixed to 32 */ -}; - -static int do_kdfontop_ioctl(unsigned int fd, unsigned int cmd, struct console_font_op32 *fontop, struct file *file) -{ - struct console_font_op op; - int perm = vt_check(file), i; - struct vt_struct *vt; - - if (perm < 0) return perm; - - if (copy_from_user(&op, (void *) fontop, sizeof(struct console_font_op32))) - return -EFAULT; - if (!perm && op.op != KD_FONT_OP_GET) - return -EPERM; - op.data = A(((struct console_font_op32 *)&op)->data); - op.flags |= KD_FONT_FLAG_OLD; - vt = (struct vt_struct *)((struct tty_struct *)file->private_data)->driver_data; - i = con_font_op(vt->vc_num, &op); - if (i) return i; - ((struct console_font_op32 *)&op)->data = (unsigned long)op.data; - if (copy_to_user((void *) fontop, &op, sizeof(struct console_font_op32))) - return -EFAULT; - return 0; -} - -struct unimapdesc32 { - unsigned short entry_ct; - u32 entries; -}; - -static int do_unimap_ioctl(unsigned int fd, unsigned int cmd, struct unimapdesc32 *user_ud, struct file *file) -{ - struct unimapdesc32 tmp; - int perm = vt_check(file); - - if (perm < 0) return perm; - if (copy_from_user(&tmp, user_ud, sizeof tmp)) - return -EFAULT; - switch (cmd) { - case PIO_UNIMAP: - if (!perm) return -EPERM; - return con_set_unimap(fg_console, tmp.entry_ct, A(tmp.entries)); - case GIO_UNIMAP: - return con_get_unimap(fg_console, tmp.entry_ct, &(user_ud->entry_ct), A(tmp.entries)); - } - return 0; -} - -static int do_smb_getmountuid(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - __kernel_uid_t kuid; - int err; - - cmd = SMB_IOC_GETMOUNTUID; - - set_fs(KERNEL_DS); - err = sys_ioctl(fd, cmd, (unsigned long)&kuid); - set_fs(old_fs); - - if (err >= 0) - err = put_user(kuid, (compat_uid_t *)arg); - - return err; -} - struct ncp_ioctl_request_32 { unsigned int function; unsigned int size; @@ -2536,223 +475,6 @@ return err; } - -struct atmif_sioc32 { - int number; - int length; - compat_caddr_t arg; -}; - -struct atm_iobuf32 { - int length; - compat_caddr_t buffer; -}; - -#define ATM_GETLINKRATE32 _IOW('a', ATMIOC_ITF+1, struct atmif_sioc32) -#define ATM_GETNAMES32 _IOW('a', ATMIOC_ITF+3, struct atm_iobuf32) -#define ATM_GETTYPE32 _IOW('a', ATMIOC_ITF+4, struct atmif_sioc32) -#define ATM_GETESI32 _IOW('a', ATMIOC_ITF+5, struct atmif_sioc32) -#define ATM_GETADDR32 _IOW('a', ATMIOC_ITF+6, struct atmif_sioc32) -#define ATM_RSTADDR32 _IOW('a', ATMIOC_ITF+7, struct atmif_sioc32) -#define ATM_ADDADDR32 _IOW('a', ATMIOC_ITF+8, struct atmif_sioc32) -#define ATM_DELADDR32 _IOW('a', ATMIOC_ITF+9, struct atmif_sioc32) -#define ATM_GETCIRANGE32 _IOW('a', ATMIOC_ITF+10, struct atmif_sioc32) -#define ATM_SETCIRANGE32 _IOW('a', ATMIOC_ITF+11, struct atmif_sioc32) -#define ATM_SETESI32 _IOW('a', ATMIOC_ITF+12, struct atmif_sioc32) -#define ATM_SETESIF32 _IOW('a', ATMIOC_ITF+13, struct atmif_sioc32) -#define ATM_GETSTAT32 _IOW('a', ATMIOC_SARCOM+0, struct atmif_sioc32) -#define ATM_GETSTATZ32 _IOW('a', ATMIOC_SARCOM+1, struct atmif_sioc32) -#define ATM_GETLOOP32 _IOW('a', ATMIOC_SARCOM+2, struct atmif_sioc32) -#define ATM_SETLOOP32 _IOW('a', ATMIOC_SARCOM+3, struct atmif_sioc32) -#define ATM_QUERYLOOP32 _IOW('a', ATMIOC_SARCOM+4, struct atmif_sioc32) - -static struct { - unsigned int cmd32; - unsigned int cmd; -} atm_ioctl_map[] = { - { ATM_GETLINKRATE32, ATM_GETLINKRATE }, - { ATM_GETNAMES32, ATM_GETNAMES }, - { ATM_GETTYPE32, ATM_GETTYPE }, - { ATM_GETESI32, ATM_GETESI }, - { ATM_GETADDR32, ATM_GETADDR }, - { ATM_RSTADDR32, ATM_RSTADDR }, - { ATM_ADDADDR32, ATM_ADDADDR }, - { ATM_DELADDR32, ATM_DELADDR }, - { ATM_GETCIRANGE32, ATM_GETCIRANGE }, - { ATM_SETCIRANGE32, ATM_SETCIRANGE }, - { ATM_SETESI32, ATM_SETESI }, - { ATM_SETESIF32, ATM_SETESIF }, - { ATM_GETSTAT32, ATM_GETSTAT }, - { ATM_GETSTATZ32, ATM_GETSTATZ }, - { ATM_GETLOOP32, ATM_GETLOOP }, - { ATM_SETLOOP32, ATM_SETLOOP }, - { ATM_QUERYLOOP32, ATM_QUERYLOOP } -}; - -#define NR_ATM_IOCTL (sizeof(atm_ioctl_map)/sizeof(atm_ioctl_map[0])) - - -static int do_atm_iobuf(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct atm_iobuf32 iobuf32; - struct atm_iobuf iobuf = { 0, NULL }; - mm_segment_t old_fs; - int err; - - err = copy_from_user(&iobuf32, (struct atm_iobuf32*)arg, - sizeof(struct atm_iobuf32)); - if (err) - return -EFAULT; - - iobuf.length = iobuf32.length; - - if (iobuf32.buffer == (compat_caddr_t) NULL || iobuf32.length == 0) { - iobuf.buffer = (void*)(unsigned long)iobuf32.buffer; - } else { - iobuf.buffer = kmalloc(iobuf.length, GFP_KERNEL); - if (iobuf.buffer == NULL) { - err = -ENOMEM; - goto out; - } - - err = copy_from_user(iobuf.buffer, A(iobuf32.buffer), iobuf.length); - if (err) { - err = -EFAULT; - goto out; - } - } - - old_fs = get_fs(); set_fs (KERNEL_DS); - err = sys_ioctl (fd, cmd, (unsigned long)&iobuf); - set_fs (old_fs); - if(err) - goto out; - - if(iobuf.buffer && iobuf.length > 0) { - err = copy_to_user(A(iobuf32.buffer), iobuf.buffer, iobuf.length); - if (err) { - err = -EFAULT; - goto out; - } - } - err = __put_user(iobuf.length, &(((struct atm_iobuf32*)arg)->length)); - - out: - if(iobuf32.buffer && iobuf32.length > 0) - kfree(iobuf.buffer); - - return err; -} - - -static int do_atmif_sioc(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct atmif_sioc32 sioc32; - struct atmif_sioc sioc = { 0, 0, NULL }; - mm_segment_t old_fs; - int err; - - err = copy_from_user(&sioc32, (struct atmif_sioc32*)arg, - sizeof(struct atmif_sioc32)); - if (err) - return -EFAULT; - - sioc.number = sioc32.number; - sioc.length = sioc32.length; - - if (sioc32.arg == (compat_caddr_t) NULL || sioc32.length == 0) { - sioc.arg = (void*)(unsigned long)sioc32.arg; - } else { - sioc.arg = kmalloc(sioc.length, GFP_KERNEL); - if (sioc.arg == NULL) { - err = -ENOMEM; - goto out; - } - - err = copy_from_user(sioc.arg, A(sioc32.arg), sioc32.length); - if (err) { - err = -EFAULT; - goto out; - } - } - - old_fs = get_fs(); set_fs (KERNEL_DS); - err = sys_ioctl (fd, cmd, (unsigned long)&sioc); - set_fs (old_fs); - if(err) { - goto out; - } - - if(sioc.arg && sioc.length > 0) { - err = copy_to_user(A(sioc32.arg), sioc.arg, sioc.length); - if (err) { - err = -EFAULT; - goto out; - } - } - err = __put_user(sioc.length, &(((struct atmif_sioc32*)arg)->length)); - - out: - if(sioc32.arg && sioc32.length > 0) - kfree(sioc.arg); - - return err; -} - - -static int do_atm_ioctl(unsigned int fd, unsigned int cmd32, unsigned long arg) -{ - int i; - unsigned int cmd = 0; - - switch (cmd32) { - case SONET_GETSTAT: - case SONET_GETSTATZ: - case SONET_GETDIAG: - case SONET_SETDIAG: - case SONET_CLRDIAG: - case SONET_SETFRAMING: - case SONET_GETFRAMING: - case SONET_GETFRSENSE: - return do_atmif_sioc(fd, cmd32, arg); - } - - for (i = 0; i < NR_ATM_IOCTL; i++) { - if (cmd32 == atm_ioctl_map[i].cmd32) { - cmd = atm_ioctl_map[i].cmd; - break; - } - } - if (i == NR_ATM_IOCTL) { - return -EINVAL; - } - - switch (cmd) { - case ATM_GETNAMES: - return do_atm_iobuf(fd, cmd, arg); - - case ATM_GETLINKRATE: - case ATM_GETTYPE: - case ATM_GETESI: - case ATM_GETADDR: - case ATM_RSTADDR: - case ATM_ADDADDR: - case ATM_DELADDR: - case ATM_GETCIRANGE: - case ATM_SETCIRANGE: - case ATM_SETESI: - case ATM_SETESIF: - case ATM_GETSTAT: - case ATM_GETSTATZ: - case ATM_GETLOOP: - case ATM_SETLOOP: - case ATM_QUERYLOOP: - return do_atmif_sioc(fd, cmd, arg); - } - - return -EINVAL; -} - #if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE) /* This really belongs in include/linux/drm.h -DaveM */ #include "../../../drivers/char/drm/drm.h" @@ -3291,57 +1013,7 @@ #endif -static int ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - return -EINVAL; -} - -static int broken_blkgetsize(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - /* The mkswap binary hard codes it to Intel value :-((( */ - return w_long(fd, BLKGETSIZE, arg); -} - -struct blkpg_ioctl_arg32 { - int op; - int flags; - int datalen; - u32 data; -}; - -static int blkpg_ioctl_trans(unsigned int fd, unsigned int cmd, struct blkpg_ioctl_arg32 *arg) -{ - struct blkpg_ioctl_arg a; - struct blkpg_partition p; - int err; - mm_segment_t old_fs = get_fs(); - - err = get_user(a.op, &arg->op); - err |= __get_user(a.flags, &arg->flags); - err |= __get_user(a.datalen, &arg->datalen); - err |= __get_user((long)a.data, &arg->data); - if (err) return err; - switch (a.op) { - case BLKPG_ADD_PARTITION: - case BLKPG_DEL_PARTITION: - if (a.datalen < sizeof(struct blkpg_partition)) - return -EINVAL; - if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition))) - return -EFAULT; - a.data = &p; - set_fs (KERNEL_DS); - err = sys_ioctl(fd, cmd, (unsigned long)&a); - set_fs (old_fs); - default: - return -EINVAL; - } - return err; -} - -static int ioc_settimeout(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - return rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg); -} +/* HERE! */ struct usbdevfs_ctrltransfer32 { __u8 bRequestType; @@ -3737,91 +1409,6 @@ return err; } -struct mtd_oob_buf32 { - u32 start; - u32 length; - u32 ptr; /* unsigned char* */ -}; - -#define MEMWRITEOOB32 _IOWR('M',3,struct mtd_oob_buf32) -#define MEMREADOOB32 _IOWR('M',4,struct mtd_oob_buf32) - -static int mtd_rw_oob(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - struct mtd_oob_buf32 *uarg = (struct mtd_oob_buf32 *)arg; - struct mtd_oob_buf karg; - u32 tmp; - char __user *ptr; - int ret; - - if (get_user(karg.start, &uarg->start) || - get_user(karg.length, &uarg->length) || - get_user(tmp, &uarg->ptr)) - return -EFAULT; - - ptr = A(tmp); - if (0 >= karg.length) - return -EINVAL; - - karg.ptr = kmalloc(karg.length, GFP_KERNEL); - if (NULL == karg.ptr) - return -ENOMEM; - - if (copy_from_user(karg.ptr, ptr, karg.length)) { - kfree(karg.ptr); - return -EFAULT; - } - - set_fs(KERNEL_DS); - if (MEMREADOOB32 == cmd) - ret = sys_ioctl(fd, MEMREADOOB, (unsigned long)&karg); - else if (MEMWRITEOOB32 == cmd) - ret = sys_ioctl(fd, MEMWRITEOOB, (unsigned long)&karg); - else - ret = -EINVAL; - set_fs(old_fs); - - if (0 == ret && cmd == MEMREADOOB32) { - ret = copy_to_user(ptr, karg.ptr, karg.length); - ret |= put_user(karg.start, &uarg->start); - ret |= put_user(karg.length, &uarg->length); - } - - kfree(karg.ptr); - return ((0 == ret) ? 0 : -EFAULT); -} - -/* Fix sizeof(sizeof()) breakage */ -#define BLKBSZGET_32 _IOR(0x12,112,int) -#define BLKBSZSET_32 _IOW(0x12,113,int) -#define BLKGETSIZE64_32 _IOR(0x12,114,int) - -static int do_blkbszget(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - return sys_ioctl(fd, BLKBSZGET, arg); -} - -static int do_blkbszset(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - return sys_ioctl(fd, BLKBSZSET, arg); -} - -static int do_blkgetsize64(unsigned int fd, unsigned int cmd, - unsigned long arg) -{ - return sys_ioctl(fd, BLKGETSIZE64, arg); -} - -/* Bluetooth ioctls */ -#define HCIUARTSETPROTO _IOW('U', 200, int) -#define HCIUARTGETPROTO _IOR('U', 201, int) - -#define BNEPCONNADD _IOW('B', 200, int) -#define BNEPCONNDEL _IOW('B', 201, int) -#define BNEPGETCONNLIST _IOR('B', 210, int) -#define BNEPGETCONNINFO _IOR('B', 211, int) - typedef int (* ioctl32_handler_t)(unsigned int, unsigned int, unsigned long, struct file *); #define COMPATIBLE_IOCTL(cmd) HANDLE_IOCTL((cmd),sys_ioctl) @@ -3833,6 +1420,8 @@ IOCTL_TABLE_START #include <linux/compat_ioctl.h> +#define DECLARES +#include "compat_ioctl.c" COMPATIBLE_IOCTL(TCSBRKP) COMPATIBLE_IOCTL(TIOCSTART) COMPATIBLE_IOCTL(TIOCSTOP) @@ -3968,120 +1557,8 @@ COMPATIBLE_IOCTL(DM_DEV_STATUS) COMPATIBLE_IOCTL(DM_TARGET_STATUS) COMPATIBLE_IOCTL(DM_TARGET_WAIT) - /* And these ioctls need translation */ -HANDLE_IOCTL(MEMREADOOB32, mtd_rw_oob) -HANDLE_IOCTL(MEMWRITEOOB32, mtd_rw_oob) -#ifdef CONFIG_NET -HANDLE_IOCTL(SIOCGIFNAME, dev_ifname32) -#endif -HANDLE_IOCTL(SIOCGIFCONF, dev_ifconf) -HANDLE_IOCTL(SIOCGIFFLAGS, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFFLAGS, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFMETRIC, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFMETRIC, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFMTU, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFMTU, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFMEM, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFMEM, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFHWADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFHWADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCADDMULTI, dev_ifsioc) -HANDLE_IOCTL(SIOCDELMULTI, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFINDEX, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFMAP, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFMAP, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFBRDADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFBRDADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFDSTADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFDSTADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFNETMASK, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFNETMASK, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFPFLAGS, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFPFLAGS, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFTXQLEN, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFTXQLEN, dev_ifsioc) -HANDLE_IOCTL(SIOCETHTOOL, ethtool_ioctl) -HANDLE_IOCTL(SIOCBONDENSLAVE, bond_ioctl) -HANDLE_IOCTL(SIOCBONDRELEASE, bond_ioctl) -HANDLE_IOCTL(SIOCBONDSETHWADDR, bond_ioctl) -HANDLE_IOCTL(SIOCBONDSLAVEINFOQUERY, bond_ioctl) -HANDLE_IOCTL(SIOCBONDINFOQUERY, bond_ioctl) -HANDLE_IOCTL(SIOCBONDCHANGEACTIVE, bond_ioctl) -HANDLE_IOCTL(SIOCADDRT, routing_ioctl) -HANDLE_IOCTL(SIOCDELRT, routing_ioctl) -/* Note SIOCRTMSG is no longer, so this is safe and * the user would have seen just an -EINVAL anyways. */ -HANDLE_IOCTL(SIOCRTMSG, ret_einval) -HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp) -HANDLE_IOCTL(HDIO_GETGEO, hdio_getgeo) HANDLE_IOCTL(HDIO_GETGEO_BIG_RAW, hdio_getgeo_big) -HANDLE_IOCTL(BLKGETSIZE, w_long) -HANDLE_IOCTL(0x1260, broken_blkgetsize) -HANDLE_IOCTL(BLKSECTGET, w_long) -HANDLE_IOCTL(BLKPG, blkpg_ioctl_trans) -HANDLE_IOCTL(FBIOPUTCMAP32, fbiogetputcmap) -HANDLE_IOCTL(FBIOGETCMAP32, fbiogetputcmap) -HANDLE_IOCTL(FBIOSCURSOR32, fbiogscursor) -HANDLE_IOCTL(FBIOGET_FSCREENINFO, fb_ioctl_trans) -HANDLE_IOCTL(FBIOGETCMAP, fb_ioctl_trans) -HANDLE_IOCTL(FBIOPUTCMAP, fb_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_UNMASKINTR, hdio_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_DMA, hdio_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_32BIT, hdio_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_MULTCOUNT, hdio_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_NOWERR, hdio_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_NICE, hdio_ioctl_trans) -HANDLE_IOCTL(FDSETPRM32, fd_ioctl_trans) -HANDLE_IOCTL(FDDEFPRM32, fd_ioctl_trans) -HANDLE_IOCTL(FDGETPRM32, fd_ioctl_trans) -HANDLE_IOCTL(FDSETDRVPRM32, fd_ioctl_trans) -HANDLE_IOCTL(FDGETDRVPRM32, fd_ioctl_trans) -HANDLE_IOCTL(FDGETDRVSTAT32, fd_ioctl_trans) -HANDLE_IOCTL(FDPOLLDRVSTAT32, fd_ioctl_trans) -HANDLE_IOCTL(FDGETFDCSTAT32, fd_ioctl_trans) -HANDLE_IOCTL(FDWERRORGET32, fd_ioctl_trans) -HANDLE_IOCTL(SG_IO,sg_ioctl_trans) -HANDLE_IOCTL(PPPIOCGIDLE32, ppp_ioctl_trans) -HANDLE_IOCTL(PPPIOCSCOMPRESS32, ppp_ioctl_trans) -HANDLE_IOCTL(PPPIOCSPASS32, ppp_sock_fprog_ioctl_trans) -HANDLE_IOCTL(PPPIOCSACTIVE32, ppp_sock_fprog_ioctl_trans) -HANDLE_IOCTL(MTIOCGET32, mt_ioctl_trans) -HANDLE_IOCTL(MTIOCPOS32, mt_ioctl_trans) -HANDLE_IOCTL(MTIOCGETCONFIG32, mt_ioctl_trans) -HANDLE_IOCTL(MTIOCSETCONFIG32, mt_ioctl_trans) -HANDLE_IOCTL(CDROMREADMODE2, cdrom_ioctl_trans) -HANDLE_IOCTL(CDROMREADMODE1, cdrom_ioctl_trans) -HANDLE_IOCTL(CDROMREADRAW, cdrom_ioctl_trans) -HANDLE_IOCTL(CDROMREADCOOKED, cdrom_ioctl_trans) -HANDLE_IOCTL(CDROMREADAUDIO, cdrom_ioctl_trans) -HANDLE_IOCTL(CDROMREADALL, cdrom_ioctl_trans) -HANDLE_IOCTL(CDROM_SEND_PACKET, cdrom_ioctl_trans) -HANDLE_IOCTL(LOOP_SET_STATUS, loop_status) -HANDLE_IOCTL(LOOP_GET_STATUS, loop_status) -#define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int) -HANDLE_IOCTL(AUTOFS_IOC_SETTIMEOUT32, ioc_settimeout) -HANDLE_IOCTL(PIO_FONTX, do_fontx_ioctl) -HANDLE_IOCTL(GIO_FONTX, do_fontx_ioctl) -HANDLE_IOCTL(PIO_UNIMAP, do_unimap_ioctl) -HANDLE_IOCTL(GIO_UNIMAP, do_unimap_ioctl) -HANDLE_IOCTL(KDFONTOP, do_kdfontop_ioctl) -HANDLE_IOCTL(EXT2_IOC32_GETFLAGS, do_ext2_ioctl) -HANDLE_IOCTL(EXT2_IOC32_SETFLAGS, do_ext2_ioctl) -HANDLE_IOCTL(EXT2_IOC32_GETVERSION, do_ext2_ioctl) -HANDLE_IOCTL(EXT2_IOC32_SETVERSION, do_ext2_ioctl) -HANDLE_IOCTL(VIDIOCGTUNER32, do_video_ioctl) -HANDLE_IOCTL(VIDIOCSTUNER32, do_video_ioctl) -HANDLE_IOCTL(VIDIOCGWIN32, do_video_ioctl) -HANDLE_IOCTL(VIDIOCSWIN32, do_video_ioctl) -HANDLE_IOCTL(VIDIOCGFBUF32, do_video_ioctl) -HANDLE_IOCTL(VIDIOCSFBUF32, do_video_ioctl) -HANDLE_IOCTL(VIDIOCGFREQ32, do_video_ioctl) -HANDLE_IOCTL(VIDIOCSFREQ32, do_video_ioctl) -/* One SMB ioctl needs translations. */ -#define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, compat_uid_t) -HANDLE_IOCTL(SMB_IOC_GETMOUNTUID_32, do_smb_getmountuid) /* NCPFS */ HANDLE_IOCTL(NCP_IOC_NCPREQUEST_32, do_ncp_ncprequest) HANDLE_IOCTL(NCP_IOC_GETMOUNTUID2_32, do_ncp_getmountuid2) @@ -4090,31 +1567,10 @@ HANDLE_IOCTL(NCP_IOC_SETOBJECTNAME_32, do_ncp_setobjectname) HANDLE_IOCTL(NCP_IOC_GETPRIVATEDATA_32, do_ncp_getprivatedata) HANDLE_IOCTL(NCP_IOC_SETPRIVATEDATA_32, do_ncp_setprivatedata) -HANDLE_IOCTL(ATM_GETLINKRATE32, do_atm_ioctl) -HANDLE_IOCTL(ATM_GETNAMES32, do_atm_ioctl) -HANDLE_IOCTL(ATM_GETTYPE32, do_atm_ioctl) -HANDLE_IOCTL(ATM_GETESI32, do_atm_ioctl) -HANDLE_IOCTL(ATM_GETADDR32, do_atm_ioctl) -HANDLE_IOCTL(ATM_RSTADDR32, do_atm_ioctl) -HANDLE_IOCTL(ATM_ADDADDR32, do_atm_ioctl) -HANDLE_IOCTL(ATM_DELADDR32, do_atm_ioctl) -HANDLE_IOCTL(ATM_GETCIRANGE32, do_atm_ioctl) -HANDLE_IOCTL(ATM_SETCIRANGE32, do_atm_ioctl) -HANDLE_IOCTL(ATM_SETESI32, do_atm_ioctl) -HANDLE_IOCTL(ATM_SETESIF32, do_atm_ioctl) -HANDLE_IOCTL(ATM_GETSTAT32, do_atm_ioctl) -HANDLE_IOCTL(ATM_GETSTATZ32, do_atm_ioctl) -HANDLE_IOCTL(ATM_GETLOOP32, do_atm_ioctl) -HANDLE_IOCTL(ATM_SETLOOP32, do_atm_ioctl) -HANDLE_IOCTL(ATM_QUERYLOOP32, do_atm_ioctl) -HANDLE_IOCTL(SONET_GETSTAT, do_atm_ioctl) -HANDLE_IOCTL(SONET_GETSTATZ, do_atm_ioctl) -HANDLE_IOCTL(SONET_GETDIAG, do_atm_ioctl) -HANDLE_IOCTL(SONET_SETDIAG, do_atm_ioctl) -HANDLE_IOCTL(SONET_CLRDIAG, do_atm_ioctl) -HANDLE_IOCTL(SONET_SETFRAMING, do_atm_ioctl) -HANDLE_IOCTL(SONET_GETFRAMING, do_atm_ioctl) -HANDLE_IOCTL(SONET_GETFRSENSE, do_atm_ioctl) +/* Note SIOCRTMSG is no longer, so this is safe and * the user would have seen just an -EINVAL anyways. */ +HANDLE_IOCTL(FBIOPUTCMAP32, fbiogetputcmap) +HANDLE_IOCTL(FBIOGETCMAP32, fbiogetputcmap) +HANDLE_IOCTL(FBIOSCURSOR32, fbiogscursor) #if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE) HANDLE_IOCTL(DRM32_IOCTL_VERSION, drm32_version) HANDLE_IOCTL(DRM32_IOCTL_GET_UNIQUE, drm32_getsetunique) @@ -4139,8 +1595,4 @@ HANDLE_IOCTL(USBDEVFS_REAPURBNDELAY32, do_usbdevfs_reapurb) HANDLE_IOCTL(USBDEVFS_DISCSIGNAL32, do_usbdevfs_discsignal) /* take care of sizeof(sizeof()) breakage */ -/* block stuff */ -HANDLE_IOCTL(BLKBSZGET_32, do_blkbszget) -HANDLE_IOCTL(BLKBSZSET_32, do_blkbszset) -HANDLE_IOCTL(BLKGETSIZE64_32, do_blkgetsize64) IOCTL_TABLE_END diff -Nru a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c --- a/arch/sparc64/kernel/sparc64_ksyms.c Mon Jun 9 23:16:17 2003 +++ b/arch/sparc64/kernel/sparc64_ksyms.c Mon Jun 9 23:16:17 2003 @@ -94,8 +94,6 @@ extern int compat_sys_ioctl(unsigned int fd, unsigned int cmd, u32 arg); extern int (*handle_mathemu)(struct pt_regs *, struct fpustate *); extern long sparc32_open(const char * filename, int flags, int mode); -extern int register_ioctl32_conversion(unsigned int cmd, int (*handler)(unsigned int, unsigned int, unsigned long, struct file *)); -extern int unregister_ioctl32_conversion(unsigned int cmd); extern int io_remap_page_range(struct vm_area_struct *vma, unsigned long from, unsigned long offset, unsigned long size, pgprot_t prot, int space); extern int __ashrdi3(int, int); @@ -233,10 +231,6 @@ EXPORT_SYMBOL(pci_dma_sync_sg); EXPORT_SYMBOL(pci_dma_supported); #endif - -/* IOCTL32 emulation hooks. */ -EXPORT_SYMBOL(register_ioctl32_conversion); -EXPORT_SYMBOL(unregister_ioctl32_conversion); /* I/O device mmaping on Sparc64. */ EXPORT_SYMBOL(io_remap_page_range); diff -Nru a/arch/sparc64/kernel/sys_sparc.c b/arch/sparc64/kernel/sys_sparc.c --- a/arch/sparc64/kernel/sys_sparc.c Mon Jun 9 23:16:13 2003 +++ b/arch/sparc64/kernel/sys_sparc.c Mon Jun 9 23:16:13 2003 @@ -223,9 +223,15 @@ } if (call <= SHMCTL) switch (call) { - case SHMAT: - err = sys_shmat (first, (char *) ptr, second, (ulong *) third); + case SHMAT: { + ulong raddr; + err = sys_shmat (first, (char *) ptr, second, &raddr); + if (!err) { + if (put_user(raddr, (ulong __user *) third)) + err = -EFAULT; + } goto out; + } case SHMDT: err = sys_shmdt ((char *)ptr); goto out; @@ -440,12 +446,6 @@ done: up_read(&uts_sem); return err; -} - -/* only AP+ systems have sys_aplib */ -asmlinkage int sys_aplib(void) -{ - return -ENOSYS; } asmlinkage int solaris_syscall(struct pt_regs *regs) diff -Nru a/arch/sparc64/kernel/systbls.S b/arch/sparc64/kernel/systbls.S --- a/arch/sparc64/kernel/systbls.S Mon Jun 9 23:16:10 2003 +++ b/arch/sparc64/kernel/systbls.S Mon Jun 9 23:16:10 2003 @@ -70,7 +70,7 @@ /*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler .word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys32_sched_rr_get_interval, compat_sys_nanosleep /*250*/ .word sys32_mremap, sys32_sysctl, sys_getsid, sys_fdatasync, sys32_nfsservctl - .word sys_aplib + .word sys_ni_syscall /* Now the 64-bit native Linux syscall table. */ @@ -132,7 +132,7 @@ /*240*/ .word sys_munlockall, sys_sched_setparam, sys_sched_getparam, sys_sched_setscheduler, sys_sched_getscheduler .word sys_sched_yield, sys_sched_get_priority_max, sys_sched_get_priority_min, sys_sched_rr_get_interval, sys_nanosleep /*250*/ .word sys64_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl - .word sys_aplib + .word sys_ni_syscall #if defined(CONFIG_SUNOS_EMUL) || defined(CONFIG_SOLARIS_EMUL) || \ defined(CONFIG_SOLARIS_EMUL_MODULE) @@ -227,6 +227,6 @@ .word sunos_nosys, sunos_nosys, sunos_nosys .word sunos_nosys, sunos_nosys /*250*/ .word sunos_nosys, sunos_nosys, sunos_nosys - .word sunos_nosys, sunos_nosys, sys_aplib + .word sunos_nosys, sunos_nosys, sys_ni_syscall #endif diff -Nru a/arch/sparc64/lib/Makefile b/arch/sparc64/lib/Makefile --- a/arch/sparc64/lib/Makefile Mon Jun 9 23:16:06 2003 +++ b/arch/sparc64/lib/Makefile Mon Jun 9 23:16:06 2003 @@ -5,8 +5,7 @@ EXTRA_AFLAGS := -ansi EXTRA_CFLAGS := -Werror -L_TARGET = lib.a -obj-y := PeeCeeI.o blockops.o debuglocks.o strlen.o strncmp.o \ +lib-y := PeeCeeI.o blockops.o debuglocks.o strlen.o strncmp.o \ memscan.o strncpy_from_user.o strlen_user.o memcmp.o checksum.o \ VIScopy.o VISbzero.o VISmemset.o VIScsum.o VIScsumcopy.o \ VIScsumcopyusr.o VISsave.o atomic.o rwlock.o bitops.o \ diff -Nru a/arch/sparc64/prom/Makefile b/arch/sparc64/prom/Makefile --- a/arch/sparc64/prom/Makefile Mon Jun 9 23:16:17 2003 +++ b/arch/sparc64/prom/Makefile Mon Jun 9 23:16:17 2003 @@ -6,6 +6,5 @@ EXTRA_AFLAGS := -ansi EXTRA_CFLAGS := -Werror -L_TARGET = lib.a -obj-y := bootstr.o devops.o init.o memory.o misc.o \ +lib-y := bootstr.o devops.o init.o memory.o misc.o \ tree.o console.o printf.o p1275.o map.o diff -Nru a/arch/sparc64/prom/console.c b/arch/sparc64/prom/console.c --- a/arch/sparc64/prom/console.c Mon Jun 9 23:16:19 2003 +++ b/arch/sparc64/prom/console.c Mon Jun 9 23:16:19 2003 @@ -76,7 +76,7 @@ /* Query for input device type */ enum prom_input_device -prom_query_input_device() +prom_query_input_device(void) { int st_p; char propb[64]; @@ -111,7 +111,7 @@ /* Query for output device type */ enum prom_output_device -prom_query_output_device() +prom_query_output_device(void) { int st_p; char propb[64]; diff -Nru a/arch/sparc64/solaris/timod.c b/arch/sparc64/solaris/timod.c --- a/arch/sparc64/solaris/timod.c Mon Jun 9 23:16:10 2003 +++ b/arch/sparc64/solaris/timod.c Mon Jun 9 23:16:10 2003 @@ -149,10 +149,10 @@ SOLD("wakeing socket"); sock = SOCKET_I(current->files->fd[fd]->f_dentry->d_inode); wake_up_interruptible(&sock->wait); - read_lock(&sock->sk->callback_lock); + read_lock(&sock->sk->sk_callback_lock); if (sock->fasync_list && !test_bit(SOCK_ASYNC_WAITDATA, &sock->flags)) __kill_fasync(sock->fasync_list, SIGIO, POLL_IN); - read_unlock(&sock->sk->callback_lock); + read_unlock(&sock->sk->sk_callback_lock); SOLD("done"); } diff -Nru a/arch/um/drivers/daemon_kern.c b/arch/um/drivers/daemon_kern.c --- a/arch/um/drivers/daemon_kern.c Mon Jun 9 23:16:05 2003 +++ b/arch/um/drivers/daemon_kern.c Mon Jun 9 23:16:05 2003 @@ -24,18 +24,13 @@ struct daemon_data *dpri; struct daemon_init *init = data; - init_etherdev(dev, 0); pri = dev->priv; dpri = (struct daemon_data *) pri->user; - *dpri = ((struct daemon_data) - { .sock_type = init->sock_type, - .ctl_sock = init->ctl_sock, - .ctl_addr = NULL, - .data_addr = NULL, - .local_addr = NULL, - .fd = -1, - .control = -1, - .dev = dev }); + dpri->sock_type = init->sock_type; + dpri->ctl_sock = init->ctl_sock; + dpri->fd = -1; + dpri->control = -1; + dpri->dev = dev; printk("daemon backend (uml_switch version %d) - %s:%s", SWITCH_VERSION, dpri->sock_type, dpri->ctl_sock); diff -Nru a/arch/um/drivers/mcast_kern.c b/arch/um/drivers/mcast_kern.c --- a/arch/um/drivers/mcast_kern.c Mon Jun 9 23:16:05 2003 +++ b/arch/um/drivers/mcast_kern.c Mon Jun 9 23:16:05 2003 @@ -32,15 +32,13 @@ struct mcast_data *dpri; struct mcast_init *init = data; - init_etherdev(dev, 0); pri = dev->priv; dpri = (struct mcast_data *) pri->user; - *dpri = ((struct mcast_data) - { .addr = init->addr, - .port = init->port, - .ttl = init->ttl, - .mcast_addr = NULL, - .dev = dev }); + dpri->addr = init->addr; + dpri->port = init->port; + dpri->ttl = init->ttl; + dpri->dev = dev; + printk("mcast backend "); printk("multicast adddress: %s:%u, TTL:%u ", dpri->addr, dpri->port, dpri->ttl); diff -Nru a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c --- a/arch/um/drivers/net_kern.c Mon Jun 9 23:16:11 2003 +++ b/arch/um/drivers/net_kern.c Mon Jun 9 23:16:11 2003 @@ -292,45 +292,46 @@ struct uml_net *device; struct net_device *dev; struct uml_net_private *lp; - int save, err, size; + int err, size; size = transport->private_size + sizeof(struct uml_net_private) + sizeof(((struct uml_net_private *) 0)->user); device = kmalloc(sizeof(*device), GFP_KERNEL); - if(device == NULL){ + if (device == NULL) { printk(KERN_ERR "eth_configure failed to allocate uml_net\n"); return(1); } - *device = ((struct uml_net) { .list = LIST_HEAD_INIT(device->list), - .dev = NULL, - .index = n, - .mac = { [ 0 ... 5 ] = 0 }, - .have_mac = 0 }); + memset(device, 0, sizeof(*device)); + INIT_LIST_HEAD(&device->list); + device->index = n; spin_lock(&devices_lock); list_add(&device->list, &devices); spin_unlock(&devices_lock); - if(setup_etheraddr(mac, device->mac)) + if (setup_etheraddr(mac, device->mac)) device->have_mac = 1; printk(KERN_INFO "Netdevice %d ", n); - if(device->have_mac) printk("(%02x:%02x:%02x:%02x:%02x:%02x) ", - device->mac[0], device->mac[1], - device->mac[2], device->mac[3], - device->mac[4], device->mac[5]); + if (device->have_mac) + printk("(%02x:%02x:%02x:%02x:%02x:%02x) ", + device->mac[0], device->mac[1], + device->mac[2], device->mac[3], + device->mac[4], device->mac[5]); printk(": "); - dev = kmalloc(sizeof(*dev) + size, GFP_KERNEL); - if(dev == NULL){ + dev = alloc_etherdev(size); + if (dev == NULL) { printk(KERN_ERR "eth_configure: failed to allocate device\n"); - return(1); + return 1; } - memset(dev, 0, sizeof(*dev) + size); + /* If this name ends up conflicting with an existing registered + * netdevice, that is OK, register_netdev{,ice}() will notice this + * and fail. + */ snprintf(dev->name, sizeof(dev->name), "eth%d", n); - dev->priv = (void *) &dev[1]; device->dev = dev; dev->hard_header = uml_net_hard_header; @@ -357,42 +358,35 @@ rtnl_lock(); err = register_netdevice(dev); rtnl_unlock(); - if(err) - return(1); + if (err) + return 1; lp = dev->priv; - /* lp.user is the first four bytes of the transport data, which - * has already been initialized. This structure assignment will - * overwrite that, so we make sure that .user gets overwritten with - * what it already has. - */ - save = lp->user[0]; - *lp = ((struct uml_net_private) - { .list = LIST_HEAD_INIT(lp->list), - .lock = SPIN_LOCK_UNLOCKED, - .dev = dev, - .fd = -1, - .mac = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0}, - .have_mac = device->have_mac, - .protocol = transport->kern->protocol, - .open = transport->user->open, - .close = transport->user->close, - .remove = transport->user->remove, - .read = transport->kern->read, - .write = transport->kern->write, - .add_address = transport->user->add_address, - .delete_address = transport->user->delete_address, - .set_mtu = transport->user->set_mtu, - .user = { save } }); + INIT_LIST_HEAD(&lp->list); + spin_lock_init(&lp->lock); + lp->dev = dev; + lp->fd = -1; + lp->mac = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0 }; + lp->have_mac = device->have_mac; + lp->protocol = transport->kern->protocol; + lp->open = transport->user->open; + lp->close = transport->user->close; + lp->remove = transport->user->remove; + lp->read = transport->kern->read; + lp->write = transport->kern->write; + lp->add_address = transport->user->add_address; + lp->delete_address = transport->user->delete_address; + lp->set_mtu = transport->user->set_mtu; + init_timer(&lp->tl); lp->tl.function = uml_net_user_timer_expire; - memset(&lp->stats, 0, sizeof(lp->stats)); - if(lp->have_mac) memcpy(lp->mac, device->mac, sizeof(lp->mac)); + if (lp->have_mac) + memcpy(lp->mac, device->mac, sizeof(lp->mac)); - if(transport->user->init) + if (transport->user->init) (*transport->user->init)(&lp->user, dev); - if(device->have_mac) + if (device->have_mac) set_ether_mac(dev, device->mac); return(0); } @@ -538,13 +532,15 @@ if(err) return(1); new = alloc_bootmem(sizeof(new)); - if(new == NULL){ + if (new == NULL){ printk("eth_init : alloc_bootmem failed\n"); return(1); } - *new = ((struct eth_init) { .list = LIST_HEAD_INIT(new->list), - .index = n, - .init = str }); + + INIT_LIST_HEAD(&new->list); + new->index = n; + new->init = str; + list_add_tail(&new->list, ð_cmd_line); return(1); } diff -Nru a/arch/um/drivers/pcap_kern.c b/arch/um/drivers/pcap_kern.c --- a/arch/um/drivers/pcap_kern.c Mon Jun 9 23:16:19 2003 +++ b/arch/um/drivers/pcap_kern.c Mon Jun 9 23:16:19 2003 @@ -23,16 +23,12 @@ struct pcap_data *ppri; struct pcap_init *init = data; - init_etherdev(dev, 0); pri = dev->priv; ppri = (struct pcap_data *) pri->user; - *ppri = ((struct pcap_data) - { .host_if = init->host_if, - .promisc = init->promisc, - .optimize = init->optimize, - .filter = init->filter, - .compiled = NULL, - .pcap = NULL }); + ppri->host_if = init->host_if; + ppri->promisc = init->promisc; + ppri->optimize = init->optimize; + ppri->filter = init->filter; } static int pcap_read(int fd, struct sk_buff **skb, diff -Nru a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c --- a/arch/um/kernel/irq.c Mon Jun 9 23:16:17 2003 +++ b/arch/um/kernel/irq.c Mon Jun 9 23:16:17 2003 @@ -31,8 +31,12 @@ static void register_irq_proc (unsigned int irq); -irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = - { [0 ... NR_IRQS-1] = { 0, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}}; +irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { + [0 ... NR_IRQS-1] = { + .handler = &no_irq_type, + .lock = SPIN_LOCK_UNLOCKED + } +}; /* * Generic no controller code diff -Nru a/arch/um/os-Linux/drivers/ethertap_kern.c b/arch/um/os-Linux/drivers/ethertap_kern.c --- a/arch/um/os-Linux/drivers/ethertap_kern.c Mon Jun 9 23:16:06 2003 +++ b/arch/um/os-Linux/drivers/ethertap_kern.c Mon Jun 9 23:16:06 2003 @@ -24,18 +24,16 @@ struct ethertap_data *epri; struct ethertap_init *init = data; - init_etherdev(dev, 0); pri = dev->priv; epri = (struct ethertap_data *) pri->user; - *epri = ((struct ethertap_data) - { .dev_name = init->dev_name, - .gate_addr = init->gate_addr, - .data_fd = -1, - .control_fd = -1, - .dev = dev }); + epri->dev_name = init->dev_name; + epri->gate_addr = init->gate_addr; + epri->data_fd = -1; + epri->control_fd = -1; + epri->dev = dev; printk("ethertap backend - %s", epri->dev_name); - if(epri->gate_addr != NULL) + if (epri->gate_addr != NULL) printk(", IP = %s", epri->gate_addr); printk("\n"); } diff -Nru a/arch/um/os-Linux/drivers/tuntap_kern.c b/arch/um/os-Linux/drivers/tuntap_kern.c --- a/arch/um/os-Linux/drivers/tuntap_kern.c Mon Jun 9 23:16:14 2003 +++ b/arch/um/os-Linux/drivers/tuntap_kern.c Mon Jun 9 23:16:14 2003 @@ -24,17 +24,16 @@ struct tuntap_data *tpri; struct tuntap_init *init = data; - init_etherdev(dev, 0); pri = dev->priv; tpri = (struct tuntap_data *) pri->user; - *tpri = ((struct tuntap_data) - { .dev_name = init->dev_name, - .fixed_config = (init->dev_name != NULL), - .gate_addr = init->gate_addr, - .fd = -1, - .dev = dev }); + tpri->dev_name = init->dev_name; + tpri->fixed_config = (init->dev_name != NULL); + tpri->gate_addr = init->gate_addr; + tpri->fd = -1; + tpri->dev = dev; + printk("TUN/TAP backend - "); - if(tpri->gate_addr != NULL) + if (tpri->gate_addr != NULL) printk("IP = %s", tpri->gate_addr); printk("\n"); } diff -Nru a/arch/um/sys-ppc/Makefile b/arch/um/sys-ppc/Makefile --- a/arch/um/sys-ppc/Makefile Mon Jun 9 23:16:12 2003 +++ b/arch/um/sys-ppc/Makefile Mon Jun 9 23:16:12 2003 @@ -6,7 +6,7 @@ OBJS = ptrace.o sigcontext.o semaphore.o checksum.o miscthings.o misc.o \ ptrace_user.o sysrq.o -EXTRA_AFLAGS := -DCONFIG_ALL_PPC -I. -I$(TOPDIR)/arch/ppc/kernel +EXTRA_AFLAGS := -DCONFIG_PPC32 -I. -I$(TOPDIR)/arch/ppc/kernel all: $(OBJ) diff -Nru a/arch/v850/Kconfig b/arch/v850/Kconfig --- a/arch/v850/Kconfig Mon Jun 9 23:16:11 2003 +++ b/arch/v850/Kconfig Mon Jun 9 23:16:11 2003 @@ -230,7 +230,7 @@ source "drivers/pcmcia/Kconfig" -source "drivers/hotplug/Kconfig" +source "drivers/pci/hotplug/Kconfig" endmenu diff -Nru a/arch/v850/as85ep1-rom.ld b/arch/v850/as85ep1-rom.ld --- a/arch/v850/as85ep1-rom.ld Mon Jun 9 23:16:10 2003 +++ b/arch/v850/as85ep1-rom.ld Mon Jun 9 23:16:10 2003 @@ -1,9 +1,6 @@ /* Linker script for the NEC AS85EP1 V850E evaluation board (CONFIG_V850E_AS85EP1), with kernel in ROM (CONFIG_ROM_KERNEL). */ -/* Note, all symbols are prefixed with an extra `_' for compatibility with - the existing linux sources. */ - MEMORY { /* 4MB of flash ROM. */ ROM : ORIGIN = 0, LENGTH = 0x00400000 @@ -12,7 +9,7 @@ SRAM : ORIGIN = 0x00400000, LENGTH = 0x00100000 /* About 58MB of DRAM. This can actually be at one of two - positions, determined by jump JP3; we have to use the first + positions, determined by jumper JP3; we have to use the first position because the second is partially out of processor instruction addressing range (though in the second position there's actually 64MB available). */ diff -Nru a/arch/v850/kernel/entry.S b/arch/v850/kernel/entry.S --- a/arch/v850/kernel/entry.S Mon Jun 9 23:16:18 2003 +++ b/arch/v850/kernel/entry.S Mon Jun 9 23:16:18 2003 @@ -29,28 +29,28 @@ #define CSYM C_SYMBOL_NAME -/* The offset of the struct pt_regs in a `state save frame' on the stack. */ +/* The offset of the struct pt_regs in a state-save-frame on the stack. */ #define PTO STATE_SAVE_PT_OFFSET -/* Save argument registers to the struct pt_regs pointed to by EP. */ +/* Save argument registers to the state-save-frame pointed to by EP. */ #define SAVE_ARG_REGS \ sst.w r6, PTO+PT_GPR(6)[ep]; \ sst.w r7, PTO+PT_GPR(7)[ep]; \ sst.w r8, PTO+PT_GPR(8)[ep]; \ sst.w r9, PTO+PT_GPR(9)[ep] -/* Restore argument registers from the struct pt_regs pointed to by EP. */ +/* Restore argument registers from the state-save-frame pointed to by EP. */ #define RESTORE_ARG_REGS \ sld.w PTO+PT_GPR(6)[ep], r6; \ sld.w PTO+PT_GPR(7)[ep], r7; \ sld.w PTO+PT_GPR(8)[ep], r8; \ sld.w PTO+PT_GPR(9)[ep], r9 -/* Save value return registers to the struct pt_regs pointed to by EP. */ +/* Save value return registers to the state-save-frame pointed to by EP. */ #define SAVE_RVAL_REGS \ sst.w r10, PTO+PT_GPR(10)[ep]; \ sst.w r11, PTO+PT_GPR(11)[ep] -/* Restore value return registers from the struct pt_regs pointed to by EP. */ +/* Restore value return registers from the state-save-frame pointed to by EP. */ #define RESTORE_RVAL_REGS \ sld.w PTO+PT_GPR(10)[ep], r10; \ sld.w PTO+PT_GPR(11)[ep], r11 @@ -81,13 +81,13 @@ sld.w PTO+PT_GPR(18)[ep], r18; \ sld.w PTO+PT_GPR(19)[ep], r19 -/* Save `call clobbered' registers to the struct pt_regs pointed to by EP. */ +/* Save `call clobbered' registers to the state-save-frame pointed to by EP. */ #define SAVE_CALL_CLOBBERED_REGS \ SAVE_CALL_CLOBBERED_REGS_BEFORE_ARGS; \ SAVE_ARG_REGS; \ SAVE_RVAL_REGS; \ SAVE_CALL_CLOBBERED_REGS_AFTER_RVAL -/* Restore `call clobbered' registers from the struct pt_regs pointed to +/* Restore `call clobbered' registers from the state-save-frame pointed to by EP. */ #define RESTORE_CALL_CLOBBERED_REGS \ RESTORE_CALL_CLOBBERED_REGS_BEFORE_ARGS; \ @@ -96,19 +96,19 @@ RESTORE_CALL_CLOBBERED_REGS_AFTER_RVAL /* Save `call clobbered' registers except for the return-value registers - to the struct pt_regs pointed to by EP. */ + to the state-save-frame pointed to by EP. */ #define SAVE_CALL_CLOBBERED_REGS_NO_RVAL \ SAVE_CALL_CLOBBERED_REGS_BEFORE_ARGS; \ SAVE_ARG_REGS; \ SAVE_CALL_CLOBBERED_REGS_AFTER_RVAL /* Restore `call clobbered' registers except for the return-value registers - from the struct pt_regs pointed to by EP. */ + from the state-save-frame pointed to by EP. */ #define RESTORE_CALL_CLOBBERED_REGS_NO_RVAL \ RESTORE_CALL_CLOBBERED_REGS_BEFORE_ARGS; \ RESTORE_ARG_REGS; \ RESTORE_CALL_CLOBBERED_REGS_AFTER_RVAL -/* Save `call saved' registers to the struct pt_regs pointed to by EP. */ +/* Save `call saved' registers to the state-save-frame pointed to by EP. */ #define SAVE_CALL_SAVED_REGS \ sst.w r2, PTO+PT_GPR(2)[ep]; \ sst.w r20, PTO+PT_GPR(20)[ep]; \ @@ -121,7 +121,7 @@ sst.w r27, PTO+PT_GPR(27)[ep]; \ sst.w r28, PTO+PT_GPR(28)[ep]; \ sst.w r29, PTO+PT_GPR(29)[ep] -/* Restore `call saved' registers from the struct pt_regs pointed to by EP. */ +/* Restore `call saved' registers from the state-save-frame pointed to by EP. */ #define RESTORE_CALL_SAVED_REGS \ sld.w PTO+PT_GPR(2)[ep], r2; \ sld.w PTO+PT_GPR(20)[ep], r20; \ @@ -136,12 +136,12 @@ sld.w PTO+PT_GPR(29)[ep], r29 -/* Save the PC stored in the special register SAVEREG to the struct pt_regs +/* Save the PC stored in the special register SAVEREG to the state-save-frame pointed to by EP. r19 is clobbered. */ #define SAVE_PC(savereg) \ stsr SR_ ## savereg, r19; \ sst.w r19, PTO+PT_PC[ep] -/* Restore the PC from the struct pt_regs pointed to by EP, to the special +/* Restore the PC from the state-save-frame pointed to by EP, to the special register SAVEREG. LP is clobbered (it is used as a scratch register because the POP_STATE macro restores it, and this macro is usually used inside POP_STATE). */ @@ -149,11 +149,11 @@ sld.w PTO+PT_PC[ep], lp; \ ldsr lp, SR_ ## savereg /* Save the PSW register stored in the special register SAVREG to the - struct pt_regs pointed to by EP r19 is clobbered. */ + state-save-frame pointed to by EP. r19 is clobbered. */ #define SAVE_PSW(savereg) \ stsr SR_ ## savereg, r19; \ sst.w r19, PTO+PT_PSW[ep] -/* Restore the PSW register from the struct pt_regs pointed to by EP, to +/* Restore the PSW register from the state-save-frame pointed to by EP, to the special register SAVEREG. LP is clobbered (it is used as a scratch register because the POP_STATE macro restores it, and this macro is usually used inside POP_STATE). */ @@ -161,7 +161,7 @@ sld.w PTO+PT_PSW[ep], lp; \ ldsr lp, SR_ ## savereg -/* Save CTPC/CTPSW/CTBP registers to the struct pt_regs pointed to by REG. +/* Save CTPC/CTPSW/CTBP registers to the state-save-frame pointed to by REG. r19 is clobbered. */ #define SAVE_CT_REGS \ stsr SR_CTPC, r19; \ @@ -170,7 +170,7 @@ sst.w r19, PTO+PT_CTPSW[ep]; \ stsr SR_CTBP, r19; \ sst.w r19, PTO+PT_CTBP[ep] -/* Restore CTPC/CTPSW/CTBP registers from the struct pt_regs pointed to by EP. +/* Restore CTPC/CTPSW/CTBP registers from the state-save-frame pointed to by EP. LP is clobbered (it is used as a scratch register because the POP_STATE macro restores it, and this macro is usually used inside POP_STATE). */ #define RESTORE_CT_REGS \ @@ -182,10 +182,11 @@ ldsr lp, SR_CTBP -/* Push register state, except for the stack pointer, on the stack in the form - of a struct pt_regs, in preparation for a system call. This macro makes - sure that `special' registers, system registers; TYPE identifies the set of - extra registers to be saved as well. EP is clobbered. */ +/* Push register state, except for the stack pointer, on the stack in the + form of a state-save-frame (plus some extra padding), in preparation for + a system call. This macro makes sure that the EP, GP, and LP + registers are saved, and TYPE identifies the set of extra registers to + be saved as well. Also copies (the new value of) SP to EP. */ #define PUSH_STATE(type) \ addi -STATE_SAVE_SIZE, sp, sp; /* Make room on the stack. */ \ st.w ep, PTO+PT_GPR(GPR_EP)[sp]; \ @@ -193,8 +194,8 @@ sst.w gp, PTO+PT_GPR(GPR_GP)[ep]; \ sst.w lp, PTO+PT_GPR(GPR_LP)[ep]; \ type ## _STATE_SAVER -/* Pop a register state, except for the stack pointer, from the struct pt_regs - on the stack. */ +/* Pop a register state pushed by PUSH_STATE, except for the stack pointer, + from the the stack. */ #define POP_STATE(type) \ mov sp, ep; \ type ## _STATE_RESTORER; \ @@ -205,7 +206,7 @@ /* Switch to the kernel stack if necessary, and push register state on the - stack in the form of a struct pt_regs. Also load the current task + stack in the form of a state-save-frame. Also load the current task pointer if switching from user mode. The stack-pointer (r3) should have already been saved to the memory location SP_SAVE_LOC (the reason for this is that the interrupt vectors may be beyond a 22-bit signed offset @@ -234,25 +235,30 @@ sst.w syscall_num, PTO+PT_CUR_SYSCALL[ep] -/* Save register state not normally saved by PUSH_STATE for TYPE. */ +/* Save register state not normally saved by PUSH_STATE for TYPE, to the + state-save-frame on the stack; also copies SP to EP. r19 may be trashed. */ #define SAVE_EXTRA_STATE(type) \ - mov sp, ep; \ + mov sp, ep; \ type ## _EXTRA_STATE_SAVER -/* Restore register state not normally restored by POP_STATE for TYPE. */ +/* Restore register state not normally restored by POP_STATE for TYPE, + from the state-save-frame on the stack; also copies SP to EP. + r19 may be trashed. */ #define RESTORE_EXTRA_STATE(type) \ - mov sp, ep; \ + mov sp, ep; \ type ## _EXTRA_STATE_RESTORER -/* Save any call-clobbered registers not normally saved by PUSH_STATE - for TYPE. */ -#define SAVE_EXTRA_STATE_FOR_FUNCALL(type) \ - mov sp, ep; \ - type ## _FUNCALL_EXTRA_STATE_SAVER -/* Restore any call-clobbered registers not normally restored by POP_STATE for - TYPE. */ -#define RESTORE_EXTRA_STATE_FOR_FUNCALL(type) \ - mov sp, ep; \ - type ## _FUNCALL_EXTRA_STATE_RESTORER +/* Save any call-clobbered registers not normally saved by PUSH_STATE for + TYPE, to the state-save-frame on the stack. + EP may be trashed, but is not guaranteed to contain a copy of SP + (unlike after most SAVE_... macros). r19 may be trashed. */ +#define SAVE_EXTRA_STATE_FOR_SCHEDULE(type) \ + type ## _SCHEDULE_EXTRA_STATE_SAVER +/* Restore any call-clobbered registers not normally restored by + POP_STATE for TYPE, to the state-save-frame on the stack. + EP may be trashed, but is not guaranteed to contain a copy of SP + (unlike after most RESTORE_... macros). r19 may be trashed. */ +#define RESTORE_EXTRA_STATE_FOR_SCHEDULE(type) \ + type ## _SCHEDULE_EXTRA_STATE_RESTORER /* These are extra_state_saver/restorer values for a user trap. Note @@ -263,36 +269,48 @@ caller of the syscall function should have saved them. */ #define TRAP_RET reti -/* Traps don't save call-clobbered registers (but do still save arg regs). */ +/* Traps don't save call-clobbered registers (but do still save arg regs). + We preserve PSw to keep long-term state, namely interrupt status (for traps + from kernel-mode), and the single-step flag (for user traps). */ #define TRAP_STATE_SAVER \ SAVE_ARG_REGS; \ - SAVE_PC(EIPC) + SAVE_PC(EIPC); \ + SAVE_PSW(EIPSW) /* When traps return, they just leave call-clobbered registers (except for arg - regs) with whatever value they have from the kernel. */ + regs) with whatever value they have from the kernel. Traps don't preserve + the PSW, but we zero EIPSW to ensure it doesn't contain anything dangerous + (in particular, the single-step flag). */ #define TRAP_STATE_RESTORER \ RESTORE_ARG_REGS; \ - RESTORE_PC(EIPC) + RESTORE_PC(EIPC); \ + RESTORE_PSW(EIPSW) /* Save registers not normally saved by traps. We need to save r12, even though it's nominally call-clobbered, because it's used when restarting a system call (the signal-handling path uses SAVE_EXTRA_STATE, and - expects r12 to be restored when the trap returns). Similarly, we must - save the PSW, so that it's at least in a known state in the the pt_regs - structure. */ + expects r12 to be restored when the trap returns). */ #define TRAP_EXTRA_STATE_SAVER \ SAVE_RVAL_REGS; \ sst.w r12, PTO+PT_GPR(12)[ep]; \ SAVE_CALL_SAVED_REGS; \ - SAVE_PSW(EIPSW); \ SAVE_CT_REGS #define TRAP_EXTRA_STATE_RESTORER \ RESTORE_RVAL_REGS; \ sld.w PTO+PT_GPR(12)[ep], r12; \ RESTORE_CALL_SAVED_REGS; \ - RESTORE_PSW(EIPSW); \ RESTORE_CT_REGS -#define TRAP_FUNCALL_EXTRA_STATE_SAVER \ +/* Save registers prior to calling scheduler (just before trap returns). + We have to save the return-value registers to preserve the trap's return + value. Note that ..._SCHEDULE_EXTRA_STATE_SAVER, unlike most ..._SAVER + macros, is required to setup EP itself if EP is needed (this is because + in many cases, the macro is empty). */ +#define TRAP_SCHEDULE_EXTRA_STATE_SAVER \ + mov sp, ep; \ SAVE_RVAL_REGS -#define TRAP_FUNCALL_EXTRA_STATE_RESTORER \ +/* Note that ..._SCHEDULE_EXTRA_STATE_RESTORER, unlike most ..._RESTORER + macros, is required to setup EP itself if EP is needed (this is because + in many cases, the macro is empty). */ +#define TRAP_SCHEDULE_EXTRA_STATE_RESTORER \ + mov sp, ep; \ RESTORE_RVAL_REGS /* Register saving/restoring for maskable interrupts. */ @@ -311,8 +329,8 @@ #define IRQ_EXTRA_STATE_RESTORER \ RESTORE_CALL_SAVED_REGS; \ RESTORE_CT_REGS -#define IRQ_FUNCALL_EXTRA_STATE_SAVER /* nothing */ -#define IRQ_FUNCALL_EXTRA_STATE_RESTORER /* nothing */ +#define IRQ_SCHEDULE_EXTRA_STATE_SAVER /* nothing */ +#define IRQ_SCHEDULE_EXTRA_STATE_RESTORER /* nothing */ /* Register saving/restoring for non-maskable interrupts. */ #define NMI_RET reti @@ -330,8 +348,8 @@ #define NMI_EXTRA_STATE_RESTORER \ RESTORE_CALL_SAVED_REGS; \ RESTORE_CT_REGS -#define NMI_FUNCALL_EXTRA_STATE_SAVER /* nothing */ -#define NMI_FUNCALL_EXTRA_STATE_RESTORER /* nothing */ +#define NMI_SCHEDULE_EXTRA_STATE_SAVER /* nothing */ +#define NMI_SCHEDULE_EXTRA_STATE_RESTORER /* nothing */ /* Register saving/restoring for debug traps. */ #define DBTRAP_RET .long 0x014607E0 /* `dbret', but gas doesn't support it. */ @@ -349,8 +367,8 @@ #define DBTRAP_EXTRA_STATE_RESTORER \ RESTORE_CALL_SAVED_REGS; \ RESTORE_CT_REGS -#define DBTRAP_FUNCALL_EXTRA_STATE_SAVER /* nothing */ -#define DBTRAP_FUNCALL_EXTRA_STATE_RESTORER /* nothing */ +#define DBTRAP_SCHEDULE_EXTRA_STATE_SAVER /* nothing */ +#define DBTRAP_SCHEDULE_EXTRA_STATE_RESTORER /* nothing */ /* Register saving/restoring for a context switch. We don't need to save too many registers, because context-switching looks like a function call @@ -372,14 +390,14 @@ RESTORE_CT_REGS -/* Restore register state from the struct pt_regs on the stack, switch back +/* Restore register state from the state-save-frame on the stack, switch back to the user stack if necessary, and return from the trap/interrupt. EXTRA_STATE_RESTORER is a sequence of assembly language statements to restore anything not restored by this macro. Only registers not saved by the C compiler are restored (that is, R3(sp), R4(gp), R31(lp), and anything restored by EXTRA_STATE_RESTORER). */ #define RETURN(type) \ - ld.b PTO+PT_KERNEL_MODE[sp], r19; \ + ld.b PTO+PT_KERNEL_MODE[sp], r19; \ di; /* Disable interrupts */ \ cmp r19, r0; /* See if returning to kernel mode, */\ bne 2f; /* ... if so, skip resched &c. */ \ @@ -390,33 +408,34 @@ ld.w TI_FLAGS[r18], r19; \ andi _TIF_NEED_RESCHED, r19, r0; \ bnz 3f; /* Call the scheduler. */ \ - andi _TIF_SIGPENDING, r19, r0; \ - bnz 4f; /* Signals to handle, handle them */ \ +5: andi _TIF_SIGPENDING, r19, r18; \ + ld.w TASK_PTRACE[CURRENT_TASK], r19; /* ptrace flags */ \ + or r18, r19; /* see if either is non-zero */ \ + bnz 4f; /* if so, handle them */ \ \ -/* Return to user state. */ \ +/* Return to user state. */ \ 1: st.b r0, KM; /* Now officially in user state. */ \ \ /* Final return. The stack-pointer fiddling is not needed when returning \ to kernel-mode, but they don't hurt, and this way we can share the \ - (somtimes rather lengthy) POP_STATE macro. */ \ + (sometimes rather lengthy) POP_STATE macro. */ \ 2: POP_STATE(type); \ st.w sp, KSP; /* Save the kernel stack pointer. */ \ - ld.w PT_GPR(GPR_SP)-PT_SIZE[sp], sp; /* Restore stack pointer. */ \ + ld.w PT_GPR(GPR_SP)-PT_SIZE[sp], sp; /* Restore stack pointer. */ \ type ## _RET; /* Return from the trap/interrupt. */ \ \ /* Call the scheduler before returning from a syscall/trap. */ \ -3: SAVE_EXTRA_STATE_FOR_FUNCALL(type); /* Prepare for funcall. */ \ - jarl CSYM(schedule), lp; /* Call scheduler */ \ +3: SAVE_EXTRA_STATE_FOR_SCHEDULE(type); /* Prepare to call scheduler. */ \ + jarl call_scheduler, lp; /* Call scheduler */ \ di; /* The scheduler enables interrupts */\ - RESTORE_EXTRA_STATE_FOR_FUNCALL(type); \ + RESTORE_EXTRA_STATE_FOR_SCHEDULE(type); \ GET_CURRENT_THREAD(r18); \ ld.w TI_FLAGS[r18], r19; \ - andi _TIF_SIGPENDING, r19, r0; \ - bz 1b; /* No signals, return. */ \ - /* Signals to handle, fall through to handle them. */ \ + br 5b; /* Continue with return path. */ \ \ -/* Handle a signal return. */ \ -4: /* Not all registers are saved by the normal trap/interrupt entry \ +/* Handle a signal or ptraced process return. \ + r18 should be non-zero if there are pending signals. */ \ +4: /* Not all registers are saved by the normal trap/interrupt entry \ points (for instance, call-saved registers (because the normal \ C-compiler calling sequence in the kernel makes sure they're \ preserved), and call-clobbered registers in the case of \ @@ -424,12 +443,9 @@ complete register state. Here we save anything not saved by \ the normal entry sequence, so that it may be safely restored \ (in a possibly modified form) after do_signal returns. */ \ - SAVE_EXTRA_STATE(type); /* Save state not saved by entry. */ \ - movea PTO, sp, r6; /* Arg 1: struct pt_regs *regs */ \ - mov r0, r7; /* Arg 2: sigset_t *oldset */ \ - jarl CSYM(do_signal), lp; /* Handle any signals */ \ - di; /* sig handling enables interrupts */ \ - RESTORE_EXTRA_STATE(type); /* Restore extra regs. */ \ + SAVE_EXTRA_STATE(type); /* Save state not saved by entry. */ \ + jarl handle_signal_or_ptrace_return, lp; \ + RESTORE_EXTRA_STATE(type); /* Restore extra regs. */ \ br 1b @@ -471,7 +487,7 @@ * Return value in r10 */ G_ENTRY(trap): - SAVE_STATE (TRAP, r12, ENTRY_SP) // Save registers. + SAVE_STATE (TRAP, r12, ENTRY_SP) // Save registers. stsr SR_ECR, r19 // Find out which trap it was. ei // Enable interrupts. mov hilo(ret_from_trap), lp // where the trap should return @@ -481,12 +497,12 @@ // numbers into the (0-31) << 2 range we want, (3) set the flags. shl 27, r19 // chop off all high bits shr 25, r19 // scale back down and then << 2 - bnz 2f // See if not trap 0. + bnz 2f // See if not trap 0. - // Trap 0 is a `short' system call, skip general trap table. - MAKE_SYS_CALL // Jump to the syscall function. + // Trap 0 is a `short' system call, skip general trap table. + MAKE_SYS_CALL // Jump to the syscall function. -2: // For other traps, use a table lookup. +2: // For other traps, use a table lookup. mov hilo(CSYM(trap_table)), r18 add r19, r18 ld.w 0[r18], r18 @@ -505,6 +521,7 @@ RETURN(TRAP) END(ret_from_trap) + /* This the initial entry point for a new child thread, with an appropriate stack in place that makes it look the the child is in the middle of an syscall. This function is actually `returned to' from switch_thread @@ -538,7 +555,7 @@ mov hilo(ret_from_long_syscall), lp MAKE_SYS_CALL // Jump to the syscall function. -END(syscall_long) +END(syscall_long) /* Entry point used to return from a long syscall. Only needed to restore r13/r14 if the general trap mechanism doesnt' do so. */ @@ -554,11 +571,14 @@ L_ENTRY(sys_fork_wrapper): #ifdef CONFIG_MMU - addi SIGCHLD, r0, r6 // Arg 0: flags + addi SIGCHLD, r0, r6 // Arg 0: flags ld.w PTO+PT_GPR(GPR_SP)[sp], r7 // Arg 1: child SP (use parent's) - movea PTO, sp, r8 // Arg 2: parent context - mov hilo(CSYM(fork_common)), r18// Where the real work gets done - br save_extra_state_tramp // Save state and go there + movea PTO, sp, r8 // Arg 2: parent context + mov r0, r9 // Arg 3/4/5: 0 + st.w r0, 16[sp] + st.w r0, 20[sp] + mov hilo(CSYM(do_fork)), r18 // Where the real work gets done + br save_extra_state_tramp // Save state and go there #else // fork almost works, enough to trick you into looking elsewhere :-( addi -EINVAL, r0, r10 @@ -569,18 +589,24 @@ L_ENTRY(sys_vfork_wrapper): addi CLONE_VFORK | CLONE_VM | SIGCHLD, r0, r6 // Arg 0: flags ld.w PTO+PT_GPR(GPR_SP)[sp], r7 // Arg 1: child SP (use parent's) - movea PTO, sp, r8 // Arg 2: parent context - mov hilo(CSYM(fork_common)), r18// Where the real work gets done - br save_extra_state_tramp // Save state and go there + movea PTO, sp, r8 // Arg 2: parent context + mov r0, r9 // Arg 3/4/5: 0 + st.w r0, 16[sp] + st.w r0, 20[sp] + mov hilo(CSYM(do_fork)), r18 // Where the real work gets done + br save_extra_state_tramp // Save state and go there END(sys_vfork_wrapper) L_ENTRY(sys_clone_wrapper): - ld.w PTO+PT_GPR(GPR_SP)[sp], r19 // parent's stack pointer - cmp r7, r0 // See if child SP arg (arg 1) is 0. - cmov z, r19, r7, r7 // ... and use the parent's if so. - movea PTO, sp, r8 // Arg 2: parent context - mov hilo(CSYM(fork_common)), r18// Where the real work gets done - br save_extra_state_tramp // Save state and go there + ld.w PTO+PT_GPR(GPR_SP)[sp], r19// parent's stack pointer + cmp r7, r0 // See if child SP arg (arg 1) is 0. + cmov z, r19, r7, r7 // ... and use the parent's if so. + movea PTO, sp, r8 // Arg 2: parent context + mov r0, r9 // Arg 3/4/5: 0 + st.w r0, 16[sp] + st.w r0, 20[sp] + mov hilo(CSYM(do_fork)), r18 // Where the real work gets done + br save_extra_state_tramp // Save state and go there END(sys_clone_wrapper) @@ -598,8 +624,8 @@ END(sys_sigsuspend_wrapper) L_ENTRY(sys_rt_sigsuspend_wrapper): movea PTO, sp, r8 // add user context as 3rd arg - mov hilo(CSYM(sys_rt_sigsuspend)), r18 // syscall function - jarl save_extra_state_tramp, lp // Save state and do it + mov hilo(CSYM(sys_rt_sigsuspend)), r18 // syscall function + jarl save_extra_state_tramp, lp // Save state and do it br restore_extra_regs_and_ret_from_trap END(sys_rt_sigsuspend_wrapper) @@ -610,10 +636,9 @@ br restore_extra_regs_and_ret_from_trap END(sys_sigreturn_wrapper) L_ENTRY(sys_rt_sigreturn_wrapper): - SAVE_EXTRA_STATE(TRAP) // Save state not saved by entry. movea PTO, sp, r6 // add user context as 1st arg - mov hilo(CSYM(sys_rt_sigreturn)), r18 // syscall function - jarl save_extra_state_tramp, lp // Save state and do it + mov hilo(CSYM(sys_rt_sigreturn)), r18// syscall function + jarl save_extra_state_tramp, lp // Save state and do it br restore_extra_regs_and_ret_from_trap END(sys_rt_sigreturn_wrapper) @@ -637,7 +662,7 @@ * indirect jump). */ G_ENTRY(irq): - SAVE_STATE (IRQ, r0, ENTRY_SP) // Save registers. + SAVE_STATE (IRQ, r0, ENTRY_SP) // Save registers. stsr SR_ECR, r6 // Find out which interrupt it was. movea PTO, sp, r7 // User regs are arg2 @@ -657,7 +682,7 @@ RETURN(IRQ) END(irq) - + /* * Debug trap / illegal-instruction exception * @@ -668,22 +693,50 @@ * indirect jump). */ G_ENTRY(dbtrap): - SAVE_STATE (DBTRAP, r0, ENTRY_SP)// Save registers. + SAVE_STATE (DBTRAP, r0, ENTRY_SP)// Save registers. + + /* First see if we came from kernel mode; if so, the dbtrap + instruction has a special meaning, to set the DIR (`debug + information register') register. This is because the DIR register + can _only_ be manipulated/read while in `debug mode,' and debug + mode is only active while we're inside the dbtrap handler. The + exact functionality is: { DIR = (DIR | r6) & ~r7; return DIR; }. */ + ld.b PTO+PT_KERNEL_MODE[sp], r19 + cmp r19, r0 + bz 1f + + stsr SR_DIR, r10 + or r6, r10 + not r7, r7 + and r7, r10 + ldsr r10, SR_DIR + stsr SR_DIR, r10 // Confirm the value we set + st.w r10, PTO+PT_GPR(10)[sp] // return it + br 3f + +1: ei // Enable interrupts. + + /* The default signal type we raise. */ + mov SIGTRAP, r6 + + /* See if it's a single-step trap. */ + stsr SR_DBPSW, r19 + andi 0x0800, r19, r19 + bnz 2f /* Look to see if the preceding instruction was is a dbtrap or not, to decide which signal we should use. */ stsr SR_DBPC, r19 // PC following trapping insn ld.hu -2[r19], r19 - mov SIGTRAP, r6 ori 0xf840, r0, r20 // DBTRAP insn cmp r19, r20 // Was this trap caused by DBTRAP? cmov ne, SIGILL, r6, r6 // Choose signal appropriately /* Raise the desired signal. */ - mov CURRENT_TASK, r7 // Arg 1: task - jarl CSYM(force_sig), lp // tail call +2: mov CURRENT_TASK, r7 // Arg 1: task + jarl CSYM(send_sig), lp // tail call - RETURN(DBTRAP) +3: RETURN(DBTRAP) END(dbtrap) @@ -725,9 +778,93 @@ /* + * Invoke the scheduler, called from the trap/irq kernel exit path. + * + * This basically just calls `schedule', but also arranges for extra + * registers to be saved for ptrace'd processes, so ptrace can modify them. + */ +L_ENTRY(call_scheduler): + ld.w TASK_PTRACE[CURRENT_TASK], r19 // See if task is ptrace'd + cmp r19, r0 + bnz 1f // ... yes, do special stuff + jr CSYM(schedule) // ... no, just tail-call scheduler + + // Save extra regs for ptrace'd task. We want to save anything + // that would otherwise only be `implicitly' saved by the normal + // compiler calling-convention. +1: mov sp, ep // Setup EP for SAVE_CALL_SAVED_REGS + SAVE_CALL_SAVED_REGS // Save call-saved registers to stack + mov lp, r20 // Save LP in a callee-saved register + + jarl CSYM(schedule), lp // Call scheduler + + mov r20, lp + mov sp, ep // We can't rely on EP after return + RESTORE_CALL_SAVED_REGS // Restore (possibly modified) regs + jmp [lp] // Return to the return path +END(call_scheduler) + + +/* + * This is an out-of-line handler for two special cases during the kernel + * trap/irq exit sequence: + * + * (1) If r18 is non-zero then a signal needs to be handled, which is + * done, and then the caller returned to. + * + * (2) If r18 is non-zero then we're returning to a ptraced process, which + * has several special cases -- single-stepping and trap tracing, both + * of which require using the `dbret' instruction to exit the kernel + * instead of the normal `reti' (this is because the CPU not correctly + * single-step after a reti). In this case, of course, this handler + * never returns to the caller. + * + * In either case, all registers should have been saved to the current + * state-save-frame on the stack, except for callee-saved registers. + * + * [These two different cases are combined merely to avoid bloating the + * macro-inlined code, not because they really make much sense together!] + */ +L_ENTRY(handle_signal_or_ptrace_return): + cmp r18, r0 // See if handling a signal + bz 1f // ... nope, go do ptrace return + + // Handle a signal + mov lp, r20 // Save link-pointer + mov r10, r21 // Save return-values (for trap) + mov r11, r22 + + movea PTO, sp, r6 // Arg 1: struct pt_regs *regs + mov r0, r7 // Arg 2: sigset_t *oldset + jarl CSYM(do_signal), lp // Handle the signal + di // sig handling enables interrupts + + mov r20, lp // Restore link-pointer + mov r21, r10 // Restore return-values (for trap) + mov r22, r11 + ld.w TASK_PTRACE[CURRENT_TASK], r19 // check ptrace flags too + cmp r19, r0 + bnz 1f // ... some set, so look more +2: jmp [lp] // ... none set, so return normally + + // ptrace return +1: ld.w PTO+PT_PSW[sp], r19 // Look at user-processes's flags + andi 0x0800, r19, r19 // See if single-step flag is set + bz 2b // ... nope, return normally + + // Return as if from a dbtrap insn + st.b r0, KM // Now officially in user state. + POP_STATE(DBTRAP) // Restore regs + st.w sp, KSP // Save the kernel stack pointer. + ld.w PT_GPR(GPR_SP)-PT_SIZE[sp], sp // Restore user stack pointer. + DBTRAP_RET // Return from the trap/interrupt. +END(handle_signal_or_ptrace_return) + + +/* * This is where we switch between two threads. The arguments are: * r6 -- pointer to the struct thread for the `current' process - * r7 -- pointer to the struct thread for the `new' process. + * r7 -- pointer to the struct thread for the `new' process. * when this function returns, it will return to the new thread. */ C_ENTRY(switch_thread): @@ -754,8 +891,8 @@ .align 4 C_DATA(trap_table): - .long bad_trap_wrapper // trap 0, doesn't use trap table. - .long syscall_long // trap 1, `long' syscall. + .long bad_trap_wrapper // trap 0, doesn't use trap table. + .long syscall_long // trap 1, `long' syscall. .long bad_trap_wrapper .long bad_trap_wrapper .long bad_trap_wrapper @@ -774,7 +911,7 @@ .section .rodata - + .align 4 C_DATA(sys_call_table): .long CSYM(sys_restart_syscall) // 0 @@ -835,7 +972,7 @@ .long CSYM(sys_fcntl) // 55 .long CSYM(sys_ni_syscall) // was: mpx .long CSYM(sys_setpgid) - .long CSYM(sys_ni_syscall) // was: ulimit + .long CSYM(sys_ni_syscall) // was: ulimit .long CSYM(sys_ni_syscall) .long CSYM(sys_umask) // 60 .long CSYM(sys_chroot) @@ -875,7 +1012,7 @@ .long CSYM(sys_fchown) // 95 .long CSYM(sys_getpriority) .long CSYM(sys_setpriority) - .long CSYM(sys_ni_syscall) // was: profil + .long CSYM(sys_ni_syscall) // was: profil .long CSYM(sys_statfs) .long CSYM(sys_fstatfs) // 100 .long CSYM(sys_ni_syscall) // i386: ioperm @@ -900,7 +1037,7 @@ .long sys_clone_wrapper // 120 .long CSYM(sys_setdomainname) .long CSYM(sys_newuname) - .long CSYM(sys_ni_syscall) // i386: modify_ldt, m68k: cacheflush + .long CSYM(sys_ni_syscall) // i386: modify_ldt, m68k: cacheflush .long CSYM(sys_adjtimex) .long CSYM(sys_ni_syscall) // 125 - sys_mprotect .long CSYM(sys_sigprocmask) @@ -937,7 +1074,7 @@ .long CSYM(sys_sched_getscheduler) .long CSYM(sys_sched_yield) .long CSYM(sys_sched_get_priority_max) - .long CSYM(sys_sched_get_priority_min) // 160 + .long CSYM(sys_sched_get_priority_min) // 160 .long CSYM(sys_sched_rr_get_interval) .long CSYM(sys_nanosleep) .long CSYM(sys_ni_syscall) // sys_mremap diff -Nru a/arch/v850/kernel/head.S b/arch/v850/kernel/head.S --- a/arch/v850/kernel/head.S Mon Jun 9 23:16:07 2003 +++ b/arch/v850/kernel/head.S Mon Jun 9 23:16:07 2003 @@ -39,7 +39,7 @@ cmp r19, r20 bne 1f // Guard was not active - // If we get here, the reset guard was active. Load up some + // If we get here, the reset guard was active. Load up some // interesting values as arguments, and jump to the handler. st.w r0, RESET_GUARD // Allow further resets to succeed mov lp, r6 // Arg 0: return address @@ -53,7 +53,7 @@ 1: st.w r20, RESET_GUARD // Turn on reset guard #endif /* CONFIG_RESET_GUARD */ - + // Setup a temporary stack for doing pre-initialization function calls. // // We can't use the initial kernel stack, because (1) it may be diff -Nru a/arch/v850/kernel/irq.c b/arch/v850/kernel/irq.c --- a/arch/v850/kernel/irq.c Mon Jun 9 23:16:16 2003 +++ b/arch/v850/kernel/irq.c Mon Jun 9 23:16:16 2003 @@ -1,7 +1,7 @@ /* * arch/v850/kernel/irq.c -- High-level interrupt handling * - * Copyright (C) 2001,02,03 NEC Corporation + * Copyright (C) 2001,02,03 NEC Electronics Corporation * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org> * Copyright (C) 1994-2000 Ralf Baechle * Copyright (C) 1992 Linus Torvalds @@ -28,14 +28,18 @@ /* * Controller mappings for all interrupt sources: */ -irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = - { [0 ... NR_IRQS-1] = { 0, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}}; +irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { + [0 ... NR_IRQS-1] = { + .handler = &no_irq_type, + .lock = SPIN_LOCK_UNLOCKED + } +}; /* * Special irq handlers. */ -void no_action(int cpl, void *dev_id, struct pt_regs *regs) { } +irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs) { } /* * Generic no controller code @@ -352,7 +356,7 @@ */ int request_irq(unsigned int irq, - void (*handler)(int, void *, struct pt_regs *), + irqreturn_t (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char * devname, void *dev_id) diff -Nru a/arch/v850/kernel/ma.c b/arch/v850/kernel/ma.c --- a/arch/v850/kernel/ma.c Mon Jun 9 23:16:08 2003 +++ b/arch/v850/kernel/ma.c Mon Jun 9 23:16:08 2003 @@ -1,8 +1,8 @@ /* * arch/v850/kernel/ma.c -- V850E/MA series of cpu chips * - * Copyright (C) 2001,02 NEC Corporation - * Copyright (C) 2001,02 Miles Bader <miles@gnu.org> + * Copyright (C) 2001,02,03 NEC Electronics Corporation + * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org> * * 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 diff -Nru a/arch/v850/kernel/mach.h b/arch/v850/kernel/mach.h --- a/arch/v850/kernel/mach.h Mon Jun 9 23:16:19 2003 +++ b/arch/v850/kernel/mach.h Mon Jun 9 23:16:19 2003 @@ -1,8 +1,8 @@ /* * arch/v850/kernel/mach.h -- Machine-dependent functions used by v850 port * - * Copyright (C) 2001,02 NEC Corporation - * Copyright (C) 2001,02 Miles Bader <miles@gnu.org> + * Copyright (C) 2001,02,03 NEC Electronics Corporation + * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org> * * 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 diff -Nru a/arch/v850/kernel/process.c b/arch/v850/kernel/process.c --- a/arch/v850/kernel/process.c Mon Jun 9 23:16:08 2003 +++ b/arch/v850/kernel/process.c Mon Jun 9 23:16:08 2003 @@ -1,7 +1,7 @@ /* * arch/v850/kernel/process.c -- Arch-dependent process handling * - * Copyright (C) 2001,02,03 NEC Corporation + * Copyright (C) 2001,02,03 NEC Electronics Corporation * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org> * * This file is subject to the terms and conditions of the GNU General @@ -198,14 +198,6 @@ } return error; -} - -/* This is the common part of the various fork-like system calls (which - are in entry.S). */ -int fork_common (int flags, unsigned long new_sp, struct pt_regs *regs) -{ - struct task_struct *p = do_fork (flags, new_sp, regs, 0, 0, 0); - return IS_ERR (p) ? PTR_ERR (p) : p->pid; } diff -Nru a/arch/v850/kernel/ptrace.c b/arch/v850/kernel/ptrace.c --- a/arch/v850/kernel/ptrace.c Mon Jun 9 23:16:13 2003 +++ b/arch/v850/kernel/ptrace.c Mon Jun 9 23:16:13 2003 @@ -1,8 +1,8 @@ /* * arch/v850/kernel/ptrace.c -- `ptrace' system call * - * Copyright (C) 2002 NEC Corporation - * Copyright (C) 2002 Miles Bader <miles@gnu.org> + * Copyright (C) 2002,03 NEC Electronics Corporation + * Copyright (C) 2002,03 Miles Bader <miles@gnu.org> * * Derived from arch/mips/kernel/ptrace.c: * @@ -29,6 +29,89 @@ #include <asm/processor.h> #include <asm/uaccess.h> +/* Returns the address where the register at REG_OFFS in P is stashed away. */ +static v850_reg_t *reg_save_addr (unsigned reg_offs, struct task_struct *t) +{ + struct pt_regs *regs; + + /* Three basic cases: + + (1) A register normally saved before calling the scheduler, is + available in the kernel entry pt_regs structure at the top + of the kernel stack. The kernel trap/irq exit path takes + care to save/restore almost all registers for ptrace'd + processes. + + (2) A call-clobbered register, where the process P entered the + kernel via [syscall] trap, is not stored anywhere; that's + OK, because such registers are not expected to be preserved + when the trap returns anyway (so we don't actually bother to + test for this case). + + (3) A few registers not used at all by the kernel, and so + normally never saved except by context-switches, are in the + context switch state. */ + + if (reg_offs == PT_CTPC || reg_offs == PT_CTPSW || reg_offs == PT_CTBP) + /* Register saved during context switch. */ + regs = thread_saved_regs (t); + else + /* Register saved during kernel entry (or not available). */ + regs = task_regs (t); + + return (v850_reg_t *)((char *)regs + reg_offs); +} + +/* Set the bits SET and clear the bits CLEAR in the v850e DIR + (`debug information register'). Returns the new value of DIR. */ +static inline v850_reg_t set_dir (v850_reg_t set, v850_reg_t clear) +{ + register v850_reg_t rval asm ("r10"); + register v850_reg_t arg0 asm ("r6") = set; + register v850_reg_t arg1 asm ("r7") = clear; + + /* The dbtrap handler has exactly this functionality when called + from kernel mode. 0xf840 is a `dbtrap' insn. */ + asm (".short 0xf840" : "=r" (rval) : "r" (arg0), "r" (arg1)); + + return rval; +} + +/* Makes sure hardware single-stepping is (globally) enabled. + Returns true if successful. */ +static inline int enable_single_stepping (void) +{ + static int enabled = 0; /* Remember whether we already did it. */ + if (! enabled) { + /* Turn on the SE (`single-step enable') bit, 0x100, in the + DIR (`debug information register'). This may fail if a + processor doesn't support it or something. We also try + to clear bit 0x40 (`INI'), which is necessary to use the + debug stuff on the v850e2; on the v850e, clearing 0x40 + shouldn't cause any problem. */ + v850_reg_t dir = set_dir (0x100, 0x40); + /* Make sure it really got set. */ + if (dir & 0x100) + enabled = 1; + } + return enabled; +} + +/* Try to set CHILD's single-step flag to VAL. Returns true if successful. */ +static int set_single_step (struct task_struct *t, int val) +{ + v850_reg_t *psw_addr = reg_save_addr(PT_PSW, t); + if (val) { + /* Make sure single-stepping is enabled. */ + if (! enable_single_stepping ()) + return 0; + /* Set T's single-step flag. */ + *psw_addr |= 0x800; + } else + *psw_addr &= ~0x800; + return 1; +} + int sys_ptrace(long request, long pid, long addr, long data) { struct task_struct *child; @@ -36,12 +119,6 @@ lock_kernel(); -#if 0 - printk("ptrace(r=%d,pid=%d,addr=%08lx,data=%08lx)\n", - (int) request, (int) pid, (unsigned long) addr, - (unsigned long) data); -#endif - if (request == PTRACE_TRACEME) { /* are we already being traced? */ if (current->ptrace & PT_PTRACED) { @@ -81,31 +158,15 @@ goto out_tsk; switch (request) { - case PTRACE_PEEKTEXT: /* read word at location addr. */ - case PTRACE_PEEKDATA:{ - unsigned long tmp; - int copied; + unsigned long val, copied; - copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); + case PTRACE_PEEKTEXT: /* read word at location addr. */ + case PTRACE_PEEKDATA: + copied = access_process_vm(child, addr, &val, sizeof(val), 0); rval = -EIO; - if (copied != sizeof(tmp)) + if (copied != sizeof(val)) break; - rval = put_user(tmp,(unsigned long *) data); - - goto out; - } - - /* Read the word at location addr in the USER area. */ - case PTRACE_PEEKUSR: - if (addr >= 0 && addr < PT_SIZE && (addr & 0x3) == 0) { - struct pt_regs *regs = task_regs (child); - unsigned long val = - *(unsigned long *)((char *)regs + addr); - rval = put_user (val, (unsigned long *)data); - } else { - rval = 0; - rval = -EIO; - } + rval = put_user(val, (unsigned long *)data); goto out; case PTRACE_POKETEXT: /* write the word at location addr. */ @@ -117,35 +178,62 @@ rval = -EIO; goto out; + /* Read/write the word at location ADDR in the registers. */ + case PTRACE_PEEKUSR: case PTRACE_POKEUSR: - if (addr >= 0 && addr < PT_SIZE && (addr & 0x3) == 0) { - struct pt_regs *regs = task_regs (child); - unsigned long *loc = - (unsigned long *)((char *)regs + addr); - *loc = data; - } else { - rval = 0; - rval = -EIO; - } + rval = 0; + if (addr >= PT_SIZE && request == PTRACE_PEEKUSR) { + /* Special requests that don't actually correspond + to offsets in struct pt_regs. */ + if (addr == PT_TEXT_ADDR) + val = child->mm->start_code; + else if (addr == PT_DATA_ADDR) + val = child->mm->start_data; + else if (addr == PT_TEXT_LEN) + val = child->mm->end_code + - child->mm->start_code; + else + rval = -EIO; + } else if (addr >= 0 && addr < PT_SIZE && (addr & 0x3) == 0) { + v850_reg_t *reg_addr = reg_save_addr(addr, child); + if (request == PTRACE_PEEKUSR) + val = *reg_addr; + else + *reg_addr = data; + } else + rval = -EIO; + + if (rval == 0 && request == PTRACE_PEEKUSR) + rval = put_user (val, (unsigned long *)data); goto out; - case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ - case PTRACE_CONT: /* rvaltart after signal. */ + /* Continue and stop at next (return from) syscall */ + case PTRACE_SYSCALL: + /* Restart after a signal. */ + case PTRACE_CONT: + /* Execute a single instruction. */ + case PTRACE_SINGLESTEP: rval = -EIO; if ((unsigned long) data > _NSIG) break; + + /* Turn CHILD's single-step flag on or off. */ + if (! set_single_step (child, request == PTRACE_SINGLESTEP)) + break; + if (request == PTRACE_SYSCALL) set_tsk_thread_flag(child, TIF_SYSCALL_TRACE); else clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE); + child->exit_code = data; wake_up_process(child); rval = 0; break; /* - * make the child exit. Best I can do is send it a sigkill. - * perhaps it should be put in the status that it wants to + * make the child exit. Best I can do is send it a sigkill. + * perhaps it should be put in the status that it wants to * exit. */ case PTRACE_KILL: @@ -157,6 +245,7 @@ break; case PTRACE_DETACH: /* detach a process that was attached. */ + set_single_step (child, 0); /* Clear single-step flag */ rval = ptrace_detach(child, data); break; @@ -181,7 +270,7 @@ /* The 0x80 provides a way for the tracing parent to distinguish between a syscall stop and SIGTRAP delivery */ current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) - ? 0x80 : 0); + ? 0x80 : 0); current->state = TASK_STOPPED; notify_parent(current, SIGCHLD); schedule(); diff -Nru a/arch/v850/kernel/rte_cb_leds.c b/arch/v850/kernel/rte_cb_leds.c --- a/arch/v850/kernel/rte_cb_leds.c Mon Jun 9 23:16:07 2003 +++ b/arch/v850/kernel/rte_cb_leds.c Mon Jun 9 23:16:07 2003 @@ -1,8 +1,8 @@ /* * include/asm-v850/rte_cb_leds.c -- Midas lab RTE-CB board LED device support * - * Copyright (C) 2002 NEC Corporation - * Copyright (C) 2002 Miles Bader <miles@gnu.org> + * Copyright (C) 2002,03 NEC Electronics Corporation + * Copyright (C) 2002,03 Miles Bader <miles@gnu.org> * * 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 @@ -14,6 +14,7 @@ #include <linux/config.h> #include <linux/init.h> #include <linux/spinlock.h> +#include <linux/fs.h> #include <linux/miscdevice.h> #include <asm/uaccess.h> diff -Nru a/arch/v850/kernel/rte_cb_multi.c b/arch/v850/kernel/rte_cb_multi.c --- a/arch/v850/kernel/rte_cb_multi.c Mon Jun 9 23:16:09 2003 +++ b/arch/v850/kernel/rte_cb_multi.c Mon Jun 9 23:16:09 2003 @@ -2,7 +2,7 @@ * include/asm-v850/rte_multi.c -- Support for Multi debugger monitor ROM * on Midas lab RTE-CB series of evaluation boards * - * Copyright (C) 2001,02,03 NEC Corporation + * Copyright (C) 2001,02,03 NEC Electronics Corporation * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org> * * This file is subject to the terms and conditions of the GNU General diff -Nru a/arch/v850/kernel/rte_ma1_cb.c b/arch/v850/kernel/rte_ma1_cb.c --- a/arch/v850/kernel/rte_ma1_cb.c Mon Jun 9 23:16:17 2003 +++ b/arch/v850/kernel/rte_ma1_cb.c Mon Jun 9 23:16:17 2003 @@ -1,7 +1,7 @@ /* * arch/v850/kernel/rte_ma1_cb.c -- Midas labs RTE-V850E/MA1-CB board * - * Copyright (C) 2001,02,03 NEC Corporation + * Copyright (C) 2001,02,03 NEC Electronics Corporation * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org> * * This file is subject to the terms and conditions of the GNU General diff -Nru a/arch/v850/kernel/rte_mb_a_pci.c b/arch/v850/kernel/rte_mb_a_pci.c --- a/arch/v850/kernel/rte_mb_a_pci.c Mon Jun 9 23:16:08 2003 +++ b/arch/v850/kernel/rte_mb_a_pci.c Mon Jun 9 23:16:08 2003 @@ -251,10 +251,10 @@ /* Resource allocation. */ static void __devinit pcibios_assign_resources (void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; struct resource *r; - pci_for_each_dev (dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { unsigned di_num; unsigned class = dev->class >> 8; diff -Nru a/arch/v850/lib/Makefile b/arch/v850/lib/Makefile --- a/arch/v850/lib/Makefile Mon Jun 9 23:16:13 2003 +++ b/arch/v850/lib/Makefile Mon Jun 9 23:16:13 2003 @@ -2,6 +2,5 @@ # arch/v850/lib/Makefile # -L_TARGET = lib.a -obj-y = ashrdi3.o ashldi3.o lshrdi3.o muldi3.o negdi2.o \ +lib-y = ashrdi3.o ashldi3.o lshrdi3.o muldi3.o negdi2.o \ checksum.o memcpy.o memset.o diff -Nru a/arch/v850/vmlinux.lds.S b/arch/v850/vmlinux.lds.S --- a/arch/v850/vmlinux.lds.S Mon Jun 9 23:16:15 2003 +++ b/arch/v850/vmlinux.lds.S Mon Jun 9 23:16:15 2003 @@ -105,9 +105,9 @@ #define RAMK_INIT_CONTENTS_NO_END \ . = ALIGN (4096) ; \ __init_start = . ; \ - _sinittext = .; \ + __sinittext = .; \ *(.init.text) /* 2.5 convention */ \ - _einittext = .; \ + __einittext = .; \ *(.init.data) \ *(.text.init) /* 2.4 convention */ \ *(.data.init) \ diff -Nru a/arch/x86_64/Kconfig b/arch/x86_64/Kconfig --- a/arch/x86_64/Kconfig Mon Jun 9 23:16:16 2003 +++ b/arch/x86_64/Kconfig Mon Jun 9 23:16:16 2003 @@ -351,7 +351,7 @@ source "drivers/pcmcia/Kconfig" -source "drivers/hotplug/Kconfig" +source "drivers/pci/hotplug/Kconfig" endmenu diff -Nru a/arch/x86_64/defconfig b/arch/x86_64/defconfig --- a/arch/x86_64/defconfig Mon Jun 9 23:16:15 2003 +++ b/arch/x86_64/defconfig Mon Jun 9 23:16:15 2003 @@ -22,6 +22,9 @@ # CONFIG_BSD_PROCESS_ACCT is not set CONFIG_SYSCTL=y CONFIG_LOG_BUF_SHIFT=16 +# CONFIG_EMBEDDED is not set +CONFIG_FUTEX=y +CONFIG_EPOLL=y # # Loadable module support @@ -546,6 +549,7 @@ CONFIG_PROC_FS=y # CONFIG_DEVFS_FS is not set CONFIG_DEVPTS_FS=y +# CONFIG_DEVPTS_FS_XATTR is not set CONFIG_TMPFS=y CONFIG_RAMFS=y diff -Nru a/arch/x86_64/ia32/Makefile b/arch/x86_64/ia32/Makefile --- a/arch/x86_64/ia32/Makefile Mon Jun 9 23:16:09 2003 +++ b/arch/x86_64/ia32/Makefile Mon Jun 9 23:16:09 2003 @@ -13,4 +13,7 @@ $(CC) -m32 -nostdlib -shared -s -Wl,-soname=linux-vsyscall.so.1 \ -o $@ -Wl,-T,$^ +clean-files += vsyscall.so + AFLAGS_vsyscall.o = -m32 +CFLAGS_ia32_ioctl.o += -Ifs/ diff -Nru a/arch/x86_64/ia32/ia32_ioctl.c b/arch/x86_64/ia32/ia32_ioctl.c --- a/arch/x86_64/ia32/ia32_ioctl.c Mon Jun 9 23:16:13 2003 +++ b/arch/x86_64/ia32/ia32_ioctl.c Mon Jun 9 23:16:13 2003 @@ -9,2264 +9,16 @@ * ioctls. */ -#include <linux/config.h> -#include <linux/sched.h> -#include <linux/types.h> -#include <linux/compat.h> -#include <linux/kernel.h> -#include <linux/smp.h> -#include <linux/smp_lock.h> -#include <linux/ioctl.h> -#include <linux/if.h> -#include <linux/slab.h> -#include <linux/hdreg.h> -#include <linux/raid/md.h> -#include <linux/kd.h> -#include <linux/dirent.h> -#include <linux/route.h> -#include <linux/in6.h> -#include <linux/ipv6_route.h> -#include <linux/skbuff.h> -#include <linux/netlink.h> -#include <linux/vt.h> -#include <linux/fs.h> -#include <linux/file.h> -#include <linux/fd.h> -#include <linux/ppp_defs.h> -#include <linux/if_ppp.h> -#include <linux/if_pppox.h> -#include <linux/mtio.h> -#include <linux/cdrom.h> -#include <linux/loop.h> -#include <linux/auto_fs.h> -#include <linux/auto_fs4.h> -#include <linux/devfs_fs.h> -#include <linux/tty.h> -#include <linux/vt_kern.h> -#include <linux/fb.h> -#include <linux/ext2_fs.h> -#include <linux/videodev.h> -#include <linux/netdevice.h> -#include <linux/raw.h> -#include <linux/smb_fs.h> -#include <linux/blkpg.h> -#include <linux/blk.h> -#include <linux/elevator.h> -#include <linux/rtc.h> -#include <linux/pci.h> -#include <linux/rtc.h> -#include <linux/module.h> -#include <linux/serial.h> -#include <linux/reiserfs_fs.h> -#include <linux/if_tun.h> -#include <linux/dirent.h> -#include <linux/ctype.h> -#include <net/sock.h> /* siocdevprivate_ioctl */ -#include <net/bluetooth/bluetooth.h> -#include <net/bluetooth/rfcomm.h> - -#include <scsi/scsi.h> -/* Ugly hack. */ -#undef __KERNEL__ -#include <scsi/scsi_ioctl.h> -#define __KERNEL__ -#include <scsi/sg.h> - -#include <asm/types.h> -#include <asm/ia32.h> -#include <asm/uaccess.h> -#include <linux/ethtool.h> -#include <linux/mii.h> -#include <linux/if_bonding.h> -#include <linux/watchdog.h> - -#include <asm/module.h> -#include <asm/ioctl32.h> -#include <linux/soundcard.h> -#include <linux/lp.h> - -#include <linux/atm.h> -#include <linux/atmarp.h> -#include <linux/atmclip.h> -#include <linux/atmdev.h> -#include <linux/atmioc.h> -#include <linux/atmlec.h> -#include <linux/atmmpc.h> -#include <linux/atmsvc.h> -#include <linux/atm_tcp.h> -#include <linux/sonet.h> -#include <linux/atm_suni.h> -#include <linux/mtd/mtd.h> - -#include <net/bluetooth/bluetooth.h> -#include <net/bluetooth/hci.h> - -#include <linux/usb.h> -#include <linux/usbdevice_fs.h> -#include <linux/nbd.h> -#include <linux/random.h> -#include <linux/filter.h> - +#define INCLUDES +#include "compat_ioctl.c" #include <asm/mtrr.h> - -/* Aiee. Someone does not find a difference between int and long */ -#define EXT2_IOC32_GETFLAGS _IOR('f', 1, int) -#define EXT2_IOC32_SETFLAGS _IOW('f', 2, int) -#define EXT2_IOC32_GETVERSION _IOR('v', 1, int) -#define EXT2_IOC32_SETVERSION _IOW('v', 2, int) +#include <asm/ia32.h> extern asmlinkage long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); -static int w_long(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - int err; - unsigned long val; - - set_fs (KERNEL_DS); - err = sys_ioctl(fd, cmd, (unsigned long)&val); - set_fs (old_fs); - if (!err && put_user(val, (u32 *)arg)) - return -EFAULT; - return err; -} - -static int rw_long(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - int err; - unsigned long val; - - if(get_user(val, (u32 *)arg)) - return -EFAULT; - set_fs (KERNEL_DS); - err = sys_ioctl(fd, cmd, (unsigned long)&val); - set_fs (old_fs); - if (!err && put_user(val, (u32 *)arg)) - return -EFAULT; - return err; -} - -static int do_ext2_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - /* These are just misnamed, they actually get/put from/to user an int */ - switch (cmd) { - case EXT2_IOC32_GETFLAGS: cmd = EXT2_IOC_GETFLAGS; break; - case EXT2_IOC32_SETFLAGS: cmd = EXT2_IOC_SETFLAGS; break; - case EXT2_IOC32_GETVERSION: cmd = EXT2_IOC_GETVERSION; break; - case EXT2_IOC32_SETVERSION: cmd = EXT2_IOC_SETVERSION; break; - } - return sys_ioctl(fd, cmd, arg); -} - -struct video_tuner32 { - compat_int_t tuner; - char name[32]; - compat_ulong_t rangelow, rangehigh; - u32 flags; /* It is really u32 in videodev.h */ - u16 mode, signal; -}; - -static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 *up) -{ - int i; - - if(get_user(kp->tuner, &up->tuner)) - return -EFAULT; - for(i = 0; i < 32; i++) - __get_user(kp->name[i], &up->name[i]); - __get_user(kp->rangelow, &up->rangelow); - __get_user(kp->rangehigh, &up->rangehigh); - __get_user(kp->flags, &up->flags); - __get_user(kp->mode, &up->mode); - __get_user(kp->signal, &up->signal); - return 0; -} - -static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 *up) -{ - int i; - - if(put_user(kp->tuner, &up->tuner)) - return -EFAULT; - for(i = 0; i < 32; i++) - __put_user(kp->name[i], &up->name[i]); - __put_user(kp->rangelow, &up->rangelow); - __put_user(kp->rangehigh, &up->rangehigh); - __put_user(kp->flags, &up->flags); - __put_user(kp->mode, &up->mode); - __put_user(kp->signal, &up->signal); - return 0; -} - -struct video_buffer32 { - compat_caddr_t base; - compat_int_t height, width, depth, bytesperline; -}; - -static int get_video_buffer32(struct video_buffer *kp, struct video_buffer32 *up) -{ - u32 tmp; - - if(get_user(tmp, &up->base)) - return -EFAULT; - kp->base = (void *) ((unsigned long)tmp); - __get_user(kp->height, &up->height); - __get_user(kp->width, &up->width); - __get_user(kp->depth, &up->depth); - __get_user(kp->bytesperline, &up->bytesperline); - return 0; -} - -static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 *up) -{ - u32 tmp = (u32)((unsigned long)kp->base); - - if(put_user(tmp, &up->base)) - return -EFAULT; - __put_user(kp->height, &up->height); - __put_user(kp->width, &up->width); - __put_user(kp->depth, &up->depth); - __put_user(kp->bytesperline, &up->bytesperline); - return 0; -} - -struct video_clip32 { - s32 x, y, width, height; /* Its really s32 in videodev.h */ - compat_caddr_t next; -}; - -struct video_window32 { - u32 x, y, width, height, chromakey, flags; - compat_caddr_t clips; - compat_int_t clipcount; -}; - -static void free_kvideo_clips(struct video_window *kp) -{ - struct video_clip *cp; - - cp = kp->clips; - if(cp != NULL) - kfree(cp); -} - -static int get_video_window32(struct video_window *kp, struct video_window32 *up) -{ - struct video_clip32 *ucp; - struct video_clip *kcp; - int nclips, err, i; - u32 tmp; - - if(get_user(kp->x, &up->x)) - return -EFAULT; - __get_user(kp->y, &up->y); - __get_user(kp->width, &up->width); - __get_user(kp->height, &up->height); - __get_user(kp->chromakey, &up->chromakey); - __get_user(kp->flags, &up->flags); - __get_user(kp->clipcount, &up->clipcount); - __get_user(tmp, &up->clips); - ucp = compat_ptr(tmp); - kp->clips = NULL; - - nclips = kp->clipcount; - if(nclips == 0) - return 0; - - if(ucp == 0) - return -EINVAL; - - /* Peculiar interface... */ - if(nclips < 0) - nclips = VIDEO_CLIPMAP_SIZE; - - kcp = kmalloc(nclips * sizeof(struct video_clip), GFP_KERNEL); - err = -ENOMEM; - if(kcp == NULL) - goto cleanup_and_err; - - kp->clips = kcp; - for(i = 0; i < nclips; i++) { - __get_user(kcp[i].x, &ucp[i].x); - __get_user(kcp[i].y, &ucp[i].y); - __get_user(kcp[i].width, &ucp[i].width); - __get_user(kcp[i].height, &ucp[i].height); - kcp[nclips].next = NULL; - } - - return 0; - -cleanup_and_err: - free_kvideo_clips(kp); - return err; -} - -/* You get back everything except the clips... */ -static int put_video_window32(struct video_window *kp, struct video_window32 *up) -{ - if(put_user(kp->x, &up->x)) - return -EFAULT; - __put_user(kp->y, &up->y); - __put_user(kp->width, &up->width); - __put_user(kp->height, &up->height); - __put_user(kp->chromakey, &up->chromakey); - __put_user(kp->flags, &up->flags); - __put_user(kp->clipcount, &up->clipcount); - return 0; -} - -#define VIDIOCGTUNER32 _IOWR('v',4, struct video_tuner32) -#define VIDIOCSTUNER32 _IOW('v',5, struct video_tuner32) -#define VIDIOCGWIN32 _IOR('v',9, struct video_window32) -#define VIDIOCSWIN32 _IOW('v',10, struct video_window32) -#define VIDIOCGFBUF32 _IOR('v',11, struct video_buffer32) -#define VIDIOCSFBUF32 _IOW('v',12, struct video_buffer32) -#define VIDIOCGFREQ32 _IOR('v',14, u32) -#define VIDIOCSFREQ32 _IOW('v',15, u32) - -static int do_video_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - union { - struct video_tuner vt; - struct video_buffer vb; - struct video_window vw; - unsigned long vx; - } karg; - mm_segment_t old_fs = get_fs(); - void *up = (void *)arg; - int err = 0; - - /* First, convert the command. */ - switch(cmd) { - case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break; - case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break; - case VIDIOCGWIN32: cmd = VIDIOCGWIN; break; - case VIDIOCSWIN32: cmd = VIDIOCSWIN; break; - case VIDIOCGFBUF32: cmd = VIDIOCGFBUF; break; - case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break; - case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break; - case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break; - }; - - switch(cmd) { - case VIDIOCSTUNER: - case VIDIOCGTUNER: - err = get_video_tuner32(&karg.vt, up); - break; - - case VIDIOCSWIN: - err = get_video_window32(&karg.vw, up); - break; - - case VIDIOCSFBUF: - err = get_video_buffer32(&karg.vb, up); - break; - - case VIDIOCSFREQ: - err = get_user(karg.vx, (u32 *)up); - break; - }; - if(err) - goto out; - - set_fs(KERNEL_DS); - err = sys_ioctl(fd, cmd, (unsigned long)&karg); - set_fs(old_fs); - - if(cmd == VIDIOCSWIN) - free_kvideo_clips(&karg.vw); - - if(err == 0) { - switch(cmd) { - case VIDIOCGTUNER: - err = put_video_tuner32(&karg.vt, up); - break; - - case VIDIOCGWIN: - err = put_video_window32(&karg.vw, up); - break; - - case VIDIOCGFBUF: - err = put_video_buffer32(&karg.vb, up); - break; - - case VIDIOCGFREQ: - err = put_user(((u32)karg.vx), (u32 *)up); - break; - }; - } -out: - return err; -} - -static int do_siocgstamp(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct compat_timeval *up = (struct compat_timeval *)arg; - struct timeval ktv; - mm_segment_t old_fs = get_fs(); - int err; - - set_fs(KERNEL_DS); - err = sys_ioctl(fd, cmd, (unsigned long)&ktv); - set_fs(old_fs); - if(!err) { - err = put_user(ktv.tv_sec, &up->tv_sec); - err |= __put_user(ktv.tv_usec, &up->tv_usec); - } - return err; -} - -struct ifmap32 { - compat_ulong_t mem_start; - compat_ulong_t mem_end; - unsigned short base_addr; - unsigned char irq; - unsigned char dma; - unsigned char port; -}; - -struct ifreq32 { -#define IFHWADDRLEN 6 -#define IFNAMSIZ 16 - union { - char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ - } ifr_ifrn; - union { - struct sockaddr ifru_addr; - struct sockaddr ifru_dstaddr; - struct sockaddr ifru_broadaddr; - struct sockaddr ifru_netmask; - struct sockaddr ifru_hwaddr; - short ifru_flags; - compat_int_t ifru_ivalue; - compat_int_t ifru_mtu; - struct ifmap32 ifru_map; - char ifru_slave[IFNAMSIZ]; /* Just fits the size */ - char ifru_newname[IFNAMSIZ]; - compat_caddr_t ifru_data; - /* XXXX? ifru_settings should be here */ - } ifr_ifru; -}; - -struct ifconf32 { - compat_int_t ifc_len; /* size of buffer */ - compat_caddr_t ifcbuf; -}; - -#ifdef CONFIG_NET -static int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct net_device *dev; - struct ifreq32 ifr32; - int err; - - if (copy_from_user(&ifr32, (struct ifreq32 *)arg, sizeof(struct ifreq32))) - return -EFAULT; - - dev = dev_get_by_index(ifr32.ifr_ifindex); - if (!dev) - return -ENODEV; - - strlcpy(ifr32.ifr_name, dev->name, sizeof(ifr32.ifr_name)); - dev_put(dev); - - err = copy_to_user((struct ifreq32 *)arg, &ifr32, sizeof(struct ifreq32)); - return (err ? -EFAULT : 0); -} -#endif - -static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct ifconf32 ifc32; - struct ifconf ifc; - struct ifreq32 *ifr32; - struct ifreq *ifr; - mm_segment_t old_fs; - unsigned int i, j; - int err; - - if (copy_from_user(&ifc32, (struct ifconf32 *)arg, sizeof(struct ifconf32))) - return -EFAULT; - - if(ifc32.ifcbuf == 0) { - ifc32.ifc_len = 0; - ifc.ifc_len = 0; - ifc.ifc_buf = NULL; - } else { - ifc.ifc_len = ((ifc32.ifc_len / sizeof (struct ifreq32)) + 1) * - sizeof (struct ifreq); - ifc.ifc_buf = kmalloc (ifc.ifc_len, GFP_KERNEL); - if (!ifc.ifc_buf) - return -ENOMEM; - } - ifr = ifc.ifc_req; - ifr32 = compat_ptr(ifc32.ifcbuf); - for (i = 0; i < ifc32.ifc_len; i += sizeof (struct ifreq32)) { - if (copy_from_user(ifr, ifr32, sizeof (struct ifreq32))) { - kfree (ifc.ifc_buf); - return -EFAULT; - } - ifr++; - ifr32++; - } - old_fs = get_fs(); set_fs (KERNEL_DS); - err = sys_ioctl (fd, SIOCGIFCONF, (unsigned long)&ifc); - set_fs (old_fs); - if (!err) { - ifr = ifc.ifc_req; - ifr32 = compat_ptr(ifc32.ifcbuf); - for (i = 0, j = 0; i < ifc32.ifc_len && j < ifc.ifc_len; - i += sizeof (struct ifreq32), j += sizeof (struct ifreq)) { - int k = copy_to_user(ifr32, ifr, sizeof (struct ifreq32)); - ifr32++; - ifr++; - if (k) { - err = -EFAULT; - break; - } - - } - if (!err) { - if (ifc32.ifcbuf == 0) { - /* Translate from 64-bit structure multiple to - * a 32-bit one. - */ - i = ifc.ifc_len; - i = ((i / sizeof(struct ifreq)) * sizeof(struct ifreq32)); - ifc32.ifc_len = i; - } else { - if (i <= ifc32.ifc_len) - ifc32.ifc_len = i; - else - ifc32.ifc_len = i - sizeof (struct ifreq32); - } - if (copy_to_user((struct ifconf32 *)arg, &ifc32, sizeof(struct ifconf32))) - err = -EFAULT; - } - } - if(ifc.ifc_buf != NULL) - kfree (ifc.ifc_buf); - return err; -} - -static int ethtool_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct ifreq ifr; - mm_segment_t old_fs; - int err, len; - u32 data, ethcmd; - - if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32))) - return -EFAULT; - ifr.ifr_data = (__kernel_caddr_t)get_zeroed_page(GFP_KERNEL); - if (!ifr.ifr_data) - return -EAGAIN; - - __get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data)); - - if (get_user(ethcmd, (u32 *)compat_ptr(data))) { - err = -EFAULT; - goto out; - } - switch (ethcmd) { - case ETHTOOL_GDRVINFO: len = sizeof(struct ethtool_drvinfo); break; - case ETHTOOL_GMSGLVL: - case ETHTOOL_SMSGLVL: - case ETHTOOL_GLINK: - case ETHTOOL_NWAY_RST: len = sizeof(struct ethtool_value); break; - case ETHTOOL_GREGS: { - struct ethtool_regs *regaddr = compat_ptr(data); - /* darned variable size arguments */ - if (get_user(len, (u32 *)®addr->len)) { - err = -EFAULT; - goto out; - } - if (len > PAGE_SIZE - sizeof(struct ethtool_regs)) { - err = -EINVAL; - goto out; - } - len += sizeof(struct ethtool_regs); - break; - } - case ETHTOOL_GSET: - case ETHTOOL_SSET: len = sizeof(struct ethtool_cmd); break; - default: - err = -EOPNOTSUPP; - goto out; - } - - if (copy_from_user(ifr.ifr_data, compat_ptr(data), len)) { - err = -EFAULT; - goto out; - } - - old_fs = get_fs(); - set_fs (KERNEL_DS); - err = sys_ioctl (fd, cmd, (unsigned long)&ifr); - set_fs (old_fs); - if (!err) { - u32 data; - - __get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data)); - len = copy_to_user(compat_ptr(data), ifr.ifr_data, len); - if (len) - err = -EFAULT; - } - -out: - free_page((unsigned long)ifr.ifr_data); - return err; -} - - -static int bond_ioctl(unsigned long fd, unsigned int cmd, unsigned long arg) -{ - struct ifreq ifr; - mm_segment_t old_fs; - int err, len; - u32 data; - - if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32))) - return -EFAULT; - ifr.ifr_data = (__kernel_caddr_t)get_zeroed_page(GFP_KERNEL); - if (!ifr.ifr_data) - return -EAGAIN; - - switch (cmd) { - case SIOCBONDENSLAVE: - case SIOCBONDRELEASE: - case SIOCBONDSETHWADDR: - case SIOCBONDCHANGEACTIVE: - len = IFNAMSIZ * sizeof(char); - break; - case SIOCBONDSLAVEINFOQUERY: - len = sizeof(struct ifslave); - break; - case SIOCBONDINFOQUERY: - len = sizeof(struct ifbond); - break; - default: - err = -EINVAL; - goto out; - }; - - __get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data)); - if (copy_from_user(ifr.ifr_data, compat_ptr(data), len)) { - err = -EFAULT; - goto out; - } - - old_fs = get_fs(); - set_fs (KERNEL_DS); - err = sys_ioctl (fd, cmd, (unsigned long)&ifr); - set_fs (old_fs); - if (!err) { - len = copy_to_user(compat_ptr(data), ifr.ifr_data, len); - if (len) - err = -EFAULT; - } - -out: - free_page((unsigned long)ifr.ifr_data); - return err; -} - -int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct ifreq *u_ifreq64; - struct ifreq32 *u_ifreq32 = (struct ifreq32 *) arg; - char tmp_buf[IFNAMSIZ]; - void *data64; - u32 data32; - - if (copy_from_user(&tmp_buf[0], &(u_ifreq32->ifr_ifrn.ifrn_name[0]), - IFNAMSIZ)) - return -EFAULT; - if (__get_user(data32, &u_ifreq32->ifr_ifru.ifru_data)) - return -EFAULT; - data64 = compat_ptr(data32); - - u_ifreq64 = compat_alloc_user_space(sizeof(*u_ifreq64)); - - /* Don't check these user accesses, just let that get trapped - * in the ioctl handler instead. - */ - copy_to_user(&u_ifreq64->ifr_ifrn.ifrn_name[0], &tmp_buf[0], IFNAMSIZ); - __put_user(data64, &u_ifreq64->ifr_ifru.ifru_data); - - return sys_ioctl(fd, cmd, (unsigned long) u_ifreq64); -} - -static int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct ifreq ifr; - mm_segment_t old_fs; - int err; - - switch (cmd) { - case SIOCSIFMAP: - err = copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(ifr.ifr_name)); - err |= __get_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_start)); - err |= __get_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_end)); - err |= __get_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.base_addr)); - err |= __get_user(ifr.ifr_map.irq, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.irq)); - err |= __get_user(ifr.ifr_map.dma, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.dma)); - err |= __get_user(ifr.ifr_map.port, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.port)); - if (err) - return -EFAULT; - break; - default: - if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32))) - return -EFAULT; - break; - } - old_fs = get_fs(); - set_fs (KERNEL_DS); - err = sys_ioctl (fd, cmd, (unsigned long)&ifr); - set_fs (old_fs); - if (!err) { - switch (cmd) { - case SIOCGIFFLAGS: - case SIOCGIFMETRIC: - case SIOCGIFMTU: - case SIOCGIFMEM: - case SIOCGIFHWADDR: - case SIOCGIFINDEX: - case SIOCGIFADDR: - case SIOCGIFBRDADDR: - case SIOCGIFDSTADDR: - case SIOCGIFNETMASK: - case SIOCGIFTXQLEN: - if (copy_to_user((struct ifreq32 *)arg, &ifr, sizeof(struct ifreq32))) - return -EFAULT; - break; - case SIOCGIFMAP: - err = copy_to_user((struct ifreq32 *)arg, &ifr, sizeof(ifr.ifr_name)); - err |= __put_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_start)); - err |= __put_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_end)); - err |= __put_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.base_addr)); - err |= __put_user(ifr.ifr_map.irq, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.irq)); - err |= __put_user(ifr.ifr_map.dma, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.dma)); - err |= __put_user(ifr.ifr_map.port, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.port)); - if (err) - err = -EFAULT; - break; - } - } - return err; -} - -struct rtentry32 { - u32 rt_pad1; - struct sockaddr rt_dst; /* target address */ - struct sockaddr rt_gateway; /* gateway addr (RTF_GATEWAY) */ - struct sockaddr rt_genmask; /* target network mask (IP) */ - unsigned short rt_flags; - short rt_pad2; - u32 rt_pad3; - unsigned char rt_tos; - unsigned char rt_class; - short rt_pad4; - short rt_metric; /* +1 for binary compatibility! */ - /* char * */ u32 rt_dev; /* forcing the device at add */ - u32 rt_mtu; /* per route MTU/Window */ - u32 rt_window; /* Window clamping */ - unsigned short rt_irtt; /* Initial RTT */ - -}; - -struct in6_rtmsg32 { - struct in6_addr rtmsg_dst; - struct in6_addr rtmsg_src; - struct in6_addr rtmsg_gateway; - u32 rtmsg_type; - u16 rtmsg_dst_len; - u16 rtmsg_src_len; - u32 rtmsg_metric; - u32 rtmsg_info; - u32 rtmsg_flags; - s32 rtmsg_ifindex; -}; - -static int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - int ret; - void *r = NULL; - struct in6_rtmsg r6; - struct rtentry r4; - char devname[16]; - u32 rtdev; - mm_segment_t old_fs = get_fs(); - - struct socket *mysock = sockfd_lookup(fd, &ret); - - if (mysock && mysock->sk && mysock->sk->family == AF_INET6) { /* ipv6 */ - ret = copy_from_user (&r6.rtmsg_dst, &(((struct in6_rtmsg32 *)arg)->rtmsg_dst), - 3 * sizeof(struct in6_addr)); - ret |= __get_user (r6.rtmsg_type, &(((struct in6_rtmsg32 *)arg)->rtmsg_type)); - ret |= __get_user (r6.rtmsg_dst_len, &(((struct in6_rtmsg32 *)arg)->rtmsg_dst_len)); - ret |= __get_user (r6.rtmsg_src_len, &(((struct in6_rtmsg32 *)arg)->rtmsg_src_len)); - ret |= __get_user (r6.rtmsg_metric, &(((struct in6_rtmsg32 *)arg)->rtmsg_metric)); - ret |= __get_user (r6.rtmsg_info, &(((struct in6_rtmsg32 *)arg)->rtmsg_info)); - ret |= __get_user (r6.rtmsg_flags, &(((struct in6_rtmsg32 *)arg)->rtmsg_flags)); - ret |= __get_user (r6.rtmsg_ifindex, &(((struct in6_rtmsg32 *)arg)->rtmsg_ifindex)); - - r = (void *) &r6; - } else { /* ipv4 */ - ret = copy_from_user (&r4.rt_dst, &(((struct rtentry32 *)arg)->rt_dst), 3 * sizeof(struct sockaddr)); - ret |= __get_user (r4.rt_flags, &(((struct rtentry32 *)arg)->rt_flags)); - ret |= __get_user (r4.rt_metric, &(((struct rtentry32 *)arg)->rt_metric)); - ret |= __get_user (r4.rt_mtu, &(((struct rtentry32 *)arg)->rt_mtu)); - ret |= __get_user (r4.rt_window, &(((struct rtentry32 *)arg)->rt_window)); - ret |= __get_user (r4.rt_irtt, &(((struct rtentry32 *)arg)->rt_irtt)); - ret |= __get_user (rtdev, &(((struct rtentry32 *)arg)->rt_dev)); - if (rtdev) { - ret |= copy_from_user (devname, compat_ptr(rtdev), 15); - r4.rt_dev = devname; devname[15] = 0; - } else - r4.rt_dev = 0; - - r = (void *) &r4; - } - - if (ret) - return -EFAULT; - - set_fs (KERNEL_DS); - ret = sys_ioctl (fd, cmd, (long) r); - set_fs (old_fs); - - if (mysock) - sockfd_put(mysock); - - return ret; -} - -struct hd_geometry32 { - unsigned char heads; - unsigned char sectors; - unsigned short cylinders; - u32 start; -}; - -static int hdio_getgeo(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - struct hd_geometry geo; - int err; - - set_fs (KERNEL_DS); - err = sys_ioctl(fd, HDIO_GETGEO, (unsigned long)&geo); - set_fs (old_fs); - if (!err) { - err = copy_to_user ((struct hd_geometry32 *)arg, &geo, 4); - err |= __put_user (geo.start, &(((struct hd_geometry32 *)arg)->start)); - } - return err ? -EFAULT : 0; -} - -struct fb_fix_screeninfo32 { - char id[16]; - compat_caddr_t smem_start; - u32 smem_len; - u32 type; - u32 type_aux; - u32 visual; - u16 xpanstep; - u16 ypanstep; - u16 ywrapstep; - u32 line_length; - compat_caddr_t mmio_start; - u32 mmio_len; - u32 accel; - u16 reserved[3]; -}; - -struct fb_cmap32 { - u32 start; - u32 len; - compat_caddr_t red; - compat_caddr_t green; - compat_caddr_t blue; - compat_caddr_t transp; -}; - -static int fb_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - u32 red = 0, green = 0, blue = 0, transp = 0; - struct fb_fix_screeninfo fix; - struct fb_cmap cmap; - void *karg; - int err = 0; - - memset(&cmap, 0, sizeof(cmap)); - switch (cmd) { - case FBIOGET_FSCREENINFO: - karg = &fix; - break; - case FBIOGETCMAP: - case FBIOPUTCMAP: - karg = &cmap; - err = __get_user(cmap.start, &((struct fb_cmap32 *)arg)->start); - err |= __get_user(cmap.len, &((struct fb_cmap32 *)arg)->len); - err |= __get_user(red, &((struct fb_cmap32 *)arg)->red); - err |= __get_user(green, &((struct fb_cmap32 *)arg)->green); - err |= __get_user(blue, &((struct fb_cmap32 *)arg)->blue); - err |= __get_user(transp, &((struct fb_cmap32 *)arg)->transp); - if (err) { - err = -EFAULT; - goto out; - } - if (cmap.len > PAGE_SIZE/sizeof(u16)) { - err = -EINVAL; - goto out; - } - err = -ENOMEM; - cmap.red = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL); - if (!cmap.red) - goto out; - cmap.green = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL); - if (!cmap.green) - goto out; - cmap.blue = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL); - if (!cmap.blue) - goto out; - if (transp) { - cmap.transp = kmalloc(cmap.len * sizeof(__u16), GFP_KERNEL); - if (!cmap.transp) - goto out; - } - - if (cmd == FBIOGETCMAP) - break; - - err = __copy_from_user(cmap.red, compat_ptr(red), cmap.len * sizeof(__u16)); - err |= __copy_from_user(cmap.green, compat_ptr(green), cmap.len * sizeof(__u16)); - err |= __copy_from_user(cmap.blue, compat_ptr(blue), cmap.len * sizeof(__u16)); - if (cmap.transp) err |= __copy_from_user(cmap.transp, compat_ptr(transp), cmap.len * sizeof(__u16)); - if (err) { - err = -EFAULT; - goto out; - } - break; - default: - do { - static int count; - if (++count <= 20) - printk("%s: Unknown fb ioctl cmd fd(%d) " - "cmd(%08x) arg(%08lx)\n", - __FUNCTION__, fd, cmd, arg); - } while(0); - return -ENOSYS; - } - set_fs(KERNEL_DS); - err = sys_ioctl(fd, cmd, (unsigned long)karg); - set_fs(old_fs); - if (err) - goto out; - switch (cmd) { - case FBIOGET_FSCREENINFO: - err = __copy_to_user((char *)((struct fb_fix_screeninfo32 *)arg)->id, (char *)fix.id, sizeof(fix.id)); - err |= __put_user((__u32)(unsigned long)fix.smem_start, &((struct fb_fix_screeninfo32 *)arg)->smem_start); - err |= __put_user(fix.smem_len, &((struct fb_fix_screeninfo32 *)arg)->smem_len); - err |= __put_user(fix.type, &((struct fb_fix_screeninfo32 *)arg)->type); - err |= __put_user(fix.type_aux, &((struct fb_fix_screeninfo32 *)arg)->type_aux); - err |= __put_user(fix.visual, &((struct fb_fix_screeninfo32 *)arg)->visual); - err |= __put_user(fix.xpanstep, &((struct fb_fix_screeninfo32 *)arg)->xpanstep); - err |= __put_user(fix.ypanstep, &((struct fb_fix_screeninfo32 *)arg)->ypanstep); - err |= __put_user(fix.ywrapstep, &((struct fb_fix_screeninfo32 *)arg)->ywrapstep); - err |= __put_user(fix.line_length, &((struct fb_fix_screeninfo32 *)arg)->line_length); - err |= __put_user((__u32)(unsigned long)fix.mmio_start, &((struct fb_fix_screeninfo32 *)arg)->mmio_start); - err |= __put_user(fix.mmio_len, &((struct fb_fix_screeninfo32 *)arg)->mmio_len); - err |= __put_user(fix.accel, &((struct fb_fix_screeninfo32 *)arg)->accel); - err |= __copy_to_user((char *)((struct fb_fix_screeninfo32 *)arg)->reserved, (char *)fix.reserved, sizeof(fix.reserved)); - break; - case FBIOGETCMAP: - err = __copy_to_user(compat_ptr(red), cmap.red, cmap.len * sizeof(__u16)); - err |= __copy_to_user(compat_ptr(green), cmap.blue, cmap.len * sizeof(__u16)); - err |= __copy_to_user(compat_ptr(blue), cmap.blue, cmap.len * sizeof(__u16)); - if (cmap.transp) - err |= __copy_to_user(compat_ptr(transp), cmap.transp, cmap.len * sizeof(__u16)); - break; - case FBIOPUTCMAP: - break; - } - if (err) - err = -EFAULT; - -out: if (cmap.red) kfree(cmap.red); - if (cmap.green) kfree(cmap.green); - if (cmap.blue) kfree(cmap.blue); - if (cmap.transp) kfree(cmap.transp); - return err; -} - -static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - unsigned long kval; - unsigned int *uvp; - int error; - - set_fs(KERNEL_DS); - error = sys_ioctl(fd, cmd, (long)&kval); - set_fs(old_fs); - - if(error == 0) { - uvp = (unsigned int *)arg; - if(put_user(kval, uvp)) - error = -EFAULT; - } - return error; -} - -struct floppy_struct32 { - compat_uint_t size; - compat_uint_t sect; - compat_uint_t head; - compat_uint_t track; - compat_uint_t stretch; - unsigned char gap; - unsigned char rate; - unsigned char spec1; - unsigned char fmt_gap; - const compat_caddr_t name; -}; - -struct floppy_drive_params32 { - char cmos; - compat_ulong_t max_dtr; - compat_ulong_t hlt; - compat_ulong_t hut; - compat_ulong_t srt; - compat_ulong_t spinup; - compat_ulong_t spindown; - unsigned char spindown_offset; - unsigned char select_delay; - unsigned char rps; - unsigned char tracks; - compat_ulong_t timeout; - unsigned char interleave_sect; - struct floppy_max_errors max_errors; - char flags; - char read_track; - short autodetect[8]; - compat_int_t checkfreq; - compat_int_t native_format; -}; - -struct floppy_drive_struct32 { - signed char flags; - compat_ulong_t spinup_date; - compat_ulong_t select_date; - compat_ulong_t first_read_date; - short probed_format; - short track; - short maxblock; - short maxtrack; - compat_int_t generation; - compat_int_t keep_data; - compat_int_t fd_ref; - compat_int_t fd_device; - compat_int_t last_checked; - compat_caddr_t dmabuf; - compat_int_t bufblocks; -}; - -struct floppy_fdc_state32 { - compat_int_t spec1; - compat_int_t spec2; - compat_int_t dtr; - unsigned char version; - unsigned char dor; - compat_ulong_t address; - unsigned int rawcmd:2; - unsigned int reset:1; - unsigned int need_configure:1; - unsigned int perp_mode:2; - unsigned int has_fifo:1; - unsigned int driver_version; - unsigned char track[4]; -}; - -struct floppy_write_errors32 { - unsigned int write_errors; - compat_ulong_t first_error_sector; - compat_int_t first_error_generation; - compat_ulong_t last_error_sector; - compat_int_t last_error_generation; - compat_uint_t badness; -}; - -#define FDSETPRM32 _IOW(2, 0x42, struct floppy_struct32) -#define FDDEFPRM32 _IOW(2, 0x43, struct floppy_struct32) -#define FDGETPRM32 _IOR(2, 0x04, struct floppy_struct32) -#define FDSETDRVPRM32 _IOW(2, 0x90, struct floppy_drive_params32) -#define FDGETDRVPRM32 _IOR(2, 0x11, struct floppy_drive_params32) -#define FDGETDRVSTAT32 _IOR(2, 0x12, struct floppy_drive_struct32) -#define FDPOLLDRVSTAT32 _IOR(2, 0x13, struct floppy_drive_struct32) -#define FDGETFDCSTAT32 _IOR(2, 0x15, struct floppy_fdc_state32) -#define FDWERRORGET32 _IOR(2, 0x17, struct floppy_write_errors32) - -static struct { - unsigned int cmd32; - unsigned int cmd; -} fd_ioctl_trans_table[] = { - { FDSETPRM32, FDSETPRM }, - { FDDEFPRM32, FDDEFPRM }, - { FDGETPRM32, FDGETPRM }, - { FDSETDRVPRM32, FDSETDRVPRM }, - { FDGETDRVPRM32, FDGETDRVPRM }, - { FDGETDRVSTAT32, FDGETDRVSTAT }, - { FDPOLLDRVSTAT32, FDPOLLDRVSTAT }, - { FDGETFDCSTAT32, FDGETFDCSTAT }, - { FDWERRORGET32, FDWERRORGET } -}; - -#define NR_FD_IOCTL_TRANS (sizeof(fd_ioctl_trans_table)/sizeof(fd_ioctl_trans_table[0])) - -static int fd_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - void *karg = NULL; - unsigned int kcmd = 0; - int i, err; - - for (i = 0; i < NR_FD_IOCTL_TRANS; i++) - if (cmd == fd_ioctl_trans_table[i].cmd32) { - kcmd = fd_ioctl_trans_table[i].cmd; - break; - } - if (!kcmd) - return -EINVAL; - - switch (cmd) { - case FDSETPRM32: - case FDDEFPRM32: - case FDGETPRM32: - { - struct floppy_struct *f; - - f = karg = kmalloc(sizeof(struct floppy_struct), GFP_KERNEL); - if (!karg) - return -ENOMEM; - if (cmd == FDGETPRM32) - break; - err = __get_user(f->size, &((struct floppy_struct32 *)arg)->size); - err |= __get_user(f->sect, &((struct floppy_struct32 *)arg)->sect); - err |= __get_user(f->head, &((struct floppy_struct32 *)arg)->head); - err |= __get_user(f->track, &((struct floppy_struct32 *)arg)->track); - err |= __get_user(f->stretch, &((struct floppy_struct32 *)arg)->stretch); - err |= __get_user(f->gap, &((struct floppy_struct32 *)arg)->gap); - err |= __get_user(f->rate, &((struct floppy_struct32 *)arg)->rate); - err |= __get_user(f->spec1, &((struct floppy_struct32 *)arg)->spec1); - err |= __get_user(f->fmt_gap, &((struct floppy_struct32 *)arg)->fmt_gap); - err |= __get_user((u64)f->name, &((struct floppy_struct32 *)arg)->name); - if (err) { - err = -EFAULT; - goto out; - } - break; - } - case FDSETDRVPRM32: - case FDGETDRVPRM32: - { - struct floppy_drive_params *f; - - f = karg = kmalloc(sizeof(struct floppy_drive_params), GFP_KERNEL); - if (!karg) - return -ENOMEM; - if (cmd == FDGETDRVPRM32) - break; - err = __get_user(f->cmos, &((struct floppy_drive_params32 *)arg)->cmos); - err |= __get_user(f->max_dtr, &((struct floppy_drive_params32 *)arg)->max_dtr); - err |= __get_user(f->hlt, &((struct floppy_drive_params32 *)arg)->hlt); - err |= __get_user(f->hut, &((struct floppy_drive_params32 *)arg)->hut); - err |= __get_user(f->srt, &((struct floppy_drive_params32 *)arg)->srt); - err |= __get_user(f->spinup, &((struct floppy_drive_params32 *)arg)->spinup); - err |= __get_user(f->spindown, &((struct floppy_drive_params32 *)arg)->spindown); - err |= __get_user(f->spindown_offset, &((struct floppy_drive_params32 *)arg)->spindown_offset); - err |= __get_user(f->select_delay, &((struct floppy_drive_params32 *)arg)->select_delay); - err |= __get_user(f->rps, &((struct floppy_drive_params32 *)arg)->rps); - err |= __get_user(f->tracks, &((struct floppy_drive_params32 *)arg)->tracks); - err |= __get_user(f->timeout, &((struct floppy_drive_params32 *)arg)->timeout); - err |= __get_user(f->interleave_sect, &((struct floppy_drive_params32 *)arg)->interleave_sect); - err |= __copy_from_user(&f->max_errors, &((struct floppy_drive_params32 *)arg)->max_errors, sizeof(f->max_errors)); - err |= __get_user(f->flags, &((struct floppy_drive_params32 *)arg)->flags); - err |= __get_user(f->read_track, &((struct floppy_drive_params32 *)arg)->read_track); - err |= __copy_from_user(f->autodetect, ((struct floppy_drive_params32 *)arg)->autodetect, sizeof(f->autodetect)); - err |= __get_user(f->checkfreq, &((struct floppy_drive_params32 *)arg)->checkfreq); - err |= __get_user(f->native_format, &((struct floppy_drive_params32 *)arg)->native_format); - if (err) { - err = -EFAULT; - goto out; - } - break; - } - case FDGETDRVSTAT32: - case FDPOLLDRVSTAT32: - karg = kmalloc(sizeof(struct floppy_drive_struct), GFP_KERNEL); - if (!karg) - return -ENOMEM; - break; - case FDGETFDCSTAT32: - karg = kmalloc(sizeof(struct floppy_fdc_state), GFP_KERNEL); - if (!karg) - return -ENOMEM; - break; - case FDWERRORGET32: - karg = kmalloc(sizeof(struct floppy_write_errors), GFP_KERNEL); - if (!karg) - return -ENOMEM; - break; - default: - return -EINVAL; - } - set_fs (KERNEL_DS); - err = sys_ioctl (fd, kcmd, (unsigned long)karg); - set_fs (old_fs); - if (err) - goto out; - switch (cmd) { - case FDGETPRM32: - { - struct floppy_struct *f = karg; - - err = __put_user(f->size, &((struct floppy_struct32 *)arg)->size); - err |= __put_user(f->sect, &((struct floppy_struct32 *)arg)->sect); - err |= __put_user(f->head, &((struct floppy_struct32 *)arg)->head); - err |= __put_user(f->track, &((struct floppy_struct32 *)arg)->track); - err |= __put_user(f->stretch, &((struct floppy_struct32 *)arg)->stretch); - err |= __put_user(f->gap, &((struct floppy_struct32 *)arg)->gap); - err |= __put_user(f->rate, &((struct floppy_struct32 *)arg)->rate); - err |= __put_user(f->spec1, &((struct floppy_struct32 *)arg)->spec1); - err |= __put_user(f->fmt_gap, &((struct floppy_struct32 *)arg)->fmt_gap); - err |= __put_user((u64)f->name, &((struct floppy_struct32 *)arg)->name); - break; - } - case FDGETDRVPRM32: - { - struct floppy_drive_params *f = karg; - - err = __put_user(f->cmos, &((struct floppy_drive_params32 *)arg)->cmos); - err |= __put_user(f->max_dtr, &((struct floppy_drive_params32 *)arg)->max_dtr); - err |= __put_user(f->hlt, &((struct floppy_drive_params32 *)arg)->hlt); - err |= __put_user(f->hut, &((struct floppy_drive_params32 *)arg)->hut); - err |= __put_user(f->srt, &((struct floppy_drive_params32 *)arg)->srt); - err |= __put_user(f->spinup, &((struct floppy_drive_params32 *)arg)->spinup); - err |= __put_user(f->spindown, &((struct floppy_drive_params32 *)arg)->spindown); - err |= __put_user(f->spindown_offset, &((struct floppy_drive_params32 *)arg)->spindown_offset); - err |= __put_user(f->select_delay, &((struct floppy_drive_params32 *)arg)->select_delay); - err |= __put_user(f->rps, &((struct floppy_drive_params32 *)arg)->rps); - err |= __put_user(f->tracks, &((struct floppy_drive_params32 *)arg)->tracks); - err |= __put_user(f->timeout, &((struct floppy_drive_params32 *)arg)->timeout); - err |= __put_user(f->interleave_sect, &((struct floppy_drive_params32 *)arg)->interleave_sect); - err |= __copy_to_user(&((struct floppy_drive_params32 *)arg)->max_errors, &f->max_errors, sizeof(f->max_errors)); - err |= __put_user(f->flags, &((struct floppy_drive_params32 *)arg)->flags); - err |= __put_user(f->read_track, &((struct floppy_drive_params32 *)arg)->read_track); - err |= __copy_to_user(((struct floppy_drive_params32 *)arg)->autodetect, f->autodetect, sizeof(f->autodetect)); - err |= __put_user(f->checkfreq, &((struct floppy_drive_params32 *)arg)->checkfreq); - err |= __put_user(f->native_format, &((struct floppy_drive_params32 *)arg)->native_format); - break; - } - case FDGETDRVSTAT32: - case FDPOLLDRVSTAT32: - { - struct floppy_drive_struct *f = karg; - - err = __put_user(f->flags, &((struct floppy_drive_struct32 *)arg)->flags); - err |= __put_user(f->spinup_date, &((struct floppy_drive_struct32 *)arg)->spinup_date); - err |= __put_user(f->select_date, &((struct floppy_drive_struct32 *)arg)->select_date); - err |= __put_user(f->first_read_date, &((struct floppy_drive_struct32 *)arg)->first_read_date); - err |= __put_user(f->probed_format, &((struct floppy_drive_struct32 *)arg)->probed_format); - err |= __put_user(f->track, &((struct floppy_drive_struct32 *)arg)->track); - err |= __put_user(f->maxblock, &((struct floppy_drive_struct32 *)arg)->maxblock); - err |= __put_user(f->maxtrack, &((struct floppy_drive_struct32 *)arg)->maxtrack); - err |= __put_user(f->generation, &((struct floppy_drive_struct32 *)arg)->generation); - err |= __put_user(f->keep_data, &((struct floppy_drive_struct32 *)arg)->keep_data); - err |= __put_user(f->fd_ref, &((struct floppy_drive_struct32 *)arg)->fd_ref); - err |= __put_user(f->fd_device, &((struct floppy_drive_struct32 *)arg)->fd_device); - err |= __put_user(f->last_checked, &((struct floppy_drive_struct32 *)arg)->last_checked); - err |= __put_user((u64)f->dmabuf, &((struct floppy_drive_struct32 *)arg)->dmabuf); - err |= __put_user((u64)f->bufblocks, &((struct floppy_drive_struct32 *)arg)->bufblocks); - break; - } - case FDGETFDCSTAT32: - { - struct floppy_fdc_state *f = karg; - - err = __put_user(f->spec1, &((struct floppy_fdc_state32 *)arg)->spec1); - err |= __put_user(f->spec2, &((struct floppy_fdc_state32 *)arg)->spec2); - err |= __put_user(f->dtr, &((struct floppy_fdc_state32 *)arg)->dtr); - err |= __put_user(f->version, &((struct floppy_fdc_state32 *)arg)->version); - err |= __put_user(f->dor, &((struct floppy_fdc_state32 *)arg)->dor); - err |= __put_user(f->address, &((struct floppy_fdc_state32 *)arg)->address); - err |= __copy_to_user((char *)&((struct floppy_fdc_state32 *)arg)->address - + sizeof(((struct floppy_fdc_state32 *)arg)->address), - (char *)&f->address + sizeof(f->address), sizeof(int)); - err |= __put_user(f->driver_version, &((struct floppy_fdc_state32 *)arg)->driver_version); - err |= __copy_to_user(((struct floppy_fdc_state32 *)arg)->track, f->track, sizeof(f->track)); - break; - } - case FDWERRORGET32: - { - struct floppy_write_errors *f = karg; - - err = __put_user(f->write_errors, &((struct floppy_write_errors32 *)arg)->write_errors); - err |= __put_user(f->first_error_sector, &((struct floppy_write_errors32 *)arg)->first_error_sector); - err |= __put_user(f->first_error_generation, &((struct floppy_write_errors32 *)arg)->first_error_generation); - err |= __put_user(f->last_error_sector, &((struct floppy_write_errors32 *)arg)->last_error_sector); - err |= __put_user(f->last_error_generation, &((struct floppy_write_errors32 *)arg)->last_error_generation); - err |= __put_user(f->badness, &((struct floppy_write_errors32 *)arg)->badness); - break; - } - default: - break; - } - if (err) - err = -EFAULT; - -out: if (karg) kfree(karg); - return err; -} - - -typedef struct sg_io_hdr32 { - compat_int_t interface_id; /* [i] 'S' for SCSI generic (required) */ - compat_int_t dxfer_direction; /* [i] data transfer direction */ - unsigned char cmd_len; /* [i] SCSI command length ( <= 16 bytes) */ - unsigned char mx_sb_len; /* [i] max length to write to sbp */ - unsigned short iovec_count; /* [i] 0 implies no scatter gather */ - compat_uint_t dxfer_len; /* [i] byte count of data transfer */ - compat_uint_t dxferp; /* [i], [*io] points to data transfer memory - or scatter gather list */ - compat_uptr_t cmdp; /* [i], [*i] points to command to perform */ - compat_uptr_t sbp; /* [i], [*o] points to sense_buffer memory */ - compat_uint_t timeout; /* [i] MAX_UINT->no timeout (unit: millisec) */ - compat_uint_t flags; /* [i] 0 -> default, see SG_FLAG... */ - compat_int_t pack_id; /* [i->o] unused internally (normally) */ - compat_uptr_t usr_ptr; /* [i->o] unused internally */ - unsigned char status; /* [o] scsi status */ - unsigned char masked_status; /* [o] shifted, masked scsi status */ - unsigned char msg_status; /* [o] messaging level data (optional) */ - unsigned char sb_len_wr; /* [o] byte count actually written to sbp */ - unsigned short host_status; /* [o] errors from host adapter */ - unsigned short driver_status; /* [o] errors from software driver */ - compat_int_t resid; /* [o] dxfer_len - actual_transferred */ - compat_uint_t duration; /* [o] time taken by cmd (unit: millisec) */ - compat_uint_t info; /* [o] auxiliary information */ -} sg_io_hdr32_t; /* 64 bytes long (on sparc32) */ - -typedef struct sg_iovec32 { - compat_uint_t iov_base; - compat_uint_t iov_len; -} sg_iovec32_t; - -#define EMU_SG_MAX 128 - -static int alloc_sg_iovec(sg_io_hdr_t *sgp, u32 uptr32) -{ - sg_iovec32_t *uiov = compat_ptr(uptr32); - sg_iovec_t *kiov; - int i; - - if (sgp->iovec_count > EMU_SG_MAX) - return -EINVAL; - sgp->dxferp = kmalloc(sgp->iovec_count * - sizeof(sg_iovec_t), GFP_KERNEL); - if (!sgp->dxferp) - return -ENOMEM; - memset(sgp->dxferp, 0, - sgp->iovec_count * sizeof(sg_iovec_t)); - - kiov = (sg_iovec_t *) sgp->dxferp; - for (i = 0; i < sgp->iovec_count; i++) { - u32 iov_base32; - if (__get_user(iov_base32, &uiov->iov_base) || - __get_user(kiov->iov_len, &uiov->iov_len)) - return -EFAULT; - if (verify_area(VERIFY_WRITE, compat_ptr(iov_base32), kiov->iov_len)) - return -EFAULT; - kiov->iov_base = compat_ptr(iov_base32); - uiov++; - kiov++; - } - - return 0; -} - -static void free_sg_iovec(sg_io_hdr_t *sgp) -{ - kfree(sgp->dxferp); - sgp->dxferp = NULL; -} - -static int sg_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - sg_io_hdr32_t *sg_io32; - sg_io_hdr_t sg_io64; - u32 dxferp32, cmdp32, sbp32; - mm_segment_t old_fs; - int err = 0; - - sg_io32 = (sg_io_hdr32_t *)arg; - err = __get_user(sg_io64.interface_id, &sg_io32->interface_id); - err |= __get_user(sg_io64.dxfer_direction, &sg_io32->dxfer_direction); - err |= __get_user(sg_io64.cmd_len, &sg_io32->cmd_len); - err |= __get_user(sg_io64.mx_sb_len, &sg_io32->mx_sb_len); - err |= __get_user(sg_io64.iovec_count, &sg_io32->iovec_count); - err |= __get_user(sg_io64.dxfer_len, &sg_io32->dxfer_len); - err |= __get_user(sg_io64.timeout, &sg_io32->timeout); - err |= __get_user(sg_io64.flags, &sg_io32->flags); - err |= __get_user(sg_io64.pack_id, &sg_io32->pack_id); - - sg_io64.dxferp = NULL; - sg_io64.cmdp = NULL; - sg_io64.sbp = NULL; - - err |= __get_user(cmdp32, &sg_io32->cmdp); - sg_io64.cmdp = kmalloc(sg_io64.cmd_len, GFP_KERNEL); - if (copy_from_user(sg_io64.cmdp, - compat_ptr(cmdp32), - sg_io64.cmd_len)) { - err = -EFAULT; - goto out; - } - - err |= __get_user(sbp32, &sg_io32->sbp); - sg_io64.sbp = kmalloc(sg_io64.mx_sb_len, GFP_KERNEL); - if (!sg_io64.sbp) { - err = -ENOMEM; - goto out; - } - if (copy_from_user(sg_io64.sbp, - compat_ptr(sbp32), - sg_io64.mx_sb_len)) { - err = -EFAULT; - goto out; - } - - err |= __get_user(dxferp32, &sg_io32->dxferp); - if (sg_io64.iovec_count) { - int ret; - - if ((ret = alloc_sg_iovec(&sg_io64, dxferp32))) { - err = ret; - goto out; - } - } else { - err = verify_area(VERIFY_WRITE, compat_ptr(dxferp32), sg_io64.dxfer_len); - if (err) - goto out; - - sg_io64.dxferp = compat_ptr(dxferp32); - } - - /* Unused internally, do not even bother to copy it over. */ - sg_io64.usr_ptr = NULL; - - if (err) - return -EFAULT; - - old_fs = get_fs(); - set_fs (KERNEL_DS); - err = sys_ioctl (fd, cmd, (unsigned long) &sg_io64); - set_fs (old_fs); - - if (err < 0) - goto out; - - err = __put_user(sg_io64.pack_id, &sg_io32->pack_id); - err |= __put_user(sg_io64.status, &sg_io32->status); - err |= __put_user(sg_io64.masked_status, &sg_io32->masked_status); - err |= __put_user(sg_io64.msg_status, &sg_io32->msg_status); - err |= __put_user(sg_io64.sb_len_wr, &sg_io32->sb_len_wr); - err |= __put_user(sg_io64.host_status, &sg_io32->host_status); - err |= __put_user(sg_io64.driver_status, &sg_io32->driver_status); - err |= __put_user(sg_io64.resid, &sg_io32->resid); - err |= __put_user(sg_io64.duration, &sg_io32->duration); - err |= __put_user(sg_io64.info, &sg_io32->info); - err |= copy_to_user(compat_ptr(sbp32), sg_io64.sbp, sg_io64.mx_sb_len); - if (err) - err = -EFAULT; - -out: - if (sg_io64.cmdp) - kfree(sg_io64.cmdp); - if (sg_io64.sbp) - kfree(sg_io64.sbp); - if (sg_io64.dxferp && sg_io64.iovec_count) - free_sg_iovec(&sg_io64); - return err; -} - -struct sock_fprog32 { - unsigned short len; - compat_caddr_t filter; -}; - -#define PPPIOCSPASS32 _IOW('t', 71, struct sock_fprog32) -#define PPPIOCSACTIVE32 _IOW('t', 70, struct sock_fprog32) - -static int ppp_sock_fprog_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct sock_fprog32 *u_fprog32 = (struct sock_fprog32 *) arg; - struct sock_fprog *u_fprog64 = compat_alloc_user_space(sizeof(struct sock_fprog)); - void *fptr64; - u32 fptr32; - u16 flen; - - if (get_user(flen, &u_fprog32->len) || - get_user(fptr32, &u_fprog32->filter)) - return -EFAULT; - - fptr64 = compat_ptr(fptr32); - - if (put_user(flen, &u_fprog64->len) || - put_user(fptr64, &u_fprog64->filter)) - return -EFAULT; - - if (cmd == PPPIOCSPASS32) - cmd = PPPIOCSPASS; - else - cmd = PPPIOCSACTIVE; - - return sys_ioctl(fd, cmd, (unsigned long) u_fprog64); -} - -struct ppp_option_data32 { - compat_caddr_t ptr; - u32 length; - compat_int_t transmit; -}; -#define PPPIOCSCOMPRESS32 _IOW('t', 77, struct ppp_option_data32) - -struct ppp_idle32 { - compat_time_t xmit_idle; - compat_time_t recv_idle; -}; -#define PPPIOCGIDLE32 _IOR('t', 63, struct ppp_idle32) - -static int ppp_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - struct ppp_option_data32 data32; - struct ppp_option_data data; - struct ppp_idle32 idle32; - struct ppp_idle idle; - unsigned int kcmd; - void *karg; - int err = 0; - - switch (cmd) { - case PPPIOCGIDLE32: - kcmd = PPPIOCGIDLE; - karg = &idle; - break; - case PPPIOCSCOMPRESS32: - if (copy_from_user(&data32, (struct ppp_option_data32 *)arg, sizeof(struct ppp_option_data32))) - return -EFAULT; - if (data32.length > PAGE_SIZE) - return -EINVAL; - data.ptr = kmalloc (data32.length, GFP_KERNEL); - if (!data.ptr) - return -ENOMEM; - if (copy_from_user(data.ptr, compat_ptr(data32.ptr), data32.length)) { - kfree(data.ptr); - return -EFAULT; - } - data.length = data32.length; - data.transmit = data32.transmit; - kcmd = PPPIOCSCOMPRESS; - karg = &data; - break; - default: - do { - static int count; - if (++count <= 20) - printk("ppp_ioctl: Unknown cmd fd(%d) " - "cmd(%08x) arg(%08x)\n", - (int)fd, (unsigned int)cmd, (unsigned int)arg); - } while(0); - return -EINVAL; - } - set_fs (KERNEL_DS); - err = sys_ioctl (fd, kcmd, (unsigned long)karg); - set_fs (old_fs); - switch (cmd) { - case PPPIOCGIDLE32: - if (err) - return err; - idle32.xmit_idle = idle.xmit_idle; - idle32.recv_idle = idle.recv_idle; - if (copy_to_user((struct ppp_idle32 *)arg, &idle32, sizeof(struct ppp_idle32))) - return -EFAULT; - break; - case PPPIOCSCOMPRESS32: - kfree(data.ptr); - break; - default: - break; - } - return err; -} - - -struct mtget32 { - compat_long_t mt_type; - compat_long_t mt_resid; - compat_long_t mt_dsreg; - compat_long_t mt_gstat; - compat_long_t mt_erreg; - compat_daddr_t mt_fileno; - compat_daddr_t mt_blkno; -}; -#define MTIOCGET32 _IOR('m', 2, struct mtget32) - -struct mtpos32 { - compat_long_t mt_blkno; -}; -#define MTIOCPOS32 _IOR('m', 3, struct mtpos32) - -struct mtconfiginfo32 { - compat_long_t mt_type; - compat_long_t ifc_type; - unsigned short irqnr; - unsigned short dmanr; - unsigned short port; - compat_ulong_t debug; - compat_uint_t have_dens:1; - compat_uint_t have_bsf:1; - compat_uint_t have_fsr:1; - compat_uint_t have_bsr:1; - compat_uint_t have_eod:1; - compat_uint_t have_seek:1; - compat_uint_t have_tell:1; - compat_uint_t have_ras1:1; - compat_uint_t have_ras2:1; - compat_uint_t have_ras3:1; - compat_uint_t have_qfa:1; - compat_uint_t pad1:5; - char reserved[10]; -}; -#define MTIOCGETCONFIG32 _IOR('m', 4, struct mtconfiginfo32) -#define MTIOCSETCONFIG32 _IOW('m', 5, struct mtconfiginfo32) - -static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - struct mtconfiginfo info; - struct mtget get; - struct mtpos pos; - unsigned long kcmd; - void *karg; - int err = 0; - - switch(cmd) { - case MTIOCPOS32: - kcmd = MTIOCPOS; - karg = &pos; - break; - case MTIOCGET32: - kcmd = MTIOCGET; - karg = &get; - break; - case MTIOCGETCONFIG32: - kcmd = MTIOCGETCONFIG; - karg = &info; - break; - case MTIOCSETCONFIG32: - kcmd = MTIOCSETCONFIG; - karg = &info; - err = __get_user(info.mt_type, &((struct mtconfiginfo32 *)arg)->mt_type); - err |= __get_user(info.ifc_type, &((struct mtconfiginfo32 *)arg)->ifc_type); - err |= __get_user(info.irqnr, &((struct mtconfiginfo32 *)arg)->irqnr); - err |= __get_user(info.dmanr, &((struct mtconfiginfo32 *)arg)->dmanr); - err |= __get_user(info.port, &((struct mtconfiginfo32 *)arg)->port); - err |= __get_user(info.debug, &((struct mtconfiginfo32 *)arg)->debug); - err |= __copy_from_user((char *)&info.debug + sizeof(info.debug), - (char *)&((struct mtconfiginfo32 *)arg)->debug - + sizeof(((struct mtconfiginfo32 *)arg)->debug), sizeof(__u32)); - if (err) - return -EFAULT; - break; - default: - do { - static int count; - if (++count <= 20) - printk("mt_ioctl: Unknown cmd fd(%d) " - "cmd(%08x) arg(%08x)\n", - (int)fd, (unsigned int)cmd, (unsigned int)arg); - } while(0); - return -EINVAL; - } - set_fs (KERNEL_DS); - err = sys_ioctl (fd, kcmd, (unsigned long)karg); - set_fs (old_fs); - if (err) - return err; - switch (cmd) { - case MTIOCPOS32: - err = __put_user(pos.mt_blkno, &((struct mtpos32 *)arg)->mt_blkno); - break; - case MTIOCGET32: - err = __put_user(get.mt_type, &((struct mtget32 *)arg)->mt_type); - err |= __put_user(get.mt_resid, &((struct mtget32 *)arg)->mt_resid); - err |= __put_user(get.mt_dsreg, &((struct mtget32 *)arg)->mt_dsreg); - err |= __put_user(get.mt_gstat, &((struct mtget32 *)arg)->mt_gstat); - err |= __put_user(get.mt_erreg, &((struct mtget32 *)arg)->mt_erreg); - err |= __put_user(get.mt_fileno, &((struct mtget32 *)arg)->mt_fileno); - err |= __put_user(get.mt_blkno, &((struct mtget32 *)arg)->mt_blkno); - break; - case MTIOCGETCONFIG32: - err = __put_user(info.mt_type, &((struct mtconfiginfo32 *)arg)->mt_type); - err |= __put_user(info.ifc_type, &((struct mtconfiginfo32 *)arg)->ifc_type); - err |= __put_user(info.irqnr, &((struct mtconfiginfo32 *)arg)->irqnr); - err |= __put_user(info.dmanr, &((struct mtconfiginfo32 *)arg)->dmanr); - err |= __put_user(info.port, &((struct mtconfiginfo32 *)arg)->port); - err |= __put_user(info.debug, &((struct mtconfiginfo32 *)arg)->debug); - err |= __copy_to_user((char *)&((struct mtconfiginfo32 *)arg)->debug - + sizeof(((struct mtconfiginfo32 *)arg)->debug), - (char *)&info.debug + sizeof(info.debug), sizeof(__u32)); - break; - case MTIOCSETCONFIG32: - break; - } - return err ? -EFAULT: 0; -} - -struct cdrom_read32 { - compat_int_t cdread_lba; - compat_caddr_t cdread_bufaddr; - compat_int_t cdread_buflen; -}; - -struct cdrom_read_audio32 { - union cdrom_addr addr; - u8 addr_format; - compat_int_t nframes; - compat_caddr_t buf; -}; - -struct cdrom_generic_command32 { - unsigned char cmd[CDROM_PACKET_SIZE]; - compat_caddr_t buffer; - compat_uint_t buflen; - compat_int_t stat; - compat_caddr_t sense; - compat_caddr_t reserved[3]; /* Oops? it has data_direction, quiet and timeout fields? */ -}; - -static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - struct cdrom_read cdread; - struct cdrom_read_audio cdreadaudio; - struct cdrom_generic_command cgc; - compat_caddr_t addr; - char *data = 0; - void *karg; - int err = 0; - - switch(cmd) { - case CDROMREADMODE2: - case CDROMREADMODE1: - case CDROMREADRAW: - case CDROMREADCOOKED: - karg = &cdread; - err = __get_user(cdread.cdread_lba, &((struct cdrom_read32 *)arg)->cdread_lba); - err |= __get_user(addr, &((struct cdrom_read32 *)arg)->cdread_bufaddr); - err |= __get_user(cdread.cdread_buflen, &((struct cdrom_read32 *)arg)->cdread_buflen); - if (err) - return -EFAULT; - if (verify_area(VERIFY_WRITE, compat_ptr(addr), cdread.cdread_buflen)) - return -EFAULT; - cdread.cdread_bufaddr = compat_ptr(addr); - break; - case CDROMREADAUDIO: - karg = &cdreadaudio; - err = copy_from_user(&cdreadaudio.addr, &((struct cdrom_read_audio32 *)arg)->addr, sizeof(cdreadaudio.addr)); - err |= __get_user(cdreadaudio.addr_format, &((struct cdrom_read_audio32 *)arg)->addr_format); - err |= __get_user(cdreadaudio.nframes, &((struct cdrom_read_audio32 *)arg)->nframes); - err |= __get_user(addr, &((struct cdrom_read_audio32 *)arg)->buf); - if (err) - return -EFAULT; - - - if (verify_area(VERIFY_WRITE, compat_ptr(addr), cdreadaudio.nframes*2352)) - return -EFAULT; - cdreadaudio.buf = compat_ptr(addr); - break; - case CDROM_SEND_PACKET: - karg = &cgc; - err = copy_from_user(cgc.cmd, &((struct cdrom_generic_command32 *)arg)->cmd, sizeof(cgc.cmd)); - err |= __get_user(addr, &((struct cdrom_generic_command32 *)arg)->buffer); - err |= __get_user(cgc.buflen, &((struct cdrom_generic_command32 *)arg)->buflen); - if (err) - return -EFAULT; - if (verify_area(VERIFY_WRITE, compat_ptr(addr), cgc.buflen)) - return -EFAULT; - cgc.buffer = compat_ptr(addr); - break; - default: - do { - static int count; - if (++count <= 20) - printk("cdrom_ioctl: Unknown cmd fd(%d) " - "cmd(%08x) arg(%08x)\n", - (int)fd, (unsigned int)cmd, (unsigned int)arg); - } while(0); - return -EINVAL; - } - set_fs (KERNEL_DS); - err = sys_ioctl (fd, cmd, (unsigned long)karg); - set_fs (old_fs); - if (data) - kfree(data); - return err ? -EFAULT : 0; -} - -struct loop_info32 { - compat_int_t lo_number; /* ioctl r/o */ - compat_dev_t lo_device; /* ioctl r/o */ - compat_ulong_t lo_inode; /* ioctl r/o */ - compat_dev_t lo_rdevice; /* ioctl r/o */ - compat_int_t lo_offset; - compat_int_t lo_encrypt_type; - compat_int_t lo_encrypt_key_size; /* ioctl w/o */ - compat_int_t lo_flags; /* ioctl r/o */ - char lo_name[LO_NAME_SIZE]; - unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */ - compat_ulong_t lo_init[2]; - char reserved[4]; -}; - -static int loop_status(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - struct loop_info l; - int err = -EINVAL; - - switch(cmd) { - case LOOP_SET_STATUS: - err = get_user(l.lo_number, &((struct loop_info32 *)arg)->lo_number); - err |= __get_user(l.lo_device, &((struct loop_info32 *)arg)->lo_device); - err |= __get_user(l.lo_inode, &((struct loop_info32 *)arg)->lo_inode); - err |= __get_user(l.lo_rdevice, &((struct loop_info32 *)arg)->lo_rdevice); - - err |= __copy_from_user((char *)&l.lo_offset, (char *)&((struct loop_info32 *)arg)->lo_offset, - 8 + (unsigned long)l.lo_init - (unsigned long)&l.lo_offset); - if (err) { - err = -EFAULT; - } else { - set_fs (KERNEL_DS); - err = sys_ioctl (fd, cmd, (unsigned long)&l); - set_fs (old_fs); - } - break; - case LOOP_GET_STATUS: - set_fs (KERNEL_DS); - err = sys_ioctl (fd, cmd, (unsigned long)&l); - set_fs (old_fs); - if (!err) { - err = put_user(l.lo_number, &((struct loop_info32 *)arg)->lo_number); - err |= __put_user(l.lo_device, &((struct loop_info32 *)arg)->lo_device); - err |= __put_user(l.lo_inode, &((struct loop_info32 *)arg)->lo_inode); - err |= __put_user(l.lo_rdevice, &((struct loop_info32 *)arg)->lo_rdevice); - err |= __copy_to_user((char *)&((struct loop_info32 *)arg)->lo_offset, - (char *)&l.lo_offset, (unsigned long)l.lo_init - (unsigned long)&l.lo_offset); - if (err) - err = -EFAULT; - } - break; - default: { - static int count; - if (++count <= 20) - printk("%s: Unknown loop ioctl cmd, fd(%d) " - "cmd(%08x) arg(%08lx)\n", - __FUNCTION__, fd, cmd, arg); - } - } - return err; -} - -extern int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg); - -static int vt_check(struct file *file) -{ - struct tty_struct *tty; - struct inode *inode = file->f_dentry->d_inode; - - if (file->f_op->ioctl != tty_ioctl) - return -EINVAL; - - tty = (struct tty_struct *)file->private_data; - if (tty_paranoia_check(tty, inode->i_rdev, "tty_ioctl")) - return -EINVAL; - - if (tty->driver->ioctl != vt_ioctl) - return -EINVAL; - - /* - * To have permissions to do most of the vt ioctls, we either have - * to be the owner of the tty, or super-user. - */ - if (current->tty == tty || capable(CAP_SYS_ADMIN)) - return 1; - return 0; -} - -struct consolefontdesc32 { - unsigned short charcount; /* characters in font (256 or 512) */ - unsigned short charheight; /* scan lines per character (1-32) */ - compat_caddr_t chardata; /* font data in expanded form */ -}; - -static int do_fontx_ioctl(unsigned int fd, int cmd, struct consolefontdesc32 *user_cfd, struct file *file) -{ - struct consolefontdesc cfdarg; - struct console_font_op op; - int i, perm; - - perm = vt_check(file); - if (perm < 0) return perm; - - if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc32))) - return -EFAULT; - - cfdarg.chardata = compat_ptr(((struct consolefontdesc32 *)&cfdarg)->chardata); - - switch (cmd) { - case PIO_FONTX: - if (!perm) - return -EPERM; - op.op = KD_FONT_OP_SET; - op.flags = 0; - op.width = 8; - op.height = cfdarg.charheight; - op.charcount = cfdarg.charcount; - op.data = cfdarg.chardata; - return con_font_op(fg_console, &op); - case GIO_FONTX: - if (!cfdarg.chardata) - return 0; - op.op = KD_FONT_OP_GET; - op.flags = 0; - op.width = 8; - op.height = cfdarg.charheight; - op.charcount = cfdarg.charcount; - op.data = cfdarg.chardata; - i = con_font_op(fg_console, &op); - if (i) - return i; - cfdarg.charheight = op.height; - cfdarg.charcount = op.charcount; - ((struct consolefontdesc32 *)&cfdarg)->chardata = (unsigned long)cfdarg.chardata; - if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc32))) - return -EFAULT; - return 0; - } - return -EINVAL; -} - -struct console_font_op32 { - compat_uint_t op; /* operation code KD_FONT_OP_* */ - compat_uint_t flags; /* KD_FONT_FLAG_* */ - compat_uint_t width, height; /* font size */ - compat_uint_t charcount; - compat_caddr_t data; /* font data with height fixed to 32 */ -}; - -static int do_kdfontop_ioctl(unsigned int fd, unsigned int cmd, struct console_font_op32 *fontop, struct file *file) -{ - struct console_font_op op; - int perm = vt_check(file), i; - struct vt_struct *vt; - - if (perm < 0) return perm; - - if (copy_from_user(&op, (void *) fontop, sizeof(struct console_font_op32))) - return -EFAULT; - if (!perm && op.op != KD_FONT_OP_GET) - return -EPERM; - op.data = compat_ptr(((struct console_font_op32 *)&op)->data); - op.flags |= KD_FONT_FLAG_OLD; - vt = (struct vt_struct *)((struct tty_struct *)file->private_data)->driver_data; - i = con_font_op(vt->vc_num, &op); - if (i) return i; - ((struct console_font_op32 *)&op)->data = (unsigned long)op.data; - if (copy_to_user((void *) fontop, &op, sizeof(struct console_font_op32))) - return -EFAULT; - return 0; -} - -struct unimapdesc32 { - unsigned short entry_ct; - compat_caddr_t entries; -}; - -static int do_unimap_ioctl(unsigned int fd, unsigned int cmd, struct unimapdesc32 *user_ud, struct file *file) -{ - struct unimapdesc32 tmp; - int perm = vt_check(file); - - if (perm < 0) return perm; - if (copy_from_user(&tmp, user_ud, sizeof tmp)) - return -EFAULT; - switch (cmd) { - case PIO_UNIMAP: - if (!perm) return -EPERM; - return con_set_unimap(fg_console, tmp.entry_ct, compat_ptr(tmp.entries)); - case GIO_UNIMAP: - return con_get_unimap(fg_console, tmp.entry_ct, &(user_ud->entry_ct), compat_ptr(tmp.entries)); - } - return 0; -} - -static int do_smb_getmountuid(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - __kernel_uid_t kuid; - int err; - - cmd = SMB_IOC_GETMOUNTUID; - - set_fs(KERNEL_DS); - err = sys_ioctl(fd, cmd, (unsigned long)&kuid); - set_fs(old_fs); - - if (err >= 0) - err = put_user(kuid, (compat_pid_t *)arg); - - return err; -} - -struct atmif_sioc32 { - compat_int_t number; - compat_int_t length; - compat_caddr_t arg; -}; - -struct atm_iobuf32 { - compat_int_t length; - compat_caddr_t buffer; -}; - -#define ATM_GETLINKRATE32 _IOW('a', ATMIOC_ITF+1, struct atmif_sioc32) -#define ATM_GETNAMES32 _IOW('a', ATMIOC_ITF+3, struct atm_iobuf32) -#define ATM_GETTYPE32 _IOW('a', ATMIOC_ITF+4, struct atmif_sioc32) -#define ATM_GETESI32 _IOW('a', ATMIOC_ITF+5, struct atmif_sioc32) -#define ATM_GETADDR32 _IOW('a', ATMIOC_ITF+6, struct atmif_sioc32) -#define ATM_RSTADDR32 _IOW('a', ATMIOC_ITF+7, struct atmif_sioc32) -#define ATM_ADDADDR32 _IOW('a', ATMIOC_ITF+8, struct atmif_sioc32) -#define ATM_DELADDR32 _IOW('a', ATMIOC_ITF+9, struct atmif_sioc32) -#define ATM_GETCIRANGE32 _IOW('a', ATMIOC_ITF+10, struct atmif_sioc32) -#define ATM_SETCIRANGE32 _IOW('a', ATMIOC_ITF+11, struct atmif_sioc32) -#define ATM_SETESI32 _IOW('a', ATMIOC_ITF+12, struct atmif_sioc32) -#define ATM_SETESIF32 _IOW('a', ATMIOC_ITF+13, struct atmif_sioc32) -#define ATM_GETSTAT32 _IOW('a', ATMIOC_SARCOM+0, struct atmif_sioc32) -#define ATM_GETSTATZ32 _IOW('a', ATMIOC_SARCOM+1, struct atmif_sioc32) -#define ATM_GETLOOP32 _IOW('a', ATMIOC_SARCOM+2, struct atmif_sioc32) -#define ATM_SETLOOP32 _IOW('a', ATMIOC_SARCOM+3, struct atmif_sioc32) -#define ATM_QUERYLOOP32 _IOW('a', ATMIOC_SARCOM+4, struct atmif_sioc32) - -static struct { - unsigned int cmd32; - unsigned int cmd; -} atm_ioctl_map[] = { - { ATM_GETLINKRATE32, ATM_GETLINKRATE }, - { ATM_GETNAMES32, ATM_GETNAMES }, - { ATM_GETTYPE32, ATM_GETTYPE }, - { ATM_GETESI32, ATM_GETESI }, - { ATM_GETADDR32, ATM_GETADDR }, - { ATM_RSTADDR32, ATM_RSTADDR }, - { ATM_ADDADDR32, ATM_ADDADDR }, - { ATM_DELADDR32, ATM_DELADDR }, - { ATM_GETCIRANGE32, ATM_GETCIRANGE }, - { ATM_SETCIRANGE32, ATM_SETCIRANGE }, - { ATM_SETESI32, ATM_SETESI }, - { ATM_SETESIF32, ATM_SETESIF }, - { ATM_GETSTAT32, ATM_GETSTAT }, - { ATM_GETSTATZ32, ATM_GETSTATZ }, - { ATM_GETLOOP32, ATM_GETLOOP }, - { ATM_SETLOOP32, ATM_SETLOOP }, - { ATM_QUERYLOOP32, ATM_QUERYLOOP } -}; - -#define NR_ATM_IOCTL (sizeof(atm_ioctl_map)/sizeof(atm_ioctl_map[0])) - - -static int do_atm_iobuf(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct atm_iobuf32 iobuf32; - struct atm_iobuf iobuf = { 0, NULL }; - mm_segment_t old_fs; - int err; - - err = copy_from_user(&iobuf32, (struct atm_iobuf32*)arg, - sizeof(struct atm_iobuf32)); - if (err) - return -EFAULT; - - iobuf.length = iobuf32.length; - - if (iobuf32.buffer == (compat_caddr_t) NULL || iobuf32.length == 0) { - iobuf.buffer = (void*)(unsigned long)iobuf32.buffer; - } else { - iobuf.buffer = compat_ptr(iobuf32.buffer); - if (verify_area(VERIFY_WRITE, iobuf.buffer, iobuf.length)) - return -EINVAL; - } - - old_fs = get_fs(); set_fs (KERNEL_DS); - err = sys_ioctl (fd, cmd, (unsigned long)&iobuf); - set_fs (old_fs); - if(!err) - err = __put_user(iobuf.length, &(((struct atm_iobuf32*)arg)->length)); - - return err; -} - - -static int do_atmif_sioc(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - struct atmif_sioc32 sioc32; - struct atmif_sioc sioc = { 0, 0, NULL }; - mm_segment_t old_fs; - int err; - - err = copy_from_user(&sioc32, (struct atmif_sioc32*)arg, - sizeof(struct atmif_sioc32)); - if (err) - return -EFAULT; - - sioc.number = sioc32.number; - sioc.length = sioc32.length; - - if (sioc32.arg == (compat_caddr_t) NULL || sioc32.length == 0) { - sioc.arg = (void*)(unsigned long)sioc32.arg; - } else { - sioc.arg = compat_ptr(sioc32.arg); - if (verify_area(VERIFY_WRITE, sioc.arg, sioc32.length)) - return -EFAULT; - } - - old_fs = get_fs(); set_fs (KERNEL_DS); - err = sys_ioctl (fd, cmd, (unsigned long)&sioc); - set_fs (old_fs); - if (!err) - err = __put_user(sioc.length, &(((struct atmif_sioc32*)arg)->length)); - return err; -} - - -static int do_atm_ioctl(unsigned int fd, unsigned int cmd32, unsigned long arg) -{ - int i; - unsigned int cmd = 0; - - switch (cmd32) { - case SONET_GETSTAT: - case SONET_GETSTATZ: - case SONET_GETDIAG: - case SONET_SETDIAG: - case SONET_CLRDIAG: - case SONET_SETFRAMING: - case SONET_GETFRAMING: - case SONET_GETFRSENSE: - return do_atmif_sioc(fd, cmd32, arg); - } - - for (i = 0; i < NR_ATM_IOCTL; i++) { - if (cmd32 == atm_ioctl_map[i].cmd32) { - cmd = atm_ioctl_map[i].cmd; - break; - } - } - if (i == NR_ATM_IOCTL) { - return -EINVAL; - } - - switch (cmd) { - case ATM_GETNAMES: - return do_atm_iobuf(fd, cmd, arg); - - case ATM_GETLINKRATE: - case ATM_GETTYPE: - case ATM_GETESI: - case ATM_GETADDR: - case ATM_RSTADDR: - case ATM_ADDADDR: - case ATM_DELADDR: - case ATM_GETCIRANGE: - case ATM_SETCIRANGE: - case ATM_SETESI: - case ATM_SETESIF: - case ATM_GETSTAT: - case ATM_GETSTATZ: - case ATM_GETLOOP: - case ATM_SETLOOP: - case ATM_QUERYLOOP: - return do_atmif_sioc(fd, cmd, arg); - } - - return -EINVAL; -} - -static int ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - return -EINVAL; -} - -static int broken_blkgetsize(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - /* The mkswap binary hard codes it to Intel value :-((( */ - return w_long(fd, BLKGETSIZE, arg); -} - -struct blkpg_ioctl_arg32 { - compat_int_t op; - compat_int_t flags; - compat_int_t datalen; - compat_caddr_t data; -}; - -static int blkpg_ioctl_trans(unsigned int fd, unsigned int cmd, struct blkpg_ioctl_arg32 *arg) -{ - struct blkpg_ioctl_arg a; - struct blkpg_partition p; - int err; - mm_segment_t old_fs = get_fs(); - - err = get_user(a.op, &arg->op); - err |= __get_user(a.flags, &arg->flags); - err |= __get_user(a.datalen, &arg->datalen); - err |= __get_user((long)a.data, &arg->data); - if (err) return err; - switch (a.op) { - case BLKPG_ADD_PARTITION: - case BLKPG_DEL_PARTITION: - if (a.datalen < sizeof(struct blkpg_partition)) - return -EINVAL; - if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition))) - return -EFAULT; - a.data = &p; - set_fs (KERNEL_DS); - err = sys_ioctl(fd, cmd, (unsigned long)&a); - set_fs (old_fs); - default: - return -EINVAL; - } - return err; -} - -static int ioc_settimeout(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - return rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg); -} - +#define CODE +#include "compat_ioctl.c" + #ifndef TIOCGDEV #define TIOCGDEV _IOR('T',0x32, unsigned int) #endif @@ -2320,56 +72,6 @@ return ret; } -struct serial_struct32 { - compat_int_t type; - compat_int_t line; - compat_uint_t port; - compat_int_t irq; - compat_int_t flags; - compat_int_t xmit_fifo_size; - compat_int_t custom_divisor; - compat_int_t baud_base; - unsigned short close_delay; - char io_type; - char reserved_char[1]; - compat_int_t hub6; - unsigned short closing_wait; /* time to wait before closing */ - unsigned short closing_wait2; /* no longer used... */ - compat_uint_t iomem_base; - unsigned short iomem_reg_shift; - unsigned int port_high; - compat_int_t reserved[1]; -}; - -static int serial_struct_ioctl(unsigned fd, unsigned cmd, void *ptr) -{ - typedef struct serial_struct SS; - struct serial_struct32 *ss32 = ptr; - int err; - struct serial_struct ss; - mm_segment_t oldseg = get_fs(); - if (cmd == TIOCSSERIAL) { - if (copy_from_user(&ss, ss32, sizeof(struct serial_struct32))) - return -EFAULT; - memmove(&ss.iomem_reg_shift, ((char*)&ss.iomem_base)+4, - sizeof(SS)-offsetof(SS,iomem_reg_shift)); - ss.iomem_base = (void *)((unsigned long)ss.iomem_base & 0xffffffff); - } - set_fs(KERNEL_DS); - err = sys_ioctl(fd,cmd,(unsigned long)(&ss)); - set_fs(oldseg); - if (cmd == TIOCGSERIAL && err >= 0) { - if (__copy_to_user(ss32,&ss,offsetof(SS,iomem_base)) || - __put_user((unsigned long)ss.iomem_base >> 32 ? - 0xffffffff : (unsigned)(unsigned long)ss.iomem_base, - &ss32->iomem_base) || - __put_user(ss.iomem_reg_shift, &ss32->iomem_reg_shift) || - __put_user(ss.port_high, &ss32->port_high)) - return -EFAULT; - } - return err; -} - #define REISERFS_IOC_UNPACK32 _IOW(0xCD,1,int) @@ -2456,35 +158,57 @@ return sys_ioctl(fd,cmd,arg); } -/* Fix sizeof(sizeof()) breakage */ -#define BLKBSZGET_32 _IOR(0x12,112,int) -#define BLKBSZSET_32 _IOW(0x12,113,int) -#define BLKGETSIZE64_32 _IOR(0x12,114,int) - -static int do_blkbszget(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - return sys_ioctl(fd, BLKBSZGET, arg); -} +struct serial_struct32 { + compat_int_t type; + compat_int_t line; + compat_uint_t port; + compat_int_t irq; + compat_int_t flags; + compat_int_t xmit_fifo_size; + compat_int_t custom_divisor; + compat_int_t baud_base; + unsigned short close_delay; + char io_type; + char reserved_char[1]; + compat_int_t hub6; + unsigned short closing_wait; /* time to wait before closing */ + unsigned short closing_wait2; /* no longer used... */ + compat_uint_t iomem_base; + unsigned short iomem_reg_shift; + unsigned int port_high; + compat_int_t reserved[1]; +}; -static int do_blkbszset(unsigned int fd, unsigned int cmd, unsigned long arg) +static int serial_struct_ioctl(unsigned fd, unsigned cmd, void *ptr) { - return sys_ioctl(fd, BLKBSZSET, arg); + typedef struct serial_struct SS; + struct serial_struct32 *ss32 = ptr; + int err; + struct serial_struct ss; + mm_segment_t oldseg = get_fs(); + if (cmd == TIOCSSERIAL) { + if (copy_from_user(&ss, ss32, sizeof(struct serial_struct32))) + return -EFAULT; + memmove(&ss.iomem_reg_shift, ((char*)&ss.iomem_base)+4, + sizeof(SS)-offsetof(SS,iomem_reg_shift)); + ss.iomem_base = (void *)((unsigned long)ss.iomem_base & 0xffffffff); + } + set_fs(KERNEL_DS); + err = sys_ioctl(fd,cmd,(unsigned long)(&ss)); + set_fs(oldseg); + if (cmd == TIOCGSERIAL && err >= 0) { + if (__copy_to_user(ss32,&ss,offsetof(SS,iomem_base)) || + __put_user((unsigned long)ss.iomem_base >> 32 ? + 0xffffffff : (unsigned)(unsigned long)ss.iomem_base, + &ss32->iomem_base) || + __put_user(ss.iomem_reg_shift, &ss32->iomem_reg_shift) || + __put_user(ss.port_high, &ss32->port_high)) + return -EFAULT; + } + return err; } -static int do_blkgetsize64(unsigned int fd, unsigned int cmd, - unsigned long arg) -{ - return sys_ioctl(fd, BLKGETSIZE64, arg); -} -/* Bluetooth ioctls */ -#define HCIUARTSETPROTO _IOW('U', 200, int) -#define HCIUARTGETPROTO _IOR('U', 201, int) - -#define BNEPCONNADD _IOW('B', 200, int) -#define BNEPCONNDEL _IOW('B', 201, int) -#define BNEPGETCONNLIST _IOR('B', 210, int) -#define BNEPGETCONNINFO _IOR('B', 211, int) struct usbdevfs_ctrltransfer32 { u8 bRequestType; @@ -2864,50 +588,6 @@ return err; } - -struct mtd_oob_buf32 { - u_int32_t start; - u_int32_t length; - compat_caddr_t ptr; /* unsigned char* */ -}; - -#define MEMWRITEOOB32 _IOWR('M',3,struct mtd_oob_buf32) -#define MEMREADOOB32 _IOWR('M',4,struct mtd_oob_buf32) - -static int mtd_rw_oob(unsigned int fd, unsigned int cmd, unsigned long arg) -{ - mm_segment_t old_fs = get_fs(); - struct mtd_oob_buf32 *uarg = (struct mtd_oob_buf32 *)arg; - struct mtd_oob_buf karg; - u32 tmp; - int ret; - - if (get_user(karg.start, &uarg->start) || - get_user(karg.length, &uarg->length) || - get_user(tmp, &uarg->ptr)) - return -EFAULT; - - karg.ptr = compat_ptr(tmp); - if (verify_area(VERIFY_WRITE, karg.ptr, karg.length)) - return -EFAULT; - - set_fs(KERNEL_DS); - if (MEMREADOOB32 == cmd) - ret = sys_ioctl(fd, MEMREADOOB, (unsigned long)&karg); - else if (MEMWRITEOOB32 == cmd) - ret = sys_ioctl(fd, MEMWRITEOOB, (unsigned long)&karg); - else - ret = -EINVAL; - set_fs(old_fs); - - if (0 == ret && cmd == MEMREADOOB32) { - ret = put_user(karg.start, &uarg->start); - ret |= put_user(karg.length, &uarg->length); - } - - return ret; -} - /* /proc/mtrr ioctls */ @@ -3002,6 +682,8 @@ IOCTL_TABLE_START #include <linux/compat_ioctl.h> +#define DECLARES +#include "compat_ioctl.c" COMPATIBLE_IOCTL(HDIO_SET_KEEPSETTINGS) COMPATIBLE_IOCTL(HDIO_SCAN_HWIF) COMPATIBLE_IOCTL(BLKRASET) @@ -3049,48 +731,8 @@ HANDLE_IOCTL(TIOCGDEV, tiocgdev) HANDLE_IOCTL(TIOCGSERIAL, serial_struct_ioctl) HANDLE_IOCTL(TIOCSSERIAL, serial_struct_ioctl) -HANDLE_IOCTL(MEMREADOOB32, mtd_rw_oob) -HANDLE_IOCTL(MEMWRITEOOB32, mtd_rw_oob) -#ifdef CONFIG_NET -HANDLE_IOCTL(SIOCGIFNAME, dev_ifname32) -#endif -HANDLE_IOCTL(SIOCGIFCONF, dev_ifconf) -HANDLE_IOCTL(SIOCGIFFLAGS, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFFLAGS, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFMETRIC, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFMETRIC, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFMTU, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFMTU, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFMEM, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFMEM, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFHWADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFHWADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCADDMULTI, dev_ifsioc) -HANDLE_IOCTL(SIOCDELMULTI, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFINDEX, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFMAP, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFMAP, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFBRDADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFBRDADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFDSTADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFDSTADDR, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFNETMASK, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFNETMASK, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFPFLAGS, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFPFLAGS, dev_ifsioc) -HANDLE_IOCTL(SIOCGIFTXQLEN, dev_ifsioc) -HANDLE_IOCTL(SIOCSIFTXQLEN, dev_ifsioc) -HANDLE_IOCTL(SIOCETHTOOL, ethtool_ioctl) -HANDLE_IOCTL(SIOCBONDENSLAVE, bond_ioctl) -HANDLE_IOCTL(SIOCBONDRELEASE, bond_ioctl) -HANDLE_IOCTL(SIOCBONDSETHWADDR, bond_ioctl) -HANDLE_IOCTL(SIOCBONDSLAVEINFOQUERY, bond_ioctl) -HANDLE_IOCTL(SIOCBONDINFOQUERY, bond_ioctl) -HANDLE_IOCTL(SIOCBONDCHANGEACTIVE, bond_ioctl) -HANDLE_IOCTL(SIOCADDRT, routing_ioctl) -HANDLE_IOCTL(SIOCDELRT, routing_ioctl) +/* Raw devices */ +HANDLE_IOCTL(RAW_SETBIND, raw_ioctl) /* realtime device */ HANDLE_IOCTL(RTC_IRQP_READ, rtc32_ioctl) HANDLE_IOCTL(RTC_IRQP_READ32,rtc32_ioctl) @@ -3098,107 +740,10 @@ HANDLE_IOCTL(RTC_EPOCH_READ32, rtc32_ioctl) HANDLE_IOCTL(RTC_EPOCH_SET32, rtc32_ioctl) HANDLE_IOCTL(REISERFS_IOC_UNPACK32, reiserfs_ioctl32) -HANDLE_IOCTL(VFAT_IOCTL_READDIR_BOTH32, vfat_ioctl32) -HANDLE_IOCTL(VFAT_IOCTL_READDIR_SHORT32, vfat_ioctl32) -/* Raw devices */ -HANDLE_IOCTL(RAW_SETBIND, raw_ioctl) -/* Note SIOCRTMSG is no longer, so this is safe and * the user would have seen just an -EINVAL anyways. */ -HANDLE_IOCTL(SIOCRTMSG, ret_einval) -HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp) -HANDLE_IOCTL(HDIO_GETGEO, hdio_getgeo) -HANDLE_IOCTL(BLKRAGET, w_long) -HANDLE_IOCTL(BLKGETSIZE, w_long) -HANDLE_IOCTL(0x1260, broken_blkgetsize) -HANDLE_IOCTL(BLKFRAGET, w_long) -HANDLE_IOCTL(BLKSECTGET, w_long) -HANDLE_IOCTL(FBIOGET_FSCREENINFO, fb_ioctl_trans) -HANDLE_IOCTL(BLKPG, blkpg_ioctl_trans) -HANDLE_IOCTL(FBIOGETCMAP, fb_ioctl_trans) -HANDLE_IOCTL(FBIOPUTCMAP, fb_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_KEEPSETTINGS, hdio_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_UNMASKINTR, hdio_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_DMA, hdio_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_32BIT, hdio_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_MULTCOUNT, hdio_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_NOWERR, hdio_ioctl_trans) -HANDLE_IOCTL(HDIO_GET_NICE, hdio_ioctl_trans) -HANDLE_IOCTL(FDSETPRM32, fd_ioctl_trans) -HANDLE_IOCTL(FDDEFPRM32, fd_ioctl_trans) -HANDLE_IOCTL(FDGETPRM32, fd_ioctl_trans) -HANDLE_IOCTL(FDSETDRVPRM32, fd_ioctl_trans) -HANDLE_IOCTL(FDGETDRVPRM32, fd_ioctl_trans) -HANDLE_IOCTL(FDGETDRVSTAT32, fd_ioctl_trans) -HANDLE_IOCTL(FDPOLLDRVSTAT32, fd_ioctl_trans) -HANDLE_IOCTL(FDGETFDCSTAT32, fd_ioctl_trans) -HANDLE_IOCTL(FDWERRORGET32, fd_ioctl_trans) -HANDLE_IOCTL(SG_IO,sg_ioctl_trans) -HANDLE_IOCTL(PPPIOCGIDLE32, ppp_ioctl_trans) -HANDLE_IOCTL(PPPIOCSCOMPRESS32, ppp_ioctl_trans) -HANDLE_IOCTL(PPPIOCSPASS32, ppp_sock_fprog_ioctl_trans) -HANDLE_IOCTL(PPPIOCSACTIVE32, ppp_sock_fprog_ioctl_trans) -HANDLE_IOCTL(MTIOCGET32, mt_ioctl_trans) -HANDLE_IOCTL(MTIOCPOS32, mt_ioctl_trans) -HANDLE_IOCTL(MTIOCGETCONFIG32, mt_ioctl_trans) -HANDLE_IOCTL(MTIOCSETCONFIG32, mt_ioctl_trans) -HANDLE_IOCTL(CDROMREADMODE2, cdrom_ioctl_trans) -HANDLE_IOCTL(CDROMREADMODE1, cdrom_ioctl_trans) -HANDLE_IOCTL(CDROMREADRAW, cdrom_ioctl_trans) -HANDLE_IOCTL(CDROMREADCOOKED, cdrom_ioctl_trans) -HANDLE_IOCTL(CDROMREADAUDIO, cdrom_ioctl_trans) -HANDLE_IOCTL(CDROMREADALL, cdrom_ioctl_trans) -HANDLE_IOCTL(CDROM_SEND_PACKET, cdrom_ioctl_trans) -HANDLE_IOCTL(LOOP_SET_STATUS, loop_status) -HANDLE_IOCTL(LOOP_GET_STATUS, loop_status) -#define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int) -HANDLE_IOCTL(AUTOFS_IOC_SETTIMEOUT32, ioc_settimeout) -HANDLE_IOCTL(PIO_FONTX, do_fontx_ioctl) -HANDLE_IOCTL(GIO_FONTX, do_fontx_ioctl) -HANDLE_IOCTL(PIO_UNIMAP, do_unimap_ioctl) -HANDLE_IOCTL(GIO_UNIMAP, do_unimap_ioctl) -HANDLE_IOCTL(KDFONTOP, do_kdfontop_ioctl) -HANDLE_IOCTL(EXT2_IOC32_GETFLAGS, do_ext2_ioctl) -HANDLE_IOCTL(EXT2_IOC32_SETFLAGS, do_ext2_ioctl) -HANDLE_IOCTL(EXT2_IOC32_GETVERSION, do_ext2_ioctl) -HANDLE_IOCTL(EXT2_IOC32_SETVERSION, do_ext2_ioctl) -HANDLE_IOCTL(VIDIOCGTUNER32, do_video_ioctl) -HANDLE_IOCTL(VIDIOCSTUNER32, do_video_ioctl) -HANDLE_IOCTL(VIDIOCGWIN32, do_video_ioctl) -HANDLE_IOCTL(VIDIOCSWIN32, do_video_ioctl) -HANDLE_IOCTL(VIDIOCGFBUF32, do_video_ioctl) -HANDLE_IOCTL(VIDIOCSFBUF32, do_video_ioctl) -HANDLE_IOCTL(VIDIOCGFREQ32, do_video_ioctl) -HANDLE_IOCTL(VIDIOCSFREQ32, do_video_ioctl) -/* One SMB ioctl needs translations. */ -#define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, compat_pid_t) -HANDLE_IOCTL(SMB_IOC_GETMOUNTUID_32, do_smb_getmountuid) -HANDLE_IOCTL(ATM_GETLINKRATE32, do_atm_ioctl) -HANDLE_IOCTL(ATM_GETNAMES32, do_atm_ioctl) -HANDLE_IOCTL(ATM_GETTYPE32, do_atm_ioctl) -HANDLE_IOCTL(ATM_GETESI32, do_atm_ioctl) -HANDLE_IOCTL(ATM_GETADDR32, do_atm_ioctl) -HANDLE_IOCTL(ATM_RSTADDR32, do_atm_ioctl) -HANDLE_IOCTL(ATM_ADDADDR32, do_atm_ioctl) -HANDLE_IOCTL(ATM_DELADDR32, do_atm_ioctl) -HANDLE_IOCTL(ATM_GETCIRANGE32, do_atm_ioctl) -HANDLE_IOCTL(ATM_SETCIRANGE32, do_atm_ioctl) -HANDLE_IOCTL(ATM_SETESI32, do_atm_ioctl) -HANDLE_IOCTL(ATM_SETESIF32, do_atm_ioctl) -HANDLE_IOCTL(ATM_GETSTAT32, do_atm_ioctl) -HANDLE_IOCTL(ATM_GETSTATZ32, do_atm_ioctl) -HANDLE_IOCTL(ATM_GETLOOP32, do_atm_ioctl) -HANDLE_IOCTL(ATM_SETLOOP32, do_atm_ioctl) -HANDLE_IOCTL(ATM_QUERYLOOP32, do_atm_ioctl) -HANDLE_IOCTL(SONET_GETSTAT, do_atm_ioctl) -HANDLE_IOCTL(SONET_GETSTATZ, do_atm_ioctl) -HANDLE_IOCTL(SONET_GETDIAG, do_atm_ioctl) -HANDLE_IOCTL(SONET_SETDIAG, do_atm_ioctl) -HANDLE_IOCTL(SONET_CLRDIAG, do_atm_ioctl) -HANDLE_IOCTL(SONET_SETFRAMING, do_atm_ioctl) -HANDLE_IOCTL(SONET_GETFRAMING, do_atm_ioctl) -HANDLE_IOCTL(SONET_GETFRSENSE, do_atm_ioctl) /* VFAT */ HANDLE_IOCTL(VFAT_IOCTL_READDIR_BOTH32, vfat_ioctl32) HANDLE_IOCTL(VFAT_IOCTL_READDIR_SHORT32, vfat_ioctl32) + HANDLE_IOCTL(USBDEVFS_CONTROL32, do_usbdevfs_control) HANDLE_IOCTL(USBDEVFS_BULK32, do_usbdevfs_bulk) /*HANDLE_IOCTL(USBDEVFS_SUBMITURB32, do_usbdevfs_urb)*/ @@ -3206,10 +751,6 @@ HANDLE_IOCTL(USBDEVFS_REAPURBNDELAY32, do_usbdevfs_reapurb) HANDLE_IOCTL(USBDEVFS_DISCSIGNAL32, do_usbdevfs_discsignal) /* take care of sizeof(sizeof()) breakage */ -/* block stuff */ -HANDLE_IOCTL(BLKBSZGET_32, do_blkbszget) -HANDLE_IOCTL(BLKBSZSET_32, do_blkbszset) -HANDLE_IOCTL(BLKGETSIZE64_32, do_blkgetsize64) /* mtrr */ HANDLE_IOCTL(MTRRIOC32_ADD_ENTRY, mtrr_ioctl32) HANDLE_IOCTL(MTRRIOC32_SET_ENTRY, mtrr_ioctl32) diff -Nru a/arch/x86_64/kernel/apic.c b/arch/x86_64/kernel/apic.c --- a/arch/x86_64/kernel/apic.c Mon Jun 9 23:16:07 2003 +++ b/arch/x86_64/kernel/apic.c Mon Jun 9 23:16:07 2003 @@ -10,6 +10,8 @@ * for testing these extensively. * Maciej W. Rozycki : Various updates and fixes. * Mikael Pettersson : Power Management for UP-APIC. + * Pavel Machek and + * Mikael Pettersson : PM converted to driver model. */ #include <linux/config.h> @@ -120,7 +122,7 @@ * PIC mode, enable APIC mode in the IMCR, i.e. * connect BSP's local APIC to INT and NMI lines. */ - printk("leaving PIC mode, enabling APIC mode.\n"); + printk(KERN_INFO "leaving PIC mode, enabling APIC mode.\n"); outb(0x70, 0x22); outb(0x01, 0x23); } @@ -135,7 +137,7 @@ * interrupts, including IPIs, won't work beyond * this point! The only exception are INIT IPIs. */ - printk("disabling APIC mode, entering PIC mode.\n"); + printk(KERN_INFO "disabling APIC mode, entering PIC mode.\n"); outb(0x70, 0x22); outb(0x00, 0x23); } @@ -438,17 +440,14 @@ #ifdef CONFIG_PM -#include <linux/slab.h> -#include <linux/pm.h> +#include <linux/device.h> +#include <linux/module.h> static struct { /* 'active' is true if the local APIC was enabled by us and not the BIOS; this signifies that we are also responsible for disabling it before entering apm/acpi suspend */ int active; - /* 'perfctr_pmdev' is here because the current (2.4.1) PM - callback system doesn't handle hierarchical dependencies */ - struct pm_dev *perfctr_pmdev; /* r/w apic fields */ unsigned int apic_id; unsigned int apic_taskpri; @@ -465,13 +464,16 @@ unsigned int apic_thmr; } apic_pm_state; -static void apic_pm_suspend(void *data) +static int lapic_suspend(struct device *dev, u32 state, u32 level) { unsigned int l, h; unsigned long flags; - if (apic_pm_state.perfctr_pmdev) - pm_send(apic_pm_state.perfctr_pmdev, PM_SUSPEND, data); + if (level != SUSPEND_POWER_DOWN) + return 0; + if (!apic_pm_state.active) + return 0; + apic_pm_state.apic_id = apic_read(APIC_ID); apic_pm_state.apic_taskpri = apic_read(APIC_TASKPRI); apic_pm_state.apic_ldr = apic_read(APIC_LDR); @@ -492,15 +494,23 @@ l &= ~MSR_IA32_APICBASE_ENABLE; wrmsr(MSR_IA32_APICBASE, l, h); local_irq_restore(flags); + return 0; } -static void apic_pm_resume(void *data) +static int lapic_resume(struct device *dev, u32 level) { unsigned int l, h; unsigned long flags; - local_save_flags(flags); - local_irq_disable(); + if (level != RESUME_POWER_ON) + return 0; + if (!apic_pm_state.active) + return 0; + + /* XXX: Pavel needs this for S3 resume, but can't explain why */ + set_fixmap_nocache(FIX_APIC_BASE, APIC_DEFAULT_PHYS_BASE); + + local_irq_save(flags); rdmsr(MSR_IA32_APICBASE, l, h); l &= ~MSR_IA32_APICBASE_BASE; l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE; @@ -524,141 +534,69 @@ apic_write(APIC_ESR, 0); apic_read(APIC_ESR); local_irq_restore(flags); - if (apic_pm_state.perfctr_pmdev) - pm_send(apic_pm_state.perfctr_pmdev, PM_RESUME, data); -} - -static int apic_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) -{ - switch (rqst) { - case PM_SUSPEND: - apic_pm_suspend(data); - break; - case PM_RESUME: - apic_pm_resume(data); - break; - } return 0; } -/* perfctr driver should call this instead of pm_register() */ -struct pm_dev *apic_pm_register(pm_dev_t type, - unsigned long id, - pm_callback callback) -{ - struct pm_dev *dev; - - if (!apic_pm_state.active) - return pm_register(type, id, callback); - if (apic_pm_state.perfctr_pmdev) - return NULL; /* we're busy */ - dev = kmalloc(sizeof(struct pm_dev), GFP_KERNEL); - if (dev) { - memset(dev, 0, sizeof(*dev)); - dev->type = type; - dev->id = id; - dev->callback = callback; - apic_pm_state.perfctr_pmdev = dev; - } - return dev; -} +static struct device_driver lapic_driver = { + .name = "lapic", + .bus = &system_bus_type, + .resume = lapic_resume, + .suspend = lapic_suspend, +}; + +/* not static, needed by child devices */ +struct sys_device device_lapic = { + .name = "lapic", + .id = 0, + .dev = { + .name = "lapic", + .driver = &lapic_driver, + }, +}; +EXPORT_SYMBOL(device_lapic); -/* perfctr driver should call this instead of pm_unregister() */ -void apic_pm_unregister(struct pm_dev *dev) +static void __init apic_pm_activate(void) { - if (!apic_pm_state.active) { - pm_unregister(dev); - } else if (dev == apic_pm_state.perfctr_pmdev) { - apic_pm_state.perfctr_pmdev = NULL; - kfree(dev); - } -} - -static void __init apic_pm_init1(void) -{ - /* can't pm_register() at this early stage in the boot process - (causes an immediate reboot), so just set the flag */ apic_pm_state.active = 1; } -static void __init apic_pm_init2(void) +static int __init init_lapic_devicefs(void) { - if (apic_pm_state.active) - pm_register(PM_SYS_DEV, 0, apic_pm_callback); + if (!cpu_has_apic) + return 0; + /* XXX: remove suspend/resume procs if !apic_pm_state.active? */ + driver_register(&lapic_driver); + return sys_device_register(&device_lapic); } +device_initcall(init_lapic_devicefs); #else /* CONFIG_PM */ -static inline void apic_pm_init1(void) { } -static inline void apic_pm_init2(void) { } +static inline void apic_pm_activate(void) { } #endif /* CONFIG_PM */ /* * Detect and enable local APICs on non-SMP boards. * Original code written by Keir Fraser. + * On AMD64 we trust the BIOS - if it says no APIC it is likely + * not correctly set up (usually the APIC timer won't work etc.) */ static int __init detect_init_APIC (void) { - u32 h, l, features; - extern void get_cpu_vendor(struct cpuinfo_x86*); - - /* Workaround for us being called before identify_cpu(). */ - get_cpu_vendor(&boot_cpu_data); - - switch (boot_cpu_data.x86_vendor) { - case X86_VENDOR_AMD: - if (boot_cpu_data.x86 > 6) - break; - goto no_apic; - case X86_VENDOR_INTEL: - if (boot_cpu_data.x86 == 6 || - (boot_cpu_data.x86 == 15 && cpu_has_apic) || - (boot_cpu_data.x86 == 5 && cpu_has_apic)) - break; - goto no_apic; - default: - goto no_apic; - } - if (!cpu_has_apic) { - /* - * Some BIOSes disable the local APIC in the - * APIC_BASE MSR. This can only be done in - * software for Intel P6 and AMD K7 (Model > 1). - */ - rdmsr(MSR_IA32_APICBASE, l, h); - if (!(l & MSR_IA32_APICBASE_ENABLE)) { - printk("Local APIC disabled by BIOS -- reenabling.\n"); - l &= ~MSR_IA32_APICBASE_BASE; - l |= MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE; - wrmsr(MSR_IA32_APICBASE, l, h); - } - } - /* - * The APIC feature bit should now be enabled - * in `cpuid' - */ - features = cpuid_edx(1); - if (!(features & (1 << X86_FEATURE_APIC))) { - printk("Could not enable APIC!\n"); + printk(KERN_INFO "No local APIC present\n"); return -1; } - set_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability); + mp_lapic_addr = APIC_DEFAULT_PHYS_BASE; boot_cpu_id = 0; if (nmi_watchdog != NMI_NONE) nmi_watchdog = NMI_LOCAL_APIC; - apic_pm_init1(); - - printk("Found and enabled local APIC!\n"); + apic_pm_activate(); return 0; - -no_apic: - printk("No local APIC present or hardware disabled\n"); - return -1; } void __init init_apic_mappings(void) @@ -745,13 +683,11 @@ local_irq_save(flags); -#if 0 /* For some reasons this doesn't work on Simics, so fake it for now */ - if (strstr(boot_cpu_data.x86_model_id, "Screwdriver")) { + if (!strstr(boot_cpu_data.x86_model_id, "Screwdriver")) { __setup_APIC_LVTT(clocks); return; } -#endif /* wait for irq slice */ { @@ -808,7 +744,7 @@ result = (apic_start - apic) * 1000L * cpu_khz / (tsc - tsc_start); - printk("Detected %d.%03d MHz APIC timer.\n", + printk(KERN_INFO "Detected %d.%03d MHz APIC timer.\n", result / 1000 / 1000, result / 1000 % 1000); return result * APIC_DIVISOR / HZ; @@ -819,11 +755,11 @@ void __init setup_boot_APIC_clock (void) { if (disable_apic_timer) { - printk("Disabling APIC timer\n"); + printk(KERN_INFO "Disabling APIC timer\n"); return; } - printk("Using local APIC timer interrupts.\n"); + printk(KERN_INFO "Using local APIC timer interrupts.\n"); using_apic_timer = 1; local_irq_disable(); @@ -1051,18 +987,9 @@ printk(KERN_INFO "Apic disabled\n"); return -1; } - if (!smp_found_config && !cpu_has_apic) { - disable_apic = 1; - return -1; - } - - /* - * Complain if the BIOS pretends there is one. - */ - if (!cpu_has_apic && APIC_INTEGRATED(apic_version[boot_cpu_id])) { - printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n", - boot_cpu_id); + if (!cpu_has_apic) { disable_apic = 1; + printk(KERN_INFO "Apic disabled by BIOS\n"); return -1; } @@ -1072,8 +999,6 @@ phys_cpu_present_map = 1; apic_write_around(APIC_ID, boot_cpu_id); - - apic_pm_init2(); setup_local_APIC(); diff -Nru a/arch/x86_64/kernel/asm-offsets.c b/arch/x86_64/kernel/asm-offsets.c --- a/arch/x86_64/kernel/asm-offsets.c Mon Jun 9 23:16:13 2003 +++ b/arch/x86_64/kernel/asm-offsets.c Mon Jun 9 23:16:13 2003 @@ -44,6 +44,7 @@ ENTRY(irqstackptr); BLANK(); #undef ENTRY +#ifdef CONFIG_IA32_EMULATION #define ENTRY(entry) DEFINE(IA32_SIGCONTEXT_ ## entry, offsetof(struct sigcontext_ia32, entry)) ENTRY(eax); ENTRY(ebx); @@ -59,6 +60,7 @@ DEFINE(IA32_RT_SIGFRAME_sigcontext, offsetof (struct rt_sigframe32, uc.uc_mcontext)); BLANK(); +#endif return 0; } diff -Nru a/arch/x86_64/kernel/bluesmoke.c b/arch/x86_64/kernel/bluesmoke.c --- a/arch/x86_64/kernel/bluesmoke.c Mon Jun 9 23:16:18 2003 +++ b/arch/x86_64/kernel/bluesmoke.c Mon Jun 9 23:16:18 2003 @@ -125,9 +125,9 @@ static struct pci_dev *find_k8_nb(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; int cpu = smp_processor_id(); - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { if (dev->bus->number==0 && PCI_FUNC(dev->devfn)==3 && PCI_SLOT(dev->devfn) == (24U+cpu)) return dev; diff -Nru a/arch/x86_64/kernel/irq.c b/arch/x86_64/kernel/irq.c --- a/arch/x86_64/kernel/irq.c Mon Jun 9 23:16:10 2003 +++ b/arch/x86_64/kernel/irq.c Mon Jun 9 23:16:10 2003 @@ -65,8 +65,12 @@ /* * Controller mappings for all interrupt sources: */ -irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = - { [0 ... NR_IRQS-1] = { 0, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}}; +irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = { + [0 ... NR_IRQS-1] = { + .handler = &no_irq_type, + .lock = SPIN_LOCK_UNLOCKED + } +}; static void register_irq_proc (unsigned int irq); diff -Nru a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c --- a/arch/x86_64/kernel/nmi.c Mon Jun 9 23:16:11 2003 +++ b/arch/x86_64/kernel/nmi.c Mon Jun 9 23:16:11 2003 @@ -8,6 +8,8 @@ * Fixes: * Mikael Pettersson : AMD K7 support for local APIC NMI watchdog. * Mikael Pettersson : Power Management for local APIC NMI watchdog. + * Pavel Machek and + * Mikael Pettersson : PM converted to driver model. Disable/enable API. */ #include <linux/config.h> @@ -19,6 +21,7 @@ #include <linux/interrupt.h> #include <linux/mc146818rtc.h> #include <linux/kernel_stat.h> +#include <linux/module.h> #include <asm/smp.h> #include <asm/mtrr.h> @@ -113,14 +116,18 @@ __setup("nmi_watchdog=", setup_nmi_watchdog); -#ifdef CONFIG_PM - -#include <linux/pm.h> - -struct pm_dev *nmi_pmdev; +/* nmi_active: + * +1: the lapic NMI watchdog is active, but can be disabled + * 0: the lapic NMI watchdog has not been set up, and cannot + * be enabled + * -1: the lapic NMI watchdog is disabled, but can be enabled + */ +static int nmi_active; -static void disable_apic_nmi_watchdog(void) +void disable_lapic_nmi_watchdog(void) { + if (nmi_active <= 0) + return; switch (boot_cpu_data.x86_vendor) { case X86_VENDOR_AMD: wrmsr(MSR_K7_EVNTSEL0, 0, 0); @@ -129,46 +136,66 @@ wrmsr(MSR_IA32_EVNTSEL0, 0, 0); break; } -} - -static int nmi_pm_callback(struct pm_dev *dev, pm_request_t rqst, void *data) -{ - switch (rqst) { - case PM_SUSPEND: - disable_apic_nmi_watchdog(); - break; - case PM_RESUME: + nmi_active = -1; + /* tell do_nmi() and others that we're not active any more */ + nmi_watchdog = 0; +} +void enable_lapic_nmi_watchdog(void) + { + if (nmi_active < 0) { + nmi_watchdog = NMI_LOCAL_APIC; setup_apic_nmi_watchdog(); - break; } - return 0; -} - -struct pm_dev * set_nmi_pm_callback(pm_callback callback) -{ - apic_pm_unregister(nmi_pmdev); - return apic_pm_register(PM_SYS_DEV, 0, callback); -} + } -void unset_nmi_pm_callback(struct pm_dev * dev) -{ - apic_pm_unregister(dev); - nmi_pmdev = apic_pm_register(PM_SYS_DEV, 0, nmi_pm_callback); -} +#ifdef CONFIG_PM -static void nmi_pm_init(void) -{ - if (!nmi_pmdev) - nmi_pmdev = apic_pm_register(PM_SYS_DEV, 0, nmi_pm_callback); -} +#include <linux/device.h> -#define __pminit /*empty*/ +static int lapic_nmi_suspend(struct device *dev, u32 state, u32 level) + { + if (level != SUSPEND_POWER_DOWN) + return 0; + disable_lapic_nmi_watchdog(); + return 0; + } -#else /* CONFIG_PM */ +static int lapic_nmi_resume(struct device *dev, u32 level) + { + if (level != RESUME_POWER_ON) + return 0; +#if 0 + enable_lapic_nmi_watchdog(); +#endif + return 0; + } -static inline void nmi_pm_init(void) { } +static struct device_driver lapic_nmi_driver = { + .name = "lapic_nmi", + .bus = &system_bus_type, + .resume = lapic_nmi_resume, + .suspend = lapic_nmi_suspend, +}; + +static struct sys_device device_lapic_nmi = { + .name = "lapic_nmi", + .id = 0, + .dev = { + .name = "lapic_nmi", + .driver = &lapic_nmi_driver, + .parent = &device_lapic.dev, + }, +}; -#define __pminit __init +static int __init init_lapic_nmi_devicefs(void) +{ + if (nmi_active == 0) + return 0; + driver_register(&lapic_nmi_driver); + return sys_device_register(&device_lapic_nmi); +} +/* must come after the local APIC's device_initcall() */ +late_initcall(init_lapic_nmi_devicefs); #endif /* CONFIG_PM */ @@ -217,7 +244,7 @@ default: return; } - nmi_pm_init(); + nmi_active = 1; } static spinlock_t nmi_print_lock = SPIN_LOCK_UNLOCKED; @@ -261,7 +288,6 @@ int sum, cpu = safe_smp_processor_id(); sum = read_pda(apic_timer_irqs); - if (last_irq_sums[cpu] == sum) { /* * Ayiee, looks like this CPU is stuck ... @@ -307,16 +333,11 @@ int cpu = safe_smp_processor_id(); init_tss[cpu].ist[NMI_STACK] -= 2048; /* this shouldn't be needed. */ - nmi_enter(); - add_pda(__nmi_count,1); - if (!nmi_callback(regs, cpu)) default_do_nmi(regs); - nmi_exit(); - init_tss[cpu].ist[NMI_STACK] += 2048; } @@ -329,3 +350,7 @@ { nmi_callback = dummy_nmi_callback; } + +EXPORT_SYMBOL(nmi_watchdog); +EXPORT_SYMBOL(disable_lapic_nmi_watchdog); +EXPORT_SYMBOL(enable_lapic_nmi_watchdog); diff -Nru a/arch/x86_64/kernel/pci-gart.c b/arch/x86_64/kernel/pci-gart.c --- a/arch/x86_64/kernel/pci-gart.c Mon Jun 9 23:16:10 2003 +++ b/arch/x86_64/kernel/pci-gart.c Mon Jun 9 23:16:10 2003 @@ -67,7 +67,8 @@ #define GPTE_DECODE(x) (((x) & 0xfffff000) | (((u64)(x) & 0xff0) << 28)) #define for_all_nb(dev) \ - pci_for_each_dev(dev) \ + dev=NULL; \ + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) \ if (dev->bus->number == 0 && PCI_FUNC(dev->devfn) == 3 && \ (PCI_SLOT(dev->devfn) >= 24) && (PCI_SLOT(dev->devfn) <= 31)) diff -Nru a/arch/x86_64/kernel/reboot.c b/arch/x86_64/kernel/reboot.c --- a/arch/x86_64/kernel/reboot.c Mon Jun 9 23:16:17 2003 +++ b/arch/x86_64/kernel/reboot.c Mon Jun 9 23:16:17 2003 @@ -12,6 +12,7 @@ #include <asm/system.h> #include <asm/pgtable.h> #include <asm/tlbflush.h> +#include <asm/apic.h> /* * Power off function, if any @@ -93,21 +94,24 @@ static void smp_halt(void) { int cpuid = safe_smp_processor_id(); - - /* Only run this on the boot processor */ - if (cpuid != boot_cpu_id) { static int first_entry = 1; + if (first_entry) { first_entry = 0; smp_call_function((void *)machine_restart, NULL, 1, 0); - } else { - /* AP reentering. just halt */ - for(;;) - asm volatile("hlt"); } + smp_stop_cpu(); + + /* AP calling this. Just halt */ + if (cpuid != boot_cpu_id) { + for (;;) + asm("hlt"); } - smp_send_stop(); + + /* Wait for all other CPUs to have run smp_stop_cpu */ + while (cpu_online_map) + rep_nop(); } #endif @@ -124,11 +128,19 @@ { int i; -#if CONFIG_SMP +#ifdef CONFIG_SMP smp_halt(); #endif + local_irq_disable(); + +#ifndef CONFIG_SMP + disable_local_APIC(); +#endif + disable_IO_APIC(); + + local_irq_enable(); /* Tell the BIOS if we want cold or warm reboot */ *((unsigned short *)__va(0x472)) = reboot_mode; diff -Nru a/arch/x86_64/kernel/setup.c b/arch/x86_64/kernel/setup.c --- a/arch/x86_64/kernel/setup.c Mon Jun 9 23:16:06 2003 +++ b/arch/x86_64/kernel/setup.c Mon Jun 9 23:16:06 2003 @@ -31,6 +31,7 @@ #include <linux/initrd.h> #include <linux/highmem.h> #include <linux/bootmem.h> +#include <linux/module.h> #include <asm/processor.h> #include <linux/console.h> #include <linux/seq_file.h> @@ -44,6 +45,7 @@ #include <asm/smp.h> #include <asm/msr.h> #include <asm/desc.h> +#include <video/edid.h> #include <asm/e820.h> #include <asm/dma.h> #include <asm/mpspec.h> @@ -52,8 +54,6 @@ #include <asm/smp.h> #include <asm/proto.h> -#define Dprintk(x...) printk(x) - /* * Machine setup.. */ @@ -61,6 +61,7 @@ struct cpuinfo_x86 boot_cpu_data; unsigned long mmu_cr4_features; +EXPORT_SYMBOL_GPL(mmu_cr4_features); int acpi_disabled __initdata = 0; @@ -79,6 +80,7 @@ unsigned char table[0]; }; +struct edid_info edid_info; struct e820map e820; unsigned char aux_device_present; @@ -241,11 +243,10 @@ void __init setup_arch(char **cmdline_p) { - Dprintk("setup_arch\n"); - ROOT_DEV = ORIG_ROOT_DEV; drive_info = DRIVE_INFO; screen_info = SCREEN_INFO; + edid_info = EDID_INFO; aux_device_present = AUX_DEVICE_INFO; saved_video_mode = SAVED_VIDEO_MODE; diff -Nru a/arch/x86_64/kernel/smp.c b/arch/x86_64/kernel/smp.c --- a/arch/x86_64/kernel/smp.c Mon Jun 9 23:16:08 2003 +++ b/arch/x86_64/kernel/smp.c Mon Jun 9 23:16:08 2003 @@ -425,7 +425,7 @@ return 0; } -static void stop_this_cpu (void * dummy) +void smp_stop_cpu(void) { /* * Remove this CPU: @@ -433,21 +433,20 @@ clear_bit(smp_processor_id(), &cpu_online_map); local_irq_disable(); disable_local_APIC(); - for(;;) __asm__("hlt"); - for (;;); + local_irq_enable(); } -/* - * this function calls the 'stop' function on all other CPUs in the system. - */ +static void smp_really_stop_cpu(void *dummy) +{ + smp_stop_cpu(); + for (;;) + asm("hlt"); +} void smp_send_stop(void) { - smp_call_function(stop_this_cpu, NULL, 1, 0); - - local_irq_disable(); - disable_local_APIC(); - local_irq_enable(); + smp_call_function(smp_really_stop_cpu, NULL, 1, 0); + smp_stop_cpu(); } /* diff -Nru a/arch/x86_64/kernel/suspend.c b/arch/x86_64/kernel/suspend.c --- a/arch/x86_64/kernel/suspend.c Mon Jun 9 23:16:12 2003 +++ b/arch/x86_64/kernel/suspend.c Mon Jun 9 23:16:12 2003 @@ -130,7 +130,7 @@ /* * Now maybe reload the debug registers */ - if (current->thread.debugreg[7]){ + if (current->thread.debugreg7){ loaddebug(¤t->thread, 0); loaddebug(¤t->thread, 1); loaddebug(¤t->thread, 2); diff -Nru a/arch/x86_64/kernel/sys_x86_64.c b/arch/x86_64/kernel/sys_x86_64.c --- a/arch/x86_64/kernel/sys_x86_64.c Mon Jun 9 23:16:15 2003 +++ b/arch/x86_64/kernel/sys_x86_64.c Mon Jun 9 23:16:15 2003 @@ -70,11 +70,14 @@ struct vm_area_struct *vma; unsigned long end = TASK_SIZE; +#ifdef CONFIG_IA32_EMULATION if (test_thread_flag(TIF_IA32)) { if (!addr) addr = TASK_UNMAPPED_32; end = IA32_PAGE_OFFSET; - } else if (flags & MAP_32BIT) { + } else +#endif + if (flags & MAP_32BIT) { /* This is usually used needed to map code in small model, so it needs to be in the first 31bit. Limit it to that. This means we need to move the unmapped base down for this case. This can diff -Nru a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c --- a/arch/x86_64/kernel/traps.c Mon Jun 9 23:16:05 2003 +++ b/arch/x86_64/kernel/traps.c Mon Jun 9 23:16:05 2003 @@ -318,19 +318,12 @@ BUG(); } -spinlock_t die_lock = SPIN_LOCK_UNLOCKED; -int die_owner = -1; +static spinlock_t die_lock = SPIN_LOCK_UNLOCKED; +static int die_owner = -1; -void die(const char * str, struct pt_regs * regs, long err) +void oops_begin(void) { - static int die_counter; - int cpu; - console_verbose(); - bust_spinlocks(1); - handle_BUG(regs); - printk(KERN_EMERG "%s: %04lx [%u]\n", str, err & 0xffff, ++die_counter); - notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV); - cpu = safe_smp_processor_id(); + int cpu = safe_smp_processor_id(); /* racy, but better than risking deadlock. */ local_irq_disable(); if (!spin_trylock(&die_lock)) { @@ -340,12 +333,29 @@ spin_lock(&die_lock); } die_owner = cpu; + console_verbose(); + bust_spinlocks(1); +} + +void __die(const char * str, struct pt_regs * regs, long err) +{ + static int die_counter; + handle_BUG(regs); + printk(KERN_EMERG "%s: %04lx [%u]\n", str, err & 0xffff, ++die_counter); + notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV); show_registers(regs); bust_spinlocks(0); + die_owner = -1; spin_unlock_irq(&die_lock); do_exit(SIGSEGV); } +void die(const char * str, struct pt_regs * regs, long err) +{ + oops_begin(); + __die(str, regs, err); +} + static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err) { if (!(regs->eflags & VM_MASK) && (regs->cs == __KERNEL_CS)) @@ -382,9 +392,13 @@ if ((regs->cs & 3) != 0) { struct task_struct *tsk = current; - if (exception_trace && trapnr != 3) - printk("%s[%d] trap %s at rip:%lx rsp:%lx err:%lx\n", - tsk->comm, tsk->pid, str, regs->rip, regs->rsp, error_code); + if (exception_trace && !(tsk->ptrace & PT_PTRACED) && + (tsk->sighand->action[signr-1].sa.sa_handler == SIG_IGN || + (tsk->sighand->action[signr-1].sa.sa_handler == SIG_DFL))) + printk(KERN_INFO + "%s[%d] trap %s rip:%lx rsp:%lx error:%lx\n", + tsk->comm, tsk->pid, str, + regs->rip,regs->rsp,error_code); tsk->thread.error_code = error_code; tsk->thread.trap_no = trapnr; @@ -401,12 +415,6 @@ const struct exception_table_entry *fixup; fixup = search_exception_tables(regs->rip); if (fixup) { - extern int exception_trace; - if (exception_trace) - printk(KERN_ERR - "%s: fixed kernel exception at %lx err:%ld\n", - current->comm, regs->rip, error_code); - regs->rip = fixup->fixup; } else die(str, regs, error_code); @@ -471,9 +479,14 @@ if ((regs->cs & 3)!=0) { struct task_struct *tsk = current; - if (exception_trace) - printk("%s[%d] #gp at rip:%lx rsp:%lx err:%lx\n", - tsk->comm, tsk->pid, regs->rip, regs->rsp, error_code); + + if (exception_trace && !(tsk->ptrace & PT_PTRACED) && + (tsk->sighand->action[SIGSEGV-1].sa.sa_handler == SIG_IGN || + (tsk->sighand->action[SIGSEGV-1].sa.sa_handler == SIG_DFL))) + printk(KERN_INFO + "%s[%d] general protection rip:%lx rsp:%lx error:%lx\n", + tsk->comm, tsk->pid, + regs->rip,regs->rsp,error_code); tsk->thread.error_code = error_code; tsk->thread.trap_no = 13; diff -Nru a/arch/x86_64/kernel/x8664_ksyms.c b/arch/x86_64/kernel/x8664_ksyms.c --- a/arch/x86_64/kernel/x8664_ksyms.c Mon Jun 9 23:16:08 2003 +++ b/arch/x86_64/kernel/x8664_ksyms.c Mon Jun 9 23:16:08 2003 @@ -95,6 +95,7 @@ EXPORT_SYMBOL(copy_user_generic); EXPORT_SYMBOL(copy_from_user); EXPORT_SYMBOL(copy_to_user); +EXPORT_SYMBOL(copy_in_user); EXPORT_SYMBOL(strnlen_user); EXPORT_SYMBOL(pci_alloc_consistent); @@ -119,11 +120,6 @@ EXPORT_SYMBOL(synchronize_irq); EXPORT_SYMBOL(smp_call_function); -#endif - -#if defined(CONFIG_X86_LOCAL_APIC) && defined(CONFIG_PM) -EXPORT_SYMBOL_GPL(set_nmi_pm_callback); -EXPORT_SYMBOL_GPL(unset_nmi_pm_callback); #endif #ifdef CONFIG_VT diff -Nru a/arch/x86_64/lib/Makefile b/arch/x86_64/lib/Makefile --- a/arch/x86_64/lib/Makefile Mon Jun 9 23:16:08 2003 +++ b/arch/x86_64/lib/Makefile Mon Jun 9 23:16:08 2003 @@ -2,13 +2,12 @@ # Makefile for x86_64-specific library files. # -L_TARGET := lib.a CFLAGS_csum-partial.o := -funroll-loops -obj-y := csum-partial.o csum-copy.o csum-wrappers.o delay.o \ +lib-y := csum-partial.o csum-copy.o csum-wrappers.o delay.o \ usercopy.o getuser.o putuser.o \ thunk.o io.o clear_page.o copy_page.o bitstr.o -obj-y += memcpy.o memmove.o memset.o copy_user.o +lib-y += memcpy.o memmove.o memset.o copy_user.o -obj-$(CONFIG_IO_DEBUG) += iodebug.o -obj-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o +lib-$(CONFIG_IO_DEBUG) += iodebug.o +lib-$(CONFIG_HAVE_DEC_LOCK) += dec_and_lock.o diff -Nru a/arch/x86_64/lib/usercopy.c b/arch/x86_64/lib/usercopy.c --- a/arch/x86_64/lib/usercopy.c Mon Jun 9 23:16:06 2003 +++ b/arch/x86_64/lib/usercopy.c Mon Jun 9 23:16:06 2003 @@ -141,3 +141,11 @@ s++; } } + +unsigned long copy_in_user(void *to, const void *from, unsigned len) +{ + if (access_ok(VERIFY_WRITE, to, len) && access_ok(VERIFY_READ, from, len)) { + return copy_user_generic(to, from, len); + } + return len; +} diff -Nru a/arch/x86_64/mm/fault.c b/arch/x86_64/mm/fault.c --- a/arch/x86_64/mm/fault.c Mon Jun 9 23:16:05 2003 +++ b/arch/x86_64/mm/fault.c Mon Jun 9 23:16:05 2003 @@ -32,10 +32,6 @@ #include <asm/tlbflush.h> #include <asm/proto.h> -extern void die(const char *,struct pt_regs *,long); - -extern spinlock_t console_lock; - void bust_spinlocks(int yes) { int loglevel_save = console_loglevel; @@ -238,10 +234,13 @@ /* User mode accesses just cause a SIGSEGV */ if (error_code & 4) { + if (exception_trace && !(tsk->ptrace & PT_PTRACED) && + (tsk->sighand->action[SIGSEGV-1].sa.sa_handler == SIG_IGN || + (tsk->sighand->action[SIGSEGV-1].sa.sa_handler == SIG_DFL))) printk(KERN_INFO - "%s[%d] segfault at rip:%lx rsp:%lx adr:%lx err:%lx\n", - tsk->comm, tsk->pid, regs->rip, regs->rsp, address, - error_code); + "%s[%d]: segfault at %016lx rip %016lx rsp %016lx error %lx\n", + tsk->comm, tsk->pid, address, regs->rip, + regs->rsp, error_code); tsk->thread.cr2 = address; tsk->thread.error_code = error_code; @@ -260,10 +259,6 @@ fixup = search_exception_tables(regs->rip); if (fixup) { regs->rip = fixup->fixup; - if (0 && exception_trace) - printk(KERN_ERR - "%s: fixed kernel exception at %lx address %lx err:%ld\n", - current->comm, regs->rip, address, error_code); return; } @@ -272,7 +267,7 @@ * terminate things with extreme prejudice. */ - bust_spinlocks(1); + oops_begin(); if (address < PAGE_SIZE) printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference"); @@ -282,8 +277,9 @@ printk(" printing rip:\n"); printk("%016lx\n", regs->rip); dump_pagetable(address); - die("Oops", regs, error_code); - bust_spinlocks(0); + __die("Oops", regs, error_code); + + /* never reached */ do_exit(SIGKILL); /* diff -Nru a/arch/x86_64/pci/irq.c b/arch/x86_64/pci/irq.c --- a/arch/x86_64/pci/irq.c Mon Jun 9 23:16:14 2003 +++ b/arch/x86_64/pci/irq.c Mon Jun 9 23:16:14 2003 @@ -391,7 +391,7 @@ int irq = 0; u32 mask; struct irq_router *r = pirq_router; - struct pci_dev *dev2; + struct pci_dev *dev2 = NULL; char *msg = NULL; /* Find IRQ pin */ @@ -483,7 +483,7 @@ printk(KERN_INFO "PCI: %s IRQ %d for device %s\n", msg, irq, dev->slot_name); /* Update IRQ for all devices with the same pirq value */ - pci_for_each_dev(dev2) { + while ((dev2 = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev2)) != NULL) { pci_read_config_byte(dev2, PCI_INTERRUPT_PIN, &pin); if (!pin) continue; @@ -511,11 +511,11 @@ void __init pcibios_fixup_irqs(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; u8 pin; DBG("PCI: IRQ fixup\n"); - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { /* * If the BIOS has set an out of range IRQ number, just ignore it. * Also keep track of which IRQ's are already in use. @@ -530,7 +530,8 @@ pirq_penalty[dev->irq]++; } - pci_for_each_dev(dev) { + dev = NULL; + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); #ifdef CONFIG_X86_IO_APIC /* diff -Nru a/arch/x86_64/pci/x86-64.c b/arch/x86_64/pci/x86-64.c --- a/arch/x86_64/pci/x86-64.c Mon Jun 9 23:16:19 2003 +++ b/arch/x86_64/pci/x86-64.c Mon Jun 9 23:16:19 2003 @@ -121,12 +121,12 @@ static void __init pcibios_allocate_resources(int pass) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; int idx, disabled; u16 command; struct resource *r, *pr; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { pci_read_config_word(dev, PCI_COMMAND, &command); for(idx = 0; idx < 6; idx++) { r = &dev->resource[idx]; @@ -166,11 +166,11 @@ static void __init pcibios_assign_resources(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; int idx; struct resource *r; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { int class = dev->class >> 8; /* Don't touch classless devices and host bridges */ diff -Nru a/crypto/Kconfig b/crypto/Kconfig --- a/crypto/Kconfig Mon Jun 9 23:16:18 2003 +++ b/crypto/Kconfig Mon Jun 9 23:16:18 2003 @@ -6,16 +6,12 @@ config CRYPTO bool "Cryptographic API" - default y if INET_AH=y || INET_AH=m || INET_ESP=y || INET_ESP=m || INET6_AH=y || INET6_AH=m || \ - INET6_ESP=y || INET6_ESP=m help This option provides the core Cryptographic API. config CRYPTO_HMAC bool "HMAC support" depends on CRYPTO - default y if INET_AH=y || INET_AH=m || INET_ESP=y || INET_ESP=m || INET6_AH=y || INET6_AH=m || \ - INET6_ESP=y || INET6_ESP=m help HMAC: Keyed-Hashing for Message Authentication (RFC2104). This is required for IPSec. @@ -35,16 +31,12 @@ config CRYPTO_MD5 tristate "MD5 digest algorithm" depends on CRYPTO - default y if INET_AH=y || INET_AH=m || INET_ESP=y || INET_ESP=m || INET6_AH=y || INET6_AH=m || \ - INET6_ESP=y || INET6_ESP=m help MD5 message digest algorithm (RFC1321). config CRYPTO_SHA1 tristate "SHA1 digest algorithm" depends on CRYPTO - default y if INET_AH=y || INET_AH=m || INET_ESP=y || INET_ESP=m || INET6_AH=y || INET6_AH=m || \ - INET6_ESP=y || INET6_ESP=m help SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2). @@ -72,7 +64,6 @@ config CRYPTO_DES tristate "DES and Triple DES EDE cipher algorithms" depends on CRYPTO - default y if INET_ESP=y || INET_ESP=m || INET6_ESP=y || INET6_ESP=m help DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3). @@ -138,7 +129,6 @@ config CRYPTO_DEFLATE tristate "Deflate compression algorithm" depends on CRYPTO - default y if INET_IPCOMP=y || INET_IPCOMP=m || INET6_IPCOMP=y || INET6_IPCOMP=m help This is the Deflate algorithm (RFC1951), specified for use in IPSec with the IPCOMP protocol (RFC3173, RFC2394). diff -Nru a/crypto/sha512.c b/crypto/sha512.c --- a/crypto/sha512.c Mon Jun 9 23:16:19 2003 +++ b/crypto/sha512.c Mon Jun 9 23:16:19 2003 @@ -48,33 +48,33 @@ } const u64 sha512_K[80] = { - 0x428a2f98d728ae22, 0x7137449123ef65cd, 0xb5c0fbcfec4d3b2f, - 0xe9b5dba58189dbbc, 0x3956c25bf348b538, 0x59f111f1b605d019, - 0x923f82a4af194f9b, 0xab1c5ed5da6d8118, 0xd807aa98a3030242, - 0x12835b0145706fbe, 0x243185be4ee4b28c, 0x550c7dc3d5ffb4e2, - 0x72be5d74f27b896f, 0x80deb1fe3b1696b1, 0x9bdc06a725c71235, - 0xc19bf174cf692694, 0xe49b69c19ef14ad2, 0xefbe4786384f25e3, - 0x0fc19dc68b8cd5b5, 0x240ca1cc77ac9c65, 0x2de92c6f592b0275, - 0x4a7484aa6ea6e483, 0x5cb0a9dcbd41fbd4, 0x76f988da831153b5, - 0x983e5152ee66dfab, 0xa831c66d2db43210, 0xb00327c898fb213f, - 0xbf597fc7beef0ee4, 0xc6e00bf33da88fc2, 0xd5a79147930aa725, - 0x06ca6351e003826f, 0x142929670a0e6e70, 0x27b70a8546d22ffc, - 0x2e1b21385c26c926, 0x4d2c6dfc5ac42aed, 0x53380d139d95b3df, - 0x650a73548baf63de, 0x766a0abb3c77b2a8, 0x81c2c92e47edaee6, - 0x92722c851482353b, 0xa2bfe8a14cf10364, 0xa81a664bbc423001, - 0xc24b8b70d0f89791, 0xc76c51a30654be30, 0xd192e819d6ef5218, - 0xd69906245565a910, 0xf40e35855771202a, 0x106aa07032bbd1b8, - 0x19a4c116b8d2d0c8, 0x1e376c085141ab53, 0x2748774cdf8eeb99, - 0x34b0bcb5e19b48a8, 0x391c0cb3c5c95a63, 0x4ed8aa4ae3418acb, - 0x5b9cca4f7763e373, 0x682e6ff3d6b2b8a3, 0x748f82ee5defb2fc, - 0x78a5636f43172f60, 0x84c87814a1f0ab72, 0x8cc702081a6439ec, - 0x90befffa23631e28, 0xa4506cebde82bde9, 0xbef9a3f7b2c67915, - 0xc67178f2e372532b, 0xca273eceea26619c, 0xd186b8c721c0c207, - 0xeada7dd6cde0eb1e, 0xf57d4f7fee6ed178, 0x06f067aa72176fba, - 0x0a637dc5a2c898a6, 0x113f9804bef90dae, 0x1b710b35131c471b, - 0x28db77f523047d84, 0x32caab7b40c72493, 0x3c9ebe0a15c9bebc, - 0x431d67c49c100d4c, 0x4cc5d4becb3e42b6, 0x597f299cfc657e2a, - 0x5fcb6fab3ad6faec, 0x6c44198c4a475817, + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, + 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, + 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL, + 0x12835b0145706fbeULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL, + 0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, + 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL, + 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, + 0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, + 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL, + 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, + 0x92722c851482353bULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, + 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL, + 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, 0x2748774cdf8eeb99ULL, + 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, + 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL, + 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, + 0xc67178f2e372532bULL, 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, + 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL, + 0x0a637dc5a2c898a6ULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL, + 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, + 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL, }; #define e0(x) (RORu64(x,28) ^ RORu64(x,34) ^ RORu64(x,39)) @@ -83,24 +83,24 @@ #define s1(x) (RORu64(x,19) ^ RORu64(x,61) ^ (x >> 6)) /* H* initial state for SHA-512 */ -#define H0 0x6a09e667f3bcc908 -#define H1 0xbb67ae8584caa73b -#define H2 0x3c6ef372fe94f82b -#define H3 0xa54ff53a5f1d36f1 -#define H4 0x510e527fade682d1 -#define H5 0x9b05688c2b3e6c1f -#define H6 0x1f83d9abfb41bd6b -#define H7 0x5be0cd19137e2179 +#define H0 0x6a09e667f3bcc908ULL +#define H1 0xbb67ae8584caa73bULL +#define H2 0x3c6ef372fe94f82bULL +#define H3 0xa54ff53a5f1d36f1ULL +#define H4 0x510e527fade682d1ULL +#define H5 0x9b05688c2b3e6c1fULL +#define H6 0x1f83d9abfb41bd6bULL +#define H7 0x5be0cd19137e2179ULL /* H'* initial state for SHA-384 */ -#define HP0 0xcbbb9d5dc1059ed8 -#define HP1 0x629a292a367cd507 -#define HP2 0x9159015a3070dd17 -#define HP3 0x152fecd8f70e5939 -#define HP4 0x67332667ffc00b31 -#define HP5 0x8eb44a8768581511 -#define HP6 0xdb0c2e0d64f98fa7 -#define HP7 0x47b5481dbefa4fa4 +#define HP0 0xcbbb9d5dc1059ed8ULL +#define HP1 0x629a292a367cd507ULL +#define HP2 0x9159015a3070dd17ULL +#define HP3 0x152fecd8f70e5939ULL +#define HP4 0x67332667ffc00b31ULL +#define HP5 0x8eb44a8768581511ULL +#define HP6 0xdb0c2e0d64f98fa7ULL +#define HP7 0x47b5481dbefa4fa4ULL static inline void LOAD_OP(int I, u64 *W, const u8 *input) { diff -Nru a/drivers/Makefile b/drivers/Makefile --- a/drivers/Makefile Mon Jun 9 23:16:17 2003 +++ b/drivers/Makefile Mon Jun 9 23:16:17 2003 @@ -31,7 +31,7 @@ obj-$(CONFIG_DIO) += dio/ obj-$(CONFIG_SBUS) += sbus/ obj-$(CONFIG_ZORRO) += zorro/ -obj-$(CONFIG_ALL_PPC) += macintosh/ +obj-$(CONFIG_PPC_PMAC) += macintosh/ obj-$(CONFIG_MAC) += macintosh/ obj-$(CONFIG_SGI) += sgi/ obj-$(CONFIG_PARIDE) += block/paride/ @@ -46,7 +46,6 @@ obj-$(CONFIG_PHONE) += telephony/ obj-$(CONFIG_MD) += md/ obj-$(CONFIG_BT) += bluetooth/ -obj-$(CONFIG_HOTPLUG_PCI) += hotplug/ obj-$(CONFIG_ISDN_BOOL) += isdn/ obj-$(CONFIG_MCA) += mca/ obj-$(CONFIG_EISA) += eisa/ diff -Nru a/drivers/acorn/char/Makefile b/drivers/acorn/char/Makefile --- a/drivers/acorn/char/Makefile Mon Jun 9 23:16:07 2003 +++ b/drivers/acorn/char/Makefile Mon Jun 9 23:16:07 2003 @@ -2,22 +2,6 @@ # Makefile for the acorn character device drivers. # -obj-arc := keyb_arc.o defkeymap-acorn.o - obj-$(CONFIG_ARCH_ACORN) += i2c.o pcf8583.o obj-$(CONFIG_L7200_KEYB) += defkeymap-l7200.o keyb_l7200.o obj-y += $(obj-$(MACHINE)) - -$(obj)/defkeymap-acorn.o: $(obj)/defkeymap-acorn.c - -# Uncomment if you're changing the keymap and have an appropriate -# loadkeys version for the map. By default, we'll use the shipped -# versions. -# GENERATE_KEYMAP := 1 - -ifdef GENERATE_KEYMAP - -$(obj)/defkeymap-acorn.c: $(obj)/%.c: $(src)/%.map - loadkeys --mktable $< > $@ - -endif diff -Nru a/drivers/acorn/char/defkeymap-acorn.c_shipped b/drivers/acorn/char/defkeymap-acorn.c_shipped --- a/drivers/acorn/char/defkeymap-acorn.c_shipped Mon Jun 9 23:16:16 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,262 +0,0 @@ -/* Do not edit this file! It was automatically generated by */ -/* loadkeys --mktable defkeymap.map > defkeymap.c */ - -#include <linux/types.h> -#include <linux/keyboard.h> -#include <linux/kd.h> - -u_short plain_map[NR_KEYS] = { - 0xf01b, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106, - 0xf107, 0xf108, 0xf109, 0xf10a, 0xf10b, 0xf200, 0xf209, 0xf205, - 0xf060, 0xf031, 0xf032, 0xf033, 0xf034, 0xf035, 0xf036, 0xf037, - 0xf038, 0xf039, 0xf030, 0xf02d, 0xf03d, 0xf0a3, 0xf07f, 0xf115, - 0xf114, 0xf118, 0xf208, 0xf30d, 0xf30c, 0xf314, 0xf009, 0xfb71, - 0xfb77, 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69, 0xfb6f, - 0xfb70, 0xf05b, 0xf05d, 0xf05c, 0xf116, 0xf117, 0xf119, 0xf307, - 0xf308, 0xf309, 0xf30b, 0xf702, 0xfb61, 0xfb73, 0xfb64, 0xfb66, - 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b, 0xf027, 0xf201, - 0xf304, 0xf305, 0xf306, 0xf30a, 0xf700, 0xf200, 0xfb7a, 0xfb78, - 0xfb63, 0xfb76, 0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, - 0xf700, 0xf603, 0xf301, 0xf302, 0xf303, 0xf207, 0xf703, 0xf020, - 0xf701, 0xf702, 0xf601, 0xf600, 0xf602, 0xf300, 0xf310, 0xf30e, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -}; - -u_short shift_map[NR_KEYS] = { - 0xf01b, 0xf10a, 0xf10b, 0xf10c, 0xf10d, 0xf10e, 0xf10f, 0xf110, - 0xf111, 0xf112, 0xf113, 0xf10a, 0xf10b, 0xf200, 0xf203, 0xf205, - 0xf07e, 0xf021, 0xf040, 0xf023, 0xf024, 0xf025, 0xf05e, 0xf026, - 0xf02a, 0xf028, 0xf029, 0xf05f, 0xf02b, 0xf0a4, 0xf07f, 0xf115, - 0xf114, 0xf20b, 0xf208, 0xf30d, 0xf30c, 0xf314, 0xf009, 0xfb51, - 0xfb57, 0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55, 0xfb49, 0xfb4f, - 0xfb50, 0xf07b, 0xf07d, 0xf07c, 0xf116, 0xf117, 0xf20a, 0xf307, - 0xf308, 0xf309, 0xf30b, 0xf702, 0xfb41, 0xfb53, 0xfb44, 0xfb46, - 0xfb47, 0xfb48, 0xfb4a, 0xfb4b, 0xfb4c, 0xf03a, 0xf022, 0xf201, - 0xf304, 0xf305, 0xf306, 0xf30a, 0xf700, 0xf200, 0xfb5a, 0xfb58, - 0xfb43, 0xfb56, 0xfb42, 0xfb4e, 0xfb4d, 0xf03c, 0xf03e, 0xf03f, - 0xf700, 0xf603, 0xf301, 0xf302, 0xf303, 0xf207, 0xf703, 0xf020, - 0xf701, 0xf702, 0xf601, 0xf600, 0xf602, 0xf300, 0xf310, 0xf30e, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -}; - -u_short altgr_map[NR_KEYS] = { - 0xf200, 0xf50c, 0xf50d, 0xf50e, 0xf50f, 0xf510, 0xf511, 0xf512, - 0xf513, 0xf514, 0xf515, 0xf516, 0xf517, 0xf200, 0xf202, 0xf205, - 0xf200, 0xf200, 0xf040, 0xf200, 0xf024, 0xf200, 0xf200, 0xf07b, - 0xf05b, 0xf05d, 0xf07d, 0xf05c, 0xf200, 0xf200, 0xf200, 0xf115, - 0xf114, 0xf118, 0xf208, 0xf30d, 0xf30c, 0xf314, 0xf200, 0xfb71, - 0xfb77, 0xf918, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69, 0xfb6f, - 0xfb70, 0xf200, 0xf07e, 0xf200, 0xf116, 0xf117, 0xf119, 0xf911, - 0xf912, 0xf913, 0xf30b, 0xf702, 0xf914, 0xfb73, 0xf917, 0xf919, - 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf200, 0xf200, 0xf201, - 0xf90e, 0xf90f, 0xf910, 0xf30a, 0xf700, 0xf200, 0xfb7a, 0xfb78, - 0xf916, 0xfb76, 0xf915, 0xfb6e, 0xfb6d, 0xf200, 0xf200, 0xf200, - 0xf700, 0xf603, 0xf90b, 0xf90c, 0xf90d, 0xf207, 0xf703, 0xf200, - 0xf701, 0xf702, 0xf601, 0xf600, 0xf602, 0xf90a, 0xf310, 0xf30e, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -}; - -u_short ctrl_map[NR_KEYS] = { - 0xf200, 0xf100, 0xf101, 0xf102, 0xf103, 0xf104, 0xf105, 0xf106, - 0xf107, 0xf108, 0xf109, 0xf10a, 0xf10b, 0xf200, 0xf204, 0xf205, - 0xf200, 0xf200, 0xf000, 0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f, - 0xf07f, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf008, 0xf115, - 0xf114, 0xf118, 0xf208, 0xf30d, 0xf30c, 0xf314, 0xf200, 0xf011, - 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009, 0xf00f, - 0xf010, 0xf01b, 0xf01d, 0xf01c, 0xf116, 0xf117, 0xf119, 0xf307, - 0xf308, 0xf309, 0xf30b, 0xf702, 0xf001, 0xf013, 0xf004, 0xf006, - 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200, 0xf007, 0xf201, - 0xf304, 0xf305, 0xf306, 0xf30a, 0xf700, 0xf200, 0xf01a, 0xf018, - 0xf003, 0xf016, 0xf002, 0xf00e, 0xf00d, 0xf200, 0xf20e, 0xf07f, - 0xf700, 0xf603, 0xf301, 0xf302, 0xf303, 0xf207, 0xf703, 0xf000, - 0xf701, 0xf702, 0xf601, 0xf600, 0xf602, 0xf300, 0xf310, 0xf30e, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -}; - -u_short shift_ctrl_map[NR_KEYS] = { - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf209, 0xf205, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf01f, 0xf200, 0xf200, 0xf200, 0xf115, - 0xf114, 0xf118, 0xf208, 0xf30d, 0xf30c, 0xf314, 0xf200, 0xf011, - 0xf017, 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009, 0xf00f, - 0xf010, 0xf200, 0xf200, 0xf200, 0xf116, 0xf117, 0xf119, 0xf307, - 0xf308, 0xf309, 0xf30b, 0xf702, 0xf001, 0xf013, 0xf004, 0xf006, - 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200, 0xf200, 0xf201, - 0xf304, 0xf305, 0xf306, 0xf30a, 0xf700, 0xf200, 0xf01a, 0xf018, - 0xf003, 0xf016, 0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf200, - 0xf700, 0xf603, 0xf301, 0xf302, 0xf303, 0xf207, 0xf703, 0xf200, - 0xf701, 0xf702, 0xf601, 0xf600, 0xf602, 0xf300, 0xf310, 0xf30e, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -}; - -u_short alt_map[NR_KEYS] = { - 0xf81b, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, 0xf505, 0xf506, - 0xf507, 0xf508, 0xf509, 0xf50a, 0xf50b, 0xf200, 0xf209, 0xf205, - 0xf860, 0xf831, 0xf832, 0xf833, 0xf834, 0xf835, 0xf836, 0xf837, - 0xf838, 0xf839, 0xf830, 0xf82d, 0xf83d, 0xf8a3, 0xf87f, 0xf115, - 0xf114, 0xf118, 0xf208, 0xf30d, 0xf30c, 0xf314, 0xf809, 0xf871, - 0xf877, 0xf865, 0xf872, 0xf874, 0xf879, 0xf875, 0xf869, 0xf86f, - 0xf870, 0xf85b, 0xf85d, 0xf85c, 0xf116, 0xf117, 0xf119, 0xf907, - 0xf908, 0xf909, 0xf30b, 0xf702, 0xf861, 0xf873, 0xf864, 0xf866, - 0xf867, 0xf868, 0xf86a, 0xf86b, 0xf86c, 0xf83b, 0xf827, 0xf80d, - 0xf904, 0xf905, 0xf906, 0xf30a, 0xf700, 0xf200, 0xf87a, 0xf878, - 0xf863, 0xf876, 0xf862, 0xf86e, 0xf86d, 0xf82c, 0xf82e, 0xf82f, - 0xf700, 0xf603, 0xf901, 0xf902, 0xf903, 0xf207, 0xf703, 0xf820, - 0xf701, 0xf702, 0xf210, 0xf600, 0xf211, 0xf900, 0xf310, 0xf30e, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -}; - -u_short ctrl_alt_map[NR_KEYS] = { - 0xf200, 0xf500, 0xf501, 0xf502, 0xf503, 0xf504, 0xf505, 0xf506, - 0xf507, 0xf508, 0xf509, 0xf50a, 0xf50b, 0xf200, 0xf209, 0xf205, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf115, - 0xf114, 0xf118, 0xf208, 0xf30d, 0xf30c, 0xf314, 0xf200, 0xf811, - 0xf817, 0xf805, 0xf812, 0xf814, 0xf819, 0xf815, 0xf809, 0xf80f, - 0xf810, 0xf200, 0xf200, 0xf200, 0xf20c, 0xf117, 0xf119, 0xf307, - 0xf308, 0xf309, 0xf30b, 0xf702, 0xf801, 0xf813, 0xf804, 0xf806, - 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c, 0xf200, 0xf200, 0xf201, - 0xf304, 0xf305, 0xf306, 0xf30a, 0xf700, 0xf200, 0xf81a, 0xf818, - 0xf803, 0xf816, 0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf200, - 0xf700, 0xf603, 0xf301, 0xf302, 0xf303, 0xf207, 0xf703, 0xf200, - 0xf701, 0xf702, 0xf601, 0xf600, 0xf602, 0xf300, 0xf20c, 0xf30e, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, - 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, -}; - -ushort *key_maps[MAX_NR_KEYMAPS] = { - plain_map, shift_map, altgr_map, 0, - ctrl_map, shift_ctrl_map, 0, 0, - alt_map, 0, 0, 0, - ctrl_alt_map, 0 -}; - -unsigned int keymap_count = 7; - -/* - * Philosophy: most people do not define more strings, but they who do - * often want quite a lot of string space. So, we statically allocate - * the default and allocate dynamically in chunks of 512 bytes. - */ - -char func_buf[] = { - '\033', '[', '[', 'A', 0, - '\033', '[', '[', 'B', 0, - '\033', '[', '[', 'C', 0, - '\033', '[', '[', 'D', 0, - '\033', '[', '[', 'E', 0, - '\033', '[', '1', '7', '~', 0, - '\033', '[', '1', '8', '~', 0, - '\033', '[', '1', '9', '~', 0, - '\033', '[', '2', '0', '~', 0, - '\033', '[', '2', '1', '~', 0, - '\033', '[', '2', '3', '~', 0, - '\033', '[', '2', '4', '~', 0, - '\033', '[', '2', '5', '~', 0, - '\033', '[', '2', '6', '~', 0, - '\033', '[', '2', '8', '~', 0, - '\033', '[', '2', '9', '~', 0, - '\033', '[', '3', '1', '~', 0, - '\033', '[', '3', '2', '~', 0, - '\033', '[', '3', '3', '~', 0, - '\033', '[', '3', '4', '~', 0, - '\033', '[', '1', '~', 0, - '\033', '[', '2', '~', 0, - '\033', '[', '3', '~', 0, - '\033', '[', '4', '~', 0, - '\033', '[', '5', '~', 0, - '\033', '[', '6', '~', 0, - '\033', '[', 'M', 0, - '\033', '[', 'P', 0, -}; - -char *funcbufptr = func_buf; -int funcbufsize = sizeof(func_buf); -int funcbufleft = 0; /* space left */ - -char *func_table[MAX_NR_FUNC] = { - func_buf + 0, - func_buf + 5, - func_buf + 10, - func_buf + 15, - func_buf + 20, - func_buf + 25, - func_buf + 31, - func_buf + 37, - func_buf + 43, - func_buf + 49, - func_buf + 55, - func_buf + 61, - func_buf + 67, - func_buf + 73, - func_buf + 79, - func_buf + 85, - func_buf + 91, - func_buf + 97, - func_buf + 103, - func_buf + 109, - func_buf + 115, - func_buf + 120, - func_buf + 125, - func_buf + 130, - func_buf + 135, - func_buf + 140, - func_buf + 145, - 0, - 0, - func_buf + 149, - 0, -}; - -struct kbdiacr accent_table[MAX_DIACR] = { - {'`', 'A', '\300'}, {'`', 'a', '\340'}, - {'\'', 'A', '\301'}, {'\'', 'a', '\341'}, - {'^', 'A', '\302'}, {'^', 'a', '\342'}, - {'~', 'A', '\303'}, {'~', 'a', '\343'}, - {'"', 'A', '\304'}, {'"', 'a', '\344'}, - {'O', 'A', '\305'}, {'o', 'a', '\345'}, - {'0', 'A', '\305'}, {'0', 'a', '\345'}, - {'A', 'A', '\305'}, {'a', 'a', '\345'}, - {'A', 'E', '\306'}, {'a', 'e', '\346'}, - {',', 'C', '\307'}, {',', 'c', '\347'}, - {'`', 'E', '\310'}, {'`', 'e', '\350'}, - {'\'', 'E', '\311'}, {'\'', 'e', '\351'}, - {'^', 'E', '\312'}, {'^', 'e', '\352'}, - {'"', 'E', '\313'}, {'"', 'e', '\353'}, - {'`', 'I', '\314'}, {'`', 'i', '\354'}, - {'\'', 'I', '\315'}, {'\'', 'i', '\355'}, - {'^', 'I', '\316'}, {'^', 'i', '\356'}, - {'"', 'I', '\317'}, {'"', 'i', '\357'}, - {'-', 'D', '\320'}, {'-', 'd', '\360'}, - {'~', 'N', '\321'}, {'~', 'n', '\361'}, - {'`', 'O', '\322'}, {'`', 'o', '\362'}, - {'\'', 'O', '\323'}, {'\'', 'o', '\363'}, - {'^', 'O', '\324'}, {'^', 'o', '\364'}, - {'~', 'O', '\325'}, {'~', 'o', '\365'}, - {'"', 'O', '\326'}, {'"', 'o', '\366'}, - {'/', 'O', '\330'}, {'/', 'o', '\370'}, - {'`', 'U', '\331'}, {'`', 'u', '\371'}, - {'\'', 'U', '\332'}, {'\'', 'u', '\372'}, - {'^', 'U', '\333'}, {'^', 'u', '\373'}, - {'"', 'U', '\334'}, {'"', 'u', '\374'}, - {'\'', 'Y', '\335'}, {'\'', 'y', '\375'}, - {'T', 'H', '\336'}, {'t', 'h', '\376'}, - {'s', 's', '\337'}, {'"', 'y', '\377'}, - {'s', 'z', '\337'}, {'i', 'j', '\377'}, -}; - -unsigned int accent_table_size = 68; diff -Nru a/drivers/acorn/char/defkeymap-acorn.map b/drivers/acorn/char/defkeymap-acorn.map --- a/drivers/acorn/char/defkeymap-acorn.map Mon Jun 9 23:16:08 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,356 +0,0 @@ -# Default kernel keymap for Acorn machines. This uses 7 modifier combinations. -keymaps 0-2,4-5,8,12 -# Change the above line into -# keymaps 0-2,4-6,8,12 -# in case you want the entries -# altgr control keycode 52 = Boot -# altgr control keycode 102 = Boot -# below. -# -# In fact AltGr is used very little, and one more keymap can -# be saved by mapping AltGr to Alt (and adapting a few entries): -# keycode 96 = Alt -# -keycode 0 = Escape - shift keycode 0 = Escape - alt keycode 0 = Meta_Escape -keycode 1 = F1 F11 Console_13 - control keycode 1 = F1 - alt keycode 1 = Console_1 - control alt keycode 1 = Console_1 -keycode 2 = F2 F12 Console_14 - control keycode 2 = F2 - alt keycode 2 = Console_2 - control alt keycode 2 = Console_2 -keycode 3 = F3 F13 Console_15 - control keycode 3 = F3 - alt keycode 3 = Console_3 - control alt keycode 3 = Console_3 -keycode 4 = F4 F14 Console_16 - control keycode 4 = F4 - alt keycode 4 = Console_4 - control alt keycode 4 = Console_4 -keycode 5 = F5 F15 Console_17 - control keycode 5 = F5 - alt keycode 5 = Console_5 - control alt keycode 5 = Console_5 -keycode 6 = F6 F16 Console_18 - control keycode 6 = F6 - alt keycode 6 = Console_6 - control alt keycode 6 = Console_6 -keycode 7 = F7 F17 Console_19 - control keycode 7 = F7 - alt keycode 7 = Console_7 - control alt keycode 7 = Console_7 -keycode 8 = F8 F18 Console_20 - control keycode 8 = F8 - alt keycode 8 = Console_8 - control alt keycode 8 = Console_8 -keycode 9 = F9 F19 Console_21 - control keycode 9 = F9 - alt keycode 9 = Console_9 - control alt keycode 9 = Console_9 -keycode 10 = F10 F20 Console_22 - control keycode 10 = F10 - alt keycode 10 = Console_10 - control alt keycode 10 = Console_10 -keycode 11 = F11 F11 Console_23 - control keycode 11 = F11 - alt keycode 11 = Console_11 - control alt keycode 11 = Console_11 -keycode 12 = F12 F12 Console_24 - control keycode 12 = F12 - alt keycode 12 = Console_12 - control alt keycode 12 = Console_12 -keycode 13 = -keycode 14 = Scroll_Lock - shift keycode 14 = Show_Memory - altgr keycode 14 = Show_Registers - control keycode 14 = Show_State - alt keycode 14 = Scroll_Lock -keycode 15 = Break -keycode 16 = grave asciitilde - alt keycode 16 = Meta_grave -keycode 17 = one exclam - alt keycode 17 = Meta_one -keycode 18 = two at at - control keycode 18 = nul - alt keycode 18 = Meta_two -keycode 19 = three numbersign - control keycode 19 = Escape - alt keycode 19 = Meta_three -keycode 20 = four dollar dollar - control keycode 20 = Control_backslash - alt keycode 20 = Meta_four -keycode 21 = five percent - control keycode 21 = Control_bracketright - alt keycode 21 = Meta_five -keycode 22 = six asciicircum - control keycode 22 = Control_asciicircum - alt keycode 22 = Meta_six -keycode 23 = seven ampersand braceleft - control keycode 23 = Control_underscore - alt keycode 23 = Meta_seven -keycode 24 = eight asterisk bracketleft - control keycode 24 = Delete - alt keycode 24 = Meta_eight -keycode 25 = nine parenleft bracketright - alt keycode 25 = Meta_nine -keycode 26 = zero parenright braceright - alt keycode 26 = Meta_zero -keycode 27 = minus underscore backslash - control keycode 27 = Control_underscore - shift control keycode 27 = Control_underscore - alt keycode 27 = Meta_minus -keycode 28 = equal plus - alt keycode 28 = Meta_equal -keycode 29 = sterling currency - alt keycode 29 = 0x08a3 -keycode 30 = Delete Delete - control keycode 30 = BackSpace - alt keycode 30 = Meta_Delete -keycode 31 = Insert -keycode 32 = Find -keycode 33 = Prior - shift keycode 33 = Scroll_Backward -keycode 34 = Num_Lock -keycode 35 = KP_Divide -keycode 36 = KP_Multiply -keycode 37 = 0x0314 -keycode 38 = Tab Tab - alt keycode 38 = Meta_Tab -keycode 39 = q -keycode 40 = w -keycode 41 = e - altgr keycode 41 = Hex_E -keycode 42 = r -keycode 43 = t -keycode 44 = y -keycode 45 = u -keycode 46 = i -keycode 47 = o -keycode 48 = p -keycode 49 = bracketleft braceleft - control keycode 49 = Escape - alt keycode 49 = Meta_bracketleft -keycode 50 = bracketright braceright asciitilde - control keycode 50 = Control_bracketright - alt keycode 50 = Meta_bracketright -keycode 51 = backslash bar - control keycode 51 = Control_backslash - alt keycode 51 = Meta_backslash -keycode 52 = Remove -# altgr control keycode 52 = Boot - control alt keycode 52 = Boot -keycode 53 = Select -keycode 54 = Next - shift keycode 54 = Scroll_Forward -keycode 55 = KP_7 - altgr keycode 55 = Hex_7 - alt keycode 55 = Ascii_7 -keycode 56 = KP_8 - altgr keycode 56 = Hex_8 - alt keycode 56 = Ascii_8 -keycode 57 = KP_9 - altgr keycode 57 = Hex_9 - alt keycode 57 = Ascii_9 -keycode 58 = KP_Subtract -keycode 59 = Control -keycode 60 = a - altgr keycode 60 = Hex_A -keycode 61 = s -keycode 62 = d - altgr keycode 62 = Hex_D -keycode 63 = f - altgr keycode 63 = Hex_F -keycode 64 = g -keycode 65 = h -keycode 66 = j -keycode 67 = k -keycode 68 = l -keycode 69 = semicolon colon - alt keycode 69 = Meta_semicolon -keycode 70 = apostrophe quotedbl - control keycode 70 = Control_g - alt keycode 70 = Meta_apostrophe -keycode 71 = Return - alt keycode 71 = Meta_Control_m -keycode 72 = KP_4 - altgr keycode 72 = Hex_4 - alt keycode 72 = Ascii_4 -keycode 73 = KP_5 - altgr keycode 73 = Hex_5 - alt keycode 73 = Ascii_5 -keycode 74 = KP_6 - altgr keycode 74 = Hex_6 - alt keycode 74 = Ascii_6 -keycode 75 = KP_Add -keycode 76 = Shift -keycode 77 = -keycode 78 = z -keycode 79 = x -keycode 80 = c - altgr keycode 80 = Hex_C -keycode 81 = v -keycode 82 = b - altgr keycode 82 = Hex_B -keycode 83 = n -keycode 84 = m -keycode 85 = comma less - alt keycode 85 = Meta_comma -keycode 86 = period greater - control keycode 86 = Compose - alt keycode 86 = Meta_period -keycode 87 = slash question - control keycode 87 = Delete - alt keycode 87 = Meta_slash -keycode 88 = Shift -keycode 89 = Up -keycode 90 = KP_1 - altgr keycode 90 = Hex_1 - alt keycode 90 = Ascii_1 -keycode 91 = KP_2 - altgr keycode 91 = Hex_2 - alt keycode 91 = Ascii_2 -keycode 92 = KP_3 - altgr keycode 92 = Hex_3 - alt keycode 92 = Ascii_3 -keycode 93 = Caps_Lock -keycode 94 = Alt -keycode 95 = space space - control keycode 95 = nul - alt keycode 95 = Meta_space -keycode 96 = AltGr -keycode 97 = Control -keycode 98 = Left - alt keycode 98 = Decr_Console -keycode 99 = Down -keycode 100 = Right - alt keycode 100 = Incr_Console -keycode 101 = KP_0 - altgr keycode 101 = Hex_0 - alt keycode 101 = Ascii_0 -keycode 102 = KP_Period -# altgr control keycode 102 = Boot - control alt keycode 102 = Boot -keycode 103 = KP_Enter -keycode 104 = -keycode 105 = -keycode 106 = -keycode 107 = -keycode 108 = -keycode 109 = -keycode 110 = -keycode 111 = -keycode 112 = -keycode 113 = -keycode 114 = -keycode 115 = -keycode 116 = -keycode 117 = -keycode 118 = -keycode 119 = -keycode 120 = -keycode 121 = -keycode 122 = -keycode 123 = -keycode 124 = -keycode 125 = -keycode 126 = -keycode 127 = -string F1 = "\033[[A" -string F2 = "\033[[B" -string F3 = "\033[[C" -string F4 = "\033[[D" -string F5 = "\033[[E" -string F6 = "\033[17~" -string F7 = "\033[18~" -string F8 = "\033[19~" -string F9 = "\033[20~" -string F10 = "\033[21~" -string F11 = "\033[23~" -string F12 = "\033[24~" -string F13 = "\033[25~" -string F14 = "\033[26~" -string F15 = "\033[28~" -string F16 = "\033[29~" -string F17 = "\033[31~" -string F18 = "\033[32~" -string F19 = "\033[33~" -string F20 = "\033[34~" -string Find = "\033[1~" -string Insert = "\033[2~" -string Remove = "\033[3~" -string Select = "\033[4~" -string Prior = "\033[5~" -string Next = "\033[6~" -string Macro = "\033[M" -string Pause = "\033[P" -compose '`' 'A' to 'À' -compose '`' 'a' to 'à' -compose '\'' 'A' to 'Á' -compose '\'' 'a' to 'á' -compose '^' 'A' to 'Â' -compose '^' 'a' to 'â' -compose '~' 'A' to 'Ã' -compose '~' 'a' to 'ã' -compose '"' 'A' to 'Ä' -compose '"' 'a' to 'ä' -compose 'O' 'A' to 'Å' -compose 'o' 'a' to 'å' -compose '0' 'A' to 'Å' -compose '0' 'a' to 'å' -compose 'A' 'A' to 'Å' -compose 'a' 'a' to 'å' -compose 'A' 'E' to 'Æ' -compose 'a' 'e' to 'æ' -compose ',' 'C' to 'Ç' -compose ',' 'c' to 'ç' -compose '`' 'E' to 'È' -compose '`' 'e' to 'è' -compose '\'' 'E' to 'É' -compose '\'' 'e' to 'é' -compose '^' 'E' to 'Ê' -compose '^' 'e' to 'ê' -compose '"' 'E' to 'Ë' -compose '"' 'e' to 'ë' -compose '`' 'I' to 'Ì' -compose '`' 'i' to 'ì' -compose '\'' 'I' to 'Í' -compose '\'' 'i' to 'í' -compose '^' 'I' to 'Î' -compose '^' 'i' to 'î' -compose '"' 'I' to 'Ï' -compose '"' 'i' to 'ï' -compose '-' 'D' to 'Ð' -compose '-' 'd' to 'ð' -compose '~' 'N' to 'Ñ' -compose '~' 'n' to 'ñ' -compose '`' 'O' to 'Ò' -compose '`' 'o' to 'ò' -compose '\'' 'O' to 'Ó' -compose '\'' 'o' to 'ó' -compose '^' 'O' to 'Ô' -compose '^' 'o' to 'ô' -compose '~' 'O' to 'Õ' -compose '~' 'o' to 'õ' -compose '"' 'O' to 'Ö' -compose '"' 'o' to 'ö' -compose '/' 'O' to 'Ø' -compose '/' 'o' to 'ø' -compose '`' 'U' to 'Ù' -compose '`' 'u' to 'ù' -compose '\'' 'U' to 'Ú' -compose '\'' 'u' to 'ú' -compose '^' 'U' to 'Û' -compose '^' 'u' to 'û' -compose '"' 'U' to 'Ü' -compose '"' 'u' to 'ü' -compose '\'' 'Y' to 'Ý' -compose '\'' 'y' to 'ý' -compose 'T' 'H' to 'Þ' -compose 't' 'h' to 'þ' -compose 's' 's' to 'ß' -compose '"' 'y' to 'ÿ' -compose 's' 'z' to 'ß' -compose 'i' 'j' to 'ÿ' diff -Nru a/drivers/acorn/char/keyb_arc.c b/drivers/acorn/char/keyb_arc.c --- a/drivers/acorn/char/keyb_arc.c Mon Jun 9 23:16:10 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,450 +0,0 @@ -/* - * linux/drivers/acorn/char/keyb_arc.c - * - * Copyright (C) 2000 Russell King - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Acorn keyboard driver for ARM Linux. - * - * The Acorn keyboard appears to have a ***very*** buggy reset protocol - - * every reset behaves differently. We try to get round this by attempting - * a few things... - */ -#include <linux/config.h> -#include <linux/sched.h> -#include <linux/interrupt.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/ptrace.h> -#include <linux/signal.h> -#include <linux/timer.h> -#include <linux/random.h> -#include <linux/ctype.h> -#include <linux/init.h> -#include <linux/kbd_ll.h> -#include <linux/kbd_kern.h> -#include <linux/delay.h> - -#include <asm/bitops.h> -#include <asm/keyboard.h> -#include <asm/irq.h> -#include <asm/hardware.h> -#include <asm/hardware/ioc.h> - -#include "../../char/busmouse.h" - -extern struct tasklet_struct keyboard_tasklet; -extern void kbd_reset_kdown(void); - -#define VERSION 108 - -#define KBD_REPORT_ERR -#define KBD_REPORT_UNKN - -#include <asm/io.h> -#include <asm/system.h> - -static char kbd_txval[4]; -static unsigned char kbd_txhead, kbd_txtail; -#define KBD_INCTXPTR(ptr) ((ptr) = ((ptr) + 1) & 3) -static int kbd_id = -1; -static DECLARE_WAIT_QUEUE_HEAD(kbd_waitq); -#ifdef CONFIG_KBDMOUSE -static int mousedev; -#endif - -/* - * Protocol codes to send the keyboard. - */ -#define HRST 0xff /* reset keyboard */ -#define RAK1 0xfe /* reset response */ -#define RAK2 0xfd /* reset response */ -#define BACK 0x3f /* Ack for first keyboard pair */ -#define SMAK 0x33 /* Last data byte ack (key scanning + mouse movement scanning) */ -#define MACK 0x32 /* Last data byte ack (mouse movement scanning) */ -#define SACK 0x31 /* Last data byte ack (key scanning) */ -#define NACK 0x30 /* Last data byte ack (no scanning, mouse data) */ -#define RQMP 0x22 /* Request mouse data */ -#define PRST 0x21 /* nothing */ -#define RQID 0x20 /* Request ID */ - -#define UP_FLAG 1 - -#ifdef CONFIG_MAGIC_SYSRQ -unsigned char a5kkbd_sysrq_xlate[] = -{ - 27, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - '`', '1', '2', '3', '4', '5', '6', '7', - '8', '9', '0', '-', '=', '£', 127, 0, - 0, 0, 0, '/', '*', '#', 9, 'q', - 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', - 'p', '[', ']', '\\', 22, 23, 25, '7', - '8', '9', '-', 0, 'a', 's', 'd', 'f', - 'g', 'h', 'j', 'k', 'l', ';', '\'', 13, - '4', '5', '6', '+', 0, 0, 'z', 'x', - 'c', 'v', 'b', 'n', 'm', ',', '.', '/', - 0, 0, '1', '2', '3', 0, 0, ' ', - 0, 0, 0, 0, 0, '0', '.', 10, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, -}; -#endif - -/* - * This array converts the scancode that we get from the keyboard to the - * real rows/columns on the A5000 keyboard. This might be keyboard specific... - * - * It is these values that we use to maintain the key down array. That way, we - * should pick up on the ghost key presses (which is what happens when you press - * three keys, and the keyboard thinks you have pressed four!) - * - * Row 8 (0x80+c) is actually a column with one key per row. It is isolated from - * the other keys, and can't cause these problems (its used for shift, ctrl, alt etc). - * - * Illegal scancodes are denoted by an 0xff (in other words, we don't know about - * them, and can't process them for ghosts). This does however, cause problems with - * autorepeat processing... - */ -static unsigned char scancode_2_colrow[256] = { - 0x01, 0x42, 0x32, 0x33, 0x43, 0x56, 0x5a, 0x6c, 0x7c, 0x5c, 0x5b, 0x6b, 0x7b, 0x84, 0x70, 0x60, - 0x11, 0x51, 0x62, 0x63, 0x44, 0x54, 0x55, 0x45, 0x46, 0x4a, 0x3c, 0x4b, 0x59, 0x49, 0x69, 0x79, - 0x83, 0x40, 0x30, 0x3b, 0x39, 0x38, 0x31, 0x61, 0x72, 0x73, 0x64, 0x74, 0x75, 0x65, 0x66, 0x6a, - 0x1c, 0x2c, 0x7a, 0x36, 0x48, 0x68, 0x78, 0x20, 0x2b, 0x29, 0x28, 0x81, 0x71, 0x22, 0x23, 0x34, - 0x24, 0x25, 0x35, 0x26, 0x3a, 0x0c, 0x2a, 0x76, 0x10, 0x1b, 0x19, 0x18, 0x82, 0xff, 0x21, 0x12, - 0x13, 0x14, 0x04, 0x05, 0x15, 0x16, 0x1a, 0x0a, 0x85, 0x77, 0x00, 0x0b, 0x09, 0x02, 0x80, 0x03, - 0x87, 0x86, 0x06, 0x17, 0x27, 0x07, 0x37, 0x08, 0xff, -}; - -#define BITS_PER_SHORT (8*sizeof(unsigned short)) -static unsigned short ghost_down[128/BITS_PER_SHORT]; - -static void a5kkbd_key(unsigned int keycode, unsigned int up_flag) -{ - unsigned int real_keycode; - - if (keycode > 0x72) { -#ifdef KBD_REPORT_UNKN - printk ("kbd: unknown scancode 0x%04x\n", keycode); -#endif - return; - } - if (keycode >= 0x70) { -#ifdef CONFIG_KBDMOUSE - if (mousedev >= 0) - switch (keycode) { - case 0x70: /* Left mouse button */ - busmouse_add_buttons(mousedev, 4, up_flag ? 4 : 0); - break; - - case 0x71: /* Middle mouse button */ - busmouse_add_buttons(mousedev, 2, up_flag ? 2 : 0); - break; - - case 0x72:/* Right mouse button */ - busmouse_add_buttons(mousedev, 1, up_flag ? 1 : 0); - break; - } -#endif - return; - } - - /* - * We have to work out if we accept this key press as a real key, or - * if it is a ghost. IE. If you press three keys, the keyboard will think - * that you've pressed a fourth: (@ = key down, # = ghost) - * - * 0 1 2 3 4 5 6 7 - * | | | | | | | | - * 0-+-+-+-+-+-+-+-+- - * | | | | | | | | - * 1-+-@-+-+-+-@-+-+- - * | | | | | | | | - * 2-+-+-+-+-+-+-+-+- - * | | | | | | | | - * 3-+-@-+-+-+-#-+-+- - * | | | | | | | | - * - * This is what happens when you have a matrix keyboard... - */ - - real_keycode = scancode_2_colrow[keycode]; - - if ((real_keycode & 0x80) == 0) { - int rr, kc = (real_keycode >> 4) & 7; - int cc; - unsigned short res, kdownkc; - - kdownkc = ghost_down[kc] | (1 << (real_keycode & 15)); - - for (rr = 0; rr < 128/BITS_PER_SHORT; rr++) - if (rr != kc && (res = ghost_down[rr] & kdownkc)) { - /* - * we have found a second row with at least one key pressed in the - * same column. - */ - for (cc = 0; res; res >>= 1) - cc += (res & 1); - if (cc > 1) - return; /* ignore it */ - } - if (up_flag) - clear_bit (real_keycode, ghost_down); - else - set_bit (real_keycode, ghost_down); - } - - handle_scancode(keycode, !up_flag); -} - -static inline void a5kkbd_sendbyte(unsigned char val) -{ - kbd_txval[kbd_txhead] = val; - KBD_INCTXPTR(kbd_txhead); - enable_irq(IRQ_KEYBOARDTX); -} - -static inline void a5kkbd_reset(void) -{ - int i; - - for (i = 0; i < NR_SCANCODES/BITS_PER_SHORT; i++) - ghost_down[i] = 0; - - kbd_reset_kdown(); -} - -void a5kkbd_leds(unsigned char leds) -{ - leds = ((leds & (1<<VC_SCROLLOCK))?4:0) | ((leds & (1<<VC_NUMLOCK))?2:0) | - ((leds & (1<<VC_CAPSLOCK))?1:0); - a5kkbd_sendbyte(leds); -} - -/* Keyboard states: - * 0 initial reset condition, receive HRST, send RRAK1 - * 1 Sent RAK1, wait for RAK1, send RRAK2 - * 2 Sent RAK2, wait for RAK2, send SMAK or RQID - * 3 Sent RQID, expect KBID, send SMAK - * 4 Sent SMAK, wait for anything - * 5 Wait for second keyboard nibble for key pressed - * 6 Wait for second keyboard nibble for key released - * 7 Wait for second part of mouse data - * - * This function returns 1 when we successfully enter the IDLE state - * (and hence need to do some keyboard processing). - */ -#define KBD_INITRST 0 -#define KBD_RAK1 1 -#define KBD_RAK2 2 -#define KBD_ID 3 -#define KBD_IDLE 4 -#define KBD_KEYDOWN 5 -#define KBD_KEYUP 6 -#define KBD_MOUSE 7 - -static int handle_rawcode(unsigned int keyval) -{ - static signed char kbd_mousedx = 0; - signed char kbd_mousedy; - static unsigned char kbd_state = KBD_INITRST; - static unsigned char kbd_keyhigh = 0; - - if (keyval == HRST && kbd_state != KBD_INITRST && kbd_state != KBD_ID) { - a5kkbd_sendbyte (HRST); - a5kkbd_reset (); - kbd_state = KBD_INITRST; - } else switch(kbd_state) { - case KBD_INITRST: /* hard reset - sent HRST */ - if (keyval == HRST) { - a5kkbd_sendbyte (RAK1); - kbd_state = KBD_RAK1; - } else if (keyval == RAK1) { - /* Some A5000 keyboards are very fussy and don't follow Acorn's - * specs - this appears to fix them, but them it might stop - * them from being initialised. - * fix by Philip Blundell - */ - printk(KERN_DEBUG "keyboard sent early RAK1 -- ignored\n"); - } else - goto kbd_wontreset; - break; - - case KBD_RAK1: /* sent RAK1 - expect RAK1 and send RAK2 */ - if (keyval == RAK1) { - a5kkbd_sendbyte (RAK2); - kbd_state = KBD_RAK2; - } else - goto kbd_wontreset; - break; - - case KBD_RAK2: /* Sent RAK2 - expect RAK2 and send either RQID or SMAK */ - if (keyval == RAK2) { - if (kbd_id == -1) { - a5kkbd_sendbyte (NACK); - a5kkbd_sendbyte (RQID); - kbd_state = KBD_ID; - } else { - a5kkbd_sendbyte (SMAK); - kbd_state = KBD_IDLE; - } - } else - goto kbd_wontreset; - break; - - case KBD_ID: /* Sent RQID - expect KBID */ - if (keyval == HRST) { - kbd_id = -2; - a5kkbd_reset (); - a5kkbd_sendbyte (HRST); - kbd_state = KBD_INITRST; - wake_up (&kbd_waitq); - } else if ((keyval & 0xc0) == 0x80) { - kbd_id = keyval & 0x3f; - a5kkbd_sendbyte (SMAK); - kbd_state = KBD_IDLE; - wake_up (&kbd_waitq); - } - break; - - case KBD_IDLE: /* Send SMAK, ready for any reply */ - switch (keyval & 0xf0) { - default: /* 0x00 - 0x7f */ - kbd_mousedx = keyval & 0x40 ? keyval|0x80 : keyval; - kbd_state = KBD_MOUSE; - a5kkbd_sendbyte (BACK); - break; - - case 0x80: - case 0x90: - case 0xa0: - case 0xb0: - if (kbd_id == -1) - kbd_id = keyval & 0x3f; - break; - - case 0xc0: - kbd_keyhigh = keyval; - kbd_state = KBD_KEYDOWN; - a5kkbd_sendbyte (BACK); - break; - - case 0xd0: - kbd_keyhigh = keyval; - kbd_state = KBD_KEYUP; - a5kkbd_sendbyte (BACK); - break; - - case 0xe0: - case 0xf0: - goto kbd_error; - } - break; - - case KBD_KEYDOWN: - if ((keyval & 0xf0) != 0xc0) - goto kbd_error; - else { - kbd_state = KBD_IDLE; - a5kkbd_sendbyte (SMAK); - if (((kbd_keyhigh ^ keyval) & 0xf0) == 0) - a5kkbd_key ((keyval & 0x0f) | ((kbd_keyhigh << 4) & 0xf0), 0); - } - break; - - case KBD_KEYUP: - if ((keyval & 0xf0) != 0xd0) - goto kbd_error; - else { - kbd_state = KBD_IDLE; - a5kkbd_sendbyte (SMAK); - if (((kbd_keyhigh ^ keyval) & 0xf0) == 0) - a5kkbd_key ((keyval & 0x0f) | ((kbd_keyhigh << 4) & 0xf0), UP_FLAG); - } - break; - - case KBD_MOUSE: - if (keyval & 0x80) - goto kbd_error; - else { - kbd_state = KBD_IDLE; - a5kkbd_sendbyte (SMAK); - kbd_mousedy = (char)(keyval & 0x40 ? keyval | 0x80 : keyval); -#ifdef CONFIG_KBDMOUSE - if (mousedev >= 0) - busmouse_add_movement(mousedev, (int)kbd_mousedx, (int)kbd_mousedy); -#endif - } - } - return kbd_state == KBD_IDLE ? 1 : 0; - -kbd_wontreset: -#ifdef KBD_REPORT_ERR - printk ("kbd: keyboard won't reset (kbdstate %d, keyval %02X)\n", - kbd_state, keyval); -#endif - mdelay(1); - ioc_readb(IOC_KARTRX); - a5kkbd_sendbyte (HRST); - kbd_state = KBD_INITRST; - return 0; - -kbd_error: -#ifdef KBD_REPORT_ERR - printk ("kbd: keyboard out of sync - resetting\n"); -#endif - a5kkbd_sendbyte (HRST); - kbd_state = KBD_INITRST; - return 0; -} - -static void a5kkbd_rx(int irq, void *dev_id, struct pt_regs *regs) -{ - if (handle_rawcode(ioc_readb(IOC_KARTRX))) - tasklet_schedule(&keyboard_tasklet); -} - -static void a5kkbd_tx(int irq, void *dev_id, struct pt_regs *regs) -{ - ioc_writeb (kbd_txval[kbd_txtail], IOC_KARTTX); - KBD_INCTXPTR(kbd_txtail); - if (kbd_txtail == kbd_txhead) - disable_irq(irq); -} - -#ifdef CONFIG_KBDMOUSE -static struct busmouse a5kkbd_mouse = { - 6, "kbdmouse", NULL, NULL, NULL, 7 -}; -#endif - -void __init a5kkbd_init_hw (void) -{ - if (request_irq (IRQ_KEYBOARDTX, a5kkbd_tx, 0, "keyboard", NULL) != 0) - panic("Could not allocate keyboard transmit IRQ!"); - (void)ioc_readb(IOC_KARTRX); - if (request_irq (IRQ_KEYBOARDRX, a5kkbd_rx, 0, "keyboard", NULL) != 0) - panic("Could not allocate keyboard receive IRQ!"); - - a5kkbd_sendbyte (HRST); /* send HRST (expect HRST) */ - - /* wait 1s for keyboard to initialise */ - interruptible_sleep_on_timeout(&kbd_waitq, HZ); - -#ifdef CONFIG_KBDMOUSE - mousedev = register_busmouse(&a5kkbd_mouse); - if (mousedev < 0) - printk(KERN_ERR "Unable to register mouse driver\n"); -#endif - - printk (KERN_INFO "Keyboard driver v%d.%02d. (", VERSION/100, VERSION%100); - if (kbd_id != -1) - printk ("id=%d ", kbd_id); - printk ("English)\n"); -} diff -Nru a/drivers/acorn/char/mouse_ps2.c b/drivers/acorn/char/mouse_ps2.c --- a/drivers/acorn/char/mouse_ps2.c Mon Jun 9 23:16:16 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,294 +0,0 @@ -/* - * Driver for PS/2 mouse on IOMD interface - */ -#include <linux/sched.h> -#include <linux/interrupt.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/ptrace.h> -#include <linux/signal.h> -#include <linux/timer.h> -#include <linux/random.h> -#include <linux/ctype.h> -#include <linux/kbd_ll.h> -#include <linux/delay.h> -#include <linux/init.h> -#include <linux/poll.h> -#include <linux/miscdevice.h> - -#include <asm/bitops.h> -#include <asm/irq.h> -#include <asm/hardware.h> -#include <asm/io.h> -#include <asm/hardware/iomd.h> -#include <asm/system.h> -#include <asm/uaccess.h> - -/* - * PS/2 Auxiliary Device - */ - -static struct aux_queue *queue; /* Mouse data buffer. */ -static int aux_count = 0; -/* used when we send commands to the mouse that expect an ACK. */ -static unsigned char mouse_reply_expected = 0; - -#define MAX_RETRIES 60 /* some aux operations take long time*/ - -/* - * Mouse Commands - */ - -#define AUX_SET_RES 0xE8 /* Set resolution */ -#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ -#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ -#define AUX_GET_SCALE 0xE9 /* Get scaling factor */ -#define AUX_SET_STREAM 0xEA /* Set stream mode */ -#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ -#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ -#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ -#define AUX_RESET 0xFF /* Reset aux device */ -#define AUX_ACK 0xFA /* Command byte ACK. */ - -#define AUX_BUF_SIZE 2048 /* This might be better divisible by - three to make overruns stay in sync - but then the read function would - need a lock etc - ick */ - -struct aux_queue { - unsigned long head; - unsigned long tail; - wait_queue_head_t proc_list; - struct fasync_struct *fasync; - unsigned char buf[AUX_BUF_SIZE]; -}; - -/* - * Send a byte to the mouse. - */ -static void aux_write_dev(int val) -{ - while (!(iomd_readb(IOMD_MSECTL) & 0x80)); - iomd_writeb(val, IOMD_MSEDAT); -} - -/* - * Send a byte to the mouse & handle returned ack - */ -static void aux_write_ack(int val) -{ - while (!(iomd_readb(IOMD_MSECTL) & 0x80)); - iomd_writeb(val, IOMD_MSEDAT); - - /* we expect an ACK in response. */ - mouse_reply_expected++; -} - -static unsigned char get_from_queue(void) -{ - unsigned char result; - - result = queue->buf[queue->tail]; - queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1); - return result; -} - -static void psaux_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - int val = iomd_readb(IOMD_MSEDAT); - - if (mouse_reply_expected) { - if (val == AUX_ACK) { - mouse_reply_expected--; - return; - } - mouse_reply_expected = 0; - } - - add_mouse_randomness(val); - if (aux_count) { - int head = queue->head; - - queue->buf[head] = val; - head = (head + 1) & (AUX_BUF_SIZE-1); - if (head != queue->tail) { - queue->head = head; - kill_fasync(&queue->fasync, SIGIO, POLL_IN); - wake_up_interruptible(&queue->proc_list); - } - } -} - -static inline int queue_empty(void) -{ - return queue->head == queue->tail; -} - -static int fasync_aux(int fd, struct file *filp, int on) -{ - int retval; - - retval = fasync_helper(fd, filp, on, &queue->fasync); - if (retval < 0) - return retval; - return 0; -} - - -/* - * Random magic cookie for the aux device - */ -#define AUX_DEV ((void *)queue) - -static int release_aux(struct inode * inode, struct file * file) -{ - fasync_aux(-1, file, 0); - if (--aux_count) - return 0; - free_irq(IRQ_MOUSERX, AUX_DEV); - return 0; -} - -/* - * Install interrupt handler. - * Enable auxiliary device. - */ - -static int open_aux(struct inode * inode, struct file * file) -{ - if (aux_count++) - return 0; - - queue->head = queue->tail = 0; /* Flush input queue */ - if (request_irq(IRQ_MOUSERX, psaux_interrupt, SA_SHIRQ, "ps/2 mouse", - AUX_DEV)) { - aux_count--; - return -EBUSY; - } - - aux_write_ack(AUX_ENABLE_DEV); /* Enable aux device */ - - return 0; -} - -/* - * Put bytes from input queue to buffer. - */ - -static ssize_t read_aux(struct file * file, char * buffer, - size_t count, loff_t *ppos) -{ - DECLARE_WAITQUEUE(wait, current); - ssize_t i = count; - unsigned char c; - - if (queue_empty()) { - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - add_wait_queue(&queue->proc_list, &wait); -repeat: - current->state = TASK_INTERRUPTIBLE; - if (queue_empty() && !signal_pending(current)) { - schedule(); - goto repeat; - } - current->state = TASK_RUNNING; - remove_wait_queue(&queue->proc_list, &wait); - } - while (i > 0 && !queue_empty()) { - c = get_from_queue(); - put_user(c, buffer++); - i--; - } - if (count-i) { - file->f_dentry->d_inode->i_atime = CURRENT_TIME; - return count-i; - } - if (signal_pending(current)) - return -ERESTARTSYS; - return 0; -} - -/* - * Write to the aux device. - */ - -static ssize_t write_aux(struct file * file, const char * buffer, - size_t count, loff_t *ppos) -{ - ssize_t retval = 0; - - if (count) { - ssize_t written = 0; - - if (count > 32) - count = 32; /* Limit to 32 bytes. */ - do { - char c; - get_user(c, buffer++); - aux_write_dev(c); - written++; - } while (--count); - retval = -EIO; - if (written) { - retval = written; - file->f_dentry->d_inode->i_mtime = CURRENT_TIME; - } - } - - return retval; -} - -static unsigned int aux_poll(struct file *file, poll_table * wait) -{ - poll_wait(file, &queue->proc_list, wait); - if (!queue_empty()) - return POLLIN | POLLRDNORM; - return 0; -} - -struct file_operations psaux_fops = { - .read = read_aux, - .write = write_aux, - .poll = aux_poll, - .open = open_aux, - .release = release_aux, - .fasync = fasync_aux, -}; - -/* - * Initialize driver. - */ -static struct miscdevice psaux_mouse = { - PSMOUSE_MINOR, "psaux", &psaux_fops -}; - -int __init psaux_init(void) -{ - /* Reset the mouse state machine. */ - iomd_writeb(0, IOMD_MSECTL); - iomd_writeb(8, IOMD_MSECTL); - - queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL); - if (queue == NULL) - return -ENOMEM; - - if (misc_register(&psaux_mouse)) { - kfree(queue); - return -ENODEV; - } - - memset(queue, 0, sizeof(*queue)); - queue->head = queue->tail = 0; - init_waitqueue_head(&queue->proc_list); - - aux_write_ack(AUX_SET_SAMPLE); - aux_write_ack(100); /* 100 samples/sec */ - aux_write_ack(AUX_SET_RES); - aux_write_ack(3); /* 8 counts per mm */ - aux_write_ack(AUX_SET_SCALE21); /* 2:1 scaling */ - - return 0; -} diff -Nru a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c --- a/drivers/acpi/pci_irq.c Mon Jun 9 23:16:11 2003 +++ b/drivers/acpi/pci_irq.c Mon Jun 9 23:16:11 2003 @@ -402,7 +402,7 @@ iosapic_parse_prt(); #endif - pci_for_each_dev(dev) + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) acpi_pci_irq_enable(dev); return_VALUE(0); diff -Nru a/drivers/acpi/processor.c b/drivers/acpi/processor.c --- a/drivers/acpi/processor.c Mon Jun 9 23:16:15 2003 +++ b/drivers/acpi/processor.c Mon Jun 9 23:16:15 2003 @@ -85,7 +85,7 @@ static int acpi_processor_throttling_open_fs(struct inode *inode, struct file *file); static int acpi_processor_power_open_fs(struct inode *inode, struct file *file); static int acpi_processor_limit_open_fs(struct inode *inode, struct file *file); - +static int acpi_processor_get_limit_info(struct acpi_processor *pr); static struct acpi_driver acpi_processor_driver = { .name = ACPI_PROCESSOR_DRIVER_NAME, @@ -769,7 +769,9 @@ } pr->performance_platform_limit = (int) ppc; - + + acpi_processor_get_limit_info(pr); + return_VALUE(0); } EXPORT_SYMBOL(acpi_processor_get_platform_limit); @@ -790,6 +792,7 @@ return_VALUE(-EBUSY); (*pr)->performance = performance; + performance->pr = *pr; return 0; } EXPORT_SYMBOL(acpi_processor_register_performance); diff -Nru a/drivers/atm/Makefile b/drivers/atm/Makefile --- a/drivers/atm/Makefile Mon Jun 9 23:16:06 2003 +++ b/drivers/atm/Makefile Mon Jun 9 23:16:06 2003 @@ -8,7 +8,9 @@ host-progs := fore200e_mkfirm # Files generated that shall be removed upon make clean -clean-files := {atmsar11,pca200e,pca200e_ecd,sba200e_ecd}.{bin,bin1,bin2} +clean-files := atmsar11.bin atmsar11.bin1 atmsar11.bin2 pca200e.bin \ + pca200e.bin1 pca200e.bin2 pca200e_ecd.bin pca200e_ecd.bin1 \ + pca200e_ecd.bin2 sba200e_ecd.bin sba200e_ecd.bin1 sba200e_ecd.bin2 # Firmware generated that shall be removed upon make clean clean-files += fore200e_pca_fw.c fore200e_sba_fw.c diff -Nru a/drivers/atm/he.c b/drivers/atm/he.c --- a/drivers/atm/he.c Mon Jun 9 23:16:08 2003 +++ b/drivers/atm/he.c Mon Jun 9 23:16:08 2003 @@ -77,14 +77,6 @@ #include <linux/atmdev.h> #include <linux/atm.h> #include <linux/sonet.h> -#ifndef ATM_OC12_PCR -#define ATM_OC12_PCR (622080000/1080*1040/8/53) -#endif - -#ifdef BUS_INT_WAR -void sn_add_polled_interrupt(int irq, int interval); -void sn_delete_polled_interrupt(int irq); -#endif #define USE_TASKLET #define USE_HE_FIND_VCC @@ -132,9 +124,9 @@ #undef DEBUG #ifdef DEBUG -#define HPRINTK(fmt,args...) hprintk(fmt,args) +#define HPRINTK(fmt,args...) printk(KERN_DEBUG DEV_LABEL "%d: " fmt, he_dev->number , ##args) #else -#define HPRINTK(fmt,args...) do { } while(0) +#define HPRINTK(fmt,args...) do { } while (0) #endif /* DEBUG */ @@ -171,25 +163,18 @@ static struct atmdev_ops he_ops = { - open: he_open, - close: he_close, - ioctl: he_ioctl, - send: he_send, - sg_send: he_sg_send, - phy_put: he_phy_put, - phy_get: he_phy_get, - proc_read: he_proc_read, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,1) - owner: THIS_MODULE -#endif + .open = he_open, + .close = he_close, + .ioctl = he_ioctl, + .send = he_send, + .sg_send = he_sg_send, + .phy_put = he_phy_put, + .phy_get = he_phy_get, + .proc_read = he_proc_read, + .owner = THIS_MODULE }; -/* see the comments in he.h about global_lock */ - -#define HE_SPIN_LOCK(dev, flags) spin_lock_irqsave(&(dev)->global_lock, flags) -#define HE_SPIN_UNLOCK(dev, flags) spin_unlock_irqrestore(&(dev)->global_lock, flags) - -#define he_writel(dev, val, reg) do { writel(val, (dev)->membase + (reg)); wmb(); } while(0) +#define he_writel(dev, val, reg) do { writel(val, (dev)->membase + (reg)); wmb(); } while (0) #define he_readl(dev, reg) readl((dev)->membase + (reg)) /* section 2.12 connection memory access */ @@ -203,7 +188,7 @@ (void) he_readl(he_dev, CON_DAT); #endif he_writel(he_dev, flags | CON_CTL_WRITE | CON_CTL_ADDR(addr), CON_CTL); - while(he_readl(he_dev, CON_CTL) & CON_CTL_BUSY); + while (he_readl(he_dev, CON_CTL) & CON_CTL_BUSY); } #define he_writel_rcm(dev, val, reg) \ @@ -219,7 +204,7 @@ he_readl_internal(struct he_dev *he_dev, unsigned addr, unsigned flags) { he_writel(he_dev, flags | CON_CTL_READ | CON_CTL_ADDR(addr), CON_CTL); - while(he_readl(he_dev, CON_CTL) & CON_CTL_BUSY); + while (he_readl(he_dev, CON_CTL) & CON_CTL_BUSY); return he_readl(he_dev, CON_DAT); } @@ -235,26 +220,26 @@ /* figure 2.2 connection id */ -#define he_mkcid(dev, vpi, vci) (((vpi<<(dev)->vcibits) | vci) & 0x1fff) +#define he_mkcid(dev, vpi, vci) (((vpi << (dev)->vcibits) | vci) & 0x1fff) /* 2.5.1 per connection transmit state registers */ #define he_writel_tsr0(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 0) + he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 0) #define he_readl_tsr0(dev, cid) \ - he_readl_tcm(dev, CONFIG_TSRA | (cid<<3) | 0) + he_readl_tcm(dev, CONFIG_TSRA | (cid << 3) | 0) #define he_writel_tsr1(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 1) + he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 1) #define he_writel_tsr2(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 2) + he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 2) #define he_writel_tsr3(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 3) + he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 3) #define he_writel_tsr4(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 4) + he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 4) /* from page 2-20 * @@ -265,43 +250,43 @@ */ #define he_writel_tsr4_upper(dev, val, cid) \ - he_writel_internal(dev, val, CONFIG_TSRA | (cid<<3) | 4, \ + he_writel_internal(dev, val, CONFIG_TSRA | (cid << 3) | 4, \ CON_CTL_TCM \ | CON_BYTE_DISABLE_2 \ | CON_BYTE_DISABLE_1 \ | CON_BYTE_DISABLE_0) #define he_readl_tsr4(dev, cid) \ - he_readl_tcm(dev, CONFIG_TSRA | (cid<<3) | 4) + he_readl_tcm(dev, CONFIG_TSRA | (cid << 3) | 4) #define he_writel_tsr5(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 5) + he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 5) #define he_writel_tsr6(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 6) + he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 6) #define he_writel_tsr7(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 7) + he_writel_tcm(dev, val, CONFIG_TSRA | (cid << 3) | 7) #define he_writel_tsr8(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRB | (cid<<2) | 0) + he_writel_tcm(dev, val, CONFIG_TSRB | (cid << 2) | 0) #define he_writel_tsr9(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRB | (cid<<2) | 1) + he_writel_tcm(dev, val, CONFIG_TSRB | (cid << 2) | 1) #define he_writel_tsr10(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRB | (cid<<2) | 2) + he_writel_tcm(dev, val, CONFIG_TSRB | (cid << 2) | 2) #define he_writel_tsr11(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRB | (cid<<2) | 3) + he_writel_tcm(dev, val, CONFIG_TSRB | (cid << 2) | 3) #define he_writel_tsr12(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRC | (cid<<1) | 0) + he_writel_tcm(dev, val, CONFIG_TSRC | (cid << 1) | 0) #define he_writel_tsr13(dev, val, cid) \ - he_writel_tcm(dev, val, CONFIG_TSRC | (cid<<1) | 1) + he_writel_tcm(dev, val, CONFIG_TSRC | (cid << 1) | 1) #define he_writel_tsr14(dev, val, cid) \ @@ -317,30 +302,30 @@ /* 2.7.1 per connection receive state registers */ #define he_writel_rsr0(dev, val, cid) \ - he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 0) + he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 0) #define he_readl_rsr0(dev, cid) \ - he_readl_rcm(dev, 0x00000 | (cid<<3) | 0) + he_readl_rcm(dev, 0x00000 | (cid << 3) | 0) #define he_writel_rsr1(dev, val, cid) \ - he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 1) + he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 1) #define he_writel_rsr2(dev, val, cid) \ - he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 2) + he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 2) #define he_writel_rsr3(dev, val, cid) \ - he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 3) + he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 3) #define he_writel_rsr4(dev, val, cid) \ - he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 4) + he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 4) #define he_writel_rsr5(dev, val, cid) \ - he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 5) + he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 5) #define he_writel_rsr6(dev, val, cid) \ - he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 6) + he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 6) #define he_writel_rsr7(dev, val, cid) \ - he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 7) + he_writel_rcm(dev, val, 0x00000 | (cid << 3) | 7) static __inline__ struct atm_vcc* he_find_vcc(struct he_dev *he_dev, unsigned cid) @@ -351,7 +336,7 @@ int vci; vpi = cid >> he_dev->vcibits; - vci = cid & ((1<<he_dev->vcibits)-1); + vci = cid & ((1 << he_dev->vcibits) - 1); spin_lock_irqsave(&he_dev->atm_dev->lock, flags); for (vcc = he_dev->atm_dev->vccs; vcc; vcc = vcc->next) @@ -374,7 +359,8 @@ printk(KERN_INFO "he: %s\n", version); - if (pci_enable_device(pci_dev)) return -EIO; + if (pci_enable_device(pci_dev)) + return -EIO; if (pci_set_dma_mask(pci_dev, HE_DMA_MASK) != 0) { printk(KERN_WARNING "he: no suitable dma available\n"); err = -EIO; @@ -407,7 +393,8 @@ goto init_one_failure; } he_dev->next = NULL; - if (he_devs) he_dev->next = he_devs; + if (he_devs) + he_dev->next = he_devs; he_devs = he_dev; return 0; @@ -443,118 +430,112 @@ static unsigned rate_to_atmf(unsigned rate) /* cps to atm forum format */ { -#define NONZERO (1<<14) +#define NONZERO (1 << 14) - unsigned exp = 0; + unsigned exp = 0; - if (rate == 0) return(0); + if (rate == 0) + return 0; - rate <<= 9; - while (rate > 0x3ff) - { - ++exp; - rate >>= 1; - } + rate <<= 9; + while (rate > 0x3ff) { + ++exp; + rate >>= 1; + } - return (NONZERO | (exp << 9) | (rate & 0x1ff)); + return (NONZERO | (exp << 9) | (rate & 0x1ff)); } static void __init he_init_rx_lbfp0(struct he_dev *he_dev) { - unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count; - unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf; - unsigned lbuf_bufsize = he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD; - unsigned row_offset = he_dev->r0_startrow * he_dev->bytes_per_row; - + unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count; + unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf; + unsigned lbuf_bufsize = he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD; + unsigned row_offset = he_dev->r0_startrow * he_dev->bytes_per_row; + lbufd_index = 0; - lbm_offset = he_readl(he_dev, RCMLBM_BA); + lbm_offset = he_readl(he_dev, RCMLBM_BA); he_writel(he_dev, lbufd_index, RLBF0_H); - for (i = 0, lbuf_count = 0; i < he_dev->r0_numbuffs; ++i) - { + for (i = 0, lbuf_count = 0; i < he_dev->r0_numbuffs; ++i) { lbufd_index += 2; - lbuf_addr = (row_offset + (lbuf_count * lbuf_bufsize)) / 32; + lbuf_addr = (row_offset + (lbuf_count * lbuf_bufsize)) / 32; he_writel_rcm(he_dev, lbuf_addr, lbm_offset); he_writel_rcm(he_dev, lbufd_index, lbm_offset + 1); - if (++lbuf_count == lbufs_per_row) - { - lbuf_count = 0; - row_offset += he_dev->bytes_per_row; - } + if (++lbuf_count == lbufs_per_row) { + lbuf_count = 0; + row_offset += he_dev->bytes_per_row; + } lbm_offset += 4; - } - - he_writel(he_dev, lbufd_index - 2, RLBF0_T); + } + + he_writel(he_dev, lbufd_index - 2, RLBF0_T); he_writel(he_dev, he_dev->r0_numbuffs, RLBF0_C); } static void __init he_init_rx_lbfp1(struct he_dev *he_dev) { - unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count; - unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf; - unsigned lbuf_bufsize = he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD; - unsigned row_offset = he_dev->r1_startrow * he_dev->bytes_per_row; - + unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count; + unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf; + unsigned lbuf_bufsize = he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD; + unsigned row_offset = he_dev->r1_startrow * he_dev->bytes_per_row; + lbufd_index = 1; - lbm_offset = he_readl(he_dev, RCMLBM_BA) + (2 * lbufd_index); + lbm_offset = he_readl(he_dev, RCMLBM_BA) + (2 * lbufd_index); he_writel(he_dev, lbufd_index, RLBF1_H); - for (i = 0, lbuf_count = 0; i < he_dev->r1_numbuffs; ++i) - { + for (i = 0, lbuf_count = 0; i < he_dev->r1_numbuffs; ++i) { lbufd_index += 2; - lbuf_addr = (row_offset + (lbuf_count * lbuf_bufsize)) / 32; + lbuf_addr = (row_offset + (lbuf_count * lbuf_bufsize)) / 32; he_writel_rcm(he_dev, lbuf_addr, lbm_offset); he_writel_rcm(he_dev, lbufd_index, lbm_offset + 1); - if (++lbuf_count == lbufs_per_row) - { - lbuf_count = 0; - row_offset += he_dev->bytes_per_row; - } + if (++lbuf_count == lbufs_per_row) { + lbuf_count = 0; + row_offset += he_dev->bytes_per_row; + } lbm_offset += 4; - } - - he_writel(he_dev, lbufd_index - 2, RLBF1_T); + } + + he_writel(he_dev, lbufd_index - 2, RLBF1_T); he_writel(he_dev, he_dev->r1_numbuffs, RLBF1_C); } static void __init he_init_tx_lbfp(struct he_dev *he_dev) { - unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count; - unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf; - unsigned lbuf_bufsize = he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD; - unsigned row_offset = he_dev->tx_startrow * he_dev->bytes_per_row; - + unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count; + unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf; + unsigned lbuf_bufsize = he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD; + unsigned row_offset = he_dev->tx_startrow * he_dev->bytes_per_row; + lbufd_index = he_dev->r0_numbuffs + he_dev->r1_numbuffs; - lbm_offset = he_readl(he_dev, RCMLBM_BA) + (2 * lbufd_index); + lbm_offset = he_readl(he_dev, RCMLBM_BA) + (2 * lbufd_index); he_writel(he_dev, lbufd_index, TLBF_H); - for (i = 0, lbuf_count = 0; i < he_dev->tx_numbuffs; ++i) - { + for (i = 0, lbuf_count = 0; i < he_dev->tx_numbuffs; ++i) { lbufd_index += 1; - lbuf_addr = (row_offset + (lbuf_count * lbuf_bufsize)) / 32; + lbuf_addr = (row_offset + (lbuf_count * lbuf_bufsize)) / 32; he_writel_rcm(he_dev, lbuf_addr, lbm_offset); he_writel_rcm(he_dev, lbufd_index, lbm_offset + 1); - if (++lbuf_count == lbufs_per_row) - { - lbuf_count = 0; - row_offset += he_dev->bytes_per_row; - } + if (++lbuf_count == lbufs_per_row) { + lbuf_count = 0; + row_offset += he_dev->bytes_per_row; + } lbm_offset += 2; - } - - he_writel(he_dev, lbufd_index - 1, TLBF_T); + } + + he_writel(he_dev, lbufd_index - 1, TLBF_T); } static int __init @@ -562,8 +543,7 @@ { he_dev->tpdrq_base = pci_alloc_consistent(he_dev->pci_dev, CONFIG_TPDRQ_SIZE * sizeof(struct he_tpdrq), &he_dev->tpdrq_phys); - if (he_dev->tpdrq_base == NULL) - { + if (he_dev->tpdrq_base == NULL) { hprintk("failed to alloc tpdrq\n"); return -ENOMEM; } @@ -588,7 +568,7 @@ /* 5.1.7 cs block initialization */ - for(reg = 0; reg < 0x20; ++reg) + for (reg = 0; reg < 0x20; ++reg) he_writel_mbox(he_dev, 0x0, CS_STTIM0 + reg); /* rate grid timer reload values */ @@ -597,8 +577,7 @@ rate = he_dev->atm_dev->link_rate; delta = rate / 16 / 2; - for(reg = 0; reg < 0x10; ++reg) - { + for (reg = 0; reg < 0x10; ++reg) { /* 2.4 internal transmit function * * we initialize the first row in the rate grid. @@ -610,8 +589,7 @@ rate -= delta; } - if (he_is622(he_dev)) - { + if (he_is622(he_dev)) { /* table 5.2 (4 cells per lbuf) */ he_writel_mbox(he_dev, 0x000800fa, CS_ERTHR0); he_writel_mbox(he_dev, 0x000c33cb, CS_ERTHR1); @@ -640,9 +618,7 @@ /* table 5.9 */ he_writel_mbox(he_dev, 0x5, CS_OTPPER); he_writel_mbox(he_dev, 0x14, CS_OTWPER); - } - else - { + } else { /* table 5.1 (4 cells per lbuf) */ he_writel_mbox(he_dev, 0x000400ea, CS_ERTHR0); he_writel_mbox(he_dev, 0x00063388, CS_ERTHR1); @@ -671,26 +647,29 @@ /* table 5.9 */ he_writel_mbox(he_dev, 0x6, CS_OTPPER); he_writel_mbox(he_dev, 0x1e, CS_OTWPER); - } he_writel_mbox(he_dev, 0x8, CS_OTTLIM); - for(reg = 0; reg < 0x8; ++reg) + for (reg = 0; reg < 0x8; ++reg) he_writel_mbox(he_dev, 0x0, CS_HGRRT0 + reg); } -static void __init +static int __init he_init_cs_block_rcm(struct he_dev *he_dev) { - unsigned rategrid[16][16]; + unsigned (*rategrid)[16][16]; unsigned rate, delta; int i, j, reg; unsigned rate_atmf, exp, man; unsigned long long rate_cps; - int mult, buf, buf_limit = 4; + int mult, buf, buf_limit = 4; + + rategrid = kmalloc( sizeof(unsigned) * 16 * 16, GFP_KERNEL); + if (!rategrid) + return -ENOMEM; /* initialize rate grid group table */ @@ -720,18 +699,17 @@ * in order to construct the rate to group table below */ - for (j = 0; j < 16; j++) - { - rategrid[0][j] = rate; + for (j = 0; j < 16; j++) { + (*rategrid)[0][j] = rate; rate -= delta; } for (i = 1; i < 16; i++) for (j = 0; j < 16; j++) if (i > 14) - rategrid[i][j] = rategrid[i - 1][j] / 4; + (*rategrid)[i][j] = (*rategrid)[i - 1][j] / 4; else - rategrid[i][j] = rategrid[i - 1][j] / 2; + (*rategrid)[i][j] = (*rategrid)[i - 1][j] / 2; /* * 2.4 transmit internal function @@ -742,8 +720,7 @@ */ rate_atmf = 0; - while (rate_atmf < 0x400) - { + while (rate_atmf < 0x400) { man = (rate_atmf & 0x1f) << 4; exp = rate_atmf >> 5; @@ -753,12 +730,12 @@ */ rate_cps = (unsigned long long) (1 << exp) * (man + 512) >> 9; - if (rate_cps < 10) rate_cps = 10; - /* 2.2.1 minimum payload rate is 10 cps */ + if (rate_cps < 10) + rate_cps = 10; /* 2.2.1 minimum payload rate is 10 cps */ for (i = 255; i > 0; i--) - if (rategrid[i/16][i%16] >= rate_cps) break; - /* pick nearest rate instead? */ + if ((*rategrid)[i/16][i%16] >= rate_cps) + break; /* pick nearest rate instead? */ /* * each table entry is 16 bits: (rate grid index (8 bits) @@ -767,28 +744,37 @@ */ #ifdef notdef - buf = rate_cps * he_dev->tx_numbuffs / + buf = rate_cps * he_dev->tx_numbuffs / (he_dev->atm_dev->link_rate * 2); #else /* this is pretty, but avoids _divdu3 and is mostly correct */ - buf = 0; - mult = he_dev->atm_dev->link_rate / ATM_OC3_PCR; - if (rate_cps > (68 * mult)) buf = 1; - if (rate_cps > (136 * mult)) buf = 2; - if (rate_cps > (204 * mult)) buf = 3; - if (rate_cps > (272 * mult)) buf = 4; + mult = he_dev->atm_dev->link_rate / ATM_OC3_PCR; + if (rate_cps > (272 * mult)) + buf = 4; + else if (rate_cps > (204 * mult)) + buf = 3; + else if (rate_cps > (136 * mult)) + buf = 2; + else if (rate_cps > (68 * mult)) + buf = 1; + else + buf = 0; #endif - if (buf > buf_limit) buf = buf_limit; - reg = (reg<<16) | ((i<<8) | buf); + if (buf > buf_limit) + buf = buf_limit; + reg = (reg << 16) | ((i << 8) | buf); #define RTGTBL_OFFSET 0x400 if (rate_atmf & 0x1) he_writel_rcm(he_dev, reg, - CONFIG_RCMABR + RTGTBL_OFFSET + (rate_atmf>>1)); + CONFIG_RCMABR + RTGTBL_OFFSET + (rate_atmf >> 1)); ++rate_atmf; } + + kfree(rategrid); + return 0; } static int __init @@ -801,8 +787,7 @@ #ifdef USE_RBPS_POOL he_dev->rbps_pool = pci_pool_create("rbps", he_dev->pci_dev, CONFIG_RBPS_BUFSIZE, 8, 0); - if (he_dev->rbps_pool == NULL) - { + if (he_dev->rbps_pool == NULL) { hprintk("unable to create rbps pages\n"); return -ENOMEM; } @@ -817,16 +802,14 @@ he_dev->rbps_base = pci_alloc_consistent(he_dev->pci_dev, CONFIG_RBPS_SIZE * sizeof(struct he_rbp), &he_dev->rbps_phys); - if (he_dev->rbps_base == NULL) - { + if (he_dev->rbps_base == NULL) { hprintk("failed to alloc rbps\n"); return -ENOMEM; } memset(he_dev->rbps_base, 0, CONFIG_RBPS_SIZE * sizeof(struct he_rbp)); he_dev->rbps_virt = kmalloc(CONFIG_RBPS_SIZE * sizeof(struct he_virt), GFP_KERNEL); - for (i = 0; i < CONFIG_RBPS_SIZE; ++i) - { + for (i = 0; i < CONFIG_RBPS_SIZE; ++i) { dma_addr_t dma_handle; void *cpuaddr; @@ -844,7 +827,7 @@ he_dev->rbps_base[i].phys = dma_handle; } - he_dev->rbps_tail = &he_dev->rbps_base[CONFIG_RBPS_SIZE-1]; + he_dev->rbps_tail = &he_dev->rbps_base[CONFIG_RBPS_SIZE - 1]; he_writel(he_dev, he_dev->rbps_phys, G0_RBPS_S + (group * 32)); he_writel(he_dev, RBPS_MASK(he_dev->rbps_tail), @@ -853,7 +836,7 @@ G0_RBPS_BS + (group * 32)); he_writel(he_dev, RBP_THRESH(CONFIG_RBPS_THRESH) | - RBP_QSIZE(CONFIG_RBPS_SIZE-1) | + RBP_QSIZE(CONFIG_RBPS_SIZE - 1) | RBP_INT_ENB, G0_RBPS_QI + (group * 32)); #else /* !USE_RBPS */ @@ -868,16 +851,14 @@ #ifdef USE_RBPL_POOL he_dev->rbpl_pool = pci_pool_create("rbpl", he_dev->pci_dev, CONFIG_RBPL_BUFSIZE, 8, 0); - if (he_dev->rbpl_pool == NULL) - { + if (he_dev->rbpl_pool == NULL) { hprintk("unable to create rbpl pool\n"); return -ENOMEM; } #else /* !USE_RBPL_POOL */ he_dev->rbpl_pages = (void *) pci_alloc_consistent(he_dev->pci_dev, CONFIG_RBPL_SIZE * CONFIG_RBPL_BUFSIZE, &he_dev->rbpl_pages_phys); - if (he_dev->rbpl_pages == NULL) - { + if (he_dev->rbpl_pages == NULL) { hprintk("unable to create rbpl pages\n"); return -ENOMEM; } @@ -885,16 +866,14 @@ he_dev->rbpl_base = pci_alloc_consistent(he_dev->pci_dev, CONFIG_RBPL_SIZE * sizeof(struct he_rbp), &he_dev->rbpl_phys); - if (he_dev->rbpl_base == NULL) - { + if (he_dev->rbpl_base == NULL) { hprintk("failed to alloc rbpl\n"); return -ENOMEM; } memset(he_dev->rbpl_base, 0, CONFIG_RBPL_SIZE * sizeof(struct he_rbp)); he_dev->rbpl_virt = kmalloc(CONFIG_RBPL_SIZE * sizeof(struct he_virt), GFP_KERNEL); - for (i = 0; i < CONFIG_RBPL_SIZE; ++i) - { + for (i = 0; i < CONFIG_RBPL_SIZE; ++i) { dma_addr_t dma_handle; void *cpuaddr; @@ -910,9 +889,8 @@ he_dev->rbpl_virt[i].virt = cpuaddr; he_dev->rbpl_base[i].status = RBP_LOANED | (i << RBP_INDEX_OFF); he_dev->rbpl_base[i].phys = dma_handle; - } - he_dev->rbpl_tail = &he_dev->rbpl_base[CONFIG_RBPL_SIZE-1]; + he_dev->rbpl_tail = &he_dev->rbpl_base[CONFIG_RBPL_SIZE - 1]; he_writel(he_dev, he_dev->rbpl_phys, G0_RBPL_S + (group * 32)); he_writel(he_dev, RBPL_MASK(he_dev->rbpl_tail), @@ -921,7 +899,7 @@ G0_RBPL_BS + (group * 32)); he_writel(he_dev, RBP_THRESH(CONFIG_RBPL_THRESH) | - RBP_QSIZE(CONFIG_RBPL_SIZE-1) | + RBP_QSIZE(CONFIG_RBPL_SIZE - 1) | RBP_INT_ENB, G0_RBPL_QI + (group * 32)); @@ -929,8 +907,7 @@ he_dev->rbrq_base = pci_alloc_consistent(he_dev->pci_dev, CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq), &he_dev->rbrq_phys); - if (he_dev->rbrq_base == NULL) - { + if (he_dev->rbrq_base == NULL) { hprintk("failed to allocate rbrq\n"); return -ENOMEM; } @@ -940,15 +917,13 @@ he_writel(he_dev, he_dev->rbrq_phys, G0_RBRQ_ST + (group * 16)); he_writel(he_dev, 0, G0_RBRQ_H + (group * 16)); he_writel(he_dev, - RBRQ_THRESH(CONFIG_RBRQ_THRESH) | RBRQ_SIZE(CONFIG_RBRQ_SIZE-1), + RBRQ_THRESH(CONFIG_RBRQ_THRESH) | RBRQ_SIZE(CONFIG_RBRQ_SIZE - 1), G0_RBRQ_Q + (group * 16)); - if (irq_coalesce) - { + if (irq_coalesce) { hprintk("coalescing interrupts\n"); he_writel(he_dev, RBRQ_TIME(768) | RBRQ_COUNT(7), G0_RBRQ_I + (group * 16)); - } - else + } else he_writel(he_dev, RBRQ_TIME(0) | RBRQ_COUNT(1), G0_RBRQ_I + (group * 16)); @@ -956,8 +931,7 @@ he_dev->tbrq_base = pci_alloc_consistent(he_dev->pci_dev, CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq), &he_dev->tbrq_phys); - if (he_dev->tbrq_base == NULL) - { + if (he_dev->tbrq_base == NULL) { hprintk("failed to allocate tbrq\n"); return -ENOMEM; } @@ -981,10 +955,9 @@ /* 2.9.3.5 tail offset for each interrupt queue is located after the end of the interrupt queue */ - he_dev->irq_base = pci_alloc_consistent(he_dev->pci_dev, + he_dev->irq_base = pci_alloc_consistent(he_dev->pci_dev, (CONFIG_IRQ_SIZE+1) * sizeof(struct he_irq), &he_dev->irq_phys); - if (he_dev->irq_base == NULL) - { + if (he_dev->irq_base == NULL) { hprintk("failed to allocate irq\n"); return -ENOMEM; } @@ -994,7 +967,7 @@ he_dev->irq_head = he_dev->irq_base; he_dev->irq_tail = he_dev->irq_base; - for(i=0; i < CONFIG_IRQ_SIZE; ++i) + for (i = 0; i < CONFIG_IRQ_SIZE; ++i) he_dev->irq_base[i].isw = ITYPE_INVALID; he_writel(he_dev, he_dev->irq_phys, IRQ0_BASE); @@ -1026,27 +999,21 @@ he_writel(he_dev, 0x0, GRP_54_MAP); he_writel(he_dev, 0x0, GRP_76_MAP); - if (request_irq(he_dev->pci_dev->irq, he_irq_handler, SA_INTERRUPT|SA_SHIRQ, DEV_LABEL, he_dev)) - { + if (request_irq(he_dev->pci_dev->irq, he_irq_handler, SA_INTERRUPT|SA_SHIRQ, DEV_LABEL, he_dev)) { hprintk("irq %d already in use\n", he_dev->pci_dev->irq); return -EINVAL; - } + } he_dev->irq = he_dev->pci_dev->irq; -#ifdef BUS_INT_WAR - HPRINTK("sn_add_polled_interrupt(irq %d, 1)\n", he_dev->irq); - sn_add_polled_interrupt(he_dev->irq, 1); -#endif - return 0; } static int __init he_start(struct atm_dev *dev) { - struct he_dev *he_dev; - struct pci_dev *pci_dev; + struct he_dev *he_dev; + struct pci_dev *pci_dev; u16 command; u32 gen_cntl_0, host_cntl, lb_swap; @@ -1056,8 +1023,8 @@ unsigned int status, reg; int i, group; - he_dev = HE_DEV(dev); - pci_dev = he_dev->pci_dev; + he_dev = HE_DEV(dev); + pci_dev = he_dev->pci_dev; he_dev->membase = pci_dev->resource[0].start; HPRINTK("membase = 0x%lx irq = %d.\n", he_dev->membase, pci_dev->irq); @@ -1067,46 +1034,39 @@ */ /* 4.3 pci bus controller-specific initialization */ - if (pci_read_config_dword(pci_dev, GEN_CNTL_0, &gen_cntl_0) != 0) - { + if (pci_read_config_dword(pci_dev, GEN_CNTL_0, &gen_cntl_0) != 0) { hprintk("can't read GEN_CNTL_0\n"); return -EINVAL; } gen_cntl_0 |= (MRL_ENB | MRM_ENB | IGNORE_TIMEOUT); - if (pci_write_config_dword(pci_dev, GEN_CNTL_0, gen_cntl_0) != 0) - { + if (pci_write_config_dword(pci_dev, GEN_CNTL_0, gen_cntl_0) != 0) { hprintk("can't write GEN_CNTL_0.\n"); return -EINVAL; } - if (pci_read_config_word(pci_dev, PCI_COMMAND, &command) != 0) - { + if (pci_read_config_word(pci_dev, PCI_COMMAND, &command) != 0) { hprintk("can't read PCI_COMMAND.\n"); return -EINVAL; } command |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE); - if (pci_write_config_word(pci_dev, PCI_COMMAND, command) != 0) - { + if (pci_write_config_word(pci_dev, PCI_COMMAND, command) != 0) { hprintk("can't enable memory.\n"); return -EINVAL; } - if (pci_read_config_byte(pci_dev, PCI_CACHE_LINE_SIZE, &cache_size)) - { + if (pci_read_config_byte(pci_dev, PCI_CACHE_LINE_SIZE, &cache_size)) { hprintk("can't read cache line size?\n"); return -EINVAL; } - if (cache_size < 16) - { + if (cache_size < 16) { cache_size = 16; if (pci_write_config_byte(pci_dev, PCI_CACHE_LINE_SIZE, cache_size)) hprintk("can't set cache line size to %d\n", cache_size); } - if (pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &timer)) - { + if (pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &timer)) { hprintk("can't read latency timer?\n"); return -EINVAL; } @@ -1120,8 +1080,7 @@ * */ #define LAT_TIMER 209 - if (timer < LAT_TIMER) - { + if (timer < LAT_TIMER) { HPRINTK("latency timer was %d, setting to %d\n", timer, LAT_TIMER); timer = LAT_TIMER; if (pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, timer)) @@ -1132,15 +1091,14 @@ hprintk("can't set up page mapping\n"); return -EINVAL; } - + /* 4.4 card reset */ he_writel(he_dev, 0x0, RESET_CNTL); he_writel(he_dev, 0xff, RESET_CNTL); udelay(16*1000); /* 16 ms */ status = he_readl(he_dev, RESET_CNTL); - if ((status & BOARD_RST_STATUS) == 0) - { + if ((status & BOARD_RST_STATUS) == 0) { hprintk("reset failed\n"); return -EINVAL; } @@ -1152,23 +1110,23 @@ else gen_cntl_0 &= ~ENBL_64; - if (disable64 == 1) - { + if (disable64 == 1) { hprintk("disabling 64-bit pci bus transfers\n"); gen_cntl_0 &= ~ENBL_64; } - if (gen_cntl_0 & ENBL_64) hprintk("64-bit transfers enabled\n"); + if (gen_cntl_0 & ENBL_64) + hprintk("64-bit transfers enabled\n"); pci_write_config_dword(pci_dev, GEN_CNTL_0, gen_cntl_0); /* 4.7 read prom contents */ - for(i=0; i<PROD_ID_LEN; ++i) + for (i = 0; i < PROD_ID_LEN; ++i) he_dev->prod_id[i] = read_prom_byte(he_dev, PROD_ID + i); he_dev->media = read_prom_byte(he_dev, MEDIA); - for(i=0; i<6; ++i) + for (i = 0; i < 6; ++i) dev->esi[i] = read_prom_byte(he_dev, MAC_ADDR + i); hprintk("%s%s, %x:%x:%x:%x:%x:%x\n", @@ -1205,7 +1163,8 @@ he_writel(he_dev, lb_swap, LB_SWAP); /* 4.10 initialize the interrupt queues */ - if ((err = he_init_irq(he_dev)) != 0) return err; + if ((err = he_init_irq(he_dev)) != 0) + return err; #ifdef USE_TASKLET tasklet_init(&he_dev->tasklet, he_tasklet, (unsigned long) he_dev); @@ -1258,27 +1217,23 @@ he_dev->vcibits = CONFIG_DEFAULT_VCIBITS; he_dev->vpibits = CONFIG_DEFAULT_VPIBITS; - if (nvpibits != -1 && nvcibits != -1 && nvpibits+nvcibits != HE_MAXCIDBITS) - { + if (nvpibits != -1 && nvcibits != -1 && nvpibits+nvcibits != HE_MAXCIDBITS) { hprintk("nvpibits + nvcibits != %d\n", HE_MAXCIDBITS); return -ENODEV; } - if (nvpibits != -1) - { + if (nvpibits != -1) { he_dev->vpibits = nvpibits; he_dev->vcibits = HE_MAXCIDBITS - nvpibits; } - if (nvcibits != -1) - { + if (nvcibits != -1) { he_dev->vcibits = nvcibits; he_dev->vpibits = HE_MAXCIDBITS - nvcibits; } - if (he_is622(he_dev)) - { + if (he_is622(he_dev)) { he_dev->cells_per_row = 40; he_dev->bytes_per_row = 2048; he_dev->r0_numrows = 256; @@ -1287,9 +1242,7 @@ he_dev->r0_startrow = 0; he_dev->tx_startrow = 256; he_dev->r1_startrow = 768; - } - else - { + } else { he_dev->cells_per_row = 20; he_dev->bytes_per_row = 1024; he_dev->r0_numrows = 512; @@ -1304,15 +1257,18 @@ he_dev->buffer_limit = 4; he_dev->r0_numbuffs = he_dev->r0_numrows * he_dev->cells_per_row / he_dev->cells_per_lbuf; - if (he_dev->r0_numbuffs > 2560) he_dev->r0_numbuffs = 2560; + if (he_dev->r0_numbuffs > 2560) + he_dev->r0_numbuffs = 2560; he_dev->r1_numbuffs = he_dev->r1_numrows * he_dev->cells_per_row / he_dev->cells_per_lbuf; - if (he_dev->r1_numbuffs > 2560) he_dev->r1_numbuffs = 2560; + if (he_dev->r1_numbuffs > 2560) + he_dev->r1_numbuffs = 2560; he_dev->tx_numbuffs = he_dev->tx_numrows * he_dev->cells_per_row / he_dev->cells_per_lbuf; - if (he_dev->tx_numbuffs > 5120) he_dev->tx_numbuffs = 5120; + if (he_dev->tx_numbuffs > 5120) + he_dev->tx_numbuffs = 5120; /* 5.1.2 configure hardware dependent registers */ @@ -1350,15 +1306,15 @@ he_writel(he_dev, 0x0, TXAAL5_PROTO); he_writel(he_dev, PHY_INT_ENB | - (he_is622(he_dev) ? PTMR_PRE(67-1) : PTMR_PRE(50-1)), + (he_is622(he_dev) ? PTMR_PRE(67 - 1) : PTMR_PRE(50 - 1)), RH_CONFIG); /* 5.1.3 initialize connection memory */ - for(i=0; i < TCM_MEM_SIZE; ++i) + for (i = 0; i < TCM_MEM_SIZE; ++i) he_writel_tcm(he_dev, 0, i); - for(i=0; i < RCM_MEM_SIZE; ++i) + for (i = 0; i < RCM_MEM_SIZE; ++i) he_writel_rcm(he_dev, 0, i); /* @@ -1448,8 +1404,7 @@ /* 5.1.5 initialize intermediate receive queues */ - if (he_is622(he_dev)) - { + if (he_is622(he_dev)) { he_writel(he_dev, 0x000f, G0_INMQ_S); he_writel(he_dev, 0x200f, G0_INMQ_L); @@ -1473,9 +1428,7 @@ he_writel(he_dev, 0x007f, G7_INMQ_S); he_writel(he_dev, 0x207f, G7_INMQ_L); - } - else - { + } else { he_writel(he_dev, 0x0000, G0_INMQ_S); he_writel(he_dev, 0x0008, G0_INMQ_L); @@ -1514,7 +1467,8 @@ /* 5.1.8 cs block connection memory initialization */ - he_init_cs_block_rcm(he_dev); + if (he_init_cs_block_rcm(he_dev) < 0) + return -ENOMEM; /* 5.1.10 initialize host structures */ @@ -1523,8 +1477,7 @@ #ifdef USE_TPD_POOL he_dev->tpd_pool = pci_pool_create("tpd", he_dev->pci_dev, sizeof(struct he_tpd), TPD_ALIGNMENT, 0); - if (he_dev->tpd_pool == NULL) - { + if (he_dev->tpd_pool == NULL) { hprintk("unable to create tpd pci_pool\n"); return -ENOMEM; } @@ -1536,21 +1489,19 @@ if (!he_dev->tpd_base) return -ENOMEM; - for(i = 0; i < CONFIG_NUMTPDS; ++i) - { + for (i = 0; i < CONFIG_NUMTPDS; ++i) { he_dev->tpd_base[i].status = (i << TPD_ADDR_SHIFT); he_dev->tpd_base[i].inuse = 0; } he_dev->tpd_head = he_dev->tpd_base; - he_dev->tpd_end = &he_dev->tpd_base[CONFIG_NUMTPDS-1]; + he_dev->tpd_end = &he_dev->tpd_base[CONFIG_NUMTPDS - 1]; #endif if (he_init_group(he_dev, 0) != 0) return -ENOMEM; - for (group = 1; group < HE_NUM_GROUPS; ++group) - { + for (group = 1; group < HE_NUM_GROUPS; ++group) { he_writel(he_dev, 0x0, G0_RBPS_S + (group * 32)); he_writel(he_dev, 0x0, G0_RBPS_T + (group * 32)); he_writel(he_dev, 0x0, G0_RBPS_QI + (group * 32)); @@ -1580,8 +1531,7 @@ he_dev->hsp = pci_alloc_consistent(he_dev->pci_dev, sizeof(struct he_hsp), &he_dev->hsp_phys); - if (he_dev->hsp == NULL) - { + if (he_dev->hsp == NULL) { hprintk("failed to allocate host status page\n"); return -ENOMEM; } @@ -1596,8 +1546,7 @@ he_dev->atm_dev->phy->start(he_dev->atm_dev); #endif /* CONFIG_ATM_HE_USE_SUNI */ - if (sdh) - { + if (sdh) { /* this really should be in suni.c but for now... */ int val; @@ -1620,8 +1569,7 @@ #ifndef USE_HE_FIND_VCC he_dev->he_vcc_table = kmalloc(sizeof(struct he_vcc_table) * (1 << (he_dev->vcibits + he_dev->vpibits)), GFP_KERNEL); - if (he_dev->he_vcc_table == NULL) - { + if (he_dev->he_vcc_table == NULL) { hprintk("failed to alloc he_vcc_table\n"); return -ENOMEM; } @@ -1629,8 +1577,7 @@ (1 << (he_dev->vcibits + he_dev->vpibits))); #endif - for (i = 0; i < HE_NUM_CS_STPER; ++i) - { + for (i = 0; i < HE_NUM_CS_STPER; ++i) { he_dev->cs_stper[i].inuse = 0; he_dev->cs_stper[i].pcr = -1; } @@ -1644,8 +1591,8 @@ he_dev->irq_peak = 0; he_dev->rbrq_peak = 0; - he_dev->rbpl_peak = 0; - he_dev->tbrq_peak = 0; + he_dev->rbpl_peak = 0; + he_dev->tbrq_peak = 0; HPRINTK("hell bent for leather!\n"); @@ -1663,8 +1610,7 @@ /* disable interrupts */ - if (he_dev->membase) - { + if (he_dev->membase) { pci_read_config_dword(pci_dev, GEN_CNTL_0, &gen_cntl_0); gen_cntl_0 &= ~(INT_PROC_ENBL | INIT_ENB); pci_write_config_dword(pci_dev, GEN_CNTL_0, gen_cntl_0); @@ -1690,12 +1636,7 @@ #endif /* CONFIG_ATM_HE_USE_SUNI */ if (he_dev->irq) - { -#ifdef BUS_INT_WAR - sn_delete_polled_interrupt(he_dev->irq); -#endif free_irq(he_dev->irq, he_dev); - } if (he_dev->irq_base) pci_free_consistent(he_dev->pci_dev, (CONFIG_IRQ_SIZE+1) @@ -1705,11 +1646,9 @@ pci_free_consistent(he_dev->pci_dev, sizeof(struct he_hsp), he_dev->hsp, he_dev->hsp_phys); - if (he_dev->rbpl_base) - { + if (he_dev->rbpl_base) { #ifdef USE_RBPL_POOL - for (i=0; i<CONFIG_RBPL_SIZE; ++i) - { + for (i = 0; i < CONFIG_RBPL_SIZE; ++i) { void *cpuaddr = he_dev->rbpl_virt[i].virt; dma_addr_t dma_handle = he_dev->rbpl_base[i].phys; @@ -1729,11 +1668,9 @@ #endif #ifdef USE_RBPS - if (he_dev->rbps_base) - { + if (he_dev->rbps_base) { #ifdef USE_RBPS_POOL - for (i=0; i<CONFIG_RBPS_SIZE; ++i) - { + for (i = 0; i < CONFIG_RBPS_SIZE; ++i) { void *cpuaddr = he_dev->rbps_virt[i].virt; dma_addr_t dma_handle = he_dev->rbps_base[i].phys; @@ -1780,14 +1717,14 @@ kfree(he_dev->he_vcc_table); #endif - if (he_dev->pci_dev) - { + if (he_dev->pci_dev) { pci_read_config_word(he_dev->pci_dev, PCI_COMMAND, &command); command &= ~(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); pci_write_config_word(he_dev->pci_dev, PCI_COMMAND, command); } - if (he_dev->membase) iounmap((void *) he_dev->membase); + if (he_dev->membase) + iounmap((void *) he_dev->membase); } static struct he_tpd * @@ -1811,8 +1748,7 @@ #else int i; - for(i = 0; i < CONFIG_NUMTPDS; ++i) - { + for (i = 0; i < CONFIG_NUMTPDS; ++i) { ++he_dev->tpd_head; if (he_dev->tpd_head > he_dev->tpd_end) { he_dev->tpd_head = he_dev->tpd_base; @@ -1833,7 +1769,7 @@ } #define AAL5_LEN(buf,len) \ - ((((unsigned char *)(buf))[(len)-6]<<8) | \ + ((((unsigned char *)(buf))[(len)-6] << 8) | \ (((unsigned char *)(buf))[(len)-5])) /* 2.10.1.2 receive @@ -1843,7 +1779,7 @@ */ #define TCP_CKSUM(buf,len) \ - ((((unsigned char *)(buf))[(len)-2]<<8) | \ + ((((unsigned char *)(buf))[(len)-2] << 8) | \ (((unsigned char *)(buf))[(len-1)])) static int @@ -1862,8 +1798,7 @@ int pdus_assembled = 0; int updated = 0; - while (he_dev->rbrq_head != rbrq_tail) - { + while (he_dev->rbrq_head != rbrq_tail) { ++updated; HPRINTK("%p rbrq%d 0x%x len=%d cid=0x%x %s%s%s%s%s%s\n", @@ -1895,8 +1830,7 @@ #else vcc = HE_LOOKUP_VCC(he_dev, cid); #endif - if (vcc == NULL) - { + if (vcc == NULL) { hprintk("vcc == NULL (cid 0x%x)\n", cid); if (!RBRQ_HBUF_ERR(he_dev->rbrq_head)) rbp->status &= ~RBP_LOANED; @@ -1905,16 +1839,14 @@ } he_vcc = HE_VCC(vcc); - if (he_vcc == NULL) - { + if (he_vcc == NULL) { hprintk("he_vcc == NULL (cid 0x%x)\n", cid); if (!RBRQ_HBUF_ERR(he_dev->rbrq_head)) rbp->status &= ~RBP_LOANED; goto next_rbrq_entry; } - if (RBRQ_HBUF_ERR(he_dev->rbrq_head)) - { + if (RBRQ_HBUF_ERR(he_dev->rbrq_head)) { hprintk("HBUF_ERR! (cid 0x%x)\n", cid); atomic_inc(&vcc->stats->rx_drop); goto return_host_buffers; @@ -1925,8 +1857,7 @@ he_vcc->pdu_len += buf_len; ++he_vcc->iov_tail; - if (RBRQ_CON_CLOSED(he_dev->rbrq_head)) - { + if (RBRQ_CON_CLOSED(he_dev->rbrq_head)) { lastcid = -1; HPRINTK("wake_up rx_waitq (cid 0x%x)\n", cid); wake_up(&he_vcc->rx_waitq); @@ -1934,17 +1865,16 @@ } #ifdef notdef - if ((he_vcc->iov_tail - he_vcc->iov_head) > HE_MAXIOV) - { + if ((he_vcc->iov_tail - he_vcc->iov_head) > HE_MAXIOV) { hprintk("iovec full! cid 0x%x\n", cid); goto return_host_buffers; } #endif - if (!RBRQ_END_PDU(he_dev->rbrq_head)) goto next_rbrq_entry; + if (!RBRQ_END_PDU(he_dev->rbrq_head)) + goto next_rbrq_entry; if (RBRQ_LEN_ERR(he_dev->rbrq_head) - || RBRQ_CRC_ERR(he_dev->rbrq_head)) - { + || RBRQ_CRC_ERR(he_dev->rbrq_head)) { HPRINTK("%s%s (%d.%d)\n", RBRQ_CRC_ERR(he_dev->rbrq_head) ? "CRC_ERR " : "", @@ -1957,19 +1887,18 @@ skb = atm_alloc_charge(vcc, he_vcc->pdu_len + rx_skb_reserve, GFP_ATOMIC); - if (!skb) - { + if (!skb) { HPRINTK("charge failed (%d.%d)\n", vcc->vpi, vcc->vci); goto return_host_buffers; } - if (rx_skb_reserve > 0) skb_reserve(skb, rx_skb_reserve); + if (rx_skb_reserve > 0) + skb_reserve(skb, rx_skb_reserve); do_gettimeofday(&skb->stamp); - for(iov = he_vcc->iov_head; - iov < he_vcc->iov_tail; ++iov) - { + for (iov = he_vcc->iov_head; + iov < he_vcc->iov_tail; ++iov) { #ifdef USE_RBPS if (iov->iov_base & RBP_SMALLBUF) memcpy(skb_put(skb, iov->iov_len), @@ -1980,8 +1909,7 @@ he_dev->rbpl_virt[RBP_INDEX(iov->iov_base)].virt, iov->iov_len); } - switch(vcc->qos.aal) - { + switch (vcc->qos.aal) { case ATM_AAL0: /* 2.10.1.5 raw cell receive */ skb->len = ATM_AAL0_SDU; @@ -1993,8 +1921,7 @@ skb->len = AAL5_LEN(skb->data, he_vcc->pdu_len); skb->tail = skb->data + skb->len; #ifdef USE_CHECKSUM_HW - if (vcc->vpi == 0 && vcc->vci >= ATM_NOT_RSV_VCI) - { + if (vcc->vpi == 0 && vcc->vci >= ATM_NOT_RSV_VCI) { skb->ip_summed = CHECKSUM_HW; skb->csum = TCP_CKSUM(skb->data, he_vcc->pdu_len); @@ -2018,9 +1945,8 @@ return_host_buffers: ++pdus_assembled; - for(iov = he_vcc->iov_head; - iov < he_vcc->iov_tail; ++iov) - { + for (iov = he_vcc->iov_head; + iov < he_vcc->iov_tail; ++iov) { #ifdef USE_RBPS if (iov->iov_base & RBP_SMALLBUF) rbp = &he_dev->rbps_base[RBP_INDEX(iov->iov_base)]; @@ -2041,9 +1967,9 @@ } - if (updated) - { - if (updated > he_dev->rbrq_peak) he_dev->rbrq_peak = updated; + if (updated) { + if (updated > he_dev->rbrq_peak) + he_dev->rbrq_peak = updated; he_writel(he_dev, RBRQ_MASK(he_dev->rbrq_head), G0_RBRQ_H + (group * 16)); @@ -2069,8 +1995,7 @@ /* 2.1.6 transmit buffer return queue */ - while (he_dev->tbrq_head != tbrq_tail) - { + while (he_dev->tbrq_head != tbrq_tail) { ++updated; HPRINTK("tbrq%d 0x%x%s%s\n", @@ -2081,19 +2006,16 @@ #ifdef USE_TPD_POOL tpd = NULL; p = &he_dev->outstanding_tpds; - while ((p = p->next) != &he_dev->outstanding_tpds) - { + while ((p = p->next) != &he_dev->outstanding_tpds) { struct he_tpd *__tpd = list_entry(p, struct he_tpd, entry); - if (TPD_ADDR(__tpd->status) == TBRQ_TPD(he_dev->tbrq_head)) - { + if (TPD_ADDR(__tpd->status) == TBRQ_TPD(he_dev->tbrq_head)) { tpd = __tpd; list_del(&__tpd->entry); break; } } - if (tpd == NULL) - { + if (tpd == NULL) { hprintk("unable to locate tpd for dma buffer %x\n", TBRQ_TPD(he_dev->tbrq_head)); goto next_tbrq_entry; @@ -2102,8 +2024,7 @@ tpd = &he_dev->tpd_base[ TPD_INDEX(TBRQ_TPD(he_dev->tbrq_head)) ]; #endif - if (TBRQ_EOS(he_dev->tbrq_head)) - { + if (TBRQ_EOS(he_dev->tbrq_head)) { HPRINTK("wake_up(tx_waitq) cid 0x%x\n", he_mkcid(he_dev, tpd->vcc->vpi, tpd->vcc->vci)); if (tpd->vcc) @@ -2112,19 +2033,18 @@ goto next_tbrq_entry; } - for(slot = 0; slot < TPD_MAXIOV; ++slot) - { + for (slot = 0; slot < TPD_MAXIOV; ++slot) { if (tpd->iovec[slot].addr) pci_unmap_single(he_dev->pci_dev, tpd->iovec[slot].addr, tpd->iovec[slot].len & TPD_LEN_MASK, PCI_DMA_TODEVICE); - if (tpd->iovec[slot].len & TPD_LST) break; + if (tpd->iovec[slot].len & TPD_LST) + break; } - if (tpd->skb) /* && !TBRQ_MULTIPLE(he_dev->tbrq_head) */ - { + if (tpd->skb) { /* && !TBRQ_MULTIPLE(he_dev->tbrq_head) */ if (tpd->vcc && tpd->vcc->pop) tpd->vcc->pop(tpd->vcc, tpd->skb); else @@ -2133,7 +2053,8 @@ next_tbrq_entry: #ifdef USE_TPD_POOL - if (tpd) pci_pool_free(he_dev->tpd_pool, tpd, TPD_ADDR(tpd->status)); + if (tpd) + pci_pool_free(he_dev->tpd_pool, tpd, TPD_ADDR(tpd->status)); #else tpd->inuse = 0; #endif @@ -2142,9 +2063,9 @@ TBRQ_MASK(++he_dev->tbrq_head)); } - if (updated) - { - if (updated > he_dev->tbrq_peak) he_dev->tbrq_peak = updated; + if (updated) { + if (updated > he_dev->tbrq_peak) + he_dev->tbrq_peak = updated; he_writel(he_dev, TBRQ_MASK(he_dev->tbrq_head), G0_TBRQ_H + (group * 16)); @@ -2165,8 +2086,7 @@ rbpl_head = (struct he_rbp *) ((unsigned long)he_dev->rbpl_base | RBPL_MASK(he_readl(he_dev, G0_RBPL_S))); - for(;;) - { + for (;;) { newtail = (struct he_rbp *) ((unsigned long)he_dev->rbpl_base | RBPL_MASK(he_dev->rbpl_tail+1)); @@ -2177,13 +2097,12 @@ newtail->status |= RBP_LOANED; he_dev->rbpl_tail = newtail; ++moved; - } if (moved) { he_writel(he_dev, RBPL_MASK(he_dev->rbpl_tail), G0_RBPL_T); #ifdef CONFIG_IA64_SGI_SN2 - (void) he_readl(he_dev, G0_RBPL_T); + (void) he_readl(he_dev, G0_RBPL_T); #endif } } @@ -2199,8 +2118,7 @@ rbps_head = (struct he_rbp *) ((unsigned long)he_dev->rbps_base | RBPS_MASK(he_readl(he_dev, G0_RBPS_S))); - for(;;) - { + for (;;) { newtail = (struct he_rbp *) ((unsigned long)he_dev->rbps_base | RBPS_MASK(he_dev->rbps_tail+1)); @@ -2211,13 +2129,12 @@ newtail->status |= RBP_LOANED; he_dev->rbps_tail = newtail; ++moved; - } if (moved) { he_writel(he_dev, RBPS_MASK(he_dev->rbps_tail), G0_RBPS_T); #ifdef CONFIG_IA64_SGI_SN2 - (void) he_readl(he_dev, G0_RBPS_T); + (void) he_readl(he_dev, G0_RBPS_T); #endif } } @@ -2233,23 +2150,21 @@ HPRINTK("tasklet (0x%lx)\n", data); #ifdef USE_TASKLET - HE_SPIN_LOCK(he_dev, flags); + spin_lock_irqsave(&he_dev->global_lock, flags); #endif - while(he_dev->irq_head != he_dev->irq_tail) - { + while (he_dev->irq_head != he_dev->irq_tail) { ++updated; type = ITYPE_TYPE(he_dev->irq_head->isw); group = ITYPE_GROUP(he_dev->irq_head->isw); - switch (type) - { + switch (type) { case ITYPE_RBRQ_THRESH: - hprintk("rbrq%d threshold\n", group); + HPRINTK("rbrq%d threshold\n", group); + /* fall through */ case ITYPE_RBRQ_TIMER: - if (he_service_rbrq(he_dev, group)) - { + if (he_service_rbrq(he_dev, group)) { he_service_rbpl(he_dev, group); #ifdef USE_RBPS he_service_rbps(he_dev, group); @@ -2257,7 +2172,8 @@ } break; case ITYPE_TBRQ_THRESH: - hprintk("tbrq%d threshold\n", group); + HPRINTK("tbrq%d threshold\n", group); + /* fall through */ case ITYPE_TPD_COMPLETE: he_service_tbrq(he_dev, group); break; @@ -2270,17 +2186,16 @@ #endif /* USE_RBPS */ break; case ITYPE_PHY: + HPRINTK("phy interrupt\n"); #ifdef CONFIG_ATM_HE_USE_SUNI - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); if (he_dev->atm_dev->phy && he_dev->atm_dev->phy->interrupt) he_dev->atm_dev->phy->interrupt(he_dev->atm_dev); - HE_SPIN_LOCK(he_dev, flags); + spin_lock_irqsave(&he_dev->global_lock, flags); #endif - HPRINTK("phy interrupt\n"); break; case ITYPE_OTHER: - switch (type|group) - { + switch (type|group) { case ITYPE_PARITY: hprintk("parity error\n"); break; @@ -2289,24 +2204,20 @@ break; } break; - default: - if (he_dev->irq_head->isw == ITYPE_INVALID) - { - /* see 8.1.1 -- check all queues */ + case ITYPE_TYPE(ITYPE_INVALID): + /* see 8.1.1 -- check all queues */ - HPRINTK("isw not updated 0x%x\n", - he_dev->irq_head->isw); + HPRINTK("isw not updated 0x%x\n", he_dev->irq_head->isw); - he_service_rbrq(he_dev, 0); - he_service_rbpl(he_dev, 0); + he_service_rbrq(he_dev, 0); + he_service_rbpl(he_dev, 0); #ifdef USE_RBPS - he_service_rbps(he_dev, 0); + he_service_rbps(he_dev, 0); #endif /* USE_RBPS */ - he_service_tbrq(he_dev, 0); - } - else - hprintk("bad isw = 0x%x?\n", - he_dev->irq_head->isw); + he_service_tbrq(he_dev, 0); + break; + default: + hprintk("bad isw 0x%x?\n", he_dev->irq_head->isw); } he_dev->irq_head->isw = ITYPE_INVALID; @@ -2314,9 +2225,9 @@ he_dev->irq_head = (struct he_irq *) NEXT_ENTRY(he_dev->irq_base, he_dev->irq_head, IRQ_MASK); } - if (updated) - { - if (updated > he_dev->irq_peak) he_dev->irq_peak = updated; + if (updated) { + if (updated > he_dev->irq_peak) + he_dev->irq_peak = updated; he_writel(he_dev, IRQ_SIZE(CONFIG_IRQ_SIZE) | @@ -2325,7 +2236,7 @@ (void) he_readl(he_dev, INT_FIFO); /* 8.1.2 controller errata */ } #ifdef USE_TASKLET - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); #endif } @@ -2339,13 +2250,12 @@ if (he_dev == NULL) return IRQ_NONE; - HE_SPIN_LOCK(he_dev, flags); + spin_lock_irqsave(&he_dev->global_lock, flags); he_dev->irq_tail = (struct he_irq *) (((unsigned long)he_dev->irq_base) | (*he_dev->irq_tailoffset << 2)); - if (he_dev->irq_tail == he_dev->irq_head) - { + if (he_dev->irq_tail == he_dev->irq_head) { HPRINTK("tailoffset not updated?\n"); he_dev->irq_tail = (struct he_irq *) ((unsigned long)he_dev->irq_base | ((he_readl(he_dev, IRQ0_BASE) & IRQ_MASK) << 2)); @@ -2357,8 +2267,7 @@ hprintk("spurious (or shared) interrupt?\n"); #endif - if (he_dev->irq_head != he_dev->irq_tail) - { + if (he_dev->irq_head != he_dev->irq_tail) { handled = 1; #ifdef USE_TASKLET tasklet_schedule(&he_dev->tasklet); @@ -2371,7 +2280,7 @@ (void) he_readl(he_dev, INT_FIFO); #endif } - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); return IRQ_RETVAL(handled); } @@ -2395,14 +2304,12 @@ * head for every enqueue would be unnecessarily slow) */ - if (new_tail == he_dev->tpdrq_head) - { + if (new_tail == he_dev->tpdrq_head) { he_dev->tpdrq_head = (struct he_tpdrq *) (((unsigned long)he_dev->tpdrq_base) | TPDRQ_MASK(he_readl(he_dev, TPDRQ_B_H))); - if (new_tail == he_dev->tpdrq_head) - { + if (new_tail == he_dev->tpdrq_head) { hprintk("tpdrq full (cid 0x%x)\n", cid); /* * FIXME @@ -2410,8 +2317,7 @@ * after service_tbrq, service the backlog * for now, we just drop the pdu */ - if (tpd->skb) - { + if (tpd->skb) { if (tpd->vcc->pop) tpd->vcc->pop(tpd->vcc, tpd->skb); else @@ -2456,12 +2362,12 @@ unsigned cid, rsr0, rsr1, rsr4, tsr0, tsr0_aal, tsr4, period, reg, clock; - if ((err = atm_find_ci(vcc, &vpi, &vci))) - { + if ((err = atm_find_ci(vcc, &vpi, &vci))) { HPRINTK("atm_find_ci err = %d\n", err); return err; } - if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC) return 0; + if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC) + return 0; vcc->vpi = vpi; vcc->vci = vci; @@ -2472,8 +2378,7 @@ cid = he_mkcid(he_dev, vpi, vci); he_vcc = (struct he_vcc *) kmalloc(sizeof(struct he_vcc), GFP_ATOMIC); - if (he_vcc == NULL) - { + if (he_vcc == NULL) { hprintk("unable to allocate he_vcc during open\n"); return -ENOMEM; } @@ -2487,20 +2392,18 @@ HE_VCC(vcc) = he_vcc; - if (vcc->qos.txtp.traffic_class != ATM_NONE) - { + if (vcc->qos.txtp.traffic_class != ATM_NONE) { int pcr_goal; - pcr_goal = atm_pcr_goal(&vcc->qos.txtp); - if (pcr_goal == 0) - pcr_goal = he_dev->atm_dev->link_rate; - if (pcr_goal < 0) /* means round down, technically */ - pcr_goal = -pcr_goal; + pcr_goal = atm_pcr_goal(&vcc->qos.txtp); + if (pcr_goal == 0) + pcr_goal = he_dev->atm_dev->link_rate; + if (pcr_goal < 0) /* means round down, technically */ + pcr_goal = -pcr_goal; HPRINTK("open tx cid 0x%x pcr_goal %d\n", cid, pcr_goal); - switch (vcc->qos.aal) - { + switch (vcc->qos.aal) { case ATM_AAL5: tsr0_aal = TSR0_AAL5; tsr4 = TSR4_AAL5; @@ -2514,19 +2417,17 @@ goto open_failed; } - HE_SPIN_LOCK(he_dev, flags); + spin_lock_irqsave(&he_dev->global_lock, flags); tsr0 = he_readl_tsr0(he_dev, cid); - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); - if (TSR0_CONN_STATE(tsr0) != 0) - { + if (TSR0_CONN_STATE(tsr0) != 0) { hprintk("cid 0x%x not idle (tsr0 = 0x%x)\n", cid, tsr0); err = -EBUSY; goto open_failed; } - switch(vcc->qos.txtp.traffic_class) - { + switch (vcc->qos.txtp.traffic_class) { case ATM_UBR: /* 2.3.3.1 open connection ubr */ @@ -2545,18 +2446,17 @@ goto open_failed; } - HE_SPIN_LOCK(he_dev, flags); /* also protects he_dev->cs_stper[] */ + spin_lock_irqsave(&he_dev->global_lock, flags); /* also protects he_dev->cs_stper[] */ /* find an unused cs_stper register */ - for(reg = 0; reg < HE_NUM_CS_STPER; ++reg) + for (reg = 0; reg < HE_NUM_CS_STPER; ++reg) if (he_dev->cs_stper[reg].inuse == 0 || - he_dev->cs_stper[reg].pcr == pcr_goal) - break; + he_dev->cs_stper[reg].pcr == pcr_goal) + break; - if (reg == HE_NUM_CS_STPER) - { + if (reg == HE_NUM_CS_STPER) { err = -EBUSY; - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); goto open_failed; } @@ -2574,7 +2474,7 @@ he_writel_mbox(he_dev, rate_to_atmf(period/2), CS_STPER0 + reg); - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); tsr0 = TSR0_CBR | TSR0_GROUP(0) | tsr0_aal | TSR0_RC_INDEX(reg); @@ -2585,7 +2485,7 @@ goto open_failed; } - HE_SPIN_LOCK(he_dev, flags); + spin_lock_irqsave(&he_dev->global_lock, flags); he_writel_tsr0(he_dev, tsr0, cid); he_writel_tsr4(he_dev, tsr4 | 1, cid); @@ -2607,18 +2507,16 @@ #ifdef CONFIG_IA64_SGI_SN2 (void) he_readl_tsr0(he_dev, cid); #endif - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); } - if (vcc->qos.rxtp.traffic_class != ATM_NONE) - { + if (vcc->qos.rxtp.traffic_class != ATM_NONE) { unsigned aal; HPRINTK("open rx cid 0x%x (rx_waitq %p)\n", cid, &HE_VCC(vcc)->rx_waitq); - switch (vcc->qos.aal) - { + switch (vcc->qos.aal) { case ATM_AAL5: aal = RSR0_AAL5; break; @@ -2630,12 +2528,11 @@ goto open_failed; } - HE_SPIN_LOCK(he_dev, flags); + spin_lock_irqsave(&he_dev->global_lock, flags); rsr0 = he_readl_rsr0(he_dev, cid); - if (rsr0 & RSR0_OPEN_CONN) - { - HE_SPIN_UNLOCK(he_dev, flags); + if (rsr0 & RSR0_OPEN_CONN) { + spin_unlock_irqrestore(&he_dev->global_lock, flags); hprintk("cid 0x%x not idle (rsr0 = 0x%x)\n", cid, rsr0); err = -EBUSY; @@ -2653,20 +2550,21 @@ (RSR0_EPD_ENABLE|RSR0_PPD_ENABLE) : 0; #ifdef USE_CHECKSUM_HW - if (vpi == 0 && vci >= ATM_NOT_RSV_VCI) rsr0 |= RSR0_TCP_CKSUM; + if (vpi == 0 && vci >= ATM_NOT_RSV_VCI) + rsr0 |= RSR0_TCP_CKSUM; #endif he_writel_rsr4(he_dev, rsr4, cid); he_writel_rsr1(he_dev, rsr1, cid); /* 5.1.11 last parameter initialized should be - the open/closed indication in rsr0 */ + the open/closed indication in rsr0 */ he_writel_rsr0(he_dev, rsr0 | RSR0_START_PDU | RSR0_OPEN_CONN | aal, cid); #ifdef CONFIG_IA64_SGI_SN2 (void) he_readl_rsr0(he_dev, cid); #endif - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); #ifndef USE_HE_FIND_VCC HE_LOOKUP_VCC(he_dev, cid) = vcc; @@ -2675,9 +2573,9 @@ open_failed: - if (err) - { - if (he_vcc) kfree(he_vcc); + if (err) { + if (he_vcc) + kfree(he_vcc); clear_bit(ATM_VF_ADDR, &vcc->flags); } else @@ -2703,8 +2601,7 @@ clear_bit(ATM_VF_READY, &vcc->flags); cid = he_mkcid(he_dev, vcc->vpi, vcc->vci); - if (vcc->qos.rxtp.traffic_class != ATM_NONE) - { + if (vcc->qos.rxtp.traffic_class != ATM_NONE) { int timeout; HPRINTK("close rx cid 0x%x\n", cid); @@ -2713,9 +2610,8 @@ /* wait for previous close (if any) to finish */ - HE_SPIN_LOCK(he_dev, flags); - while(he_readl(he_dev, RCC_STAT) & RCC_BUSY) - { + spin_lock_irqsave(&he_dev->global_lock, flags); + while (he_readl(he_dev, RCC_STAT) & RCC_BUSY) { HPRINTK("close cid 0x%x RCC_BUSY\n", cid); udelay(250); } @@ -2728,7 +2624,7 @@ (void) he_readl_rsr0(he_dev, cid); #endif he_writel_mbox(he_dev, cid, RXCON_CLOSE); - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); timeout = schedule_timeout(30*HZ); @@ -2745,8 +2641,7 @@ } - if (vcc->qos.txtp.traffic_class != ATM_NONE) - { + if (vcc->qos.txtp.traffic_class != ATM_NONE) { volatile unsigned tsr4, tsr0; int timeout; @@ -2761,31 +2656,30 @@ * TBRQ, the host issues the close command to the adapter. */ - while (((tx_inuse = atomic_read(&vcc->sk->wmem_alloc)) > 0) - && (retry < MAX_RETRY)) - { + while (((tx_inuse = atomic_read(&vcc->sk->sk_wmem_alloc)) > 0) && + (retry < MAX_RETRY)) { set_current_state(TASK_UNINTERRUPTIBLE); (void) schedule_timeout(sleep); set_current_state(TASK_RUNNING); - if (sleep < HZ) sleep = sleep * 2; + if (sleep < HZ) + sleep = sleep * 2; ++retry; } - if (tx_inuse) hprintk("close tx cid 0x%x tx_inuse = %d\n", - cid, tx_inuse); + if (tx_inuse) + hprintk("close tx cid 0x%x tx_inuse = %d\n", cid, tx_inuse); /* 2.3.1.1 generic close operations with flush */ - HE_SPIN_LOCK(he_dev, flags); + spin_lock_irqsave(&he_dev->global_lock, flags); he_writel_tsr4_upper(he_dev, TSR4_FLUSH_CONN, cid); /* also clears TSR4_SESSION_ENDED */ #ifdef CONFIG_IA64_SGI_SN2 (void) he_readl_tsr4(he_dev, cid); #endif - switch(vcc->qos.txtp.traffic_class) - { + switch (vcc->qos.txtp.traffic_class) { case ATM_UBR: he_writel_tsr1(he_dev, TSR1_MCR(rate_to_atmf(200000)) @@ -2796,10 +2690,8 @@ break; } - tpd = __alloc_tpd(he_dev); - if (tpd == NULL) - { + if (tpd == NULL) { hprintk("close tx he_alloc_tpd failed cid 0x%x\n", cid); goto close_tx_incomplete; } @@ -2811,37 +2703,32 @@ add_wait_queue(&he_vcc->tx_waitq, &wait); set_current_state(TASK_UNINTERRUPTIBLE); __enqueue_tpd(he_dev, tpd, cid); - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); timeout = schedule_timeout(30*HZ); remove_wait_queue(&he_vcc->tx_waitq, &wait); set_current_state(TASK_RUNNING); - if (timeout == 0) - { + if (timeout == 0) { hprintk("close tx timeout cid 0x%x\n", cid); goto close_tx_incomplete; } - HE_SPIN_LOCK(he_dev, flags); - while (!((tsr4 = he_readl_tsr4(he_dev, cid)) - & TSR4_SESSION_ENDED)) - { + spin_lock_irqsave(&he_dev->global_lock, flags); + while (!((tsr4 = he_readl_tsr4(he_dev, cid)) & TSR4_SESSION_ENDED)) { HPRINTK("close tx cid 0x%x !TSR4_SESSION_ENDED (tsr4 = 0x%x)\n", cid, tsr4); udelay(250); } - while (TSR0_CONN_STATE(tsr0 = he_readl_tsr0(he_dev, cid)) != 0) - { + while (TSR0_CONN_STATE(tsr0 = he_readl_tsr0(he_dev, cid)) != 0) { HPRINTK("close tx cid 0x%x TSR0_CONN_STATE != 0 (tsr0 = 0x%x)\n", cid, tsr0); udelay(250); } close_tx_incomplete: - if (vcc->qos.txtp.traffic_class == ATM_CBR) - { + if (vcc->qos.txtp.traffic_class == ATM_CBR) { int reg = he_vcc->rc_index; HPRINTK("cs_stper reg = %d\n", reg); @@ -2853,7 +2740,7 @@ he_dev->total_bw -= he_dev->cs_stper[reg].pcr; } - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); HPRINTK("close tx cid 0x%x complete\n", cid); } @@ -2889,8 +2776,7 @@ HPRINTK("send %d.%d\n", vcc->vpi, vcc->vci); if ((skb->len > HE_TPD_BUFSIZE) || - ((vcc->qos.aal == ATM_AAL0) && (skb->len != ATM_AAL0_SDU))) - { + ((vcc->qos.aal == ATM_AAL0) && (skb->len != ATM_AAL0_SDU))) { hprintk("buffer too large (or small) -- %d bytes\n", skb->len ); if (vcc->pop) vcc->pop(vcc, skb); @@ -2901,8 +2787,7 @@ } #ifndef USE_SCATTERGATHER - if (skb_shinfo(skb)->nr_frags) - { + if (skb_shinfo(skb)->nr_frags) { hprintk("no scatter/gather support\n"); if (vcc->pop) vcc->pop(vcc, skb); @@ -2912,31 +2797,30 @@ return -EINVAL; } #endif - HE_SPIN_LOCK(he_dev, flags); + spin_lock_irqsave(&he_dev->global_lock, flags); tpd = __alloc_tpd(he_dev); - if (tpd == NULL) - { + if (tpd == NULL) { if (vcc->pop) vcc->pop(vcc, skb); else dev_kfree_skb_any(skb); atomic_inc(&vcc->stats->tx_err); - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); return -ENOMEM; } if (vcc->qos.aal == ATM_AAL5) tpd->status |= TPD_CELLTYPE(TPD_USERCELL); - else - { + else { char *pti_clp = (void *) (skb->data + 3); int clp, pti; pti = (*pti_clp & ATM_HDR_PTI_MASK) >> ATM_HDR_PTI_SHIFT; clp = (*pti_clp & ATM_HDR_CLP); tpd->status |= TPD_CELLTYPE(pti); - if (clp) tpd->status |= TPD_CLP; + if (clp) + tpd->status |= TPD_CLP; skb_pull(skb, ATM_AAL0_SDU - ATM_CELL_PAYLOAD); } @@ -2947,12 +2831,10 @@ tpd->iovec[slot].len = skb->len - skb->data_len; ++slot; - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) - { + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; - if (slot == TPD_MAXIOV) /* send tpd; start new tpd */ - { + if (slot == TPD_MAXIOV) { /* queue tpd; start new tpd */ tpd->vcc = vcc; tpd->skb = NULL; /* not the last fragment so dont ->push() yet */ @@ -2960,14 +2842,13 @@ __enqueue_tpd(he_dev, tpd, cid); tpd = __alloc_tpd(he_dev); - if (tpd == NULL) - { + if (tpd == NULL) { if (vcc->pop) vcc->pop(vcc, skb); else dev_kfree_skb_any(skb); atomic_inc(&vcc->stats->tx_err); - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); return -ENOMEM; } tpd->status |= TPD_USERCELL; @@ -2982,7 +2863,7 @@ } - tpd->iovec[slot-1].len |= TPD_LST; + tpd->iovec[slot - 1].len |= TPD_LST; #else tpd->address0 = pci_map_single(he_dev->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE); tpd->length0 = skb->len | TPD_LST; @@ -2995,7 +2876,7 @@ ATM_SKB(skb)->vcc = vcc; __enqueue_tpd(he_dev, tpd, cid); - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); atomic_inc(&vcc->stats->tx); @@ -3010,16 +2891,15 @@ struct he_ioctl_reg reg; int err = 0; - switch (cmd) - { + switch (cmd) { case HE_GET_REG: - if (!capable(CAP_NET_ADMIN)) return -EPERM; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; copy_from_user(®, (struct he_ioctl_reg *) arg, sizeof(struct he_ioctl_reg)); - HE_SPIN_LOCK(he_dev, flags); - switch (reg.type) - { + spin_lock_irqsave(&he_dev->global_lock, flags); + switch (reg.type) { case HE_REGTYPE_PCI: reg.val = he_readl(he_dev, reg.addr); break; @@ -3039,8 +2919,9 @@ err = -EINVAL; break; } - HE_SPIN_UNLOCK(he_dev, flags); - if (err == 0) copy_to_user((struct he_ioctl_reg *) arg, ®, + spin_unlock_irqrestore(&he_dev->global_lock, flags); + if (err == 0) + copy_to_user((struct he_ioctl_reg *) arg, ®, sizeof(struct he_ioctl_reg)); break; default: @@ -3048,7 +2929,7 @@ if (atm_dev->phy && atm_dev->phy->ioctl) err = atm_dev->phy->ioctl(atm_dev, cmd, arg); #else /* CONFIG_ATM_HE_USE_SUNI */ - return -EINVAL; + err = -EINVAL; #endif /* CONFIG_ATM_HE_USE_SUNI */ break; } @@ -3064,15 +2945,15 @@ HPRINTK("phy_put(val 0x%x, addr 0x%lx)\n", val, addr); - HE_SPIN_LOCK(he_dev, flags); - he_writel(he_dev, val, FRAMER + (addr*4)); + spin_lock_irqsave(&he_dev->global_lock, flags); + he_writel(he_dev, val, FRAMER + (addr*4)); #ifdef CONFIG_IA64_SGI_SN2 (void) he_readl(he_dev, FRAMER + (addr*4)); #endif - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); } - + static unsigned char he_phy_get(struct atm_dev *atm_dev, unsigned long addr) { @@ -3080,9 +2961,9 @@ struct he_dev *he_dev = HE_DEV(atm_dev); unsigned reg; - HE_SPIN_LOCK(he_dev, flags); - reg = he_readl(he_dev, FRAMER + (addr*4)); - HE_SPIN_UNLOCK(he_dev, flags); + spin_lock_irqsave(&he_dev->global_lock, flags); + reg = he_readl(he_dev, FRAMER + (addr*4)); + spin_unlock_irqrestore(&he_dev->global_lock, flags); HPRINTK("phy_get(addr 0x%lx) =0x%x\n", addr, reg); return reg; @@ -3097,7 +2978,7 @@ #ifdef notdef struct he_rbrq *rbrq_tail; struct he_tpdrq *tpdrq_head; - int rbpl_head, rbpl_tail; + int rbpl_head, rbpl_tail; #endif static long mcc = 0, oec = 0, dcc = 0, cec = 0; @@ -3113,12 +2994,12 @@ if (!left--) return sprintf(page, "Mismatched Cells VPI/VCI Not Open Dropped Cells RCM Dropped Cells\n"); - HE_SPIN_LOCK(he_dev, flags); + spin_lock_irqsave(&he_dev->global_lock, flags); mcc += he_readl(he_dev, MCC); oec += he_readl(he_dev, OEC); dcc += he_readl(he_dev, DCC); cec += he_readl(he_dev, CEC); - HE_SPIN_UNLOCK(he_dev, flags); + spin_unlock_irqrestore(&he_dev->global_lock, flags); if (!left--) return sprintf(page, "%16ld %16ld %13ld %17ld\n\n", @@ -3142,11 +3023,12 @@ #ifdef notdef - rbpl_head = RBPL_MASK(he_readl(he_dev, G0_RBPL_S)); - rbpl_tail = RBPL_MASK(he_readl(he_dev, G0_RBPL_T)); + rbpl_head = RBPL_MASK(he_readl(he_dev, G0_RBPL_S)); + rbpl_tail = RBPL_MASK(he_readl(he_dev, G0_RBPL_T)); inuse = rbpl_head - rbpl_tail; - if (inuse < 0) inuse += CONFIG_RBPL_SIZE * sizeof(struct he_rbp); + if (inuse < 0) + inuse += CONFIG_RBPL_SIZE * sizeof(struct he_rbp); inuse /= sizeof(struct he_rbp); if (!left--) @@ -3187,32 +3069,31 @@ he_writel(he_dev, val, HOST_CNTL); /* Send READ instruction */ - for (i=0; i<sizeof(readtab)/sizeof(readtab[0]); i++) { + for (i = 0; i < sizeof(readtab)/sizeof(readtab[0]); i++) { he_writel(he_dev, val | readtab[i], HOST_CNTL); udelay(EEPROM_DELAY); } - /* Next, we need to send the byte address to read from */ - for (i=7; i>=0; i--) { + /* Next, we need to send the byte address to read from */ + for (i = 7; i >= 0; i--) { he_writel(he_dev, val | clocktab[j++] | (((addr >> i) & 1) << 9), HOST_CNTL); udelay(EEPROM_DELAY); he_writel(he_dev, val | clocktab[j++] | (((addr >> i) & 1) << 9), HOST_CNTL); udelay(EEPROM_DELAY); } - j=0; + j = 0; val &= 0xFFFFF7FF; /* Turn off write enable */ he_writel(he_dev, val, HOST_CNTL); /* Now, we can read data from the EEPROM by clocking it in */ - for (i=7; i>=0; i--) { + for (i = 7; i >= 0; i--) { he_writel(he_dev, val | clocktab[j++], HOST_CNTL); - udelay(EEPROM_DELAY); - tmp_read = he_readl(he_dev, HOST_CNTL); - byte_read |= (unsigned char) - ((tmp_read & ID_DOUT) - >> ID_DOFFSET << i); + udelay(EEPROM_DELAY); + tmp_read = he_readl(he_dev, HOST_CNTL); + byte_read |= (unsigned char) + ((tmp_read & ID_DOUT) >> ID_DOFFSET << i); he_writel(he_dev, val | clocktab[j++], HOST_CNTL); udelay(EEPROM_DELAY); } @@ -3220,7 +3101,7 @@ he_writel(he_dev, val | ID_CS, HOST_CNTL); udelay(EEPROM_DELAY); - return (byte_read); + return byte_read; } MODULE_LICENSE("GPL"); @@ -3242,7 +3123,7 @@ static struct pci_device_id he_pci_tbl[] __devinitdata = { { PCI_VENDOR_ID_FORE, PCI_DEVICE_ID_FORE_HE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, - { 0, } + { 0, } }; static struct pci_driver he_driver = { @@ -3254,12 +3135,12 @@ static int __init he_init(void) { - return pci_module_init(&he_driver); + return pci_module_init(&he_driver); } static void __exit he_cleanup(void) { - pci_unregister_driver(&he_driver); + pci_unregister_driver(&he_driver); } module_init(he_init); diff -Nru a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c --- a/drivers/atm/idt77252.c Mon Jun 9 23:16:12 2003 +++ b/drivers/atm/idt77252.c Mon Jun 9 23:16:12 2003 @@ -728,7 +728,8 @@ struct atm_vcc *vcc = vc->tx_vcc; vc->estimator->cells += (skb->len + 47) / 48; - if (atomic_read(&vcc->sk->wmem_alloc) > (vcc->sk->sndbuf >> 1)) { + if (atomic_read(&vcc->sk->sk_wmem_alloc) > + (vcc->sk->sk_sndbuf >> 1)) { u32 cps = vc->estimator->maxcps; vc->estimator->cps = cps; @@ -2023,7 +2024,7 @@ atomic_inc(&vcc->stats->tx_err); return -ENOMEM; } - atomic_add(skb->truesize, &vcc->sk->wmem_alloc); + atomic_add(skb->truesize, &vcc->sk->sk_wmem_alloc); memcpy(skb_put(skb, 52), cell, 52); diff -Nru a/drivers/atm/iphase.c b/drivers/atm/iphase.c --- a/drivers/atm/iphase.c Mon Jun 9 23:16:19 2003 +++ b/drivers/atm/iphase.c Mon Jun 9 23:16:19 2003 @@ -1782,14 +1782,14 @@ if (ia_vcc->pcr < iadev->rate_limit) { if (vcc->qos.txtp.max_sdu != 0) { if (ia_vcc->pcr > 60000) - vcc->sk->sndbuf = vcc->qos.txtp.max_sdu * 5; + vcc->sk->sk_sndbuf = vcc->qos.txtp.max_sdu * 5; else if (ia_vcc->pcr > 2000) - vcc->sk->sndbuf = vcc->qos.txtp.max_sdu * 4; + vcc->sk->sk_sndbuf = vcc->qos.txtp.max_sdu * 4; else - vcc->sk->sndbuf = 3*vcc->qos.txtp.max_sdu; + vcc->sk->sk_sndbuf = vcc->qos.txtp.max_sdu * 3; } else - vcc->sk->sndbuf = 24576; + vcc->sk->sk_sndbuf = 24576; } vc = (struct main_vc *)iadev->MAIN_VC_TABLE_ADDR; diff -Nru a/drivers/base/base.h b/drivers/base/base.h --- a/drivers/base/base.h Mon Jun 9 23:16:10 2003 +++ b/drivers/base/base.h Mon Jun 9 23:16:10 2003 @@ -4,3 +4,12 @@ extern int bus_add_driver(struct device_driver *); extern void bus_remove_driver(struct device_driver *); +static inline struct class_device *to_class_dev(struct kobject *obj) +{ + return container_of(obj,struct class_device,kobj); +} +static inline +struct class_device_attribute *to_class_dev_attr(struct attribute *_attr) +{ + return container_of(_attr,struct class_device_attribute,attr); +} diff -Nru a/drivers/base/bus.c b/drivers/base/bus.c --- a/drivers/base/bus.c Mon Jun 9 23:16:08 2003 +++ b/drivers/base/bus.c Mon Jun 9 23:16:08 2003 @@ -1,10 +1,11 @@ /* * bus.c - bus driver management + * + * Copyright (c) 2002-3 Patrick Mochel + * Copyright (c) 2002-3 Open Source Development Labs * - * Copyright (c) 2002 Patrick Mochel - * 2002 Open Source Development Lab - * - * + * This file is released under the GPLv2 + * */ #undef DEBUG diff -Nru a/drivers/base/class.c b/drivers/base/class.c --- a/drivers/base/class.c Mon Jun 9 23:16:19 2003 +++ b/drivers/base/class.c Mon Jun 9 23:16:19 2003 @@ -1,7 +1,11 @@ /* * class.c - basic device class management + * + * Copyright (c) 2002-3 Patrick Mochel + * Copyright (c) 2002-3 Open Source Development Labs * - * Copyright (c) 2001-2003 Patrick Mochel <mochel@osdl.org> + * This file is released under the GPLv2 + * */ #undef DEBUG @@ -148,9 +152,6 @@ } -#define to_class_dev(obj) container_of(obj,struct class_device,kobj) -#define to_class_dev_attr(_attr) container_of(_attr,struct class_device_attribute,attr) - static ssize_t class_device_attr_show(struct kobject * kobj, struct attribute * attr, char * buf) @@ -182,8 +183,20 @@ .store = class_device_attr_store, }; +static void class_dev_release(struct kobject * kobj) +{ + struct class_device *cd = to_class_dev(kobj); + struct class * cls = cd->class; + + pr_debug("device class '%s': release.\n",cd->class_id); + + if (cls->release) + cls->release(cd); +} + static struct kobj_type ktype_class_device = { .sysfs_ops = &class_dev_sysfs_ops, + .release = class_dev_release, }; static int class_hotplug_filter(struct kset *kset, struct kobject *kobj) @@ -311,11 +324,8 @@ up_write(&parent->subsys.rwsem); } - if (class_dev->dev) { - class_device_dev_unlink(class_dev); - class_device_driver_unlink(class_dev); - put_device(class_dev->dev); - } + class_device_dev_unlink(class_dev); + class_device_driver_unlink(class_dev); kobject_del(&class_dev->kobj); diff -Nru a/drivers/base/core.c b/drivers/base/core.c --- a/drivers/base/core.c Mon Jun 9 23:16:06 2003 +++ b/drivers/base/core.c Mon Jun 9 23:16:06 2003 @@ -1,8 +1,11 @@ /* * drivers/base/core.c - core driver model code (device registration, etc) + * + * Copyright (c) 2002-3 Patrick Mochel + * Copyright (c) 2002-3 Open Source Development Labs * - * Copyright (c) 2002 Patrick Mochel - * 2002 Open Source Development Lab + * This file is released under the GPLv2 + * */ #undef DEBUG @@ -340,10 +343,39 @@ put_device(dev); } +/** + * device_for_each_child - device child iterator. + * @dev: parent struct device. + * @data: data for the callback. + * @fn: function to be called for each device. + * + * Iterate over @dev's child devices, and call @fn for each, + * passing it @data. + * + * We check the return of @fn each time. If it returns anything + * other than 0, we break out and return that value. + */ +int device_for_each_child(struct device * dev, void * data, + int (*fn)(struct device *, void *)) +{ + struct device * child; + int error = 0; + + down_read(&devices_subsys.rwsem); + list_for_each_entry(child,&dev->children,node) { + if((error = fn(child,data))) + break; + } + up_read(&devices_subsys.rwsem); + return error; +} + int __init devices_init(void) { return subsystem_register(&devices_subsys); } + +EXPORT_SYMBOL(device_for_each_child); EXPORT_SYMBOL(device_initialize); EXPORT_SYMBOL(device_add); diff -Nru a/drivers/base/cpu.c b/drivers/base/cpu.c --- a/drivers/base/cpu.c Mon Jun 9 23:16:09 2003 +++ b/drivers/base/cpu.c Mon Jun 9 23:16:09 2003 @@ -6,8 +6,7 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/cpu.h> - -#include <asm/topology.h> +#include <linux/topology.h> struct class cpu_class = { @@ -46,7 +45,7 @@ snprintf(cpu->sysdev.class_dev.class_id, BUS_ID_SIZE, "cpu%d", num); retval = class_device_register(&cpu->sysdev.class_dev); if (retval) { - // FIXME cleanup sys_device_register + sys_device_unregister(&cpu->sysdev); return retval; } return 0; @@ -58,10 +57,12 @@ int error; error = class_register(&cpu_class); - if (!error) { - error = driver_register(&cpu_driver); - if (error) - class_unregister(&cpu_class); - } + if (error) + goto out; + + error = driver_register(&cpu_driver); + if (error) + class_unregister(&cpu_class); +out: return error; } diff -Nru a/drivers/base/driver.c b/drivers/base/driver.c --- a/drivers/base/driver.c Mon Jun 9 23:16:18 2003 +++ b/drivers/base/driver.c Mon Jun 9 23:16:18 2003 @@ -1,6 +1,11 @@ /* * driver.c - centralized device driver management * + * Copyright (c) 2002-3 Patrick Mochel + * Copyright (c) 2002-3 Open Source Development Labs + * + * This file is released under the GPLv2 + * */ #undef DEBUG diff -Nru a/drivers/base/firmware.c b/drivers/base/firmware.c --- a/drivers/base/firmware.c Mon Jun 9 23:16:13 2003 +++ b/drivers/base/firmware.c Mon Jun 9 23:16:13 2003 @@ -1,5 +1,11 @@ /* * firmware.c - firmware subsystem hoohaw. + * + * Copyright (c) 2002-3 Patrick Mochel + * Copyright (c) 2002-3 Open Source Development Labs + * + * This file is released under the GPLv2 + * */ #include <linux/kobject.h> diff -Nru a/drivers/base/init.c b/drivers/base/init.c --- a/drivers/base/init.c Mon Jun 9 23:16:06 2003 +++ b/drivers/base/init.c Mon Jun 9 23:16:06 2003 @@ -1,3 +1,11 @@ +/* + * + * Copyright (c) 2002-3 Patrick Mochel + * Copyright (c) 2002-3 Open Source Development Labs + * + * This file is released under the GPLv2 + * + */ #include <linux/device.h> #include <linux/init.h> diff -Nru a/drivers/base/interface.c b/drivers/base/interface.c --- a/drivers/base/interface.c Mon Jun 9 23:16:07 2003 +++ b/drivers/base/interface.c Mon Jun 9 23:16:07 2003 @@ -1,8 +1,12 @@ /* * drivers/base/interface.c - common driverfs interface that's exported to * the world for all devices. - * Copyright (c) 2002 Patrick Mochel - * 2002 Open Source Development Lab + * + * Copyright (c) 2002-3 Patrick Mochel + * Copyright (c) 2002-3 Open Source Development Labs + * + * This file is released under the GPLv2 + * */ #include <linux/device.h> diff -Nru a/drivers/base/memblk.c b/drivers/base/memblk.c --- a/drivers/base/memblk.c Mon Jun 9 23:16:19 2003 +++ b/drivers/base/memblk.c Mon Jun 9 23:16:19 2003 @@ -7,8 +7,7 @@ #include <linux/init.h> #include <linux/memblk.h> #include <linux/node.h> - -#include <asm/topology.h> +#include <linux/topology.h> static struct class memblk_class = { diff -Nru a/drivers/base/node.c b/drivers/base/node.c --- a/drivers/base/node.c Mon Jun 9 23:16:08 2003 +++ b/drivers/base/node.c Mon Jun 9 23:16:08 2003 @@ -7,8 +7,7 @@ #include <linux/init.h> #include <linux/mm.h> #include <linux/node.h> - -#include <asm/topology.h> +#include <linux/topology.h> static struct class node_class = { diff -Nru a/drivers/base/platform.c b/drivers/base/platform.c --- a/drivers/base/platform.c Mon Jun 9 23:16:07 2003 +++ b/drivers/base/platform.c Mon Jun 9 23:16:07 2003 @@ -1,6 +1,11 @@ /* * platform.c - platform 'psuedo' bus for legacy devices * + * Copyright (c) 2002-3 Patrick Mochel + * Copyright (c) 2002-3 Open Source Development Labs + * + * This file is released under the GPLv2 + * * Please see Documentation/driver-model/platform.txt for more * information. */ diff -Nru a/drivers/base/power.c b/drivers/base/power.c --- a/drivers/base/power.c Mon Jun 9 23:16:15 2003 +++ b/drivers/base/power.c Mon Jun 9 23:16:15 2003 @@ -1,14 +1,16 @@ /* * power.c - power management functions for the device tree. * - * Copyright (c) 2002 Patrick Mochel - * 2002 Open Source Development Lab + * Copyright (c) 2002-3 Patrick Mochel + * 2002-3 Open Source Development Lab + * + * This file is released under the GPLv2 * * Kai Germaschewski contributed to the list walking routines. * */ -#undef DEBUG +#define DEBUG #include <linux/device.h> #include <linux/module.h> @@ -88,10 +90,12 @@ down_write(&devices_subsys.rwsem); list_for_each(entry,&devices_subsys.kset.list) { struct device * dev = to_dev(entry); + pr_debug("shutting down %s: ",dev->name); if (dev->driver && dev->driver->shutdown) { - pr_debug("shutting down %s\n",dev->name); + pr_debug("Ok\n"); dev->driver->shutdown(dev); - } + } else + pr_debug("Ignored.\n"); } up_write(&devices_subsys.rwsem); } diff -Nru a/drivers/base/sys.c b/drivers/base/sys.c --- a/drivers/base/sys.c Mon Jun 9 23:16:05 2003 +++ b/drivers/base/sys.c Mon Jun 9 23:16:05 2003 @@ -1,8 +1,10 @@ /* * sys.c - pseudo-bus for system 'devices' (cpus, PICs, timers, etc) * - * Copyright (c) 2002 Patrick Mochel - * 2002 Open Source Development Lab + * Copyright (c) 2002-3 Patrick Mochel + * 2002-3 Open Source Development Lab + * + * This file is released under the GPLv2 * * This exports a 'system' bus type. * By default, a 'sys' bus gets added to the root of the system. There will diff -Nru a/drivers/block/DAC960.c b/drivers/block/DAC960.c --- a/drivers/block/DAC960.c Mon Jun 9 23:16:16 2003 +++ b/drivers/block/DAC960.c Mon Jun 9 23:16:16 2003 @@ -2309,8 +2309,7 @@ (PhysicalDeviceInfo->NegotiatedDataWidthBits == 16 ? "Wide " :""), (PhysicalDeviceInfo->NegotiatedSynchronousMegaTransfers - * (PhysicalDeviceInfo->NegotiatedDataWidthBits == 16 - ? 2 : 1))); + * PhysicalDeviceInfo->NegotiatedDataWidthBits/8)); if (InquiryUnitSerialNumber->PeripheralDeviceType != 0x1F) DAC960_Info(" Serial Number: %s\n", Controller, SerialNumber); if (PhysicalDeviceInfo->PhysicalDeviceState == diff -Nru a/drivers/block/acsi.c b/drivers/block/acsi.c --- a/drivers/block/acsi.c Mon Jun 9 23:16:19 2003 +++ b/drivers/block/acsi.c Mon Jun 9 23:16:19 2003 @@ -1728,10 +1728,8 @@ sprintf(disk->disk_name, "ad%c", 'a'+i); disk->major = ACSI_MAJOR; disk->first_minor = i << 4; - if (acsi_info[i].type != HARDDISK) { - disk->minor_shift = 0; + if (acsi_info[i].type != HARDDISK) disk->minors = 1; - } disk->fops = &acsi_fops; disk->private_data = &acsi_info[i]; set_capacity(disk, acsi_info[i].size); diff -Nru a/drivers/block/cciss.c b/drivers/block/cciss.c --- a/drivers/block/cciss.c Mon Jun 9 23:16:19 2003 +++ b/drivers/block/cciss.c Mon Jun 9 23:16:19 2003 @@ -1961,7 +1961,7 @@ goto queue; startio: - __blk_stop_queue(q); + blk_stop_queue(q); start_io(h); } @@ -2021,8 +2021,8 @@ /* * See if we can queue up some more IO */ - spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); blk_start_queue(&h->queue); + spin_unlock_irqrestore(CCISS_LOCK(h->ctlr), flags); return IRQ_HANDLED; } /* diff -Nru a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c --- a/drivers/block/cciss_scsi.c Mon Jun 9 23:16:08 2003 +++ b/drivers/block/cciss_scsi.c Mon Jun 9 23:16:08 2003 @@ -54,11 +54,11 @@ const char *cciss_scsi_info(struct Scsi_Host *sa); int cciss_scsi_proc_info( + struct Scsi_Host *sh, char *buffer, /* data buffer */ char **start, /* where data in buffer starts */ off_t offset, /* offset from start of imaginary file */ int length, /* length of data in buffer */ - int hostnum, /* which host adapter (always zero for me) */ int func); /* 0 == read, 1 == write */ int cciss_scsi_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)); @@ -1121,24 +1121,19 @@ int -cciss_scsi_proc_info(char *buffer, /* data buffer */ +cciss_scsi_proc_info(struct Scsi_Host *sh, + char *buffer, /* data buffer */ char **start, /* where data in buffer starts */ off_t offset, /* offset from start of imaginary file */ int length, /* length of data in buffer */ - int hostnum, /* which host adapter (always zero for me) */ int func) /* 0 == read, 1 == write */ { int buflen, datalen; - struct Scsi_Host *sh; ctlr_info_t *ci; int cntl_num; - sh = scsi_host_hn_get(hostnum); - if (sh == NULL) /* This really shouldn't ever happen. */ - return -EINVAL; - ci = (ctlr_info_t *) sh->hostdata[0]; if (ci == NULL) /* This really shouldn't ever happen. */ return -EINVAL; @@ -1146,7 +1141,7 @@ cntl_num = ci->ctlr; /* Get our index into the hba[] array */ if (func == 0) { /* User is reading from /proc/scsi/ciss*?/?* */ - buflen = sprintf(buffer, "hostnum=%d\n", hostnum); + buflen = sprintf(buffer, "hostnum=%d\n", sh->host_no); datalen = buflen - offset; if (datalen < 0) { /* they're reading past EOF. */ @@ -1156,7 +1151,7 @@ *start = buffer + offset; return(datalen); } else /* User is writing to /proc/scsi/cciss*?/?* ... */ - return cciss_scsi_user_command(cntl_num, hostnum, + return cciss_scsi_user_command(cntl_num, sh->host_no, buffer, length); } diff -Nru a/drivers/block/deadline-iosched.c b/drivers/block/deadline-iosched.c --- a/drivers/block/deadline-iosched.c Mon Jun 9 23:16:17 2003 +++ b/drivers/block/deadline-iosched.c Mon Jun 9 23:16:17 2003 @@ -121,6 +121,15 @@ __deadline_del_drq_hash(drq); } +static void +deadline_remove_merge_hints(request_queue_t *q, struct deadline_rq *drq) +{ + deadline_del_drq_hash(drq); + + if (q->last_merge == &drq->request->queuelist) + q->last_merge = NULL; +} + static inline void deadline_add_drq_hash(struct deadline_data *dd, struct deadline_rq *drq) { @@ -310,7 +319,7 @@ struct deadline_data *dd = q->elevator.elevator_data; list_del_init(&drq->fifo); - deadline_del_drq_hash(drq); + deadline_remove_merge_hints(q, drq); deadline_del_drq_rb(dd, drq); } } diff -Nru a/drivers/block/genhd.c b/drivers/block/genhd.c --- a/drivers/block/genhd.c Mon Jun 9 23:16:11 2003 +++ b/drivers/block/genhd.c Mon Jun 9 23:16:11 2003 @@ -538,8 +538,6 @@ memset(disk->part, 0, size); } disk->minors = minors; - while (minors >>= 1) - disk->minor_shift++; kobj_set_kset_s(disk,block_subsys); kobject_init(&disk->kobj); rand_initialize_disk(disk); diff -Nru a/drivers/block/ioctl.c b/drivers/block/ioctl.c --- a/drivers/block/ioctl.c Mon Jun 9 23:16:06 2003 +++ b/drivers/block/ioctl.c Mon Jun 9 23:16:06 2003 @@ -207,11 +207,8 @@ set_device_ro(bdev, n); return 0; default: - if (disk->fops->ioctl) { - ret = disk->fops->ioctl(inode, file, cmd, arg); - if (ret != -EINVAL) - return ret; - } + if (disk->fops->ioctl) + return disk->fops->ioctl(inode, file, cmd, arg); } return -ENOTTY; } diff -Nru a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c --- a/drivers/block/ll_rw_blk.c Mon Jun 9 23:16:07 2003 +++ b/drivers/block/ll_rw_blk.c Mon Jun 9 23:16:07 2003 @@ -391,12 +391,6 @@ q->dma_alignment = mask; } -void blk_queue_assign_lock(request_queue_t *q, spinlock_t *lock) -{ - spin_lock_init(lock); - q->queue_lock = lock; -} - /** * blk_queue_find_tag - find a request by its tag and queue * @@ -413,11 +407,12 @@ { struct blk_queue_tag *bqt = q->queue_tags; - if (unlikely(bqt == NULL || bqt->max_depth < tag)) + if (unlikely(bqt == NULL || tag >= bqt->real_max_depth)) return NULL; return bqt->tag_index[tag]; } + /** * blk_queue_free_tags - release tag maintenance info * @q: the request queue for the device @@ -448,39 +443,28 @@ q->queue_flags &= ~(1 << QUEUE_FLAG_QUEUED); } -/** - * blk_queue_init_tags - initialize the queue tag info - * @q: the request queue for the device - * @depth: the maximum queue depth supported - **/ -int blk_queue_init_tags(request_queue_t *q, int depth) +static int init_tag_map(struct blk_queue_tag *tags, int depth) { - struct blk_queue_tag *tags; int bits, i; if (depth > (queue_nr_requests*2)) { depth = (queue_nr_requests*2); - printk("blk_queue_init_tags: adjusted depth to %d\n", depth); + printk(KERN_ERR "%s: adjusted depth to %d\n", __FUNCTION__, depth); } - tags = kmalloc(sizeof(struct blk_queue_tag),GFP_ATOMIC); - if (!tags) - goto fail; - tags->tag_index = kmalloc(depth * sizeof(struct request *), GFP_ATOMIC); if (!tags->tag_index) - goto fail_index; + goto fail; bits = (depth / BLK_TAGS_PER_LONG) + 1; tags->tag_map = kmalloc(bits * sizeof(unsigned long), GFP_ATOMIC); if (!tags->tag_map) - goto fail_map; + goto fail; memset(tags->tag_index, 0, depth * sizeof(struct request *)); memset(tags->tag_map, 0, bits * sizeof(unsigned long)); - INIT_LIST_HEAD(&tags->busy_list); - tags->busy = 0; tags->max_depth = depth; + tags->real_max_depth = bits * BITS_PER_LONG; /* * set the upper bits if the depth isn't a multiple of the word size @@ -488,22 +472,89 @@ for (i = depth; i < bits * BLK_TAGS_PER_LONG; i++) __set_bit(i, tags->tag_map); + return 0; +fail: + kfree(tags->tag_index); + return -ENOMEM; +} + + +/** + * blk_queue_init_tags - initialize the queue tag info + * @q: the request queue for the device + * @depth: the maximum queue depth supported + **/ +int blk_queue_init_tags(request_queue_t *q, int depth) +{ + struct blk_queue_tag *tags; + + tags = kmalloc(sizeof(struct blk_queue_tag),GFP_ATOMIC); + if (!tags) + goto fail; + + if (init_tag_map(tags, depth)) + goto fail; + + INIT_LIST_HEAD(&tags->busy_list); + tags->busy = 0; + /* * assign it, all done */ q->queue_tags = tags; q->queue_flags |= (1 << QUEUE_FLAG_QUEUED); return 0; - -fail_map: - kfree(tags->tag_index); -fail_index: - kfree(tags); fail: + kfree(tags); return -ENOMEM; } /** + * blk_queue_resize_tags - change the queueing depth + * @q: the request queue for the device + * @new_depth: the new max command queueing depth + * + * Notes: + * Must be called with the queue lock held. + **/ +int blk_queue_resize_tags(request_queue_t *q, int new_depth) +{ + struct blk_queue_tag *bqt = q->queue_tags; + struct request **tag_index; + unsigned long *tag_map; + int bits, max_depth; + + if (!bqt) + return -ENXIO; + + /* + * don't bother sizing down + */ + if (new_depth <= bqt->real_max_depth) { + bqt->max_depth = new_depth; + return 0; + } + + /* + * save the old state info, so we can copy it back + */ + tag_index = bqt->tag_index; + tag_map = bqt->tag_map; + max_depth = bqt->real_max_depth; + + if (init_tag_map(bqt, new_depth)) + return -ENOMEM; + + memcpy(bqt->tag_index, tag_index, max_depth * sizeof(struct request *)); + bits = max_depth / BLK_TAGS_PER_LONG; + memcpy(bqt->tag_map, tag_map, bits * sizeof(unsigned long)); + + kfree(tag_index); + kfree(tag_map); + return 0; +} + +/** * blk_queue_end_tag - end tag operations for a request * @q: the request queue for the device * @tag: the tag that has completed @@ -524,7 +575,7 @@ BUG_ON(tag == -1); - if (unlikely(tag >= bqt->max_depth)) + if (unlikely(tag >= bqt->real_max_depth)) return; if (unlikely(!__test_and_clear_bit(tag, bqt->tag_map))) { @@ -1019,30 +1070,12 @@ * blk_start_queue() will clear the stop flag on the queue, and call * the request_fn for the queue if it was in a stopped state when * entered. Also see blk_stop_queue(). Must not be called from driver - * request function due to recursion issues. + * request function due to recursion issues. Queue lock must be held. **/ void blk_start_queue(request_queue_t *q) { - if (test_and_clear_bit(QUEUE_FLAG_STOPPED, &q->queue_flags)) { - unsigned long flags; - - spin_lock_irqsave(q->queue_lock, flags); - if (!elv_queue_empty(q)) - q->request_fn(q); - spin_unlock_irqrestore(q->queue_lock, flags); - } -} - -/** - * __blk_stop_queue: see blk_stop_queue() - * - * Description: - * Like blk_stop_queue(), but queue_lock must be held - **/ -void __blk_stop_queue(request_queue_t *q) -{ - blk_remove_plug(q); - set_bit(QUEUE_FLAG_STOPPED, &q->queue_flags); + if (test_and_clear_bit(QUEUE_FLAG_STOPPED, &q->queue_flags)) + schedule_work(&q->unplug_work); } /** @@ -1057,15 +1090,12 @@ * or if it simply chooses not to queue more I/O at one point, it can * call this function to prevent the request_fn from being called until * the driver has signalled it's ready to go again. This happens by calling - * blk_start_queue() to restart queue operations. + * blk_start_queue() to restart queue operations. Queue lock must be held. **/ void blk_stop_queue(request_queue_t *q) { - unsigned long flags; - - spin_lock_irqsave(q->queue_lock, flags); - __blk_stop_queue(q); - spin_unlock_irqrestore(q->queue_lock, flags); + blk_remove_plug(q); + set_bit(QUEUE_FLAG_STOPPED, &q->queue_flags); } /** @@ -2307,7 +2337,6 @@ EXPORT_SYMBOL(blk_nohighio); EXPORT_SYMBOL(blk_dump_rq_flags); EXPORT_SYMBOL(submit_bio); -EXPORT_SYMBOL(blk_queue_assign_lock); EXPORT_SYMBOL(blk_phys_contig_segment); EXPORT_SYMBOL(blk_hw_contig_segment); EXPORT_SYMBOL(blk_get_request); @@ -2326,7 +2355,6 @@ EXPORT_SYMBOL(blk_start_queue); EXPORT_SYMBOL(blk_stop_queue); -EXPORT_SYMBOL(__blk_stop_queue); EXPORT_SYMBOL(blk_run_queue); EXPORT_SYMBOL(blk_run_queues); diff -Nru a/drivers/block/loop.c b/drivers/block/loop.c --- a/drivers/block/loop.c Mon Jun 9 23:16:14 2003 +++ b/drivers/block/loop.c Mon Jun 9 23:16:14 2003 @@ -236,7 +236,6 @@ up(&mapping->host->i_sem); out: kunmap(bvec->bv_page); - balance_dirty_pages_ratelimited(mapping); return ret; unlock: diff -Nru a/drivers/block/nbd.c b/drivers/block/nbd.c --- a/drivers/block/nbd.c Mon Jun 9 23:16:08 2003 +++ b/drivers/block/nbd.c Mon Jun 9 23:16:08 2003 @@ -120,7 +120,7 @@ do { - sock->sk->allocation = GFP_NOIO; + sock->sk->sk_allocation = GFP_NOIO; iov.iov_base = buf; iov.iov_len = size; msg.msg_name = NULL; diff -Nru a/drivers/block/scsi_ioctl.c b/drivers/block/scsi_ioctl.c --- a/drivers/block/scsi_ioctl.c Mon Jun 9 23:16:19 2003 +++ b/drivers/block/scsi_ioctl.c Mon Jun 9 23:16:19 2003 @@ -68,7 +68,6 @@ rq->flags |= REQ_NOMERGE; rq->waiting = &wait; - drive_stat_acct(rq, rq->nr_sectors, 1); elv_add_request(q, rq, 1, 1); generic_unplug_device(q); wait_for_completion(&wait); @@ -99,7 +98,7 @@ static int sg_get_timeout(request_queue_t *q) { - return q->sg_timeout; + return q->sg_timeout / (HZ / USER_HZ); } static int sg_set_timeout(request_queue_t *q, int *p) @@ -107,7 +106,7 @@ int timeout, err = get_user(timeout, p); if (!err) - q->sg_timeout = timeout; + q->sg_timeout = timeout * (HZ / USER_HZ); return err; } @@ -121,10 +120,14 @@ { int size, err = get_user(size, p); - if (!err) - q->sg_reserved_size = size; + if (err) + return err; - return err; + if (size > (q->max_sectors << 9)) + return -EINVAL; + + q->sg_reserved_size = size; + return 0; } /* @@ -139,16 +142,14 @@ static int sg_io(request_queue_t *q, struct block_device *bdev, struct sg_io_hdr *uptr) { - unsigned long uaddr, start_time; - int reading, writing, nr_sectors; + unsigned long start_time; + int reading, writing; struct sg_io_hdr hdr; struct request *rq; struct bio *bio; char sense[SCSI_SENSE_BUFFERSIZE]; void *buffer; - if (!access_ok(VERIFY_WRITE, uptr, sizeof(*uptr))) - return -EFAULT; if (copy_from_user(&hdr, uptr, sizeof(*uptr))) return -EFAULT; @@ -156,11 +157,6 @@ return -EINVAL; if (hdr.cmd_len > sizeof(rq->cmd)) return -EINVAL; - if (!access_ok(VERIFY_READ, hdr.cmdp, hdr.cmd_len)) - return -EFAULT; - - if (hdr.dxfer_len > 65536) - return -EINVAL; /* * we'll do that later @@ -168,7 +164,9 @@ if (hdr.iovec_count) return -EOPNOTSUPP; - nr_sectors = 0; + if (hdr.dxfer_len > (q->max_sectors << 9)) + return -EIO; + reading = writing = 0; buffer = NULL; bio = NULL; @@ -189,19 +187,12 @@ break; } - uaddr = (unsigned long) hdr.dxferp; - /* writing to device -> reading from vm */ - if (writing && !access_ok(VERIFY_READ, uaddr, bytes)) - return -EFAULT; - /* reading from device -> writing to vm */ - else if (reading && !access_ok(VERIFY_WRITE, uaddr, bytes)) - return -EFAULT; - /* * first try to map it into a bio. reading from device will * be a write to vm. */ - bio = bio_map_user(bdev, uaddr, hdr.dxfer_len, reading); + bio = bio_map_user(bdev, (unsigned long) hdr.dxferp, + hdr.dxfer_len, reading); /* * if bio setup failed, fall back to slow approach @@ -211,10 +202,11 @@ if (!buffer) return -ENOMEM; - nr_sectors = bytes >> 9; - if (writing) - copy_from_user(buffer,hdr.dxferp,hdr.dxfer_len); - else + if (writing) { + if (copy_from_user(buffer, hdr.dxferp, + hdr.dxfer_len)) + goto out_buffer; + } else memset(buffer, 0, hdr.dxfer_len); } } @@ -225,7 +217,8 @@ * fill in request structure */ rq->cmd_len = hdr.cmd_len; - copy_from_user(rq->cmd, hdr.cmdp, hdr.cmd_len); + if (copy_from_user(rq->cmd, hdr.cmdp, hdr.cmd_len)) + goto out_request; if (sizeof(rq->cmd) != hdr.cmd_len) memset(rq->cmd + hdr.cmd_len, 0, sizeof(rq->cmd) - hdr.cmd_len); @@ -235,18 +228,15 @@ rq->flags |= REQ_BLOCK_PC; - rq->hard_nr_sectors = rq->nr_sectors = nr_sectors; - rq->hard_cur_sectors = rq->current_nr_sectors = nr_sectors; - - rq->bio = rq->biotail = bio; + rq->bio = rq->biotail = NULL; if (bio) blk_rq_bio_prep(q, rq, bio); - rq->data_len = hdr.dxfer_len; rq->data = buffer; + rq->data_len = hdr.dxfer_len; - rq->timeout = hdr.timeout; + rq->timeout = (hdr.timeout * HZ) / 1000; if (!rq->timeout) rq->timeout = q->sg_timeout; if (!rq->timeout) @@ -273,12 +263,11 @@ if (hdr.masked_status || hdr.host_status || hdr.driver_status) hdr.info |= SG_INFO_CHECK; hdr.resid = rq->data_len; - hdr.duration = (jiffies - start_time) * (1000 / HZ); + hdr.duration = ((jiffies - start_time) * 1000) / HZ; hdr.sb_len_wr = 0; if (rq->sense_len && hdr.sbp) { - int len = (hdr.mx_sb_len < rq->sense_len) ? - hdr.mx_sb_len : rq->sense_len; + int len = min((unsigned int) hdr.mx_sb_len, rq->sense_len); if (!copy_to_user(hdr.sbp, rq->sense, len)) hdr.sb_len_wr = len; @@ -286,17 +275,25 @@ blk_put_request(rq); - copy_to_user(uptr, &hdr, sizeof(*uptr)); + if (copy_to_user(uptr, &hdr, sizeof(*uptr))) + goto out_buffer; if (buffer) { if (reading) - copy_to_user(hdr.dxferp, buffer, hdr.dxfer_len); + if (copy_to_user(hdr.dxferp, buffer, hdr.dxfer_len)) + goto out_buffer; kfree(buffer); } + /* may not have succeeded, but output values written to control * structure (struct sg_io_hdr). */ return 0; +out_request: + blk_put_request(rq); +out_buffer: + kfree(buffer); + return -EFAULT; } #define FORMAT_UNIT_TIMEOUT (2 * 60 * 60 * HZ) diff -Nru a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c --- a/drivers/bluetooth/hci_usb.c Mon Jun 9 23:16:18 2003 +++ b/drivers/bluetooth/hci_usb.c Mon Jun 9 23:16:18 2003 @@ -943,6 +943,7 @@ } static struct usb_driver hci_usb_driver = { + .owner = THIS_MODULE, .name = "hci_usb", .probe = hci_usb_probe, .disconnect = hci_usb_disconnect, diff -Nru a/drivers/char/Kconfig b/drivers/char/Kconfig --- a/drivers/char/Kconfig Mon Jun 9 23:16:05 2003 +++ b/drivers/char/Kconfig Mon Jun 9 23:16:05 2003 @@ -94,17 +94,20 @@ two modules called ip2 and ip2main. config ROCKETPORT - tristate "Comtrol Rocketport support" + tristate "Comtrol RocketPort support" depends on SERIAL_NONSTANDARD help - This is a driver for the Comtrol Rocketport cards which provide - multiple serial ports. You would need something like this to connect - more than two modems to your Linux box, for instance in order to - become a dial-in server. + This driver supports Comtrol RocketPort and RocketModem PCI boards. + These boards provide 2, 4, 8, 16, or 32 high-speed serial ports or + modems. For information about the RocketPort/RocketModem boards + and this driver read <file:Documentation/rocket.txt>. If you want to compile this driver as a module, say M here and read <file:Documentation/modules.txt>. The module will be called rocket. + + If you want to compile this driver into the kernel, say Y here. If + you don't have a Comtrol RocketPort/RocketModem card installed, say N. config CYCLADES tristate "Cyclades async mux support" diff -Nru a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig --- a/drivers/char/agp/Kconfig Mon Jun 9 23:16:14 2003 +++ b/drivers/char/agp/Kconfig Mon Jun 9 23:16:14 2003 @@ -134,7 +134,7 @@ config AGP_UNINORTH tristate "Apple UniNorth AGP support" - depends on AGP && ALL_PPC + depends on AGP && PPC_PMAC help This option gives you AGP support for Apple machines with a UniNorth bridge. diff -Nru a/drivers/char/agp/amd-k8-agp.c b/drivers/char/agp/amd-k8-agp.c --- a/drivers/char/agp/amd-k8-agp.c Mon Jun 9 23:16:15 2003 +++ b/drivers/char/agp/amd-k8-agp.c Mon Jun 9 23:16:15 2003 @@ -244,7 +244,7 @@ const struct pci_device_id *ent) { struct agp_bridge_data *bridge; - struct pci_dev *loop_dev; + struct pci_dev *loop_dev = NULL; u8 rev_id; u8 cap_ptr; int i = 0; @@ -297,7 +297,7 @@ pci_read_config_dword(pdev, bridge->capndx+PCI_AGP_STATUS, &bridge->mode); /* cache pci_devs of northbridges. */ - pci_for_each_dev(loop_dev) { + while ((loop_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, loop_dev)) != NULL) { if (loop_dev->bus->number == 0 && PCI_FUNC(loop_dev->devfn) == 3 && PCI_SLOT(loop_dev->devfn) >=24 && diff -Nru a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c --- a/drivers/char/agp/generic.c Mon Jun 9 23:16:10 2003 +++ b/drivers/char/agp/generic.c Mon Jun 9 23:16:10 2003 @@ -462,12 +462,12 @@ //We need a function we pass an agp_device to. u32 agp_collect_device_status(u32 mode, u32 cmd) { - struct pci_dev *device; + struct pci_dev *device = NULL; u8 cap_ptr; u32 tmp; u32 agp3; - pci_for_each_dev(device) { + while ((device = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, device)) != NULL) { cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP); if (!cap_ptr) continue; @@ -502,14 +502,14 @@ void agp_device_command(u32 command, int agp_v3) { - struct pci_dev *device; + struct pci_dev *device = NULL; int mode; mode = command & 0x7; if (agp_v3) mode *= 4; - pci_for_each_dev(device) { + while ((device = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, device)) != NULL) { u8 agp = pci_find_capability(device, PCI_CAP_ID_AGP); if (!agp) continue; diff -Nru a/drivers/char/agp/isoch.c b/drivers/char/agp/isoch.c --- a/drivers/char/agp/isoch.c Mon Jun 9 23:16:18 2003 +++ b/drivers/char/agp/isoch.c Mon Jun 9 23:16:18 2003 @@ -316,7 +316,7 @@ */ int agp_3_5_enable(struct agp_bridge_data *bridge) { - struct pci_dev *td = bridge->dev, *dev; + struct pci_dev *td = bridge->dev, *dev = NULL; u8 mcapndx; u32 isoch, arqsz; u32 tstatus, mstatus, ncapid; @@ -347,7 +347,7 @@ INIT_LIST_HEAD(head); /* Find all AGP devices, and add them to dev_list. */ - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { mcapndx = pci_find_capability(dev, PCI_CAP_ID_AGP); if (mcapndx == 0) continue; diff -Nru a/drivers/char/amiserial.c b/drivers/char/amiserial.c --- a/drivers/char/amiserial.c Mon Jun 9 23:16:19 2003 +++ b/drivers/char/amiserial.c Mon Jun 9 23:16:20 2003 @@ -102,13 +102,12 @@ static char *serial_name = "Amiga-builtin serial driver"; -static struct tty_driver serial_driver, callout_driver; +static struct tty_driver serial_driver; static int serial_refcount; /* serial subtype definitions */ #ifndef SERIAL_TYPE_NORMAL #define SERIAL_TYPE_NORMAL 1 -#define SERIAL_TYPE_CALLOUT 2 #endif /* number of characters left in xmit buffer before we ask for more */ @@ -448,8 +447,7 @@ #endif if (!(status & SER_DCD)) wake_up_interruptible(&info->open_wait); - else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_CALLOUT_NOHUP))) { + else { #ifdef SERIAL_DEBUG_OPEN printk("doing serial hangup..."); #endif @@ -1567,8 +1565,6 @@ */ if (info->flags & ASYNC_NORMAL_ACTIVE) info->state->normal_termios = *tty->termios; - if (info->flags & ASYNC_CALLOUT_ACTIVE) - info->state->callout_termios = *tty->termios; /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. @@ -1613,8 +1609,7 @@ } wake_up_interruptible(&info->open_wait); } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| - ASYNC_CLOSING); + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); local_irq_restore(flags); } @@ -1698,7 +1693,7 @@ shutdown(info); info->event = 0; state->count = 0; - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->flags &= ~ASYNC_NORMAL_ACTIVE; info->tty = 0; wake_up_interruptible(&info->open_wait); } @@ -1738,43 +1733,17 @@ } /* - * If this is a callout device, then just make sure the normal - * device isn't being used. - */ - if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) { - if (info->flags & ASYNC_NORMAL_ACTIVE) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_SESSION_LOCKOUT) && - (info->session != current->session)) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_PGRP_LOCKOUT) && - (info->pgrp != current->pgrp)) - return -EBUSY; - info->flags |= ASYNC_CALLOUT_ACTIVE; - return 0; - } - - /* * If non-blocking mode is set, or the port is not enabled, * then make the check up front and then exit. */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { - if (info->flags & ASYNC_CALLOUT_ACTIVE) - return -EBUSY; info->flags |= ASYNC_NORMAL_ACTIVE; return 0; } - if (info->flags & ASYNC_CALLOUT_ACTIVE) { - if (state->normal_termios.c_cflag & CLOCAL) - do_clocal = 1; - } else { - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - } + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; /* * Block waiting for the carrier detect and the line to become @@ -1798,8 +1767,7 @@ info->blocked_open++; while (1) { local_irq_save(flags); - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - (tty->termios->c_cflag & CBAUD)) + if (tty->termios->c_cflag & CBAUD) rtsdtr_ctrl(SER_DTR|SER_RTS); local_irq_restore(flags); set_current_state(TASK_INTERRUPTIBLE); @@ -1815,8 +1783,7 @@ #endif break; } - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - !(info->flags & ASYNC_CLOSING) && + if (!(info->flags & ASYNC_CLOSING) && (do_clocal || (!(ciab.pra & SER_DCD)) )) break; if (signal_pending(current)) { @@ -1957,14 +1924,9 @@ if ((info->state->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver->subtype == SERIAL_TYPE_NORMAL) - *tty->termios = info->state->normal_termios; - else - *tty->termios = info->state->callout_termios; + *tty->termios = info->state->normal_termios; change_speed(info, 0); } - info->session = current->session; - info->pgrp = current->pgrp; #ifdef SERIAL_DEBUG_OPEN printk("rs_open %s successful...", tty->name); @@ -2150,21 +2112,8 @@ serial_driver.wait_until_sent = rs_wait_until_sent; serial_driver.read_proc = rs_read_proc; - /* - * The callout device is just like normal device except for - * major number and the subtype code. - */ - callout_driver = serial_driver; - callout_driver.name = "cua"; - callout_driver.major = TTYAUX_MAJOR; - callout_driver.subtype = SERIAL_TYPE_CALLOUT; - callout_driver.read_proc = 0; - callout_driver.proc_entry = 0; - if (tty_register_driver(&serial_driver)) panic("Couldn't register serial driver\n"); - if (tty_register_driver(&callout_driver)) - panic("Couldn't register callout driver\n"); state = rs_table; state->magic = SSTATE_MAGIC; @@ -2173,7 +2122,6 @@ state->custom_divisor = 0; state->close_delay = 5*HZ/10; state->closing_wait = 30*HZ; - state->callout_termios = callout_driver.init_termios; state->normal_termios = serial_driver.init_termios; state->icount.cts = state->icount.dsr = state->icount.rng = state->icount.dcd = 0; @@ -2229,9 +2177,6 @@ if ((e1 = tty_unregister_driver(&serial_driver))) printk("SERIAL: failed to unregister serial driver (%d)\n", e1); - if ((e2 = tty_unregister_driver(&callout_driver))) - printk("SERIAL: failed to unregister callout driver (%d)\n", - e2); if (info) { rs_table[0].info = NULL; diff -Nru a/drivers/char/cyclades.c b/drivers/char/cyclades.c --- a/drivers/char/cyclades.c Mon Jun 9 23:16:08 2003 +++ b/drivers/char/cyclades.c Mon Jun 9 23:16:08 2003 @@ -712,7 +712,7 @@ #define JIFFIES_DIFF(n, j) ((j) - (n)) -static struct tty_driver cy_serial_driver, cy_callout_driver; +static struct tty_driver cy_serial_driver; static int serial_refcount; #ifdef CONFIG_ISA @@ -968,8 +968,7 @@ if (test_and_clear_bit(Cy_EVENT_HANGUP, &info->event)) { tty_hangup(info->tty); wake_up_interruptible(&info->open_wait); - info->flags &= ~(ASYNC_NORMAL_ACTIVE| - ASYNC_CALLOUT_ACTIVE); + info->flags &= ~ASYNC_NORMAL_ACTIVE; } if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) { wake_up_interruptible(&info->open_wait); @@ -1448,10 +1447,7 @@ if(mdm_status & CyDCD){ cy_sched_event(info, Cy_EVENT_OPEN_WAKEUP); - }else if(!((info->flags - & ASYNC_CALLOUT_ACTIVE) - &&(info->flags - & ASYNC_CALLOUT_NOHUP))){ + }else{ cy_sched_event(info, Cy_EVENT_HANGUP); } @@ -1823,8 +1819,7 @@ ((u_long)param) : cy_readl(&ch_ctrl->rs_status)) & C_RS_DCD) { cy_sched_event(info, Cy_EVENT_OPEN_WAKEUP); - }else if(!((info->flags & ASYNC_CALLOUT_ACTIVE) - &&(info->flags & ASYNC_CALLOUT_NOHUP))){ + }else{ cy_sched_event(info, Cy_EVENT_HANGUP); } } @@ -2376,36 +2371,11 @@ } /* - * If this is a callout device, then just make sure the normal - * device isn't being used. - */ - if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) { - if (info->flags & ASYNC_NORMAL_ACTIVE){ - return -EBUSY; - } - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_SESSION_LOCKOUT) && - (info->session != current->session)){ - return -EBUSY; - } - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_PGRP_LOCKOUT) && - (info->pgrp != current->pgrp)){ - return -EBUSY; - } - info->flags |= ASYNC_CALLOUT_ACTIVE; - return 0; - } - - /* * If non-blocking mode is set, then make the check up front * and then exit. */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { - if (info->flags & ASYNC_CALLOUT_ACTIVE){ - return -EBUSY; - } info->flags |= ASYNC_NORMAL_ACTIVE; return 0; } @@ -2442,8 +2412,7 @@ while (1) { CY_LOCK(info, flags); - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - (tty->termios->c_cflag & CBAUD)){ + if ((tty->termios->c_cflag & CBAUD)){ cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel); cy_writeb((u_long)base_addr+(CyMSVR1<<index), CyRTS); cy_writeb((u_long)base_addr+(CyMSVR2<<index), CyDTR); @@ -2466,8 +2435,7 @@ CY_LOCK(info, flags); cy_writeb((u_long)base_addr+(CyCAR<<index), (u_char)channel); - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) - && !(info->flags & ASYNC_CLOSING) + if (!(info->flags & ASYNC_CLOSING) && (C_CLOCAL(tty) || (cy_readb(base_addr+(CyMSVR1<<index)) & CyDCD))) { CY_UNLOCK(info, flags); @@ -2507,8 +2475,7 @@ ch_ctrl = zfw_ctrl->ch_ctrl; while (1) { - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - (tty->termios->c_cflag & CBAUD)){ + if ((tty->termios->c_cflag & CBAUD)){ cy_writel(&ch_ctrl[channel].rs_control, cy_readl(&ch_ctrl[channel].rs_control) | (C_RS_RTS | C_RS_DTR)); @@ -2530,8 +2497,7 @@ -EAGAIN : -ERESTARTSYS); break; } - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) - && !(info->flags & ASYNC_CLOSING) + if (!(info->flags & ASYNC_CLOSING) && (C_CLOCAL(tty) || (cy_readl(&ch_ctrl[channel].rs_status) & C_RS_DCD))) { break; @@ -2680,15 +2646,9 @@ } if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver->subtype == SERIAL_TYPE_NORMAL) - *tty->termios = info->normal_termios; - else - *tty->termios = info->callout_termios; + *tty->termios = info->normal_termios; } - info->session = current->session; - info->pgrp = current->pgrp; - #ifdef CY_DEBUG_OPEN printk(" cyc:cy_open done\n");/**/ #endif @@ -2839,8 +2799,6 @@ */ if (info->flags & ASYNC_NORMAL_ACTIVE) info->normal_termios = *tty->termios; - if (info->flags & ASYNC_CALLOUT_ACTIVE) - info->callout_termios = *tty->termios; /* * Now we wait for the transmit buffer to clear; and we notify @@ -2917,8 +2875,7 @@ wake_up_interruptible(&info->open_wait); CY_LOCK(info, flags); } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| - ASYNC_CLOSING); + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); #ifdef CY_DEBUG_OTHER @@ -4701,7 +4658,7 @@ printk("cyc:cy_hangup (%d): setting count to 0\n", current->pid); #endif info->tty = 0; - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->flags &= ~ASYNC_NORMAL_ACTIVE; wake_up_interruptible(&info->open_wait); } /* cy_hangup */ @@ -5523,22 +5480,8 @@ cy_serial_driver.wait_until_sent = cy_wait_until_sent; cy_serial_driver.read_proc = cyclades_get_proc_info; - /* - * The callout device is just like normal device except for - * major number and the subtype code. - */ - cy_callout_driver = cy_serial_driver; - cy_callout_driver.name = "cub"; - cy_callout_driver.major = CYCLADESAUX_MAJOR; - cy_callout_driver.subtype = SERIAL_TYPE_CALLOUT; - cy_callout_driver.read_proc = 0; - cy_callout_driver.proc_entry = 0; - - if (tty_register_driver(&cy_serial_driver)) panic("Couldn't register Cyclades serial driver\n"); - if (tty_register_driver(&cy_callout_driver)) - panic("Couldn't register Cyclades callout driver\n"); for (i = 0; i < NR_CARDS; i++) { /* base_addr=0 indicates board not found */ @@ -5629,8 +5572,6 @@ info->default_threshold = 0; info->default_timeout = 0; INIT_WORK(&info->tqueue, do_softint, info); - info->callout_termios = - cy_callout_driver.init_termios; info->normal_termios = cy_serial_driver.init_termios; init_waitqueue_head(&info->open_wait); @@ -5708,8 +5649,6 @@ info->default_threshold = 0; info->default_timeout = 0; INIT_WORK(&info->tqueue, do_softint, info); - info->callout_termios = - cy_callout_driver.init_termios; info->normal_termios = cy_serial_driver.init_termios; init_waitqueue_head(&info->open_wait); @@ -5761,9 +5700,6 @@ if ((e1 = tty_unregister_driver(&cy_serial_driver))) printk("cyc: failed to unregister Cyclades serial driver(%d)\n", e1); - if ((e2 = tty_unregister_driver(&cy_callout_driver))) - printk("cyc: failed to unregister Cyclades callout driver (%d)\n", - e2); restore_flags(flags); diff -Nru a/drivers/char/dz.c b/drivers/char/dz.c --- a/drivers/char/dz.c Mon Jun 9 23:16:07 2003 +++ b/drivers/char/dz.c Mon Jun 9 23:16:07 2003 @@ -1095,8 +1095,6 @@ */ if (info->flags & DZ_NORMAL_ACTIVE) info->normal_termios = *tty->termios; - if (info->flags & DZ_CALLOUT_ACTIVE) - info->callout_termios = *tty->termios; /* * Now we wait for the transmit buffer to clear; and we notify the line * discipline to only process XON/XOFF characters. @@ -1136,7 +1134,7 @@ wake_up_interruptible(&info->open_wait); } - info->flags &= ~(DZ_NORMAL_ACTIVE | DZ_CALLOUT_ACTIVE | DZ_CLOSING); + info->flags &= ~(DZ_NORMAL_ACTIVE | DZ_CLOSING); wake_up_interruptible(&info->close_wait); restore_flags(flags); @@ -1153,7 +1151,7 @@ shutdown(info); info->event = 0; info->count = 0; - info->flags &= ~(DZ_NORMAL_ACTIVE | DZ_CALLOUT_ACTIVE); + info->flags &= ~DZ_NORMAL_ACTIVE; info->tty = 0; wake_up_interruptible(&info->open_wait); } @@ -1180,47 +1178,18 @@ } /* - * If this is a callout device, then just make sure the normal - * device isn't being used. - */ - if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) { - if (info->flags & DZ_NORMAL_ACTIVE) - return -EBUSY; - - if ((info->flags & DZ_CALLOUT_ACTIVE) && - (info->flags & DZ_SESSION_LOCKOUT) && - (info->session != current->session)) - return -EBUSY; - - if ((info->flags & DZ_CALLOUT_ACTIVE) && - (info->flags & DZ_PGRP_LOCKOUT) && - (info->pgrp != current->pgrp)) - return -EBUSY; - - info->flags |= DZ_CALLOUT_ACTIVE; - return 0; - } - - /* * If non-blocking mode is set, or the port is not enabled, then make * the check up front and then exit. */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { - if (info->flags & DZ_CALLOUT_ACTIVE) - return -EBUSY; info->flags |= DZ_NORMAL_ACTIVE; return 0; } - if (info->flags & DZ_CALLOUT_ACTIVE) { - if (info->normal_termios.c_cflag & CLOCAL) - do_clocal = 1; - } else { - if (tty->termios->c_cflag & CLOCAL) + if (tty->termios->c_cflag & CLOCAL) do_clocal = 1; - } /* * Block waiting for the carrier detect and the line to become free @@ -1239,8 +1208,7 @@ retval = -EAGAIN; break; } - if (!(info->flags & DZ_CALLOUT_ACTIVE) && - !(info->flags & DZ_CLOSING) && do_clocal) + if (!(info->flags & DZ_CLOSING) && do_clocal) break; if (signal_pending(current)) { retval = -ERESTARTSYS; @@ -1301,16 +1269,10 @@ return retval; if ((info->count == 1) && (info->flags & DZ_SPLIT_TERMIOS)) { - if (tty->driver->subtype == SERIAL_TYPE_NORMAL) - *tty->termios = info->normal_termios; - else - *tty->termios = info->callout_termios; + *tty->termios = info->normal_termios; change_speed(info); } - info->session = current->session; - info->pgrp = current->pgrp; - return 0; } @@ -1333,11 +1295,8 @@ memset(&serial_driver, 0, sizeof(struct tty_driver)); serial_driver.magic = TTY_DRIVER_MAGIC; serial_driver.owner = THIS_MODULE; -#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) + serial_driver.devfs_name = "tts/"; serial_driver.name = "ttyS"; -#else - serial_driver.name = "tts/"; -#endif serial_driver.major = TTY_MAJOR; serial_driver.minor_start = 64; serial_driver.num = DZ_NB_PORT; @@ -1369,23 +1328,8 @@ serial_driver.start = dz_start; serial_driver.hangup = dz_hangup; - /* - * The callout device is just like normal device except for major - * number and the subtype code. - */ - callout_driver = serial_driver; -#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) - callout_driver.name = "cua"; -#else - callout_driver.name = "cua/"; -#endif - callout_driver.major = TTYAUX_MAJOR; - callout_driver.subtype = SERIAL_TYPE_CALLOUT; - if (tty_register_driver (&serial_driver)) panic("Couldn't register serial driver\n"); - if (tty_register_driver (&callout_driver)) - panic("Couldn't register callout driver\n"); save_flags(flags); cli(); for (i=0; i < DZ_NB_PORT; i++) { @@ -1411,7 +1355,6 @@ info->tqueue.data = info; info->tqueue_hangup.routine = do_serial_hangup; info->tqueue_hangup.data = info; - info->callout_termios = callout_driver.init_termios; info->normal_termios = serial_driver.init_termios; init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); @@ -1427,7 +1370,6 @@ info->port, SERIAL); tty_register_device(&serial_driver, info->line, NULL); - tty_register_device(&callout_driver, info->line, NULL); } /* Reset the chip */ diff -Nru a/drivers/char/dz.h b/drivers/char/dz.h --- a/drivers/char/dz.h Mon Jun 9 23:16:08 2003 +++ b/drivers/char/dz.h Mon Jun 9 23:16:08 2003 @@ -157,12 +157,8 @@ struct tq_struct tqueue; /* Queue for BH */ struct tq_struct tqueue_hangup; struct termios normal_termios; - struct termios callout_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_console; /* flag indicating a serial console */ unsigned char is_initialized; diff -Nru a/drivers/char/epca.c b/drivers/char/epca.c --- a/drivers/char/epca.c Mon Jun 9 23:16:14 2003 +++ b/drivers/char/epca.c Mon Jun 9 23:16:14 2003 @@ -98,7 +98,6 @@ /* ------------- Begin structures used for driver registeration ---------- */ struct tty_driver pc_driver; -struct tty_driver pc_callout; struct tty_driver pc_info; /* The below structures are used to initialize the tty_driver structures. */ @@ -562,9 +561,6 @@ if (ch->asyncflags & ASYNC_NORMAL_ACTIVE) ch->normal_termios = *tty->termios; - if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE) - ch->callout_termios = *tty->termios; - tty->closing = 1; if (ch->asyncflags & ASYNC_INITIALIZED) @@ -599,7 +595,7 @@ } /* End if blocked_open */ ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED | - ASYNC_CALLOUT_ACTIVE | ASYNC_CLOSING); + ASYNC_CLOSING); wake_up_interruptible(&ch->close_wait); @@ -693,7 +689,7 @@ ch->event = 0; ch->count = 0; restore_flags(flags); - ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED | ASYNC_CALLOUT_ACTIVE); + ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_INITIALIZED); wake_up_interruptible(&ch->open_wait); } /* End if ch != NULL */ @@ -1233,31 +1229,6 @@ return -ERESTARTSYS; } - /* ----------------------------------------------------------------- - If this is a callout device, then just make sure the normal - device isn't being used. - -------------------------------------------------------------------- */ - - if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) - { /* A cud device has been opened */ - if (ch->asyncflags & ASYNC_NORMAL_ACTIVE) - return -EBUSY; - - if ((ch->asyncflags & ASYNC_CALLOUT_ACTIVE) && - (ch->asyncflags & ASYNC_SESSION_LOCKOUT) && - (ch->session != current->session)) - return -EBUSY; - - if ((ch->asyncflags & ASYNC_CALLOUT_ACTIVE) && - (ch->asyncflags & ASYNC_PGRP_LOCKOUT) && - (ch->pgrp != current->pgrp)) - return -EBUSY; - - ch->asyncflags |= ASYNC_CALLOUT_ACTIVE; - - return 0; - } /* End a cud device has been opened */ - if (filp->f_flags & O_NONBLOCK) { /* ----------------------------------------------------------------- @@ -1265,25 +1236,14 @@ and then exit. -------------------------------------------------------------------- */ - if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE) - return -EBUSY; - ch->asyncflags |= ASYNC_NORMAL_ACTIVE; return 0; } - if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE) - { - if (ch->normal_termios.c_cflag & CLOCAL) - do_clocal = 1; - } - else - { - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - } + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; /* Block waiting for the carrier detect and the line to become free */ @@ -1317,7 +1277,6 @@ } if (!(ch->asyncflags & ASYNC_CLOSING) && - !(ch->asyncflags & ASYNC_CALLOUT_ACTIVE) && (do_clocal || (ch->imodem & ch->dcd))) break; @@ -1453,15 +1412,9 @@ /* Should this be here except for SPLIT termios ? */ if (ch->count == 1) { - if (tty->driver->subtype == SERIAL_TYPE_NORMAL) - *tty->termios = ch->normal_termios; - else - *tty->termios = ch->callout_termios; + *tty->termios = ch->normal_termios; } - ch->session = current->session; - ch->pgrp = current->pgrp; - save_flags(flags); cli(); @@ -1558,7 +1511,6 @@ cli(); if ((tty_unregister_driver(&pc_driver)) || - (tty_unregister_driver(&pc_callout)) || (tty_unregister_driver(&pc_info))) { printk(KERN_WARNING "<Error> - DIGI : cleanup_module failed to un-register tty driver\n"); @@ -1701,7 +1653,6 @@ #endif /* ENABLE_PCI */ memset(&pc_driver, 0, sizeof(struct tty_driver)); - memset(&pc_callout, 0, sizeof(struct tty_driver)); memset(&pc_info, 0, sizeof(struct tty_driver)); pc_driver.magic = TTY_DRIVER_MAGIC; @@ -1747,13 +1698,6 @@ pc_driver.throttle = pc_throttle; pc_driver.unthrottle = pc_unthrottle; pc_driver.hangup = pc_hangup; - pc_callout = pc_driver; - - pc_callout.name = "cud"; - pc_callout.major = DIGICU_MAJOR; - pc_callout.minor_start = 0; - pc_callout.init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL; - pc_callout.subtype = SERIAL_TYPE_CALLOUT; pc_info = pc_driver; pc_info.name = "digi_ctl"; @@ -1889,9 +1833,6 @@ if (tty_register_driver(&pc_driver)) panic("Couldn't register Digi PC/ driver"); - if (tty_register_driver(&pc_callout)) - panic("Couldn't register Digi PC/ callout"); - if (tty_register_driver(&pc_info)) panic("Couldn't register Digi PC/ info "); @@ -2165,7 +2106,6 @@ ch->close_delay = 50; ch->count = 0; ch->blocked_open = 0; - ch->callout_termios = pc_callout.init_termios; ch->normal_termios = pc_driver.init_termios; init_waitqueue_head(&ch->open_wait); init_waitqueue_head(&ch->close_wait); @@ -2712,7 +2652,7 @@ the driver will wait on carrier detect. ------------------------------------------------------------------- */ - if ((ts->c_cflag & CLOCAL) || (tty->driver->subtype == SERIAL_TYPE_CALLOUT)) + if (ts->c_cflag & CLOCAL) { /* Begin it is a cud device or a ttyD device with CLOCAL on */ ch->asyncflags &= ~ASYNC_CHECK_CD; } /* End it is a cud device or a ttyD device with CLOCAL on */ @@ -3406,7 +3346,7 @@ tty_hangup(tty); /* FIXME: module removal race here - AKPM */ wake_up_interruptible(&ch->open_wait); - ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE); + ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE; } /* End if clear_bit */ } diff -Nru a/drivers/char/epca.h b/drivers/char/epca.h --- a/drivers/char/epca.h Mon Jun 9 23:16:14 2003 +++ b/drivers/char/epca.h Mon Jun 9 23:16:14 2003 @@ -78,7 +78,6 @@ #define FEPTIMEOUT 200000 #define SERIAL_TYPE_NORMAL 1 -#define SERIAL_TYPE_CALLOUT 2 #define SERIAL_TYPE_INFO 3 #define EPCA_EVENT_HANGUP 1 #define EPCA_MAGIC 0x5c6df104L @@ -124,8 +123,6 @@ ulong event; int asyncflags; uint dev; - long session; - long pgrp; ulong statusflags; ulong c_iflag; ulong c_cflag; @@ -139,7 +136,6 @@ struct digi_struct digiext; struct tty_struct *tty; struct termios normal_termios; - struct termios callout_termios; wait_queue_head_t open_wait; wait_queue_head_t close_wait; struct work_struct tqueue; diff -Nru a/drivers/char/esp.c b/drivers/char/esp.c --- a/drivers/char/esp.c Mon Jun 9 23:16:05 2003 +++ b/drivers/char/esp.c Mon Jun 9 23:16:05 2003 @@ -109,12 +109,11 @@ static DECLARE_TASK_QUEUE(tq_esp); -static struct tty_driver esp_driver, esp_callout_driver; +static struct tty_driver esp_driver; static int serial_refcount; /* serial subtype definitions */ #define SERIAL_TYPE_NORMAL 1 -#define SERIAL_TYPE_CALLOUT 2 /* * Serial driver configuration section. Here are the various options: @@ -638,8 +637,7 @@ #endif if (status & UART_MSR_DCD) wake_up_interruptible(&info->open_wait); - else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_CALLOUT_NOHUP))) { + else { #ifdef SERIAL_DEBUG_OPEN printk("scheduling hangup..."); #endif @@ -2077,8 +2075,6 @@ */ if (info->flags & ASYNC_NORMAL_ACTIVE) info->normal_termios = *tty->termios; - if (info->flags & ASYNC_CALLOUT_ACTIVE) - info->callout_termios = *tty->termios; /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. @@ -2126,8 +2122,7 @@ } wake_up_interruptible(&info->open_wait); } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| - ASYNC_CLOSING); + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); out: restore_flags(flags); @@ -2185,7 +2180,7 @@ shutdown(info); info->event = 0; info->count = 0; - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->flags &= ~ASYNC_NORMAL_ACTIVE; info->tty = 0; wake_up_interruptible(&info->open_wait); } @@ -2222,44 +2217,18 @@ } /* - * If this is a callout device, then just make sure the normal - * device isn't being used. - */ - if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) { - if (info->flags & ASYNC_NORMAL_ACTIVE) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_SESSION_LOCKOUT) && - (info->session != current->session)) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_PGRP_LOCKOUT) && - (info->pgrp != current->pgrp)) - return -EBUSY; - info->flags |= ASYNC_CALLOUT_ACTIVE; - return 0; - } - - /* * If non-blocking mode is set, or the port is not enabled, * then make the check up front and then exit. */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { - if (info->flags & ASYNC_CALLOUT_ACTIVE) - return -EBUSY; info->flags |= ASYNC_NORMAL_ACTIVE; return 0; } - if (info->flags & ASYNC_CALLOUT_ACTIVE) { - if (info->normal_termios.c_cflag & CLOCAL) - do_clocal = 1; - } else { - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - } - + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + /* * Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). While we are in @@ -2282,8 +2251,7 @@ while (1) { save_flags(flags); cli(); - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - (tty->termios->c_cflag & CBAUD)) { + if ((tty->termios->c_cflag & CBAUD)) { unsigned int scratch; serial_out(info, UART_ESI_CMD1, ESI_READ_UART); @@ -2313,8 +2281,7 @@ if (serial_in(info, UART_ESI_STAT2) & UART_MSR_DCD) do_clocal = 1; - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - !(info->flags & ASYNC_CLOSING) && + if (!(info->flags & ASYNC_CLOSING) && (do_clocal)) break; if (signal_pending(current)) { @@ -2399,16 +2366,10 @@ } if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver->subtype == SERIAL_TYPE_NORMAL) - *tty->termios = info->normal_termios; - else - *tty->termios = info->callout_termios; + *tty->termios = info->normal_termios; change_speed(info); } - info->session = current->session; - info->pgrp = current->pgrp; - #ifdef SERIAL_DEBUG_OPEN printk("esp_open %s successful...", tty->name); #endif @@ -2581,35 +2542,18 @@ esp_driver.break_ctl = esp_break; esp_driver.wait_until_sent = rs_wait_until_sent; - /* - * The callout device is just like normal device except for - * major number and the subtype code. - */ - esp_callout_driver = esp_driver; - esp_callout_driver.name = "cup"; - esp_callout_driver.major = ESP_OUT_MAJOR; - esp_callout_driver.subtype = SERIAL_TYPE_CALLOUT; - if (tty_register_driver(&esp_driver)) { printk(KERN_ERR "Couldn't register esp serial driver"); return 1; } - if (tty_register_driver(&esp_callout_driver)) - { - printk(KERN_ERR "Couldn't register esp callout driver"); - tty_unregister_driver(&esp_driver); - return 1; - } - info = kmalloc(sizeof(struct esp_struct), GFP_KERNEL); if (!info) { printk(KERN_ERR "Couldn't allocate memory for esp serial device information\n"); tty_unregister_driver(&esp_driver); - tty_unregister_driver(&esp_callout_driver); return 1; } @@ -2643,7 +2587,6 @@ info->tqueue.data = info; info->tqueue_hangup.routine = do_serial_hangup; info->tqueue_hangup.data = info; - info->callout_termios = esp_callout_driver.init_termios; info->normal_termios = esp_driver.init_termios; info->config.rx_timeout = rx_timeout; info->config.flow_on = flow_on; @@ -2717,9 +2660,6 @@ if ((e1 = tty_unregister_driver(&esp_driver))) printk("SERIAL: failed to unregister serial driver (%d)\n", e1); - if ((e2 = tty_unregister_driver(&esp_callout_driver))) - printk("SERIAL: failed to unregister callout driver (%d)\n", - e2); restore_flags(flags); while (ports) { diff -Nru a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c --- a/drivers/char/generic_serial.c Mon Jun 9 23:16:12 2003 +++ b/drivers/char/generic_serial.c Mon Jun 9 23:16:12 2003 @@ -554,7 +554,7 @@ return; gs_shutdown_port (port); - port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE |GS_ACTIVE); + port->flags &= ~(ASYNC_NORMAL_ACTIVE|GS_ACTIVE); port->tty = NULL; port->count = 0; @@ -619,47 +619,19 @@ gs_dprintk (GS_DEBUG_BTR, "after hung up\n"); /* - * If this is a callout device, then just make sure the normal - * device isn't being used. - */ - if (tty->driver->subtype == GS_TYPE_CALLOUT) { - if (port->flags & ASYNC_NORMAL_ACTIVE) - return -EBUSY; - if ((port->flags & ASYNC_CALLOUT_ACTIVE) && - (port->flags & ASYNC_SESSION_LOCKOUT) && - (port->session != current->session)) - return -EBUSY; - if ((port->flags & ASYNC_CALLOUT_ACTIVE) && - (port->flags & ASYNC_PGRP_LOCKOUT) && - (port->pgrp != current->pgrp)) - return -EBUSY; - port->flags |= ASYNC_CALLOUT_ACTIVE; - return 0; - } - - gs_dprintk (GS_DEBUG_BTR, "after subtype\n"); - - /* * If non-blocking mode is set, or the port is not enabled, * then make the check up front and then exit. */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { - if (port->flags & ASYNC_CALLOUT_ACTIVE) - return -EBUSY; port->flags |= ASYNC_NORMAL_ACTIVE; return 0; } gs_dprintk (GS_DEBUG_BTR, "after nonblock\n"); - if (port->flags & ASYNC_CALLOUT_ACTIVE) { - if (port->normal_termios.c_cflag & CLOCAL) - do_clocal = 1; - } else { - if (C_CLOCAL(tty)) - do_clocal = 1; - } + if (C_CLOCAL(tty)) + do_clocal = 1; /* * Block waiting for the carrier detect and the line to become @@ -690,8 +662,7 @@ retval = -ERESTARTSYS; break; } - if (!(port->flags & ASYNC_CALLOUT_ACTIVE) && - !(port->flags & ASYNC_CLOSING) && + if (!(port->flags & ASYNC_CLOSING) && (do_clocal || CD)) break; gs_dprintk (GS_DEBUG_BTR, "signal_pending is now: %d (%lx)\n", @@ -769,8 +740,6 @@ */ if (port->flags & ASYNC_NORMAL_ACTIVE) port->normal_termios = *tty->termios; - if (port->flags & ASYNC_CALLOUT_ACTIVE) - port->callout_termios = *tty->termios; /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. @@ -812,8 +781,7 @@ } wake_up_interruptible(&port->open_wait); } - port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| - ASYNC_CLOSING | ASYNC_INITIALIZED); + port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING | ASYNC_INITIALIZED); wake_up_interruptible(&port->close_wait); restore_flags(flags); diff -Nru a/drivers/char/hw_random.c b/drivers/char/hw_random.c --- a/drivers/char/hw_random.c Mon Jun 9 23:16:10 2003 +++ b/drivers/char/hw_random.c Mon Jun 9 23:16:10 2003 @@ -573,13 +573,13 @@ static int __init rng_init (void) { int rc; - struct pci_dev *pdev; + struct pci_dev *pdev = NULL; const struct pci_device_id *ent; DPRINTK ("ENTER\n"); /* Probe for Intel, AMD RNGs */ - pci_for_each_dev(pdev) { + while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { ent = pci_match_device (rng_pci_tbl, pdev); if (ent) { rng_ops = &rng_vendor_ops[ent->driver_data]; diff -Nru a/drivers/char/ip2/i2lib.c b/drivers/char/ip2/i2lib.c --- a/drivers/char/ip2/i2lib.c Mon Jun 9 23:16:19 2003 +++ b/drivers/char/ip2/i2lib.c Mon Jun 9 23:16:19 2003 @@ -326,8 +326,6 @@ pCh->speed = CBR_9600; pCh->flags = 0; - pCh->session = 0; - pCh->pgrp = 0; pCh->ClosingDelay = 5*HZ/10; pCh->ClosingWaitTime = 30*HZ; diff -Nru a/drivers/char/ip2/i2lib.h b/drivers/char/ip2/i2lib.h --- a/drivers/char/ip2/i2lib.h Mon Jun 9 23:16:09 2003 +++ b/drivers/char/ip2/i2lib.h Mon Jun 9 23:16:09 2003 @@ -92,8 +92,6 @@ int throttled; // Set if upper layer can take no data int flags; // Defined in tty.h - int session; // Defined in tty.h - int pgrp; // Defined in tty.h PWAITQ open_wait; // Pointer for OS sleep function. PWAITQ close_wait; // Pointer for OS sleep function. @@ -104,7 +102,6 @@ wait_queue_head_t pBookmarkWait; // Used by i2DrainOutput struct termios NormalTermios; - struct termios CalloutTermios; int BaudBase; int BaudDivisor; diff -Nru a/drivers/char/ip2main.c b/drivers/char/ip2main.c --- a/drivers/char/ip2main.c Mon Jun 9 23:16:20 2003 +++ b/drivers/char/ip2main.c Mon Jun 9 23:16:20 2003 @@ -94,9 +94,7 @@ #include <linux/module.h> #include <linux/signal.h> #include <linux/sched.h> -#ifdef CONFIG_DEVFS_FS #include <linux/devfs_fs_kernel.h> -#endif #include <linux/timer.h> #include <linux/interrupt.h> #include <linux/pci.h> @@ -194,7 +192,6 @@ #define ioremap(a,b) vremap((a),(b)) #define iounmap(a) vfree((a)) #define SERIAL_TYPE_NORMAL 1 -#define SERIAL_TYPE_CALLOUT 2 #define schedule_timeout(a){current->timeout = jiffies + (a); schedule();} #define signal_pending(a) ((a)->signal & ~(a)->blocked) #define in_interrupt() intr_count @@ -230,18 +227,10 @@ /* String constants for port names */ static char *pcDriver_name = "ip2"; -#ifdef CONFIG_DEVFS_FS -static char *pcTty = "tts/F%d"; -static char *pcCallout = "cua/F%d"; -#else -static char *pcTty = "ttyF"; -static char *pcCallout = "cuf"; -#endif static char *pcIpl = "ip2ipl"; /* Serial subtype definitions */ #define SERIAL_TYPE_NORMAL 1 -#define SERIAL_TYPE_CALLOUT 2 // cheezy kludge or genius - you decide? int ip2_loadmain(int *, int *, unsigned char *, int); @@ -307,7 +296,6 @@ /***************/ static struct tty_driver ip2_tty_driver; -static struct tty_driver ip2_callout_driver; static int ref_count; @@ -523,9 +511,6 @@ if ( ( err = tty_unregister_driver ( &ip2_tty_driver ) ) ) { printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", err); } - if ( ( err = tty_unregister_driver ( &ip2_callout_driver ) ) ) { - printk(KERN_ERR "IP2: failed to unregister callout driver (%d)\n", err); - } if ( ( err = unregister_chrdev ( IP2_IPL_MAJOR, pcIpl ) ) ) { printk(KERN_ERR "IP2: failed to unregister IPL driver (%d)\n", err); } @@ -572,10 +557,7 @@ int ip2_loadmain(int *iop, int *irqp, unsigned char *firmware, int firmsize) { -#ifdef CONFIG_DEVFS_FS - int j, box; -#endif - int i; + int i, j, box; int err; int status = 0; static int loaded; @@ -794,7 +776,8 @@ /* Initialise the relevant fields. */ ip2_tty_driver.magic = TTY_DRIVER_MAGIC; ip2_tty_driver.owner = THIS_MODULE; - ip2_tty_driver.name = pcTty; + ip2_tty_driver.name = "ttyF"; + ip2_tty_driver.devfs_name = "tts/F"; #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0) ip2_tty_driver.driver_name = pcDriver_name; ip2_tty_driver.read_proc = ip2_read_proc; @@ -806,11 +789,7 @@ ip2_tty_driver.subtype = SERIAL_TYPE_NORMAL; ip2_tty_driver.init_termios = tty_std_termios; ip2_tty_driver.init_termios.c_cflag = B9600|CS8|CREAD|HUPCL|CLOCAL; -#ifdef CONFIG_DEVFS_FS ip2_tty_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; -#else - ip2_tty_driver.flags = TTY_DRIVER_REAL_RAW; -#endif ip2_tty_driver.refcount = &ref_count; ip2_tty_driver.table = TtyTable; ip2_tty_driver.termios = Termios; @@ -834,27 +813,12 @@ ip2_tty_driver.start = ip2_start; ip2_tty_driver.hangup = ip2_hangup; - /* Initialise the callout driver structure from the tty driver, and - * make the needed adjustments. - */ - ip2_callout_driver = ip2_tty_driver; - ip2_callout_driver.name = pcCallout; -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0) - ip2_callout_driver.driver_name = pcDriver_name; - ip2_callout_driver.read_proc = NULL; -#endif - ip2_callout_driver.major = IP2_CALLOUT_MAJOR; - ip2_callout_driver.subtype = SERIAL_TYPE_CALLOUT; - ip2trace (ITRC_NO_PORT, ITRC_INIT, 3, 0 ); /* Register the tty devices. */ if ( ( err = tty_register_driver ( &ip2_tty_driver ) ) ) { printk(KERN_ERR "IP2: failed to register tty driver (%d)\n", err); } else - if ( ( err = tty_register_driver ( &ip2_callout_driver ) ) ) { - printk(KERN_ERR "IP2: failed to register callout driver (%d)\n", err); - } else /* Register the IPL driver. */ if ( ( err = register_chrdev ( IP2_IPL_MAJOR, pcIpl, &ip2_ipl ) ) ) { printk(KERN_ERR "IP2: failed to register IPL device (%d)\n", err ); @@ -874,7 +838,6 @@ continue; } -#ifdef CONFIG_DEVFS_FS if ( NULL != ( pB = i2BoardPtrTable[i] ) ) { devfs_mk_cdev(MKDEV(IP2_IPL_MAJOR, 4 * i), S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR, @@ -893,14 +856,10 @@ tty_register_device(&ip2_tty_driver, j + ABS_BIGGEST_BOX * (box+i*ABS_MAX_BOXES), NULL); - tty_register_device(&ip2_callout_driver, - j + ABS_BIGGEST_BOX * - (box+i*ABS_MAX_BOXES), NULL); } } } } -#endif if (poll_only) { // Poll only forces driver to only use polling and @@ -1497,7 +1456,7 @@ if ( pCh->wopen ) { wake_up_interruptible ( &pCh->open_wait ); } - } else if ( !(pCh->flags & ASYNC_CALLOUT_ACTIVE) ) { + } else { if (pCh->pTTY && (!(pCh->pTTY->termios->c_cflag & CLOCAL)) ) { tty_hangup( pCh->pTTY ); } @@ -1603,35 +1562,9 @@ remove_wait_queue(&pCh->close_wait, &wait); /* - * 2. If this is a callout device, make sure the normal port is not in - * use, and that someone else doesn't have the callout device locked. - * (These are the only tests the standard serial driver makes for - * callout devices.) - */ - if ( tty->driver->subtype == SERIAL_TYPE_CALLOUT ) { - if ( pCh->flags & ASYNC_NORMAL_ACTIVE ) { - return -EBUSY; - } - if ( ( pCh->flags & ASYNC_CALLOUT_ACTIVE ) && - ( pCh->flags & ASYNC_SESSION_LOCKOUT ) && - ( pCh->session != current->session ) ) { - return -EBUSY; - } - if ( ( pCh->flags & ASYNC_CALLOUT_ACTIVE ) && - ( pCh->flags & ASYNC_PGRP_LOCKOUT ) && - ( pCh->pgrp != current->pgrp ) ) { - return -EBUSY; - } - pCh->flags |= ASYNC_CALLOUT_ACTIVE; - goto noblock; - } - /* * 3. Handle a non-blocking open of a normal port. */ if ( (pFile->f_flags & O_NONBLOCK) || (tty->flags & (1<<TTY_IO_ERROR) )) { - if ( pCh->flags & ASYNC_CALLOUT_ACTIVE ) { - return -EBUSY; - } pCh->flags |= ASYNC_NORMAL_ACTIVE; goto noblock; } @@ -1639,15 +1572,8 @@ * 4. Now loop waiting for the port to be free and carrier present * (if required). */ - if ( pCh->flags & ASYNC_CALLOUT_ACTIVE ) { - if ( pCh->NormalTermios.c_cflag & CLOCAL ) { - do_clocal = 1; - } - } else { - if ( tty->termios->c_cflag & CLOCAL ) { - do_clocal = 1; - } - } + if ( tty->termios->c_cflag & CLOCAL ) + do_clocal = 1; #ifdef IP2DEBUG_OPEN printk(KERN_DEBUG "OpenBlock: do_clocal = %d\n", do_clocal); @@ -1659,32 +1585,27 @@ add_wait_queue(&pCh->open_wait, &wait); for(;;) { - if ( !(pCh->flags & ASYNC_CALLOUT_ACTIVE)) { - i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_DTRUP, CMD_RTSUP); - pCh->dataSetOut |= (I2_DTR | I2_RTS); - set_current_state( TASK_INTERRUPTIBLE ); - serviceOutgoingFifo( pCh->pMyBord ); - } + i2QueueCommands(PTYPE_INLINE, pCh, 100, 2, CMD_DTRUP, CMD_RTSUP); + pCh->dataSetOut |= (I2_DTR | I2_RTS); + set_current_state( TASK_INTERRUPTIBLE ); + serviceOutgoingFifo( pCh->pMyBord ); if ( tty_hung_up_p(pFile) ) { set_current_state( TASK_RUNNING ); remove_wait_queue(&pCh->open_wait, &wait); return ( pCh->flags & ASYNC_HUP_NOTIFY ) ? -EBUSY : -ERESTARTSYS; } - if ( !(pCh->flags & ASYNC_CALLOUT_ACTIVE) && - !(pCh->flags & ASYNC_CLOSING) && + if (!(pCh->flags & ASYNC_CLOSING) && (do_clocal || (pCh->dataSetIn & I2_DCD) )) { rc = 0; break; } #ifdef IP2DEBUG_OPEN - printk(KERN_DEBUG "ASYNC_CALLOUT_ACTIVE = %s\n", - (pCh->flags & ASYNC_CALLOUT_ACTIVE)?"True":"False"); printk(KERN_DEBUG "ASYNC_CLOSING = %s\n", (pCh->flags & ASYNC_CLOSING)?"True":"False"); printk(KERN_DEBUG "OpenBlock: waiting for CD or signal\n"); #endif - ip2trace (CHANN, ITRC_OPEN, 3, 2, (pCh->flags & ASYNC_CALLOUT_ACTIVE), + ip2trace (CHANN, ITRC_OPEN, 3, 2, 0, (pCh->flags & ASYNC_CLOSING) ); /* check for signal */ if (signal_pending(current)) { @@ -1711,20 +1632,12 @@ if ( tty->count == 1 ) { i2QueueCommands(PTYPE_INLINE, pCh, 0, 2, CMD_CTSFL_DSAB, CMD_RTSFL_DSAB); if ( pCh->flags & ASYNC_SPLIT_TERMIOS ) { - if ( tty->driver->subtype == SERIAL_TYPE_NORMAL ) { - *tty->termios = pCh->NormalTermios; - } else { - *tty->termios = pCh->CalloutTermios; - } + *tty->termios = pCh->NormalTermios; } /* Now we must send the termios settings to the loadware */ set_params( pCh, NULL ); } - /* override previous and never reset ??? */ - pCh->session = current->session; - pCh->pgrp = current->pgrp; - /* * Now set any i2lib options. These may go away if the i2lib code ends * up rolled into the mainline. @@ -1786,8 +1699,6 @@ */ if (pCh->flags & ASYNC_NORMAL_ACTIVE) pCh->NormalTermios = *tty->termios; - if (pCh->flags & ASYNC_CALLOUT_ACTIVE) - pCh->CalloutTermios = *tty->termios; tty->closing = 1; @@ -1833,7 +1744,7 @@ wake_up_interruptible(&pCh->open_wait); } - pCh->flags &=~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|ASYNC_CLOSING); + pCh->flags &=~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&pCh->close_wait); #ifdef IP2DEBUG_OPEN @@ -1883,7 +1794,7 @@ wake_up_interruptible ( &pCh->delta_msr_wait ); - pCh->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + pCh->flags &= ~ASYNC_NORMAL_ACTIVE; pCh->pTTY = NULL; wake_up_interruptible ( &pCh->open_wait ); diff -Nru a/drivers/char/isicom.c b/drivers/char/isicom.c --- a/drivers/char/isicom.c Mon Jun 9 23:16:05 2003 +++ b/drivers/char/isicom.c Mon Jun 9 23:16:05 2003 @@ -76,7 +76,7 @@ static int isicom_refcount; static int prev_card = 3; /* start servicing isi_card[0] */ static struct isi_board * irq_to_board[16]; -static struct tty_driver isicom_normal, isicom_callout; +static struct tty_driver isicom_normal; static struct tty_struct * isicom_table[PORT_COUNT]; static struct termios * isicom_termios[PORT_COUNT]; static struct termios * isicom_termios_locked[PORT_COUNT]; @@ -588,10 +588,7 @@ printk(KERN_DEBUG "ISICOM: interrupt: DCD->low.\n"); #endif port->status &= ~ISI_DCD; - if (!((port->flags & ASYNC_CALLOUT_ACTIVE) && - (port->flags & ASYNC_CALLOUT_NOHUP))) { - schedule_task(&port->hangup_tq); - } + schedule_task(&port->hangup_tq); } } else { @@ -903,49 +900,18 @@ return -ERESTARTSYS; } - /* trying to open a callout device... check for constraints */ - - if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) { -#ifdef ISICOM_DEBUG - printk(KERN_DEBUG "ISICOM: bl_ti_rdy: callout open.\n"); -#endif - if (port->flags & ASYNC_NORMAL_ACTIVE) - return -EBUSY; - if ((port->flags & ASYNC_CALLOUT_ACTIVE) && - (port->flags & ASYNC_SESSION_LOCKOUT) && - (port->session != current->session)) - return -EBUSY; - - if ((port->flags & ASYNC_CALLOUT_ACTIVE) && - (port->flags & ASYNC_PGRP_LOCKOUT) && - (port->pgrp != current->pgrp)) - return -EBUSY; - port->flags |= ASYNC_CALLOUT_ACTIVE; - cli(); - raise_dtr_rts(port); - sti(); - return 0; - } - /* if non-blocking mode is set ... */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { #ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: block_til_ready: non-block mode.\n"); #endif - if (port->flags & ASYNC_CALLOUT_ACTIVE) - return -EBUSY; port->flags |= ASYNC_NORMAL_ACTIVE; return 0; } - if (port->flags & ASYNC_CALLOUT_ACTIVE) { - if (port->normal_termios.c_cflag & CLOCAL) - do_clocal = 1; - } else { - if (C_CLOCAL(tty)) - do_clocal = 1; - } + if (C_CLOCAL(tty)) + do_clocal = 1; #ifdef ISICOM_DEBUG if (do_clocal) printk(KERN_DEBUG "ISICOM: block_til_ready: CLOCAL set.\n"); @@ -965,9 +931,7 @@ #endif while (1) { cli(); - if (!(port->flags & ASYNC_CALLOUT_ACTIVE)) - raise_dtr_rts(port); - + raise_dtr_rts(port); sti(); set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) { @@ -980,8 +944,7 @@ #endif break; } - if (!(port->flags & ASYNC_CALLOUT_ACTIVE) && - !(port->flags & ASYNC_CLOSING) && + if (!(port->flags & ASYNC_CLOSING) && (do_clocal || (port->status & ISI_DCD))) { #ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: block_til_ready: do_clocal || DCD.\n"); @@ -1070,17 +1033,12 @@ return error; if ((port->count == 1) && (port->flags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver->subtype == SERIAL_TYPE_NORMAL) - *tty->termios = port->normal_termios; - else - *tty->termios = port->callout_termios; + *tty->termios = port->normal_termios; save_flags(flags); cli(); isicom_config_port(port); restore_flags(flags); } - port->session = current->session; - port->pgrp = current->pgrp; #ifdef ISICOM_DEBUG printk(KERN_DEBUG "ISICOM: open end!!!.\n"); #endif @@ -1180,8 +1138,6 @@ */ if (port->flags & ASYNC_NORMAL_ACTIVE) port->normal_termios = *tty->termios; - if (port->flags & ASYNC_CALLOUT_ACTIVE) - port->callout_termios = *tty->termios; tty->closing = 1; if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE) @@ -1209,8 +1165,7 @@ } wake_up_interruptible(&port->open_wait); } - port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE | - ASYNC_CLOSING); + port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING); wake_up_interruptible(&port->close_wait); restore_flags(flags); #ifdef ISICOM_DEBUG @@ -1651,7 +1606,7 @@ isicom_shutdown_port(port); port->count = 0; - port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE); + port->flags &= ~ASYNC_NORMAL_ACTIVE; port->tty = 0; wake_up_interruptible(&port->open_wait); } @@ -1743,32 +1698,17 @@ isicom_normal.hangup = isicom_hangup; isicom_normal.flush_buffer = isicom_flush_buffer; - /* callout device */ - - isicom_callout = isicom_normal; - isicom_callout.name = "cum"; - isicom_callout.major = ISICOM_CMAJOR; - isicom_callout.subtype = SERIAL_TYPE_CALLOUT; - if ((error=tty_register_driver(&isicom_normal))!=0) { printk(KERN_DEBUG "ISICOM: Couldn't register the dialin driver, error=%d\n", error); return error; } - if ((error=tty_register_driver(&isicom_callout))!=0) { - tty_unregister_driver(&isicom_normal); - printk(KERN_DEBUG "ISICOM: Couldn't register the callout driver, error=%d\n", - error); - return error; - } return 0; } static void unregister_drivers(void) { int error; - if ((error=tty_unregister_driver(&isicom_callout))!=0) - printk(KERN_DEBUG "ISICOM: couldn't unregister callout driver error=%d.\n",error); if (tty_unregister_driver(&isicom_normal)) printk(KERN_DEBUG "ISICOM: couldn't unregister normal driver error=%d.\n",error); } @@ -1897,7 +1837,6 @@ port->card = &isi_card[card]; port->channel = channel; port->normal_termios = isicom_normal.init_termios; - port->callout_termios = isicom_callout.init_termios; port->close_delay = 50 * HZ/100; port->closing_wait = 3000 * HZ/100; port->hangup_tq.routine = do_isicom_hangup; diff -Nru a/drivers/char/istallion.c b/drivers/char/istallion.c --- a/drivers/char/istallion.c Mon Jun 9 23:16:14 2003 +++ b/drivers/char/istallion.c Mon Jun 9 23:16:14 2003 @@ -159,9 +159,6 @@ #define STL_CALLOUTMAJOR 25 #endif -#define STL_DRVTYPSERIAL 1 -#define STL_DRVTYPCALLOUT 2 - /*****************************************************************************/ /* @@ -172,10 +169,8 @@ static char *stli_drvname = "istallion"; static char *stli_drvversion = "5.6.0"; static char *stli_serialname = "ttyE"; -static char *stli_calloutname = "cue"; static struct tty_driver stli_serial; -static struct tty_driver stli_callout; static struct tty_struct *stli_ttys[STL_MAXDEVS]; static struct termios *stli_termios[STL_MAXDEVS]; static struct termios *stli_termioslocked[STL_MAXDEVS]; @@ -857,10 +852,9 @@ } i = tty_unregister_driver(&stli_serial); - j = tty_unregister_driver(&stli_callout); - if (i || j) { + if (i) { printk("STALLION: failed to un-register tty driver, " - "errno=%d,%d\n", -i, -j); + "errno=%d,%d\n", -i); restore_flags(flags); return; } @@ -1114,39 +1108,16 @@ * previous opens still in effect. If we are a normal serial device * then also we might have to wait for carrier. */ - if (tty->driver->subtype == STL_DRVTYPCALLOUT) { - if (portp->flags & ASYNC_NORMAL_ACTIVE) - return(-EBUSY); - if (portp->flags & ASYNC_CALLOUT_ACTIVE) { - if ((portp->flags & ASYNC_SESSION_LOCKOUT) && - (portp->session != current->session)) - return(-EBUSY); - if ((portp->flags & ASYNC_PGRP_LOCKOUT) && - (portp->pgrp != current->pgrp)) - return(-EBUSY); - } - portp->flags |= ASYNC_CALLOUT_ACTIVE; - } else { - if (filp->f_flags & O_NONBLOCK) { - if (portp->flags & ASYNC_CALLOUT_ACTIVE) - return(-EBUSY); - } else { - if ((rc = stli_waitcarrier(brdp, portp, filp)) != 0) - return(rc); - } - portp->flags |= ASYNC_NORMAL_ACTIVE; + if (!(filp->f_flags & O_NONBLOCK)) { + if ((rc = stli_waitcarrier(brdp, portp, filp)) != 0) + return(rc); } + portp->flags |= ASYNC_NORMAL_ACTIVE; if ((portp->refcount == 1) && (portp->flags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver->subtype == STL_DRVTYPSERIAL) - *tty->termios = portp->normaltermios; - else - *tty->termios = portp->callouttermios; + *tty->termios = portp->normaltermios; stli_setport(portp); } - - portp->session = current->session; - portp->pgrp = current->pgrp; return(0); } @@ -1183,8 +1154,6 @@ if (portp->flags & ASYNC_NORMAL_ACTIVE) portp->normaltermios = *tty->termios; - if (portp->flags & ASYNC_CALLOUT_ACTIVE) - portp->callouttermios = *tty->termios; /* * May want to wait for data to drain before closing. The BUSY flag @@ -1226,8 +1195,7 @@ wake_up_interruptible(&portp->open_wait); } - portp->flags &= ~(ASYNC_CALLOUT_ACTIVE | ASYNC_NORMAL_ACTIVE | - ASYNC_CLOSING); + portp->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&portp->close_wait); restore_flags(flags); } @@ -1558,13 +1526,8 @@ rc = 0; doclocal = 0; - if (portp->flags & ASYNC_CALLOUT_ACTIVE) { - if (portp->normaltermios.c_cflag & CLOCAL) - doclocal++; - } else { - if (portp->tty->termios->c_cflag & CLOCAL) - doclocal++; - } + if (portp->tty->termios->c_cflag & CLOCAL) + doclocal++; save_flags(flags); cli(); @@ -1573,12 +1536,10 @@ portp->refcount--; for (;;) { - if ((portp->flags & ASYNC_CALLOUT_ACTIVE) == 0) { - stli_mkasysigs(&portp->asig, 1, 1); - if ((rc = stli_cmdwait(brdp, portp, A_SETSIGNALS, - &portp->asig, sizeof(asysigs_t), 0)) < 0) - break; - } + stli_mkasysigs(&portp->asig, 1, 1); + if ((rc = stli_cmdwait(brdp, portp, A_SETSIGNALS, + &portp->asig, sizeof(asysigs_t), 0)) < 0) + break; if (tty_hung_up_p(filp) || ((portp->flags & ASYNC_INITIALIZED) == 0)) { if (portp->flags & ASYNC_HUP_NOTIFY) @@ -1587,8 +1548,7 @@ rc = -ERESTARTSYS; break; } - if (((portp->flags & ASYNC_CALLOUT_ACTIVE) == 0) && - ((portp->flags & ASYNC_CLOSING) == 0) && + if (((portp->flags & ASYNC_CLOSING) == 0) && (doclocal || (portp->sigs & TIOCM_CD))) { break; } @@ -2420,7 +2380,7 @@ clear_bit(ST_RXSTOP, &portp->state); set_bit(TTY_IO_ERROR, &tty->flags); portp->tty = (struct tty_struct *) NULL; - portp->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE); + portp->flags &= ~ASYNC_NORMAL_ACTIVE; portp->refcount = 0; wake_up_interruptible(&portp->open_wait); } @@ -2996,12 +2956,8 @@ if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0)) { if (portp->flags & ASYNC_CHECK_CD) { - if (! ((portp->flags & ASYNC_CALLOUT_ACTIVE) && - (portp->flags & ASYNC_CALLOUT_NOHUP))) { - if (tty != (struct tty_struct *) NULL) { - schedule_task(&portp->tqhangup); - } - } + if (tty) + schedule_task(&portp->tqhangup); } } } @@ -3370,7 +3326,6 @@ init_waitqueue_head(&portp->close_wait); init_waitqueue_head(&portp->raw_wait); portp->normaltermios = stli_deftermios; - portp->callouttermios = stli_deftermios; panelport++; if (panelport >= brdp->panels[panelnr]) { panelport = 0; @@ -5336,7 +5291,6 @@ /* * Set up the tty driver structure and register us as a driver. - * Also setup the callout tty device. */ memset(&stli_serial, 0, sizeof(struct tty_driver)); stli_serial.magic = TTY_DRIVER_MAGIC; @@ -5347,7 +5301,7 @@ stli_serial.minor_start = 0; stli_serial.num = STL_MAXBRDS * STL_MAXPORTS; stli_serial.type = TTY_DRIVER_TYPE_SERIAL; - stli_serial.subtype = STL_DRVTYPSERIAL; + stli_serial.subtype = SERIAL_TYPE_NORMAL; stli_serial.init_termios = stli_deftermios; stli_serial.flags = TTY_DRIVER_REAL_RAW; stli_serial.refcount = &stli_refcount; @@ -5375,17 +5329,8 @@ stli_serial.send_xchar = stli_sendxchar; stli_serial.read_proc = stli_readproc; - stli_callout = stli_serial; - stli_callout.name = stli_calloutname; - stli_callout.major = STL_CALLOUTMAJOR; - stli_callout.subtype = STL_DRVTYPCALLOUT; - stli_callout.read_proc = 0; - if (tty_register_driver(&stli_serial)) printk(KERN_ERR "STALLION: failed to register serial driver\n"); - if (tty_register_driver(&stli_callout)) - printk(KERN_ERR "STALLION: failed to register callout driver\n"); - return(0); } diff -Nru a/drivers/char/mem.c b/drivers/char/mem.c --- a/drivers/char/mem.c Mon Jun 9 23:16:12 2003 +++ b/drivers/char/mem.c Mon Jun 9 23:16:12 2003 @@ -23,6 +23,7 @@ #include <linux/capability.h> #include <linux/smp_lock.h> #include <linux/devfs_fs_kernel.h> +#include <linux/ptrace.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -524,20 +525,22 @@ { loff_t ret; - lock_kernel(); + down(&file->f_dentry->d_inode->i_sem); switch (orig) { case 0: file->f_pos = offset; ret = file->f_pos; + force_successful_syscall_return(); break; case 1: file->f_pos += offset; ret = file->f_pos; + force_successful_syscall_return(); break; default: ret = -EINVAL; } - unlock_kernel(); + up(&file->f_dentry->d_inode->i_sem); return ret; } @@ -710,4 +713,4 @@ return 0; } -__initcall(chr_dev_init); +subsys_initcall(chr_dev_init); diff -Nru a/drivers/char/moxa.c b/drivers/char/moxa.c --- a/drivers/char/moxa.c Mon Jun 9 23:16:18 2003 +++ b/drivers/char/moxa.c Mon Jun 9 23:16:18 2003 @@ -151,12 +151,9 @@ int blocked_open; long event; /* long req'd for set_bit --RR */ int asyncflags; - long session; - long pgrp; unsigned long statusflags; struct tty_struct *tty; struct termios normal_termios; - struct termios callout_termios; wait_queue_head_t open_wait; wait_queue_head_t close_wait; struct work_struct tqueue; @@ -185,7 +182,6 @@ #define SERIAL_TYPE_NORMAL 1 -#define SERIAL_TYPE_CALLOUT 2 #define WAKEUP_CHARS 256 @@ -193,7 +189,6 @@ static int verbose = 0; static int ttymajor = MOXAMAJOR; -static int calloutmajor = MOXACUMAJOR; #ifdef MODULE /* Variables for insmod */ static int baseaddr[] = {0, 0, 0, 0}; @@ -207,13 +202,11 @@ MODULE_PARM(baseaddr, "1-4i"); MODULE_PARM(numports, "1-4i"); MODULE_PARM(ttymajor, "i"); -MODULE_PARM(calloutmajor, "i"); MODULE_PARM(verbose, "i"); #endif //MODULE static struct tty_driver moxaDriver; -static struct tty_driver moxaCallout; static struct tty_struct *moxaTable[MAX_PORTS + 1]; static struct termios *moxaTermios[MAX_PORTS + 1]; static struct termios *moxaTermiosLocked[MAX_PORTS + 1]; @@ -319,8 +312,6 @@ if (moxaEmptyTimer_on[i]) del_timer(&moxaEmptyTimer[i]); - if (tty_unregister_driver(&moxaCallout)) - printk("Couldn't unregister MOXA Intellio family callout driver\n"); if (tty_unregister_driver(&moxaDriver)) printk("Couldn't unregister MOXA Intellio family serial driver\n"); if (verbose) @@ -339,7 +330,6 @@ init_MUTEX(&moxaBuffSem); memset(&moxaDriver, 0, sizeof(struct tty_driver)); - memset(&moxaCallout, 0, sizeof(struct tty_driver)); moxaDriver.magic = TTY_DRIVER_MAGIC; moxaDriver.owner = THIS_MODULE; moxaDriver.name = "ttya"; @@ -375,11 +365,6 @@ moxaDriver.start = moxa_start; moxaDriver.hangup = moxa_hangup; - moxaCallout = moxaDriver; - moxaCallout.name = "ttyA"; - moxaCallout.major = calloutmajor; - moxaCallout.subtype = SERIAL_TYPE_CALLOUT; - moxaXmitBuff = 0; for (i = 0, ch = moxaChannels; i < MAX_PORTS; i++, ch++) { @@ -391,7 +376,6 @@ ch->closing_wait = 30 * HZ; ch->count = 0; ch->blocked_open = 0; - ch->callout_termios = moxaCallout.init_termios; ch->normal_termios = moxaDriver.init_termios; init_waitqueue_head(&ch->open_wait); init_waitqueue_head(&ch->close_wait); @@ -406,17 +390,10 @@ moxa_boards[i].pciInfo.devNum = 0; } MoxaDriverInit(); - printk("Tty devices major number = %d, callout devices major number = %d\n", ttymajor, calloutmajor); + printk("Tty devices major number = %d\n", ttymajor); - ret1 = 0; - ret2 = 0; - if ((ret1 = tty_register_driver(&moxaDriver))) { + if (tty_register_driver(&moxaDriver)) { printk(KERN_ERR "Couldn't install MOXA Smartio family driver !\n"); - } else if ((ret2 = tty_register_driver(&moxaCallout))) { - tty_unregister_driver(&moxaDriver); - printk(KERN_ERR "Couldn't install MOXA Smartio family callout driver !\n"); - } - if (ret1 || ret2) { return -1; } for (i = 0; i < MAX_PORTS; i++) { @@ -542,7 +519,7 @@ if (test_and_clear_bit(MOXA_EVENT_HANGUP, &ch->event)) { tty_hangup(tty); /* FIXME: module removal race here - AKPM */ wake_up_interruptible(&ch->open_wait); - ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE); + ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE; } } } @@ -583,13 +560,8 @@ tty->driver_data = ch; ch->tty = tty; if (ch->count == 1 && (ch->asyncflags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver->subtype == SERIAL_TYPE_NORMAL) - *tty->termios = ch->normal_termios; - else - *tty->termios = ch->callout_termios; + *tty->termios = ch->normal_termios; } - ch->session = current->session; - ch->pgrp = current->pgrp; if (!(ch->asyncflags & ASYNC_INITIALIZED)) { ch->statusflags = 0; set_tty_param(tty); @@ -655,8 +627,6 @@ */ if (ch->asyncflags & ASYNC_NORMAL_ACTIVE) ch->normal_termios = *tty->termios; - if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE) - ch->callout_termios = *tty->termios; if (ch->asyncflags & ASYNC_INITIALIZED) { setup_empty_event(tty); tty_wait_until_sent(tty, 30 * HZ); /* 30 seconds timeout */ @@ -680,8 +650,7 @@ } wake_up_interruptible(&ch->open_wait); } - ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE | - ASYNC_CLOSING); + ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING); wake_up_interruptible(&ch->close_wait); } @@ -963,7 +932,7 @@ shut_down(ch); ch->event = 0; ch->count = 0; - ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE); + ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE; ch->tty = 0; wake_up_interruptible(&ch->open_wait); } @@ -1083,30 +1052,10 @@ #endif } /* - * If this is a callout device, then just make sure the normal - * device isn't being used. - */ - if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) { - if (ch->asyncflags & ASYNC_NORMAL_ACTIVE) - return (-EBUSY); - if ((ch->asyncflags & ASYNC_CALLOUT_ACTIVE) && - (ch->asyncflags & ASYNC_SESSION_LOCKOUT) && - (ch->session != current->session)) - return (-EBUSY); - if ((ch->asyncflags & ASYNC_CALLOUT_ACTIVE) && - (ch->asyncflags & ASYNC_PGRP_LOCKOUT) && - (ch->pgrp != current->pgrp)) - return (-EBUSY); - ch->asyncflags |= ASYNC_CALLOUT_ACTIVE; - return (0); - } - /* * If non-blocking mode is set, then make the check up front * and then exit. */ if (filp->f_flags & O_NONBLOCK) { - if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE) - return (-EBUSY); ch->asyncflags |= ASYNC_NORMAL_ACTIVE; return (0); } @@ -1139,8 +1088,7 @@ #endif break; } - if (!(ch->asyncflags & ASYNC_CALLOUT_ACTIVE) && - !(ch->asyncflags & ASYNC_CLOSING) && (do_clocal || + if (!(ch->asyncflags & ASYNC_CLOSING) && (do_clocal || MoxaPortDCDON(ch->port))) break; @@ -1717,7 +1665,8 @@ return -EFAULT; return 0; case MOXA_GET_CUMAJOR: - if(copy_to_user((void *)arg, &calloutmajor, sizeof(int))) + i = 0; + if(copy_to_user((void *)arg, &i, sizeof(int))) return -EFAULT; return 0; case MOXA_GETMSTATUS: diff -Nru a/drivers/char/mxser.c b/drivers/char/mxser.c --- a/drivers/char/mxser.c Mon Jun 9 23:16:15 2003 +++ b/drivers/char/mxser.c Mon Jun 9 23:16:15 2003 @@ -87,7 +87,6 @@ #define MXSER_ERR_VECTOR -4 #define SERIAL_TYPE_NORMAL 1 -#define SERIAL_TYPE_CALLOUT 2 #define WAKEUP_CHARS 256 @@ -208,7 +207,6 @@ static int ioaddr[MXSER_BOARDS]; static int ttymajor = MXSERMAJOR; -static int calloutmajor = MXSERCUMAJOR; static int verbose; /* Variables for insmod */ @@ -218,7 +216,6 @@ MODULE_LICENSE("GPL"); MODULE_PARM(ioaddr, "1-4i"); MODULE_PARM(ttymajor, "i"); -MODULE_PARM(calloutmajor, "i"); MODULE_PARM(verbose, "i"); struct mxser_hwconf { @@ -256,15 +253,12 @@ unsigned long event; int count; /* # of fd on device */ int blocked_open; /* # of blocked opens */ - long session; /* Session of opening process */ - long pgrp; /* pgrp of opening process */ unsigned char *xmit_buf; int xmit_head; int xmit_tail; int xmit_cnt; struct work_struct tqueue; struct termios normal_termios; - struct termios callout_termios; wait_queue_head_t open_wait; wait_queue_head_t close_wait; wait_queue_head_t delta_msr_wait; @@ -294,7 +288,7 @@ }; -static struct tty_driver mxvar_sdriver, mxvar_cdriver; +static struct tty_driver mxvar_sdriver; static int mxvar_refcount; static struct mxser_struct mxvar_table[MXSER_PORTS]; static struct tty_struct *mxvar_tty[MXSER_PORTS + 1]; @@ -374,8 +368,6 @@ if (verbose) printk("Unloading module mxser ...\n"); - if ((err |= tty_unregister_driver(&mxvar_cdriver))) - printk("Couldn't unregister MOXA Smartio family callout driver\n"); if ((err |= tty_unregister_driver(&mxvar_sdriver))) printk("Couldn't unregister MOXA Smartio family serial driver\n"); @@ -428,7 +420,6 @@ info->close_delay = 5 * HZ / 10; info->closing_wait = 30 * HZ; INIT_WORK(&info->tqueue, mxser_do_softint, info); - info->callout_termios = mxvar_cdriver.init_termios; info->normal_termios = mxvar_sdriver.init_termios; init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); @@ -532,16 +523,7 @@ mxvar_sdriver.start = mxser_start; mxvar_sdriver.hangup = mxser_hangup; - /* - * The callout device is just like normal device except for - * major number and the subtype code. - */ - mxvar_cdriver = mxvar_sdriver; - mxvar_cdriver.name = "cum"; - mxvar_cdriver.major = calloutmajor; - mxvar_cdriver.subtype = SERIAL_TYPE_CALLOUT; - - printk("Tty devices major number = %d, callout devices major number = %d\n", ttymajor, calloutmajor); + printk("Tty devices major number = %d\n", ttymajor); mxvar_diagflag = 0; memset(mxvar_table, 0, MXSER_PORTS * sizeof(struct mxser_struct)); @@ -666,30 +648,17 @@ } - ret1 = 0; - ret2 = 0; - if (!(ret1 = tty_register_driver(&mxvar_sdriver))) { - if (!(ret2 = tty_register_driver(&mxvar_cdriver))) { - return 0; - } else { - tty_unregister_driver(&mxvar_sdriver); - printk("Couldn't install MOXA Smartio family callout driver !\n"); - } - } else - printk("Couldn't install MOXA Smartio family driver !\n"); + if (!tty_register_driver(&mxvar_sdriver)) + return 0; + printk("Couldn't install MOXA Smartio family driver !\n"); - if (ret1 || ret2) { - for (i = 0; i < MXSER_BOARDS; i++) { - if (mxsercfg[i].board_type == -1) - continue; - else { - free_irq(mxsercfg[i].irq, &mxvar_table[i * MXSER_PORTS_PER_BOARD]); - } - } - return -1; + for (i = 0; i < MXSER_BOARDS; i++) { + if (mxsercfg[i].board_type == -1) + continue; + free_irq(mxsercfg[i].irq, &mxvar_table[i * MXSER_PORTS_PER_BOARD]); } - return (0); + return -1; } static void mxser_do_softint(void *private_) @@ -758,15 +727,9 @@ return (retval); if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver->subtype == SERIAL_TYPE_NORMAL) - *tty->termios = info->normal_termios; - else - *tty->termios = info->callout_termios; + *tty->termios = info->normal_termios; mxser_change_speed(info, 0); } - info->session = current->session; - info->pgrp = current->pgrp; - return (0); } @@ -823,8 +786,6 @@ */ if (info->flags & ASYNC_NORMAL_ACTIVE) info->normal_termios = *tty->termios; - if (info->flags & ASYNC_CALLOUT_ACTIVE) - info->callout_termios = *tty->termios; /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. @@ -872,8 +833,7 @@ } wake_up_interruptible(&info->open_wait); } - info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE | - ASYNC_CLOSING); + info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); restore_flags(flags); @@ -1154,7 +1114,8 @@ return 0; case MOXA_GET_CUMAJOR: - if(copy_to_user((int *) arg, &calloutmajor, sizeof(int))) + result = 0; + if(copy_to_user((int *) arg, &result, sizeof(int))) return -EFAULT; return 0; @@ -1349,7 +1310,7 @@ mxser_shutdown(info); info->event = 0; info->count = 0; - info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE); + info->flags &= ~ASYNC_NORMAL_ACTIVE; info->tty = 0; wake_up_interruptible(&info->open_wait); } @@ -1513,8 +1474,7 @@ if ((info->flags & ASYNC_CHECK_CD) && (status & UART_MSR_DDCD)) { if (status & UART_MSR_DCD) wake_up_interruptible(&info->open_wait); - else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_CALLOUT_NOHUP))) + else set_bit(MXSER_EVENT_HANGUP, &info->event); schedule_work(&info->tqueue); } @@ -1563,41 +1523,16 @@ #endif } /* - * If this is a callout device, then just make sure the normal - * device isn't being used. - */ - if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) { - if (info->flags & ASYNC_NORMAL_ACTIVE) - return (-EBUSY); - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_SESSION_LOCKOUT) && - (info->session != current->session)) - return (-EBUSY); - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_PGRP_LOCKOUT) && - (info->pgrp != current->pgrp)) - return (-EBUSY); - info->flags |= ASYNC_CALLOUT_ACTIVE; - return (0); - } - /* * If non-blocking mode is set, or the port is not enabled, * then make the check up front and then exit. */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { - if (info->flags & ASYNC_CALLOUT_ACTIVE) - return (-EBUSY); info->flags |= ASYNC_NORMAL_ACTIVE; return (0); } - if (info->flags & ASYNC_CALLOUT_ACTIVE) { - if (info->normal_termios.c_cflag & CLOCAL) - do_clocal = 1; - } else { - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - } + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; /* * Block waiting for the carrier detect and the line to become @@ -1617,9 +1552,8 @@ while (1) { save_flags(flags); cli(); - if (!(info->flags & ASYNC_CALLOUT_ACTIVE)) - outb(inb(info->base + UART_MCR) | UART_MCR_DTR | UART_MCR_RTS, - info->base + UART_MCR); + outb(inb(info->base + UART_MCR) | UART_MCR_DTR | UART_MCR_RTS, + info->base + UART_MCR); restore_flags(flags); set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)) { @@ -1633,8 +1567,7 @@ #endif break; } - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - !(info->flags & ASYNC_CLOSING) && + if (!(info->flags & ASYNC_CLOSING) && (do_clocal || (inb(info->base + UART_MSR) & UART_MSR_DCD))) break; if (signal_pending(current)) { diff -Nru a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c --- a/drivers/char/n_hdlc.c Mon Jun 9 23:16:09 2003 +++ b/drivers/char/n_hdlc.c Mon Jun 9 23:16:09 2003 @@ -6,7 +6,8 @@ * Microgate and SyncLink are registered trademarks of Microgate Corporation * * Adapted from ppp.c, written by Michael Callahan <callahan@maths.ox.ac.uk>, - * Al Longyear <longyear@netcom.com>, Paul Mackerras <Paul.Mackerras@cs.anu.edu.au> + * Al Longyear <longyear@netcom.com>, + * Paul Mackerras <Paul.Mackerras@cs.anu.edu.au> * * Original release 01/11/99 * $Id: n_hdlc.c,v 4.8 2003/05/06 21:18:51 paulkf Exp $ @@ -96,32 +97,19 @@ #include <linux/poll.h> #include <linux/in.h> +#include <linux/ioctl.h> #include <linux/slab.h> #include <linux/tty.h> #include <linux/errno.h> #include <linux/string.h> /* used in new tty drivers */ #include <linux/signal.h> /* used in new tty drivers */ +#include <linux/if.h> + #include <asm/system.h> #include <asm/bitops.h> #include <asm/termios.h> -#include <linux/if.h> - -#include <linux/ioctl.h> - -#ifdef CONFIG_KERNELD -#include <linux/kerneld.h> -#endif - -#define GET_USER(error,value,addr) error = get_user(value,addr) -#define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0 -#define PUT_USER(error,value,addr) error = put_user(value,addr) -#define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0 - #include <asm/uaccess.h> -typedef ssize_t rw_ret_t; -typedef size_t rw_count_t; - /* * Buffers for individual HDLC frames */ @@ -130,91 +118,90 @@ #define MAX_RX_BUF_COUNT 60 #define DEFAULT_TX_BUF_COUNT 1 +struct n_hdlc_buf { + struct n_hdlc_buf *link; + int count; + char buf[1]; +}; -typedef struct _n_hdlc_buf -{ - struct _n_hdlc_buf *link; - int count; - char buf[1]; -} N_HDLC_BUF; - -#define N_HDLC_BUF_SIZE (sizeof(N_HDLC_BUF)+maxframe) +#define N_HDLC_BUF_SIZE (sizeof(struct n_hdlc_buf) + maxframe) -typedef struct _n_hdlc_buf_list -{ - N_HDLC_BUF *head; - N_HDLC_BUF *tail; - int count; - spinlock_t spinlock; - -} N_HDLC_BUF_LIST; +struct n_hdlc_buf_list { + struct n_hdlc_buf *head; + struct n_hdlc_buf *tail; + int count; + spinlock_t spinlock; +}; -/* - * Per device instance data structure +/** + * struct n_hdlc - per device instance data structure + * @magic - magic value for structure + * @flags - miscellaneous control flags + * @tty - ptr to TTY structure + * @backup_tty - TTY to use if tty gets closed + * @tbusy - reentrancy flag for tx wakeup code + * @woke_up - FIXME: describe this field + * @tbuf - currently transmitting tx buffer + * @tx_buf_list - list of pending transmit frame buffers + * @rx_buf_list - list of received frame buffers + * @tx_free_buf_list - list unused transmit frame buffers + * @rx_free_buf_list - list unused received frame buffers */ struct n_hdlc { - int magic; /* magic value for structure */ - __u32 flags; /* miscellaneous control flags */ - - struct tty_struct *tty; /* ptr to TTY structure */ - struct tty_struct *backup_tty; /* TTY to use if tty gets closed */ - - int tbusy; /* reentrancy flag for tx wakeup code */ - int woke_up; - N_HDLC_BUF *tbuf; /* currently transmitting tx buffer */ - N_HDLC_BUF_LIST tx_buf_list; /* list of pending transmit frame buffers */ - N_HDLC_BUF_LIST rx_buf_list; /* list of received frame buffers */ - N_HDLC_BUF_LIST tx_free_buf_list; /* list unused transmit frame buffers */ - N_HDLC_BUF_LIST rx_free_buf_list; /* list unused received frame buffers */ + int magic; + __u32 flags; + struct tty_struct *tty; + struct tty_struct *backup_tty; + int tbusy; + int woke_up; + struct n_hdlc_buf *tbuf; + struct n_hdlc_buf_list tx_buf_list; + struct n_hdlc_buf_list rx_buf_list; + struct n_hdlc_buf_list tx_free_buf_list; + struct n_hdlc_buf_list rx_free_buf_list; }; /* * HDLC buffer list manipulation functions */ -static void n_hdlc_buf_list_init(N_HDLC_BUF_LIST *list); -static void n_hdlc_buf_put(N_HDLC_BUF_LIST *list,N_HDLC_BUF *buf); -static N_HDLC_BUF* n_hdlc_buf_get(N_HDLC_BUF_LIST *list); +static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list); +static void n_hdlc_buf_put(struct n_hdlc_buf_list *list, + struct n_hdlc_buf *buf); +static struct n_hdlc_buf *n_hdlc_buf_get(struct n_hdlc_buf_list *list); /* Local functions */ static struct n_hdlc *n_hdlc_alloc (void); -MODULE_PARM(debuglevel, "i"); -MODULE_PARM(maxframe, "i"); - - /* debug level can be set by insmod for debugging purposes */ #define DEBUG_LEVEL_INFO 1 static int debuglevel; /* max frame size for memory allocations */ -static ssize_t maxframe=4096; +static ssize_t maxframe = 4096; /* TTY callbacks */ -static rw_ret_t n_hdlc_tty_read(struct tty_struct *, - struct file *, __u8 *, rw_count_t); -static rw_ret_t n_hdlc_tty_write(struct tty_struct *, - struct file *, const __u8 *, rw_count_t); -static int n_hdlc_tty_ioctl(struct tty_struct *, - struct file *, unsigned int, unsigned long); -static unsigned int n_hdlc_tty_poll (struct tty_struct *tty, struct file *filp, - poll_table * wait); -static int n_hdlc_tty_open (struct tty_struct *); -static void n_hdlc_tty_close (struct tty_struct *); -static int n_hdlc_tty_room (struct tty_struct *tty); -static void n_hdlc_tty_receive (struct tty_struct *tty, - const __u8 * cp, char *fp, int count); -static void n_hdlc_tty_wakeup (struct tty_struct *tty); +static int n_hdlc_tty_read(struct tty_struct *tty, struct file *file, + __u8 *buf, size_t nr); +static int n_hdlc_tty_write(struct tty_struct *tty, struct file *file, + const __u8 *buf, size_t nr); +static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg); +static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp, + poll_table *wait); +static int n_hdlc_tty_open(struct tty_struct *tty); +static void n_hdlc_tty_close(struct tty_struct *tty); +static int n_hdlc_tty_room(struct tty_struct *tty); +static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *cp, + char *fp, int count); +static void n_hdlc_tty_wakeup(struct tty_struct *tty); #define bset(p,b) ((p)[(b) >> 5] |= (1 << ((b) & 0x1f))) #define tty2n_hdlc(tty) ((struct n_hdlc *) ((tty)->disc_data)) #define n_hdlc2tty(n_hdlc) ((n_hdlc)->tty) -/* Define this string only once for all macro invocations */ -static char szVersion[] = HDLC_VERSION; - static struct tty_ldisc n_hdlc_ldisc = { .owner = THIS_MODULE, .magic = TTY_LDISC_MAGIC, @@ -230,15 +217,14 @@ .write_wakeup = n_hdlc_tty_wakeup, }; -/* n_hdlc_release() - * - * release an n_hdlc per device line discipline info structure - * +/** + * n_hdlc_release - release an n_hdlc per device line discipline info structure + * @n_hdlc - per device line discipline info structure */ -static void n_hdlc_release (struct n_hdlc *n_hdlc) +static void n_hdlc_release(struct n_hdlc *n_hdlc) { struct tty_struct *tty = n_hdlc2tty (n_hdlc); - N_HDLC_BUF *buf; + struct n_hdlc_buf *buf; if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_release() called\n",__FILE__,__LINE__); @@ -285,10 +271,12 @@ } /* end of n_hdlc_release() */ -/* n_hdlc_tty_close() +/** + * n_hdlc_tty_close - line discipline close + * @tty - pointer to tty info structure * - * Called when the line discipline is changed to something - * else, the tty is closed, or the tty detects a hangup. + * Called when the line discipline is changed to something + * else, the tty is closed, or the tty detects a hangup. */ static void n_hdlc_tty_close(struct tty_struct *tty) { @@ -322,12 +310,11 @@ } /* end of n_hdlc_tty_close() */ -/* n_hdlc_tty_open - * - * called when line discipline changed to n_hdlc - * - * Arguments: tty pointer to tty info structure - * Return Value: 0 if success, otherwise error code +/** + * n_hdlc_tty_open - called when line discipline changed to n_hdlc + * @tty - pointer to tty info structure + * + * Returns 0 if success, otherwise error code */ static int n_hdlc_tty_open (struct tty_struct *tty) { @@ -373,22 +360,20 @@ } /* end of n_tty_hdlc_open() */ -/* n_hdlc_send_frames() - * - * send frames on pending send buffer list until the - * driver does not accept a frame (busy) - * this function is called after adding a frame to the - * send buffer list and by the tty wakeup callback - * - * Arguments: n_hdlc pointer to ldisc instance data - * tty pointer to tty instance data - * Return Value: None +/** + * n_hdlc_send_frames - send frames on pending send buffer list + * @n_hdlc - pointer to ldisc instance data + * @tty - pointer to tty instance data + * + * Send frames on pending send buffer list until the driver does not accept a + * frame (busy) this function is called after adding a frame to the send buffer + * list and by the tty wakeup callback. */ -static void n_hdlc_send_frames (struct n_hdlc *n_hdlc, struct tty_struct *tty) +static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty) { register int actual; unsigned long flags; - N_HDLC_BUF *tbuf; + struct n_hdlc_buf *tbuf; if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_send_frames() called\n",__FILE__,__LINE__); @@ -431,7 +416,7 @@ __FILE__,__LINE__,tbuf); /* free current transmit buffer */ - n_hdlc_buf_put(&n_hdlc->tx_free_buf_list,tbuf); + n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, tbuf); /* this tx buffer is done */ n_hdlc->tbuf = NULL; @@ -469,17 +454,15 @@ } /* end of n_hdlc_send_frames() */ -/* n_hdlc_tty_wakeup() +/** + * n_hdlc_tty_wakeup - Callback for transmit wakeup + * @tty - pointer to associated tty instance data * - * Callback for transmit wakeup. Called when low level - * device driver can accept more send data. - * - * Arguments: tty pointer to associated tty instance data - * Return Value: None + * Called when low level device driver can accept more send data. */ -static void n_hdlc_tty_wakeup (struct tty_struct *tty) +static void n_hdlc_tty_wakeup(struct tty_struct *tty) { - struct n_hdlc *n_hdlc = tty2n_hdlc (tty); + struct n_hdlc *n_hdlc = tty2n_hdlc(tty); if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_tty_wakeup() called\n",__FILE__,__LINE__); @@ -496,16 +479,14 @@ } /* end of n_hdlc_tty_wakeup() */ -/* n_hdlc_tty_room() - * - * Callback function from tty driver. Return the amount of - * space left in the receiver's buffer to decide if remote - * transmitter is to be throttled. +/** + * n_hdlc_tty_room - Return the amount of space left in the receiver's buffer + * @tty - pointer to associated tty instance data * - * Arguments: tty pointer to associated tty instance data - * Return Value: number of bytes left in receive buffer + * Callback function from tty driver. Return the amount of space left in the + * receiver's buffer to decide if remote transmitter is to be throttled. */ -static int n_hdlc_tty_room (struct tty_struct *tty) +static int n_hdlc_tty_room(struct tty_struct *tty) { if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_tty_room() called\n",__FILE__,__LINE__); @@ -514,23 +495,21 @@ return 65536; } /* end of n_hdlc_tty_root() */ -/* n_hdlc_tty_receive() - * - * Called by tty low level driver when receive data is - * available. Data is interpreted as one HDLC frame. - * - * Arguments: tty pointer to tty isntance data - * data pointer to received data - * flags pointer to flags for data - * count count of received data in bytes - * - * Return Value: None +/** + * n_hdlc_tty_receive - Called by tty driver when receive data is available + * @tty - pointer to tty instance data + * @data - pointer to received data + * @flags - pointer to flags for data + * @count - count of received data in bytes + * + * Called by tty low level driver when receive data is available. Data is + * interpreted as one HDLC frame. */ -static void n_hdlc_tty_receive(struct tty_struct *tty, - const __u8 * data, char *flags, int count) +static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data, + char *flags, int count) { register struct n_hdlc *n_hdlc = tty2n_hdlc (tty); - register N_HDLC_BUF *buf; + register struct n_hdlc_buf *buf; if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_tty_receive() called count=%d\n", @@ -560,7 +539,7 @@ /* no buffers in free list, attempt to allocate another rx buffer */ /* unless the maximum count has been reached */ if (n_hdlc->rx_buf_list.count < MAX_RX_BUF_COUNT) - buf = (N_HDLC_BUF*)kmalloc(N_HDLC_BUF_SIZE,GFP_ATOMIC); + buf = kmalloc(N_HDLC_BUF_SIZE, GFP_ATOMIC); } if (!buf) { @@ -575,7 +554,7 @@ buf->count=count; /* add HDLC buffer to list of received frames */ - n_hdlc_buf_put(&n_hdlc->rx_buf_list,buf); + n_hdlc_buf_put(&n_hdlc->rx_buf_list, buf); /* wake up any blocked reads and perform async signalling */ wake_up_interruptible (&tty->read_wait); @@ -584,28 +563,22 @@ } /* end of n_hdlc_tty_receive() */ -/* n_hdlc_tty_read() - * - * Called to retreive one frame of data (if available) - * - * Arguments: - * - * tty pointer to tty instance data - * file pointer to open file object - * buf pointer to returned data buffer - * nr size of returned data buffer +/** + * n_hdlc_tty_read - Called to retreive one frame of data (if available) + * @tty - pointer to tty instance data + * @file - pointer to open file object + * @buf - pointer to returned data buffer + * @nr - size of returned data buffer * - * Return Value: - * - * Number of bytes returned or error code + * Returns the number of bytes returned or error code. */ -static rw_ret_t n_hdlc_tty_read (struct tty_struct *tty, - struct file *file, __u8 * buf, rw_count_t nr) +static int n_hdlc_tty_read(struct tty_struct *tty, struct file *file, + __u8 *buf, size_t nr) { struct n_hdlc *n_hdlc = tty2n_hdlc(tty); int error; - rw_ret_t ret; - N_HDLC_BUF *rbuf; + int ret; + struct n_hdlc_buf *rbuf; if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_tty_read() called\n",__FILE__,__LINE__); @@ -644,16 +617,15 @@ return -EINTR; } - if (rbuf->count > nr) { + if (rbuf->count > nr) /* frame too large for caller's buffer (discard frame) */ - ret = (rw_ret_t)-EOVERFLOW; - } else { + ret = -EOVERFLOW; + else { /* Copy the data to the caller's buffer */ - COPY_TO_USER(error,buf,rbuf->buf,rbuf->count); - if (error) - ret = (rw_ret_t)error; + if (copy_to_user(buf, rbuf->buf, rbuf->count)) + ret = -EFAULT; else - ret = (rw_ret_t)rbuf->count; + ret = rbuf->count; } /* return HDLC buffer to free list unless the free list */ @@ -668,24 +640,22 @@ } /* end of n_hdlc_tty_read() */ -/* n_hdlc_tty_write() - * - * write a single frame of data to device - * - * Arguments: tty pointer to associated tty device instance data - * file pointer to file object data - * data pointer to transmit data (one frame) - * count size of transmit frame in bytes +/** + * n_hdlc_tty_write - write a single frame of data to device + * @tty - pointer to associated tty device instance data + * @file - pointer to file object data + * @data - pointer to transmit data (one frame) + * @count - size of transmit frame in bytes * - * Return Value: number of bytes written (or error code) + * Returns the number of bytes written (or error code). */ -static rw_ret_t n_hdlc_tty_write (struct tty_struct *tty, struct file *file, - const __u8 * data, rw_count_t count) +static int n_hdlc_tty_write(struct tty_struct *tty, struct file *file, + const __u8 *data, size_t count) { struct n_hdlc *n_hdlc = tty2n_hdlc (tty); int error = 0; DECLARE_WAITQUEUE(wait, current); - N_HDLC_BUF *tbuf; + struct n_hdlc_buf *tbuf; if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_tty_write() called count=%d\n", @@ -735,10 +705,10 @@ if (!error) { /* Retrieve the user's buffer */ - COPY_FROM_USER (error, tbuf->buf, data, count); - if (error) { + if (copy_from_user(tbuf->buf, data, count)) { /* return tx buffer to free list */ n_hdlc_buf_put(&n_hdlc->tx_free_buf_list,tbuf); + error = -EFAULT; } else { /* Send the data */ tbuf->count = error = count; @@ -751,21 +721,17 @@ } /* end of n_hdlc_tty_write() */ -/* n_hdlc_tty_ioctl() - * - * Process IOCTL system call for the tty device. +/** + * n_hdlc_tty_ioctl - process IOCTL system call for the tty device. + * @tty - pointer to tty instance data + * @file - pointer to open file object for device + * @cmd - IOCTL command code + * @arg - argument for IOCTL call (cmd dependent) * - * Arguments: - * - * tty pointer to tty instance data - * file pointer to open file object for device - * cmd IOCTL command code - * arg argument for IOCTL call (cmd dependent) - * - * Return Value: Command dependent + * Returns command dependent result. */ -static int n_hdlc_tty_ioctl (struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg) +static int n_hdlc_tty_ioctl(struct tty_struct *tty, struct file *file, + unsigned int cmd, unsigned long arg) { struct n_hdlc *n_hdlc = tty2n_hdlc (tty); int error = 0; @@ -790,7 +756,7 @@ else count = 0; spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock,flags); - PUT_USER (error, count, (int *) arg); + error = put_user(count, (int *)arg); break; case TIOCOUTQ: @@ -802,7 +768,7 @@ if (n_hdlc->tx_buf_list.head) count += n_hdlc->tx_buf_list.head->count; spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock,flags); - PUT_USER (error, count, (int*)arg); + error = put_user(count, (int*)arg); break; default: @@ -813,24 +779,18 @@ } /* end of n_hdlc_tty_ioctl() */ -/* n_hdlc_tty_poll() - * - * TTY callback for poll system call. Determine which - * operations (read/write) will not block and return - * info to caller. - * - * Arguments: - * - * tty pointer to tty instance data - * filp pointer to open file object for device - * poll_table wait queue for operations - * - * Return Value: - * - * bit mask containing info on which ops will not block +/** + * n_hdlc_tty_poll - TTY callback for poll system call + * @tty - pointer to tty instance data + * @filp - pointer to open file object for device + * @poll_table - wait queue for operations + * + * Determine which operations (read/write) will not block and return info + * to caller. + * Returns a bit mask containing info on which ops will not block. */ -static unsigned int n_hdlc_tty_poll (struct tty_struct *tty, - struct file *filp, poll_table * wait) +static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp, + poll_table *wait) { struct n_hdlc *n_hdlc = tty2n_hdlc (tty); unsigned int mask = 0; @@ -858,20 +818,17 @@ return mask; } /* end of n_hdlc_tty_poll() */ -/* n_hdlc_alloc() - * - * Allocate an n_hdlc instance data structure +/** + * n_hdlc_alloc - allocate an n_hdlc instance data structure * - * Arguments: None - * Return Value: pointer to structure if success, otherwise 0 + * Returns a pointer to newly created structure if success, otherwise %NULL */ -static struct n_hdlc *n_hdlc_alloc (void) +static struct n_hdlc *n_hdlc_alloc(void) { - struct n_hdlc *n_hdlc; - N_HDLC_BUF *buf; - int i; - - n_hdlc = (struct n_hdlc *)kmalloc(sizeof(struct n_hdlc), GFP_KERNEL); + struct n_hdlc_buf *buf; + int i; + struct n_hdlc *n_hdlc = kmalloc(sizeof(*n_hdlc), GFP_KERNEL); + if (!n_hdlc) return 0; @@ -884,7 +841,7 @@ /* allocate free rx buffer list */ for(i=0;i<DEFAULT_RX_BUF_COUNT;i++) { - buf = (N_HDLC_BUF*)kmalloc(N_HDLC_BUF_SIZE,GFP_KERNEL); + buf = kmalloc(N_HDLC_BUF_SIZE, GFP_KERNEL); if (buf) n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,buf); else if (debuglevel >= DEBUG_LEVEL_INFO) @@ -893,7 +850,7 @@ /* allocate free tx buffer list */ for(i=0;i<DEFAULT_TX_BUF_COUNT;i++) { - buf = (N_HDLC_BUF*)kmalloc(N_HDLC_BUF_SIZE,GFP_KERNEL); + buf = kmalloc(N_HDLC_BUF_SIZE, GFP_KERNEL); if (buf) n_hdlc_buf_put(&n_hdlc->tx_free_buf_list,buf); else if (debuglevel >= DEBUG_LEVEL_INFO) @@ -908,31 +865,23 @@ } /* end of n_hdlc_alloc() */ -/* n_hdlc_buf_list_init() - * - * initialize specified HDLC buffer list - * - * Arguments: list pointer to buffer list - * Return Value: None +/** + * n_hdlc_buf_list_init - initialize specified HDLC buffer list + * @list - pointer to buffer list */ -static void n_hdlc_buf_list_init(N_HDLC_BUF_LIST *list) +static void n_hdlc_buf_list_init(struct n_hdlc_buf_list *list) { - memset(list,0,sizeof(N_HDLC_BUF_LIST)); + memset(list, 0, sizeof(*list)); spin_lock_init(&list->spinlock); } /* end of n_hdlc_buf_list_init() */ -/* n_hdlc_buf_put() - * - * add specified HDLC buffer to tail of specified list - * - * Arguments: - * - * list pointer to buffer list - * buf pointer to buffer - * - * Return Value: None +/** + * n_hdlc_buf_put - add specified HDLC buffer to tail of specified list + * @list - pointer to buffer list + * @buf - pointer to buffer */ -static void n_hdlc_buf_put(N_HDLC_BUF_LIST *list,N_HDLC_BUF *buf) +static void n_hdlc_buf_put(struct n_hdlc_buf_list *list, + struct n_hdlc_buf *buf) { unsigned long flags; spin_lock_irqsave(&list->spinlock,flags); @@ -949,23 +898,18 @@ } /* end of n_hdlc_buf_put() */ -/* n_hdlc_buf_get() - * - * remove and return an HDLC buffer from the - * head of the specified HDLC buffer list - * - * Arguments: - * - * list pointer to HDLC buffer list - * - * Return Value: - * - * pointer to HDLC buffer if available, otherwise NULL +/** + * n_hdlc_buf_get - remove and return an HDLC buffer from list + * @list - pointer to HDLC buffer list + * + * Remove and return an HDLC buffer from the head of the specified HDLC buffer + * list. + * Returns a pointer to HDLC buffer if available, otherwise %NULL. */ -static N_HDLC_BUF* n_hdlc_buf_get(N_HDLC_BUF_LIST *list) +static struct n_hdlc_buf* n_hdlc_buf_get(struct n_hdlc_buf_list *list) { unsigned long flags; - N_HDLC_BUF *buf; + struct n_hdlc_buf *buf; spin_lock_irqsave(&list->spinlock,flags); buf = list->head; @@ -981,42 +925,60 @@ } /* end of n_hdlc_buf_get() */ +static char hdlc_banner[] __initdata = + KERN_INFO "HDLC line discipline: version " HDLC_VERSION + ", maxframe=%u\n"; +static char hdlc_register_ok[] __initdata = + KERN_INFO "N_HDLC line discipline registered.\n"; +static char hdlc_register_fail[] __initdata = + KERN_ERR "error registering line discipline: %d\n"; +static char hdlc_init_fail[] __initdata = + KERN_INFO "N_HDLC: init failure %d\n"; + static int __init n_hdlc_init(void) { - int status; + int status; /* range check maxframe arg */ - if ( maxframe<4096) - maxframe=4096; - else if ( maxframe>65535) - maxframe=65535; + if (maxframe < 4096) + maxframe = 4096; + else if (maxframe > 65535) + maxframe = 65535; - printk("HDLC line discipline: version %s, maxframe=%u\n", - szVersion, maxframe); + printk(hdlc_banner, maxframe); status = tty_register_ldisc(N_HDLC, &n_hdlc_ldisc); if (!status) - printk (KERN_INFO"N_HDLC line discipline registered.\n"); + printk(hdlc_register_ok); else - printk (KERN_ERR"error registering line discipline: %d\n",status); + printk(hdlc_register_fail, status); if (status) - printk(KERN_INFO"N_HDLC: init failure %d\n", status); - return (status); + printk(hdlc_init_fail, status); + return status; } /* end of init_module() */ +static char hdlc_unregister_ok[] __exitdata = + KERN_INFO "N_HDLC: line discipline unregistered\n"; +static char hdlc_unregister_fail[] __exitdata = + KERN_ERR "N_HDLC: can't unregister line discipline (err = %d)\n"; + static void __exit n_hdlc_exit(void) { - int status; /* Release tty registration of line discipline */ - if ((status = tty_register_ldisc(N_HDLC, NULL))) - printk("N_HDLC: can't unregister line discipline (err = %d)\n", status); + int status = tty_register_ldisc(N_HDLC, NULL); + + if (status) + printk(hdlc_unregister_fail, status); else - printk("N_HDLC: line discipline unregistered\n"); + printk(hdlc_unregister_ok); } module_init(n_hdlc_init); module_exit(n_hdlc_exit); MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Paul Fulghum paulkf@microgate.com"); +MODULE_PARM(debuglevel, "i"); +MODULE_PARM(maxframe, "i"); diff -Nru a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c --- a/drivers/char/pcmcia/synclink_cs.c Mon Jun 9 23:16:10 2003 +++ b/drivers/char/pcmcia/synclink_cs.c Mon Jun 9 23:16:10 2003 @@ -155,14 +155,11 @@ struct mgsl_icount icount; struct termios normal_termios; - struct termios callout_termios; struct tty_struct *tty; int timeout; int x_char; /* xon/xoff character */ int blocked_open; /* # of blocked opens */ - long session; /* Session of opening process */ - long pgrp; /* pgrp of opening process */ unsigned char read_status_mask; unsigned char ignore_status_mask; @@ -500,7 +497,7 @@ static char *driver_name = "SyncLink PC Card driver"; static char *driver_version = "$Revision: 4.10 $"; -static struct tty_driver serial_driver, callout_driver; +static struct tty_driver serial_driver; static int serial_refcount; /* number of characters left in xmit buffer before we ask for more */ @@ -617,8 +614,7 @@ memset(serial_table,0,sizeof(struct tty_struct*)*MAX_DEVICE_COUNT); memset(serial_termios,0,sizeof(struct termios*)*MAX_DEVICE_COUNT); memset(serial_termios_locked,0,sizeof(struct termios*)*MAX_DEVICE_COUNT); - - info->callout_termios = callout_driver.init_termios; + info->normal_termios = serial_driver.init_termios; return link; @@ -1307,7 +1303,7 @@ (info->serial_signals & SerialSignal_DCD) ? "on" : "off"); if (info->serial_signals & SerialSignal_DCD) wake_up_interruptible(&info->open_wait); - else if (!(info->flags & (ASYNC_CALLOUT_ACTIVE | ASYNC_CALLOUT_NOHUP))) { + else if (!(info->flags & ASYNC_CALLOUT_NOHUP)) { if (debug_level >= DEBUG_LEVEL_ISR) printk("doing serial hangup..."); if (info->tty) @@ -2589,9 +2585,7 @@ */ if (info->flags & ASYNC_NORMAL_ACTIVE) info->normal_termios = *tty->termios; - if (info->flags & ASYNC_CALLOUT_ACTIVE) - info->callout_termios = *tty->termios; - + /* set tty->closing to notify line discipline to * only process XON/XOFF characters. Only the N_TTY * discipline appears to use this (ppp does not). @@ -2629,8 +2623,7 @@ wake_up_interruptible(&info->open_wait); } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| - ASYNC_CLOSING); + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); @@ -2723,7 +2716,7 @@ shutdown(info); info->count = 0; - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->flags &= ~ASYNC_NORMAL_ACTIVE; info->tty = 0; wake_up_interruptible(&info->open_wait); @@ -2744,40 +2737,16 @@ printk("%s(%d):block_til_ready on %s\n", __FILE__,__LINE__, tty->driver->name ); - if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) { - /* this is a callout device */ - /* just verify that normal device is not in use */ - if (info->flags & ASYNC_NORMAL_ACTIVE) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_SESSION_LOCKOUT) && - (info->session != current->session)) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_PGRP_LOCKOUT) && - (info->pgrp != current->pgrp)) - return -EBUSY; - info->flags |= ASYNC_CALLOUT_ACTIVE; - return 0; - } - if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){ /* nonblock mode is set or port is not enabled */ /* just verify that callout device is not active */ - if (info->flags & ASYNC_CALLOUT_ACTIVE) - return -EBUSY; info->flags |= ASYNC_NORMAL_ACTIVE; return 0; } - if (info->flags & ASYNC_CALLOUT_ACTIVE) { - if (info->normal_termios.c_cflag & CLOCAL) - do_clocal = 1; - } else { - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - } - + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + /* Wait for carrier detect and the line to become * free (i.e., not in use by the callout). While we are in * this loop, info->count is dropped by one, so that @@ -2801,8 +2770,7 @@ info->blocked_open++; while (1) { - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - (tty->termios->c_cflag & CBAUD)) { + if ((tty->termios->c_cflag & CBAUD)) { spin_lock_irqsave(&info->lock,flags); info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; set_signals(info); @@ -2821,8 +2789,7 @@ get_signals(info); spin_unlock_irqrestore(&info->lock,flags); - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - !(info->flags & ASYNC_CLOSING) && + if (!(info->flags & ASYNC_CLOSING) && (do_clocal || (info->serial_signals & SerialSignal_DCD)) ) { break; } @@ -2926,16 +2893,10 @@ if ((info->count == 1) && info->flags & ASYNC_SPLIT_TERMIOS) { - if (tty->driver->subtype == SERIAL_TYPE_NORMAL) - *tty->termios = info->normal_termios; - else - *tty->termios = info->callout_termios; + *tty->termios = info->normal_termios; mgslpc_change_params(info); } - info->session = current->session; - info->pgrp = current->pgrp; - if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgslpc_open(%s) success\n", __FILE__,__LINE__, info->device_name); @@ -3170,9 +3131,18 @@ } } +static struct pcmcia_driver mgslpc_driver = { + .owner = THIS_MODULE, + .drv = { + .name = "synclink_cs", + }, + .attach = mgslpc_attach, + .detach = mgslpc_detach, +}; + static int __init synclink_cs_init(void) { - servinfo_t serv; + int error; if (break_on_load) { mgslpc_get_text_ptr(); @@ -3181,13 +3151,9 @@ printk("%s %s\n", driver_name, driver_version); - CardServices(GetCardServicesInfo, &serv); - if (serv.Revision != CS_RELEASE_CODE) { - printk(KERN_NOTICE "synclink_cs: Card Services release " - "does not match!\n"); - return -1; - } - register_pccard_driver(&dev_info, &mgslpc_attach, &mgslpc_detach); + error = pcmcia_register_driver(&mgslpc_driver); + if (error) + return error; /* Initialize the tty_driver structure */ @@ -3232,28 +3198,13 @@ serial_driver.tiocmget = tiocmget; serial_driver.tiocmset = tiocmset; - /* - * The callout device is just like normal device except for - * major number and the subtype code. - */ - callout_driver = serial_driver; - callout_driver.name = "cuaSLP"; - callout_driver.major = cuamajor; - callout_driver.subtype = SERIAL_TYPE_CALLOUT; - callout_driver.read_proc = 0; - callout_driver.proc_entry = 0; - if (tty_register_driver(&serial_driver) < 0) printk("%s(%d):Couldn't register serial driver\n", __FILE__,__LINE__); - if (tty_register_driver(&callout_driver) < 0) - printk("%s(%d):Couldn't register callout driver\n", - __FILE__,__LINE__); - - printk("%s %s, tty major#%d callout major#%d\n", + printk("%s %s, tty major#%d\n", driver_name, driver_version, - serial_driver.major, callout_driver.major); + serial_driver.major); return 0; } @@ -3270,11 +3221,10 @@ if ((rc = tty_unregister_driver(&serial_driver))) printk("%s(%d) failed to unregister tty driver err=%d\n", __FILE__,__LINE__,rc); - if ((rc = tty_unregister_driver(&callout_driver))) - printk("%s(%d) failed to unregister callout driver err=%d\n", - __FILE__,__LINE__,rc); - unregister_pccard_driver(&dev_info); + pcmcia_unregister_driver(&mgslpc_driver); + + /* XXX: this really needs to move into generic code.. */ while (dev_list != NULL) { if (dev_list->state & DEV_CONFIG) mgslpc_release((u_long)dev_list); diff -Nru a/drivers/char/pcxx.c b/drivers/char/pcxx.c --- a/drivers/char/pcxx.c Mon Jun 9 23:16:14 2003 +++ b/drivers/char/pcxx.c Mon Jun 9 23:16:14 2003 @@ -141,11 +141,9 @@ #define FEPTIMEOUT 200000 #define SERIAL_TYPE_NORMAL 1 -#define SERIAL_TYPE_CALLOUT 2 #define PCXE_EVENT_HANGUP 1 struct tty_driver pcxe_driver; -struct tty_driver pcxe_callout; static int pcxe_refcount; static struct timer_list pcxx_timer; @@ -240,8 +238,6 @@ if ((e1 = tty_unregister_driver(&pcxe_driver))) printk("SERIAL: failed to unregister serial driver (%d)\n", e1); - if ((e2 = tty_unregister_driver(&pcxe_callout))) - printk("SERIAL: failed to unregister callout driver (%d)\n",e2); cleanup_board_resources(); kfree(digi_channels); @@ -341,13 +337,8 @@ int retval = 0; int do_clocal = 0; - if (info->asyncflags & ASYNC_CALLOUT_ACTIVE) { - if (info->normal_termios.c_cflag & CLOCAL) - do_clocal = 1; - } else { - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - } + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; /* * Block waiting for the carrier detect and the line to become free @@ -360,12 +351,10 @@ for (;;) { cli(); - if ((info->asyncflags & ASYNC_CALLOUT_ACTIVE) == 0) { - globalwinon(info); - info->omodem |= DTR|RTS; - fepcmd(info, SETMODEM, DTR|RTS, 0, 10, 1); - memoff(info); - } + globalwinon(info); + info->omodem |= DTR|RTS; + fepcmd(info, SETMODEM, DTR|RTS, 0, 10, 1); + memoff(info); sti(); set_current_state(TASK_INTERRUPTIBLE); if(tty_hung_up_p(filp) || (info->asyncflags & ASYNC_INITIALIZED) == 0) { @@ -375,8 +364,7 @@ retval = -ERESTARTSYS; break; } - if ((info->asyncflags & ASYNC_CALLOUT_ACTIVE) == 0 && - (info->asyncflags & ASYNC_CLOSING) == 0 && + if ((info->asyncflags & ASYNC_CLOSING) == 0 && (do_clocal || (info->imodem & info->dcd))) break; if(signal_pending(current)) { @@ -476,56 +464,29 @@ else return -ERESTARTSYS; } - /* - * If this is a callout device, then just make sure the normal - * device isn't being used. - */ - if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) { - if (ch->asyncflags & ASYNC_NORMAL_ACTIVE) - return -EBUSY; - if (ch->asyncflags & ASYNC_CALLOUT_ACTIVE) { - if ((ch->asyncflags & ASYNC_SESSION_LOCKOUT) && - (ch->session != current->session)) - return -EBUSY; - if((ch->asyncflags & ASYNC_PGRP_LOCKOUT) && - (ch->pgrp != current->pgrp)) - return -EBUSY; - } - ch->asyncflags |= ASYNC_CALLOUT_ACTIVE; - } - else { - if (filp->f_flags & O_NONBLOCK) { - if(ch->asyncflags & ASYNC_CALLOUT_ACTIVE) - return -EBUSY; - } - else { - /* this has to be set in order for the "block until - * CD" code to work correctly. i'm not sure under - * what circumstances asyncflags should be set to - * ASYNC_NORMAL_ACTIVE though - * brian@ilinx.com - */ - ch->asyncflags |= ASYNC_NORMAL_ACTIVE; - if ((retval = pcxx_waitcarrier(tty, filp, ch)) != 0) - return retval; - } + + if (!(filp->f_flags & O_NONBLOCK)) { + /* this has to be set in order for the "block until + * CD" code to work correctly. i'm not sure under + * what circumstances asyncflags should be set to + * ASYNC_NORMAL_ACTIVE though + * brian@ilinx.com + */ ch->asyncflags |= ASYNC_NORMAL_ACTIVE; + if ((retval = pcxx_waitcarrier(tty, filp, ch)) != 0) + return retval; } + ch->asyncflags |= ASYNC_NORMAL_ACTIVE; save_flags(flags); cli(); if((ch->count == 1) && (ch->asyncflags & ASYNC_SPLIT_TERMIOS)) { - if(tty->driver->subtype == SERIAL_TYPE_NORMAL) - *tty->termios = ch->normal_termios; - else - *tty->termios = ch->callout_termios; + *tty->termios = ch->normal_termios; globalwinon(ch); pcxxparam(tty,ch); memoff(ch); } - ch->session = current->session; - ch->pgrp = current->pgrp; restore_flags(flags); return 0; } @@ -605,8 +566,6 @@ */ if(info->asyncflags & ASYNC_NORMAL_ACTIVE) info->normal_termios = *tty->termios; - if(info->asyncflags & ASYNC_CALLOUT_ACTIVE) - info->callout_termios = *tty->termios; tty->closing = 1; if(info->asyncflags & ASYNC_INITIALIZED) { setup_empty_event(tty,info); @@ -644,8 +603,7 @@ } wake_up_interruptible(&info->open_wait); } - info->asyncflags &= ~(ASYNC_NORMAL_ACTIVE| - ASYNC_CALLOUT_ACTIVE|ASYNC_CLOSING); + info->asyncflags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); restore_flags(flags); } @@ -665,7 +623,7 @@ ch->event = 0; ch->count = 0; ch->tty = NULL; - ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + ch->asyncflags &= ~ASYNC_NORMAL_ACTIVE; wake_up_interruptible(&ch->open_wait); restore_flags(flags); } @@ -1257,12 +1215,6 @@ pcxe_driver.start = pcxe_start; pcxe_driver.hangup = pcxe_hangup; - pcxe_callout = pcxe_driver; - pcxe_callout.name = "cud"; - pcxe_callout.major = DIGICU_MAJOR; - pcxe_callout.subtype = SERIAL_TYPE_CALLOUT; - pcxe_callout.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; - for(crd=0; crd < numcards; crd++) { bd = &boards[crd]; outb(FEPRST, bd->port); @@ -1619,7 +1571,6 @@ ch->close_delay = 50; ch->count = 0; ch->blocked_open = 0; - ch->callout_termios = pcxe_callout.init_termios; ch->normal_termios = pcxe_driver.init_termios; init_waitqueue_head(&ch->open_wait); init_waitqueue_head(&ch->close_wait); @@ -1651,12 +1602,6 @@ goto cleanup_boards; } - ret = tty_register_driver(&pcxe_callout); - if(ret) { - printk(KERN_ERR "Couldn't register PC/Xe callout\n"); - goto cleanup_pcxe_driver; - } - /* * Start up the poller to check for events on all enabled boards */ @@ -1760,7 +1705,7 @@ if (event & MODEMCHG_IND) { ch->imodem = mstat; - if (ch->asyncflags & (ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE)) { + if (ch->asyncflags & ASYNC_NORMAL_ACTIVE) { if (ch->asyncflags & ASYNC_CHECK_CD) { if (mstat & ch->dcd) { wake_up_interruptible(&ch->open_wait); @@ -2377,7 +2322,7 @@ if(test_and_clear_bit(PCXE_EVENT_HANGUP, &info->event)) { tty_hangup(tty); wake_up_interruptible(&info->open_wait); - info->asyncflags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->asyncflags &= ~ASYNC_NORMAL_ACTIVE; } } } diff -Nru a/drivers/char/pcxx.h b/drivers/char/pcxx.h --- a/drivers/char/pcxx.h Mon Jun 9 23:16:10 2003 +++ b/drivers/char/pcxx.h Mon Jun 9 23:16:10 2003 @@ -68,7 +68,6 @@ #define FEPTIMEOUT 200000 #define SERIAL_TYPE_NORMAL 1 -#define SERIAL_TYPE_CALLOUT 2 #define PCXE_EVENT_HANGUP 1 #define PCXX_MAGIC 0x5c6df104L @@ -78,8 +77,6 @@ unchar boardnum; unchar channelnum; uint dev; - long session; - long pgrp; struct tty_struct *tty; struct board_info *board; volatile struct board_chan *brdchan; @@ -127,7 +124,6 @@ ulong c_lflag; ulong c_oflag; struct termios normal_termios; - struct termios callout_termios; struct digi_struct digiext; ulong dummy[8]; }; diff -Nru a/drivers/char/pty.c b/drivers/char/pty.c --- a/drivers/char/pty.c Mon Jun 9 23:16:09 2003 +++ b/drivers/char/pty.c Mon Jun 9 23:16:09 2003 @@ -347,11 +347,8 @@ pty_driver.magic = TTY_DRIVER_MAGIC; pty_driver.owner = THIS_MODULE; pty_driver.driver_name = "pty_master"; -#ifdef CONFIG_DEVFS_FS - pty_driver.name = "pty/m"; -#else pty_driver.name = "pty"; -#endif + pty_driver.devfs_name = "pty/m"; pty_driver.major = PTY_MASTER_MAJOR; pty_driver.minor_start = 0; pty_driver.num = NR_PTYS; @@ -382,11 +379,8 @@ pty_slave_driver = pty_driver; pty_slave_driver.driver_name = "pty_slave"; pty_slave_driver.proc_entry = 0; -#ifdef CONFIG_DEVFS_FS - pty_slave_driver.name = "pty/s"; -#else pty_slave_driver.name = "ttyp"; -#endif + pty_slave_driver.devfs_name = "pty/s"; pty_slave_driver.subtype = PTY_TYPE_SLAVE; pty_slave_driver.major = PTY_SLAVE_MAJOR; pty_slave_driver.minor_start = 0; diff -Nru a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c --- a/drivers/char/rio/rio_linux.c Mon Jun 9 23:16:14 2003 +++ b/drivers/char/rio/rio_linux.c Mon Jun 9 23:16:14 2003 @@ -111,18 +111,11 @@ of boards in rio.h. You'll have to allocate more majors if you need more than 512 ports.... */ - -/* Why the hell am I defining these here? */ -#define RIO_TYPE_NORMAL 1 -#define RIO_TYPE_CALLOUT 2 - #ifndef RIO_NORMAL_MAJOR0 /* This allows overriding on the compiler commandline, or in a "major.h" include or something like that */ #define RIO_NORMAL_MAJOR0 154 -#define RIO_CALLOUT_MAJOR0 155 #define RIO_NORMAL_MAJOR1 156 -#define RIO_CALLOUT_MAJOR1 157 #endif #ifndef PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8 @@ -208,8 +201,7 @@ void my_hd (void *addr, int len); -static struct tty_driver rio_driver, rio_callout_driver; -static struct tty_driver rio_driver2, rio_callout_driver2; +static struct tty_driver rio_driver, rio_driver2; static struct tty_struct * rio_table[RIO_NPORTS]; static struct termios ** rio_termios; @@ -889,7 +881,7 @@ rio_driver.major = RIO_NORMAL_MAJOR0; rio_driver.num = 256; rio_driver.type = TTY_DRIVER_TYPE_SERIAL; - rio_driver.subtype = RIO_TYPE_NORMAL; + rio_driver.subtype = SERIAL_TYPE_NORMAL; rio_driver.init_termios = tty_std_termios; rio_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; @@ -920,28 +912,14 @@ rio_driver2.termios += 256; rio_driver2.termios_locked += 256; - rio_callout_driver = rio_driver; - rio_callout_driver.name = "cusr"; - rio_callout_driver.major = RIO_CALLOUT_MAJOR0; - rio_callout_driver.subtype = RIO_TYPE_CALLOUT; - - rio_callout_driver2 = rio_callout_driver; - rio_callout_driver2.major = RIO_CALLOUT_MAJOR1; - rio_callout_driver2.termios += 256; - rio_callout_driver2.termios_locked += 256; - rio_dprintk (RIO_DEBUG_INIT, "set_termios = %p\n", gs_set_termios); if ((error = tty_register_driver(&rio_driver))) goto bad1; if ((error = tty_register_driver(&rio_driver2))) goto bad2; - if ((error = tty_register_driver(&rio_callout_driver))) goto bad3; - if ((error = tty_register_driver(&rio_callout_driver2))) goto bad4; func_exit(); return 0; /* - bad5:tty_unregister_driver (&rio_callout_driver2); */ - bad4:tty_unregister_driver (&rio_callout_driver); bad3:tty_unregister_driver (&rio_driver2); bad2:tty_unregister_driver (&rio_driver); bad1:printk(KERN_ERR "rio: Couldn't register a rio driver, error = %d\n", @@ -1006,7 +984,6 @@ } rio_dprintk (RIO_DEBUG_INIT, "initing port %d (%d)\n", i, port->Mapped); port->PortNum = i; - port->gs.callout_termios = tty_std_termios; port->gs.normal_termios = tty_std_termios; port->gs.magic = RIO_MAGIC; port->gs.close_delay = HZ/2; @@ -1051,8 +1028,6 @@ static void __exit rio_release_drivers(void) { func_enter(); - tty_unregister_driver (&rio_callout_driver2); - tty_unregister_driver (&rio_callout_driver); tty_unregister_driver (&rio_driver2); tty_unregister_driver (&rio_driver); func_exit(); diff -Nru a/drivers/char/riscom8.c b/drivers/char/riscom8.c --- a/drivers/char/riscom8.c Mon Jun 9 23:16:11 2003 +++ b/drivers/char/riscom8.c Mon Jun 9 23:16:11 2003 @@ -83,11 +83,8 @@ static DECLARE_TASK_QUEUE(tq_riscom); -#define RISCOM_TYPE_NORMAL 1 -#define RISCOM_TYPE_CALLOUT 2 - static struct riscom_board * IRQ_to_board[16]; -static struct tty_driver riscom_driver, riscom_callout_driver; +static struct tty_driver riscom_driver; static int riscom_refcount; static struct tty_struct * riscom_table[RC_NBOARD * RC_NPORT]; static struct termios * riscom_termios[RC_NBOARD * RC_NPORT]; @@ -550,10 +547,8 @@ if (mcr & MCR_CDCHG) { if (rc_in(bp, CD180_MSVR) & MSVR_CD) wake_up_interruptible(&port->open_wait); - else if (!((port->flags & ASYNC_CALLOUT_ACTIVE) && - (port->flags & ASYNC_CALLOUT_NOHUP))) { + else schedule_task(&port->tqueue_hangup); - } } #ifdef RISCOM_BRAIN_DAMAGED_CTS @@ -986,44 +981,18 @@ } /* - * If this is a callout device, then just make sure the normal - * device isn't being used. - */ - if (tty->driver->subtype == RISCOM_TYPE_CALLOUT) { - if (port->flags & ASYNC_NORMAL_ACTIVE) - return -EBUSY; - if ((port->flags & ASYNC_CALLOUT_ACTIVE) && - (port->flags & ASYNC_SESSION_LOCKOUT) && - (port->session != current->session)) - return -EBUSY; - if ((port->flags & ASYNC_CALLOUT_ACTIVE) && - (port->flags & ASYNC_PGRP_LOCKOUT) && - (port->pgrp != current->pgrp)) - return -EBUSY; - port->flags |= ASYNC_CALLOUT_ACTIVE; - return 0; - } - - /* * If non-blocking mode is set, or the port is not enabled, * then make the check up front and then exit. */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { - if (port->flags & ASYNC_CALLOUT_ACTIVE) - return -EBUSY; port->flags |= ASYNC_NORMAL_ACTIVE; return 0; } - if (port->flags & ASYNC_CALLOUT_ACTIVE) { - if (port->normal_termios.c_cflag & CLOCAL) - do_clocal = 1; - } else { - if (C_CLOCAL(tty)) - do_clocal = 1; - } - + if (C_CLOCAL(tty)) + do_clocal = 1; + /* * Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). While we are in @@ -1042,11 +1011,9 @@ cli(); rc_out(bp, CD180_CAR, port_No(port)); CD = rc_in(bp, CD180_MSVR) & MSVR_CD; - if (!(port->flags & ASYNC_CALLOUT_ACTIVE)) { - rc_out(bp, CD180_MSVR, MSVR_RTS); - bp->DTR &= ~(1u << port_No(port)); - rc_out(bp, RC_DTR, bp->DTR); - } + rc_out(bp, CD180_MSVR, MSVR_RTS); + bp->DTR &= ~(1u << port_No(port)); + rc_out(bp, RC_DTR, bp->DTR); sti(); set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || @@ -1057,8 +1024,7 @@ retval = -ERESTARTSYS; break; } - if (!(port->flags & ASYNC_CALLOUT_ACTIVE) && - !(port->flags & ASYNC_CLOSING) && + if (!(port->flags & ASYNC_CLOSING) && (do_clocal || CD)) break; if (signal_pending(current)) { @@ -1110,18 +1076,11 @@ return error; if ((port->count == 1) && (port->flags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver->subtype == RISCOM_TYPE_NORMAL) - *tty->termios = port->normal_termios; - else - *tty->termios = port->callout_termios; + *tty->termios = port->normal_termios; save_flags(flags); cli(); rc_change_speed(bp, port); restore_flags(flags); } - - port->session = current->session; - port->pgrp = current->pgrp; - return 0; } @@ -1161,8 +1120,6 @@ */ if (port->flags & ASYNC_NORMAL_ACTIVE) port->normal_termios = *tty->termios; - if (port->flags & ASYNC_CALLOUT_ACTIVE) - port->callout_termios = *tty->termios; /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. @@ -1210,8 +1167,7 @@ } wake_up_interruptible(&port->open_wait); } - port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| - ASYNC_CLOSING); + port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&port->close_wait); out: restore_flags(flags); } @@ -1689,7 +1645,7 @@ rc_shutdown_port(bp, port); port->event = 0; port->count = 0; - port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + port->flags &= ~ASYNC_NORMAL_ACTIVE; port->tty = 0; wake_up_interruptible(&port->open_wait); } @@ -1757,7 +1713,7 @@ riscom_driver.major = RISCOM8_NORMAL_MAJOR; riscom_driver.num = RC_NBOARD * RC_NPORT; riscom_driver.type = TTY_DRIVER_TYPE_SERIAL; - riscom_driver.subtype = RISCOM_TYPE_NORMAL; + riscom_driver.subtype = SERIAL_TYPE_NORMAL; riscom_driver.init_termios = tty_std_termios; riscom_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; @@ -1783,11 +1739,6 @@ riscom_driver.start = rc_start; riscom_driver.hangup = rc_hangup; - riscom_callout_driver = riscom_driver; - riscom_callout_driver.name = "cul"; - riscom_callout_driver.major = RISCOM8_CALLOUT_MAJOR; - riscom_callout_driver.subtype = RISCOM_TYPE_CALLOUT; - if ((error = tty_register_driver(&riscom_driver))) { free_page((unsigned long)tmp_buf); printk(KERN_ERR "rc: Couldn't register RISCom/8 driver, " @@ -1795,18 +1746,9 @@ error); return 1; } - if ((error = tty_register_driver(&riscom_callout_driver))) { - free_page((unsigned long)tmp_buf); - tty_unregister_driver(&riscom_driver); - printk(KERN_ERR "rc: Couldn't register RISCom/8 callout " - "driver, error = %d\n", - error); - return 1; - } - + memset(rc_port, 0, sizeof(rc_port)); for (i = 0; i < RC_NPORT * RC_NBOARD; i++) { - rc_port[i].callout_termios = riscom_callout_driver.init_termios; rc_port[i].normal_termios = riscom_driver.init_termios; rc_port[i].magic = RISCOM8_MAGIC; rc_port[i].tqueue.routine = do_softint; @@ -1831,7 +1773,6 @@ remove_bh(RISCOM8_BH); free_page((unsigned long)tmp_buf); tty_unregister_driver(&riscom_driver); - tty_unregister_driver(&riscom_callout_driver); restore_flags(flags); } diff -Nru a/drivers/char/riscom8.h b/drivers/char/riscom8.h --- a/drivers/char/riscom8.h Mon Jun 9 23:16:20 2003 +++ b/drivers/char/riscom8.h Mon Jun 9 23:16:20 2003 @@ -74,15 +74,12 @@ long event; /* long req'd for set_bit --RR */ int timeout; int close_delay; - long session; - long pgrp; unsigned char * xmit_buf; int custom_divisor; int xmit_head; int xmit_tail; int xmit_cnt; struct termios normal_termios; - struct termios callout_termios; wait_queue_head_t open_wait; wait_queue_head_t close_wait; struct tq_struct tqueue; diff -Nru a/drivers/char/rocket.c b/drivers/char/rocket.c --- a/drivers/char/rocket.c Mon Jun 9 23:16:15 2003 +++ b/drivers/char/rocket.c Mon Jun 9 23:16:15 2003 @@ -1,9 +1,9 @@ /* - * Rocketport device driver for Linux + * RocketPort device driver for Linux * - * Written by Theodore Ts'o, 1995, 1996, 1997. + * Written by Theodore Ts'o, 1995, 1996, 1997, 1998, 1999, 2000. * - * Copyright (C) 1995, 1996, 1997 by Comtrol, Inc. + * Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000, 2003 by Comtrol, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -21,60 +21,46 @@ */ /* - * Minor number schema: + * Kernel Synchronization: * - * +-------------------------------+ - * | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | - * +---+-------+-------+-----------+ - * | C | Board | AIOP | Port # | - * +---+-------+-------+-----------+ + * This driver has 2 kernel control paths - exception handlers (calls into the driver + * from user mode) and the timer bottom half (tasklet). This is a polled driver, interrupts + * are not used. * - * C=0 implements normal POSIX tty. - * C=1 is reserved for the callout device. + * Critical data: + * - rp_table[], accessed through passed "info" pointers, is a global (static) array of + * serial port state information and the xmit_buf circular buffer. Protected by + * a per port spinlock. + * - xmit_flags[], an array of ints indexed by line (port) number, indicating that there + * is data to be transmitted. Protected by atomic bit operations. + * - rp_num_ports, int indicating number of open ports, protected by atomic operations. * - * Normally, the user won't have to worry about the AIOP; as far as - * the user is concerned, the lower 5 bits of the minor number address - * the ports on a particular board (from 0 up to 32). + * rp_write() and rp_write_char() functions use a per port semaphore to protect against + * simultaneous access to the same port by more than one process. */ -/* Kernel includes */ - +/****** Defines ******/ #include <linux/config.h> #include <linux/version.h> -#include <linux/module.h> -#include <linux/errno.h> -#include <linux/major.h> -#include <linux/kernel.h> -#include <linux/signal.h> -#include <linux/slab.h> -#include <linux/mm.h> - -#include <linux/sched.h> -#include <linux/timer.h> -#include <linux/interrupt.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/string.h> -#include <linux/fcntl.h> -#include <linux/ptrace.h> -#include <linux/ioport.h> -#include <linux/pci.h> -#include <linux/init.h> - -#include "rocket_int.h" -#ifdef LOCAL_ROCKET_H -#include "rocket.h" -#include "version.h" +#ifdef PCI_NUM_RESOURCES +#define PCI_BASE_ADDRESS(dev, r) ((dev)->resource[r].start) #else -#include <linux/rocket.h> -#define ROCKET_VERSION "1.14c" -#define ROCKET_DATE "24-Aug-98" -#endif /* LOCAL_ROCKET_H */ +#define PCI_BASE_ADDRESS(dev, r) ((dev)->base_address[r]) +#endif + +#ifndef VERSION_CODE +# define VERSION_CODE(vers,rel,seq) ( ((vers)<<16) | ((rel)<<8) | (seq) ) +#endif + +#if LINUX_VERSION_CODE < VERSION_CODE(2,2,9) /* No version < 2.2 */ +# error "This kernel is too old: not supported by this file" +#endif #define ROCKET_PARANOIA_CHECK -#define ROCKET_SOFT_FLOW +#define ROCKET_DISABLE_SIMUSAGE +#undef ROCKET_SOFT_FLOW #undef ROCKET_DEBUG_OPEN #undef ROCKET_DEBUG_INTR #undef ROCKET_DEBUG_WRITE @@ -83,7 +69,8 @@ #undef ROCKET_DEBUG_WAIT_UNTIL_SENT #undef ROCKET_DEBUG_RECEIVE #undef ROCKET_DEBUG_HANGUP - +#undef REV_PCI_ORDER +#undef ROCKET_DEBUG_IO /* CAUTION!!!!! The TIME_STAT Function relies on the Pentium 64 bit * register. For various reasons related to 1.2.13, the test for this @@ -96,46 +83,132 @@ * CPU, there is probably something funny about your CPU. */ -#undef TIME_STAT /* For performing timing statistics on driver. */ +#undef TIME_STAT /* For performing timing statistics on driver. */ /* Produces printks, one every TIME_COUNTER loops, eats */ /* some of your CPU time. Good for testing or */ /* other checking, otherwise, leave it undefed */ /* Doug Ledford */ -#define TIME_STAT_CPU 100 /* This needs to be set to your processor speed */ - /* For example, 100Mhz CPU, set this to 100 */ -#define TIME_COUNTER 180000 /* This is how many iterations to run before */ +#define TIME_STAT_CPU 100 /* This needs to be set to your processor speed */ + /* For example, 100Mhz CPU, set this to 100 */ +#define TIME_COUNTER 180000 /* This is how many iterations to run before */ /* performing the printk statements. */ /* 6000 = 1 minute, 360000 = 1 hour, etc. */ /* Since time_stat is long long, this */ /* Can be really high if you want :) */ -#undef TIME_STAT_VERBOSE /* Undef this if you want a terse log message. */ +#undef TIME_STAT_VERBOSE /* Undef this if you want a terse log message. */ + +#if LINUX_VERSION_CODE < VERSION_CODE(2,4,0) +#define TTY_DRIVER_NO_DEVFS 0 +#endif + +#define POLL_PERIOD HZ/100 /* Polling period .01 seconds (10ms) */ + +/****** Kernel includes ******/ + +#ifdef MODVERSIONS +#if LINUX_VERSION_CODE < VERSION_CODE(2,5,00) +#include <linux/modversions.h> +#else +#include <config/modversions.h> +#endif +#endif + +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/major.h> +#include <linux/kernel.h> +#include <linux/signal.h> -#define _INLINE_ inline +#if LINUX_VERSION_CODE < VERSION_CODE(2,4,0) +#include <linux/malloc.h> +#else +#include <linux/slab.h> +#endif -static struct r_port *rp_table[MAX_RP_PORTS]; -static struct tty_struct *rocket_table[MAX_RP_PORTS]; -static unsigned int xmit_flags[NUM_BOARDS]; +#include <linux/mm.h> +#include <linux/sched.h> +#include <linux/timer.h> +#include <linux/interrupt.h> +#include <linux/tty.h> +#include <linux/tty_driver.h> +#include <linux/tty_flip.h> +#include <linux/string.h> +#include <linux/fcntl.h> +#include <linux/ptrace.h> +#include <linux/major.h> +#include <linux/ioport.h> +#include <linux/delay.h> +#include <linux/wait.h> +#include <linux/delay.h> +#include <linux/pci.h> +#include <asm/uaccess.h> +#include <asm/atomic.h> +#include <asm/bitops.h> +#include <linux/spinlock.h> +#include <asm/semaphore.h> +#include <linux/init.h> + +/****** RocketPort includes ******/ + +#include "rocket_int.h" +#include "rocket.h" + +#ifdef LOCAL_ROCKET_H +#include "version.h" +#else +#define ROCKET_VERSION "2.08" +#define ROCKET_DATE "02-June-2003" +#endif /* LOCAL_ROCKET_H */ + +/* + * All of the compatibilty code so we can compile serial.c against + * older kernels is hidden in rocket_compat.h + */ +#if defined(LOCAL_ROCKET_H) || (LINUX_VERSION_CODE < VERSION_CODE(2,3,23)) +#include "rocket_compat.h" +#endif + +/****** RocketPort Local Variables ******/ + +static struct tty_struct *rocket_table[MAX_RP_PORTS]; /* TTY required variables */ static struct termios *rocket_termios[MAX_RP_PORTS]; static struct termios *rocket_termios_locked[MAX_RP_PORTS]; -static void rp_wait_until_sent(struct tty_struct *tty, int timeout); -static void rp_flush_buffer(struct tty_struct *tty); - -static struct tty_driver rocket_driver, callout_driver; +static struct tty_driver rocket_driver; static int rocket_refcount; -static int rp_num_ports_open; +static struct rocket_version driver_version = { + ROCKET_VERSION, ROCKET_DATE +}; +static struct r_port *rp_table[MAX_RP_PORTS]; /* The main repository of serial port state information. */ +static unsigned int xmit_flags[NUM_BOARDS]; /* Bit significant, indicates port had data to transmit. */ + /* eg. Bit 0 indicates port 0 has xmit data, ... */ +static atomic_t rp_num_ports_open; /* Number of serial ports open */ static struct timer_list rocket_timer; -unsigned long board1; -unsigned long board2; -unsigned long board3; -unsigned long board4; -unsigned long controller; -unsigned long support_low_speed; -int rp_baud_base = 460800; +static unsigned long board1; /* ISA addresses, retrieved from rocketport.conf */ +static unsigned long board2; +static unsigned long board3; +static unsigned long board4; +static unsigned long controller; +static unsigned long support_low_speed; +static unsigned long modem1; +static unsigned long modem2; +static unsigned long modem3; +static unsigned long modem4; +static unsigned long pc104_1[8]; +static unsigned long pc104_2[8]; +static unsigned long pc104_3[8]; +static unsigned long pc104_4[8]; +static unsigned long *pc104[4] = { pc104_1, pc104_2, pc104_3, pc104_4 }; + +static int rp_baud_base[NUM_BOARDS]; /* Board config info (Someday make a per-board structure) */ static unsigned long rcktpt_io_addr[NUM_BOARDS]; +static int rcktpt_type[NUM_BOARDS]; +static int is_PCI[NUM_BOARDS]; +static rocketModel_t rocketModel[NUM_BOARDS]; static int max_board; + #ifdef TIME_STAT static unsigned long long time_stat; static unsigned long time_stat_short; @@ -143,83 +216,140 @@ static unsigned long time_counter; #endif +/* + * The following arrays define the interrupt bits corresponding to each AIOP. + * These bits are different between the ISA and regular PCI boards and the + * Universal PCI boards. + */ + +static Word_t aiop_intr_bits[AIOP_CTL_SIZE] = { + AIOP_INTR_BIT_0, + AIOP_INTR_BIT_1, + AIOP_INTR_BIT_2, + AIOP_INTR_BIT_3 +}; + +static Word_t upci_aiop_intr_bits[AIOP_CTL_SIZE] = { + UPCI_AIOP_INTR_BIT_0, + UPCI_AIOP_INTR_BIT_1, + UPCI_AIOP_INTR_BIT_2, + UPCI_AIOP_INTR_BIT_3 +}; + +/* + * Line number is the ttySIx number (x), the Minor number. We + * assign them sequentially, starting at zero. The following + * array keeps track of the line number assigned to a given board/aiop/channel. + */ +static unsigned char lineNumbers[MAX_RP_PORTS]; +static unsigned long nextLineNumber; + +/***** RocketPort Static Prototypes *********/ +static int __init init_ISA(int i, int *reserved_controller); +static void rp_wait_until_sent(struct tty_struct *tty, int timeout); +static void rp_flush_buffer(struct tty_struct *tty); +static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model); +static unsigned char GetLineNumber(int ctrl, int aiop, int ch); +static unsigned char SetLineNumber(int ctrl, int aiop, int ch); +static void rp_start(struct tty_struct *tty); + +#ifdef MODULE MODULE_AUTHOR("Theodore Ts'o"); -MODULE_DESCRIPTION("Comtrol Rocketport driver"); -MODULE_LICENSE("GPL"); -MODULE_PARM(board1, "i"); +MODULE_DESCRIPTION("Comtrol RocketPort driver"); +MODULE_PARM(board1, "i"); MODULE_PARM_DESC(board1, "I/O port for (ISA) board #1"); -MODULE_PARM(board2, "i"); +MODULE_PARM(board2, "i"); MODULE_PARM_DESC(board2, "I/O port for (ISA) board #2"); -MODULE_PARM(board3, "i"); +MODULE_PARM(board3, "i"); MODULE_PARM_DESC(board3, "I/O port for (ISA) board #3"); -MODULE_PARM(board4, "i"); +MODULE_PARM(board4, "i"); MODULE_PARM_DESC(board4, "I/O port for (ISA) board #4"); MODULE_PARM(controller, "i"); MODULE_PARM_DESC(controller, "I/O port for (ISA) rocketport controller"); MODULE_PARM(support_low_speed, "i"); -MODULE_PARM_DESC(support_low_speed, "0 means support 50 baud, 1 means support 460400 baud"); +MODULE_PARM_DESC(support_low_speed, "1 means support 50 baud, 0 means support 460400 baud"); +MODULE_PARM(modem1, "i"); +MODULE_PARM_DESC(modem1, "1 means (ISA) board #1 is a RocketModem"); +MODULE_PARM(modem2, "i"); +MODULE_PARM_DESC(modem2, "1 means (ISA) board #2 is a RocketModem"); +MODULE_PARM(modem3, "i"); +MODULE_PARM_DESC(modem3, "1 means (ISA) board #3 is a RocketModem"); +MODULE_PARM(modem4, "i"); +MODULE_PARM_DESC(modem4, "1 means (ISA) board #4 is a RocketModem"); +MODULE_PARM(pc104_1, "1-8i"); +MODULE_PARM_DESC(pc104_1, "set interface types for ISA(PC104) board #1 (e.g. pc104_1=232,232,485,485,..."); +MODULE_PARM(pc104_2, "1-8i"); +MODULE_PARM_DESC(pc104_2, "set interface types for ISA(PC104) board #2 (e.g. pc104_2=232,232,485,485,..."); +MODULE_PARM(pc104_3, "1-8i"); +MODULE_PARM_DESC(pc104_3, "set interface types for ISA(PC104) board #3 (e.g. pc104_3=232,232,485,485,..."); +MODULE_PARM(pc104_4, "1-8i"); +MODULE_PARM_DESC(pc104_4, "set interface types for ISA(PC104) board #4 (e.g. pc104_4=232,232,485,485,..."); + +int rp_init(void); +static void rp_cleanup_module(void); + +module_init(rp_init); +module_exit(rp_cleanup_module); -#include <asm/uaccess.h> +#endif -/* - * tmp_buf is used as a temporary buffer by rp_write. We need to - * lock it in case the memcpy_fromfs 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 = 0; -static DECLARE_MUTEX(tmp_buf_sem); +#ifdef MODULE_LICENSE +MODULE_LICENSE("Dual BSD/GPL"); +#endif -static void rp_start(struct tty_struct *tty); +/*************************************************************************/ +/* Module code starts here */ static inline int rocket_paranoia_check(struct r_port *info, - char *name, const char *routine) + const char *routine) { #ifdef ROCKET_PARANOIA_CHECK - static const char *badmagic = - "Warning: bad magic number for rocketport struct %s in %s\n"; if (!info) return 1; if (info->magic != RPORT_MAGIC) { - printk(badmagic, name, routine); + printk(KERN_INFO "Warning: bad magic number for rocketport struct in %s\n", + routine); return 1; } #endif return 0; } -/* - * Here begins the interrupt/polling routine for the Rocketport! + +/* Serial port receive data function. Called (from timer poll) when an AIOPIC signals + * that receive data is present on a serial port. Pulls data from FIFO, moves it into the + * tty layer. */ -static _INLINE_ void rp_do_receive(struct r_port *info, struct tty_struct *tty, - CHANNEL_t *cp, unsigned int ChanStatus) +static void rp_do_receive(struct r_port *info, + struct tty_struct *tty, + CHANNEL_t * cp, unsigned int ChanStatus) { unsigned int CharNStat; int ToRecv, wRecv, space, count; - unsigned char *cbuf; - char *fbuf; - - ToRecv= sGetRxCnt(cp); - space = 2*TTY_FLIPBUF_SIZE; + unsigned char *cbuf; + char *fbuf; + + ToRecv = sGetRxCnt(cp); + space = tty->ldisc.receive_room(tty); + if (space > 2 * TTY_FLIPBUF_SIZE) + space = 2 * TTY_FLIPBUF_SIZE; cbuf = tty->flip.char_buf; fbuf = tty->flip.flag_buf; count = 0; #ifdef ROCKET_DEBUG_INTR - printk("rp_do_receive(%d, %d)...", ToRecv, space); + printk(KERN_INFO "rp_do_receive(%d, %d)...", ToRecv, space); #endif - if (ToRecv == 0 || (space <= 0)) - return; - + /* * determine how many we can actually read in. If we can't * read any in then we have a software overrun condition. */ if (ToRecv > space) ToRecv = space; - + + if (ToRecv <= 0) + return; + /* * if status indicates there are errored characters in the * FIFO, then enter status mode (a word in FIFO holds @@ -228,7 +358,7 @@ if (ChanStatus & (RXFOVERFL | RXBREAK | RXFRAME | RXPARITY)) { if (!(ChanStatus & STATMODE)) { #ifdef ROCKET_DEBUG_RECEIVE - printk("Entering STATMODE..."); + printk(KERN_INFO "Entering STATMODE..."); #endif ChanStatus |= STATMODE; sEnRxStatusMode(cp); @@ -242,16 +372,14 @@ */ if (ChanStatus & STATMODE) { #ifdef ROCKET_DEBUG_RECEIVE - printk("Ignore %x, read %x...", info->ignore_status_mask, + printk(KERN_INFO "Ignore %x, read %x...", info->ignore_status_mask, info->read_status_mask); #endif while (ToRecv) { - CharNStat= sInW(sGetTxRxDataIO(cp)); - + CharNStat = sInW(sGetTxRxDataIO(cp)); #ifdef ROCKET_DEBUG_RECEIVE - printk("%x...", CharNStat); + printk(KERN_INFO "%x...", CharNStat); #endif - if (CharNStat & STMBREAKH) CharNStat &= ~(STMFRAMEH | STMPARITYH); if (CharNStat & info->ignore_status_mask) { @@ -259,18 +387,14 @@ continue; } CharNStat &= info->read_status_mask; - if (CharNStat & STMBREAKH) { + if (CharNStat & STMBREAKH) *fbuf++ = TTY_BREAK; -#if 0 - if (info->flags & ROCKET_SAK) - do_SAK(tty); -#endif - } else if (CharNStat & STMPARITYH) + else if (CharNStat & STMPARITYH) *fbuf++ = TTY_PARITY; else if (CharNStat & STMFRAMEH) *fbuf++ = TTY_FRAME; else if (CharNStat & STMRCVROVRH) - *fbuf++ =TTY_OVERRUN; + *fbuf++ = TTY_OVERRUN; else *fbuf++ = 0; *cbuf++ = CharNStat & 0xff; @@ -284,7 +408,7 @@ */ if (sGetRxCnt(cp) == 0) { #ifdef ROCKET_DEBUG_RECEIVE - printk("Status mode off.\n"); + printk(KERN_INFO "Status mode off.\n"); #endif sDisRxStatusMode(cp); } @@ -294,86 +418,93 @@ * characters at time by doing repeated word IO * transfer. */ - wRecv= ToRecv >> 1; + wRecv = ToRecv >> 1; if (wRecv) - sInStrW(sGetTxRxDataIO(cp), cbuf, - wRecv); + sInStrW(sGetTxRxDataIO(cp), (unsigned short *) cbuf, wRecv); if (ToRecv & 1) - cbuf[ToRecv-1] = sInB(sGetTxRxDataIO(cp)); + cbuf[ToRecv - 1] = sInB(sGetTxRxDataIO(cp)); memset(fbuf, 0, ToRecv); cbuf += ToRecv; fbuf += ToRecv; count += ToRecv; } - tty->ldisc.receive_buf(tty, tty->flip.char_buf, - tty->flip.flag_buf, count); + /* Push the data up to the tty layer */ + tty->ldisc.receive_buf(tty, tty->flip.char_buf, tty->flip.flag_buf, count); } /* - * This routine is called when a transmit interrupt is found. It's - * responsible for pushing data found in the transmit buffer out to - * the serial card. + * Serial port transmit data function. Called from the timer polling loop as a + * result of a bit set in xmit_flags[], indicating data (from the tty layer) is ready + * to be sent out the serial port. Data is buffered in rp_table[line].xmit_buf, it is + * moved to the port's xmit FIFO. *info is critical data, protected by spinlocks. */ -static _INLINE_ void rp_do_transmit(struct r_port *info) +static void rp_do_transmit(struct r_port *info) { - int c; + int c; CHANNEL_t *cp = &info->channel; struct tty_struct *tty; - + unsigned long flags; + #ifdef ROCKET_DEBUG_INTR - printk("rp_do_transmit "); + printk(KERN_INFO "rp_do_transmit "); #endif if (!info) return; if (!info->tty) { - printk("rp: WARNING rp_do_transmit called with info->tty==NULL\n"); - xmit_flags[info->line >> 5] &= ~(1 << (info->line & 0x1f)); + printk(KERN_INFO "rp: WARNING rp_do_transmit called with info->tty==NULL\n"); + clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); return; } + + spin_lock_irqsave(&info->slock, flags); tty = info->tty; info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp); + + /* Loop sending data to FIFO until done or FIFO full */ while (1) { if (tty->stopped || tty->hw_stopped) break; - c = MIN(info->xmit_fifo_room, - MIN(info->xmit_cnt, - XMIT_BUF_SIZE - info->xmit_tail)); + c = MIN(info->xmit_fifo_room, MIN(info->xmit_cnt, XMIT_BUF_SIZE - info->xmit_tail)); if (c <= 0 || info->xmit_fifo_room <= 0) break; - sOutStrW(sGetTxRxDataIO(cp), - info->xmit_buf + info->xmit_tail, c/2); + sOutStrW(sGetTxRxDataIO(cp), (unsigned short *) (info->xmit_buf + info->xmit_tail), c / 2); if (c & 1) - sOutB(sGetTxRxDataIO(cp), - info->xmit_buf[info->xmit_tail + c - - 1]); + sOutB(sGetTxRxDataIO(cp), info->xmit_buf[info->xmit_tail + c - 1]); info->xmit_tail += c; - info->xmit_tail &= XMIT_BUF_SIZE-1; + info->xmit_tail &= XMIT_BUF_SIZE - 1; info->xmit_cnt -= c; info->xmit_fifo_room -= c; #ifdef ROCKET_DEBUG_INTR - printk("tx %d chars...", c); + printk(KERN_INFO "tx %d chars...", c); #endif } + if (info->xmit_cnt == 0) - xmit_flags[info->line >> 5] &= ~(1 << (info->line & 0x1f)); + clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); + if (info->xmit_cnt < WAKEUP_CHARS) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_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); +#ifdef ROCKETPORT_HAVE_POLL_WAIT + wake_up_interruptible(&tty->poll_wait); +#endif } + + spin_unlock_irqrestore(&info->slock, flags); + #ifdef ROCKET_DEBUG_INTR - printk("(%d,%d,%d,%d)...", info->xmit_cnt, info->xmit_head, + printk(KERN_INFO "(%d,%d,%d,%d)...", info->xmit_cnt, info->xmit_head, info->xmit_tail, info->xmit_fifo_room); #endif } /* - * This function is called for each port which has signalled an - * interrupt. It checks what interrupts are pending and services - * them. + * Called when a serial port signals it has read data in it's RX FIFO. + * It checks what interrupts are pending and services them, including + * receiving serial data. */ -static _INLINE_ void rp_handle_port(struct r_port *info) +static void rp_handle_port(struct r_port *info) { CHANNEL_t *cp; struct tty_struct *tty; @@ -381,12 +512,13 @@ if (!info) return; - if ( (info->flags & ROCKET_INITIALIZED) == 0 ) { - printk("rp: WARNING: rp_handle_port called with info->flags & NOT_INIT\n"); + + if ((info->flags & ROCKET_INITIALIZED) == 0) { + printk(KERN_INFO "rp: WARNING: rp_handle_port called with info->flags & NOT_INIT\n"); return; } if (!info->tty) { - printk("rp: WARNING: rp_handle_port called with info->tty==NULL\n"); + printk(KERN_INFO "rp: WARNING: rp_handle_port called with info->tty==NULL\n"); return; } cp = &info->channel; @@ -394,28 +526,20 @@ IntMask = sGetChanIntID(cp) & info->intmask; #ifdef ROCKET_DEBUG_INTR - printk("rp_interrupt %02x...", IntMask); + printk(KERN_INFO "rp_interrupt %02x...", IntMask); #endif - ChanStatus= sGetChanStatus(cp); + ChanStatus = sGetChanStatus(cp); if (IntMask & RXF_TRIG) { /* Rx FIFO trigger level */ rp_do_receive(info, tty, cp, ChanStatus); } -#if 0 - if (IntMask & SRC_INT) { /* Special receive condition */ - } -#endif if (IntMask & DELTA_CD) { /* CD change */ -#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_INTR) || \ - defined(ROCKET_DEBUG_HANGUP)) - printk("ttyR%d CD now %s...", info->line, +#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_INTR) || defined(ROCKET_DEBUG_HANGUP)) + printk(KERN_INFO "ttyR%d CD now %s...", info->line, (ChanStatus & CD_ACT) ? "on" : "off"); #endif - if (!(ChanStatus & CD_ACT) && - info->cd_status && - !((info->flags & ROCKET_CALLOUT_ACTIVE) && - (info->flags & ROCKET_CALLOUT_NOHUP))) { + if (!(ChanStatus & CD_ACT) && info->cd_status) { #ifdef ROCKET_DEBUG_HANGUP - printk("CD drop, calling hangup.\n"); + printk(KERN_INFO "CD drop, calling hangup.\n"); #endif tty_hangup(tty); } @@ -424,125 +548,166 @@ } #ifdef ROCKET_DEBUG_INTR if (IntMask & DELTA_CTS) { /* CTS change */ - printk("CTS change...\n"); + printk(KERN_INFO "CTS change...\n"); } if (IntMask & DELTA_DSR) { /* DSR change */ - printk("DSR change...\n"); + printk(KERN_INFO "DSR change...\n"); } #endif } /* - * The top level polling routine. + * The top level polling routine. Repeats every 1/100 HZ (10ms). */ static void rp_do_poll(unsigned long dummy) { CONTROLLER_t *ctlp; - int ctrl, aiop, ch, line; + int ctrl, aiop, ch, line, i; unsigned int xmitmask; - unsigned char CtlMask, AiopMask; + unsigned int CtlMask; + unsigned char AiopMask; + Word_t bit; #ifdef TIME_STAT - unsigned long loop_time; - unsigned long long time_stat_tmp=0, time_stat_tmp2=0; + unsigned long low = 0, high = 0, loop_time; + unsigned long long time_stat_tmp = 0, time_stat_tmp2 = 0; - rdtscll(time_stat_tmp); -#endif /* TIME_STAT */ + __asm__(".byte 0x0f,0x31":"=a"(low), "=d"(high)); + time_stat_tmp = high; + time_stat_tmp <<= 32; + time_stat_tmp += low; +#endif /* TIME_STAT */ - for (ctrl=0; ctrl < max_board; ctrl++) { + /* Walk through all the boards (ctrl's) */ + for (ctrl = 0; ctrl < max_board; ctrl++) { if (rcktpt_io_addr[ctrl] <= 0) continue; - ctlp= sCtlNumToCtlPtr(ctrl); + /* Get a ptr to the board's control struct */ + ctlp = sCtlNumToCtlPtr(ctrl); + + /* Get the interupt status from the board */ #ifdef CONFIG_PCI - if(ctlp->BusType == isPCI) - CtlMask= sPCIGetControllerIntStatus(ctlp); + if (ctlp->BusType == isPCI) + CtlMask = sPCIGetControllerIntStatus(ctlp); else #endif - CtlMask= sGetControllerIntStatus(ctlp); - for (aiop=0; CtlMask; CtlMask >>= 1, aiop++) { - if (CtlMask & 1) { - AiopMask= sGetAiopIntStatus(ctlp, aiop); - for (ch=0; AiopMask; AiopMask >>= 1, ch++) { + CtlMask = sGetControllerIntStatus(ctlp); + + /* Check if any AIOP read bits are set */ + for (aiop = 0; CtlMask; aiop++) { + bit = ctlp->AiopIntrBits[aiop]; + if (CtlMask & bit) { + CtlMask &= ~bit; + AiopMask = sGetAiopIntStatus(ctlp, aiop); + + /* Check if any port read bits are set */ + for (ch = 0; AiopMask; AiopMask >>= 1, ch++) { if (AiopMask & 1) { - line = (ctrl << 5) | - (aiop << 3) | ch; + + /* Get the line number (/dev/ttyRx number). */ + /* Read the data from the port. */ + line = GetLineNumber(ctrl, aiop, ch); rp_handle_port(rp_table[line]); } } } } + xmitmask = xmit_flags[ctrl]; - for (line = ctrl << 5; xmitmask; xmitmask >>= 1, line++) { - if (xmitmask & 1) - rp_do_transmit(rp_table[line]); + + /* + * xmit_flags contains bit-significant flags, indicating there is data + * to xmit on the port. Bit 0 is port 0 on this board, bit 1 is port + * 1, ... (32 total possible). The variable i has the aiop and ch + * numbers encoded in it (port 0-7 are aiop0, 8-15 are aiop1, etc). + */ + if (xmitmask) { + for (i = 0; i < rocketModel[ctrl].numPorts; i++) { + if (xmitmask & (1 << i)) { + aiop = (i & 0x18) >> 3; + ch = i & 0x07; + line = GetLineNumber(ctrl, aiop, ch); + rp_do_transmit(rp_table[line]); + } + } } } /* - * Reset the timer so we get called at the next clock tick. + * Reset the timer so we get called at the next clock tick (10ms). */ - if (rp_num_ports_open) { - mod_timer(&rocket_timer, jiffies + 1); - } + if (atomic_read(&rp_num_ports_open)) + mod_timer(&rocket_timer, jiffies + POLL_PERIOD); + #ifdef TIME_STAT - rdtscll(time_stat_tmp2); + __asm__(".byte 0x0f,0x31":"=a"(low), "=d"(high)); + time_stat_tmp2 = high; + time_stat_tmp2 <<= 32; + time_stat_tmp2 += low; time_stat_tmp2 -= time_stat_tmp; time_stat += time_stat_tmp2; - if (time_counter == 0) + if (time_counter == 0) time_stat_short = time_stat_long = time_stat_tmp2; else { - if ( time_stat_tmp2 < time_stat_short ) + if (time_stat_tmp2 < time_stat_short) time_stat_short = time_stat_tmp2; - else if ( time_stat_tmp2 > time_stat_long ) + else if (time_stat_tmp2 > time_stat_long) time_stat_long = time_stat_tmp2; } - if ( ++time_counter == TIME_COUNTER ) { - loop_time = (unsigned long) ( ((unsigned long)(time_stat >> 32) * ( (unsigned long)(0xffffffff)/(TIME_STAT_CPU * TIME_COUNTER) ) ) + ((unsigned long)time_stat/(TIME_STAT_CPU*TIME_COUNTER))); + if (++time_counter == TIME_COUNTER) { + loop_time = + (unsigned + long) (((unsigned long) (time_stat >> 32) * + ((unsigned long) (0xffffffff) / + (TIME_STAT_CPU * TIME_COUNTER))) + + ((unsigned long) time_stat / + (TIME_STAT_CPU * TIME_COUNTER))); #ifdef TIME_STAT_VERBOSE - printk("rp_do_poll: Interrupt Timings\n"); - printk(" %5ld iterations; %ld us min,\n", - (long)TIME_COUNTER, (time_stat_short/TIME_STAT_CPU)); - printk(" %5ld us max, %ld us average per iteration.\n", - (time_stat_long/TIME_STAT_CPU), loop_time); - printk("We want to use < 5,000 us for an iteration.\n"); -#else /* TIME_STAT_VERBOSE */ - printk("rp: %ld loops: %ld min, %ld max, %ld us/loop.\n", - (long)TIME_COUNTER, (time_stat_short/TIME_STAT_CPU), - (time_stat_long/TIME_STAT_CPU), loop_time); -#endif /* TIME_STAT_VERBOSE */ + printk(KERN_INFO "rp_do_poll: Interrupt Timings\n"); + printk(KERN_INFO " %5ld iterations; %ld us min,\n", + (long) TIME_COUNTER, + (time_stat_short / TIME_STAT_CPU)); + printk(KERN_INFO " %5ld us max, %ld us average per iteration.\n", + (time_stat_long / TIME_STAT_CPU), loop_time); + printk(KERN_INFO "We want to use < 5,000 us for an iteration.\n"); +#else /* TIME_STAT_VERBOSE */ + printk(KERN_INFO "rp: %ld loops: %ld min, %ld max, %ld us/loop.\n", + (long) TIME_COUNTER, + (time_stat_short / TIME_STAT_CPU), + (time_stat_long / TIME_STAT_CPU), loop_time); +#endif /* TIME_STAT_VERBOSE */ time_counter = time_stat = 0; time_stat_short = time_stat_long = 0; } -#endif /* TIME_STAT */ +#endif /* TIME_STAT */ } -/* - * Here ends the interrupt/polling routine. - */ - /* - * This function initializes the r_port structure, as well as enabling - * the port on the RocketPort board. + * Initializes the r_port structure for a port, as well as enabling the port on + * the board. + * Inputs: board, aiop, chan numbers */ -static void init_r_port(int board, int aiop, int chan) +static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev) { + unsigned rocketMode; struct r_port *info; int line; CONTROLLER_T *ctlp; - CHANNEL_t *cp; - - line = (board << 5) | (aiop << 3) | chan; - ctlp= sCtlNumToCtlPtr(board); + /* Get the next available line number */ + line = SetLineNumber(board, aiop, chan); - info = kmalloc(sizeof(struct r_port), GFP_KERNEL); + ctlp = sCtlNumToCtlPtr(board); + + /* Get a r_port struct for the port, fill it in and save it globally, indexed by line number */ + info = kmalloc(sizeof (struct r_port), GFP_KERNEL); if (!info) { - printk("Couldn't allocate info struct for line #%d\n", line); + printk(KERN_INFO "Couldn't allocate info struct for line #%d\n", line); return; } - memset(info, 0, sizeof(struct r_port)); - + memset(info, 0, sizeof (struct r_port)); + info->magic = RPORT_MAGIC; info->line = line; info->ctlp = ctlp; @@ -551,35 +716,76 @@ info->chan = chan; info->closing_wait = 3000; info->close_delay = 50; - info->callout_termios =callout_driver.init_termios; info->normal_termios = rocket_driver.init_termios; init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); + info->flags &= ~ROCKET_MODE_MASK; + switch (pc104[board][line]) { + case 422: + info->flags |= ROCKET_MODE_RS422; + break; + case 485: + info->flags |= ROCKET_MODE_RS485; + break; + case 232: + default: + info->flags |= ROCKET_MODE_RS232; + break; + } - info->intmask = RXF_TRIG | TXFIFO_MT | SRC_INT | DELTA_CD | - DELTA_CTS | DELTA_DSR; + info->intmask = RXF_TRIG | TXFIFO_MT | SRC_INT | DELTA_CD | DELTA_CTS | DELTA_DSR; if (sInitChan(ctlp, &info->channel, aiop, chan) == 0) { - printk("Rocketport sInitChan(%d, %d, %d) failed!\n", - board, aiop, chan); + printk(KERN_INFO "RocketPort sInitChan(%d, %d, %d) failed!\n", board, aiop, chan); kfree(info); return; } - cp = &info->channel; + + rocketMode = info->flags & ROCKET_MODE_MASK; + + if ((info->flags & ROCKET_RTS_TOGGLE) || (rocketMode == ROCKET_MODE_RS485)) + sEnRTSToggle(&info->channel); + else + sDisRTSToggle(&info->channel); + + if (ctlp->boardType == ROCKET_TYPE_PC104) { + switch (rocketMode) { + case ROCKET_MODE_RS485: + sSetInterfaceMode(&info->channel, InterfaceModeRS485); + break; + case ROCKET_MODE_RS422: + sSetInterfaceMode(&info->channel, InterfaceModeRS422); + break; + case ROCKET_MODE_RS232: + default: + if (info->flags & ROCKET_RTS_TOGGLE) + sSetInterfaceMode(&info->channel, InterfaceModeRS232T); + else + sSetInterfaceMode(&info->channel, InterfaceModeRS232); + break; + } + } + spin_lock_init(&info->slock); + sema_init(&info->write_sem, 1); rp_table[line] = info; +#if LINUX_VERSION_CODE > VERSION_CODE(2,5,0) + if (pci_dev) + tty_register_device(&rocket_driver, line, &pci_dev->dev); +#endif } - /* - * This routine configures a rocketport port so according to its - * termio settings. + * Configures a rocketport port according to its termio settings. Called from + * user mode into the driver (exception handler). *info CD manipulation is spinlock protected. */ -static void configure_r_port(struct r_port *info) +static void configure_r_port(struct r_port *info, + struct termios *old_termios) { unsigned cflag; - unsigned long flags; - int bits, baud; - CHANNEL_t *cp; - + unsigned long flags; + unsigned rocketMode; + int bits, baud, divisor; + CHANNEL_t *cp; + if (!info->tty || !info->tty->termios) return; cp = &info->channel; @@ -593,13 +799,13 @@ sSetData7(cp); bits = 9; } - if (cflag & CSTOPB) { + if (cflag & CSTOPB) { sSetStop2(cp); bits++; } else { sSetStop1(cp); } - + if (cflag & PARENB) { sEnParity(cp); bits++; @@ -611,14 +817,28 @@ } else { sDisParity(cp); } - + /* baud rate */ baud = tty_get_baud_rate(info->tty); if (!baud) baud = 9600; + divisor = ((rp_baud_base[info->board] + (baud >> 1)) / baud) - 1; + if ((divisor >= 8192 || divisor < 0) && old_termios) { + info->tty->termios->c_cflag &= ~CBAUD; + info->tty->termios->c_cflag |= + (old_termios->c_cflag & CBAUD); + baud = tty_get_baud_rate(info->tty); + if (!baud) + baud = 9600; + divisor = (rp_baud_base[info->board] / baud) - 1; + } + if (divisor >= 8192 || divisor < 0) { + baud = 9600; + divisor = (rp_baud_base[info->board] / baud) - 1; + } info->cps = baud / bits; - sSetBaud(cp, (rp_baud_base/baud) - 1); - + sSetBaud(cp, divisor); + if (cflag & CRTSCTS) { info->intmask |= DELTA_CTS; sEnCTSFlowCtl(cp); @@ -626,17 +846,16 @@ info->intmask &= ~DELTA_CTS; sDisCTSFlowCtl(cp); } - sSetRTS(&info->channel); - if (cflag & CLOCAL) + if (cflag & CLOCAL) { info->intmask &= ~DELTA_CD; - else { - save_flags(flags); cli(); + } else { + spin_lock_irqsave(&info->slock, flags); if (sGetChanStatus(cp) & CD_ACT) info->cd_status = 1; else info->cd_status = 0; info->intmask |= DELTA_CD; - restore_flags(flags); + spin_unlock_irqrestore(&info->slock, flags); } /* @@ -658,7 +877,7 @@ sClrTxXOFF(cp); } #endif - + /* * Set up ignore/read mask words */ @@ -683,296 +902,281 @@ if (I_IGNPAR(info->tty)) info->ignore_status_mask |= STMRCVROVRH; } + + rocketMode = info->flags & ROCKET_MODE_MASK; + + if ((info->flags & ROCKET_RTS_TOGGLE) + || (rocketMode == ROCKET_MODE_RS485)) + sEnRTSToggle(cp); + else + sDisRTSToggle(cp); + + sSetRTS(&info->channel); + + if (cp->CtlP->boardType == ROCKET_TYPE_PC104) { + switch (rocketMode) { + case ROCKET_MODE_RS485: + sSetInterfaceMode(cp, InterfaceModeRS485); + break; + case ROCKET_MODE_RS422: + sSetInterfaceMode(cp, InterfaceModeRS422); + break; + case ROCKET_MODE_RS232: + default: + if (info->flags & ROCKET_RTS_TOGGLE) + sSetInterfaceMode(cp, InterfaceModeRS232T); + else + sSetInterfaceMode(cp, InterfaceModeRS232); + break; + } + } } -static int block_til_ready(struct tty_struct *tty, struct file * filp, +/* info->count is considered critical, protected by spinlocks. */ +static int block_til_ready(struct tty_struct *tty, struct file *filp, struct r_port *info) { DECLARE_WAITQUEUE(wait, current); - int retval; - int do_clocal = 0, extra_count = 0; - unsigned long flags; + int retval; + int do_clocal = 0, extra_count = 0; + unsigned long flags; /* * If the device is in the middle of being closed, then block * until it's done, and then try again. */ if (tty_hung_up_p(filp)) - return ((info->flags & ROCKET_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS); + return ((info->flags & ROCKET_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); if (info->flags & ROCKET_CLOSING) { interruptible_sleep_on(&info->close_wait); - return ((info->flags & ROCKET_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS); + return ((info->flags & ROCKET_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); } /* - * If this is a callout device, then just make sure the normal - * device isn't being used. - */ - if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) { - if (info->flags & ROCKET_NORMAL_ACTIVE) - return -EBUSY; - if ((info->flags & ROCKET_CALLOUT_ACTIVE) && - (info->flags & ROCKET_SESSION_LOCKOUT) && - (info->session != current->session)) - return -EBUSY; - if ((info->flags & ROCKET_CALLOUT_ACTIVE) && - (info->flags & ROCKET_PGRP_LOCKOUT) && - (info->pgrp != current->pgrp)) - return -EBUSY; - info->flags |= ROCKET_CALLOUT_ACTIVE; - return 0; - } - - /* * If non-blocking mode is set, or the port is not enabled, * then make the check up front and then exit. */ - if ((filp->f_flags & O_NONBLOCK) || - (tty->flags & (1 << TTY_IO_ERROR))) { - if (info->flags & ROCKET_CALLOUT_ACTIVE) - return -EBUSY; + if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { info->flags |= ROCKET_NORMAL_ACTIVE; return 0; } + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; - if (info->flags & ROCKET_CALLOUT_ACTIVE) { - if (info->normal_termios.c_cflag & CLOCAL) - do_clocal = 1; - } else { - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - } - /* - * Block waiting for the carrier detect and the line to become - * free (i.e., not in use by the callout). While we are in - * this loop, info->count is dropped by one, so that - * rp_close() knows when to free things. We restore it upon - * exit, either normal or abnormal. + * Block waiting for the carrier detect and the line to become free. While we are in + * this loop, info->count is dropped by one, so that rp_close() knows when to free things. + * We restore it upon exit, either normal or abnormal. */ retval = 0; add_wait_queue(&info->open_wait, &wait); #ifdef ROCKET_DEBUG_OPEN - printk("block_til_ready before block: ttyR%d, count = %d\n", - info->line, info->count); + printk(KERN_INFO "block_til_ready before block: ttyR%d, count = %d\n", info->line, info->count); #endif - save_flags(flags); cli(); + spin_lock_irqsave(&info->slock, flags); + +#ifdef ROCKET_DISABLE_SIMUSAGE + info->flags |= ROCKET_NORMAL_ACTIVE; +#else if (!tty_hung_up_p(filp)) { extra_count = 1; info->count--; } - restore_flags(flags); +#endif info->blocked_open++; + + spin_unlock_irqrestore(&info->slock, flags); + while (1) { - if (!(info->flags & ROCKET_CALLOUT_ACTIVE) && - (tty->termios->c_cflag & CBAUD)) { + if (tty->termios->c_cflag & CBAUD) { sSetDTR(&info->channel); sSetRTS(&info->channel); } set_current_state(TASK_INTERRUPTIBLE); - if (tty_hung_up_p(filp) || - !(info->flags & ROCKET_INITIALIZED)) { + if (tty_hung_up_p(filp) || !(info->flags & ROCKET_INITIALIZED)) { if (info->flags & ROCKET_HUP_NOTIFY) retval = -EAGAIN; else - retval = -ERESTARTSYS; + retval = -ERESTARTSYS; break; } - if (!(info->flags & ROCKET_CALLOUT_ACTIVE) && - !(info->flags & ROCKET_CLOSING) && - (do_clocal || (sGetChanStatusLo(&info->channel) & - CD_ACT))) + if (!(info->flags & ROCKET_CLOSING) && (do_clocal || (sGetChanStatusLo(&info->channel) & CD_ACT))) break; if (signal_pending(current)) { retval = -ERESTARTSYS; break; } #ifdef ROCKET_DEBUG_OPEN - printk("block_til_ready blocking: ttyR%d, count = %d, flags=0x%0x\n", - info->line, info->count, info->flags); + printk(KERN_INFO "block_til_ready blocking: ttyR%d, count = %d, flags=0x%0x\n", + info->line, info->count, info->flags); #endif - schedule(); + schedule(); /* Don't hold spinlock here, will hang PC */ } current->state = TASK_RUNNING; remove_wait_queue(&info->open_wait, &wait); - cli(); + + spin_lock_irqsave(&info->slock, flags); + if (extra_count) info->count++; - restore_flags(flags); info->blocked_open--; + + spin_unlock_irqrestore(&info->slock, flags); + #ifdef ROCKET_DEBUG_OPEN - printk("block_til_ready after blocking: ttyR%d, count = %d\n", + printk(KERN_INFO "block_til_ready after blocking: ttyR%d, count = %d\n", info->line, info->count); #endif if (retval) return retval; info->flags |= ROCKET_NORMAL_ACTIVE; return 0; -} +} /* - * This routine is called whenever a rocketport board is opened. + * Exception handler that opens a serial port. Creates xmit_buf storage, fills in + * port's r_port struct. Initializes the port hardware. */ -static int rp_open(struct tty_struct *tty, struct file * filp) +static int rp_open(struct tty_struct *tty, struct file *filp) { struct r_port *info; - int line, retval; - CHANNEL_t *cp; + int line = 0, retval; + CHANNEL_t *cp; unsigned long page; - - line = tty->index; - if ((line < 0) || (line >= MAX_RP_PORTS)) - return -ENODEV; - if (!tmp_buf) { - page = get_zeroed_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - if (tmp_buf) - free_page(page); - else - tmp_buf = (unsigned char *) page; - } - page = get_zeroed_page(GFP_KERNEL); + +#if LINUX_VERSION_CODE > VERSION_CODE(2,5,0) + line = TTY_GET_LINE(tty); +#else + line = MINOR(tty->device) - TTY_DRIVER_MINOR_START(tty); +#endif + + if ((line < 0) || (line >= MAX_RP_PORTS) || ((info = rp_table[line]) == NULL)) + return -ENXIO; + + page = __get_free_page(GFP_KERNEL); if (!page) return -ENOMEM; - tty->driver_data = info = rp_table[line]; - if (info->flags & ROCKET_CLOSING) { interruptible_sleep_on(&info->close_wait); free_page(page); - return ((info->flags & ROCKET_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS); + return ((info->flags & ROCKET_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS); } - + /* - * We must not sleep from here until the port is marked fully - * in use. + * We must not sleep from here until the port is marked fully in use. */ - if (rp_table[line] == NULL) { - tty->flags = (1 << TTY_IO_ERROR); - free_page(page); - return 0; - } - if (!info) { - printk("rp_open: rp_table[%d] is NULL!\n", line); - free_page(page); - return -EIO; - } if (info->xmit_buf) free_page(page); else info->xmit_buf = (unsigned char *) page; - info->tty = tty; - if (info->flags & ROCKET_CLOSING) { - interruptible_sleep_on(&info->close_wait); - return ((info->flags & ROCKET_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS); - } + tty->driver_data = info; + info->tty = tty; if (info->count++ == 0) { - rp_num_ports_open++; +#if ((LINUX_VERSION_CODE < VERSION_CODE(2,5,0)) && defined(MODULE)) + MOD_INC_USE_COUNT; +#endif + atomic_inc(&rp_num_ports_open); + #ifdef ROCKET_DEBUG_OPEN - printk("rocket mod++ = %d...", rp_num_ports_open); + printk(KERN_INFO "rocket mod++ = %d...", atomic_read(&rp_num_ports_open)); #endif } #ifdef ROCKET_DEBUG_OPEN - printk("rp_open ttyR%d, count=%d\n", info->line, info->count); + printk(KERN_INFO "rp_open ttyR%d, count=%d\n", info->line, info->count); #endif + /* * Info->count is now 1; so it's safe to sleep now. */ info->session = current->session; info->pgrp = current->pgrp; - - cp = &info->channel; - sSetRxTrigger(cp, TRIG_1); - if (sGetChanStatus(cp) & CD_ACT) - info->cd_status = 1; - else - info->cd_status = 0; - sDisRxStatusMode(cp); - sFlushRxFIFO(cp); - sFlushTxFIFO(cp); - sEnInterrupts(cp, (TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN)); - sSetRxTrigger(cp, TRIG_1); + if ((info->flags & ROCKET_INITIALIZED) == 0) { + cp = &info->channel; + sSetRxTrigger(cp, TRIG_1); + if (sGetChanStatus(cp) & CD_ACT) + info->cd_status = 1; + else + info->cd_status = 0; + sDisRxStatusMode(cp); + sFlushRxFIFO(cp); + sFlushTxFIFO(cp); - sGetChanStatus(cp); - sDisRxStatusMode(cp); - sClrTxXOFF(cp); + sEnInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN)); + sSetRxTrigger(cp, TRIG_1); - sDisCTSFlowCtl(cp); - sDisTxSoftFlowCtl(cp); + sGetChanStatus(cp); + sDisRxStatusMode(cp); + sClrTxXOFF(cp); - sEnRxFIFO(cp); - sEnTransmit(cp); + sDisCTSFlowCtl(cp); + sDisTxSoftFlowCtl(cp); - info->flags |= ROCKET_INITIALIZED; + sEnRxFIFO(cp); + sEnTransmit(cp); - /* - * Set up the tty->alt_speed kludge - */ - if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI) - info->tty->alt_speed = 57600; - if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI) - info->tty->alt_speed = 115200; - if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI) - info->tty->alt_speed = 230400; - if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP) - info->tty->alt_speed = 460800; + info->flags |= ROCKET_INITIALIZED; - configure_r_port(info); - if (tty->termios->c_cflag & CBAUD) { - sSetDTR(cp); - sSetRTS(cp); + /* + * Set up the tty->alt_speed kludge + */ + if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI) + info->tty->alt_speed = 57600; + if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI) + info->tty->alt_speed = 115200; + if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI) + info->tty->alt_speed = 230400; + if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP) + info->tty->alt_speed = 460800; + + configure_r_port(info, NULL); + if (tty->termios->c_cflag & CBAUD) { + sSetDTR(cp); + sSetRTS(cp); + } } - - mod_timer(&rocket_timer, jiffies + 1); + /* Starts (or resets) the maint polling loop */ + mod_timer(&rocket_timer, jiffies + POLL_PERIOD); retval = block_til_ready(tty, filp, info); if (retval) { #ifdef ROCKET_DEBUG_OPEN - printk("rp_open returning after block_til_ready with %d\n", - retval); + printk(KERN_INFO "rp_open returning after block_til_ready with %d\n", retval); #endif return retval; } if ((info->count == 1) && (info->flags & ROCKET_SPLIT_TERMIOS)) { - if (tty->driver->subtype == SERIAL_TYPE_NORMAL) - *tty->termios = info->normal_termios; - else - *tty->termios = info->callout_termios; - configure_r_port(info); + *tty->termios = info->normal_termios; + configure_r_port(info, NULL); } - return 0; } -static void rp_close(struct tty_struct *tty, struct file * filp) +/* + * Exception handler that closes a serial port. info->count is considered critical. + */ +static void rp_close(struct tty_struct *tty, struct file *filp) { - struct r_port * info = (struct r_port *)tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; unsigned long flags; int timeout; - CHANNEL_t *cp; + CHANNEL_t *cp; - if (rocket_paranoia_check(info, tty->name, "rp_close")) + if (rocket_paranoia_check(info, "rp_close")) return; #ifdef ROCKET_DEBUG_OPEN - printk("rp_close ttyR%d, count = %d\n", info->line, info->count); + printk(KERN_INFO "rp_close ttyR%d, count = %d\n", info->line, info->count); #endif - - save_flags(flags); cli(); - - if (tty_hung_up_p(filp)) { - restore_flags(flags); + + if (tty_hung_up_p(filp)) return; - } + spin_lock_irqsave(&info->slock, flags); + if ((tty->count == 1) && (info->count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty @@ -981,29 +1185,23 @@ * one, we've got real problems, since it means the * serial port won't be shutdown. */ - printk("rp_close: bad serial port count; tty->count is 1, " + printk(KERN_INFO "rp_close: bad serial port count; tty->count is 1, " "info->count is %d\n", info->count); info->count = 1; } if (--info->count < 0) { - printk("rp_close: bad serial port count for ttyR%d: %d\n", + printk(KERN_INFO "rp_close: bad serial port count for ttyR%d: %d\n", info->line, info->count); info->count = 0; } if (info->count) { - restore_flags(flags); + spin_unlock_irqrestore(&info->slock, flags); return; } info->flags |= ROCKET_CLOSING; - /* - * Save the termios structure, since this port may have - * separate termios for callout and dialin. - */ - if (info->flags & ROCKET_NORMAL_ACTIVE) - info->normal_termios = *tty->termios; - if (info->flags & ROCKET_CALLOUT_ACTIVE) - info->callout_termios = *tty->termios; - + spin_unlock_irqrestore(&info->slock, flags); + + info->normal_termios = *tty->termios; cp = &info->channel; /* @@ -1028,29 +1226,30 @@ * has completely drained; this is especially * important if there is a transmit FIFO! */ - timeout = (sGetTxCnt(cp)+1) * HZ / info->cps; + timeout = (sGetTxCnt(cp) + 1) * HZ / info->cps; if (timeout == 0) timeout = 1; rp_wait_until_sent(tty, timeout); - - xmit_flags[info->line >> 5] &= ~(1 << (info->line & 0x1f)); + clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); + sDisTransmit(cp); - sDisInterrupts(cp, (TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN)); + sDisInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN)); sDisCTSFlowCtl(cp); sDisTxSoftFlowCtl(cp); sClrTxXOFF(cp); - sFlushRxFIFO(cp); + sFlushRxFIFO(cp); sFlushTxFIFO(cp); sClrRTS(cp); - if (C_HUPCL(tty)) { + if (C_HUPCL(tty)) sClrDTR(cp); - } - if (tty->driver->flush_buffer) - tty->driver->flush_buffer(tty); + + if (TTY_DRIVER_FLUSH_BUFFER_EXISTS(tty)) + TTY_DRIVER_FLUSH_BUFFER(tty); if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); - xmit_flags[info->line >> 5] &= ~(1 << (info->line & 0x1f)); + clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); + if (info->blocked_open) { if (info->close_delay) { current->state = TASK_INTERRUPTIBLE; @@ -1063,31 +1262,30 @@ info->xmit_buf = 0; } } - info->flags &= ~(ROCKET_INITIALIZED | ROCKET_CLOSING | - ROCKET_CALLOUT_ACTIVE | ROCKET_NORMAL_ACTIVE); + info->flags &= ~(ROCKET_INITIALIZED | ROCKET_CLOSING | ROCKET_NORMAL_ACTIVE); tty->closing = 0; wake_up_interruptible(&info->close_wait); - - rp_num_ports_open--; -#ifdef ROCKET_DEBUG_OPEN - printk("rocket mod-- = %d...", rp_num_ports_open); + +#if ((LINUX_VERSION_CODE < VERSION_CODE(2,5,0)) && defined(MODULE)) + MOD_DEC_USE_COUNT; #endif - restore_flags(flags); - + atomic_dec(&rp_num_ports_open); + #ifdef ROCKET_DEBUG_OPEN - printk("rp_close ttyR%d complete shutdown\n", info->line); + printk(KERN_INFO "rocket mod-- = %d...", atomic_read(&rp_num_ports_open)); + printk(KERN_INFO "rp_close ttyR%d complete shutdown\n", info->line); #endif - + } -static void rp_set_termios(struct tty_struct *tty, struct termios *old_termios) +static void rp_set_termios(struct tty_struct *tty, + struct termios *old_termios) { - struct r_port * info = (struct r_port *)tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; CHANNEL_t *cp; unsigned cflag; - - if (rocket_paranoia_check(info, tty->name, "rp_set_termios")) + if (rocket_paranoia_check(info, "rp_set_termios")) return; cflag = tty->termios->c_cflag; @@ -1098,88 +1296,103 @@ /* * This driver doesn't support CS5 or CS6 */ - if (((cflag & CSIZE) == CS5) || - ((cflag & CSIZE) == CS6)) - tty->termios->c_cflag = ((cflag & ~CSIZE) | - (old_termios->c_cflag & CSIZE)); + if (((cflag & CSIZE) == CS5) || ((cflag & CSIZE) == CS6)) + tty->termios->c_cflag = + ((cflag & ~CSIZE) | (old_termios->c_cflag & CSIZE)); - configure_r_port(info); + configure_r_port(info, old_termios); cp = &info->channel; /* Handle transition to B0 status */ - if ((old_termios->c_cflag & CBAUD) && - !(tty->termios->c_cflag & CBAUD)) { + if ((old_termios->c_cflag & CBAUD) && !(tty->termios->c_cflag & CBAUD)) { sClrDTR(cp); sClrRTS(cp); } - + /* Handle transition away from B0 status */ - if (!(old_termios->c_cflag & CBAUD) && - (tty->termios->c_cflag & CBAUD)) { - if (!tty->hw_stopped || - !(tty->termios->c_cflag & CRTSCTS)) { + if (!(old_termios->c_cflag & CBAUD) && (tty->termios->c_cflag & CBAUD)) { + if (!tty->hw_stopped || !(tty->termios->c_cflag & CRTSCTS)) sSetRTS(cp); - } sSetDTR(cp); } - - if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { + + if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { tty->hw_stopped = 0; rp_start(tty); } } -/* - * Here are the routines used by rp_ioctl - */ static void rp_break(struct tty_struct *tty, int break_state) { - struct r_port * info = (struct r_port *)tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; unsigned long flags; - - if (rocket_paranoia_check(info, tty->name, "rp_break")) + + if (rocket_paranoia_check(info, "rp_break")) return; - save_flags(flags); cli(); - if (break_state == -1) { + spin_lock_irqsave(&info->slock, flags); + if (break_state == -1) sSendBreak(&info->channel); - } else { + else sClrBreak(&info->channel); - } - restore_flags(flags); + spin_unlock_irqrestore(&info->slock, flags); } -static int get_modem_info(struct r_port * info, unsigned int *value) +/* + * sGetChanRI used to be a macro in rocket_int.h. When the functionality for + * the UPCI boards was added, it was decided to make this a function because + * the macro was getting too complicated. All cases except the first one + * (UPCIRingInd) are taken directly from the original macro. + */ +static int sGetChanRI(CHANNEL_T * ChP) +{ + CONTROLLER_t *CtlP = ChP->CtlP; + int ChanNum = ChP->ChanNum; + int RingInd = 0; + + if (CtlP->UPCIRingInd) + RingInd = !(sInB(CtlP->UPCIRingInd) & sBitMapSetTbl[ChanNum]); + else if (CtlP->AltChanRingIndicator) + RingInd = sInB((ByteIO_t) (ChP->ChanStat + 8)) & DSR_ACT; + else if (CtlP->boardType == ROCKET_TYPE_PC104) + RingInd = !(sInB(CtlP->AiopIO[3]) & sBitMapSetTbl[ChanNum]); + + return RingInd; +} + +/********************************************************************************************/ +/* Here are the routines used by rp_ioctl. These are all called from exception handlers. */ + +static int get_modem_info(struct r_port *info, unsigned int *value) { unsigned int control, result, ChanStatus; ChanStatus = sGetChanStatusLo(&info->channel); - + control = info->channel.TxControl[3]; - result = ((control & SET_RTS) ? TIOCM_RTS : 0) - | ((control & SET_DTR) ? TIOCM_DTR : 0) - | ((ChanStatus & CD_ACT) ? TIOCM_CAR : 0) - /* TIOCM_RNG not supported */ - | ((ChanStatus & DSR_ACT) ? TIOCM_DSR : 0) - | ((ChanStatus & CTS_ACT) ? TIOCM_CTS : 0); + result = ((control & SET_RTS) ? TIOCM_RTS : 0) | + ((control & SET_DTR) ? TIOCM_DTR : 0) | + ((ChanStatus & CD_ACT) ? TIOCM_CAR : 0) | + (sGetChanRI(&info->channel) ? TIOCM_RNG : 0) | + ((ChanStatus & DSR_ACT) ? TIOCM_DSR : 0) | + ((ChanStatus & CTS_ACT) ? TIOCM_CTS : 0); - if (copy_to_user(value, &result, sizeof(int))) + if (copy_to_user(value, &result, sizeof (int))) return -EFAULT; return 0; } -static int set_modem_info(struct r_port * info, unsigned int cmd, +static int set_modem_info(struct r_port *info, unsigned int cmd, unsigned int *value) { unsigned int arg; - if (copy_from_user(&arg, value, sizeof(int))) + if (copy_from_user(&arg, value, sizeof (int))) return -EFAULT; switch (cmd) { - case TIOCMBIS: + case TIOCMBIS: if (arg & TIOCM_RTS) info->channel.TxControl[3] |= SET_RTS; if (arg & TIOCM_DTR) @@ -1192,59 +1405,103 @@ info->channel.TxControl[3] &= ~SET_DTR; break; case TIOCMSET: - info->channel.TxControl[3] = - ((info->channel.TxControl[3] & ~(SET_RTS | SET_DTR)) - | ((arg & TIOCM_RTS) ? SET_RTS : 0) - | ((arg & TIOCM_DTR) ? SET_DTR : 0)); + info->channel.TxControl[3] = ((info->channel.TxControl[3] & ~(SET_RTS | SET_DTR)) | + ((arg & TIOCM_RTS) ? SET_RTS : 0) | + ((arg & TIOCM_DTR) ? SET_DTR : 0)); break; default: return -EINVAL; } - sOutDW(info->channel.IndexAddr, - *(DWord_t *) &(info->channel.TxControl[0])); - + sOutDW(info->channel.IndexAddr, *(DWord_t *) & (info->channel.TxControl[0])); + return 0; +} + +#if LINUX_VERSION_CODE > VERSION_CODE(2,5,0) + +/* + * Returns the state of the serial modem control lines. These next 2 functions + * are the way kernel versions > 2.5 handle modem control lines rather than IOCTLs. + */ +static int rp_tiocmget(struct tty_struct *tty, struct file *file) +{ + struct r_port *info = (struct r_port *)tty->driver_data; + unsigned int control, result, ChanStatus; + + ChanStatus = sGetChanStatusLo(&info->channel); + control = info->channel.TxControl[3]; + result = ((control & SET_RTS) ? TIOCM_RTS : 0) | + ((control & SET_DTR) ? TIOCM_DTR : 0) | + ((ChanStatus & CD_ACT) ? TIOCM_CAR : 0) | + (sGetChanRI(&info->channel) ? TIOCM_RNG : 0) | + ((ChanStatus & DSR_ACT) ? TIOCM_DSR : 0) | + ((ChanStatus & CTS_ACT) ? TIOCM_CTS : 0); + + return result; +} + +/* + * Sets the modem control lines + */ +static int rp_tiocmset(struct tty_struct *tty, struct file *file, + unsigned int set, unsigned int clear) +{ + struct r_port *info = (struct r_port *)tty->driver_data; + + if (set & TIOCM_RTS) + info->channel.TxControl[3] |= SET_RTS; + if (set & TIOCM_DTR) + info->channel.TxControl[3] |= SET_DTR; + if (clear & TIOCM_RTS) + info->channel.TxControl[3] &= ~SET_RTS; + if (clear & TIOCM_DTR) + info->channel.TxControl[3] &= ~SET_DTR; + + sOutDW(info->channel.IndexAddr, *(DWord_t *) & (info->channel.TxControl[0])); return 0; } -static int get_config(struct r_port * info, struct rocket_config * retinfo) +#endif /* Linux > 2.5 */ + +static int get_config(struct r_port *info, struct rocket_config *retinfo) { struct rocket_config tmp; - + if (!retinfo) return -EFAULT; - memset(&tmp, 0, sizeof(tmp)); + memset(&tmp, 0, sizeof (tmp)); tmp.line = info->line; tmp.flags = info->flags; tmp.close_delay = info->close_delay; tmp.closing_wait = info->closing_wait; tmp.port = rcktpt_io_addr[(info->line >> 5) & 3]; - - if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) + + if (copy_to_user(retinfo, &tmp, sizeof (*retinfo))) return -EFAULT; return 0; } -static int set_config(struct r_port * info, struct rocket_config * new_info) +static int set_config(struct r_port *info, struct rocket_config *new_info) { struct rocket_config new_serial; - if (copy_from_user(&new_serial, new_info, sizeof(new_serial))) + if (copy_from_user(&new_serial, new_info, sizeof (new_serial))) return -EFAULT; +#ifdef CAP_SYS_ADMIN if (!capable(CAP_SYS_ADMIN)) +#else + if (!suser()) +#endif { - if ((new_serial.flags & ~ROCKET_USR_MASK) != - (info->flags & ~ROCKET_USR_MASK)) + if ((new_serial.flags & ~ROCKET_USR_MASK) != (info->flags & ~ROCKET_USR_MASK)) return -EPERM; - info->flags = ((info->flags & ~ROCKET_USR_MASK) | - (new_serial.flags & ROCKET_USR_MASK)); - configure_r_port(info); + info->flags = ((info->flags & ~ROCKET_USR_MASK) | (new_serial.flags & ROCKET_USR_MASK)); + configure_r_port(info, 0); return 0; } - - info->flags = ((info->flags & ~ROCKET_FLAGS) | - (new_serial.flags & ROCKET_FLAGS)); + + info->flags = ((info->flags & ~ROCKET_FLAGS) | (new_serial.flags & ROCKET_FLAGS)); info->close_delay = new_serial.close_delay; info->closing_wait = new_serial.closing_wait; @@ -1256,117 +1513,162 @@ info->tty->alt_speed = 230400; if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP) info->tty->alt_speed = 460800; - - configure_r_port(info); + + configure_r_port(info, 0); return 0; } -static int get_ports(struct r_port * info, struct rocket_ports * retports) +/* + * This function fills in a rocket_ports struct with information + * about what boards/ports are in the system. This info is passed + * to user space. See setrocket.c where the info is used to create + * the /dev/ttyRx ports. + */ +static int get_ports(struct r_port *info, struct rocket_ports *retports) { struct rocket_ports tmp; - int board, port, index; - + int board; + if (!retports) return -EFAULT; - memset(&tmp, 0, sizeof(tmp)); + memset(&tmp, 0, sizeof (tmp)); tmp.tty_major = rocket_driver.major; - tmp.callout_major = callout_driver.major; + for (board = 0; board < 4; board++) { - index = board << 5; - for (port = 0; port < 32; port++, index++) { - if (rp_table[index]) - tmp.port_bitmap[board] |= 1 << port; - } + tmp.rocketModel[board].model = rocketModel[board].model; + strcpy(tmp.rocketModel[board].modelString, rocketModel[board].modelString); + tmp.rocketModel[board].numPorts = rocketModel[board].numPorts; + tmp.rocketModel[board].loadrm2 = rocketModel[board].loadrm2; + tmp.rocketModel[board].startingPortNumber = rocketModel[board].startingPortNumber; } - if (copy_to_user(retports,&tmp,sizeof(*retports))) + if (copy_to_user(retports, &tmp, sizeof (*retports))) return -EFAULT; return 0; } -static int rp_ioctl(struct tty_struct *tty, struct file * file, +static int reset_rm2(struct r_port *info, unsigned long arg) +{ + int reset; + + if (copy_from_user(&reset, (void *) arg, sizeof (int))) + return -EFAULT; + if (reset) + reset = 1; + + if (rcktpt_type[info->board] != ROCKET_TYPE_MODEMII && + rcktpt_type[info->board] != ROCKET_TYPE_MODEMIII) + return -EINVAL; + + if (info->ctlp->BusType == isISA) + sModemReset(info->ctlp, info->chan, reset); + else + sPCIModemReset(info->ctlp, info->chan, reset); + + return 0; +} + +static int get_version(struct r_port *info, struct rocket_version *retvers) +{ + if (copy_to_user(retvers, &driver_version, sizeof (*retvers))) + return -EFAULT; + return 0; +} + +/* IOCTL call handler into the driver */ +static int rp_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { - struct r_port * info = (struct r_port *)tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; - if (cmd != RCKP_GET_PORTS && - rocket_paranoia_check(info, tty->name, "rp_ioctl")) - return -ENODEV; + if (cmd != RCKP_GET_PORTS && rocket_paranoia_check(info, "rp_ioctl")) + return -ENXIO; switch (cmd) { - - case TIOCMGET: - return get_modem_info(info, (unsigned int *) arg); - case TIOCMBIS: - case TIOCMBIC: - case TIOCMSET: - return set_modem_info(info, cmd, (unsigned int *) arg); - case RCKP_GET_STRUCT: - if (copy_to_user((void *) arg, info, - sizeof(struct r_port))) - return -EFAULT; - return 0; - - case RCKP_GET_CONFIG: - return get_config(info, (struct rocket_config *) arg); - case RCKP_SET_CONFIG: - return set_config(info, (struct rocket_config *) arg); - - case RCKP_GET_PORTS: - return get_ports(info, (struct rocket_ports *) arg); - default: - return -ENOIOCTLCMD; - } + case TIOCMGET: + return get_modem_info(info, (unsigned int *) arg); + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + return set_modem_info(info, cmd, (unsigned int *) arg); + case RCKP_GET_STRUCT: + if (copy_to_user((void *) arg, info, sizeof (struct r_port))) + return -EFAULT; + return 0; + case RCKP_GET_CONFIG: + return get_config(info, (struct rocket_config *) arg); + case RCKP_SET_CONFIG: + return set_config(info, (struct rocket_config *) arg); + case RCKP_GET_PORTS: + return get_ports(info, (struct rocket_ports *) arg); + case RCKP_RESET_RM2: + return reset_rm2(info, arg); + case RCKP_GET_VERSION: + return get_version(info, (struct rocket_version *) arg); + default: + return -ENOIOCTLCMD; + } return 0; } +#if (defined(ROCKET_DEBUG_FLOW) || defined(ROCKET_DEBUG_THROTTLE)) +static char *rp_tty_name(struct tty_struct *tty, char *buf) +{ + if (tty) + sprintf(buf, "%s%d", TTY_DRIVER_NAME(tty), MINOR(tty->device) - TTY_DRIVER_MINOR_START(tty) + TTY_DRIVER_NAME_BASE); + else + strcpy(buf, "NULL tty"); + return buf; +} +#endif + static void rp_send_xchar(struct tty_struct *tty, char ch) { - struct r_port *info = (struct r_port *)tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; CHANNEL_t *cp; - if (rocket_paranoia_check(info, tty->name, "rp_send_xchar")) + if (rocket_paranoia_check(info, "rp_send_xchar")) return; cp = &info->channel; - if (sGetTxCnt(cp)) + if (sGetTxCnt(cp)) sWriteTxPrioByte(cp, ch); else sWriteTxByte(sGetTxRxDataIO(cp), ch); } -static void rp_throttle(struct tty_struct * tty) +static void rp_throttle(struct tty_struct *tty) { - struct r_port *info = (struct r_port *)tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; CHANNEL_t *cp; #ifdef ROCKET_DEBUG_THROTTLE - char buf[64]; - - printk("throttle %s: %d....\n", tty->name, + char buf[64]; + + printk(KERN_INFO "throttle %s: %d....\n", rp_tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty)); #endif - if (rocket_paranoia_check(info, tty->name, "rp_throttle")) + if (rocket_paranoia_check(info, "rp_throttle")) return; cp = &info->channel; if (I_IXOFF(tty)) rp_send_xchar(tty, STOP_CHAR(tty)); - + sClrRTS(&info->channel); } -static void rp_unthrottle(struct tty_struct * tty) +static void rp_unthrottle(struct tty_struct *tty) { - struct r_port *info = (struct r_port *)tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; CHANNEL_t *cp; #ifdef ROCKET_DEBUG_THROTTLE - char buf[64]; - - printk("unthrottle %s: %d....\n", tty->name, + char buf[64]; + + printk(KERN_INFO "unthrottle %s: %d....\n", rp_tty_name(tty, buf), tty->ldisc.chars_in_buffer(tty)); #endif - if (rocket_paranoia_check(info, tty->name, "rp_throttle")) + if (rocket_paranoia_check(info, "rp_throttle")) return; cp = &info->channel; @@ -1386,15 +1688,15 @@ */ static void rp_stop(struct tty_struct *tty) { - struct r_port * info = (struct r_port *)tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; #ifdef ROCKET_DEBUG_FLOW - char buf[64]; - - printk("stop %s: %d %d....\n", tty->name, + char buf[64]; + + printk(KERN_INFO "stop %s: %d %d....\n", rp_tty_name(tty, buf), info->xmit_cnt, info->xmit_fifo_room); #endif - if (rocket_paranoia_check(info, tty->name, "rp_stop")) + if (rocket_paranoia_check(info, "rp_stop")) return; if (sGetTxCnt(&info->channel)) @@ -1403,19 +1705,20 @@ static void rp_start(struct tty_struct *tty) { - struct r_port * info = (struct r_port *)tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; #ifdef ROCKET_DEBUG_FLOW - char buf[64]; - - printk("start %s: %d %d....\n", tty->name, + char buf[64]; + + printk(KERN_INFO "start %s: %d %d....\n", rp_tty_name(tty, buf), info->xmit_cnt, info->xmit_fifo_room); #endif - if (rocket_paranoia_check(info, tty->name, "rp_stop")) + if (rocket_paranoia_check(info, "rp_stop")) return; sEnTransmit(&info->channel); - xmit_flags[info->line >> 5] |= (1 << (info->line & 0x1f)); + set_bit((info->aiop * 8) + info->chan, + (void *) &xmit_flags[info->board]); } /* @@ -1423,21 +1726,22 @@ */ static void rp_wait_until_sent(struct tty_struct *tty, int timeout) { - struct r_port *info = (struct r_port *)tty->driver_data; + struct r_port *info = (struct r_port *) tty->driver_data; CHANNEL_t *cp; unsigned long orig_jiffies; int check_time, exit_time; int txcnt; - - if (rocket_paranoia_check(info, tty->name, "rp_wait_until_sent")) + + if (rocket_paranoia_check(info, "rp_wait_until_sent")) return; cp = &info->channel; orig_jiffies = jiffies; #ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT - printk("In RP_wait_until_sent(%d) (jiff=%lu)...", timeout, jiffies); - printk("cps=%d...", info->cps); + printk(KERN_INFO "In RP_wait_until_sent(%d) (jiff=%lu)...", timeout, + jiffies); + printk(KERN_INFO "cps=%d...", info->cps); #endif while (1) { txcnt = sGetTxCnt(cp); @@ -1445,8 +1749,9 @@ if (sGetChanStatusLo(cp) & TXSHRMT) break; check_time = (HZ / info->cps) / 5; - } else + } else { check_time = HZ * txcnt / info->cps; + } if (timeout) { exit_time = orig_jiffies + timeout - jiffies; if (exit_time <= 0) @@ -1457,8 +1762,7 @@ if (check_time == 0) check_time = 1; #ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT - printk("txcnt = %d (jiff=%lu,check=%d)...", txcnt, - jiffies, check_time); + printk(KERN_INFO "txcnt = %d (jiff=%lu,check=%d)...", txcnt, jiffies, check_time); #endif current->state = TASK_INTERRUPTIBLE; schedule_timeout(check_time); @@ -1467,7 +1771,7 @@ } current->state = TASK_RUNNING; #ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT - printk("txcnt = %d (jiff=%lu)...done\n", txcnt, jiffies); + printk(KERN_INFO "txcnt = %d (jiff=%lu)...done\n", txcnt, jiffies); #endif } @@ -1476,182 +1780,195 @@ */ static void rp_hangup(struct tty_struct *tty) { - CHANNEL_t *cp; - struct r_port * info = (struct r_port *)tty->driver_data; - - if (rocket_paranoia_check(info, tty->name, "rp_hangup")) + CHANNEL_t *cp; + struct r_port *info = (struct r_port *) tty->driver_data; + + if (rocket_paranoia_check(info, "rp_hangup")) return; #if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_HANGUP)) - printk("rp_hangup of ttyR%d...", info->line); + printk(KERN_INFO "rp_hangup of ttyR%d...", info->line); #endif - /* - * If the port is in the process of being closed, just force - * the transmit buffer to be empty, and let rp_close handle - * the clean up. - */ - if (info->flags & ROCKET_CLOSING) { - cli(); - info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - sti(); - wake_up_interruptible(&tty->write_wait); + rp_flush_buffer(tty); + if (info->flags & ROCKET_CLOSING) return; - } if (info->count) { - rp_num_ports_open--; +#if ((LINUX_VERSION_CODE < VERSION_CODE(2,5,0)) && defined(MODULE)) + MOD_DEC_USE_COUNT; +#endif + atomic_dec(&rp_num_ports_open); } - - xmit_flags[info->line >> 5] &= ~(1 << (info->line & 0x1f)); + clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); + info->count = 0; - info->flags &= ~(ROCKET_NORMAL_ACTIVE|ROCKET_CALLOUT_ACTIVE); + info->flags &= ~ROCKET_NORMAL_ACTIVE; info->tty = 0; cp = &info->channel; sDisRxFIFO(cp); sDisTransmit(cp); - sDisInterrupts(cp, (TXINT_EN|MCINT_EN|RXINT_EN|SRCINT_EN|CHANINT_EN)); + sDisInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN)); sDisCTSFlowCtl(cp); sDisTxSoftFlowCtl(cp); sClrTxXOFF(cp); info->flags &= ~ROCKET_INITIALIZED; - + wake_up_interruptible(&info->open_wait); } /* - * The Rocketport write routines. The Rocketport driver uses a - * double-buffering strategy, with the twist that if the in-memory CPU - * buffer is empty, and there's space in the transmit FIFO, the - * writing routines will write directly to transmit FIFO. - * - * This gets a little tricky, but I'm pretty sure I got it all right. + * Exception handler - write char routine. The RocketPort driver uses a + * double-buffering strategy, with the twist that if the in-memory CPU + * buffer is empty, and there's space in the transmit FIFO, the + * writing routines will write directly to transmit FIFO. + * Write buffer and counters protected by spinlocks */ static void rp_put_char(struct tty_struct *tty, unsigned char ch) { - struct r_port * info = (struct r_port *)tty->driver_data; - CHANNEL_t *cp; + struct r_port *info = (struct r_port *) tty->driver_data; + CHANNEL_t *cp; + unsigned long flags; - if (rocket_paranoia_check(info, tty->name, "rp_put_char")) + if (rocket_paranoia_check(info, "rp_put_char")) return; + /* Grab the port write semaphore, locking out other processes that try to write to this port */ + down(&info->write_sem); + #ifdef ROCKET_DEBUG_WRITE - printk("rp_put_char %c...", ch); + printk(KERN_INFO "rp_put_char %c...", ch); #endif - + + spin_lock_irqsave(&info->slock, flags); cp = &info->channel; if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room == 0) info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp); - if (tty->stopped || tty->hw_stopped || - info->xmit_fifo_room == 0 || info->xmit_cnt != 0) { + if (tty->stopped || tty->hw_stopped || info->xmit_fifo_room == 0 || info->xmit_cnt != 0) { info->xmit_buf[info->xmit_head++] = ch; - info->xmit_head &= XMIT_BUF_SIZE-1; + info->xmit_head &= XMIT_BUF_SIZE - 1; info->xmit_cnt++; - xmit_flags[info->line >> 5] |= (1 << (info->line & 0x1f)); + set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); } else { sOutB(sGetTxRxDataIO(cp), ch); info->xmit_fifo_room--; } + spin_unlock_irqrestore(&info->slock, flags); + up(&info->write_sem); } -static int rp_write(struct tty_struct * tty, int from_user, +/* + * Exception handler - write routine, called when user app writes to the device. + * A per port write semaphore is used to protect from another process writing to + * this port at the same time. This other process could be running on the other CPU + * or get control of the CPU if the copy_from_user() blocks due to a page fault (swapped out). + * Spinlocks protect the info xmit members. + */ +static int rp_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count) { - struct r_port * info = (struct r_port *)tty->driver_data; - CHANNEL_t *cp; - const unsigned char *b; - int c, retval = 0; - unsigned long flags; + struct r_port *info = (struct r_port *) tty->driver_data; + CHANNEL_t *cp; + const unsigned char *b; + int c, retval = 0; + unsigned long flags; - if (count <= 0 || rocket_paranoia_check(info, tty->name, "rp_write")) + if (count <= 0 || rocket_paranoia_check(info, "rp_write")) return 0; + down_interruptible(&info->write_sem); + #ifdef ROCKET_DEBUG_WRITE - printk("rp_write %d chars...", count); + printk(KERN_INFO "rp_write %d chars...", count); #endif cp = &info->channel; - if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room == 0) + if (!tty->stopped && !tty->hw_stopped && info->xmit_fifo_room < count) info->xmit_fifo_room = TXFIFO_SIZE - sGetTxCnt(cp); - if (!tty->stopped && !tty->hw_stopped && info->xmit_cnt == 0 - && info->xmit_fifo_room >= 0) { + /* + * If the write queue for the port is empty, and there is FIFO space, stuff bytes + * into FIFO. Use the write queue for temp storage. + */ + if (!tty->stopped && !tty->hw_stopped && info->xmit_cnt == 0 && info->xmit_fifo_room > 0) { c = MIN(count, info->xmit_fifo_room); b = buf; if (from_user) { - down(&tmp_buf_sem); - c -= copy_from_user(tmp_buf, buf, c); - b = tmp_buf; - up(&tmp_buf_sem); - /* In case we got pre-empted */ - if (!c) { + if (copy_from_user(info->xmit_buf, buf, c)) { retval = -EFAULT; goto end; } if (info->tty == 0) goto end; + b = info->xmit_buf; c = MIN(c, info->xmit_fifo_room); } - sOutStrW(sGetTxRxDataIO(cp), b, c/2); + + /* Push data into FIFO, 2 bytes at a time */ + sOutStrW(sGetTxRxDataIO(cp), (unsigned short *) b, c / 2); + + /* If there is a byte remaining, write it */ if (c & 1) - sOutB(sGetTxRxDataIO(cp), b[c-1]); + sOutB(sGetTxRxDataIO(cp), b[c - 1]); + retval += c; buf += c; count -= c; + + spin_lock_irqsave(&info->slock, flags); info->xmit_fifo_room -= c; + spin_unlock_irqrestore(&info->slock, flags); } + + /* If count is zero, we wrote it all and are done */ if (!count) goto end; - - save_flags(flags); + + /* Write remaining data into the port's xmit_buf */ while (1) { - if (info->tty == 0) { - restore_flags(flags); + if (info->tty == 0) /* Seemingly obligatory check... */ goto end; - } - c = MIN(count, MIN(XMIT_BUF_SIZE - info->xmit_cnt - 1, - XMIT_BUF_SIZE - info->xmit_head)); + + c = MIN(count, MIN(XMIT_BUF_SIZE - info->xmit_cnt - 1, XMIT_BUF_SIZE - info->xmit_head)); if (c <= 0) break; b = buf; if (from_user) { - down(&tmp_buf_sem); - c -= copy_from_user(tmp_buf, buf, c); - b = tmp_buf; - up(&tmp_buf_sem); - if (!c) { - if (retval == 0) - retval = -EFAULT; + if (copy_from_user(info->xmit_buf + info->xmit_head, b, c)) { + retval = -EFAULT; goto end_intr; + } else { + memcpy(info->xmit_buf + info->xmit_head, b, c); } - /* In case we got pre-empted */ - if (info->tty == 0) - goto end_intr; } - cli(); - c = MIN(c, MIN(XMIT_BUF_SIZE - info->xmit_cnt - 1, - XMIT_BUF_SIZE - info->xmit_head)); - memcpy(info->xmit_buf + info->xmit_head, b, c); - info->xmit_head = (info->xmit_head + c) & (XMIT_BUF_SIZE-1); + + spin_lock_irqsave(&info->slock, flags); + info->xmit_head = + (info->xmit_head + c) & (XMIT_BUF_SIZE - 1); info->xmit_cnt += c; - restore_flags(flags); + spin_unlock_irqrestore(&info->slock, flags); + buf += c; count -= c; retval += c; } + end_intr: if ((retval > 0) && !tty->stopped && !tty->hw_stopped) - xmit_flags[info->line >> 5] |= (1 << (info->line & 0x1f)); - restore_flags(flags); + set_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]); + end: - if (info->xmit_cnt < WAKEUP_CHARS) { - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); + if (info->xmit_cnt < WAKEUP_CHARS) { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup) (tty); wake_up_interruptible(&tty->write_wait); +#ifdef ROCKETPORT_HAVE_POLL_WAIT + wake_up_interruptible(&tty->poll_wait); +#endif } + up(&info->write_sem); return retval; } @@ -1662,17 +1979,17 @@ */ static int rp_write_room(struct tty_struct *tty) { - struct r_port * info = (struct r_port *)tty->driver_data; - int ret; + struct r_port *info = (struct r_port *) tty->driver_data; + int ret; - if (rocket_paranoia_check(info, tty->name, "rp_write_room")) + if (rocket_paranoia_check(info, "rp_write_room")) return 0; ret = XMIT_BUF_SIZE - info->xmit_cnt - 1; if (ret < 0) ret = 0; #ifdef ROCKET_DEBUG_WRITE - printk("rp_write_room returns %d...", ret); + printk(KERN_INFO "rp_write_room returns %d...", ret); #endif return ret; } @@ -1683,332 +2000,656 @@ */ static int rp_chars_in_buffer(struct tty_struct *tty) { - struct r_port * info = (struct r_port *)tty->driver_data; - CHANNEL_t *cp; + struct r_port *info = (struct r_port *) tty->driver_data; + CHANNEL_t *cp; - if (rocket_paranoia_check(info, tty->name, "rp_chars_in_buffer")) + if (rocket_paranoia_check(info, "rp_chars_in_buffer")) return 0; cp = &info->channel; #ifdef ROCKET_DEBUG_WRITE - printk("rp_chars_in_buffer returns %d...", info->xmit_cnt); + printk(KERN_INFO "rp_chars_in_buffer returns %d...", info->xmit_cnt); #endif return info->xmit_cnt; } +/* + * Flushes the TX fifo for a port, deletes data in the xmit_buf stored in the + * r_port struct for the port. Note that spinlock are used to protect info members, + * do not call this function if the spinlock is already held. + */ static void rp_flush_buffer(struct tty_struct *tty) { - struct r_port * info = (struct r_port *)tty->driver_data; - CHANNEL_t *cp; + struct r_port *info = (struct r_port *) tty->driver_data; + CHANNEL_t *cp; + unsigned long flags; - if (rocket_paranoia_check(info, tty->name, "rp_flush_buffer")) + if (rocket_paranoia_check(info, "rp_flush_buffer")) return; - cli(); + spin_lock_irqsave(&info->slock, flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - sti(); + spin_unlock_irqrestore(&info->slock, flags); + wake_up_interruptible(&tty->write_wait); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); - +#ifdef ROCKETPORT_HAVE_POLL_WAIT + wake_up_interruptible(&tty->poll_wait); +#endif + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup) (tty); + cp = &info->channel; - sFlushTxFIFO(cp); } #ifdef CONFIG_PCI - -int __init register_PCI(int i, unsigned int bus, unsigned int device_fn) + +/* + * Called when a PCI card is found. Retrieves and stores model information, + * init's aiopic and serial port hardware. + * Inputs: i is the board number (0-n) + */ +__init int register_PCI(int i, struct pci_dev *dev) { - int num_aiops, aiop, max_num_aiops, num_chan, chan; - unsigned int aiopio[MAX_AIOPS_PER_BOARD]; - char *str; - CONTROLLER_t *ctlp; - struct pci_dev *dev = pci_find_slot(bus, device_fn); + int num_aiops, aiop, max_num_aiops, num_chan, chan; + unsigned int aiopio[MAX_AIOPS_PER_BOARD]; + char *str, *board_type; + CONTROLLER_t *ctlp; + + int fast_clock = 0; + int altChanRingIndicator = 0; + int ports_per_aiop = 8; + int ret; + unsigned int class_rev; + WordIO_t ConfigIO = 0; + ByteIO_t UPCIRingInd = 0; - if (!dev) + if (!dev || pci_enable_device(dev)) return 0; - if (pci_enable_device(dev)) + rcktpt_io_addr[i] = pci_resource_start(dev, 0); + ret = pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); + + if (ret) { + printk(KERN_INFO " Error during register_PCI(), unable to read config dword \n"); return 0; + } + + rcktpt_type[i] = ROCKET_TYPE_NORMAL; + rocketModel[i].loadrm2 = 0; + rocketModel[i].startingPortNumber = nextLineNumber; - rcktpt_io_addr[i] = pci_resource_start (dev, 0); - switch(dev->device) { + /* Depending on the model, set up some config variables */ + switch (dev->device) { case PCI_DEVICE_ID_RP4QUAD: str = "Quadcable"; max_num_aiops = 1; + ports_per_aiop = 4; + rocketModel[i].model = MODEL_RP4QUAD; + strcpy(rocketModel[i].modelString, "RocketPort 4 port w/quad cable"); + rocketModel[i].numPorts = 4; break; case PCI_DEVICE_ID_RP8OCTA: str = "Octacable"; max_num_aiops = 1; + rocketModel[i].model = MODEL_RP8OCTA; + strcpy(rocketModel[i].modelString, "RocketPort 8 port w/octa cable"); + rocketModel[i].numPorts = 8; + break; + case PCI_DEVICE_ID_URP8OCTA: + str = "Octacable"; + max_num_aiops = 1; + rocketModel[i].model = MODEL_UPCI_RP8OCTA; + strcpy(rocketModel[i].modelString, "RocketPort UPCI 8 port w/octa cable"); + rocketModel[i].numPorts = 8; break; case PCI_DEVICE_ID_RP8INTF: str = "8"; max_num_aiops = 1; + rocketModel[i].model = MODEL_RP8INTF; + strcpy(rocketModel[i].modelString, "RocketPort 8 port w/external I/F"); + rocketModel[i].numPorts = 8; + break; + case PCI_DEVICE_ID_URP8INTF: + str = "8"; + max_num_aiops = 1; + rocketModel[i].model = MODEL_UPCI_RP8INTF; + strcpy(rocketModel[i].modelString, "RocketPort UPCI 8 port w/external I/F"); + rocketModel[i].numPorts = 8; break; case PCI_DEVICE_ID_RP8J: str = "8J"; max_num_aiops = 1; + rocketModel[i].model = MODEL_RP8J; + strcpy(rocketModel[i].modelString, "RocketPort 8 port w/RJ11 connectors"); + rocketModel[i].numPorts = 8; + break; + case PCI_DEVICE_ID_RP4J: + str = "4J"; + max_num_aiops = 1; + ports_per_aiop = 4; + rocketModel[i].model = MODEL_RP4J; + strcpy(rocketModel[i].modelString, "RocketPort 4 port w/RJ45 connectors"); + rocketModel[i].numPorts = 4; + break; + case PCI_DEVICE_ID_RP8SNI: + str = "8 (DB78 Custom)"; + max_num_aiops = 1; + rocketModel[i].model = MODEL_RP8SNI; + strcpy(rocketModel[i].modelString, "RocketPort 8 port w/ custom DB78"); + rocketModel[i].numPorts = 8; + break; + case PCI_DEVICE_ID_RP16SNI: + str = "16 (DB78 Custom)"; + max_num_aiops = 2; + rocketModel[i].model = MODEL_RP16SNI; + strcpy(rocketModel[i].modelString, "RocketPort 16 port w/ custom DB78"); + rocketModel[i].numPorts = 16; break; case PCI_DEVICE_ID_RP16INTF: str = "16"; max_num_aiops = 2; + rocketModel[i].model = MODEL_RP16INTF; + strcpy(rocketModel[i].modelString, "RocketPort 16 port w/external I/F"); + rocketModel[i].numPorts = 16; + break; + case PCI_DEVICE_ID_URP16INTF: + str = "16"; + max_num_aiops = 2; + rocketModel[i].model = MODEL_UPCI_RP16INTF; + strcpy(rocketModel[i].modelString, "RocketPort UPCI 16 port w/external I/F"); + rocketModel[i].numPorts = 16; + break; + case PCI_DEVICE_ID_CRP16INTF: + str = "16"; + max_num_aiops = 2; + rocketModel[i].model = MODEL_CPCI_RP16INTF; + strcpy(rocketModel[i].modelString, "RocketPort Compact PCI 16 port w/external I/F"); + rocketModel[i].numPorts = 16; break; case PCI_DEVICE_ID_RP32INTF: str = "32"; max_num_aiops = 4; + rocketModel[i].model = MODEL_RP32INTF; + strcpy(rocketModel[i].modelString, "RocketPort 32 port w/external I/F"); + rocketModel[i].numPorts = 32; + break; + case PCI_DEVICE_ID_URP32INTF: + str = "32"; + max_num_aiops = 4; + rocketModel[i].model = MODEL_UPCI_RP32INTF; + strcpy(rocketModel[i].modelString, "RocketPort UPCI 32 port w/external I/F"); + rocketModel[i].numPorts = 32; break; case PCI_DEVICE_ID_RPP4: str = "Plus Quadcable"; max_num_aiops = 1; + ports_per_aiop = 4; + altChanRingIndicator++; + fast_clock++; + rocketModel[i].model = MODEL_RPP4; + strcpy(rocketModel[i].modelString, "RocketPort Plus 4 port"); + rocketModel[i].numPorts = 4; break; case PCI_DEVICE_ID_RPP8: str = "Plus Octacable"; + max_num_aiops = 2; + ports_per_aiop = 4; + altChanRingIndicator++; + fast_clock++; + rocketModel[i].model = MODEL_RPP8; + strcpy(rocketModel[i].modelString, "RocketPort Plus 8 port"); + rocketModel[i].numPorts = 8; + break; + case PCI_DEVICE_ID_RP2_232: + str = "Plus 2 (RS-232)"; + max_num_aiops = 1; + ports_per_aiop = 2; + altChanRingIndicator++; + fast_clock++; + rocketModel[i].model = MODEL_RP2_232; + strcpy(rocketModel[i].modelString, "RocketPort Plus 2 port RS232"); + rocketModel[i].numPorts = 2; + break; + case PCI_DEVICE_ID_RP2_422: + str = "Plus 2 (RS-422)"; max_num_aiops = 1; + ports_per_aiop = 2; + altChanRingIndicator++; + fast_clock++; + rocketModel[i].model = MODEL_RP2_422; + strcpy(rocketModel[i].modelString, "RocketPort Plus 2 port RS422"); + rocketModel[i].numPorts = 2; break; - case PCI_DEVICE_ID_RP8M: - str = "8-port Modem"; + case PCI_DEVICE_ID_RP6M: + max_num_aiops = 1; + ports_per_aiop = 6; + str = "6-port"; + + /* If class_rev is 1, the rocketmodem flash must be loaded. If it is 2 it is a "socketed" version. */ + if ((class_rev & 0xFF) == 1) { + rcktpt_type[i] = ROCKET_TYPE_MODEMII; + rocketModel[i].loadrm2 = 1; + } else { + rcktpt_type[i] = ROCKET_TYPE_MODEM; + } + + rocketModel[i].model = MODEL_RP6M; + strcpy(rocketModel[i].modelString, "RocketModem 6 port"); + rocketModel[i].numPorts = 6; break; - case 0x8: - str = "mysterious 8 port"; + case PCI_DEVICE_ID_RP4M: max_num_aiops = 1; + ports_per_aiop = 4; + str = "4-port"; + if ((class_rev & 0xFF) == 1) { + rcktpt_type[i] = ROCKET_TYPE_MODEMII; + rocketModel[i].loadrm2 = 1; + } else { + rcktpt_type[i] = ROCKET_TYPE_MODEM; + } + + rocketModel[i].model = MODEL_RP4M; + strcpy(rocketModel[i].modelString, "RocketModem 4 port"); + rocketModel[i].numPorts = 4; break; default: str = "(unknown/unsupported)"; max_num_aiops = 0; break; } - for(aiop=0;aiop < max_num_aiops;aiop++) + + /* + * Check for UPCI boards. + */ + + switch (dev->device) { + case PCI_DEVICE_ID_URP32INTF: + case PCI_DEVICE_ID_URP8INTF: + case PCI_DEVICE_ID_URP16INTF: + case PCI_DEVICE_ID_CRP16INTF: + case PCI_DEVICE_ID_URP8OCTA: + rcktpt_io_addr[i] = pci_resource_start(dev, 2); + ConfigIO = pci_resource_start(dev, 1); + if (dev->device == PCI_DEVICE_ID_URP8OCTA) { + UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND; + + /* + * Check for octa or quad cable. + */ + if (! + (sInW(ConfigIO + _PCI_9030_GPIO_CTRL) & + PCI_GPIO_CTRL_8PORT)) { + str = "Quadcable"; + ports_per_aiop = 4; + rocketModel[i].numPorts = 4; + } + } + break; + case PCI_DEVICE_ID_UPCI_RM3_8PORT: + str = "8 ports"; + max_num_aiops = 1; + rocketModel[i].model = MODEL_UPCI_RM3_8PORT; + strcpy(rocketModel[i].modelString, "RocketModem III 8 port"); + rocketModel[i].numPorts = 8; + rcktpt_io_addr[i] = pci_resource_start(dev, 2); + UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND; + ConfigIO = pci_resource_start(dev, 1); + rcktpt_type[i] = ROCKET_TYPE_MODEMIII; + break; + case PCI_DEVICE_ID_UPCI_RM3_4PORT: + str = "4 ports"; + max_num_aiops = 1; + rocketModel[i].model = MODEL_UPCI_RM3_4PORT; + strcpy(rocketModel[i].modelString, "RocketModem III 4 port"); + rocketModel[i].numPorts = 4; + rcktpt_io_addr[i] = pci_resource_start(dev, 2); + UPCIRingInd = rcktpt_io_addr[i] + _PCI_9030_RING_IND; + ConfigIO = pci_resource_start(dev, 1); + rcktpt_type[i] = ROCKET_TYPE_MODEMIII; + break; + default: + break; + } + + switch (rcktpt_type[i]) { + case ROCKET_TYPE_MODEM: + board_type = "RocketModem"; + break; + case ROCKET_TYPE_MODEMII: + board_type = "RocketModem II"; + break; + case ROCKET_TYPE_MODEMIII: + board_type = "RocketModem III"; + break; + default: + board_type = "RocketPort"; + break; + } + + if (fast_clock) { + sClockPrescale = 0x12; /* mod 2 (divide by 3) */ + rp_baud_base[i] = 921600; + } else { + /* + * If support_low_speed is set, use the slow clock + * prescale, which supports 50 bps + */ + if (support_low_speed) { + /* mod 9 (divide by 10) prescale */ + sClockPrescale = 0x19; + rp_baud_base[i] = 230400; + } else { + /* mod 4 (devide by 5) prescale */ + sClockPrescale = 0x14; + rp_baud_base[i] = 460800; + } + } + + for (aiop = 0; aiop < max_num_aiops; aiop++) aiopio[aiop] = rcktpt_io_addr[i] + (aiop * 0x40); ctlp = sCtlNumToCtlPtr(i); - num_aiops = sPCIInitController(ctlp, i, - aiopio, max_num_aiops, 0, - FREQ_DIS, 0); - printk("Rocketport controller #%d found at %02x:%02x, " - "%d AIOP(s) (PCI Rocketport %s)\n", i, bus, device_fn, - num_aiops, str); - if(num_aiops <= 0) { + num_aiops = sPCIInitController(ctlp, i, aiopio, max_num_aiops, ConfigIO, 0, FREQ_DIS, 0, altChanRingIndicator, UPCIRingInd); + for (aiop = 0; aiop < max_num_aiops; aiop++) + ctlp->AiopNumChan[aiop] = ports_per_aiop; + +#if LINUX_VERSION_CODE < VERSION_CODE(2,3,99) + printk(KERN_INFO "Comtrol PCI controller #%d ID 0x%x found at 0x%lx, " + "%d AIOP(s) (%s)\n", i, dev->device, rcktpt_io_addr[i], + num_aiops, rocketModel[i].modelString); +#else + printk + ("Comtrol PCI controller #%d ID 0x%x found in bus:slot:fn %s at address %04lx, " + "%d AIOP(s) (%s)\n", i, dev->device, dev->slot_name, + rcktpt_io_addr[i], num_aiops, rocketModel[i].modelString); +#endif + + printk(KERN_INFO "Installing %s, creating /dev/ttyR%d - %ld\n", + rocketModel[i].modelString, + rocketModel[i].startingPortNumber, + rocketModel[i].startingPortNumber + + rocketModel[i].numPorts - 1); + + if (num_aiops <= 0) { rcktpt_io_addr[i] = 0; - return(0); + return (0); } - for(aiop = 0;aiop < num_aiops; aiop++) { + is_PCI[i] = 1; + + /* Reset the AIOPIC, init the serial ports */ + for (aiop = 0; aiop < num_aiops; aiop++) { sResetAiopByNum(ctlp, aiop); - sEnAiop(ctlp, aiop); - num_chan = sGetAiopNumChan(ctlp, aiop); - for(chan=0;chan < num_chan; chan++) - init_r_port(i, aiop, chan); + num_chan = ports_per_aiop; + for (chan = 0; chan < num_chan; chan++) + init_r_port(i, aiop, chan, dev); + } + + /* Rocket modems must be reset */ + if ((rcktpt_type[i] == ROCKET_TYPE_MODEM) || + (rcktpt_type[i] == ROCKET_TYPE_MODEMII) || + (rcktpt_type[i] == ROCKET_TYPE_MODEMIII)) { + num_chan = ports_per_aiop; + for (chan = 0; chan < num_chan; chan++) + sPCIModemReset(ctlp, chan, 1); + mdelay(500); + for (chan = 0; chan < num_chan; chan++) + sPCIModemReset(ctlp, chan, 0); + mdelay(500); + rmSpeakerReset(ctlp, rocketModel[i].model); } - return(1); + return (1); } +#if LINUX_VERSION_CODE > VERSION_CODE(2,3,99) /* Linux version 2.4 and greater */ + + +/* + * Probes for PCI cards, inits them if found + * Input: board_found = number of ISA boards already found, or the + * starting board number + * Returns: Number of PCI boards found + */ static int __init init_PCI(int boards_found) { - unsigned char bus, device_fn; - int i, count = 0; + struct pci_dev *dev = NULL; + int count = 0; - for(i=0; i < (NUM_BOARDS - boards_found); i++) { - if (!pcibios_find_device(PCI_VENDOR_ID_RP, - PCI_DEVICE_ID_RP4QUAD, i, &bus, &device_fn)) - if (register_PCI(count+boards_found, bus, device_fn)) - count++; - if (!pcibios_find_device(PCI_VENDOR_ID_RP, - PCI_DEVICE_ID_RP8J, i, &bus, &device_fn)) - if (register_PCI(count+boards_found, bus, device_fn)) - count++; - if(!pcibios_find_device(PCI_VENDOR_ID_RP, - PCI_DEVICE_ID_RP8OCTA, i, &bus, &device_fn)) - if(register_PCI(count+boards_found, bus, device_fn)) - count++; - if(!pcibios_find_device(PCI_VENDOR_ID_RP, - PCI_DEVICE_ID_RP8INTF, i, &bus, &device_fn)) - if(register_PCI(count+boards_found, bus, device_fn)) - count++; - if(!pcibios_find_device(PCI_VENDOR_ID_RP, - PCI_DEVICE_ID_RP16INTF, i, &bus, &device_fn)) - if(register_PCI(count+boards_found, bus, device_fn)) - count++; - if(!pcibios_find_device(PCI_VENDOR_ID_RP, - PCI_DEVICE_ID_RP32INTF, i, &bus, &device_fn)) - if(register_PCI(count+boards_found, bus, device_fn)) - count++; - if(!pcibios_find_device(PCI_VENDOR_ID_RP, - PCI_DEVICE_ID_RP4QUAD, i, &bus, &device_fn)) - if(register_PCI(count+boards_found, bus, device_fn)) - count++; - if(!pcibios_find_device(PCI_VENDOR_ID_RP, - PCI_DEVICE_ID_RP8J, i, &bus, &device_fn)) - if(register_PCI(count+boards_found, bus, device_fn)) - count++; - if(!pcibios_find_device(PCI_VENDOR_ID_RP, - PCI_DEVICE_ID_RPP4, i, &bus, &device_fn)) - if(register_PCI(count+boards_found, bus, device_fn)) - count++; - if(!pcibios_find_device(PCI_VENDOR_ID_RP, - PCI_DEVICE_ID_RPP8, i, &bus, &device_fn)) - if(register_PCI(count+boards_found, bus, device_fn)) - count++; - if(!pcibios_find_device(PCI_VENDOR_ID_RP, - PCI_DEVICE_ID_RP8M, i, &bus, &device_fn)) - if(register_PCI(count+boards_found, bus, device_fn)) - count++; - if(!pcibios_find_device(PCI_VENDOR_ID_RP, - 0x8, i, &bus, &device_fn)) - if(register_PCI(count+boards_found, bus, device_fn)) - count++; + /* Work through the PCI device list, pulling out ours */ + while ((dev = pci_find_device(PCI_VENDOR_ID_RP, PCI_ANY_ID, dev))) { + if (register_PCI(count + boards_found, dev)) + count++; } - return(count); + return (count); } -#endif +#else /* Linux version 2.2 */ + +/* + * Linux 2.2 pci_find_device() does not allow a search of all devices for a certain vendor, + * you have to try each device ID. Comtrol device ID's are 0x0000 -0x000F for the original + * boards. Newer board are 0x08xx (see upci_ids[]). + */ +static int __init init_PCI(int boards_found) +{ + int j, count = 0; + struct pci_dev *dev = NULL; + + static int upci_ids[] = { + PCI_DEVICE_ID_URP32INTF, + PCI_DEVICE_ID_URP8INTF, + PCI_DEVICE_ID_URP16INTF, + PCI_DEVICE_ID_CRP16INTF, + PCI_DEVICE_ID_URP8OCTA, + PCI_DEVICE_ID_UPCI_RM3_8PORT, + PCI_DEVICE_ID_UPCI_RM3_4PORT + }; + +#define NUM_UPCI_IDS (sizeof(upci_ids) / sizeof(upci_ids[0])) + + /* Try finding devices with PCI ID's 0x0000 - 0x000F */ + for (j = 0; j < 16; j++) { + while ((dev = pci_find_device(PCI_VENDOR_ID_RP, j, dev))) { + register_PCI(count + boards_found, dev); + count++; + } + } + + /* Now try finding the UPCI devices, which have PCI ID's 0x0800 - 0x080F */ + for (j = 0; j < NUM_UPCI_IDS; j++) { + while ((dev = + pci_find_device(PCI_VENDOR_ID_RP, upci_ids[j], dev))) { + register_PCI(count + boards_found, dev); + count++; + } + } + return (count); +} + +#endif /* Linux version 2.2/2.4 */ + +#endif /* CONFIG_PCI */ + +/* + * Probes for ISA cards + * Input: i = the board number to look for + * Returns: 1 if board found, 0 else + */ static int __init init_ISA(int i, int *reserved_controller) { - int num_aiops, num_chan; - int aiop, chan; - int extent = 0; - unsigned int aiopio[MAX_AIOPS_PER_BOARD]; - CONTROLLER_t *ctlp; + int num_aiops, num_chan = 0, total_num_chan = 0; + int aiop, chan; + unsigned int aiopio[MAX_AIOPS_PER_BOARD]; + CONTROLLER_t *ctlp; + char *type_string; - if (rcktpt_io_addr[i] == 0) - return(0); + if (rcktpt_io_addr[i] == 0 || controller == 0) + return (0); + if (check_region(rcktpt_io_addr[i], 64)) { + printk(KERN_INFO "RocketPort board address 0x%lx in use...\n", rcktpt_io_addr[i]); + rcktpt_io_addr[i] = 0; + return (0); + } if (rcktpt_io_addr[i] + 0x40 == controller) { *reserved_controller = 1; - extent = 68; + request_region(rcktpt_io_addr[i], 68, "Comtrol RocketPort"); } else { - extent = 64; + request_region(rcktpt_io_addr[i], 64, "Comtrol RocketPort"); } - if (!request_region(rcktpt_io_addr[i], extent, - "Comtrol Rocketport")) { - printk("RocketPort board address 0x%lx in use...\n", - rcktpt_io_addr[i]); - rcktpt_io_addr[i] = 0; - return(0); + + ctlp = sCtlNumToCtlPtr(i); + + ctlp->boardType = rcktpt_type[i]; + + switch (rcktpt_type[i]) { + case ROCKET_TYPE_PC104: + type_string = "(PC104)"; + break; + case ROCKET_TYPE_MODEM: + type_string = "(RocketModem)"; + break; + case ROCKET_TYPE_MODEMII: + type_string = "(RocketModem II)"; + break; + default: + type_string = ""; + break; } - - for (aiop=0; aiop<MAX_AIOPS_PER_BOARD; aiop++) - aiopio[aiop]= rcktpt_io_addr[i] + (aiop * 0x400); - ctlp= sCtlNumToCtlPtr(i); - num_aiops = sInitController(ctlp, i, controller + (i*0x400), - aiopio, MAX_AIOPS_PER_BOARD, 0, - FREQ_DIS, 0); + + /* + * If support_low_speed is set, use the slow clock prescale, + * which supports 50 bps + */ + if (support_low_speed) { + sClockPrescale = 0x19; /* mod 9 (divide by 10) prescale */ + rp_baud_base[i] = 230400; + } else { + sClockPrescale = 0x14; /* mod 4 (devide by 5) prescale */ + rp_baud_base[i] = 460800; + } + + for (aiop = 0; aiop < MAX_AIOPS_PER_BOARD; aiop++) + aiopio[aiop] = rcktpt_io_addr[i] + (aiop * 0x400); + + num_aiops = + sInitController(ctlp, i, controller + (i * 0x400), aiopio, MAX_AIOPS_PER_BOARD, 0, FREQ_DIS, 0); + + if (ctlp->boardType == ROCKET_TYPE_PC104) { + sEnAiop(ctlp, 2); /* only one AIOPIC, but these */ + sEnAiop(ctlp, 3); /* CSels used for other stuff */ + } + if (num_aiops <= 0) { - release_region(rcktpt_io_addr[i], extent); + if (rcktpt_io_addr[i] + 0x40 == controller) { + *reserved_controller = 0; + release_region(rcktpt_io_addr[i], 68); + } else { + release_region(rcktpt_io_addr[i], 64); + } rcktpt_io_addr[i] = 0; - return(0); + return (0); } for (aiop = 0; aiop < num_aiops; aiop++) { sResetAiopByNum(ctlp, aiop); sEnAiop(ctlp, aiop); - num_chan = sGetAiopNumChan(ctlp,aiop); - for (chan=0; chan < num_chan; chan++) - init_r_port(i, aiop, chan); - } - printk("Rocketport controller #%d found at 0x%lx, " - "%d AIOPs\n", i, rcktpt_io_addr[i], - num_aiops); - return(1); -} + num_chan = sGetAiopNumChan(ctlp, aiop); + total_num_chan += num_chan; + for (chan = 0; chan < num_chan; chan++) + init_r_port(i, aiop, chan, NULL); + } + is_PCI[i] = 0; + if ((rcktpt_type[i] == ROCKET_TYPE_MODEM) || (rcktpt_type[i] == ROCKET_TYPE_MODEMII)) { + num_chan = sGetAiopNumChan(ctlp, 0); + total_num_chan = num_chan; + for (chan = 0; chan < num_chan; chan++) + sModemReset(ctlp, chan, 1); + mdelay(500); + for (chan = 0; chan < num_chan; chan++) + sModemReset(ctlp, chan, 0); + mdelay(500); + strcpy(rocketModel[i].modelString, "RocketModem ISA"); + } else { + strcpy(rocketModel[i].modelString, "RocketPort ISA"); + } + rocketModel[i].numPorts = total_num_chan; + rocketModel[i].model = MODEL_ISA; + + printk(KERN_INFO "Comtrol ISA controller #%d found at 0x%lx, " + "%d AIOPs %s\n", i, rcktpt_io_addr[i], num_aiops, + type_string); + printk(KERN_INFO "Installing %s, creating /dev/ttyR%d - %ld\n", + rocketModel[i].modelString, + rocketModel[i].startingPortNumber, + rocketModel[i].startingPortNumber + + rocketModel[i].numPorts - 1); + return (1); +} /* * The module "startup" routine; it's run when the module is loaded. */ int __init rp_init(void) { - int i, retval, pci_boards_found, isa_boards_found; - int reserved_controller = 0; + int retval, pci_boards_found, isa_boards_found, i; + int reserved_controller = 0; - printk("Rocketport device driver module, version %s, %s\n", + printk(KERN_INFO "RocketPort device driver module, version %s, %s\n", ROCKET_VERSION, ROCKET_DATE); /* - * Set up the timer channel. If it is already in use by - * some other driver, give up. + * Set up the timer channel. */ - if (rocket_timer.function) { - printk("rocket.o: Timer already in use!\n"); - return -EBUSY; - } init_timer(&rocket_timer); rocket_timer.function = rp_do_poll; - + /* * Initialize the array of pointers to our own internal state * structures. */ - memset(rp_table, 0, sizeof(rp_table)); - memset(xmit_flags, 0, sizeof(xmit_flags)); + memset(rp_table, 0, sizeof (rp_table)); + memset(xmit_flags, 0, sizeof (xmit_flags)); + + for (i = 0; i < MAX_RP_PORTS; i++) + lineNumbers[i] = 0; + nextLineNumber = 0; + memset(rocketModel, 0, sizeof (rocketModel)); - if (board1 == 0) - board1 = 0x180; - if (controller == 0) + if (board1 && controller == 0) controller = board1 + 0x40; - if (check_region(controller, 4)) { - printk("Controller IO addresses in use, unloading driver.\n"); + if (controller && check_region(controller, 4)) { + printk(KERN_INFO "Controller IO addresses in use, unloading driver.\n"); return -EBUSY; } - + + /* Store ISA variable retrieved from command line or .conf file. */ rcktpt_io_addr[0] = board1; rcktpt_io_addr[1] = board2; rcktpt_io_addr[2] = board3; rcktpt_io_addr[3] = board4; - /* - * If support_low_speed is set, use the slow clock prescale, - * which supports 50 bps - */ - if (support_low_speed) { - sClockPrescale = 0x19; /* mod 9 (divide by 10) prescale */ - rp_baud_base = 230400; - } else { - sClockPrescale = 0x14; /* mod 4 (devide by 5) prescale */ - rp_baud_base = 460800; - } - - /* - * OK, let's probe each of the controllers looking for boards. - */ - isa_boards_found = 0; - pci_boards_found = 0; - for (i=0; i < NUM_BOARDS; i++) { - if(init_ISA(i, &reserved_controller)) - isa_boards_found++; - } -#ifdef CONFIG_PCI - if (pci_present()) { - if(isa_boards_found < NUM_BOARDS) - pci_boards_found = init_PCI(isa_boards_found); - } else { - printk("No PCI BIOS found\n"); - } -#endif - max_board = pci_boards_found + isa_boards_found; - - if (max_board == 0) { - printk("No rocketport ports found; unloading driver.\n"); - rocket_timer.function = 0; - return -ENODEV; - } - - if (reserved_controller == 0) - request_region(controller, 4, "Comtrol Rocketport"); + rcktpt_type[0] = modem1 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL; + rcktpt_type[0] = pc104_1[0] ? ROCKET_TYPE_PC104 : rcktpt_type[0]; + rcktpt_type[1] = modem2 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL; + rcktpt_type[1] = pc104_2[0] ? ROCKET_TYPE_PC104 : rcktpt_type[1]; + rcktpt_type[2] = modem3 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL; + rcktpt_type[2] = pc104_3[0] ? ROCKET_TYPE_PC104 : rcktpt_type[2]; + rcktpt_type[3] = modem4 ? ROCKET_TYPE_MODEM : ROCKET_TYPE_NORMAL; + rcktpt_type[3] = pc104_4[0] ? ROCKET_TYPE_PC104 : rcktpt_type[3]; /* * Set up the tty driver structure and then register this * driver with the tty layer. */ - memset(&rocket_driver, 0, sizeof(struct tty_driver)); + memset(&rocket_driver, 0, sizeof (struct tty_driver)); rocket_driver.magic = TTY_DRIVER_MAGIC; - rocket_driver.owner = THIS_MODULE; -#ifdef CONFIG_DEVFS_FS - rocket_driver.name = "tts/R"; -#else + rocket_driver.flags = TTY_DRIVER_NO_DEVFS; + rocket_driver.devfs_name = "tts/R"; rocket_driver.name = "ttyR"; -#endif + rocket_driver.driver_name = "Comtrol RocketPort"; rocket_driver.major = TTY_ROCKET_MAJOR; rocket_driver.minor_start = 0; rocket_driver.num = MAX_RP_PORTS; @@ -2016,8 +2657,10 @@ rocket_driver.subtype = SERIAL_TYPE_NORMAL; rocket_driver.init_termios = tty_std_termios; rocket_driver.init_termios.c_cflag = - B9600 | CS8 | CREAD | HUPCL | CLOCAL; - rocket_driver.flags = TTY_DRIVER_REAL_RAW; + B9600 | CS8 | CREAD | HUPCL | CLOCAL; +#ifdef ROCKET_SOFT_FLOW + rocket_driver.flags |= TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; +#endif rocket_driver.refcount = &rocket_refcount; rocket_driver.table = rocket_table; rocket_driver.termios = rocket_termios; @@ -2041,85 +2684,93 @@ rocket_driver.send_xchar = rp_send_xchar; rocket_driver.wait_until_sent = rp_wait_until_sent; - /* - * The callout device is just like normal device except for - * the minor number and the subtype code. - */ - callout_driver = rocket_driver; -#ifdef CONFIG_DEVFS_FS - callout_driver.name = "cua/R"; -#else - callout_driver.name = "cur"; -#endif - callout_driver.major = CUA_ROCKET_MAJOR; - callout_driver.minor_start = 0; - callout_driver.subtype = SERIAL_TYPE_CALLOUT; - - retval = tty_register_driver(&callout_driver); - if (retval < 0) { - printk("Couldn't install Rocketport callout driver " - "(error %d)\n", -retval); - release_region(controller, 4); - return -1; - } +#if (LINUX_VERSION_CODE > VERSION_CODE(2,5,0)) + rocket_driver.owner = THIS_MODULE; + rocket_driver.tiocmget = rp_tiocmget; + rocket_driver.tiocmset = rp_tiocmset; +#endif /* Kernel > 2.5 */ retval = tty_register_driver(&rocket_driver); if (retval < 0) { - printk("Couldn't install tty Rocketport driver " - "(error %d)\n", -retval); - release_region(controller, 4); + printk(KERN_INFO "Couldn't install tty RocketPort driver (error %d)\n", -retval); return -1; } + #ifdef ROCKET_DEBUG_OPEN - printk("Rocketport driver is major %d, callout is %d\n", - rocket_driver.major, callout_driver.major); + printk(KERN_INFO "RocketPort driver is major %d\n", rocket_driver.major); #endif + /* + * OK, let's probe each of the controllers looking for boards. Any boards found + * will be initialized here. + */ + isa_boards_found = 0; + pci_boards_found = 0; + + for (i = 0; i < NUM_BOARDS; i++) { + if (init_ISA(i, &reserved_controller)) + isa_boards_found++; + } + +#ifdef CONFIG_PCI + if (pci_present()) { + if (isa_boards_found < NUM_BOARDS) + pci_boards_found = init_PCI(isa_boards_found); + } else { + printk(KERN_INFO "No PCI BIOS found\n"); + } +#endif + + max_board = pci_boards_found + isa_boards_found; + + if (max_board == 0) { + printk(KERN_INFO "No rocketport ports found; unloading driver.\n"); + del_timer_sync(&rocket_timer); + return -ENXIO; + } + + if (isa_boards_found) { + if (reserved_controller == 0) + request_region(controller, 4, "Comtrol RocketPort"); + } else { + controller = 0; + } + return 0; } #ifdef MODULE -int init_module(void) -{ - return rp_init(); -} -void -cleanup_module( void) { - int retval; - int i; - int released_controller = 0; +static void rp_cleanup_module(void) +{ + int retval; + int i; + int released_controller = 0; del_timer_sync(&rocket_timer); - retval = tty_unregister_driver(&callout_driver); - if (retval) { - printk("Error %d while trying to unregister " - "rocketport callout driver\n", -retval); - } retval = tty_unregister_driver(&rocket_driver); - if (retval) { - printk("Error %d while trying to unregister " + if (retval) + printk(KERN_INFO "Error %d while trying to unregister " "rocketport driver\n", -retval); - } + for (i = 0; i < MAX_RP_PORTS; i++) { if (rp_table[i]) kfree(rp_table[i]); } - for (i=0; i < NUM_BOARDS; i++) { - if (rcktpt_io_addr[i] <= 0) + + for (i = 0; i < NUM_BOARDS; i++) { + if (rcktpt_io_addr[i] <= 0 || is_PCI[i]) continue; if (rcktpt_io_addr[i] + 0x40 == controller) { released_controller++; release_region(rcktpt_io_addr[i], 68); - } else + } else { release_region(rcktpt_io_addr[i], 64); - if (released_controller == 0) - release_region(controller, 4); + } } - if (tmp_buf) - free_page((unsigned long) tmp_buf); - rocket_timer.function = 0; + if (controller && released_controller == 0) + release_region(controller, 4); } #endif @@ -2155,69 +2806,60 @@ #define FALSE 0 #endif -static Byte_t RData[RDATASIZE] = -{ - 0x00, 0x09, 0xf6, 0x82, - 0x02, 0x09, 0x86, 0xfb, - 0x04, 0x09, 0x00, 0x0a, - 0x06, 0x09, 0x01, 0x0a, - 0x08, 0x09, 0x8a, 0x13, - 0x0a, 0x09, 0xc5, 0x11, - 0x0c, 0x09, 0x86, 0x85, - 0x0e, 0x09, 0x20, 0x0a, - 0x10, 0x09, 0x21, 0x0a, - 0x12, 0x09, 0x41, 0xff, - 0x14, 0x09, 0x82, 0x00, - 0x16, 0x09, 0x82, 0x7b, - 0x18, 0x09, 0x8a, 0x7d, - 0x1a, 0x09, 0x88, 0x81, - 0x1c, 0x09, 0x86, 0x7a, - 0x1e, 0x09, 0x84, 0x81, - 0x20, 0x09, 0x82, 0x7c, - 0x22, 0x09, 0x0a, 0x0a -}; - -static Byte_t RRegData[RREGDATASIZE]= -{ - 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */ - 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */ - 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */ - 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */ - 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */ - 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */ - 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */ - 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */ - 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */ - 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */ - 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */ - 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */ - 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */ +static Byte_t RData[RDATASIZE] = { + 0x00, 0x09, 0xf6, 0x82, + 0x02, 0x09, 0x86, 0xfb, + 0x04, 0x09, 0x00, 0x0a, + 0x06, 0x09, 0x01, 0x0a, + 0x08, 0x09, 0x8a, 0x13, + 0x0a, 0x09, 0xc5, 0x11, + 0x0c, 0x09, 0x86, 0x85, + 0x0e, 0x09, 0x20, 0x0a, + 0x10, 0x09, 0x21, 0x0a, + 0x12, 0x09, 0x41, 0xff, + 0x14, 0x09, 0x82, 0x00, + 0x16, 0x09, 0x82, 0x7b, + 0x18, 0x09, 0x8a, 0x7d, + 0x1a, 0x09, 0x88, 0x81, + 0x1c, 0x09, 0x86, 0x7a, + 0x1e, 0x09, 0x84, 0x81, + 0x20, 0x09, 0x82, 0x7c, + 0x22, 0x09, 0x0a, 0x0a }; -CONTROLLER_T sController[CTL_SIZE] = -{ - {-1,-1,0,0,0,0,0,0,0,0,0,{0,0,0,0},{0,0,0,0},{-1,-1,-1,-1},{0,0,0,0}}, - {-1,-1,0,0,0,0,0,0,0,0,0,{0,0,0,0},{0,0,0,0},{-1,-1,-1,-1},{0,0,0,0}}, - {-1,-1,0,0,0,0,0,0,0,0,0,{0,0,0,0},{0,0,0,0},{-1,-1,-1,-1},{0,0,0,0}}, - {-1,-1,0,0,0,0,0,0,0,0,0,{0,0,0,0},{0,0,0,0},{-1,-1,-1,-1},{0,0,0,0}} +static Byte_t RRegData[RREGDATASIZE] = { + 0x00, 0x09, 0xf6, 0x82, /* 00: Stop Rx processor */ + 0x08, 0x09, 0x8a, 0x13, /* 04: Tx software flow control */ + 0x0a, 0x09, 0xc5, 0x11, /* 08: XON char */ + 0x0c, 0x09, 0x86, 0x85, /* 0c: XANY */ + 0x12, 0x09, 0x41, 0xff, /* 10: Rx mask char */ + 0x14, 0x09, 0x82, 0x00, /* 14: Compare/Ignore #0 */ + 0x16, 0x09, 0x82, 0x7b, /* 18: Compare #1 */ + 0x18, 0x09, 0x8a, 0x7d, /* 1c: Compare #2 */ + 0x1a, 0x09, 0x88, 0x81, /* 20: Interrupt #1 */ + 0x1c, 0x09, 0x86, 0x7a, /* 24: Ignore/Replace #1 */ + 0x1e, 0x09, 0x84, 0x81, /* 28: Interrupt #2 */ + 0x20, 0x09, 0x82, 0x7c, /* 2c: Ignore/Replace #2 */ + 0x22, 0x09, 0x0a, 0x0a /* 30: Rx FIFO Enable */ }; -#if 0 -/* IRQ number to MUDBAC register 2 mapping */ -Byte_t sIRQMap[16] = -{ - 0,0,0,0x10,0x20,0x30,0,0,0,0x40,0x50,0x60,0x70,0,0,0x80 +CONTROLLER_T sController[CTL_SIZE] = { + {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, + {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, + {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, + {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, + {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, + {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}}, + {-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, {0, 0, 0, 0}, + {0, 0, 0, 0}, {-1, -1, -1, -1}, {0, 0, 0, 0}} }; -#endif -Byte_t sBitMapClrTbl[8] = -{ - 0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f +Byte_t sBitMapClrTbl[8] = { + 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f }; -Byte_t sBitMapSetTbl[8] = -{ - 0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80 +Byte_t sBitMapSetTbl[8] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; int sClockPrescale = 0x14; @@ -2292,76 +2934,68 @@ After this function all AIOPs on the controller are disabled, they can be enabled with sEnAiop(). */ -int sInitController( CONTROLLER_T *CtlP, - int CtlNum, - ByteIO_t MudbacIO, - ByteIO_t *AiopIOList, - int AiopIOListSize, - int IRQNum, - Byte_t Frequency, - int PeriodicOnly) -{ - int i; - ByteIO_t io; - - CtlP->CtlNum = CtlNum; - CtlP->CtlID = CTLID_0001; /* controller release 1 */ - CtlP->BusType = isISA; - CtlP->MBaseIO = MudbacIO; - CtlP->MReg1IO = MudbacIO + 1; - CtlP->MReg2IO = MudbacIO + 2; - CtlP->MReg3IO = MudbacIO + 3; +int sInitController(CONTROLLER_T * CtlP, int CtlNum, ByteIO_t MudbacIO, + ByteIO_t * AiopIOList, int AiopIOListSize, int IRQNum, + Byte_t Frequency, int PeriodicOnly) +{ + int i; + ByteIO_t io; + int done; + + CtlP->AiopIntrBits = aiop_intr_bits; + CtlP->AltChanRingIndicator = 0; + CtlP->CtlNum = CtlNum; + CtlP->CtlID = CTLID_0001; /* controller release 1 */ + CtlP->BusType = isISA; + CtlP->MBaseIO = MudbacIO; + CtlP->MReg1IO = MudbacIO + 1; + CtlP->MReg2IO = MudbacIO + 2; + CtlP->MReg3IO = MudbacIO + 3; #if 1 - CtlP->MReg2 = 0; /* interrupt disable */ - CtlP->MReg3 = 0; /* no periodic interrupts */ + CtlP->MReg2 = 0; /* interrupt disable */ + CtlP->MReg3 = 0; /* no periodic interrupts */ #else - if(sIRQMap[IRQNum] == 0) /* interrupts globally disabled */ - { - CtlP->MReg2 = 0; /* interrupt disable */ - CtlP->MReg3 = 0; /* no periodic interrupts */ - } - else - { - CtlP->MReg2 = sIRQMap[IRQNum]; /* set IRQ number */ - CtlP->MReg3 = Frequency; /* set frequency */ - if(PeriodicOnly) /* periodic interrupt only */ - { - CtlP->MReg3 |= PERIODIC_ONLY; - } - } -#endif - sOutB(CtlP->MReg2IO,CtlP->MReg2); - sOutB(CtlP->MReg3IO,CtlP->MReg3); - sControllerEOI(CtlP); /* clear EOI if warm init */ - /* Init AIOPs */ - CtlP->NumAiop = 0; - for(i=0; i < AiopIOListSize; i++) - { - io = AiopIOList[i]; - CtlP->AiopIO[i] = (WordIO_t)io; - CtlP->AiopIntChanIO[i] = io + _INT_CHAN; - sOutB(CtlP->MReg2IO,CtlP->MReg2 | (i & 0x03)); /* AIOP index */ - sOutB(MudbacIO,(Byte_t)(io >> 6)); /* set up AIOP I/O in MUDBAC */ - sEnAiop(CtlP,i); /* enable the AIOP */ - - CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */ - if(CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */ - { - sDisAiop(CtlP,i); /* disable AIOP */ - break; /* done looking for AIOPs */ - } - - CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t)io); /* num channels in AIOP */ - sOutW((WordIO_t)io + _INDX_ADDR,_CLK_PRE); /* clock prescaler */ - sOutB(io + _INDX_DATA,sClockPrescale); - CtlP->NumAiop++; /* bump count of AIOPs */ - sDisAiop(CtlP,i); /* disable AIOP */ - } - - if(CtlP->NumAiop == 0) - return(-1); - else - return(CtlP->NumAiop); + if (sIRQMap[IRQNum] == 0) { /* interrupts globally disabled */ + CtlP->MReg2 = 0; /* interrupt disable */ + CtlP->MReg3 = 0; /* no periodic interrupts */ + } else { + CtlP->MReg2 = sIRQMap[IRQNum]; /* set IRQ number */ + CtlP->MReg3 = Frequency; /* set frequency */ + if (PeriodicOnly) { /* periodic interrupt only */ + CtlP->MReg3 |= PERIODIC_ONLY; + } + } +#endif + sOutB(CtlP->MReg2IO, CtlP->MReg2); + sOutB(CtlP->MReg3IO, CtlP->MReg3); + sControllerEOI(CtlP); /* clear EOI if warm init */ + /* Init AIOPs */ + CtlP->NumAiop = 0; + for (i = done = 0; i < AiopIOListSize; i++) { + io = AiopIOList[i]; + CtlP->AiopIO[i] = (WordIO_t) io; + CtlP->AiopIntChanIO[i] = io + _INT_CHAN; + sOutB(CtlP->MReg2IO, CtlP->MReg2 | (i & 0x03)); /* AIOP index */ + sOutB(MudbacIO, (Byte_t) (io >> 6)); /* set up AIOP I/O in MUDBAC */ + if (done) + continue; + sEnAiop(CtlP, i); /* enable the AIOP */ + CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */ + if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */ + done = 1; /* done looking for AIOPs */ + else { + CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */ + sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */ + sOutB(io + _INDX_DATA, sClockPrescale); + CtlP->NumAiop++; /* bump count of AIOPs */ + } + sDisAiop(CtlP, i); /* disable AIOP */ + } + + if (CtlP->NumAiop == 0) + return (-1); + else + return (CtlP->NumAiop); } /*************************************************************************** @@ -2433,46 +3067,55 @@ After this function all AIOPs on the controller are disabled, they can be enabled with sEnAiop(). */ -int sPCIInitController( CONTROLLER_T *CtlP, - int CtlNum, - ByteIO_t *AiopIOList, - int AiopIOListSize, - int IRQNum, - Byte_t Frequency, - int PeriodicOnly) -{ - int i; - ByteIO_t io; - - CtlP->CtlNum = CtlNum; - CtlP->CtlID = CTLID_0001; /* controller release 1 */ - CtlP->BusType = isPCI; /* controller release 1 */ - - CtlP->PCIIO = (WordIO_t)((ByteIO_t)AiopIOList[0] + _PCI_INT_FUNC); - - sPCIControllerEOI(CtlP); /* clear EOI if warm init */ - /* Init AIOPs */ - CtlP->NumAiop = 0; - for(i=0; i < AiopIOListSize; i++) - { - io = AiopIOList[i]; - CtlP->AiopIO[i] = (WordIO_t)io; - CtlP->AiopIntChanIO[i] = io + _INT_CHAN; - - CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */ - if(CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */ - break; /* done looking for AIOPs */ - - CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t)io); /* num channels in AIOP */ - sOutW((WordIO_t)io + _INDX_ADDR,_CLK_PRE); /* clock prescaler */ - sOutB(io + _INDX_DATA,sClockPrescale); - CtlP->NumAiop++; /* bump count of AIOPs */ - } - - if(CtlP->NumAiop == 0) - return(-1); - else - return(CtlP->NumAiop); +int sPCIInitController(CONTROLLER_T * CtlP, int CtlNum, + ByteIO_t * AiopIOList, int AiopIOListSize, + WordIO_t ConfigIO, int IRQNum, Byte_t Frequency, + int PeriodicOnly, int altChanRingIndicator, + int UPCIRingInd) +{ + int i; + ByteIO_t io; + + CtlP->AltChanRingIndicator = altChanRingIndicator; + CtlP->UPCIRingInd = UPCIRingInd; + CtlP->CtlNum = CtlNum; + CtlP->CtlID = CTLID_0001; /* controller release 1 */ + CtlP->BusType = isPCI; /* controller release 1 */ + + if (ConfigIO) { + CtlP->isUPCI = 1; + CtlP->PCIIO = ConfigIO + _PCI_9030_INT_CTRL; + CtlP->PCIIO2 = ConfigIO + _PCI_9030_GPIO_CTRL; + CtlP->AiopIntrBits = upci_aiop_intr_bits; + } else { + CtlP->isUPCI = 0; + CtlP->PCIIO = + (WordIO_t) ((ByteIO_t) AiopIOList[0] + _PCI_INT_FUNC); + CtlP->AiopIntrBits = aiop_intr_bits; + } + + sPCIControllerEOI(CtlP); /* clear EOI if warm init */ + /* Init AIOPs */ + CtlP->NumAiop = 0; + for (i = 0; i < AiopIOListSize; i++) { + io = AiopIOList[i]; + CtlP->AiopIO[i] = (WordIO_t) io; + CtlP->AiopIntChanIO[i] = io + _INT_CHAN; + + CtlP->AiopID[i] = sReadAiopID(io); /* read AIOP ID */ + if (CtlP->AiopID[i] == AIOPID_NULL) /* if AIOP does not exist */ + break; /* done looking for AIOPs */ + + CtlP->AiopNumChan[i] = sReadAiopNumChan((WordIO_t) io); /* num channels in AIOP */ + sOutW((WordIO_t) io + _INDX_ADDR, _CLK_PRE); /* clock prescaler */ + sOutB(io + _INDX_DATA, sClockPrescale); + CtlP->NumAiop++; /* bump count of AIOPs */ + } + + if (CtlP->NumAiop == 0) + return (-1); + else + return (CtlP->NumAiop); } /*************************************************************************** @@ -2488,15 +3131,15 @@ */ int sReadAiopID(ByteIO_t io) { - Byte_t AiopID; /* ID byte from AIOP */ + Byte_t AiopID; /* ID byte from AIOP */ - sOutB(io + _CMD_REG,RESET_ALL); /* reset AIOP */ - sOutB(io + _CMD_REG,0x0); - AiopID = sInB(io + _CHN_STAT0) & 0x07; - if(AiopID == 0x06) - return(1); - else /* AIOP does not exist */ - return(-1); + sOutB(io + _CMD_REG, RESET_ALL); /* reset AIOP */ + sOutB(io + _CMD_REG, 0x0); + AiopID = sInW(io + _CHN_STAT0) & 0x07; + if (AiopID == 0x06) + return (1); + else /* AIOP does not exist */ + return (-1); } /*************************************************************************** @@ -2514,16 +3157,18 @@ */ int sReadAiopNumChan(WordIO_t io) { - Word_t x; + Word_t x; + static Byte_t R[4] = { 0x00, 0x00, 0x34, 0x12 }; - sOutDW((DWordIO_t)io + _INDX_ADDR,0x12340000L); /* write to chan 0 SRAM */ - sOutW(io + _INDX_ADDR,0); /* read from SRAM, chan 0 */ - x = sInW(io + _INDX_DATA); - sOutW(io + _INDX_ADDR,0x4000); /* read from SRAM, chan 4 */ - if(x != sInW(io + _INDX_DATA)) /* if different must be 8 chan */ - return(8); - else - return(4); + /* write to chan 0 SRAM */ + sOutDW((DWordIO_t) io + _INDX_ADDR, *((DWord_t *) & R[0])); + sOutW(io + _INDX_ADDR, 0); /* read from SRAM, chan 0 */ + x = sInW(io + _INDX_DATA); + sOutW(io + _INDX_ADDR, 0x4000); /* read from SRAM, chan 4 */ + if (x != sInW(io + _INDX_DATA)) /* if different must be 8 chan */ + return (8); + else + return (4); } /*************************************************************************** @@ -2541,138 +3186,134 @@ No context switches are allowed while executing this function. */ -int sInitChan( CONTROLLER_T *CtlP, - CHANNEL_T *ChP, - int AiopNum, - int ChanNum) -{ - int i; - WordIO_t AiopIO; - WordIO_t ChIOOff; - Byte_t *ChR; - Word_t ChOff; - static Byte_t R[4]; - int brd9600; - - if(ChanNum >= CtlP->AiopNumChan[AiopNum]) - return(FALSE); /* exceeds num chans in AIOP */ - - /* Channel, AIOP, and controller identifiers */ - ChP->CtlP = CtlP; - ChP->ChanID = CtlP->AiopID[AiopNum]; - ChP->AiopNum = AiopNum; - ChP->ChanNum = ChanNum; - - /* Global direct addresses */ - AiopIO = CtlP->AiopIO[AiopNum]; - ChP->Cmd = (ByteIO_t)AiopIO + _CMD_REG; - ChP->IntChan = (ByteIO_t)AiopIO + _INT_CHAN; - ChP->IntMask = (ByteIO_t)AiopIO + _INT_MASK; - ChP->IndexAddr = (DWordIO_t)AiopIO + _INDX_ADDR; - ChP->IndexData = AiopIO + _INDX_DATA; - - /* Channel direct addresses */ - ChIOOff = AiopIO + ChP->ChanNum * 2; - ChP->TxRxData = ChIOOff + _TD0; - ChP->ChanStat = ChIOOff + _CHN_STAT0; - ChP->TxRxCount = ChIOOff + _FIFO_CNT0; - ChP->IntID = (ByteIO_t)AiopIO + ChP->ChanNum + _INT_ID0; - - /* Initialize the channel from the RData array */ - for(i=0; i < RDATASIZE; i+=4) - { - R[0] = RData[i]; - R[1] = RData[i+1] + 0x10 * ChanNum; - R[2] = RData[i+2]; - R[3] = RData[i+3]; - sOutDW(ChP->IndexAddr,*((DWord_t *)&R[0])); - } - - ChR = ChP->R; - for(i=0; i < RREGDATASIZE; i+=4) - { - ChR[i] = RRegData[i]; - ChR[i+1] = RRegData[i+1] + 0x10 * ChanNum; - ChR[i+2] = RRegData[i+2]; - ChR[i+3] = RRegData[i+3]; - } - - /* Indexed registers */ - ChOff = (Word_t)ChanNum * 0x1000; - - if (sClockPrescale == 0x14) - brd9600 = 47; - else - brd9600 = 23; - - ChP->BaudDiv[0] = (Byte_t)(ChOff + _BAUD); - ChP->BaudDiv[1] = (Byte_t)((ChOff + _BAUD) >> 8); - ChP->BaudDiv[2] = (Byte_t)brd9600; - ChP->BaudDiv[3] = (Byte_t)(brd9600 >> 8); - sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->BaudDiv[0]); - - ChP->TxControl[0] = (Byte_t)(ChOff + _TX_CTRL); - ChP->TxControl[1] = (Byte_t)((ChOff + _TX_CTRL) >> 8); - ChP->TxControl[2] = 0; - ChP->TxControl[3] = 0; - sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxControl[0]); - - ChP->RxControl[0] = (Byte_t)(ChOff + _RX_CTRL); - ChP->RxControl[1] = (Byte_t)((ChOff + _RX_CTRL) >> 8); - ChP->RxControl[2] = 0; - ChP->RxControl[3] = 0; - sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->RxControl[0]); - - ChP->TxEnables[0] = (Byte_t)(ChOff + _TX_ENBLS); - ChP->TxEnables[1] = (Byte_t)((ChOff + _TX_ENBLS) >> 8); - ChP->TxEnables[2] = 0; - ChP->TxEnables[3] = 0; - sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxEnables[0]); - - ChP->TxCompare[0] = (Byte_t)(ChOff + _TXCMP1); - ChP->TxCompare[1] = (Byte_t)((ChOff + _TXCMP1) >> 8); - ChP->TxCompare[2] = 0; - ChP->TxCompare[3] = 0; - sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxCompare[0]); - - ChP->TxReplace1[0] = (Byte_t)(ChOff + _TXREP1B1); - ChP->TxReplace1[1] = (Byte_t)((ChOff + _TXREP1B1) >> 8); - ChP->TxReplace1[2] = 0; - ChP->TxReplace1[3] = 0; - sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxReplace1[0]); - - ChP->TxReplace2[0] = (Byte_t)(ChOff + _TXREP2); - ChP->TxReplace2[1] = (Byte_t)((ChOff + _TXREP2) >> 8); - ChP->TxReplace2[2] = 0; - ChP->TxReplace2[3] = 0; - sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxReplace2[0]); - - ChP->TxFIFOPtrs = ChOff + _TXF_OUTP; - ChP->TxFIFO = ChOff + _TX_FIFO; - - sOutB(ChP->Cmd,(Byte_t)ChanNum | RESTXFCNT); /* apply reset Tx FIFO count */ - sOutB(ChP->Cmd,(Byte_t)ChanNum); /* remove reset Tx FIFO count */ - sOutW((WordIO_t)ChP->IndexAddr,ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */ - sOutW(ChP->IndexData,0); - ChP->RxFIFOPtrs = ChOff + _RXF_OUTP; - ChP->RxFIFO = ChOff + _RX_FIFO; - - sOutB(ChP->Cmd,(Byte_t)ChanNum | RESRXFCNT); /* apply reset Rx FIFO count */ - sOutB(ChP->Cmd,(Byte_t)ChanNum); /* remove reset Rx FIFO count */ - sOutW((WordIO_t)ChP->IndexAddr,ChP->RxFIFOPtrs); /* clear Rx out ptr */ - sOutW(ChP->IndexData,0); - sOutW((WordIO_t)ChP->IndexAddr,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */ - sOutW(ChP->IndexData,0); - ChP->TxPrioCnt = ChOff + _TXP_CNT; - sOutW((WordIO_t)ChP->IndexAddr,ChP->TxPrioCnt); - sOutB(ChP->IndexData,0); - ChP->TxPrioPtr = ChOff + _TXP_PNTR; - sOutW((WordIO_t)ChP->IndexAddr,ChP->TxPrioPtr); - sOutB(ChP->IndexData,0); - ChP->TxPrioBuf = ChOff + _TXP_BUF; - sEnRxProcessor(ChP); /* start the Rx processor */ +int sInitChan(CONTROLLER_T * CtlP, CHANNEL_T * ChP, int AiopNum, + int ChanNum) +{ + int i; + WordIO_t AiopIO; + WordIO_t ChIOOff; + Byte_t *ChR; + Word_t ChOff; + static Byte_t R[4]; + int brd9600; + + if (ChanNum >= CtlP->AiopNumChan[AiopNum]) + return (FALSE); /* exceeds num chans in AIOP */ + + /* Channel, AIOP, and controller identifiers */ + ChP->CtlP = CtlP; + ChP->ChanID = CtlP->AiopID[AiopNum]; + ChP->AiopNum = AiopNum; + ChP->ChanNum = ChanNum; + + /* Global direct addresses */ + AiopIO = CtlP->AiopIO[AiopNum]; + ChP->Cmd = (ByteIO_t) AiopIO + _CMD_REG; + ChP->IntChan = (ByteIO_t) AiopIO + _INT_CHAN; + ChP->IntMask = (ByteIO_t) AiopIO + _INT_MASK; + ChP->IndexAddr = (DWordIO_t) AiopIO + _INDX_ADDR; + ChP->IndexData = AiopIO + _INDX_DATA; + + /* Channel direct addresses */ + ChIOOff = AiopIO + ChP->ChanNum * 2; + ChP->TxRxData = ChIOOff + _TD0; + ChP->ChanStat = ChIOOff + _CHN_STAT0; + ChP->TxRxCount = ChIOOff + _FIFO_CNT0; + ChP->IntID = (ByteIO_t) AiopIO + ChP->ChanNum + _INT_ID0; + + /* Initialize the channel from the RData array */ + for (i = 0; i < RDATASIZE; i += 4) { + R[0] = RData[i]; + R[1] = RData[i + 1] + 0x10 * ChanNum; + R[2] = RData[i + 2]; + R[3] = RData[i + 3]; + sOutDW(ChP->IndexAddr, *((DWord_t *) & R[0])); + } + + ChR = ChP->R; + for (i = 0; i < RREGDATASIZE; i += 4) { + ChR[i] = RRegData[i]; + ChR[i + 1] = RRegData[i + 1] + 0x10 * ChanNum; + ChR[i + 2] = RRegData[i + 2]; + ChR[i + 3] = RRegData[i + 3]; + } + + /* Indexed registers */ + ChOff = (Word_t) ChanNum *0x1000; + + if (sClockPrescale == 0x14) + brd9600 = 47; + else + brd9600 = 23; - return(TRUE); + ChP->BaudDiv[0] = (Byte_t) (ChOff + _BAUD); + ChP->BaudDiv[1] = (Byte_t) ((ChOff + _BAUD) >> 8); + ChP->BaudDiv[2] = (Byte_t) brd9600; + ChP->BaudDiv[3] = (Byte_t) (brd9600 >> 8); + sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->BaudDiv[0]); + + ChP->TxControl[0] = (Byte_t) (ChOff + _TX_CTRL); + ChP->TxControl[1] = (Byte_t) ((ChOff + _TX_CTRL) >> 8); + ChP->TxControl[2] = 0; + ChP->TxControl[3] = 0; + sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->TxControl[0]); + + ChP->RxControl[0] = (Byte_t) (ChOff + _RX_CTRL); + ChP->RxControl[1] = (Byte_t) ((ChOff + _RX_CTRL) >> 8); + ChP->RxControl[2] = 0; + ChP->RxControl[3] = 0; + sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->RxControl[0]); + + ChP->TxEnables[0] = (Byte_t) (ChOff + _TX_ENBLS); + ChP->TxEnables[1] = (Byte_t) ((ChOff + _TX_ENBLS) >> 8); + ChP->TxEnables[2] = 0; + ChP->TxEnables[3] = 0; + sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->TxEnables[0]); + + ChP->TxCompare[0] = (Byte_t) (ChOff + _TXCMP1); + ChP->TxCompare[1] = (Byte_t) ((ChOff + _TXCMP1) >> 8); + ChP->TxCompare[2] = 0; + ChP->TxCompare[3] = 0; + sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->TxCompare[0]); + + ChP->TxReplace1[0] = (Byte_t) (ChOff + _TXREP1B1); + ChP->TxReplace1[1] = (Byte_t) ((ChOff + _TXREP1B1) >> 8); + ChP->TxReplace1[2] = 0; + ChP->TxReplace1[3] = 0; + sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->TxReplace1[0]); + + ChP->TxReplace2[0] = (Byte_t) (ChOff + _TXREP2); + ChP->TxReplace2[1] = (Byte_t) ((ChOff + _TXREP2) >> 8); + ChP->TxReplace2[2] = 0; + ChP->TxReplace2[3] = 0; + sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->TxReplace2[0]); + + ChP->TxFIFOPtrs = ChOff + _TXF_OUTP; + ChP->TxFIFO = ChOff + _TX_FIFO; + + sOutB(ChP->Cmd, (Byte_t) ChanNum | RESTXFCNT); /* apply reset Tx FIFO count */ + sOutB(ChP->Cmd, (Byte_t) ChanNum); /* remove reset Tx FIFO count */ + sOutW((WordIO_t) ChP->IndexAddr, ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */ + sOutW(ChP->IndexData, 0); + ChP->RxFIFOPtrs = ChOff + _RXF_OUTP; + ChP->RxFIFO = ChOff + _RX_FIFO; + + sOutB(ChP->Cmd, (Byte_t) ChanNum | RESRXFCNT); /* apply reset Rx FIFO count */ + sOutB(ChP->Cmd, (Byte_t) ChanNum); /* remove reset Rx FIFO count */ + sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs); /* clear Rx out ptr */ + sOutW(ChP->IndexData, 0); + sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */ + sOutW(ChP->IndexData, 0); + ChP->TxPrioCnt = ChOff + _TXP_CNT; + sOutW((WordIO_t) ChP->IndexAddr, ChP->TxPrioCnt); + sOutB(ChP->IndexData, 0); + ChP->TxPrioPtr = ChOff + _TXP_PNTR; + sOutW((WordIO_t) ChP->IndexAddr, ChP->TxPrioPtr); + sOutB(ChP->IndexData, 0); + ChP->TxPrioBuf = ChOff + _TXP_BUF; + sEnRxProcessor(ChP); /* start the Rx processor */ + + return (TRUE); } /*************************************************************************** @@ -2693,15 +3334,15 @@ After calling this function a delay of 4 uS is required to ensure that the receive processor is no longer processing this channel. */ -void sStopRxProcessor(CHANNEL_T *ChP) +void sStopRxProcessor(CHANNEL_T * ChP) { - Byte_t R[4]; + Byte_t R[4]; - R[0] = ChP->R[0]; - R[1] = ChP->R[1]; - R[2] = 0x0a; - R[3] = ChP->R[3]; - sOutDW(ChP->IndexAddr,*(DWord_t *)&R[0]); + R[0] = ChP->R[0]; + R[1] = ChP->R[1]; + R[2] = 0x0a; + R[3] = ChP->R[3]; + sOutDW(ChP->IndexAddr, *(DWord_t *) & R[0]); } /*************************************************************************** @@ -2718,33 +3359,32 @@ this function. Warnings: No context switches are allowed while executing this function. */ -void sFlushRxFIFO(CHANNEL_T *ChP) +void sFlushRxFIFO(CHANNEL_T * ChP) { - int i; - Byte_t Ch; /* channel number within AIOP */ - int RxFIFOEnabled; /* TRUE if Rx FIFO enabled */ - - if(sGetRxCnt(ChP) == 0) /* Rx FIFO empty */ - return; /* don't need to flush */ - - RxFIFOEnabled = FALSE; - if(ChP->R[0x32] == 0x08) /* Rx FIFO is enabled */ - { - RxFIFOEnabled = TRUE; - sDisRxFIFO(ChP); /* disable it */ - for(i=0; i < 2000/200; i++) /* delay 2 uS to allow proc to disable FIFO*/ - sInB(ChP->IntChan); /* depends on bus i/o timing */ - } - sGetChanStatus(ChP); /* clear any pending Rx errors in chan stat */ - Ch = (Byte_t)sGetChanNum(ChP); - sOutB(ChP->Cmd,Ch | RESRXFCNT); /* apply reset Rx FIFO count */ - sOutB(ChP->Cmd,Ch); /* remove reset Rx FIFO count */ - sOutW((WordIO_t)ChP->IndexAddr,ChP->RxFIFOPtrs); /* clear Rx out ptr */ - sOutW(ChP->IndexData,0); - sOutW((WordIO_t)ChP->IndexAddr,ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */ - sOutW(ChP->IndexData,0); - if(RxFIFOEnabled) - sEnRxFIFO(ChP); /* enable Rx FIFO */ + int i; + Byte_t Ch; /* channel number within AIOP */ + int RxFIFOEnabled; /* TRUE if Rx FIFO enabled */ + + if (sGetRxCnt(ChP) == 0) /* Rx FIFO empty */ + return; /* don't need to flush */ + + RxFIFOEnabled = FALSE; + if (ChP->R[0x32] == 0x08) { /* Rx FIFO is enabled */ + RxFIFOEnabled = TRUE; + sDisRxFIFO(ChP); /* disable it */ + for (i = 0; i < 2000 / 200; i++) /* delay 2 uS to allow proc to disable FIFO */ + sInB(ChP->IntChan); /* depends on bus i/o timing */ + } + sGetChanStatus(ChP); /* clear any pending Rx errors in chan stat */ + Ch = (Byte_t) sGetChanNum(ChP); + sOutB(ChP->Cmd, Ch | RESRXFCNT); /* apply reset Rx FIFO count */ + sOutB(ChP->Cmd, Ch); /* remove reset Rx FIFO count */ + sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs); /* clear Rx out ptr */ + sOutW(ChP->IndexData, 0); + sOutW((WordIO_t) ChP->IndexAddr, ChP->RxFIFOPtrs + 2); /* clear Rx in ptr */ + sOutW(ChP->IndexData, 0); + if (RxFIFOEnabled) + sEnRxFIFO(ChP); /* enable Rx FIFO */ } /*************************************************************************** @@ -2761,32 +3401,31 @@ this function. Warnings: No context switches are allowed while executing this function. */ -void sFlushTxFIFO(CHANNEL_T *ChP) +void sFlushTxFIFO(CHANNEL_T * ChP) { - int i; - Byte_t Ch; /* channel number within AIOP */ - int TxEnabled; /* TRUE if transmitter enabled */ - - if(sGetTxCnt(ChP) == 0) /* Tx FIFO empty */ - return; /* don't need to flush */ - - TxEnabled = FALSE; - if(ChP->TxControl[3] & TX_ENABLE) - { - TxEnabled = TRUE; - sDisTransmit(ChP); /* disable transmitter */ - } - sStopRxProcessor(ChP); /* stop Rx processor */ - for(i = 0; i < 4000/200; i++) /* delay 4 uS to allow proc to stop */ - sInB(ChP->IntChan); /* depends on bus i/o timing */ - Ch = (Byte_t)sGetChanNum(ChP); - sOutB(ChP->Cmd,Ch | RESTXFCNT); /* apply reset Tx FIFO count */ - sOutB(ChP->Cmd,Ch); /* remove reset Tx FIFO count */ - sOutW((WordIO_t)ChP->IndexAddr,ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */ - sOutW(ChP->IndexData,0); - if(TxEnabled) - sEnTransmit(ChP); /* enable transmitter */ - sStartRxProcessor(ChP); /* restart Rx processor */ + int i; + Byte_t Ch; /* channel number within AIOP */ + int TxEnabled; /* TRUE if transmitter enabled */ + + if (sGetTxCnt(ChP) == 0) /* Tx FIFO empty */ + return; /* don't need to flush */ + + TxEnabled = FALSE; + if (ChP->TxControl[3] & TX_ENABLE) { + TxEnabled = TRUE; + sDisTransmit(ChP); /* disable transmitter */ + } + sStopRxProcessor(ChP); /* stop Rx processor */ + for (i = 0; i < 4000 / 200; i++) /* delay 4 uS to allow proc to stop */ + sInB(ChP->IntChan); /* depends on bus i/o timing */ + Ch = (Byte_t) sGetChanNum(ChP); + sOutB(ChP->Cmd, Ch | RESTXFCNT); /* apply reset Tx FIFO count */ + sOutB(ChP->Cmd, Ch); /* remove reset Tx FIFO count */ + sOutW((WordIO_t) ChP->IndexAddr, ChP->TxFIFOPtrs); /* clear Tx in/out ptrs */ + sOutW(ChP->IndexData, 0); + if (TxEnabled) + sEnTransmit(ChP); /* enable transmitter */ + sStartRxProcessor(ChP); /* restart Rx processor */ } /*************************************************************************** @@ -2802,36 +3441,34 @@ Warnings: No context switches are allowed while executing this function. */ -int sWriteTxPrioByte(CHANNEL_T *ChP, Byte_t Data) +int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data) { - Byte_t DWBuf[4]; /* buffer for double word writes */ - Word_t *WordPtr; /* must be far because Win SS != DS */ - register DWordIO_t IndexAddr; - - if(sGetTxCnt(ChP) > 1) /* write it to Tx priority buffer */ - { - IndexAddr = ChP->IndexAddr; - sOutW((WordIO_t)IndexAddr,ChP->TxPrioCnt); /* get priority buffer status */ - if(sInB((ByteIO_t)ChP->IndexData) & PRI_PEND) /* priority buffer busy */ - return(0); /* nothing sent */ - - WordPtr = (Word_t *)(&DWBuf[0]); - *WordPtr = ChP->TxPrioBuf; /* data byte address */ - - DWBuf[2] = Data; /* data byte value */ - sOutDW(IndexAddr,*((DWord_t *)(&DWBuf[0]))); /* write it out */ - - *WordPtr = ChP->TxPrioCnt; /* Tx priority count address */ - - DWBuf[2] = PRI_PEND + 1; /* indicate 1 byte pending */ - DWBuf[3] = 0; /* priority buffer pointer */ - sOutDW(IndexAddr,*((DWord_t *)(&DWBuf[0]))); /* write it out */ - } - else /* write it to Tx FIFO */ - { - sWriteTxByte(sGetTxRxDataIO(ChP),Data); - } - return(1); /* 1 byte sent */ + Byte_t DWBuf[4]; /* buffer for double word writes */ + Word_t *WordPtr; /* must be far because Win SS != DS */ + register DWordIO_t IndexAddr; + + if (sGetTxCnt(ChP) > 1) { /* write it to Tx priority buffer */ + IndexAddr = ChP->IndexAddr; + sOutW((WordIO_t) IndexAddr, ChP->TxPrioCnt); /* get priority buffer status */ + if (sInB((ByteIO_t) ChP->IndexData) & PRI_PEND) /* priority buffer busy */ + return (0); /* nothing sent */ + + WordPtr = (Word_t *) (&DWBuf[0]); + *WordPtr = ChP->TxPrioBuf; /* data byte address */ + + DWBuf[2] = Data; /* data byte value */ + sOutDW(IndexAddr, *((DWord_t *) (&DWBuf[0]))); /* write it out */ + + *WordPtr = ChP->TxPrioCnt; /* Tx priority count address */ + + DWBuf[2] = PRI_PEND + 1; /* indicate 1 byte pending */ + DWBuf[3] = 0; /* priority buffer pointer */ + sOutDW(IndexAddr, *((DWord_t *) (&DWBuf[0]))); /* write it out */ + } else { /* write it to Tx FIFO */ + + sWriteTxByte(sGetTxRxDataIO(ChP), Data); + } + return (1); /* 1 byte sent */ } /*************************************************************************** @@ -2866,24 +3503,23 @@ enable channel interrupts. This would allow the global interrupt status register to be used to determine which AIOPs need service. */ -void sEnInterrupts(CHANNEL_T *ChP,Word_t Flags) +void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags) { - Byte_t Mask; /* Interrupt Mask Register */ + Byte_t Mask; /* Interrupt Mask Register */ - ChP->RxControl[2] |= - ((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN)); + ChP->RxControl[2] |= + ((Byte_t) Flags & (RXINT_EN | SRCINT_EN | MCINT_EN)); - sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->RxControl[0]); + sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->RxControl[0]); - ChP->TxControl[2] |= ((Byte_t)Flags & TXINT_EN); + ChP->TxControl[2] |= ((Byte_t) Flags & TXINT_EN); - sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxControl[0]); + sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->TxControl[0]); - if(Flags & CHANINT_EN) - { - Mask = sInB(ChP->IntMask) | sBitMapSetTbl[ChP->ChanNum]; - sOutB(ChP->IntMask,Mask); - } + if (Flags & CHANINT_EN) { + Mask = sInB(ChP->IntMask) | sBitMapSetTbl[ChP->ChanNum]; + sOutB(ChP->IntMask, Mask); + } } /*************************************************************************** @@ -2911,19 +3547,98 @@ this channel's bit from being set in the AIOP's Interrupt Channel Register. */ -void sDisInterrupts(CHANNEL_T *ChP,Word_t Flags) +void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags) +{ + Byte_t Mask; /* Interrupt Mask Register */ + + ChP->RxControl[2] &= + ~((Byte_t) Flags & (RXINT_EN | SRCINT_EN | MCINT_EN)); + sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->RxControl[0]); + ChP->TxControl[2] &= ~((Byte_t) Flags & TXINT_EN); + sOutDW(ChP->IndexAddr, *(DWord_t *) & ChP->TxControl[0]); + + if (Flags & CHANINT_EN) { + Mask = sInB(ChP->IntMask) & sBitMapClrTbl[ChP->ChanNum]; + sOutB(ChP->IntMask, Mask); + } +} + +void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode) { - Byte_t Mask; /* Interrupt Mask Register */ + sOutB(ChP->CtlP->AiopIO[2], (mode & 0x18) | ChP->ChanNum); +} - ChP->RxControl[2] &= - ~((Byte_t)Flags & (RXINT_EN | SRCINT_EN | MCINT_EN)); - sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->RxControl[0]); - ChP->TxControl[2] &= ~((Byte_t)Flags & TXINT_EN); - sOutDW(ChP->IndexAddr,*(DWord_t *)&ChP->TxControl[0]); - - if(Flags & CHANINT_EN) - { - Mask = sInB(ChP->IntMask) & sBitMapClrTbl[ChP->ChanNum]; - sOutB(ChP->IntMask,Mask); - } +/* + * Not an official SSCI function, but how to reset RocketModems. + * ISA bus version + */ +void sModemReset(CONTROLLER_T * CtlP, int chan, int on) +{ + ByteIO_t addr; + Byte_t val; + + addr = CtlP->AiopIO[0] + 0x400; + val = sInB(CtlP->MReg3IO); + /* if AIOP[1] is not enabled, enable it */ + if ((val & 2) == 0) { + val = sInB(CtlP->MReg2IO); + sOutB(CtlP->MReg2IO, (val & 0xfc) | (1 & 0x03)); + sOutB(CtlP->MBaseIO, (unsigned char) (addr >> 6)); + } + + sEnAiop(CtlP, 1); + if (!on) + addr += 8; + sOutB(addr + chan, 0); /* apply or remove reset */ + sDisAiop(CtlP, 1); +} + +/* + * Not an official SSCI function, but how to reset RocketModems. + * PCI bus version + */ +void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on) +{ + ByteIO_t addr; + + addr = CtlP->AiopIO[0] + 0x40; /* 2nd AIOP */ + if (!on) + addr += 8; + sOutB(addr + chan, 0); /* apply or remove reset */ +} + +/* Resets the speaker controller on RocketModem II and III devices */ +static void rmSpeakerReset(CONTROLLER_T * CtlP, unsigned long model) +{ + ByteIO_t addr; + + /* RocketModem II speaker control is at the 8th port location of offset 0x40 */ + if ((model == MODEL_RP4M) || (model == MODEL_RP6M)) { + addr = CtlP->AiopIO[0] + 0x4F; + sOutB(addr, 0); + } + + /* RocketModem III speaker control is at the 1st port location of offset 0x80 */ + if ((model == MODEL_UPCI_RM3_8PORT) + || (model == MODEL_UPCI_RM3_4PORT)) { + addr = CtlP->AiopIO[0] + 0x88; + sOutB(addr, 0); + } +} + +/* Returns the line number given the controller (board), aiop and channel number */ +static unsigned char GetLineNumber(int ctrl, int aiop, int ch) +{ + return lineNumbers[(ctrl << 5) | (aiop << 3) | ch]; +} + +/* + * Stores the line number associated with a given controller (board), aiop + * and channel number. + * Returns: The line number assigned + */ +static unsigned char SetLineNumber(int ctrl, int aiop, int ch) +{ + lineNumbers[(ctrl << 5) | (aiop << 3) | ch] = nextLineNumber++; + return (nextLineNumber - 1); } diff -Nru a/drivers/char/rocket.h b/drivers/char/rocket.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/char/rocket.h Mon Jun 9 23:16:05 2003 @@ -0,0 +1,131 @@ +/* + * rocket.h --- the exported interface of the rocket driver to + * its configuration program. + * + * Written by Theodore Ts'o, Copyright 1997. + * + * Copyright 1994, 1997, 2003 Comtrol Corporation. All Rights Reserved. + * + * The following source code is subject to Comtrol Corporation's + * Developer's License Agreement. + * + * This source code is protected by United States copyright law and + * international copyright treaties. + * + * This source code may only be used to develop software products that + * will operate with Comtrol brand hardware. + * + * You may not reproduce nor distribute this source code in its original + * form but must produce a derivative work which includes portions of + * this source code only. + * + * The portions of this source code which you use in your derivative + * work must bear Comtrol's copyright notice: + * + * Copyright 1994 Comtrol Corporation. + * + */ + +/* Model Information Struct */ +typedef struct { + unsigned long model; + char modelString[80]; + unsigned long numPorts; + int loadrm2; + int startingPortNumber; +} rocketModel_t; + +struct rocket_config { + int line; + int flags; + int closing_wait; + int close_delay; + int port; + int reserved[32]; +}; + +struct rocket_ports { + int tty_major; + int callout_major; + rocketModel_t rocketModel[8]; +}; + +struct rocket_version { + char rocket_version[32]; + char rocket_date[32]; + char reserved[64]; +}; + +/* + * Rocketport flags + */ +#define ROCKET_CALLOUT_NOHUP 0x00000001 +#define ROCKET_FORCE_CD 0x00000002 +#define ROCKET_HUP_NOTIFY 0x00000004 +#define ROCKET_SPLIT_TERMIOS 0x00000008 +#define ROCKET_SPD_MASK 0x00000070 +#define ROCKET_SPD_HI 0x00000010 /* Use 56000 instead of 38400 bps */ +#define ROCKET_SPD_VHI 0x00000020 /* Use 115200 instead of 38400 bps */ +#define ROCKET_SPD_SHI 0x00000030 /* Use 230400 instead of 38400 bps */ +#define ROCKET_SPD_WARP 0x00000040 /* Use 460800 instead of 38400 bps */ +#define ROCKET_SAK 0x00000080 +#define ROCKET_SESSION_LOCKOUT 0x00000100 +#define ROCKET_PGRP_LOCKOUT 0x00000200 +#define ROCKET_RTS_TOGGLE 0x00000400 +#define ROCKET_MODE_MASK 0x00003000 +#define ROCKET_MODE_RS232 0x00000000 +#define ROCKET_MODE_RS485 0x00001000 +#define ROCKET_MODE_RS422 0x00002000 +#define ROCKET_FLAGS 0x00003FFF + +#define ROCKET_USR_MASK 0x0071 /* Legal flags that non-privileged + * users can set or reset */ + +/* + * For closing_wait and closing_wait2 + */ +#define ROCKET_CLOSING_WAIT_NONE 65535 +#define ROCKET_CLOSING_WAIT_INF 0 + +/* + * Rocketport ioctls -- "RP" + */ +#define RCKP_GET_STRUCT 0x00525001 +#define RCKP_GET_CONFIG 0x00525002 +#define RCKP_SET_CONFIG 0x00525003 +#define RCKP_GET_PORTS 0x00525004 +#define RCKP_RESET_RM2 0x00525005 +#define RCKP_GET_VERSION 0x00525006 + +/* Rocketport Models */ +#define MODEL_RP32INTF 0x0001 /* RP 32 port w/external I/F */ +#define MODEL_RP8INTF 0x0002 /* RP 8 port w/external I/F */ +#define MODEL_RP16INTF 0x0003 /* RP 16 port w/external I/F */ +#define MODEL_RP8OCTA 0x0005 /* RP 8 port w/octa cable */ +#define MODEL_RP4QUAD 0x0004 /* RP 4 port w/quad cable */ +#define MODEL_RP8J 0x0006 /* RP 8 port w/RJ11 connectors */ +#define MODEL_RP4J 0x0007 /* RP 4 port w/RJ45 connectors */ +#define MODEL_RP8SNI 0x0008 /* RP 8 port w/ DB78 SNI connector */ +#define MODEL_RP16SNI 0x0009 /* RP 16 port w/ DB78 SNI connector */ +#define MODEL_RPP4 0x000A /* RP Plus 4 port */ +#define MODEL_RPP8 0x000B /* RP Plus 8 port */ +#define MODEL_RP2_232 0x000E /* RP Plus 2 port RS232 */ +#define MODEL_RP2_422 0x000F /* RP Plus 2 port RS232 */ + +/* Rocketmodem II Models */ +#define MODEL_RP6M 0x000C /* RM 6 port */ +#define MODEL_RP4M 0x000D /* RM 4 port */ + +/* Universal PCI boards */ +#define MODEL_UPCI_RP32INTF 0x0801 /* RP UPCI 32 port w/external I/F */ +#define MODEL_UPCI_RP8INTF 0x0802 /* RP UPCI 8 port w/external I/F */ +#define MODEL_UPCI_RP16INTF 0x0803 /* RP UPCI 16 port w/external I/F */ +#define MODEL_UPCI_RP8OCTA 0x0805 /* RP UPCI 8 port w/octa cable */ +#define MODEL_UPCI_RM3_8PORT 0x080C /* RP UPCI Rocketmodem III 8 port */ +#define MODEL_UPCI_RM3_4PORT 0x080C /* RP UPCI Rocketmodem III 4 port */ + +/* Compact PCI 16 port */ +#define MODEL_CPCI_RP16INTF 0x0903 /* RP Compact PCI 16 port w/external I/F */ + +/* All ISA boards */ +#define MODEL_ISA 0x1000 diff -Nru a/drivers/char/rocket_int.h b/drivers/char/rocket_int.h --- a/drivers/char/rocket_int.h Mon Jun 9 23:16:08 2003 +++ b/drivers/char/rocket_int.h Mon Jun 9 23:16:08 2003 @@ -3,9 +3,7 @@ * * Written by Theodore Ts'o, Copyright 1997. * - * Portions of this file are.... - * - * Copyright 1994 Comtrol Corporation. All Rights Reserved. + * Copyright 1994, 1997, 2003 Comtrol Corporation. All Rights Reserved. * * The following source code is subject to Comtrol Corporation's * Developer's License Agreement. @@ -28,23 +26,16 @@ */ /* - * Begin Comtrol-provided headers, et. al. + * Definition of the types in rcktpt_type */ - -/* - user definitions for Rocket Toolkit - - The following typedefs and defines must be established - depending on the platform the toolkit is being used - with. - -*/ - -/************************************************************ -The following sets up the world for use with Linux -************************************************************/ +#define ROCKET_TYPE_NORMAL 0 +#define ROCKET_TYPE_MODEM 1 +#define ROCKET_TYPE_MODEMII 2 +#define ROCKET_TYPE_MODEMIII 3 +#define ROCKET_TYPE_PC104 4 #include <asm/io.h> +#include <asm/byteorder.h> typedef unsigned char Byte_t; typedef unsigned int ByteIO_t; @@ -55,17 +46,71 @@ typedef unsigned long DWord_t; typedef unsigned int DWordIO_t; +/* + * Note! Normally the Linux I/O macros already take care of + * byte-swapping the I/O instructions. However, all accesses using + * sOutDW aren't really 32-bit accesses, but should be handled in byte + * order. Hence the use of the cpu_to_le32() macro to byte-swap + * things to no-op the byte swapping done by the big-endian outl() + * instruction. + */ + +#ifdef ROCKET_DEBUG_IO +static inline void sOutB(unsigned short port, unsigned char value) +{ +#ifdef ROCKET_DEBUG_IO + printk("sOutB(%x, %x)...", port, value); +#endif + outb_p(value, port); +} + +static inline void sOutW(unsigned short port, unsigned short value) +{ +#ifdef ROCKET_DEBUG_IO + printk("sOutW(%x, %x)...", port, value); +#endif + outw_p(value, port); +} + +static inline void sOutDW(unsigned short port, unsigned long value) +{ +#ifdef ROCKET_DEBUG_IO + printk("sOutDW(%x, %lx)...", port, value); +#endif + outl_p(cpu_to_le32(value), port); +} + +static inline unsigned char sInB(unsigned short port) +{ + return inb_p(port); +} + +static inline unsigned short sInW(unsigned short port) +{ + return inw_p(port); +} + +#else /* !ROCKET_DEBUG_IO */ #define sOutB(a, b) outb_p(b, a) #define sOutW(a, b) outw_p(b, a) -#define sOutDW(a, b) outl_p(b, a) +#define sOutDW(port, value) outl_p(cpu_to_le32(value), port) #define sInB(a) (inb_p(a)) #define sInW(a) (inw_p(a)) +#endif /* ROCKET_DEBUG_IO */ -#define sOutStrW(port, addr, count) outsw(port, addr, count) +/* This is used to move arrays of bytes so byte swapping isn't + * appropriate. On Linux 2.3 and above outsw is the same as + * outsw_ns, but we use the old form for compatibility with + * old kernels. */ +#if defined(__BIG_ENDIAN) && (LINUX_VERSION_CODE < VERSION_CODE(2,3,0)) +#define sOutStrW(port, addr, count) if (count) outsw_ns(port, addr, count) +#define sInStrW(port, addr, count) if (count) insw_ns(port, addr, count) +#else +#define sOutStrW(port, addr, count) if (count) outsw(port, addr, count) +#define sInStrW(port, addr, count) if (count) insw(port, addr, count) +#endif -#define sInStrW(port, addr, count) insw(port, addr, count) - -#define CTL_SIZE 4 +#define CTL_SIZE 8 #define AIOP_CTL_SIZE 4 #define CHAN_AIOP_SIZE 8 #define MAX_PORTS_PER_AIOP 8 @@ -78,219 +123,159 @@ #define isMC 2 /* Controller ID numbers */ -#define CTLID_NULL -1 /* no controller exists */ -#define CTLID_0001 0x0001 /* controller release 1 */ +#define CTLID_NULL -1 /* no controller exists */ +#define CTLID_0001 0x0001 /* controller release 1 */ /* AIOP ID numbers, identifies AIOP type implementing channel */ -#define AIOPID_NULL -1 /* no AIOP or channel exists */ -#define AIOPID_0001 0x0001 /* AIOP release 1 */ +#define AIOPID_NULL -1 /* no AIOP or channel exists */ +#define AIOPID_0001 0x0001 /* AIOP release 1 */ -#define NULLDEV -1 /* identifies non-existant device */ -#define NULLCTL -1 /* identifies non-existant controller */ -#define NULLCTLPTR (CONTROLLER_T *)0 /* identifies non-existant controller */ -#define NULLAIOP -1 /* identifies non-existant AIOP */ -#define NULLCHAN -1 /* identifies non-existant channel */ +#define NULLDEV -1 /* identifies non-existant device */ +#define NULLCTL -1 /* identifies non-existant controller */ +#define NULLCTLPTR (CONTROLLER_T *)0 /* identifies non-existant controller */ +#define NULLAIOP -1 /* identifies non-existant AIOP */ +#define NULLCHAN -1 /* identifies non-existant channel */ /************************************************************************ Global Register Offsets - Direct Access - Fixed values ************************************************************************/ -#define _CMD_REG 0x38 /* Command Register 8 Write */ -#define _INT_CHAN 0x39 /* Interrupt Channel Register 8 Read */ -#define _INT_MASK 0x3A /* Interrupt Mask Register 8 Read / Write */ -#define _UNUSED 0x3B /* Unused 8 */ -#define _INDX_ADDR 0x3C /* Index Register Address 16 Write */ -#define _INDX_DATA 0x3E /* Index Register Data 8/16 Read / Write */ +#define _CMD_REG 0x38 /* Command Register 8 Write */ +#define _INT_CHAN 0x39 /* Interrupt Channel Register 8 Read */ +#define _INT_MASK 0x3A /* Interrupt Mask Register 8 Read / Write */ +#define _UNUSED 0x3B /* Unused 8 */ +#define _INDX_ADDR 0x3C /* Index Register Address 16 Write */ +#define _INDX_DATA 0x3E /* Index Register Data 8/16 Read / Write */ /************************************************************************ Channel Register Offsets for 1st channel in AIOP - Direct Access ************************************************************************/ -#define _TD0 0x00 /* Transmit Data 16 Write */ -#define _RD0 0x00 /* Receive Data 16 Read */ -#define _CHN_STAT0 0x20 /* Channel Status 8/16 Read / Write */ -#define _FIFO_CNT0 0x10 /* Transmit/Receive FIFO Count 16 Read */ -#define _INT_ID0 0x30 /* Interrupt Identification 8 Read */ +#define _TD0 0x00 /* Transmit Data 16 Write */ +#define _RD0 0x00 /* Receive Data 16 Read */ +#define _CHN_STAT0 0x20 /* Channel Status 8/16 Read / Write */ +#define _FIFO_CNT0 0x10 /* Transmit/Receive FIFO Count 16 Read */ +#define _INT_ID0 0x30 /* Interrupt Identification 8 Read */ /************************************************************************ Tx Control Register Offsets - Indexed - External - Fixed ************************************************************************/ -#define _TX_ENBLS 0x980 /* Tx Processor Enables Register 8 Read / Write */ -#define _TXCMP1 0x988 /* Transmit Compare Value #1 8 Read / Write */ -#define _TXCMP2 0x989 /* Transmit Compare Value #2 8 Read / Write */ -#define _TXREP1B1 0x98A /* Tx Replace Value #1 - Byte 1 8 Read / Write */ -#define _TXREP1B2 0x98B /* Tx Replace Value #1 - Byte 2 8 Read / Write */ -#define _TXREP2 0x98C /* Transmit Replace Value #2 8 Read / Write */ +#define _TX_ENBLS 0x980 /* Tx Processor Enables Register 8 Read / Write */ +#define _TXCMP1 0x988 /* Transmit Compare Value #1 8 Read / Write */ +#define _TXCMP2 0x989 /* Transmit Compare Value #2 8 Read / Write */ +#define _TXREP1B1 0x98A /* Tx Replace Value #1 - Byte 1 8 Read / Write */ +#define _TXREP1B2 0x98B /* Tx Replace Value #1 - Byte 2 8 Read / Write */ +#define _TXREP2 0x98C /* Transmit Replace Value #2 8 Read / Write */ /************************************************************************ Memory Controller Register Offsets - Indexed - External - Fixed ************************************************************************/ -#define _RX_FIFO 0x000 /* Rx FIFO */ -#define _TX_FIFO 0x800 /* Tx FIFO */ -#define _RXF_OUTP 0x990 /* Rx FIFO OUT pointer 16 Read / Write */ -#define _RXF_INP 0x992 /* Rx FIFO IN pointer 16 Read / Write */ -#define _TXF_OUTP 0x994 /* Tx FIFO OUT pointer 8 Read / Write */ -#define _TXF_INP 0x995 /* Tx FIFO IN pointer 8 Read / Write */ -#define _TXP_CNT 0x996 /* Tx Priority Count 8 Read / Write */ -#define _TXP_PNTR 0x997 /* Tx Priority Pointer 8 Read / Write */ - -#define PRI_PEND 0x80 /* Priority data pending (bit7, Tx pri cnt) */ -#define TXFIFO_SIZE 255 /* size of Tx FIFO */ -#define RXFIFO_SIZE 1023 /* size of Rx FIFO */ +#define _RX_FIFO 0x000 /* Rx FIFO */ +#define _TX_FIFO 0x800 /* Tx FIFO */ +#define _RXF_OUTP 0x990 /* Rx FIFO OUT pointer 16 Read / Write */ +#define _RXF_INP 0x992 /* Rx FIFO IN pointer 16 Read / Write */ +#define _TXF_OUTP 0x994 /* Tx FIFO OUT pointer 8 Read / Write */ +#define _TXF_INP 0x995 /* Tx FIFO IN pointer 8 Read / Write */ +#define _TXP_CNT 0x996 /* Tx Priority Count 8 Read / Write */ +#define _TXP_PNTR 0x997 /* Tx Priority Pointer 8 Read / Write */ + +#define PRI_PEND 0x80 /* Priority data pending (bit7, Tx pri cnt) */ +#define TXFIFO_SIZE 255 /* size of Tx FIFO */ +#define RXFIFO_SIZE 1023 /* size of Rx FIFO */ /************************************************************************ Tx Priority Buffer - Indexed - External - Fixed ************************************************************************/ -#define _TXP_BUF 0x9C0 /* Tx Priority Buffer 32 Bytes Read / Write */ -#define TXP_SIZE 0x20 /* 32 bytes */ +#define _TXP_BUF 0x9C0 /* Tx Priority Buffer 32 Bytes Read / Write */ +#define TXP_SIZE 0x20 /* 32 bytes */ /************************************************************************ Channel Register Offsets - Indexed - Internal - Fixed ************************************************************************/ -#define _TX_CTRL 0xFF0 /* Transmit Control 16 Write */ -#define _RX_CTRL 0xFF2 /* Receive Control 8 Write */ -#define _BAUD 0xFF4 /* Baud Rate 16 Write */ -#define _CLK_PRE 0xFF6 /* Clock Prescaler 8 Write */ - -#if 0 -#define CLOCK_PRESC 0x14 /* ?????? new mod 4 (divide by 5) prescale */ - -#define BRD50 9215 -#define BRD75 6143 -#define BRD110 4188 -#define BRD134 3438 -#define BRD150 3071 -#define BRD200 2303 -#define BRD300 1535 -#define BRD600 767 -#define BRD1200 383 -#define BRD1800 255 -#define BRD2000 229 -#define BRD2400 191 -#define BRD3600 127 -#define BRD4800 95 -#define BRD7200 63 -#define BRD9600 47 -#define BRD14400 31 -#define BRD19200 23 -#define BRD38400 11 -#define BRD57600 7 -#define BRD76800 5 -#define BRD115200 3 -#define BRD230400 1 -#define BRD460800 0 -#endif - -#if 0 - -/* Old clock prescale definition and baud rates associated with it */ - -#define CLOCK_PRESC 0x19 /* mod 9 (divide by 10) prescale */ -#define BRD50 4607 -#define BRD75 3071 -#define BRD110 2094 -#define BRD134 1712 -#define BRD150 1535 -#define BRD200 1151 -#define BRD300 767 -#define BRD600 383 -#define BRD1200 191 -#define BRD1800 127 -#define BRD2000 114 -#define BRD2400 95 -#define BRD3600 64 -#define BRD4800 47 -#define BRD7200 31 -#define BRD9600 23 -#define BRD14400 15 -#define BRD19200 11 -#define BRD38400 5 -#define BRD57600 3 -#define BRD76800 2 -#define BRD115200 1 -#define BRD230400 0 - -#endif - -#define STMBREAK 0x08 /* BREAK */ -#define STMFRAME 0x04 /* framing error */ -#define STMRCVROVR 0x02 /* receiver over run error */ -#define STMPARITY 0x01 /* parity error */ +#define _TX_CTRL 0xFF0 /* Transmit Control 16 Write */ +#define _RX_CTRL 0xFF2 /* Receive Control 8 Write */ +#define _BAUD 0xFF4 /* Baud Rate 16 Write */ +#define _CLK_PRE 0xFF6 /* Clock Prescaler 8 Write */ + +#define STMBREAK 0x08 /* BREAK */ +#define STMFRAME 0x04 /* framing error */ +#define STMRCVROVR 0x02 /* receiver over run error */ +#define STMPARITY 0x01 /* parity error */ #define STMERROR (STMBREAK | STMFRAME | STMPARITY) -#define STMBREAKH 0x800 /* BREAK */ -#define STMFRAMEH 0x400 /* framing error */ -#define STMRCVROVRH 0x200 /* receiver over run error */ -#define STMPARITYH 0x100 /* parity error */ +#define STMBREAKH 0x800 /* BREAK */ +#define STMFRAMEH 0x400 /* framing error */ +#define STMRCVROVRH 0x200 /* receiver over run error */ +#define STMPARITYH 0x100 /* parity error */ #define STMERRORH (STMBREAKH | STMFRAMEH | STMPARITYH) -#define CTS_ACT 0x20 /* CTS input asserted */ -#define DSR_ACT 0x10 /* DSR input asserted */ -#define CD_ACT 0x08 /* CD input asserted */ -#define TXFIFOMT 0x04 /* Tx FIFO is empty */ -#define TXSHRMT 0x02 /* Tx shift register is empty */ -#define RDA 0x01 /* Rx data available */ -#define DRAINED (TXFIFOMT | TXSHRMT) /* indicates Tx is drained */ - -#define STATMODE 0x8000 /* status mode enable bit */ -#define RXFOVERFL 0x2000 /* receive FIFO overflow */ -#define RX2MATCH 0x1000 /* receive compare byte 2 match */ -#define RX1MATCH 0x0800 /* receive compare byte 1 match */ -#define RXBREAK 0x0400 /* received BREAK */ -#define RXFRAME 0x0200 /* received framing error */ -#define RXPARITY 0x0100 /* received parity error */ +#define CTS_ACT 0x20 /* CTS input asserted */ +#define DSR_ACT 0x10 /* DSR input asserted */ +#define CD_ACT 0x08 /* CD input asserted */ +#define TXFIFOMT 0x04 /* Tx FIFO is empty */ +#define TXSHRMT 0x02 /* Tx shift register is empty */ +#define RDA 0x01 /* Rx data available */ +#define DRAINED (TXFIFOMT | TXSHRMT) /* indicates Tx is drained */ + +#define STATMODE 0x8000 /* status mode enable bit */ +#define RXFOVERFL 0x2000 /* receive FIFO overflow */ +#define RX2MATCH 0x1000 /* receive compare byte 2 match */ +#define RX1MATCH 0x0800 /* receive compare byte 1 match */ +#define RXBREAK 0x0400 /* received BREAK */ +#define RXFRAME 0x0200 /* received framing error */ +#define RXPARITY 0x0100 /* received parity error */ #define STATERROR (RXBREAK | RXFRAME | RXPARITY) -#define CTSFC_EN 0x80 /* CTS flow control enable bit */ -#define RTSTOG_EN 0x40 /* RTS toggle enable bit */ -#define TXINT_EN 0x10 /* transmit interrupt enable */ -#define STOP2 0x08 /* enable 2 stop bits (0 = 1 stop) */ -#define PARITY_EN 0x04 /* enable parity (0 = no parity) */ -#define EVEN_PAR 0x02 /* even parity (0 = odd parity) */ -#define DATA8BIT 0x01 /* 8 bit data (0 = 7 bit data) */ - -#define SETBREAK 0x10 /* send break condition (must clear) */ -#define LOCALLOOP 0x08 /* local loopback set for test */ -#define SET_DTR 0x04 /* assert DTR */ -#define SET_RTS 0x02 /* assert RTS */ -#define TX_ENABLE 0x01 /* enable transmitter */ - -#define RTSFC_EN 0x40 /* RTS flow control enable */ -#define RXPROC_EN 0x20 /* receive processor enable */ -#define TRIG_NO 0x00 /* Rx FIFO trigger level 0 (no trigger) */ -#define TRIG_1 0x08 /* trigger level 1 char */ -#define TRIG_1_2 0x10 /* trigger level 1/2 */ -#define TRIG_7_8 0x18 /* trigger level 7/8 */ -#define TRIG_MASK 0x18 /* trigger level mask */ -#define SRCINT_EN 0x04 /* special Rx condition interrupt enable */ -#define RXINT_EN 0x02 /* Rx interrupt enable */ -#define MCINT_EN 0x01 /* modem change interrupt enable */ - -#define RXF_TRIG 0x20 /* Rx FIFO trigger level interrupt */ -#define TXFIFO_MT 0x10 /* Tx FIFO empty interrupt */ -#define SRC_INT 0x08 /* special receive condition interrupt */ -#define DELTA_CD 0x04 /* CD change interrupt */ -#define DELTA_CTS 0x02 /* CTS change interrupt */ -#define DELTA_DSR 0x01 /* DSR change interrupt */ - -#define REP1W2_EN 0x10 /* replace byte 1 with 2 bytes enable */ -#define IGN2_EN 0x08 /* ignore byte 2 enable */ -#define IGN1_EN 0x04 /* ignore byte 1 enable */ -#define COMP2_EN 0x02 /* compare byte 2 enable */ -#define COMP1_EN 0x01 /* compare byte 1 enable */ - -#define RESET_ALL 0x80 /* reset AIOP (all channels) */ -#define TXOVERIDE 0x40 /* Transmit software off override */ -#define RESETUART 0x20 /* reset channel's UART */ -#define RESTXFCNT 0x10 /* reset channel's Tx FIFO count register */ -#define RESRXFCNT 0x08 /* reset channel's Rx FIFO count register */ - -#define INTSTAT0 0x01 /* AIOP 0 interrupt status */ -#define INTSTAT1 0x02 /* AIOP 1 interrupt status */ -#define INTSTAT2 0x04 /* AIOP 2 interrupt status */ -#define INTSTAT3 0x08 /* AIOP 3 interrupt status */ +#define CTSFC_EN 0x80 /* CTS flow control enable bit */ +#define RTSTOG_EN 0x40 /* RTS toggle enable bit */ +#define TXINT_EN 0x10 /* transmit interrupt enable */ +#define STOP2 0x08 /* enable 2 stop bits (0 = 1 stop) */ +#define PARITY_EN 0x04 /* enable parity (0 = no parity) */ +#define EVEN_PAR 0x02 /* even parity (0 = odd parity) */ +#define DATA8BIT 0x01 /* 8 bit data (0 = 7 bit data) */ + +#define SETBREAK 0x10 /* send break condition (must clear) */ +#define LOCALLOOP 0x08 /* local loopback set for test */ +#define SET_DTR 0x04 /* assert DTR */ +#define SET_RTS 0x02 /* assert RTS */ +#define TX_ENABLE 0x01 /* enable transmitter */ + +#define RTSFC_EN 0x40 /* RTS flow control enable */ +#define RXPROC_EN 0x20 /* receive processor enable */ +#define TRIG_NO 0x00 /* Rx FIFO trigger level 0 (no trigger) */ +#define TRIG_1 0x08 /* trigger level 1 char */ +#define TRIG_1_2 0x10 /* trigger level 1/2 */ +#define TRIG_7_8 0x18 /* trigger level 7/8 */ +#define TRIG_MASK 0x18 /* trigger level mask */ +#define SRCINT_EN 0x04 /* special Rx condition interrupt enable */ +#define RXINT_EN 0x02 /* Rx interrupt enable */ +#define MCINT_EN 0x01 /* modem change interrupt enable */ + +#define RXF_TRIG 0x20 /* Rx FIFO trigger level interrupt */ +#define TXFIFO_MT 0x10 /* Tx FIFO empty interrupt */ +#define SRC_INT 0x08 /* special receive condition interrupt */ +#define DELTA_CD 0x04 /* CD change interrupt */ +#define DELTA_CTS 0x02 /* CTS change interrupt */ +#define DELTA_DSR 0x01 /* DSR change interrupt */ + +#define REP1W2_EN 0x10 /* replace byte 1 with 2 bytes enable */ +#define IGN2_EN 0x08 /* ignore byte 2 enable */ +#define IGN1_EN 0x04 /* ignore byte 1 enable */ +#define COMP2_EN 0x02 /* compare byte 2 enable */ +#define COMP1_EN 0x01 /* compare byte 1 enable */ + +#define RESET_ALL 0x80 /* reset AIOP (all channels) */ +#define TXOVERIDE 0x40 /* Transmit software off override */ +#define RESETUART 0x20 /* reset channel's UART */ +#define RESTXFCNT 0x10 /* reset channel's Tx FIFO count register */ +#define RESRXFCNT 0x08 /* reset channel's Rx FIFO count register */ + +#define INTSTAT0 0x01 /* AIOP 0 interrupt status */ +#define INTSTAT1 0x02 /* AIOP 1 interrupt status */ +#define INTSTAT2 0x04 /* AIOP 2 interrupt status */ +#define INTSTAT3 0x08 /* AIOP 3 interrupt status */ -#define INTR_EN 0x08 /* allow interrupts to host */ -#define INT_STROB 0x04 /* strobe and clear interrupt line (EOI) */ +#define INTR_EN 0x08 /* allow interrupts to host */ +#define INT_STROB 0x04 /* strobe and clear interrupt line (EOI) */ /************************************************************************** MUDBAC remapped for PCI @@ -299,14 +284,22 @@ #define _CFG_INT_PCI 0x40 #define _PCI_INT_FUNC 0x3A -#define PCI_STROB 0x2000 /* bit 13 of int aiop register */ -#define INTR_EN_PCI 0x0010 /* allow interrupts to host */ - +#define PCI_STROB 0x2000 /* bit 13 of int aiop register */ +#define INTR_EN_PCI 0x0010 /* allow interrupts to host */ -#define CHAN3_EN 0x08 /* enable AIOP 3 */ -#define CHAN2_EN 0x04 /* enable AIOP 2 */ -#define CHAN1_EN 0x02 /* enable AIOP 1 */ -#define CHAN0_EN 0x01 /* enable AIOP 0 */ +/* + * Definitions for Universal PCI board registers + */ +#define _PCI_9030_INT_CTRL 0x4c /* Offsets from BAR1 */ +#define _PCI_9030_GPIO_CTRL 0x54 +#define PCI_INT_CTRL_AIOP 0x0001 +#define PCI_GPIO_CTRL_8PORT 0x4000 +#define _PCI_9030_RING_IND 0xc0 /* Offsets from BAR1 */ + +#define CHAN3_EN 0x08 /* enable AIOP 3 */ +#define CHAN2_EN 0x04 /* enable AIOP 2 */ +#define CHAN1_EN 0x02 /* enable AIOP 1 */ +#define CHAN0_EN 0x01 /* enable AIOP 0 */ #define FREQ_DIS 0x00 #define FREQ_274HZ 0x60 #define FREQ_137HZ 0x50 @@ -314,75 +307,110 @@ #define FREQ_34HZ 0x30 #define FREQ_17HZ 0x20 #define FREQ_9HZ 0x10 -#define PERIODIC_ONLY 0x80 /* only PERIODIC interrupt */ +#define PERIODIC_ONLY 0x80 /* only PERIODIC interrupt */ -#define CHANINT_EN 0x0100 /* flags to enable/disable channel ints */ +#define CHANINT_EN 0x0100 /* flags to enable/disable channel ints */ #define RDATASIZE 72 #define RREGDATASIZE 52 +/* + * AIOP interrupt bits for ISA/PCI boards and UPCI boards. + */ +#define AIOP_INTR_BIT_0 0x0001 +#define AIOP_INTR_BIT_1 0x0002 +#define AIOP_INTR_BIT_2 0x0004 +#define AIOP_INTR_BIT_3 0x0008 + +#define AIOP_INTR_BITS ( \ + AIOP_INTR_BIT_0 \ + | AIOP_INTR_BIT_1 \ + | AIOP_INTR_BIT_2 \ + | AIOP_INTR_BIT_3) + +#define UPCI_AIOP_INTR_BIT_0 0x0004 +#define UPCI_AIOP_INTR_BIT_1 0x0020 +#define UPCI_AIOP_INTR_BIT_2 0x0100 +#define UPCI_AIOP_INTR_BIT_3 0x0800 + +#define UPCI_AIOP_INTR_BITS ( \ + UPCI_AIOP_INTR_BIT_0 \ + | UPCI_AIOP_INTR_BIT_1 \ + | UPCI_AIOP_INTR_BIT_2 \ + | UPCI_AIOP_INTR_BIT_3) + /* Controller level information structure */ -typedef struct -{ - int CtlID; - int CtlNum; - int BusType; - WordIO_t PCIIO; - ByteIO_t MBaseIO; - ByteIO_t MReg1IO; - ByteIO_t MReg2IO; - ByteIO_t MReg3IO; - Byte_t MReg2; - Byte_t MReg3; - int NumAiop; - WordIO_t AiopIO[AIOP_CTL_SIZE]; - ByteIO_t AiopIntChanIO[AIOP_CTL_SIZE]; - int AiopID[AIOP_CTL_SIZE]; - int AiopNumChan[AIOP_CTL_SIZE]; +typedef struct { + int CtlID; + int CtlNum; + int BusType; + int boardType; + int isUPCI; + WordIO_t PCIIO; + WordIO_t PCIIO2; + ByteIO_t MBaseIO; + ByteIO_t MReg1IO; + ByteIO_t MReg2IO; + ByteIO_t MReg3IO; + Byte_t MReg2; + Byte_t MReg3; + int NumAiop; + int AltChanRingIndicator; + ByteIO_t UPCIRingInd; + WordIO_t AiopIO[AIOP_CTL_SIZE]; + ByteIO_t AiopIntChanIO[AIOP_CTL_SIZE]; + int AiopID[AIOP_CTL_SIZE]; + int AiopNumChan[AIOP_CTL_SIZE]; + Word_t *AiopIntrBits; } CONTROLLER_T; typedef CONTROLLER_T CONTROLLER_t; /* Channel level information structure */ -typedef struct -{ - CONTROLLER_T *CtlP; - int AiopNum; - int ChanID; - int ChanNum; - - ByteIO_t Cmd; - ByteIO_t IntChan; - ByteIO_t IntMask; - DWordIO_t IndexAddr; - WordIO_t IndexData; - - WordIO_t TxRxData; - WordIO_t ChanStat; - WordIO_t TxRxCount; - ByteIO_t IntID; - - Word_t TxFIFO; - Word_t TxFIFOPtrs; - Word_t RxFIFO; - Word_t RxFIFOPtrs; - Word_t TxPrioCnt; - Word_t TxPrioPtr; - Word_t TxPrioBuf; - - Byte_t R[RREGDATASIZE]; - - Byte_t BaudDiv[4]; - Byte_t TxControl[4]; - Byte_t RxControl[4]; - Byte_t TxEnables[4]; - Byte_t TxCompare[4]; - Byte_t TxReplace1[4]; - Byte_t TxReplace2[4]; +typedef struct { + CONTROLLER_T *CtlP; + int AiopNum; + int ChanID; + int ChanNum; + int rtsToggle; + + ByteIO_t Cmd; + ByteIO_t IntChan; + ByteIO_t IntMask; + DWordIO_t IndexAddr; + WordIO_t IndexData; + + WordIO_t TxRxData; + WordIO_t ChanStat; + WordIO_t TxRxCount; + ByteIO_t IntID; + + Word_t TxFIFO; + Word_t TxFIFOPtrs; + Word_t RxFIFO; + Word_t RxFIFOPtrs; + Word_t TxPrioCnt; + Word_t TxPrioPtr; + Word_t TxPrioBuf; + + Byte_t R[RREGDATASIZE]; + + Byte_t BaudDiv[4]; + Byte_t TxControl[4]; + Byte_t RxControl[4]; + Byte_t TxEnables[4]; + Byte_t TxCompare[4]; + Byte_t TxReplace1[4]; + Byte_t TxReplace2[4]; } CHANNEL_T; typedef CHANNEL_T CHANNEL_t; -typedef CHANNEL_T * CHANPTR_T; +typedef CHANNEL_T *CHANPTR_T; + +#define InterfaceModeRS232 0x00 +#define InterfaceModeRS422 0x08 +#define InterfaceModeRS485 0x10 +#define InterfaceModeRS232T 0x18 /*************************************************************************** Function: sClrBreak @@ -391,10 +419,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sClrBreak(ChP) \ -{ \ +do { \ (ChP)->TxControl[3] &= ~SETBREAK; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sClrDTR @@ -403,10 +431,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sClrDTR(ChP) \ -{ \ +do { \ (ChP)->TxControl[3] &= ~SET_DTR; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sClrRTS @@ -415,10 +443,11 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sClrRTS(ChP) \ -{ \ +do { \ + if ((ChP)->rtsToggle) break; \ (ChP)->TxControl[3] &= ~SET_RTS; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sClrTxXOFF @@ -427,10 +456,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sClrTxXOFF(ChP) \ -{ \ +do { \ sOutB((ChP)->Cmd,TXOVERIDE | (Byte_t)(ChP)->ChanNum); \ sOutB((ChP)->Cmd,(Byte_t)(ChP)->ChanNum); \ -} +} while (0) /*************************************************************************** Function: sCtlNumToCtlPtr @@ -452,10 +481,22 @@ /*************************************************************************** Function: sPCIControllerEOI Purpose: Strobe the PCI End Of Interrupt bit. + For the UPCI boards, toggle the AIOP interrupt enable bit + (this was taken from the Windows driver). Call: sPCIControllerEOI(CtlP) CONTROLLER_T *CtlP; Ptr to controller structure */ -#define sPCIControllerEOI(CTLP) sOutW((CTLP)->PCIIO, PCI_STROB) +#define sPCIControllerEOI(CTLP) \ +do { \ + if ((CTLP)->isUPCI) { \ + Word_t w = sInW((CTLP)->PCIIO); \ + sOutW((CTLP)->PCIIO, (w ^ PCI_INT_CTRL_AIOP)); \ + sOutW((CTLP)->PCIIO, w); \ + } \ + else { \ + sOutW((CTLP)->PCIIO, PCI_STROB); \ + } \ +} while (0) /*************************************************************************** Function: sDisAiop @@ -465,10 +506,10 @@ int AiopNum; Number of AIOP on controller */ #define sDisAiop(CTLP,AIOPNUM) \ -{ \ +do { \ (CTLP)->MReg3 &= sBitMapClrTbl[AIOPNUM]; \ sOutB((CTLP)->MReg3IO,(CTLP)->MReg3); \ -} +} while (0) /*************************************************************************** Function: sDisCTSFlowCtl @@ -477,10 +518,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sDisCTSFlowCtl(ChP) \ -{ \ +do { \ (ChP)->TxControl[2] &= ~CTSFC_EN; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sDisIXANY @@ -489,10 +530,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sDisIXANY(ChP) \ -{ \ +do { \ (ChP)->R[0x0e] = 0x86; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x0c]); \ -} +} while (0) /*************************************************************************** Function: DisParity @@ -503,10 +544,23 @@ sDisParity(), sSetOddParity(), and sSetEvenParity(). */ #define sDisParity(ChP) \ -{ \ +do { \ (ChP)->TxControl[2] &= ~PARITY_EN; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) + +/*************************************************************************** +Function: sDisRTSToggle +Purpose: Disable RTS toggle +Call: sDisRTSToggle(ChP) + CHANNEL_T *ChP; Ptr to channel structure +*/ +#define sDisRTSToggle(ChP) \ +do { \ + (ChP)->TxControl[2] &= ~RTSTOG_EN; \ + sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ + (ChP)->rtsToggle = 0; \ +} while (0) /*************************************************************************** Function: sDisRxFIFO @@ -515,10 +569,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sDisRxFIFO(ChP) \ -{ \ +do { \ (ChP)->R[0x32] = 0x0a; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x30]); \ -} +} while (0) /*************************************************************************** Function: sDisRxStatusMode @@ -542,10 +596,10 @@ and transmit shift register going completely empty. */ #define sDisTransmit(ChP) \ -{ \ +do { \ (ChP)->TxControl[3] &= ~TX_ENABLE; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sDisTxSoftFlowCtl @@ -554,10 +608,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sDisTxSoftFlowCtl(ChP) \ -{ \ +do { \ (ChP)->R[0x06] = 0x8a; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x04]); \ -} +} while (0) /*************************************************************************** Function: sEnAiop @@ -567,10 +621,10 @@ int AiopNum; Number of AIOP on controller */ #define sEnAiop(CTLP,AIOPNUM) \ -{ \ +do { \ (CTLP)->MReg3 |= sBitMapSetTbl[AIOPNUM]; \ sOutB((CTLP)->MReg3IO,(CTLP)->MReg3); \ -} +} while (0) /*************************************************************************** Function: sEnCTSFlowCtl @@ -579,10 +633,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sEnCTSFlowCtl(ChP) \ -{ \ +do { \ (ChP)->TxControl[2] |= CTSFC_EN; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sEnIXANY @@ -591,10 +645,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sEnIXANY(ChP) \ -{ \ +do { \ (ChP)->R[0x0e] = 0x21; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x0c]); \ -} +} while (0) /*************************************************************************** Function: EnParity @@ -608,10 +662,28 @@ functions sSetOddParity() or sSetEvenParity(). */ #define sEnParity(ChP) \ -{ \ +do { \ (ChP)->TxControl[2] |= PARITY_EN; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) + +/*************************************************************************** +Function: sEnRTSToggle +Purpose: Enable RTS toggle +Call: sEnRTSToggle(ChP) + CHANNEL_T *ChP; Ptr to channel structure +Comments: This function will disable RTS flow control and clear the RTS + line to allow operation of RTS toggle. +*/ +#define sEnRTSToggle(ChP) \ +do { \ + (ChP)->RxControl[2] &= ~RTSFC_EN; \ + sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->RxControl[0]); \ + (ChP)->TxControl[2] |= RTSTOG_EN; \ + (ChP)->TxControl[3] &= ~SET_RTS; \ + sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ + (ChP)->rtsToggle = 1; \ +} while (0) /*************************************************************************** Function: sEnRxFIFO @@ -620,10 +692,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sEnRxFIFO(ChP) \ -{ \ +do { \ (ChP)->R[0x32] = 0x08; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x30]); \ -} +} while (0) /*************************************************************************** Function: sEnRxProcessor @@ -641,10 +713,10 @@ microcode has been downloaded. */ #define sEnRxProcessor(ChP) \ -{ \ +do { \ (ChP)->RxControl[2] |= RXPROC_EN; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->RxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sEnRxStatusMode @@ -665,10 +737,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sEnTransmit(ChP) \ -{ \ +do { \ (ChP)->TxControl[3] |= TX_ENABLE; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sEnTxSoftFlowCtl @@ -677,10 +749,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sEnTxSoftFlowCtl(ChP) \ -{ \ +do { \ (ChP)->R[0x06] = 0xc5; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x04]); \ -} +} while (0) /*************************************************************************** Function: sGetAiopIntStatus @@ -774,6 +846,18 @@ */ #define sGetChanStatusLo(ChP) sInB((ByteIO_t)(ChP)->ChanStat) +/********************************************************************** + * Get RI status of channel + * Defined as a function in rocket.c -aes + */ +#if 0 +#define sGetChanRI(ChP) ((ChP)->CtlP->AltChanRingIndicator ? \ + (sInB((ByteIO_t)((ChP)->ChanStat+8)) & DSR_ACT) : \ + (((ChP)->CtlP->boardType == ROCKET_TYPE_PC104) ? \ + (!(sInB((ChP)->CtlP->AiopIO[3]) & sBitMapSetTbl[(ChP)->ChanNum])) : \ + 0)) +#endif + /*************************************************************************** Function: sGetControllerIntStatus Purpose: Get the controller interrupt status @@ -798,7 +882,10 @@ was generated from periodic. If a bit is set the AIOP is interrupting. */ -#define sPCIGetControllerIntStatus(CTLP) ((sInW((CTLP)->PCIIO) >> 8) & 0x1f) +#define sPCIGetControllerIntStatus(CTLP) \ + ((CTLP)->isUPCI ? \ + (sInW((CTLP)->PCIIO2) & UPCI_AIOP_INTR_BITS) : \ + ((sInW((CTLP)->PCIIO) >> 8) & AIOP_INTR_BITS)) /*************************************************************************** @@ -834,7 +921,7 @@ /*************************************************************************** Function: sInitChanDefaults -Purpose: Initialize a channel structure to its default state. +Purpose: Initialize a channel structure to it's default state. Call: sInitChanDefaults(ChP) CHANNEL_T *ChP; Ptr to the channel structure Comments: This function must be called once for every channel structure @@ -842,12 +929,12 @@ */ #define sInitChanDefaults(ChP) \ -{ \ +do { \ (ChP)->CtlP = NULLCTLPTR; \ (ChP)->AiopNum = NULLAIOP; \ (ChP)->ChanID = AIOPID_NULL; \ (ChP)->ChanNum = NULLCHAN; \ -} +} while (0) /*************************************************************************** Function: sResetAiopByNum @@ -857,10 +944,10 @@ AIOPNUM; AIOP index */ #define sResetAiopByNum(CTLP,AIOPNUM) \ -{ \ +do { \ sOutB((CTLP)->AiopIO[(AIOPNUM)]+_CMD_REG,RESET_ALL); \ sOutB((CTLP)->AiopIO[(AIOPNUM)]+_CMD_REG,0x0); \ -} +} while (0) /*************************************************************************** Function: sSendBreak @@ -869,10 +956,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sSendBreak(ChP) \ -{ \ +do { \ (ChP)->TxControl[3] |= SETBREAK; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sSetBaud @@ -882,11 +969,11 @@ Word_t Divisor; 16 bit baud rate divisor for channel */ #define sSetBaud(ChP,DIVISOR) \ -{ \ +do { \ (ChP)->BaudDiv[2] = (Byte_t)(DIVISOR); \ (ChP)->BaudDiv[3] = (Byte_t)((DIVISOR) >> 8); \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->BaudDiv[0]); \ -} +} while (0) /*************************************************************************** Function: sSetData7 @@ -895,10 +982,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sSetData7(ChP) \ -{ \ +do { \ (ChP)->TxControl[2] &= ~DATA8BIT; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sSetData8 @@ -907,10 +994,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sSetData8(ChP) \ -{ \ +do { \ (ChP)->TxControl[2] |= DATA8BIT; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sSetDTR @@ -919,10 +1006,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sSetDTR(ChP) \ -{ \ +do { \ (ChP)->TxControl[3] |= SET_DTR; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sSetEvenParity @@ -936,10 +1023,10 @@ sEnParity(). */ #define sSetEvenParity(ChP) \ -{ \ +do { \ (ChP)->TxControl[2] |= EVEN_PAR; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sSetOddParity @@ -953,10 +1040,10 @@ sEnParity(). */ #define sSetOddParity(ChP) \ -{ \ +do { \ (ChP)->TxControl[2] &= ~EVEN_PAR; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sSetRTS @@ -965,10 +1052,11 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sSetRTS(ChP) \ -{ \ +do { \ + if ((ChP)->rtsToggle) break; \ (ChP)->TxControl[3] |= SET_RTS; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sSetRxTrigger @@ -990,11 +1078,11 @@ */ #define sSetRxTrigger(ChP,LEVEL) \ -{ \ +do { \ (ChP)->RxControl[2] &= ~TRIG_MASK; \ (ChP)->RxControl[2] |= LEVEL; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->RxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sSetStop1 @@ -1003,10 +1091,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sSetStop1(ChP) \ -{ \ +do { \ (ChP)->TxControl[2] &= ~STOP2; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sSetStop2 @@ -1015,10 +1103,10 @@ CHANNEL_T *ChP; Ptr to channel structure */ #define sSetStop2(ChP) \ -{ \ +do { \ (ChP)->TxControl[2] |= STOP2; \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->TxControl[0]); \ -} +} while (0) /*************************************************************************** Function: sSetTxXOFFChar @@ -1028,10 +1116,10 @@ Byte_t Ch; The value to set the Tx XOFF character to */ #define sSetTxXOFFChar(ChP,CH) \ -{ \ +do { \ (ChP)->R[0x07] = (CH); \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x04]); \ -} +} while (0) /*************************************************************************** Function: sSetTxXONChar @@ -1041,10 +1129,10 @@ Byte_t Ch; The value to set the Tx XON character to */ #define sSetTxXONChar(ChP,CH) \ -{ \ +do { \ (ChP)->R[0x0b] = (CH); \ sOutDW((ChP)->IndexAddr,*(DWord_t *)&(ChP)->R[0x08]); \ -} +} while (0) /*************************************************************************** Function: sStartRxProcessor @@ -1069,37 +1157,38 @@ */ #define sWriteTxByte(IO,DATA) sOutB(IO,DATA) -int sInitController( CONTROLLER_T *CtlP, - int CtlNum, - ByteIO_t MudbacIO, - ByteIO_t *AiopIOList, - int AiopIOListSize, - int IRQNum, - Byte_t Frequency, - int PeriodicOnly); - -int sPCIInitController( CONTROLLER_T *CtlP, - int CtlNum, - ByteIO_t *AiopIOList, - int AiopIOListSize, - int IRQNum, - Byte_t Frequency, - int PeriodicOnly); +int sInitController(CONTROLLER_T * CtlP, + int CtlNum, + ByteIO_t MudbacIO, + ByteIO_t * AiopIOList, + int AiopIOListSize, + int IRQNum, Byte_t Frequency, int PeriodicOnly); + +int sPCIInitController(CONTROLLER_T * CtlP, + int CtlNum, + ByteIO_t * AiopIOList, + int AiopIOListSize, + WordIO_t ConfigIO, + int IRQNum, + Byte_t Frequency, + int PeriodicOnly, + int altChanRingIndicator, int UPCIRingInd); int sReadAiopID(ByteIO_t io); int sReadAiopNumChan(WordIO_t io); -int sInitChan( CONTROLLER_T *CtlP, - CHANNEL_T *ChP, - int AiopNum, - int ChanNum); -Byte_t sGetRxErrStatus(CHANNEL_T *ChP); -void sStopRxProcessor(CHANNEL_T *ChP); -void sStopSWInFlowCtl(CHANNEL_T *ChP); -void sFlushRxFIFO(CHANNEL_T *ChP); -void sFlushTxFIFO(CHANNEL_T *ChP); -int sWriteTxPrioByte(CHANNEL_T *ChP, Byte_t Data); -void sEnInterrupts(CHANNEL_T *ChP,Word_t Flags); -void sDisInterrupts(CHANNEL_T *ChP,Word_t Flags); +int sInitChan(CONTROLLER_T * CtlP, + CHANNEL_T * ChP, int AiopNum, int ChanNum); +Byte_t sGetRxErrStatus(CHANNEL_T * ChP); +void sStopRxProcessor(CHANNEL_T * ChP); +void sStopSWInFlowCtl(CHANNEL_T * ChP); +void sFlushRxFIFO(CHANNEL_T * ChP); +void sFlushTxFIFO(CHANNEL_T * ChP); +int sWriteTxPrioByte(CHANNEL_T * ChP, Byte_t Data); +void sEnInterrupts(CHANNEL_T * ChP, Word_t Flags); +void sDisInterrupts(CHANNEL_T * ChP, Word_t Flags); +void sModemReset(CONTROLLER_T * CtlP, int chan, int on); +void sPCIModemReset(CONTROLLER_T * CtlP, int chan, int on); +void sSetInterfaceMode(CHANNEL_T * ChP, Byte_t mode); extern Byte_t R[RDATASIZE]; extern CONTROLLER_T sController[CTL_SIZE]; @@ -1108,7 +1197,6 @@ extern Byte_t sBitMapSetTbl[8]; extern int sClockPrescale; - /* * Begin Linux specific definitions for the Rocketport driver * @@ -1116,37 +1204,45 @@ */ struct r_port { - int magic; - int line; - int flags; - int count; - int blocked_open; - struct tty_struct *tty; - int board:2; - int aiop:2; - int chan:3; + int magic; + int line; + int flags; + int count; + int blocked_open; + struct tty_struct *tty; + unsigned int board:3; + unsigned int aiop:2; + unsigned int chan:3; CONTROLLER_t *ctlp; - CHANNEL_t channel; - int closing_wait; - int close_delay; - int intmask; - int xmit_fifo_room; /* room in xmit fifo */ - unsigned char *xmit_buf; - int xmit_head; - int xmit_tail; - int xmit_cnt; - int session; - int pgrp; - int cd_status; - int ignore_status_mask; - int read_status_mask; - int cps; - struct termios normal_termios; - struct termios callout_termios; - wait_queue_head_t open_wait; - wait_queue_head_t close_wait; + CHANNEL_t channel; + int closing_wait; + int close_delay; + int intmask; + int xmit_fifo_room; /* room in xmit fifo */ + unsigned char *xmit_buf; + int xmit_head; + int xmit_tail; + int xmit_cnt; + int session; + int pgrp; + int cd_status; + int ignore_status_mask; + int read_status_mask; + int cps; + struct termios normal_termios; + struct termios callout_termios; + +#ifdef DECLARE_WAITQUEUE + wait_queue_head_t open_wait; + wait_queue_head_t close_wait; +#else + struct wait_queue *open_wait; + struct wait_queue *close_wait; +#endif + spinlock_t slock; + struct semaphore write_sem; }; - + #define RPORT_MAGIC 0x525001 #define NUM_BOARDS 8 @@ -1161,15 +1257,12 @@ #define WAKEUP_CHARS 256 /* Internal flags used only by the rocketport driver */ -#define ROCKET_INITIALIZED 0x80000000 /* Port is active */ -#define ROCKET_CLOSING 0x40000000 /* Serial port is closing */ -#define ROCKET_NORMAL_ACTIVE 0x20000000 /* Normal port is active */ -#define ROCKET_CALLOUT_ACTIVE 0x10000000 /* Callout port is active */ +#define ROCKET_INITIALIZED 0x80000000 /* Port is active */ +#define ROCKET_CLOSING 0x40000000 /* Serial port is closing */ +#define ROCKET_NORMAL_ACTIVE 0x20000000 /* Normal port is active */ +#define ROCKET_CALLOUT_ACTIVE 0x10000000 /* Callout port is active */ -/* - * tty subtypes - * - */ +/* tty subtypes */ #define SERIAL_TYPE_NORMAL 1 #define SERIAL_TYPE_CALLOUT 2 @@ -1179,9 +1272,6 @@ #define TTY_ROCKET_MAJOR 46 #define CUA_ROCKET_MAJOR 47 -/* - * Utility function. - */ #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif @@ -1192,27 +1282,65 @@ #undef PCI_DEVICE_ID_RP8INTF #undef PCI_DEVICE_ID_RP16INTF #undef PCI_DEVICE_ID_RP32INTF +#undef PCI_DEVICE_ID_URP8OCTA +#undef PCI_DEVICE_ID_URP8INTF +#undef PCI_DEVICE_ID_URP16INTF +#undef PCI_DEVICE_ID_CRP16INTF +#undef PCI_DEVICE_ID_URP32INTF #endif +/* Comtrol PCI Vendor ID */ #define PCI_VENDOR_ID_RP 0x11fe -#define PCI_DEVICE_ID_RP32INTF 0x0001 -#define PCI_DEVICE_ID_RP8INTF 0x0002 -#define PCI_DEVICE_ID_RP16INTF 0x0003 -#define PCI_DEVICE_ID_RP8OCTA 0x0005 -#ifndef PCI_DEVICE_ID_RP4QUAD -#define PCI_DEVICE_ID_RP4QUAD 0x0004 -#endif -#ifndef PCI_DEVICE_ID_RP8J -#define PCI_DEVICE_ID_RP8J 0x0006 -#endif -#ifndef PCI_DEVICE_ID_RPP4 -#define PCI_DEVICE_ID_RPP4 0x000A -#endif -#ifndef PCI_DEVICE_ID_RPP8 -#define PCI_DEVICE_ID_RPP8 0x000B -#endif -#ifndef PCI_DEVICE_ID_RP8M -#define PCI_DEVICE_ID_RP8M 0x000C -#endif +/* Comtrol Device ID's */ +#define PCI_DEVICE_ID_RP32INTF 0x0001 /* Rocketport 32 port w/external I/F */ +#define PCI_DEVICE_ID_RP8INTF 0x0002 /* Rocketport 8 port w/external I/F */ +#define PCI_DEVICE_ID_RP16INTF 0x0003 /* Rocketport 16 port w/external I/F */ +#define PCI_DEVICE_ID_RP4QUAD 0x0004 /* Rocketport 4 port w/quad cable */ +#define PCI_DEVICE_ID_RP8OCTA 0x0005 /* Rocketport 8 port w/octa cable */ +#define PCI_DEVICE_ID_RP8J 0x0006 /* Rocketport 8 port w/RJ11 connectors */ +#define PCI_DEVICE_ID_RP4J 0x0007 /* Rocketport 4 port w/RJ11 connectors */ +#define PCI_DEVICE_ID_RP8SNI 0x0008 /* Rocketport 8 port w/ DB78 SNI (Siemens) connector */ +#define PCI_DEVICE_ID_RP16SNI 0x0009 /* Rocketport 16 port w/ DB78 SNI (Siemens) connector */ +#define PCI_DEVICE_ID_RPP4 0x000A /* Rocketport Plus 4 port */ +#define PCI_DEVICE_ID_RPP8 0x000B /* Rocketport Plus 8 port */ +#define PCI_DEVICE_ID_RP6M 0x000C /* RocketModem 6 port */ +#define PCI_DEVICE_ID_RP4M 0x000D /* RocketModem 4 port */ +#define PCI_DEVICE_ID_RP2_232 0x000E /* Rocketport Plus 2 port RS232 */ +#define PCI_DEVICE_ID_RP2_422 0x000F /* Rocketport Plus 2 port RS422 */ + +/* Universal PCI boards */ +#define PCI_DEVICE_ID_URP32INTF 0x0801 /* Rocketport UPCI 32 port w/external I/F */ +#define PCI_DEVICE_ID_URP8INTF 0x0802 /* Rocketport UPCI 8 port w/external I/F */ +#define PCI_DEVICE_ID_URP16INTF 0x0803 /* Rocketport UPCI 16 port w/external I/F */ +#define PCI_DEVICE_ID_URP8OCTA 0x0805 /* Rocketport UPCI 8 port w/octa cable */ +#define PCI_DEVICE_ID_UPCI_RM3_8PORT 0x080C /* Rocketmodem III 8 port */ +#define PCI_DEVICE_ID_UPCI_RM3_4PORT 0x080D /* Rocketmodem III 4 port */ + +/* Compact PCI device */ +#define PCI_DEVICE_ID_CRP16INTF 0x0903 /* Rocketport Compact PCI 16 port w/external I/F */ + +/* Taking care of some kernel incompatibilities... */ +#if LINUX_VERSION_CODE > VERSION_CODE(2,5,68) + +#define TTY_GET_LINE(t) t->index + +#define TTY_DRIVER_MINOR_START(t) t->driver->minor_start +#define TTY_DRIVER_SUBTYPE(t) t->driver->subtype +#define TTY_DRIVER_NAME(t) t->driver->name +#define TTY_DRIVER_NAME_BASE(t) t->driver->name_base +#define TTY_DRIVER_FLUSH_BUFFER_EXISTS(t) t->driver->flush_buffer +#define TTY_DRIVER_FLUSH_BUFFER(t) t->driver->flush_buffer(t) + +#else + +#define TTY_GET_LINE(t) minor(t->device) - TTY_DRIVER_MINOR_START(t) + +#define TTY_DRIVER_MINOR_START(t) t->driver.minor_start +#define TTY_DRIVER_SUBTYPE(t) t->driver.subtype +#define TTY_DRIVER_NAME(t) t->driver.name +#define TTY_DRIVER_NAME_BASE(t) t->driver.name_base +#define TTY_DRIVER_FLUSH_BUFFER_EXISTS(t) t->driver.flush_buffer +#define TTY_DRIVER_FLUSH_BUFFER(t) t->driver.flush_buffer(t) +#endif diff -Nru a/drivers/char/selection.c b/drivers/char/selection.c --- a/drivers/char/selection.c Mon Jun 9 23:16:19 2003 +++ b/drivers/char/selection.c Mon Jun 9 23:16:19 2003 @@ -118,7 +118,6 @@ int i, ps, pe; unsigned int currcons = fg_console; - unblank_screen(); poke_blanked_console(); { unsigned short *args, xs, ys, xe, ye; diff -Nru a/drivers/char/ser_a2232.c b/drivers/char/ser_a2232.c --- a/drivers/char/ser_a2232.c Mon Jun 9 23:16:09 2003 +++ b/drivers/char/ser_a2232.c Mon Jun 9 23:16:09 2003 @@ -172,7 +172,6 @@ /* TTY driver structs */ static struct tty_driver a2232_driver; -static struct tty_driver a2232_callout_driver; /* Variables used by the TTY driver */ static int a2232_refcount; @@ -474,16 +473,10 @@ } if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)){ - if (tty->driver->subtype == A2232_TTY_SUBTYPE_NORMAL) - *tty->termios = port->gs.normal_termios; - else - *tty->termios = port->gs.callout_termios; + *tty->termios = port->gs.normal_termios; a2232_set_real_termios (port); } - port->gs.session = current->session; - port->gs.pgrp = current->pgrp; - a2232_enable_rx_interrupts(port); return 0; @@ -649,18 +642,13 @@ if (!(port->gs.flags & ASYNC_CHECK_CD)) ; /* Don't report DCD changes */ else if (port->cd_status) { // if DCD on: DCD went UP! - if (~(port->gs.flags & ASYNC_NORMAL_ACTIVE) || - ~(port->gs.flags & ASYNC_CALLOUT_ACTIVE)) { - /* Are we blocking in open?*/ - wake_up_interruptible(&port->gs.open_wait); - } + + /* Are we blocking in open?*/ + wake_up_interruptible(&port->gs.open_wait); } else { // if DCD off: DCD went DOWN! - if (!((port->gs.flags & ASYNC_CALLOUT_ACTIVE) && - (port->gs.flags & ASYNC_CALLOUT_NOHUP))) { - if (port->gs.tty) - tty_hangup (port->gs.tty); - } + if (port->gs.tty) + tty_hangup (port->gs.tty); } } // if CD changed for this port @@ -686,7 +674,6 @@ port->which_a2232 = i/NUMLINES; port->which_port_on_a2232 = i%NUMLINES; port->disable_rx = port->throttle_input = port->cd_status = 0; - port->gs.callout_termios = tty_std_termios; port->gs.normal_termios = tty_std_termios; port->gs.magic = A2232_MAGIC; port->gs.close_delay = HZ/2; @@ -712,7 +699,7 @@ a2232_driver.major = A2232_NORMAL_MAJOR; a2232_driver.num = NUMLINES * nr_a2232; a2232_driver.type = TTY_DRIVER_TYPE_SERIAL; - a2232_driver.subtype = A2232_TTY_SUBTYPE_NORMAL; + a2232_driver.subtype = SERIAL_TTY_NORMAL; a2232_driver.init_termios = tty_std_termios; a2232_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; @@ -738,22 +725,11 @@ a2232_driver.start = gs_start; a2232_driver.hangup = gs_hangup; - a2232_callout_driver = a2232_driver; - a2232_callout_driver.name = "cuy"; - a2232_callout_driver.major = A2232_CALLOUT_MAJOR; - a2232_callout_driver.subtype = A2232_TTY_SUBTYPE_CALLOUT; - if ((error = tty_register_driver(&a2232_driver))) { printk(KERN_ERR "A2232: Couldn't register A2232 driver, error = %d\n", error); return 1; } - if ((error = tty_register_driver(&a2232_callout_driver))) { - tty_unregister_driver(&a2232_driver); - printk(KERN_ERR "A2232: Couldn't register A2232 callout driver, error = %d\n", - error); - return 1; - } return 0; } @@ -865,7 +841,6 @@ } tty_unregister_driver(&a2232_driver); - tty_unregister_driver(&a2232_callout_driver); free_irq(IRQ_AMIGA_VERTB, a2232_driver_ID); } #endif diff -Nru a/drivers/char/ser_a2232.h b/drivers/char/ser_a2232.h --- a/drivers/char/ser_a2232.h Mon Jun 9 23:16:18 2003 +++ b/drivers/char/ser_a2232.h Mon Jun 9 23:16:18 2003 @@ -49,10 +49,6 @@ /* Some magic is always good - Who knows :) */ #define A2232_MAGIC 0x000a2232 -/* for the tty_struct subtype field */ -#define A2232_TTY_SUBTYPE_NORMAL 1 -#define A2232_TTY_SUBTYPE_CALLOUT 2 - /* A2232 port structure to keep track of the status of every single line used */ struct a2232_port{ diff -Nru a/drivers/char/serial167.c b/drivers/char/serial167.c --- a/drivers/char/serial167.c Mon Jun 9 23:16:10 2003 +++ b/drivers/char/serial167.c Mon Jun 9 23:16:10 2003 @@ -97,12 +97,10 @@ #define STD_COM_FLAGS (0) #define SERIAL_TYPE_NORMAL 1 -#define SERIAL_TYPE_CALLOUT 2 - DECLARE_TASK_QUEUE(tq_cyclades); -struct tty_driver cy_serial_driver, cy_callout_driver; +struct tty_driver cy_serial_driver; extern int serial_console; static struct cyclades_port *serial_console_info = NULL; static unsigned int serial_console_cflag = 0; @@ -517,8 +515,7 @@ if(mdm_status & CyDCD){ /* CP('!'); */ cy_sched_event(info, Cy_EVENT_OPEN_WAKEUP); - }else if(!((info->flags & ASYNC_CALLOUT_ACTIVE) - &&(info->flags & ASYNC_CALLOUT_NOHUP))){ + } else { /* CP('@'); */ cy_sched_event(info, Cy_EVENT_HANGUP); } @@ -769,8 +766,7 @@ if (test_and_clear_bit(Cy_EVENT_HANGUP, &info->event)) { tty_hangup(info->tty); wake_up_interruptible(&info->open_wait); - info->flags &= ~(ASYNC_NORMAL_ACTIVE| - ASYNC_CALLOUT_ACTIVE); + info->flags &= ~ASYNC_NORMAL_ACTIVE; } if (test_and_clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) { wake_up_interruptible(&info->open_wait); @@ -1912,8 +1908,6 @@ */ if (info->flags & ASYNC_NORMAL_ACTIVE) info->normal_termios = *tty->termios; - if (info->flags & ASYNC_CALLOUT_ACTIVE) - info->callout_termios = *tty->termios; if (info->flags & ASYNC_INITIALIZED) tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */ shutdown(info); @@ -1938,8 +1932,7 @@ } wake_up_interruptible(&info->open_wait); } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| - ASYNC_CLOSING); + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); #ifdef SERIAL_DEBUG_OTHER @@ -1973,7 +1966,7 @@ #endif info->tty = 0; #endif - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->flags &= ~ASYNC_NORMAL_ACTIVE; wake_up_interruptible(&info->open_wait); } /* cy_hangup */ @@ -2009,35 +2002,10 @@ } /* - * If this is a callout device, then just make sure the normal - * device isn't being used. - */ - if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) { - if (info->flags & ASYNC_NORMAL_ACTIVE){ - return -EBUSY; - } - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_SESSION_LOCKOUT) && - (info->session != current->session)){ - return -EBUSY; - } - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_PGRP_LOCKOUT) && - (info->pgrp != current->pgrp)){ - return -EBUSY; - } - info->flags |= ASYNC_CALLOUT_ACTIVE; - return 0; - } - - /* * If non-blocking mode is set, then make the check up front * and then exit. */ if (filp->f_flags & O_NONBLOCK) { - if (info->flags & ASYNC_CALLOUT_ACTIVE){ - return -EBUSY; - } info->flags |= ASYNC_NORMAL_ACTIVE; return 0; } @@ -2065,16 +2033,14 @@ while (1) { local_irq_save(flags); - if (!(info->flags & ASYNC_CALLOUT_ACTIVE)){ - base_addr[CyCAR] = (u_char)channel; - base_addr[CyMSVR1] = CyRTS; + base_addr[CyCAR] = (u_char)channel; + base_addr[CyMSVR1] = CyRTS; /* CP('S');CP('4'); */ - base_addr[CyMSVR2] = CyDTR; + base_addr[CyMSVR2] = CyDTR; #ifdef SERIAL_DEBUG_DTR - printk("cyc: %d: raising DTR\n", __LINE__); - printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]); + printk("cyc: %d: raising DTR\n", __LINE__); + printk(" status: 0x%x, 0x%x\n", base_addr[CyMSVR1], base_addr[CyMSVR2]); #endif - } local_irq_restore(flags); set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) @@ -2089,8 +2055,7 @@ local_irq_save(flags); base_addr[CyCAR] = (u_char)channel; /* CP('L');CP1(1 && C_CLOCAL(tty)); CP1(1 && (base_addr[CyMSVR1] & CyDCD) ); */ - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) - && !(info->flags & ASYNC_CLOSING) + if (!(info->flags & ASYNC_CLOSING) && (C_CLOCAL(tty) || (base_addr[CyMSVR1] & CyDCD))) { local_irq_restore(flags); @@ -2169,10 +2134,7 @@ } if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver->subtype == SERIAL_TYPE_NORMAL) - *tty->termios = info->normal_termios; - else - *tty->termios = info->callout_termios; + *tty->termios = info->normal_termios; } /* * Start up serial port @@ -2191,9 +2153,6 @@ return retval; } - info->session = current->session; - info->pgrp = current->pgrp; - #ifdef SERIAL_DEBUG_OPEN printk("cy_open done\n");/**/ #endif @@ -2400,11 +2359,8 @@ memset(&cy_serial_driver, 0, sizeof(struct tty_driver)); cy_serial_driver.magic = TTY_DRIVER_MAGIC; cy_serial_driver.owner = THIS_MODULE; -#ifdef CONFIG_DEVFS_FS - cy_serial_driver.name = "tts/"; -#else + cy_serial_driver.devfs_name = "tts/"; cy_serial_driver.name = "ttyS"; -#endif cy_serial_driver.major = TTY_MAJOR; cy_serial_driver.minor_start = 64; cy_serial_driver.num = NR_PORTS; @@ -2434,29 +2390,11 @@ cy_serial_driver.start = cy_start; cy_serial_driver.hangup = cy_hangup; - /* - * The callout device is just like normal device except for - * major number and the subtype code. - */ - cy_callout_driver = cy_serial_driver; -#ifdef CONFIG_DEVFS_FS - cy_callout_driver.name = "cua/"; -#else - cy_callout_driver.name = "cua"; -#endif - cy_callout_driver.major = TTYAUX_MAJOR; - cy_callout_driver.subtype = SERIAL_TYPE_CALLOUT; - ret = tty_register_driver(&cy_serial_driver); if (ret) { printk(KERN_ERR "Couldn't register MVME166/7 serial driver\n"); return ret; } - ret = tty_register_driver(&cy_callout_driver); - if (ret) { - printk(KERN_ERR "Couldn't register MVME166/7 callout driver\n"); - goto cleanup_serial_driver; - } init_bh(CYCLADES_BH, do_cyclades_bh); @@ -2499,7 +2437,6 @@ info->default_timeout = 0; info->tqueue.routine = do_softint; info->tqueue.data = info; - info->callout_termios =cy_callout_driver.init_termios; info->normal_termios = cy_serial_driver.init_termios; init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); @@ -2530,7 +2467,7 @@ "cd2401_errors", cd2401_rxerr_interrupt); if (ret) { printk(KERN_ERR "Could't get cd2401_errors IRQ"); - goto cleanup_callout_driver; + goto cleanup_serial_driver; } ret = request_irq(MVME167_IRQ_SER_MODEM, cd2401_modem_interrupt, 0, @@ -2569,9 +2506,6 @@ free_irq(MVME167_IRQ_SER_MODEM, cd2401_modem_interrupt); cleanup_irq_cd2401_errors: free_irq(MVME167_IRQ_SER_ERR, cd2401_rxerr_interrupt); -cleanup_callout_driver: - if (tty_unregister_driver(&cy_callout_driver)) - printk(KERN_ERR "Couldn't unregister MVME166/7 callout driver\n"); cleanup_serial_driver: if (tty_unregister_driver(&cy_serial_driver)) printk(KERN_ERR "Couldn't unregister MVME166/7 serial driver\n"); @@ -2607,8 +2541,8 @@ info->close_delay, info->event, info->count); printk(" x_char blocked_open = %x %x\n", info->x_char, info->blocked_open); - printk(" session pgrp open_wait = %lx %lx %lx\n", - info->session, info->pgrp, (long)info->open_wait); + printk(" open_wait = %lx %lx %lx\n", + (long)info->open_wait); local_irq_save(flags); diff -Nru a/drivers/char/serial_tx3912.c b/drivers/char/serial_tx3912.c --- a/drivers/char/serial_tx3912.c Mon Jun 9 23:16:13 2003 +++ b/drivers/char/serial_tx3912.c Mon Jun 9 23:16:13 2003 @@ -59,7 +59,7 @@ /* * Structures and such for TTY sessions and usage counts */ -static struct tty_driver rs_driver, rs_callout_driver; +static struct tty_driver rs_driver; static struct tty_struct * rs_table[TX3912_UART_NPORTS] = { NULL, }; static struct termios ** rs_termios; static struct termios ** rs_termios_locked; @@ -594,15 +594,10 @@ /* tty->low_latency = 1; */ if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver->subtype == SERIAL_TYPE_NORMAL) - *tty->termios = port->gs.normal_termios; - else - *tty->termios = port->gs.callout_termios; + *tty->termios = port->gs.normal_termios; rs_set_real_termios (port); } - port->gs.session = current->session; - port->gs.pgrp = current->pgrp; func_exit(); /* Jim */ @@ -773,7 +768,6 @@ port = rs_ports; for (i=0; i < TX3912_UART_NPORTS;i++) { rs_dprintk (TX3912_UART_DEBUG_INIT, "initing port %d\n", i); - port->gs.callout_termios = tty_std_termios; port->gs.normal_termios = tty_std_termios; port->gs.magic = SERIAL_MAGIC; port->gs.close_delay = HZ/2; @@ -837,24 +831,11 @@ rs_driver.start = gs_start; rs_driver.hangup = gs_hangup; - rs_callout_driver = rs_driver; - rs_callout_driver.name = "cua"; - rs_callout_driver.major = TTYAUX_MAJOR; - rs_callout_driver.subtype = SERIAL_TYPE_CALLOUT; - if ((error = tty_register_driver(&rs_driver))) { printk(KERN_ERR "Couldn't register serial driver, error = %d\n", error); return 1; } - if ((error = tty_register_driver(&rs_callout_driver))) { - tty_unregister_driver(&rs_driver); - printk(KERN_ERR "Couldn't register callout driver, error = %d\n", - error); - return 1; - } - - func_exit(); return 0; } diff -Nru a/drivers/char/sh-sci.c b/drivers/char/sh-sci.c --- a/drivers/char/sh-sci.c Mon Jun 9 23:16:19 2003 +++ b/drivers/char/sh-sci.c Mon Jun 9 23:16:19 2003 @@ -76,7 +76,7 @@ static void sci_free_irq(struct sci_port *port); static int sci_init_drivers(void); -static struct tty_driver sci_driver, sci_callout_driver; +static struct tty_driver sci_driver; static struct sci_port sci_ports[SCI_NPORTS] = SCI_INIT; static struct tty_struct *sci_table[SCI_NPORTS] = { NULL, }; @@ -844,10 +844,7 @@ } if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver->subtype == SERIAL_TYPE_NORMAL) - *tty->termios = port->gs.normal_termios; - else - *tty->termios = port->gs.callout_termios; + *tty->termios = port->gs.normal_termios; sci_set_real_termios(port); } @@ -862,9 +859,6 @@ sci_enable_rx_interrupts(port); - port->gs.session = current->session; - port->gs.pgrp = current->pgrp; - return 0; failed_3: @@ -1000,11 +994,8 @@ sci_driver.magic = TTY_DRIVER_MAGIC; sci_driver.owner = THIS_MODULE; sci_driver.driver_name = "sci"; -#ifdef CONFIG_DEVFS_FS - sci_driver.name = "ttsc/"; -#else sci_driver.name = "ttySC"; -#endif + sci_driver.devfs_name = "ttsc/"; sci_driver.major = SCI_MAJOR; sci_driver.minor_start = SCI_MINOR_START; sci_driver.num = SCI_NPORTS; @@ -1038,30 +1029,13 @@ sci_driver.read_proc = sci_read_proc; #endif - sci_callout_driver = sci_driver; -#ifdef CONFIG_DEVFS_FS - sci_callout_driver.name = "cusc/"; -#else - sci_callout_driver.name = "cusc"; -#endif - sci_callout_driver.major = SCI_MAJOR+1; - sci_callout_driver.subtype = SERIAL_TYPE_CALLOUT; - sci_callout_driver.read_proc = NULL; - if ((error = tty_register_driver(&sci_driver))) { printk(KERN_ERR "sci: Couldn't register SCI driver, error = %d\n", error); return 1; } - if ((error = tty_register_driver(&sci_callout_driver))) { - tty_unregister_driver(&sci_driver); - printk(KERN_ERR "sci: Couldn't register SCI callout driver, error = %d\n", - error); - return 1; - } for (port = &sci_ports[0]; port < &sci_ports[SCI_NPORTS]; port++) { - port->gs.callout_termios = sci_callout_driver.init_termios; port->gs.normal_termios = sci_driver.init_termios; port->gs.magic = SCI_MAGIC; port->gs.close_delay = HZ/2; @@ -1142,7 +1116,6 @@ void cleanup_module(void) { tty_unregister_driver(&sci_driver); - tty_unregister_driver(&sci_callout_driver); } #include "generic_serial.c" diff -Nru a/drivers/char/specialix.c b/drivers/char/specialix.c --- a/drivers/char/specialix.c Mon Jun 9 23:16:18 2003 +++ b/drivers/char/specialix.c Mon Jun 9 23:16:18 2003 @@ -176,10 +176,7 @@ #undef RS_EVENT_WRITE_WAKEUP #define RS_EVENT_WRITE_WAKEUP 0 -#define SPECIALIX_TYPE_NORMAL 1 -#define SPECIALIX_TYPE_CALLOUT 2 - -static struct tty_driver specialix_driver, specialix_callout_driver; +static struct tty_driver specialix_driver; static int specialix_refcount; static struct tty_struct * specialix_table[SX_NBOARD * SX_NPORT]; static struct termios * specialix_termios[SX_NBOARD * SX_NPORT]; @@ -827,17 +824,11 @@ printk ( "Waking up guys in open.\n"); #endif wake_up_interruptible(&port->open_wait); - } - else if (!((port->flags & ASYNC_CALLOUT_ACTIVE) && - (port->flags & ASYNC_CALLOUT_NOHUP))) { + } else { #ifdef SPECIALIX_DEBUG printk ( "Sending HUP.\n"); #endif schedule_task(&port->tqueue_hangup); - } else { -#ifdef SPECIALIX_DEBUG - printk ( "Don't need to send HUP.\n"); -#endif } } @@ -1341,25 +1332,6 @@ else return -ERESTARTSYS; } - - /* - * If this is a callout device, then just make sure the normal - * device isn't being used. - */ - if (tty->driver->subtype == SPECIALIX_TYPE_CALLOUT) { - if (port->flags & ASYNC_NORMAL_ACTIVE) - return -EBUSY; - if ((port->flags & ASYNC_CALLOUT_ACTIVE) && - (port->flags & ASYNC_SESSION_LOCKOUT) && - (port->session != current->session)) - return -EBUSY; - if ((port->flags & ASYNC_CALLOUT_ACTIVE) && - (port->flags & ASYNC_PGRP_LOCKOUT) && - (port->pgrp != current->pgrp)) - return -EBUSY; - port->flags |= ASYNC_CALLOUT_ACTIVE; - return 0; - } /* * If non-blocking mode is set, or the port is not enabled, @@ -1367,20 +1339,13 @@ */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { - if (port->flags & ASYNC_CALLOUT_ACTIVE) - return -EBUSY; port->flags |= ASYNC_NORMAL_ACTIVE; return 0; } - if (port->flags & ASYNC_CALLOUT_ACTIVE) { - if (port->normal_termios.c_cflag & CLOCAL) - do_clocal = 1; - } else { - if (C_CLOCAL(tty)) - do_clocal = 1; - } - + if (C_CLOCAL(tty)) + do_clocal = 1; + /* * Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). While we are in @@ -1399,17 +1364,15 @@ cli(); sx_out(bp, CD186x_CAR, port_No(port)); CD = sx_in(bp, CD186x_MSVR) & MSVR_CD; - if (!(port->flags & ASYNC_CALLOUT_ACTIVE)) { - if (SX_CRTSCTS (tty)) { - /* Activate RTS */ - port->MSVR |= MSVR_DTR; - sx_out (bp, CD186x_MSVR, port->MSVR); - } else { - /* Activate DTR */ - port->MSVR |= MSVR_DTR; - sx_out (bp, CD186x_MSVR, port->MSVR); - } - } + if (SX_CRTSCTS (tty)) { + /* Activate RTS */ + port->MSVR |= MSVR_DTR; /* WTF? */ + sx_out (bp, CD186x_MSVR, port->MSVR); + } else { + /* Activate DTR */ + port->MSVR |= MSVR_DTR; + sx_out (bp, CD186x_MSVR, port->MSVR); + } sti(); set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || @@ -1420,8 +1383,7 @@ retval = -ERESTARTSYS; break; } - if (!(port->flags & ASYNC_CALLOUT_ACTIVE) && - !(port->flags & ASYNC_CLOSING) && + if (!(port->flags & ASYNC_CLOSING) && (do_clocal || CD)) break; if (signal_pending(current)) { @@ -1481,17 +1443,11 @@ return error; if ((port->count == 1) && (port->flags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver->subtype == SPECIALIX_TYPE_NORMAL) - *tty->termios = port->normal_termios; - else - *tty->termios = port->callout_termios; + *tty->termios = port->normal_termios; save_flags(flags); cli(); sx_change_speed(bp, port); restore_flags(flags); } - - port->session = current->session; - port->pgrp = current->pgrp; return 0; } @@ -1535,8 +1491,6 @@ */ if (port->flags & ASYNC_NORMAL_ACTIVE) port->normal_termios = *tty->termios; - if (port->flags & ASYNC_CALLOUT_ACTIVE) - port->callout_termios = *tty->termios; /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. @@ -1587,8 +1541,7 @@ } wake_up_interruptible(&port->open_wait); } - port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| - ASYNC_CLOSING); + port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&port->close_wait); restore_flags(flags); } @@ -2162,7 +2115,7 @@ sx_shutdown_port(bp, port); port->event = 0; port->count = 0; - port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + port->flags &= ~ASYNC_NORMAL_ACTIVE; port->tty = 0; wake_up_interruptible(&port->open_wait); } @@ -2233,7 +2186,7 @@ specialix_driver.major = SPECIALIX_NORMAL_MAJOR; specialix_driver.num = SX_NBOARD * SX_NPORT; specialix_driver.type = TTY_DRIVER_TYPE_SERIAL; - specialix_driver.subtype = SPECIALIX_TYPE_NORMAL; + specialix_driver.subtype = SERIAL_TYPE_NORMAL; specialix_driver.init_termios = tty_std_termios; specialix_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; @@ -2259,28 +2212,14 @@ specialix_driver.start = sx_start; specialix_driver.hangup = sx_hangup; - specialix_callout_driver = specialix_driver; - specialix_callout_driver.name = "cuw"; - specialix_callout_driver.major = SPECIALIX_CALLOUT_MAJOR; - specialix_callout_driver.subtype = SPECIALIX_TYPE_CALLOUT; - if ((error = tty_register_driver(&specialix_driver))) { free_page((unsigned long)tmp_buf); printk(KERN_ERR "sx: Couldn't register specialix IO8+ driver, error = %d\n", error); return 1; } - if ((error = tty_register_driver(&specialix_callout_driver))) { - free_page((unsigned long)tmp_buf); - tty_unregister_driver(&specialix_driver); - printk(KERN_ERR "sx: Couldn't register specialix IO8+ callout driver, error = %d\n", - error); - return 1; - } - memset(sx_port, 0, sizeof(sx_port)); for (i = 0; i < SX_NPORT * SX_NBOARD; i++) { - sx_port[i].callout_termios = specialix_callout_driver.init_termios; sx_port[i].normal_termios = specialix_driver.init_termios; sx_port[i].magic = SPECIALIX_MAGIC; sx_port[i].tqueue.routine = do_softint; @@ -2301,7 +2240,6 @@ { free_page((unsigned long)tmp_buf); tty_unregister_driver(&specialix_driver); - tty_unregister_driver(&specialix_callout_driver); } diff -Nru a/drivers/char/specialix_io8.h b/drivers/char/specialix_io8.h --- a/drivers/char/specialix_io8.h Mon Jun 9 23:16:05 2003 +++ b/drivers/char/specialix_io8.h Mon Jun 9 23:16:05 2003 @@ -113,15 +113,12 @@ ulong event; int timeout; int close_delay; - long session; - long pgrp; unsigned char * xmit_buf; int custom_divisor; int xmit_head; int xmit_tail; int xmit_cnt; struct termios normal_termios; - struct termios callout_termios; wait_queue_head_t open_wait; wait_queue_head_t close_wait; struct tq_struct tqueue; diff -Nru a/drivers/char/stallion.c b/drivers/char/stallion.c --- a/drivers/char/stallion.c Mon Jun 9 23:16:16 2003 +++ b/drivers/char/stallion.c Mon Jun 9 23:16:16 2003 @@ -120,9 +120,6 @@ #define STL_CALLOUTMAJOR 25 #endif -#define STL_DRVTYPSERIAL 1 -#define STL_DRVTYPCALLOUT 2 - /* * Set the TX buffer size. Bigger is better, but we don't want * to chew too much memory with buffers! @@ -139,16 +136,8 @@ static char *stl_drvtitle = "Stallion Multiport Serial Driver"; static char *stl_drvname = "stallion"; static char *stl_drvversion = "5.6.0"; -#ifdef CONFIG_DEVFS_FS -static char *stl_serialname = "tts/E%d"; -static char *stl_calloutname = "cua/E%d"; -#else -static char *stl_serialname = "ttyE"; -static char *stl_calloutname = "cue"; -#endif static struct tty_driver stl_serial; -static struct tty_driver stl_callout; static struct tty_struct *stl_ttys[STL_MAXDEVS]; static struct termios *stl_termios[STL_MAXDEVS]; static struct termios *stl_termioslocked[STL_MAXDEVS]; @@ -799,10 +788,9 @@ * hanging onto ports. */ i = tty_unregister_driver(&stl_serial); - j = tty_unregister_driver(&stl_callout); - if (i || j) { + if (i) { printk("STALLION: failed to un-register tty driver, " - "errno=%d,%d\n", -i, -j); + "errno=%d\n", -i); restore_flags(flags); return; } @@ -1087,39 +1075,16 @@ * previous opens still in effect. If we are a normal serial device * then also we might have to wait for carrier. */ - if (tty->driver->subtype == STL_DRVTYPCALLOUT) { - if (portp->flags & ASYNC_NORMAL_ACTIVE) - return(-EBUSY); - if (portp->flags & ASYNC_CALLOUT_ACTIVE) { - if ((portp->flags & ASYNC_SESSION_LOCKOUT) && - (portp->session != current->session)) - return(-EBUSY); - if ((portp->flags & ASYNC_PGRP_LOCKOUT) && - (portp->pgrp != current->pgrp)) - return(-EBUSY); - } - portp->flags |= ASYNC_CALLOUT_ACTIVE; - } else { - if (filp->f_flags & O_NONBLOCK) { - if (portp->flags & ASYNC_CALLOUT_ACTIVE) - return(-EBUSY); - } else { - if ((rc = stl_waitcarrier(portp, filp)) != 0) - return(rc); - } - portp->flags |= ASYNC_NORMAL_ACTIVE; + if (!(filp->f_flags & O_NONBLOCK)) { + if ((rc = stl_waitcarrier(portp, filp)) != 0) + return(rc); } + portp->flags |= ASYNC_NORMAL_ACTIVE; if ((portp->refcount == 1) && (portp->flags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver->subtype == STL_DRVTYPSERIAL) - *tty->termios = portp->normaltermios; - else - *tty->termios = portp->callouttermios; + *tty->termios = portp->normaltermios; stl_setport(portp, tty->termios); } - - portp->session = current->session; - portp->pgrp = current->pgrp; return(0); } @@ -1142,13 +1107,8 @@ rc = 0; doclocal = 0; - if (portp->flags & ASYNC_CALLOUT_ACTIVE) { - if (portp->normaltermios.c_cflag & CLOCAL) - doclocal++; - } else { - if (portp->tty->termios->c_cflag & CLOCAL) - doclocal++; - } + if (portp->tty->termios->c_cflag & CLOCAL) + doclocal++; save_flags(flags); cli(); @@ -1157,8 +1117,7 @@ portp->refcount--; for (;;) { - if ((portp->flags & ASYNC_CALLOUT_ACTIVE) == 0) - stl_setsignals(portp, 1, 1); + stl_setsignals(portp, 1, 1); if (tty_hung_up_p(filp) || ((portp->flags & ASYNC_INITIALIZED) == 0)) { if (portp->flags & ASYNC_HUP_NOTIFY) @@ -1167,8 +1126,7 @@ rc = -ERESTARTSYS; break; } - if (((portp->flags & ASYNC_CALLOUT_ACTIVE) == 0) && - ((portp->flags & ASYNC_CLOSING) == 0) && + if (((portp->flags & ASYNC_CLOSING) == 0) && (doclocal || (portp->sigs & TIOCM_CD))) { break; } @@ -1220,8 +1178,6 @@ if (portp->flags & ASYNC_NORMAL_ACTIVE) portp->normaltermios = *tty->termios; - if (portp->flags & ASYNC_CALLOUT_ACTIVE) - portp->callouttermios = *tty->termios; /* * May want to wait for any data to drain before closing. The BUSY @@ -1260,8 +1216,7 @@ wake_up_interruptible(&portp->open_wait); } - portp->flags &= ~(ASYNC_CALLOUT_ACTIVE | ASYNC_NORMAL_ACTIVE | - ASYNC_CLOSING); + portp->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&portp->close_wait); restore_flags(flags); } @@ -1838,7 +1793,7 @@ portp->tx.tail = (char *) NULL; } portp->tty = (struct tty_struct *) NULL; - portp->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE); + portp->flags &= ~ASYNC_NORMAL_ACTIVE; portp->refcount = 0; wake_up_interruptible(&portp->open_wait); } @@ -2256,12 +2211,8 @@ if ((portp->sigs & TIOCM_CD) && ((oldsigs & TIOCM_CD) == 0)) wake_up_interruptible(&portp->open_wait); if ((oldsigs & TIOCM_CD) && ((portp->sigs & TIOCM_CD) == 0)) { - if (portp->flags & ASYNC_CHECK_CD) { - if (! ((portp->flags & ASYNC_CALLOUT_ACTIVE) && - (portp->flags & ASYNC_CALLOUT_NOHUP))) { - tty_hangup(tty); /* FIXME: module removal race here - AKPM */ - } - } + if (portp->flags & ASYNC_CHECK_CD) + tty_hangup(tty); /* FIXME: module removal race here - AKPM */ } } unlock_kernel(); @@ -2340,7 +2291,6 @@ portp->close_delay = STL_CLOSEDELAY; portp->closing_wait = 30 * HZ; portp->normaltermios = stl_deftermios; - portp->callouttermios = stl_deftermios; INIT_WORK(&portp->tqueue, stl_offintr, portp); init_waitqueue_head(&portp->open_wait); init_waitqueue_head(&portp->close_wait); @@ -3218,18 +3168,18 @@ /* * Set up the tty driver structure and register us as a driver. - * Also setup the callout tty device. */ memset(&stl_serial, 0, sizeof(struct tty_driver)); stl_serial.magic = TTY_DRIVER_MAGIC; stl_serial.owner = THIS_MODULE; stl_serial.driver_name = stl_drvname; - stl_serial.name = stl_serialname; + stl_serial.name = "ttyE"; + stl_serial.devfs_name = "tts/E"; stl_serial.major = STL_SERIALMAJOR; stl_serial.minor_start = 0; stl_serial.num = STL_MAXBRDS * STL_MAXPORTS; stl_serial.type = TTY_DRIVER_TYPE_SERIAL; - stl_serial.subtype = STL_DRVTYPSERIAL; + stl_serial.subtype = SERIAL_TYPE_NORMAL; stl_serial.init_termios = stl_deftermios; stl_serial.flags = TTY_DRIVER_REAL_RAW; stl_serial.refcount = &stl_refcount; @@ -3257,16 +3207,8 @@ stl_serial.send_xchar = stl_sendxchar; stl_serial.read_proc = stl_readproc; - stl_callout = stl_serial; - stl_callout.name = stl_calloutname; - stl_callout.major = STL_CALLOUTMAJOR; - stl_callout.subtype = STL_DRVTYPCALLOUT; - stl_callout.read_proc = 0; - if (tty_register_driver(&stl_serial)) printk("STALLION: failed to register serial driver\n"); - if (tty_register_driver(&stl_callout)) - printk("STALLION: failed to register callout driver\n"); return(0); } diff -Nru a/drivers/char/sx.c b/drivers/char/sx.c --- a/drivers/char/sx.c Mon Jun 9 23:16:10 2003 +++ b/drivers/char/sx.c Mon Jun 9 23:16:10 2003 @@ -249,12 +249,6 @@ one machine. You'll have to increase the number of boards in sx.h if you want more than 4 boards. */ - -/* Why the hell am I defining these here? */ -#define SX_TYPE_NORMAL 1 -#define SX_TYPE_CALLOUT 2 - - #ifndef PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8 #define PCI_DEVICE_ID_SPECIALIX_SX_XIO_IO8 0x2000 #endif @@ -314,7 +308,7 @@ static int sx_init_drivers(void); -static struct tty_driver sx_driver, sx_callout_driver; +static struct tty_driver sx_driver; static struct tty_struct * sx_table[SX_NPORTS]; static struct termios ** sx_termios; @@ -1168,9 +1162,7 @@ port->c_dcd = c_dcd; if (sx_get_CD (port)) { /* DCD went UP */ - if( (~(port->gs.flags & ASYNC_NORMAL_ACTIVE) || - ~(port->gs.flags & ASYNC_CALLOUT_ACTIVE)) && - (sx_read_channel_byte(port, hi_hstat) != HS_IDLE_CLOSED) && + if ((sx_read_channel_byte(port, hi_hstat) != HS_IDLE_CLOSED) && !(port->gs.tty->termios->c_cflag & CLOCAL) ) { /* Are we blocking in open?*/ sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD active, unblocking open\n"); @@ -1180,9 +1172,7 @@ } } else { /* DCD went down! */ - if (!((port->gs.flags & ASYNC_CALLOUT_ACTIVE) && - (port->gs.flags & ASYNC_CALLOUT_NOHUP)) && - !(port->gs.tty->termios->c_cflag & CLOCAL) ) { + if (!(port->gs.tty->termios->c_cflag & CLOCAL) ) { sx_dprintk (SX_DEBUG_MODEMSIGNALS, "DCD dropped. hanging up....\n"); tty_hangup (port->gs.tty); } else { @@ -1497,15 +1487,10 @@ /* tty->low_latency = 1; */ if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver->subtype == SERIAL_TYPE_NORMAL) - *tty->termios = port->gs.normal_termios; - else - *tty->termios = port->gs.callout_termios; + *tty->termios = port->gs.normal_termios; sx_set_real_termios (port); } - port->gs.session = current->session; - port->gs.pgrp = current->pgrp; port->c_dcd = sx_get_CD (port); sx_dprintk (SX_DEBUG_OPEN, "at open: cd=%d\n", port->c_dcd); func_exit(); @@ -2250,7 +2235,7 @@ sx_driver.major = SX_NORMAL_MAJOR; sx_driver.num = sx_nports; sx_driver.type = TTY_DRIVER_TYPE_SERIAL; - sx_driver.subtype = SX_TYPE_NORMAL; + sx_driver.subtype = SERIAL_TYPE_NORMAL; sx_driver.init_termios = tty_std_termios; sx_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; @@ -2277,23 +2262,11 @@ sx_driver.start = gs_start; sx_driver.hangup = gs_hangup; - sx_callout_driver = sx_driver; - sx_callout_driver.name = "cux"; - sx_callout_driver.major = SX_CALLOUT_MAJOR; - sx_callout_driver.subtype = SX_TYPE_CALLOUT; - if ((error = tty_register_driver(&sx_driver))) { printk(KERN_ERR "sx: Couldn't register sx driver, error = %d\n", error); return 1; } - if ((error = tty_register_driver(&sx_callout_driver))) { - tty_unregister_driver(&sx_driver); - printk(KERN_ERR "sx: Couldn't register sx callout driver, error = %d\n", - error); - return 1; - } - func_exit(); return 0; } @@ -2349,7 +2322,6 @@ board->ports = port; for (j=0; j < boards[i].nports;j++) { sx_dprintk (SX_DEBUG_INIT, "initing port %d\n", j); - port->gs.callout_termios = tty_std_termios; port->gs.normal_termios = tty_std_termios; port->gs.magic = SX_MAGIC; port->gs.close_delay = HZ/2; @@ -2410,7 +2382,6 @@ { func_enter(); tty_unregister_driver(&sx_driver); - tty_unregister_driver(&sx_callout_driver); func_exit(); } diff -Nru a/drivers/char/synclink.c b/drivers/char/synclink.c --- a/drivers/char/synclink.c Mon Jun 9 23:16:10 2003 +++ b/drivers/char/synclink.c Mon Jun 9 23:16:10 2003 @@ -200,14 +200,11 @@ struct mgsl_icount icount; struct termios normal_termios; - struct termios callout_termios; - + struct tty_struct *tty; int timeout; int x_char; /* xon/xoff character */ int blocked_open; /* # of blocked opens */ - long session; /* Session of opening process */ - long pgrp; /* pgrp of opening process */ u16 read_status_mask; u16 ignore_status_mask; unsigned char *xmit_buf; @@ -891,8 +888,6 @@ */ static int ttymajor; -static int cuamajor; - /* * Array of user specified options for ISA adapters. */ @@ -907,7 +902,6 @@ MODULE_PARM(break_on_load,"i"); MODULE_PARM(ttymajor,"i"); -MODULE_PARM(cuamajor,"i"); MODULE_PARM(io,"1-" __MODULE_STRING(MAX_ISA_DEVICES) "i"); MODULE_PARM(irq,"1-" __MODULE_STRING(MAX_ISA_DEVICES) "i"); MODULE_PARM(dma,"1-" __MODULE_STRING(MAX_ISA_DEVICES) "i"); @@ -940,7 +934,7 @@ .remove = __devexit_p(synclink_remove_one), }; -static struct tty_driver serial_driver, callout_driver; +static struct tty_driver serial_driver; static int serial_refcount; /* number of characters left in xmit buffer before we ask for more */ @@ -1377,8 +1371,7 @@ (status & MISCSTATUS_DCD) ? "on" : "off"); if (status & MISCSTATUS_DCD) wake_up_interruptible(&info->open_wait); - else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_CALLOUT_NOHUP))) { + else { if ( debug_level >= DEBUG_LEVEL_ISR ) printk("doing serial hangup..."); if (info->tty) @@ -3218,9 +3211,7 @@ */ if (info->flags & ASYNC_NORMAL_ACTIVE) info->normal_termios = *tty->termios; - if (info->flags & ASYNC_CALLOUT_ACTIVE) - info->callout_termios = *tty->termios; - + /* set tty->closing to notify line discipline to * only process XON/XOFF characters. Only the N_TTY * discipline appears to use this (ppp does not). @@ -3258,8 +3249,7 @@ wake_up_interruptible(&info->open_wait); } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| - ASYNC_CLOSING); + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); @@ -3369,7 +3359,7 @@ shutdown(info); info->count = 0; - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->flags &= ~ASYNC_NORMAL_ACTIVE; info->tty = 0; wake_up_interruptible(&info->open_wait); @@ -3401,40 +3391,15 @@ printk("%s(%d):block_til_ready on %s\n", __FILE__,__LINE__, tty->driver->name ); - if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) { - /* this is a callout device */ - /* just verify that normal device is not in use */ - if (info->flags & ASYNC_NORMAL_ACTIVE) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_SESSION_LOCKOUT) && - (info->session != current->session)) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_PGRP_LOCKOUT) && - (info->pgrp != current->pgrp)) - return -EBUSY; - info->flags |= ASYNC_CALLOUT_ACTIVE; - return 0; - } - if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){ /* nonblock mode is set or port is not enabled */ - /* just verify that callout device is not active */ - if (info->flags & ASYNC_CALLOUT_ACTIVE) - return -EBUSY; info->flags |= ASYNC_NORMAL_ACTIVE; return 0; } - if (info->flags & ASYNC_CALLOUT_ACTIVE) { - if (info->normal_termios.c_cflag & CLOCAL) - do_clocal = 1; - } else { - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - } - + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + /* Wait for carrier detect and the line to become * free (i.e., not in use by the callout). While we are in * this loop, info->count is dropped by one, so that @@ -3458,8 +3423,7 @@ info->blocked_open++; while (1) { - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - (tty->termios->c_cflag & CBAUD)) { + if (tty->termios->c_cflag & CBAUD) { spin_lock_irqsave(&info->irq_spinlock,flags); info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; usc_set_serial_signals(info); @@ -3478,8 +3442,7 @@ usc_get_serial_signals(info); spin_unlock_irqrestore(&info->irq_spinlock,flags); - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - !(info->flags & ASYNC_CLOSING) && + if (!(info->flags & ASYNC_CLOSING) && (do_clocal || (info->serial_signals & SerialSignal_DCD)) ) { break; } @@ -3607,16 +3570,10 @@ if ((info->count == 1) && info->flags & ASYNC_SPLIT_TERMIOS) { - if (tty->driver->subtype == SERIAL_TYPE_NORMAL) - *tty->termios = info->normal_termios; - else - *tty->termios = info->callout_termios; + *tty->termios = info->normal_termios; mgsl_change_params(info); } - info->session = current->session; - info->pgrp = current->pgrp; - if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):mgsl_open(%s) success\n", __FILE__,__LINE__, info->device_name); @@ -4548,34 +4505,18 @@ serial_driver.tiocmget = tiocmget; serial_driver.tiocmset = tiocmset; - /* - * The callout device is just like normal device except for - * major number and the subtype code. - */ - callout_driver = serial_driver; - callout_driver.name = "cuaSL"; - callout_driver.major = cuamajor; - callout_driver.subtype = SERIAL_TYPE_CALLOUT; - callout_driver.read_proc = 0; - callout_driver.proc_entry = 0; - if (tty_register_driver(&serial_driver) < 0) printk("%s(%d):Couldn't register serial driver\n", __FILE__,__LINE__); - if (tty_register_driver(&callout_driver) < 0) - printk("%s(%d):Couldn't register callout driver\n", - __FILE__,__LINE__); - - printk("%s %s, tty major#%d callout major#%d\n", + printk("%s %s, tty major#%d\n", driver_name, driver_version, - serial_driver.major, callout_driver.major); + serial_driver.major); /* Propagate these values to all device instances */ info = mgsl_device_list; while(info){ - info->callout_termios = callout_driver.init_termios; info->normal_termios = serial_driver.init_termios; info = info->next_device; } @@ -4670,9 +4611,6 @@ if ((rc = tty_unregister_driver(&serial_driver))) printk("%s(%d) failed to unregister tty driver err=%d\n", - __FILE__,__LINE__,rc); - if ((rc = tty_unregister_driver(&callout_driver))) - printk("%s(%d) failed to unregister callout driver err=%d\n", __FILE__,__LINE__,rc); info = mgsl_device_list; diff -Nru a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c --- a/drivers/char/synclinkmp.c Mon Jun 9 23:16:08 2003 +++ b/drivers/char/synclinkmp.c Mon Jun 9 23:16:08 2003 @@ -167,14 +167,11 @@ struct mgsl_icount icount; struct termios normal_termios; - struct termios callout_termios; struct tty_struct *tty; int timeout; int x_char; /* xon/xoff character */ int blocked_open; /* # of blocked opens */ - long session; /* Session of opening process */ - long pgrp; /* pgrp of opening process */ u16 read_status_mask1; /* break detection (SR1 indications) */ u16 read_status_mask2; /* parity/framing/overun (SR2 indications) */ unsigned char ignore_status_mask1; /* break detection (SR1 indications) */ @@ -524,7 +521,7 @@ }; -static struct tty_driver serial_driver, callout_driver; +static struct tty_driver serial_driver; static int serial_refcount; /* number of characters left in xmit buffer before we ask for more */ @@ -807,16 +804,10 @@ if ((info->count == 1) && info->flags & ASYNC_SPLIT_TERMIOS) { - if (tty->driver->subtype == SERIAL_TYPE_NORMAL) - *tty->termios = info->normal_termios; - else - *tty->termios = info->callout_termios; + *tty->termios = info->normal_termios; change_params(info); } - info->session = current->session; - info->pgrp = current->pgrp; - if (debug_level >= DEBUG_LEVEL_INFO) printk("%s(%d):%s open() success\n", __FILE__,__LINE__, info->device_name); @@ -873,8 +864,6 @@ */ if (info->flags & ASYNC_NORMAL_ACTIVE) info->normal_termios = *tty->termios; - if (info->flags & ASYNC_CALLOUT_ACTIVE) - info->callout_termios = *tty->termios; /* set tty->closing to notify line discipline to * only process XON/XOFF characters. Only the N_TTY @@ -913,8 +902,7 @@ wake_up_interruptible(&info->open_wait); } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| - ASYNC_CLOSING); + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); @@ -942,7 +930,7 @@ shutdown(info); info->count = 0; - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->flags &= ~ASYNC_NORMAL_ACTIVE; info->tty = 0; wake_up_interruptible(&info->open_wait); @@ -2402,8 +2390,7 @@ (status & SerialSignal_DCD) ? "on" : "off"); if (status & SerialSignal_DCD) wake_up_interruptible(&info->open_wait); - else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_CALLOUT_NOHUP))) { + else { if ( debug_level >= DEBUG_LEVEL_ISR ) printk("doing serial hangup..."); if (info->tty) @@ -3202,39 +3189,15 @@ printk("%s(%d):%s block_til_ready()\n", __FILE__,__LINE__, tty->driver->name ); - if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) { - /* this is a callout device */ - /* just verify that normal device is not in use */ - if (info->flags & ASYNC_NORMAL_ACTIVE) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_SESSION_LOCKOUT) && - (info->session != current->session)) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_PGRP_LOCKOUT) && - (info->pgrp != current->pgrp)) - return -EBUSY; - info->flags |= ASYNC_CALLOUT_ACTIVE; - return 0; - } - if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){ /* nonblock mode is set or port is not enabled */ /* just verify that callout device is not active */ - if (info->flags & ASYNC_CALLOUT_ACTIVE) - return -EBUSY; info->flags |= ASYNC_NORMAL_ACTIVE; return 0; } - if (info->flags & ASYNC_CALLOUT_ACTIVE) { - if (info->normal_termios.c_cflag & CLOCAL) - do_clocal = 1; - } else { - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - } + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; /* Wait for carrier detect and the line to become * free (i.e., not in use by the callout). While we are in @@ -3259,8 +3222,7 @@ info->blocked_open++; while (1) { - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - (tty->termios->c_cflag & CBAUD)) { + if ((tty->termios->c_cflag & CBAUD)) { spin_lock_irqsave(&info->lock,flags); info->serial_signals |= SerialSignal_RTS + SerialSignal_DTR; set_signals(info); @@ -3279,8 +3241,7 @@ get_signals(info); spin_unlock_irqrestore(&info->lock,flags); - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - !(info->flags & ASYNC_CLOSING) && + if (!(info->flags & ASYNC_CLOSING) && (do_clocal || (info->serial_signals & SerialSignal_DCD)) ) { break; } @@ -3873,34 +3834,18 @@ serial_driver.tiocmget = tiocmget; serial_driver.tiocmset = tiocmset; - /* - * The callout device is just like normal device except for - * major number and the subtype code. - */ - callout_driver = serial_driver; - callout_driver.name = "cuaSLM"; - callout_driver.major = cuamajor; - callout_driver.subtype = SERIAL_TYPE_CALLOUT; - callout_driver.read_proc = 0; - callout_driver.proc_entry = 0; - if (tty_register_driver(&serial_driver) < 0) printk("%s(%d):Couldn't register serial driver\n", __FILE__,__LINE__); - if (tty_register_driver(&callout_driver) < 0) - printk("%s(%d):Couldn't register callout driver\n", - __FILE__,__LINE__); - - printk("%s %s, tty major#%d callout major#%d\n", + printk("%s %s, tty major#%d\n", driver_name, driver_version, - serial_driver.major, callout_driver.major); + serial_driver.major); /* Propagate these values to all device instances */ info = synclinkmp_device_list; while(info){ - info->callout_termios = callout_driver.init_termios; info->normal_termios = serial_driver.init_termios; info = info->next_device; } @@ -3919,9 +3864,6 @@ if ((rc = tty_unregister_driver(&serial_driver))) printk("%s(%d) failed to unregister tty driver err=%d\n", - __FILE__,__LINE__,rc); - if ((rc = tty_unregister_driver(&callout_driver))) - printk("%s(%d) failed to unregister callout driver err=%d\n", __FILE__,__LINE__,rc); info = synclinkmp_device_list; diff -Nru a/drivers/char/tty_io.c b/drivers/char/tty_io.c --- a/drivers/char/tty_io.c Mon Jun 9 23:16:14 2003 +++ b/drivers/char/tty_io.c Mon Jun 9 23:16:14 2003 @@ -1305,7 +1305,6 @@ int index; kdev_t device; unsigned short saved_flags; - char buf[64]; saved_flags = filp->f_flags; retry_open: @@ -1379,7 +1378,7 @@ tty->driver->subtype == PTY_TYPE_MASTER) noctty = 1; #ifdef TTY_DEBUG_HANGUP - printk(KERN_DEBUG "opening %s...", tty_name(tty, buf)); + printk(KERN_DEBUG "opening %s...", tty->name); #endif if (tty->driver->open) retval = tty->driver->open(tty, filp); @@ -1393,7 +1392,7 @@ if (retval) { #ifdef TTY_DEBUG_HANGUP printk(KERN_DEBUG "error %d in opening %s...", retval, - tty_name(tty, buf)); + tty->name); #endif release_dev(filp); @@ -1419,19 +1418,6 @@ tty->session = current->session; tty->pgrp = current->pgrp; } - if ((tty->driver->type == TTY_DRIVER_TYPE_SERIAL) && - (tty->driver->subtype == SERIAL_TYPE_CALLOUT) && - (tty->count == 1)) { - static int nr_warns; - if (nr_warns < 5) { - printk(KERN_WARNING "tty_io.c: " - "process %d (%s) used obsolete /dev/%s - " - "update software to use /dev/ttyS%d\n", - current->pid, current->comm, - tty_name(tty, buf), TTY_NUMBER(tty)); - nr_warns++; - } - } return 0; } @@ -2096,21 +2082,6 @@ tty->driver->write(tty, 0, &ch, 1); } -#ifdef CONFIG_DEVFS_FS -static void tty_unregister_devfs(struct tty_driver *driver, int index) -{ - char path[64]; - tty_line_name(driver, index, path); - devfs_remove(path); -} -#else -# define tty_unregister_devfs(driver, index) do { } while (0) -#endif /* CONFIG_DEVFS_FS */ - -static struct class tty_class = { - .name = "tty", -}; - struct tty_dev { struct list_head node; dev_t dev; @@ -2118,6 +2089,17 @@ }; #define to_tty_dev(d) container_of(d, struct tty_dev, class_dev) +static void release_tty_dev(struct class_device *class_dev) +{ + struct tty_dev *tty_dev = to_tty_dev(class_dev); + kfree(tty_dev); +} + +static struct class tty_class = { + .name = "tty", + .release = &release_tty_dev, +}; + static LIST_HEAD(tty_dev_list); static spinlock_t tty_dev_list_lock = SPIN_LOCK_UNLOCKED; @@ -2131,7 +2113,6 @@ static void tty_add_class_device(char *name, dev_t dev, struct device *device) { struct tty_dev *tty_dev = NULL; - char *temp; int retval; tty_dev = kmalloc(sizeof(*tty_dev), GFP_KERNEL); @@ -2139,16 +2120,9 @@ return; memset(tty_dev, 0x00, sizeof(*tty_dev)); - /* stupid '/' in tty name strings... */ - temp = strrchr(name, '/'); - if (temp && (temp[1] != 0x00)) - ++temp; - else - temp = name; - tty_dev->class_dev.dev = device; tty_dev->class_dev.class = &tty_class; - snprintf(tty_dev->class_dev.class_id, BUS_ID_SIZE, "%s", temp); + snprintf(tty_dev->class_dev.class_id, BUS_ID_SIZE, "%s", name); retval = class_device_register(&tty_dev->class_dev); if (retval) goto error; @@ -2181,7 +2155,6 @@ list_del(&tty_dev->node); spin_unlock(&tty_dev_list_lock); class_device_unregister(&tty_dev->class_dev); - kfree(tty_dev); } else { spin_unlock(&tty_dev_list_lock); } @@ -2203,7 +2176,6 @@ struct device *device) { dev_t dev = MKDEV(driver->major, driver->minor_start) + index; - char name[64]; if (index >= driver->num) { printk(KERN_ERR "Attempt to register invalid tty line number " @@ -2211,16 +2183,16 @@ return; } - tty_line_name(driver, index, name); - devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR, name); - - /* stupid console driver devfs names... change vc/X into ttyX */ - if (driver->type == TTY_DRIVER_TYPE_CONSOLE) - sprintf(name, "tty%d", MINOR(dev)); + devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR, + "%s%d", driver->devfs_name, index + driver->name_base); /* we don't care about the ptys */ - if (driver->type != TTY_DRIVER_TYPE_PTY) - tty_add_class_device (name, dev, device); + /* how nice to hide this behind some crappy interface.. */ + if (driver->type != TTY_DRIVER_TYPE_PTY) { + char name[64]; + tty_line_name(driver, index, name); + tty_add_class_device(name, dev, device); + } } /** @@ -2233,7 +2205,7 @@ */ void tty_unregister_device(struct tty_driver *driver, unsigned index) { - tty_unregister_devfs(driver, index); + devfs_remove("%s%d", driver->devfs_name, index + driver->name_base); tty_remove_class_device(MKDEV(driver->major, driver->minor_start) + index); } @@ -2255,7 +2227,7 @@ return 0; if (!driver->major) { - error = alloc_chrdev_region(&dev, driver->num, + error = alloc_chrdev_region(&dev, driver->minor_start, driver->num, (char*)driver->name); if (!error) { driver->major = MAJOR(dev); diff -Nru a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c --- a/drivers/char/vme_scc.c Mon Jun 9 23:16:05 2003 +++ b/drivers/char/vme_scc.c Mon Jun 9 23:16:05 2003 @@ -90,7 +90,7 @@ static void scc_setsignals(struct scc_port *port, int dtr, int rts); static void scc_break_ctl(struct tty_struct *tty, int break_state); -static struct tty_driver scc_driver, scc_callout_driver; +static struct tty_driver scc_driver; static struct tty_struct *scc_table[2] = { NULL, }; static struct termios * scc_termios[2]; @@ -131,11 +131,8 @@ scc_driver.magic = TTY_DRIVER_MAGIC; scc_driver.owner = THIS_MODULE; scc_driver.driver_name = "scc"; -#ifdef CONFIG_DEVFS_FS - scc_driver.name = "tts/"; -#else scc_driver.name = "ttyS"; -#endif + scc_driver.devfs_name = "tts/"; scc_driver.major = TTY_MAJOR; scc_driver.minor_start = SCC_MINOR_BASE; scc_driver.num = 2; @@ -167,26 +164,11 @@ scc_driver.hangup = gs_hangup; scc_driver.break_ctl = scc_break_ctl; - scc_callout_driver = scc_driver; -#ifdef CONFIG_DEVFS_FS - scc_callout_driver.name = "cua/"; -#else - scc_callout_driver.name = "cua"; -#endif - scc_callout_driver.major = TTYAUX_MAJOR; - scc_callout_driver.subtype = SERIAL_TYPE_CALLOUT; - if ((error = tty_register_driver(&scc_driver))) { printk(KERN_ERR "scc: Couldn't register scc driver, error = %d\n", error); return 1; } - if ((error = tty_register_driver(&scc_callout_driver))) { - tty_unregister_driver(&scc_driver); - printk(KERN_ERR "scc: Couldn't register scc callout driver, error = %d\n", - error); - return 1; - } return 0; } @@ -202,7 +184,6 @@ for (i = 0; i < 2; i++) { port = scc_ports + i; - port->gs.callout_termios = tty_std_termios; port->gs.normal_termios = tty_std_termios; port->gs.magic = SCC_MAGIC; port->gs.close_delay = HZ/2; @@ -599,18 +580,11 @@ if (!(port->gs.flags & ASYNC_CHECK_CD)) ; /* Don't report DCD changes */ else if (port->c_dcd) { - if (~(port->gs.flags & ASYNC_NORMAL_ACTIVE) || - ~(port->gs.flags & ASYNC_CALLOUT_ACTIVE)) { - /* Are we blocking in open?*/ - wake_up_interruptible(&port->gs.open_wait); - } + wake_up_interruptible(&port->gs.open_wait); } else { - if (!((port->gs.flags & ASYNC_CALLOUT_ACTIVE) && - (port->gs.flags & ASYNC_CALLOUT_NOHUP))) { - if (port->gs.tty) - tty_hangup (port->gs.tty); - } + if (port->gs.tty) + tty_hangup (port->gs.tty); } } SCCwrite(COMMAND_REG, CR_EXTSTAT_RESET); @@ -949,15 +923,10 @@ } if ((port->gs.count == 1) && (port->gs.flags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver->subtype == SERIAL_TYPE_NORMAL) - *tty->termios = port->gs.normal_termios; - else - *tty->termios = port->gs.callout_termios; + *tty->termios = port->gs.normal_termios; scc_set_real_termios (port); } - port->gs.session = current->session; - port->gs.pgrp = current->pgrp; port->c_dcd = scc_get_CD (port); scc_enable_rx_interrupts(port); diff -Nru a/drivers/char/vt.c b/drivers/char/vt.c --- a/drivers/char/vt.c Mon Jun 9 23:16:17 2003 +++ b/drivers/char/vt.c Mon Jun 9 23:16:17 2003 @@ -163,6 +163,12 @@ static int printable; /* Is console ready for printing? */ +/* + * ignore_poke: don't unblank the screen when things are typed. This is + * mainly for the privacy of braille terminal users. + */ +static int ignore_poke; + int do_poke_blanked_console; int console_blanked; @@ -1314,7 +1320,7 @@ case 14: /* set vesa powerdown interval */ vesa_off_interval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ; break; - case 15: /* Activate the previous console */ + case 15: /* activate the previous console */ set_console(last_console); break; } @@ -2282,6 +2288,13 @@ ret = 0; } break; + case 14: /* blank screen until explicitly unblanked, not only poked */ + ignore_poke = 1; + do_blank_screen(0); + break; + case 15: /* which console is blanked ? */ + ret = console_blanked; + break; default: ret = -EINVAL; break; @@ -2518,7 +2531,8 @@ memset(&console_driver, 0, sizeof(struct tty_driver)); console_driver.magic = TTY_DRIVER_MAGIC; console_driver.owner = THIS_MODULE; - console_driver.name = "vc/"; + console_driver.devfs_name = "vc/"; + console_driver.name = "tty"; console_driver.name_base = 1; console_driver.major = TTY_MAJOR; console_driver.minor_start = 1; @@ -2712,14 +2726,7 @@ hide_cursor(currcons); if (!from_timer_handler) del_timer_sync(&console_timer); - if (vesa_off_interval) { - console_timer.function = vesa_powerdown_screen; - mod_timer(&console_timer, jiffies + vesa_off_interval); - } else { - if (!from_timer_handler) - del_timer_sync(&console_timer); - console_timer.function = unblank_screen_t; - } + console_timer.function = unblank_screen_t; save_screen(currcons); /* In case we need to reset origin, blanking hook returns 1 */ @@ -2730,6 +2737,12 @@ if (console_blank_hook && console_blank_hook(1)) return; + + if (vesa_off_interval) { + console_timer.function = vesa_powerdown_screen; + mod_timer(&console_timer, jiffies + vesa_off_interval); + } + if (vesa_blank_mode) sw->con_blank(vc_cons[currcons].d, vesa_blank_mode + 1); } @@ -2754,6 +2767,7 @@ { int currcons; + ignore_poke = 0; if (!console_blanked) return; if (!vc_cons_allocated(fg_console)) { @@ -2771,12 +2785,12 @@ } console_blanked = 0; - if (console_blank_hook) - console_blank_hook(0); - set_palette(currcons); if (sw->con_blank(vc_cons[currcons].d, 0)) /* Low-level driver cannot restore -> do it ourselves */ update_screen(fg_console); + if (console_blank_hook) + console_blank_hook(0); + set_palette(currcons); set_cursor(fg_console); } @@ -2791,7 +2805,7 @@ void poke_blanked_console(void) { del_timer(&console_timer); - if (!vt_cons[fg_console] || vt_cons[fg_console]->vc_mode == KD_GRAPHICS) + if (ignore_poke || !vt_cons[fg_console] || vt_cons[fg_console]->vc_mode == KD_GRAPHICS) return; if (console_blanked) { console_timer.function = unblank_screen_t; diff -Nru a/drivers/char/watchdog/amd7xx_tco.c b/drivers/char/watchdog/amd7xx_tco.c --- a/drivers/char/watchdog/amd7xx_tco.c Mon Jun 9 23:16:08 2003 +++ b/drivers/char/watchdog/amd7xx_tco.c Mon Jun 9 23:16:08 2003 @@ -309,7 +309,8 @@ sema_init(&open_sem, 1); spin_lock_init(&amdtco_lock); - pci_for_each_dev(dev) { + dev = NULL; + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { if (pci_match_device (amdtco_pci_tbl, dev) != NULL) goto found_one; } diff -Nru a/drivers/char/watchdog/i810-tco.c b/drivers/char/watchdog/i810-tco.c --- a/drivers/char/watchdog/i810-tco.c Mon Jun 9 23:16:05 2003 +++ b/drivers/char/watchdog/i810-tco.c Mon Jun 9 23:16:05 2003 @@ -315,14 +315,14 @@ static unsigned char __init i810tco_getdevice (void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; u8 val1, val2; u16 badr; /* * Find the PCI device */ - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { if (pci_match_device(i810tco_pci_tbl, dev)) { i810tco_pci = dev; break; diff -Nru a/drivers/cpufreq/proc_intf.c b/drivers/cpufreq/proc_intf.c --- a/drivers/cpufreq/proc_intf.c Mon Jun 9 23:16:07 2003 +++ b/drivers/cpufreq/proc_intf.c Mon Jun 9 23:16:07 2003 @@ -209,10 +209,7 @@ { struct proc_dir_entry *entry = NULL; - if (!cpufreq_driver) - return -ENODEV; - - /* are these acceptable values? */ + /* are these acceptable values? */ entry = create_proc_entry("cpufreq", S_IFREG|S_IRUGO|S_IWUSR, &proc_root); diff -Nru a/drivers/hotplug/Kconfig b/drivers/hotplug/Kconfig --- a/drivers/hotplug/Kconfig Mon Jun 9 23:16:10 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,120 +0,0 @@ -# -# PCI Hotplug support -# - -menu "PCI Hotplug Support" - depends on HOTPLUG - -config HOTPLUG_PCI - tristate "Support for PCI Hotplug (EXPERIMENTAL)" - depends on PCI && EXPERIMENTAL - ---help--- - Say Y here if you have a motherboard with a PCI Hotplug controller. - This allows you to add and remove PCI cards while the machine is - powered up and running. The file system pcihpfs must be mounted - in order to interact with any PCI Hotplug controllers. - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called pci_hotplug. If you want to compile it - as a module, say M here and read <file:Documentation/modules.txt>. - - When in doubt, say N. - -config HOTPLUG_PCI_COMPAQ - tristate "Compaq PCI Hotplug driver" - depends on HOTPLUG_PCI && X86 - help - Say Y here if you have a motherboard with a Compaq PCI Hotplug - controller. - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called cpqphp. If you want to compile it - as a module, say M here and read <file:Documentation/modules.txt>. - - When in doubt, say N. - -config HOTPLUG_PCI_COMPAQ_NVRAM - bool "Save configuration into NVRAM on Compaq servers" - depends on HOTPLUG_PCI_COMPAQ - help - Say Y here if you have a Compaq server that has a PCI Hotplug - controller. This will allow the PCI Hotplug driver to store the PCI - system configuration options in NVRAM. - - When in doubt, say N. - -config HOTPLUG_PCI_IBM - tristate "IBM PCI Hotplug driver" - depends on HOTPLUG_PCI && X86_IO_APIC && X86 - help - Say Y here if you have a motherboard with a IBM PCI Hotplug - controller. - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called cpqphp. If you want to compile it - as a module, say M here and read <file:Documentation/modules.txt>. - - When in doubt, say N. - -config HOTPLUG_PCI_ACPI - tristate "ACPI PCI Hotplug driver" - depends on ACPI_BUS && HOTPLUG_PCI - help - Say Y here if you have a system that supports PCI Hotplug using - ACPI. - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called acpiphp. If you want to compile it - as a module, say M here and read <file:Documentation/modules.txt>. - - When in doubt, say N. - -config HOTPLUG_PCI_CPCI - tristate "CompactPCI Hotplug driver" - depends on HOTPLUG_PCI - help - Say Y here if you have a CompactPCI system card with CompactPCI - hotswap support per the PICMG 2.1 specification. - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called cpci_hotplug. If you want to compile it - as a module, say M here and read <file:Documentation/modules.txt>. - - When in doubt, say N. - -config HOTPLUG_PCI_CPCI_ZT5550 - tristate "Ziatech ZT5550 CompactPCI Hotplug driver" - depends on HOTPLUG_PCI_CPCI && X86 - help - Say Y here if you have an Performance Technologies (formerly Intel, - formerly just Ziatech) Ziatech ZT5550 CompactPCI system card. - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called cpcihp_zt5550. If you want to compile it - as a module, say M here and read <file:Documentation/modules.txt>. - - When in doubt, say N. - -config HOTPLUG_PCI_CPCI_GENERIC - tristate "Generic port I/O CompactPCI Hotplug driver" - depends on HOTPLUG_PCI_CPCI && X86 - help - Say Y here if you have a CompactPCI system card that exposes the #ENUM - hotswap signal as a bit in a system register that can be read through - standard port I/O. - - This code is also available as a module ( = code which can be - inserted in and removed from the running kernel whenever you want). - The module will be called cpcihp_generic. If you want to compile it - as a module, say M here and read <file:Documentation/modules.txt>. - - When in doubt, say N. - -endmenu - diff -Nru a/drivers/hotplug/Makefile b/drivers/hotplug/Makefile --- a/drivers/hotplug/Makefile Mon Jun 9 23:16:15 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,44 +0,0 @@ -# -# Makefile for the Linux kernel pci hotplug controller drivers. -# - -obj-$(CONFIG_HOTPLUG_PCI) += pci_hotplug.o -obj-$(CONFIG_HOTPLUG_PCI_COMPAQ) += cpqphp.o -obj-$(CONFIG_HOTPLUG_PCI_IBM) += ibmphp.o -obj-$(CONFIG_HOTPLUG_PCI_ACPI) += acpiphp.o -obj-$(CONFIG_HOTPLUG_PCI_CPCI_ZT5550) += cpcihp_zt5550.o -obj-$(CONFIG_HOTPLUG_PCI_CPCI_GENERIC) += cpcihp_generic.o - -pci_hotplug-objs := pci_hotplug_core.o - -ifdef CONFIG_HOTPLUG_PCI_CPCI -pci_hotplug-objs += cpci_hotplug_core.o \ - cpci_hotplug_pci.o -endif - -cpqphp-objs := cpqphp_core.o \ - cpqphp_ctrl.o \ - cpqphp_sysfs.o \ - cpqphp_pci.o - -ibmphp-objs := ibmphp_core.o \ - ibmphp_ebda.o \ - ibmphp_pci.o \ - ibmphp_res.o \ - ibmphp_hpc.o - -acpiphp-objs := acpiphp_core.o \ - acpiphp_glue.o \ - acpiphp_pci.o \ - acpiphp_res.o - -ifdef CONFIG_HOTPLUG_PCI_ACPI - EXTRA_CFLAGS += -D_LINUX -I$(TOPDIR)/drivers/acpi - ifdef CONFIG_ACPI_DEBUG - EXTRA_CFLAGS += -DACPI_DEBUG_OUTPUT - endif -endif - -ifeq ($(CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM),y) - cpqphp-objs += cpqphp_nvram.o -endif diff -Nru a/drivers/hotplug/acpiphp.h b/drivers/hotplug/acpiphp.h --- a/drivers/hotplug/acpiphp.h Mon Jun 9 23:16:19 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,262 +0,0 @@ -/* - * ACPI PCI Hot Plug Controller Driver - * - * Copyright (c) 1995,2001 Compaq Computer Corporation - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001 IBM Corp. - * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) - * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) - * Copyright (c) 2002 NEC Corporation - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or - * NON INFRINGEMENT. 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. - * - * Send feedback to <gregkh@us.ibm.com>, - * <h-aono@ap.jp.nec.com>, - * <t-kouchi@cq.jp.nec.com> - * - */ - -#ifndef _ACPIPHP_H -#define _ACPIPHP_H - -#include <linux/acpi.h> -#include "pci_hotplug.h" - -#define dbg(format, arg...) \ - do { \ - if (acpiphp_debug) \ - printk(KERN_DEBUG "%s: " format, \ - MY_NAME , ## arg); \ - } while (0) -#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg) -#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg) -#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg) - -#define SLOT_MAGIC 0x67267322 -/* name size which is used for entries in pcihpfs */ -#define SLOT_NAME_SIZE 32 /* ACPI{_SUN}-{BUS}:{DEV} */ - -struct acpiphp_bridge; -struct acpiphp_slot; -struct pci_resource; - -/* - * struct slot - slot information for each *physical* slot - */ -struct slot { - u32 magic; - u8 number; - struct hotplug_slot *hotplug_slot; - struct list_head slot_list; - - struct acpiphp_slot *acpi_slot; -}; - -/* - * struct pci_resource - describes pci resource (mem, pfmem, io, bus) - */ -struct pci_resource { - struct pci_resource * next; - u64 base; - u32 length; -}; - -/** - * struct hpp_param - ACPI 2.0 _HPP Hot Plug Parameters - * @cache_line_size in DWORD - * @latency_timer in PCI clock - * @enable_SERR 0 or 1 - * @enable_PERR 0 or 1 - */ -struct hpp_param { - u8 cache_line_size; - u8 latency_timer; - u8 enable_SERR; - u8 enable_PERR; -}; - - -/** - * struct acpiphp_bridge - PCI bridge information - * - * for each bridge device in ACPI namespace - */ -struct acpiphp_bridge { - struct list_head list; - acpi_handle handle; - struct acpiphp_slot *slots; - int type; - int nr_slots; - - u8 seg; - u8 bus; - u8 sub; - - u32 flags; - - /* This bus (host bridge) or Secondary bus (PCI-to-PCI bridge) */ - struct pci_bus *pci_bus; - - /* PCI-to-PCI bridge device */ - struct pci_dev *pci_dev; - - /* ACPI 2.0 _HPP parameters */ - struct hpp_param hpp; - - spinlock_t res_lock; - - /* available resources on this bus */ - struct pci_resource *mem_head; - struct pci_resource *p_mem_head; - struct pci_resource *io_head; - struct pci_resource *bus_head; -}; - - -/** - * struct acpiphp_slot - PCI slot information - * - * PCI slot information for each *physical* PCI slot - */ -struct acpiphp_slot { - struct acpiphp_slot *next; - struct acpiphp_bridge *bridge; /* parent */ - struct list_head funcs; /* one slot may have different - objects (i.e. for each function) */ - struct semaphore crit_sect; - - u32 id; /* slot id (serial #) for hotplug core */ - u8 device; /* pci device# */ - - u32 sun; /* ACPI _SUN (slot unique number) */ - u32 slotno; /* slot number relative to bridge */ - u32 flags; /* see below */ -}; - - -/** - * struct acpiphp_func - PCI function information - * - * PCI function information for each object in ACPI namespace - * typically 8 objects per slot (i.e. for each PCI function) - */ -struct acpiphp_func { - struct acpiphp_slot *slot; /* parent */ - - struct list_head sibling; - struct pci_dev *pci_dev; - - acpi_handle handle; - - u8 function; /* pci function# */ - u32 flags; /* see below */ - - /* resources used for this function */ - struct pci_resource *mem_head; - struct pci_resource *p_mem_head; - struct pci_resource *io_head; - struct pci_resource *bus_head; -}; - - -/* PCI bus bridge HID */ -#define ACPI_PCI_HOST_HID "PNP0A03" - -/* PCI BRIDGE type */ -#define BRIDGE_TYPE_HOST 0 -#define BRIDGE_TYPE_P2P 1 - -/* ACPI _STA method value (ignore bit 4; battery present) */ -#define ACPI_STA_PRESENT (0x00000001) -#define ACPI_STA_ENABLED (0x00000002) -#define ACPI_STA_SHOW_IN_UI (0x00000004) -#define ACPI_STA_FUNCTIONING (0x00000008) -#define ACPI_STA_ALL (0x0000000f) - -/* bridge flags */ -#define BRIDGE_HAS_STA (0x00000001) -#define BRIDGE_HAS_EJ0 (0x00000002) -#define BRIDGE_HAS_HPP (0x00000004) -#define BRIDGE_HAS_PS0 (0x00000010) -#define BRIDGE_HAS_PS1 (0x00000020) -#define BRIDGE_HAS_PS2 (0x00000040) -#define BRIDGE_HAS_PS3 (0x00000080) - -/* slot flags */ - -#define SLOT_POWEREDON (0x00000001) -#define SLOT_ENABLED (0x00000002) -#define SLOT_MULTIFUNCTION (x000000004) - -/* function flags */ - -#define FUNC_HAS_STA (0x00000001) -#define FUNC_HAS_EJ0 (0x00000002) -#define FUNC_HAS_PS0 (0x00000010) -#define FUNC_HAS_PS1 (0x00000020) -#define FUNC_HAS_PS2 (0x00000040) -#define FUNC_HAS_PS3 (0x00000080) - -/* not yet */ -#define SLOT_SUPPORT_66MHZ (0x00010000) -#define SLOT_SUPPORT_100MHZ (0x00020000) -#define SLOT_SUPPORT_133MHZ (0x00040000) -#define SLOT_SUPPORT_PCIX (0x00080000) - -/* function prototypes */ - -/* acpiphp_glue.c */ -extern int acpiphp_glue_init (void); -extern void acpiphp_glue_exit (void); -extern int acpiphp_get_num_slots (void); -extern struct acpiphp_slot *get_slot_from_id (int id); -typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data); -extern int acpiphp_for_each_slot (acpiphp_callback fn, void *data); - -extern int acpiphp_check_bridge (struct acpiphp_bridge *bridge); -extern int acpiphp_enable_slot (struct acpiphp_slot *slot); -extern int acpiphp_disable_slot (struct acpiphp_slot *slot); -extern u8 acpiphp_get_power_status (struct acpiphp_slot *slot); -extern u8 acpiphp_get_attention_status (struct acpiphp_slot *slot); -extern u8 acpiphp_get_latch_status (struct acpiphp_slot *slot); -extern u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot); - -/* acpiphp_pci.c */ -extern struct pci_dev *acpiphp_allocate_pcidev (struct pci_bus *pbus, int dev, int fn); -extern int acpiphp_configure_slot (struct acpiphp_slot *slot); -extern int acpiphp_configure_function (struct acpiphp_func *func); -extern int acpiphp_unconfigure_function (struct acpiphp_func *func); -extern int acpiphp_detect_pci_resource (struct acpiphp_bridge *bridge); -extern int acpiphp_init_func_resource (struct acpiphp_func *func); - -/* acpiphp_res.c */ -extern struct pci_resource *acpiphp_get_io_resource (struct pci_resource **head, u32 size); -extern struct pci_resource *acpiphp_get_max_resource (struct pci_resource **head, u32 size); -extern struct pci_resource *acpiphp_get_resource (struct pci_resource **head, u32 size); -extern struct pci_resource *acpiphp_get_resource_with_base (struct pci_resource **head, u64 base, u32 size); -extern int acpiphp_resource_sort_and_combine (struct pci_resource **head); -extern struct pci_resource *acpiphp_make_resource (u64 base, u32 length); -extern void acpiphp_move_resource (struct pci_resource **from, struct pci_resource **to); -extern void acpiphp_free_resource (struct pci_resource **res); -extern void acpiphp_dump_resource (struct acpiphp_bridge *bridge); /* debug */ -extern void acpiphp_dump_func_resource (struct acpiphp_func *func); /* debug */ - -/* variables */ -extern int acpiphp_debug; - -#endif /* _ACPIPHP_H */ diff -Nru a/drivers/hotplug/acpiphp_core.c b/drivers/hotplug/acpiphp_core.c --- a/drivers/hotplug/acpiphp_core.c Mon Jun 9 23:16:14 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,505 +0,0 @@ -/* - * ACPI PCI Hot Plug Controller Driver - * - * Copyright (c) 1995,2001 Compaq Computer Corporation - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001 IBM Corp. - * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) - * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) - * Copyright (c) 2002 NEC Corporation - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or - * NON INFRINGEMENT. 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. - * - * Send feedback to <gregkh@us.ibm.com>, - * <h-aono@ap.jp.nec.com>, - * <t-kouchi@cq.jp.nec.com> - * - */ - -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/slab.h> -#include <linux/smp.h> -#include <linux/smp_lock.h> -#include <linux/init.h> -#include "pci_hotplug.h" -#include "acpiphp.h" - -static LIST_HEAD(slot_list); - -#if !defined(CONFIG_HOTPLUG_PCI_ACPI_MODULE) - #define MY_NAME "acpiphp" -#else - #define MY_NAME THIS_MODULE->name -#endif - -static int debug; -int acpiphp_debug; - -/* local variables */ -static int num_slots; - -#define DRIVER_VERSION "0.4" -#define DRIVER_AUTHOR "Greg Kroah-Hartman <gregkh@us.ibm.com>, Takayoshi Kochi <t-kouchi@cq.jp.nec.com>" -#define DRIVER_DESC "ACPI Hot Plug PCI Controller Driver" - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -MODULE_PARM(debug, "i"); -MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); - -static int enable_slot (struct hotplug_slot *slot); -static int disable_slot (struct hotplug_slot *slot); -static int set_attention_status (struct hotplug_slot *slot, u8 value); -static int hardware_test (struct hotplug_slot *slot, u32 value); -static int get_power_status (struct hotplug_slot *slot, u8 *value); -static int get_attention_status (struct hotplug_slot *slot, u8 *value); -static int get_latch_status (struct hotplug_slot *slot, u8 *value); -static int get_adapter_status (struct hotplug_slot *slot, u8 *value); -static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value); -static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value); - -static struct hotplug_slot_ops acpi_hotplug_slot_ops = { - .owner = THIS_MODULE, - .enable_slot = enable_slot, - .disable_slot = disable_slot, - .set_attention_status = set_attention_status, - .hardware_test = hardware_test, - .get_power_status = get_power_status, - .get_attention_status = get_attention_status, - .get_latch_status = get_latch_status, - .get_adapter_status = get_adapter_status, - .get_max_bus_speed = get_max_bus_speed, - .get_cur_bus_speed = get_cur_bus_speed, -}; - - -/* Inline functions to check the sanity of a pointer that is passed to us */ -static inline int slot_paranoia_check (struct slot *slot, const char *function) -{ - if (!slot) { - dbg("%s - slot == NULL\n", function); - return -1; - } - if (slot->magic != SLOT_MAGIC) { - dbg("%s - bad magic number for slot\n", function); - return -1; - } - if (!slot->hotplug_slot) { - dbg("%s - slot->hotplug_slot == NULL!\n", function); - return -1; - } - return 0; -} - - -static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function) -{ - struct slot *slot; - - if (!hotplug_slot) { - dbg("%s - hotplug_slot == NULL\n", function); - return NULL; - } - - slot = (struct slot *)hotplug_slot->private; - if (slot_paranoia_check(slot, function)) - return NULL; - return slot; -} - - -/** - * enable_slot - power on and enable a slot - * @hotplug_slot: slot to enable - * - * Actual tasks are done in acpiphp_enable_slot() - * - */ -static int enable_slot (struct hotplug_slot *hotplug_slot) -{ - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - /* enable the specified slot */ - retval = acpiphp_enable_slot(slot->acpi_slot); - - return retval; -} - - -/** - * disable_slot - disable and power off a slot - * @hotplug_slot: slot to disable - * - * Actual tasks are done in acpiphp_disable_slot() - * - */ -static int disable_slot (struct hotplug_slot *hotplug_slot) -{ - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - /* disable the specified slot */ - retval = acpiphp_disable_slot(slot->acpi_slot); - - return retval; -} - - -/** - * set_attention_status - set attention LED - * - * TBD: - * ACPI doesn't have known method to manipulate - * attention status LED. - * - */ -static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status) -{ - int retval = 0; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - switch (status) { - case 0: - /* FIXME turn light off */ - hotplug_slot->info->attention_status = 0; - break; - - case 1: - default: - /* FIXME turn light on */ - hotplug_slot->info->attention_status = 1; - break; - } - - return retval; -} - - -/** - * hardware_test - hardware test - * - * We have nothing to do for now... - * - */ -static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value) -{ - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - err("No hardware tests are defined for this driver\n"); - retval = -ENODEV; - - return retval; -} - - -/** - * get_power_status - get power status of a slot - * @hotplug_slot: slot to get status - * @value: pointer to store status - * - * Some platforms may not implement _STA method properly. - * In that case, the value returned may not be reliable. - * - */ -static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value) -{ - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - *value = acpiphp_get_power_status(slot->acpi_slot); - - return retval; -} - - -/** - * get_attention_status - get attention LED status - * - * TBD: - * ACPI doesn't provide any formal means to access attention LED status. - * - */ -static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value) -{ - int retval = 0; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - *value = hotplug_slot->info->attention_status; - - return retval; -} - - -/** - * get_latch_status - get latch status of a slot - * @hotplug_slot: slot to get status - * @value: pointer to store status - * - * ACPI doesn't provide any formal means to access latch status. - * Instead, we fake latch status from _STA - * - */ -static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value) -{ - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - *value = acpiphp_get_latch_status(slot->acpi_slot); - - return retval; -} - - -/** - * get_adapter_status - get adapter status of a slot - * @hotplug_slot: slot to get status - * @value: pointer to store status - * - * ACPI doesn't provide any formal means to access adapter status. - * Instead, we fake adapter status from _STA - * - */ -static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value) -{ - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - *value = acpiphp_get_adapter_status(slot->acpi_slot); - - return retval; -} - - -/* return dummy value because ACPI doesn't provide any method... */ -static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) -{ - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - - if (slot == NULL) - return -ENODEV; - - *value = PCI_SPEED_UNKNOWN; - - return 0; -} - - -/* return dummy value because ACPI doesn't provide any method... */ -static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) -{ - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - - if (slot == NULL) - return -ENODEV; - - *value = PCI_SPEED_UNKNOWN; - - return 0; -} - - -static int init_acpi (void) -{ - int retval; - - /* initialize internal data structure etc. */ - retval = acpiphp_glue_init(); - - /* read initial number of slots */ - if (!retval) { - num_slots = acpiphp_get_num_slots(); - if (num_slots == 0) - retval = -ENODEV; - } - - return retval; -} - - -/** - * make_slot_name - make a slot name that appears in pcihpfs - * @slot: slot to name - * - */ -static void make_slot_name (struct slot *slot) -{ - snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "ACPI%d-%02x:%02x", - slot->acpi_slot->sun, - slot->acpi_slot->bridge->bus, - slot->acpi_slot->device); -} - -/** - * init_slots - initialize 'struct slot' structures for each slot - * - */ -static int init_slots (void) -{ - struct slot *slot; - int retval = 0; - int i; - - for (i = 0; i < num_slots; ++i) { - slot = kmalloc(sizeof(struct slot), GFP_KERNEL); - if (!slot) - return -ENOMEM; - memset(slot, 0, sizeof(struct slot)); - - slot->hotplug_slot = kmalloc(sizeof(struct hotplug_slot), GFP_KERNEL); - if (!slot->hotplug_slot) { - kfree(slot); - return -ENOMEM; - } - memset(slot->hotplug_slot, 0, sizeof(struct hotplug_slot)); - - slot->hotplug_slot->info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL); - if (!slot->hotplug_slot->info) { - kfree(slot->hotplug_slot); - kfree(slot); - return -ENOMEM; - } - memset(slot->hotplug_slot->info, 0, sizeof(struct hotplug_slot_info)); - - slot->hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL); - if (!slot->hotplug_slot->name) { - kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot); - kfree(slot); - return -ENOMEM; - } - - slot->magic = SLOT_MAGIC; - slot->number = i; - - slot->hotplug_slot->private = slot; - slot->hotplug_slot->ops = &acpi_hotplug_slot_ops; - - slot->acpi_slot = get_slot_from_id(i); - slot->hotplug_slot->info->power_status = acpiphp_get_power_status(slot->acpi_slot); - slot->hotplug_slot->info->attention_status = acpiphp_get_attention_status(slot->acpi_slot); - slot->hotplug_slot->info->latch_status = acpiphp_get_latch_status(slot->acpi_slot); - slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot); - - make_slot_name(slot); - - retval = pci_hp_register(slot->hotplug_slot); - if (retval) { - err("pci_hp_register failed with error %d\n", retval); - kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot->name); - kfree(slot->hotplug_slot); - kfree(slot); - return retval; - } - - /* add slot to our internal list */ - list_add(&slot->slot_list, &slot_list); - info("Slot [%s] registered\n", slot->hotplug_slot->name); - } - - return retval; -} - - -static void cleanup_slots (void) -{ - struct list_head *tmp, *n; - struct slot *slot; - - list_for_each_safe (tmp, n, &slot_list) { - slot = list_entry(tmp, struct slot, slot_list); - list_del(&slot->slot_list); - pci_hp_deregister(slot->hotplug_slot); - kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot->name); - kfree(slot->hotplug_slot); - kfree(slot); - } - - return; -} - - -static int __init acpiphp_init(void) -{ - int retval; - - info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); - - acpiphp_debug = debug; - - /* read all the ACPI info from the system */ - retval = init_acpi(); - if (retval) - return retval; - - retval = init_slots(); - if (retval) - return retval; - - return 0; -} - - -static void __exit acpiphp_exit(void) -{ - cleanup_slots(); - /* deallocate internal data structures etc. */ - acpiphp_glue_exit(); -} - -module_init(acpiphp_init); -module_exit(acpiphp_exit); diff -Nru a/drivers/hotplug/acpiphp_glue.c b/drivers/hotplug/acpiphp_glue.c --- a/drivers/hotplug/acpiphp_glue.c Mon Jun 9 23:16:09 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,1359 +0,0 @@ -/* - * ACPI PCI HotPlug glue functions to ACPI CA subsystem - * - * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) - * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) - * Copyright (c) 2002 NEC Corporation - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or - * NON INFRINGEMENT. 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. - * - * Send feedback to <t-kouchi@cq.jp.nec.com> - * - */ - -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/smp_lock.h> -#include <linux/init.h> -#include <asm/semaphore.h> - -#include "pci_hotplug.h" -#include "acpiphp.h" - -static LIST_HEAD(bridge_list); - -#define MY_NAME "acpiphp_glue" - -static void handle_hotplug_event_bridge (acpi_handle, u32, void *); -static void handle_hotplug_event_func (acpi_handle, u32, void *); - -/* - * initialization & terminatation routines - */ - -/** - * is_ejectable - determine if a slot is ejectable - * @handle: handle to acpi namespace - * - * Ejectable slot should satisfy at least these conditions: - * - * 1. has _ADR method - * 2. has _EJ0 method - * - * optionally - * - * 1. has _STA method - * 2. has _PS0 method - * 3. has _PS3 method - * 4. .. - * - */ -static int is_ejectable (acpi_handle handle) -{ - acpi_status status; - acpi_handle tmp; - - status = acpi_get_handle(handle, "_ADR", &tmp); - if (ACPI_FAILURE(status)) { - return 0; - } - - status = acpi_get_handle(handle, "_EJ0", &tmp); - if (ACPI_FAILURE(status)) { - return 0; - } - - return 1; -} - - -/* callback routine to check the existence of ejectable slots */ -static acpi_status -is_ejectable_slot (acpi_handle handle, u32 lvl, void *context, void **rv) -{ - int *count = (int *)context; - - if (is_ejectable(handle)) { - (*count)++; - /* only one ejectable slot is enough */ - return AE_CTRL_TERMINATE; - } else { - return AE_OK; - } -} - - -/* callback routine to register each ACPI PCI slot object */ -static acpi_status -register_slot (acpi_handle handle, u32 lvl, void *context, void **rv) -{ - struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context; - struct acpiphp_slot *slot; - struct acpiphp_func *newfunc; - acpi_handle tmp; - acpi_status status = AE_OK; - unsigned long adr, sun; - int device, function; - static int num_slots = 0; /* XXX if we support I/O node hotplug... */ - - status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr); - - if (ACPI_FAILURE(status)) - return AE_OK; - - status = acpi_get_handle(handle, "_EJ0", &tmp); - - if (ACPI_FAILURE(status)) - return AE_OK; - - device = (adr >> 16) & 0xffff; - function = adr & 0xffff; - - newfunc = kmalloc(sizeof(struct acpiphp_func), GFP_KERNEL); - if (!newfunc) - return AE_NO_MEMORY; - memset(newfunc, 0, sizeof(struct acpiphp_func)); - - INIT_LIST_HEAD(&newfunc->sibling); - newfunc->handle = handle; - newfunc->function = function; - newfunc->flags = FUNC_HAS_EJ0; - - if (ACPI_SUCCESS(acpi_get_handle(handle, "_STA", &tmp))) - newfunc->flags |= FUNC_HAS_STA; - - if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS0", &tmp))) - newfunc->flags |= FUNC_HAS_PS0; - - if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp))) - newfunc->flags |= FUNC_HAS_PS3; - - status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun); - if (ACPI_FAILURE(status)) - sun = -1; - - /* search for objects that share the same slot */ - for (slot = bridge->slots; slot; slot = slot->next) - if (slot->device == device) { - if (slot->sun != sun) - warn("sibling found, but _SUN doesn't match!\n"); - break; - } - - if (!slot) { - slot = kmalloc(sizeof(struct acpiphp_slot), GFP_KERNEL); - if (!slot) { - kfree(newfunc); - return AE_NO_MEMORY; - } - - memset(slot, 0, sizeof(struct acpiphp_slot)); - slot->bridge = bridge; - slot->id = num_slots++; - slot->device = device; - slot->sun = sun; - INIT_LIST_HEAD(&slot->funcs); - init_MUTEX(&slot->crit_sect); - - slot->next = bridge->slots; - bridge->slots = slot; - - bridge->nr_slots++; - - dbg("found ACPI PCI Hotplug slot at PCI %02x:%02x Slot:%d\n", - slot->bridge->bus, slot->device, slot->sun); - } - - newfunc->slot = slot; - list_add_tail(&newfunc->sibling, &slot->funcs); - - /* associate corresponding pci_dev */ - newfunc->pci_dev = pci_find_slot(bridge->bus, - PCI_DEVFN(device, function)); - if (newfunc->pci_dev) { - if (acpiphp_init_func_resource(newfunc) < 0) { - kfree(newfunc); - return AE_ERROR; - } - slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); - } - - /* install notify handler */ - status = acpi_install_notify_handler(handle, - ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_func, - newfunc); - - if (ACPI_FAILURE(status)) { - err("failed to register interrupt notify handler\n"); - kfree(newfunc); - return status; - } - - return AE_OK; -} - - -/* see if it's worth looking at this bridge */ -static int detect_ejectable_slots (acpi_handle *bridge_handle) -{ - acpi_status status; - int count; - - count = 0; - - /* only check slots defined directly below bridge object */ - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1, - is_ejectable_slot, (void *)&count, NULL); - - return count; -} - - -/* decode ACPI _CRS data and convert into our internal resource list - * TBD: _TRA, etc. - */ -static acpi_status -decode_acpi_resource (struct acpi_resource *resource, void *context) -{ - struct acpiphp_bridge *bridge = (struct acpiphp_bridge *) context; - struct acpi_resource_address64 address; - struct pci_resource *res; - - if (resource->id != ACPI_RSTYPE_ADDRESS16 && - resource->id != ACPI_RSTYPE_ADDRESS32 && - resource->id != ACPI_RSTYPE_ADDRESS64) - return AE_OK; - - acpi_resource_to_address64(resource, &address); - - if (address.producer_consumer == ACPI_PRODUCER && address.address_length > 0) { - dbg("resource type: %d: 0x%llx - 0x%llx\n", address.resource_type, address.min_address_range, address.max_address_range); - res = acpiphp_make_resource(address.min_address_range, - address.address_length); - if (!res) { - err("out of memory\n"); - return AE_OK; - } - - switch (address.resource_type) { - case ACPI_MEMORY_RANGE: - if (address.attribute.memory.cache_attribute == ACPI_PREFETCHABLE_MEMORY) { - res->next = bridge->p_mem_head; - bridge->p_mem_head = res; - } else { - res->next = bridge->mem_head; - bridge->mem_head = res; - } - break; - case ACPI_IO_RANGE: - res->next = bridge->io_head; - bridge->io_head = res; - break; - case ACPI_BUS_NUMBER_RANGE: - res->next = bridge->bus_head; - bridge->bus_head = res; - break; - default: - /* invalid type */ - kfree(res); - break; - } - } - - return AE_OK; -} - - -/* find pci_bus structure associated to specific bus number */ -static struct pci_bus *find_pci_bus(const struct list_head *list, int bus) -{ - const struct list_head *l; - - list_for_each (l, list) { - struct pci_bus *b = pci_bus_b(l); - if (b->number == bus) - return b; - - if (!list_empty(&b->children)) { - /* XXX recursive call */ - b = find_pci_bus(&b->children, bus); - - if (b) - return b; - } - } - - return NULL; -} - - -/* decode ACPI 2.0 _HPP hot plug parameters */ -static void decode_hpp(struct acpiphp_bridge *bridge) -{ - acpi_status status; - struct acpi_buffer buffer = { .length = ACPI_ALLOCATE_BUFFER, - .pointer = NULL}; - union acpi_object *package; - int i; - - /* default numbers */ - bridge->hpp.cache_line_size = 0x10; - bridge->hpp.latency_timer = 0x40; - bridge->hpp.enable_SERR = 0; - bridge->hpp.enable_PERR = 0; - - status = acpi_evaluate_object(bridge->handle, "_HPP", NULL, &buffer); - - if (ACPI_FAILURE(status)) { - dbg("_HPP evaluation failed\n"); - return; - } - - package = (union acpi_object *) buffer.pointer; - - if (!package || package->type != ACPI_TYPE_PACKAGE || - package->package.count != 4 || !package->package.elements) { - err("invalid _HPP object; ignoring\n"); - goto err_exit; - } - - for (i = 0; i < 4; i++) { - if (package->package.elements[i].type != ACPI_TYPE_INTEGER) { - err("invalid _HPP parameter type; ignoring\n"); - goto err_exit; - } - } - - bridge->hpp.cache_line_size = package->package.elements[0].integer.value; - bridge->hpp.latency_timer = package->package.elements[1].integer.value; - bridge->hpp.enable_SERR = package->package.elements[2].integer.value; - bridge->hpp.enable_PERR = package->package.elements[3].integer.value; - - dbg("_HPP parameter = (%02x, %02x, %02x, %02x)\n", - bridge->hpp.cache_line_size, - bridge->hpp.latency_timer, - bridge->hpp.enable_SERR, - bridge->hpp.enable_PERR); - - bridge->flags |= BRIDGE_HAS_HPP; - - err_exit: - kfree(buffer.pointer); -} - - -/* initialize miscellaneous stuff for both root and PCI-to-PCI bridge */ -static void init_bridge_misc (struct acpiphp_bridge *bridge) -{ - acpi_status status; - - /* decode ACPI 2.0 _HPP (hot plug parameters) */ - decode_hpp(bridge); - - /* subtract all resources already allocated */ - acpiphp_detect_pci_resource(bridge); - - /* register all slot objects under this bridge */ - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1, - register_slot, bridge, NULL); - - /* install notify handler */ - status = acpi_install_notify_handler(bridge->handle, - ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_bridge, - bridge); - - if (ACPI_FAILURE(status)) { - err("failed to register interrupt notify handler\n"); - } - - list_add(&bridge->list, &bridge_list); - - dbg("Bridge resource:\n"); - acpiphp_dump_resource(bridge); -} - - -/* allocate and initialize host bridge data structure */ -static void add_host_bridge (acpi_handle *handle, int seg, int bus) -{ - acpi_status status; - struct acpiphp_bridge *bridge; - - bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); - if (bridge == NULL) - return; - - memset(bridge, 0, sizeof(struct acpiphp_bridge)); - - bridge->type = BRIDGE_TYPE_HOST; - bridge->handle = handle; - bridge->seg = seg; - bridge->bus = bus; - - bridge->pci_bus = find_pci_bus(&pci_root_buses, bus); - - bridge->res_lock = SPIN_LOCK_UNLOCKED; - - /* to be overridden when we decode _CRS */ - bridge->sub = bridge->bus; - - /* decode resources */ - - status = acpi_walk_resources(handle, METHOD_NAME__CRS, - decode_acpi_resource, bridge); - - if (ACPI_FAILURE(status)) { - err("failed to decode bridge resources\n"); - kfree(bridge); - return; - } - - acpiphp_resource_sort_and_combine(&bridge->io_head); - acpiphp_resource_sort_and_combine(&bridge->mem_head); - acpiphp_resource_sort_and_combine(&bridge->p_mem_head); - acpiphp_resource_sort_and_combine(&bridge->bus_head); - - dbg("ACPI _CRS resource:\n"); - acpiphp_dump_resource(bridge); - - if (bridge->bus_head) { - bridge->bus = bridge->bus_head->base; - bridge->sub = bridge->bus_head->base + bridge->bus_head->length - 1; - } - - init_bridge_misc(bridge); -} - - -/* allocate and initialize PCI-to-PCI bridge data structure */ -static void add_p2p_bridge (acpi_handle *handle, int seg, int bus, int dev, int fn) -{ - struct acpiphp_bridge *bridge; - u8 tmp8; - u16 tmp16; - u64 base64, limit64; - u32 base, limit, base32u, limit32u; - - bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); - if (bridge == NULL) { - err("out of memory\n"); - return; - } - - memset(bridge, 0, sizeof(struct acpiphp_bridge)); - - bridge->type = BRIDGE_TYPE_P2P; - bridge->handle = handle; - bridge->seg = seg; - - bridge->pci_dev = pci_find_slot(bus, PCI_DEVFN(dev, fn)); - if (!bridge->pci_dev) { - err("Can't get pci_dev\n"); - kfree(bridge); - return; - } - - bridge->pci_bus = bridge->pci_dev->subordinate; - if (!bridge->pci_bus) { - err("This is not a PCI-to-PCI bridge!\n"); - kfree(bridge); - return; - } - - bridge->res_lock = SPIN_LOCK_UNLOCKED; - - bridge->bus = bridge->pci_bus->number; - bridge->sub = bridge->pci_bus->subordinate; - - /* - * decode resources under this P2P bridge - */ - - /* I/O resources */ - pci_read_config_byte(bridge->pci_dev, PCI_IO_BASE, &tmp8); - base = tmp8; - pci_read_config_byte(bridge->pci_dev, PCI_IO_LIMIT, &tmp8); - limit = tmp8; - - switch (base & PCI_IO_RANGE_TYPE_MASK) { - case PCI_IO_RANGE_TYPE_16: - base = (base << 8) & 0xf000; - limit = ((limit << 8) & 0xf000) + 0xfff; - bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1); - if (!bridge->io_head) { - err("out of memory\n"); - kfree(bridge); - return; - } - dbg("16bit I/O range: %04x-%04x\n", - (u32)bridge->io_head->base, - (u32)(bridge->io_head->base + bridge->io_head->length - 1)); - break; - case PCI_IO_RANGE_TYPE_32: - pci_read_config_word(bridge->pci_dev, PCI_IO_BASE_UPPER16, &tmp16); - base = ((u32)tmp16 << 16) | ((base << 8) & 0xf000); - pci_read_config_word(bridge->pci_dev, PCI_IO_LIMIT_UPPER16, &tmp16); - limit = (((u32)tmp16 << 16) | ((limit << 8) & 0xf000)) + 0xfff; - bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1); - if (!bridge->io_head) { - err("out of memory\n"); - kfree(bridge); - return; - } - dbg("32bit I/O range: %08x-%08x\n", - (u32)bridge->io_head->base, - (u32)(bridge->io_head->base + bridge->io_head->length - 1)); - break; - case 0x0f: - dbg("I/O space unsupported\n"); - break; - default: - warn("Unknown I/O range type\n"); - } - - /* Memory resources (mandatory for P2P bridge) */ - pci_read_config_word(bridge->pci_dev, PCI_MEMORY_BASE, &tmp16); - base = (tmp16 & 0xfff0) << 16; - pci_read_config_word(bridge->pci_dev, PCI_MEMORY_LIMIT, &tmp16); - limit = ((tmp16 & 0xfff0) << 16) | 0xfffff; - bridge->mem_head = acpiphp_make_resource((u64)base, limit - base + 1); - if (!bridge->mem_head) { - err("out of memory\n"); - kfree(bridge); - return; - } - dbg("32bit Memory range: %08x-%08x\n", - (u32)bridge->mem_head->base, - (u32)(bridge->mem_head->base + bridge->mem_head->length-1)); - - /* Prefetchable Memory resources (optional) */ - pci_read_config_word(bridge->pci_dev, PCI_PREF_MEMORY_BASE, &tmp16); - base = tmp16; - pci_read_config_word(bridge->pci_dev, PCI_PREF_MEMORY_LIMIT, &tmp16); - limit = tmp16; - - switch (base & PCI_MEMORY_RANGE_TYPE_MASK) { - case PCI_PREF_RANGE_TYPE_32: - base = (base & 0xfff0) << 16; - limit = ((limit & 0xfff0) << 16) | 0xfffff; - bridge->p_mem_head = acpiphp_make_resource((u64)base, limit - base + 1); - if (!bridge->p_mem_head) { - err("out of memory\n"); - kfree(bridge); - return; - } - dbg("32bit Prefetchable memory range: %08x-%08x\n", - (u32)bridge->p_mem_head->base, - (u32)(bridge->p_mem_head->base + bridge->p_mem_head->length - 1)); - break; - case PCI_PREF_RANGE_TYPE_64: - pci_read_config_dword(bridge->pci_dev, PCI_PREF_BASE_UPPER32, &base32u); - pci_read_config_dword(bridge->pci_dev, PCI_PREF_LIMIT_UPPER32, &limit32u); - base64 = ((u64)base32u << 32) | ((base & 0xfff0) << 16); - limit64 = (((u64)limit32u << 32) | ((limit & 0xfff0) << 16)) + 0xfffff; - - bridge->p_mem_head = acpiphp_make_resource(base64, limit64 - base64 + 1); - if (!bridge->p_mem_head) { - err("out of memory\n"); - kfree(bridge); - return; - } - dbg("64bit Prefetchable memory range: %08x%08x-%08x%08x\n", - (u32)(bridge->p_mem_head->base >> 32), - (u32)(bridge->p_mem_head->base & 0xffffffff), - (u32)((bridge->p_mem_head->base + bridge->p_mem_head->length - 1) >> 32), - (u32)((bridge->p_mem_head->base + bridge->p_mem_head->length - 1) & 0xffffffff)); - break; - case 0x0f: - break; - default: - warn("Unknown prefetchale memory type\n"); - } - - init_bridge_misc(bridge); -} - - -/* callback routine to find P2P bridges */ -static acpi_status -find_p2p_bridge (acpi_handle handle, u32 lvl, void *context, void **rv) -{ - acpi_status status; - acpi_handle dummy_handle; - unsigned long *segbus = context; - unsigned long tmp; - int seg, bus, device, function; - struct pci_dev *dev; - - /* get PCI address */ - seg = (*segbus >> 8) & 0xff; - bus = *segbus & 0xff; - - status = acpi_get_handle(handle, "_ADR", &dummy_handle); - if (ACPI_FAILURE(status)) - return AE_OK; /* continue */ - - status = acpi_evaluate_integer(handle, "_ADR", NULL, &tmp); - if (ACPI_FAILURE(status)) { - dbg("%s: _ADR evaluation failure\n", __FUNCTION__); - return AE_OK; - } - - device = (tmp >> 16) & 0xffff; - function = tmp & 0xffff; - - dev = pci_find_slot(bus, PCI_DEVFN(device, function)); - - if (!dev) - return AE_OK; - - if (!dev->subordinate) - return AE_OK; - - /* check if this bridge has ejectable slots */ - if (detect_ejectable_slots(handle) > 0) { - dbg("found PCI-to-PCI bridge at PCI %s\n", dev->slot_name); - add_p2p_bridge(handle, seg, bus, device, function); - } - - return AE_OK; -} - - -/* find hot-pluggable slots, and then find P2P bridge */ -static int add_bridges(struct acpi_device *device) -{ - acpi_handle *handle = device->handle; - acpi_status status; - unsigned long tmp; - int seg, bus; - acpi_handle dummy_handle; - - /* if the bridge doesn't have _STA, we assume it is always there */ - status = acpi_get_handle(handle, "_STA", &dummy_handle); - if (ACPI_SUCCESS(status)) { - status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp); - if (ACPI_FAILURE(status)) { - dbg("%s: _STA evaluation failure\n", __FUNCTION__); - return 0; - } - if ((tmp & ACPI_STA_FUNCTIONING) == 0) - /* don't register this object */ - return 0; - } - - /* get PCI segment number */ - status = acpi_evaluate_integer(handle, "_SEG", NULL, &tmp); - - seg = ACPI_SUCCESS(status) ? tmp : 0; - - /* get PCI bus number */ - status = acpi_evaluate_integer(handle, "_BBN", NULL, &tmp); - - if (ACPI_SUCCESS(status)) { - bus = tmp; - } else { - warn("can't get bus number, assuming 0\n"); - bus = 0; - } - - /* check if this bridge has ejectable slots */ - if (detect_ejectable_slots(handle) > 0) { - dbg("found PCI host-bus bridge with hot-pluggable slots\n"); - add_host_bridge(handle, seg, bus); - return 0; - } - - tmp = seg << 8 | bus; - - /* search P2P bridges under this host bridge */ - status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, - find_p2p_bridge, &tmp, NULL); - - if (ACPI_FAILURE(status)) - warn("find_p2p_bridge faied (error code = 0x%x)\n",status); - - return 0; -} - - -static int power_on_slot (struct acpiphp_slot *slot) -{ - acpi_status status; - struct acpiphp_func *func; - struct list_head *l; - int retval = 0; - - /* is this already enabled? */ - if (slot->flags & SLOT_POWEREDON) - goto err_exit; - - list_for_each (l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, sibling); - - if (func->flags & FUNC_HAS_PS0) { - dbg("%s: executing _PS0 on %s\n", __FUNCTION__, - func->pci_dev->slot_name); - status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL); - if (ACPI_FAILURE(status)) { - warn("%s: _PS0 failed\n", __FUNCTION__); - retval = -1; - goto err_exit; - } - } - } - - /* TBD: evaluate _STA to check if the slot is enabled */ - - slot->flags |= SLOT_POWEREDON; - - err_exit: - return retval; -} - - -static int power_off_slot (struct acpiphp_slot *slot) -{ - acpi_status status; - struct acpiphp_func *func; - struct list_head *l; - struct acpi_object_list arg_list; - union acpi_object arg; - - int retval = 0; - - /* is this already enabled? */ - if ((slot->flags & SLOT_POWEREDON) == 0) - goto err_exit; - - list_for_each (l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, sibling); - - if (func->flags & FUNC_HAS_PS3) { - dbg("%s: executing _PS3 on %s\n", __FUNCTION__, - func->pci_dev->slot_name); - status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL); - if (ACPI_FAILURE(status)) { - warn("%s: _PS3 failed\n", __FUNCTION__); - retval = -1; - goto err_exit; - } - } - } - - list_for_each (l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, sibling); - - if (func->flags & FUNC_HAS_EJ0) { - dbg("%s: executing _EJ0 on %s\n", __FUNCTION__, - func->pci_dev->slot_name); - - /* _EJ0 method take one argument */ - arg_list.count = 1; - arg_list.pointer = &arg; - arg.type = ACPI_TYPE_INTEGER; - arg.integer.value = 1; - - status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL); - if (ACPI_FAILURE(status)) { - warn("%s: _EJ0 failed\n", __FUNCTION__); - retval = -1; - goto err_exit; - } - } - } - - /* TBD: evaluate _STA to check if the slot is disabled */ - - slot->flags &= (~SLOT_POWEREDON); - - err_exit: - return retval; -} - - -/** - * enable_device - enable, configure a slot - * @slot: slot to be enabled - * - * This function should be called per *physical slot*, - * not per each slot object in ACPI namespace. - * - */ -static int enable_device (struct acpiphp_slot *slot) -{ - u8 bus; - struct pci_dev *dev; - struct pci_bus *child; - struct list_head *l; - struct acpiphp_func *func; - int retval = 0; - int num; - - if (slot->flags & SLOT_ENABLED) - goto err_exit; - - /* sanity check: dev should be NULL when hot-plugged in */ - dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0)); - if (dev) { - /* This case shouldn't happen */ - err("pci_dev structure already exists.\n"); - retval = -1; - goto err_exit; - } - - /* allocate resources to device */ - retval = acpiphp_configure_slot(slot); - if (retval) - goto err_exit; - - /* returned `dev' is the *first function* only! */ - num = pci_scan_slot(slot->bridge->pci_bus, PCI_DEVFN(slot->device, 0)); - if (num) - pci_bus_add_devices(slot->bridge->pci_bus); - dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0)); - - if (!dev) { - err("No new device found\n"); - retval = -1; - goto err_exit; - } - - if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - pci_read_config_byte(dev, PCI_SECONDARY_BUS, &bus); - child = (struct pci_bus*) pci_add_new_bus(dev->bus, dev, bus); - pci_do_scan_bus(child); - } - - /* associate pci_dev to our representation */ - list_for_each (l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, sibling); - - func->pci_dev = pci_find_slot(slot->bridge->bus, - PCI_DEVFN(slot->device, - func->function)); - if (!func->pci_dev) - continue; - - /* configure device */ - retval = acpiphp_configure_function(func); - if (retval) - goto err_exit; - } - - slot->flags |= SLOT_ENABLED; - - dbg("Available resources:\n"); - acpiphp_dump_resource(slot->bridge); - - err_exit: - return retval; -} - - -/** - * disable_device - disable a slot - */ -static int disable_device (struct acpiphp_slot *slot) -{ - int retval = 0; - struct acpiphp_func *func; - struct list_head *l; - - /* is this slot already disabled? */ - if (!(slot->flags & SLOT_ENABLED)) - goto err_exit; - - list_for_each (l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, sibling); - - if (func->pci_dev) { - if (acpiphp_unconfigure_function(func) == 0) { - func->pci_dev = NULL; - } else { - err("failed to unconfigure device\n"); - retval = -1; - goto err_exit; - } - } - } - - slot->flags &= (~SLOT_ENABLED); - - err_exit: - return retval; -} - - -/** - * get_slot_status - get ACPI slot status - * - * if a slot has _STA for each function and if any one of them - * returned non-zero status, return it - * - * if a slot doesn't have _STA and if any one of its functions' - * configuration space is configured, return 0x0f as a _STA - * - * otherwise return 0 - */ -static unsigned int get_slot_status (struct acpiphp_slot *slot) -{ - acpi_status status; - unsigned long sta = 0; - u32 dvid; - struct list_head *l; - struct acpiphp_func *func; - - list_for_each (l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, sibling); - - if (func->flags & FUNC_HAS_STA) { - status = acpi_evaluate_integer(func->handle, "_STA", NULL, &sta); - if (ACPI_SUCCESS(status) && sta) - break; - } else { - pci_bus_read_config_dword(slot->bridge->pci_bus, - PCI_DEVFN(slot->device, - func->function), - PCI_VENDOR_ID, &dvid); - if (dvid != 0xffffffff) { - sta = ACPI_STA_ALL; - break; - } - } - } - - return (unsigned int)sta; -} - - -/* - * ACPI event handlers - */ - -/** - * handle_hotplug_event_bridge - handle ACPI event on bridges - * - * @handle: Notify()'ed acpi_handle - * @type: Notify code - * @context: pointer to acpiphp_bridge structure - * - * handles ACPI event notification on {host,p2p} bridges - * - */ -static void handle_hotplug_event_bridge (acpi_handle handle, u32 type, void *context) -{ - struct acpiphp_bridge *bridge; - char objname[64]; - struct acpi_buffer buffer = { .length = sizeof(objname), - .pointer = objname }; - - bridge = (struct acpiphp_bridge *)context; - - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - - switch (type) { - case ACPI_NOTIFY_BUS_CHECK: - /* bus re-enumerate */ - dbg("%s: Bus check notify on %s\n", __FUNCTION__, objname); - acpiphp_check_bridge(bridge); - break; - - case ACPI_NOTIFY_DEVICE_CHECK: - /* device check */ - dbg("%s: Device check notify on %s\n", __FUNCTION__, objname); - acpiphp_check_bridge(bridge); - break; - - case ACPI_NOTIFY_DEVICE_WAKE: - /* wake event */ - dbg("%s: Device wake notify on %s\n", __FUNCTION__, objname); - break; - - case ACPI_NOTIFY_EJECT_REQUEST: - /* request device eject */ - dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname); - break; - - default: - warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); - break; - } -} - - -/** - * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots) - * - * @handle: Notify()'ed acpi_handle - * @type: Notify code - * @context: pointer to acpiphp_func structure - * - * handles ACPI event notification on slots - * - */ -static void handle_hotplug_event_func (acpi_handle handle, u32 type, void *context) -{ - struct acpiphp_func *func; - char objname[64]; - struct acpi_buffer buffer = { .length = sizeof(objname), - .pointer = objname }; - - acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); - - func = (struct acpiphp_func *)context; - - switch (type) { - case ACPI_NOTIFY_BUS_CHECK: - /* bus re-enumerate */ - dbg("%s: Bus check notify on %s\n", __FUNCTION__, objname); - acpiphp_enable_slot(func->slot); - break; - - case ACPI_NOTIFY_DEVICE_CHECK: - /* device check : re-enumerate from parent bus */ - dbg("%s: Device check notify on %s\n", __FUNCTION__, objname); - acpiphp_check_bridge(func->slot->bridge); - break; - - case ACPI_NOTIFY_DEVICE_WAKE: - /* wake event */ - dbg("%s: Device wake notify on %s\n", __FUNCTION__, objname); - break; - - case ACPI_NOTIFY_EJECT_REQUEST: - /* request device eject */ - dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname); - acpiphp_disable_slot(func->slot); - break; - - default: - warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); - break; - } -} - -static struct acpi_driver acpi_pci_hp_driver = { - .name = "pci_hp", - .class = "", - .ids = ACPI_PCI_HOST_HID, - .ops = { - .add = add_bridges, - } -}; - -/** - * acpiphp_glue_init - initializes all PCI hotplug - ACPI glue data structures - * - */ -int acpiphp_glue_init (void) -{ - acpi_status status; - - if (list_empty(&pci_root_buses)) - return -1; - - status = acpi_bus_register_driver(&acpi_pci_hp_driver); - - if (ACPI_FAILURE(status)) { - err("%s: acpi_walk_namespace() failed\n", __FUNCTION__); - return -1; - } - - return 0; -} - - -/** - * acpiphp_glue_exit - terminates all PCI hotplug - ACPI glue data structures - * - * This function frees all data allocated in acpiphp_glue_init() - */ -void acpiphp_glue_exit (void) -{ - struct list_head *l1, *l2, *n1, *n2; - struct acpiphp_bridge *bridge; - struct acpiphp_slot *slot, *next; - struct acpiphp_func *func; - acpi_status status; - - list_for_each_safe (l1, n1, &bridge_list) { - bridge = (struct acpiphp_bridge *)l1; - slot = bridge->slots; - while (slot) { - next = slot->next; - list_for_each_safe (l2, n2, &slot->funcs) { - func = list_entry(l2, struct acpiphp_func, sibling); - acpiphp_free_resource(&func->io_head); - acpiphp_free_resource(&func->mem_head); - acpiphp_free_resource(&func->p_mem_head); - acpiphp_free_resource(&func->bus_head); - status = acpi_remove_notify_handler(func->handle, - ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_func); - if (ACPI_FAILURE(status)) - err("failed to remove notify handler\n"); - kfree(func); - } - kfree(slot); - slot = next; - } - status = acpi_remove_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_bridge); - if (ACPI_FAILURE(status)) - err("failed to remove notify handler\n"); - - acpiphp_free_resource(&bridge->io_head); - acpiphp_free_resource(&bridge->mem_head); - acpiphp_free_resource(&bridge->p_mem_head); - acpiphp_free_resource(&bridge->bus_head); - - kfree(bridge); - } -} - - -/** - * acpiphp_get_num_slots - count number of slots in a system - */ -int acpiphp_get_num_slots (void) -{ - struct list_head *node; - struct acpiphp_bridge *bridge; - int num_slots; - - num_slots = 0; - - list_for_each (node, &bridge_list) { - bridge = (struct acpiphp_bridge *)node; - dbg("Bus%d %dslot(s)\n", bridge->bus, bridge->nr_slots); - num_slots += bridge->nr_slots; - } - - dbg("Total %dslots\n", num_slots); - return num_slots; -} - - -/** - * acpiphp_for_each_slot - call function for each slot - * @fn: callback function - * @data: context to be passed to callback function - * - */ -int acpiphp_for_each_slot(acpiphp_callback fn, void *data) -{ - struct list_head *node; - struct acpiphp_bridge *bridge; - struct acpiphp_slot *slot; - int retval = 0; - - list_for_each (node, &bridge_list) { - bridge = (struct acpiphp_bridge *)node; - for (slot = bridge->slots; slot; slot = slot->next) { - retval = fn(slot, data); - if (!retval) - goto err_exit; - } - } - - err_exit: - return retval; -} - - -/* search matching slot from id */ -struct acpiphp_slot *get_slot_from_id (int id) -{ - struct list_head *node; - struct acpiphp_bridge *bridge; - struct acpiphp_slot *slot; - - list_for_each (node, &bridge_list) { - bridge = (struct acpiphp_bridge *)node; - for (slot = bridge->slots; slot; slot = slot->next) - if (slot->id == id) - return slot; - } - - /* should never happen! */ - err("%s: no object for id %d\n",__FUNCTION__, id); - return 0; -} - - -/** - * acpiphp_enable_slot - power on slot - */ -int acpiphp_enable_slot (struct acpiphp_slot *slot) -{ - int retval; - - down(&slot->crit_sect); - - /* wake up all functions */ - retval = power_on_slot(slot); - if (retval) - goto err_exit; - - if (get_slot_status(slot) == ACPI_STA_ALL) - /* configure all functions */ - retval = enable_device(slot); - - err_exit: - up(&slot->crit_sect); - return retval; -} - - -/** - * acpiphp_disable_slot - power off slot - */ -int acpiphp_disable_slot (struct acpiphp_slot *slot) -{ - int retval = 0; - - down(&slot->crit_sect); - - /* unconfigure all functions */ - retval = disable_device(slot); - if (retval) - goto err_exit; - - /* power off all functions */ - retval = power_off_slot(slot); - if (retval) - goto err_exit; - - acpiphp_resource_sort_and_combine(&slot->bridge->io_head); - acpiphp_resource_sort_and_combine(&slot->bridge->mem_head); - acpiphp_resource_sort_and_combine(&slot->bridge->p_mem_head); - acpiphp_resource_sort_and_combine(&slot->bridge->bus_head); - dbg("Available resources:\n"); - acpiphp_dump_resource(slot->bridge); - - err_exit: - up(&slot->crit_sect); - return retval; -} - - -/** - * acpiphp_check_bridge - re-enumerate devices - */ -int acpiphp_check_bridge (struct acpiphp_bridge *bridge) -{ - struct acpiphp_slot *slot; - unsigned int sta; - int retval = 0; - int enabled, disabled; - - enabled = disabled = 0; - - for (slot = bridge->slots; slot; slot = slot->next) { - sta = get_slot_status(slot); - if (slot->flags & SLOT_ENABLED) { - /* if enabled but not present, disable */ - if (sta != ACPI_STA_ALL) { - retval = acpiphp_disable_slot(slot); - if (retval) { - err("Error occurred in enabling\n"); - up(&slot->crit_sect); - goto err_exit; - } - enabled++; - } - } else { - /* if disabled but present, enable */ - if (sta == ACPI_STA_ALL) { - retval = acpiphp_enable_slot(slot); - if (retval) { - err("Error occurred in enabling\n"); - up(&slot->crit_sect); - goto err_exit; - } - disabled++; - } - } - } - - dbg("%s: %d enabled, %d disabled\n", __FUNCTION__, enabled, disabled); - - err_exit: - return retval; -} - - -/* - * slot enabled: 1 - * slot disabled: 0 - */ -u8 acpiphp_get_power_status (struct acpiphp_slot *slot) -{ - unsigned int sta; - - sta = get_slot_status(slot); - - return (sta & ACPI_STA_ENABLED) ? 1 : 0; -} - - -/* - * attention LED ON: 1 - * OFF: 0 - * - * TBD - * no direct attention led status information via ACPI - * - */ -u8 acpiphp_get_attention_status (struct acpiphp_slot *slot) -{ - return 0; -} - - -/* - * latch closed: 1 - * latch open: 0 - */ -u8 acpiphp_get_latch_status (struct acpiphp_slot *slot) -{ - unsigned int sta; - - sta = get_slot_status(slot); - - return (sta & ACPI_STA_SHOW_IN_UI) ? 1 : 0; -} - - -/* - * adapter presence : 1 - * absence : 0 - */ -u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot) -{ - unsigned int sta; - - sta = get_slot_status(slot); - - return (sta == 0) ? 0 : 1; -} diff -Nru a/drivers/hotplug/acpiphp_pci.c b/drivers/hotplug/acpiphp_pci.c --- a/drivers/hotplug/acpiphp_pci.c Mon Jun 9 23:16:05 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,510 +0,0 @@ -/* - * ACPI PCI HotPlug PCI configuration space management - * - * Copyright (c) 1995,2001 Compaq Computer Corporation - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001,2002 IBM Corp. - * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) - * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) - * Copyright (c) 2002 NEC Corporation - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or - * NON INFRINGEMENT. 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. - * - * Send feedback to <t-kouchi@cq.jp.nec.com> - * - */ - -#include <linux/config.h> -#include <linux/kernel.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/acpi.h> -#include "pci_hotplug.h" -#include "acpiphp.h" - -#define MY_NAME "acpiphp_pci" - - -/* allocate mem/pmem/io resource to a new function */ -static int init_config_space (struct acpiphp_func *func) -{ - u32 bar, len; - u32 address[] = { - PCI_BASE_ADDRESS_0, - PCI_BASE_ADDRESS_1, - PCI_BASE_ADDRESS_2, - PCI_BASE_ADDRESS_3, - PCI_BASE_ADDRESS_4, - PCI_BASE_ADDRESS_5, - 0 - }; - int count; - struct acpiphp_bridge *bridge; - struct pci_resource *res; - struct pci_bus *pbus; - int bus, device, function; - unsigned int devfn; - u16 tmp; - - bridge = func->slot->bridge; - pbus = bridge->pci_bus; - bus = bridge->bus; - device = func->slot->device; - function = func->function; - devfn = PCI_DEVFN(device, function); - - for (count = 0; address[count]; count++) { /* for 6 BARs */ - pci_bus_write_config_dword(pbus, devfn, - address[count], 0xFFFFFFFF); - pci_bus_read_config_dword(pbus, devfn, address[count], &bar); - - if (!bar) /* This BAR is not implemented */ - continue; - - dbg("Device %02x.%02x BAR %d wants %x\n", device, function, count, bar); - - if (bar & PCI_BASE_ADDRESS_SPACE_IO) { - /* This is IO */ - - len = bar & 0xFFFFFFFC; - len = ~len + 1; - - dbg("len in IO %x, BAR %d\n", len, count); - - spin_lock(&bridge->res_lock); - res = acpiphp_get_io_resource(&bridge->io_head, len); - spin_unlock(&bridge->res_lock); - - if (!res) { - err("cannot allocate requested io for %02x:%02x.%d len %x\n", - bus, device, function, len); - return -1; - } - pci_bus_write_config_dword(pbus, devfn, - address[count], - (u32)res->base); - res->next = func->io_head; - func->io_head = res; - - } else { - /* This is Memory */ - if (bar & PCI_BASE_ADDRESS_MEM_PREFETCH) { - /* pfmem */ - - len = bar & 0xFFFFFFF0; - len = ~len + 1; - - dbg("len in PFMEM %x, BAR %d\n", len, count); - - spin_lock(&bridge->res_lock); - res = acpiphp_get_resource(&bridge->p_mem_head, len); - spin_unlock(&bridge->res_lock); - - if (!res) { - err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n", - bus, device, function, len); - return -1; - } - - pci_bus_write_config_dword(pbus, devfn, - address[count], - (u32)res->base); - - if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */ - dbg("inside the pfmem 64 case, count %d\n", count); - count += 1; - pci_bus_write_config_dword(pbus, devfn, - address[count], - (u32)(res->base >> 32)); - } - - res->next = func->p_mem_head; - func->p_mem_head = res; - - } else { - /* regular memory */ - - len = bar & 0xFFFFFFF0; - len = ~len + 1; - - dbg("len in MEM %x, BAR %d\n", len, count); - - spin_lock(&bridge->res_lock); - res = acpiphp_get_resource(&bridge->mem_head, len); - spin_unlock(&bridge->res_lock); - - if (!res) { - err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n", - bus, device, function, len); - return -1; - } - - pci_bus_write_config_dword(pbus, devfn, - address[count], - (u32)res->base); - - if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) { - /* takes up another dword */ - dbg("inside mem 64 case, reg. mem, count %d\n", count); - count += 1; - pci_bus_write_config_dword(pbus, devfn, - address[count], - (u32)(res->base >> 32)); - } - - res->next = func->mem_head; - func->mem_head = res; - - } - } - } - - /* disable expansion rom */ - pci_bus_write_config_dword(pbus, devfn, PCI_ROM_ADDRESS, 0x00000000); - - /* set PCI parameters from _HPP */ - pci_bus_write_config_byte(pbus, devfn, PCI_CACHE_LINE_SIZE, - bridge->hpp.cache_line_size); - pci_bus_write_config_byte(pbus, devfn, PCI_LATENCY_TIMER, - bridge->hpp.latency_timer); - - pci_bus_read_config_word(pbus, devfn, PCI_COMMAND, &tmp); - if (bridge->hpp.enable_SERR) - tmp |= PCI_COMMAND_SERR; - if (bridge->hpp.enable_PERR) - tmp |= PCI_COMMAND_PARITY; - pci_bus_write_config_word(pbus, devfn, PCI_COMMAND, tmp); - - return 0; -} - -/* detect_used_resource - subtract resource under dev from bridge */ -static int detect_used_resource (struct acpiphp_bridge *bridge, struct pci_dev *dev) -{ - u32 bar, len; - u64 base; - u32 address[] = { - PCI_BASE_ADDRESS_0, - PCI_BASE_ADDRESS_1, - PCI_BASE_ADDRESS_2, - PCI_BASE_ADDRESS_3, - PCI_BASE_ADDRESS_4, - PCI_BASE_ADDRESS_5, - 0 - }; - int count; - struct pci_resource *res; - - dbg("Device %s\n", dev->slot_name); - - for (count = 0; address[count]; count++) { /* for 6 BARs */ - pci_read_config_dword(dev, address[count], &bar); - - if (!bar) /* This BAR is not implemented */ - continue; - - pci_write_config_dword(dev, address[count], 0xFFFFFFFF); - pci_read_config_dword(dev, address[count], &len); - - if (len & PCI_BASE_ADDRESS_SPACE_IO) { - /* This is IO */ - base = bar & 0xFFFFFFFC; - len &= 0xFFFFFFFC; - len = ~len + 1; - - dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1); - - spin_lock(&bridge->res_lock); - res = acpiphp_get_resource_with_base(&bridge->io_head, base, len); - spin_unlock(&bridge->res_lock); - if (res) - kfree(res); - } else { - /* This is Memory */ - base = bar & 0xFFFFFFF0; - if (len & PCI_BASE_ADDRESS_MEM_PREFETCH) { - /* pfmem */ - - len &= 0xFFFFFFF0; - len = ~len + 1; - - if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */ - dbg("prefetch mem 64\n"); - count += 1; - } - dbg("BAR[%d] %08x - %08x (PMEM)\n", count, (u32)base, (u32)base + len - 1); - spin_lock(&bridge->res_lock); - res = acpiphp_get_resource_with_base(&bridge->p_mem_head, base, len); - spin_unlock(&bridge->res_lock); - if (res) - kfree(res); - } else { - /* regular memory */ - - len &= 0xFFFFFFF0; - len = ~len + 1; - - if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) { - /* takes up another dword */ - dbg("mem 64\n"); - count += 1; - } - dbg("BAR[%d] %08x - %08x (MEM)\n", count, (u32)base, (u32)base + len - 1); - spin_lock(&bridge->res_lock); - res = acpiphp_get_resource_with_base(&bridge->mem_head, base, len); - spin_unlock(&bridge->res_lock); - if (res) - kfree(res); - } - } - - pci_write_config_dword(dev, address[count], bar); - } - - return 0; -} - - -/* detect_pci_resource_bus - subtract resource under pci_bus */ -static void detect_used_resource_bus(struct acpiphp_bridge *bridge, struct pci_bus *bus) -{ - struct list_head *l; - struct pci_dev *dev; - - list_for_each (l, &bus->devices) { - dev = pci_dev_b(l); - detect_used_resource(bridge, dev); - /* XXX recursive call */ - if (dev->subordinate) - detect_used_resource_bus(bridge, dev->subordinate); - } -} - - -/** - * acpiphp_detect_pci_resource - detect resources under bridge - * @bridge: detect all resources already used under this bridge - * - * collect all resources already allocated for all devices under a bridge. - */ -int acpiphp_detect_pci_resource (struct acpiphp_bridge *bridge) -{ - detect_used_resource_bus(bridge, bridge->pci_bus); - - return 0; -} - - -/** - * acpiphp_init_slot_resource - gather resource usage information of a slot - * @slot: ACPI slot object to be checked, should have valid pci_dev member - * - * TBD: PCI-to-PCI bridge case - * use pci_dev->resource[] - */ -int acpiphp_init_func_resource (struct acpiphp_func *func) -{ - u64 base; - u32 bar, len; - u32 address[] = { - PCI_BASE_ADDRESS_0, - PCI_BASE_ADDRESS_1, - PCI_BASE_ADDRESS_2, - PCI_BASE_ADDRESS_3, - PCI_BASE_ADDRESS_4, - PCI_BASE_ADDRESS_5, - 0 - }; - int count; - struct pci_resource *res; - struct pci_dev *dev; - - dev = func->pci_dev; - dbg("Hot-pluggable device %s\n", dev->slot_name); - - for (count = 0; address[count]; count++) { /* for 6 BARs */ - pci_read_config_dword(dev, address[count], &bar); - - if (!bar) /* This BAR is not implemented */ - continue; - - pci_write_config_dword(dev, address[count], 0xFFFFFFFF); - pci_read_config_dword(dev, address[count], &len); - - if (len & PCI_BASE_ADDRESS_SPACE_IO) { - /* This is IO */ - base = bar & 0xFFFFFFFC; - len &= 0xFFFFFFFC; - len = ~len + 1; - - dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1); - - res = acpiphp_make_resource(base, len); - if (!res) - goto no_memory; - - res->next = func->io_head; - func->io_head = res; - - } else { - /* This is Memory */ - base = bar & 0xFFFFFFF0; - if (len & PCI_BASE_ADDRESS_MEM_PREFETCH) { - /* pfmem */ - - len &= 0xFFFFFFF0; - len = ~len + 1; - - if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */ - dbg("prefetch mem 64\n"); - count += 1; - } - dbg("BAR[%d] %08x - %08x (PMEM)\n", count, (u32)base, (u32)base + len - 1); - res = acpiphp_make_resource(base, len); - if (!res) - goto no_memory; - - res->next = func->p_mem_head; - func->p_mem_head = res; - - } else { - /* regular memory */ - - len &= 0xFFFFFFF0; - len = ~len + 1; - - if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) { - /* takes up another dword */ - dbg("mem 64\n"); - count += 1; - } - dbg("BAR[%d] %08x - %08x (MEM)\n", count, (u32)base, (u32)base + len - 1); - res = acpiphp_make_resource(base, len); - if (!res) - goto no_memory; - - res->next = func->mem_head; - func->mem_head = res; - - } - } - - pci_write_config_dword(dev, address[count], bar); - } -#if 1 - acpiphp_dump_func_resource(func); -#endif - - return 0; - - no_memory: - err("out of memory\n"); - acpiphp_free_resource(&func->io_head); - acpiphp_free_resource(&func->mem_head); - acpiphp_free_resource(&func->p_mem_head); - - return -1; -} - - -/** - * acpiphp_configure_slot - allocate PCI resources - * @slot: slot to be configured - * - * initializes a PCI functions on a device inserted - * into the slot - * - */ -int acpiphp_configure_slot (struct acpiphp_slot *slot) -{ - struct acpiphp_func *func; - struct list_head *l; - u8 hdr; - u32 dvid; - int retval = 0; - int is_multi = 0; - - pci_bus_read_config_byte(slot->bridge->pci_bus, - PCI_DEVFN(slot->device, 0), - PCI_HEADER_TYPE, &hdr); - - if (hdr & 0x80) - is_multi = 1; - - list_for_each (l, &slot->funcs) { - func = list_entry(l, struct acpiphp_func, sibling); - if (is_multi || func->function == 0) { - pci_bus_read_config_dword(slot->bridge->pci_bus, - PCI_DEVFN(slot->device, - func->function), - PCI_VENDOR_ID, &dvid); - if (dvid != 0xffffffff) { - retval = init_config_space(func); - if (retval) - break; - } - } - } - - return retval; -} - -/** - * acpiphp_configure_function - configure PCI function - * @func: function to be configured - * - * initializes a PCI functions on a device inserted - * into the slot - * - */ -int acpiphp_configure_function (struct acpiphp_func *func) -{ - /* all handled by the pci core now */ - return 0; -} - -/** - * acpiphp_unconfigure_function - unconfigure PCI function - * @func: function to be unconfigured - * - */ -int acpiphp_unconfigure_function (struct acpiphp_func *func) -{ - struct acpiphp_bridge *bridge; - int retval = 0; - - /* if pci_dev is NULL, ignore it */ - if (!func->pci_dev) - goto err_exit; - - pci_remove_bus_device(func->pci_dev); - - /* free all resources */ - bridge = func->slot->bridge; - - spin_lock(&bridge->res_lock); - acpiphp_move_resource(&func->io_head, &bridge->io_head); - acpiphp_move_resource(&func->mem_head, &bridge->mem_head); - acpiphp_move_resource(&func->p_mem_head, &bridge->p_mem_head); - acpiphp_move_resource(&func->bus_head, &bridge->bus_head); - spin_unlock(&bridge->res_lock); - - err_exit: - return retval; -} diff -Nru a/drivers/hotplug/acpiphp_res.c b/drivers/hotplug/acpiphp_res.c --- a/drivers/hotplug/acpiphp_res.c Mon Jun 9 23:16:10 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,699 +0,0 @@ -/* - * ACPI PCI HotPlug Utility functions - * - * Copyright (c) 1995,2001 Compaq Computer Corporation - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001 IBM Corp. - * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) - * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) - * Copyright (c) 2002 NEC Corporation - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or - * NON INFRINGEMENT. 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. - * - * Send feedback to <gregkh@us.ibm.com>,<h-aono@ap.jp.nec.com> - * - */ - -#include <linux/config.h> -#include <linux/module.h> - -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/proc_fs.h> -#include <linux/sysctl.h> -#include <linux/pci.h> -#include <linux/smp.h> -#include <linux/smp_lock.h> -#include <linux/init.h> - -#include <linux/string.h> -#include <linux/mm.h> -#include <linux/errno.h> -#include <linux/ioport.h> -#include <linux/slab.h> -#include <linux/interrupt.h> -#include <linux/timer.h> - -#include <linux/ioctl.h> -#include <linux/fcntl.h> - -#include <linux/list.h> - -#include "pci_hotplug.h" -#include "acpiphp.h" - -#define MY_NAME "acpiphp_res" - - -/* - * sort_by_size - sort nodes by their length, smallest first - */ -static int sort_by_size(struct pci_resource **head) -{ - struct pci_resource *current_res; - struct pci_resource *next_res; - int out_of_order = 1; - - if (!(*head)) - return 1; - - if (!((*head)->next)) - return 0; - - while (out_of_order) { - out_of_order = 0; - - /* Special case for swapping list head */ - if (((*head)->next) && - ((*head)->length > (*head)->next->length)) { - out_of_order++; - current_res = *head; - *head = (*head)->next; - current_res->next = (*head)->next; - (*head)->next = current_res; - } - - current_res = *head; - - while (current_res->next && current_res->next->next) { - if (current_res->next->length > current_res->next->next->length) { - out_of_order++; - next_res = current_res->next; - current_res->next = current_res->next->next; - current_res = current_res->next; - next_res->next = current_res->next; - current_res->next = next_res; - } else - current_res = current_res->next; - } - } /* End of out_of_order loop */ - - return 0; -} - - -/* - * sort_by_max_size - sort nodes by their length, largest first - */ -static int sort_by_max_size(struct pci_resource **head) -{ - struct pci_resource *current_res; - struct pci_resource *next_res; - int out_of_order = 1; - - if (!(*head)) - return 1; - - if (!((*head)->next)) - return 0; - - while (out_of_order) { - out_of_order = 0; - - /* Special case for swapping list head */ - if (((*head)->next) && - ((*head)->length < (*head)->next->length)) { - out_of_order++; - current_res = *head; - *head = (*head)->next; - current_res->next = (*head)->next; - (*head)->next = current_res; - } - - current_res = *head; - - while (current_res->next && current_res->next->next) { - if (current_res->next->length < current_res->next->next->length) { - out_of_order++; - next_res = current_res->next; - current_res->next = current_res->next->next; - current_res = current_res->next; - next_res->next = current_res->next; - current_res->next = next_res; - } else - current_res = current_res->next; - } - } /* End of out_of_order loop */ - - return 0; -} - -/** - * get_io_resource - get resource for I/O ports - * - * this function sorts the resource list by size and then - * returns the first node of "size" length that is not in the - * ISA aliasing window. If it finds a node larger than "size" - * it will split it up. - * - * size must be a power of two. - * - * difference from get_resource is handling of ISA aliasing space. - * - */ -struct pci_resource *acpiphp_get_io_resource (struct pci_resource **head, u32 size) -{ - struct pci_resource *prevnode; - struct pci_resource *node; - struct pci_resource *split_node; - u64 temp_qword; - - if (!(*head)) - return NULL; - - if (acpiphp_resource_sort_and_combine(head)) - return NULL; - - if (sort_by_size(head)) - return NULL; - - for (node = *head; node; node = node->next) { - if (node->length < size) - continue; - - if (node->base & (size - 1)) { - /* this one isn't base aligned properly - so we'll make a new entry and split it up */ - temp_qword = (node->base | (size-1)) + 1; - - /* Short circuit if adjusted size is too small */ - if ((node->length - (temp_qword - node->base)) < size) - continue; - - split_node = acpiphp_make_resource(node->base, temp_qword - node->base); - - if (!split_node) - return NULL; - - node->base = temp_qword; - node->length -= split_node->length; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of non-aligned base */ - - /* Don't need to check if too small since we already did */ - if (node->length > size) { - /* this one is longer than we need - so we'll make a new entry and split it up */ - split_node = acpiphp_make_resource(node->base + size, node->length - size); - - if (!split_node) - return NULL; - - node->length = size; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of too big on top end */ - - /* For IO make sure it's not in the ISA aliasing space */ - if (node->base & 0x300L) - continue; - - /* If we got here, then it is the right size - Now take it out of the list */ - if (*head == node) { - *head = node->next; - } else { - prevnode = *head; - while (prevnode->next != node) - prevnode = prevnode->next; - - prevnode->next = node->next; - } - node->next = NULL; - /* Stop looping */ - break; - } - - return node; -} - - -/** - * get_max_resource - get the largest resource - * - * Gets the largest node that is at least "size" big from the - * list pointed to by head. It aligns the node on top and bottom - * to "size" alignment before returning it. - */ -struct pci_resource *acpiphp_get_max_resource (struct pci_resource **head, u32 size) -{ - struct pci_resource *max; - struct pci_resource *temp; - struct pci_resource *split_node; - u64 temp_qword; - - if (!(*head)) - return NULL; - - if (acpiphp_resource_sort_and_combine(head)) - return NULL; - - if (sort_by_max_size(head)) - return NULL; - - for (max = *head;max; max = max->next) { - - /* If not big enough we could probably just bail, - instead we'll continue to the next. */ - if (max->length < size) - continue; - - if (max->base & (size - 1)) { - /* this one isn't base aligned properly - so we'll make a new entry and split it up */ - temp_qword = (max->base | (size-1)) + 1; - - /* Short circuit if adjusted size is too small */ - if ((max->length - (temp_qword - max->base)) < size) - continue; - - split_node = acpiphp_make_resource(max->base, temp_qword - max->base); - - if (!split_node) - return NULL; - - max->base = temp_qword; - max->length -= split_node->length; - - /* Put it next in the list */ - split_node->next = max->next; - max->next = split_node; - } - - if ((max->base + max->length) & (size - 1)) { - /* this one isn't end aligned properly at the top - so we'll make a new entry and split it up */ - temp_qword = ((max->base + max->length) & ~(size - 1)); - - split_node = acpiphp_make_resource(temp_qword, - max->length + max->base - temp_qword); - - if (!split_node) - return NULL; - - max->length -= split_node->length; - - /* Put it in the list */ - split_node->next = max->next; - max->next = split_node; - } - - /* Make sure it didn't shrink too much when we aligned it */ - if (max->length < size) - continue; - - /* Now take it out of the list */ - temp = (struct pci_resource*) *head; - if (temp == max) { - *head = max->next; - } else { - while (temp && temp->next != max) { - temp = temp->next; - } - - temp->next = max->next; - } - - max->next = NULL; - return max; - } - - /* If we get here, we couldn't find one */ - return NULL; -} - - -/** - * get_resource - get resource (mem, pfmem) - * - * this function sorts the resource list by size and then - * returns the first node of "size" length. If it finds a node - * larger than "size" it will split it up. - * - * size must be a power of two. - * - */ -struct pci_resource *acpiphp_get_resource (struct pci_resource **head, u32 size) -{ - struct pci_resource *prevnode; - struct pci_resource *node; - struct pci_resource *split_node; - u64 temp_qword; - - if (!(*head)) - return NULL; - - if (acpiphp_resource_sort_and_combine(head)) - return NULL; - - if (sort_by_size(head)) - return NULL; - - for (node = *head; node; node = node->next) { - dbg("%s: req_size =%x node=%p, base=%x, length=%x\n", - __FUNCTION__, size, node, (u32)node->base, node->length); - if (node->length < size) - continue; - - if (node->base & (size - 1)) { - dbg("%s: not aligned\n", __FUNCTION__); - /* this one isn't base aligned properly - so we'll make a new entry and split it up */ - temp_qword = (node->base | (size-1)) + 1; - - /* Short circuit if adjusted size is too small */ - if ((node->length - (temp_qword - node->base)) < size) - continue; - - split_node = acpiphp_make_resource(node->base, temp_qword - node->base); - - if (!split_node) - return NULL; - - node->base = temp_qword; - node->length -= split_node->length; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of non-aligned base */ - - /* Don't need to check if too small since we already did */ - if (node->length > size) { - dbg("%s: too big\n", __FUNCTION__); - /* this one is longer than we need - so we'll make a new entry and split it up */ - split_node = acpiphp_make_resource(node->base + size, node->length - size); - - if (!split_node) - return NULL; - - node->length = size; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of too big on top end */ - - dbg("%s: got one!!!\n", __FUNCTION__); - /* If we got here, then it is the right size - Now take it out of the list */ - if (*head == node) { - *head = node->next; - } else { - prevnode = *head; - while (prevnode->next != node) - prevnode = prevnode->next; - - prevnode->next = node->next; - } - node->next = NULL; - /* Stop looping */ - break; - } - return node; -} - -/** - * get_resource_with_base - get resource with specific base address - * - * this function - * returns the first node of "size" length located at specified base address. - * If it finds a node larger than "size" it will split it up. - * - * size must be a power of two. - * - */ -struct pci_resource *acpiphp_get_resource_with_base (struct pci_resource **head, u64 base, u32 size) -{ - struct pci_resource *prevnode; - struct pci_resource *node; - struct pci_resource *split_node; - u64 temp_qword; - - if (!(*head)) - return NULL; - - if (acpiphp_resource_sort_and_combine(head)) - return NULL; - - for (node = *head; node; node = node->next) { - dbg(": 1st req_base=%x req_size =%x node=%p, base=%x, length=%x\n", - (u32)base, size, node, (u32)node->base, node->length); - if (node->base > base) - continue; - - if ((node->base + node->length) < (base + size)) - continue; - - if (node->base < base) { - dbg(": split 1\n"); - /* this one isn't base aligned properly - so we'll make a new entry and split it up */ - temp_qword = base; - - /* Short circuit if adjusted size is too small */ - if ((node->length - (temp_qword - node->base)) < size) - continue; - - split_node = acpiphp_make_resource(node->base, temp_qword - node->base); - - if (!split_node) - return NULL; - - node->base = temp_qword; - node->length -= split_node->length; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } - - dbg(": 2nd req_base=%x req_size =%x node=%p, base=%x, length=%x\n", - (u32)base, size, node, (u32)node->base, node->length); - - /* Don't need to check if too small since we already did */ - if (node->length > size) { - dbg(": split 2\n"); - /* this one is longer than we need - so we'll make a new entry and split it up */ - split_node = acpiphp_make_resource(node->base + size, node->length - size); - - if (!split_node) - return NULL; - - node->length = size; - - /* Put it in the list */ - split_node->next = node->next; - node->next = split_node; - } /* End of too big on top end */ - - dbg(": got one!!!\n"); - /* If we got here, then it is the right size - Now take it out of the list */ - if (*head == node) { - *head = node->next; - } else { - prevnode = *head; - while (prevnode->next != node) - prevnode = prevnode->next; - - prevnode->next = node->next; - } - node->next = NULL; - /* Stop looping */ - break; - } - return node; -} - - -/** - * acpiphp_resource_sort_and_combine - * - * Sorts all of the nodes in the list in ascending order by - * their base addresses. Also does garbage collection by - * combining adjacent nodes. - * - * returns 0 if success - */ -int acpiphp_resource_sort_and_combine (struct pci_resource **head) -{ - struct pci_resource *node1; - struct pci_resource *node2; - int out_of_order = 1; - - if (!(*head)) - return 1; - - dbg("*head->next = %p\n",(*head)->next); - - if (!(*head)->next) - return 0; /* only one item on the list, already sorted! */ - - dbg("*head->base = 0x%x\n",(u32)(*head)->base); - dbg("*head->next->base = 0x%x\n", (u32)(*head)->next->base); - while (out_of_order) { - out_of_order = 0; - - /* Special case for swapping list head */ - if (((*head)->next) && - ((*head)->base > (*head)->next->base)) { - node1 = *head; - (*head) = (*head)->next; - node1->next = (*head)->next; - (*head)->next = node1; - out_of_order++; - } - - node1 = (*head); - - while (node1->next && node1->next->next) { - if (node1->next->base > node1->next->next->base) { - out_of_order++; - node2 = node1->next; - node1->next = node1->next->next; - node1 = node1->next; - node2->next = node1->next; - node1->next = node2; - } else - node1 = node1->next; - } - } /* End of out_of_order loop */ - - node1 = *head; - - while (node1 && node1->next) { - if ((node1->base + node1->length) == node1->next->base) { - /* Combine */ - dbg("8..\n"); - node1->length += node1->next->length; - node2 = node1->next; - node1->next = node1->next->next; - kfree(node2); - } else - node1 = node1->next; - } - - return 0; -} - - -/** - * acpiphp_make_resource - make resource structure - * @base: base address of a resource - * @length: length of a resource - */ -struct pci_resource *acpiphp_make_resource (u64 base, u32 length) -{ - struct pci_resource *res; - - res = kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (res) { - memset(res, 0, sizeof(struct pci_resource)); - res->base = base; - res->length = length; - } - - return res; -} - - -/** - * acpiphp_move_resource - move linked resources from one to another - * @from: head of linked resource list - * @to: head of linked resource list - */ -void acpiphp_move_resource (struct pci_resource **from, struct pci_resource **to) -{ - struct pci_resource *tmp; - - while (*from) { - tmp = (*from)->next; - (*from)->next = *to; - *to = *from; - *from = tmp; - } - - /* *from = NULL is guaranteed */ -} - - -/** - * acpiphp_free_resource - free all linked resources - * @res: head of linked resource list - */ -void acpiphp_free_resource (struct pci_resource **res) -{ - struct pci_resource *tmp; - - while (*res) { - tmp = (*res)->next; - kfree(*res); - *res = tmp; - } - - /* *res = NULL is guaranteed */ -} - - -/* debug support functions; will go away sometime :) */ -static void dump_resource(struct pci_resource *head) -{ - struct pci_resource *p; - int cnt; - - p = head; - cnt = 0; - - while (p) { - dbg("[%02d] %08x - %08x\n", - cnt++, (u32)p->base, (u32)p->base + p->length - 1); - p = p->next; - } -} - -void acpiphp_dump_resource(struct acpiphp_bridge *bridge) -{ - dbg("I/O resource:\n"); - dump_resource(bridge->io_head); - dbg("MEM resource:\n"); - dump_resource(bridge->mem_head); - dbg("PMEM resource:\n"); - dump_resource(bridge->p_mem_head); - dbg("BUS resource:\n"); - dump_resource(bridge->bus_head); -} - -void acpiphp_dump_func_resource(struct acpiphp_func *func) -{ - dbg("I/O resource:\n"); - dump_resource(func->io_head); - dbg("MEM resource:\n"); - dump_resource(func->mem_head); - dbg("PMEM resource:\n"); - dump_resource(func->p_mem_head); - dbg("BUS resource:\n"); - dump_resource(func->bus_head); -} diff -Nru a/drivers/hotplug/cpci_hotplug.h b/drivers/hotplug/cpci_hotplug.h --- a/drivers/hotplug/cpci_hotplug.h Mon Jun 9 23:16:08 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,100 +0,0 @@ -/* - * CompactPCI Hot Plug Core Functions - * - * Copyright (c) 2002 SOMA Networks, Inc. - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or - * NON INFRINGEMENT. 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. - * - * Send feedback to <scottm@somanetworks.com> - */ - -#ifndef _CPCI_HOTPLUG_H -#define _CPCI_HOTPLUG_H - -#include <linux/types.h> -#include <linux/pci.h> - -/* PICMG 2.12 R2.0 HS CSR bits: */ -#define HS_CSR_INS 0x0080 -#define HS_CSR_EXT 0x0040 -#define HS_CSR_PI 0x0030 -#define HS_CSR_LOO 0x0008 -#define HS_CSR_PIE 0x0004 -#define HS_CSR_EIM 0x0002 -#define HS_CSR_DHA 0x0001 - -#define SLOT_MAGIC 0x67267322 -struct slot { - u32 magic; - u8 number; - unsigned int devfn; - struct pci_bus *bus; - struct pci_dev *dev; - unsigned int extracting; - struct hotplug_slot *hotplug_slot; - struct list_head slot_list; -}; - -struct cpci_hp_controller_ops { - int (*query_enum) (void); - int (*enable_irq) (void); - int (*disable_irq) (void); - int (*check_irq) (void *dev_id); - int (*hardware_test) (struct slot* slot, u32 value); - u8 (*get_power) (struct slot* slot); - int (*set_power) (struct slot* slot, int value); -}; - -struct cpci_hp_controller { - unsigned int irq; - unsigned long irq_flags; - char *devname; - void *dev_id; - char *name; - struct cpci_hp_controller_ops *ops; -}; - -extern int cpci_hp_register_controller(struct cpci_hp_controller *controller); -extern int cpci_hp_unregister_controller(struct cpci_hp_controller *controller); -extern int cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last); -extern int cpci_hp_unregister_bus(struct pci_bus *bus); -extern struct slot *cpci_find_slot(struct pci_bus *bus, unsigned int devfn); -extern int cpci_hp_start(void); -extern int cpci_hp_stop(void); - -/* - * Internal function prototypes, these functions should not be used by - * board/chassis drivers. - */ -extern u8 cpci_get_attention_status(struct slot *slot); -extern u8 cpci_get_latch_status(struct slot *slot); -extern u8 cpci_get_adapter_status(struct slot *slot); -extern u16 cpci_get_hs_csr(struct slot * slot); -extern u16 cpci_set_hs_csr(struct slot * slot, u16 hs_csr); -extern int cpci_set_attention_status(struct slot *slot, int status); -extern int cpci_check_and_clear_ins(struct slot * slot); -extern int cpci_check_ext(struct slot * slot); -extern int cpci_clear_ext(struct slot * slot); -extern int cpci_led_on(struct slot * slot); -extern int cpci_led_off(struct slot * slot); -extern int cpci_configure_slot(struct slot *slot); -extern int cpci_unconfigure_slot(struct slot *slot); - -#endif /* _CPCI_HOTPLUG_H */ diff -Nru a/drivers/hotplug/cpci_hotplug_core.c b/drivers/hotplug/cpci_hotplug_core.c --- a/drivers/hotplug/cpci_hotplug_core.c Mon Jun 9 23:16:10 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,919 +0,0 @@ -/* - * CompactPCI Hot Plug Driver - * - * Copyright (c) 2002 SOMA Networks, Inc. - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or - * NON INFRINGEMENT. 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. - * - * Send feedback to <scottm@somanetworks.com> - */ - -#include <linux/config.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/interrupt.h> -#include <linux/smp_lock.h> -#include "pci_hotplug.h" -#include "cpci_hotplug.h" - -#define DRIVER_VERSION "0.2" -#define DRIVER_AUTHOR "Scott Murray <scottm@somanetworks.com>" -#define DRIVER_DESC "CompactPCI Hot Plug Core" - -#if !defined(CONFIG_HOTPLUG_CPCI_MODULE) -#define MY_NAME "cpci_hotplug" -#else -#define MY_NAME THIS_MODULE->name -#endif - -#define dbg(format, arg...) \ - do { \ - if(cpci_debug) \ - printk (KERN_DEBUG "%s: " format "\n", \ - MY_NAME , ## arg); \ - } while(0) -#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) -#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) -#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) - -/* local variables */ -static spinlock_t list_lock; -static LIST_HEAD(slot_list); -static int slots; -int cpci_debug; -static struct cpci_hp_controller *controller; -static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ -static struct semaphore thread_exit; /* guard ensure thread has exited before calling it quits */ -static int thread_finished = 1; - -static int enable_slot(struct hotplug_slot *slot); -static int disable_slot(struct hotplug_slot *slot); -static int set_attention_status(struct hotplug_slot *slot, u8 value); -static int get_power_status(struct hotplug_slot *slot, u8 * value); -static int get_attention_status(struct hotplug_slot *slot, u8 * value); -static int get_latch_status(struct hotplug_slot *slot, u8 * value); -static int get_adapter_status(struct hotplug_slot *slot, u8 * value); - -static struct hotplug_slot_ops cpci_hotplug_slot_ops = { - .owner = THIS_MODULE, - .enable_slot = enable_slot, - .disable_slot = disable_slot, - .set_attention_status = set_attention_status, - .hardware_test = NULL, - .get_power_status = get_power_status, - .get_attention_status = get_attention_status, - .get_latch_status = get_latch_status, - .get_adapter_status = get_adapter_status, -}; - -/* Inline functions to check the sanity of a pointer that is passed to us */ -static inline int -slot_paranoia_check(struct slot *slot, const char *function) -{ - if(!slot) { - dbg("%s - slot == NULL", function); - return -1; - } - if(slot->magic != SLOT_MAGIC) { - dbg("%s - bad magic number for slot", function); - return -1; - } - if(!slot->hotplug_slot) { - dbg("%s - slot->hotplug_slot == NULL!", function); - return -1; - } - return 0; -} - -static inline struct slot * -get_slot(struct hotplug_slot *hotplug_slot, const char *function) -{ - struct slot *slot; - - if(!hotplug_slot) { - dbg("%s - hotplug_slot == NULL", function); - return NULL; - } - - slot = (struct slot *) hotplug_slot->private; - if(slot_paranoia_check(slot, function)) - return NULL; - return slot; -} - -static int -update_latch_status(struct hotplug_slot *hotplug_slot, u8 value) -{ - struct hotplug_slot_info info; - - if(!(hotplug_slot && hotplug_slot->info)) - return -EINVAL; - memcpy(&info, hotplug_slot->info, sizeof(struct hotplug_slot_info)); - info.latch_status = value; - return pci_hp_change_slot_info(hotplug_slot, &info); -} - -static int -update_adapter_status(struct hotplug_slot *hotplug_slot, u8 value) -{ - struct hotplug_slot_info info; - - if(!(hotplug_slot && hotplug_slot->info)) - return -EINVAL; - memcpy(&info, hotplug_slot->info, sizeof(struct hotplug_slot_info)); - info.adapter_status = value; - return pci_hp_change_slot_info(hotplug_slot, &info); -} - -static int -enable_slot(struct hotplug_slot *hotplug_slot) -{ - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - int retval = 0; - - if(slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name); - - if(controller->ops->set_power) { - retval = controller->ops->set_power(slot, 1); - } - - return retval; -} - -static int -disable_slot(struct hotplug_slot *hotplug_slot) -{ - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - int retval = 0; - - if(slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name); - - /* Unconfigure device */ - dbg("%s - unconfiguring slot %s", - __FUNCTION__, slot->hotplug_slot->name); - if((retval = cpci_unconfigure_slot(slot))) { - err("%s - could not unconfigure slot %s", - __FUNCTION__, slot->hotplug_slot->name); - return retval; - } - dbg("%s - finished unconfiguring slot %s", - __FUNCTION__, slot->hotplug_slot->name); - - /* Clear EXT (by setting it) */ - if(cpci_clear_ext(slot)) { - err("%s - could not clear EXT for slot %s", - __FUNCTION__, slot->hotplug_slot->name); - retval = -ENODEV; - } - cpci_led_on(slot); - - if(controller->ops->set_power) { - retval = controller->ops->set_power(slot, 0); - } - - if(update_adapter_status(slot->hotplug_slot, 0)) { - warn("failure to update adapter file"); - } - - slot->extracting = 0; - - return retval; -} - -static u8 -cpci_get_power_status(struct slot *slot) -{ - u8 power = 1; - - if(controller->ops->get_power) { - power = controller->ops->get_power(slot); - } - return power; -} - -static int -get_power_status(struct hotplug_slot *hotplug_slot, u8 * value) -{ - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - - if(slot == NULL) - return -ENODEV; - *value = cpci_get_power_status(slot); - return 0; -} - -static int -get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value) -{ - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - - if(slot == NULL) - return -ENODEV; - *value = cpci_get_attention_status(slot); - return 0; -} - -static int -set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) -{ - struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); - - if(slot == NULL) - return -ENODEV; - switch (status) { - case 0: - cpci_set_attention_status(slot, 0); - break; - - case 1: - default: - cpci_set_attention_status(slot, 1); - break; - } - - return 0; -} - -static int -get_latch_status(struct hotplug_slot *hotplug_slot, u8 * value) -{ - if(hotplug_slot == NULL || hotplug_slot->info == NULL) - return -ENODEV; - *value = hotplug_slot->info->latch_status; - return 0; -} - -static int -get_adapter_status(struct hotplug_slot *hotplug_slot, u8 * value) -{ - if(hotplug_slot == NULL || hotplug_slot->info == NULL) - return -ENODEV; - *value = hotplug_slot->info->adapter_status; - return 0; -} - -#define SLOT_NAME_SIZE 6 -static void -make_slot_name(struct slot *slot) -{ - snprintf(slot->hotplug_slot->name, - SLOT_NAME_SIZE, "%02x:%02x", slot->bus->number, slot->number); -} - -int -cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last) -{ - struct slot *slot; - struct hotplug_slot *hotplug_slot; - struct hotplug_slot_info *info; - char *name; - int status = 0; - int i; - - if(!(controller && bus)) { - return -ENODEV; - } - if(last < first) { - return -EINVAL; - } - - /* - * Create a structure for each slot, and register that slot - * with the pci_hotplug subsystem. - */ - for (i = first; i <= last; ++i) { - slot = kmalloc(sizeof (struct slot), GFP_KERNEL); - if(!slot) - return -ENOMEM; - memset(slot, 0, sizeof (struct slot)); - - hotplug_slot = - kmalloc(sizeof (struct hotplug_slot), GFP_KERNEL); - if(!hotplug_slot) { - kfree(slot); - return -ENOMEM; - } - memset(hotplug_slot, 0, sizeof (struct hotplug_slot)); - slot->hotplug_slot = hotplug_slot; - - info = kmalloc(sizeof (struct hotplug_slot_info), GFP_KERNEL); - if(!info) { - kfree(hotplug_slot); - kfree(slot); - return -ENOMEM; - } - memset(info, 0, sizeof (struct hotplug_slot_info)); - hotplug_slot->info = info; - - name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL); - if(!name) { - kfree(info); - kfree(hotplug_slot); - kfree(slot); - return -ENOMEM; - } - hotplug_slot->name = name; - - slot->magic = SLOT_MAGIC; - slot->bus = bus; - slot->number = i; - slot->devfn = PCI_DEVFN(i, 0); - - hotplug_slot->private = slot; - make_slot_name(slot); - hotplug_slot->ops = &cpci_hotplug_slot_ops; - - /* - * Initialize the slot info structure with some known - * good values. - */ - dbg("initializing slot %s", slot->hotplug_slot->name); - info->power_status = cpci_get_power_status(slot); - info->attention_status = cpci_get_attention_status(slot); - - dbg("registering slot %s", slot->hotplug_slot->name); - status = pci_hp_register(slot->hotplug_slot); - if(status) { - err("pci_hp_register failed with error %d", status); - kfree(info); - kfree(name); - kfree(hotplug_slot); - kfree(slot); - return status; - } - - /* Add slot to our internal list */ - spin_lock(&list_lock); - list_add(&slot->slot_list, &slot_list); - slots++; - spin_unlock(&list_lock); - } - return status; -} - -int -cpci_hp_unregister_bus(struct pci_bus *bus) -{ - struct slot *slot; - struct list_head *tmp; - int status; - - if(!bus) { - return -ENODEV; - } - - spin_lock(&list_lock); - if(!slots) { - spin_unlock(&list_lock); - return -1; - } - list_for_each(tmp, &slot_list) { - slot = list_entry(tmp, struct slot, slot_list); - if(slot->bus == bus) { - dbg("deregistering slot %s", slot->hotplug_slot->name); - status = pci_hp_deregister(slot->hotplug_slot); - if(status) { - err("pci_hp_deregister failed with error %d", - status); - return status; - } - - list_del(&slot->slot_list); - kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot->name); - kfree(slot->hotplug_slot); - kfree(slot); - - slots--; - } - } - spin_unlock(&list_lock); - return 0; -} - -struct slot * -cpci_find_slot(struct pci_bus *bus, unsigned int devfn) -{ - struct slot *slot; - struct slot *found; - struct list_head *tmp; - - if(!bus) { - return NULL; - } - - spin_lock(&list_lock); - if(!slots) { - spin_unlock(&list_lock); - return NULL; - } - found = NULL; - list_for_each(tmp, &slot_list) { - slot = list_entry(tmp, struct slot, slot_list); - if(slot->bus == bus && slot->devfn == devfn) { - found = slot; - break; - } - } - spin_unlock(&list_lock); - return found; -} - -/* This is the interrupt mode interrupt handler */ -irqreturn_t -cpci_hp_intr(int irq, void *data, struct pt_regs *regs) -{ - dbg("entered cpci_hp_intr"); - - /* Check to see if it was our interrupt */ - if((controller->irq_flags & SA_SHIRQ) && - !controller->ops->check_irq(controller->dev_id)) { - dbg("exited cpci_hp_intr, not our interrupt"); - return IRQ_NONE; - } - - /* Disable ENUM interrupt */ - controller->ops->disable_irq(); - - /* Trigger processing by the event thread */ - dbg("Signal event_semaphore"); - up(&event_semaphore); - dbg("exited cpci_hp_intr"); - return IRQ_HANDLED; -} - -/* - * According to PICMG 2.12 R2.0, section 6.3.2, upon - * initialization, the system driver shall clear the - * INS bits of the cold-inserted devices. - */ -static int -init_slots(void) -{ - struct slot *slot; - struct list_head *tmp; - struct pci_dev* dev; - - dbg("%s - enter", __FUNCTION__); - spin_lock(&list_lock); - if(!slots) { - spin_unlock(&list_lock); - return -1; - } - list_for_each(tmp, &slot_list) { - slot = list_entry(tmp, struct slot, slot_list); - dbg("%s - looking at slot %s", - __FUNCTION__, slot->hotplug_slot->name); - if(cpci_check_and_clear_ins(slot)) { - dbg("%s - cleared INS for slot %s", - __FUNCTION__, slot->hotplug_slot->name); - dev = pci_find_slot(slot->bus->number, PCI_DEVFN(slot->number, 0)); - if(dev) { - if(update_adapter_status(slot->hotplug_slot, 1)) { - warn("failure to update adapter file"); - } - if(update_latch_status(slot->hotplug_slot, 1)) { - warn("failure to update latch file"); - } - slot->dev = dev; - } else { - err("%s - no driver attached to device in slot %s", - __FUNCTION__, slot->hotplug_slot->name); - } - } - } - spin_unlock(&list_lock); - dbg("%s - exit", __FUNCTION__); - return 0; -} - -static int -check_slots(void) -{ - struct slot *slot; - struct list_head *tmp; - int extracted; - int inserted; - - spin_lock(&list_lock); - if(!slots) { - spin_unlock(&list_lock); - err("no slots registered, shutting down"); - return -1; - } - extracted = inserted = 0; - list_for_each(tmp, &slot_list) { - slot = list_entry(tmp, struct slot, slot_list); - dbg("%s - looking at slot %s", - __FUNCTION__, slot->hotplug_slot->name); - if(cpci_check_and_clear_ins(slot)) { - u16 hs_csr; - - /* Some broken hardware (e.g. PLX 9054AB) asserts ENUM# twice... */ - if(slot->dev) { - warn("slot %s already inserted", slot->hotplug_slot->name); - inserted++; - continue; - } - - /* Process insertion */ - dbg("%s - slot %s inserted", - __FUNCTION__, slot->hotplug_slot->name); - - /* GSM, debug */ - hs_csr = cpci_get_hs_csr(slot); - dbg("%s - slot %s HS_CSR (1) = %04x", - __FUNCTION__, slot->hotplug_slot->name, hs_csr); - - /* Configure device */ - dbg("%s - configuring slot %s", - __FUNCTION__, slot->hotplug_slot->name); - if(cpci_configure_slot(slot)) { - err("%s - could not configure slot %s", - __FUNCTION__, slot->hotplug_slot->name); - continue; - } - dbg("%s - finished configuring slot %s", - __FUNCTION__, slot->hotplug_slot->name); - - /* GSM, debug */ - hs_csr = cpci_get_hs_csr(slot); - dbg("%s - slot %s HS_CSR (2) = %04x", - __FUNCTION__, slot->hotplug_slot->name, hs_csr); - - if(update_latch_status(slot->hotplug_slot, 1)) { - warn("failure to update latch file"); - } - - if(update_adapter_status(slot->hotplug_slot, 1)) { - warn("failure to update adapter file"); - } - - cpci_led_off(slot); - - /* GSM, debug */ - hs_csr = cpci_get_hs_csr(slot); - dbg("%s - slot %s HS_CSR (3) = %04x", - __FUNCTION__, slot->hotplug_slot->name, hs_csr); - - inserted++; - } else if(cpci_check_ext(slot)) { - u16 hs_csr; - - /* Process extraction request */ - dbg("%s - slot %s extracted", - __FUNCTION__, slot->hotplug_slot->name); - - /* GSM, debug */ - hs_csr = cpci_get_hs_csr(slot); - dbg("%s - slot %s HS_CSR = %04x", - __FUNCTION__, slot->hotplug_slot->name, hs_csr); - - if(!slot->extracting) { - if(update_latch_status(slot->hotplug_slot, 0)) { - warn("failure to update latch file"); - } - slot->extracting = 1; - } - extracted++; - } - } - spin_unlock(&list_lock); - if(inserted || extracted) { - return extracted; - } - else { - err("cannot find ENUM# source, shutting down"); - return -1; - } -} - -/* This is the interrupt mode worker thread body */ -static int -event_thread(void *data) -{ - int rc; - struct slot *slot; - struct list_head *tmp; - - lock_kernel(); - daemonize("cpci_hp_eventd"); - unlock_kernel(); - - dbg("%s - event thread started", __FUNCTION__); - while(1) { - dbg("event thread sleeping"); - down_interruptible(&event_semaphore); - dbg("event thread woken, thread_finished = %d", - thread_finished); - if(thread_finished || signal_pending(current)) - break; - while(controller->ops->query_enum()) { - rc = check_slots(); - if(rc > 0) { - /* Give userspace a chance to handle extraction */ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ / 2); - } else if(rc < 0) { - dbg("%s - error checking slots", __FUNCTION__); - thread_finished = 1; - break; - } - } - /* Check for someone yanking out a board */ - list_for_each(tmp, &slot_list) { - slot = list_entry(tmp, struct slot, slot_list); - if(slot->extracting) { - /* - * Hmmm, we're likely hosed at this point, should we - * bother trying to tell the driver or not? - */ - err("card in slot %s was improperly removed", - slot->hotplug_slot->name); - if(update_adapter_status(slot->hotplug_slot, 0)) { - warn("failure to update adapter file"); - } - slot->extracting = 0; - } - } - - /* Re-enable ENUM# interrupt */ - dbg("%s - re-enabling irq", __FUNCTION__); - controller->ops->enable_irq(); - } - - dbg("%s - event thread signals exit", __FUNCTION__); - up(&thread_exit); - return 0; -} - -/* This is the polling mode worker thread body */ -static int -poll_thread(void *data) -{ - int rc; - struct slot *slot; - struct list_head *tmp; - - lock_kernel(); - daemonize("cpci_hp_polld"); - unlock_kernel(); - - while(1) { - if(thread_finished || signal_pending(current)) - break; - - while(controller->ops->query_enum()) { - rc = check_slots(); - if(rc > 0) { - /* Give userspace a chance to handle extraction */ - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ / 2); - } else if(rc < 0) { - dbg("%s - error checking slots", __FUNCTION__); - thread_finished = 1; - break; - } - } - /* Check for someone yanking out a board */ - list_for_each(tmp, &slot_list) { - slot = list_entry(tmp, struct slot, slot_list); - if(slot->extracting) { - /* - * Hmmm, we're likely hosed at this point, should we - * bother trying to tell the driver or not? - */ - err("card in slot %s was improperly removed", - slot->hotplug_slot->name); - if(update_adapter_status(slot->hotplug_slot, 0)) { - warn("failure to update adapter file"); - } - slot->extracting = 0; - } - } - - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(HZ / 10); - } - dbg("poll thread signals exit"); - up(&thread_exit); - return 0; -} - -static int -cpci_start_thread(void) -{ - int pid; - - /* initialize our semaphores */ - init_MUTEX_LOCKED(&event_semaphore); - init_MUTEX_LOCKED(&thread_exit); - thread_finished = 0; - - if(controller->irq) { - pid = kernel_thread(event_thread, 0, 0); - } else { - pid = kernel_thread(poll_thread, 0, 0); - } - if(pid < 0) { - err("Can't start up our thread"); - return -1; - } - dbg("Our thread pid = %d", pid); - return 0; -} - -static void -cpci_stop_thread(void) -{ - thread_finished = 1; - dbg("thread finish command given"); - if(controller->irq) { - up(&event_semaphore); - } - dbg("wait for thread to exit"); - down(&thread_exit); -} - -int -cpci_hp_register_controller(struct cpci_hp_controller *new_controller) -{ - int status = 0; - - if(!controller) { - controller = new_controller; - if(controller->irq) { - if(request_irq(controller->irq, - cpci_hp_intr, - controller->irq_flags, - MY_NAME, controller->dev_id)) { - err("Can't get irq %d for the hotplug cPCI controller", controller->irq); - status = -ENODEV; - } - dbg("%s - acquired controller irq %d", __FUNCTION__, - controller->irq); - } - } else { - err("cPCI hotplug controller already registered"); - status = -1; - } - return status; -} - -int -cpci_hp_unregister_controller(struct cpci_hp_controller *old_controller) -{ - int status = 0; - - if(controller) { - if(!thread_finished) { - cpci_stop_thread(); - } - if(controller->irq) { - free_irq(controller->irq, controller->dev_id); - } - controller = NULL; - } else { - status = -ENODEV; - } - return status; -} - -int -cpci_hp_start(void) -{ - static int first = 1; - int status; - - dbg("%s - enter", __FUNCTION__); - if(!controller) { - return -ENODEV; - } - - spin_lock(&list_lock); - if(!slots) { - spin_unlock(&list_lock); - return -ENODEV; - } - spin_unlock(&list_lock); - - if(first) { - status = init_slots(); - if(status) { - return status; - } - first = 0; - } - - status = cpci_start_thread(); - if(status) { - return status; - } - dbg("%s - thread started", __FUNCTION__); - - if(controller->irq) { - /* Start enum interrupt processing */ - dbg("%s - enabling irq", __FUNCTION__); - controller->ops->enable_irq(); - } - dbg("%s - exit", __FUNCTION__); - return 0; -} - -int -cpci_hp_stop(void) -{ - if(!controller) { - return -ENODEV; - } - - if(controller->irq) { - /* Stop enum interrupt processing */ - dbg("%s - disabling irq", __FUNCTION__); - controller->ops->disable_irq(); - } - cpci_stop_thread(); - return 0; -} - -static void __exit -cleanup_slots(void) -{ - struct list_head *tmp; - struct slot *slot; - - /* - * Unregister all of our slots with the pci_hotplug subsystem, - * and free up all memory that we had allocated. - */ - spin_lock(&list_lock); - if(!slots) { - goto null_cleanup; - } - list_for_each(tmp, &slot_list) { - slot = list_entry(tmp, struct slot, slot_list); - list_del(&slot->slot_list); - pci_hp_deregister(slot->hotplug_slot); - kfree(slot->hotplug_slot->info); - kfree(slot->hotplug_slot->name); - kfree(slot->hotplug_slot); - kfree(slot); - } - null_cleanup: - spin_unlock(&list_lock); - return; -} - -int __init -cpci_hotplug_init(int debug) -{ - spin_lock_init(&list_lock); - cpci_debug = debug; - - info(DRIVER_DESC " version: " DRIVER_VERSION); - return 0; -} - -void __exit -cpci_hotplug_exit(void) -{ - /* - * Clean everything up. - */ - cleanup_slots(); -} - - -EXPORT_SYMBOL_GPL(cpci_hp_register_controller); -EXPORT_SYMBOL_GPL(cpci_hp_unregister_controller); -EXPORT_SYMBOL_GPL(cpci_hp_register_bus); -EXPORT_SYMBOL_GPL(cpci_hp_unregister_bus); -EXPORT_SYMBOL_GPL(cpci_find_slot); -EXPORT_SYMBOL_GPL(cpci_hp_start); -EXPORT_SYMBOL_GPL(cpci_hp_stop); diff -Nru a/drivers/hotplug/cpci_hotplug_pci.c b/drivers/hotplug/cpci_hotplug_pci.c --- a/drivers/hotplug/cpci_hotplug_pci.c Mon Jun 9 23:16:15 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,647 +0,0 @@ -/* - * CompactPCI Hot Plug Driver PCI functions - * - * Copyright (c) 2002 by SOMA Networks, Inc. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or - * NON INFRINGEMENT. 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. - * - * Send feedback to <scottm@somanetworks.com> - */ - -#include <linux/config.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/pci.h> -#include <linux/proc_fs.h> -#include "pci_hotplug.h" -#include "cpci_hotplug.h" - -#if !defined(CONFIG_HOTPLUG_CPCI_MODULE) -#define MY_NAME "cpci_hotplug" -#else -#define MY_NAME THIS_MODULE->name -#endif - -extern int cpci_debug; - -#define dbg(format, arg...) \ - do { \ - if(cpci_debug) \ - printk (KERN_DEBUG "%s: " format "\n", \ - MY_NAME , ## arg); \ - } while(0) -#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) -#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) -#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) - -#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1)) - - -u8 cpci_get_attention_status(struct slot* slot) -{ - int hs_cap; - u16 hs_csr; - - hs_cap = pci_bus_find_capability(slot->bus, - slot->devfn, - PCI_CAP_ID_CHSWP); - if(!hs_cap) { - return 0; - } - - if(pci_bus_read_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - &hs_csr)) { - return 0; - } - return hs_csr & 0x0008 ? 1 : 0; -} - -int cpci_set_attention_status(struct slot* slot, int status) -{ - int hs_cap; - u16 hs_csr; - - hs_cap = pci_bus_find_capability(slot->bus, - slot->devfn, - PCI_CAP_ID_CHSWP); - if(!hs_cap) { - return 0; - } - - if(pci_bus_read_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - &hs_csr)) { - return 0; - } - if(status) { - hs_csr |= HS_CSR_LOO; - } else { - hs_csr &= ~HS_CSR_LOO; - } - if(pci_bus_write_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - hs_csr)) { - return 0; - } - return 1; -} - -u16 cpci_get_hs_csr(struct slot* slot) -{ - int hs_cap; - u16 hs_csr; - - hs_cap = pci_bus_find_capability(slot->bus, - slot->devfn, - PCI_CAP_ID_CHSWP); - if(!hs_cap) { - return 0xFFFF; - } - - if(pci_bus_read_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - &hs_csr)) { - return 0xFFFF; - } - return hs_csr; -} - -u16 cpci_set_hs_csr(struct slot* slot, u16 hs_csr) -{ - int hs_cap; - u16 new_hs_csr; - - hs_cap = pci_bus_find_capability(slot->bus, - slot->devfn, - PCI_CAP_ID_CHSWP); - if(!hs_cap) { - return 0xFFFF; - } - - /* Write out the new value */ - if(pci_bus_write_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - hs_csr)) { - return 0xFFFF; - } - - /* Read back what we just wrote out */ - if(pci_bus_read_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - &new_hs_csr)) { - return 0xFFFF; - } - return new_hs_csr; -} - -int cpci_check_and_clear_ins(struct slot* slot) -{ - int hs_cap; - u16 hs_csr; - int ins = 0; - - hs_cap = pci_bus_find_capability(slot->bus, - slot->devfn, - PCI_CAP_ID_CHSWP); - if(!hs_cap) { - return 0; - } - if(pci_bus_read_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - &hs_csr)) { - return 0; - } - if(hs_csr & HS_CSR_INS) { - /* Clear INS (by setting it) */ - if(pci_bus_write_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - hs_csr)) { - ins = 0; - } - ins = 1; - } - return ins; -} - -int cpci_check_ext(struct slot* slot) -{ - int hs_cap; - u16 hs_csr; - int ext = 0; - - hs_cap = pci_bus_find_capability(slot->bus, - slot->devfn, - PCI_CAP_ID_CHSWP); - if(!hs_cap) { - return 0; - } - if(pci_bus_read_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - &hs_csr)) { - return 0; - } - if(hs_csr & HS_CSR_EXT) { - ext = 1; - } - return ext; -} - -int cpci_clear_ext(struct slot* slot) -{ - int hs_cap; - u16 hs_csr; - - hs_cap = pci_bus_find_capability(slot->bus, - slot->devfn, - PCI_CAP_ID_CHSWP); - if(!hs_cap) { - return -ENODEV; - } - if(pci_bus_read_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - &hs_csr)) { - return -ENODEV; - } - if(hs_csr & HS_CSR_EXT) { - /* Clear EXT (by setting it) */ - if(pci_bus_write_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - hs_csr)) { - return -ENODEV; - } - } - return 0; -} - -int cpci_led_on(struct slot* slot) -{ - int hs_cap; - u16 hs_csr; - - hs_cap = pci_bus_find_capability(slot->bus, - slot->devfn, - PCI_CAP_ID_CHSWP); - if(!hs_cap) { - return -ENODEV; - } - if(pci_bus_read_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - &hs_csr)) { - return -ENODEV; - } - if((hs_csr & HS_CSR_LOO) != HS_CSR_LOO) { - /* Set LOO */ - hs_csr |= HS_CSR_LOO; - if(pci_bus_write_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - hs_csr)) { - err("Could not set LOO for slot %s", - slot->hotplug_slot->name); - return -ENODEV; - } - } - return 0; -} - -int cpci_led_off(struct slot* slot) -{ - int hs_cap; - u16 hs_csr; - - hs_cap = pci_bus_find_capability(slot->bus, - slot->devfn, - PCI_CAP_ID_CHSWP); - if(!hs_cap) { - return -ENODEV; - } - if(pci_bus_read_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - &hs_csr)) { - return -ENODEV; - } - if(hs_csr & HS_CSR_LOO) { - /* Clear LOO */ - hs_csr &= ~HS_CSR_LOO; - if(pci_bus_write_config_word(slot->bus, - slot->devfn, - hs_cap + 2, - hs_csr)) { - err("Could not clear LOO for slot %s", - slot->hotplug_slot->name); - return -ENODEV; - } - } - return 0; -} - - -/* - * Device configuration functions - */ - -static int cpci_configure_dev(struct pci_bus *bus, struct pci_dev *dev) -{ - u8 irq_pin; - int r; - - dbg("%s - enter", __FUNCTION__); - - /* NOTE: device already setup from prior scan */ - - /* FIXME: How would we know if we need to enable the expansion ROM? */ - pci_write_config_word(dev, PCI_ROM_ADDRESS, 0x00L); - - /* Assign resources */ - dbg("assigning resources for %02x:%02x.%x", - dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - for (r = 0; r < 6; r++) { - struct resource *res = dev->resource + r; - if(res->flags) - pci_assign_resource(dev, r); - } - dbg("finished assigning resources for %02x:%02x.%x", - dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - - /* Does this function have an interrupt at all? */ - dbg("checking for function interrupt"); - pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq_pin); - if(irq_pin) { - dbg("function uses interrupt pin %d", irq_pin); - } - - /* - * Need to explicitly set irq field to 0 so that it'll get assigned - * by the pcibios platform dependent code called by pci_enable_device. - */ - dev->irq = 0; - - dbg("enabling device"); - pci_enable_device(dev); /* XXX check return */ - dbg("now dev->irq = %d", dev->irq); - if(irq_pin && dev->irq) { - pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); - } - - /* Can't use pci_insert_device at the moment, do it manually for now */ - pci_proc_attach_device(dev); - dbg("notifying drivers"); - //pci_announce_device_to_drivers(dev); - dbg("%s - exit", __FUNCTION__); - return 0; -} - -static int cpci_configure_bridge(struct pci_bus* bus, struct pci_dev* dev) -{ - int rc; - struct pci_bus* child; - struct resource* r; - u8 max, n; - u16 command; - - dbg("%s - enter", __FUNCTION__); - - /* Do basic bridge initialization */ - rc = pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40); - if(rc) { - printk(KERN_ERR "%s - write of PCI_LATENCY_TIMER failed\n", __FUNCTION__); - } - rc = pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 0x40); - if(rc) { - printk(KERN_ERR "%s - write of PCI_SEC_LATENCY_TIMER failed\n", __FUNCTION__); - } - rc = pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES / 4); - if(rc) { - printk(KERN_ERR "%s - write of PCI_CACHE_LINE_SIZE failed\n", __FUNCTION__); - } - - /* - * Set parent bridge's subordinate field so that configuration space - * access will work in pci_scan_bridge and friends. - */ - max = pci_max_busnr(); - bus->subordinate = max + 1; - pci_write_config_byte(bus->self, PCI_SUBORDINATE_BUS, max + 1); - - /* Scan behind bridge */ - n = pci_scan_bridge(bus, dev, max, 2); - child = pci_find_bus(max + 1); - if (!child) - return -ENODEV; -#ifdef CONFIG_PROC_FS - pci_proc_attach_bus(child); -#endif - /* - * Update parent bridge's subordinate field if there were more bridges - * behind the bridge that was scanned. - */ - if(n > max) { - bus->subordinate = n; - pci_write_config_byte(bus->self, PCI_SUBORDINATE_BUS, n); - } - - /* - * Update the bridge resources of the bridge to accommodate devices - * behind it. - */ - pci_bus_size_bridges(child); - pci_bus_assign_resources(child); - - /* Enable resource mapping via command register */ - command = PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | PCI_COMMAND_SERR; - r = child->resource[0]; - if(r && r->start) { - command |= PCI_COMMAND_IO; - } - r = child->resource[1]; - if(r && r->start) { - command |= PCI_COMMAND_MEMORY; - } - r = child->resource[2]; - if(r && r->start) { - command |= PCI_COMMAND_MEMORY; - } - rc = pci_write_config_word(dev, PCI_COMMAND, command); - if(rc) { - err("Error setting command register"); - return rc; - } - - /* Set bridge control register */ - command = PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR | PCI_BRIDGE_CTL_NO_ISA; - rc = pci_write_config_word(dev, PCI_BRIDGE_CONTROL, command); - if(rc) { - err("Error setting bridge control register"); - return rc; - } - dbg("%s - exit", __FUNCTION__); - return 0; -} - -static int configure_visit_pci_dev(struct pci_dev_wrapped *wrapped_dev, - struct pci_bus_wrapped *wrapped_bus) -{ - int rc; - struct pci_dev *dev = wrapped_dev->dev; - struct pci_bus *bus = wrapped_bus->bus; - struct slot* slot; - - dbg("%s - enter", __FUNCTION__); - - /* - * We need to fix up the hotplug representation with the Linux - * representation. - */ - slot = cpci_find_slot(dev->bus, dev->devfn); - if(slot) { - slot->dev = dev; - } - - /* If it's a bridge, scan behind it for devices */ - if(dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - rc = cpci_configure_bridge(bus, dev); - if(rc) - return rc; - } - - /* Actually configure device */ - if(dev) { - rc = cpci_configure_dev(bus, dev); - if(rc) - return rc; - } - dbg("%s - exit", __FUNCTION__); - return 0; -} - -static int unconfigure_visit_pci_dev_phase2(struct pci_dev_wrapped *wrapped_dev, - struct pci_bus_wrapped *wrapped_bus) -{ - struct pci_dev *dev = wrapped_dev->dev; - struct slot* slot; - - dbg("%s - enter", __FUNCTION__); - if(!dev) - return -ENODEV; - - /* Remove the Linux representation */ - if(pci_remove_device_safe(dev) == 0) { - kfree(dev); - } else { - err("Could not remove device\n"); - return -1; - } - - /* - * Now remove the hotplug representation. - */ - slot = cpci_find_slot(dev->bus, dev->devfn); - if(slot) { - slot->dev = NULL; - } else { - dbg("No hotplug representation for %02x:%02x.%x", - dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); - } - dbg("%s - exit", __FUNCTION__); - return 0; -} - -static int unconfigure_visit_pci_bus_phase2(struct pci_bus_wrapped *wrapped_bus, - struct pci_dev_wrapped *wrapped_dev) -{ - struct pci_bus *bus = wrapped_bus->bus; - struct pci_bus *parent = bus->self->bus; - - dbg("%s - enter", __FUNCTION__); - - /* The cleanup code for proc entries regarding buses should be in the kernel... */ - if(bus->procdir) - dbg("detach_pci_bus %s", bus->procdir->name); - pci_proc_detach_bus(bus); - - /* The cleanup code should live in the kernel... */ - bus->self->subordinate = NULL; - - /* unlink from parent bus */ - list_del(&bus->node); - - /* Now, remove */ - if(bus) - kfree(bus); - - /* Update parent's subordinate field */ - if(parent) { - u8 n = pci_bus_max_busnr(parent); - if(n < parent->subordinate) { - parent->subordinate = n; - pci_write_config_byte(parent->self, PCI_SUBORDINATE_BUS, n); - } - } - dbg("%s - exit", __FUNCTION__); - return 0; -} - -static struct pci_visit configure_functions = { - .visit_pci_dev = configure_visit_pci_dev, -}; - -static struct pci_visit unconfigure_functions_phase2 = { - .post_visit_pci_bus = unconfigure_visit_pci_bus_phase2, - .post_visit_pci_dev = unconfigure_visit_pci_dev_phase2 -}; - - -int cpci_configure_slot(struct slot* slot) -{ - int rc = 0; - - dbg("%s - enter", __FUNCTION__); - - if(slot->dev == NULL) { - dbg("pci_dev null, finding %02x:%02x:%x", - slot->bus->number, PCI_SLOT(slot->devfn), PCI_FUNC(slot->devfn)); - slot->dev = pci_find_slot(slot->bus->number, slot->devfn); - } - - /* Still NULL? Well then scan for it! */ - if(slot->dev == NULL) { - dbg("pci_dev still null"); - - /* - * This will generate pci_dev structures for all functions, but - * we will only call this case when lookup fails. - */ - slot->dev = pci_scan_slot(slot->bus, slot->devfn); - if(slot->dev == NULL) { - err("Could not find PCI device for slot %02x", slot->number); - return 0; - } - } - dbg("slot->dev = %p", slot->dev); - if(slot->dev) { - struct pci_dev *dev; - struct pci_dev_wrapped wrapped_dev; - struct pci_bus_wrapped wrapped_bus; - int i; - - memset(&wrapped_dev, 0, sizeof (struct pci_dev_wrapped)); - memset(&wrapped_bus, 0, sizeof (struct pci_bus_wrapped)); - - for (i = 0; i < 8; i++) { - dev = pci_find_slot(slot->bus->number, - PCI_DEVFN(PCI_SLOT(slot->dev->devfn), i)); - if(!dev) - continue; - wrapped_dev.dev = dev; - wrapped_bus.bus = slot->dev->bus; - rc = pci_visit_dev(&configure_functions, &wrapped_dev, &wrapped_bus); - } - } - - dbg("%s - exit, rc = %d", __FUNCTION__, rc); - return rc; -} - -int cpci_unconfigure_slot(struct slot* slot) -{ - int rc = 0; - int i; - struct pci_dev_wrapped wrapped_dev; - struct pci_bus_wrapped wrapped_bus; - struct pci_dev *dev; - - dbg("%s - enter", __FUNCTION__); - - if(!slot->dev) { - err("No device for slot %02x\n", slot->number); - return -ENODEV; - } - - memset(&wrapped_dev, 0, sizeof (struct pci_dev_wrapped)); - memset(&wrapped_bus, 0, sizeof (struct pci_bus_wrapped)); - - for (i = 0; i < 8; i++) { - dev = pci_find_slot(slot->bus->number, - PCI_DEVFN(PCI_SLOT(slot->devfn), i)); - if(dev) { - wrapped_dev.dev = dev; - wrapped_bus.bus = dev->bus; - dbg("%s - unconfigure phase 2", __FUNCTION__); - rc = pci_visit_dev(&unconfigure_functions_phase2, - &wrapped_dev, &wrapped_bus); - if(rc) - break; - } - } - dbg("%s - exit, rc = %d", __FUNCTION__, rc); - return rc; -} diff -Nru a/drivers/hotplug/cpcihp_generic.c b/drivers/hotplug/cpcihp_generic.c --- a/drivers/hotplug/cpcihp_generic.c Mon Jun 9 23:16:13 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,290 +0,0 @@ -/* - * cpcihp_generic.c - * - * Generic port I/O CompactPCI driver - * - * Copyright 2002 SOMA Networks, Inc. - * Copyright 2001 Intel San Luis Obispo - * Copyright 2000,2001 MontaVista Software Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License 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. - * - * This generic CompactPCI hotplug driver should allow using the PCI hotplug - * mechanism on any CompactPCI board that exposes the #ENUM signal as a bit - * in a system register that can be read through standard port I/O. - * - * Send feedback to <scottm@somanetworks.com> - */ - -#include <linux/config.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/errno.h> -#include <linux/pci.h> -#include "cpci_hotplug.h" - -#define DRIVER_VERSION "0.1" -#define DRIVER_AUTHOR "Scott Murray <scottm@somanetworks.com>" -#define DRIVER_DESC "Generic port I/O CompactPCI Hot Plug Driver" - -#if !defined(CONFIG_HOTPLUG_CPCI_GENERIC_MODULE) -#define MY_NAME "cpcihp_generic" -#else -#define MY_NAME THIS_MODULE->name -#endif - -#define dbg(format, arg...) \ - do { \ - if(debug) \ - printk (KERN_DEBUG "%s: " format "\n", \ - MY_NAME , ## arg); \ - } while(0) -#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) -#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) -#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) - -/* local variables */ -static int debug; -static char* bridge; -static u8 bridge_busnr; -static u8 bridge_slot; -static struct pci_bus *bus; -static u8 first_slot; -static u8 last_slot; -static u16 port; -static unsigned int enum_bit; -static u8 enum_mask; - -static struct cpci_hp_controller_ops generic_hpc_ops; -static struct cpci_hp_controller generic_hpc; - -/* The following allows configuring the driver when it's compiled into the kernel */ -#ifndef MODULE -static int __init cpcihp_generic_setup(char* str) -{ - char* p; - unsigned long tmp; - - if(!str) - return -EINVAL; - bridge = str; - - p = strchr(str, ','); - str = p + 1; - if(!(p && *str && *p == ',')) - goto setup_error; - tmp = simple_strtoul(str, &p, 0); - if(p == str || tmp > 0xff) { - err("hotplug bus first slot number out of range"); - goto setup_error; - } - first_slot = (u8) tmp; - - str = p + 1; - if(!(*str && *p == ',')) - return -EINVAL; - tmp = simple_strtoul(str, &p, 0); - if(p == str || tmp > 0xff) { - err("hotplug bus last slot number out of range"); - goto setup_error; - } - last_slot = (u8) tmp; - - str = p + 1; - if(!(*str && *p == ',')) - goto setup_error; - tmp = simple_strtoul(str, &p, 0); - if(p == str || tmp > 0xffff) { - err("port number out of range"); - goto setup_error; - } - port = (u16) tmp; - - str = p + 1; - if(!(*str && *p == ',')) - goto setup_error; - tmp = simple_strtoul(str, &p, 0); - if(p == str) { - err("invalid #ENUM bit number"); - goto setup_error; - } - enum_bit = (u8) tmp; - - str = p + 1; - if(*str && *p == ',') { - tmp = simple_strtoul(str, &p, 0); - if(p != str) - debug = (int) tmp; - } - return 0; -setup_error: - bridge = NULL; - return -EINVAL; -} - -__setup("cpcihp_generic=", cpcihp_generic_setup); -#endif - -static int __init validate_parameters(void) -{ - char* str; - char* p; - unsigned long tmp; - - if(!bridge) { - info("not configured, disabling."); - return 1; - } - str = bridge; - if(!*str) - return -EINVAL; - - tmp = simple_strtoul(str, &p, 16); - if(p == str || tmp > 0xff) { - err("Invalid hotplug bus bridge device bus number"); - return -EINVAL; - } - bridge_busnr = (u8) tmp; - dbg("bridge_busnr = 0x%02x", bridge_busnr); - if(*p != ':') { - err("Invalid hotplug bus bridge device"); - return -EINVAL; - } - str = p + 1; - tmp = simple_strtoul(str, &p, 16); - if(p == str || tmp > 0x1f) { - err("Invalid hotplug bus bridge device slot number"); - return -EINVAL; - } - bridge_slot = (u8) tmp; - dbg("bridge_slot = 0x%02x", bridge_slot); - - dbg("first_slot = 0x%02x", first_slot); - dbg("last_slot = 0x%02x", last_slot); - if(!(first_slot && last_slot)) { - err("Need to specify first_slot and last_slot"); - return -EINVAL; - } - if(last_slot < first_slot) { - err("first_slot must be less than last_slot"); - return -EINVAL; - } - - dbg("port = 0x%04x", port); - dbg("enum_bit = 0x%02x", enum_bit); - if(enum_bit > 7) { - err("Invalid #ENUM bit"); - return -EINVAL; - } - enum_mask = 1 << enum_bit; - return 0; -} - -static int query_enum(void) -{ - u8 value; - - value = inb_p(port); - return ((value & enum_mask) == enum_mask); -} - -static int __init cpcihp_generic_init(void) -{ - int status; - struct resource* r; - struct pci_dev* dev; - - info(DRIVER_DESC " version: " DRIVER_VERSION); - status = validate_parameters(); - if(status != 0) - return status; - - r = request_region(port, 1, "#ENUM hotswap signal register"); - if(!r) - return -EBUSY; - - dev = pci_find_slot(bridge_busnr, PCI_DEVFN(bridge_slot, 0)); - if(!dev || dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) { - err("Invalid bridge device %s", bridge); - return -EINVAL; - } - bus = dev->subordinate; - - memset(&generic_hpc, 0, sizeof (struct cpci_hp_controller)); - generic_hpc_ops.query_enum = query_enum; - generic_hpc.ops = &generic_hpc_ops; - - status = cpci_hp_register_controller(&generic_hpc); - if(status != 0) { - err("Could not register cPCI hotplug controller"); - return -ENODEV; - } - dbg("registered controller"); - - status = cpci_hp_register_bus(bus, first_slot, last_slot); - if(status != 0) { - err("Could not register cPCI hotplug bus"); - goto init_bus_register_error; - } - dbg("registered bus"); - - status = cpci_hp_start(); - if(status != 0) { - err("Could not started cPCI hotplug system"); - goto init_start_error; - } - dbg("started cpci hp system"); - return 0; -init_start_error: - cpci_hp_unregister_bus(bus); -init_bus_register_error: - cpci_hp_unregister_controller(&generic_hpc); - err("status = %d", status); - return status; - -} - -static void __exit cpcihp_generic_exit(void) -{ - cpci_hp_stop(); - cpci_hp_unregister_bus(bus); - cpci_hp_unregister_controller(&generic_hpc); - release_region(port, 1); -} - -module_init(cpcihp_generic_init); -module_exit(cpcihp_generic_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -MODULE_PARM(debug, "i"); -MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); -MODULE_PARM(bridge, "s"); -MODULE_PARM_DESC(bridge, "Hotswap bus bridge device, <bus>:<slot> (bus and slot are in hexadecimal)"); -MODULE_PARM(first_slot, "b"); -MODULE_PARM_DESC(first_slot, "Hotswap bus first slot number"); -MODULE_PARM(last_slot, "b"); -MODULE_PARM_DESC(last_slot, "Hotswap bus last slot number"); -MODULE_PARM(port, "h"); -MODULE_PARM_DESC(port, "#ENUM signal I/O port"); -MODULE_PARM(enum_bit, "i"); -MODULE_PARM_DESC(enum_bit, "#ENUM signal bit (0-7)"); diff -Nru a/drivers/hotplug/cpcihp_zt5550.c b/drivers/hotplug/cpcihp_zt5550.c --- a/drivers/hotplug/cpcihp_zt5550.c Mon Jun 9 23:16:14 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,306 +0,0 @@ -/* - * cpcihp_zt5550.c - * - * Intel/Ziatech ZT5550 CompactPCI Host Controller driver - * - * Copyright 2002 SOMA Networks, Inc. - * Copyright 2001 Intel San Luis Obispo - * Copyright 2000,2001 MontaVista Software Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License 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. - * - * Send feedback to <scottm@somanetworks.com> - */ - -#include <linux/config.h> -#include <linux/module.h> -#include <linux/init.h> -#include <linux/errno.h> -#include <linux/pci.h> -#include "cpci_hotplug.h" -#include "cpcihp_zt5550.h" - -#define DRIVER_VERSION "0.2" -#define DRIVER_AUTHOR "Scott Murray <scottm@somanetworks.com>" -#define DRIVER_DESC "ZT5550 CompactPCI Hot Plug Driver" - -#if !defined(CONFIG_HOTPLUG_PCI_CPCI_ZT5550_MODULE) -#define MY_NAME "cpcihp_zt5550" -#else -#define MY_NAME THIS_MODULE->name -#endif - -#define dbg(format, arg...) \ - do { \ - if(debug) \ - printk (KERN_DEBUG "%s: " format "\n", \ - MY_NAME , ## arg); \ - } while(0) -#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) -#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) -#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) - -/* local variables */ -static int debug; -static int poll; -static struct cpci_hp_controller_ops zt5550_hpc_ops; -static struct cpci_hp_controller zt5550_hpc; - -/* Primary cPCI bus bridge device */ -static struct pci_dev *bus0_dev; -static struct pci_bus *bus0; - -/* Host controller device */ -static struct pci_dev *hc_dev; - -/* Host controller register addresses */ -static void *hc_registers; -static void *csr_hc_index; -static void *csr_hc_data; -static void *csr_int_status; -static void *csr_int_mask; - - -static int zt5550_hc_config(struct pci_dev *pdev) -{ - /* Since we know that no boards exist with two HC chips, treat it as an error */ - if(hc_dev) { - err("too many host controller devices?"); - return -EBUSY; - } - hc_dev = pdev; - dbg("hc_dev = %p", hc_dev); - dbg("pci resource start %lx", pci_resource_start(hc_dev, 1)); - dbg("pci resource len %lx", pci_resource_len(hc_dev, 1)); - - if(!request_mem_region(pci_resource_start(hc_dev, 1), - pci_resource_len(hc_dev, 1), MY_NAME)) { - err("cannot reserve MMIO region"); - return -ENOMEM; - } - - hc_registers = - ioremap(pci_resource_start(hc_dev, 1), pci_resource_len(hc_dev, 1)); - if(!hc_registers) { - err("cannot remap MMIO region %lx @ %lx", - pci_resource_len(hc_dev, 1), pci_resource_start(hc_dev, 1)); - release_mem_region(pci_resource_start(hc_dev, 1), - pci_resource_len(hc_dev, 1)); - return -ENODEV; - } - - csr_hc_index = hc_registers + CSR_HCINDEX; - csr_hc_data = hc_registers + CSR_HCDATA; - csr_int_status = hc_registers + CSR_INTSTAT; - csr_int_mask = hc_registers + CSR_INTMASK; - - /* - * Disable host control, fault and serial interrupts - */ - dbg("disabling host control, fault and serial interrupts"); - writeb((u8) HC_INT_MASK_REG, csr_hc_index); - writeb((u8) ALL_INDEXED_INTS_MASK, csr_hc_data); - dbg("disabled host control, fault and serial interrupts"); - - /* - * Disable timer0, timer1 and ENUM interrupts - */ - dbg("disabling timer0, timer1 and ENUM interrupts"); - writeb((u8) ALL_DIRECT_INTS_MASK, csr_int_mask); - dbg("disabled timer0, timer1 and ENUM interrupts"); - return 0; -} - -static int zt5550_hc_cleanup(void) -{ - if(!hc_dev) - return -ENODEV; - release_mem_region(pci_resource_start(hc_dev, 1), - pci_resource_len(hc_dev, 1)); - return 0; -} - -static int zt5550_hc_query_enum(void) -{ - u8 value; - - value = inb_p(ENUM_PORT); - return ((value & ENUM_MASK) == ENUM_MASK); -} - -static int zt5550_hc_check_irq(void *dev_id) -{ - int ret; - u8 reg; - - ret = 0; - if(dev_id == zt5550_hpc.dev_id) { - reg = readb(csr_int_status); - if(reg) - ret = 1; - } - return ret; -} - -static int zt5550_hc_enable_irq(void) -{ - u8 reg; - - if(hc_dev == NULL) { - return -ENODEV; - } - reg = readb(csr_int_mask); - reg = reg & ~ENUM_INT_MASK; - writeb(reg, csr_int_mask); - return 0; -} - -int zt5550_hc_disable_irq(void) -{ - u8 reg; - - if(hc_dev == NULL) { - return -ENODEV; - } - - reg = readb(csr_int_mask); - reg = reg | ENUM_INT_MASK; - writeb(reg, csr_int_mask); - return 0; -} - -static int __devinit zt5550_hc_init_one (struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - int status; - - status = zt5550_hc_config(pdev); - if(status != 0) { - return status; - } - dbg("returned from zt5550_hc_config"); - - memset(&zt5550_hpc, 0, sizeof (struct cpci_hp_controller)); - zt5550_hpc_ops.query_enum = zt5550_hc_query_enum; - zt5550_hpc.ops = &zt5550_hpc_ops; - if(!poll) { - zt5550_hpc.irq = hc_dev->irq; - zt5550_hpc.irq_flags = SA_SHIRQ; - zt5550_hpc.dev_id = hc_dev; - - zt5550_hpc_ops.enable_irq = zt5550_hc_enable_irq; - zt5550_hpc_ops.disable_irq = zt5550_hc_disable_irq; - zt5550_hpc_ops.check_irq = zt5550_hc_check_irq; - } else { - info("using ENUM# polling mode"); - } - - status = cpci_hp_register_controller(&zt5550_hpc); - if(status != 0) { - err("could not register cPCI hotplug controller"); - goto init_hc_error; - } - dbg("registered controller"); - - /* Look for first device matching cPCI bus's bridge vendor and device IDs */ - if(!(bus0_dev = pci_find_device(PCI_VENDOR_ID_DEC, - PCI_DEVICE_ID_DEC_21154, NULL))) { - status = -ENODEV; - goto init_register_error; - } - bus0 = bus0_dev->subordinate; - - status = cpci_hp_register_bus(bus0, 0x0a, 0x0f); - if(status != 0) { - err("could not register cPCI hotplug bus"); - goto init_register_error; - } - dbg("registered bus"); - - status = cpci_hp_start(); - if(status != 0) { - err("could not started cPCI hotplug system"); - cpci_hp_unregister_bus(bus0); - goto init_register_error; - } - dbg("started cpci hp system"); - - return 0; -init_register_error: - cpci_hp_unregister_controller(&zt5550_hpc); -init_hc_error: - err("status = %d", status); - zt5550_hc_cleanup(); - return status; - -} - -static void __devexit zt5550_hc_remove_one(struct pci_dev *pdev) -{ - cpci_hp_stop(); - cpci_hp_unregister_bus(bus0); - cpci_hp_unregister_controller(&zt5550_hpc); - zt5550_hc_cleanup(); -} - - -static struct pci_device_id zt5550_hc_pci_tbl[] __devinitdata = { - { PCI_VENDOR_ID_ZIATECH, PCI_DEVICE_ID_ZIATECH_5550_HC, PCI_ANY_ID, PCI_ANY_ID, }, - { 0, } -}; -MODULE_DEVICE_TABLE(pci, zt5550_hc_pci_tbl); - -static struct pci_driver zt5550_hc_driver = { - .name = "zt5550_hc", - .id_table = zt5550_hc_pci_tbl, - .probe = zt5550_hc_init_one, - .remove = __devexit_p(zt5550_hc_remove_one), -}; - -static int __init zt5550_init(void) -{ - struct resource* r; - - info(DRIVER_DESC " version: " DRIVER_VERSION); - r = request_region(ENUM_PORT, 1, "#ENUM hotswap signal register"); - if(!r) - return -EBUSY; - - return pci_module_init(&zt5550_hc_driver); -} - -static void __exit -zt5550_exit(void) -{ - pci_unregister_driver(&zt5550_hc_driver); - release_region(ENUM_PORT, 1); -} - -module_init(zt5550_init); -module_exit(zt5550_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -MODULE_PARM(debug, "i"); -MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); -MODULE_PARM(poll, "i"); -MODULE_PARM_DESC(poll, "#ENUM polling mode enabled or not"); diff -Nru a/drivers/hotplug/cpcihp_zt5550.h b/drivers/hotplug/cpcihp_zt5550.h --- a/drivers/hotplug/cpcihp_zt5550.h Mon Jun 9 23:16:06 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,79 +0,0 @@ -/* - * cpcihp_zt5550.h - * - * Intel/Ziatech ZT5550 CompactPCI Host Controller driver definitions - * - * Copyright 2002 SOMA Networks, Inc. - * Copyright 2001 Intel San Luis Obispo - * Copyright 2000,2001 MontaVista Software Inc. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License 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. - * - * Send feedback to <scottm@somanetworks.com> - */ - -#ifndef _CPCIHP_ZT5550_H -#define _CPCIHP_ZT5550_H - -/* Direct registers */ -#define CSR_HCINDEX 0x00 -#define CSR_HCDATA 0x04 -#define CSR_INTSTAT 0x08 -#define CSR_INTMASK 0x09 -#define CSR_CNT0CMD 0x0C -#define CSR_CNT1CMD 0x0E -#define CSR_CNT0 0x10 -#define CSR_CNT1 0x14 - -/* Masks for interrupt bits in CSR_INTMASK direct register */ -#define CNT0_INT_MASK 0x01 -#define CNT1_INT_MASK 0x02 -#define ENUM_INT_MASK 0x04 -#define ALL_DIRECT_INTS_MASK 0x07 - -/* Indexed registers (through CSR_INDEX, CSR_DATA) */ -#define HC_INT_MASK_REG 0x04 -#define HC_STATUS_REG 0x08 -#define HC_CMD_REG 0x0C -#define ARB_CONFIG_GNT_REG 0x10 -#define ARB_CONFIG_CFG_REG 0x12 -#define ARB_CONFIG_REG 0x10 -#define ISOL_CONFIG_REG 0x18 -#define FAULT_STATUS_REG 0x20 -#define FAULT_CONFIG_REG 0x24 -#define WD_CONFIG_REG 0x2C -#define HC_DIAG_REG 0x30 -#define SERIAL_COMM_REG 0x34 -#define SERIAL_OUT_REG 0x38 -#define SERIAL_IN_REG 0x3C - -/* Masks for interrupt bits in HC_INT_MASK_REG indexed register */ -#define SERIAL_INT_MASK 0x01 -#define FAULT_INT_MASK 0x02 -#define HCF_INT_MASK 0x04 -#define ALL_INDEXED_INTS_MASK 0x07 - -/* Digital I/O port storing ENUM# */ -#define ENUM_PORT 0xE1 -/* Mask to get to the ENUM# bit on the bus */ -#define ENUM_MASK 0x40 - -#endif /* _CPCIHP_ZT5550_H */ diff -Nru a/drivers/hotplug/cpqphp.h b/drivers/hotplug/cpqphp.h --- a/drivers/hotplug/cpqphp.h Mon Jun 9 23:16:17 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,912 +0,0 @@ -/* - * Compaq Hot Plug Controller Driver - * - * Copyright (c) 1995,2001 Compaq Computer Corporation - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001 IBM - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or - * NON INFRINGEMENT. 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. - * - * Send feedback to <greg@kroah.com> - * - */ -#ifndef _CPQPHP_H -#define _CPQPHP_H - -#include "pci_hotplug.h" -#include <linux/interrupt.h> -#include <asm/io.h> /* for read? and write? functions */ -#include <linux/delay.h> /* for delays */ - -#if !defined(CONFIG_HOTPLUG_PCI_COMPAQ_MODULE) - #define MY_NAME "cpqphp.o" -#else - #define MY_NAME THIS_MODULE->name -#endif - -#define dbg(fmt, arg...) do { if (cpqhp_debug) printk(KERN_DEBUG "%s: " fmt , MY_NAME , ## arg); } while (0) -#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg) -#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg) -#define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg) - - - -struct smbios_system_slot { - u8 type; - u8 length; - u16 handle; - u8 name_string_num; - u8 slot_type; - u8 slot_width; - u8 slot_current_usage; - u8 slot_length; - u16 slot_number; - u8 properties1; - u8 properties2; -} __attribute__ ((packed)); - -/* offsets to the smbios generic type based on the above structure layout */ -enum smbios_system_slot_offsets { - SMBIOS_SLOT_GENERIC_TYPE = offsetof(struct smbios_system_slot, type), - SMBIOS_SLOT_GENERIC_LENGTH = offsetof(struct smbios_system_slot, length), - SMBIOS_SLOT_GENERIC_HANDLE = offsetof(struct smbios_system_slot, handle), - SMBIOS_SLOT_NAME_STRING_NUM = offsetof(struct smbios_system_slot, name_string_num), - SMBIOS_SLOT_TYPE = offsetof(struct smbios_system_slot, slot_type), - SMBIOS_SLOT_WIDTH = offsetof(struct smbios_system_slot, slot_width), - SMBIOS_SLOT_CURRENT_USAGE = offsetof(struct smbios_system_slot, slot_current_usage), - SMBIOS_SLOT_LENGTH = offsetof(struct smbios_system_slot, slot_length), - SMBIOS_SLOT_NUMBER = offsetof(struct smbios_system_slot, slot_number), - SMBIOS_SLOT_PROPERTIES1 = offsetof(struct smbios_system_slot, properties1), - SMBIOS_SLOT_PROPERTIES2 = offsetof(struct smbios_system_slot, properties2), -}; - -struct smbios_generic { - u8 type; - u8 length; - u16 handle; -} __attribute__ ((packed)); - -/* offsets to the smbios generic type based on the above structure layout */ -enum smbios_generic_offsets { - SMBIOS_GENERIC_TYPE = offsetof(struct smbios_generic, type), - SMBIOS_GENERIC_LENGTH = offsetof(struct smbios_generic, length), - SMBIOS_GENERIC_HANDLE = offsetof(struct smbios_generic, handle), -}; - -struct smbios_entry_point { - char anchor[4]; - u8 ep_checksum; - u8 ep_length; - u8 major_version; - u8 minor_version; - u16 max_size_entry; - u8 ep_rev; - u8 reserved[5]; - char int_anchor[5]; - u8 int_checksum; - u16 st_length; - u32 st_address; - u16 number_of_entrys; - u8 bcd_rev; -} __attribute__ ((packed)); - -/* offsets to the smbios entry point based on the above structure layout */ -enum smbios_entry_point_offsets { - ANCHOR = offsetof(struct smbios_entry_point, anchor[0]), - EP_CHECKSUM = offsetof(struct smbios_entry_point, ep_checksum), - EP_LENGTH = offsetof(struct smbios_entry_point, ep_length), - MAJOR_VERSION = offsetof(struct smbios_entry_point, major_version), - MINOR_VERSION = offsetof(struct smbios_entry_point, minor_version), - MAX_SIZE_ENTRY = offsetof(struct smbios_entry_point, max_size_entry), - EP_REV = offsetof(struct smbios_entry_point, ep_rev), - INT_ANCHOR = offsetof(struct smbios_entry_point, int_anchor[0]), - INT_CHECKSUM = offsetof(struct smbios_entry_point, int_checksum), - ST_LENGTH = offsetof(struct smbios_entry_point, st_length), - ST_ADDRESS = offsetof(struct smbios_entry_point, st_address), - NUMBER_OF_ENTRYS = offsetof(struct smbios_entry_point, number_of_entrys), - BCD_REV = offsetof(struct smbios_entry_point, bcd_rev), -}; - -struct ctrl_reg { /* offset */ - u8 slot_RST; /* 0x00 */ - u8 slot_enable; /* 0x01 */ - u16 misc; /* 0x02 */ - u32 led_control; /* 0x04 */ - u32 int_input_clear; /* 0x08 */ - u32 int_mask; /* 0x0a */ - u8 reserved0; /* 0x10 */ - u8 reserved1; /* 0x11 */ - u8 reserved2; /* 0x12 */ - u8 gen_output_AB; /* 0x13 */ - u32 non_int_input; /* 0x14 */ - u32 reserved3; /* 0x18 */ - u32 reserved4; /* 0x1a */ - u32 reserved5; /* 0x20 */ - u8 reserved6; /* 0x24 */ - u8 reserved7; /* 0x25 */ - u16 reserved8; /* 0x26 */ - u8 slot_mask; /* 0x28 */ - u8 reserved9; /* 0x29 */ - u8 reserved10; /* 0x2a */ - u8 reserved11; /* 0x2b */ - u8 slot_SERR; /* 0x2c */ - u8 slot_power; /* 0x2d */ - u8 reserved12; /* 0x2e */ - u8 reserved13; /* 0x2f */ - u8 next_curr_freq; /* 0x30 */ - u8 reset_freq_mode; /* 0x31 */ -} __attribute__ ((packed)); - -/* offsets to the controller registers based on the above structure layout */ -enum ctrl_offsets { - SLOT_RST = offsetof(struct ctrl_reg, slot_RST), - SLOT_ENABLE = offsetof(struct ctrl_reg, slot_enable), - MISC = offsetof(struct ctrl_reg, misc), - LED_CONTROL = offsetof(struct ctrl_reg, led_control), - INT_INPUT_CLEAR = offsetof(struct ctrl_reg, int_input_clear), - INT_MASK = offsetof(struct ctrl_reg, int_mask), - CTRL_RESERVED0 = offsetof(struct ctrl_reg, reserved0), - CTRL_RESERVED1 = offsetof(struct ctrl_reg, reserved1), - CTRL_RESERVED2 = offsetof(struct ctrl_reg, reserved1), - GEN_OUTPUT_AB = offsetof(struct ctrl_reg, gen_output_AB), - NON_INT_INPUT = offsetof(struct ctrl_reg, non_int_input), - CTRL_RESERVED3 = offsetof(struct ctrl_reg, reserved3), - CTRL_RESERVED4 = offsetof(struct ctrl_reg, reserved4), - CTRL_RESERVED5 = offsetof(struct ctrl_reg, reserved5), - CTRL_RESERVED6 = offsetof(struct ctrl_reg, reserved6), - CTRL_RESERVED7 = offsetof(struct ctrl_reg, reserved7), - CTRL_RESERVED8 = offsetof(struct ctrl_reg, reserved8), - SLOT_MASK = offsetof(struct ctrl_reg, slot_mask), - CTRL_RESERVED9 = offsetof(struct ctrl_reg, reserved9), - CTRL_RESERVED10 = offsetof(struct ctrl_reg, reserved10), - CTRL_RESERVED11 = offsetof(struct ctrl_reg, reserved11), - SLOT_SERR = offsetof(struct ctrl_reg, slot_SERR), - SLOT_POWER = offsetof(struct ctrl_reg, slot_power), - NEXT_CURR_FREQ = offsetof(struct ctrl_reg, next_curr_freq), - RESET_FREQ_MODE = offsetof(struct ctrl_reg, reset_freq_mode), -}; - -struct hrt { - char sig0; - char sig1; - char sig2; - char sig3; - u16 unused_IRQ; - u16 PCIIRQ; - u8 number_of_entries; - u8 revision; - u16 reserved1; - u32 reserved2; -} __attribute__ ((packed)); - -/* offsets to the hotplug resource table registers based on the above structure layout */ -enum hrt_offsets { - SIG0 = offsetof(struct hrt, sig0), - SIG1 = offsetof(struct hrt, sig1), - SIG2 = offsetof(struct hrt, sig2), - SIG3 = offsetof(struct hrt, sig3), - UNUSED_IRQ = offsetof(struct hrt, unused_IRQ), - PCIIRQ = offsetof(struct hrt, PCIIRQ), - NUMBER_OF_ENTRIES = offsetof(struct hrt, number_of_entries), - REVISION = offsetof(struct hrt, revision), - HRT_RESERVED1 = offsetof(struct hrt, reserved1), - HRT_RESERVED2 = offsetof(struct hrt, reserved2), -}; - -struct slot_rt { - u8 dev_func; - u8 primary_bus; - u8 secondary_bus; - u8 max_bus; - u16 io_base; - u16 io_length; - u16 mem_base; - u16 mem_length; - u16 pre_mem_base; - u16 pre_mem_length; -} __attribute__ ((packed)); - -/* offsets to the hotplug slot resource table registers based on the above structure layout */ -enum slot_rt_offsets { - DEV_FUNC = offsetof(struct slot_rt, dev_func), - PRIMARY_BUS = offsetof(struct slot_rt, primary_bus), - SECONDARY_BUS = offsetof(struct slot_rt, secondary_bus), - MAX_BUS = offsetof(struct slot_rt, max_bus), - IO_BASE = offsetof(struct slot_rt, io_base), - IO_LENGTH = offsetof(struct slot_rt, io_length), - MEM_BASE = offsetof(struct slot_rt, mem_base), - MEM_LENGTH = offsetof(struct slot_rt, mem_length), - PRE_MEM_BASE = offsetof(struct slot_rt, pre_mem_base), - PRE_MEM_LENGTH = offsetof(struct slot_rt, pre_mem_length), -}; - -struct pci_func { - struct pci_func *next; - u8 bus; - u8 device; - u8 function; - u8 is_a_board; - u16 status; - u8 configured; - u8 switch_save; - u8 presence_save; - u32 base_length[0x06]; - u8 base_type[0x06]; - u16 reserved2; - u32 config_space[0x20]; - struct pci_resource *mem_head; - struct pci_resource *p_mem_head; - struct pci_resource *io_head; - struct pci_resource *bus_head; - struct timer_list *p_task_event; - struct pci_dev* pci_dev; -}; - -#define SLOT_MAGIC 0x67267321 -struct slot { - u32 magic; - struct slot *next; - u8 bus; - u8 device; - u8 number; - u8 is_a_board; - u8 configured; - u8 state; - u8 switch_save; - u8 presence_save; - u32 capabilities; - u16 reserved2; - struct timer_list task_event; - u8 hp_slot; - struct controller *ctrl; - void *p_sm_slot; - struct hotplug_slot *hotplug_slot; -}; - -struct pci_resource { - struct pci_resource * next; - u32 base; - u32 length; -}; - -struct event_info { - u32 event_type; - u8 hp_slot; -}; - -struct controller { - struct controller *next; - u32 ctrl_int_comp; - struct semaphore crit_sect; /* critical section semaphore */ - void *hpc_reg; /* cookie for our pci controller location */ - struct pci_resource *mem_head; - struct pci_resource *p_mem_head; - struct pci_resource *io_head; - struct pci_resource *bus_head; - struct pci_dev *pci_dev; - struct pci_bus *pci_bus; - struct event_info event_queue[10]; - struct slot *slot; - u8 next_event; - u8 interrupt; - u8 cfgspc_irq; - u8 bus; /* bus number for the pci hotplug controller */ - u8 rev; - u8 slot_device_offset; - u8 first_slot; - u8 add_support; - u8 push_flag; - enum pci_bus_speed speed; - enum pci_bus_speed speed_capability; - u8 push_button; /* 0 = no pushbutton, 1 = pushbutton present */ - u8 slot_switch_type; /* 0 = no switch, 1 = switch present */ - u8 defeature_PHP; /* 0 = PHP not supported, 1 = PHP supported */ - u8 alternate_base_address; /* 0 = not supported, 1 = supported */ - u8 pci_config_space; /* Index/data access to working registers 0 = not supported, 1 = supported */ - u8 pcix_speed_capability; /* PCI-X */ - u8 pcix_support; /* PCI-X */ - u16 vendor_id; - struct work_struct int_task_event; - wait_queue_head_t queue; /* sleep & wake process */ -}; - -struct irq_mapping { - u8 barber_pole; - u8 valid_INT; - u8 interrupt[4]; -}; - -struct resource_lists { - struct pci_resource *mem_head; - struct pci_resource *p_mem_head; - struct pci_resource *io_head; - struct pci_resource *bus_head; - struct irq_mapping *irqs; -}; - -#define ROM_PHY_ADDR 0x0F0000 -#define ROM_PHY_LEN 0x00ffff - -#define PCI_HPC_ID 0xA0F7 -#define PCI_SUB_HPC_ID 0xA2F7 -#define PCI_SUB_HPC_ID2 0xA2F8 -#define PCI_SUB_HPC_ID3 0xA2F9 -#define PCI_SUB_HPC_ID_INTC 0xA2FA -#define PCI_SUB_HPC_ID4 0xA2FD - -#define INT_BUTTON_IGNORE 0 -#define INT_PRESENCE_ON 1 -#define INT_PRESENCE_OFF 2 -#define INT_SWITCH_CLOSE 3 -#define INT_SWITCH_OPEN 4 -#define INT_POWER_FAULT 5 -#define INT_POWER_FAULT_CLEAR 6 -#define INT_BUTTON_PRESS 7 -#define INT_BUTTON_RELEASE 8 -#define INT_BUTTON_CANCEL 9 - -#define STATIC_STATE 0 -#define BLINKINGON_STATE 1 -#define BLINKINGOFF_STATE 2 -#define POWERON_STATE 3 -#define POWEROFF_STATE 4 - -#define PCISLOT_INTERLOCK_CLOSED 0x00000001 -#define PCISLOT_ADAPTER_PRESENT 0x00000002 -#define PCISLOT_POWERED 0x00000004 -#define PCISLOT_66_MHZ_OPERATION 0x00000008 -#define PCISLOT_64_BIT_OPERATION 0x00000010 -#define PCISLOT_REPLACE_SUPPORTED 0x00000020 -#define PCISLOT_ADD_SUPPORTED 0x00000040 -#define PCISLOT_INTERLOCK_SUPPORTED 0x00000080 -#define PCISLOT_66_MHZ_SUPPORTED 0x00000100 -#define PCISLOT_64_BIT_SUPPORTED 0x00000200 - - - -#define PCI_TO_PCI_BRIDGE_CLASS 0x00060400 - - -#define INTERLOCK_OPEN 0x00000002 -#define ADD_NOT_SUPPORTED 0x00000003 -#define CARD_FUNCTIONING 0x00000005 -#define ADAPTER_NOT_SAME 0x00000006 -#define NO_ADAPTER_PRESENT 0x00000009 -#define NOT_ENOUGH_RESOURCES 0x0000000B -#define DEVICE_TYPE_NOT_SUPPORTED 0x0000000C -#define POWER_FAILURE 0x0000000E - -#define REMOVE_NOT_SUPPORTED 0x00000003 - - -/* - * error Messages - */ -#define msg_initialization_err "Initialization failure, error=%d\n" -#define msg_HPC_rev_error "Unsupported revision of the PCI hot plug controller found.\n" -#define msg_HPC_non_compaq_or_intel "The PCI hot plug controller is not supported by this driver.\n" -#define msg_HPC_not_supported "this system is not supported by this version of cpqphpd. Upgrade to a newer version of cpqphpd\n" -#define msg_unable_to_save "unable to store PCI hot plug add resource information. This system must be rebooted before adding any PCI devices.\n" -#define msg_button_on "PCI slot #%d - powering on due to button press.\n" -#define msg_button_off "PCI slot #%d - powering off due to button press.\n" -#define msg_button_cancel "PCI slot #%d - action canceled due to button press.\n" -#define msg_button_ignore "PCI slot #%d - button press ignored. (action in progress...)\n" - - -/* sysfs functions for the hotplug controller info */ -extern void cpqhp_create_ctrl_files (struct controller *ctrl); - -/* controller functions */ -extern void cpqhp_pushbutton_thread (unsigned long event_pointer); -extern irqreturn_t cpqhp_ctrl_intr (int IRQ, void *data, struct pt_regs *regs); -extern int cpqhp_find_available_resources (struct controller *ctrl, void *rom_start); -extern int cpqhp_event_start_thread (void); -extern void cpqhp_event_stop_thread (void); -extern struct pci_func *cpqhp_slot_create (unsigned char busnumber); -extern struct pci_func *cpqhp_slot_find (unsigned char bus, unsigned char device, unsigned char index); -extern int cpqhp_process_SI (struct controller *ctrl, struct pci_func *func); -extern int cpqhp_process_SS (struct controller *ctrl, struct pci_func *func); -extern int cpqhp_hardware_test (struct controller *ctrl, int test_num); - -/* resource functions */ -extern int cpqhp_resource_sort_and_combine (struct pci_resource **head); - -/* pci functions */ -extern int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num); -extern int cpqhp_get_bus_dev (struct controller *ctrl, u8 *bus_num, u8 *dev_num, u8 slot); -extern int cpqhp_save_config (struct controller *ctrl, int busnumber, int is_hot_plug); -extern int cpqhp_save_base_addr_length (struct controller *ctrl, struct pci_func * func); -extern int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func); -extern int cpqhp_configure_board (struct controller *ctrl, struct pci_func * func); -extern int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot); -extern int cpqhp_valid_replace (struct controller *ctrl, struct pci_func * func); -extern void cpqhp_destroy_board_resources (struct pci_func * func); -extern int cpqhp_return_board_resources (struct pci_func * func, struct resource_lists * resources); -extern void cpqhp_destroy_resource_list (struct resource_lists * resources); -extern int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func); -extern int cpqhp_unconfigure_device (struct pci_func* func); -extern struct slot *cpqhp_find_slot (struct controller *ctrl, u8 device); - -/* Global variables */ -extern int cpqhp_debug; -extern struct controller *cpqhp_ctrl_list; -extern struct pci_func *cpqhp_slot_list[256]; - -/* these can be gotten rid of, but for debugging they are purty */ -extern u8 cpqhp_nic_irq; -extern u8 cpqhp_disk_irq; - - - -/* inline functions */ - - -/* Inline functions to check the sanity of a pointer that is passed to us */ -static inline int slot_paranoia_check (struct slot *slot, const char *function) -{ - if (!slot) { - dbg("%s - slot == NULL", function); - return -1; - } - if (slot->magic != SLOT_MAGIC) { - dbg("%s - bad magic number for slot", function); - return -1; - } - if (!slot->hotplug_slot) { - dbg("%s - slot->hotplug_slot == NULL!", function); - return -1; - } - return 0; -} - -static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function) -{ - struct slot *slot; - - if (!hotplug_slot) { - dbg("%s - hotplug_slot == NULL\n", function); - return NULL; - } - - slot = (struct slot *)hotplug_slot->private; - if (slot_paranoia_check (slot, function)) - return NULL; - return slot; -} - -/* - * return_resource - * - * Puts node back in the resource list pointed to by head - * - */ -static inline void return_resource (struct pci_resource **head, struct pci_resource *node) -{ - if (!node || !head) - return; - node->next = *head; - *head = node; -} - -static inline void set_SOGO (struct controller *ctrl) -{ - u16 misc; - - misc = readw(ctrl->hpc_reg + MISC); - misc = (misc | 0x0001) & 0xFFFB; - writew(misc, ctrl->hpc_reg + MISC); -} - - -static inline void amber_LED_on (struct controller *ctrl, u8 slot) -{ - u32 led_control; - - led_control = readl(ctrl->hpc_reg + LED_CONTROL); - led_control |= (0x01010000L << slot); - writel(led_control, ctrl->hpc_reg + LED_CONTROL); -} - - -static inline void amber_LED_off (struct controller *ctrl, u8 slot) -{ - u32 led_control; - - led_control = readl(ctrl->hpc_reg + LED_CONTROL); - led_control &= ~(0x01010000L << slot); - writel(led_control, ctrl->hpc_reg + LED_CONTROL); -} - - -static inline int read_amber_LED (struct controller *ctrl, u8 slot) -{ - u32 led_control; - - led_control = readl(ctrl->hpc_reg + LED_CONTROL); - led_control &= (0x01010000L << slot); - - return led_control ? 1 : 0; -} - - -static inline void green_LED_on (struct controller *ctrl, u8 slot) -{ - u32 led_control; - - led_control = readl(ctrl->hpc_reg + LED_CONTROL); - led_control |= 0x0101L << slot; - writel(led_control, ctrl->hpc_reg + LED_CONTROL); -} - -static inline void green_LED_off (struct controller *ctrl, u8 slot) -{ - u32 led_control; - - led_control = readl(ctrl->hpc_reg + LED_CONTROL); - led_control &= ~(0x0101L << slot); - writel(led_control, ctrl->hpc_reg + LED_CONTROL); -} - - -static inline void green_LED_blink (struct controller *ctrl, u8 slot) -{ - u32 led_control; - - led_control = readl(ctrl->hpc_reg + LED_CONTROL); - led_control &= ~(0x0101L << slot); - led_control |= (0x0001L << slot); - writel(led_control, ctrl->hpc_reg + LED_CONTROL); -} - - -static inline void slot_disable (struct controller *ctrl, u8 slot) -{ - u8 slot_enable; - - slot_enable = readb(ctrl->hpc_reg + SLOT_ENABLE); - slot_enable &= ~(0x01 << slot); - writeb(slot_enable, ctrl->hpc_reg + SLOT_ENABLE); -} - - -static inline void slot_enable (struct controller *ctrl, u8 slot) -{ - u8 slot_enable; - - slot_enable = readb(ctrl->hpc_reg + SLOT_ENABLE); - slot_enable |= (0x01 << slot); - writeb(slot_enable, ctrl->hpc_reg + SLOT_ENABLE); -} - - -static inline u8 is_slot_enabled (struct controller *ctrl, u8 slot) -{ - u8 slot_enable; - - slot_enable = readb(ctrl->hpc_reg + SLOT_ENABLE); - slot_enable &= (0x01 << slot); - return slot_enable ? 1 : 0; -} - - -static inline u8 read_slot_enable (struct controller *ctrl) -{ - return readb(ctrl->hpc_reg + SLOT_ENABLE); -} - - -/* - * get_controller_speed - find the current frequency/mode of controller. - * - * @ctrl: controller to get frequency/mode for. - * - * Returns controller speed. - * - */ -static inline u8 get_controller_speed (struct controller *ctrl) -{ - u8 curr_freq; - u16 misc; - - if (ctrl->pcix_support) { - curr_freq = readb(ctrl->hpc_reg + NEXT_CURR_FREQ); - if ((curr_freq & 0xB0) == 0xB0) - return PCI_SPEED_133MHz_PCIX; - if ((curr_freq & 0xA0) == 0xA0) - return PCI_SPEED_100MHz_PCIX; - if ((curr_freq & 0x90) == 0x90) - return PCI_SPEED_66MHz_PCIX; - if (curr_freq & 0x10) - return PCI_SPEED_66MHz; - - return PCI_SPEED_33MHz; - } - - misc = readw(ctrl->hpc_reg + MISC); - return (misc & 0x0800) ? PCI_SPEED_66MHz : PCI_SPEED_33MHz; -} - - -/* - * get_adapter_speed - find the max supported frequency/mode of adapter. - * - * @ctrl: hotplug controller. - * @hp_slot: hotplug slot where adapter is installed. - * - * Returns adapter speed. - * - */ -static inline u8 get_adapter_speed (struct controller *ctrl, u8 hp_slot) -{ - u32 temp_dword = readl(ctrl->hpc_reg + NON_INT_INPUT); - dbg("slot: %d, PCIXCAP: %8x\n", hp_slot, temp_dword); - if (ctrl->pcix_support) { - if (temp_dword & (0x10000 << hp_slot)) - return PCI_SPEED_133MHz_PCIX; - if (temp_dword & (0x100 << hp_slot)) - return PCI_SPEED_66MHz_PCIX; - } - - if (temp_dword & (0x01 << hp_slot)) - return PCI_SPEED_66MHz; - - return PCI_SPEED_33MHz; -} - -static inline void enable_slot_power (struct controller *ctrl, u8 slot) -{ - u8 slot_power; - - slot_power = readb(ctrl->hpc_reg + SLOT_POWER); - slot_power |= (0x01 << slot); - writeb(slot_power, ctrl->hpc_reg + SLOT_POWER); -} - -static inline void disable_slot_power (struct controller *ctrl, u8 slot) -{ - u8 slot_power; - - slot_power = readb(ctrl->hpc_reg + SLOT_POWER); - slot_power &= ~(0x01 << slot); - writeb(slot_power, ctrl->hpc_reg + SLOT_POWER); -} - - -static inline int cpq_get_attention_status (struct controller *ctrl, struct slot *slot) -{ - u8 hp_slot; - - if (slot == NULL) - return 1; - - hp_slot = slot->device - ctrl->slot_device_offset; - - return read_amber_LED (ctrl, hp_slot); -} - - -static inline int get_slot_enabled (struct controller *ctrl, struct slot *slot) -{ - u8 hp_slot; - - if (slot == NULL) - return 1; - - hp_slot = slot->device - ctrl->slot_device_offset; - - return is_slot_enabled (ctrl, hp_slot); -} - - -static inline int cpq_get_latch_status (struct controller *ctrl, struct slot *slot) -{ - u32 status; - u8 hp_slot; - - if (slot == NULL) - return 1; - - hp_slot = slot->device - ctrl->slot_device_offset; - dbg("%s: slot->device = %d, ctrl->slot_device_offset = %d \n", - __FUNCTION__, slot->device, ctrl->slot_device_offset); - - status = (readl(ctrl->hpc_reg + INT_INPUT_CLEAR) & (0x01L << hp_slot)); - - return(status == 0) ? 1 : 0; -} - - -static inline int get_presence_status (struct controller *ctrl, struct slot *slot) -{ - int presence_save = 0; - u8 hp_slot; - u32 tempdword; - - if (slot == NULL) - return 0; - - hp_slot = slot->device - ctrl->slot_device_offset; - - tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); - presence_save = (int) ((((~tempdword) >> 23) | ((~tempdword) >> 15)) >> hp_slot) & 0x02; - - return presence_save; -} - -#define SLOT_NAME_SIZE 10 - -static inline void make_slot_name (char *buffer, int buffer_size, struct slot *slot) -{ - snprintf (buffer, buffer_size, "%d", slot->number); -} - - -static inline int wait_for_ctrl_irq (struct controller *ctrl) -{ - DECLARE_WAITQUEUE(wait, current); - int retval = 0; - - dbg("%s - start\n", __FUNCTION__); - add_wait_queue(&ctrl->queue, &wait); - set_current_state(TASK_INTERRUPTIBLE); - /* Sleep for up to 1 second to wait for the LED to change. */ - schedule_timeout(1*HZ); - set_current_state(TASK_RUNNING); - remove_wait_queue(&ctrl->queue, &wait); - if (signal_pending(current)) - retval = -EINTR; - - dbg("%s - end\n", __FUNCTION__); - return retval; -} - - -/** - * set_controller_speed - set the frequency and/or mode of a specific - * controller segment. - * - * @ctrl: controller to change frequency/mode for. - * @adapter_speed: the speed of the adapter we want to match. - * @hp_slot: the slot number where the adapter is installed. - * - * Returns 0 if we successfully change frequency and/or mode to match the - * adapter speed. - * - */ -static inline u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_slot) -{ - struct slot *slot; - u8 reg; - u8 slot_power = readb(ctrl->hpc_reg + SLOT_POWER); - u16 reg16; - u32 leds = readl(ctrl->hpc_reg + LED_CONTROL); - - if (ctrl->speed == adapter_speed) - return 0; - - /* We don't allow freq/mode changes if we find another adapter running - * in another slot on this controller */ - for(slot = ctrl->slot; slot; slot = slot->next) { - if (slot->device == (hp_slot + ctrl->slot_device_offset)) - continue; - if (!slot->hotplug_slot && !slot->hotplug_slot->info) - continue; - if (slot->hotplug_slot->info->adapter_status == 0) - continue; - /* If another adapter is running on the same segment but at a - * lower speed/mode, we allow the new adapter to function at - * this rate if supported */ - if (ctrl->speed < adapter_speed) - return 0; - - return 1; - } - - /* If the controller doesn't support freq/mode changes and the - * controller is running at a higher mode, we bail */ - if ((ctrl->speed > adapter_speed) && (!ctrl->pcix_speed_capability)) - return 1; - - /* But we allow the adapter to run at a lower rate if possible */ - if ((ctrl->speed < adapter_speed) && (!ctrl->pcix_speed_capability)) - return 0; - - /* We try to set the max speed supported by both the adapter and - * controller */ - if (ctrl->speed_capability < adapter_speed) { - if (ctrl->speed == ctrl->speed_capability) - return 0; - adapter_speed = ctrl->speed_capability; - } - - writel(0x0L, ctrl->hpc_reg + LED_CONTROL); - writeb(0x00, ctrl->hpc_reg + SLOT_ENABLE); - - set_SOGO(ctrl); - wait_for_ctrl_irq(ctrl); - - if (adapter_speed != PCI_SPEED_133MHz_PCIX) - reg = 0xF5; - else - reg = 0xF4; - pci_write_config_byte(ctrl->pci_dev, 0x41, reg); - - reg16 = readw(ctrl->hpc_reg + NEXT_CURR_FREQ); - reg16 &= ~0x000F; - switch(adapter_speed) { - case(PCI_SPEED_133MHz_PCIX): - reg = 0x75; - reg16 |= 0xB; - break; - case(PCI_SPEED_100MHz_PCIX): - reg = 0x74; - reg16 |= 0xA; - break; - case(PCI_SPEED_66MHz_PCIX): - reg = 0x73; - reg16 |= 0x9; - break; - case(PCI_SPEED_66MHz): - reg = 0x73; - reg16 |= 0x1; - break; - default: /* 33MHz PCI 2.2 */ - reg = 0x71; - break; - - } - reg16 |= 0xB << 12; - writew(reg16, ctrl->hpc_reg + NEXT_CURR_FREQ); - - mdelay(5); - - /* Reenable interrupts */ - writel(0, ctrl->hpc_reg + INT_MASK); - - pci_write_config_byte(ctrl->pci_dev, 0x41, reg); - - /* Restart state machine */ - reg = ~0xF; - pci_read_config_byte(ctrl->pci_dev, 0x43, ®); - pci_write_config_byte(ctrl->pci_dev, 0x43, reg); - - /* Only if mode change...*/ - if (((ctrl->speed == PCI_SPEED_66MHz) && (adapter_speed == PCI_SPEED_66MHz_PCIX)) || - ((ctrl->speed == PCI_SPEED_66MHz_PCIX) && (adapter_speed == PCI_SPEED_66MHz))) - set_SOGO(ctrl); - - wait_for_ctrl_irq(ctrl); - mdelay(1100); - - /* Restore LED/Slot state */ - writel(leds, ctrl->hpc_reg + LED_CONTROL); - writeb(slot_power, ctrl->hpc_reg + SLOT_ENABLE); - - set_SOGO(ctrl); - wait_for_ctrl_irq(ctrl); - - ctrl->speed = adapter_speed; - slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); - - info("Successfully changed frequency/mode for adapter in slot %d\n", - slot->number); - return 0; -} - -#endif - diff -Nru a/drivers/hotplug/cpqphp_core.c b/drivers/hotplug/cpqphp_core.c --- a/drivers/hotplug/cpqphp_core.c Mon Jun 9 23:16:05 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,1541 +0,0 @@ -/* - * Compaq Hot Plug Controller Driver - * - * Copyright (c) 1995,2001 Compaq Computer Corporation - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or - * NON INFRINGEMENT. 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. - * - * Send feedback to <greg@kroah.com> - * - * Jan 12, 2003 - Added 66/100/133MHz PCI-X support, - * Torben Mathiasen <torben.mathiasen@hp.com> - * - */ - -#include <linux/config.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/proc_fs.h> -#include <linux/miscdevice.h> -#include <linux/slab.h> -#include <linux/workqueue.h> -#include <linux/pci.h> -#include <linux/init.h> -#include <linux/interrupt.h> - -#include <asm/uaccess.h> - -#include "cpqphp.h" -#include "cpqphp_nvram.h" -#include "../../arch/i386/pci/pci.h" /* horrible hack showing how processor dependent we are... */ - - -/* Global variables */ -int cpqhp_debug; -struct controller *cpqhp_ctrl_list; /* = NULL */ -struct pci_func *cpqhp_slot_list[256]; - -/* local variables */ -static void *smbios_table; -static void *smbios_start; -static void *cpqhp_rom_start; -static u8 power_mode; -static int debug; - -#define DRIVER_VERSION "0.9.7" -#define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>" -#define DRIVER_DESC "Compaq Hot Plug PCI Controller Driver" - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); - -MODULE_PARM(power_mode, "b"); -MODULE_PARM_DESC(power_mode, "Power mode enabled or not"); - -MODULE_PARM(debug, "i"); -MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); - -#define CPQHPC_MODULE_MINOR 208 - -static int one_time_init (void); -static int set_attention_status (struct hotplug_slot *slot, u8 value); -static int process_SI (struct hotplug_slot *slot); -static int process_SS (struct hotplug_slot *slot); -static int hardware_test (struct hotplug_slot *slot, u32 value); -static int get_power_status (struct hotplug_slot *slot, u8 *value); -static int get_attention_status (struct hotplug_slot *slot, u8 *value); -static int get_latch_status (struct hotplug_slot *slot, u8 *value); -static int get_adapter_status (struct hotplug_slot *slot, u8 *value); -static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); -static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); - -static struct hotplug_slot_ops cpqphp_hotplug_slot_ops = { - .owner = THIS_MODULE, - .set_attention_status = set_attention_status, - .enable_slot = process_SI, - .disable_slot = process_SS, - .hardware_test = hardware_test, - .get_power_status = get_power_status, - .get_attention_status = get_attention_status, - .get_latch_status = get_latch_status, - .get_adapter_status = get_adapter_status, - .get_max_bus_speed = get_max_bus_speed, - .get_cur_bus_speed = get_cur_bus_speed, -}; - - -static inline int is_slot64bit (struct slot *slot) -{ - if (!slot || !slot->p_sm_slot) - return 0; - - if (readb(slot->p_sm_slot + SMBIOS_SLOT_WIDTH) == 0x06) - return 1; - - return 0; -} - -static inline int is_slot66mhz (struct slot *slot) -{ - if (!slot || !slot->p_sm_slot) - return 0; - - if (readb(slot->p_sm_slot + SMBIOS_SLOT_TYPE) == 0x0E) - return 1; - - return 0; -} - -/** - * detect_SMBIOS_pointer - find the system Management BIOS Table in the specified region of memory. - * - * @begin: begin pointer for region to be scanned. - * @end: end pointer for region to be scanned. - * - * Returns pointer to the head of the SMBIOS tables (or NULL) - * - */ -static void * detect_SMBIOS_pointer(void *begin, void *end) -{ - void *fp; - void *endp; - u8 temp1, temp2, temp3, temp4; - int status = 0; - - endp = (end - sizeof(u32) + 1); - - for (fp = begin; fp <= endp; fp += 16) { - temp1 = readb(fp); - temp2 = readb(fp+1); - temp3 = readb(fp+2); - temp4 = readb(fp+3); - if (temp1 == '_' && - temp2 == 'S' && - temp3 == 'M' && - temp4 == '_') { - status = 1; - break; - } - } - - if (!status) - fp = NULL; - - dbg("Discovered SMBIOS Entry point at %p\n", fp); - - return fp; -} - -/** - * init_SERR - Initializes the per slot SERR generation. - * - * For unexpected switch opens - * - */ -static int init_SERR(struct controller * ctrl) -{ - u32 tempdword; - u32 number_of_slots; - u8 physical_slot; - - if (!ctrl) - return 1; - - tempdword = ctrl->first_slot; - - number_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F; - // Loop through slots - while (number_of_slots) { - physical_slot = tempdword; - writeb(0, ctrl->hpc_reg + SLOT_SERR); - tempdword++; - number_of_slots--; - } - - return 0; -} - - -/* nice debugging output */ -static int pci_print_IRQ_route (void) -{ - struct irq_routing_table *routing_table; - int len; - int loop; - - u8 tbus, tdevice, tslot; - - routing_table = pcibios_get_irq_routing_table(); - if (routing_table == NULL) { - err("No BIOS Routing Table??? Not good\n"); - return -ENOMEM; - } - - len = (routing_table->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); - // Make sure I got at least one entry - if (len == 0) { - kfree(routing_table); - return -1; - } - - dbg("bus dev func slot\n"); - - for (loop = 0; loop < len; ++loop) { - tbus = routing_table->slots[loop].bus; - tdevice = routing_table->slots[loop].devfn; - tslot = routing_table->slots[loop].slot; - dbg("%d %d %d %d\n", tbus, tdevice >> 3, tdevice & 0x7, tslot); - - } - kfree(routing_table); - return 0; -} - - -/* - * get_subsequent_smbios_entry - * - * Gets the first entry if previous == NULL - * Otherwise, returns the next entry - * Uses global SMBIOS Table pointer - * - * @curr: %NULL or pointer to previously returned structure - * - * returns a pointer to an SMBIOS structure or NULL if none found - */ -static void * get_subsequent_smbios_entry(void *smbios_start, void *smbios_table, void *curr) -{ - u8 bail = 0; - u8 previous_byte = 1; - void *p_temp; - void *p_max; - - if (!smbios_table || !curr) - return(NULL); - - // set p_max to the end of the table - p_max = smbios_start + readw(smbios_table + ST_LENGTH); - - p_temp = curr; - p_temp += readb(curr + SMBIOS_GENERIC_LENGTH); - - while ((p_temp < p_max) && !bail) { - // Look for the double NULL terminator - // The first condition is the previous byte and the second is the curr - if (!previous_byte && !(readb(p_temp))) { - bail = 1; - } - - previous_byte = readb(p_temp); - p_temp++; - } - - if (p_temp < p_max) { - return p_temp; - } else { - return NULL; - } -} - - -/** - * get_SMBIOS_entry - * - * @type:SMBIOS structure type to be returned - * @previous: %NULL or pointer to previously returned structure - * - * Gets the first entry of the specified type if previous == NULL - * Otherwise, returns the next entry of the given type. - * Uses global SMBIOS Table pointer - * Uses get_subsequent_smbios_entry - * - * returns a pointer to an SMBIOS structure or %NULL if none found - */ -static void *get_SMBIOS_entry (void *smbios_start, void *smbios_table, u8 type, void * previous) -{ - if (!smbios_table) - return NULL; - - if (!previous) { - previous = smbios_start; - } else { - previous = get_subsequent_smbios_entry(smbios_start, smbios_table, previous); - } - - while (previous) { - if (readb(previous + SMBIOS_GENERIC_TYPE) != type) { - previous = get_subsequent_smbios_entry(smbios_start, smbios_table, previous); - } else { - break; - } - } - - return previous; -} - - -static int ctrl_slot_setup (struct controller * ctrl, void *smbios_start, void *smbios_table) -{ - struct slot *new_slot; - u8 number_of_slots; - u8 slot_device; - u8 slot_number; - u8 ctrl_slot; - u32 tempdword; - void *slot_entry= NULL; - int result; - - dbg("%s\n", __FUNCTION__); - - tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); - - number_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F; - slot_device = readb(ctrl->hpc_reg + SLOT_MASK) >> 4; - slot_number = ctrl->first_slot; - - while (number_of_slots) { - new_slot = (struct slot *) kmalloc(sizeof(struct slot), GFP_KERNEL); - if (!new_slot) - return -ENOMEM; - - memset(new_slot, 0, sizeof(struct slot)); - new_slot->hotplug_slot = kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL); - if (!new_slot->hotplug_slot) { - kfree (new_slot); - return -ENOMEM; - } - memset(new_slot->hotplug_slot, 0, sizeof (struct hotplug_slot)); - - new_slot->hotplug_slot->info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); - if (!new_slot->hotplug_slot->info) { - kfree (new_slot->hotplug_slot); - kfree (new_slot); - return -ENOMEM; - } - memset(new_slot->hotplug_slot->info, 0, sizeof (struct hotplug_slot_info)); - new_slot->hotplug_slot->name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL); - if (!new_slot->hotplug_slot->name) { - kfree (new_slot->hotplug_slot->info); - kfree (new_slot->hotplug_slot); - kfree (new_slot); - return -ENOMEM; - } - - new_slot->magic = SLOT_MAGIC; - new_slot->ctrl = ctrl; - new_slot->bus = ctrl->bus; - new_slot->device = slot_device; - new_slot->number = slot_number; - dbg("slot->number = %d\n",new_slot->number); - - slot_entry = get_SMBIOS_entry(smbios_start, smbios_table, 9, slot_entry); - - while (slot_entry && (readw(slot_entry + SMBIOS_SLOT_NUMBER) != new_slot->number)) { - slot_entry = get_SMBIOS_entry(smbios_start, smbios_table, 9, slot_entry); - } - - new_slot->p_sm_slot = slot_entry; - - init_timer(&new_slot->task_event); - new_slot->task_event.expires = jiffies + 5 * HZ; - new_slot->task_event.function = cpqhp_pushbutton_thread; - - //FIXME: these capabilities aren't used but if they are - // they need to be correctly implemented - new_slot->capabilities |= PCISLOT_REPLACE_SUPPORTED; - new_slot->capabilities |= PCISLOT_INTERLOCK_SUPPORTED; - - if (is_slot64bit(new_slot)) - new_slot->capabilities |= PCISLOT_64_BIT_SUPPORTED; - if (is_slot66mhz(new_slot)) - new_slot->capabilities |= PCISLOT_66_MHZ_SUPPORTED; - if (ctrl->speed == PCI_SPEED_66MHz) - new_slot->capabilities |= PCISLOT_66_MHZ_OPERATION; - - ctrl_slot = slot_device - (readb(ctrl->hpc_reg + SLOT_MASK) >> 4); - - // Check presence - new_slot->capabilities |= ((((~tempdword) >> 23) | ((~tempdword) >> 15)) >> ctrl_slot) & 0x02; - // Check the switch state - new_slot->capabilities |= ((~tempdword & 0xFF) >> ctrl_slot) & 0x01; - // Check the slot enable - new_slot->capabilities |= ((read_slot_enable(ctrl) << 2) >> ctrl_slot) & 0x04; - - /* register this slot with the hotplug pci core */ - new_slot->hotplug_slot->private = new_slot; - make_slot_name (new_slot->hotplug_slot->name, SLOT_NAME_SIZE, new_slot); - new_slot->hotplug_slot->ops = &cpqphp_hotplug_slot_ops; - - new_slot->hotplug_slot->info->power_status = get_slot_enabled(ctrl, new_slot); - new_slot->hotplug_slot->info->attention_status = cpq_get_attention_status(ctrl, new_slot); - new_slot->hotplug_slot->info->latch_status = cpq_get_latch_status(ctrl, new_slot); - new_slot->hotplug_slot->info->adapter_status = get_presence_status(ctrl, new_slot); - - dbg ("registering bus %d, dev %d, number %d, ctrl->slot_device_offset %d, slot %d\n", - new_slot->bus, new_slot->device, new_slot->number, ctrl->slot_device_offset, slot_number); - result = pci_hp_register (new_slot->hotplug_slot); - if (result) { - err ("pci_hp_register failed with error %d\n", result); - kfree (new_slot->hotplug_slot->info); - kfree (new_slot->hotplug_slot->name); - kfree (new_slot->hotplug_slot); - kfree (new_slot); - return result; - } - - new_slot->next = ctrl->slot; - ctrl->slot = new_slot; - - number_of_slots--; - slot_device++; - slot_number++; - } - - return(0); -} - - -static int ctrl_slot_cleanup (struct controller * ctrl) -{ - struct slot *old_slot, *next_slot; - - old_slot = ctrl->slot; - ctrl->slot = NULL; - - while (old_slot) { - next_slot = old_slot->next; - pci_hp_deregister (old_slot->hotplug_slot); - kfree(old_slot->hotplug_slot->info); - kfree(old_slot->hotplug_slot->name); - kfree(old_slot->hotplug_slot); - kfree(old_slot); - old_slot = next_slot; - } - - //Free IRQ associated with hot plug device - free_irq(ctrl->interrupt, ctrl); - //Unmap the memory - iounmap(ctrl->hpc_reg); - //Finally reclaim PCI mem - release_mem_region(pci_resource_start(ctrl->pci_dev, 0), - pci_resource_len(ctrl->pci_dev, 0)); - - return(0); -} - - -//============================================================================ -// function: get_slot_mapping -// -// Description: Attempts to determine a logical slot mapping for a PCI -// device. Won't work for more than one PCI-PCI bridge -// in a slot. -// -// Input: u8 bus_num - bus number of PCI device -// u8 dev_num - device number of PCI device -// u8 *slot - Pointer to u8 where slot number will -// be returned -// -// Output: SUCCESS or FAILURE -//============================================================================= -static int get_slot_mapping (struct pci_bus *bus, u8 bus_num, u8 dev_num, u8 *slot) -{ - struct irq_routing_table *PCIIRQRoutingInfoLength; - u32 work; - long len; - long loop; - - u8 tbus, tdevice, tslot, bridgeSlot; - - dbg("%s: %p, %d, %d, %p\n", __FUNCTION__, bus, bus_num, dev_num, slot); - - bridgeSlot = 0xFF; - - PCIIRQRoutingInfoLength = pcibios_get_irq_routing_table(); - if (!PCIIRQRoutingInfoLength) - return -1; - - len = (PCIIRQRoutingInfoLength->size - - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); - // Make sure I got at least one entry - if (len == 0) { - if (PCIIRQRoutingInfoLength != NULL) kfree(PCIIRQRoutingInfoLength ); - return -1; - } - - for (loop = 0; loop < len; ++loop) { - tbus = PCIIRQRoutingInfoLength->slots[loop].bus; - tdevice = PCIIRQRoutingInfoLength->slots[loop].devfn >> 3; - tslot = PCIIRQRoutingInfoLength->slots[loop].slot; - - if ((tbus == bus_num) && (tdevice == dev_num)) { - *slot = tslot; - - if (PCIIRQRoutingInfoLength != NULL) - kfree(PCIIRQRoutingInfoLength); - return 0; - } else { - // Didn't get a match on the target PCI device. Check if the - // current IRQ table entry is a PCI-to-PCI bridge device. If so, - // and it's secondary bus matches the bus number for the target - // device, I need to save the bridge's slot number. If I can't - // find an entry for the target device, I will have to assume it's - // on the other side of the bridge, and assign it the bridge's slot. - bus->number = tbus; - pci_bus_read_config_dword (bus, PCI_DEVFN(tdevice, 0), PCI_REVISION_ID, &work); - - if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) { - pci_bus_read_config_dword (bus, PCI_DEVFN(tdevice, 0), PCI_PRIMARY_BUS, &work); - // See if bridge's secondary bus matches target bus. - if (((work >> 8) & 0x000000FF) == (long) bus_num) { - bridgeSlot = tslot; - } - } - } - - } - - // If we got here, we didn't find an entry in the IRQ mapping table - // for the target PCI device. If we did determine that the target - // device is on the other side of a PCI-to-PCI bridge, return the - // slot number for the bridge. - if (bridgeSlot != 0xFF) { - *slot = bridgeSlot; - if (PCIIRQRoutingInfoLength != NULL) kfree(PCIIRQRoutingInfoLength ); - return 0; - } - if (PCIIRQRoutingInfoLength != NULL) kfree(PCIIRQRoutingInfoLength ); - // Couldn't find an entry in the routing table for this PCI device - return -1; -} - - -/** - * cpqhp_set_attention_status - Turns the Amber LED for a slot on or off - * - */ -static int cpqhp_set_attention_status (struct controller *ctrl, struct pci_func *func, u32 status) -{ - u8 hp_slot; - - hp_slot = func->device - ctrl->slot_device_offset; - - if (func == NULL) - return(1); - - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); - - if (status == 1) { - amber_LED_on (ctrl, hp_slot); - } else if (status == 0) { - amber_LED_off (ctrl, hp_slot); - } else { - // Done with exclusive hardware access - up(&ctrl->crit_sect); - return(1); - } - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - // Done with exclusive hardware access - up(&ctrl->crit_sect); - - return(0); -} - - -/** - * set_attention_status - Turns the Amber LED for a slot on or off - * - */ -static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status) -{ - struct pci_func *slot_func; - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - struct controller *ctrl; - u8 bus; - u8 devfn; - u8 device; - u8 function; - - if (slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - ctrl = slot->ctrl; - if (ctrl == NULL) - return -ENODEV; - - if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1) - return -ENODEV; - - device = devfn >> 3; - function = devfn & 0x7; - dbg("bus, dev, fn = %d, %d, %d\n", bus, device, function); - - slot_func = cpqhp_slot_find(bus, device, function); - if (!slot_func) { - return -ENODEV; - } - - return cpqhp_set_attention_status(ctrl, slot_func, status); -} - - -static int process_SI (struct hotplug_slot *hotplug_slot) -{ - struct pci_func *slot_func; - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - struct controller *ctrl; - u8 bus; - u8 devfn; - u8 device; - u8 function; - - if (slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - ctrl = slot->ctrl; - if (ctrl == NULL) - return -ENODEV; - - if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1) - return -ENODEV; - - device = devfn >> 3; - function = devfn & 0x7; - dbg("bus, dev, fn = %d, %d, %d\n", bus, device, function); - - slot_func = cpqhp_slot_find(bus, device, function); - if (!slot_func) { - return -ENODEV; - } - - slot_func->bus = bus; - slot_func->device = device; - slot_func->function = function; - slot_func->configured = 0; - dbg("board_added(%p, %p)\n", slot_func, ctrl); - return cpqhp_process_SI(ctrl, slot_func); -} - - -static int process_SS (struct hotplug_slot *hotplug_slot) -{ - struct pci_func *slot_func; - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - struct controller *ctrl; - u8 bus; - u8 devfn; - u8 device; - u8 function; - - if (slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - ctrl = slot->ctrl; - if (ctrl == NULL) - return -ENODEV; - - if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1) - return -ENODEV; - - device = devfn >> 3; - function = devfn & 0x7; - dbg("bus, dev, fn = %d, %d, %d\n", bus, device, function); - - slot_func = cpqhp_slot_find(bus, device, function); - if (!slot_func) { - return -ENODEV; - } - - dbg("In power_down_board, slot_func = %p, ctrl = %p\n", slot_func, ctrl); - return cpqhp_process_SS(ctrl, slot_func); -} - - -static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value) -{ - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - struct controller *ctrl; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - if (slot == NULL) - return -ENODEV; - - ctrl = slot->ctrl; - if (ctrl == NULL) - return -ENODEV; - - return cpqhp_hardware_test (ctrl, value); -} - - -static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value) -{ - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - struct controller *ctrl; - - if (slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - ctrl = slot->ctrl; - if (ctrl == NULL) - return -ENODEV; - - *value = get_slot_enabled(ctrl, slot); - return 0; -} - -static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value) -{ - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - struct controller *ctrl; - - if (slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - ctrl = slot->ctrl; - if (ctrl == NULL) - return -ENODEV; - - *value = cpq_get_attention_status(ctrl, slot); - return 0; -} - -static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value) -{ - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - struct controller *ctrl; - - if (slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - ctrl = slot->ctrl; - if (ctrl == NULL) - return -ENODEV; - - *value = cpq_get_latch_status (ctrl, slot); - - return 0; -} - -static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value) -{ - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - struct controller *ctrl; - - if (slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - ctrl = slot->ctrl; - if (ctrl == NULL) - return -ENODEV; - - *value = get_presence_status (ctrl, slot); - - return 0; -} - -static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) -{ - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - struct controller *ctrl; - - if (slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - ctrl = slot->ctrl; - if (ctrl == NULL) - return -ENODEV; - - *value = ctrl->speed_capability; - - return 0; -} - -static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) -{ - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - struct controller *ctrl; - - if (slot == NULL) - return -ENODEV; - - dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - ctrl = slot->ctrl; - if (ctrl == NULL) - return -ENODEV; - - *value = ctrl->speed; - - return 0; -} - -static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) -{ - u8 num_of_slots = 0; - u8 hp_slot = 0; - u8 device; - u8 rev; - u8 bus_cap; - u16 temp_word; - u16 vendor_id; - u16 subsystem_vid; - u16 subsystem_deviceid; - u32 rc; - struct controller *ctrl; - struct pci_func *func; - - // Need to read VID early b/c it's used to differentiate CPQ and INTC discovery - rc = pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor_id); - if (rc || ((vendor_id != PCI_VENDOR_ID_COMPAQ) && (vendor_id != PCI_VENDOR_ID_INTEL))) { - err(msg_HPC_non_compaq_or_intel); - return -ENODEV; - } - dbg("Vendor ID: %x\n", vendor_id); - - rc = pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); - dbg("revision: %d\n", rev); - if (rc || ((vendor_id == PCI_VENDOR_ID_COMPAQ) && (!rev))) { - err(msg_HPC_rev_error); - return -ENODEV; - } - - /* Check for the proper subsytem ID's - * Intel uses a different SSID programming model than Compaq. - * For Intel, each SSID bit identifies a PHP capability. - * Also Intel HPC's may have RID=0. - */ - if ((rev > 2) || (vendor_id == PCI_VENDOR_ID_INTEL)) { - // TODO: This code can be made to support non-Compaq or Intel subsystem IDs - rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vid); - if (rc) { - err("%s : pci_read_config_word failed\n", __FUNCTION__); - return rc; - } - dbg("Subsystem Vendor ID: %x\n", subsystem_vid); - if ((subsystem_vid != PCI_VENDOR_ID_COMPAQ) && (subsystem_vid != PCI_VENDOR_ID_INTEL)) { - err(msg_HPC_non_compaq_or_intel); - return -ENODEV; - } - - ctrl = (struct controller *) kmalloc(sizeof(struct controller), GFP_KERNEL); - if (!ctrl) { - err("%s : out of memory\n", __FUNCTION__); - return -ENOMEM; - } - memset(ctrl, 0, sizeof(struct controller)); - - rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsystem_deviceid); - if (rc) { - err("%s : pci_read_config_word failed\n", __FUNCTION__); - goto err_free_ctrl; - } - - info("Hot Plug Subsystem Device ID: %x\n", subsystem_deviceid); - - /* Set Vendor ID, so it can be accessed later from other functions */ - ctrl->vendor_id = vendor_id; - - switch (subsystem_vid) { - case PCI_VENDOR_ID_COMPAQ: - if (rev >= 0x13) { /* CIOBX */ - ctrl->push_flag = 1; - ctrl->slot_switch_type = 1; // Switch is present - ctrl->push_button = 1; // Pushbutton is present - ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported - ctrl->defeature_PHP = 1; // PHP is supported - ctrl->pcix_support = 1; // PCI-X supported - ctrl->pcix_speed_capability = 1; - pci_read_config_byte(pdev, 0x41, &bus_cap); - if (bus_cap & 0x80) { - dbg("bus max supports 133MHz PCI-X\n"); - ctrl->speed_capability = PCI_SPEED_133MHz_PCIX; - break; - } - if (bus_cap & 0x40) { - dbg("bus max supports 100MHz PCI-X\n"); - ctrl->speed_capability = PCI_SPEED_100MHz_PCIX; - break; - } - if (bus_cap & 20) { - dbg("bus max supports 66MHz PCI-X\n"); - ctrl->speed_capability = PCI_SPEED_66MHz_PCIX; - break; - } - if (bus_cap & 10) { - dbg("bus max supports 66MHz PCI\n"); - ctrl->speed_capability = PCI_SPEED_66MHz; - break; - } - - break; - } - - switch (subsystem_deviceid) { - case PCI_SUB_HPC_ID: - /* Original 6500/7000 implementation */ - ctrl->slot_switch_type = 1; // Switch is present - ctrl->speed_capability = PCI_SPEED_33MHz; - ctrl->push_button = 0; // No pushbutton - ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported - ctrl->defeature_PHP = 1; // PHP is supported - ctrl->pcix_support = 0; // PCI-X not supported - ctrl->pcix_speed_capability = 0; // N/A since PCI-X not supported - break; - case PCI_SUB_HPC_ID2: - /* First Pushbutton implementation */ - ctrl->push_flag = 1; - ctrl->slot_switch_type = 1; // Switch is present - ctrl->speed_capability = PCI_SPEED_33MHz; - ctrl->push_button = 1; // Pushbutton is present - ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported - ctrl->defeature_PHP = 1; // PHP is supported - ctrl->pcix_support = 0; // PCI-X not supported - ctrl->pcix_speed_capability = 0; // N/A since PCI-X not supported - break; - case PCI_SUB_HPC_ID_INTC: - /* Third party (6500/7000) */ - ctrl->slot_switch_type = 1; // Switch is present - ctrl->speed_capability = PCI_SPEED_33MHz; - ctrl->push_button = 0; // No pushbutton - ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported - ctrl->defeature_PHP = 1; // PHP is supported - ctrl->pcix_support = 0; // PCI-X not supported - ctrl->pcix_speed_capability = 0; // N/A since PCI-X not supported - break; - case PCI_SUB_HPC_ID3: - /* First 66 Mhz implementation */ - ctrl->push_flag = 1; - ctrl->slot_switch_type = 1; // Switch is present - ctrl->speed_capability = PCI_SPEED_66MHz; - ctrl->push_button = 1; // Pushbutton is present - ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported - ctrl->defeature_PHP = 1; // PHP is supported - ctrl->pcix_support = 0; // PCI-X not supported - ctrl->pcix_speed_capability = 0; // N/A since PCI-X not supported - break; - case PCI_SUB_HPC_ID4: - /* First PCI-X implementation, 100MHz */ - ctrl->push_flag = 1; - ctrl->slot_switch_type = 1; // Switch is present - ctrl->speed_capability = PCI_SPEED_100MHz_PCIX; - ctrl->push_button = 1; // Pushbutton is present - ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported - ctrl->defeature_PHP = 1; // PHP is supported - ctrl->pcix_support = 1; // PCI-X supported - ctrl->pcix_speed_capability = 0; - break; - default: - err(msg_HPC_not_supported); - rc = -ENODEV; - goto err_free_ctrl; - } - break; - - case PCI_VENDOR_ID_INTEL: - /* Check for speed capability (0=33, 1=66) */ - if (subsystem_deviceid & 0x0001) { - ctrl->speed_capability = PCI_SPEED_66MHz; - } else { - ctrl->speed_capability = PCI_SPEED_33MHz; - } - - /* Check for push button */ - if (subsystem_deviceid & 0x0002) { - /* no push button */ - ctrl->push_button = 0; - } else { - /* push button supported */ - ctrl->push_button = 1; - } - - /* Check for slot switch type (0=mechanical, 1=not mechanical) */ - if (subsystem_deviceid & 0x0004) { - /* no switch */ - ctrl->slot_switch_type = 0; - } else { - /* switch */ - ctrl->slot_switch_type = 1; - } - - /* PHP Status (0=De-feature PHP, 1=Normal operation) */ - if (subsystem_deviceid & 0x0008) { - ctrl->defeature_PHP = 1; // PHP supported - } else { - ctrl->defeature_PHP = 0; // PHP not supported - } - - /* Alternate Base Address Register Interface (0=not supported, 1=supported) */ - if (subsystem_deviceid & 0x0010) { - ctrl->alternate_base_address = 1; // supported - } else { - ctrl->alternate_base_address = 0; // not supported - } - - /* PCI Config Space Index (0=not supported, 1=supported) */ - if (subsystem_deviceid & 0x0020) { - ctrl->pci_config_space = 1; // supported - } else { - ctrl->pci_config_space = 0; // not supported - } - - /* PCI-X support */ - if (subsystem_deviceid & 0x0080) { - /* PCI-X capable */ - ctrl->pcix_support = 1; - /* Frequency of operation in PCI-X mode */ - if (subsystem_deviceid & 0x0040) { - /* 133MHz PCI-X if bit 7 is 1 */ - ctrl->pcix_speed_capability = 1; - } else { - /* 100MHz PCI-X if bit 7 is 1 and bit 0 is 0, */ - /* 66MHz PCI-X if bit 7 is 1 and bit 0 is 1 */ - ctrl->pcix_speed_capability = 0; - } - } else { - /* Conventional PCI */ - ctrl->pcix_support = 0; - ctrl->pcix_speed_capability = 0; - } - break; - - default: - err(msg_HPC_not_supported); - rc = -ENODEV; - goto err_free_ctrl; - } - - } else { - err(msg_HPC_not_supported); - return -ENODEV; - } - - // Tell the user that we found one. - info("Initializing the PCI hot plug controller residing on PCI bus %d\n", pdev->bus->number); - - dbg ("Hotplug controller capabilities:\n"); - dbg (" speed_capability %d\n", ctrl->speed_capability); - dbg (" slot_switch_type %s\n", ctrl->slot_switch_type == 0 ? "no switch" : "switch present"); - dbg (" defeature_PHP %s\n", ctrl->defeature_PHP == 0 ? "PHP not supported" : "PHP supported"); - dbg (" alternate_base_address %s\n", ctrl->alternate_base_address == 0 ? "not supported" : "supported"); - dbg (" pci_config_space %s\n", ctrl->pci_config_space == 0 ? "not supported" : "supported"); - dbg (" pcix_speed_capability %s\n", ctrl->pcix_speed_capability == 0 ? "not supported" : "supported"); - dbg (" pcix_support %s\n", ctrl->pcix_support == 0 ? "not supported" : "supported"); - - ctrl->pci_dev = pdev; - pci_set_drvdata(pdev, ctrl); - - /* make our own copy of the pci bus structure, as we like tweaking it a lot */ - ctrl->pci_bus = kmalloc (sizeof (*ctrl->pci_bus), GFP_KERNEL); - if (!ctrl->pci_bus) { - err("out of memory\n"); - rc = -ENOMEM; - goto err_free_ctrl; - } - memcpy (ctrl->pci_bus, pdev->bus, sizeof (*ctrl->pci_bus)); - - ctrl->bus = pdev->bus->number; - ctrl->rev = rev; - dbg("bus device function rev: %d %d %d %d\n", ctrl->bus, - PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), ctrl->rev); - - init_MUTEX(&ctrl->crit_sect); - init_waitqueue_head(&ctrl->queue); - - /* initialize our threads if they haven't already been started up */ - rc = one_time_init(); - if (rc) { - goto err_free_bus; - } - - dbg("pdev = %p\n", pdev); - dbg("pci resource start %lx\n", pci_resource_start(pdev, 0)); - dbg("pci resource len %lx\n", pci_resource_len(pdev, 0)); - - if (!request_mem_region(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0), MY_NAME)) { - err("cannot reserve MMIO region\n"); - rc = -ENOMEM; - goto err_free_bus; - } - - ctrl->hpc_reg = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); - if (!ctrl->hpc_reg) { - err("cannot remap MMIO region %lx @ %lx\n", pci_resource_len(pdev, 0), pci_resource_start(pdev, 0)); - rc = -ENODEV; - goto err_free_mem_region; - } - - // Check for 66Mhz operation - ctrl->speed = get_controller_speed(ctrl); - - - //************************************************** - // - // Save configuration headers for this and - // subordinate PCI buses - // - //************************************************** - - // find the physical slot number of the first hot plug slot - - // Get slot won't work for devices behind bridges, but - // in this case it will always be called for the "base" - // bus/dev/func of a slot. - // CS: this is leveraging the PCIIRQ routing code from the kernel (pci-pc.c: get_irq_routing_table) - rc = get_slot_mapping(ctrl->pci_bus, pdev->bus->number, (readb(ctrl->hpc_reg + SLOT_MASK) >> 4), &(ctrl->first_slot)); - dbg("get_slot_mapping: first_slot = %d, returned = %d\n", ctrl->first_slot, rc); - if (rc) { - err(msg_initialization_err, rc); - goto err_iounmap; - } - - // Store PCI Config Space for all devices on this bus - rc = cpqhp_save_config(ctrl, ctrl->bus, readb(ctrl->hpc_reg + SLOT_MASK)); - if (rc) { - err("%s: unable to save PCI configuration data, error %d\n", __FUNCTION__, rc); - goto err_iounmap; - } - - /* - * Get IO, memory, and IRQ resources for new devices - */ - // The next line is required for cpqhp_find_available_resources - ctrl->interrupt = pdev->irq; - - ctrl->cfgspc_irq = 0; - pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &ctrl->cfgspc_irq); - - rc = cpqhp_find_available_resources(ctrl, cpqhp_rom_start); - ctrl->add_support = !rc; - if (rc) { - dbg("cpqhp_find_available_resources = 0x%x\n", rc); - err("unable to locate PCI configuration resources for hot plug add.\n"); - goto err_iounmap; - } - - /* - * Finish setting up the hot plug ctrl device - */ - ctrl->slot_device_offset = readb(ctrl->hpc_reg + SLOT_MASK) >> 4; - dbg("NumSlots %d \n", ctrl->slot_device_offset); - - ctrl->next_event = 0; - - /* Setup the slot information structures */ - rc = ctrl_slot_setup(ctrl, smbios_start, smbios_table); - if (rc) { - err(msg_initialization_err, 6); - err("%s: unable to save PCI configuration data, error %d\n", __FUNCTION__, rc); - goto err_iounmap; - } - - /* Mask all general input interrupts */ - writel(0xFFFFFFFFL, ctrl->hpc_reg + INT_MASK); - - /* set up the interrupt */ - dbg("HPC interrupt = %d \n", ctrl->interrupt); - if (request_irq(ctrl->interrupt, cpqhp_ctrl_intr, - SA_SHIRQ, MY_NAME, ctrl)) { - err("Can't get irq %d for the hotplug pci controller\n", ctrl->interrupt); - rc = -ENODEV; - goto err_iounmap; - } - - /* Enable Shift Out interrupt and clear it, also enable SERR on power fault */ - temp_word = readw(ctrl->hpc_reg + MISC); - temp_word |= 0x4006; - writew(temp_word, ctrl->hpc_reg + MISC); - - // Changed 05/05/97 to clear all interrupts at start - writel(0xFFFFFFFFL, ctrl->hpc_reg + INT_INPUT_CLEAR); - - ctrl->ctrl_int_comp = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); - - writel(0x0L, ctrl->hpc_reg + INT_MASK); - - if (!cpqhp_ctrl_list) { - cpqhp_ctrl_list = ctrl; - ctrl->next = NULL; - } else { - ctrl->next = cpqhp_ctrl_list; - cpqhp_ctrl_list = ctrl; - } - - // turn off empty slots here unless command line option "ON" set - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); - - num_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F; - - // find first device number for the ctrl - device = readb(ctrl->hpc_reg + SLOT_MASK) >> 4; - - while (num_of_slots) { - dbg("num_of_slots: %d\n", num_of_slots); - func = cpqhp_slot_find(ctrl->bus, device, 0); - if (!func) - break; - - hp_slot = func->device - ctrl->slot_device_offset; - dbg("hp_slot: %d\n", hp_slot); - - // We have to save the presence info for these slots - temp_word = ctrl->ctrl_int_comp >> 16; - func->presence_save = (temp_word >> hp_slot) & 0x01; - func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; - - if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) { - func->switch_save = 0; - } else { - func->switch_save = 0x10; - } - - if (!power_mode) { - if (!func->is_a_board) { - green_LED_off (ctrl, hp_slot); - slot_disable (ctrl, hp_slot); - } - } - - device++; - num_of_slots--; - } - - if (!power_mode) { - set_SOGO(ctrl); - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - } - - rc = init_SERR(ctrl); - if (rc) { - err("init_SERR failed\n"); - up(&ctrl->crit_sect); - goto err_free_irq; - } - - // Done with exclusive hardware access - up(&ctrl->crit_sect); - - cpqhp_create_ctrl_files (ctrl); - - return 0; - -err_free_irq: - free_irq(ctrl->interrupt, ctrl); -err_iounmap: - iounmap(ctrl->hpc_reg); -err_free_mem_region: - release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); -err_free_bus: - kfree(ctrl->pci_bus); -err_free_ctrl: - kfree(ctrl); - return rc; -} - - -static int one_time_init(void) -{ - int loop; - int retval = 0; - static int initialized = 0; - - if (initialized) - return 0; - - power_mode = 0; - - retval = pci_print_IRQ_route(); - if (retval) - goto error; - - dbg("Initialize + Start the notification mechanism \n"); - - retval = cpqhp_event_start_thread(); - if (retval) - goto error; - - dbg("Initialize slot lists\n"); - for (loop = 0; loop < 256; loop++) { - cpqhp_slot_list[loop] = NULL; - } - - // FIXME: We also need to hook the NMI handler eventually. - // this also needs to be worked with Christoph - // register_NMI_handler(); - - // Map rom address - cpqhp_rom_start = ioremap(ROM_PHY_ADDR, ROM_PHY_LEN); - if (!cpqhp_rom_start) { - err ("Could not ioremap memory region for ROM\n"); - retval = -EIO;; - goto error; - } - - /* Now, map the int15 entry point if we are on compaq specific hardware */ - compaq_nvram_init(cpqhp_rom_start); - - /* Map smbios table entry point structure */ - smbios_table = detect_SMBIOS_pointer(cpqhp_rom_start, cpqhp_rom_start + ROM_PHY_LEN); - if (!smbios_table) { - err ("Could not find the SMBIOS pointer in memory\n"); - retval = -EIO;; - goto error; - } - - smbios_start = ioremap(readl(smbios_table + ST_ADDRESS), readw(smbios_table + ST_LENGTH)); - if (!smbios_start) { - err ("Could not ioremap memory region taken from SMBIOS values\n"); - retval = -EIO;; - goto error; - } - - initialized = 1; - - return retval; - -error: - if (cpqhp_rom_start) - iounmap(cpqhp_rom_start); - if (smbios_start) - iounmap(smbios_start); - - return retval; -} - - -static void unload_cpqphpd(void) -{ - struct pci_func *next; - struct pci_func *TempSlot; - int loop; - u32 rc; - struct controller *ctrl; - struct controller *tctrl; - struct pci_resource *res; - struct pci_resource *tres; - - rc = compaq_nvram_store(cpqhp_rom_start); - - ctrl = cpqhp_ctrl_list; - - while (ctrl) { - if (ctrl->hpc_reg) { - u16 misc; - rc = read_slot_enable (ctrl); - - writeb(0, ctrl->hpc_reg + SLOT_SERR); - writel(0xFFFFFFC0L | ~rc, ctrl->hpc_reg + INT_MASK); - - misc = readw(ctrl->hpc_reg + MISC); - misc &= 0xFFFD; - writew(misc, ctrl->hpc_reg + MISC); - } - - ctrl_slot_cleanup(ctrl); - - res = ctrl->io_head; - while (res) { - tres = res; - res = res->next; - kfree(tres); - } - - res = ctrl->mem_head; - while (res) { - tres = res; - res = res->next; - kfree(tres); - } - - res = ctrl->p_mem_head; - while (res) { - tres = res; - res = res->next; - kfree(tres); - } - - res = ctrl->bus_head; - while (res) { - tres = res; - res = res->next; - kfree(tres); - } - - kfree (ctrl->pci_bus); - - tctrl = ctrl; - ctrl = ctrl->next; - kfree(tctrl); - } - - for (loop = 0; loop < 256; loop++) { - next = cpqhp_slot_list[loop]; - while (next != NULL) { - res = next->io_head; - while (res) { - tres = res; - res = res->next; - kfree(tres); - } - - res = next->mem_head; - while (res) { - tres = res; - res = res->next; - kfree(tres); - } - - res = next->p_mem_head; - while (res) { - tres = res; - res = res->next; - kfree(tres); - } - - res = next->bus_head; - while (res) { - tres = res; - res = res->next; - kfree(tres); - } - - TempSlot = next; - next = next->next; - kfree(TempSlot); - } - } - - // Stop the notification mechanism - cpqhp_event_stop_thread(); - - //unmap the rom address - if (cpqhp_rom_start) - iounmap(cpqhp_rom_start); - if (smbios_start) - iounmap(smbios_start); -} - - - -static struct pci_device_id hpcd_pci_tbl[] __devinitdata = { - { - /* handle any PCI Hotplug controller */ - .class = ((PCI_CLASS_SYSTEM_PCI_HOTPLUG << 8) | 0x00), - .class_mask = ~0, - - /* no matter who makes it */ - .vendor = PCI_ANY_ID, - .device = PCI_ANY_ID, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - - }, { /* end: all zeroes */ } -}; - -MODULE_DEVICE_TABLE(pci, hpcd_pci_tbl); - - - -static struct pci_driver cpqhpc_driver = { - .name = "pci_hotplug", - .id_table = hpcd_pci_tbl, - .probe = cpqhpc_probe, - /* remove: cpqhpc_remove_one, */ -}; - - - -static int __init cpqhpc_init(void) -{ - int result; - - cpqhp_debug = debug; - - result = pci_module_init(&cpqhpc_driver); - dbg("pci_module_init = %d\n", result); - if (result) - return result; - info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); - return 0; -} - - -static void __exit cpqhpc_cleanup(void) -{ - dbg("unload_cpqphpd()\n"); - unload_cpqphpd(); - - dbg("pci_unregister_driver\n"); - pci_unregister_driver(&cpqhpc_driver); -} - - -module_init(cpqhpc_init); -module_exit(cpqhpc_cleanup); - - diff -Nru a/drivers/hotplug/cpqphp_ctrl.c b/drivers/hotplug/cpqphp_ctrl.c --- a/drivers/hotplug/cpqphp_ctrl.c Mon Jun 9 23:16:10 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,3084 +0,0 @@ -/* - * Compaq Hot Plug Controller Driver - * - * Copyright (c) 1995,2001 Compaq Computer Corporation - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or - * NON INFRINGEMENT. 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. - * - * Send feedback to <greg@kroah.com> - * - */ - -#include <linux/config.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/slab.h> -#include <linux/workqueue.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/wait.h> -#include <linux/smp_lock.h> -#include <linux/pci.h> -#include "cpqphp.h" - -static u32 configure_new_device(struct controller* ctrl, struct pci_func *func,u8 behind_bridge, struct resource_lists *resources); -static int configure_new_function(struct controller* ctrl, struct pci_func *func,u8 behind_bridge, struct resource_lists *resources); -static void interrupt_event_handler(struct controller *ctrl); - -static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ -static struct semaphore event_exit; /* guard ensure thread has exited before calling it quits */ -static int event_finished; -static unsigned long pushbutton_pending; /* = 0 */ - -/* things needed for the long_delay function */ -static struct semaphore delay_sem; -static wait_queue_head_t delay_wait; - -/* delay is in jiffies to wait for */ -static void long_delay (int delay) -{ - DECLARE_WAITQUEUE(wait, current); - - /* only allow 1 customer into the delay queue at once - * yes this makes some people wait even longer, but who really cares? - * this is for _huge_ delays to make the hardware happy as the - * signals bounce around - */ - down (&delay_sem); - - init_waitqueue_head (&delay_wait); - - add_wait_queue(&delay_wait, &wait); - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(delay); - remove_wait_queue(&delay_wait, &wait); - set_current_state(TASK_RUNNING); - - up (&delay_sem); -} - - -//FIXME: The following line needs to be somewhere else... -#define WRONG_BUS_FREQUENCY 0x07 -static u8 handle_switch_change(u8 change, struct controller * ctrl) -{ - int hp_slot; - u8 rc = 0; - u16 temp_word; - struct pci_func *func; - struct event_info *taskInfo; - - if (!change) - return 0; - - // Switch Change - dbg("cpqsbd: Switch interrupt received.\n"); - - for (hp_slot = 0; hp_slot < 6; hp_slot++) { - if (change & (0x1L << hp_slot)) { - //********************************* - // this one changed. - //********************************* - func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0); - - //this is the structure that tells the worker thread - //what to do - taskInfo = &(ctrl->event_queue[ctrl->next_event]); - ctrl->next_event = (ctrl->next_event + 1) % 10; - taskInfo->hp_slot = hp_slot; - - rc++; - - temp_word = ctrl->ctrl_int_comp >> 16; - func->presence_save = (temp_word >> hp_slot) & 0x01; - func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; - - if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) { - //********************************* - // Switch opened - //********************************* - - func->switch_save = 0; - - taskInfo->event_type = INT_SWITCH_OPEN; - } else { - //********************************* - // Switch closed - //********************************* - - func->switch_save = 0x10; - - taskInfo->event_type = INT_SWITCH_CLOSE; - } - } - } - - return rc; -} - - -/* - * cpqhp_find_slot - */ -struct slot *cpqhp_find_slot (struct controller * ctrl, u8 device) -{ - struct slot *slot; - - if (!ctrl) - return NULL; - - slot = ctrl->slot; - - while (slot && (slot->device != device)) { - slot = slot->next; - } - - return slot; -} - - -static u8 handle_presence_change(u16 change, struct controller * ctrl) -{ - int hp_slot; - u8 rc = 0; - u8 temp_byte; - u16 temp_word; - struct pci_func *func; - struct event_info *taskInfo; - struct slot *p_slot; - - if (!change) - return 0; - - //********************************* - // Presence Change - //********************************* - dbg("cpqsbd: Presence/Notify input change.\n"); - dbg(" Changed bits are 0x%4.4x\n", change ); - - for (hp_slot = 0; hp_slot < 6; hp_slot++) { - if (change & (0x0101 << hp_slot)) { - //********************************* - // this one changed. - //********************************* - func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0); - - taskInfo = &(ctrl->event_queue[ctrl->next_event]); - ctrl->next_event = (ctrl->next_event + 1) % 10; - taskInfo->hp_slot = hp_slot; - - rc++; - - p_slot = cpqhp_find_slot(ctrl, hp_slot + (readb(ctrl->hpc_reg + SLOT_MASK) >> 4)); - if (!p_slot) - return 0; - - // If the switch closed, must be a button - // If not in button mode, nevermind - if (func->switch_save && (ctrl->push_button == 1)) { - temp_word = ctrl->ctrl_int_comp >> 16; - temp_byte = (temp_word >> hp_slot) & 0x01; - temp_byte |= (temp_word >> (hp_slot + 7)) & 0x02; - - if (temp_byte != func->presence_save) { - //********************************* - // button Pressed (doesn't do anything) - //********************************* - dbg("hp_slot %d button pressed\n", hp_slot); - taskInfo->event_type = INT_BUTTON_PRESS; - } else { - //********************************* - // button Released - TAKE ACTION!!!! - //********************************* - dbg("hp_slot %d button released\n", hp_slot); - taskInfo->event_type = INT_BUTTON_RELEASE; - - // Cancel if we are still blinking - if ((p_slot->state == BLINKINGON_STATE) - || (p_slot->state == BLINKINGOFF_STATE)) { - taskInfo->event_type = INT_BUTTON_CANCEL; - dbg("hp_slot %d button cancel\n", hp_slot); - } else if ((p_slot->state == POWERON_STATE) - || (p_slot->state == POWEROFF_STATE)) { - //info(msg_button_ignore, p_slot->number); - taskInfo->event_type = INT_BUTTON_IGNORE; - dbg("hp_slot %d button ignore\n", hp_slot); - } - } - } else { - // Switch is open, assume a presence change - // Save the presence state - temp_word = ctrl->ctrl_int_comp >> 16; - func->presence_save = (temp_word >> hp_slot) & 0x01; - func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; - - if ((!(ctrl->ctrl_int_comp & (0x010000 << hp_slot))) || - (!(ctrl->ctrl_int_comp & (0x01000000 << hp_slot)))) { - //********************************* - // Present - //********************************* - taskInfo->event_type = INT_PRESENCE_ON; - } else { - //********************************* - // Not Present - //********************************* - taskInfo->event_type = INT_PRESENCE_OFF; - } - } - } - } - - return rc; -} - - -static u8 handle_power_fault(u8 change, struct controller * ctrl) -{ - int hp_slot; - u8 rc = 0; - struct pci_func *func; - struct event_info *taskInfo; - - if (!change) - return 0; - - //********************************* - // power fault - //********************************* - - info("power fault interrupt\n"); - - for (hp_slot = 0; hp_slot < 6; hp_slot++) { - if (change & (0x01 << hp_slot)) { - //********************************* - // this one changed. - //********************************* - func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0); - - taskInfo = &(ctrl->event_queue[ctrl->next_event]); - ctrl->next_event = (ctrl->next_event + 1) % 10; - taskInfo->hp_slot = hp_slot; - - rc++; - - if (ctrl->ctrl_int_comp & (0x00000100 << hp_slot)) { - //********************************* - // power fault Cleared - //********************************* - func->status = 0x00; - - taskInfo->event_type = INT_POWER_FAULT_CLEAR; - } else { - //********************************* - // power fault - //********************************* - taskInfo->event_type = INT_POWER_FAULT; - - if (ctrl->rev < 4) { - amber_LED_on (ctrl, hp_slot); - green_LED_off (ctrl, hp_slot); - set_SOGO (ctrl); - - // this is a fatal condition, we want to crash the - // machine to protect from data corruption - // simulated_NMI shouldn't ever return - //FIXME - //simulated_NMI(hp_slot, ctrl); - - //The following code causes a software crash just in - //case simulated_NMI did return - //FIXME - //panic(msg_power_fault); - } else { - // set power fault status for this board - func->status = 0xFF; - info("power fault bit %x set\n", hp_slot); - } - } - } - } - - return rc; -} - - -/* - * sort_by_size - * - * Sorts nodes on the list by their length. - * Smallest first. - * - */ -static int sort_by_size(struct pci_resource **head) -{ - struct pci_resource *current_res; - struct pci_resource *next_res; - int out_of_order = 1; - - if (!(*head)) - return(1); - - if (!((*head)->next)) - return(0); - - while (out_of_order) { - out_of_order = 0; - - // Special case for swapping list head - if (((*head)->next) && - ((*head)->length > (*head)->next->length)) { - out_of_order++; - current_res = *head; - *head = (*head)->next; - current_res->next = (*head)->next; - (*head)->next = current_res; - } - - current_res = *head; - - while (current_res->next && current_res->next->next) { - if (current_res->next->length > current_res->next->next->length) { - out_of_order++; - next_res = current_res->next; - current_res->next = current_res->next->next; - current_res = current_res->next; - next_res->next = current_res->next; - current_res->next = next_res; - } else - current_res = current_res->next; - } - } // End of out_of_order loop - - return(0); -} - - -/* - * sort_by_max_size - * - * Sorts nodes on the list by their length. - * Largest first. - * - */ -static int sort_by_max_size(struct pci_resource **head) -{ - struct pci_resource *current_res; - struct pci_resource *next_res; - int out_of_order = 1; - - if (!(*head)) - return(1); - - if (!((*head)->next)) - return(0); - - while (out_of_order) { - out_of_order = 0; - - // Special case for swapping list head - if (((*head)->next) && - ((*head)->length < (*head)->next->length)) { - out_of_order++; - current_res = *head; - *head = (*head)->next; - current_res->next = (*head)->next; - (*head)->next = current_res; - } - - current_res = *head; - - while (current_res->next && current_res->next->next) { - if (current_res->next->length < current_res->next->next->length) { - out_of_order++; - next_res = current_res->next; - current_res->next = current_res->next->next; - current_res = current_res->next; - next_res->next = current_res->next; - current_res->next = next_res; - } else - current_res = current_res->next; - } - } // End of out_of_order loop - - return(0); -} - - -/* - * do_pre_bridge_resource_split - * - * Returns zero or one node of resources that aren't in use - * - */ -static struct pci_resource *do_pre_bridge_resource_split (struct pci_resource **head, struct pci_resource **orig_head, u32 alignment) -{ - struct pci_resource *prevnode = NULL; - struct pci_resource *node; - struct pci_resource *split_node; - u32 rc; - u32 temp_dword; - dbg("do_pre_bridge_resource_split\n"); - - if (!(*head) || !(*orig_head)) - return(NULL); - - rc = cpqhp_resource_sort_and_combine(head); - - if (rc) - return(NULL); - - if ((*head)->base != (*orig_head)->base) - return(NULL); - - if ((*head)->length == (*orig_head)->length) - return(NULL); - - - // If we got here, there the bridge requires some of the resource, but - // we may be able to split some off of the front - - node = *head; - - if (node->length & (alignment -1)) { - // this one isn't an aligned length, so we'll make a new entry - // and split it up. - split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - - if (!split_node) - return(NULL); - - temp_dword = (node->length | (alignment-1)) + 1 - alignment; - - split_node->base = node->base; - split_node->length = temp_dword; - - node->length -= temp_dword; - node->base += split_node->length; - - // Put it in the list - *head = split_node; - split_node->next = node; - } - - if (node->length < alignment) { - return(NULL); - } - - // Now unlink it - if (*head == node) { - *head = node->next; - node->next = NULL; - } else { - prevnode = *head; - while (prevnode->next != node) - prevnode = prevnode->next; - - prevnode->next = node->next; - node->next = NULL; - } - - return(node); -} - - -/* - * do_bridge_resource_split - * - * Returns zero or one node of resources that aren't in use - * - */ -static struct pci_resource *do_bridge_resource_split (struct pci_resource **head, u32 alignment) -{ - struct pci_resource *prevnode = NULL; - struct pci_resource *node; - u32 rc; - u32 temp_dword; - - if (!(*head)) - return(NULL); - - rc = cpqhp_resource_sort_and_combine(head); - - if (rc) - return(NULL); - - node = *head; - - while (node->next) { - prevnode = node; - node = node->next; - kfree(prevnode); - } - - if (node->length < alignment) { - kfree(node); - return(NULL); - } - - if (node->base & (alignment - 1)) { - // Short circuit if adjusted size is too small - temp_dword = (node->base | (alignment-1)) + 1; - if ((node->length - (temp_dword - node->base)) < alignment) { - kfree(node); - return(NULL); - } - - node->length -= (temp_dword - node->base); - node->base = temp_dword; - } - - if (node->length & (alignment - 1)) { - // There's stuff in use after this node - kfree(node); - return(NULL); - } - - return(node); -} - - -/* - * get_io_resource - * - * this function sorts the resource list by size and then - * returns the first node of "size" length that is not in the - * ISA aliasing window. If it finds a node larger than "size" - * it will split it up. - * - * size must be a power of two. - */ -static struct pci_resource *get_io_resource (struct pci_resource **head, u32 size) -{ - struct pci_resource *prevnode; - struct pci_resource *node; - struct pci_resource *split_node; - u32 temp_dword; - - if (!(*head)) - return(NULL); - - if ( cpqhp_resource_sort_and_combine(head) ) - return(NULL); - - if ( sort_by_size(head) ) - return(NULL); - - for (node = *head; node; node = node->next) { - if (node->length < size) - continue; - - if (node->base & (size - 1)) { - // this one isn't base aligned properly - // so we'll make a new entry and split it up - temp_dword = (node->base | (size-1)) + 1; - - // Short circuit if adjusted size is too small - if ((node->length - (temp_dword - node->base)) < size) - continue; - - split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - - if (!split_node) - return(NULL); - - split_node->base = node->base; - split_node->length = temp_dword - node->base; - node->base = temp_dword; - node->length -= split_node->length; - - // Put it in the list - split_node->next = node->next; - node->next = split_node; - } // End of non-aligned base - - // Don't need to check if too small since we already did - if (node->length > size) { - // this one is longer than we need - // so we'll make a new entry and split it up - split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - - if (!split_node) - return(NULL); - - split_node->base = node->base + size; - split_node->length = node->length - size; - node->length = size; - - // Put it in the list - split_node->next = node->next; - node->next = split_node; - } // End of too big on top end - - // For IO make sure it's not in the ISA aliasing space - if (node->base & 0x300L) - continue; - - // If we got here, then it is the right size - // Now take it out of the list - if (*head == node) { - *head = node->next; - } else { - prevnode = *head; - while (prevnode->next != node) - prevnode = prevnode->next; - - prevnode->next = node->next; - } - node->next = NULL; - // Stop looping - break; - } - - return(node); -} - - -/* - * get_max_resource - * - * Gets the largest node that is at least "size" big from the - * list pointed to by head. It aligns the node on top and bottom - * to "size" alignment before returning it. - */ -static struct pci_resource *get_max_resource (struct pci_resource **head, u32 size) -{ - struct pci_resource *max; - struct pci_resource *temp; - struct pci_resource *split_node; - u32 temp_dword; - - if (!(*head)) - return(NULL); - - if (cpqhp_resource_sort_and_combine(head)) - return(NULL); - - if (sort_by_max_size(head)) - return(NULL); - - for (max = *head;max; max = max->next) { - - // If not big enough we could probably just bail, - // instead we'll continue to the next. - if (max->length < size) - continue; - - if (max->base & (size - 1)) { - // this one isn't base aligned properly - // so we'll make a new entry and split it up - temp_dword = (max->base | (size-1)) + 1; - - // Short circuit if adjusted size is too small - if ((max->length - (temp_dword - max->base)) < size) - continue; - - split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - - if (!split_node) - return(NULL); - - split_node->base = max->base; - split_node->length = temp_dword - max->base; - max->base = temp_dword; - max->length -= split_node->length; - - // Put it next in the list - split_node->next = max->next; - max->next = split_node; - } - - if ((max->base + max->length) & (size - 1)) { - // this one isn't end aligned properly at the top - // so we'll make a new entry and split it up - split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - - if (!split_node) - return(NULL); - temp_dword = ((max->base + max->length) & ~(size - 1)); - split_node->base = temp_dword; - split_node->length = max->length + max->base - - split_node->base; - max->length -= split_node->length; - - // Put it in the list - split_node->next = max->next; - max->next = split_node; - } - - // Make sure it didn't shrink too much when we aligned it - if (max->length < size) - continue; - - // Now take it out of the list - temp = (struct pci_resource*) *head; - if (temp == max) { - *head = max->next; - } else { - while (temp && temp->next != max) { - temp = temp->next; - } - - temp->next = max->next; - } - - max->next = NULL; - return(max); - } - - // If we get here, we couldn't find one - return(NULL); -} - - -/* - * get_resource - * - * this function sorts the resource list by size and then - * returns the first node of "size" length. If it finds a node - * larger than "size" it will split it up. - * - * size must be a power of two. - */ -static struct pci_resource *get_resource (struct pci_resource **head, u32 size) -{ - struct pci_resource *prevnode; - struct pci_resource *node; - struct pci_resource *split_node; - u32 temp_dword; - - if (!(*head)) - return(NULL); - - if ( cpqhp_resource_sort_and_combine(head) ) - return(NULL); - - if ( sort_by_size(head) ) - return(NULL); - - for (node = *head; node; node = node->next) { - dbg("%s: req_size =%x node=%p, base=%x, length=%x\n", - __FUNCTION__, size, node, node->base, node->length); - if (node->length < size) - continue; - - if (node->base & (size - 1)) { - dbg("%s: not aligned\n", __FUNCTION__); - // this one isn't base aligned properly - // so we'll make a new entry and split it up - temp_dword = (node->base | (size-1)) + 1; - - // Short circuit if adjusted size is too small - if ((node->length - (temp_dword - node->base)) < size) - continue; - - split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - - if (!split_node) - return(NULL); - - split_node->base = node->base; - split_node->length = temp_dword - node->base; - node->base = temp_dword; - node->length -= split_node->length; - - // Put it in the list - split_node->next = node->next; - node->next = split_node; - } // End of non-aligned base - - // Don't need to check if too small since we already did - if (node->length > size) { - dbg("%s: too big\n", __FUNCTION__); - // this one is longer than we need - // so we'll make a new entry and split it up - split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - - if (!split_node) - return(NULL); - - split_node->base = node->base + size; - split_node->length = node->length - size; - node->length = size; - - // Put it in the list - split_node->next = node->next; - node->next = split_node; - } // End of too big on top end - - dbg("%s: got one!!!\n", __FUNCTION__); - // If we got here, then it is the right size - // Now take it out of the list - if (*head == node) { - *head = node->next; - } else { - prevnode = *head; - while (prevnode->next != node) - prevnode = prevnode->next; - - prevnode->next = node->next; - } - node->next = NULL; - // Stop looping - break; - } - return(node); -} - - -/* - * cpqhp_resource_sort_and_combine - * - * Sorts all of the nodes in the list in ascending order by - * their base addresses. Also does garbage collection by - * combining adjacent nodes. - * - * returns 0 if success - */ -int cpqhp_resource_sort_and_combine(struct pci_resource **head) -{ - struct pci_resource *node1; - struct pci_resource *node2; - int out_of_order = 1; - - dbg("%s: head = %p, *head = %p\n", __FUNCTION__, head, *head); - - if (!(*head)) - return(1); - - dbg("*head->next = %p\n",(*head)->next); - - if (!(*head)->next) - return(0); /* only one item on the list, already sorted! */ - - dbg("*head->base = 0x%x\n",(*head)->base); - dbg("*head->next->base = 0x%x\n",(*head)->next->base); - while (out_of_order) { - out_of_order = 0; - - // Special case for swapping list head - if (((*head)->next) && - ((*head)->base > (*head)->next->base)) { - node1 = *head; - (*head) = (*head)->next; - node1->next = (*head)->next; - (*head)->next = node1; - out_of_order++; - } - - node1 = (*head); - - while (node1->next && node1->next->next) { - if (node1->next->base > node1->next->next->base) { - out_of_order++; - node2 = node1->next; - node1->next = node1->next->next; - node1 = node1->next; - node2->next = node1->next; - node1->next = node2; - } else - node1 = node1->next; - } - } // End of out_of_order loop - - node1 = *head; - - while (node1 && node1->next) { - if ((node1->base + node1->length) == node1->next->base) { - // Combine - dbg("8..\n"); - node1->length += node1->next->length; - node2 = node1->next; - node1->next = node1->next->next; - kfree(node2); - } else - node1 = node1->next; - } - - return(0); -} - - -irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data, struct pt_regs *regs) -{ - struct controller *ctrl = data; - u8 schedule_flag = 0; - u8 reset; - u16 misc; - u32 Diff; - u32 temp_dword; - - - misc = readw(ctrl->hpc_reg + MISC); - //********************************* - // Check to see if it was our interrupt - //********************************* - if (!(misc & 0x000C)) { - return IRQ_NONE; - } - - if (misc & 0x0004) { - //********************************* - // Serial Output interrupt Pending - //********************************* - - // Clear the interrupt - misc |= 0x0004; - writew(misc, ctrl->hpc_reg + MISC); - - // Read to clear posted writes - misc = readw(ctrl->hpc_reg + MISC); - - dbg ("%s - waking up\n", __FUNCTION__); - wake_up_interruptible(&ctrl->queue); - } - - if (misc & 0x0008) { - // General-interrupt-input interrupt Pending - Diff = readl(ctrl->hpc_reg + INT_INPUT_CLEAR) ^ ctrl->ctrl_int_comp; - - ctrl->ctrl_int_comp = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); - - // Clear the interrupt - writel(Diff, ctrl->hpc_reg + INT_INPUT_CLEAR); - - // Read it back to clear any posted writes - temp_dword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); - - if (!Diff) { - // Clear all interrupts - writel(0xFFFFFFFF, ctrl->hpc_reg + INT_INPUT_CLEAR); - } - - schedule_flag += handle_switch_change((u8)(Diff & 0xFFL), ctrl); - schedule_flag += handle_presence_change((u16)((Diff & 0xFFFF0000L) >> 16), ctrl); - schedule_flag += handle_power_fault((u8)((Diff & 0xFF00L) >> 8), ctrl); - } - - reset = readb(ctrl->hpc_reg + RESET_FREQ_MODE); - if (reset & 0x40) { - /* Bus reset has completed */ - reset &= 0xCF; - writeb(reset, ctrl->hpc_reg + RESET_FREQ_MODE); - reset = readb(ctrl->hpc_reg + RESET_FREQ_MODE); - wake_up_interruptible(&ctrl->queue); - } - - if (schedule_flag) { - up(&event_semaphore); - dbg("Signal event_semaphore\n"); - } - return IRQ_HANDLED; -} - - -/** - * cpqhp_slot_create - Creates a node and adds it to the proper bus. - * @busnumber - bus where new node is to be located - * - * Returns pointer to the new node or NULL if unsuccessful - */ -struct pci_func *cpqhp_slot_create(u8 busnumber) -{ - struct pci_func *new_slot; - struct pci_func *next; - - new_slot = (struct pci_func *) kmalloc(sizeof(struct pci_func), GFP_KERNEL); - - if (new_slot == NULL) { - // I'm not dead yet! - // You will be. - return(new_slot); - } - - memset(new_slot, 0, sizeof(struct pci_func)); - - new_slot->next = NULL; - new_slot->configured = 1; - - if (cpqhp_slot_list[busnumber] == NULL) { - cpqhp_slot_list[busnumber] = new_slot; - } else { - next = cpqhp_slot_list[busnumber]; - while (next->next != NULL) - next = next->next; - next->next = new_slot; - } - return(new_slot); -} - - -/* - * slot_remove - Removes a node from the linked list of slots. - * @old_slot: slot to remove - * - * Returns 0 if successful, !0 otherwise. - */ -static int slot_remove(struct pci_func * old_slot) -{ - struct pci_func *next; - - if (old_slot == NULL) - return(1); - - next = cpqhp_slot_list[old_slot->bus]; - - if (next == NULL) { - return(1); - } - - if (next == old_slot) { - cpqhp_slot_list[old_slot->bus] = old_slot->next; - cpqhp_destroy_board_resources(old_slot); - kfree(old_slot); - return(0); - } - - while ((next->next != old_slot) && (next->next != NULL)) { - next = next->next; - } - - if (next->next == old_slot) { - next->next = old_slot->next; - cpqhp_destroy_board_resources(old_slot); - kfree(old_slot); - return(0); - } else - return(2); -} - - -/** - * bridge_slot_remove - Removes a node from the linked list of slots. - * @bridge: bridge to remove - * - * Returns 0 if successful, !0 otherwise. - */ -static int bridge_slot_remove(struct pci_func *bridge) -{ - u8 subordinateBus, secondaryBus; - u8 tempBus; - struct pci_func *next; - - if (bridge == NULL) - return(1); - - secondaryBus = (bridge->config_space[0x06] >> 8) & 0xFF; - subordinateBus = (bridge->config_space[0x06] >> 16) & 0xFF; - - for (tempBus = secondaryBus; tempBus <= subordinateBus; tempBus++) { - next = cpqhp_slot_list[tempBus]; - - while (!slot_remove(next)) { - next = cpqhp_slot_list[tempBus]; - } - } - - next = cpqhp_slot_list[bridge->bus]; - - if (next == NULL) { - return(1); - } - - if (next == bridge) { - cpqhp_slot_list[bridge->bus] = bridge->next; - kfree(bridge); - return(0); - } - - while ((next->next != bridge) && (next->next != NULL)) { - next = next->next; - } - - if (next->next == bridge) { - next->next = bridge->next; - kfree(bridge); - return(0); - } else - return(2); -} - - -/** - * cpqhp_slot_find - Looks for a node by bus, and device, multiple functions accessed - * @bus: bus to find - * @device: device to find - * @index: is 0 for first function found, 1 for the second... - * - * Returns pointer to the node if successful, %NULL otherwise. - */ -struct pci_func *cpqhp_slot_find(u8 bus, u8 device, u8 index) -{ - int found = -1; - struct pci_func *func; - - func = cpqhp_slot_list[bus]; - - if ((func == NULL) || ((func->device == device) && (index == 0))) - return(func); - - if (func->device == device) - found++; - - while (func->next != NULL) { - func = func->next; - - if (func->device == device) - found++; - - if (found == index) - return(func); - } - - return(NULL); -} - - -// DJZ: I don't think is_bridge will work as is. -//FIXME -static int is_bridge(struct pci_func * func) -{ - // Check the header type - if (((func->config_space[0x03] >> 16) & 0xFF) == 0x01) - return 1; - else - return 0; -} - - -/* the following routines constitute the bulk of the - hotplug controller logic - */ - - -/** - * board_replaced - Called after a board has been replaced in the system. - * - * This is only used if we don't have resources for hot add - * Turns power on for the board - * Checks to see if board is the same - * If board is same, reconfigures it - * If board isn't same, turns it back off. - * - */ -static u32 board_replaced(struct pci_func * func, struct controller * ctrl) -{ - u8 hp_slot; - u8 temp_byte; - u8 adapter_speed; - u32 index; - u32 rc = 0; - u32 src = 8; - - hp_slot = func->device - ctrl->slot_device_offset; - - if (readl(ctrl->hpc_reg + INT_INPUT_CLEAR) & (0x01L << hp_slot)) { - //********************************* - // The switch is open. - //********************************* - rc = INTERLOCK_OPEN; - } else if (is_slot_enabled (ctrl, hp_slot)) { - //********************************* - // The board is already on - //********************************* - rc = CARD_FUNCTIONING; - } else { - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); - - // turn on board without attaching to the bus - enable_slot_power (ctrl, hp_slot); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - // Change bits in slot power register to force another shift out - // NOTE: this is to work around the timer bug - temp_byte = readb(ctrl->hpc_reg + SLOT_POWER); - writeb(0x00, ctrl->hpc_reg + SLOT_POWER); - writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - adapter_speed = get_adapter_speed(ctrl, hp_slot); - if (ctrl->speed != adapter_speed) - if (set_controller_speed(ctrl, adapter_speed, hp_slot)) - rc = WRONG_BUS_FREQUENCY; - - // turn off board without attaching to the bus - disable_slot_power (ctrl, hp_slot); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - // Done with exclusive hardware access - up(&ctrl->crit_sect); - - if (rc) - return(rc); - - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); - - slot_enable (ctrl, hp_slot); - green_LED_blink (ctrl, hp_slot); - - amber_LED_off (ctrl, hp_slot); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - // Done with exclusive hardware access - up(&ctrl->crit_sect); - - // Wait for ~1 second because of hot plug spec - long_delay(1*HZ); - - // Check for a power fault - if (func->status == 0xFF) { - // power fault occurred, but it was benign - rc = POWER_FAILURE; - func->status = 0; - } else - rc = cpqhp_valid_replace(ctrl, func); - - if (!rc) { - // It must be the same board - - rc = cpqhp_configure_board(ctrl, func); - - if (rc || src) { - // If configuration fails, turn it off - // Get slot won't work for devices behind bridges, but - // in this case it will always be called for the "base" - // bus/dev/func of an adapter. - - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); - - amber_LED_on (ctrl, hp_slot); - green_LED_off (ctrl, hp_slot); - slot_disable (ctrl, hp_slot); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - // Done with exclusive hardware access - up(&ctrl->crit_sect); - - if (rc) - return(rc); - else - return(1); - } - - func->status = 0; - func->switch_save = 0x10; - - index = 1; - while (((func = cpqhp_slot_find(func->bus, func->device, index)) != NULL) && !rc) { - rc |= cpqhp_configure_board(ctrl, func); - index++; - } - - if (rc) { - // If configuration fails, turn it off - // Get slot won't work for devices behind bridges, but - // in this case it will always be called for the "base" - // bus/dev/func of an adapter. - - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); - - amber_LED_on (ctrl, hp_slot); - green_LED_off (ctrl, hp_slot); - slot_disable (ctrl, hp_slot); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - // Done with exclusive hardware access - up(&ctrl->crit_sect); - - return(rc); - } - // Done configuring so turn LED on full time - - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); - - green_LED_on (ctrl, hp_slot); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - // Done with exclusive hardware access - up(&ctrl->crit_sect); - rc = 0; - } else { - // Something is wrong - - // Get slot won't work for devices behind bridges, but - // in this case it will always be called for the "base" - // bus/dev/func of an adapter. - - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); - - amber_LED_on (ctrl, hp_slot); - green_LED_off (ctrl, hp_slot); - slot_disable (ctrl, hp_slot); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - // Done with exclusive hardware access - up(&ctrl->crit_sect); - } - - } - return(rc); - -} - - -/** - * board_added - Called after a board has been added to the system. - * - * Turns power on for the board - * Configures board - * - */ -static u32 board_added(struct pci_func * func, struct controller * ctrl) -{ - u8 hp_slot; - u8 temp_byte; - u8 adapter_speed; - int index; - u32 temp_register = 0xFFFFFFFF; - u32 rc = 0; - struct pci_func *new_slot = NULL; - struct slot *p_slot; - struct resource_lists res_lists; - - hp_slot = func->device - ctrl->slot_device_offset; - dbg("%s: func->device, slot_offset, hp_slot = %d, %d ,%d\n", - __FUNCTION__, func->device, ctrl->slot_device_offset, hp_slot); - - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); - - // turn on board without attaching to the bus - enable_slot_power (ctrl, hp_slot); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - // Change bits in slot power register to force another shift out - // NOTE: this is to work around the timer bug - temp_byte = readb(ctrl->hpc_reg + SLOT_POWER); - writeb(0x00, ctrl->hpc_reg + SLOT_POWER); - writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - adapter_speed = get_adapter_speed(ctrl, hp_slot); - if (ctrl->speed != adapter_speed) - if (set_controller_speed(ctrl, adapter_speed, hp_slot)) - rc = WRONG_BUS_FREQUENCY; - - // turn off board without attaching to the bus - disable_slot_power (ctrl, hp_slot); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - // Done with exclusive hardware access - up(&ctrl->crit_sect); - - if (rc) - return(rc); - - p_slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); - - // turn on board and blink green LED - - // Wait for exclusive access to hardware - dbg("%s: before down\n", __FUNCTION__); - down(&ctrl->crit_sect); - dbg("%s: after down\n", __FUNCTION__); - - dbg("%s: before slot_enable\n", __FUNCTION__); - slot_enable (ctrl, hp_slot); - - dbg("%s: before green_LED_blink\n", __FUNCTION__); - green_LED_blink (ctrl, hp_slot); - - dbg("%s: before amber_LED_blink\n", __FUNCTION__); - amber_LED_off (ctrl, hp_slot); - - dbg("%s: before set_SOGO\n", __FUNCTION__); - set_SOGO(ctrl); - - // Wait for SOBS to be unset - dbg("%s: before wait_for_ctrl_irq\n", __FUNCTION__); - wait_for_ctrl_irq (ctrl); - dbg("%s: after wait_for_ctrl_irq\n", __FUNCTION__); - - // Done with exclusive hardware access - dbg("%s: before up\n", __FUNCTION__); - up(&ctrl->crit_sect); - dbg("%s: after up\n", __FUNCTION__); - - // Wait for ~1 second because of hot plug spec - dbg("%s: before long_delay\n", __FUNCTION__); - long_delay(1*HZ); - dbg("%s: after long_delay\n", __FUNCTION__); - - dbg("%s: func status = %x\n", __FUNCTION__, func->status); - // Check for a power fault - if (func->status == 0xFF) { - // power fault occurred, but it was benign - temp_register = 0xFFFFFFFF; - dbg("%s: temp register set to %x by power fault\n", __FUNCTION__, temp_register); - rc = POWER_FAILURE; - func->status = 0; - } else { - // Get vendor/device ID u32 - ctrl->pci_bus->number = func->bus; - rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(func->device, func->function), PCI_VENDOR_ID, &temp_register); - dbg("%s: pci_read_config_dword returns %d\n", __FUNCTION__, rc); - dbg("%s: temp_register is %x\n", __FUNCTION__, temp_register); - - if (rc != 0) { - // Something's wrong here - temp_register = 0xFFFFFFFF; - dbg("%s: temp register set to %x by error\n", __FUNCTION__, temp_register); - } - // Preset return code. It will be changed later if things go okay. - rc = NO_ADAPTER_PRESENT; - } - - // All F's is an empty slot or an invalid board - if (temp_register != 0xFFFFFFFF) { // Check for a board in the slot - res_lists.io_head = ctrl->io_head; - res_lists.mem_head = ctrl->mem_head; - res_lists.p_mem_head = ctrl->p_mem_head; - res_lists.bus_head = ctrl->bus_head; - res_lists.irqs = NULL; - - rc = configure_new_device(ctrl, func, 0, &res_lists); - - dbg("%s: back from configure_new_device\n", __FUNCTION__); - ctrl->io_head = res_lists.io_head; - ctrl->mem_head = res_lists.mem_head; - ctrl->p_mem_head = res_lists.p_mem_head; - ctrl->bus_head = res_lists.bus_head; - - cpqhp_resource_sort_and_combine(&(ctrl->mem_head)); - cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head)); - cpqhp_resource_sort_and_combine(&(ctrl->io_head)); - cpqhp_resource_sort_and_combine(&(ctrl->bus_head)); - - if (rc) { - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); - - amber_LED_on (ctrl, hp_slot); - green_LED_off (ctrl, hp_slot); - slot_disable (ctrl, hp_slot); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - // Done with exclusive hardware access - up(&ctrl->crit_sect); - return(rc); - } else { - cpqhp_save_slot_config(ctrl, func); - } - - - func->status = 0; - func->switch_save = 0x10; - func->is_a_board = 0x01; - - //next, we will instantiate the linux pci_dev structures (with appropriate driver notification, if already present) - dbg("%s: configure linux pci_dev structure\n", __FUNCTION__); - index = 0; - do { - new_slot = cpqhp_slot_find(ctrl->bus, func->device, index++); - if (new_slot && !new_slot->pci_dev) { - cpqhp_configure_device(ctrl, new_slot); - } - } while (new_slot); - - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); - - green_LED_on (ctrl, hp_slot); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - // Done with exclusive hardware access - up(&ctrl->crit_sect); - } else { - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); - - amber_LED_on (ctrl, hp_slot); - green_LED_off (ctrl, hp_slot); - slot_disable (ctrl, hp_slot); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - // Done with exclusive hardware access - up(&ctrl->crit_sect); - - return(rc); - } - return 0; -} - - -/** - * remove_board - Turns off slot and LED's - * - */ -static u32 remove_board(struct pci_func * func, u32 replace_flag, struct controller * ctrl) -{ - int index; - u8 skip = 0; - u8 device; - u8 hp_slot; - u8 temp_byte; - u32 rc; - struct resource_lists res_lists; - struct pci_func *temp_func; - - if (func == NULL) - return(1); - - if (cpqhp_unconfigure_device(func)) - return(1); - - device = func->device; - - hp_slot = func->device - ctrl->slot_device_offset; - dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot); - - // When we get here, it is safe to change base Address Registers. - // We will attempt to save the base Address Register Lengths - if (replace_flag || !ctrl->add_support) - rc = cpqhp_save_base_addr_length(ctrl, func); - else if (!func->bus_head && !func->mem_head && - !func->p_mem_head && !func->io_head) { - // Here we check to see if we've saved any of the board's - // resources already. If so, we'll skip the attempt to - // determine what's being used. - index = 0; - temp_func = cpqhp_slot_find(func->bus, func->device, index++); - while (temp_func) { - if (temp_func->bus_head || temp_func->mem_head - || temp_func->p_mem_head || temp_func->io_head) { - skip = 1; - break; - } - temp_func = cpqhp_slot_find(temp_func->bus, temp_func->device, index++); - } - - if (!skip) - rc = cpqhp_save_used_resources(ctrl, func); - } - // Change status to shutdown - if (func->is_a_board) - func->status = 0x01; - func->configured = 0; - - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); - - green_LED_off (ctrl, hp_slot); - slot_disable (ctrl, hp_slot); - - set_SOGO(ctrl); - - // turn off SERR for slot - temp_byte = readb(ctrl->hpc_reg + SLOT_SERR); - temp_byte &= ~(0x01 << hp_slot); - writeb(temp_byte, ctrl->hpc_reg + SLOT_SERR); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - // Done with exclusive hardware access - up(&ctrl->crit_sect); - - if (!replace_flag && ctrl->add_support) { - while (func) { - res_lists.io_head = ctrl->io_head; - res_lists.mem_head = ctrl->mem_head; - res_lists.p_mem_head = ctrl->p_mem_head; - res_lists.bus_head = ctrl->bus_head; - - cpqhp_return_board_resources(func, &res_lists); - - ctrl->io_head = res_lists.io_head; - ctrl->mem_head = res_lists.mem_head; - ctrl->p_mem_head = res_lists.p_mem_head; - ctrl->bus_head = res_lists.bus_head; - - cpqhp_resource_sort_and_combine(&(ctrl->mem_head)); - cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head)); - cpqhp_resource_sort_and_combine(&(ctrl->io_head)); - cpqhp_resource_sort_and_combine(&(ctrl->bus_head)); - - if (is_bridge(func)) { - bridge_slot_remove(func); - } else - slot_remove(func); - - func = cpqhp_slot_find(ctrl->bus, device, 0); - } - - // Setup slot structure with entry for empty slot - func = cpqhp_slot_create(ctrl->bus); - - if (func == NULL) { - // Out of memory - return(1); - } - - func->bus = ctrl->bus; - func->device = device; - func->function = 0; - func->configured = 0; - func->switch_save = 0x10; - func->is_a_board = 0; - func->p_task_event = NULL; - } - - return 0; -} - - -static void pushbutton_helper_thread (unsigned long data) -{ - pushbutton_pending = data; - up(&event_semaphore); -} - - -// this is the main worker thread -static int event_thread(void* data) -{ - struct controller *ctrl; - lock_kernel(); - daemonize("phpd_event"); - - unlock_kernel(); - - while (1) { - dbg("!!!!event_thread sleeping\n"); - down_interruptible (&event_semaphore); - dbg("event_thread woken finished = %d\n", event_finished); - if (event_finished) break; - /* Do stuff here */ - if (pushbutton_pending) - cpqhp_pushbutton_thread(pushbutton_pending); - else - for (ctrl = cpqhp_ctrl_list; ctrl; ctrl=ctrl->next) - interrupt_event_handler(ctrl); - } - dbg("event_thread signals exit\n"); - up(&event_exit); - return 0; -} - - -int cpqhp_event_start_thread (void) -{ - int pid; - - /* initialize our semaphores */ - init_MUTEX(&delay_sem); - init_MUTEX_LOCKED(&event_semaphore); - init_MUTEX_LOCKED(&event_exit); - event_finished=0; - - pid = kernel_thread(event_thread, 0, 0); - if (pid < 0) { - err ("Can't start up our event thread\n"); - return -1; - } - dbg("Our event thread pid = %d\n", pid); - return 0; -} - - -void cpqhp_event_stop_thread (void) -{ - event_finished = 1; - dbg("event_thread finish command given\n"); - up(&event_semaphore); - dbg("wait for event_thread to exit\n"); - down(&event_exit); -} - - -static int update_slot_info (struct controller *ctrl, struct slot *slot) -{ - struct hotplug_slot_info *info; - int result; - - info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); - if (!info) - return -ENOMEM; - - info->power_status = get_slot_enabled(ctrl, slot); - info->attention_status = cpq_get_attention_status(ctrl, slot); - info->latch_status = cpq_get_latch_status(ctrl, slot); - info->adapter_status = get_presence_status(ctrl, slot); - result = pci_hp_change_slot_info(slot->hotplug_slot, info); - kfree (info); - return result; -} - -static void interrupt_event_handler(struct controller *ctrl) -{ - int loop = 0; - int change = 1; - struct pci_func *func; - u8 hp_slot; - struct slot *p_slot; - - while (change) { - change = 0; - - for (loop = 0; loop < 10; loop++) { - //dbg("loop %d\n", loop); - if (ctrl->event_queue[loop].event_type != 0) { - hp_slot = ctrl->event_queue[loop].hp_slot; - - func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0); - if (!func) - return; - - p_slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); - if (!p_slot) - return; - - dbg("hp_slot %d, func %p, p_slot %p\n", - hp_slot, func, p_slot); - - if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) { - dbg("button pressed\n"); - } else if (ctrl->event_queue[loop].event_type == - INT_BUTTON_CANCEL) { - dbg("button cancel\n"); - del_timer(&p_slot->task_event); - - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); - - if (p_slot->state == BLINKINGOFF_STATE) { - // slot is on - // turn on green LED - dbg("turn on green LED\n"); - green_LED_on (ctrl, hp_slot); - } else if (p_slot->state == BLINKINGON_STATE) { - // slot is off - // turn off green LED - dbg("turn off green LED\n"); - green_LED_off (ctrl, hp_slot); - } - - info(msg_button_cancel, p_slot->number); - - p_slot->state = STATIC_STATE; - - amber_LED_off (ctrl, hp_slot); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - // Done with exclusive hardware access - up(&ctrl->crit_sect); - } - // ***********button Released (No action on press...) - else if (ctrl->event_queue[loop].event_type == INT_BUTTON_RELEASE) { - dbg("button release\n"); - - if (is_slot_enabled (ctrl, hp_slot)) { - // slot is on - dbg("slot is on\n"); - p_slot->state = BLINKINGOFF_STATE; - info(msg_button_off, p_slot->number); - } else { - // slot is off - dbg("slot is off\n"); - p_slot->state = BLINKINGON_STATE; - info(msg_button_on, p_slot->number); - } - // Wait for exclusive access to hardware - down(&ctrl->crit_sect); - - dbg("blink green LED and turn off amber\n"); - - amber_LED_off (ctrl, hp_slot); - green_LED_blink (ctrl, hp_slot); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - - // Done with exclusive hardware access - up(&ctrl->crit_sect); - init_timer(&p_slot->task_event); - p_slot->hp_slot = hp_slot; - p_slot->ctrl = ctrl; -// p_slot->physical_slot = physical_slot; - p_slot->task_event.expires = jiffies + 5 * HZ; // 5 second delay - p_slot->task_event.function = pushbutton_helper_thread; - p_slot->task_event.data = (u32) p_slot; - - dbg("add_timer p_slot = %p\n", p_slot); - add_timer(&p_slot->task_event); - } - // ***********POWER FAULT - else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) { - dbg("power fault\n"); - } else { - /* refresh notification */ - if (p_slot) - update_slot_info(ctrl, p_slot); - } - - ctrl->event_queue[loop].event_type = 0; - - change = 1; - } - } // End of FOR loop - } - - return; -} - - -/** - * cpqhp_pushbutton_thread - * - * Scheduled procedure to handle blocking stuff for the pushbuttons - * Handles all pending events and exits. - * - */ -void cpqhp_pushbutton_thread (unsigned long slot) -{ - u8 hp_slot; - u8 device; - struct pci_func *func; - struct slot *p_slot = (struct slot *) slot; - struct controller *ctrl = (struct controller *) p_slot->ctrl; - - pushbutton_pending = 0; - hp_slot = p_slot->hp_slot; - - device = p_slot->device; - - if (is_slot_enabled (ctrl, hp_slot)) { - p_slot->state = POWEROFF_STATE; - // power Down board - func = cpqhp_slot_find(p_slot->bus, p_slot->device, 0); - dbg("In power_down_board, func = %p, ctrl = %p\n", func, ctrl); - if (!func) { - dbg("Error! func NULL in %s\n", __FUNCTION__); - return ; - } - - if (func != NULL && ctrl != NULL) { - if (cpqhp_process_SS(ctrl, func) != 0) { - amber_LED_on (ctrl, hp_slot); - green_LED_on (ctrl, hp_slot); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - } - } - - p_slot->state = STATIC_STATE; - } else { - p_slot->state = POWERON_STATE; - // slot is off - - func = cpqhp_slot_find(p_slot->bus, p_slot->device, 0); - dbg("In add_board, func = %p, ctrl = %p\n", func, ctrl); - if (!func) { - dbg("Error! func NULL in %s\n", __FUNCTION__); - return ; - } - - if (func != NULL && ctrl != NULL) { - if (cpqhp_process_SI(ctrl, func) != 0) { - amber_LED_on (ctrl, hp_slot); - green_LED_off (ctrl, hp_slot); - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - } - } - - p_slot->state = STATIC_STATE; - } - - return; -} - - -int cpqhp_process_SI (struct controller *ctrl, struct pci_func *func) -{ - u8 device, hp_slot; - u16 temp_word; - u32 tempdword; - int rc; - struct slot* p_slot; - int physical_slot = 0; - - if (!ctrl) - return(1); - - tempdword = 0; - - device = func->device; - hp_slot = device - ctrl->slot_device_offset; - p_slot = cpqhp_find_slot(ctrl, device); - if (p_slot) { - physical_slot = p_slot->number; - } - - // Check to see if the interlock is closed - tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); - - if (tempdword & (0x01 << hp_slot)) { - return(1); - } - - if (func->is_a_board) { - rc = board_replaced(func, ctrl); - } else { - // add board - slot_remove(func); - - func = cpqhp_slot_create(ctrl->bus); - if (func == NULL) { - return(1); - } - - func->bus = ctrl->bus; - func->device = device; - func->function = 0; - func->configured = 0; - func->is_a_board = 1; - - // We have to save the presence info for these slots - temp_word = ctrl->ctrl_int_comp >> 16; - func->presence_save = (temp_word >> hp_slot) & 0x01; - func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; - - if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) { - func->switch_save = 0; - } else { - func->switch_save = 0x10; - } - - rc = board_added(func, ctrl); - if (rc) { - if (is_bridge(func)) { - bridge_slot_remove(func); - } else - slot_remove(func); - - // Setup slot structure with entry for empty slot - func = cpqhp_slot_create(ctrl->bus); - - if (func == NULL) { - // Out of memory - return(1); - } - - func->bus = ctrl->bus; - func->device = device; - func->function = 0; - func->configured = 0; - func->is_a_board = 0; - - // We have to save the presence info for these slots - temp_word = ctrl->ctrl_int_comp >> 16; - func->presence_save = (temp_word >> hp_slot) & 0x01; - func->presence_save |= - (temp_word >> (hp_slot + 7)) & 0x02; - - if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) { - func->switch_save = 0; - } else { - func->switch_save = 0x10; - } - } - } - - if (rc) { - dbg("%s: rc = %d\n", __FUNCTION__, rc); - } - - if (p_slot) - update_slot_info(ctrl, p_slot); - - return rc; -} - - -int cpqhp_process_SS (struct controller *ctrl, struct pci_func *func) -{ - u8 device, class_code, header_type, BCR; - u8 index = 0; - u8 replace_flag; - u32 rc = 0; - unsigned int devfn; - struct slot* p_slot; - struct pci_bus *pci_bus = ctrl->pci_bus; - int physical_slot=0; - - device = func->device; - func = cpqhp_slot_find(ctrl->bus, device, index++); - p_slot = cpqhp_find_slot(ctrl, device); - if (p_slot) { - physical_slot = p_slot->number; - } - - // Make sure there are no video controllers here - while (func && !rc) { - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - // Check the Class Code - rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); - if (rc) - return rc; - - if (class_code == PCI_BASE_CLASS_DISPLAY) { - /* Display/Video adapter (not supported) */ - rc = REMOVE_NOT_SUPPORTED; - } else { - // See if it's a bridge - rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); - if (rc) - return rc; - - // If it's a bridge, check the VGA Enable bit - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { - rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_BRIDGE_CONTROL, &BCR); - if (rc) - return rc; - - // If the VGA Enable bit is set, remove isn't supported - if (BCR & PCI_BRIDGE_CTL_VGA) { - rc = REMOVE_NOT_SUPPORTED; - } - } - } - - func = cpqhp_slot_find(ctrl->bus, device, index++); - } - - func = cpqhp_slot_find(ctrl->bus, device, 0); - if ((func != NULL) && !rc) { - //FIXME: Replace flag should be passed into process_SS - replace_flag = !(ctrl->add_support); - rc = remove_board(func, replace_flag, ctrl); - } else if (!rc) { - rc = 1; - } - - if (p_slot) - update_slot_info(ctrl, p_slot); - - return(rc); -} - - - -/** - * hardware_test - runs hardware tests - * - * For hot plug ctrl folks to play with. - * test_num is the number entered in the GUI - * - */ -int cpqhp_hardware_test(struct controller *ctrl, int test_num) -{ - u32 save_LED; - u32 work_LED; - int loop; - int num_of_slots; - - num_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0f; - - switch (test_num) { - case 1: - // Do stuff here! - - // Do that funky LED thing - save_LED = readl(ctrl->hpc_reg + LED_CONTROL); // so we can restore them later - work_LED = 0x01010101; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - for (loop = 0; loop < num_of_slots; loop++) { - set_SOGO(ctrl); - - // Wait for SOGO interrupt - wait_for_ctrl_irq (ctrl); - - // Get ready for next iteration - work_LED = work_LED << 1; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - long_delay((2*HZ)/10); - } - for (loop = 0; loop < num_of_slots; loop++) { - work_LED = work_LED >> 1; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - - set_SOGO(ctrl); - - // Wait for SOGO interrupt - wait_for_ctrl_irq (ctrl); - - // Get ready for next iteration - long_delay((2*HZ)/10); - } - for (loop = 0; loop < num_of_slots; loop++) { - work_LED = work_LED << 1; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - - set_SOGO(ctrl); - - // Wait for SOGO interrupt - wait_for_ctrl_irq (ctrl); - - // Get ready for next iteration - long_delay((2*HZ)/10); - } - for (loop = 0; loop < num_of_slots; loop++) { - work_LED = work_LED >> 1; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - - set_SOGO(ctrl); - - // Wait for SOGO interrupt - wait_for_ctrl_irq (ctrl); - - // Get ready for next iteration - long_delay((2*HZ)/10); - } - - work_LED = 0x01010000; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - for (loop = 0; loop < num_of_slots; loop++) { - set_SOGO(ctrl); - - // Wait for SOGO interrupt - wait_for_ctrl_irq (ctrl); - - // Get ready for next iteration - work_LED = work_LED << 1; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - long_delay((2*HZ)/10); - } - for (loop = 0; loop < num_of_slots; loop++) { - work_LED = work_LED >> 1; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - - set_SOGO(ctrl); - - // Wait for SOGO interrupt - wait_for_ctrl_irq (ctrl); - - // Get ready for next iteration - long_delay((2*HZ)/10); - } - work_LED = 0x00000101; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - for (loop = 0; loop < num_of_slots; loop++) { - work_LED = work_LED << 1; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - - set_SOGO(ctrl); - - // Wait for SOGO interrupt - wait_for_ctrl_irq (ctrl); - - // Get ready for next iteration - long_delay((2*HZ)/10); - } - for (loop = 0; loop < num_of_slots; loop++) { - work_LED = work_LED >> 1; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - - set_SOGO(ctrl); - - // Wait for SOGO interrupt - wait_for_ctrl_irq (ctrl); - - // Get ready for next iteration - long_delay((2*HZ)/10); - } - - - work_LED = 0x01010000; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - for (loop = 0; loop < num_of_slots; loop++) { - set_SOGO(ctrl); - - // Wait for SOGO interrupt - wait_for_ctrl_irq (ctrl); - - // Get ready for next iteration - long_delay((3*HZ)/10); - work_LED = work_LED >> 16; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - - set_SOGO(ctrl); - - // Wait for SOGO interrupt - wait_for_ctrl_irq (ctrl); - - // Get ready for next iteration - long_delay((3*HZ)/10); - work_LED = work_LED << 16; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - work_LED = work_LED << 1; - writel(work_LED, ctrl->hpc_reg + LED_CONTROL); - } - - writel (save_LED, ctrl->hpc_reg + LED_CONTROL); // put it back the way it was - - set_SOGO(ctrl); - - // Wait for SOBS to be unset - wait_for_ctrl_irq (ctrl); - break; - case 2: - // Do other stuff here! - break; - case 3: - // and more... - break; - } - return 0; -} - - -/** - * configure_new_device - Configures the PCI header information of one board. - * - * @ctrl: pointer to controller structure - * @func: pointer to function structure - * @behind_bridge: 1 if this is a recursive call, 0 if not - * @resources: pointer to set of resource lists - * - * Returns 0 if success - * - */ -static u32 configure_new_device (struct controller * ctrl, struct pci_func * func, - u8 behind_bridge, struct resource_lists * resources) -{ - u8 temp_byte, function, max_functions, stop_it; - int rc; - u32 ID; - struct pci_func *new_slot; - int index; - - new_slot = func; - - dbg("%s\n", __FUNCTION__); - // Check for Multi-function device - ctrl->pci_bus->number = func->bus; - rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(func->device, func->function), 0x0E, &temp_byte); - if (rc) { - dbg("%s: rc = %d\n", __FUNCTION__, rc); - return rc; - } - - if (temp_byte & 0x80) // Multi-function device - max_functions = 8; - else - max_functions = 1; - - function = 0; - - do { - rc = configure_new_function(ctrl, new_slot, behind_bridge, resources); - - if (rc) { - dbg("configure_new_function failed %d\n",rc); - index = 0; - - while (new_slot) { - new_slot = cpqhp_slot_find(new_slot->bus, new_slot->device, index++); - - if (new_slot) - cpqhp_return_board_resources(new_slot, resources); - } - - return(rc); - } - - function++; - - stop_it = 0; - - // The following loop skips to the next present function - // and creates a board structure - - while ((function < max_functions) && (!stop_it)) { - pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(func->device, function), 0x00, &ID); - - if (ID == 0xFFFFFFFF) { // There's nothing there. - function++; - } else { // There's something there - // Setup slot structure. - new_slot = cpqhp_slot_create(func->bus); - - if (new_slot == NULL) { - // Out of memory - return(1); - } - - new_slot->bus = func->bus; - new_slot->device = func->device; - new_slot->function = function; - new_slot->is_a_board = 1; - new_slot->status = 0; - - stop_it++; - } - } - - } while (function < max_functions); - dbg("returning from configure_new_device\n"); - - return 0; -} - - -/* - Configuration logic that involves the hotplug data structures and - their bookkeeping - */ - - -/** - * configure_new_function - Configures the PCI header information of one device - * - * @ctrl: pointer to controller structure - * @func: pointer to function structure - * @behind_bridge: 1 if this is a recursive call, 0 if not - * @resources: pointer to set of resource lists - * - * Calls itself recursively for bridged devices. - * Returns 0 if success - * - */ -static int configure_new_function (struct controller * ctrl, struct pci_func * func, - u8 behind_bridge, struct resource_lists * resources) -{ - int cloop; - u8 IRQ; - u8 temp_byte; - u8 device; - u8 class_code; - u16 command; - u16 temp_word; - u32 temp_dword; - u32 rc; - u32 temp_register; - u32 base; - u32 ID; - unsigned int devfn; - struct pci_resource *mem_node; - struct pci_resource *p_mem_node; - struct pci_resource *io_node; - struct pci_resource *bus_node; - struct pci_resource *hold_mem_node; - struct pci_resource *hold_p_mem_node; - struct pci_resource *hold_IO_node; - struct pci_resource *hold_bus_node; - struct irq_mapping irqs; - struct pci_func *new_slot; - struct pci_bus *pci_bus; - struct resource_lists temp_resources; - - pci_bus = ctrl->pci_bus; - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - // Check for Bridge - rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &temp_byte); - if (rc) - return rc; - - if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge - // set Primary bus - dbg("set Primary bus = %d\n", func->bus); - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_PRIMARY_BUS, func->bus); - if (rc) - return rc; - - // find range of busses to use - dbg("find ranges of buses to use\n"); - bus_node = get_max_resource(&resources->bus_head, 1); - - // If we don't have any busses to allocate, we can't continue - if (!bus_node) - return -ENOMEM; - - // set Secondary bus - temp_byte = bus_node->base; - dbg("set Secondary bus = %d\n", bus_node->base); - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, temp_byte); - if (rc) - return rc; - - // set subordinate bus - temp_byte = bus_node->base + bus_node->length - 1; - dbg("set subordinate bus = %d\n", bus_node->base + bus_node->length - 1); - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte); - if (rc) - return rc; - - // set subordinate Latency Timer and base Latency Timer - temp_byte = 0x40; - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SEC_LATENCY_TIMER, temp_byte); - if (rc) - return rc; - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte); - if (rc) - return rc; - - // set Cache Line size - temp_byte = 0x08; - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte); - if (rc) - return rc; - - // Setup the IO, memory, and prefetchable windows - - io_node = get_max_resource(&(resources->io_head), 0x1000); - if (!io_node) - return -ENOMEM; - mem_node = get_max_resource(&(resources->mem_head), 0x100000); - if (!mem_node) - return -ENOMEM; - p_mem_node = get_max_resource(&(resources->p_mem_head), 0x100000); - if (!p_mem_node) - return -ENOMEM; - dbg("Setup the IO, memory, and prefetchable windows\n"); - dbg("io_node\n"); - dbg("(base, len, next) (%x, %x, %p)\n", io_node->base, io_node->length, io_node->next); - dbg("mem_node\n"); - dbg("(base, len, next) (%x, %x, %p)\n", mem_node->base, mem_node->length, mem_node->next); - dbg("p_mem_node\n"); - dbg("(base, len, next) (%x, %x, %p)\n", p_mem_node->base, p_mem_node->length, p_mem_node->next); - - // set up the IRQ info - if (!resources->irqs) { - irqs.barber_pole = 0; - irqs.interrupt[0] = 0; - irqs.interrupt[1] = 0; - irqs.interrupt[2] = 0; - irqs.interrupt[3] = 0; - irqs.valid_INT = 0; - } else { - irqs.barber_pole = resources->irqs->barber_pole; - irqs.interrupt[0] = resources->irqs->interrupt[0]; - irqs.interrupt[1] = resources->irqs->interrupt[1]; - irqs.interrupt[2] = resources->irqs->interrupt[2]; - irqs.interrupt[3] = resources->irqs->interrupt[3]; - irqs.valid_INT = resources->irqs->valid_INT; - } - - // set up resource lists that are now aligned on top and bottom - // for anything behind the bridge. - temp_resources.bus_head = bus_node; - temp_resources.io_head = io_node; - temp_resources.mem_head = mem_node; - temp_resources.p_mem_head = p_mem_node; - temp_resources.irqs = &irqs; - - // Make copies of the nodes we are going to pass down so that - // if there is a problem,we can just use these to free resources - hold_bus_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - hold_IO_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - hold_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - hold_p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - - if (!hold_bus_node || !hold_IO_node || !hold_mem_node || !hold_p_mem_node) { - if (hold_bus_node) - kfree(hold_bus_node); - if (hold_IO_node) - kfree(hold_IO_node); - if (hold_mem_node) - kfree(hold_mem_node); - if (hold_p_mem_node) - kfree(hold_p_mem_node); - - return(1); - } - - memcpy(hold_bus_node, bus_node, sizeof(struct pci_resource)); - - bus_node->base += 1; - bus_node->length -= 1; - bus_node->next = NULL; - - // If we have IO resources copy them and fill in the bridge's - // IO range registers - if (io_node) { - memcpy(hold_IO_node, io_node, sizeof(struct pci_resource)); - io_node->next = NULL; - - // set IO base and Limit registers - temp_byte = io_node->base >> 8; - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_BASE, temp_byte); - - temp_byte = (io_node->base + io_node->length - 1) >> 8; - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte); - } else { - kfree(hold_IO_node); - hold_IO_node = NULL; - } - - // If we have memory resources copy them and fill in the bridge's - // memory range registers. Otherwise, fill in the range - // registers with values that disable them. - if (mem_node) { - memcpy(hold_mem_node, mem_node, sizeof(struct pci_resource)); - mem_node->next = NULL; - - // set Mem base and Limit registers - temp_word = mem_node->base >> 16; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word); - - temp_word = (mem_node->base + mem_node->length - 1) >> 16; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); - } else { - temp_word = 0xFFFF; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word); - - temp_word = 0x0000; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); - - kfree(hold_mem_node); - hold_mem_node = NULL; - } - - // If we have prefetchable memory resources copy them and - // fill in the bridge's memory range registers. Otherwise, - // fill in the range registers with values that disable them. - if (p_mem_node) { - memcpy(hold_p_mem_node, p_mem_node, sizeof(struct pci_resource)); - p_mem_node->next = NULL; - - // set Pre Mem base and Limit registers - temp_word = p_mem_node->base >> 16; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word); - - temp_word = (p_mem_node->base + p_mem_node->length - 1) >> 16; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); - } else { - temp_word = 0xFFFF; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word); - - temp_word = 0x0000; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); - - kfree(hold_p_mem_node); - hold_p_mem_node = NULL; - } - - // Adjust this to compensate for extra adjustment in first loop - irqs.barber_pole--; - - rc = 0; - - // Here we actually find the devices and configure them - for (device = 0; (device <= 0x1F) && !rc; device++) { - irqs.barber_pole = (irqs.barber_pole + 1) & 0x03; - - ID = 0xFFFFFFFF; - pci_bus->number = hold_bus_node->base; - pci_bus_read_config_dword (pci_bus, PCI_DEVFN(device, 0), 0x00, &ID); - pci_bus->number = func->bus; - - if (ID != 0xFFFFFFFF) { // device Present - // Setup slot structure. - new_slot = cpqhp_slot_create(hold_bus_node->base); - - if (new_slot == NULL) { - // Out of memory - rc = -ENOMEM; - continue; - } - - new_slot->bus = hold_bus_node->base; - new_slot->device = device; - new_slot->function = 0; - new_slot->is_a_board = 1; - new_slot->status = 0; - - rc = configure_new_device(ctrl, new_slot, 1, &temp_resources); - dbg("configure_new_device rc=0x%x\n",rc); - } // End of IF (device in slot?) - } // End of FOR loop - - if (rc) { - cpqhp_destroy_resource_list(&temp_resources); - - return_resource(&(resources->bus_head), hold_bus_node); - return_resource(&(resources->io_head), hold_IO_node); - return_resource(&(resources->mem_head), hold_mem_node); - return_resource(&(resources->p_mem_head), hold_p_mem_node); - return(rc); - } - // save the interrupt routing information - if (resources->irqs) { - resources->irqs->interrupt[0] = irqs.interrupt[0]; - resources->irqs->interrupt[1] = irqs.interrupt[1]; - resources->irqs->interrupt[2] = irqs.interrupt[2]; - resources->irqs->interrupt[3] = irqs.interrupt[3]; - resources->irqs->valid_INT = irqs.valid_INT; - } else if (!behind_bridge) { - // We need to hook up the interrupts here - for (cloop = 0; cloop < 4; cloop++) { - if (irqs.valid_INT & (0x01 << cloop)) { - rc = cpqhp_set_irq(func->bus, func->device, - 0x0A + cloop, irqs.interrupt[cloop]); - if (rc) { - cpqhp_destroy_resource_list (&temp_resources); - - return_resource(&(resources-> bus_head), hold_bus_node); - return_resource(&(resources-> io_head), hold_IO_node); - return_resource(&(resources-> mem_head), hold_mem_node); - return_resource(&(resources-> p_mem_head), hold_p_mem_node); - return rc; - } - } - } // end of for loop - } - // Return unused bus resources - // First use the temporary node to store information for the board - if (hold_bus_node && bus_node && temp_resources.bus_head) { - hold_bus_node->length = bus_node->base - hold_bus_node->base; - - hold_bus_node->next = func->bus_head; - func->bus_head = hold_bus_node; - - temp_byte = temp_resources.bus_head->base - 1; - - // set subordinate bus - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte); - - if (temp_resources.bus_head->length == 0) { - kfree(temp_resources.bus_head); - temp_resources.bus_head = NULL; - } else { - return_resource(&(resources->bus_head), temp_resources.bus_head); - } - } - - // If we have IO space available and there is some left, - // return the unused portion - if (hold_IO_node && temp_resources.io_head) { - io_node = do_pre_bridge_resource_split(&(temp_resources.io_head), - &hold_IO_node, 0x1000); - - // Check if we were able to split something off - if (io_node) { - hold_IO_node->base = io_node->base + io_node->length; - - temp_byte = (hold_IO_node->base) >> 8; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_IO_BASE, temp_byte); - - return_resource(&(resources->io_head), io_node); - } - - io_node = do_bridge_resource_split(&(temp_resources.io_head), 0x1000); - - // Check if we were able to split something off - if (io_node) { - // First use the temporary node to store information for the board - hold_IO_node->length = io_node->base - hold_IO_node->base; - - // If we used any, add it to the board's list - if (hold_IO_node->length) { - hold_IO_node->next = func->io_head; - func->io_head = hold_IO_node; - - temp_byte = (io_node->base - 1) >> 8; - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte); - - return_resource(&(resources->io_head), io_node); - } else { - // it doesn't need any IO - temp_word = 0x0000; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_IO_LIMIT, temp_word); - - return_resource(&(resources->io_head), io_node); - kfree(hold_IO_node); - } - } else { - // it used most of the range - hold_IO_node->next = func->io_head; - func->io_head = hold_IO_node; - } - } else if (hold_IO_node) { - // it used the whole range - hold_IO_node->next = func->io_head; - func->io_head = hold_IO_node; - } - // If we have memory space available and there is some left, - // return the unused portion - if (hold_mem_node && temp_resources.mem_head) { - mem_node = do_pre_bridge_resource_split(&(temp_resources. mem_head), - &hold_mem_node, 0x100000); - - // Check if we were able to split something off - if (mem_node) { - hold_mem_node->base = mem_node->base + mem_node->length; - - temp_word = (hold_mem_node->base) >> 16; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word); - - return_resource(&(resources->mem_head), mem_node); - } - - mem_node = do_bridge_resource_split(&(temp_resources.mem_head), 0x100000); - - // Check if we were able to split something off - if (mem_node) { - // First use the temporary node to store information for the board - hold_mem_node->length = mem_node->base - hold_mem_node->base; - - if (hold_mem_node->length) { - hold_mem_node->next = func->mem_head; - func->mem_head = hold_mem_node; - - // configure end address - temp_word = (mem_node->base - 1) >> 16; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); - - // Return unused resources to the pool - return_resource(&(resources->mem_head), mem_node); - } else { - // it doesn't need any Mem - temp_word = 0x0000; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); - - return_resource(&(resources->mem_head), mem_node); - kfree(hold_mem_node); - } - } else { - // it used most of the range - hold_mem_node->next = func->mem_head; - func->mem_head = hold_mem_node; - } - } else if (hold_mem_node) { - // it used the whole range - hold_mem_node->next = func->mem_head; - func->mem_head = hold_mem_node; - } - // If we have prefetchable memory space available and there is some - // left at the end, return the unused portion - if (hold_p_mem_node && temp_resources.p_mem_head) { - p_mem_node = do_pre_bridge_resource_split(&(temp_resources.p_mem_head), - &hold_p_mem_node, 0x100000); - - // Check if we were able to split something off - if (p_mem_node) { - hold_p_mem_node->base = p_mem_node->base + p_mem_node->length; - - temp_word = (hold_p_mem_node->base) >> 16; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word); - - return_resource(&(resources->p_mem_head), p_mem_node); - } - - p_mem_node = do_bridge_resource_split(&(temp_resources.p_mem_head), 0x100000); - - // Check if we were able to split something off - if (p_mem_node) { - // First use the temporary node to store information for the board - hold_p_mem_node->length = p_mem_node->base - hold_p_mem_node->base; - - // If we used any, add it to the board's list - if (hold_p_mem_node->length) { - hold_p_mem_node->next = func->p_mem_head; - func->p_mem_head = hold_p_mem_node; - - temp_word = (p_mem_node->base - 1) >> 16; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); - - return_resource(&(resources->p_mem_head), p_mem_node); - } else { - // it doesn't need any PMem - temp_word = 0x0000; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); - - return_resource(&(resources->p_mem_head), p_mem_node); - kfree(hold_p_mem_node); - } - } else { - // it used the most of the range - hold_p_mem_node->next = func->p_mem_head; - func->p_mem_head = hold_p_mem_node; - } - } else if (hold_p_mem_node) { - // it used the whole range - hold_p_mem_node->next = func->p_mem_head; - func->p_mem_head = hold_p_mem_node; - } - // We should be configuring an IRQ and the bridge's base address - // registers if it needs them. Although we have never seen such - // a device - - // enable card - command = 0x0157; // = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | PCI_COMMAND_SERR - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_COMMAND, command); - - // set Bridge Control Register - command = 0x07; // = PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR | PCI_BRIDGE_CTL_NO_ISA - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_BRIDGE_CONTROL, command); - } else if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_NORMAL) { - // Standard device - rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); - - if (class_code == PCI_BASE_CLASS_DISPLAY) { - // Display (video) adapter (not supported) - return(DEVICE_TYPE_NOT_SUPPORTED); - } - // Figure out IO and memory needs - for (cloop = 0x10; cloop <= 0x24; cloop += 4) { - temp_register = 0xFFFFFFFF; - - dbg("CND: bus=%d, devfn=%d, offset=%d\n", pci_bus->number, devfn, cloop); - rc = pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); - - rc = pci_bus_read_config_dword (pci_bus, devfn, cloop, &temp_register); - dbg("CND: base = 0x%x\n", temp_register); - - if (temp_register) { // If this register is implemented - if ((temp_register & 0x03L) == 0x01) { - // Map IO - - // set base = amount of IO space - base = temp_register & 0xFFFFFFFC; - base = ~base + 1; - - dbg("CND: length = 0x%x\n", base); - io_node = get_io_resource(&(resources->io_head), base); - dbg("Got io_node start = %8.8x, length = %8.8x next (%p)\n", - io_node->base, io_node->length, io_node->next); - dbg("func (%p) io_head (%p)\n", func, func->io_head); - - // allocate the resource to the board - if (io_node) { - base = io_node->base; - - io_node->next = func->io_head; - func->io_head = io_node; - } else - return -ENOMEM; - } else if ((temp_register & 0x0BL) == 0x08) { - // Map prefetchable memory - base = temp_register & 0xFFFFFFF0; - base = ~base + 1; - - dbg("CND: length = 0x%x\n", base); - p_mem_node = get_resource(&(resources->p_mem_head), base); - - // allocate the resource to the board - if (p_mem_node) { - base = p_mem_node->base; - - p_mem_node->next = func->p_mem_head; - func->p_mem_head = p_mem_node; - } else - return -ENOMEM; - } else if ((temp_register & 0x0BL) == 0x00) { - // Map memory - base = temp_register & 0xFFFFFFF0; - base = ~base + 1; - - dbg("CND: length = 0x%x\n", base); - mem_node = get_resource(&(resources->mem_head), base); - - // allocate the resource to the board - if (mem_node) { - base = mem_node->base; - - mem_node->next = func->mem_head; - func->mem_head = mem_node; - } else - return -ENOMEM; - } else if ((temp_register & 0x0BL) == 0x04) { - // Map memory - base = temp_register & 0xFFFFFFF0; - base = ~base + 1; - - dbg("CND: length = 0x%x\n", base); - mem_node = get_resource(&(resources->mem_head), base); - - // allocate the resource to the board - if (mem_node) { - base = mem_node->base; - - mem_node->next = func->mem_head; - func->mem_head = mem_node; - } else - return -ENOMEM; - } else if ((temp_register & 0x0BL) == 0x06) { - // Those bits are reserved, we can't handle this - return(1); - } else { - // Requesting space below 1M - return(NOT_ENOUGH_RESOURCES); - } - - rc = pci_bus_write_config_dword (pci_bus, devfn, cloop, base); - - // Check for 64-bit base - if ((temp_register & 0x07L) == 0x04) { - cloop += 4; - - // Upper 32 bits of address always zero on today's systems - // FIXME this is probably not true on Alpha and ia64??? - base = 0; - rc = pci_bus_write_config_dword (pci_bus, devfn, cloop, base); - } - } - } // End of base register loop - - // Figure out which interrupt pin this function uses - rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_INTERRUPT_PIN, &temp_byte); - - // If this function needs an interrupt and we are behind a bridge - // and the pin is tied to something that's alread mapped, - // set this one the same - if (temp_byte && resources->irqs && - (resources->irqs->valid_INT & - (0x01 << ((temp_byte + resources->irqs->barber_pole - 1) & 0x03)))) { - // We have to share with something already set up - IRQ = resources->irqs->interrupt[(temp_byte + resources->irqs->barber_pole - 1) & 0x03]; - } else { - // Program IRQ based on card type - rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); - - if (class_code == PCI_BASE_CLASS_STORAGE) { - IRQ = cpqhp_disk_irq; - } else { - IRQ = cpqhp_nic_irq; - } - } - - // IRQ Line - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_INTERRUPT_LINE, IRQ); - - if (!behind_bridge) { - rc = cpqhp_set_irq(func->bus, func->device, temp_byte + 0x09, IRQ); - if (rc) - return(1); - } else { - //TBD - this code may also belong in the other clause of this If statement - resources->irqs->interrupt[(temp_byte + resources->irqs->barber_pole - 1) & 0x03] = IRQ; - resources->irqs->valid_INT |= 0x01 << (temp_byte + resources->irqs->barber_pole - 1) & 0x03; - } - - // Latency Timer - temp_byte = 0x40; - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte); - - // Cache Line size - temp_byte = 0x08; - rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte); - - // disable ROM base Address - temp_dword = 0x00L; - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_ROM_ADDRESS, temp_dword); - - // enable card - temp_word = 0x0157; // = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | PCI_COMMAND_SERR - rc = pci_bus_write_config_word (pci_bus, devfn, PCI_COMMAND, temp_word); - } // End of Not-A-Bridge else - else { - // It's some strange type of PCI adapter (Cardbus?) - return(DEVICE_TYPE_NOT_SUPPORTED); - } - - func->configured = 1; - - return 0; -} - diff -Nru a/drivers/hotplug/cpqphp_nvram.c b/drivers/hotplug/cpqphp_nvram.c --- a/drivers/hotplug/cpqphp_nvram.c Mon Jun 9 23:16:18 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,667 +0,0 @@ -/* - * Compaq Hot Plug Controller Driver - * - * Copyright (c) 1995,2001 Compaq Computer Corporation - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or - * NON INFRINGEMENT. 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. - * - * Send feedback to <greg@kroah.com> - * - */ - -#include <linux/config.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/proc_fs.h> -#include <linux/miscdevice.h> -#include <linux/slab.h> -#include <linux/workqueue.h> -#include <linux/pci.h> -#include <linux/init.h> -#include <asm/uaccess.h> -#include "cpqphp.h" -#include "cpqphp_nvram.h" - - -#define ROM_INT15_PHY_ADDR 0x0FF859 -#define READ_EV 0xD8A4 -#define WRITE_EV 0xD8A5 - -struct register_foo { - union { - unsigned long lword; /* eax */ - unsigned short word; /* ax */ - - struct { - unsigned char low; /* al */ - unsigned char high; /* ah */ - } byte; - } data; - - unsigned char opcode; /* see below */ - unsigned long length; /* if the reg. is a pointer, how much data */ -} __attribute__ ((packed)); - -struct all_reg { - struct register_foo eax_reg; - struct register_foo ebx_reg; - struct register_foo ecx_reg; - struct register_foo edx_reg; - struct register_foo edi_reg; - struct register_foo esi_reg; - struct register_foo eflags_reg; -} __attribute__ ((packed)); - - -struct ev_hrt_header { - u8 Version; - u8 num_of_ctrl; - u8 next; -}; - -struct ev_hrt_ctrl { - u8 bus; - u8 device; - u8 function; - u8 mem_avail; - u8 p_mem_avail; - u8 io_avail; - u8 bus_avail; - u8 next; -}; - - -static u8 evbuffer_init; -static u8 evbuffer_length; -static u8 evbuffer[1024]; - -static void *compaq_int15_entry_point; - -static spinlock_t int15_lock; /* lock for ordering int15_bios_call() */ - - -/* This is a series of function that deals with - setting & getting the hotplug resource table in some environment variable. -*/ - -/* - * We really shouldn't be doing this unless there is a _very_ good reason to!!! - * greg k-h - */ - - -static u32 add_byte( u32 **p_buffer, u8 value, u32 *used, u32 *avail) -{ - u8 **tByte; - - if ((*used + 1) > *avail) - return(1); - - *((u8*)*p_buffer) = value; - tByte = (u8**)p_buffer; - (*tByte)++; - *used+=1; - return(0); -} - - -static u32 add_dword( u32 **p_buffer, u32 value, u32 *used, u32 *avail) -{ - if ((*used + 4) > *avail) - return(1); - - **p_buffer = value; - (*p_buffer)++; - *used+=4; - return(0); -} - - -/* - * check_for_compaq_ROM - * - * this routine verifies that the ROM OEM string is 'COMPAQ' - * - * returns 0 for non-Compaq ROM, 1 for Compaq ROM - */ -static int check_for_compaq_ROM (void *rom_start) -{ - u8 temp1, temp2, temp3, temp4, temp5, temp6; - int result = 0; - - temp1 = readb(rom_start + 0xffea + 0); - temp2 = readb(rom_start + 0xffea + 1); - temp3 = readb(rom_start + 0xffea + 2); - temp4 = readb(rom_start + 0xffea + 3); - temp5 = readb(rom_start + 0xffea + 4); - temp6 = readb(rom_start + 0xffea + 5); - if ((temp1 == 'C') && - (temp2 == 'O') && - (temp3 == 'M') && - (temp4 == 'P') && - (temp5 == 'A') && - (temp6 == 'Q')) { - result = 1; - } - dbg ("%s - returned %d\n", __FUNCTION__, result); - return result; -} - - -static u32 access_EV (u16 operation, u8 *ev_name, u8 *buffer, u32 *buf_size) -{ - unsigned long flags; - int op = operation; - int ret_val; - - if (!compaq_int15_entry_point) - return -ENODEV; - - spin_lock_irqsave(&int15_lock, flags); - __asm__ ( - "xorl %%ebx,%%ebx\n" \ - "xorl %%edx,%%edx\n" \ - "pushf\n" \ - "push %%cs\n" \ - "cli\n" \ - "call *%6\n" - : "=c" (*buf_size), "=a" (ret_val) - : "a" (op), "c" (*buf_size), "S" (ev_name), - "D" (buffer), "m" (compaq_int15_entry_point) - : "%ebx", "%edx"); - spin_unlock_irqrestore(&int15_lock, flags); - - return((ret_val & 0xFF00) >> 8); -} - - -/* - * load_HRT - * - * Read the hot plug Resource Table from NVRAM - */ -static int load_HRT (void *rom_start) -{ - u32 available; - u32 temp_dword; - u8 temp_byte = 0xFF; - u32 rc; - - if (!check_for_compaq_ROM(rom_start)) { - return -ENODEV; - } - - available = 1024; - - // Now load the EV - temp_dword = available; - - rc = access_EV(READ_EV, "CQTHPS", evbuffer, &temp_dword); - - evbuffer_length = temp_dword; - - // We're maintaining the resource lists so write FF to invalidate old info - temp_dword = 1; - - rc = access_EV(WRITE_EV, "CQTHPS", &temp_byte, &temp_dword); - - return rc; -} - - -/* - * store_HRT - * - * Save the hot plug Resource Table in NVRAM - */ -static u32 store_HRT (void *rom_start) -{ - u32 *buffer; - u32 *pFill; - u32 usedbytes; - u32 available; - u32 temp_dword; - u32 rc; - u8 loop; - u8 numCtrl = 0; - struct controller *ctrl; - struct pci_resource *resNode; - struct ev_hrt_header *p_EV_header; - struct ev_hrt_ctrl *p_ev_ctrl; - - available = 1024; - - if (!check_for_compaq_ROM(rom_start)) { - return(1); - } - - buffer = (u32*) evbuffer; - - if (!buffer) - return(1); - - pFill = buffer; - usedbytes = 0; - - p_EV_header = (struct ev_hrt_header *) pFill; - - ctrl = cpqhp_ctrl_list; - - // The revision of this structure - rc = add_byte( &pFill, 1 + ctrl->push_flag, &usedbytes, &available); - if (rc) - return(rc); - - // The number of controllers - rc = add_byte( &pFill, 1, &usedbytes, &available); - if (rc) - return(rc); - - while (ctrl) { - p_ev_ctrl = (struct ev_hrt_ctrl *) pFill; - - numCtrl++; - - // The bus number - rc = add_byte( &pFill, ctrl->bus, &usedbytes, &available); - if (rc) - return(rc); - - // The device Number - rc = add_byte( &pFill, PCI_SLOT(ctrl->pci_dev->devfn), &usedbytes, &available); - if (rc) - return(rc); - - // The function Number - rc = add_byte( &pFill, PCI_FUNC(ctrl->pci_dev->devfn), &usedbytes, &available); - if (rc) - return(rc); - - // Skip the number of available entries - rc = add_dword( &pFill, 0, &usedbytes, &available); - if (rc) - return(rc); - - // Figure out memory Available - - resNode = ctrl->mem_head; - - loop = 0; - - while (resNode) { - loop ++; - - // base - rc = add_dword( &pFill, resNode->base, &usedbytes, &available); - if (rc) - return(rc); - - // length - rc = add_dword( &pFill, resNode->length, &usedbytes, &available); - if (rc) - return(rc); - - resNode = resNode->next; - } - - // Fill in the number of entries - p_ev_ctrl->mem_avail = loop; - - // Figure out prefetchable memory Available - - resNode = ctrl->p_mem_head; - - loop = 0; - - while (resNode) { - loop ++; - - // base - rc = add_dword( &pFill, resNode->base, &usedbytes, &available); - if (rc) - return(rc); - - // length - rc = add_dword( &pFill, resNode->length, &usedbytes, &available); - if (rc) - return(rc); - - resNode = resNode->next; - } - - // Fill in the number of entries - p_ev_ctrl->p_mem_avail = loop; - - // Figure out IO Available - - resNode = ctrl->io_head; - - loop = 0; - - while (resNode) { - loop ++; - - // base - rc = add_dword( &pFill, resNode->base, &usedbytes, &available); - if (rc) - return(rc); - - // length - rc = add_dword( &pFill, resNode->length, &usedbytes, &available); - if (rc) - return(rc); - - resNode = resNode->next; - } - - // Fill in the number of entries - p_ev_ctrl->io_avail = loop; - - // Figure out bus Available - - resNode = ctrl->bus_head; - - loop = 0; - - while (resNode) { - loop ++; - - // base - rc = add_dword( &pFill, resNode->base, &usedbytes, &available); - if (rc) - return(rc); - - // length - rc = add_dword( &pFill, resNode->length, &usedbytes, &available); - if (rc) - return(rc); - - resNode = resNode->next; - } - - // Fill in the number of entries - p_ev_ctrl->bus_avail = loop; - - ctrl = ctrl->next; - } - - p_EV_header->num_of_ctrl = numCtrl; - - // Now store the EV - - temp_dword = usedbytes; - - rc = access_EV(WRITE_EV, "CQTHPS", (u8*) buffer, &temp_dword); - - dbg("usedbytes = 0x%x, length = 0x%x\n", usedbytes, temp_dword); - - evbuffer_length = temp_dword; - - if (rc) { - err(msg_unable_to_save); - return(1); - } - - return(0); -} - - -void compaq_nvram_init (void *rom_start) -{ - if (rom_start) { - compaq_int15_entry_point = (rom_start + ROM_INT15_PHY_ADDR - ROM_PHY_ADDR); - } - dbg("int15 entry = %p\n", compaq_int15_entry_point); - - /* initialize our int15 lock */ - spin_lock_init(&int15_lock); -} - - -int compaq_nvram_load (void *rom_start, struct controller *ctrl) -{ - u8 bus, device, function; - u8 nummem, numpmem, numio, numbus; - u32 rc; - u8 *p_byte; - struct pci_resource *mem_node; - struct pci_resource *p_mem_node; - struct pci_resource *io_node; - struct pci_resource *bus_node; - struct ev_hrt_ctrl *p_ev_ctrl; - struct ev_hrt_header *p_EV_header; - - if (!evbuffer_init) { - // Read the resource list information in from NVRAM - if (load_HRT(rom_start)) - memset (evbuffer, 0, 1024); - - evbuffer_init = 1; - } - - // If we saved information in NVRAM, use it now - p_EV_header = (struct ev_hrt_header *) evbuffer; - - // The following code is for systems where version 1.0 of this - // driver has been loaded, but doesn't support the hardware. - // In that case, the driver would incorrectly store something - // in NVRAM. - if ((p_EV_header->Version == 2) || - ((p_EV_header->Version == 1) && !ctrl->push_flag)) { - p_byte = &(p_EV_header->next); - - p_ev_ctrl = (struct ev_hrt_ctrl *) &(p_EV_header->next); - - p_byte += 3; - - if (p_byte > ((u8*)p_EV_header + evbuffer_length)) - return 2; - - bus = p_ev_ctrl->bus; - device = p_ev_ctrl->device; - function = p_ev_ctrl->function; - - while ((bus != ctrl->bus) || - (device != PCI_SLOT(ctrl->pci_dev->devfn)) || - (function != PCI_FUNC(ctrl->pci_dev->devfn))) { - nummem = p_ev_ctrl->mem_avail; - numpmem = p_ev_ctrl->p_mem_avail; - numio = p_ev_ctrl->io_avail; - numbus = p_ev_ctrl->bus_avail; - - p_byte += 4; - - if (p_byte > ((u8*)p_EV_header + evbuffer_length)) - return 2; - - // Skip forward to the next entry - p_byte += (nummem + numpmem + numio + numbus) * 8; - - if (p_byte > ((u8*)p_EV_header + evbuffer_length)) - return 2; - - p_ev_ctrl = (struct ev_hrt_ctrl *) p_byte; - - p_byte += 3; - - if (p_byte > ((u8*)p_EV_header + evbuffer_length)) - return 2; - - bus = p_ev_ctrl->bus; - device = p_ev_ctrl->device; - function = p_ev_ctrl->function; - } - - nummem = p_ev_ctrl->mem_avail; - numpmem = p_ev_ctrl->p_mem_avail; - numio = p_ev_ctrl->io_avail; - numbus = p_ev_ctrl->bus_avail; - - p_byte += 4; - - if (p_byte > ((u8*)p_EV_header + evbuffer_length)) - return 2; - - while (nummem--) { - mem_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - - if (!mem_node) - break; - - mem_node->base = *(u32*)p_byte; - dbg("mem base = %8.8x\n",mem_node->base); - p_byte += 4; - - if (p_byte > ((u8*)p_EV_header + evbuffer_length)) { - kfree(mem_node); - return 2; - } - - mem_node->length = *(u32*)p_byte; - dbg("mem length = %8.8x\n",mem_node->length); - p_byte += 4; - - if (p_byte > ((u8*)p_EV_header + evbuffer_length)) { - kfree(mem_node); - return 2; - } - - mem_node->next = ctrl->mem_head; - ctrl->mem_head = mem_node; - } - - while (numpmem--) { - p_mem_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - - if (!p_mem_node) - break; - - p_mem_node->base = *(u32*)p_byte; - dbg("pre-mem base = %8.8x\n",p_mem_node->base); - p_byte += 4; - - if (p_byte > ((u8*)p_EV_header + evbuffer_length)) { - kfree(p_mem_node); - return 2; - } - - p_mem_node->length = *(u32*)p_byte; - dbg("pre-mem length = %8.8x\n",p_mem_node->length); - p_byte += 4; - - if (p_byte > ((u8*)p_EV_header + evbuffer_length)) { - kfree(p_mem_node); - return 2; - } - - p_mem_node->next = ctrl->p_mem_head; - ctrl->p_mem_head = p_mem_node; - } - - while (numio--) { - io_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - - if (!io_node) - break; - - io_node->base = *(u32*)p_byte; - dbg("io base = %8.8x\n",io_node->base); - p_byte += 4; - - if (p_byte > ((u8*)p_EV_header + evbuffer_length)) { - kfree(io_node); - return 2; - } - - io_node->length = *(u32*)p_byte; - dbg("io length = %8.8x\n",io_node->length); - p_byte += 4; - - if (p_byte > ((u8*)p_EV_header + evbuffer_length)) { - kfree(io_node); - return 2; - } - - io_node->next = ctrl->io_head; - ctrl->io_head = io_node; - } - - while (numbus--) { - bus_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - - if (!bus_node) - break; - - bus_node->base = *(u32*)p_byte; - p_byte += 4; - - if (p_byte > ((u8*)p_EV_header + evbuffer_length)) { - kfree(bus_node); - return 2; - } - - bus_node->length = *(u32*)p_byte; - p_byte += 4; - - if (p_byte > ((u8*)p_EV_header + evbuffer_length)) { - kfree(bus_node); - return 2; - } - - bus_node->next = ctrl->bus_head; - ctrl->bus_head = bus_node; - } - - // If all of the following fail, we don't have any resources for - // hot plug add - rc = 1; - rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head)); - rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head)); - rc &= cpqhp_resource_sort_and_combine(&(ctrl->io_head)); - rc &= cpqhp_resource_sort_and_combine(&(ctrl->bus_head)); - - if (rc) - return(rc); - } else { - if ((evbuffer[0] != 0) && (!ctrl->push_flag)) - return 1; - } - - return 0; -} - - -int compaq_nvram_store (void *rom_start) -{ - int rc = 1; - - if (rom_start == NULL) - return -ENODEV; - - if (evbuffer_init) { - rc = store_HRT(rom_start); - if (rc) { - err(msg_unable_to_save); - } - } - return rc; -} - diff -Nru a/drivers/hotplug/cpqphp_nvram.h b/drivers/hotplug/cpqphp_nvram.h --- a/drivers/hotplug/cpqphp_nvram.h Mon Jun 9 23:16:14 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,57 +0,0 @@ -/* - * Compaq Hot Plug Controller Driver - * - * Copyright (c) 1995,2001 Compaq Computer Corporation - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or - * NON INFRINGEMENT. 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. - * - * Send feedback to <greg@kroah.com> - * - */ - -#ifndef _CPQPHP_NVRAM_H -#define _CPQPHP_NVRAM_H - -#ifndef CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM - -static inline void compaq_nvram_init (void *rom_start) -{ - return; -} - -static inline int compaq_nvram_load (void *rom_start, struct controller *ctrl) -{ - return 0; -} - -static inline int compaq_nvram_store (void *rom_start) -{ - return 0; -} - -#else - -extern void compaq_nvram_init (void *rom_start); -extern int compaq_nvram_load (void *rom_start, struct controller *ctrl); -extern int compaq_nvram_store (void *rom_start); - -#endif - -#endif - diff -Nru a/drivers/hotplug/cpqphp_pci.c b/drivers/hotplug/cpqphp_pci.c --- a/drivers/hotplug/cpqphp_pci.c Mon Jun 9 23:16:18 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,1548 +0,0 @@ -/* - * Compaq Hot Plug Controller Driver - * - * Copyright (c) 1995,2001 Compaq Computer Corporation - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or - * NON INFRINGEMENT. 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. - * - * Send feedback to <greg@kroah.com> - * - */ - -#include <linux/config.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/slab.h> -#include <linux/workqueue.h> -#include <linux/proc_fs.h> -#include <linux/pci.h> -#include "cpqphp.h" -#include "cpqphp_nvram.h" -#include "../../arch/i386/pci/pci.h" /* horrible hack showing how processor dependent we are... */ - - -u8 cpqhp_nic_irq; -u8 cpqhp_disk_irq; - -static u16 unused_IRQ; - -/* - * detect_HRT_floating_pointer - * - * find the Hot Plug Resource Table in the specified region of memory. - * - */ -static void *detect_HRT_floating_pointer(void *begin, void *end) -{ - void *fp; - void *endp; - u8 temp1, temp2, temp3, temp4; - int status = 0; - - endp = (end - sizeof(struct hrt) + 1); - - for (fp = begin; fp <= endp; fp += 16) { - temp1 = readb(fp + SIG0); - temp2 = readb(fp + SIG1); - temp3 = readb(fp + SIG2); - temp4 = readb(fp + SIG3); - if (temp1 == '$' && - temp2 == 'H' && - temp3 == 'R' && - temp4 == 'T') { - status = 1; - break; - } - } - - if (!status) - fp = NULL; - - dbg("Discovered Hotplug Resource Table at %p\n", fp); - return fp; -} - - -int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func) -{ - unsigned char bus; - struct pci_bus *child; - int num; - - if (func->pci_dev == NULL) - func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function)); - - /* No pci device, we need to create it then */ - if (func->pci_dev == NULL) { - dbg("INFO: pci_dev still null\n"); - - num = pci_scan_slot(ctrl->pci_dev->bus, PCI_DEVFN(func->device, func->function)); - if (num) - pci_bus_add_devices(ctrl->pci_dev->bus); - - func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function)); - if (func->pci_dev == NULL) { - dbg("ERROR: pci_dev still null\n"); - return 0; - } - } - - if (func->pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { - pci_read_config_byte(func->pci_dev, PCI_SECONDARY_BUS, &bus); - child = (struct pci_bus*) pci_add_new_bus(func->pci_dev->bus, (func->pci_dev), bus); - pci_do_scan_bus(child); - } - - return 0; -} - - -int cpqhp_unconfigure_device(struct pci_func* func) -{ - int j; - - dbg("%s: bus/dev/func = %x/%x/%x\n", __FUNCTION__, func->bus, func->device, func->function); - - for (j=0; j<8 ; j++) { - struct pci_dev* temp = pci_find_slot(func->bus, (func->device << 3) | j); - if (temp) - pci_remove_bus_device(temp); - } - return 0; -} - -static int PCI_RefinedAccessConfig(struct pci_bus *bus, unsigned int devfn, u8 offset, u32 *value) -{ - u32 vendID = 0; - - if (pci_bus_read_config_dword (bus, devfn, PCI_VENDOR_ID, &vendID) == -1) - return -1; - if (vendID == 0xffffffff) - return -1; - return pci_bus_read_config_dword (bus, devfn, offset, value); -} - - -/* - * cpqhp_set_irq - * - * @bus_num: bus number of PCI device - * @dev_num: device number of PCI device - * @slot: pointer to u8 where slot number will be returned - */ -int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num) -{ - int rc; - u16 temp_word; - struct pci_dev fakedev; - struct pci_bus fakebus; - - fakedev.devfn = dev_num << 3; - fakedev.bus = &fakebus; - fakebus.number = bus_num; - dbg("%s: dev %d, bus %d, pin %d, num %d\n", - __FUNCTION__, dev_num, bus_num, int_pin, irq_num); - rc = pcibios_set_irq_routing(&fakedev, int_pin - 0x0a, irq_num); - dbg("%s: rc %d\n", __FUNCTION__, rc); - if (!rc) - return !rc; - - // set the Edge Level Control Register (ELCR) - temp_word = inb(0x4d0); - temp_word |= inb(0x4d1) << 8; - - temp_word |= 0x01 << irq_num; - - // This should only be for x86 as it sets the Edge Level Control Register - outb((u8) (temp_word & 0xFF), 0x4d0); - outb((u8) ((temp_word & 0xFF00) >> 8), 0x4d1); - - return 0; -} - - -/* - * WTF??? This function isn't in the code, yet a function calls it, but the - * compiler optimizes it away? strange. Here as a placeholder to keep the - * compiler happy. - */ -static int PCI_ScanBusNonBridge (u8 bus, u8 device) -{ - return 0; -} - -static int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 * dev_num) -{ - u8 tdevice; - u32 work; - u8 tbus; - - ctrl->pci_bus->number = bus_num; - - for (tdevice = 0; tdevice < 0x100; tdevice++) { - //Scan for access first - if (PCI_RefinedAccessConfig(ctrl->pci_bus, tdevice, 0x08, &work) == -1) - continue; - dbg("Looking for nonbridge bus_num %d dev_num %d\n", bus_num, tdevice); - //Yep we got one. Not a bridge ? - if ((work >> 8) != PCI_TO_PCI_BRIDGE_CLASS) { - *dev_num = tdevice; - dbg("found it !\n"); - return 0; - } - } - for (tdevice = 0; tdevice < 0x100; tdevice++) { - //Scan for access first - if (PCI_RefinedAccessConfig(ctrl->pci_bus, tdevice, 0x08, &work) == -1) - continue; - dbg("Looking for bridge bus_num %d dev_num %d\n", bus_num, tdevice); - //Yep we got one. bridge ? - if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) { - pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(tdevice, 0), PCI_SECONDARY_BUS, &tbus); - dbg("Recurse on bus_num %d tdevice %d\n", tbus, tdevice); - if (PCI_ScanBusNonBridge(tbus, tdevice) == 0) - return 0; - } - } - - return -1; -} - - -static int PCI_GetBusDevHelper(struct controller *ctrl, u8 *bus_num, u8 *dev_num, u8 slot, u8 nobridge) -{ - struct irq_routing_table *PCIIRQRoutingInfoLength; - long len; - long loop; - u32 work; - - u8 tbus, tdevice, tslot; - - PCIIRQRoutingInfoLength = pcibios_get_irq_routing_table(); - if (!PCIIRQRoutingInfoLength) - return -1; - - len = (PCIIRQRoutingInfoLength->size - - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); - // Make sure I got at least one entry - if (len == 0) { - if (PCIIRQRoutingInfoLength != NULL) - kfree(PCIIRQRoutingInfoLength ); - return -1; - } - - for (loop = 0; loop < len; ++loop) { - tbus = PCIIRQRoutingInfoLength->slots[loop].bus; - tdevice = PCIIRQRoutingInfoLength->slots[loop].devfn; - tslot = PCIIRQRoutingInfoLength->slots[loop].slot; - - if (tslot == slot) { - *bus_num = tbus; - *dev_num = tdevice; - ctrl->pci_bus->number = tbus; - pci_bus_read_config_dword (ctrl->pci_bus, *dev_num, PCI_VENDOR_ID, &work); - if (!nobridge || (work == 0xffffffff)) { - if (PCIIRQRoutingInfoLength != NULL) - kfree(PCIIRQRoutingInfoLength ); - return 0; - } - - dbg("bus_num %d devfn %d\n", *bus_num, *dev_num); - pci_bus_read_config_dword (ctrl->pci_bus, *dev_num, PCI_CLASS_REVISION, &work); - dbg("work >> 8 (%x) = BRIDGE (%x)\n", work >> 8, PCI_TO_PCI_BRIDGE_CLASS); - - if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) { - pci_bus_read_config_byte (ctrl->pci_bus, *dev_num, PCI_SECONDARY_BUS, &tbus); - dbg("Scan bus for Non Bridge: bus %d\n", tbus); - if (PCI_ScanBusForNonBridge(ctrl, tbus, dev_num) == 0) { - *bus_num = tbus; - if (PCIIRQRoutingInfoLength != NULL) - kfree(PCIIRQRoutingInfoLength ); - return 0; - } - } else { - if (PCIIRQRoutingInfoLength != NULL) - kfree(PCIIRQRoutingInfoLength ); - return 0; - } - - } - } - if (PCIIRQRoutingInfoLength != NULL) - kfree(PCIIRQRoutingInfoLength ); - return -1; -} - - -int cpqhp_get_bus_dev (struct controller *ctrl, u8 * bus_num, u8 * dev_num, u8 slot) -{ - return PCI_GetBusDevHelper(ctrl, bus_num, dev_num, slot, 0); //plain (bridges allowed) -} - - -/* More PCI configuration routines; this time centered around hotplug controller */ - - -/* - * cpqhp_save_config - * - * Reads configuration for all slots in a PCI bus and saves info. - * - * Note: For non-hot plug busses, the slot # saved is the device # - * - * returns 0 if success - */ -int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug) -{ - long rc; - u8 class_code; - u8 header_type; - u32 ID; - u8 secondary_bus; - struct pci_func *new_slot; - int sub_bus; - int FirstSupported; - int LastSupported; - int max_functions; - int function; - u8 DevError; - int device = 0; - int cloop = 0; - int stop_it; - int index; - - // Decide which slots are supported - - if (is_hot_plug) { - //********************************* - // is_hot_plug is the slot mask - //********************************* - FirstSupported = is_hot_plug >> 4; - LastSupported = FirstSupported + (is_hot_plug & 0x0F) - 1; - } else { - FirstSupported = 0; - LastSupported = 0x1F; - } - - // Save PCI configuration space for all devices in supported slots - ctrl->pci_bus->number = busnumber; - for (device = FirstSupported; device <= LastSupported; device++) { - ID = 0xFFFFFFFF; - rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID); - - if (ID != 0xFFFFFFFF) { // device in slot - rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, 0), 0x0B, &class_code); - if (rc) - return rc; - - rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_HEADER_TYPE, &header_type); - if (rc) - return rc; - - // If multi-function device, set max_functions to 8 - if (header_type & 0x80) - max_functions = 8; - else - max_functions = 1; - - function = 0; - - do { - DevError = 0; - - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // P-P Bridge - // Recurse the subordinate bus - // get the subordinate bus number - rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_SECONDARY_BUS, &secondary_bus); - if (rc) { - return rc; - } else { - sub_bus = (int) secondary_bus; - - // Save secondary bus cfg spc - // with this recursive call. - rc = cpqhp_save_config(ctrl, sub_bus, 0); - if (rc) - return rc; - ctrl->pci_bus->number = busnumber; - } - } - - index = 0; - new_slot = cpqhp_slot_find(busnumber, device, index++); - while (new_slot && - (new_slot->function != (u8) function)) - new_slot = cpqhp_slot_find(busnumber, device, index++); - - if (!new_slot) { - // Setup slot structure. - new_slot = cpqhp_slot_create(busnumber); - - if (new_slot == NULL) - return(1); - } - - new_slot->bus = (u8) busnumber; - new_slot->device = (u8) device; - new_slot->function = (u8) function; - new_slot->is_a_board = 1; - new_slot->switch_save = 0x10; - // In case of unsupported board - new_slot->status = DevError; - new_slot->pci_dev = pci_find_slot(new_slot->bus, (new_slot->device << 3) | new_slot->function); - - for (cloop = 0; cloop < 0x20; cloop++) { - rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop])); - if (rc) - return rc; - } - - function++; - - stop_it = 0; - - // this loop skips to the next present function - // reading in Class Code and Header type. - - while ((function < max_functions)&&(!stop_it)) { - rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_VENDOR_ID, &ID); - if (ID == 0xFFFFFFFF) { // nothing there. - function++; - } else { // Something there - rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), 0x0B, &class_code); - if (rc) - return rc; - - rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_HEADER_TYPE, &header_type); - if (rc) - return rc; - - stop_it++; - } - } - - } while (function < max_functions); - } // End of IF (device in slot?) - else if (is_hot_plug) { - // Setup slot structure with entry for empty slot - new_slot = cpqhp_slot_create(busnumber); - - if (new_slot == NULL) { - return(1); - } - - new_slot->bus = (u8) busnumber; - new_slot->device = (u8) device; - new_slot->function = 0; - new_slot->is_a_board = 0; - new_slot->presence_save = 0; - new_slot->switch_save = 0; - } - } // End of FOR loop - - return(0); -} - - -/* - * cpqhp_save_slot_config - * - * Saves configuration info for all PCI devices in a given slot - * including subordinate busses. - * - * returns 0 if success - */ -int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot) -{ - long rc; - u8 class_code; - u8 header_type; - u32 ID; - u8 secondary_bus; - int sub_bus; - int max_functions; - int function; - int cloop = 0; - int stop_it; - - ID = 0xFFFFFFFF; - - ctrl->pci_bus->number = new_slot->bus; - pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_VENDOR_ID, &ID); - - if (ID != 0xFFFFFFFF) { // device in slot - pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), 0x0B, &class_code); - pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_HEADER_TYPE, &header_type); - - if (header_type & 0x80) // Multi-function device - max_functions = 8; - else - max_functions = 1; - - function = 0; - - do { - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge - // Recurse the subordinate bus - pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_SECONDARY_BUS, &secondary_bus); - - sub_bus = (int) secondary_bus; - - // Save the config headers for the secondary bus. - rc = cpqhp_save_config(ctrl, sub_bus, 0); - if (rc) - return(rc); - ctrl->pci_bus->number = new_slot->bus; - - } // End of IF - - new_slot->status = 0; - - for (cloop = 0; cloop < 0x20; cloop++) { - pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop])); - } - - function++; - - stop_it = 0; - - // this loop skips to the next present function - // reading in the Class Code and the Header type. - - while ((function < max_functions) && (!stop_it)) { - pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_VENDOR_ID, &ID); - - if (ID == 0xFFFFFFFF) { // nothing there. - function++; - } else { // Something there - pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), 0x0B, &class_code); - - pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_HEADER_TYPE, &header_type); - - stop_it++; - } - } - - } while (function < max_functions); - } // End of IF (device in slot?) - else { - return(2); - } - - return(0); -} - - -/* - * cpqhp_save_base_addr_length - * - * Saves the length of all base address registers for the - * specified slot. this is for hot plug REPLACE - * - * returns 0 if success - */ -int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func * func) -{ - u8 cloop; - u8 header_type; - u8 secondary_bus; - u8 type; - int sub_bus; - u32 temp_register; - u32 base; - u32 rc; - struct pci_func *next; - int index = 0; - struct pci_bus *pci_bus = ctrl->pci_bus; - unsigned int devfn; - - func = cpqhp_slot_find(func->bus, func->device, index++); - - while (func != NULL) { - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - // Check for Bridge - pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); - - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { - // PCI-PCI Bridge - pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); - - sub_bus = (int) secondary_bus; - - next = cpqhp_slot_list[sub_bus]; - - while (next != NULL) { - rc = cpqhp_save_base_addr_length(ctrl, next); - - if (rc) - return(rc); - - next = next->next; - } - pci_bus->number = func->bus; - - //FIXME: this loop is duplicated in the non-bridge case. The two could be rolled together - // Figure out IO and memory base lengths - for (cloop = 0x10; cloop <= 0x14; cloop += 4) { - temp_register = 0xFFFFFFFF; - pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); - pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); - - if (base) { // If this register is implemented - if (base & 0x01L) { - // IO base - // set base = amount of IO space requested - base = base & 0xFFFFFFFE; - base = (~base) + 1; - - type = 1; - } else { - // memory base - base = base & 0xFFFFFFF0; - base = (~base) + 1; - - type = 0; - } - } else { - base = 0x0L; - type = 0; - } - - // Save information in slot structure - func->base_length[(cloop - 0x10) >> 2] = - base; - func->base_type[(cloop - 0x10) >> 2] = type; - - } // End of base register loop - - - } else if ((header_type & 0x7F) == 0x00) { // PCI-PCI Bridge - // Figure out IO and memory base lengths - for (cloop = 0x10; cloop <= 0x24; cloop += 4) { - temp_register = 0xFFFFFFFF; - pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); - pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); - - if (base) { // If this register is implemented - if (base & 0x01L) { - // IO base - // base = amount of IO space requested - base = base & 0xFFFFFFFE; - base = (~base) + 1; - - type = 1; - } else { - // memory base - // base = amount of memory space requested - base = base & 0xFFFFFFF0; - base = (~base) + 1; - - type = 0; - } - } else { - base = 0x0L; - type = 0; - } - - // Save information in slot structure - func->base_length[(cloop - 0x10) >> 2] = base; - func->base_type[(cloop - 0x10) >> 2] = type; - - } // End of base register loop - - } else { // Some other unknown header type - } - - // find the next device in this slot - func = cpqhp_slot_find(func->bus, func->device, index++); - } - - return(0); -} - - -/* - * cpqhp_save_used_resources - * - * Stores used resource information for existing boards. this is - * for boards that were in the system when this driver was loaded. - * this function is for hot plug ADD - * - * returns 0 if success - */ -int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) -{ - u8 cloop; - u8 header_type; - u8 secondary_bus; - u8 temp_byte; - u8 b_base; - u8 b_length; - u16 command; - u16 save_command; - u16 w_base; - u16 w_length; - u32 temp_register; - u32 save_base; - u32 base; - int index = 0; - struct pci_resource *mem_node; - struct pci_resource *p_mem_node; - struct pci_resource *io_node; - struct pci_resource *bus_node; - struct pci_bus *pci_bus = ctrl->pci_bus; - unsigned int devfn; - - func = cpqhp_slot_find(func->bus, func->device, index++); - - while ((func != NULL) && func->is_a_board) { - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - // Save the command register - pci_bus_read_config_word (pci_bus, devfn, PCI_COMMAND, &save_command); - - // disable card - command = 0x00; - pci_bus_write_config_word (pci_bus, devfn, PCI_COMMAND, command); - - // Check for Bridge - pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); - - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge - // Clear Bridge Control Register - command = 0x00; - pci_bus_write_config_word (pci_bus, devfn, PCI_BRIDGE_CONTROL, command); - pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); - pci_bus_read_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, &temp_byte); - - bus_node =(struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!bus_node) - return -ENOMEM; - - bus_node->base = secondary_bus; - bus_node->length = temp_byte - secondary_bus + 1; - - bus_node->next = func->bus_head; - func->bus_head = bus_node; - - // Save IO base and Limit registers - pci_bus_read_config_byte (pci_bus, devfn, PCI_IO_BASE, &b_base); - pci_bus_read_config_byte (pci_bus, devfn, PCI_IO_LIMIT, &b_length); - - if ((b_base <= b_length) && (save_command & 0x01)) { - io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!io_node) - return -ENOMEM; - - io_node->base = (b_base & 0xF0) << 8; - io_node->length = (b_length - b_base + 0x10) << 8; - - io_node->next = func->io_head; - func->io_head = io_node; - } - - // Save memory base and Limit registers - pci_bus_read_config_word (pci_bus, devfn, PCI_MEMORY_BASE, &w_base); - pci_bus_read_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, &w_length); - - if ((w_base <= w_length) && (save_command & 0x02)) { - mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!mem_node) - return -ENOMEM; - - mem_node->base = w_base << 16; - mem_node->length = (w_length - w_base + 0x10) << 16; - - mem_node->next = func->mem_head; - func->mem_head = mem_node; - } - - // Save prefetchable memory base and Limit registers - pci_bus_read_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, &w_base); - pci_bus_read_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &w_length); - - if ((w_base <= w_length) && (save_command & 0x02)) { - p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!p_mem_node) - return -ENOMEM; - - p_mem_node->base = w_base << 16; - p_mem_node->length = (w_length - w_base + 0x10) << 16; - - p_mem_node->next = func->p_mem_head; - func->p_mem_head = p_mem_node; - } - // Figure out IO and memory base lengths - for (cloop = 0x10; cloop <= 0x14; cloop += 4) { - pci_bus_read_config_dword (pci_bus, devfn, cloop, &save_base); - - temp_register = 0xFFFFFFFF; - pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); - pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); - - temp_register = base; - - if (base) { // If this register is implemented - if (((base & 0x03L) == 0x01) - && (save_command & 0x01)) { - // IO base - // set temp_register = amount of IO space requested - temp_register = base & 0xFFFFFFFE; - temp_register = (~temp_register) + 1; - - io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!io_node) - return -ENOMEM; - - io_node->base = - save_base & (~0x03L); - io_node->length = temp_register; - - io_node->next = func->io_head; - func->io_head = io_node; - } else - if (((base & 0x0BL) == 0x08) - && (save_command & 0x02)) { - // prefetchable memory base - temp_register = base & 0xFFFFFFF0; - temp_register = (~temp_register) + 1; - - p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!p_mem_node) - return -ENOMEM; - - p_mem_node->base = save_base & (~0x0FL); - p_mem_node->length = temp_register; - - p_mem_node->next = func->p_mem_head; - func->p_mem_head = p_mem_node; - } else - if (((base & 0x0BL) == 0x00) - && (save_command & 0x02)) { - // prefetchable memory base - temp_register = base & 0xFFFFFFF0; - temp_register = (~temp_register) + 1; - - mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!mem_node) - return -ENOMEM; - - mem_node->base = save_base & (~0x0FL); - mem_node->length = temp_register; - - mem_node->next = func->mem_head; - func->mem_head = mem_node; - } else - return(1); - } - } // End of base register loop - } else if ((header_type & 0x7F) == 0x00) { // Standard header - // Figure out IO and memory base lengths - for (cloop = 0x10; cloop <= 0x24; cloop += 4) { - pci_bus_read_config_dword (pci_bus, devfn, cloop, &save_base); - - temp_register = 0xFFFFFFFF; - pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); - pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); - - temp_register = base; - - if (base) { // If this register is implemented - if (((base & 0x03L) == 0x01) - && (save_command & 0x01)) { - // IO base - // set temp_register = amount of IO space requested - temp_register = base & 0xFFFFFFFE; - temp_register = (~temp_register) + 1; - - io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!io_node) - return -ENOMEM; - - io_node->base = save_base & (~0x01L); - io_node->length = temp_register; - - io_node->next = func->io_head; - func->io_head = io_node; - } else - if (((base & 0x0BL) == 0x08) - && (save_command & 0x02)) { - // prefetchable memory base - temp_register = base & 0xFFFFFFF0; - temp_register = (~temp_register) + 1; - - p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!p_mem_node) - return -ENOMEM; - - p_mem_node->base = save_base & (~0x0FL); - p_mem_node->length = temp_register; - - p_mem_node->next = func->p_mem_head; - func->p_mem_head = p_mem_node; - } else - if (((base & 0x0BL) == 0x00) - && (save_command & 0x02)) { - // prefetchable memory base - temp_register = base & 0xFFFFFFF0; - temp_register = (~temp_register) + 1; - - mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!mem_node) - return -ENOMEM; - - mem_node->base = save_base & (~0x0FL); - mem_node->length = temp_register; - - mem_node->next = func->mem_head; - func->mem_head = mem_node; - } else - return(1); - } - } // End of base register loop - } else { // Some other unknown header type - } - - // find the next device in this slot - func = cpqhp_slot_find(func->bus, func->device, index++); - } - - return(0); -} - - -/* - * cpqhp_configure_board - * - * Copies saved configuration information to one slot. - * this is called recursively for bridge devices. - * this is for hot plug REPLACE! - * - * returns 0 if success - */ -int cpqhp_configure_board(struct controller *ctrl, struct pci_func * func) -{ - int cloop; - u8 header_type; - u8 secondary_bus; - int sub_bus; - struct pci_func *next; - u32 temp; - u32 rc; - int index = 0; - struct pci_bus *pci_bus = ctrl->pci_bus; - unsigned int devfn; - - func = cpqhp_slot_find(func->bus, func->device, index++); - - while (func != NULL) { - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - // Start at the top of config space so that the control - // registers are programmed last - for (cloop = 0x3C; cloop > 0; cloop -= 4) { - pci_bus_write_config_dword (pci_bus, devfn, cloop, func->config_space[cloop >> 2]); - } - - pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); - - // If this is a bridge device, restore subordinate devices - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge - pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); - - sub_bus = (int) secondary_bus; - - next = cpqhp_slot_list[sub_bus]; - - while (next != NULL) { - rc = cpqhp_configure_board(ctrl, next); - - if (rc) - return rc; - - next = next->next; - } - } else { - - // Check all the base Address Registers to make sure - // they are the same. If not, the board is different. - - for (cloop = 16; cloop < 40; cloop += 4) { - pci_bus_read_config_dword (pci_bus, devfn, cloop, &temp); - - if (temp != func->config_space[cloop >> 2]) { - dbg("Config space compare failure!!! offset = %x\n", cloop); - dbg("bus = %x, device = %x, function = %x\n", func->bus, func->device, func->function); - dbg("temp = %x, config space = %x\n\n", temp, func->config_space[cloop >> 2]); - return 1; - } - } - } - - func->configured = 1; - - func = cpqhp_slot_find(func->bus, func->device, index++); - } - - return 0; -} - - -/* - * cpqhp_valid_replace - * - * this function checks to see if a board is the same as the - * one it is replacing. this check will detect if the device's - * vendor or device id's are the same - * - * returns 0 if the board is the same nonzero otherwise - */ -int cpqhp_valid_replace(struct controller *ctrl, struct pci_func * func) -{ - u8 cloop; - u8 header_type; - u8 secondary_bus; - u8 type; - u32 temp_register = 0; - u32 base; - u32 rc; - struct pci_func *next; - int index = 0; - struct pci_bus *pci_bus = ctrl->pci_bus; - unsigned int devfn; - - if (!func->is_a_board) - return(ADD_NOT_SUPPORTED); - - func = cpqhp_slot_find(func->bus, func->device, index++); - - while (func != NULL) { - pci_bus->number = func->bus; - devfn = PCI_DEVFN(func->device, func->function); - - pci_bus_read_config_dword (pci_bus, devfn, PCI_VENDOR_ID, &temp_register); - - // No adapter present - if (temp_register == 0xFFFFFFFF) - return(NO_ADAPTER_PRESENT); - - if (temp_register != func->config_space[0]) - return(ADAPTER_NOT_SAME); - - // Check for same revision number and class code - pci_bus_read_config_dword (pci_bus, devfn, PCI_CLASS_REVISION, &temp_register); - - // Adapter not the same - if (temp_register != func->config_space[0x08 >> 2]) - return(ADAPTER_NOT_SAME); - - // Check for Bridge - pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); - - if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge - // In order to continue checking, we must program the - // bus registers in the bridge to respond to accesses - // for it's subordinate bus(es) - - temp_register = func->config_space[0x18 >> 2]; - pci_bus_write_config_dword (pci_bus, devfn, PCI_PRIMARY_BUS, temp_register); - - secondary_bus = (temp_register >> 8) & 0xFF; - - next = cpqhp_slot_list[secondary_bus]; - - while (next != NULL) { - rc = cpqhp_valid_replace(ctrl, next); - - if (rc) - return(rc); - - next = next->next; - } - - } - // Check to see if it is a standard config header - else if ((header_type & 0x7F) == PCI_HEADER_TYPE_NORMAL) { - // Check subsystem vendor and ID - pci_bus_read_config_dword (pci_bus, devfn, PCI_SUBSYSTEM_VENDOR_ID, &temp_register); - - if (temp_register != func->config_space[0x2C >> 2]) { - // If it's a SMART-2 and the register isn't filled - // in, ignore the difference because - // they just have an old rev of the firmware - - if (!((func->config_space[0] == 0xAE100E11) - && (temp_register == 0x00L))) - return(ADAPTER_NOT_SAME); - } - // Figure out IO and memory base lengths - for (cloop = 0x10; cloop <= 0x24; cloop += 4) { - temp_register = 0xFFFFFFFF; - pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); - pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); - if (base) { // If this register is implemented - if (base & 0x01L) { - // IO base - // set base = amount of IO space requested - base = base & 0xFFFFFFFE; - base = (~base) + 1; - - type = 1; - } else { - // memory base - base = base & 0xFFFFFFF0; - base = (~base) + 1; - - type = 0; - } - } else { - base = 0x0L; - type = 0; - } - - // Check information in slot structure - if (func->base_length[(cloop - 0x10) >> 2] != base) - return(ADAPTER_NOT_SAME); - - if (func->base_type[(cloop - 0x10) >> 2] != type) - return(ADAPTER_NOT_SAME); - - } // End of base register loop - - } // End of (type 0 config space) else - else { - // this is not a type 0 or 1 config space header so - // we don't know how to do it - return(DEVICE_TYPE_NOT_SUPPORTED); - } - - // Get the next function - func = cpqhp_slot_find(func->bus, func->device, index++); - } - - - return(0); -} - - -/* - * cpqhp_find_available_resources - * - * Finds available memory, IO, and IRQ resources for programming - * devices which may be added to the system - * this function is for hot plug ADD! - * - * returns 0 if success - */ -int cpqhp_find_available_resources (struct controller *ctrl, void *rom_start) -{ - u8 temp; - u8 populated_slot; - u8 bridged_slot; - void *one_slot; - struct pci_func *func = NULL; - int i = 10, index; - u32 temp_dword, rc; - struct pci_resource *mem_node; - struct pci_resource *p_mem_node; - struct pci_resource *io_node; - struct pci_resource *bus_node; - void *rom_resource_table; - - rom_resource_table = detect_HRT_floating_pointer(rom_start, rom_start+0xffff); - dbg("rom_resource_table = %p\n", rom_resource_table); - - if (rom_resource_table == NULL) { - return -ENODEV; - } - // Sum all resources and setup resource maps - unused_IRQ = readl(rom_resource_table + UNUSED_IRQ); - dbg("unused_IRQ = %x\n", unused_IRQ); - - temp = 0; - while (unused_IRQ) { - if (unused_IRQ & 1) { - cpqhp_disk_irq = temp; - break; - } - unused_IRQ = unused_IRQ >> 1; - temp++; - } - - dbg("cpqhp_disk_irq= %d\n", cpqhp_disk_irq); - unused_IRQ = unused_IRQ >> 1; - temp++; - - while (unused_IRQ) { - if (unused_IRQ & 1) { - cpqhp_nic_irq = temp; - break; - } - unused_IRQ = unused_IRQ >> 1; - temp++; - } - - dbg("cpqhp_nic_irq= %d\n", cpqhp_nic_irq); - unused_IRQ = readl(rom_resource_table + PCIIRQ); - - temp = 0; - - if (!cpqhp_nic_irq) { - cpqhp_nic_irq = ctrl->cfgspc_irq; - } - - if (!cpqhp_disk_irq) { - cpqhp_disk_irq = ctrl->cfgspc_irq; - } - - dbg("cpqhp_disk_irq, cpqhp_nic_irq= %d, %d\n", cpqhp_disk_irq, cpqhp_nic_irq); - - rc = compaq_nvram_load(rom_start, ctrl); - if (rc) - return rc; - - one_slot = rom_resource_table + sizeof (struct hrt); - - i = readb(rom_resource_table + NUMBER_OF_ENTRIES); - dbg("number_of_entries = %d\n", i); - - if (!readb(one_slot + SECONDARY_BUS)) { - return(1); - } - - dbg("dev|IO base|length|Mem base|length|Pre base|length|PB SB MB\n"); - - while (i && readb(one_slot + SECONDARY_BUS)) { - u8 dev_func = readb(one_slot + DEV_FUNC); - u8 primary_bus = readb(one_slot + PRIMARY_BUS); - u8 secondary_bus = readb(one_slot + SECONDARY_BUS); - u8 max_bus = readb(one_slot + MAX_BUS); - u16 io_base = readw(one_slot + IO_BASE); - u16 io_length = readw(one_slot + IO_LENGTH); - u16 mem_base = readw(one_slot + MEM_BASE); - u16 mem_length = readw(one_slot + MEM_LENGTH); - u16 pre_mem_base = readw(one_slot + PRE_MEM_BASE); - u16 pre_mem_length = readw(one_slot + PRE_MEM_LENGTH); - - dbg("%2.2x | %4.4x | %4.4x | %4.4x | %4.4x | %4.4x | %4.4x |%2.2x %2.2x %2.2x\n", - dev_func, io_base, io_length, mem_base, mem_length, pre_mem_base, pre_mem_length, - primary_bus, secondary_bus, max_bus); - - // If this entry isn't for our controller's bus, ignore it - if (primary_bus != ctrl->bus) { - i--; - one_slot += sizeof (struct slot_rt); - continue; - } - // find out if this entry is for an occupied slot - ctrl->pci_bus->number = primary_bus; - pci_bus_read_config_dword (ctrl->pci_bus, dev_func, PCI_VENDOR_ID, &temp_dword); - dbg("temp_D_word = %x\n", temp_dword); - - if (temp_dword != 0xFFFFFFFF) { - index = 0; - func = cpqhp_slot_find(primary_bus, dev_func >> 3, 0); - - while (func && (func->function != (dev_func & 0x07))) { - dbg("func = %p (bus, dev, fun) = (%d, %d, %d)\n", func, primary_bus, dev_func >> 3, index); - func = cpqhp_slot_find(primary_bus, dev_func >> 3, index++); - } - - // If we can't find a match, skip this table entry - if (!func) { - i--; - one_slot += sizeof (struct slot_rt); - continue; - } - // this may not work and shouldn't be used - if (secondary_bus != primary_bus) - bridged_slot = 1; - else - bridged_slot = 0; - - populated_slot = 1; - } else { - populated_slot = 0; - bridged_slot = 0; - } - - - // If we've got a valid IO base, use it - - temp_dword = io_base + io_length; - - if ((io_base) && (temp_dword < 0x10000)) { - io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!io_node) - return -ENOMEM; - - io_node->base = io_base; - io_node->length = io_length; - - dbg("found io_node(base, length) = %x, %x\n", io_node->base, io_node->length); - dbg("populated slot =%d \n", populated_slot); - if (!populated_slot) { - io_node->next = ctrl->io_head; - ctrl->io_head = io_node; - } else { - io_node->next = func->io_head; - func->io_head = io_node; - } - } - - // If we've got a valid memory base, use it - temp_dword = mem_base + mem_length; - if ((mem_base) && (temp_dword < 0x10000)) { - mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!mem_node) - return -ENOMEM; - - mem_node->base = mem_base << 16; - - mem_node->length = mem_length << 16; - - dbg("found mem_node(base, length) = %x, %x\n", mem_node->base, mem_node->length); - dbg("populated slot =%d \n", populated_slot); - if (!populated_slot) { - mem_node->next = ctrl->mem_head; - ctrl->mem_head = mem_node; - } else { - mem_node->next = func->mem_head; - func->mem_head = mem_node; - } - } - - // If we've got a valid prefetchable memory base, and - // the base + length isn't greater than 0xFFFF - temp_dword = pre_mem_base + pre_mem_length; - if ((pre_mem_base) && (temp_dword < 0x10000)) { - p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!p_mem_node) - return -ENOMEM; - - p_mem_node->base = pre_mem_base << 16; - - p_mem_node->length = pre_mem_length << 16; - dbg("found p_mem_node(base, length) = %x, %x\n", p_mem_node->base, p_mem_node->length); - dbg("populated slot =%d \n", populated_slot); - - if (!populated_slot) { - p_mem_node->next = ctrl->p_mem_head; - ctrl->p_mem_head = p_mem_node; - } else { - p_mem_node->next = func->p_mem_head; - func->p_mem_head = p_mem_node; - } - } - - // If we've got a valid bus number, use it - // The second condition is to ignore bus numbers on - // populated slots that don't have PCI-PCI bridges - if (secondary_bus && (secondary_bus != primary_bus)) { - bus_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); - if (!bus_node) - return -ENOMEM; - - bus_node->base = secondary_bus; - bus_node->length = max_bus - secondary_bus + 1; - dbg("found bus_node(base, length) = %x, %x\n", bus_node->base, bus_node->length); - dbg("populated slot =%d \n", populated_slot); - if (!populated_slot) { - bus_node->next = ctrl->bus_head; - ctrl->bus_head = bus_node; - } else { - bus_node->next = func->bus_head; - func->bus_head = bus_node; - } - } - - i--; - one_slot += sizeof (struct slot_rt); - } - - // If all of the following fail, we don't have any resources for - // hot plug add - rc = 1; - rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head)); - rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head)); - rc &= cpqhp_resource_sort_and_combine(&(ctrl->io_head)); - rc &= cpqhp_resource_sort_and_combine(&(ctrl->bus_head)); - - return(rc); -} - - -/* - * cpqhp_return_board_resources - * - * this routine returns all resources allocated to a board to - * the available pool. - * - * returns 0 if success - */ -int cpqhp_return_board_resources(struct pci_func * func, struct resource_lists * resources) -{ - int rc = 0; - struct pci_resource *node; - struct pci_resource *t_node; - dbg("%s\n", __FUNCTION__); - - if (!func) - return(1); - - node = func->io_head; - func->io_head = NULL; - while (node) { - t_node = node->next; - return_resource(&(resources->io_head), node); - node = t_node; - } - - node = func->mem_head; - func->mem_head = NULL; - while (node) { - t_node = node->next; - return_resource(&(resources->mem_head), node); - node = t_node; - } - - node = func->p_mem_head; - func->p_mem_head = NULL; - while (node) { - t_node = node->next; - return_resource(&(resources->p_mem_head), node); - node = t_node; - } - - node = func->bus_head; - func->bus_head = NULL; - while (node) { - t_node = node->next; - return_resource(&(resources->bus_head), node); - node = t_node; - } - - rc |= cpqhp_resource_sort_and_combine(&(resources->mem_head)); - rc |= cpqhp_resource_sort_and_combine(&(resources->p_mem_head)); - rc |= cpqhp_resource_sort_and_combine(&(resources->io_head)); - rc |= cpqhp_resource_sort_and_combine(&(resources->bus_head)); - - return(rc); -} - - -/* - * cpqhp_destroy_resource_list - * - * Puts node back in the resource list pointed to by head - */ -void cpqhp_destroy_resource_list (struct resource_lists * resources) -{ - struct pci_resource *res, *tres; - - res = resources->io_head; - resources->io_head = NULL; - - while (res) { - tres = res; - res = res->next; - kfree(tres); - } - - res = resources->mem_head; - resources->mem_head = NULL; - - while (res) { - tres = res; - res = res->next; - kfree(tres); - } - - res = resources->p_mem_head; - resources->p_mem_head = NULL; - - while (res) { - tres = res; - res = res->next; - kfree(tres); - } - - res = resources->bus_head; - resources->bus_head = NULL; - - while (res) { - tres = res; - res = res->next; - kfree(tres); - } -} - - -/* - * cpqhp_destroy_board_resources - * - * Puts node back in the resource list pointed to by head - */ -void cpqhp_destroy_board_resources (struct pci_func * func) -{ - struct pci_resource *res, *tres; - - res = func->io_head; - func->io_head = NULL; - - while (res) { - tres = res; - res = res->next; - kfree(tres); - } - - res = func->mem_head; - func->mem_head = NULL; - - while (res) { - tres = res; - res = res->next; - kfree(tres); - } - - res = func->p_mem_head; - func->p_mem_head = NULL; - - while (res) { - tres = res; - res = res->next; - kfree(tres); - } - - res = func->bus_head; - func->bus_head = NULL; - - while (res) { - tres = res; - res = res->next; - kfree(tres); - } -} - diff -Nru a/drivers/hotplug/cpqphp_sysfs.c b/drivers/hotplug/cpqphp_sysfs.c --- a/drivers/hotplug/cpqphp_sysfs.c Mon Jun 9 23:16:19 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,143 +0,0 @@ -/* - * Compaq Hot Plug Controller Driver - * - * Copyright (c) 1995,2001 Compaq Computer Corporation - * Copyright (c) 2001,2003 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or - * NON INFRINGEMENT. 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. - * - * Send feedback to <greg@kroah.com> - * - */ - -#include <linux/config.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/proc_fs.h> -#include <linux/workqueue.h> -#include <linux/pci.h> -#include "cpqphp.h" - - -/* A few routines that create sysfs entries for the hot plug controller */ - -static int show_ctrl (struct device *dev, char *buf) -{ - struct pci_dev *pci_dev; - struct controller *ctrl; - char * out = buf; - int index; - struct pci_resource *res; - - pci_dev = container_of (dev, struct pci_dev, dev); - ctrl = pci_get_drvdata(pci_dev); - - out += sprintf(buf, "Free resources: memory\n"); - index = 11; - res = ctrl->mem_head; - while (res && index--) { - out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); - res = res->next; - } - out += sprintf(out, "Free resources: prefetchable memory\n"); - index = 11; - res = ctrl->p_mem_head; - while (res && index--) { - out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); - res = res->next; - } - out += sprintf(out, "Free resources: IO\n"); - index = 11; - res = ctrl->io_head; - while (res && index--) { - out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); - res = res->next; - } - out += sprintf(out, "Free resources: bus numbers\n"); - index = 11; - res = ctrl->bus_head; - while (res && index--) { - out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); - res = res->next; - } - - return out - buf; -} -static DEVICE_ATTR (ctrl, S_IRUGO, show_ctrl, NULL); - -static int show_dev (struct device *dev, char *buf) -{ - struct pci_dev *pci_dev; - struct controller *ctrl; - char * out = buf; - int index; - struct pci_resource *res; - struct pci_func *new_slot; - struct slot *slot; - - pci_dev = container_of (dev, struct pci_dev, dev); - ctrl = pci_get_drvdata(pci_dev); - - slot=ctrl->slot; - - while (slot) { - new_slot = cpqhp_slot_find(slot->bus, slot->device, 0); - if (!new_slot) - break; - out += sprintf(out, "assigned resources: memory\n"); - index = 11; - res = new_slot->mem_head; - while (res && index--) { - out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); - res = res->next; - } - out += sprintf(out, "assigned resources: prefetchable memory\n"); - index = 11; - res = new_slot->p_mem_head; - while (res && index--) { - out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); - res = res->next; - } - out += sprintf(out, "assigned resources: IO\n"); - index = 11; - res = new_slot->io_head; - while (res && index--) { - out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); - res = res->next; - } - out += sprintf(out, "assigned resources: bus numbers\n"); - index = 11; - res = new_slot->bus_head; - while (res && index--) { - out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); - res = res->next; - } - slot=slot->next; - } - - return out - buf; -} -static DEVICE_ATTR (dev, S_IRUGO, show_dev, NULL); - -void cpqhp_create_ctrl_files (struct controller *ctrl) -{ - device_create_file (&ctrl->pci_dev->dev, &dev_attr_ctrl); - device_create_file (&ctrl->pci_dev->dev, &dev_attr_dev); -} diff -Nru a/drivers/hotplug/ibmphp.h b/drivers/hotplug/ibmphp.h --- a/drivers/hotplug/ibmphp.h Mon Jun 9 23:16:07 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,772 +0,0 @@ -#ifndef __IBMPHP_H -#define __IBMPHP_H - -/* - * IBM Hot Plug Controller Driver - * - * Written By: Jyoti Shah, Tong Yu, Irene Zubarev, IBM Corporation - * - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001,2002 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or - * NON INFRINGEMENT. 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. - * - * Send feedback to <gregkh@us.ibm.com> - * - */ - -#include "pci_hotplug.h" - -extern int ibmphp_debug; - -#if !defined(CONFIG_HOTPLUG_PCI_IBM_MODULE) - #define MY_NAME "ibmphpd" -#else - #define MY_NAME THIS_MODULE->name -#endif -#define debug(fmt, arg...) do { if (ibmphp_debug == 1) printk(KERN_DEBUG "%s: " fmt , MY_NAME , ## arg); } while (0) -#define debug_pci(fmt, arg...) do { if (ibmphp_debug) printk(KERN_DEBUG "%s: " fmt , MY_NAME , ## arg); } while (0) -#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg) -#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg) -#define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg) - - -/* EBDA stuff */ - -/*********************************************************** -* SLOT CAPABILITY * -***********************************************************/ - -#define EBDA_SLOT_133_MAX 0x20 -#define EBDA_SLOT_100_MAX 0x10 -#define EBDA_SLOT_66_MAX 0x02 -#define EBDA_SLOT_PCIX_CAP 0x08 - - -/************************************************************ -* RESOURE TYPE * -************************************************************/ - -#define EBDA_RSRC_TYPE_MASK 0x03 -#define EBDA_IO_RSRC_TYPE 0x00 -#define EBDA_MEM_RSRC_TYPE 0x01 -#define EBDA_PFM_RSRC_TYPE 0x03 -#define EBDA_RES_RSRC_TYPE 0x02 - - -/************************************************************* -* IO RESTRICTION TYPE * -*************************************************************/ - -#define EBDA_IO_RESTRI_MASK 0x0c -#define EBDA_NO_RESTRI 0x00 -#define EBDA_AVO_VGA_ADDR 0x04 -#define EBDA_AVO_VGA_ADDR_AND_ALIA 0x08 -#define EBDA_AVO_ISA_ADDR 0x0c - - -/************************************************************** -* DEVICE TYPE DEF * -**************************************************************/ - -#define EBDA_DEV_TYPE_MASK 0x10 -#define EBDA_PCI_DEV 0x10 -#define EBDA_NON_PCI_DEV 0x00 - - -/*************************************************************** -* PRIMARY DEF DEFINITION * -***************************************************************/ - -#define EBDA_PRI_DEF_MASK 0x20 -#define EBDA_PRI_PCI_BUS_INFO 0x20 -#define EBDA_NORM_DEV_RSRC_INFO 0x00 - - -//-------------------------------------------------------------- -// RIO TABLE DATA STRUCTURE -//-------------------------------------------------------------- - -struct rio_table_hdr { - u8 ver_num; - u8 scal_count; - u8 riodev_count; - u16 offset; -}; - -//------------------------------------------------------------- -// SCALABILITY DETAIL -//------------------------------------------------------------- - -struct scal_detail { - u8 node_id; - u32 cbar; - u8 port0_node_connect; - u8 port0_port_connect; - u8 port1_node_connect; - u8 port1_port_connect; - u8 port2_node_connect; - u8 port2_port_connect; - u8 chassis_num; -// struct list_head scal_detail_list; -}; - -//-------------------------------------------------------------- -// RIO DETAIL -//-------------------------------------------------------------- - -struct rio_detail { - u8 rio_node_id; - u32 bbar; - u8 rio_type; - u8 owner_id; - u8 port0_node_connect; - u8 port0_port_connect; - u8 port1_node_connect; - u8 port1_port_connect; - u8 first_slot_num; - u8 status; - u8 wpindex; - u8 chassis_num; - struct list_head rio_detail_list; -}; - -struct opt_rio { - u8 rio_type; - u8 chassis_num; - u8 first_slot_num; - u8 middle_num; - struct list_head opt_rio_list; -}; - -struct opt_rio_lo { - u8 rio_type; - u8 chassis_num; - u8 first_slot_num; - u8 middle_num; - u8 pack_count; - struct list_head opt_rio_lo_list; -}; - -/**************************************************************** -* HPC DESCRIPTOR NODE * -****************************************************************/ - -struct ebda_hpc_list { - u8 format; - u16 num_ctlrs; - short phys_addr; -// struct list_head ebda_hpc_list; -}; -/***************************************************************** -* IN HPC DATA STRUCTURE, THE ASSOCIATED SLOT AND BUS * -* STRUCTURE * -*****************************************************************/ - -struct ebda_hpc_slot { - u8 slot_num; - u32 slot_bus_num; - u8 ctl_index; - u8 slot_cap; -}; - -struct ebda_hpc_bus { - u32 bus_num; - u8 slots_at_33_conv; - u8 slots_at_66_conv; - u8 slots_at_66_pcix; - u8 slots_at_100_pcix; - u8 slots_at_133_pcix; -}; - - -/******************************************************************** -* THREE TYPE OF HOT PLUG CONTROLER * -********************************************************************/ - -struct isa_ctlr_access { - u16 io_start; - u16 io_end; -}; - -struct pci_ctlr_access { - u8 bus; - u8 dev_fun; -}; - -struct wpeg_i2c_ctlr_access { - ulong wpegbbar; - u8 i2c_addr; -}; - -#define HPC_DEVICE_ID 0x0246 -#define HPC_SUBSYSTEM_ID 0x0247 -#define HPC_PCI_OFFSET 0x40 -/************************************************************************* -* RSTC DESCRIPTOR NODE * -*************************************************************************/ - -struct ebda_rsrc_list { - u8 format; - u16 num_entries; - u16 phys_addr; - struct ebda_rsrc_list *next; -}; - - -/*************************************************************************** -* PCI RSRC NODE * -***************************************************************************/ - -struct ebda_pci_rsrc { - u8 rsrc_type; - u8 bus_num; - u8 dev_fun; - u32 start_addr; - u32 end_addr; - u8 marked; /* for NVRAM */ - struct list_head ebda_pci_rsrc_list; -}; - - -/*********************************************************** -* BUS_INFO DATE STRUCTURE * -***********************************************************/ - -struct bus_info { - u8 slot_min; - u8 slot_max; - u8 slot_count; - u8 busno; - u8 controller_id; - u8 current_speed; - u8 current_bus_mode; - u8 index; - u8 slots_at_33_conv; - u8 slots_at_66_conv; - u8 slots_at_66_pcix; - u8 slots_at_100_pcix; - u8 slots_at_133_pcix; - struct list_head bus_info_list; -}; - - -/*********************************************************** -* GLOBAL VARIABLES * -***********************************************************/ -extern struct list_head ibmphp_ebda_pci_rsrc_head; -extern struct list_head ibmphp_slot_head; -extern struct list_head ibmphp_res_head; -/*********************************************************** -* FUNCTION PROTOTYPES * -***********************************************************/ - -extern void ibmphp_free_ebda_hpc_queue (void); -extern int ibmphp_access_ebda (void); -extern struct slot *ibmphp_get_slot_from_physical_num (u8); -extern int ibmphp_get_total_hp_slots (void); -extern void ibmphp_free_ibm_slot (struct slot *); -extern void ibmphp_free_bus_info_queue (void); -extern void ibmphp_free_ebda_pci_rsrc_queue (void); -extern struct bus_info *ibmphp_find_same_bus_num (u32); -extern int ibmphp_get_bus_index (u8); -extern u16 ibmphp_get_total_controllers (void); -extern int ibmphp_register_pci (void); - -/* passed parameters */ -#define MEM 0 -#define IO 1 -#define PFMEM 2 - -/* bit masks */ -#define RESTYPE 0x03 -#define IOMASK 0x00 /* will need to take its complement */ -#define MMASK 0x01 -#define PFMASK 0x03 -#define PCIDEVMASK 0x10 /* we should always have PCI devices */ -#define PRIMARYBUSMASK 0x20 - -/* pci specific defines */ -#define PCI_VENDOR_ID_NOTVALID 0xFFFF -#define PCI_HEADER_TYPE_MULTIDEVICE 0x80 -#define PCI_HEADER_TYPE_MULTIBRIDGE 0x81 - -#define LATENCY 0x64 -#define CACHE 64 -#define DEVICEENABLE 0x015F /* CPQ has 0x0157 */ - -#define IOBRIDGE 0x1000 /* 4k */ -#define MEMBRIDGE 0x100000 /* 1M */ - -/* irqs */ -#define SCSI_IRQ 0x09 -#define LAN_IRQ 0x0A -#define OTHER_IRQ 0x0B - -/* Data Structures */ - -/* type is of the form x x xx xx - * | | | |_ 00 - I/O, 01 - Memory, 11 - PFMemory - * | | - 00 - No Restrictions, 01 - Avoid VGA, 10 - Avoid - * | | VGA and their aliases, 11 - Avoid ISA - * | - 1 - PCI device, 0 - non pci device - * - 1 - Primary PCI Bus Information (0 if Normal device) - * the IO restrictions [2:3] are only for primary buses - */ - - -/* we need this struct because there could be several resource blocks - * allocated per primary bus in the EBDA - */ -struct range_node { - int rangeno; - u32 start; - u32 end; - struct range_node *next; -}; - -struct bus_node { - u8 busno; - int noIORanges; - struct range_node *rangeIO; - int noMemRanges; - struct range_node *rangeMem; - int noPFMemRanges; - struct range_node *rangePFMem; - int needIOUpdate; - int needMemUpdate; - int needPFMemUpdate; - struct resource_node *firstIO; /* first IO resource on the Bus */ - struct resource_node *firstMem; /* first memory resource on the Bus */ - struct resource_node *firstPFMem; /* first prefetchable memory resource on the Bus */ - struct resource_node *firstPFMemFromMem; /* when run out of pfmem available, taking from Mem */ - struct list_head bus_list; -}; - -struct resource_node { - int rangeno; - u8 busno; - u8 devfunc; - u32 start; - u32 end; - u32 len; - int type; /* MEM, IO, PFMEM */ - u8 fromMem; /* this is to indicate that the range is from - * from the Memory bucket rather than from PFMem */ - struct resource_node *next; - struct resource_node *nextRange; /* for the other mem range on bus */ -}; - -struct res_needed { - u32 mem; - u32 pfmem; - u32 io; - u8 not_correct; /* needed for return */ - int devices[32]; /* for device numbers behind this bridge */ -}; - -/* functions */ - -extern int ibmphp_rsrc_init (void); -extern int ibmphp_add_resource (struct resource_node *); -extern int ibmphp_remove_resource (struct resource_node *); -extern int ibmphp_find_resource (struct bus_node *, u32, struct resource_node **, int); -extern int ibmphp_check_resource (struct resource_node *, u8); -extern int ibmphp_remove_bus (struct bus_node *, u8); -extern void ibmphp_free_resources (void); -extern int ibmphp_add_pfmem_from_mem (struct resource_node *); -extern struct bus_node *ibmphp_find_res_bus (u8); -extern void ibmphp_print_test (void); /* for debugging purposes */ - -extern void ibmphp_hpc_initvars (void); -extern int ibmphp_hpc_readslot (struct slot *, u8, u8 *); -extern int ibmphp_hpc_writeslot (struct slot *, u8); -extern void ibmphp_lock_operations (void); -extern void ibmphp_unlock_operations (void); -extern int ibmphp_hpc_fillhpslotinfo (struct hotplug_slot *); -extern int ibmphp_hpc_start_poll_thread (void); -extern void ibmphp_hpc_stop_poll_thread (void); - -//---------------------------------------------------------------------------- - - -//---------------------------------------------------------------------------- -// HPC return codes -//---------------------------------------------------------------------------- -#define FALSE 0x00 -#define TRUE 0x01 -#define HPC_ERROR 0xFF - -//----------------------------------------------------------------------------- -// BUS INFO -//----------------------------------------------------------------------------- -#define BUS_SPEED 0x30 -#define BUS_MODE 0x40 -#define BUS_MODE_PCIX 0x01 -#define BUS_MODE_PCI 0x00 -#define BUS_SPEED_2 0x20 -#define BUS_SPEED_1 0x10 -#define BUS_SPEED_33 0x00 -#define BUS_SPEED_66 0x01 -#define BUS_SPEED_100 0x02 -#define BUS_SPEED_133 0x03 -#define BUS_SPEED_66PCIX 0x04 -#define BUS_SPEED_66UNKNOWN 0x05 -#define BUS_STATUS_AVAILABLE 0x01 -#define BUS_CONTROL_AVAILABLE 0x02 -#define SLOT_LATCH_REGS_SUPPORTED 0x10 - -#define PRGM_MODEL_REV_LEVEL 0xF0 -#define MAX_ADAPTER_NONE 0x09 - -//---------------------------------------------------------------------------- -// HPC 'write' operations/commands -//---------------------------------------------------------------------------- -// Command Code State Write to reg -// Machine at index -//------------------------- ---- ------- ------------ -#define HPC_CTLR_ENABLEIRQ 0x00 // N 15 -#define HPC_CTLR_DISABLEIRQ 0x01 // N 15 -#define HPC_SLOT_OFF 0x02 // Y 0-14 -#define HPC_SLOT_ON 0x03 // Y 0-14 -#define HPC_SLOT_ATTNOFF 0x04 // N 0-14 -#define HPC_SLOT_ATTNON 0x05 // N 0-14 -#define HPC_CTLR_CLEARIRQ 0x06 // N 15 -#define HPC_CTLR_RESET 0x07 // Y 15 -#define HPC_CTLR_IRQSTEER 0x08 // N 15 -#define HPC_BUS_33CONVMODE 0x09 // Y 31-34 -#define HPC_BUS_66CONVMODE 0x0A // Y 31-34 -#define HPC_BUS_66PCIXMODE 0x0B // Y 31-34 -#define HPC_BUS_100PCIXMODE 0x0C // Y 31-34 -#define HPC_BUS_133PCIXMODE 0x0D // Y 31-34 -#define HPC_ALLSLOT_OFF 0x11 // Y 15 -#define HPC_ALLSLOT_ON 0x12 // Y 15 -#define HPC_SLOT_BLINKLED 0x13 // N 0-14 - -//---------------------------------------------------------------------------- -// read commands -//---------------------------------------------------------------------------- -#define READ_SLOTSTATUS 0x01 -#define READ_EXTSLOTSTATUS 0x02 -#define READ_BUSSTATUS 0x03 -#define READ_CTLRSTATUS 0x04 -#define READ_ALLSTAT 0x05 -#define READ_ALLSLOT 0x06 -#define READ_SLOTLATCHLOWREG 0x07 -#define READ_REVLEVEL 0x08 -#define READ_HPCOPTIONS 0x09 -//---------------------------------------------------------------------------- -// slot status -//---------------------------------------------------------------------------- -#define HPC_SLOT_POWER 0x01 -#define HPC_SLOT_CONNECT 0x02 -#define HPC_SLOT_ATTN 0x04 -#define HPC_SLOT_PRSNT2 0x08 -#define HPC_SLOT_PRSNT1 0x10 -#define HPC_SLOT_PWRGD 0x20 -#define HPC_SLOT_BUS_SPEED 0x40 -#define HPC_SLOT_LATCH 0x80 - -//---------------------------------------------------------------------------- -// HPC_SLOT_POWER status return codes -//---------------------------------------------------------------------------- -#define HPC_SLOT_POWER_OFF 0x00 -#define HPC_SLOT_POWER_ON 0x01 - -//---------------------------------------------------------------------------- -// HPC_SLOT_CONNECT status return codes -//---------------------------------------------------------------------------- -#define HPC_SLOT_CONNECTED 0x00 -#define HPC_SLOT_DISCONNECTED 0x01 - -//---------------------------------------------------------------------------- -// HPC_SLOT_ATTN status return codes -//---------------------------------------------------------------------------- -#define HPC_SLOT_ATTN_OFF 0x00 -#define HPC_SLOT_ATTN_ON 0x01 -#define HPC_SLOT_ATTN_BLINK 0x02 - -//---------------------------------------------------------------------------- -// HPC_SLOT_PRSNT status return codes -//---------------------------------------------------------------------------- -#define HPC_SLOT_EMPTY 0x00 -#define HPC_SLOT_PRSNT_7 0x01 -#define HPC_SLOT_PRSNT_15 0x02 -#define HPC_SLOT_PRSNT_25 0x03 - -//---------------------------------------------------------------------------- -// HPC_SLOT_PWRGD status return codes -//---------------------------------------------------------------------------- -#define HPC_SLOT_PWRGD_FAULT_NONE 0x00 -#define HPC_SLOT_PWRGD_GOOD 0x01 - -//---------------------------------------------------------------------------- -// HPC_SLOT_BUS_SPEED status return codes -//---------------------------------------------------------------------------- -#define HPC_SLOT_BUS_SPEED_OK 0x00 -#define HPC_SLOT_BUS_SPEED_MISM 0x01 - -//---------------------------------------------------------------------------- -// HPC_SLOT_LATCH status return codes -//---------------------------------------------------------------------------- -#define HPC_SLOT_LATCH_OPEN 0x01 // NOTE : in PCI spec bit off = open -#define HPC_SLOT_LATCH_CLOSED 0x00 // NOTE : in PCI spec bit on = closed - - -//---------------------------------------------------------------------------- -// extended slot status -//---------------------------------------------------------------------------- -#define HPC_SLOT_PCIX 0x01 -#define HPC_SLOT_SPEED1 0x02 -#define HPC_SLOT_SPEED2 0x04 -#define HPC_SLOT_BLINK_ATTN 0x08 -#define HPC_SLOT_RSRVD1 0x10 -#define HPC_SLOT_RSRVD2 0x20 -#define HPC_SLOT_BUS_MODE 0x40 -#define HPC_SLOT_RSRVD3 0x80 - -//---------------------------------------------------------------------------- -// HPC_XSLOT_PCIX_CAP status return codes -//---------------------------------------------------------------------------- -#define HPC_SLOT_PCIX_NO 0x00 -#define HPC_SLOT_PCIX_YES 0x01 - -//---------------------------------------------------------------------------- -// HPC_XSLOT_SPEED status return codes -//---------------------------------------------------------------------------- -#define HPC_SLOT_SPEED_33 0x00 -#define HPC_SLOT_SPEED_66 0x01 -#define HPC_SLOT_SPEED_133 0x02 - -//---------------------------------------------------------------------------- -// HPC_XSLOT_ATTN_BLINK status return codes -//---------------------------------------------------------------------------- -#define HPC_SLOT_ATTN_BLINK_OFF 0x00 -#define HPC_SLOT_ATTN_BLINK_ON 0x01 - -//---------------------------------------------------------------------------- -// HPC_XSLOT_BUS_MODE status return codes -//---------------------------------------------------------------------------- -#define HPC_SLOT_BUS_MODE_OK 0x00 -#define HPC_SLOT_BUS_MODE_MISM 0x01 - -//---------------------------------------------------------------------------- -// Controller status -//---------------------------------------------------------------------------- -#define HPC_CTLR_WORKING 0x01 -#define HPC_CTLR_FINISHED 0x02 -#define HPC_CTLR_RESULT0 0x04 -#define HPC_CTLR_RESULT1 0x08 -#define HPC_CTLR_RESULE2 0x10 -#define HPC_CTLR_RESULT3 0x20 -#define HPC_CTLR_IRQ_ROUTG 0x40 -#define HPC_CTLR_IRQ_PENDG 0x80 - -//---------------------------------------------------------------------------- -// HPC_CTLR_WROKING status return codes -//---------------------------------------------------------------------------- -#define HPC_CTLR_WORKING_NO 0x00 -#define HPC_CTLR_WORKING_YES 0x01 - -//---------------------------------------------------------------------------- -// HPC_CTLR_FINISHED status return codes -//---------------------------------------------------------------------------- -#define HPC_CTLR_FINISHED_NO 0x00 -#define HPC_CTLR_FINISHED_YES 0x01 - -//---------------------------------------------------------------------------- -// HPC_CTLR_RESULT status return codes -//---------------------------------------------------------------------------- -#define HPC_CTLR_RESULT_SUCCESS 0x00 -#define HPC_CTLR_RESULT_FAILED 0x01 -#define HPC_CTLR_RESULT_RSVD 0x02 -#define HPC_CTLR_RESULT_NORESP 0x03 - - -//---------------------------------------------------------------------------- -// macro for slot info -//---------------------------------------------------------------------------- -#define SLOT_POWER(s) ((u8) ((s & HPC_SLOT_POWER) \ - ? HPC_SLOT_POWER_ON : HPC_SLOT_POWER_OFF)) - -#define SLOT_CONNECT(s) ((u8) ((s & HPC_SLOT_CONNECT) \ - ? HPC_SLOT_DISCONNECTED : HPC_SLOT_CONNECTED)) - -#define SLOT_ATTN(s,es) ((u8) ((es & HPC_SLOT_BLINK_ATTN) \ - ? HPC_SLOT_ATTN_BLINK \ - : ((s & HPC_SLOT_ATTN) ? HPC_SLOT_ATTN_ON : HPC_SLOT_ATTN_OFF))) - -#define SLOT_PRESENT(s) ((u8) ((s & HPC_SLOT_PRSNT1) \ - ? ((s & HPC_SLOT_PRSNT2) ? HPC_SLOT_EMPTY : HPC_SLOT_PRSNT_15) \ - : ((s & HPC_SLOT_PRSNT2) ? HPC_SLOT_PRSNT_25 : HPC_SLOT_PRSNT_7))) - -#define SLOT_PWRGD(s) ((u8) ((s & HPC_SLOT_PWRGD) \ - ? HPC_SLOT_PWRGD_GOOD : HPC_SLOT_PWRGD_FAULT_NONE)) - -#define SLOT_BUS_SPEED(s) ((u8) ((s & HPC_SLOT_BUS_SPEED) \ - ? HPC_SLOT_BUS_SPEED_MISM : HPC_SLOT_BUS_SPEED_OK)) - -#define SLOT_LATCH(s) ((u8) ((s & HPC_SLOT_LATCH) \ - ? HPC_SLOT_LATCH_CLOSED : HPC_SLOT_LATCH_OPEN)) - -#define SLOT_PCIX(es) ((u8) ((es & HPC_SLOT_PCIX) \ - ? HPC_SLOT_PCIX_YES : HPC_SLOT_PCIX_NO)) - -#define SLOT_SPEED(es) ((u8) ((es & HPC_SLOT_SPEED2) \ - ? ((es & HPC_SLOT_SPEED1) ? HPC_SLOT_SPEED_133 \ - : HPC_SLOT_SPEED_66) \ - : HPC_SLOT_SPEED_33)) - -#define SLOT_BUS_MODE(es) ((u8) ((es & HPC_SLOT_BUS_MODE) \ - ? HPC_SLOT_BUS_MODE_MISM : HPC_SLOT_BUS_MODE_OK)) - -//-------------------------------------------------------------------------- -// macro for bus info -//--------------------------------------------------------------------------- -#define CURRENT_BUS_SPEED(s) ((u8) (s & BUS_SPEED_2) \ - ? ((s & BUS_SPEED_1) ? BUS_SPEED_133 : BUS_SPEED_100) \ - : ((s & BUS_SPEED_1) ? BUS_SPEED_66 : BUS_SPEED_33)) - -#define CURRENT_BUS_MODE(s) ((u8) (s & BUS_MODE) ? BUS_MODE_PCIX : BUS_MODE_PCI) - -#define READ_BUS_STATUS(s) ((u8) (s->options & BUS_STATUS_AVAILABLE)) - -#define READ_BUS_MODE(s) ((s->revision & PRGM_MODEL_REV_LEVEL) >= 0x20) - -#define SET_BUS_STATUS(s) ((u8) (s->options & BUS_CONTROL_AVAILABLE)) - -#define READ_SLOT_LATCH(s) ((u8) (s->options & SLOT_LATCH_REGS_SUPPORTED)) - -//---------------------------------------------------------------------------- -// macro for controller info -//---------------------------------------------------------------------------- -#define CTLR_WORKING(c) ((u8) ((c & HPC_CTLR_WORKING) \ - ? HPC_CTLR_WORKING_YES : HPC_CTLR_WORKING_NO)) -#define CTLR_FINISHED(c) ((u8) ((c & HPC_CTLR_FINISHED) \ - ? HPC_CTLR_FINISHED_YES : HPC_CTLR_FINISHED_NO)) -#define CTLR_RESULT(c) ((u8) ((c & HPC_CTLR_RESULT1) \ - ? ((c & HPC_CTLR_RESULT0) ? HPC_CTLR_RESULT_NORESP \ - : HPC_CTLR_RESULT_RSVD) \ - : ((c & HPC_CTLR_RESULT0) ? HPC_CTLR_RESULT_FAILED \ - : HPC_CTLR_RESULT_SUCCESS))) - -// command that affect the state machine of HPC -#define NEEDTOCHECK_CMDSTATUS(c) ((c == HPC_SLOT_OFF) || \ - (c == HPC_SLOT_ON) || \ - (c == HPC_CTLR_RESET) || \ - (c == HPC_BUS_33CONVMODE) || \ - (c == HPC_BUS_66CONVMODE) || \ - (c == HPC_BUS_66PCIXMODE) || \ - (c == HPC_BUS_100PCIXMODE) || \ - (c == HPC_BUS_133PCIXMODE) || \ - (c == HPC_ALLSLOT_OFF) || \ - (c == HPC_ALLSLOT_ON)) - - -/* Core part of the driver */ - -#define ENABLE 1 -#define DISABLE 0 - -#define CARD_INFO 0x07 -#define PCIX133 0x07 -#define PCIX66 0x05 -#define PCI66 0x04 - -extern struct pci_bus *ibmphp_pci_bus; - -/* Variables */ - -struct pci_func { - struct pci_dev *dev; /* from the OS */ - u8 busno; - u8 device; - u8 function; - struct resource_node *io[6]; - struct resource_node *mem[6]; - struct resource_node *pfmem[6]; - struct pci_func *next; - int devices[32]; /* for bridge config */ - u8 irq[4]; /* for interrupt config */ - u8 bus; /* flag for unconfiguring, to say if PPB */ -}; - -struct slot { - u8 bus; - u8 device; - u8 number; - u8 real_physical_slot_num; - char name[100]; - u32 capabilities; - u8 supported_speed; - u8 supported_bus_mode; - struct hotplug_slot *hotplug_slot; - struct controller *ctrl; - struct pci_func *func; - u8 irq[4]; - u8 flag; /* this is for disable slot and polling */ - int bit_mode; /* 0 = 32, 1 = 64 */ - u8 ctlr_index; - struct bus_info *bus_on; - struct list_head ibm_slot_list; - u8 status; - u8 ext_status; - u8 busstatus; -}; - -struct controller { - struct ebda_hpc_slot *slots; - struct ebda_hpc_bus *buses; - struct pci_dev *ctrl_dev; /* in case where controller is PCI */ - u8 starting_slot_num; /* starting and ending slot #'s this ctrl controls*/ - u8 ending_slot_num; - u8 revision; - u8 options; /* which options HPC supports */ - u8 status; - u8 ctlr_id; - u8 slot_count; - u8 bus_count; - u8 ctlr_relative_id; - u32 irq; - union { - struct isa_ctlr_access isa_ctlr; - struct pci_ctlr_access pci_ctlr; - struct wpeg_i2c_ctlr_access wpeg_ctlr; - } u; - u8 ctlr_type; - struct list_head ebda_hpc_list; -}; - -/* Functions */ - -extern int ibmphp_init_devno (struct slot **); /* This function is called from EBDA, so we need it not be static */ -extern int ibmphp_disable_slot (struct hotplug_slot *); /* This function is called from HPC, so we need it to not be static */ -extern int ibmphp_do_disable_slot (struct slot *slot_cur); -extern int ibmphp_update_slot_info (struct slot *); /* This function is called from HPC, so we need it to not be be static */ -extern int ibmphp_configure_card (struct pci_func *, u8); -extern int ibmphp_unconfigure_card (struct slot **, int); -extern struct hotplug_slot_ops ibmphp_hotplug_slot_ops; - -static inline void long_delay (int delay) -{ - set_current_state (TASK_INTERRUPTIBLE); - schedule_timeout (delay); -} - -#endif //__IBMPHP_H - diff -Nru a/drivers/hotplug/ibmphp_core.c b/drivers/hotplug/ibmphp_core.c --- a/drivers/hotplug/ibmphp_core.c Mon Jun 9 23:16:20 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,1439 +0,0 @@ -/* - * IBM Hot Plug Controller Driver - * - * Written By: Chuck Cole, Jyoti Shah, Tong Yu, Irene Zubarev, IBM Corporation - * - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001,2002 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or - * NON INFRINGEMENT. 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. - * - * Send feedback to <gregkh@us.ibm.com> - * - */ - -#include <linux/init.h> -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/pci.h> -#include <linux/interrupt.h> -#include <linux/delay.h> -#include <linux/wait.h> -#include <linux/smp_lock.h> -#include "../../arch/i386/pci/pci.h" /* for struct irq_routing_table */ -#include "ibmphp.h" - -#define attn_on(sl) ibmphp_hpc_writeslot (sl, HPC_SLOT_ATTNON) -#define attn_off(sl) ibmphp_hpc_writeslot (sl, HPC_SLOT_ATTNOFF) -#define attn_LED_blink(sl) ibmphp_hpc_writeslot (sl, HPC_SLOT_BLINKLED) -#define get_ctrl_revision(sl, rev) ibmphp_hpc_readslot (sl, READ_REVLEVEL, rev) -#define get_hpc_options(sl, opt) ibmphp_hpc_readslot (sl, READ_HPCOPTIONS, opt) - -#define DRIVER_VERSION "0.6" -#define DRIVER_DESC "IBM Hot Plug PCI Controller Driver" - -int ibmphp_debug; - -static int debug; -MODULE_PARM (debug, "i"); -MODULE_PARM_DESC (debug, "Debugging mode enabled or not"); -MODULE_LICENSE ("GPL"); -MODULE_DESCRIPTION (DRIVER_DESC); - -struct pci_bus *ibmphp_pci_bus; -static int max_slots; - -static int irqs[16]; /* PIC mode IRQ's we're using so far (in case MPS tables don't provide default info for empty slots */ - -static int init_flag; - -/* -static int get_max_adapter_speed_1 (struct hotplug_slot *, u8 *, u8); - -static inline int get_max_adapter_speed (struct hotplug_slot *hs, u8 *value) -{ - return get_max_adapter_speed_1 (hs, value, 1); -} -*/ -static inline int get_cur_bus_info (struct slot **sl) -{ - int rc = 1; - struct slot * slot_cur = *sl; - - debug ("options = %x\n", slot_cur->ctrl->options); - debug ("revision = %x\n", slot_cur->ctrl->revision); - - if (READ_BUS_STATUS (slot_cur->ctrl)) - rc = ibmphp_hpc_readslot (slot_cur, READ_BUSSTATUS, NULL); - - if (rc) - return rc; - - slot_cur->bus_on->current_speed = CURRENT_BUS_SPEED (slot_cur->busstatus); - if (READ_BUS_MODE (slot_cur->ctrl)) - slot_cur->bus_on->current_bus_mode = CURRENT_BUS_MODE (slot_cur->busstatus); - else - slot_cur->bus_on->current_bus_mode = 0xFF; - - debug ("busstatus = %x, bus_speed = %x, bus_mode = %x\n", slot_cur->busstatus, slot_cur->bus_on->current_speed, slot_cur->bus_on->current_bus_mode); - - *sl = slot_cur; - return 0; -} - -static inline int slot_update (struct slot **sl) -{ - int rc; - rc = ibmphp_hpc_readslot (*sl, READ_ALLSTAT, NULL); - if (rc) - return rc; - if (!init_flag) - return get_cur_bus_info (sl); - return rc; -} - -static int __init get_max_slots (void) -{ - struct slot * slot_cur; - struct list_head * tmp; - u8 slot_count = 0; - - list_for_each (tmp, &ibmphp_slot_head) { - slot_cur = list_entry (tmp, struct slot, ibm_slot_list); - /* sometimes the hot-pluggable slots start with 4 (not always from 1 */ - slot_count = max (slot_count, slot_cur->number); - } - return slot_count; -} - -/* This routine will put the correct slot->device information per slot. It's - * called from initialization of the slot structures. It will also assign - * interrupt numbers per each slot. - * Parameters: struct slot - * Returns 0 or errors - */ -int ibmphp_init_devno (struct slot **cur_slot) -{ - struct irq_routing_table *rtable; - int len; - int loop; - int i; - - rtable = pcibios_get_irq_routing_table (); - if (!rtable) { - err ("no BIOS routing table...\n"); - return -ENOMEM; - } - - len = (rtable->size - sizeof (struct irq_routing_table)) / sizeof (struct irq_info); - - if (!len) - return -1; - for (loop = 0; loop < len; loop++) { - if ((*cur_slot)->number == rtable->slots[loop].slot) { - if ((*cur_slot)->bus == rtable->slots[loop].bus) { - (*cur_slot)->device = PCI_SLOT (rtable->slots[loop].devfn); - for (i = 0; i < 4; i++) - (*cur_slot)->irq[i] = IO_APIC_get_PCI_irq_vector ((int) (*cur_slot)->bus, (int) (*cur_slot)->device, i); - - debug ("(*cur_slot)->irq[0] = %x\n", (*cur_slot)->irq[0]); - debug ("(*cur_slot)->irq[1] = %x\n", (*cur_slot)->irq[1]); - debug ("(*cur_slot)->irq[2] = %x\n", (*cur_slot)->irq[2]); - debug ("(*cur_slot)->irq[3] = %x\n", (*cur_slot)->irq[3]); - - debug ("rtable->exlusive_irqs = %x\n", rtable->exclusive_irqs); - debug ("rtable->slots[loop].irq[0].bitmap = %x\n", rtable->slots[loop].irq[0].bitmap); - debug ("rtable->slots[loop].irq[1].bitmap = %x\n", rtable->slots[loop].irq[1].bitmap); - debug ("rtable->slots[loop].irq[2].bitmap = %x\n", rtable->slots[loop].irq[2].bitmap); - debug ("rtable->slots[loop].irq[3].bitmap = %x\n", rtable->slots[loop].irq[3].bitmap); - - debug ("rtable->slots[loop].irq[0].link= %x\n", rtable->slots[loop].irq[0].link); - debug ("rtable->slots[loop].irq[1].link = %x\n", rtable->slots[loop].irq[1].link); - debug ("rtable->slots[loop].irq[2].link = %x\n", rtable->slots[loop].irq[2].link); - debug ("rtable->slots[loop].irq[3].link = %x\n", rtable->slots[loop].irq[3].link); - debug ("end of init_devno\n"); - return 0; - } - } - } - - return -1; -} - -static inline int power_on (struct slot *slot_cur) -{ - u8 cmd = HPC_SLOT_ON; - int retval; - - retval = ibmphp_hpc_writeslot (slot_cur, cmd); - if (retval) { - err ("power on failed\n"); - return retval; - } - if (CTLR_RESULT (slot_cur->ctrl->status)) { - err ("command not completed successfully in power_on \n"); - return -EIO; - } - long_delay (3 * HZ); /* For ServeRAID cards, and some 66 PCI */ - return 0; -} - -static inline int power_off (struct slot *slot_cur) -{ - u8 cmd = HPC_SLOT_OFF; - int retval; - - retval = ibmphp_hpc_writeslot (slot_cur, cmd); - if (retval) { - err ("power off failed \n"); - return retval; - } - if (CTLR_RESULT (slot_cur->ctrl->status)) { - err ("command not completed successfully in power_off \n"); - return -EIO; - } - return 0; -} - -static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 value) -{ - int rc = 0; - struct slot *pslot; - u8 cmd; - int hpcrc = 0; - - debug ("set_attention_status - Entry hotplug_slot[%lx] value[%x]\n", (ulong) hotplug_slot, value); - ibmphp_lock_operations (); - cmd = 0x00; // avoid compiler warning - - if (hotplug_slot) { - switch (value) { - case HPC_SLOT_ATTN_OFF: - cmd = HPC_SLOT_ATTNOFF; - break; - case HPC_SLOT_ATTN_ON: - cmd = HPC_SLOT_ATTNON; - break; - case HPC_SLOT_ATTN_BLINK: - cmd = HPC_SLOT_BLINKLED; - break; - default: - rc = -ENODEV; - err ("set_attention_status - Error : invalid input [%x]\n", value); - break; - } - if (rc == 0) { - pslot = (struct slot *) hotplug_slot->private; - if (pslot) - hpcrc = ibmphp_hpc_writeslot (pslot, cmd); - else - rc = -ENODEV; - } - } else - rc = -ENODEV; - - if (hpcrc) - rc = hpcrc; - - ibmphp_unlock_operations (); - - debug ("set_attention_status - Exit rc[%d]\n", rc); - return rc; -} - -static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 * value) -{ - int rc = -ENODEV; - struct slot *pslot; - int hpcrc = 0; - struct slot myslot; - - debug ("get_attention_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); - - ibmphp_lock_operations (); - if (hotplug_slot && value) { - pslot = (struct slot *) hotplug_slot->private; - if (pslot) { - memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); - hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status)); - if (!hpcrc) - hpcrc = ibmphp_hpc_readslot (pslot, READ_EXTSLOTSTATUS, &(myslot.ext_status)); - if (!hpcrc) { - *value = SLOT_ATTN (myslot.status, myslot.ext_status); - rc = 0; - } - } - } else - rc = -ENODEV; - - if (hpcrc) - rc = hpcrc; - - ibmphp_unlock_operations (); - debug ("get_attention_status - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value); - return rc; -} - -static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 * value) -{ - int rc = -ENODEV; - struct slot *pslot; - int hpcrc = 0; - struct slot myslot; - - debug ("get_latch_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); - ibmphp_lock_operations (); - if (hotplug_slot && value) { - pslot = (struct slot *) hotplug_slot->private; - if (pslot) { - memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); - hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status)); - if (!hpcrc) { - *value = SLOT_LATCH (myslot.status); - rc = 0; - } - } - } else - rc = -ENODEV; - - if (hpcrc) - rc = hpcrc; - - ibmphp_unlock_operations (); - debug ("get_latch_status - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value); - return rc; -} - - -static int get_power_status (struct hotplug_slot *hotplug_slot, u8 * value) -{ - int rc = -ENODEV; - struct slot *pslot; - int hpcrc = 0; - struct slot myslot; - - debug ("get_power_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); - ibmphp_lock_operations (); - if (hotplug_slot && value) { - pslot = (struct slot *) hotplug_slot->private; - if (pslot) { - memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); - hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status)); - if (!hpcrc) { - *value = SLOT_PWRGD (myslot.status); - rc = 0; - } - } - } else - rc = -ENODEV; - - if (hpcrc) - rc = hpcrc; - - ibmphp_unlock_operations (); - debug ("get_power_status - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value); - return rc; -} - -static int get_adapter_present (struct hotplug_slot *hotplug_slot, u8 * value) -{ - int rc = -ENODEV; - struct slot *pslot; - u8 present; - int hpcrc = 0; - struct slot myslot; - - debug ("get_adapter_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); - ibmphp_lock_operations (); - if (hotplug_slot && value) { - pslot = (struct slot *) hotplug_slot->private; - if (pslot) { - memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); - hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status)); - if (!hpcrc) { - present = SLOT_PRESENT (myslot.status); - if (present == HPC_SLOT_EMPTY) - *value = 0; - else - *value = 1; - rc = 0; - } - } - } else - rc = -ENODEV; - if (hpcrc) - rc = hpcrc; - - ibmphp_unlock_operations (); - debug ("get_adapter_present - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value); - return rc; -} - -static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) -{ - int rc = -ENODEV; - struct slot *pslot; - u8 mode = 0; - - debug ("%s - Entry hotplug_slot[%p] pvalue[%p]\n", __FUNCTION__, - hotplug_slot, value); - - ibmphp_lock_operations (); - - if (hotplug_slot && value) { - pslot = (struct slot *) hotplug_slot->private; - if (pslot) { - rc = 0; - mode = pslot->supported_bus_mode; - *value = pslot->supported_speed; - switch (*value) { - case BUS_SPEED_33: - break; - case BUS_SPEED_66: - if (mode == BUS_MODE_PCIX) - *value += 0x01; - break; - case BUS_SPEED_100: - case BUS_SPEED_133: - *value = pslot->supported_speed + 0x01; - break; - default: - /* Note (will need to change): there would be soon 256, 512 also */ - rc = -ENODEV; - } - } - } else - rc = -ENODEV; - - ibmphp_unlock_operations (); - debug ("%s - Exit rc[%d] value[%x]\n", __FUNCTION__, rc, *value); - return rc; -} - -static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) -{ - int rc = -ENODEV; - struct slot *pslot; - u8 mode = 0; - - debug ("%s - Entry hotplug_slot[%p] pvalue[%p]\n", __FUNCTION__, - hotplug_slot, value); - - ibmphp_lock_operations (); - - if (hotplug_slot && value) { - pslot = (struct slot *) hotplug_slot->private; - if (pslot) { - rc = get_cur_bus_info (&pslot); - if (!rc) { - mode = pslot->bus_on->current_bus_mode; - *value = pslot->bus_on->current_speed; - switch (*value) { - case BUS_SPEED_33: - break; - case BUS_SPEED_66: - if (mode == BUS_MODE_PCIX) - *value += 0x01; - else if (mode == BUS_MODE_PCI) - ; - else - *value = PCI_SPEED_UNKNOWN; - break; - case BUS_SPEED_100: - case BUS_SPEED_133: - *value += 0x01; - break; - default: - /* Note of change: there would also be 256, 512 soon */ - rc = -ENODEV; - } - } - } - } else - rc = -ENODEV; - - ibmphp_unlock_operations (); - debug ("%s - Exit rc[%d] value[%x]\n", __FUNCTION__, rc, *value); - return rc; -} -/* -static int get_max_adapter_speed_1 (struct hotplug_slot *hotplug_slot, u8 * value, u8 flag) -{ - int rc = -ENODEV; - struct slot *pslot; - int hpcrc = 0; - struct slot myslot; - - debug ("get_max_adapter_speed_1 - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong)hotplug_slot, (ulong) value); - - if (flag) - ibmphp_lock_operations (); - - if (hotplug_slot && value) { - pslot = (struct slot *) hotplug_slot->private; - if (pslot) { - memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); - hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status)); - - if (!(SLOT_LATCH (myslot.status)) && (SLOT_PRESENT (myslot.status))) { - hpcrc = ibmphp_hpc_readslot (pslot, READ_EXTSLOTSTATUS, &(myslot.ext_status)); - if (!hpcrc) { - *value = SLOT_SPEED (myslot.ext_status); - rc = 0; - } - } else { - *value = MAX_ADAPTER_NONE; - rc = 0; - } - } - } else - rc = -ENODEV; - - if (hpcrc) - rc = hpcrc; - - if (flag) - ibmphp_unlock_operations (); - - debug ("get_max_adapter_speed_1 - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value); - return rc; -} - -static int get_bus_name (struct hotplug_slot *hotplug_slot, char * value) -{ - int rc = -ENODEV; - struct slot *pslot = NULL; - - debug ("get_bus_name - Entry hotplug_slot[%lx] \n", (ulong)hotplug_slot); - - ibmphp_lock_operations (); - - if (hotplug_slot) { - pslot = (struct slot *) hotplug_slot->private; - if (pslot) { - rc = 0; - snprintf (value, 100, "Bus %x", pslot->bus); - } - } else - rc = -ENODEV; - - ibmphp_unlock_operations (); - debug ("get_bus_name - Exit rc[%d] value[%x]\n", rc, *value); - return rc; -} -*/ - -/******************************************************************************* - * This routine will initialize the ops data structure used in the validate - * function. It will also power off empty slots that are powered on since BIOS - * leaves those on, albeit disconnected - ******************************************************************************/ -static int __init init_ops (void) -{ - struct slot *slot_cur; - struct list_head *tmp; - int retval; - int rc; - - list_for_each (tmp, &ibmphp_slot_head) { - slot_cur = list_entry (tmp, struct slot, ibm_slot_list); - - if (!slot_cur) - return -ENODEV; - - debug ("BEFORE GETTING SLOT STATUS, slot # %x\n", slot_cur->number); - if (slot_cur->ctrl->revision == 0xFF) - if (get_ctrl_revision (slot_cur, &slot_cur->ctrl->revision)) - return -1; - - if (slot_cur->bus_on->current_speed == 0xFF) - if (get_cur_bus_info (&slot_cur)) - return -1; - - if (slot_cur->ctrl->options == 0xFF) - if (get_hpc_options (slot_cur, &slot_cur->ctrl->options)) - return -1; - - retval = slot_update (&slot_cur); - if (retval) - return retval; - - debug ("status = %x\n", slot_cur->status); - debug ("ext_status = %x\n", slot_cur->ext_status); - debug ("SLOT_POWER = %x\n", SLOT_POWER (slot_cur->status)); - debug ("SLOT_PRESENT = %x\n", SLOT_PRESENT (slot_cur->status)); - debug ("SLOT_LATCH = %x\n", SLOT_LATCH (slot_cur->status)); - - if ((SLOT_PWRGD (slot_cur->status)) && - !(SLOT_PRESENT (slot_cur->status)) && - !(SLOT_LATCH (slot_cur->status))) { - debug ("BEFORE POWER OFF COMMAND\n"); - rc = power_off (slot_cur); - if (rc) - return rc; - - /* retval = slot_update (&slot_cur); - * if (retval) - * return retval; - * ibmphp_update_slot_info (slot_cur); - */ - } - } - init_flag = 0; - return 0; -} - -/* This operation will check whether the slot is within the bounds and - * the operation is valid to perform on that slot - * Parameters: slot, operation - * Returns: 0 or error codes - */ -static int validate (struct slot *slot_cur, int opn) -{ - int number; - int retval; - - if (!slot_cur) - return -ENODEV; - number = slot_cur->number; - if ((number > max_slots) || (number < 0)) - return -EBADSLT; - debug ("slot_number in validate is %d\n", slot_cur->number); - - retval = slot_update (&slot_cur); - if (retval) - return retval; - - switch (opn) { - case ENABLE: - if (!(SLOT_PWRGD (slot_cur->status)) && - (SLOT_PRESENT (slot_cur->status)) && - !(SLOT_LATCH (slot_cur->status))) - return 0; - break; - case DISABLE: - if ((SLOT_PWRGD (slot_cur->status)) && - (SLOT_PRESENT (slot_cur->status)) && - !(SLOT_LATCH (slot_cur->status))) - return 0; - break; - default: - break; - } - err ("validate failed....\n"); - return -EINVAL; -} - -/******************************************************************************** - * This routine is for updating the data structures in the hotplug core - * Parameters: struct slot - * Returns: 0 or error - *******************************************************************************/ -int ibmphp_update_slot_info (struct slot *slot_cur) -{ - struct hotplug_slot_info *info; - int rc; - u8 bus_speed; - u8 mode; - - info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); - if (!info) { - err ("out of system memory \n"); - return -ENOMEM; - } - - info->power_status = SLOT_PWRGD (slot_cur->status); - info->attention_status = SLOT_ATTN (slot_cur->status, slot_cur->ext_status); - info->latch_status = SLOT_LATCH (slot_cur->status); - if (!SLOT_PRESENT (slot_cur->status)) { - info->adapter_status = 0; -// info->max_adapter_speed_status = MAX_ADAPTER_NONE; - } else { - info->adapter_status = 1; -// get_max_adapter_speed_1 (slot_cur->hotplug_slot, &info->max_adapter_speed_status, 0); - } - - bus_speed = slot_cur->bus_on->current_speed; - mode = slot_cur->bus_on->current_bus_mode; - - switch (bus_speed) { - case BUS_SPEED_33: - break; - case BUS_SPEED_66: - if (mode == BUS_MODE_PCIX) - bus_speed += 0x01; - else if (mode == BUS_MODE_PCI) - ; - else - bus_speed = PCI_SPEED_UNKNOWN; - break; - case BUS_SPEED_100: - case BUS_SPEED_133: - bus_speed += 0x01; - break; - default: - bus_speed = PCI_SPEED_UNKNOWN; - } - - info->cur_bus_speed = bus_speed; - info->max_bus_speed = slot_cur->hotplug_slot->info->max_bus_speed; - // To do: bus_names - - rc = pci_hp_change_slot_info (slot_cur->hotplug_slot, info); - kfree (info); - return rc; -} - - -/****************************************************************************** - * This function will return the pci_func, given bus and devfunc, or NULL. It - * is called from visit routines - ******************************************************************************/ - -static struct pci_func *ibm_slot_find (u8 busno, u8 device, u8 function) -{ - struct pci_func *func_cur; - struct slot *slot_cur; - struct list_head * tmp; - list_for_each (tmp, &ibmphp_slot_head) { - slot_cur = list_entry (tmp, struct slot, ibm_slot_list); - if (slot_cur->func) { - func_cur = slot_cur->func; - while (func_cur) { - if ((func_cur->busno == busno) && (func_cur->device == device) && (func_cur->function == function)) - return func_cur; - func_cur = func_cur->next; - } - } - } - return NULL; -} - -/* This routine is to find the pci_bus from kernel structures. - * Parameters: bus number - * Returns : pci_bus * or NULL if not found - */ -static struct pci_bus *ibmphp_find_bus (u8 busno) -{ - const struct list_head *tmp; - struct pci_bus *bus; - debug ("inside %s, busno = %x \n", __FUNCTION__, busno); - - list_for_each (tmp, &pci_root_buses) { - bus = (struct pci_bus *) pci_bus_b (tmp); - if (bus) - if (bus->number == busno) - return bus; - } - return NULL; -} - -/************************************************************* - * This routine frees up memory used by struct slot, including - * the pointers to pci_func, bus, hotplug_slot, controller, - * and deregistering from the hotplug core - *************************************************************/ -static void free_slots (void) -{ - struct slot *slot_cur; - struct list_head * tmp; - struct list_head * next; - - debug ("%s -- enter\n", __FUNCTION__); - - list_for_each_safe (tmp, next, &ibmphp_slot_head) { - - slot_cur = list_entry (tmp, struct slot, ibm_slot_list); - - pci_hp_deregister (slot_cur->hotplug_slot); - - if (slot_cur->hotplug_slot) { - kfree (slot_cur->hotplug_slot); - slot_cur->hotplug_slot = NULL; - } - - if (slot_cur->ctrl) - slot_cur->ctrl = NULL; - - if (slot_cur->bus_on) - slot_cur->bus_on = NULL; - - ibmphp_unconfigure_card (&slot_cur, -1); /* we don't want to actually remove the resources, since free_resources will do just that */ - - kfree (slot_cur); - slot_cur = NULL; - } - debug ("%s -- exit\n", __FUNCTION__); -} - -static int ibm_unconfigure_device (struct pci_func *func) -{ - struct pci_dev *temp; - u8 j; - - debug ("inside %s\n", __FUNCTION__); - debug ("func->device = %x, func->function = %x\n", func->device, func->function); - debug ("func->device << 3 | 0x0 = %x\n", func->device << 3 | 0x0); - - for (j = 0; j < 0x08; j++) { - temp = pci_find_slot (func->busno, (func->device << 3) | j); - if (temp) - pci_remove_bus_device(temp); - } - return 0; -} - -/* - * The following function is to fix kernel bug regarding - * getting bus entries, here we manually add those primary - * bus entries to kernel bus structure whenever apply - */ - -static u8 bus_structure_fixup (u8 busno) -{ - struct pci_bus *bus; - struct pci_dev *dev; - u16 l; - - if (ibmphp_find_bus (busno) || !(ibmphp_find_same_bus_num (busno))) - return 1; - - bus = kmalloc (sizeof (*bus), GFP_KERNEL); - if (!bus) { - err ("%s - out of memory\n", __FUNCTION__); - return 1; - } - dev = kmalloc (sizeof (*dev), GFP_KERNEL); - if (!dev) { - kfree (bus); - err ("%s - out of memory\n", __FUNCTION__); - return 1; - } - - bus->number = busno; - bus->ops = ibmphp_pci_bus->ops; - dev->bus = bus; - for (dev->devfn = 0; dev->devfn < 256; dev->devfn += 8) { - if (!pci_read_config_word (dev, PCI_VENDOR_ID, &l) && l != 0x0000 && l != 0xffff) { - debug ("%s - Inside bus_struture_fixup() \n", __FUNCTION__); - pci_scan_bus (busno, ibmphp_pci_bus->ops, NULL); - break; - } - } - - kfree (dev); - kfree (bus); - - return 0; -} - -static int ibm_configure_device (struct pci_func *func) -{ - unsigned char bus; - struct pci_bus *child; - int num; - int flag = 0; /* this is to make sure we don't double scan the bus, for bridged devices primarily */ - - if (!(bus_structure_fixup (func->busno))) - flag = 1; - if (func->dev == NULL) - func->dev = pci_find_slot (func->busno, PCI_DEVFN(func->device, func->function)); - - if (func->dev == NULL) { - struct pci_bus *bus = ibmphp_find_bus (func->busno); - if (!bus) - return 0; - - num = pci_scan_slot(bus, PCI_DEVFN(func->device, func->function)); - if (num) - pci_bus_add_devices(bus); - - func->dev = pci_find_slot(func->busno, PCI_DEVFN(func->device, func->function)); - if (func->dev == NULL) { - err ("ERROR... : pci_dev still NULL \n"); - return 0; - } - } - if (!(flag) && (func->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)) { - pci_read_config_byte (func->dev, PCI_SECONDARY_BUS, &bus); - child = (struct pci_bus *) pci_add_new_bus (func->dev->bus, (func->dev), bus); - pci_do_scan_bus (child); - } - - return 0; -} - -/******************************************************* - * Returns whether the bus is empty or not - *******************************************************/ -static int is_bus_empty (struct slot * slot_cur) -{ - int rc; - struct slot * tmp_slot; - u8 i = slot_cur->bus_on->slot_min; - - while (i <= slot_cur->bus_on->slot_max) { - if (i == slot_cur->number) { - i++; - continue; - } - tmp_slot = ibmphp_get_slot_from_physical_num (i); - if (!tmp_slot) - return 0; - rc = slot_update (&tmp_slot); - if (rc) - return 0; - if (SLOT_PRESENT (tmp_slot->status) && SLOT_PWRGD (tmp_slot->status)) - return 0; - i++; - } - return 1; -} - -/*********************************************************** - * If the HPC permits and the bus currently empty, tries to set the - * bus speed and mode at the maximum card and bus capability - * Parameters: slot - * Returns: bus is set (0) or error code - ***********************************************************/ -static int set_bus (struct slot * slot_cur) -{ - int rc; - u8 speed; - u8 cmd = 0x0; - const struct list_head *tmp; - struct pci_dev * dev; - int retval; - - debug ("%s - entry slot # %d \n", __FUNCTION__, slot_cur->number); - if (SET_BUS_STATUS (slot_cur->ctrl) && is_bus_empty (slot_cur)) { - rc = slot_update (&slot_cur); - if (rc) - return rc; - speed = SLOT_SPEED (slot_cur->ext_status); - debug ("ext_status = %x, speed = %x\n", slot_cur->ext_status, speed); - switch (speed) { - case HPC_SLOT_SPEED_33: - cmd = HPC_BUS_33CONVMODE; - break; - case HPC_SLOT_SPEED_66: - if (SLOT_PCIX (slot_cur->ext_status)) { - if ((slot_cur->supported_speed >= BUS_SPEED_66) && (slot_cur->supported_bus_mode == BUS_MODE_PCIX)) - cmd = HPC_BUS_66PCIXMODE; - else if (!SLOT_BUS_MODE (slot_cur->ext_status)) - /* if max slot/bus capability is 66 pci - and there's no bus mode mismatch, then - the adapter supports 66 pci */ - cmd = HPC_BUS_66CONVMODE; - else - cmd = HPC_BUS_33CONVMODE; - } else { - if (slot_cur->supported_speed >= BUS_SPEED_66) - cmd = HPC_BUS_66CONVMODE; - else - cmd = HPC_BUS_33CONVMODE; - } - break; - case HPC_SLOT_SPEED_133: - switch (slot_cur->supported_speed) { - case BUS_SPEED_33: - cmd = HPC_BUS_33CONVMODE; - break; - case BUS_SPEED_66: - if (slot_cur->supported_bus_mode == BUS_MODE_PCIX) - cmd = HPC_BUS_66PCIXMODE; - else - cmd = HPC_BUS_66CONVMODE; - break; - case BUS_SPEED_100: - cmd = HPC_BUS_100PCIXMODE; - break; - case BUS_SPEED_133: - /* This is to take care of the bug in CIOBX chip*/ - list_for_each (tmp, &pci_devices) { - dev = (struct pci_dev *) pci_dev_g (tmp); - if (dev) { - if ((dev->vendor == 0x1166) && (dev->device == 0x0101)) - ibmphp_hpc_writeslot (slot_cur, HPC_BUS_100PCIXMODE); - } - } - cmd = HPC_BUS_133PCIXMODE; - break; - default: - err ("Wrong bus speed \n"); - return -ENODEV; - } - break; - default: - err ("wrong slot speed \n"); - return -ENODEV; - } - debug ("setting bus speed for slot %d, cmd %x\n", slot_cur->number, cmd); - retval = ibmphp_hpc_writeslot (slot_cur, cmd); - if (retval) { - err ("setting bus speed failed\n"); - return retval; - } - if (CTLR_RESULT (slot_cur->ctrl->status)) { - err ("command not completed successfully in set_bus \n"); - return -EIO; - } - } - /* This is for x440, once Brandon fixes the firmware, - will not need this delay */ - long_delay (1 * HZ); - debug ("%s -Exit \n", __FUNCTION__); - return 0; -} - -/* This routine checks the bus limitations that the slot is on from the BIOS. - * This is used in deciding whether or not to power up the slot. - * (electrical/spec limitations. For example, >1 133 MHz or >2 66 PCI cards on - * same bus) - * Parameters: slot - * Returns: 0 = no limitations, -EINVAL = exceeded limitations on the bus - */ -static int check_limitations (struct slot *slot_cur) -{ - u8 i; - struct slot * tmp_slot; - u8 count = 0; - u8 limitation = 0; - - for (i = slot_cur->bus_on->slot_min; i <= slot_cur->bus_on->slot_max; i++) { - tmp_slot = ibmphp_get_slot_from_physical_num (i); - if (!tmp_slot) - return -ENODEV; - if ((SLOT_PWRGD (tmp_slot->status)) && !(SLOT_CONNECT (tmp_slot->status))) - count++; - } - get_cur_bus_info (&slot_cur); - switch (slot_cur->bus_on->current_speed) { - case BUS_SPEED_33: - limitation = slot_cur->bus_on->slots_at_33_conv; - break; - case BUS_SPEED_66: - if (slot_cur->bus_on->current_bus_mode == BUS_MODE_PCIX) - limitation = slot_cur->bus_on->slots_at_66_pcix; - else - limitation = slot_cur->bus_on->slots_at_66_conv; - break; - case BUS_SPEED_100: - limitation = slot_cur->bus_on->slots_at_100_pcix; - break; - case BUS_SPEED_133: - limitation = slot_cur->bus_on->slots_at_133_pcix; - break; - } - - if ((count + 1) > limitation) - return -EINVAL; - return 0; -} - -static inline void print_card_capability (struct slot *slot_cur) -{ - info ("capability of the card is "); - if ((slot_cur->ext_status & CARD_INFO) == PCIX133) - info (" 133 MHz PCI-X \n"); - else if ((slot_cur->ext_status & CARD_INFO) == PCIX66) - info (" 66 MHz PCI-X \n"); - else if ((slot_cur->ext_status & CARD_INFO) == PCI66) - info (" 66 MHz PCI \n"); - else - info (" 33 MHz PCI \n"); - -} - -/* This routine will power on the slot, configure the device(s) and find the - * drivers for them. - * Parameters: hotplug_slot - * Returns: 0 or failure codes - */ -static int enable_slot (struct hotplug_slot *hs) -{ - int rc, i, rcpr; - struct slot *slot_cur; - u8 function; - struct pci_func *tmp_func; - - ibmphp_lock_operations (); - - debug ("ENABLING SLOT........ \n"); - slot_cur = (struct slot *) hs->private; - - if ((rc = validate (slot_cur, ENABLE))) { - err ("validate function failed \n"); - goto error_nopower; - } - - attn_LED_blink (slot_cur); - - rc = set_bus (slot_cur); - if (rc) { - err ("was not able to set the bus \n"); - goto error_nopower; - } - - /*-----------------debugging------------------------------*/ - get_cur_bus_info (&slot_cur); - debug ("the current bus speed right after set_bus = %x \n", slot_cur->bus_on->current_speed); - /*----------------------------------------------------------*/ - - rc = check_limitations (slot_cur); - if (rc) { - err ("Adding this card exceeds the limitations of this bus.\n"); - err ("(i.e., >1 133MHz cards running on same bus, or " - ">2 66 PCI cards running on same bus\n."); - err ("Try hot-adding into another bus \n"); - rc = -EINVAL; - goto error_nopower; - } - - rc = power_on (slot_cur); - - if (rc) { - err ("something wrong when powering up... please see below for details\n"); - /* need to turn off before on, otherwise, blinking overwrites */ - attn_off(slot_cur); - attn_on (slot_cur); - if (slot_update (&slot_cur)) { - attn_off (slot_cur); - attn_on (slot_cur); - rc = -ENODEV; - goto exit; - } - /* Check to see the error of why it failed */ - if ((SLOT_POWER (slot_cur->status)) && !(SLOT_PWRGD (slot_cur->status))) - err ("power fault occurred trying to power up \n"); - else if (SLOT_BUS_SPEED (slot_cur->status)) { - err ("bus speed mismatch occurred. please check current bus speed and card capability \n"); - print_card_capability (slot_cur); - } else if (SLOT_BUS_MODE (slot_cur->ext_status)) { - err ("bus mode mismatch occurred. please check current bus mode and card capability \n"); - print_card_capability (slot_cur); - } - ibmphp_update_slot_info (slot_cur); - goto exit; - } - debug ("after power_on\n"); - /*-----------------------debugging---------------------------*/ - get_cur_bus_info (&slot_cur); - debug ("the current bus speed right after power_on = %x \n", slot_cur->bus_on->current_speed); - /*----------------------------------------------------------*/ - - rc = slot_update (&slot_cur); - if (rc) - goto error_power; - - rc = -EINVAL; - if (SLOT_POWER (slot_cur->status) && !(SLOT_PWRGD (slot_cur->status))) { - err ("power fault occurred trying to power up... \n"); - goto error_power; - } - if (SLOT_POWER (slot_cur->status) && (SLOT_BUS_SPEED (slot_cur->status))) { - err ("bus speed mismatch occurred. please check current bus speed and card capability \n"); - print_card_capability (slot_cur); - goto error_power; - } - /* Don't think this case will happen after above checks... but just in case, for paranoia sake */ - if (!(SLOT_POWER (slot_cur->status))) { - err ("power on failed... \n"); - goto error_power; - } - - slot_cur->func = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); - if (!slot_cur->func) { - /* We cannot do update_slot_info here, since no memory for - * kmalloc n.e.ways, and update_slot_info allocates some */ - err ("out of system memory \n"); - rc = -ENOMEM; - goto error_power; - } - memset (slot_cur->func, 0, sizeof (struct pci_func)); - slot_cur->func->busno = slot_cur->bus; - slot_cur->func->device = slot_cur->device; - for (i = 0; i < 4; i++) - slot_cur->func->irq[i] = slot_cur->irq[i]; - - debug ("b4 configure_card, slot_cur->bus = %x, slot_cur->device = %x\n", slot_cur->bus, slot_cur->device); - - if (ibmphp_configure_card (slot_cur->func, slot_cur->number)) { - err ("configure_card was unsuccessful... \n"); - ibmphp_unconfigure_card (&slot_cur, 1); /* true because don't need to actually deallocate resources, just remove references */ - debug ("after unconfigure_card\n"); - slot_cur->func = NULL; - rc = -ENOMEM; - goto error_power; - } - - function = 0x00; - do { - tmp_func = ibm_slot_find (slot_cur->bus, slot_cur->func->device, function++); - if (tmp_func && !(tmp_func->dev)) - ibm_configure_device (tmp_func); - } while (tmp_func); - - attn_off (slot_cur); - if (slot_update (&slot_cur)) { - rc = -EFAULT; - goto exit; - } - ibmphp_print_test (); - rc = ibmphp_update_slot_info (slot_cur); -exit: - ibmphp_unlock_operations(); - return rc; - -error_nopower: - attn_off (slot_cur); /* need to turn off if was blinking b4 */ - attn_on (slot_cur); -error_cont: - rcpr = slot_update (&slot_cur); - if (rcpr) { - rc = rcpr; - goto exit; - } - ibmphp_update_slot_info (slot_cur); - goto exit; - -error_power: - attn_off (slot_cur); /* need to turn off if was blinking b4 */ - attn_on (slot_cur); - rcpr = power_off (slot_cur); - if (rcpr) { - rc = rcpr; - goto exit; - } - goto error_cont; -} - -/************************************************************** -* HOT REMOVING ADAPTER CARD * -* INPUT: POINTER TO THE HOTPLUG SLOT STRUCTURE * -* OUTPUT: SUCCESS 0 ; FAILURE: UNCONFIGURE , VALIDATE * - DISABLE POWER , * -**************************************************************/ -int ibmphp_disable_slot (struct hotplug_slot *hotplug_slot) -{ - struct slot *slot = hotplug_slot->private; - int rc; - - ibmphp_lock_operations(); - rc = ibmphp_do_disable_slot(slot); - ibmphp_unlock_operations(); - return rc; -} - -int ibmphp_do_disable_slot (struct slot *slot_cur) -{ - int rc; - u8 flag; - int parm = 0; - - debug ("DISABLING SLOT... \n"); - - if ((slot_cur == NULL) || (slot_cur->ctrl == NULL)) { - return -ENODEV; - } - - flag = slot_cur->flag; - slot_cur->flag = TRUE; - - if (flag == TRUE) { - rc = validate (slot_cur, DISABLE); /* checking if powered off already & valid slot # */ - if (rc) - goto error; - } - attn_LED_blink (slot_cur); - - if (slot_cur->func == NULL) { - /* We need this for fncs's that were there on bootup */ - slot_cur->func = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); - if (!slot_cur->func) { - err ("out of system memory \n"); - rc = -ENOMEM; - goto error; - } - memset (slot_cur->func, 0, sizeof (struct pci_func)); - slot_cur->func->busno = slot_cur->bus; - slot_cur->func->device = slot_cur->device; - } - - if ((rc = ibm_unconfigure_device (slot_cur->func))) { - err ("removing from kernel failed... \n"); - err ("Please check to see if it was statically linked or is " - "in use otherwise. (perhaps the driver is not 'hot-removable')\n"); - goto error; - } - - /* If we got here from latch suddenly opening on operating card or - a power fault, there's no power to the card, so cannot - read from it to determine what resources it occupied. This operation - is forbidden anyhow. The best we can do is remove it from kernel - lists at least */ - - if (!flag) { - attn_off (slot_cur); - return 0; - } - - rc = ibmphp_unconfigure_card (&slot_cur, parm); - slot_cur->func = NULL; - debug ("in disable_slot. after unconfigure_card\n"); - if (rc) { - err ("could not unconfigure card.\n"); - goto error; - } - - rc = ibmphp_hpc_writeslot (slot_cur, HPC_SLOT_OFF); - if (rc) - goto error; - - attn_off (slot_cur); - rc = slot_update (&slot_cur); - if (rc) - goto exit; - - rc = ibmphp_update_slot_info (slot_cur); - ibmphp_print_test (); -exit: - return rc; - -error: - /* Need to turn off if was blinking b4 */ - attn_off (slot_cur); - attn_on (slot_cur); - if (slot_update (&slot_cur)) { - rc = -EFAULT; - goto exit; - } - if (flag) - ibmphp_update_slot_info (slot_cur); - goto exit; -} - -struct hotplug_slot_ops ibmphp_hotplug_slot_ops = { - .owner = THIS_MODULE, - .set_attention_status = set_attention_status, - .enable_slot = enable_slot, - .disable_slot = ibmphp_disable_slot, - .hardware_test = NULL, - .get_power_status = get_power_status, - .get_attention_status = get_attention_status, - .get_latch_status = get_latch_status, - .get_adapter_status = get_adapter_present, - .get_max_bus_speed = get_max_bus_speed, - .get_cur_bus_speed = get_cur_bus_speed, -/* .get_max_adapter_speed = get_max_adapter_speed, - .get_bus_name_status = get_bus_name, -*/ -}; - -static void ibmphp_unload (void) -{ - free_slots (); - debug ("after slots \n"); - ibmphp_free_resources (); - debug ("after resources \n"); - ibmphp_free_bus_info_queue (); - debug ("after bus info \n"); - ibmphp_free_ebda_hpc_queue (); - debug ("after ebda hpc \n"); - ibmphp_free_ebda_pci_rsrc_queue (); - debug ("after ebda pci rsrc \n"); - kfree (ibmphp_pci_bus); -} - -static int __init ibmphp_init (void) -{ - struct pci_bus *bus; - int i = 0; - int rc = 0; - - init_flag = 1; - - info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); - - ibmphp_pci_bus = kmalloc (sizeof (*ibmphp_pci_bus), GFP_KERNEL); - if (!ibmphp_pci_bus) { - err ("out of memory\n"); - rc = -ENOMEM; - goto exit; - } - - bus = ibmphp_find_bus (0); - if (!bus) { - err ("Can't find the root pci bus, can not continue\n"); - rc = -ENODEV; - goto error; - } - memcpy (ibmphp_pci_bus, bus, sizeof (*ibmphp_pci_bus)); - - ibmphp_debug = debug; - - ibmphp_hpc_initvars (); - - for (i = 0; i < 16; i++) - irqs[i] = 0; - - if ((rc = ibmphp_access_ebda ())) - goto error; - debug ("after ibmphp_access_ebda ()\n"); - - if ((rc = ibmphp_rsrc_init ())) - goto error; - debug ("AFTER Resource & EBDA INITIALIZATIONS\n"); - - max_slots = get_max_slots (); - - if ((rc = ibmphp_register_pci ())) - goto error; - - if (init_ops ()) { - rc = -ENODEV; - goto error; - } - - ibmphp_print_test (); - if ((rc = ibmphp_hpc_start_poll_thread ())) { - goto error; - } - - /* lock ourselves into memory with a module - * count of -1 so that no one can unload us. */ - module_put(THIS_MODULE); - -exit: - return rc; - -error: - ibmphp_unload (); - goto exit; -} - -static void __exit ibmphp_exit (void) -{ - ibmphp_hpc_stop_poll_thread (); - debug ("after polling\n"); - ibmphp_unload (); - debug ("done\n"); -} - -module_init (ibmphp_init); -module_exit (ibmphp_exit); diff -Nru a/drivers/hotplug/ibmphp_ebda.c b/drivers/hotplug/ibmphp_ebda.c --- a/drivers/hotplug/ibmphp_ebda.c Mon Jun 9 23:16:08 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,1228 +0,0 @@ -/* - * IBM Hot Plug Controller Driver - * - * Written By: Tong Yu, IBM Corporation - * - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001,2002 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or - * NON INFRINGEMENT. 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. - * - * Send feedback to <gregkh@us.ibm.com> - * - */ - -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/errno.h> -#include <linux/mm.h> -#include <linux/slab.h> -#include <linux/pci.h> -#include <linux/list.h> -#include <linux/init.h> -#include "ibmphp.h" - -/* - * POST builds data blocks(in this data block definition, a char-1 - * byte, short(or word)-2 byte, long(dword)-4 byte) in the Extended - * BIOS Data Area which describe the configuration of the hot-plug - * controllers and resources used by the PCI Hot-Plug devices. - * - * This file walks EBDA, maps data block from physical addr, - * reconstruct linked lists about all system resource(MEM, PFM, IO) - * already assigned by POST, as well as linked lists about hot plug - * controllers (ctlr#, slot#, bus&slot features...) - */ - -/* Global lists */ -LIST_HEAD (ibmphp_ebda_pci_rsrc_head); -LIST_HEAD (ibmphp_slot_head); - -/* Local variables */ -static struct ebda_hpc_list *hpc_list_ptr; -static struct ebda_rsrc_list *rsrc_list_ptr; -static struct rio_table_hdr *rio_table_ptr = NULL; -static LIST_HEAD (ebda_hpc_head); -static LIST_HEAD (bus_info_head); -static LIST_HEAD (rio_vg_head); -static LIST_HEAD (rio_lo_head); -static LIST_HEAD (opt_vg_head); -static LIST_HEAD (opt_lo_head); -static void *io_mem; - -/* Local functions */ -static int ebda_rsrc_controller (void); -static int ebda_rsrc_rsrc (void); -static int ebda_rio_table (void); - -static struct ebda_hpc_list * __init alloc_ebda_hpc_list (void) -{ - struct ebda_hpc_list *list; - - list = kmalloc (sizeof (struct ebda_hpc_list), GFP_KERNEL); - if (!list) - return NULL; - memset (list, 0, sizeof (*list)); - return list; -} - -static struct controller *alloc_ebda_hpc (u32 slot_count, u32 bus_count) -{ - struct controller *controller; - struct ebda_hpc_slot *slots; - struct ebda_hpc_bus *buses; - - controller = kmalloc (sizeof (struct controller), GFP_KERNEL); - if (!controller) - return NULL; - memset (controller, 0, sizeof (*controller)); - - slots = kmalloc (sizeof (struct ebda_hpc_slot) * slot_count, GFP_KERNEL); - if (!slots) { - kfree (controller); - return NULL; - } - memset (slots, 0, sizeof (*slots) * slot_count); - controller->slots = slots; - - buses = kmalloc (sizeof (struct ebda_hpc_bus) * bus_count, GFP_KERNEL); - if (!buses) { - kfree (controller->slots); - kfree (controller); - return NULL; - } - memset (buses, 0, sizeof (*buses) * bus_count); - controller->buses = buses; - - return controller; -} - -static void free_ebda_hpc (struct controller *controller) -{ - kfree (controller->slots); - controller->slots = NULL; - kfree (controller->buses); - controller->buses = NULL; - controller->ctrl_dev = NULL; - kfree (controller); -} - -static struct ebda_rsrc_list * __init alloc_ebda_rsrc_list (void) -{ - struct ebda_rsrc_list *list; - - list = kmalloc (sizeof (struct ebda_rsrc_list), GFP_KERNEL); - if (!list) - return NULL; - memset (list, 0, sizeof (*list)); - return list; -} - -static struct ebda_pci_rsrc *alloc_ebda_pci_rsrc (void) -{ - struct ebda_pci_rsrc *resource; - - resource = kmalloc (sizeof (struct ebda_pci_rsrc), GFP_KERNEL); - if (!resource) - return NULL; - memset (resource, 0, sizeof (*resource)); - return resource; -} - -static void __init print_bus_info (void) -{ - struct bus_info *ptr; - struct list_head *ptr1; - - list_for_each (ptr1, &bus_info_head) { - ptr = list_entry (ptr1, struct bus_info, bus_info_list); - debug ("%s - slot_min = %x\n", __FUNCTION__, ptr->slot_min); - debug ("%s - slot_max = %x\n", __FUNCTION__, ptr->slot_max); - debug ("%s - slot_count = %x\n", __FUNCTION__, ptr->slot_count); - debug ("%s - bus# = %x\n", __FUNCTION__, ptr->busno); - debug ("%s - current_speed = %x\n", __FUNCTION__, ptr->current_speed); - debug ("%s - controller_id = %x\n", __FUNCTION__, ptr->controller_id); - - debug ("%s - slots_at_33_conv = %x\n", __FUNCTION__, ptr->slots_at_33_conv); - debug ("%s - slots_at_66_conv = %x\n", __FUNCTION__, ptr->slots_at_66_conv); - debug ("%s - slots_at_66_pcix = %x\n", __FUNCTION__, ptr->slots_at_66_pcix); - debug ("%s - slots_at_100_pcix = %x\n", __FUNCTION__, ptr->slots_at_100_pcix); - debug ("%s - slots_at_133_pcix = %x\n", __FUNCTION__, ptr->slots_at_133_pcix); - - } -} - -static void print_lo_info (void) -{ - struct rio_detail *ptr; - struct list_head *ptr1; - debug ("print_lo_info ---- \n"); - list_for_each (ptr1, &rio_lo_head) { - ptr = list_entry (ptr1, struct rio_detail, rio_detail_list); - debug ("%s - rio_node_id = %x\n", __FUNCTION__, ptr->rio_node_id); - debug ("%s - rio_type = %x\n", __FUNCTION__, ptr->rio_type); - debug ("%s - owner_id = %x\n", __FUNCTION__, ptr->owner_id); - debug ("%s - first_slot_num = %x\n", __FUNCTION__, ptr->first_slot_num); - debug ("%s - wpindex = %x\n", __FUNCTION__, ptr->wpindex); - debug ("%s - chassis_num = %x\n", __FUNCTION__, ptr->chassis_num); - - } -} - -static void print_vg_info (void) -{ - struct rio_detail *ptr; - struct list_head *ptr1; - debug ("%s --- \n", __FUNCTION__); - list_for_each (ptr1, &rio_vg_head) { - ptr = list_entry (ptr1, struct rio_detail, rio_detail_list); - debug ("%s - rio_node_id = %x\n", __FUNCTION__, ptr->rio_node_id); - debug ("%s - rio_type = %x\n", __FUNCTION__, ptr->rio_type); - debug ("%s - owner_id = %x\n", __FUNCTION__, ptr->owner_id); - debug ("%s - first_slot_num = %x\n", __FUNCTION__, ptr->first_slot_num); - debug ("%s - wpindex = %x\n", __FUNCTION__, ptr->wpindex); - debug ("%s - chassis_num = %x\n", __FUNCTION__, ptr->chassis_num); - - } -} - -static void __init print_ebda_pci_rsrc (void) -{ - struct ebda_pci_rsrc *ptr; - struct list_head *ptr1; - - list_for_each (ptr1, &ibmphp_ebda_pci_rsrc_head) { - ptr = list_entry (ptr1, struct ebda_pci_rsrc, ebda_pci_rsrc_list); - debug ("%s - rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n", - __FUNCTION__, ptr->rsrc_type ,ptr->bus_num, ptr->dev_fun,ptr->start_addr, ptr->end_addr); - } -} - -static void __init print_ibm_slot (void) -{ - struct slot *ptr; - struct list_head *ptr1; - - list_for_each (ptr1, &ibmphp_slot_head) { - ptr = list_entry (ptr1, struct slot, ibm_slot_list); - debug ("%s - slot_number: %x \n", __FUNCTION__, ptr->number); - } -} - -static void __init print_opt_vg (void) -{ - struct opt_rio *ptr; - struct list_head *ptr1; - debug ("%s --- \n", __FUNCTION__); - list_for_each (ptr1, &opt_vg_head) { - ptr = list_entry (ptr1, struct opt_rio, opt_rio_list); - debug ("%s - rio_type %x \n", __FUNCTION__, ptr->rio_type); - debug ("%s - chassis_num: %x \n", __FUNCTION__, ptr->chassis_num); - debug ("%s - first_slot_num: %x \n", __FUNCTION__, ptr->first_slot_num); - debug ("%s - middle_num: %x \n", __FUNCTION__, ptr->middle_num); - } -} - -static void __init print_ebda_hpc (void) -{ - struct controller *hpc_ptr; - struct list_head *ptr1; - u16 index; - - list_for_each (ptr1, &ebda_hpc_head) { - - hpc_ptr = list_entry (ptr1, struct controller, ebda_hpc_list); - - for (index = 0; index < hpc_ptr->slot_count; index++) { - debug ("%s - physical slot#: %x\n", __FUNCTION__, hpc_ptr->slots[index].slot_num); - debug ("%s - pci bus# of the slot: %x\n", __FUNCTION__, hpc_ptr->slots[index].slot_bus_num); - debug ("%s - index into ctlr addr: %x\n", __FUNCTION__, hpc_ptr->slots[index].ctl_index); - debug ("%s - cap of the slot: %x\n", __FUNCTION__, hpc_ptr->slots[index].slot_cap); - } - - for (index = 0; index < hpc_ptr->bus_count; index++) { - debug ("%s - bus# of each bus controlled by this ctlr: %x\n", __FUNCTION__, hpc_ptr->buses[index].bus_num); - } - - debug ("%s - type of hpc: %x\n", __FUNCTION__, hpc_ptr->ctlr_type); - switch (hpc_ptr->ctlr_type) { - case 1: - debug ("%s - bus: %x\n", __FUNCTION__, hpc_ptr->u.pci_ctlr.bus); - debug ("%s - dev_fun: %x\n", __FUNCTION__, hpc_ptr->u.pci_ctlr.dev_fun); - debug ("%s - irq: %x\n", __FUNCTION__, hpc_ptr->irq); - break; - - case 0: - debug ("%s - io_start: %x\n", __FUNCTION__, hpc_ptr->u.isa_ctlr.io_start); - debug ("%s - io_end: %x\n", __FUNCTION__, hpc_ptr->u.isa_ctlr.io_end); - debug ("%s - irq: %x\n", __FUNCTION__, hpc_ptr->irq); - break; - - case 2: - case 4: - debug ("%s - wpegbbar: %lx\n", __FUNCTION__, hpc_ptr->u.wpeg_ctlr.wpegbbar); - debug ("%s - i2c_addr: %x\n", __FUNCTION__, hpc_ptr->u.wpeg_ctlr.i2c_addr); - debug ("%s - irq: %x\n", __FUNCTION__, hpc_ptr->irq); - break; - } - } -} - -int __init ibmphp_access_ebda (void) -{ - u8 format, num_ctlrs, rio_complete, hs_complete; - u16 ebda_seg, num_entries, next_offset, offset, blk_id, sub_addr, rc, re, rc_id, re_id, base; - - - rio_complete = 0; - hs_complete = 0; - - io_mem = ioremap ((0x40 << 4) + 0x0e, 2); - if (!io_mem ) - return -ENOMEM; - ebda_seg = readw (io_mem); - iounmap (io_mem); - debug ("returned ebda segment: %x\n", ebda_seg); - - io_mem = ioremap (ebda_seg<<4, 65000); - if (!io_mem ) - return -ENOMEM; - next_offset = 0x180; - - for (;;) { - offset = next_offset; - next_offset = readw (io_mem + offset); /* offset of next blk */ - - offset += 2; - if (next_offset == 0) /* 0 indicate it's last blk */ - break; - blk_id = readw (io_mem + offset); /* this blk id */ - - offset += 2; - /* check if it is hot swap block or rio block */ - if (blk_id != 0x4853 && blk_id != 0x4752) - continue; - /* found hs table */ - if (blk_id == 0x4853) { - debug ("now enter hot swap block---\n"); - debug ("hot blk id: %x\n", blk_id); - format = readb (io_mem + offset); - - offset += 1; - if (format != 4) { - iounmap (io_mem); - return -ENODEV; - } - debug ("hot blk format: %x\n", format); - /* hot swap sub blk */ - base = offset; - - sub_addr = base; - re = readw (io_mem + sub_addr); /* next sub blk */ - - sub_addr += 2; - rc_id = readw (io_mem + sub_addr); /* sub blk id */ - - sub_addr += 2; - if (rc_id != 0x5243) { - iounmap (io_mem); - return -ENODEV; - } - /* rc sub blk signature */ - num_ctlrs = readb (io_mem + sub_addr); - - sub_addr += 1; - hpc_list_ptr = alloc_ebda_hpc_list (); - if (!hpc_list_ptr) { - iounmap (io_mem); - return -ENOMEM; - } - hpc_list_ptr->format = format; - hpc_list_ptr->num_ctlrs = num_ctlrs; - hpc_list_ptr->phys_addr = sub_addr; /* offset of RSRC_CONTROLLER blk */ - debug ("info about hpc descriptor---\n"); - debug ("hot blk format: %x\n", format); - debug ("num of controller: %x\n", num_ctlrs); - debug ("offset of hpc data structure enteries: %x\n ", sub_addr); - - sub_addr = base + re; /* re sub blk */ - rc = readw (io_mem + sub_addr); /* next sub blk */ - - sub_addr += 2; - re_id = readw (io_mem + sub_addr); /* sub blk id */ - - sub_addr += 2; - if (re_id != 0x5245) { - iounmap (io_mem); - return -ENODEV; - } - - /* signature of re */ - num_entries = readw (io_mem + sub_addr); - - sub_addr += 2; /* offset of RSRC_ENTRIES blk */ - rsrc_list_ptr = alloc_ebda_rsrc_list (); - if (!rsrc_list_ptr ) { - iounmap (io_mem); - return -ENOMEM; - } - rsrc_list_ptr->format = format; - rsrc_list_ptr->num_entries = num_entries; - rsrc_list_ptr->phys_addr = sub_addr; - - debug ("info about rsrc descriptor---\n"); - debug ("format: %x\n", format); - debug ("num of rsrc: %x\n", num_entries); - debug ("offset of rsrc data structure enteries: %x\n ", sub_addr); - - hs_complete = 1; - } - /* found rio table */ - else if (blk_id == 0x4752) { - debug ("now enter io table ---\n"); - debug ("rio blk id: %x\n", blk_id); - - rio_table_ptr = kmalloc (sizeof (struct rio_table_hdr), GFP_KERNEL); - if (!rio_table_ptr) - return -ENOMEM; - memset (rio_table_ptr, 0, sizeof (struct rio_table_hdr) ); - rio_table_ptr->ver_num = readb (io_mem + offset); - rio_table_ptr->scal_count = readb (io_mem + offset + 1); - rio_table_ptr->riodev_count = readb (io_mem + offset + 2); - rio_table_ptr->offset = offset +3 ; - - debug ("info about rio table hdr ---\n"); - debug ("ver_num: %x\nscal_count: %x\nriodev_count: %x\noffset of rio table: %x\n ", rio_table_ptr->ver_num, rio_table_ptr->scal_count, rio_table_ptr->riodev_count, rio_table_ptr->offset); - - rio_complete = 1; - } - } - - if (!hs_complete && !rio_complete) { - iounmap (io_mem); - return -ENODEV; - } - - if (rio_table_ptr) { - if (rio_complete == 1 && rio_table_ptr->ver_num == 3) { - rc = ebda_rio_table (); - if (rc) { - iounmap (io_mem); - return rc; - } - } - } - rc = ebda_rsrc_controller (); - if (rc) { - iounmap (io_mem); - return rc; - } - - rc = ebda_rsrc_rsrc (); - if (rc) { - iounmap (io_mem); - return rc; - } - - iounmap (io_mem); - return 0; -} - -/* - * map info of scalability details and rio details from physical address - */ -static int __init ebda_rio_table (void) -{ - u16 offset; - u8 i; - struct rio_detail *rio_detail_ptr; - - offset = rio_table_ptr->offset; - offset += 12 * rio_table_ptr->scal_count; - - // we do concern about rio details - for (i = 0; i < rio_table_ptr->riodev_count; i++) { - rio_detail_ptr = kmalloc (sizeof (struct rio_detail), GFP_KERNEL); - if (!rio_detail_ptr) - return -ENOMEM; - memset (rio_detail_ptr, 0, sizeof (struct rio_detail)); - rio_detail_ptr->rio_node_id = readb (io_mem + offset); - rio_detail_ptr->bbar = readl (io_mem + offset + 1); - rio_detail_ptr->rio_type = readb (io_mem + offset + 5); - rio_detail_ptr->owner_id = readb (io_mem + offset + 6); - rio_detail_ptr->port0_node_connect = readb (io_mem + offset + 7); - rio_detail_ptr->port0_port_connect = readb (io_mem + offset + 8); - rio_detail_ptr->port1_node_connect = readb (io_mem + offset + 9); - rio_detail_ptr->port1_port_connect = readb (io_mem + offset + 10); - rio_detail_ptr->first_slot_num = readb (io_mem + offset + 11); - rio_detail_ptr->status = readb (io_mem + offset + 12); - rio_detail_ptr->wpindex = readb (io_mem + offset + 13); - rio_detail_ptr->chassis_num = readb (io_mem + offset + 14); -// debug ("rio_node_id: %x\nbbar: %x\nrio_type: %x\nowner_id: %x\nport0_node: %x\nport0_port: %x\nport1_node: %x\nport1_port: %x\nfirst_slot_num: %x\nstatus: %x\n", rio_detail_ptr->rio_node_id, rio_detail_ptr->bbar, rio_detail_ptr->rio_type, rio_detail_ptr->owner_id, rio_detail_ptr->port0_node_connect, rio_detail_ptr->port0_port_connect, rio_detail_ptr->port1_node_connect, rio_detail_ptr->port1_port_connect, rio_detail_ptr->first_slot_num, rio_detail_ptr->status); - //create linked list of chassis - if (rio_detail_ptr->rio_type == 4 || rio_detail_ptr->rio_type == 5) - list_add (&rio_detail_ptr->rio_detail_list, &rio_vg_head); - //create linked list of expansion box - else if (rio_detail_ptr->rio_type == 6 || rio_detail_ptr->rio_type == 7) - list_add (&rio_detail_ptr->rio_detail_list, &rio_lo_head); - else - // not in my concern - kfree (rio_detail_ptr); - offset += 15; - } - print_lo_info (); - print_vg_info (); - return 0; -} - -/* - * reorganizing linked list of chassis - */ -static struct opt_rio *search_opt_vg (u8 chassis_num) -{ - struct opt_rio *ptr; - struct list_head *ptr1; - list_for_each (ptr1, &opt_vg_head) { - ptr = list_entry (ptr1, struct opt_rio, opt_rio_list); - if (ptr->chassis_num == chassis_num) - return ptr; - } - return NULL; -} - -static int __init combine_wpg_for_chassis (void) -{ - struct opt_rio *opt_rio_ptr = NULL; - struct rio_detail *rio_detail_ptr = NULL; - struct list_head *list_head_ptr = NULL; - - list_for_each (list_head_ptr, &rio_vg_head) { - rio_detail_ptr = list_entry (list_head_ptr, struct rio_detail, rio_detail_list); - opt_rio_ptr = search_opt_vg (rio_detail_ptr->chassis_num); - if (!opt_rio_ptr) { - opt_rio_ptr = (struct opt_rio *) kmalloc (sizeof (struct opt_rio), GFP_KERNEL); - if (!opt_rio_ptr) - return -ENOMEM; - memset (opt_rio_ptr, 0, sizeof (struct opt_rio)); - opt_rio_ptr->rio_type = rio_detail_ptr->rio_type; - opt_rio_ptr->chassis_num = rio_detail_ptr->chassis_num; - opt_rio_ptr->first_slot_num = rio_detail_ptr->first_slot_num; - opt_rio_ptr->middle_num = rio_detail_ptr->first_slot_num; - list_add (&opt_rio_ptr->opt_rio_list, &opt_vg_head); - } else { - opt_rio_ptr->first_slot_num = min (opt_rio_ptr->first_slot_num, rio_detail_ptr->first_slot_num); - opt_rio_ptr->middle_num = max (opt_rio_ptr->middle_num, rio_detail_ptr->first_slot_num); - } - } - print_opt_vg (); - return 0; -} - -/* - * reorgnizing linked list of expansion box - */ -static struct opt_rio_lo *search_opt_lo (u8 chassis_num) -{ - struct opt_rio_lo *ptr; - struct list_head *ptr1; - list_for_each (ptr1, &opt_lo_head) { - ptr = list_entry (ptr1, struct opt_rio_lo, opt_rio_lo_list); - if (ptr->chassis_num == chassis_num) - return ptr; - } - return NULL; -} - -static int combine_wpg_for_expansion (void) -{ - struct opt_rio_lo *opt_rio_lo_ptr = NULL; - struct rio_detail *rio_detail_ptr = NULL; - struct list_head *list_head_ptr = NULL; - - list_for_each (list_head_ptr, &rio_lo_head) { - rio_detail_ptr = list_entry (list_head_ptr, struct rio_detail, rio_detail_list); - opt_rio_lo_ptr = search_opt_lo (rio_detail_ptr->chassis_num); - if (!opt_rio_lo_ptr) { - opt_rio_lo_ptr = (struct opt_rio_lo *) kmalloc (sizeof (struct opt_rio_lo), GFP_KERNEL); - if (!opt_rio_lo_ptr) - return -ENOMEM; - memset (opt_rio_lo_ptr, 0, sizeof (struct opt_rio_lo)); - opt_rio_lo_ptr->rio_type = rio_detail_ptr->rio_type; - opt_rio_lo_ptr->chassis_num = rio_detail_ptr->chassis_num; - opt_rio_lo_ptr->first_slot_num = rio_detail_ptr->first_slot_num; - opt_rio_lo_ptr->middle_num = rio_detail_ptr->first_slot_num; - opt_rio_lo_ptr->pack_count = 1; - - list_add (&opt_rio_lo_ptr->opt_rio_lo_list, &opt_lo_head); - } else { - opt_rio_lo_ptr->first_slot_num = min (opt_rio_lo_ptr->first_slot_num, rio_detail_ptr->first_slot_num); - opt_rio_lo_ptr->middle_num = max (opt_rio_lo_ptr->middle_num, rio_detail_ptr->first_slot_num); - opt_rio_lo_ptr->pack_count = 2; - } - } - return 0; -} - - -/* Since we don't know the max slot number per each chassis, hence go - * through the list of all chassis to find out the range - * Arguments: slot_num, 1st slot number of the chassis we think we are on, - * var (0 = chassis, 1 = expansion box) - */ -static int first_slot_num (u8 slot_num, u8 first_slot, u8 var) -{ - struct opt_rio *opt_vg_ptr = NULL; - struct opt_rio_lo *opt_lo_ptr = NULL; - struct list_head *ptr = NULL; - int rc = 0; - - if (!var) { - list_for_each (ptr, &opt_vg_head) { - opt_vg_ptr = list_entry (ptr, struct opt_rio, opt_rio_list); - if ((first_slot < opt_vg_ptr->first_slot_num) && (slot_num >= opt_vg_ptr->first_slot_num)) { - rc = -ENODEV; - break; - } - } - } else { - list_for_each (ptr, &opt_lo_head) { - opt_lo_ptr = list_entry (ptr, struct opt_rio_lo, opt_rio_lo_list); - if ((first_slot < opt_lo_ptr->first_slot_num) && (slot_num >= opt_lo_ptr->first_slot_num)) { - rc = -ENODEV; - break; - } - } - } - return rc; -} - -static struct opt_rio_lo * find_rxe_num (u8 slot_num) -{ - struct opt_rio_lo *opt_lo_ptr; - struct list_head *ptr; - - list_for_each (ptr, &opt_lo_head) { - opt_lo_ptr = list_entry (ptr, struct opt_rio_lo, opt_rio_lo_list); - //check to see if this slot_num belongs to expansion box - if ((slot_num >= opt_lo_ptr->first_slot_num) && (!first_slot_num (slot_num, opt_lo_ptr->first_slot_num, 1))) - return opt_lo_ptr; - } - return NULL; -} - -static struct opt_rio * find_chassis_num (u8 slot_num) -{ - struct opt_rio *opt_vg_ptr; - struct list_head *ptr; - - list_for_each (ptr, &opt_vg_head) { - opt_vg_ptr = list_entry (ptr, struct opt_rio, opt_rio_list); - //check to see if this slot_num belongs to chassis - if ((slot_num >= opt_vg_ptr->first_slot_num) && (!first_slot_num (slot_num, opt_vg_ptr->first_slot_num, 0))) - return opt_vg_ptr; - } - return NULL; -} - -/* This routine will find out how many slots are in the chassis, so that - * the slot numbers for rxe100 would start from 1, and not from 7, or 6 etc - */ -static u8 calculate_first_slot (u8 slot_num) -{ - u8 first_slot = 1; - struct list_head * list; - struct slot * slot_cur; - - list_for_each (list, &ibmphp_slot_head) { - slot_cur = list_entry (list, struct slot, ibm_slot_list); - if (slot_cur->ctrl) { - if ((slot_cur->ctrl->ctlr_type != 4) && (slot_cur->ctrl->ending_slot_num > first_slot) && (slot_num > slot_cur->ctrl->ending_slot_num)) - first_slot = slot_cur->ctrl->ending_slot_num; - } - } - return first_slot + 1; - -} -static char *create_file_name (struct slot * slot_cur) -{ - struct opt_rio *opt_vg_ptr = NULL; - struct opt_rio_lo *opt_lo_ptr = NULL; - static char str[30]; - int which = 0; /* rxe = 1, chassis = 0 */ - u8 number = 1; /* either chassis or rxe # */ - u8 first_slot = 1; - u8 slot_num; - u8 flag = 0; - - if (!slot_cur) { - err ("Structure passed is empty \n"); - return NULL; - } - - slot_num = slot_cur->number; - - memset (str, 0, sizeof(str)); - - if (rio_table_ptr) { - if (rio_table_ptr->ver_num == 3) { - opt_vg_ptr = find_chassis_num (slot_num); - opt_lo_ptr = find_rxe_num (slot_num); - } - } - if (opt_vg_ptr) { - if (opt_lo_ptr) { - if ((slot_num - opt_vg_ptr->first_slot_num) > (slot_num - opt_lo_ptr->first_slot_num)) { - number = opt_lo_ptr->chassis_num; - first_slot = opt_lo_ptr->first_slot_num; - which = 1; /* it is RXE */ - } else { - first_slot = opt_vg_ptr->first_slot_num; - number = opt_vg_ptr->chassis_num; - which = 0; - } - } else { - first_slot = opt_vg_ptr->first_slot_num; - number = opt_vg_ptr->chassis_num; - which = 0; - } - ++flag; - } else if (opt_lo_ptr) { - number = opt_lo_ptr->chassis_num; - first_slot = opt_lo_ptr->first_slot_num; - which = 1; - ++flag; - } else if (rio_table_ptr) { - if (rio_table_ptr->ver_num == 3) { - /* if both NULL and we DO have correct RIO table in BIOS */ - return NULL; - } - } - if (!flag) { - if (slot_cur->ctrl->ctlr_type == 4) { - first_slot = calculate_first_slot (slot_num); - which = 1; - } else { - which = 0; - } - } - - sprintf(str, "%s%dslot%d", - which == 0 ? "chassis" : "rxe", - number, slot_num - first_slot + 1); - return str; -} - -static struct pci_driver ibmphp_driver; - -/* - * map info (ctlr-id, slot count, slot#.. bus count, bus#, ctlr type...) of - * each hpc from physical address to a list of hot plug controllers based on - * hpc descriptors. - */ -static int __init ebda_rsrc_controller (void) -{ - u16 addr, addr_slot, addr_bus; - u8 ctlr_id, temp, bus_index; - u16 ctlr, slot, bus; - u16 slot_num, bus_num, index; - struct hotplug_slot *hp_slot_ptr; - struct controller *hpc_ptr; - struct ebda_hpc_bus *bus_ptr; - struct ebda_hpc_slot *slot_ptr; - struct bus_info *bus_info_ptr1, *bus_info_ptr2; - int rc; - struct slot *tmp_slot; - struct list_head *list; - - addr = hpc_list_ptr->phys_addr; - for (ctlr = 0; ctlr < hpc_list_ptr->num_ctlrs; ctlr++) { - bus_index = 1; - ctlr_id = readb (io_mem + addr); - addr += 1; - slot_num = readb (io_mem + addr); - - addr += 1; - addr_slot = addr; /* offset of slot structure */ - addr += (slot_num * 4); - - bus_num = readb (io_mem + addr); - - addr += 1; - addr_bus = addr; /* offset of bus */ - addr += (bus_num * 9); /* offset of ctlr_type */ - temp = readb (io_mem + addr); - - addr += 1; - /* init hpc structure */ - hpc_ptr = alloc_ebda_hpc (slot_num, bus_num); - if (!hpc_ptr ) { - rc = -ENOMEM; - goto error_no_hpc; - } - hpc_ptr->ctlr_id = ctlr_id; - hpc_ptr->ctlr_relative_id = ctlr; - hpc_ptr->slot_count = slot_num; - hpc_ptr->bus_count = bus_num; - debug ("now enter ctlr data struture ---\n"); - debug ("ctlr id: %x\n", ctlr_id); - debug ("ctlr_relative_id: %x\n", hpc_ptr->ctlr_relative_id); - debug ("count of slots controlled by this ctlr: %x\n", slot_num); - debug ("count of buses controlled by this ctlr: %x\n", bus_num); - - /* init slot structure, fetch slot, bus, cap... */ - slot_ptr = hpc_ptr->slots; - for (slot = 0; slot < slot_num; slot++) { - slot_ptr->slot_num = readb (io_mem + addr_slot); - slot_ptr->slot_bus_num = readb (io_mem + addr_slot + slot_num); - slot_ptr->ctl_index = readb (io_mem + addr_slot + 2*slot_num); - slot_ptr->slot_cap = readb (io_mem + addr_slot + 3*slot_num); - - // create bus_info lined list --- if only one slot per bus: slot_min = slot_max - - bus_info_ptr2 = ibmphp_find_same_bus_num (slot_ptr->slot_bus_num); - if (!bus_info_ptr2) { - bus_info_ptr1 = (struct bus_info *) kmalloc (sizeof (struct bus_info), GFP_KERNEL); - if (!bus_info_ptr1) { - rc = -ENOMEM; - goto error_no_hp_slot; - } - memset (bus_info_ptr1, 0, sizeof (struct bus_info)); - bus_info_ptr1->slot_min = slot_ptr->slot_num; - bus_info_ptr1->slot_max = slot_ptr->slot_num; - bus_info_ptr1->slot_count += 1; - bus_info_ptr1->busno = slot_ptr->slot_bus_num; - bus_info_ptr1->index = bus_index++; - bus_info_ptr1->current_speed = 0xff; - bus_info_ptr1->current_bus_mode = 0xff; - - bus_info_ptr1->controller_id = hpc_ptr->ctlr_id; - - list_add_tail (&bus_info_ptr1->bus_info_list, &bus_info_head); - - } else { - bus_info_ptr2->slot_min = min (bus_info_ptr2->slot_min, slot_ptr->slot_num); - bus_info_ptr2->slot_max = max (bus_info_ptr2->slot_max, slot_ptr->slot_num); - bus_info_ptr2->slot_count += 1; - - } - - // end of creating the bus_info linked list - - slot_ptr++; - addr_slot += 1; - } - - /* init bus structure */ - bus_ptr = hpc_ptr->buses; - for (bus = 0; bus < bus_num; bus++) { - bus_ptr->bus_num = readb (io_mem + addr_bus + bus); - bus_ptr->slots_at_33_conv = readb (io_mem + addr_bus + bus_num + 8 * bus); - bus_ptr->slots_at_66_conv = readb (io_mem + addr_bus + bus_num + 8 * bus + 1); - - bus_ptr->slots_at_66_pcix = readb (io_mem + addr_bus + bus_num + 8 * bus + 2); - - bus_ptr->slots_at_100_pcix = readb (io_mem + addr_bus + bus_num + 8 * bus + 3); - - bus_ptr->slots_at_133_pcix = readb (io_mem + addr_bus + bus_num + 8 * bus + 4); - - bus_info_ptr2 = ibmphp_find_same_bus_num (bus_ptr->bus_num); - if (bus_info_ptr2) { - bus_info_ptr2->slots_at_33_conv = bus_ptr->slots_at_33_conv; - bus_info_ptr2->slots_at_66_conv = bus_ptr->slots_at_66_conv; - bus_info_ptr2->slots_at_66_pcix = bus_ptr->slots_at_66_pcix; - bus_info_ptr2->slots_at_100_pcix = bus_ptr->slots_at_100_pcix; - bus_info_ptr2->slots_at_133_pcix = bus_ptr->slots_at_133_pcix; - } - bus_ptr++; - } - - hpc_ptr->ctlr_type = temp; - - switch (hpc_ptr->ctlr_type) { - case 1: - hpc_ptr->u.pci_ctlr.bus = readb (io_mem + addr); - hpc_ptr->u.pci_ctlr.dev_fun = readb (io_mem + addr + 1); - hpc_ptr->irq = readb (io_mem + addr + 2); - addr += 3; - debug ("ctrl bus = %x, ctlr devfun = %x, irq = %x\n", - hpc_ptr->u.pci_ctlr.bus, - hpc_ptr->u.pci_ctlr.dev_fun, hpc_ptr->irq); - break; - - case 0: - hpc_ptr->u.isa_ctlr.io_start = readw (io_mem + addr); - hpc_ptr->u.isa_ctlr.io_end = readw (io_mem + addr + 2); - if (!request_region (hpc_ptr->u.isa_ctlr.io_start, - (hpc_ptr->u.isa_ctlr.io_end - hpc_ptr->u.isa_ctlr.io_start + 1), - "ibmphp")) { - rc = -ENODEV; - goto error_no_hp_slot; - } - hpc_ptr->irq = readb (io_mem + addr + 4); - addr += 5; - break; - - case 2: - case 4: - hpc_ptr->u.wpeg_ctlr.wpegbbar = readl (io_mem + addr); - hpc_ptr->u.wpeg_ctlr.i2c_addr = readb (io_mem + addr + 4); - hpc_ptr->irq = readb (io_mem + addr + 5); - addr += 6; - break; - default: - rc = -ENODEV; - goto error_no_hp_slot; - } - - //reorganize chassis' linked list - combine_wpg_for_chassis (); - combine_wpg_for_expansion (); - hpc_ptr->revision = 0xff; - hpc_ptr->options = 0xff; - hpc_ptr->starting_slot_num = hpc_ptr->slots[0].slot_num; - hpc_ptr->ending_slot_num = hpc_ptr->slots[slot_num-1].slot_num; - - // register slots with hpc core as well as create linked list of ibm slot - for (index = 0; index < hpc_ptr->slot_count; index++) { - - hp_slot_ptr = (struct hotplug_slot *) kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL); - if (!hp_slot_ptr) { - rc = -ENOMEM; - goto error_no_hp_slot; - } - memset (hp_slot_ptr, 0, sizeof (struct hotplug_slot)); - - hp_slot_ptr->info = (struct hotplug_slot_info *) kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); - if (!hp_slot_ptr->info) { - rc = -ENOMEM; - goto error_no_hp_info; - } - memset (hp_slot_ptr->info, 0, sizeof (struct hotplug_slot_info)); - - hp_slot_ptr->name = (char *) kmalloc (30, GFP_KERNEL); - if (!hp_slot_ptr->name) { - rc = -ENOMEM; - goto error_no_hp_name; - } - - tmp_slot = kmalloc (sizeof (struct slot), GFP_KERNEL); - if (!tmp_slot) { - rc = -ENOMEM; - goto error_no_slot; - } - memset (tmp_slot, 0, sizeof (*tmp_slot)); - - tmp_slot->flag = TRUE; - - tmp_slot->capabilities = hpc_ptr->slots[index].slot_cap; - if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_133_MAX) == EBDA_SLOT_133_MAX) - tmp_slot->supported_speed = 3; - else if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_100_MAX) == EBDA_SLOT_100_MAX) - tmp_slot->supported_speed = 2; - else if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_66_MAX) == EBDA_SLOT_66_MAX) - tmp_slot->supported_speed = 1; - - if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_PCIX_CAP) == EBDA_SLOT_PCIX_CAP) - tmp_slot->supported_bus_mode = 1; - else - tmp_slot->supported_bus_mode = 0; - - - tmp_slot->bus = hpc_ptr->slots[index].slot_bus_num; - - bus_info_ptr1 = ibmphp_find_same_bus_num (hpc_ptr->slots[index].slot_bus_num); - if (!bus_info_ptr1) { - rc = -ENODEV; - goto error; - } - tmp_slot->bus_on = bus_info_ptr1; - bus_info_ptr1 = NULL; - tmp_slot->ctrl = hpc_ptr; - - tmp_slot->ctlr_index = hpc_ptr->slots[index].ctl_index; - tmp_slot->number = hpc_ptr->slots[index].slot_num; - tmp_slot->hotplug_slot = hp_slot_ptr; - - hp_slot_ptr->private = tmp_slot; - - rc = ibmphp_hpc_fillhpslotinfo (hp_slot_ptr); - if (rc) - goto error; - - rc = ibmphp_init_devno ((struct slot **) &hp_slot_ptr->private); - if (rc) - goto error; - hp_slot_ptr->ops = &ibmphp_hotplug_slot_ops; - - // end of registering ibm slot with hotplug core - - list_add (& ((struct slot *)(hp_slot_ptr->private))->ibm_slot_list, &ibmphp_slot_head); - } - - print_bus_info (); - list_add (&hpc_ptr->ebda_hpc_list, &ebda_hpc_head ); - - } /* each hpc */ - - list_for_each (list, &ibmphp_slot_head) { - tmp_slot = list_entry (list, struct slot, ibm_slot_list); - - snprintf (tmp_slot->hotplug_slot->name, 30, "%s", create_file_name (tmp_slot)); - pci_hp_register (tmp_slot->hotplug_slot); - } - - print_ebda_hpc (); - print_ibm_slot (); - return 0; - -error: - kfree (hp_slot_ptr->private); -error_no_slot: - kfree (hp_slot_ptr->name); -error_no_hp_name: - kfree (hp_slot_ptr->info); -error_no_hp_info: - kfree (hp_slot_ptr); -error_no_hp_slot: - free_ebda_hpc (hpc_ptr); -error_no_hpc: - iounmap (io_mem); - return rc; -} - -/* - * map info (bus, devfun, start addr, end addr..) of i/o, memory, - * pfm from the physical addr to a list of resource. - */ -static int __init ebda_rsrc_rsrc (void) -{ - u16 addr; - short rsrc; - u8 type, rsrc_type; - struct ebda_pci_rsrc *rsrc_ptr; - - addr = rsrc_list_ptr->phys_addr; - debug ("now entering rsrc land\n"); - debug ("offset of rsrc: %x\n", rsrc_list_ptr->phys_addr); - - for (rsrc = 0; rsrc < rsrc_list_ptr->num_entries; rsrc++) { - type = readb (io_mem + addr); - - addr += 1; - rsrc_type = type & EBDA_RSRC_TYPE_MASK; - - if (rsrc_type == EBDA_IO_RSRC_TYPE) { - rsrc_ptr = alloc_ebda_pci_rsrc (); - if (!rsrc_ptr) { - iounmap (io_mem); - return -ENOMEM; - } - rsrc_ptr->rsrc_type = type; - - rsrc_ptr->bus_num = readb (io_mem + addr); - rsrc_ptr->dev_fun = readb (io_mem + addr + 1); - rsrc_ptr->start_addr = readw (io_mem + addr + 2); - rsrc_ptr->end_addr = readw (io_mem + addr + 4); - addr += 6; - - debug ("rsrc from io type ----\n"); - debug ("rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n", - rsrc_ptr->rsrc_type, rsrc_ptr->bus_num, rsrc_ptr->dev_fun, rsrc_ptr->start_addr, rsrc_ptr->end_addr); - - list_add (&rsrc_ptr->ebda_pci_rsrc_list, &ibmphp_ebda_pci_rsrc_head); - } - - if (rsrc_type == EBDA_MEM_RSRC_TYPE || rsrc_type == EBDA_PFM_RSRC_TYPE) { - rsrc_ptr = alloc_ebda_pci_rsrc (); - if (!rsrc_ptr ) { - iounmap (io_mem); - return -ENOMEM; - } - rsrc_ptr->rsrc_type = type; - - rsrc_ptr->bus_num = readb (io_mem + addr); - rsrc_ptr->dev_fun = readb (io_mem + addr + 1); - rsrc_ptr->start_addr = readl (io_mem + addr + 2); - rsrc_ptr->end_addr = readl (io_mem + addr + 6); - addr += 10; - - debug ("rsrc from mem or pfm ---\n"); - debug ("rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n", - rsrc_ptr->rsrc_type, rsrc_ptr->bus_num, rsrc_ptr->dev_fun, rsrc_ptr->start_addr, rsrc_ptr->end_addr); - - list_add (&rsrc_ptr->ebda_pci_rsrc_list, &ibmphp_ebda_pci_rsrc_head); - } - } - kfree (rsrc_list_ptr); - rsrc_list_ptr = NULL; - print_ebda_pci_rsrc (); - return 0; -} - -u16 ibmphp_get_total_controllers (void) -{ - return hpc_list_ptr->num_ctlrs; -} - -struct slot *ibmphp_get_slot_from_physical_num (u8 physical_num) -{ - struct slot *slot; - struct list_head *list; - - list_for_each (list, &ibmphp_slot_head) { - slot = list_entry (list, struct slot, ibm_slot_list); - if (slot->number == physical_num) - return slot; - } - return NULL; -} - -/* To find: - * - the smallest slot number - * - the largest slot number - * - the total number of the slots based on each bus - * (if only one slot per bus slot_min = slot_max ) - */ -struct bus_info *ibmphp_find_same_bus_num (u32 num) -{ - struct bus_info *ptr; - struct list_head *ptr1; - - list_for_each (ptr1, &bus_info_head) { - ptr = list_entry (ptr1, struct bus_info, bus_info_list); - if (ptr->busno == num) - return ptr; - } - return NULL; -} - -/* Finding relative bus number, in order to map corresponding - * bus register - */ -int ibmphp_get_bus_index (u8 num) -{ - struct bus_info *ptr; - struct list_head *ptr1; - - list_for_each (ptr1, &bus_info_head) { - ptr = list_entry (ptr1, struct bus_info, bus_info_list); - if (ptr->busno == num) - return ptr->index; - } - return -ENODEV; -} - -void ibmphp_free_bus_info_queue (void) -{ - struct bus_info *bus_info; - struct list_head *list; - struct list_head *next; - - list_for_each_safe (list, next, &bus_info_head ) { - bus_info = list_entry (list, struct bus_info, bus_info_list); - kfree (bus_info); - } -} - -void ibmphp_free_ebda_hpc_queue (void) -{ - struct controller *controller = NULL; - struct list_head *list; - struct list_head *next; - int pci_flag = 0; - - list_for_each_safe (list, next, &ebda_hpc_head) { - controller = list_entry (list, struct controller, ebda_hpc_list); - if (controller->ctlr_type == 0) - release_region (controller->u.isa_ctlr.io_start, (controller->u.isa_ctlr.io_end - controller->u.isa_ctlr.io_start + 1)); - else if ((controller->ctlr_type == 1) && (!pci_flag)) { - ++pci_flag; - pci_unregister_driver (&ibmphp_driver); - } - free_ebda_hpc (controller); - } -} - -void ibmphp_free_ebda_pci_rsrc_queue (void) -{ - struct ebda_pci_rsrc *resource; - struct list_head *list; - struct list_head *next; - - list_for_each_safe (list, next, &ibmphp_ebda_pci_rsrc_head) { - resource = list_entry (list, struct ebda_pci_rsrc, ebda_pci_rsrc_list); - kfree (resource); - resource = NULL; - } -} - -static struct pci_device_id id_table[] __devinitdata = { - { - .vendor = PCI_VENDOR_ID_IBM, - .device = HPC_DEVICE_ID, - .subvendor = PCI_VENDOR_ID_IBM, - .subdevice = HPC_SUBSYSTEM_ID, - .class = ((PCI_CLASS_SYSTEM_PCI_HOTPLUG << 8) | 0x00), - }, {} -}; - -MODULE_DEVICE_TABLE(pci, id_table); - -static int ibmphp_probe (struct pci_dev *, const struct pci_device_id *); -static struct pci_driver ibmphp_driver = { - .name = "ibmphp", - .id_table = id_table, - .probe = ibmphp_probe, -}; - -int ibmphp_register_pci (void) -{ - struct controller *ctrl; - struct list_head *tmp; - int rc = 0; - - list_for_each (tmp, &ebda_hpc_head) { - ctrl = list_entry (tmp, struct controller, ebda_hpc_list); - if (ctrl->ctlr_type == 1) { - rc = pci_module_init (&ibmphp_driver); - break; - } - } - return rc; -} -static int ibmphp_probe (struct pci_dev * dev, const struct pci_device_id *ids) -{ - struct controller *ctrl; - struct list_head *tmp; - - debug ("inside ibmphp_probe \n"); - - list_for_each (tmp, &ebda_hpc_head) { - ctrl = list_entry (tmp, struct controller, ebda_hpc_list); - if (ctrl->ctlr_type == 1) { - if ((dev->devfn == ctrl->u.pci_ctlr.dev_fun) && (dev->bus->number == ctrl->u.pci_ctlr.bus)) { - ctrl->ctrl_dev = dev; - debug ("found device!!! \n"); - debug ("dev->device = %x, dev->subsystem_device = %x\n", dev->device, dev->subsystem_device); - return 0; - } - } - } - return -ENODEV; -} - diff -Nru a/drivers/hotplug/ibmphp_hpc.c b/drivers/hotplug/ibmphp_hpc.c --- a/drivers/hotplug/ibmphp_hpc.c Mon Jun 9 23:16:08 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,1228 +0,0 @@ -/* - * IBM Hot Plug Controller Driver - * - * Written By: Jyoti Shah, IBM Corporation - * - * Copyright (c) 2001-2002 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or - * NON INFRINGEMENT. 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. - * - * Send feedback to <gregkh@us.ibm.com> - * <jshah@us.ibm.com> - * - */ - -#include <linux/wait.h> -#include <linux/time.h> -#include <linux/module.h> -#include <linux/pci.h> -#include <linux/smp_lock.h> -#include <linux/init.h> -#include "ibmphp.h" - -static int to_debug = FALSE; -#define debug_polling(fmt, arg...) do { if (to_debug) debug (fmt, arg); } while (0) - -//---------------------------------------------------------------------------- -// timeout values -//---------------------------------------------------------------------------- -#define CMD_COMPLETE_TOUT_SEC 60 // give HPC 60 sec to finish cmd -#define HPC_CTLR_WORKING_TOUT 60 // give HPC 60 sec to finish cmd -#define HPC_GETACCESS_TIMEOUT 60 // seconds -#define POLL_INTERVAL_SEC 2 // poll HPC every 2 seconds -#define POLL_LATCH_CNT 5 // poll latch 5 times, then poll slots - -//---------------------------------------------------------------------------- -// Winnipeg Architected Register Offsets -//---------------------------------------------------------------------------- -#define WPG_I2CMBUFL_OFFSET 0x08 // I2C Message Buffer Low -#define WPG_I2CMOSUP_OFFSET 0x10 // I2C Master Operation Setup Reg -#define WPG_I2CMCNTL_OFFSET 0x20 // I2C Master Control Register -#define WPG_I2CPARM_OFFSET 0x40 // I2C Parameter Register -#define WPG_I2CSTAT_OFFSET 0x70 // I2C Status Register - -//---------------------------------------------------------------------------- -// Winnipeg Store Type commands (Add this commands to the register offset) -//---------------------------------------------------------------------------- -#define WPG_I2C_AND 0x1000 // I2C AND operation -#define WPG_I2C_OR 0x2000 // I2C OR operation - -//---------------------------------------------------------------------------- -// Command set for I2C Master Operation Setup Regisetr -//---------------------------------------------------------------------------- -#define WPG_READATADDR_MASK 0x00010000 // read,bytes,I2C shifted,index -#define WPG_WRITEATADDR_MASK 0x40010000 // write,bytes,I2C shifted,index -#define WPG_READDIRECT_MASK 0x10010000 -#define WPG_WRITEDIRECT_MASK 0x60010000 - - -//---------------------------------------------------------------------------- -// bit masks for I2C Master Control Register -//---------------------------------------------------------------------------- -#define WPG_I2CMCNTL_STARTOP_MASK 0x00000002 // Start the Operation - -//---------------------------------------------------------------------------- -// -//---------------------------------------------------------------------------- -#define WPG_I2C_IOREMAP_SIZE 0x2044 // size of linear address interval - -//---------------------------------------------------------------------------- -// command index -//---------------------------------------------------------------------------- -#define WPG_1ST_SLOT_INDEX 0x01 // index - 1st slot for ctlr -#define WPG_CTLR_INDEX 0x0F // index - ctlr -#define WPG_1ST_EXTSLOT_INDEX 0x10 // index - 1st ext slot for ctlr -#define WPG_1ST_BUS_INDEX 0x1F // index - 1st bus for ctlr - -//---------------------------------------------------------------------------- -// macro utilities -//---------------------------------------------------------------------------- -// if bits 20,22,25,26,27,29,30 are OFF return TRUE -#define HPC_I2CSTATUS_CHECK(s) ((u8)((s & 0x00000A76) ? FALSE : TRUE)) - -//---------------------------------------------------------------------------- -// global variables -//---------------------------------------------------------------------------- -static int ibmphp_shutdown; -static int tid_poll; -static struct semaphore sem_hpcaccess; // lock access to HPC -static struct semaphore semOperations; // lock all operations and - // access to data structures -static struct semaphore sem_exit; // make sure polling thread goes away -//---------------------------------------------------------------------------- -// local function prototypes -//---------------------------------------------------------------------------- -static u8 i2c_ctrl_read (struct controller *, void *, u8); -static u8 i2c_ctrl_write (struct controller *, void *, u8, u8); -static u8 hpc_writecmdtoindex (u8, u8); -static u8 hpc_readcmdtoindex (u8, u8); -static void get_hpc_access (void); -static void free_hpc_access (void); -static void poll_hpc (void); -static int update_slot (struct slot *, u8); -static int process_changeinstatus (struct slot *, struct slot *); -static int process_changeinlatch (u8, u8, struct controller *); -static int hpc_poll_thread (void *); -static int hpc_wait_ctlr_notworking (int, struct controller *, void *, u8 *); -//---------------------------------------------------------------------------- - - -/*---------------------------------------------------------------------- -* Name: ibmphp_hpc_initvars -* -* Action: initialize semaphores and variables -*---------------------------------------------------------------------*/ -void __init ibmphp_hpc_initvars (void) -{ - debug ("%s - Entry\n", __FUNCTION__); - - init_MUTEX (&sem_hpcaccess); - init_MUTEX (&semOperations); - init_MUTEX_LOCKED (&sem_exit); - to_debug = FALSE; - ibmphp_shutdown = FALSE; - tid_poll = 0; - - debug ("%s - Exit\n", __FUNCTION__); -} - -/*---------------------------------------------------------------------- -* Name: i2c_ctrl_read -* -* Action: read from HPC over I2C -* -*---------------------------------------------------------------------*/ -static u8 i2c_ctrl_read (struct controller *ctlr_ptr, void *WPGBbar, u8 index) -{ - u8 status; - int i; - void *wpg_addr; // base addr + offset - ulong wpg_data, // data to/from WPG LOHI format - ultemp, data; // actual data HILO format - - - debug_polling ("%s - Entry WPGBbar[%lx] index[%x] \n", __FUNCTION__, (ulong) WPGBbar, index); - - //-------------------------------------------------------------------- - // READ - step 1 - // read at address, byte length, I2C address (shifted), index - // or read direct, byte length, index - if (ctlr_ptr->ctlr_type == 0x02) { - data = WPG_READATADDR_MASK; - // fill in I2C address - ultemp = (ulong) ctlr_ptr->u.wpeg_ctlr.i2c_addr; - ultemp = ultemp >> 1; - data |= (ultemp << 8); - - // fill in index - data |= (ulong) index; - } else if (ctlr_ptr->ctlr_type == 0x04) { - data = WPG_READDIRECT_MASK; - - // fill in index - ultemp = (ulong) index; - ultemp = ultemp << 8; - data |= ultemp; - } else { - err ("this controller type is not supported \n"); - return HPC_ERROR; - } - - wpg_data = swab32 (data); // swap data before writing - (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMOSUP_OFFSET; - writel (wpg_data, wpg_addr); - - //-------------------------------------------------------------------- - // READ - step 2 : clear the message buffer - data = 0x00000000; - wpg_data = swab32 (data); - (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMBUFL_OFFSET; - writel (wpg_data, wpg_addr); - - //-------------------------------------------------------------------- - // READ - step 3 : issue start operation, I2C master control bit 30:ON - // 2020 : [20] OR operation at [20] offset 0x20 - data = WPG_I2CMCNTL_STARTOP_MASK; - wpg_data = swab32 (data); - (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET + (ulong) WPG_I2C_OR; - writel (wpg_data, wpg_addr); - - //-------------------------------------------------------------------- - // READ - step 4 : wait until start operation bit clears - i = CMD_COMPLETE_TOUT_SEC; - while (i) { - long_delay (1 * HZ / 100); - (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET; - wpg_data = readl (wpg_addr); - data = swab32 (wpg_data); - if (!(data & WPG_I2CMCNTL_STARTOP_MASK)) - break; - i--; - } - if (i == 0) { - debug ("%s - Error : WPG timeout\n", __FUNCTION__); - return HPC_ERROR; - } - //-------------------------------------------------------------------- - // READ - step 5 : read I2C status register - i = CMD_COMPLETE_TOUT_SEC; - while (i) { - long_delay (1 * HZ / 100); - (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CSTAT_OFFSET; - wpg_data = readl (wpg_addr); - data = swab32 (wpg_data); - if (HPC_I2CSTATUS_CHECK (data)) - break; - i--; - } - if (i == 0) { - debug ("ctrl_read - Exit Error:I2C timeout\n"); - return HPC_ERROR; - } - - //-------------------------------------------------------------------- - // READ - step 6 : get DATA - (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMBUFL_OFFSET; - wpg_data = readl (wpg_addr); - data = swab32 (wpg_data); - - status = (u8) data; - - debug_polling ("%s - Exit index[%x] status[%x]\n", __FUNCTION__, index, status); - - return (status); -} - -/*---------------------------------------------------------------------- -* Name: i2c_ctrl_write -* -* Action: write to HPC over I2C -* -* Return 0 or error codes -*---------------------------------------------------------------------*/ -static u8 i2c_ctrl_write (struct controller *ctlr_ptr, void *WPGBbar, u8 index, u8 cmd) -{ - u8 rc; - void *wpg_addr; // base addr + offset - ulong wpg_data, // data to/from WPG LOHI format - ultemp, data; // actual data HILO format - int i; - - - debug_polling ("%s - Entry WPGBbar[%lx] index[%x] cmd[%x]\n", __FUNCTION__, (ulong) WPGBbar, index, cmd); - - rc = 0; - //-------------------------------------------------------------------- - // WRITE - step 1 - // write at address, byte length, I2C address (shifted), index - // or write direct, byte length, index - data = 0x00000000; - - if (ctlr_ptr->ctlr_type == 0x02) { - data = WPG_WRITEATADDR_MASK; - // fill in I2C address - ultemp = (ulong) ctlr_ptr->u.wpeg_ctlr.i2c_addr; - ultemp = ultemp >> 1; - data |= (ultemp << 8); - - // fill in index - data |= (ulong) index; - } else if (ctlr_ptr->ctlr_type == 0x04) { - data = WPG_WRITEDIRECT_MASK; - - // fill in index - ultemp = (ulong) index; - ultemp = ultemp << 8; - data |= ultemp; - } else { - err ("this controller type is not supported \n"); - return HPC_ERROR; - } - - wpg_data = swab32 (data); // swap data before writing - (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMOSUP_OFFSET; - writel (wpg_data, wpg_addr); - - //-------------------------------------------------------------------- - // WRITE - step 2 : clear the message buffer - data = 0x00000000 | (ulong) cmd; - wpg_data = swab32 (data); - (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMBUFL_OFFSET; - writel (wpg_data, wpg_addr); - - //-------------------------------------------------------------------- - // WRITE - step 3 : issue start operation,I2C master control bit 30:ON - // 2020 : [20] OR operation at [20] offset 0x20 - data = WPG_I2CMCNTL_STARTOP_MASK; - wpg_data = swab32 (data); - (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET + (ulong) WPG_I2C_OR; - writel (wpg_data, wpg_addr); - - //-------------------------------------------------------------------- - // WRITE - step 4 : wait until start operation bit clears - i = CMD_COMPLETE_TOUT_SEC; - while (i) { - long_delay (1 * HZ / 100); - (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET; - wpg_data = readl (wpg_addr); - data = swab32 (wpg_data); - if (!(data & WPG_I2CMCNTL_STARTOP_MASK)) - break; - i--; - } - if (i == 0) { - debug ("%s - Exit Error:WPG timeout\n", __FUNCTION__); - rc = HPC_ERROR; - } - - //-------------------------------------------------------------------- - // WRITE - step 5 : read I2C status register - i = CMD_COMPLETE_TOUT_SEC; - while (i) { - long_delay (1 * HZ / 100); - (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CSTAT_OFFSET; - wpg_data = readl (wpg_addr); - data = swab32 (wpg_data); - if (HPC_I2CSTATUS_CHECK (data)) - break; - i--; - } - if (i == 0) { - debug ("ctrl_read - Error : I2C timeout\n"); - rc = HPC_ERROR; - } - - debug_polling ("%s Exit rc[%x]\n", __FUNCTION__, rc); - return (rc); -} - -//------------------------------------------------------------ -// Read from ISA type HPC -//------------------------------------------------------------ -static u8 isa_ctrl_read (struct controller *ctlr_ptr, u8 offset) -{ - u16 start_address; - u16 end_address; - u8 data; - - start_address = ctlr_ptr->u.isa_ctlr.io_start; - end_address = ctlr_ptr->u.isa_ctlr.io_end; - data = inb (start_address + offset); - return data; -} - -//-------------------------------------------------------------- -// Write to ISA type HPC -//-------------------------------------------------------------- -static void isa_ctrl_write (struct controller *ctlr_ptr, u8 offset, u8 data) -{ - u16 start_address; - u16 port_address; - - start_address = ctlr_ptr->u.isa_ctlr.io_start; - port_address = start_address + (u16) offset; - outb (data, port_address); -} - -static u8 pci_ctrl_read (struct controller *ctrl, u8 offset) -{ - u8 data = 0x00; - debug ("inside pci_ctrl_read\n"); - if (ctrl->ctrl_dev) - pci_read_config_byte (ctrl->ctrl_dev, HPC_PCI_OFFSET + offset, &data); - return data; -} - -static u8 pci_ctrl_write (struct controller *ctrl, u8 offset, u8 data) -{ - u8 rc = -ENODEV; - debug ("inside pci_ctrl_write\n"); - if (ctrl->ctrl_dev) { - pci_write_config_byte (ctrl->ctrl_dev, HPC_PCI_OFFSET + offset, data); - rc = 0; - } - return rc; -} - -static u8 ctrl_read (struct controller *ctlr, void *base, u8 offset) -{ - u8 rc; - switch (ctlr->ctlr_type) { - case 0: - rc = isa_ctrl_read (ctlr, offset); - break; - case 1: - rc = pci_ctrl_read (ctlr, offset); - break; - case 2: - case 4: - rc = i2c_ctrl_read (ctlr, base, offset); - break; - default: - return -ENODEV; - } - return rc; -} - -static u8 ctrl_write (struct controller *ctlr, void *base, u8 offset, u8 data) -{ - u8 rc = 0; - switch (ctlr->ctlr_type) { - case 0: - isa_ctrl_write(ctlr, offset, data); - break; - case 1: - rc = pci_ctrl_write (ctlr, offset, data); - break; - case 2: - case 4: - rc = i2c_ctrl_write(ctlr, base, offset, data); - break; - default: - return -ENODEV; - } - return rc; -} -/*---------------------------------------------------------------------- -* Name: hpc_writecmdtoindex() -* -* Action: convert a write command to proper index within a controller -* -* Return index, HPC_ERROR -*---------------------------------------------------------------------*/ -static u8 hpc_writecmdtoindex (u8 cmd, u8 index) -{ - u8 rc; - - switch (cmd) { - case HPC_CTLR_ENABLEIRQ: // 0x00.N.15 - case HPC_CTLR_CLEARIRQ: // 0x06.N.15 - case HPC_CTLR_RESET: // 0x07.N.15 - case HPC_CTLR_IRQSTEER: // 0x08.N.15 - case HPC_CTLR_DISABLEIRQ: // 0x01.N.15 - case HPC_ALLSLOT_ON: // 0x11.N.15 - case HPC_ALLSLOT_OFF: // 0x12.N.15 - rc = 0x0F; - break; - - case HPC_SLOT_OFF: // 0x02.Y.0-14 - case HPC_SLOT_ON: // 0x03.Y.0-14 - case HPC_SLOT_ATTNOFF: // 0x04.N.0-14 - case HPC_SLOT_ATTNON: // 0x05.N.0-14 - case HPC_SLOT_BLINKLED: // 0x13.N.0-14 - rc = index; - break; - - case HPC_BUS_33CONVMODE: - case HPC_BUS_66CONVMODE: - case HPC_BUS_66PCIXMODE: - case HPC_BUS_100PCIXMODE: - case HPC_BUS_133PCIXMODE: - rc = index + WPG_1ST_BUS_INDEX - 1; - break; - - default: - err ("hpc_writecmdtoindex - Error invalid cmd[%x]\n", cmd); - rc = HPC_ERROR; - } - - return rc; -} - -/*---------------------------------------------------------------------- -* Name: hpc_readcmdtoindex() -* -* Action: convert a read command to proper index within a controller -* -* Return index, HPC_ERROR -*---------------------------------------------------------------------*/ -static u8 hpc_readcmdtoindex (u8 cmd, u8 index) -{ - u8 rc; - - switch (cmd) { - case READ_CTLRSTATUS: - rc = 0x0F; - break; - case READ_SLOTSTATUS: - case READ_ALLSTAT: - rc = index; - break; - case READ_EXTSLOTSTATUS: - rc = index + WPG_1ST_EXTSLOT_INDEX; - break; - case READ_BUSSTATUS: - rc = index + WPG_1ST_BUS_INDEX - 1; - break; - case READ_SLOTLATCHLOWREG: - rc = 0x28; - break; - case READ_REVLEVEL: - rc = 0x25; - break; - case READ_HPCOPTIONS: - rc = 0x27; - break; - default: - rc = HPC_ERROR; - } - return rc; -} - -/*---------------------------------------------------------------------- -* Name: HPCreadslot() -* -* Action: issue a READ command to HPC -* -* Input: pslot - can not be NULL for READ_ALLSTAT -* pstatus - can be NULL for READ_ALLSTAT -* -* Return 0 or error codes -*---------------------------------------------------------------------*/ -int ibmphp_hpc_readslot (struct slot * pslot, u8 cmd, u8 * pstatus) -{ - void *wpg_bbar = NULL; - struct controller *ctlr_ptr; - struct list_head *pslotlist; - u8 index, status; - int rc = 0; - int busindex; - - debug_polling ("%s - Entry pslot[%lx] cmd[%x] pstatus[%lx]\n", __FUNCTION__, (ulong) pslot, cmd, (ulong) pstatus); - - if ((pslot == NULL) - || ((pstatus == NULL) && (cmd != READ_ALLSTAT) && (cmd != READ_BUSSTATUS))) { - rc = -EINVAL; - err ("%s - Error invalid pointer, rc[%d]\n", __FUNCTION__, rc); - return rc; - } - - if (cmd == READ_BUSSTATUS) { - busindex = ibmphp_get_bus_index (pslot->bus); - if (busindex < 0) { - rc = -EINVAL; - err ("%s - Exit Error:invalid bus, rc[%d]\n", __FUNCTION__, rc); - return rc; - } else - index = (u8) busindex; - } else - index = pslot->ctlr_index; - - index = hpc_readcmdtoindex (cmd, index); - - if (index == HPC_ERROR) { - rc = -EINVAL; - err ("%s - Exit Error:invalid index, rc[%d]\n", __FUNCTION__, rc); - return rc; - } - - ctlr_ptr = pslot->ctrl; - - get_hpc_access (); - - //-------------------------------------------------------------------- - // map physical address to logical address - //-------------------------------------------------------------------- - if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4)) - wpg_bbar = ioremap (ctlr_ptr->u.wpeg_ctlr.wpegbbar, WPG_I2C_IOREMAP_SIZE); - - //-------------------------------------------------------------------- - // check controller status before reading - //-------------------------------------------------------------------- - rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, &status); - if (!rc) { - switch (cmd) { - case READ_ALLSTAT: - // update the slot structure - pslot->ctrl->status = status; - pslot->status = ctrl_read (ctlr_ptr, wpg_bbar, index); - rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, - &status); - if (!rc) - pslot->ext_status = ctrl_read (ctlr_ptr, wpg_bbar, index + WPG_1ST_EXTSLOT_INDEX); - - break; - - case READ_SLOTSTATUS: - // DO NOT update the slot structure - *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); - break; - - case READ_EXTSLOTSTATUS: - // DO NOT update the slot structure - *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); - break; - - case READ_CTLRSTATUS: - // DO NOT update the slot structure - *pstatus = status; - break; - - case READ_BUSSTATUS: - pslot->busstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); - break; - case READ_REVLEVEL: - *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); - break; - case READ_HPCOPTIONS: - *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); - break; - case READ_SLOTLATCHLOWREG: - // DO NOT update the slot structure - *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); - break; - - // Not used - case READ_ALLSLOT: - list_for_each (pslotlist, &ibmphp_slot_head) { - pslot = list_entry (pslotlist, struct slot, ibm_slot_list); - index = pslot->ctlr_index; - rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, - wpg_bbar, &status); - if (!rc) { - pslot->status = ctrl_read (ctlr_ptr, wpg_bbar, index); - rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, - ctlr_ptr, wpg_bbar, &status); - if (!rc) - pslot->ext_status = - ctrl_read (ctlr_ptr, wpg_bbar, - index + WPG_1ST_EXTSLOT_INDEX); - } else { - err ("%s - Error ctrl_read failed\n", __FUNCTION__); - rc = -EINVAL; - break; - } - } - break; - default: - rc = -EINVAL; - break; - } - } - //-------------------------------------------------------------------- - // cleanup - //-------------------------------------------------------------------- - - // remove physical to logical address mapping - if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4)) - iounmap (wpg_bbar); - - free_hpc_access (); - - debug_polling ("%s - Exit rc[%d]\n", __FUNCTION__, rc); - return rc; -} - -/*---------------------------------------------------------------------- -* Name: ibmphp_hpc_writeslot() -* -* Action: issue a WRITE command to HPC -*---------------------------------------------------------------------*/ -int ibmphp_hpc_writeslot (struct slot * pslot, u8 cmd) -{ - void *wpg_bbar = NULL; - struct controller *ctlr_ptr; - u8 index, status; - int busindex; - u8 done; - int rc = 0; - int timeout; - - debug_polling ("%s - Entry pslot[%lx] cmd[%x]\n", __FUNCTION__, (ulong) pslot, cmd); - if (pslot == NULL) { - rc = -EINVAL; - err ("%s - Error Exit rc[%d]\n", __FUNCTION__, rc); - return rc; - } - - if ((cmd == HPC_BUS_33CONVMODE) || (cmd == HPC_BUS_66CONVMODE) || - (cmd == HPC_BUS_66PCIXMODE) || (cmd == HPC_BUS_100PCIXMODE) || - (cmd == HPC_BUS_133PCIXMODE)) { - busindex = ibmphp_get_bus_index (pslot->bus); - if (busindex < 0) { - rc = -EINVAL; - err ("%s - Exit Error:invalid bus, rc[%d]\n", __FUNCTION__, rc); - return rc; - } else - index = (u8) busindex; - } else - index = pslot->ctlr_index; - - index = hpc_writecmdtoindex (cmd, index); - - if (index == HPC_ERROR) { - rc = -EINVAL; - err ("%s - Error Exit rc[%d]\n", __FUNCTION__, rc); - return rc; - } - - ctlr_ptr = pslot->ctrl; - - get_hpc_access (); - - //-------------------------------------------------------------------- - // map physical address to logical address - //-------------------------------------------------------------------- - if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4)) { - wpg_bbar = ioremap (ctlr_ptr->u.wpeg_ctlr.wpegbbar, WPG_I2C_IOREMAP_SIZE); - - debug ("%s - ctlr id[%x] physical[%lx] logical[%lx] i2c[%x]\n", __FUNCTION__, - ctlr_ptr->ctlr_id, (ulong) (ctlr_ptr->u.wpeg_ctlr.wpegbbar), (ulong) wpg_bbar, - ctlr_ptr->u.wpeg_ctlr.i2c_addr); - } - //-------------------------------------------------------------------- - // check controller status before writing - //-------------------------------------------------------------------- - rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, &status); - if (!rc) { - - ctrl_write (ctlr_ptr, wpg_bbar, index, cmd); - - //-------------------------------------------------------------------- - // check controller is still not working on the command - //-------------------------------------------------------------------- - timeout = CMD_COMPLETE_TOUT_SEC; - done = FALSE; - while (!done) { - rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, - &status); - if (!rc) { - if (NEEDTOCHECK_CMDSTATUS (cmd)) { - if (CTLR_FINISHED (status) == HPC_CTLR_FINISHED_YES) - done = TRUE; - } else - done = TRUE; - } - if (!done) { - long_delay (1 * HZ); - if (timeout < 1) { - done = TRUE; - err ("%s - Error command complete timeout\n", __FUNCTION__); - rc = -EFAULT; - } else - timeout--; - } - } - ctlr_ptr->status = status; - } - // cleanup - - // remove physical to logical address mapping - if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4)) - iounmap (wpg_bbar); - free_hpc_access (); - - debug_polling ("%s - Exit rc[%d]\n", __FUNCTION__, rc); - return rc; -} - -/*---------------------------------------------------------------------- -* Name: get_hpc_access() -* -* Action: make sure only one process can access HPC at one time -*---------------------------------------------------------------------*/ -static void get_hpc_access (void) -{ - down (&sem_hpcaccess); -} - -/*---------------------------------------------------------------------- -* Name: free_hpc_access() -*---------------------------------------------------------------------*/ -void free_hpc_access (void) -{ - up (&sem_hpcaccess); -} - -/*---------------------------------------------------------------------- -* Name: ibmphp_lock_operations() -* -* Action: make sure only one process can change the data structure -*---------------------------------------------------------------------*/ -void ibmphp_lock_operations (void) -{ - down (&semOperations); - to_debug = TRUE; -} - -/*---------------------------------------------------------------------- -* Name: ibmphp_unlock_operations() -*---------------------------------------------------------------------*/ -void ibmphp_unlock_operations (void) -{ - debug ("%s - Entry\n", __FUNCTION__); - up (&semOperations); - to_debug = FALSE; - debug ("%s - Exit\n", __FUNCTION__); -} - -/*---------------------------------------------------------------------- -* Name: poll_hpc() -*---------------------------------------------------------------------*/ -#define POLL_LATCH_REGISTER 0 -#define POLL_SLOTS 1 -#define POLL_SLEEP 2 -static void poll_hpc (void) -{ - struct slot myslot; - struct slot *pslot = NULL; - struct list_head *pslotlist; - int rc; - int poll_state = POLL_LATCH_REGISTER; - u8 oldlatchlow = 0x00; - u8 curlatchlow = 0x00; - int poll_count = 0; - u8 ctrl_count = 0x00; - - debug ("%s - Entry\n", __FUNCTION__); - - while (!ibmphp_shutdown) { - if (ibmphp_shutdown) - break; - - /* try to get the lock to do some kind of harware access */ - down (&semOperations); - - switch (poll_state) { - case POLL_LATCH_REGISTER: - oldlatchlow = curlatchlow; - ctrl_count = 0x00; - list_for_each (pslotlist, &ibmphp_slot_head) { - if (ctrl_count >= ibmphp_get_total_controllers()) - break; - pslot = list_entry (pslotlist, struct slot, ibm_slot_list); - if (pslot->ctrl->ctlr_relative_id == ctrl_count) { - ctrl_count++; - if (READ_SLOT_LATCH (pslot->ctrl)) { - rc = ibmphp_hpc_readslot (pslot, - READ_SLOTLATCHLOWREG, - &curlatchlow); - if (oldlatchlow != curlatchlow) - process_changeinlatch (oldlatchlow, - curlatchlow, - pslot->ctrl); - } - } - } - ++poll_count; - poll_state = POLL_SLEEP; - break; - case POLL_SLOTS: - list_for_each (pslotlist, &ibmphp_slot_head) { - pslot = list_entry (pslotlist, struct slot, ibm_slot_list); - // make a copy of the old status - memcpy ((void *) &myslot, (void *) pslot, - sizeof (struct slot)); - rc = ibmphp_hpc_readslot (pslot, READ_ALLSTAT, NULL); - if ((myslot.status != pslot->status) - || (myslot.ext_status != pslot->ext_status)) - process_changeinstatus (pslot, &myslot); - } - ctrl_count = 0x00; - list_for_each (pslotlist, &ibmphp_slot_head) { - if (ctrl_count >= ibmphp_get_total_controllers()) - break; - pslot = list_entry (pslotlist, struct slot, ibm_slot_list); - if (pslot->ctrl->ctlr_relative_id == ctrl_count) { - ctrl_count++; - if (READ_SLOT_LATCH (pslot->ctrl)) - rc = ibmphp_hpc_readslot (pslot, - READ_SLOTLATCHLOWREG, - &curlatchlow); - } - } - ++poll_count; - poll_state = POLL_SLEEP; - break; - case POLL_SLEEP: - /* don't sleep with a lock on the hardware */ - up (&semOperations); - long_delay (POLL_INTERVAL_SEC * HZ); - - if (ibmphp_shutdown) - break; - - down (&semOperations); - - if (poll_count >= POLL_LATCH_CNT) { - poll_count = 0; - poll_state = POLL_SLOTS; - } else - poll_state = POLL_LATCH_REGISTER; - break; - } - /* give up the harware semaphore */ - up (&semOperations); - /* sleep for a short time just for good measure */ - set_current_state (TASK_INTERRUPTIBLE); - schedule_timeout (HZ/10); - } - up (&sem_exit); - debug ("%s - Exit\n", __FUNCTION__); -} - - -/* ---------------------------------------------------------------------- - * Name: ibmphp_hpc_fillhpslotinfo(hotplug_slot * phpslot) - * - * Action: fill out the hotplug_slot info - * - * Input: pointer to hotplug_slot - * - * Return - * Value: 0 or error codes - *-----------------------------------------------------------------------*/ -int ibmphp_hpc_fillhpslotinfo (struct hotplug_slot *phpslot) -{ - int rc = 0; - struct slot *pslot; - - if (phpslot && phpslot->private) { - pslot = (struct slot *) phpslot->private; - rc = update_slot (pslot, (u8) TRUE); - if (!rc) { - - // power - enabled:1 not:0 - phpslot->info->power_status = SLOT_POWER (pslot->status); - - // attention - off:0, on:1, blinking:2 - phpslot->info->attention_status = SLOT_ATTN (pslot->status, pslot->ext_status); - - // latch - open:1 closed:0 - phpslot->info->latch_status = SLOT_LATCH (pslot->status); - - // pci board - present:1 not:0 - if (SLOT_PRESENT (pslot->status)) - phpslot->info->adapter_status = 1; - else - phpslot->info->adapter_status = 0; -/* - if (pslot->bus_on->supported_bus_mode - && (pslot->bus_on->supported_speed == BUS_SPEED_66)) - phpslot->info->max_bus_speed_status = BUS_SPEED_66PCIX; - else - phpslot->info->max_bus_speed_status = pslot->bus_on->supported_speed; -*/ } else - rc = -EINVAL; - } else - rc = -EINVAL; - - return rc; -} - -/*---------------------------------------------------------------------- -* Name: update_slot -* -* Action: fill out slot status and extended status, controller status -* -* Input: pointer to slot struct -*---------------------------------------------------------------------*/ -static int update_slot (struct slot *pslot, u8 update) -{ - int rc = 0; - - debug ("%s - Entry pslot[%lx]\n", __FUNCTION__, (ulong) pslot); - rc = ibmphp_hpc_readslot (pslot, READ_ALLSTAT, NULL); - debug ("%s - Exit rc[%d]\n", __FUNCTION__, rc); - return rc; -} - -/*---------------------------------------------------------------------- -* Name: process_changeinstatus -* -* Action: compare old and new slot status, process the change in status -* -* Input: pointer to slot struct, old slot struct -* -* Return 0 or error codes -* Value: -* -* Side -* Effects: None. -* -* Notes: -*---------------------------------------------------------------------*/ -static int process_changeinstatus (struct slot *pslot, struct slot *poldslot) -{ - u8 status; - int rc = 0; - u8 disable = FALSE; - u8 update = FALSE; - - debug ("process_changeinstatus - Entry pslot[%lx], poldslot[%lx]\n", (ulong) pslot, - (ulong) poldslot); - - // bit 0 - HPC_SLOT_POWER - if ((pslot->status & 0x01) != (poldslot->status & 0x01)) - update = TRUE; - - // bit 1 - HPC_SLOT_CONNECT - // ignore - - // bit 2 - HPC_SLOT_ATTN - if ((pslot->status & 0x04) != (poldslot->status & 0x04)) - update = TRUE; - - // bit 3 - HPC_SLOT_PRSNT2 - // bit 4 - HPC_SLOT_PRSNT1 - if (((pslot->status & 0x08) != (poldslot->status & 0x08)) - || ((pslot->status & 0x10) != (poldslot->status & 0x10))) - update = TRUE; - - // bit 5 - HPC_SLOT_PWRGD - if ((pslot->status & 0x20) != (poldslot->status & 0x20)) - // OFF -> ON: ignore, ON -> OFF: disable slot - if ((poldslot->status & 0x20) && (SLOT_CONNECT (poldslot->status) == HPC_SLOT_CONNECTED) && (SLOT_PRESENT (poldslot->status))) - disable = TRUE; - - // bit 6 - HPC_SLOT_BUS_SPEED - // ignore - - // bit 7 - HPC_SLOT_LATCH - if ((pslot->status & 0x80) != (poldslot->status & 0x80)) { - update = TRUE; - // OPEN -> CLOSE - if (pslot->status & 0x80) { - if (SLOT_PWRGD (pslot->status)) { - // power goes on and off after closing latch - // check again to make sure power is still ON - long_delay (1 * HZ); - rc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &status); - if (SLOT_PWRGD (status)) - update = TRUE; - else // overwrite power in pslot to OFF - pslot->status &= ~HPC_SLOT_POWER; - } - } - // CLOSE -> OPEN - else if ((SLOT_PWRGD (poldslot->status) == HPC_SLOT_PWRGD_GOOD) - && (SLOT_CONNECT (poldslot->status) == HPC_SLOT_CONNECTED) && (SLOT_PRESENT (poldslot->status))) { - disable = TRUE; - } - // else - ignore - } - // bit 4 - HPC_SLOT_BLINK_ATTN - if ((pslot->ext_status & 0x08) != (poldslot->ext_status & 0x08)) - update = TRUE; - - if (disable) { - debug ("process_changeinstatus - disable slot\n"); - pslot->flag = FALSE; - rc = ibmphp_do_disable_slot (pslot); - } - - if (update || disable) { - ibmphp_update_slot_info (pslot); - } - - debug ("%s - Exit rc[%d] disable[%x] update[%x]\n", __FUNCTION__, rc, disable, update); - - return rc; -} - -/*---------------------------------------------------------------------- -* Name: process_changeinlatch -* -* Action: compare old and new latch reg status, process the change -* -* Input: old and current latch register status -* -* Return 0 or error codes -* Value: -*---------------------------------------------------------------------*/ -static int process_changeinlatch (u8 old, u8 new, struct controller *ctrl) -{ - struct slot myslot, *pslot; - u8 i; - u8 mask; - int rc = 0; - - debug ("%s - Entry old[%x], new[%x]\n", __FUNCTION__, old, new); - // bit 0 reserved, 0 is LSB, check bit 1-6 for 6 slots - - for (i = ctrl->starting_slot_num; i <= ctrl->ending_slot_num; i++) { - mask = 0x01 << i; - if ((mask & old) != (mask & new)) { - pslot = ibmphp_get_slot_from_physical_num (i); - if (pslot) { - memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); - rc = ibmphp_hpc_readslot (pslot, READ_ALLSTAT, NULL); - debug ("%s - call process_changeinstatus for slot[%d]\n", __FUNCTION__, i); - process_changeinstatus (pslot, &myslot); - } else { - rc = -EINVAL; - err ("%s - Error bad pointer for slot[%d]\n", __FUNCTION__, i); - } - } - } - debug ("%s - Exit rc[%d]\n", __FUNCTION__, rc); - return rc; -} - -/*---------------------------------------------------------------------- -* Name: hpc_poll_thread -* -* Action: polling -* -* Return 0 -* Value: -*---------------------------------------------------------------------*/ -static int hpc_poll_thread (void *data) -{ - debug ("%s - Entry\n", __FUNCTION__); - - daemonize("hpc_poll"); - allow_signal(SIGKILL); - - poll_hpc (); - - tid_poll = 0; - debug ("%s - Exit\n", __FUNCTION__); - return 0; -} - - -/*---------------------------------------------------------------------- -* Name: ibmphp_hpc_start_poll_thread -* -* Action: start polling thread -*---------------------------------------------------------------------*/ -int __init ibmphp_hpc_start_poll_thread (void) -{ - int rc = 0; - - debug ("%s - Entry\n", __FUNCTION__); - - tid_poll = kernel_thread (hpc_poll_thread, 0, 0); - if (tid_poll < 0) { - err ("%s - Error, thread not started\n", __FUNCTION__); - rc = -1; - } - - debug ("%s - Exit tid_poll[%d] rc[%d]\n", __FUNCTION__, tid_poll, rc); - return rc; -} - -/*---------------------------------------------------------------------- -* Name: ibmphp_hpc_stop_poll_thread -* -* Action: stop polling thread and cleanup -*---------------------------------------------------------------------*/ -void __exit ibmphp_hpc_stop_poll_thread (void) -{ - debug ("%s - Entry\n", __FUNCTION__); - - ibmphp_shutdown = TRUE; - debug ("before locking operations \n"); - ibmphp_lock_operations (); - debug ("after locking operations \n"); - - // wait for poll thread to exit - debug ("before sem_exit down \n"); - down (&sem_exit); - debug ("after sem_exit down \n"); - - // cleanup - debug ("before free_hpc_access \n"); - free_hpc_access (); - debug ("after free_hpc_access \n"); - ibmphp_unlock_operations (); - debug ("after unlock operations \n"); - up (&sem_exit); - debug ("after sem exit up\n"); - - debug ("%s - Exit\n", __FUNCTION__); -} - -/*---------------------------------------------------------------------- -* Name: hpc_wait_ctlr_notworking -* -* Action: wait until the controller is in a not working state -* -* Return 0, HPC_ERROR -* Value: -*---------------------------------------------------------------------*/ -static int hpc_wait_ctlr_notworking (int timeout, struct controller *ctlr_ptr, void *wpg_bbar, - u8 * pstatus) -{ - int rc = 0; - u8 done = FALSE; - - debug_polling ("hpc_wait_ctlr_notworking - Entry timeout[%d]\n", timeout); - - while (!done) { - *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, WPG_CTLR_INDEX); - if (*pstatus == HPC_ERROR) { - rc = HPC_ERROR; - done = TRUE; - } - if (CTLR_WORKING (*pstatus) == HPC_CTLR_WORKING_NO) - done = TRUE; - if (!done) { - long_delay (1 * HZ); - if (timeout < 1) { - done = TRUE; - err ("HPCreadslot - Error ctlr timeout\n"); - rc = HPC_ERROR; - } else - timeout--; - } - } - debug_polling ("hpc_wait_ctlr_notworking - Exit rc[%x] status[%x]\n", rc, *pstatus); - return rc; -} diff -Nru a/drivers/hotplug/ibmphp_pci.c b/drivers/hotplug/ibmphp_pci.c --- a/drivers/hotplug/ibmphp_pci.c Mon Jun 9 23:16:05 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,1758 +0,0 @@ -/* - * IBM Hot Plug Controller Driver - * - * Written By: Irene Zubarev, IBM Corporation - * - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001,2002 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or - * NON INFRINGEMENT. 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. - * - * Send feedback to <gregkh@us.ibm.com> - * - */ - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/pci.h> -#include <linux/list.h> -#include "ibmphp.h" - - -static int configure_device(struct pci_func *); -static int configure_bridge(struct pci_func **, u8); -static struct res_needed *scan_behind_bridge(struct pci_func *, u8); -static int add_new_bus (struct bus_node *, struct resource_node *, struct resource_node *, struct resource_node *, u8); -static u8 find_sec_number (u8 primary_busno, u8 slotno); - -/* - * NOTE..... If BIOS doesn't provide default routing, we assign: - * 9 for SCSI, 10 for LAN adapters, and 11 for everything else. - * If adapter is bridged, then we assign 11 to it and devices behind it. - * We also assign the same irq numbers for multi function devices. - * These are PIC mode, so shouldn't matter n.e.ways (hopefully) - */ -static void assign_alt_irq (struct pci_func * cur_func, u8 class_code) -{ - int j = 0; - for (j = 0; j < 4; j++) { - if (cur_func->irq[j] == 0xff) { - switch (class_code) { - case PCI_BASE_CLASS_STORAGE: - cur_func->irq[j] = SCSI_IRQ; - break; - case PCI_BASE_CLASS_NETWORK: - cur_func->irq[j] = LAN_IRQ; - break; - default: - cur_func->irq[j] = OTHER_IRQ; - break; - } - } - } -} - -/* - * Configures the device to be added (will allocate needed resources if it - * can), the device can be a bridge or a regular pci device, can also be - * multi-functional - * - * Input: function to be added - * - * TO DO: The error case with Multifunction device or multi function bridge, - * if there is an error, will need to go through all previous functions and - * unconfigure....or can add some code into unconfigure_card.... - */ -int ibmphp_configure_card (struct pci_func *func, u8 slotno) -{ - u16 vendor_id; - u32 class; - u8 class_code; - u8 hdr_type, device, sec_number; - u8 function; - struct pci_func *newfunc; /* for multi devices */ - struct pci_func *cur_func, *prev_func; - int rc, i, j; - int cleanup_count; - u8 flag; - u8 valid_device = 0x00; /* to see if we are able to read from card any device info at all */ - - debug ("inside configure_card, func->busno = %x \n", func->busno); - - device = func->device; - cur_func = func; - - /* We only get bus and device from IRQ routing table. So at this point, - * func->busno is correct, and func->device contains only device (at the 5 - * highest bits) - */ - - /* For every function on the card */ - for (function = 0x00; function < 0x08; function++) { - unsigned int devfn = PCI_DEVFN(device, function); - ibmphp_pci_bus->number = cur_func->busno; - - cur_func->function = function; - - debug ("inside the loop, cur_func->busno = %x, cur_func->device = %x, cur_func->funcion = %x\n", - cur_func->busno, cur_func->device, cur_func->function); - - pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id); - - debug ("vendor_id is %x\n", vendor_id); - if (vendor_id != PCI_VENDOR_ID_NOTVALID) { - /* found correct device!!! */ - debug ("found valid device, vendor_id = %x\n", vendor_id); - - ++valid_device; - - /* header: x x x x x x x x - * | |___________|=> 1=PPB bridge, 0=normal device, 2=CardBus Bridge - * |_=> 0 = single function device, 1 = multi-function device - */ - - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type); - pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_CLASS_REVISION, &class); - - class_code = class >> 24; - debug ("hrd_type = %x, class = %x, class_code %x \n", hdr_type, class, class_code); - class >>= 8; /* to take revision out, class = class.subclass.prog i/f */ - if (class == PCI_CLASS_NOT_DEFINED_VGA) { - err ("The device %x is VGA compatible and as is not supported for hot plugging. " - "Please choose another device.\n", cur_func->device); - return -ENODEV; - } else if (class == PCI_CLASS_DISPLAY_VGA) { - err ("The device %x is not supported for hot plugging. " - "Please choose another device.\n", cur_func->device); - return -ENODEV; - } - switch (hdr_type) { - case PCI_HEADER_TYPE_NORMAL: - debug ("single device case.... vendor id = %x, hdr_type = %x, class = %x\n", vendor_id, hdr_type, class); - assign_alt_irq (cur_func, class_code); - if ((rc = configure_device (cur_func)) < 0) { - /* We need to do this in case some other BARs were properly inserted */ - err ("was not able to configure devfunc %x on bus %x. \n", - cur_func->device, cur_func->busno); - cleanup_count = 6; - goto error; - } - cur_func->next = NULL; - function = 0x8; - break; - case PCI_HEADER_TYPE_MULTIDEVICE: - assign_alt_irq (cur_func, class_code); - if ((rc = configure_device (cur_func)) < 0) { - /* We need to do this in case some other BARs were properly inserted */ - err ("was not able to configure devfunc %x on bus %x...bailing out\n", - cur_func->device, cur_func->busno); - cleanup_count = 6; - goto error; - } - newfunc = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); - if (!newfunc) { - err ("out of system memory \n"); - return -ENOMEM; - } - memset (newfunc, 0, sizeof (struct pci_func)); - newfunc->busno = cur_func->busno; - newfunc->device = device; - cur_func->next = newfunc; - cur_func = newfunc; - for (j = 0; j < 4; j++) - newfunc->irq[j] = cur_func->irq[j]; - break; - case PCI_HEADER_TYPE_MULTIBRIDGE: - class >>= 8; - if (class != PCI_CLASS_BRIDGE_PCI) { - err ("This %x is not PCI-to-PCI bridge, and as is not supported for hot-plugging. " - "Please insert another card.\n", cur_func->device); - return -ENODEV; - } - assign_alt_irq (cur_func, class_code); - rc = configure_bridge (&cur_func, slotno); - if (rc == -ENODEV) { - err ("You chose to insert Single Bridge, or nested bridges, this is not supported...\n"); - err ("Bus %x, devfunc %x \n", cur_func->busno, cur_func->device); - return rc; - } - if (rc) { - /* We need to do this in case some other BARs were properly inserted */ - err ("was not able to hot-add PPB properly.\n"); - func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */ - cleanup_count = 2; - goto error; - } - - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number); - flag = FALSE; - for (i = 0; i < 32; i++) { - if (func->devices[i]) { - newfunc = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); - if (!newfunc) { - err ("out of system memory \n"); - return -ENOMEM; - } - memset (newfunc, 0, sizeof (struct pci_func)); - newfunc->busno = sec_number; - newfunc->device = (u8) i; - for (j = 0; j < 4; j++) - newfunc->irq[j] = cur_func->irq[j]; - - if (flag) { - for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next) ; - prev_func->next = newfunc; - } else - cur_func->next = newfunc; - - rc = ibmphp_configure_card (newfunc, slotno); - /* This could only happen if kmalloc failed */ - if (rc) { - /* We need to do this in case bridge itself got configured properly, but devices behind it failed */ - func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */ - cleanup_count = 2; - goto error; - } - flag = TRUE; - } - } - - newfunc = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); - if (!newfunc) { - err ("out of system memory \n"); - return -ENOMEM; - } - memset (newfunc, 0, sizeof (struct pci_func)); - newfunc->busno = cur_func->busno; - newfunc->device = device; - for (j = 0; j < 4; j++) - newfunc->irq[j] = cur_func->irq[j]; - for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next) ; - prev_func->next = newfunc; - cur_func = newfunc; - break; - case PCI_HEADER_TYPE_BRIDGE: - class >>= 8; - debug ("class now is %x\n", class); - if (class != PCI_CLASS_BRIDGE_PCI) { - err ("This %x is not PCI-to-PCI bridge, and as is not supported for hot-plugging. " - "Please insert another card.\n", cur_func->device); - return -ENODEV; - } - - assign_alt_irq (cur_func, class_code); - - debug ("cur_func->busno b4 configure_bridge is %x\n", cur_func->busno); - rc = configure_bridge (&cur_func, slotno); - if (rc == -ENODEV) { - err ("You chose to insert Single Bridge, or nested bridges, this is not supported...\n"); - err ("Bus %x, devfunc %x \n", cur_func->busno, cur_func->device); - return rc; - } - if (rc) { - /* We need to do this in case some other BARs were properly inserted */ - func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */ - err ("was not able to hot-add PPB properly.\n"); - cleanup_count = 2; - goto error; - } - debug ("cur_func->busno = %x, device = %x, function = %x\n", - cur_func->busno, device, function); - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number); - debug ("after configuring bridge..., sec_number = %x\n", sec_number); - flag = FALSE; - for (i = 0; i < 32; i++) { - if (func->devices[i]) { - debug ("inside for loop, device is %x\n", i); - newfunc = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); - if (!newfunc) { - err (" out of system memory \n"); - return -ENOMEM; - } - memset (newfunc, 0, sizeof (struct pci_func)); - newfunc->busno = sec_number; - newfunc->device = (u8) i; - for (j = 0; j < 4; j++) - newfunc->irq[j] = cur_func->irq[j]; - - if (flag) { - for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next) ; - prev_func->next = newfunc; - } else - cur_func->next = newfunc; - - rc = ibmphp_configure_card (newfunc, slotno); - - /* Again, this case should not happen... For complete paranoia, will need to call remove_bus */ - if (rc) { - /* We need to do this in case some other BARs were properly inserted */ - func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */ - cleanup_count = 2; - goto error; - } - flag = TRUE; - } - } - - function = 0x8; - break; - default: - err ("MAJOR PROBLEM!!!!, header type not supported? %x\n", hdr_type); - return -ENXIO; - break; - } /* end of switch */ - } /* end of valid device */ - } /* end of for */ - - if (!valid_device) { - err ("Cannot find any valid devices on the card. Or unable to read from card.\n"); - return -ENODEV; - } - - return 0; - -error: - for (i = 0; i < cleanup_count; i++) { - if (cur_func->io[i]) { - ibmphp_remove_resource (cur_func->io[i]); - cur_func->io[i] = NULL; - } else if (cur_func->pfmem[i]) { - ibmphp_remove_resource (cur_func->pfmem[i]); - cur_func->pfmem[i] = NULL; - } else if (cur_func->mem[i]) { - ibmphp_remove_resource (cur_func->mem[i]); - cur_func->mem[i] = NULL; - } - } - return rc; -} - -/* - * This function configures the pci BARs of a single device. - * Input: pointer to the pci_func - * Output: configured PCI, 0, or error - */ -static int configure_device (struct pci_func *func) -{ - u32 bar[6]; - u32 address[] = { - PCI_BASE_ADDRESS_0, - PCI_BASE_ADDRESS_1, - PCI_BASE_ADDRESS_2, - PCI_BASE_ADDRESS_3, - PCI_BASE_ADDRESS_4, - PCI_BASE_ADDRESS_5, - 0 - }; - u8 irq; - int count; - int len[6]; - struct resource_node *io[6]; - struct resource_node *mem[6]; - struct resource_node *mem_tmp; - struct resource_node *pfmem[6]; - unsigned int devfn; - - debug ("%s - inside\n", __FUNCTION__); - - devfn = PCI_DEVFN(func->device, func->function); - ibmphp_pci_bus->number = func->busno; - - for (count = 0; address[count]; count++) { /* for 6 BARs */ - - /* not sure if i need this. per scott, said maybe need smth like this - if devices don't adhere 100% to the spec, so don't want to write - to the reserved bits - - pcibios_read_config_byte(cur_func->busno, cur_func->device, - PCI_BASE_ADDRESS_0 + 4 * count, &tmp); - if (tmp & 0x01) // IO - pcibios_write_config_dword(cur_func->busno, cur_func->device, - PCI_BASE_ADDRESS_0 + 4 * count, 0xFFFFFFFD); - else // Memory - pcibios_write_config_dword(cur_func->busno, cur_func->device, - PCI_BASE_ADDRESS_0 + 4 * count, 0xFFFFFFFF); - */ - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF); - pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]); - - if (!bar[count]) /* This BAR is not implemented */ - continue; - - debug ("Device %x BAR %d wants %x\n", func->device, count, bar[count]); - - if (bar[count] & PCI_BASE_ADDRESS_SPACE_IO) { - /* This is IO */ - debug ("inside IO SPACE\n"); - - len[count] = bar[count] & 0xFFFFFFFC; - len[count] = ~len[count] + 1; - - debug ("len[count] in IO %x, count %d\n", len[count], count); - - io[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - - if (!io[count]) { - err ("out of system memory \n"); - return -ENOMEM; - } - memset (io[count], 0, sizeof (struct resource_node)); - io[count]->type = IO; - io[count]->busno = func->busno; - io[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); - io[count]->len = len[count]; - if (ibmphp_check_resource(io[count], 0) == 0) { - ibmphp_add_resource (io[count]); - func->io[count] = io[count]; - } else { - err ("cannot allocate requested io for bus %x device %x function %x len %x\n", - func->busno, func->device, func->function, len[count]); - kfree (io[count]); - return -EIO; - } - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->io[count]->start); - - /* _______________This is for debugging purposes only_____________________ */ - debug ("b4 writing, the IO address is %x\n", func->io[count]->start); - pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]); - debug ("after writing.... the start address is %x\n", bar[count]); - /* _________________________________________________________________________*/ - - } else { - /* This is Memory */ - if (bar[count] & PCI_BASE_ADDRESS_MEM_PREFETCH) { - /* pfmem */ - debug ("PFMEM SPACE\n"); - - len[count] = bar[count] & 0xFFFFFFF0; - len[count] = ~len[count] + 1; - - debug ("len[count] in PFMEM %x, count %d\n", len[count], count); - - pfmem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - if (!pfmem[count]) { - err ("out of system memory \n"); - return -ENOMEM; - } - memset (pfmem[count], 0, sizeof (struct resource_node)); - pfmem[count]->type = PFMEM; - pfmem[count]->busno = func->busno; - pfmem[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); - pfmem[count]->len = len[count]; - pfmem[count]->fromMem = FALSE; - if (ibmphp_check_resource (pfmem[count], 0) == 0) { - ibmphp_add_resource (pfmem[count]); - func->pfmem[count] = pfmem[count]; - } else { - mem_tmp = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - if (!mem_tmp) { - err ("out of system memory \n"); - kfree (pfmem[count]); - return -ENOMEM; - } - memset (mem_tmp, 0, sizeof (struct resource_node)); - mem_tmp->type = MEM; - mem_tmp->busno = pfmem[count]->busno; - mem_tmp->devfunc = pfmem[count]->devfunc; - mem_tmp->len = pfmem[count]->len; - debug ("there's no pfmem... going into mem.\n"); - if (ibmphp_check_resource (mem_tmp, 0) == 0) { - ibmphp_add_resource (mem_tmp); - pfmem[count]->fromMem = TRUE; - pfmem[count]->rangeno = mem_tmp->rangeno; - pfmem[count]->start = mem_tmp->start; - pfmem[count]->end = mem_tmp->end; - ibmphp_add_pfmem_from_mem (pfmem[count]); - func->pfmem[count] = pfmem[count]; - } else { - err ("cannot allocate requested pfmem for bus %x, device %x, len %x\n", - func->busno, func->device, len[count]); - kfree (mem_tmp); - kfree (pfmem[count]); - return -EIO; - } - } - - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->pfmem[count]->start); - - /*_______________This is for debugging purposes only______________________________*/ - debug ("b4 writing, start address is %x\n", func->pfmem[count]->start); - pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]); - debug ("after writing, start address is %x\n", bar[count]); - /*_________________________________________________________________________________*/ - - if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */ - debug ("inside the mem 64 case, count %d\n", count); - count += 1; - /* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */ - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0x00000000); - } - } else { - /* regular memory */ - debug ("REGULAR MEM SPACE\n"); - - len[count] = bar[count] & 0xFFFFFFF0; - len[count] = ~len[count] + 1; - - debug ("len[count] in Mem %x, count %d\n", len[count], count); - - mem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - if (!mem[count]) { - err ("out of system memory \n"); - return -ENOMEM; - } - memset (mem[count], 0, sizeof (struct resource_node)); - mem[count]->type = MEM; - mem[count]->busno = func->busno; - mem[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); - mem[count]->len = len[count]; - if (ibmphp_check_resource (mem[count], 0) == 0) { - ibmphp_add_resource (mem[count]); - func->mem[count] = mem[count]; - } else { - err ("cannot allocate requested mem for bus %x, device %x, len %x\n", - func->busno, func->device, len[count]); - kfree (mem[count]); - return -EIO; - } - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->mem[count]->start); - /* _______________________This is for debugging purposes only _______________________*/ - debug ("b4 writing, start address is %x\n", func->mem[count]->start); - pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]); - debug ("after writing, the address is %x\n", bar[count]); - /* __________________________________________________________________________________*/ - - if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) { - /* takes up another dword */ - debug ("inside mem 64 case, reg. mem, count %d\n", count); - count += 1; - /* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */ - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0x00000000); - } - } - } /* end of mem */ - } /* end of for */ - - func->bus = 0; /* To indicate that this is not a PPB */ - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_INTERRUPT_PIN, &irq); - if ((irq > 0x00) && (irq < 0x05)) - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_INTERRUPT_LINE, func->irq[irq - 1]); - - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_CACHE_LINE_SIZE, CACHE); - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_LATENCY_TIMER, LATENCY); - - pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_ROM_ADDRESS, 0x00L); - pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_COMMAND, DEVICEENABLE); - - return 0; -} - -/****************************************************************************** - * This routine configures a PCI-2-PCI bridge and the functions behind it - * Parameters: pci_func - * Returns: - ******************************************************************************/ -static int configure_bridge (struct pci_func **func_passed, u8 slotno) -{ - int count; - int i; - int rc; - u8 sec_number; - u8 io_base; - u16 pfmem_base; - u32 bar[2]; - u32 len[2]; - u8 flag_io = FALSE; - u8 flag_mem = FALSE; - u8 flag_pfmem = FALSE; - u8 need_io_upper = FALSE; - u8 need_pfmem_upper = FALSE; - struct res_needed *amount_needed = NULL; - struct resource_node *io = NULL; - struct resource_node *bus_io[2] = {NULL, NULL}; - struct resource_node *mem = NULL; - struct resource_node *bus_mem[2] = {NULL, NULL}; - struct resource_node *mem_tmp = NULL; - struct resource_node *pfmem = NULL; - struct resource_node *bus_pfmem[2] = {NULL, NULL}; - struct bus_node *bus; - u32 address[] = { - PCI_BASE_ADDRESS_0, - PCI_BASE_ADDRESS_1, - 0 - }; - struct pci_func *func = *func_passed; - unsigned int devfn; - u8 irq; - int retval; - - debug ("%s - enter\n", __FUNCTION__); - - devfn = PCI_DEVFN(func->function, func->device); - ibmphp_pci_bus->number = func->busno; - - /* Configuring necessary info for the bridge so that we could see the devices - * behind it - */ - - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_PRIMARY_BUS, func->busno); - - /* _____________________For debugging purposes only __________________________ - pci_bus_config_byte (ibmphp_pci_bus, devfn, PCI_PRIMARY_BUS, &pri_number); - debug ("primary # written into the bridge is %x\n", pri_number); - ___________________________________________________________________________*/ - - /* in EBDA, only get allocated 1 additional bus # per slot */ - sec_number = find_sec_number (func->busno, slotno); - if (sec_number == 0xff) { - err ("cannot allocate secondary bus number for the bridged device \n"); - return -EINVAL; - } - - debug ("after find_sec_number, the number we got is %x\n", sec_number); - debug ("AFTER FIND_SEC_NUMBER, func->busno IS %x\n", func->busno); - - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, sec_number); - - /* __________________For debugging purposes only __________________________________ - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number); - debug ("sec_number after write/read is %x\n", sec_number); - ________________________________________________________________________________*/ - - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_SUBORDINATE_BUS, sec_number); - - /* __________________For debugging purposes only ____________________________________ - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SUBORDINATE_BUS, &sec_number); - debug ("subordinate number after write/read is %x\n", sec_number); - __________________________________________________________________________________*/ - - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_CACHE_LINE_SIZE, CACHE); - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_LATENCY_TIMER, LATENCY); - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_SEC_LATENCY_TIMER, LATENCY); - - debug ("func->busno is %x\n", func->busno); - debug ("sec_number after writing is %x\n", sec_number); - - - /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - !!!!!!!!!!!!!!!NEED TO ADD!!! FAST BACK-TO-BACK ENABLE!!!!!!!!!!!!!!!!!!!! - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ - - - /* First we need to allocate mem/io for the bridge itself in case it needs it */ - for (count = 0; address[count]; count++) { /* for 2 BARs */ - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF); - pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]); - - if (!bar[count]) { - /* This BAR is not implemented */ - debug ("so we come here then, eh?, count = %d\n", count); - continue; - } - // tmp_bar = bar[count]; - - debug ("Bar %d wants %x\n", count, bar[count]); - - if (bar[count] & PCI_BASE_ADDRESS_SPACE_IO) { - /* This is IO */ - len[count] = bar[count] & 0xFFFFFFFC; - len[count] = ~len[count] + 1; - - debug ("len[count] in IO = %x\n", len[count]); - - bus_io[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - - if (!bus_io[count]) { - err ("out of system memory \n"); - retval = -ENOMEM; - goto error; - } - memset (bus_io[count], 0, sizeof (struct resource_node)); - bus_io[count]->type = IO; - bus_io[count]->busno = func->busno; - bus_io[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); - bus_io[count]->len = len[count]; - if (ibmphp_check_resource (bus_io[count], 0) == 0) { - ibmphp_add_resource (bus_io[count]); - func->io[count] = bus_io[count]; - } else { - err ("cannot allocate requested io for bus %x, device %x, len %x\n", - func->busno, func->device, len[count]); - kfree (bus_io[count]); - return -EIO; - } - - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->io[count]->start); - - } else { - /* This is Memory */ - if (bar[count] & PCI_BASE_ADDRESS_MEM_PREFETCH) { - /* pfmem */ - len[count] = bar[count] & 0xFFFFFFF0; - len[count] = ~len[count] + 1; - - debug ("len[count] in PFMEM = %x\n", len[count]); - - bus_pfmem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - if (!bus_pfmem[count]) { - err ("out of system memory \n"); - retval = -ENOMEM; - goto error; - } - memset (bus_pfmem[count], 0, sizeof (struct resource_node)); - bus_pfmem[count]->type = PFMEM; - bus_pfmem[count]->busno = func->busno; - bus_pfmem[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); - bus_pfmem[count]->len = len[count]; - bus_pfmem[count]->fromMem = FALSE; - if (ibmphp_check_resource (bus_pfmem[count], 0) == 0) { - ibmphp_add_resource (bus_pfmem[count]); - func->pfmem[count] = bus_pfmem[count]; - } else { - mem_tmp = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - if (!mem_tmp) { - err ("out of system memory \n"); - retval = -ENOMEM; - goto error; - } - memset (mem_tmp, 0, sizeof (struct resource_node)); - mem_tmp->type = MEM; - mem_tmp->busno = bus_pfmem[count]->busno; - mem_tmp->devfunc = bus_pfmem[count]->devfunc; - mem_tmp->len = bus_pfmem[count]->len; - if (ibmphp_check_resource (mem_tmp, 0) == 0) { - ibmphp_add_resource (mem_tmp); - bus_pfmem[count]->fromMem = TRUE; - bus_pfmem[count]->rangeno = mem_tmp->rangeno; - ibmphp_add_pfmem_from_mem (bus_pfmem[count]); - func->pfmem[count] = bus_pfmem[count]; - } else { - err ("cannot allocate requested pfmem for bus %x, device %x, len %x\n", - func->busno, func->device, len[count]); - kfree (mem_tmp); - kfree (bus_pfmem[count]); - return -EIO; - } - } - - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->pfmem[count]->start); - - if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) { - /* takes up another dword */ - count += 1; - /* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */ - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0x00000000); - - } - } else { - /* regular memory */ - len[count] = bar[count] & 0xFFFFFFF0; - len[count] = ~len[count] + 1; - - debug ("len[count] in Memory is %x\n", len[count]); - - bus_mem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - if (!bus_mem[count]) { - err ("out of system memory \n"); - retval = -ENOMEM; - goto error; - } - memset (bus_mem[count], 0, sizeof (struct resource_node)); - bus_mem[count]->type = MEM; - bus_mem[count]->busno = func->busno; - bus_mem[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); - bus_mem[count]->len = len[count]; - if (ibmphp_check_resource (bus_mem[count], 0) == 0) { - ibmphp_add_resource (bus_mem[count]); - func->mem[count] = bus_mem[count]; - } else { - err ("cannot allocate requested mem for bus %x, device %x, len %x\n", - func->busno, func->device, len[count]); - kfree (bus_mem[count]); - return -EIO; - } - - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->mem[count]->start); - - if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) { - /* takes up another dword */ - count += 1; - /* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */ - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0x00000000); - - } - } - } /* end of mem */ - } /* end of for */ - - /* Now need to see how much space the devices behind the bridge needed */ - amount_needed = scan_behind_bridge (func, sec_number); - if (amount_needed == NULL) - return -ENOMEM; - - ibmphp_pci_bus->number = func->busno; - debug ("after coming back from scan_behind_bridge\n"); - debug ("amount_needed->not_correct = %x\n", amount_needed->not_correct); - debug ("amount_needed->io = %x\n", amount_needed->io); - debug ("amount_needed->mem = %x\n", amount_needed->mem); - debug ("amount_needed->pfmem = %x\n", amount_needed->pfmem); - - if (amount_needed->not_correct) { - debug ("amount_needed is not correct \n"); - for (count = 0; address[count]; count++) { - /* for 2 BARs */ - if (bus_io[count]) { - ibmphp_remove_resource (bus_io[count]); - func->io[count] = NULL; - } else if (bus_pfmem[count]) { - ibmphp_remove_resource (bus_pfmem[count]); - func->pfmem[count] = NULL; - } else if (bus_mem[count]) { - ibmphp_remove_resource (bus_mem[count]); - func->mem[count] = NULL; - } - } - kfree (amount_needed); - return -ENODEV; - } - - if (!amount_needed->io) { - debug ("it doesn't want IO?\n"); - flag_io = TRUE; - } else { - debug ("it wants %x IO behind the bridge \n", amount_needed->io); - io = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - - if (!io) { - err ("out of system memory \n"); - retval = -ENOMEM; - goto error; - } - memset (io, 0, sizeof (struct resource_node)); - io->type = IO; - io->busno = func->busno; - io->devfunc = ((func->device << 3) | (func->function & 0x7)); - io->len = amount_needed->io; - if (ibmphp_check_resource (io, 1) == 0) { - debug ("were we able to add io\n"); - ibmphp_add_resource (io); - flag_io = TRUE; - } - } - - if (!amount_needed->mem) { - debug ("it doesn't want n.e.memory?\n"); - flag_mem = TRUE; - } else { - debug ("it wants %x memory behind the bridge\n", amount_needed->mem); - mem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - if (!mem) { - err ("out of system memory \n"); - retval = -ENOMEM; - goto error; - } - memset (mem, 0, sizeof (struct resource_node)); - mem->type = MEM; - mem->busno = func->busno; - mem->devfunc = ((func->device << 3) | (func->function & 0x7)); - mem->len = amount_needed->mem; - if (ibmphp_check_resource (mem, 1) == 0) { - ibmphp_add_resource (mem); - flag_mem = TRUE; - debug ("were we able to add mem\n"); - } - } - - if (!amount_needed->pfmem) { - debug ("it doesn't want n.e.pfmem mem?\n"); - flag_pfmem = TRUE; - } else { - debug ("it wants %x pfmemory behind the bridge\n", amount_needed->pfmem); - pfmem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - if (!pfmem) { - err ("out of system memory \n"); - retval = -ENOMEM; - goto error; - } - memset (pfmem, 0, sizeof (struct resource_node)); - pfmem->type = PFMEM; - pfmem->busno = func->busno; - pfmem->devfunc = ((func->device << 3) | (func->function & 0x7)); - pfmem->len = amount_needed->pfmem; - pfmem->fromMem = FALSE; - if (ibmphp_check_resource (pfmem, 1) == 0) { - ibmphp_add_resource (pfmem); - flag_pfmem = TRUE; - } else { - mem_tmp = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - if (!mem_tmp) { - err ("out of system memory \n"); - retval = -ENOMEM; - goto error; - } - memset (mem_tmp, 0, sizeof (struct resource_node)); - mem_tmp->type = MEM; - mem_tmp->busno = pfmem->busno; - mem_tmp->devfunc = pfmem->devfunc; - mem_tmp->len = pfmem->len; - if (ibmphp_check_resource (mem_tmp, 1) == 0) { - ibmphp_add_resource (mem_tmp); - pfmem->fromMem = TRUE; - pfmem->rangeno = mem_tmp->rangeno; - ibmphp_add_pfmem_from_mem (pfmem); - flag_pfmem = TRUE; - } - } - } - - debug ("b4 if (flag_io && flag_mem && flag_pfmem)\n"); - debug ("flag_io = %x, flag_mem = %x, flag_pfmem = %x\n", flag_io, flag_mem, flag_pfmem); - - if (flag_io && flag_mem && flag_pfmem) { - /* If on bootup, there was a bridged card in this slot, - * then card was removed and ibmphp got unloaded and loaded - * back again, there's no way for us to remove the bus - * struct, so no need to kmalloc, can use existing node - */ - bus = ibmphp_find_res_bus (sec_number); - if (!bus) { - bus = kmalloc (sizeof (struct bus_node), GFP_KERNEL); - if (!bus) { - err ("out of system memory \n"); - retval = -ENOMEM; - goto error; - } - memset (bus, 0, sizeof (struct bus_node)); - bus->busno = sec_number; - debug ("b4 adding new bus\n"); - rc = add_new_bus (bus, io, mem, pfmem, func->busno); - } else if (!(bus->rangeIO) && !(bus->rangeMem) && !(bus->rangePFMem)) - rc = add_new_bus (bus, io, mem, pfmem, 0xFF); - else { - err ("expected bus structure not empty? \n"); - retval = -EIO; - goto error; - } - if (rc) { - if (rc == -ENOMEM) { - ibmphp_remove_bus (bus, func->busno); - kfree (amount_needed); - return rc; - } - retval = rc; - goto error; - } - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, &io_base); - pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, &pfmem_base); - - if ((io_base & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) { - debug ("io 32\n"); - need_io_upper = TRUE; - } - if ((io_base & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) { - debug ("pfmem 64\n"); - need_pfmem_upper = TRUE; - } - - if (bus->noIORanges) { - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, 0x00 | bus->rangeIO->start >> 8); - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_IO_LIMIT, 0x00 | bus->rangeIO->end >> 8); - - /* _______________This is for debugging purposes only ____________________ - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, &temp); - debug ("io_base = %x\n", (temp & PCI_IO_RANGE_TYPE_MASK) << 8); - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_LIMIT, &temp); - debug ("io_limit = %x\n", (temp & PCI_IO_RANGE_TYPE_MASK) << 8); - ________________________________________________________________________*/ - - if (need_io_upper) { /* since can't support n.e.ways */ - pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_IO_BASE_UPPER16, 0x0000); - pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_IO_LIMIT_UPPER16, 0x0000); - } - } else { - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, 0x00); - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_IO_LIMIT, 0x00); - } - - if (bus->noMemRanges) { - pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_BASE, 0x0000 | bus->rangeMem->start >> 16); - pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_LIMIT, 0x0000 | bus->rangeMem->end >> 16); - - /* ____________________This is for debugging purposes only ________________________ - pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_BASE, &temp); - debug ("mem_base = %x\n", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16); - pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_LIMIT, &temp); - debug ("mem_limit = %x\n", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16); - __________________________________________________________________________________*/ - - } else { - pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_BASE, 0xffff); - pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_LIMIT, 0x0000); - } - if (bus->noPFMemRanges) { - pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, 0x0000 | bus->rangePFMem->start >> 16); - pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, 0x0000 | bus->rangePFMem->end >> 16); - - /* __________________________This is for debugging purposes only _______________________ - pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, &temp); - debug ("pfmem_base = %x", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16); - pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &temp); - debug ("pfmem_limit = %x\n", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16); - ______________________________________________________________________________________*/ - - if (need_pfmem_upper) { /* since can't support n.e.ways */ - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, PCI_PREF_BASE_UPPER32, 0x00000000); - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, PCI_PREF_LIMIT_UPPER32, 0x00000000); - } - } else { - pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, 0xffff); - pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, 0x0000); - } - - debug ("b4 writing control information\n"); - - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_INTERRUPT_PIN, &irq); - if ((irq > 0x00) && (irq < 0x05)) - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_INTERRUPT_LINE, func->irq[irq - 1]); - /* - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_BRIDGE_CONTROL, ctrl); - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_PARITY); - pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_SERR); - */ - - pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_COMMAND, DEVICEENABLE); - pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_BRIDGE_CONTROL, 0x07); - for (i = 0; i < 32; i++) { - if (amount_needed->devices[i]) { - debug ("device where devices[i] is 1 = %x\n", i); - func->devices[i] = 1; - } - } - func->bus = 1; /* For unconfiguring, to indicate it's PPB */ - func_passed = &func; - debug ("func->busno b4 returning is %x\n", func->busno); - debug ("func->busno b4 returning in the other structure is %x\n", (*func_passed)->busno); - kfree (amount_needed); - return 0; - } else { - err ("Configuring bridge was unsuccessful... \n"); - mem_tmp = NULL; - retval = -EIO; - goto error; - } - -error: - if (amount_needed) - kfree (amount_needed); - if (pfmem) - ibmphp_remove_resource (pfmem); - if (io) - ibmphp_remove_resource (io); - if (mem) - ibmphp_remove_resource (mem); - for (i = 0; i < 2; i++) { /* for 2 BARs */ - if (bus_io[i]) { - ibmphp_remove_resource (bus_io[i]); - func->io[i] = NULL; - } else if (bus_pfmem[i]) { - ibmphp_remove_resource (bus_pfmem[i]); - func->pfmem[i] = NULL; - } else if (bus_mem[i]) { - ibmphp_remove_resource (bus_mem[i]); - func->mem[i] = NULL; - } - } - return retval; -} - -/***************************************************************************** - * This function adds up the amount of resources needed behind the PPB bridge - * and passes it to the configure_bridge function - * Input: bridge function - * Ouput: amount of resources needed - *****************************************************************************/ -static struct res_needed *scan_behind_bridge (struct pci_func * func, u8 busno) -{ - int count, len[6]; - u16 vendor_id; - u8 hdr_type; - u8 device, function; - unsigned int devfn; - int howmany = 0; /*this is to see if there are any devices behind the bridge */ - - u32 bar[6], class; - u32 address[] = { - PCI_BASE_ADDRESS_0, - PCI_BASE_ADDRESS_1, - PCI_BASE_ADDRESS_2, - PCI_BASE_ADDRESS_3, - PCI_BASE_ADDRESS_4, - PCI_BASE_ADDRESS_5, - 0 - }; - struct res_needed *amount; - - amount = kmalloc (sizeof (struct res_needed), GFP_KERNEL); - if (amount == NULL) - return NULL; - memset (amount, 0, sizeof (struct res_needed)); - - ibmphp_pci_bus->number = busno; - - debug ("the bus_no behind the bridge is %x\n", busno); - debug ("scanning devices behind the bridge...\n"); - for (device = 0; device < 32; device++) { - amount->devices[device] = 0; - for (function = 0; function < 8; function++) { - devfn = PCI_DEVFN(device, function); - - pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id); - - if (vendor_id != PCI_VENDOR_ID_NOTVALID) { - /* found correct device!!! */ - howmany++; - - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type); - pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_CLASS_REVISION, &class); - - debug ("hdr_type behind the bridge is %x\n", hdr_type); - if (hdr_type & PCI_HEADER_TYPE_BRIDGE) { - err ("embedded bridges not supported for hot-plugging.\n"); - amount->not_correct = TRUE; - return amount; - } - - class >>= 8; /* to take revision out, class = class.subclass.prog i/f */ - if (class == PCI_CLASS_NOT_DEFINED_VGA) { - err ("The device %x is VGA compatible and as is not supported for hot plugging. " - "Please choose another device.\n", device); - amount->not_correct = TRUE; - return amount; - } else if (class == PCI_CLASS_DISPLAY_VGA) { - err ("The device %x is not supported for hot plugging. " - "Please choose another device.\n", device); - amount->not_correct = TRUE; - return amount; - } - - amount->devices[device] = 1; - - for (count = 0; address[count]; count++) { - /* for 6 BARs */ - /* - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, address[count], &tmp); - if (tmp & 0x01) // IO - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFD); - else // MEMORY - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF); - */ - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF); - pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]); - - debug ("what is bar[count]? %x, count = %d\n", bar[count], count); - - if (!bar[count]) /* This BAR is not implemented */ - continue; - - //tmp_bar = bar[count]; - - debug ("count %d device %x function %x wants %x resources \n", count, device, function, bar[count]); - - if (bar[count] & PCI_BASE_ADDRESS_SPACE_IO) { - /* This is IO */ - len[count] = bar[count] & 0xFFFFFFFC; - len[count] = ~len[count] + 1; - amount->io += len[count]; - } else { - /* This is Memory */ - if (bar[count] & PCI_BASE_ADDRESS_MEM_PREFETCH) { - /* pfmem */ - len[count] = bar[count] & 0xFFFFFFF0; - len[count] = ~len[count] + 1; - amount->pfmem += len[count]; - if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) - /* takes up another dword */ - count += 1; - - } else { - /* regular memory */ - len[count] = bar[count] & 0xFFFFFFF0; - len[count] = ~len[count] + 1; - amount->mem += len[count]; - if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) { - /* takes up another dword */ - count += 1; - } - } - } - } /* end for */ - } /* end if (valid) */ - } /* end for */ - } /* end for */ - - if (!howmany) - amount->not_correct = TRUE; - else - amount->not_correct = FALSE; - if ((amount->io) && (amount->io < IOBRIDGE)) - amount->io = IOBRIDGE; - if ((amount->mem) && (amount->mem < MEMBRIDGE)) - amount->mem = MEMBRIDGE; - if ((amount->pfmem) && (amount->pfmem < MEMBRIDGE)) - amount->pfmem = MEMBRIDGE; - return amount; -} - -/* The following 3 unconfigure_boot_ routines deal with the case when we had the card - * upon bootup in the system, since we don't allocate func to such case, we need to read - * the start addresses from pci config space and then find the corresponding entries in - * our resource lists. The functions return either 0, -ENODEV, or -1 (general failure) - * Change: we also call these functions even if we configured the card ourselves (i.e., not - * the bootup case), since it should work same way - */ -static int unconfigure_boot_device (u8 busno, u8 device, u8 function) -{ - u32 start_address; - u32 address[] = { - PCI_BASE_ADDRESS_0, - PCI_BASE_ADDRESS_1, - PCI_BASE_ADDRESS_2, - PCI_BASE_ADDRESS_3, - PCI_BASE_ADDRESS_4, - PCI_BASE_ADDRESS_5, - 0 - }; - int count; - struct resource_node *io; - struct resource_node *mem; - struct resource_node *pfmem; - struct bus_node *bus; - u32 end_address; - u32 temp_end; - u32 size; - u32 tmp_address; - unsigned int devfn; - - debug ("%s - enter\n", __FUNCTION__); - - bus = ibmphp_find_res_bus (busno); - if (!bus) { - debug ("cannot find corresponding bus.\n"); - return -EINVAL; - } - - devfn = PCI_DEVFN(device, function); - ibmphp_pci_bus->number = busno; - for (count = 0; address[count]; count++) { /* for 6 BARs */ - pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &start_address); - - /* We can do this here, b/c by that time the device driver of the card has been stopped */ - - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF); - pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &size); - pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], start_address); - - debug ("start_address is %x\n", start_address); - debug ("busno, device, function %x %x %x\n", busno, device, function); - if (!size) { - /* This BAR is not implemented */ - debug ("is this bar no implemented?, count = %d\n", count); - continue; - } - tmp_address = start_address; - if (start_address & PCI_BASE_ADDRESS_SPACE_IO) { - /* This is IO */ - start_address &= PCI_BASE_ADDRESS_IO_MASK; - size = size & 0xFFFFFFFC; - size = ~size + 1; - end_address = start_address + size - 1; - if (ibmphp_find_resource (bus, start_address, &io, IO) < 0) { - err ("cannot find corresponding IO resource to remove\n"); - return -EIO; - } - debug ("io->start = %x\n", io->start); - temp_end = io->end; - start_address = io->end + 1; - ibmphp_remove_resource (io); - /* This is needed b/c of the old I/O restrictions in the BIOS */ - while (temp_end < end_address) { - if (ibmphp_find_resource (bus, start_address, &io, IO) < 0) { - err ("cannot find corresponding IO resource to remove\n"); - return -EIO; - } - debug ("io->start = %x\n", io->start); - temp_end = io->end; - start_address = io->end + 1; - ibmphp_remove_resource (io); - } - - /* ????????? DO WE NEED TO WRITE ANYTHING INTO THE PCI CONFIG SPACE BACK ?????????? */ - } else { - /* This is Memory */ - if (start_address & PCI_BASE_ADDRESS_MEM_PREFETCH) { - /* pfmem */ - start_address &= PCI_BASE_ADDRESS_MEM_MASK; - debug ("start address of pfmem is %x\n", start_address); - - if (ibmphp_find_resource (bus, start_address, &pfmem, PFMEM) < 0) { - err ("cannot find corresponding PFMEM resource to remove\n"); - return -EIO; - } - if (pfmem) - debug ("pfmem->start = %x\n", pfmem->start); - - ibmphp_remove_resource (pfmem); - - if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) { - /* takes up another dword */ - count += 1; - } - - } else { - /* regular memory */ - start_address &= PCI_BASE_ADDRESS_MEM_MASK; - debug ("start address of mem is %x\n", start_address); - if (ibmphp_find_resource (bus, start_address, &mem, MEM) < 0) { - err ("cannot find corresponding MEM resource to remove\n"); - return -EIO; - } - if (mem) - debug ("mem->start = %x\n", mem->start); - - ibmphp_remove_resource (mem); - - if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) { - /* takes up another dword */ - count += 1; - } - } - } /* end of mem */ - } /* end of for */ - - return 0; -} - -static int unconfigure_boot_bridge (u8 busno, u8 device, u8 function) -{ - int count; - int bus_no, pri_no, sub_no, sec_no = 0; - u32 start_address, tmp_address; - u8 sec_number, sub_number, pri_number; - struct resource_node *io = NULL; - struct resource_node *mem = NULL; - struct resource_node *pfmem = NULL; - struct bus_node *bus; - u32 address[] = { - PCI_BASE_ADDRESS_0, - PCI_BASE_ADDRESS_1, - 0 - }; - unsigned int devfn; - - devfn = PCI_DEVFN(device, function); - ibmphp_pci_bus->number = busno; - bus_no = (int) busno; - debug ("busno is %x\n", busno); - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_PRIMARY_BUS, &pri_number); - debug ("%s - busno = %x, primary_number = %x\n", __FUNCTION__, busno, pri_number); - - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number); - debug ("sec_number is %x\n", sec_number); - sec_no = (int) sec_number; - pri_no = (int) pri_number; - if (pri_no != bus_no) { - err ("primary numbers in our structures and pci config space don't match.\n"); - return -EINVAL; - } - - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number); - sec_no = (int) sec_no; - - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SUBORDINATE_BUS, &sub_number); - sub_no = (int) sub_number; - debug ("sub_no is %d, sec_no is %d\n", sub_no, sec_no); - if (sec_no != sub_number) { - err ("there're more buses behind this bridge. Hot removal is not supported. Please choose another card\n"); - return -ENODEV; - } - - bus = ibmphp_find_res_bus (sec_number); - debug ("bus->busno is %x\n", bus->busno); - debug ("sec_number is %x\n", sec_number); - if (!bus) { - err ("cannot find Bus structure for the bridged device\n"); - return -EINVAL; - } - - ibmphp_remove_bus (bus, busno); - - for (count = 0; address[count]; count++) { - /* for 2 BARs */ - pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &start_address); - - if (!start_address) { - /* This BAR is not implemented */ - continue; - } - - tmp_address = start_address; - - if (start_address & PCI_BASE_ADDRESS_SPACE_IO) { - /* This is IO */ - start_address &= PCI_BASE_ADDRESS_IO_MASK; - if (ibmphp_find_resource (bus, start_address, &io, IO) < 0) { - err ("cannot find corresponding IO resource to remove\n"); - return -EIO; - } - if (io) - debug ("io->start = %x\n", io->start); - - ibmphp_remove_resource (io); - - /* ????????? DO WE NEED TO WRITE ANYTHING INTO THE PCI CONFIG SPACE BACK ?????????? */ - } else { - /* This is Memory */ - if (start_address & PCI_BASE_ADDRESS_MEM_PREFETCH) { - /* pfmem */ - start_address &= PCI_BASE_ADDRESS_MEM_MASK; - if (ibmphp_find_resource (bus, start_address, &pfmem, PFMEM) < 0) { - err ("cannot find corresponding PFMEM resource to remove\n"); - return -EINVAL; - } - if (pfmem) - debug ("pfmem->start = %x\n", pfmem->start); - - ibmphp_remove_resource (pfmem); - - if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) { - /* takes up another dword */ - count += 1; - } - - } else { - /* regular memory */ - start_address &= PCI_BASE_ADDRESS_MEM_MASK; - if (ibmphp_find_resource (bus, start_address, &mem, MEM) < 0) { - err ("cannot find corresponding MEM resource to remove\n"); - return -EINVAL; - } - if (mem) - debug ("mem->start = %x\n", mem->start); - - ibmphp_remove_resource (mem); - - if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) { - /* takes up another dword */ - count += 1; - } - } - } /* end of mem */ - } /* end of for */ - debug ("%s - exiting, returning success\n", __FUNCTION__); - return 0; -} - -static int unconfigure_boot_card (struct slot *slot_cur) -{ - u16 vendor_id; - u32 class; - u8 hdr_type; - u8 device; - u8 busno; - u8 function; - int rc; - unsigned int devfn; - u8 valid_device = 0x00; /* To see if we are ever able to find valid device and read it */ - - debug ("%s - enter\n", __FUNCTION__); - - device = slot_cur->device; - busno = slot_cur->bus; - - debug ("b4 for loop, device is %x\n", device); - /* For every function on the card */ - for (function = 0x0; function < 0x08; function++) { - devfn = PCI_DEVFN(device, function); - ibmphp_pci_bus->number = busno; - - pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id); - - if (vendor_id != PCI_VENDOR_ID_NOTVALID) { - /* found correct device!!! */ - ++valid_device; - - debug ("%s - found correct device\n", __FUNCTION__); - - /* header: x x x x x x x x - * | |___________|=> 1=PPB bridge, 0=normal device, 2=CardBus Bridge - * |_=> 0 = single function device, 1 = multi-function device - */ - - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type); - pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_CLASS_REVISION, &class); - - debug ("hdr_type %x, class %x\n", hdr_type, class); - class >>= 8; /* to take revision out, class = class.subclass.prog i/f */ - if (class == PCI_CLASS_NOT_DEFINED_VGA) { - err ("The device %x function %x is VGA compatible and is not supported for hot removing. " - "Please choose another device.\n", device, function); - return -ENODEV; - } else if (class == PCI_CLASS_DISPLAY_VGA) { - err ("The device %x function %x is not supported for hot removing. " - "Please choose another device.\n", device, function); - return -ENODEV; - } - - switch (hdr_type) { - case PCI_HEADER_TYPE_NORMAL: - rc = unconfigure_boot_device (busno, device, function); - if (rc) { - err ("was not able to unconfigure device %x func %x on bus %x. bailing out... \n", - device, function, busno); - return rc; - } - function = 0x8; - break; - case PCI_HEADER_TYPE_MULTIDEVICE: - rc = unconfigure_boot_device (busno, device, function); - if (rc) { - err ("was not able to unconfigure device %x func %x on bus %x. bailing out... \n", - device, function, busno); - return rc; - } - break; - case PCI_HEADER_TYPE_BRIDGE: - class >>= 8; - if (class != PCI_CLASS_BRIDGE_PCI) { - err ("This device %x function %x is not PCI-to-PCI bridge, " - "and is not supported for hot-removing. " - "Please try another card.\n", device, function); - return -ENODEV; - } - rc = unconfigure_boot_bridge (busno, device, function); - if (rc != 0) { - err ("was not able to hot-remove PPB properly.\n"); - return rc; - } - - function = 0x8; - break; - case PCI_HEADER_TYPE_MULTIBRIDGE: - class >>= 8; - if (class != PCI_CLASS_BRIDGE_PCI) { - err ("This device %x function %x is not PCI-to-PCI bridge, " - "and is not supported for hot-removing. " - "Please try another card.\n", device, function); - return -ENODEV; - } - rc = unconfigure_boot_bridge (busno, device, function); - if (rc != 0) { - err ("was not able to hot-remove PPB properly.\n"); - return rc; - } - break; - default: - err ("MAJOR PROBLEM!!!! Cannot read device's header \n"); - return -1; - break; - } /* end of switch */ - } /* end of valid device */ - } /* end of for */ - - if (!valid_device) { - err ("Could not find device to unconfigure. Or could not read the card. \n"); - return -1; - } - return 0; -} - -/* - * free the resources of the card (multi, single, or bridged) - * Parameters: slot, flag to say if this is for removing entire module or just - * unconfiguring the device - * TO DO: will probably need to add some code in case there was some resource, - * to remove it... this is from when we have errors in the configure_card... - * !!!!!!!!!!!!!!!!!!!!!!!!!FOR BUSES!!!!!!!!!!!! - * Returns: 0, -1, -ENODEV - */ -int ibmphp_unconfigure_card (struct slot **slot_cur, int the_end) -{ - int i; - int count; - int rc; - struct slot *sl = *slot_cur; - struct pci_func *cur_func = NULL; - struct pci_func *temp_func; - - debug ("%s - enter\n", __FUNCTION__); - - if (!the_end) { - /* Need to unconfigure the card */ - rc = unconfigure_boot_card (sl); - if ((rc == -ENODEV) || (rc == -EIO) || (rc == -EINVAL)) { - /* In all other cases, will still need to get rid of func structure if it exists */ - return rc; - } - } - - if (sl->func) { - cur_func = sl->func; - while (cur_func) { - /* TO DO: WILL MOST LIKELY NEED TO GET RID OF THE BUS STRUCTURE FROM RESOURCES AS WELL */ - if (cur_func->bus) { - /* in other words, it's a PPB */ - count = 2; - } else { - count = 6; - } - - for (i = 0; i < count; i++) { - if (cur_func->io[i]) { - debug ("io[%d] exists \n", i); - if (the_end > 0) - ibmphp_remove_resource (cur_func->io[i]); - cur_func->io[i] = NULL; - } - if (cur_func->mem[i]) { - debug ("mem[%d] exists \n", i); - if (the_end > 0) - ibmphp_remove_resource (cur_func->mem[i]); - cur_func->mem[i] = NULL; - } - if (cur_func->pfmem[i]) { - debug ("pfmem[%d] exists \n", i); - if (the_end > 0) - ibmphp_remove_resource (cur_func->pfmem[i]); - cur_func->pfmem[i] = NULL; - } - } - - temp_func = cur_func->next; - kfree (cur_func); - cur_func = temp_func; - } - } - - sl->func = NULL; - *slot_cur = sl; - debug ("%s - exit\n", __FUNCTION__); - return 0; -} - -/* - * add a new bus resulting from hot-plugging a PPB bridge with devices - * - * Input: bus and the amount of resources needed (we know we can assign those, - * since they've been checked already - * Output: bus added to the correct spot - * 0, -1, error - */ -static int add_new_bus (struct bus_node *bus, struct resource_node *io, struct resource_node *mem, struct resource_node *pfmem, u8 parent_busno) -{ - struct range_node *io_range = NULL; - struct range_node *mem_range = NULL; - struct range_node *pfmem_range = NULL; - struct bus_node *cur_bus = NULL; - - /* Trying to find the parent bus number */ - if (parent_busno != 0xFF) { - cur_bus = ibmphp_find_res_bus (parent_busno); - if (!cur_bus) { - err ("strange, cannot find bus which is supposed to be at the system... something is terribly wrong...\n"); - return -ENODEV; - } - - list_add (&bus->bus_list, &cur_bus->bus_list); - } - if (io) { - io_range = kmalloc (sizeof (struct range_node), GFP_KERNEL); - if (!io_range) { - err ("out of system memory \n"); - return -ENOMEM; - } - memset (io_range, 0, sizeof (struct range_node)); - io_range->start = io->start; - io_range->end = io->end; - io_range->rangeno = 1; - bus->noIORanges = 1; - bus->rangeIO = io_range; - } - if (mem) { - mem_range = kmalloc (sizeof (struct range_node), GFP_KERNEL); - if (!mem_range) { - err ("out of system memory \n"); - return -ENOMEM; - } - memset (mem_range, 0, sizeof (struct range_node)); - mem_range->start = mem->start; - mem_range->end = mem->end; - mem_range->rangeno = 1; - bus->noMemRanges = 1; - bus->rangeMem = mem_range; - } - if (pfmem) { - pfmem_range = kmalloc (sizeof (struct range_node), GFP_KERNEL); - if (!pfmem_range) { - err ("out of system memory \n"); - return -ENOMEM; - } - memset (pfmem_range, 0, sizeof (struct range_node)); - pfmem_range->start = pfmem->start; - pfmem_range->end = pfmem->end; - pfmem_range->rangeno = 1; - bus->noPFMemRanges = 1; - bus->rangePFMem = pfmem_range; - } - return 0; -} - -/* - * find the 1st available bus number for PPB to set as its secondary bus - * Parameters: bus_number of the primary bus - * Returns: bus_number of the secondary bus or 0xff in case of failure - */ -static u8 find_sec_number (u8 primary_busno, u8 slotno) -{ - int min, max; - u8 busno; - struct bus_info *bus; - struct bus_node *bus_cur; - - bus = ibmphp_find_same_bus_num (primary_busno); - if (!bus) { - err ("cannot get slot range of the bus from the BIOS\n"); - return 0xff; - } - max = bus->slot_max; - min = bus->slot_min; - if ((slotno > max) || (slotno < min)) { - err ("got the wrong range\n"); - return 0xff; - } - busno = (u8) (slotno - (u8) min); - busno += primary_busno + 0x01; - bus_cur = ibmphp_find_res_bus (busno); - /* either there is no such bus number, or there are no ranges, which - * can only happen if we removed the bridged device in previous load - * of the driver, and now only have the skeleton bus struct - */ - if ((!bus_cur) || (!(bus_cur->rangeIO) && !(bus_cur->rangeMem) && !(bus_cur->rangePFMem))) - return busno; - return 0xff; -} - diff -Nru a/drivers/hotplug/ibmphp_res.c b/drivers/hotplug/ibmphp_res.c --- a/drivers/hotplug/ibmphp_res.c Mon Jun 9 23:16:17 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,2157 +0,0 @@ -/* - * IBM Hot Plug Controller Driver - * - * Written By: Irene Zubarev, IBM Corporation - * - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001,2002 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or - * NON INFRINGEMENT. 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. - * - * Send feedback to <gregkh@us.ibm.com> - * - */ - -#include <linux/module.h> -#include <linux/slab.h> -#include <linux/pci.h> -#include <linux/list.h> -#include <linux/init.h> -#include "ibmphp.h" - -static int flags = 0; /* for testing */ - -static void update_resources (struct bus_node *bus_cur, int type, int rangeno); -static int once_over (void); -static int remove_ranges (struct bus_node *, struct bus_node *); -static int update_bridge_ranges (struct bus_node **); -static int add_range (int type, struct range_node *, struct bus_node *); -static void fix_resources (struct bus_node *); -static inline struct bus_node *find_bus_wprev (u8, struct bus_node **, u8); - -static LIST_HEAD(gbuses); -LIST_HEAD(ibmphp_res_head); - -static struct bus_node * __init alloc_error_bus (struct ebda_pci_rsrc * curr, u8 busno, int flag) -{ - struct bus_node * newbus; - - if (!(curr) && !(flag)) { - err ("NULL pointer passed \n"); - return NULL; - } - - newbus = kmalloc (sizeof (struct bus_node), GFP_KERNEL); - if (!newbus) { - err ("out of system memory \n"); - return NULL; - } - - memset (newbus, 0, sizeof (struct bus_node)); - if (flag) - newbus->busno = busno; - else - newbus->busno = curr->bus_num; - list_add_tail (&newbus->bus_list, &gbuses); - return newbus; -} - -static struct resource_node * __init alloc_resources (struct ebda_pci_rsrc * curr) -{ - struct resource_node *rs; - - if (!curr) { - err ("NULL passed to allocate \n"); - return NULL; - } - - rs = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - if (!rs) { - err ("out of system memory \n"); - return NULL; - } - memset (rs, 0, sizeof (struct resource_node)); - rs->busno = curr->bus_num; - rs->devfunc = curr->dev_fun; - rs->start = curr->start_addr; - rs->end = curr->end_addr; - rs->len = curr->end_addr - curr->start_addr + 1; - return rs; -} - -static int __init alloc_bus_range (struct bus_node **new_bus, struct range_node **new_range, struct ebda_pci_rsrc *curr, int flag, u8 first_bus) -{ - struct bus_node * newbus; - struct range_node *newrange; - u8 num_ranges = 0; - - if (first_bus) { - newbus = kmalloc (sizeof (struct bus_node), GFP_KERNEL); - if (!newbus) { - err ("out of system memory. \n"); - return -ENOMEM; - } - memset (newbus, 0, sizeof (struct bus_node)); - newbus->busno = curr->bus_num; - } else { - newbus = *new_bus; - switch (flag) { - case MEM: - num_ranges = newbus->noMemRanges; - break; - case PFMEM: - num_ranges = newbus->noPFMemRanges; - break; - case IO: - num_ranges = newbus->noIORanges; - break; - } - } - - newrange = kmalloc (sizeof (struct range_node), GFP_KERNEL); - if (!newrange) { - if (first_bus) - kfree (newbus); - err ("out of system memory \n"); - return -ENOMEM; - } - memset (newrange, 0, sizeof (struct range_node)); - newrange->start = curr->start_addr; - newrange->end = curr->end_addr; - - if (first_bus || (!num_ranges)) - newrange->rangeno = 1; - else { - /* need to insert our range */ - add_range (flag, newrange, newbus); - debug ("%d resource Primary Bus inserted on bus %x [%x - %x]\n", flag, newbus->busno, newrange->start, newrange->end); - } - - switch (flag) { - case MEM: - newbus->rangeMem = newrange; - if (first_bus) - newbus->noMemRanges = 1; - else { - debug ("First Memory Primary on bus %x, [%x - %x]\n", newbus->busno, newrange->start, newrange->end); - ++newbus->noMemRanges; - fix_resources (newbus); - } - break; - case IO: - newbus->rangeIO = newrange; - if (first_bus) - newbus->noIORanges = 1; - else { - debug ("First IO Primary on bus %x, [%x - %x]\n", newbus->busno, newrange->start, newrange->end); - ++newbus->noIORanges; - fix_resources (newbus); - } - break; - case PFMEM: - newbus->rangePFMem = newrange; - if (first_bus) - newbus->noPFMemRanges = 1; - else { - debug ("1st PFMemory Primary on Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); - ++newbus->noPFMemRanges; - fix_resources (newbus); - } - - break; - } - - *new_bus = newbus; - *new_range = newrange; - return 0; -} - - -/* Notes: - * 1. The ranges are ordered. The buses are not ordered. (First come) - * - * 2. If cannot allocate out of PFMem range, allocate from Mem ranges. PFmemFromMem - * are not sorted. (no need since use mem node). To not change the entire code, we - * also add mem node whenever this case happens so as not to change - * ibmphp_check_mem_resource etc (and since it really is taking Mem resource) - */ - -/***************************************************************************** - * This is the Resource Management initialization function. It will go through - * the Resource list taken from EBDA and fill in this module's data structures - * - * THIS IS NOT TAKING INTO CONSIDERATION IO RESTRICTIONS OF PRIMARY BUSES, - * SINCE WE'RE GOING TO ASSUME FOR NOW WE DON'T HAVE THOSE ON OUR BUSES FOR NOW - * - * Input: ptr to the head of the resource list from EBDA - * Output: 0, -1 or error codes - ***************************************************************************/ -int __init ibmphp_rsrc_init (void) -{ - struct ebda_pci_rsrc *curr; - struct range_node *newrange = NULL; - struct bus_node *newbus = NULL; - struct bus_node *bus_cur; - struct bus_node *bus_prev; - struct list_head *tmp; - struct resource_node *new_io = NULL; - struct resource_node *new_mem = NULL; - struct resource_node *new_pfmem = NULL; - int rc; - struct list_head *tmp_ebda; - - list_for_each (tmp_ebda, &ibmphp_ebda_pci_rsrc_head) { - curr = list_entry (tmp_ebda, struct ebda_pci_rsrc, ebda_pci_rsrc_list); - if (!(curr->rsrc_type & PCIDEVMASK)) { - /* EBDA still lists non PCI devices, so ignore... */ - debug ("this is not a PCI DEVICE in rsrc_init, please take care\n"); - // continue; - } - - /* this is a primary bus resource */ - if (curr->rsrc_type & PRIMARYBUSMASK) { - /* memory */ - if ((curr->rsrc_type & RESTYPE) == MMASK) { - /* no bus structure exists in place yet */ - if (list_empty (&gbuses)) { - if ((rc = alloc_bus_range (&newbus, &newrange, curr, MEM, 1))) - return rc; - list_add_tail (&newbus->bus_list, &gbuses); - debug ("gbuses = NULL, Memory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); - } else { - bus_cur = find_bus_wprev (curr->bus_num, &bus_prev, 1); - /* found our bus */ - if (bus_cur) { - rc = alloc_bus_range (&bus_cur, &newrange, curr, MEM, 0); - if (rc) - return rc; - } else { - /* went through all the buses and didn't find ours, need to create a new bus node */ - if ((rc = alloc_bus_range (&newbus, &newrange, curr, MEM, 1))) - return rc; - - list_add_tail (&newbus->bus_list, &gbuses); - debug ("New Bus, Memory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); - } - } - } else if ((curr->rsrc_type & RESTYPE) == PFMASK) { - /* prefetchable memory */ - if (list_empty (&gbuses)) { - /* no bus structure exists in place yet */ - if ((rc = alloc_bus_range (&newbus, &newrange, curr, PFMEM, 1))) - return rc; - list_add_tail (&newbus->bus_list, &gbuses); - debug ("gbuses = NULL, PFMemory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); - } else { - bus_cur = find_bus_wprev (curr->bus_num, &bus_prev, 1); - if (bus_cur) { - /* found our bus */ - rc = alloc_bus_range (&bus_cur, &newrange, curr, PFMEM, 0); - if (rc) - return rc; - } else { - /* went through all the buses and didn't find ours, need to create a new bus node */ - if ((rc = alloc_bus_range (&newbus, &newrange, curr, PFMEM, 1))) - return rc; - list_add_tail (&newbus->bus_list, &gbuses); - debug ("1st Bus, PFMemory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); - } - } - } else if ((curr->rsrc_type & RESTYPE) == IOMASK) { - /* IO */ - if (list_empty (&gbuses)) { - /* no bus structure exists in place yet */ - if ((rc = alloc_bus_range (&newbus, &newrange, curr, IO, 1))) - return rc; - list_add_tail (&newbus->bus_list, &gbuses); - debug ("gbuses = NULL, IO Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); - } else { - bus_cur = find_bus_wprev (curr->bus_num, &bus_prev, 1); - if (bus_cur) { - rc = alloc_bus_range (&bus_cur, &newrange, curr, IO, 0); - if (rc) - return rc; - } else { - /* went through all the buses and didn't find ours, need to create a new bus node */ - if ((rc = alloc_bus_range (&newbus, &newrange, curr, IO, 1))) - return rc; - list_add_tail (&newbus->bus_list, &gbuses); - debug ("1st Bus, IO Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); - } - } - - } else { - ; /* type is reserved WHAT TO DO IN THIS CASE??? - NOTHING TO DO??? */ - } - } else { - /* regular pci device resource */ - if ((curr->rsrc_type & RESTYPE) == MMASK) { - /* Memory resource */ - new_mem = alloc_resources (curr); - if (!new_mem) - return -ENOMEM; - new_mem->type = MEM; - /* - * if it didn't find the bus, means PCI dev - * came b4 the Primary Bus info, so need to - * create a bus rangeno becomes a problem... - * assign a -1 and then update once the range - * actually appears... - */ - if (ibmphp_add_resource (new_mem) < 0) { - newbus = alloc_error_bus (curr, 0, 0); - if (!newbus) - return -ENOMEM; - newbus->firstMem = new_mem; - ++newbus->needMemUpdate; - new_mem->rangeno = -1; - } - debug ("Memory resource for device %x, bus %x, [%x - %x]\n", new_mem->devfunc, new_mem->busno, new_mem->start, new_mem->end); - - } else if ((curr->rsrc_type & RESTYPE) == PFMASK) { - /* PFMemory resource */ - new_pfmem = alloc_resources (curr); - if (!new_pfmem) - return -ENOMEM; - new_pfmem->type = PFMEM; - new_pfmem->fromMem = FALSE; - if (ibmphp_add_resource (new_pfmem) < 0) { - newbus = alloc_error_bus (curr, 0, 0); - if (!newbus) - return -ENOMEM; - newbus->firstPFMem = new_pfmem; - ++newbus->needPFMemUpdate; - new_pfmem->rangeno = -1; - } - - debug ("PFMemory resource for device %x, bus %x, [%x - %x]\n", new_pfmem->devfunc, new_pfmem->busno, new_pfmem->start, new_pfmem->end); - } else if ((curr->rsrc_type & RESTYPE) == IOMASK) { - /* IO resource */ - new_io = alloc_resources (curr); - if (!new_io) - return -ENOMEM; - new_io->type = IO; - - /* - * if it didn't find the bus, means PCI dev - * came b4 the Primary Bus info, so need to - * create a bus rangeno becomes a problem... - * Can assign a -1 and then update once the - * range actually appears... - */ - if (ibmphp_add_resource (new_io) < 0) { - newbus = alloc_error_bus (curr, 0, 0); - if (!newbus) - return -ENOMEM; - newbus->firstIO = new_io; - ++newbus->needIOUpdate; - new_io->rangeno = -1; - } - debug ("IO resource for device %x, bus %x, [%x - %x]\n", new_io->devfunc, new_io->busno, new_io->start, new_io->end); - } - } - } - - list_for_each (tmp, &gbuses) { - bus_cur = list_entry (tmp, struct bus_node, bus_list); - /* This is to get info about PPB resources, since EBDA doesn't put this info into the primary bus info */ - rc = update_bridge_ranges (&bus_cur); - if (rc) - return rc; - } - rc = once_over (); /* This is to align ranges (so no -1) */ - if (rc) - return rc; - return 0; -} - -/******************************************************************************** - * This function adds a range into a sorted list of ranges per bus for a particular - * range type, it then calls another routine to update the range numbers on the - * pci devices' resources for the appropriate resource - * - * Input: type of the resource, range to add, current bus - * Output: 0 or -1, bus and range ptrs - ********************************************************************************/ -static int add_range (int type, struct range_node *range, struct bus_node *bus_cur) -{ - struct range_node *range_cur = NULL; - struct range_node *range_prev; - int count = 0, i_init; - int noRanges = 0; - - switch (type) { - case MEM: - range_cur = bus_cur->rangeMem; - noRanges = bus_cur->noMemRanges; - break; - case PFMEM: - range_cur = bus_cur->rangePFMem; - noRanges = bus_cur->noPFMemRanges; - break; - case IO: - range_cur = bus_cur->rangeIO; - noRanges = bus_cur->noIORanges; - break; - } - - range_prev = NULL; - while (range_cur) { - if (range->start < range_cur->start) - break; - range_prev = range_cur; - range_cur = range_cur->next; - count = count + 1; - } - if (!count) { - /* our range will go at the beginning of the list */ - switch (type) { - case MEM: - bus_cur->rangeMem = range; - break; - case PFMEM: - bus_cur->rangePFMem = range; - break; - case IO: - bus_cur->rangeIO = range; - break; - } - range->next = range_cur; - range->rangeno = 1; - i_init = 0; - } else if (!range_cur) { - /* our range will go at the end of the list */ - range->next = NULL; - range_prev->next = range; - range->rangeno = range_prev->rangeno + 1; - return 0; - } else { - /* the range is in the middle */ - range_prev->next = range; - range->next = range_cur; - range->rangeno = range_cur->rangeno; - i_init = range_prev->rangeno; - } - - for (count = i_init; count < noRanges; ++count) { - ++range_cur->rangeno; - range_cur = range_cur->next; - } - - update_resources (bus_cur, type, i_init + 1); - return 0; -} - -/******************************************************************************* - * This routine goes through the list of resources of type 'type' and updates - * the range numbers that they correspond to. It was called from add_range fnc - * - * Input: bus, type of the resource, the rangeno starting from which to update - ******************************************************************************/ -static void update_resources (struct bus_node *bus_cur, int type, int rangeno) -{ - struct resource_node *res = NULL; - u8 eol = FALSE; /* end of list indicator */ - - switch (type) { - case MEM: - if (bus_cur->firstMem) - res = bus_cur->firstMem; - break; - case PFMEM: - if (bus_cur->firstPFMem) - res = bus_cur->firstPFMem; - break; - case IO: - if (bus_cur->firstIO) - res = bus_cur->firstIO; - break; - } - - if (res) { - while (res) { - if (res->rangeno == rangeno) - break; - if (res->next) - res = res->next; - else if (res->nextRange) - res = res->nextRange; - else { - eol = TRUE; - break; - } - } - - if (!eol) { - /* found the range */ - while (res) { - ++res->rangeno; - res = res->next; - } - } - } -} - -static void fix_me (struct resource_node *res, struct bus_node *bus_cur, struct range_node *range) -{ - char * str = ""; - switch (res->type) { - case IO: - str = "io"; - break; - case MEM: - str = "mem"; - break; - case PFMEM: - str = "pfmem"; - break; - } - - while (res) { - if (res->rangeno == -1) { - while (range) { - if ((res->start >= range->start) && (res->end <= range->end)) { - res->rangeno = range->rangeno; - debug ("%s->rangeno in fix_resources is %d\n", str, res->rangeno); - switch (res->type) { - case IO: - --bus_cur->needIOUpdate; - break; - case MEM: - --bus_cur->needMemUpdate; - break; - case PFMEM: - --bus_cur->needPFMemUpdate; - break; - } - break; - } - range = range->next; - } - } - if (res->next) - res = res->next; - else - res = res->nextRange; - } - -} - -/***************************************************************************** - * This routine reassigns the range numbers to the resources that had a -1 - * This case can happen only if upon initialization, resources taken by pci dev - * appear in EBDA before the resources allocated for that bus, since we don't - * know the range, we assign -1, and this routine is called after a new range - * is assigned to see the resources with unknown range belong to the added range - * - * Input: current bus - * Output: none, list of resources for that bus are fixed if can be - *******************************************************************************/ -static void fix_resources (struct bus_node *bus_cur) -{ - struct range_node *range; - struct resource_node *res; - - debug ("%s - bus_cur->busno = %d\n", __FUNCTION__, bus_cur->busno); - - if (bus_cur->needIOUpdate) { - res = bus_cur->firstIO; - range = bus_cur->rangeIO; - fix_me (res, bus_cur, range); - } - if (bus_cur->needMemUpdate) { - res = bus_cur->firstMem; - range = bus_cur->rangeMem; - fix_me (res, bus_cur, range); - } - if (bus_cur->needPFMemUpdate) { - res = bus_cur->firstPFMem; - range = bus_cur->rangePFMem; - fix_me (res, bus_cur, range); - } -} - -/******************************************************************************* - * This routine adds a resource to the list of resources to the appropriate bus - * based on their resource type and sorted by their starting addresses. It assigns - * the ptrs to next and nextRange if needed. - * - * Input: resource ptr - * Output: ptrs assigned (to the node) - * 0 or -1 - *******************************************************************************/ -int ibmphp_add_resource (struct resource_node *res) -{ - struct resource_node *res_cur; - struct resource_node *res_prev; - struct bus_node *bus_cur; - struct range_node *range_cur = NULL; - struct resource_node *res_start = NULL; - - debug ("%s - enter\n", __FUNCTION__); - - if (!res) { - err ("NULL passed to add \n"); - return -ENODEV; - } - - bus_cur = find_bus_wprev (res->busno, NULL, 0); - - if (!bus_cur) { - /* didn't find a bus, smth's wrong!!! */ - debug ("no bus in the system, either pci_dev's wrong or allocation failed\n"); - return -ENODEV; - } - - /* Normal case */ - switch (res->type) { - case IO: - range_cur = bus_cur->rangeIO; - res_start = bus_cur->firstIO; - break; - case MEM: - range_cur = bus_cur->rangeMem; - res_start = bus_cur->firstMem; - break; - case PFMEM: - range_cur = bus_cur->rangePFMem; - res_start = bus_cur->firstPFMem; - break; - default: - err ("cannot read the type of the resource to add... problem \n"); - return -EINVAL; - } - while (range_cur) { - if ((res->start >= range_cur->start) && (res->end <= range_cur->end)) { - res->rangeno = range_cur->rangeno; - break; - } - range_cur = range_cur->next; - } - - /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - * this is again the case of rangeno = -1 - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - */ - - if (!range_cur) { - switch (res->type) { - case IO: - ++bus_cur->needIOUpdate; - break; - case MEM: - ++bus_cur->needMemUpdate; - break; - case PFMEM: - ++bus_cur->needPFMemUpdate; - break; - } - res->rangeno = -1; - } - - debug ("The range is %d\n", res->rangeno); - if (!res_start) { - /* no first{IO,Mem,Pfmem} on the bus, 1st IO/Mem/Pfmem resource ever */ - switch (res->type) { - case IO: - bus_cur->firstIO = res; - break; - case MEM: - bus_cur->firstMem = res; - break; - case PFMEM: - bus_cur->firstPFMem = res; - break; - } - res->next = NULL; - res->nextRange = NULL; - } else { - res_cur = res_start; - res_prev = NULL; - - debug ("res_cur->rangeno is %d\n", res_cur->rangeno); - - while (res_cur) { - if (res_cur->rangeno >= res->rangeno) - break; - res_prev = res_cur; - if (res_cur->next) - res_cur = res_cur->next; - else - res_cur = res_cur->nextRange; - } - - if (!res_cur) { - /* at the end of the resource list */ - debug ("i should be here, [%x - %x]\n", res->start, res->end); - res_prev->nextRange = res; - res->next = NULL; - res->nextRange = NULL; - } else if (res_cur->rangeno == res->rangeno) { - /* in the same range */ - while (res_cur) { - if (res->start < res_cur->start) - break; - res_prev = res_cur; - res_cur = res_cur->next; - } - if (!res_cur) { - /* the last resource in this range */ - res_prev->next = res; - res->next = NULL; - res->nextRange = res_prev->nextRange; - res_prev->nextRange = NULL; - } else if (res->start < res_cur->start) { - /* at the beginning or middle of the range */ - if (!res_prev) { - switch (res->type) { - case IO: - bus_cur->firstIO = res; - break; - case MEM: - bus_cur->firstMem = res; - break; - case PFMEM: - bus_cur->firstPFMem = res; - break; - } - } else if (res_prev->rangeno == res_cur->rangeno) - res_prev->next = res; - else - res_prev->nextRange = res; - - res->next = res_cur; - res->nextRange = NULL; - } - } else { - /* this is the case where it is 1st occurrence of the range */ - if (!res_prev) { - /* at the beginning of the resource list */ - res->next = NULL; - switch (res->type) { - case IO: - res->nextRange = bus_cur->firstIO; - bus_cur->firstIO = res; - break; - case MEM: - res->nextRange = bus_cur->firstMem; - bus_cur->firstMem = res; - break; - case PFMEM: - res->nextRange = bus_cur->firstPFMem; - bus_cur->firstPFMem = res; - break; - } - } else if (res_cur->rangeno > res->rangeno) { - /* in the middle of the resource list */ - res_prev->nextRange = res; - res->next = NULL; - res->nextRange = res_cur; - } - } - } - - debug ("%s - exit\n", __FUNCTION__); - return 0; -} - -/**************************************************************************** - * This routine will remove the resource from the list of resources - * - * Input: io, mem, and/or pfmem resource to be deleted - * Ouput: modified resource list - * 0 or error code - ****************************************************************************/ -int ibmphp_remove_resource (struct resource_node *res) -{ - struct bus_node *bus_cur; - struct resource_node *res_cur = NULL; - struct resource_node *res_prev; - struct resource_node *mem_cur; - char * type = ""; - - if (!res) { - err ("resource to remove is NULL \n"); - return -ENODEV; - } - - bus_cur = find_bus_wprev (res->busno, NULL, 0); - - if (!bus_cur) { - err ("cannot find corresponding bus of the io resource to remove " - "bailing out...\n"); - return -ENODEV; - } - - switch (res->type) { - case IO: - res_cur = bus_cur->firstIO; - type = "io"; - break; - case MEM: - res_cur = bus_cur->firstMem; - type = "mem"; - break; - case PFMEM: - res_cur = bus_cur->firstPFMem; - type = "pfmem"; - break; - default: - err ("unknown type for resource to remove \n"); - return -EINVAL; - } - res_prev = NULL; - - while (res_cur) { - if ((res_cur->start == res->start) && (res_cur->end == res->end)) - break; - res_prev = res_cur; - if (res_cur->next) - res_cur = res_cur->next; - else - res_cur = res_cur->nextRange; - } - - if (!res_cur) { - if (res->type == PFMEM) { - /* - * case where pfmem might be in the PFMemFromMem list - * so will also need to remove the corresponding mem - * entry - */ - res_cur = bus_cur->firstPFMemFromMem; - res_prev = NULL; - - while (res_cur) { - if ((res_cur->start == res->start) && (res_cur->end == res->end)) { - mem_cur = bus_cur->firstMem; - while (mem_cur) { - if ((mem_cur->start == res_cur->start) - && (mem_cur->end == res_cur->end)) - break; - if (mem_cur->next) - mem_cur = mem_cur->next; - else - mem_cur = mem_cur->nextRange; - } - if (!mem_cur) { - err ("cannot find corresponding mem node for pfmem...\n"); - return -EINVAL; - } - - ibmphp_remove_resource (mem_cur); - if (!res_prev) - bus_cur->firstPFMemFromMem = res_cur->next; - else - res_prev->next = res_cur->next; - kfree (res_cur); - return 0; - } - res_prev = res_cur; - if (res_cur->next) - res_cur = res_cur->next; - else - res_cur = res_cur->nextRange; - } - if (!res_cur) { - err ("cannot find pfmem to delete...\n"); - return -EINVAL; - } - } else { - err ("the %s resource is not in the list to be deleted...\n", type); - return -EINVAL; - } - } - if (!res_prev) { - /* first device to be deleted */ - if (res_cur->next) { - switch (res->type) { - case IO: - bus_cur->firstIO = res_cur->next; - break; - case MEM: - bus_cur->firstMem = res_cur->next; - break; - case PFMEM: - bus_cur->firstPFMem = res_cur->next; - break; - } - } else if (res_cur->nextRange) { - switch (res->type) { - case IO: - bus_cur->firstIO = res_cur->nextRange; - break; - case MEM: - bus_cur->firstMem = res_cur->nextRange; - break; - case PFMEM: - bus_cur->firstPFMem = res_cur->nextRange; - break; - } - } else { - switch (res->type) { - case IO: - bus_cur->firstIO = NULL; - break; - case MEM: - bus_cur->firstMem = NULL; - break; - case PFMEM: - bus_cur->firstPFMem = NULL; - break; - } - } - kfree (res_cur); - return 0; - } else { - if (res_cur->next) { - if (res_prev->rangeno == res_cur->rangeno) - res_prev->next = res_cur->next; - else - res_prev->nextRange = res_cur->next; - } else if (res_cur->nextRange) { - res_prev->next = NULL; - res_prev->nextRange = res_cur->nextRange; - } else { - res_prev->next = NULL; - res_prev->nextRange = NULL; - } - kfree (res_cur); - return 0; - } - - return 0; -} - -static struct range_node * find_range (struct bus_node *bus_cur, struct resource_node * res) -{ - struct range_node * range = NULL; - - switch (res->type) { - case IO: - range = bus_cur->rangeIO; - break; - case MEM: - range = bus_cur->rangeMem; - break; - case PFMEM: - range = bus_cur->rangePFMem; - break; - default: - err ("cannot read resource type in find_range \n"); - } - - while (range) { - if (res->rangeno == range->rangeno) - break; - range = range->next; - } - return range; -} - -/***************************************************************************** - * This routine will check to make sure the io/mem/pfmem->len that the device asked for - * can fit w/i our list of available IO/MEM/PFMEM resources. If cannot, returns -EINVAL, - * otherwise, returns 0 - * - * Input: resource - * Ouput: the correct start and end address are inputted into the resource node, - * 0 or -EINVAL - *****************************************************************************/ -int ibmphp_check_resource (struct resource_node *res, u8 bridge) -{ - struct bus_node *bus_cur; - struct range_node *range = NULL; - struct resource_node *res_prev; - struct resource_node *res_cur = NULL; - u32 len_cur = 0, start_cur = 0, len_tmp = 0; - int noranges = 0; - u32 tmp_start; /* this is to make sure start address is divisible by the length needed */ - u32 tmp_divide; - u8 flag = FALSE; - - if (!res) - return -EINVAL; - - if (bridge) { - /* The rules for bridges are different, 4K divisible for IO, 1M for (pf)mem*/ - if (res->type == IO) - tmp_divide = IOBRIDGE; - else - tmp_divide = MEMBRIDGE; - } else - tmp_divide = res->len; - - bus_cur = find_bus_wprev (res->busno, NULL, 0); - - if (!bus_cur) { - /* didn't find a bus, smth's wrong!!! */ - debug ("no bus in the system, either pci_dev's wrong or allocation failed \n"); - return -EINVAL; - } - - debug ("%s - enter\n", __FUNCTION__); - debug ("bus_cur->busno is %d\n", bus_cur->busno); - - /* This is a quick fix to not mess up with the code very much. i.e., - * 2000-2fff, len = 1000, but when we compare, we need it to be fff */ - res->len -= 1; - - switch (res->type) { - case IO: - res_cur = bus_cur->firstIO; - noranges = bus_cur->noIORanges; - break; - case MEM: - res_cur = bus_cur->firstMem; - noranges = bus_cur->noMemRanges; - break; - case PFMEM: - res_cur = bus_cur->firstPFMem; - noranges = bus_cur->noPFMemRanges; - break; - default: - err ("wrong type of resource to check \n"); - return -EINVAL; - } - res_prev = NULL; - - while (res_cur) { - range = find_range (bus_cur, res_cur); - debug ("%s - rangeno = %d\n", __FUNCTION__, res_cur->rangeno); - - if (!range) { - err ("no range for the device exists... bailing out...\n"); - return -EINVAL; - } - - /* found our range */ - if (!res_prev) { - /* first time in the loop */ - if ((res_cur->start != range->start) && ((len_tmp = res_cur->start - 1 - range->start) >= res->len)) { - debug ("len_tmp = %x\n", len_tmp); - - if ((len_tmp < len_cur) || (len_cur == 0)) { - - if ((range->start % tmp_divide) == 0) { - /* just perfect, starting address is divisible by length */ - flag = TRUE; - len_cur = len_tmp; - start_cur = range->start; - } else { - /* Needs adjusting */ - tmp_start = range->start; - flag = FALSE; - - while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) { - if ((tmp_start % tmp_divide) == 0) { - flag = TRUE; - len_cur = len_tmp; - start_cur = tmp_start; - break; - } - tmp_start += tmp_divide - tmp_start % tmp_divide; - if (tmp_start >= res_cur->start - 1) - break; - } - } - - if (flag && len_cur == res->len) { - debug ("but we are not here, right?\n"); - res->start = start_cur; - res->len += 1; /* To restore the balance */ - res->end = res->start + res->len - 1; - return 0; - } - } - } - } - if (!res_cur->next) { - /* last device on the range */ - if ((range->end != res_cur->end) && ((len_tmp = range->end - (res_cur->end + 1)) >= res->len)) { - debug ("len_tmp = %x\n", len_tmp); - if ((len_tmp < len_cur) || (len_cur == 0)) { - - if (((res_cur->end + 1) % tmp_divide) == 0) { - /* just perfect, starting address is divisible by length */ - flag = TRUE; - len_cur = len_tmp; - start_cur = res_cur->end + 1; - } else { - /* Needs adjusting */ - tmp_start = res_cur->end + 1; - flag = FALSE; - - while ((len_tmp = range->end - tmp_start) >= res->len) { - if ((tmp_start % tmp_divide) == 0) { - flag = TRUE; - len_cur = len_tmp; - start_cur = tmp_start; - break; - } - tmp_start += tmp_divide - tmp_start % tmp_divide; - if (tmp_start >= range->end) - break; - } - } - if (flag && len_cur == res->len) { - res->start = start_cur; - res->len += 1; /* To restore the balance */ - res->end = res->start + res->len - 1; - return 0; - } - } - } - } - - if (res_prev) { - if (res_prev->rangeno != res_cur->rangeno) { - /* 1st device on this range */ - if ((res_cur->start != range->start) && - ((len_tmp = res_cur->start - 1 - range->start) >= res->len)) { - if ((len_tmp < len_cur) || (len_cur == 0)) { - if ((range->start % tmp_divide) == 0) { - /* just perfect, starting address is divisible by length */ - flag = TRUE; - len_cur = len_tmp; - start_cur = range->start; - } else { - /* Needs adjusting */ - tmp_start = range->start; - flag = FALSE; - - while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) { - if ((tmp_start % tmp_divide) == 0) { - flag = TRUE; - len_cur = len_tmp; - start_cur = tmp_start; - break; - } - tmp_start += tmp_divide - tmp_start % tmp_divide; - if (tmp_start >= res_cur->start - 1) - break; - } - } - - if (flag && len_cur == res->len) { - res->start = start_cur; - res->len += 1; /* To restore the balance */ - res->end = res->start + res->len - 1; - return 0; - } - } - } - } else { - /* in the same range */ - if ((len_tmp = res_cur->start - 1 - res_prev->end - 1) >= res->len) { - if ((len_tmp < len_cur) || (len_cur == 0)) { - if (((res_prev->end + 1) % tmp_divide) == 0) { - /* just perfect, starting address's divisible by length */ - flag = TRUE; - len_cur = len_tmp; - start_cur = res_prev->end + 1; - } else { - /* Needs adjusting */ - tmp_start = res_prev->end + 1; - flag = FALSE; - - while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) { - if ((tmp_start % tmp_divide) == 0) { - flag = TRUE; - len_cur = len_tmp; - start_cur = tmp_start; - break; - } - tmp_start += tmp_divide - tmp_start % tmp_divide; - if (tmp_start >= res_cur->start - 1) - break; - } - } - - if (flag && len_cur == res->len) { - res->start = start_cur; - res->len += 1; /* To restore the balance */ - res->end = res->start + res->len - 1; - return 0; - } - } - } - } - } - /* end if (res_prev) */ - res_prev = res_cur; - if (res_cur->next) - res_cur = res_cur->next; - else - res_cur = res_cur->nextRange; - } /* end of while */ - - - if (!res_prev) { - /* 1st device ever */ - /* need to find appropriate range */ - switch (res->type) { - case IO: - range = bus_cur->rangeIO; - break; - case MEM: - range = bus_cur->rangeMem; - break; - case PFMEM: - range = bus_cur->rangePFMem; - break; - } - while (range) { - if ((len_tmp = range->end - range->start) >= res->len) { - if ((len_tmp < len_cur) || (len_cur == 0)) { - if ((range->start % tmp_divide) == 0) { - /* just perfect, starting address's divisible by length */ - flag = TRUE; - len_cur = len_tmp; - start_cur = range->start; - } else { - /* Needs adjusting */ - tmp_start = range->start; - flag = FALSE; - - while ((len_tmp = range->end - tmp_start) >= res->len) { - if ((tmp_start % tmp_divide) == 0) { - flag = TRUE; - len_cur = len_tmp; - start_cur = tmp_start; - break; - } - tmp_start += tmp_divide - tmp_start % tmp_divide; - if (tmp_start >= range->end) - break; - } - } - - if (flag && len_cur == res->len) { - res->start = start_cur; - res->len += 1; /* To restore the balance */ - res->end = res->start + res->len - 1; - return 0; - } - } - } - range = range->next; - } /* end of while */ - - if ((!range) && (len_cur == 0)) { - /* have gone through the list of devices and ranges and haven't found n.e.thing */ - err ("no appropriate range.. bailing out...\n"); - return -EINVAL; - } else if (len_cur) { - res->start = start_cur; - res->len += 1; /* To restore the balance */ - res->end = res->start + res->len - 1; - return 0; - } - } - - if (!res_cur) { - debug ("prev->rangeno = %d, noranges = %d\n", res_prev->rangeno, noranges); - if (res_prev->rangeno < noranges) { - /* if there're more ranges out there to check */ - switch (res->type) { - case IO: - range = bus_cur->rangeIO; - break; - case MEM: - range = bus_cur->rangeMem; - break; - case PFMEM: - range = bus_cur->rangePFMem; - break; - } - while (range) { - if ((len_tmp = range->end - range->start) >= res->len) { - if ((len_tmp < len_cur) || (len_cur == 0)) { - if ((range->start % tmp_divide) == 0) { - /* just perfect, starting address's divisible by length */ - flag = TRUE; - len_cur = len_tmp; - start_cur = range->start; - } else { - /* Needs adjusting */ - tmp_start = range->start; - flag = FALSE; - - while ((len_tmp = range->end - tmp_start) >= res->len) { - if ((tmp_start % tmp_divide) == 0) { - flag = TRUE; - len_cur = len_tmp; - start_cur = tmp_start; - break; - } - tmp_start += tmp_divide - tmp_start % tmp_divide; - if (tmp_start >= range->end) - break; - } - } - - if (flag && len_cur == res->len) { - res->start = start_cur; - res->len += 1; /* To restore the balance */ - res->end = res->start + res->len - 1; - return 0; - } - } - } - range = range->next; - } /* end of while */ - - if ((!range) && (len_cur == 0)) { - /* have gone through the list of devices and ranges and haven't found n.e.thing */ - err ("no appropriate range.. bailing out...\n"); - return -EINVAL; - } else if (len_cur) { - res->start = start_cur; - res->len += 1; /* To restore the balance */ - res->end = res->start + res->len - 1; - return 0; - } - } else { - /* no more ranges to check on */ - if (len_cur) { - res->start = start_cur; - res->len += 1; /* To restore the balance */ - res->end = res->start + res->len - 1; - return 0; - } else { - /* have gone through the list of devices and haven't found n.e.thing */ - err ("no appropriate range.. bailing out...\n"); - return -EINVAL; - } - } - } /* end if(!res_cur) */ - return -EINVAL; -} - -/******************************************************************************** - * This routine is called from remove_card if the card contained PPB. - * It will remove all the resources on the bus as well as the bus itself - * Input: Bus - * Ouput: 0, -ENODEV - ********************************************************************************/ -int ibmphp_remove_bus (struct bus_node *bus, u8 parent_busno) -{ - struct resource_node *res_cur; - struct resource_node *res_tmp; - struct bus_node *prev_bus; - int rc; - - prev_bus = find_bus_wprev (parent_busno, NULL, 0); - - if (!prev_bus) { - debug ("something terribly wrong. Cannot find parent bus to the one to remove\n"); - return -ENODEV; - } - - debug ("In ibmphp_remove_bus... prev_bus->busno is %x\n", prev_bus->busno); - - rc = remove_ranges (bus, prev_bus); - if (rc) - return rc; - - if (bus->firstIO) { - res_cur = bus->firstIO; - while (res_cur) { - res_tmp = res_cur; - if (res_cur->next) - res_cur = res_cur->next; - else - res_cur = res_cur->nextRange; - kfree (res_tmp); - res_tmp = NULL; - } - bus->firstIO = NULL; - } - if (bus->firstMem) { - res_cur = bus->firstMem; - while (res_cur) { - res_tmp = res_cur; - if (res_cur->next) - res_cur = res_cur->next; - else - res_cur = res_cur->nextRange; - kfree (res_tmp); - res_tmp = NULL; - } - bus->firstMem = NULL; - } - if (bus->firstPFMem) { - res_cur = bus->firstPFMem; - while (res_cur) { - res_tmp = res_cur; - if (res_cur->next) - res_cur = res_cur->next; - else - res_cur = res_cur->nextRange; - kfree (res_tmp); - res_tmp = NULL; - } - bus->firstPFMem = NULL; - } - - if (bus->firstPFMemFromMem) { - res_cur = bus->firstPFMemFromMem; - while (res_cur) { - res_tmp = res_cur; - res_cur = res_cur->next; - - kfree (res_tmp); - res_tmp = NULL; - } - bus->firstPFMemFromMem = NULL; - } - - list_del (&bus->bus_list); - kfree (bus); - return 0; -} - -/****************************************************************************** - * This routine deletes the ranges from a given bus, and the entries from the - * parent's bus in the resources - * Input: current bus, previous bus - * Output: 0, -EINVAL - ******************************************************************************/ -static int remove_ranges (struct bus_node *bus_cur, struct bus_node *bus_prev) -{ - struct range_node *range_cur; - struct range_node *range_tmp; - int i; - struct resource_node *res = NULL; - - if (bus_cur->noIORanges) { - range_cur = bus_cur->rangeIO; - for (i = 0; i < bus_cur->noIORanges; i++) { - if (ibmphp_find_resource (bus_prev, range_cur->start, &res, IO) < 0) - return -EINVAL; - ibmphp_remove_resource (res); - - range_tmp = range_cur; - range_cur = range_cur->next; - kfree (range_tmp); - range_tmp = NULL; - } - bus_cur->rangeIO = NULL; - } - if (bus_cur->noMemRanges) { - range_cur = bus_cur->rangeMem; - for (i = 0; i < bus_cur->noMemRanges; i++) { - if (ibmphp_find_resource (bus_prev, range_cur->start, &res, MEM) < 0) - return -EINVAL; - - ibmphp_remove_resource (res); - range_tmp = range_cur; - range_cur = range_cur->next; - kfree (range_tmp); - range_tmp = NULL; - } - bus_cur->rangeMem = NULL; - } - if (bus_cur->noPFMemRanges) { - range_cur = bus_cur->rangePFMem; - for (i = 0; i < bus_cur->noPFMemRanges; i++) { - if (ibmphp_find_resource (bus_prev, range_cur->start, &res, PFMEM) < 0) - return -EINVAL; - - ibmphp_remove_resource (res); - range_tmp = range_cur; - range_cur = range_cur->next; - kfree (range_tmp); - range_tmp = NULL; - } - bus_cur->rangePFMem = NULL; - } - return 0; -} - -/* - * find the resource node in the bus - * Input: Resource needed, start address of the resource, type of resource - */ -int ibmphp_find_resource (struct bus_node *bus, u32 start_address, struct resource_node **res, int flag) -{ - struct resource_node *res_cur = NULL; - char * type = ""; - - if (!bus) { - err ("The bus passed in NULL to find resource \n"); - return -ENODEV; - } - - switch (flag) { - case IO: - res_cur = bus->firstIO; - type = "io"; - break; - case MEM: - res_cur = bus->firstMem; - type = "mem"; - break; - case PFMEM: - res_cur = bus->firstPFMem; - type = "pfmem"; - break; - default: - err ("wrong type of flag \n"); - return -EINVAL; - } - - while (res_cur) { - if (res_cur->start == start_address) { - *res = res_cur; - break; - } - if (res_cur->next) - res_cur = res_cur->next; - else - res_cur = res_cur->nextRange; - } - - if (!res_cur) { - if (flag == PFMEM) { - res_cur = bus->firstPFMemFromMem; - while (res_cur) { - if (res_cur->start == start_address) { - *res = res_cur; - break; - } - res_cur = res_cur->next; - } - if (!res_cur) { - debug ("SOS...cannot find %s resource in the bus. \n", type); - return -EINVAL; - } - } else { - debug ("SOS... cannot find %s resource in the bus. \n", type); - return -EINVAL; - } - } - - if (*res) - debug ("*res->start = %x \n", (*res)->start); - - return 0; -} - -/*********************************************************************** - * This routine will free the resource structures used by the - * system. It is called from cleanup routine for the module - * Parameters: none - * Returns: none - ***********************************************************************/ -void ibmphp_free_resources (void) -{ - struct bus_node *bus_cur = NULL; - struct bus_node *bus_tmp; - struct range_node *range_cur; - struct range_node *range_tmp; - struct resource_node *res_cur; - struct resource_node *res_tmp; - struct list_head *tmp; - struct list_head *next; - int i = 0; - flags = 1; - - list_for_each_safe (tmp, next, &gbuses) { - bus_cur = list_entry (tmp, struct bus_node, bus_list); - if (bus_cur->noIORanges) { - range_cur = bus_cur->rangeIO; - for (i = 0; i < bus_cur->noIORanges; i++) { - if (!range_cur) - break; - range_tmp = range_cur; - range_cur = range_cur->next; - kfree (range_tmp); - range_tmp = NULL; - } - } - if (bus_cur->noMemRanges) { - range_cur = bus_cur->rangeMem; - for (i = 0; i < bus_cur->noMemRanges; i++) { - if (!range_cur) - break; - range_tmp = range_cur; - range_cur = range_cur->next; - kfree (range_tmp); - range_tmp = NULL; - } - } - if (bus_cur->noPFMemRanges) { - range_cur = bus_cur->rangePFMem; - for (i = 0; i < bus_cur->noPFMemRanges; i++) { - if (!range_cur) - break; - range_tmp = range_cur; - range_cur = range_cur->next; - kfree (range_tmp); - range_tmp = NULL; - } - } - - if (bus_cur->firstIO) { - res_cur = bus_cur->firstIO; - while (res_cur) { - res_tmp = res_cur; - if (res_cur->next) - res_cur = res_cur->next; - else - res_cur = res_cur->nextRange; - kfree (res_tmp); - res_tmp = NULL; - } - bus_cur->firstIO = NULL; - } - if (bus_cur->firstMem) { - res_cur = bus_cur->firstMem; - while (res_cur) { - res_tmp = res_cur; - if (res_cur->next) - res_cur = res_cur->next; - else - res_cur = res_cur->nextRange; - kfree (res_tmp); - res_tmp = NULL; - } - bus_cur->firstMem = NULL; - } - if (bus_cur->firstPFMem) { - res_cur = bus_cur->firstPFMem; - while (res_cur) { - res_tmp = res_cur; - if (res_cur->next) - res_cur = res_cur->next; - else - res_cur = res_cur->nextRange; - kfree (res_tmp); - res_tmp = NULL; - } - bus_cur->firstPFMem = NULL; - } - - if (bus_cur->firstPFMemFromMem) { - res_cur = bus_cur->firstPFMemFromMem; - while (res_cur) { - res_tmp = res_cur; - res_cur = res_cur->next; - - kfree (res_tmp); - res_tmp = NULL; - } - bus_cur->firstPFMemFromMem = NULL; - } - - bus_tmp = bus_cur; - list_del (&bus_cur->bus_list); - kfree (bus_tmp); - bus_tmp = NULL; - } -} - -/********************************************************************************* - * This function will go over the PFmem resources to check if the EBDA allocated - * pfmem out of memory buckets of the bus. If so, it will change the range numbers - * and a flag to indicate that this resource is out of memory. It will also move the - * Pfmem out of the pfmem resource list to the PFMemFromMem list, and will create - * a new Mem node - * This routine is called right after initialization - *******************************************************************************/ -static int __init once_over (void) -{ - struct resource_node *pfmem_cur; - struct resource_node *pfmem_prev; - struct resource_node *mem; - struct bus_node *bus_cur; - struct list_head *tmp; - - list_for_each (tmp, &gbuses) { - bus_cur = list_entry (tmp, struct bus_node, bus_list); - if ((!bus_cur->rangePFMem) && (bus_cur->firstPFMem)) { - for (pfmem_cur = bus_cur->firstPFMem, pfmem_prev = NULL; pfmem_cur; pfmem_prev = pfmem_cur, pfmem_cur = pfmem_cur->next) { - pfmem_cur->fromMem = TRUE; - if (pfmem_prev) - pfmem_prev->next = pfmem_cur->next; - else - bus_cur->firstPFMem = pfmem_cur->next; - - if (!bus_cur->firstPFMemFromMem) - pfmem_cur->next = NULL; - else - /* we don't need to sort PFMemFromMem since we're using mem node for - all the real work anyways, so just insert at the beginning of the - list - */ - pfmem_cur->next = bus_cur->firstPFMemFromMem; - - bus_cur->firstPFMemFromMem = pfmem_cur; - - mem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - if (!mem) { - err ("out of system memory \n"); - return -ENOMEM; - } - memset (mem, 0, sizeof (struct resource_node)); - mem->type = MEM; - mem->busno = pfmem_cur->busno; - mem->devfunc = pfmem_cur->devfunc; - mem->start = pfmem_cur->start; - mem->end = pfmem_cur->end; - mem->len = pfmem_cur->len; - if (ibmphp_add_resource (mem) < 0) - err ("Trouble...trouble... EBDA allocated pfmem from mem, but system doesn't display it has this space... unless not PCI device...\n"); - pfmem_cur->rangeno = mem->rangeno; - } /* end for pfmem */ - } /* end if */ - } /* end list_for_each bus */ - return 0; -} - -int ibmphp_add_pfmem_from_mem (struct resource_node *pfmem) -{ - struct bus_node *bus_cur = find_bus_wprev (pfmem->busno, NULL, 0); - - if (!bus_cur) { - err ("cannot find bus of pfmem to add...\n"); - return -ENODEV; - } - - if (bus_cur->firstPFMemFromMem) - pfmem->next = bus_cur->firstPFMemFromMem; - else - pfmem->next = NULL; - - bus_cur->firstPFMemFromMem = pfmem; - - return 0; -} - -/* This routine just goes through the buses to see if the bus already exists. - * It is called from ibmphp_find_sec_number, to find out a secondary bus number for - * bridged cards - * Parameters: bus_number - * Returns: Bus pointer or NULL - */ -struct bus_node *ibmphp_find_res_bus (u8 bus_number) -{ - return find_bus_wprev (bus_number, NULL, 0); -} - -static inline struct bus_node *find_bus_wprev (u8 bus_number, struct bus_node **prev, u8 flag) -{ - struct bus_node *bus_cur; - struct list_head *tmp; - struct list_head *tmp_prev; - - list_for_each (tmp, &gbuses) { - tmp_prev = tmp->prev; - bus_cur = list_entry (tmp, struct bus_node, bus_list); - if (flag) - *prev = list_entry (tmp_prev, struct bus_node, bus_list); - if (bus_cur->busno == bus_number) - return bus_cur; - } - - return NULL; -} - -void ibmphp_print_test (void) -{ - int i = 0; - struct bus_node *bus_cur = NULL; - struct range_node *range; - struct resource_node *res; - struct list_head *tmp; - - debug_pci ("*****************START**********************\n"); - - if ((!list_empty(&gbuses)) && flags) { - err ("The GBUSES is not NULL?!?!?!?!?\n"); - return; - } - - list_for_each (tmp, &gbuses) { - bus_cur = list_entry (tmp, struct bus_node, bus_list); - debug_pci ("This is bus # %d. There are \n", bus_cur->busno); - debug_pci ("IORanges = %d\t", bus_cur->noIORanges); - debug_pci ("MemRanges = %d\t", bus_cur->noMemRanges); - debug_pci ("PFMemRanges = %d\n", bus_cur->noPFMemRanges); - debug_pci ("The IO Ranges are as follows:\n"); - if (bus_cur->rangeIO) { - range = bus_cur->rangeIO; - for (i = 0; i < bus_cur->noIORanges; i++) { - debug_pci ("rangeno is %d\n", range->rangeno); - debug_pci ("[%x - %x]\n", range->start, range->end); - range = range->next; - } - } - - debug_pci ("The Mem Ranges are as follows:\n"); - if (bus_cur->rangeMem) { - range = bus_cur->rangeMem; - for (i = 0; i < bus_cur->noMemRanges; i++) { - debug_pci ("rangeno is %d\n", range->rangeno); - debug_pci ("[%x - %x]\n", range->start, range->end); - range = range->next; - } - } - - debug_pci ("The PFMem Ranges are as follows:\n"); - - if (bus_cur->rangePFMem) { - range = bus_cur->rangePFMem; - for (i = 0; i < bus_cur->noPFMemRanges; i++) { - debug_pci ("rangeno is %d\n", range->rangeno); - debug_pci ("[%x - %x]\n", range->start, range->end); - range = range->next; - } - } - - debug_pci ("The resources on this bus are as follows\n"); - - debug_pci ("IO...\n"); - if (bus_cur->firstIO) { - res = bus_cur->firstIO; - while (res) { - debug_pci ("The range # is %d\n", res->rangeno); - debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc); - debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len); - if (res->next) - res = res->next; - else if (res->nextRange) - res = res->nextRange; - else - break; - } - } - debug_pci ("Mem...\n"); - if (bus_cur->firstMem) { - res = bus_cur->firstMem; - while (res) { - debug_pci ("The range # is %d\n", res->rangeno); - debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc); - debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len); - if (res->next) - res = res->next; - else if (res->nextRange) - res = res->nextRange; - else - break; - } - } - debug_pci ("PFMem...\n"); - if (bus_cur->firstPFMem) { - res = bus_cur->firstPFMem; - while (res) { - debug_pci ("The range # is %d\n", res->rangeno); - debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc); - debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len); - if (res->next) - res = res->next; - else if (res->nextRange) - res = res->nextRange; - else - break; - } - } - - debug_pci ("PFMemFromMem...\n"); - if (bus_cur->firstPFMemFromMem) { - res = bus_cur->firstPFMemFromMem; - while (res) { - debug_pci ("The range # is %d\n", res->rangeno); - debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc); - debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len); - res = res->next; - } - } - } - debug_pci ("***********************END***********************\n"); -} - -static int range_exists_already (struct range_node * range, struct bus_node * bus_cur, u8 type) -{ - struct range_node * range_cur = NULL; - switch (type) { - case IO: - range_cur = bus_cur->rangeIO; - break; - case MEM: - range_cur = bus_cur->rangeMem; - break; - case PFMEM: - range_cur = bus_cur->rangePFMem; - break; - default: - err ("wrong type passed to find out if range already exists \n"); - return -ENODEV; - } - - while (range_cur) { - if ((range_cur->start == range->start) && (range_cur->end == range->end)) - return 1; - range_cur = range_cur->next; - } - - return 0; -} - -/* This routine will read the windows for any PPB we have and update the - * range info for the secondary bus, and will also input this info into - * primary bus, since BIOS doesn't. This is for PPB that are in the system - * on bootup. For bridged cards that were added during previous load of the - * driver, only the ranges and the bus structure are added, the devices are - * added from NVRAM - * Input: primary busno - * Returns: none - * Note: this function doesn't take into account IO restrictions etc, - * so will only work for bridges with no video/ISA devices behind them It - * also will not work for onboard PPB's that can have more than 1 *bus - * behind them All these are TO DO. - * Also need to add more error checkings... (from fnc returns etc) - */ -static int __init update_bridge_ranges (struct bus_node **bus) -{ - u8 sec_busno, device, function, hdr_type, start_io_address, end_io_address; - u16 vendor_id, upper_io_start, upper_io_end, start_mem_address, end_mem_address; - u32 start_address, end_address, upper_start, upper_end; - struct bus_node *bus_sec; - struct bus_node *bus_cur; - struct resource_node *io; - struct resource_node *mem; - struct resource_node *pfmem; - struct range_node *range; - unsigned int devfn; - - bus_cur = *bus; - if (!bus_cur) - return -ENODEV; - ibmphp_pci_bus->number = bus_cur->busno; - - debug ("inside %s \n", __FUNCTION__); - debug ("bus_cur->busno = %x\n", bus_cur->busno); - - for (device = 0; device < 32; device++) { - for (function = 0x00; function < 0x08; function++) { - devfn = PCI_DEVFN(device, function); - pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id); - - if (vendor_id != PCI_VENDOR_ID_NOTVALID) { - /* found correct device!!! */ - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type); - - switch (hdr_type) { - case PCI_HEADER_TYPE_NORMAL: - function = 0x8; - break; - case PCI_HEADER_TYPE_MULTIDEVICE: - break; - case PCI_HEADER_TYPE_BRIDGE: - function = 0x8; - case PCI_HEADER_TYPE_MULTIBRIDGE: - /* We assume here that only 1 bus behind the bridge - TO DO: add functionality for several: - temp = secondary; - while (temp < subordinate) { - ... - temp++; - } - */ - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_busno); - bus_sec = find_bus_wprev (sec_busno, NULL, 0); - /* this bus structure doesn't exist yet, PPB was configured during previous loading of ibmphp */ - if (!bus_sec) { - bus_sec = alloc_error_bus (NULL, sec_busno, 1); - /* the rest will be populated during NVRAM call */ - return 0; - } - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, &start_io_address); - pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_LIMIT, &end_io_address); - pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_IO_BASE_UPPER16, &upper_io_start); - pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_IO_LIMIT_UPPER16, &upper_io_end); - start_address = (start_io_address & PCI_IO_RANGE_MASK) << 8; - start_address |= (upper_io_start << 16); - end_address = (end_io_address & PCI_IO_RANGE_MASK) << 8; - end_address |= (upper_io_end << 16); - - if ((start_address) && (start_address <= end_address)) { - range = kmalloc (sizeof (struct range_node), GFP_KERNEL); - if (!range) { - err ("out of system memory \n"); - return -ENOMEM; - } - memset (range, 0, sizeof (struct range_node)); - range->start = start_address; - range->end = end_address + 0xfff; - - if (bus_sec->noIORanges > 0) { - if (!range_exists_already (range, bus_sec, IO)) { - add_range (IO, range, bus_sec); - ++bus_sec->noIORanges; - } else { - kfree (range); - range = NULL; - } - } else { - /* 1st IO Range on the bus */ - range->rangeno = 1; - bus_sec->rangeIO = range; - ++bus_sec->noIORanges; - } - fix_resources (bus_sec); - - if (ibmphp_find_resource (bus_cur, start_address, &io, IO)) { - io = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - if (!io) { - kfree (range); - err ("out of system memory \n"); - return -ENOMEM; - } - memset (io, 0, sizeof (struct resource_node)); - io->type = IO; - io->busno = bus_cur->busno; - io->devfunc = ((device << 3) | (function & 0x7)); - io->start = start_address; - io->end = end_address + 0xfff; - io->len = io->end - io->start + 1; - ibmphp_add_resource (io); - } - } - - pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_BASE, &start_mem_address); - pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_LIMIT, &end_mem_address); - - start_address = 0x00000000 | (start_mem_address & PCI_MEMORY_RANGE_MASK) << 16; - end_address = 0x00000000 | (end_mem_address & PCI_MEMORY_RANGE_MASK) << 16; - - if ((start_address) && (start_address <= end_address)) { - - range = kmalloc (sizeof (struct range_node), GFP_KERNEL); - if (!range) { - err ("out of system memory \n"); - return -ENOMEM; - } - memset (range, 0, sizeof (struct range_node)); - range->start = start_address; - range->end = end_address + 0xfffff; - - if (bus_sec->noMemRanges > 0) { - if (!range_exists_already (range, bus_sec, MEM)) { - add_range (MEM, range, bus_sec); - ++bus_sec->noMemRanges; - } else { - kfree (range); - range = NULL; - } - } else { - /* 1st Mem Range on the bus */ - range->rangeno = 1; - bus_sec->rangeMem = range; - ++bus_sec->noMemRanges; - } - - fix_resources (bus_sec); - - if (ibmphp_find_resource (bus_cur, start_address, &mem, MEM)) { - mem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - if (!mem) { - kfree (range); - err ("out of system memory \n"); - return -ENOMEM; - } - memset (mem, 0, sizeof (struct resource_node)); - mem->type = MEM; - mem->busno = bus_cur->busno; - mem->devfunc = ((device << 3) | (function & 0x7)); - mem->start = start_address; - mem->end = end_address + 0xfffff; - mem->len = mem->end - mem->start + 1; - ibmphp_add_resource (mem); - } - } - pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, &start_mem_address); - pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &end_mem_address); - pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_PREF_BASE_UPPER32, &upper_start); - pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_PREF_LIMIT_UPPER32, &upper_end); - start_address = 0x00000000 | (start_mem_address & PCI_MEMORY_RANGE_MASK) << 16; - end_address = 0x00000000 | (end_mem_address & PCI_MEMORY_RANGE_MASK) << 16; -#if BITS_PER_LONG == 64 - start_address |= ((long) upper_start) << 32; - end_address |= ((long) upper_end) << 32; -#endif - - if ((start_address) && (start_address <= end_address)) { - - range = kmalloc (sizeof (struct range_node), GFP_KERNEL); - if (!range) { - err ("out of system memory \n"); - return -ENOMEM; - } - memset (range, 0, sizeof (struct range_node)); - range->start = start_address; - range->end = end_address + 0xfffff; - - if (bus_sec->noPFMemRanges > 0) { - if (!range_exists_already (range, bus_sec, PFMEM)) { - add_range (PFMEM, range, bus_sec); - ++bus_sec->noPFMemRanges; - } else { - kfree (range); - range = NULL; - } - } else { - /* 1st PFMem Range on the bus */ - range->rangeno = 1; - bus_sec->rangePFMem = range; - ++bus_sec->noPFMemRanges; - } - - fix_resources (bus_sec); - if (ibmphp_find_resource (bus_cur, start_address, &pfmem, PFMEM)) { - pfmem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); - if (!pfmem) { - kfree (range); - err ("out of system memory \n"); - return -ENOMEM; - } - memset (pfmem, 0, sizeof (struct resource_node)); - pfmem->type = PFMEM; - pfmem->busno = bus_cur->busno; - pfmem->devfunc = ((device << 3) | (function & 0x7)); - pfmem->start = start_address; - pfmem->end = end_address + 0xfffff; - pfmem->len = pfmem->end - pfmem->start + 1; - pfmem->fromMem = FALSE; - - ibmphp_add_resource (pfmem); - } - } - break; - } /* end of switch */ - } /* end if vendor */ - } /* end for function */ - } /* end for device */ - - bus = &bus_cur; - return 0; -} diff -Nru a/drivers/hotplug/pci_hotplug.h b/drivers/hotplug/pci_hotplug.h --- a/drivers/hotplug/pci_hotplug.h Mon Jun 9 23:16:10 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,146 +0,0 @@ -/* - * PCI HotPlug Core Functions - * - * Copyright (c) 1995,2001 Compaq Computer Corporation - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or - * NON INFRINGEMENT. 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. - * - * Send feedback to <greg@kroah.com> - * - */ -#ifndef _PCI_HOTPLUG_H -#define _PCI_HOTPLUG_H - - -/* These values come from the PCI Hotplug Spec */ -enum pci_bus_speed { - PCI_SPEED_33MHz = 0x00, - PCI_SPEED_66MHz = 0x01, - PCI_SPEED_66MHz_PCIX = 0x02, - PCI_SPEED_100MHz_PCIX = 0x03, - PCI_SPEED_133MHz_PCIX = 0x04, - PCI_SPEED_66MHz_PCIX_266 = 0x09, - PCI_SPEED_100MHz_PCIX_266 = 0x0a, - PCI_SPEED_133MHz_PCIX_266 = 0x0b, - PCI_SPEED_66MHz_PCIX_533 = 0x11, - PCI_SPEED_100MHz_PCIX_533 = 0X12, - PCI_SPEED_133MHz_PCIX_533 = 0x13, - PCI_SPEED_UNKNOWN = 0xff, -}; - -struct hotplug_slot; -struct hotplug_slot_attribute { - struct attribute attr; - ssize_t (*show)(struct hotplug_slot *, char *); - ssize_t (*store)(struct hotplug_slot *, const char *, size_t); -}; -/** - * struct hotplug_slot_ops -the callbacks that the hotplug pci core can use - * @owner: The module owner of this structure - * @enable_slot: Called when the user wants to enable a specific pci slot - * @disable_slot: Called when the user wants to disable a specific pci slot - * @set_attention_status: Called to set the specific slot's attention LED to - * the specified value - * @hardware_test: Called to run a specified hardware test on the specified - * slot. - * @get_power_status: Called to get the current power status of a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_attention_status: Called to get the current attention status of a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_latch_status: Called to get the current latch status of a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_adapter_status: Called to get see if an adapter is present in the slot or not. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_max_bus_speed: Called to get the max bus speed for a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * @get_cur_bus_speed: Called to get the current bus speed for a slot. - * If this field is NULL, the value passed in the struct hotplug_slot_info - * will be used when this value is requested by a user. - * - * The table of function pointers that is passed to the hotplug pci core by a - * hotplug pci driver. These functions are called by the hotplug pci core when - * the user wants to do something to a specific slot (query it for information, - * set an LED, enable / disable power, etc.) - */ -struct hotplug_slot_ops { - struct module *owner; - int (*enable_slot) (struct hotplug_slot *slot); - int (*disable_slot) (struct hotplug_slot *slot); - int (*set_attention_status) (struct hotplug_slot *slot, u8 value); - int (*hardware_test) (struct hotplug_slot *slot, u32 value); - int (*get_power_status) (struct hotplug_slot *slot, u8 *value); - int (*get_attention_status) (struct hotplug_slot *slot, u8 *value); - int (*get_latch_status) (struct hotplug_slot *slot, u8 *value); - int (*get_adapter_status) (struct hotplug_slot *slot, u8 *value); - int (*get_max_bus_speed) (struct hotplug_slot *slot, enum pci_bus_speed *value); - int (*get_cur_bus_speed) (struct hotplug_slot *slot, enum pci_bus_speed *value); -}; - -/** - * struct hotplug_slot_info - used to notify the hotplug pci core of the state of the slot - * @power: if power is enabled or not (1/0) - * @attention_status: if the attention light is enabled or not (1/0) - * @latch_status: if the latch (if any) is open or closed (1/0) - * @adapter_present: if there is a pci board present in the slot or not (1/0) - * - * Used to notify the hotplug pci core of the status of a specific slot. - */ -struct hotplug_slot_info { - u8 power_status; - u8 attention_status; - u8 latch_status; - u8 adapter_status; - enum pci_bus_speed max_bus_speed; - enum pci_bus_speed cur_bus_speed; -}; - -/** - * struct hotplug_slot - used to register a physical slot with the hotplug pci core - * @name: the name of the slot being registered. This string must - * be unique amoung slots registered on this system. - * @ops: pointer to the &struct hotplug_slot_ops to be used for this slot - * @info: pointer to the &struct hotplug_slot_info for the inital values for - * this slot. - * @private: used by the hotplug pci controller driver to store whatever it - * needs. - */ -struct hotplug_slot { - char *name; - struct hotplug_slot_ops *ops; - struct hotplug_slot_info *info; - void *private; - - /* Variables below this are for use only by the hotplug pci core. */ - struct list_head slot_list; - struct kobject kobj; -}; - -extern int pci_hp_register (struct hotplug_slot *slot); -extern int pci_hp_deregister (struct hotplug_slot *slot); -extern int pci_hp_change_slot_info (struct hotplug_slot *slot, - struct hotplug_slot_info *info); - -#endif - diff -Nru a/drivers/hotplug/pci_hotplug_core.c b/drivers/hotplug/pci_hotplug_core.c --- a/drivers/hotplug/pci_hotplug_core.c Mon Jun 9 23:16:17 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,666 +0,0 @@ -/* - * PCI HotPlug Controller Core - * - * Copyright (c) 2001-2002 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001-2002 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or - * NON INFRINGEMENT. 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. - * - * Send feedback to <greg@kroah.com> - * - * Filesystem portion based on work done by Pat Mochel on ddfs/driverfs - * - */ - -#include <linux/config.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/types.h> -#include <linux/list.h> -#include <linux/pagemap.h> -#include <linux/slab.h> -#include <linux/smp_lock.h> -#include <linux/init.h> -#include <linux/mount.h> -#include <linux/namei.h> -#include <linux/pci.h> -#include <asm/uaccess.h> -#include <linux/kobject.h> -#include <linux/sysfs.h> -#include "pci_hotplug.h" - - -#if !defined(CONFIG_HOTPLUG_PCI_MODULE) - #define MY_NAME "pci_hotplug" -#else - #define MY_NAME THIS_MODULE->name -#endif - -#define dbg(fmt, arg...) do { if (debug) printk(KERN_DEBUG "%s: %s: " fmt , MY_NAME , __FUNCTION__ , ## arg); } while (0) -#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg) -#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg) -#define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg) - - -/* local variables */ -static int debug; - -#define DRIVER_VERSION "0.5" -#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Scott Murray <scottm@somanetworks.com>" -#define DRIVER_DESC "PCI Hot Plug PCI Core" - - -////////////////////////////////////////////////////////////////// - -static LIST_HEAD(pci_hotplug_slot_list); - -static struct subsystem hotplug_slots_subsys; - -static ssize_t hotplug_slot_attr_show(struct kobject *kobj, - struct attribute *attr, char *buf) -{ - struct hotplug_slot *slot=container_of(kobj, - struct hotplug_slot,kobj); - struct hotplug_slot_attribute *attribute = - container_of(attr, struct hotplug_slot_attribute, attr); - return attribute->show ? attribute->show(slot, buf) : 0; -} - -static ssize_t hotplug_slot_attr_store(struct kobject *kobj, - struct attribute *attr, const char *buf, size_t len) -{ - struct hotplug_slot *slot=container_of(kobj, - struct hotplug_slot,kobj); - struct hotplug_slot_attribute *attribute = - container_of(attr, struct hotplug_slot_attribute, attr); - return attribute->store ? attribute->store(slot, buf, len) : 0; -} - -static struct sysfs_ops hotplug_slot_sysfs_ops = { - .show = hotplug_slot_attr_show, - .store = hotplug_slot_attr_store, -}; - -static struct kobj_type hotplug_slot_ktype = { - .sysfs_ops = &hotplug_slot_sysfs_ops -}; - -static decl_subsys(hotplug_slots, &hotplug_slot_ktype, NULL); - - -/* these strings match up with the values in pci_bus_speed */ -static char *pci_bus_speed_strings[] = { - "33 MHz PCI", /* 0x00 */ - "66 MHz PCI", /* 0x01 */ - "66 MHz PCIX", /* 0x02 */ - "100 MHz PCIX", /* 0x03 */ - "133 MHz PCIX", /* 0x04 */ - NULL, /* 0x05 */ - NULL, /* 0x06 */ - NULL, /* 0x07 */ - NULL, /* 0x08 */ - "66 MHz PCIX 266", /* 0x09 */ - "100 MHz PCIX 266", /* 0x0a */ - "133 MHz PCIX 266", /* 0x0b */ - NULL, /* 0x0c */ - NULL, /* 0x0d */ - NULL, /* 0x0e */ - NULL, /* 0x0f */ - NULL, /* 0x10 */ - "66 MHz PCIX 533", /* 0x11 */ - "100 MHz PCIX 533", /* 0x12 */ - "133 MHz PCIX 533", /* 0x13 */ -}; - -#ifdef CONFIG_HOTPLUG_PCI_CPCI -extern int cpci_hotplug_init(int debug); -extern void cpci_hotplug_exit(void); -#else -static inline int cpci_hotplug_init(int debug) { return 0; } -static inline void cpci_hotplug_exit(void) { } -#endif - -/* Weee, fun with macros... */ -#define GET_STATUS(name,type) \ -static int get_##name (struct hotplug_slot *slot, type *value) \ -{ \ - struct hotplug_slot_ops *ops = slot->ops; \ - int retval = 0; \ - if (try_module_get(ops->owner)) { \ - if (ops->get_##name) \ - retval = ops->get_##name (slot, value); \ - else \ - *value = slot->info->name; \ - module_put(ops->owner); \ - } \ - return retval; \ -} - -GET_STATUS(power_status, u8) -GET_STATUS(attention_status, u8) -GET_STATUS(latch_status, u8) -GET_STATUS(adapter_status, u8) -GET_STATUS(max_bus_speed, enum pci_bus_speed) -GET_STATUS(cur_bus_speed, enum pci_bus_speed) - -static ssize_t power_read_file (struct hotplug_slot *slot, char *buf) -{ - int retval; - u8 value; - - retval = get_power_status (slot, &value); - if (retval) - goto exit; - retval = sprintf (buf, "%d\n", value); -exit: - return retval; -} - -static ssize_t power_write_file (struct hotplug_slot *slot, const char *buf, - size_t count) -{ - unsigned long lpower; - u8 power; - int retval = 0; - - lpower = simple_strtoul (buf, NULL, 10); - power = (u8)(lpower & 0xff); - dbg ("power = %d\n", power); - - if (!try_module_get(slot->ops->owner)) { - retval = -ENODEV; - goto exit; - } - switch (power) { - case 0: - if (slot->ops->disable_slot) - retval = slot->ops->disable_slot(slot); - break; - - case 1: - if (slot->ops->enable_slot) - retval = slot->ops->enable_slot(slot); - break; - - default: - err ("Illegal value specified for power\n"); - retval = -EINVAL; - } - module_put(slot->ops->owner); - -exit: - if (retval) - return retval; - return count; -} - -static struct hotplug_slot_attribute hotplug_slot_attr_power = { - .attr = {.name = "power", .mode = S_IFREG | S_IRUGO | S_IWUSR}, - .show = power_read_file, - .store = power_write_file -}; - -static ssize_t attention_read_file (struct hotplug_slot *slot, char *buf) -{ - int retval; - u8 value; - - retval = get_attention_status (slot, &value); - if (retval) - goto exit; - retval = sprintf (buf, "%d\n", value); - -exit: - return retval; -} - -static ssize_t attention_write_file (struct hotplug_slot *slot, const char *buf, - size_t count) -{ - unsigned long lattention; - u8 attention; - int retval = 0; - - lattention = simple_strtoul (buf, NULL, 10); - attention = (u8)(lattention & 0xff); - dbg (" - attention = %d\n", attention); - - if (!try_module_get(slot->ops->owner)) { - retval = -ENODEV; - goto exit; - } - if (slot->ops->set_attention_status) - retval = slot->ops->set_attention_status(slot, attention); - module_put(slot->ops->owner); - -exit: - if (retval) - return retval; - return count; -} - -static struct hotplug_slot_attribute hotplug_slot_attr_attention = { - .attr = {.name = "attention", .mode = S_IFREG | S_IRUGO | S_IWUSR}, - .show = attention_read_file, - .store = attention_write_file -}; - -static ssize_t latch_read_file (struct hotplug_slot *slot, char *buf) -{ - int retval; - u8 value; - - retval = get_latch_status (slot, &value); - if (retval) - goto exit; - retval = sprintf (buf, "%d\n", value); - -exit: - return retval; -} - -static struct hotplug_slot_attribute hotplug_slot_attr_latch = { - .attr = {.name = "latch", .mode = S_IFREG | S_IRUGO | S_IWUSR}, - .show = latch_read_file, -}; - -static ssize_t presence_read_file (struct hotplug_slot *slot, char *buf) -{ - int retval; - u8 value; - - retval = get_adapter_status (slot, &value); - if (retval) - goto exit; - retval = sprintf (buf, "%d\n", value); - -exit: - return retval; -} - -static struct hotplug_slot_attribute hotplug_slot_attr_presence = { - .attr = {.name = "adapter", .mode = S_IFREG | S_IRUGO | S_IWUSR}, - .show = presence_read_file, -}; - -static char *unknown_speed = "Unknown bus speed"; - -static ssize_t max_bus_speed_read_file (struct hotplug_slot *slot, char *buf) -{ - char *speed_string; - int retval; - enum pci_bus_speed value; - - retval = get_max_bus_speed (slot, &value); - if (retval) - goto exit; - - if (value == PCI_SPEED_UNKNOWN) - speed_string = unknown_speed; - else - speed_string = pci_bus_speed_strings[value]; - - retval = sprintf (buf, "%s\n", speed_string); - -exit: - return retval; -} - -static struct hotplug_slot_attribute hotplug_slot_attr_max_bus_speed = { - .attr = {.name = "max_bus_speed", .mode = S_IFREG | S_IRUGO | S_IWUSR}, - .show = max_bus_speed_read_file, -}; - -static ssize_t cur_bus_speed_read_file (struct hotplug_slot *slot, char *buf) -{ - char *speed_string; - int retval; - enum pci_bus_speed value; - - retval = get_cur_bus_speed (slot, &value); - if (retval) - goto exit; - - if (value == PCI_SPEED_UNKNOWN) - speed_string = unknown_speed; - else - speed_string = pci_bus_speed_strings[value]; - - retval = sprintf (buf, "%s\n", speed_string); - -exit: - return retval; -} - -static struct hotplug_slot_attribute hotplug_slot_attr_cur_bus_speed = { - .attr = {.name = "cur_bus_speed", .mode = S_IFREG | S_IRUGO | S_IWUSR}, - .show = cur_bus_speed_read_file, -}; - -static ssize_t test_write_file (struct hotplug_slot *slot, const char *buf, - size_t count) -{ - unsigned long ltest; - u32 test; - int retval = 0; - - ltest = simple_strtoul (buf, NULL, 10); - test = (u32)(ltest & 0xffffffff); - dbg ("test = %d\n", test); - - if (!try_module_get(slot->ops->owner)) { - retval = -ENODEV; - goto exit; - } - if (slot->ops->hardware_test) - retval = slot->ops->hardware_test(slot, test); - module_put(slot->ops->owner); - -exit: - if (retval) - return retval; - return count; -} - -static struct hotplug_slot_attribute hotplug_slot_attr_test = { - .attr = {.name = "test", .mode = S_IFREG | S_IRUGO | S_IWUSR}, - .store = test_write_file -}; - -static int has_power_file (struct hotplug_slot *slot) -{ - if ((!slot) || (!slot->ops)) - return -ENODEV; - if ((slot->ops->enable_slot) || - (slot->ops->disable_slot) || - (slot->ops->get_power_status)) - return 0; - return -ENOENT; -} - -static int has_attention_file (struct hotplug_slot *slot) -{ - if ((!slot) || (!slot->ops)) - return -ENODEV; - if ((slot->ops->set_attention_status) || - (slot->ops->get_attention_status)) - return 0; - return -ENOENT; -} - -static int has_latch_file (struct hotplug_slot *slot) -{ - if ((!slot) || (!slot->ops)) - return -ENODEV; - if (slot->ops->get_latch_status) - return 0; - return -ENOENT; -} - -static int has_adapter_file (struct hotplug_slot *slot) -{ - if ((!slot) || (!slot->ops)) - return -ENODEV; - if (slot->ops->get_adapter_status) - return 0; - return -ENOENT; -} - -static int has_max_bus_speed_file (struct hotplug_slot *slot) -{ - if ((!slot) || (!slot->ops)) - return -ENODEV; - if (slot->ops->get_max_bus_speed) - return 0; - return -ENOENT; -} - -static int has_cur_bus_speed_file (struct hotplug_slot *slot) -{ - if ((!slot) || (!slot->ops)) - return -ENODEV; - if (slot->ops->get_cur_bus_speed) - return 0; - return -ENOENT; -} - -static int has_test_file (struct hotplug_slot *slot) -{ - if ((!slot) || (!slot->ops)) - return -ENODEV; - if (slot->ops->hardware_test) - return 0; - return -ENOENT; -} - -static int fs_add_slot (struct hotplug_slot *slot) -{ - if (has_power_file(slot) == 0) - sysfs_create_file(&slot->kobj, &hotplug_slot_attr_power.attr); - - if (has_attention_file(slot) == 0) - sysfs_create_file(&slot->kobj, &hotplug_slot_attr_attention.attr); - - if (has_latch_file(slot) == 0) - sysfs_create_file(&slot->kobj, &hotplug_slot_attr_latch.attr); - - if (has_adapter_file(slot) == 0) - sysfs_create_file(&slot->kobj, &hotplug_slot_attr_presence.attr); - - if (has_max_bus_speed_file(slot) == 0) - sysfs_create_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); - - if (has_cur_bus_speed_file(slot) == 0) - sysfs_create_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr); - - if (has_test_file(slot) == 0) - sysfs_create_file(&slot->kobj, &hotplug_slot_attr_test.attr); - - return 0; -} - -static void fs_remove_slot (struct hotplug_slot *slot) -{ - if (has_power_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr); - - if (has_attention_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_attention.attr); - - if (has_latch_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_latch.attr); - - if (has_adapter_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr); - - if (has_max_bus_speed_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); - - if (has_cur_bus_speed_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr); - - if (has_test_file(slot) == 0) - sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_test.attr); -} - -static struct hotplug_slot *get_slot_from_name (const char *name) -{ - struct hotplug_slot *slot; - struct list_head *tmp; - - list_for_each (tmp, &pci_hotplug_slot_list) { - slot = list_entry (tmp, struct hotplug_slot, slot_list); - if (strcmp(slot->name, name) == 0) - return slot; - } - return NULL; -} - -/** - * pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem - * @slot: pointer to the &struct hotplug_slot to register - * - * Registers a hotplug slot with the pci hotplug subsystem, which will allow - * userspace interaction to the slot. - * - * Returns 0 if successful, anything else for an error. - */ -int pci_hp_register (struct hotplug_slot *slot) -{ - int result; - - if (slot == NULL) - return -ENODEV; - if ((slot->info == NULL) || (slot->ops == NULL)) - return -EINVAL; - - strlcpy(slot->kobj.name, slot->name, KOBJ_NAME_LEN); - kobj_set_kset_s(slot, hotplug_slots_subsys); - - /* this can fail if we have already registered a slot with the same name */ - if (kobject_register(&slot->kobj)) { - err("Unable to register kobject"); - return -EINVAL; - } - - list_add (&slot->slot_list, &pci_hotplug_slot_list); - - result = fs_add_slot (slot); - dbg ("Added slot %s to the list\n", slot->name); - return result; -} - -/** - * pci_hp_deregister - deregister a hotplug_slot with the PCI hotplug subsystem - * @slot: pointer to the &struct hotplug_slot to deregister - * - * The @slot must have been registered with the pci hotplug subsystem - * previously with a call to pci_hp_register(). - * - * Returns 0 if successful, anything else for an error. - */ -int pci_hp_deregister (struct hotplug_slot *slot) -{ - struct hotplug_slot *temp; - - if (slot == NULL) - return -ENODEV; - - temp = get_slot_from_name (slot->name); - if (temp != slot) { - return -ENODEV; - } - list_del (&slot->slot_list); - - fs_remove_slot (slot); - dbg ("Removed slot %s from the list\n", slot->name); - kobject_unregister(&slot->kobj); - return 0; -} - -/** - * pci_hp_change_slot_info - changes the slot's information structure in the core - * @slot: pointer to the slot whose info has changed - * @info: pointer to the info copy into the slot's info structure - * - * @slot must have been registered with the pci - * hotplug subsystem previously with a call to pci_hp_register(). - * - * Returns 0 if successful, anything else for an error. - */ -int pci_hp_change_slot_info (struct hotplug_slot *slot, struct hotplug_slot_info *info) -{ - if ((slot == NULL) || (info == NULL)) - return -ENODEV; - - /* - * check all fields in the info structure, and update timestamps - * for the files referring to the fields that have now changed. - */ - if ((has_power_file(slot) == 0) && - (slot->info->power_status != info->power_status)) - sysfs_update_file(&slot->kobj, &hotplug_slot_attr_power.attr); - - if ((has_attention_file(slot) == 0) && - (slot->info->attention_status != info->attention_status)) - sysfs_update_file(&slot->kobj, &hotplug_slot_attr_attention.attr); - - if ((has_latch_file(slot) == 0) && - (slot->info->latch_status != info->latch_status)) - sysfs_update_file(&slot->kobj, &hotplug_slot_attr_latch.attr); - - if ((has_adapter_file(slot) == 0) && - (slot->info->adapter_status != info->adapter_status)) - sysfs_update_file(&slot->kobj, &hotplug_slot_attr_presence.attr); - - if ((has_max_bus_speed_file(slot) == 0) && - (slot->info->max_bus_speed != info->max_bus_speed)) - sysfs_update_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); - - if ((has_cur_bus_speed_file(slot) == 0) && - (slot->info->cur_bus_speed != info->cur_bus_speed)) - sysfs_update_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr); - - memcpy (slot->info, info, sizeof (struct hotplug_slot_info)); - - return 0; -} - -static int __init pci_hotplug_init (void) -{ - int result; - - kset_set_kset_s(&hotplug_slots_subsys, pci_bus_type.subsys); - result = subsystem_register(&hotplug_slots_subsys); - if (result) { - err("Register subsys with error %d\n", result); - goto exit; - } - result = cpci_hotplug_init(debug); - if (result) { - err ("cpci_hotplug_init with error %d\n", result); - goto err_subsys; - } - - info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); - goto exit; - -err_subsys: - subsystem_unregister(&hotplug_slots_subsys); -exit: - return result; -} - -static void __exit pci_hotplug_exit (void) -{ - cpci_hotplug_exit(); - subsystem_unregister(&hotplug_slots_subsys); -} - -module_init(pci_hotplug_init); -module_exit(pci_hotplug_exit); - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -MODULE_PARM(debug, "i"); -MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); - -EXPORT_SYMBOL_GPL(pci_hp_register); -EXPORT_SYMBOL_GPL(pci_hp_deregister); -EXPORT_SYMBOL_GPL(pci_hp_change_slot_info); diff -Nru a/drivers/hotplug/pcihp_skeleton.c b/drivers/hotplug/pcihp_skeleton.c --- a/drivers/hotplug/pcihp_skeleton.c Mon Jun 9 23:16:13 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,432 +0,0 @@ -/* - * PCI Hot Plug Controller Skeleton Driver - 0.1 - * - * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) - * Copyright (c) 2001 IBM Corp. - * - * All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or - * NON INFRINGEMENT. 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. - * - * This driver is to be used as a skeleton driver to be show how to interface - * with the pci hotplug core easily. - * - * Send feedback to <greg@kroah.com> - * - */ - -#include <linux/config.h> -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/pci.h> -#include <linux/init.h> -#include "pci_hotplug.h" - - -#define SLOT_MAGIC 0x67267322 -struct slot { - u32 magic; - u8 number; - struct hotplug_slot *hotplug_slot; - struct list_head slot_list; -}; - -static LIST_HEAD(slot_list); - -#if !defined(CONFIG_HOTPLUG_PCI_SKELETON_MODULE) - #define MY_NAME "pcihp_skeleton" -#else - #define MY_NAME THIS_MODULE->name -#endif - -#define dbg(format, arg...) \ - do { \ - if (debug) \ - printk (KERN_DEBUG "%s: " format "\n", \ - MY_NAME , ## arg); \ - } while (0) -#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) -#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) -#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) - - - -/* local variables */ -static int debug; -static int num_slots; - -#define DRIVER_VERSION "0.1" -#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>" -#define DRIVER_DESC "Hot Plug PCI Controller Skeleton Driver" - -MODULE_AUTHOR(DRIVER_AUTHOR); -MODULE_DESCRIPTION(DRIVER_DESC); -MODULE_LICENSE("GPL"); -MODULE_PARM(debug, "i"); -MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); - -static int enable_slot (struct hotplug_slot *slot); -static int disable_slot (struct hotplug_slot *slot); -static int set_attention_status (struct hotplug_slot *slot, u8 value); -static int hardware_test (struct hotplug_slot *slot, u32 value); -static int get_power_status (struct hotplug_slot *slot, u8 *value); -static int get_attention_status (struct hotplug_slot *slot, u8 *value); -static int get_latch_status (struct hotplug_slot *slot, u8 *value); -static int get_adapter_status (struct hotplug_slot *slot, u8 *value); - -static struct hotplug_slot_ops skel_hotplug_slot_ops = { - .owner = THIS_MODULE, - .enable_slot = enable_slot, - .disable_slot = disable_slot, - .set_attention_status = set_attention_status, - .hardware_test = hardware_test, - .get_power_status = get_power_status, - .get_attention_status = get_attention_status, - .get_latch_status = get_latch_status, - .get_adapter_status = get_adapter_status, -}; - - -/* Inline functions to check the sanity of a pointer that is passed to us */ -static inline int slot_paranoia_check (struct slot *slot, const char *function) -{ - if (!slot) { - dbg("%s - slot == NULL", function); - return -1; - } - if (slot->magic != SLOT_MAGIC) { - dbg("%s - bad magic number for slot", function); - return -1; - } - if (!slot->hotplug_slot) { - dbg("%s - slot->hotplug_slot == NULL!", function); - return -1; - } - return 0; -} - -static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function) -{ - struct slot *slot; - - if (!hotplug_slot) { - dbg("%s - hotplug_slot == NULL\n", function); - return NULL; - } - - slot = (struct slot *)hotplug_slot->private; - if (slot_paranoia_check (slot, function)) - return NULL; - return slot; -} - - -static int enable_slot (struct hotplug_slot *hotplug_slot) -{ - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; - - dbg ("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - /* - * Fill in code here to enable the specified slot - */ - - return retval; -} - - -static int disable_slot (struct hotplug_slot *hotplug_slot) -{ - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; - - dbg ("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - /* - * Fill in code here to disable the specified slot - */ - - return retval; -} - -static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status) -{ - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; - - dbg ("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - switch (status) { - case 0: - /* - * Fill in code here to turn light off - */ - break; - - case 1: - default: - /* - * Fill in code here to turn light on - */ - break; - } - - return retval; -} - -static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value) -{ - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; - - dbg ("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); - - err ("No hardware tests are defined for this driver"); - retval = -ENODEV; - - /* Or you can specify a test if you want to */ - - return retval; -} - -static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value) -{ - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; - - dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name); - - /* - * Fill in logic to get the current power status of the specific - * slot and store it in the *value location. - */ - - return retval; -} - -static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value) -{ - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; - - dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name); - - /* - * Fill in logic to get the current attention status of the specific - * slot and store it in the *value location. - */ - - return retval; -} - -static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value) -{ - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; - - dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name); - - /* - * Fill in logic to get the current latch status of the specific - * slot and store it in the *value location. - */ - - return retval; -} - -static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value) -{ - struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); - int retval = 0; - - if (slot == NULL) - return -ENODEV; - - dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name); - - /* - * Fill in logic to get the current adapter status of the specific - * slot and store it in the *value location. - */ - - return retval; -} - -#define SLOT_NAME_SIZE 10 -static void make_slot_name (struct slot *slot) -{ - /* - * Stupid way to make a filename out of the slot name. - * replace this if your hardware provides a better way to name slots. - */ - snprintf (slot->hotplug_slot->name, SLOT_NAME_SIZE, "%d", slot->number); -} - -static int init_slots (void) -{ - struct slot *slot; - struct hotplug_slot *hotplug_slot; - struct hotplug_slot_info *info; - char *name; - int retval = 0; - int i; - - /* - * Create a structure for each slot, and register that slot - * with the pci_hotplug subsystem. - */ - for (i = 0; i < num_slots; ++i) { - slot = kmalloc (sizeof (struct slot), GFP_KERNEL); - if (!slot) - return -ENOMEM; - memset(slot, 0, sizeof(struct slot)); - - hotplug_slot = kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL); - if (!hotplug_slot) { - kfree (slot); - return -ENOMEM; - } - memset(hotplug_slot, 0, sizeof (struct hotplug_slot)); - slot->hotplug_slot = hotplug_slot; - - info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); - if (!info) { - kfree (hotplug_slot); - kfree (slot); - return -ENOMEM; - } - memset(info, 0, sizeof (struct hotplug_slot_info)); - hotplug_slot->info = info; - - name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL); - if (!name) { - kfree (info); - kfree (hotplug_slot); - kfree (slot); - return -ENOMEM; - } - hotplug_slot->name = name; - - slot->magic = SLOT_MAGIC; - slot->number = i; - - hotplug_slot->private = slot; - make_slot_name (slot); - hotplug_slot->ops = &skel_hotplug_slot_ops; - - /* - * Initilize the slot info structure with some known - * good values. - */ - info->power_status = get_skel_power_status(slot); - info->attention_status = get_skel_attention_status(slot); - info->latch_status = get_skel_latch_status(slot); - info->adapter_status = get_skel_adapter_status(slot); - - dbg ("registering slot %d\n", i); - retval = pci_hp_register (slot->hotplug_slot); - if (retval) { - err ("pci_hp_register failed with error %d\n", retval); - kfree (info); - kfree (name); - kfree (hotplug_slot); - kfree (slot); - return retval; - } - - /* add slot to our internal list */ - list_add (&slot->slot_list, &slot_list); - } - - return retval; -} - -static void cleanup_slots (void) -{ - struct list_head *tmp; - struct slot *slot; - - /* - * Unregister all of our slots with the pci_hotplug subsystem, - * and free up all memory that we had allocated. - */ - list_for_each (tmp, &slot_list) { - slot = list_entry (tmp, struct slot, slot_list); - list_del (&slot->slot_list); - pci_hp_deregister (slot->hotplug_slot); - kfree (slot->hotplug_slot->info); - kfree (slot->hotplug_slot->name); - kfree (slot->hotplug_slot); - kfree (slot); - } - - return; -} - -static int __init pcihp_skel_init(void) -{ - int retval; - - /* - * Do specific initialization stuff for your driver here - * Like initilizing your controller hardware (if any) and - * determining the number of slots you have in the system - * right now. - */ - num_slots = 5; - - retval = init_slots(); - if (retval) - return retval; - - info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); - return 0; -} - -static void __exit pcihp_skel_exit(void) -{ - /* - * Clean everything up. - */ - cleanup_slots(); -} - -module_init(pcihp_skel_init); -module_exit(pcihp_skel_exit); - diff -Nru a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig --- a/drivers/i2c/Kconfig Mon Jun 9 23:16:08 2003 +++ b/drivers/i2c/Kconfig Mon Jun 9 23:16:08 2003 @@ -144,7 +144,7 @@ config I2C_KEYWEST tristate "Powermac Keywest I2C interface" - depends on I2C && ALL_PPC + depends on I2C && PPC_PMAC help This supports the use of the I2C interface in the combo-I/O chip on recent Apple machines. Say Y if you have such a machine. diff -Nru a/drivers/i2c/chips/w83781d.c b/drivers/i2c/chips/w83781d.c --- a/drivers/i2c/chips/w83781d.c Mon Jun 9 23:16:05 2003 +++ b/drivers/i2c/chips/w83781d.c Mon Jun 9 23:16:05 2003 @@ -1031,27 +1031,129 @@ return i2c_detect(adapter, &addr_data, w83781d_detect); } +/* Assumes that adapter is of I2C, not ISA variety. + * OTHERWISE DON'T CALL THIS + */ +static int +w83781d_detect_subclients(struct i2c_adapter *adapter, int address, int kind, + struct i2c_client *new_client) +{ + int i, val1 = 0, id; + int err; + const char *client_name; + struct w83781d_data *data = i2c_get_clientdata(new_client); + + if (!(data->lm75 = kmalloc(2 * sizeof (struct i2c_client), + GFP_KERNEL))) { + err = -ENOMEM; + goto ERROR_SC_0; + } + memset(data->lm75, 0x00, 2 * sizeof (struct i2c_client)); + + id = i2c_adapter_id(adapter); + + if (force_subclients[0] == id && force_subclients[1] == address) { + for (i = 2; i <= 3; i++) { + if (force_subclients[i] < 0x48 || + force_subclients[i] > 0x4f) { + dev_err(&new_client->dev, "Invalid subclient " + "address %d; must be 0x48-0x4f\n", + force_subclients[i]); + err = -EINVAL; + goto ERROR_SC_1; + } + } + w83781d_write_value(new_client, W83781D_REG_I2C_SUBADDR, + (force_subclients[2] & 0x07) | + ((force_subclients[3] & 0x07) << 4)); + data->lm75[0].addr = force_subclients[2]; + } else { + val1 = w83781d_read_value(new_client, W83781D_REG_I2C_SUBADDR); + data->lm75[0].addr = 0x48 + (val1 & 0x07); + } + + if (kind != w83783s) { + if (force_subclients[0] == id && + force_subclients[1] == address) { + data->lm75[1].addr = force_subclients[3]; + } else { + data->lm75[1].addr = 0x48 + ((val1 >> 4) & 0x07); + } + if (data->lm75[0].addr == data->lm75[1].addr) { + dev_err(&new_client->dev, + "Duplicate addresses 0x%x for subclients.\n", + data->lm75[0].addr); + err = -EBUSY; + goto ERROR_SC_1; + } + } + + if (kind == w83781d) + client_name = "W83781D subclient"; + else if (kind == w83782d) + client_name = "W83782D subclient"; + else if (kind == w83783s) + client_name = "W83783S subclient"; + else if (kind == w83627hf) + client_name = "W83627HF subclient"; + else if (kind == as99127f) + client_name = "AS99127F subclient"; + else + client_name = "unknown subclient?"; + + for (i = 0; i <= 1; i++) { + /* store all data in w83781d */ + i2c_set_clientdata(&data->lm75[i], NULL); + data->lm75[i].adapter = adapter; + data->lm75[i].driver = &w83781d_driver; + data->lm75[i].flags = 0; + strlcpy(data->lm75[i].dev.name, client_name, + DEVICE_NAME_SIZE); + if ((err = i2c_attach_client(&(data->lm75[i])))) { + dev_err(&new_client->dev, "Subclient %d " + "registration at address 0x%x " + "failed.\n", i, data->lm75[i].addr); + if (i == 1) + goto ERROR_SC_2; + goto ERROR_SC_1; + } + if (kind == w83783s) + break; + } + + return 0; + +/* Undo inits in case of errors */ +ERROR_SC_2: + i2c_detach_client(&(data->lm75[0])); +ERROR_SC_1: + kfree(data->lm75); +ERROR_SC_0: + return err; +} + static int w83781d_detect(struct i2c_adapter *adapter, int address, int kind) { - int i = 0, val1 = 0, val2, id; + int i = 0, val1 = 0, val2; struct i2c_client *new_client; struct w83781d_data *data; - int err = 0; - const char *type_name = ""; + int err; const char *client_name = ""; int is_isa = i2c_is_isa_adapter(adapter); enum vendor { winbond, asus } vendid; if (!is_isa - && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) + && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { + err = -EINVAL; goto ERROR0; + } - if (is_isa) { - if (!request_region(address, W83781D_EXTENT, "w83781d")) + if (is_isa) + if (!request_region(address, W83781D_EXTENT, "w83781d")) { + err = -EBUSY; goto ERROR0; - release_region(address, W83781D_EXTENT); - } + } /* Probe whether there is anything available on this address. Already done for SMBus clients */ @@ -1059,15 +1161,21 @@ if (is_isa) { #define REALLY_SLOW_IO - /* We need the timeouts for at least some LM78-like chips. But only - if we read 'undefined' registers. */ + /* We need the timeouts for at least some LM78-like + chips. But only if we read 'undefined' registers. */ i = inb_p(address + 1); - if (inb_p(address + 2) != i) - goto ERROR0; - if (inb_p(address + 3) != i) - goto ERROR0; - if (inb_p(address + 7) != i) - goto ERROR0; + if (inb_p(address + 2) != i) { + err = -ENODEV; + goto ERROR1; + } + if (inb_p(address + 3) != i) { + err = -ENODEV; + goto ERROR1; + } + if (inb_p(address + 7) != i) { + err = -ENODEV; + goto ERROR1; + } #undef REALLY_SLOW_IO /* Let's just hope nothing breaks here */ @@ -1075,7 +1183,8 @@ outb_p(~i & 0x7f, address + 5); if ((inb_p(address + 5) & 0x7f) != (~i & 0x7f)) { outb_p(i, address + 5); - return 0; + err = -ENODEV; + goto ERROR1; } } } @@ -1087,7 +1196,7 @@ if (!(new_client = kmalloc(sizeof (struct i2c_client) + sizeof (struct w83781d_data), GFP_KERNEL))) { err = -ENOMEM; - goto ERROR0; + goto ERROR1; } memset(new_client, 0x00, sizeof (struct i2c_client) + @@ -1108,8 +1217,10 @@ force_*=... parameter, and the Winbond will be reset to the right bank. */ if (kind < 0) { - if (w83781d_read_value(new_client, W83781D_REG_CONFIG) & 0x80) - goto ERROR1; + if (w83781d_read_value(new_client, W83781D_REG_CONFIG) & 0x80){ + err = -ENODEV; + goto ERROR2; + } val1 = w83781d_read_value(new_client, W83781D_REG_BANK); val2 = w83781d_read_value(new_client, W83781D_REG_CHIPMAN); /* Check for Winbond or Asus ID if in bank 0 */ @@ -1117,14 +1228,19 @@ (((!(val1 & 0x80)) && (val2 != 0xa3) && (val2 != 0xc3) && (val2 != 0x94)) || ((val1 & 0x80) && (val2 != 0x5c) && (val2 != 0x12) - && (val2 != 0x06)))) - goto ERROR1; - /* If Winbond SMBus, check address at 0x48. Asus doesn't support */ + && (val2 != 0x06)))) { + err = -ENODEV; + goto ERROR2; + } + /* If Winbond SMBus, check address at 0x48. + Asus doesn't support */ if ((!is_isa) && (((!(val1 & 0x80)) && (val2 == 0xa3)) || ((val1 & 0x80) && (val2 == 0x5c)))) { if (w83781d_read_value - (new_client, W83781D_REG_I2C_ADDR) != address) - goto ERROR1; + (new_client, W83781D_REG_I2C_ADDR) != address) { + err = -ENODEV; + goto ERROR2; + } } } @@ -1143,8 +1259,11 @@ vendid = winbond; else if ((val2 == 0x12) || (val2 == 0x06)) vendid = asus; - else - goto ERROR1; + else { + err = -ENODEV; + goto ERROR2; + } + /* mask off lower bit, not reliable */ val1 = w83781d_read_value(new_client, W83781D_REG_WCHIPID) & 0xfe; @@ -1166,38 +1285,31 @@ "Ignoring 'force' parameter for unknown chip at" "adapter %d, address 0x%02x\n", i2c_adapter_id(adapter), address); - goto ERROR1; + err = -EINVAL; + goto ERROR2; } } if (kind == w83781d) { - type_name = "w83781d"; client_name = "W83781D chip"; } else if (kind == w83782d) { - type_name = "w83782d"; client_name = "W83782D chip"; } else if (kind == w83783s) { - type_name = "w83783s"; client_name = "W83783S chip"; } else if (kind == w83627hf) { - type_name = "w83627hf"; client_name = "W83627HF chip"; } else if (kind == as99127f) { - type_name = "as99127f"; client_name = "AS99127F chip"; } else if (kind == w83697hf) { - type_name = "w83697hf"; client_name = "W83697HF chip"; } else { - dev_err(&new_client->dev, "Internal error: unknown kind (%d)?!?", kind); - goto ERROR1; + dev_err(&new_client->dev, "Internal error: unknown " + "kind (%d)?!?", kind); + err = -ENODEV; + goto ERROR2; } - /* Reserve the ISA region */ - if (is_isa) - request_region(address, W83781D_EXTENT, type_name); - - /* Fill in the remaining client fields and put it into the global list */ + /* Fill in the remaining client fields and put into the global list */ strlcpy(new_client->dev.name, client_name, DEVICE_NAME_SIZE); data->type = kind; @@ -1206,76 +1318,13 @@ /* Tell the I2C layer a new client has arrived */ if ((err = i2c_attach_client(new_client))) - goto ERROR3; + goto ERROR2; /* attach secondary i2c lm75-like clients */ if (!is_isa) { - if (!(data->lm75 = kmalloc(2 * sizeof (struct i2c_client), - GFP_KERNEL))) { - err = -ENOMEM; - goto ERROR4; - } - - memset(data->lm75, 0x00, 2 * sizeof (struct i2c_client)); - - id = i2c_adapter_id(adapter); - if (force_subclients[0] == id && force_subclients[1] == address) { - for (i = 2; i <= 3; i++) { - if (force_subclients[i] < 0x48 || - force_subclients[i] > 0x4f) { - dev_err(&new_client->dev, - "Invalid subclient address %d; must be 0x48-0x4f\n", - force_subclients[i]); - goto ERROR5; - } - } - w83781d_write_value(new_client, - W83781D_REG_I2C_SUBADDR, - (force_subclients[2] & 0x07) | - ((force_subclients[3] & 0x07) << - 4)); - data->lm75[0].addr = force_subclients[2]; - } else { - val1 = w83781d_read_value(new_client, - W83781D_REG_I2C_SUBADDR); - data->lm75[0].addr = 0x48 + (val1 & 0x07); - } - if (kind != w83783s) { - if (force_subclients[0] == id && - force_subclients[1] == address) { - data->lm75[1].addr = force_subclients[3]; - } else { - data->lm75[1].addr = - 0x48 + ((val1 >> 4) & 0x07); - } - if (data->lm75[0].addr == data->lm75[1].addr) { - dev_err(&new_client->dev, - "Duplicate addresses 0x%x for subclients.\n", - data->lm75[0].addr); - goto ERROR5; - } - } - if (kind == w83781d) - client_name = "W83781D subclient"; - else if (kind == w83782d) - client_name = "W83782D subclient"; - else if (kind == w83783s) - client_name = "W83783S subclient"; - else if (kind == w83627hf) - client_name = "W83627HF subclient"; - else if (kind == as99127f) - client_name = "AS99127F subclient"; - - for (i = 0; i <= 1; i++) { - i2c_set_clientdata(&data->lm75[i], NULL); /* store all data in w83781d */ - data->lm75[i].adapter = adapter; - data->lm75[i].driver = &w83781d_driver; - data->lm75[i].flags = 0; - strlcpy(data->lm75[i].dev.name, client_name, - DEVICE_NAME_SIZE); - if (kind == w83783s) - break; - } + if ((err = w83781d_detect_subclients(adapter, address, + kind, new_client))) + goto ERROR3; } else { data->lm75 = NULL; } @@ -1346,24 +1395,14 @@ w83781d_init_client(new_client); return 0; -/* OK, this is not exactly good programming practice, usually. But it is - very code-efficient in this case. */ - - ERROR5: - if (!is_isa) { - i2c_detach_client(&data->lm75[0]); - if (data->type != w83783s) - i2c_detach_client(&data->lm75[1]); - kfree(data->lm75); - } - ERROR4: +ERROR3: i2c_detach_client(new_client); - ERROR3: +ERROR2: + kfree(new_client); +ERROR1: if (is_isa) release_region(address, W83781D_EXTENT); - ERROR1: - kfree(new_client); - ERROR0: +ERROR0: return err; } @@ -1373,12 +1412,7 @@ struct w83781d_data *data = i2c_get_clientdata(client); int err; - if ((err = i2c_detach_client(client))) { - dev_err(&client->dev, - "Client deregistration failed, client not detached.\n"); - return err; - } - + /* release ISA region or I2C subclients first */ if (i2c_is_isa_client(client)) { release_region(client->addr, W83781D_EXTENT); } else { @@ -1387,6 +1421,14 @@ i2c_detach_client(&data->lm75[1]); kfree(data->lm75); } + + /* now it's safe to scrap the rest */ + if ((err = i2c_detach_client(client))) { + dev_err(&client->dev, + "Client deregistration failed, client not detached.\n"); + return err; + } + kfree(client); return 0; diff -Nru a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c --- a/drivers/i2c/i2c-core.c Mon Jun 9 23:16:07 2003 +++ b/drivers/i2c/i2c-core.c Mon Jun 9 23:16:07 2003 @@ -124,7 +124,7 @@ int i2c_del_adapter(struct i2c_adapter *adap) { - struct list_head *item; + struct list_head *item, *_n; struct i2c_driver *driver; struct i2c_client *client; int res = 0; @@ -144,7 +144,7 @@ /* detach any active clients. This must be done first, because * it can fail; in which case we give upp. */ - list_for_each(item,&adap->clients) { + list_for_each_safe(item, _n, &adap->clients) { client = list_entry(item, struct i2c_client, list); /* detaching devices is unconditional of the set notify @@ -215,8 +215,7 @@ int i2c_del_driver(struct i2c_driver *driver) { - struct list_head *item1; - struct list_head *item2; + struct list_head *item1, *item2, *_n; struct i2c_client *client; struct i2c_adapter *adap; @@ -245,7 +244,7 @@ goto out_unlock; } } else { - list_for_each(item2,&adap->clients) { + list_for_each_safe(item2, _n, &adap->clients) { client = list_entry(item2, struct i2c_client, list); if (client->driver != driver) continue; diff -Nru a/drivers/ide/Kconfig b/drivers/ide/Kconfig --- a/drivers/ide/Kconfig Mon Jun 9 23:16:11 2003 +++ b/drivers/ide/Kconfig Mon Jun 9 23:16:11 2003 @@ -219,7 +219,6 @@ If you are unsure, say N here. -#bool ' IDE Taskfile IO' CONFIG_IDE_TASKFILE_IO comment "IDE chipset support/bugfixes" depends on BLK_DEV_IDE @@ -268,7 +267,7 @@ config BLK_DEV_IDEPCI bool "PCI IDE chipset support" if PCI depends on BLK_DEV_IDE - default BLK_DEV_IDEDMA_PMAC if ALL_PPC && BLK_DEV_IDEDMA_PMAC + default BLK_DEV_IDEDMA_PMAC if PPC_PMAC && BLK_DEV_IDEDMA_PMAC help Say Y here for PCI systems which use IDE drive(s). This option helps the IDE driver to automatically detect and @@ -409,7 +408,7 @@ bool depends on BLK_DEV_IDE default BLK_DEV_IDEDMA_ICS if ARCH_ACORN - default BLK_DEV_IDEDMA_PMAC if ALL_PPC && BLK_DEV_IDE_PMAC + default BLK_DEV_IDEDMA_PMAC if PPC_PMAC && BLK_DEV_IDE_PMAC default BLK_DEV_IDEDMA_PCI if PCI && BLK_DEV_IDEPCI config IDEDMA_PCI_WIP @@ -734,7 +733,7 @@ config BLK_DEV_IDE_PMAC bool "Builtin PowerMac IDE support" - depends on BLK_DEV_IDE && ALL_PPC + depends on BLK_DEV_IDE && PPC_PMAC help This driver provides support for the built-in IDE controller on most of the recent Apple Power Macintoshes and PowerBooks. @@ -1071,11 +1070,6 @@ If unsure, say N. -##if [ "$CONFIG_IDE_TASKFILE_IO" = "y" ]; then -## dep_mbool CONFIG_BLK_DEV_TF_DISK $CONFIG_BLK_DEV_IDEDISK -##else -## dep_mbool CONFIG_BLK_DEV_NTF_DISK $CONFIG_BLK_DEV_IDEDISK -##fi config BLK_DEV_IDE_MODES bool depends on BLK_DEV_4DRIVES || BLK_DEV_ALI14XX || BLK_DEV_DTC2278 || BLK_DEV_HT6560B || BLK_DEV_PDC4030 || BLK_DEV_QD65XX || BLK_DEV_UMC8672 || BLK_DEV_AEC62XX=y || BLK_DEV_ALI15X3=y || BLK_DEV_AMD74XX=y || BLK_DEV_CMD640 || BLK_DEV_CMD64X=y || BLK_DEV_CS5530=y || BLK_DEV_CY82C693=y || BLK_DEV_HPT34X=y || BLK_DEV_HPT366=y || BLK_DEV_IDE_PMAC || BLK_DEV_IT8172 || BLK_DEV_MPC8xx_IDE || BLK_DEV_NFORCE=y || BLK_DEV_OPTI621=y || BLK_DEV_PDC202XX || BLK_DEV_PIIX=y || BLK_DEV_SVWKS=y || BLK_DEV_SIIMAGE=y || BLK_DEV_SIS5513=y || BLK_DEV_SL82C105=y || BLK_DEV_SLC90E66=y || BLK_DEV_VIA82CXXX=y diff -Nru a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c --- a/drivers/ide/ide-cd.c Mon Jun 9 23:16:11 2003 +++ b/drivers/ide/ide-cd.c Mon Jun 9 23:16:11 2003 @@ -666,8 +666,10 @@ struct cdrom_info *info = drive->driver_data; void *sense = &info->sense_data; - if (failed && failed->sense) + if (failed && failed->sense) { sense = failed->sense; + failed->sense_len = rq->sense_len; + } cdrom_analyze_sense_data(drive, failed, sense); } @@ -723,7 +725,7 @@ * scsi status byte */ if ((rq->flags & REQ_BLOCK_PC) && !rq->errors) - rq->errors = CHECK_CONDITION; + rq->errors = SAM_STAT_CHECK_CONDITION; /* Check for tray open. */ if (sense_key == NOT_READY) { @@ -1471,8 +1473,9 @@ /* Keep count of how much data we've moved. */ rq->data += thislen; rq->data_len -= thislen; - if (rq->cmd[0] == GPCMD_REQUEST_SENSE) - rq->sense_len++; + + if (rq->flags & REQ_SENSE) + rq->sense_len += thislen; } else { confused: printk ("%s: cdrom_pc_intr: The drive " @@ -1609,12 +1612,20 @@ static void post_transform_command(struct request *req) { - char *ibuf = req->buffer; u8 *c = req->cmd; + char *ibuf; if (!blk_pc_request(req)) return; + if (req->bio) + ibuf = bio_data(req->bio); + else + ibuf = req->data; + + if (!ibuf) + return; + /* * set ansi-revision and response data as atapi */ @@ -2993,12 +3004,6 @@ long block = (long)rq->hard_sector / (hard_sect >> 9); unsigned long blocks = rq->hard_nr_sectors / (hard_sect >> 9); - BUG_ON(sizeof(rq->hard_sector) > 4 && (rq->hard_sector >> 32)); - - if (rq->hard_nr_sectors != rq->nr_sectors) { - printk(KERN_ERR "ide-cd: hard_nr_sectors differs from nr_sectors! %lu %lu\n", - rq->nr_sectors, rq->hard_nr_sectors); - } memset(rq->cmd, 0, sizeof(rq->cmd)); if (rq_data_dir(rq) == READ) @@ -3371,7 +3376,6 @@ drive->driver_data = info; DRIVER(drive)->busy++; g->minors = 1; - g->minor_shift = 0; snprintf(g->devfs_name, sizeof(g->devfs_name), "%s/cd", drive->devfs_name); g->driverfs_dev = &drive->gendev; diff -Nru a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c --- a/drivers/ide/ide-disk.c Mon Jun 9 23:16:10 2003 +++ b/drivers/ide/ide-disk.c Mon Jun 9 23:16:10 2003 @@ -136,423 +136,6 @@ return ret; } -#ifndef CONFIG_IDE_TASKFILE_IO - -static int driver_blocked; - -/* - * read_intr() is the handler for disk read/multread interrupts - */ -static ide_startstop_t read_intr (ide_drive_t *drive) -{ - ide_hwif_t *hwif = HWIF(drive); - u32 i = 0, nsect = 0, msect = drive->mult_count; - struct request *rq; - unsigned long flags; - u8 stat; - char *to; - - /* new way for dealing with premature shared PCI interrupts */ - if (!OK_STAT(stat=hwif->INB(IDE_STATUS_REG),DATA_READY,BAD_R_STAT)) { - if (stat & (ERR_STAT|DRQ_STAT)) { - return DRIVER(drive)->error(drive, "read_intr", stat); - } - /* no data yet, so wait for another interrupt */ - ide_set_handler(drive, &read_intr, WAIT_CMD, NULL); - return ide_started; - } - -read_next: - rq = HWGROUP(drive)->rq; - if (msect) { - if ((nsect = rq->current_nr_sectors) > msect) - nsect = msect; - msect -= nsect; - } else - nsect = 1; - to = ide_map_buffer(rq, &flags); - taskfile_input_data(drive, to, nsect * SECTOR_WORDS); -#ifdef DEBUG - printk("%s: read: sectors(%ld-%ld), buffer=0x%08lx, remaining=%ld\n", - drive->name, rq->sector, rq->sector+nsect-1, - (unsigned long) rq->buffer+(nsect<<9), rq->nr_sectors-nsect); -#endif - ide_unmap_buffer(rq, to, &flags); - rq->sector += nsect; - rq->errors = 0; - i = (rq->nr_sectors -= nsect); - if (((long)(rq->current_nr_sectors -= nsect)) <= 0) - ide_end_request(drive, 1, rq->hard_cur_sectors); - /* - * Another BH Page walker and DATA INTEGRITY Questioned on ERROR. - * If passed back up on multimode read, BAD DATA could be ACKED - * to FILE SYSTEMS above ... - */ - if (i > 0) { - if (msect) - goto read_next; - ide_set_handler(drive, &read_intr, WAIT_CMD, NULL); - return ide_started; - } - return ide_stopped; -} - -/* - * write_intr() is the handler for disk write interrupts - */ -static ide_startstop_t write_intr (ide_drive_t *drive) -{ - ide_hwgroup_t *hwgroup = HWGROUP(drive); - ide_hwif_t *hwif = HWIF(drive); - struct request *rq = hwgroup->rq; - u32 i = 0; - u8 stat; - - if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG), - DRIVE_READY, drive->bad_wstat)) { - printk("%s: write_intr error1: nr_sectors=%ld, stat=0x%02x\n", - drive->name, rq->nr_sectors, stat); - } else { -#ifdef DEBUG - printk("%s: write: sector %ld, buffer=0x%08lx, remaining=%ld\n", - drive->name, rq->sector, (unsigned long) rq->buffer, - rq->nr_sectors-1); -#endif - if ((rq->nr_sectors == 1) ^ ((stat & DRQ_STAT) != 0)) { - rq->sector++; - rq->errors = 0; - i = --rq->nr_sectors; - --rq->current_nr_sectors; - if (((long)rq->current_nr_sectors) <= 0) - ide_end_request(drive, 1, rq->hard_cur_sectors); - if (i > 0) { - unsigned long flags; - char *to = ide_map_buffer(rq, &flags); - taskfile_output_data(drive, to, SECTOR_WORDS); - ide_unmap_buffer(rq, to, &flags); - ide_set_handler(drive, &write_intr, WAIT_CMD, NULL); - return ide_started; - } - return ide_stopped; - } - /* the original code did this here (?) */ - return ide_stopped; - } - return DRIVER(drive)->error(drive, "write_intr", stat); -} - -/* - * ide_multwrite() transfers a block of up to mcount sectors of data - * to a drive as part of a disk multiple-sector write operation. - * - * Returns 0 on success. - * - * Note that we may be called from two contexts - __ide_do_rw_disk() context - * and IRQ context. The IRQ can happen any time after we've output the - * full "mcount" number of sectors, so we must make sure we update the - * state _before_ we output the final part of the data! - * - * The update and return to BH is a BLOCK Layer Fakey to get more data - * to satisfy the hardware atomic segment. If the hardware atomic segment - * is shorter or smaller than the BH segment then we should be OKAY. - * This is only valid if we can rewind the rq->current_nr_sectors counter. - */ -int ide_multwrite (ide_drive_t *drive, unsigned int mcount) -{ - ide_hwgroup_t *hwgroup = HWGROUP(drive); - struct request *rq = &hwgroup->wrq; - - do { - char *buffer; - int nsect = rq->current_nr_sectors; - unsigned long flags; - - if (nsect > mcount) - nsect = mcount; - mcount -= nsect; - buffer = ide_map_buffer(rq, &flags); - - rq->sector += nsect; - rq->nr_sectors -= nsect; - rq->current_nr_sectors -= nsect; - - /* Do we move to the next bh after this? */ - if (!rq->current_nr_sectors) { - struct bio *bio = rq->bio; - - /* - * only move to next bio, when we have processed - * all bvecs in this one. - */ - if (++bio->bi_idx >= bio->bi_vcnt) { - bio->bi_idx = 0; - bio = bio->bi_next; - } - - /* end early early we ran out of requests */ - if (!bio) { - mcount = 0; - } else { - rq->bio = bio; - rq->current_nr_sectors = bio_iovec(bio)->bv_len >> 9; - rq->hard_cur_sectors = rq->current_nr_sectors; - } - } - - /* - * Ok, we're all setup for the interrupt - * re-entering us on the last transfer. - */ - taskfile_output_data(drive, buffer, nsect<<7); - ide_unmap_buffer(rq, buffer, &flags); - } while (mcount); - - return 0; -} - -/* - * multwrite_intr() is the handler for disk multwrite interrupts - */ -static ide_startstop_t multwrite_intr (ide_drive_t *drive) -{ - ide_hwgroup_t *hwgroup = HWGROUP(drive); - ide_hwif_t *hwif = HWIF(drive); - struct request *rq = &hwgroup->wrq; - u8 stat; - - stat = hwif->INB(IDE_STATUS_REG); - if (OK_STAT(stat, DRIVE_READY, drive->bad_wstat)) { - if (stat & DRQ_STAT) { - /* - * The drive wants data. Remember rq is the copy - * of the request - */ - if (rq->nr_sectors) { - if (ide_multwrite(drive, drive->mult_count)) - return ide_stopped; - ide_set_handler(drive, &multwrite_intr, WAIT_CMD, NULL); - return ide_started; - } - } else { - /* - * If the copy has all the blocks completed then - * we can end the original request. - */ - if (!rq->nr_sectors) { /* all done? */ - rq = hwgroup->rq; - ide_end_request(drive, 1, rq->nr_sectors); - return ide_stopped; - } - } - /* the original code did this here (?) */ - return ide_stopped; - } - return DRIVER(drive)->error(drive, "multwrite_intr", stat); -} - -/* - * __ide_do_rw_disk() issues READ and WRITE commands to a disk, - * using LBA if supported, or CHS otherwise, to address sectors. - * It also takes care of issuing special DRIVE_CMDs. - */ -ide_startstop_t __ide_do_rw_disk (ide_drive_t *drive, struct request *rq, sector_t block) -{ - ide_hwif_t *hwif = HWIF(drive); - u8 lba48 = (drive->addressing == 1) ? 1 : 0; - task_ioreg_t command = WIN_NOP; - ata_nsector_t nsectors; - - nsectors.all = (u16) rq->nr_sectors; - - if (driver_blocked) - panic("Request while ide driver is blocked?"); - - if (drive->using_tcq && idedisk_start_tag(drive, rq)) { - if (!ata_pending_commands(drive)) - BUG(); - - return ide_started; - } - - if (IDE_CONTROL_REG) - hwif->OUTB(drive->ctl, IDE_CONTROL_REG); - - if (drive->select.b.lba) { - if (drive->addressing == 1) { - task_ioreg_t tasklets[10]; - - if (blk_rq_tagged(rq)) { - tasklets[0] = nsectors.b.low; - tasklets[1] = nsectors.b.high; - tasklets[2] = rq->tag << 3; - tasklets[3] = 0; - } else { - tasklets[0] = 0; - tasklets[1] = 0; - tasklets[2] = nsectors.b.low; - tasklets[3] = nsectors.b.high; - } - - tasklets[4] = (task_ioreg_t) block; - tasklets[5] = (task_ioreg_t) (block>>8); - tasklets[6] = (task_ioreg_t) (block>>16); - tasklets[7] = (task_ioreg_t) (block>>24); - if (sizeof(block) == 4) { - tasklets[8] = (task_ioreg_t) 0; - tasklets[9] = (task_ioreg_t) 0; - } else { - tasklets[8] = (task_ioreg_t)((u64)block >> 32); - tasklets[9] = (task_ioreg_t)((u64)block >> 40); - } -#ifdef DEBUG - printk("%s: %sing: LBAsect=%lu, sectors=%ld, " - "buffer=0x%08lx, LBAsect=0x%012lx\n", - drive->name, - rq_data_dir(rq)==READ?"read":"writ", - block, - rq->nr_sectors, - (unsigned long) rq->buffer, - block); - printk("%s: 0x%02x%02x 0x%02x%02x%02x%02x%02x%02x\n", - drive->name, tasklets[3], tasklets[2], - tasklets[9], tasklets[8], tasklets[7], - tasklets[6], tasklets[5], tasklets[4]); -#endif - hwif->OUTB(tasklets[1], IDE_FEATURE_REG); - hwif->OUTB(tasklets[3], IDE_NSECTOR_REG); - hwif->OUTB(tasklets[7], IDE_SECTOR_REG); - hwif->OUTB(tasklets[8], IDE_LCYL_REG); - hwif->OUTB(tasklets[9], IDE_HCYL_REG); - - hwif->OUTB(tasklets[0], IDE_FEATURE_REG); - hwif->OUTB(tasklets[2], IDE_NSECTOR_REG); - hwif->OUTB(tasklets[4], IDE_SECTOR_REG); - hwif->OUTB(tasklets[5], IDE_LCYL_REG); - hwif->OUTB(tasklets[6], IDE_HCYL_REG); - hwif->OUTB(0x00|drive->select.all,IDE_SELECT_REG); - } else { -#ifdef DEBUG - printk("%s: %sing: LBAsect=%llu, sectors=%ld, " - "buffer=0x%08lx\n", - drive->name, - rq_data_dir(rq)==READ?"read":"writ", - (unsigned long long)block, rq->nr_sectors, - (unsigned long) rq->buffer); -#endif - if (blk_rq_tagged(rq)) { - hwif->OUTB(nsectors.b.low, IDE_FEATURE_REG); - hwif->OUTB(rq->tag << 3, IDE_NSECTOR_REG); - } else { - hwif->OUTB(0x00, IDE_FEATURE_REG); - hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG); - } - - hwif->OUTB(block, IDE_SECTOR_REG); - hwif->OUTB(block>>=8, IDE_LCYL_REG); - hwif->OUTB(block>>=8, IDE_HCYL_REG); - hwif->OUTB(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG); - } - } else { - unsigned int sect,head,cyl,track; - track = (int)block / drive->sect; - sect = (int)block % drive->sect + 1; - hwif->OUTB(sect, IDE_SECTOR_REG); - head = track % drive->head; - cyl = track / drive->head; - - if (blk_rq_tagged(rq)) { - hwif->OUTB(nsectors.b.low, IDE_FEATURE_REG); - hwif->OUTB(rq->tag << 3, IDE_NSECTOR_REG); - } else { - hwif->OUTB(0x00, IDE_FEATURE_REG); - hwif->OUTB(nsectors.b.low, IDE_NSECTOR_REG); - } - - hwif->OUTB(cyl, IDE_LCYL_REG); - hwif->OUTB(cyl>>8, IDE_HCYL_REG); - hwif->OUTB(head|drive->select.all,IDE_SELECT_REG); -#ifdef DEBUG - printk("%s: %sing: CHS=%d/%d/%d, sectors=%ld, buffer=0x%08lx\n", - drive->name, rq_data_dir(rq)==READ?"read":"writ", cyl, - head, sect, rq->nr_sectors, (unsigned long) rq->buffer); -#endif - } - - if (rq_data_dir(rq) == READ) { - if (blk_rq_tagged(rq)) - return hwif->ide_dma_queued_read(drive); - - if (drive->using_dma && !hwif->ide_dma_read(drive)) - return ide_started; - - command = ((drive->mult_count) ? - ((lba48) ? WIN_MULTREAD_EXT : WIN_MULTREAD) : - ((lba48) ? WIN_READ_EXT : WIN_READ)); - ide_execute_command(drive, command, &read_intr, WAIT_CMD, NULL); - return ide_started; - } else if (rq_data_dir(rq) == WRITE) { - ide_startstop_t startstop; - - if (blk_rq_tagged(rq)) - return hwif->ide_dma_queued_write(drive); - - if (drive->using_dma && !(HWIF(drive)->ide_dma_write(drive))) - return ide_started; - - command = ((drive->mult_count) ? - ((lba48) ? WIN_MULTWRITE_EXT : WIN_MULTWRITE) : - ((lba48) ? WIN_WRITE_EXT : WIN_WRITE)); - hwif->OUTB(command, IDE_COMMAND_REG); - - if (ide_wait_stat(&startstop, drive, DATA_READY, - drive->bad_wstat, WAIT_DRQ)) { - printk(KERN_ERR "%s: no DRQ after issuing %s\n", - drive->name, - drive->mult_count ? "MULTWRITE" : "WRITE"); - return startstop; - } - if (!drive->unmask) - local_irq_disable(); - if (drive->mult_count) { - ide_hwgroup_t *hwgroup = HWGROUP(drive); - /* - * Ugh.. this part looks ugly because we MUST set up - * the interrupt handler before outputting the first block - * of data to be written. If we hit an error (corrupted buffer list) - * in ide_multwrite(), then we need to remove the handler/timer - * before returning. Fortunately, this NEVER happens (right?). - * - * Except when you get an error it seems... - * - * MAJOR DATA INTEGRITY BUG !!! only if we error - */ - hwgroup->wrq = *rq; /* scratchpad */ - ide_set_handler(drive, &multwrite_intr, WAIT_CMD, NULL); - if (ide_multwrite(drive, drive->mult_count)) { - unsigned long flags; - spin_lock_irqsave(&ide_lock, flags); - hwgroup->handler = NULL; - del_timer(&hwgroup->timer); - spin_unlock_irqrestore(&ide_lock, flags); - return ide_stopped; - } - } else { - unsigned long flags; - char *to = ide_map_buffer(rq, &flags); - ide_set_handler(drive, &write_intr, WAIT_CMD, NULL); - taskfile_output_data(drive, to, SECTOR_WORDS); - ide_unmap_buffer(rq, to, &flags); - } - return ide_started; - } - blk_dump_rq_flags(rq, "__ide_do_rw_disk - bad command"); - ide_end_request(drive, 0, 0); - return ide_stopped; -} -EXPORT_SYMBOL_GPL(__ide_do_rw_disk); - -#else /* CONFIG_IDE_TASKFILE_IO */ - static ide_startstop_t chs_rw_disk(ide_drive_t *, struct request *, unsigned long); static ide_startstop_t lba_28_rw_disk(ide_drive_t *, struct request *, unsigned long); static ide_startstop_t lba_48_rw_disk(ide_drive_t *, struct request *, unsigned long long); @@ -750,8 +333,6 @@ return do_rw_taskfile(drive, &args); } -#endif /* CONFIG_IDE_TASKFILE_IO */ - static ide_startstop_t ide_do_rw_disk (ide_drive_t *drive, struct request *rq, sector_t block) { ide_hwif_t *hwif = HWIF(drive); @@ -866,6 +447,9 @@ return ide_stopped; } #endif + /* make rq completion pointers new submission pointers */ + blk_rq_prep_restart(rq); + if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) { /* other bits are useless when BUSY */ rq->errors |= ERROR_RESET; @@ -1814,7 +1398,6 @@ } DRIVER(drive)->busy--; g->minors = 1 << PARTN_BITS; - g->minor_shift = PARTN_BITS; strcpy(g->devfs_name, drive->devfs_name); g->driverfs_dev = &drive->gendev; g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0; diff -Nru a/drivers/ide/ide-floppy.c b/drivers/ide/ide-floppy.c --- a/drivers/ide/ide-floppy.c Mon Jun 9 23:16:12 2003 +++ b/drivers/ide/ide-floppy.c Mon Jun 9 23:16:12 2003 @@ -2057,7 +2057,6 @@ idefloppy_setup (drive, floppy); DRIVER(drive)->busy--; g->minors = 1 << PARTN_BITS; - g->minor_shift = PARTN_BITS; g->driverfs_dev = &drive->gendev; strcpy(g->devfs_name, drive->devfs_name); g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0; diff -Nru a/drivers/ide/ide-proc.c b/drivers/ide/ide-proc.c --- a/drivers/ide/ide-proc.c Mon Jun 9 23:16:13 2003 +++ b/drivers/ide/ide-proc.c Mon Jun 9 23:16:13 2003 @@ -712,7 +712,6 @@ for (d = 0; d < MAX_DRIVES; d++) { ide_drive_t *drive = &hwif->drives[d]; - ide_driver_t *driver = drive->driver; if (!drive->present) continue; @@ -720,13 +719,8 @@ continue; drive->proc = proc_mkdir(drive->name, parent); - if (drive->proc) { + if (drive->proc) ide_add_proc_entries(drive->proc, generic_drive_entries, drive); - if (driver) { - ide_add_proc_entries(drive->proc, generic_subdriver_entries, drive); - ide_add_proc_entries(drive->proc, driver->proc, drive); - } - } sprintf(name,"ide%d/%s", (drive->name[2]-'a')/2, drive->name); ent = proc_symlink(drive->name, proc_ide_root, name); if (!ent) return; @@ -735,34 +729,6 @@ EXPORT_SYMBOL(create_proc_ide_drives); -void recreate_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive) -{ - struct proc_dir_entry *ent; - struct proc_dir_entry *parent = hwif->proc; - char name[64]; - - if (drive->present && !drive->proc) { - drive->proc = proc_mkdir(drive->name, parent); - if (drive->proc) - ide_add_proc_entries(drive->proc, generic_drive_entries, drive); - -/* - * assume that we have these already, however, should test FIXME! - * if (driver) { - * ide_add_proc_entries(drive->proc, generic_subdriver_entries, drive); - * ide_add_proc_entries(drive->proc, driver->proc, drive); - * } - * - */ - sprintf(name,"ide%d/%s", (drive->name[2]-'a')/2, drive->name); - ent = proc_symlink(drive->name, proc_ide_root, name); - if (!ent) - return; - } -} - -EXPORT_SYMBOL(recreate_proc_ide_device); - void destroy_proc_ide_device(ide_hwif_t *hwif, ide_drive_t *drive) { ide_driver_t *driver = drive->driver; @@ -909,16 +875,11 @@ void proc_ide_destroy(void) { #ifdef CONFIG_BLK_DEV_IDEPCI - ide_pci_host_proc_t *p = ide_pci_host_proc_list; - char name[32]; + ide_pci_host_proc_t *p; - while ((p->name != NULL) && (p->set) && (p->get_info != NULL)) { - name[0] = '\0'; - sprintf(name, "ide/%s", p->name); + for (p = ide_pci_host_proc_list; p; p = p->next) { if (p->set == 2) remove_proc_entry(p->name, p->parent); - if (p->next == NULL) break; - p = p->next; } #endif /* CONFIG_BLK_DEV_IDEPCI */ remove_proc_entry("ide/drivers", proc_ide_root); diff -Nru a/drivers/ide/ide-taskfile.c b/drivers/ide/ide-taskfile.c --- a/drivers/ide/ide-taskfile.c Mon Jun 9 23:16:05 2003 +++ b/drivers/ide/ide-taskfile.c Mon Jun 9 23:16:05 2003 @@ -5,6 +5,7 @@ * Copyright (C) 2000-2002 Andre Hedrick <andre@linux-ide.org> * Copyright (C) 2001-2002 Klaus Smolin * IBM Storage Technology Division + * Copyright (C) 2003 Bartlomiej Zolnierkiewicz * * The big the bad and the ugly. * @@ -58,9 +59,6 @@ #define DTF(x...) #endif -#define task_map_rq(rq, flags) ide_map_buffer((rq), (flags)) -#define task_unmap_rq(rq, buf, flags) ide_unmap_buffer((rq), (buf), (flags)) - static void ata_bswap_data (void *buffer, int wcount) { u16 *p = buffer; @@ -167,9 +165,12 @@ hwif->OUTB((taskfile->device_head & HIHI) | drive->select.all, IDE_SELECT_REG); if (task->handler != NULL) { - ide_execute_command(drive, taskfile->command, task->handler, WAIT_WORSTCASE, NULL); - if (task->prehandler != NULL) + if (task->prehandler != NULL) { + hwif->OUTBSYNC(drive, taskfile->command, IDE_COMMAND_REG); + ndelay(400); /* FIXME */ return task->prehandler(drive, task->rq); + } + ide_execute_command(drive, taskfile->command, task->handler, WAIT_WORSTCASE, NULL); return ide_started; } @@ -351,404 +352,271 @@ EXPORT_SYMBOL(task_no_data_intr); +static u8 wait_drive_not_busy(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + int retries = 5; + u8 stat; + /* + * (ks) Last sector was transfered, wait until drive is ready. + * This can take up to 10 usec. We willl wait max 50 us. + */ + while (((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) && retries--) + udelay(10); + return stat; +} + /* - * Handler for command with PIO data-in phase, READ - */ -/* - * FIXME before 2.4 enable ... - * DATA integrity issue upon error. <andre@linux-ide.org> + * Handler for command with PIO data-in phase (Read). */ ide_startstop_t task_in_intr (ide_drive_t *drive) { - struct request *rq = HWGROUP(drive)->rq; - ide_hwif_t *hwif = HWIF(drive); - char *pBuf = NULL; - u8 stat; - unsigned long flags; + struct request *rq = HWGROUP(drive)->rq; + u8 stat, good_stat; - if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),DATA_READY,BAD_R_STAT)) { - if (stat & (ERR_STAT|DRQ_STAT)) { -#if 0 - DTF("%s: attempting to recover last " \ - "sector counter status=0x%02x\n", - drive->name, stat); - /* - * Expect a BUG BOMB if we attempt to rewind the - * offset in the BH aka PAGE in the current BLOCK - * segment. This is different than the HOST segment. - */ -#endif - if (!rq->bio) - rq->current_nr_sectors++; - return DRIVER(drive)->error(drive, "task_in_intr", stat); - } - if (!(stat & BUSY_STAT)) { - DTF("task_in_intr to Soon wait for next interrupt\n"); - if (HWGROUP(drive)->handler == NULL) - ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL); - return ide_started; - } + good_stat = DATA_READY; + stat = HWIF(drive)->INB(IDE_STATUS_REG); +check_status: + if (!OK_STAT(stat, good_stat, BAD_R_STAT)) { + if (stat & (ERR_STAT | DRQ_STAT)) + return DRIVER(drive)->error(drive, __FUNCTION__, stat); + /* BUSY_STAT: No data yet, so wait for another IRQ. */ + ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL); + return ide_started; } -#if 0 /* - * Holding point for a brain dump of a thought :-/ + * Complete previously submitted bios (if any). + * Status was already verifyied. */ - - if (!OK_STAT(stat,DRIVE_READY,drive->bad_wstat)) { - DTF("%s: READ attempting to recover last " \ - "sector counter status=0x%02x\n", - drive->name, stat); - rq->current_nr_sectors++; - return DRIVER(drive)->error(drive, "task_in_intr", stat); - } - if (!rq->current_nr_sectors) - if (!DRIVER(drive)->end_request(drive, 1, 0)) + while (rq->bio != rq->cbio) + if (!DRIVER(drive)->end_request(drive, 1, bio_sectors(rq->bio))) return ide_stopped; + /* Complete rq->buffer based request (ioctls). */ + if (!rq->bio && !rq->nr_sectors) { + ide_end_drive_cmd(drive, stat, HWIF(drive)->INB(IDE_ERROR_REG)); + return ide_stopped; + } - if (--rq->current_nr_sectors <= 0) - if (!DRIVER(drive)->end_request(drive, 1, 0)) - return ide_stopped; -#endif + rq->errors = 0; + task_sectors(drive, rq, 1, IDE_PIO_IN); + + /* If it was the last datablock check status and finish transfer. */ + if (!rq->nr_sectors) { + good_stat = 0; + stat = wait_drive_not_busy(drive); + goto check_status; + } + + /* Still data left to transfer. */ + ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL); - pBuf = task_map_rq(rq, &flags); - DTF("Read: %p, rq->current_nr_sectors: %d, stat: %02x\n", - pBuf, (int) rq->current_nr_sectors, stat); - taskfile_input_data(drive, pBuf, SECTOR_WORDS); - task_unmap_rq(rq, pBuf, &flags); - /* - * FIXME :: We really can not legally get a new page/bh - * regardless, if this is the end of our segment. - * BH walking or segment can only be updated after we have a good - * hwif->INB(IDE_STATUS_REG); return. - */ - if (--rq->current_nr_sectors <= 0) - if (!DRIVER(drive)->end_request(drive, 1, 0)) - return ide_stopped; - /* - * ERM, it is techincally legal to leave/exit here but it makes - * a mess of the code ... - */ - if (HWGROUP(drive)->handler == NULL) - ide_set_handler(drive, &task_in_intr, WAIT_WORSTCASE, NULL); return ide_started; } - EXPORT_SYMBOL(task_in_intr); /* - * Handler for command with Read Multiple + * Handler for command with PIO data-in phase (Read Multiple). */ ide_startstop_t task_mulin_intr (ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct request *rq = HWGROUP(drive)->rq; - char *pBuf = NULL; - unsigned int msect = drive->mult_count; + struct request *rq = HWGROUP(drive)->rq; + unsigned int msect = drive->mult_count; unsigned int nsect; - unsigned long flags; - u8 stat; + u8 stat, good_stat; - if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG),DATA_READY,BAD_R_STAT)) { - if (stat & (ERR_STAT|DRQ_STAT)) { - if (!rq->bio) { - rq->current_nr_sectors += drive->mult_count; - /* - * NOTE: could rewind beyond beginning :-/ - */ - } else { - printk(KERN_ERR "%s: MULTI-READ assume all data " \ - "transfered is bad status=0x%02x\n", - drive->name, stat); - } - return DRIVER(drive)->error(drive, "task_mulin_intr", stat); - } - /* no data yet, so wait for another interrupt */ - if (HWGROUP(drive)->handler == NULL) - ide_set_handler(drive, &task_mulin_intr, WAIT_WORSTCASE, NULL); + good_stat = DATA_READY; + stat = HWIF(drive)->INB(IDE_STATUS_REG); +check_status: + if (!OK_STAT(stat, good_stat, BAD_R_STAT)) { + if (stat & (ERR_STAT | DRQ_STAT)) + return DRIVER(drive)->error(drive, __FUNCTION__, stat); + /* BUSY_STAT: No data yet, so wait for another IRQ. */ + ide_set_handler(drive, &task_mulin_intr, WAIT_WORSTCASE, NULL); return ide_started; } + /* + * Complete previously submitted bios (if any). + * Status was already verifyied. + */ + while (rq->bio != rq->cbio) + if (!DRIVER(drive)->end_request(drive, 1, bio_sectors(rq->bio))) + return ide_stopped; + /* Complete rq->buffer based request (ioctls). */ + if (!rq->bio && !rq->nr_sectors) { + ide_end_drive_cmd(drive, stat, HWIF(drive)->INB(IDE_ERROR_REG)); + return ide_stopped; + } + + rq->errors = 0; do { nsect = rq->current_nr_sectors; if (nsect > msect) nsect = msect; - pBuf = task_map_rq(rq, &flags); - DTF("Multiread: %p, nsect: %d, msect: %d, " \ - " rq->current_nr_sectors: %d\n", - pBuf, nsect, msect, rq->current_nr_sectors); - taskfile_input_data(drive, pBuf, nsect * SECTOR_WORDS); - task_unmap_rq(rq, pBuf, &flags); - rq->errors = 0; - rq->current_nr_sectors -= nsect; - msect -= nsect; - /* - * FIXME :: We really can not legally get a new page/bh - * regardless, if this is the end of our segment. - * BH walking or segment can only be updated after we have a - * good hwif->INB(IDE_STATUS_REG); return. - */ - if (!rq->current_nr_sectors) { - if (!DRIVER(drive)->end_request(drive, 1, 0)) - return ide_stopped; - } - } while (msect); - if (HWGROUP(drive)->handler == NULL) - ide_set_handler(drive, &task_mulin_intr, WAIT_WORSTCASE, NULL); - return ide_started; -} -EXPORT_SYMBOL(task_mulin_intr); + task_sectors(drive, rq, nsect, IDE_PIO_IN); -/* - * VERIFY ME before 2.4 ... unexpected race is possible based on details - * RMK with 74LS245/373/374 TTL buffer logic because of passthrough. - */ -ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq) -{ - char *pBuf = NULL; - unsigned long flags; - ide_startstop_t startstop; + if (!rq->nr_sectors) + msect = 0; + else + msect -= nsect; + } while (msect); - if (ide_wait_stat(&startstop, drive, DATA_READY, - drive->bad_wstat, WAIT_DRQ)) { - printk(KERN_ERR "%s: no DRQ after issuing WRITE%s\n", - drive->name, - drive->addressing ? "_EXT" : ""); - return startstop; + /* If it was the last datablock check status and finish transfer. */ + if (!rq->nr_sectors) { + good_stat = 0; + stat = wait_drive_not_busy(drive); + goto check_status; } - /* For Write_sectors we need to stuff the first sector */ - pBuf = task_map_rq(rq, &flags); - taskfile_output_data(drive, pBuf, SECTOR_WORDS); - rq->current_nr_sectors--; - task_unmap_rq(rq, pBuf, &flags); + + /* Still data left to transfer. */ + ide_set_handler(drive, &task_mulin_intr, WAIT_WORSTCASE, NULL); + return ide_started; } - -EXPORT_SYMBOL(pre_task_out_intr); +EXPORT_SYMBOL(task_mulin_intr); /* - * Handler for command with PIO data-out phase WRITE - * - * WOOHOO this is a CORRECT STATE DIAGRAM NOW, <andre@linux-ide.org> + * Handler for command with PIO data-out phase (Write). */ ide_startstop_t task_out_intr (ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - struct request *rq = HWGROUP(drive)->rq; - char *pBuf = NULL; - unsigned long flags; + struct request *rq = HWGROUP(drive)->rq; u8 stat; - if (!OK_STAT(stat = hwif->INB(IDE_STATUS_REG), DRIVE_READY, drive->bad_wstat)) { - DTF("%s: WRITE attempting to recover last " \ - "sector counter status=0x%02x\n", - drive->name, stat); - rq->current_nr_sectors++; - return DRIVER(drive)->error(drive, "task_out_intr", stat); + stat = HWIF(drive)->INB(IDE_STATUS_REG); + if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat)) { + if ((stat & (ERR_STAT | DRQ_STAT)) || + ((stat & WRERR_STAT) && !drive->nowerr)) + return DRIVER(drive)->error(drive, __FUNCTION__, stat); + if (stat & BUSY_STAT) { + /* Not ready yet, so wait for another IRQ. */ + ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL); + return ide_started; + } } - /* - * Safe to update request for partial completions. - * We have a good STATUS CHECK!!! + + /* Deal with unexpected ATA data phase. */ + if ((!(stat & DATA_READY) && rq->nr_sectors) || + ((stat & DATA_READY) && !rq->nr_sectors)) + return DRIVER(drive)->error(drive, __FUNCTION__, stat); + + /* + * Complete previously submitted bios (if any). + * Status was already verifyied. */ - if (!rq->current_nr_sectors) - if (!DRIVER(drive)->end_request(drive, 1, 0)) + while (rq->bio != rq->cbio) + if (!DRIVER(drive)->end_request(drive, 1, bio_sectors(rq->bio))) return ide_stopped; - if ((rq->current_nr_sectors==1) ^ (stat & DRQ_STAT)) { - rq = HWGROUP(drive)->rq; - pBuf = task_map_rq(rq, &flags); - DTF("write: %p, rq->current_nr_sectors: %d\n", - pBuf, (int) rq->current_nr_sectors); - taskfile_output_data(drive, pBuf, SECTOR_WORDS); - task_unmap_rq(rq, pBuf, &flags); - rq->errors = 0; - rq->current_nr_sectors--; + /* Complete rq->buffer based request (ioctls). */ + if (!rq->bio && !rq->nr_sectors) { + ide_end_drive_cmd(drive, stat, HWIF(drive)->INB(IDE_ERROR_REG)); + return ide_stopped; } - if (HWGROUP(drive)->handler == NULL) - ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL); + + /* Still data left to transfer. */ + ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL); + + rq->errors = 0; + task_sectors(drive, rq, 1, IDE_PIO_OUT); + return ide_started; } EXPORT_SYMBOL(task_out_intr); -#undef ALTERNATE_STATE_DIAGRAM_MULTI_OUT - -ide_startstop_t pre_task_mulout_intr (ide_drive_t *drive, struct request *rq) +ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq) { -#ifdef ALTERNATE_STATE_DIAGRAM_MULTI_OUT - ide_hwif_t *hwif = HWIF(drive); - char *pBuf = NULL; - unsigned int nsect = 0, msect = drive->mult_count; - u8 stat; - unsigned long flags; -#endif /* ALTERNATE_STATE_DIAGRAM_MULTI_OUT */ - - ide_task_t *args = rq->special; ide_startstop_t startstop; -#if 0 - /* - * assign private copy for multi-write - */ - memcpy(&HWGROUP(drive)->wrq, rq, sizeof(struct request)); -#endif - if (ide_wait_stat(&startstop, drive, DATA_READY, - drive->bad_wstat, WAIT_DRQ)) { - printk(KERN_ERR "%s: no DRQ after issuing %s\n", - drive->name, - drive->addressing ? "MULTWRITE_EXT" : "MULTWRITE"); + drive->bad_wstat, WAIT_DRQ)) { + printk(KERN_ERR "%s: no DRQ after issuing WRITE%s\n", + drive->name, drive->addressing ? "_EXT" : ""); return startstop; } -#ifdef ALTERNATE_STATE_DIAGRAM_MULTI_OUT - do { - nsect = rq->current_nr_sectors; - if (nsect > msect) - nsect = msect; - pBuf = task_map_rq(rq, &flags); - DTF("Pre-Multiwrite: %p, nsect: %d, msect: %d, " \ - "rq->current_nr_sectors: %ld\n", - pBuf, nsect, msect, rq->current_nr_sectors); - msect -= nsect; - taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS); - task_unmap_rq(rq, pBuf, &flags); - rq->current_nr_sectors -= nsect; - if (!rq->current_nr_sectors) { - if (!DRIVER(drive)->end_request(drive, 1, 0)) - if (!rq->bio) { - stat = hwif->INB(IDE_STATUS_REG); - return ide_stopped; - } - } - } while (msect); - rq->errors = 0; - return ide_started; -#else /* ! ALTERNATE_STATE_DIAGRAM_MULTI_OUT */ - if (!(drive_is_ready(drive))) { - int i; - for (i=0; i<100; i++) { - if (drive_is_ready(drive)) - break; - } - } - - /* - * WARNING :: if the drive as not acked good status we may not - * move the DATA-TRANSFER T-Bar as BSY != 0. <andre@linux-ide.org> - */ - return args->handler(drive); -#endif /* ALTERNATE_STATE_DIAGRAM_MULTI_OUT */ + return task_out_intr(drive); } - -EXPORT_SYMBOL(pre_task_mulout_intr); +EXPORT_SYMBOL(pre_task_out_intr); /* - * FIXME before enabling in 2.4 ... DATA integrity issue upon error. - */ -/* - * Handler for command write multiple - * Called directly from execute_drive_cmd for the first bunch of sectors, - * afterwards only by the ISR + * Handler for command with PIO data-out phase (Write Multiple). */ ide_startstop_t task_mulout_intr (ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); - u8 stat = hwif->INB(IDE_STATUS_REG); - struct request *rq = HWGROUP(drive)->rq; - char *pBuf = NULL; - ide_startstop_t startstop = ide_stopped; - unsigned int msect = drive->mult_count; + struct request *rq = HWGROUP(drive)->rq; + unsigned int msect = drive->mult_count; unsigned int nsect; - unsigned long flags; + u8 stat; - /* - * (ks/hs): Handle last IRQ on multi-sector transfer, - * occurs after all data was sent in this chunk - */ - if (rq->current_nr_sectors == 0) { - if (stat & (ERR_STAT|DRQ_STAT)) { - if (!rq->bio) { - rq->current_nr_sectors += drive->mult_count; - /* - * NOTE: could rewind beyond beginning :-/ - */ - } else { - printk(KERN_ERR "%s: MULTI-WRITE assume all data " \ - "transfered is bad status=0x%02x\n", - drive->name, stat); - } - return DRIVER(drive)->error(drive, "task_mulout_intr", stat); + stat = HWIF(drive)->INB(IDE_STATUS_REG); + if (!OK_STAT(stat, DRIVE_READY, drive->bad_wstat)) { + if ((stat & (ERR_STAT | DRQ_STAT)) || + ((stat & WRERR_STAT) && !drive->nowerr)) + return DRIVER(drive)->error(drive, __FUNCTION__, stat); + if (stat & BUSY_STAT) { + /* Not ready yet, so wait for another IRQ. */ + ide_set_handler(drive, &task_mulout_intr, WAIT_WORSTCASE, NULL); + return ide_started; } - if (!rq->bio) - DRIVER(drive)->end_request(drive, 1, 0); - return startstop; } - /* - * DON'T be lazy code the above and below togather !!! + + /* Deal with unexpected ATA data phase. */ + if ((!(stat & DATA_READY) && rq->nr_sectors) || + ((stat & DATA_READY) && !rq->nr_sectors)) + return DRIVER(drive)->error(drive, __FUNCTION__, stat); + + /* + * Complete previously submitted bios (if any). + * Status was already verifyied. */ - if (!OK_STAT(stat,DATA_READY,BAD_R_STAT)) { - if (stat & (ERR_STAT|DRQ_STAT)) { - if (!rq->bio) { - rq->current_nr_sectors += drive->mult_count; - /* - * NOTE: could rewind beyond beginning :-/ - */ - } else { - printk("%s: MULTI-WRITE assume all data " \ - "transfered is bad status=0x%02x\n", - drive->name, stat); - } - return DRIVER(drive)->error(drive, "task_mulout_intr", stat); - } - /* no data yet, so wait for another interrupt */ - if (HWGROUP(drive)->handler == NULL) - ide_set_handler(drive, &task_mulout_intr, WAIT_WORSTCASE, NULL); - return ide_started; + while (rq->bio != rq->cbio) + if (!DRIVER(drive)->end_request(drive, 1, bio_sectors(rq->bio))) + return ide_stopped; + /* Complete rq->buffer based request (ioctls). */ + if (!rq->bio && !rq->nr_sectors) { + ide_end_drive_cmd(drive, stat, HWIF(drive)->INB(IDE_ERROR_REG)); + return ide_stopped; } -#ifndef ALTERNATE_STATE_DIAGRAM_MULTI_OUT - if (HWGROUP(drive)->handler != NULL) { - unsigned long lflags; - spin_lock_irqsave(&ide_lock, lflags); - HWGROUP(drive)->handler = NULL; - del_timer(&HWGROUP(drive)->timer); - spin_unlock_irqrestore(&ide_lock, lflags); - } -#endif /* ALTERNATE_STATE_DIAGRAM_MULTI_OUT */ + /* Still data left to transfer. */ + ide_set_handler(drive, &task_mulout_intr, WAIT_WORSTCASE, NULL); + rq->errors = 0; do { nsect = rq->current_nr_sectors; if (nsect > msect) nsect = msect; - pBuf = task_map_rq(rq, &flags); - DTF("Multiwrite: %p, nsect: %d, msect: %d, " \ - "rq->current_nr_sectors: %ld\n", - pBuf, nsect, msect, rq->current_nr_sectors); - msect -= nsect; - taskfile_output_data(drive, pBuf, nsect * SECTOR_WORDS); - task_unmap_rq(rq, pBuf, &flags); - rq->current_nr_sectors -= nsect; - /* - * FIXME :: We really can not legally get a new page/bh - * regardless, if this is the end of our segment. - * BH walking or segment can only be updated after we - * have a good hwif->INB(IDE_STATUS_REG); return. - */ - if (!rq->current_nr_sectors) { - if (!DRIVER(drive)->end_request(drive, 1, 0)) - if (!rq->bio) - return ide_stopped; - } + + task_sectors(drive, rq, nsect, IDE_PIO_OUT); + + if (!rq->nr_sectors) + msect = 0; + else + msect -= nsect; } while (msect); - rq->errors = 0; - if (HWGROUP(drive)->handler == NULL) - ide_set_handler(drive, &task_mulout_intr, WAIT_WORSTCASE, NULL); + return ide_started; } - EXPORT_SYMBOL(task_mulout_intr); +ide_startstop_t pre_task_mulout_intr (ide_drive_t *drive, struct request *rq) +{ + ide_startstop_t startstop; + + if (ide_wait_stat(&startstop, drive, DATA_READY, + drive->bad_wstat, WAIT_DRQ)) { + printk(KERN_ERR "%s: no DRQ after issuing MULTWRITE%s\n", + drive->name, drive->addressing ? "_EXT" : ""); + return startstop; + } + + return task_mulout_intr(drive); +} +EXPORT_SYMBOL(pre_task_mulout_intr); + /* Called by internal to feature out type of command being called */ //ide_pre_handler_t * ide_pre_handler_parser (task_struct_t *taskfile, hob_struct_t *hobfile) ide_pre_handler_t * ide_pre_handler_parser (struct hd_drive_task_hdr *taskfile, struct hd_drive_hob_hdr *hobfile) @@ -1092,11 +960,12 @@ */ if (args->command_type != IDE_DRIVE_TASK_NO_DATA) { if (data_size == 0) - rq.current_nr_sectors = rq.nr_sectors = (args->hobRegister[IDE_NSECTOR_OFFSET_HOB] << 8) | args->tfRegister[IDE_NSECTOR_OFFSET]; - /* rq.hard_cur_sectors */ + rq.nr_sectors = (args->hobRegister[IDE_NSECTOR_OFFSET_HOB] << 8) | args->tfRegister[IDE_NSECTOR_OFFSET]; else - rq.current_nr_sectors = rq.nr_sectors = data_size / SECTOR_SIZE; - /* rq.hard_cur_sectors */ + rq.nr_sectors = data_size / SECTOR_SIZE; + + rq.hard_nr_sectors = rq.nr_sectors; + rq.hard_cur_sectors = rq.current_nr_sectors = rq.nr_sectors; } if (args->tf_out_flags.all == 0) { diff -Nru a/drivers/ide/ide.c b/drivers/ide/ide.c --- a/drivers/ide/ide.c Mon Jun 9 23:16:09 2003 +++ b/drivers/ide/ide.c Mon Jun 9 23:16:09 2003 @@ -462,7 +462,6 @@ return -ENXIO; } -static LIST_HEAD(ata_unused); static spinlock_t drives_lock = SPIN_LOCK_UNLOCKED; static spinlock_t drivers_lock = SPIN_LOCK_UNLOCKED; static LIST_HEAD(drivers); @@ -1437,9 +1436,6 @@ spin_unlock(&drivers_lock); if(idedefault_driver.attach(drive) != 0) panic("ide: default attach failed"); - spin_lock(&drives_lock); - list_add_tail(&drive->list, &ata_unused); - spin_unlock(&drives_lock); return 1; } @@ -1737,7 +1733,6 @@ * "hdx=cyl,head,sect" : disk drive is present, with specified geometry * "hdx=remap63" : add 63 to all sector numbers (for OnTrack DM) * "hdx=remap" : remap 0->1 (for EZDrive) - * "hdx=noremap" : do not remap 0->1 even though EZD was detected * "hdx=autotune" : driver will attempt to tune interface speed * to the fastest PIO mode supported, * if possible for this drive only. @@ -1859,8 +1854,8 @@ const char *hd_words[] = { "none", "noprobe", "nowerr", "cdrom", "serialize", "autotune", "noautotune", "slow", "swapdata", "bswap", - "flash", "remap", "noremap", "scsi", "biostimings", - "remap63", NULL }; + "flash", "remap", "remap63", "scsi", "biostimings", + NULL }; unit = s[2] - 'a'; hw = unit / MAX_DRIVES; unit = unit % MAX_DRIVES; @@ -1920,23 +1915,15 @@ case -12: /* "remap" */ drive->remap_0_to_1 = 1; goto done; - case -13: /* "noremap" */ - drive->remap_0_to_1 = 2; + case -13: /* "remap63" */ + drive->sect0 = 63; goto done; case -14: /* "scsi" */ -#if defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI) drive->scsi = 1; goto done; -#else - drive->scsi = 0; - goto bad_option; -#endif /* defined(CONFIG_BLK_DEV_IDESCSI) && defined(CONFIG_SCSI) */ case -15: /* "biostimings" */ drive->autotune = IDE_TUNE_BIOS; goto done; - case -16: /* "remap63" */ - drive->sect0 = 63; - goto done; case 3: /* cyl,head,sect */ drive->media = ide_disk; drive->cyl = drive->bios_cyl = vals[0]; @@ -2348,7 +2335,7 @@ setup_driver_defaults(drive); spin_unlock_irqrestore(&ide_lock, flags); spin_lock(&drives_lock); - list_add(&drive->list, &driver->drives); + list_add_tail(&drive->list, &driver->drives); spin_unlock(&drives_lock); // printk(KERN_INFO "%s: attached %s driver.\n", drive->name, driver->name); if ((drive->autotune == IDE_TUNE_DEFAULT) || @@ -2362,8 +2349,10 @@ } drive->suspend_reset = 0; #ifdef CONFIG_PROC_FS - ide_add_proc_entries(drive->proc, generic_subdriver_entries, drive); - ide_add_proc_entries(drive->proc, driver->proc, drive); + if (drive->driver != &idedefault_driver) { + ide_add_proc_entries(drive->proc, generic_subdriver_entries, drive); + ide_add_proc_entries(drive->proc, driver->proc, drive); + } #endif return 0; } @@ -2392,8 +2381,8 @@ spin_unlock_irqrestore(&ide_lock, flags); spin_lock(&drives_lock); list_del_init(&drive->list); - list_add(&drive->list, &drive->driver->drives); spin_unlock(&drives_lock); + /* drive will be added to &idedefault_driver->drives in ata_attach() */ return 0; } @@ -2416,9 +2405,9 @@ list_add(&driver->drivers, &drivers); spin_unlock(&drivers_lock); - spin_lock(&drives_lock); INIT_LIST_HEAD(&list); - list_splice_init(&ata_unused, &list); + spin_lock(&drives_lock); + list_splice_init(&idedefault_driver.drives, &list); spin_unlock(&drives_lock); list_for_each_safe(list_loop, tmp_storage, &list) { diff -Nru a/drivers/ide/legacy/ide-cs.c b/drivers/ide/legacy/ide-cs.c --- a/drivers/ide/legacy/ide-cs.c Mon Jun 9 23:16:15 2003 +++ b/drivers/ide/legacy/ide-cs.c Mon Jun 9 23:16:15 2003 @@ -470,28 +470,25 @@ return 0; } /* ide_event */ -/*====================================================================*/ +static struct pcmcia_driver ide_cs_driver = { + .owner = THIS_MODULE, + .drv = { + .name = "ide_cs", + }, + .attach = ide_attach, + .detach = ide_detach, +}; static int __init init_ide_cs(void) { - servinfo_t serv; - DEBUG(0, "%s\n", version); - CardServices(GetCardServicesInfo, &serv); - if (serv.Revision != CS_RELEASE_CODE) { - printk(KERN_NOTICE "ide-cs: Card Services release " - "does not match!\n"); - return -EINVAL; - } - register_pccard_driver(&dev_info, &ide_attach, &ide_detach); - return 0; + return pcmcia_register_driver(&ide_cs_driver); } static void __exit exit_ide_cs(void) { - DEBUG(0, "ide-cs: unloading\n"); - unregister_pccard_driver(&dev_info); - while (dev_list != NULL) - ide_detach(dev_list); + pcmcia_unregister_driver(&ide_cs_driver); + while (dev_list != NULL) + ide_detach(dev_list); } module_init(init_ide_cs); diff -Nru a/drivers/ide/legacy/pdc4030.c b/drivers/ide/legacy/pdc4030.c --- a/drivers/ide/legacy/pdc4030.c Mon Jun 9 23:16:12 2003 +++ b/drivers/ide/legacy/pdc4030.c Mon Jun 9 23:16:12 2003 @@ -94,7 +94,7 @@ #include "pdc4030.h" -static ide_startstop_t promise_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block); +static ide_startstop_t promise_rw_disk (ide_drive_t *drive, struct request *rq, sector_t block); /* * promise_selectproc() is invoked by ide.c @@ -408,67 +408,44 @@ */ static ide_startstop_t promise_read_intr (ide_drive_t *drive) { - int total_remaining; unsigned int sectors_left, sectors_avail, nsect; - struct request *rq; + struct request *rq = HWGROUP(drive)->rq; ata_status_t status; -#ifdef CONFIG_IDE_TASKFILE_IO - unsigned long flags; - char *to; -#endif /* CONFIG_IDE_TASKFILE_IO */ status.all = HWIF(drive)->INB(IDE_STATUS_REG); if (!OK_STAT(status.all, DATA_READY, BAD_R_STAT)) - return DRIVER(drive)->error(drive, - "promise_read_intr", status.all); + return DRIVER(drive)->error(drive, __FUNCTION__, status.all); read_again: do { sectors_left = HWIF(drive)->INB(IDE_NSECTOR_REG); HWIF(drive)->INB(IDE_SECTOR_REG); } while (HWIF(drive)->INB(IDE_NSECTOR_REG) != sectors_left); - rq = HWGROUP(drive)->rq; sectors_avail = rq->nr_sectors - sectors_left; if (!sectors_avail) goto read_again; read_next: - rq = HWGROUP(drive)->rq; nsect = rq->current_nr_sectors; if (nsect > sectors_avail) nsect = sectors_avail; sectors_avail -= nsect; -#ifdef CONFIG_IDE_TASKFILE_IO - to = ide_map_buffer(rq, &flags); - HWIF(drive)->ata_input_data(drive, to, nsect * SECTOR_WORDS); -#else /* !CONFIG_IDE_TASKFILE_IO */ - HWIF(drive)->ata_input_data(drive, rq->buffer, nsect * SECTOR_WORDS); -#endif /* CONFIG_IDE_TASKFILE_IO */ #ifdef DEBUG_READ - printk(KERN_DEBUG "%s: promise_read: sectors(%ld-%ld), " - "buf=0x%08lx, rem=%ld\n", drive->name, (long)rq->sector, - (long)rq->sector+nsect-1, -#ifdef CONFIG_IDE_TASKFILE_IO - (unsigned long) to, -#else /* !CONFIG_IDE_TASKFILE_IO */ - (unsigned long) rq->buffer, -#endif /* CONFIG_IDE_TASKFILE_IO */ - rq->nr_sectors-nsect); + printk(KERN_DEBUG "%s: %s: sectors(%lu-%lu), rem=%lu\n", + drive->name, __FUNCTION__, + (unsigned long)rq->sector, + (unsigned long)rq->sector + nsect - 1, + (unsigned long)rq->nr_sectors - nsect); #endif /* DEBUG_READ */ -#ifdef CONFIG_IDE_TASKFILE_IO - ide_unmap_buffer(to, &flags); -#else /* !CONFIG_IDE_TASKFILE_IO */ - rq->buffer += nsect<<9; -#endif /* CONFIG_IDE_TASKFILE_IO */ - rq->sector += nsect; - rq->errors = 0; - rq->nr_sectors -= nsect; - total_remaining = rq->nr_sectors; - if ((rq->current_nr_sectors -= nsect) <= 0) { - DRIVER(drive)->end_request(drive, 1, 0); - } + task_sectors(drive, rq, nsect, IDE_PIO_IN); + + /* FIXME: can we check status after transfer on pdc4030? */ + /* Complete previously submitted bios. */ + while (rq->bio != rq->cbio) + if (!DRIVER(drive)->end_request(drive, 1, bio_sectors(rq->bio))) + return ide_stopped; /* * Now the data has been read in, do the following: * @@ -480,7 +457,7 @@ * else if BUSY is asserted, we are going to get an interrupt, so * set the handler for the interrupt and just return */ - if (total_remaining > 0) { + if (rq->nr_sectors > 0) { if (sectors_avail) goto read_next; status.all = HWIF(drive)->INB(IDE_STATUS_REG); @@ -519,7 +496,6 @@ { ide_hwgroup_t *hwgroup = HWGROUP(drive); struct request *rq = hwgroup->rq; - int i; if ((HWIF(drive)->INB(IDE_STATUS_REG)) & BUSY_STAT) { if (time_before(jiffies, hwgroup->poll_timeout)) { @@ -542,85 +518,35 @@ #ifdef DEBUG_WRITE printk(KERN_DEBUG "%s: Write complete - end_request\n", drive->name); #endif /* DEBUG_WRITE */ - for (i = rq->nr_sectors; i > 0; ) { - i -= rq->current_nr_sectors; - DRIVER(drive)->end_request(drive, 1, 0); - } + + /* Complete previously submitted bios. */ + while (rq->bio != rq->cbio) + (void) DRIVER(drive)->end_request(drive, 1, bio_sectors(rq->bio)); return ide_stopped; } /* * promise_multwrite() transfers a block of up to mcount sectors of data * to a drive as part of a disk multiple-sector write operation. - * - * Returns 0 on success. - * - * Note that we may be called from two contexts - the do_rw_disk context - * and IRQ context. The IRQ can happen any time after we've output the - * full "mcount" number of sectors, so we must make sure we update the - * state _before_ we output the final part of the data! */ -int promise_multwrite (ide_drive_t *drive, unsigned int mcount) +static void promise_multwrite (ide_drive_t *drive, unsigned int msect) { - ide_hwgroup_t *hwgroup = HWGROUP(drive); - struct request *rq = &hwgroup->wrq; + struct request* rq = HWGROUP(drive)->rq; + unsigned int nsect; + rq->errors = 0; do { - char *buffer; - int nsect = rq->current_nr_sectors; -#ifdef CONFIG_IDE_TASKFILE_IO - unsigned long flags; -#endif /* CONFIG_IDE_TASKFILE_IO */ - - if (nsect > mcount) - nsect = mcount; - mcount -= nsect; -#ifdef CONFIG_IDE_TASKFILE_IO - buffer = ide_map_buffer(rq, &flags); - rq->sector += nsect; -#else /* !CONFIG_IDE_TASKFILE_IO */ - buffer = rq->buffer; - - rq->sector += nsect; - rq->buffer += nsect << 9; -#endif /* CONFIG_IDE_TASKFILE_IO */ - rq->nr_sectors -= nsect; - rq->current_nr_sectors -= nsect; - - /* Do we move to the next bh after this? */ - if (!rq->current_nr_sectors) { - struct bio *bio = rq->bio; - - /* - * only move to next bio, when we have processed - * all bvecs in this one. - */ - if (++bio->bi_idx >= bio->bi_vcnt) { - bio->bi_idx = 0; - bio = bio->bi_next; - } - - /* end early early we ran out of requests */ - if (!bio) { - mcount = 0; - } else { - rq->bio = bio; - rq->current_nr_sectors = bio_iovec(bio)->bv_len >> 9; - rq->hard_cur_sectors = rq->current_nr_sectors; - } - } - - /* - * Ok, we're all setup for the interrupt - * re-entering us on the last transfer. - */ - taskfile_output_data(drive, buffer, nsect<<7); -#ifdef CONFIG_IDE_TASKFILE_IO - ide_unmap_buffer(buffer, &flags); -#endif /* CONFIG_IDE_TASKFILE_IO */ - } while (mcount); - - return 0; + nsect = rq->current_nr_sectors; + if (nsect > msect) + nsect = msect; + + task_sectors(drive, rq, nsect, IDE_PIO_OUT); + + if (!rq->nr_sectors) + msect = 0; + else + msect -= nsect; + } while (msect); } /* @@ -629,6 +555,7 @@ static ide_startstop_t promise_write_pollfunc (ide_drive_t *drive) { ide_hwgroup_t *hwgroup = HWGROUP(drive); + struct request *rq = hwgroup->rq; if (HWIF(drive)->INB(IDE_NSECTOR_REG) != 0) { if (time_before(jiffies, hwgroup->poll_timeout)) { @@ -646,6 +573,10 @@ HWIF(drive)->INB(IDE_STATUS_REG)); } + /* Complete previously submitted bios. */ + while (rq->bio != rq->cbio) + (void) DRIVER(drive)->end_request(drive, 1, bio_sectors(rq->bio)); + /* * Now write out last 4 sectors and poll for not BUSY */ @@ -671,12 +602,13 @@ static ide_startstop_t promise_write (ide_drive_t *drive) { ide_hwgroup_t *hwgroup = HWGROUP(drive); - struct request *rq = &hwgroup->wrq; + struct request *rq = hwgroup->rq; #ifdef DEBUG_WRITE - printk(KERN_DEBUG "%s: promise_write: sectors(%ld-%ld), " - "buffer=%p\n", drive->name, (long)rq->sector, - (long)rq->sector + rq->nr_sectors - 1, rq->buffer); + printk(KERN_DEBUG "%s: %s: sectors(%lu-%lu)\n", + drive->name, __FUNCTION__, + (unsigned long)rq->sector, + (unsigned long)rq->sector + rq->nr_sectors - 1); #endif /* DEBUG_WRITE */ /* @@ -684,8 +616,7 @@ * the polling strategy as defined above. */ if (rq->nr_sectors > 4) { - if (promise_multwrite(drive, rq->nr_sectors - 4)) - return ide_stopped; + promise_multwrite(drive, rq->nr_sectors - 4); hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; if (hwgroup->handler != NULL) /* paranoia check */ BUG(); @@ -696,8 +627,7 @@ * There are 4 or fewer sectors to transfer, do them all in one go * and wait for NOT BUSY. */ - if (promise_multwrite(drive, rq->nr_sectors)) - return ide_stopped; + promise_multwrite(drive, rq->nr_sectors); hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; if (hwgroup->handler != NULL) BUG(); @@ -720,26 +650,14 @@ * already set up. It issues a READ or WRITE command to the Promise * controller, assuming LBA has been used to set up the block number. */ -#ifndef CONFIG_IDE_TASKFILE_IO -ide_startstop_t do_pdc4030_io (ide_drive_t *drive, struct request *rq) -{ -#else /* CONFIG_IDE_TASKFILE_IO */ -ide_startstop_t do_pdc4030_io (ide_drive_t *drive, ide_task_t *task) +static ide_startstop_t do_pdc4030_io (ide_drive_t *drive, ide_task_t *task) { struct request *rq = HWGROUP(drive)->rq; task_struct_t *taskfile = (task_struct_t *) task->tfRegister; -#endif /* CONFIG_IDE_TASKFILE_IO */ ide_startstop_t startstop; unsigned long timeout; u8 stat = 0; - if (!blk_fs_request(rq)) { - blk_dump_rq_flags(rq, "do_pdc4030_io - bad command"); - DRIVER(drive)->end_request(drive, 0, 0); - return ide_stopped; - } - -#ifdef CONFIG_IDE_TASKFILE_IO if (IDE_CONTROL_REG) HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG); /* clear nIEN */ SELECT_MASK(drive, 0); @@ -752,12 +670,8 @@ HWIF(drive)->OUTB(taskfile->high_cylinder, IDE_HCYL_REG); HWIF(drive)->OUTB(taskfile->device_head, IDE_SELECT_REG); HWIF(drive)->OUTB(taskfile->command, IDE_COMMAND_REG); -#endif /* CONFIG_IDE_TASKFILE_IO */ if (rq_data_dir(rq) == READ) { -#ifndef CONFIG_IDE_TASKFILE_IO - HWIF(drive)->OUTB(PROMISE_READ, IDE_COMMAND_REG); -#endif /* CONFIG_IDE_TASKFILE_IO */ /* * The card's behaviour is odd at this point. If the data is * available, DRQ will be true, and no interrupt will be @@ -793,9 +707,6 @@ "waiting - Odd!\n", drive->name); return ide_stopped; } else { -#ifndef CONFIG_IDE_TASKFILE_IO - HWIF(drive)->OUTB(PROMISE_WRITE, IDE_COMMAND_REG); -#endif /* CONFIG_IDE_TASKFILE_IO */ if (ide_wait_stat(&startstop, drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) { printk(KERN_ERR "%s: no DRQ after issuing " @@ -804,12 +715,11 @@ } if (!drive->unmask) local_irq_disable(); - HWGROUP(drive)->wrq = *rq; /* scratchpad */ return promise_write(drive); } } -static ide_startstop_t promise_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block) +static ide_startstop_t promise_rw_disk (ide_drive_t *drive, struct request *rq, sector_t block) { /* The four drives on the two logical (one physical) interfaces are distinguished by writing the drive number (0-3) to the @@ -817,33 +727,22 @@ FIXME: Is promise_selectproc now redundant?? */ int drive_number = (HWIF(drive)->channel << 1) + drive->select.b.unit; -#ifndef CONFIG_IDE_TASKFILE_IO - ide_hwif_t *hwif = HWIF(drive); + struct hd_drive_task_hdr taskfile; + ide_task_t args; BUG_ON(rq->nr_sectors > 127); - if (IDE_CONTROL_REG) - hwif->OUTB(drive->ctl, IDE_CONTROL_REG); + if (!blk_fs_request(rq)) { + blk_dump_rq_flags(rq, "promise_rw_disk - bad command"); + DRIVER(drive)->end_request(drive, 0, 0); + return ide_stopped; + } #ifdef DEBUG - printk("%s: %sing: LBAsect=%ld, sectors=%ld, " - "buffer=0x%08lx\n", drive->name, - (rq->cmd==READ)?"read":"writ", block, - rq->nr_sectors, (unsigned long) rq->buffer); + printk(KERN_DEBUG "%s: %sing: LBAsect=%lu, sectors=%lu\n", + drive->name, rq_data_dir(rq) ? "writ" : "read", + block, rq->nr_sectors); #endif - hwif->OUTB(drive_number, IDE_FEATURE_REG); - hwif->OUTB(rq->nr_sectors, IDE_NSECTOR_REG); - hwif->OUTB(block,IDE_SECTOR_REG); - hwif->OUTB(block>>=8,IDE_LCYL_REG); - hwif->OUTB(block>>=8,IDE_HCYL_REG); - hwif->OUTB(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG); - - return do_pdc4030_io(drive, rq); - -#else /* CONFIG_IDE_TASKFILE_IO */ - - struct hd_drive_task_hdr taskfile; - ide_task_t args; memset(&taskfile, 0, sizeof(struct hd_drive_task_hdr)); @@ -867,5 +766,4 @@ rq->special = (ide_task_t *)&args; return do_pdc4030_io(drive, &args); -#endif /* CONFIG_IDE_TASKFILE_IO */ } diff -Nru a/drivers/ide/pci/cs5530.c b/drivers/ide/pci/cs5530.c --- a/drivers/ide/pci/cs5530.c Mon Jun 9 23:16:10 2003 +++ b/drivers/ide/pci/cs5530.c Mon Jun 9 23:16:10 2003 @@ -281,16 +281,15 @@ } #endif /* DISPLAY_CS5530_TIMINGS && CONFIG_PROC_FS */ - pci_for_each_dev (dev) { - if (dev->vendor == PCI_VENDOR_ID_CYRIX) { - switch (dev->device) { - case PCI_DEVICE_ID_CYRIX_PCI_MASTER: - master_0 = dev; - break; - case PCI_DEVICE_ID_CYRIX_5530_LEGACY: - cs5530_0 = dev; - break; - } + dev = NULL; + while ((dev = pci_find_device(PCI_VENDOR_ID_CYRIX, PCI_ANY_ID, dev)) != NULL) { + switch (dev->device) { + case PCI_DEVICE_ID_CYRIX_PCI_MASTER: + master_0 = dev; + break; + case PCI_DEVICE_ID_CYRIX_5530_LEGACY: + cs5530_0 = dev; + break; } } if (!master_0) { diff -Nru a/drivers/ide/pci/hpt366.c b/drivers/ide/pci/hpt366.c --- a/drivers/ide/pci/hpt366.c Mon Jun 9 23:16:14 2003 +++ b/drivers/ide/pci/hpt366.c Mon Jun 9 23:16:14 2003 @@ -1100,7 +1100,7 @@ if (PCI_FUNC(dev->devfn) & 1) return; - pci_for_each_dev(findev) { + while ((findev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) { if ((findev->vendor == dev->vendor) && (findev->device == dev->device) && ((findev->devfn - dev->devfn) == 1) && @@ -1150,7 +1150,7 @@ d->channels = 1; pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin1); - pci_for_each_dev(findev) { + while ((findev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) { if ((findev->vendor == dev->vendor) && (findev->device == dev->device) && ((findev->devfn - dev->devfn) == 1) && diff -Nru a/drivers/ide/pci/pdc202xx_new.c b/drivers/ide/pci/pdc202xx_new.c --- a/drivers/ide/pci/pdc202xx_new.c Mon Jun 9 23:16:16 2003 +++ b/drivers/ide/pci/pdc202xx_new.c Mon Jun 9 23:16:16 2003 @@ -579,7 +579,7 @@ static void __init init_setup_pdc20270 (struct pci_dev *dev, ide_pci_device_t *d) { - struct pci_dev *findev; + struct pci_dev *findev = NULL; if ((dev->bus->self && dev->bus->self->vendor == PCI_VENDOR_ID_DEC) && @@ -588,7 +588,7 @@ return; } d->extra = 0; - pci_for_each_dev(findev) { + while ((findev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, findev)) != NULL) { if ((findev->vendor == dev->vendor) && (findev->device == dev->device) && (PCI_SLOT(findev->devfn) & 2)) { diff -Nru a/drivers/ide/setup-pci.c b/drivers/ide/setup-pci.c --- a/drivers/ide/setup-pci.c Mon Jun 9 23:16:10 2003 +++ b/drivers/ide/setup-pci.c Mon Jun 9 23:16:10 2003 @@ -870,17 +870,17 @@ void __init ide_scan_pcibus (int scan_direction) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; struct pci_driver *d; struct list_head *l, *n; pre_init = 0; if (!scan_direction) { - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { ide_scan_pcidev(dev); } } else { - pci_for_each_dev_reverse(dev) { + while ((dev = pci_find_device_reverse(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { ide_scan_pcidev(dev); } } diff -Nru a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c --- a/drivers/ieee1394/eth1394.c Mon Jun 9 23:16:14 2003 +++ b/drivers/ieee1394/eth1394.c Mon Jun 9 23:16:14 2003 @@ -3,6 +3,7 @@ * * Copyright (C) 2001 Ben Collins <bcollins@debian.org> * 2000 Bonin Franck <boninf@free.fr> + * 2003 Steve Kinneberg <kinnebergsteve@acmsystems.com> * * Mainly based on work by Emanuel Pirker and Andreas E. Bombe * @@ -21,22 +22,27 @@ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -/* State of this driver: - * - * This driver intends to support RFC 2734, which describes a method for +/* This driver intends to support RFC 2734, which describes a method for * transporting IPv4 datagrams over IEEE-1394 serial busses. This driver * will ultimately support that method, but currently falls short in - * several areas. A few issues are: + * several areas. + * + * TODO: + * RFC 2734 related: + * - Add Config ROM entry + * - Add MCAP and multicast * - * - Does not support send/recv over Async streams using GASP - * packet formats, as per the RFC for ARP requests. - * - Does not yet support fragmented packets. - * - Relies on hardware address being equal to the nodeid for some things. - * - Does not support multicast - * - Hardcoded address for sending packets, instead of using discovery - * (ARP, see first item) + * Non-RFC 2734 related: + * - Fix bug related to fragmented broadcast datagrams + * - Move generic GASP reception to core 1394 code + * - Convert kmalloc/kfree for link fragments to use kmem_cache_* instead + * - Stability improvements + * - Performance enhancements + * - Change hardcoded 1394 bus address region to a dynamic memory space allocation + * - Consider garbage collecting old partial datagrams after X amount of time */ + #include <linux/module.h> #include <linux/sched.h> @@ -56,7 +62,6 @@ #include <linux/tcp.h> #include <linux/skbuff.h> #include <linux/bitops.h> -#include <linux/workqueue.h> #include <asm/delay.h> #include <asm/semaphore.h> #include <net/arp.h> @@ -67,6 +72,7 @@ #include "ieee1394.h" #include "highlevel.h" #include "iso.h" +#include "nodemgr.h" #include "eth1394.h" #define ETH1394_PRINT_G(level, fmt, args...) \ @@ -76,10 +82,27 @@ printk(level ETHER1394_DRIVER_NAME": %s: " fmt, dev_name, ## args) #define DEBUG(fmt, args...) \ - printk(KERN_ERR fmt, ## args) + printk(KERN_ERR "eth1394:%s[%d]: "fmt"\n", __FUNCTION__, __LINE__, ## args) +#define TRACE() printk(KERN_ERR "eth1394:%s[%d] ---- TRACE\n", __FUNCTION__, __LINE__) static char version[] __devinitdata = - "$Rev: 931 $ Ben Collins <bcollins@debian.org>"; + "$Rev: 945 $ Ben Collins <bcollins@debian.org>"; + +struct fragment_info { + struct list_head list; + int offset; + int len; +}; + +struct partial_datagram { + struct list_head list; + u16 dgl; + u16 dg_size; + u16 ether_type; + struct sk_buff *skb; + char *pbuf; + struct list_head frag_info; +}; /* Our ieee1394 highlevel driver */ #define ETHER1394_DRIVER_NAME "ether1394" @@ -89,27 +112,139 @@ static struct hpsb_highlevel eth1394_highlevel; /* Use common.lf to determine header len */ -static int hdr_type_len[] = { +static const int hdr_type_len[] = { sizeof (struct eth1394_uf_hdr), sizeof (struct eth1394_ff_hdr), sizeof (struct eth1394_sf_hdr), sizeof (struct eth1394_sf_hdr) }; +static const u16 eth1394_speedto_maxpayload[] = { +/* S100, S200, S400, S800, S1600, S3200 */ + 512, 1024, 2048, 4096, 8192, 16384 +}; + MODULE_AUTHOR("Ben Collins (bcollins@debian.org)"); MODULE_DESCRIPTION("IEEE 1394 IPv4 Driver (IPv4-over-1394 as per RFC 2734)"); MODULE_LICENSE("GPL"); +/* The max_partial_datagrams parameter is the maximum number of fragmented + * datagrams per node that eth1394 will keep in memory. Providing an upper + * bound allows us to limit the amount of memory that partial datagrams + * consume in the event that some partial datagrams are never completed. This + * should probably change to a sysctl item or the like if possible. + */ +MODULE_PARM(max_partial_datagrams, "i"); +MODULE_PARM_DESC(max_partial_datagrams, + "Maximum number of partially received fragmented datagrams " + "(default = 25)."); +static int max_partial_datagrams = 25; + + +static int ether1394_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, void *daddr, void *saddr, + unsigned len); +static int ether1394_rebuild_header(struct sk_buff *skb); +static int ether1394_header_parse(struct sk_buff *skb, unsigned char *haddr); +static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh); +static void ether1394_header_cache_update(struct hh_cache *hh, + struct net_device *dev, + unsigned char * haddr); +static int ether1394_mac_addr(struct net_device *dev, void *p); + +static inline void purge_partial_datagram(struct list_head *old); +static int ether1394_tx(struct sk_buff *skb, struct net_device *dev); static void ether1394_iso(struct hpsb_iso *iso); +static int ether1394_init_bc(struct net_device *dev) +{ + int ret = 0; + struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv; + + /* First time sending? Need a broadcast channel for ARP and for + * listening on */ + if(priv->bc_state == ETHER1394_BC_CHECK) { + quadlet_t bc; + + /* Get the local copy of the broadcast channel and check its + * validity (the IRM should validate it for us) */ + + bc = priv->host->csr.broadcast_channel; + + if((bc & 0xc0000000) != 0xc0000000) { + /* broadcast channel not validated yet */ + ETH1394_PRINT(KERN_WARNING, dev->name, + "Error BROADCAST_CHANNEL register valid " + "bit not set, can't send IP traffic\n"); + if(!in_interrupt()) { + hpsb_iso_shutdown(priv->iso); + priv->bc_state = ETHER1394_BC_CLOSED; + } + ret = -EAGAIN; + goto fail; + } + if(priv->broadcast_channel != (bc & 0x3f)) { + /* This really shouldn't be possible, but just in case + * the IEEE 1394 spec changes regarding broadcast + * channels in the future. */ + + if(in_interrupt()) { + ret = -EAGAIN; + goto fail; + + } + + hpsb_iso_shutdown(priv->iso); + + priv->broadcast_channel = bc & 0x3f; + ETH1394_PRINT(KERN_INFO, dev->name, + "Changing to broadcast channel %d...\n", + priv->broadcast_channel); + + priv->iso = hpsb_iso_recv_init(priv->host, 16 * 4096, + 16, priv->broadcast_channel, + 1, ether1394_iso); + if(priv->iso == NULL) { + ETH1394_PRINT(KERN_ERR, dev->name, + "failed to change broadcast " + "channel\n"); + ret = -EAGAIN; + goto fail; + } + } + if(hpsb_iso_recv_start(priv->iso, -1, (1 << 3), -1) < 0) { + ETH1394_PRINT(KERN_ERR, dev->name, + "Could not start data stream reception\n"); + if(!in_interrupt()) { + hpsb_iso_shutdown(priv->iso); + priv->bc_state = ETHER1394_BC_CLOSED; + } + ret = -EAGAIN; + goto fail; + } + priv->bc_state = ETHER1394_BC_OPENED; + } + +fail: + return ret; +} + /* This is called after an "ifup" */ static int ether1394_open (struct net_device *dev) { struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv; + unsigned long flags; + int ret; /* Set the spinlock before grabbing IRQ! */ priv->lock = SPIN_LOCK_UNLOCKED; + spin_lock_irqsave(&priv->lock, flags); + ret = ether1394_init_bc(dev); + spin_unlock_irqrestore(&priv->lock, flags); + + if(ret) + return ret; netif_start_queue (dev); return 0; @@ -140,116 +275,35 @@ netif_wake_queue (dev); } -/* We need to encapsulate the standard header with our own. We use the - * ethernet header's proto for our own. - * - * XXX: This is where we need to create a list of skb's for fragmented - * packets. */ -static inline void ether1394_encapsulate (struct sk_buff *skb, struct net_device *dev, - int proto, struct packet_task *ptask) -{ - union eth1394_hdr *hdr = - (union eth1394_hdr *)skb_push (skb, hdr_type_len[ETH1394_HDR_LF_UF]); - - hdr->words.word1 = 0; - hdr->common.lf = ETH1394_HDR_LF_UF; - hdr->words.word1 = htons(hdr->words.word1); - hdr->uf.ether_type = proto; - - /* Set the transmission type for the packet. Right now only ARP - * packets are sent via GASP. IP broadcast and IP multicast are not - * yet supported properly, they too should use GASP. */ - switch(proto) { - case __constant_htons(ETH_P_ARP): - ptask->tx_type = ETH1394_GASP; - break; - default: - ptask->tx_type = ETH1394_WRREQ; - } - return; -} - -/* Convert a standard ARP packet to 1394 ARP. The first 8 bytes (the - * entire arphdr) is the same format as the ip1394 header, so they - * overlap. The rest needs to be munged a bit. The remainder of the - * arphdr is formatted based on hwaddr len and ipaddr len. We know what - * they'll be, so it's easy to judge. */ -static inline void ether1394_arp_to_1394arp (struct sk_buff *skb, struct net_device *dev) -{ - struct eth1394_priv *priv = - (struct eth1394_priv *)(dev->priv); - u16 phy_id = NODEID_TO_NODE(priv->host->node_id); - - unsigned char *arp_ptr = (unsigned char *)skb->data; - struct eth1394_arp *arp1394 = (struct eth1394_arp *)skb->data; - unsigned char arp_data[2*(dev->addr_len+4)]; - - /* Copy the main data that we need */ - memcpy (arp_data, arp_ptr + sizeof(struct arphdr), sizeof (arp_data)); - - /* Extend the buffer enough for our new header */ - skb_put (skb, sizeof (struct eth1394_arp) - - (sizeof (arp_data) + sizeof (struct arphdr))); - -#define PROCESS_MEMBER(ptr,val,len) \ - memcpy (val, ptr, len); ptr += len - arp_ptr = arp_data + arp1394->hw_addr_len; - PROCESS_MEMBER (arp_ptr, &arp1394->sip, arp1394->ip_addr_len); - arp_ptr += arp1394->hw_addr_len; - PROCESS_MEMBER (arp_ptr, &arp1394->tip, arp1394->ip_addr_len); -#undef PROCESS_MEMBER - - /* Now add our own flavor of arp header fields to the orig one */ - arp1394->hw_addr_len = IP1394_HW_ADDR_LEN; - arp1394->hw_type = __constant_htons (ARPHRD_IEEE1394); - arp1394->s_uniq_id = cpu_to_le64 (priv->eui[phy_id]); - arp1394->max_rec = priv->max_rec[phy_id]; - arp1394->sspd = priv->sspd[phy_id]; - arp1394->fifo_hi = htons (priv->fifo_hi[phy_id]); - arp1394->fifo_lo = htonl (priv->fifo_lo[phy_id]); - - return; -} - static int ether1394_change_mtu(struct net_device *dev, int new_mtu) { - if ((new_mtu < 68) || (new_mtu > ETHER1394_REGION_ADDR_LEN)) + struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv; + int phy_id = NODEID_TO_NODE(priv->host->node_id); + + if ((new_mtu < 68) || (new_mtu > (priv->maxpayload[phy_id] - + (sizeof(union eth1394_hdr) + + ETHER1394_GASP_OVERHEAD)))) return -EINVAL; dev->mtu = new_mtu; return 0; } -static inline void ether1394_register_limits (int nodeid, unsigned char max_rec, - unsigned char sspd, u64 eui, u16 fifo_hi, - u32 fifo_lo, struct eth1394_priv *priv) +static inline void ether1394_register_limits(int nodeid, u16 maxpayload, + unsigned char sspd, u64 eui, u64 fifo, + struct eth1394_priv *priv) { - int i; - if (nodeid < 0 || nodeid >= ALL_NODES) { ETH1394_PRINT_G (KERN_ERR, "Cannot register invalid nodeid %d\n", nodeid); return; } - priv->max_rec[nodeid] = max_rec; - priv->sspd[nodeid] = sspd; - priv->fifo_hi[nodeid] = fifo_hi; - priv->fifo_lo[nodeid] = fifo_lo; - priv->eui[nodeid] = eui; - - /* 63 is used for broadcasts to all hosts. It is equal to the - * minimum of all registered nodes. A registered node is one with - * a nonzero offset. Set the values rediculously high to start. We - * know we have atleast one to change the default to. */ - sspd = 0xff; - max_rec = 0xff; - for (i = 0; i < ALL_NODES; i++) { - if (!priv->fifo_hi && !priv->fifo_lo) continue; /* Unregistered */ - if (priv->max_rec[i] < max_rec) max_rec = priv->max_rec[i]; - if (priv->sspd[i] < sspd) sspd = priv->sspd[i]; - } + priv->maxpayload[nodeid] = maxpayload; + priv->sspd[nodeid] = sspd; + priv->fifo[nodeid] = fifo; + priv->eui[nodeid] = eui; - priv->max_rec[ALL_NODES] = max_rec; - priv->sspd[ALL_NODES] = sspd; + priv->maxpayload[ALL_NODES] = min(priv->maxpayload[ALL_NODES], maxpayload); + priv->sspd[ALL_NODES] = min(priv->sspd[ALL_NODES], sspd); return; } @@ -257,40 +311,63 @@ static void ether1394_reset_priv (struct net_device *dev, int set_mtu) { unsigned long flags; + int i; struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv; - int phy_id = NODEID_TO_NODE(priv->host->node_id); struct hpsb_host *host = priv->host; + int phy_id = NODEID_TO_NODE(host->node_id); + u64 guid = *((u64*)&(host->csr.rom[3])); + u16 maxpayload = 1 << (((be32_to_cpu(host->csr.rom[2]) >> 12) & 0xf) + 1); spin_lock_irqsave (&priv->lock, flags); /* Clear the speed/payload/offset tables */ - memset (priv->max_rec, 0, sizeof (priv->max_rec)); + memset (priv->maxpayload, 0, sizeof (priv->maxpayload)); memset (priv->sspd, 0, sizeof (priv->sspd)); - memset (priv->fifo_hi, 0, sizeof (priv->fifo_hi)); - memset (priv->fifo_lo, 0, sizeof (priv->fifo_lo)); + memset (priv->fifo, 0, sizeof (priv->fifo)); + +#if 0 +/* Compile this out to make testing of fragmented broadcast datagrams + * easier. */ + priv->sspd[ALL_NODES] = SPEED_MAX; + priv->maxpayload[ALL_NODES] = eth1394_speedto_maxpayload[SPEED_MAX]; +#else + priv->sspd[ALL_NODES] = SPEED_100; + priv->maxpayload[ALL_NODES] = eth1394_speedto_maxpayload[SPEED_100]; +#endif priv->bc_state = ETHER1394_BC_CHECK; /* Register our limits now */ - ether1394_register_limits (phy_id, (be32_to_cpu(host->csr.rom[2]) >> 12) & 0xf, - host->speed_map[(phy_id << 6) + phy_id], - (u64)(((u64)be32_to_cpu(host->csr.rom[3]) << 32) | - be32_to_cpu(host->csr.rom[4])), - ETHER1394_REGION_ADDR >> 32, - ETHER1394_REGION_ADDR & 0xffffffff, priv); - - /* We'll use our max_rec as the default mtu */ - if (set_mtu) - dev->mtu = (1 << (priv->max_rec[phy_id] + 1)) - /* mtu = max_rec - */ - (sizeof (union eth1394_hdr) + 8); /* (hdr + GASP) */ - - /* Set our hardware address while we're at it */ - *(nodeid_t *)dev->dev_addr = htons (host->node_id); + ether1394_register_limits(phy_id, maxpayload, + host->speed_map[(phy_id << 6) + phy_id], + guid, ETHER1394_REGION_ADDR, priv); + + /* We'll use our maxpayload as the default mtu */ + if (set_mtu) { + dev->mtu = priv->maxpayload[phy_id] - (sizeof(union eth1394_hdr) + + ETHER1394_GASP_OVERHEAD); + + /* Set our hardware address while we're at it */ + *(u64*)dev->dev_addr = guid; + *(u64*)dev->broadcast = ~0x0ULL; + } spin_unlock_irqrestore (&priv->lock, flags); -} -static int ether1394_tx (struct sk_buff *skb, struct net_device *dev); + for(i = 0; i < ALL_NODES; i++) { + struct list_head *lh, *n; + + spin_lock_irqsave(&priv->pdg[i].lock, flags); + if(!set_mtu) { + list_for_each_safe(lh, n, &priv->pdg[i].list) { + purge_partial_datagram(lh); + } + } + INIT_LIST_HEAD(&(priv->pdg[i].list)); + priv->pdg[i].sz = 0; + spin_unlock_irqrestore(&priv->pdg[i].lock, flags); + } +} /* This function is called by register_netdev */ static int ether1394_init_dev (struct net_device *dev) @@ -303,11 +380,20 @@ dev->tx_timeout = ether1394_tx_timeout; dev->change_mtu = ether1394_change_mtu; + dev->hard_header = ether1394_header; + dev->rebuild_header = ether1394_rebuild_header; + dev->hard_header_cache = ether1394_header_cache; + dev->header_cache_update= ether1394_header_cache_update; + dev->hard_header_parse = ether1394_header_parse; + dev->set_mac_address = ether1394_mac_addr; + /* Some constants */ dev->watchdog_timeo = ETHER1394_TIMEOUT; - dev->flags = IFF_BROADCAST; /* TODO: Support MCAP */ + dev->flags = IFF_BROADCAST; /* | IFF_MULTICAST someday */ dev->features = NETIF_F_NO_CSUM|NETIF_F_SG|NETIF_F_HIGHDMA|NETIF_F_FRAGLIST; - dev->addr_len = 2; + dev->addr_len = ETH1394_ALEN; + dev->hard_header_len = ETH1394_HLEN; + dev->type = ARPHRD_IEEE1394; ether1394_reset_priv (dev, 1); @@ -321,6 +407,7 @@ */ static void ether1394_add_host (struct hpsb_host *host) { + int i; struct host_info *hi = NULL; struct net_device *dev = NULL; struct eth1394_priv *priv; @@ -329,6 +416,9 @@ if (version_printed++ == 0) ETH1394_PRINT_G (KERN_INFO, "%s\n", version); + /* We should really have our own alloc_hpsbdev() function in + * net_init.c instead of calling the one for ethernet then hijacking + * it for ourselves. That way we'd be a real networking device. */ dev = alloc_etherdev(sizeof (struct eth1394_priv)); if (dev == NULL) @@ -343,6 +433,12 @@ priv->host = host; spin_lock_init(&priv->lock); + for(i = 0; i < ALL_NODES; i++) { + spin_lock_init(&priv->pdg[i].lock); + INIT_LIST_HEAD(&priv->pdg[i].list); + priv->pdg[i].sz = 0; + } + hi = hpsb_create_hostinfo(ð1394_highlevel, host, sizeof(*hi)); if (hi == NULL) @@ -360,10 +456,10 @@ hi->dev = dev; /* Ignore validity in hopes that it will be set in the future. It'll - * check it on transmit. */ + * be checked when the eth device is opened. */ priv->broadcast_channel = host->csr.broadcast_channel & 0x3f; - priv->iso = hpsb_iso_recv_init(host, 8 * 4096, 8, priv->broadcast_channel, + priv->iso = hpsb_iso_recv_init(host, 16 * 4096, 16, priv->broadcast_channel, 1, ether1394_iso); if (priv->iso == NULL) { priv->bc_state = ETHER1394_BC_CLOSED; @@ -372,7 +468,7 @@ out: if (dev != NULL) - kfree (dev); + kfree(dev); if (hi) hpsb_destroy_hostinfo(ð1394_highlevel, host); @@ -393,7 +489,7 @@ unregister_netdev (hi->dev); hpsb_iso_shutdown(priv->iso); - kfree (hi->dev); + kfree(hi->dev); } return; @@ -417,26 +513,140 @@ netif_wake_queue (dev); } +/****************************************** + * HW Header net device functions + ******************************************/ +/* These functions have been adapted from net/ethernet/eth.c */ + + +/* Create a fake MAC header for an arbitrary protocol layer. + * saddr=NULL means use device source address + * daddr=NULL means leave destination address (eg unresolved arp). */ +static int ether1394_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, void *daddr, void *saddr, + unsigned len) +{ + struct eth1394hdr *eth = (struct eth1394hdr *)skb_push(skb, ETH1394_HLEN); + + eth->h_proto = htons(type); + + if (dev->flags & (IFF_LOOPBACK|IFF_NOARP)) + { + memset(eth->h_dest, 0, dev->addr_len); + return(dev->hard_header_len); + } + + if(daddr) + { + memcpy(eth->h_dest,daddr,dev->addr_len); + return dev->hard_header_len; + } + + return -dev->hard_header_len; + +} + + +/* Rebuild the faked MAC header. This is called after an ARP + * (or in future other address resolution) has completed on this + * sk_buff. We now let ARP fill in the other fields. + * + * This routine CANNOT use cached dst->neigh! + * Really, it is used only when dst->neigh is wrong. + */ +static int ether1394_rebuild_header(struct sk_buff *skb) +{ + struct eth1394hdr *eth = (struct eth1394hdr *)skb->data; + struct net_device *dev = skb->dev; + + switch (eth->h_proto) + { +#ifdef CONFIG_INET + case __constant_htons(ETH_P_IP): + return arp_find((unsigned char*)ð->h_dest, skb); +#endif + default: + printk(KERN_DEBUG + "%s: unable to resolve type %X addresses.\n", + dev->name, (int)eth->h_proto); + break; + } + + return 0; +} + +static int ether1394_header_parse(struct sk_buff *skb, unsigned char *haddr) +{ + struct net_device *dev = skb->dev; + memcpy(haddr, dev->dev_addr, ETH1394_ALEN); + return ETH_ALEN; +} + + +static int ether1394_header_cache(struct neighbour *neigh, struct hh_cache *hh) +{ + unsigned short type = hh->hh_type; + struct eth1394hdr *eth = (struct eth1394hdr*)(((u8*)hh->hh_data) + 6); + struct net_device *dev = neigh->dev; + + if (type == __constant_htons(ETH_P_802_3)) { + return -1; + } + + eth->h_proto = type; + memcpy(eth->h_dest, neigh->ha, dev->addr_len); + + hh->hh_len = ETH1394_HLEN; + return 0; +} + +/* Called by Address Resolution module to notify changes in address. */ +static void ether1394_header_cache_update(struct hh_cache *hh, + struct net_device *dev, + unsigned char * haddr) +{ + memcpy(((u8*)hh->hh_data) + 6, haddr, dev->addr_len); +} + +static int ether1394_mac_addr(struct net_device *dev, void *p) +{ + if (netif_running(dev)) + return -EBUSY; + + /* Not going to allow setting the MAC address, we really need to use + * the real one suppliled by the hardware */ + return -EINVAL; + } + + + +/****************************************** + * Datagram reception code + ******************************************/ + /* Copied from net/ethernet/eth.c */ -static inline unsigned short ether1394_type_trans(struct sk_buff *skb, struct net_device *dev) +static inline u16 ether1394_type_trans(struct sk_buff *skb, + struct net_device *dev) { - struct ethhdr *eth; + struct eth1394hdr *eth; unsigned char *rawp; skb->mac.raw = skb->data; - skb_pull (skb, ETH_HLEN); - eth = skb->mac.ethernet; -#if 0 + skb_pull (skb, ETH1394_HLEN); + eth = (struct eth1394hdr*)skb->mac.raw; + if(*eth->h_dest & 1) { if(memcmp(eth->h_dest, dev->broadcast, dev->addr_len)==0) skb->pkt_type = PACKET_BROADCAST; +#if 0 else skb->pkt_type = PACKET_MULTICAST; +#endif } else { if(memcmp(eth->h_dest, dev->dev_addr, dev->addr_len)) skb->pkt_type = PACKET_OTHERHOST; } -#endif + if (ntohs (eth->h_proto) >= 1536) return eth->h_proto; @@ -450,102 +660,376 @@ /* Parse an encapsulated IP1394 header into an ethernet frame packet. * We also perform ARP translation here, if need be. */ -static inline unsigned short ether1394_parse_encap (struct sk_buff *skb, struct net_device *dev, - nodeid_t srcid, nodeid_t destid) +static inline u16 ether1394_parse_encap(struct sk_buff *skb, + struct net_device *dev, + nodeid_t srcid, nodeid_t destid, + u16 ether_type) { - union eth1394_hdr *hdr = (union eth1394_hdr *)skb->data; - unsigned char src_hw[ETH_ALEN], dest_hw[ETH_ALEN]; + struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv; + u64 dest_hw; unsigned short ret = 0; /* Setup our hw addresses. We use these to build the * ethernet header. */ - *(u16 *)dest_hw = htons(destid); - *(u16 *)src_hw = htons(srcid); - - /* Remove the encapsulation header */ - hdr->words.word1 = ntohs(hdr->words.word1); - skb_pull (skb, hdr_type_len[hdr->common.lf]); + if(destid == (LOCAL_BUS | ALL_NODES)) + dest_hw = ~0ULL; /* broadcast */ + else + dest_hw = priv->eui[NODEID_TO_NODE(destid)]; /* If this is an ARP packet, convert it. First, we want to make * use of some of the fields, since they tell us a little bit * about the sending machine. */ - if (hdr->uf.ether_type == __constant_htons (ETH_P_ARP)) { + if (ether_type == __constant_htons (ETH_P_ARP)) { unsigned long flags; - u16 phy_id = NODEID_TO_NODE(srcid); - struct eth1394_priv *priv = - (struct eth1394_priv *)dev->priv; - struct eth1394_arp arp1394; + struct eth1394_arp *arp1394 = (struct eth1394_arp*)skb->data; struct arphdr *arp = (struct arphdr *)skb->data; unsigned char *arp_ptr = (unsigned char *)(arp + 1); + u64 fifo_addr = (u64)ntohs(arp1394->fifo_hi) << 32 | + ntohl(arp1394->fifo_lo); + u8 host_max_rec = (be32_to_cpu(priv->host->csr.rom[2]) >> + 12) & 0xf; + u8 max_rec = min(host_max_rec, (u8)(arp1394->max_rec)); + u16 maxpayload = min(eth1394_speedto_maxpayload[arp1394->sspd], + (u16)(1 << (max_rec + 1))); - memcpy (&arp1394, arp, sizeof (struct eth1394_arp)); /* Update our speed/payload/fifo_offset table */ spin_lock_irqsave (&priv->lock, flags); - ether1394_register_limits (phy_id, arp1394.max_rec, arp1394.sspd, - le64_to_cpu (arp1394.s_uniq_id), - ntohs (arp1394.fifo_hi), - ntohl (arp1394.fifo_lo), priv); + ether1394_register_limits(NODEID_TO_NODE(srcid), maxpayload, + arp1394->sspd, arp1394->s_uniq_id, + fifo_addr, priv); spin_unlock_irqrestore (&priv->lock, flags); -#define PROCESS_MEMBER(ptr,val,len) \ - memcpy (ptr, val, len); ptr += len - PROCESS_MEMBER (arp_ptr, src_hw, dev->addr_len); - PROCESS_MEMBER (arp_ptr, &arp1394.sip, 4); - PROCESS_MEMBER (arp_ptr, dest_hw, dev->addr_len); - PROCESS_MEMBER (arp_ptr, &arp1394.tip, 4); -#undef PROCESS_MEMBER - - arp->ar_hln = dev->addr_len; - arp->ar_hrd = __constant_htons (ARPHRD_ETHER); - - skb_trim (skb, sizeof (struct arphdr) + 2*(dev->addr_len+4)); + /* Now that we're done with the 1394 specific stuff, we'll + * need to alter some of the data. Believe it or not, all + * that needs to be done is sender_IP_address needs to be + * moved, the destination hardware address get stuffed + * in and the hardware address length set to 8. + * + * IMPORTANT: The code below overwrites 1394 specific data + * needed above data so keep the call to + * ether1394_register_limits() before munging the data for the + * higher level IP stack. */ + + arp->ar_hln = 8; + arp_ptr += arp->ar_hln; /* skip over sender unique id */ + *(u32*)arp_ptr = arp1394->sip; /* move sender IP addr */ + arp_ptr += arp->ar_pln; /* skip over sender IP addr */ + + if(arp->ar_op == 1) + /* just set ARP req target unique ID to 0 */ + memset(arp_ptr, 0, ETH1394_ALEN); + else + memcpy(arp_ptr, dev->dev_addr, ETH1394_ALEN); } /* Now add the ethernet header. */ - if (dev->hard_header (skb, dev, __constant_ntohs (hdr->uf.ether_type), - dest_hw, src_hw, skb->len) >= 0) + if (dev->hard_header (skb, dev, __constant_ntohs (ether_type), + &dest_hw, NULL, skb->len) >= 0) ret = ether1394_type_trans(skb, dev); return ret; } +static inline int fragment_overlap(struct list_head *frag_list, int offset, int len) +{ + struct list_head *lh; + struct fragment_info *fi; + + list_for_each(lh, frag_list) { + fi = list_entry(lh, struct fragment_info, list); + + if( ! ((offset > (fi->offset + fi->len - 1)) || + ((offset + len - 1) < fi->offset))) + return 1; + } + return 0; +} + +static inline struct list_head *find_partial_datagram(struct list_head *pdgl, int dgl) +{ + struct list_head *lh; + struct partial_datagram *pd; + + list_for_each(lh, pdgl) { + pd = list_entry(lh, struct partial_datagram, list); + if(pd->dgl == dgl) + return lh; + } + return NULL; +} + +/* Assumes that new fragment does not overlap any existing fragments */ +static inline int new_fragment(struct list_head *frag_info, int offset, int len) +{ + struct list_head *lh; + struct fragment_info *fi, *fi2, *new; + + list_for_each(lh, frag_info) { + fi = list_entry(lh, struct fragment_info, list); + if((fi->offset + fi->len) == offset) { + /* The new fragment can be tacked on to the end */ + fi->len += len; + /* Did the new fragment plug a hole? */ + fi2 = list_entry(lh->next, struct fragment_info, list); + if((fi->offset + fi->len) == fi2->offset) { + /* glue fragments together */ + fi->len += fi2->len; + list_del(lh->next); + kfree(fi2); + } + return 0; + } else if((offset + len) == fi->offset) { + /* The new fragment can be tacked on to the beginning */ + fi->offset = offset; + fi->len += len; + /* Did the new fragment plug a hole? */ + fi2 = list_entry(lh->prev, struct fragment_info, list); + if((fi2->offset + fi2->len) == fi->offset) { + /* glue fragments together */ + fi2->len += fi->len; + list_del(lh); + kfree(fi); + } + return 0; + } else if(offset > (fi->offset + fi->len)) { + break; + } else if ((offset + len) < fi->offset) { + lh = lh->prev; + break; + } + } + + new = kmalloc(sizeof(struct fragment_info), GFP_ATOMIC); + if(!new) + return -ENOMEM; + + new->offset = offset; + new->len = len; + + list_add(&new->list, lh); + + return 0; +} + +static inline int new_partial_datagram(struct net_device *dev, + struct list_head *pdgl, int dgl, + int dg_size, char *frag_buf, + int frag_off, int frag_len) +{ + struct partial_datagram *new; + + new = kmalloc(sizeof(struct partial_datagram), GFP_ATOMIC); + if(!new) + return -ENOMEM; + + INIT_LIST_HEAD(&new->frag_info); + + if(new_fragment(&new->frag_info, frag_off, frag_len) < 0) { + kfree(new); + return -ENOMEM; + } + + new->dgl = dgl; + new->dg_size = dg_size; + + new->skb = dev_alloc_skb(dg_size + dev->hard_header_len + 15); + if(!new->skb) { + struct fragment_info *fi = list_entry(new->frag_info.next, + struct fragment_info, + list); + kfree(fi); + kfree(new); + return -ENOMEM; + } + + skb_reserve(new->skb, (dev->hard_header_len + 15) & ~15); + new->pbuf = skb_put(new->skb, dg_size); + memcpy(new->pbuf + frag_off, frag_buf, frag_len); + + list_add(&new->list, pdgl); + + return 0; +} + +static inline int update_partial_datagram(struct list_head *pdgl, struct list_head *lh, + char *frag_buf, int frag_off, int frag_len) +{ + struct partial_datagram *pd = list_entry(lh, struct partial_datagram, list); + + if(new_fragment(&pd->frag_info, frag_off, frag_len) < 0) { + return -ENOMEM; + } + + memcpy(pd->pbuf + frag_off, frag_buf, frag_len); + + /* Move list entry to beginnig of list so that oldest partial + * datagrams percolate to the end of the list */ + list_del(lh); + list_add(lh, pdgl); + + return 0; +} + +static inline void purge_partial_datagram(struct list_head *old) +{ + struct partial_datagram *pd = list_entry(old, struct partial_datagram, list); + struct list_head *lh, *n; + + list_for_each_safe(lh, n, &pd->frag_info) { + struct fragment_info *fi = list_entry(lh, struct fragment_info, list); + list_del(lh); + kfree(fi); + } + list_del(old); + kfree_skb(pd->skb); + kfree(pd); +} + +static inline int is_datagram_complete(struct list_head *lh, int dg_size) +{ + struct partial_datagram *pd = list_entry(lh, struct partial_datagram, list); + struct fragment_info *fi = list_entry(pd->frag_info.next, + struct fragment_info, list); + + return (fi->len == dg_size); +} + /* Packet reception. We convert the IP1394 encapsulation header to an * ethernet header, and fill it with some of our other fields. This is * an incoming packet from the 1394 bus. */ -static int ether1394_write (struct hpsb_host *host, int srcid, int destid, - quadlet_t *data, u64 addr, unsigned int len, u16 fl) +static int ether1394_data_handler(struct net_device *dev, int srcid, int destid, + char *buf, int len) { struct sk_buff *skb; - char *buf = (char *)data; unsigned long flags; - struct host_info *hi = hpsb_get_hostinfo(ð1394_highlevel, host); - struct net_device *dev; struct eth1394_priv *priv; + union eth1394_hdr *hdr = (union eth1394_hdr *)buf; + u16 ether_type = 0; /* initialized to clear warning */ + int hdr_len; - if (hi == NULL) { - ETH1394_PRINT_G (KERN_ERR, "Could not find net device for host %p\n", - host); - return RCODE_ADDRESS_ERROR; - } + priv = (struct eth1394_priv *)dev->priv; - dev = hi->dev; + /* First, did we receive a fragmented or unfragmented datagram? */ + hdr->words.word1 = ntohs(hdr->words.word1); - priv = (struct eth1394_priv *)dev->priv; + hdr_len = hdr_type_len[hdr->common.lf]; - /* A packet has been received by the ieee1394 bus. Build an skbuff - * around it so we can pass it to the high level network layer. */ + if(hdr->common.lf == ETH1394_HDR_LF_UF) { + /* An unfragmented datagram has been received by the ieee1394 + * bus. Build an skbuff around it so we can pass it to the + * high level network layer. */ - skb = dev_alloc_skb (len + dev->hard_header_len + 15); - if (!skb) { - HPSB_PRINT (KERN_ERR, "ether1394 rx: low on mem\n"); - priv->stats.rx_dropped++; - return RCODE_ADDRESS_ERROR; - } + skb = dev_alloc_skb(len + dev->hard_header_len + 15); + if (!skb) { + HPSB_PRINT (KERN_ERR, "ether1394 rx: low on mem\n"); + priv->stats.rx_dropped++; + return -1; + } + skb_reserve(skb, (dev->hard_header_len + 15) & ~15); + memcpy(skb_put(skb, len - hdr_len), buf + hdr_len, len - hdr_len); + ether_type = hdr->uf.ether_type; + } else { + /* A datagram fragment has been received, now the fun begins. */ - skb_reserve(skb, (dev->hard_header_len + 15) & ~15); + struct list_head *pdgl, *lh; + struct partial_datagram *pd; + int fg_off; + int fg_len = len - hdr_len; + int dg_size; + int dgl; + int retval; + int sid = NODEID_TO_NODE(srcid); + struct pdg_list *pdg = &(priv->pdg[sid]); + + hdr->words.word3 = ntohs(hdr->words.word3); + /* The 4th header word is reserved so no need to do ntohs() */ + + if(hdr->common.lf == ETH1394_HDR_LF_FF) { + ether_type = hdr->ff.ether_type; + dgl = hdr->ff.dgl; + dg_size = hdr->ff.dg_size; + fg_off = 0; + } else { + hdr->words.word2 = ntohs(hdr->words.word2); + dgl = hdr->sf.dgl; + dg_size = hdr->sf.dg_size; + fg_off = hdr->sf.fg_off; + } + spin_lock_irqsave(&pdg->lock, flags); - memcpy (skb_put (skb, len), buf, len); + pdgl = &(pdg->list); + lh = find_partial_datagram(pdgl, dgl); + + if(lh == NULL) { + if(pdg->sz == max_partial_datagrams) { + /* remove the oldest */ + purge_partial_datagram(pdgl->prev); + pdg->sz--; + } + + retval = new_partial_datagram(dev, pdgl, dgl, dg_size, + buf + hdr_len, fg_off, + fg_len); + if(retval < 0) { + spin_unlock_irqrestore(&pdg->lock, flags); + goto bad_proto; + } + pdg->sz++; + lh = find_partial_datagram(pdgl, dgl); + } else { + struct partial_datagram *pd; + + pd = list_entry(lh, struct partial_datagram, list); + + if(fragment_overlap(&pd->frag_info, fg_off, fg_len)) { + /* Overlapping fragments, obliterate old + * datagram and start new one. */ + purge_partial_datagram(lh); + retval = new_partial_datagram(dev, pdgl, dgl, + dg_size, + buf + hdr_len, + fg_off, fg_len); + if(retval < 0) { + pdg->sz--; + spin_unlock_irqrestore(&pdg->lock, flags); + goto bad_proto; + } + } else { + retval = update_partial_datagram(pdgl, lh, + buf + hdr_len, + fg_off, fg_len); + if(retval < 0) { + /* Couldn't save off fragment anyway + * so might as well obliterate the + * datagram now. */ + purge_partial_datagram(lh); + pdg->sz--; + spin_unlock_irqrestore(&pdg->lock, flags); + goto bad_proto; + } + } /* fragment overlap */ + } /* new datagram or add to existing one */ + + pd = list_entry(lh, struct partial_datagram, list); + + if(hdr->common.lf == ETH1394_HDR_LF_FF) { + pd->ether_type = ether_type; + } + + if(is_datagram_complete(lh, dg_size)) { + ether_type = pd->ether_type; + pdg->sz--; + skb = skb_get(pd->skb); + purge_partial_datagram(lh); + spin_unlock_irqrestore(&pdg->lock, flags); + } else { + /* Datagram is not complete, we're done for the + * moment. */ + spin_unlock_irqrestore(&pdg->lock, flags); + return 0; + } + } /* unframgented datagram or fragmented one */ /* Write metadata, and then pass to the receive level */ skb->dev = dev; @@ -555,18 +1039,19 @@ * converting to an ethernet frame header, aswell as arp * conversion if needed. ARP conversion is easier in this * direction, since we are using ethernet as our backend. */ - skb->protocol = ether1394_parse_encap (skb, dev, srcid, destid); + skb->protocol = ether1394_parse_encap(skb, dev, srcid, destid, + ether_type); - spin_lock_irqsave (&priv->lock, flags); - if (!skb->protocol) { + + spin_lock_irqsave(&priv->lock, flags); + if(!skb->protocol) { priv->stats.rx_errors++; priv->stats.rx_dropped++; dev_kfree_skb_any(skb); goto bad_proto; } - netif_stop_queue(dev); - if (netif_rx (skb) == NET_RX_DROP) { + if(netif_rx(skb) == NET_RX_DROP) { priv->stats.rx_errors++; priv->stats.rx_dropped++; goto bad_proto; @@ -577,20 +1062,36 @@ priv->stats.rx_bytes += skb->len; bad_proto: - netif_start_queue(dev); - spin_unlock_irqrestore (&priv->lock, flags); + if(netif_queue_stopped(dev)) + netif_wake_queue(dev); + spin_unlock_irqrestore(&priv->lock, flags); dev->last_rx = jiffies; - return RCODE_COMPLETE; + return 0; +} + +static int ether1394_write(struct hpsb_host *host, int srcid, int destid, + quadlet_t *data, u64 addr, unsigned int len, u16 flags) +{ + struct host_info *hi = hpsb_get_hostinfo(ð1394_highlevel, host); + + if(hi == NULL) { + ETH1394_PRINT_G(KERN_ERR, "Could not find net device for host %s\n", + host->driver->name); + return RCODE_ADDRESS_ERROR; + } + + if(ether1394_data_handler(hi->dev, srcid, destid, (char*)data, len)) + return RCODE_ADDRESS_ERROR; + else + return RCODE_COMPLETE; } static void ether1394_iso(struct hpsb_iso *iso) { - struct sk_buff *skb; quadlet_t *data; char *buf; - unsigned long flags; struct host_info *hi = hpsb_get_hostinfo(ð1394_highlevel, iso->host); struct net_device *dev; struct eth1394_priv *priv; @@ -600,9 +1101,9 @@ int i; int nready; - if (hi == NULL) { - ETH1394_PRINT_G (KERN_ERR, "Could not find net device for host %s\n", - iso->host->driver->name); + if(hi == NULL) { + ETH1394_PRINT_G(KERN_ERR, "Could not find net device for host %s\n", + iso->host->driver->name); return; } @@ -623,186 +1124,328 @@ priv = (struct eth1394_priv *)dev->priv; - if (info->channel != priv->broadcast_channel || - specifier_id != ETHER1394_GASP_SPECIFIER_ID) { + if(info->channel != (iso->host->csr.broadcast_channel & 0x3f) || + specifier_id != ETHER1394_GASP_SPECIFIER_ID) { /* This packet is not for us */ continue; } + ether1394_data_handler(dev, source_id, LOCAL_BUS | ALL_NODES, + buf, len); + } - /* A packet has been received by the ieee1394 bus. Build an skbuff - * around it so we can pass it to the high level network layer. */ - skb = dev_alloc_skb (len + dev->hard_header_len + 15); - if (!skb) { - HPSB_PRINT (KERN_ERR, "ether1394 rx: low on mem\n"); - priv->stats.rx_dropped++; - break; - } + hpsb_iso_recv_release_packets(iso, i); - skb_reserve(skb, (dev->hard_header_len + 15) & ~15); + dev->last_rx = jiffies; +} - memcpy (skb_put (skb, len), buf, len); +/****************************************** + * Datagram transmission code + ******************************************/ + +/* Convert a standard ARP packet to 1394 ARP. The first 8 bytes (the entire + * arphdr) is the same format as the ip1394 header, so they overlap. The rest + * needs to be munged a bit. The remainder of the arphdr is formatted based + * on hwaddr len and ipaddr len. We know what they'll be, so it's easy to + * judge. + * + * Now that the EUI is used for the hardware address all we need to do to make + * this work for 1394 is to insert 2 quadlets that contain max_rec size, + * speed, and unicast FIFO address information between the sender_unique_id + * and the IP addresses. + */ +static inline void ether1394_arp_to_1394arp(struct sk_buff *skb, + struct net_device *dev) +{ + struct eth1394_priv *priv = (struct eth1394_priv *)(dev->priv); + u16 phy_id = NODEID_TO_NODE(priv->host->node_id); - /* Write metadata, and then pass to the receive level */ - skb->dev = dev; - skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */ - - /* Parse the encapsulation header. This actually does the job of - * converting to an ethernet frame header, aswell as arp - * conversion if needed. ARP conversion is easier in this - * direction, since we are using ethernet as our backend. */ - skb->protocol = ether1394_parse_encap (skb, dev, source_id, - LOCAL_BUS | ALL_NODES); + struct arphdr *arp = (struct arphdr *)skb->data; + unsigned char *arp_ptr = (unsigned char *)(arp + 1); + struct eth1394_arp *arp1394 = (struct eth1394_arp *)skb->data; - spin_lock_irqsave (&priv->lock, flags); - if (!skb->protocol) { - priv->stats.rx_errors++; - priv->stats.rx_dropped++; - dev_kfree_skb_any(skb); - goto bad_proto; - } + /* Believe it or not, all that need to happen is sender IP get moved + * and set hw_addr_len, max_rec, sspd, fifo_hi and fifo_lo. */ + arp1394->hw_addr_len = 16; + arp1394->sip = *(u32*)(arp_ptr + ETH1394_ALEN); + arp1394->max_rec = (be32_to_cpu(priv->host->csr.rom[2]) >> 12) & 0xf; + arp1394->sspd = priv->sspd[phy_id]; + arp1394->fifo_hi = htons (priv->fifo[phy_id] >> 32); + arp1394->fifo_lo = htonl (priv->fifo[phy_id] & ~0x0); - netif_stop_queue(dev); - if (netif_rx (skb) == NET_RX_DROP) { - priv->stats.rx_errors++; - priv->stats.rx_dropped++; - goto bad_proto; - } + return; +} - /* Statistics */ - priv->stats.rx_packets++; - priv->stats.rx_bytes += skb->len; +/* We need to encapsulate the standard header with our own. We use the + * ethernet header's proto for our own. */ +static inline unsigned int ether1394_encapsulate_prep(unsigned int max_payload, + int proto, + union eth1394_hdr *hdr, + u16 dg_size, u16 dgl) +{ + unsigned int adj_max_payload = max_payload - hdr_type_len[ETH1394_HDR_LF_UF]; - bad_proto: - spin_unlock_irqrestore (&priv->lock, flags); + /* Does it all fit in one packet? */ + if(dg_size <= adj_max_payload) { + hdr->uf.lf = ETH1394_HDR_LF_UF; + hdr->uf.ether_type = proto; + } else { + hdr->ff.lf = ETH1394_HDR_LF_FF; + hdr->ff.ether_type = proto; + hdr->ff.dg_size = dg_size; + hdr->ff.dgl = dgl; + adj_max_payload = max_payload - hdr_type_len[ETH1394_HDR_LF_FF]; } + return((dg_size + (adj_max_payload - 1)) / adj_max_payload); +} - hpsb_iso_recv_release_packets(iso, i); +static inline unsigned int ether1394_encapsulate(struct sk_buff *skb, + unsigned int max_payload, + union eth1394_hdr *hdr) +{ + union eth1394_hdr *bufhdr; + int ftype = hdr->common.lf; + int hdrsz = hdr_type_len[ftype]; + unsigned int adj_max_payload = max_payload - hdrsz; + + switch(ftype) { + case ETH1394_HDR_LF_UF: + bufhdr = (union eth1394_hdr *)skb_push(skb, hdrsz); + bufhdr->words.word1 = htons(hdr->words.word1); + bufhdr->words.word2 = hdr->words.word2; + break; - netif_start_queue(dev); - - dev->last_rx = jiffies; + case ETH1394_HDR_LF_FF: + bufhdr = (union eth1394_hdr *)skb_push(skb, hdrsz); + bufhdr->words.word1 = htons(hdr->words.word1); + bufhdr->words.word2 = hdr->words.word2; + bufhdr->words.word3 = htons(hdr->words.word3); + bufhdr->words.word4 = 0; + + /* Set frag type here for future interior fragments */ + hdr->common.lf = ETH1394_HDR_LF_IF; + hdr->sf.fg_off = 0; + break; + + default: + hdr->sf.fg_off += adj_max_payload; + bufhdr = (union eth1394_hdr *)skb_pull(skb, adj_max_payload); + if(max_payload >= skb->len) + hdr->common.lf = ETH1394_HDR_LF_LF; + bufhdr->words.word1 = htons(hdr->words.word1); + bufhdr->words.word2 = htons(hdr->words.word2); + bufhdr->words.word3 = htons(hdr->words.word3); + bufhdr->words.word4 = 0; + } - return; + return min(max_payload, skb->len); +} + +static inline struct hpsb_packet *ether1394_alloc_common_packet(struct hpsb_host *host) +{ + struct hpsb_packet *p; + + p = alloc_hpsb_packet(0); + if(p) { + p->host = host; + p->data = NULL; + p->generation = get_hpsb_generation(host); + p->type = hpsb_async; + } + return p; } +static inline int ether1394_prep_write_packet(struct hpsb_packet *p, + struct hpsb_host *host, + nodeid_t node, u64 addr, + void * data, int tx_len) +{ + p->node_id = node; + p->data = NULL; + + p->tcode = TCODE_WRITEB; + p->header[1] = (host->node_id << 16) | (addr >> 32); + p->header[2] = addr & 0xffffffff; + + p->header_size = 16; + p->expect_response = 1; + + if(hpsb_get_tlabel(p, !in_interrupt())) { + ETH1394_PRINT_G(KERN_ERR, "No more tlabels left"); + return -1; + } + p->header[0] = (p->node_id << 16) | (p->tlabel << 10) + | (1 << 8) | (TCODE_WRITEB << 4); + + p->header[3] = tx_len << 16; + p->data_size = tx_len + (tx_len % 4 ? 4 - (tx_len % 4) : 0); + p->data = (quadlet_t*)data; -/* This function is our scheduled write */ -static void hpsb_write_sched (void *__ptask) + return 0; +} + +static inline void ether1394_prep_gasp_packet(struct hpsb_packet *p, + struct eth1394_priv *priv, + struct sk_buff *skb, int length) { - struct packet_task *ptask = (struct packet_task *)__ptask; - struct sk_buff *skb = ptask->skb; - struct net_device *dev = ptask->skb->dev; - struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv; - unsigned long flags; - int status; - - if (ptask->tx_type == ETH1394_GASP) { - status = hpsb_send_gasp(priv->host, priv->broadcast_channel, - get_hpsb_generation(priv->host), - (quadlet_t *)skb->data, skb->len, - ETHER1394_GASP_SPECIFIER_ID, - ETHER1394_GASP_VERSION); + p->header_size = 4; + p->tcode = TCODE_STREAM_DATA; + + p->header[0] = (length << 16) | (3 << 14) + | ((priv->broadcast_channel) << 8) + | (TCODE_STREAM_DATA << 4); + p->data_size = length; + p->data = ((quadlet_t*)skb->data) - 2; + p->data[0] = cpu_to_be32((priv->host->node_id << 16) | + ETHER1394_GASP_SPECIFIER_ID_HI); + p->data[1] = cpu_to_be32((ETHER1394_GASP_SPECIFIER_ID_LO << 24) | + ETHER1394_GASP_VERSION); + + /* Setting the node id to ALL_NODES (not LOCAL_BUS | ALL_NODES) + * prevents hpsb_send_packet() from setting the speed to an arbitrary + * value based on packet->node_id if packet->node_id is not set. */ + p->node_id = ALL_NODES; + p->speed_code = priv->sspd[ALL_NODES]; +} + +static inline void ether1394_free_packet(struct hpsb_packet *packet) +{ + packet->data = NULL; + free_hpsb_packet(packet); +} + +static void ether1394_complete_cb(void *__ptask); +static int ether1394_send_packet(struct packet_task *ptask, unsigned int tx_len) +{ + struct eth1394_priv *priv = ptask->priv; + struct hpsb_packet *packet; + + packet = ether1394_alloc_common_packet(priv->host); + if(!packet) + return -1; + + if(ptask->tx_type == ETH1394_GASP) { + int length = tx_len + (2 * sizeof(quadlet_t)); + + ether1394_prep_gasp_packet(packet, priv, ptask->skb, length); + } else { - status = hpsb_write(priv->host, ptask->dest_node, - get_hpsb_generation(priv->host), - ptask->addr, (quadlet_t *)skb->data, - skb->len); + if(ether1394_prep_write_packet(packet, priv->host, + ptask->dest_node, + ptask->addr, ptask->skb->data, + tx_len)) + goto fail; } + ptask->packet = packet; + hpsb_set_packet_complete_task(ptask->packet, ether1394_complete_cb, + ptask); + + if(hpsb_send_packet(packet)) { + return 0; + } +fail: + return -1; +} + +/* Task function to be run when a datagram transmission is completed */ +static inline void ether1394_dg_complete(struct packet_task *ptask, int fail) +{ + struct sk_buff *skb = ptask->skb; + struct net_device *dev = skb->dev; + struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv; + unsigned long flags; + /* Statistics */ - spin_lock_irqsave (&priv->lock, flags); - if (!status) { - priv->stats.tx_bytes += skb->len; - priv->stats.tx_packets++; - } else { - //printk("Failed in hpsb_write_sched\n"); + if(fail) { + spin_lock_irqsave(&priv->lock, flags); priv->stats.tx_dropped++; priv->stats.tx_errors++; - if (netif_queue_stopped (dev)) - netif_wake_queue (dev); + spin_unlock_irqrestore(&priv->lock, flags); + } else { + spin_lock_irqsave(&priv->lock, flags); + priv->stats.tx_bytes += skb->len; + priv->stats.tx_packets++; + spin_unlock_irqrestore(&priv->lock, flags); } - spin_unlock_irqrestore (&priv->lock, flags); - dev->trans_start = jiffies; - dev_kfree_skb(skb); + dev_kfree_skb_any(skb); kmem_cache_free(packet_task_cache, ptask); +} - return; + +/* Callback for when a packet has been sent and the status of that packet is + * known */ +static void ether1394_complete_cb(void *__ptask) +{ + struct packet_task *ptask = (struct packet_task *)__ptask; + struct hpsb_packet *packet = ptask->packet; + int fail = 0; + + if(packet->tcode != TCODE_STREAM_DATA) { + fail = hpsb_packet_success(packet); + hpsb_free_tlabel(packet); + } + + ether1394_free_packet(packet); + + ptask->outstanding_pkts--; + if(ptask->outstanding_pkts > 0 && !fail) + { + int tx_len; + + /* Add the encapsulation header to the fragment */ + tx_len = ether1394_encapsulate(ptask->skb, ptask->max_payload, + &ptask->hdr); + if(ether1394_send_packet(ptask, tx_len)) + ether1394_dg_complete(ptask, 1); + } else { + ether1394_dg_complete(ptask, fail); + } } + + /* Transmit a packet (called by kernel) */ static int ether1394_tx (struct sk_buff *skb, struct net_device *dev) { - int kmflags = in_interrupt () ? GFP_ATOMIC : GFP_KERNEL; - struct ethhdr *eth; + int kmflags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL; + struct eth1394hdr *eth; struct eth1394_priv *priv = (struct eth1394_priv *)dev->priv; int proto; unsigned long flags; nodeid_t dest_node; - u64 addr; - struct packet_task *ptask = NULL; + eth1394_tx_type tx_type; int ret = 0; + unsigned int tx_len; + unsigned int max_payload; + u16 dg_size; + u16 dgl; + struct packet_task *ptask; + struct node_entry *ne; + + ptask = kmem_cache_alloc(packet_task_cache, kmflags); + if(ptask == NULL) { + ret = -ENOMEM; + goto fail; + } spin_lock_irqsave (&priv->lock, flags); if (priv->bc_state == ETHER1394_BC_CLOSED) { ETH1394_PRINT(KERN_ERR, dev->name, - "Cannot send packet, no broadcast channel available."); + "Cannot send packet, no broadcast channel available.\n"); ret = -EAGAIN; + spin_unlock_irqrestore (&priv->lock, flags); goto fail; } - /* First time sending? Need a broadcast channel for ARP and for - * listening on */ if (priv->bc_state == ETHER1394_BC_CHECK) { - quadlet_t bc; - - /* Get the local copy of the broadcast channel and check its - * validity (the IRM should validate it for us) */ - - bc = priv->host->csr.broadcast_channel; - - if ((bc & 0xc0000000) != 0xc0000000) { - /* broadcast channel not validated yet */ - ETH1394_PRINT(KERN_WARNING, dev->name, - "Error BROADCAST_CHANNEL register valid " - "bit not set, can't send IP traffic\n"); - hpsb_iso_shutdown(priv->iso); - priv->bc_state = ETHER1394_BC_CLOSED; - ret = -EAGAIN; + if(ether1394_init_bc(dev)) { spin_unlock_irqrestore (&priv->lock, flags); goto fail; } - if (priv->broadcast_channel != (bc & 0x3f)) { - /* This really shouldn't be possible, but just in case - * the IEEE 1394 spec changes regarding broadcast - * channels in the future. */ - hpsb_iso_shutdown(priv->iso); - - priv->broadcast_channel = bc & 0x3f; - ETH1394_PRINT(KERN_WARNING, dev->name, - "Changing to broadcast channel %d...\n", - priv->broadcast_channel); - - priv->iso = hpsb_iso_recv_init(priv->host, 8 * 4096, - 8, priv->broadcast_channel, - 1, ether1394_iso); - if (priv->iso == NULL) { - ret = -EAGAIN; - goto fail; - } - } - if (hpsb_iso_recv_start(priv->iso, -1, (1 << 3), -1) < 0) { - ETH1394_PRINT(KERN_ERR, dev->name, - "Could not start async reception\n"); - hpsb_iso_shutdown(priv->iso); - priv->bc_state = ETHER1394_BC_CLOSED; - ret = -EAGAIN; - spin_unlock_irqrestore (&priv->lock, flags); - goto fail; - } - priv->bc_state = ETHER1394_BC_OPENED; } + spin_unlock_irqrestore (&priv->lock, flags); if ((skb = skb_share_check (skb, kmflags)) == NULL) { @@ -810,66 +1453,113 @@ goto fail; } - /* Get rid of the ethernet header, but save a pointer */ - eth = (struct ethhdr *)skb->data; - skb_pull (skb, ETH_HLEN); - - /* Save the destination id, and proto for our encapsulation, then - * toss the ethernet header aside like the cheap whore it is. */ - dest_node = ntohs (*(nodeid_t *)(eth->h_dest)); + /* Get rid of the fake eth1394 header, but save a pointer */ + eth = (struct eth1394hdr*)skb->data; + skb_pull(skb, ETH1394_HLEN); + + ne = hpsb_guid_get_entry(be64_to_cpu(*(u64*)eth->h_dest)); + if(!ne) + dest_node = LOCAL_BUS | ALL_NODES; + else + dest_node = ne->nodeid; + proto = eth->h_proto; /* If this is an ARP packet, convert it */ if (proto == __constant_htons (ETH_P_ARP)) ether1394_arp_to_1394arp (skb, dev); - ptask = kmem_cache_alloc(packet_task_cache, kmflags); - if (ptask == NULL) { - ret = -ENOMEM; - goto fail; + max_payload = priv->maxpayload[NODEID_TO_NODE(dest_node)]; + + /* This check should be unnecessary, but we'll keep it for safety for + * a while longer. */ + if(max_payload < 512) { + ETH1394_PRINT(KERN_WARNING, dev->name, + "max_payload too small: %d (setting to 512)\n", + max_payload); + max_payload = 512; } - /* Now add our encapsulation header */ - ether1394_encapsulate (skb, dev, proto, ptask); + /* Set the transmission type for the packet. ARP packets and IP + * broadcast packets are sent via GASP, however, we cheat a little bit + * when detecting IP broadcast packets. This will need to change when + * we switch from using node id for the hardware address to the EUI + * which we should be using instead. IP multicast is not yet + * supported. */ + if((memcmp(eth->h_dest, dev->broadcast, ETH1394_ALEN) == 0) || + (proto == __constant_htons(ETH_P_ARP))) { + tx_type = ETH1394_GASP; + max_payload -= ETHER1394_GASP_OVERHEAD; + } else { + tx_type = ETH1394_WRREQ; + } - /* TODO: The above encapsulate function needs to recognize when a - * packet needs to be split for a specified node. It should create - * a list of skb's that we could then iterate over for the below - * call to schedule our writes. */ - - /* XXX: Right now we accept that we don't exactly follow RFC. When - * we do, we will send ARP requests via GASP format, and so we won't - * need this hack. */ + dg_size = skb->len; spin_lock_irqsave (&priv->lock, flags); - addr = (u64)priv->fifo_hi[NODEID_TO_NODE(dest_node)] << 32 | - priv->fifo_lo[NODEID_TO_NODE(dest_node)]; + dgl = priv->dgl[NODEID_TO_NODE(dest_node)]; + if(max_payload < dg_size + hdr_type_len[ETH1394_HDR_LF_UF]) + priv->dgl[NODEID_TO_NODE(dest_node)]++; spin_unlock_irqrestore (&priv->lock, flags); - if (!addr) - addr = ETHER1394_REGION_ADDR; - + ptask->hdr.words.word1 = 0; + ptask->hdr.words.word2 = 0; + ptask->hdr.words.word3 = 0; + ptask->hdr.words.word4 = 0; ptask->skb = skb; - ptask->addr = addr; - ptask->dest_node = dest_node; - /* TODO: When 2.4 is out of the way, give each of our ethernet - * dev's a workqueue to handle these. */ - INIT_WORK(&ptask->tq, hpsb_write_sched, ptask); - schedule_work(&ptask->tq); + ptask->priv = priv; + ptask->tx_type = tx_type; + + if(tx_type != ETH1394_GASP) { + u64 addr; + + /* This test is just temporary until ConfigROM support has + * been added to eth1394. Until then, we need an ARP packet + * after a bus reset from the current destination node so that + * we can get FIFO information. */ + if(priv->fifo[NODEID_TO_NODE(dest_node)] == 0ULL) { + ret = -EAGAIN; + goto fail; + } + + spin_lock_irqsave(&priv->lock, flags); + addr = priv->fifo[NODEID_TO_NODE(dest_node)]; + spin_unlock_irqrestore(&priv->lock, flags); + + ptask->addr = addr; + ptask->dest_node = dest_node; + } + + ptask->tx_type = tx_type; + ptask->max_payload = max_payload; + ptask->outstanding_pkts = ether1394_encapsulate_prep(max_payload, proto, + &ptask->hdr, dg_size, + dgl); + /* Add the encapsulation header to the fragment */ + tx_len = ether1394_encapsulate(skb, max_payload, &ptask->hdr); + dev->trans_start = jiffies; + if(ether1394_send_packet(ptask, tx_len)) + goto fail; + + netif_wake_queue(dev); return 0; fail: - printk("Failed in ether1394_tx\n"); - - if (skb != NULL) - dev_kfree_skb (skb); + if(ptask->packet) + ether1394_free_packet(ptask->packet); + if(ptask) + kmem_cache_free(packet_task_cache, ptask); + if(skb != NULL) { + dev_kfree_skb(skb); + } spin_lock_irqsave (&priv->lock, flags); priv->stats.tx_dropped++; priv->stats.tx_errors++; - if (netif_queue_stopped (dev)) - netif_wake_queue (dev); spin_unlock_irqrestore (&priv->lock, flags); + + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); return 0; /* returning non-zero causes serious problems */ } diff -Nru a/drivers/ieee1394/eth1394.h b/drivers/ieee1394/eth1394.h --- a/drivers/ieee1394/eth1394.h Mon Jun 9 23:16:18 2003 +++ b/drivers/ieee1394/eth1394.h Mon Jun 9 23:16:18 2003 @@ -24,6 +24,8 @@ #ifndef __ETH1394_H #define __ETH1394_H +#include "ieee1394.h" + /* Register for incoming packets. This is 8192 bytes, which supports up to * 1600mbs. We'll need to change this if that ever becomes "small" :) */ #define ETHER1394_REGION_ADDR_LEN 8192 @@ -32,27 +34,38 @@ /* GASP identifier numbers for IPv4 over IEEE 1394 */ #define ETHER1394_GASP_SPECIFIER_ID 0x00005E +#define ETHER1394_GASP_SPECIFIER_ID_HI ((ETHER1394_GASP_SPECIFIER_ID >> 8) & 0xffff) +#define ETHER1394_GASP_SPECIFIER_ID_LO (ETHER1394_GASP_SPECIFIER_ID & 0xff) #define ETHER1394_GASP_VERSION 1 +#define ETHER1394_GASP_OVERHEAD (2 * sizeof(quadlet_t)) /* GASP header overhead */ + /* Node set == 64 */ #define NODE_SET (ALL_NODES + 1) enum eth1394_bc_states { ETHER1394_BC_CLOSED, ETHER1394_BC_OPENED, ETHER1394_BC_CHECK }; +struct pdg_list { + struct list_head list; /* partial datagram list per node */ + unsigned int sz; /* partial datagram list size per node */ + spinlock_t lock; /* partial datagram lock */ +}; + /* Private structure for our ethernet driver */ struct eth1394_priv { struct net_device_stats stats; /* Device stats */ struct hpsb_host *host; /* The card for this dev */ - unsigned char max_rec[NODE_SET];/* Max payload per node */ + u16 maxpayload[NODE_SET]; /* Max payload per node */ unsigned char sspd[NODE_SET]; /* Max speed per node */ - u16 fifo_hi[ALL_NODES]; /* 16bit hi fifo offset per node */ - u32 fifo_lo[ALL_NODES]; /* 32bit lo fifo offset per node */ + u64 fifo[ALL_NODES]; /* FIFO offset per node */ u64 eui[ALL_NODES]; /* EUI-64 per node */ spinlock_t lock; /* Private lock */ int broadcast_channel; /* Async stream Broadcast Channel */ enum eth1394_bc_states bc_state; /* broadcast channel state */ struct hpsb_iso *iso; /* Async stream recv handle */ + struct pdg_list pdg[ALL_NODES]; /* partial RX datagram lists */ + int dgl[NODE_SET]; /* Outgoing datagram label per node */ }; struct host_info { @@ -60,16 +73,22 @@ struct net_device *dev; }; -typedef enum {ETH1394_GASP, ETH1394_WRREQ} eth1394_tx_type; -/* This is our task struct. It's used for the packet complete callback. */ -struct packet_task { - struct sk_buff *skb; /* Socket buffer we are sending */ - nodeid_t dest_node; /* Destination of the packet */ - u64 addr; /* Address */ - struct work_struct tq; /* The task */ - eth1394_tx_type tx_type; /* Send data via GASP or Write Req. */ -}; +/* Define a fake hardware header format for the networking core. Note that + * header size cannot exceed 16 bytes as that is the size of the header cache. + * Also, we do not need the source address in the header so we omit it and + * keep the header to under 16 bytes */ +#define ETH1394_ALEN (8) +#define ETH1394_HLEN (10) + +struct eth1394hdr { + unsigned char h_dest[ETH1394_ALEN]; /* destination eth1394 addr */ + unsigned short h_proto; /* packet type ID field */ +} __attribute__((packed)); + + + +typedef enum {ETH1394_GASP, ETH1394_WRREQ} eth1394_tx_type; /* IP1394 headers */ #include <asm/byteorder.h> @@ -77,14 +96,14 @@ /* Unfragmented */ #if defined __BIG_ENDIAN_BITFIELD struct eth1394_uf_hdr { - u8 lf:2; + u16 lf:2; u16 res:14; u16 ether_type; /* Ethernet packet type */ } __attribute__((packed)); #elif defined __LITTLE_ENDIAN_BITFIELD struct eth1394_uf_hdr { u16 res:14; - u8 lf:2; + u16 lf:2; u16 ether_type; } __attribute__((packed)); #else @@ -94,8 +113,8 @@ /* First fragment */ #if defined __BIG_ENDIAN_BITFIELD struct eth1394_ff_hdr { - u8 lf:2; - u8 res1:2; + u16 lf:2; + u16 res1:2; u16 dg_size:12; /* Datagram size */ u16 ether_type; /* Ethernet packet type */ u16 dgl; /* Datagram label */ @@ -104,8 +123,8 @@ #elif defined __LITTLE_ENDIAN_BITFIELD struct eth1394_ff_hdr { u16 dg_size:12; - u8 res1:2; - u8 lf:2; + u16 res1:2; + u16 lf:2; u16 ether_type; u16 dgl; u16 res2; @@ -117,21 +136,21 @@ /* XXX: Subsequent fragments, including last */ #if defined __BIG_ENDIAN_BITFIELD struct eth1394_sf_hdr { - u8 lf:2; - u8 res1:2; + u16 lf:2; + u16 res1:2; u16 dg_size:12; /* Datagram size */ - u8 res2:6; - u16 fg_off:10; /* Fragment offset */ + u16 res2:4; + u16 fg_off:12; /* Fragment offset */ u16 dgl; /* Datagram label */ u16 res3; } __attribute__((packed)); #elif defined __LITTLE_ENDIAN_BITFIELD struct eth1394_sf_hdr { u16 dg_size:12; - u8 res1:2; - u8 lf:2; - u16 fg_off:10; - u8 res2:6; + u16 res1:2; + u16 lf:2; + u16 fg_off:12; + u16 res2:4; u16 dgl; u16 res3; } __attribute__((packed)); @@ -141,13 +160,13 @@ #if defined __BIG_ENDIAN_BITFIELD struct eth1394_common_hdr { - u8 lf:2; + u16 lf:2; u16 pad1:14; } __attribute__((packed)); #elif defined __LITTLE_ENDIAN_BITFIELD struct eth1394_common_hdr { u16 pad1:14; - u8 lf:2; + u16 lf:2; } __attribute__((packed)); #else #error Unknown bit field type @@ -198,5 +217,18 @@ /* Network timeout */ #define ETHER1394_TIMEOUT 100000 + +/* This is our task struct. It's used for the packet complete callback. */ +struct packet_task { + struct sk_buff *skb; + int outstanding_pkts; + eth1394_tx_type tx_type; + int max_payload; + struct hpsb_packet *packet; + struct eth1394_priv *priv; + union eth1394_hdr hdr; + u64 addr; + u16 dest_node; +}; #endif /* __ETH1394_H */ diff -Nru a/drivers/ieee1394/ieee1394.h b/drivers/ieee1394/ieee1394.h --- a/drivers/ieee1394/ieee1394.h Mon Jun 9 23:16:09 2003 +++ b/drivers/ieee1394/ieee1394.h Mon Jun 9 23:16:09 2003 @@ -57,7 +57,6 @@ /* Maps speed values above to a string representation */ extern const char *hpsb_speedto_str[]; -extern const u8 hpsb_speedto_maxrec[]; #define SELFID_PWRCL_NO_POWER 0x0 diff -Nru a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c --- a/drivers/ieee1394/ieee1394_core.c Mon Jun 9 23:16:08 2003 +++ b/drivers/ieee1394/ieee1394_core.c Mon Jun 9 23:16:08 2003 @@ -61,7 +61,6 @@ /* Some globals used */ const char *hpsb_speedto_str[] = { "S100", "S200", "S400", "S800", "S1600", "S3200" }; -const u8 hpsb_speedto_maxrec[] = { 0x7, 0x8, 0x9, 0x10, 0x11, 0x12 }; static void dump_packet(const char *text, quadlet_t *data, int size) { @@ -80,9 +79,12 @@ static void run_packet_complete(struct hpsb_packet *packet) { if (packet->complete_routine != NULL) { - packet->complete_routine(packet->complete_data); + void (*complete_routine)(void*) = packet->complete_routine; + void *complete_data = packet->complete_data; + packet->complete_routine = NULL; packet->complete_data = NULL; + complete_routine(complete_data); } return; } @@ -938,7 +940,7 @@ { unsigned long flags; struct hpsb_packet *packet; - struct list_head *lh; + struct list_head *lh, *tlh; LIST_HEAD(llist); host->driver->devctl(host, CANCEL_REQUESTS, 0); @@ -948,8 +950,9 @@ INIT_LIST_HEAD(&host->pending_packets); spin_unlock_irqrestore(&host->pending_pkt_lock, flags); - list_for_each(lh, &llist) { + list_for_each_safe(lh, tlh, &llist) { packet = list_entry(lh, struct hpsb_packet, list); + list_del(&packet->list); packet->state = hpsb_complete; packet->ack_code = ACKX_ABORTED; up(&packet->state_change); @@ -962,7 +965,7 @@ unsigned long flags; struct hpsb_packet *packet; unsigned long expire; - struct list_head *lh, *next; + struct list_head *lh, *next, *tlh; LIST_HEAD(expiredlist); spin_lock_irqsave(&host->csr.lock, flags); @@ -990,8 +993,9 @@ spin_unlock_irqrestore(&host->pending_pkt_lock, flags); - list_for_each(lh, &expiredlist) { + list_for_each_safe(lh, tlh, &expiredlist) { packet = list_entry(lh, struct hpsb_packet, list); + list_del(&packet->list); packet->state = hpsb_complete; packet->ack_code = ACKX_TIMEOUT; up(&packet->state_change); @@ -1241,7 +1245,6 @@ /** ieee1394_core.c **/ EXPORT_SYMBOL(hpsb_speedto_str); -EXPORT_SYMBOL(hpsb_speedto_maxrec); EXPORT_SYMBOL(hpsb_set_packet_complete_task); EXPORT_SYMBOL(alloc_hpsb_packet); EXPORT_SYMBOL(free_hpsb_packet); diff -Nru a/drivers/ieee1394/ieee1394_transactions.c b/drivers/ieee1394/ieee1394_transactions.c --- a/drivers/ieee1394/ieee1394_transactions.c Mon Jun 9 23:16:09 2003 +++ b/drivers/ieee1394/ieee1394_transactions.c Mon Jun 9 23:16:09 2003 @@ -147,6 +147,8 @@ spin_lock_irqsave(&tp->lock, flags); packet->tlabel = find_next_zero_bit(tp->pool, 64, tp->next); + if(packet->tlabel > 63) + packet->tlabel = find_first_zero_bit(tp->pool, 64); tp->next = (packet->tlabel + 1) % 64; /* Should _never_ happen */ BUG_ON(test_and_set_bit(packet->tlabel, tp->pool)); @@ -573,10 +575,6 @@ quadlet_t *buffer, size_t length, u32 specifier_id, unsigned int version) { -#ifdef CONFIG_IEEE1394_VERBOSEDEBUG - int i; -#endif - struct hpsb_packet *packet; int retval = 0; u16 specifier_id_hi = (specifier_id & 0x00ffff00) >> 8; @@ -603,14 +601,6 @@ packet->data[1] = cpu_to_be32((specifier_id_lo << 24) | (version & 0x00ffffff)); memcpy(&(packet->data[2]), buffer, length - 4); - -#ifdef CONFIG_IEEE1394_VERBOSEDEBUG - HPSB_DEBUG("GASP: packet->header_size = %d", packet->header_size); - HPSB_DEBUG("GASP: packet->data_size = %d", packet->data_size); - - for(i=0; i<(packet->data_size/4); i++) - HPSB_DEBUG("GASP: data[%d]: 0x%08x", i*4, be32_to_cpu(packet->data[i])); -#endif packet->generation = generation; diff -Nru a/drivers/ieee1394/iso.c b/drivers/ieee1394/iso.c --- a/drivers/ieee1394/iso.c Mon Jun 9 23:16:17 2003 +++ b/drivers/ieee1394/iso.c Mon Jun 9 23:16:17 2003 @@ -10,6 +10,7 @@ */ #include <linux/slab.h> +#include <linux/sched.h> #include "iso.h" void hpsb_iso_stop(struct hpsb_iso *iso) diff -Nru a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c --- a/drivers/ieee1394/ohci1394.c Mon Jun 9 23:16:17 2003 +++ b/drivers/ieee1394/ohci1394.c Mon Jun 9 23:16:17 2003 @@ -111,7 +111,7 @@ #include <linux/vmalloc.h> #include <linux/init.h> -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC #include <asm/machdep.h> #include <asm/pmac_feature.h> #include <asm/prom.h> @@ -164,7 +164,7 @@ printk(level "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args) static char version[] __devinitdata = - "$Rev: 931 $ Ben Collins <bcollins@debian.org>"; + "$Rev: 938 $ Ben Collins <bcollins@debian.org>"; /* Module Parameters */ static int phys_dma = 1; @@ -3165,7 +3165,7 @@ struct config_rom_ptr cr; memset(&cr, 0, sizeof(cr)); - memset(ohci->csr_config_rom_cpu, 0, sizeof(*ohci->csr_config_rom_cpu)); + memset(ohci->csr_config_rom_cpu, 0, OHCI_CONFIG_ROM_LEN); cr.data = ohci->csr_config_rom_cpu; @@ -3508,7 +3508,7 @@ OHCI1394_REGISTER_SIZE); #endif -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC /* On UniNorth, power down the cable and turn off the chip * clock when the module is removed to save power on * laptops. Turning it back ON is done by the arch code when @@ -3522,7 +3522,7 @@ pmac_call_feature(PMAC_FTR_1394_CABLE_POWER, of_node, 0, 0); } } -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PMAC */ case OHCI_INIT_ALLOC_HOST: pci_set_drvdata(ohci->dev, NULL); @@ -3530,6 +3530,16 @@ } } + +#ifdef CONFIG_PM +static int ohci1394_pci_resume (struct pci_dev *dev) +{ + pci_enable_device(dev); + return 0; +} +#endif + + #define PCI_CLASS_FIREWIRE_OHCI ((PCI_CLASS_SERIAL_FIREWIRE << 8) | 0x10) static struct pci_device_id ohci1394_pci_tbl[] __devinitdata = { @@ -3551,6 +3561,10 @@ .id_table = ohci1394_pci_tbl, .probe = ohci1394_pci_probe, .remove = ohci1394_pci_remove, + +#ifdef CONFIG_PM + .resume = ohci1394_pci_resume, +#endif /* PM */ }; diff -Nru a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c --- a/drivers/ieee1394/sbp2.c Mon Jun 9 23:16:07 2003 +++ b/drivers/ieee1394/sbp2.c Mon Jun 9 23:16:07 2003 @@ -79,7 +79,7 @@ #include "sbp2.h" static char version[] __devinitdata = - "$Rev: 931 $ Ben Collins <bcollins@debian.org>"; + "$Rev: 942 $ Ben Collins <bcollins@debian.org>"; /* * Module load parameter definitions @@ -230,6 +230,8 @@ static Scsi_Host_Template scsi_driver_template; +const u8 sbp2_speedto_max_payload[] = { 0x7, 0x8, 0x9, 0xA, 0xB, 0xC }; + static struct hpsb_highlevel sbp2_highlevel = { .name = SBP2_DEVICE_NAME, .remove_host = sbp2_remove_host, @@ -779,7 +781,7 @@ scsi_id->ne = ud->ne; scsi_id->hi = hi; scsi_id->speed_code = SPEED_100; - scsi_id->max_payload_size = hpsb_speedto_maxrec[SPEED_100]; + scsi_id->max_payload_size = sbp2_speedto_max_payload[SPEED_100]; atomic_set(&scsi_id->sbp2_login_complete, 0); INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_inuse); INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_completed); @@ -1690,7 +1692,7 @@ /* Payload size is the lesser of what our speed supports and what * our host supports. */ - scsi_id->max_payload_size = min(hpsb_speedto_maxrec[scsi_id->speed_code], + scsi_id->max_payload_size = min(sbp2_speedto_max_payload[scsi_id->speed_code], (u8)(((be32_to_cpu(hi->host->csr.rom[2]) >> 12) & 0xf) - 1)); SBP2_ERR("Node[" NODE_BUS_FMT "]: Max speed [%s] - Max payload [%u]", @@ -2845,11 +2847,10 @@ #define SPRINTF(args...) \ do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0) -static int sbp2scsi_proc_info(char *buffer, char **start, off_t offset, - int length, int hostno, int inout) +static int sbp2scsi_proc_info(struct Scsi_Host *scsi_host, char *buffer, char **start, off_t offset, + int length, int inout) { Scsi_Device *scd; - struct Scsi_Host *scsi_host; struct hpsb_host *host; char *pos = buffer; @@ -2857,16 +2858,12 @@ if (inout) return length; - scsi_host = scsi_host_hn_get(hostno); - if (!scsi_host) /* if we couldn't find it, we return an error */ - return -ESRCH; - host = hpsb_get_host_bykey(&sbp2_highlevel, (unsigned long)scsi_host); if (!host) /* shouldn't happen, but... */ return -ESRCH; - SPRINTF("Host scsi%d : SBP-2 IEEE-1394 (%s)\n", hostno, - host->driver->name); + SPRINTF("Host scsi%d : SBP-2 IEEE-1394 (%s)\n", + scsi_host->host_no, host->driver->name); SPRINTF("Driver version : %s\n", version); SPRINTF("\nModule options :\n"); @@ -2899,8 +2896,6 @@ SPRINTF("\n"); - /* release the reference count on this host */ - scsi_host_put(scsi_host); /* Calculate start of next buffer, and return value. */ *start = buffer + offset; diff -Nru a/drivers/isdn/hardware/avm/avm_cs.c b/drivers/isdn/hardware/avm/avm_cs.c --- a/drivers/isdn/hardware/avm/avm_cs.c Mon Jun 9 23:16:05 2003 +++ b/drivers/isdn/hardware/avm/avm_cs.c Mon Jun 9 23:16:05 2003 @@ -510,29 +510,30 @@ return 0; } /* avmcs_event */ -/*====================================================================*/ +static struct pcmcia_driver avmcs_driver = { + .owner = THIS_MODULE, + .drv = { + .name = "avmcs_cs", + }, + .attach = avmcs_attach, + .detach = avmcs_detach, +}; static int __init avmcs_init(void) { - servinfo_t serv; - CardServices(GetCardServicesInfo, &serv); - if (serv.Revision != CS_RELEASE_CODE) { - printk(KERN_NOTICE "avm_cs: Card Services release " - "does not match!\n"); - return -1; - } - register_pccard_driver(&dev_info, &avmcs_attach, &avmcs_detach); - return 0; + return pcmcia_register_driver(&avmcs_driver); } static void __exit avmcs_exit(void) { - unregister_pccard_driver(&dev_info); - while (dev_list != NULL) { - if (dev_list->state & DEV_CONFIG) - avmcs_release((u_long)dev_list); - avmcs_detach(dev_list); - } + pcmcia_unregister_driver(&avmcs_driver); + + /* XXX: this really needs to move into generic code.. */ + while (dev_list != NULL) { + if (dev_list->state & DEV_CONFIG) + avmcs_release((u_long)dev_list); + avmcs_detach(dev_list); + } } module_init(avmcs_init); diff -Nru a/drivers/isdn/hardware/eicon/divamnt.c b/drivers/isdn/hardware/eicon/divamnt.c --- a/drivers/isdn/hardware/eicon/divamnt.c Mon Jun 9 23:16:13 2003 +++ b/drivers/isdn/hardware/eicon/divamnt.c Mon Jun 9 23:16:13 2003 @@ -421,7 +421,7 @@ return (0); } - devfs_mk_cdev(MKDEV(major, 0), S_IFCHR|S_IRUSR|S_IWUSR, DivasMAINT); + devfs_mk_cdev(MKDEV(major, 0), S_IFCHR|S_IRUSR|S_IWUSR, "DivasMAINT"); return (1); } diff -Nru a/drivers/isdn/hisax/avma1_cs.c b/drivers/isdn/hisax/avma1_cs.c --- a/drivers/isdn/hisax/avma1_cs.c Mon Jun 9 23:16:15 2003 +++ b/drivers/isdn/hisax/avma1_cs.c Mon Jun 9 23:16:15 2003 @@ -515,30 +515,30 @@ return 0; } /* avma1cs_event */ -/*====================================================================*/ +static struct pcmcia_driver avma1cs_driver = { + .owner = THIS_MODULE, + .drv = { + .name = "avma1_cs", + }, + .attach = avma1cs_attach, + .detach = avma1cs_detach, +}; static int __init init_avma1_cs(void) { - servinfo_t serv; - DEBUG(0, "%s\n", version); - CardServices(GetCardServicesInfo, &serv); - if (serv.Revision != CS_RELEASE_CODE) { - printk(KERN_NOTICE "avma1_cs: Card Services release " - "does not match!\n"); - return -1; - } - register_pccard_driver(&dev_info, &avma1cs_attach, &avma1cs_detach); - return 0; + return pcmcia_register_driver(&avma1cs_driver); } static void __exit exit_avma1_cs(void) { - DEBUG(0, "avma1_cs: unloading\n"); - unregister_pccard_driver(&dev_info); - while (dev_list != NULL) - if (dev_list->state & DEV_CONFIG) - avma1cs_release((u_long)dev_list); - avma1cs_detach(dev_list); + pcmcia_unregister_driver(&avma1cs_driver); + + /* XXX: this really needs to move into generic code.. */ + while (dev_list != NULL) { + if (dev_list->state & DEV_CONFIG) + avma1cs_release((u_long)dev_list); + avma1cs_detach(dev_list); + } } module_init(init_avma1_cs); diff -Nru a/drivers/isdn/hisax/elsa_cs.c b/drivers/isdn/hisax/elsa_cs.c --- a/drivers/isdn/hisax/elsa_cs.c Mon Jun 9 23:16:11 2003 +++ b/drivers/isdn/hisax/elsa_cs.c Mon Jun 9 23:16:11 2003 @@ -531,28 +531,27 @@ return 0; } /* elsa_cs_event */ -/*====================================================================*/ +static struct pcmcia_driver elsa_cs_driver = { + .owner = THIS_MODULE, + .drv = { + .name = "elsa_cs", + }, + .attach = elsa_cs_attach, + .detach = elsa_cs_detach, +}; static int __init init_elsa_cs(void) { - servinfo_t serv; - DEBUG(0, "%s\n", version); - CardServices(GetCardServicesInfo, &serv); - if (serv.Revision != CS_RELEASE_CODE) { - printk(KERN_NOTICE "elsa_cs: Card Services release " - "does not match!\n"); - return -1; - } - register_pccard_driver(&dev_info, &elsa_cs_attach, &elsa_cs_detach); - return 0; + return pcmcia_register_driver(&elsa_cs_driver); } static void __exit exit_elsa_cs(void) { - DEBUG(0, "elsa_cs: unloading\n"); - unregister_pccard_driver(&dev_info); - while (dev_list != NULL) - elsa_cs_detach(dev_list); + pcmcia_unregister_driver(&elsa_cs_driver); + + /* XXX: this really needs to move into generic code.. */ + while (dev_list != NULL) + elsa_cs_detach(dev_list); } module_init(init_elsa_cs); diff -Nru a/drivers/isdn/hisax/sedlbauer_cs.c b/drivers/isdn/hisax/sedlbauer_cs.c --- a/drivers/isdn/hisax/sedlbauer_cs.c Mon Jun 9 23:16:09 2003 +++ b/drivers/isdn/hisax/sedlbauer_cs.c Mon Jun 9 23:16:09 2003 @@ -633,34 +633,32 @@ return 0; } /* sedlbauer_event */ -/*====================================================================*/ +static struct pcmcia_driver sedlbauer_driver = { + .owner = THIS_MODULE, + .drv = { + .name = "sedlbauer_cs", + }, + .attach = sedlbauer_attach, + .detach = sedlbauer_detach, +}; static int __init init_sedlbauer_cs(void) { - servinfo_t serv; - DEBUG(0, "%s\n", version); - CardServices(GetCardServicesInfo, &serv); - if (serv.Revision != CS_RELEASE_CODE) { - printk(KERN_NOTICE "sedlbauer_cs: Card Services release " - "does not match!\n"); - return -1; - } - register_pccard_driver(&dev_info, &sedlbauer_attach, &sedlbauer_detach); - return 0; + return pcmcia_register_driver(&sedlbauer_driver); } static void __exit exit_sedlbauer_cs(void) { - DEBUG(0, "sedlbauer_cs: unloading\n"); - unregister_pccard_driver(&dev_info); - while (dev_list != NULL) { - del_timer(&dev_list->release); - if (dev_list->state & DEV_CONFIG) - sedlbauer_release((u_long)dev_list); - sedlbauer_detach(dev_list); - } + pcmcia_unregister_driver(&sedlbauer_driver); + + /* XXX: this really needs to move into generic code.. */ + while (dev_list != NULL) { + del_timer(&dev_list->release); + if (dev_list->state & DEV_CONFIG) + sedlbauer_release((u_long)dev_list); + sedlbauer_detach(dev_list); + } } module_init(init_sedlbauer_cs); module_exit(exit_sedlbauer_cs); - diff -Nru a/drivers/isdn/hisax/st5481_init.c b/drivers/isdn/hisax/st5481_init.c --- a/drivers/isdn/hisax/st5481_init.c Mon Jun 9 23:16:19 2003 +++ b/drivers/isdn/hisax/st5481_init.c Mon Jun 9 23:16:19 2003 @@ -181,6 +181,7 @@ MODULE_DEVICE_TABLE (usb, st5481_ids); static struct usb_driver st5481_usb_driver = { + .owner = THIS_MODULE, .name = "st5481_usb", .probe = probe_st5481, .disconnect = disconnect_st5481, diff -Nru a/drivers/isdn/i4l/isdn_tty.c b/drivers/isdn/i4l/isdn_tty.c --- a/drivers/isdn/i4l/isdn_tty.c Mon Jun 9 23:16:15 2003 +++ b/drivers/isdn/i4l/isdn_tty.c Mon Jun 9 23:16:15 2003 @@ -62,14 +62,6 @@ #define MODEM_PARANOIA_CHECK #define MODEM_DO_RESTART -#ifdef CONFIG_DEVFS_FS -static char *isdn_ttyname_ttyI = "isdn/ttyI%d"; -static char *isdn_ttyname_cui = "isdn/cui%d"; -#else -static char *isdn_ttyname_ttyI = "ttyI"; -static char *isdn_ttyname_cui = "cui"; -#endif - struct isdn_modem isdn_mdm; static int bit2si[8] = @@ -1652,41 +1644,16 @@ #endif } /* - * If this is a callout device, then just make sure the normal - * device isn't being used. - */ - if (tty->driver->subtype == ISDN_SERIAL_TYPE_CALLOUT) { - if (info->flags & ISDN_ASYNC_NORMAL_ACTIVE) - return -EBUSY; - if ((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) && - (info->flags & ISDN_ASYNC_SESSION_LOCKOUT) && - (info->session != current->session)) - return -EBUSY; - if ((info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) && - (info->flags & ISDN_ASYNC_PGRP_LOCKOUT) && - (info->pgrp != current->pgrp)) - return -EBUSY; - info->flags |= ISDN_ASYNC_CALLOUT_ACTIVE; - return 0; - } - /* * If non-blocking mode is set, then make the check up front * and then exit. */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { - if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) - return -EBUSY; info->flags |= ISDN_ASYNC_NORMAL_ACTIVE; return 0; } - if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) { - if (info->normal_termios.c_cflag & CLOCAL) - do_clocal = 1; - } else { - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - } + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; /* * Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). While we are in @@ -1720,8 +1687,7 @@ #endif break; } - if (!(info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) && - !(info->flags & ISDN_ASYNC_CLOSING) && + if (!(info->flags & ISDN_ASYNC_CLOSING) && (do_clocal || (info->msr & UART_MSR_DCD))) { break; } @@ -1797,14 +1763,9 @@ return retval; } if ((info->count == 1) && (info->flags & ISDN_ASYNC_SPLIT_TERMIOS)) { - if (tty->driver->subtype == ISDN_SERIAL_TYPE_NORMAL) - *tty->termios = info->normal_termios; - else - *tty->termios = info->callout_termios; + *tty->termios = info->normal_termios; isdn_tty_change_speed(info); } - info->session = current->session; - info->pgrp = current->pgrp; #ifdef ISDN_DEBUG_MODEM_OPEN printk(KERN_DEBUG "isdn_tty_open ttyi%d successful...\n", info->line); #endif @@ -1865,8 +1826,6 @@ */ if (info->flags & ISDN_ASYNC_NORMAL_ACTIVE) info->normal_termios = *tty->termios; - if (info->flags & ISDN_ASYNC_CALLOUT_ACTIVE) - info->callout_termios = *tty->termios; tty->closing = 1; /* @@ -1904,8 +1863,7 @@ schedule_timeout(HZ/2); wake_up_interruptible(&info->open_wait); } - info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE | - ISDN_ASYNC_CLOSING); + info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); restore_flags(flags); #ifdef ISDN_DEBUG_MODEM_OPEN @@ -1927,7 +1885,7 @@ return; isdn_tty_shutdown(info); info->count = 0; - info->flags &= ~(ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE); + info->flags &= ~ISDN_ASYNC_NORMAL_ACTIVE; info->tty = 0; wake_up_interruptible(&info->open_wait); } @@ -2049,12 +2007,13 @@ m = &isdn_mdm; memset(&m->tty_modem, 0, sizeof(struct tty_driver)); m->tty_modem.magic = TTY_DRIVER_MAGIC; - m->tty_modem.name = isdn_ttyname_ttyI; + m->tty_modem.name = "ttyI"; + m->tty_modem.devfs_name = "isdn/ttyI"; m->tty_modem.major = ISDN_TTY_MAJOR; m->tty_modem.minor_start = 0; m->tty_modem.num = ISDN_MAX_CHANNELS; m->tty_modem.type = TTY_DRIVER_TYPE_SERIAL; - m->tty_modem.subtype = ISDN_SERIAL_TYPE_NORMAL; + m->tty_modem.subtype = SERIAL_TYPE_NORMAL; m->tty_modem.init_termios = tty_std_termios; m->tty_modem.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; m->tty_modem.flags = TTY_DRIVER_REAL_RAW; @@ -2078,26 +2037,12 @@ m->tty_modem.start = NULL; m->tty_modem.hangup = isdn_tty_hangup; m->tty_modem.driver_name = "isdn_tty"; - /* - * The callout device is just like normal device except for - * major number and the subtype code. - */ - m->cua_modem = m->tty_modem; - m->cua_modem.name = isdn_ttyname_cui; - m->cua_modem.major = ISDN_TTYAUX_MAJOR; - m->tty_modem.minor_start = 0; - m->cua_modem.subtype = ISDN_SERIAL_TYPE_CALLOUT; retval = tty_register_driver(&m->tty_modem); if (retval) { printk(KERN_WARNING "isdn_tty: Couldn't register modem-device\n"); goto err; } - retval = tty_register_driver(&m->cua_modem); - if (retval) { - printk(KERN_WARNING "isdn_tty: Couldn't register modem-callout-device\n"); - goto err_unregister_tty; - } for (i = 0; i < ISDN_MAX_CHANNELS; i++) { info = &m->info[i]; #ifdef CONFIG_ISDN_TTY_FAX @@ -2121,7 +2066,6 @@ info->x_char = 0; info->count = 0; info->blocked_open = 0; - info->callout_termios = m->cua_modem.init_termios; info->normal_termios = m->tty_modem.init_termios; init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); @@ -2167,7 +2111,6 @@ #endif kfree(info->xmit_buf - 4); } - tty_unregister_driver(&isdn_mdm.cua_modem); err_unregister_tty: tty_unregister_driver(&isdn_mdm.tty_modem); err: @@ -2189,7 +2132,6 @@ #endif kfree(info->xmit_buf - 4); } - tty_unregister_driver(&isdn_mdm.cua_modem); tty_unregister_driver(&isdn_mdm.tty_modem); } @@ -2334,7 +2276,7 @@ } #define TTY_IS_ACTIVE(info) \ - (info->flags & (ISDN_ASYNC_NORMAL_ACTIVE | ISDN_ASYNC_CALLOUT_ACTIVE)) + (info->flags & ISDN_ASYNC_NORMAL_ACTIVE) static int isdn_tty_stat_callback(struct isdn_slot *slot, isdn_ctrl *c) @@ -2833,9 +2775,7 @@ } 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)))) { + if (info->flags & ISDN_ASYNC_CHECK_CD) { tty_hangup(info->tty); } restore_flags(flags); diff -Nru a/drivers/isdn/i4l/isdn_tty.h b/drivers/isdn/i4l/isdn_tty.h --- a/drivers/isdn/i4l/isdn_tty.h Mon Jun 9 23:16:15 2003 +++ b/drivers/isdn/i4l/isdn_tty.h Mon Jun 9 23:16:15 2003 @@ -116,7 +116,6 @@ struct isdn_modem { int refcount; /* Number of opens */ struct tty_driver tty_modem; /* tty-device */ - struct tty_driver cua_modem; /* cua-device */ struct tty_struct *modem_table[ISDN_MAX_CHANNELS]; /* ?? copied from Orig */ struct termios *modem_termios[ISDN_MAX_CHANNELS]; struct termios *modem_termios_locked[ISDN_MAX_CHANNELS]; diff -Nru a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c --- a/drivers/macintosh/adb.c Mon Jun 9 23:16:20 2003 +++ b/drivers/macintosh/adb.c Mon Jun 9 23:16:20 2003 @@ -749,7 +749,7 @@ return 0; } -static ssize_t adb_read(struct file *file, char *buf, +static ssize_t adb_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { int ret; @@ -810,7 +810,7 @@ return ret; } -static ssize_t adb_write(struct file *file, const char *buf, +static ssize_t adb_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { int ret/*, i*/; diff -Nru a/drivers/macintosh/apm_emu.c b/drivers/macintosh/apm_emu.c --- a/drivers/macintosh/apm_emu.c Mon Jun 9 23:16:19 2003 +++ b/drivers/macintosh/apm_emu.c Mon Jun 9 23:16:19 2003 @@ -180,7 +180,7 @@ return 0; } -static ssize_t do_read(struct file *fp, char *buf, size_t count, loff_t *ppos) +static ssize_t do_read(struct file *fp, char __user *buf, size_t count, loff_t *ppos) { struct apm_user * as; size_t i; diff -Nru a/drivers/macintosh/macserial.c b/drivers/macintosh/macserial.c --- a/drivers/macintosh/macserial.c Mon Jun 9 23:16:19 2003 +++ b/drivers/macintosh/macserial.c Mon Jun 9 23:16:19 2003 @@ -105,12 +105,11 @@ #endif #define ZS_CLOCK 3686400 /* Z8530 RTxC input clock rate */ -static struct tty_driver serial_driver, callout_driver; +static struct tty_driver serial_driver; static int serial_refcount; /* serial subtype definitions */ #define SERIAL_TYPE_NORMAL 1 -#define SERIAL_TYPE_CALLOUT 2 /* number of characters left in xmit buffer before we ask for more */ #define WAKEUP_CHARS 256 @@ -492,7 +491,7 @@ && info->tty && !C_CLOCAL(info->tty)) { if (status & DCD) { wake_up_interruptible(&info->open_wait); - } else if (!(info->flags & ZILOG_CALLOUT_ACTIVE)) { + } else { if (info->tty) tty_hangup(info->tty); } @@ -1695,7 +1694,7 @@ */ static int get_serial_info(struct mac_serial * info, - struct serial_struct * retinfo) + struct serial_struct __user * retinfo) { struct serial_struct tmp; @@ -1717,7 +1716,7 @@ } static int set_serial_info(struct mac_serial * info, - struct serial_struct * new_info) + struct serial_struct __user * new_info) { struct serial_struct new_serial; struct mac_serial old_info; @@ -1877,15 +1876,15 @@ return set_modem_info(info, cmd, (unsigned int *) arg); case TIOCGSERIAL: return get_serial_info(info, - (struct serial_struct *) arg); + (struct serial_struct __user *) arg); case TIOCSSERIAL: return set_serial_info(info, - (struct serial_struct *) arg); + (struct serial_struct __user *) arg); case TIOCSERGETLSR: /* Get line status register */ return get_lsr_info(info, (unsigned int *) arg); case TIOCSERGSTRUCT: - if (copy_to_user((struct mac_serial *) arg, + if (copy_to_user((struct mac_serial __user *) arg, info, sizeof(struct mac_serial))) return -EFAULT; return 0; @@ -1965,8 +1964,6 @@ */ if (info->flags & ZILOG_NORMAL_ACTIVE) info->normal_termios = *tty->termios; - if (info->flags & ZILOG_CALLOUT_ACTIVE) - info->callout_termios = *tty->termios; /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. @@ -2021,8 +2018,7 @@ } wake_up_interruptible(&info->open_wait); } - info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE| - ZILOG_CLOSING); + info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CLOSING); wake_up_interruptible(&info->close_wait); } @@ -2087,7 +2083,7 @@ shutdown(info); info->event = 0; info->count = 0; - info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE); + info->flags &= ~ZILOG_NORMAL_ACTIVE; info->tty = 0; wake_up_interruptible(&info->open_wait); } @@ -2119,43 +2115,17 @@ } /* - * If this is a callout device, then just make sure the normal - * device isn't being used. - */ - if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) { - if (info->flags & ZILOG_NORMAL_ACTIVE) - return -EBUSY; - if ((info->flags & ZILOG_CALLOUT_ACTIVE) && - (info->flags & ZILOG_SESSION_LOCKOUT) && - (info->session != current->session)) - return -EBUSY; - if ((info->flags & ZILOG_CALLOUT_ACTIVE) && - (info->flags & ZILOG_PGRP_LOCKOUT) && - (info->pgrp != current->pgrp)) - return -EBUSY; - info->flags |= ZILOG_CALLOUT_ACTIVE; - return 0; - } - - /* * If non-blocking mode is set, or the port is not enabled, * then make the check up front and then exit. */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { - if (info->flags & ZILOG_CALLOUT_ACTIVE) - return -EBUSY; info->flags |= ZILOG_NORMAL_ACTIVE; return 0; } - if (info->flags & ZILOG_CALLOUT_ACTIVE) { - if (info->normal_termios.c_cflag & CLOCAL) - do_clocal = 1; - } else { - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - } + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; /* * Block waiting for the carrier detect and the line to become @@ -2175,8 +2145,7 @@ info->blocked_open++; while (1) { spin_lock_irq(&info->lock); - if (!(info->flags & ZILOG_CALLOUT_ACTIVE) && - (tty->termios->c_cflag & CBAUD) && + if ((tty->termios->c_cflag & CBAUD) && !info->is_irda) zs_rtsdtr(info, 1); spin_unlock_irq(&info->lock); @@ -2193,8 +2162,7 @@ #endif break; } - if (!(info->flags & ZILOG_CALLOUT_ACTIVE) && - !(info->flags & ZILOG_CLOSING) && + if (!(info->flags & ZILOG_CLOSING) && (do_clocal || (read_zsreg(info->zs_channel, 0) & DCD))) break; if (signal_pending(current)) { @@ -2291,10 +2259,7 @@ } if ((info->count == 1) && (info->flags & ZILOG_SPLIT_TERMIOS)) { - if (tty->driver->subtype == SERIAL_TYPE_NORMAL) - *tty->termios = info->normal_termios; - else - *tty->termios = info->callout_termios; + *tty->termios = info->normal_termios; change_speed(info, 0); } #ifdef CONFIG_SERIAL_CONSOLE @@ -2305,9 +2270,6 @@ } #endif - info->session = current->session; - info->pgrp = current->pgrp; - OPNDBG("rs_open %s successful...\n", tty->name); return 0; } @@ -2470,7 +2432,7 @@ /* Ask the PROM how many Z8530s we have and initialize their zs_channels */ static void -probe_sccs() +probe_sccs(void) { struct device_node *dev, *ch; struct mac_serial **pp; @@ -2606,11 +2568,8 @@ serial_driver.magic = TTY_DRIVER_MAGIC; serial_driver.owner = THIS_MODULE; serial_driver.driver_name = "macserial"; -#ifdef CONFIG_DEVFS_FS - serial_driver.name = "tts/"; -#else + serial_driver.devfs_name = "tts/"; serial_driver.name = "ttyS"; -#endif /* CONFIG_DEVFS_FS */ serial_driver.major = TTY_MAJOR; serial_driver.minor_start = 64; serial_driver.num = zs_channels_found; @@ -2644,25 +2603,8 @@ serial_driver.wait_until_sent = rs_wait_until_sent; serial_driver.read_proc = macserial_read_proc; - /* - * The callout device is just like normal device except for - * major number and the subtype code. - */ - callout_driver = serial_driver; -#ifdef CONFIG_DEVFS_FS - callout_driver.name = "cua/"; -#else - callout_driver.name = "cua"; -#endif /* CONFIG_DEVFS_FS */ - callout_driver.major = TTYAUX_MAJOR; - callout_driver.subtype = SERIAL_TYPE_CALLOUT; - callout_driver.read_proc = 0; - callout_driver.proc_entry = 0; - if (tty_register_driver(&serial_driver)) printk(KERN_ERR "Error: couldn't register serial driver\n"); - if (tty_register_driver(&callout_driver)) - printk(KERN_ERR "Error: couldn't register callout driver\n"); for (channel = 0; channel < zs_channels_found; ++channel) { #ifdef CONFIG_KGDB @@ -2713,7 +2655,6 @@ info->blocked_open = 0; INIT_WORK(&info->tqueue, do_softint, info); spin_lock_init(&info->lock); - info->callout_termios = callout_driver.init_termios; info->normal_termios = serial_driver.init_termios; init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); @@ -2758,7 +2699,6 @@ } } spin_unlock_irqrestore(&info->lock, flags); - tty_unregister_driver(&callout_driver); tty_unregister_driver(&serial_driver); if (tmp_buf) { diff -Nru a/drivers/macintosh/macserial.h b/drivers/macintosh/macserial.h --- a/drivers/macintosh/macserial.h Mon Jun 9 23:16:10 2003 +++ b/drivers/macintosh/macserial.h Mon Jun 9 23:16:10 2003 @@ -156,15 +156,12 @@ 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 */ unsigned char *xmit_buf; int xmit_head; int xmit_tail; int xmit_cnt; struct work_struct tqueue; struct termios normal_termios; - struct termios callout_termios; wait_queue_head_t open_wait; wait_queue_head_t close_wait; diff -Nru a/drivers/macintosh/nvram.c b/drivers/macintosh/nvram.c --- a/drivers/macintosh/nvram.c Mon Jun 9 23:16:07 2003 +++ b/drivers/macintosh/nvram.c Mon Jun 9 23:16:07 2003 @@ -39,11 +39,11 @@ return file->f_pos; } -static ssize_t read_nvram(struct file *file, char *buf, +static ssize_t read_nvram(struct file *file, char __user *buf, size_t count, loff_t *ppos) { unsigned int i; - char *p = buf; + char __user *p = buf; if (verify_area(VERIFY_WRITE, buf, count)) return -EFAULT; @@ -56,11 +56,11 @@ return p - buf; } -static ssize_t write_nvram(struct file *file, const char *buf, +static ssize_t write_nvram(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { unsigned int i; - const char *p = buf; + const char __user *p = buf; char c; if (verify_area(VERIFY_READ, buf, count)) @@ -83,12 +83,12 @@ case PMAC_NVRAM_GET_OFFSET: { int part, offset; - if (copy_from_user(&part,(void*)arg,sizeof(part))!=0) + if (copy_from_user(&part, (void __user*)arg, sizeof(part)) != 0) return -EFAULT; if (part < pmac_nvram_OF || part > pmac_nvram_NR) return -EINVAL; offset = pmac_get_partition(part); - if (copy_to_user((void*)arg,&offset,sizeof(offset))!=0) + if (copy_to_user((void __user*)arg, &offset, sizeof(offset)) != 0) return -EFAULT; break; } diff -Nru a/drivers/macintosh/via-cuda.c b/drivers/macintosh/via-cuda.c --- a/drivers/macintosh/via-cuda.c Mon Jun 9 23:16:07 2003 +++ b/drivers/macintosh/via-cuda.c Mon Jun 9 23:16:07 2003 @@ -213,7 +213,7 @@ #ifdef CONFIG_ADB static int -cuda_probe() +cuda_probe(void) { #ifdef CONFIG_PPC if (sys_ctrler != SYS_CTRLER_CUDA) @@ -258,7 +258,7 @@ } while (0) static int -cuda_init_via() +cuda_init_via(void) { out_8(&via[DIRB], (in_8(&via[DIRB]) | TACK | TIP) & ~TREQ); /* TACK & TIP out */ out_8(&via[B], in_8(&via[B]) | TACK | TIP); /* negate them */ @@ -407,7 +407,7 @@ } static void -cuda_start() +cuda_start(void) { struct adb_request *req; @@ -427,7 +427,7 @@ } void -cuda_poll() +cuda_poll(void) { unsigned long flags; diff -Nru a/drivers/macintosh/via-pmu.c b/drivers/macintosh/via-pmu.c --- a/drivers/macintosh/via-pmu.c Mon Jun 9 23:16:18 2003 +++ b/drivers/macintosh/via-pmu.c Mon Jun 9 23:16:18 2003 @@ -195,7 +195,7 @@ #endif /* CONFIG_PMAC_PBOOK */ static int proc_read_options(char *page, char **start, off_t off, int count, int *eof, void *data); -static int proc_write_options(struct file *file, const char *buffer, +static int proc_write_options(struct file *file, const char __user *buffer, unsigned long count, void *data); #ifdef CONFIG_ADB @@ -290,7 +290,7 @@ #endif /* CONFIG_PMAC_BACKLIGHT */ int __openfirmware -find_via_pmu() +find_via_pmu(void) { if (via != 0) return 1; @@ -371,7 +371,7 @@ #ifdef CONFIG_ADB static int __openfirmware -pmu_probe() +pmu_probe(void) { return vias == NULL? -ENODEV: 0; } @@ -510,7 +510,7 @@ device_initcall(via_pmu_dev_init); static int __openfirmware -init_pmu() +init_pmu(void) { int timeout; struct adb_request req; @@ -815,7 +815,7 @@ } static int __pmac -proc_write_options(struct file *file, const char *buffer, +proc_write_options(struct file *file, const char __user *buffer, unsigned long count, void *data) { char tmp[33]; @@ -1112,7 +1112,7 @@ } static void __pmac -pmu_start() +pmu_start(void) { struct adb_request *req; @@ -1136,7 +1136,7 @@ } void __openfirmware -pmu_poll() +pmu_poll(void) { if (!via) return; @@ -1713,10 +1713,10 @@ pbook_alloc_pci_save(void) { int npci; - struct pci_dev *pd; + struct pci_dev *pd = NULL; npci = 0; - pci_for_each_dev(pd) { + while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) { ++npci; } if (npci == 0) @@ -1740,13 +1740,13 @@ pbook_pci_save(void) { struct pci_save *ps = pbook_pci_saves; - struct pci_dev *pd; + struct pci_dev *pd = NULL; int npci = pbook_npci_saves; if (ps == NULL) return; - pci_for_each_dev(pd) { + while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) { if (npci-- == 0) return; #ifndef HACKED_PCI_SAVE @@ -1772,11 +1772,11 @@ { u16 cmd; struct pci_save *ps = pbook_pci_saves - 1; - struct pci_dev *pd; + struct pci_dev *pd = NULL; int npci = pbook_npci_saves; int j; - pci_for_each_dev(pd) { + while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) { #ifdef HACKED_PCI_SAVE int i; if (npci-- == 0) @@ -2402,7 +2402,7 @@ } static ssize_t __pmac -pmu_read(struct file *file, char *buf, +pmu_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct pmu_private *pp = file->private_data; @@ -2455,7 +2455,7 @@ } static ssize_t __pmac -pmu_write(struct file *file, const char *buf, +pmu_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { return 0; diff -Nru a/drivers/macintosh/via-pmu68k.c b/drivers/macintosh/via-pmu68k.c --- a/drivers/macintosh/via-pmu68k.c Mon Jun 9 23:16:07 2003 +++ b/drivers/macintosh/via-pmu68k.c Mon Jun 9 23:16:07 2003 @@ -839,11 +839,11 @@ pbook_pci_save(void) { int npci; - struct pci_dev *pd; + struct pci_dev *pd = NULL; struct pci_save *ps; npci = 0; - for (pd = pci_devices; pd != NULL; pd = pd->next) + while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) ++npci; n_pbook_pci_saves = npci; if (npci == 0) @@ -853,7 +853,8 @@ if (ps == NULL) return; - for (pd = pci_devices; pd != NULL && npci != 0; pd = pd->next) { + pd = NULL; + while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) { pci_read_config_word(pd, PCI_COMMAND, &ps->command); pci_read_config_word(pd, PCI_CACHE_LINE_SIZE, &ps->cache_lat); pci_read_config_word(pd, PCI_INTERRUPT_LINE, &ps->intr); @@ -867,10 +868,10 @@ { u16 cmd; struct pci_save *ps = pbook_pci_saves; - struct pci_dev *pd; + struct pci_dev *pd = NULL; int j; - for (pd = pci_devices; pd != NULL; pd = pd->next, ++ps) { + while ((pd = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pd)) != NULL) { if (ps->command == 0) continue; pci_read_config_word(pd, PCI_COMMAND, &cmd); diff -Nru a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c --- a/drivers/md/dm-ioctl.c Mon Jun 9 23:16:08 2003 +++ b/drivers/md/dm-ioctl.c Mon Jun 9 23:16:08 2003 @@ -351,7 +351,8 @@ static int populate_table(struct dm_table *table, struct dm_ioctl *args) { - int i = 0, r, first = 1; + int r, first = 1; + unsigned int i = 0; struct dm_target_spec *spec; char *params; void *begin, *end; @@ -380,7 +381,8 @@ } r = dm_table_add_target(table, spec->target_type, - spec->sector_start, spec->length, + (sector_t) spec->sector_start, + (sector_t) spec->length, params); if (r) { DMWARN("internal error adding target to table"); @@ -558,7 +560,7 @@ int r; struct dm_table *t; struct mapped_device *md; - int minor; + unsigned int minor = 0; r = check_name(param->name); if (r) @@ -574,8 +576,8 @@ return r; } - minor = (param->flags & DM_PERSISTENT_DEV_FLAG) ? - minor(to_kdev_t(param->dev)) : -1; + if (param->flags & DM_PERSISTENT_DEV_FLAG) + minor = minor(to_kdev_t(param->dev)); r = dm_create(minor, t, &md); if (r) { @@ -584,7 +586,7 @@ } dm_table_put(t); /* md will have grabbed its own reference */ - set_disk_ro(dm_disk(md), (param->flags & DM_READONLY_FLAG)); + set_disk_ro(dm_disk(md), (param->flags & DM_READONLY_FLAG) ? 1 : 0); r = dm_hash_insert(param->name, *param->uuid ? param->uuid : NULL, md); dm_put(md); @@ -595,9 +597,9 @@ * Build up the status struct for each target */ static int __status(struct mapped_device *md, struct dm_ioctl *param, - char *outbuf, int *len) + char *outbuf, size_t *len) { - int i, num_targets; + unsigned int i, num_targets; struct dm_target_spec *spec; char *outptr; status_type_t type; @@ -657,7 +659,7 @@ static int get_status(struct dm_ioctl *param, struct dm_ioctl *user) { struct mapped_device *md; - int len = 0; + size_t len = 0; int ret; char *outbuf = NULL; @@ -738,7 +740,8 @@ */ static int dep(struct dm_ioctl *param, struct dm_ioctl *user) { - int count, r; + int r; + unsigned int count; struct mapped_device *md; struct list_head *tmp; size_t len = 0; @@ -889,7 +892,7 @@ } dm_table_put(t); /* md will have taken its own reference */ - set_disk_ro(dm_disk(md), (param->flags & DM_READONLY_FLAG)); + set_disk_ro(dm_disk(md), (param->flags & DM_READONLY_FLAG) ? 1 : 0); dm_put(md); r = info(param, user); @@ -945,7 +948,7 @@ * As well as checking the version compatibility this always * copies the kernel interface version out. */ -static int check_version(int cmd, struct dm_ioctl *user) +static int check_version(unsigned int cmd, struct dm_ioctl *user) { uint32_t version[3]; int r = 0; @@ -1028,7 +1031,8 @@ static int ctl_ioctl(struct inode *inode, struct file *file, uint command, ulong u) { - int r = 0, cmd; + int r = 0; + unsigned int cmd; struct dm_ioctl *param; struct dm_ioctl *user = (struct dm_ioctl *) u; ioctl_fn fn = NULL; diff -Nru a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c --- a/drivers/md/dm-linear.c Mon Jun 9 23:16:13 2003 +++ b/drivers/md/dm-linear.c Mon Jun 9 23:16:13 2003 @@ -23,7 +23,7 @@ /* * Construct a linear mapping: <dev_path> <offset> */ -static int linear_ctr(struct dm_target *ti, int argc, char **argv) +static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv) { struct linear_c *lc; @@ -76,7 +76,7 @@ } static int linear_status(struct dm_target *ti, status_type_t type, - char *result, int maxlen) + char *result, unsigned int maxlen) { struct linear_c *lc = (struct linear_c *) ti->private; char b[BDEVNAME_SIZE]; diff -Nru a/drivers/md/dm-stripe.c b/drivers/md/dm-stripe.c --- a/drivers/md/dm-stripe.c Mon Jun 9 23:16:11 2003 +++ b/drivers/md/dm-stripe.c Mon Jun 9 23:16:11 2003 @@ -30,7 +30,7 @@ struct stripe stripe[0]; }; -static inline struct stripe_c *alloc_context(int stripes) +static inline struct stripe_c *alloc_context(unsigned int stripes) { size_t len; @@ -47,7 +47,7 @@ * Parse a single <dev> <sector> pair */ static int get_stripe(struct dm_target *ti, struct stripe_c *sc, - int stripe, char **argv) + unsigned int stripe, char **argv) { sector_t start; @@ -91,14 +91,15 @@ * Construct a striped mapping. * <number of stripes> <chunk size (2^^n)> [<dev_path> <offset>]+ */ -static int stripe_ctr(struct dm_target *ti, int argc, char **argv) +static int stripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) { struct stripe_c *sc; sector_t width; uint32_t stripes; uint32_t chunk_size; char *end; - int r, i; + int r; + unsigned int i; if (argc < 2) { ti->error = "dm-stripe: Not enough arguments"; @@ -204,11 +205,11 @@ } static int stripe_status(struct dm_target *ti, - status_type_t type, char *result, int maxlen) + status_type_t type, char *result, unsigned int maxlen) { struct stripe_c *sc = (struct stripe_c *) ti->private; int offset; - int i; + unsigned int i; char b[BDEVNAME_SIZE]; switch (type) { diff -Nru a/drivers/md/dm-table.c b/drivers/md/dm-table.c --- a/drivers/md/dm-table.c Mon Jun 9 23:16:19 2003 +++ b/drivers/md/dm-table.c Mon Jun 9 23:16:19 2003 @@ -23,12 +23,12 @@ atomic_t holders; /* btree table */ - int depth; - int counts[MAX_DEPTH]; /* in nodes */ + unsigned int depth; + unsigned int counts[MAX_DEPTH]; /* in nodes */ sector_t *index[MAX_DEPTH]; - int num_targets; - int num_allocated; + unsigned int num_targets; + unsigned int num_allocated; sector_t *highs; struct dm_target *targets; @@ -56,14 +56,6 @@ }; /* - * Ceiling(n / size) - */ -static inline unsigned long div_up(unsigned long n, unsigned long size) -{ - return dm_round_up(n, size) / size; -} - -/* * Similar to ceiling(log_size(n)) */ static unsigned int int_log(unsigned long n, unsigned long base) @@ -71,35 +63,46 @@ int result = 0; while (n > 1) { - n = div_up(n, base); + n = dm_div_up(n, base); result++; } return result; } -#define __HIGH(l, r) if (*(l) < (r)) *(l) = (r) -#define __LOW(l, r) if (*(l) == 0 || *(l) > (r)) *(l) = (r) +/* + * Returns the minimum that is _not_ zero, unless both are zero. + */ +#define min_not_zero(l, r) (l == 0) ? r : ((r == 0) ? l : min(l, r)) /* * Combine two io_restrictions, always taking the lower value. */ - static void combine_restrictions_low(struct io_restrictions *lhs, struct io_restrictions *rhs) { - __LOW(&lhs->max_sectors, rhs->max_sectors); - __LOW(&lhs->max_phys_segments, rhs->max_phys_segments); - __LOW(&lhs->max_hw_segments, rhs->max_hw_segments); - __HIGH(&lhs->hardsect_size, rhs->hardsect_size); - __LOW(&lhs->max_segment_size, rhs->max_segment_size); - __LOW(&lhs->seg_boundary_mask, rhs->seg_boundary_mask); + lhs->max_sectors = + min_not_zero(lhs->max_sectors, rhs->max_sectors); + + lhs->max_phys_segments = + min_not_zero(lhs->max_phys_segments, rhs->max_phys_segments); + + lhs->max_hw_segments = + min_not_zero(lhs->max_hw_segments, rhs->max_hw_segments); + + lhs->hardsect_size = max(lhs->hardsect_size, rhs->hardsect_size); + + lhs->max_segment_size = + min_not_zero(lhs->max_segment_size, rhs->max_segment_size); + + lhs->seg_boundary_mask = + min_not_zero(lhs->seg_boundary_mask, rhs->seg_boundary_mask); } /* * Calculate the index of the child node of the n'th node k'th key. */ -static inline int get_child(int n, int k) +static inline unsigned int get_child(unsigned int n, unsigned int k) { return (n * CHILDREN_PER_NODE) + k; } @@ -107,7 +110,8 @@ /* * Return the n'th node of level l from table t. */ -static inline sector_t *get_node(struct dm_table *t, int l, int n) +static inline sector_t *get_node(struct dm_table *t, + unsigned int l, unsigned int n) { return t->index[l] + (n * KEYS_PER_NODE); } @@ -116,7 +120,7 @@ * Return the highest key that you could lookup from the n'th * node on level l of the btree. */ -static sector_t high(struct dm_table *t, int l, int n) +static sector_t high(struct dm_table *t, unsigned int l, unsigned int n) { for (; l < t->depth - 1; l++) n = get_child(n, CHILDREN_PER_NODE - 1); @@ -131,15 +135,15 @@ * Fills in a level of the btree based on the highs of the level * below it. */ -static int setup_btree_index(int l, struct dm_table *t) +static int setup_btree_index(unsigned int l, struct dm_table *t) { - int n, k; + unsigned int n, k; sector_t *node; - for (n = 0; n < t->counts[l]; n++) { + for (n = 0U; n < t->counts[l]; n++) { node = get_node(t, l, n); - for (k = 0; k < KEYS_PER_NODE; k++) + for (k = 0U; k < KEYS_PER_NODE; k++) node[k] = high(t, l + 1, get_child(n, k)); } @@ -169,7 +173,7 @@ * highs, and targets are managed as dynamic arrays during a * table load. */ -static int alloc_targets(struct dm_table *t, int num) +static int alloc_targets(struct dm_table *t, unsigned int num) { sector_t *n_highs; struct dm_target *n_targets; @@ -237,9 +241,7 @@ void table_destroy(struct dm_table *t) { - int i; - - DMWARN("destroying table"); + unsigned int i; /* destroying the table counts as an event */ dm_table_event(t); @@ -481,13 +483,31 @@ request_queue_t *q = bdev_get_queue((*result)->bdev); struct io_restrictions *rs = &ti->limits; - /* combine the device limits low */ - __LOW(&rs->max_sectors, q->max_sectors); - __LOW(&rs->max_phys_segments, q->max_phys_segments); - __LOW(&rs->max_hw_segments, q->max_hw_segments); - __HIGH(&rs->hardsect_size, q->hardsect_size); - __LOW(&rs->max_segment_size, q->max_segment_size); - __LOW(&rs->seg_boundary_mask, q->seg_boundary_mask); + /* + * Combine the device limits low. + * + * FIXME: if we move an io_restriction struct + * into q this would just be a call to + * combine_restrictions_low() + */ + rs->max_sectors = + min_not_zero(rs->max_sectors, q->max_sectors); + + rs->max_phys_segments = + min_not_zero(rs->max_phys_segments, + q->max_phys_segments); + + rs->max_hw_segments = + min_not_zero(rs->max_hw_segments, q->max_hw_segments); + + rs->hardsect_size = max(rs->hardsect_size, q->hardsect_size); + + rs->max_segment_size = + min_not_zero(rs->max_segment_size, q->max_segment_size); + + rs->seg_boundary_mask = + min_not_zero(rs->seg_boundary_mask, + q->seg_boundary_mask); } return r; @@ -628,12 +648,13 @@ static int setup_indexes(struct dm_table *t) { - int i, total = 0; + int i; + unsigned int total = 0; sector_t *indexes; /* allocate the space for *all* the indexes */ for (i = t->depth - 2; i >= 0; i--) { - t->counts[i] = div_up(t->counts[i + 1], CHILDREN_PER_NODE); + t->counts[i] = dm_div_up(t->counts[i + 1], CHILDREN_PER_NODE); total += t->counts[i]; } @@ -656,10 +677,11 @@ */ int dm_table_complete(struct dm_table *t) { - int leaf_nodes, r = 0; + int r = 0; + unsigned int leaf_nodes; /* how many indexes will the btree have ? */ - leaf_nodes = div_up(t->num_targets, KEYS_PER_NODE); + leaf_nodes = dm_div_up(t->num_targets, KEYS_PER_NODE); t->depth = 1 + int_log(leaf_nodes, CHILDREN_PER_NODE); /* leaf layer has already been set up */ @@ -682,7 +704,7 @@ return t->num_targets ? (t->highs[t->num_targets - 1] + 1) : 0; } -struct dm_target *dm_table_get_target(struct dm_table *t, int index) +struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index) { if (index > t->num_targets) return NULL; @@ -695,7 +717,7 @@ */ struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector) { - int l, n = 0, k = 0; + unsigned int l, n = 0, k = 0; sector_t *node; for (l = 0; l < t->depth; l++) { @@ -743,6 +765,31 @@ { add_wait_queue(&t->eventq, wq); } + +void dm_table_suspend_targets(struct dm_table *t) +{ + int i; + + for (i = 0; i < t->num_targets; i++) { + struct dm_target *ti = t->targets + i; + + if (ti->type->suspend) + ti->type->suspend(ti); + } +} + +void dm_table_resume_targets(struct dm_table *t) +{ + int i; + + for (i = 0; i < t->num_targets; i++) { + struct dm_target *ti = t->targets + i; + + if (ti->type->resume) + ti->type->resume(ti); + } +} + EXPORT_SYMBOL(dm_get_device); EXPORT_SYMBOL(dm_put_device); diff -Nru a/drivers/md/dm-target.c b/drivers/md/dm-target.c --- a/drivers/md/dm-target.c Mon Jun 9 23:16:19 2003 +++ b/drivers/md/dm-target.c Mon Jun 9 23:16:19 2003 @@ -109,9 +109,10 @@ return -ENOMEM; down_write(&_lock); - if (__find_target_type(t->name)) + if (__find_target_type(t->name)) { + kfree(ti); rv = -EEXIST; - else + } else list_add(&ti->list, &_targets); up_write(&_lock); @@ -146,7 +147,7 @@ * io-err: always fails an io, useful for bringing * up LVs that have holes in them. */ -static int io_err_ctr(struct dm_target *ti, int argc, char **args) +static int io_err_ctr(struct dm_target *ti, unsigned int argc, char **args) { return 0; } diff -Nru a/drivers/md/dm.c b/drivers/md/dm.c --- a/drivers/md/dm.c Mon Jun 9 23:16:16 2003 +++ b/drivers/md/dm.c Mon Jun 9 23:16:16 2003 @@ -17,8 +17,8 @@ static const char *_name = DM_NAME; #define MAX_DEVICES 1024 -static int major = 0; -static int _major = 0; +static unsigned int major = 0; +static unsigned int _major = 0; struct dm_io { struct mapped_device *md; @@ -281,9 +281,6 @@ sector_t offset = sector - ti->begin; sector_t len = ti->len - offset; - /* FIXME: obey io_restrictions ! */ - - /* * Does the target need to split even further ? */ @@ -524,7 +521,7 @@ static spinlock_t _minor_lock = SPIN_LOCK_UNLOCKED; static unsigned long _minor_bits[MAX_DEVICES / BITS_PER_LONG]; -static void free_minor(int minor) +static void free_minor(unsigned int minor) { spin_lock(&_minor_lock); clear_bit(minor, _minor_bits); @@ -534,7 +531,7 @@ /* * See if the device with a specific minor # is free. */ -static int specific_minor(int minor) +static int specific_minor(unsigned int minor) { int r = -EBUSY; @@ -546,21 +543,23 @@ spin_lock(&_minor_lock); if (!test_and_set_bit(minor, _minor_bits)) - r = minor; + r = 0; spin_unlock(&_minor_lock); return r; } -static int next_free_minor(void) +static int next_free_minor(unsigned int *minor) { - int minor, r = -EBUSY; + int r = -EBUSY; + unsigned int m; spin_lock(&_minor_lock); - minor = find_first_zero_bit(_minor_bits, MAX_DEVICES); - if (minor != MAX_DEVICES) { - set_bit(minor, _minor_bits); - r = minor; + m = find_first_zero_bit(_minor_bits, MAX_DEVICES); + if (m != MAX_DEVICES) { + set_bit(m, _minor_bits); + *minor = m; + r = 0; } spin_unlock(&_minor_lock); @@ -570,8 +569,9 @@ /* * Allocate and initialise a blank device with a given minor. */ -static struct mapped_device *alloc_dev(int minor) +static struct mapped_device *alloc_dev(unsigned int minor) { + int r; struct mapped_device *md = kmalloc(sizeof(*md), GFP_KERNEL); if (!md) { @@ -580,13 +580,12 @@ } /* get a minor number for the dev */ - minor = (minor < 0) ? next_free_minor() : specific_minor(minor); - if (minor < 0) { + r = (minor < 0) ? next_free_minor(&minor) : specific_minor(minor); + if (r < 0) { kfree(md); return NULL; } - DMWARN("allocating minor %d.", minor); memset(md, 0, sizeof(*md)); init_rwsem(&md->lock); atomic_set(&md->holders, 1); @@ -597,7 +596,7 @@ md->io_pool = mempool_create(MIN_IOS, mempool_alloc_slab, mempool_free_slab, _io_cache); if (!md->io_pool) { - free_minor(md->disk->first_minor); + free_minor(minor); kfree(md); return NULL; } @@ -605,7 +604,7 @@ md->disk = alloc_disk(1); if (!md->disk) { mempool_destroy(md->io_pool); - free_minor(md->disk->first_minor); + free_minor(minor); kfree(md); return NULL; } @@ -661,7 +660,8 @@ /* * Constructor for a new device. */ -int dm_create(int minor, struct dm_table *table, struct mapped_device **result) +int dm_create(unsigned int minor, struct dm_table *table, + struct mapped_device **result) { int r; struct mapped_device *md; @@ -675,6 +675,7 @@ free_dev(md); return r; } + dm_table_resume_targets(md->map); *result = md; return 0; @@ -688,7 +689,8 @@ void dm_put(struct mapped_device *md) { if (atomic_dec_and_test(&md->holders)) { - DMWARN("destroying md"); + if (!test_bit(DMF_SUSPENDED, &md->flags)) + dm_table_suspend_targets(md->map); __unbind(md); free_dev(md); } @@ -778,6 +780,7 @@ down_write(&md->lock); remove_wait_queue(&md->wait, &wait); set_bit(DMF_SUSPENDED, &md->flags); + dm_table_suspend_targets(md->map); up_write(&md->lock); return 0; @@ -794,6 +797,7 @@ return -EINVAL; } + dm_table_resume_targets(md->map); clear_bit(DMF_SUSPENDED, &md->flags); clear_bit(DMF_BLOCK_IO, &md->flags); def = md->deferred; diff -Nru a/drivers/md/dm.h b/drivers/md/dm.h --- a/drivers/md/dm.h Mon Jun 9 23:16:11 2003 +++ b/drivers/md/dm.h Mon Jun 9 23:16:11 2003 @@ -51,7 +51,8 @@ * Functions for manipulating a struct mapped_device. * Drop the reference with dm_put when you finish with the object. *---------------------------------------------------------------*/ -int dm_create(int minor, struct dm_table *table, struct mapped_device **md); +int dm_create(unsigned int minor, struct dm_table *table, + struct mapped_device **md); /* * Reference counting for md. @@ -96,13 +97,15 @@ int dm_table_complete(struct dm_table *t); void dm_table_event(struct dm_table *t); sector_t dm_table_get_size(struct dm_table *t); -struct dm_target *dm_table_get_target(struct dm_table *t, int index); +struct dm_target *dm_table_get_target(struct dm_table *t, unsigned int index); struct dm_target *dm_table_find_target(struct dm_table *t, sector_t sector); void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q); unsigned int dm_table_get_num_targets(struct dm_table *t); struct list_head *dm_table_get_devices(struct dm_table *t); int dm_table_get_mode(struct dm_table *t); void dm_table_add_wait_queue(struct dm_table *t, wait_queue_t *wq); +void dm_table_suspend_targets(struct dm_table *t); +void dm_table_resume_targets(struct dm_table *t); /*----------------------------------------------------------------- * A registry of target types. @@ -129,6 +132,14 @@ { unsigned long r = n % size; return n + (r ? (size - r) : 0); +} + +/* + * Ceiling(n / size) + */ +static inline unsigned long dm_div_up(unsigned long n, unsigned long size) +{ + return dm_round_up(n, size) / size; } /* diff -Nru a/drivers/md/linear.c b/drivers/md/linear.c --- a/drivers/md/linear.c Mon Jun 9 23:16:10 2003 +++ b/drivers/md/linear.c Mon Jun 9 23:16:10 2003 @@ -20,7 +20,6 @@ #include <linux/raid/md.h> #include <linux/slab.h> -#include <linux/bio.h> #include <linux/raid/linear.h> #define MAJOR_NR MD_MAJOR @@ -67,7 +66,18 @@ dev0 = which_dev(mddev, bio->bi_sector); maxsectors = (dev0->size << 1) - (bio->bi_sector - (dev0->offset<<1)); - return (maxsectors - bio_sectors) << 9; + if (maxsectors < bio_sectors) + maxsectors = 0; + else + maxsectors -= bio_sectors; + + if (maxsectors <= (PAGE_SIZE >> 9 ) && bio_sectors == 0) + return biovec->bv_len; + /* The bytes available at this offset could be really big, + * so we cap at 2^31 to avoid overflow */ + if (maxsectors > (1 << (31-9))) + return 1<<31; + return maxsectors << 9; } static int linear_run (mddev_t *mddev) @@ -79,7 +89,8 @@ unsigned int curr_offset; struct list_head *tmp; - conf = kmalloc (sizeof (*conf), GFP_KERNEL); + conf = kmalloc (sizeof (*conf) + mddev->raid_disks*sizeof(dev_info_t), + GFP_KERNEL); if (!conf) goto out; memset(conf, 0, sizeof(*conf)); @@ -209,6 +220,23 @@ bio_io_error(bio, bio->bi_size); return 0; } + if (unlikely(bio->bi_sector + (bio->bi_size >> 9) > + (tmp_dev->offset + tmp_dev->size)<<1)) { + /* This bio crosses a device boundary, so we have to + * split it. + */ + struct bio_pair *bp; + bp = bio_split(bio, bio_split_pool, + (bio->bi_sector + (bio->bi_size >> 9) - + (tmp_dev->offset + tmp_dev->size))<<1); + if (linear_make_request(q, &bp->bio1)) + generic_make_request(&bp->bio1); + if (linear_make_request(q, &bp->bio2)) + generic_make_request(&bp->bio2); + bio_pair_release(bp); + return 0; + } + bio->bi_bdev = tmp_dev->rdev->bdev; bio->bi_sector = bio->bi_sector - (tmp_dev->offset << 1) + tmp_dev->rdev->data_offset; @@ -226,12 +254,13 @@ seq_printf(seq, " "); for (j = 0; j < conf->nr_zones; j++) { + char b[BDEVNAME_SIZE]; seq_printf(seq, "[%s", - bdev_partition_name(conf->hash_table[j].dev0->rdev->bdev)); + bdevname(conf->hash_table[j].dev0->rdev->bdev,b)); if (conf->hash_table[j].dev1) seq_printf(seq, "/%s] ", - bdev_partition_name(conf->hash_table[j].dev1->rdev->bdev)); + bdevname(conf->hash_table[j].dev1->rdev->bdev,b)); else seq_printf(seq, "] "); } diff -Nru a/drivers/md/md.c b/drivers/md/md.c --- a/drivers/md/md.c Mon Jun 9 23:16:09 2003 +++ b/drivers/md/md.c Mon Jun 9 23:16:09 2003 @@ -33,7 +33,6 @@ #include <linux/linkage.h> #include <linux/raid/md.h> #include <linux/sysctl.h> -#include <linux/bio.h> #include <linux/devfs_fs_kernel.h> #include <linux/buffer_head.h> /* for invalidate_bdev */ #include <linux/suspend.h> @@ -350,7 +349,7 @@ static int read_disk_sb(mdk_rdev_t * rdev) { - + char b[BDEVNAME_SIZE]; if (!rdev->sb_page) { MD_BUG(); return -EINVAL; @@ -366,7 +365,7 @@ fail: printk(KERN_ERR "md: disabled device %s, could not read superblock.\n", - bdev_partition_name(rdev->bdev)); + bdevname(rdev->bdev,b)); return -EINVAL; } @@ -474,6 +473,7 @@ */ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev, int minor_version) { + char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE]; mdp_super_t *sb; int ret; sector_t sb_offset; @@ -492,11 +492,12 @@ ret = -EINVAL; + bdevname(rdev->bdev, b); sb = (mdp_super_t*)page_address(rdev->sb_page); if (sb->md_magic != MD_SB_MAGIC) { printk(KERN_ERR "md: invalid raid superblock magic on %s\n", - bdev_partition_name(rdev->bdev)); + b); goto abort; } @@ -504,13 +505,13 @@ sb->minor_version != 90) { printk(KERN_WARNING "Bad version number %d.%d on %s\n", sb->major_version, sb->minor_version, - bdev_partition_name(rdev->bdev)); + b); goto abort; } if (sb->md_minor >= MAX_MD_DEVS) { printk(KERN_ERR "md: %s: invalid raid minor (%x)\n", - bdev_partition_name(rdev->bdev), sb->md_minor); + b, sb->md_minor); goto abort; } if (sb->raid_disks <= 0) @@ -518,7 +519,7 @@ if (calc_sb_csum(sb) != sb->sb_csum) { printk(KERN_WARNING "md: invalid superblock checksum on %s\n", - bdev_partition_name(rdev->bdev)); + b); goto abort; } @@ -537,15 +538,13 @@ mdp_super_t *refsb = (mdp_super_t*)page_address(refdev->sb_page); if (!uuid_equal(refsb, sb)) { printk(KERN_WARNING "md: %s has different UUID to %s\n", - bdev_partition_name(rdev->bdev), - bdev_partition_name(refdev->bdev)); + b, bdevname(refdev->bdev,b2)); goto abort; } if (!sb_equal(refsb, sb)) { printk(KERN_WARNING "md: %s has same UUID" - " but different superblock to %s\n", - bdev_partition_name(rdev->bdev), - bdev_partition_name(refdev->bdev)); + " but different superblock to %s\n", + b, bdevname(refdev->bdev, b2)); goto abort; } ev1 = md_event(sb); @@ -757,6 +756,7 @@ struct mdp_superblock_1 *sb; int ret; sector_t sb_offset; + char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE]; /* * Calculate the position of the superblock. @@ -800,7 +800,7 @@ if (calc_sb_1_csum(sb) != sb->sb_csum) { printk("md: invalid superblock checksum on %s\n", - bdev_partition_name(rdev->bdev)); + bdevname(rdev->bdev,b)); return -EINVAL; } rdev->preferred_minor = 0xffff; @@ -819,8 +819,8 @@ sb->chunksize != refsb->chunksize) { printk(KERN_WARNING "md: %s has strangely different" " superblock to %s\n", - bdev_partition_name(rdev->bdev), - bdev_partition_name(refdev->bdev)); + bdevname(rdev->bdev,b), + bdevname(refdev->bdev,b2)); return -EINVAL; } ev1 = le64_to_cpu(sb->events); @@ -988,6 +988,7 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev) { mdk_rdev_t *same_pdev; + char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE]; if (rdev->mddev) { MD_BUG(); @@ -999,8 +1000,8 @@ "md%d: WARNING: %s appears to be on the same physical" " disk as %s. True\n protection against single-disk" " failure might be compromised.\n", - mdidx(mddev), bdev_partition_name(rdev->bdev), - bdev_partition_name(same_pdev->bdev)); + mdidx(mddev), bdevname(rdev->bdev,b), + bdevname(same_pdev->bdev,b2)); /* Verify rdev->desc_nr is unique. * If it is -1, assign a free number, else @@ -1019,18 +1020,19 @@ list_add(&rdev->same_set, &mddev->disks); rdev->mddev = mddev; - printk(KERN_INFO "md: bind<%s>\n", bdev_partition_name(rdev->bdev)); + printk(KERN_INFO "md: bind<%s>\n", bdevname(rdev->bdev,b)); return 0; } static void unbind_rdev_from_array(mdk_rdev_t * rdev) { + char b[BDEVNAME_SIZE]; if (!rdev->mddev) { MD_BUG(); return; } list_del_init(&rdev->same_set); - printk(KERN_INFO "md: unbind<%s>\n", bdev_partition_name(rdev->bdev)); + printk(KERN_INFO "md: unbind<%s>\n", bdevname(rdev->bdev,b)); rdev->mddev = NULL; } @@ -1072,8 +1074,9 @@ static void export_rdev(mdk_rdev_t * rdev) { + char b[BDEVNAME_SIZE]; printk(KERN_INFO "md: export_rdev(%s)\n", - bdev_partition_name(rdev->bdev)); + bdevname(rdev->bdev,b)); if (rdev->mddev) MD_BUG(); free_disk_sb(rdev); @@ -1154,8 +1157,9 @@ static void print_rdev(mdk_rdev_t *rdev) { + char b[BDEVNAME_SIZE]; printk(KERN_INFO "md: rdev %s, SZ:%08llu F:%d S:%d DN:%u\n", - bdev_partition_name(rdev->bdev), (unsigned long long)rdev->size, + bdevname(rdev->bdev,b), (unsigned long long)rdev->size, rdev->faulty, rdev->in_sync, rdev->desc_nr); if (rdev->sb_loaded) { printk(KERN_INFO "md: rdev superblock:\n"); @@ -1169,6 +1173,7 @@ struct list_head *tmp, *tmp2; mdk_rdev_t *rdev; mddev_t *mddev; + char b[BDEVNAME_SIZE]; printk("\n"); printk("md: **********************************\n"); @@ -1178,7 +1183,7 @@ printk("md%d: ", mdidx(mddev)); ITERATE_RDEV(mddev,rdev,tmp2) - printk("<%s>", bdev_partition_name(rdev->bdev)); + printk("<%s>", bdevname(rdev->bdev,b)); printk("\n"); ITERATE_RDEV(mddev,rdev,tmp2) @@ -1191,7 +1196,7 @@ static int write_disk_sb(mdk_rdev_t * rdev) { - + char b[BDEVNAME_SIZE]; if (!rdev->sb_loaded) { MD_BUG(); return 1; @@ -1202,14 +1207,14 @@ } dprintk(KERN_INFO "(write) %s's sb offset: %llu\n", - bdev_partition_name(rdev->bdev), + bdevname(rdev->bdev,b), (unsigned long long)rdev->sb_offset); if (sync_page_io(rdev->bdev, rdev->sb_offset<<1, MD_SB_BYTES, rdev->sb_page, WRITE)) return 0; printk("md: write_disk_sb failed for device %s\n", - bdev_partition_name(rdev->bdev)); + bdevname(rdev->bdev,b)); return 1; } @@ -1260,11 +1265,12 @@ err = 0; ITERATE_RDEV(mddev,rdev,tmp) { + char b[BDEVNAME_SIZE]; dprintk(KERN_INFO "md: "); if (rdev->faulty) dprintk("(skipping faulty "); - dprintk("%s ", bdev_partition_name(rdev->bdev)); + dprintk("%s ", bdevname(rdev->bdev,b)); if (!rdev->faulty) { err += write_disk_sb(rdev); } else @@ -1328,7 +1334,7 @@ if (!size) { printk(KERN_WARNING "md: %s has zero or unknown size, marking faulty!\n", - bdev_partition_name(rdev->bdev)); + bdevname(rdev->bdev,b)); err = -EINVAL; goto abort_free; } @@ -1339,13 +1345,13 @@ if (err == -EINVAL) { printk(KERN_WARNING "md: %s has invalid sb, not importing!\n", - bdev_partition_name(rdev->bdev)); + bdevname(rdev->bdev,b)); goto abort_free; } if (err < 0) { printk(KERN_WARNING "md: could not read %s's sb, not importing!\n", - bdev_partition_name(rdev->bdev)); + bdevname(rdev->bdev,b)); goto abort_free; } } @@ -1373,6 +1379,7 @@ int i; struct list_head *tmp; mdk_rdev_t *rdev, *freshest; + char b[BDEVNAME_SIZE]; freshest = NULL; ITERATE_RDEV(mddev,rdev,tmp) @@ -1387,7 +1394,7 @@ printk( KERN_ERR \ "md: fatal superblock inconsistency in %s" " -- removing from array\n", - bdev_partition_name(rdev->bdev)); + bdevname(rdev->bdev,b)); kick_rdev_from_array(rdev); } @@ -1402,7 +1409,7 @@ validate_super(mddev, rdev)) { printk(KERN_WARNING "md: kicking non-fresh %s" " from array!\n", - bdev_partition_name(rdev->bdev)); + bdevname(rdev->bdev,b)); kick_rdev_from_array(rdev); continue; } @@ -1490,6 +1497,7 @@ struct list_head *tmp; mdk_rdev_t *rdev; struct gendisk *disk; + char b[BDEVNAME_SIZE]; if (list_empty(&mddev->disks)) { MD_BUG(); @@ -1548,7 +1556,7 @@ printk(KERN_WARNING "md: Dev %s smaller than chunk_size:" " %lluk < %dk\n", - bdev_partition_name(rdev->bdev), + bdevname(rdev->bdev,b), (unsigned long long)rdev->size, chunk_size / 1024); return -EINVAL; @@ -1670,13 +1678,12 @@ int err = 0; struct gendisk *disk = disks[mdidx(mddev)]; - if (atomic_read(&mddev->active)>2) { - printk("md: md%d still in use.\n",mdidx(mddev)); - err = -EBUSY; - goto out; - } - if (mddev->pers) { + if (atomic_read(&mddev->active)>2) { + printk("md: md%d still in use.\n",mdidx(mddev)); + return -EBUSY; + } + if (mddev->sync_thread) { set_bit(MD_RECOVERY_INTR, &mddev->recovery); md_unregister_thread(mddev->sync_thread); @@ -1749,7 +1756,8 @@ printk(KERN_INFO "md: running: "); ITERATE_RDEV(mddev,rdev,tmp) { - printk("<%s>", bdev_partition_name(rdev->bdev)); + char b[BDEVNAME_SIZE]; + printk("<%s>", bdevname(rdev->bdev,b)); } printk("\n"); @@ -1778,6 +1786,7 @@ struct list_head *tmp; mdk_rdev_t *rdev0, *rdev; mddev_t *mddev; + char b[BDEVNAME_SIZE]; printk(KERN_INFO "md: autorun ...\n"); while (!list_empty(&pending_raid_disks)) { @@ -1785,12 +1794,12 @@ mdk_rdev_t, same_set); printk(KERN_INFO "md: considering %s ...\n", - bdev_partition_name(rdev0->bdev)); + bdevname(rdev0->bdev,b)); INIT_LIST_HEAD(&candidates); ITERATE_RDEV_PENDING(rdev,tmp) if (super_90_load(rdev, rdev0, 0) >= 0) { printk(KERN_INFO "md: adding %s ...\n", - bdev_partition_name(rdev->bdev)); + bdevname(rdev->bdev,b)); list_move(&rdev->same_set, &candidates); } /* @@ -1812,7 +1821,7 @@ || !list_empty(&mddev->disks)) { printk(KERN_WARNING "md: md%d already running, cannot run %s\n", - mdidx(mddev), bdev_partition_name(rdev0->bdev)); + mdidx(mddev), bdevname(rdev0->bdev,b)); mddev_unlock(mddev); } else { printk(KERN_INFO "md: created md%d\n", mdidx(mddev)); @@ -1865,7 +1874,7 @@ if (start_rdev->faulty) { printk(KERN_WARNING "md: can not autostart based on faulty %s!\n", - bdev_partition_name(start_rdev->bdev)); + bdevname(start_rdev->bdev,b)); export_rdev(start_rdev); return err; } @@ -2002,6 +2011,7 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info) { + char b[BDEVNAME_SIZE], b2[BDEVNAME_SIZE]; mdk_rdev_t *rdev; dev_t dev; dev = MKDEV(info->major,info->minor); @@ -2023,8 +2033,8 @@ if (err < 0) { printk(KERN_WARNING "md: %s has different UUID to %s\n", - bdev_partition_name(rdev->bdev), - bdev_partition_name(rdev0->bdev)); + bdevname(rdev->bdev,b), + bdevname(rdev0->bdev,b2)); export_rdev(rdev); return -EINVAL; } @@ -2176,7 +2186,7 @@ return 0; busy: printk(KERN_WARNING "md: cannot remove active disk %s from md%d ... \n", - bdev_partition_name(rdev->bdev), mdidx(mddev)); + bdevname(rdev->bdev,b), mdidx(mddev)); return -EBUSY; } @@ -2230,7 +2240,7 @@ if (rdev->faulty) { printk(KERN_WARNING "md: can not hot-add faulty %s disk to md%d!\n", - bdev_partition_name(rdev->bdev), mdidx(mddev)); + bdevname(rdev->bdev,b), mdidx(mddev)); err = -EINVAL; goto abort_export; } @@ -2783,9 +2793,10 @@ seq_printf(seq, "unused devices: "); ITERATE_RDEV_PENDING(rdev,tmp) { + char b[BDEVNAME_SIZE]; i++; seq_printf(seq, "%s ", - bdev_partition_name(rdev->bdev)); + bdevname(rdev->bdev,b)); } if (!i) seq_printf(seq, "<none>"); @@ -2849,7 +2860,7 @@ loff_t l = *pos; mddev_t *mddev; - if (l > 0x10000) + if (l >= 0x10000) return NULL; if (!l--) /* header */ @@ -2864,7 +2875,9 @@ return mddev; } spin_unlock(&all_mddevs_lock); - return (void*)2;/* tail */ + if (!l--) + return (void*)2;/* tail */ + return NULL; } static void *md_seq_next(struct seq_file *seq, void *v, loff_t *pos) @@ -2940,8 +2953,9 @@ size = 0; ITERATE_RDEV(mddev,rdev,tmp2) { + char b[BDEVNAME_SIZE]; seq_printf(seq, " %s[%d]", - bdev_partition_name(rdev->bdev), rdev->desc_nr); + bdevname(rdev->bdev,b), rdev->desc_nr); if (rdev->faulty) { seq_printf(seq, "(F)"); continue; diff -Nru a/drivers/md/multipath.c b/drivers/md/multipath.c --- a/drivers/md/multipath.c Mon Jun 9 23:16:11 2003 +++ b/drivers/md/multipath.c Mon Jun 9 23:16:11 2003 @@ -23,7 +23,6 @@ #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/raid/multipath.h> -#include <linux/bio.h> #include <linux/buffer_head.h> #include <asm/atomic.h> @@ -59,7 +58,7 @@ static int multipath_map (mddev_t *mddev, mdk_rdev_t **rdevp) { multipath_conf_t *conf = mddev_to_conf(mddev); - int i, disks = mddev->max_disks; + int i, disks = conf->raid_disks; /* * Later we do read balancing on the read side @@ -128,9 +127,10 @@ /* * oops, IO error: */ + char b[BDEVNAME_SIZE]; md_error (mp_bh->mddev, rdev); printk(KERN_ERR "multipath: %s: rescheduling sector %llu\n", - bdev_partition_name(rdev->bdev), + bdevname(rdev->bdev,b), (unsigned long long)bio->bi_sector); multipath_reschedule_retry(mp_bh); } @@ -147,7 +147,7 @@ { int disk; - for (disk = 0; disk < conf->mddev->max_disks; disk++) { + for (disk = 0; disk < conf->raid_disks; disk++) { mdk_rdev_t *rdev = conf->multipaths[disk].rdev; if (rdev && rdev->in_sync) return disk; @@ -221,6 +221,7 @@ * Mark disk as unusable */ if (!rdev->faulty) { + char b[BDEVNAME_SIZE]; rdev->in_sync = 0; rdev->faulty = 1; mddev->sb_dirty = 1; @@ -228,7 +229,7 @@ printk(KERN_ALERT "multipath: IO failure on %s," " disabling IO path. \n Operation continuing" " on %d IO paths.\n", - bdev_partition_name (rdev->bdev), + bdevname (rdev->bdev,b), conf->working_disks); } } @@ -247,12 +248,13 @@ printk(" --- wd:%d rd:%d\n", conf->working_disks, conf->raid_disks); - for (i = 0; i < conf->mddev->max_disks; i++) { + for (i = 0; i < conf->raid_disks; i++) { + char b[BDEVNAME_SIZE]; tmp = conf->multipaths + i; if (tmp->rdev) printk(" disk%d, o:%d, dev:%s\n", i,!tmp->rdev->faulty, - bdev_partition_name(tmp->rdev->bdev)); + bdevname(tmp->rdev->bdev,b)); } } @@ -327,6 +329,7 @@ md_check_recovery(mddev); for (;;) { + char b[BDEVNAME_SIZE]; spin_lock_irqsave(&retry_list_lock, flags); mp_bh = multipath_retry_list; if (!mp_bh) @@ -342,13 +345,13 @@ if (multipath_map (mddev, &rdev)<0) { printk(KERN_ALERT "multipath: %s: unrecoverable IO read" " error for block %llu\n", - bdev_partition_name(bio->bi_bdev), + bdevname(bio->bi_bdev,b), (unsigned long long)bio->bi_sector); multipath_end_bh_io(mp_bh, 0); } else { printk(KERN_ERR "multipath: %s: redirecting sector %llu" " to another IO path\n", - bdev_partition_name(bio->bi_bdev), + bdevname(bio->bi_bdev,b), (unsigned long long)bio->bi_sector); bio->bi_bdev = rdev->bdev; generic_make_request(bio); @@ -386,6 +389,15 @@ } memset(conf, 0, sizeof(*conf)); + conf->multipaths = kmalloc(sizeof(struct multipath_info)*mddev->raid_disks, + GFP_KERNEL); + if (!conf->multipaths) { + printk(KERN_ERR + "multipath: couldn't allocate memory for md%d\n", + mdidx(mddev)); + goto out_free_conf; + } + conf->working_disks = 0; ITERATE_RDEV(mddev,rdev,tmp) { disk_idx = rdev->raid_disk; @@ -444,6 +456,8 @@ out_free_conf: if (conf->pool) mempool_destroy(conf->pool); + if (conf->multipaths) + kfree(conf->multipaths); kfree(conf); mddev->private = NULL; out: @@ -457,6 +471,7 @@ md_unregister_thread(mddev->thread); mempool_destroy(conf->pool); + kfree(conf->multipaths); kfree(conf); mddev->private = NULL; return 0; diff -Nru a/drivers/md/raid0.c b/drivers/md/raid0.c --- a/drivers/md/raid0.c Mon Jun 9 23:16:13 2003 +++ b/drivers/md/raid0.c Mon Jun 9 23:16:13 2003 @@ -20,7 +20,6 @@ #include <linux/module.h> #include <linux/raid/raid0.h> -#include <linux/bio.h> #define MAJOR_NR MD_MAJOR #define MD_DRIVER @@ -31,11 +30,13 @@ { int i, c, j; sector_t current_offset, curr_zone_offset; + sector_t min_spacing; raid0_conf_t *conf = mddev_to_conf(mddev); mdk_rdev_t *smallest, *rdev1, *rdev2, *rdev; struct list_head *tmp1, *tmp2; struct strip_zone *zone; int cnt; + char b[BDEVNAME_SIZE]; /* * The number of 'same size groups' @@ -44,14 +45,15 @@ ITERATE_RDEV(mddev,rdev1,tmp1) { printk("raid0: looking at %s\n", - bdev_partition_name(rdev1->bdev)); + bdevname(rdev1->bdev,b)); c = 0; ITERATE_RDEV(mddev,rdev2,tmp2) { - printk("raid0: comparing %s(%llu) with %s(%llu)\n", - bdev_partition_name(rdev1->bdev), - (unsigned long long)rdev1->size, - bdev_partition_name(rdev2->bdev), - (unsigned long long)rdev2->size); + printk("raid0: comparing %s(%llu)", + bdevname(rdev1->bdev,b), + (unsigned long long)rdev1->size); + printk(" with %s(%llu)\n", + bdevname(rdev2->bdev,b), + (unsigned long long)rdev2->size); if (rdev2 == rdev1) { printk("raid0: END\n"); break; @@ -76,19 +78,25 @@ } printk("raid0: FINAL %d zones\n", conf->nr_strip_zones); - conf->strip_zone = vmalloc(sizeof(struct strip_zone)* - conf->nr_strip_zones); + conf->strip_zone = kmalloc(sizeof(struct strip_zone)* + conf->nr_strip_zones, GFP_KERNEL); if (!conf->strip_zone) return 1; + conf->devlist = kmalloc(sizeof(mdk_rdev_t*)* + conf->nr_strip_zones*mddev->raid_disks, + GFP_KERNEL); + if (!conf->devlist) + return 1; memset(conf->strip_zone, 0,sizeof(struct strip_zone)* conf->nr_strip_zones); /* The first zone must contain all devices, so here we check that - * there is a properly alignment of slots to devices and find them all + * there is a proper alignment of slots to devices and find them all */ zone = &conf->strip_zone[0]; cnt = 0; smallest = NULL; + zone->dev = conf->devlist; ITERATE_RDEV(mddev, rdev1, tmp1) { int j = rdev1->raid_disk; @@ -115,7 +123,6 @@ zone->size = smallest->size * cnt; zone->zone_offset = 0; - conf->smallest = zone; current_offset = smallest->size; curr_zone_offset = zone->size; @@ -123,6 +130,7 @@ for (i = 1; i < conf->nr_strip_zones; i++) { zone = conf->strip_zone + i; + zone->dev = conf->strip_zone[i-1].dev + mddev->raid_disks; printk("raid0: zone %d\n", i); zone->dev_offset = current_offset; @@ -130,8 +138,9 @@ c = 0; for (j=0; j<cnt; j++) { + char b[BDEVNAME_SIZE]; rdev = conf->strip_zone[0].dev[j]; - printk("raid0: checking %s ...", bdev_partition_name(rdev->bdev)); + printk("raid0: checking %s ...", bdevname(rdev->bdev,b)); if (rdev->size > current_offset) { printk(" contained as device %d\n", c); @@ -151,9 +160,6 @@ printk("raid0: zone->nb_dev: %d, size: %llu\n", zone->nb_dev, (unsigned long long)zone->size); - if (!conf->smallest || (zone->size < conf->smallest->size)) - conf->smallest = zone; - zone->zone_offset = curr_zone_offset; curr_zone_offset += zone->size; @@ -161,10 +167,30 @@ printk("raid0: current zone offset: %llu\n", (unsigned long long)current_offset); } + + /* Now find appropriate hash spacing. + * We want a number which causes most hash entries to cover + * at most two strips, but the hash table must be at most + * 1 PAGE. We choose the smallest strip, or contiguous collection + * of strips, that has big enough size. We never consider the last + * strip though as it's size has no bearing on the efficacy of the hash + * table. + */ + conf->hash_spacing = curr_zone_offset; + min_spacing = curr_zone_offset; + sector_div(min_spacing, PAGE_SIZE/sizeof(struct strip_zone*)); + for (i=0; i < conf->nr_strip_zones-1; i++) { + sector_t sz = 0; + for (j=i; j<conf->nr_strip_zones-1 && + sz < min_spacing ; j++) + sz += conf->strip_zone[j].size; + if (sz >= min_spacing && sz < conf->hash_spacing) + conf->hash_spacing = sz; + } + printk("raid0: done.\n"); return 0; abort: - vfree(conf->strip_zone); return 1; } @@ -179,31 +205,34 @@ static int raid0_mergeable_bvec(request_queue_t *q, struct bio *bio, struct bio_vec *biovec) { mddev_t *mddev = q->queuedata; - sector_t sector; - unsigned int chunk_sectors; - unsigned int bio_sectors; - - chunk_sectors = mddev->chunk_size >> 9; - sector = bio->bi_sector; - bio_sectors = bio->bi_size >> 9; - - return (chunk_sectors - ((sector & (chunk_sectors - 1)) + bio_sectors)) << 9; + sector_t sector = bio->bi_sector; + int max; + unsigned int chunk_sectors = mddev->chunk_size >> 9; + unsigned int bio_sectors = bio->bi_size >> 9; + + max = (chunk_sectors - ((sector & (chunk_sectors - 1)) + bio_sectors)) << 9; + if (max < 0) max = 0; /* bio_add cannot handle a negative return */ + if (max <= biovec->bv_len && bio_sectors == 0) + return biovec->bv_len; + else + return max; } static int raid0_run (mddev_t *mddev) { unsigned cur=0, i=0, nb_zone; - sector_t zone0_size; s64 size; raid0_conf_t *conf; mdk_rdev_t *rdev; struct list_head *tmp; - conf = vmalloc(sizeof (raid0_conf_t)); + conf = kmalloc(sizeof (raid0_conf_t), GFP_KERNEL); if (!conf) goto out; mddev->private = (void *)conf; + conf->strip_zone = NULL; + conf->devlist = NULL; if (create_strip_zones (mddev)) goto out_free_conf; @@ -214,70 +243,63 @@ printk("raid0 : md_size is %llu blocks.\n", (unsigned long long)mddev->array_size); - printk("raid0 : conf->smallest->size is %llu blocks.\n", - (unsigned long long)conf->smallest->size); + printk("raid0 : conf->hash_spacing is %llu blocks.\n", + (unsigned long long)conf->hash_spacing); { #if __GNUC__ < 3 volatile #endif sector_t s = mddev->array_size; - int round = sector_div(s, (unsigned long)conf->smallest->size) ? 1 : 0; + sector_t space = conf->hash_spacing; + int round; + conf->preshift = 0; + if (sizeof(sector_t) > sizeof(unsigned long)) { + /*shift down space and s so that sector_div will work */ + while (space > (sector_t) (~(unsigned long)0)) { + s >>= 1; + space >>= 1; + s += 1; /* force round-up */ + conf->preshift++; + } + } + round = sector_div(s, (unsigned long)space) ? 1 : 0; nb_zone = s + round; } printk("raid0 : nb_zone is %d.\n", nb_zone); - conf->nr_zones = nb_zone; printk("raid0 : Allocating %Zd bytes for hash.\n", - nb_zone*sizeof(struct raid0_hash)); - conf->hash_table = vmalloc (sizeof (struct raid0_hash)*nb_zone); + nb_zone*sizeof(struct strip_zone*)); + conf->hash_table = kmalloc (sizeof (struct strip_zone *)*nb_zone, GFP_KERNEL); if (!conf->hash_table) - goto out_free_zone_conf; + goto out_free_conf; size = conf->strip_zone[cur].size; - i = 0; - while (cur < conf->nr_strip_zones) { - conf->hash_table[i].zone0 = conf->strip_zone + cur; - - /* - * If we completely fill the slot - */ - if (size >= conf->smallest->size) { - conf->hash_table[i++].zone1 = NULL; - size -= conf->smallest->size; - - if (!size) { - if (++cur == conf->nr_strip_zones) - continue; - size = conf->strip_zone[cur].size; - } - continue; - } - if (++cur == conf->nr_strip_zones) { - /* - * Last dev, set unit1 as NULL - */ - conf->hash_table[i].zone1=NULL; - continue; + for (i=0; i< nb_zone; i++) { + conf->hash_table[i] = conf->strip_zone + cur; + while (size <= conf->hash_spacing) { + cur++; + size += conf->strip_zone[cur].size; } - - /* - * Here we use a 2nd dev to fill the slot + size -= conf->hash_spacing; + } + if (conf->preshift) { + conf->hash_spacing >>= conf->preshift; + /* round hash_spacing up so when we divide by it, we + * err on the side of too-low, which is safest */ - zone0_size = size; - size = conf->strip_zone[cur].size; - conf->hash_table[i++].zone1 = conf->strip_zone + cur; - size -= (conf->smallest->size - zone0_size); + conf->hash_spacing++; } + blk_queue_max_sectors(&mddev->queue, mddev->chunk_size >> 9); blk_queue_merge_bvec(&mddev->queue, raid0_mergeable_bvec); return 0; -out_free_zone_conf: - vfree(conf->strip_zone); - conf->strip_zone = NULL; - out_free_conf: - vfree(conf); + if (conf->strip_zone) + kfree(conf->strip_zone); + if (conf->devlist) + kfree (conf->devlist); + kfree(conf); mddev->private = NULL; out: return 1; @@ -287,11 +309,11 @@ { raid0_conf_t *conf = mddev_to_conf(mddev); - vfree (conf->hash_table); + kfree (conf->hash_table); conf->hash_table = NULL; - vfree (conf->strip_zone); + kfree (conf->strip_zone); conf->strip_zone = NULL; - vfree (conf); + kfree (conf); mddev->private = NULL; return 0; @@ -302,7 +324,6 @@ mddev_t *mddev = q->queuedata; unsigned int sect_in_chunk, chunksize_bits, chunk_size; raid0_conf_t *conf = mddev_to_conf(mddev); - struct raid0_hash *hash; struct strip_zone *zone; mdk_rdev_t *tmp_dev; unsigned long chunk; @@ -313,39 +334,45 @@ block = bio->bi_sector >> 1; + if (unlikely(chunk_size < (block & (chunk_size - 1)) + (bio->bi_size >> 10))) { + struct bio_pair *bp; + /* Sanity check -- queue functions should prevent this happening */ + if (bio->bi_vcnt != 1 || + bio->bi_idx != 0) + goto bad_map; + /* This is a one page bio that upper layers + * refuse to split for us, so we need to split it. + */ + bp = bio_split(bio, bio_split_pool, (chunk_size - (block & (chunk_size - 1)))<<1 ); + if (raid0_make_request(q, &bp->bio1)) + generic_make_request(&bp->bio1); + if (raid0_make_request(q, &bp->bio2)) + generic_make_request(&bp->bio2); + + bio_pair_release(bp); + return 0; + } + + { #if __GNUC__ < 3 volatile #endif - sector_t x = block; - sector_div(x, (unsigned long)conf->smallest->size); - hash = conf->hash_table + x; + sector_t x = block >> conf->preshift; + sector_div(x, (unsigned long)conf->hash_spacing); + zone = conf->hash_table[x]; } - - /* Sanity check -- queue functions should prevent this happening */ - if (unlikely(chunk_size < (block & (chunk_size - 1)) + (bio->bi_size >> 10))) - goto bad_map; - if (!hash) - goto bad_hash; - - if (!hash->zone0) - goto bad_zone0; - - if (block >= (hash->zone0->size + hash->zone0->zone_offset)) { - if (!hash->zone1) - goto bad_zone1; - zone = hash->zone1; - } else - zone = hash->zone0; + while (block >= (zone->zone_offset + zone->size)) + zone++; sect_in_chunk = bio->bi_sector & ((chunk_size<<1) -1); { - sector_t x = block - zone->zone_offset; + sector_t x = (block - zone->zone_offset) >> chunksize_bits; - sector_div(x, (zone->nb_dev << chunksize_bits)); + sector_div(x, zone->nb_dev); chunk = x; BUG_ON(x != (sector_t)chunk); @@ -355,10 +382,6 @@ rsect = (((chunk << chunksize_bits) + zone->dev_offset)<<1) + sect_in_chunk; - /* - * The new BH_Lock semantics in ll_rw_blk.c guarantee that this - * is the only IO operation happening on this bh. - */ bio->bi_bdev = tmp_dev->bdev; bio->bi_sector = rsect + tmp_dev->data_offset; @@ -371,19 +394,7 @@ printk("raid0_make_request bug: can't convert block across chunks" " or bigger than %dk %llu %d\n", chunk_size, (unsigned long long)bio->bi_sector, bio->bi_size >> 10); - goto outerr; -bad_hash: - printk("raid0_make_request bug: hash==NULL for block %llu\n", - (unsigned long long)block); - goto outerr; -bad_zone0: - printk("raid0_make_request bug: hash->zone0==NULL for block %llu\n", - (unsigned long long)block); - goto outerr; -bad_zone1: - printk("raid0_make_request bug: hash->zone1==NULL for block %llu\n", - (unsigned long long)block); - outerr: + bio_io_error(bio, bio->bi_size); return 0; } @@ -392,27 +403,19 @@ { #undef MD_DEBUG #ifdef MD_DEBUG - int j, k; + int j, k, h; + char b[BDEVNAME_SIZE]; raid0_conf_t *conf = mddev_to_conf(mddev); - seq_printf(seq, " "); - for (j = 0; j < conf->nr_zones; j++) { - seq_printf(seq, "[z%d", - conf->hash_table[j].zone0 - conf->strip_zone); - if (conf->hash_table[j].zone1) - seq_printf(seq, "/z%d] ", - conf->hash_table[j].zone1 - conf->strip_zone); - else - seq_printf(seq, "] "); - } - - seq_printf(seq, "\n"); - + h = 0; for (j = 0; j < conf->nr_strip_zones; j++) { - seq_printf(seq, " z%d=[", j); + seq_printf(seq, " z%d", j); + if (conf->hash_table[h] == conf->strip_zone+j) + seq_printf("(h%d)", h++); + seq_printf(seq, "=["); for (k = 0; k < conf->strip_zone[j].nb_dev; k++) - seq_printf (seq, "%s/", bdev_partition_name( - conf->strip_zone[j].dev[k]->bdev)); + seq_printf (seq, "%s/", bdevname( + conf->strip_zone[j].dev[k]->bdev,b)); seq_printf (seq, "] zo=%d do=%d s=%d\n", conf->strip_zone[j].zone_offset, diff -Nru a/drivers/md/raid1.c b/drivers/md/raid1.c --- a/drivers/md/raid1.c Mon Jun 9 23:16:13 2003 +++ b/drivers/md/raid1.c Mon Jun 9 23:16:13 2003 @@ -23,7 +23,6 @@ */ #include <linux/raid/raid1.h> -#include <linux/bio.h> #define MAJOR_NR MD_MAJOR #define MD_DRIVER @@ -41,9 +40,12 @@ static void * r1bio_pool_alloc(int gfp_flags, void *data) { + mddev_t *mddev = data; r1bio_t *r1_bio; - r1_bio = kmalloc(sizeof(r1bio_t), gfp_flags); + /* allocate a r1bio with room for raid_disks entries in the write_bios array */ + r1_bio = kmalloc(sizeof(r1bio_t) + sizeof(struct bio*)*mddev->raid_disks, + gfp_flags); if (r1_bio) memset(r1_bio, 0, sizeof(*r1_bio)); @@ -68,8 +70,9 @@ struct bio *bio; int i, j; - r1_bio = mempool_alloc(conf->r1bio_pool, gfp_flags); - + r1_bio = r1bio_pool_alloc(gfp_flags, conf->mddev); + if (!r1_bio) + return NULL; bio = bio_alloc(gfp_flags, RESYNC_PAGES); if (!bio) goto out_free_r1_bio; @@ -102,7 +105,7 @@ __free_page(bio->bi_io_vec[j].bv_page); bio_put(bio); out_free_r1_bio: - mempool_free(r1_bio, conf->r1bio_pool); + r1bio_pool_free(r1_bio, conf->mddev); return NULL; } @@ -122,7 +125,7 @@ if (atomic_read(&bio->bi_cnt) != 1) BUG(); bio_put(bio); - mempool_free(r1bio, conf->r1bio_pool); + r1bio_pool_free(r1bio, conf->mddev); } static void put_all_bios(conf_t *conf, r1bio_t *r1_bio) @@ -305,8 +308,9 @@ /* * oops, read error: */ + char b[BDEVNAME_SIZE]; printk(KERN_ERR "raid1: %s: rescheduling sector %llu\n", - bdev_partition_name(conf->mirrors[mirror].rdev->bdev), (unsigned long long)r1_bio->sector); + bdevname(conf->mirrors[mirror].rdev->bdev,b), (unsigned long long)r1_bio->sector); reschedule_retry(r1_bio); } } else { @@ -458,7 +462,7 @@ mirror_info_t *mirror; r1bio_t *r1_bio; struct bio *read_bio; - int i, sum_bios = 0, disks = conf->raid_disks; + int i, disks = conf->raid_disks; /* * Register the new request and wait if the reconstruction @@ -521,6 +525,9 @@ r1_bio->write_bios[i] = NULL; } spin_unlock_irq(&conf->device_lock); + + atomic_set(&r1_bio->remaining, 1); + md_write_start(mddev); for (i = 0; i < disks; i++) { struct bio *mbio; if (!r1_bio->write_bios[i]) @@ -535,37 +542,7 @@ mbio->bi_rw = r1_bio->cmd; mbio->bi_private = r1_bio; - sum_bios++; - } - if (!sum_bios) { - /* - * If all mirrors are non-operational - * then return an IO error: - */ - md_write_end(mddev); - raid_end_bio_io(r1_bio); - return 0; - } - atomic_set(&r1_bio->remaining, sum_bios+1); - - /* - * We have to be a bit careful about the semaphore above, thats - * why we start the requests separately. Since generic_make_request() - * can sleep, this is the safer solution. Imagine, raid1_end_request - * decreasing the semaphore before we could have set it up ... - * We could play tricks with the semaphore (presetting it and - * correcting at the end if sum_bios is not 'n' but we have to - * do raid1_end_request by hand if all requests finish until we had a - * chance to set up the semaphore correctly ... lots of races). - */ - - md_write_start(mddev); - for (i=disks; i--; ) { - struct bio *mbio; - mbio = r1_bio->write_bios[i]; - if (!mbio) - continue; - + atomic_inc(&r1_bio->remaining); generic_make_request(mbio); } @@ -594,6 +571,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) { + char b[BDEVNAME_SIZE]; conf_t *conf = mddev_to_conf(mddev); /* @@ -622,7 +600,7 @@ mddev->sb_dirty = 1; printk(KERN_ALERT "raid1: Disk failure on %s, disabling device. \n" " Operation continuing on %d devices\n", - bdev_partition_name(rdev->bdev), conf->working_disks); + bdevname(rdev->bdev,b), conf->working_disks); } static void print_conf(conf_t *conf) @@ -639,11 +617,12 @@ conf->raid_disks); for (i = 0; i < conf->raid_disks; i++) { + char b[BDEVNAME_SIZE]; tmp = conf->mirrors + i; if (tmp->rdev) printk(" disk %d, wo:%d, o:%d, dev:%s\n", i, !tmp->rdev->in_sync, !tmp->rdev->faulty, - bdev_partition_name(tmp->rdev->bdev)); + bdevname(tmp->rdev->bdev,b)); } } @@ -796,7 +775,7 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio) { conf_t *conf = mddev_to_conf(mddev); - int i, sum_bios = 0; + int i; int disks = conf->raid_disks; struct bio *bio, *mbio; @@ -811,9 +790,10 @@ * There is no point trying a read-for-reconstruct as * reconstruct is about to be aborted */ + char b[BDEVNAME_SIZE]; printk(KERN_ALERT "raid1: %s: unrecoverable I/O read error" " for block %llu\n", - bdev_partition_name(bio->bi_bdev), + bdevname(bio->bi_bdev,b), (unsigned long long)r1_bio->sector); md_done_sync(mddev, r1_bio->master_bio->bi_size >> 9, 0); put_buf(r1_bio); @@ -826,7 +806,7 @@ if (!conf->mirrors[i].rdev || conf->mirrors[i].rdev->faulty) continue; - if (i == conf->last_used) + if (conf->mirrors[i].rdev->bdev == bio->bi_bdev) /* * we read from here, no need to write */ @@ -842,7 +822,8 @@ } spin_unlock_irq(&conf->device_lock); - for (i = 0; i < disks ; i++) { + atomic_set(&r1_bio->remaining, 1); + for (i = disks; i-- ; ) { if (!r1_bio->write_bios[i]) continue; mbio = bio_clone(bio, GFP_NOIO); @@ -853,32 +834,14 @@ mbio->bi_rw = WRITE; mbio->bi_private = r1_bio; - sum_bios++; + atomic_inc(&r1_bio->remaining); + md_sync_acct(conf->mirrors[i].rdev, mbio->bi_size >> 9); + generic_make_request(mbio); } - if (i != disks) - BUG(); - atomic_set(&r1_bio->remaining, sum_bios); - - if (!sum_bios) { - /* - * Nowhere to write this to... I guess we - * must be done - */ - printk(KERN_ALERT "raid1: sync aborting as there is nowhere" - " to write sector %llu\n", - (unsigned long long)r1_bio->sector); + if (atomic_dec_and_test(&r1_bio->remaining)) { md_done_sync(mddev, r1_bio->master_bio->bi_size >> 9, 0); put_buf(r1_bio); - return; - } - for (i = 0; i < disks ; i++) { - mbio = r1_bio->write_bios[i]; - if (!mbio) - continue; - - md_sync_acct(conf->mirrors[i].rdev, mbio->bi_size >> 9); - generic_make_request(mbio); } } @@ -903,6 +866,7 @@ md_handle_safemode(mddev); for (;;) { + char b[BDEVNAME_SIZE]; spin_lock_irqsave(&retry_list_lock, flags); if (list_empty(head)) break; @@ -922,14 +886,14 @@ if (map(mddev, &rdev) == -1) { printk(KERN_ALERT "raid1: %s: unrecoverable I/O" " read error for block %llu\n", - bdev_partition_name(bio->bi_bdev), + bdevname(bio->bi_bdev,b), (unsigned long long)r1_bio->sector); raid_end_bio_io(r1_bio); break; } printk(KERN_ERR "raid1: %s: redirecting sector %llu to" " another mirror\n", - bdev_partition_name(rdev->bdev), + bdevname(rdev->bdev,b), (unsigned long long)r1_bio->sector); bio->bi_bdev = rdev->bdev; bio->bi_sector = r1_bio->sector + rdev->data_offset; @@ -1086,13 +1050,20 @@ goto out; } memset(conf, 0, sizeof(*conf)); + conf->mirrors = kmalloc(sizeof(struct mirror_info)*mddev->raid_disks, + GFP_KERNEL); + if (!conf->mirrors) { + printk(KERN_ERR "raid1: couldn't allocate memory for md%d\n", + mdidx(mddev)); + goto out_free_conf; + } conf->r1bio_pool = mempool_create(NR_RAID1_BIOS, r1bio_pool_alloc, - r1bio_pool_free, NULL); + r1bio_pool_free, mddev); if (!conf->r1bio_pool) { printk(KERN_ERR "raid1: couldn't allocate memory for md%d\n", mdidx(mddev)); - goto out; + goto out_free_conf; } @@ -1170,6 +1141,8 @@ out_free_conf: if (conf->r1bio_pool) mempool_destroy(conf->r1bio_pool); + if (conf->mirrors) + kfree(conf->mirrors); kfree(conf); mddev->private = NULL; out: @@ -1184,6 +1157,8 @@ mddev->thread = NULL; if (conf->r1bio_pool) mempool_destroy(conf->r1bio_pool); + if (conf->mirrors) + kfree(conf->mirrors); kfree(conf); mddev->private = NULL; return 0; diff -Nru a/drivers/md/raid5.c b/drivers/md/raid5.c --- a/drivers/md/raid5.c Mon Jun 9 23:16:08 2003 +++ b/drivers/md/raid5.c Mon Jun 9 23:16:08 2003 @@ -20,7 +20,6 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/raid/raid5.h> -#include <linux/bio.h> #include <linux/highmem.h> #include <asm/bitops.h> #include <asm/atomic.h> @@ -458,6 +457,7 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev) { + char b[BDEVNAME_SIZE]; raid5_conf_t *conf = (raid5_conf_t *) mddev->private; PRINTK("raid5: error called\n"); @@ -477,7 +477,7 @@ printk (KERN_ALERT "raid5: Disk failure on %s, disabling device." " Operation continuing on %d devices\n", - bdev_partition_name(rdev->bdev), conf->working_disks); + bdevname(rdev->bdev,b), conf->working_disks); } } @@ -919,7 +919,7 @@ /* check if the array has lost two devices and, if so, some requests might * need to be failed */ - if (failed > 1 && to_read+to_write) { + if (failed > 1 && to_read+to_write+written) { spin_lock_irq(&conf->device_lock); for (i=disks; i--; ) { /* fail all writes first */ @@ -937,6 +937,20 @@ } bi = nextbi; } + /* and fail all 'written' */ + bi = sh->dev[i].written; + sh->dev[i].written = NULL; + while (bi && bi->bi_sector < sh->dev[i].sector + STRIPE_SECTORS) { + struct bio *bi2 = bi->bi_next; + clear_bit(BIO_UPTODATE, &bi->bi_flags); + if (--bi->bi_phys_segments == 0) { + md_write_end(conf->mddev); + bi->bi_next = return_bi; + return_bi = bi; + } + bi = bi2; + } + /* fail any reads if this device is non-operational */ if (!test_bit(R5_Insync, &sh->dev[i].flags)) { bi = sh->dev[i].toread; @@ -1439,7 +1453,9 @@ return -EIO; } - mddev->private = kmalloc (sizeof (raid5_conf_t), GFP_KERNEL); + mddev->private = kmalloc (sizeof (raid5_conf_t) + + mddev->raid_disks * sizeof(struct disk_info), + GFP_KERNEL); if ((conf = mddev->private) == NULL) goto abort; memset (conf, 0, sizeof (*conf)); @@ -1463,7 +1479,7 @@ ITERATE_RDEV(mddev,rdev,tmp) { raid_disk = rdev->raid_disk; - if (raid_disk > mddev->raid_disks + if (raid_disk >= mddev->raid_disks || raid_disk < 0) continue; disk = conf->disks + raid_disk; @@ -1471,8 +1487,9 @@ disk->rdev = rdev; if (rdev->in_sync) { + char b[BDEVNAME_SIZE]; printk(KERN_INFO "raid5: device %s operational as raid" - " disk %d\n", bdev_partition_name(rdev->bdev), + " disk %d\n", bdevname(rdev->bdev,b), raid_disk); conf->working_disks++; } @@ -1648,11 +1665,12 @@ conf->working_disks, conf->failed_disks); for (i = 0; i < conf->raid_disks; i++) { + char b[BDEVNAME_SIZE]; tmp = conf->disks + i; if (tmp->rdev) printk(" disk %d, o:%d, dev:%s\n", i, !tmp->rdev->faulty, - bdev_partition_name(tmp->rdev->bdev)); + bdevname(tmp->rdev->bdev,b)); } } diff -Nru a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c --- a/drivers/media/radio/radio-cadet.c Mon Jun 9 23:16:10 2003 +++ b/drivers/media/radio/radio-cadet.c Mon Jun 9 23:16:10 2003 @@ -389,9 +389,6 @@ v->flags|=VIDEO_TUNER_STEREO_ON; } v->flags|=cadet_getrds(); - if(copy_to_user(arg,&v, sizeof(v))) { - return -EFAULT; - } break; case 1: strcpy(v->name,"AM"); @@ -402,9 +399,6 @@ v->mode=0; v->mode|=VIDEO_MODE_AUTO; v->signal=sigstrength; - if(copy_to_user(arg,&v, sizeof(v))) { - return -EFAULT; - } break; } return 0; diff -Nru a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig --- a/drivers/media/video/Kconfig Mon Jun 9 23:16:18 2003 +++ b/drivers/media/video/Kconfig Mon Jun 9 23:16:18 2003 @@ -45,7 +45,7 @@ config VIDEO_PLANB tristate "PlanB Video-In on PowerMac" - depends on ALL_PPC && VIDEO_DEV + depends on PPC_PMAC && VIDEO_DEV help PlanB is the V4L driver for the PowerMac 7x00/8x00 series video input hardware. If you want to experiment with this, say Y. diff -Nru a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c --- a/drivers/media/video/bw-qcam.c Mon Jun 9 23:16:08 2003 +++ b/drivers/media/video/bw-qcam.c Mon Jun 9 23:16:08 2003 @@ -723,8 +723,6 @@ /* Good question.. its composite or SVHS so.. */ v->type = VIDEO_TYPE_CAMERA; strcpy(v->name, "Camera"); - if(copy_to_user(arg, &v, sizeof(v))) - return -EFAULT; return 0; } case VIDIOCSCHAN: diff -Nru a/drivers/media/video/cpia_usb.c b/drivers/media/video/cpia_usb.c --- a/drivers/media/video/cpia_usb.c Mon Jun 9 23:16:05 2003 +++ b/drivers/media/video/cpia_usb.c Mon Jun 9 23:16:05 2003 @@ -586,6 +586,7 @@ static struct usb_driver cpia_driver = { + .owner = THIS_MODULE, .name = "cpia", .probe = cpia_probe, .disconnect = cpia_disconnect, diff -Nru a/drivers/media/video/zoran_procfs.c b/drivers/media/video/zoran_procfs.c --- a/drivers/media/video/zoran_procfs.c Mon Jun 9 23:16:18 2003 +++ b/drivers/media/video/zoran_procfs.c Mon Jun 9 23:16:18 2003 @@ -119,7 +119,10 @@ printk(KERN_ERR "%s: write_proc: can not allocate memory\n", zr->name); return -ENOMEM; } - memcpy(string, buffer, count); + if (copy_from_user(string, buffer, count)) { + vfree(string); + return -EFAULT; + } string[count] = 0; DEBUG2(printk(KERN_INFO "%s: write_proc: name=%s count=%lu data=%x\n", zr->name, file->f_dentry->d_name.name, count, (int) data)); ldelim = " \t\n"; diff -Nru a/drivers/media/video/zr36120.c b/drivers/media/video/zr36120.c --- a/drivers/media/video/zr36120.c Mon Jun 9 23:16:12 2003 +++ b/drivers/media/video/zr36120.c Mon Jun 9 23:16:12 2003 @@ -1693,12 +1693,12 @@ for (x=0; optr+1<eptr && x<-done->w; x++) { unsigned char a = iptr[x*2]; - *optr++ = a; - *optr++ = a; + __put_user(a, optr++); + __put_user(a, optr++); } /* and clear the rest of the line */ for (x*=2; optr<eptr && x<done->bpl; x++) - *optr++ = 0; + __put_user(0, optr++); /* next line */ iptr += done->bpl; } @@ -1715,10 +1715,10 @@ { /* copy to doubled data to userland */ for (x=0; optr<eptr && x<-done->w; x++) - *optr++ = iptr[x*2]; + __put_user(iptr[x*2], optr++); /* and clear the rest of the line */ for (;optr<eptr && x<done->bpl; x++) - *optr++ = 0; + __put_user(0, optr++); /* next line */ iptr += done->bpl; } @@ -1727,7 +1727,7 @@ /* API compliance: * place the framenumber (half fieldnr) in the last long */ - ((ulong*)eptr)[-1] = done->fieldnr/2; + __put_user(done->fieldnr/2, ((ulong*)eptr)[-1]); } /* keep the engine running */ diff -Nru a/drivers/message/fusion/linux_compat.h b/drivers/message/fusion/linux_compat.h --- a/drivers/message/fusion/linux_compat.h Mon Jun 9 23:16:09 2003 +++ b/drivers/message/fusion/linux_compat.h Mon Jun 9 23:16:09 2003 @@ -147,9 +147,7 @@ /* PCI/driver subsystem { */ -#ifndef pci_for_each_dev -#define pci_for_each_dev(dev) for((dev)=pci_devices; (dev)!=NULL; (dev)=(dev)->next) -#define pci_peek_next_dev(dev) ((dev)->next ? (dev)->next : NULL) +#if 0 /* FIXME Don't know what to use to check for the proper kernel version */ #define DEVICE_COUNT_RESOURCE 6 #define PCI_BASEADDR_FLAGS(idx) base_address[idx] #define PCI_BASEADDR_START(idx) base_address[idx] & ~0xFUL @@ -169,11 +167,10 @@ (4 - size); \ }) #else -#define pci_peek_next_dev(dev) ((dev) != pci_dev_g(&pci_devices) ? pci_dev_g((dev)->global_list.next) : NULL) #define PCI_BASEADDR_FLAGS(idx) resource[idx].flags #define PCI_BASEADDR_START(idx) resource[idx].start #define PCI_BASEADDR_SIZE(dev,idx) (dev)->resource[idx].end - (dev)->resource[idx].start + 1 -#endif /* } ifndef pci_for_each_dev */ +#endif /* } ifndef 0 */ /* Compatability for the 2.3.x PCI DMA API. */ diff -Nru a/drivers/message/fusion/mptbase.c b/drivers/message/fusion/mptbase.c --- a/drivers/message/fusion/mptbase.c Mon Jun 9 23:16:08 2003 +++ b/drivers/message/fusion/mptbase.c Mon Jun 9 23:16:08 2003 @@ -1152,7 +1152,7 @@ static int __init mpt_pci_scan(void) { - struct pci_dev *pdev; + struct pci_dev *pdev = NULL; struct pci_dev *pdev2; int found = 0; int count = 0; @@ -1164,11 +1164,8 @@ * NOTE: The 929, 929X, 1030 and 1035 will appear as 2 separate PCI devices, * one for each channel. */ - pci_for_each_dev(pdev) { + while ((pdev = pci_find_device(PCI_VENDOR_ID_LSI_LOGIC, PCI_ANY_ID, pdev)) != NULL) { pdev2 = NULL; - if (pdev->vendor != 0x1000) - continue; - if ((pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC909) && (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC929) && (pdev->device != MPI_MANUFACTPAGE_DEVICEID_FC919) && @@ -1187,7 +1184,7 @@ * Do some kind of look ahead here... */ if (pdev->devfn & 1) { - pdev2 = pci_peek_next_dev(pdev); + pdev2 = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev); if (pdev2 && (pdev2->vendor == 0x1000) && (PCI_SLOT(pdev2->devfn) == PCI_SLOT(pdev->devfn)) && (pdev2->device == pdev->device) && diff -Nru a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c --- a/drivers/message/fusion/mptlan.c Mon Jun 9 23:16:12 2003 +++ b/drivers/message/fusion/mptlan.c Mon Jun 9 23:16:12 2003 @@ -1356,16 +1356,16 @@ } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -struct net_device * +static struct net_device * mpt_register_lan_device (MPT_ADAPTER *mpt_dev, int pnum) { - struct net_device *dev = NULL; + struct net_device *dev = alloc_fcdev(sizeof(struct mpt_lan_priv)); struct mpt_lan_priv *priv = NULL; u8 HWaddr[FC_ALEN], *a; - dev = init_fcdev(NULL, sizeof(struct mpt_lan_priv)); if (!dev) - return (NULL); + return NULL; + dev->mtu = MPT_LAN_MTU; priv = (struct mpt_lan_priv *) dev->priv; @@ -1435,15 +1435,18 @@ SET_MODULE_OWNER(dev); + if (register_netdev(dev) != 0) { + kfree(dev); + dev = NULL; + } return dev; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -int __init -mpt_lan_init (void) +static int __init mpt_lan_init (void) { struct net_device *dev; - MPT_ADAPTER *curadapter; + MPT_ADAPTER *p; int i, j; show_mptmod_ver(LANAME, LANVER); @@ -1477,51 +1480,49 @@ mpt_landev[j] = NULL; } - curadapter = mpt_adapter_find_first(); - while (curadapter != NULL) { - for (i = 0; i < curadapter->facts.NumberOfPorts; i++) { + for (p = mpt_adapter_find_first(); p; p = mpt_adapter_find_next(p)) { + for (i = 0; i < p->facts.NumberOfPorts; i++) { printk (KERN_INFO MYNAM ": %s: PortNum=%x, ProtocolFlags=%02Xh (%c%c%c%c)\n", - curadapter->name, - curadapter->pfacts[i].PortNumber, - curadapter->pfacts[i].ProtocolFlags, - MPT_PROTOCOL_FLAGS_c_c_c_c(curadapter->pfacts[i].ProtocolFlags)); - - if (curadapter->pfacts[i].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN) { - dev = mpt_register_lan_device (curadapter, i); - if (dev != NULL) { - printk (KERN_INFO MYNAM ": %s: Fusion MPT LAN device registered as '%s'\n", - curadapter->name, dev->name); - printk (KERN_INFO MYNAM ": %s/%s: LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n", - IOC_AND_NETDEV_NAMES_s_s(dev), - dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5]); + p->name, + p->pfacts[i].PortNumber, + p->pfacts[i].ProtocolFlags, + MPT_PROTOCOL_FLAGS_c_c_c_c(p->pfacts[i].ProtocolFlags)); + + if (!(p->pfacts[i].ProtocolFlags & MPI_PORTFACTS_PROTOCOL_LAN)) { + printk (KERN_INFO MYNAM ": %s: Hmmm... LAN protocol seems to be disabled on this adapter port!\n", + p->name); + continue; + } + + dev = mpt_register_lan_device (p, i); + if (!dev) { + printk (KERN_ERR MYNAM ": %s: Unable to register port%d as a LAN device\n", + p->name, + p->pfacts[i].PortNumber); + } + printk (KERN_INFO MYNAM ": %s: Fusion MPT LAN device registered as '%s'\n", + p->name, dev->name); + printk (KERN_INFO MYNAM ": %s/%s: LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n", + IOC_AND_NETDEV_NAMES_s_s(dev), + 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 (KERN_INFO MYNAM ": %s/%s: Max_TX_outstanding = %d\n", // IOC_AND_NETDEV_NAMES_s_s(dev), // NETDEV_TO_LANPRIV_PTR(dev)->tx_max_out); - j = curadapter->id; - mpt_landev[j] = dev; - dlprintk((KERN_INFO MYNAM "/init: dev_addr=%p, mpt_landev[%d]=%p\n", - dev, j, mpt_landev[j])); - - } else { - printk (KERN_ERR MYNAM ": %s: Unable to register port%d as a LAN device\n", - curadapter->name, - curadapter->pfacts[i].PortNumber); - } - } else { - printk (KERN_INFO MYNAM ": %s: Hmmm... LAN protocol seems to be disabled on this adapter port!\n", - curadapter->name); - } + j = p->id; + mpt_landev[j] = dev; + dlprintk((KERN_INFO MYNAM "/init: dev_addr=%p, mpt_landev[%d]=%p\n", + dev, j, mpt_landev[j])); + } - curadapter = mpt_adapter_find_next(curadapter); } return 0; } /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ -static void mpt_lan_exit(void) +static void __exit mpt_lan_exit(void) { int i; @@ -1532,7 +1533,7 @@ printk (KERN_INFO ": %s/%s: Fusion MPT LAN device unregistered\n", IOC_AND_NETDEV_NAMES_s_s(dev)); - unregister_fcdev(dev); + unregister_netdev(dev); //mpt_landev[i] = (struct net_device *) 0xdeadbeef; /* Debug */ mpt_landev[i] = NULL; } diff -Nru a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c --- a/drivers/message/fusion/mptscsih.c Mon Jun 9 23:16:10 2003 +++ b/drivers/message/fusion/mptscsih.c Mon Jun 9 23:16:10 2003 @@ -2149,8 +2149,8 @@ * hostno: scsi host number * func: if write = 1; if read = 0 */ -int mptscsih_proc_info(char *buffer, char **start, off_t offset, - int length, int hostno, int func) +int mptscsih_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, + int length, int func) { MPT_ADAPTER *ioc = NULL; MPT_SCSI_HOST *hd = NULL; @@ -2161,7 +2161,7 @@ buffer, start, *start, offset, length)); for (ioc = mpt_adapter_find_first(); ioc != NULL; ioc = mpt_adapter_find_next(ioc)) { - if ((ioc->sh) && (ioc->sh->host_no == hostno)) { + if ((ioc->sh) && (ioc->sh == host)) { hd = (MPT_SCSI_HOST *)ioc->sh->hostdata; break; } diff -Nru a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h --- a/drivers/message/fusion/mptscsih.h Mon Jun 9 23:16:20 2003 +++ b/drivers/message/fusion/mptscsih.h Mon Jun 9 23:16:20 2003 @@ -199,7 +199,7 @@ extern int x_scsi_slave_alloc(Scsi_Device *); extern int x_scsi_slave_configure(Scsi_Device *); extern void x_scsi_slave_destroy(Scsi_Device *); -extern int x_scsi_proc_info(char *, char **, off_t, int, int, int); +extern int x_scsi_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int); /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/ diff -Nru a/drivers/message/i2o/i2o_core.c b/drivers/message/i2o/i2o_core.c --- a/drivers/message/i2o/i2o_core.c Mon Jun 9 23:16:14 2003 +++ b/drivers/message/i2o/i2o_core.c Mon Jun 9 23:16:14 2003 @@ -1690,7 +1690,9 @@ if((jiffies-time)>=20*HZ) { printk(KERN_ERR "IOP reset timeout.\n"); - // Better to leak this for safety: - status; + /* The controller still may respond and overwrite + * status_phys, LEAK it to prevent memory corruption. + */ return -ETIMEDOUT; } schedule(); @@ -1719,6 +1721,10 @@ { printk(KERN_ERR "%s: Timeout waiting for IOP reset.\n", c->name); + /* The controller still may respond and + * overwrite status_phys, LEAK it to prevent + * memory corruption. + */ return -ETIMEDOUT; } schedule(); @@ -3639,12 +3645,12 @@ int __init i2o_pci_scan(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; int count=0; printk(KERN_INFO "i2o: Checking for PCI I2O controllers...\n"); - pci_for_each_dev(dev) + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { if((dev->class>>8)!=PCI_CLASS_INTELLIGENT_I2O) continue; diff -Nru a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig --- a/drivers/mtd/Kconfig Mon Jun 9 23:16:08 2003 +++ b/drivers/mtd/Kconfig Mon Jun 9 23:16:08 2003 @@ -1,4 +1,4 @@ -# $Id: Config.in,v 1.74 2002/04/23 13:52:14 mag Exp $ +# $Id: Kconfig,v 1.3 2003/05/28 11:02:23 dwmw2 Exp $ menu "Memory Technology Devices (MTD)" @@ -199,13 +199,28 @@ not use it. config NFTL_RW - bool "Write support for NFTL (BETA)" + bool "Write support for NFTL" depends on NFTL help - If you're lucky, this will actually work. Don't whinge if it - doesn't. Send mail to the MTD mailing list - <linux-mtd@lists.infradead.org> if you want to help to make it more - reliable. + Support for writing to the NAND Flash Translation Layer, as used + on the DiskOnChip. + +config INFTL + tristate "INFTL (Inverse NAND Flash Translation Layer) support" + depends on MTD + ---help--- + This provides support for the Inverse NAND Flash Translation + Layer which is used on M-Systems' newer DiskOnChip devices. It + uses a kind of pseudo-file system on a flash device to emulate + a block device with 512-byte sectors, on top of which you put + a 'normal' file system. + + You may find that the algorithms used in this code are patented + unless you live in the Free World where software patents aren't + legal - in the USA you are only permitted to use this on DiskOnChip + hardware, although under the terms of the GPL you're obviously + permitted to copy, modify and distribute the code as you wish. Just + not use it. source "drivers/mtd/chips/Kconfig" diff -Nru a/drivers/mtd/Makefile b/drivers/mtd/Makefile --- a/drivers/mtd/Makefile Mon Jun 9 23:16:10 2003 +++ b/drivers/mtd/Makefile Mon Jun 9 23:16:10 2003 @@ -1,10 +1,7 @@ # # Makefile for the memory technology device drivers. # -# Based on: -# $Id: Makefile,v 1.66 2002/04/23 13:52:14 mag Exp $ - -obj-y += chips/ maps/ devices/ nand/ +# $Id: Makefile.common,v 1.2 2003/05/23 11:38:29 dwmw2 Exp $ # *** BIG UGLY NOTE *** # @@ -27,14 +24,18 @@ obj-$(CONFIG_MTD_CONCAT) += mtdconcat.o obj-$(CONFIG_MTD_PARTITIONS) += mtdpart.o obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o -obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdline.o +obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o obj-$(CONFIG_MTD_AFS_PARTS) += afs.o # 'Users' - code which presents functionality to userspace. obj-$(CONFIG_MTD_CHAR) += mtdchar.o -obj-$(CONFIG_MTD_BLOCK) += mtdblock.o -obj-$(CONFIG_MTD_BLOCK_RO) += mtdblock_ro.o -obj-$(CONFIG_FTL) += ftl.o -obj-$(CONFIG_NFTL) += nftl.o +obj-$(CONFIG_MTD_BLOCK) += mtdblock.o mtd_blkdevs.o +obj-$(CONFIG_MTD_BLOCK_RO) += mtdblock_ro.o mtd_blkdevs.o +obj-$(CONFIG_FTL) += ftl.o mtd_blkdevs.o +obj-$(CONFIG_NFTL) += nftl.o mtd_blkdevs.o +obj-$(CONFIG_INFTL) += inftl.o mtd_blkdevs.o + +nftl-objs := nftlcore.o nftlmount.o +inftl-objs := inftlcore.o inftlmount.o -nftl-objs := nftlcore.o nftlmount.o +obj-y += chips/ maps/ devices/ nand/ diff -Nru a/drivers/mtd/afs.c b/drivers/mtd/afs.c --- a/drivers/mtd/afs.c Mon Jun 9 23:16:18 2003 +++ b/drivers/mtd/afs.c Mon Jun 9 23:16:18 2003 @@ -21,7 +21,7 @@ This is access code for flashes using ARM's flash partitioning standards. - $Id: afs.c,v 1.8 2002/05/04 08:49:09 rmk Exp $ + $Id: afs.c,v 1.11 2003/05/16 17:08:24 dwmw2 Exp $ ======================================================================*/ @@ -125,7 +125,9 @@ return ret; } -int parse_afs_partitions(struct mtd_info *mtd, struct mtd_partition **pparts) +static int parse_afs_partitions(struct mtd_info *mtd, + struct mtd_partition **pparts, + unsigned long origin) { struct mtd_partition *parts; u_int mask, off, idx, sz; @@ -227,7 +229,25 @@ return idx ? idx : ret; } -EXPORT_SYMBOL(parse_afs_partitions); +static struct mtd_part_parser afs_parser = { + .owner = THIS_MODULE, + .parse_fn = parse_afs_partitions, + .name = "afs", +}; + +static int __init afs_parser_init(void) +{ + return register_mtd_parser(&afs_parser); +} + +static void __exit afs_parser_exit(void) +{ + deregister_mtd_parser(&afs_parser); +} + +module_init(afs_parser_init); +module_exit(afs_parser_exit); + MODULE_AUTHOR("ARM Ltd"); MODULE_DESCRIPTION("ARM Firmware Suite partition parser"); diff -Nru a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig --- a/drivers/mtd/chips/Kconfig Mon Jun 9 23:16:09 2003 +++ b/drivers/mtd/chips/Kconfig Mon Jun 9 23:16:09 2003 @@ -1,5 +1,5 @@ -# drivers/mtd/chips/Config.in -# $Id: Config.in,v 1.12 2001/09/23 15:35:21 dwmw2 Exp $ +# drivers/mtd/chips/Kconfig +# $Id: Kconfig,v 1.3 2003/05/28 15:13:24 dwmw2 Exp $ menu "RAM/ROM/Flash chip drivers" depends on MTD!=n @@ -15,7 +15,6 @@ option. Visit <http://www.amd.com/products/nvd/overview/cfi.html> for more information on CFI. -#dep_tristate ' Detect non-CFI Intel-compatible flash chips' CONFIG_MTD_INTELPROBE $CONFIG_MTD config MTD_JEDECPROBE tristate "Detect non-CFI AMD/JEDEC-compatible flash chips" depends on MTD @@ -107,6 +106,13 @@ If you wish to support CFI devices on a physical bus which is 32 bits wide, say 'Y'. +config MTD_CFI_B8 + bool "Support 64-bit buswidth" + depends on MTD_CFI_GEOMETRY + help + If you wish to support CFI devices on a physical bus which is + 64 bits wide, say 'Y'. + config MTD_CFI_I1 bool "Support 1-chip flash interleave" if !MTD_CFI_B1 depends on MTD_CFI_GEOMETRY @@ -129,6 +135,13 @@ If your flash chips are interleaved in fours - i.e. you have four flash chips addressed by each bus cycle, then say 'Y'. +config MTD_CFI_I8 + bool "Support 8-chip flash interleave" + depends on MTD_CFI_GEOMETRY + help + If your flash chips are interleaved in eights - i.e. you have eight + flash chips addressed by each bus cycle, then say 'Y'. + config MTD_CFI_INTELEXT tristate "Support for Intel/Sharp flash chips" depends on MTD_GEN_PROBE @@ -145,7 +158,15 @@ The Common Flash Interface defines a number of different command sets which a CFI-compliant chip may claim to implement. This code provides support for one of those command sets, used on chips - chips including the AMD Am29LV320. + including the AMD Am29LV320. + +config MTD_CFI_STAA + tristate "Support for ST (Advanced Architecture) flash chips" + depends on MTD_GEN_PROBE + help + The Common Flash Interface defines a number of different command + sets which a CFI-compliant chip may claim to implement. This code + provides support for one of those command sets. config MTD_RAM tristate "Support for RAM chips in bus mapping" @@ -177,10 +198,10 @@ help This option does not enable any code directly, but will allow you to select some other chip drivers which are now considered obsolete, - because the generic CONFIG_JEDEC_PROBE code above should now detect + because the generic CONFIG_JEDECPROBE code above should now detect the chips which are supported by these drivers, and allow the generic CFI-compatible drivers to drive the chips. Say 'N' here unless you have - already tried the CONFIG_JEDEC_PROBE method and reported its failure + already tried the CONFIG_JEDECPROBE method and reported its failure to the MTD mailing list at <linux-mtd@lists.infradead.org> config MTD_AMDSTD @@ -209,8 +230,7 @@ programming flash. It is commonly used in older AMD chips. It is only called JEDEC because the JEDEC association <http://www.jedec.org/> distributes the identification codes for the - chips. WARNING!!!! This code does not compile and is incomplete as - are the specific JEDEC devices drivers. + chips. endmenu diff -Nru a/drivers/mtd/chips/Makefile b/drivers/mtd/chips/Makefile --- a/drivers/mtd/chips/Makefile Mon Jun 9 23:16:08 2003 +++ b/drivers/mtd/chips/Makefile Mon Jun 9 23:16:08 2003 @@ -1,7 +1,7 @@ # # linux/drivers/chips/Makefile # -# $Id: Makefile,v 1.7 2001/10/05 06:53:51 dwmw2 Exp $ +# $Id: Makefile.common,v 1.1 2003/05/21 15:00:01 dwmw2 Exp $ # *** BIG UGLY NOTE *** # @@ -13,10 +13,10 @@ obj-$(CONFIG_MTD) += chipreg.o 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_AMDSTD) += cfi_cmdset_0002.o obj-$(CONFIG_MTD_CFI_INTELEXT) += cfi_cmdset_0001.o obj-$(CONFIG_MTD_GEN_PROBE) += gen_probe.o -obj-$(CONFIG_MTD_INTELPROBE) += intel_probe.o obj-$(CONFIG_MTD_JEDEC) += jedec.o obj-$(CONFIG_MTD_JEDECPROBE) += jedec_probe.o obj-$(CONFIG_MTD_RAM) += map_ram.o diff -Nru a/drivers/mtd/chips/amd_flash.c b/drivers/mtd/chips/amd_flash.c --- a/drivers/mtd/chips/amd_flash.c Mon Jun 9 23:16:09 2003 +++ b/drivers/mtd/chips/amd_flash.c Mon Jun 9 23:16:09 2003 @@ -3,7 +3,7 @@ * * Author: Jonas Holmberg <jonas.holmberg@axis.com> * - * $Id: amd_flash.c,v 1.15 2001/10/02 15:05:11 dwmw2 Exp $ + * $Id: amd_flash.c,v 1.22 2003/05/28 13:47:19 dwmw2 Exp $ * * Copyright (c) 2001 Axis Communications AB * @@ -52,6 +52,7 @@ /* Manufacturers */ #define MANUFACTURER_AMD 0x0001 +#define MANUFACTURER_ATMEL 0x001F #define MANUFACTURER_FUJITSU 0x0004 #define MANUFACTURER_ST 0x0020 #define MANUFACTURER_SST 0x00BF @@ -67,10 +68,14 @@ #define AM29BDS323D 0x22D1 #define AM29BDS643D 0x227E +/* Atmel */ +#define AT49xV16x 0x00C0 +#define AT49xV16xT 0x00C2 /* Fujitsu */ #define MBM29LV160TE 0x22C4 #define MBM29LV160BE 0x2249 +#define MBM29LV800BB 0x225B /* ST - www.st.com */ #define M29W800T 0x00D7 @@ -120,10 +125,10 @@ static struct mtd_chip_driver amd_flash_chipdrv = { - .probe = amd_flash_probe, - .destroy = amd_flash_destroy, - .name = "amd_flash", - .module = THIS_MODULE + .probe = amd_flash_probe, + .destroy = amd_flash_destroy, + .name = "amd_flash", + .module = THIS_MODULE }; @@ -135,11 +140,11 @@ static inline __u32 wide_read(struct map_info *map, __u32 addr) { if (map->buswidth == 1) { - return map->read8(map, addr); + return map_read8(map, addr); } else if (map->buswidth == 2) { - return map->read16(map, addr); + return map_read16(map, addr); } else if (map->buswidth == 4) { - return map->read32(map, addr); + return map_read32(map, addr); } return 0; @@ -148,11 +153,11 @@ static inline void wide_write(struct map_info *map, __u32 val, __u32 addr) { if (map->buswidth == 1) { - map->write8(map, val, addr); + map_write8(map, val, addr); } else if (map->buswidth == 2) { - map->write16(map, val, addr); + map_write16(map, val, addr); } else if (map->buswidth == 4) { - map->write32(map, val, addr); + map_write32(map, val, addr); } } @@ -419,10 +424,7 @@ static struct mtd_info *amd_flash_probe(struct map_info *map) { - /* Keep this table on the stack so that it gets deallocated after the - * probe is done. - */ - const struct amd_flash_info table[] = { + static const struct amd_flash_info table[] = { { .mfr_id = MANUFACTURER_AMD, .dev_id = AM29LV160DT, @@ -431,9 +433,9 @@ .numeraseregions = 4, .regions = { { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 }, - { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 }, - { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 }, - { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 } + { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 } } }, { .mfr_id = MANUFACTURER_AMD, @@ -442,9 +444,9 @@ .size = 0x00200000, .numeraseregions = 4, .regions = { - { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, - { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, - { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, + { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 } } }, { @@ -455,9 +457,9 @@ .numeraseregions = 4, .regions = { { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 }, - { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 }, - { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 }, - { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 } + { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 } } }, { .mfr_id = MANUFACTURER_FUJITSU, @@ -467,9 +469,9 @@ .numeraseregions = 4, .regions = { { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 }, - { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 }, - { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 }, - { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 } + { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 } } }, { .mfr_id = MANUFACTURER_TOSHIBA, @@ -478,9 +480,9 @@ .size = 0x00200000, .numeraseregions = 4, .regions = { - { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, - { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, - { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, + { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 } } }, { @@ -490,9 +492,9 @@ .size = 0x00200000, .numeraseregions = 4, .regions = { - { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, - { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, - { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, + { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 } } }, { @@ -502,9 +504,9 @@ .size = 0x00100000, .numeraseregions = 4, .regions = { - { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, - { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, - { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, + { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 } } }, { @@ -514,9 +516,9 @@ .size = 0x00100000, .numeraseregions = 4, .regions = { - { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, - { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, - { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, + { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 } } }, { @@ -527,9 +529,9 @@ .numeraseregions = 4, .regions = { { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 }, - { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 }, - { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 }, - { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 } + { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 } } }, { .mfr_id = MANUFACTURER_AMD, @@ -539,9 +541,9 @@ .numeraseregions = 4, .regions = { { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 }, - { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 }, - { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 }, - { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 } + { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 } } }, { .mfr_id = MANUFACTURER_AMD, @@ -551,9 +553,21 @@ .numeraseregions = 4, .regions = { { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 }, - { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 }, - { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 }, - { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 } + { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 } + } + }, { + .mfr_id = MANUFACTURER_FUJITSU, + .dev_id = MBM29LV800BB, + .name = "Fujitsu MBM29LV800BB", + .size = 0x00100000, + .numeraseregions = 4, + .regions = { + { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, + { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 } } }, { .mfr_id = MANUFACTURER_ST, @@ -563,9 +577,9 @@ .numeraseregions = 4, .regions = { { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 }, - { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 }, - { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 }, - { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 } + { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks = 1 } } }, { .mfr_id = MANUFACTURER_ST, @@ -575,9 +589,9 @@ .numeraseregions = 4, .regions = { { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 }, - { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 }, - { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 }, - { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 } + { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks = 1 } } }, { .mfr_id = MANUFACTURER_ST, @@ -586,9 +600,9 @@ .size = 0x00200000, .numeraseregions = 4, .regions = { - { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, - { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, - { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, + { .offset = 0x000000, .erasesize = 0x04000, .numblocks = 1 }, + { .offset = 0x004000, .erasesize = 0x02000, .numblocks = 2 }, + { .offset = 0x008000, .erasesize = 0x08000, .numblocks = 1 }, { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 } } }, { @@ -600,7 +614,7 @@ .regions = { { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 48 }, { .offset = 0x300000, .erasesize = 0x10000, .numblocks = 15 }, - { .offset = 0x3f0000, .erasesize = 0x02000, .numblocks = 8 }, + { .offset = 0x3f0000, .erasesize = 0x02000, .numblocks = 8 }, } }, { .mfr_id = MANUFACTURER_AMD, @@ -611,7 +625,27 @@ .regions = { { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 96 }, { .offset = 0x600000, .erasesize = 0x10000, .numblocks = 31 }, - { .offset = 0x7f0000, .erasesize = 0x02000, .numblocks = 8 }, + { .offset = 0x7f0000, .erasesize = 0x02000, .numblocks = 8 }, + } + }, { + .mfr_id = MANUFACTURER_ATMEL, + .dev_id = AT49xV16x, + .name = "Atmel AT49xV16x", + .size = 0x00200000, + .numeraseregions = 2, + .regions = { + { .offset = 0x000000, .erasesize = 0x02000, .numblocks = 8 }, + { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 } + } + }, { + .mfr_id = MANUFACTURER_ATMEL, + .dev_id = AT49xV16xT, + .name = "Atmel AT49xV16xT", + .size = 0x00200000, + .numeraseregions = 2, + .regions = { + { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 }, + { .offset = 0x1F0000, .erasesize = 0x02000, .numblocks = 8 } } } }; @@ -785,7 +819,7 @@ chip->state = FL_READY; - map->copy_from(map, buf, adr, len); + map_copy_from(map, buf, adr, len); wake_up(&chip->wq); spin_unlock_bh(chip->mutex); @@ -947,7 +981,7 @@ u_char tmp_buf[4]; __u32 datum; - map->copy_from(map, tmp_buf, + map_copy_from(map, tmp_buf, bus_ofs + private->chips[chipnum].start, map->buswidth); while (len && i < map->buswidth) @@ -1020,7 +1054,7 @@ u_char tmp_buf[2]; __u32 datum; - map->copy_from(map, tmp_buf, + map_copy_from(map, tmp_buf, ofs + private->chips[chipnum].start, map->buswidth); while (len--) { @@ -1141,7 +1175,7 @@ __u8 verify; for (address = adr; address < (adr + size); address++) { - if ((verify = map->read8(map, address)) != 0xFF) { + if ((verify = map_read8(map, address)) != 0xFF) { error = 1; break; } diff -Nru a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c --- a/drivers/mtd/chips/cfi_cmdset_0001.c Mon Jun 9 23:16:09 2003 +++ b/drivers/mtd/chips/cfi_cmdset_0001.c Mon Jun 9 23:16:09 2003 @@ -4,7 +4,7 @@ * * (C) 2000 Red Hat. GPL'd * - * $Id: cfi_cmdset_0001.c,v 1.87 2001/10/02 15:05:11 dwmw2 Exp $ + * $Id: cfi_cmdset_0001.c,v 1.123 2003/05/28 12:51:48 dwmw2 Exp $ * * * 10/10/2000 Nicolas Pitre <nico@cam.org> @@ -13,12 +13,15 @@ * - scalability vs code size is completely set at compile-time * (see include/linux/mtd/cfi.h for selection) * - optimized write buffer method + * 02/05/2002 Christopher Hoover <ch@hpl.hp.com>/<ch@murgatroid.com> + * - reworked lock/unlock/erase support for var size flash */ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/sched.h> +#include <linux/init.h> #include <asm/io.h> #include <asm/byteorder.h> @@ -27,10 +30,16 @@ #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/mtd/map.h> -#include <linux/mtd/cfi.h> +#include <linux/mtd/mtd.h> #include <linux/mtd/compatmac.h> +#include <linux/mtd/cfi.h> + +// debugging, turns off buffer write mode if set to 1 +#define FORCE_WORD_WRITE 0 static int cfi_intelext_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); +static int cfi_intelext_read_user_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *); +static int cfi_intelext_read_fact_prot_reg (struct mtd_info *, loff_t, size_t, size_t *, u_char *); static int cfi_intelext_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); static int cfi_intelext_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); static int cfi_intelext_erase_varsize(struct mtd_info *, struct erase_info *); @@ -46,6 +55,16 @@ static struct mtd_info *cfi_intelext_setup (struct map_info *); +static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char **mtdbuf); +static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, + size_t len); + + +/* + * *********** SETUP AND PROBE BITS *********** + */ + static struct mtd_chip_driver cfi_intelext_chipdrv = { .probe = NULL, /* Not usable directly */ .destroy = cfi_intelext_destroy, @@ -59,6 +78,7 @@ #ifdef DEBUG_CFI_FEATURES static void cfi_tell_features(struct cfi_pri_intelext *extp) { + int i; printk(" Feature/Command Support: %4.4X\n", extp->FeatureSupport); printk(" - Chip Erase: %s\n", extp->FeatureSupport&1?"supported":"unsupported"); printk(" - Suspend Erase: %s\n", extp->FeatureSupport&2?"supported":"unsupported"); @@ -110,7 +130,7 @@ int i; __u32 base = cfi->chips[0].start; - if (cfi->cfi_mode) { + if (cfi->cfi_mode == CFI_MODE_CFI) { /* * It's a real CFI chip, not one for which the probe * routine faked a CFI structure. So we read the feature @@ -140,7 +160,7 @@ } if (extp->MajorVersion != '1' || - (extp->MinorVersion < '0' || extp->MinorVersion > '2')) { + (extp->MinorVersion < '0' || extp->MinorVersion > '3')) { printk(KERN_WARNING " Unknown IntelExt Extended Query " "version %c.%c.\n", extp->MajorVersion, extp->MinorVersion); @@ -149,26 +169,38 @@ } /* Do some byteswapping if necessary */ - extp->FeatureSupport = cfi32_to_cpu(extp->FeatureSupport); - extp->BlkStatusRegMask = cfi32_to_cpu(extp->BlkStatusRegMask); - + extp->FeatureSupport = le32_to_cpu(extp->FeatureSupport); + extp->BlkStatusRegMask = le16_to_cpu(extp->BlkStatusRegMask); + extp->ProtRegAddr = le16_to_cpu(extp->ProtRegAddr); + #ifdef DEBUG_CFI_FEATURES /* Tell the user about it in lots of lovely detail */ cfi_tell_features(extp); #endif + if(extp->SuspendCmdSupport & 1) { +//#define CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE +#ifdef CMDSET0001_DISABLE_ERASE_SUSPEND_ON_WRITE +/* Some Intel Strata Flash prior to FPO revision C has bugs in this area */ + printk(KERN_WARNING "cfi_cmdset_0001: Suspend " + "erase on write disabled.\n"); + extp->SuspendCmdSupport &= ~1; +#else + printk(KERN_NOTICE "cfi_cmdset_0001: Erase suspend on write enabled\n"); +#endif + } /* Install our own private info structure */ - cfi->cmdset_priv = extp; - } + cfi->cmdset_priv = extp; + } for (i=0; i< cfi->numchips; i++) { - cfi->chips[i].word_write_time = 128; - cfi->chips[i].buffer_write_time = 128; - cfi->chips[i].erase_time = 1024; + 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; + cfi->chips[i].ref_point_counter = 0; } map->fldrv = &cfi_intelext_chipdrv; - MOD_INC_USE_COUNT; /* Make sure it's in read mode */ cfi_send_gen_cmd(0xff, 0x55, base, map, cfi, cfi->device_type, NULL); @@ -188,8 +220,7 @@ if (!mtd) { printk(KERN_ERR "Failed to allocate memory for MTD device\n"); - kfree(cfi->cmdset_priv); - return NULL; + goto setup_err; } memset(mtd, 0, sizeof(*mtd)); @@ -202,9 +233,7 @@ * mtd->numeraseregions, GFP_KERNEL); if (!mtd->eraseregions) { printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n"); - kfree(cfi->cmdset_priv); - kfree(mtd); - return NULL; + goto setup_err; } for (i=0; i<cfi->cfiq->NumEraseRegions; i++) { @@ -221,34 +250,39 @@ mtd->eraseregions[(j*cfi->cfiq->NumEraseRegions)+i].numblocks = ernum; } offset += (ersize * ernum); - } + } - if (offset != devsize) { - /* Argh */ - printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize); - kfree(mtd->eraseregions); - kfree(cfi->cmdset_priv); - kfree(mtd); - return NULL; - } + if (offset != devsize) { + /* Argh */ + printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize); + goto setup_err; + } - for (i=0; i<mtd->numeraseregions;i++){ - printk(KERN_DEBUG "%d: offset=0x%x,size=0x%x,blocks=%d\n", - i,mtd->eraseregions[i].offset, - mtd->eraseregions[i].erasesize, - mtd->eraseregions[i].numblocks); - } + for (i=0; i<mtd->numeraseregions;i++){ + printk(KERN_DEBUG "%d: offset=0x%x,size=0x%x,blocks=%d\n", + i,mtd->eraseregions[i].offset, + mtd->eraseregions[i].erasesize, + mtd->eraseregions[i].numblocks); + } /* Also select the correct geometry setup too */ - mtd->erase = cfi_intelext_erase_varsize; + mtd->erase = cfi_intelext_erase_varsize; mtd->read = cfi_intelext_read; - if ( cfi->cfiq->BufWriteTimeoutTyp ) { - //printk(KERN_INFO "Using buffer write method\n" ); + + if (map_is_linear(map)) { + mtd->point = cfi_intelext_point; + mtd->unpoint = cfi_intelext_unpoint; + } + + if ( cfi->cfiq->BufWriteTimeoutTyp && !FORCE_WORD_WRITE) { + printk(KERN_INFO "Using buffer write method\n" ); mtd->write = cfi_intelext_write_buffers; } else { - //printk(KERN_INFO "Using word write method\n" ); + printk(KERN_INFO "Using word write method\n" ); mtd->write = cfi_intelext_write_words; } + mtd->read_user_prot_reg = cfi_intelext_read_user_prot_reg; + mtd->read_fact_prot_reg = cfi_intelext_read_fact_prot_reg; mtd->sync = cfi_intelext_sync; mtd->lock = cfi_intelext_lock; mtd->unlock = cfi_intelext_unlock; @@ -256,127 +290,130 @@ mtd->resume = cfi_intelext_resume; mtd->flags = MTD_CAP_NORFLASH; map->fldrv = &cfi_intelext_chipdrv; - MOD_INC_USE_COUNT; mtd->name = map->name; + __module_get(THIS_MODULE); return mtd; + + setup_err: + if(mtd) { + if(mtd->eraseregions) + kfree(mtd->eraseregions); + kfree(mtd); + } + kfree(cfi->cmdset_priv); + kfree(cfi->cfiq); + return NULL; } +/* + * *********** CHIP ACCESS FUNCTIONS *********** + */ -static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf) +static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr, int mode) { - __u32 status, status_OK; - unsigned long timeo; DECLARE_WAITQUEUE(wait, current); - int suspended = 0; - unsigned long cmd_addr; struct cfi_private *cfi = map->fldrv_priv; + cfi_word status, status_OK = CMD(0x80); + unsigned long timeo; + struct cfi_pri_intelext *cfip = (struct cfi_pri_intelext *)cfi->cmdset_priv; - adr += chip->start; - - /* Ensure cmd read/writes are aligned. */ - cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1); - - /* Let's determine this according to the interleave only once */ - status_OK = CMD(0x80); - + resettime: timeo = jiffies + HZ; retry: - spin_lock_bh(chip->mutex); - - /* Check that the chip's ready to talk to us. - * If it's in FL_ERASING state, suspend it and make it talk now. - */ switch (chip->state) { + + case FL_STATUS: + for (;;) { + status = cfi_read(map, adr); + if ((status & status_OK) == status_OK) + break; + + if (time_after(jiffies, timeo)) { + printk(KERN_ERR "Waiting for chip to be ready timed out. Status %llx\n", + (long long)status); + spin_unlock(chip->mutex); + return -EIO; + } + spin_unlock(chip->mutex); + cfi_udelay(1); + spin_lock(chip->mutex); + /* Someone else might have been playing with it. */ + goto retry; + } + + case FL_READY: + case FL_CFI_QUERY: + case FL_JEDEC_QUERY: + return 0; + case FL_ERASING: - if (!((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2) - goto sleep; /* We don't support erase suspend */ - - cfi_write (map, CMD(0xb0), cmd_addr); + if (!(cfip->FeatureSupport & 2) || + !(mode == FL_READY || mode == FL_POINT || + (mode == FL_WRITING && (cfip->SuspendCmdSupport & 1)))) + goto sleep; + + + /* Erase suspend */ + cfi_write(map, CMD(0xB0), adr); + /* If the flash has finished erasing, then 'erase suspend' * appears to make some (28F320) flash devices switch to * 'read' mode. Make sure that we switch to 'read status' * mode so we get the right data. --rmk */ - cfi_write(map, CMD(0x70), cmd_addr); + cfi_write(map, CMD(0x70), adr); chip->oldstate = FL_ERASING; chip->state = FL_ERASE_SUSPENDING; - // printk("Erase suspending at 0x%lx\n", cmd_addr); + chip->erase_suspended = 1; for (;;) { - status = cfi_read(map, cmd_addr); + status = cfi_read(map, adr); if ((status & status_OK) == status_OK) - break; - + break; + if (time_after(jiffies, timeo)) { - /* Urgh */ - cfi_write(map, CMD(0xd0), cmd_addr); - /* make sure we're in 'read status' mode */ - cfi_write(map, CMD(0x70), cmd_addr); + /* Urgh. Resume and pretend we weren't here. */ + cfi_write(map, CMD(0xd0), adr); + /* Make sure we're in 'read status' mode if it had finished */ + cfi_write(map, CMD(0x70), adr); chip->state = FL_ERASING; - spin_unlock_bh(chip->mutex); + chip->oldstate = FL_READY; printk(KERN_ERR "Chip not ready after erase " "suspended: status = 0x%x\n", status); return -EIO; } - - spin_unlock_bh(chip->mutex); + + spin_unlock(chip->mutex); cfi_udelay(1); - spin_lock_bh(chip->mutex); + spin_lock(chip->mutex); + /* Nobody will touch it while it's in state FL_ERASE_SUSPENDING. + So we can just loop here. */ } - - suspended = 1; - cfi_write(map, CMD(0xff), cmd_addr); - chip->state = FL_READY; - break; - -#if 0 - case FL_WRITING: - /* Not quite yet */ -#endif - - case FL_READY: - break; - - case FL_CFI_QUERY: - case FL_JEDEC_QUERY: - cfi_write(map, CMD(0x70), cmd_addr); chip->state = FL_STATUS; + return 0; - case FL_STATUS: - status = cfi_read(map, cmd_addr); - if ((status & status_OK) == status_OK) { - cfi_write(map, CMD(0xff), cmd_addr); - chip->state = FL_READY; - break; - } - - /* Urgh. Chip not yet ready to talk to us. */ - if (time_after(jiffies, timeo)) { - spin_unlock_bh(chip->mutex); - printk(KERN_ERR "waiting for chip to be ready timed out in read. WSM status = %x\n", status); - return -EIO; - } - - /* Latency issues. Drop the lock, wait a while and retry */ - spin_unlock_bh(chip->mutex); - cfi_udelay(1); - goto retry; + case FL_POINT: + /* Only if there's no operation suspended... */ + if (mode == FL_READY && chip->oldstate == FL_READY) + return 0; default: sleep: - /* Stick ourselves on a wait queue to be woken when - someone changes the status */ set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); - spin_unlock_bh(chip->mutex); + spin_unlock(chip->mutex); schedule(); remove_wait_queue(&chip->wq, &wait); - timeo = jiffies + HZ; - goto retry; + spin_lock(chip->mutex); + goto resettime; } +} - map->copy_from(map, buf, adr, len); +static void put_chip(struct map_info *map, struct flchip *chip, unsigned long adr) +{ + struct cfi_private *cfi = map->fldrv_priv; - if (suspended) { + switch(chip->oldstate) { + case FL_ERASING: chip->state = chip->oldstate; /* What if one interleaved chip has finished and the other hasn't? The old code would leave the finished @@ -387,12 +424,167 @@ sending the 0x70 (Read Status) command to an erasing chip and expecting it to be ignored, that's what we do. */ - cfi_write(map, CMD(0xd0), cmd_addr); - cfi_write(map, CMD(0x70), cmd_addr); - } + cfi_write(map, CMD(0xd0), adr); + cfi_write(map, CMD(0x70), adr); + chip->oldstate = FL_READY; + chip->state = FL_ERASING; + break; + case FL_READY: + /* We should really make set_vpp() count, rather than doing this */ + DISABLE_VPP(map); + break; + default: + printk(KERN_ERR "put_chip() called with oldstate %d!!\n", chip->oldstate); + } wake_up(&chip->wq); - spin_unlock_bh(chip->mutex); +} + +static int do_point_onechip (struct map_info *map, struct flchip *chip, loff_t adr, size_t len) +{ + unsigned long cmd_addr; + struct cfi_private *cfi = map->fldrv_priv; + int ret = 0; + + adr += chip->start; + + /* Ensure cmd read/writes are aligned. */ + cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1); + + spin_lock(chip->mutex); + + ret = get_chip(map, chip, cmd_addr, FL_POINT); + + if (!ret) { + if (chip->state != FL_POINT && chip->state != FL_READY) + cfi_write(map, CMD(0xff), cmd_addr); + + chip->state = FL_POINT; + chip->ref_point_counter++; + } + spin_unlock(chip->mutex); + + return ret; +} + +static int cfi_intelext_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf) +{ + struct map_info *map = mtd->priv; + struct cfi_private *cfi = map->fldrv_priv; + unsigned long ofs; + int chipnum; + int ret = 0; + + if (from + len > mtd->size) + return -EINVAL; + + *mtdbuf = (void *)map->virt + from; + if(*mtdbuf == NULL) + return -EINVAL; /* can not point this region */ + *retlen = 0; + + /* Now lock the chip(s) to POINT state */ + + /* ofs: offset within the first chip that the first read should start */ + chipnum = (from >> cfi->chipshift); + ofs = from - (chipnum << cfi->chipshift); + + 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_point_onechip(map, &cfi->chips[chipnum], ofs, thislen); + if (ret) + break; + + *retlen += thislen; + len -= thislen; + + ofs = 0; + chipnum++; + } + return 0; +} + +static void cfi_intelext_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) +{ + struct map_info *map = mtd->priv; + struct cfi_private *cfi = map->fldrv_priv; + unsigned long ofs; + int chipnum; + + /* Now unlock the chip(s) POINT state */ + + /* ofs: offset within the first chip that the first read should start */ + chipnum = (from >> cfi->chipshift); + ofs = from - (chipnum << cfi->chipshift); + + while (len) { + unsigned long thislen; + struct flchip *chip; + + chip = &cfi->chips[chipnum]; + if (chipnum >= cfi->numchips) + break; + + if ((len + ofs -1) >> cfi->chipshift) + thislen = (1<<cfi->chipshift) - ofs; + else + thislen = len; + + spin_lock(chip->mutex); + if (chip->state == FL_POINT) { + chip->ref_point_counter--; + if(chip->ref_point_counter == 0) + chip->state = FL_READY; + } else + printk(KERN_ERR "Warning: unpoint called on non pointed region\n"); /* Should this give an error? */ + + put_chip(map, chip, chip->start); + spin_unlock(chip->mutex); + + len -= thislen; + ofs = 0; + chipnum++; + } +} + +static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf) +{ + unsigned long cmd_addr; + struct cfi_private *cfi = map->fldrv_priv; + int ret; + + adr += chip->start; + + /* Ensure cmd read/writes are aligned. */ + cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1); + + spin_lock(chip->mutex); + ret = get_chip(map, chip, cmd_addr, FL_READY); + if (ret) { + spin_unlock(chip->mutex); + return ret; + } + + if (chip->state != FL_POINT && chip->state != FL_READY) { + cfi_write(map, CMD(0xff), cmd_addr); + + chip->state = FL_READY; + } + + map_copy_from(map, buf, adr, len); + + put_chip(map, chip, cmd_addr); + + spin_unlock(chip->mutex); return 0; } @@ -435,64 +627,115 @@ return ret; } -static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, __u32 datum) +static int cfi_intelext_read_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, int base_offst, int reg_sz) { + struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; - __u32 status, status_OK; - unsigned long timeo; - DECLARE_WAITQUEUE(wait, current); - int z; + struct cfi_pri_intelext *extp = cfi->cmdset_priv; + struct flchip *chip; + int ofs_factor = cfi->interleave * cfi->device_type; + int count = len; + int chip_num, offst; + int ret; - adr += chip->start; + chip_num = ((unsigned int)from/reg_sz); + offst = from - (reg_sz*chip_num)+base_offst; - /* Let's determine this according to the interleave only once */ - status_OK = CMD(0x80); + while (count) { + /* Calculate which chip & protection register offset we need */ - timeo = jiffies + HZ; - retry: - spin_lock_bh(chip->mutex); + if (chip_num >= cfi->numchips) + goto out; - /* Check that the chip's ready to talk to us. - * Later, we can actually think about interrupting it - * if it's in FL_ERASING state. - * Not just yet, though. - */ - switch (chip->state) { - case FL_READY: - break; + chip = &cfi->chips[chip_num]; - case FL_CFI_QUERY: - case FL_JEDEC_QUERY: - cfi_write(map, CMD(0x70), adr); - chip->state = FL_STATUS; + spin_lock(chip->mutex); + ret = get_chip(map, chip, chip->start, FL_JEDEC_QUERY); + if (ret) { + spin_unlock(chip->mutex); + return (len-count)?:ret; + } - case FL_STATUS: - status = cfi_read(map, adr); - if ((status & status_OK) == status_OK) - break; - - /* Urgh. Chip not yet ready to talk to us. */ - if (time_after(jiffies, timeo)) { - spin_unlock_bh(chip->mutex); - printk(KERN_ERR "waiting for chip to be ready timed out in read\n"); - return -EIO; + if (chip->state != FL_JEDEC_QUERY) { + cfi_write(map, CMD(0x90), chip->start); + chip->state = FL_JEDEC_QUERY; } - /* Latency issues. Drop the lock, wait a while and retry */ - spin_unlock_bh(chip->mutex); - cfi_udelay(1); - goto retry; + while (count && ((offst-base_offst) < reg_sz)) { + *buf = map_read8(map,(chip->start+((extp->ProtRegAddr+1)*ofs_factor)+offst)); + buf++; + offst++; + count--; + } - default: - /* Stick ourselves on a wait queue to be woken when - someone changes the status */ - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&chip->wq, &wait); - spin_unlock_bh(chip->mutex); - schedule(); - remove_wait_queue(&chip->wq, &wait); - timeo = jiffies + HZ; - goto retry; + put_chip(map, chip, chip->start); + spin_unlock(chip->mutex); + + /* Move on to the next chip */ + chip_num++; + offst = base_offst; + } + + out: + return len-count; +} + +static int cfi_intelext_read_user_prot_reg (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; + struct cfi_pri_intelext *extp=cfi->cmdset_priv; + int base_offst,reg_sz; + + /* Check that we actually have some protection registers */ + if(!(extp->FeatureSupport&64)){ + printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name); + return 0; + } + + base_offst=(1<<extp->FactProtRegSize); + reg_sz=(1<<extp->UserProtRegSize); + + return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz); +} + +static int cfi_intelext_read_fact_prot_reg (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; + struct cfi_pri_intelext *extp=cfi->cmdset_priv; + int base_offst,reg_sz; + + /* Check that we actually have some protection registers */ + if(!(extp->FeatureSupport&64)){ + printk(KERN_WARNING "%s: This flash device has no protection data to read!\n",map->name); + return 0; + } + + base_offst=0; + reg_sz=(1<<extp->FactProtRegSize); + + return cfi_intelext_read_prot_reg(mtd, from, len, retlen, buf, base_offst, reg_sz); +} + + +static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, cfi_word datum) +{ + struct cfi_private *cfi = map->fldrv_priv; + cfi_word status, status_OK; + unsigned long timeo; + int z, ret=0; + + adr += chip->start; + + /* Let's determine this according to the interleave only once */ + status_OK = CMD(0x80); + + spin_lock(chip->mutex); + ret = get_chip(map, chip, adr, FL_WRITING); + if (ret) { + spin_unlock(chip->mutex); + return ret; } ENABLE_VPP(map); @@ -500,22 +743,24 @@ cfi_write(map, datum, adr); chip->state = FL_WRITING; - spin_unlock_bh(chip->mutex); + spin_unlock(chip->mutex); cfi_udelay(chip->word_write_time); - spin_lock_bh(chip->mutex); + spin_lock(chip->mutex); timeo = jiffies + (HZ/2); z = 0; for (;;) { if (chip->state != FL_WRITING) { /* Someone's suspended the write. Sleep */ + DECLARE_WAITQUEUE(wait, current); + set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); - spin_unlock_bh(chip->mutex); + spin_unlock(chip->mutex); schedule(); remove_wait_queue(&chip->wq, &wait); timeo = jiffies + (HZ / 2); /* FIXME */ - spin_lock_bh(chip->mutex); + spin_lock(chip->mutex); continue; } @@ -526,17 +771,16 @@ /* OK Still waiting */ if (time_after(jiffies, timeo)) { chip->state = FL_STATUS; - DISABLE_VPP(map); - spin_unlock_bh(chip->mutex); printk(KERN_ERR "waiting for chip to be ready timed out in word write\n"); - return -EIO; + ret = -EIO; + goto out; } /* Latency issues. Drop the lock, wait a while and retry */ - spin_unlock_bh(chip->mutex); + spin_unlock(chip->mutex); z++; cfi_udelay(1); - spin_lock_bh(chip->mutex); + spin_lock(chip->mutex); } if (!z) { chip->word_write_time--; @@ -547,7 +791,6 @@ chip->word_write_time++; /* Done and happy. */ - DISABLE_VPP(map); chip->state = FL_STATUS; /* check for lock bit */ if (status & CMD(0x02)) { @@ -555,13 +798,13 @@ cfi_write(map, CMD(0x50), adr); /* put back into read status register mode */ cfi_write(map, CMD(0x70), adr); - wake_up(&chip->wq); - spin_unlock_bh(chip->mutex); - return -EROFS; + ret = -EROFS; } - wake_up(&chip->wq); - spin_unlock_bh(chip->mutex); - return 0; + out: + put_chip(map, chip, adr); + spin_unlock(chip->mutex); + + return ret; } @@ -585,8 +828,8 @@ unsigned long bus_ofs = ofs & ~(CFIDEV_BUSWIDTH-1); int gap = ofs - bus_ofs; int i = 0, n = 0; - u_char tmp_buf[4]; - __u32 datum; + u_char tmp_buf[8]; + cfi_word datum; while (gap--) tmp_buf[i++] = 0xff; @@ -599,6 +842,8 @@ datum = *(__u16*)tmp_buf; } else if (cfi_buswidth_is_4()) { datum = *(__u32*)tmp_buf; + } else if (cfi_buswidth_is_8()) { + datum = *(__u64*)tmp_buf; } else { return -EINVAL; /* should never happen, but be safe */ } @@ -621,7 +866,7 @@ } while(len >= CFIDEV_BUSWIDTH) { - __u32 datum; + cfi_word datum; if (cfi_buswidth_is_1()) { datum = *(__u8*)buf; @@ -629,6 +874,8 @@ datum = *(__u16*)buf; } else if (cfi_buswidth_is_4()) { datum = *(__u32*)buf; + } else if (cfi_buswidth_is_8()) { + datum = *(__u64*)buf; } else { return -EINVAL; } @@ -653,8 +900,8 @@ if (len & (CFIDEV_BUSWIDTH-1)) { int i = 0, n = 0; - u_char tmp_buf[4]; - __u32 datum; + u_char tmp_buf[8]; + cfi_word datum; while (len--) tmp_buf[i++] = buf[n++]; @@ -665,6 +912,8 @@ datum = *(__u16*)tmp_buf; } else if (cfi_buswidth_is_4()) { datum = *(__u32*)tmp_buf; + } else if (cfi_buswidth_is_8()) { + datum = *(__u64*)tmp_buf; } else { return -EINVAL; /* should never happen, but be safe */ } @@ -685,10 +934,9 @@ unsigned long adr, const u_char *buf, int len) { struct cfi_private *cfi = map->fldrv_priv; - __u32 status, status_OK; + cfi_word status, status_OK; unsigned long cmd_adr, timeo; - DECLARE_WAITQUEUE(wait, current); - int wbufsize, z; + int wbufsize, z, ret=0; wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize; adr += chip->start; @@ -697,74 +945,52 @@ /* Let's determine this according to the interleave only once */ status_OK = CMD(0x80); - timeo = jiffies + HZ; - retry: - spin_lock_bh(chip->mutex); + spin_lock(chip->mutex); + ret = get_chip(map, chip, cmd_adr, FL_WRITING); + if (ret) { + spin_unlock(chip->mutex); + return ret; + } - /* Check that the chip's ready to talk to us. - * Later, we can actually think about interrupting it - * if it's in FL_ERASING state. - * Not just yet, though. - */ - switch (chip->state) { - case FL_READY: - break; - - case FL_CFI_QUERY: - case FL_JEDEC_QUERY: + if (chip->state != FL_STATUS) cfi_write(map, CMD(0x70), cmd_adr); - chip->state = FL_STATUS; - - case FL_STATUS: - status = cfi_read(map, cmd_adr); - if ((status & status_OK) == status_OK) - break; - /* Urgh. Chip not yet ready to talk to us. */ - if (time_after(jiffies, timeo)) { - spin_unlock_bh(chip->mutex); - printk(KERN_ERR "waiting for chip to be ready timed out in buffer write\n"); - return -EIO; - } - /* Latency issues. Drop the lock, wait a while and retry */ - spin_unlock_bh(chip->mutex); - cfi_udelay(1); - goto retry; + status = cfi_read(map, cmd_adr); - default: - /* Stick ourselves on a wait queue to be woken when - someone changes the status */ - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&chip->wq, &wait); - spin_unlock_bh(chip->mutex); - schedule(); - remove_wait_queue(&chip->wq, &wait); - timeo = jiffies + HZ; - goto retry; + /* §4.8 of the 28FxxxJ3A datasheet says "Any time SR.4 and/or SR.5 is set + [...], the device will not accept any more Write to Buffer commands". + So we must check here and reset those bits if they're set. Otherwise + we're just pissing in the wind */ + if (status & CMD(0x30)) { + printk(KERN_WARNING "SR.4 or SR.5 bits set in buffer write (status %x). Clearing.\n", status); + cfi_write(map, CMD(0x50), cmd_adr); + cfi_write(map, CMD(0x70), cmd_adr); } - ENABLE_VPP(map); - cfi_write(map, CMD(0xe8), cmd_adr); chip->state = FL_WRITING_TO_BUFFER; z = 0; for (;;) { + cfi_write(map, CMD(0xe8), cmd_adr); + status = cfi_read(map, cmd_adr); if ((status & status_OK) == status_OK) break; - spin_unlock_bh(chip->mutex); + spin_unlock(chip->mutex); cfi_udelay(1); - spin_lock_bh(chip->mutex); + spin_lock(chip->mutex); if (++z > 20) { /* Argh. Not ready for write to buffer */ cfi_write(map, CMD(0x70), cmd_adr); chip->state = FL_STATUS; - DISABLE_VPP(map); - spin_unlock_bh(chip->mutex); - printk(KERN_ERR "Chip not ready for buffer write. Xstatus = %x, status = %x\n", status, cfi_read(map, cmd_adr)); - return -EIO; + printk(KERN_ERR "Chip not ready for buffer write. Xstatus = %llx, status = %llx\n", (__u64)status, (__u64)cfi_read(map, cmd_adr)); + /* Odd. Clear status bits */ + cfi_write(map, CMD(0x50), cmd_adr); + cfi_write(map, CMD(0x70), cmd_adr); + ret = -EIO; + goto out; } } @@ -774,36 +1000,39 @@ /* Write data */ for (z = 0; z < len; z += CFIDEV_BUSWIDTH) { if (cfi_buswidth_is_1()) { - map->write8 (map, *((__u8*)buf)++, adr+z); + map_write8 (map, *((__u8*)buf)++, adr+z); } else if (cfi_buswidth_is_2()) { - map->write16 (map, *((__u16*)buf)++, adr+z); + map_write16 (map, *((__u16*)buf)++, adr+z); } else if (cfi_buswidth_is_4()) { - map->write32 (map, *((__u32*)buf)++, adr+z); + map_write32 (map, *((__u32*)buf)++, adr+z); + } else if (cfi_buswidth_is_8()) { + map_write64 (map, *((__u64*)buf)++, adr+z); } else { - DISABLE_VPP(map); - return -EINVAL; + ret = -EINVAL; + goto out; } } /* GO GO GO */ cfi_write(map, CMD(0xd0), cmd_adr); chip->state = FL_WRITING; - spin_unlock_bh(chip->mutex); + spin_unlock(chip->mutex); cfi_udelay(chip->buffer_write_time); - spin_lock_bh(chip->mutex); + spin_lock(chip->mutex); timeo = jiffies + (HZ/2); z = 0; for (;;) { if (chip->state != FL_WRITING) { /* Someone's suspended the write. Sleep */ + DECLARE_WAITQUEUE(wait, current); set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); - spin_unlock_bh(chip->mutex); + spin_unlock(chip->mutex); schedule(); remove_wait_queue(&chip->wq, &wait); timeo = jiffies + (HZ / 2); /* FIXME */ - spin_lock_bh(chip->mutex); + spin_lock(chip->mutex); continue; } @@ -814,17 +1043,16 @@ /* OK Still waiting */ if (time_after(jiffies, timeo)) { chip->state = FL_STATUS; - DISABLE_VPP(map); - spin_unlock_bh(chip->mutex); printk(KERN_ERR "waiting for chip to be ready timed out in bufwrite\n"); - return -EIO; + ret = -EIO; + goto out; } /* Latency issues. Drop the lock, wait a while and retry */ - spin_unlock_bh(chip->mutex); + spin_unlock(chip->mutex); cfi_udelay(1); z++; - spin_lock_bh(chip->mutex); + spin_lock(chip->mutex); } if (!z) { chip->buffer_write_time--; @@ -835,21 +1063,21 @@ chip->buffer_write_time++; /* Done and happy. */ - DISABLE_VPP(map); - chip->state = FL_STATUS; + chip->state = FL_STATUS; + /* check for lock bit */ if (status & CMD(0x02)) { /* clear status */ cfi_write(map, CMD(0x50), cmd_adr); /* put back into read status register mode */ cfi_write(map, CMD(0x70), adr); - wake_up(&chip->wq); - spin_unlock_bh(chip->mutex); - return -EROFS; + ret = -EROFS; } - wake_up(&chip->wq); - spin_unlock_bh(chip->mutex); - return 0; + + out: + put_chip(map, chip, cmd_adr); + spin_unlock(chip->mutex); + return ret; } static int cfi_intelext_write_buffers (struct mtd_info *mtd, loff_t to, @@ -928,11 +1156,102 @@ return 0; } +typedef int (*varsize_frob_t)(struct map_info *map, struct flchip *chip, + unsigned long adr, void *thunk); + +static int cfi_intelext_varsize_frob(struct mtd_info *mtd, varsize_frob_t frob, + loff_t ofs, size_t len, void *thunk) +{ + struct map_info *map = mtd->priv; + struct cfi_private *cfi = map->fldrv_priv; + unsigned long adr; + int chipnum, ret = 0; + int i, first; + struct mtd_erase_region_info *regions = mtd->eraseregions; + + if (ofs > mtd->size) + return -EINVAL; + + if ((len + ofs) > 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 && ofs >= 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 (ofs & (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 && (ofs + len) >= regions[i].offset) + i++; + + /* As before, drop back one to point at the region in which + the address actually falls + */ + i--; + + if ((ofs + len) & (regions[i].erasesize-1)) + return -EINVAL; + + chipnum = ofs >> cfi->chipshift; + adr = ofs - (chipnum << cfi->chipshift); + + i=first; + + while(len) { + ret = (*frob)(map, &cfi->chips[chipnum], adr, thunk); + + 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; + } + } + + return 0; +} + -static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr) +static int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk) { struct cfi_private *cfi = map->fldrv_priv; - __u32 status, status_OK; + cfi_word status, status_OK; unsigned long timeo; int retries = 3; DECLARE_WAITQUEUE(wait, current); @@ -943,45 +1262,12 @@ /* Let's determine this according to the interleave only once */ status_OK = CMD(0x80); - timeo = jiffies + HZ; -retry: - spin_lock_bh(chip->mutex); - - /* Check that the chip's ready to talk to us. */ - switch (chip->state) { - case FL_CFI_QUERY: - case FL_JEDEC_QUERY: - case FL_READY: - cfi_write(map, CMD(0x70), adr); - chip->state = FL_STATUS; - - case FL_STATUS: - status = cfi_read(map, adr); - if ((status & status_OK) == status_OK) - break; - - /* Urgh. Chip not yet ready to talk to us. */ - if (time_after(jiffies, timeo)) { - spin_unlock_bh(chip->mutex); - printk(KERN_ERR "waiting for chip to be ready timed out in erase\n"); - return -EIO; - } - - /* Latency issues. Drop the lock, wait a while and retry */ - spin_unlock_bh(chip->mutex); - cfi_udelay(1); - goto retry; - - default: - /* Stick ourselves on a wait queue to be woken when - someone changes the status */ - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&chip->wq, &wait); - spin_unlock_bh(chip->mutex); - schedule(); - remove_wait_queue(&chip->wq, &wait); - timeo = jiffies + HZ; - goto retry; + retry: + spin_lock(chip->mutex); + ret = get_chip(map, chip, adr, FL_ERASING); + if (ret) { + spin_unlock(chip->mutex); + return ret; } ENABLE_VPP(map); @@ -992,10 +1278,12 @@ cfi_write(map, CMD(0x20), adr); cfi_write(map, CMD(0xD0), adr); chip->state = FL_ERASING; - - spin_unlock_bh(chip->mutex); - schedule_timeout(HZ); - spin_lock_bh(chip->mutex); + chip->erase_suspended = 0; + + spin_unlock(chip->mutex); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((chip->erase_time*HZ)/(2*1000)); + spin_lock(chip->mutex); /* FIXME. Use a timer to check this, and return immediately. */ /* Once the state machine's known to be working I'll do that */ @@ -1006,13 +1294,18 @@ /* Someone's suspended the erase. Sleep */ set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); - spin_unlock_bh(chip->mutex); + spin_unlock(chip->mutex); schedule(); remove_wait_queue(&chip->wq, &wait); - timeo = jiffies + (HZ*20); /* FIXME */ - spin_lock_bh(chip->mutex); + spin_lock(chip->mutex); continue; } + if (chip->erase_suspended) { + /* This erase was suspended and resumed. + Adjust the timeout */ + timeo = jiffies + (HZ*20); /* FIXME */ + chip->erase_suspended = 0; + } status = cfi_read(map, adr); if ((status & status_OK) == status_OK) @@ -1022,16 +1315,21 @@ if (time_after(jiffies, timeo)) { cfi_write(map, CMD(0x70), adr); chip->state = FL_STATUS; - printk(KERN_ERR "waiting for erase to complete timed out. Xstatus = %x, status = %x.\n", status, cfi_read(map, adr)); + printk(KERN_ERR "waiting for erase at %08lx to complete timed out. Xstatus = %llx, status = %llx.\n", + adr, (__u64)status, (__u64)cfi_read(map, adr)); + /* Clear status bits */ + cfi_write(map, CMD(0x50), adr); + cfi_write(map, CMD(0x70), adr); DISABLE_VPP(map); - spin_unlock_bh(chip->mutex); + spin_unlock(chip->mutex); return -EIO; } /* Latency issues. Drop the lock, wait a while and retry */ - spin_unlock_bh(chip->mutex); - cfi_udelay(1); - spin_lock_bh(chip->mutex); + spin_unlock(chip->mutex); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(1); + spin_lock(chip->mutex); } DISABLE_VPP(map); @@ -1050,124 +1348,52 @@ for (i = 1; i<CFIDEV_INTERLEAVE; i++) { chipstatus |= status >> (cfi->device_type * 8); } - printk(KERN_WARNING "Status is not identical for all chips: 0x%x. Merging to give 0x%02x\n", status, chipstatus); + printk(KERN_WARNING "Status is not identical for all chips: 0x%llx. Merging to give 0x%02x\n", (__u64)status, chipstatus); } /* Reset the error bits */ cfi_write(map, CMD(0x50), adr); cfi_write(map, CMD(0x70), adr); if ((chipstatus & 0x30) == 0x30) { - printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\n", status); + printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%llx\n", (__u64)status); ret = -EIO; } else if (chipstatus & 0x02) { /* Protection bit set */ ret = -EROFS; } else if (chipstatus & 0x8) { /* Voltage */ - printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%x\n", status); + printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%llx\n", (__u64)status); ret = -EIO; } else if (chipstatus & 0x20) { if (retries--) { - printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x. Retrying...\n", adr, status); + printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%llx. Retrying...\n", adr, (__u64)status); timeo = jiffies + HZ; chip->state = FL_STATUS; - spin_unlock_bh(chip->mutex); + spin_unlock(chip->mutex); goto retry; } - printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x\n", adr, status); + printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%llx\n", adr, (__u64)status); ret = -EIO; } } wake_up(&chip->wq); - spin_unlock_bh(chip->mutex); + spin_unlock(chip->mutex); return ret; } int cfi_intelext_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; +{ + unsigned long ofs, len; + int ret; - chipnum = instr->addr >> cfi->chipshift; - adr = instr->addr - (chipnum << cfi->chipshift); + ofs = instr->addr; len = instr->len; - i=first; + ret = cfi_intelext_varsize_frob(mtd, do_erase_oneblock, ofs, len, 0); + if (ret) + return ret; - 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); @@ -1182,38 +1408,20 @@ 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: - spin_lock_bh(chip->mutex); + spin_lock(chip->mutex); + ret = get_chip(map, chip, chip->start, FL_SYNCING); - switch(chip->state) { - case FL_READY: - case FL_STATUS: - case FL_CFI_QUERY: - case FL_JEDEC_QUERY: + if (!ret) { 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: - spin_unlock_bh(chip->mutex); - break; - - default: - /* Not an idle state */ - add_wait_queue(&chip->wq, &wait); - - spin_unlock_bh(chip->mutex); - schedule(); - remove_wait_queue(&chip->wq, &wait); - - goto retry; } } @@ -1222,231 +1430,73 @@ for (i--; i >=0; i--) { chip = &cfi->chips[i]; - spin_lock_bh(chip->mutex); + spin_lock(chip->mutex); if (chip->state == FL_SYNCING) { chip->state = chip->oldstate; wake_up(&chip->wq); } - spin_unlock_bh(chip->mutex); + spin_unlock(chip->mutex); } } -static inline int do_lock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr) +#ifdef DEBUG_LOCK_BITS +static int do_printlockstatus_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk) { struct cfi_private *cfi = map->fldrv_priv; - __u32 status, status_OK; - unsigned long timeo = jiffies + HZ; - DECLARE_WAITQUEUE(wait, current); - - adr += chip->start; - - /* Let's determine this according to the interleave only once */ - status_OK = CMD(0x80); - - timeo = jiffies + HZ; -retry: - spin_lock_bh(chip->mutex); - - /* Check that the chip's ready to talk to us. */ - switch (chip->state) { - case FL_CFI_QUERY: - case FL_JEDEC_QUERY: - case FL_READY: - cfi_write(map, CMD(0x70), adr); - chip->state = FL_STATUS; - - case FL_STATUS: - status = cfi_read(map, adr); - if ((status & status_OK) == status_OK) - break; - - /* Urgh. Chip not yet ready to talk to us. */ - if (time_after(jiffies, timeo)) { - spin_unlock_bh(chip->mutex); - printk(KERN_ERR "waiting for chip to be ready timed out in lock\n"); - return -EIO; - } - - /* Latency issues. Drop the lock, wait a while and retry */ - spin_unlock_bh(chip->mutex); - cfi_udelay(1); - goto retry; - - default: - /* Stick ourselves on a wait queue to be woken when - someone changes the status */ - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&chip->wq, &wait); - spin_unlock_bh(chip->mutex); - schedule(); - remove_wait_queue(&chip->wq, &wait); - timeo = jiffies + HZ; - goto retry; - } - - ENABLE_VPP(map); - cfi_write(map, CMD(0x60), adr); - cfi_write(map, CMD(0x01), adr); - chip->state = FL_LOCKING; - - spin_unlock_bh(chip->mutex); - schedule_timeout(HZ); - spin_lock_bh(chip->mutex); - - /* FIXME. Use a timer to check this, and return immediately. */ - /* Once the state machine's known to be working I'll do that */ - - timeo = jiffies + (HZ*2); - for (;;) { + int ofs_factor = cfi->interleave * cfi->device_type; - status = cfi_read(map, adr); - if ((status & status_OK) == status_OK) - break; - - /* OK Still waiting */ - if (time_after(jiffies, timeo)) { - cfi_write(map, CMD(0x70), adr); - chip->state = FL_STATUS; - printk(KERN_ERR "waiting for lock to complete timed out. Xstatus = %x, status = %x.\n", status, cfi_read(map, adr)); - DISABLE_VPP(map); - spin_unlock_bh(chip->mutex); - return -EIO; - } - - /* Latency issues. Drop the lock, wait a while and retry */ - spin_unlock_bh(chip->mutex); - cfi_udelay(1); - spin_lock_bh(chip->mutex); - } + cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL); + printk(KERN_DEBUG "block status register for 0x%08lx is %x\n", + adr, cfi_read_query(map, adr+(2*ofs_factor))); + cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL); - /* Done and happy. */ - chip->state = FL_STATUS; - DISABLE_VPP(map); - wake_up(&chip->wq); - spin_unlock_bh(chip->mutex); return 0; } -static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len) -{ - struct map_info *map = mtd->priv; - struct cfi_private *cfi = map->fldrv_priv; - unsigned long adr; - int chipnum, ret = 0; -#ifdef DEBUG_LOCK_BITS - int ofs_factor = cfi->interleave * cfi->device_type; -#endif - - if (ofs & (mtd->erasesize - 1)) - return -EINVAL; - - if (len & (mtd->erasesize -1)) - return -EINVAL; - - if ((len + ofs) > mtd->size) - return -EINVAL; - - chipnum = ofs >> cfi->chipshift; - adr = ofs - (chipnum << cfi->chipshift); - - while(len) { - -#ifdef DEBUG_LOCK_BITS - cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL); - printk("before lock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor))); - cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL); #endif - ret = do_lock_oneblock(map, &cfi->chips[chipnum], adr); - -#ifdef DEBUG_LOCK_BITS - cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL); - printk("after lock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor))); - cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL); -#endif - - if (ret) - return ret; - - adr += mtd->erasesize; - len -= mtd->erasesize; +#define DO_XXLOCK_ONEBLOCK_LOCK ((void *) 1) +#define DO_XXLOCK_ONEBLOCK_UNLOCK ((void *) 2) - if (adr >> cfi->chipshift) { - adr = 0; - chipnum++; - - if (chipnum >= cfi->numchips) - break; - } - } - return 0; -} -static inline int do_unlock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr) +static int do_xxlock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr, void *thunk) { struct cfi_private *cfi = map->fldrv_priv; - __u32 status, status_OK; + cfi_word status, status_OK; unsigned long timeo = jiffies + HZ; - DECLARE_WAITQUEUE(wait, current); + int ret; adr += chip->start; /* Let's determine this according to the interleave only once */ status_OK = CMD(0x80); - timeo = jiffies + HZ; -retry: - spin_lock_bh(chip->mutex); - - /* Check that the chip's ready to talk to us. */ - switch (chip->state) { - case FL_CFI_QUERY: - case FL_JEDEC_QUERY: - case FL_READY: - cfi_write(map, CMD(0x70), adr); - chip->state = FL_STATUS; - - case FL_STATUS: - status = cfi_read(map, adr); - if ((status & status_OK) == status_OK) - break; - - /* Urgh. Chip not yet ready to talk to us. */ - if (time_after(jiffies, timeo)) { - spin_unlock_bh(chip->mutex); - printk(KERN_ERR "waiting for chip to be ready timed out in unlock\n"); - return -EIO; - } - - /* Latency issues. Drop the lock, wait a while and retry */ - spin_unlock_bh(chip->mutex); - cfi_udelay(1); - goto retry; - - default: - /* Stick ourselves on a wait queue to be woken when - someone changes the status */ - set_current_state(TASK_UNINTERRUPTIBLE); - add_wait_queue(&chip->wq, &wait); - spin_unlock_bh(chip->mutex); - schedule(); - remove_wait_queue(&chip->wq, &wait); - timeo = jiffies + HZ; - goto retry; + spin_lock(chip->mutex); + ret = get_chip(map, chip, adr, FL_LOCKING); + if (ret) { + spin_unlock(chip->mutex); + return ret; } ENABLE_VPP(map); cfi_write(map, CMD(0x60), adr); - cfi_write(map, CMD(0xD0), adr); - chip->state = FL_UNLOCKING; - - spin_unlock_bh(chip->mutex); + + if (thunk == DO_XXLOCK_ONEBLOCK_LOCK) { + cfi_write(map, CMD(0x01), adr); + chip->state = FL_LOCKING; + } else if (thunk == DO_XXLOCK_ONEBLOCK_UNLOCK) { + cfi_write(map, CMD(0xD0), adr); + chip->state = FL_UNLOCKING; + } else + BUG(); + + spin_unlock(chip->mutex); schedule_timeout(HZ); - spin_lock_bh(chip->mutex); + spin_lock(chip->mutex); /* FIXME. Use a timer to check this, and return immediately. */ /* Once the state machine's known to be working I'll do that */ - timeo = jiffies + (HZ*2); + timeo = jiffies + (HZ*20); for (;;) { status = cfi_read(map, adr); @@ -1457,59 +1507,67 @@ if (time_after(jiffies, timeo)) { cfi_write(map, CMD(0x70), adr); chip->state = FL_STATUS; - printk(KERN_ERR "waiting for unlock to complete timed out. Xstatus = %x, status = %x.\n", status, cfi_read(map, adr)); + printk(KERN_ERR "waiting for unlock to complete timed out. Xstatus = %llx, status = %llx.\n", (__u64)status, (__u64)cfi_read(map, adr)); DISABLE_VPP(map); - spin_unlock_bh(chip->mutex); + spin_unlock(chip->mutex); return -EIO; } - /* Latency issues. Drop the unlock, wait a while and retry */ - spin_unlock_bh(chip->mutex); + /* Latency issues. Drop the lock, wait a while and retry */ + spin_unlock(chip->mutex); cfi_udelay(1); - spin_lock_bh(chip->mutex); + spin_lock(chip->mutex); } /* Done and happy. */ chip->state = FL_STATUS; - DISABLE_VPP(map); - wake_up(&chip->wq); - spin_unlock_bh(chip->mutex); + put_chip(map, chip, adr); + spin_unlock(chip->mutex); return 0; } -static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) + +static int cfi_intelext_lock(struct mtd_info *mtd, loff_t ofs, size_t len) { - struct map_info *map = mtd->priv; - struct cfi_private *cfi = map->fldrv_priv; - unsigned long adr; - int chipnum, ret = 0; + int ret; + #ifdef DEBUG_LOCK_BITS - int ofs_factor = cfi->interleave * cfi->device_type; + printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n", + __FUNCTION__, ofs, len); + cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock, + ofs, len, 0); #endif - chipnum = ofs >> cfi->chipshift; - adr = ofs - (chipnum << cfi->chipshift); - + ret = cfi_intelext_varsize_frob(mtd, do_xxlock_oneblock, + ofs, len, DO_XXLOCK_ONEBLOCK_LOCK); + #ifdef DEBUG_LOCK_BITS - { - unsigned long temp_adr = adr; - unsigned long temp_len = len; - - cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL); - while (temp_len) { - printk("before unlock %x: block status register is %x\n",temp_adr,cfi_read_query(map, temp_adr+(2*ofs_factor))); - temp_adr += mtd->erasesize; - temp_len -= mtd->erasesize; - } - cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL); - } + printk(KERN_DEBUG __FUNCTION__ + "%s: lock status after, ret=%d\n", __FUNCTION__, ret); + cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock, + ofs, len, 0); #endif - ret = do_unlock_oneblock(map, &cfi->chips[chipnum], adr); + return ret; +} + +static int cfi_intelext_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) +{ + int ret; #ifdef DEBUG_LOCK_BITS - cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL); - printk("after unlock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor))); - cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL); + printk(KERN_DEBUG "%s: lock status before, ofs=0x%08llx, len=0x%08X\n", + __FUNCTION__, ofs, len); + cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock, + ofs, len, 0); +#endif + + ret = cfi_intelext_varsize_frob(mtd, do_xxlock_oneblock, + ofs, len, DO_XXLOCK_ONEBLOCK_UNLOCK); + +#ifdef DEBUG_LOCK_BITS + printk(KERN_DEBUG "%s: lock status after, ret=%d\n", __FUNCTION__, ret); + cfi_intelext_varsize_frob(mtd, do_printlockstatus_oneblock, + ofs, len, 0); #endif return ret; @@ -1526,27 +1584,28 @@ for (i=0; !ret && i<cfi->numchips; i++) { chip = &cfi->chips[i]; - spin_lock_bh(chip->mutex); + spin_lock(chip->mutex); - switch(chip->state) { + 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: + if (chip->oldstate == FL_READY) { + 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. + */ + } break; - default: ret = -EAGAIN; + case FL_PM_SUSPENDED: break; } - spin_unlock_bh(chip->mutex); + spin_unlock(chip->mutex); } /* Unlock the chips again */ @@ -1555,7 +1614,7 @@ for (i--; i >=0; i--) { chip = &cfi->chips[i]; - spin_lock_bh(chip->mutex); + spin_lock(chip->mutex); if (chip->state == FL_PM_SUSPENDED) { /* No need to force it into a known state here, @@ -1564,7 +1623,7 @@ chip->state = chip->oldstate; wake_up(&chip->wq); } - spin_unlock_bh(chip->mutex); + spin_unlock(chip->mutex); } } @@ -1582,7 +1641,7 @@ chip = &cfi->chips[i]; - spin_lock_bh(chip->mutex); + spin_lock(chip->mutex); /* Go to known state. Chip may have been power cycled */ if (chip->state == FL_PM_SUSPENDED) { @@ -1591,7 +1650,7 @@ wake_up(&chip->wq); } - spin_unlock_bh(chip->mutex); + spin_unlock(chip->mutex); } } @@ -1600,7 +1659,9 @@ struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; kfree(cfi->cmdset_priv); + kfree(cfi->cfiq); kfree(cfi); + kfree(mtd->eraseregions); } static char im_name_1[]="cfi_cmdset_0001"; diff -Nru a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c --- a/drivers/mtd/chips/cfi_cmdset_0002.c Mon Jun 9 23:16:10 2003 +++ b/drivers/mtd/chips/cfi_cmdset_0002.c Mon Jun 9 23:16:10 2003 @@ -8,7 +8,7 @@ * * This code is GPL * - * $Id: cfi_cmdset_0002.c,v 1.52 2001/10/24 09:37:30 dwmw2 Exp $ + * $Id: cfi_cmdset_0002.c,v 1.74 2003/05/28 12:51:48 dwmw2 Exp $ * */ @@ -16,6 +16,7 @@ #include <linux/types.h> #include <linux/kernel.h> #include <linux/sched.h> +#include <linux/init.h> #include <asm/io.h> #include <asm/byteorder.h> @@ -24,17 +25,21 @@ #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/mtd/map.h> +#include <linux/mtd/mtd.h> #include <linux/mtd/cfi.h> +#include <linux/mtd/compatmac.h> #define AMD_BOOTLOC_BUG static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); static int cfi_amdstd_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); +static int cfi_amdstd_erase_chip(struct mtd_info *, struct erase_info *); static int cfi_amdstd_erase_onesize(struct mtd_info *, struct erase_info *); static int cfi_amdstd_erase_varsize(struct mtd_info *, struct erase_info *); static void cfi_amdstd_sync (struct mtd_info *); static int cfi_amdstd_suspend (struct mtd_info *); static void cfi_amdstd_resume (struct mtd_info *); +static int cfi_amdstd_secsi_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); static void cfi_amdstd_destroy(struct mtd_info *); @@ -49,6 +54,7 @@ .module = THIS_MODULE }; + struct mtd_info *cfi_cmdset_0002(struct map_info *map, int primary) { struct cfi_private *cfi = map->fldrv_priv; @@ -58,7 +64,7 @@ __u8 major, minor; __u32 base = cfi->chips[0].start; - if (cfi->cfi_mode==1){ + if (cfi->cfi_mode==CFI_MODE_CFI){ __u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR; cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); @@ -73,8 +79,9 @@ cfi_send_gen_cmd(0xaa, 0x555, base, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x55, 0x2aa, base, map, cfi, cfi->device_type, NULL); cfi_send_gen_cmd(0x90, 0x555, base, map, cfi, cfi->device_type, NULL); + /* FIXME - should have a delay before continuing */ cfi->mfr = cfi_read_query(map, base); - cfi->id = cfi_read_query(map, base + ofs_factor); + cfi->id = cfi_read_query(map, base + ofs_factor); /* Wheee. Bring me the head of someone at AMD. */ #ifdef AMD_BOOTLOC_BUG @@ -104,6 +111,10 @@ cfi->cfiq->EraseRegionInfo[j] = swap; } } + /* + * FIXME - These might already be setup (more correctly) + * buy jedec_probe.c. + */ switch (cfi->device_type) { case CFI_DEVICETYPE_X8: cfi->addr_unlock1 = 0x555; @@ -135,7 +146,6 @@ } map->fldrv = &cfi_amdstd_chipdrv; - MOD_INC_USE_COUNT; cfi_send_gen_cmd(0xf0, 0x55, base, map, cfi, cfi->device_type, NULL); return cfi_amdstd_setup(map); @@ -148,12 +158,12 @@ unsigned long devsize = (1<<cfi->cfiq->DevSize) * cfi->interleave; mtd = kmalloc(sizeof(*mtd), GFP_KERNEL); - printk(KERN_NOTICE "number of %s chips: %d\n", (cfi->cfi_mode)?"CFI":"JEDEC",cfi->numchips); + printk(KERN_NOTICE "number of %s chips: %d\n", + (cfi->cfi_mode == CFI_MODE_CFI)?"CFI":"JEDEC",cfi->numchips); if (!mtd) { printk(KERN_WARNING "Failed to allocate memory for MTD device\n"); - kfree(cfi->cmdset_priv); - return NULL; + goto setup_err; } memset(mtd, 0, sizeof(*mtd)); @@ -173,9 +183,7 @@ mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) * mtd->numeraseregions, GFP_KERNEL); if (!mtd->eraseregions) { printk(KERN_WARNING "Failed to allocate memory for MTD erase region info\n"); - kfree(cfi->cmdset_priv); - kfree(mtd); - return NULL; + goto setup_err; } for (i=0; i<cfi->cfiq->NumEraseRegions; i++) { @@ -196,10 +204,7 @@ if (offset != devsize) { /* Argh */ printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize); - kfree(mtd->eraseregions); - kfree(cfi->cmdset_priv); - kfree(mtd); - return NULL; + goto setup_err; } #if 0 // debug @@ -222,6 +227,9 @@ mtd->erase = cfi_amdstd_erase_varsize; else #endif + if (((cfi->cfiq->EraseRegionInfo[0] & 0xffff) + 1) == 1) + mtd->erase = cfi_amdstd_erase_chip; + else mtd->erase = cfi_amdstd_erase_onesize; mtd->read = cfi_amdstd_read; mtd->write = cfi_amdstd_write; @@ -229,19 +237,56 @@ default: printk(KERN_WARNING "Unsupported buswidth\n"); - kfree(mtd); - kfree(cfi->cmdset_priv); - return NULL; + goto setup_err; break; } + if (cfi->fast_prog) { + /* In cfi_amdstd_write() we frob the protection stuff + without paying any attention to the state machine. + This upsets in-progress erases. So we turn this flag + off for now till the code gets fixed. */ + printk(KERN_NOTICE "cfi_cmdset_0002: Disabling fast programming due to code brokenness.\n"); + cfi->fast_prog = 0; + } + + + /* does this chip have a secsi area? */ + if(cfi->mfr==1){ + + switch(cfi->id){ + case 0x50: + case 0x53: + case 0x55: + case 0x56: + case 0x5C: + case 0x5F: + /* Yes */ + mtd->read_user_prot_reg = cfi_amdstd_secsi_read; + mtd->read_fact_prot_reg = cfi_amdstd_secsi_read; + default: + ; + } + } + + mtd->sync = cfi_amdstd_sync; mtd->suspend = cfi_amdstd_suspend; mtd->resume = cfi_amdstd_resume; mtd->flags = MTD_CAP_NORFLASH; map->fldrv = &cfi_amdstd_chipdrv; mtd->name = map->name; - MOD_INC_USE_COUNT; + __module_get(THIS_MODULE); return mtd; + + setup_err: + if(mtd) { + if(mtd->eraseregions) + kfree(mtd->eraseregions); + kfree(mtd); + } + kfree(cfi->cmdset_priv); + kfree(cfi->cfiq); + return NULL; } static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf) @@ -276,7 +321,7 @@ chip->state = FL_READY; - map->copy_from(map, buf, adr, len); + map_copy_from(map, buf, adr, len); wake_up(&chip->wq); cfi_spin_unlock(chip->mutex); @@ -325,19 +370,122 @@ return ret; } -static int do_write_oneword(struct map_info *map, struct flchip *chip, unsigned long adr, __u32 datum, int fast) +static inline int do_read_secsi_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; - unsigned int Last[4]; - unsigned long Count = 0; struct cfi_private *cfi = map->fldrv_priv; + + retry: + cfi_spin_lock(chip->mutex); + + if (chip->state != FL_READY){ +#if 0 + printk(KERN_DEBUG "Waiting for chip to read, status = %d\n", chip->state); +#endif + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&chip->wq, &wait); + + cfi_spin_unlock(chip->mutex); + + schedule(); + remove_wait_queue(&chip->wq, &wait); +#if 0 + if(signal_pending(current)) + return -EINTR; +#endif + timeo = jiffies + HZ; + + goto retry; + } + + adr += chip->start; + + chip->state = FL_READY; + + cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0x88, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); + + map_copy_from(map, buf, adr, len); + + cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0x90, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0x00, cfi->addr_unlock1, chip->start, map, cfi, cfi->device_type, NULL); + + wake_up(&chip->wq); + cfi_spin_unlock(chip->mutex); + + return 0; +} + +static int cfi_amdstd_secsi_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 */ + + /* 8 secsi bytes per chip */ + chipnum=from>>3; + ofs=from & 7; + + + *retlen = 0; + + while (len) { + unsigned long thislen; + + if (chipnum >= cfi->numchips) + break; + + if ((len + ofs -1) >> 3) + thislen = (1<<3) - ofs; + else + thislen = len; + + ret = do_read_secsi_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, cfi_word datum, int fast) +{ + unsigned long timeo = jiffies + HZ; + unsigned int oldstatus, status, prev_oldstatus, prev_status; + unsigned int dq6; + struct cfi_private *cfi = map->fldrv_priv; + /* We use a 1ms + 1 jiffies generic timeout for writes (most devices have + a max write time of a few hundreds usec). However, we should use the + maximum timeout value given by the chip at probe time instead. + Unfortunately, struct flchip does have a field for maximum timeout, + only for typical which can be far too short depending of the conditions. + The ' + 1' is to avoid having a timeout of 0 jiffies if HZ is smaller + than 1000. Using a static variable allows makes us save the costly + divide operation at each word write.*/ + static unsigned long uWriteTimeout = ( HZ / 1000 ) + 1; DECLARE_WAITQUEUE(wait, current); int ret = 0; + int ta = 0; retry: cfi_spin_lock(chip->mutex); - if (chip->state != FL_READY){ + if (chip->state != FL_READY) { #if 0 printk(KERN_DEBUG "Waiting for chip to write, status = %d\n", chip->state); #endif @@ -361,6 +509,9 @@ chip->state = FL_WRITING; adr += chip->start; + DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): WRITE 0x%.8lx(0x%.8x)\n", + __func__, adr, datum ); + ENABLE_VPP(map); if (fast) { /* Unlock bypass */ cfi_send_gen_cmd(0xA0, 0, chip->start, map, cfi, cfi->device_type, NULL); @@ -370,40 +521,147 @@ cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); cfi_send_gen_cmd(0xA0, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, 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); + /* + * Polling toggle bits instead of reading back many times + * This ensures that write operation is really completed, + * or tells us why it failed. + * + * It appears tha the polling and decoding of error state might + * be simplified. Don't do it unless you really know what you + * are doing. You must remember that JESD21-C 3.5.3 states that + * the status must be read back an _additional_ two times before + * a failure is determined. This is because these devices have + * internal state machines that are asynchronous to the external + * data bus. During an erase or write the read-back status of the + * polling bits might be transitioning internaly when the external + * read-back occurs. This means that the bits aren't in the final + * state and they might appear to report an error as they transition + * and are in a weird state. This will produce infrequent errors + * that will usually disappear the next time an erase or write + * happens (Try tracking those errors down!). To ensure that + * the bits are not in transition the location must be read-back + * two more times and compared against what was written - BOTH reads + * MUST match what was written - don't think this can be simplified + * to only the last read matching. If the comparison fails, error + * state can then be decoded. + * + * - Thayne Harbaugh + */ + dq6 = CMD(1<<6); + /* See comment above for timeout value. */ + timeo = jiffies + uWriteTimeout; - Last[Count % 4] = cfi_read(map, adr); - // printk("Last[%d%%4] is %x\n", Count, Last[Count%4]); + oldstatus = cfi_read(map, adr); + status = cfi_read(map, adr); + DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n", + __func__, oldstatus, status ); + + /* + * This only checks if dq6 is still toggling and that our + * timer hasn't expired. We purposefully ignore the chips + * internal timer that will assert dq5 and leave dq6 toggling. + * This is done for a variety of reasons: + * 1) Not all chips support dq5. + * 2) Dealing with asynchronous status bit and data updates + * and reading a device two more times creates _messy_ + * logic when trying to deal with interleaved devices - + * some may be changing while others are still busy. + * 3) Checking dq5 only helps to optimize an error case that + * should at worst be infrequent and at best non-existent. + * + * If our timeout occurs _then_ we will check dq5 to see + * if the device also had an internal timeout. + */ + while( ( ( status ^ oldstatus ) & dq6 ) + && ! ( ta = time_after(jiffies, timeo) ) ) { + + if (need_resched()) { + cfi_spin_unlock(chip->mutex); + yield(); + cfi_spin_lock(chip->mutex); + } else + udelay(1); + + oldstatus = cfi_read( map, adr ); + status = cfi_read( map, adr ); + DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n", + __func__, oldstatus, status ); } - - if (Last[(Count - 1) % 4] != datum){ - printk(KERN_WARNING "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; - } + + /* + * Something kicked us out of the read-back loop. We'll + * check success befor checking failure. + * Even though dq6 might be true data, it is unkown if + * all of the other bits have changed to true data due to + * the asynchronous nature of the internal state machine. + * We will read two more times and use this to either + * verify that the write completed successfully or + * that something really went wrong. BOTH reads + * must match what was written - this certifies that + * bits aren't still changing and that the status + * bits erroneously match the datum that was written. + */ + prev_oldstatus = oldstatus; + prev_status = status; + oldstatus = cfi_read(map, adr); + status = cfi_read(map, adr); + DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n", + __func__, oldstatus, status ); + + if ( oldstatus == datum && status == datum ) { + /* success - do nothing */ + goto write_done; + } + + if ( ta ) { + int dq5mask = ( ( status ^ oldstatus ) & dq6 ) >> 1; + if ( status & dq5mask ) { + /* dq5 asserted - decode interleave chips */ + printk( KERN_WARNING + "MTD %s(): FLASH internal timeout: 0x%.8x\n", + __func__, + status & dq5mask ); + } else { + printk( KERN_WARNING + "MTD %s(): Software timed out during write.\n", + __func__ ); + } + goto write_failed; + } + + /* + * If we get to here then it means that something + * is wrong and it's not a timeout. Something + * is seriously wacky! Dump some debug info. + */ + printk(KERN_WARNING + "MTD %s(): Wacky! Unable to decode failure status\n", + __func__ ); + + printk(KERN_WARNING + "MTD %s(): 0x%.8lx(0x%.8x): 0x%.8x 0x%.8x 0x%.8x 0x%.8x\n", + __func__, adr, datum, + prev_oldstatus, prev_status, + oldstatus, status); + + write_failed: + ret = -EIO; + /* reset on all failures. */ + cfi_write( map, CMD(0xF0), chip->start ); + /* FIXME - should have reset delay before continuing */ + + write_done: DISABLE_VPP(map); chip->state = FL_READY; wake_up(&chip->wq); cfi_spin_unlock(chip->mutex); - + return ret; } @@ -428,10 +686,10 @@ unsigned long bus_ofs = ofs & ~(CFIDEV_BUSWIDTH-1); int i = ofs - bus_ofs; int n = 0; - u_char tmp_buf[4]; - __u32 datum; + u_char tmp_buf[8]; + cfi_word datum; - map->copy_from(map, tmp_buf, bus_ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH); + 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--; @@ -444,7 +702,7 @@ } ret = do_write_oneword(map, &cfi->chips[chipnum], - bus_ofs, datum, 0); + bus_ofs, datum, 0); if (ret) return ret; @@ -460,14 +718,16 @@ } } - /* Go into unlock bypass mode */ - cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0x20, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL); + if (cfi->fast_prog) { + /* Go into unlock bypass mode */ + cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0x20, cfi->addr_unlock1, chipstart, map, cfi, CFI_DEVICETYPE_X8, NULL); + } /* We are now aligned, write as much as possible */ while(len >= CFIDEV_BUSWIDTH) { - __u32 datum; + cfi_word datum; if (cfi_buswidth_is_1()) { datum = *(__u8*)buf; @@ -521,12 +781,13 @@ cfi_send_gen_cmd(0x00, 0, chipstart, map, cfi, cfi->device_type, NULL); } + /* Write the trailing bytes if any */ if (len & (CFIDEV_BUSWIDTH-1)) { int i = 0, n = 0; - u_char tmp_buf[4]; - __u32 datum; + u_char tmp_buf[8]; + cfi_word datum; - map->copy_from(map, tmp_buf, ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH); + map_copy_from(map, tmp_buf, ofs + cfi->chips[chipnum].start, CFIDEV_BUSWIDTH); while (len--) tmp_buf[i++] = buf[n++]; @@ -549,13 +810,197 @@ return 0; } +static inline int do_erase_chip(struct map_info *map, struct flchip *chip) +{ + unsigned int oldstatus, status, prev_oldstatus, prev_status; + unsigned int dq6; + unsigned long timeo = jiffies + HZ; + unsigned long int adr; + struct cfi_private *cfi = map->fldrv_priv; + DECLARE_WAITQUEUE(wait, current); + int ret = 0; + int ta = 0; + cfi_word ones = 0; + + 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); +#if 0 + if(signal_pending(current)) + return -EINTR; +#endif + timeo = jiffies + HZ; + + goto retry; + } + + chip->state = FL_ERASING; + DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n", + __func__, chip->start ); + + /* Handle devices with one erase region, that only implement + * the chip erase command. + */ + ENABLE_VPP(map); + cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0x10, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); + timeo = jiffies + (HZ*20); + adr = cfi->addr_unlock1; + + /* Wait for the end of programing/erasure by using the toggle method. + * As long as there is a programming procedure going on, bit 6 + * is toggling it's state with each consecutive read. + * The toggling stops as soon as the procedure is completed. + * + * If the process has gone on for too long on the chip bit 5 gets. + * After bit5 is set you can kill the operation by sending a reset + * command to the chip. + */ + /* see comments in do_write_oneword */ + dq6 = CMD(1<<6); + + oldstatus = cfi_read(map, adr); + status = cfi_read(map, adr); + DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n", + __func__, oldstatus, status ); + + while( ( ( status ^ oldstatus ) & dq6 ) + && ! ( ta = time_after(jiffies, timeo) ) ) { + int wait_reps; + + /* an initial short sleep */ + cfi_spin_unlock(chip->mutex); + schedule_timeout(HZ/100); + cfi_spin_lock(chip->mutex); + + 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); +#if 0 + if (signal_pending(current)) + return -EINTR; +#endif + timeo = jiffies + (HZ*2); /* FIXME */ + cfi_spin_lock(chip->mutex); + continue; + } + + /* Busy wait for 1/10 of a milisecond */ + for(wait_reps = 0; + (wait_reps < 100) + && ( ( status ^ oldstatus ) & dq6 ); + wait_reps++) { + + /* Latency issues. Drop the lock, wait a while and retry */ + cfi_spin_unlock(chip->mutex); + + cfi_udelay(1); + + cfi_spin_lock(chip->mutex); + oldstatus = cfi_read(map, adr); + status = cfi_read(map, adr); + DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n", + __func__, oldstatus, status ); + } + oldstatus = cfi_read(map, adr); + status = cfi_read(map, adr); + DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n", + __func__, oldstatus, status ); + } + + prev_oldstatus = oldstatus; + prev_status = status; + oldstatus = cfi_read(map, adr); + status = cfi_read(map, adr); + DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n", + __func__, oldstatus, status ); + + if ( cfi_buswidth_is_1() ) { + ones = (__u8)~0; + } else if ( cfi_buswidth_is_2() ) { + ones = (__u16)~0; + } else if ( cfi_buswidth_is_4() ) { + ones = (__u32)~0; + } else { + printk(KERN_WARNING "Unsupported buswidth\n"); + goto erase_failed; + } + + if ( oldstatus == ones && status == ones ) { + /* success - do nothing */ + goto erase_done; + } + + if ( ta ) { + int dq5mask = ( ( status ^ oldstatus ) & dq6 ) >> 1; + if ( status & dq5mask ) { + /* dq5 asserted - decode interleave chips */ + printk( KERN_WARNING + "MTD %s(): FLASH internal timeout: 0x%.8x\n", + __func__, + status & dq5mask ); + } else { + printk( KERN_WARNING + "MTD %s(): Software timed out during write.\n", + __func__ ); + } + goto erase_failed; + } + + printk(KERN_WARNING + "MTD %s(): Wacky! Unable to decode failure status\n", + __func__ ); + + printk(KERN_WARNING + "MTD %s(): 0x%.8lx(0x%.8x): 0x%.8x 0x%.8x 0x%.8x 0x%.8x\n", + __func__, adr, ones, + prev_oldstatus, prev_status, + oldstatus, status); + + erase_failed: + ret = -EIO; + /* reset on all failures. */ + cfi_write( map, CMD(0xF0), chip->start ); + /* FIXME - should have reset delay before continuing */ + + erase_done: + DISABLE_VPP(map); + chip->state = FL_READY; + wake_up(&chip->wq); + cfi_spin_unlock(chip->mutex); + return ret; +} + + static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr) { - unsigned int status; + unsigned int oldstatus, status, prev_oldstatus, prev_status; + unsigned int dq6; unsigned long timeo = jiffies + HZ; struct cfi_private *cfi = map->fldrv_priv; - unsigned int rdy_mask; DECLARE_WAITQUEUE(wait, current); + int ret = 0; + int ta = 0; + cfi_word ones = 0; retry: cfi_spin_lock(chip->mutex); @@ -580,28 +1025,46 @@ chip->state = FL_ERASING; adr += chip->start; + DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): ERASE 0x%.8lx\n", + __func__, adr ); + ENABLE_VPP(map); cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); cfi_send_gen_cmd(0x80, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); cfi_send_gen_cmd(0xAA, cfi->addr_unlock1, chip->start, map, cfi, CFI_DEVICETYPE_X8, NULL); cfi_send_gen_cmd(0x55, cfi->addr_unlock2, chip->start, map, cfi, CFI_DEVICETYPE_X8, 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); - - /* FIXME. Use a timer to check this, and return immediately. */ - /* Once the state machine's known to be working I'll do that */ + /* Wait for the end of programing/erasure by using the toggle method. + * As long as there is a programming procedure going on, bit 6 + * is toggling it's state with each consecutive read. + * The toggling stops as soon as the procedure is completed. + * + * If the process has gone on for too long on the chip bit 5 gets. + * After bit5 is set you can kill the operation by sending a reset + * command to the chip. + */ + /* see comments in do_write_oneword */ + dq6 = CMD(1<<6); - while ( ( (status = cfi_read(map,adr)) & rdy_mask ) != rdy_mask ) { - static int z=0; + oldstatus = cfi_read(map, adr); + status = cfi_read(map, adr); + DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n", + __func__, oldstatus, status ); + + while( ( ( status ^ oldstatus ) & dq6 ) + && ! ( ta = time_after(jiffies, timeo) ) ) { + int wait_reps; + /* an initial short sleep */ + cfi_spin_unlock(chip->mutex); + schedule_timeout(HZ/100); + cfi_spin_lock(chip->mutex); + if (chip->state != FL_ERASING) { /* Someone's suspended the erase. Sleep */ set_current_state(TASK_UNINTERRUPTIBLE); @@ -621,34 +1084,90 @@ continue; } - /* OK Still waiting */ - if (time_after(jiffies, timeo)) { - chip->state = FL_READY; + /* Busy wait for 1/10 of a milisecond */ + for(wait_reps = 0; + (wait_reps < 100) + && ( ( status ^ oldstatus ) & dq6 ); + wait_reps++) { + + /* Latency issues. Drop the lock, wait a while and retry */ cfi_spin_unlock(chip->mutex); - printk(KERN_WARNING "waiting for erase to complete timed out."); - DISABLE_VPP(map); - return -EIO; - } + + cfi_udelay(1); - /* Latency issues. Drop the lock, wait a while and retry */ - cfi_spin_unlock(chip->mutex); + cfi_spin_lock(chip->mutex); + oldstatus = cfi_read(map, adr); + status = cfi_read(map, adr); + DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n", + __func__, oldstatus, status ); + } + oldstatus = cfi_read(map, adr); + status = cfi_read(map, adr); + DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n", + __func__, oldstatus, status ); + } - z++; - if ( 0 && !(z % 100 )) - printk(KERN_WARNING "chip not ready yet after erase. looping\n"); + prev_oldstatus = oldstatus; + prev_status = status; + oldstatus = cfi_read(map, adr); + status = cfi_read(map, adr); + DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): Check 0x%.8x 0x%.8x\n", + __func__, oldstatus, status ); + + if ( cfi_buswidth_is_1() ) { + ones = (__u8)~0; + } else if ( cfi_buswidth_is_2() ) { + ones = (__u16)~0; + } else if ( cfi_buswidth_is_4() ) { + ones = (__u32)~0; + } else { + printk(KERN_WARNING "Unsupported buswidth\n"); + goto erase_failed; + } - cfi_udelay(1); - - cfi_spin_lock(chip->mutex); - continue; + if ( oldstatus == ones && status == ones ) { + /* success - do nothing */ + goto erase_done; } - - /* Done and happy. */ + + if ( ta ) { + int dq5mask = ( ( status ^ oldstatus ) & dq6 ) >> 1; + if ( status & dq5mask ) { + /* dq5 asserted - decode interleave chips */ + printk( KERN_WARNING + "MTD %s(): FLASH internal timeout: 0x%.8x\n", + __func__, + status & dq5mask ); + } else { + printk( KERN_WARNING + "MTD %s(): Software timed out during write.\n", + __func__ ); + } + goto erase_failed; + } + + printk(KERN_WARNING + "MTD %s(): Wacky! Unable to decode failure status\n", + __func__ ); + + printk(KERN_WARNING + "MTD %s(): 0x%.8lx(0x%.8x): 0x%.8x 0x%.8x 0x%.8x 0x%.8x\n", + __func__, adr, ones, + prev_oldstatus, prev_status, + oldstatus, status); + + erase_failed: + ret = -EIO; + /* reset on all failures. */ + cfi_write( map, CMD(0xF0), chip->start ); + /* FIXME - should have reset delay before continuing */ + + erase_done: DISABLE_VPP(map); chip->state = FL_READY; wake_up(&chip->wq); cfi_spin_unlock(chip->mutex); - return 0; + return ret; } static int cfi_amdstd_erase_varsize(struct mtd_info *mtd, struct erase_info *instr) @@ -788,6 +1307,29 @@ return 0; } +static int cfi_amdstd_erase_chip(struct mtd_info *mtd, struct erase_info *instr) +{ + struct map_info *map = mtd->priv; + struct cfi_private *cfi = map->fldrv_priv; + int ret = 0; + + if (instr->addr != 0) + return -EINVAL; + + if (instr->len != mtd->size) + return -EINVAL; + + ret = do_erase_chip(map, &cfi->chips[0]); + if (ret) + return ret; + + instr->state = MTD_ERASE_DONE; + if (instr->callback) + instr->callback(instr); + + return 0; +} + static void cfi_amdstd_sync (struct mtd_info *mtd) { struct map_info *map = mtd->priv; @@ -855,7 +1397,6 @@ int i; struct flchip *chip; int ret = 0; -//printk("suspend\n"); for (i=0; !ret && i<cfi->numchips; i++) { chip = &cfi->chips[i]; @@ -908,7 +1449,6 @@ struct cfi_private *cfi = map->fldrv_priv; int i; struct flchip *chip; -//printk("resume\n"); for (i=0; i<cfi->numchips; i++) { @@ -933,7 +1473,9 @@ struct map_info *map = mtd->priv; struct cfi_private *cfi = map->fldrv_priv; kfree(cfi->cmdset_priv); + kfree(cfi->cfiq); kfree(cfi); + kfree(mtd->eraseregions); } static char im_name[]="cfi_cmdset_0002"; @@ -955,3 +1497,4 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Crossnet Co. <info@crossnet.co.jp> et al."); MODULE_DESCRIPTION("MTD chip driver for AMD/Fujitsu flash chips"); + diff -Nru a/drivers/mtd/chips/cfi_cmdset_0020.c b/drivers/mtd/chips/cfi_cmdset_0020.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/chips/cfi_cmdset_0020.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,1451 @@ +/* + * Common Flash Interface support: + * ST Advanced Architecture Command Set (ID 0x0020) + * + * (C) 2000 Red Hat. GPL'd + * + * + * 10/10/2000 Nicolas Pitre <nico@cam.org> + * - completely revamped method functions so they are aware and + * independent of the flash geometry (buswidth, interleave, etc.) + * - scalability vs code size is completely set at compile-time + * (see include/linux/mtd/cfi.h for selection) + * - optimized write buffer method + * 06/21/2002 Joern Engel <joern@wh.fh-wedel.de> and others + * - modified Intel Command Set 0x0001 to support ST Advanced Architecture + * (command set 0x0020) + * - added a writev function + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/init.h> +#include <asm/io.h> +#include <asm/byteorder.h> + +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/mtd/map.h> +#include <linux/mtd/cfi.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/compatmac.h> + + +static int cfi_staa_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *); +static int cfi_staa_write_buffers(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); +static int cfi_staa_writev(struct mtd_info *mtd, const struct iovec *vecs, + unsigned long count, loff_t to, size_t *retlen); +static int cfi_staa_erase_varsize(struct mtd_info *, struct erase_info *); +static void cfi_staa_sync (struct mtd_info *); +static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, size_t len); +static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, size_t len); +static int cfi_staa_suspend (struct mtd_info *); +static void cfi_staa_resume (struct mtd_info *); + +static void cfi_staa_destroy(struct mtd_info *); + +struct mtd_info *cfi_cmdset_0020(struct map_info *, int); + +static struct mtd_info *cfi_staa_setup (struct map_info *); + +static struct mtd_chip_driver cfi_staa_chipdrv = { + .probe = NULL, /* Not usable directly */ + .destroy = cfi_staa_destroy, + .name = "cfi_cmdset_0020", + .module = THIS_MODULE +}; + +/* #define DEBUG_LOCK_BITS */ +//#define DEBUG_CFI_FEATURES + +#ifdef DEBUG_CFI_FEATURES +static void cfi_tell_features(struct cfi_pri_intelext *extp) +{ + int i; + printk(" Feature/Command Support: %4.4X\n", extp->FeatureSupport); + printk(" - Chip Erase: %s\n", extp->FeatureSupport&1?"supported":"unsupported"); + printk(" - Suspend Erase: %s\n", extp->FeatureSupport&2?"supported":"unsupported"); + printk(" - Suspend Program: %s\n", extp->FeatureSupport&4?"supported":"unsupported"); + printk(" - Legacy Lock/Unlock: %s\n", extp->FeatureSupport&8?"supported":"unsupported"); + printk(" - Queued Erase: %s\n", extp->FeatureSupport&16?"supported":"unsupported"); + printk(" - Instant block lock: %s\n", extp->FeatureSupport&32?"supported":"unsupported"); + printk(" - Protection Bits: %s\n", extp->FeatureSupport&64?"supported":"unsupported"); + printk(" - Page-mode read: %s\n", extp->FeatureSupport&128?"supported":"unsupported"); + printk(" - Synchronous read: %s\n", extp->FeatureSupport&256?"supported":"unsupported"); + for (i=9; i<32; i++) { + if (extp->FeatureSupport & (1<<i)) + printk(" - Unknown Bit %X: supported\n", i); + } + + printk(" Supported functions after Suspend: %2.2X\n", extp->SuspendCmdSupport); + printk(" - Program after Erase Suspend: %s\n", extp->SuspendCmdSupport&1?"supported":"unsupported"); + for (i=1; i<8; i++) { + if (extp->SuspendCmdSupport & (1<<i)) + printk(" - Unknown Bit %X: supported\n", i); + } + + printk(" Block Status Register Mask: %4.4X\n", extp->BlkStatusRegMask); + printk(" - Lock Bit Active: %s\n", extp->BlkStatusRegMask&1?"yes":"no"); + printk(" - Valid Bit Active: %s\n", extp->BlkStatusRegMask&2?"yes":"no"); + for (i=2; i<16; i++) { + if (extp->BlkStatusRegMask & (1<<i)) + printk(" - Unknown Bit %X Active: yes\n",i); + } + + printk(" Vcc Logic Supply Optimum Program/Erase Voltage: %d.%d V\n", + extp->VccOptimal >> 8, extp->VccOptimal & 0xf); + if (extp->VppOptimal) + printk(" Vpp Programming Supply Optimum Program/Erase Voltage: %d.%d V\n", + extp->VppOptimal >> 8, extp->VppOptimal & 0xf); +} +#endif + +/* This routine is made available to other mtd code via + * inter_module_register. It must only be accessed through + * inter_module_get which will bump the use count of this module. The + * addresses passed back in cfi are valid as long as the use count of + * this module is non-zero, i.e. between inter_module_get and + * inter_module_put. Keith Owens <kaos@ocs.com.au> 29 Oct 2000. + */ +struct mtd_info *cfi_cmdset_0020(struct map_info *map, int primary) +{ + struct cfi_private *cfi = map->fldrv_priv; + int i; + __u32 base = cfi->chips[0].start; + + if (cfi->cfi_mode) { + /* + * It's a real CFI chip, not one for which the probe + * routine faked a CFI structure. So we read the feature + * table from it. + */ + __u16 adr = primary?cfi->cfiq->P_ADR:cfi->cfiq->A_ADR; + struct cfi_pri_intelext *extp; + int ofs_factor = cfi->interleave * cfi->device_type; + + printk(" ST Microelectronics Extended Query Table at 0x%4.4X\n", adr); + if (!adr) + return NULL; + + /* Switch it into Query Mode */ + cfi_send_gen_cmd(0x98, 0x55, base, map, cfi, cfi->device_type, NULL); + + extp = kmalloc(sizeof(*extp), GFP_KERNEL); + if (!extp) { + printk(KERN_ERR "Failed to allocate memory\n"); + return NULL; + } + + /* Read in the Extended Query Table */ + for (i=0; i<sizeof(*extp); i++) { + ((unsigned char *)extp)[i] = + cfi_read_query(map, (base+((adr+i)*ofs_factor))); + } + + if (extp->MajorVersion != '1' || + (extp->MinorVersion < '0' || extp->MinorVersion > '2')) { + printk(KERN_WARNING " Unknown staa Extended Query " + "version %c.%c.\n", extp->MajorVersion, + extp->MinorVersion); + kfree(extp); + return NULL; + } + + /* Do some byteswapping if necessary */ + extp->FeatureSupport = cfi32_to_cpu(extp->FeatureSupport); + extp->BlkStatusRegMask = cfi32_to_cpu(extp->BlkStatusRegMask); + +#ifdef DEBUG_CFI_FEATURES + /* Tell the user about it in lots of lovely detail */ + cfi_tell_features(extp); +#endif + + /* Install our own private info structure */ + cfi->cmdset_priv = extp; + } + + for (i=0; i< cfi->numchips; i++) { + cfi->chips[i].word_write_time = 128; + cfi->chips[i].buffer_write_time = 128; + cfi->chips[i].erase_time = 1024; + } + + /* Make sure it's in read mode */ + cfi_send_gen_cmd(0xff, 0x55, base, map, cfi, cfi->device_type, NULL); + return cfi_staa_setup(map); +} + +static struct mtd_info *cfi_staa_setup(struct map_info *map) +{ + struct cfi_private *cfi = map->fldrv_priv; + struct mtd_info *mtd; + unsigned long offset = 0; + int i,j; + unsigned long devsize = (1<<cfi->cfiq->DevSize) * cfi->interleave; + + mtd = kmalloc(sizeof(*mtd), GFP_KERNEL); + //printk(KERN_DEBUG "number of CFI chips: %d\n", cfi->numchips); + + if (!mtd) { + printk(KERN_ERR "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; + mtd->size = devsize * cfi->numchips; + + mtd->numeraseregions = cfi->cfiq->NumEraseRegions * cfi->numchips; + mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) + * mtd->numeraseregions, GFP_KERNEL); + if (!mtd->eraseregions) { + printk(KERN_ERR "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); + } + + if (offset != devsize) { + /* Argh */ + printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize); + kfree(mtd->eraseregions); + kfree(cfi->cmdset_priv); + return NULL; + } + + for (i=0; i<mtd->numeraseregions;i++){ + printk(KERN_DEBUG "%d: offset=0x%x,size=0x%x,blocks=%d\n", + i,mtd->eraseregions[i].offset, + mtd->eraseregions[i].erasesize, + mtd->eraseregions[i].numblocks); + } + + /* Also select the correct geometry setup too */ + mtd->erase = cfi_staa_erase_varsize; + mtd->read = cfi_staa_read; + mtd->write = cfi_staa_write_buffers; + mtd->writev = cfi_staa_writev; + mtd->sync = cfi_staa_sync; + mtd->lock = cfi_staa_lock; + mtd->unlock = cfi_staa_unlock; + mtd->suspend = cfi_staa_suspend; + mtd->resume = cfi_staa_resume; + mtd->flags = MTD_CAP_NORFLASH; + mtd->flags |= MTD_ECC; /* FIXME: Not all STMicro flashes have this */ + mtd->eccsize = 8; /* FIXME: Should be 0 for STMicro flashes w/out ECC */ + map->fldrv = &cfi_staa_chipdrv; + __module_get(THIS_MODULE); + mtd->name = map->name; + return mtd; +} + + +static inline int do_read_onechip(struct map_info *map, struct flchip *chip, loff_t adr, size_t len, u_char *buf) +{ + __u32 status, status_OK; + unsigned long timeo; + DECLARE_WAITQUEUE(wait, current); + int suspended = 0; + unsigned long cmd_addr; + struct cfi_private *cfi = map->fldrv_priv; + + adr += chip->start; + + /* Ensure cmd read/writes are aligned. */ + cmd_addr = adr & ~(CFIDEV_BUSWIDTH-1); + + /* Let's determine this according to the interleave only once */ + status_OK = CMD(0x80); + + timeo = jiffies + HZ; + retry: + spin_lock_bh(chip->mutex); + + /* Check that the chip's ready to talk to us. + * If it's in FL_ERASING state, suspend it and make it talk now. + */ + switch (chip->state) { + case FL_ERASING: + if (!((struct cfi_pri_intelext *)cfi->cmdset_priv)->FeatureSupport & 2) + goto sleep; /* We don't support erase suspend */ + + cfi_write (map, CMD(0xb0), cmd_addr); + /* If the flash has finished erasing, then 'erase suspend' + * appears to make some (28F320) flash devices switch to + * 'read' mode. Make sure that we switch to 'read status' + * mode so we get the right data. --rmk + */ + cfi_write(map, CMD(0x70), cmd_addr); + chip->oldstate = FL_ERASING; + chip->state = FL_ERASE_SUSPENDING; + // printk("Erase suspending at 0x%lx\n", cmd_addr); + for (;;) { + status = cfi_read(map, cmd_addr); + if ((status & status_OK) == status_OK) + break; + + if (time_after(jiffies, timeo)) { + /* Urgh */ + cfi_write(map, CMD(0xd0), cmd_addr); + /* make sure we're in 'read status' mode */ + cfi_write(map, CMD(0x70), cmd_addr); + chip->state = FL_ERASING; + spin_unlock_bh(chip->mutex); + printk(KERN_ERR "Chip not ready after erase " + "suspended: status = 0x%x\n", status); + return -EIO; + } + + spin_unlock_bh(chip->mutex); + cfi_udelay(1); + spin_lock_bh(chip->mutex); + } + + suspended = 1; + cfi_write(map, CMD(0xff), cmd_addr); + chip->state = FL_READY; + break; + +#if 0 + case FL_WRITING: + /* Not quite yet */ +#endif + + case FL_READY: + break; + + case FL_CFI_QUERY: + case FL_JEDEC_QUERY: + cfi_write(map, CMD(0x70), cmd_addr); + chip->state = FL_STATUS; + + case FL_STATUS: + status = cfi_read(map, cmd_addr); + if ((status & status_OK) == status_OK) { + cfi_write(map, CMD(0xff), cmd_addr); + chip->state = FL_READY; + break; + } + + /* Urgh. Chip not yet ready to talk to us. */ + if (time_after(jiffies, timeo)) { + spin_unlock_bh(chip->mutex); + printk(KERN_ERR "waiting for chip to be ready timed out in read. WSM status = %x\n", status); + return -EIO; + } + + /* Latency issues. Drop the lock, wait a while and retry */ + spin_unlock_bh(chip->mutex); + cfi_udelay(1); + goto retry; + + default: + sleep: + /* Stick ourselves on a wait queue to be woken when + someone changes the status */ + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&chip->wq, &wait); + spin_unlock_bh(chip->mutex); + schedule(); + remove_wait_queue(&chip->wq, &wait); + timeo = jiffies + HZ; + goto retry; + } + + map_copy_from(map, buf, adr, len); + + if (suspended) { + chip->state = chip->oldstate; + /* What if one interleaved chip has finished and the + other hasn't? The old code would leave the finished + one in READY mode. That's bad, and caused -EROFS + errors to be returned from do_erase_oneblock because + that's the only bit it checked for at the time. + As the state machine appears to explicitly allow + sending the 0x70 (Read Status) command to an erasing + chip and expecting it to be ignored, that's what we + do. */ + cfi_write(map, CMD(0xd0), cmd_addr); + cfi_write(map, CMD(0x70), cmd_addr); + } + + wake_up(&chip->wq); + spin_unlock_bh(chip->mutex); + return 0; +} + +static int cfi_staa_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 inline int do_write_buffer(struct map_info *map, struct flchip *chip, + unsigned long adr, const u_char *buf, int len) +{ + struct cfi_private *cfi = map->fldrv_priv; + __u32 status, status_OK; + unsigned long cmd_adr, timeo; + DECLARE_WAITQUEUE(wait, current); + int wbufsize, z; + + /* M58LW064A requires bus alignment for buffer wriets -- saw */ + if (adr & (CFIDEV_BUSWIDTH-1)) + return -EINVAL; + + wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize; + adr += chip->start; + cmd_adr = adr & ~(wbufsize-1); + + /* Let's determine this according to the interleave only once */ + status_OK = CMD(0x80); + + timeo = jiffies + HZ; + retry: + +#ifdef DEBUG_CFI_FEATURES + printk("%s: chip->state[%d]\n", __FUNCTION__, chip->state); +#endif + spin_lock_bh(chip->mutex); + + /* Check that the chip's ready to talk to us. + * Later, we can actually think about interrupting it + * if it's in FL_ERASING state. + * Not just yet, though. + */ + switch (chip->state) { + case FL_READY: + break; + + case FL_CFI_QUERY: + case FL_JEDEC_QUERY: + cfi_write(map, CMD(0x70), cmd_adr); + chip->state = FL_STATUS; +#ifdef DEBUG_CFI_FEATURES + printk("%s: 1 status[%x]\n", __FUNCTION__, cfi_read(map, cmd_adr)); +#endif + + case FL_STATUS: + status = cfi_read(map, cmd_adr); + if ((status & status_OK) == status_OK) + break; + /* Urgh. Chip not yet ready to talk to us. */ + if (time_after(jiffies, timeo)) { + spin_unlock_bh(chip->mutex); + printk(KERN_ERR "waiting for chip to be ready timed out in buffer write Xstatus = %x, status = %x\n", + status, cfi_read(map, cmd_adr)); + return -EIO; + } + + /* Latency issues. Drop the lock, wait a while and retry */ + spin_unlock_bh(chip->mutex); + cfi_udelay(1); + goto retry; + + default: + /* Stick ourselves on a wait queue to be woken when + someone changes the status */ + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&chip->wq, &wait); + spin_unlock_bh(chip->mutex); + schedule(); + remove_wait_queue(&chip->wq, &wait); + timeo = jiffies + HZ; + goto retry; + } + + ENABLE_VPP(map); + cfi_write(map, CMD(0xe8), cmd_adr); + chip->state = FL_WRITING_TO_BUFFER; + + z = 0; + for (;;) { + status = cfi_read(map, cmd_adr); + if ((status & status_OK) == status_OK) + break; + + spin_unlock_bh(chip->mutex); + cfi_udelay(1); + spin_lock_bh(chip->mutex); + + if (++z > 100) { + /* Argh. Not ready for write to buffer */ + DISABLE_VPP(map); + cfi_write(map, CMD(0x70), cmd_adr); + chip->state = FL_STATUS; + spin_unlock_bh(chip->mutex); + printk(KERN_ERR "Chip not ready for buffer write. Xstatus = %x\n", status); + return -EIO; + } + } + + /* Write length of data to come */ + cfi_write(map, CMD(len/CFIDEV_BUSWIDTH-1), cmd_adr ); + + /* Write data */ + for (z = 0; z < len; z += CFIDEV_BUSWIDTH) { + if (cfi_buswidth_is_1()) { + map_write8 (map, *((__u8*)buf)++, adr+z); + } else if (cfi_buswidth_is_2()) { + map_write16 (map, *((__u16*)buf)++, adr+z); + } else if (cfi_buswidth_is_4()) { + map_write32 (map, *((__u32*)buf)++, adr+z); + } else { + DISABLE_VPP(map); + return -EINVAL; + } + } + /* GO GO GO */ + cfi_write(map, CMD(0xd0), cmd_adr); + chip->state = FL_WRITING; + + spin_unlock_bh(chip->mutex); + cfi_udelay(chip->buffer_write_time); + spin_lock_bh(chip->mutex); + + timeo = jiffies + (HZ/2); + z = 0; + for (;;) { + if (chip->state != FL_WRITING) { + /* Someone's suspended the write. Sleep */ + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&chip->wq, &wait); + spin_unlock_bh(chip->mutex); + schedule(); + remove_wait_queue(&chip->wq, &wait); + timeo = jiffies + (HZ / 2); /* FIXME */ + spin_lock_bh(chip->mutex); + continue; + } + + status = cfi_read(map, cmd_adr); + if ((status & status_OK) == status_OK) + break; + + /* OK Still waiting */ + if (time_after(jiffies, timeo)) { + /* clear status */ + cfi_write(map, CMD(0x50), cmd_adr); + /* put back into read status register mode */ + cfi_write(map, CMD(0x70), adr); + chip->state = FL_STATUS; + DISABLE_VPP(map); + spin_unlock_bh(chip->mutex); + printk(KERN_ERR "waiting for chip to be ready timed out in bufwrite\n"); + return -EIO; + } + + /* Latency issues. Drop the lock, wait a while and retry */ + spin_unlock_bh(chip->mutex); + cfi_udelay(1); + z++; + spin_lock_bh(chip->mutex); + } + if (!z) { + chip->buffer_write_time--; + if (!chip->buffer_write_time) + chip->buffer_write_time++; + } + if (z > 1) + chip->buffer_write_time++; + + /* Done and happy. */ + DISABLE_VPP(map); + chip->state = FL_STATUS; + + /* check for errors: 'lock bit', 'VPP', 'dead cell'/'unerased cell' or 'incorrect cmd' -- saw */ + if ((status & CMD(0x02)) || (status & CMD(0x08)) || + (status & CMD(0x10)) || (status & CMD(0x20))) { +#ifdef DEBUG_CFI_FEATURES + printk("%s: 2 status[%x]\n", __FUNCTION__, status); +#endif + /* clear status */ + cfi_write(map, CMD(0x50), cmd_adr); + /* put back into read status register mode */ + cfi_write(map, CMD(0x70), adr); + wake_up(&chip->wq); + spin_unlock_bh(chip->mutex); + return (status & CMD(0x02)) ? -EROFS : -EIO; + } + wake_up(&chip->wq); + spin_unlock_bh(chip->mutex); + + return 0; +} + +static int cfi_staa_write_buffers (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 wbufsize = CFIDEV_INTERLEAVE << cfi->cfiq->MaxBufWriteSize; + int ret = 0; + int chipnum; + unsigned long ofs; + + *retlen = 0; + if (!len) + return 0; + + chipnum = to >> cfi->chipshift; + ofs = to - (chipnum << cfi->chipshift); + +#ifdef DEBUG_CFI_FEATURES + printk("%s: CFIDEV_BUSWIDTH[%x]\n", __FUNCTION__, CFIDEV_BUSWIDTH); + printk("%s: chipnum[%x] wbufsize[%x]\n", __FUNCTION__, chipnum, wbufsize); + printk("%s: ofs[%x] len[%x]\n", __FUNCTION__, ofs, len); +#endif + + /* Write buffer is worth it only if more than one word to write... */ + while (len > 0) { + /* We must not cross write block boundaries */ + int size = wbufsize - (ofs & (wbufsize-1)); + + if (size > len) + size = len; + + ret = do_write_buffer(map, &cfi->chips[chipnum], + ofs, buf, size); + if (ret) + return ret; + + ofs += size; + buf += size; + (*retlen) += size; + len -= size; + + if (ofs >> cfi->chipshift) { + chipnum ++; + ofs = 0; + if (chipnum == cfi->numchips) + return 0; + } + } + + return 0; +} + +/* + * Writev for ECC-Flashes is a little more complicated. We need to maintain + * a small buffer for this. + * XXX: If the buffer size is not a multiple of 2, this will break + */ +#define ECCBUF_SIZE (mtd->eccsize) +#define ECCBUF_DIV(x) ((x) & ~(ECCBUF_SIZE - 1)) +#define ECCBUF_MOD(x) ((x) & (ECCBUF_SIZE - 1)) +static int +cfi_staa_writev(struct mtd_info *mtd, const struct iovec *vecs, + unsigned long count, loff_t to, size_t *retlen) +{ + unsigned long i; + size_t totlen = 0, thislen; + int ret = 0; + size_t buflen = 0; + static char *buffer; + + if (!ECCBUF_SIZE) { + /* We should fall back to a general writev implementation. + * Until that is written, just break. + */ + return -EIO; + } + buffer = kmalloc(ECCBUF_SIZE, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + for (i=0; i<count; i++) { + size_t elem_len = vecs[i].iov_len; + void *elem_base = vecs[i].iov_base; + if (!elem_len) /* FIXME: Might be unnecessary. Check that */ + continue; + if (buflen) { /* cut off head */ + if (buflen + elem_len < ECCBUF_SIZE) { /* just accumulate */ + memcpy(buffer+buflen, elem_base, elem_len); + buflen += elem_len; + continue; + } + memcpy(buffer+buflen, elem_base, ECCBUF_SIZE-buflen); + ret = mtd->write(mtd, to, ECCBUF_SIZE, &thislen, buffer); + totlen += thislen; + if (ret || thislen != ECCBUF_SIZE) + goto write_error; + elem_len -= thislen-buflen; + elem_base += thislen-buflen; + to += ECCBUF_SIZE; + } + if (ECCBUF_DIV(elem_len)) { /* write clean aligned data */ + ret = mtd->write(mtd, to, ECCBUF_DIV(elem_len), &thislen, elem_base); + totlen += thislen; + if (ret || thislen != ECCBUF_DIV(elem_len)) + goto write_error; + to += thislen; + } + buflen = ECCBUF_MOD(elem_len); /* cut off tail */ + if (buflen) { + memset(buffer, 0xff, ECCBUF_SIZE); + memcpy(buffer, elem_base + thislen, buflen); + } + } + if (buflen) { /* flush last page, even if not full */ + /* This is sometimes intended behaviour, really */ + ret = mtd->write(mtd, to, buflen, &thislen, buffer); + totlen += thislen; + if (ret || thislen != ECCBUF_SIZE) + goto write_error; + } +write_error: + if (retlen) + *retlen = totlen; + return ret; +} + + +static inline int do_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr) +{ + struct cfi_private *cfi = map->fldrv_priv; + __u32 status, status_OK; + unsigned long timeo; + int retries = 3; + DECLARE_WAITQUEUE(wait, current); + int ret = 0; + + adr += chip->start; + + /* Let's determine this according to the interleave only once */ + status_OK = CMD(0x80); + + timeo = jiffies + HZ; +retry: + spin_lock_bh(chip->mutex); + + /* Check that the chip's ready to talk to us. */ + switch (chip->state) { + case FL_CFI_QUERY: + case FL_JEDEC_QUERY: + case FL_READY: + cfi_write(map, CMD(0x70), adr); + chip->state = FL_STATUS; + + case FL_STATUS: + status = cfi_read(map, adr); + if ((status & status_OK) == status_OK) + break; + + /* Urgh. Chip not yet ready to talk to us. */ + if (time_after(jiffies, timeo)) { + spin_unlock_bh(chip->mutex); + printk(KERN_ERR "waiting for chip to be ready timed out in erase\n"); + return -EIO; + } + + /* Latency issues. Drop the lock, wait a while and retry */ + spin_unlock_bh(chip->mutex); + cfi_udelay(1); + goto retry; + + default: + /* Stick ourselves on a wait queue to be woken when + someone changes the status */ + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&chip->wq, &wait); + spin_unlock_bh(chip->mutex); + schedule(); + remove_wait_queue(&chip->wq, &wait); + timeo = jiffies + HZ; + goto retry; + } + + ENABLE_VPP(map); + /* Clear the status register first */ + cfi_write(map, CMD(0x50), adr); + + /* Now erase */ + cfi_write(map, CMD(0x20), adr); + cfi_write(map, CMD(0xD0), adr); + chip->state = FL_ERASING; + + spin_unlock_bh(chip->mutex); + schedule_timeout(HZ); + spin_lock_bh(chip->mutex); + + /* FIXME. Use a timer to check this, and return immediately. */ + /* Once the state machine's known to be working I'll do that */ + + timeo = jiffies + (HZ*20); + for (;;) { + if (chip->state != FL_ERASING) { + /* Someone's suspended the erase. Sleep */ + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&chip->wq, &wait); + spin_unlock_bh(chip->mutex); + schedule(); + remove_wait_queue(&chip->wq, &wait); + timeo = jiffies + (HZ*20); /* FIXME */ + spin_lock_bh(chip->mutex); + continue; + } + + status = cfi_read(map, adr); + if ((status & status_OK) == status_OK) + break; + + /* OK Still waiting */ + if (time_after(jiffies, timeo)) { + cfi_write(map, CMD(0x70), adr); + chip->state = FL_STATUS; + printk(KERN_ERR "waiting for erase to complete timed out. Xstatus = %x, status = %x.\n", status, cfi_read(map, adr)); + DISABLE_VPP(map); + spin_unlock_bh(chip->mutex); + return -EIO; + } + + /* Latency issues. Drop the lock, wait a while and retry */ + spin_unlock_bh(chip->mutex); + cfi_udelay(1); + spin_lock_bh(chip->mutex); + } + + DISABLE_VPP(map); + ret = 0; + + /* We've broken this before. It doesn't hurt to be safe */ + cfi_write(map, CMD(0x70), adr); + chip->state = FL_STATUS; + status = cfi_read(map, adr); + + /* check for lock bit */ + if (status & CMD(0x3a)) { + unsigned char chipstatus = status; + if (status != CMD(status & 0xff)) { + int i; + for (i = 1; i<CFIDEV_INTERLEAVE; i++) { + chipstatus |= status >> (cfi->device_type * 8); + } + printk(KERN_WARNING "Status is not identical for all chips: 0x%x. Merging to give 0x%02x\n", status, chipstatus); + } + /* Reset the error bits */ + cfi_write(map, CMD(0x50), adr); + cfi_write(map, CMD(0x70), adr); + + if ((chipstatus & 0x30) == 0x30) { + printk(KERN_NOTICE "Chip reports improper command sequence: status 0x%x\n", status); + ret = -EIO; + } else if (chipstatus & 0x02) { + /* Protection bit set */ + ret = -EROFS; + } else if (chipstatus & 0x8) { + /* Voltage */ + printk(KERN_WARNING "Chip reports voltage low on erase: status 0x%x\n", status); + ret = -EIO; + } else if (chipstatus & 0x20) { + if (retries--) { + printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x. Retrying...\n", adr, status); + timeo = jiffies + HZ; + chip->state = FL_STATUS; + spin_unlock_bh(chip->mutex); + goto retry; + } + printk(KERN_DEBUG "Chip erase failed at 0x%08lx: status 0x%x\n", adr, status); + ret = -EIO; + } + } + + wake_up(&chip->wq); + spin_unlock_bh(chip->mutex); + return ret; +} + +int cfi_staa_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 void cfi_staa_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: + spin_lock_bh(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: + spin_unlock_bh(chip->mutex); + break; + + default: + /* Not an idle state */ + add_wait_queue(&chip->wq, &wait); + + spin_unlock_bh(chip->mutex); + schedule(); + remove_wait_queue(&chip->wq, &wait); + + goto retry; + } + } + + /* Unlock the chips again */ + + for (i--; i >=0; i--) { + chip = &cfi->chips[i]; + + spin_lock_bh(chip->mutex); + + if (chip->state == FL_SYNCING) { + chip->state = chip->oldstate; + wake_up(&chip->wq); + } + spin_unlock_bh(chip->mutex); + } +} + +static inline int do_lock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr) +{ + struct cfi_private *cfi = map->fldrv_priv; + __u32 status, status_OK; + unsigned long timeo = jiffies + HZ; + DECLARE_WAITQUEUE(wait, current); + + adr += chip->start; + + /* Let's determine this according to the interleave only once */ + status_OK = CMD(0x80); + + timeo = jiffies + HZ; +retry: + spin_lock_bh(chip->mutex); + + /* Check that the chip's ready to talk to us. */ + switch (chip->state) { + case FL_CFI_QUERY: + case FL_JEDEC_QUERY: + case FL_READY: + cfi_write(map, CMD(0x70), adr); + chip->state = FL_STATUS; + + case FL_STATUS: + status = cfi_read(map, adr); + if ((status & status_OK) == status_OK) + break; + + /* Urgh. Chip not yet ready to talk to us. */ + if (time_after(jiffies, timeo)) { + spin_unlock_bh(chip->mutex); + printk(KERN_ERR "waiting for chip to be ready timed out in lock\n"); + return -EIO; + } + + /* Latency issues. Drop the lock, wait a while and retry */ + spin_unlock_bh(chip->mutex); + cfi_udelay(1); + goto retry; + + default: + /* Stick ourselves on a wait queue to be woken when + someone changes the status */ + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&chip->wq, &wait); + spin_unlock_bh(chip->mutex); + schedule(); + remove_wait_queue(&chip->wq, &wait); + timeo = jiffies + HZ; + goto retry; + } + + ENABLE_VPP(map); + cfi_write(map, CMD(0x60), adr); + cfi_write(map, CMD(0x01), adr); + chip->state = FL_LOCKING; + + spin_unlock_bh(chip->mutex); + schedule_timeout(HZ); + spin_lock_bh(chip->mutex); + + /* FIXME. Use a timer to check this, and return immediately. */ + /* Once the state machine's known to be working I'll do that */ + + timeo = jiffies + (HZ*2); + for (;;) { + + status = cfi_read(map, adr); + if ((status & status_OK) == status_OK) + break; + + /* OK Still waiting */ + if (time_after(jiffies, timeo)) { + cfi_write(map, CMD(0x70), adr); + chip->state = FL_STATUS; + printk(KERN_ERR "waiting for lock to complete timed out. Xstatus = %x, status = %x.\n", status, cfi_read(map, adr)); + DISABLE_VPP(map); + spin_unlock_bh(chip->mutex); + return -EIO; + } + + /* Latency issues. Drop the lock, wait a while and retry */ + spin_unlock_bh(chip->mutex); + cfi_udelay(1); + spin_lock_bh(chip->mutex); + } + + /* Done and happy. */ + chip->state = FL_STATUS; + DISABLE_VPP(map); + wake_up(&chip->wq); + spin_unlock_bh(chip->mutex); + return 0; +} +static int cfi_staa_lock(struct mtd_info *mtd, loff_t ofs, size_t len) +{ + struct map_info *map = mtd->priv; + struct cfi_private *cfi = map->fldrv_priv; + unsigned long adr; + int chipnum, ret = 0; +#ifdef DEBUG_LOCK_BITS + int ofs_factor = cfi->interleave * cfi->device_type; +#endif + + if (ofs & (mtd->erasesize - 1)) + return -EINVAL; + + if (len & (mtd->erasesize -1)) + return -EINVAL; + + if ((len + ofs) > mtd->size) + return -EINVAL; + + chipnum = ofs >> cfi->chipshift; + adr = ofs - (chipnum << cfi->chipshift); + + while(len) { + +#ifdef DEBUG_LOCK_BITS + cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL); + printk("before lock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor))); + cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL); +#endif + + ret = do_lock_oneblock(map, &cfi->chips[chipnum], adr); + +#ifdef DEBUG_LOCK_BITS + cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL); + printk("after lock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor))); + cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL); +#endif + + if (ret) + return ret; + + adr += mtd->erasesize; + len -= mtd->erasesize; + + if (adr >> cfi->chipshift) { + adr = 0; + chipnum++; + + if (chipnum >= cfi->numchips) + break; + } + } + return 0; +} +static inline int do_unlock_oneblock(struct map_info *map, struct flchip *chip, unsigned long adr) +{ + struct cfi_private *cfi = map->fldrv_priv; + __u32 status, status_OK; + unsigned long timeo = jiffies + HZ; + DECLARE_WAITQUEUE(wait, current); + + adr += chip->start; + + /* Let's determine this according to the interleave only once */ + status_OK = CMD(0x80); + + timeo = jiffies + HZ; +retry: + spin_lock_bh(chip->mutex); + + /* Check that the chip's ready to talk to us. */ + switch (chip->state) { + case FL_CFI_QUERY: + case FL_JEDEC_QUERY: + case FL_READY: + cfi_write(map, CMD(0x70), adr); + chip->state = FL_STATUS; + + case FL_STATUS: + status = cfi_read(map, adr); + if ((status & status_OK) == status_OK) + break; + + /* Urgh. Chip not yet ready to talk to us. */ + if (time_after(jiffies, timeo)) { + spin_unlock_bh(chip->mutex); + printk(KERN_ERR "waiting for chip to be ready timed out in unlock\n"); + return -EIO; + } + + /* Latency issues. Drop the lock, wait a while and retry */ + spin_unlock_bh(chip->mutex); + cfi_udelay(1); + goto retry; + + default: + /* Stick ourselves on a wait queue to be woken when + someone changes the status */ + set_current_state(TASK_UNINTERRUPTIBLE); + add_wait_queue(&chip->wq, &wait); + spin_unlock_bh(chip->mutex); + schedule(); + remove_wait_queue(&chip->wq, &wait); + timeo = jiffies + HZ; + goto retry; + } + + ENABLE_VPP(map); + cfi_write(map, CMD(0x60), adr); + cfi_write(map, CMD(0xD0), adr); + chip->state = FL_UNLOCKING; + + spin_unlock_bh(chip->mutex); + schedule_timeout(HZ); + spin_lock_bh(chip->mutex); + + /* FIXME. Use a timer to check this, and return immediately. */ + /* Once the state machine's known to be working I'll do that */ + + timeo = jiffies + (HZ*2); + for (;;) { + + status = cfi_read(map, adr); + if ((status & status_OK) == status_OK) + break; + + /* OK Still waiting */ + if (time_after(jiffies, timeo)) { + cfi_write(map, CMD(0x70), adr); + chip->state = FL_STATUS; + printk(KERN_ERR "waiting for unlock to complete timed out. Xstatus = %x, status = %x.\n", status, cfi_read(map, adr)); + DISABLE_VPP(map); + spin_unlock_bh(chip->mutex); + return -EIO; + } + + /* Latency issues. Drop the unlock, wait a while and retry */ + spin_unlock_bh(chip->mutex); + cfi_udelay(1); + spin_lock_bh(chip->mutex); + } + + /* Done and happy. */ + chip->state = FL_STATUS; + DISABLE_VPP(map); + wake_up(&chip->wq); + spin_unlock_bh(chip->mutex); + return 0; +} +static int cfi_staa_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) +{ + struct map_info *map = mtd->priv; + struct cfi_private *cfi = map->fldrv_priv; + unsigned long adr; + int chipnum, ret = 0; +#ifdef DEBUG_LOCK_BITS + int ofs_factor = cfi->interleave * cfi->device_type; +#endif + + chipnum = ofs >> cfi->chipshift; + adr = ofs - (chipnum << cfi->chipshift); + +#ifdef DEBUG_LOCK_BITS + { + unsigned long temp_adr = adr; + unsigned long temp_len = len; + + cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL); + while (temp_len) { + printk("before unlock %x: block status register is %x\n",temp_adr,cfi_read_query(map, temp_adr+(2*ofs_factor))); + temp_adr += mtd->erasesize; + temp_len -= mtd->erasesize; + } + cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL); + } +#endif + + ret = do_unlock_oneblock(map, &cfi->chips[chipnum], adr); + +#ifdef DEBUG_LOCK_BITS + cfi_send_gen_cmd(0x90, 0x55, 0, map, cfi, cfi->device_type, NULL); + printk("after unlock: block status register is %x\n",cfi_read_query(map, adr+(2*ofs_factor))); + cfi_send_gen_cmd(0xff, 0x55, 0, map, cfi, cfi->device_type, NULL); +#endif + + return ret; +} + +static int cfi_staa_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; + + for (i=0; !ret && i<cfi->numchips; i++) { + chip = &cfi->chips[i]; + + spin_lock_bh(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; + } + spin_unlock_bh(chip->mutex); + } + + /* Unlock the chips again */ + + if (ret) { + for (i--; i >=0; i--) { + chip = &cfi->chips[i]; + + spin_lock_bh(chip->mutex); + + if (chip->state == FL_PM_SUSPENDED) { + /* No need to force it into a known state here, + because we're returning failure, and it didn't + get power cycled */ + chip->state = chip->oldstate; + wake_up(&chip->wq); + } + spin_unlock_bh(chip->mutex); + } + } + + return ret; +} + +static void cfi_staa_resume(struct mtd_info *mtd) +{ + struct map_info *map = mtd->priv; + struct cfi_private *cfi = map->fldrv_priv; + int i; + struct flchip *chip; + + for (i=0; i<cfi->numchips; i++) { + + chip = &cfi->chips[i]; + + spin_lock_bh(chip->mutex); + + /* Go to known state. Chip may have been power cycled */ + if (chip->state == FL_PM_SUSPENDED) { + cfi_write(map, CMD(0xFF), 0); + chip->state = FL_READY; + wake_up(&chip->wq); + } + + spin_unlock_bh(chip->mutex); + } +} + +static void cfi_staa_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_staa_init init_module +#define cfi_staa_exit cleanup_module +#endif + +static char im_name[]="cfi_cmdset_0020"; + +int __init cfi_staa_init(void) +{ + inter_module_register(im_name, THIS_MODULE, &cfi_cmdset_0020); + return 0; +} + +static void __exit cfi_staa_exit(void) +{ + inter_module_unregister(im_name); +} + +module_init(cfi_staa_init); +module_exit(cfi_staa_exit); diff -Nru a/drivers/mtd/chips/cfi_probe.c b/drivers/mtd/chips/cfi_probe.c --- a/drivers/mtd/chips/cfi_probe.c Mon Jun 9 23:16:16 2003 +++ b/drivers/mtd/chips/cfi_probe.c Mon Jun 9 23:16:16 2003 @@ -1,13 +1,14 @@ /* Common Flash Interface probe code. (C) 2000 Red Hat. GPL'd. - $Id: cfi_probe.c,v 1.66 2001/10/02 15:05:12 dwmw2 Exp $ + $Id: cfi_probe.c,v 1.71 2003/05/28 12:51:48 dwmw2 Exp $ */ #include <linux/config.h> #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> +#include <linux/init.h> #include <asm/io.h> #include <asm/byteorder.h> #include <linux/errno.h> @@ -24,16 +25,13 @@ static void print_cfi_ident(struct cfi_ident *); #endif -int cfi_jedec_setup(struct cfi_private *p_cfi, int index); -int cfi_jedec_lookup(int index, int mfr_id, int dev_id); - static int cfi_probe_chip(struct map_info *map, __u32 base, struct flchip *chips, struct cfi_private *cfi); static int cfi_chip_setup(struct map_info *map, struct cfi_private *cfi); struct mtd_info *cfi_probe(struct map_info *map); -/* check for QRY, or search for jedec id. +/* check for QRY. in: interleave,type,mode ret: table index, <0 for error */ @@ -55,6 +53,18 @@ { 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", + (unsigned long)base, map->size -1); + return 0; + } + if ((base + 0xff) >= map->size) { + printk(KERN_NOTICE + "Probe at base[0x55](0x%08lx) past the end of the map(0x%08lx)\n", + (unsigned long)base + 0x55, map->size -1); + return 0; + } 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); @@ -139,7 +149,7 @@ memset(cfi->cfiq,0,sizeof(struct cfi_ident)); - cfi->cfi_mode = 1; + cfi->cfi_mode = CFI_MODE_CFI; cfi->fast_prog=1; /* CFI supports fast programming */ /* Read the CFI info structure */ @@ -250,11 +260,11 @@ else printk("Full buffer write not supported\n"); - printk("Typical block erase timeout: %d µs\n", 1<<cfip->BlockEraseTimeoutTyp); - printk("Maximum block erase timeout: %d µs\n", (1<<cfip->BlockEraseTimeoutMax) * (1<<cfip->BlockEraseTimeoutTyp)); + printk("Typical block erase timeout: %d ms\n", 1<<cfip->BlockEraseTimeoutTyp); + printk("Maximum block erase timeout: %d ms\n", (1<<cfip->BlockEraseTimeoutMax) * (1<<cfip->BlockEraseTimeoutTyp)); if (cfip->ChipEraseTimeoutTyp || cfip->ChipEraseTimeoutMax) { - printk("Typical chip erase timeout: %d µs\n", 1<<cfip->ChipEraseTimeoutTyp); - printk("Maximum chip erase timeout: %d µs\n", (1<<cfip->ChipEraseTimeoutMax) * (1<<cfip->ChipEraseTimeoutTyp)); + printk("Typical chip erase timeout: %d ms\n", 1<<cfip->ChipEraseTimeoutTyp); + printk("Maximum chip erase timeout: %d ms\n", (1<<cfip->ChipEraseTimeoutMax) * (1<<cfip->ChipEraseTimeoutTyp)); } else printk("Chip erase not supported\n"); diff -Nru a/drivers/mtd/chips/chipreg.c b/drivers/mtd/chips/chipreg.c --- a/drivers/mtd/chips/chipreg.c Mon Jun 9 23:16:10 2003 +++ b/drivers/mtd/chips/chipreg.c Mon Jun 9 23:16:10 2003 @@ -1,5 +1,5 @@ /* - * $Id: chipreg.c,v 1.12 2001/10/02 15:29:53 dwmw2 Exp $ + * $Id: chipreg.c,v 1.15 2003/05/21 15:15:05 dwmw2 Exp $ * * Registration for chip drivers * @@ -7,10 +7,13 @@ #include <linux/kernel.h> #include <linux/config.h> +#include <linux/module.h> #include <linux/kmod.h> #include <linux/spinlock.h> -#include <linux/mtd/compatmac.h> +#include <linux/slab.h> #include <linux/mtd/map.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/compatmac.h> spinlock_t chip_drvs_lock = SPIN_LOCK_UNLOCKED; static LIST_HEAD(chip_drvs_list); @@ -29,7 +32,7 @@ spin_unlock(&chip_drvs_lock); } -static struct mtd_chip_driver *get_mtd_chip_driver (char *name) +static struct mtd_chip_driver *get_mtd_chip_driver (const char *name) { struct list_head *pos; struct mtd_chip_driver *ret = NULL, *this; @@ -44,10 +47,8 @@ break; } } - if (ret && !try_module_get(ret->module)) { - /* Eep. Failed. */ + if (ret && !try_module_get(ret->module)) ret = NULL; - } spin_unlock(&chip_drvs_lock); @@ -57,7 +58,7 @@ /* Hide all the horrid details, like some silly person taking get_module_symbol() away from us, from the caller. */ -struct mtd_info *do_map_probe(char *name, struct map_info *map) +struct mtd_info *do_map_probe(const char *name, struct map_info *map) { struct mtd_chip_driver *drv; struct mtd_info *ret; @@ -84,10 +85,26 @@ return NULL; } +/* + * Destroy an MTD device which was created for a map device. + * Make sure the MTD device is already unregistered before calling this + */ +void map_destroy(struct mtd_info *mtd) +{ + struct map_info *map = mtd->priv; + + if (map->fldrv->destroy) + map->fldrv->destroy(mtd); + + module_put(map->fldrv->module); + + kfree(mtd); +} EXPORT_SYMBOL(register_mtd_chip_driver); EXPORT_SYMBOL(unregister_mtd_chip_driver); EXPORT_SYMBOL(do_map_probe); +EXPORT_SYMBOL(map_destroy); MODULE_LICENSE("GPL"); MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); diff -Nru a/drivers/mtd/chips/gen_probe.c b/drivers/mtd/chips/gen_probe.c --- a/drivers/mtd/chips/gen_probe.c Mon Jun 9 23:16:18 2003 +++ b/drivers/mtd/chips/gen_probe.c Mon Jun 9 23:16:18 2003 @@ -2,13 +2,16 @@ * Routines common to all CFI-type probes. * (C) 2001, 2001 Red Hat, Inc. * GPL'd - * $Id: gen_probe.c,v 1.5 2001/10/02 15:05:12 dwmw2 Exp $ + * $Id: gen_probe.c,v 1.11 2003/05/21 15:15:05 dwmw2 Exp $ */ #include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/module.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> #include <linux/mtd/cfi.h> +#include <linux/mtd/mtd.h> #include <linux/mtd/gen_probe.h> static struct mtd_info *check_cmd_set(struct map_info *, int); @@ -38,7 +41,7 @@ if (mtd) return mtd; - printk(KERN_WARNING"cfi_probe: No supported Vendor Command Set found\n"); + printk(KERN_WARNING"gen_probe: No supported Vendor Command Set found\n"); kfree(cfi->cfiq); kfree(cfi); @@ -57,6 +60,7 @@ int i; memset(&cfi, 0, sizeof(cfi)); + memset(&chip[0], 0, sizeof(chip)); /* Call the probetype-specific code with all permutations of interleave and device type, etc. */ @@ -106,6 +110,12 @@ * Now probe for other chips, checking sensibly for aliases while * we're at it. The new_chip probe above should have let the first * chip in read mode. + * + * NOTE: Here, we're checking if there is room for another chip + * the same size within the mapping. Therefore, + * base + chipsize <= map->size is the correct thing to do, + * because, base + chipsize would be the _first_ byte of the + * next chip, not the one we're currently pondering. */ for (base = (1<<cfi.chipshift); base + (1<<cfi.chipshift) <= map->size; @@ -224,6 +234,41 @@ break; #endif /* CFIDEV_BUSWIDTH_4 */ +#ifdef CFIDEV_BUSWIDTH_8 + case CFIDEV_BUSWIDTH_8: +#if defined(CFIDEV_INTERLEAVE_2) && defined(SOMEONE_ACTUALLY_MAKES_THESE) + cfi->interleave = CFIDEV_INTERLEAVE_2; + + cfi->device_type = CFI_DEVICETYPE_X32; + if (cp->probe_chip(map, 0, NULL, cfi)) + return 1; +#endif /* CFIDEV_INTERLEAVE_2 */ +#ifdef CFIDEV_INTERLEAVE_4 + cfi->interleave = CFIDEV_INTERLEAVE_4; + +#ifdef SOMEONE_ACTUALLY_MAKES_THESE + cfi->device_type = CFI_DEVICETYPE_X32; + if (cp->probe_chip(map, 0, NULL, cfi)) + return 1; +#endif + cfi->device_type = CFI_DEVICETYPE_X16; + if (cp->probe_chip(map, 0, NULL, cfi)) + return 1; +#endif /* CFIDEV_INTERLEAVE_4 */ +#ifdef CFIDEV_INTERLEAVE_8 + cfi->interleave = CFIDEV_INTERLEAVE_8; + + cfi->device_type = CFI_DEVICETYPE_X16; + if (cp->probe_chip(map, 0, NULL, cfi)) + return 1; + + cfi->device_type = CFI_DEVICETYPE_X8; + if (cp->probe_chip(map, 0, NULL, cfi)) + return 1; +#endif /* CFIDEV_INTERLEAVE_8 */ + break; +#endif /* CFIDEV_BUSWIDTH_8 */ + default: printk(KERN_WARNING "genprobe_new_chip called with unsupported buswidth %d\n", map->buswidth); return 0; @@ -288,6 +333,10 @@ #ifdef CONFIG_MTD_CFI_AMDSTD case 0x0002: return cfi_cmdset_0002(map, primary); +#endif +#ifdef CONFIG_MTD_CFI_STAA + case 0x0020: + return cfi_cmdset_0020(map, primary); #endif } diff -Nru a/drivers/mtd/chips/jedec.c b/drivers/mtd/chips/jedec.c --- a/drivers/mtd/chips/jedec.c Mon Jun 9 23:16:14 2003 +++ b/drivers/mtd/chips/jedec.c Mon Jun 9 23:16:14 2003 @@ -11,10 +11,16 @@ * not going to guess how to send commands to them, plus I expect they will * all speak CFI.. * - * $Id: jedec.c,v 1.12 2001/11/06 14:37:35 dwmw2 Exp $ + * $Id: jedec.c,v 1.19 2003/05/29 09:25:23 dwmw2 Exp $ */ +#include <linux/init.h> +#include <linux/module.h> +#include <linux/kernel.h> #include <linux/mtd/jedec.h> +#include <linux/mtd/map.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/compatmac.h> static struct mtd_info *jedec_probe(struct map_info *); static int jedec_probe8(struct map_info *map,unsigned long base, @@ -264,7 +270,7 @@ MTD->priv = map; map->fldrv_priv = priv; map->fldrv = &jedec_chipdrv; - MOD_INC_USE_COUNT; + __module_get(THIS_MODULE); return MTD; } @@ -386,8 +392,8 @@ static int jedec_probe8(struct map_info *map,unsigned long base, struct jedec_private *priv) { - #define flread(x) map->read8(map,base+x) - #define flwrite(v,x) map->write8(map,v,base+x) + #define flread(x) map_read8(map,base+x) + #define flwrite(v,x) map_write8(map,v,base+x) const unsigned long AutoSel1 = 0xAA; const unsigned long AutoSel2 = 0x55; @@ -446,8 +452,8 @@ static int jedec_probe32(struct map_info *map,unsigned long base, struct jedec_private *priv) { - #define flread(x) map->read32(map,base+((x)<<2)) - #define flwrite(v,x) map->write32(map,v,base+((x)<<2)) + #define flread(x) map_read32(map,base+((x)<<2)) + #define flwrite(v,x) map_write32(map,v,base+((x)<<2)) const unsigned long AutoSel1 = 0xAAAAAAAA; const unsigned long AutoSel2 = 0x55555555; @@ -500,8 +506,8 @@ we call this routine with the JEDEC return still enabled, if two or more flashes have a truncated address space the probe test will still work */ - if (base + Size+0x555 < map->size && - base + Size+0x555 < (base & (~(my_bank_size-1))) + my_bank_size) + if (base + (Size<<2)+0x555 < map->size && + base + (Size<<2)+0x555 < (base & (~(my_bank_size-1))) + my_bank_size) { if (flread(base+Size) != flread(base+Size + 0x100) || flread(base+Size + 1) != flread(base+Size + 0x101)) @@ -525,7 +531,7 @@ { struct map_info *map = (struct map_info *)mtd->priv; - map->copy_from(map, buf, from, len); + map_copy_from(map, buf, from, len); *retlen = len; return 0; } @@ -549,7 +555,7 @@ get = priv->bank_fill[0] - offset; bank /= priv->bank_fill[0]; - map->copy_from(map,buf + *retlen,bank*my_bank_size + offset,get); + map_copy_from(map,buf + *retlen,bank*my_bank_size + offset,get); len -= get; *retlen += get; @@ -580,8 +586,8 @@ static int flash_erase(struct mtd_info *mtd, struct erase_info *instr) { // Does IO to the currently selected chip - #define flread(x) map->read8(map,chip->base+((x)<<chip->addrshift)) - #define flwrite(v,x) map->write8(map,v,chip->base+((x)<<chip->addrshift)) + #define flread(x) map_read8(map,chip->base+((x)<<chip->addrshift)) + #define flwrite(v,x) map_write8(map,v,chip->base+((x)<<chip->addrshift)) unsigned long Time = 0; unsigned long NoTime = 0; @@ -686,19 +692,19 @@ or this is not really flash ;> */ switch (map->buswidth) { case 1: - Last[0] = map->read8(map,(chip->base >> chip->addrshift) + chip->start + off); - Last[1] = map->read8(map,(chip->base >> chip->addrshift) + chip->start + off); - Last[2] = map->read8(map,(chip->base >> chip->addrshift) + chip->start + off); + Last[0] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off); + Last[1] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off); + Last[2] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off); break; case 2: - Last[0] = map->read16(map,(chip->base >> chip->addrshift) + chip->start + off); - Last[1] = map->read16(map,(chip->base >> chip->addrshift) + chip->start + off); - Last[2] = map->read16(map,(chip->base >> chip->addrshift) + chip->start + off); + Last[0] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off); + Last[1] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off); + Last[2] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off); break; case 3: - Last[0] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off); - Last[1] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off); - Last[2] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off); + Last[0] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off); + Last[1] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off); + Last[2] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off); break; } Count = 3; @@ -734,13 +740,13 @@ switch (map->buswidth) { case 1: - Last[Count % 4] = map->read8(map,(chip->base >> chip->addrshift) + chip->start + off); + Last[Count % 4] = map_read8(map,(chip->base >> chip->addrshift) + chip->start + off); break; case 2: - Last[Count % 4] = map->read16(map,(chip->base >> chip->addrshift) + chip->start + off); + Last[Count % 4] = map_read16(map,(chip->base >> chip->addrshift) + chip->start + off); break; case 4: - Last[Count % 4] = map->read32(map,(chip->base >> chip->addrshift) + chip->start + off); + Last[Count % 4] = map_read32(map,(chip->base >> chip->addrshift) + chip->start + off); break; } Count++; @@ -773,6 +779,7 @@ } //printk("done\n"); + instr->state = MTD_ERASE_DONE; if (instr->callback) instr->callback(instr); return 0; @@ -790,9 +797,9 @@ { /* Does IO to the currently selected chip. It takes the bank addressing base (which is divisible by the chip size) adds the necessary lower bits - of addrshift (interleve index) and then adds the control register index. */ - #define flread(x) map->read8(map,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift)) - #define flwrite(v,x) map->write8(map,v,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift)) + of addrshift (interleave index) and then adds the control register index. */ + #define flread(x) map_read8(map,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift)) + #define flwrite(v,x) map_write8(map,v,base+(off&((1<<chip->addrshift)-1))+((x)<<chip->addrshift)) struct map_info *map = (struct map_info *)mtd->priv; struct jedec_private *priv = (struct jedec_private *)map->fldrv_priv; @@ -828,7 +835,7 @@ // Loop over this page for (; off != (chip->size << chip->addrshift) && len != 0; start++, len--, off++,buf++) { - unsigned char oldbyte = map->read8(map,base+off); + unsigned char oldbyte = map_read8(map,base+off); unsigned char Last[4]; unsigned long Count = 0; @@ -843,10 +850,10 @@ flwrite(0xAA,0x555); flwrite(0x55,0x2AA); flwrite(0xA0,0x555); - map->write8(map,*buf,base + off); - Last[0] = map->read8(map,base + off); - Last[1] = map->read8(map,base + off); - Last[2] = map->read8(map,base + off); + map_write8(map,*buf,base + off); + Last[0] = map_read8(map,base + off); + Last[1] = map_read8(map,base + off); + Last[2] = map_read8(map,base + off); /* Wait for the flash to finish the operation. We store the last 4 status bytes that have been retrieved so we can determine why @@ -854,7 +861,7 @@ failure */ for (Count = 3; Last[(Count - 1) % 4] != Last[(Count - 2) % 4] && Count < 10000; Count++) - Last[Count % 4] = map->read8(map,base + off); + Last[Count % 4] = map_read8(map,base + off); if (Last[(Count - 1) % 4] != *buf) { jedec_flash_failed(Last[(Count - 3) % 4]); diff -Nru a/drivers/mtd/chips/jedec_probe.c b/drivers/mtd/chips/jedec_probe.c --- a/drivers/mtd/chips/jedec_probe.c Mon Jun 9 23:16:19 2003 +++ b/drivers/mtd/chips/jedec_probe.c Mon Jun 9 23:16:19 2003 @@ -1,7 +1,9 @@ /* Common Flash Interface probe code. (C) 2000 Red Hat. GPL'd. - $Id: jedec_probe.c,v 1.3 2001/10/02 15:05:12 dwmw2 Exp $ + $Id: jedec_probe.c,v 1.29 2003/05/28 13:57:46 dwmw2 Exp $ + See JEDEC (http://www.jedec.org/) standard JESD21C (section 3.5) + for the standard this probe goes back to. */ #include <linux/config.h> @@ -14,18 +16,23 @@ #include <linux/slab.h> #include <linux/interrupt.h> +#include <linux/mtd/mtd.h> #include <linux/mtd/map.h> #include <linux/mtd/cfi.h> #include <linux/mtd/gen_probe.h> - /* Manufacturers */ #define MANUFACTURER_AMD 0x0001 -#define MANUFACTURER_FUJITSU 0x0004 #define MANUFACTURER_ATMEL 0x001f -#define MANUFACTURER_ST 0x0020 +#define MANUFACTURER_FUJITSU 0x0004 +#define MANUFACTURER_INTEL 0x0089 +#define MANUFACTURER_MACRONIX 0x00C2 +#define MANUFACTURER_PMC 0x009D #define MANUFACTURER_SST 0x00BF +#define MANUFACTURER_ST 0x0020 #define MANUFACTURER_TOSHIBA 0x0098 +#define MANUFACTURER_WINBOND 0x00da + /* AMD */ #define AM29F800BB 0x2258 @@ -34,27 +41,167 @@ #define AM29LV800BT 0x22DA #define AM29LV160DT 0x22C4 #define AM29LV160DB 0x2249 +#define AM29F017D 0x003D +#define AM29F016D 0x00AD +#define AM29F080 0x00D5 +#define AM29F040 0x00A4 +#define AM29LV040B 0x004F +#define AM29F032B 0x0041 /* Atmel */ -#define AT49BV16X4 0x00c0 -#define AT49BV16X4T 0x00c2 +#define AT49BV512 0x0003 +#define AT29LV512 0x003d +#define AT49BV16X 0x00C0 +#define AT49BV16XT 0x00C2 +#define AT49BV32X 0x00C8 +#define AT49BV32XT 0x00C9 /* Fujitsu */ +#define MBM29LV650UE 0x22D7 +#define MBM29LV320TE 0x22F6 +#define MBM29LV320BE 0x22F9 #define MBM29LV160TE 0x22C4 #define MBM29LV160BE 0x2249 +#define MBM29LV800BA 0x225B +#define MBM29LV800TA 0x22DA + +/* Intel */ +#define I28F004B3T 0x00d4 +#define I28F004B3B 0x00d5 +#define I28F400B3T 0x8894 +#define I28F400B3B 0x8895 +#define I28F008S5 0x00a6 +#define I28F016S5 0x00a0 +#define I28F008SA 0x00a2 +#define I28F008B3T 0x00d2 +#define I28F008B3B 0x00d3 +#define I28F800B3T 0x8892 +#define I28F800B3B 0x8893 +#define I28F016S3 0x00aa +#define I28F016B3T 0x00d0 +#define I28F016B3B 0x00d1 +#define I28F160B3T 0x8890 +#define I28F160B3B 0x8891 +#define I28F320B3T 0x8896 +#define I28F320B3B 0x8897 +#define I28F640B3T 0x8898 +#define I28F640B3B 0x8899 +#define I82802AB 0x00ad +#define I82802AC 0x00ac + +/* Macronix */ +#define MX29LV160T 0x22C4 +#define MX29LV160B 0x2249 +#define MX29F016 0x00AD +#define MX29F004T 0x0045 +#define MX29F004B 0x0046 + +/* PMC */ +#define PM49FL002 0x006D +#define PM49FL004 0x006E +#define PM49FL008 0x006A /* ST - www.st.com */ -#define M29W800T 0x00D7 +#define M29W800DT 0x00D7 +#define M29W800DB 0x005B #define M29W160DT 0x22C4 #define M29W160DB 0x2249 +#define M29W040B 0x00E3 /* SST */ +#define SST29EE512 0x005d +#define SST29LE512 0x003d #define SST39LF800 0x2781 #define SST39LF160 0x2782 +#define SST39LF512 0x00D4 +#define SST39LF010 0x00D5 +#define SST39LF020 0x00D6 +#define SST39LF040 0x00D7 +#define SST39SF010A 0x00B5 +#define SST39SF020A 0x00B6 +#define SST49LF030A 0x001C +#define SST49LF040A 0x0051 +#define SST49LF080A 0x005B /* Toshiba */ #define TC58FVT160 0x00C2 #define TC58FVB160 0x0043 +#define TC58FVT321 0x009A +#define TC58FVB321 0x009C +#define TC58FVT641 0x0093 +#define TC58FVB641 0x0095 + +/* Winbond */ +#define W49V002A 0x00b0 + + +/* + * Unlock address sets for AMD command sets. + * Intel command sets use the MTD_UADDR_UNNECESSARY. + * Each identifier, except MTD_UADDR_UNNECESSARY, and + * MTD_UADDR_NO_SUPPORT must be defined below in unlock_addrs[]. + * MTD_UADDR_NOT_SUPPORTED must be 0 so that structure + * initialization need not require initializing all of the + * unlock addresses for all bit widths. + */ +enum uaddr { + MTD_UADDR_NOT_SUPPORTED = 0, /* data width not supported */ + MTD_UADDR_0x0555_0x02AA, + MTD_UADDR_0x0555_0x0AAA, + MTD_UADDR_0x5555_0x2AAA, + MTD_UADDR_0x0AAA_0x0555, + MTD_UADDR_DONT_CARE, /* Requires an arbitrary address */ + MTD_UADDR_UNNECESSARY, /* Does not require any address */ +}; + + +struct unlock_addr { + int addr1; + int addr2; +}; + + +/* + * I don't like the fact that the first entry in unlock_addrs[] + * exists, but is for MTD_UADDR_NOT_SUPPORTED - and, therefore, + * should not be used. The problem is that structures with + * initializers have extra fields initialized to 0. It is _very_ + * desireable to have the unlock address entries for unsupported + * data widths automatically initialized - that means that + * MTD_UADDR_NOT_SUPPORTED must be 0 and the first entry here + * must go unused. + */ +static const struct unlock_addr unlock_addrs[] = { + [MTD_UADDR_NOT_SUPPORTED] = { + .addr1 = 0xffff, + .addr2 = 0xffff + }, + + [MTD_UADDR_0x0555_0x02AA] = { + .addr1 = 0x0555, + .addr2 = 0x02aa + }, + + [MTD_UADDR_0x0555_0x0AAA] = { + .addr1 = 0x0555, + .addr2 = 0x0aaa + }, + + [MTD_UADDR_0x5555_0x2AAA] = { + .addr1 = 0x5555, + .addr2 = 0x2aaa + }, + + [MTD_UADDR_0x0AAA_0x0555] = { + .addr1 = 0x0AAA, + .addr2 = 0x0555 + }, + + [MTD_UADDR_DONT_CARE] = { + .addr1 = 0x0000, /* Doesn't matter which address */ + .addr2 = 0x0000 /* is used - must be last entry */ + } +}; struct amd_flash_info { @@ -64,190 +211,1137 @@ const int DevSize; const int InterfaceDesc; const int NumEraseRegions; + const int CmdSet; + const __u8 uaddr[3]; /* unlock addrs for 8, 16, 32 modes */ const ulong regions[4]; }; #define ERASEINFO(size,blocks) (size<<8)|(blocks-1) -#define SIZE_1MiB 20 -#define SIZE_2MiB 21 -#define SIZE_4MiB 22 +#define SIZE_64KiB 16 +#define SIZE_128KiB 17 +#define SIZE_256KiB 18 +#define SIZE_512KiB 19 +#define SIZE_1MiB 20 +#define SIZE_2MiB 21 +#define SIZE_4MiB 22 +#define SIZE_8MiB 23 + +/* + * Please keep this list ordered by manufacturer! + * Fortunately, the list isn't searched often and so a + * slow, linear search isn't so bad. + */ static const struct amd_flash_info jedec_table[] = { { - .mfr_id = MANUFACTURER_AMD, - .dev_id = AM29LV160DT, - .name = "AMD AM29LV160DT", - .DevSize = SIZE_2MiB, - .NumEraseRegions = 4, - .regions = {ERASEINFO(0x10000,31), - ERASEINFO(0x08000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x04000,1) - } - }, { - .mfr_id = MANUFACTURER_AMD, - .dev_id = AM29LV160DB, - .name = "AMD AM29LV160DB", - .DevSize = SIZE_2MiB, - .NumEraseRegions = 4, - .regions = {ERASEINFO(0x04000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x08000,1), - ERASEINFO(0x10000,31) - } - }, { - .mfr_id = MANUFACTURER_TOSHIBA, - .dev_id = TC58FVT160, - .name = "Toshiba TC58FVT160", - .DevSize = SIZE_2MiB, - .NumEraseRegions = 4, - .regions = {ERASEINFO(0x10000,31), - ERASEINFO(0x08000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x04000,1) - } - }, { - .mfr_id = MANUFACTURER_FUJITSU, - .dev_id = MBM29LV160TE, - .name = "Fujitsu MBM29LV160TE", - .DevSize = SIZE_2MiB, - .NumEraseRegions = 4, - .regions = {ERASEINFO(0x10000,31), - ERASEINFO(0x08000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x04000,1) - } - }, { - .mfr_id = MANUFACTURER_TOSHIBA, - .dev_id = TC58FVB160, - .name = "Toshiba TC58FVB160", - .DevSize = SIZE_2MiB, - .NumEraseRegions = 4, - .regions = {ERASEINFO(0x04000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x08000,1), - ERASEINFO(0x10000,31) - } - }, { - .mfr_id = MANUFACTURER_FUJITSU, - .dev_id = MBM29LV160BE, - .name = "Fujitsu MBM29LV160BE", - .DevSize = SIZE_2MiB, - .NumEraseRegions = 4, - .regions = {ERASEINFO(0x04000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x08000,1), - ERASEINFO(0x10000,31) - } - }, { - .mfr_id = MANUFACTURER_AMD, - .dev_id = AM29LV800BB, - .name = "AMD AM29LV800BB", - .DevSize = SIZE_1MiB, - .NumEraseRegions = 4, - .regions = {ERASEINFO(0x04000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x08000,1), - ERASEINFO(0x10000,15), - } - }, { - .mfr_id = MANUFACTURER_AMD, - .dev_id = AM29F800BB, - .name = "AMD AM29F800BB", - .DevSize = SIZE_1MiB, - .NumEraseRegions = 4, - .regions = {ERASEINFO(0x04000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x08000,1), - ERASEINFO(0x10000,15), - } - }, { - .mfr_id = MANUFACTURER_AMD, - .dev_id = AM29LV800BT, - .name = "AMD AM29LV800BT", - .DevSize = SIZE_1MiB, - .NumEraseRegions = 4, - .regions = {ERASEINFO(0x10000,15), - ERASEINFO(0x08000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x04000,1) - } - }, { - .mfr_id = MANUFACTURER_AMD, - .dev_id = AM29F800BT, - .name = "AMD AM29F800BT", - .DevSize = SIZE_1MiB, - .NumEraseRegions = 4, - .regions = {ERASEINFO(0x10000,15), - ERASEINFO(0x08000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x04000,1) - } - }, { - .mfr_id = MANUFACTURER_AMD, - .dev_id = AM29LV800BB, - .name = "AMD AM29LV800BB", - .DevSize = SIZE_1MiB, - .NumEraseRegions = 4, - .regions = {ERASEINFO(0x10000,15), - ERASEINFO(0x08000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x04000,1) - } - }, { - .mfr_id = MANUFACTURER_ST, - .dev_id = M29W800T, - .name = "ST M29W800T", - .DevSize = SIZE_1MiB, - .NumEraseRegions = 4, - .regions = {ERASEINFO(0x10000,15), - ERASEINFO(0x08000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x04000,1) - } - }, { - .mfr_id = MANUFACTURER_ST, - .dev_id = M29W160DT, - .name = "ST M29W160DT", - .DevSize = SIZE_2MiB, - .NumEraseRegions = 4, - .regions = {ERASEINFO(0x10000,31), - ERASEINFO(0x08000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x04000,1) - } - }, { - .mfr_id = MANUFACTURER_ST, - .dev_id = M29W160DB, - .name = "ST M29W160DB", - .DevSize = SIZE_2MiB, - .NumEraseRegions = 4, - .regions = {ERASEINFO(0x04000,1), - ERASEINFO(0x02000,2), - ERASEINFO(0x08000,1), - ERASEINFO(0x10000,31) - } - }, { - .mfr_id = MANUFACTURER_ATMEL, - .dev_id = AT49BV16X4, - .name = "Atmel AT49BV16X4", - .DevSize = SIZE_2MiB, - .NumEraseRegions = 3, - .regions = {ERASEINFO(0x02000,8), - ERASEINFO(0x08000,2), - ERASEINFO(0x10000,30) - } - }, { - .mfr_id = MANUFACTURER_ATMEL, - .dev_id = AT49BV16X4T, - .name = "Atmel AT49BV16X4T", - .DevSize = SIZE_2MiB, - .NumEraseRegions = 3, - .regions = {ERASEINFO(0x10000,30), - ERASEINFO(0x08000,2), - ERASEINFO(0x02000,8) - } + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29F032B, + .name = "AMD AM29F032B", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ + }, + .DevSize = SIZE_4MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000,64) + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29LV160DT, + .name = "AMD AM29LV160DT", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x10000,31), + ERASEINFO(0x08000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x04000,1) + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29LV160DB, + .name = "AMD AM29LV160DB", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x04000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x08000,1), + ERASEINFO(0x10000,31) + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29LV800BB, + .name = "AMD AM29LV800BB", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x04000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x08000,1), + ERASEINFO(0x10000,15), + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29F800BB, + .name = "AMD AM29F800BB", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x04000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x08000,1), + ERASEINFO(0x10000,15), + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29LV800BT, + .name = "AMD AM29LV800BT", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x10000,15), + ERASEINFO(0x08000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x04000,1) + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29F800BT, + .name = "AMD AM29F800BT", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x10000,15), + ERASEINFO(0x08000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x04000,1) + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29F017D, + .name = "AMD AM29F017D", + .uaddr = { + [0] = MTD_UADDR_DONT_CARE /* x8 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000,32), + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29F016D, + .name = "AMD AM29F016D", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000,32), + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29F080, + .name = "AMD AM29F080", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000,16), + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29F040, + .name = "AMD AM29F040", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000,8), + } + }, { + .mfr_id = MANUFACTURER_AMD, + .dev_id = AM29LV040B, + .name = "AMD AM29LV040B", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000,8), + } + }, { + .mfr_id = MANUFACTURER_ATMEL, + .dev_id = AT49BV512, + .name = "Atmel AT49BV512", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ + }, + .DevSize = SIZE_64KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000,1) + } + }, { + .mfr_id = MANUFACTURER_ATMEL, + .dev_id = AT29LV512, + .name = "Atmel AT29LV512", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ + }, + .DevSize = SIZE_64KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x80,256), + ERASEINFO(0x80,256) + } + }, { + .mfr_id = MANUFACTURER_ATMEL, + .dev_id = AT49BV16X, + .name = "Atmel AT49BV16X", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x0AAA, /* x8 */ + [1] = MTD_UADDR_0x0555_0x0AAA /* x16 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x02000,8), + ERASEINFO(0x10000,31) + } + }, { + .mfr_id = MANUFACTURER_ATMEL, + .dev_id = AT49BV16XT, + .name = "Atmel AT49BV16XT", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x0AAA, /* x8 */ + [1] = MTD_UADDR_0x0555_0x0AAA /* x16 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x10000,31), + ERASEINFO(0x02000,8) + } + }, { + .mfr_id = MANUFACTURER_ATMEL, + .dev_id = AT49BV32X, + .name = "Atmel AT49BV32X", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x0AAA, /* x8 */ + [1] = MTD_UADDR_0x0555_0x0AAA /* x16 */ + }, + .DevSize = SIZE_4MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x02000,8), + ERASEINFO(0x10000,63) + } + }, { + .mfr_id = MANUFACTURER_ATMEL, + .dev_id = AT49BV32XT, + .name = "Atmel AT49BV32XT", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x0AAA, /* x8 */ + [1] = MTD_UADDR_0x0555_0x0AAA /* x16 */ + }, + .DevSize = SIZE_4MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x10000,63), + ERASEINFO(0x02000,8) + } + }, { + .mfr_id = MANUFACTURER_FUJITSU, + .dev_id = MBM29LV650UE, + .name = "Fujitsu MBM29LV650UE", + .uaddr = { + [0] = MTD_UADDR_DONT_CARE /* x16 */ + }, + .DevSize = SIZE_8MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000,128) + } + }, { + .mfr_id = MANUFACTURER_FUJITSU, + .dev_id = MBM29LV320TE, + .name = "Fujitsu MBM29LV320TE", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_4MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x10000,63), + ERASEINFO(0x02000,8) + } + }, { + .mfr_id = MANUFACTURER_FUJITSU, + .dev_id = MBM29LV320BE, + .name = "Fujitsu MBM29LV320BE", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_4MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x02000,8), + ERASEINFO(0x10000,63) + } + }, { + .mfr_id = MANUFACTURER_FUJITSU, + .dev_id = MBM29LV160TE, + .name = "Fujitsu MBM29LV160TE", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x10000,31), + ERASEINFO(0x08000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x04000,1) + } + }, { + .mfr_id = MANUFACTURER_FUJITSU, + .dev_id = MBM29LV160BE, + .name = "Fujitsu MBM29LV160BE", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x04000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x08000,1), + ERASEINFO(0x10000,31) + } + }, { + .mfr_id = MANUFACTURER_FUJITSU, + .dev_id = MBM29LV800BA, + .name = "Fujitsu MBM29LV800BA", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x04000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x08000,1), + ERASEINFO(0x10000,15) + } + }, { + .mfr_id = MANUFACTURER_FUJITSU, + .dev_id = MBM29LV800TA, + .name = "Fujitsu MBM29LV800TA", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x10000,15), + ERASEINFO(0x08000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x04000,1) + } + }, { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F004B3B, + .name = "Intel 28F004B3B", + .uaddr = { + [0] = MTD_UADDR_UNNECESSARY, /* x8 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x02000, 8), + ERASEINFO(0x10000, 7), + } + }, { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F004B3T, + .name = "Intel 28F004B3T", + .uaddr = { + [0] = MTD_UADDR_UNNECESSARY, /* x8 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x10000, 7), + ERASEINFO(0x02000, 8), + } + }, { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F400B3B, + .name = "Intel 28F400B3B", + .uaddr = { + [0] = MTD_UADDR_UNNECESSARY, /* x8 */ + [1] = MTD_UADDR_UNNECESSARY, /* x16 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x02000, 8), + ERASEINFO(0x10000, 7), + } + }, { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F400B3T, + .name = "Intel 28F400B3T", + .uaddr = { + [0] = MTD_UADDR_UNNECESSARY, /* x8 */ + [1] = MTD_UADDR_UNNECESSARY, /* x16 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x10000, 7), + ERASEINFO(0x02000, 8), + } + }, { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F008B3B, + .name = "Intel 28F008B3B", + .uaddr = { + [0] = MTD_UADDR_UNNECESSARY, /* x8 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x02000, 8), + ERASEINFO(0x10000, 15), + } + }, { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F008B3T, + .name = "Intel 28F008B3T", + .uaddr = { + [0] = MTD_UADDR_UNNECESSARY, /* x8 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x10000, 15), + ERASEINFO(0x02000, 8), + } + }, { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F008S5, + .name = "Intel 28F008S5", + .uaddr = { + [0] = MTD_UADDR_UNNECESSARY, /* x8 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_INTEL_EXT, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000,16), + } + }, { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F016S5, + .name = "Intel 28F016S5", + .uaddr = { + [0] = MTD_UADDR_UNNECESSARY, /* x8 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_INTEL_EXT, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000,32), + } + }, { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F008SA, + .name = "Intel 28F008SA", + .uaddr = { + [0] = MTD_UADDR_UNNECESSARY, /* x8 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000, 16), + } + }, { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F800B3B, + .name = "Intel 28F800B3B", + .uaddr = { + [1] = MTD_UADDR_UNNECESSARY, /* x16 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x02000, 8), + ERASEINFO(0x10000, 15), + } + }, { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F800B3T, + .name = "Intel 28F800B3T", + .uaddr = { + [1] = MTD_UADDR_UNNECESSARY, /* x16 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x10000, 15), + ERASEINFO(0x02000, 8), + } + }, { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F016B3B, + .name = "Intel 28F016B3B", + .uaddr = { + [0] = MTD_UADDR_UNNECESSARY, /* x8 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x02000, 8), + ERASEINFO(0x10000, 31), + } + }, { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F016S3, + .name = "Intel I28F016S3", + .uaddr = { + [0] = MTD_UADDR_UNNECESSARY, /* x8 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000, 32), + } + }, { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F016B3T, + .name = "Intel 28F016B3T", + .uaddr = { + [0] = MTD_UADDR_UNNECESSARY, /* x8 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x10000, 31), + ERASEINFO(0x02000, 8), + } + }, { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F160B3B, + .name = "Intel 28F160B3B", + .uaddr = { + [1] = MTD_UADDR_UNNECESSARY, /* x16 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x02000, 8), + ERASEINFO(0x10000, 31), + } + }, { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F160B3T, + .name = "Intel 28F160B3T", + .uaddr = { + [1] = MTD_UADDR_UNNECESSARY, /* x16 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x10000, 31), + ERASEINFO(0x02000, 8), + } + }, { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F320B3B, + .name = "Intel 28F320B3B", + .uaddr = { + [1] = MTD_UADDR_UNNECESSARY, /* x16 */ + }, + .DevSize = SIZE_4MiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x02000, 8), + ERASEINFO(0x10000, 63), + } + }, { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F320B3T, + .name = "Intel 28F320B3T", + .uaddr = { + [1] = MTD_UADDR_UNNECESSARY, /* x16 */ + }, + .DevSize = SIZE_4MiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x10000, 63), + ERASEINFO(0x02000, 8), + } + }, { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F640B3B, + .name = "Intel 28F640B3B", + .uaddr = { + [1] = MTD_UADDR_UNNECESSARY, /* x16 */ + }, + .DevSize = SIZE_8MiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x02000, 8), + ERASEINFO(0x10000, 127), + } + }, { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I28F640B3T, + .name = "Intel 28F640B3T", + .uaddr = { + [1] = MTD_UADDR_UNNECESSARY, /* x16 */ + }, + .DevSize = SIZE_8MiB, + .CmdSet = P_ID_INTEL_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x10000, 127), + ERASEINFO(0x02000, 8), + } + }, { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I82802AB, + .name = "Intel 82802AB", + .uaddr = { + [0] = MTD_UADDR_UNNECESSARY, /* x8 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_INTEL_EXT, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000,8), + } + }, { + .mfr_id = MANUFACTURER_INTEL, + .dev_id = I82802AC, + .name = "Intel 82802AC", + .uaddr = { + [0] = MTD_UADDR_UNNECESSARY, /* x8 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_INTEL_EXT, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000,16), + } + }, { + .mfr_id = MANUFACTURER_MACRONIX, + .dev_id = MX29LV160T, + .name = "MXIC MX29LV160T", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x10000,31), + ERASEINFO(0x08000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x04000,1) + } + }, { + .mfr_id = MANUFACTURER_MACRONIX, + .dev_id = MX29LV160B, + .name = "MXIC MX29LV160B", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x04000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x08000,1), + ERASEINFO(0x10000,31) + } + }, { + .mfr_id = MANUFACTURER_MACRONIX, + .dev_id = MX29F016, + .name = "Macronix MX29F016", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000,32), + } + }, { + .mfr_id = MANUFACTURER_MACRONIX, + .dev_id = MX29F004T, + .name = "Macronix MX29F004T", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x10000,7), + ERASEINFO(0x08000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x04000,1), + } + }, { + .mfr_id = MANUFACTURER_MACRONIX, + .dev_id = MX29F004B, + .name = "Macronix MX29F004B", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x04000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x08000,1), + ERASEINFO(0x10000,7), + } + }, { + .mfr_id = MANUFACTURER_PMC, + .dev_id = PM49FL002, + .name = "PMC Pm49FL002", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ + }, + .DevSize = SIZE_256KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO( 0x01000, 64 ) + } + }, { + .mfr_id = MANUFACTURER_PMC, + .dev_id = PM49FL004, + .name = "PMC Pm49FL004", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO( 0x01000, 128 ) + } + }, { + .mfr_id = MANUFACTURER_PMC, + .dev_id = PM49FL008, + .name = "PMC Pm49FL008", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO( 0x01000, 256 ) + } + }, { + .mfr_id = MANUFACTURER_SST, + .dev_id = SST39LF512, + .name = "SST 39LF512", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ + }, + .DevSize = SIZE_64KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x01000,16), + } + }, { + .mfr_id = MANUFACTURER_SST, + .dev_id = SST39LF010, + .name = "SST 39LF010", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ + }, + .DevSize = SIZE_128KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x01000,32), + } + }, { + .mfr_id = MANUFACTURER_SST, + .dev_id = SST39LF020, + .name = "SST 39LF020", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ + }, + .DevSize = SIZE_256KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x01000,64), + } + }, { + .mfr_id = MANUFACTURER_SST, + .dev_id = SST39LF040, + .name = "SST 39LF040", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x01000,128), + } + }, { + .mfr_id = MANUFACTURER_SST, + .dev_id = SST39SF010A, + .name = "SST 39SF010A", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ + }, + .DevSize = SIZE_128KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x01000,32), + } + }, { + .mfr_id = MANUFACTURER_SST, + .dev_id = SST39SF020A, + .name = "SST 39SF020A", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ + }, + .DevSize = SIZE_256KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x01000,64), + } + }, { + .mfr_id = MANUFACTURER_SST, + .dev_id = SST49LF030A, + .name = "SST 49LF030A", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x01000,96), + } + }, { + .mfr_id = MANUFACTURER_SST, + .dev_id = SST49LF040A, + .name = "SST 49LF040A", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x01000,128), + } + }, { + .mfr_id = MANUFACTURER_SST, + .dev_id = SST49LF080A, + .name = "SST 49LF080A", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x01000,256), + } + }, { + .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */ + .dev_id = M29W800DT, + .name = "ST M29W800DT", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA, /* x8 */ + [1] = MTD_UADDR_0x5555_0x2AAA /* x16 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x10000,15), + ERASEINFO(0x08000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x04000,1) + } + }, { + .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */ + .dev_id = M29W800DB, + .name = "ST M29W800DB", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA, /* x8 */ + [1] = MTD_UADDR_0x5555_0x2AAA /* x16 */ + }, + .DevSize = SIZE_1MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x04000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x08000,1), + ERASEINFO(0x10000,15) + } + }, { + .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */ + .dev_id = M29W160DT, + .name = "ST M29W160DT", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x02AA, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x10000,31), + ERASEINFO(0x08000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x04000,1) + } + }, { + .mfr_id = MANUFACTURER_ST, /* FIXME - CFI device? */ + .dev_id = M29W160DB, + .name = "ST M29W160DB", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x02AA, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x04000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x08000,1), + ERASEINFO(0x10000,31) + } + }, { + .mfr_id = MANUFACTURER_ST, + .dev_id = M29W040B, + .name = "ST M29W040B", + .uaddr = { + [0] = MTD_UADDR_0x0555_0x02AA /* x8 */ + }, + .DevSize = SIZE_512KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 1, + .regions = { + ERASEINFO(0x10000,8), + } + }, { + .mfr_id = MANUFACTURER_TOSHIBA, + .dev_id = TC58FVT160, + .name = "Toshiba TC58FVT160", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x10000,31), + ERASEINFO(0x08000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x04000,1) + } + }, { + .mfr_id = MANUFACTURER_TOSHIBA, + .dev_id = TC58FVB160, + .name = "Toshiba TC58FVB160", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ + }, + .DevSize = SIZE_2MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x04000,1), + ERASEINFO(0x02000,2), + ERASEINFO(0x08000,1), + ERASEINFO(0x10000,31) + } + }, { + .mfr_id = MANUFACTURER_TOSHIBA, + .dev_id = TC58FVB321, + .name = "Toshiba TC58FVB321", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ + }, + .DevSize = SIZE_4MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x02000,8), + ERASEINFO(0x10000,63) + } + }, { + .mfr_id = MANUFACTURER_TOSHIBA, + .dev_id = TC58FVT321, + .name = "Toshiba TC58FVT321", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA /* x16 */ + }, + .DevSize = SIZE_4MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x10000,63), + ERASEINFO(0x02000,8) + } + }, { + .mfr_id = MANUFACTURER_TOSHIBA, + .dev_id = TC58FVB641, + .name = "Toshiba TC58FVB641", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_8MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x02000,8), + ERASEINFO(0x10000,127) + } + }, { + .mfr_id = MANUFACTURER_TOSHIBA, + .dev_id = TC58FVT641, + .name = "Toshiba TC58FVT641", + .uaddr = { + [0] = MTD_UADDR_0x0AAA_0x0555, /* x8 */ + [1] = MTD_UADDR_0x0555_0x02AA, /* x16 */ + }, + .DevSize = SIZE_8MiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 2, + .regions = { + ERASEINFO(0x10000,127), + ERASEINFO(0x02000,8) + } + }, { + .mfr_id = MANUFACTURER_WINBOND, + .dev_id = W49V002A, + .name = "Winbond W49V002A", + .uaddr = { + [0] = MTD_UADDR_0x5555_0x2AAA /* x8 */ + }, + .DevSize = SIZE_256KiB, + .CmdSet = P_ID_AMD_STD, + .NumEraseRegions= 4, + .regions = { + ERASEINFO(0x10000, 3), + ERASEINFO(0x08000, 1), + ERASEINFO(0x02000, 2), + ERASEINFO(0x04000, 1), + } } }; @@ -258,12 +1352,70 @@ struct flchip *chips, struct cfi_private *cfi); struct mtd_info *jedec_probe(struct map_info *map); -#define jedec_read_mfr(map, base, osf) cfi_read(map, base) -#define jedec_read_id(map, base, osf) cfi_read(map, (base)+(osf)) + +static inline u32 jedec_read_mfr(struct map_info *map, __u32 base, + struct cfi_private *cfi) +{ + u32 result, mask; + mask = (1 << (cfi->device_type * 8)) -1; + result = cfi_read(map, base); + result &= mask; + return result; +} + +static inline u32 jedec_read_id(struct map_info *map, __u32 base, + struct cfi_private *cfi) +{ + int osf; + u32 result, mask; + osf = cfi->interleave *cfi->device_type; + mask = (1 << (cfi->device_type * 8)) -1; + result = cfi_read(map, base + osf); + result &= mask; + return result; +} + +static inline void jedec_reset(u32 base, struct map_info *map, + struct cfi_private *cfi) +{ + /* Reset */ + cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); + /* Some misdesigned intel chips do not respond for 0xF0 for a reset, + * so ensure we're in read mode. Send both the Intel and the AMD command + * for this. Intel uses 0xff for this, AMD uses 0xff for NOP, so + * this should be safe. + */ + cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); + /* FIXME - should have reset delay before continuing */ +} + + +static inline __u8 finfo_uaddr(const struct amd_flash_info *finfo, int device_type) +{ + int uaddr_idx; + __u8 uaddr = MTD_UADDR_NOT_SUPPORTED; + + switch ( device_type ) { + case CFI_DEVICETYPE_X8: uaddr_idx = 0; break; + case CFI_DEVICETYPE_X16: uaddr_idx = 1; break; + case CFI_DEVICETYPE_X32: uaddr_idx = 2; break; + default: + printk(KERN_NOTICE "MTD: %s(): unknown device_type %d\n", + __func__, device_type); + goto uaddr_done; + } + + uaddr = finfo->uaddr[uaddr_idx]; + + uaddr_done: + return uaddr; +} + static int cfi_jedec_setup(struct cfi_private *p_cfi, int index) { int i,num_erase_regions; + __u8 uaddr; printk("Found: %s\n",jedec_table[index].name); @@ -276,29 +1428,142 @@ } memset(p_cfi->cfiq,0,sizeof(struct cfi_ident)); - - p_cfi->cfiq->P_ID = P_ID_AMD_STD; + + p_cfi->cfiq->P_ID = jedec_table[index].CmdSet; p_cfi->cfiq->NumEraseRegions = jedec_table[index].NumEraseRegions; p_cfi->cfiq->DevSize = jedec_table[index].DevSize; + p_cfi->cfi_mode = CFI_MODE_JEDEC; for (i=0; i<num_erase_regions; i++){ p_cfi->cfiq->EraseRegionInfo[i] = jedec_table[index].regions[i]; - } + } + p_cfi->cmdset_priv = 0; + + /* This may be redundant for some cases, but it doesn't hurt */ + p_cfi->mfr = jedec_table[index].mfr_id; + p_cfi->id = jedec_table[index].dev_id; + + uaddr = finfo_uaddr(&jedec_table[index], p_cfi->device_type); + if ( MTD_UADDR_NOT_SUPPORTED ) { + kfree( p_cfi->cfiq ); + return 0; + } + p_cfi->addr_unlock1 = unlock_addrs[uaddr].addr1; + p_cfi->addr_unlock2 = unlock_addrs[uaddr].addr2; + return 1; /* ok */ } + +/* + * There is a BIG problem properly ID'ing the JEDEC devic and guaranteeing + * the mapped address, unlock addresses, and proper chip ID. This function + * attempts to minimize errors. It is doubtfull that this probe will ever + * be perfect - consequently there should be some module parameters that + * could be manually specified to force the chip info. + */ +static inline int jedec_match( __u32 base, + struct map_info *map, + struct cfi_private *cfi, + const struct amd_flash_info *finfo ) +{ + int rc = 0; /* failure until all tests pass */ + u32 mfr, id; + __u8 uaddr; + + /* The ID's must match */ + if ( cfi->mfr != finfo->mfr_id || cfi->id != finfo->dev_id ) { + goto match_done; + } + + /* the part size must fit in the memory window */ + DEBUG( MTD_DEBUG_LEVEL3, + "MTD %s(): Check fit 0x%.8x + 0x%.8x = 0x%.8x\n", + __func__, base, 1 << finfo->DevSize, base + (1 << finfo->DevSize) ); + if ( base + ( 1 << finfo->DevSize ) > map->size ) { + DEBUG( MTD_DEBUG_LEVEL3, + "MTD %s(): 0x%.4x 0x%.4x %dKiB doesn't fit\n", + __func__, finfo->mfr_id, finfo->dev_id, + 1 << finfo->DevSize ); + goto match_done; + } + + uaddr = finfo_uaddr(finfo, cfi->device_type); + if ( MTD_UADDR_NOT_SUPPORTED ) { + goto match_done; + } + + DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): check unlock addrs 0x%.4x 0x%.4x\n", + __func__, cfi->addr_unlock1, cfi->addr_unlock2 ); + if ( MTD_UADDR_UNNECESSARY != uaddr && MTD_UADDR_DONT_CARE != uaddr + && ( unlock_addrs[uaddr].addr1 != cfi->addr_unlock1 + || unlock_addrs[uaddr].addr2 != cfi->addr_unlock2 ) ) { + DEBUG( MTD_DEBUG_LEVEL3, + "MTD %s(): 0x%.4x 0x%.4x did not match\n", + __func__, + unlock_addrs[uaddr].addr1, + unlock_addrs[uaddr].addr2 ); + goto match_done; + } + + /* + * Make sure the ID's dissappear when the device is taken out of + * ID mode. The only time this should fail when it should succeed + * is when the ID's are written as data to the same + * addresses. For this rare and unfortunate case the chip + * cannot be probed correctly. + * FIXME - write a driver that takes all of the chip info as + * module parameters, doesn't probe but forces a load. + */ + DEBUG( MTD_DEBUG_LEVEL3, + "MTD %s(): check ID's disappear when not in ID mode\n", + __func__ ); + jedec_reset( base, map, cfi ); + mfr = jedec_read_mfr( map, base, cfi ); + id = jedec_read_id( map, base, cfi ); + if ( mfr == cfi->mfr && id == cfi->id ) { + DEBUG( MTD_DEBUG_LEVEL3, + "MTD %s(): ID 0x%.2x:0x%.2x did not change after reset:\n" + "You might need to manually specify JEDEC parameters.\n", + __func__, cfi->mfr, cfi->id ); + goto match_done; + } + + /* all tests passed - mark as success */ + rc = 1; + + /* + * Put the device back in ID mode - only need to do this if we + * were truly frobbing a real device. + */ + DEBUG( MTD_DEBUG_LEVEL3, "MTD %s(): return to ID mode\n", __func__ ); + if(cfi->addr_unlock1) { + cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, CFI_DEVICETYPE_X8, NULL); + } + cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL); + /* FIXME - should have a delay before continuing */ + + match_done: + return rc; +} + + static int jedec_probe_chip(struct map_info *map, __u32 base, struct flchip *chips, struct cfi_private *cfi) { int i; - int osf = cfi->interleave * cfi->device_type; - int retried = 0; + int unlockpass = 0; + /* + * FIXME - eventually replace these unlock address seeds with + * information from unlock_addrs[]. + */ if (!cfi->numchips) { switch (cfi->device_type) { case CFI_DEVICETYPE_X8: - cfi->addr_unlock1 = 0x555; - cfi->addr_unlock2 = 0x2aa; + cfi->addr_unlock1 = 0x555; + cfi->addr_unlock2 = 0x2aa; break; case CFI_DEVICETYPE_X16: cfi->addr_unlock1 = 0xaaa; @@ -320,48 +1585,98 @@ } retry: + /* Make certain we aren't probing past the end of map */ + if (base >= map->size) { + printk(KERN_NOTICE + "Probe at base(0x%08x) past the end of the map(0x%08lx)\n", + base, map->size -1); + return 0; + + } + if ((base + cfi->addr_unlock1) >= map->size) { + printk(KERN_NOTICE + "Probe at addr_unlock1(0x%08x + 0x%08x) past the end of the map(0x%08lx)\n", + base, cfi->addr_unlock1, map->size -1); + + return 0; + } + if ((base + cfi->addr_unlock2) >= map->size) { + printk(KERN_NOTICE + "Probe at addr_unlock2(0x%08x + 0x%08x) past the end of the map(0x%08lx)\n", + base, cfi->addr_unlock2, map->size -1); + return 0; + + } + /* Reset */ - cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); + jedec_reset(base, map, cfi); /* Autoselect Mode */ - cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL); - cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, CFI_DEVICETYPE_X8, NULL); + if(cfi->addr_unlock1) { + cfi_send_gen_cmd(0xaa, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL); + cfi_send_gen_cmd(0x55, cfi->addr_unlock2, base, map, cfi, CFI_DEVICETYPE_X8, NULL); + } cfi_send_gen_cmd(0x90, cfi->addr_unlock1, base, map, cfi, CFI_DEVICETYPE_X8, NULL); + /* FIXME - should have a delay before continuing */ if (!cfi->numchips) { /* This is the first time we're called. Set up the CFI stuff accordingly and return */ - cfi->mfr = jedec_read_mfr(map, base, osf); - cfi->id = jedec_read_id(map, base, osf); - + cfi->mfr = jedec_read_mfr(map, base, cfi); + cfi->id = jedec_read_id(map, base, cfi); + printk(KERN_INFO "Search for id:(%02x %02x) interleave(%d) type(%d)\n", + cfi->mfr, cfi->id, cfi->interleave, cfi->device_type); for (i=0; i<sizeof(jedec_table)/sizeof(jedec_table[0]); i++) { - if (cfi->mfr == jedec_table[i].mfr_id && - cfi->id == jedec_table[i].dev_id) - return cfi_jedec_setup(cfi, i); - } - if (!retried++) { - /* Deal with whichever strange chips these were */ - cfi->addr_unlock1 |= cfi->addr_unlock1 << 8; - cfi->addr_unlock2 |= cfi->addr_unlock2 << 8; + if ( jedec_match( base, map, cfi, &jedec_table[i] ) ) { + DEBUG( MTD_DEBUG_LEVEL3, + "MTD %s(): matched device 0x%x,0x%x unlock_addrs: 0x%.4x 0x%.4x\n", + __func__, cfi->mfr, cfi->id, + cfi->addr_unlock1, cfi->addr_unlock2 ); + if (!cfi_jedec_setup(cfi, i)) + return 0; + goto ok_out; + } + } + switch(unlockpass++) { + case 0: + cfi->addr_unlock1 |= cfi->addr_unlock1 << 4; + cfi->addr_unlock2 |= cfi->addr_unlock2 << 4; + goto retry; + case 1: + cfi->addr_unlock1 = cfi->addr_unlock2 = 0; goto retry; } return 0; + } else { + __u16 mfr; + __u16 id; + + /* Make sure it is a chip of the same manufacturer and id */ + mfr = jedec_read_mfr(map, base, cfi); + id = jedec_read_id(map, base, cfi); + + if ((mfr != cfi->mfr) || (id != cfi->id)) { + printk(KERN_DEBUG "%s: Found different chip or no chip at all (mfr 0x%x, id 0x%x) at 0x%x\n", + map->name, mfr, id, base); + jedec_reset(base, map, cfi); + return 0; + } } /* Check each previous chip to see if it's an alias */ for (i=0; i<cfi->numchips; i++) { /* This chip should be in read mode if it's one we've already touched. */ - if (jedec_read_mfr(map, base, osf) == cfi->mfr && - jedec_read_id(map, base, osf) == cfi->id) { + if (jedec_read_mfr(map, chips[i].start, cfi) == cfi->mfr && + jedec_read_id(map, chips[i].start, cfi) == cfi->id) { /* Eep. This chip also looks like it's in autoselect mode. Is it an alias for the new one? */ - - cfi_send_gen_cmd(0xF0, 0, chips[i].start, map, cfi, cfi->device_type, NULL); + jedec_reset(chips[i].start, map, cfi); + /* If the device IDs go away, it's an alias */ - if (jedec_read_mfr(map, base, osf) != cfi->mfr || - jedec_read_id(map, base, osf) != cfi->id) { + if (jedec_read_mfr(map, base, cfi) != cfi->mfr || + jedec_read_id(map, base, cfi) != cfi->id) { printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n", map->name, base, chips[i].start); return 0; @@ -371,9 +1686,9 @@ * unfortunate. Stick the new chip in read mode * too and if it's the same, assume it's an alias. */ /* FIXME: Use other modes to do a proper check */ - cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); - if (jedec_read_mfr(map, base, osf) == cfi->mfr && - jedec_read_id(map, base, osf) == cfi->id) { + jedec_reset(base, map, cfi); + if (jedec_read_mfr(map, base, cfi) == cfi->mfr && + jedec_read_id(map, base, cfi) == cfi->id) { printk(KERN_DEBUG "%s: Found an alias at 0x%x for the chip at 0x%lx\n", map->name, base, chips[i].start); return 0; @@ -392,8 +1707,9 @@ chips[cfi->numchips].state = FL_READY; cfi->numchips++; +ok_out: /* Put it back into Read Mode */ - cfi_send_gen_cmd(0xF0, 0, base, map, cfi, cfi->device_type, NULL); + jedec_reset(base, map, cfi); printk(KERN_INFO "%s: Found %d x%d devices at 0x%x in %d-bit mode\n", map->name, cfi->interleave, cfi->device_type*8, base, diff -Nru a/drivers/mtd/chips/map_absent.c b/drivers/mtd/chips/map_absent.c --- a/drivers/mtd/chips/map_absent.c Mon Jun 9 23:16:15 2003 +++ b/drivers/mtd/chips/map_absent.c Mon Jun 9 23:16:15 2003 @@ -1,7 +1,7 @@ /* * Common code to handle absent "placeholder" devices * Copyright 2001 Resilience Corporation <ebrower@resilience.com> - * $Id: map_absent.c,v 1.2 2001/10/02 15:05:12 dwmw2 Exp $ + * $Id: map_absent.c,v 1.4 2003/05/28 12:51:49 dwmw2 Exp $ * * This map driver is used to allocate "placeholder" MTD * devices on systems that have socketed/removable media. @@ -23,9 +23,10 @@ #include <linux/kernel.h> #include <linux/errno.h> #include <linux/slab.h> - +#include <linux/init.h> +#include <linux/mtd/mtd.h> #include <linux/mtd/map.h> - +#include <linux/mtd/compatmac.h> static int map_absent_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); static int map_absent_write (struct mtd_info *, loff_t, size_t, size_t *, const u_char *); @@ -36,10 +37,10 @@ static struct mtd_chip_driver map_absent_chipdrv = { - .probe = map_absent_probe, + .probe = map_absent_probe, .destroy = map_absent_destroy, - .name = "map_absent", - .module = THIS_MODULE + .name = "map_absent", + .module = THIS_MODULE }; static struct mtd_info *map_absent_probe(struct map_info *map) @@ -65,7 +66,7 @@ mtd->flags = 0; mtd->erasesize = PAGE_SIZE; - MOD_INC_USE_COUNT; + __module_get(THIS_MODULE); return mtd; } diff -Nru a/drivers/mtd/chips/map_ram.c b/drivers/mtd/chips/map_ram.c --- a/drivers/mtd/chips/map_ram.c Mon Jun 9 23:16:09 2003 +++ b/drivers/mtd/chips/map_ram.c Mon Jun 9 23:16:09 2003 @@ -1,7 +1,7 @@ /* * Common code to handle map devices which are simple RAM * (C) 2000 Red Hat. GPL'd. - * $Id: map_ram.c,v 1.14 2001/10/02 15:05:12 dwmw2 Exp $ + * $Id: map_ram.c,v 1.17 2003/05/28 12:51:49 dwmw2 Exp $ */ #include <linux/module.h> @@ -11,8 +11,10 @@ #include <asm/byteorder.h> #include <linux/errno.h> #include <linux/slab.h> - +#include <linux/init.h> +#include <linux/mtd/mtd.h> #include <linux/mtd/map.h> +#include <linux/mtd/compatmac.h> static int mapram_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); @@ -34,21 +36,21 @@ /* Check the first byte is RAM */ #if 0 - map->write8(map, 0x55, 0); - if (map->read8(map, 0) != 0x55) + map_write8(map, 0x55, 0); + if (map_read8(map, 0) != 0x55) return NULL; - map->write8(map, 0xAA, 0); - if (map->read8(map, 0) != 0xAA) + map_write8(map, 0xAA, 0); + if (map_read8(map, 0) != 0xAA) return NULL; /* Check the last byte is RAM */ - map->write8(map, 0x55, map->size-1); - if (map->read8(map, map->size-1) != 0x55) + map_write8(map, 0x55, map->size-1); + if (map_read8(map, map->size-1) != 0x55) return NULL; - map->write8(map, 0xAA, map->size-1); - if (map->read8(map, map->size-1) != 0xAA) + map_write8(map, 0xAA, map->size-1); + if (map_read8(map, map->size-1) != 0xAA) return NULL; #endif /* OK. It seems to be RAM. */ @@ -74,7 +76,7 @@ while(mtd->size & (mtd->erasesize - 1)) mtd->erasesize >>= 1; - MOD_INC_USE_COUNT; + __module_get(THIS_MODULE); return mtd; } @@ -83,7 +85,7 @@ { struct map_info *map = (struct map_info *)mtd->priv; - map->copy_from(map, buf, from, len); + map_copy_from(map, buf, from, len); *retlen = len; return 0; } @@ -92,7 +94,7 @@ { struct map_info *map = (struct map_info *)mtd->priv; - map->copy_to(map, to, buf, len); + map_copy_to(map, to, buf, len); *retlen = len; return 0; } @@ -105,7 +107,7 @@ unsigned long i; for (i=0; i<instr->len; i++) - map->write8(map, 0xFF, instr->addr + i); + map_write8(map, 0xFF, instr->addr + i); if (instr->callback) instr->callback(instr); diff -Nru a/drivers/mtd/chips/map_rom.c b/drivers/mtd/chips/map_rom.c --- a/drivers/mtd/chips/map_rom.c Mon Jun 9 23:16:14 2003 +++ b/drivers/mtd/chips/map_rom.c Mon Jun 9 23:16:14 2003 @@ -1,7 +1,7 @@ /* * Common code to handle map devices which are simple ROM * (C) 2000 Red Hat. GPL'd. - * $Id: map_rom.c,v 1.17 2001/10/02 15:05:12 dwmw2 Exp $ + * $Id: map_rom.c,v 1.20 2003/05/28 12:51:49 dwmw2 Exp $ */ #include <linux/version.h> @@ -12,8 +12,10 @@ #include <asm/byteorder.h> #include <linux/errno.h> #include <linux/slab.h> - +#include <linux/init.h> +#include <linux/mtd/mtd.h> #include <linux/mtd/map.h> +#include <linux/mtd/compatmac.h> static int maprom_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *); static int maprom_write (struct mtd_info *, loff_t, size_t, size_t *, const u_char *); @@ -49,7 +51,7 @@ while(mtd->size & (mtd->erasesize - 1)) mtd->erasesize >>= 1; - MOD_INC_USE_COUNT; + __module_get(THIS_MODULE); return mtd; } @@ -58,7 +60,7 @@ { struct map_info *map = (struct map_info *)mtd->priv; - map->copy_from(map, buf, from, len); + map_copy_from(map, buf, from, len); *retlen = len; return 0; } diff -Nru a/drivers/mtd/chips/sharp.c b/drivers/mtd/chips/sharp.c --- a/drivers/mtd/chips/sharp.c Mon Jun 9 23:16:14 2003 +++ b/drivers/mtd/chips/sharp.c Mon Jun 9 23:16:14 2003 @@ -4,7 +4,7 @@ * Copyright 2000,2001 David A. Schleef <ds@schleef.org> * 2000,2001 Lineo, Inc. * - * $Id: sharp.c,v 1.6 2001/10/02 15:05:12 dwmw2 Exp $ + * $Id: sharp.c,v 1.12 2003/05/28 15:39:52 dwmw2 Exp $ * * Devices supported: * LH28F016SCT Symmetrical block flash memory, 2Mx8 @@ -28,6 +28,7 @@ #include <linux/errno.h> #include <linux/interrupt.h> #include <linux/mtd/map.h> +#include <linux/mtd/mtd.h> #include <linux/mtd/cfi.h> #include <linux/delay.h> @@ -165,12 +166,12 @@ u32 read0, read4; int width = 4; - tmp = map->read32(map, base+0); + tmp = map_read32(map, base+0); - map->write32(map, CMD_READ_ID, base+0); + map_write32(map, CMD_READ_ID, base+0); - read0=map->read32(map, base+0); - read4=map->read32(map, base+4); + read0=map_read32(map, base+0); + read4=map_read32(map, base+4); if(read0 == 0x89898989){ printk("Looks like sharp flash\n"); switch(read4){ @@ -198,10 +199,10 @@ printk("Sort-of looks like sharp flash, 0x%08x 0x%08x\n", read0,read4); } - }else if((map->read32(map, base+0) == CMD_READ_ID)){ + }else if((map_read32(map, base+0) == CMD_READ_ID)){ /* RAM, probably */ printk("Looks like RAM\n"); - map->write32(map, tmp, base+0); + map_write32(map, tmp, base+0); }else{ printk("Doesn't look like sharp flash, 0x%08x 0x%08x\n", read0,read4); @@ -223,10 +224,10 @@ switch(chip->state){ case FL_READY: - map->write32(map,CMD_READ_STATUS,adr); + map_write32(map,CMD_READ_STATUS,adr); chip->state = FL_STATUS; case FL_STATUS: - status = map->read32(map,adr); + status = map_read32(map,adr); //printk("status=%08x\n",status); udelay(100); @@ -254,7 +255,7 @@ goto retry; } - map->write32(map,CMD_RESET, adr); + map_write32(map,CMD_RESET, adr); chip->state = FL_READY; @@ -295,7 +296,7 @@ if(ret<0) break; - map->copy_from(map,buf,ofs,thislen); + map_copy_from(map,buf,ofs,thislen); sharp_release(&sharp->chips[chipnum]); @@ -356,17 +357,17 @@ ret = sharp_wait(map,chip); for(try=0;try<10;try++){ - map->write32(map,CMD_BYTE_WRITE,adr); + map_write32(map,CMD_BYTE_WRITE,adr); /* cpu_to_le32 -> hack to fix the writel be->le conversion */ - map->write32(map,cpu_to_le32(datum),adr); + map_write32(map,cpu_to_le32(datum),adr); chip->state = FL_WRITING; timeo = jiffies + (HZ/2); - map->write32(map,CMD_READ_STATUS,adr); + map_write32(map,CMD_READ_STATUS,adr); for(i=0;i<100;i++){ - status = map->read32(map,adr); + status = map_read32(map,adr); if((status & SR_READY)==SR_READY) break; } @@ -379,9 +380,9 @@ printk("sharp: error writing byte at addr=%08lx status=%08x\n",adr,status); - map->write32(map,CMD_CLEAR_STATUS,adr); + map_write32(map,CMD_CLEAR_STATUS,adr); } - map->write32(map,CMD_RESET,adr); + map_write32(map,CMD_RESET,adr); chip->state = FL_READY; wake_up(&chip->wq); @@ -423,6 +424,7 @@ } } + instr->state = MTD_ERASE_DONE; if(instr->callback) instr->callback(instr); @@ -433,18 +435,18 @@ unsigned long adr) { int ret; - unsigned long timeo; + int timeo; int status; DECLARE_WAITQUEUE(wait, current); - map->write32(map,CMD_READ_STATUS,adr); - status = map->read32(map,adr); + map_write32(map,CMD_READ_STATUS,adr); + status = map_read32(map,adr); timeo = jiffies + HZ; while(time_before(jiffies, timeo)){ - map->write32(map,CMD_READ_STATUS,adr); - status = map->read32(map,adr); + map_write32(map,CMD_READ_STATUS,adr); + status = map_read32(map,adr); if((status & SR_READY)==SR_READY){ ret = 0; goto out; @@ -486,26 +488,26 @@ sharp_unlock_oneblock(map,chip,adr); #endif - map->write32(map,CMD_BLOCK_ERASE_1,adr); - map->write32(map,CMD_BLOCK_ERASE_2,adr); + map_write32(map,CMD_BLOCK_ERASE_1,adr); + map_write32(map,CMD_BLOCK_ERASE_2,adr); chip->state = FL_ERASING; ret = sharp_do_wait_for_ready(map,chip,adr); if(ret<0)return ret; - map->write32(map,CMD_READ_STATUS,adr); - status = map->read32(map,adr); + map_write32(map,CMD_READ_STATUS,adr); + status = map_read32(map,adr); if(!(status&SR_ERRORS)){ - map->write32(map,CMD_RESET,adr); + map_write32(map,CMD_RESET,adr); chip->state = FL_READY; //spin_unlock_bh(chip->mutex); return 0; } printk("sharp: error erasing block at addr=%08lx status=%08x\n",adr,status); - map->write32(map,CMD_CLEAR_STATUS,adr); + map_write32(map,CMD_CLEAR_STATUS,adr); //spin_unlock_bh(chip->mutex); @@ -519,17 +521,17 @@ int i; int status; - map->write32(map,CMD_CLEAR_BLOCK_LOCKS_1,adr); - map->write32(map,CMD_CLEAR_BLOCK_LOCKS_2,adr); + map_write32(map,CMD_CLEAR_BLOCK_LOCKS_1,adr); + map_write32(map,CMD_CLEAR_BLOCK_LOCKS_2,adr); udelay(100); - status = map->read32(map,adr); + status = map_read32(map,adr); printk("status=%08x\n",status); for(i=0;i<1000;i++){ - //map->write32(map,CMD_READ_STATUS,adr); - status = map->read32(map,adr); + //map_write32(map,CMD_READ_STATUS,adr); + status = map_read32(map,adr); if((status & SR_READY)==SR_READY) break; udelay(100); @@ -539,13 +541,13 @@ } if(!(status&SR_ERRORS)){ - map->write32(map,CMD_RESET,adr); + map_write32(map,CMD_RESET,adr); chip->state = FL_READY; return; } printk("sharp: error unlocking block at addr=%08lx status=%08x\n",adr,status); - map->write32(map,CMD_CLEAR_STATUS,adr); + map_write32(map,CMD_CLEAR_STATUS,adr); } #endif diff -Nru a/drivers/mtd/cmdline.c b/drivers/mtd/cmdline.c --- a/drivers/mtd/cmdline.c Mon Jun 9 23:16:15 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,362 +0,0 @@ -/* - * $Id: cmdline.c,v 1.5 2002/11/06 22:40:04 rmk Exp $ - * - * Read flash partition table from command line - * - * Copyright 2002 SYSGO Real-Time Solutions GmbH - * - * The format for the command line is as follows: - * - * mtdparts=<mtddef>[;<mtddef] - * <mtddef> := <mtd-id>:<partdef>[,<partdef>] - * <partdef> := <size>[@offset][<name>][ro] - * <mtd-id> := unique id used in mapping driver/device - * <size> := standard linux memsize OR "-" to denote all remaining space - * <name> := '(' NAME ')' - * - * Examples: - * - * 1 NOR Flash, with 1 single writable partition: - * edb7312-nor:- - * - * 1 NOR Flash with 2 partitions, 1 NAND with one - * edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home) - */ - -#include <linux/kernel.h> -#include <linux/slab.h> - -#include <linux/mtd/mtd.h> -#include <linux/mtd/partitions.h> -#include <asm/setup.h> -#include <linux/bootmem.h> - -/* error message prefix */ -#define ERRP "mtd: " - -/* debug macro */ -#if 0 -#define dbg(x) do { printk("DEBUG-CMDLINE-PART: "); printk x; } while(0) -#else -#define dbg(x) -#endif - - -/* special size referring to all the remaining space in a partition */ -#define SIZE_REMAINING 0xffffffff - -struct cmdline_mtd_partition { - struct cmdline_mtd_partition *next; - char *mtd_id; - int num_parts; - struct mtd_partition *parts; -}; - -/* mtdpart_setup() parses into here */ -static struct cmdline_mtd_partition *partitions; - -/* the command line passed to mtdpart_setupd() */ -static char *cmdline; -static int cmdline_parsed = 0; - -/* - * Parse one partition definition for an MTD. Since there can be many - * comma separated partition definitions, this function calls itself - * recursively until no more partition definitions are found. Nice side - * effect: the memory to keep the mtd_partition structs and the names - * is allocated upon the last definition being found. At that point the - * syntax has been verified ok. - */ -static struct mtd_partition * newpart(char *s, - char **retptr, - int *num_parts, - int this_part, - unsigned char **extra_mem_ptr, - int extra_mem_size) -{ - struct mtd_partition *parts; - unsigned long size; - unsigned long offset = 0; - char *name; - int name_len; - unsigned char *extra_mem; - char delim; - unsigned int mask_flags; - - /* fetch the partition size */ - if (*s == '-') - { /* assign all remaining space to this partition */ - size = SIZE_REMAINING; - s++; - } - else - { - size = memparse(s, &s); - if (!size) - { - printk(KERN_ERR ERRP "couldn't parse number from input string\n"); - return 0; - } - if (size < PAGE_SIZE) - { - printk(KERN_ERR ERRP "partition size too small (%lx)\n", size); - return 0; - } - } - - /* fetch partition name and flags */ - mask_flags = 0; /* this is going to be a regular partition */ - delim = 0; - /* check for offset */ - if (*s == '@') - { - s++; - offset = memparse(s, &s); - if (!offset) - { - printk(KERN_ERR ERRP "couldn't parse number from input string\n"); - return 0; - } - } - /* now look for name */ - if (*s == '(') - { - delim = ')'; - } - if (delim) - { - char *p; - - name = ++s; - if ((p = strchr(name, delim)) == 0) - { - printk(KERN_ERR ERRP "no closing %c found in partition name\n", delim); - return 0; - } - name_len = p - name; - s = p + 1; - } - else - { - name = NULL; - name_len = 13; /* Partition_000 */ - } - - /* record name length for memory allocation later */ - extra_mem_size += name_len + 1; - - /* test for options */ - if (strncmp(s, "ro", 2) == 0) - { - mask_flags |= MTD_WRITEABLE; - s += 2; - } - - /* test if more partitions are following */ - if (*s == ',') - { - if (size == SIZE_REMAINING) - { - printk(KERN_ERR ERRP "no partitions allowed after a fill-up partition\n"); - return 0; - } - /* more partitions follow, parse them */ - if ((parts = newpart(s + 1, &s, num_parts, - this_part + 1, &extra_mem, extra_mem_size)) == 0) - return 0; - } - else - { /* this is the last partition: allocate space for all */ - int alloc_size; - - *num_parts = this_part + 1; - alloc_size = *num_parts * sizeof(struct mtd_partition) + - extra_mem_size; - parts = kmalloc(alloc_size, GFP_KERNEL); - if (!parts) - { - printk(KERN_ERR ERRP "out of memory\n"); - return 0; - } - memset(parts, 0, alloc_size); - extra_mem = (unsigned char *)(parts + *num_parts); - } - /* enter this partition (offset will be calculated later if it is zero at this point) */ - parts[this_part].size = size; - parts[this_part].offset = offset; - parts[this_part].mask_flags = mask_flags; - if (name) - { - strlcpy(extra_mem, name, name_len + 1); - } - else - { - sprintf(extra_mem, "Partition_%03d", this_part); - } - parts[this_part].name = extra_mem; - extra_mem += name_len + 1; - - dbg(("partition %d: name <%s>, offset %x, size %x, mask flags %x\n", - this_part, - parts[this_part].name, - parts[this_part].offset, - parts[this_part].size, - parts[this_part].mask_flags)); - - /* return (updated) pointer to extra_mem memory */ - if (extra_mem_ptr) - *extra_mem_ptr = extra_mem; - - /* return (updated) pointer command line string */ - *retptr = s; - - /* return partition table */ - return parts; -} - -/* - * Parse the command line. - */ -static int mtdpart_setup_real(char *s) -{ - cmdline_parsed = 1; - - for( ; s != NULL; ) - { - struct cmdline_mtd_partition *this_mtd; - struct mtd_partition *parts; - int mtd_id_len; - int num_parts; - char *p, *mtd_id; - - mtd_id = s; - /* fetch <mtd-id> */ - if (!(p = strchr(s, ':'))) - { - printk(KERN_ERR ERRP "no mtd-id\n"); - return 0; - } - mtd_id_len = p - mtd_id; - - dbg(("parsing <%s>\n", p+1)); - - /* - * parse one mtd. have it reserve memory for the - * struct cmdline_mtd_partition and the mtd-id string. - */ - parts = newpart(p + 1, /* cmdline */ - &s, /* out: updated cmdline ptr */ - &num_parts, /* out: number of parts */ - 0, /* first partition */ - (unsigned char**)&this_mtd, /* out: extra mem */ - mtd_id_len + 1 + sizeof(*this_mtd)); - if(!parts) - { - /* - * An error occurred. We're either: - * a) out of memory, or - * b) in the middle of the partition spec - * Either way, this mtd is hosed and we're - * unlikely to succeed in parsing any more - */ - return 0; - } - - /* enter results */ - this_mtd->parts = parts; - this_mtd->num_parts = num_parts; - this_mtd->mtd_id = (char*)(this_mtd + 1); - strlcpy(this_mtd->mtd_id, mtd_id, mtd_id_len + 1); - - /* link into chain */ - this_mtd->next = partitions; - partitions = this_mtd; - - dbg(("mtdid=<%s> num_parts=<%d>\n", - this_mtd->mtd_id, this_mtd->num_parts)); - - - /* EOS - we're done */ - if (*s == 0) - break; - - /* does another spec follow? */ - if (*s != ';') - { - printk(KERN_ERR ERRP "bad character after partition (%c)\n", *s); - return 0; - } - s++; - } - return 1; -} - -/* - * Main function to be called from the MTD mapping driver/device to - * obtain the partitioning information. At this point the command line - * arguments will actually be parsed and turned to struct mtd_partition - * information. - */ -int parse_cmdline_partitions(struct mtd_info *master, - struct mtd_partition **pparts, - const char *mtd_id) -{ - unsigned long offset; - int i; - struct cmdline_mtd_partition *part; - - if (!cmdline) - return -EINVAL; - - /* parse command line */ - if (!cmdline_parsed) - mtdpart_setup_real(cmdline); - - for(part = partitions; part; part = part->next) - { - if (!strcmp(part->mtd_id, mtd_id)) - { - for(i = 0, offset = 0; i < part->num_parts; i++) - { - if (!part->parts[i].offset) - part->parts[i].offset = offset; - else - offset = part->parts[i].offset; - if (part->parts[i].size == SIZE_REMAINING) - part->parts[i].size = master->size - offset; - if (offset + part->parts[i].size > master->size) - { - printk(KERN_WARNING ERRP - "%s: partitioning exceeds flash size, truncating\n", - mtd_id); - part->parts[i].size = master->size - offset; - part->num_parts = i; - } - offset += part->parts[i].size; - } - *pparts = part->parts; - return part->num_parts; - } - } - return -EINVAL; -} - - -/* - * This is the handler for our kernel parameter, called from - * main.c::checksetup(). Note that we can not yet kmalloc() anything, - * so we only save the commandline for later processing. - */ -static int __init mtdpart_setup(char *s) -{ - cmdline = s; - return 1; -} - -__setup("mtdparts=", mtdpart_setup); - -EXPORT_SYMBOL(parse_cmdline_partitions); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>"); -MODULE_DESCRIPTION("Command line configuration of MTD partitions"); diff -Nru a/drivers/mtd/cmdlinepart.c b/drivers/mtd/cmdlinepart.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/cmdlinepart.c Mon Jun 9 23:16:15 2003 @@ -0,0 +1,373 @@ +/* + * $Id: cmdlinepart.c,v 1.9 2003/05/16 17:08:24 dwmw2 Exp $ + * + * Read flash partition table from command line + * + * Copyright 2002 SYSGO Real-Time Solutions GmbH + * + * The format for the command line is as follows: + * + * mtdparts=<mtddef>[;<mtddef] + * <mtddef> := <mtd-id>:<partdef>[,<partdef>] + * <partdef> := <size>[@offset][<name>][ro] + * <mtd-id> := unique id used in mapping driver/device + * <size> := standard linux memsize OR "-" to denote all remaining space + * <name> := '(' NAME ')' + * + * Examples: + * + * 1 NOR Flash, with 1 single writable partition: + * edb7312-nor:- + * + * 1 NOR Flash with 2 partitions, 1 NAND with one + * edb7312-nor:256k(ARMboot)ro,-(root);edb7312-nand:-(home) + */ + +#include <linux/kernel.h> +#include <linux/slab.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/partitions.h> +#include <asm/setup.h> +#include <linux/bootmem.h> + +/* error message prefix */ +#define ERRP "mtd: " + +/* debug macro */ +#if 0 +#define dbg(x) do { printk("DEBUG-CMDLINE-PART: "); printk x; } while(0) +#else +#define dbg(x) +#endif + + +/* special size referring to all the remaining space in a partition */ +#define SIZE_REMAINING 0xffffffff + +struct cmdline_mtd_partition { + struct cmdline_mtd_partition *next; + char *mtd_id; + int num_parts; + struct mtd_partition *parts; +}; + +/* mtdpart_setup() parses into here */ +static struct cmdline_mtd_partition *partitions; + +/* the command line passed to mtdpart_setupd() */ +static char *cmdline; +static int cmdline_parsed = 0; + +/* + * Parse one partition definition for an MTD. Since there can be many + * comma separated partition definitions, this function calls itself + * recursively until no more partition definitions are found. Nice side + * effect: the memory to keep the mtd_partition structs and the names + * is allocated upon the last definition being found. At that point the + * syntax has been verified ok. + */ +static struct mtd_partition * newpart(char *s, + char **retptr, + int *num_parts, + int this_part, + unsigned char **extra_mem_ptr, + int extra_mem_size) +{ + struct mtd_partition *parts; + unsigned long size; + unsigned long offset = 0; + char *name; + int name_len; + unsigned char *extra_mem; + char delim; + unsigned int mask_flags; + + /* fetch the partition size */ + if (*s == '-') + { /* assign all remaining space to this partition */ + size = SIZE_REMAINING; + s++; + } + else + { + size = memparse(s, &s); + if (size < PAGE_SIZE) + { + printk(KERN_ERR ERRP "partition size too small (%lx)\n", size); + return 0; + } + } + + /* fetch partition name and flags */ + mask_flags = 0; /* this is going to be a regular partition */ + delim = 0; + /* check for offset */ + if (*s == '@') + { + s++; + offset = memparse(s, &s); + } + /* now look for name */ + if (*s == '(') + { + delim = ')'; + } + + if (delim) + { + char *p; + + name = ++s; + if ((p = strchr(name, delim)) == 0) + { + printk(KERN_ERR ERRP "no closing %c found in partition name\n", delim); + return 0; + } + name_len = p - name; + s = p + 1; + } + else + { + name = NULL; + name_len = 13; /* Partition_000 */ + } + + /* record name length for memory allocation later */ + extra_mem_size += name_len + 1; + + /* test for options */ + if (strncmp(s, "ro", 2) == 0) + { + mask_flags |= MTD_WRITEABLE; + s += 2; + } + + /* test if more partitions are following */ + if (*s == ',') + { + if (size == SIZE_REMAINING) + { + printk(KERN_ERR ERRP "no partitions allowed after a fill-up partition\n"); + return 0; + } + /* more partitions follow, parse them */ + if ((parts = newpart(s + 1, &s, num_parts, + this_part + 1, &extra_mem, extra_mem_size)) == 0) + return 0; + } + else + { /* this is the last partition: allocate space for all */ + int alloc_size; + + *num_parts = this_part + 1; + alloc_size = *num_parts * sizeof(struct mtd_partition) + + extra_mem_size; + parts = kmalloc(alloc_size, GFP_KERNEL); + if (!parts) + { + printk(KERN_ERR ERRP "out of memory\n"); + return 0; + } + memset(parts, 0, alloc_size); + extra_mem = (unsigned char *)(parts + *num_parts); + } + /* enter this partition (offset will be calculated later if it is zero at this point) */ + parts[this_part].size = size; + parts[this_part].offset = offset; + parts[this_part].mask_flags = mask_flags; + if (name) + { + strlcpy(extra_mem, name, name_len + 1); + } + else + { + sprintf(extra_mem, "Partition_%03d", this_part); + } + parts[this_part].name = extra_mem; + extra_mem += name_len + 1; + + dbg(("partition %d: name <%s>, offset %x, size %x, mask flags %x\n", + this_part, + parts[this_part].name, + parts[this_part].offset, + parts[this_part].size, + parts[this_part].mask_flags)); + + /* return (updated) pointer to extra_mem memory */ + if (extra_mem_ptr) + *extra_mem_ptr = extra_mem; + + /* return (updated) pointer command line string */ + *retptr = s; + + /* return partition table */ + return parts; +} + +/* + * Parse the command line. + */ +static int mtdpart_setup_real(char *s) +{ + cmdline_parsed = 1; + + for( ; s != NULL; ) + { + struct cmdline_mtd_partition *this_mtd; + struct mtd_partition *parts; + int mtd_id_len; + int num_parts; + char *p, *mtd_id; + + mtd_id = s; + /* fetch <mtd-id> */ + if (!(p = strchr(s, ':'))) + { + printk(KERN_ERR ERRP "no mtd-id\n"); + return 0; + } + mtd_id_len = p - mtd_id; + + dbg(("parsing <%s>\n", p+1)); + + /* + * parse one mtd. have it reserve memory for the + * struct cmdline_mtd_partition and the mtd-id string. + */ + parts = newpart(p + 1, /* cmdline */ + &s, /* out: updated cmdline ptr */ + &num_parts, /* out: number of parts */ + 0, /* first partition */ + (unsigned char**)&this_mtd, /* out: extra mem */ + mtd_id_len + 1 + sizeof(*this_mtd)); + if(!parts) + { + /* + * An error occurred. We're either: + * a) out of memory, or + * b) in the middle of the partition spec + * Either way, this mtd is hosed and we're + * unlikely to succeed in parsing any more + */ + return 0; + } + + /* enter results */ + this_mtd->parts = parts; + this_mtd->num_parts = num_parts; + this_mtd->mtd_id = (char*)(this_mtd + 1); + strlcpy(this_mtd->mtd_id, mtd_id, mtd_id_len + 1); + + /* link into chain */ + this_mtd->next = partitions; + partitions = this_mtd; + + dbg(("mtdid=<%s> num_parts=<%d>\n", + this_mtd->mtd_id, this_mtd->num_parts)); + + + /* EOS - we're done */ + if (*s == 0) + break; + + /* does another spec follow? */ + if (*s != ';') + { + printk(KERN_ERR ERRP "bad character after partition (%c)\n", *s); + return 0; + } + s++; + } + return 1; +} + +/* + * Main function to be called from the MTD mapping driver/device to + * obtain the partitioning information. At this point the command line + * arguments will actually be parsed and turned to struct mtd_partition + * information. It returns partitions for the requested mtd device, or + * the first one in the chain if a NULL mtd_id is passed in. + */ +static int parse_cmdline_partitions(struct mtd_info *master, + struct mtd_partition **pparts, + unsigned long origin) +{ + unsigned long offset; + int i; + struct cmdline_mtd_partition *part; + char *mtd_id = master->name; + + if(!cmdline) + return -EINVAL; + + /* parse command line */ + if (!cmdline_parsed) + mtdpart_setup_real(cmdline); + + for(part = partitions; part; part = part->next) + { + if ((!mtd_id) || (!strcmp(part->mtd_id, mtd_id))) + { + for(i = 0, offset = 0; i < part->num_parts; i++) + { + if (!part->parts[i].offset) + part->parts[i].offset = offset; + else + offset = part->parts[i].offset; + if (part->parts[i].size == SIZE_REMAINING) + part->parts[i].size = master->size - offset; + if (offset + part->parts[i].size > master->size) + { + printk(KERN_WARNING ERRP + "%s: partitioning exceeds flash size, truncating\n", + part->mtd_id); + part->parts[i].size = master->size - offset; + part->num_parts = i; + } + offset += part->parts[i].size; + } + *pparts = part->parts; + return part->num_parts; + } + } + return -EINVAL; +} + + +/* + * This is the handler for our kernel parameter, called from + * main.c::checksetup(). Note that we can not yet kmalloc() anything, + * so we only save the commandline for later processing. + */ +static int __init mtdpart_setup(char *s) +{ + cmdline = s; + return 1; +} + +__setup("mtdparts=", mtdpart_setup); + +static struct mtd_part_parser cmdline_parser = { + .owner = THIS_MODULE, + .parse_fn = parse_cmdline_partitions, + .name = "cmdlinepart", +}; + +static int __init cmdline_parser_init(void) +{ + return register_mtd_parser(&cmdline_parser); +} + +static void __exit cmdline_parser_exit(void) +{ + deregister_mtd_parser(&cmdline_parser); +} + +module_init(cmdline_parser_init); +module_exit(cmdline_parser_exit); + + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>"); +MODULE_DESCRIPTION("Command line configuration of MTD partitions"); diff -Nru a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig --- a/drivers/mtd/devices/Kconfig Mon Jun 9 23:16:10 2003 +++ b/drivers/mtd/devices/Kconfig Mon Jun 9 23:16:10 2003 @@ -1,5 +1,5 @@ -# drivers/mtd/maps/Config.in -# $Id: Config.in,v 1.5 2001/09/23 15:33:10 dwmw2 Exp $ +# drivers/mtd/maps/Kconfig +# $Id: Kconfig,v 1.4 2003/05/28 15:18:54 dwmw2 Exp $ menu "Self-contained MTD device drivers" depends on MTD!=n @@ -38,6 +38,12 @@ is only really useful if you are developing on this driver or suspect a possible hardware or driver bug. If unsure say N. +config MTD_MS02NV + tristate "DEC MS02-NV NVRAM module support" + depends on CONFIG_DECSTATION + help + Support for NVRAM module on DECstation. + config MTD_SLRAM tristate "Uncached system RAM" depends on MTD @@ -108,13 +114,6 @@ comment "Disk-On-Chip Device Drivers" -config MTD_DOC1000 - tristate "M-Systems Disk-On-Chip 1000" - depends on MTD - help - This provides an MTD device driver for the M-Systems DiskOnChip - 1000 devices, which are obsolete so you probably want to say 'N'. - config MTD_DOC2000 tristate "M-Systems Disk-On-Chip 2000 and Millennium" depends on MTD @@ -148,10 +147,22 @@ emulate a block device by using a kind of file system on the flash chips. +config MTD_DOC2001PLUS + tristate "M-Systems Disk-On-Chip Millennium Plus" + depends on MTD + ---help--- + This provides an MTD device driver for the M-Systems DiskOnChip + Millennium Plus devices. + + If you use this device, you probably also want to enable the INFTL + 'Inverse NAND Flash Translation Layer' option below, which is used + to emulate a block device by using a kind of file system on the + flash chips. + config MTD_DOCPROBE tristate - default m if MTD_DOC2001!=y && MTD_DOC2000!=y && (MTD_DOC2001=m || MTD_DOC2000=m) - default y if MTD_DOC2001=y || MTD_DOC2000=y + default m if MTD_DOC2001!=y && MTD_DOC2000!=y && MTD_DOC2001PLUS!=y && (MTD_DOC2001=m || MTD_DOC2000=m || MOD_DOC2001PLUS=m) + default y if MTD_DOC2001=y || MTD_DOC2000=y || MTD_DOC2001PLUS=y help This isn't a real config option, it's derived. @@ -200,7 +211,7 @@ continue with probing if it is absent. The signature will always be present for a DiskOnChip 2000 or a normal DiskOnChip Millennium. Only if you have overwritten the first block of a DiskOnChip - Millennium will it be absent. Enable this option if you are using + Millennium will it be absent. Enable this option if you are using LinuxBIOS or if you need to recover a DiskOnChip Millennium on which you have managed to wipe the first block. diff -Nru a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile --- a/drivers/mtd/devices/Makefile Mon Jun 9 23:16:05 2003 +++ b/drivers/mtd/devices/Makefile Mon Jun 9 23:16:05 2003 @@ -1,7 +1,7 @@ # # linux/drivers/devices/Makefile # -# $Id: Makefile,v 1.4 2001/06/26 21:10:05 spse Exp $ +# $Id: Makefile.common,v 1.3 2003/05/28 10:54:23 dwmw2 Exp $ # *** BIG UGLY NOTE *** # @@ -10,12 +10,13 @@ # here where previously there was none. We now have to ensure that # doc200[01].o are linked before docprobe.o -obj-$(CONFIG_MTD_DOC1000) += doc1000.o obj-$(CONFIG_MTD_DOC2000) += doc2000.o obj-$(CONFIG_MTD_DOC2001) += doc2001.o +obj-$(CONFIG_MTD_DOC2001PLUS) += doc2001plus.o obj-$(CONFIG_MTD_DOCPROBE) += docprobe.o docecc.o obj-$(CONFIG_MTD_SLRAM) += slram.o obj-$(CONFIG_MTD_PMC551) += pmc551.o +obj-$(CONFIG_MTD_MS02NV) += ms02-nv.o obj-$(CONFIG_MTD_MTDRAM) += mtdram.o obj-$(CONFIG_MTD_LART) += lart.o obj-$(CONFIG_MTD_BLKMTD) += blkmtd.o diff -Nru a/drivers/mtd/devices/doc2000.c b/drivers/mtd/devices/doc2000.c --- a/drivers/mtd/devices/doc2000.c Mon Jun 9 23:16:05 2003 +++ b/drivers/mtd/devices/doc2000.c Mon Jun 9 23:16:05 2003 @@ -4,7 +4,7 @@ * (c) 1999 Machine Vision Holdings, Inc. * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org> * - * $Id: doc2000.c,v 1.46 2001/10/02 15:05:13 dwmw2 Exp $ + * $Id: doc2000.c,v 1.52 2003/05/20 21:03:07 dwmw2 Exp $ */ #include <linux/kernel.h> @@ -22,7 +22,6 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> -#include <linux/mtd/nand_ids.h> #include <linux/mtd/doc2000.h> #define DOC_SUPPORT_2000 @@ -54,9 +53,9 @@ static int doc_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf, u_char *eccbuf); + size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel); static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf, u_char *eccbuf); + size_t *retlen, const u_char *buf, u_char *eccbuf, int oobsel); static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, size_t *retlen, u_char *buf); static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, @@ -97,12 +96,8 @@ DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n"); return -EIO; } - if (need_resched()) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(1); - } - else - udelay(1); + udelay(1); + cond_resched(); } return 0; @@ -320,7 +315,7 @@ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) { - int mfr, id, i; + int mfr, id, i, j; volatile char dummy; /* Page in the required floor/chip */ @@ -378,12 +373,16 @@ /* Print and store the manufacturer and ID codes. */ for (i = 0; nand_flash_ids[i].name != NULL; i++) { - if (mfr == nand_flash_ids[i].manufacture_id && - id == nand_flash_ids[i].model_id) { + if (id == nand_flash_ids[i].id) { + /* Try to identify manufacturer */ + for (j = 0; nand_manuf_ids[j].id != 0x0; j++) { + if (nand_manuf_ids[j].id == mfr) + break; + } printk(KERN_INFO "Flash chip found: Manufacturer ID: %2.2X, " - "Chip ID: %2.2X (%s)\n", mfr, id, - nand_flash_ids[i].name); + "Chip ID: %2.2X (%s:%s)\n", mfr, id, + nand_manuf_ids[j].name, nand_flash_ids[i].name); if (!doc->mfr) { doc->mfr = mfr; doc->id = id; @@ -391,7 +390,7 @@ nand_flash_ids[i].chipshift; doc->page256 = nand_flash_ids[i].page256; doc->pageadrlen = - nand_flash_ids[i].pageadrlen; + nand_flash_ids[i].chipshift > 25 ? 3 : 2; doc->erasesize = nand_flash_ids[i].erasesize; return 1; @@ -558,7 +557,7 @@ mtd->erasesize = 0; mtd->oobblock = 512; mtd->oobsize = 16; - mtd->module = THIS_MODULE; + mtd->owner = THIS_MODULE; mtd->erase = doc_erase; mtd->point = NULL; mtd->unpoint = NULL; @@ -597,11 +596,11 @@ size_t * retlen, u_char * buf) { /* Just a special case of doc_read_ecc */ - return doc_read_ecc(mtd, from, len, retlen, buf, NULL); + return doc_read_ecc(mtd, from, len, retlen, buf, NULL, 0); } static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, - size_t * retlen, u_char * buf, u_char * eccbuf) + size_t * retlen, u_char * buf, u_char * eccbuf, int oobsel) { struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv; unsigned long docptr; @@ -745,12 +744,12 @@ size_t * retlen, const u_char * buf) { char eccbuf[6]; - return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf); + return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, 0); } static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf, - u_char * eccbuf) + u_char * eccbuf, int oobsel) { struct DiskOnChip *this = (struct DiskOnChip *) mtd->priv; int di; /* Yes, DI is a hangover from when I was disassembling the binary driver */ diff -Nru a/drivers/mtd/devices/doc2001.c b/drivers/mtd/devices/doc2001.c --- a/drivers/mtd/devices/doc2001.c Mon Jun 9 23:16:09 2003 +++ b/drivers/mtd/devices/doc2001.c Mon Jun 9 23:16:09 2003 @@ -4,7 +4,7 @@ * (c) 1999 Machine Vision Holdings, Inc. * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org> * - * $Id: doc2001.c,v 1.35 2001/10/02 15:05:13 dwmw2 Exp $ + * $Id: doc2001.c,v 1.40 2003/05/20 21:03:07 dwmw2 Exp $ */ #include <linux/kernel.h> @@ -22,7 +22,6 @@ #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> -#include <linux/mtd/nand_ids.h> #include <linux/mtd/doc2000.h> /* #define ECC_DEBUG */ @@ -38,9 +37,9 @@ static int doc_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf, u_char *eccbuf); + size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel); static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf, u_char *eccbuf); + size_t *retlen, const u_char *buf, u_char *eccbuf, int oobsel); static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, size_t *retlen, u_char *buf); static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, @@ -182,7 +181,7 @@ /* DoC_IdentChip: Identify a given NAND chip given {floor,chip} */ static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) { - int mfr, id, i; + int mfr, id, i, j; volatile char dummy; /* Page in the required floor/chip @@ -216,11 +215,15 @@ /* FIXME: to deal with multi-flash on multi-Millennium case more carefully */ for (i = 0; nand_flash_ids[i].name != NULL; i++) { - if (mfr == nand_flash_ids[i].manufacture_id && - id == nand_flash_ids[i].model_id) { + if ( id == nand_flash_ids[i].id) { + /* Try to identify manufacturer */ + for (j = 0; nand_manuf_ids[j].id != 0x0; j++) { + if (nand_manuf_ids[j].id == mfr) + break; + } printk(KERN_INFO "Flash chip found: Manufacturer ID: %2.2X, " - "Chip ID: %2.2X (%s)\n", - mfr, id, nand_flash_ids[i].name); + "Chip ID: %2.2X (%s:%s)\n", + mfr, id, nand_manuf_ids[j].name, nand_flash_ids[i].name); doc->mfr = mfr; doc->id = id; doc->chipshift = nand_flash_ids[i].chipshift; @@ -363,7 +366,7 @@ mtd->oobblock = 512; mtd->oobsize = 16; - mtd->module = THIS_MODULE; + mtd->owner = THIS_MODULE; mtd->erase = doc_erase; mtd->point = NULL; mtd->unpoint = NULL; @@ -399,11 +402,11 @@ size_t *retlen, u_char *buf) { /* Just a special case of doc_read_ecc */ - return doc_read_ecc(mtd, from, len, retlen, buf, NULL); + return doc_read_ecc(mtd, from, len, retlen, buf, NULL, 0); } static int doc_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf, u_char *eccbuf) + size_t *retlen, u_char *buf, u_char *eccbuf, int oobsel) { int i, ret; volatile char dummy; @@ -525,11 +528,11 @@ size_t *retlen, const u_char *buf) { char eccbuf[6]; - return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf); + return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, 0); } static int doc_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf, u_char *eccbuf) + size_t *retlen, const u_char *buf, u_char *eccbuf, int oobsel) { int i,ret = 0; volatile char dummy; diff -Nru a/drivers/mtd/devices/doc2001plus.c b/drivers/mtd/devices/doc2001plus.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/devices/doc2001plus.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,1120 @@ +/* + * Linux driver for Disk-On-Chip Millennium Plus + * + * (c) 2002-2003 Greg Ungerer <gerg@snapgear.com> + * (c) 2002-2003 SnapGear Inc + * (c) 1999 Machine Vision Holdings, Inc. + * (c) 1999, 2000 David Woodhouse <dwmw2@infradead.org> + * + * $Id: doc2001plus.c,v 1.4 2003/05/23 11:28:46 dwmw2 Exp $ + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <asm/errno.h> +#include <asm/io.h> +#include <asm/uaccess.h> +#include <linux/miscdevice.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/sched.h> +#include <linux/init.h> +#include <linux/types.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/doc2000.h> + +/* #define ECC_DEBUG */ + +/* I have no idea why some DoC chips can not use memcop_form|to_io(). + * This may be due to the different revisions of the ASIC controller built-in or + * simplily a QA/Bug issue. Who knows ?? If you have trouble, please uncomment + * this:*/ +#undef USE_MEMCPY + +static int doc_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf); +static int doc_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf); +static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf, u_char *eccbuf, + struct nand_oobinfo *oobsel); +static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf, u_char *eccbuf, + struct nand_oobinfo *oobsel); +static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, + size_t *retlen, u_char *buf); +static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, + size_t *retlen, const u_char *buf); +static int doc_erase (struct mtd_info *mtd, struct erase_info *instr); + +static struct mtd_info *docmilpluslist = NULL; + + +/* Perform the required delay cycles by writing to the NOP register */ +static void DoC_Delay(unsigned long docptr, int cycles) +{ + int i; + + for (i = 0; (i < cycles); i++) + WriteDOC(0, docptr, Mplus_NOP); +} + +#define CDSN_CTRL_FR_B_MASK (CDSN_CTRL_FR_B0 | CDSN_CTRL_FR_B1) + +/* DOC_WaitReady: Wait for RDY line to be asserted by the flash chip */ +static int _DoC_WaitReady(unsigned long docptr) +{ + unsigned int c = 0xffff; + + DEBUG(MTD_DEBUG_LEVEL3, + "_DoC_WaitReady called for out-of-line wait\n"); + + /* Out-of-line routine to wait for chip response */ + while (((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) && --c) + ; + + if (c == 0) + DEBUG(MTD_DEBUG_LEVEL2, "_DoC_WaitReady timed out.\n"); + + return (c == 0); +} + +static inline int DoC_WaitReady(unsigned long docptr) +{ + /* This is inline, to optimise the common case, where it's ready instantly */ + int ret = 0; + + /* read form NOP register should be issued prior to the read from CDSNControl + see Software Requirement 11.4 item 2. */ + DoC_Delay(docptr, 4); + + if ((ReadDOC(docptr, Mplus_FlashControl) & CDSN_CTRL_FR_B_MASK) != CDSN_CTRL_FR_B_MASK) + /* Call the out-of-line routine to wait */ + ret = _DoC_WaitReady(docptr); + + return ret; +} + +/* For some reason the Millennium Plus seems to occassionally put itself + * into reset mode. For me this happens randomly, with no pattern that I + * can detect. M-systems suggest always check this on any block level + * operation and setting to normal mode if in reset mode. + */ +static inline void DoC_CheckASIC(unsigned long docptr) +{ + /* Make sure the DoC is in normal mode */ + if ((ReadDOC(docptr, Mplus_DOCControl) & DOC_MODE_NORMAL) == 0) { + WriteDOC((DOC_MODE_NORMAL | DOC_MODE_MDWREN), docptr, Mplus_DOCControl); + WriteDOC(~(DOC_MODE_NORMAL | DOC_MODE_MDWREN), docptr, Mplus_CtrlConfirm); + } +} + +/* DoC_Command: Send a flash command to the flash chip through the Flash + * command register. Need 2 Write Pipeline Terminates to complete send. + */ +static inline void DoC_Command(unsigned long docptr, unsigned char command, + unsigned char xtraflags) +{ + WriteDOC(command, docptr, Mplus_FlashCmd); + WriteDOC(command, docptr, Mplus_WritePipeTerm); + WriteDOC(command, docptr, Mplus_WritePipeTerm); +} + +/* DoC_Address: Set the current address for the flash chip through the Flash + * Address register. Need 2 Write Pipeline Terminates to complete send. + */ +static inline void DoC_Address(struct DiskOnChip *doc, int numbytes, + unsigned long ofs, unsigned char xtraflags1, + unsigned char xtraflags2) +{ + unsigned long docptr = doc->virtadr; + + /* Allow for possible Mill Plus internal flash interleaving */ + ofs >>= doc->interleave; + + switch (numbytes) { + case 1: + /* Send single byte, bits 0-7. */ + WriteDOC(ofs & 0xff, docptr, Mplus_FlashAddress); + break; + case 2: + /* Send bits 9-16 followed by 17-23 */ + WriteDOC((ofs >> 9) & 0xff, docptr, Mplus_FlashAddress); + WriteDOC((ofs >> 17) & 0xff, docptr, Mplus_FlashAddress); + break; + case 3: + /* Send 0-7, 9-16, then 17-23 */ + WriteDOC(ofs & 0xff, docptr, Mplus_FlashAddress); + WriteDOC((ofs >> 9) & 0xff, docptr, Mplus_FlashAddress); + WriteDOC((ofs >> 17) & 0xff, docptr, Mplus_FlashAddress); + break; + default: + return; + } + + WriteDOC(0x00, docptr, Mplus_WritePipeTerm); + WriteDOC(0x00, docptr, Mplus_WritePipeTerm); +} + +/* DoC_SelectChip: Select a given flash chip within the current floor */ +static int DoC_SelectChip(unsigned long docptr, int chip) +{ + /* No choice for flash chip on Millennium Plus */ + return 0; +} + +/* DoC_SelectFloor: Select a given floor (bank of flash chips) */ +static int DoC_SelectFloor(unsigned long docptr, int floor) +{ + WriteDOC((floor & 0x3), docptr, Mplus_DeviceSelect); + return 0; +} + +/* + * Translate the given offset into the appropriate command and offset. + * This does the mapping using the 16bit interleave layout defined by + * M-Systems, and looks like this for a sector pair: + * +-----------+-------+-------+-------+--------------+---------+-----------+ + * | 0 --- 511 |512-517|518-519|520-521| 522 --- 1033 |1034-1039|1040 - 1055| + * +-----------+-------+-------+-------+--------------+---------+-----------+ + * | Data 0 | ECC 0 |Flags0 |Flags1 | Data 1 |ECC 1 | OOB 1 + 2 | + * +-----------+-------+-------+-------+--------------+---------+-----------+ + */ +static unsigned int DoC_GetDataOffset(struct mtd_info *mtd, loff_t *from) +{ + unsigned int ofs = *from & 0x3ff; + unsigned int cmd; + + if (ofs < 512) { + cmd = NAND_CMD_READ0; + ofs &= 0x1ff; + } else if (ofs < 1014) { + cmd = NAND_CMD_READ1; + ofs = (ofs & 0x1ff) + 10; + } else { + cmd = NAND_CMD_READOOB; + ofs = ofs - 1014; + } + + *from = (*from & ~0x3ff) | ofs; + return cmd; +} + +static unsigned int DoC_GetECCOffset(struct mtd_info *mtd, loff_t *from) +{ + unsigned int ofs, cmd; + + if (*from & 0x200) { + cmd = NAND_CMD_READOOB; + ofs = 10 + (*from & 0xf); + } else { + cmd = NAND_CMD_READ1; + ofs = (*from & 0xf); + } + + *from = (*from & ~0x3ff) | ofs; + return cmd; +} + +static unsigned int DoC_GetFlagsOffset(struct mtd_info *mtd, loff_t *from) +{ + unsigned int ofs, cmd; + + cmd = NAND_CMD_READ1; + ofs = (*from & 0x200) ? 8 : 6; + *from = (*from & ~0x3ff) | ofs; + return cmd; +} + +static unsigned int DoC_GetHdrOffset(struct mtd_info *mtd, loff_t *from) +{ + unsigned int ofs, cmd; + + cmd = NAND_CMD_READOOB; + ofs = (*from & 0x200) ? 24 : 16; + *from = (*from & ~0x3ff) | ofs; + return cmd; +} + +static inline void MemReadDOC(unsigned long docptr, unsigned char *buf, int len) +{ +#ifndef USE_MEMCPY + int i; + for (i = 0; i < len; i++) + buf[i] = ReadDOC(docptr, Mil_CDSN_IO + i); +#else + memcpy_fromio(buf, docptr + DoC_Mil_CDSN_IO, len); +#endif +} + +static inline void MemWriteDOC(unsigned long docptr, unsigned char *buf, int len) +{ +#ifndef USE_MEMCPY + int i; + for (i = 0; i < len; i++) + WriteDOC(buf[i], docptr, Mil_CDSN_IO + i); +#else + memcpy_toio(docptr + DoC_Mil_CDSN_IO, buf, len); +#endif +} + +/* DoC_IdentChip: Identify a given NAND chip given {floor,chip} */ +static int DoC_IdentChip(struct DiskOnChip *doc, int floor, int chip) +{ + int mfr, id, i, j; + volatile char dummy; + unsigned long docptr = doc->virtadr; + + /* Page in the required floor/chip */ + DoC_SelectFloor(docptr, floor); + DoC_SelectChip(docptr, chip); + + /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */ + WriteDOC((DOC_FLASH_CE | DOC_FLASH_WP), docptr, Mplus_FlashSelect); + + /* Reset the chip, see Software Requirement 11.4 item 1. */ + DoC_Command(docptr, NAND_CMD_RESET, 0); + DoC_WaitReady(docptr); + + /* Read the NAND chip ID: 1. Send ReadID command */ + DoC_Command(docptr, NAND_CMD_READID, 0); + + /* Read the NAND chip ID: 2. Send address byte zero */ + DoC_Address(doc, 1, 0x00, 0, 0x00); + + WriteDOC(0, docptr, Mplus_FlashControl); + DoC_WaitReady(docptr); + + /* Read the manufacturer and device id codes of the flash device through + CDSN IO register see Software Requirement 11.4 item 5.*/ + dummy = ReadDOC(docptr, Mplus_ReadPipeInit); + dummy = ReadDOC(docptr, Mplus_ReadPipeInit); + + mfr = ReadDOC(docptr, Mil_CDSN_IO); + dummy = ReadDOC(docptr, Mil_CDSN_IO); /* 2 way interleave */ + + id = ReadDOC(docptr, Mil_CDSN_IO); + dummy = ReadDOC(docptr, Mil_CDSN_IO); /* 2 way interleave */ + + dummy = ReadDOC(docptr, Mplus_LastDataRead); + dummy = ReadDOC(docptr, Mplus_LastDataRead); + + /* Disable flash internally */ + WriteDOC(0, docptr, Mplus_FlashSelect); + + /* No response - return failure */ + if (mfr == 0xff || mfr == 0) + return 0; + + for (i = 0; nand_flash_ids[i].name != NULL; i++) { + if (id == nand_flash_ids[i].id) { + /* Try to identify manufacturer */ + for (j = 0; nand_manuf_ids[j].id != 0x0; j++) { + if (nand_manuf_ids[j].id == mfr) + break; + } + printk(KERN_INFO "Flash chip found: Manufacturer ID: %2.2X, " + "Chip ID: %2.2X (%s:%s)\n", mfr, id, + nand_manuf_ids[j].name, nand_flash_ids[i].name); + doc->mfr = mfr; + doc->id = id; + doc->interleave = 0; + if (doc->ChipID == DOC_ChipID_DocMilPlus32) + doc->interleave = 1; + doc->chipshift = nand_flash_ids[i].chipshift; + doc->erasesize = nand_flash_ids[i].erasesize << doc->interleave; + break; + } + } + + if (nand_flash_ids[i].name == NULL) + return 0; + return 1; +} + +/* DoC_ScanChips: Find all NAND chips present in a DiskOnChip, and identify them */ +static void DoC_ScanChips(struct DiskOnChip *this) +{ + int floor, chip; + int numchips[MAX_FLOORS_MPLUS]; + int ret; + + this->numchips = 0; + this->mfr = 0; + this->id = 0; + + /* For each floor, find the number of valid chips it contains */ + for (floor = 0,ret = 1; floor < MAX_FLOORS_MPLUS; floor++) { + numchips[floor] = 0; + for (chip = 0; chip < MAX_CHIPS_MPLUS && ret != 0; chip++) { + ret = DoC_IdentChip(this, floor, chip); + if (ret) { + numchips[floor]++; + this->numchips++; + } + } + } + /* If there are none at all that we recognise, bail */ + if (!this->numchips) { + printk("No flash chips recognised.\n"); + return; + } + + /* Allocate an array to hold the information for each chip */ + this->chips = kmalloc(sizeof(struct Nand) * this->numchips, GFP_KERNEL); + if (!this->chips){ + printk("MTD: No memory for allocating chip info structures\n"); + return; + } + + /* Fill out the chip array with {floor, chipno} for each + * detected chip in the device. */ + for (floor = 0, ret = 0; floor < MAX_FLOORS_MPLUS; floor++) { + for (chip = 0 ; chip < numchips[floor] ; chip++) { + this->chips[ret].floor = floor; + this->chips[ret].chip = chip; + this->chips[ret].curadr = 0; + this->chips[ret].curmode = 0x50; + ret++; + } + } + + /* Calculate and print the total size of the device */ + this->totlen = this->numchips * (1 << this->chipshift); + printk(KERN_INFO "%d flash chips found. Total DiskOnChip size: %ld MiB\n", + this->numchips ,this->totlen >> 20); +} + +static int DoCMilPlus_is_alias(struct DiskOnChip *doc1, struct DiskOnChip *doc2) +{ + int tmp1, tmp2, retval; + + if (doc1->physadr == doc2->physadr) + return 1; + + /* Use the alias resolution register which was set aside for this + * purpose. If it's value is the same on both chips, they might + * be the same chip, and we write to one and check for a change in + * the other. It's unclear if this register is usuable in the + * DoC 2000 (it's in the Millennium docs), but it seems to work. */ + tmp1 = ReadDOC(doc1->virtadr, Mplus_AliasResolution); + tmp2 = ReadDOC(doc2->virtadr, Mplus_AliasResolution); + if (tmp1 != tmp2) + return 0; + + WriteDOC((tmp1+1) % 0xff, doc1->virtadr, Mplus_AliasResolution); + tmp2 = ReadDOC(doc2->virtadr, Mplus_AliasResolution); + if (tmp2 == (tmp1+1) % 0xff) + retval = 1; + else + retval = 0; + + /* Restore register contents. May not be necessary, but do it just to + * be safe. */ + WriteDOC(tmp1, doc1->virtadr, Mplus_AliasResolution); + + return retval; +} + +static const char im_name[] = "DoCMilPlus_init"; + +/* This routine is made available to other mtd code via + * inter_module_register. It must only be accessed through + * inter_module_get which will bump the use count of this module. The + * addresses passed back in mtd are valid as long as the use count of + * this module is non-zero, i.e. between inter_module_get and + * inter_module_put. Keith Owens <kaos@ocs.com.au> 29 Oct 2000. + */ +static void DoCMilPlus_init(struct mtd_info *mtd) +{ + struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; + struct DiskOnChip *old = NULL; + + /* We must avoid being called twice for the same device. */ + if (docmilpluslist) + old = (struct DiskOnChip *)docmilpluslist->priv; + + while (old) { + if (DoCMilPlus_is_alias(this, old)) { + printk(KERN_NOTICE "Ignoring DiskOnChip Millennium " + "Plus at 0x%lX - already configured\n", + this->physadr); + iounmap((void *)this->virtadr); + kfree(mtd); + return; + } + if (old->nextdoc) + old = (struct DiskOnChip *)old->nextdoc->priv; + else + old = NULL; + } + + mtd->name = "DiskOnChip Millennium Plus"; + printk(KERN_NOTICE "DiskOnChip Millennium Plus found at " + "address 0x%lX\n", this->physadr); + + mtd->type = MTD_NANDFLASH; + mtd->flags = MTD_CAP_NANDFLASH; + mtd->size = 0; + + mtd->erasesize = 0; + mtd->oobblock = 512; + mtd->oobsize = 16; + mtd->owner = THIS_MODULE; + mtd->erase = doc_erase; + mtd->point = NULL; + mtd->unpoint = NULL; + mtd->read = doc_read; + mtd->write = doc_write; + mtd->read_ecc = doc_read_ecc; + mtd->write_ecc = doc_write_ecc; + mtd->read_oob = doc_read_oob; + mtd->write_oob = doc_write_oob; + mtd->sync = NULL; + + this->totlen = 0; + this->numchips = 0; + this->curfloor = -1; + this->curchip = -1; + + /* Ident all the chips present. */ + DoC_ScanChips(this); + + if (!this->totlen) { + kfree(mtd); + iounmap((void *)this->virtadr); + } else { + this->nextdoc = docmilpluslist; + docmilpluslist = mtd; + mtd->size = this->totlen; + mtd->erasesize = this->erasesize; + add_mtd_device(mtd); + return; + } +} + +#if 0 +static int doc_dumpblk(struct mtd_info *mtd, loff_t from) +{ + int i; + loff_t fofs; + struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; + unsigned long docptr = this->virtadr; + struct Nand *mychip = &this->chips[from >> (this->chipshift)]; + unsigned char *bp, buf[1056]; + char c[32]; + + from &= ~0x3ff; + + /* Don't allow read past end of device */ + if (from >= this->totlen) + return -EINVAL; + + DoC_CheckASIC(docptr); + + /* Find the chip which is to be used and select it */ + if (this->curfloor != mychip->floor) { + DoC_SelectFloor(docptr, mychip->floor); + DoC_SelectChip(docptr, mychip->chip); + } else if (this->curchip != mychip->chip) { + DoC_SelectChip(docptr, mychip->chip); + } + this->curfloor = mychip->floor; + this->curchip = mychip->chip; + + /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */ + WriteDOC((DOC_FLASH_CE | DOC_FLASH_WP), docptr, Mplus_FlashSelect); + + /* Reset the chip, see Software Requirement 11.4 item 1. */ + DoC_Command(docptr, NAND_CMD_RESET, 0); + DoC_WaitReady(docptr); + + fofs = from; + DoC_Command(docptr, DoC_GetDataOffset(mtd, &fofs), 0); + DoC_Address(this, 3, fofs, 0, 0x00); + WriteDOC(0, docptr, Mplus_FlashControl); + DoC_WaitReady(docptr); + + /* disable the ECC engine */ + WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); + + ReadDOC(docptr, Mplus_ReadPipeInit); + ReadDOC(docptr, Mplus_ReadPipeInit); + + /* Read the data via the internal pipeline through CDSN IO + register, see Pipelined Read Operations 11.3 */ + MemReadDOC(docptr, buf, 1054); + buf[1054] = ReadDOC(docptr, Mplus_LastDataRead); + buf[1055] = ReadDOC(docptr, Mplus_LastDataRead); + + memset(&c[0], 0, sizeof(c)); + printk("DUMP OFFSET=%x:\n", (int)from); + + for (i = 0, bp = &buf[0]; (i < 1056); i++) { + if ((i % 16) == 0) + printk("%08x: ", i); + printk(" %02x", *bp); + c[(i & 0xf)] = ((*bp >= 0x20) && (*bp <= 0x7f)) ? *bp : '.'; + bp++; + if (((i + 1) % 16) == 0) + printk(" %s\n", c); + } + printk("\n"); + + /* Disable flash internally */ + WriteDOC(0, docptr, Mplus_FlashSelect); + + return 0; +} +#endif + +static int doc_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + /* Just a special case of doc_read_ecc */ + return doc_read_ecc(mtd, from, len, retlen, buf, NULL, NULL); +} + +static int doc_read_ecc(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf, u_char *eccbuf, + struct nand_oobinfo *oobsel) +{ + int ret, i; + volatile char dummy; + loff_t fofs; + unsigned char syndrome[6]; + struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; + unsigned long docptr = this->virtadr; + struct Nand *mychip = &this->chips[from >> (this->chipshift)]; + + /* Don't allow read past end of device */ + if (from >= this->totlen) + return -EINVAL; + + /* Don't allow a single read to cross a 512-byte block boundary */ + if (from + len > ((from | 0x1ff) + 1)) + len = ((from | 0x1ff) + 1) - from; + + DoC_CheckASIC(docptr); + + /* Find the chip which is to be used and select it */ + if (this->curfloor != mychip->floor) { + DoC_SelectFloor(docptr, mychip->floor); + DoC_SelectChip(docptr, mychip->chip); + } else if (this->curchip != mychip->chip) { + DoC_SelectChip(docptr, mychip->chip); + } + this->curfloor = mychip->floor; + this->curchip = mychip->chip; + + /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */ + WriteDOC((DOC_FLASH_CE | DOC_FLASH_WP), docptr, Mplus_FlashSelect); + + /* Reset the chip, see Software Requirement 11.4 item 1. */ + DoC_Command(docptr, NAND_CMD_RESET, 0); + DoC_WaitReady(docptr); + + fofs = from; + DoC_Command(docptr, DoC_GetDataOffset(mtd, &fofs), 0); + DoC_Address(this, 3, fofs, 0, 0x00); + WriteDOC(0, docptr, Mplus_FlashControl); + DoC_WaitReady(docptr); + + if (eccbuf) { + /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/ + WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); + WriteDOC(DOC_ECC_EN, docptr, Mplus_ECCConf); + } else { + /* disable the ECC engine */ + WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); + } + + /* Let the caller know we completed it */ + *retlen = len; + ret = 0; + + ReadDOC(docptr, Mplus_ReadPipeInit); + ReadDOC(docptr, Mplus_ReadPipeInit); + + if (eccbuf) { + /* Read the data via the internal pipeline through CDSN IO + register, see Pipelined Read Operations 11.3 */ + MemReadDOC(docptr, buf, len); + + /* Read the ECC data following raw data */ + MemReadDOC(docptr, eccbuf, 4); + eccbuf[4] = ReadDOC(docptr, Mplus_LastDataRead); + eccbuf[5] = ReadDOC(docptr, Mplus_LastDataRead); + + /* Flush the pipeline */ + dummy = ReadDOC(docptr, Mplus_ECCConf); + dummy = ReadDOC(docptr, Mplus_ECCConf); + + /* Check the ECC Status */ + if (ReadDOC(docptr, Mplus_ECCConf) & 0x80) { + int nb_errors; + /* There was an ECC error */ +#ifdef ECC_DEBUG + printk("DiskOnChip ECC Error: Read at %lx\n", (long)from); +#endif + /* Read the ECC syndrom through the DiskOnChip ECC logic. + These syndrome will be all ZERO when there is no error */ + for (i = 0; i < 6; i++) + syndrome[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i); + + nb_errors = doc_decode_ecc(buf, syndrome); +#ifdef ECC_DEBUG + printk("ECC Errors corrected: %x\n", nb_errors); +#endif + if (nb_errors < 0) { + /* We return error, but have actually done the read. Not that + this can be told to user-space, via sys_read(), but at least + MTD-aware stuff can know about it by checking *retlen */ +#ifdef ECC_DEBUG + printk("%s(%d): Millennium Plus ECC error (from=0x%x:\n", + __FILE__, __LINE__, (int)from); + printk(" syndrome= %02x:%02x:%02x:%02x:%02x:" + "%02x\n", + syndrome[0], syndrome[1], syndrome[2], + syndrome[3], syndrome[4], syndrome[5]); + printk(" eccbuf= %02x:%02x:%02x:%02x:%02x:" + "%02x\n", + eccbuf[0], eccbuf[1], eccbuf[2], + eccbuf[3], eccbuf[4], eccbuf[5]); +#endif + ret = -EIO; + } + } + +#ifdef PSYCHO_DEBUG + printk("ECC DATA at %lx: %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", + (long)from, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3], + eccbuf[4], eccbuf[5]); +#endif + + /* disable the ECC engine */ + WriteDOC(DOC_ECC_DIS, docptr , Mplus_ECCConf); + } else { + /* Read the data via the internal pipeline through CDSN IO + register, see Pipelined Read Operations 11.3 */ + MemReadDOC(docptr, buf, len-2); + buf[len-2] = ReadDOC(docptr, Mplus_LastDataRead); + buf[len-1] = ReadDOC(docptr, Mplus_LastDataRead); + } + + /* Disable flash internally */ + WriteDOC(0, docptr, Mplus_FlashSelect); + + return ret; +} + +static int doc_write(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + char eccbuf[6]; + return doc_write_ecc(mtd, to, len, retlen, buf, eccbuf, NULL); +} + +static int doc_write_ecc(struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf, u_char *eccbuf, + struct nand_oobinfo *oobsel) +{ + int i, before, ret = 0; + loff_t fto; + volatile char dummy; + struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; + unsigned long docptr = this->virtadr; + struct Nand *mychip = &this->chips[to >> (this->chipshift)]; + + /* Don't allow write past end of device */ + if (to >= this->totlen) + return -EINVAL; + + /* Don't allow writes which aren't exactly one block (512 bytes) */ + if ((to & 0x1ff) || (len != 0x200)) + return -EINVAL; + + /* Determine position of OOB flags, before or after data */ + before = to & 0x200; + + DoC_CheckASIC(docptr); + + /* Find the chip which is to be used and select it */ + if (this->curfloor != mychip->floor) { + DoC_SelectFloor(docptr, mychip->floor); + DoC_SelectChip(docptr, mychip->chip); + } else if (this->curchip != mychip->chip) { + DoC_SelectChip(docptr, mychip->chip); + } + this->curfloor = mychip->floor; + this->curchip = mychip->chip; + + /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */ + WriteDOC(DOC_FLASH_CE, docptr, Mplus_FlashSelect); + + /* Reset the chip, see Software Requirement 11.4 item 1. */ + DoC_Command(docptr, NAND_CMD_RESET, 0); + DoC_WaitReady(docptr); + + /* Set device to appropriate plane of flash */ + fto = to; + WriteDOC(DoC_GetDataOffset(mtd, &fto), docptr, Mplus_FlashCmd); + + /* On interleaved devices the flags for 2nd half 512 are before data */ + if (eccbuf && before) + fto -= 2; + + /* issue the Serial Data In command to initial the Page Program process */ + DoC_Command(docptr, NAND_CMD_SEQIN, 0x00); + DoC_Address(this, 3, fto, 0x00, 0x00); + + /* Disable the ECC engine */ + WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); + + if (eccbuf) { + if (before) { + /* Write the block status BLOCK_USED (0x5555) */ + WriteDOC(0x55, docptr, Mil_CDSN_IO); + WriteDOC(0x55, docptr, Mil_CDSN_IO); + } + + /* init the ECC engine, see Reed-Solomon EDC/ECC 11.1 .*/ + WriteDOC(DOC_ECC_EN | DOC_ECC_RW, docptr, Mplus_ECCConf); + } + + MemWriteDOC(docptr, (unsigned char *) buf, len); + + if (eccbuf) { + /* Write ECC data to flash, the ECC info is generated by + the DiskOnChip ECC logic see Reed-Solomon EDC/ECC 11.1 */ + DoC_Delay(docptr, 3); + + /* Read the ECC data through the DiskOnChip ECC logic */ + for (i = 0; i < 6; i++) + eccbuf[i] = ReadDOC(docptr, Mplus_ECCSyndrome0 + i); + + /* disable the ECC engine */ + WriteDOC(DOC_ECC_DIS, docptr, Mplus_ECCConf); + + /* Write the ECC data to flash */ + MemWriteDOC(docptr, eccbuf, 6); + + if (!before) { + /* Write the block status BLOCK_USED (0x5555) */ + WriteDOC(0x55, docptr, Mil_CDSN_IO+6); + WriteDOC(0x55, docptr, Mil_CDSN_IO+7); + } + +#ifdef PSYCHO_DEBUG + printk("OOB data at %lx is %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X\n", + (long) to, eccbuf[0], eccbuf[1], eccbuf[2], eccbuf[3], + eccbuf[4], eccbuf[5]); +#endif + } + + WriteDOC(0x00, docptr, Mplus_WritePipeTerm); + WriteDOC(0x00, docptr, Mplus_WritePipeTerm); + + /* Commit the Page Program command and wait for ready + see Software Requirement 11.4 item 1.*/ + DoC_Command(docptr, NAND_CMD_PAGEPROG, 0x00); + DoC_WaitReady(docptr); + + /* Read the status of the flash device through CDSN IO register + see Software Requirement 11.4 item 5.*/ + DoC_Command(docptr, NAND_CMD_STATUS, 0); + dummy = ReadDOC(docptr, Mplus_ReadPipeInit); + dummy = ReadDOC(docptr, Mplus_ReadPipeInit); + DoC_Delay(docptr, 2); + if ((dummy = ReadDOC(docptr, Mplus_LastDataRead)) & 1) { + printk("MTD: Error 0x%x programming at 0x%x\n", dummy, (int)to); + /* Error in programming + FIXME: implement Bad Block Replacement (in nftl.c ??) */ + *retlen = 0; + ret = -EIO; + } + dummy = ReadDOC(docptr, Mplus_LastDataRead); + + /* Disable flash internally */ + WriteDOC(0, docptr, Mplus_FlashSelect); + + /* Let the caller know we completed it */ + *retlen = len; + + return ret; +} + +static int doc_read_oob(struct mtd_info *mtd, loff_t ofs, size_t len, + size_t *retlen, u_char *buf) +{ + loff_t fofs, base; + struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; + unsigned long docptr = this->virtadr; + struct Nand *mychip = &this->chips[ofs >> this->chipshift]; + size_t i, size, got, want; + + DoC_CheckASIC(docptr); + + /* Find the chip which is to be used and select it */ + if (this->curfloor != mychip->floor) { + DoC_SelectFloor(docptr, mychip->floor); + DoC_SelectChip(docptr, mychip->chip); + } else if (this->curchip != mychip->chip) { + DoC_SelectChip(docptr, mychip->chip); + } + this->curfloor = mychip->floor; + this->curchip = mychip->chip; + + /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */ + WriteDOC((DOC_FLASH_CE | DOC_FLASH_WP), docptr, Mplus_FlashSelect); + + /* disable the ECC engine */ + WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); + DoC_WaitReady(docptr); + + /* Maximum of 16 bytes in the OOB region, so limit read to that */ + if (len > 16) + len = 16; + got = 0; + want = len; + + for (i = 0; ((i < 3) && (want > 0)); i++) { + /* Figure out which region we are accessing... */ + fofs = ofs; + base = ofs & 0xf; + if (base < 6) { + DoC_Command(docptr, DoC_GetECCOffset(mtd, &fofs), 0); + size = 6 - base; + } else if (base < 8) { + DoC_Command(docptr, DoC_GetFlagsOffset(mtd, &fofs), 0); + size = 8 - base; + } else { + DoC_Command(docptr, DoC_GetHdrOffset(mtd, &fofs), 0); + size = 16 - base; + } + if (size > want) + size = want; + + /* Issue read command */ + DoC_Address(this, 3, fofs, 0, 0x00); + WriteDOC(0, docptr, Mplus_FlashControl); + DoC_WaitReady(docptr); + + ReadDOC(docptr, Mplus_ReadPipeInit); + ReadDOC(docptr, Mplus_ReadPipeInit); + MemReadDOC(docptr, &buf[got], size - 2); + buf[got + size - 2] = ReadDOC(docptr, Mplus_LastDataRead); + buf[got + size - 1] = ReadDOC(docptr, Mplus_LastDataRead); + + ofs += size; + got += size; + want -= size; + } + + /* Disable flash internally */ + WriteDOC(0, docptr, Mplus_FlashSelect); + + *retlen = len; + return 0; +} + +static int doc_write_oob(struct mtd_info *mtd, loff_t ofs, size_t len, + size_t *retlen, const u_char *buf) +{ + volatile char dummy; + loff_t fofs, base; + struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; + unsigned long docptr = this->virtadr; + struct Nand *mychip = &this->chips[ofs >> this->chipshift]; + size_t i, size, got, want; + int ret = 0; + + DoC_CheckASIC(docptr); + + /* Find the chip which is to be used and select it */ + if (this->curfloor != mychip->floor) { + DoC_SelectFloor(docptr, mychip->floor); + DoC_SelectChip(docptr, mychip->chip); + } else if (this->curchip != mychip->chip) { + DoC_SelectChip(docptr, mychip->chip); + } + this->curfloor = mychip->floor; + this->curchip = mychip->chip; + + /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */ + WriteDOC(DOC_FLASH_CE, docptr, Mplus_FlashSelect); + + + /* Maximum of 16 bytes in the OOB region, so limit write to that */ + if (len > 16) + len = 16; + got = 0; + want = len; + + for (i = 0; ((i < 3) && (want > 0)); i++) { + /* Reset the chip, see Software Requirement 11.4 item 1. */ + DoC_Command(docptr, NAND_CMD_RESET, 0); + DoC_WaitReady(docptr); + + /* Figure out which region we are accessing... */ + fofs = ofs; + base = ofs & 0x0f; + if (base < 6) { + WriteDOC(DoC_GetECCOffset(mtd, &fofs), docptr, Mplus_FlashCmd); + size = 6 - base; + } else if (base < 8) { + WriteDOC(DoC_GetFlagsOffset(mtd, &fofs), docptr, Mplus_FlashCmd); + size = 8 - base; + } else { + WriteDOC(DoC_GetHdrOffset(mtd, &fofs), docptr, Mplus_FlashCmd); + size = 16 - base; + } + if (size > want) + size = want; + + /* Issue the Serial Data In command to initial the Page Program process */ + DoC_Command(docptr, NAND_CMD_SEQIN, 0x00); + DoC_Address(this, 3, fofs, 0, 0x00); + + /* Disable the ECC engine */ + WriteDOC(DOC_ECC_RESET, docptr, Mplus_ECCConf); + + /* Write the data via the internal pipeline through CDSN IO + register, see Pipelined Write Operations 11.2 */ + MemWriteDOC(docptr, (unsigned char *) &buf[got], size); + WriteDOC(0x00, docptr, Mplus_WritePipeTerm); + WriteDOC(0x00, docptr, Mplus_WritePipeTerm); + + /* Commit the Page Program command and wait for ready + see Software Requirement 11.4 item 1.*/ + DoC_Command(docptr, NAND_CMD_PAGEPROG, 0x00); + DoC_WaitReady(docptr); + + /* Read the status of the flash device through CDSN IO register + see Software Requirement 11.4 item 5.*/ + DoC_Command(docptr, NAND_CMD_STATUS, 0x00); + dummy = ReadDOC(docptr, Mplus_ReadPipeInit); + dummy = ReadDOC(docptr, Mplus_ReadPipeInit); + DoC_Delay(docptr, 2); + if ((dummy = ReadDOC(docptr, Mplus_LastDataRead)) & 1) { + printk("MTD: Error 0x%x programming oob at 0x%x\n", + dummy, (int)ofs); + /* FIXME: implement Bad Block Replacement */ + *retlen = 0; + ret = -EIO; + } + dummy = ReadDOC(docptr, Mplus_LastDataRead); + + ofs += size; + got += size; + want -= size; + } + + /* Disable flash internally */ + WriteDOC(0, docptr, Mplus_FlashSelect); + + *retlen = len; + return ret; +} + +int doc_erase(struct mtd_info *mtd, struct erase_info *instr) +{ + volatile char dummy; + struct DiskOnChip *this = (struct DiskOnChip *)mtd->priv; + __u32 ofs = instr->addr; + __u32 len = instr->len; + unsigned long docptr = this->virtadr; + struct Nand *mychip = &this->chips[ofs >> this->chipshift]; + + DoC_CheckASIC(docptr); + + if (len != mtd->erasesize) + printk(KERN_WARNING "MTD: Erase not right size (%x != %x)n", + len, mtd->erasesize); + + /* Find the chip which is to be used and select it */ + if (this->curfloor != mychip->floor) { + DoC_SelectFloor(docptr, mychip->floor); + DoC_SelectChip(docptr, mychip->chip); + } else if (this->curchip != mychip->chip) { + DoC_SelectChip(docptr, mychip->chip); + } + this->curfloor = mychip->floor; + this->curchip = mychip->chip; + + instr->state = MTD_ERASE_PENDING; + + /* Millennium Plus bus cycle sequence as per figure 2, section 2.4 */ + WriteDOC(DOC_FLASH_CE, docptr, Mplus_FlashSelect); + + DoC_Command(docptr, NAND_CMD_RESET, 0x00); + DoC_WaitReady(docptr); + + DoC_Command(docptr, NAND_CMD_ERASE1, 0); + DoC_Address(this, 2, ofs, 0, 0x00); + DoC_Command(docptr, NAND_CMD_ERASE2, 0); + DoC_WaitReady(docptr); + instr->state = MTD_ERASING; + + /* Read the status of the flash device through CDSN IO register + see Software Requirement 11.4 item 5. */ + DoC_Command(docptr, NAND_CMD_STATUS, 0); + dummy = ReadDOC(docptr, Mplus_ReadPipeInit); + dummy = ReadDOC(docptr, Mplus_ReadPipeInit); + if ((dummy = ReadDOC(docptr, Mplus_LastDataRead)) & 1) { + printk("MTD: Error 0x%x erasing at 0x%x\n", dummy, ofs); + /* FIXME: implement Bad Block Replacement (in nftl.c ??) */ + instr->state = MTD_ERASE_FAILED; + } else { + instr->state = MTD_ERASE_DONE; + } + dummy = ReadDOC(docptr, Mplus_LastDataRead); + + /* Disable flash internally */ + WriteDOC(0, docptr, Mplus_FlashSelect); + + if (instr->callback) + instr->callback(instr); + + return 0; +} + +/**************************************************************************** + * + * Module stuff + * + ****************************************************************************/ + +int __init init_doc2001plus(void) +{ + inter_module_register(im_name, THIS_MODULE, &DoCMilPlus_init); + return 0; +} + +static void __exit cleanup_doc2001plus(void) +{ + struct mtd_info *mtd; + struct DiskOnChip *this; + + while ((mtd=docmilpluslist)) { + this = (struct DiskOnChip *)mtd->priv; + docmilpluslist = this->nextdoc; + + del_mtd_device(mtd); + + iounmap((void *)this->virtadr); + kfree(this->chips); + kfree(mtd); + } + inter_module_unregister(im_name); +} + +module_exit(cleanup_doc2001plus); +module_init(init_doc2001plus); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com> et al."); +MODULE_DESCRIPTION("Driver for DiskOnChip Millennium Plus"); diff -Nru a/drivers/mtd/devices/docecc.c b/drivers/mtd/devices/docecc.c --- a/drivers/mtd/devices/docecc.c Mon Jun 9 23:16:12 2003 +++ b/drivers/mtd/devices/docecc.c Mon Jun 9 23:16:12 2003 @@ -7,7 +7,7 @@ * Author: Fabrice Bellard (fabrice.bellard@netgem.com) * Copyright (C) 2000 Netgem S.A. * - * $Id: docecc.c,v 1.4 2001/10/02 15:05:13 dwmw2 Exp $ + * $Id: docecc.c,v 1.5 2003/05/21 15:15:06 dwmw2 Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -518,6 +518,8 @@ kfree(Index_of); return nb_errors; } + +EXPORT_SYMBOL_GPL(doc_decode_ecc); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Fabrice Bellard <fabrice.bellard@netgem.com>"); diff -Nru a/drivers/mtd/devices/docprobe.c b/drivers/mtd/devices/docprobe.c --- a/drivers/mtd/devices/docprobe.c Mon Jun 9 23:16:15 2003 +++ b/drivers/mtd/devices/docprobe.c Mon Jun 9 23:16:15 2003 @@ -1,9 +1,10 @@ /* Linux driver for Disk-On-Chip devices */ /* Probe routines common to all DoC devices */ -/* (c) 1999 Machine Vision Holdings, Inc. */ -/* Author: David Woodhouse <dwmw2@infradead.org> */ -/* $Id: docprobe.c,v 1.30 2001/10/02 15:05:13 dwmw2 Exp $ */ +/* (C) 1999 Machine Vision Holdings, Inc. */ +/* (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> */ + +/* $Id: docprobe.c,v 1.36 2003/05/23 11:29:34 dwmw2 Exp $ */ @@ -30,14 +31,12 @@ /* DOC_SINGLE_DRIVER: Millennium driver has been merged into DOC2000 driver. - The newly-merged driver doesn't appear to work for writing. It's the - same with the DiskOnChip 2000 and the Millennium. If you have a - Millennium and you want write support to work, remove the definition - of DOC_SINGLE_DRIVER below to use the old doc2001-specific driver. - - Otherwise, it's left on in the hope that it'll annoy someone with - a Millennium enough that they go through and work out what the - difference is :) + The old Millennium-only driver has been retained just in case there + are problems with the new code. If the combined driver doesn't work + for you, you can try the old one by undefining DOC_SINGLE_DRIVER + below and also enabling it in your configuration. If this fixes the + problems, please send a report to the MTD mailing list at + <linux-mtd@lists.infradead.org>. */ #define DOC_SINGLE_DRIVER @@ -46,18 +45,15 @@ #include <linux/module.h> #include <asm/errno.h> #include <asm/io.h> -#include <asm/uaccess.h> -#include <linux/miscdevice.h> -#include <linux/pci.h> #include <linux/delay.h> #include <linux/slab.h> -#include <linux/sched.h> #include <linux/init.h> #include <linux/types.h> #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> #include <linux/mtd/doc2000.h> +#include <linux/mtd/compatmac.h> /* Where to look for the devices? */ #ifndef CONFIG_MTD_DOCPROBE_ADDRESS @@ -67,7 +63,7 @@ static unsigned long doc_config_location = CONFIG_MTD_DOCPROBE_ADDRESS; MODULE_PARM(doc_config_location, "l"); - +MODULE_PARM_DESC(doc_config_location, "Physical memory address at which to probe for DiskOnChip"); static unsigned long __initdata doc_locations[] = { #if defined (__alpha__) || defined(__i386__) || defined(__x86_64__) @@ -84,21 +80,24 @@ 0xe0000, 0xe2000, 0xe4000, 0xe6000, 0xe8000, 0xea000, 0xec000, 0xee000, #endif /* CONFIG_MTD_DOCPROBE_HIGH */ -#elif defined(__ppc__) +#elif defined(__PPC__) 0xe4000000, #elif defined(CONFIG_MOMENCO_OCELOT) 0x2f000000, -#else + 0xff000000, +#elif defined(CONFIG_MOMENCO_OCELOT_G) || defined (CONFIG_MOMENCO_OCELOT_C) + 0xff000000, +##else #warning Unknown architecture for DiskOnChip. No default probe locations defined #endif - 0 }; + 0xffffffff }; /* doccheck: Probe a given memory window to see if there's a DiskOnChip present */ static inline int __init doccheck(unsigned long potential, unsigned long physadr) { unsigned long window=potential; - unsigned char tmp, ChipID; + unsigned char tmp, tmpb, tmpc, ChipID; #ifndef DOC_PASSIVE_PROBE unsigned char tmp2; #endif @@ -141,19 +140,65 @@ switch (ChipID) { case DOC_ChipID_Doc2k: /* Check the TOGGLE bit in the ECC register */ - tmp = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT; - if ((ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT) != tmp) + tmp = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT; + tmpb = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT; + tmpc = ReadDOC(window, 2k_ECCStatus) & DOC_TOGGLE_BIT; + if (tmp != tmpb && tmp == tmpc) return ChipID; break; case DOC_ChipID_DocMil: /* Check the TOGGLE bit in the ECC register */ - tmp = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT; - if ((ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT) != tmp) + tmp = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT; + tmpb = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT; + tmpc = ReadDOC(window, ECCConf) & DOC_TOGGLE_BIT; + if (tmp != tmpb && tmp == tmpc) return ChipID; break; + case DOC_ChipID_DocMilPlus16: + case DOC_ChipID_DocMilPlus32: + case 0: + /* Possible Millennium+, need to do more checks */ +#ifndef DOC_PASSIVE_PROBE + /* Possibly release from power down mode */ + for (tmp = 0; (tmp < 4); tmp++) + ReadDOC(window, Mplus_Power); + + /* Reset the DiskOnChip ASIC */ + tmp = DOC_MODE_RESET | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | + DOC_MODE_BDECT; + WriteDOC(tmp, window, Mplus_DOCControl); + WriteDOC(~tmp, window, Mplus_CtrlConfirm); + + mdelay(1); + /* Enable the DiskOnChip ASIC */ + tmp = DOC_MODE_NORMAL | DOC_MODE_MDWREN | DOC_MODE_RST_LAT | + DOC_MODE_BDECT; + WriteDOC(tmp, window, Mplus_DOCControl); + WriteDOC(~tmp, window, Mplus_CtrlConfirm); + mdelay(1); +#endif /* !DOC_PASSIVE_PROBE */ + + ChipID = ReadDOC(window, ChipID); + + switch (ChipID) { + case DOC_ChipID_DocMilPlus16: + case DOC_ChipID_DocMilPlus32: + /* Check the TOGGLE bit in the toggle register */ + tmp = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT; + tmpb = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT; + tmpc = ReadDOC(window, Mplus_Toggle) & DOC_TOGGLE_BIT; + if (tmp != tmpb && tmp == tmpc) + return ChipID; + break; + default: + break; + } + /* FALL TRHU */ + default: + #ifndef CONFIG_MTD_DOCPROBE_55AA printk(KERN_WARNING "Possible DiskOnChip with unknown ChipID %2.2X found at 0x%lx\n", ChipID, physadr); @@ -233,6 +278,13 @@ im_modname = "doc2001"; #endif /* DOC_SINGLE_DRIVER */ break; + + case DOC_ChipID_DocMilPlus16: + case DOC_ChipID_DocMilPlus32: + name="MillenniumPlus"; + im_funcname = "DoCMilPlus_init"; + im_modname = "doc2001plus"; + break; } if (im_funcname) @@ -244,6 +296,7 @@ return; } printk(KERN_NOTICE "Cannot find driver for DiskOnChip %s at 0x%lX\n", name, physadr); + kfree(mtd); } iounmap((void *)docptr); } @@ -263,7 +316,7 @@ printk(KERN_INFO "Using configured DiskOnChip probe address 0x%lx\n", doc_config_location); DoC_Probe(doc_config_location); } else { - for (i=0; doc_locations[i]; i++) { + for (i=0; (doc_locations[i] != 0xffffffff); i++) { DoC_Probe(doc_locations[i]); } } @@ -271,11 +324,7 @@ found, so the user knows we at least tried. */ if (!docfound) printk(KERN_INFO "No recognised DiskOnChip devices found\n"); - /* So it looks like we've been used and we get unloaded */ - MOD_INC_USE_COUNT; - MOD_DEC_USE_COUNT; - return 0; - + return -EAGAIN; } module_init(init_doc); diff -Nru a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c --- a/drivers/mtd/devices/lart.c Mon Jun 9 23:16:10 2003 +++ b/drivers/mtd/devices/lart.c Mon Jun 9 23:16:10 2003 @@ -2,7 +2,7 @@ /* * MTD driver for the 28F160F3 Flash Memory (non-CFI) on LART. * - * $Id: lart.c,v 1.2 2001/10/02 15:05:13 dwmw2 Exp $ + * $Id: lart.c,v 1.5 2003/05/20 21:03:07 dwmw2 Exp $ * * Author: Abraham vd Merwe <abraham@2d3d.co.za> * @@ -584,46 +584,41 @@ static struct mtd_info mtd; -static struct mtd_erase_region_info erase_regions[] = -{ - /* parameter blocks */ - { - offset: 0x00000000, - erasesize: FLASH_BLOCKSIZE_PARAM, - numblocks: FLASH_NUMBLOCKS_16m_PARAM - }, - /* main blocks */ - { - offset: FLASH_BLOCKSIZE_PARAM * FLASH_NUMBLOCKS_16m_PARAM, - erasesize: FLASH_BLOCKSIZE_MAIN, - numblocks: FLASH_NUMBLOCKS_16m_MAIN - } +static struct mtd_erase_region_info erase_regions[] = { + /* parameter blocks */ + { + .offset = 0x00000000, + .erasesize = FLASH_BLOCKSIZE_PARAM, + .numblocks = FLASH_NUMBLOCKS_16m_PARAM, + }, + /* main blocks */ + { + .offset = FLASH_BLOCKSIZE_PARAM * FLASH_NUMBLOCKS_16m_PARAM, + .erasesize = FLASH_BLOCKSIZE_MAIN, + .numblocks = FLASH_NUMBLOCKS_16m_MAIN, + } }; #ifdef HAVE_PARTITIONS -static struct mtd_partition lart_partitions[] = -{ - /* blob */ - { - name: "blob", - offset: BLOB_START, - size: BLOB_LEN, - mask_flags: 0 - }, - /* kernel */ - { - name: "kernel", - offset: KERNEL_START, /* MTDPART_OFS_APPEND */ - size: KERNEL_LEN, - mask_flags: 0 - }, - /* initial ramdisk / file system */ - { - name: "file system", - offset: INITRD_START, /* MTDPART_OFS_APPEND */ - size: INITRD_LEN, /* MTDPART_SIZ_FULL */ - mask_flags: 0 - } +static struct mtd_partition lart_partitions[] = { + /* blob */ + { + .name = "blob", + .offset = BLOB_START, + .size = BLOB_LEN, + }, + /* kernel */ + { + .name = "kernel", + .offset = KERNEL_START, /* MTDPART_OFS_APPEND */ + .size = KERNEL_LEN, + }, + /* initial ramdisk / file system */ + { + .name = "file system", + .offset = INITRD_START, /* MTDPART_OFS_APPEND */ + .size = INITRD_LEN, /* MTDPART_SIZ_FULL */ + } }; #endif @@ -646,10 +641,10 @@ mtd.erasesize = FLASH_BLOCKSIZE_MAIN; mtd.numeraseregions = NB_OF (erase_regions); mtd.eraseregions = erase_regions; - mtd.module = THIS_MODULE; mtd.erase = flash_erase; mtd.read = flash_read; mtd.write = flash_write; + mtd.owner = THIS_MODULE; #ifdef LART_DEBUG printk (KERN_DEBUG diff -Nru a/drivers/mtd/devices/ms02-nv.c b/drivers/mtd/devices/ms02-nv.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/devices/ms02-nv.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,326 @@ +/* + * 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. + * + * $Id: ms02-nv.c,v 1.4 2003/05/20 21:03:07 dwmw2 Exp $ + */ + +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mtd/mtd.h> +#include <linux/slab.h> +#include <linux/types.h> + +#include <asm/addrspace.h> +#include <asm/bootinfo.h> +#include <asm/dec/ioasic_addrs.h> +#include <asm/dec/kn02.h> +#include <asm/dec/kn03.h> +#include <asm/io.h> +#include <asm/paccess.h> + +#include "ms02-nv.h" + + +static char version[] __initdata = + "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_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. + */ +static ulong ms02nv_addrs[] __initdata = { + 0x07000000, 0x06800000, 0x06000000, 0x05800000, 0x05000000, + 0x04800000, 0x04000000, 0x03800000, 0x03000000, 0x02800000, + 0x02000000, 0x01800000, 0x01000000, 0x00800000 +}; + +static const char ms02nv_name[] = "DEC MS02-NV NVRAM"; +static const char ms02nv_res_diag_ram[] = "Diagnostic RAM"; +static const char ms02nv_res_user_ram[] = "General-purpose RAM"; +static const char ms02nv_res_csr[] = "Control and status register"; + +static struct mtd_info *root_ms02nv_mtd; + + +static int ms02nv_read(struct mtd_info *mtd, loff_t from, + size_t len, size_t *retlen, u_char *buf) +{ + struct ms02nv_private *mp = (struct ms02nv_private *)mtd->priv; + + if (from + len > mtd->size) + return -EINVAL; + + memcpy(buf, mp->uaddr + from, len); + *retlen = len; + + return 0; +} + +static int ms02nv_write(struct mtd_info *mtd, loff_t to, + size_t len, size_t *retlen, const u_char *buf) +{ + struct ms02nv_private *mp = (struct ms02nv_private *)mtd->priv; + + if (to + len > mtd->size) + return -EINVAL; + + memcpy(mp->uaddr + to, buf, len); + *retlen = len; + + return 0; +} + + +static inline uint ms02nv_probe_one(ulong addr) +{ + ms02nv_uint *ms02nv_diagp; + ms02nv_uint *ms02nv_magicp; + uint ms02nv_diag; + uint ms02nv_magic; + size_t size; + + int err; + + /* + * The firmware writes MS02NV_ID at MS02NV_MAGIC and also + * a diagnostic status at MS02NV_DIAG. + */ + ms02nv_diagp = (ms02nv_uint *)(KSEG1ADDR(addr + MS02NV_DIAG)); + ms02nv_magicp = (ms02nv_uint *)(KSEG1ADDR(addr + MS02NV_MAGIC)); + err = get_dbe(ms02nv_magic, ms02nv_magicp); + if (err) + return 0; + if (ms02nv_magic != MS02NV_ID) + return 0; + + ms02nv_diag = *ms02nv_diagp; + size = (ms02nv_diag & MS02NV_DIAG_SIZE_MASK) << MS02NV_DIAG_SIZE_SHIFT; + if (size > MS02NV_CSR) + size = MS02NV_CSR; + + return size; +} + +static int __init ms02nv_init_one(ulong addr) +{ + struct mtd_info *mtd; + struct ms02nv_private *mp; + struct resource *mod_res; + struct resource *diag_res; + struct resource *user_res; + struct resource *csr_res; + ulong fixaddr; + size_t size, fixsize; + + static int version_printed; + + int ret = -ENODEV; + + /* The module decodes 8MB of address space. */ + mod_res = kmalloc(sizeof(*mod_res), GFP_KERNEL); + if (!mod_res) + return -ENOMEM; + + memset(mod_res, 0, sizeof(*mod_res)); + mod_res->name = ms02nv_name; + mod_res->start = addr; + mod_res->end = addr + MS02NV_SLOT_SIZE - 1; + mod_res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; + if (request_resource(&iomem_resource, mod_res) < 0) + goto err_out_mod_res; + + size = ms02nv_probe_one(addr); + if (!size) + goto err_out_mod_res_rel; + + if (!version_printed) { + printk(KERN_INFO "%s", version); + version_printed = 1; + } + + ret = -ENOMEM; + mtd = kmalloc(sizeof(*mtd), GFP_KERNEL); + if (!mtd) + goto err_out_mod_res_rel; + memset(mtd, 0, sizeof(*mtd)); + mp = kmalloc(sizeof(*mp), GFP_KERNEL); + if (!mp) + goto err_out_mtd; + memset(mp, 0, sizeof(*mp)); + + mtd->priv = mp; + mp->resource.module = mod_res; + + /* Firmware's diagnostic NVRAM area. */ + diag_res = kmalloc(sizeof(*diag_res), GFP_KERNEL); + if (!diag_res) + goto err_out_mp; + + memset(diag_res, 0, sizeof(*diag_res)); + diag_res->name = ms02nv_res_diag_ram; + diag_res->start = addr; + diag_res->end = addr + MS02NV_RAM - 1; + diag_res->flags = IORESOURCE_BUSY; + request_resource(mod_res, diag_res); + + mp->resource.diag_ram = diag_res; + + /* User-available general-purpose NVRAM area. */ + user_res = kmalloc(sizeof(*user_res), GFP_KERNEL); + if (!user_res) + goto err_out_diag_res; + + memset(user_res, 0, sizeof(*user_res)); + user_res->name = ms02nv_res_user_ram; + user_res->start = addr + MS02NV_RAM; + user_res->end = addr + size - 1; + user_res->flags = IORESOURCE_BUSY; + request_resource(mod_res, user_res); + + mp->resource.user_ram = user_res; + + /* Control and status register. */ + csr_res = kmalloc(sizeof(*csr_res), GFP_KERNEL); + if (!csr_res) + goto err_out_user_res; + + memset(csr_res, 0, sizeof(*csr_res)); + csr_res->name = ms02nv_res_csr; + csr_res->start = addr + MS02NV_CSR; + csr_res->end = addr + MS02NV_CSR + 3; + csr_res->flags = IORESOURCE_BUSY; + request_resource(mod_res, csr_res); + + mp->resource.csr = csr_res; + + mp->addr = phys_to_virt(addr); + mp->size = size; + + /* + * Hide the firmware's diagnostic area. It may get destroyed + * upon a reboot. Take paging into account for mapping support. + */ + fixaddr = (addr + MS02NV_RAM + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); + fixsize = (size - (fixaddr - addr)) & ~(PAGE_SIZE - 1); + mp->uaddr = phys_to_virt(fixaddr); + + mtd->type = MTD_RAM; + mtd->flags = MTD_CAP_RAM | MTD_XIP; + mtd->size = fixsize; + mtd->name = (char *)ms02nv_name; + mtd->owner = THIS_MODULE; + mtd->read = ms02nv_read; + mtd->write = ms02nv_write; + + ret = -EIO; + if (add_mtd_device(mtd)) { + printk(KERN_ERR + "ms02-nv: Unable to register MTD device, aborting!\n"); + goto err_out_csr_res; + } + + printk(KERN_INFO "mtd%d: %s at 0x%08lx, size %uMB.\n", + mtd->index, ms02nv_name, addr, size >> 20); + + mp->next = root_ms02nv_mtd; + root_ms02nv_mtd = mtd; + + return 0; + + +err_out_csr_res: + release_resource(csr_res); + kfree(csr_res); +err_out_user_res: + release_resource(user_res); + kfree(user_res); +err_out_diag_res: + release_resource(diag_res); + kfree(diag_res); +err_out_mp: + kfree(mp); +err_out_mtd: + kfree(mtd); +err_out_mod_res_rel: + release_resource(mod_res); +err_out_mod_res: + kfree(mod_res); + return ret; +} + +static void __exit ms02nv_remove_one(void) +{ + struct mtd_info *mtd = root_ms02nv_mtd; + struct ms02nv_private *mp = (struct ms02nv_private *)mtd->priv; + + root_ms02nv_mtd = mp->next; + + del_mtd_device(mtd); + + release_resource(mp->resource.csr); + kfree(mp->resource.csr); + release_resource(mp->resource.user_ram); + kfree(mp->resource.user_ram); + release_resource(mp->resource.diag_ram); + kfree(mp->resource.diag_ram); + release_resource(mp->resource.module); + kfree(mp->resource.module); + kfree(mp); + kfree(mtd); +} + + +static int __init ms02nv_init(void) +{ + volatile u32 *csr; + uint stride = 0; + int count = 0; + int i; + + switch (mips_machtype) { + case MACH_DS5000_200: + csr = (volatile u32 *)KN02_CSR_ADDR; + if (*csr & KN02_CSR_BNK32M) + stride = 2; + break; + case MACH_DS5000_2X0: + case MACH_DS5000: + csr = (volatile u32 *)KN03_MCR_BASE; + if (*csr & KN03_MCR_BNK32M) + stride = 2; + break; + default: + return -ENODEV; + break; + } + + for (i = 0; i < (sizeof(ms02nv_addrs) / sizeof(*ms02nv_addrs)); i++) + if (!ms02nv_init_one(ms02nv_addrs[i] << stride)) + count++; + + return (count > 0) ? 0 : -ENODEV; +} + +static void __exit ms02nv_cleanup(void) +{ + while (root_ms02nv_mtd) + ms02nv_remove_one(); +} + + +module_init(ms02nv_init); +module_exit(ms02nv_cleanup); diff -Nru a/drivers/mtd/devices/ms02-nv.h b/drivers/mtd/devices/ms02-nv.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/devices/ms02-nv.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,45 @@ +/* + * 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. + * + * $Id: ms02-nv.h,v 1.1 2002/09/13 13:46:55 dwmw2 Exp $ + */ + +#include <linux/ioport.h> +#include <linux/mtd/mtd.h> + +/* MS02-NV iomem register offsets. */ +#define MS02NV_CSR 0x400000 /* control & status register */ + +/* 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 */ + +/* 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 general constants. */ +#define MS02NV_ID 0x03021966 /* MS02-NV 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 { + struct mtd_info *next; + struct { + struct resource *module; + struct resource *diag_ram; + struct resource *user_ram; + struct resource *csr; + } resource; + u_char *addr; + size_t size; + u_char *uaddr; +}; diff -Nru a/drivers/mtd/devices/mtdram.c b/drivers/mtd/devices/mtdram.c --- a/drivers/mtd/devices/mtdram.c Mon Jun 9 23:16:06 2003 +++ b/drivers/mtd/devices/mtdram.c Mon Jun 9 23:16:06 2003 @@ -1,6 +1,6 @@ /* * mtdram - a test mtd device - * $Id: mtdram.c,v 1.25 2001/10/02 15:05:13 dwmw2 Exp $ + * $Id: mtdram.c,v 1.32 2003/05/21 15:15:07 dwmw2 Exp $ * Author: Alexander Larsson <alex@cendio.se> * * Copyright (c) 1999 Alexander Larsson <alex@cendio.se> @@ -13,6 +13,8 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/ioport.h> +#include <linux/vmalloc.h> +#include <linux/init.h> #include <linux/mtd/compatmac.h> #include <linux/mtd/mtd.h> @@ -28,7 +30,9 @@ static unsigned long total_size = CONFIG_MTDRAM_TOTAL_SIZE; static unsigned long erase_size = CONFIG_MTDRAM_ERASE_SIZE; MODULE_PARM(total_size,"l"); +MODULE_PARM_DESC(total_size, "Total device size in KiB"); MODULE_PARM(erase_size,"l"); +MODULE_PARM_DESC(erase_size, "Device erase block size in KiB"); #define MTDRAM_TOTAL_SIZE (total_size * 1024) #define MTDRAM_ERASE_SIZE (erase_size * 1024) #else @@ -69,7 +73,8 @@ return 0; } -static void ram_unpoint (struct mtd_info *mtd, u_char *addr) +static void ram_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, + size_t len) { DEBUG(MTD_DEBUG_LEVEL2, "ram_unpoint\n"); } @@ -108,65 +113,119 @@ { if (mtd_info) { del_mtd_device(mtd_info); +#if CONFIG_MTDRAM_TOTAL_SIZE > 0 if (mtd_info->priv) #if CONFIG_MTDRAM_ABS_POS > 0 iounmap(mtd_info->priv); #else vfree(mtd_info->priv); #endif +#endif kfree(mtd_info); } } +int mtdram_init_device(struct mtd_info *mtd, void *mapped_address, + unsigned long size, char *name) +{ + memset(mtd, 0, sizeof(*mtd)); + + /* Setup the MTD structure */ + mtd->name = name; + mtd->type = MTD_RAM; + mtd->flags = MTD_CAP_RAM; + mtd->size = size; + mtd->erasesize = MTDRAM_ERASE_SIZE; + mtd->priv = mapped_address; + + mtd->owner = THIS_MODULE; + mtd->erase = ram_erase; + mtd->point = ram_point; + mtd->unpoint = ram_unpoint; + mtd->read = ram_read; + mtd->write = ram_write; + + if (add_mtd_device(mtd)) { + return -EIO; + } + + return 0; +} + +#if CONFIG_MTDRAM_TOTAL_SIZE > 0 +#if CONFIG_MTDRAM_ABS_POS > 0 int __init init_mtdram(void) { - // Allocate some memory + void *addr; + int err; + /* Allocate some memory */ mtd_info = (struct mtd_info *)kmalloc(sizeof(struct mtd_info), GFP_KERNEL); if (!mtd_info) - return 0; + return -ENOMEM; - memset(mtd_info, 0, sizeof(*mtd_info)); + addr = ioremap(CONFIG_MTDRAM_ABS_POS, MTDRAM_TOTAL_SIZE); + if (!addr) { + DEBUG(MTD_DEBUG_LEVEL1, + "Failed to ioremap) memory region of size %ld at ABS_POS:%ld\n", + (long)MTDRAM_TOTAL_SIZE, (long)CONFIG_MTDRAM_ABS_POS); + kfree(mtd_info); + mtd_info = NULL; + return -ENOMEM; + } + err = mtdram_init_device(mtd_info, addr, + MTDRAM_TOTAL_SIZE, "mtdram test device"); + if (err) + { + iounmap(addr); + kfree(mtd_info); + mtd_info = NULL; + return err; + } + memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE); + return err; +} - // Setup the MTD structure - mtd_info->name = "mtdram test device"; - mtd_info->type = MTD_RAM; - mtd_info->flags = MTD_CAP_RAM; - mtd_info->size = MTDRAM_TOTAL_SIZE; - mtd_info->erasesize = MTDRAM_ERASE_SIZE; -#if CONFIG_MTDRAM_ABS_POS > 0 - mtd_info->priv = ioremap(CONFIG_MTDRAM_ABS_POS, MTDRAM_TOTAL_SIZE); -#else - mtd_info->priv = vmalloc(MTDRAM_TOTAL_SIZE); -#endif +#else /* CONFIG_MTDRAM_ABS_POS > 0 */ - if (!mtd_info->priv) { - DEBUG(MTD_DEBUG_LEVEL1, "Failed to vmalloc(/ioremap) memory region of size %ld (ABS_POS:%ld)\n", (long)MTDRAM_TOTAL_SIZE, (long)CONFIG_MTDRAM_ABS_POS); - kfree(mtd_info); - mtd_info = NULL; +int __init init_mtdram(void) +{ + void *addr; + int err; + /* Allocate some memory */ + mtd_info = (struct mtd_info *)kmalloc(sizeof(struct mtd_info), GFP_KERNEL); + if (!mtd_info) return -ENOMEM; - } - memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE); - mtd_info->module = THIS_MODULE; - mtd_info->erase = ram_erase; - mtd_info->point = ram_point; - mtd_info->unpoint = ram_unpoint; - mtd_info->read = ram_read; - mtd_info->write = ram_write; + addr = vmalloc(MTDRAM_TOTAL_SIZE); + if (!addr) { + DEBUG(MTD_DEBUG_LEVEL1, + "Failed to vmalloc memory region of size %ld\n", + (long)MTDRAM_TOTAL_SIZE); + kfree(mtd_info); + mtd_info = NULL; + return -ENOMEM; + } + err = mtdram_init_device(mtd_info, addr, + MTDRAM_TOTAL_SIZE, "mtdram test device"); + if (err) + { + vfree(addr); + kfree(mtd_info); + mtd_info = NULL; + return err; + } + memset(mtd_info->priv, 0xff, MTDRAM_TOTAL_SIZE); + return err; +} +#endif /* !(CONFIG_MTDRAM_ABS_POS > 0) */ - if (add_mtd_device(mtd_info)) { -#if CONFIG_MTDRAM_ABS_POS > 0 - iounmap(mtd_info->priv); -#else - vfree(mtd_info->priv); -#endif - kfree(mtd_info); - mtd_info = NULL; - return -EIO; - } - - return 0; +#else /* CONFIG_MTDRAM_TOTAL_SIZE > 0 */ + +int __init init_mtdram(void) +{ + return 0; } +#endif /* !(CONFIG_MTDRAM_TOTAL_SIZE > 0) */ module_init(init_mtdram); module_exit(cleanup_mtdram); diff -Nru a/drivers/mtd/devices/pmc551.c b/drivers/mtd/devices/pmc551.c --- a/drivers/mtd/devices/pmc551.c Mon Jun 9 23:16:16 2003 +++ b/drivers/mtd/devices/pmc551.c Mon Jun 9 23:16:16 2003 @@ -1,5 +1,5 @@ /* - * $Id: pmc551.c,v 1.19 2001/10/02 15:05:13 dwmw2 Exp $ + * $Id: pmc551.c,v 1.24 2003/05/20 21:03:08 dwmw2 Exp $ * * PMC551 PCI Mezzanine Ram Device * @@ -30,7 +30,7 @@ * * Notes: * Due to what I assume is more buggy SROM, the 64M PMC551 I - * have available claims that all 4 of its DRAM banks have 64M + * have available claims that all 4 of it's DRAM banks have 64M * of ram configured (making a grand total of 256M onboard). * This is slightly annoying since the BAR0 size reflects the * aperture size, not the dram size, and the V370PDC supplies no @@ -98,7 +98,6 @@ #include <linux/ioctl.h> #include <asm/io.h> #include <asm/system.h> -#include <stdarg.h> #include <linux/pci.h> #ifndef CONFIG_PCI @@ -215,7 +214,7 @@ } -static void pmc551_unpoint (struct mtd_info *mtd, u_char *addr) +static void pmc551_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) { #ifdef CONFIG_MTD_PMC551_DEBUG printk(KERN_DEBUG "pmc551_unpoint()\n"); @@ -788,10 +787,10 @@ mtd->write = pmc551_write; mtd->point = pmc551_point; mtd->unpoint = pmc551_unpoint; - mtd->module = THIS_MODULE; mtd->type = MTD_RAM; mtd->name = "PMC551 RAM board"; mtd->erasesize = 0x10000; + mtd->owner = THIS_MODULE; if (add_mtd_device(mtd)) { printk(KERN_NOTICE "pmc551: Failed to register new device\n"); diff -Nru a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c --- a/drivers/mtd/devices/slram.c Mon Jun 9 23:16:05 2003 +++ b/drivers/mtd/devices/slram.c Mon Jun 9 23:16:05 2003 @@ -1,6 +1,32 @@ /*====================================================================== - $Id: slram.c,v 1.25 2001/10/02 15:05:13 dwmw2 Exp $ + $Id: slram.c,v 1.30 2003/05/20 21:03:08 dwmw2 Exp $ + + This driver provides a method to access memory not used by the kernel + itself (i.e. if the kernel commandline mem=xxx is used). To actually + use slram at least mtdblock or mtdchar is required (for block or + character device access). + + Usage: + + if compiled as loadable module: + modprobe slram map=<name>,<start>,<end/offset> + if statically linked into the kernel use the following kernel cmd.line + slram=<name>,<start>,<end/offset> + + <name>: name of the device that will be listed in /proc/mtd + <start>: start of the memory region, decimal or hex (0xabcdef) + <end/offset>: end of the memory region. It's possible to use +0x1234 + to specify the offset instead of the absolute address + + NOTE: + With slram it's only possible to map a contigous memory region. Therfore + if there's a device mapped somewhere in the region specified slram will + fail to load (see kernel log if modprobe fails). + + - + + Jochen Schaeuble <psionic@psionic.de> ======================================================================*/ @@ -20,7 +46,6 @@ #include <linux/init.h> #include <asm/io.h> #include <asm/system.h> -#include <stdarg.h> #include <linux/mtd/mtd.h> @@ -52,7 +77,7 @@ int slram_erase(struct mtd_info *, struct erase_info *); int slram_point(struct mtd_info *, loff_t, size_t, size_t *, u_char **); -void slram_unpoint(struct mtd_info *, u_char *); +void slram_unpoint(struct mtd_info *, u_char *, loff_t, size_t); int slram_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *); int slram_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); @@ -93,7 +118,7 @@ return(0); } -void slram_unpoint(struct mtd_info *mtd, u_char *addr) +void slram_unpoint(struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) { } @@ -174,9 +199,9 @@ (*curmtd)->mtdinfo->unpoint = slram_unpoint; (*curmtd)->mtdinfo->read = slram_read; (*curmtd)->mtdinfo->write = slram_write; - (*curmtd)->mtdinfo->module = THIS_MODULE; + (*curmtd)->mtdinfo->owner = THIS_MODULE; (*curmtd)->mtdinfo->type = MTD_RAM; - (*curmtd)->mtdinfo->erasesize = 0x10000; + (*curmtd)->mtdinfo->erasesize = 0x0; if (add_mtd_device((*curmtd)->mtdinfo)) { E("slram: Failed to register new device\n"); diff -Nru a/drivers/mtd/ftl.c b/drivers/mtd/ftl.c --- a/drivers/mtd/ftl.c Mon Jun 9 23:16:17 2003 +++ b/drivers/mtd/ftl.c Mon Jun 9 23:16:17 2003 @@ -1,5 +1,5 @@ /* This version ported to the Linux-MTD system by dwmw2@infradead.org - * $Id: ftl.c,v 1.39 2001/10/02 15:05:11 dwmw2 Exp $ + * $Id: ftl.c,v 1.50 2003/05/21 10:49:47 dwmw2 Exp $ * * Fixes: Arnaldo Carvalho de Melo <acme@conectiva.com.br> * - fixes some leaks on failure in build_maps and ftl_notify_add, cleanups @@ -55,30 +55,27 @@ contact M-Systems (http://www.m-sys.com) directly. ======================================================================*/ +#include <linux/mtd/blktrans.h> #include <linux/module.h> -#include <linux/mtd/compatmac.h> #include <linux/mtd/mtd.h> /*#define PSYCHO_DEBUG */ #include <linux/kernel.h> -#include <linux/jiffies.h> +#include <linux/sched.h> #include <linux/ptrace.h> #include <linux/slab.h> #include <linux/string.h> #include <linux/timer.h> #include <linux/major.h> #include <linux/fs.h> -#include <linux/ioctl.h> +#include <linux/init.h> #include <linux/hdreg.h> -#include <stdarg.h> - #include <linux/vmalloc.h> #include <linux/blkpg.h> +#include <asm/uaccess.h> #include <linux/mtd/ftl.h> -#define request_arg_t request_queue_t *q - /*====================================================================*/ /* Parameters that can be set with 'insmod' */ @@ -92,10 +89,6 @@ #define FTL_MAJOR 44 #endif -/* Funky stuff for setting up a block device */ -#define MAJOR_NR FTL_MAJOR - -#include <linux/blk.h> /*====================================================================*/ @@ -106,8 +99,7 @@ #define MAX_REGION 4 /* Maximum number of partitions in an FTL region */ -#define PART_BITS 3 -#define MAX_PART 8 +#define PART_BITS 4 /* Maximum number of outstanding erase requests per socket */ #define MAX_ERASE 8 @@ -118,8 +110,7 @@ /* Each memory region corresponds to a minor device */ typedef struct partition_t { - struct mtd_info *mtd; - struct gendisk *disk; + struct mtd_blktrans_dev mbd; u_int32_t state; u_int32_t *VirtualBlockMap; u_int32_t *VirtualPageMap; @@ -144,21 +135,10 @@ region_info_t region; memory_handle_t handle; #endif - atomic_t open; } partition_t; -partition_t *myparts[MAX_MTD_DEVICES]; - -static void ftl_notify_add(struct mtd_info *mtd); -static void ftl_notify_remove(struct mtd_info *mtd); - void ftl_freepart(partition_t *part); -static struct mtd_notifier ftl_notifier = { - .add = ftl_notify_add, - .remove = ftl_notify_remove, -}; - /* Partition state flags */ #define FTL_FORMATTED 0x01 @@ -171,21 +151,9 @@ /*====================================================================*/ -static int ftl_ioctl(struct inode *inode, struct file *file, - u_int cmd, u_long arg); -static int ftl_open(struct inode *inode, struct file *file); -static release_t ftl_close(struct inode *inode, struct file *file); -static int ftl_revalidate(struct gendisk *disk); static void ftl_erase_callback(struct erase_info *done); -static struct block_device_operations ftl_blk_fops = { - .owner = THIS_MODULE, - .open = ftl_open, - .release = ftl_close, - .ioctl = ftl_ioctl, - .revalidate_disk= ftl_revalidate, -}; /*====================================================================== @@ -201,13 +169,13 @@ loff_t offset, max_offset; int ret; part->header.FormattedSize = 0; - max_offset = (0x100000<part->mtd->size)?0x100000:part->mtd->size; + max_offset = (0x100000<part->mbd.mtd->size)?0x100000:part->mbd.mtd->size; /* Search first megabyte for a valid FTL header */ for (offset = 0; (offset + sizeof(header)) < max_offset; - offset += part->mtd->erasesize ? : 0x2000) { + offset += part->mbd.mtd->erasesize ? : 0x2000) { - ret = part->mtd->read(part->mtd, offset, sizeof(header), &ret, + ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &ret, (unsigned char *)&header); if (ret) @@ -226,9 +194,9 @@ printk(KERN_NOTICE "ftl_cs: FTL header corrupt!\n"); return -1; } - if ((1 << header.EraseUnitSize) != part->mtd->erasesize) { + if ((1 << header.EraseUnitSize) != part->mbd.mtd->erasesize) { printk(KERN_NOTICE "ftl: FTL EraseUnitSize %x != MTD erasesize %x\n", - 1 << header.EraseUnitSize,part->mtd->erasesize); + 1 << header.EraseUnitSize,part->mbd.mtd->erasesize); return -1; } part->header = header; @@ -263,7 +231,7 @@ for (i = 0; i < le16_to_cpu(part->header.NumEraseUnits); i++) { offset = ((i + le16_to_cpu(part->header.FirstPhysicalEUN)) << part->header.EraseUnitSize); - ret = part->mtd->read(part->mtd, offset, sizeof(header), &retval, + ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(header), &retval, (unsigned char *)&header); if (ret) @@ -328,7 +296,7 @@ part->EUNInfo[i].Deleted = 0; offset = part->EUNInfo[i].Offset + le32_to_cpu(header.BAMOffset); - ret = part->mtd->read(part->mtd, offset, + ret = part->mbd.mtd->read(part->mbd.mtd, offset, part->BlocksPerUnit * sizeof(u_int32_t), &retval, (unsigned char *)part->bam_cache); @@ -393,7 +361,7 @@ erase->len = 1 << part->header.EraseUnitSize; erase->priv = (u_long)part; - ret = part->mtd->erase(part->mtd, erase); + ret = part->mbd.mtd->erase(part->mbd.mtd, erase); if (!ret) xfer->EraseCount++; @@ -460,7 +428,7 @@ header.LogicalEUN = cpu_to_le16(0xffff); header.EraseCount = cpu_to_le32(xfer->EraseCount); - ret = part->mtd->write(part->mtd, xfer->Offset, sizeof(header), + ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset, sizeof(header), &retlen, (u_char *)&header); if (ret) { @@ -476,7 +444,7 @@ for (i = 0; i < nbam; i++, offset += sizeof(u_int32_t)) { - ret = part->mtd->write(part->mtd, offset, sizeof(u_int32_t), + ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t), &retlen, (u_char *)&ctl); if (ret) @@ -523,7 +491,7 @@ offset = eun->Offset + le32_to_cpu(part->header.BAMOffset); - ret = part->mtd->read(part->mtd, offset, + ret = part->mbd.mtd->read(part->mbd.mtd, offset, part->BlocksPerUnit * sizeof(u_int32_t), &retlen, (u_char *) (part->bam_cache)); @@ -541,7 +509,7 @@ offset = xfer->Offset + 20; /* Bad! */ unit = cpu_to_le16(0x7fff); - ret = part->mtd->write(part->mtd, offset, sizeof(u_int16_t), + ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int16_t), &retlen, (u_char *) &unit); if (ret) { @@ -561,7 +529,7 @@ break; case BLOCK_DATA: case BLOCK_REPLACEMENT: - ret = part->mtd->read(part->mtd, src, SECTOR_SIZE, + ret = part->mbd.mtd->read(part->mbd.mtd, src, SECTOR_SIZE, &retlen, (u_char *) buf); if (ret) { printk(KERN_WARNING "ftl: Error reading old xfer unit in copy_erase_unit\n"); @@ -569,7 +537,7 @@ } - ret = part->mtd->write(part->mtd, dest, SECTOR_SIZE, + ret = part->mbd.mtd->write(part->mbd.mtd, dest, SECTOR_SIZE, &retlen, (u_char *) buf); if (ret) { printk(KERN_WARNING "ftl: Error writing new xfer unit in copy_erase_unit\n"); @@ -588,7 +556,7 @@ } /* Write the BAM to the transfer unit */ - ret = part->mtd->write(part->mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset), + ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + le32_to_cpu(part->header.BAMOffset), part->BlocksPerUnit * sizeof(int32_t), &retlen, (u_char *)part->bam_cache); if (ret) { @@ -598,7 +566,7 @@ /* All clear? Then update the LogicalEUN again */ - ret = part->mtd->write(part->mtd, xfer->Offset + 20, sizeof(u_int16_t), + ret = part->mbd.mtd->write(part->mbd.mtd, xfer->Offset + 20, sizeof(u_int16_t), &retlen, (u_char *)&srcunitswap); if (ret) { @@ -686,8 +654,8 @@ if (queued) { DEBUG(1, "ftl_cs: waiting for transfer " "unit to be prepared...\n"); - if (part->mtd->sync) - part->mtd->sync(part->mtd); + if (part->mbd.mtd->sync) + part->mbd.mtd->sync(part->mbd.mtd); } else { static int ne = 0; if (++ne < 5) @@ -785,7 +753,7 @@ /* Invalidate cache */ part->bam_index = 0xffff; - ret = part->mtd->read(part->mtd, + ret = part->mbd.mtd->read(part->mbd.mtd, part->EUNInfo[eun].Offset + le32_to_cpu(part->header.BAMOffset), part->BlocksPerUnit * sizeof(u_int32_t), &retlen, (u_char *) (part->bam_cache)); @@ -814,64 +782,6 @@ } /* find_free */ -/*====================================================================== - - This gets a memory handle for the region corresponding to the - minor device number. - -======================================================================*/ - -static int ftl_open(struct inode *inode, struct file *file) -{ - partition_t *partition = inode->i_bdev->bd_disk->private_data; - if (!partition) - return -ENODEV; - - if (partition->state != FTL_FORMATTED) - return -ENXIO; - - if (get_capacity(partition->disk) == 0) - return -ENXIO; - - if (!get_mtd_device(partition->mtd, -1)) - return /* -E'SBUGGEREDOFF */ -ENXIO; - - if ((file->f_mode & 2) && !(partition->mtd->flags & MTD_CLEAR_BITS) ) { - put_mtd_device(partition->mtd); - return -EROFS; - } - - DEBUG(0, "ftl_cs: ftl_open(%s)\n", inode->i_bdev->bd_disk->disk_name); - - atomic_inc(&partition->open); - - return 0; -} - -/*====================================================================*/ - -static release_t ftl_close(struct inode *inode, struct file *file) -{ - partition_t *part = inode->i_bdev->bd_disk->private_data; - int i; - - DEBUG(0, "ftl_cs: ftl_close(%s)\n", inode->i_bdev->bd_disk->disk_name); - - /* Wait for any pending erase operations to complete */ - if (part->mtd->sync) - part->mtd->sync(part->mtd); - - for (i = 0; i < part->header.NumTransferUnits; i++) { - if (part->XferInfo[i].state == XFER_ERASED) - prepare_xfer(part, i); - } - - atomic_dec(&part->open); - - put_mtd_device(part->mtd); - release_return(0); -} /* ftl_close */ - /*====================================================================== @@ -906,7 +816,7 @@ else { offset = (part->EUNInfo[log_addr / bsize].Offset + (log_addr % bsize)); - ret = part->mtd->read(part->mtd, offset, SECTOR_SIZE, + ret = part->mbd.mtd->read(part->mbd.mtd, offset, SECTOR_SIZE, &retlen, (u_char *) buffer); if (ret) { @@ -945,7 +855,7 @@ le32_to_cpu(part->header.BAMOffset)); #ifdef PSYCHO_DEBUG - ret = part->mtd->read(part->mtd, offset, sizeof(u_int32_t), + ret = part->mbd.mtd->read(part->mbd.mtd, offset, sizeof(u_int32_t), &retlen, (u_char *)&old_addr); if (ret) { printk(KERN_WARNING"ftl: Error reading old_addr in set_bam_entry: %d\n",ret); @@ -982,7 +892,7 @@ #endif part->bam_cache[blk] = le_virt_addr; } - ret = part->mtd->write(part->mtd, offset, sizeof(u_int32_t), + ret = part->mbd.mtd->write(part->mbd.mtd, offset, sizeof(u_int32_t), &retlen, (u_char *)&le_virt_addr); if (ret) { @@ -1042,7 +952,7 @@ part->EUNInfo[part->bam_index].Deleted++; offset = (part->EUNInfo[part->bam_index].Offset + blk * SECTOR_SIZE); - ret = part->mtd->write(part->mtd, offset, SECTOR_SIZE, &retlen, + ret = part->mbd.mtd->write(part->mbd.mtd, offset, SECTOR_SIZE, &retlen, buffer); if (ret) { @@ -1080,94 +990,43 @@ ======================================================================*/ -static int ftl_ioctl(struct inode *inode, struct file *file, - u_int cmd, u_long arg) +static int ftl_ioctl(struct mtd_blktrans_dev *dev, struct inode *inode, + struct file *file, u_int cmd, u_long arg) { - partition_t *part = inode->i_bdev->bd_disk->private_data; - struct hd_geometry *geo = (struct hd_geometry *)arg; - int ret = 0; - u_long sect; - - if (!part) - return -ENODEV; /* How? */ - - if (cmd != HDIO_GETGEO) - return -EINVAL; - ret = verify_area(VERIFY_WRITE, (long *)arg, sizeof(*geo)); - if (ret) - return ret; + struct hd_geometry *geo = (struct hd_geometry *)arg; + partition_t *part = (void *)dev; + u_long sect; + + switch (cmd) { + case HDIO_GETGEO: /* Sort of arbitrary: round size down to 4K boundary */ sect = le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE; - put_user(1, (char *)&geo->heads); - put_user(8, (char *)&geo->sectors); - put_user((sect>>3), (short *)&geo->cylinders); - put_user(get_start_sect(inode->i_bdev), (u_long *)&geo->start); - return 0; -} /* ftl_ioctl */ + if (put_user(1, (char *)&geo->heads) || + put_user(8, (char *)&geo->sectors) || + put_user((sect>>3), (short *)&geo->cylinders) || + put_user(0, (u_long *)&geo->start)) + return -EFAULT; -/*====================================================================== + case BLKFLSBUF: + return 0; + } + return -ENOTTY; +} /* ftl_ioctl */ - Handler for block device requests -======================================================================*/ +/*======================================================================*/ -static int ftl_revalidate(struct gendisk *disk) +static int ftl_readsect(struct mtd_blktrans_dev *dev, + unsigned long block, char *buf) { - partition_t *part = disk->private_data; - scan_header(part); - set_capacity(disk, le32_to_cpu(part->header.FormattedSize)/SECTOR_SIZE); - return 0; + return ftl_read((void *)dev, buf, block, 1); } -/*====================================================================== - - Handler for block device requests - -======================================================================*/ - -static struct request_queue ftl_queue; - -static void do_ftl_request(struct request_queue *q) +static int ftl_writesect(struct mtd_blktrans_dev *dev, + unsigned long block, char *buf) { - struct request *req; - partition_t *part; - int ret; - - do { - // sti(); - req = elv_next_request(q); - if (!req) - return; - part = req->rq_disk->private_data; - if (part) { - ret = 0; - switch (rq_data_dir(req)) { - case READ: - ret = ftl_read(part, req->buffer, req->sector, - req->current_nr_sectors); - if (ret) - printk("ftl_read returned %d\n", ret); - break; - case WRITE: - ret = ftl_write(part, req->buffer, req->sector, - req->current_nr_sectors); - if (ret) - printk("ftl_write returned %d\n", ret); - break; - default: - panic("ftl_cs: unknown block command!\n"); - } - } else { - ret = 1; - printk("NULL part in ftl_request\n"); - } - - if (!ret) - req->sector += req->current_nr_sectors; - - end_request(req, (ret == 0) ? 1 : 0); - } while (1); -} /* do_ftl_request */ + return ftl_write((void *)dev, buf, block, 1); +} /*====================================================================*/ @@ -1196,109 +1055,75 @@ } /* ftl_freepart */ -static void ftl_notify_add(struct mtd_info *mtd) +static void ftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) { partition_t *partition; - struct gendisk *disk; - int device; - - for (device=0; device < MAX_MTD_DEVICES && myparts[device]; device++) - ; - - if (device == MAX_MTD_DEVICES) { - printk(KERN_NOTICE "Maximum number of FTL partitions reached\n" - "Not scanning <%s>\n", mtd->name); - return; - } partition = kmalloc(sizeof(partition_t), GFP_KERNEL); - disk = alloc_disk(1 << PART_BITS); - if (!partition||!disk) { + if (!partition) { printk(KERN_WARNING "No memory to scan for FTL on %s\n", - mtd->name); - kfree(partition); - put_disk(disk); + mtd->name); return; } memset(partition, 0, sizeof(partition_t)); - sprintf(disk->disk_name, "ftl%c", 'a' + device); - disk->major = FTL_MAJOR; - disk->first_minor = device << 4; - disk->fops = &ftl_blk_fops; - partition->mtd = mtd; - partition->disk = disk; - if ((scan_header(partition) == 0) && (build_maps(partition) == 0)) { + partition->mbd.mtd = mtd; + + if ((scan_header(partition) == 0) && + (build_maps(partition) == 0)) { + partition->state = FTL_FORMATTED; - atomic_set(&partition->open, 0); - myparts[device] = partition; - set_capacity(disk, le32_to_cpu(partition->header.FormattedSize)/SECTOR_SIZE); - disk->private_data = partition; - disk->queue = &ftl_queue; - add_disk(disk); #ifdef PCMCIA_DEBUG - printk(KERN_INFO "ftl_cs: opening %d kb FTL partition\n", + printk(KERN_INFO "ftl_cs: opening %d KiB FTL partition\n", le32_to_cpu(partition->header.FormattedSize) >> 10); #endif - } else { + partition->mbd.size = le32_to_cpu(partition->header.FormattedSize) >> 9; + partition->mbd.blksize = SECTOR_SIZE; + partition->mbd.tr = tr; + partition->mbd.devnum = -1; + if (add_mtd_blktrans_dev((void *)partition)) + kfree(partition); + + } else kfree(partition); - put_disk(disk); - } } -static void ftl_notify_remove(struct mtd_info *mtd) +static void ftl_remove_dev(struct mtd_blktrans_dev *dev) { - int i; - - /* Q: What happens if you try to remove a device which has - * a currently-open FTL partition on it? - * - * A: You don't. The ftl_open routine is responsible for - * increasing the use count of the driver module which - * it uses. - */ - - /* That's the theory, anyway :) */ - - for (i=0; i< MAX_MTD_DEVICES; i++) - if (myparts[i] && myparts[i]->mtd == mtd) { - - if (myparts[i]->state == FTL_FORMATTED) - ftl_freepart(myparts[i]); - - myparts[i]->state = 0; - del_gendisk(myparts[i]->disk); - put_disk(myparts[i]->disk); - kfree(myparts[i]); - myparts[i] = NULL; - } + del_mtd_blktrans_dev(dev); + kfree(dev); } +struct mtd_blktrans_ops ftl_tr = { + .name = "ftl", + .major = FTL_MAJOR, + .part_bits = PART_BITS, + .readsect = ftl_readsect, + .writesect = ftl_writesect, + .ioctl = ftl_ioctl, + .add_mtd = ftl_add_mtd, + .remove_dev = ftl_remove_dev, + .owner = THIS_MODULE, +}; + int init_ftl(void) { - static spinlock_t lock = SPIN_LOCK_UNLOCKED; - DEBUG(0, "$Id: ftl.c,v 1.39 2001/10/02 15:05:11 dwmw2 Exp $\n"); - - if (register_blkdev(FTL_MAJOR, "ftl")) - return -EAGAIN; + DEBUG(0, "$Id: ftl.c,v 1.50 2003/05/21 10:49:47 dwmw2 Exp $\n"); - blk_init_queue(&ftl_queue, &do_ftl_request, &lock); - register_mtd_user(&ftl_notifier); - return 0; + return register_mtd_blktrans(&ftl_tr); } static void __exit cleanup_ftl(void) { - unregister_mtd_user(&ftl_notifier); - unregister_blkdev(FTL_MAJOR, "ftl"); - blk_cleanup_queue(&ftl_queue); + deregister_mtd_blktrans(&ftl_tr); } module_init(init_ftl); module_exit(cleanup_ftl); + MODULE_LICENSE("Dual MPL/GPL"); MODULE_AUTHOR("David Hinds <dahinds@users.sourceforge.net>"); -MODULE_DESCRIPTION("Support code for Flash Translation Layer, used on PCMCIA devices and M-Systems DiskOnChip 1000"); +MODULE_DESCRIPTION("Support code for Flash Translation Layer, used on PCMCIA devices"); diff -Nru a/drivers/mtd/inftlcore.c b/drivers/mtd/inftlcore.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/inftlcore.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,894 @@ +/* + * inftlcore.c -- Linux driver for Inverse Flash Translation Layer (INFTL) + * + * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) + * + * Based heavily on the nftlcore.c code which is: + * (c) 1999 Machine Vision Holdings, Inc. + * Author: David Woodhouse <dwmw2@infradead.org> + * + * $Id: inftlcore.c,v 1.9 2003/05/23 11:41:47 dwmw2 Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/sched.h> +#include <linux/init.h> +#include <linux/kmod.h> +#include <linux/hdreg.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nftl.h> +#include <linux/mtd/inftl.h> +#include <asm/uaccess.h> +#include <asm/errno.h> +#include <asm/io.h> + +/* + * Maximum number of loops while examining next block, to have a + * chance to detect consistency problems (they should never happen + * because of the checks done in the mounting. + */ +#define MAX_LOOPS 10000 + +extern void INFTL_dumptables(struct INFTLrecord *inftl); +extern void INFTL_dumpVUchains(struct INFTLrecord *inftl); + +static void inftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) +{ + struct INFTLrecord *inftl; + unsigned long temp; + + if (mtd->ecctype != MTD_ECC_RS_DiskOnChip) + return; + + DEBUG(MTD_DEBUG_LEVEL3, "INFTL: add_mtd for %s\n", mtd->name); + + inftl = kmalloc(sizeof(*inftl), GFP_KERNEL); + + if (!inftl) { + printk(KERN_WARNING "INFTL: Out of memory for data structures\n"); + return; + } + memset(inftl, 0, sizeof(*inftl)); + + inftl->mbd.mtd = mtd; + inftl->mbd.devnum = -1; + inftl->mbd.blksize = 512; + inftl->mbd.tr = tr; + + if (INFTL_mount(inftl) < 0) { + printk(KERN_WARNING "INFTL: could not mount device\n"); + kfree(inftl); + return; + } + + /* OK, it's a new one. Set up all the data structures. */ + + /* Calculate geometry */ + inftl->cylinders = 1024; + inftl->heads = 16; + + temp = inftl->cylinders * inftl->heads; + inftl->sectors = inftl->mbd.size / temp; + if (inftl->mbd.size % temp) { + inftl->sectors++; + temp = inftl->cylinders * inftl->sectors; + inftl->heads = inftl->mbd.size / temp; + + if (inftl->mbd.size % temp) { + inftl->heads++; + temp = inftl->heads * inftl->sectors; + inftl->cylinders = inftl->mbd.size / temp; + } + } + + if (inftl->mbd.size != inftl->heads * inftl->cylinders * inftl->sectors) { + /* + Oh no we don't have + mbd.size == heads * cylinders * sectors + */ + printk(KERN_WARNING "INFTL: cannot calculate a geometry to " + "match size of 0x%lx.\n", inftl->mbd.size); + printk(KERN_WARNING "INFTL: using C:%d H:%d S:%d " + "(== 0x%lx sects)\n", + inftl->cylinders, inftl->heads , inftl->sectors, + (long)inftl->cylinders * (long)inftl->heads * + (long)inftl->sectors ); + } + + if (add_mtd_blktrans_dev) { + if (inftl->PUtable) + kfree(inftl->PUtable); + if (inftl->VUtable) + kfree(inftl->VUtable); + kfree(inftl); + return; + } +#ifdef PSYCHO_DEBUG + printk(KERN_INFO "INFTL: Found new nftl%c\n", nftl->mbd.devnum + 'a'); +#endif + return; +} + +static void inftl_remove_dev(struct mtd_blktrans_dev *dev) +{ + struct INFTLrecord *inftl = (void *)dev; + + DEBUG(MTD_DEBUG_LEVEL3, "INFTL: remove_dev (i=%d)\n", dev->devnum); + + del_mtd_blktrans_dev(dev); + + if (inftl->PUtable) + kfree(inftl->PUtable); + if (inftl->VUtable) + kfree(inftl->VUtable); + kfree(inftl); +} + +/* + * Actual INFTL access routines. + */ + +/* + * INFTL_findfreeblock: Find a free Erase Unit on the INFTL partition. + * This function is used when the give Virtual Unit Chain. + */ +static u16 INFTL_findfreeblock(struct INFTLrecord *inftl, int desperate) +{ + u16 pot = inftl->LastFreeEUN; + int silly = inftl->nb_blocks; + + DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_findfreeblock(inftl=0x%x," + "desperate=%d)\n", (int)inftl, desperate); + + /* + * Normally, we force a fold to happen before we run out of free + * blocks completely. + */ + if (!desperate && inftl->numfreeEUNs < 2) { + DEBUG(MTD_DEBUG_LEVEL1, "INFTL: there are too few free " + "EUNs (%d)\n", inftl->numfreeEUNs); + return 0xffff; + } + + /* Scan for a free block */ + do { + if (inftl->PUtable[pot] == BLOCK_FREE) { + inftl->LastFreeEUN = pot; + return pot; + } + + if (++pot > inftl->lastEUN) + pot = 0; + + if (!silly--) { + printk(KERN_WARNING "INFTL: no free blocks found! " + "EUN range = %d - %d\n", 0, inftl->LastFreeEUN); + return BLOCK_NIL; + } + } while (pot != inftl->LastFreeEUN); + + return BLOCK_NIL; +} + +static u16 INFTL_foldchain(struct INFTLrecord *inftl, unsigned thisVUC, unsigned pendingblock) +{ + u16 BlockMap[MAX_SECTORS_PER_UNIT]; + unsigned char BlockDeleted[MAX_SECTORS_PER_UNIT]; + unsigned int thisEUN, prevEUN, status; + int block, silly; + unsigned int targetEUN; + struct inftl_oob oob; + size_t retlen; + + DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_foldchain(inftl=0x%x,thisVUC=%d," + "pending=%d)\n", (int)inftl, thisVUC, pendingblock); + + memset(BlockMap, 0xff, sizeof(BlockMap)); + memset(BlockDeleted, 0, sizeof(BlockDeleted)); + + thisEUN = targetEUN = inftl->VUtable[thisVUC]; + + if (thisEUN == BLOCK_NIL) { + printk(KERN_WARNING "INFTL: trying to fold non-existent " + "Virtual Unit Chain %d!\n", thisVUC); + return BLOCK_NIL; + } + + /* + * Scan to find the Erase Unit which holds the actual data for each + * 512-byte block within the Chain. + */ + silly = MAX_LOOPS; + while (thisEUN < inftl->nb_blocks) { + for (block = 0; block < inftl->EraseSize/SECTORSIZE; block ++) { + if ((BlockMap[block] != 0xffff) || BlockDeleted[block]) + continue; + + if (MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) + + (block * SECTORSIZE), 16 , &retlen, + (char *)&oob) < 0) + status = SECTOR_IGNORE; + else + status = oob.b.Status | oob.b.Status1; + + switch(status) { + case SECTOR_FREE: + case SECTOR_IGNORE: + break; + case SECTOR_USED: + BlockMap[block] = thisEUN; + continue; + case SECTOR_DELETED: + BlockDeleted[block] = 1; + continue; + default: + printk(KERN_WARNING "INFTL: unknown status " + "for block %d in EUN %d: %x\n", + block, thisEUN, status); + break; + } + } + + if (!silly--) { + printk(KERN_WARNING "INFTL: infinite loop in Virtual " + "Unit Chain 0x%x\n", thisVUC); + return BLOCK_NIL; + } + + thisEUN = inftl->PUtable[thisEUN]; + } + + /* + * OK. We now know the location of every block in the Virtual Unit + * Chain, and the Erase Unit into which we are supposed to be copying. + * Go for it. + */ + DEBUG(MTD_DEBUG_LEVEL1, "INFTL: folding chain %d into unit %d\n", + thisVUC, targetEUN); + + for (block = 0; block < inftl->EraseSize/SECTORSIZE ; block++) { + unsigned char movebuf[SECTORSIZE]; + int ret; + + /* + * If it's in the target EUN already, or if it's pending write, + * do nothing. + */ + if (BlockMap[block] == targetEUN || (pendingblock == + (thisVUC * (inftl->EraseSize / SECTORSIZE) + block))) { + continue; + } + + /* + * Copy only in non free block (free blocks can only + * happen in case of media errors or deleted blocks). + */ + if (BlockMap[block] == BLOCK_NIL) + continue; + + ret = MTD_READECC(inftl->mbd.mtd, (inftl->EraseSize * + BlockMap[block]) + (block * SECTORSIZE), SECTORSIZE, + &retlen, movebuf, (char *)&oob, NULL); + if (ret < 0) { + ret = MTD_READECC(inftl->mbd.mtd, (inftl->EraseSize * + BlockMap[block]) + (block * SECTORSIZE), + SECTORSIZE, &retlen, movebuf, (char *)&oob, + NULL); + if (ret != -EIO) + DEBUG(MTD_DEBUG_LEVEL1, "INFTL: error went " + "away on retry?\n"); + } + MTD_WRITEECC(inftl->mbd.mtd, (inftl->EraseSize * targetEUN) + + (block * SECTORSIZE), SECTORSIZE, &retlen, + movebuf, (char *)&oob, NULL); + } + + /* + * Newest unit in chain now contains data from _all_ older units. + * So go through and erase each unit in chain, oldest first. (This + * is important, by doing oldest first if we crash/reboot then it + * it is relatively simple to clean up the mess). + */ + DEBUG(MTD_DEBUG_LEVEL1, "INFTL: want to erase virtual chain %d\n", + thisVUC); + + for (;;) { + /* Find oldest unit in chain. */ + thisEUN = inftl->VUtable[thisVUC]; + prevEUN = BLOCK_NIL; + while (inftl->PUtable[thisEUN] != BLOCK_NIL) { + prevEUN = thisEUN; + thisEUN = inftl->PUtable[thisEUN]; + } + + /* Check if we are all done */ + if (thisEUN == targetEUN) + break; + + if (INFTL_formatblock(inftl, thisEUN) < 0) { + /* + * Could not erase : mark block as reserved. + * FixMe: Update Bad Unit Table on disk. + */ + inftl->PUtable[thisEUN] = BLOCK_RESERVED; + } else { + /* Correctly erased : mark it as free */ + inftl->PUtable[thisEUN] = BLOCK_FREE; + inftl->PUtable[prevEUN] = BLOCK_NIL; + inftl->numfreeEUNs++; + } + } + + return targetEUN; +} + +u16 INFTL_makefreeblock(struct INFTLrecord *inftl, unsigned pendingblock) +{ + /* + * This is the part that needs some cleverness applied. + * For now, I'm doing the minimum applicable to actually + * get the thing to work. + * Wear-levelling and other clever stuff needs to be implemented + * and we also need to do some assessment of the results when + * the system loses power half-way through the routine. + */ + u16 LongestChain = 0; + u16 ChainLength = 0, thislen; + u16 chain, EUN; + + DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_makefreeblock(inftl=0x%x," + "pending=%d)\n", (int)inftl, pendingblock); + + for (chain = 0; chain < inftl->nb_blocks; chain++) { + EUN = inftl->VUtable[chain]; + thislen = 0; + + while (EUN <= inftl->lastEUN) { + thislen++; + EUN = inftl->PUtable[EUN]; + if (thislen > 0xff00) { + printk(KERN_WARNING "INFTL: endless loop in " + "Virtual Chain %d: Unit %x\n", + chain, EUN); + /* + * Actually, don't return failure. + * Just ignore this chain and get on with it. + */ + thislen = 0; + break; + } + } + + if (thislen > ChainLength) { + ChainLength = thislen; + LongestChain = chain; + } + } + + if (ChainLength < 2) { + printk(KERN_WARNING "INFTL: no Virtual Unit Chains available " + "for folding. Failing request\n"); + return BLOCK_NIL; + } + + return INFTL_foldchain(inftl, LongestChain, pendingblock); +} + +static int nrbits(unsigned int val, int bitcount) +{ + int i, total = 0; + + for (i = 0; (i < bitcount); i++) + total += (((0x1 << i) & val) ? 1 : 0); + return total; +} + +/* + * INFTL_findwriteunit: Return the unit number into which we can write + * for this block. Make it available if it isn't already. + */ +static inline u16 INFTL_findwriteunit(struct INFTLrecord *inftl, unsigned block) +{ + unsigned int thisVUC = block / (inftl->EraseSize / SECTORSIZE); + unsigned int thisEUN, writeEUN, prev_block, status; + unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize -1); + struct inftl_oob oob; + struct inftl_bci bci; + unsigned char anac, nacs, parity; + size_t retlen; + int silly, silly2 = 3; + + DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_findwriteunit(inftl=0x%x," + "block=%d)\n", (int)inftl, block); + + do { + /* + * Scan the media to find a unit in the VUC which has + * a free space for the block in question. + */ + writeEUN = BLOCK_NIL; + thisEUN = inftl->VUtable[thisVUC]; + silly = MAX_LOOPS; + + while (thisEUN <= inftl->lastEUN) { + MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) + + blockofs, 8, &retlen, (char *)&bci); + + status = bci.Status | bci.Status1; + DEBUG(MTD_DEBUG_LEVEL3, "INFTL: status of block %d in " + "EUN %d is %x\n", block , writeEUN, status); + + switch(status) { + case SECTOR_FREE: + writeEUN = thisEUN; + break; + case SECTOR_DELETED: + case SECTOR_USED: + /* Can't go any further */ + goto hitused; + case SECTOR_IGNORE: + break; + default: + /* + * Invalid block. Don't use it any more. + * Must implement. + */ + break; + } + + if (!silly--) { + printk(KERN_WARNING "INFTL: infinite loop in " + "Virtual Unit Chain 0x%x\n", thisVUC); + return 0xffff; + } + + /* Skip to next block in chain */ + thisEUN = inftl->PUtable[thisEUN]; + } + +hitused: + if (writeEUN != BLOCK_NIL) + return writeEUN; + + + /* + * OK. We didn't find one in the existing chain, or there + * is no existing chain. Allocate a new one. + */ + writeEUN = INFTL_findfreeblock(inftl, 0); + + if (writeEUN == BLOCK_NIL) { + /* + * That didn't work - there were no free blocks just + * waiting to be picked up. We're going to have to fold + * a chain to make room. + */ + thisEUN = INFTL_makefreeblock(inftl, 0xffff); + + /* + * Hopefully we free something, lets try again. + * This time we are desperate... + */ + DEBUG(MTD_DEBUG_LEVEL1, "INFTL: using desperate==1 " + "to find free EUN to accommodate write to " + "VUC %d\n", thisVUC); + writeEUN = INFTL_findfreeblock(inftl, 1); + if (writeEUN == BLOCK_NIL) { + /* + * Ouch. This should never happen - we should + * always be able to make some room somehow. + * If we get here, we've allocated more storage + * space than actual media, or our makefreeblock + * routine is missing something. + */ + printk(KERN_WARNING "INFTL: cannot make free " + "space.\n"); +#ifdef DEBUG + INFTL_dumptables(inftl); + INFTL_dumpVUchains(inftl); +#endif + return BLOCK_NIL; + } + } + + /* + * Insert new block into virtual chain. Firstly update the + * block headers in flash... + */ + anac = 0; + nacs = 0; + thisEUN = inftl->VUtable[thisVUC]; + if (thisEUN != BLOCK_NIL) { + MTD_READOOB(inftl->mbd.mtd, thisEUN * inftl->EraseSize + + 8, 8, &retlen, (char *)&oob.u); + anac = oob.u.a.ANAC + 1; + nacs = oob.u.a.NACs + 1; + } + + prev_block = inftl->VUtable[thisVUC]; + if (prev_block < inftl->nb_blocks) + prev_block -= inftl->firstEUN; + + parity = (nrbits(thisVUC, 16) & 0x1) ? 0x1 : 0; + parity |= (nrbits(prev_block, 16) & 0x1) ? 0x2 : 0; + parity |= (nrbits(anac, 8) & 0x1) ? 0x4 : 0; + parity |= (nrbits(nacs, 8) & 0x1) ? 0x8 : 0; + + oob.u.a.virtualUnitNo = cpu_to_le16(thisVUC); + oob.u.a.prevUnitNo = cpu_to_le16(prev_block); + oob.u.a.ANAC = anac; + oob.u.a.NACs = nacs; + oob.u.a.parityPerField = parity; + oob.u.a.discarded = 0xaa; + + MTD_WRITEOOB(inftl->mbd.mtd, writeEUN * inftl->EraseSize + 8, 8, + &retlen, (char *)&oob.u); + + /* Also back up header... */ + oob.u.b.virtualUnitNo = cpu_to_le16(thisVUC); + oob.u.b.prevUnitNo = cpu_to_le16(prev_block); + oob.u.b.ANAC = anac; + oob.u.b.NACs = nacs; + oob.u.b.parityPerField = parity; + oob.u.b.discarded = 0xaa; + + MTD_WRITEOOB(inftl->mbd.mtd, writeEUN * inftl->EraseSize + + SECTORSIZE * 4 + 8, 8, &retlen, (char *)&oob.u); + + inftl->PUtable[writeEUN] = inftl->VUtable[thisVUC]; + inftl->VUtable[thisVUC] = writeEUN; + + inftl->numfreeEUNs--; + return writeEUN; + + } while (silly2--); + + printk(KERN_WARNING "INFTL: error folding to make room for Virtual " + "Unit Chain 0x%x\n", thisVUC); + return 0xffff; +} + +/* + * Given a Virtual Unit Chain, see if it can be deleted, and if so do it. + */ +static void INFTL_trydeletechain(struct INFTLrecord *inftl, unsigned thisVUC) +{ + unsigned char BlockUsed[MAX_SECTORS_PER_UNIT]; + unsigned char BlockDeleted[MAX_SECTORS_PER_UNIT]; + unsigned int thisEUN, prevEUN, status; + int block, silly; + struct inftl_bci bci; + size_t retlen; + + DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_trydeletechain(inftl=0x%x," + "thisVUC=%d)\n", (int)inftl, thisVUC); + + memset(BlockUsed, 0, sizeof(BlockUsed)); + memset(BlockDeleted, 0, sizeof(BlockDeleted)); + + thisEUN = inftl->VUtable[thisVUC]; + if (thisEUN == BLOCK_NIL) { + printk(KERN_WARNING "INFTL: trying to delete non-existent " + "Virtual Unit Chain %d!\n", thisVUC); + return; + } + + /* + * Scan through the Erase Units to determine whether any data is in + * each of the 512-byte blocks within the Chain. + */ + silly = MAX_LOOPS; + while (thisEUN < inftl->nb_blocks) { + for (block = 0; block < inftl->EraseSize/SECTORSIZE; block++) { + if (BlockUsed[block] || BlockDeleted[block]) + continue; + + if (MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) + + (block * SECTORSIZE), 8 , &retlen, + (char *)&bci) < 0) + status = SECTOR_IGNORE; + else + status = bci.Status | bci.Status1; + + switch(status) { + case SECTOR_FREE: + case SECTOR_IGNORE: + break; + case SECTOR_USED: + BlockUsed[block] = 1; + continue; + case SECTOR_DELETED: + BlockDeleted[block] = 1; + continue; + default: + printk(KERN_WARNING "INFTL: unknown status " + "for block %d in EUN %d: 0x%x\n", + block, thisEUN, status); + } + } + + if (!silly--) { + printk(KERN_WARNING "INFTL: infinite loop in Virtual " + "Unit Chain 0x%x\n", thisVUC); + return; + } + + thisEUN = inftl->PUtable[thisEUN]; + } + + for (block = 0; block < inftl->EraseSize/SECTORSIZE; block++) + if (BlockUsed[block]) + return; + + /* + * For each block in the chain free it and make it available + * for future use. Erase from the oldest unit first. + */ + DEBUG(MTD_DEBUG_LEVEL1, "INFTL: deleting empty VUC %d\n", thisVUC); + + for (;;) { + /* Find oldest unit in chain. */ + thisEUN = inftl->VUtable[thisVUC]; + prevEUN = BLOCK_NIL; + while (inftl->PUtable[thisEUN] != BLOCK_NIL) { + prevEUN = thisEUN; + thisEUN = inftl->PUtable[thisEUN]; + } + + if (INFTL_formatblock(inftl, thisEUN) < 0) { + /* + * Could not erase : mark block as reserved. + * FixMe: Update Bad Unit Table on disk. + */ + inftl->PUtable[thisEUN] = BLOCK_RESERVED; + } else { + /* Correctly erased : mark it as free */ + inftl->PUtable[thisEUN] = BLOCK_FREE; + inftl->PUtable[prevEUN] = BLOCK_NIL; + inftl->numfreeEUNs++; + } + } + + inftl->VUtable[thisVUC] = BLOCK_NIL; +} + +static int INFTL_deleteblock(struct INFTLrecord *inftl, unsigned block) +{ + unsigned int thisEUN = inftl->VUtable[block / (inftl->EraseSize / SECTORSIZE)]; + unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1); + unsigned int status; + int silly = MAX_LOOPS; + size_t retlen; + struct inftl_bci bci; + + DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_deleteblock(inftl=0x%x," + "block=%d)\n", (int)inftl, block); + + while (thisEUN < inftl->nb_blocks) { + if (MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) + + blockofs, 8, &retlen, (char *)&bci) < 0) + status = SECTOR_IGNORE; + else + status = bci.Status | bci.Status1; + + switch (status) { + case SECTOR_FREE: + case SECTOR_IGNORE: + break; + case SECTOR_DELETED: + thisEUN = BLOCK_NIL; + goto foundit; + case SECTOR_USED: + goto foundit; + default: + printk(KERN_WARNING "INFTL: unknown status for " + "block %d in EUN %d: 0x%x\n", + block, thisEUN, status); + break; + } + + if (!silly--) { + printk(KERN_WARNING "INFTL: infinite loop in Virtual " + "Unit Chain 0x%x\n", + block / (inftl->EraseSize / SECTORSIZE)); + return 1; + } + thisEUN = inftl->PUtable[thisEUN]; + } + +foundit: + if (thisEUN != BLOCK_NIL) { + loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs; + + if (MTD_READOOB(inftl->mbd.mtd, ptr, 8, &retlen, (char *)&bci) < 0) + return -EIO; + bci.Status = bci.Status1 = SECTOR_DELETED; + if (MTD_WRITEOOB(inftl->mbd.mtd, ptr, 8, &retlen, (char *)&bci) < 0) + return -EIO; + INFTL_trydeletechain(inftl, block / (inftl->EraseSize / SECTORSIZE)); + } + return 0; +} + +static int inftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block, + char *buffer) +{ + struct INFTLrecord *inftl = (void *)mbd; + unsigned int writeEUN; + unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1); + size_t retlen; + u8 eccbuf[6]; + char *p, *pend; + + DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_writeblock(inftl=0x%x,block=%d," + "buffer=0x%x)\n", (int)inftl, block, (int)buffer); + + /* Is block all zero? */ + pend = buffer + SECTORSIZE; + for (p = buffer; p < pend && !*p; p++) + ; + + if (p < pend) { + writeEUN = INFTL_findwriteunit(inftl, block); + + if (writeEUN == BLOCK_NIL) { + printk(KERN_WARNING "inftl_writeblock(): cannot find " + "block to write to\n"); + /* + * If we _still_ haven't got a block to use, + * we're screwed. + */ + return 1; + } + + MTD_WRITEECC(inftl->mbd.mtd, (writeEUN * inftl->EraseSize) + + blockofs, SECTORSIZE, &retlen, (char *)buffer, + (char *)eccbuf, NULL); + /* + * No need to write SECTOR_USED flags since they are written + * in mtd_writeecc + */ + } else { + INFTL_deleteblock(inftl, block); + } + + return 0; +} + +static int inftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block, + char *buffer) +{ + struct INFTLrecord *inftl = (void *)mbd; + unsigned int thisEUN = inftl->VUtable[block / (inftl->EraseSize / SECTORSIZE)]; + unsigned long blockofs = (block * SECTORSIZE) & (inftl->EraseSize - 1); + unsigned int status; + int silly = MAX_LOOPS; + struct inftl_bci bci; + size_t retlen; + + DEBUG(MTD_DEBUG_LEVEL3, "INFTL: inftl_readblock(inftl=0x%x,block=%d," + "buffer=0x%x)\n", (int)inftl, block, (int)buffer); + + while (thisEUN < inftl->nb_blocks) { + if (MTD_READOOB(inftl->mbd.mtd, (thisEUN * inftl->EraseSize) + + blockofs, 8, &retlen, (char *)&bci) < 0) + status = SECTOR_IGNORE; + else + status = bci.Status | bci.Status1; + + switch (status) { + case SECTOR_DELETED: + thisEUN = BLOCK_NIL; + goto foundit; + case SECTOR_USED: + goto foundit; + case SECTOR_FREE: + case SECTOR_IGNORE: + break; + default: + printk(KERN_WARNING "INFTL: unknown status for " + "block %ld in EUN %d: 0x%04x\n", + block, thisEUN, status); + break; + } + + if (!silly--) { + printk(KERN_WARNING "INFTL: infinite loop in " + "Virtual Unit Chain 0x%lx\n", + block / (inftl->EraseSize / SECTORSIZE)); + return 1; + } + + thisEUN = inftl->PUtable[thisEUN]; + } + +foundit: + if (thisEUN == BLOCK_NIL) { + /* The requested block is not on the media, return all 0x00 */ + memset(buffer, 0, SECTORSIZE); + } else { + size_t retlen; + loff_t ptr = (thisEUN * inftl->EraseSize) + blockofs; + u_char eccbuf[6]; + if (MTD_READECC(inftl->mbd.mtd, ptr, SECTORSIZE, &retlen, + buffer, eccbuf, NULL)) + return -EIO; + } + return 0; +} + + +static int inftl_ioctl(struct mtd_blktrans_dev *dev, + struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct NFTLrecord *nftl = (void *)dev; + + switch (cmd) { + case HDIO_GETGEO: { + struct hd_geometry g; + + g.heads = nftl->heads; + g.sectors = nftl->sectors; + g.cylinders = nftl->cylinders; + g.start = 0; + return copy_to_user((void *)arg, &g, sizeof g) ? -EFAULT : 0; + } + + default: + return -ENOTTY; + } +} + + +struct mtd_blktrans_ops inftl_tr = { + .name = "inftl", + .major = INFTL_MAJOR, + .part_bits = INFTL_PARTN_BITS, + .ioctl = inftl_ioctl, + .readsect = inftl_readblock, + .writesect = inftl_writeblock, + .add_mtd = inftl_add_mtd, + .remove_dev = inftl_remove_dev, + .owner = THIS_MODULE, +}; + +extern char inftlmountrev[]; + +int __init init_inftl(void) +{ + printk(KERN_INFO "INFTL: inftlcore.c $Revision: 1.9 $, " + "inftlmount.c %s\n", inftlmountrev); + + return register_mtd_blktrans(&inftl_tr); +} + +static void __exit cleanup_inftl(void) +{ + deregister_mtd_blktrans(&inftl_tr); +} + +module_init(init_inftl); +module_exit(cleanup_inftl); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>, David Woodhouse <dwmw2@infradead.org>, Fabrice Bellard <fabrice.bellard@netgem.com> et al."); +MODULE_DESCRIPTION("Support code for Inverse Flash Translation Layer, used on M-Systems DiskOnChip 2000, Millennium and Millennium Plus"); diff -Nru a/drivers/mtd/inftlmount.c b/drivers/mtd/inftlmount.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/inftlmount.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,815 @@ +/* + * inftlmount.c -- INFTL mount code with extensive checks. + * + * Author: Greg Ungerer (gerg@snapgear.com) + * (C) Copyright 2002-2003, Greg Ungerer (gerg@snapgear.com) + * + * Based heavily on the nftlmount.c code which is: + * Author: Fabrice Bellard (fabrice.bellard@netgem.com) + * Copyright (C) 2000 Netgem S.A. + * + * $Id: inftlmount.c,v 1.9 2003/05/23 11:35:07 dwmw2 Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#define __NO_VERSION__ +#include <linux/kernel.h> +#include <linux/module.h> +#include <asm/errno.h> +#include <asm/io.h> +#include <asm/uaccess.h> +#include <linux/miscdevice.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/sched.h> +#include <linux/init.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nftl.h> +#include <linux/mtd/inftl.h> +#include <linux/mtd/compatmac.h> + +char inftlmountrev[]="$Revision: 1.9 $"; + +/* + * find_boot_record: Find the INFTL Media Header and its Spare copy which + * contains the various device information of the INFTL partition and + * Bad Unit Table. Update the PUtable[] table according to the Bad + * Unit Table. PUtable[] is used for management of Erase Unit in + * other routines in inftlcore.c and inftlmount.c. + */ +static int find_boot_record(struct INFTLrecord *inftl) +{ + struct inftl_unittail h1; + //struct inftl_oob oob; + unsigned int i, block, boot_record_count = 0; + u8 buf[SECTORSIZE]; + struct INFTLMediaHeader *mh = &inftl->MediaHdr; + struct INFTLPartition *ip; + int retlen; + + DEBUG(MTD_DEBUG_LEVEL3, "INFTL: find_boot_record(inftl=0x%x)\n", + (int)inftl); + + /* + * Assume logical EraseSize == physical erasesize for starting the + * scan. We'll sort it out later if we find a MediaHeader which says + * otherwise. + */ + inftl->EraseSize = inftl->mbd.mtd->erasesize; + inftl->nb_blocks = inftl->mbd.mtd->size / inftl->EraseSize; + + inftl->MediaUnit = BLOCK_NIL; + inftl->SpareMediaUnit = BLOCK_NIL; + + /* Search for a valid boot record */ + for (block = 0; block < inftl->nb_blocks; block++) { + int ret; + + /* + * Check for BNAND header first. Then whinge if it's found + * but later checks fail. + */ + if ((ret = MTD_READ(inftl->mbd.mtd, block * inftl->EraseSize, + SECTORSIZE, &retlen, buf))) { + static int warncount = 5; + + if (warncount) { + printk(KERN_WARNING "INFTL: block read at 0x%x " + "of mtd%d failed: %d\n", + block * inftl->EraseSize, + inftl->mbd.mtd->index, ret); + if (!--warncount) + printk(KERN_WARNING "INFTL: further " + "failures for this block will " + "not be printed\n"); + } + continue; + } + + if (retlen < 6 || memcmp(buf, "BNAND", 6)) { + /* BNAND\0 not found. Continue */ + continue; + } + + /* To be safer with BIOS, also use erase mark as discriminant */ + if ((ret = MTD_READOOB(inftl->mbd.mtd, block * inftl->EraseSize + + SECTORSIZE + 8, 8, &retlen, (char *)&h1) < 0)) { + printk(KERN_WARNING "INFTL: ANAND header found at " + "0x%x in mtd%d, but OOB data read failed " + "(err %d)\n", block * inftl->EraseSize, + inftl->mbd.mtd->index, ret); + continue; + } + + if (boot_record_count) { + /* + * We've already processed one. So we just check if + * this one is the same as the first one we found. + */ + if (memcmp(mh, buf, sizeof(struct INFTLMediaHeader))) { + printk(KERN_WARNING "INFTL: Media Headers at " + "0x%x and 0x%x disagree.\n", + inftl->MediaUnit * inftl->EraseSize, + block * inftl->EraseSize); + return -1; + } + if (boot_record_count == 1) + inftl->SpareMediaUnit = block; + + /* + * Mark this boot record (INFTL MediaHeader) block as + * reserved. + */ + inftl->PUtable[block] = BLOCK_RESERVED; + + boot_record_count++; + continue; + } + + /* + * This is the first we've seen. + * Copy the media header structure into place. + */ + memcpy(mh, buf, sizeof(struct INFTLMediaHeader)); + mh->NoOfBootImageBlocks = le32_to_cpu(mh->NoOfBootImageBlocks); + mh->NoOfBinaryPartitions = le32_to_cpu(mh->NoOfBinaryPartitions); + mh->NoOfBDTLPartitions = le32_to_cpu(mh->NoOfBDTLPartitions); + mh->BlockMultiplierBits = le32_to_cpu(mh->BlockMultiplierBits); + mh->FormatFlags = le32_to_cpu(mh->FormatFlags); + mh->PercentUsed = le32_to_cpu(mh->PercentUsed); + +#ifdef CONFIG_MTD_DEBUG_VERBOSE + if (CONFIG_MTD_DEBUG_VERBOSE >= 2) { + printk("INFTL: Media Header ->\n" + " bootRecordID = %s\n" + " NoOfBootImageBlocks = %d\n" + " NoOfBinaryPartitions = %d\n" + " NoOfBDTLPartitions = %d\n" + " BlockMultiplerBits = %d\n" + " FormatFlgs = %d\n" + " OsakVersion = 0x%x\n" + " PercentUsed = %d\n", + mh->bootRecordID, mh->NoOfBootImageBlocks, + mh->NoOfBinaryPartitions, + mh->NoOfBDTLPartitions, + mh->BlockMultiplierBits, mh->FormatFlags, + mh->OsakVersion, mh->PercentUsed); + } +#endif + + if (mh->NoOfBDTLPartitions == 0) { + printk(KERN_WARNING "INFTL: Media Header sanity check " + "failed: NoOfBDTLPartitions (%d) == 0, " + "must be at least 1\n", mh->NoOfBDTLPartitions); + return -1; + } + + if ((mh->NoOfBDTLPartitions + mh->NoOfBinaryPartitions) > 4) { + printk(KERN_WARNING "INFTL: Media Header sanity check " + "failed: Total Partitions (%d) > 4, " + "BDTL=%d Binary=%d\n", mh->NoOfBDTLPartitions + + mh->NoOfBinaryPartitions, + mh->NoOfBDTLPartitions, + mh->NoOfBinaryPartitions); + return -1; + } + + if (mh->BlockMultiplierBits > 1) { + printk(KERN_WARNING "INFTL: sorry, we don't support " + "UnitSizeFactor 0x%02x\n", + mh->BlockMultiplierBits); + return -1; + } else if (mh->BlockMultiplierBits == 1) { + printk(KERN_WARNING "INFTL: support for INFTL with " + "UnitSizeFactor 0x%02x is experimental\n", + mh->BlockMultiplierBits); + inftl->EraseSize = inftl->mbd.mtd->erasesize << + (0xff - mh->BlockMultiplierBits); + inftl->nb_blocks = inftl->mbd.mtd->size / inftl->EraseSize; + } + + /* Scan the partitions */ + for (i = 0; (i < 4); i++) { + ip = &mh->Partitions[i]; + ip->virtualUnits = le32_to_cpu(ip->virtualUnits); + ip->firstUnit = le32_to_cpu(ip->firstUnit); + ip->lastUnit = le32_to_cpu(ip->lastUnit); + ip->flags = le32_to_cpu(ip->flags); + ip->spareUnits = le32_to_cpu(ip->spareUnits); + ip->Reserved0 = le32_to_cpu(ip->Reserved0); + +#ifdef CONFIG_MTD_DEBUG_VERBOSE + if (CONFIG_MTD_DEBUG_VERBOSE >= 2) { + printk(" PARTITION[%d] ->\n" + " virtualUnits = %d\n" + " firstUnit = %d\n" + " lastUnit = %d\n" + " flags = 0x%x\n" + " spareUnits = %d\n", + i, ip->virtualUnits, ip->firstUnit, + ip->lastUnit, ip->flags, + ip->spareUnits); + } +#endif + + if (ip->Reserved0 != ip->firstUnit) { + struct erase_info *instr = &inftl->instr; + + /* + * Most likely this is using the + * undocumented qiuck mount feature. + * We don't support that, we will need + * to erase the hidden block for full + * compatibility. + */ + instr->addr = ip->Reserved0 * inftl->EraseSize; + instr->len = inftl->EraseSize; + MTD_ERASE(inftl->mbd.mtd, instr); + } + if ((ip->lastUnit - ip->firstUnit + 1) < ip->virtualUnits) { + printk(KERN_WARNING "INFTL: Media Header " + "Parition %d sanity check failed\n" + " firstUnit %d : lastUnit %d > " + "virtualUnits %d\n", i, ip->lastUnit, + ip->firstUnit, ip->Reserved0); + return -1; + } + if (ip->Reserved1 != 0) { + printk(KERN_WARNING "INFTL: Media Header " + "Parition %d sanity check failed: " + "Reserved1 %d != 0\n", + i, ip->Reserved1); + return -1; + } + + if (ip->flags & INFTL_BDTL) + break; + } + + if (i >= 4) { + printk(KERN_WARNING "INFTL: Media Header Parition " + "sanity check failed:\n No partition " + "marked as Disk Partition\n"); + return -1; + } + + inftl->nb_boot_blocks = ip->firstUnit; + inftl->numvunits = ip->virtualUnits; + if (inftl->numvunits > (inftl->nb_blocks - + inftl->nb_boot_blocks - 2)) { + printk(KERN_WARNING "INFTL: Media Header sanity check " + "failed:\n numvunits (%d) > nb_blocks " + "(%d) - nb_boot_blocks(%d) - 2\n", + inftl->numvunits, inftl->nb_blocks, + inftl->nb_boot_blocks); + return -1; + } + + inftl->mbd.size = inftl->numvunits * + (inftl->EraseSize / SECTORSIZE); + + /* + * Block count is set to last used EUN (we won't need to keep + * any meta-data past that point). + */ + inftl->firstEUN = ip->firstUnit; + inftl->lastEUN = ip->lastUnit; + inftl->nb_blocks = ip->lastUnit + 1; + + /* Memory alloc */ + inftl->PUtable = kmalloc(inftl->nb_blocks * sizeof(u16), GFP_KERNEL); + if (!inftl->PUtable) { + printk(KERN_WARNING "INFTL: allocation of PUtable " + "failed (%d bytes)\n", + inftl->nb_blocks * sizeof(u16)); + return -ENOMEM; + } + + inftl->VUtable = kmalloc(inftl->nb_blocks * sizeof(u16), GFP_KERNEL); + if (!inftl->VUtable) { + kfree(inftl->PUtable); + printk(KERN_WARNING "INFTL: allocation of VUtable " + "failed (%d bytes)\n", + inftl->nb_blocks * sizeof(u16)); + return -ENOMEM; + } + + /* Mark the blocks before INFTL MediaHeader as reserved */ + for (i = 0; i < inftl->nb_boot_blocks; i++) + inftl->PUtable[i] = BLOCK_RESERVED; + /* Mark all remaining blocks as potentially containing data */ + for (; i < inftl->nb_blocks; i++) + inftl->PUtable[i] = BLOCK_NOTEXPLORED; + + /* Mark this boot record (NFTL MediaHeader) block as reserved */ + inftl->PUtable[block] = BLOCK_RESERVED; + +#if 0 + /* Read Bad Erase Unit Table and modify PUtable[] accordingly */ + for (i = 0; i < inftl->nb_blocks; i++) { + if ((i & (SECTORSIZE - 1)) == 0) { + /* read one sector for every SECTORSIZE of blocks */ + if ((ret = MTD_READECC(inftl->mbd.mtd, + block * inftl->EraseSize + i + SECTORSIZE, + SECTORSIZE, &retlen, buf, + (char *)&oob, NULL)) < 0) { + printk(KERN_WARNING "INFTL: read of " + "bad sector table failed " + "(err %d)\n", ret); + kfree(inftl->VUtable); + kfree(inftl->PUtable); + return -1; + } + } + /* Mark the Bad Erase Unit as RESERVED in PUtable */ + if (buf[i & (SECTORSIZE - 1)] != 0xff) + inftl->PUtable[i] = BLOCK_RESERVED; + } +#endif + + inftl->MediaUnit = block; + boot_record_count++; + } + + return boot_record_count ? 0 : -1; +} + +static int memcmpb(void *a, int c, int n) +{ + int i; + for (i = 0; i < n; i++) { + if (c != ((unsigned char *)a)[i]) + return 1; + } + return 0; +} + +/* + * check_free_sector: check if a free sector is actually FREE, + * i.e. All 0xff in data and oob area. + */ +static int check_free_sectors(struct INFTLrecord *inftl, unsigned int address, + int len, int check_oob) +{ + int i, retlen; + u8 buf[SECTORSIZE]; + + DEBUG(MTD_DEBUG_LEVEL3, "INFTL: check_free_sectors(inftl=0x%x," + "address=0x%x,len=%d,check_oob=%d)\n", (int)inftl, + address, len, check_oob); + + for (i = 0; i < len; i += SECTORSIZE) { + /* + * We want to read the sector without ECC check here since a + * free sector does not have ECC syndrome on it yet. + */ + if (MTD_READ(inftl->mbd.mtd, address, SECTORSIZE, &retlen, buf) < 0) + return -1; + if (memcmpb(buf, 0xff, SECTORSIZE) != 0) + return -1; + + if (check_oob) { + if (MTD_READOOB(inftl->mbd.mtd, address, + inftl->mbd.mtd->oobsize, &retlen, buf) < 0) + return -1; + if (memcmpb(buf, 0xff, inftl->mbd.mtd->oobsize) != 0) + return -1; + } + address += SECTORSIZE; + } + + return 0; +} + +/* + * INFTL_format: format a Erase Unit by erasing ALL Erase Zones in the Erase + * Unit and Update INFTL metadata. Each erase operation is + * checked with check_free_sectors. + * + * Return: 0 when succeed, -1 on error. + * + * ToDo: 1. Is it neceressary to check_free_sector after erasing ?? + * 2. UnitSizeFactor != 0xFF + */ +int INFTL_formatblock(struct INFTLrecord *inftl, int block) +{ + int retlen; + struct inftl_unittail uci; + struct erase_info *instr = &inftl->instr; + + DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_formatblock(inftl=0x%x," + "block=%d)\n", (int)inftl, block); + + memset(instr, 0, sizeof(struct erase_info)); + + /* Use async erase interface, test return code */ + instr->addr = block * inftl->EraseSize; + instr->len = inftl->EraseSize; + MTD_ERASE(inftl->mbd.mtd, instr); + + if (instr->state == MTD_ERASE_FAILED) { + /* + * Could not format, FixMe: We should update the BadUnitTable + * both in memory and on disk. + */ + printk(KERN_WARNING "INFTL: error while formatting block %d\n", + block); + return -1; + } + + /* + * Check the "freeness" of Erase Unit before updating metadata. + * FixMe: is this check really necessary? Since we have check the + * return code after the erase operation. + */ + if (check_free_sectors(inftl, instr->addr, inftl->EraseSize, 1) != 0) + return -1; + + uci.EraseMark = cpu_to_le16(ERASE_MARK); + uci.EraseMark1 = cpu_to_le16(ERASE_MARK); + uci.Reserved[0] = 0; + uci.Reserved[1] = 0; + uci.Reserved[2] = 0; + uci.Reserved[3] = 0; + if (MTD_WRITEOOB(inftl->mbd.mtd, block * inftl->EraseSize + SECTORSIZE * 2 + + 8, 8, &retlen, (char *)&uci) < 0) + return -1; + return 0; +} + +/* + * format_chain: Format an invalid Virtual Unit chain. It frees all the Erase + * Units in a Virtual Unit Chain, i.e. all the units are disconnected. + * + * Since the chain is invalid then we will have to erase it from its + * head (normally for INFTL we go from the oldest). But if it has a + * loop then there is no oldest... + */ +static void format_chain(struct INFTLrecord *inftl, unsigned int first_block) +{ + unsigned int block = first_block, block1; + + printk(KERN_WARNING "INFTL: formatting chain at block %d\n", + first_block); + + for (;;) { + block1 = inftl->PUtable[block]; + + printk(KERN_WARNING "INFTL: formatting block %d\n", block); + if (INFTL_formatblock(inftl, block) < 0) { + /* + * Cannot format !!!! Mark it as Bad Unit, + * FixMe: update the BadUnitTable on disk. + */ + inftl->PUtable[block] = BLOCK_RESERVED; + } else { + inftl->PUtable[block] = BLOCK_FREE; + } + + /* Goto next block on the chain */ + block = block1; + + if (block == BLOCK_NIL || block >= inftl->lastEUN) + break; + } +} + +void INFTL_dumptables(struct INFTLrecord *s) +{ + int i; + + printk("-------------------------------------------" + "----------------------------------\n"); + + printk("VUtable[%d] ->", s->nb_blocks); + for (i = 0; i < s->nb_blocks; i++) { + if ((i % 8) == 0) + printk("\n%04x: ", i); + printk("%04x ", s->VUtable[i]); + } + + printk("\n-------------------------------------------" + "----------------------------------\n"); + + printk("PUtable[%d-%d=%d] ->", s->firstEUN, s->lastEUN, s->nb_blocks); + for (i = 0; i <= s->lastEUN; i++) { + if ((i % 8) == 0) + printk("\n%04x: ", i); + printk("%04x ", s->PUtable[i]); + } + + printk("\n-------------------------------------------" + "----------------------------------\n"); + + printk("INFTL ->\n" + " EraseSize = %d\n" + " h/s/c = %d/%d/%d\n" + " numvunits = %d\n" + " firstEUN = %d\n" + " lastEUN = %d\n" + " numfreeEUNs = %d\n" + " LastFreeEUN = %d\n" + " nb_blocks = %d\n" + " nb_boot_blocks = %d", + s->EraseSize, s->heads, s->sectors, s->cylinders, + s->numvunits, s->firstEUN, s->lastEUN, s->numfreeEUNs, + s->LastFreeEUN, s->nb_blocks, s->nb_boot_blocks); + + printk("\n-------------------------------------------" + "----------------------------------\n"); +} + +void INFTL_dumpVUchains(struct INFTLrecord *s) +{ + int logical, block, i; + + printk("-------------------------------------------" + "----------------------------------\n"); + + printk("INFTL Virtual Unit Chains:\n"); + for (logical = 0; logical < s->nb_blocks; logical++) { + block = s->VUtable[logical]; + if (block > s->nb_blocks) + continue; + printk(" LOGICAL %d --> %d ", logical, block); + for (i = 0; i < s->nb_blocks; i++) { + if (s->PUtable[block] == BLOCK_NIL) + break; + block = s->PUtable[block]; + printk("%d ", block); + } + printk("\n"); + } + + printk("-------------------------------------------" + "----------------------------------\n"); +} + +int INFTL_mount(struct INFTLrecord *s) +{ + unsigned int block, first_block, prev_block, last_block; + unsigned int first_logical_block, logical_block, erase_mark; + int chain_length, do_format_chain; + struct inftl_unithead1 h0; + struct inftl_unittail h1; + int i, retlen; + u8 *ANACtable, ANAC; + + DEBUG(MTD_DEBUG_LEVEL3, "INFTL: INFTL_mount(inftl=0x%x)\n", (int)s); + + /* Search for INFTL MediaHeader and Spare INFTL Media Header */ + if (find_boot_record(s) < 0) { + printk(KERN_WARNING "INFTL: could not find valid boot record?\n"); + return -1; + } + + /* Init the logical to physical table */ + for (i = 0; i < s->nb_blocks; i++) + s->VUtable[i] = BLOCK_NIL; + + logical_block = block = BLOCK_NIL; + + /* Temporary buffer to store ANAC numbers. */ + ANACtable = kmalloc(s->nb_blocks * sizeof(u8), GFP_KERNEL); + memset(ANACtable, 0, s->nb_blocks); + + /* + * First pass is to explore each physical unit, and construct the + * virtual chains that exist (newest physical unit goes into VUtable). + * Any block that is in any way invalid will be left in the + * NOTEXPLORED state. Then at the end we will try to format it and + * mark it as free. + */ + DEBUG(MTD_DEBUG_LEVEL3, "INFTL: pass 1, explore each unit\n"); + for (first_block = s->firstEUN; first_block <= s->lastEUN; first_block++) { + if (s->PUtable[first_block] != BLOCK_NOTEXPLORED) + continue; + + do_format_chain = 0; + first_logical_block = BLOCK_NIL; + last_block = BLOCK_NIL; + block = first_block; + + for (chain_length = 0; ; chain_length++) { + + if ((chain_length == 0) && + (s->PUtable[block] != BLOCK_NOTEXPLORED)) { + /* Nothing to do here, onto next block */ + break; + } + + if (MTD_READOOB(s->mbd.mtd, block * s->EraseSize + 8, + 8, &retlen, (char *)&h0) < 0 || + MTD_READOOB(s->mbd.mtd, block * s->EraseSize + + 2 * SECTORSIZE + 8, 8, &retlen, (char *)&h1) < 0) { + /* Should never happen? */ + do_format_chain++; + break; + } + + logical_block = le16_to_cpu(h0.virtualUnitNo); + prev_block = le16_to_cpu(h0.prevUnitNo); + erase_mark = le16_to_cpu((h1.EraseMark | h1.EraseMark1)); + ANACtable[block] = h0.ANAC; + + /* Previous block is relative to start of Partition */ + if (prev_block < s->nb_blocks) + prev_block += s->firstEUN; + + /* Already explored paritial chain? */ + if (s->PUtable[block] != BLOCK_NOTEXPLORED) { + /* Check if chain for this logical */ + if (logical_block == first_logical_block) { + if (last_block != BLOCK_NIL) + s->PUtable[last_block] = block; + } + break; + } + + /* Check for invalid block */ + if (erase_mark != ERASE_MARK) { + printk(KERN_WARNING "INFTL: corrupt block %d " + "in chain %d, chain length %d, erase " + "mark 0x%x?\n", block, first_block, + chain_length, erase_mark); + /* + * Assume end of chain, probably incomplete + * fold/erase... + */ + if (chain_length == 0) + do_format_chain++; + break; + } + + /* Check for it being free already then... */ + if ((logical_block == BLOCK_FREE) || + (logical_block == BLOCK_NIL)) { + s->PUtable[block] = BLOCK_FREE; + break; + } + + /* Sanity checks on block numbers */ + if ((logical_block >= s->nb_blocks) || + ((prev_block >= s->nb_blocks) && + (prev_block != BLOCK_NIL))) { + if (chain_length > 0) { + printk(KERN_WARNING "INFTL: corrupt " + "block %d in chain %d?\n", + block, first_block); + do_format_chain++; + } + break; + } + + if (first_logical_block == BLOCK_NIL) { + first_logical_block = logical_block; + } else { + if (first_logical_block != logical_block) { + /* Normal for folded chain... */ + break; + } + } + + /* + * Current block is valid, so if we followed a virtual + * chain to get here then we can set the previous + * block pointer in our PUtable now. Then move onto + * the previous block in the chain. + */ + s->PUtable[block] = BLOCK_NIL; + if (last_block != BLOCK_NIL) + s->PUtable[last_block] = block; + last_block = block; + block = prev_block; + + /* Check for end of chain */ + if (block == BLOCK_NIL) + break; + + /* Validate next block before following it... */ + if (block > s->lastEUN) { + printk(KERN_WARNING "INFTL: invalid previous " + "block %d in chain %d?\n", block, + first_block); + do_format_chain++; + break; + } + } + + if (do_format_chain) { + format_chain(s, first_block); + continue; + } + + /* + * Looks like a valid chain then. It may not really be the + * newest block in the chain, but it is the newest we have + * found so far. We might update it in later iterations of + * this loop if we find something newer. + */ + s->VUtable[first_logical_block] = first_block; + logical_block = BLOCK_NIL; + } + +#ifdef CONFIG_MTD_DEBUG_VERBOSE + if (CONFIG_MTD_DEBUG_VERBOSE >= 2) + INFTL_dumptables(s); +#endif + + /* + * Second pass, check for infinite loops in chains. These are + * possible because we don't update the previous pointers when + * we fold chains. No big deal, just fix them up in PUtable. + */ + DEBUG(MTD_DEBUG_LEVEL3, "INFTL: pass 2, validate virtual chains\n"); + for (logical_block = 0; logical_block < s->numvunits; logical_block++) { + block = s->VUtable[logical_block]; + last_block = BLOCK_NIL; + + /* Check for free/reserved/nil */ + if (block >= BLOCK_RESERVED) + continue; + + ANAC = ANACtable[block]; + for (i = 0; i < s->numvunits; i++) { + if (s->PUtable[block] == BLOCK_NIL) + break; + if (s->PUtable[block] > s->lastEUN) { + printk(KERN_WARNING "INFTL: invalid prev %d, " + "in virtual chain %d\n", + s->PUtable[block], logical_block); + s->PUtable[block] = BLOCK_NIL; + + } + if (ANACtable[block] != ANAC) { + /* + * Chain must point back to itself. This is ok, + * but we will need adjust the tables with this + * newest block and oldest block. + */ + s->VUtable[logical_block] = block; + s->PUtable[last_block] = BLOCK_NIL; + break; + } + + ANAC--; + last_block = block; + block = s->PUtable[block]; + } + + if (i >= s->nb_blocks) { + /* + * Uhoo, infinite chain with valid ANACS! + * Format whole chain... + */ + format_chain(s, first_block); + } + } + +#ifdef CONFIG_MTD_DEBUG_VERBOSE + if (CONFIG_MTD_DEBUG_VERBOSE >= 2) + INFTL_dumptables(s); + if (CONFIG_MTD_DEBUG_VERBOSE >= 2) + INFTL_dumpVUchains(s); +#endif + + /* + * Third pass, format unreferenced blocks and init free block count. + */ + s->numfreeEUNs = 0; + s->LastFreeEUN = BLOCK_NIL; + + DEBUG(MTD_DEBUG_LEVEL3, "INFTL: pass 3, format unused blocks\n"); + for (block = s->firstEUN; block <= s->lastEUN; block++) { + if (s->PUtable[block] == BLOCK_NOTEXPLORED) { + printk("INFTL: unreferenced block %d, formatting it\n", + block); + if (INFTL_formatblock(s, block) < 0) + s->PUtable[block] = BLOCK_RESERVED; + else + s->PUtable[block] = BLOCK_FREE; + } + if (s->PUtable[block] == BLOCK_FREE) { + s->numfreeEUNs++; + if (s->LastFreeEUN == BLOCK_NIL) + s->LastFreeEUN = block; + } + } + + kfree(ANACtable); + return 0; +} diff -Nru a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig --- a/drivers/mtd/maps/Kconfig Mon Jun 9 23:16:19 2003 +++ b/drivers/mtd/maps/Kconfig Mon Jun 9 23:16:19 2003 @@ -1,9 +1,16 @@ -# drivers/mtd/maps/Config.in -# $Id: Config.in,v 1.16 2001/09/19 18:28:37 dwmw2 Exp $ +# drivers/mtd/maps/Kconfig +# $Id: Kconfig,v 1.11 2003/05/28 15:16:56 dwmw2 Exp $ menu "Mapping drivers for chip access" depends on MTD!=n +config MTD_COMPLEX_MAPPINGS + bool "Support non-linear mappings of flash chips" + depends on MTD + help + This causes the chip drivers to allow for complicated + paged mappings of flash chips. + config MTD_PHYSMAP tristate "CFI Flash device in physical memory map" depends on MTD_CFI @@ -80,7 +87,7 @@ config MTD_SBC_GXX tristate "CFI Flash device mapped on Arcom SBC-GXx boards" - depends on X86 && MTD_CFI_INTELEXT && MTD_PARTITIONS + depends on X86 && MTD_CFI_INTELEXT && MTD_PARTITIONS && MTD_COMPLEX_MAPPINGS help This provides a driver for the on-board flash of Arcom Control Systems' SBC-GXn family of boards, formerly known as SBC-MediaGX. @@ -91,7 +98,7 @@ config MTD_ELAN_104NC tristate "CFI Flash device mapped on Arcom ELAN-104NC" - depends on X86 && MTD_CFI_INTELEXT && MTD_PARTITIONS + depends on X86 && MTD_CFI_INTELEXT && MTD_PARTITIONS && MTD_COMPLEX_MAPPINGS help This provides a driver for the on-board flash of the Arcom Control System's ELAN-104NC development board. By default the flash @@ -99,20 +106,16 @@ devices. This board utilizes Intel StrataFlash. More info at <http://www.arcomcontrols.com/products/icp/pc104/processors/>. -config MTD_MIXMEM - tristate "JEDEC Flash device mapped on Mixcom piggyback card" - depends on X86 && MTD_JEDEC - help - This supports the paging arrangement for access to flash chips - on the MixCOM piggyback card, allowing the flash chip drivers - to get on with their job of driving the flash chips without - having to know about the paging. If you have one of these boards, - you probably want to enable this mapping driver. More info is at - <http://www.itc.hu/>. +config MTD_LUBBOCK + tristate "CFI Flash device mapped on Intel Lubbock XScale eval board" + depends on ARCH_LUBBOCK && MTD_CFI_INTELEXT && MTD_PARTITIONS + help + This provides a driver for the on-board flash of the Intel + 'Lubbock' XScale evaluation board. config MTD_OCTAGON tristate "JEDEC Flash device mapped on Octagon 5066 SBC" - depends on X86 && MTD_JEDEC + depends on X86 && MTD_JEDEC && MTD_COMPLEX_MAPPINGS help This provides a 'mapping' driver which supports the way in which the flash chips are connected in the Octagon-5066 Single Board @@ -121,7 +124,7 @@ config MTD_VMAX tristate "JEDEC Flash device mapped on Tempustech VMAX SBC301" - depends on X86 && MTD_JEDEC + depends on X86 && MTD_JEDEC && MTD_COMPLEX_MAPPINGS help This provides a 'mapping' driver which supports the way in which the flash chips are connected in the Tempustech VMAX SBC301 Single @@ -139,9 +142,93 @@ If compiled as a module, it will be called scx200_docflash. +config MTD_AMD76XROM + tristate "BIOS flash chip on AMD76x southbridge" + depends on X86 && MTD_JEDECPROBE + help + Support for treating the BIOS flash chip on AMD76x motherboards + as an MTD device - with this you can reprogram your BIOS. + + BE VERY CAREFUL. + +config MTD_ICH2ROM + tristate "BIOS flash chip on Intel Hub Controller 2" + depends on X86 && MTD_JEDECPROBE && MTD_COMPLEX_MAPPINGS + help + Support for treating the BIOS flash chip on ICH2 motherboards + as an MTD device - with this you can reprogram your BIOS. + + BE VERY CAREFUL. + +config MTD_SCB2_FLASH + tristate "BIOS flash chip on Intel SCB2 boards" + depends on X86 && MTD_JEDECPROBE + help + Support for treating the BIOS flash chip on Intel SCB2 boards + as an MTD device - with this you can reprogram your BIOS. + + BE VERY CAREFUL. + +config MTD_TSUNAMI + tristate "Flash chips on Tsunami TIG bus" + depends on ALPHA_TSUNAMI && MTD_COMPLEX_MAPPINGS + help + Support for the flash chip on Tsunami TIG bus. + +config MTD_LASAT + tristate "Flash chips on LASAT board" + depends on LASAT && MTD_CFI + help + Support for the flash chips on the Lasat 100 and 200 boards. + +config MTD_NETtel + tristate "CFI flash device on SnapGear/SecureEdge" + depends on X86 && MTD_PARTITIONS && MTD_JEDECPROBE + help + Support for flash chips on NETtel/SecureEdge/SnapGear boards. + +config MTD_PB1XXX + tristate "Flash devices on Alchemy PB1xxx boards" + depends on MIPS && ( MIPS_PB1000 || MIPS_PB1100 || MIPS_PB1500 ) + help + Flash memory access on Alchemy Pb1000/Pb1100/Pb1500 boards + +config MTD_PB1XXX_BOOT + bool "PB1x00 boot flash device" + depends on MTD_PB1XXX && ( MIPS_PB1100 || MIPS_PB1500 ) + help + Use the first of the two 32MiB flash banks on Pb1100/Pb1500 board. + You can say 'Y' to both this and 'MTD_PB1XXX_USER' below, to use + both banks. + +config MTD_PB1XXX_USER + bool "PB1x00 user flash device" + depends on MTD_PB1XXX && ( MIPS_PB1100 || MIPS_PB1500 ) + default y if MTD_PB1XX_BOOT = n + help + Use the second of the two 32MiB flash banks on Pb1100/Pb1500 board. + You can say 'Y' to both this and 'MTD_PB1XXX_BOOT' above, to use + both banks. + +config MTD_DILNETPC + tristate "CFI Flash device mapped on DIL/Net PC" + depends on X86 && MTD_CONCAT && MTD_PARTITIONS && MTD_CFI_INTELEXT + help + MTD map driver for SSV DIL/Net PC Boards "DNP" and "ADNP". + For details, see http://www.ssv-embedded.de/ssv/pc104/p169.htm + and http://www.ssv-embedded.de/ssv/pc104/p170.htm + +config MTD_DILNETPC_BOOTSIZE + hex "Size of DIL/Net PC flash boot partition" + depends on MTD_DILNETPC + default "0x80000" + help + The amount of space taken up by the kernel or Etherboot + on the DIL/Net PC flash chips. + config MTD_L440GX tristate "BIOS flash chip on Intel L440GX boards" - depends on X86 && MTD_JEDEC + depends on X86 && MTD_JEDECPROBE help Support for treating the BIOS flash chip on Intel L440GX motherboards as an MTD device - with this you can reprogram your BIOS. @@ -150,7 +237,7 @@ config MTD_TQM8XXL tristate "CFI Flash device mapped on TQM8XXL" - depends on MTD_CFI && TQM8xxL && PPC + depends on MTD_CFI && PPC32 && 8xx && TQM8xxL help The TQM8xxL PowerPC board has up to two banks of CFI-compliant chips, currently uses AMD one. This 'mapping' driver supports @@ -160,7 +247,7 @@ config MTD_RPXLITE tristate "CFI Flash device mapped on RPX Lite or CLLF" - depends on MTD_CFI && PPC + depends on MTD_CFI && PPC32 && 8xx && (RPXCLASSIC || RPXLITE) help The RPXLite PowerPC board has CFI-compliant chips mapped in a strange sparse mapping. This 'mapping' driver supports that @@ -168,9 +255,17 @@ to communicate with the chips on the RPXLite board. More at <http://www.embeddedplanet.com/rpx_lite_specification_sheet.htm>. +config MTD_MBX860 + tristate "System flash on MBX860 board" + depends on MTD_CFI && PPC32 && 8xx && MBX + help + This enables access routines for the flash chips on the Motorola + MBX860 board. If you have one of these boards and would like + to use the flash chips on it, say 'Y'. + config MTD_DBOX2 tristate "CFI Flash device mapped on D-Box2" - depends on PPC && MTD_CFI_INTELSTD && MTD_CFI_INTELEXT && MTD_CFI_AMDSTD + depends on PPC32 && 8xx && MTD_CFI_INTELSTD && MTD_CFI_INTELEXT && MTD_CFI_AMDSTD help This enables access routines for the flash chips on the Nokia/Sagem D-Box 2 board. If you have one of these boards and would like to use @@ -178,15 +273,47 @@ config MTD_CFI_FLAGADM tristate "CFI Flash device mapping on FlagaDM" - depends on PPC && MTD_CFI + depends on PPC32 && 8xx && MTD_CFI help Mapping for the Flaga digital module. If you don´t have one, ignore this setting. +config MTD_BEECH + tristate "CFI Flash device mapped on IBM 405LP Beech" + depends on MTD_CFI && PPC32 && 40x && BEECH + help + This enables access routines for the flash chips on the IBM + 405LP Beech board. If you have one of these boards and would like + to use the flash chips on it, say 'Y'. + +config MTD_ARCTIC + tristate "CFI Flash device mapped on IBM 405LP Arctic" + depends on MTD_CFI && PPC32 && 40x && ARCTIC2 + help + This enables access routines for the flash chips on the IBM 405LP + Arctic board. If you have one of these boards and would like to + use the flash chips on it, say 'Y'. + +config MTD_EBONY + tristate "CFI Flash device mapped on IBM 440GP Ebony" + depends on MTD_CFI && PPC32 && 440 && EBONY + help + This enables access routines for the flash chips on the IBM 440GP + Ebony board. If you have one of these boards and would like to + use the flash chips on it, say 'Y'. + +config MTD_REDWOOD + tristate "CFI Flash devices mapped on IBM Redwood" + depends on MTD_CFI && PPC32 && 4xx && 40x && ( REDWOOD_4 || REDWOOD_5 || REDWOOD_6 ) + help + This enables access routines for the flash chips on the IBM + Redwood board. If you have one of these boards and would like to + use the flash chips on it, say 'Y'. + config MTD_CSTM_MIPS_IXX tristate "Flash chip mapping on ITE QED-4N-S01B, Globespan IVR or custom board" - depends on MIPS && MTD_CFI && MTD_JEDEC && MTD_PARTITIONS - ---help--- + depends on MIPS && MTD_CFI && MTD_JEDECPROBE && MTD_PARTITIONS + help This provides a mapping driver for the Integrated Tecnology Express, Inc (ITE) QED-4N-S01B eval board and the Globespan IVR Reference Board. It provides the necessary addressing, length, @@ -242,12 +369,6 @@ This enables access to the flash chips on the Hitachi SolutionEngine and similar boards. Say 'Y' if you are building a kernel for such a board. -config MTD_NORA - tristate "CFI Flash device mapped on Nora" - depends on ARM && MTD_CFI - help - If you had to ask, you don't have one. Say 'N'. - config MTD_ARM_INTEGRATOR tristate "CFI Flash device mapped on ARM Integrator/P720T" depends on ARM && MTD_CFI @@ -269,7 +390,7 @@ config MTD_DC21285 tristate "CFI Flash device mapped on DC21285 Footbridge" - depends on ARM && MTD_CFI && ARCH_FOOTBRIDGE + depends on ARM && MTD_CFI && ARCH_FOOTBRIDGE && MTD_COMPLEX_MAPPINGS help This provides a driver for the flash accessed using Intel's 21285 bridge used with Intel's StrongARM processors. More info at @@ -283,14 +404,6 @@ IQ80310 evaluation board. If you have one of these boards and would like to use the flash chips on it, say 'Y'. -config MTD_IQ80321 - tristate "CFI Flash device mapped on the XScale IQ80321 board" - depends on ARM && MTD_CFI && ARCH_IQ80321 - help - This enables access routines for the flash chips on the Intel XScale - IQ80321 evaluation board. If you have one of these boards and would - like to use the flash chips on it, say 'Y'. - config MTD_EPXA10DB tristate "CFI Flash device mapped on Epxa10db" depends on ARM && MTD_CFI && MTD_PARTITIONS && ARCH_CAMELOT @@ -335,10 +448,17 @@ PhotoMax Digital Picture Frame. If you have such a device, say 'Y'. +config MTD_H720X + tristate "Hynix evaluation board mappings" + depends on ARM && MTD_CFI && ( ARCH_H7201 || ARCH_H7202 ) + help + This enables access to the flash chips on the Hynix evaluation boards. + If you have such a board, say 'Y'. + # This needs CFI or JEDEC, depending on the cards found. config MTD_PCI tristate "PCI MTD driver" - depends on MTD && PCI + depends on MTD && PCI && MTD_COMPLEX_MAPPINGS help Mapping for accessing flash devices on add-in cards like the Intel XScale IQ80310 card, and the Intel EBSA285 card in blank ROM programming mode @@ -348,7 +468,7 @@ config MTD_PCMCIA tristate "PCMCIA MTD driver" - depends on MTD && PCMCIA + depends on MTD && PCMCIA && MTD_COMPLEX_MAPPINGS help Map driver for accessing PCMCIA linear flash memory cards. These cards are usually around 4-16MiB in size. This does not include diff -Nru a/drivers/mtd/maps/Makefile b/drivers/mtd/maps/Makefile --- a/drivers/mtd/maps/Makefile Mon Jun 9 23:16:05 2003 +++ b/drivers/mtd/maps/Makefile Mon Jun 9 23:16:05 2003 @@ -1,7 +1,11 @@ # # linux/drivers/maps/Makefile # -# $Id: Makefile,v 1.13 2001/08/16 15:16:58 rmk Exp $ +# $Id: Makefile.common,v 1.2 2003/05/28 10:48:41 dwmw2 Exp $ + +ifeq ($(CONFIG_MTD_COMPLEX_MAPPINGS),y) +obj-$(CONFIG_MTD) += map_funcs.o +endif # Chip mappings obj-$(CONFIG_MTD_CDB89712) += cdb89712.o @@ -9,12 +13,16 @@ obj-$(CONFIG_MTD_CFI_FLAGADM) += cfi_flagadm.o obj-$(CONFIG_MTD_CSTM_MIPS_IXX) += cstm_mips_ixx.o obj-$(CONFIG_MTD_DC21285) += dc21285.o +obj-$(CONFIG_MTD_DILNETPC) += dilnetpc.o obj-$(CONFIG_MTD_ELAN_104NC) += elan-104nc.o obj-$(CONFIG_MTD_EPXA10DB) += epxa10db-flash.o obj-$(CONFIG_MTD_IQ80310) += iq80310.o -obj-$(CONFIG_MTD_IQ80321) += iq80321.o obj-$(CONFIG_MTD_L440GX) += l440gx.o -obj-$(CONFIG_MTD_NORA) += nora.o +obj-$(CONFIG_MTD_AMD76XROM) += amd76xrom.o +obj-$(CONFIG_MTD_ICH2ROM) += ich2rom.o +obj-$(CONFIG_MTD_TSUNAMI) += tsunami_flash.o +obj-$(CONFIG_MTD_LUBBOCK) += lubbock-flash.o +obj-$(CONFIG_MTD_MBX860) += mbx860.o obj-$(CONFIG_MTD_CEIVA) += ceiva.o obj-$(CONFIG_MTD_OCTAGON) += octagon-5066.o obj-$(CONFIG_MTD_PHYSMAP) += physmap.o @@ -31,10 +39,19 @@ obj-$(CONFIG_MTD_SCx200_DOCFLASH)+= scx200_docflash.o obj-$(CONFIG_MTD_DBOX2) += dbox2-flash.o obj-$(CONFIG_MTD_OCELOT) += ocelot.o -obj-$(CONFIG_MTD_UCLINUX) += uclinux.o obj-$(CONFIG_MTD_SOLUTIONENGINE)+= solutionengine.o obj-$(CONFIG_MTD_PCI) += pci.o +obj-$(CONFIG_MTD_PB1XXX) += pb1xxx-flash.o +obj-$(CONFIG_MTD_LASAT) += lasat.o obj-$(CONFIG_MTD_AUTCPU12) += autcpu12-nvram.o obj-$(CONFIG_MTD_EDB7312) += edb7312.o obj-$(CONFIG_MTD_IMPA7) += impa7.o obj-$(CONFIG_MTD_FORTUNET) += fortunet.o +obj-$(CONFIG_MTD_REDWOOD) += redwood.o +obj-$(CONFIG_MTD_UCLINUX) += uclinux.o +obj-$(CONFIG_MTD_NETtel) += nettel.o +obj-$(CONFIG_MTD_SCB2_FLASH) += scb2_flash.o +obj-$(CONFIG_MTD_EBONY) += ebony.o +obj-$(CONFIG_MTD_BEECH) += beech-mtd.o +obj-$(CONFIG_MTD_ARCTIC) += arctic-mtd.o +obj-$(CONFIG_MTD_H720X) += h720x-flash.o diff -Nru a/drivers/mtd/maps/amd76xrom.c b/drivers/mtd/maps/amd76xrom.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/amd76xrom.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,215 @@ +/* + * amd76xrom.c + * + * Normal mappings of chips in physical memory + * $Id: amd76xrom.c,v 1.8 2003/05/28 15:44:28 dwmw2 Exp $ + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <asm/io.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/config.h> +#include <linux/pci.h> +#include <linux/pci_ids.h> + + +struct amd76xrom_map_info { + struct map_info map; + struct mtd_info *mtd; + unsigned long window_addr; + u32 window_start, window_size; + struct pci_dev *pdev; +}; + + +static struct amd76xrom_map_info amd76xrom_map = { + .map = { + .name = "AMD76X rom", + .size = 0, + .buswidth = 1, + }, + .mtd = 0, + .window_addr = 0, +}; + +static int __devinit amd76xrom_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct rom_window { + u32 start; + u32 size; + u8 segen_bits; + }; + static struct rom_window rom_window[] = { + { 0xffb00000, 5*1024*1024, (1<<7) | (1<<6), }, + { 0xffc00000, 4*1024*1024, (1<<7), }, + { 0xffff0000, 64*1024, 0 }, + { 0 , 0, 0 }, + }; + static const u32 rom_probe_sizes[] = { + 5*1024*1024, 4*1024*1024, 2*1024*1024, 1024*1024, 512*1024, + 256*1024, 128*1024, 64*1024, 0}; + static char *rom_probe_types[] = { "cfi_probe", "jedec_probe", 0 }; + u8 byte; + struct amd76xrom_map_info *info = &amd76xrom_map; + struct rom_window *window; + int i; + u32 rom_size; + + window = &rom_window[0]; + + /* disabled because it fights with BIOS reserved regions */ +#define REQUEST_MEM_REGION 0 +#if REQUEST_MEM_REGION + while(window->size) { + if (request_mem_region(window->start, window->size, "amd76xrom")) { + break; + } + window++; + } + if (!window->size) { + printk(KERN_ERR "amd76xrom: cannot reserve rom window\n"); + goto err_out_none; + } +#endif /* REQUEST_MEM_REGION */ + + /* Enable the selected rom window */ + pci_read_config_byte(pdev, 0x43, &byte); + pci_write_config_byte(pdev, 0x43, byte | window->segen_bits); + + /* Enable writes through the rom window */ + pci_read_config_byte(pdev, 0x40, &byte); + pci_write_config_byte(pdev, 0x40, byte | 1); + + /* FIXME handle registers 0x80 - 0x8C the bios region locks */ + + printk(KERN_NOTICE "amd76xrom window : %x at %x\n", + window->size, window->start); + /* For write accesses caches are useless */ + info->window_addr = (unsigned long)ioremap_nocache(window->start, window->size); + + if (!info->window_addr) { + printk(KERN_ERR "Failed to ioremap\n"); + goto err_out_free_mmio_region; + } + info->mtd = 0; + for(i = 0; (rom_size = rom_probe_sizes[i]); i++) { + char **chip_type; + if (rom_size > window->size) { + continue; + } + info->map.phys = window->start + window->size - rom_size; + info->map.virt = + info->window_addr + window->size - rom_size; + info->map.size = rom_size; + simple_map_init(&info->map); + chip_type = rom_probe_types; + for(; !info->mtd && *chip_type; chip_type++) { + info->mtd = do_map_probe(*chip_type, &amd76xrom_map.map); + } + if (info->mtd) { + break; + } + } + if (!info->mtd) { + goto err_out_iounmap; + } + printk(KERN_NOTICE "amd76xrom chip at offset: 0x%x\n", + window->size - rom_size); + + info->mtd->owner = THIS_MODULE; + add_mtd_device(info->mtd); + info->window_start = window->start; + info->window_size = window->size; + return 0; + +err_out_iounmap: + iounmap((void *)(info->window_addr)); +err_out_free_mmio_region: +#if REQUEST_MEM_REGION + release_mem_region(window->start, window->size); +err_out_none: +#endif /* REQUEST_MEM_REGION */ + return -ENODEV; +} + + +static void __devexit amd76xrom_remove_one (struct pci_dev *pdev) +{ + struct amd76xrom_map_info *info = &amd76xrom_map; + u8 byte; + + del_mtd_device(info->mtd); + map_destroy(info->mtd); + info->mtd = 0; + info->map.virt = 0; + + iounmap((void *)(info->window_addr)); + info->window_addr = 0; + + /* Disable writes through the rom window */ + pci_read_config_byte(pdev, 0x40, &byte); + pci_write_config_byte(pdev, 0x40, byte & ~1); + +#if REQUEST_MEM_REGION + release_mem_region(info->window_start, info->window_size); +#endif /* REQUEST_MEM_REGION */ +} + +static struct pci_device_id amd76xrom_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7410, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_VIPER_7440, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_AMD, 0x7468 }, /* amd8111 support */ + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, amd76xrom_pci_tbl); + +#if 0 +static struct pci_driver amd76xrom_driver = { + .name = "amd76xrom", + .id_table = amd76xrom_pci_tbl, + .probe = amd76xrom_init_one, + .remove = amd76xrom_remove_one, +}; +#endif + +int __init init_amd76xrom(void) +{ + struct pci_dev *pdev; + struct pci_device_id *id; + pdev = 0; + for(id = amd76xrom_pci_tbl; id->vendor; id++) { + pdev = pci_find_device(id->vendor, id->device, 0); + if (pdev) { + break; + } + } + if (pdev) { + amd76xrom_map.pdev = pdev; + return amd76xrom_init_one(pdev, &amd76xrom_pci_tbl[0]); + } + return -ENXIO; +#if 0 + return pci_module_init(&amd76xrom_driver); +#endif +} + +static void __exit cleanup_amd76xrom(void) +{ + amd76xrom_remove_one(amd76xrom_map.pdev); +} + +module_init(init_amd76xrom); +module_exit(cleanup_amd76xrom); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Eric Biederman <ebiederman@lnxi.com>"); +MODULE_DESCRIPTION("MTD map driver for BIOS chips on the AMD76X southbridge"); + diff -Nru a/drivers/mtd/maps/arctic-mtd.c b/drivers/mtd/maps/arctic-mtd.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/arctic-mtd.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,128 @@ +/* + * $Id: arctic-mtd.c,v 1.8 2003/05/21 12:45:17 dwmw2 Exp $ + * + * drivers/mtd/maps/arctic-mtd.c MTD mappings and partition tables for + * IBM 405LP Arctic boards. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the 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 + * + * Copyright (C) 2002, International Business Machines Corporation + * All Rights Reserved. + * + * Bishop Brock + * IBM Research, Austin Center for Low-Power Computing + * bcbrock@us.ibm.com + * March 2002 + * + * modified for Arctic by, + * David Gibson + * IBM OzLabs, Canberra, Australia + * <arctic@gibson.dropbear.id.au> + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/init.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> + +#include <asm/io.h> +#include <asm/ibm4xx.h> + +/* + * fe000000 -- ff9fffff Arctic FFS (26MB) + * ffa00000 -- fff5ffff kernel (5.504MB) + * fff60000 -- ffffffff firmware (640KB) + */ + +#define ARCTIC_FFS_SIZE 0x01a00000 /* 26 M */ +#define ARCTIC_FIRMWARE_SIZE 0x000a0000 /* 640K */ + +#define NAME "Arctic Linux Flash" +#define PADDR SUBZERO_BOOTFLASH_PADDR +#define SIZE SUBZERO_BOOTFLASH_SIZE +#define BUSWIDTH 2 + +/* Flash memories on these boards are memory resources, accessed big-endian. */ + +{ + /* do nothing for now */ +} + +static struct map_info arctic_mtd_map = { + .name = NAME, + .size = SIZE, + .buswidth = BUSWIDTH, + .phys = PADDR, +}; + +static struct mtd_info *arctic_mtd; + +static struct mtd_partition arctic_partitions[3] = { + { .name = "Arctic FFS", + .size = ARCTIC_FFS_SIZE, + .offset = 0,}, + { .name = "Kernel", + .size = SUBZERO_BOOTFLASH_SIZE - ARCTIC_FFS_SIZE - + ARCTIC_FIRMWARE_SIZE, + .offset = ARCTIC_FFS_SIZE,}, + { .name = "Firmware", + .size = ARCTIC_FIRMWARE_SIZE, + .offset = SUBZERO_BOOTFLASH_SIZE - ARCTIC_FIRMWARE_SIZE,}, +}; + +static int __init +init_arctic_mtd(void) +{ + printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR); + + arctic_mtd_map.virt = (unsigned long) ioremap(PADDR, SIZE); + + if (!arctic_mtd_map.virt) { + printk("%s: failed to ioremap 0x%x\n", NAME, PADDR); + return -EIO; + } + simple_map_init(&arctic_mtd_map); + + printk("%s: probing %d-bit flash bus\n", NAME, BUSWIDTH * 8); + arctic_mtd = do_map_probe("cfi_probe", &arctic_mtd_map); + + if (!arctic_mtd) + return -ENXIO; + + arctic_mtd->owner = THIS_MODULE; + + return add_mtd_partitions(arctic_mtd, arctic_partitions, 3); +} + +static void __exit +cleanup_arctic_mtd(void) +{ + if (arctic_mtd) { + del_mtd_partitions(arctic_mtd); + map_destroy(arctic_mtd); + iounmap((void *) arctic_mtd_map.virt); + } +} + +module_init(init_arctic_mtd); +module_exit(cleanup_arctic_mtd); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("David Gibson <arctic@gibson.dropbear.id.au>"); +MODULE_DESCRIPTION("MTD map and partitions for IBM 405LP Arctic boards"); diff -Nru a/drivers/mtd/maps/autcpu12-nvram.c b/drivers/mtd/maps/autcpu12-nvram.c --- a/drivers/mtd/maps/autcpu12-nvram.c Mon Jun 9 23:16:18 2003 +++ b/drivers/mtd/maps/autcpu12-nvram.c Mon Jun 9 23:16:18 2003 @@ -2,7 +2,7 @@ * NV-RAM memory access on autcpu12 * (C) 2002 Thomas Gleixner (gleixner@autronix.de) * - * $Id: autcpu12-nvram.c,v 1.1 2002/02/22 09:30:24 gleixner Exp $ + * $Id: autcpu12-nvram.c,v 1.5 2003/05/21 12:45:18 dwmw2 Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -24,6 +24,7 @@ #include <linux/types.h> #include <linux/kernel.h> #include <linux/ioport.h> +#include <linux/init.h> #include <asm/io.h> #include <asm/sizes.h> #include <asm/hardware.h> @@ -32,81 +33,28 @@ #include <linux/mtd/map.h> #include <linux/mtd/partitions.h> -__u8 autcpu12_read8(struct map_info *map, unsigned long ofs) -{ - return __raw_readb(map->map_priv_1 + ofs); -} - -__u16 autcpu12_read16(struct map_info *map, unsigned long ofs) -{ - return __raw_readw(map->map_priv_1 + ofs); -} - -__u32 autcpu12_read32(struct map_info *map, unsigned long ofs) -{ - return __raw_readl(map->map_priv_1 + ofs); -} - -void autcpu12_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - __raw_writeb(d, map->map_priv_1 + adr); - mb(); -} - -void autcpu12_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - __raw_writew(d, map->map_priv_1 + adr); - mb(); -} - -void autcpu12_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - __raw_writel(d, map->map_priv_1 + adr); - mb(); -} - -void autcpu12_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, map->map_priv_1 + from, len); -} - -void autcpu12_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - while(len) { - __raw_writeb(*(unsigned char *) from, map->map_priv_1 + to); - from++; - to++; - len--; - } -} static struct mtd_info *sram_mtd; struct map_info autcpu12_sram_map = { - .name = "SRAM", - .size = 32768, - .buswidth = 8, - .read8 = autcpu12_read8, - .read16 = autcpu12_read16, - .read32 = autcpu12_read32, - .copy_from = autcpu12_copy_from, - .write8 = autcpu12_write8, - .write16 = autcpu12_write16, - .write32 = autcpu12_write32, - .copy_to = autcpu12_copy_to + .name = "SRAM", + .size = 32768, + .buswidth = 4, + .phys = 0x12000000, }; static int __init init_autcpu12_sram (void) { int err, save0, save1; - autcpu12_sram_map.map_priv_1 = (unsigned long)ioremap(0x12000000, SZ_128K); - if (!autcpu12_sram_map.map_priv_1) { + autcpu12_sram_map.virt = (unsigned long)ioremap(0x12000000, SZ_128K); + if (!autcpu12_sram_map.virt) { printk("Failed to ioremap autcpu12 NV-RAM space\n"); err = -EIO; goto out; } - + simple_map_init(&autcpu_sram_map); + /* * Check for 32K/128K * read ofs 0 @@ -115,20 +63,20 @@ * Read and check result on ofs 0x0 * Restore contents */ - save0 = autcpu12_read32(&autcpu12_sram_map,0); - save1 = autcpu12_read32(&autcpu12_sram_map,0x10000); - autcpu12_write32(&autcpu12_sram_map,~save0,0x10000); + save0 = map_read32(&autcpu12_sram_map,0); + save1 = map_read32(&autcpu12_sram_map,0x10000); + map_write32(&autcpu12_sram_map,~save0,0x10000); /* if we find this pattern on 0x0, we have 32K size * restore contents and exit */ - if ( autcpu12_read32(&autcpu12_sram_map,0) != save0) { - autcpu12_write32(&autcpu12_sram_map,save0,0x0); + if ( map_read32(&autcpu12_sram_map,0) != save0) { + map_write32(&autcpu12_sram_map,save0,0x0); goto map; } /* We have a 128K found, restore 0x10000 and set size * to 128K */ - autcpu12_write32(&autcpu12_sram_map,save1,0x10000); + ma[_write32(&autcpu12_sram_map,save1,0x10000); autcpu12_sram_map.size = SZ_128K; map: @@ -139,7 +87,7 @@ goto out_ioremap; } - sram_mtd->module = THIS_MODULE; + sram_mtd->owner = THIS_MODULE; sram_mtd->erasesize = 16; if (add_mtd_device(sram_mtd)) { @@ -148,7 +96,7 @@ goto out_probe; } - printk("NV-RAM device size %ldK registered on AUTCPU12\n",autcpu12_sram_map.size/SZ_1K); + printk("NV-RAM device size %ldKiB registered on AUTCPU12\n",autcpu12_sram_map.size/SZ_1K); return 0; @@ -157,7 +105,7 @@ sram_mtd = 0; out_ioremap: - iounmap((void *)autcpu12_sram_map.map_priv_1); + iounmap((void *)autcpu12_sram_map.virt); out: return err; } @@ -167,7 +115,7 @@ if (sram_mtd) { del_mtd_device(sram_mtd); map_destroy(sram_mtd); - iounmap((void *)autcpu12_sram_map.map_priv_1); + iounmap((void *)autcpu12_sram_map.virt); } } diff -Nru a/drivers/mtd/maps/beech-mtd.c b/drivers/mtd/maps/beech-mtd.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/beech-mtd.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,112 @@ +/* + * $Id: beech-mtd.c,v 1.7 2003/05/21 12:45:18 dwmw2 Exp $ + * + * drivers/mtd/maps/beech-mtd.c MTD mappings and partition tables for + * IBM 405LP Beech boards. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the 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 + * + * Copyright (C) 2002, International Business Machines Corporation + * All Rights Reserved. + * + * Bishop Brock + * IBM Research, Austin Center for Low-Power Computing + * bcbrock@us.ibm.com + * March 2002 + * + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/init.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> + +#include <asm/io.h> +#include <asm/ibm4xx.h> + +#define NAME "Beech Linux Flash" +#define PADDR BEECH_BIGFLASH_PADDR +#define SIZE BEECH_BIGFLASH_SIZE +#define BUSWIDTH 1 + +/* Flash memories on these boards are memory resources, accessed big-endian. */ + + +static struct map_info beech_mtd_map = { + .name = NAME, + .size = SIZE, + .buswidth = BUSWIDTH, + .phys = PADDR +}; + +static struct mtd_info *beech_mtd; + +static struct mtd_partition beech_partitions[2] = { + { + .name = "Linux Kernel", + .size = BEECH_KERNEL_SIZE, + .offset = BEECH_KERNEL_OFFSET + }, { + .name = "Free Area", + .size = BEECH_FREE_AREA_SIZE, + .offset = BEECH_FREE_AREA_OFFSET + } +}; + +static int __init +init_beech_mtd(void) +{ + printk("%s: 0x%08x at 0x%08x\n", NAME, SIZE, PADDR); + + beech_mtd_map.virt = (unsigned long) ioremap(PADDR, SIZE); + + if (!beech_mtd_map.virt) { + printk("%s: failed to ioremap 0x%x\n", NAME, PADDR); + return -EIO; + } + + simple_map_init(&beech_mtd_map); + + printk("%s: probing %d-bit flash bus\n", NAME, BUSWIDTH * 8); + beech_mtd = do_map_probe("cfi_probe", &beech_mtd_map); + + if (!beech_mtd) + return -ENXIO; + + beech_mtd->owner = THIS_MODULE; + + return add_mtd_partitions(beech_mtd, beech_partitions, 2); +} + +static void __exit +cleanup_beech_mtd(void) +{ + if (beech_mtd) { + del_mtd_partitions(beech_mtd); + map_destroy(beech_mtd); + iounmap((void *) beech_mtd_map.virt); + } +} + +module_init(init_beech_mtd); +module_exit(cleanup_beech_mtd); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Bishop Brock <bcbrock@us.ibm.com>"); +MODULE_DESCRIPTION("MTD map and partitions for IBM 405LP Beech boards"); diff -Nru a/drivers/mtd/maps/cdb89712.c b/drivers/mtd/maps/cdb89712.c --- a/drivers/mtd/maps/cdb89712.c Mon Jun 9 23:16:20 2003 +++ b/drivers/mtd/maps/cdb89712.c Mon Jun 9 23:16:20 2003 @@ -1,89 +1,37 @@ /* * Flash on Cirrus CDB89712 * - * $Id: cdb89712.c,v 1.3 2001/10/02 15:14:43 rmk Exp $ + * $Id: cdb89712.c,v 1.7 2003/05/21 12:45:18 dwmw2 Exp $ */ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/ioport.h> +#include <linux/init.h> #include <asm/io.h> #include <asm/arch/hardware.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> #include <linux/mtd/partitions.h> -__u8 cdb89712_read8(struct map_info *map, unsigned long ofs) -{ - return __raw_readb(map->map_priv_1 + ofs); -} - -__u16 cdb89712_read16(struct map_info *map, unsigned long ofs) -{ - return __raw_readw(map->map_priv_1 + ofs); -} - -__u32 cdb89712_read32(struct map_info *map, unsigned long ofs) -{ - return __raw_readl(map->map_priv_1 + ofs); -} - -void cdb89712_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - __raw_writeb(d, map->map_priv_1 + adr); - mb(); -} -void cdb89712_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - __raw_writew(d, map->map_priv_1 + adr); - mb(); -} - -void cdb89712_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - __raw_writel(d, map->map_priv_1 + adr); - mb(); -} -void cdb89712_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - // printk ("cdb89712_copy_from: 0x%x@0x%x -> 0x%x\n", len, from, to); - memcpy_fromio(to, map->map_priv_1 + from, len); -} - -void cdb89712_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - while(len) { - __raw_writeb(*(unsigned char *) from, map->map_priv_1 + to); - from++; - to++; - len--; - } -} static struct mtd_info *flash_mtd; struct map_info cdb89712_flash_map = { - .name = "flash", - .size = FLASH_SIZE, - .buswidth = FLASH_WIDTH, - .read8 = cdb89712_read8, - .read16 = cdb89712_read16, - .read32 = cdb89712_read32, - .copy_from = cdb89712_copy_from, - .write8 = cdb89712_write8, - .write16 = cdb89712_write16, - .write32 = cdb89712_write32, - .copy_to = cdb89712_copy_to + .name = "flash", + .size = FLASH_SIZE, + .buswidth = FLASH_WIDTH, + .phys = FLASH_START, }; struct resource cdb89712_flash_resource = { - .name = "Flash", - .start = FLASH_START, - .end = FLASH_START + FLASH_SIZE - 1, - .flags = IORESOURCE_IO | IORESOURCE_BUSY, + .name = "Flash", + .start = FLASH_START, + .end = FLASH_START + FLASH_SIZE - 1, + .flags = IORESOURCE_IO | IORESOURCE_BUSY, }; static int __init init_cdb89712_flash (void) @@ -96,13 +44,13 @@ goto out; } - cdb89712_flash_map.map_priv_1 = (unsigned long)ioremap(FLASH_START, FLASH_SIZE); - if (!cdb89712_flash_map.map_priv_1) { + cdb89712_flash_map.virt = (unsigned long)ioremap(FLASH_START, FLASH_SIZE); + if (!cdb89712_flash_map.virt) { printk(KERN_NOTICE "Failed to ioremap Cdb89712 FLASH space\n"); err = -EIO; goto out_resource; } - + simple_map_init(&cdb89712_flash_map); flash_mtd = do_map_probe("cfi_probe", &cdb89712_flash_map); if (!flash_mtd) { flash_mtd = do_map_probe("map_rom", &cdb89712_flash_map); @@ -115,7 +63,7 @@ goto out_ioremap; } - flash_mtd->module = THIS_MODULE; + flash_mtd->owner = THIS_MODULE; if (add_mtd_device(flash_mtd)) { printk("FLASH device addition failed\n"); @@ -129,34 +77,31 @@ map_destroy(flash_mtd); flash_mtd = 0; out_ioremap: - iounmap((void *)cdb89712_flash_map.map_priv_1); + iounmap((void *)cdb89712_flash_map.virt); out_resource: release_resource (&cdb89712_flash_resource); out: return err; } + + + + static struct mtd_info *sram_mtd; struct map_info cdb89712_sram_map = { - .name = "SRAM", - .size = SRAM_SIZE, - .buswidth = SRAM_WIDTH, - .read8 = cdb89712_read8, - .read16 = cdb89712_read16, - .read32 = cdb89712_read32, - .copy_from = cdb89712_copy_from, - .write8 = cdb89712_write8, - .write16 = cdb89712_write16, - .write32 = cdb89712_write32, - .copy_to = cdb89712_copy_to + .name = "SRAM", + .size = SRAM_SIZE, + .buswidth = SRAM_WIDTH, + .phys = SRAM_START, }; struct resource cdb89712_sram_resource = { - .name = "SRAM", - .start = SRAM_START, - .end = SRAM_START + SRAM_SIZE - 1, - .flags = IORESOURCE_IO | IORESOURCE_BUSY, + .name = "SRAM", + .start = SRAM_START, + .end = SRAM_START + SRAM_SIZE - 1, + .flags = IORESOURCE_IO | IORESOURCE_BUSY, }; static int __init init_cdb89712_sram (void) @@ -169,13 +114,13 @@ goto out; } - cdb89712_sram_map.map_priv_1 = (unsigned long)ioremap(SRAM_START, SRAM_SIZE); - if (!cdb89712_sram_map.map_priv_1) { + cdb89712_sram_map.virt = (unsigned long)ioremap(SRAM_START, SRAM_SIZE); + if (!cdb89712_sram_map.virt) { printk(KERN_NOTICE "Failed to ioremap Cdb89712 SRAM space\n"); err = -EIO; goto out_resource; } - + simple_map_init(&cdb89712_sram_map); sram_mtd = do_map_probe("map_ram", &cdb89712_sram_map); if (!sram_mtd) { printk("SRAM probe failed\n"); @@ -183,7 +128,7 @@ goto out_ioremap; } - sram_mtd->module = THIS_MODULE; + sram_mtd->owner = THIS_MODULE; sram_mtd->erasesize = 16; if (add_mtd_device(sram_mtd)) { @@ -198,30 +143,33 @@ map_destroy(sram_mtd); sram_mtd = 0; out_ioremap: - iounmap((void *)cdb89712_sram_map.map_priv_1); + iounmap((void *)cdb89712_sram_map.virt); out_resource: release_resource (&cdb89712_sram_resource); out: return err; } + + + + + + static struct mtd_info *bootrom_mtd; struct map_info cdb89712_bootrom_map = { - .name = "BootROM", - .size = BOOTROM_SIZE, - .buswidth = BOOTROM_WIDTH, - .read8 = cdb89712_read8, - .read16 = cdb89712_read16, - .read32 = cdb89712_read32, - .copy_from = cdb89712_copy_from, + .name = "BootROM", + .size = BOOTROM_SIZE, + .buswidth = BOOTROM_WIDTH, + .phys = BOOTROM_START, }; struct resource cdb89712_bootrom_resource = { - .name = "BootROM", - .start = BOOTROM_START, - .end = BOOTROM_START + BOOTROM_SIZE - 1, - .flags = IORESOURCE_IO | IORESOURCE_BUSY, + .name = "BootROM", + .start = BOOTROM_START, + .end = BOOTROM_START + BOOTROM_SIZE - 1, + .flags = IORESOURCE_IO | IORESOURCE_BUSY, }; static int __init init_cdb89712_bootrom (void) @@ -234,13 +182,13 @@ goto out; } - cdb89712_bootrom_map.map_priv_1 = (unsigned long)ioremap(BOOTROM_START, BOOTROM_SIZE); - if (!cdb89712_bootrom_map.map_priv_1) { + cdb89712_bootrom_map.virt = (unsigned long)ioremap(BOOTROM_START, BOOTROM_SIZE); + if (!cdb89712_bootrom_map.virt) { printk(KERN_NOTICE "Failed to ioremap Cdb89712 BootROM space\n"); err = -EIO; goto out_resource; } - + simple_map_init(&cdb89712_bootrom_map); bootrom_mtd = do_map_probe("map_rom", &cdb89712_bootrom_map); if (!bootrom_mtd) { printk("BootROM probe failed\n"); @@ -248,7 +196,7 @@ goto out_ioremap; } - bootrom_mtd->module = THIS_MODULE; + bootrom_mtd->owner = THIS_MODULE; bootrom_mtd->erasesize = 0x10000; if (add_mtd_device(bootrom_mtd)) { @@ -263,13 +211,17 @@ map_destroy(bootrom_mtd); bootrom_mtd = 0; out_ioremap: - iounmap((void *)cdb89712_bootrom_map.map_priv_1); + iounmap((void *)cdb89712_bootrom_map.virt); out_resource: release_resource (&cdb89712_bootrom_resource); out: return err; } + + + + static int __init init_cdb89712_maps(void) { @@ -289,21 +241,21 @@ if (sram_mtd) { del_mtd_device(sram_mtd); map_destroy(sram_mtd); - iounmap((void *)cdb89712_sram_map.map_priv_1); + iounmap((void *)cdb89712_sram_map.virt); release_resource (&cdb89712_sram_resource); } if (flash_mtd) { del_mtd_device(flash_mtd); map_destroy(flash_mtd); - iounmap((void *)cdb89712_flash_map.map_priv_1); + iounmap((void *)cdb89712_flash_map.virt); release_resource (&cdb89712_flash_resource); } if (bootrom_mtd) { del_mtd_device(bootrom_mtd); map_destroy(bootrom_mtd); - iounmap((void *)cdb89712_bootrom_map.map_priv_1); + iounmap((void *)cdb89712_bootrom_map.virt); release_resource (&cdb89712_bootrom_resource); } } diff -Nru a/drivers/mtd/maps/ceiva.c b/drivers/mtd/maps/ceiva.c --- a/drivers/mtd/maps/ceiva.c Mon Jun 9 23:16:10 2003 +++ b/drivers/mtd/maps/ceiva.c Mon Jun 9 23:16:10 2003 @@ -11,7 +11,7 @@ * * (C) 2000 Nicolas Pitre <nico@cam.org> * - * $Id: ceiva.c,v 1.2 2002/10/14 12:50:22 rmk Exp $ + * $Id: ceiva.c,v 1.8 2003/05/21 12:45:18 dwmw2 Exp $ */ #include <linux/config.h> @@ -19,6 +19,7 @@ #include <linux/types.h> #include <linux/ioport.h> #include <linux/kernel.h> +#include <linux/init.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> @@ -31,62 +32,10 @@ #include <asm/sizes.h> /* - * This isnt complete yet, so... + * This isn't complete yet, so... */ #define CONFIG_MTD_CEIVA_STATICMAP -static __u8 clps_read8(struct map_info *map, unsigned long ofs) -{ - return readb(map->map_priv_1 + ofs); -} - -static __u16 clps_read16(struct map_info *map, unsigned long ofs) -{ - return readw(map->map_priv_1 + ofs); -} - -static __u32 clps_read32(struct map_info *map, unsigned long ofs) -{ - return readl(map->map_priv_1 + ofs); -} - -static void clps_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy(to, (void *)(map->map_priv_1 + from), len); -} - -static void clps_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - writeb(d, map->map_priv_1 + adr); -} - -static void clps_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - writew(d, map->map_priv_1 + adr); -} - -static void clps_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - writel(d, map->map_priv_1 + adr); -} - -static void clps_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy((void *)(map->map_priv_1 + to), from, len); -} - -static struct map_info clps_map __initdata = { - .name = "clps flash", - .read8 = clps_read8, - .read16 = clps_read16, - .read32 = clps_read32, - .copy_from = clps_copy_from, - .write8 = clps_write8, - .write16 = clps_write16, - .write32 = clps_write32, - .copy_to = clps_copy_to, -}; - #ifdef CONFIG_MTD_CEIVA_STATICMAP /* * See include/linux/mtd/partitions.h for definition of the mtd_partition @@ -94,7 +43,7 @@ * * Please note: * 1. The flash size given should be the largest flash size that can - * be accommodated. + * be accomodated. * * 2. The bus width must defined in clps_setup_flash. * @@ -115,25 +64,23 @@ static struct mtd_partition ceiva_partitions[] = { { - .name = "Ceiva BOOT partition", - .size = BOOT_PARTITION_SIZE_KiB*1024, - - }, - { - .name = "Ceiva parameters partition", - .size = PARAMS_PARTITION_SIZE_KiB*1024, - .offset = (16 + 8) * 1024, - }, - { - .name = "Ceiva kernel partition", - .size = (KERNEL_PARTITION_SIZE_KiB)*1024, - .offset = 0x20000, - - }, - { - .name = "Ceiva root filesystem partition", - .offset = MTDPART_OFS_APPEND, - .size = (ROOT_PARTITION_SIZE_KiB)*1024, + name: "Ceiva BOOT partition", + size: BOOT_PARTITION_SIZE_KiB*1024, + offset: 0, + + },{ + name: "Ceiva parameters partition", + size: PARAMS_PARTITION_SIZE_KiB*1024, + offset: (16 + 8) * 1024, + },{ + name: "Ceiva kernel partition", + size: (KERNEL_PARTITION_SIZE_KiB)*1024, + offset: 0x20000, + + },{ + name: "Ceiva root filesystem partition", + offset: MTDPART_OFS_APPEND, + size: (ROOT_PARTITION_SIZE_KiB)*1024, } }; #endif @@ -178,7 +125,7 @@ maps = kmalloc(sizeof(struct map_info) * nr, GFP_KERNEL); if (!maps) return -ENOMEM; - + memset(maps, 0, sizeof(struct map_info) * nr); /* * Claim and then map the memory regions. */ @@ -193,7 +140,9 @@ } clps[i].map = maps + i; - memcpy(clps[i].map, &clps_map, sizeof(struct map_info)); + + clps[i].map->name = "clps flash"; + clps[i].map->phys = clps[i].base; clps[i].vbase = ioremap(clps[i].base, clps[i].size); if (!clps[i].vbase) { @@ -201,16 +150,18 @@ break; } - clps[i].map->map_priv_1 = (unsigned long)clps[i].vbase; + clps[i].map->virt = (unsigned long)clps[i].vbase; clps[i].map->buswidth = clps[i].width; clps[i].map->size = clps[i].size; + simple_map_init(&clps[i].map); + clps[i].mtd = do_map_probe("jedec_probe", clps[i].map); if (clps[i].mtd == NULL) { ret = -ENXIO; break; } - clps[i].mtd->module = THIS_MODULE; + clps[i].mtd->owner = THIS_MODULE; subdev[i] = clps[i].mtd; printk(KERN_INFO "clps flash: JEDEC device at 0x%08lx, %dMiB, " @@ -320,10 +271,8 @@ return nr; } -extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); -extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, char *); - static struct mtd_partition *parsed_parts; +static const char *probes[] = { "cmdlinepart", "RedBoot", NULL }; static void __init clps_locate_partitions(struct mtd_info *mtd) { @@ -333,20 +282,11 @@ /* * Partition selection stuff. */ -#ifdef CONFIG_MTD_CMDLINE_PARTS - nr_parts = parse_cmdline_partitions(mtd, &parsed_parts, "clps"); + nr_parts = parse_mtd_partitions(mtd, probes, &parsed_parts, 0); if (nr_parts > 0) { part_type = "command line"; break; } -#endif -#ifdef CONFIG_MTD_REDBOOT_PARTS - nr_parts = parse_redboot_partitions(mtd, &parsed_parts); - if (nr_parts > 0) { - part_type = "RedBoot"; - break; - } -#endif #ifdef CONFIG_MTD_CEIVA_STATICMAP nr_parts = clps_static_partitions(&parsed_parts); if (nr_parts > 0) { diff -Nru a/drivers/mtd/maps/cfi_flagadm.c b/drivers/mtd/maps/cfi_flagadm.c --- a/drivers/mtd/maps/cfi_flagadm.c Mon Jun 9 23:16:05 2003 +++ b/drivers/mtd/maps/cfi_flagadm.c Mon Jun 9 23:16:05 2003 @@ -1,7 +1,7 @@ /* * Copyright © 2001 Flaga hf. Medical Devices, Kári Davíðsson <kd@flaga.is> * - * $Id: cfi_flagadm.c,v 1.7 2001/10/02 15:05:13 dwmw2 Exp $ + * $Id: cfi_flagadm.c,v 1.11 2003/05/21 12:45:18 dwmw2 Exp $ * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -27,6 +27,7 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> +#include <linux/init.h> #include <asm/io.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> @@ -55,83 +56,33 @@ #define FLASH_PARTITION3_ADDR 0x00240000 #define FLASH_PARTITION3_SIZE 0x001C0000 -__u8 flagadm_read8(struct map_info *map, unsigned long ofs) -{ - return __raw_readb(map->map_priv_1 + ofs); -} - -__u16 flagadm_read16(struct map_info *map, unsigned long ofs) -{ - return __raw_readw(map->map_priv_1 + ofs); -} - -__u32 flagadm_read32(struct map_info *map, unsigned long ofs) -{ - return __raw_readl(map->map_priv_1 + ofs); -} - -void flagadm_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, map->map_priv_1 + from, len); -} - -void flagadm_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - __raw_writeb(d, map->map_priv_1 + adr); - mb(); -} - -void flagadm_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - __raw_writew(d, map->map_priv_1 + adr); - mb(); -} - -void flagadm_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - __raw_writel(d, map->map_priv_1 + adr); - mb(); -} - -void flagadm_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 flagadm_map = { - .name = "FlagaDM flash device", - .size = FLASH_SIZE, - .buswidth = 2, - .read8 = flagadm_read8, - .read16 = flagadm_read16, - .read32 = flagadm_read32, - .copy_from = flagadm_copy_from, - .write8 = flagadm_write8, - .write16 = flagadm_write16, - .write32 = flagadm_write32, - .copy_to = flagadm_copy_to + .name = "FlagaDM flash device", + .size = FLASH_SIZE, + .buswidth = 2, }; struct mtd_partition flagadm_parts[] = { { - .name = "Bootloader", - .offset = FLASH_PARTITION0_ADDR, - .size = FLASH_PARTITION0_SIZE + .name = "Bootloader", + .offset = FLASH_PARTITION0_ADDR, + .size = FLASH_PARTITION0_SIZE }, { - .name = "Kernel image", - .offset = FLASH_PARTITION1_ADDR, - .size = FLASH_PARTITION1_SIZE + .name = "Kernel image", + .offset = FLASH_PARTITION1_ADDR, + .size = FLASH_PARTITION1_SIZE }, { - .name = "Initial ramdisk image", - .offset = FLASH_PARTITION2_ADDR, - .size = FLASH_PARTITION2_SIZE + .name = "Initial ramdisk image", + .offset = FLASH_PARTITION2_ADDR, + .size = FLASH_PARTITION2_SIZE }, { - .name = "Persistant storage", - .offset = FLASH_PARTITION3_ADDR, - .size = FLASH_PARTITION3_SIZE + .name = "Persistant storage", + .offset = FLASH_PARTITION3_ADDR, + .size = FLASH_PARTITION3_SIZE } }; @@ -144,22 +95,26 @@ printk(KERN_NOTICE "FlagaDM flash device: %x at %x\n", FLASH_SIZE, FLASH_PHYS_ADDR); - flagadm_map.map_priv_1 = (unsigned long)ioremap(FLASH_PHYS_ADDR, + flagadm_map.phys = FLASH_PHYS_ADDR; + flagadm_map.virt = (unsigned long)ioremap(FLASH_PHYS_ADDR, FLASH_SIZE); - if (!flagadm_map.map_priv_1) { + if (!flagadm_map.virt) { printk("Failed to ioremap\n"); return -EIO; } + + simple_map_init(&flagadm_map); + mymtd = do_map_probe("cfi_probe", &flagadm_map); if (mymtd) { - mymtd->module = THIS_MODULE; + mymtd->owner = THIS_MODULE; add_mtd_partitions(mymtd, flagadm_parts, PARTITION_COUNT); printk(KERN_NOTICE "FlagaDM flash device initialized\n"); return 0; } - iounmap((void *)flagadm_map.map_priv_1); + iounmap((void *)flagadm_map.virt); return -ENXIO; } @@ -169,9 +124,9 @@ del_mtd_partitions(mymtd); map_destroy(mymtd); } - if (flagadm_map.map_priv_1) { - iounmap((void *)flagadm_map.map_priv_1); - flagadm_map.map_priv_1 = 0; + if (flagadm_map.virt) { + iounmap((void *)flagadm_map.virt); + flagadm_map.virt = 0; } } diff -Nru a/drivers/mtd/maps/cstm_mips_ixx.c b/drivers/mtd/maps/cstm_mips_ixx.c --- a/drivers/mtd/maps/cstm_mips_ixx.c Mon Jun 9 23:16:08 2003 +++ b/drivers/mtd/maps/cstm_mips_ixx.c Mon Jun 9 23:16:08 2003 @@ -1,11 +1,11 @@ /* - * $Id: cstm_mips_ixx.c,v 1.5 2001/10/02 15:05:14 dwmw2 Exp $ + * $Id: cstm_mips_ixx.c,v 1.9 2003/05/21 12:45:18 dwmw2 Exp $ * * Mapping of a custom board with both AMD CFI and JEDEC flash in partitions. * Config with both CFI and JEDEC device support. * * Basically physmap.c with the addition of partitions and - * an array of mapping info to accommodate more than one flash type per board. + * an array of mapping info to accomodate more than one flash type per board. * * Copyright 2000 MontaVista Software Inc. * @@ -33,55 +33,13 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> +#include <linux/init.h> #include <asm/io.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> #include <linux/mtd/partitions.h> #include <linux/config.h> - -#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) #include <linux/delay.h> -#endif - -__u8 cstm_mips_ixx_read8(struct map_info *map, unsigned long ofs) -{ - return *(__u8 *)(map->map_priv_1 + ofs); -} - -__u16 cstm_mips_ixx_read16(struct map_info *map, unsigned long ofs) -{ - return *(__u16 *)(map->map_priv_1 + ofs); -} - -__u32 cstm_mips_ixx_read32(struct map_info *map, unsigned long ofs) -{ - return *(__u32 *)(map->map_priv_1 + ofs); -} - -void cstm_mips_ixx_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, map->map_priv_1 + from, len); -} - -void cstm_mips_ixx_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - *(__u8 *)(map->map_priv_1 + adr) = d; -} - -void cstm_mips_ixx_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - *(__u16 *)(map->map_priv_1 + adr) = d; -} - -void cstm_mips_ixx_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - *(__u32 *)(map->map_priv_1 + adr) = d; -} - -void cstm_mips_ixx_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy_toio(map->map_priv_1 + to, from, len); -} #if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) #define CC_GCR 0xB4013818 @@ -97,51 +55,47 @@ #define CC_GPAICR 0xB4013804 #endif /* defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) */ +#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) void cstm_mips_ixx_set_vpp(struct map_info *map,int vpp) { - if (vpp) { -#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) - __u16 data; - __u8 data1; - static u8 first = 1; - - // Set GPIO port B pin3 to high - data = *(__u16 *)(CC_GPBCR); - data = (data & 0xff0f) | 0x0040; - *(__u16 *)CC_GPBCR = data; - *(__u8 *)CC_GPBDR = (*(__u8*)CC_GPBDR) | 0x08; - if (first) { - first = 0; - /* need to have this delay for first - enabling vpp after powerup */ - udelay(40); + static spinlock_t vpp_lock = SPIN_LOCK_UNLOCKED; + static int vpp_count = 0; + unsigned long flags; + + spin_lock_irqsave(&vpp_lock, flags); + + if (vpp) { + if (!vpp_count++) { + __u16 data; + __u8 data1; + static u8 first = 1; + + // Set GPIO port B pin3 to high + data = *(__u16 *)(CC_GPBCR); + data = (data & 0xff0f) | 0x0040; + *(__u16 *)CC_GPBCR = data; + *(__u8 *)CC_GPBDR = (*(__u8*)CC_GPBDR) | 0x08; + if (first) { + first = 0; + /* need to have this delay for first + enabling vpp after powerup */ + udelay(40); + } + } + } else { + if (!--vpp_count) { + __u16 data; + + // Set GPIO port B pin3 to high + data = *(__u16 *)(CC_GPBCR); + data = (data & 0xff3f) | 0x0040; + *(__u16 *)CC_GPBCR = data; + *(__u8 *)CC_GPBDR = (*(__u8*)CC_GPBDR) & 0xf7; + } } -#endif /* CONFIG_MIPS_ITE8172 */ - } - else { -#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) - __u16 data; - - // Set GPIO port B pin3 to high - data = *(__u16 *)(CC_GPBCR); - data = (data & 0xff3f) | 0x0040; - *(__u16 *)CC_GPBCR = data; - *(__u8 *)CC_GPBDR = (*(__u8*)CC_GPBDR) & 0xf7; -#endif /* CONFIG_MIPS_ITE8172 */ - } + spin_unlock_irqrestore(&vpp_lock, flags); } - -const struct map_info basic_cstm_mips_ixx_map = { - .read8 = cstm_mips_ixx_read8, - .read16 = cstm_mips_ixx_read16, - .read32 = cstm_mips_ixx_read32, - .copy_from = cstm_mips_ixx_copy_from, - .write8 = cstm_mips_ixx_write8, - .write16 = cstm_mips_ixx_write16, - .write32 = cstm_mips_ixx_write32, - .copy_to = cstm_mips_ixx_copy_to, - .set_vpp = cstm_mips_ixx_set_vpp, -}; +#endif /* board and partition description */ @@ -170,8 +124,9 @@ static struct mtd_partition cstm_mips_ixx_partitions[PHYSMAP_NUMBER][MAX_PHYSMAP_PARTITIONS] = { { // 28F128J3A in 2x16 configuration { - .name = "main partition ", - .size = 0x02000000, // 128 x 2 x 128k byte sectors + .name = "main partition ", + .size = 0x02000000, // 128 x 2 x 128k byte sectors + .offset = 0, }, }, }; @@ -191,8 +146,9 @@ static struct mtd_partition cstm_mips_ixx_partitions[PHYSMAP_NUMBER][MAX_PHYSMAP_PARTITIONS] = { { { - .name = "main partition", - .size = CONFIG_MTD_CSTM_MIPS_IXX_LEN, + .name = "main partition", + .size = CONFIG_MTD_CSTM_MIPS_IXX_LEN, + .offset = 0, }, }, }; @@ -209,17 +165,24 @@ /* Initialize mapping */ for (i=0;i<PHYSMAP_NUMBER;i++) { - printk(KERN_NOTICE "cstm_mips_ixx flash device: %lx at %lx\n", cstm_mips_ixx_board_desc[i].window_size, cstm_mips_ixx_board_desc[i].window_addr); - memcpy((char *)&cstm_mips_ixx_map[i],(char *)&basic_cstm_mips_ixx_map,sizeof(struct map_info)); - cstm_mips_ixx_map[i].map_priv_1 = (unsigned long)ioremap(cstm_mips_ixx_board_desc[i].window_addr, cstm_mips_ixx_board_desc[i].window_size); - if (!cstm_mips_ixx_map[i].map_priv_1) { + printk(KERN_NOTICE "cstm_mips_ixx flash device: 0x%lx at 0x%lx\n", + cstm_mips_ixx_board_desc[i].window_size, cstm_mips_ixx_board_desc[i].window_addr); + + + cstm_mips_ixx_map[i].phys = cstm_mips_ixx_board_desc[i].window_addr; + cstm_mips_ixx_map[i].virt = (unsigned long)ioremap(cstm_mips_ixx_board_desc[i].window_addr, cstm_mips_ixx_board_desc[i].window_size); + if (!cstm_mips_ixx_map[i].virt) { printk(KERN_WARNING "Failed to ioremap\n"); return -EIO; } cstm_mips_ixx_map[i].name = cstm_mips_ixx_board_desc[i].name; cstm_mips_ixx_map[i].size = cstm_mips_ixx_board_desc[i].window_size; cstm_mips_ixx_map[i].buswidth = cstm_mips_ixx_board_desc[i].buswidth; - //printk(KERN_NOTICE "cstm_mips_ixx: ioremap is %x\n",(unsigned int)(cstm_mips_ixx_map[i].map_priv_1)); +#if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) + cstm_mips_ixx_map[i].set_vpp = cstm_mips_ixx_set_vpp; +#endif + simple_map_init(&cstm_mips_ixx_map[i]); + //printk(KERN_NOTICE "cstm_mips_ixx: ioremap is %x\n",(unsigned int)(cstm_mips_ixx_map[i].virt)); } #if defined(CONFIG_MIPS_ITE8172) || defined(CONFIG_MIPS_IVR) @@ -237,7 +200,7 @@ printk(KERN_NOTICE "cstm_mips_ixx %d jedec: mymtd is %x\n",i,(unsigned int)mymtd); } if (mymtd) { - mymtd->module = THIS_MODULE; + mymtd->owner = THIS_MODULE; cstm_mips_ixx_map[i].map_priv_2 = (unsigned long)mymtd; add_mtd_partitions(mymtd, parts, cstm_mips_ixx_board_desc[i].num_partitions); @@ -259,9 +222,9 @@ del_mtd_partitions(mymtd); map_destroy(mymtd); } - if (cstm_mips_ixx_map[i].map_priv_1) { - iounmap((void *)cstm_mips_ixx_map[i].map_priv_1); - cstm_mips_ixx_map[i].map_priv_1 = 0; + if (cstm_mips_ixx_map[i].virt) { + iounmap((void *)cstm_mips_ixx_map[i].virt); + cstm_mips_ixx_map[i].virt = 0; } } } diff -Nru a/drivers/mtd/maps/dbox2-flash.c b/drivers/mtd/maps/dbox2-flash.c --- a/drivers/mtd/maps/dbox2-flash.c Mon Jun 9 23:16:19 2003 +++ b/drivers/mtd/maps/dbox2-flash.c Mon Jun 9 23:16:19 2003 @@ -1,12 +1,13 @@ /* - * $Id: dbox2-flash.c,v 1.4 2001/10/02 15:05:14 dwmw2 Exp $ + * $Id: dbox2-flash.c,v 1.9 2003/05/21 12:45:18 dwmw2 Exp $ * - * Nokia / Sagem D-Box 2 flash driver + * D-Box 2 flash driver */ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> +#include <linux/init.h> #include <asm/io.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> @@ -18,24 +19,40 @@ * device. */ static struct mtd_partition partition_info[]= { { - .name = "BR bootloader", /* raw */ - .size = 128 * 1024, - .mask_flags = MTD_WRITEABLE + .name = "BR bootloader", + .size = 128 * 1024, + .offset = 0, + .mask_flags = MTD_WRITEABLE }, { - .name = "PPC bootloader", /* flfs */ - .size = 128 * 1024, - .offset = MTDPART_OFS_APPEND, + .name = "flfs (ppcboot)", + .size = 128 * 1024, + .offset = MTDPART_OFS_APPEND, + .mask_flags = 0 }, { - .name = "Kernel", /* idxfs */ - .size = 768 * 1024, - .offset = MTDPART_OFS_APPEND, + .name = "root (cramfs)", + .size = 7040 * 1024, + .offset = MTDPART_OFS_APPEND, + .mask_flags = 0 }, { - .name = "System", /* jffs */ - .size = MTDPART_SIZ_FULL, - .offset = MTDPART_OFS_APPEND, + .name = "var (jffs2)", + .size = 896 * 1024, + .offset = MTDPART_OFS_APPEND, + .mask_flags = 0 + }, + { + .name = "flash without bootloader", + .size = MTDPART_SIZ_FULL, + .offset = 128 * 1024, + .mask_flags = 0 + }, + { + .name = "complete flash", + .size = MTDPART_SIZ_FULL, + .offset = 0, + .mask_flags = MTD_WRITEABLE } }; @@ -46,72 +63,24 @@ static struct mtd_info *mymtd; -__u8 dbox2_flash_read8(struct map_info *map, unsigned long ofs) -{ - return __raw_readb(map->map_priv_1 + ofs); -} - -__u16 dbox2_flash_read16(struct map_info *map, unsigned long ofs) -{ - return __raw_readw(map->map_priv_1 + ofs); -} - -__u32 dbox2_flash_read32(struct map_info *map, unsigned long ofs) -{ - return __raw_readl(map->map_priv_1 + ofs); -} - -void dbox2_flash_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, map->map_priv_1 + from, len); -} - -void dbox2_flash_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - __raw_writeb(d, map->map_priv_1 + adr); - mb(); -} - -void dbox2_flash_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - __raw_writew(d, map->map_priv_1 + adr); - mb(); -} - -void dbox2_flash_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - __raw_writel(d, map->map_priv_1 + adr); - mb(); -} - -void dbox2_flash_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 dbox2_flash_map = { .name = "D-Box 2 flash memory", .size = WINDOW_SIZE, .buswidth = 4, - .read8 = dbox2_flash_read8, - .read16 = dbox2_flash_read16, - .read32 = dbox2_flash_read32, - .copy_from = dbox2_flash_copy_from, - .write8 = dbox2_flash_write8, - .write16 = dbox2_flash_write16, - .write32 = dbox2_flash_write32, - .copy_to = dbox2_flash_copy_to + .phys = WINDOW_ADDR, }; int __init init_dbox2_flash(void) { printk(KERN_NOTICE "D-Box 2 flash driver (size->0x%X mem->0x%X)\n", WINDOW_SIZE, WINDOW_ADDR); - dbox2_flash_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); + dbox2_flash_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); - if (!dbox2_flash_map.map_priv_1) { + if (!dbox2_flash_map.virt) { printk("Failed to ioremap\n"); return -EIO; } + simple_map_init(&dbox2_flash_map); // Probe for dual Intel 28F320 or dual AMD mymtd = do_map_probe("cfi_probe", &dbox2_flash_map); @@ -123,7 +92,7 @@ } if (mymtd) { - mymtd->module = THIS_MODULE; + mymtd->owner = THIS_MODULE; /* Create MTD devices for each partition. */ add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS); @@ -131,7 +100,7 @@ return 0; } - iounmap((void *)dbox2_flash_map.map_priv_1); + iounmap((void *)dbox2_flash_map.virt); return -ENXIO; } @@ -141,9 +110,9 @@ del_mtd_partitions(mymtd); map_destroy(mymtd); } - if (dbox2_flash_map.map_priv_1) { - iounmap((void *)dbox2_flash_map.map_priv_1); - dbox2_flash_map.map_priv_1 = 0; + if (dbox2_flash_map.virt) { + iounmap((void *)dbox2_flash_map.virt); + dbox2_flash_map.virt = 0; } } @@ -152,5 +121,5 @@ MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Kári Davíðsson <kd@flaga.is>"); -MODULE_DESCRIPTION("MTD map driver for Nokia/Sagem D-Box 2 board"); +MODULE_AUTHOR("Kári Davíðsson <kd@flaga.is>, Bastian Blank <waldi@tuxbox.org>, Alexander Wild <wild@te-elektronik.com>"); +MODULE_DESCRIPTION("MTD map driver for D-Box 2 board"); diff -Nru a/drivers/mtd/maps/dc21285.c b/drivers/mtd/maps/dc21285.c --- a/drivers/mtd/maps/dc21285.c Mon Jun 9 23:16:10 2003 +++ b/drivers/mtd/maps/dc21285.c Mon Jun 9 23:16:10 2003 @@ -5,12 +5,13 @@ * * This code is GPL * - * $Id: dc21285.c,v 1.9 2002/10/14 12:22:10 rmk Exp $ + * $Id: dc21285.c,v 1.15 2003/05/21 12:45:18 dwmw2 Exp $ */ #include <linux/config.h> #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> @@ -92,28 +93,42 @@ } struct map_info dc21285_map = { - .name = "DC21285 flash", - .size = 16*1024*1024, - .read8 = dc21285_read8, - .read16 = dc21285_read16, - .read32 = dc21285_read32, - .copy_from = dc21285_copy_from, - .write8 = dc21285_write8, - .write16 = dc21285_write16, - .write32 = dc21285_write32, - .copy_to = dc21285_copy_to + .name = "DC21285 flash", + .phys = NO_XIP, + .size = 16*1024*1024, + .read8 = dc21285_read8, + .read16 = dc21285_read16, + .read32 = dc21285_read32, + .copy_from = dc21285_copy_from, + .write8 = dc21285_write8, + .write16 = dc21285_write16, + .write32 = dc21285_write32, + .copy_to = dc21285_copy_to }; + /* Partition stuff */ static struct mtd_partition *dc21285_parts; - -extern int parse_redboot_partitions(struct mtd_info *, struct mtd_partition **); -extern int parse_cmdline_partitions(struct mtd_info *master, - struct mtd_partition **pparts, - const char *mtd_id); - +#ifdef CONFIG_MTD_PARTITIONS +static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; +#endif + int __init init_dc21285(void) { + + /* + * Flash timing is determined with bits 19-16 of the + * CSR_SA110_CNTL. The value is the number of wait cycles, or + * 0 for 16 cycles (the default). Cycles are 20 ns. + * Here we use 7 for 140 ns flash chips. + */ + /* access time */ + *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x000f0000) | (7 << 16)); + /* burst time */ + *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x00f00000) | (7 << 20)); + /* tristate time */ + *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x0f000000) | (7 << 24)); + /* Determine buswidth */ switch (*CSR_SA110_CNTL & (3<<14)) { case SA110_CNTL_ROMWIDTH_8: @@ -142,50 +157,19 @@ mymtd = do_map_probe("cfi_probe", &dc21285_map); if (mymtd) { int nrparts = 0; - const char *part_type = NULL; - mymtd->module = THIS_MODULE; + mymtd->owner = THIS_MODULE; /* partition fixup */ - do { -#ifdef CONFIG_MTD_CMDLINE_PARTS - nrparts = parse_cmdline_partitions(mymtd, &dc21285_parts, "dc21285"); - if (nrparts > 0) { - part_type = "command line"; - break; - } -#endif -#ifdef CONFIG_MTD_REDBOOT_PARTS - nrparts = parse_redboot_partitions(mymtd, &dc21285_parts); - if (nrparts > 0) { - part_type = "RedBoot"; - break; - } -#endif - } while (0); +#ifdef CONFIG_MTD_PARTITIONS + nrparts = parse_mtd_partitions(mymtd, probes, &dc21285_parts, (void *)0); if (nrparts > 0) { add_mtd_partitions(mymtd, dc21285_parts, nrparts); - printk(KERN_NOTICE "DC21285 using %s partition " - "definition\n", part_type); - } else if (nrparts == 0) { - printk(KERN_NOTICE "DC21285 partition table failed\n"); - add_mtd_device(mymtd); + return 0; } - - /* - * Flash timing is determined with bits 19-16 of the - * CSR_SA110_CNTL. The value is the number of wait cycles, or - * 0 for 16 cycles (the default). Cycles are 20 ns. - * Here we use 7 for 140 ns flash chips. - */ - /* access time */ - *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x000f0000) | (7 << 16)); - /* burst time */ - *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x00f00000) | (7 << 20)); - /* tristate time */ - *CSR_SA110_CNTL = ((*CSR_SA110_CNTL & ~0x0f000000) | (7 << 24)); - +#endif + add_mtd_device(mymtd); return 0; } @@ -195,17 +179,16 @@ static void __exit cleanup_dc21285(void) { - if (mymtd) { - del_mtd_device(mymtd); - map_destroy(mymtd); - mymtd = NULL; - } - if (dc21285_map.map_priv_1) { - iounmap((void *)dc21285_map.map_priv_1); - dc21285_map.map_priv_1 = 0; - } - if(dc21285_parts) +#ifdef CONFIG_MTD_PARTITIONS + if (dc21285_parts) { + del_mtd_partitions(mymtd); kfree(dc21285_parts); + } else +#endif + del_mtd_device(mymtd); + + map_destroy(mymtd); + iounmap((void *)dc21285_map.map_priv_1); } module_init(init_dc21285); diff -Nru a/drivers/mtd/maps/dilnetpc.c b/drivers/mtd/maps/dilnetpc.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/dilnetpc.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,495 @@ +/* dilnetpc.c -- MTD map driver for SSV DIL/Net PC Boards "DNP" and "ADNP" + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + * + * $Id: dilnetpc.c,v 1.12 2003/05/21 12:45:18 dwmw2 Exp $ + * + * The DIL/Net PC is a tiny embedded PC board made by SSV Embedded Systems + * featuring the AMD Elan SC410 processor. There are two variants of this + * board: DNP/1486 and ADNP/1486. The DNP version has 2 megs of flash + * ROM (Intel 28F016S3) and 8 megs of DRAM, the ADNP version has 4 megs + * flash and 16 megs of RAM. + * For details, see http://www.ssv-embedded.de/ssv/pc104/p169.htm + * and http://www.ssv-embedded.de/ssv/pc104/p170.htm + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <asm/io.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> +#include <linux/mtd/concat.h> + +/* +** The DIL/NetPC keeps its BIOS in two distinct flash blocks. +** Destroying any of these blocks transforms the DNPC into +** a paperweight (albeit not a very useful one, considering +** it only weighs a few grams). +** +** Therefore, the BIOS blocks must never be erased or written to +** except by people who know exactly what they are doing (e.g. +** to install a BIOS update). These partitions are marked read-only +** by default, but can be made read/write by undefining +** DNPC_BIOS_BLOCKS_WRITEPROTECTED: +*/ +#define DNPC_BIOS_BLOCKS_WRITEPROTECTED + +/* +** The ID string (in ROM) is checked to determine whether we +** are running on a DNP/1486 or ADNP/1486 +*/ +#define BIOSID_BASE 0x000fe100 + +#define ID_DNPC "DNP1486" +#define ID_ADNP "ADNP1486" + +/* +** Address where the flash should appear in CPU space +*/ +#define FLASH_BASE 0x2000000 + +/* +** Chip Setup and Control (CSC) indexed register space +*/ +#define CSC_INDEX 0x22 +#define CSC_DATA 0x23 + +#define CSC_MMSWAR 0x30 /* MMS window C-F attributes register */ +#define CSC_MMSWDSR 0x31 /* MMS window C-F device select register */ + +#define CSC_RBWR 0xa7 /* GPIO Read-Back/Write Register B */ + +#define CSC_CR 0xd0 /* internal I/O device disable/Echo */ + /* Z-bus/configuration register */ + +#define CSC_PCCMDCR 0xf1 /* PC card mode and DMA control register */ + + +/* +** PC Card indexed register space: +*/ + +#define PCC_INDEX 0x3e0 +#define PCC_DATA 0x3e1 + +#define PCC_AWER_B 0x46 /* Socket B Address Window enable register */ +#define PCC_MWSAR_1_Lo 0x58 /* memory window 1 start address low register */ +#define PCC_MWSAR_1_Hi 0x59 /* memory window 1 start address high register */ +#define PCC_MWEAR_1_Lo 0x5A /* memory window 1 stop address low register */ +#define PCC_MWEAR_1_Hi 0x5B /* memory window 1 stop address high register */ +#define PCC_MWAOR_1_Lo 0x5C /* memory window 1 address offset low register */ +#define PCC_MWAOR_1_Hi 0x5D /* memory window 1 address offset high register */ + + +/* +** Access to SC4x0's Chip Setup and Control (CSC) +** and PC Card (PCC) indexed registers: +*/ +static inline void setcsc(int reg, unsigned char data) +{ + outb(reg, CSC_INDEX); + outb(data, CSC_DATA); +} + +static inline unsigned char getcsc(int reg) +{ + outb(reg, CSC_INDEX); + return(inb(CSC_DATA)); +} + +static inline void setpcc(int reg, unsigned char data) +{ + outb(reg, PCC_INDEX); + outb(data, PCC_DATA); +} + +static inline unsigned char getpcc(int reg) +{ + outb(reg, PCC_INDEX); + return(inb(PCC_DATA)); +} + + +/* +************************************************************ +** Enable access to DIL/NetPC's flash by mapping it into +** the SC4x0's MMS Window C. +************************************************************ +*/ +static void dnpc_map_flash(unsigned long flash_base, unsigned long flash_size) +{ + unsigned long flash_end = flash_base + flash_size - 1; + + /* + ** enable setup of MMS windows C-F: + */ + /* - enable PC Card indexed register space */ + setcsc(CSC_CR, getcsc(CSC_CR) | 0x2); + /* - set PC Card controller to operate in standard mode */ + setcsc(CSC_PCCMDCR, getcsc(CSC_PCCMDCR) & ~1); + + /* + ** Program base address and end address of window + ** where the flash ROM should appear in CPU address space + */ + setpcc(PCC_MWSAR_1_Lo, (flash_base >> 12) & 0xff); + setpcc(PCC_MWSAR_1_Hi, (flash_base >> 20) & 0x3f); + setpcc(PCC_MWEAR_1_Lo, (flash_end >> 12) & 0xff); + setpcc(PCC_MWEAR_1_Hi, (flash_end >> 20) & 0x3f); + + /* program offset of first flash location to appear in this window (0) */ + setpcc(PCC_MWAOR_1_Lo, ((0 - flash_base) >> 12) & 0xff); + setpcc(PCC_MWAOR_1_Hi, ((0 - flash_base)>> 20) & 0x3f); + + /* set attributes for MMS window C: non-cacheable, write-enabled */ + setcsc(CSC_MMSWAR, getcsc(CSC_MMSWAR) & ~0x11); + + /* select physical device ROMCS0 (i.e. flash) for MMS Window C */ + setcsc(CSC_MMSWDSR, getcsc(CSC_MMSWDSR) & ~0x03); + + /* enable memory window 1 */ + setpcc(PCC_AWER_B, getpcc(PCC_AWER_B) | 0x02); + + /* now disable PC Card indexed register space again */ + setcsc(CSC_CR, getcsc(CSC_CR) & ~0x2); +} + + +/* +************************************************************ +** Disable access to DIL/NetPC's flash by mapping it into +** the SC4x0's MMS Window C. +************************************************************ +*/ +static void dnpc_unmap_flash(void) +{ + /* - enable PC Card indexed register space */ + setcsc(CSC_CR, getcsc(CSC_CR) | 0x2); + + /* disable memory window 1 */ + setpcc(PCC_AWER_B, getpcc(PCC_AWER_B) & ~0x02); + + /* now disable PC Card indexed register space again */ + setcsc(CSC_CR, getcsc(CSC_CR) & ~0x2); +} + + + +/* +************************************************************ +** Enable/Disable VPP to write to flash +************************************************************ +*/ + +static spinlock_t dnpc_spin = SPIN_LOCK_UNLOCKED; +static int vpp_counter = 0; +/* +** This is what has to be done for the DNP board .. +*/ +static void dnp_set_vpp(struct map_info *not_used, int on) +{ + spin_lock_irq(&dnpc_spin); + + if (on) + { + if(++vpp_counter == 1) + setcsc(CSC_RBWR, getcsc(CSC_RBWR) & ~0x4); + } + else + { + if(--vpp_counter == 0) + setcsc(CSC_RBWR, getcsc(CSC_RBWR) | 0x4); + else if(vpp_counter < 0) + BUG(); + } + spin_unlock_irq(&dnpc_spin); +} + +/* +** .. and this the ADNP version: +*/ +static void adnp_set_vpp(struct map_info *not_used, int on) +{ + spin_lock_irq(&dnpc_spin); + + if (on) + { + if(++vpp_counter == 1) + setcsc(CSC_RBWR, getcsc(CSC_RBWR) & ~0x8); + } + else + { + if(--vpp_counter == 0) + setcsc(CSC_RBWR, getcsc(CSC_RBWR) | 0x8); + else if(vpp_counter < 0) + BUG(); + } + spin_unlock_irq(&dnpc_spin); +} + + + +#define DNP_WINDOW_SIZE 0x00200000 /* DNP flash size is 2MiB */ +#define ADNP_WINDOW_SIZE 0x00400000 /* ADNP flash size is 4MiB */ +#define WINDOW_ADDR FLASH_BASE + +static struct map_info dnpc_map = { + .name = "ADNP Flash Bank", + .size = ADNP_WINDOW_SIZE, + .buswidth = 1, + .set_vpp = adnp_set_vpp, + .phys = WINDOW_ADDR +}; + +/* +** The layout of the flash is somewhat "strange": +** +** 1. 960 KiB (15 blocks) : Space for ROM Bootloader and user data +** 2. 64 KiB (1 block) : System BIOS +** 3. 960 KiB (15 blocks) : User Data (DNP model) or +** 3. 3008 KiB (47 blocks) : User Data (ADNP model) +** 4. 64 KiB (1 block) : System BIOS Entry +*/ + +static struct mtd_partition partition_info[]= +{ + { + .name = "ADNP boot", + .offset = 0, + .size = 0xf0000, + }, + { + .name = "ADNP system BIOS", + .offset = MTDPART_OFS_NXTBLK, + .size = 0x10000, +#ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED + .mask_flags = MTD_WRITEABLE, +#endif + }, + { + .name = "ADNP file system", + .offset = MTDPART_OFS_NXTBLK, + .size = 0x2f0000, + }, + { + .name = "ADNP system BIOS entry", + .offset = MTDPART_OFS_NXTBLK, + .size = MTDPART_SIZ_FULL, +#ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED + .mask_flags = MTD_WRITEABLE, +#endif + }, +}; + +#define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0])) + +static struct mtd_info *mymtd; +static struct mtd_info *lowlvl_parts[NUM_PARTITIONS]; +static struct mtd_info *merged_mtd; + +/* +** "Highlevel" partition info: +** +** Using the MTD concat layer, we can re-arrange partitions to our +** liking: we construct a virtual MTD device by concatenating the +** partitions, specifying the sequence such that the boot block +** is immediately followed by the filesystem block (i.e. the stupid +** system BIOS block is mapped to a different place). When re-partitioning +** this concatenated MTD device, we can set the boot block size to +** an arbitrary (though erase block aligned) value i.e. not one that +** is dictated by the flash's physical layout. We can thus set the +** boot block to be e.g. 64 KB (which is fully sufficient if we want +** to boot an etherboot image) or to -say- 1.5 MB if we want to boot +** a large kernel image. In all cases, the remainder of the flash +** is available as file system space. +*/ + +static struct mtd_partition higlvl_partition_info[]= +{ + { + .name = "ADNP boot block", + .offset = 0, + .size = CONFIG_MTD_DILNETPC_BOOTSIZE, + }, + { + .name = "ADNP file system space", + .offset = MTDPART_OFS_NXTBLK, + .size = ADNP_WINDOW_SIZE-CONFIG_MTD_DILNETPC_BOOTSIZE-0x20000, + }, + { + .name = "ADNP system BIOS + BIOS Entry", + .offset = MTDPART_OFS_NXTBLK, + .size = MTDPART_SIZ_FULL, +#ifdef DNPC_BIOS_BLOCKS_WRITEPROTECTED + .mask_flags = MTD_WRITEABLE, +#endif + }, +}; + +#define NUM_HIGHLVL_PARTITIONS (sizeof(higlvl_partition_info)/sizeof(partition_info[0])) + + +static int dnp_adnp_probe(void) +{ + char *biosid, rc = -1; + + biosid = (char*)ioremap(BIOSID_BASE, 16); + if(biosid) + { + if(!strcmp(biosid, ID_DNPC)) + rc = 1; /* this is a DNPC */ + else if(!strcmp(biosid, ID_ADNP)) + rc = 0; /* this is a ADNPC */ + } + iounmap((void *)biosid); + return(rc); +} + + +static int __init init_dnpc(void) +{ + int is_dnp; + + /* + ** determine hardware (DNP/ADNP/invalid) + */ + if((is_dnp = dnp_adnp_probe()) < 0) + return -ENXIO; + + /* + ** Things are set up for ADNP by default + ** -> modify all that needs to be different for DNP + */ + if(is_dnp) + { /* + ** Adjust window size, select correct set_vpp function. + ** The partitioning scheme is identical on both DNP + ** and ADNP except for the size of the third partition. + */ + int i; + dnpc_map.size = DNP_WINDOW_SIZE; + dnpc_map.set_vpp = dnp_set_vpp; + partition_info[2].size = 0xf0000; + + /* + ** increment all string pointers so the leading 'A' gets skipped, + ** thus turning all occurrences of "ADNP ..." into "DNP ..." + */ + ++dnpc_map.name; + for(i = 0; i < NUM_PARTITIONS; i++) + ++partition_info[i].name; + higlvl_partition_info[1].size = DNP_WINDOW_SIZE - + CONFIG_MTD_DILNETPC_BOOTSIZE - 0x20000; + for(i = 0; i < NUM_HIGHLVL_PARTITIONS; i++) + ++higlvl_partition_info[i].name; + } + + printk(KERN_NOTICE "DIL/Net %s flash: 0x%lx at 0x%lx\n", + is_dnp ? "DNPC" : "ADNP", dnpc_map.size, dnpc_map.phys); + + dnpc_map.virt = (unsigned long)ioremap_nocache(dnpc_map.phys, dnpc_map.size); + + dnpc_map_flash(dnpc_map.phys, dnpc_map.size); + + if (!dnpc_map.virt) { + printk("Failed to ioremap_nocache\n"); + return -EIO; + } + simple_map_init(&dnpc_map); + + printk("FLASH virtual address: 0x%lx\n", dnpc_map.virt); + + mymtd = do_map_probe("jedec_probe", &dnpc_map); + + if (!mymtd) + mymtd = do_map_probe("cfi_probe", &dnpc_map); + + /* + ** If flash probes fail, try to make flashes accessible + ** at least as ROM. Ajust erasesize in this case since + ** the default one (128M) will break our partitioning + */ + if (!mymtd) + if((mymtd = do_map_probe("map_rom", &dnpc_map))) + mymtd->erasesize = 0x10000; + + if (!mymtd) { + iounmap((void *)dnpc_map.virt); + return -ENXIO; + } + + mymtd->owner = THIS_MODULE; + + /* + ** Supply pointers to lowlvl_parts[] array to add_mtd_partitions() + ** -> add_mtd_partitions() will _not_ register MTD devices for + ** the partitions, but will instead store pointers to the MTD + ** objects it creates into our lowlvl_parts[] array. + ** NOTE: we arrange the pointers such that the sequence of the + ** partitions gets re-arranged: partition #2 follows + ** partition #0. + */ + partition_info[0].mtdp = &lowlvl_parts[0]; + partition_info[1].mtdp = &lowlvl_parts[2]; + partition_info[2].mtdp = &lowlvl_parts[1]; + partition_info[3].mtdp = &lowlvl_parts[3]; + + add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS); + + /* + ** now create a virtual MTD device by concatenating the for partitions + ** (in the sequence given by the lowlvl_parts[] array. + */ + merged_mtd = mtd_concat_create(lowlvl_parts, NUM_PARTITIONS, "(A)DNP Flash Concatenated"); + if(merged_mtd) + { /* + ** now partition the new device the way we want it. This time, + ** we do not supply mtd pointers in higlvl_partition_info, so + ** add_mtd_partitions() will register the devices. + */ + add_mtd_partitions(merged_mtd, higlvl_partition_info, NUM_HIGHLVL_PARTITIONS); + } + + return 0; +} + +static void __exit cleanup_dnpc(void) +{ + if(merged_mtd) { + del_mtd_partitions(merged_mtd); + mtd_concat_destroy(merged_mtd); + } + + if (mymtd) { + del_mtd_partitions(mymtd); + map_destroy(mymtd); + } + if (dnpc_map.virt) { + iounmap((void *)dnpc_map.virt); + dnpc_unmap_flash(); + dnpc_map.virt = 0; + } +} + +module_init(init_dnpc); +module_exit(cleanup_dnpc); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Sysgo Real-Time Solutions GmbH"); +MODULE_DESCRIPTION("MTD map driver for SSV DIL/NetPC DNP & ADNP"); diff -Nru a/drivers/mtd/maps/ebony.c b/drivers/mtd/maps/ebony.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/ebony.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,166 @@ +/* + * $Id: ebony.c,v 1.7 2003/05/21 12:45:18 dwmw2 Exp $ + * + * Mapping for Ebony user flash + * + * Matt Porter <mporter@mvista.com> + * + * Copyright 2002 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/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> +#include <asm/ibm440.h> +#include <platforms/ebony.h> + +static struct mtd_info *flash; + +static struct map_info ebony_small_map = { + .name = "Ebony small flash", + .size = EBONY_SMALL_FLASH_SIZE, + .buswidth = 1, +}; + +static struct map_info ebony_large_map = { + .name = "Ebony large flash", + .size = EBONY_LARGE_FLASH_SIZE, + .buswidth = 1, +}; + +static struct mtd_partition ebony_small_partitions[] = { + { + .name = "OpenBIOS", + .offset = 0x0, + .size = 0x80000, + } +}; + +static struct mtd_partition ebony_large_partitions[] = { + { + .name = "fs", + .offset = 0, + .size = 0x380000, + }, + { + .name = "firmware", + .offset = 0x380000, + .size = 0x80000, + } +}; + +#define NB_OF(x) (sizeof(x)/sizeof(x[0])) + +int __init init_ebony(void) +{ + u8 fpga0_reg; + unsigned long fpga0_adr; + unsigned long long small_flash_base, large_flash_base; + + fpga0_adr = ioremap64(EBONY_FPGA_ADDR, 16); + if (!fpga0_adr) + return -ENOMEM; + + fpga0_reg = readb(fpga0_adr); + iounmap64(fpga0_adr); + + if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) && + !EBONY_FLASH_SEL(fpga0_reg)) + small_flash_base = EBONY_SMALL_FLASH_HIGH2; + else if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) && + EBONY_FLASH_SEL(fpga0_reg)) + small_flash_base = EBONY_SMALL_FLASH_HIGH1; + else if (!EBONY_BOOT_SMALL_FLASH(fpga0_reg) && + !EBONY_FLASH_SEL(fpga0_reg)) + small_flash_base = EBONY_SMALL_FLASH_LOW2; + else + small_flash_base = EBONY_SMALL_FLASH_LOW1; + + if (EBONY_BOOT_SMALL_FLASH(fpga0_reg) && + !EBONY_ONBRD_FLASH_EN(fpga0_reg)) + large_flash_base = EBONY_LARGE_FLASH_LOW; + else + large_flash_base = EBONY_LARGE_FLASH_HIGH; + + ebony_small_map.phys = small_flash_base; + ebony_small_map.virt = + (unsigned long)ioremap64(small_flash_base, + ebony_small_map.size); + + if (!ebony_small_map.virt) { + printk("Failed to ioremap flash\n"); + return -EIO; + } + + simple_map_init(&ebony_small_map); + + flash = do_map_probe("map_rom", &ebony_small_map); + if (flash) { + flash->owner = THIS_MODULE; + add_mtd_partitions(flash, ebony_small_partitions, + NB_OF(ebony_small_partitions)); + } else { + printk("map probe failed for flash\n"); + return -ENXIO; + } + + ebony_large_map.phys = large_flash_base; + ebony_large_map.virt = + (unsigned long)ioremap64(large_flash_base, + ebony_large_map.size); + + if (!ebony_large_map.virt) { + printk("Failed to ioremap flash\n"); + return -EIO; + } + + simple_map_init(&ebony_large_map); + + flash = do_map_probe("cfi_probe", &ebony_large_map); + if (flash) { + flash->owner = THIS_MODULE; + add_mtd_partitions(flash, ebony_large_partitions, + NB_OF(ebony_large_partitions)); + } else { + printk("map probe failed for flash\n"); + return -ENXIO; + } + + return 0; +} + +static void __exit cleanup_ebony(void) +{ + if (flash) { + del_mtd_partitions(flash); + map_destroy(flash); + } + + if (ebony_small_map.virt) { + iounmap((void *)ebony_small_map.virt); + ebony_small_map.virt = 0; + } + + if (ebony_large_map.virt) { + iounmap((void *)ebony_large_map.virt); + ebony_large_map.virt = 0; + } +} + +module_init(init_ebony); +module_exit(cleanup_ebony); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Matt Porter <mporter@mvista.com>"); +MODULE_DESCRIPTION("MTD map and partitions for IBM 440GP Ebony boards"); diff -Nru a/drivers/mtd/maps/edb7312.c b/drivers/mtd/maps/edb7312.c --- a/drivers/mtd/maps/edb7312.c Mon Jun 9 23:16:20 2003 +++ b/drivers/mtd/maps/edb7312.c Mon Jun 9 23:16:20 2003 @@ -1,5 +1,5 @@ /* - * $Id: edb7312.c,v 1.2 2002/09/05 05:11:24 acurtis Exp $ + * $Id: edb7312.c,v 1.8 2003/05/21 12:45:18 dwmw2 Exp $ * * Handle mapping of the NOR flash on Cogent EDB7312 boards * @@ -13,6 +13,7 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> +#include <linux/init.h> #include <asm/io.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> @@ -35,61 +36,11 @@ static struct mtd_info *mymtd; -__u8 edb7312nor_read8(struct map_info *map, unsigned long ofs) -{ - return __raw_readb(map->map_priv_1 + ofs); -} - -__u16 edb7312nor_read16(struct map_info *map, unsigned long ofs) -{ - return __raw_readw(map->map_priv_1 + ofs); -} - -__u32 edb7312nor_read32(struct map_info *map, unsigned long ofs) -{ - return __raw_readl(map->map_priv_1 + ofs); -} - -void edb7312nor_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, map->map_priv_1 + from, len); -} - -void edb7312nor_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - __raw_writeb(d, map->map_priv_1 + adr); - mb(); -} - -void edb7312nor_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - __raw_writew(d, map->map_priv_1 + adr); - mb(); -} - -void edb7312nor_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - __raw_writel(d, map->map_priv_1 + adr); - mb(); -} - -void edb7312nor_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 edb7312nor_map = { - .name = "NOR flash on EDB7312", - .size = WINDOW_SIZE, - .buswidth = BUSWIDTH, - .read8 = edb7312nor_read8, - .read16 = edb7312nor_read16, - .read32 = edb7312nor_read32, - .copy_from = edb7312nor_copy_from, - .write8 = edb7312nor_write8, - .write16 = edb7312nor_write16, - .write32 = edb7312nor_write32, - .copy_to = edb7312nor_copy_to + .name = "NOR flash on EDB7312", + .size = WINDOW_SIZE, + .buswidth = BUSWIDTH, + .phys = WINDOW_ADDR, }; #ifdef CONFIG_MTD_PARTITIONS @@ -97,7 +48,8 @@ /* * MTD partitioning stuff */ -static struct mtd_partition static_partitions[3] = { +static struct mtd_partition static_partitions[3] = +{ { .name = "ARMboot", .size = 0x40000, @@ -116,12 +68,7 @@ }; #define NB_OF(x) (sizeof (x) / sizeof (x[0])) - -#ifdef CONFIG_MTD_CMDLINE_PARTS -int parse_cmdline_partitions(struct mtd_info *master, - struct mtd_partition **pparts, - const char *mtd_id); -#endif +static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; #endif @@ -136,13 +83,15 @@ printk(KERN_NOTICE MSG_PREFIX "0x%08x at 0x%08x\n", WINDOW_SIZE, WINDOW_ADDR); - edb7312nor_map.map_priv_1 = (unsigned long) + edb7312nor_map.virt = (unsigned long) ioremap(WINDOW_ADDR, WINDOW_SIZE); - if (!edb7312nor_map.map_priv_1) { + if (!edb7312nor_map.virt) { printk(MSG_PREFIX "failed to ioremap\n"); return -EIO; } + + simple_map_init(&edb7312nor_map); mymtd = 0; type = rom_probe_types; @@ -150,14 +99,13 @@ mymtd = do_map_probe(*type, &edb7312nor_map); } if (mymtd) { - mymtd->module = THIS_MODULE; + mymtd->owner = THIS_MODULE; #ifdef CONFIG_MTD_PARTITIONS -#ifdef CONFIG_MTD_CMDLINE_PARTS - mtd_parts_nb = parse_cmdline_partitions(mymtd, &mtd_parts, MTDID); + mtd_parts_nb = parse_mtd_partitions(mymtd, probes, &mtd_parts, MTDID); if (mtd_parts_nb > 0) - part_type = "command line"; -#endif + part_type = "detected"; + if (mtd_parts_nb == 0) { mtd_parts = static_partitions; @@ -177,7 +125,7 @@ return 0; } - iounmap((void *)edb7312nor_map.map_priv_1); + iounmap((void *)edb7312nor_map.virt); return -ENXIO; } @@ -187,9 +135,9 @@ del_mtd_device(mymtd); map_destroy(mymtd); } - if (edb7312nor_map.map_priv_1) { - iounmap((void *)edb7312nor_map.map_priv_1); - edb7312nor_map.map_priv_1 = 0; + if (edb7312nor_map.virt) { + iounmap((void *)edb7312nor_map.virt); + edb7312nor_map.virt = 0; } } diff -Nru a/drivers/mtd/maps/elan-104nc.c b/drivers/mtd/maps/elan-104nc.c --- a/drivers/mtd/maps/elan-104nc.c Mon Jun 9 23:16:12 2003 +++ b/drivers/mtd/maps/elan-104nc.c Mon Jun 9 23:16:12 2003 @@ -16,7 +16,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - $Id: elan-104nc.c,v 1.12 2001/10/02 15:05:14 dwmw2 Exp $ + $Id: elan-104nc.c,v 1.17 2003/05/21 15:15:07 dwmw2 Exp $ The ELAN-104NC has up to 8 Mibyte of Intel StrataFlash (28F320/28F640) in x16 mode. This drivers uses the CFI probe and Intel Extended Command Set drivers. @@ -27,7 +27,7 @@ 16 bit I/O port (0x22) for some sort of paging. -The single flash device is divided into 3 partition which appear as separate +The single flash device is divided into 3 partition which appear as seperate MTD devices. Linux thinks that the I/O port is used by the PIC and hence check_region() will @@ -40,6 +40,7 @@ #include <asm/io.h> #include <linux/mtd/map.h> +#include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> #define WINDOW_START 0xb0000 @@ -58,20 +59,15 @@ /* partition_info gives details on the logical partitions that the split the * single flash device into. If the size if zero we use up to the end of the * device. */ -static struct mtd_partition partition_info[] = { - { - .name = "ELAN-104NC flash boot partition", - .size = 640*1024 - }, - { - .name = "ELAN-104NC flash partition 1", - .offset = 640*1024, - .size = 896*1024 - }, - { - .name = "ELAN-104NC flash partition 2", - .offset = (640+896)*1024, - } +static struct mtd_partition partition_info[]={ + { .name = "ELAN-104NC flash boot partition", + .offset = 0, + .size = 640*1024 }, + { .name = "ELAN-104NC flash partition 1", + .offset = 640*1024, + .size = 896*1024 }, + { .name = "ELAN-104NC flash partition 2", + .offset = (640+896)*1024 } }; #define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0])) @@ -200,20 +196,20 @@ } static struct map_info elan_104nc_map = { - .name = "ELAN-104NC flash", - .size = 8*1024*1024, /* this must be set to a maximum - possible amount of flash so the - cfi probe routines find all - the chips */ - .buswidth = 2, - .read8 = elan_104nc_read8, - .read16 = elan_104nc_read16, - .read32 = elan_104nc_read32, - .copy_from = elan_104nc_copy_from, - .write8 = elan_104nc_write8, - .write16 = elan_104nc_write16, - .write32 = elan_104nc_write32, - .copy_to = elan_104nc_copy_to + .name = "ELAN-104NC flash", + .phys = NO_XIP, + .size = 8*1024*1024, /* this must be set to a maximum possible amount + of flash so the cfi probe routines find all + the chips */ + .buswidth = 2, + .read8 = elan_104nc_read8, + .read16 = elan_104nc_read16, + .read32 = elan_104nc_read32, + .copy_from = elan_104nc_copy_from, + .write8 = elan_104nc_write8, + .write16 = elan_104nc_write16, + .write32 = elan_104nc_write32, + .copy_to = elan_104nc_copy_to }; /* MTD device for all of the flash. */ @@ -266,7 +262,7 @@ return -ENXIO; } - all_mtd->module=THIS_MODULE; + all_mtd->owner = THIS_MODULE; /* Create MTD devices for each partition. */ add_mtd_partitions( all_mtd, partition_info, NUM_PARTITIONS ); diff -Nru a/drivers/mtd/maps/epxa10db-flash.c b/drivers/mtd/maps/epxa10db-flash.c --- a/drivers/mtd/maps/epxa10db-flash.c Mon Jun 9 23:16:16 2003 +++ b/drivers/mtd/maps/epxa10db-flash.c Mon Jun 9 23:16:16 2003 @@ -5,7 +5,7 @@ * Copyright (C) 2001 Altera Corporation * Copyright (C) 2001 Red Hat, Inc. * - * $Id: epxa10db-flash.c,v 1.4 2002/08/22 10:46:19 cdavies Exp $ + * $Id: epxa10db-flash.c,v 1.10 2003/05/21 12:45:18 dwmw2 Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +26,7 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> +#include <linux/init.h> #include <asm/io.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> @@ -43,87 +44,38 @@ static struct mtd_info *mymtd; -extern int parse_redboot_partitions(struct mtd_info *, struct mtd_partition **); static int epxa_default_partitions(struct mtd_info *master, struct mtd_partition **pparts); -static __u8 epxa_read8(struct map_info *map, unsigned long ofs) -{ - return __raw_readb(map->map_priv_1 + ofs); -} - -static __u16 epxa_read16(struct map_info *map, unsigned long ofs) -{ - return __raw_readw(map->map_priv_1 + ofs); -} - -static __u32 epxa_read32(struct map_info *map, unsigned long ofs) -{ - return __raw_readl(map->map_priv_1 + ofs); -} - -static void epxa_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, (void *)(map->map_priv_1 + from), len); -} - -static void epxa_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - __raw_writeb(d, map->map_priv_1 + adr); - mb(); -} - -static void epxa_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - __raw_writew(d, map->map_priv_1 + adr); - mb(); -} - -static void epxa_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - __raw_writel(d, map->map_priv_1 + adr); - mb(); -} - -static void epxa_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy_toio((void *)(map->map_priv_1 + to), from, len); -} - - static struct map_info epxa_map = { - .name = "EPXA flash", - .size = FLASH_SIZE, - .buswidth = 2, - .read8 = epxa_read8, - .read16 = epxa_read16, - .read32 = epxa_read32, - .copy_from = epxa_copy_from, - .write8 = epxa_write8, - .write16 = epxa_write16, - .write32 = epxa_write32, - .copy_to = epxa_copy_to + .name = "EPXA flash", + .size = FLASH_SIZE, + .buswidth = 2, + .phys = FLASH_START, }; +static const char *probes[] = { "RedBoot", "afs", NULL }; static int __init epxa_mtd_init(void) { int i; - printk(KERN_NOTICE "%s flash device: %x at %x\n", BOARD_NAME, FLASH_SIZE, FLASH_START); - epxa_map.map_priv_1 = (unsigned long)ioremap(FLASH_START, FLASH_SIZE); - if (!epxa_map.map_priv_1) { + printk(KERN_NOTICE "%s flash device: 0x%x at 0x%x\n", BOARD_NAME, FLASH_SIZE, FLASH_START); + + epxa_map.virt = (unsigned long)ioremap(FLASH_START, FLASH_SIZE); + if (!epxa_map.virt) { printk("Failed to ioremap %s flash\n",BOARD_NAME); return -EIO; } + simple_map_init(&epxa_map); mymtd = do_map_probe("cfi_probe", &epxa_map); if (!mymtd) { - iounmap((void *)epxa_map.map_priv_1); + iounmap((void *)epxa_map.virt); return -ENXIO; } - mymtd->module = THIS_MODULE; + mymtd->owner = THIS_MODULE; /* Unlock the flash device. */ if(mymtd->unlock){ @@ -135,23 +87,14 @@ } } -#ifdef CONFIG_MTD_REDBOOT_PARTS - nr_parts = parse_redboot_partitions(mymtd, &parts); +#ifdef CONFIG_MTD_PARTITIONS + nr_parts = parse_mtd_partitions(mymtd, probes, &parts, 0); if (nr_parts > 0) { add_mtd_partitions(mymtd, parts, nr_parts); return 0; } #endif -#ifdef CONFIG_MTD_AFS_PARTS - nr_parts = parse_afs_partitions(mymtd, &parts); - - if (nr_parts > 0) { - add_mtd_partitions(mymtd, parts, nr_parts); - return 0; - } -#endif - /* No recognised partitioning schemes found - use defaults */ nr_parts = epxa_default_partitions(mymtd, &parts); if (nr_parts > 0) { @@ -173,9 +116,9 @@ del_mtd_device(mymtd); map_destroy(mymtd); } - if (epxa_map.map_priv_1) { - iounmap((void *)epxa_map.map_priv_1); - epxa_map.map_priv_1 = 0; + if (epxa_map.virt) { + iounmap((void *)epxa_map.virt); + epxa_map.virt = 0; } } @@ -199,12 +142,12 @@ printk("Using default partitions for %s\n",BOARD_NAME); npartitions=1; - parts = kmalloc(npartitions*sizeof(*parts)+strlen(name)+1, GFP_KERNEL); + parts = kmalloc(npartitions*sizeof(*parts)+strlen(name), GFP_KERNEL); + memzero(parts,npartitions*sizeof(*parts)+strlen(name)); if (!parts) { ret = -ENOMEM; goto out; } - memzero(parts,npartitions*sizeof(*parts)+strlen(name)); i=0; names = (char *)&parts[npartitions]; parts[i].name = names; @@ -218,11 +161,10 @@ parts[i].size = FLASH_SIZE-0x00180000; parts[i].offset = 0x00180000; #endif - ret = npartitions; out: *pparts = parts; - return ret; + return npartitions; } diff -Nru a/drivers/mtd/maps/fortunet.c b/drivers/mtd/maps/fortunet.c --- a/drivers/mtd/maps/fortunet.c Mon Jun 9 23:16:08 2003 +++ b/drivers/mtd/maps/fortunet.c Mon Jun 9 23:16:08 2003 @@ -1,11 +1,12 @@ /* fortunet.c memory map * - * $Id: fortunet.c,v 1.2 2002/10/14 12:50:22 rmk Exp $ + * $Id: fortunet.c,v 1.6 2003/05/21 12:45:18 dwmw2 Exp $ */ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> +#include <linux/init.h> #include <asm/io.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> @@ -23,7 +24,7 @@ struct map_region { - int window_addr_phyical; + int window_addr_physical; int altbuswidth; struct map_info map_info; struct mtd_info *mymtd; @@ -37,57 +38,10 @@ static int map_regions_parts[MAX_NUM_REGIONS] = {0,0,0,0}; -__u8 fortunet_read8(struct map_info *map, unsigned long ofs) -{ - return *(__u8 *)(map->map_priv_1 + ofs); -} - -__u16 fortunet_read16(struct map_info *map, unsigned long ofs) -{ - return *(__u16 *)(map->map_priv_1 + ofs); -} - -__u32 fortunet_read32(struct map_info *map, unsigned long ofs) -{ - return *(__u32 *)(map->map_priv_1 + ofs); -} - -void fortunet_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy(to, (void *)(map->map_priv_1 + from), len); -} - -void fortunet_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - *(__u8 *)(map->map_priv_1 + adr) = d; -} - -void fortunet_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - *(__u16 *)(map->map_priv_1 + adr) = d; -} - -void fortunet_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - *(__u32 *)(map->map_priv_1 + adr) = d; -} - -void fortunet_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy((void *)(map->map_priv_1 + to), from, len); -} struct map_info default_map = { - .size = DEF_WINDOW_SIZE, - .buswidth = 4, - .read8 = fortunet_read8, - .read16 = fortunet_read16, - .read32 = fortunet_read32, - .copy_from = fortunet_copy_from, - .write8 = fortunet_write8, - .write16 = fortunet_write16, - .write32 = fortunet_write32, - .copy_to = fortunet_copy_to + .size = DEF_WINDOW_SIZE, + .buswidth = 4, }; static char * __init get_string_option(char *dest,int dest_size,char *sor) @@ -147,7 +101,7 @@ get_options (get_string_option(string,sizeof(string),line),6,params); if(params[0]<1) { - printk(MTD_FORTUNET_PK "Bad paramters for MTD Region " + printk(MTD_FORTUNET_PK "Bad parameters for MTD Region " " name,region-number[,base,size,buswidth,altbuswidth]\n"); return 1; } @@ -161,14 +115,14 @@ memcpy(&map_regions[params[1]].map_info, &default_map,sizeof(map_regions[params[1]].map_info)); map_regions_set[params[1]] = 1; - map_regions[params[1]].window_addr_phyical = DEF_WINDOW_ADDR_PHY; + map_regions[params[1]].window_addr_physical = DEF_WINDOW_ADDR_PHY; map_regions[params[1]].altbuswidth = 2; map_regions[params[1]].mymtd = NULL; map_regions[params[1]].map_info.name = map_regions[params[1]].map_name; strcpy(map_regions[params[1]].map_info.name,string); if(params[0]>1) { - map_regions[params[1]].window_addr_phyical = params[2]; + map_regions[params[1]].window_addr_physical = params[2]; } if(params[0]>2) { @@ -185,14 +139,14 @@ return 1; } -static int __init MTD_New_Partion(char *line) +static int __init MTD_New_Partition(char *line) { char string[MAX_NAME_SIZE]; int params[4]; get_options (get_string_option(string,sizeof(string),line),4,params); if(params[0]<3) { - printk(MTD_FORTUNET_PK "Bad paramters for MTD Partion " + printk(MTD_FORTUNET_PK "Bad parameters for MTD Partition " " name,region-number,size,offset\n"); return 1; } @@ -204,7 +158,7 @@ } if(map_regions_parts[params[1]]>=MAX_NUM_PARTITIONS) { - printk(MTD_FORTUNET_PK "Out of space for partion in this region\n"); + printk(MTD_FORTUNET_PK "Out of space for partition in this region\n"); return 1; } map_regions[params[1]].parts[map_regions_parts[params[1]]].name = @@ -220,7 +174,10 @@ } __setup("MTD_Region=", MTD_New_Region); -__setup("MTD_Partion=", MTD_New_Partion); +__setup("MTD_Partition=", MTD_New_Partition); + +/* Backwards-spelling-compatibility */ +__setup("MTD_Partion=", MTD_New_Partition); int __init init_fortunet(void) { @@ -229,13 +186,13 @@ { if(map_regions_parts[ix]&&(!map_regions_set[ix])) { - printk(MTD_FORTUNET_PK "Region %d is not setup (Seting to default)\n", + printk(MTD_FORTUNET_PK "Region %d is not setup (Setting to default)\n", ix); memset(&map_regions[ix],0,sizeof(map_regions[ix])); memcpy(&map_regions[ix].map_info,&default_map, sizeof(map_regions[ix].map_info)); map_regions_set[ix] = 1; - map_regions[ix].window_addr_phyical = DEF_WINDOW_ADDR_PHY; + map_regions[ix].window_addr_physical = DEF_WINDOW_ADDR_PHY; map_regions[ix].altbuswidth = 2; map_regions[ix].mymtd = NULL; map_regions[ix].map_info.name = map_regions[ix].map_name; @@ -244,30 +201,35 @@ if(map_regions_set[ix]) { iy++; - printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash device at phyicaly " + printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash device at physically " " address %x size %x\n", map_regions[ix].map_info.name, - map_regions[ix].window_addr_phyical, + map_regions[ix].window_addr_physical, map_regions[ix].map_info.size); - map_regions[ix].map_info.map_priv_1 = + + map_regions[ix].map_info.phys = map_regions[ix].window_addr_physical, + + map_regions[ix].map_info.virt = (int)ioremap_nocache( - map_regions[ix].window_addr_phyical, + map_regions[ix].window_addr_physical, map_regions[ix].map_info.size); - if(!map_regions[ix].map_info.map_priv_1) + if(!map_regions[ix].map_info.virt) { printk(MTD_FORTUNET_PK "%s flash failed to ioremap!\n", map_regions[ix].map_info.name); return -ENXIO; } - printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash is veritualy at: %x\n", + simple_map_init(&map_regions[ix].map_info); + + printk(KERN_NOTICE MTD_FORTUNET_PK "%s flash is virtually at: %x\n", map_regions[ix].map_info.name, - map_regions[ix].map_info.map_priv_1); + map_regions[ix].map_info.virt); map_regions[ix].mymtd = do_map_probe("cfi_probe", &map_regions[ix].map_info); if((!map_regions[ix].mymtd)&&( map_regions[ix].altbuswidth!=map_regions[ix].map_info.buswidth)) { - printk(KERN_NOTICE MTD_FORTUNET_PK "Trying alternet buswidth " + printk(KERN_NOTICE MTD_FORTUNET_PK "Trying alternate buswidth " "for %s flash.\n", map_regions[ix].map_info.name); map_regions[ix].map_info.buswidth = @@ -275,7 +237,7 @@ map_regions[ix].mymtd = do_map_probe("cfi_probe", &map_regions[ix].map_info); } - map_regions[ix].mymtd->module = THIS_MODULE; + map_regions[ix].mymtd->owner = THIS_MODULE; add_mtd_partitions(map_regions[ix].mymtd, map_regions[ix].parts,map_regions_parts[ix]); } @@ -297,7 +259,7 @@ del_mtd_partitions( map_regions[ix].mymtd ); map_destroy( map_regions[ix].mymtd ); } - iounmap((void *)map_regions[ix].map_info.map_priv_1); + iounmap((void *)map_regions[ix].map_info.virt); } } } diff -Nru a/drivers/mtd/maps/h720x-flash.c b/drivers/mtd/maps/h720x-flash.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/h720x-flash.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,142 @@ +/* + * Flash memory access on Hynix GMS30C7201/HMS30C7202 based + * evaluation boards + * + * (C) 2002 Jungjun Kim <jungjun.kim@hynix.com> + * 2003 Thomas Gleixner <tglx@linutronix.de> +*/ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/slab.h> + +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> +#include <asm/hardware.h> +#include <asm/io.h> + +static struct mtd_info *mymtd; + +static struct map_info h720x_map = { + .name = "H720X", + .buswidth = 4, + .size = FLASH_SIZE, + .phys = FLASH_PHYS, +}; + +static struct mtd_partition h720x_partitions[] = { + { + .name = "ArMon", + .size = 0x00080000, + .offset = 0, + .mask_flags = MTD_WRITEABLE + },{ + .name = "Env", + .size = 0x00040000, + .offset = 0x00080000, + .mask_flags = MTD_WRITEABLE + },{ + .name = "Kernel", + .size = 0x00180000, + .offset = 0x000c0000, + .mask_flags = MTD_WRITEABLE + },{ + .name = "Ramdisk", + .size = 0x00400000, + .offset = 0x00240000, + .mask_flags = MTD_WRITEABLE + },{ + .name = "jffs2", + .size = MTDPART_SIZ_FULL, + .offset = MTDPART_OFS_APPEND + } +}; + +#define NUM_PARTITIONS (sizeof(h720x_partitions)/sizeof(h720x_partitions[0])) + +static int nr_mtd_parts; +static struct mtd_partition *mtd_parts; +static const char *probes[] = { "cmdlinepart", NULL }; + +/* + * Initialize FLASH support + */ +int __init h720x_mtd_init(void) +{ + + char *part_type = NULL; + + h720x_map.virt = (unsigned long)ioremap(FLASH_PHYS, FLASH_SIZE); + + if (!h720x_map.virt) { + printk(KERN_ERR "H720x-MTD: ioremap failed\n"); + return -EIO; + } + + simple_map_init(&h720x_map); + + // Probe for flash buswidth 4 + printk (KERN_INFO "H720x-MTD probing 32bit FLASH\n"); + mymtd = do_map_probe("cfi_probe", &h720x_map); + if (!mymtd) { + printk (KERN_INFO "H720x-MTD probing 16bit FLASH\n"); + // Probe for buswidth 2 + h720x_map.buswidth = 2; + mymtd = do_map_probe("cfi_probe", &h720x_map); + } + + if (mymtd) { + mymtd->owner = THIS_MODULE; + +#ifdef CONFIG_MTD_PARTITIONS + nr_mtd_parts = parse_mtd_partitions(mymtd, probes, &mtd_parts, 0); + if (nr_mtd_parts > 0) + part_type = "command line"; +#endif + if (nr_mtd_parts <= 0) { + mtd_parts = h720x_partitions; + nr_mtd_parts = NUM_PARTITIONS; + part_type = "builtin"; + } + printk(KERN_INFO "Using %s partition table\n", part_type); + add_mtd_partitions(mymtd, mtd_parts, nr_mtd_parts); + return 0; + } + + iounmap((void *)h720x_map.virt); + return -ENXIO; +} + +/* + * Cleanup + */ +static void __exit h720x_mtd_cleanup(void) +{ + + if (mymtd) { + del_mtd_partitions(mymtd); + map_destroy(mymtd); + } + + /* Free partition info, if commandline partition was used */ + if (mtd_parts && (mtd_parts != h720x_partitions)) + kfree (mtd_parts); + + if (h720x_map.virt) { + iounmap((void *)h720x_map.virt); + h720x_map.virt = 0; + } +} + + +module_init(h720x_mtd_init); +module_exit(h720x_mtd_cleanup); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>"); +MODULE_DESCRIPTION("MTD map driver for Hynix evaluation boards"); diff -Nru a/drivers/mtd/maps/ich2rom.c b/drivers/mtd/maps/ich2rom.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/ich2rom.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,316 @@ +/* + * ich2rom.c + * + * Normal mappings of chips in physical memory + * $Id: ich2rom.c,v 1.7 2003/05/21 12:45:18 dwmw2 Exp $ + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <asm/io.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/config.h> +#include <linux/pci.h> +#include <linux/pci_ids.h> + +#define RESERVE_MEM_REGION 0 + +#define ICH2_FWH_REGION_START 0xFF000000UL +#define ICH2_FWH_REGION_SIZE 0x01000000UL +#define BIOS_CNTL 0x4e +#define FWH_DEC_EN1 0xE3 +#define FWH_DEC_EN2 0xF0 +#define FWH_SEL1 0xE8 +#define FWH_SEL2 0xEE + +struct ich2rom_map_info { + struct map_info map; + struct mtd_info *mtd; + unsigned long window_addr; +}; + +static inline unsigned long addr(struct map_info *map, unsigned long ofs) +{ + unsigned long offset; + offset = ((8*1024*1024) - map->size) + ofs; + if (offset >= (4*1024*1024)) { + offset += 0x400000; + } + return map->map_priv_1 + 0x400000 + offset; +} + +static inline unsigned long dbg_addr(struct map_info *map, unsigned long addr) +{ + return addr - map->map_priv_1 + ICH2_FWH_REGION_START; +} + +static __u8 ich2rom_read8(struct map_info *map, unsigned long ofs) +{ + return __raw_readb(addr(map, ofs)); +} + +static __u16 ich2rom_read16(struct map_info *map, unsigned long ofs) +{ + return __raw_readw(addr(map, ofs)); +} + +static __u32 ich2rom_read32(struct map_info *map, unsigned long ofs) +{ + return __raw_readl(addr(map, ofs)); +} + +static void ich2rom_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy_fromio(to, addr(map, from), len); +} + +static void ich2rom_write8(struct map_info *map, __u8 d, unsigned long ofs) +{ + __raw_writeb(d, addr(map,ofs)); + mb(); +} + +static void ich2rom_write16(struct map_info *map, __u16 d, unsigned long ofs) +{ + __raw_writew(d, addr(map, ofs)); + mb(); +} + +static void ich2rom_write32(struct map_info *map, __u32 d, unsigned long ofs) +{ + __raw_writel(d, addr(map, ofs)); + mb(); +} + +static void ich2rom_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + memcpy_toio(addr(map, to), from, len); +} + +static struct ich2rom_map_info ich2rom_map = { + .map = { + .name = "ICH2 rom", + .phys = NO_XIP, + .size = 0, + .buswidth = 1, + .read8 = ich2rom_read8, + .read16 = ich2rom_read16, + .read32 = ich2rom_read32, + .copy_from = ich2rom_copy_from, + .write8 = ich2rom_write8, + .write16 = ich2rom_write16, + .write32 = ich2rom_write32, + .copy_to = ich2rom_copy_to, + /* Firmware hubs only use vpp when being programmed + * in a factory setting. So in place programming + * needs to use a different method. + */ + }, + .mtd = 0, + .window_addr = 0, +}; + +enum fwh_lock_state { + FWH_DENY_WRITE = 1, + FWH_IMMUTABLE = 2, + FWH_DENY_READ = 4, +}; + +static int ich2rom_set_lock_state(struct mtd_info *mtd, loff_t ofs, size_t len, + enum fwh_lock_state state) +{ + struct map_info *map = mtd->priv; + unsigned long start = ofs; + unsigned long end = start + len -1; + + /* FIXME do I need to guard against concurrency here? */ + /* round down to 64K boundaries */ + start = start & ~0xFFFF; + end = end & ~0xFFFF; + while (start <= end) { + unsigned long ctrl_addr; + ctrl_addr = addr(map, start) - 0x400000 + 2; + writeb(state, ctrl_addr); + start = start + 0x10000; + } + return 0; +} + +static int ich2rom_lock(struct mtd_info *mtd, loff_t ofs, size_t len) +{ + return ich2rom_set_lock_state(mtd, ofs, len, FWH_DENY_WRITE); +} + +static int ich2rom_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) +{ + return ich2rom_set_lock_state(mtd, ofs, len, 0); +} + +static int __devinit ich2rom_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + u16 word; + struct ich2rom_map_info *info = &ich2rom_map; + unsigned long map_size; + + /* For now I just handle the ich2 and I assume there + * are not a lot of resources up at the top of the address + * space. It is possible to handle other devices in the + * top 16MB but it is very painful. Also since + * you can only really attach a FWH to an ICH2 there + * a number of simplifications you can make. + * + * Also you can page firmware hubs if an 8MB window isn't enough + * but don't currently handle that case either. + */ + +#if RESERVE_MEM_REGION + /* Some boards have this reserved and I haven't found a good work + * around to say I know what I'm doing! + */ + if (!request_mem_region(ICH2_FWH_REGION_START, ICH2_FWH_REGION_SIZE, "ich2rom")) { + printk(KERN_ERR "ich2rom: cannot reserve rom window\n"); + goto err_out_none; + } +#endif /* RESERVE_MEM_REGION */ + + /* Enable writes through the rom window */ + pci_read_config_word(pdev, BIOS_CNTL, &word); + if (!(word & 1) && (word & (1<<1))) { + /* The BIOS will generate an error if I enable + * this device, so don't even try. + */ + printk(KERN_ERR "ich2rom: firmware access control, I can't enable writes\n"); + goto err_out_none; + } + pci_write_config_word(pdev, BIOS_CNTL, word | 1); + + + /* Map the firmware hub into my address space. */ + /* Does this use to much virtual address space? */ + info->window_addr = (unsigned long)ioremap( + ICH2_FWH_REGION_START, ICH2_FWH_REGION_SIZE); + if (!info->window_addr) { + printk(KERN_ERR "Failed to ioremap\n"); + goto err_out_free_mmio_region; + } + + /* For now assume the firmware has setup all relevant firmware + * windows. We don't have enough information to handle this case + * intelligently. + */ + + /* FIXME select the firmware hub and enable a window to it. */ + + info->mtd = 0; + info->map.map_priv_1 = info->window_addr; + + map_size = ICH2_FWH_REGION_SIZE; + while(!info->mtd && (map_size > 0)) { + info->map.size = map_size; + info->mtd = do_map_probe("jedec_probe", &ich2rom_map.map); + map_size -= 512*1024; + } + if (!info->mtd) { + goto err_out_iounmap; + } + /* I know I can only be a firmware hub here so put + * in the special lock and unlock routines. + */ + info->mtd->lock = ich2rom_lock; + info->mtd->unlock = ich2rom_unlock; + + info->mtd->owner = THIS_MODULE; + add_mtd_device(info->mtd); + return 0; + +err_out_iounmap: + iounmap((void *)(info->window_addr)); +err_out_free_mmio_region: +#if RESERVE_MEM_REGION + release_mem_region(ICH2_FWH_REGION_START, ICH2_FWH_REGION_SIZE); +#endif +err_out_none: + return -ENODEV; +} + + +static void __devexit ich2rom_remove_one (struct pci_dev *pdev) +{ + struct ich2rom_map_info *info = &ich2rom_map; + u16 word; + + del_mtd_device(info->mtd); + map_destroy(info->mtd); + info->mtd = 0; + info->map.map_priv_1 = 0; + + iounmap((void *)(info->window_addr)); + info->window_addr = 0; + + /* Disable writes through the rom window */ + pci_read_config_word(pdev, BIOS_CNTL, &word); + pci_write_config_word(pdev, BIOS_CNTL, word & ~1); + +#if RESERVE_MEM_REGION + release_mem_region(ICH2_FWH_REGION_START, ICH2_FWH_REGION_SIZE); +#endif +} + +static struct pci_device_id ich2rom_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801BA_0, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801CA_0, + PCI_ANY_ID, PCI_ANY_ID, }, + { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82801DB_0, + PCI_ANY_ID, PCI_ANY_ID, }, + { 0, }, +}; + +MODULE_DEVICE_TABLE(pci, ich2rom_pci_tbl); + +#if 0 +static struct pci_driver ich2rom_driver = { + .name = "ich2rom", + .id_table = ich2rom_pci_tbl, + .probe = ich2rom_init_one, + .remove = ich2rom_remove_one, +}; +#endif + +static struct pci_dev *mydev; +int __init init_ich2rom(void) +{ + struct pci_dev *pdev; + struct pci_device_id *id; + pdev = 0; + for(id = ich2rom_pci_tbl; id->vendor; id++) { + pdev = pci_find_device(id->vendor, id->device, 0); + if (pdev) { + break; + } + } + if (pdev) { + mydev = pdev; + return ich2rom_init_one(pdev, &ich2rom_pci_tbl[0]); + } + return -ENXIO; +#if 0 + return pci_module_init(&ich2rom_driver); +#endif +} + +static void __exit cleanup_ich2rom(void) +{ + ich2rom_remove_one(mydev); +} + +module_init(init_ich2rom); +module_exit(cleanup_ich2rom); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Eric Biederman <ebiederman@lnxi.com>"); +MODULE_DESCRIPTION("MTD map driver for BIOS chips on the ICH2 southbridge"); diff -Nru a/drivers/mtd/maps/impa7.c b/drivers/mtd/maps/impa7.c --- a/drivers/mtd/maps/impa7.c Mon Jun 9 23:16:08 2003 +++ b/drivers/mtd/maps/impa7.c Mon Jun 9 23:16:08 2003 @@ -1,5 +1,5 @@ /* - * $Id: impa7.c,v 1.2 2002/09/05 05:11:24 acurtis Exp $ + * $Id: impa7.c,v 1.8 2003/05/21 12:45:18 dwmw2 Exp $ * * Handle mapping of the NOR flash on implementa A7 boards * @@ -13,6 +13,7 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> +#include <linux/init.h> #include <asm/io.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> @@ -37,75 +38,17 @@ static struct mtd_info *impa7_mtd[NUM_FLASHBANKS] = { 0 }; -__u8 impa7_read8(struct map_info *map, unsigned long ofs) -{ - return __raw_readb(map->map_priv_1 + ofs); -} - -__u16 impa7_read16(struct map_info *map, unsigned long ofs) -{ - return __raw_readw(map->map_priv_1 + ofs); -} - -__u32 impa7_read32(struct map_info *map, unsigned long ofs) -{ - return __raw_readl(map->map_priv_1 + ofs); -} - -void impa7_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, map->map_priv_1 + from, len); -} - -void impa7_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - __raw_writeb(d, map->map_priv_1 + adr); - mb(); -} - -void impa7_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - __raw_writew(d, map->map_priv_1 + adr); - mb(); -} - -void impa7_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - __raw_writel(d, map->map_priv_1 + adr); - mb(); -} - -void impa7_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy_toio(map->map_priv_1 + to, from, len); -} static struct map_info impa7_map[NUM_FLASHBANKS] = { { - .name = "impA7 NOR Flash Bank #0", - .size = WINDOW_SIZE0, - .buswidth = BUSWIDTH, - .read8 = impa7_read8, - .read16 = impa7_read16, - .read32 = impa7_read32, - .copy_from = impa7_copy_from, - .write8 = impa7_write8, - .write16 = impa7_write16, - .write32 = impa7_write32, - .copy_to = impa7_copy_to + .name = "impA7 NOR Flash Bank #0", + .size = WINDOW_SIZE0, + .buswidth = BUSWIDTH, }, { - .name = "impA7 NOR Flash Bank #1", - .size = WINDOW_SIZE1, - .buswidth = BUSWIDTH, - .read8 = impa7_read8, - .read16 = impa7_read16, - .read32 = impa7_read32, - .copy_from = impa7_copy_from, - .write8 = impa7_write8, - .write16 = impa7_write16, - .write32 = impa7_write32, - .copy_to = impa7_copy_to + .name = "impA7 NOR Flash Bank #1", + .size = WINDOW_SIZE1, + .buswidth = BUSWIDTH, }, }; @@ -114,26 +57,22 @@ /* * MTD partitioning stuff */ -static struct mtd_partition static_partitions[] = { +static struct mtd_partition static_partitions[] = +{ { - .name = "FileSystem", - .size = 0x800000, - .offset = 0x00000000 + .name = "FileSystem", + .size = 0x800000, + .offset = 0x00000000 }, }; #define NB_OF(x) (sizeof (x) / sizeof (x[0])) -#ifdef CONFIG_MTD_CMDLINE_PARTS -int parse_cmdline_partitions(struct mtd_info *master, - struct mtd_partition **pparts, - const char *mtd_id); -#endif - #endif static int mtd_parts_nb = 0; static struct mtd_partition *mtd_parts = 0; +static const char *probes[] = { "cmdlinepart", NULL }; int __init init_impa7(void) { @@ -142,8 +81,8 @@ const char *part_type = 0; int i; static struct { u_long addr; u_long size; } pt[NUM_FLASHBANKS] = { - { .addr = WINDOW_ADDR0, .size = WINDOW_SIZE0 }, - { .addr = WINDOW_ADDR1, .size = WINDOW_SIZE1 }, + { WINDOW_ADDR0, WINDOW_SIZE0 }, + { WINDOW_ADDR1, WINDOW_SIZE1 }, }; char mtdid[10]; int devicesfound = 0; @@ -152,13 +91,15 @@ { printk(KERN_NOTICE MSG_PREFIX "probing 0x%08lx at 0x%08lx\n", pt[i].size, pt[i].addr); - impa7_map[i].map_priv_1 = (unsigned long) - ioremap(pt[i].addr, pt[i].size); - if (!impa7_map[i].map_priv_1) { + impa7_map[i].phys = pt[i].addr; + impa7_map[i].virt = (unsigned long) + ioremap(pt[i].addr, pt[i].size); + if (!impa7_map[i].virt) { printk(MSG_PREFIX "failed to ioremap\n"); return -EIO; } + simple_map_init(&impa7_map[i]); impa7_mtd[i] = 0; type = rom_probe_types; @@ -168,15 +109,14 @@ if (impa7_mtd[i]) { - impa7_mtd[i]->module = THIS_MODULE; + impa7_mtd[i]->owner = THIS_MODULE; add_mtd_device(impa7_mtd[i]); devicesfound++; #ifdef CONFIG_MTD_PARTITIONS -#ifdef CONFIG_MTD_CMDLINE_PARTS - sprintf(mtdid, MTDID, i); - mtd_parts_nb = parse_cmdline_partitions(impa7_mtd[i], - &mtd_parts, - mtdid); + mtd_parts_nb = parse_mtd_partitions(impa7_mtd[i], + probes, + &mtd_parts, + 0); if (mtd_parts_nb > 0) part_type = "command line"; #endif @@ -202,7 +142,7 @@ #endif } else - iounmap((void *)impa7_map[i].map_priv_1); + iounmap((void *)impa7_map[i].virt); } return devicesfound == 0 ? -ENXIO : 0; } @@ -217,10 +157,10 @@ del_mtd_device(impa7_mtd[i]); map_destroy(impa7_mtd[i]); } - if (impa7_map[i].map_priv_1) + if (impa7_map[i].virt) { - iounmap((void *)impa7_map[i].map_priv_1); - impa7_map[i].map_priv_1 = 0; + iounmap((void *)impa7_map[i].virt); + impa7_map[i].virt = 0; } } } diff -Nru a/drivers/mtd/maps/integrator-flash.c b/drivers/mtd/maps/integrator-flash.c --- a/drivers/mtd/maps/integrator-flash.c Mon Jun 9 23:16:16 2003 +++ b/drivers/mtd/maps/integrator-flash.c Mon Jun 9 23:16:16 2003 @@ -21,7 +21,7 @@ This is access code for flashes using ARM's flash partitioning standards. - $Id: integrator-flash.c,v 1.7 2001/11/01 20:55:47 rmk Exp $ + $Id: integrator-flash.c,v 1.12 2003/05/20 20:59:30 dwmw2 Exp $ ======================================================================*/ @@ -41,8 +41,6 @@ #include <asm/io.h> #include <asm/system.h> -extern int parse_afs_partitions(struct mtd_info *, struct mtd_partition **); - // board specific stuff - sorry, it should be in arch/arm/mach-*. #ifdef CONFIG_ARCH_INTEGRATOR @@ -153,62 +151,17 @@ } #endif -static __u8 armflash_read8(struct map_info *map, unsigned long ofs) -{ - return readb(ofs + map->map_priv_2); -} - -static __u16 armflash_read16(struct map_info *map, unsigned long ofs) -{ - return readw(ofs + map->map_priv_2); -} - -static __u32 armflash_read32(struct map_info *map, unsigned long ofs) -{ - return readl(ofs + map->map_priv_2); -} - -static void armflash_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy(to, (void *) (from + map->map_priv_2), len); -} - -static void armflash_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - writeb(d, adr + map->map_priv_2); -} - -static void armflash_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - writew(d, adr + map->map_priv_2); -} - -static void armflash_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - writel(d, adr + map->map_priv_2); -} - -static void armflash_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy((void *) (to + map->map_priv_2), from, len); -} static struct map_info armflash_map = { - .name = "AFS", - .read8 = armflash_read8, - .read16 = armflash_read16, - .read32 = armflash_read32, - .copy_from = armflash_copy_from, - .write8 = armflash_write8, - .write16 = armflash_write16, - .write32 = armflash_write32, - .copy_to = armflash_copy_to, - .set_vpp = armflash_set_vpp, + .name = "AFS", + .set_vpp = armflash_set_vpp, + .phys = FLASH_BASE, }; static struct mtd_info *mtd; static struct mtd_partition *parts; +static const char *probes[] = { "RedBoot", "afs", NULL }; static int __init armflash_cfi_init(void *base, u_int size) { @@ -222,7 +175,9 @@ */ armflash_map.size = size; armflash_map.buswidth = 4; - armflash_map.map_priv_2 = (unsigned long) base; + armflash_map.virt = (unsigned long) base; + + simple_map_init(&armflash_map); /* * Also, the CFI layer automatically works out what size @@ -233,9 +188,9 @@ if (!mtd) return -ENXIO; - mtd->module = THIS_MODULE; + mtd->owner = THIS_MODULE; - ret = parse_afs_partitions(mtd, &parts); + ret = parse_mtd_partitions(mtd, probes, &parts, (void *)0); if (ret > 0) { ret = add_mtd_partitions(mtd, parts, ret); if (ret) @@ -290,7 +245,7 @@ static void __exit armflash_exit(void) { armflash_cfi_exit(); - iounmap((void *)armflash_map.map_priv_2); + iounmap((void *)armflash_map.virt); release_mem_region(FLASH_BASE, FLASH_SIZE); armflash_flash_exit(); } diff -Nru a/drivers/mtd/maps/iq80310.c b/drivers/mtd/maps/iq80310.c --- a/drivers/mtd/maps/iq80310.c Mon Jun 9 23:16:18 2003 +++ b/drivers/mtd/maps/iq80310.c Mon Jun 9 23:16:18 2003 @@ -1,5 +1,5 @@ /* - * $Id: iq80310.c,v 1.9 2002/01/01 22:45:02 rmk Exp $ + * $Id: iq80310.c,v 1.16 2003/05/21 15:15:07 dwmw2 Exp $ * * Mapping for the Intel XScale IQ80310 evaluation board * @@ -14,6 +14,8 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> +#include <linux/init.h> +#include <linux/slab.h> #include <asm/io.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> @@ -26,81 +28,32 @@ static struct mtd_info *mymtd; -static __u8 iq80310_read8(struct map_info *map, unsigned long ofs) -{ - return *(__u8 *)(map->map_priv_1 + ofs); -} - -static __u16 iq80310_read16(struct map_info *map, unsigned long ofs) -{ - return *(__u16 *)(map->map_priv_1 + ofs); -} - -static __u32 iq80310_read32(struct map_info *map, unsigned long ofs) -{ - return *(__u32 *)(map->map_priv_1 + ofs); -} - -static void iq80310_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy(to, (void *)(map->map_priv_1 + from), len); -} - -static void iq80310_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - *(__u8 *)(map->map_priv_1 + adr) = d; -} - -static void iq80310_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - *(__u16 *)(map->map_priv_1 + adr) = d; -} - -static void iq80310_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - *(__u32 *)(map->map_priv_1 + adr) = d; -} - -static void iq80310_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy((void *)(map->map_priv_1 + to), from, len); -} - static struct map_info iq80310_map = { - .name = "IQ80310 flash", - .size = WINDOW_SIZE, - .buswidth = BUSWIDTH, - .read8 = iq80310_read8, - .read16 = iq80310_read16, - .read32 = iq80310_read32, - .copy_from = iq80310_copy_from, - .write8 = iq80310_write8, - .write16 = iq80310_write16, - .write32 = iq80310_write32, - .copy_to = iq80310_copy_to + .name = "IQ80310 flash", + .size = WINDOW_SIZE, + .buswidth = BUSWIDTH, + .phys = WINDOW_ADDR }; static struct mtd_partition iq80310_partitions[4] = { { - .name = "Firmware", - .size = 0x00080000, - .mask_flags = MTD_WRITEABLE /* force read-only */ - }, - { - .name = "Kernel", - .size = 0x000a0000, - .offset = 0x00080000, - }, - { - .name = "Filesystem", - .size = 0x00600000, - .offset = 0x00120000 - }, - { - .name = "RedBoot", - .size = 0x000e0000, - .offset = 0x00720000, - .mask_flags = MTD_WRITEABLE + .name = "Firmware", + .size = 0x00080000, + .offset = 0, + .mask_flags = MTD_WRITEABLE /* force read-only */ + },{ + .name = "Kernel", + .size = 0x000a0000, + .offset = 0x00080000, + },{ + .name = "Filesystem", + .size = 0x00600000, + .offset = 0x00120000 + },{ + .name = "RedBoot", + .size = 0x000e0000, + .offset = 0x00720000, + .mask_flags = MTD_WRITEABLE } }; @@ -108,38 +61,33 @@ static struct mtd_info *mymtd; static struct mtd_partition *parsed_parts; - -extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); +static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; static int __init init_iq80310(void) { struct mtd_partition *parts; int nb_parts = 0; int parsed_nr_parts = 0; - char *part_type = "static"; + int ret; - iq80310_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); - if (!iq80310_map.map_priv_1) { + iq80310_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); + if (!iq80310_map.virt) { printk("Failed to ioremap\n"); return -EIO; } + simple_map_init(&iq80310_map); + mymtd = do_map_probe("cfi_probe", &iq80310_map); if (!mymtd) { - iounmap((void *)iq80310_map.map_priv_1); + iounmap((void *)iq80310_map.virt); return -ENXIO; } - mymtd->module = THIS_MODULE; + mymtd->owner = THIS_MODULE; -#ifdef CONFIG_MTD_REDBOOT_PARTS - if (parsed_nr_parts == 0) { - int ret = parse_redboot_partitions(mymtd, &parsed_parts); - - if (ret > 0) { - part_type = "RedBoot"; - parsed_nr_parts = ret; - } - } -#endif + ret = parse_mtd_partitions(mymtd, probes, &parsed_parts, 0); + + if (ret > 0) + parsed_nr_parts = ret; if (parsed_nr_parts > 0) { parts = parsed_parts; @@ -148,7 +96,6 @@ parts = iq80310_partitions; nb_parts = NB_OF(iq80310_partitions); } - printk(KERN_NOTICE "Using %s partition definition\n", part_type); add_mtd_partitions(mymtd, parts, nb_parts); return 0; } @@ -161,8 +108,8 @@ if (parsed_parts) kfree(parsed_parts); } - if (iq80310_map.map_priv_1) - iounmap((void *)iq80310_map.map_priv_1); + if (iq80310_map.virt) + iounmap((void *)iq80310_map.virt); } module_init(init_iq80310); diff -Nru a/drivers/mtd/maps/iq80321.c b/drivers/mtd/maps/iq80321.c --- a/drivers/mtd/maps/iq80321.c Mon Jun 9 23:16:14 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,169 +0,0 @@ -/* - * $Id: iq80321.c,v 1.1.2.1 2003/03/04 16:14:31 ejc Exp $ - * - * Mapping for the Intel XScale IQ80321 evaluation board - * - * Author: Rory Bolt <rorybolt@pacbell.net> - * Copyright: (C) 2002 Rory Bolt - * - * This program is free software; you can 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/kernel.h> -#include <asm/io.h> -#include <linux/mtd/mtd.h> -#include <linux/mtd/map.h> -#include <linux/mtd/partitions.h> - - -#define WINDOW_ADDR 0xf0000000 -#define WINDOW_SIZE 8*1024*1024 -#define BUSWIDTH 1 - -static struct mtd_info *mymtd; - -static __u8 iq80321_read8(struct map_info *map, unsigned long ofs) -{ - return *(__u8 *)(map->map_priv_1 + ofs); -} - -static __u16 iq80321_read16(struct map_info *map, unsigned long ofs) -{ - return *(__u16 *)(map->map_priv_1 + ofs); -} - -static __u32 iq80321_read32(struct map_info *map, unsigned long ofs) -{ - return *(__u32 *)(map->map_priv_1 + ofs); -} - -static void iq80321_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy(to, (void *)(map->map_priv_1 + from), len); -} - -static void iq80321_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - *(__u8 *)(map->map_priv_1 + adr) = d; -} - -static void iq80321_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - *(__u16 *)(map->map_priv_1 + adr) = d; -} - -static void iq80321_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - *(__u32 *)(map->map_priv_1 + adr) = d; -} - -static void iq80321_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy((void *)(map->map_priv_1 + to), from, len); -} - -static struct map_info iq80321_map = { - .name = "IQ80321 flash", - .size = WINDOW_SIZE, - .buswidth = BUSWIDTH, - .read8 = iq80321_read8, - .read16 = iq80321_read16, - .read32 = iq80321_read32, - .copy_from = iq80321_copy_from, - .write8 = iq80321_write8, - .write16 = iq80321_write16, - .write32 = iq80321_write32, - .copy_to = iq80321_copy_to -}; - -static struct mtd_partition iq80321_partitions[4] = { - { - .name = "Firmware", - .size = 0x00080000, - .offset = 0, - .mask_flags = MTD_WRITEABLE /* force read-only */ - },{ - .name = "Kernel", - .size = 0x000a0000, - .offset = 0x00080000, - },{ - .name = "Filesystem", - .size = 0x00600000, - .offset = 0x00120000 - },{ - .name = "RedBoot", - .size = 0x000e0000, - .offset = 0x00720000, - .mask_flags = MTD_WRITEABLE - } -}; - -#define NB_OF(x) (sizeof(x)/sizeof(x[0])) - -static struct mtd_info *mymtd; -static struct mtd_partition *parsed_parts; - -extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); - -static int __init init_iq80321(void) -{ - struct mtd_partition *parts; - int nb_parts = 0; - int parsed_nr_parts = 0; - char *part_type = "Static"; - - iq80321_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); - if (!iq80321_map.map_priv_1) { - printk("Failed to ioremap\n"); - return -EIO; - } - mymtd = do_map_probe("cfi_probe", &iq80321_map); - if (!mymtd) { - iounmap((void *)iq80321_map.map_priv_1); - return -ENXIO; - } - mymtd->module = THIS_MODULE; - -#ifdef CONFIG_MTD_REDBOOT_PARTS - if (parsed_nr_parts == 0) { - int ret = parse_redboot_partitions(mymtd, &parsed_parts); - - if (ret > 0) { - part_type = "RedBoot"; - parsed_nr_parts = ret; - } - } -#endif - - if (parsed_nr_parts > 0) { - parts = parsed_parts; - nb_parts = parsed_nr_parts; - } else { - parts = iq80321_partitions; - nb_parts = NB_OF(iq80321_partitions); - } - printk(KERN_NOTICE "Using %s partition definition\n", part_type); - add_mtd_partitions(mymtd, parts, nb_parts); - return 0; -} - -static void __exit cleanup_iq80321(void) -{ - if (mymtd) { - del_mtd_partitions(mymtd); - map_destroy(mymtd); - if (parsed_parts) - kfree(parsed_parts); - } - if (iq80321_map.map_priv_1) - iounmap((void *)iq80321_map.map_priv_1); -} - -module_init(init_iq80321); -module_exit(cleanup_iq80321); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("MTD map driver for Intel XScale IQ80321 evaluation board"); diff -Nru a/drivers/mtd/maps/l440gx.c b/drivers/mtd/maps/l440gx.c --- a/drivers/mtd/maps/l440gx.c Mon Jun 9 23:16:17 2003 +++ b/drivers/mtd/maps/l440gx.c Mon Jun 9 23:16:17 2003 @@ -1,142 +1,143 @@ /* - * $Id: l440gx.c,v 1.7 2001/10/02 15:05:14 dwmw2 Exp $ + * $Id: l440gx.c,v 1.12 2003/05/21 12:45:19 dwmw2 Exp $ * * BIOS Flash chip on Intel 440GX board. + * + * Bugs this currently does not work under linuxBIOS. */ #include <linux/module.h> #include <linux/pci.h> #include <linux/kernel.h> +#include <linux/init.h> #include <asm/io.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> #include <linux/config.h> +#define PIIXE_IOBASE_RESOURCE 11 #define WINDOW_ADDR 0xfff00000 #define WINDOW_SIZE 0x00100000 #define BUSWIDTH 1 -#define IOBASE 0xc00 +static u32 iobase; +#define IOBASE iobase #define TRIBUF_PORT (IOBASE+0x37) #define VPP_PORT (IOBASE+0x28) static struct mtd_info *mymtd; -__u8 l440gx_read8(struct map_info *map, unsigned long ofs) -{ - return __raw_readb(map->map_priv_1 + ofs); -} - -__u16 l440gx_read16(struct map_info *map, unsigned long ofs) -{ - return __raw_readw(map->map_priv_1 + ofs); -} - -__u32 l440gx_read32(struct map_info *map, unsigned long ofs) -{ - return __raw_readl(map->map_priv_1 + ofs); -} - -void l440gx_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, map->map_priv_1 + from, len); -} - -void l440gx_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - __raw_writeb(d, map->map_priv_1 + adr); - mb(); -} - -void l440gx_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - __raw_writew(d, map->map_priv_1 + adr); - mb(); -} - -void l440gx_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - __raw_writel(d, map->map_priv_1 + adr); - mb(); -} - -void l440gx_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy_toio(map->map_priv_1 + to, from, len); -} +/* Is this really the vpp port? */ void l440gx_set_vpp(struct map_info *map, int vpp) { unsigned long l; l = inl(VPP_PORT); - l = vpp?(l | 1):(l & ~1); + if (vpp) { + l |= 1; + } else { + l &= ~1; + } outl(l, VPP_PORT); } struct map_info l440gx_map = { - .name = "L440GX BIOS", - .size = WINDOW_SIZE, - .buswidth = BUSWIDTH, - .read8 = l440gx_read8, - .read16 = l440gx_read16, - .read32 = l440gx_read32, - .copy_from = l440gx_copy_from, - .write8 = l440gx_write8, - .write16 = l440gx_write16, - .write32 = l440gx_write32, - .copy_to = l440gx_copy_to, - .set_vpp = l440gx_set_vpp + .name = "L440GX BIOS", + .size = WINDOW_SIZE, + .buswidth = BUSWIDTH, + .phys = WINDOW_ADDR, +#if 0 + /* FIXME verify that this is the + * appripriate code for vpp enable/disable + */ + .set_vpp = l440gx_set_vpp +#endif }; static int __init init_l440gx(void) { - struct pci_dev *dev; - unsigned char b; - __u16 w; + struct pci_dev *dev, *pm_dev; + struct resource *pm_iobase; + __u16 word; + + dev = pci_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82371AB_0, NULL); - dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0, - NULL); + pm_dev = pci_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82371AB_3, NULL); - if (!dev) { + if (!dev || !pm_dev) { printk(KERN_NOTICE "L440GX flash mapping: failed to find PIIX4 ISA bridge, cannot continue\n"); return -ENODEV; } + l440gx_map.virt = (unsigned long)ioremap_nocache(WINDOW_ADDR, WINDOW_SIZE); - l440gx_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); - - if (!l440gx_map.map_priv_1) { - printk("Failed to ioremap L440GX flash region\n"); + if (!l440gx_map.virt) { + printk(KERN_WARNING "Failed to ioremap L440GX flash region\n"); return -ENOMEM; } + simple_map_init(&l440gx_map); + printk(KERN_NOTICE "window_addr = 0x%08lx\n", (unsigned long)l440gx_map.virt); + + /* Setup the pm iobase resource + * This code should move into some kind of generic bridge + * driver but for the moment I'm content with getting the + * allocation correct. + */ + pm_iobase = &pm_dev->resource[PIIXE_IOBASE_RESOURCE]; + if (!(pm_iobase->flags & IORESOURCE_IO)) { + pm_iobase->name = "pm iobase"; + pm_iobase->start = 0; + pm_iobase->end = 63; + pm_iobase->flags = IORESOURCE_IO; + + /* Put the current value in the resource */ + pci_read_config_dword(pm_dev, 0x40, &iobase); + iobase &= ~1; + pm_iobase->start += iobase & ~1; + pm_iobase->end += iobase & ~1; + + /* Allocate the resource region */ + if (pci_assign_resource(pm_dev, PIIXE_IOBASE_RESOURCE) != 0) { + printk(KERN_WARNING "Could not allocate pm iobase resource\n"); + iounmap((void *)l440gx_map.virt); + return -ENXIO; + } + } + /* Set the iobase */ + iobase = pm_iobase->start; + pci_write_config_dword(pm_dev, 0x40, iobase | 1); + /* Set XBCS# */ - pci_read_config_word(dev, 0x4e, &w); - w |= 0x4; - pci_write_config_word(dev, 0x4e, w); + pci_read_config_word(dev, 0x4e, &word); + word |= 0x4; + pci_write_config_word(dev, 0x4e, word); + + /* Supply write voltage to the chip */ + l440gx_set_vpp(&l440gx_map, 1); /* Enable the gate on the WE line */ - b = inb(TRIBUF_PORT); - b |= 1; - outb(b, TRIBUF_PORT); + outb(inb(TRIBUF_PORT) & ~1, TRIBUF_PORT); printk(KERN_NOTICE "Enabled WE line to L440GX BIOS flash chip.\n"); - mymtd = do_map_probe("jedec", &l440gx_map); + mymtd = do_map_probe("jedec_probe", &l440gx_map); if (!mymtd) { printk(KERN_NOTICE "JEDEC probe on BIOS chip failed. Using ROM\n"); mymtd = do_map_probe("map_rom", &l440gx_map); } if (mymtd) { - mymtd->module = THIS_MODULE; + mymtd->owner = THIS_MODULE; add_mtd_device(mymtd); return 0; } - iounmap((void *)l440gx_map.map_priv_1); + iounmap((void *)l440gx_map.virt); return -ENXIO; } @@ -145,7 +146,7 @@ del_mtd_device(mymtd); map_destroy(mymtd); - iounmap((void *)l440gx_map.map_priv_1); + iounmap((void *)l440gx_map.virt); } module_init(init_l440gx); diff -Nru a/drivers/mtd/maps/lasat.c b/drivers/mtd/maps/lasat.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/lasat.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,94 @@ +/* + * 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.5 2003/05/21 12:45:19 dwmw2 Exp $ + * + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <asm/io.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#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; + +static struct map_info sp_map = { + .name = "SP flash", + .buswidth = 4, +}; + +static struct mtd_partition partition_info[LASAT_MTD_LAST]; +static char *lasat_mtd_partnames[] = {"Bootloader", "Service", "Normal", "Filesystem", "Config"}; + +static int __init init_sp(void) +{ + int i; + /* this does not play well with the old flash code which + * protects and uprotects the flash when necessary */ + /* FIXME: Implement set_vpp() */ + printk(KERN_NOTICE "Unprotecting flash\n"); + *lasat_misc->flash_wp_reg |= 1 << lasat_misc->flash_wp_bit; + + sp_map.virt = lasat_flash_partition_start(LASAT_MTD_BOOTLOADER); + sp_map.phys = virt_to_phys(sp_map.virt); + sp_map.size = lasat_board_info.li_flash_size; + + simple_map_init(&sp_map); + + printk(KERN_NOTICE "sp flash device: %lx at %lx\n", + sp_map.size, sp_map.phys); + + for (i=0; i < LASAT_MTD_LAST; i++) + partition_info[i].name = lasat_mtd_partnames[i]; + + mymtd = do_map_probe("cfi_probe", &sp_map); + if (mymtd) { + u32 size, offset = 0; + + mymtd->owner = THIS_MODULE; + + 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; + } + + add_mtd_partitions( mymtd, partition_info, LASAT_MTD_LAST ); + return 0; + } + + return -ENXIO; +} + +static void __exit cleanup_sp(void) +{ + if (mymtd) { + del_mtd_partitions(mymtd); + map_destroy(mymtd); + } + if (sp_map.virt) { + sp_map.virt = 0; + } +} + +module_init(init_sp); +module_exit(cleanup_sp); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Brian Murphy <brian@murphy.dk>"); +MODULE_DESCRIPTION("Lasat Safepipe/Masquerade MTD map driver"); diff -Nru a/drivers/mtd/maps/lubbock-flash.c b/drivers/mtd/maps/lubbock-flash.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/lubbock-flash.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,153 @@ +/* + * $Id: lubbock-flash.c,v 1.8 2003/05/21 12:45:19 dwmw2 Exp $ + * + * Map driver for the Lubbock developer platform. + * + * Author: Nicolas Pitre + * Copyright: (C) 2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <asm/io.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> +#include <asm/hardware.h> + + +#define ROM_ADDR 0x00000000 +#define FLASH_ADDR 0x04000000 + +#define WINDOW_SIZE 64*1024*1024 + +static struct map_info lubbock_maps[2] = { { + .size = WINDOW_SIZE, + .phys = 0x00000000, +}, { + .size = WINDOW_SIZE, + .phys = 0x04000000, +} }; + +static struct mtd_partition lubbock_partitions[] = { + { + .name = "Bootloader", + .size = 0x00040000, + .offset = 0, + .mask_flags = MTD_WRITEABLE /* force read-only */ + },{ + .name = "Kernel", + .size = 0x00100000, + .offset = 0x00040000, + },{ + .name = "Filesystem", + .size = MTDPART_SIZ_FULL, + .offset = 0x00140000 + } +}; + +#define NB_OF(x) (sizeof(x)/sizeof(x[0])) + +static struct mtd_info *mymtds[2]; +static struct mtd_partition *parsed_parts[2]; +static int nr_parsed_parts[2]; + +static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; + +static int __init init_lubbock(void) +{ + int flashboot = (CONF_SWITCHES & 1); + int ret = 0, i; + + lubbock_maps[0].buswidth = lubbock_maps[1].buswidth = + (BOOT_DEF & 1) ? 2 : 4; + + /* Compensate for the nROMBT switch which swaps the flash banks */ + printk(KERN_NOTICE "Lubbock configured to boot from %s (bank %d)\n", + flashboot?"Flash":"ROM", flashboot); + + lubbock_maps[flashboot^1].name = "Lubbock Application Flash"; + lubbock_maps[flashboot].name = "Lubbock Boot ROM"; + + for (i = 0; i < 2; i++) { + lubbock_maps[i].virt = (unsigned long)__ioremap(lubbock_maps[i].phys, WINDOW_SIZE, 0); + if (!lubbock_maps[i].virt) { + printk(KERN_WARNING "Failed to ioremap %s\n", lubbock_maps[i].name); + if (!ret) + ret = -ENOMEM; + continue; + } + simple_map_init(&lubbock_maps[i]); + + printk(KERN_NOTICE "Probing %s at physical address 0x%08lx (%d-bit buswidth)\n", + lubbock_maps[i].name, lubbock_maps[i].phys, + lubbock_maps[i].buswidth * 8); + + mymtds[i] = do_map_probe("cfi_probe", &lubbock_maps[i]); + + if (!mymtds[i]) { + iounmap((void *)lubbock_maps[i].virt); + if (!ret) + ret = -EIO; + continue; + } + mymtds[i]->owner = THIS_MODULE; + + int ret = parse_mtd_partitions(mymtds[i], probes, + &parsed_parts[i], 0); + + if (ret > 0) + nr_parsed_parts[i] = ret; + } + + if (!mymtds[0] && !mymtds[1]) + return ret; + + for (i = 0; i < 2; i++) { + if (!mymtds[i]) { + printk(KERN_WARNING "%s is absent. Skipping\n", lubbock_maps[i].name); + } else if (nr_parsed_parts[i]) { + add_mtd_partitions(mymtds[i], parsed_parts[i], nr_parsed_parts[i]); + } else if (!i) { + printk("Using static partitions on %s\n", lubbock_maps[i].name); + add_mtd_partitions(mymtds[i], lubbock_partitions, NB_OF(lubbock_partitions)); + } else { + printk("Registering %s as whole device\n", lubbock_maps[i].name); + add_mtd_device(mymtds[i]); + } + } + return 0; +} + +static void __exit cleanup_lubbock(void) +{ + int i; + for (i = 0; i < 2; i++) { + if (!mymtds[i]) + continue; + + if (nr_parsed_parts[i] || !i) + del_mtd_partitions(mymtds[i]); + else + del_mtd_device(mymtds[i]); + + map_destroy(mymtds[i]); + iounmap((void *)lubbock_maps[i].virt); + + if (parsed_parts[i]) + kfree(parsed_parts[i]); + } +} + +module_init(init_lubbock); +module_exit(cleanup_lubbock); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>"); +MODULE_DESCRIPTION("MTD map driver for Intel Lubbock"); diff -Nru a/drivers/mtd/maps/map_funcs.c b/drivers/mtd/maps/map_funcs.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/map_funcs.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,95 @@ +/* + * $Id: map_funcs.c,v 1.2 2003/05/21 15:15:07 dwmw2 Exp $ + * + * Out-of-line map I/O functions for simple maps when CONFIG_COMPLEX_MAPPINGS + * is enabled. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/config.h> +#include <linux/types.h> +#include <linux/string.h> +#include <asm/io.h> + +#include <linux/mtd/map.h> +#include <linux/mtd/cfi.h> + +static u8 simple_map_read8(struct map_info *map, unsigned long ofs) +{ + return __raw_readb(map->virt + ofs); +} + +static u16 simple_map_read16(struct map_info *map, unsigned long ofs) +{ + return __raw_readw(map->virt + ofs); +} + +static u32 simple_map_read32(struct map_info *map, unsigned long ofs) +{ + return __raw_readl(map->virt + ofs); +} + +static u64 simple_map_read64(struct map_info *map, unsigned long ofs) +{ +#ifndef CONFIG_MTD_CFI_B8 /* 64-bit mappings */ + BUG(); + return 0; +#else + return __raw_readll(map->virt + ofs); +#endif +} + +static void simple_map_write8(struct map_info *map, u8 datum, unsigned long ofs) +{ + __raw_writeb(datum, map->virt + ofs); + mb(); +} + +static void simple_map_write16(struct map_info *map, u16 datum, unsigned long ofs) +{ + __raw_writew(datum, map->virt + ofs); + mb(); +} + +static void simple_map_write32(struct map_info *map, u32 datum, unsigned long ofs) +{ + __raw_writel(datum, map->virt + ofs); + mb(); +} + +static void simple_map_write64(struct map_info *map, u64 datum, unsigned long ofs) +{ +#ifndef CONFIG_MTD_CFI_B8 /* 64-bit mappings */ + BUG(); +#else + __raw_writell(datum, map->virt + ofs); + mb(); +#endif /* CFI_B8 */ +} + +static void simple_map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy_fromio(to, map->virt + from, len); +} + +static void simple_map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + memcpy_toio(map->virt + to, from, len); +} + +void simple_map_init(struct map_info *map) +{ + map->read8 = simple_map_read8; + map->read16 = simple_map_read16; + map->read32 = simple_map_read32; + map->read64 = simple_map_read64; + map->write8 = simple_map_write8; + map->write16 = simple_map_write16; + map->write32 = simple_map_write32; + map->write64 = simple_map_write64; + map->copy_from = simple_map_copy_from; + map->copy_to = simple_map_copy_to; +} + +EXPORT_SYMBOL(simple_map_init); diff -Nru a/drivers/mtd/maps/mbx860.c b/drivers/mtd/maps/mbx860.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/mbx860.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,100 @@ +/* + * $Id: mbx860.c,v 1.5 2003/05/21 12:45:19 dwmw2 Exp $ + * + * Handle mapping of the flash on MBX860 boards + * + * Author: Anton Todorov + * Copyright: (C) 2001 Emness Technology + * + * This program is free software; you can 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/kernel.h> +#include <linux/init.h> +#include <asm/io.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/partitions.h> + + +#define WINDOW_ADDR 0xfe000000 +#define WINDOW_SIZE 0x00200000 + +/* Flash / Partition sizing */ +#define MAX_SIZE_KiB 8192 +#define BOOT_PARTITION_SIZE_KiB 512 +#define KERNEL_PARTITION_SIZE_KiB 5632 +#define APP_PARTITION_SIZE_KiB 2048 + +#define NUM_PARTITIONS 3 + +/* partition_info gives details on the logical partitions that the split the + * single flash device into. If the size if zero we use up to the end of the + * device. */ +static struct mtd_partition partition_info[]={ + { .name = "MBX flash BOOT partition", + .offset = 0, + .size = BOOT_PARTITION_SIZE_KiB*1024 }, + { .name = "MBX flash DATA partition", + .offset = BOOT_PARTITION_SIZE_KiB*1024, + .size = (KERNEL_PARTITION_SIZE_KiB)*1024 }, + { .name = "MBX flash APPLICATION partition", + .offset = (BOOT_PARTITION_SIZE_KiB+KERNEL_PARTITION_SIZE_KiB)*1024 } +}; + + +static struct mtd_info *mymtd; + +struct map_info mbx_map = { + .name = "MBX flash", + .size = WINDOW_SIZE, + .phys = WINDOW_ADDR, + .buswidth = 4, +}; + +int __init init_mbx(void) +{ + printk(KERN_NOTICE "Motorola MBX flash device: 0x%x at 0x%x\n", WINDOW_SIZE*4, WINDOW_ADDR); + mbx_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE * 4); + + if (!mbx_map.virt) { + printk("Failed to ioremap\n"); + return -EIO; + } + simple_map_init(&mbx_map); + + mymtd = do_map_probe("jedec_probe", &mbx_map); + if (mymtd) { + mymtd->owner = THIS_MODULE; + add_mtd_device(mymtd); + add_mtd_partitions(mymtd, partition_info, NUM_PARTITIONS); + return 0; + } + + iounmap((void *)mbx_map.virt); + return -ENXIO; +} + +static void __exit cleanup_mbx(void) +{ + if (mymtd) { + del_mtd_device(mymtd); + map_destroy(mymtd); + } + if (mbx_map.virt) { + iounmap((void *)mbx_map.virt); + mbx_map.virt = 0; + } +} + +module_init(init_mbx); +module_exit(cleanup_mbx); + +MODULE_AUTHOR("Anton Todorov <a.todorov@emness.com>"); +MODULE_DESCRIPTION("MTD map driver for Motorola MBX860 board"); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/mtd/maps/netsc520.c b/drivers/mtd/maps/netsc520.c --- a/drivers/mtd/maps/netsc520.c Mon Jun 9 23:16:16 2003 +++ b/drivers/mtd/maps/netsc520.c Mon Jun 9 23:16:16 2003 @@ -3,7 +3,7 @@ * Copyright (C) 2001 Mark Langsdorf (mark.langsdorf@amd.com) * based on sc520cdp.c by Sysgo Real-Time Solutions GmbH * - * $Id: netsc520.c,v 1.5 2001/10/02 15:05:14 dwmw2 Exp $ + * $Id: netsc520.c,v 1.9 2003/05/21 12:45:19 dwmw2 Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,6 +27,7 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> +#include <linux/init.h> #include <asm/io.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> @@ -50,94 +51,41 @@ ** recoverable afterwards. */ -static __u8 netsc520_read8(struct map_info *map, unsigned long ofs) -{ - return readb(map->map_priv_1 + ofs); -} - -static __u16 netsc520_read16(struct map_info *map, unsigned long ofs) -{ - return readw(map->map_priv_1 + ofs); -} - -static __u32 netsc520_read32(struct map_info *map, unsigned long ofs) -{ - return readl(map->map_priv_1 + ofs); -} - -static void netsc520_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, (void *)(map->map_priv_1 + from), len); -} - -static void netsc520_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - writeb(d, map->map_priv_1 + adr); -} - -static void netsc520_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - writew(d, map->map_priv_1 + adr); -} - -static void netsc520_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - writel(d, map->map_priv_1 + adr); -} - -static void netsc520_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy_toio((void *)(map->map_priv_1 + to), from, len); -} - /* partition_info gives details on the logical partitions that the split the * single flash device into. If the size if zero we use up to the end of the * device. */ -static struct mtd_partition partition_info[] = { - { - .name = "NetSc520 boot kernel", - .size = 0xc0000 - }, - { - .name = "NetSc520 Low BIOS", - .offset = 0xc0000, - .size = 0x40000 - }, - { - .name = "NetSc520 file system", - .offset = 0x100000, - .size = 0xe80000 - }, - { - .name = "NetSc520 High BIOS", - .offset = 0xf80000, - .size = 0x80000 - }, +static struct mtd_partition partition_info[]={ + { + .name = "NetSc520 boot kernel", + .offset = 0, + .size = 0xc0000 + }, + { + .name = "NetSc520 Low BIOS", + .offset = 0xc0000, + .size = 0x40000 + }, + { + .name = "NetSc520 file system", + .offset = 0x100000, + .size = 0xe80000 + }, + { + .name = "NetSc520 High BIOS", + .offset = 0xf80000, + .size = 0x80000 + }, }; #define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0])) -/* - * If no idea what is going on here. This is taken from the FlashFX stuff. - */ -#define ROMCS 1 - - #define WINDOW_SIZE 0x00100000 #define WINDOW_ADDR 0x00200000 static struct map_info netsc520_map = { - .name = "netsc520 Flash Bank", - .size = WINDOW_SIZE, - .buswidth = 4, - .read8 = netsc520_read8, - .read16 = netsc520_read16, - .read32 = netsc520_read32, - .copy_from = netsc520_copy_from, - .write8 = netsc520_write8, - .write16 = netsc520_write16, - .write32 = netsc520_write32, - .copy_to = netsc520_copy_to, - .map_priv_2 = WINDOW_ADDR + .name = "netsc520 Flash Bank", + .size = WINDOW_SIZE, + .buswidth = 4, + .phys = WINDOW_ADDR, }; #define NUM_FLASH_BANKS (sizeof(netsc520_map)/sizeof(struct map_info)) @@ -146,13 +94,16 @@ static int __init init_netsc520(void) { - printk(KERN_NOTICE "NetSc520 flash device: %lx at %lx\n", netsc520_map.size, netsc520_map.map_priv_2); - netsc520_map.map_priv_1 = (unsigned long)ioremap_nocache(netsc520_map.map_priv_2, netsc520_map.size); + printk(KERN_NOTICE "NetSc520 flash device: 0x%lx at 0x%lx\n", netsc520_map.size, netsc520_map.phys); + netsc520_map.virt = (unsigned long)ioremap_nocache(netsc520_map.phys, netsc520_map.size); - if (!netsc520_map.map_priv_1) { + if (!netsc520_map.virt) { printk("Failed to ioremap_nocache\n"); return -EIO; } + + simple_map_init(&netsc520_map); + mymtd = do_map_probe("cfi_probe", &netsc520_map); if(!mymtd) mymtd = do_map_probe("map_ram", &netsc520_map); @@ -160,11 +111,11 @@ mymtd = do_map_probe("map_rom", &netsc520_map); if (!mymtd) { - iounmap((void *)netsc520_map.map_priv_1); + iounmap((void *)netsc520_map.virt); return -ENXIO; } - mymtd->module = THIS_MODULE; + mymtd->owner = THIS_MODULE; add_mtd_partitions( mymtd, partition_info, NUM_PARTITIONS ); return 0; } @@ -175,9 +126,9 @@ del_mtd_partitions(mymtd); map_destroy(mymtd); } - if (netsc520_map.map_priv_1) { - iounmap((void *)netsc520_map.map_priv_1); - netsc520_map.map_priv_1 = 0; + if (netsc520_map.virt) { + iounmap((void *)netsc520_map.virt); + netsc520_map.virt = 0; } } diff -Nru a/drivers/mtd/maps/nettel.c b/drivers/mtd/maps/nettel.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/nettel.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,499 @@ +/****************************************************************************/ + +/* + * nettel.c -- mappings for NETtel/SecureEdge/SnapGear (x86) boards. + * + * (C) Copyright 2000-2001, Greg Ungerer (gerg@snapgear.com) + * (C) Copyright 2001-2002, SnapGear (www.snapgear.com) + * + * $Id: nettel.c,v 1.4 2003/05/20 20:59:30 dwmw2 Exp $ + */ + +/****************************************************************************/ + +#include <linux/module.h> +#include <linux/init.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 <linux/mtd/cfi.h> +#include <linux/reboot.h> +#include <asm/io.h> + +/****************************************************************************/ + +#define INTEL_BUSWIDTH 1 +#define AMD_WINDOW_MAXSIZE 0x00200000 +#define AMD_BUSWIDTH 1 + +/* + * PAR masks and shifts, assuming 64K pages. + */ +#define SC520_PAR_ADDR_MASK 0x00003fff +#define SC520_PAR_ADDR_SHIFT 16 +#define SC520_PAR_TO_ADDR(par) \ + (((par)&SC520_PAR_ADDR_MASK) << SC520_PAR_ADDR_SHIFT) + +#define SC520_PAR_SIZE_MASK 0x01ffc000 +#define SC520_PAR_SIZE_SHIFT 2 +#define SC520_PAR_TO_SIZE(par) \ + ((((par)&SC520_PAR_SIZE_MASK) << SC520_PAR_SIZE_SHIFT) + (64*1024)) + +#define SC520_PAR(cs, addr, size) \ + ((cs) | \ + ((((size)-(64*1024)) >> SC520_PAR_SIZE_SHIFT) & SC520_PAR_SIZE_MASK) | \ + (((addr) >> SC520_PAR_ADDR_SHIFT) & SC520_PAR_ADDR_MASK)) + +#define SC520_PAR_BOOTCS 0x8a000000 +#define SC520_PAR_ROMCS1 0xaa000000 +#define SC520_PAR_ROMCS2 0xca000000 /* Cache disabled, 64K page */ + +static void *nettel_mmcrp = NULL; + +#ifdef CONFIG_MTD_CFI_INTELEXT +static struct mtd_info *intel_mtd; +#endif +static struct mtd_info *amd_mtd; + +/****************************************************************************/ + +/****************************************************************************/ + +#ifdef CONFIG_MTD_CFI_INTELEXT +static struct map_info nettel_intel_map = { + .name = "SnapGear Intel", + .size = 0, + .buswidth = INTEL_BUSWIDTH, +}; + +static struct mtd_partition nettel_intel_partitions[] = { + { + .name = "SnapGear kernel", + .offset = 0, + .size = 0x000e0000 + }, + { + .name = "SnapGear filesystem", + .offset = 0x00100000, + }, + { + .name = "SnapGear config", + .offset = 0x000e0000, + .size = 0x00020000 + }, + { + .name = "SnapGear Intel", + .offset = 0 + }, + { + .name = "SnapGear BIOS Config", + .offset = 0x007e0000, + .size = 0x00020000 + }, + { + .name = "SnapGear BIOS", + .offset = 0x007e0000, + .size = 0x00020000 + }, +}; +#endif + +static struct map_info nettel_amd_map = { + .name = "SnapGear AMD", + .size = AMD_WINDOW_MAXSIZE, + .buswidth = AMD_BUSWIDTH, +}; + +static struct mtd_partition nettel_amd_partitions[] = { + { + .name = "SnapGear BIOS config", + .offset = 0x000e0000, + .size = 0x00010000 + }, + { + .name = "SnapGear BIOS", + .offset = 0x000f0000, + .size = 0x00010000 + }, + { + .name = "SnapGear AMD", + .offset = 0 + }, + { + .name = "SnapGear high BIOS", + .offset = 0x001f0000, + .size = 0x00010000 + } +}; + +#define NUM_AMD_PARTITIONS \ + (sizeof(nettel_amd_partitions)/sizeof(nettel_amd_partitions[0])) + +/****************************************************************************/ + +#ifdef CONFIG_MTD_CFI_INTELEXT + +/* + * Set the Intel flash back to read mode since some old boot + * loaders don't. + */ +static int nettel_reboot_notifier(struct notifier_block *nb, unsigned long val, void *v) +{ + struct cfi_private *cfi = nettel_intel_map.fldrv_priv; + unsigned long b; + + /* Make sure all FLASH chips are put back into read mode */ + for (b = 0; (b < nettel_intel_partitions[3].size); b += 0x100000) { + cfi_send_gen_cmd(0xff, 0x55, b, &nettel_intel_map, cfi, + cfi->device_type, NULL); + } + return(NOTIFY_OK); +} + +static struct notifier_block nettel_notifier_block = { + nettel_reboot_notifier, NULL, 0 +}; + +/* + * Erase the configuration file system. + * Used to support the software reset button. + */ +static void nettel_erasecallback(struct erase_info *done) +{ + wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv; + wake_up(wait_q); +} + +static struct erase_info nettel_erase; + +int nettel_eraseconfig(void) +{ + struct mtd_info *mtd; + DECLARE_WAITQUEUE(wait, current); + wait_queue_head_t wait_q; + int ret; + + init_waitqueue_head(&wait_q); + mtd = get_mtd_device(NULL, 2); + if (mtd) { + nettel_erase.mtd = mtd; + nettel_erase.callback = nettel_erasecallback; + nettel_erase.callback = 0; + nettel_erase.addr = 0; + nettel_erase.len = mtd->size; + nettel_erase.priv = (u_long) &wait_q; + nettel_erase.priv = 0; + + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&wait_q, &wait); + + ret = MTD_ERASE(mtd, &nettel_erase); + if (ret) { + set_current_state(TASK_RUNNING); + remove_wait_queue(&wait_q, &wait); + put_mtd_device(mtd); + return(ret); + } + + schedule(); /* Wait for erase to finish. */ + remove_wait_queue(&wait_q, &wait); + + put_mtd_device(mtd); + } + + return(0); +} + +#else + +int nettel_eraseconfig(void) +{ + return(0); +} + +#endif + +/****************************************************************************/ + +int __init nettel_init(void) +{ + volatile unsigned long *amdpar; + unsigned long amdaddr, maxsize; + int num_amd_partitions=0; +#ifdef CONFIG_MTD_CFI_INTELEXT + volatile unsigned long *intel0par, *intel1par; + unsigned long orig_bootcspar, orig_romcs1par; + unsigned long intel0addr, intel0size; + unsigned long intel1addr, intel1size; + int intelboot, intel0cs, intel1cs; + int num_intel_partitions; +#endif + int rc = 0; + + nettel_mmcrp = (void *) ioremap_nocache(0xfffef000, 4096); + if (nettel_mmcrp == NULL) { + printk("SNAPGEAR: failed to disable MMCR cache??\n"); + return(-EIO); + } + + /* Set CPU clock to be 33.000MHz */ + *((unsigned char *) (nettel_mmcrp + 0xc64)) = 0x01; + + amdpar = (volatile unsigned long *) (nettel_mmcrp + 0xc4); + +#ifdef CONFIG_MTD_CFI_INTELEXT + intelboot = 0; + intel0cs = SC520_PAR_ROMCS1; + intel0par = (volatile unsigned long *) (nettel_mmcrp + 0xc0); + intel1cs = SC520_PAR_ROMCS2; + intel1par = (volatile unsigned long *) (nettel_mmcrp + 0xbc); + + /* + * Save the CS settings then ensure ROMCS1 and ROMCS2 are off, + * otherwise they might clash with where we try to map BOOTCS. + */ + orig_bootcspar = *amdpar; + orig_romcs1par = *intel0par; + *intel0par = 0; + *intel1par = 0; +#endif + + /* + * The first thing to do is determine if we have a separate + * boot FLASH device. Typically this is a small (1 to 2MB) + * AMD FLASH part. It seems that device size is about the + * only way to tell if this is the case... + */ + amdaddr = 0x20000000; + maxsize = AMD_WINDOW_MAXSIZE; + + *amdpar = SC520_PAR(SC520_PAR_BOOTCS, amdaddr, maxsize); + __asm__ ("wbinvd"); + + nettel_amd_map.phys = amdaddr; + nettel_amd_map.virt = (unsigned long) + ioremap_nocache(amdaddr, maxsize); + if (!nettel_amd_map.virt) { + printk("SNAPGEAR: failed to ioremap() BOOTCS\n"); + return(-EIO); + } + simple_map_init(&nettel_amd_map); + + if ((amd_mtd = do_map_probe("jedec_probe", &nettel_amd_map))) { + printk(KERN_NOTICE "SNAPGEAR: AMD flash device size = %dK\n", + amd_mtd->size>>10); + + amd_mtd->owner = THIS_MODULE; + + /* The high BIOS partition is only present for 2MB units */ + num_amd_partitions = NUM_AMD_PARTITIONS; + if (amd_mtd->size < AMD_WINDOW_MAXSIZE) + num_amd_partitions--; + /* Don't add the partition until after the primary INTEL's */ + +#ifdef CONFIG_MTD_CFI_INTELEXT + /* + * Map the Intel flash into memory after the AMD + * It has to start on a multiple of maxsize. + */ + maxsize = SC520_PAR_TO_SIZE(orig_romcs1par); + if (maxsize < (32 * 1024 * 1024)) + maxsize = (32 * 1024 * 1024); + intel0addr = amdaddr + maxsize; +#endif + } else { +#ifdef CONFIG_MTD_CFI_INTELEXT + /* INTEL boot FLASH */ + intelboot++; + + if (!orig_romcs1par) { + intel0cs = SC520_PAR_BOOTCS; + intel0par = (volatile unsigned long *) + (nettel_mmcrp + 0xc4); + intel1cs = SC520_PAR_ROMCS1; + intel1par = (volatile unsigned long *) + (nettel_mmcrp + 0xc0); + + intel0addr = SC520_PAR_TO_ADDR(orig_bootcspar); + maxsize = SC520_PAR_TO_SIZE(orig_bootcspar); + } else { + /* Kernel base is on ROMCS1, not BOOTCS */ + intel0cs = SC520_PAR_ROMCS1; + intel0par = (volatile unsigned long *) + (nettel_mmcrp + 0xc0); + intel1cs = SC520_PAR_BOOTCS; + intel1par = (volatile unsigned long *) + (nettel_mmcrp + 0xc4); + + intel0addr = SC520_PAR_TO_ADDR(orig_romcs1par); + maxsize = SC520_PAR_TO_SIZE(orig_romcs1par); + } + + /* Destroy useless AMD MTD mapping */ + amd_mtd = NULL; + iounmap((void *) nettel_amd_map.virt); + nettel_amd_map.virt = (unsigned long) NULL; +#else + /* Only AMD flash supported */ + return(-ENXIO); +#endif + } + +#ifdef CONFIG_MTD_CFI_INTELEXT + /* + * We have determined the INTEL FLASH configuration, so lets + * go ahead and probe for them now. + */ + + /* Set PAR to the maximum size */ + if (maxsize < (32 * 1024 * 1024)) + maxsize = (32 * 1024 * 1024); + *intel0par = SC520_PAR(intel0cs, intel0addr, maxsize); + + /* Turn other PAR off so the first probe doesn't find it */ + *intel1par = 0; + + /* Probe for the the size of the first Intel flash */ + nettel_intel_map.size = maxsize; + nettel_intel_map.phys = intel0addr; + nettel_intel_map.virt = (unsigned long) + ioremap_nocache(intel0addr, maxsize); + if (!nettel_intel_map.virt) { + printk("SNAPGEAR: failed to ioremap() ROMCS1\n"); + return(-EIO); + } + simple_map_init(&nettel_intel_map); + + intel_mtd = do_map_probe("cfi_probe", &nettel_intel_map); + if (! intel_mtd) { + iounmap((void *) nettel_intel_map.virt); + return(-ENXIO); + } + + /* Set PAR to the detected size */ + intel0size = intel_mtd->size; + *intel0par = SC520_PAR(intel0cs, intel0addr, intel0size); + + /* + * Map second Intel FLASH right after first. Set its size to the + * same maxsize used for the first Intel FLASH. + */ + intel1addr = intel0addr + intel0size; + *intel1par = SC520_PAR(intel1cs, intel1addr, maxsize); + __asm__ ("wbinvd"); + + maxsize += intel0size; + + /* Delete the old map and probe again to do both chips */ + map_destroy(intel_mtd); + intel_mtd = NULL; + iounmap((void *) nettel_intel_map.virt); + + nettel_intel_map.size = maxsize; + nettel_intel_map.virt = (unsigned long) + ioremap_nocache(intel0addr, maxsize); + if (!nettel_intel_map.virt) { + printk("SNAPGEAR: failed to ioremap() ROMCS1/2\n"); + return(-EIO); + } + + intel_mtd = do_map_probe("cfi_probe", &nettel_intel_map); + if (! intel_mtd) { + iounmap((void *) nettel_intel_map.virt); + return(-ENXIO); + } + + intel1size = intel_mtd->size - intel0size; + if (intel1size > 0) { + *intel1par = SC520_PAR(intel1cs, intel1addr, intel1size); + __asm__ ("wbinvd"); + } else { + *intel1par = 0; + } + + printk(KERN_NOTICE "SNAPGEAR: Intel flash device size = %dK\n", + (intel_mtd->size >> 10)); + + intel_mtd->owner = THIS_MODULE; + +#ifndef CONFIG_BLK_DEV_INITRD + ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, 1); +#endif + + num_intel_partitions = sizeof(nettel_intel_partitions) / + sizeof(nettel_intel_partitions[0]); + + if (intelboot) { + /* + * Adjust offset and size of last boot partition. + * Must allow for BIOS region at end of FLASH. + */ + nettel_intel_partitions[1].size = (intel0size + intel1size) - + (1024*1024 + intel_mtd->erasesize); + nettel_intel_partitions[3].size = intel0size + intel1size; + nettel_intel_partitions[4].offset = + (intel0size + intel1size) - intel_mtd->erasesize; + nettel_intel_partitions[4].size = intel_mtd->erasesize; + nettel_intel_partitions[5].offset = + nettel_intel_partitions[4].offset; + nettel_intel_partitions[5].size = + nettel_intel_partitions[4].size; + } else { + /* No BIOS regions when AMD boot */ + num_intel_partitions -= 2; + } + rc = add_mtd_partitions(intel_mtd, nettel_intel_partitions, + num_intel_partitions); +#endif + + if (amd_mtd) { + rc = add_mtd_partitions(amd_mtd, nettel_amd_partitions, + num_amd_partitions); + } + +#ifdef CONFIG_MTD_CFI_INTELEXT + register_reboot_notifier(&nettel_notifier_block); +#endif + + return(rc); +} + +/****************************************************************************/ + +void __exit nettel_cleanup(void) +{ +#ifdef CONFIG_MTD_CFI_INTELEXT + unregister_reboot_notifier(&nettel_notifier_block); +#endif + if (amd_mtd) { + del_mtd_partitions(amd_mtd); + map_destroy(amd_mtd); + } + if (nettel_amd_map.virt) { + iounmap((void *)nettel_amd_map.virt); + nettel_amd_map.virt = 0; + } +#ifdef CONFIG_MTD_CFI_INTELEXT + if (intel_mtd) { + del_mtd_partitions(intel_mtd); + map_destroy(intel_mtd); + } + if (nettel_intel_map.virt) { + iounmap((void *)nettel_intel_map.virt); + nettel_intel_map.virt = 0; + } +#endif +} + +/****************************************************************************/ + +module_init(nettel_init); +module_exit(nettel_cleanup); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>"); +MODULE_DESCRIPTION("SnapGear/SecureEdge FLASH support"); + +/****************************************************************************/ diff -Nru a/drivers/mtd/maps/nora.c b/drivers/mtd/maps/nora.c --- a/drivers/mtd/maps/nora.c Mon Jun 9 23:16:15 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,203 +0,0 @@ -/* - * $Id: nora.c,v 1.21 2001/10/02 15:05:14 dwmw2 Exp $ - * - * This is so simple I love it. - */ - -#include <linux/module.h> -#include <linux/types.h> -#include <linux/kernel.h> - -#include <linux/mtd/mtd.h> -#include <linux/mtd/map.h> - - -#define WINDOW_ADDR 0xd0000000 -#define WINDOW_SIZE 0x04000000 - -static struct mtd_info *mymtd; - -__u8 nora_read8(struct map_info *map, unsigned long ofs) -{ - return *(__u8 *)(WINDOW_ADDR + ofs); -} - -__u16 nora_read16(struct map_info *map, unsigned long ofs) -{ - return *(__u16 *)(WINDOW_ADDR + ofs); -} - -__u32 nora_read32(struct map_info *map, unsigned long ofs) -{ - return *(__u32 *)(WINDOW_ADDR + ofs); -} - -void nora_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy(to, (void *)(WINDOW_ADDR + from), len); -} - -void nora_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - *(__u8 *)(WINDOW_ADDR + adr) = d; -} - -void nora_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - *(__u16 *)(WINDOW_ADDR + adr) = d; -} - -void nora_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - *(__u32 *)(WINDOW_ADDR + adr) = d; -} - -void nora_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy((void *)(WINDOW_ADDR + to), from, len); -} - -struct map_info nora_map = { - .name = "NORA", - .size = WINDOW_SIZE, - .buswidth = 2, - .read8 = nora_read8, - .read16 = nora_read16, - .read32 = nora_read32, - .copy_from = nora_copy_from, - .write8 = nora_write8, - .write16 = nora_write16, - .write32 = nora_write32, - .copy_to = nora_copy_to -}; - - -static int nora_mtd_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) -{ - return mymtd->read(mymtd, from + (unsigned long)mtd->priv, len, retlen, buf); -} - -static int nora_mtd_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) -{ - return mymtd->write(mymtd, to + (unsigned long)mtd->priv, len, retlen, buf); -} - -static int nora_mtd_erase (struct mtd_info *mtd, struct erase_info *instr) -{ - instr->addr += (unsigned long)mtd->priv; - return mymtd->erase(mymtd, instr); -} - -static void nora_mtd_sync (struct mtd_info *mtd) -{ - mymtd->sync(mymtd); -} - -static int nora_mtd_suspend (struct mtd_info *mtd) -{ - return mymtd->suspend(mymtd); -} - -static void nora_mtd_resume (struct mtd_info *mtd) -{ - mymtd->resume(mymtd); -} - - -static struct mtd_info nora_mtds[4] = { /* boot, kernel, ramdisk, fs */ - { - .type = MTD_NORFLASH, - .flags = MTD_CAP_NORFLASH, - .size = 0x60000, - .erasesize = 0x20000, - .name = "NORA boot firmware", - .module = THIS_MODULE, - .erase = nora_mtd_erase, - .read = nora_mtd_read, - .write = nora_mtd_write, - .suspend = nora_mtd_suspend, - .resume = nora_mtd_resume, - .sync = nora_mtd_sync, - }, - { - .type = MTD_NORFLASH, - .flags = MTD_CAP_NORFLASH, - .size = 0x0a0000, - .erasesize = 0x20000, - .name = "NORA kernel", - .module = THIS_MODULE, - .erase = nora_mtd_erase, - .read = nora_mtd_read, - .write = nora_mtd_write, - .suspend = nora_mtd_suspend, - .resume = nora_mtd_resume, - .sync = nora_mtd_sync, - .priv = (void *)0x60000 - }, - { - .type = MTD_NORFLASH, - .flags = MTD_CAP_NORFLASH, - .size = 0x900000, - .erasesize = 0x20000, - .name = "NORA root filesystem", - .module = THIS_MODULE, - .erase = nora_mtd_erase, - .read = nora_mtd_read, - .write = nora_mtd_write, - .suspend = nora_mtd_suspend, - .resume = nora_mtd_resume, - .sync = nora_mtd_sync, - .priv = (void *)0x100000 - }, - { - .type = MTD_NORFLASH, - .flags = MTD_CAP_NORFLASH, - .size = 0x1600000, - .erasesize = 0x20000, - .name = "NORA second filesystem", - .module = THIS_MODULE, - .erase = nora_mtd_erase, - .read = nora_mtd_read, - .write = nora_mtd_write, - .suspend = nora_mtd_suspend, - .resume = nora_mtd_resume, - .sync = nora_mtd_sync, - .priv = (void *)0xa00000 - } -}; - -int __init init_nora(void) -{ - printk(KERN_NOTICE "nora flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR); - - mymtd = do_map_probe("cfi_probe", &nora_map); - if (mymtd) { - mymtd->module = THIS_MODULE; - - add_mtd_device(&nora_mtds[2]); - add_mtd_device(&nora_mtds[0]); - add_mtd_device(&nora_mtds[1]); - add_mtd_device(&nora_mtds[3]); - return 0; - } - - return -ENXIO; -} - -static void __exit cleanup_nora(void) -{ - if (mymtd) { - del_mtd_device(&nora_mtds[3]); - del_mtd_device(&nora_mtds[1]); - del_mtd_device(&nora_mtds[0]); - del_mtd_device(&nora_mtds[2]); - map_destroy(mymtd); - } -} - -module_init(init_nora); -module_exit(cleanup_nora); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Red Hat, Inc. - David Woodhouse <dwmw2@cambridge.redhat.com>"); -MODULE_DESCRIPTION("MTD map driver for Nora board"); diff -Nru a/drivers/mtd/maps/ocelot.c b/drivers/mtd/maps/ocelot.c --- a/drivers/mtd/maps/ocelot.c Mon Jun 9 23:16:19 2003 +++ b/drivers/mtd/maps/ocelot.c Mon Jun 9 23:16:19 2003 @@ -1,5 +1,5 @@ /* - * $Id: ocelot.c,v 1.6 2001/10/02 15:05:14 dwmw2 Exp $ + * $Id: ocelot.c,v 1.12 2003/05/21 12:45:19 dwmw2 Exp $ * * Flash on Momenco Ocelot */ @@ -7,6 +7,7 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> +#include <linux/init.h> #include <asm/io.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> @@ -20,47 +21,23 @@ #define NVRAM_WINDOW_SIZE 0x00007FF0 #define NVRAM_BUSWIDTH 1 -extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); - static unsigned int cacheflush = 0; static struct mtd_info *flash_mtd; static struct mtd_info *nvram_mtd; -__u8 ocelot_read8(struct map_info *map, unsigned long ofs) -{ - return __raw_readb(map->map_priv_1 + ofs); -} - -void ocelot_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - cacheflush = 1; - __raw_writeb(d, map->map_priv_1 + adr); - mb(); -} - -void ocelot_copy_from_cache(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - if (cacheflush) { - dma_cache_inv(map->map_priv_2, map->size); - cacheflush = 0; - } - memcpy_fromio(to, map->map_priv_1 + from, len); -} - -void ocelot_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +static void ocelot_ram_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) { - memcpy_fromio(to, map->map_priv_1 + from, len); -} + struct map_info *map = (struct map_info *)mtd->priv; + size_t done = 0; -void ocelot_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ /* If we use memcpy, it does word-wide writes. Even though we told the GT64120A that it's an 8-bit wide region, word-wide writes don't work. We end up just writing the first byte of the four to all four bytes. So we have this loop instead */ + *retlen = len; while(len) { - __raw_writeb(*(unsigned char *) from, map->map_priv_1 + to); + __raw_writeb(*(unsigned char *) from, map->virt + to); from++; to++; len--; @@ -70,24 +47,21 @@ static struct mtd_partition *parsed_parts; struct map_info ocelot_flash_map = { - .name = "Ocelot boot flash", - .size = FLASH_WINDOW_SIZE, - .buswidth = FLASH_BUSWIDTH, - .read8 = ocelot_read8, - .copy_from = ocelot_copy_from_cache, - .write8 = ocelot_write8, + .name = "Ocelot boot flash", + .size = FLASH_WINDOW_SIZE, + .buswidth = FLASH_BUSWIDTH, + .phys = FLASH_WINDOW_ADDR, }; struct map_info ocelot_nvram_map = { - .name = "Ocelot NVRAM", - .size = NVRAM_WINDOW_SIZE, - .buswidth = NVRAM_BUSWIDTH, - .read8 = ocelot_read8, - .copy_from = ocelot_copy_from, - .write8 = ocelot_write8, - .copy_to = ocelot_copy_to + .name = "Ocelot NVRAM", + .size = NVRAM_WINDOW_SIZE, + .buswidth = NVRAM_BUSWIDTH, + .phys = NVRAM_WINDOW_ADDR, }; +static const char *probes[] = { "RedBoot", NULL }; + static int __init init_ocelot_maps(void) { void *pld; @@ -107,12 +81,13 @@ iounmap(pld); /* Now ioremap the NVRAM space */ - ocelot_nvram_map.map_priv_1 = (unsigned long)ioremap_nocache(NVRAM_WINDOW_ADDR, NVRAM_WINDOW_SIZE); - if (!ocelot_nvram_map.map_priv_1) { + ocelot_nvram_map.virt = (unsigned long)ioremap_nocache(NVRAM_WINDOW_ADDR, NVRAM_WINDOW_SIZE); + if (!ocelot_nvram_map.virt) { printk(KERN_NOTICE "Failed to ioremap Ocelot NVRAM space\n"); return -EIO; } - // ocelot_nvram_map.map_priv_2 = ocelot_nvram_map.map_priv_1; + + simple_map_init(&ocelot_nvram_map); /* And do the RAM probe on it to get an MTD device */ nvram_mtd = do_map_probe("map_ram", &ocelot_nvram_map); @@ -120,22 +95,21 @@ printk("NVRAM probe failed\n"); goto fail_1; } - nvram_mtd->module = THIS_MODULE; + nvram_mtd->owner = THIS_MODULE; nvram_mtd->erasesize = 16; + /* Override the write() method */ + nvram_mtd->write = ocelot_ram_write; /* Now map the flash space */ - ocelot_flash_map.map_priv_1 = (unsigned long)ioremap_nocache(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE); - if (!ocelot_flash_map.map_priv_1) { + ocelot_flash_map.virt = (unsigned long)ioremap_nocache(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE); + if (!ocelot_flash_map.virt) { printk(KERN_NOTICE "Failed to ioremap Ocelot flash space\n"); goto fail_2; } /* Now the cached version */ - ocelot_flash_map.map_priv_2 = (unsigned long)__ioremap(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE, 0); + ocelot_flash_map.cached = (unsigned long)__ioremap(FLASH_WINDOW_ADDR, FLASH_WINDOW_SIZE, 0); - if (!ocelot_flash_map.map_priv_2) { - /* Doesn't matter if it failed. Just use the uncached version */ - ocelot_flash_map.map_priv_2 = ocelot_flash_map.map_priv_1; - } + simple_map_init(&ocelot_flash_map); /* Only probe for flash if the write jumper is present */ if (brd_status & 0x40) { @@ -155,10 +129,10 @@ add_mtd_device(nvram_mtd); - flash_mtd->module = THIS_MODULE; - nr_parts = parse_redboot_partitions(flash_mtd, &parsed_parts); + flash_mtd->owner = THIS_MODULE; + nr_parts = parse_mtd_partitions(flash_mtd, probes, &parsed_parts, 0); - if (nr_parts) + if (nr_parts > 0) add_mtd_partitions(flash_mtd, parsed_parts, nr_parts); else add_mtd_device(flash_mtd); @@ -166,14 +140,13 @@ return 0; fail3: - iounmap((void *)ocelot_flash_map.map_priv_1); - if (ocelot_flash_map.map_priv_2 && - ocelot_flash_map.map_priv_2 != ocelot_flash_map.map_priv_1) - iounmap((void *)ocelot_flash_map.map_priv_2); + iounmap((void *)ocelot_flash_map.virt); + if (ocelot_flash_map.cached) + iounmap((void *)ocelot_flash_map.cached); fail_2: map_destroy(nvram_mtd); fail_1: - iounmap((void *)ocelot_nvram_map.map_priv_1); + iounmap((void *)ocelot_nvram_map.virt); return -ENXIO; } @@ -182,16 +155,16 @@ { del_mtd_device(nvram_mtd); map_destroy(nvram_mtd); - iounmap((void *)ocelot_nvram_map.map_priv_1); + iounmap((void *)ocelot_nvram_map.virt); if (parsed_parts) del_mtd_partitions(flash_mtd); else del_mtd_device(flash_mtd); map_destroy(flash_mtd); - iounmap((void *)ocelot_flash_map.map_priv_1); - if (ocelot_flash_map.map_priv_2 != ocelot_flash_map.map_priv_1) - iounmap((void *)ocelot_flash_map.map_priv_2); + iounmap((void *)ocelot_flash_map.virt); + if (ocelot_flash_map.cached) + iounmap((void *)ocelot_flash_map.cached); } module_init(init_ocelot_maps); diff -Nru a/drivers/mtd/maps/octagon-5066.c b/drivers/mtd/maps/octagon-5066.c --- a/drivers/mtd/maps/octagon-5066.c Mon Jun 9 23:16:08 2003 +++ b/drivers/mtd/maps/octagon-5066.c Mon Jun 9 23:16:08 2003 @@ -1,4 +1,4 @@ -// $Id: octagon-5066.c,v 1.19 2001/10/02 15:05:14 dwmw2 Exp $ +// $Id: octagon-5066.c,v 1.24 2003/05/21 15:15:07 dwmw2 Exp $ /* ###################################################################### Octagon 5066 MTD Driver. @@ -31,6 +31,7 @@ #include <asm/io.h> #include <linux/mtd/map.h> +#include <linux/mtd/mtd.h> #define WINDOW_START 0xe8000 #define WINDOW_LENGTH 0x8000 @@ -151,32 +152,34 @@ static struct map_info oct5066_map[2] = { { - .name = "Octagon 5066 Socket", - .size = 512 * 1024, - .buswidth = 1, - .read8 = oct5066_read8, - .read16 = oct5066_read16, - .read32 = oct5066_read32, - .copy_from = oct5066_copy_from, - .write8 = oct5066_write8, - .write16 = oct5066_write16, - .write32 = oct5066_write32, - .copy_to = oct5066_copy_to, - .map_priv_1 = 1<<6 + .name = "Octagon 5066 Socket", + .phys = NO_XIP, + .size = 512 * 1024, + .buswidth = 1, + .read8 = oct5066_read8, + .read16 = oct5066_read16, + .read32 = oct5066_read32, + .copy_from = oct5066_copy_from, + .write8 = oct5066_write8, + .write16 = oct5066_write16, + .write32 = oct5066_write32, + .copy_to = oct5066_copy_to, + .map_priv_1 = 1<<6 }, { - .name = "Octagon 5066 Internal Flash", - .size = 2 * 1024 * 1024, - .buswidth = 1, - .read8 = oct5066_read8, - .read16 = oct5066_read16, - .read32 = oct5066_read32, - .copy_from = oct5066_copy_from, - .write8 = oct5066_write8, - .write16 = oct5066_write16, - .write32 = oct5066_write32, - .copy_to = oct5066_copy_to, - .map_priv_1 = 2<<6 + .name = "Octagon 5066 Internal Flash", + .phys = NO_XIP, + .size = 2 * 1024 * 1024, + .buswidth = 1, + .read8 = oct5066_read8, + .read16 = oct5066_read16, + .read32 = oct5066_read32, + .copy_from = oct5066_copy_from, + .write8 = oct5066_write8, + .write16 = oct5066_write16, + .write32 = oct5066_write32, + .copy_to = oct5066_copy_to, + .map_priv_1 = 2<<6 } }; @@ -223,33 +226,32 @@ } } iounmap((void *)iomapadr); - release_region(PAGE_IO,1); + release_region(PAGE_IO, 1); } int __init init_oct5066(void) { int i; - + int ret = 0; + // Do an autoprobe sequence - if (check_region(PAGE_IO,1) != 0) - { - printk("5066: Page Register in Use\n"); - return -EAGAIN; - } + if (!request_region(PAGE_IO,1,"Octagon SSD")) { + printk(KERN_NOTICE "5066: Page Register in Use\n"); + return -EAGAIN; + } iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH); if (!iomapadr) { - printk("Failed to ioremap memory region\n"); - return -EIO; + printk(KERN_NOTICE "Failed to ioremap memory region\n"); + ret = -EIO; + goto out_rel; } - if (OctProbe() != 0) - { - printk("5066: Octagon Probe Failed, is this an Octagon 5066 SBC?\n"); - iounmap((void *)iomapadr); - return -EAGAIN; - } - - request_region(PAGE_IO,1,"Octagon SSD"); - + if (OctProbe() != 0) { + printk(KERN_NOTICE "5066: Octagon Probe Failed, is this an Octagon 5066 SBC?\n"); + iounmap((void *)iomapadr); + ret = -EAGAIN; + goto out_unmap; + } + // Print out our little header.. printk("Octagon 5066 SSD IO:0x%x MEM:0x%x-0x%x\n",PAGE_IO,WINDOW_START, WINDOW_START+WINDOW_LENGTH); @@ -263,7 +265,7 @@ if (!oct5066_mtd[i]) oct5066_mtd[i] = do_map_probe("map_rom", &oct5066_map[i]); if (oct5066_mtd[i]) { - oct5066_mtd[i]->module = THIS_MODULE; + oct5066_mtd[i]->owner = THIS_MODULE; add_mtd_device(oct5066_mtd[i]); } } @@ -272,8 +274,14 @@ cleanup_oct5066(); return -ENXIO; } - + return 0; + + out_unmap: + iounmap((void *)iomapadr); + out_rel: + release_region(PAGE_IO, 1); + return ret; } module_init(init_oct5066); diff -Nru a/drivers/mtd/maps/pb1xxx-flash.c b/drivers/mtd/maps/pb1xxx-flash.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/pb1xxx-flash.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,196 @@ +/* + * Flash memory access on Alchemy Pb1xxx boards + * + * (C) 2001 Pete Popov <ppopov@mvista.com> + * + * $Id: pb1xxx-flash.c,v 1.8 2003/05/21 12:45:19 dwmw2 Exp $ + */ + +#include <linux/config.h> +#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 <asm/io.h> +#include <asm/au1000.h> + +#ifdef DEBUG_RW +#define DBG(x...) printk(x) +#else +#define DBG(x...) +#endif + +#ifdef CONFIG_MIPS_PB1000 +#define WINDOW_ADDR 0x1F800000 +#define WINDOW_SIZE 0x800000 +#endif + + +static struct map_info pb1xxx_map = { + .name = "Pb1xxx flash", +}; + + +#ifdef CONFIG_MIPS_PB1000 + +static unsigned long flash_size = 0x00800000; +static unsigned char flash_buswidth = 4; +static struct mtd_partition pb1xxx_partitions[] = { + { + .name = "yamon env", + .size = 0x00020000, + .offset = 0, + .mask_flags = MTD_WRITEABLE + },{ + .name = "User FS", + .size = 0x003e0000, + .offset = 0x20000, + },{ + .name = "boot code", + .size = 0x100000, + .offset = 0x400000, + .mask_flags = MTD_WRITEABLE + },{ + .name = "raw/kernel", + .size = 0x300000, + .offset = 0x500000 + } +}; + +#elif defined(CONFIG_MIPS_PB1500) || defined(CONFIG_MIPS_PB1100) + +static unsigned char flash_buswidth = 4; +#if defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER) +/* both 32MiB banks will be used. Combine the first 32MiB bank and the + * first 28MiB of the second bank together into a single jffs/jffs2 + * partition. + */ +static unsigned long flash_size = 0x04000000; +#define WINDOW_ADDR 0x1C000000 +#define WINDOW_SIZE 0x4000000 +static struct mtd_partition pb1xxx_partitions[] = { + { + .name = "User FS", + .size = 0x3c00000, + .offset = 0x0000000 + },{ + .name = "yamon", + .size = 0x0100000, + .offset = 0x3c00000, + .mask_flags = MTD_WRITEABLE + },{ + .name = "raw kernel", + .size = 0x02c0000, + .offset = 0x3d00000 + } +}; +#elif defined(CONFIG_MTD_PB1500_BOOT) && !defined(CONFIG_MTD_PB1500_USER) +static unsigned long flash_size = 0x02000000; +#define WINDOW_ADDR 0x1E000000 +#define WINDOW_SIZE 0x2000000 +static struct mtd_partition pb1xxx_partitions[] = { + { + .name = "User FS", + .size = 0x1c00000, + .offset = 0x0000000 + },{ + .name = "yamon", + .size = 0x0100000, + .offset = 0x1c00000, + .mask_flags = MTD_WRITEABLE + },{ + .name = "raw kernel", + .size = 0x02c0000, + .offset = 0x1d00000 + } +}; +#elif !defined(CONFIG_MTD_PB1500_BOOT) && defined(CONFIG_MTD_PB1500_USER) +static unsigned long flash_size = 0x02000000; +#define WINDOW_ADDR 0x1C000000 +#define WINDOW_SIZE 0x2000000 +static struct mtd_partition pb1xxx_partitions[] = { + { + .name = "User FS", + .size = 0x1e00000, + .offset = 0x0000000 + },{ + .name = "raw kernel", + .size = 0x0200000, + .offset = 0x1e00000, + } +}; +#else +#error MTD_PB1500 define combo error /* should never happen */ +#endif +#else +#error Unsupported board +#endif + + +#define NB_OF(x) (sizeof(x)/sizeof(x[0])) + +static struct mtd_partition *parsed_parts; +static struct mtd_info *mymtd; + +int __init pb1xxx_mtd_init(void) +{ + struct mtd_partition *parts; + int nb_parts = 0; + char *part_type; + + /* Default flash buswidth */ + pb1xxx_map.buswidth = flash_buswidth; + + /* + * Static partition definition selection + */ + part_type = "static"; + parts = pb1xxx_partitions; + nb_parts = NB_OF(pb1xxx_partitions); + pb1xxx_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 "Pb1xxx flash: probing %d-bit flash bus\n", + pb1xxx_map.buswidth*8); + pb1xxx_map.phys = WINDOW_ADDR; + pb1xxx_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); + + simple_map_init(&pb1xxx_map); + + mymtd = do_map_probe("cfi_probe", &pb1xxx_map); + if (!mymtd) { + iounmap(pb1xxx_map.virt); + return -ENXIO; + } + mymtd->owner = THIS_MODULE; + + add_mtd_partitions(mymtd, parts, nb_parts); + return 0; +} + +static void __exit pb1xxx_mtd_cleanup(void) +{ + if (mymtd) { + del_mtd_partitions(mymtd); + map_destroy(mymtd); + if (parsed_parts) + kfree(parsed_parts); + } + if (pb1xxx_map.virt) + iounmap(pb1xxx_map.virt); +} + +module_init(pb1xxx_mtd_init); +module_exit(pb1xxx_mtd_cleanup); + +MODULE_AUTHOR("Pete Popov"); +MODULE_DESCRIPTION("Pb1xxx CFI map driver"); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/mtd/maps/pci.c b/drivers/mtd/maps/pci.c --- a/drivers/mtd/maps/pci.c Mon Jun 9 23:16:10 2003 +++ b/drivers/mtd/maps/pci.c Mon Jun 9 23:16:10 2003 @@ -7,7 +7,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * $Id: pci.c,v 1.1 2001/09/27 20:28:45 rmk Exp $ + * $Id: pci.c,v 1.5 2003/05/20 20:59:31 dwmw2 Exp $ * * Generic PCI memory map driver. We support the following boards: * - Intel IQ80310 ATU. @@ -98,10 +98,10 @@ } static struct mtd_pci_info intel_iq80310_info = { - .init = intel_iq80310_init, - .exit = intel_iq80310_exit, - .translate = intel_iq80310_translate, - .map_name = "cfi_probe", + .init = intel_iq80310_init, + .exit = intel_iq80310_exit, + .translate = intel_iq80310_translate, + .map_name = "cfi_probe", }; /* @@ -181,10 +181,10 @@ } static struct mtd_pci_info intel_dc21285_info = { - .init = intel_dc21285_init, - .exit = intel_dc21285_exit, - .translate = intel_dc21285_translate, - .map_name = "jedec_probe", + .init = intel_dc21285_init, + .exit = intel_dc21285_exit, + .translate = intel_dc21285_translate, + .map_name = "jedec_probe", }; /* @@ -193,22 +193,22 @@ static struct pci_device_id mtd_pci_ids[] __devinitdata = { { - .vendor = PCI_VENDOR_ID_INTEL, - .device = 0x530d, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .class = PCI_CLASS_MEMORY_OTHER << 8, - .class_mask = 0xffff00, - .driver_data = (unsigned long)&intel_iq80310_info, + .vendor = PCI_VENDOR_ID_INTEL, + .device = 0x530d, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .class = PCI_CLASS_MEMORY_OTHER << 8, + .class_mask = 0xffff00, + .driver_data = (unsigned long)&intel_iq80310_info, }, { - .vendor = PCI_VENDOR_ID_DEC, - .device = PCI_DEVICE_ID_DEC_21285, - .subvendor = 0, /* DC21285 defaults to 0 on reset */ - .subdevice = 0, /* DC21285 defaults to 0 on reset */ - .driver_data = (unsigned long)&intel_dc21285_info, + .vendor = PCI_VENDOR_ID_DEC, + .device = PCI_DEVICE_ID_DEC_21285, + .subvendor = 0, /* DC21285 defaults to 0 on reset */ + .subdevice = 0, /* DC21285 defaults to 0 on reset */ + .driver_data = (unsigned long)&intel_dc21285_info, }, - { .vendor = 0, } + { 0, } }; /* @@ -273,14 +273,15 @@ } static struct map_info mtd_pci_map = { - .read8 = mtd_pci_read8, - .read16 = mtd_pci_read16, - .read32 = mtd_pci_read32, - .copy_from = mtd_pci_copyfrom, - .write8 = mtd_pci_write8, - .write16 = mtd_pci_write16, - .write32 = mtd_pci_write32, - .copy_to = mtd_pci_copyto, + .phys = NO_XIP, + .read8 = mtd_pci_read8, + .read16 = mtd_pci_read16, + .read32 = mtd_pci_read32, + .copy_from = mtd_pci_copyfrom, + .write8 = mtd_pci_write8, + .write16 = mtd_pci_write16, + .write32 = mtd_pci_write32, + .copy_to = mtd_pci_copyto, }; static int __devinit @@ -320,7 +321,7 @@ if (!mtd) goto release; - mtd->module = THIS_MODULE; + mtd->owner = THIS_MODULE; add_mtd_device(mtd); pci_set_drvdata(dev, mtd); @@ -357,10 +358,10 @@ } static struct pci_driver mtd_pci_driver = { - .name = "MTD PCI", - .probe = mtd_pci_probe, - .remove = mtd_pci_remove, - .id_table = mtd_pci_ids, + .name = "MTD PCI", + .probe = mtd_pci_probe, + .remove = __devexit_p(mtd_pci_remove), + .id_table = mtd_pci_ids, }; static int __init mtd_pci_maps_init(void) diff -Nru a/drivers/mtd/maps/pcmciamtd.c b/drivers/mtd/maps/pcmciamtd.c --- a/drivers/mtd/maps/pcmciamtd.c Mon Jun 9 23:16:07 2003 +++ b/drivers/mtd/maps/pcmciamtd.c Mon Jun 9 23:16:07 2003 @@ -1,5 +1,5 @@ /* - * $Id: pcmciamtd.c,v 1.36 2002/10/14 18:49:12 rmk Exp $ + * $Id: pcmciamtd.c,v 1.47 2003/05/28 13:36:14 dwmw2 Exp $ * * pcmciamtd.c - MTD driver for PCMCIA flash memory cards * @@ -14,6 +14,7 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/timer.h> +#include <linux/init.h> #include <asm/io.h> #include <asm/system.h> @@ -24,6 +25,7 @@ #include <pcmcia/ds.h> #include <linux/mtd/map.h> +#include <linux/mtd/mtd.h> #ifdef CONFIG_MTD_DEBUG static int debug = CONFIG_MTD_DEBUG_VERBOSE; @@ -47,7 +49,7 @@ #define DRIVER_DESC "PCMCIA Flash memory card driver" -#define DRIVER_VERSION "$Revision: 1.36 $" +#define DRIVER_VERSION "$Revision: 1.47 $" /* Size of the PCMCIA address space: 26 bits = 64 MB */ #define MAX_PCMCIA_ADDR 0x4000000 @@ -519,6 +521,7 @@ card_settings(dev, link, &new_name); + dev->pcmcia_map.phys = NO_XIP; dev->pcmcia_map.read8 = pcmcia_read8_remap; dev->pcmcia_map.read16 = pcmcia_read16_remap; dev->pcmcia_map.copy_from = pcmcia_copy_from_remap; @@ -529,7 +532,7 @@ dev->pcmcia_map.set_vpp = pcmciamtd_set_vpp; /* Request a memory window for PCMCIA. Some architeures can map windows upto the maximum - that PCMCIA can support (64Mb) - this is ideal and we aim for a window the size of the + that PCMCIA can support (64MiB) - this is ideal and we aim for a window the size of the whole card - otherwise we try smaller windows until we succeed */ req.Attributes = WIN_MEMORY_TYPE_CM | WIN_ENABLE; @@ -542,7 +545,7 @@ do { int ret; - DEBUG(2, "requesting window with size = %dKB memspeed = %d", + DEBUG(2, "requesting window with size = %dKiB memspeed = %d", req.Size >> 10, req.AccessSpeed); link->win = (window_handle_t)link->handle; ret = CardServices(RequestWindow, &link->win, &req); @@ -550,7 +553,7 @@ if(ret) { req.Size >>= 1; } else { - DEBUG(2, "Got window of size %dKB", req.Size >> 10); + DEBUG(2, "Got window of size %dKiB", req.Size >> 10); dev->win_size = req.Size; break; } @@ -563,7 +566,7 @@ pcmciamtd_release((u_long)link); return; } - DEBUG(1, "Allocated a window of %dKB", dev->win_size >> 10); + DEBUG(1, "Allocated a window of %dKiB", dev->win_size >> 10); /* Get write protect status */ CS_CHECK(GetStatus, link->handle, &status); @@ -636,7 +639,7 @@ } dev->mtd_info = mtd; - mtd->module = THIS_MODULE; + mtd->owner = THIS_MODULE; dev->cardsize = mtd->size; if(new_name) { @@ -644,14 +647,14 @@ char unit = ' '; /* Since we are using a default name, make it better by adding in the size */ - if(mtd->size < 1048576) { /* <1MB in size, show size in K */ + if(mtd->size < 1048576) { /* <1MiB in size, show size in KiB */ size = mtd->size >> 10; unit = 'K'; } else { size = mtd->size >> 20; unit = 'M'; } - sprintf(mtd->name, "%d%cB %s", size, unit, "PCMCIA Memory card"); + sprintf(mtd->name, "%d%ciB %s", size, unit, "PCMCIA Memory card"); } /* If the memory found is fits completely into the mapped PCMCIA window, @@ -836,17 +839,18 @@ return link; } +static struct pcmcia_driver pcmciamtd_driver = { + .owner = THIS_MODULE, + .drv = { + .name = "pcmciamtd", + }, + .attach = pcmciamtd_attach, + .detach = pcmciamtd_detach, +}; static int __init init_pcmciamtd(void) { - servinfo_t serv; - info(DRIVER_DESC " " DRIVER_VERSION); - CardServices(GetCardServicesInfo, &serv); - if (serv.Revision != CS_RELEASE_CODE) { - err("Card Services release does not match!"); - return -1; - } if(buswidth && buswidth != 1 && buswidth != 2) { info("bad buswidth (%d), using default", buswidth); @@ -860,8 +864,8 @@ info("bad mem_type (%d), using default", mem_type); mem_type = 0; } - register_pccard_driver(&dev_info, &pcmciamtd_attach, &pcmciamtd_detach); - return 0; + + return pcmcia_register_driver(&pcmciamtd_driver); } @@ -870,7 +874,10 @@ struct list_head *temp1, *temp2; DEBUG(1, DRIVER_DESC " unloading"); - unregister_pccard_driver(&dev_info); + + pcmcia_unregister_driver(&pcmciamtd_driver); + + /* XXX: this really needs to move into generic code.. */ list_for_each_safe(temp1, temp2, &dev_list) { dev_link_t *link = &list_entry(temp1, struct pcmciamtd_dev, list)->link; if (link && (link->state & DEV_CONFIG)) { diff -Nru a/drivers/mtd/maps/physmap.c b/drivers/mtd/maps/physmap.c --- a/drivers/mtd/maps/physmap.c Mon Jun 9 23:16:14 2003 +++ b/drivers/mtd/maps/physmap.c Mon Jun 9 23:16:14 2003 @@ -1,5 +1,5 @@ /* - * $Id: physmap.c,v 1.15 2001/10/02 15:05:14 dwmw2 Exp $ + * $Id: physmap.c,v 1.29 2003/05/29 09:24:10 dwmw2 Exp $ * * Normal mappings of chips in physical memory */ @@ -7,11 +7,13 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> +#include <linux/init.h> +#include <linux/slab.h> #include <asm/io.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> #include <linux/config.h> - +#include <linux/mtd/partitions.h> #define WINDOW_ADDR CONFIG_MTD_PHYSMAP_START #define WINDOW_SIZE CONFIG_MTD_PHYSMAP_LEN @@ -19,94 +21,118 @@ static struct mtd_info *mymtd; -__u8 physmap_read8(struct map_info *map, unsigned long ofs) -{ - return __raw_readb(map->map_priv_1 + ofs); -} - -__u16 physmap_read16(struct map_info *map, unsigned long ofs) -{ - return __raw_readw(map->map_priv_1 + ofs); -} - -__u32 physmap_read32(struct map_info *map, unsigned long ofs) -{ - return __raw_readl(map->map_priv_1 + ofs); -} - -void physmap_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, map->map_priv_1 + from, len); -} -void physmap_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - __raw_writeb(d, map->map_priv_1 + adr); - mb(); -} - -void physmap_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - __raw_writew(d, map->map_priv_1 + adr); - mb(); -} +struct map_info physmap_map = { + .name = "Physically mapped flash", + .size = WINDOW_SIZE, + .buswidth = BUSWIDTH, + .phys = WINDOW_ADDR, +}; -void physmap_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - __raw_writel(d, map->map_priv_1 + adr); - mb(); -} +#ifdef CONFIG_MTD_PARTITIONS +static struct mtd_partition *mtd_parts; +static int mtd_parts_nb; + +static struct mtd_partition physmap_partitions[] = { +#if 0 +/* Put your own partition definitions here */ + { + .name = "bootROM", + .size = 0x80000, + .offset = 0, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, { + .name = "zImage", + .size = 0x100000, + .offset = MTDPART_OFS_APPEND, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, { + .name = "ramdisk.gz", + .size = 0x300000, + .offset = MTDPART_OFS_APPEND, + .mask_flags = MTD_WRITEABLE, /* force read-only */ + }, { + .name = "User FS", + .size = MTDPART_SIZ_FULL, + .offset = MTDPART_OFS_APPEND, + } +#endif +}; -void physmap_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy_toio(map->map_priv_1 + to, from, len); -} +#define NUM_PARTITIONS (sizeof(physmap_partitions)/sizeof(struct mtd_partition)) +const char *part_probes[] = {"cmdlinepart", "RedBoot", NULL}; -struct map_info physmap_map = { - .name = "Physically mapped flash", - .size = WINDOW_SIZE, - .buswidth = BUSWIDTH, - .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 -}; +#endif /* CONFIG_MTD_PARTITIONS */ int __init init_physmap(void) { + static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", 0 }; + const char **type; + printk(KERN_NOTICE "physmap flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR); - physmap_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); + physmap_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); - if (!physmap_map.map_priv_1) { + if (!physmap_map.virt) { printk("Failed to ioremap\n"); return -EIO; } - mymtd = do_map_probe("cfi_probe", &physmap_map); + + simple_map_init(&physmap_map); + + mymtd = 0; + type = rom_probe_types; + for(; !mymtd && *type; type++) { + mymtd = do_map_probe(*type, &physmap_map); + } if (mymtd) { - mymtd->module = THIS_MODULE; + mymtd->owner = THIS_MODULE; + +#ifdef CONFIG_MTD_PARTITIONS + mtd_parts_nb = parse_mtd_partitions(mymtd, part_probes, + &mtd_parts, 0); + + if (mtd_parts_nb > 0) + { + add_mtd_partitions (mymtd, mtd_parts, mtd_parts_nb); + return 0; + } + + if (NUM_PARTITIONS != 0) + { + printk(KERN_NOTICE + "Using physmap partition definition\n"); + add_mtd_partitions (mymtd, physmap_partitions, NUM_PARTITIONS); + return 0; + } +#endif add_mtd_device(mymtd); + return 0; } - iounmap((void *)physmap_map.map_priv_1); + iounmap((void *)physmap_map.virt); return -ENXIO; } static void __exit cleanup_physmap(void) { - if (mymtd) { +#ifdef CONFIG_MTD_PARTITIONS + if (mtd_parts_nb) { + del_mtd_partitions(mymtd); + kfree(mtd_parts); + } else if (NUM_PARTITIONS) { + del_mtd_partitions(mymtd); + } else { del_mtd_device(mymtd); - map_destroy(mymtd); - } - if (physmap_map.map_priv_1) { - iounmap((void *)physmap_map.map_priv_1); - physmap_map.map_priv_1 = 0; } +#else + del_mtd_device(mymtd); +#endif + map_destroy(mymtd); + + iounmap((void *)physmap_map.virt); + physmap_map.virt = 0; } module_init(init_physmap); diff -Nru a/drivers/mtd/maps/pnc2000.c b/drivers/mtd/maps/pnc2000.c --- a/drivers/mtd/maps/pnc2000.c Mon Jun 9 23:16:11 2003 +++ b/drivers/mtd/maps/pnc2000.c Mon Jun 9 23:16:11 2003 @@ -5,12 +5,13 @@ * * This code is GPL * - * $Id: pnc2000.c,v 1.10 2001/10/02 15:05:14 dwmw2 Exp $ + * $Id: pnc2000.c,v 1.14 2003/05/21 12:45:19 dwmw2 Exp $ */ #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> @@ -24,58 +25,13 @@ * MAP DRIVER STUFF */ -__u8 pnc_read8(struct map_info *map, unsigned long ofs) -{ - return *(__u8 *)(WINDOW_ADDR + ofs); -} - -__u16 pnc_read16(struct map_info *map, unsigned long ofs) -{ - return *(__u16 *)(WINDOW_ADDR + ofs); -} - -__u32 pnc_read32(struct map_info *map, unsigned long ofs) -{ - return *(volatile unsigned int *)(WINDOW_ADDR + ofs); -} - -void pnc_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy(to, (void *)(WINDOW_ADDR + from), len); -} - -void pnc_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - *(__u8 *)(WINDOW_ADDR + adr) = d; -} - -void pnc_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - *(__u16 *)(WINDOW_ADDR + adr) = d; -} - -void pnc_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - *(__u32 *)(WINDOW_ADDR + adr) = d; -} - -void pnc_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy((void *)(WINDOW_ADDR + to), from, len); -} struct map_info pnc_map = { - .name = "PNC-2000", - .size = WINDOW_SIZE, - .buswidth = 4, - .read8 = pnc_read8, - .read16 = pnc_read16, - .read32 = pnc_read32, - .copy_from = pnc_copy_from, - .write8 = pnc_write8, - .write16 = pnc_write16, - .write32 = pnc_write32, - .copy_to = pnc_copy_to + .name = "PNC-2000", + .size = WINDOW_SIZE, + .buswidth = 4, + .phys = 0xFFFFFFFF, + .virt = WINDOW_ADDR, }; @@ -84,18 +40,19 @@ */ static struct mtd_partition pnc_partitions[3] = { { - .name = "PNC-2000 boot firmware", - .size = 0x20000, + .name = "PNC-2000 boot firmware", + .size = 0x20000, + .offset = 0 }, { - .name = "PNC-2000 kernel", - .size = 0x1a0000, - .offset = 0x20000 + .name = "PNC-2000 kernel", + .size = 0x1a0000, + .offset = 0x20000 }, { - .name = "PNC-2000 filesystem", - .size = 0x240000, - .offset = 0x1c0000 + .name = "PNC-2000 filesystem", + .size = 0x240000, + .offset = 0x1c0000 } }; @@ -109,9 +66,11 @@ { printk(KERN_NOTICE "Photron PNC-2000 flash mapping: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR); + simple_map_init(&pnc_map); + mymtd = do_map_probe("cfi_probe", &pnc_map); if (mymtd) { - mymtd->module = THIS_MODULE; + mymtd->owner = THIS_MODULE; return add_mtd_partitions(mymtd, pnc_partitions, 3); } diff -Nru a/drivers/mtd/maps/redwood.c b/drivers/mtd/maps/redwood.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/redwood.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,171 @@ +/* + * $Id: redwood.c,v 1.6 2003/05/21 12:45:19 dwmw2 Exp $ + * + * drivers/mtd/maps/redwood.c + * + * FLASH map for the IBM Redwood 4/5/6 boards. + * + * + * Author: Armin Kuster <akuster@mvista.com> + * + * 2001-2002 (c) MontaVista, Software, 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/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 <asm/io.h> + +#if !defined (CONFIG_REDWOOD_6) + +#define WINDOW_ADDR 0xffc00000 +#define WINDOW_SIZE 0x00400000 + +#define RW_PART0_OF 0 +#define RW_PART0_SZ 0x10000 +#define RW_PART1_OF RW_PART0_SZ +#define RW_PART1_SZ 0x200000 - 0x10000 +#define RW_PART2_OF 0x200000 +#define RW_PART2_SZ 0x10000 +#define RW_PART3_OF 0x210000 +#define RW_PART3_SZ 0x200000 - (0x10000 + 0x20000) +#define RW_PART4_OF 0x3e0000 +#define RW_PART4_SZ 0x20000 + +static struct mtd_partition redwood_flash_partitions[] = { + { + .name = "Redwood OpenBIOS Vital Product Data", + .offset = RW_PART0_OF, + .size = RW_PART0_SZ, + .mask_flags = MTD_WRITEABLE /* force read-only */ + }, + { + .name = "Redwood kernel", + .offset = RW_PART1_OF, + .size = RW_PART1_SZ + }, + { + .name = "Redwood OpenBIOS non-volatile storage", + .offset = RW_PART2_OF, + .size = RW_PART2_SZ, + .mask_flags = MTD_WRITEABLE /* force read-only */ + }, + { + .name = "Redwood filesystem", + .offset = RW_PART3_OF, + .size = RW_PART3_SZ + }, + { + .name = "Redwood OpenBIOS", + .offset = RW_PART4_OF, + .size = RW_PART4_SZ, + .mask_flags = MTD_WRITEABLE /* force read-only */ + } +}; + +#else /* CONFIG_REDWOOD_6 */ +/* FIXME: the window is bigger - armin */ +#define WINDOW_ADDR 0xff800000 +#define WINDOW_SIZE 0x00800000 + +#define RW_PART0_OF 0 +#define RW_PART0_SZ 0x400000 /* 4 MiB data */ +#define RW_PART1_OF RW_PART0_OF + RW_PART0_SZ +#define RW_PART1_SZ 0x10000 /* 64K VPD */ +#define RW_PART2_OF RW_PART1_OF + RW_PART1_SZ +#define RW_PART2_SZ 0x400000 - (0x10000 + 0x20000) +#define RW_PART3_OF RW_PART2_OF + RW_PART2_SZ +#define RW_PART3_SZ 0x20000 + +static struct mtd_partition redwood_flash_partitions[] = { + { + .name = "Redwood kernel", + .offset = RW_PART0_OF, + .size = RW_PART0_SZ + }, + { + .name = "Redwood OpenBIOS Vital Product Data", + .offset = RW_PART1_OF, + .size = RW_PART1_SZ, + .mask_flags = MTD_WRITEABLE /* force read-only */ + }, + { + .name = "Redwood filesystem", + .offset = RW_PART2_OF, + .size = RW_PART2_SZ + }, + { + .name = "Redwood OpenBIOS", + .offset = RW_PART3_OF, + .size = RW_PART3_SZ, + .mask_flags = MTD_WRITEABLE /* force read-only */ + } +}; + +#endif /* CONFIG_REDWOOD_6 */ + +struct map_info redwood_flash_map = { + .name = "IBM Redwood", + .size = WINDOW_SIZE, + .buswidth = 2, + .phys = WINDOW_ADDR, +}; + + +#define NUM_REDWOOD_FLASH_PARTITIONS \ + (sizeof(redwood_flash_partitions)/sizeof(redwood_flash_partitions[0])) + +static struct mtd_info *redwood_mtd; + +int __init init_redwood_flash(void) +{ + printk(KERN_NOTICE "redwood: flash mapping: %x at %x\n", + WINDOW_SIZE, WINDOW_ADDR); + + redwood_flash_map.virt = + (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE); + + if (!redwood_flash_map.virt) { + printk("init_redwood_flash: failed to ioremap\n"); + return -EIO; + } + simple_map_init(&redwood_flash_map); + + redwood_mtd = do_map_probe("cfi_probe",&redwood_flash_map); + + if (redwood_mtd) { + redwood_mtd->owner = THIS_MODULE; + return add_mtd_partitions(redwood_mtd, + redwood_flash_partitions, + NUM_REDWOOD_FLASH_PARTITIONS); + } + + return -ENXIO; +} + +static void __exit cleanup_redwood_flash(void) +{ + if (redwood_mtd) { + del_mtd_partitions(redwood_mtd); + /* moved iounmap after map_destroy - armin */ + map_destroy(redwood_mtd); + iounmap((void *)redwood_flash_map.virt); + } +} + +module_init(init_redwood_flash); +module_exit(cleanup_redwood_flash); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Armin Kuster <akuster@mvista.com>"); +MODULE_DESCRIPTION("MTD map driver for the IBM Redwood reference boards"); diff -Nru a/drivers/mtd/maps/rpxlite.c b/drivers/mtd/maps/rpxlite.c --- a/drivers/mtd/maps/rpxlite.c Mon Jun 9 23:16:19 2003 +++ b/drivers/mtd/maps/rpxlite.c Mon Jun 9 23:16:19 2003 @@ -1,5 +1,5 @@ /* - * $Id: rpxlite.c,v 1.15 2001/10/02 15:05:14 dwmw2 Exp $ + * $Id: rpxlite.c,v 1.19 2003/05/21 12:45:19 dwmw2 Exp $ * * Handle mapping of the flash on the RPX Lite and CLLF boards */ @@ -7,6 +7,7 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> +#include <linux/init.h> #include <asm/io.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> @@ -17,80 +18,31 @@ static struct mtd_info *mymtd; -__u8 rpxlite_read8(struct map_info *map, unsigned long ofs) -{ - return __raw_readb(map->map_priv_1 + ofs); -} - -__u16 rpxlite_read16(struct map_info *map, unsigned long ofs) -{ - return __raw_readw(map->map_priv_1 + ofs); -} - -__u32 rpxlite_read32(struct map_info *map, unsigned long ofs) -{ - return __raw_readl(map->map_priv_1 + ofs); -} - -void rpxlite_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, (void *)(map->map_priv_1 + from), len); -} - -void rpxlite_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - __raw_writeb(d, map->map_priv_1 + adr); - mb(); -} - -void rpxlite_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - __raw_writew(d, map->map_priv_1 + adr); - mb(); -} - -void rpxlite_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - __raw_writel(d, map->map_priv_1 + adr); - mb(); -} - -void rpxlite_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy_toio((void *)(map->map_priv_1 + to), from, len); -} - -struct map_info rpxlite_map = { - .name = "RPX", - .size = WINDOW_SIZE, - .buswidth = 4, - .read8 = rpxlite_read8, - .read16 = rpxlite_read16, - .read32 = rpxlite_read32, - .copy_from = rpxlite_copy_from, - .write8 = rpxlite_write8, - .write16 = rpxlite_write16, - .write32 = rpxlite_write32, - .copy_to = rpxlite_copy_to +static struct map_info rpxlite_map = { + .name = "RPX", + .size = WINDOW_SIZE, + .buswidth = 4, + .phys = WINDOW_ADDR, }; int __init init_rpxlite(void) { printk(KERN_NOTICE "RPX Lite or CLLF flash device: %x at %x\n", WINDOW_SIZE*4, WINDOW_ADDR); - rpxlite_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE * 4); + rpxlite_map.virt = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE * 4); - if (!rpxlite_map.map_priv_1) { + if (!rpxlite_map.virt) { printk("Failed to ioremap\n"); return -EIO; } + simple_map_init(&rpxlite_map); mymtd = do_map_probe("cfi_probe", &rpxlite_map); if (mymtd) { - mymtd->module = THIS_MODULE; + mymtd->owner = THIS_MODULE; add_mtd_device(mymtd); return 0; } - iounmap((void *)rpxlite_map.map_priv_1); + iounmap((void *)rpxlite_map.virt); return -ENXIO; } @@ -100,9 +52,9 @@ del_mtd_device(mymtd); map_destroy(mymtd); } - if (rpxlite_map.map_priv_1) { - iounmap((void *)rpxlite_map.map_priv_1); - rpxlite_map.map_priv_1 = 0; + if (rpxlite_map.virt) { + iounmap((void *)rpxlite_map.virt); + rpxlite_map.virt = 0; } } diff -Nru a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c --- a/drivers/mtd/maps/sa1100-flash.c Mon Jun 9 23:16:08 2003 +++ b/drivers/mtd/maps/sa1100-flash.c Mon Jun 9 23:16:08 2003 @@ -3,7 +3,7 @@ * * (C) 2000 Nicolas Pitre <nico@cam.org> * - * $Id: sa1100-flash.c,v 1.28 2002/05/07 13:48:38 abz Exp $ + * $Id: sa1100-flash.c,v 1.36 2003/05/29 08:59:35 dwmw2 Exp $ */ #include <linux/config.h> @@ -11,6 +11,9 @@ #include <linux/types.h> #include <linux/ioport.h> #include <linux/kernel.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/slab.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> @@ -33,59 +36,6 @@ */ #define CONFIG_MTD_SA1100_STATICMAP 1 -static __u8 sa1100_read8(struct map_info *map, unsigned long ofs) -{ - return readb(map->map_priv_1 + ofs); -} - -static __u16 sa1100_read16(struct map_info *map, unsigned long ofs) -{ - return readw(map->map_priv_1 + ofs); -} - -static __u32 sa1100_read32(struct map_info *map, unsigned long ofs) -{ - return readl(map->map_priv_1 + ofs); -} - -static void sa1100_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy(to, (void *)(map->map_priv_1 + from), len); -} - -static void sa1100_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - writeb(d, map->map_priv_1 + adr); -} - -static void sa1100_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - writew(d, map->map_priv_1 + adr); -} - -static void sa1100_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - writel(d, map->map_priv_1 + adr); -} - -static void sa1100_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy((void *)(map->map_priv_1 + to), from, len); -} - -static struct map_info sa1100_map __initdata = { - .name = "SA1100 flash", - .read8 = sa1100_read8, - .read16 = sa1100_read16, - .read32 = sa1100_read32, - .copy_from = sa1100_copy_from, - .write8 = sa1100_write8, - .write16 = sa1100_write16, - .write32 = sa1100_write32, - .copy_to = sa1100_copy_to, -}; - - #ifdef CONFIG_MTD_SA1100_STATICMAP /* * Here are partition information for all known SA1100-based devices. @@ -959,6 +909,7 @@ unsigned long size; int width; void *vbase; + void (*set_vpp)(struct map_info *, int); struct map_info *map; struct mtd_info *mtd; struct resource *res; @@ -981,6 +932,8 @@ if (!maps) return -ENOMEM; + memset(maps, 0, sizeof(struct map_info) * nr); + /* * Claim and then map the memory regions. */ @@ -995,7 +948,6 @@ } sa[i].map = maps + i; - memcpy(sa[i].map, &sa1100_map, sizeof(struct map_info)); sa[i].vbase = ioremap(sa[i].base, sa[i].size); if (!sa[i].vbase) { @@ -1003,10 +955,14 @@ break; } - sa[i].map->map_priv_1 = (unsigned long)sa[i].vbase; + sa[i].map->virt = (unsigned long)sa[i].vbase; + sa[i].map->phys = sa[i].base; + sa[i].map->set_vpp = sa[i].set_vpp; sa[i].map->buswidth = sa[i].width; sa[i].map->size = sa[i].size; + simple_map_init(sa[i].map); + /* * Now let's probe for the actual flash. Do it here since * specific machine settings might have been set above. @@ -1016,7 +972,7 @@ ret = -ENXIO; break; } - sa[i].mtd->module = THIS_MODULE; + sa[i].mtd->owner = THIS_MODULE; subdev[i] = sa[i].mtd; printk(KERN_INFO "SA1100 flash: CFI device at 0x%08lx, %dMiB, " @@ -1105,10 +1061,76 @@ kfree(sa[0].map); } +/* + * A Thought: can we automatically detect the flash? + * - Check to see if the region is busy (yes -> failure) + * - Is the MSC setup for flash (no -> failure) + * - Probe for flash + */ + +static struct map_info sa1100_probe_map __initdata = { + .name = "SA1100-flash", +}; + +static void __init sa1100_probe_one_cs(unsigned int msc, unsigned long phys) +{ + struct mtd_info *mtd; + + printk(KERN_INFO "* Probing 0x%08lx: MSC = 0x%04x %d bit ", + phys, msc & 0xffff, msc & MSC_RBW ? 16 : 32); + + if (check_mem_region(phys, 0x08000000)) { + printk("busy\n"); + return; + } + + if ((msc & 3) == 1) { + printk("wrong type\n"); + return; + } + + sa1100_probe_map.buswidth = msc & MSC_RBW ? 2 : 4; + sa1100_probe_map.size = SZ_1M; + sa1100_probe_map.phys = phys; + sa1100_probe_map.virt = (unsigned long)ioremap(phys, SZ_1M); + if (sa1100_probe_map.virt == 0) + goto fail; + simple_map_init(&sa1100_probe_map); + + /* Shame cfi_probe blurts out kernel messages... */ + mtd = do_map_probe("cfi_probe", &sa1100_probe_map); + if (mtd) + map_destroy(mtd); + iounmap((void *)sa1100_probe_map.virt); + + if (!mtd) + goto fail; + + printk("pass\n"); + return; + + fail: + printk("failed\n"); +} + +static void __init sa1100_probe_flash(void) +{ + printk(KERN_INFO "-- SA11xx Flash probe. Please report results.\n"); + sa1100_probe_one_cs(MSC0, SA1100_CS0_PHYS); + sa1100_probe_one_cs(MSC0 >> 16, SA1100_CS1_PHYS); + sa1100_probe_one_cs(MSC1, SA1100_CS2_PHYS); + sa1100_probe_one_cs(MSC1 >> 16, SA1100_CS3_PHYS); + sa1100_probe_one_cs(MSC2, SA1100_CS4_PHYS); + sa1100_probe_one_cs(MSC2 >> 16, SA1100_CS5_PHYS); + printk(KERN_INFO "-- SA11xx Flash probe complete.\n"); +} + static int __init sa1100_locate_flash(void) { int i, nr = -ENODEV; + sa1100_probe_flash(); + if (machine_is_adsbitsy()) { info[0].base = SA1100_CS1_PHYS; info[0].size = SZ_32M; @@ -1162,7 +1184,7 @@ nr = 1; } if (machine_is_h3xxx()) { - sa1100_map.set_vpp = h3xxx_set_vpp; + info[0].set_vpp = h3xxx_set_vpp; info[0].base = SA1100_CS0_PHYS; info[0].size = SZ_32M; nr = 1; @@ -1178,7 +1200,7 @@ nr = 1; } if (machine_is_jornada720()) { - sa1100_map.set_vpp = jornada720_set_vpp; + info[0].set_vpp = jornada720_set_vpp; info[0].base = SA1100_CS0_PHYS; info[0].size = SZ_32M; nr = 1; @@ -1273,10 +1295,8 @@ return nr; } -extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); -extern int parse_cmdline_partitions(struct mtd_info *master, struct mtd_partition **pparts, char *); - static struct mtd_partition *parsed_parts; +const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL }; static void __init sa1100_locate_partitions(struct mtd_info *mtd) { @@ -1287,17 +1307,10 @@ /* * Partition selection stuff. */ -#ifdef CONFIG_MTD_CMDLINE_PARTS - nr_parts = parse_cmdline_partitions(mtd, &parsed_parts, "sa1100"); - if (nr_parts > 0) { - part_type = "command line"; - break; - } -#endif -#ifdef CONFIG_MTD_REDBOOT_PARTS - nr_parts = parse_redboot_partitions(mtd, &parsed_parts); +#ifdef CONFIG_MTD_PARTITIONS + nr_parts = parse_mtd_partitions(mtd, part_probes, &parsed_parts, 0); if (nr_parts > 0) { - part_type = "RedBoot"; + part_type = "dynamic"; break; } #endif diff -Nru a/drivers/mtd/maps/sbc_gxx.c b/drivers/mtd/maps/sbc_gxx.c --- a/drivers/mtd/maps/sbc_gxx.c Mon Jun 9 23:16:14 2003 +++ b/drivers/mtd/maps/sbc_gxx.c Mon Jun 9 23:16:14 2003 @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - $Id: sbc_gxx.c,v 1.19 2001/10/02 15:05:14 dwmw2 Exp $ + $Id: sbc_gxx.c,v 1.26 2003/05/26 08:50:36 dwmw2 Exp $ The SBC-MediaGX / SBC-GXx has up to 16 MiB of Intel StrataFlash (28F320/28F640) in x8 mode. @@ -26,7 +26,7 @@ The flash is accessed as follows: - 16 kbyte memory window at 0xdc000-0xdffff + 16 KiB memory window at 0xdc000-0xdffff Two IO address locations for paging @@ -90,20 +90,15 @@ /* partition_info gives details on the logical partitions that the split the * single flash device into. If the size if zero we use up to the end of the * device. */ -static struct mtd_partition partition_info[] = { - { - .name = "SBC-GXx flash boot partition", - .size = BOOT_PARTITION_SIZE_KiB*1024 - }, - { - .name = "SBC-GXx flash data partition", - .offset = BOOT_PARTITION_SIZE_KiB*1024, - .size = (DATA_PARTITION_SIZE_KiB)*1024 - }, - { - .name = "SBC-GXx flash application partition", - .offset = (BOOT_PARTITION_SIZE_KiB+DATA_PARTITION_SIZE_KiB)*1024 - } +static struct mtd_partition partition_info[]={ + { .name = "SBC-GXx flash boot partition", + .offset = 0, + .size = BOOT_PARTITION_SIZE_KiB*1024 }, + { .name = "SBC-GXx flash data partition", + .offset = BOOT_PARTITION_SIZE_KiB*1024, + .size = (DATA_PARTITION_SIZE_KiB)*1024 }, + { .name = "SBC-GXx flash application partition", + .offset = (BOOT_PARTITION_SIZE_KiB+DATA_PARTITION_SIZE_KiB)*1024 } }; #define NUM_PARTITIONS 3 @@ -208,20 +203,20 @@ } static struct map_info sbc_gxx_map = { - .name = "SBC-GXx flash", - .size = MAX_SIZE_KiB*1024, /* this must be set to a maximum - possible amount of flash so - the cfi probe routines find - all the chips */ - .buswidth = 1, - .read8 = sbc_gxx_read8, - .read16 = sbc_gxx_read16, - .read32 = sbc_gxx_read32, - .copy_from = sbc_gxx_copy_from, - .write8 = sbc_gxx_write8, - .write16 = sbc_gxx_write16, - .write32 = sbc_gxx_write32, - .copy_to = sbc_gxx_copy_to + .name = "SBC-GXx flash", + .phys = NO_XIP, + .size = MAX_SIZE_KiB*1024, /* this must be set to a maximum possible amount + of flash so the cfi probe routines find all + the chips */ + .buswidth = 1, + .read8 = sbc_gxx_read8, + .read16 = sbc_gxx_read16, + .read32 = sbc_gxx_read32, + .copy_from = sbc_gxx_copy_from, + .write8 = sbc_gxx_write8, + .write16 = sbc_gxx_write16, + .write32 = sbc_gxx_write32, + .copy_to = sbc_gxx_copy_to }; /* MTD device for all of the flash. */ @@ -240,12 +235,6 @@ int __init init_sbc_gxx(void) { - if (check_region(PAGE_IO,PAGE_IO_SIZE) != 0) { - printk( KERN_ERR"%s: IO ports 0x%x-0x%x in use\n", - sbc_gxx_map.name, - PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1 ); - return -EAGAIN; - } iomapadr = (unsigned long)ioremap(WINDOW_START, WINDOW_LENGTH); if (!iomapadr) { printk( KERN_ERR"%s: failed to ioremap memory region\n", @@ -253,7 +242,14 @@ return -EIO; } - request_region( PAGE_IO, PAGE_IO_SIZE, "SBC-GXx flash" ); + if (!request_region( PAGE_IO, PAGE_IO_SIZE, "SBC-GXx flash")) { + printk( KERN_ERR"%s: IO ports 0x%x-0x%x in use\n", + sbc_gxx_map.name, + PAGE_IO, PAGE_IO+PAGE_IO_SIZE-1 ); + iounmap((void *)iomapadr); + return -EAGAIN; + } + printk( KERN_INFO"%s: IO:0x%x-0x%x MEM:0x%x-0x%x\n", sbc_gxx_map.name, @@ -267,7 +263,7 @@ return -ENXIO; } - all_mtd->module=THIS_MODULE; + all_mtd->owner = THIS_MODULE; /* Create MTD devices for each partition. */ add_mtd_partitions(all_mtd, partition_info, NUM_PARTITIONS ); diff -Nru a/drivers/mtd/maps/sc520cdp.c b/drivers/mtd/maps/sc520cdp.c --- a/drivers/mtd/maps/sc520cdp.c Mon Jun 9 23:16:18 2003 +++ b/drivers/mtd/maps/sc520cdp.c Mon Jun 9 23:16:18 2003 @@ -16,7 +16,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA * - * $Id: sc520cdp.c,v 1.9 2001/10/02 15:05:14 dwmw2 Exp $ + * $Id: sc520cdp.c,v 1.15 2003/05/21 12:45:20 dwmw2 Exp $ * * * The SC520CDP is an evaluation board for the Elan SC520 processor available @@ -25,13 +25,15 @@ * For details see http://www.amd.com/products/epd/desiging/evalboards/18.elansc520/520_cdp_brief/index.html */ +#include <linux/config.h> #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> +#include <linux/init.h> #include <asm/io.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> - +#include <linux/mtd/concat.h> /* ** The Embedded Systems BIOS decodes the first FLASH starting at @@ -83,94 +85,32 @@ #define WINDOW_SIZE_1 0x00800000 #define WINDOW_SIZE_2 0x00080000 -static __u8 sc520cdp_read8(struct map_info *map, unsigned long ofs) -{ - return readb(map->map_priv_1 + ofs); -} - -static __u16 sc520cdp_read16(struct map_info *map, unsigned long ofs) -{ - return readw(map->map_priv_1 + ofs); -} - -static __u32 sc520cdp_read32(struct map_info *map, unsigned long ofs) -{ - return readl(map->map_priv_1 + ofs); -} - -static void sc520cdp_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, (void *)(map->map_priv_1 + from), len); -} - -static void sc520cdp_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - writeb(d, map->map_priv_1 + adr); -} - -static void sc520cdp_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - writew(d, map->map_priv_1 + adr); -} - -static void sc520cdp_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - writel(d, map->map_priv_1 + adr); -} - -static void sc520cdp_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy_toio((void *)(map->map_priv_1 + to), from, len); -} static struct map_info sc520cdp_map[] = { { - .name = "SC520CDP Flash Bank #0", - .size = WINDOW_SIZE_0, - .buswidth = 4, - .read8 = sc520cdp_read8, - .read16 = sc520cdp_read16, - .read32 = sc520cdp_read32, - .copy_from = sc520cdp_copy_from, - .write8 = sc520cdp_write8, - .write16 = sc520cdp_write16, - .write32 = sc520cdp_write32, - .copy_to = sc520cdp_copy_to, - .map_priv_2 = WINDOW_ADDR_0 + .name = "SC520CDP Flash Bank #0", + .size = WINDOW_SIZE_0, + .buswidth = 4, + .phys = WINDOW_ADDR_0 }, { - .name = "SC520CDP Flash Bank #1", - .size = WINDOW_SIZE_1, - .buswidth = 4, - .read8 = sc520cdp_read8, - .read16 = sc520cdp_read16, - .read32 = sc520cdp_read32, - .copy_from = sc520cdp_copy_from, - .write8 = sc520cdp_write8, - .write16 = sc520cdp_write16, - .write32 = sc520cdp_write32, - .copy_to = sc520cdp_copy_to, - .map_priv_2 = WINDOW_ADDR_1 + .name = "SC520CDP Flash Bank #1", + .size = WINDOW_SIZE_1, + .buswidth = 4, + .phys = WINDOW_ADDR_1 }, { - .name = "SC520CDP DIL Flash", - .size = WINDOW_SIZE_2, - .buswidth = 1, - .read8 = sc520cdp_read8, - .read16 = sc520cdp_read16, - .read32 = sc520cdp_read32, - .copy_from = sc520cdp_copy_from, - .write8 = sc520cdp_write8, - .write16 = sc520cdp_write16, - .write32 = sc520cdp_write32, - .copy_to = sc520cdp_copy_to, - .map_priv_2 = WINDOW_ADDR_2 + .name = "SC520CDP DIL Flash", + .size = WINDOW_SIZE_2, + .buswidth = 1, + .phys = WINDOW_ADDR_2 }, }; #define NUM_FLASH_BANKS (sizeof(sc520cdp_map)/sizeof(struct map_info)) static struct mtd_info *mymtd[NUM_FLASH_BANKS]; +static struct mtd_info *merged_mtd; #ifdef REPROGRAM_PAR @@ -253,9 +193,9 @@ /* map in SC520's MMCR area */ mmcr = (unsigned long *)ioremap_nocache(SC520_MMCR_BASE, SC520_MMCR_EXTENT); if(!mmcr) { /* ioremap_nocache failed: skip the PAR reprogramming */ - /* force map_priv_2 fields to BIOS defaults: */ + /* force physical address fields to BIOS defaults: */ for(i = 0; i < NUM_FLASH_BANKS; i++) - sc520cdp_map[i].map_priv_2 = par_table[i].default_address; + sc520cdp_map[i].phys = par_table[i].default_address; return; } @@ -280,7 +220,7 @@ sc520cdp_map[i].name); printk(KERN_NOTICE "Trying default address 0x%lx\n", par_table[i].default_address); - sc520cdp_map[i].map_priv_2 = par_table[i].default_address; + sc520cdp_map[i].phys = par_table[i].default_address; } } iounmap((void *)mmcr); @@ -298,28 +238,40 @@ #endif for (i = 0; i < NUM_FLASH_BANKS; i++) { - printk(KERN_NOTICE "SC520 CDP flash device: %lx at %lx\n", sc520cdp_map[i].size, sc520cdp_map[i].map_priv_2); - sc520cdp_map[i].map_priv_1 = (unsigned long)ioremap_nocache(sc520cdp_map[i].map_priv_2, sc520cdp_map[i].size); + printk(KERN_NOTICE "SC520 CDP flash device: 0x%lx at 0x%lx\n", + sc520cdp_map[i].size, sc520cdp_map[i].phys); - if (!sc520cdp_map[i].map_priv_1) { + sc520cdp_map[i].virt = (unsigned long)ioremap_nocache(sc520cdp_map[i].phys, sc520cdp_map[i].size); + + if (!sc520cdp_map[i].virt) { printk("Failed to ioremap_nocache\n"); return -EIO; } + + simple_map_init(&sc520cdp_map[i]); + mymtd[i] = do_map_probe("cfi_probe", &sc520cdp_map[i]); if(!mymtd[i]) - mymtd[i] = do_map_probe("jedec", &sc520cdp_map[i]); + mymtd[i] = do_map_probe("jedec_probe", &sc520cdp_map[i]); if(!mymtd[i]) mymtd[i] = do_map_probe("map_rom", &sc520cdp_map[i]); if (mymtd[i]) { - mymtd[i]->module = THIS_MODULE; - add_mtd_device(mymtd[i]); + mymtd[i]->owner = THIS_MODULE; ++devices_found; } else { - iounmap((void *)sc520cdp_map[i].map_priv_1); + iounmap((void *)sc520cdp_map[i].virt); } } + if(devices_found >= 2) { + /* Combine the two flash banks into a single MTD device & register it: */ + merged_mtd = mtd_concat_create(mymtd, 2, "SC520CDP Flash Banks #0 and #1"); + if(merged_mtd) + add_mtd_device(merged_mtd); + } + if(devices_found == 3) /* register the third (DIL-Flash) device */ + add_mtd_device(mymtd[2]); return(devices_found ? 0 : -ENXIO); } @@ -327,14 +279,19 @@ { int i; + if (merged_mtd) { + del_mtd_device(merged_mtd); + mtd_concat_destroy(merged_mtd); + } + if (mymtd[2]) + del_mtd_device(mymtd[2]); + for (i = 0; i < NUM_FLASH_BANKS; i++) { - if (mymtd[i]) { - del_mtd_device(mymtd[i]); + if (mymtd[i]) map_destroy(mymtd[i]); - } - if (sc520cdp_map[i].map_priv_1) { - iounmap((void *)sc520cdp_map[i].map_priv_1); - sc520cdp_map[i].map_priv_1 = 0; + if (sc520cdp_map[i].virt) { + iounmap((void *)sc520cdp_map[i].virt); + sc520cdp_map[i].virt = 0; } } } diff -Nru a/drivers/mtd/maps/scb2_flash.c b/drivers/mtd/maps/scb2_flash.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/scb2_flash.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,256 @@ +/* + * MTD map driver for BIOS Flash on Intel SCB2 boards + * $Id: scb2_flash.c,v 1.6 2003/05/21 12:45:20 dwmw2 Exp $ + * Copyright (C) 2002 Sun Microsystems, Inc. + * Tim Hockin <thockin@sun.com> + * + * A few notes on this MTD map: + * + * This was developed with a small number of SCB2 boards to test on. + * Hopefully, Intel has not introducted too many unaccounted variables in the + * making of this board. + * + * The BIOS marks its own memory region as 'reserved' in the e820 map. We + * try to request it here, but if it fails, we carry on anyway. + * + * This is how the chip is attached, so said the schematic: + * * a 4 MiB (32 Mib) 16 bit chip + * * a 1 MiB memory region + * * A20 and A21 pulled up + * * D8-D15 ignored + * What this means is that, while we are addressing bytes linearly, we are + * really addressing words, and discarding the other byte. This means that + * the chip MUST BE at least 2 MiB. This also means that every block is + * actually half as big as the chip reports. It also means that accesses of + * logical address 0 hit higher-address sections of the chip, not physical 0. + * One can only hope that these 4MiB x16 chips were a lot cheaper than 1MiB x8 + * chips. + * + * This driver assumes the chip is not write-protected by an external signal. + * As of the this writing, that is true, but may change, just to spite me. + * + * The actual BIOS layout has been mostly reverse engineered. Intel BIOS + * updates for this board include 10 related (*.bio - &.bi9) binary files and + * another seperate (*.bbo) binary file. The 10 files are 64k of data + a + * small header. If the headers are stripped off, the 10 64k files can be + * concatenated into a 640k image. This is your BIOS image, proper. The + * seperate .bbo file also has a small header. It is the 'Boot Block' + * recovery BIOS. Once the header is stripped, no further prep is needed. + * As best I can tell, the BIOS is arranged as such: + * offset 0x00000 to 0x4ffff (320k): unknown - SCSI BIOS, etc? + * offset 0x50000 to 0xeffff (640k): BIOS proper + * offset 0xf0000 ty 0xfffff (64k): Boot Block region + * + * Intel's BIOS update program flashes the BIOS and Boot Block in seperate + * steps. Probably a wise thing to do. + */ + +#include <linux/module.h> +#include <linux/types.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <asm/io.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/map.h> +#include <linux/mtd/cfi.h> +#include <linux/config.h> +#include <linux/pci.h> +#include <linux/pci_ids.h> + +#define MODNAME "scb2_flash" +#define SCB2_ADDR 0xfff00000 +#define SCB2_WINDOW 0x00100000 + + +static void *scb2_ioaddr; +static struct mtd_info *scb2_mtd; +struct map_info scb2_map = { + .name = "SCB2 BIOS Flash", + .size = 0, + .buswidth = 1, +}; +static int region_fail; + +static int __devinit +scb2_fixup_mtd(struct mtd_info *mtd) +{ + int i; + int done = 0; + struct map_info *map = mtd->priv; + struct cfi_private *cfi = map->fldrv_priv; + + /* barf if this doesn't look right */ + if (cfi->cfiq->InterfaceDesc != 1) { + printk(KERN_ERR MODNAME ": unsupported InterfaceDesc: %#x\n", + cfi->cfiq->InterfaceDesc); + return -1; + } + + /* I wasn't here. I didn't see. dwmw2. */ + + /* the chip is sometimes bigger than the map - what a waste */ + mtd->size = map->size; + + /* + * We only REALLY get half the chip, due to the way it is + * wired up - D8-D15 are tossed away. We read linear bytes, + * but in reality we are getting 1/2 of each 16-bit read, + * which LOOKS linear to us. Because CFI code accounts for + * things like lock/unlock/erase by eraseregions, we need to + * fudge them to reflect this. Erases go like this: + * * send an erase to an address + * * the chip samples the address and erases the block + * * add the block erasesize to the address and repeat + * -- the problem is that addresses are 16-bit addressable + * -- we end up erasing every-other block + */ + mtd->erasesize /= 2; + for (i = 0; i < mtd->numeraseregions; i++) { + struct mtd_erase_region_info *region = &mtd->eraseregions[i]; + region->erasesize /= 2; + } + + /* + * If the chip is bigger than the map, it is wired with the high + * address lines pulled up. This makes us access the top portion of + * the chip, so all our erase-region info is wrong. Start cutting from + * the bottom. + */ + for (i = 0; !done && i < mtd->numeraseregions; i++) { + struct mtd_erase_region_info *region = &mtd->eraseregions[i]; + + if (region->numblocks * region->erasesize > mtd->size) { + region->numblocks = (mtd->size / region->erasesize); + done = 1; + } else { + region->numblocks = 0; + } + region->offset = 0; + } + + return 0; +} + +/* CSB5's 'Function Control Register' has bits for decoding @ >= 0xffc00000 */ +#define CSB5_FCR 0x41 +#define CSB5_FCR_DECODE_ALL 0x0e +static int __devinit +scb2_flash_probe(struct pci_dev *dev, const struct pci_device_id *ent) +{ + u8 reg; + + /* enable decoding of the flash region in the south bridge */ + pci_read_config_byte(dev, CSB5_FCR, ®); + pci_write_config_byte(dev, CSB5_FCR, reg | CSB5_FCR_DECODE_ALL); + + if (!request_mem_region(SCB2_ADDR, SCB2_WINDOW, scb2_map.name)) { + /* + * The BIOS seems to mark the flash region as 'reserved' + * in the e820 map. Warn and go about our business. + */ + printk(KERN_WARNING MODNAME + ": warning - can't reserve rom window, continuing\n"); + region_fail = 1; + } + + /* remap the IO window (w/o caching) */ + scb2_ioaddr = ioremap_nocache(SCB2_ADDR, SCB2_WINDOW); + if (!scb2_ioaddr) { + printk(KERN_ERR MODNAME ": Failed to ioremap window!\n"); + if (!region_fail) + release_mem_region(SCB2_ADDR, SCB2_WINDOW); + return -ENOMEM; + } + + scb2_map.phys = SCB2_ADDR; + scb2_map.virt = (unsigned long)scb2_ioaddr; + scb2_map.size = SCB2_WINDOW; + + simple_map_init(&scb2_map); + + /* try to find a chip */ + scb2_mtd = do_map_probe("cfi_probe", &scb2_map); + + if (!scb2_mtd) { + printk(KERN_ERR MODNAME ": flash probe failed!\n"); + iounmap(scb2_ioaddr); + if (!region_fail) + release_mem_region(SCB2_ADDR, SCB2_WINDOW); + return -ENODEV; + } + + scb2_mtd->owner = THIS_MODULE; + if (scb2_fixup_mtd(scb2_mtd) < 0) { + del_mtd_device(scb2_mtd); + map_destroy(scb2_mtd); + iounmap(scb2_ioaddr); + if (!region_fail) + release_mem_region(SCB2_ADDR, SCB2_WINDOW); + return -ENODEV; + } + + printk(KERN_NOTICE MODNAME ": chip size 0x%x at offset 0x%x\n", + scb2_mtd->size, SCB2_WINDOW - scb2_mtd->size); + + add_mtd_device(scb2_mtd); + + return 0; +} + +static void __devexit +scb2_flash_remove(struct pci_dev *dev) +{ + if (!scb2_mtd) + return; + + /* disable flash writes */ + if (scb2_mtd->lock) + scb2_mtd->lock(scb2_mtd, 0, scb2_mtd->size); + + del_mtd_device(scb2_mtd); + map_destroy(scb2_mtd); + + iounmap(scb2_ioaddr); + scb2_ioaddr = NULL; + + if (!region_fail) + release_mem_region(SCB2_ADDR, SCB2_WINDOW); + pci_set_drvdata(dev, NULL); +} + +static struct pci_device_id scb2_flash_pci_ids[] __devinitdata = { + { + .vendor = PCI_VENDOR_ID_SERVERWORKS, + .device = PCI_DEVICE_ID_SERVERWORKS_CSB5, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID + }, + { 0, } +}; + +static struct pci_driver scb2_flash_driver = { + .name = "Intel SCB2 BIOS Flash", + .id_table = scb2_flash_pci_ids, + .probe = scb2_flash_probe, + .remove = __devexit_p(scb2_flash_remove), +}; + +static int __init +scb2_flash_init(void) +{ + return pci_module_init(&scb2_flash_driver); +} + +static void __exit +scb2_flash_exit(void) +{ + pci_unregister_driver(&scb2_flash_driver); +} + +module_init(scb2_flash_init); +module_exit(scb2_flash_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Tim Hockin <thockin@sun.com>"); +MODULE_DESCRIPTION("MTD map driver for Intel SCB2 BIOS Flash"); +MODULE_DEVICE_TABLE(pci, scb2_flash_pci_ids); diff -Nru a/drivers/mtd/maps/scx200_docflash.c b/drivers/mtd/maps/scx200_docflash.c --- a/drivers/mtd/maps/scx200_docflash.c Mon Jun 9 23:16:15 2003 +++ b/drivers/mtd/maps/scx200_docflash.c Mon Jun 9 23:16:15 2003 @@ -2,6 +2,8 @@ Copyright (c) 2001,2002 Christer Weinigel <wingel@nano-system.com> + $Id: scx200_docflash.c,v 1.5 2003/05/21 12:45:20 dwmw2 Exp $ + National Semiconductor SCx200 flash mapped with DOCCS */ @@ -9,6 +11,7 @@ #include <linux/config.h> #include <linux/types.h> #include <linux/kernel.h> +#include <linux/init.h> #include <asm/io.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> @@ -36,7 +39,7 @@ MODULE_PARM_DESC(flashtype, "Type of MTD probe to do"); static int probe = 0; /* Don't autoprobe */ -static unsigned size = 0x1000000; /* 16 MB the whole ISA address space */ +static unsigned size = 0x1000000; /* 16 MiB the whole ISA address space */ static unsigned width = 8; /* Default to 8 bits wide */ static char *flashtype = "cfi_probe"; @@ -73,46 +76,9 @@ #define NUM_PARTITIONS (sizeof(partition_info)/sizeof(partition_info[0])) #endif -static __u8 scx200_docflash_read8(struct map_info *map, unsigned long ofs) -{ - return __raw_readb(map->map_priv_1 + ofs); -} - -static __u16 scx200_docflash_read16(struct map_info *map, unsigned long ofs) -{ - return __raw_readw(map->map_priv_1 + ofs); -} - -static void scx200_docflash_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, map->map_priv_1 + from, len); -} - -static void scx200_docflash_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - __raw_writeb(d, map->map_priv_1 + adr); - mb(); -} - -static void scx200_docflash_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - __raw_writew(d, map->map_priv_1 + adr); - mb(); -} - -static void scx200_docflash_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy_toio(map->map_priv_1 + to, from, len); -} static struct map_info scx200_docflash_map = { .name = "NatSemi SCx200 DOCCS Flash", - .read8 = scx200_docflash_read8, - .read16 = scx200_docflash_read16, - .copy_from = scx200_docflash_copy_from, - .write8 = scx200_docflash_write8, - .write16 = scx200_docflash_write16, - .copy_to = scx200_docflash_copy_to }; int __init init_scx200_docflash(void) @@ -211,8 +177,11 @@ else scx200_docflash_map.buswidth = 2; - scx200_docflash_map.map_priv_1 = (unsigned long)ioremap(docmem.start, scx200_docflash_map.size); - if (!scx200_docflash_map.map_priv_1) { + simple_map_init(&scx200_docflash_map); + + scx200_docflash_map.phys = docmem.start; + scx200_docflash_map.virt = (unsigned long)ioremap(docmem.start, scx200_docflash_map.size); + if (!scx200_docflash_map.virt) { printk(KERN_ERR NAME ": failed to ioremap the flash\n"); release_resource(&docmem); return -EIO; @@ -221,7 +190,7 @@ mymtd = do_map_probe(flashtype, &scx200_docflash_map); if (!mymtd) { printk(KERN_ERR NAME ": unable to detect flash\n"); - iounmap((void *)scx200_docflash_map.map_priv_1); + iounmap((void *)scx200_docflash_map.virt); release_resource(&docmem); return -ENXIO; } @@ -229,7 +198,7 @@ if (size < mymtd->size) printk(KERN_WARNING NAME ": warning, flash mapping is smaller than flash size\n"); - mymtd->module = THIS_MODULE; + mymtd->owner = THIS_MODULE; #if PARTITION partition_info[3].offset = mymtd->size-partition_info[3].size; @@ -251,8 +220,8 @@ #endif map_destroy(mymtd); } - if (scx200_docflash_map.map_priv_1) { - iounmap((void *)scx200_docflash_map.map_priv_1); + if (scx200_docflash_map.virt) { + iounmap((void *)scx200_docflash_map.virt); release_resource(&docmem); } } diff -Nru a/drivers/mtd/maps/solutionengine.c b/drivers/mtd/maps/solutionengine.c --- a/drivers/mtd/maps/solutionengine.c Mon Jun 9 23:16:19 2003 +++ b/drivers/mtd/maps/solutionengine.c Mon Jun 9 23:16:19 2003 @@ -1,5 +1,5 @@ /* - * $Id: solutionengine.c,v 1.3 2001/10/02 15:05:14 dwmw2 Exp $ + * $Id: solutionengine.c,v 1.10 2003/05/21 12:45:20 dwmw2 Exp $ * * Flash and EPROM on Hitachi Solution Engine and similar boards. * @@ -11,29 +11,12 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> +#include <linux/init.h> #include <asm/io.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> #include <linux/mtd/partitions.h> - - -extern int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts); - -__u32 soleng_read32(struct map_info *map, unsigned long ofs) -{ - return __raw_readl(map->map_priv_1 + ofs); -} - -void soleng_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - __raw_writel(d, map->map_priv_1 + adr); - mb(); -} - -void soleng_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, map->map_priv_1 + from, len); -} +#include <linux/config.h> static struct mtd_info *flash_mtd; @@ -42,36 +25,58 @@ static struct mtd_partition *parsed_parts; struct map_info soleng_eprom_map = { - .name = "Solution Engine EPROM", - .size = 0x400000, - .buswidth = 4, - .copy_from = soleng_copy_from, + .name = "Solution Engine EPROM", + .size = 0x400000, + .buswidth = 4, }; struct map_info soleng_flash_map = { - .name = "Solution Engine FLASH", - .size = 0x400000, - .buswidth = 4, - .read32 = soleng_read32, - .copy_from = soleng_copy_from, - .write32 = soleng_write32, + .name = "Solution Engine FLASH", + .size = 0x400000, + .buswidth = 4, }; +static const char *probes[] = { "RedBoot", "cmdlinepart", NULL }; + +#ifdef CONFIG_MTD_SUPERH_RESERVE +static struct mtd_partition superh_se_partitions[] = { + /* Reserved for boot code, read-only */ + { + .name = "flash_boot", + .offset = 0x00000000, + .size = CONFIG_MTD_SUPERH_RESERVE, + .mask_flags = MTD_WRITEABLE, + }, + /* All else is writable (e.g. JFFS) */ + { + .name = "Flash FS", + .offset = MTDPART_OFS_NXTBLK, + .size = MTDPART_SIZ_FULL, + } +}; +#endif /* CONFIG_MTD_SUPERH_RESERVE */ + static int __init init_soleng_maps(void) { - int nr_parts; + int nr_parts = 0; /* First probe at offset 0 */ - soleng_flash_map.map_priv_1 = P2SEGADDR(0); - soleng_eprom_map.map_priv_1 = P1SEGADDR(0x400000); - - printk(KERN_NOTICE "Probing for flash chips at 0x000000:\n"); + soleng_flash_map.phys = 0; + soleng_flash_map.virt = P2SEGADDR(0); + soleng_eprom_map.phys = 0x01000000; + soleng_eprom_map.virt = P1SEGADDR(0x01000000); + simple_map_init(&soleng_eprom_map); + simple_map_init(&soleng_flash_map); + + printk(KERN_NOTICE "Probing for flash chips at 0x00000000:\n"); flash_mtd = do_map_probe("cfi_probe", &soleng_flash_map); if (!flash_mtd) { /* Not there. Try swapping */ - printk(KERN_NOTICE "Probing for flash chips at 0x400000:\n"); - soleng_flash_map.map_priv_1 = P2SEGADDR(0x400000); - soleng_eprom_map.map_priv_1 = P1SEGADDR(0); + printk(KERN_NOTICE "Probing for flash chips at 0x01000000:\n"); + soleng_flash_map.phys = 0x01000000; + soleng_flash_map.virt = P2SEGADDR(0x01000000); + soleng_eprom_map.phys = 0; + soleng_eprom_map.virt = P1SEGADDR(0); flash_mtd = do_map_probe("cfi_probe", &soleng_flash_map); if (!flash_mtd) { /* Eep. */ @@ -80,19 +85,28 @@ } } printk(KERN_NOTICE "Solution Engine: Flash at 0x%08lx, EPROM at 0x%08lx\n", - soleng_flash_map.map_priv_1 & 0x1fffffff, - soleng_eprom_map.map_priv_1 & 0x1fffffff); - flash_mtd->module = THIS_MODULE; + soleng_flash_map.phys & 0x1fffffff, + soleng_eprom_map.phys & 0x1fffffff); + flash_mtd->owner = THIS_MODULE; eprom_mtd = do_map_probe("map_rom", &soleng_eprom_map); if (eprom_mtd) { - eprom_mtd->module = THIS_MODULE; + eprom_mtd->owner = THIS_MODULE; add_mtd_device(eprom_mtd); } - nr_parts = parse_redboot_partitions(flash_mtd, &parsed_parts); + nr_parts = parse_mtd_partitions(flash_mtd, probes, &parsed_parts, 0); + +#if CONFIG_MTD_SUPERH_RESERVE + if (nr_parts <= 0) { + printk(KERN_NOTICE "Using configured partition at 0x%08x.\n", + CONFIG_MTD_SUPERH_RESERVE); + parsed_parts = superh_se_partitions; + nr_parts = sizeof(superh_se_partitions)/sizeof(*parsed_parts); + } +#endif /* CONFIG_MTD_SUPERH_RESERVE */ - if (nr_parts) + if (nr_parts > 0) add_mtd_partitions(flash_mtd, parsed_parts, nr_parts); else add_mtd_device(flash_mtd); diff -Nru a/drivers/mtd/maps/sun_uflash.c b/drivers/mtd/maps/sun_uflash.c --- a/drivers/mtd/maps/sun_uflash.c Mon Jun 9 23:16:15 2003 +++ b/drivers/mtd/maps/sun_uflash.c Mon Jun 9 23:16:15 2003 @@ -1,4 +1,4 @@ -/* $Id: sun_uflash.c,v 1.4 2001/10/02 15:05:14 dwmw2 Exp $ +/* $Id: sun_uflash.c,v 1.7 2003/05/20 20:59:32 dwmw2 Exp $ * * sun_uflash - Driver implementation for user-programmable flash * present on many Sun Microsystems SME boardsets. @@ -48,60 +48,11 @@ struct list_head list; }; -__u8 uflash_read8(struct map_info *map, unsigned long ofs) -{ - return(__raw_readb(map->map_priv_1 + ofs)); -} - -__u16 uflash_read16(struct map_info *map, unsigned long ofs) -{ - return(__raw_readw(map->map_priv_1 + ofs)); -} - -__u32 uflash_read32(struct map_info *map, unsigned long ofs) -{ - return(__raw_readl(map->map_priv_1 + ofs)); -} - -void uflash_copy_from(struct map_info *map, void *to, unsigned long from, - ssize_t len) -{ - memcpy_fromio(to, map->map_priv_1 + from, len); -} - -void uflash_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - __raw_writeb(d, map->map_priv_1 + adr); -} - -void uflash_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - __raw_writew(d, map->map_priv_1 + adr); -} - -void uflash_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - __raw_writel(d, map->map_priv_1 + adr); -} - -void uflash_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 uflash_map_templ = { - .name = "SUNW,???-????", - .size = UFLASH_WINDOW_SIZE, - .buswidth = UFLASH_BUSWIDTH, - .read8 = uflash_read8, - .read16 = uflash_read16, - .read32 = uflash_read32, - .copy_from = uflash_copy_from, - .write8 = uflash_write8, - .write16 = uflash_write16, - .write32 = uflash_write32, - .copy_to = uflash_copy_to + .name = "SUNW,???-????", + .size = UFLASH_WINDOW_SIZE, + .buswidth = UFLASH_BUSWIDTH, }; int uflash_devinit(struct linux_ebus_device* edev) @@ -145,20 +96,22 @@ if(0 != pdev->name && 0 < strlen(pdev->name)) { pdev->map.name = pdev->name; } - - pdev->map.map_priv_1 = + pdev->phys = edev->resource[0].start; + pdev->virt = (unsigned long)ioremap_nocache(edev->resource[0].start, pdev->map.size); - if(0 == pdev->map.map_priv_1) { + if(0 == pdev->map.virt) { printk("%s: failed to map device\n", __FUNCTION__); kfree(pdev->name); kfree(pdev); return(-1); } + simple_map_init(&pdev->map); + /* MTD registration */ pdev->mtd = do_map_probe("cfi_probe", &pdev->map); if(0 == pdev->mtd) { - iounmap((void *)pdev->map.map_priv_1); + iounmap((void *)pdev->map.virt); kfree(pdev->name); kfree(pdev); return(-ENXIO); @@ -166,7 +119,7 @@ list_add(&pdev->list, &device_list); - pdev->mtd->module = THIS_MODULE; + pdev->mtd->owner = THIS_MODULE; add_mtd_device(pdev->mtd); return(0); @@ -211,9 +164,9 @@ del_mtd_device(udev->mtd); map_destroy(udev->mtd); } - if(0 != udev->map.map_priv_1) { - iounmap((void*)udev->map.map_priv_1); - udev->map.map_priv_1 = 0; + if(0 != udev->map.virt) { + iounmap((void*)udev->map.virt); + udev->map.virt = 0; } if(0 != udev->name) { kfree(udev->name); diff -Nru a/drivers/mtd/maps/tqm8xxl.c b/drivers/mtd/maps/tqm8xxl.c --- a/drivers/mtd/maps/tqm8xxl.c Mon Jun 9 23:16:08 2003 +++ b/drivers/mtd/maps/tqm8xxl.c Mon Jun 9 23:16:08 2003 @@ -2,7 +2,7 @@ * Handle mapping of the flash memory access routines * on TQM8xxL based devices. * - * $Id: tqm8xxl.c,v 1.3 2001/10/02 15:05:14 dwmw2 Exp $ + * $Id: tqm8xxl.c,v 1.8 2003/05/21 12:45:20 dwmw2 Exp $ * * based on rpxlite.c * @@ -26,6 +26,7 @@ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> +#include <linux/init.h> #include <asm/io.h> #include <linux/mtd/mtd.h> @@ -51,59 +52,6 @@ static unsigned long num_banks; static unsigned long start_scan_addr; -__u8 tqm8xxl_read8(struct map_info *map, unsigned long ofs) -{ - return *((__u8 *)(map->map_priv_1 + ofs)); -} - -__u16 tqm8xxl_read16(struct map_info *map, unsigned long ofs) -{ - return *((__u16 *)(map->map_priv_1 + ofs)); -} - -__u32 tqm8xxl_read32(struct map_info *map, unsigned long ofs) -{ - return *((__u32 *)(map->map_priv_1 + ofs)); -} - -void tqm8xxl_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy_fromio(to, (void *)(map->map_priv_1 + from), len); -} - -void tqm8xxl_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - *((__u8 *)(map->map_priv_1 + adr)) = d; -} - -void tqm8xxl_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - *((__u16 *)( map->map_priv_1 + adr)) = d; -} - -void tqm8xxl_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - *((__u32 *)(map->map_priv_1 + adr)) = d; -} - -void tqm8xxl_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy_toio((void *)(map->map_priv_1 + to), from, len); -} - -struct map_info tqm8xxl_map = { - .name = "TQM8xxL", - .buswidth = 4, - .read8 = tqm8xxl_read8, - .read16 = tqm8xxl_read16, - .read32 = tqm8xxl_read32, - .copy_from = tqm8xxl_copy_from, - .write8 = tqm8xxl_write8, - .write16 = tqm8xxl_write16, - .write32 = tqm8xxl_write32, - .copy_to = tqm8xxl_copy_to -}; - /* * Here are partition information for all known TQM8xxL series devices. * See include/linux/mtd/partitions.h for definition of the mtd_partition @@ -120,43 +68,44 @@ static unsigned long tqm8xxl_max_flash_size = 0x00800000; /* partition definition for first flash bank - * also ref. to "drivers\char\flash_config.c" + * (cf. "drivers/char/flash_config.c") */ static struct mtd_partition tqm8xxl_partitions[] = { { - .name = "ppcboot", - .offset = 0x00000000, - .size = 0x00020000, /* 128KB */ - .mask_flags = MTD_WRITEABLE, /* force read-only */ + .name = "ppcboot", + .offset = 0x00000000, + .size = 0x00020000, /* 128KB */ + .mask_flags = MTD_WRITEABLE, /* force read-only */ }, { - .name = "kernel", /* default kernel image */ - .offset = 0x00020000, - .size = 0x000e0000, - .mask_flags = MTD_WRITEABLE, /* force read-only */ + .name = "kernel", /* default kernel image */ + .offset = 0x00020000, + .size = 0x000e0000, + .mask_flags = MTD_WRITEABLE, /* force read-only */ }, { - .name = "user", - .offset = 0x00100000, - .size = 0x00100000, + .name = "user", + .offset = 0x00100000, + .size = 0x00100000, }, { - .name = "initrd", - .offset = 0x00200000, - .size = 0x00200000, + .name = "initrd", + .offset = 0x00200000, + .size = 0x00200000, } }; -/* partition definition for second flahs bank */ +/* partition definition for second flash bank */ static struct mtd_partition tqm8xxl_fs_partitions[] = { { - .name = "cramfs", - .offset = 0x00000000, - .size = 0x00200000, + .name = "cramfs", + .offset = 0x00000000, + .size = 0x00200000, }, { - .name = "jffs", - .offset = 0x00200000, - .size = 0x00200000, + .name = "jffs", + .offset = 0x00200000, + .size = 0x00200000, + .//size = MTDPART_SIZ_FULL, } }; #endif @@ -172,66 +121,73 @@ flash_addr = bd->bi_flashstart; flash_size = bd->bi_flashsize; - //request maximum flash size address spzce + + //request maximum flash size address space start_scan_addr = (unsigned long)ioremap(flash_addr, flash_size); if (!start_scan_addr) { - //printk("%s:Failed to ioremap address:0x%x\n", __FUNCTION__, FLASH_ADDR); - printk("%s:Failed to ioremap address:0x%x\n", __FUNCTION__, flash_addr); + printk(KERN_WARNING "%s:Failed to ioremap address:0x%x\n", __FUNCTION__, flash_addr); return -EIO; } - for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++) - { + + for (idx = 0 ; idx < FLASH_BANK_MAX ; idx++) { if(mtd_size >= flash_size) break; - printk("%s: chip probing count %d\n", __FUNCTION__, idx); + printk(KERN_INFO "%s: chip probing count %d\n", __FUNCTION__, idx); map_banks[idx] = (struct map_info *)kmalloc(sizeof(struct map_info), GFP_KERNEL); - if(map_banks[idx] == NULL) - { - //return -ENOMEM; + if(map_banks[idx] == NULL) { ret = -ENOMEM; + /* FIXME: What if some MTD devices were probed already? */ goto error_mem; } + memset((void *)map_banks[idx], 0, sizeof(struct map_info)); map_banks[idx]->name = (char *)kmalloc(16, GFP_KERNEL); - if(map_banks[idx]->name == NULL) - { - //return -ENOMEM; + + if (!map_banks[idx]->name) { ret = -ENOMEM; + /* FIXME: What if some MTD devices were probed already? */ goto error_mem; } - memset((void *)map_banks[idx]->name, 0, 16); - sprintf(map_banks[idx]->name, "TQM8xxL%d", idx); + + map_banks[idx]->size = flash_size; map_banks[idx]->buswidth = 4; - map_banks[idx]->read8 = tqm8xxl_read8; - map_banks[idx]->read16 = tqm8xxl_read16; - map_banks[idx]->read32 = tqm8xxl_read32; - map_banks[idx]->copy_from = tqm8xxl_copy_from; - map_banks[idx]->write8 = tqm8xxl_write8; - map_banks[idx]->write16 = tqm8xxl_write16; - map_banks[idx]->write32 = tqm8xxl_write32; - map_banks[idx]->copy_to = tqm8xxl_copy_to; - map_banks[idx]->map_priv_1 = - start_scan_addr + ((idx > 0) ? + + simple_map_init(map_banks[idx]); + + map_banks[idx]->virt = start_scan_addr; + map_banks[idx]->phys = flash_addr; + /* FIXME: This looks utterly bogus, but I'm trying to + preserve the behaviour of the original (shown here)... + + map_banks[idx]->map_priv_1 = + start_scan_addr + ((idx > 0) ? (mtd_banks[idx-1] ? mtd_banks[idx-1]->size : 0) : 0); + */ + + if (idx && mtd_banks[idx-1]) { + map_banks[idx]->virt += mtd_banks[idx-1]->size; + map_banks[idx]->phys += mtd_banks[idx-1]->size; + } + //start to probe flash chips mtd_banks[idx] = do_map_probe("cfi_probe", map_banks[idx]); - if(mtd_banks[idx]) - { - mtd_banks[idx]->module = THIS_MODULE; + + if (mtd_banks[idx]) { + mtd_banks[idx]->owner = THIS_MODULE; mtd_size += mtd_banks[idx]->size; num_banks++; - printk("%s: bank%d, name:%s, size:%dbytes \n", __FUNCTION__, num_banks, + + printk(KERN_INFO "%s: bank%d, name:%s, size:%dbytes \n", __FUNCTION__, num_banks, mtd_banks[idx]->name, mtd_banks[idx]->size); } } /* no supported flash chips found */ - if(!num_banks) - { - printk("TQM8xxL: No support flash chips found!\n"); + if (!num_banks) { + printk(KERN_NOTICE "TQM8xxL: No support flash chips found!\n"); ret = -ENXIO; goto error_mem; } @@ -243,11 +199,12 @@ part_banks[0].mtd_part = tqm8xxl_partitions; part_banks[0].type = "Static image"; part_banks[0].nums = NB_OF(tqm8xxl_partitions); + part_banks[1].mtd_part = tqm8xxl_fs_partitions; part_banks[1].type = "Static file system"; part_banks[1].nums = NB_OF(tqm8xxl_fs_partitions); - for(idx = 0; idx < num_banks ; idx++) - { + + for(idx = 0; idx < num_banks ; idx++) { if (part_banks[idx].nums == 0) { printk(KERN_NOTICE "TQM flash%d: no partition info available, registering whole flash at once\n", idx); add_mtd_device(mtd_banks[idx]); @@ -265,12 +222,9 @@ #endif return 0; error_mem: - for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++) - { - if(map_banks[idx] != NULL) - { - if(map_banks[idx]->name != NULL) - { + for(idx = 0 ; idx < FLASH_BANK_MAX ; idx++) { + if(map_banks[idx] != NULL) { + if(map_banks[idx]->name != NULL) { kfree(map_banks[idx]->name); map_banks[idx]->name = NULL; } @@ -278,18 +232,15 @@ map_banks[idx] = NULL; } } - //return -ENOMEM; error: iounmap((void *)start_scan_addr); - //return -ENXIO; return ret; } static void __exit cleanup_tqm_mtd(void) { unsigned int idx = 0; - for(idx = 0 ; idx < num_banks ; idx++) - { + for(idx = 0 ; idx < num_banks ; idx++) { /* destroy mtd_info previously allocated */ if (mtd_banks[idx]) { del_mtd_partitions(mtd_banks[idx]); @@ -299,6 +250,7 @@ kfree(map_banks[idx]->name); kfree(map_banks[idx]); } + if (start_scan_addr) { iounmap((void *)start_scan_addr); start_scan_addr = 0; diff -Nru a/drivers/mtd/maps/tsunami_flash.c b/drivers/mtd/maps/tsunami_flash.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/maps/tsunami_flash.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,106 @@ +/* + * tsunami_flash.c + * + * flash chip on alpha ds10... + * $Id: tsunami_flash.c,v 1.6 2003/05/21 15:15:08 dwmw2 Exp $ + */ +#include <asm/io.h> +#include <asm/core_tsunami.h> +#include <linux/init.h> +#include <linux/mtd/map.h> +#include <linux/mtd/mtd.h> + +#define FLASH_ENABLE_PORT 0x00C00001 +#define FLASH_ENABLE_BYTE 0x01 +#define FLASH_DISABLE_BYTE 0x00 + +#define MAX_TIG_FLASH_SIZE (12*1024*1024) +static inline __u8 tsunami_flash_read8(struct map_info *map, unsigned long offset) +{ + return tsunami_tig_readb(offset); +} + +static void tsunami_flash_write8(struct map_info *map, __u8 value, unsigned long offset) +{ + tsunami_tig_writeb(value, offset); +} + +static void tsunami_flash_copy_from( + struct map_info *map, void *addr, unsigned long offset, ssize_t len) +{ + unsigned char *dest; + dest = addr; + while(len && (offset < MAX_TIG_FLASH_SIZE)) { + *dest = tsunami_tig_readb(offset); + offset++; + dest++; + len--; + } +} + +static void tsunami_flash_copy_to( + struct map_info *map, unsigned long offset, + const void *addr, ssize_t len) +{ + const unsigned char *src; + src = addr; + while(len && (offset < MAX_TIG_FLASH_SIZE)) { + tsunami_tig_writeb(*src, offset); + offset++; + src++; + len--; + } +} + +/* + * Deliberately don't provide operations wider than 8 bits. I don't + * have then and it scares me to think how you could mess up if + * you tried to use them. Buswidth is correctly so I'm safe. + */ +static struct map_info tsunami_flash_map = { + .name = "flash chip on the Tsunami TIG bus", + .size = MAX_TIG_FLASH_SIZE, + .phys = NO_XIP; + .buswidth = 1, + .read8 = tsunami_flash_read8, + .copy_from = tsunami_flash_copy_from, + .write8 = tsunami_flash_write8, + .copy_to = tsunami_flash_copy_to, +}; + +static struct mtd_info *tsunami_flash_mtd; + +static void __exit cleanup_tsunami_flash(void) +{ + struct mtd_info *mtd; + mtd = tsunami_flash_mtd; + if (mtd) { + del_mtd_device(mtd); + map_destroy(mtd); + } + tsunami_flash_mtd = 0; +} + + +static int __init init_tsunami_flash(void) +{ + static const char *rom_probe_types[] = { "cfi_probe", "jedec_probe", "map_rom", 0 }; + char **type; + + tsunami_tig_writeb(FLASH_ENABLE_BYTE, FLASH_ENABLE_PORT); + + tsunami_flash_mtd = 0; + type = rom_probe_types; + for(; !tsunami_flash_mtd && *type; type++) { + tsunami_flash_mtd = do_map_probe(*type, &tsunami_flash_map); + } + if (tsunami_flash_mtd) { + tsunami_flash_mtd->owner = THIS_MODULE; + add_mtd_device(tsunami_flash_mtd); + return 0; + } + return -ENXIO; +} + +module_init(init_tsunami_flash); +module_exit(cleanup_tsunami_flash); diff -Nru a/drivers/mtd/maps/uclinux.c b/drivers/mtd/maps/uclinux.c --- a/drivers/mtd/maps/uclinux.c Mon Jun 9 23:16:18 2003 +++ b/drivers/mtd/maps/uclinux.c Mon Jun 9 23:16:18 2003 @@ -4,6 +4,8 @@ * uclinux.c -- generic memory mapped MTD driver for uclinux * * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) + * + * $Id: uclinux.c,v 1.5 2003/05/20 20:59:32 dwmw2 Exp $ */ /****************************************************************************/ @@ -15,7 +17,6 @@ #include <linux/kernel.h> #include <linux/fs.h> #include <linux/major.h> -#include <linux/root_dev.h> #include <linux/mtd/mtd.h> #include <linux/mtd/map.h> #include <linux/mtd/partitions.h> @@ -23,58 +24,11 @@ /****************************************************************************/ -__u8 uclinux_read8(struct map_info *map, unsigned long ofs) -{ - return(*((__u8 *) (map->map_priv_1 + ofs))); -} - -__u16 uclinux_read16(struct map_info *map, unsigned long ofs) -{ - return(*((__u16 *) (map->map_priv_1 + ofs))); -} - -__u32 uclinux_read32(struct map_info *map, unsigned long ofs) -{ - return(*((__u32 *) (map->map_priv_1 + ofs))); -} - -void uclinux_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - memcpy(to, (void *)(map->map_priv_1 + from), len); -} - -void uclinux_write8(struct map_info *map, __u8 d, unsigned long adr) -{ - *((__u8 *) (map->map_priv_1 + adr)) = d; -} - -void uclinux_write16(struct map_info *map, __u16 d, unsigned long adr) -{ - *((__u16 *) (map->map_priv_1 + adr)) = d; -} - -void uclinux_write32(struct map_info *map, __u32 d, unsigned long adr) -{ - *((__u32 *) (map->map_priv_1 + adr)) = d; -} - -void uclinux_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - memcpy((void *) (map->map_priv_1 + to), from, len); -} /****************************************************************************/ struct map_info uclinux_ram_map = { - .name = "RAM", - .read8 = uclinux_read8, - .read16 = uclinux_read16, - .read32 = uclinux_read32, - .copy_from = uclinux_copy_from, - .write8 = uclinux_write8, - .write16 = uclinux_write16, - .write32 = uclinux_write32, - .copy_to = uclinux_copy_to, + .name = "RAM", }; struct mtd_info *uclinux_ram_mtdinfo; @@ -82,7 +36,7 @@ /****************************************************************************/ struct mtd_partition uclinux_romfs[] = { - { .name = "ROMfs", .offset = 0 } + { .name = "ROMfs" } }; #define NUM_PARTITIONS (sizeof(uclinux_romfs) / sizeof(uclinux_romfs[0])) @@ -93,7 +47,7 @@ size_t *retlen, u_char **mtdbuf) { struct map_info *map = (struct map_info *) mtd->priv; - *mtdbuf = (u_char *) (map->map_priv_1 + ((int) from)); + *mtdbuf = (u_char *) (map->virt + ((int) from)); *retlen = len; return(0); } @@ -107,29 +61,31 @@ extern char _ebss; mapp = &uclinux_ram_map; - mapp->map_priv_2 = (unsigned long) &_ebss; + mapp->phys = (unsigned long) &_ebss; mapp->size = PAGE_ALIGN(*((unsigned long *)((&_ebss) + 8))); mapp->buswidth = 4; printk("uclinux[mtd]: RAM probe address=0x%x size=0x%x\n", (int) mapp->map_priv_2, (int) mapp->size); - mapp->map_priv_1 = (unsigned long) - ioremap_nocache(mapp->map_priv_2, mapp->size); + mapp->virt = (unsigned long) + ioremap_nocache(mapp->phys, mapp->size); - if (mapp->map_priv_1 == 0) { + if (mapp->virt == 0) { printk("uclinux[mtd]: ioremap_nocache() failed\n"); return(-EIO); } + simple_map_init(mapp); + mtd = do_map_probe("map_ram", mapp); if (!mtd) { printk("uclinux[mtd]: failed to find a mapping?\n"); - iounmap((void *) mapp->map_priv_1); + iounmap((void *) mapp->virt); return(-ENXIO); } - mtd->module = THIS_MODULE; + mtd->owner = THIS_MODULE; mtd->point = uclinux_point; mtd->priv = mapp; @@ -137,7 +93,7 @@ add_mtd_partitions(mtd, uclinux_romfs, NUM_PARTITIONS); printk("uclinux[mtd]: set %s to be root filesystem\n", - uclinux_romfs[0].name); + uclinux_romfs[0].name); ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, 0); put_mtd_device(mtd); @@ -154,8 +110,8 @@ uclinux_ram_mtdinfo = NULL; } if (uclinux_ram_map.map_priv_1) { - iounmap((void *) uclinux_ram_map.map_priv_1); - uclinux_ram_map.map_priv_1 = 0; + iounmap((void *) uclinux_ram_map.virt); + uclinux_ram_map.virt = 0; } } diff -Nru a/drivers/mtd/maps/vmax301.c b/drivers/mtd/maps/vmax301.c --- a/drivers/mtd/maps/vmax301.c Mon Jun 9 23:16:09 2003 +++ b/drivers/mtd/maps/vmax301.c Mon Jun 9 23:16:09 2003 @@ -1,4 +1,4 @@ -// $Id: vmax301.c,v 1.24 2001/10/02 15:05:14 dwmw2 Exp $ +// $Id: vmax301.c,v 1.28 2003/05/21 15:15:08 dwmw2 Exp $ /* ###################################################################### Tempustech VMAX SBC301 MTD Driver. @@ -24,6 +24,7 @@ #include <asm/io.h> #include <linux/mtd/map.h> +#include <linux/mtd/mtd.h> #define WINDOW_START 0xd8000 @@ -142,33 +143,36 @@ static struct map_info vmax_map[2] = { { - .name = "VMAX301 Internal Flash", - .size = 3*2*1024*1024, - .buswidth = 1, - .read8 = vmax301_read8, - .read16 = vmax301_read16, - .read32 = vmax301_read32, - .copy_from = vmax301_copy_from, - .write8 = vmax301_write8, - .write16 = vmax301_write16, - .write32 = vmax301_write32, - .copy_to = vmax301_copy_to, - .map_priv_1 = WINDOW_START + WINDOW_LENGTH, - .map_priv_2 = 0xFFFFFFFF + .name = "VMAX301 Internal Flash", + .phys = NO_XIP, + .size = 3*2*1024*1024, + .buswidth = 1, + .read8 = vmax301_read8, + .read16 = vmax301_read16, + .read32 = vmax301_read32, + .copy_from = vmax301_copy_from, + .write8 = vmax301_write8, + .write16 = vmax301_write16, + .write32 = vmax301_write32, + .copy_to = vmax301_copy_to, + .map_priv_1 = WINDOW_START + WINDOW_LENGTH, + .map_priv_2 = 0xFFFFFFFF }, { - .name = "VMAX301 Socket", - .buswidth = 1, - .read8 = vmax301_read8, - .read16 = vmax301_read16, - .read32 = vmax301_read32, - .copy_from = vmax301_copy_from, - .write8 = vmax301_write8, - .write16 = vmax301_write16, - .write32 = vmax301_write32, - .copy_to = vmax301_copy_to, - .map_priv_1 = WINDOW_START + (3*WINDOW_LENGTH), - .map_priv_2 = 0xFFFFFFFF + .name = "VMAX301 Socket", + .phys = NO_XIP, + .size = 0, + .buswidth = 1, + .read8 = vmax301_read8, + .read16 = vmax301_read16, + .read32 = vmax301_read32, + .copy_from = vmax301_copy_from, + .write8 = vmax301_write8, + .write16 = vmax301_write16, + .write32 = vmax301_write32, + .copy_to = vmax301_copy_to, + .map_priv_1 = WINDOW_START + (3*WINDOW_LENGTH), + .map_priv_2 = 0xFFFFFFFF } }; @@ -205,8 +209,8 @@ address of the first half, because it's used more often. */ - vmax_map[0].map_priv_1 = iomapadr + WINDOW_START; - vmax_map[1].map_priv_1 = iomapadr + (3*WINDOW_START); + vmax_map[0].map_priv_2 = iomapadr + WINDOW_START; + vmax_map[1].map_priv_2 = iomapadr + (3*WINDOW_START); for (i=0; i<2; i++) { vmax_mtd[i] = do_map_probe("cfi_probe", &vmax_map[i]); @@ -217,7 +221,7 @@ if (!vmax_mtd[i]) vmax_mtd[i] = do_map_probe("map_rom", &vmax_map[i]); if (vmax_mtd[i]) { - vmax_mtd[i]->module = THIS_MODULE; + vmax_mtd[i]->owner = THIS_MODULE; add_mtd_device(vmax_mtd[i]); } } diff -Nru a/drivers/mtd/mtd_blkdevs.c b/drivers/mtd/mtd_blkdevs.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/mtd_blkdevs.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,456 @@ +/* + * $Id: mtd_blkdevs.c,v 1.12 2003/05/21 01:00:59 dwmw2 Exp $ + * + * (C) 2003 David Woodhouse <dwmw2@infradead.org> + * + * Interface to Linux 2.5 block layer for MTD 'translation layers'. + * + */ + +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/list.h> +#include <linux/fs.h> +#include <linux/mtd/blktrans.h> +#include <linux/mtd/mtd.h> +#include <linux/blkdev.h> +#include <linux/blk.h> +#include <linux/blkpg.h> +#include <linux/spinlock.h> +#include <linux/init.h> +#include <asm/semaphore.h> +#include <linux/devfs_fs_kernel.h> + +static LIST_HEAD(blktrans_majors); + +extern struct semaphore mtd_table_mutex; +extern struct mtd_info *mtd_table[]; + +struct mtd_blkcore_priv { + struct completion thread_dead; + int exiting; + wait_queue_head_t thread_wq; + struct request_queue rq; + spinlock_t queue_lock; +}; + +static int do_blktrans_request(struct mtd_blktrans_ops *tr, + struct mtd_blktrans_dev *dev, + struct request *req) +{ + unsigned long block, nsect; + char *buf; + + block = req->sector; + nsect = req->current_nr_sectors; + buf = req->buffer; + + if (!req->flags & REQ_CMD) + return 0; + + if (block + nsect > get_capacity(req->rq_disk)) + return 0; + + switch(rq_data_dir(req)) { + case READ: + for (; nsect > 0; nsect--, block++, buf += 512) + if (tr->readsect(dev, block, buf)) + return 0; + return 1; + + case WRITE: + if (!tr->writesect) + return 0; + + for (; nsect > 0; nsect--, block++, buf += 512) + if (tr->writesect(dev, block, buf)) + return 0; + return 1; + + default: + printk(KERN_NOTICE "Unknown request %ld\n", rq_data_dir(req)); + return 0; + } +} + +static int mtd_blktrans_thread(void *arg) +{ + struct mtd_blktrans_ops *tr = arg; + struct request_queue *rq = &tr->blkcore_priv->rq; + + /* we might get involved when memory gets low, so use PF_MEMALLOC */ + current->flags |= PF_MEMALLOC; + + daemonize("%sd", tr->name); + + /* daemonize() doesn't do this for us since some kernel threads + actually want to deal with signals. We can't just call + exit_sighand() since that'll cause an oops when we finally + do exit. */ + spin_lock_irq(¤t->sighand->siglock); + sigfillset(¤t->blocked); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); + + while (!tr->blkcore_priv->exiting) { + struct request *req; + struct mtd_blktrans_dev *dev; + int res = 0; + DECLARE_WAITQUEUE(wait, current); + + spin_lock_irq(rq->queue_lock); + + req = elv_next_request(rq); + + if (!req) { + add_wait_queue(&tr->blkcore_priv->thread_wq, &wait); + set_current_state(TASK_INTERRUPTIBLE); + + spin_unlock_irq(rq->queue_lock); + + schedule(); + remove_wait_queue(&tr->blkcore_priv->thread_wq, &wait); + + continue; + } + + dev = req->rq_disk->private_data; + tr = dev->tr; + + spin_unlock_irq(rq->queue_lock); + + down(&dev->sem); + res = do_blktrans_request(tr, dev, req); + up(&dev->sem); + + spin_lock_irq(rq->queue_lock); + + end_request(req, res); + } + complete_and_exit(&tr->blkcore_priv->thread_dead, 0); +} + +static void mtd_blktrans_request(struct request_queue *rq) +{ + struct mtd_blktrans_ops *tr = rq->queuedata; + wake_up(&tr->blkcore_priv->thread_wq); +} + + +int blktrans_open(struct inode *i, struct file *f) +{ + struct mtd_blktrans_dev *dev; + struct mtd_blktrans_ops *tr; + int ret = -ENODEV; + + dev = i->i_bdev->bd_disk->private_data; + tr = dev->tr; + + if (!try_module_get(dev->mtd->owner)) + goto out; + + if (!try_module_get(tr->owner)) + goto out_tr; + + /* FIXME: Locking. A hot pluggable device can go away + (del_mtd_device can be called for it) without its module + being unloaded. */ + dev->mtd->usecount++; + + ret = 0; + if (tr->open && (ret = tr->open(dev, i, f))) { + dev->mtd->usecount--; + module_put(dev->mtd->owner); + out_tr: + module_put(tr->owner); + } + out: + return ret; +} + +int blktrans_release(struct inode *i, struct file *f) +{ + struct mtd_blktrans_dev *dev; + struct mtd_blktrans_ops *tr; + int ret = 0; + + dev = i->i_bdev->bd_disk->private_data; + tr = dev->tr; + + if (tr->release) + ret = tr->release(dev, i, f); + + if (!ret) { + dev->mtd->usecount--; + module_put(dev->mtd->owner); + module_put(tr->owner); + } + + return ret; +} + + +static int blktrans_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct mtd_blktrans_dev *dev; + struct mtd_blktrans_ops *tr; + int ret = -ENOTTY; + + dev = inode->i_bdev->bd_disk->private_data; + tr = dev->tr; + + if (tr->ioctl) + ret = tr->ioctl(dev, inode, file, cmd, arg); + + if (ret == -ENOTTY && (cmd == BLKROSET || cmd == BLKFLSBUF)) { + /* The core code did the work, we had nothing to do. */ + ret = 0; + } + return ret; +} + +struct block_device_operations mtd_blktrans_ops = { + .owner = THIS_MODULE, + .open = blktrans_open, + .release = blktrans_release, + .ioctl = blktrans_ioctl, +}; + +int add_mtd_blktrans_dev(struct mtd_blktrans_dev *new) +{ + struct mtd_blktrans_ops *tr = new->tr; + struct list_head *this; + int last_devnum = -1; + struct gendisk *gd; + + if (!down_trylock(&mtd_table_mutex)) { + up(&mtd_table_mutex); + BUG(); + } + + list_for_each(this, &tr->devs) { + struct mtd_blktrans_dev *d = list_entry(this, struct mtd_blktrans_dev, list); + if (new->devnum == -1) { + /* Use first free number */ + if (d->devnum != last_devnum+1) { + /* Found a free devnum. Plug it in here */ + new->devnum = last_devnum+1; + list_add_tail(&new->list, &d->list); + goto added; + } + } else if (d->devnum == new->devnum) { + /* Required number taken */ + return -EBUSY; + } else if (d->devnum > new->devnum) { + /* Required number was free */ + list_add_tail(&new->list, &d->list); + goto added; + } + last_devnum = d->devnum; + } + if (new->devnum == -1) + new->devnum = last_devnum+1; + + if ((new->devnum << tr->part_bits) > 256) { + return -EBUSY; + } + + init_MUTEX(&new->sem); + list_add_tail(&new->list, &tr->devs); + added: + if (!tr->writesect) + new->readonly = 1; + + gd = alloc_disk(1 << tr->part_bits); + if (!gd) { + list_del(&new->list); + return -ENOMEM; + } + gd->major = tr->major; + gd->first_minor = (new->devnum) << tr->part_bits; + gd->fops = &mtd_blktrans_ops; + + snprintf(gd->disk_name, sizeof(gd->disk_name), + "%s%c", tr->name, (tr->part_bits?'a':'0') + new->devnum); + snprintf(gd->devfs_name, sizeof(gd->devfs_name), + "%s/%c", tr->name, (tr->part_bits?'a':'0') + new->devnum); + + set_capacity(gd, new->size); + gd->private_data = new; + new->blkcore_priv = gd; + gd->queue = &tr->blkcore_priv->rq; + + if (new->readonly) + set_disk_ro(gd, 1); + + add_disk(gd); + + return 0; +} + +int del_mtd_blktrans_dev(struct mtd_blktrans_dev *old) +{ + if (!down_trylock(&mtd_table_mutex)) { + up(&mtd_table_mutex); + BUG(); + } + + list_del(&old->list); + + del_gendisk(old->blkcore_priv); + put_disk(old->blkcore_priv); + + return 0; +} + +void blktrans_notify_remove(struct mtd_info *mtd) +{ + struct list_head *this, *this2, *next; + + list_for_each(this, &blktrans_majors) { + struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list); + + list_for_each_safe(this2, next, &tr->devs) { + struct mtd_blktrans_dev *dev = list_entry(this2, struct mtd_blktrans_dev, list); + + if (dev->mtd == mtd) + tr->remove_dev(dev); + } + } +} + +void blktrans_notify_add(struct mtd_info *mtd) +{ + struct list_head *this; + + if (mtd->type == MTD_ABSENT) + return; + + printk("%s:%s %d: count %d\n", __FILE__, __func__, __LINE__, atomic_read(&mtd_table_mutex.count)); + + list_for_each(this, &blktrans_majors) { + struct mtd_blktrans_ops *tr = list_entry(this, struct mtd_blktrans_ops, list); + + tr->add_mtd(tr, mtd); + } + +} + +static struct mtd_notifier blktrans_notifier = { + .add = blktrans_notify_add, + .remove = blktrans_notify_remove, +}; + +int register_mtd_blktrans(struct mtd_blktrans_ops *tr) +{ + int ret, i; + + /* Register the notifier if/when the first device type is + registered, to prevent the link/init ordering from fucking + us over. */ + if (!blktrans_notifier.list.next) + register_mtd_user(&blktrans_notifier); + + tr->blkcore_priv = kmalloc(sizeof(*tr->blkcore_priv), GFP_KERNEL); + if (!tr->blkcore_priv) + return -ENOMEM; + + memset(tr->blkcore_priv, 0, sizeof(*tr->blkcore_priv)); + + down(&mtd_table_mutex); + + ret = register_blkdev(tr->major, tr->name); + if (ret) { + printk(KERN_WARNING "Unable to register %s block device on major %d: %d\n", + tr->name, tr->major, ret); + kfree(tr->blkcore_priv); + up(&mtd_table_mutex); + return ret; + } + spin_lock_init(&tr->blkcore_priv->queue_lock); + init_completion(&tr->blkcore_priv->thread_dead); + init_waitqueue_head(&tr->blkcore_priv->thread_wq); + + blk_init_queue(&tr->blkcore_priv->rq, mtd_blktrans_request, + &tr->blkcore_priv->queue_lock); + tr->blkcore_priv->rq.queuedata = tr; + + ret = kernel_thread(mtd_blktrans_thread, tr, + CLONE_FS|CLONE_FILES|CLONE_SIGHAND); + if (ret < 0) { + blk_cleanup_queue(&tr->blkcore_priv->rq); + unregister_blkdev(tr->major, tr->name); + kfree(tr->blkcore_priv); + up(&mtd_table_mutex); + return ret; + } + + devfs_mk_dir(tr->name); + + INIT_LIST_HEAD(&tr->devs); + list_add(&tr->list, &blktrans_majors); + + printk("%s:%s %d: count %d\n", __FILE__, __func__, __LINE__, atomic_read(&mtd_table_mutex.count)); + + for (i=0; i<MAX_MTD_DEVICES; i++) { + if (mtd_table[i] && mtd_table[i]->type != MTD_ABSENT) + tr->add_mtd(tr, mtd_table[i]); + } + + up(&mtd_table_mutex); + + return 0; +} + +int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr) +{ + struct list_head *this, *next; + + down(&mtd_table_mutex); + + /* Clean up the kernel thread */ + tr->blkcore_priv->exiting = 1; + wake_up(&tr->blkcore_priv->thread_wq); + wait_for_completion(&tr->blkcore_priv->thread_dead); + + /* Remove it from the list of active majors */ + list_del(&tr->list); + + list_for_each_safe(this, next, &tr->devs) { + struct mtd_blktrans_dev *dev = list_entry(this, struct mtd_blktrans_dev, list); + tr->remove_dev(dev); + } + + devfs_remove(tr->name); + blk_cleanup_queue(&tr->blkcore_priv->rq); + unregister_blkdev(tr->major, tr->name); + + up(&mtd_table_mutex); + + kfree(tr->blkcore_priv); + + if (!list_empty(&tr->devs)) + BUG(); + return 0; +} + +static void __exit mtd_blktrans_exit(void) +{ + /* No race here -- if someone's currently in register_mtd_blktrans + we're screwed anyway. */ + if (blktrans_notifier.list.next) + unregister_mtd_user(&blktrans_notifier); +} + +module_exit(mtd_blktrans_exit); + +EXPORT_SYMBOL_GPL(register_mtd_blktrans); +EXPORT_SYMBOL_GPL(deregister_mtd_blktrans); +EXPORT_SYMBOL_GPL(add_mtd_blktrans_dev); +EXPORT_SYMBOL_GPL(del_mtd_blktrans_dev); + +MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Common interface to block layer for MTD 'translation layers'"); diff -Nru a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c --- a/drivers/mtd/mtdblock.c Mon Jun 9 23:16:10 2003 +++ b/drivers/mtd/mtdblock.c Mon Jun 9 23:16:10 2003 @@ -1,37 +1,25 @@ /* * Direct MTD block device access * - * $Id: mtdblock.c,v 1.47 2001/10/02 15:05:11 dwmw2 Exp $ + * $Id: mtdblock.c,v 1.61 2003/05/21 10:49:38 dwmw2 Exp $ * - * 02-nov-2000 Nicolas Pitre Added read-modify-write with cache + * (C) 2000-2003 Nicolas Pitre <nico@cam.org> + * (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> */ #include <linux/config.h> #include <linux/types.h> #include <linux/module.h> #include <linux/kernel.h> +#include <linux/fs.h> +#include <linux/init.h> #include <linux/slab.h> -#include <linux/buffer_head.h> +#include <linux/vmalloc.h> #include <linux/mtd/mtd.h> -#include <linux/mtd/compatmac.h> -#include <linux/buffer_head.h> - -#define MAJOR_NR MTD_BLOCK_MAJOR -#define DEVICE_NAME "mtdblock" -#define DEVICE_NR(device) (device) -#include <linux/blk.h> -#include <linux/devfs_fs_kernel.h> - -static void mtd_notify_add(struct mtd_info* mtd); -static void mtd_notify_remove(struct mtd_info* mtd); -static struct mtd_notifier notifier = { - mtd_notify_add, - mtd_notify_remove, - NULL -}; +#include <linux/mtd/blktrans.h> static struct mtdblk_dev { - struct mtd_info *mtd; /* Locked */ + struct mtd_info *mtd; int count; struct semaphore cache_sem; unsigned char *cache_data; @@ -40,10 +28,6 @@ enum { STATE_EMPTY, STATE_CLEAN, STATE_DIRTY } cache_state; } *mtdblks[MAX_MTD_DEVICES]; -static struct gendisk *mtddisk[MAX_MTD_DEVICES]; - -static spinlock_t mtdblks_lock; - /* * Cache stuff... * @@ -127,7 +111,7 @@ return ret; /* - * Here we could argably set the cache state to STATE_CLEAN. + * Here we could argubly set the cache state to STATE_CLEAN. * However this could lead to inconsistency since we will not * be notified if this content is altered on the flash by other * means. Let's declare it empty and leave buffering tasks to @@ -253,48 +237,39 @@ return 0; } -static struct block_device_operations mtd_fops; +static int mtdblock_readsect(struct mtd_blktrans_dev *dev, + unsigned long block, char *buf) +{ + struct mtdblk_dev *mtdblk = mtdblks[dev->devnum]; + return do_cached_read(mtdblk, block<<9, 512, buf); +} + +static int mtdblock_writesect(struct mtd_blktrans_dev *dev, + unsigned long block, char *buf) +{ + struct mtdblk_dev *mtdblk = mtdblks[dev->devnum]; + return do_cached_write(mtdblk, block<<9, 512, buf); +} -static int mtdblock_open(struct inode *inode, struct file *file) +static int mtdblock_open(struct mtd_blktrans_dev *mbd, + struct inode *inode, struct file *file) { struct mtdblk_dev *mtdblk; - struct mtd_info *mtd; - int dev = minor(inode->i_rdev); - struct gendisk *disk; + struct mtd_info *mtd = mbd->mtd; + int dev = mbd->devnum; DEBUG(MTD_DEBUG_LEVEL1,"mtdblock_open\n"); - - if (dev >= MAX_MTD_DEVICES) - return -EINVAL; - - mtd = get_mtd_device(NULL, dev); - if (!mtd) - return -ENODEV; - if (MTD_ABSENT == mtd->type) { - put_mtd_device(mtd); - return -ENODEV; - } - spin_lock(&mtdblks_lock); - - /* If it's already open, no need to piss about. */ if (mtdblks[dev]) { mtdblks[dev]->count++; - spin_unlock(&mtdblks_lock); return 0; } - /* OK, it's not open. Try to find it */ - - /* First we have to drop the lock, because we have to - to things which might sleep. - */ - spin_unlock(&mtdblks_lock); - + /* OK, it's not open. Create cache info for it */ mtdblk = kmalloc(sizeof(struct mtdblk_dev), GFP_KERNEL); - disk = mtddisk[dev]; - if (!mtdblk || !disk) - goto Enomem; + if (!mtdblks) + return -ENOMEM; + memset(mtdblk, 0, sizeof(*mtdblk)); mtdblk->count = 1; mtdblk->mtd = mtd; @@ -305,46 +280,26 @@ mtdblk->mtd->erasesize) { mtdblk->cache_size = mtdblk->mtd->erasesize; mtdblk->cache_data = vmalloc(mtdblk->mtd->erasesize); - if (!mtdblk->cache_data) - goto Enomem; - } - - /* OK, we've created a new one. Add it to the list. */ - - spin_lock(&mtdblks_lock); - - if (mtdblks[dev]) { - /* Another CPU made one at the same time as us. */ - mtdblks[dev]->count++; - spin_unlock(&mtdblks_lock); - put_mtd_device(mtdblk->mtd); - vfree(mtdblk->cache_data); - kfree(mtdblk); - return 0; + if (!mtdblk->cache_data) { + kfree(mtdblk); + return -ENOMEM; + } } mtdblks[dev] = mtdblk; - set_device_ro(inode->i_bdev, !(mtdblk->mtd->flags & MTD_WRITEABLE)); - - spin_unlock(&mtdblks_lock); - + DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); return 0; -Enomem: - put_mtd_device(mtd); - kfree(mtdblk); - return -ENOMEM; } -static release_t mtdblock_release(struct inode *inode, struct file *file) +static int mtdblock_release(struct mtd_blktrans_dev *mbd, + struct inode *inode, struct file *file) { int dev; struct mtdblk_dev *mtdblk; - DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n"); - if (inode == NULL) - release_return(-ENODEV); + DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n"); dev = minor(inode->i_rdev); mtdblk = mtdblks[dev]; @@ -353,149 +308,30 @@ write_cached_data(mtdblk); up(&mtdblk->cache_sem); - spin_lock(&mtdblks_lock); if (!--mtdblk->count) { /* It was the last usage. Free the device */ mtdblks[dev] = NULL; - spin_unlock(&mtdblks_lock); if (mtdblk->mtd->sync) mtdblk->mtd->sync(mtdblk->mtd); - put_mtd_device(mtdblk->mtd); vfree(mtdblk->cache_data); kfree(mtdblk); - } else { - spin_unlock(&mtdblks_lock); } - DEBUG(MTD_DEBUG_LEVEL1, "ok\n"); - release_return(0); -} - - -/* - * This is a special request_fn because it is executed in a process context - * to be able to sleep independently of the caller. The queue_lock - * is held upon entry and exit. - * The head of our request queue is considered active so there is no need - * to dequeue requests before we are done. - */ -static struct request_queue mtd_queue; -static void handle_mtdblock_request(void) -{ - struct request *req; - struct mtdblk_dev *mtdblk; - unsigned int res; - - while ((req = elv_next_request(&mtd_queue)) != NULL) { - struct mtdblk_dev **p = req->rq_disk->private_data; - spin_unlock_irq(mtd_queue.queue_lock); - mtdblk = *p; - res = 0; - - if (! (req->flags & REQ_CMD)) - goto end_req; - - if ((req->sector + req->current_nr_sectors) > (mtdblk->mtd->size >> 9)) - goto end_req; - - // Handle the request - switch (rq_data_dir(req)) - { - int err; - - case READ: - down(&mtdblk->cache_sem); - err = do_cached_read (mtdblk, req->sector << 9, - req->current_nr_sectors << 9, - req->buffer); - up(&mtdblk->cache_sem); - if (!err) - res = 1; - break; - - case WRITE: - // Read only device - if ( !(mtdblk->mtd->flags & MTD_WRITEABLE) ) - break; - - // Do the write - down(&mtdblk->cache_sem); - err = do_cached_write (mtdblk, req->sector << 9, - req->current_nr_sectors << 9, - req->buffer); - up(&mtdblk->cache_sem); - if (!err) - res = 1; - break; - } - -end_req: - spin_lock_irq(mtd_queue.queue_lock); - if (!end_that_request_first(req, res, req->hard_cur_sectors)) { - blkdev_dequeue_request(req); - end_that_request_last(req); - } - - } -} - -static volatile int leaving = 0; -static DECLARE_MUTEX_LOCKED(thread_sem); -static DECLARE_WAIT_QUEUE_HEAD(thr_wq); - -int mtdblock_thread(void *dummy) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - /* we might get involved when memory gets low, so use PF_MEMALLOC */ - tsk->flags |= PF_MEMALLOC; - daemonize("mtdblockd"); - - while (!leaving) { - add_wait_queue(&thr_wq, &wait); - set_current_state(TASK_INTERRUPTIBLE); - spin_lock_irq(mtd_queue.queue_lock); - if (!elv_next_request(&mtd_queue) || blk_queue_plugged(&mtd_queue)) { - spin_unlock_irq(mtd_queue.queue_lock); - schedule(); - remove_wait_queue(&thr_wq, &wait); - } else { - remove_wait_queue(&thr_wq, &wait); - set_current_state(TASK_RUNNING); - handle_mtdblock_request(); - spin_unlock_irq(mtd_queue.queue_lock); - } - } - - up(&thread_sem); return 0; -} - -static void mtdblock_request(struct request_queue *q) -{ - /* Don't do anything, except wake the thread if necessary */ - wake_up(&thr_wq); -} +} -static int mtdblock_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg) +static int mtdblock_ioctl(struct mtd_blktrans_dev *dev, + struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg) { struct mtdblk_dev *mtdblk; mtdblk = mtdblks[minor(inode->i_rdev)]; -#ifdef PARANOIA - if (!mtdblk) - BUG(); -#endif - switch (cmd) { case BLKFLSBUF: - fsync_bdev(inode->i_bdev); - invalidate_bdev(inode->i_bdev, 0); down(&mtdblk->cache_sem); write_cached_data(mtdblk); up(&mtdblk->cache_sem); @@ -504,90 +340,59 @@ return 0; default: - return -EINVAL; + return -ENOTTY; } } -static struct block_device_operations mtd_fops = +static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) { - .owner = THIS_MODULE, - .open = mtdblock_open, - .release = mtdblock_release, - .ioctl = mtdblock_ioctl -}; + struct mtd_blktrans_dev *dev = kmalloc(sizeof(*dev), GFP_KERNEL); -/* Notification that a new device has been added. Create the devfs entry for - * it. */ + if (!dev) + return; -static void mtd_notify_add(struct mtd_info* mtd) -{ - struct gendisk *disk; - char name[16]; - - if (!mtd || mtd->type == MTD_ABSENT) - return; + memset(dev, 0, sizeof(*dev)); - disk = alloc_disk(1); - if (disk) { - disk->major = MAJOR_NR; - disk->first_minor = mtd->index; - disk->fops = &mtd_fops; + dev->mtd = mtd; + dev->devnum = mtd->index; + dev->blksize = 512; + dev->size = mtd->size >> 9; + dev->tr = tr; - sprintf(disk->disk_name, "mtdblock%d", mtd->index); - sprintf(disk->devfs_name, "mtdblock/%d", mtd->index); + if (!(mtd->flags & MTD_WRITEABLE)) + dev->readonly = 1; - mtddisk[mtd->index] = disk; - set_capacity(disk, mtd->size / 512); - disk->private_data = &mtdblks[mtd->index]; - disk->queue = &mtd_queue; - - add_disk(disk); - } + add_mtd_blktrans_dev(dev); } -static void mtd_notify_remove(struct mtd_info* mtd) +static void mtdblock_remove_dev(struct mtd_blktrans_dev *dev) { - if (!mtd || mtd->type == MTD_ABSENT) - return; - - if (mtddisk[mtd->index]) { - del_gendisk(mtddisk[mtd->index]); - put_disk(mtddisk[mtd->index]); - mtddisk[mtd->index] = NULL; - } + del_mtd_blktrans_dev(dev); + kfree(dev); } -static spinlock_t mtddev_lock = SPIN_LOCK_UNLOCKED; +struct mtd_blktrans_ops mtdblock_tr = { + .name = "mtdblock", + .major = 31, + .part_bits = 0, + .open = mtdblock_open, + .ioctl = mtdblock_ioctl, + .release = mtdblock_release, + .readsect = mtdblock_readsect, + .writesect = mtdblock_writesect, + .add_mtd = mtdblock_add_mtd, + .remove_dev = mtdblock_remove_dev, + .owner = THIS_MODULE, +}; int __init init_mtdblock(void) { - spin_lock_init(&mtdblks_lock); - - if (register_blkdev(MAJOR_NR, DEVICE_NAME)) - return -EAGAIN; - -#ifdef CONFIG_DEVFS_FS - devfs_mk_dir(DEVICE_NAME); -#endif - register_mtd_user(¬ifier); - - init_waitqueue_head(&thr_wq); - blk_init_queue(&mtd_queue, &mtdblock_request, &mtddev_lock); - kernel_thread (mtdblock_thread, NULL, CLONE_FS|CLONE_FILES|CLONE_SIGHAND); - return 0; + return register_mtd_blktrans(&mtdblock_tr); } static void __exit cleanup_mtdblock(void) { - leaving = 1; - wake_up(&thr_wq); - down(&thread_sem); - unregister_mtd_user(¬ifier); -#ifdef CONFIG_DEVFS_FS - devfs_remove(DEVICE_NAME); -#endif - unregister_blkdev(MAJOR_NR,DEVICE_NAME); - blk_cleanup_queue(&mtd_queue); + deregister_mtd_blktrans(&mtdblock_tr); } module_init(init_mtdblock); diff -Nru a/drivers/mtd/mtdblock.h b/drivers/mtd/mtdblock.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/mtdblock.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,35 @@ +/* + * drivers/mtd/mtdblock.h + * + * common defines for mtdblock-core and mtdblock-2x + * + * $Id: mtdblock.h,v 1.1 2002/11/27 10:33:37 gleixner Exp $ + * + */ + +#ifndef __MTD_MTDBLOCK_H__ +#define __MTD_MTDBLOCK_H__ + +#define MAJOR_NR MTD_BLOCK_MAJOR +#define DEVICE_NAME "mtdblock" + +struct mtdblk_dev { + struct mtd_info *mtd; /* Locked */ + int count; + struct semaphore cache_sem; + unsigned char *cache_data; + unsigned long cache_offset; + unsigned int cache_size; + enum { STATE_EMPTY, STATE_CLEAN, STATE_DIRTY } cache_state; +}; + +extern int write_cached_data (struct mtdblk_dev *mtdblk); +extern int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos, + int len, const char *buf); +extern int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos, + int len, char *buf); + +extern void __exit cleanup_mtdblock(void); +extern int __init init_mtdblock(void); + +#endif diff -Nru a/drivers/mtd/mtdblock_ro.c b/drivers/mtd/mtdblock_ro.c --- a/drivers/mtd/mtdblock_ro.c Mon Jun 9 23:16:12 2003 +++ b/drivers/mtd/mtdblock_ro.c Mon Jun 9 23:16:12 2003 @@ -1,265 +1,86 @@ /* - * $Id: mtdblock_ro.c,v 1.13 2002/03/11 16:03:29 sioux Exp $ + * $Id: mtdblock_ro.c,v 1.17 2003/05/18 19:27:27 dwmw2 Exp $ * - * Read-only flash, read-write RAM version of the mtdblock device, - * without caching. + * (C) 2003 David Woodhouse <dwmw2@infradead.org> + * + * Simple read-only (writable only for RAM) mtdblock driver */ -#ifdef MTDBLOCK_DEBUG -#define DEBUGLVL debug -#endif - - -#include <linux/module.h> -#include <linux/types.h> - +#include <linux/slab.h> #include <linux/mtd/mtd.h> -#include <linux/mtd/compatmac.h> -#include <linux/buffer_head.h> -#include <linux/genhd.h> - -#define MAJOR_NR MTD_BLOCK_MAJOR -#define DEVICE_NAME "mtdblock" -#include <linux/blk.h> - -#ifdef MTDBLOCK_DEBUG -static int debug = MTDBLOCK_DEBUG; -MODULE_PARM(debug, "i"); -#endif - -struct mtdro_dev { - struct gendisk *disk; - struct mtd_info *mtd; - int open; -}; +#include <linux/mtd/blktrans.h> -static struct mtdro_dev mtd_dev[MAX_MTD_DEVICES]; -static DECLARE_MUTEX(mtd_sem); - -static struct request_queue mtdro_queue; -static spinlock_t mtdro_lock = SPIN_LOCK_UNLOCKED; - -static int mtdblock_open(struct inode *inode, struct file *file) +static int mtdblock_readsect(struct mtd_blktrans_dev *dev, + unsigned long block, char *buf) { - struct mtdro_dev *mdev = inode->i_bdev->bd_disk->private_data; - int ret = 0; - - DEBUG(1,"mtdblock_open\n"); - - down(&mtd_sem); - if (mdev->mtd == NULL) { - mdev->mtd = get_mtd_device(NULL, minor(inode->i_rdev)); - if (!mdev->mtd || mdev->mtd->type == MTD_ABSENT) { - if (mdev->mtd) - put_mtd_device(mdev->mtd); - ret = -ENODEV; - } - } - - if (ret == 0) { - set_device_ro(inode->i_bdev, !(mdev->mtd->flags & MTD_CAP_RAM)); - mdev->open++; - } - up(&mtd_sem); - - DEBUG(1, "%s\n", ret ? "ok" : "nodev"); + size_t retlen; - return ret; + if (dev->mtd->read(dev->mtd, (block * 512), 512, &retlen, buf)) + return 1; + return 0; } -static release_t mtdblock_release(struct inode *inode, struct file *file) +static int mtdblock_writesect(struct mtd_blktrans_dev *dev, + unsigned long block, char *buf) { - struct mtdro_dev *mdev = inode->i_bdev->bd_disk->private_data; - - DEBUG(1, "mtdblock_release\n"); - - down(&mtd_sem); - if (mdev->open-- == 0) { - struct mtd_info *mtd = mdev->mtd; - - mdev->mtd = NULL; - if (mtd->sync) - mtd->sync(mtd); - - put_mtd_device(mtd); - } - up(&mtd_sem); + size_t retlen; - DEBUG(1, "ok\n"); - - release_return(0); -} - -static void mtdblock_request(request_queue_t *q) -{ - struct request *req; - - while ((req = elv_next_request(q)) != NULL) { - struct mtdro_dev *mdev = req->rq_disk->private_data; - struct mtd_info *mtd = mdev->mtd; - unsigned int res; - - if (!(req->flags & REQ_CMD)) { - res = 0; - goto end_req; - } - - if ((req->sector + req->current_nr_sectors) > (mtd->size >> 9)) { - printk("mtd: Attempt to read past end of device!\n"); - printk("size: %x, sector: %lx, nr_sectors: %x\n", - mtd->size, req->sector, req->current_nr_sectors); - res = 0; - goto end_req; - } - - /* Now drop the lock that the ll_rw_blk functions grabbed for - us and process the request. This is necessary due to the - extreme time we spend processing it. */ - spin_unlock_irq(q->queue_lock); - - /* Handle the request */ - switch (rq_data_dir(req)) { - size_t retlen; - - case READ: - if (MTD_READ(mtd, req->sector << 9, - req->current_nr_sectors << 9, - &retlen, req->buffer) == 0) - res = 1; - else - res = 0; - break; - - case WRITE: - /* printk("mtdblock_request WRITE sector=%d(%d)\n", - req->sector, req->current_nr_sectors); - */ - - /* Read only device */ - if ((mtd->flags & MTD_CAP_RAM) == 0) { - res = 0; - break; - } - - /* Do the write */ - if (MTD_WRITE(mtd, req->sector << 9, - req->current_nr_sectors << 9, - &retlen, req->buffer) == 0) - res = 1; - else - res = 0; - break; - - /* Shouldn't happen */ - default: - printk("mtd: unknown request\n"); - res = 0; - break; - } - - /* Grab the lock and re-thread the item onto the linked list */ - spin_lock_irq(q->queue_lock); - end_req: - if (!end_that_request_first(req, res, req->hard_cur_sectors)) { - blkdev_dequeue_request(req); - end_that_request_last(req); - } - } + if (dev->mtd->write(dev->mtd, (block * 512), 512, &retlen, buf)) + return 1; + return 0; } -static int mtdblock_ioctl(struct inode * inode, struct file * file, - unsigned int cmd, unsigned long arg) +static void mtdblock_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) { - struct mtdro_dev *mdev = inode->i_bdev->bd_disk->private_data; - - if (cmd != BLKFLSBUF) - return -EINVAL; - - fsync_bdev(inode->i_bdev); - invalidate_bdev(inode->i_bdev, 0); - if (mdev->mtd->sync) - mdev->mtd->sync(mdev->mtd); + struct mtd_blktrans_dev *dev = kmalloc(sizeof(*dev), GFP_KERNEL); - return 0; -} + if (!dev) + return; -static struct block_device_operations mtd_fops = { - .owner = THIS_MODULE, - .open = mtdblock_open, - .release = mtdblock_release, - .ioctl = mtdblock_ioctl -}; - -/* Called with mtd_table_mutex held. */ -static void mtd_notify_add(struct mtd_info* mtd) -{ - struct gendisk *disk; + memset(dev, 0, sizeof(*dev)); - if (!mtd || mtd->type == MTD_ABSENT || mtd->index >= MAX_MTD_DEVICES) - return; + dev->mtd = mtd; + dev->devnum = mtd->index; + dev->blksize = 512; + dev->size = mtd->size >> 9; + dev->tr = tr; + if ((mtd->flags & (MTD_CLEAR_BITS|MTD_SET_BITS|MTD_WRITEABLE)) != + (MTD_CLEAR_BITS|MTD_SET_BITS|MTD_WRITEABLE)) + dev->readonly = 1; - disk = alloc_disk(1); - if (disk) { - disk->major = MAJOR_NR; - disk->first_minor = mtd->index; - disk->fops = &mtd_fops; - sprintf(disk->disk_name, "mtdblock%d", mtd->index); - - mtd_dev[mtd->index].disk = disk; - set_capacity(disk, mtd->size / 512); - disk->queue = &mtdro_queue; - disk->private_data = &mtd_dev[mtd->index]; - add_disk(disk); - } + add_mtd_blktrans_dev(dev); } -/* Called with mtd_table_mutex held. */ -static void mtd_notify_remove(struct mtd_info* mtd) +static void mtdblock_remove_dev(struct mtd_blktrans_dev *dev) { - struct mtdro_dev *mdev; - struct gendisk *disk; - - if (!mtd || mtd->type == MTD_ABSENT || mtd->index >= MAX_MTD_DEVICES) - return; - - mdev = &mtd_dev[mtd->index]; - - disk = mdev->disk; - mdev->disk = NULL; - - if (disk) { - del_gendisk(disk); - put_disk(disk); - } + del_mtd_blktrans_dev(dev); + kfree(dev); } -static struct mtd_notifier notifier = { - .add = mtd_notify_add, - .remove = mtd_notify_remove, +struct mtd_blktrans_ops mtdblock_tr = { + .name = "mtdblock", + .major = 31, + .part_bits = 0, + .readsect = mtdblock_readsect, + .writesect = mtdblock_writesect, + .add_mtd = mtdblock_add_mtd, + .remove_dev = mtdblock_remove_dev, + .owner = THIS_MODULE, }; -int __init init_mtdblock(void) +static int __init mtdblock_init(void) { - if (register_blkdev(MAJOR_NR, DEVICE_NAME)) - return -EAGAIN; - - blk_init_queue(&mtdro_queue, &mtdblock_request, &mtdro_lock); - register_mtd_user(¬ifier); - - return 0; + return register_mtd_blktrans(&mtdblock_tr); } -static void __exit cleanup_mtdblock(void) +static void __exit mtdblock_exit(void) { - unregister_mtd_user(¬ifier); - unregister_blkdev(MAJOR_NR,DEVICE_NAME); - blk_cleanup_queue(&mtdro_queue); + deregister_mtd_blktrans(&mtdblock_tr); } -module_init(init_mtdblock); -module_exit(cleanup_mtdblock); - +module_init(mtdblock_init); +module_exit(mtdblock_exit); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Erwin Authried <eauth@softsys.co.at> et al."); -MODULE_DESCRIPTION("Simple uncached block device emulation access to MTD devices"); +MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>"); +MODULE_DESCRIPTION("Simple read-only block device emulation access to MTD devices"); diff -Nru a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c --- a/drivers/mtd/mtdchar.c Mon Jun 9 23:16:15 2003 +++ b/drivers/mtd/mtdchar.c Mon Jun 9 23:16:15 2003 @@ -1,8 +1,7 @@ /* - * $Id: mtdchar.c,v 1.44 2001/10/02 15:05:11 dwmw2 Exp $ + * $Id: mtdchar.c,v 1.54 2003/05/21 10:50:43 dwmw2 Exp $ * * Character-device access to raw MTD devices. - * Pure 2.4 version - compatibility cruft removed to mtdchar-compat.c * */ @@ -10,8 +9,10 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/mtd/mtd.h> -#include <linux/smp_lock.h> #include <linux/slab.h> +#include <linux/init.h> +#include <linux/fs.h> +#include <asm/uaccess.h> #ifdef CONFIG_DEVFS_FS #include <linux/devfs_fs_kernel.h> @@ -29,7 +30,6 @@ { struct mtd_info *mtd=(struct mtd_info *)file->private_data; - lock_kernel(); switch (orig) { case 0: /* SEEK_SET */ @@ -44,7 +44,6 @@ file->f_pos =mtd->size + offset; break; default: - unlock_kernel(); return -EINVAL; } @@ -53,7 +52,6 @@ else if (file->f_pos >= mtd->size) file->f_pos = mtd->size - 1; - unlock_kernel(); return file->f_pos; } @@ -288,7 +286,12 @@ case MEMERASE: { - struct erase_info *erase=kmalloc(sizeof(struct erase_info),GFP_KERNEL); + struct erase_info *erase; + + if(!(file->f_mode & 2)) + return -EPERM; + + erase=kmalloc(sizeof(struct erase_info),GFP_KERNEL); if (!erase) ret = -ENOMEM; else { @@ -339,6 +342,9 @@ void *databuf; ssize_t retlen; + if(!(file->f_mode & 2)) + return -EPERM; + if (copy_from_user(&buf, (struct mtd_oob_buf *)arg, sizeof(struct mtd_oob_buf))) return -EFAULT; @@ -435,6 +441,12 @@ break; } + case MEMSETOOBSEL: + { + if (copy_from_user(&mtd->oobinfo ,(void *)arg, sizeof(struct nand_oobinfo))) + return -EFAULT; + break; + } default: DEBUG(MTD_DEBUG_LEVEL0, "Invalid ioctl %x (MEMGETINFO = %x)\n", cmd, MEMGETINFO); @@ -446,12 +458,12 @@ static struct file_operations mtd_fops = { .owner = THIS_MODULE, - .llseek = mtd_lseek, /* lseek */ - .read = mtd_read, /* read */ - .write = mtd_write, /* write */ - .ioctl = mtd_ioctl, /* ioctl */ - .open = mtd_open, /* open */ - .release = mtd_close, /* release */ + .llseek = mtd_lseek, + .read = mtd_read, + .write = mtd_write, + .ioctl = mtd_ioctl, + .open = mtd_open, + .release = mtd_close, }; diff -Nru a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c --- a/drivers/mtd/mtdconcat.c Mon Jun 9 23:16:16 2003 +++ b/drivers/mtd/mtdconcat.c Mon Jun 9 23:16:16 2003 @@ -3,9 +3,11 @@ * * (C) 2002 Robert Kaiser <rkaiser@sysgo.de> * + * NAND support by Christian Gan <cgan@iders.ca> + * * This code is GPL * - * $Id: mtdconcat.c,v 1.3 2002/05/21 21:04:25 dwmw2 Exp $ + * $Id: mtdconcat.c,v 1.4 2003/03/07 17:44:59 rkaiser Exp $ */ #include <linux/module.h> @@ -63,16 +65,16 @@ size_t size, retsize; if (from >= subdev->size) - { + { /* Not destined for this subdev */ size = 0; from -= subdev->size; } else { if (from + len > subdev->size) - size = subdev->size - from; + size = subdev->size - from; /* First part goes into this subdev */ else - size = len; + size = len; /* Entire transaction goes into this subdev */ err = subdev->read(subdev, from, size, &retsize, buf); @@ -142,6 +144,214 @@ return err; } +static int concat_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel) +{ + struct mtd_concat *concat = CONCAT(mtd); + int err = -EINVAL; + int i; + + *retlen = 0; + + for(i = 0; i < concat->num_subdev; i++) + { + struct mtd_info *subdev = concat->subdev[i]; + size_t size, retsize; + + if (from >= subdev->size) + { /* Not destined for this subdev */ + size = 0; + from -= subdev->size; + } + else + { + if (from + len > subdev->size) + size = subdev->size - from; /* First part goes into this subdev */ + else + size = len; /* Entire transaction goes into this subdev */ + + if (subdev->read_ecc) + err = subdev->read_ecc(subdev, from, size, &retsize, buf, eccbuf, oobsel); + else + err = -EINVAL; + + if(err) + break; + + *retlen += retsize; + len -= size; + if(len == 0) + break; + + err = -EINVAL; + buf += size; + if (eccbuf) + { + eccbuf += subdev->oobsize; + /* in nand.c at least, eccbufs are tagged with 2 (int)eccstatus', + we must account for these */ + eccbuf += 2 * (sizeof(int)); + } + from = 0; + } + } + return err; +} + +static int concat_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel) +{ + struct mtd_concat *concat = CONCAT(mtd); + int err = -EINVAL; + int i; + + if (!(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + + *retlen = 0; + + for(i = 0; i < concat->num_subdev; i++) + { + struct mtd_info *subdev = concat->subdev[i]; + size_t size, retsize; + + if (to >= subdev->size) + { + size = 0; + to -= subdev->size; + } + else + { + if (to + len > subdev->size) + size = subdev->size - to; + else + size = len; + + if (!(subdev->flags & MTD_WRITEABLE)) + err = -EROFS; + else if (subdev->write_ecc) + err = subdev->write_ecc(subdev, to, size, &retsize, buf, eccbuf, oobsel); + else + err = -EINVAL; + + if(err) + break; + + *retlen += retsize; + len -= size; + if(len == 0) + break; + + err = -EINVAL; + buf += size; + if (eccbuf) + eccbuf += subdev->oobsize; + to = 0; + } + } + return err; +} + +static int concat_read_oob (struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct mtd_concat *concat = CONCAT(mtd); + int err = -EINVAL; + int i; + + *retlen = 0; + + for(i = 0; i < concat->num_subdev; i++) + { + struct mtd_info *subdev = concat->subdev[i]; + size_t size, retsize; + + if (from >= subdev->size) + { /* Not destined for this subdev */ + size = 0; + from -= subdev->size; + } + else + { + if (from + len > subdev->size) + size = subdev->size - from; /* First part goes into this subdev */ + else + size = len; /* Entire transaction goes into this subdev */ + + if (subdev->read_oob) + err = subdev->read_oob(subdev, from, size, &retsize, buf); + else + err = -EINVAL; + + if(err) + break; + + *retlen += retsize; + len -= size; + if(len == 0) + break; + + err = -EINVAL; + buf += size; + from = 0; + } + } + return err; +} + +static int concat_write_oob (struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct mtd_concat *concat = CONCAT(mtd); + int err = -EINVAL; + int i; + + if (!(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + + *retlen = 0; + + for(i = 0; i < concat->num_subdev; i++) + { + struct mtd_info *subdev = concat->subdev[i]; + size_t size, retsize; + + if (to >= subdev->size) + { + size = 0; + to -= subdev->size; + } + else + { + if (to + len > subdev->size) + size = subdev->size - to; + else + size = len; + + if (!(subdev->flags & MTD_WRITEABLE)) + err = -EROFS; + else if (subdev->write_oob) + err = subdev->write_oob(subdev, to, size, &retsize, buf); + else + err = -EINVAL; + + if(err) + break; + + *retlen += retsize; + len -= size; + if(len == 0) + break; + + err = -EINVAL; + buf += size; + to = 0; + } + } + return err; +} + + static void concat_erase_callback (struct erase_info *instr) { wake_up((wait_queue_head_t *)instr->priv); @@ -526,14 +736,18 @@ * because they are messy to implement and they are not * used to a great extent anyway. */ - concat->mtd.erase = concat_erase; - concat->mtd.read = concat_read; - concat->mtd.write = concat_write; - concat->mtd.sync = concat_sync; - concat->mtd.lock = concat_lock; - concat->mtd.unlock = concat_unlock; - concat->mtd.suspend = concat_suspend; - concat->mtd.resume = concat_resume; + concat->mtd.erase = concat_erase; + concat->mtd.read = concat_read; + concat->mtd.write = concat_write; + concat->mtd.read_ecc = concat_read_ecc; + concat->mtd.write_ecc = concat_write_ecc; + concat->mtd.read_oob = concat_read_oob; + concat->mtd.write_oob = concat_write_oob; + concat->mtd.sync = concat_sync; + concat->mtd.lock = concat_lock; + concat->mtd.unlock = concat_unlock; + concat->mtd.suspend = concat_suspend; + concat->mtd.resume = concat_resume; /* diff -Nru a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c --- a/drivers/mtd/mtdcore.c Mon Jun 9 23:16:12 2003 +++ b/drivers/mtd/mtdcore.c Mon Jun 9 23:16:12 2003 @@ -1,5 +1,5 @@ /* - * $Id: mtdcore.c,v 1.31 2001/10/02 15:05:11 dwmw2 Exp $ + * $Id: mtdcore.c,v 1.39 2003/05/21 15:15:03 dwmw2 Exp $ * * Core registration and callback routines for MTD * drivers and users. @@ -17,7 +17,7 @@ #include <linux/major.h> #include <linux/fs.h> #include <linux/ioctl.h> -#include <stdarg.h> +#include <linux/init.h> #include <linux/mtd/compatmac.h> #ifdef CONFIG_PROC_FS #include <linux/proc_fs.h> @@ -25,9 +25,15 @@ #include <linux/mtd/mtd.h> -static DECLARE_MUTEX(mtd_table_mutex); -static struct mtd_info *mtd_table[MAX_MTD_DEVICES]; -static struct mtd_notifier *mtd_notifiers = NULL; +/* These are exported solely for the purpose of mtd_blkdevs.c. You + should not use them for _anything_ else */ +DECLARE_MUTEX(mtd_table_mutex); +struct mtd_info *mtd_table[MAX_MTD_DEVICES]; + +EXPORT_SYMBOL_GPL(mtd_table_mutex); +EXPORT_SYMBOL_GPL(mtd_table); + +static LIST_HEAD(mtd_notifiers); /** * add_mtd_device - register an MTD device @@ -45,21 +51,28 @@ down(&mtd_table_mutex); - for (i=0; i< MAX_MTD_DEVICES; i++) - if (!mtd_table[i]) - { - struct mtd_notifier *not=mtd_notifiers; + for (i=0; i < MAX_MTD_DEVICES; i++) + if (!mtd_table[i]) { + struct list_head *this; mtd_table[i] = mtd; mtd->index = i; + mtd->usecount = 0; + DEBUG(0, "mtd: Giving out device %d to %s\n",i, mtd->name); - while (not) - { - (*(not->add))(mtd); - not = not->next; + /* No need to get a refcount on the module containing + the notifier, since we hold the mtd_table_mutex */ + list_for_each(this, &mtd_notifiers) { + struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list); + not->add(mtd); } + up(&mtd_table_mutex); - MOD_INC_USE_COUNT; + /* We _know_ we aren't being removed, because + our caller is still holding us here. So none + of this try_ nonsense, and no bitching about it + either. :) */ + __module_get(THIS_MODULE); return 0; } @@ -79,29 +92,34 @@ int del_mtd_device (struct mtd_info *mtd) { - struct mtd_notifier *not=mtd_notifiers; - int i; + int ret; down(&mtd_table_mutex); - for (i=0; i < MAX_MTD_DEVICES; i++) - { - if (mtd_table[i] == mtd) - { - while (not) - { - (*(not->remove))(mtd); - not = not->next; - } - mtd_table[i] = NULL; - up (&mtd_table_mutex); - MOD_DEC_USE_COUNT; - return 0; + if (mtd_table[mtd->index] != mtd) { + ret = -ENODEV; + } else if (mtd->usecount) { + printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count %d\n", + mtd->index, mtd->name, mtd->usecount); + ret = -EBUSY; + } else { + struct list_head *this; + + /* No need to get a refcount on the module containing + the notifier, since we hold the mtd_table_mutex */ + list_for_each(this, &mtd_notifiers) { + struct mtd_notifier *not = list_entry(this, struct mtd_notifier, list); + not->remove(mtd); } + + mtd_table[mtd->index] = NULL; + + module_put(THIS_MODULE); + ret = 0; } up(&mtd_table_mutex); - return 1; + return ret; } /** @@ -119,10 +137,9 @@ down(&mtd_table_mutex); - new->next = mtd_notifiers; - mtd_notifiers = new; + list_add(&new->list, &mtd_notifiers); - MOD_INC_USE_COUNT; + __module_get(THIS_MODULE); for (i=0; i< MAX_MTD_DEVICES; i++) if (mtd_table[i]) @@ -143,34 +160,24 @@ int unregister_mtd_user (struct mtd_notifier *old) { - struct mtd_notifier **prev = &mtd_notifiers; - struct mtd_notifier *cur; int i; down(&mtd_table_mutex); - while ((cur = *prev)) { - if (cur == old) { - *prev = cur->next; - - MOD_DEC_USE_COUNT; - - for (i=0; i< MAX_MTD_DEVICES; i++) - if (mtd_table[i]) - old->remove(mtd_table[i]); + module_put(THIS_MODULE); + + for (i=0; i< MAX_MTD_DEVICES; i++) + if (mtd_table[i]) + old->remove(mtd_table[i]); - up(&mtd_table_mutex); - return 0; - } - prev = &cur->next; - } + list_del(&old->list); up(&mtd_table_mutex); - return 1; + return 0; } /** - * __get_mtd_device - obtain a validated handle for an MTD device + * get_mtd_device - obtain a validated handle for an MTD device * @mtd: last known address of the required MTD device * @num: internal device number of the required MTD device * @@ -178,11 +185,10 @@ * table, if any. Given an address and num == -1, search the device table * for a device with that address and return if it's still present. Given * both, return the num'th driver only if its address matches. Return NULL - * if not. get_mtd_device() increases the use count, but - * __get_mtd_device() doesn't - you should generally use get_mtd_device(). + * if not. */ -struct mtd_info *__get_mtd_device(struct mtd_info *mtd, int num) +struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num) { struct mtd_info *ret = NULL; int i; @@ -198,16 +204,97 @@ if (mtd && mtd != ret) ret = NULL; } - + + if (ret && !try_module_get(ret->owner)) + ret = NULL; + + if (ret) + ret->usecount++; + up(&mtd_table_mutex); return ret; } +void put_mtd_device(struct mtd_info *mtd) +{ + int c; + + down(&mtd_table_mutex); + c = --mtd->usecount; + up(&mtd_table_mutex); + BUG_ON(c < 0); + + module_put(mtd->owner); +} + +/* default_mtd_writev - default mtd writev method for MTD devices that + * dont implement their own + */ + +int default_mtd_writev(struct mtd_info *mtd, const struct iovec *vecs, + unsigned long count, loff_t to, size_t *retlen) +{ + unsigned long i; + size_t totlen = 0, thislen; + int ret = 0; + + if(!mtd->write) { + ret = -EROFS; + } else { + for (i=0; i<count; i++) { + if (!vecs[i].iov_len) + continue; + ret = mtd->write(mtd, to, vecs[i].iov_len, &thislen, vecs[i].iov_base); + totlen += thislen; + if (ret || thislen != vecs[i].iov_len) + break; + to += vecs[i].iov_len; + } + } + if (retlen) + *retlen = totlen; + return ret; +} + + +/* default_mtd_readv - default mtd readv method for MTD devices that dont + * implement their own + */ + +int default_mtd_readv(struct mtd_info *mtd, struct iovec *vecs, + unsigned long count, loff_t from, size_t *retlen) +{ + unsigned long i; + size_t totlen = 0, thislen; + int ret = 0; + + if(!mtd->read) { + ret = -EIO; + } else { + for (i=0; i<count; i++) { + if (!vecs[i].iov_len) + continue; + ret = mtd->read(mtd, from, vecs[i].iov_len, &thislen, vecs[i].iov_base); + totlen += thislen; + if (ret || thislen != vecs[i].iov_len) + break; + from += vecs[i].iov_len; + } + } + if (retlen) + *retlen = totlen; + return ret; +} + + EXPORT_SYMBOL(add_mtd_device); EXPORT_SYMBOL(del_mtd_device); -EXPORT_SYMBOL(__get_mtd_device); +EXPORT_SYMBOL(get_mtd_device); +EXPORT_SYMBOL(put_mtd_device); EXPORT_SYMBOL(register_mtd_user); EXPORT_SYMBOL(unregister_mtd_user); +EXPORT_SYMBOL(default_mtd_writev); +EXPORT_SYMBOL(default_mtd_readv); /*====================================================================*/ /* Power management code */ @@ -296,7 +383,7 @@ up(&mtd_table_mutex); if (off >= len+begin) return 0; - *start = page + (begin-off); + *start = page + (off-begin); return ((count < begin+len-off) ? count : begin+len-off); } diff -Nru a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c --- a/drivers/mtd/mtdpart.c Mon Jun 9 23:16:16 2003 +++ b/drivers/mtd/mtdpart.c Mon Jun 9 23:16:16 2003 @@ -5,18 +5,22 @@ * * This code is GPL * - * $Id: mtdpart.c,v 1.23 2001/10/02 15:05:11 dwmw2 Exp $ - */ + * $Id: mtdpart.c,v 1.39 2003/05/21 15:15:03 dwmw2 Exp $ + * + * 02-21-2002 Thomas Gleixner <gleixner@autronix.de> + * added support for read_oob, write_oob + */ #include <linux/module.h> #include <linux/types.h> #include <linux/kernel.h> #include <linux/slab.h> #include <linux/list.h> - +#include <linux/config.h> +#include <linux/kmod.h> #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> - +#include <linux/mtd/compatmac.h> /* Our partition linked list */ static LIST_HEAD(mtd_partitions); @@ -28,6 +32,7 @@ u_int32_t offset; int index; struct list_head list; + int registered; }; /* @@ -50,7 +55,72 @@ len = 0; else if (from + len > mtd->size) len = mtd->size - from; - return part->master->read (part->master, from + part->offset, + if (part->master->read_ecc == NULL) + return part->master->read (part->master, from + part->offset, + len, retlen, buf); + else + return part->master->read_ecc (part->master, from + part->offset, + len, retlen, buf, NULL, &mtd->oobinfo); +} + +static int part_point (struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char **buf) +{ + struct mtd_part *part = PART(mtd); + if (from >= mtd->size) + len = 0; + else if (from + len > mtd->size) + len = mtd->size - from; + return part->master->point (part->master, from + part->offset, + len, retlen, buf); +} +static void part_unpoint (struct mtd_info *mtd, u_char *addr, loff_t from, size_t len) +{ + struct mtd_part *part = PART(mtd); + + part->master->unpoint (part->master, addr, from + part->offset, len); +} + + +static int part_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel) +{ + struct mtd_part *part = PART(mtd); + if (oobsel == NULL) + oobsel = &mtd->oobinfo; + if (from >= mtd->size) + len = 0; + else if (from + len > mtd->size) + len = mtd->size - from; + return part->master->read_ecc (part->master, from + part->offset, + len, retlen, buf, eccbuf, oobsel); +} + +static int part_read_oob (struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct mtd_part *part = PART(mtd); + if (from >= mtd->size) + len = 0; + else if (from + len > mtd->size) + len = mtd->size - from; + return part->master->read_oob (part->master, from + part->offset, + len, retlen, buf); +} + +static int part_read_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct mtd_part *part = PART(mtd); + return part->master->read_user_prot_reg (part->master, from, + len, retlen, buf); +} + +static int part_read_fact_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct mtd_part *part = PART(mtd); + return part->master->read_user_prot_reg (part->master, from, len, retlen, buf); } @@ -64,7 +134,51 @@ len = 0; else if (to + len > mtd->size) len = mtd->size - to; - return part->master->write (part->master, to + part->offset, + if (part->master->write_ecc == NULL) + return part->master->write (part->master, to + part->offset, + len, retlen, buf); + else + return part->master->write_ecc (part->master, to + part->offset, + len, retlen, buf, NULL, &mtd->oobinfo); + +} + +static int part_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf, + u_char *eccbuf, struct nand_oobinfo *oobsel) +{ + struct mtd_part *part = PART(mtd); + if (!(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + if (oobsel == NULL) + oobsel = &mtd->oobinfo; + if (to >= mtd->size) + len = 0; + else if (to + len > mtd->size) + len = mtd->size - to; + return part->master->write_ecc (part->master, to + part->offset, + len, retlen, buf, eccbuf, oobsel); +} + +static int part_write_oob (struct mtd_info *mtd, loff_t to, size_t len, + size_t *retlen, const u_char *buf) +{ + struct mtd_part *part = PART(mtd); + if (!(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + if (to >= mtd->size) + len = 0; + else if (to + len > mtd->size) + len = mtd->size - to; + return part->master->write_oob (part->master, to + part->offset, + len, retlen, buf); +} + +static int part_write_user_prot_reg (struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf) +{ + struct mtd_part *part = PART(mtd); + return part->master->write_user_prot_reg (part->master, from, len, retlen, buf); } @@ -74,16 +188,52 @@ struct mtd_part *part = PART(mtd); if (!(mtd->flags & MTD_WRITEABLE)) return -EROFS; - return part->master->writev (part->master, vecs, count, + if (part->master->writev_ecc == NULL) + return part->master->writev (part->master, vecs, count, to + part->offset, retlen); + else + return part->master->writev_ecc (part->master, vecs, count, + to + part->offset, retlen, + NULL, &mtd->oobinfo); } static int part_readv (struct mtd_info *mtd, struct iovec *vecs, unsigned long count, loff_t from, size_t *retlen) { struct mtd_part *part = PART(mtd); - return part->master->readv (part->master, vecs, count, + if (part->master->readv_ecc == NULL) + return part->master->readv (part->master, vecs, count, from + part->offset, retlen); + else + return part->master->readv_ecc (part->master, vecs, count, + from + part->offset, retlen, + NULL, &mtd->oobinfo); +} + +static int part_writev_ecc (struct mtd_info *mtd, const struct iovec *vecs, + unsigned long count, loff_t to, size_t *retlen, + u_char *eccbuf, struct nand_oobinfo *oobsel) +{ + struct mtd_part *part = PART(mtd); + if (!(mtd->flags & MTD_WRITEABLE)) + return -EROFS; + if (oobsel == NULL) + oobsel = &mtd->oobinfo; + return part->master->writev_ecc (part->master, vecs, count, + to + part->offset, retlen, + eccbuf, oobsel); +} + +static int part_readv_ecc (struct mtd_info *mtd, struct iovec *vecs, + unsigned long count, loff_t from, size_t *retlen, + u_char *eccbuf, struct nand_oobinfo *oobsel) +{ + struct mtd_part *part = PART(mtd); + if (oobsel == NULL) + oobsel = &mtd->oobinfo; + return part->master->readv_ecc (part->master, vecs, count, + from + part->offset, retlen, + eccbuf, oobsel); } static int part_erase (struct mtd_info *mtd, struct erase_info *instr) @@ -148,7 +298,8 @@ if (slave->master == master) { struct list_head *prev = node->prev; __list_del(prev, node->next); - del_mtd_device(&slave->mtd); + if(slave->registered) + del_mtd_device(&slave->mtd); kfree(slave); node = prev; } @@ -198,22 +349,44 @@ slave->mtd.name = parts[i].name; slave->mtd.bank_size = master->bank_size; - - slave->mtd.module = master->module; + slave->mtd.owner = master->owner; slave->mtd.read = part_read; slave->mtd.write = part_write; + + if(master->point && master->unpoint){ + slave->mtd.point = part_point; + slave->mtd.unpoint = part_unpoint; + } + + if (master->read_ecc) + slave->mtd.read_ecc = part_read_ecc; + if (master->write_ecc) + slave->mtd.write_ecc = part_write_ecc; + if (master->read_oob) + slave->mtd.read_oob = part_read_oob; + if (master->write_oob) + slave->mtd.write_oob = part_write_oob; + if(master->read_user_prot_reg) + slave->mtd.read_user_prot_reg = part_read_user_prot_reg; + if(master->read_fact_prot_reg) + slave->mtd.read_fact_prot_reg = part_read_fact_prot_reg; + if(master->write_user_prot_reg) + slave->mtd.write_user_prot_reg = part_write_user_prot_reg; if (master->sync) slave->mtd.sync = part_sync; if (!i && master->suspend && master->resume) { slave->mtd.suspend = part_suspend; slave->mtd.resume = part_resume; } - if (master->writev) slave->mtd.writev = part_writev; if (master->readv) slave->mtd.readv = part_readv; + if (master->writev_ecc) + slave->mtd.writev_ecc = part_writev_ecc; + if (master->readv_ecc) + slave->mtd.readv_ecc = part_readv_ecc; if (master->lock) slave->mtd.lock = part_lock; if (master->unlock) @@ -225,6 +398,15 @@ if (slave->offset == MTDPART_OFS_APPEND) slave->offset = cur_offset; + if (slave->offset == MTDPART_OFS_NXTBLK) { + u_int32_t emask = master->erasesize-1; + slave->offset = (cur_offset + emask) & ~emask; + if (slave->offset != cur_offset) { + printk(KERN_NOTICE "Moving partition %d: " + "0x%08x -> 0x%08x\n", i, + cur_offset, slave->offset); + } + } if (slave->mtd.size == MTDPART_SIZ_FULL) slave->mtd.size = master->size - slave->offset; cur_offset = slave->offset + slave->mtd.size; @@ -279,8 +461,17 @@ parts[i].name); } - /* register our partition */ - add_mtd_device(&slave->mtd); + if(parts[i].mtdp) + { /* store the object pointer (caller may or may not register it */ + *parts[i].mtdp = &slave->mtd; + slave->registered = 0; + } + else + { + /* register our partition */ + add_mtd_device(&slave->mtd); + slave->registered = 1; + } } return 0; @@ -289,6 +480,75 @@ EXPORT_SYMBOL(add_mtd_partitions); EXPORT_SYMBOL(del_mtd_partitions); +static spinlock_t part_parser_lock = SPIN_LOCK_UNLOCKED; +static LIST_HEAD(part_parsers); + +struct mtd_part_parser *get_partition_parser(const char *name) +{ + struct list_head *this; + void *ret = NULL; + spin_lock(&part_parser_lock); + + list_for_each(this, &part_parsers) { + struct mtd_part_parser *p = list_entry(this, struct mtd_part_parser, list); + + if (!strcmp(p->name, name) && try_module_get(p->owner)) { + ret = p; + break; + } + } + spin_unlock(&part_parser_lock); + + return ret; +} + +int register_mtd_parser(struct mtd_part_parser *p) +{ + spin_lock(&part_parser_lock); + list_add(&p->list, &part_parsers); + spin_unlock(&part_parser_lock); + + return 0; +} + +int deregister_mtd_parser(struct mtd_part_parser *p) +{ + spin_lock(&part_parser_lock); + list_del(&p->list); + spin_unlock(&part_parser_lock); + return 0; +} + +int parse_mtd_partitions(struct mtd_info *master, const char **types, + struct mtd_partition **pparts, unsigned long origin) +{ + struct mtd_part_parser *parser; + int ret = 0; + + for ( ; ret <= 0 && *types; types++) { + parser = get_partition_parser(*types); +#ifdef CONFIG_KMOD + if (!parser && !request_module("%s", *types)) + parser = get_partition_parser(*types); +#endif + if (!parser) { + printk(KERN_NOTICE "%s partition parsing not available\n", + *types); + continue; + } + ret = (*parser->parse_fn)(master, pparts, origin); + if (ret > 0) { + printk(KERN_NOTICE "%d %s partitions found on MTD device %s\n", + ret, parser->name, master->name); + } + put_partition_parser(parser); + } + return ret; +} + +EXPORT_SYMBOL_GPL(parse_mtd_partitions); +EXPORT_SYMBOL_GPL(register_mtd_parser); +EXPORT_SYMBOL_GPL(deregister_mtd_parser); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Nicolas Pitre <nico@cam.org>"); diff -Nru a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig --- a/drivers/mtd/nand/Kconfig Mon Jun 9 23:16:16 2003 +++ b/drivers/mtd/nand/Kconfig Mon Jun 9 23:16:16 2003 @@ -1,5 +1,5 @@ -# drivers/mtd/nand/Config.in -# $Id: Config.in,v 1.4 2001/09/19 09:35:23 dwmw2 Exp $ +# drivers/mtd/nand/Kconfig +# $Id: Kconfig,v 1.4 2003/05/28 10:04:23 dwmw2 Exp $ menu "NAND Flash Device Drivers" depends on MTD!=n @@ -9,16 +9,8 @@ depends on MTD help This enables support for accessing all type of NAND flash - devices. - -config MTD_NAND_ECC - bool "Enable ECC correction algorithm" - depends on MTD_NAND - help - This enables software-based ECC for use with NAND flash chips. It - can detect and correct 1 bit errors per 256 byte blocks. This - should be used to increase the reliability of the data stored and - read on the device. + devices with an 8-bit data bus interface. For further + information see www.linux-mtd.infradead.org/tech/nand.html. config MTD_NAND_VERIFY_WRITE bool "Verify NAND page writes" @@ -28,8 +20,21 @@ NAND flash device internally checks only bits transitioning from 1 to 0. There is a rare possibility that even though the device thinks the write was successful, a bit could have been - flipped accidentaly due to device wear, gamma rays, whatever. - Enable this if you are really paranoid. + flipped accidentaly due to device wear or something else. + +config MTD_NAND_AUTCPU12 + tristate "SmartMediaCard on autronix autcpu12 board" + depends on ARM && MTD_NAND && ARCH_AUTCPU12 + help + This enables the driver for the autronix autcpu12 board to + access the SmartMediaCard. + +config MTD_NAND_EDB7312 + tristate "Support for Cirrus Logic EBD7312 evaluation board" + depends on ARM && MTD_NAND && ARCH_EDB7312 + help + This enables the driver for the Cirrus Logic EBD7312 evaluation + board to access the onboard NAND Flash. config MTD_NAND_SPIA tristate "NAND Flash device on SPIA board" @@ -37,5 +42,10 @@ help If you had to ask, you don't have one. Say 'N'. +config MTD_NAND_IDS + tristate + default y if MTD_NAND = y || MTD_DOC2000 = y || MTD_DOC2001 = y || MTD_DOC2001PLUS = y + default m if MTD_NAND = m || MTD_DOC2000 = m || MTD_DOC2001 = m || MTD_DOC2001PLUS = m + endmenu diff -Nru a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile --- a/drivers/mtd/nand/Makefile Mon Jun 9 23:16:05 2003 +++ b/drivers/mtd/nand/Makefile Mon Jun 9 23:16:05 2003 @@ -1,10 +1,10 @@ # # linux/drivers/nand/Makefile # -# $Id: Makefile,v 1.5 2001/09/19 22:39:59 dwmw2 Exp $ +# $Id: Makefile.common,v 1.2 2003/05/28 11:38:54 dwmw2 Exp $ -nandobjs-y := nand.o -nandobjs-$(CONFIG_MTD_NAND_ECC) += nand_ecc.o - -obj-$(CONFIG_MTD_NAND) += $(nandobjs-y) +obj-$(CONFIG_MTD_NAND) += nand.o nand_ecc.o obj-$(CONFIG_MTD_NAND_SPIA) += spia.o +obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o +obj-$(CONFIG_MTD_NAND_EDB7312) += edb7312.o +obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o diff -Nru a/drivers/mtd/nand/autcpu12.c b/drivers/mtd/nand/autcpu12.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/nand/autcpu12.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,254 @@ +/* + * drivers/mtd/autcpu12.c + * + * Copyright (c) 2002 Thomas Gleixner <tgxl@linutronix.de> + * + * Derived from drivers/mtd/spia.c + * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) + * + * $Id: autcpu12.c,v 1.10 2003/04/20 07:24:40 gleixner Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Overview: + * This is a device driver for the NAND flash device found on the + * autronix autcpu12 board, which is a SmartMediaCard. It supports + * 16MB, 32MB and 64MB cards. + * + * + * 02-12-2002 TG Cleanup of module params + * + * 02-20-2002 TG adjusted for different rd/wr adress support + * added support for read device ready/busy line + * added page_cache + * + * 10-06-2002 TG 128K card support added + */ + +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/partitions.h> +#include <asm/io.h> +#include <asm/arch/hardware.h> +#include <asm/sizes.h> +#include <asm/arch/autcpu12.h> + +/* + * MTD structure for AUTCPU12 board + */ +static struct mtd_info *autcpu12_mtd = NULL; + +/* + * Module stuff + */ +#if LINUX_VERSION_CODE < 0x20212 && defined(MODULE) +#define autcpu12_init init_module +#define autcpu12_cleanup cleanup_module +#endif + +static int autcpu12_io_base = CS89712_VIRT_BASE; +static int autcpu12_fio_pbase = AUTCPU12_PHYS_SMC; +static int autcpu12_fio_ctrl = AUTCPU12_SMC_SELECT_OFFSET; +static int autcpu12_pedr = AUTCPU12_SMC_PORT_OFFSET; +static int autcpu12_fio_base; + +#ifdef MODULE +MODULE_PARM(autcpu12_fio_pbase, "i"); +MODULE_PARM(autcpu12_fio_ctrl, "i"); +MODULE_PARM(autcpu12_pedr, "i"); + +__setup("autcpu12_fio_pbase=",autcpu12_fio_pbase); +__setup("autcpu12_fio_ctrl=",autcpu12_fio_ctrl); +__setup("autcpu12_pedr=",autcpu12_pedr); +#endif + +/* + * Define partitions for flash devices + */ +extern struct nand_oobinfo jffs2_oobinfo; + +static struct mtd_partition partition_info16k[] = { + { name: "AUTCPU12 flash partition 1", + offset: 0, + size: 8 * SZ_1M }, + { name: "AUTCPU12 flash partition 2", + offset: 8 * SZ_1M, + size: 8 * SZ_1M }, +}; + +static struct mtd_partition partition_info32k[] = { + { name: "AUTCPU12 flash partition 1", + offset: 0, + size: 8 * SZ_1M }, + { name: "AUTCPU12 flash partition 2", + offset: 8 * SZ_1M, + size: 24 * SZ_1M }, +}; + +static struct mtd_partition partition_info64k[] = { + { name: "AUTCPU12 flash partition 1", + offset: 0, + size: 16 * SZ_1M }, + { name: "AUTCPU12 flash partition 2", + offset: 16 * SZ_1M, + size: 48 * SZ_1M }, +}; + +static struct mtd_partition partition_info128k[] = { + { name: "AUTCPU12 flash partition 1", + offset: 0, + size: 16 * SZ_1M }, + { name: "AUTCPU12 flash partition 2", + offset: 16 * SZ_1M, + size: 112 * SZ_1M }, +}; + +#define NUM_PARTITIONS16K 2 +#define NUM_PARTITIONS32K 2 +#define NUM_PARTITIONS64K 2 +#define NUM_PARTITIONS128K 2 +/* + * hardware specific access to control-lines +*/ +void autcpu12_hwcontrol(int cmd) +{ + + switch(cmd){ + + case NAND_CTL_SETCLE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) |= AUTCPU12_SMC_CLE; break; + case NAND_CTL_CLRCLE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) &= ~AUTCPU12_SMC_CLE; break; + + case NAND_CTL_SETALE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) |= AUTCPU12_SMC_ALE; break; + case NAND_CTL_CLRALE: (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) &= ~AUTCPU12_SMC_ALE; break; + + case NAND_CTL_SETNCE: (*(volatile unsigned char *) (autcpu12_fio_base + autcpu12_fio_ctrl)) = 0x01; break; + case NAND_CTL_CLRNCE: (*(volatile unsigned char *) (autcpu12_fio_base + autcpu12_fio_ctrl)) = 0x00; break; + } +} + +/* +* read device ready pin +*/ +int autcpu12_device_ready(void) +{ + + return ( (*(volatile unsigned char *) (autcpu12_io_base + autcpu12_pedr)) & AUTCPU12_SMC_RDY) ? 1 : 0; + +} +/* + * Main initialization routine + */ +int __init autcpu12_init (void) +{ + struct nand_chip *this; + int err = 0; + + /* Allocate memory for MTD device structure and private data */ + autcpu12_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip), + GFP_KERNEL); + if (!autcpu12_mtd) { + printk ("Unable to allocate AUTCPU12 NAND MTD device structure.\n"); + err = -ENOMEM; + goto out; + } + + /* map physical adress */ + autcpu12_fio_base=(unsigned long)ioremap(autcpu12_fio_pbase,SZ_1K); + if(!autcpu12_fio_base){ + printk("Ioremap autcpu12 SmartMedia Card failed\n"); + err = -EIO; + goto out_mtd; + } + + /* Get pointer to private data */ + this = (struct nand_chip *) (&autcpu12_mtd[1]); + + /* Initialize structures */ + memset((char *) autcpu12_mtd, 0, sizeof(struct mtd_info)); + memset((char *) this, 0, sizeof(struct nand_chip)); + + /* Link the private data with the MTD structure */ + autcpu12_mtd->priv = this; + + /* Set address of NAND IO lines */ + this->IO_ADDR_R = autcpu12_fio_base; + this->IO_ADDR_W = autcpu12_fio_base; + this->hwcontrol = autcpu12_hwcontrol; + this->dev_ready = autcpu12_device_ready; + /* 20 us command delay time */ + this->chip_delay = 20; + this->eccmode = NAND_ECC_SOFT; + + /* Scan to find existance of the device */ + if (nand_scan (autcpu12_mtd)) { + err = -ENXIO; + goto out_ior; + } + + /* Allocate memory for internal data buffer */ + this->data_buf = kmalloc (sizeof(u_char) * (autcpu12_mtd->oobblock + autcpu12_mtd->oobsize), GFP_KERNEL); + if (!this->data_buf) { + printk ("Unable to allocate NAND data buffer for AUTCPU12.\n"); + err = -ENOMEM; + goto out_ior; + } + + /* Register the partitions */ + switch(autcpu12_mtd->size){ + case SZ_16M: add_mtd_partitions(autcpu12_mtd, partition_info16k, NUM_PARTITIONS16K); break; + case SZ_32M: add_mtd_partitions(autcpu12_mtd, partition_info32k, NUM_PARTITIONS32K); break; + case SZ_64M: add_mtd_partitions(autcpu12_mtd, partition_info64k, NUM_PARTITIONS64K); break; + case SZ_128M: add_mtd_partitions(autcpu12_mtd, partition_info128k, NUM_PARTITIONS128K); break; + default: { + printk ("Unsupported SmartMedia device\n"); + err = -ENXIO; + goto out_buf; + } + } + goto out; + +out_buf: + kfree (this->data_buf); +out_ior: + iounmap((void *)autcpu12_fio_base); +out_mtd: + kfree (autcpu12_mtd); +out: + return err; +} + +module_init(autcpu12_init); + +/* + * Clean up routine + */ +#ifdef MODULE +static void __exit autcpu12_cleanup (void) +{ + struct nand_chip *this = (struct nand_chip *) &autcpu12_mtd[1]; + + /* Unregister partitions */ + del_mtd_partitions(autcpu12_mtd); + + /* Unregister the device */ + del_mtd_device (autcpu12_mtd); + + /* Free internal data buffers */ + kfree (this->data_buf); + + /* unmap physical adress */ + iounmap((void *)autcpu12_fio_base); + + /* Free the MTD device structure */ + kfree (autcpu12_mtd); +} +module_exit(autcpu12_cleanup); +#endif + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>"); +MODULE_DESCRIPTION("Glue layer for SmartMediaCard on autronix autcpu12"); diff -Nru a/drivers/mtd/nand/edb7312.c b/drivers/mtd/nand/edb7312.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/nand/edb7312.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,233 @@ +/* + * drivers/mtd/nand/edb7312.c + * + * Copyright (C) 2002 Marius Gröger (mag@sysgo.de) + * + * Derived from drivers/mtd/nand/autcpu12.c + * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) + * + * $Id: edb7312.c,v 1.5 2003/04/20 07:24:40 gleixner Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Overview: + * This is a device driver for the NAND flash device found on the + * CLEP7312 board which utilizes the Toshiba TC58V64AFT part. This is + * a 64Mibit (8MiB x 8 bits) NAND flash device. + */ + +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/partitions.h> +#include <asm/io.h> +#include <asm/arch/hardware.h> /* for CLPS7111_VIRT_BASE */ +#include <asm/sizes.h> +#include <asm/hardware/clps7111.h> + +/* + * MTD structure for EDB7312 board + */ +static struct mtd_info *ep7312_mtd = NULL; + +/* + * Values specific to the EDB7312 board (used with EP7312 processor) + */ +#define EP7312_FIO_PBASE 0x10000000 /* Phys address of flash */ +#define EP7312_PXDR 0x0001 /* + * IO offset to Port B data register + * where the CLE, ALE and NCE pins + * are wired to. + */ +#define EP7312_PXDDR 0x0041 /* + * IO offset to Port B data direction + * register so we can control the IO + * lines. + */ + +/* + * Module stuff + */ + +static int ep7312_fio_pbase = EP7312_FIO_PBASE; +static int ep7312_pxdr = EP7312_PXDR; +static int ep7312_pxddr = EP7312_PXDDR; + +#ifdef MODULE +MODULE_PARM(ep7312_fio_pbase, "i"); +MODULE_PARM(ep7312_pxdr, "i"); +MODULE_PARM(ep7312_pxddr, "i"); + +__setup("ep7312_fio_pbase=",ep7312_fio_pbase); +__setup("ep7312_pxdr=",ep7312_pxdr); +__setup("ep7312_pxddr=",ep7312_pxddr); +#endif + +#ifdef CONFIG_MTD_PARTITIONS +/* + * Define static partitions for flash device + */ +static struct mtd_partition partition_info[] = { + { name: "EP7312 Nand Flash", + offset: 0, + size: 8*1024*1024 } +}; +#define NUM_PARTITIONS 1 + +#endif + + +/* + * hardware specific access to control-lines + */ +static void ep7312_hwcontrol(int cmd) +{ + switch(cmd) { + + case NAND_CTL_SETCLE: + clps_writeb(clps_readb(ep7312_pxdr) | 0x10, ep7312_pxdr); + break; + case NAND_CTL_CLRCLE: + clps_writeb(clps_readb(ep7312_pxdr) & ~0x10, ep7312_pxdr); + break; + + case NAND_CTL_SETALE: + clps_writeb(clps_readb(ep7312_pxdr) | 0x20, ep7312_pxdr); + break; + case NAND_CTL_CLRALE: + clps_writeb(clps_readb(ep7312_pxdr) & ~0x20, ep7312_pxdr); + break; + + case NAND_CTL_SETNCE: + clps_writeb((clps_readb(ep7312_pxdr) | 0x80) & ~0x40, ep7312_pxdr); + break; + case NAND_CTL_CLRNCE: + clps_writeb((clps_readb(ep7312_pxdr) | 0x80) | 0x40, ep7312_pxdr); + break; + } +} + +/* + * read device ready pin + */ +static int ep7312_device_ready(void) +{ + return 1; +} + +/* + * Main initialization routine + */ +static int __init ep7312_init (void) +{ + struct nand_chip *this; + const char *part_type = 0; + int mtd_parts_nb = 0; + struct mtd_partition *mtd_parts = 0; + int ep7312_fio_base; + + /* Allocate memory for MTD device structure and private data */ + ep7312_mtd = kmalloc(sizeof(struct mtd_info) + + sizeof(struct nand_chip), + GFP_KERNEL); + if (!ep7312_mtd) { + printk("Unable to allocate EDB7312 NAND MTD device structure.\n"); + return -ENOMEM; + } + + /* map physical adress */ + ep7312_fio_base = (unsigned long)ioremap(ep7312_fio_pbase, SZ_1K); + if(!ep7312_fio_base) { + printk("ioremap EDB7312 NAND flash failed\n"); + kfree(ep7312_mtd); + return -EIO; + } + + /* Get pointer to private data */ + this = (struct nand_chip *) (&ep7312_mtd[1]); + + /* Initialize structures */ + memset((char *) ep7312_mtd, 0, sizeof(struct mtd_info)); + memset((char *) this, 0, sizeof(struct nand_chip)); + + /* Link the private data with the MTD structure */ + ep7312_mtd->priv = this; + + /* + * Set GPIO Port B control register so that the pins are configured + * to be outputs for controlling the NAND flash. + */ + clps_writeb(0xf0, ep7312_pxddr); + + /* insert callbacks */ + this->IO_ADDR_R = ep7312_fio_base; + this->IO_ADDR_W = ep7312_fio_base; + this->hwcontrol = ep7312_hwcontrol; + this->dev_ready = ep7312_device_ready; + /* 15 us command delay time */ + this->chip_delay = 15; + + /* Scan to find existence of the device */ + if (nand_scan (ep7312_mtd)) { + iounmap((void *)ep7312_fio_base); + kfree (ep7312_mtd); + return -ENXIO; + } + + /* Allocate memory for internal data buffer */ + this->data_buf = kmalloc (sizeof(u_char) * (ep7312_mtd->oobblock + ep7312_mtd->oobsize), GFP_KERNEL); + if (!this->data_buf) { + printk("Unable to allocate NAND data buffer for EDB7312.\n"); + iounmap((void *)ep7312_fio_base); + kfree (ep7312_mtd); + return -ENOMEM; + } + +#ifdef CONFIG_MTD_CMDLINE_PARTS + mtd_parts_nb = parse_cmdline_partitions(ep7312_mtd, &mtd_parts, + "edb7312-nand"); + if (mtd_parts_nb > 0) + part_type = "command line"; + else + mtd_parts_nb = 0; +#endif + if (mtd_parts_nb == 0) + { + mtd_parts = partition_info; + mtd_parts_nb = NUM_PARTITIONS; + part_type = "static"; + } + + /* Register the partitions */ + printk(KERN_NOTICE "Using %s partition definition\n", part_type); + add_mtd_partitions(ep7312_mtd, mtd_parts, mtd_parts_nb); + + /* Return happy */ + return 0; +} +module_init(ep7312_init); + +/* + * Clean up routine + */ +static void __exit ep7312_cleanup (void) +{ + struct nand_chip *this = (struct nand_chip *) &ep7312_mtd[1]; + + /* Unregister the device */ + del_mtd_device (ep7312_mtd); + + /* Free internal data buffer */ + kfree (this->data_buf); + + /* Free the MTD device structure */ + kfree (ep7312_mtd); +} +module_exit(ep7312_cleanup); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Marius Groeger <mag@sysgo.de>"); +MODULE_DESCRIPTION("MTD map driver for Cogent EDB7312 board"); diff -Nru a/drivers/mtd/nand/nand.c b/drivers/mtd/nand/nand.c --- a/drivers/mtd/nand/nand.c Mon Jun 9 23:16:20 2003 +++ b/drivers/mtd/nand/nand.c Mon Jun 9 23:16:20 2003 @@ -1,17 +1,137 @@ /* * drivers/mtd/nand.c * - * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) + * Overview: + * This is the generic MTD driver for NAND flash devices. It should be + * capable of working with almost all NAND chips currently available. + * + * Additional technical information is available on + * http://www.linux-mtd.infradead.org/tech/nand.html + * + * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) + * 2002 Thomas Gleixner (tglx@linutronix.de) + * + * 10-29-2001 Thomas Gleixner (tglx@linutronix.de) + * - Changed nand_chip structure for controlline function to + * support different hardware structures (Access to + * controllines ALE,CLE,NCE via hardware specific function. + * - exit out of "failed erase block" changed, to avoid + * driver hangup + * - init_waitqueue_head added in function nand_scan !! + * + * 01-30-2002 Thomas Gleixner (tglx@linutronix.de) + * change in nand_writev to block invalid vecs entries + * + * 02-11-2002 Thomas Gleixner (tglx@linutronix.de) + * - major rewrite to avoid duplicated code + * common nand_write_page function + * common get_chip function + * - added oob_config structure for out of band layouts + * - write_oob changed for partial programming + * - read cache for faster access for subsequent reads + * from the same page. + * - support for different read/write address + * - support for device ready/busy line + * - read oob for more than one page enabled + * + * 02-27-2002 Thomas Gleixner (tglx@linutronix.de) + * - command-delay can be programmed + * - fixed exit from erase with callback-function enabled + * + * 03-21-2002 Thomas Gleixner (tglx@linutronix.de) + * - DEBUG improvements provided by Elizabeth Clarke + * (eclarke@aminocom.com) + * - added zero check for this->chip_delay + * + * 04-03-2002 Thomas Gleixner (tglx@linutronix.de) + * - added added hw-driver supplied command and wait functions + * - changed blocking for erase (erase suspend enabled) + * - check pointers before accessing flash provided by + * John Hall (john.hall@optionexist.co.uk) + * + * 04-09-2002 Thomas Gleixner (tglx@linutronix.de) + * - nand_wait repaired + * + * 04-28-2002 Thomas Gleixner (tglx@linutronix.de) + * - OOB config defines moved to nand.h + * + * 08-01-2002 Thomas Gleixner (tglx@linutronix.de) + * - changed my mailaddress, added pointer to tech/nand.html + * + * 08-07-2002 Thomas Gleixner (tglx@linutronix.de) + * forced bad block location to byte 5 of OOB, even if + * CONFIG_MTD_NAND_ECC_JFFS2 is not set, to prevent + * erase /dev/mtdX from erasing bad blocks and destroying + * bad block info + * + * 08-10-2002 Thomas Gleixner (tglx@linutronix.de) + * Fixed writing tail of data. Thanks to Alice Hennessy + * <ahennessy@mvista.com>. * - * $Id: nand.c,v 1.12 2001/10/02 15:05:14 dwmw2 Exp $ + * 08-10-2002 Thomas Gleixner (tglx@linutronix.de) + * nand_read_ecc and nand_write_page restructured to support + * hardware ECC. Thanks to Steven Hein (ssh@sgi.com) + * for basic implementation and suggestions. + * 3 new pointers in nand_chip structure: + * calculate_ecc, correct_data, enabled_hwecc + * forcing all hw-drivers to support page cache + * eccvalid_pos is now mandatory + * + * 08-17-2002 tglx: fixed signed/unsigned missmatch in write.c + * Thanks to Ken Offer <koffer@arlut.utexas.edu> + * + * 08-29-2002 tglx: use buffered read/write only for non pagealigned + * access, speed up the aligned path by using the fs-buffer + * reset chip removed from nand_select(), implicit done + * only, when erase is interrupted + * waitfuntion use yield, instead of schedule_timeout + * support for 6byte/512byte hardware ECC + * read_ecc, write_ecc extended for different oob-layout + * selections: Implemented NAND_NONE_OOB, NAND_JFFS2_OOB, + * NAND_YAFFS_OOB. fs-driver gives one of these constants + * to select the oob-layout fitting the filesystem. + * oobdata can be read together with the raw data, when + * the fs-driver supplies a big enough buffer. + * size = 12 * number of pages to read (256B pagesize) + * 24 * number of pages to read (512B pagesize) + * the buffer contains 8/16 byte oobdata and 4/8 byte + * returncode from calculate_ecc + * oobdata can be given from filesystem to program them + * in one go together with the raw data. ECC codes are + * filled in at the place selected by oobsel. + * + * 09-04-2002 tglx: fixed write_verify (John Hall (john.hall@optionexist.co.uk)) + * + * 11-11-2002 tglx: fixed debug output in nand_write_page + * (John Hall (john.hall@optionexist.co.uk)) + * + * 11-25-2002 tglx: Moved device ID/ manufacturer ID from nand_ids.h + * Splitted device ID and manufacturer ID table. + * Removed CONFIG_MTD_NAND_ECC, as it defaults to ECC_NONE for + * mtd->read / mtd->write and is controllable by the fs driver + * for mtd->read_ecc / mtd->write_ecc + * some minor cleanups + * + * 12-05-2002 tglx: Dave Ellis (DGE@sixnetio) provided the fix for + * WRITE_VERIFY long time ago. Thanks for remembering me. + * + * 02-14-2003 tglx: Reject non page aligned writes + * Fixed ecc select in nand_write_page to match semantics. + * + * 02-18-2003 tglx: Changed oobsel to pointer. Added a default oob-selector + * + * 02-18-2003 tglx: Implemented oobsel again. Now it uses a pointer to + + a structure, which will be supplied by a filesystem driver + * If NULL is given, then the defaults (none or defaults + * supplied by ioctl (MEMSETOOBSEL) are used. + * For partitions the partition defaults are used (mtdpart.c) + * + * $Id: nand.c,v 1.45 2003/05/20 21:01:30 dwmw2 Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * Overview: - * This is the generic MTD driver for NAND flash devices. It should be - * capable of working with almost all NAND chips currently available. */ #include <linux/delay.h> @@ -20,178 +140,426 @@ #include <linux/types.h> #include <linux/mtd/mtd.h> #include <linux/mtd/nand.h> -#include <linux/mtd/nand_ids.h> +#include <linux/mtd/nand_ecc.h> #include <linux/interrupt.h> #include <asm/io.h> -#ifdef CONFIG_MTD_NAND_ECC -#include <linux/mtd/nand_ecc.h> -#endif - /* * Macros for low-level register control */ -#define NAND_CTRL (*(volatile unsigned char *) \ - ((struct nand_chip *) mtd->priv)->CTRL_ADDR) -#define nand_select() NAND_CTRL &= ~this->NCE; \ - nand_command(mtd, NAND_CMD_RESET, -1, -1); \ - udelay (10); -#define nand_deselect() NAND_CTRL |= ~this->NCE; +#define nand_select() this->hwcontrol(NAND_CTL_SETNCE); +#define nand_deselect() this->hwcontrol(NAND_CTL_CLRNCE); /* * NAND low-level MTD interface functions */ -static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf); +static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf); static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf, u_char *ecc_code); -static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf); -static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf); + size_t * retlen, u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel); +static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf); +static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf); static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf, - u_char *ecc_code); -static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf); + size_t * retlen, const u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel); +static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char *buf); static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs, - unsigned long count, loff_t to, size_t *retlen); + unsigned long count, loff_t to, size_t * retlen); +static int nand_writev_ecc (struct mtd_info *mtd, const struct iovec *vecs, + unsigned long count, loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel); static int nand_erase (struct mtd_info *mtd, struct erase_info *instr); static void nand_sync (struct mtd_info *mtd); +static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf, struct nand_oobinfo *oobsel); + /* * Send command to NAND device */ -static void nand_command (struct mtd_info *mtd, unsigned command, - int column, int page_addr) +static void nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr) { register struct nand_chip *this = mtd->priv; - register unsigned long NAND_IO_ADDR = this->IO_ADDR; + register unsigned long NAND_IO_ADDR = this->IO_ADDR_W; /* Begin command latch cycle */ - NAND_CTRL |= this->CLE; - + this->hwcontrol (NAND_CTL_SETCLE); /* * Write out the command to the device. */ - if (command != NAND_CMD_SEQIN) + if (command != NAND_CMD_SEQIN) writeb (command, NAND_IO_ADDR); else { if (mtd->oobblock == 256 && column >= 256) { column -= 256; - writeb(NAND_CMD_RESET, NAND_IO_ADDR); - writeb(NAND_CMD_READOOB, NAND_IO_ADDR); - writeb(NAND_CMD_SEQIN, NAND_IO_ADDR); - } - else if (mtd->oobblock == 512 && column >= 256) { + writeb (NAND_CMD_READOOB, NAND_IO_ADDR); + writeb (NAND_CMD_SEQIN, NAND_IO_ADDR); + } else if (mtd->oobblock == 512 && column >= 256) { if (column < 512) { column -= 256; - writeb(NAND_CMD_READ1, NAND_IO_ADDR); - writeb(NAND_CMD_SEQIN, NAND_IO_ADDR); - } - else { + writeb (NAND_CMD_READ1, NAND_IO_ADDR); + writeb (NAND_CMD_SEQIN, NAND_IO_ADDR); + } else { column -= 512; - writeb(NAND_CMD_READOOB, NAND_IO_ADDR); - writeb(NAND_CMD_SEQIN, NAND_IO_ADDR); + writeb (NAND_CMD_READOOB, NAND_IO_ADDR); + writeb (NAND_CMD_SEQIN, NAND_IO_ADDR); } - } - else { - writeb(NAND_CMD_READ0, NAND_IO_ADDR); - writeb(NAND_CMD_SEQIN, NAND_IO_ADDR); + } else { + writeb (NAND_CMD_READ0, NAND_IO_ADDR); + writeb (NAND_CMD_SEQIN, NAND_IO_ADDR); } } /* Set ALE and clear CLE to start address cycle */ - NAND_CTRL &= ~this->CLE; - NAND_CTRL |= this->ALE; + this->hwcontrol (NAND_CTL_CLRCLE); + + if (column != -1 || page_addr != -1) { + this->hwcontrol (NAND_CTL_SETALE); - /* Serially input address */ - if (column != -1) - writeb (column, NAND_IO_ADDR); - if (page_addr != -1) { - writeb ((unsigned char) (page_addr & 0xff), NAND_IO_ADDR); - writeb ((unsigned char) ((page_addr >> 8) & 0xff), NAND_IO_ADDR); - /* One more address cycle for higher density devices */ - if (mtd->size & 0x0c000000) { - writeb ((unsigned char) ((page_addr >> 16) & 0x0f), - NAND_IO_ADDR); + /* Serially input address */ + if (column != -1) + writeb (column, NAND_IO_ADDR); + if (page_addr != -1) { + writeb ((unsigned char) (page_addr & 0xff), NAND_IO_ADDR); + writeb ((unsigned char) ((page_addr >> 8) & 0xff), NAND_IO_ADDR); + /* One more address cycle for higher density devices */ + if (mtd->size & 0x0c000000) + writeb ((unsigned char) ((page_addr >> 16) & 0x0f), NAND_IO_ADDR); } + /* Latch in address */ + this->hwcontrol (NAND_CTL_CLRALE); } + + /* + * program and erase have their own busy handlers + * status and sequential in needs no delay + */ + switch (command) { + + case NAND_CMD_PAGEPROG: + case NAND_CMD_ERASE1: + case NAND_CMD_ERASE2: + case NAND_CMD_SEQIN: + case NAND_CMD_STATUS: + return; - /* Latch in address */ - NAND_CTRL &= ~this->ALE; + case NAND_CMD_RESET: + if (this->dev_ready) + break; + this->hwcontrol (NAND_CTL_SETCLE); + writeb (NAND_CMD_STATUS, NAND_IO_ADDR); + this->hwcontrol (NAND_CTL_CLRCLE); + while ( !(readb (this->IO_ADDR_R) & 0x40)); + return; - /* Pause for 15us */ - udelay (15); + /* This applies to read commands */ + default: + /* + * If we don't have access to the busy pin, we apply the given + * command delay + */ + if (!this->dev_ready) { + udelay (this->chip_delay); + return; + } + } + + /* wait until command is processed */ + while (!this->dev_ready()); } /* - * NAND read + * Get chip for selected access */ -static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf) +static inline void nand_get_chip (struct nand_chip *this, struct mtd_info *mtd, int new_state, int *erase_state) { -#ifdef CONFIG_MTD_NAND_ECC - struct nand_chip *this = mtd->priv; + + DECLARE_WAITQUEUE (wait, current); + + /* + * Grab the lock and see if the device is available + * For erasing, we keep the spinlock until the + * erase command is written. + */ +retry: + spin_lock_bh (&this->chip_lock); + + if (this->state == FL_READY) { + this->state = new_state; + if (new_state != FL_ERASING) + spin_unlock_bh (&this->chip_lock); + return; + } + + if (this->state == FL_ERASING) { + if (new_state != FL_ERASING) { + this->state = new_state; + spin_unlock_bh (&this->chip_lock); + nand_select (); /* select in any case */ + this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1); + return; + } + } + + set_current_state (TASK_UNINTERRUPTIBLE); + add_wait_queue (&this->wq, &wait); + spin_unlock_bh (&this->chip_lock); + schedule (); + remove_wait_queue (&this->wq, &wait); + goto retry; +} + +/* + * Wait for command done. This applies to erase and program only + * Erase can take up to 400ms and program up to 20ms according to + * general NAND and SmartMedia specs + * +*/ +static int nand_wait(struct mtd_info *mtd, struct nand_chip *this, int state) +{ + + unsigned long timeo = jiffies; + int status; + + if (state == FL_ERASING) + timeo += (HZ * 400) / 1000; + else + timeo += (HZ * 20) / 1000; + + spin_lock_bh (&this->chip_lock); + this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); + + while (time_before(jiffies, timeo)) { + /* Check, if we were interrupted */ + if (this->state != state) { + spin_unlock_bh (&this->chip_lock); + return 0; + } + if (this->dev_ready) { + if (this->dev_ready ()) + break; + } + if (readb (this->IO_ADDR_R) & 0x40) + break; + + spin_unlock_bh (&this->chip_lock); + yield (); + spin_lock_bh (&this->chip_lock); + } + status = (int) readb (this->IO_ADDR_R); + spin_unlock_bh (&this->chip_lock); + + return status; +} + +/* + * Nand_page_program function is used for write and writev ! + * This function will always program a full page of data + * If you call it with a non page aligned buffer, you're lost :) + */ +static int nand_write_page (struct mtd_info *mtd, struct nand_chip *this, int page, u_char *oob_buf, struct nand_oobinfo *oobsel) +{ + int i, status; + u_char ecc_code[6], *oob_data; + int eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE; + int *oob_config = oobsel->eccpos; - return nand_read_ecc (mtd, from, len, retlen, buf, this->ecc_code_buf); -#else - return nand_read_ecc (mtd, from, len, retlen, buf, NULL); + /* pad oob area, if we have no oob buffer from fs-driver */ + if (!oob_buf) { + oob_data = &this->data_buf[mtd->oobblock]; + for (i = 0; i < mtd->oobsize; i++) + oob_data[i] = 0xff; + } else + oob_data = oob_buf; + + /* Send command to begin auto page programming */ + this->cmdfunc (mtd, NAND_CMD_SEQIN, 0x00, page); + + /* Write out complete page of data, take care of eccmode */ + switch (eccmode) { + /* No ecc and software ecc 3/256, write all */ + case NAND_ECC_NONE: + printk (KERN_WARNING "Writing data without ECC to NAND-FLASH is not recommended\n"); + for (i = 0; i < mtd->oobblock; i++) + writeb ( this->data_poi[i] , this->IO_ADDR_W); + break; + case NAND_ECC_SOFT: + this->calculate_ecc (&this->data_poi[0], &(ecc_code[0])); + for (i = 0; i < 3; i++) + oob_data[oob_config[i]] = ecc_code[i]; + /* Calculate and write the second ECC for 512 Byte page size */ + if (mtd->oobblock == 512) { + this->calculate_ecc (&this->data_poi[256], &(ecc_code[3])); + for (i = 3; i < 6; i++) + oob_data[oob_config[i]] = ecc_code[i]; + } + for (i = 0; i < mtd->oobblock; i++) + writeb ( this->data_poi[i] , this->IO_ADDR_W); + break; + + /* Hardware ecc 3 byte / 256 data, write first half, get ecc, then second, if 512 byte pagesize */ + case NAND_ECC_HW3_256: + this->enable_hwecc (NAND_ECC_WRITE); /* enable hardware ecc logic for write */ + for (i = 0; i < mtd->eccsize; i++) + writeb ( this->data_poi[i] , this->IO_ADDR_W); + + this->calculate_ecc (NULL, &(ecc_code[0])); + for (i = 0; i < 3; i++) + oob_data[oob_config[i]] = ecc_code[i]; + + if (mtd->oobblock == 512) { + this->enable_hwecc (NAND_ECC_WRITE); /* enable hardware ecc logic for write*/ + for (i = mtd->eccsize; i < mtd->oobblock; i++) + writeb ( this->data_poi[i] , this->IO_ADDR_W); + this->calculate_ecc (NULL, &(ecc_code[3])); + for (i = 3; i < 6; i++) + oob_data[oob_config[i]] = ecc_code[i]; + } + break; + + /* Hardware ecc 3 byte / 512 byte data, write full page */ + case NAND_ECC_HW3_512: + this->enable_hwecc (NAND_ECC_WRITE); /* enable hardware ecc logic */ + for (i = 0; i < mtd->oobblock; i++) + writeb ( this->data_poi[i] , this->IO_ADDR_W); + this->calculate_ecc (NULL, &(ecc_code[0])); + for (i = 0; i < 3; i++) + oob_data[oob_config[i]] = ecc_code[i]; + break; + + /* Hardware ecc 6 byte / 512 byte data, write full page */ + case NAND_ECC_HW6_512: + this->enable_hwecc (NAND_ECC_WRITE); /* enable hardware ecc logic */ + for (i = 0; i < mtd->oobblock; i++) + writeb ( this->data_poi[i] , this->IO_ADDR_W); + this->calculate_ecc (NULL, &(ecc_code[0])); + for (i = 0; i < 6; i++) + oob_data[oob_config[i]] = ecc_code[i]; + break; + + default: + printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode); + BUG(); + } + + /* Write out OOB data */ + for (i = 0; i < mtd->oobsize; i++) + writeb ( oob_data[i] , this->IO_ADDR_W); + + /* Send command to actually program the data */ + this->cmdfunc (mtd, NAND_CMD_PAGEPROG, -1, -1); + + /* call wait ready function */ + status = this->waitfunc (mtd, this, FL_WRITING); + + /* See if device thinks it succeeded */ + if (status & 0x01) { + DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write, page 0x%08x, ", __FUNCTION__, page); + return -EIO; + } + +#ifdef CONFIG_MTD_NAND_VERIFY_WRITE + /* + * The NAND device assumes that it is always writing to + * a cleanly erased page. Hence, it performs its internal + * write verification only on bits that transitioned from + * 1 to 0. The device does NOT verify the whole page on a + * byte by byte basis. It is possible that the page was + * not completely erased or the page is becoming unusable + * due to wear. The read with ECC would catch the error + * later when the ECC page check fails, but we would rather + * catch it early in the page write stage. Better to write + * no data than invalid data. + */ + + /* Send command to read back the page */ + this->cmdfunc (mtd, NAND_CMD_READ0, 0, page); + /* Loop through and verify the data */ + for (i = 0; i < mtd->oobblock; i++) { + if (this->data_poi[i] != readb (this->IO_ADDR_R)) { + DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page); + return -EIO; + } + } + + /* check, if we have a fs-supplied oob-buffer */ + if (oob_buf) { + for (i = 0; i < mtd->oobsize; i++) { + if (oob_data[i] != readb (this->IO_ADDR_R)) { + DEBUG (MTD_DEBUG_LEVEL0, "%s: " "Failed write verify, page 0x%08x ", __FUNCTION__, page); + return -EIO; + } + } + } else { + if (eccmode != NAND_ECC_NONE) { + int ecc_bytes = 0; + + switch (this->eccmode) { + case NAND_ECC_SOFT: + case NAND_ECC_HW3_256: ecc_bytes = (mtd->oobblock == 512) ? 6 : 3; break; + case NAND_ECC_HW3_512: ecc_bytes = 3; break; + case NAND_ECC_HW6_512: ecc_bytes = 6; break; + } + + for (i = 0; i < mtd->oobsize; i++) + oob_data[i] = readb (this->IO_ADDR_R); + + for (i = 0; i < ecc_bytes; i++) { + if (oob_data[oob_config[i]] != ecc_code[i]) { + DEBUG (MTD_DEBUG_LEVEL0, + "%s: Failed ECC write " + "verify, page 0x%08x, " "%6i bytes were succesful\n", __FUNCTION__, page, i); + return -EIO; + } + } + } + } #endif + return 0; } /* +* Use NAND read ECC +*/ +static int nand_read (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf) +{ + return (nand_read_ecc (mtd, from, len, retlen, buf, NULL, NULL)); +} + + +/* * NAND read with ECC */ static int nand_read_ecc (struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf, u_char *ecc_code) + size_t * retlen, u_char * buf, u_char * oob_buf, struct nand_oobinfo *oobsel) { - int j, col, page, state; + int j, col, page, end, ecc; int erase_state = 0; + int read = 0, oob = 0, ecc_status = 0, ecc_failed = 0; struct nand_chip *this = mtd->priv; - DECLARE_WAITQUEUE(wait, current); -#ifdef CONFIG_MTD_NAND_ECC - int ecc_result; + u_char *data_poi, *oob_data = oob_buf; u_char ecc_calc[6]; -#endif + u_char ecc_code[6]; + int eccmode; + int *oob_config; + + // use chip default if zero + if (oobsel == NULL) + oobsel = &mtd->oobinfo; + + eccmode = oobsel->useecc ? this->eccmode : NAND_ECC_NONE; + oob_config = oobsel->eccpos; - DEBUG (MTD_DEBUG_LEVEL3, - "nand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from, - (int) len); + DEBUG (MTD_DEBUG_LEVEL3, "nand_read_ecc: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); /* Do not allow reads past end of device */ if ((from + len) > mtd->size) { - DEBUG (MTD_DEBUG_LEVEL0, - "nand_read_ecc: Attempt read beyond end of device\n"); + DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: Attempt read beyond end of device\n"); *retlen = 0; return -EINVAL; } /* Grab the lock and see if the device is available */ -retry: - spin_lock_bh (&this->chip_lock); + nand_get_chip (this, mtd ,FL_READING, &erase_state); - switch (this->state) { - case FL_READY: - this->state = FL_READING; - spin_unlock_bh (&this->chip_lock); - break; - - case FL_ERASING: - this->state = FL_READING; - erase_state = 1; - spin_unlock_bh (&this->chip_lock); - break; - - default: - set_current_state (TASK_UNINTERRUPTIBLE); - add_wait_queue (&this->wq, &wait); - spin_unlock_bh (&this->chip_lock); - schedule(); - - remove_wait_queue (&this->wq, &wait); - goto retry; - }; + /* Select the NAND device */ + nand_select (); /* First we calculate the starting page */ page = from >> this->page_shift; @@ -199,122 +567,127 @@ /* Get raw starting column */ col = from & (mtd->oobblock - 1); - /* State machine for devices having pages larger than 256 bytes */ - state = (col < mtd->eccsize) ? 0 : 1; - - /* Calculate column address within ECC block context */ - col = (col >= mtd->eccsize) ? (col - mtd->eccsize) : col; - - /* Initialize return value */ - *retlen = 0; - - /* Select the NAND device */ - nand_select (); + end = mtd->oobblock; + ecc = mtd->eccsize; + /* Send the read command */ + this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page); + /* Loop until all data read */ - while (*retlen < len) { - -#ifdef CONFIG_MTD_NAND_ECC - /* Send the read command */ - if (!state) - nand_command (mtd, NAND_CMD_READ0, 0x00, page); - else - nand_command (mtd, NAND_CMD_READ1, 0x00, page); - - /* Read in a block big enough for ECC */ - for (j=0 ; j < mtd->eccsize ; j++) - this->data_buf[j] = readb (this->IO_ADDR); - - /* Read in the out-of-band data */ - if (!state) { - nand_command (mtd, NAND_CMD_READOOB, 0x00, page); - for (j=0 ; j<3 ; j++) - ecc_code[j] = readb(this->IO_ADDR); - nand_command (mtd, NAND_CMD_READ0, 0x00, page); - } - else { - nand_command (mtd, NAND_CMD_READOOB, 0x03, page); - for (j=3 ; j<6 ; j++) - ecc_code[j] = readb(this->IO_ADDR); - nand_command (mtd, NAND_CMD_READ0, 0x00, page); - } - - /* Calculate the ECC and verify it */ - if (!state) { - nand_calculate_ecc (&this->data_buf[0], - &ecc_calc[0]); - ecc_result = nand_correct_data (&this->data_buf[0], - &ecc_code[0], &ecc_calc[0]); - } - else { - nand_calculate_ecc (&this->data_buf[0], - &ecc_calc[3]); - ecc_result = nand_correct_data (&this->data_buf[0], - &ecc_code[3], &ecc_calc[3]); - } - if (ecc_result == -1) { - DEBUG (MTD_DEBUG_LEVEL0, - "nand_read_ecc: " \ - "Failed ECC read, page 0x%08x\n", page); - nand_deselect (); - spin_lock_bh (&this->chip_lock); - if (erase_state) - this->state = FL_ERASING; + while (read < len) { + + /* If we have consequent page reads, apply delay or wait for ready/busy pin */ + if (read) { + if (!this->dev_ready) + udelay (this->chip_delay); else - this->state = FL_READY; - wake_up (&this->wq); - spin_unlock_bh (&this->chip_lock); - return -EIO; + while (!this->dev_ready()); } - /* Read the data from ECC data buffer into return buffer */ - if ((*retlen + (mtd->eccsize - col)) >= len) { - while (*retlen < len) - buf[(*retlen)++] = this->data_buf[col++]; - /* We're done */ - continue; - } - else - for (j=col ; j < mtd->eccsize ; j++) - buf[(*retlen)++] = this->data_buf[j]; -#else - /* Send the read command */ - if (!state) - nand_command (mtd, NAND_CMD_READ0, col, page); + /* + * If the read is not page aligned, we have to read into data buffer + * due to ecc, else we read into return buffer direct + */ + if (!col && (len - read) >= end) + data_poi = &buf[read]; else - nand_command (mtd, NAND_CMD_READ1, col, page); + data_poi = this->data_buf; - /* Read the data directly into the return buffer */ - if ((*retlen + (mtd->eccsize - col)) >= len) { - while (*retlen < len) - buf[(*retlen)++] = readb (this->IO_ADDR); - /* We're done */ - continue; - } - else - for (j=col ; j < mtd->eccsize ; j++) - buf[(*retlen)++] = readb (this->IO_ADDR); -#endif + /* get oob area, if we have no oob buffer from fs-driver */ + if (!oob_buf) { + oob_data = &this->data_buf[end]; + oob = 0; + } + + j = 0; + switch (eccmode) { + case NAND_ECC_NONE: /* No ECC, Read in a page */ + printk (KERN_WARNING "Reading data from NAND FLASH without ECC is not recommended\n"); + while (j < end) + data_poi[j++] = readb (this->IO_ADDR_R); + break; + + case NAND_ECC_SOFT: /* Software ECC 3/256: Read in a page + oob data */ + while (j < end) + data_poi[j++] = readb (this->IO_ADDR_R); + this->calculate_ecc (&data_poi[0], &ecc_calc[0]); + if (mtd->oobblock == 512) + this->calculate_ecc (&data_poi[256], &ecc_calc[3]); + break; + + case NAND_ECC_HW3_256: /* Hardware ECC 3 byte /256 byte data: Read in first 256 byte, get ecc, */ + this->enable_hwecc (NAND_ECC_READ); + while (j < ecc) + data_poi[j++] = readb (this->IO_ADDR_R); + this->calculate_ecc (&data_poi[0], &ecc_calc[0]); /* read from hardware */ + + if (mtd->oobblock == 512) { /* read second, if pagesize = 512 */ + this->enable_hwecc (NAND_ECC_READ); + while (j < end) + data_poi[j++] = readb (this->IO_ADDR_R); + this->calculate_ecc (&data_poi[256], &ecc_calc[3]); /* read from hardware */ + } + break; + + case NAND_ECC_HW3_512: + case NAND_ECC_HW6_512: /* Hardware ECC 3/6 byte / 512 byte data : Read in a page */ + this->enable_hwecc (NAND_ECC_READ); + while (j < end) + data_poi[j++] = readb (this->IO_ADDR_R); + this->calculate_ecc (&data_poi[0], &ecc_calc[0]); /* read from hardware */ + break; - /* - * If the amount of data to be read is greater than - * (256 - col), then all subsequent reads will take - * place on page or half-page (in the case of 512 byte - * page devices) aligned boundaries and the column - * address will be zero. Setting the column address to - * to zero after the first read allows us to simplify - * the reading of data and the if/else statements above. - */ - if (col) - col = 0x00; + default: + printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode); + BUG(); + } + /* read oobdata */ + for (j = 0; j < mtd->oobsize; j++) + oob_data[oob + j] = readb (this->IO_ADDR_R); + + /* Skip ECC, if not active */ + if (eccmode == NAND_ECC_NONE) + goto readdata; + + /* Pick the ECC bytes out of the oob data */ + for (j = 0; j < 6; j++) + ecc_code[j] = oob_data[oob + oob_config[j]]; + + /* correct data, if neccecary */ + ecc_status = this->correct_data (&data_poi[0], &ecc_code[0], &ecc_calc[0]); + /* check, if we have a fs supplied oob-buffer */ + if (oob_buf) { + oob += mtd->oobsize; + *((int *)&oob_data[oob]) = ecc_status; + oob += sizeof(int); + } + if (ecc_status == -1) { + DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page); + ecc_failed++; + } + + if (mtd->oobblock == 512 && eccmode != NAND_ECC_HW3_512) { + ecc_status = this->correct_data (&data_poi[256], &ecc_code[3], &ecc_calc[3]); + if (oob_buf) { + *((int *)&oob_data[oob]) = ecc_status; + oob += sizeof(int); + } + if (ecc_status == -1) { + DEBUG (MTD_DEBUG_LEVEL0, "nand_read_ecc: " "Failed ECC read, page 0x%08x\n", page); + ecc_failed++; + } + } +readdata: + if (col || (len - read) < end) { + for (j = col; j < end && read < len; j++) + buf[read++] = data_poi[j]; + } else + read += mtd->oobblock; + /* For subsequent reads align to page boundary. */ + col = 0; /* Increment page address */ - if ((mtd->oobblock == 256) || state) - page++; - - /* Toggle state machine */ - if (mtd->oobblock == 512) - state = state ? 0 : 1; + page++; } /* De-select the NAND device */ @@ -322,31 +695,29 @@ /* Wake up anyone waiting on the device */ spin_lock_bh (&this->chip_lock); - if (erase_state) - this->state = FL_ERASING; - else - this->state = FL_READY; + this->state = FL_READY; wake_up (&this->wq); spin_unlock_bh (&this->chip_lock); - - /* Return happy */ - return 0; + + /* + * Return success, if no ECC failures, else -EIO + * fs driver will take care of that, because + * retlen == desired len and result == -EIO + */ + *retlen = read; + return ecc_failed ? -EIO : 0; } /* * NAND read out-of-band */ -static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, - size_t *retlen, u_char *buf) +static int nand_read_oob (struct mtd_info *mtd, loff_t from, size_t len, size_t * retlen, u_char * buf) { int i, col, page; int erase_state = 0; struct nand_chip *this = mtd->priv; - DECLARE_WAITQUEUE(wait, current); - - DEBUG (MTD_DEBUG_LEVEL3, - "nand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, - (int) len); + + DEBUG (MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08x, len = %i\n", (unsigned int) from, (int) len); /* Shift to get page */ page = ((int) from) >> this->page_shift; @@ -357,59 +728,36 @@ /* Initialize return length value */ *retlen = 0; - /* Do not allow read past end of page */ - if ((col + len) > mtd->oobsize) { - DEBUG (MTD_DEBUG_LEVEL0, - "nand_read_oob: Attempt read past end of page " \ - "0x%08x, column %i, length %i\n", page, col, len); + /* Do not allow reads past end of device */ + if ((from + len) > mtd->size) { + DEBUG (MTD_DEBUG_LEVEL0, "nand_read_oob: Attempt read beyond end of device\n"); + *retlen = 0; return -EINVAL; } -retry: /* Grab the lock and see if the device is available */ - spin_lock_bh (&this->chip_lock); - - switch (this->state) { - case FL_READY: - this->state = FL_READING; - spin_unlock_bh (&this->chip_lock); - break; - - case FL_ERASING: - this->state = FL_READING; - erase_state = 1; - spin_unlock_bh (&this->chip_lock); - break; - - default: - set_current_state (TASK_UNINTERRUPTIBLE); - add_wait_queue (&this->wq, &wait); - spin_unlock_bh (&this->chip_lock); - schedule(); - - remove_wait_queue (&this->wq, &wait); - goto retry; - }; + nand_get_chip (this, mtd , FL_READING, &erase_state); /* Select the NAND device */ nand_select (); /* Send the read command */ - nand_command (mtd, NAND_CMD_READOOB, col, page); - - /* Read the data */ - for (i = 0 ; i < len ; i++) - buf[i] = readb (this->IO_ADDR); - + this->cmdfunc (mtd, NAND_CMD_READOOB, col, page); + /* + * Read the data, if we read more than one page + * oob data, let the device transfer the data ! + */ + for (i = 0; i < len; i++) { + buf[i] = readb (this->IO_ADDR_R); + if ((col++ & (mtd->oobsize - 1)) == (mtd->oobsize - 1)) + udelay (this->chip_delay); + } /* De-select the NAND device */ nand_deselect (); /* Wake up anyone waiting on the device */ spin_lock_bh (&this->chip_lock); - if (erase_state) - this->state = FL_ERASING; - else - this->state = FL_READY; + this->state = FL_READY; wake_up (&this->wq); spin_unlock_bh (&this->chip_lock); @@ -418,265 +766,80 @@ return 0; } +#define NOTALIGNED(x) (x & (mtd->oobblock-1)) != 0 + /* - * NAND write - */ -static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf) +* Use NAND write ECC +*/ +static int nand_write (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf) { -#ifdef CONFIG_MTD_NAND_ECC - struct nand_chip *this = mtd->priv; - - return nand_write_ecc (mtd, to, len, retlen, buf, this->ecc_code_buf); -#else - return nand_write_ecc (mtd, to, len, retlen, buf, NULL); -#endif -} - + return (nand_write_ecc (mtd, to, len, retlen, buf, NULL, NULL)); +} /* * NAND write with ECC */ static int nand_write_ecc (struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf, - u_char *ecc_code) + size_t * retlen, const u_char * buf, u_char * eccbuf, struct nand_oobinfo *oobsel) { - int i, page, col, cnt, status; + int page, ret = 0, oob = 0, written = 0; struct nand_chip *this = mtd->priv; - DECLARE_WAITQUEUE(wait, current); -#ifdef CONFIG_MTD_NAND_ECC - int ecc_bytes = (mtd->oobblock == 512) ? 6 : 3; -#endif - DEBUG (MTD_DEBUG_LEVEL3, - "nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, - (int) len); + DEBUG (MTD_DEBUG_LEVEL3, "nand_write_ecc: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); - /* Do not allow write past end of page */ + /* Do not allow write past end of device */ if ((to + len) > mtd->size) { - DEBUG (MTD_DEBUG_LEVEL0, - "nand_write_ecc: Attempted write past end of device\n"); + DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Attempt to write past end of page\n"); return -EINVAL; } -retry: - /* Grab the lock and see if the device is available */ - spin_lock_bh (&this->chip_lock); - - switch (this->state) { - case FL_READY: - this->state = FL_WRITING; - spin_unlock_bh (&this->chip_lock); - break; - - default: - set_current_state (TASK_UNINTERRUPTIBLE); - add_wait_queue (&this->wq, &wait); - spin_unlock_bh (&this->chip_lock); - schedule(); + /* reject writes, which are not page aligned */ + if (NOTALIGNED (to) || NOTALIGNED(len)) { + printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); + return -EINVAL; + } - remove_wait_queue (&this->wq, &wait); - goto retry; - }; + // if oobsel is NULL, use chip defaults + if (oobsel == NULL) + oobsel = &mtd->oobinfo; /* Shift to get page */ page = ((int) to) >> this->page_shift; - /* Get the starting column */ - col = to & (mtd->oobblock - 1); - - /* Initialize return length value */ - *retlen = 0; + /* Grab the lock and see if the device is available */ + nand_get_chip (this, mtd, FL_WRITING, NULL); /* Select the NAND device */ nand_select (); /* Check the WP bit */ - nand_command (mtd, NAND_CMD_STATUS, -1, -1); - if (!(readb (this->IO_ADDR) & 0x80)) { - DEBUG (MTD_DEBUG_LEVEL0, - "nand_write_ecc: Device is write protected!!!\n"); - nand_deselect (); - spin_lock_bh (&this->chip_lock); - this->state = FL_READY; - wake_up (&this->wq); - spin_unlock_bh (&this->chip_lock); - return -EIO; + this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); + if (!(readb (this->IO_ADDR_R) & 0x80)) { + DEBUG (MTD_DEBUG_LEVEL0, "nand_write_ecc: Device is write protected!!!\n"); + ret = -EIO; + goto out; } /* Loop until all data is written */ - while (*retlen < len) { - /* Write data into buffer */ - if ((col + len) >= mtd->oobblock) - for(i=col, cnt=0 ; i < mtd->oobblock ; i++, cnt++) - this->data_buf[i] = buf[(*retlen + cnt)]; - else - for(i=col, cnt=0 ; cnt < (len - *retlen) ; i++, cnt++) - this->data_buf[i] = buf[(*retlen + cnt)]; + while (written < len) { + int cnt = mtd->oobblock; + this->data_poi = (u_char*) &buf[written]; + /* We use the same function for write and writev */ + if (eccbuf) { + ret = nand_write_page (mtd, this, page, &eccbuf[oob], oobsel); + oob += mtd->oobsize; + } else + ret = nand_write_page (mtd, this, page, NULL, oobsel); -#ifdef CONFIG_MTD_NAND_ECC - /* Zero out the ECC array */ - for (i=0 ; i < 6 ; i++) - ecc_code[i] = 0x00; - - /* Calculate and write the ECC if we have enough data */ - if ((col < mtd->eccsize) && - ((col + (len - *retlen)) >= mtd->eccsize)) { - nand_command (mtd, NAND_CMD_READ0, col, page); - for (i=0 ; i < col ; i++) - this->data_buf[i] = readb (this->IO_ADDR); - nand_calculate_ecc (&this->data_buf[0], &ecc_code[0]); - for (i=0 ; i<3 ; i++) - this->data_buf[(mtd->oobblock + i)] = - ecc_code[i]; - } - - /* Calculate and write the second ECC if we have enough data */ - if ((mtd->oobblock == 512) && - ((col + (len - *retlen)) >= mtd->oobblock)) { - nand_calculate_ecc (&this->data_buf[256], &ecc_code[3]); - for (i=3 ; i<6 ; i++) - this->data_buf[(mtd->oobblock + i)] = - ecc_code[i]; - } - - /* Write ones for partial page programming */ - for (i=ecc_bytes ; i < mtd->oobsize ; i++) - this->data_buf[(mtd->oobblock + i)] = 0xff; -#else - /* Write ones for partial page programming */ - for (i=mtd->oobblock ; i < (mtd->oobblock + mtd->oobsize) ; i++) - this->data_buf[i] = 0xff; -#endif - - /* Write pre-padding bytes into buffer */ - for (i=0 ; i < col ; i++) - this->data_buf[i] = 0xff; - - /* Write post-padding bytes into buffer */ - if ((col + (len - *retlen)) < mtd->oobblock) { - for(i=(col + cnt) ; i < mtd->oobblock ; i++) - this->data_buf[i] = 0xff; - } - - /* Send command to begin auto page programming */ - nand_command (mtd, NAND_CMD_SEQIN, 0x00, page); - - /* Write out complete page of data */ - for (i=0 ; i < (mtd->oobblock + mtd->oobsize) ; i++) - writeb (this->data_buf[i], this->IO_ADDR); - - /* Send command to actually program the data */ - nand_command (mtd, NAND_CMD_PAGEPROG, -1, -1); - - /* - * Wait for program operation to complete. This could - * take up to 3000us (3ms) on some devices, so we try - * and exit as quickly as possible. - */ - status = 0; - for (i=0 ; i<24 ; i++) { - /* Delay for 125us */ - udelay (125); - - /* Check the status */ - nand_command (mtd, NAND_CMD_STATUS, -1, -1); - status = (int) readb (this->IO_ADDR); - if (status & 0x40) - break; - } - - /* See if device thinks it succeeded */ - if (status & 0x01) { - DEBUG (MTD_DEBUG_LEVEL0, - "nand_write_ecc: " \ - "Failed write, page 0x%08x, " \ - "%6i bytes were succesful\n", page, *retlen); - nand_deselect (); - spin_lock_bh (&this->chip_lock); - this->state = FL_READY; - wake_up (&this->wq); - spin_unlock_bh (&this->chip_lock); - return -EIO; - } - -#ifdef CONFIG_MTD_NAND_VERIFY_WRITE - /* - * The NAND device assumes that it is always writing to - * a cleanly erased page. Hence, it performs its internal - * write verification only on bits that transitioned from - * 1 to 0. The device does NOT verify the whole page on a - * byte by byte basis. It is possible that the page was - * not completely erased or the page is becoming unusable - * due to wear. The read with ECC would catch the error - * later when the ECC page check fails, but we would rather - * catch it early in the page write stage. Better to write - * no data than invalid data. - */ - - /* Send command to read back the page */ - if (col < mtd->eccsize) - nand_command (mtd, NAND_CMD_READ0, col, page); - else - nand_command (mtd, NAND_CMD_READ1, col - 256, page); - - /* Loop through and verify the data */ - for (i=col ; i < cnt ; i++) { - if (this->data_buf[i] != readb (this->IO_ADDR)) { - DEBUG (MTD_DEBUG_LEVEL0, - "nand_write_ecc: " \ - "Failed write verify, page 0x%08x, " \ - "%6i bytes were succesful\n", - page, *retlen); - nand_deselect (); - spin_lock_bh (&this->chip_lock); - this->state = FL_READY; - wake_up (&this->wq); - spin_unlock_bh (&this->chip_lock); - return -EIO; - } - } - -#ifdef CONFIG_MTD_NAND_ECC - /* - * We also want to check that the ECC bytes wrote - * correctly for the same reasons stated above. - */ - nand_command (mtd, NAND_CMD_READOOB, 0x00, page); - for (i=0 ; i < ecc_bytes ; i++) { - if ((readb (this->IO_ADDR) != ecc_code[i]) && - ecc_code[i]) { - DEBUG (MTD_DEBUG_LEVEL0, - "nand_write_ecc: Failed ECC write " \ - "verify, page 0x%08x, " \ - "%6i bytes were succesful\n", - page, i); - nand_deselect (); - spin_lock_bh (&this->chip_lock); - this->state = FL_READY; - wake_up (&this->wq); - spin_unlock_bh (&this->chip_lock); - return -EIO; - } - } -#endif - -#endif - - /* - * If we are writing a large amount of data and/or it - * crosses page or half-page boundaries, we set the - * the column to zero. It simplifies the program logic. - */ - if (col) - col = 0x00; + if (ret) + goto out; /* Update written bytes count */ - *retlen += cnt; - + written += cnt; /* Increment page address */ page++; } +out: /* De-select the NAND device */ nand_deselect (); @@ -686,24 +849,19 @@ wake_up (&this->wq); spin_unlock_bh (&this->chip_lock); - /* Return happy */ - *retlen = len; - return 0; + *retlen = written; + return ret; } /* * NAND write out-of-band */ -static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, - size_t *retlen, const u_char *buf) +static int nand_write_oob (struct mtd_info *mtd, loff_t to, size_t len, size_t * retlen, const u_char * buf) { - int i, column, page, status; + int i, column, page, status, ret = 0; struct nand_chip *this = mtd->priv; - DECLARE_WAITQUEUE(wait, current); - - DEBUG (MTD_DEBUG_LEVEL3, - "nand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, - (int) len); + + DEBUG (MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n", (unsigned int) to, (int) len); /* Shift to get page */ page = ((int) to) >> this->page_shift; @@ -716,105 +874,65 @@ /* Do not allow write past end of page */ if ((column + len) > mtd->oobsize) { - DEBUG (MTD_DEBUG_LEVEL0, - "nand_write_oob: Attempt to write past end of page\n"); + DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Attempt to write past end of page\n"); return -EINVAL; } -retry: /* Grab the lock and see if the device is available */ - spin_lock_bh (&this->chip_lock); - - switch (this->state) { - case FL_READY: - this->state = FL_WRITING; - spin_unlock_bh (&this->chip_lock); - break; - - default: - set_current_state (TASK_UNINTERRUPTIBLE); - add_wait_queue (&this->wq, &wait); - spin_unlock_bh (&this->chip_lock); - schedule(); - - remove_wait_queue (&this->wq, &wait); - goto retry; - }; + nand_get_chip (this, mtd, FL_WRITING, NULL); /* Select the NAND device */ nand_select (); /* Check the WP bit */ - nand_command (mtd, NAND_CMD_STATUS, -1, -1); - if (!(readb (this->IO_ADDR) & 0x80)) { - DEBUG (MTD_DEBUG_LEVEL0, - "nand_write_oob: Device is write protected!!!\n"); - nand_deselect (); - spin_lock_bh (&this->chip_lock); - this->state = FL_READY; - wake_up (&this->wq); - spin_unlock_bh (&this->chip_lock); - return -EIO; + this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); + if (!(readb (this->IO_ADDR_R) & 0x80)) { + DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: Device is write protected!!!\n"); + ret = -EIO; + goto out; } /* Write out desired data */ - nand_command (mtd, NAND_CMD_SEQIN, column + 512, page); - for (i=0 ; i<len ; i++) - writeb (buf[i], this->IO_ADDR); + this->cmdfunc (mtd, NAND_CMD_SEQIN, mtd->oobblock, page); + /* prepad 0xff for partial programming */ + for (i = 0; i < column; i++) + writeb (0xff, this->IO_ADDR_W); + /* write data */ + for (i = 0; i < len; i++) + writeb (buf[i], this->IO_ADDR_W); + /* postpad 0xff for partial programming */ + for (i = len + column; i < mtd->oobsize; i++) + writeb (0xff, this->IO_ADDR_W); /* Send command to program the OOB data */ - nand_command (mtd, NAND_CMD_PAGEPROG, -1, -1); + this->cmdfunc (mtd, NAND_CMD_PAGEPROG, -1, -1); - /* - * Wait for program operation to complete. This could - * take up to 3000us (3ms) on some devices, so we try - * and exit as quickly as possible. - */ - status = 0; - for (i=0 ; i<24 ; i++) { - /* Delay for 125us */ - udelay (125); - - /* Check the status */ - nand_command (mtd, NAND_CMD_STATUS, -1, -1); - status = (int) readb (this->IO_ADDR); - if (status & 0x40) - break; - } + status = this->waitfunc (mtd, this, FL_WRITING); /* See if device thinks it succeeded */ if (status & 0x01) { - DEBUG (MTD_DEBUG_LEVEL0, - "nand_write_oob: " \ - "Failed write, page 0x%08x\n", page); - nand_deselect (); - spin_lock_bh (&this->chip_lock); - this->state = FL_READY; - wake_up (&this->wq); - spin_unlock_bh (&this->chip_lock); - return -EIO; + DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write, page 0x%08x\n", page); + ret = -EIO; + goto out; } + /* Return happy */ + *retlen = len; #ifdef CONFIG_MTD_NAND_VERIFY_WRITE /* Send command to read back the data */ - nand_command (mtd, NAND_CMD_READOOB, column, page); + this->cmdfunc (mtd, NAND_CMD_READOOB, column, page); /* Loop through and verify the data */ - for (i=0 ; i<len ; i++) { - if (buf[i] != readb (this->IO_ADDR)) { - DEBUG (MTD_DEBUG_LEVEL0, - "nand_write_oob: " \ - "Failed write verify, page 0x%08x\n", page); - nand_deselect (); - spin_lock_bh (&this->chip_lock); - this->state = FL_READY; - wake_up (&this->wq); - spin_unlock_bh (&this->chip_lock); - return -EIO; + for (i = 0; i < len; i++) { + if (buf[i] != readb (this->IO_ADDR_R)) { + DEBUG (MTD_DEBUG_LEVEL0, "nand_write_oob: " "Failed write verify, page 0x%08x\n", page); + ret = -EIO; + goto out; } } #endif +out: /* De-select the NAND device */ nand_deselect (); @@ -824,258 +942,117 @@ wake_up (&this->wq); spin_unlock_bh (&this->chip_lock); - /* Return happy */ - *retlen = len; - return 0; + return ret; } + /* * NAND write with iovec */ -static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs, - unsigned long count, loff_t to, size_t *retlen) +static int nand_writev (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, + loff_t to, size_t * retlen) +{ + return (nand_writev_ecc (mtd, vecs, count, to, retlen, NULL, 0)); +} + +static int nand_writev_ecc (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, + loff_t to, size_t * retlen, u_char *eccbuf, struct nand_oobinfo *oobsel) { - int i, page, col, cnt, len, total_len, status; + int i, page, len, total_len, ret = 0, written = 0; struct nand_chip *this = mtd->priv; - DECLARE_WAITQUEUE(wait, current); -#ifdef CONFIG_MTD_NAND_ECC - int ecc_bytes = (mtd->oobblock == 512) ? 6 : 3; -#endif /* Calculate total length of data */ total_len = 0; - for (i=0 ; i < count ; i++) + for (i = 0; i < count; i++) total_len += (int) vecs[i].iov_len; DEBUG (MTD_DEBUG_LEVEL3, - "nand_writev: to = 0x%08x, len = %i\n", (unsigned int) to, - (unsigned int) total_len); + "nand_writev: to = 0x%08x, len = %i, count = %ld\n", (unsigned int) to, (unsigned int) total_len, count); /* Do not allow write past end of page */ if ((to + total_len) > mtd->size) { - DEBUG (MTD_DEBUG_LEVEL0, - "nand_writev: Attempted write past end of device\n"); + DEBUG (MTD_DEBUG_LEVEL0, "nand_writev: Attempted write past end of device\n"); return -EINVAL; } -retry: - /* Grab the lock and see if the device is available */ - spin_lock_bh (&this->chip_lock); - - switch (this->state) { - case FL_READY: - this->state = FL_WRITING; - spin_unlock_bh (&this->chip_lock); - break; - - default: - set_current_state (TASK_UNINTERRUPTIBLE); - add_wait_queue (&this->wq, &wait); - spin_unlock_bh (&this->chip_lock); - schedule(); + /* reject writes, which are not page aligned */ + if (NOTALIGNED (to) || NOTALIGNED(total_len)) { + printk (KERN_NOTICE "nand_write_ecc: Attempt to write not page aligned data\n"); + return -EINVAL; + } - remove_wait_queue (&this->wq, &wait); - goto retry; - }; + // if oobsel is NULL, use chip defaults + if (oobsel == NULL) + oobsel = &mtd->oobinfo; /* Shift to get page */ page = ((int) to) >> this->page_shift; - /* Get the starting column */ - col = to & (mtd->oobblock - 1); - - /* Initialize return length value */ - *retlen = 0; + /* Grab the lock and see if the device is available */ + nand_get_chip (this, mtd, FL_WRITING, NULL); /* Select the NAND device */ nand_select (); /* Check the WP bit */ - nand_command (mtd, NAND_CMD_STATUS, -1, -1); - if (!(readb (this->IO_ADDR) & 0x80)) { - DEBUG (MTD_DEBUG_LEVEL0, - "nand_writev: Device is write protected!!!\n"); - nand_deselect (); - spin_lock_bh (&this->chip_lock); - this->state = FL_READY; - wake_up (&this->wq); - spin_unlock_bh (&this->chip_lock); - return -EIO; + this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); + if (!(readb (this->IO_ADDR_R) & 0x80)) { + DEBUG (MTD_DEBUG_LEVEL0, "nand_writev: Device is write protected!!!\n"); + ret = -EIO; + goto out; } /* Loop until all iovecs' data has been written */ - cnt = col; len = 0; while (count) { - /* Do any need pre-fill for partial page programming */ - for (i=0 ; i < cnt ; i++) - this->data_buf[i] = 0xff; - - /* - * Read data out of each tuple until we have a full page - * to write or we've read all the tuples. + /* + * Check, if the tuple gives us not enough data for a + * full page write. Then we can use the iov direct, + * else we have to copy into data_buf. */ - while ((cnt < mtd->oobblock) && count) { - this->data_buf[cnt++] = - ((u_char *) vecs->iov_base)[len++]; + if ((vecs->iov_len - len) >= mtd->oobblock) { + this->data_poi = (u_char *) vecs->iov_base; + this->data_poi += len; + len += mtd->oobblock; + /* Check, if we have to switch to the next tuple */ if (len >= (int) vecs->iov_len) { vecs++; len = 0; count--; } + } else { + /* + * Read data out of each tuple until we have a full page + * to write or we've read all the tuples. + */ + int cnt = 0; + while ((cnt < mtd->oobblock) && count) { + if (vecs->iov_base != NULL && vecs->iov_len) { + this->data_buf[cnt++] = ((u_char *) vecs->iov_base)[len++]; + } + /* Check, if we have to switch to the next tuple */ + if (len >= (int) vecs->iov_len) { + vecs++; + len = 0; + count--; + } + } + this->data_poi = this->data_buf; } - /* Do any need post-fill for partial page programming */ - for (i=cnt ; i < mtd->oobblock ; i++) - this->data_buf[i] = 0xff; - -#ifdef CONFIG_MTD_NAND_ECC - /* Zero out the ECC array */ - for (i=0 ; i < 6 ; i++) - this->ecc_code_buf[i] = 0x00; - - /* Calculate and write the first ECC */ - if (col >= mtd->eccsize) { - nand_command (mtd, NAND_CMD_READ0, col, page); - for (i=0 ; i < col ; i++) - this->data_buf[i] = readb (this->IO_ADDR); - nand_calculate_ecc (&this->data_buf[0], - &(this->ecc_code_buf[0])); - for (i=0 ; i<3 ; i++) - this->data_buf[(mtd->oobblock + i)] = - this->ecc_code_buf[i]; - } - - /* Calculate and write the second ECC */ - if ((mtd->oobblock == 512) && (cnt == mtd->oobblock)) { - nand_calculate_ecc (&this->data_buf[256], - &(this->ecc_code_buf[3])); - for (i=3 ; i<6 ; i++) - this->data_buf[(mtd->oobblock + i)] = - this->ecc_code_buf[i]; - } - - /* Write ones for partial page programming */ - for (i=ecc_bytes ; i < mtd->oobsize ; i++) - this->data_buf[(mtd->oobblock + i)] = 0xff; -#else - /* Write ones for partial page programming */ - for (i=mtd->oobblock ; i < (mtd->oobblock + mtd->oobsize) ; i++) - this->data_buf[i] = 0xff; -#endif - /* Send command to begin auto page programming */ - nand_command (mtd, NAND_CMD_SEQIN, 0x00, page); - - /* Write out complete page of data */ - for (i=0 ; i < (mtd->oobblock + mtd->oobsize) ; i++) - writeb (this->data_buf[i], this->IO_ADDR); - - /* Send command to actually program the data */ - nand_command (mtd, NAND_CMD_PAGEPROG, -1, -1); - - /* - * Wait for program operation to complete. This could - * take up to 3000us (3ms) on some devices, so we try - * and exit as quickly as possible. - */ - status = 0; - for (i=0 ; i<24 ; i++) { - /* Delay for 125us */ - udelay (125); - - /* Check the status */ - nand_command (mtd, NAND_CMD_STATUS, -1, -1); - status = (int) readb (this->IO_ADDR); - if (status & 0x40) - break; - } - - /* See if device thinks it succeeded */ - if (status & 0x01) { - DEBUG (MTD_DEBUG_LEVEL0, - "nand_writev: " \ - "Failed write, page 0x%08x, " \ - "%6i bytes were succesful\n", page, *retlen); - nand_deselect (); - spin_lock_bh (&this->chip_lock); - this->state = FL_READY; - wake_up (&this->wq); - spin_unlock_bh (&this->chip_lock); - return -EIO; - } - -#ifdef CONFIG_MTD_NAND_VERIFY_WRITE - /* - * The NAND device assumes that it is always writing to - * a cleanly erased page. Hence, it performs its internal - * write verification only on bits that transitioned from - * 1 to 0. The device does NOT verify the whole page on a - * byte by byte basis. It is possible that the page was - * not completely erased or the page is becoming unusable - * due to wear. The read with ECC would catch the error - * later when the ECC page check fails, but we would rather - * catch it early in the page write stage. Better to write - * no data than invalid data. - */ - - /* Send command to read back the page */ - if (col < mtd->eccsize) - nand_command (mtd, NAND_CMD_READ0, col, page); - else - nand_command (mtd, NAND_CMD_READ1, col - 256, page); - - /* Loop through and verify the data */ - for (i=col ; i < cnt ; i++) { - if (this->data_buf[i] != readb (this->IO_ADDR)) { - DEBUG (MTD_DEBUG_LEVEL0, - "nand_writev: " \ - "Failed write verify, page 0x%08x, " \ - "%6i bytes were succesful\n", - page, *retlen); - nand_deselect (); - spin_lock_bh (&this->chip_lock); - this->state = FL_READY; - wake_up (&this->wq); - spin_unlock_bh (&this->chip_lock); - return -EIO; - } - } + /* We use the same function for write and writev !) */ + ret = nand_write_page (mtd, this, page, NULL, oobsel); + if (ret) + goto out; -#ifdef CONFIG_MTD_NAND_ECC - /* - * We also want to check that the ECC bytes wrote - * correctly for the same reasons stated above. - */ - nand_command (mtd, NAND_CMD_READOOB, 0x00, page); - for (i=0 ; i < ecc_bytes ; i++) { - if ((readb (this->IO_ADDR) != this->ecc_code_buf[i]) && - this->ecc_code_buf[i]) { - DEBUG (MTD_DEBUG_LEVEL0, - "nand_writev: Failed ECC write " \ - "verify, page 0x%08x, " \ - "%6i bytes were succesful\n", - page, i); - nand_deselect (); - spin_lock_bh (&this->chip_lock); - this->state = FL_READY; - wake_up (&this->wq); - spin_unlock_bh (&this->chip_lock); - return -EIO; - } - } -#endif - -#endif /* Update written bytes count */ - *retlen += (cnt - col); - - /* Reset written byte counter and column */ - col = cnt = 0; + written += mtd->oobblock;; /* Increment page address */ page++; } +out: /* De-select the NAND device */ nand_deselect (); @@ -1085,8 +1062,8 @@ wake_up (&this->wq); spin_unlock_bh (&this->chip_lock); - /* Return happy */ - return 0; + *retlen = written; + return ret; } /* @@ -1094,53 +1071,33 @@ */ static int nand_erase (struct mtd_info *mtd, struct erase_info *instr) { - int i, page, len, status, pages_per_block; + int page, len, status, pages_per_block, ret; struct nand_chip *this = mtd->priv; - DECLARE_WAITQUEUE(wait, current); + DECLARE_WAITQUEUE (wait, current); DEBUG (MTD_DEBUG_LEVEL3, - "nand_erase: start = 0x%08x, len = %i\n", - (unsigned int) instr->addr, (unsigned int) instr->len); + "nand_erase: start = 0x%08x, len = %i\n", (unsigned int) instr->addr, (unsigned int) instr->len); /* Start address must align on block boundary */ if (instr->addr & (mtd->erasesize - 1)) { - DEBUG (MTD_DEBUG_LEVEL0, - "nand_erase: Unaligned address\n"); + DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n"); return -EINVAL; } /* Length must align on block boundary */ if (instr->len & (mtd->erasesize - 1)) { - DEBUG (MTD_DEBUG_LEVEL0, - "nand_erase: Length not block aligned\n"); + DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Length not block aligned\n"); return -EINVAL; } /* Do not allow erase past end of device */ if ((instr->len + instr->addr) > mtd->size) { - DEBUG (MTD_DEBUG_LEVEL0, - "nand_erase: Erase past end of device\n"); + DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Erase past end of device\n"); return -EINVAL; } -retry: /* Grab the lock and see if the device is available */ - spin_lock_bh (&this->chip_lock); - - switch (this->state) { - case FL_READY: - this->state = FL_ERASING; - break; - - default: - set_current_state (TASK_UNINTERRUPTIBLE); - add_wait_queue (&this->wq, &wait); - spin_unlock_bh (&this->chip_lock); - schedule(); - - remove_wait_queue (&this->wq, &wait); - goto retry; - }; + nand_get_chip (this, mtd, FL_ERASING, NULL); /* Shift to get first page */ page = (int) (instr->addr >> this->page_shift); @@ -1152,81 +1109,78 @@ nand_select (); /* Check the WP bit */ - nand_command (mtd, NAND_CMD_STATUS, -1, -1); - if (!(readb (this->IO_ADDR) & 0x80)) { - DEBUG (MTD_DEBUG_LEVEL0, - "nand_erase: Device is write protected!!!\n"); - nand_deselect (); - this->state = FL_READY; - spin_unlock_bh (&this->chip_lock); - return -EIO; + this->cmdfunc (mtd, NAND_CMD_STATUS, -1, -1); + if (!(readb (this->IO_ADDR_R) & 0x80)) { + DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: Device is write protected!!!\n"); + instr->state = MTD_ERASE_FAILED; + goto erase_exit; } /* Loop through the pages */ len = instr->len; + + instr->state = MTD_ERASING; + while (len) { + /* Check if we have a bad block, we do not erase bad blocks ! */ + this->cmdfunc (mtd, NAND_CMD_READOOB, NAND_BADBLOCK_POS, page); + if (readb (this->IO_ADDR_R) != 0xff) { + printk (KERN_WARNING "nand_erase: attempt to erase a bad block at page 0x%08x\n", page); + instr->state = MTD_ERASE_FAILED; + goto erase_exit; + } + /* Send commands to erase a page */ - nand_command(mtd, NAND_CMD_ERASE1, -1, page); - nand_command(mtd, NAND_CMD_ERASE2, -1, -1); + this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page); + this->cmdfunc (mtd, NAND_CMD_ERASE2, -1, -1); - /* - * Wait for program operation to complete. This could - * take up to 4000us (4ms) on some devices, so we try - * and exit as quickly as possible. - */ - status = 0; - for (i=0 ; i<32 ; i++) { - /* Delay for 125us */ - udelay (125); - - /* Check the status */ - nand_command (mtd, NAND_CMD_STATUS, -1, -1); - status = (int) readb (this->IO_ADDR); - if (status & 0x40) - break; - } + spin_unlock_bh (&this->chip_lock); + status = this->waitfunc (mtd, this, FL_ERASING); + /* Get spinlock, in case we exit */ + spin_lock_bh (&this->chip_lock); /* See if block erase succeeded */ if (status & 0x01) { - DEBUG (MTD_DEBUG_LEVEL0, - "nand_erase: " \ - "Failed erase, page 0x%08x\n", page); - nand_deselect (); - this->state = FL_READY; - spin_unlock_bh (&this->chip_lock); - return -EIO; + DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page); + instr->state = MTD_ERASE_FAILED; + goto erase_exit; + } + + /* Check, if we were interupted */ + if (this->state == FL_ERASING) { + /* Increment page address and decrement length */ + len -= mtd->erasesize; + page += pages_per_block; } - - /* Increment page address and decrement length */ - len -= mtd->erasesize; - page += pages_per_block; - /* Release the spin lock */ spin_unlock_bh (&this->chip_lock); - erase_retry: - /* Check the state and sleep if it changed */ spin_lock_bh (&this->chip_lock); - if (this->state == FL_ERASING) { + /* Check the state and sleep if it changed */ + if (this->state == FL_ERASING || this->state == FL_READY) { + /* Select the NAND device again, if we were interrupted */ + this->state = FL_ERASING; + nand_select (); continue; - } - else { + } else { set_current_state (TASK_UNINTERRUPTIBLE); add_wait_queue (&this->wq, &wait); spin_unlock_bh (&this->chip_lock); - schedule(); - + schedule (); remove_wait_queue (&this->wq, &wait); goto erase_retry; } } - spin_unlock_bh (&this->chip_lock); + instr->state = MTD_ERASE_DONE; +erase_exit: /* De-select the NAND device */ nand_deselect (); + spin_unlock_bh (&this->chip_lock); + ret = instr->state == MTD_ERASE_DONE ? 0 : -EIO;; /* Do call back function */ - if (instr->callback) + if (!ret && instr->callback) instr->callback (instr); /* The device is ready */ @@ -1234,8 +1188,8 @@ this->state = FL_READY; spin_unlock_bh (&this->chip_lock); - /* Return happy */ - return 0; + /* Return more or less happy */ + return ret; } /* @@ -1244,16 +1198,16 @@ static void nand_sync (struct mtd_info *mtd) { struct nand_chip *this = mtd->priv; - DECLARE_WAITQUEUE(wait, current); + DECLARE_WAITQUEUE (wait, current); DEBUG (MTD_DEBUG_LEVEL3, "nand_sync: called\n"); retry: /* Grab the spinlock */ - spin_lock_bh(&this->chip_lock); + spin_lock_bh (&this->chip_lock); /* See what's going on */ - switch(this->state) { + switch (this->state) { case FL_READY: case FL_SYNCING: this->state = FL_SYNCING; @@ -1270,7 +1224,7 @@ goto retry; } - /* Lock the device */ + /* Lock the device */ spin_lock_bh (&this->chip_lock); /* Set the device to be ready again */ @@ -1279,7 +1233,7 @@ wake_up (&this->wq); } - /* Unlock the device */ + /* Unlock the device */ spin_unlock_bh (&this->chip_lock); } @@ -1291,46 +1245,100 @@ int i, nand_maf_id, nand_dev_id; struct nand_chip *this = mtd->priv; + /* check for proper chip_delay setup, set 20us if not */ + if (!this->chip_delay) + this->chip_delay = 20; + + /* check, if a user supplied command function given */ + if (this->cmdfunc == NULL) + this->cmdfunc = nand_command; + + /* check, if a user supplied wait function given */ + if (this->waitfunc == NULL) + this->waitfunc = nand_wait; + /* Select the device */ nand_select (); /* Send the command for reading device ID */ - nand_command (mtd, NAND_CMD_READID, 0x00, -1); + this->cmdfunc (mtd, NAND_CMD_READID, 0x00, -1); /* Read manufacturer and device IDs */ - nand_maf_id = readb (this->IO_ADDR); - nand_dev_id = readb (this->IO_ADDR); + nand_maf_id = readb (this->IO_ADDR_R); + nand_dev_id = readb (this->IO_ADDR_R); /* Print and store flash device information */ for (i = 0; nand_flash_ids[i].name != NULL; i++) { - if (nand_maf_id == nand_flash_ids[i].manufacture_id && - nand_dev_id == nand_flash_ids[i].model_id) { - if (!mtd->size) { - mtd->name = nand_flash_ids[i].name; - mtd->erasesize = nand_flash_ids[i].erasesize; - mtd->size = (1 << nand_flash_ids[i].chipshift); - mtd->eccsize = 256; - if (nand_flash_ids[i].page256) { - mtd->oobblock = 256; - mtd->oobsize = 8; - this->page_shift = 8; - } - else { - mtd->oobblock = 512; - mtd->oobsize = 16; - this->page_shift = 9; - } + if (nand_dev_id == nand_flash_ids[i].id && !mtd->size) { + mtd->name = nand_flash_ids[i].name; + mtd->erasesize = nand_flash_ids[i].erasesize; + mtd->size = (1 << nand_flash_ids[i].chipshift); + mtd->eccsize = 256; + if (nand_flash_ids[i].page256) { + mtd->oobblock = 256; + mtd->oobsize = 8; + this->page_shift = 8; + } else { + mtd->oobblock = 512; + mtd->oobsize = 16; + this->page_shift = 9; } - printk (KERN_INFO "NAND device: Manufacture ID:" \ - " 0x%02x, Chip ID: 0x%02x (%s)\n", - nand_maf_id, nand_dev_id, mtd->name); + /* Try to identify manufacturer */ + for (i = 0; nand_manuf_ids[i].id != 0x0; i++) { + if (nand_manuf_ids[i].id == nand_maf_id) + break; + } + printk (KERN_INFO "NAND device: Manufacture ID:" + " 0x%02x, Chip ID: 0x%02x (%s %s)\n", nand_maf_id, nand_dev_id, + nand_manuf_ids[i].name , mtd->name); break; } } - /* Initialize state and spinlock */ + /* + * check ECC mode, default to software + * if 3byte/512byte hardware ECC is selected and we have 256 byte pagesize + * fallback to software ECC + */ + this->eccsize = 256; /* set default eccsize */ + + switch (this->eccmode) { + + case NAND_ECC_HW3_512: + if (mtd->oobblock == 256) { + printk (KERN_WARNING "512 byte HW ECC not possible on 256 Byte pagesize, fallback to SW ECC \n"); + this->eccmode = NAND_ECC_SOFT; + this->calculate_ecc = nand_calculate_ecc; + this->correct_data = nand_correct_data; + break; + } else + this->eccsize = 512; /* set eccsize to 512 and fall through for function check */ + + case NAND_ECC_HW3_256: + if (this->calculate_ecc && this->correct_data && this->enable_hwecc) + break; + printk (KERN_WARNING "No ECC functions supplied, Hardware ECC not possible\n"); + BUG(); + + case NAND_ECC_NONE: + printk (KERN_WARNING "NAND_ECC_NONE selected by board driver. This is not recommended !!\n"); + this->eccmode = NAND_ECC_NONE; + break; + + case NAND_ECC_SOFT: + this->calculate_ecc = nand_calculate_ecc; + this->correct_data = nand_correct_data; + break; + + default: + printk (KERN_WARNING "Invalid NAND_ECC_MODE %d\n", this->eccmode); + BUG(); + } + + /* Initialize state, waitqueue and spinlock */ this->state = FL_READY; - spin_lock_init(&this->chip_lock); + init_waitqueue_head (&this->wq); + spin_lock_init (&this->chip_lock); /* De-select the device */ nand_deselect (); @@ -1344,7 +1352,6 @@ /* Fill in remaining MTD driver data */ mtd->type = MTD_NANDFLASH; mtd->flags = MTD_CAP_NANDFLASH | MTD_ECC; - mtd->module = THIS_MODULE; mtd->ecctype = MTD_ECC_SW; mtd->erase = nand_erase; mtd->point = NULL; @@ -1357,18 +1364,20 @@ mtd->write_oob = nand_write_oob; mtd->readv = NULL; mtd->writev = nand_writev; + mtd->writev_ecc = nand_writev_ecc; mtd->sync = nand_sync; mtd->lock = NULL; mtd->unlock = NULL; mtd->suspend = NULL; mtd->resume = NULL; + mtd->owner = THIS_MODULE; /* Return happy */ return 0; } -EXPORT_SYMBOL(nand_scan); +EXPORT_SYMBOL (nand_scan); -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Steven J. Hill <sjhill@cotw.com"); -MODULE_DESCRIPTION("Generic NAND flash driver code"); +MODULE_LICENSE ("GPL"); +MODULE_AUTHOR ("Steven J. Hill <sjhill@realitydiluted.com>, Thomas Gleixner <tglx@linutronix.de>"); +MODULE_DESCRIPTION ("Generic NAND flash driver code"); diff -Nru a/drivers/mtd/nand/nand_ecc.c b/drivers/mtd/nand/nand_ecc.c --- a/drivers/mtd/nand/nand_ecc.c Mon Jun 9 23:16:09 2003 +++ b/drivers/mtd/nand/nand_ecc.c Mon Jun 9 23:16:09 2003 @@ -1,14 +1,14 @@ /* * drivers/mtd/nand_ecc.c * - * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) + * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) * Toshiba America Electronics Components, Inc. * - * $Id: nand_ecc.c,v 1.6 2001/06/28 10:52:26 dwmw2 Exp $ + * $Id: nand_ecc.c,v 1.9 2003/02/20 13:34:19 sjhill Exp $ * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * version 2.1 as published by the Free Software Foundation. * * This file contains an ECC algorithm from Toshiba that detects and * corrects 1 bit errors in a 256 byte block of data. @@ -209,5 +209,5 @@ EXPORT_SYMBOL(nand_correct_data); MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Steven J. Hill <sjhill@cotw.com>"); +MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com>"); MODULE_DESCRIPTION("Generic NAND ECC support"); diff -Nru a/drivers/mtd/nand/nand_ids.c b/drivers/mtd/nand/nand_ids.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/mtd/nand/nand_ids.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,56 @@ +/* + * drivers/mtd/nandids.c + * + * Copyright (C) 2002 Thomas Gleixner (tglx@linutronix.de) + * + * + * $Id: nand_ids.c,v 1.4 2003/05/21 15:15:08 dwmw2 Exp $ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ +#include <linux/module.h> +#include <linux/mtd/nand.h> + +/* +* Chip ID list +*/ +struct nand_flash_dev nand_flash_ids[] = { + {"NAND 1MiB 5V", 0x6e, 20, 0x1000, 1}, + {"NAND 2MiB 5V", 0x64, 21, 0x1000, 1}, + {"NAND 4MiB 5V", 0x6b, 22, 0x2000, 0}, + {"NAND 1MiB 3,3V", 0xe8, 20, 0x1000, 1}, + {"NAND 1MiB 3,3V", 0xec, 20, 0x1000, 1}, + {"NAND 2MiB 3,3V", 0xea, 21, 0x1000, 1}, + {"NAND 4MiB 3,3V", 0xd5, 22, 0x2000, 0}, + {"NAND 4MiB 3,3V", 0xe3, 22, 0x2000, 0}, + {"NAND 4MiB 3,3V", 0xe5, 22, 0x2000, 0}, + {"NAND 8MiB 3,3V", 0xd6, 23, 0x2000, 0}, + {"NAND 8MiB 3,3V", 0xe6, 23, 0x2000, 0}, + {"NAND 16MiB 3,3V", 0x73, 24, 0x4000, 0}, + {"NAND 32MiB 3,3V", 0x75, 25, 0x4000, 0}, + {"NAND 64MiB 3,3V", 0x76, 26, 0x4000, 0}, + {"NAND 128MiB 3,3V", 0x79, 27, 0x4000, 0}, + {NULL,} +}; + +/* +* Manufacturer ID list +*/ +struct nand_manufacturers nand_manuf_ids[] = { + {NAND_MFR_TOSHIBA, "Toshiba"}, + {NAND_MFR_SAMSUNG, "Samsung"}, + {NAND_MFR_FUJITSU, "Fujitsu"}, + {NAND_MFR_NATIONAL, "National"}, + {0x0, "Unknown"} +}; + + +EXPORT_SYMBOL (nand_manuf_ids); +EXPORT_SYMBOL (nand_flash_ids); + +MODULE_LICENSE ("GPL"); +MODULE_AUTHOR ("Thomas Gleixner <tglx@linutronix.de>"); +MODULE_DESCRIPTION ("Nand device & manufacturer ID's"); diff -Nru a/drivers/mtd/nand/spia.c b/drivers/mtd/nand/spia.c --- a/drivers/mtd/nand/spia.c Mon Jun 9 23:16:14 2003 +++ b/drivers/mtd/nand/spia.c Mon Jun 9 23:16:14 2003 @@ -1,9 +1,14 @@ /* * drivers/mtd/nand/spia.c * - * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) + * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) * - * $Id: spia.c,v 1.12 2001/10/02 15:05:14 dwmw2 Exp $ + * + * 10-29-2001 TG change to support hardwarespecific access + * to controllines (due to change in nand.c) + * page_cache added + * + * $Id: spia.c,v 1.19 2003/04/20 07:24:40 gleixner Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -68,6 +73,7 @@ const static struct mtd_partition partition_info[] = { { .name = "SPIA flash partition 1", + .offset = 0, .size = 2*1024*1024 }, { @@ -78,6 +84,25 @@ }; #define NUM_PARTITIONS 2 + +/* + * hardware specific access to control-lines +*/ +void spia_hwcontrol(int cmd){ + + switch(cmd){ + + case NAND_CTL_SETCLE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) |= 0x01; break; + case NAND_CTL_CLRCLE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) &= ~0x01; break; + + case NAND_CTL_SETALE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) |= 0x02; break; + case NAND_CTL_CLRALE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) &= ~0x02; break; + + case NAND_CTL_SETNCE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) &= ~0x04; break; + case NAND_CTL_CLRNCE: (*(volatile unsigned char *) (spia_io_base + spia_pedr)) |= 0x04; break; + } +} + /* * Main initialization routine */ @@ -110,11 +135,12 @@ (*(volatile unsigned char *) (spia_io_base + spia_peddr)) = 0x07; /* Set address of NAND IO lines */ - this->IO_ADDR = spia_fio_base; - this->CTRL_ADDR = spia_io_base + spia_pedr; - this->CLE = 0x01; - this->ALE = 0x02; - this->NCE = 0x04; + this->IO_ADDR_R = spia_fio_base; + this->IO_ADDR_W = spia_fio_base; + /* Set address of hardware control function */ + this->hwcontrol = spia_hwcontrol; + /* 15 us command delay time */ + this->chip_delay = 15; /* Scan to find existence of the device */ if (nand_scan (spia_mtd)) { @@ -159,5 +185,5 @@ #endif MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Steven J. Hill <sjhill@cotw.com"); +MODULE_AUTHOR("Steven J. Hill <sjhill@realitydiluted.com"); MODULE_DESCRIPTION("Board-specific glue layer for NAND flash on SPIA board"); diff -Nru a/drivers/mtd/nftlcore.c b/drivers/mtd/nftlcore.c --- a/drivers/mtd/nftlcore.c Mon Jun 9 23:16:05 2003 +++ b/drivers/mtd/nftlcore.c Mon Jun 9 23:16:05 2003 @@ -1,7 +1,7 @@ /* Linux driver for NAND Flash Translation Layer */ /* (c) 1999 Machine Vision Holdings, Inc. */ /* Author: David Woodhouse <dwmw2@infradead.org> */ -/* $Id: nftlcore.c,v 1.82 2001/10/02 15:05:11 dwmw2 Exp $ */ +/* $Id: nftlcore.c,v 1.92 2003/05/23 11:41:47 dwmw2 Exp $ */ /* The contents of this file are distributed under the GNU General @@ -23,15 +23,13 @@ #include <linux/slab.h> #include <linux/sched.h> #include <linux/init.h> -#include <linux/blkpg.h> -#include <linux/buffer_head.h> +#include <linux/hdreg.h> -#ifdef CONFIG_KMOD #include <linux/kmod.h> -#endif #include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> #include <linux/mtd/nftl.h> -#include <linux/mtd/compatmac.h> +#include <linux/mtd/blktrans.h> /* maximum number of loops while examining next block, to have a chance to detect consistency problems (they should never happen @@ -39,154 +37,97 @@ #define MAX_LOOPS 10000 -/* NFTL block device stuff */ -#define MAJOR_NR NFTL_MAJOR - -#include <linux/blk.h> -#include <linux/hdreg.h> - -/* Linux-specific block device functions */ - -struct NFTLrecord *NFTLs[MAX_NFTLS]; -static struct request_queue nftl_queue; - -static void NFTL_setup(struct mtd_info *mtd) +static void nftl_add_mtd(struct mtd_blktrans_ops *tr, struct mtd_info *mtd) { - int i; struct NFTLrecord *nftl; unsigned long temp; - int firstfree = -1; - struct gendisk *gd; - - DEBUG(MTD_DEBUG_LEVEL1,"NFTL_setup\n"); - for (i = 0; i < MAX_NFTLS; i++) { - if (!NFTLs[i] && firstfree == -1) - firstfree = i; - else if (NFTLs[i] && NFTLs[i]->mtd == mtd) { - /* This is a Spare Media Header for an NFTL we've already found */ - DEBUG(MTD_DEBUG_LEVEL1, "MTD already mounted as NFTL\n"); - return; - } - } - if (firstfree == -1) { - printk(KERN_WARNING "No more NFTL slot available\n"); + if (mtd->ecctype != MTD_ECC_RS_DiskOnChip) return; - } + + DEBUG(MTD_DEBUG_LEVEL1, "NFTL: add_mtd for %s\n", mtd->name); nftl = kmalloc(sizeof(struct NFTLrecord), GFP_KERNEL); - gd = alloc_disk(1 << NFTL_PARTN_BITS); - if (!nftl || !gd) { - kfree(nftl); - put_disk(gd); - printk(KERN_WARNING "Out of memory for NFTL data structures\n"); + + if (!nftl) { + printk(KERN_WARNING "NFTL: out of memory for data structures\n"); return; } + memset(nftl, 0, sizeof(*nftl)); - init_MUTEX(&nftl->mutex); - - /* get physical parameters */ - nftl->EraseSize = mtd->erasesize; - nftl->nb_blocks = mtd->size / mtd->erasesize; - nftl->mtd = mtd; + nftl->mbd.mtd = mtd; + nftl->mbd.devnum = -1; + nftl->mbd.blksize = 512; + nftl->mbd.tr = tr; if (NFTL_mount(nftl) < 0) { - printk(KERN_WARNING "Could not mount NFTL device\n"); + printk(KERN_WARNING "NFTL: could not mount device\n"); kfree(nftl); - put_disk(gd); return; } /* OK, it's a new one. Set up all the data structures. */ -#ifdef PSYCHO_DEBUG - printk("Found new NFTL nftl%c\n", firstfree + 'a'); -#endif - /* linux stuff */ + /* Calculate geometry */ nftl->cylinders = 1024; nftl->heads = 16; temp = nftl->cylinders * nftl->heads; - nftl->sectors = nftl->nr_sects / temp; - if (nftl->nr_sects % temp) { + nftl->sectors = nftl->mbd.size / temp; + if (nftl->mbd.size % temp) { nftl->sectors++; temp = nftl->cylinders * nftl->sectors; - nftl->heads = nftl->nr_sects / temp; + nftl->heads = nftl->mbd.size / temp; - if (nftl->nr_sects % temp) { + if (nftl->mbd.size % temp) { nftl->heads++; temp = nftl->heads * nftl->sectors; - nftl->cylinders = nftl->nr_sects / temp; + nftl->cylinders = nftl->mbd.size / temp; } } - if (nftl->nr_sects != nftl->heads * nftl->cylinders * nftl->sectors) { - printk(KERN_WARNING "Cannot calculate an NFTL geometry to " - "match size of 0x%lx.\n", nftl->nr_sects); - printk(KERN_WARNING "Using C:%d H:%d S:%d (== 0x%lx sects)\n", - nftl->cylinders, nftl->heads , nftl->sectors, - (long)nftl->cylinders * (long)nftl->heads * (long)nftl->sectors ); - - /* Oh no we don't have nftl->nr_sects = nftl->heads * nftl->cylinders * nftl->sectors; */ - } - NFTLs[firstfree] = nftl; - sprintf(gd->disk_name, "nftl%c", 'a' + firstfree); - gd->major = MAJOR_NR; - gd->first_minor = firstfree << NFTL_PARTN_BITS; - set_capacity(gd, nftl->nr_sects); - nftl->disk = gd; - gd->private_data = nftl; - gd->queue = &nftl_queue; - add_disk(gd); + if (nftl->mbd.size != nftl->heads * nftl->cylinders * nftl->sectors) { + /* + Oh no we don't have + mbd.size == heads * cylinders * sectors + */ + printk(KERN_WARNING "NFTL: cannot calculate a geometry to " + "match size of 0x%lx.\n", nftl->mbd.size); + printk(KERN_WARNING "NFTL: using C:%d H:%d S:%d " + "(== 0x%lx sects)\n", + nftl->cylinders, nftl->heads , nftl->sectors, + (long)nftl->cylinders * (long)nftl->heads * + (long)nftl->sectors ); + } + + if (add_mtd_blktrans_dev) { + if (nftl->ReplUnitTable) + kfree(nftl->ReplUnitTable); + if (nftl->EUNtable) + kfree(nftl->EUNtable); + kfree(nftl); + return; + } +#ifdef PSYCHO_DEBUG + printk(KERN_INFO "NFTL: Found new nftl%c\n", nftl->mbd.devnum + 'a'); +#endif } -static void NFTL_unsetup(int i) +static void nftl_remove_dev(struct mtd_blktrans_dev *dev) { - struct NFTLrecord *nftl = NFTLs[i]; + struct NFTLrecord *nftl = (void *)dev; - DEBUG(MTD_DEBUG_LEVEL1, "NFTL_unsetup %d\n", i); - - NFTLs[i] = NULL; - + DEBUG(MTD_DEBUG_LEVEL1, "NFTL: remove_dev (i=%d)\n", dev->devnum); + + del_mtd_blktrans_dev(dev); if (nftl->ReplUnitTable) kfree(nftl->ReplUnitTable); if (nftl->EUNtable) kfree(nftl->EUNtable); - del_gendisk(nftl->disk); - put_disk(nftl->disk); kfree(nftl); } -/* Search the MTD device for NFTL partitions */ -static void NFTL_notify_add(struct mtd_info *mtd) -{ - DEBUG(MTD_DEBUG_LEVEL1, "NFTL_notify_add for %s\n", mtd->name); - - if (mtd) { - if (!mtd->read_oob) { - /* If this MTD doesn't have out-of-band data, - then there's no point continuing */ - DEBUG(MTD_DEBUG_LEVEL1, "No OOB data, quitting\n"); - return; - } - DEBUG(MTD_DEBUG_LEVEL3, "mtd->read = %p, size = %d, erasesize = %d\n", - mtd->read, mtd->size, mtd->erasesize); - - NFTL_setup(mtd); - } -} - -static void NFTL_notify_remove(struct mtd_info *mtd) -{ - int i; - - for (i = 0; i < MAX_NFTLS; i++) { - if (NFTLs[i] && NFTLs[i]->mtd == mtd) - NFTL_unsetup(i); - } -} - #ifdef CONFIG_NFTL_RW /* Actual NFTL access routines */ @@ -268,7 +209,7 @@ targetEUN = thisEUN; for (block = 0; block < nftl->EraseSize / 512; block ++) { - MTD_READOOB(nftl->mtd, + MTD_READOOB(nftl->mbd.mtd, (thisEUN * nftl->EraseSize) + (block * 512), 16 , &retlen, (char *)&oob); if (block == 2) { @@ -385,7 +326,7 @@ chain by selecting the longer one */ oob.u.c.FoldMark = oob.u.c.FoldMark1 = cpu_to_le16(FOLD_MARK_IN_PROGRESS); oob.u.c.unused = 0xffffffff; - MTD_WRITEOOB(nftl->mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8, + MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 2 * 512 + 8, 8, &retlen, (char *)&oob.u); } @@ -409,17 +350,17 @@ if (BlockMap[block] == BLOCK_NIL) continue; - ret = MTD_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block]) - + (block * 512), 512, &retlen, movebuf, (char *)&oob); + ret = MTD_READECC(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512), + 512, &retlen, movebuf, (char *)&oob, NAND_ECC_DISKONCHIP); if (ret < 0) { - ret = MTD_READECC(nftl->mtd, (nftl->EraseSize * BlockMap[block]) + ret = MTD_READECC(nftl->mbd.mtd, (nftl->EraseSize * BlockMap[block]) + (block * 512), 512, &retlen, - movebuf, (char *)&oob); + movebuf, (char *)&oob, NAND_ECC_DISKONCHIP); if (ret != -EIO) printk("Error went away on retry.\n"); } - MTD_WRITEECC(nftl->mtd, (nftl->EraseSize * targetEUN) + (block * 512), - 512, &retlen, movebuf, (char *)&oob); + MTD_WRITEECC(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + (block * 512), + 512, &retlen, movebuf, (char *)&oob, NAND_ECC_DISKONCHIP); } /* add the header so that it is now a valid chain */ @@ -427,7 +368,7 @@ = cpu_to_le16(thisVUC); oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = 0xffff; - MTD_WRITEOOB(nftl->mtd, (nftl->EraseSize * targetEUN) + 8, + MTD_WRITEOOB(nftl->mbd.mtd, (nftl->EraseSize * targetEUN) + 8, 8, &retlen, (char *)&oob.u); /* OK. We've moved the whole lot into the new block. Now we have to free the original blocks. */ @@ -547,7 +488,7 @@ lastEUN = writeEUN; - MTD_READOOB(nftl->mtd, (writeEUN * nftl->EraseSize) + blockofs, + MTD_READOOB(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs, 8, &retlen, (char *)&bci); DEBUG(MTD_DEBUG_LEVEL2, "Status of block %d in EUN %d is %x\n", @@ -635,12 +576,12 @@ nftl->ReplUnitTable[writeEUN] = BLOCK_NIL; /* ... and on the flash itself */ - MTD_READOOB(nftl->mtd, writeEUN * nftl->EraseSize + 8, 8, + MTD_READOOB(nftl->mbd.mtd, writeEUN * nftl->EraseSize + 8, 8, &retlen, (char *)&oob.u); oob.u.a.VirtUnitNum = oob.u.a.SpareVirtUnitNum = cpu_to_le16(thisVUC); - MTD_WRITEOOB(nftl->mtd, writeEUN * nftl->EraseSize + 8, 8, + MTD_WRITEOOB(nftl->mbd.mtd, writeEUN * nftl->EraseSize + 8, 8, &retlen, (char *)&oob.u); /* we link the new block to the chain only after the @@ -650,13 +591,13 @@ /* Both in our cache... */ nftl->ReplUnitTable[lastEUN] = writeEUN; /* ... and on the flash itself */ - MTD_READOOB(nftl->mtd, (lastEUN * nftl->EraseSize) + 8, + MTD_READOOB(nftl->mbd.mtd, (lastEUN * nftl->EraseSize) + 8, 8, &retlen, (char *)&oob.u); oob.u.a.ReplUnitNum = oob.u.a.SpareReplUnitNum = cpu_to_le16(writeEUN); - MTD_WRITEOOB(nftl->mtd, (lastEUN * nftl->EraseSize) + 8, + MTD_WRITEOOB(nftl->mbd.mtd, (lastEUN * nftl->EraseSize) + 8, 8, &retlen, (char *)&oob.u); } @@ -669,8 +610,10 @@ return 0xffff; } -static int NFTL_writeblock(struct NFTLrecord *nftl, unsigned block, char *buffer) +static int nftl_writeblock(struct mtd_blktrans_dev *mbd, unsigned long block, + char *buffer) { + struct NFTLrecord *nftl = (void *)mbd; u16 writeEUN; unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1); size_t retlen; @@ -685,16 +628,18 @@ return 1; } - MTD_WRITEECC(nftl->mtd, (writeEUN * nftl->EraseSize) + blockofs, - 512, &retlen, (char *)buffer, (char *)eccbuf); + MTD_WRITEECC(nftl->mbd.mtd, (writeEUN * nftl->EraseSize) + blockofs, + 512, &retlen, (char *)buffer, (char *)eccbuf, NAND_ECC_DISKONCHIP); /* no need to write SECTOR_USED flags since they are written in mtd_writeecc */ return 0; } #endif /* CONFIG_NFTL_RW */ -static int NFTL_readblock(struct NFTLrecord *nftl, unsigned block, char *buffer) +static int nftl_readblock(struct mtd_blktrans_dev *mbd, unsigned long block, + char *buffer) { + struct NFTLrecord *nftl = (void *)mbd; u16 lastgoodEUN; u16 thisEUN = nftl->EUNtable[block / (nftl->EraseSize / 512)]; unsigned long blockofs = (block * 512) & (nftl->EraseSize - 1); @@ -707,7 +652,7 @@ if (thisEUN != BLOCK_NIL) { while (thisEUN < nftl->nb_blocks) { - if (MTD_READOOB(nftl->mtd, (thisEUN * nftl->EraseSize) + blockofs, + if (MTD_READOOB(nftl->mbd.mtd, (thisEUN * nftl->EraseSize) + blockofs, 8, &retlen, (char *)&bci) < 0) status = SECTOR_IGNORE; else @@ -726,13 +671,13 @@ case SECTOR_IGNORE: break; default: - printk("Unknown status for block %d in EUN %d: %x\n", + printk("Unknown status for block %ld in EUN %d: %x\n", block, thisEUN, status); break; } if (!silly--) { - printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%x\n", + printk(KERN_WARNING "Infinite loop in Virtual Unit Chain 0x%lx\n", block / (nftl->EraseSize / 512)); return 1; } @@ -748,15 +693,18 @@ loff_t ptr = (lastgoodEUN * nftl->EraseSize) + blockofs; size_t retlen; u_char eccbuf[6]; - if (MTD_READECC(nftl->mtd, ptr, 512, &retlen, buffer, eccbuf)) + if (MTD_READECC(nftl->mbd.mtd, ptr, 512, &retlen, buffer, eccbuf, NAND_ECC_DISKONCHIP)) return -EIO; } return 0; } -static int nftl_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) +static int nftl_ioctl(struct mtd_blktrans_dev *dev, + struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg) { - struct NFTLrecord *nftl = inode->i_bdev->bd_disk->private_data; + struct NFTLrecord *nftl = (void *)dev; + switch (cmd) { case HDIO_GETGEO: { struct hd_geometry g; @@ -764,149 +712,15 @@ g.heads = nftl->heads; g.sectors = nftl->sectors; g.cylinders = nftl->cylinders; - g.start = get_start_sect(inode->i_bdev); + g.start = 0; return copy_to_user((void *)arg, &g, sizeof g) ? -EFAULT : 0; } - case BLKFLSBUF: - fsync_bdev(inode->i_bdev); - invalidate_bdev(inode->i_bdev, 0); - if (nftl->mtd->sync) - nftl->mtd->sync(nftl->mtd); - return 0; - default: - return -EINVAL; - } -} - -void nftl_request(struct request_queue *q) -{ - struct request *req; - - while ((req = elv_next_request(q)) != NULL) { - unsigned block = req->sector; - unsigned nsect = req->current_nr_sectors; - char *buffer = req->buffer; - struct NFTLrecord *nftl = req->rq_disk->private_data; - int res = 1; /* succeed */ - - /* We can do this because the generic code knows not to - touch the request at the head of the queue */ - spin_unlock_irq(q->queue_lock); - - DEBUG(MTD_DEBUG_LEVEL2, "NFTL_request\n"); - DEBUG(MTD_DEBUG_LEVEL3, - "NFTL %s request, from sector 0x%04llx for %d sectors\n", - (req->cmd == READ) ? "Read " : "Write", - (unsigned long long)req->sector, req->current_nr_sectors); - - DEBUG(MTD_DEBUG_LEVEL3, "Waiting for mutex\n"); - down(&nftl->mutex); - DEBUG(MTD_DEBUG_LEVEL3, "Got mutex\n"); - - if (block + nsect > get_capacity(nftl->disk)) { - /* access past the end of device */ - printk("%s: bad access: block = %d, count = %d\n", - nftl->disk->disk_name, block, nsect); - up(&nftl->mutex); - res = 0; /* fail */ - goto repeat; - } - - if (req->cmd == READ) { - DEBUG(MTD_DEBUG_LEVEL2, "NFTL read request of 0x%x sectors @ %x " - "(req->nr_sectors == %lx)\n", nsect, block, req->nr_sectors); - - for ( ; nsect > 0; nsect-- , block++, buffer += 512) { - /* Read a single sector to req->buffer + (512 * i) */ - if (NFTL_readblock(nftl, block, buffer)) { - DEBUG(MTD_DEBUG_LEVEL2, "NFTL read request failed\n"); - up(&nftl->mutex); - res = 0; - goto repeat; - } - } - DEBUG(MTD_DEBUG_LEVEL2,"NFTL read request completed OK\n"); - up(&nftl->mutex); - goto repeat; - } else if (rq_data_dir(req) == WRITE) { - DEBUG(MTD_DEBUG_LEVEL2, "NFTL write request of 0x%x sectors @ %x " - "(req->nr_sectors == %lx)\n", nsect, block, - req->nr_sectors); -#ifdef CONFIG_NFTL_RW - for ( ; nsect > 0; nsect-- , block++, buffer += 512) { - /* Read a single sector to req->buffer + (512 * i) */ - if (NFTL_writeblock(nftl, block, buffer)) { - DEBUG(MTD_DEBUG_LEVEL1,"NFTL write request failed\n"); - up(&nftl->mutex); - res = 0; - goto repeat; - } - } - DEBUG(MTD_DEBUG_LEVEL2,"NFTL write request completed OK\n"); -#else - res = 0; /* Writes always fail */ -#endif /* CONFIG_NFTL_RW */ - up(&nftl->mutex); - goto repeat; - } else { - DEBUG(MTD_DEBUG_LEVEL0, "NFTL unknown request\n"); - up(&nftl->mutex); - res = 0; - goto repeat; - } - repeat: - DEBUG(MTD_DEBUG_LEVEL3, "end_request(%d)\n", res); - spin_lock_irq(q->queue_lock); - end_request(req, res); + default: + return -ENOTTY; } } -static struct kobject *nftl_probe(dev_t dev, int *part, void *data) -{ - request_module("docprobe"); - return NULL; -} - -static int nftl_open(struct inode *ip, struct file *fp) -{ - struct NFTLrecord *thisNFTL = ip->i_bdev->bd_disk->private_data; - - DEBUG(MTD_DEBUG_LEVEL2,"NFTL_open\n"); - if (!thisNFTL) - return -ENODEV; - -#ifndef CONFIG_NFTL_RW - if (fp->f_mode & FMODE_WRITE) - return -EROFS; -#endif /* !CONFIG_NFTL_RW */ - - if (!get_mtd_device(thisNFTL->mtd, -1)) - return /* -E'SBUGGEREDOFF */ -ENXIO; - - return 0; -} - -static int nftl_release(struct inode *inode, struct file *fp) -{ - struct NFTLrecord *thisNFTL = inode->i_bdev->bd_disk->private_data; - - DEBUG(MTD_DEBUG_LEVEL2, "NFTL_release\n"); - - if (thisNFTL->mtd->sync) - thisNFTL->mtd->sync(thisNFTL->mtd); - - put_mtd_device(thisNFTL->mtd); - - return 0; -} -static struct block_device_operations nftl_fops = -{ - .owner = THIS_MODULE, - .open = nftl_open, - .release = nftl_release, - .ioctl = nftl_ioctl -}; /**************************************************************************** * @@ -914,40 +728,33 @@ * ****************************************************************************/ -static struct mtd_notifier nftl_notifier = { - .add = NFTL_notify_add, - .remove = NFTL_notify_remove + +struct mtd_blktrans_ops nftl_tr = { + .name = "nftl", + .major = NFTL_MAJOR, + .part_bits = NFTL_PARTN_BITS, + .ioctl = nftl_ioctl, + .readsect = nftl_readblock, +#ifdef CONFIG_NFTL_RW + .writesect = nftl_writeblock, +#endif + .add_mtd = nftl_add_mtd, + .remove_dev = nftl_remove_dev, + .owner = THIS_MODULE, }; extern char nftlmountrev[]; -static spinlock_t nftl_lock = SPIN_LOCK_UNLOCKED; int __init init_nftl(void) { + printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.92 $, nftlmount.c %s\n", nftlmountrev); -#ifdef PRERELEASE - printk(KERN_INFO "NFTL driver: nftlcore.c $Revision: 1.82 $, nftlmount.c %s\n", nftlmountrev); -#endif - - if (register_blkdev(MAJOR_NR, "nftl")) - return -EBUSY; - - blk_register_region(MKDEV(MAJOR_NR, 0), 256, - THIS_MODULE, nftl_probe, NULL, NULL); - - blk_init_queue(&nftl_queue, &nftl_request, &nftl_lock); - - register_mtd_user(&nftl_notifier); - - return 0; + return register_mtd_blktrans(&nftl_tr); } static void __exit cleanup_nftl(void) { - unregister_mtd_user(&nftl_notifier); - blk_unregister_region(MKDEV(MAJOR_NR, 0), 256); - unregister_blkdev(MAJOR_NR, "nftl"); - blk_cleanup_queue(&nftl_queue); + deregister_mtd_blktrans(&nftl_tr); } module_init(init_nftl); diff -Nru a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c --- a/drivers/mtd/nftlmount.c Mon Jun 9 23:16:15 2003 +++ b/drivers/mtd/nftlmount.c Mon Jun 9 23:16:15 2003 @@ -4,7 +4,7 @@ * Author: Fabrice Bellard (fabrice.bellard@netgem.com) * Copyright (C) 2000 Netgem S.A. * - * $Id: nftlmount.c,v 1.25 2001/11/30 16:46:27 dwmw2 Exp $ + * $Id: nftlmount.c,v 1.34 2003/05/21 10:54:10 dwmw2 Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,23 +22,16 @@ */ #include <linux/kernel.h> -#include <linux/module.h> #include <asm/errno.h> -#include <asm/io.h> -#include <asm/uaccess.h> -#include <linux/miscdevice.h> -#include <linux/pci.h> #include <linux/delay.h> #include <linux/slab.h> -#include <linux/sched.h> -#include <linux/init.h> #include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> #include <linux/mtd/nftl.h> -#include <linux/mtd/compatmac.h> #define SECTORSIZE 512 -char nftlmountrev[]="$Revision: 1.25 $"; +char nftlmountrev[]="$Revision: 1.34 $"; /* find_boot_record: Find the NFTL Media Header and its Spare copy which contains the * various device information of the NFTL partition and Bad Unit Table. Update @@ -50,11 +43,16 @@ struct nftl_uci1 h1; struct nftl_oob oob; unsigned int block, boot_record_count = 0; - int retlen; + size_t retlen; u8 buf[SECTORSIZE]; struct NFTLMediaHeader *mh = &nftl->MediaHdr; unsigned int i; + /* Assume logical EraseSize == physical erasesize for starting the scan. + We'll sort it out later if we find a MediaHeader which says otherwise */ + nftl->EraseSize = nftl->mbd.mtd->erasesize; + nftl->nb_blocks = nftl->mbd.mtd->size / nftl->EraseSize; + nftl->MediaUnit = BLOCK_NIL; nftl->SpareMediaUnit = BLOCK_NIL; @@ -64,12 +62,12 @@ /* Check for ANAND header first. Then can whinge if it's found but later checks fail */ - if ((ret = MTD_READ(nftl->mtd, block * nftl->EraseSize, SECTORSIZE, &retlen, buf))) { + if ((ret = MTD_READ(nftl->mbd.mtd, block * nftl->EraseSize, SECTORSIZE, &retlen, buf))) { static int warncount = 5; if (warncount) { printk(KERN_WARNING "Block read at 0x%x of mtd%d failed: %d\n", - block * nftl->EraseSize, nftl->mtd->index, ret); + block * nftl->EraseSize, nftl->mbd.mtd->index, ret); if (!--warncount) printk(KERN_WARNING "Further failures for this block will not be printed\n"); } @@ -80,16 +78,16 @@ /* ANAND\0 not found. Continue */ #if 0 printk(KERN_DEBUG "ANAND header not found at 0x%x in mtd%d\n", - block * nftl->EraseSize, nftl->mtd->index); + block * nftl->EraseSize, nftl->mbd.mtd->index); #endif continue; } /* To be safer with BIOS, also use erase mark as discriminant */ - if ((ret = MTD_READOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, + if ((ret = MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, &retlen, (char *)&h1) < 0)) { printk(KERN_WARNING "ANAND header found at 0x%x in mtd%d, but OOB data read failed (err %d)\n", - block * nftl->EraseSize, nftl->mtd->index, ret); + block * nftl->EraseSize, nftl->mbd.mtd->index, ret); continue; } @@ -99,29 +97,28 @@ */ if (le16_to_cpu(h1.EraseMark | h1.EraseMark1) != ERASE_MARK) { printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but erase mark not present (0x%04x,0x%04x instead)\n", - block * nftl->EraseSize, nftl->mtd->index, + block * nftl->EraseSize, nftl->mbd.mtd->index, le16_to_cpu(h1.EraseMark), le16_to_cpu(h1.EraseMark1)); continue; } /* Finally reread to check ECC */ - if ((ret = MTD_READECC(nftl->mtd, block * nftl->EraseSize, SECTORSIZE, - &retlen, buf, (char *)&oob) < 0)) { + if ((ret = MTD_READECC(nftl->mbd.mtd, block * nftl->EraseSize, SECTORSIZE, + &retlen, buf, (char *)&oob, NAND_ECC_DISKONCHIP) < 0)) { printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but ECC read failed (err %d)\n", - block * nftl->EraseSize, nftl->mtd->index, ret); + block * nftl->EraseSize, nftl->mbd.mtd->index, ret); continue; } /* Paranoia. Check the ANAND header is still there after the ECC read */ if (memcmp(buf, "ANAND", 6)) { printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but went away on reread!\n", - block * nftl->EraseSize, nftl->mtd->index); + block * nftl->EraseSize, nftl->mbd.mtd->index); printk(KERN_NOTICE "New data are: %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]); continue; } #endif - /* OK, we like it. */ if (boot_record_count) { @@ -131,11 +128,19 @@ printk(KERN_NOTICE "NFTL Media Headers at 0x%x and 0x%x disagree.\n", nftl->MediaUnit * nftl->EraseSize, block * nftl->EraseSize); /* if (debug) Print both side by side */ - return -1; + if (boot_record_count < 2) { + /* We haven't yet seen two real ones */ + return -1; + } + continue; } if (boot_record_count == 1) nftl->SpareMediaUnit = block; + /* Mark this boot record (NFTL MediaHeader) block as reserved */ + nftl->ReplUnitTable[block] = BLOCK_RESERVED; + + boot_record_count++; continue; } @@ -144,12 +149,18 @@ memcpy(mh, buf, sizeof(struct NFTLMediaHeader)); /* Do some sanity checks on it */ - if (mh->UnitSizeFactor != 0xff) { - printk(KERN_NOTICE "Sorry, we don't support UnitSizeFactor " - "of != 1 yet.\n"); + if (mh->UnitSizeFactor == 0) { + printk(KERN_NOTICE "NFTL: UnitSizeFactor 0x00 detected. This violates the spec but we think we know what it means...\n"); + } else if (mh->UnitSizeFactor < 0xfc) { + printk(KERN_NOTICE "Sorry, we don't support UnitSizeFactor 0x%02x\n", + mh->UnitSizeFactor); return -1; + } else if (mh->UnitSizeFactor != 0xff) { + printk(KERN_NOTICE "WARNING: Support for NFTL with UnitSizeFactor 0x%02x is experimental\n", + mh->UnitSizeFactor); + nftl->EraseSize = nftl->mbd.mtd->erasesize << (0xff - mh->UnitSizeFactor); + nftl->nb_blocks = nftl->mbd.mtd->size / nftl->EraseSize; } - nftl->nb_boot_blocks = le16_to_cpu(mh->FirstPhysicalEUN); if ((nftl->nb_boot_blocks + 2) >= nftl->nb_blocks) { printk(KERN_NOTICE "NFTL Media Header sanity check failed:\n"); @@ -166,21 +177,51 @@ return -1; } - nftl->nr_sects = nftl->numvunits * (nftl->EraseSize / SECTORSIZE); - + nftl->mbd.size = nftl->numvunits * (nftl->EraseSize / SECTORSIZE); + /* If we're not using the last sectors in the device for some reason, reduce nb_blocks accordingly so we forget they're there */ nftl->nb_blocks = le16_to_cpu(mh->NumEraseUnits) + le16_to_cpu(mh->FirstPhysicalEUN); + /* XXX: will be suppressed */ + nftl->lastEUN = nftl->nb_blocks - 1; + + /* memory alloc */ + nftl->EUNtable = kmalloc(nftl->nb_blocks * sizeof(u16), GFP_KERNEL); + if (!nftl->EUNtable) { + printk(KERN_NOTICE "NFTL: allocation of EUNtable failed\n"); + return -ENOMEM; + } + + nftl->ReplUnitTable = kmalloc(nftl->nb_blocks * sizeof(u16), GFP_KERNEL); + if (!nftl->ReplUnitTable) { + kfree(nftl->EUNtable); + printk(KERN_NOTICE "NFTL: allocation of ReplUnitTable failed\n"); + return -ENOMEM; + } + + /* mark the bios blocks (blocks before NFTL MediaHeader) as reserved */ + for (i = 0; i < nftl->nb_boot_blocks; i++) + nftl->ReplUnitTable[i] = BLOCK_RESERVED; + /* mark all remaining blocks as potentially containing data */ + for (; i < nftl->nb_blocks; i++) { + nftl->ReplUnitTable[i] = BLOCK_NOTEXPLORED; + } + + /* Mark this boot record (NFTL MediaHeader) block as reserved */ + nftl->ReplUnitTable[block] = BLOCK_RESERVED; + /* read the Bad Erase Unit Table and modify ReplUnitTable[] accordingly */ for (i = 0; i < nftl->nb_blocks; i++) { if ((i & (SECTORSIZE - 1)) == 0) { /* read one sector for every SECTORSIZE of blocks */ - if ((ret = MTD_READECC(nftl->mtd, block * nftl->EraseSize + - i + SECTORSIZE, SECTORSIZE, - &retlen, buf, (char *)&oob)) < 0) { + if ((ret = MTD_READECC(nftl->mbd.mtd, block * nftl->EraseSize + + i + SECTORSIZE, SECTORSIZE, &retlen, buf, + (char *)&oob, NAND_ECC_DISKONCHIP)) < 0) { printk(KERN_NOTICE "Read of bad sector table failed (err %d)\n", ret); + kfree(nftl->ReplUnitTable); + kfree(nftl->EUNtable); return -1; } } @@ -217,16 +258,16 @@ for (i = 0; i < len; i += SECTORSIZE) { /* we want to read the sector without ECC check here since a free sector does not have ECC syndrome on it yet */ - if (MTD_READ(nftl->mtd, address, SECTORSIZE, &retlen, buf) < 0) + if (MTD_READ(nftl->mbd.mtd, address, SECTORSIZE, &retlen, buf) < 0) return -1; if (memcmpb(buf, 0xff, SECTORSIZE) != 0) return -1; if (check_oob) { - if (MTD_READOOB(nftl->mtd, address, nftl->mtd->oobsize, + if (MTD_READOOB(nftl->mbd.mtd, address, nftl->mbd.mtd->oobsize, &retlen, buf) < 0) return -1; - if (memcmpb(buf, 0xff, nftl->mtd->oobsize) != 0) + if (memcmpb(buf, 0xff, nftl->mbd.mtd->oobsize) != 0) return -1; } address += SECTORSIZE; @@ -245,13 +286,13 @@ */ int NFTL_formatblock(struct NFTLrecord *nftl, int block) { - int retlen; + size_t retlen; unsigned int nb_erases, erase_mark; struct nftl_uci1 uci; struct erase_info *instr = &nftl->instr; /* Read the Unit Control Information #1 for Wear-Leveling */ - if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, + if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, &retlen, (char *)&uci) < 0) goto default_uci1; @@ -268,7 +309,7 @@ /* XXX: use async erase interface, XXX: test return code */ instr->addr = block * nftl->EraseSize; instr->len = nftl->EraseSize; - MTD_ERASE(nftl->mtd, instr); + MTD_ERASE(nftl->mbd.mtd, instr); if (instr->state == MTD_ERASE_FAILED) { /* could not format, FixMe: We should update the BadUnitTable @@ -291,7 +332,7 @@ return -1; uci.WearInfo = le32_to_cpu(nb_erases); - if (MTD_WRITEOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, + if (MTD_WRITEOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, &retlen, (char *)&uci) < 0) return -1; return 0; @@ -317,7 +358,7 @@ block = first_block; for (;;) { for (i = 0; i < sectors_per_block; i++) { - if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + i * SECTORSIZE, + if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + i * SECTORSIZE, 8, &retlen, (char *)&bci) < 0) status = SECTOR_IGNORE; else @@ -337,7 +378,7 @@ /* sector not free actually : mark it as SECTOR_IGNORE */ bci.Status = SECTOR_IGNORE; bci.Status1 = SECTOR_IGNORE; - MTD_WRITEOOB(nftl->mtd, + MTD_WRITEOOB(nftl->mbd.mtd, block * nftl->EraseSize + i * SECTORSIZE, 8, &retlen, (char *)&bci); } @@ -427,10 +468,10 @@ { struct nftl_uci1 h1; unsigned int erase_mark; - int retlen; + size_t retlen; /* check erase mark. */ - if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, + if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, &retlen, (char *)&h1) < 0) return -1; @@ -445,7 +486,7 @@ h1.EraseMark = cpu_to_le16(ERASE_MARK); h1.EraseMark1 = cpu_to_le16(ERASE_MARK); h1.WearInfo = cpu_to_le32(0); - if (MTD_WRITEOOB(nftl->mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, + if (MTD_WRITEOOB(nftl->mbd.mtd, block * nftl->EraseSize + SECTORSIZE + 8, 8, &retlen, (char *)&h1) < 0) return -1; } else { @@ -457,7 +498,7 @@ SECTORSIZE, 0) != 0) return -1; - if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + i, + if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + i, 16, &retlen, buf) < 0) return -1; if (i == SECTORSIZE) { @@ -485,9 +526,9 @@ static int get_fold_mark(struct NFTLrecord *nftl, unsigned int block) { struct nftl_uci2 uci; - int retlen; + size_t retlen; - if (MTD_READOOB(nftl->mtd, block * nftl->EraseSize + 2 * SECTORSIZE + 8, + if (MTD_READOOB(nftl->mbd.mtd, block * nftl->EraseSize + 2 * SECTORSIZE + 8, 8, &retlen, (char *)&uci) < 0) return 0; @@ -502,44 +543,14 @@ int chain_length, do_format_chain; struct nftl_uci0 h0; struct nftl_uci1 h1; - int retlen; - - /* XXX: will be suppressed */ - s->lastEUN = s->nb_blocks - 1; - - /* memory alloc */ - s->EUNtable = kmalloc(s->nb_blocks * sizeof(u16), GFP_KERNEL); - s->ReplUnitTable = kmalloc(s->nb_blocks * sizeof(u16), GFP_KERNEL); - if (!s->EUNtable || !s->ReplUnitTable) { - fail: - if (s->EUNtable) - kfree(s->EUNtable); - if (s->ReplUnitTable) - kfree(s->ReplUnitTable); - return -1; - } - - /* mark all blocks as potentially containing data */ - for (i = 0; i < s->nb_blocks; i++) { - s->ReplUnitTable[i] = BLOCK_NOTEXPLORED; - } + size_t retlen; /* search for NFTL MediaHeader and Spare NFTL Media Header */ if (find_boot_record(s) < 0) { printk("Could not find valid boot record\n"); - goto fail; + return -1; } - /* mark the bios blocks (blocks before NFTL MediaHeader) as reserved */ - for (i = 0; i < s->nb_boot_blocks; i++) - s->ReplUnitTable[i] = BLOCK_RESERVED; - - /* also mark the boot records (NFTL MediaHeader) blocks as reserved */ - if (s->MediaUnit != BLOCK_NIL) - s->ReplUnitTable[s->MediaUnit] = BLOCK_RESERVED; - if (s->SpareMediaUnit != BLOCK_NIL) - s->ReplUnitTable[s->SpareMediaUnit] = BLOCK_RESERVED; - /* init the logical to physical table */ for (i = 0; i < s->nb_blocks; i++) { s->EUNtable[i] = BLOCK_NIL; @@ -556,9 +567,9 @@ for (;;) { /* read the block header. If error, we format the chain */ - if (MTD_READOOB(s->mtd, block * s->EraseSize + 8, 8, + if (MTD_READOOB(s->mbd.mtd, block * s->EraseSize + 8, 8, &retlen, (char *)&h0) < 0 || - MTD_READOOB(s->mtd, block * s->EraseSize + SECTORSIZE + 8, 8, + MTD_READOOB(s->mbd.mtd, block * s->EraseSize + SECTORSIZE + 8, 8, &retlen, (char *)&h1) < 0) { s->ReplUnitTable[block] = BLOCK_NIL; do_format_chain = 1; @@ -724,7 +735,7 @@ /* second pass to format unreferenced blocks and init free block count */ s->numfreeEUNs = 0; - s->LastFreeEUN = BLOCK_NIL; + s->LastFreeEUN = le16_to_cpu(s->MediaHdr.FirstPhysicalEUN); for (block = 0; block < s->nb_blocks; block++) { if (s->ReplUnitTable[block] == BLOCK_NOTEXPLORED) { diff -Nru a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c --- a/drivers/mtd/redboot.c Mon Jun 9 23:16:14 2003 +++ b/drivers/mtd/redboot.c Mon Jun 9 23:16:14 2003 @@ -1,5 +1,5 @@ /* - * $Id: redboot.c,v 1.6 2001/10/25 09:16:06 dwmw2 Exp $ + * $Id: redboot.c,v 1.11 2003/05/21 10:39:26 dwmw2 Exp $ * * Parse RedBoot-style Flash Image System (FIS) tables and * produce a Linux partition array to match. @@ -7,6 +7,7 @@ #include <linux/kernel.h> #include <linux/slab.h> +#include <linux/init.h> #include <linux/mtd/mtd.h> #include <linux/mtd/partitions.h> @@ -34,7 +35,9 @@ return 1; } -int parse_redboot_partitions(struct mtd_info *master, struct mtd_partition **pparts) +static int parse_redboot_partitions(struct mtd_info *master, + struct mtd_partition **pparts, + unsigned long fis_origin) { int nrparts = 0; struct fis_image_desc *buf; @@ -43,7 +46,9 @@ int ret, i; size_t retlen; char *names; + char *nullname; int namelen = 0; + static char nullstring[] = "unallocated"; buf = kmalloc(PAGE_SIZE, GFP_KERNEL); @@ -90,7 +95,11 @@ goto out; } new_fl->img = &buf[i]; - buf[i].flash_base &= master->size-1; + if (fis_origin) { + buf[i].flash_base -= fis_origin; + } else { + buf[i].flash_base &= master->size-1; + } /* I'm sure the JFFS2 code has done me permanent damage. * I now think the following is _normal_ @@ -110,18 +119,24 @@ if (tmp_fl->img->flash_base + tmp_fl->img->size + master->erasesize < tmp_fl->next->img->flash_base) nrparts++; } - parts = kmalloc(sizeof(*parts)*nrparts + namelen, GFP_KERNEL); + parts = kmalloc(sizeof(*parts)*nrparts + sizeof(nullstring) + namelen, GFP_KERNEL); if (!parts) { ret = -ENOMEM; goto out; } - names = (char *)&parts[nrparts]; + memset(parts, 0, sizeof(*parts)*nrparts + namelen); + + /* FIXME: Include nullname only if it's used */ + nullname = (char *)&parts[nrparts]; + sprintf(nullname, nullstring); + names = nullname + sizeof(nullstring); + i=0; if (fl->img->flash_base) { - parts[0].name = "unallocated space"; + parts[0].name = nullname; parts[0].size = fl->img->flash_base; parts[0].offset = 0; } @@ -137,7 +152,7 @@ i++; parts[i].offset = parts[i-1].size + parts[i-1].offset; parts[i].size = fl->next->img->flash_base - parts[i].offset; - parts[i].name = "unallocated space"; + parts[i].name = nullname; } tmp_fl = fl; fl = fl->next; @@ -155,7 +170,24 @@ return ret; } -EXPORT_SYMBOL(parse_redboot_partitions); +static struct mtd_part_parser redboot_parser = { + .owner = THIS_MODULE, + .parse_fn = parse_redboot_partitions, + .name = "RedBoot", +}; + +static int __init redboot_parser_init(void) +{ + return register_mtd_parser(&redboot_parser); +} + +static void __exit redboot_parser_exit(void) +{ + deregister_mtd_parser(&redboot_parser); +} + +module_init(redboot_parser_init); +module_exit(redboot_parser_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Red Hat, Inc. - David Woodhouse <dwmw2@cambridge.redhat.com>"); diff -Nru a/drivers/net/3c509.c b/drivers/net/3c509.c --- a/drivers/net/3c509.c Mon Jun 9 23:16:06 2003 +++ b/drivers/net/3c509.c Mon Jun 9 23:16:06 2003 @@ -300,17 +300,11 @@ * * Both call el3_common_init/el3_common_remove. */ -static int __init el3_common_init (struct net_device *dev) +static void __init el3_common_init(struct net_device *dev) { struct el3_private *lp = dev->priv; short i; - el3_cards++; - if (!lp->dev) /* probed devices are not chained */ - { - lp->next_dev = el3_root_dev; - el3_root_dev = dev; - } spin_lock_init(&lp->lock); if (dev->mem_start & 0x05) { /* xcvr codes 1/3/4/12 */ @@ -343,8 +337,6 @@ dev->tx_timeout = el3_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; dev->do_ioctl = netdev_ioctl; - - return 0; } static void el3_common_remove (struct net_device *dev) @@ -374,6 +366,7 @@ int ioaddr, irq, if_port; u16 phys_addr[3]; static int current_tag; + int err = -ENODEV; #if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800) static int pnp_cards; struct pnp_dev *idev = NULL; @@ -413,7 +406,8 @@ phys_addr[j] = htons(read_eeprom(ioaddr, j)); if_port = read_eeprom(ioaddr, 8) >> 14; - if (!(dev = init_etherdev(NULL, sizeof(struct el3_private)))) { + dev = alloc_etherdev(sizeof (struct el3_private)); + if (!dev) { release_region(ioaddr, EL3_IO_EXTENT); pnp_device_detach(idev); return -ENOMEM; @@ -421,6 +415,8 @@ SET_MODULE_OWNER(dev); pnp_cards++; + + netdev_boot_setup_check(dev); goto found; } } @@ -514,28 +510,29 @@ irq = 13; #endif - if (!(dev = init_etherdev(NULL, sizeof(struct el3_private)))) - return -ENOMEM; + dev = alloc_etherdev(sizeof (struct el3_private)); + if (!dev) + return -ENOMEM; SET_MODULE_OWNER(dev); + + netdev_boot_setup_check(dev); /* Set passed-in IRQ or I/O Addr. */ if (dev->irq > 1 && dev->irq < 16) irq = dev->irq; if (dev->base_addr) { - if (dev->mem_end == 0x3c509 /* Magic key */ - && dev->base_addr >= 0x200 && dev->base_addr <= 0x3e0) - ioaddr = dev->base_addr & 0x3f0; - else if (dev->base_addr != ioaddr) { - unregister_netdev (dev); - return -ENODEV; - } + if (dev->mem_end == 0x3c509 /* Magic key */ + && dev->base_addr >= 0x200 && dev->base_addr <= 0x3e0) + ioaddr = dev->base_addr & 0x3f0; + else if (dev->base_addr != ioaddr) + goto out; } if (!request_region(ioaddr, EL3_IO_EXTENT, "3c509")) { - unregister_netdev (dev); - return -EBUSY; + err = -EBUSY; + goto out; } /* Set the adaptor tag so that the next card can be found. */ @@ -549,11 +546,8 @@ #endif EL3WINDOW(0); - if (inw(ioaddr) != 0x6d50) { - unregister_netdev (dev); - release_region(ioaddr, EL3_IO_EXTENT); - return -ENODEV; - } + if (inw(ioaddr) != 0x6d50) + goto out1; /* Free the interrupt so that some other card can use it. */ outw(0x0f00, ioaddr + WN0_IRQ); @@ -570,6 +564,11 @@ #if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800) lp->dev = &idev->dev; #endif + el3_common_init(dev); + + err = register_netdev(dev); + if (err) + goto out1; #ifdef CONFIG_PM /* register power management */ @@ -581,7 +580,22 @@ } #endif - return el3_common_init (dev); + el3_cards++; +#if !defined(__ISAPNP__) || defined(CONFIG_X86_PC9800) + lp->next_dev = el3_root_dev; + el3_root_dev = dev; +#endif + return 0; + +out1: + release_region(ioaddr, EL3_IO_EXTENT); +#if defined(__ISAPNP__) && !defined(CONFIG_X86_PC9800) + if (idev) + pnp_device_detach(idev); +#endif +out: + kfree(dev); + return err; } #ifdef CONFIG_MCA @@ -602,6 +616,7 @@ u_char pos4, pos5; struct mca_device *mdev = to_mca_device(device); int slot = mdev->slot; + int err; pos4 = mca_device_read_stored_pos(mdev, 4); pos5 = mca_device_read_stored_pos(mdev, 5); @@ -630,13 +645,14 @@ phys_addr[i] = htons(read_eeprom(ioaddr, i)); } - dev = init_etherdev(NULL, sizeof(struct el3_private)); + dev = alloc_etherdev(sizeof (struct el3_private)); if (dev == NULL) { release_region(ioaddr, EL3_IO_EXTENT); return -ENOMEM; } SET_MODULE_OWNER(dev); + netdev_boot_setup_check(dev); memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr)); dev->base_addr = ioaddr; @@ -646,8 +662,16 @@ lp->dev = device; lp->type = EL3_MCA; device->driver_data = dev; + el3_common_init(dev); - return el3_common_init (dev); + err = register_netdev(dev); + if (err) { + release_region(ioaddr, EL3_IO_EXTENT); + return -ENOMEM; + } + + el3_cards++; + return 0; } #endif /* CONFIG_MCA */ @@ -661,6 +685,7 @@ u16 phys_addr[3]; struct net_device *dev = NULL; struct eisa_device *edev; + int err; /* Yeepee, The driver framework is calling us ! */ edev = to_eisa_device (device); @@ -680,7 +705,7 @@ /* Restore the "Product ID" to the EEPROM read register. */ read_eeprom(ioaddr, 3); - dev = init_etherdev(NULL, sizeof(struct el3_private)); + dev = alloc_etherdev(sizeof (struct el3_private)); if (dev == NULL) { release_region(ioaddr, EL3_IO_EXTENT); return -ENOMEM; @@ -688,6 +713,8 @@ SET_MODULE_OWNER(dev); + netdev_boot_setup_check(dev); + memcpy(dev->dev_addr, phys_addr, sizeof(phys_addr)); dev->base_addr = ioaddr; dev->irq = irq; @@ -696,8 +723,16 @@ lp->dev = device; lp->type = EL3_EISA; eisa_set_drvdata (edev, dev); + el3_common_init(dev); - return el3_common_init (dev); + err = register_netdev(dev); + if (err) { + release_region(ioaddr, EL3_IO_EXTENT); + return err; + } + + el3_cards++; + return 0; } #endif diff -Nru a/drivers/net/8139cp.c b/drivers/net/8139cp.c --- a/drivers/net/8139cp.c Mon Jun 9 23:16:11 2003 +++ b/drivers/net/8139cp.c Mon Jun 9 23:16:11 2003 @@ -1846,7 +1846,7 @@ } /* Configure DMA attributes. */ - if (!pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff)) { + if (!pci_set_dma_mask(pdev, (u64) 0xffffffffffffffffULL)) { cp->pci_using_dac = 1; } else { rc = pci_set_dma_mask(pdev, (u64) 0xffffffff); diff -Nru a/drivers/net/8139too.c b/drivers/net/8139too.c --- a/drivers/net/8139too.c Mon Jun 9 23:16:05 2003 +++ b/drivers/net/8139too.c Mon Jun 9 23:16:05 2003 @@ -980,7 +980,7 @@ dev->irq = pdev->irq; - /* dev->priv/tp zeroed and aligned in init_etherdev */ + /* dev->priv/tp zeroed and aligned in alloc_etherdev */ tp = dev->priv; /* note: tp->chipset set in rtl8139_init_board */ @@ -2143,9 +2143,7 @@ spin_unlock_irqrestore (&tp->lock, flags); - /* TODO: isn't this code racy? we synchronize the IRQ and then free it, */ - /* but another IRQ could've happened in between the sync and free */ - synchronize_irq (dev->irq); + synchronize_irq (dev->irq); /* racy, but that's ok here */ free_irq (dev->irq, dev); rtl8139_tx_clear (tp); diff -Nru a/drivers/net/Kconfig b/drivers/net/Kconfig --- a/drivers/net/Kconfig Mon Jun 9 23:16:17 2003 +++ b/drivers/net/Kconfig Mon Jun 9 23:16:17 2003 @@ -225,7 +225,7 @@ config MACE tristate "MACE (Power Mac ethernet) support" - depends on NET_ETHERNET && PPC && ALL_PPC + depends on NET_ETHERNET && PPC_PMAC help Power Macintoshes and clones with Ethernet built-in on the motherboard will usually use a MACE (Medium Access Control for @@ -249,7 +249,7 @@ config BMAC tristate "BMAC (G3 ethernet) support" - depends on NET_ETHERNET && PPC && ALL_PPC + depends on NET_ETHERNET && PPC_PMAC help Say Y for support of BMAC Ethernet interfaces. These are used on G3 computers. diff -Nru a/drivers/net/Makefile b/drivers/net/Makefile --- a/drivers/net/Makefile Mon Jun 9 23:16:09 2003 +++ b/drivers/net/Makefile Mon Jun 9 23:16:09 2003 @@ -65,7 +65,7 @@ obj-$(CONFIG_WINBOND_840) += mii.o obj-$(CONFIG_SUNDANCE) += sundance.o mii.o obj-$(CONFIG_HAMACHI) += hamachi.o mii.o -obj-$(CONFIG_NET) += Space.o setup.o net_init.o loopback.o +obj-$(CONFIG_NET) += Space.o net_init.o loopback.o obj-$(CONFIG_SEEQ8005) += seeq8005.o obj-$(CONFIG_ETHERTAP) += ethertap.o obj-$(CONFIG_NET_SB1000) += sb1000.o @@ -173,7 +173,7 @@ obj-$(CONFIG_TUN) += tun.o obj-$(CONFIG_DL2K) += dl2k.o obj-$(CONFIG_R8169) += r8169.o -obj-$(CONFIG_AMD8111_ETH) += amd8111e.o +obj-$(CONFIG_AMD8111_ETH) += amd8111e.o mii.o # non-drivers/net drivers who want mii lib obj-$(CONFIG_PCMCIA_SMC91C92) += mii.o diff -Nru a/drivers/net/Space.c b/drivers/net/Space.c --- a/drivers/net/Space.c Mon Jun 9 23:16:07 2003 +++ b/drivers/net/Space.c Mon Jun 9 23:16:07 2003 @@ -105,9 +105,6 @@ /* Detachable devices ("pocket adaptors") */ extern int de620_probe(struct net_device *); -/* FDDI adapters */ -extern int skfp_probe(struct net_device *dev); - /* Fibre Channel adapters */ extern int iph5526_probe(struct net_device *dev); @@ -401,29 +398,6 @@ return -ENODEV; } -#ifdef CONFIG_FDDI -static int __init fddiif_probe(struct net_device *dev) -{ - unsigned long base_addr = dev->base_addr; - - if (base_addr == 1) - return 1; /* ENXIO */ - - if (1 -#ifdef CONFIG_APFDDI - && apfddi_init(dev) -#endif -#ifdef CONFIG_SKFP - && skfp_probe(dev) -#endif - && 1 ) { - return 1; /* -ENODEV or -EAGAIN would be more accurate. */ - } - return 0; -} -#endif - - #ifdef CONFIG_NET_FC static int fcif_probe(struct net_device *dev) { @@ -614,52 +588,6 @@ #define NEXT_DEV (&tr0_dev) #endif - -#ifdef CONFIG_FDDI -static struct net_device fddi7_dev = { - .name = "fddi7", - .next = NEXT_DEV, - .init = fddiif_probe -}; -static struct net_device fddi6_dev = { - .name = "fddi6", - .next = &fddi7_dev, - .init = fddiif_probe -}; -static struct net_device fddi5_dev = { - .name = "fddi5", - .next = &fddi6_dev, - .init = fddiif_probe -}; -static struct net_device fddi4_dev = { - .name = "fddi4", - .next = &fddi5_dev, - .init = fddiif_probe -}; -static struct net_device fddi3_dev = { - .name = "fddi3", - .next = &fddi4_dev, - .init = fddiif_probe -}; -static struct net_device fddi2_dev = { - .name = "fddi2", - .next = &fddi3_dev, - .init = fddiif_probe -}; -static struct net_device fddi1_dev = { - .name = "fddi1", - .next = &fddi2_dev, - .init = fddiif_probe -}; -static struct net_device fddi0_dev = { - .name = "fddi0", - .next = &fddi1_dev, - .init = fddiif_probe -}; -#undef NEXT_DEV -#define NEXT_DEV (&fddi0_dev) -#endif - #ifdef CONFIG_NET_FC static struct net_device fc1_dev = { diff -Nru a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c --- a/drivers/net/amd8111e.c Mon Jun 9 23:16:14 2003 +++ b/drivers/net/amd8111e.c Mon Jun 9 23:16:14 2003 @@ -1,6 +1,6 @@ /* Advanced Micro Devices Inc. AMD8111E Linux Network Driver - * Copyright (C) 2002 Advanced Micro Devices + * Copyright (C) 2003 Advanced Micro Devices * * * Copyright 2001,2002 Jeff Garzik <jgarzik@mandrakesoft.com> [ 8139cp.c,tg3.c ] @@ -41,6 +41,18 @@ Kernel Mode Revision History: + 3.0.0 + Initial Revision. + 3.0.1 + 1. Dynamic interrupt coalescing. + 2. Removed prev_stats. + 3. MII support. + 4. Dynamic IPG support + 3.0.2 05/29/2003 + 1. Bug fix: Fixed failure to send jumbo packets larger than 4k. + 2. Bug fix: Fixed VLAN support failure. + 3. Bug fix: Fixed receive interrupt coalescing bug. + 4. Dynamic IPG support is disabled by default. */ @@ -77,13 +89,16 @@ #include "amd8111e.h" #define MODULE_NAME "amd8111e" -#define MODULE_VERSION "3.0.0" +#define MODULE_VERSION "3.0.2" MODULE_AUTHOR("Advanced Micro Devices, Inc."); -MODULE_DESCRIPTION ("AMD8111 based 10/100 Ethernet Controller. Driver Version 3.0.0"); +MODULE_DESCRIPTION ("AMD8111 based 10/100 Ethernet Controller. Driver Version 3.0.2"); MODULE_LICENSE("GPL"); - MODULE_PARM(speed_duplex, "1-" __MODULE_STRING (MAX_UNITS) "i"); MODULE_PARM_DESC(speed_duplex, "Set device speed and duplex modes, 0: Auto Negotitate, 1: 10Mbps Half Duplex, 2: 10Mbps Full Duplex, 3: 100Mbps Half Duplex, 4: 100Mbps Full Duplex"); +MODULE_PARM(coalesce, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM_DESC(coalesce, "Enable or Disable interrupt coalescing, 1: Enable, 0: Disable"); +MODULE_PARM(dynamic_ipg, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM_DESC(dynamic_ipg, "Enable or Disable dynamic IPG, 1: Enable, 0: Disable"); static struct pci_device_id amd8111e_pci_tbl[] __devinitdata = { @@ -92,6 +107,88 @@ { 0, } }; +/* +This function will read the PHY registers. +*/ +static int amd8111e_read_phy(struct amd8111e_priv* lp, int phy_id, int reg, u32* val) +{ + void * mmio = lp->mmio; + unsigned int reg_val; + unsigned int repeat= REPEAT_CNT; + + reg_val = readl(mmio + PHY_ACCESS); + while (reg_val & PHY_CMD_ACTIVE) + reg_val = readl( mmio + PHY_ACCESS ); + + writel( PHY_RD_CMD | ((phy_id & 0x1f) << 21) | + ((reg & 0x1f) << 16), mmio +PHY_ACCESS); + do{ + reg_val = readl(mmio + PHY_ACCESS); + udelay(30); /* It takes 30 us to read/write data */ + } while (--repeat && (reg_val & PHY_CMD_ACTIVE)); + if(reg_val & PHY_RD_ERR) + goto err_phy_read; + + *val = reg_val & 0xffff; + return 0; +err_phy_read: + *val = 0; + return -EINVAL; + +} + +/* +This function will write into PHY registers. +*/ +static int amd8111e_write_phy(struct amd8111e_priv* lp,int phy_id, int reg, u32 val) +{ + unsigned int repeat = REPEAT_CNT + void * mmio = lp->mmio; + unsigned int reg_val; + + reg_val = readl(mmio + PHY_ACCESS); + while (reg_val & PHY_CMD_ACTIVE) + reg_val = readl( mmio + PHY_ACCESS ); + + writel( PHY_WR_CMD | ((phy_id & 0x1f) << 21) | + ((reg & 0x1f) << 16)|val, mmio + PHY_ACCESS); + + do{ + reg_val = readl(mmio + PHY_ACCESS); + udelay(30); /* It takes 30 us to read/write the data */ + } while (--repeat && (reg_val & PHY_CMD_ACTIVE)); + + if(reg_val & PHY_RD_ERR) + goto err_phy_write; + + return 0; + +err_phy_write: + return -EINVAL; + +} +/* +This is the mii register read function provided to the mii interface. +*/ +static int amd8111e_mdio_read(struct net_device * dev, int phy_id, int reg_num) +{ + struct amd8111e_priv* lp = dev->priv; + unsigned int reg_val; + + amd8111e_read_phy(lp,phy_id,reg_num,®_val); + return reg_val; + +} + +/* +This is the mii register write function provided to the mii interface. +*/ +static void amd8111e_mdio_write(struct net_device * dev, int phy_id, int reg_num, int val) +{ + struct amd8111e_priv* lp = dev->priv; + + amd8111e_write_phy(lp, phy_id, reg_num, val); +} /* This function will set PHY speed. During initialization sets the original speed to 100 full. @@ -99,26 +196,39 @@ static void amd8111e_set_ext_phy(struct net_device *dev) { struct amd8111e_priv *lp = (struct amd8111e_priv *)dev->priv; - unsigned long reg_val = 0; - void * mmio = lp->mmio; - struct amd8111e_link_config *link_config = &lp->link_config; + u32 bmcr,advert,tmp; - if(!lp->opened){ - /* Initializing SPEED_100 and DUPLEX_FULL as original values */ - link_config->orig_speed = SPEED_100; - link_config->orig_duplex = DUPLEX_FULL; - link_config->orig_phy_option = XPHYSP |XPHYFD; - } - reg_val = lp->ext_phy_option; - - /* Disable port manager */ - writel((u32) EN_PMGR, mmio + CMD3 ); + /* Determine mii register values to set the speed */ + advert = amd8111e_mdio_read(dev, PHY_ID, MII_ADVERTISE); + tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4); + switch (lp->ext_phy_option){ + + default: + case SPEED_AUTONEG: /* advertise all values */ + tmp |= ( ADVERTISE_10HALF|ADVERTISE_10FULL| + ADVERTISE_100HALF|ADVERTISE_100FULL) ; + break; + case SPEED10_HALF: + tmp |= ADVERTISE_10HALF; + break; + case SPEED10_FULL: + tmp |= ADVERTISE_10FULL; + break; + case SPEED100_HALF: + tmp |= ADVERTISE_100HALF; + break; + case SPEED100_FULL: + tmp |= ADVERTISE_100FULL; + break; + } + + if(advert != tmp) + amd8111e_mdio_write(dev, PHY_ID, MII_ADVERTISE, tmp); + /* Restart auto negotiation */ + bmcr = amd8111e_mdio_read(dev, PHY_ID, MII_BMCR); + bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); + amd8111e_mdio_write(dev, PHY_ID, MII_BMCR, bmcr); - /* Reset PHY */ - writel((u32)XPHYRST | lp->ext_phy_option, mmio + CTRL2); - - /* Enable port manager */ - writel((u32)VAL1 | EN_PMGR, mmio + CMD3 ); } /* @@ -156,7 +266,7 @@ } /* - This will set the receive buffer length corresponding to the mtu size of network interface. +This will set the receive buffer length corresponding to the mtu size of networkinterface. */ static inline void amd8111e_set_rx_buff_len(struct net_device* dev) { @@ -226,13 +336,13 @@ lp->rx_ring[i].buff_phy_addr = cpu_to_le32(lp->rx_dma_addr[i]); lp->rx_ring[i].buff_count = cpu_to_le16(lp->rx_buff_len); - lp->rx_ring[i].rx_dr_offset10 = cpu_to_le16(OWN_BIT); + lp->rx_ring[i].rx_flags = cpu_to_le16(OWN_BIT); } /* Initializing transmit descriptors */ for (i = 0; i < NUM_TX_RING_DR; i++) { lp->tx_ring[i].buff_phy_addr = 0; - lp->tx_ring[i].tx_dr_offset2 = 0; + lp->tx_ring[i].tx_flags = 0; lp->tx_ring[i].buff_count = 0; } @@ -253,6 +363,65 @@ err_no_mem: return -ENOMEM; } +/* This function will set the interrupt coalescing according to the input arguments */ +static int amd8111e_set_coalesce(struct net_device * dev, enum coal_mode cmod) +{ + unsigned int timeout; + unsigned int event_count; + + struct amd8111e_priv *lp = dev->priv; + void* mmio = lp->mmio; + struct amd8111e_coalesce_conf * coal_conf = &lp->coal_conf; + + + switch(cmod) + { + case RX_INTR_COAL : + timeout = coal_conf->rx_timeout; + event_count = coal_conf->rx_event_count; + if( timeout > MAX_TIMEOUT || + event_count > MAX_EVENT_COUNT ) + return -EINVAL; + + timeout = timeout * DELAY_TIMER_CONV; + writel(VAL0|STINTEN, mmio+INTEN0); + writel((u32)DLY_INT_A_R0|( event_count<< 16 )|timeout, + mmio+DLY_INT_A); + break; + + case TX_INTR_COAL : + timeout = coal_conf->tx_timeout; + event_count = coal_conf->tx_event_count; + if( timeout > MAX_TIMEOUT || + event_count > MAX_EVENT_COUNT ) + return -EINVAL; + + + timeout = timeout * DELAY_TIMER_CONV; + writel(VAL0|STINTEN,mmio+INTEN0); + writel((u32)DLY_INT_B_T0|( event_count<< 16 )|timeout, + mmio+DLY_INT_B); + break; + + case DISABLE_COAL: + writel(0,mmio+STVAL); + writel(STINTEN, mmio+INTEN0); + writel(0, mmio +DLY_INT_B); + writel(0, mmio+DLY_INT_A); + break; + case ENABLE_COAL: + /* Start the timer */ + writel((u32)SOFT_TIMER_FREQ, mmio+STVAL); /* 0.5 sec */ + writel(VAL0|STINTEN, mmio+INTEN0); + break; + default: + break; + + } + return 0; + +} + /* This function initializes the device registers and starts the device. */ @@ -267,13 +436,17 @@ if(amd8111e_init_ring(dev)) return -ENOMEM; + + /* enable the port manager and set auto negotiation always */ + writel((u32) VAL1|EN_PMGR, mmio + CMD3 ); + writel((u32)XPHYANE|XPHYRST , mmio + CTRL2); amd8111e_set_ext_phy(dev); /* set control registers */ reg_val = readl(mmio + CTRL1); - - writel( reg_val| XMTSP_128 | CACHE_ALIGN | B1_MASK, mmio + CTRL1 ); + reg_val &= ~XMTSP_MASK; + writel( reg_val| XMTSP_128 | CACHE_ALIGN, mmio + CTRL1 ); /* enable interrupt */ writel( APINT5EN | APINT4EN | APINT3EN | APINT2EN | APINT1EN | @@ -288,15 +461,21 @@ writew((u32)NUM_TX_RING_DR, mmio + XMT_RING_LEN0); writew((u16)NUM_RX_RING_DR, mmio + RCV_RING_LEN0); + + /* set default IPG to 96 */ + writew((u32)DEFAULT_IPG,mmio+IPG); + writew((u32)(DEFAULT_IPG-IFS1_DELTA), mmio + IFS1); if(lp->options & OPTION_JUMBO_ENABLE){ writel((u32)VAL2|JUMBO, mmio + CMD3); /* Reset REX_UFLO */ writel( REX_UFLO, mmio + CMD2); /* Should not set REX_UFLO for jumbo frames */ - writel( VAL0 | APAD_XMT | REX_RTRY, mmio + CMD2); - }else + writel( VAL0 | APAD_XMT|REX_RTRY , mmio + CMD2); + }else{ writel( VAL0 | APAD_XMT | REX_RTRY|REX_UFLO, mmio + CMD2); + writel((u32)JUMBO, mmio + CMD3); + } #if AMD8111E_VLAN_TAG_USED writel((u32) VAL2|VSIZE|VL_TAG_DEL, mmio + CMD3); @@ -306,11 +485,20 @@ /* Setting the MAC address to the device */ for(i = 0; i < ETH_ADDR_LEN; i++) writeb( dev->dev_addr[i], mmio + PADR + i ); + + /* Enable interrupt coalesce */ + if(lp->options & OPTION_INTR_COAL_ENABLE){ + printk(KERN_INFO "%s: Interrupt Coalescing Enabled.\n", + dev->name); + amd8111e_set_coalesce(dev,ENABLE_COAL); + } /* set RUN bit to start the chip */ writel(VAL2 | RDMD0, mmio + CMD0); writel(VAL0 | INTREN | RUN, mmio + CMD0); + /* To avoid PCI posting bug */ + readl(mmio+CMD0); return 0; } /* @@ -383,7 +571,7 @@ writew(MIB_CLEAR, mmio + MIB_ADDR); /* Clear LARF */ - AMD8111E_WRITE_REG64(mmio, LADRF,logic_filter); + amd8111e_writeq(*(u64*)logic_filter,mmio+LADRF); /* SRAM_SIZE register */ reg_val = readl(mmio + SRAM_SIZE); @@ -393,8 +581,11 @@ #if AMD8111E_VLAN_TAG_USED writel(VAL2|VSIZE|VL_TAG_DEL, mmio + CMD3 ); #endif - /* CMD2 register */ - reg_val = readl(mmio + CMD2); + /* Set default value to CTRL1 Register */ + writel(CTRL1_DEFAULT, mmio + CTRL1); + + /* To avoid PCI posting bug */ + readl(mmio + CMD2); } @@ -412,6 +603,9 @@ /* Clear INT0 */ intr0 = readl(lp->mmio + INT0); writel(intr0, lp->mmio + INT0); + + /* To avoid PCI posting bug */ + readl(lp->mmio + INT0); } @@ -421,6 +615,9 @@ static void amd8111e_stop_chip(struct amd8111e_priv* lp) { writel(RUN, lp->mmio + CMD0); + + /* To avoid PCI posting bug */ + readl(lp->mmio + CMD0); } /* @@ -467,11 +664,10 @@ struct amd8111e_priv* lp = dev->priv; int tx_index = lp->tx_complete_idx & TX_RING_DR_MOD_MASK; int status; - /* Complete all the transmit packet */ while (lp->tx_complete_idx != lp->tx_idx){ tx_index = lp->tx_complete_idx & TX_RING_DR_MOD_MASK; - status = le16_to_cpu(lp->tx_ring[tx_index].tx_dr_offset2); + status = le16_to_cpu(lp->tx_ring[tx_index].tx_flags); if(status & OWN_BIT) break; /* It still hasn't been Txed */ @@ -487,11 +683,15 @@ lp->tx_skbuff[tx_index] = 0; lp->tx_dma_addr[tx_index] = 0; } - lp->tx_complete_idx++; + lp->tx_complete_idx++; + /*COAL update tx coalescing parameters */ + lp->coal_conf.tx_packets++; + lp->coal_conf.tx_bytes += lp->tx_ring[tx_index].buff_count; if (netif_queue_stopped(dev) && lp->tx_complete_idx > lp->tx_idx - NUM_TX_BUFFERS +2){ /* The ring is no longer full, clear tbusy. */ + /* lp->tx_full = 0; */ netif_wake_queue (dev); } } @@ -516,33 +716,31 @@ /* If we own the next entry, it's a new packet. Send it up. */ while(++num_rx_pkt <= max_rx_pkt){ - if(lp->rx_ring[rx_index].rx_dr_offset10 & OWN_BIT) + if(lp->rx_ring[rx_index].rx_flags & OWN_BIT) return 0; /* check if err summary bit is set */ - if(le16_to_cpu(lp->rx_ring[rx_index].rx_dr_offset10) & ERR_BIT){ + if(le16_to_cpu(lp->rx_ring[rx_index].rx_flags) & ERR_BIT){ /* * There is a tricky error noted by John Murphy, * <murf@perftech.com> to Russ Nelson: Even with full-sized * buffers it's possible for a jabber packet to use two * buffers, with only the last correctly noting the error. */ /* reseting flags */ - lp->rx_ring[rx_index].rx_dr_offset10 &= - cpu_to_le16(RESET_RX_FLAGS); + lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS; goto err_next_pkt; } /* check for STP and ENP */ - status = le16_to_cpu(lp->rx_ring[rx_index].rx_dr_offset10); + status = le16_to_cpu(lp->rx_ring[rx_index].rx_flags); if(!((status & STP_BIT) && (status & ENP_BIT))){ /* reseting flags */ - lp->rx_ring[rx_index].rx_dr_offset10 &= - cpu_to_le16(RESET_RX_FLAGS); + lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS; goto err_next_pkt; } pkt_len = le16_to_cpu(lp->rx_ring[rx_index].msg_count) - 4; #if AMD8111E_VLAN_TAG_USED - vtag = le16_to_cpu(lp->rx_ring[rx_index].rx_dr_offset10) & TT_MASK; + vtag = le16_to_cpu(lp->rx_ring[rx_index].rx_flags) & TT_MASK; /*MAC will strip vlan tag*/ if(lp->vlgrp != NULL && vtag !=0) min_pkt_len =MIN_PKT_LEN - 4; @@ -551,16 +749,14 @@ min_pkt_len =MIN_PKT_LEN; if (pkt_len < min_pkt_len) { - lp->rx_ring[rx_index].rx_dr_offset10 &= - cpu_to_le16(RESET_RX_FLAGS); + lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS; lp->stats.rx_errors++; goto err_next_pkt; } if(!(new_skb = dev_alloc_skb(lp->rx_buff_len))){ /* if allocation fail, ignore that pkt and go to next one */ - lp->rx_ring[rx_index].rx_dr_offset10 &= - cpu_to_le16(RESET_RX_FLAGS); + lp->rx_ring[rx_index].rx_flags &= RESET_RX_FLAGS; lp->stats.rx_errors++; goto err_next_pkt; } @@ -580,22 +776,26 @@ #if AMD8111E_VLAN_TAG_USED - vtag = lp->rx_ring[rx_index].rx_dr_offset10 & TT_MASK; + vtag = lp->rx_ring[rx_index].rx_flags & TT_MASK; if(lp->vlgrp != NULL && (vtag == TT_VLAN_TAGGED)){ amd8111e_vlan_rx(lp, skb, lp->rx_ring[rx_index].tag_ctrl_info); } else #endif - dev->last_rx = jiffies; netif_rx (skb); + /*COAL update rx coalescing parameters*/ + lp->coal_conf.rx_packets++; + lp->coal_conf.rx_bytes += pkt_len; + + dev->last_rx = jiffies; err_next_pkt: lp->rx_ring[rx_index].buff_phy_addr = cpu_to_le32(lp->rx_dma_addr[rx_index]); lp->rx_ring[rx_index].buff_count = cpu_to_le16(lp->rx_buff_len-2); - lp->rx_ring[rx_index].rx_dr_offset10 |= cpu_to_le16(OWN_BIT); + lp->rx_ring[rx_index].rx_flags |= cpu_to_le16(OWN_BIT); rx_index = (++lp->rx_idx) & RX_RING_DR_MOD_MASK; } @@ -603,8 +803,8 @@ } /* -This function will store the original speed to restore later, if autoneg is turned on. This speed will be set later when the autoneg is turned off. If the link status indicates that link is down, that will be indicated to the kernel */ - +This function will indicate the link status to the kernel. +*/ static int amd8111e_link_change(struct net_device* dev) { struct amd8111e_priv *lp = dev->priv; @@ -614,21 +814,11 @@ status0 = readl(lp->mmio + STAT0); if(status0 & LINK_STATS){ - if(status0 & AUTONEG_COMPLETE){ - /* keeping the original speeds */ - if((lp->link_config.speed != SPEED_INVALID)&& - (lp->link_config.duplex != DUPLEX_INVALID)){ - lp->link_config.orig_speed = lp->link_config.speed; - lp->link_config.orig_duplex = lp->link_config.duplex; - lp->link_config.orig_phy_option = lp->ext_phy_option; - } - - lp->link_config.speed = SPEED_INVALID; - lp->link_config.duplex = DUPLEX_INVALID; + if(status0 & AUTONEG_COMPLETE) lp->link_config.autoneg = AUTONEG_ENABLE; - netif_carrier_on(dev); - return 0; - } + else + lp->link_config.autoneg = AUTONEG_DISABLE; + if(status0 & FULL_DPLX) lp->link_config.duplex = DUPLEX_FULL; else @@ -638,13 +828,17 @@ lp->link_config.speed = SPEED_10; else if(speed == PHY_SPEED_100) lp->link_config.speed = SPEED_100; - lp->link_config.autoneg = AUTONEG_DISABLE; + + printk(KERN_INFO "%s: Link is Up. Speed is %s Mbps %s Duplex\n", dev->name, + (lp->link_config.speed == SPEED_100) ? "100": "10", + (lp->link_config.duplex == DUPLEX_FULL)? "Full": "Half"); netif_carrier_on(dev); } else{ lp->link_config.speed = SPEED_INVALID; lp->link_config.duplex = DUPLEX_INVALID; lp->link_config.autoneg = AUTONEG_INVALID; + printk(KERN_INFO "%s: Link is Down.\n",dev->name); netif_carrier_off(dev); } @@ -671,129 +865,250 @@ } /* -This function retuurns the reads the mib registers and returns the hardware statistics. It adds the previous statistics with new values.*/ +This function reads the mib registers and returns the hardware statistics. It updates previous internal driver statistics with new values. +*/ static struct net_device_stats *amd8111e_get_stats(struct net_device * dev) { struct amd8111e_priv *lp = dev->priv; void * mmio = lp->mmio; unsigned long flags; - struct net_device_stats *prev_stats = &lp->prev_stats; + /* struct net_device_stats *prev_stats = &lp->prev_stats; */ struct net_device_stats* new_stats = &lp->stats; if(!lp->opened) - return prev_stats; + return &lp->stats; spin_lock_irqsave (&lp->lock, flags); /* stats.rx_packets */ - new_stats->rx_packets = prev_stats->rx_packets+ - amd8111e_read_mib(mmio, rcv_broadcast_pkts)+ - amd8111e_read_mib(mmio, rcv_multicast_pkts)+ - amd8111e_read_mib(mmio, rcv_unicast_pkts); + new_stats->rx_packets = amd8111e_read_mib(mmio, rcv_broadcast_pkts)+ + amd8111e_read_mib(mmio, rcv_multicast_pkts)+ + amd8111e_read_mib(mmio, rcv_unicast_pkts); /* stats.tx_packets */ - new_stats->tx_packets = prev_stats->tx_packets+ - amd8111e_read_mib(mmio, xmt_packets); + new_stats->tx_packets = amd8111e_read_mib(mmio, xmt_packets); /*stats.rx_bytes */ - new_stats->rx_bytes = prev_stats->rx_bytes+ - amd8111e_read_mib(mmio, rcv_octets); + new_stats->rx_bytes = amd8111e_read_mib(mmio, rcv_octets); /* stats.tx_bytes */ - new_stats->tx_bytes = prev_stats->tx_bytes+ - amd8111e_read_mib(mmio, xmt_octets); + new_stats->tx_bytes = amd8111e_read_mib(mmio, xmt_octets); /* stats.rx_errors */ - new_stats->rx_errors = prev_stats->rx_errors+ - amd8111e_read_mib(mmio, rcv_undersize_pkts)+ - amd8111e_read_mib(mmio, rcv_fragments)+ - amd8111e_read_mib(mmio, rcv_jabbers)+ - amd8111e_read_mib(mmio, rcv_alignment_errors)+ - amd8111e_read_mib(mmio, rcv_fcs_errors)+ - amd8111e_read_mib(mmio, rcv_miss_pkts); + new_stats->rx_errors = amd8111e_read_mib(mmio, rcv_undersize_pkts)+ + amd8111e_read_mib(mmio, rcv_fragments)+ + amd8111e_read_mib(mmio, rcv_jabbers)+ + amd8111e_read_mib(mmio, rcv_alignment_errors)+ + amd8111e_read_mib(mmio, rcv_fcs_errors)+ + amd8111e_read_mib(mmio, rcv_miss_pkts); /* stats.tx_errors */ - new_stats->tx_errors = prev_stats->tx_errors+ - amd8111e_read_mib(mmio, xmt_underrun_pkts); + new_stats->tx_errors = amd8111e_read_mib(mmio, xmt_underrun_pkts); /* stats.rx_dropped*/ - new_stats->rx_dropped = prev_stats->rx_dropped+ - amd8111e_read_mib(mmio, rcv_miss_pkts); + new_stats->rx_dropped = amd8111e_read_mib(mmio, rcv_miss_pkts); /* stats.tx_dropped*/ - new_stats->tx_dropped = prev_stats->tx_dropped+ - amd8111e_read_mib(mmio, xmt_underrun_pkts); + new_stats->tx_dropped = amd8111e_read_mib(mmio, xmt_underrun_pkts); /* stats.multicast*/ - new_stats->multicast = prev_stats->multicast+ - amd8111e_read_mib(mmio, rcv_multicast_pkts); + new_stats->multicast = amd8111e_read_mib(mmio, rcv_multicast_pkts); /* stats.collisions*/ - new_stats->collisions = prev_stats->collisions+ - amd8111e_read_mib(mmio, xmt_collisions); + new_stats->collisions = amd8111e_read_mib(mmio, xmt_collisions); /* stats.rx_length_errors*/ - new_stats->rx_length_errors = prev_stats->rx_length_errors+ + new_stats->rx_length_errors = amd8111e_read_mib(mmio, rcv_undersize_pkts)+ amd8111e_read_mib(mmio, rcv_oversize_pkts); /* stats.rx_over_errors*/ - new_stats->rx_over_errors = prev_stats->rx_over_errors+ - amd8111e_read_mib(mmio, rcv_miss_pkts); + new_stats->rx_over_errors = amd8111e_read_mib(mmio, rcv_miss_pkts); /* stats.rx_crc_errors*/ - new_stats->rx_crc_errors = prev_stats->rx_crc_errors+ - amd8111e_read_mib(mmio, rcv_fcs_errors); + new_stats->rx_crc_errors = amd8111e_read_mib(mmio, rcv_fcs_errors); /* stats.rx_frame_errors*/ - new_stats->rx_frame_errors = prev_stats->rx_frame_errors+ + new_stats->rx_frame_errors = amd8111e_read_mib(mmio, rcv_alignment_errors); /* stats.rx_fifo_errors */ - new_stats->rx_fifo_errors = prev_stats->rx_fifo_errors+ - amd8111e_read_mib(mmio, rcv_miss_pkts); + new_stats->rx_fifo_errors = amd8111e_read_mib(mmio, rcv_miss_pkts); /* stats.rx_missed_errors */ - new_stats->rx_missed_errors = prev_stats->rx_missed_errors+ - amd8111e_read_mib(mmio, rcv_miss_pkts); + new_stats->rx_missed_errors = amd8111e_read_mib(mmio, rcv_miss_pkts); /* stats.tx_aborted_errors*/ - new_stats->tx_aborted_errors = prev_stats->tx_aborted_errors+ + new_stats->tx_aborted_errors = amd8111e_read_mib(mmio, xmt_excessive_collision); /* stats.tx_carrier_errors*/ - new_stats->tx_carrier_errors = prev_stats->tx_carrier_errors+ + new_stats->tx_carrier_errors = amd8111e_read_mib(mmio, xmt_loss_carrier); /* stats.tx_fifo_errors*/ - new_stats->tx_fifo_errors = prev_stats->tx_fifo_errors+ - amd8111e_read_mib(mmio, xmt_underrun_pkts); + new_stats->tx_fifo_errors = amd8111e_read_mib(mmio, xmt_underrun_pkts); /* stats.tx_window_errors*/ - new_stats->tx_window_errors = prev_stats->tx_window_errors+ + new_stats->tx_window_errors = amd8111e_read_mib(mmio, xmt_late_collision); + /* Reset the mibs for collecting new statistics */ + /* writew(MIB_CLEAR, mmio + MIB_ADDR);*/ + spin_unlock_irqrestore (&lp->lock, flags); return new_stats; } +/* This function recalculate the interupt coalescing mode on every interrupt +according to the datarate and the packet rate. +*/ +static int amd8111e_calc_coalesce(struct net_device *dev) +{ + struct amd8111e_priv *lp = dev->priv; + struct amd8111e_coalesce_conf * coal_conf = &lp->coal_conf; + int tx_pkt_rate; + int rx_pkt_rate; + int tx_data_rate; + int rx_data_rate; + int rx_pkt_size; + int tx_pkt_size; + + tx_pkt_rate = coal_conf->tx_packets - coal_conf->tx_prev_packets; + coal_conf->tx_prev_packets = coal_conf->tx_packets; + + tx_data_rate = coal_conf->tx_bytes - coal_conf->tx_prev_bytes; + coal_conf->tx_prev_bytes = coal_conf->tx_bytes; + + rx_pkt_rate = coal_conf->rx_packets - coal_conf->rx_prev_packets; + coal_conf->rx_prev_packets = coal_conf->rx_packets; + + rx_data_rate = coal_conf->rx_bytes - coal_conf->rx_prev_bytes; + coal_conf->rx_prev_bytes = coal_conf->rx_bytes; + + if(rx_pkt_rate < 800){ + if(coal_conf->rx_coal_type != NO_COALESCE){ + + coal_conf->rx_timeout = 0x0; + coal_conf->rx_event_count = 0; + amd8111e_set_coalesce(dev,RX_INTR_COAL); + coal_conf->rx_coal_type = NO_COALESCE; + } + } + else{ + + rx_pkt_size = rx_data_rate/rx_pkt_rate; + if (rx_pkt_size < 128){ + if(coal_conf->rx_coal_type != NO_COALESCE){ + + coal_conf->rx_timeout = 0; + coal_conf->rx_event_count = 0; + amd8111e_set_coalesce(dev,RX_INTR_COAL); + coal_conf->rx_coal_type = NO_COALESCE; + } + } + else if ( (rx_pkt_size >= 128) && (rx_pkt_size < 512) ){ + + if(coal_conf->rx_coal_type != LOW_COALESCE){ + coal_conf->rx_timeout = 1; + coal_conf->rx_event_count = 4; + amd8111e_set_coalesce(dev,RX_INTR_COAL); + coal_conf->rx_coal_type = LOW_COALESCE; + } + } + else if ((rx_pkt_size >= 512) && (rx_pkt_size < 1024)){ + + if(coal_conf->rx_coal_type != MEDIUM_COALESCE){ + coal_conf->rx_timeout = 1; + coal_conf->rx_event_count = 4; + amd8111e_set_coalesce(dev,RX_INTR_COAL); + coal_conf->rx_coal_type = MEDIUM_COALESCE; + } + + } + else if(rx_pkt_size >= 1024){ + if(coal_conf->rx_coal_type != HIGH_COALESCE){ + coal_conf->rx_timeout = 2; + coal_conf->rx_event_count = 3; + amd8111e_set_coalesce(dev,RX_INTR_COAL); + coal_conf->rx_coal_type = HIGH_COALESCE; + } + } + } + /* NOW FOR TX INTR COALESC */ + if(tx_pkt_rate < 800){ + if(coal_conf->tx_coal_type != NO_COALESCE){ + + coal_conf->tx_timeout = 0x0; + coal_conf->tx_event_count = 0; + amd8111e_set_coalesce(dev,TX_INTR_COAL); + coal_conf->tx_coal_type = NO_COALESCE; + } + } + else{ + + tx_pkt_size = tx_data_rate/tx_pkt_rate; + if (tx_pkt_size < 128){ + + if(coal_conf->tx_coal_type != NO_COALESCE){ + + coal_conf->tx_timeout = 0; + coal_conf->tx_event_count = 0; + amd8111e_set_coalesce(dev,TX_INTR_COAL); + coal_conf->tx_coal_type = NO_COALESCE; + } + + } + else if ( (tx_pkt_size >= 128) && (tx_pkt_size < 512) ){ + + if(coal_conf->tx_coal_type != LOW_COALESCE){ + coal_conf->tx_timeout = 1; + coal_conf->tx_event_count = 2; + amd8111e_set_coalesce(dev,TX_INTR_COAL); + coal_conf->tx_coal_type = LOW_COALESCE; + + } + } + else if ((tx_pkt_size >= 512) && (tx_pkt_size < 1024)){ + + if(coal_conf->tx_coal_type != MEDIUM_COALESCE){ + coal_conf->tx_timeout = 2; + coal_conf->tx_event_count = 5; + amd8111e_set_coalesce(dev,TX_INTR_COAL); + coal_conf->tx_coal_type = MEDIUM_COALESCE; + } + + } + else if(tx_pkt_size >= 1024){ + if (tx_pkt_size >= 1024){ + if(coal_conf->tx_coal_type != HIGH_COALESCE){ + coal_conf->tx_timeout = 4; + coal_conf->tx_event_count = 8; + amd8111e_set_coalesce(dev,TX_INTR_COAL); + coal_conf->tx_coal_type = HIGH_COALESCE; + } + } + } + } + return 0; + +} /* -This is device interrupt function. It handles transmit, receive and link change interrupts. +This is device interrupt function. It handles transmit, receive,link change and hardware timer interrupts. */ -static irqreturn_t -amd8111e_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t amd8111e_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct net_device * dev = (struct net_device *) dev_id; struct amd8111e_priv *lp = dev->priv; void * mmio = lp->mmio; unsigned int intr0; - int handled = 0; + unsigned int handled = 1; if(dev == NULL) return IRQ_NONE; - spin_lock (&lp->lock); + if (regs) spin_lock (&lp->lock); /* disabling interrupt */ writel(INTREN, mmio + CMD0); @@ -802,10 +1117,11 @@ /* Process all the INT event until INTR bit is clear. */ - if (!(intr0 & INTR)) + if (!(intr0 & INTR)) { + handled = 0; goto err_no_interrupt; - - handled = 1; + } + /* Current driver processes 3 interrupts : RINT,TINT,LCINT */ writel(intr0, mmio + INT0); @@ -822,15 +1138,21 @@ /* Check if Link Change Interrupt has occurred. */ if (intr0 & LCINT) amd8111e_link_change(dev); - + + /* Check if Hardware Timer Interrupt has occurred. */ + if (intr0 & STINT) + amd8111e_calc_coalesce(dev); + err_no_interrupt: writel( VAL0 | INTREN,mmio + CMD0); - spin_unlock(&lp->lock); + + if (regs) spin_unlock(&lp->lock); + return IRQ_RETVAL(handled); - } + /* -This function closes the network interface and copies the new set of statistics into the previous statistics structure so that most recent statistics will be available after the interface is down. +This function closes the network interface and updates the statistics so that most recent statistics will be available after the interface is down. */ static int amd8111e_close(struct net_device * dev) { @@ -845,10 +1167,15 @@ netif_carrier_off(lp->amd8111e_net_dev); + /* Delete ipg timer */ + if(lp->options & OPTION_DYN_IPG_ENABLE) + del_timer_sync(&lp->ipg_data.ipg_timer); + + /* Update the statistics before closing */ + amd8111e_get_stats(dev); spin_unlock_irq(&lp->lock); free_irq(dev->irq, dev); - memcpy(&lp->prev_stats,amd8111e_get_stats(dev), sizeof(lp->prev_stats)); lp->opened = 0; return 0; } @@ -870,7 +1197,12 @@ spin_unlock_irq(&lp->lock); return -ENOMEM; } - + /* Start ipg timer */ + if(lp->options & OPTION_DYN_IPG_ENABLE){ + add_timer(&lp->ipg_data.ipg_timer); + printk(KERN_INFO "%s: Dynamic IPG Enabled.\n",dev->name); + } + lp->opened = 1; spin_unlock_irq(&lp->lock); @@ -908,11 +1240,10 @@ lp->tx_ring[tx_index].buff_count = cpu_to_le16(skb->len); lp->tx_skbuff[tx_index] = skb; - lp->tx_ring[tx_index].tx_dr_offset2 = 0; + lp->tx_ring[tx_index].tx_flags = 0; #if AMD8111E_VLAN_TAG_USED if((lp->vlgrp != NULL) && vlan_tx_tag_present(skb)){ - lp->tx_ring[tx_index].tag_ctrl_cmd |= cpu_to_le32(TCC_VLAN_INSERT); lp->tx_ring[tx_index].tag_ctrl_info = @@ -926,7 +1257,7 @@ (u32) cpu_to_le32(lp->tx_dma_addr[tx_index]); /* Set FCS and LTINT bits */ - lp->tx_ring[tx_index].tx_dr_offset2 |= + lp->tx_ring[tx_index].tx_flags |= cpu_to_le16(OWN_BIT | STP_BIT | ENP_BIT|ADD_FCS_BIT|LTINT_BIT); lp->tx_idx++; @@ -949,16 +1280,54 @@ static char* amd8111e_read_regs(struct amd8111e_priv* lp) { void * mmio = lp->mmio; - unsigned char * reg_buff; + u32 * reg_buff; - int i; - reg_buff = kmalloc( AMD8111E_REG_DUMP_LEN,GFP_KERNEL); if(NULL == reg_buff) return NULL; - for (i=0; i < AMD8111E_REG_DUMP_LEN; i+=4) - reg_buff[i]= readl(mmio + i); - return reg_buff; + + /* Read only necessary registers */ + reg_buff[0] = readl(mmio + XMT_RING_BASE_ADDR0); + reg_buff[1] = readl(mmio + XMT_RING_LEN0); + reg_buff[2] = readl(mmio + RCV_RING_BASE_ADDR0); + reg_buff[3] = readl(mmio + RCV_RING_LEN0); + reg_buff[4] = readl(mmio + CMD0); + reg_buff[5] = readl(mmio + CMD2); + reg_buff[6] = readl(mmio + CMD3); + reg_buff[7] = readl(mmio + CMD7); + reg_buff[8] = readl(mmio + INT0); + reg_buff[9] = readl(mmio + INTEN0); + reg_buff[10] = readl(mmio + LADRF); + reg_buff[11] = readl(mmio + LADRF+4); + reg_buff[12] = readl(mmio + STAT0); + + return (char *)reg_buff; +} +/* +amd8111e crc generator implementation is different from the kernel +ether_crc() function. +*/ +int amd8111e_ether_crc(int len, char* mac_addr) +{ + int i,byte; + unsigned char octet; + u32 crc= INITCRC; + + for(byte=0; byte < len; byte++){ + octet = mac_addr[byte]; + for( i=0;i < 8; i++){ + /*If the next bit form the input stream is 1,subtract the divisor (CRC32) from the dividend(crc).*/ + if( (octet & 0x1) ^ (crc & 0x1) ){ + crc >>= 1; + crc ^= CRC32; + } + else + crc >>= 1; + + octet >>= 1; + } + } + return crc; } /* This function sets promiscuos mode, all-multi mode or the multicast address @@ -970,9 +1339,8 @@ struct amd8111e_priv *lp = dev->priv; u32 mc_filter[2] ; int i,bit_num; - if(dev->flags & IFF_PROMISC){ - printk("%s: Setting promiscuous mode.\n",dev->name); + printk(KERN_INFO "%s: Setting promiscuous mode.\n",dev->name); writel( VAL2 | PROM, lp->mmio + CMD2); return; } @@ -983,7 +1351,7 @@ mc_filter[1] = mc_filter[0] = 0xffffffff; lp->mc_list = dev->mc_list; lp->options |= OPTION_MULTICAST_ENABLE; - AMD8111E_WRITE_REG64(lp->mmio, LADRF,mc_filter); + amd8111e_writeq(*(u64*)mc_filter,lp->mmio + LADRF); return; } if( dev->mc_count == 0 ){ @@ -991,7 +1359,7 @@ mc_filter[1] = mc_filter[0] = 0; lp->mc_list = 0; lp->options &= ~OPTION_MULTICAST_ENABLE; - AMD8111E_WRITE_REG64(lp->mmio, LADRF,mc_filter); + amd8111e_writeq(*(u64*)mc_filter,lp->mmio + LADRF); /* disable promiscous mode */ writel(PROM, lp->mmio + CMD2); return; @@ -1002,14 +1370,16 @@ mc_filter[1] = mc_filter[0] = 0; for (i = 0, mc_ptr = dev->mc_list; mc_ptr && i < dev->mc_count; i++, mc_ptr = mc_ptr->next) { - bit_num = ether_crc(ETH_ALEN, mc_ptr->dmi_addr) >> 26; - + bit_num = ( amd8111e_ether_crc(ETH_ALEN,mc_ptr->dmi_addr) >> 26 ) & 0x3f; mc_filter[bit_num >> 5] |= 1 << (bit_num & 31); } + amd8111e_writeq(*(u64*)mc_filter,lp->mmio+ LADRF); + + /* To eliminate PCI posting bug */ + readl(lp->mmio + CMD2); - AMD8111E_WRITE_REG64(lp->mmio, LADRF, mc_filter); - return; } + /* This function handles all the ethtool ioctls. It gives driver info, gets/sets driver speed, gets memory mapped register values, forces auto negotiation, sets/gets WOL options for ethtool application. */ @@ -1032,6 +1402,7 @@ strcpy (info.driver, MODULE_NAME); strcpy (info.version, MODULE_VERSION); memset(&info.fw_version, 0, sizeof(info.fw_version)); + sprintf(info.fw_version,"%u",chip_version); strcpy (info.bus_info, pci_dev->slot_name); info.eedump_len = 0; info.regdump_len = AMD8111E_REG_DUMP_LEN; @@ -1039,85 +1410,27 @@ return -EFAULT; return 0; } - case ETHTOOL_GSET:{ - struct ethtool_cmd cmd = { ETHTOOL_GSET }; - - if (!lp->opened) - return -EAGAIN; - - cmd.supported = SUPPORTED_Autoneg | - SUPPORTED_100baseT_Half | - SUPPORTED_100baseT_Full | - SUPPORTED_10baseT_Half | - SUPPORTED_10baseT_Full | - SUPPORTED_MII; - - cmd.advertising = ADVERTISED_Autoneg | - ADVERTISED_100baseT_Half | - ADVERTISED_100baseT_Full | - ADVERTISED_10baseT_Half | - ADVERTISED_10baseT_Full | - ADVERTISED_MII; - cmd.speed = lp->link_config.speed; - cmd.duplex = lp->link_config.duplex; - cmd.port = 0; - cmd.phy_address = PHY_ID; - cmd.transceiver = XCVR_EXTERNAL; - cmd.autoneg = lp->link_config.autoneg; - cmd.maxtxpkt = 0; /* not implemented interrupt coalasing */ - cmd.maxrxpkt = 0; /* not implemented interrupt coalasing */ - if (copy_to_user(useraddr, &cmd, sizeof(cmd))) + /* get settings */ + case ETHTOOL_GSET: { + struct ethtool_cmd ecmd = { ETHTOOL_GSET }; + spin_lock_irq(&lp->lock); + mii_ethtool_gset(&lp->mii_if, &ecmd); + spin_unlock_irq(&lp->lock); + if (copy_to_user(useraddr, &ecmd, sizeof(ecmd))) return -EFAULT; return 0; - } + } + /* set settings */ case ETHTOOL_SSET: { - - struct ethtool_cmd cmd; - - if (!lp->opened) - return -EAGAIN; - if (copy_from_user(&cmd, useraddr, sizeof(cmd))) + int r; + struct ethtool_cmd ecmd; + if (copy_from_user(&ecmd, useraddr, sizeof(ecmd))) return -EFAULT; spin_lock_irq(&lp->lock); - - if(cmd.autoneg == AUTONEG_ENABLE){ - /* keeping the original speeds */ - if((lp->link_config.speed != SPEED_INVALID)&& - (lp->link_config.duplex != DUPLEX_INVALID)){ - lp->link_config.orig_speed = lp->link_config.speed; - lp->link_config.orig_duplex = lp->link_config.duplex; - lp->link_config.orig_phy_option = lp->ext_phy_option; - } - - lp->ext_phy_option = XPHYANE; - } - else if(cmd.speed == SPEED_100 && cmd.duplex == DUPLEX_HALF) - lp->ext_phy_option = XPHYSP; - else if(cmd.speed == SPEED_100 && cmd.duplex == DUPLEX_FULL) - lp->ext_phy_option = XPHYSP |XPHYFD; - else if(cmd.speed == SPEED_10 && cmd.duplex == DUPLEX_HALF) - lp->ext_phy_option = 0; - else if(cmd.speed == SPEED_10 && cmd.duplex == DUPLEX_FULL) - lp->ext_phy_option = XPHYFD; - else { - /* setting the original speed */ - cmd.speed = lp->link_config.orig_speed; - cmd.duplex = lp->link_config.orig_duplex; - lp->ext_phy_option = lp->link_config.orig_phy_option; - } - lp->link_config.autoneg = cmd.autoneg; - if (cmd.autoneg == AUTONEG_ENABLE) { - - lp->link_config.speed = SPEED_INVALID; - lp->link_config.duplex = DUPLEX_INVALID; - } else { - lp->link_config.speed = cmd.speed; - lp->link_config.duplex = cmd.duplex; - } - amd8111e_set_ext_phy(dev); + r = mii_ethtool_sset(&lp->mii_if, &ecmd); spin_unlock_irq(&lp->lock); - return 0; + return r; } case ETHTOOL_GREGS: { struct ethtool_regs regs; @@ -1143,24 +1456,17 @@ kfree(regbuf); return ret; } + /* restart autonegotiation */ case ETHTOOL_NWAY_RST: { - int ret; - spin_lock_irq(&lp->lock); - if(lp->link_config.autoneg == AUTONEG_ENABLE){ - lp->ext_phy_option = XPHYANE; - amd8111e_set_ext_phy(dev); - ret = 0; - }else - ret = -EINVAL; - spin_unlock_irq(&lp->lock); - return ret; + return mii_nway_restart(&lp->mii_if); } + /* get link status */ case ETHTOOL_GLINK: { - struct ethtool_value val = { ETHTOOL_GLINK }; - - val.data = netif_carrier_ok(dev) ? 1 : 0; + struct ethtool_value val = {ETHTOOL_GLINK}; + val.data = mii_link_ok(&lp->mii_if); if (copy_to_user(useraddr, &val, sizeof(val))) return -EFAULT; + return 0; } case ETHTOOL_GWOL: { struct ethtool_wolinfo wol_info = { ETHTOOL_GWOL }; @@ -1199,60 +1505,6 @@ } return -EOPNOTSUPP; } -static int amd8111e_read_phy(struct amd8111e_priv* lp, int phy_id, int reg, u32* val) -{ - void * mmio = lp->mmio; - unsigned int reg_val; - unsigned int repeat= REPEAT_CNT; - - reg_val = readl(mmio + PHY_ACCESS); - while (reg_val & PHY_CMD_ACTIVE) - reg_val = readl( mmio + PHY_ACCESS ); - - writel( PHY_RD_CMD | ((phy_id & 0x1f) << 21) | - ((reg & 0x1f) << 16), mmio +PHY_ACCESS); - do{ - reg_val = readl(mmio + PHY_ACCESS); - udelay(30); /* It takes 30 us to read/write data */ - } while (--repeat && (reg_val & PHY_CMD_ACTIVE)); - if(reg_val & PHY_RD_ERR) - goto err_phy_read; - - *val = reg_val & 0xffff; - return 0; -err_phy_read: - *val = 0; - return -EINVAL; - -} -static int amd8111e_write_phy(struct amd8111e_priv* lp,int phy_id, int reg, u32 val) -{ - unsigned int repeat = REPEAT_CNT - void * mmio = lp->mmio; - unsigned int reg_val; - - - reg_val = readl(mmio + PHY_ACCESS); - while (reg_val & PHY_CMD_ACTIVE) - reg_val = readl( mmio + PHY_ACCESS ); - - writel( PHY_WR_CMD | ((phy_id & 0x1f) << 21) | - ((reg & 0x1f) << 16)|val, mmio + PHY_ACCESS); - - do{ - reg_val = readl(mmio + PHY_ACCESS); - udelay(30); /* It takes 30 us to read/write the data */ - } while (--repeat && (reg_val & PHY_CMD_ACTIVE)); - - if(reg_val & PHY_RD_ERR) - goto err_phy_write; - - return 0; - -err_phy_write: - return -EINVAL; - -} static int amd8111e_ioctl(struct net_device * dev , struct ifreq *ifr, int cmd) { struct mii_ioctl_data *data = (struct mii_ioctl_data *)&ifr->ifr_data; @@ -1320,15 +1572,10 @@ dev->mtu = new_mtu; - /* if (new_mtu > ETH_DATA_LEN) - lp->options |= OPTION_JUMBO_ENABLE; - else - lp->options &= ~OPTION_JUMBO_ENABLE; - */ err = amd8111e_restart(dev); spin_unlock_irq(&lp->lock); - - netif_start_queue(dev); + if(!err) + netif_start_queue(dev); return err; } @@ -1354,73 +1601,41 @@ { writel( VAL1|MPPLBA, lp->mmio + CMD3); writel( VAL0|MPEN_SW, lp->mmio + CMD7); + + /* To eliminate PCI posting bug */ + readl(lp->mmio + CMD7); return 0; } static int amd8111e_enable_link_change(struct amd8111e_priv* lp) { + /* Adapter is already stoped/suspended/interrupt-disabled */ writel(VAL0|LCMODE_SW,lp->mmio + CMD7); - return 0; -} - -/* -This function sets the power state of the device. When the device go to lower power states 1,2, and 3 it enables the wake on lan -*/ -static int amd8111e_set_power_state(struct amd8111e_priv* lp, u32 state) -{ - u16 power_control; - int pm = lp->pm_cap; - - pci_read_config_word(lp->pci_dev, - pm + PCI_PM_CTRL, - &power_control); - - power_control |= PCI_PM_CTRL_PME_STATUS; - power_control &= ~(PCI_PM_CTRL_STATE_MASK); - switch (state) { - case 0: - power_control |= 0; - pci_write_config_word(lp->pci_dev, - pm + PCI_PM_CTRL, - power_control); - return 0; - - case 1: - power_control |= 1; - break; - - case 2: - power_control |= 2; - break; - - case 3: - power_control |= 3; - break; - default: - - printk(KERN_WARNING "%s: Invalid power state (%d) requested.\n", - lp->amd8111e_net_dev->name, state); - return -EINVAL; - } - if(lp->options & OPTION_WAKE_MAGIC_ENABLE) - amd8111e_enable_magicpkt(lp); - if(lp->options & OPTION_WAKE_PHY_ENABLE) - amd8111e_enable_link_change(lp); - - /* Setting new power state. */ - pci_write_config_word(lp->pci_dev, pm + PCI_PM_CTRL, power_control); - + /* To eliminate PCI posting bug */ + readl(lp->mmio + CMD7); return 0; +} +/* This function is called when a packet transmission fails to complete within a resonable period, on the assumption that an interrupts have been failed or the interface is locked up. This function will reinitialize the hardware */ +static void amd8111e_tx_timeout(struct net_device *dev) +{ + struct amd8111e_priv* lp = dev->priv; + int err; + printk(KERN_ERR "%s: transmit timed out, resetting\n", + dev->name); + spin_lock_irq(&lp->lock); + err = amd8111e_restart(dev); + spin_unlock_irq(&lp->lock); + if(!err) + netif_wake_queue(dev); } static int amd8111e_suspend(struct pci_dev *pci_dev, u32 state) { struct net_device *dev = pci_get_drvdata(pci_dev); struct amd8111e_priv *lp = dev->priv; - int err; if (!netif_running(dev)) return 0; @@ -1434,37 +1649,54 @@ /* stop chip */ spin_lock_irq(&lp->lock); + if(lp->options & OPTION_DYN_IPG_ENABLE) + del_timer_sync(&lp->ipg_data.ipg_timer); amd8111e_stop_chip(lp); spin_unlock_irq(&lp->lock); - err = amd8111e_set_power_state(lp, state); - if (err) { + if(lp->options & OPTION_WOL_ENABLE){ + /* enable wol */ + if(lp->options & OPTION_WAKE_MAGIC_ENABLE) + amd8111e_enable_magicpkt(lp); + if(lp->options & OPTION_WAKE_PHY_ENABLE) + amd8111e_enable_link_change(lp); - spin_lock_irq(&lp->lock); - amd8111e_restart(dev); - spin_unlock_irq(&lp->lock); + pci_enable_wake(pci_dev, 3, 1); + pci_enable_wake(pci_dev, 4, 1); /* D3 cold */ - netif_device_attach(dev); } - return err; + else{ + pci_enable_wake(pci_dev, 3, 0); + pci_enable_wake(pci_dev, 4, 0); /* 4 == D3 cold */ + } + + pci_save_state(pci_dev, lp->pm_state); + pci_set_power_state(pci_dev, 3); + + return 0; } static int amd8111e_resume(struct pci_dev *pci_dev) { struct net_device *dev = pci_get_drvdata(pci_dev); struct amd8111e_priv *lp = dev->priv; - int err; if (!netif_running(dev)) return 0; - err = amd8111e_set_power_state(lp, 0); - if (err) - return err; + pci_set_power_state(pci_dev, 0); + pci_restore_state(pci_dev, lp->pm_state); + + pci_enable_wake(pci_dev, 3, 0); + pci_enable_wake(pci_dev, 4, 0); /* D3 cold */ netif_device_attach(dev); spin_lock_irq(&lp->lock); amd8111e_restart(dev); + /* Restart ipg timer */ + if(lp->options & OPTION_DYN_IPG_ENABLE) + mod_timer(&lp->ipg_data.ipg_timer, + jiffies + (IPG_CONVERGE_TIME * HZ)); spin_unlock_irq(&lp->lock); return 0; @@ -1483,6 +1715,65 @@ pci_set_drvdata(pdev, NULL); } } +static void amd8111e_config_ipg(struct net_device* dev) +{ + struct amd8111e_priv *lp = dev->priv; + struct ipg_info* ipg_data = &lp->ipg_data; + void * mmio = lp->mmio; + unsigned int prev_col_cnt = ipg_data->col_cnt; + unsigned int total_col_cnt; + unsigned int tmp_ipg; + + if(lp->link_config.duplex == DUPLEX_FULL){ + ipg_data->ipg = DEFAULT_IPG; + return; + } + + if(ipg_data->ipg_state == SSTATE){ + + if(ipg_data->timer_tick == IPG_STABLE_TIME){ + + ipg_data->timer_tick = 0; + ipg_data->ipg = MIN_IPG - IPG_STEP; + ipg_data->current_ipg = MIN_IPG; + ipg_data->diff_col_cnt = 0xFFFFFFFF; + ipg_data->ipg_state = CSTATE; + } + else + ipg_data->timer_tick++; + } + + if(ipg_data->ipg_state == CSTATE){ + + /* Get the current collision count */ + + total_col_cnt = ipg_data->col_cnt = + amd8111e_read_mib(mmio, xmt_collisions); + + if ((total_col_cnt - prev_col_cnt) < + (ipg_data->diff_col_cnt)){ + + ipg_data->diff_col_cnt = + total_col_cnt - prev_col_cnt ; + + ipg_data->ipg = ipg_data->current_ipg; + } + + ipg_data->current_ipg += IPG_STEP; + + if (ipg_data->current_ipg <= MAX_IPG) + tmp_ipg = ipg_data->current_ipg; + else{ + tmp_ipg = ipg_data->ipg; + ipg_data->ipg_state = SSTATE; + } + writew((u32)tmp_ipg, mmio + IPG); + writew((u32)(tmp_ipg - IFS1_DELTA), mmio + IFS1); + } + mod_timer(&lp->ipg_data.ipg_timer, jiffies + (IPG_CONVERGE_TIME * HZ)); + return; + +} static int __devinit amd8111e_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -1491,7 +1782,6 @@ unsigned long reg_addr,reg_len; struct amd8111e_priv* lp; struct net_device* dev; - unsigned int chip_version; err = pci_enable_device(pdev); if(err){ @@ -1542,7 +1832,6 @@ } SET_MODULE_OWNER(dev); - SET_NETDEV_DEV(dev, &pdev->dev); #if AMD8111E_VLAN_TAG_USED dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX ; @@ -1551,11 +1840,16 @@ #endif lp = dev->priv; - memset (lp, 0, sizeof (*lp)); lp->pci_dev = pdev; lp->amd8111e_net_dev = dev; lp->pm_cap = pm_cap; + /* setting mii default values */ + lp->mii_if.dev = dev; + lp->mii_if.mdio_read = amd8111e_mdio_read; + lp->mii_if.mdio_write = amd8111e_mdio_write; + lp->mii_if.phy_id = PHY_ID; + spin_lock_init(&lp->lock); lp->mmio = ioremap(reg_addr, reg_len); @@ -1569,12 +1863,14 @@ /* Initializing MAC address */ for(i = 0; i < ETH_ADDR_LEN; i++) dev->dev_addr[i] =readb(lp->mmio + PADR + i); - /* Setting user defined speed */ - if (speed_duplex[card_idx] > sizeof(speed_duplex_mapping)) - lp->ext_phy_option = XPHYANE; - else - lp->ext_phy_option = - speed_duplex_mapping[speed_duplex[card_idx]]; + + /* Setting user defined parametrs */ + lp->ext_phy_option = speed_duplex[card_idx]; + if(coalesce[card_idx]) + lp->options |= OPTION_INTR_COAL_ENABLE; + if(dynamic_ipg[card_idx++]) + lp->options |= OPTION_DYN_IPG_ENABLE; + /* Initialize driver entry points */ dev->open = amd8111e_open; dev->hard_start_xmit = amd8111e_start_xmit; @@ -1584,6 +1880,8 @@ dev->do_ioctl = amd8111e_ioctl; dev->change_mtu = amd8111e_change_mtu; dev->irq =pdev->irq; + dev->tx_timeout = amd8111e_tx_timeout; + dev->watchdog_timeo = AMD8111E_TX_TIMEOUT; #if AMD8111E_VLAN_TAG_USED dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; @@ -1593,10 +1891,6 @@ /* Set receive buffer length and set jumbo option*/ amd8111e_set_rx_buff_len(dev); - - - /* dev->tx_timeout = tg3_tx_timeout; */ - /* dev->watchdog_timeo = TG3_TX_TIMEOUT; */ err = register_netdev(dev); if (err) { @@ -1607,15 +1901,26 @@ pci_set_drvdata(pdev, dev); + /* Initialize software ipg timer */ + if(lp->options & OPTION_DYN_IPG_ENABLE){ + init_timer(&lp->ipg_data.ipg_timer); + lp->ipg_data.ipg_timer.data = (unsigned long) dev; + lp->ipg_data.ipg_timer.function = (void *)&amd8111e_config_ipg; + lp->ipg_data.ipg_timer.expires = jiffies + + IPG_CONVERGE_TIME * HZ; + lp->ipg_data.ipg = DEFAULT_IPG; + lp->ipg_data.ipg_state = CSTATE; + }; + /* display driver and device information */ - chip_version = (readl(lp->mmio + CHIPID) & 0xf0000000)>>28; - printk("%s: AMD-8111e Driver Version: %s\n",dev->name,MODULE_VERSION); - printk("%s: [ Rev %x ] PCI 10/100BaseT Ethernet ", dev->name, chip_version); - for (i = 0; i < 6; i++) - printk("%2.2x%c", dev->dev_addr[i],i == 5 ? ' ' : ':'); - printk("\n"); - return 0; + chip_version = (readl(lp->mmio + CHIPID) & 0xf0000000)>>28; + printk(KERN_INFO "%s: AMD-8111e Driver Version: %s\n", dev->name,MODULE_VERSION); + printk(KERN_INFO "%s: [ Rev %x ] PCI 10/100BaseT Ethernet ", dev->name, chip_version); + for (i = 0; i < 6; i++) + printk("%2.2x%c",dev->dev_addr[i],i == 5 ? ' ' : ':'); + printk( "\n"); + return 0; err_iounmap: iounmap((void *) lp->mmio); diff -Nru a/drivers/net/amd8111e.h b/drivers/net/amd8111e.h --- a/drivers/net/amd8111e.h Mon Jun 9 23:16:07 2003 +++ b/drivers/net/amd8111e.h Mon Jun 9 23:16:07 2003 @@ -1,4 +1,7 @@ /* + * Advanced Micro Devices Inc. AMD8111E Linux Network Driver + * Copyright (C) 2003 Advanced Micro Devices + * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or @@ -27,73 +30,14 @@ Kernel Mode Revision History: - + 3.0.0 + Initial Revision. + 3.0.1 */ #ifndef _AMD811E_H #define _AMD811E_H -/* Hardware definitions */ - -#define B31_MASK 0x80000000 -#define B30_MASK 0X40000000 -#define B29_MASK 0x20000000 -#define B28_MASK 0x10000000 -#define B27_MASK 0x08000000 -#define B26_MASK 0x04000000 -#define B25_MASK 0x02000000 -#define B24_MASK 0x01000000 -#define B23_MASK 0x00800000 -#define B22_MASK 0x00400000 -#define B21_MASK 0x00200000 -#define B20_MASK 0x00100000 -#define B19_MASK 0x00080000 -#define B18_MASK 0x00040000 -#define B17_MASK 0x00020000 -#define B16_MASK 0x00010000 - -#define B15_MASK 0x8000 -#define B14_MASK 0x4000 -#define B13_MASK 0x2000 -#define B12_MASK 0x1000 -#define B11_MASK 0x0800 -#define B10_MASK 0x0400 -#define B9_MASK 0x0200 -#define B8_MASK 0x0100 -#define B7_MASK 0x0080 -#define B6_MASK 0x0040 -#define B5_MASK 0x0020 -#define B4_MASK 0x0010 -#define B3_MASK 0x0008 -#define B2_MASK 0x0004 -#define B1_MASK 0x0002 -#define B0_MASK 0x0001 - -/* PCI register offset */ -#define PCI_ID_REG 0x00 -#define PCI_COMMAND_REG 0x04 -/* #define MEMEN_BIT B1_MASK */ -/* #define IOEN_BIT B0_MASK */ -#define PCI_REV_ID_REG 0x08 -#define PCI_MEM_BASE_REG 0x10 -/* #define MEMBASE_MASK 0xFFFFF000 */ -/* #define MEMBASE_SIZE 4096 */ -#define PCI_INTR_REG 0x3C -#define PCI_STATUS_REG 0x06 -#define PCI_CAP_ID_REG_OFFSET 0x34 -#define PCI_PMC_REG_OFFSET 0x36 -#define PCI_PMCSR_REG_OFFSET 0x38 - -/* #define NEW_CAP 0x0010 */ -#define PME_EN 0x0100 - -#define PARTID_MASK 0xFFFFF000 -#define PARTID_START_BIT 12 - -/* #define LANCE_DWIO_RESET_PORT 0x18 -#define LANCE_WIO_RESET_PORT 0x14 */ -#define MIB_OFFSET 0x28 - /* Command style register access Registers CMD0, CMD2, CMD3,CMD7 and INTEN0 uses a write access technique called command style access. It allows the write to selected bits of this register without altering the bits that are not selected. Command style registers are divided into 4 bytes that can be written independently. Higher order bit of each byte is the value bit that specifies the value that will be written into the selected bits of register. @@ -155,7 +99,7 @@ #define XMT_RING_LEN2 0x148 /* Transmit Ring2 length register */ #define XMT_RING_LEN3 0x14C /* Transmit Ring3 length register */ -#define RCV_RING_LEN0 0x150 /* Transmit Ring0 length register */ +#define RCV_RING_LEN0 0x150 /* Receive Ring0 length register */ #define SRAM_SIZE 0x178 /* SRAM size register */ #define SRAM_BOUNDARY 0x17A /* SRAM boundary register */ @@ -164,391 +108,398 @@ #define PADR 0x160 /* Physical address register */ +#define IFS1 0x18C /* Inter-frame spacing Part1 register */ +#define IFS 0x18D /* Inter-frame spacing register */ +#define IPG 0x18E /* Inter-frame gap register */ /* 64bit register */ #define LADRF 0x168 /* Logical address filter register */ -/* 8bit regsisters */ - -#define IFS1 0x18C /* Inter-frame spacing Part1 register */ -#define IFS 0x18D /* Inter-frame spacing register */ /* Register Bit Definitions */ +typedef enum { + + ASF_INIT_DONE = (1 << 1), + ASF_INIT_PRESENT = (1 << 0), + +}STAT_ASF_BITS; + +typedef enum { + + MIB_CMD_ACTIVE = (1 << 15 ), + MIB_RD_CMD = (1 << 13 ), + MIB_CLEAR = (1 << 12 ), + MIB_ADDRESS = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3)| + (1 << 4) | (1 << 5), +}MIB_ADDR_BITS; + + +typedef enum { + + PMAT_DET = (1 << 12), + MP_DET = (1 << 11), + LC_DET = (1 << 10), + SPEED_MASK = (1 << 9)|(1 << 8)|(1 << 7), + FULL_DPLX = (1 << 6), + LINK_STATS = (1 << 5), + AUTONEG_COMPLETE = (1 << 4), + MIIPD = (1 << 3), + RX_SUSPENDED = (1 << 2), + TX_SUSPENDED = (1 << 1), + RUNNING = (1 << 0), + +}STAT0_BITS; -/* STAT_ASF 0x00, 32bit register */ -#define ASF_INIT_DONE B1_MASK -#define ASF_INIT_PRESENT B0_MASK - -/* MIB_ADDR 0x14, 16bit register */ -#define MIB_CMD_ACTIVE B15_MASK -#define MIB_RD_CMD B13_MASK -#define MIB_CLEAR B12_MASK -#define MIB_ADDRESS 0x0000003F /* 5:0 */ - -/* QOS_ADDR 0x1C, 16bit register */ -#define QOS_CMD_ACTIVE B15_MASK -#define QOS_WR_CMD B14_MASK -#define QOS_RD_CMD B13_MASK -#define QOS_ADDRESS 0x0000001F /* 4:0 */ - -/* STAT0 0x30, 32bit register */ -#define PAUSE_PEND B14_MASK -#define PAUSING B13_MASK -#define PMAT_DET B12_MASK -#define MP_DET B11_MASK -#define LC_DET B10_MASK -#define SPEED_MASK 0x0380 /* 9:7 */ -#define FULL_DPLX B6_MASK -#define LINK_STATS B5_MASK -#define AUTONEG_COMPLETE B4_MASK -#define MIIPD B3_MASK -#define RX_SUSPENDED B2_MASK -#define TX_SUSPENDED B1_MASK -#define RUNNING B0_MASK #define PHY_SPEED_10 0x2 #define PHY_SPEED_100 0x3 /* INT0 0x38, 32bit register */ -#define INTR B31_MASK -#define PCSINT B28_MASK -#define LCINT B27_MASK -#define APINT5 B26_MASK -#define APINT4 B25_MASK -#define APINT3 B24_MASK -#define TINT_SUM B23_MASK -#define APINT2 B22_MASK -#define APINT1 B21_MASK -#define APINT0 B20_MASK -#define MIIPDTINT B19_MASK -#define MCCIINT B18_MASK -#define MCCINT B17_MASK -#define MREINT B16_MASK -#define RINT_SUM B15_MASK -#define SPNDINT B14_MASK -#define MPINT B13_MASK -#define SINT B12_MASK -#define TINT3 B11_MASK -#define TINT2 B10_MASK -#define TINT1 B9_MASK -#define TINT0 B8_MASK -#define UINT B7_MASK -#define STINT B4_MASK -#define RINT3 B3_MASK -#define RINT2 B2_MASK -#define RINT1 B1_MASK -#define RINT0 B0_MASK - -/* INTEN0 0x40, 32bit register */ -#define VAL3 B31_MASK /* VAL bit for byte 3 */ -#define VAL2 B23_MASK /* VAL bit for byte 2 */ -#define VAL1 B15_MASK /* VAL bit for byte 1 */ -#define VAL0 B7_MASK /* VAL bit for byte 0 */ -/* VAL3 */ -#define PSCINTEN B28_MASK -#define LCINTEN B27_MASK -#define APINT5EN B26_MASK -#define APINT4EN B25_MASK -#define APINT3EN B24_MASK -/* VAL2 */ -#define APINT2EN B22_MASK -#define APINT1EN B21_MASK -#define APINT0EN B20_MASK -#define MIIPDTINTEN B19_MASK -#define MCCIINTEN B18_MASK -#define MCCINTEN B17_MASK -#define MREINTEN B16_MASK -/* VAL1 */ -#define SPNDINTEN B14_MASK -#define MPINTEN B13_MASK -#define SINTEN B12_MASK -#define TINTEN3 B11_MASK -#define TINTEN2 B10_MASK -#define TINTEN1 B9_MASK -#define TINTEN0 B8_MASK -/* VAL0 */ -#define STINTEN B4_MASK -#define RINTEN3 B3_MASK -#define RINTEN2 B2_MASK -#define RINTEN1 B1_MASK -#define RINTEN0 B0_MASK - -#define INTEN0_CLEAR 0x1F7F7F1F /* Command style register */ - -/* CMD0 0x48, 32bit register */ -/* VAL2 */ -#define RDMD3 B19_MASK -#define RDMD2 B18_MASK -#define RDMD1 B17_MASK -#define RDMD0 B16_MASK -/* VAL1 */ -#define TDMD3 B11_MASK -#define TDMD2 B10_MASK -#define TDMD1 B9_MASK -#define TDMD0 B8_MASK -/* VAL0 */ -#define UINTCMD B6_MASK -#define RX_FAST_SPND B5_MASK -#define TX_FAST_SPND B4_MASK -#define RX_SPND B3_MASK -#define TX_SPND B2_MASK -#define INTREN B1_MASK -#define RUN B0_MASK - -#define CMD0_CLEAR 0x000F0F7F /* Command style register */ - -/* CMD2 0x50, 32bit register */ -/* VAL3 */ -#define CONDUIT_MODE B29_MASK -/* VAL2 */ -#define RPA B19_MASK -#define DRCVPA B18_MASK -#define DRCVBC B17_MASK -#define PROM B16_MASK -/* VAL1 */ -#define ASTRP_RCV B13_MASK -#define FCOLL B12_MASK -#define EMBA B11_MASK -#define DXMT2PD B10_MASK -#define LTINTEN B9_MASK -#define DXMTFCS B8_MASK -/* VAL0 */ -#define APAD_XMT B6_MASK -#define DRTY B5_MASK -#define INLOOP B4_MASK -#define EXLOOP B3_MASK -#define REX_RTRY B2_MASK -#define REX_UFLO B1_MASK -#define REX_LCOL B0_MASK - -#define CMD2_CLEAR 0x3F7F3F7F /* Command style register */ - -/* CMD3 0x54, 32bit register */ -/* VAL3 */ -#define ASF_INIT_DONE_ALIAS B29_MASK -/* VAL2 */ -#define JUMBO B21_MASK -#define VSIZE B20_MASK -#define VLONLY B19_MASK -#define VL_TAG_DEL B18_MASK -/* VAL1 */ -#define EN_PMGR B14_MASK -#define INTLEVEL B13_MASK -#define FORCE_FULL_DUPLEX B12_MASK -#define FORCE_LINK_STATUS B11_MASK -#define APEP B10_MASK -#define MPPLBA B9_MASK -/* VAL0 */ -#define RESET_PHY_PULSE B2_MASK -#define RESET_PHY B1_MASK -#define PHY_RST_POL B0_MASK -/* CMD7 0x64, 32bit register */ -/* VAL0 */ -#define PMAT_SAVE_MATCH B4_MASK -#define PMAT_MODE B3_MASK -#define MPEN_SW B1_MASK -#define LCMODE_SW B0_MASK - -#define CMD7_CLEAR 0x0000001B /* Command style register */ -/* CTRL0 0x68, 32bit register */ -#define PHY_SEL 0x03000000 /* 25:24 */ -#define RESET_PHY_WIDTH 0x00FF0000 /* 23:16 */ -#define BSWP_REGS B10_MASK -#define BSWP_DESC B9_MASK -#define BSWP_DATA B8_MASK -#define CACHE_ALIGN B4_MASK -#define BURST_LIMIT 0x0000000F /* 3:0 */ - -/* CTRL1 0x6C, 32bit register */ -#define SLOTMOD_MASK 0x03000000 /* 25:24 */ -#define XMTSP_MASK 0x300 /* 17:16 */ -#define XMTSP_128 0x200 -#define XMTSP_64 0x100 -#define CRTL1_DEFAULT 0x00000017 - -/* CTRL2 0x70, 32bit register */ -#define FS_MASK 0x00070000 /* 18:16 */ -#define FMDC_MASK 0x00000300 /* 9:8 */ -#define XPHYRST B7_MASK -#define XPHYANE B6_MASK -#define XPHYFD B5_MASK -#define XPHYSP B3_MASK /* 4:3 */ -#define APDW_MASK 0x00000007 /* 2:0 */ - -/* RCV_RING_CFG 0x78, 16bit register */ -#define RCV_DROP3 B11_MASK -#define RCV_DROP2 B10_MASK -#define RCV_DROP1 B9_MASK -#define RCV_DROP0 B8_MASK -#define RCV_RING_DEFAULT 0x0030 /* 5:4 */ -#define RCV_RING3_EN B3_MASK -#define RCV_RING2_EN B2_MASK -#define RCV_RING1_EN B1_MASK -#define RCV_RING0_EN B0_MASK +typedef enum { + + INTR = (1 << 31), + PCSINT = (1 << 28), + LCINT = (1 << 27), + APINT5 = (1 << 26), + APINT4 = (1 << 25), + APINT3 = (1 << 24), + TINT_SUM = (1 << 23), + APINT2 = (1 << 22), + APINT1 = (1 << 21), + APINT0 = (1 << 20), + MIIPDTINT = (1 << 19), + MCCINT = (1 << 17), + MREINT = (1 << 16), + RINT_SUM = (1 << 15), + SPNDINT = (1 << 14), + MPINT = (1 << 13), + SINT = (1 << 12), + TINT3 = (1 << 11), + TINT2 = (1 << 10), + TINT1 = (1 << 9), + TINT0 = (1 << 8), + UINT = (1 << 7), + STINT = (1 << 4), + RINT0 = (1 << 0), + +}INT0_BITS; + +typedef enum { + + VAL3 = (1 << 31), /* VAL bit for byte 3 */ + VAL2 = (1 << 23), /* VAL bit for byte 2 */ + VAL1 = (1 << 15), /* VAL bit for byte 1 */ + VAL0 = (1 << 7), /* VAL bit for byte 0 */ + +}VAL_BITS; + +typedef enum { + + /* VAL3 */ + LCINTEN = (1 << 27), + APINT5EN = (1 << 26), + APINT4EN = (1 << 25), + APINT3EN = (1 << 24), + /* VAL2 */ + APINT2EN = (1 << 22), + APINT1EN = (1 << 21), + APINT0EN = (1 << 20), + MIIPDTINTEN = (1 << 19), + MCCIINTEN = (1 << 18), + MCCINTEN = (1 << 17), + MREINTEN = (1 << 16), + /* VAL1 */ + SPNDINTEN = (1 << 14), + MPINTEN = (1 << 13), + TINTEN3 = (1 << 11), + SINTEN = (1 << 12), + TINTEN2 = (1 << 10), + TINTEN1 = (1 << 9), + TINTEN0 = (1 << 8), + /* VAL0 */ + STINTEN = (1 << 4), + RINTEN0 = (1 << 0), + + INTEN0_CLEAR = 0x1F7F7F1F, /* Command style register */ + +}INTEN0_BITS; + +typedef enum { + /* VAL2 */ + RDMD0 = (1 << 16), + /* VAL1 */ + TDMD3 = (1 << 11), + TDMD2 = (1 << 10), + TDMD1 = (1 << 9), + TDMD0 = (1 << 8), + /* VAL0 */ + UINTCMD = (1 << 6), + RX_FAST_SPND = (1 << 5), + TX_FAST_SPND = (1 << 4), + RX_SPND = (1 << 3), + TX_SPND = (1 << 2), + INTREN = (1 << 1), + RUN = (1 << 0), + + CMD0_CLEAR = 0x000F0F7F, /* Command style register */ + +}CMD0_BITS; + +typedef enum { + + /* VAL3 */ + CONDUIT_MODE = (1 << 29), + /* VAL2 */ + RPA = (1 << 19), + DRCVPA = (1 << 18), + DRCVBC = (1 << 17), + PROM = (1 << 16), + /* VAL1 */ + ASTRP_RCV = (1 << 13), + RCV_DROP0 = (1 << 12), + EMBA = (1 << 11), + DXMT2PD = (1 << 10), + LTINTEN = (1 << 9), + DXMTFCS = (1 << 8), + /* VAL0 */ + APAD_XMT = (1 << 6), + DRTY = (1 << 5), + INLOOP = (1 << 4), + EXLOOP = (1 << 3), + REX_RTRY = (1 << 2), + REX_UFLO = (1 << 1), + REX_LCOL = (1 << 0), + + CMD2_CLEAR = 0x3F7F3F7F, /* Command style register */ + +}CMD2_BITS; + +typedef enum { + + /* VAL3 */ + ASF_INIT_DONE_ALIAS = (1 << 29), + /* VAL2 */ + JUMBO = (1 << 21), + VSIZE = (1 << 20), + VLONLY = (1 << 19), + VL_TAG_DEL = (1 << 18), + /* VAL1 */ + EN_PMGR = (1 << 14), + INTLEVEL = (1 << 13), + FORCE_FULL_DUPLEX = (1 << 12), + FORCE_LINK_STATUS = (1 << 11), + APEP = (1 << 10), + MPPLBA = (1 << 9), + /* VAL0 */ + RESET_PHY_PULSE = (1 << 2), + RESET_PHY = (1 << 1), + PHY_RST_POL = (1 << 0), + +}CMD3_BITS; + + +typedef enum { + + /* VAL0 */ + PMAT_SAVE_MATCH = (1 << 4), + PMAT_MODE = (1 << 3), + MPEN_SW = (1 << 1), + LCMODE_SW = (1 << 0), + + CMD7_CLEAR = 0x0000001B /* Command style register */ + +}CMD7_BITS; + + +typedef enum { + + RESET_PHY_WIDTH = (0xF << 16) | (0xF<< 20), /* 0x00FF0000 */ + XMTSP_MASK = (1 << 9) | (1 << 8), /* 9:8 */ + XMTSP_128 = (1 << 9), /* 9 */ + XMTSP_64 = (1 << 8), + CACHE_ALIGN = (1 << 4), + BURST_LIMIT_MASK = (0xF << 0 ), + CTRL1_DEFAULT = 0x00010111, + +}CTRL1_BITS; + +typedef enum { + + FMDC_MASK = (1 << 9)|(1 << 8), /* 9:8 */ + XPHYRST = (1 << 7), + XPHYANE = (1 << 6), + XPHYFD = (1 << 5), + XPHYSP = (1 << 4) | (1 << 3), /* 4:3 */ + APDW_MASK = (1 << 2) | (1 << 1) | (1 << 0), /* 2:0 */ + +}CTRL2_BITS; /* XMT_RING_LIMIT 0x7C, 32bit register */ -#define XMT_RING2_LIMIT 0x00FF0000 /* 23:16 */ -#define XMT_RING1_LIMIT 0x0000FF00 /* 15:8 */ -#define XMT_RING0_LIMIT 0x000000FF /* 7:0 */ - -/* AUTOPOLL0 0x88, 16bit register */ -#define AP_REG0_EN B15_MASK -#define AP_REG0_ADDR_MASK 0x1F00 /* 12:8 */ -#define AP_PHY0_ADDR_MASK 0x001F /* 4:0 */ +typedef enum { + + XMT_RING2_LIMIT = (0xFF << 16), /* 23:16 */ + XMT_RING1_LIMIT = (0xFF << 8), /* 15:8 */ + XMT_RING0_LIMIT = (0xFF << 0), /* 7:0 */ + +}XMT_RING_LIMIT_BITS; + +typedef enum { + + AP_REG0_EN = (1 << 15), + AP_REG0_ADDR_MASK = (0xF << 8) |(1 << 12),/* 12:8 */ + AP_PHY0_ADDR_MASK = (0xF << 0) |(1 << 4),/* 4:0 */ + +}AUTOPOLL0_BITS; /* AUTOPOLL1 0x8A, 16bit register */ -#define AP_REG1_EN B15_MASK -#define AP_REG1_ADDR_MASK 0x1F00 /* 12:8 */ -#define AP_PRE_SUP1 B6_MASK -#define AP_PHY1_DFLT B5_MASK -#define AP_PHY1_ADDR_MASK 0x001F /* 4:0 */ - -/* AUTOPOLL2 0x8C, 16bit register */ -#define AP_REG2_EN B15_MASK -#define AP_REG2_ADDR_MASK 0x1F00 /* 12:8 */ -#define AP_PRE_SUP2 B6_MASK -#define AP_PHY2_DFLT B5_MASK -#define AP_PHY2_ADDR_MASK 0x001F /* 4:0 */ - -/* AUTOPOLL3 0x8E, 16bit register */ -#define AP_REG3_EN B15_MASK -#define AP_REG3_ADDR_MASK 0x1F00 /* 12:8 */ -#define AP_PRE_SUP3 B6_MASK -#define AP_PHY3_DFLT B5_MASK -#define AP_PHY3_ADDR_MASK 0x001F /* 4:0 */ - -/* AUTOPOLL4 0x90, 16bit register */ -#define AP_REG4_EN B15_MASK -#define AP_REG4_ADDR_MASK 0x1F00 /* 12:8 */ -#define AP_PRE_SUP4 B6_MASK -#define AP_PHY4_DFLT B5_MASK -#define AP_PHY4_ADDR_MASK 0x001F /* 4:0 */ - -/* AUTOPOLL5 0x92, 16bit register */ -#define AP_REG5_EN B15_MASK -#define AP_REG5_ADDR_MASK 0x1F00 /* 12:8 */ -#define AP_PRE_SUP5 B6_MASK -#define AP_PHY5_DFLT B5_MASK -#define AP_PHY5_ADDR_MASK 0x001F /* 4:0 */ +typedef enum { + + AP_REG1_EN = (1 << 15), + AP_REG1_ADDR_MASK = (0xF << 8) |(1 << 12),/* 12:8 */ + AP_PRE_SUP1 = (1 << 6), + AP_PHY1_DFLT = (1 << 5), + AP_PHY1_ADDR_MASK = (0xF << 0) |(1 << 4),/* 4:0 */ + +}AUTOPOLL1_BITS; + + +typedef enum { + + AP_REG2_EN = (1 << 15), + AP_REG2_ADDR_MASK = (0xF << 8) |(1 << 12),/* 12:8 */ + AP_PRE_SUP2 = (1 << 6), + AP_PHY2_DFLT = (1 << 5), + AP_PHY2_ADDR_MASK = (0xF << 0) |(1 << 4),/* 4:0 */ + +}AUTOPOLL2_BITS; + +typedef enum { + + AP_REG3_EN = (1 << 15), + AP_REG3_ADDR_MASK = (0xF << 8) |(1 << 12),/* 12:8 */ + AP_PRE_SUP3 = (1 << 6), + AP_PHY3_DFLT = (1 << 5), + AP_PHY3_ADDR_MASK = (0xF << 0) |(1 << 4),/* 4:0 */ + +}AUTOPOLL3_BITS; + + +typedef enum { + + AP_REG4_EN = (1 << 15), + AP_REG4_ADDR_MASK = (0xF << 8) |(1 << 12),/* 12:8 */ + AP_PRE_SUP4 = (1 << 6), + AP_PHY4_DFLT = (1 << 5), + AP_PHY4_ADDR_MASK = (0xF << 0) |(1 << 4),/* 4:0 */ + +}AUTOPOLL4_BITS; + + +typedef enum { + + AP_REG5_EN = (1 << 15), + AP_REG5_ADDR_MASK = (0xF << 8) |(1 << 12),/* 12:8 */ + AP_PRE_SUP5 = (1 << 6), + AP_PHY5_DFLT = (1 << 5), + AP_PHY5_ADDR_MASK = (0xF << 0) |(1 << 4),/* 4:0 */ + +}AUTOPOLL5_BITS; + + + /* AP_VALUE 0x98, 32bit ragister */ -#define AP_VAL_ACTIVE B31_MASK -#define AP_VAL_RD_CMD B29_MASK -#define AP_ADDR 0x00070000 /* 18:16 */ -#define AP_VAL 0x0000FFFF /* 15:0 */ - -/* PCS_ANEG 0x9C, 32bit register */ -#define SYNC_LOST B10_MASK -#define IMATCH B9_MASK -#define CMATCH B8_MASK -#define PCS_AN_IDLE B1_MASK -#define PCS_AN_CFG B0_MASK - -/* DLY_INT_A 0xA8, 32bit register */ -#define DLY_INT_A_R3 B31_MASK -#define DLY_INT_A_R2 B30_MASK -#define DLY_INT_A_R1 B29_MASK -#define DLY_INT_A_R0 B28_MASK -#define DLY_INT_A_T3 B27_MASK -#define DLY_INT_A_T2 B26_MASK -#define DLY_INT_A_T1 B25_MASK -#define DLY_INT_A_T0 B24_MASK -#define EVENT_COUNT_A 0x00FF0000 /* 20:16 */ -#define MAX_DELAY_TIME_A 0x000007FF /* 10:0 */ - -/* DLY_INT_B 0xAC, 32bit register */ -#define DLY_INT_B_R3 B31_MASK -#define DLY_INT_B_R2 B30_MASK -#define DLY_INT_B_R1 B29_MASK -#define DLY_INT_B_R0 B28_MASK -#define DLY_INT_B_T3 B27_MASK -#define DLY_INT_B_T2 B26_MASK -#define DLY_INT_B_T1 B25_MASK -#define DLY_INT_B_T0 B24_MASK -#define EVENT_COUNT_B 0x00FF0000 /* 20:16 */ -#define MAX_DELAY_TIME_B 0x000007FF /* 10:0 */ - -/* DFC_THRESH2 0xC0, 16bit register */ -#define DFC_THRESH2_HIGH 0xFF00 /* 15:8 */ -#define DFC_THRESH2_LOW 0x00FF /* 7:0 */ - -/* DFC_THRESH3 0xC2, 16bit register */ -#define DFC_THRESH3_HIGH 0xFF00 /* 15:8 */ -#define DFC_THRESH3_LOW 0x00FF /* 7:0 */ - -/* DFC_THRESH0 0xC4, 16bit register */ -#define DFC_THRESH0_HIGH 0xFF00 /* 15:8 */ -#define DFC_THRESH0_LOW 0x00FF /* 7:0 */ - -/* DFC_THRESH1 0xC6, 16bit register */ -#define DFC_THRESH1_HIGH 0xFF00 /* 15:8 */ -#define DFC_THRESH1_LOW 0x00FF /* 7:0 */ +typedef enum { + + AP_VAL_ACTIVE = (1 << 31), + AP_VAL_RD_CMD = ( 1 << 29), + AP_ADDR = (1 << 18)|(1 << 17)|(1 << 16), /* 18:16 */ + AP_VAL = (0xF << 0) | (0xF << 4) |( 0xF << 8) | + (0xF << 12), /* 15:0 */ + +}AP_VALUE_BITS; + +typedef enum { + + DLY_INT_A_R3 = (1 << 31), + DLY_INT_A_R2 = (1 << 30), + DLY_INT_A_R1 = (1 << 29), + DLY_INT_A_R0 = (1 << 28), + DLY_INT_A_T3 = (1 << 27), + DLY_INT_A_T2 = (1 << 26), + DLY_INT_A_T1 = (1 << 25), + DLY_INT_A_T0 = ( 1 << 24), + EVENT_COUNT_A = (0xF << 16) | (0x1 << 20),/* 20:16 */ + MAX_DELAY_TIME_A = (0xF << 0) | (0xF << 4) | (1 << 8)| + (1 << 9) | (1 << 10), /* 10:0 */ + +}DLY_INT_A_BITS; + +typedef enum { + + DLY_INT_B_R3 = (1 << 31), + DLY_INT_B_R2 = (1 << 30), + DLY_INT_B_R1 = (1 << 29), + DLY_INT_B_R0 = (1 << 28), + DLY_INT_B_T3 = (1 << 27), + DLY_INT_B_T2 = (1 << 26), + DLY_INT_B_T1 = (1 << 25), + DLY_INT_B_T0 = ( 1 << 24), + EVENT_COUNT_B = (0xF << 16) | (0x1 << 20),/* 20:16 */ + MAX_DELAY_TIME_B = (0xF << 0) | (0xF << 4) | (1 << 8)| + (1 << 9) | (1 << 10), /* 10:0 */ +}DLY_INT_B_BITS; + /* FLOW_CONTROL 0xC8, 32bit register */ -#define PAUSE_LEN_CHG B30_MASK -#define FFC_EN B28_MASK -#define DFC_RING3_EN B27_MASK -#define DFC_RING2_EN B26_MASK -#define DFC_RING1_EN B25_MASK -#define DFC_RING0_EN B24_MASK -#define FIXP_CONGEST B21_MASK -#define FPA B20_MASK -#define NPA B19_MASK -#define FIXP B18_MASK -#define FCPEN B17_MASK -#define FCCMD B16_MASK -#define PAUSE_LEN 0x0000FFFF /* 15:0 */ - -/* FFC THRESH 0xCC, 32bit register */ -#define FFC_HIGH 0xFFFF0000 /* 31:16 */ -#define FFC_LOW 0x0000FFFF /* 15:0 */ +typedef enum { + + PAUSE_LEN_CHG = (1 << 30), + FTPE = (1 << 22), + FRPE = (1 << 21), + NAPA = (1 << 20), + NPA = (1 << 19), + FIXP = ( 1 << 18), + FCCMD = ( 1 << 16), + PAUSE_LEN = (0xF << 0) | (0xF << 4) |( 0xF << 8) | (0xF << 12), /* 15:0 */ + +}FLOW_CONTROL_BITS; /* PHY_ ACCESS 0xD0, 32bit register */ -#define PHY_CMD_ACTIVE B31_MASK -#define PHY_WR_CMD B30_MASK -#define PHY_RD_CMD B29_MASK -#define PHY_RD_ERR B28_MASK -#define PHY_PRE_SUP B27_MASK -#define PHY_ADDR 0x03E00000 /* 25:21 */ -#define PHY_REG_ADDR 0x001F0000 /* 20:16 */ -#define PHY_DATA 0x0000FFFF /* 15:0 */ - -/* LED0..3 0xE0..0xE6, 16bit register */ -#define LEDOUT B15_MASK -#define LEDPOL B14_MASK -#define LEDDIS B13_MASK -#define LEDSTRETCH B12_MASK -#define LED1000 B8_MASK -#define LED100 B7_MASK -#define LEDMP B6_MASK -#define LEDFD B5_MASK -#define LEDLINK B4_MASK -#define LEDRCVMAT B3_MASK -#define LEDXMT B2_MASK -#define LEDRCV B1_MASK -#define LEDCOLOUT B0_MASK - -/* EEPROM_ACC 0x17C, 16bit register */ -#define PVALID B15_MASK -#define PREAD B14_MASK -#define EEDET B13_MASK -#define EEN B4_MASK -#define ECS B2_MASK -#define EESK B1_MASK -#define edi_edo b0_MASK +typedef enum { + + PHY_CMD_ACTIVE = (1 << 31), + PHY_WR_CMD = (1 << 30), + PHY_RD_CMD = (1 << 29), + PHY_RD_ERR = (1 << 28), + PHY_PRE_SUP = (1 << 27), + PHY_ADDR = (1 << 21) | (1 << 22) | (1 << 23)| + (1 << 24) |(1 << 25),/* 25:21 */ + PHY_REG_ADDR = (1 << 16) | (1 << 17) | (1 << 18)| (1 << 19) | (1 << 20),/* 20:16 */ + PHY_DATA = (0xF << 0)|(0xF << 4) |(0xF << 8)| + (0xF << 12),/* 15:0 */ + +}PHY_ACCESS_BITS; + /* PMAT0 0x190, 32bit register */ -#define PMR_ACTIVE B31_MASK -#define PMR_WR_CMD B30_MASK -#define PMR_RD_CMD B29_MASK -#define PMR_BANK B28_MASK -#define PMR_ADDR 0x007F0000 /* 22:16 */ -#define PMR_B4 0x000000FF /* 15:0 */ +typedef enum { + PMR_ACTIVE = (1 << 31), + PMR_WR_CMD = (1 << 30), + PMR_RD_CMD = (1 << 29), + PMR_BANK = (1 <<28), + PMR_ADDR = (0xF << 16)|(1 << 20)|(1 << 21)| + (1 << 22),/* 22:16 */ + PMR_B4 = (0xF << 0) | (0xF << 4),/* 15:0 */ +}PMAT0_BITS; + /* PMAT1 0x194, 32bit register */ -#define PMR_B3 0xFF000000 /* 31:24 */ -#define PMR_B2 0x00FF0000 /* 23:16 */ -#define PMR_B1 0x0000FF00 /* 15:8 */ -#define PMR_B0 0x000000FF /* 7:0 */ +typedef enum { + PMR_B3 = (0xF << 24) | (0xF <<28),/* 31:24 */ + PMR_B2 = (0xF << 16) |(0xF << 20),/* 23:16 */ + PMR_B1 = (0xF << 8) | (0xF <<12), /* 15:8 */ + PMR_B0 = (0xF << 0)|(0xF << 4),/* 7:0 */ +}PMAT1_BITS; /************************************************************************/ /* */ @@ -615,7 +566,7 @@ #define PCI_VENDOR_ID_AMD 0x1022 #define PCI_DEVICE_ID_AMD8111E_7462 0x7462 -#define MAX_UNITS 16 /* Maximum number of devices possible */ +#define MAX_UNITS 8 /* Maximum number of devices possible */ #define NUM_TX_BUFFERS 32 /* Number of transmit buffers */ #define NUM_RX_BUFFERS 32 /* Number of receive buffers */ @@ -637,45 +588,73 @@ #define MIN_PKT_LEN 60 #define ETH_ADDR_LEN 6 +#define AMD8111E_TX_TIMEOUT (3 * HZ)/* 3 sec */ +#define SOFT_TIMER_FREQ 0xBEBC /* 0.5 sec */ +#define DELAY_TIMER_CONV 50 /* msec to 10 usec conversion. + Only 500 usec resolution */ #define OPTION_VLAN_ENABLE 0x0001 #define OPTION_JUMBO_ENABLE 0x0002 #define OPTION_MULTICAST_ENABLE 0x0004 #define OPTION_WOL_ENABLE 0x0008 #define OPTION_WAKE_MAGIC_ENABLE 0x0010 #define OPTION_WAKE_PHY_ENABLE 0x0020 +#define OPTION_INTR_COAL_ENABLE 0x0040 +#define OPTION_DYN_IPG_ENABLE 0x0080 #define PHY_REG_ADDR_MASK 0x1f +/* ipg parameters */ +#define DEFAULT_IPG 0x60 +#define IFS1_DELTA 36 +#define IPG_CONVERGE_TIME 0.5 +#define IPG_STABLE_TIME 5 +#define MIN_IPG 96 +#define MAX_IPG 255 +#define IPG_STEP 16 +#define CSTATE 1 +#define SSTATE 2 + /* Assume contoller gets data 10 times the maximum processing time */ #define REPEAT_CNT 10; /* amd8111e decriptor flag definitions */ +typedef enum { -#define OWN_BIT B15_MASK -#define ADD_FCS_BIT B13_MASK -#define LTINT_BIT B12_MASK -#define STP_BIT B9_MASK -#define ENP_BIT B8_MASK -#define KILL_BIT B6_MASK -#define TCC_MASK 0x0003 -#define TCC_VLAN_INSERT B1_MASK -#define TCC_VLAN_REPLACE 0x0003 -#define RESET_RX_FLAGS 0x0000 + OWN_BIT = (1 << 15), + ADD_FCS_BIT = (1 << 13), + LTINT_BIT = (1 << 12), + STP_BIT = (1 << 9), + ENP_BIT = (1 << 8), + KILL_BIT = (1 << 6), + TCC_VLAN_INSERT = (1 << 1), + TCC_VLAN_REPLACE = (1 << 1) |( 1<< 0), + +}TX_FLAG_BITS; + +typedef enum { + ERR_BIT = (1 << 14), + FRAM_BIT = (1 << 13), + OFLO_BIT = (1 << 12), + CRC_BIT = (1 << 11), + PAM_BIT = (1 << 6), + LAFM_BIT = (1 << 5), + BAM_BIT = (1 << 4), + TT_VLAN_TAGGED = (1 << 3) |(1 << 2),/* 0x000 */ + TT_PRTY_TAGGED = (1 << 3),/* 0x0008 */ + +}RX_FLAG_BITS; -#define ERR_BIT B14_MASK -#define FRAM_BIT B13_MASK -#define OFLO_BIT B12_MASK -#define CRC_BIT B11_MASK -#define PAM_BIT B6_MASK -#define LAFM_BIT B5_MASK -#define BAM_BIT B4_MASK +#define RESET_RX_FLAGS 0x0000 #define TT_MASK 0x000c -#define TT_VLAN_TAGGED 0x000c -#define TT_PRTY_TAGGED 0x0008 +#define TCC_MASK 0x0003 /* driver ioctl parameters */ #define PHY_ID 0x01 /* currently it is fixed */ -#define AMD8111E_REG_DUMP_LEN 4096 /* Memory mapped register length */ +#define AMD8111E_REG_DUMP_LEN 13*sizeof(u32) + +/* crc generator constants */ +#define CRC32 0xedb88320 +#define INITCRC 0xFFFFFFFF /* amd8111e desriptor format */ @@ -683,7 +662,7 @@ u16 buff_count; /* Size of the buffer pointed by this descriptor */ - u16 tx_dr_offset2; + u16 tx_flags; u16 tag_ctrl_info; @@ -704,7 +683,7 @@ u16 buff_count; /* Len of the buffer pointed by descriptor. */ - u16 rx_dr_offset10; + u16 rx_flags; u32 buff_phy_addr; @@ -719,10 +698,58 @@ u16 speed; u8 duplex; u8 autoneg; - u16 orig_speed; - u8 orig_duplex; u8 reserved; /* 32bit alignment */ }; + +enum coal_type{ + + NO_COALESCE, + LOW_COALESCE, + MEDIUM_COALESCE, + HIGH_COALESCE, + +}; + +enum coal_mode{ + RX_INTR_COAL, + TX_INTR_COAL, + DISABLE_COAL, + ENABLE_COAL, + +}; +#define MAX_TIMEOUT 40 +#define MAX_EVENT_COUNT 31 +struct amd8111e_coalesce_conf{ + + unsigned int rx_timeout; + unsigned int rx_event_count; + unsigned long rx_packets; + unsigned long rx_prev_packets; + unsigned long rx_bytes; + unsigned long rx_prev_bytes; + unsigned int rx_coal_type; + + unsigned int tx_timeout; + unsigned int tx_event_count; + unsigned long tx_packets; + unsigned long tx_prev_packets; + unsigned long tx_bytes; + unsigned long tx_prev_bytes; + unsigned int tx_coal_type; + +}; +struct ipg_info{ + + unsigned int ipg_state; + unsigned int ipg; + unsigned int current_ipg; + unsigned int col_cnt; + unsigned int diff_col_cnt; + unsigned int timer_tick; + unsigned int prev_ipg; + struct timer_list ipg_timer; +}; + struct amd8111e_priv{ struct amd8111e_tx_dr* tx_ring; @@ -742,45 +769,54 @@ void * mmio; spinlock_t lock; /* Guard lock */ - unsigned long rx_idx, tx_idx; /* The next free ring entry */ - unsigned long tx_complete_idx; + unsigned long rx_idx, tx_idx; /* The next free ring entry */ + unsigned long tx_complete_idx; unsigned long tx_ring_complete_idx; unsigned long tx_ring_idx; - int rx_buff_len; /* Buffer length of rx buffers */ + unsigned int rx_buff_len; /* Buffer length of rx buffers */ int options; /* Options enabled/disabled for the device */ + unsigned long ext_phy_option; + struct amd8111e_link_config link_config; int pm_cap; + u32 pm_state[12]; struct net_device *next; + int mii; + struct mii_if_info mii_if; #if AMD8111E_VLAN_TAG_USED struct vlan_group *vlgrp; #endif char opened; struct net_device_stats stats; - struct net_device_stats prev_stats; struct dev_mc_list* mc_list; + struct amd8111e_coalesce_conf coal_conf; + + struct ipg_info ipg_data; }; -#define AMD8111E_READ_REG64(_memMapBase, _offset, _pUlData) \ - *(u32*)(_pUlData) = readl(_memMapBase + (_offset)); \ - *((u32*)(_pUlData))+1) = readl(_memMapBase + ((_offset)+4)) - -#define AMD8111E_WRITE_REG64(_memMapBase, _offset, _pUlData) \ - writel(*(u32*)(_pUlData), _memMapBase + (_offset)); \ - writel(*(u32*)((u8*)(_pUlData)+4), _memMapBase + ((_offset)+4)) \ + +/* kernel provided writeq does not write 64 bits into the amd8111e device register instead writes only higher 32bits data into lower 32bits of the register. +BUG? */ +#define amd8111e_writeq(_UlData,_memMap) \ + writel(*(u32*)(&_UlData), _memMap); \ + writel(*(u32*)((u8*)(&_UlData)+4), _memMap+4) /* maps the external speed options to internal value */ -static unsigned char speed_duplex_mapping[] = { +typedef enum { + SPEED_AUTONEG, + SPEED10_HALF, + SPEED10_FULL, + SPEED100_HALF, + SPEED100_FULL, +}EXT_PHY_OPTION; - XPHYANE, /* Auto-negotiation, speed_duplex option 0 */ - 0, /* 10M Half, speed_duplex option 1 */ - XPHYFD, /* 10M Full, speed_duplex option 2 */ - XPHYSP, /* 100M Half, speed_duplex option 3 */ - XPHYFD | XPHYSP /* 100M Full, speed_duplex option 4 */ -}; static int card_idx; static int speed_duplex[MAX_UNITS] = { 0, }; +static int coalesce[MAX_UNITS] = {1,1,1,1,1,1,1,1}; +static int dynamic_ipg[MAX_UNITS] = {0,0,0,0,0,0,0,0}; +static unsigned int chip_version; #endif /* _AMD8111E_H */ diff -Nru a/drivers/net/arcnet/arc-rawmode.c b/drivers/net/arcnet/arc-rawmode.c --- a/drivers/net/arcnet/arc-rawmode.c Mon Jun 9 23:16:19 2003 +++ b/drivers/net/arcnet/arc-rawmode.c Mon Jun 9 23:16:19 2003 @@ -45,11 +45,11 @@ struct ArcProto rawmode_proto = { - 'r', - XMTU, - rx, - build_header, - prepare_tx + .suffix = 'r', + .mtu = XMTU, + .rx = rx, + .build_header = build_header, + .prepare_tx = prepare_tx, }; diff -Nru a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c --- a/drivers/net/arcnet/arcnet.c Mon Jun 9 23:16:15 2003 +++ b/drivers/net/arcnet/arcnet.c Mon Jun 9 23:16:15 2003 @@ -73,11 +73,11 @@ struct ArcProto arc_proto_null = { - '?', - XMTU, - null_rx, - null_build_header, - null_prepare_tx + .suffix = '?', + .mtu = XMTU, + .rx = null_rx, + .build_header = null_build_header, + .prepare_tx = null_prepare_tx, }; static spinlock_t arcnet_lock = SPIN_LOCK_UNLOCKED; diff -Nru a/drivers/net/arcnet/rfc1051.c b/drivers/net/arcnet/rfc1051.c --- a/drivers/net/arcnet/rfc1051.c Mon Jun 9 23:16:15 2003 +++ b/drivers/net/arcnet/rfc1051.c Mon Jun 9 23:16:15 2003 @@ -45,11 +45,11 @@ struct ArcProto rfc1051_proto = { - 's', - XMTU - RFC1051_HDR_SIZE, - rx, - build_header, - prepare_tx + .suffix = 's', + .mtu = XMTU - RFC1051_HDR_SIZE, + .rx = rx, + .build_header = build_header, + .prepare_tx = prepare_tx, }; diff -Nru a/drivers/net/arcnet/rfc1201.c b/drivers/net/arcnet/rfc1201.c --- a/drivers/net/arcnet/rfc1201.c Mon Jun 9 23:16:11 2003 +++ b/drivers/net/arcnet/rfc1201.c Mon Jun 9 23:16:11 2003 @@ -44,12 +44,12 @@ struct ArcProto rfc1201_proto = { - 'a', - 1500, /* could be more, but some receivers can't handle it... */ - rx, - build_header, - prepare_tx, - continue_tx + .suffix = 'a', + .mtu = 1500, /* could be more, but some receivers can't handle it... */ + .rx = rx, + .build_header = build_header, + .prepare_tx = prepare_tx, + .continue_tx = continue_tx, }; diff -Nru a/drivers/net/bmac.c b/drivers/net/bmac.c --- a/drivers/net/bmac.c Mon Jun 9 23:16:05 2003 +++ b/drivers/net/bmac.c Mon Jun 9 23:16:05 2003 @@ -1331,12 +1331,13 @@ } } - dev = init_etherdev(NULL, PRIV_BYTES); + dev = alloc_etherdev(PRIV_BYTES); if (!dev) { - printk(KERN_ERR "init_etherdev failed, out of memory for BMAC %s\n", + printk(KERN_ERR "alloc_etherdev failed, out of memory for BMAC %s\n", bmac->full_name); return; } + bp = (struct bmac_data *) dev->priv; SET_MODULE_OWNER(dev); bp->node = bmac; @@ -1344,21 +1345,22 @@ if (!request_OF_resource(bmac, 0, " (bmac)")) { printk(KERN_ERR "BMAC: can't request IO resource !\n"); - goto err_out; + goto out1; } if (!request_OF_resource(bmac, 1, " (bmac tx dma)")) { printk(KERN_ERR "BMAC: can't request TX DMA resource !\n"); - goto err_out; + goto out2; } - if (!request_OF_resource(bmac, 2, " (bmac rx dma)")) { printk(KERN_ERR "BMAC: can't request RX DMA resource !\n"); - goto err_out; + goto out3; } + dev->base_addr = (unsigned long) ioremap(bmac->addrs[0].address, bmac->addrs[0].size); if (!dev->base_addr) - goto err_out; + goto out4; + dev->irq = bmac->intrs[0].line; bmac_enable_and_reset_chip(dev); @@ -1429,11 +1431,19 @@ */ disable_irq(dev->irq); pmac_call_feature(PMAC_FTR_BMAC_ENABLE, bp->node, 0, 0); + + if (register_netdev(dev) != 0) { + printk(KERN_ERR "registration failed for BMAC %s\n", + bmac->full_name); + goto err_out_irq2; + } bp->next_bmac = bmac_devs; bmac_devs = dev; return; +err_out_irq2: + free_irq(bmac->intrs[2].line, dev); err_out_irq1: free_irq(bmac->intrs[1].line, dev); err_out_irq0: @@ -1444,14 +1454,14 @@ iounmap((void *)bp->tx_dma); err_out_iounmap: iounmap((void *)dev->base_addr); -err_out: - if (bp->node) { - release_OF_resource(bp->node, 0); - release_OF_resource(bp->node, 1); - release_OF_resource(bp->node, 2); - pmac_call_feature(PMAC_FTR_BMAC_ENABLE, bp->node, 0, 0); - } - unregister_netdev(dev); +out4: + release_OF_resource(bp->node, 2); +out3: + release_OF_resource(bp->node, 1); +out2: + release_OF_resource(bp->node, 0); +out1: + pmac_call_feature(PMAC_FTR_BMAC_ENABLE, bp->node, 0, 0); kfree(dev); } diff -Nru a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c --- a/drivers/net/bonding/bond_3ad.c Mon Jun 9 23:16:16 2003 +++ b/drivers/net/bonding/bond_3ad.c Mon Jun 9 23:16:16 2003 @@ -721,7 +721,7 @@ } /** - * __detach_bond_to_agg + * __detach_bond_from_agg * @port: the port we're looking at * * Handle the detaching of the port's control parser/multiplexer from the @@ -828,6 +828,55 @@ return retval; } +/** + * __update_lacpdu_from_port - update a port's lacpdu fields + * @port: the port we're looking at + * + */ +static inline void __update_lacpdu_from_port(struct port *port) +{ + struct lacpdu *lacpdu = &port->lacpdu; + + /* update current actual Actor parameters */ + /* lacpdu->subtype initialized + * lacpdu->version_number initialized + * lacpdu->tlv_type_actor_info initialized + * lacpdu->actor_information_length initialized + */ + + lacpdu->actor_system_priority = port->actor_system_priority; + lacpdu->actor_system = port->actor_system; + lacpdu->actor_key = port->actor_oper_port_key; + lacpdu->actor_port_priority = port->actor_port_priority; + lacpdu->actor_port = port->actor_port_number; + lacpdu->actor_state = port->actor_oper_port_state; + + /* lacpdu->reserved_3_1 initialized + * lacpdu->tlv_type_partner_info initialized + * lacpdu->partner_information_length initialized + */ + + lacpdu->partner_system_priority = port->partner_oper_system_priority; + lacpdu->partner_system = port->partner_oper_system; + lacpdu->partner_key = port->partner_oper_key; + lacpdu->partner_port_priority = port->partner_oper_port_priority; + lacpdu->partner_port = port->partner_oper_port_number; + lacpdu->partner_state = port->partner_oper_port_state; + + /* lacpdu->reserved_3_2 initialized + * lacpdu->tlv_type_collector_info initialized + * lacpdu->collector_information_length initialized + * collector_max_delay initialized + * reserved_12[12] initialized + * tlv_type_terminator initialized + * terminator_length initialized + * reserved_50[50] initialized + */ + + /* Convert all non u8 parameters to Big Endian for transmit */ + __ntohs_lacpdu(lacpdu); +} + ////////////////////////////////////////////////////////////////////////////////////// // ================= main 802.3ad protocol code ====================================== ////////////////////////////////////////////////////////////////////////////////////// @@ -1177,43 +1226,11 @@ */ static void ad_tx_machine(struct port *port) { - struct lacpdu *lacpdu = &port->lacpdu; - // check if tx timer expired, to verify that we do not send more than 3 packets per second if (port->sm_tx_timer_counter && !(--port->sm_tx_timer_counter)) { // check if there is something to send if (port->ntt && (port->sm_vars & AD_PORT_LACP_ENABLED)) { - //update current actual Actor parameters - //lacpdu->subtype initialized - //lacpdu->version_number initialized - //lacpdu->tlv_type_actor_info initialized - //lacpdu->actor_information_length initialized - lacpdu->actor_system_priority = port->actor_system_priority; - lacpdu->actor_system = port->actor_system; - lacpdu->actor_key = port->actor_oper_port_key; - lacpdu->actor_port_priority = port->actor_port_priority; - lacpdu->actor_port = port->actor_port_number; - lacpdu->actor_state = port->actor_oper_port_state; - //lacpdu->reserved_3_1 initialized - //lacpdu->tlv_type_partner_info initialized - //lacpdu->partner_information_length initialized - lacpdu->partner_system_priority = port->partner_oper_system_priority; - lacpdu->partner_system = port->partner_oper_system; - lacpdu->partner_key = port->partner_oper_key; - lacpdu->partner_port_priority = port->partner_oper_port_priority; - lacpdu->partner_port = port->partner_oper_port_number; - lacpdu->partner_state = port->partner_oper_port_state; - //lacpdu->reserved_3_2 initialized - //lacpdu->tlv_type_collector_info initialized - //lacpdu->collector_information_length initialized - //collector_max_delay initialized - //reserved_12[12] initialized - //tlv_type_terminator initialized - //terminator_length initialized - //reserved_50[50] initialized - - // We need to convert all non u8 parameters to Big Endian for transmit - __ntohs_lacpdu(lacpdu); + __update_lacpdu_from_port(port); // send the lacpdu if (ad_lacpdu_send(port) >= 0) { BOND_PRINT_DBG(("Sent LACPDU on port %d", port->actor_port_number)); @@ -1971,13 +1988,13 @@ return; } - // disable the port - ad_disable_collecting_distributing(port); + BOND_PRINT_DBG(("Unbinding Link Aggregation Group %d", aggregator->aggregator_identifier)); - // deinitialize port's locks if necessary(os-specific) - __deinitialize_port_locks(port); + /* Tell the partner that this port is not suitable for aggregation */ + port->actor_oper_port_state &= ~AD_STATE_AGGREGATION; + __update_lacpdu_from_port(port); + ad_lacpdu_send(port); - BOND_PRINT_DBG(("Unbinding Link Aggregation Group %d", aggregator->aggregator_identifier)); // check if this aggregator is occupied if (aggregator->lag_ports) { // check if there are other ports related to this aggregator except diff -Nru a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c --- a/drivers/net/bonding/bond_main.c Mon Jun 9 23:16:18 2003 +++ b/drivers/net/bonding/bond_main.c Mon Jun 9 23:16:18 2003 @@ -2220,7 +2220,7 @@ } printk(KERN_INFO "%s: link status definitely down " - "for interface %s, disabling it\n", + "for interface %s, disabling it", master->name, dev->name); @@ -2994,6 +2994,7 @@ struct ifbond *u_binfo = NULL, k_binfo; struct ifslave *u_sinfo = NULL, k_sinfo; struct mii_ioctl_data *mii = NULL; + int prev_abi_ver = orig_app_abi_ver; int ret = 0; #ifdef BONDING_DEBUG @@ -3112,6 +3113,15 @@ } dev_put(slave_dev); } + + if (ret < 0) { + /* The ioctl failed, so there's no point in changing the + * orig_app_abi_ver. We'll restore it's value just in case + * we've changed it earlier in this function. + */ + orig_app_abi_ver = prev_abi_ver; + } + return ret; } diff -Nru a/drivers/net/defxx.c b/drivers/net/defxx.c --- a/drivers/net/defxx.c Mon Jun 9 23:16:05 2003 +++ b/drivers/net/defxx.c Mon Jun 9 23:16:05 2003 @@ -425,11 +425,7 @@ } #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)); + dev = alloc_fddidev(sizeof(*bp)); if (!dev) { printk (KERN_ERR "defxx: unable to allocate fddidev, aborting\n"); return -ENOMEM; @@ -483,12 +479,17 @@ goto err_out_region; } + err = register_netdev(dev); + if (err) + goto err_out_kfree; + return 0; +err_out_kfree: + if (bp->kmalloced) kfree(bp->kmalloced); err_out_region: release_region(ioaddr, pdev ? PFI_K_CSR_IO_LEN : PI_ESIC_K_CSR_IO_LEN); err_out: - unregister_netdev(dev); kfree(dev); return err; } diff -Nru a/drivers/net/dl2k.h b/drivers/net/dl2k.h --- a/drivers/net/dl2k.h Mon Jun 9 23:16:18 2003 +++ b/drivers/net/dl2k.h Mon Jun 9 23:16:18 2003 @@ -243,7 +243,6 @@ VLANTagInsert = 0x0000000010000000, TFDDone = 0x80000000, VIDShift = 32, - CFI = 0x0000100000000000, UsePriorityShift = 48, }; diff -Nru a/drivers/net/e100/e100_main.c b/drivers/net/e100/e100_main.c --- a/drivers/net/e100/e100_main.c Mon Jun 9 23:16:11 2003 +++ b/drivers/net/e100/e100_main.c Mon Jun 9 23:16:11 2003 @@ -614,10 +614,6 @@ goto err_dealloc; } - if ((rc = register_netdev(dev)) != 0) { - goto err_pci; - } - if (((bdp->pdev->device > 0x1030) && (bdp->pdev->device < 0x103F)) || ((bdp->pdev->device >= 0x1050) @@ -641,6 +637,28 @@ } else { bdp->rfd_size = 16; } + + dev->vlan_rx_register = e100_vlan_rx_register; + dev->vlan_rx_add_vid = e100_vlan_rx_add_vid; + dev->vlan_rx_kill_vid = e100_vlan_rx_kill_vid; + dev->irq = pcid->irq; + dev->open = &e100_open; + dev->hard_start_xmit = &e100_xmit_frame; + dev->stop = &e100_close; + dev->change_mtu = &e100_change_mtu; + dev->get_stats = &e100_get_stats; + dev->set_multicast_list = &e100_set_multi; + dev->set_mac_address = &e100_set_mac; + dev->do_ioctl = &e100_ioctl; + + if (bdp->flags & USE_IPCB) + dev->features = NETIF_F_SG | NETIF_F_HW_CSUM | + NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; + + if ((rc = register_netdev(dev)) != 0) { + goto err_pci; + } + e100_check_options(e100nics, bdp); if (!e100_init(bdp)) { @@ -660,23 +678,6 @@ goto err_unregister_netdev; } - dev->vlan_rx_register = e100_vlan_rx_register; - dev->vlan_rx_add_vid = e100_vlan_rx_add_vid; - dev->vlan_rx_kill_vid = e100_vlan_rx_kill_vid; - dev->irq = pcid->irq; - dev->open = &e100_open; - dev->hard_start_xmit = &e100_xmit_frame; - dev->stop = &e100_close; - dev->change_mtu = &e100_change_mtu; - dev->get_stats = &e100_get_stats; - dev->set_multicast_list = &e100_set_multi; - dev->set_mac_address = &e100_set_mac; - dev->do_ioctl = &e100_ioctl; - - if (bdp->flags & USE_IPCB) - dev->features = NETIF_F_SG | NETIF_F_HW_CSUM | - NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - e100nics++; e100_get_speed_duplex_caps(bdp); @@ -4271,13 +4272,13 @@ static int e100_notify_reboot(struct notifier_block *nb, unsigned long event, void *p) { - struct pci_dev *pdev; + struct pci_dev *pdev = NULL; switch(event) { case SYS_DOWN: case SYS_HALT: case SYS_POWER_OFF: - pci_for_each_dev(pdev) { + while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { if(pci_dev_driver(pdev) == &e100_driver) { /* If net_device struct is allocated? */ if (pci_get_drvdata(pdev)) diff -Nru a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c --- a/drivers/net/e1000/e1000_main.c Mon Jun 9 23:16:10 2003 +++ b/drivers/net/e1000/e1000_main.c Mon Jun 9 23:16:10 2003 @@ -2649,7 +2649,7 @@ case SYS_DOWN: case SYS_HALT: case SYS_POWER_OFF: - pci_for_each_dev(pdev) { + while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { if(pci_dev_driver(pdev) == &e1000_driver) e1000_suspend(pdev, 3); } diff -Nru a/drivers/net/eepro.c b/drivers/net/eepro.c --- a/drivers/net/eepro.c Mon Jun 9 23:16:16 2003 +++ b/drivers/net/eepro.c Mon Jun 9 23:16:16 2003 @@ -1715,7 +1715,7 @@ static int n_eepro; /* For linux 2.1.xx */ -MODULE_AUTHOR("Pascal Dupuis <dupuis@lei.ucl.ac.be> for the 2.1 stuff (locking,...)"); +MODULE_AUTHOR("Pascal Dupuis, and aris@cathedrallabs.org"); MODULE_DESCRIPTION("Intel i82595 ISA EtherExpressPro10/10+ driver"); MODULE_LICENSE("GPL"); diff -Nru a/drivers/net/ethertap.c b/drivers/net/ethertap.c --- a/drivers/net/ethertap.c Mon Jun 9 23:16:08 2003 +++ b/drivers/net/ethertap.c Mon Jun 9 23:16:08 2003 @@ -292,19 +292,19 @@ static void ethertap_rx(struct sock *sk, int len) { - struct net_device *dev = tap_map[sk->protocol]; + struct net_device *dev = tap_map[sk->sk_protocol]; struct sk_buff *skb; if (dev==NULL) { printk(KERN_CRIT "ethertap: bad unit!\n"); - skb_queue_purge(&sk->receive_queue); + skb_queue_purge(&sk->sk_receive_queue); return; } if (ethertap_debug > 3) printk("%s: ethertap_rx()\n", dev->name); - while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) + while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) ethertap_rx_skb(skb, dev); } @@ -320,7 +320,7 @@ if (sk) { lp->nl = NULL; - sock_release(sk->socket); + sock_release(sk->sk_socket); } return 0; diff -Nru a/drivers/net/fc/iph5526.c b/drivers/net/fc/iph5526.c --- a/drivers/net/fc/iph5526.c Mon Jun 9 23:16:08 2003 +++ b/drivers/net/fc/iph5526.c Mon Jun 9 23:16:08 2003 @@ -234,7 +234,7 @@ { if (pci_present() && (iph5526_probe_pci(dev) == 0)) return 0; - return -ENODEV; + return -ENODEV; } static int __init iph5526_probe_pci(struct net_device *dev) @@ -242,37 +242,30 @@ #ifdef MODULE struct fc_info *fi = (struct fc_info *)dev->priv; #else - struct fc_info *fi; + struct fc_info *fi = fc[count]; static int count; + int err; - if(fc[count] != NULL) { - if (dev == NULL) { - dev = init_fcdev(NULL, 0); - if (dev == NULL) - return -ENOMEM; - } - fi = fc[count]; -#endif - fi->dev = dev; - dev->base_addr = fi->base_addr; - dev->irq = fi->irq; - if (dev->priv == NULL) - dev->priv = fi; - fcdev_init(dev); - /* Assign ur MAC address. - */ - dev->dev_addr[0] = (fi->g.my_port_name_high & 0x0000FF00) >> 8; - dev->dev_addr[1] = fi->g.my_port_name_high; - dev->dev_addr[2] = (fi->g.my_port_name_low & 0xFF000000) >> 24; - dev->dev_addr[3] = (fi->g.my_port_name_low & 0x00FF0000) >> 16; - dev->dev_addr[4] = (fi->g.my_port_name_low & 0x0000FF00) >> 8; - dev->dev_addr[5] = fi->g.my_port_name_low; -#ifndef MODULE - count++; - } - else + if (!fi) return -ENODEV; + + fc_setup(dev); + count++; #endif + fi->dev = dev; + dev->base_addr = fi->base_addr; + dev->irq = fi->irq; + if (dev->priv == NULL) + dev->priv = fi; + fcdev_init(dev); + /* Assign ur MAC address. + */ + dev->dev_addr[0] = (fi->g.my_port_name_high & 0x0000FF00) >> 8; + dev->dev_addr[1] = fi->g.my_port_name_high; + dev->dev_addr[2] = (fi->g.my_port_name_low & 0xFF000000) >> 24; + dev->dev_addr[3] = (fi->g.my_port_name_low & 0x00FF0000) >> 16; + dev->dev_addr[4] = (fi->g.my_port_name_low & 0x0000FF00) >> 8; + dev->dev_addr[5] = fi->g.my_port_name_low; display_cache(fi); return 0; } @@ -287,9 +280,6 @@ dev->change_mtu = iph5526_change_mtu; dev->tx_timeout = iph5526_timeout; dev->watchdog_timeo = 5*HZ; -#ifndef MODULE - fc_setup(dev); -#endif return 0; } @@ -4507,7 +4497,7 @@ int init_module(void) { -int i = 0; + int i = 0; driver_template.module = THIS_MODULE; scsi_register_host(&driver_template); @@ -4520,43 +4510,39 @@ } while(fc[i] != NULL) { - dev_fc[i] = NULL; - dev_fc[i] = init_fcdev(dev_fc[i], 0); - if (dev_fc[i] == NULL) { + struct net_device *dev = alloc_fcdev(0); + int err; + + if (!dev) { printk("iph5526.c: init_fcdev failed for card #%d\n", i+1); break; } - dev_fc[i]->irq = irq; - dev_fc[i]->mem_end = bad; - dev_fc[i]->base_addr = io; - dev_fc[i]->init = iph5526_probe; - dev_fc[i]->priv = fc[i]; - fc[i]->dev = dev_fc[i]; - if (register_fcdev(dev_fc[i]) != 0) { - kfree(dev_fc[i]); - dev_fc[i] = NULL; - if (i == 0) { - printk("iph5526.c: IP registeration failed!!!\n"); - return -ENODEV; - } + dev->priv = fc[i]; + iph5526_probe_pci(dev); + err = register_netdev(dev); + if (err < 0) { + kfree(dev); + printk("iph5526.c: init_fcdev failed for card #%d\n", i+1); + break; } + dev_fc[i] = dev; i++; } if (i == 0) return -ENODEV; - + return 0; } void cleanup_module(void) { -int i = 0; + int i = 0; while(fc[i] != NULL) { - struct net_device *dev = fc[i]->dev; - void *priv = dev->priv; + struct net_device *dev = fc[i]->dev; + void *priv = dev->priv; fc[i]->g.dont_init = TRUE; take_tachyon_offline(fc[i]); - unregister_fcdev(dev); + unregister_netdev(dev); clean_up_memory(fc[i]); if (dev->priv) kfree(priv); diff -Nru a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c --- a/drivers/net/hamradio/dmascc.c Mon Jun 9 23:16:10 2003 +++ b/drivers/net/hamradio/dmascc.c Mon Jun 9 23:16:10 2003 @@ -250,8 +250,6 @@ /* Function declarations */ - -int dmascc_init(void) __init; static int setup_adapter(int card_base, int type, int n) __init; static void write_scc(struct scc_priv *priv, int reg, int val); @@ -299,23 +297,12 @@ static unsigned long rand; -/* Module functions */ - -#ifdef MODULE - - MODULE_AUTHOR("Klaus Kudielka"); MODULE_DESCRIPTION("Driver for high-speed SCC boards"); MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NUM_DEVS) "i"); MODULE_LICENSE("GPL"); - -int init_module(void) { - return dmascc_init(); -} - - -void cleanup_module(void) { +static void __exit dmascc_exit(void) { int i; struct scc_info *info; @@ -324,11 +311,8 @@ /* Unregister devices */ for (i = 0; i < 2; i++) { - if (info->dev[i].name) { - rtnl_lock(); - unregister_netdevice(&info->dev[i]); - rtnl_unlock(); - } + if (info->dev[i].name) + unregister_netdev(&info->dev[i]); } /* Reset board */ @@ -344,24 +328,16 @@ } } - -#else - - +#ifndef MODULE void __init dmascc_setup(char *str, int *ints) { int i; for (i = 0; i < MAX_NUM_DEVS && i < ints[0]; i++) io[i] = ints[i+1]; } - - #endif - -/* Initialization functions */ - -int __init dmascc_init(void) { +static int __init dmascc_init(void) { int h, i, j, n; int base[MAX_NUM_DEVS], tcmd[MAX_NUM_DEVS], t0[MAX_NUM_DEVS], t1[MAX_NUM_DEVS]; @@ -464,6 +440,9 @@ return -EIO; } +module_init(dmascc_init); +module_exit(dmascc_exit); + int __init setup_adapter(int card_base, int type, int n) { int i, irq, chip; @@ -583,6 +562,7 @@ if (sizeof(dev->name) == sizeof(char *)) dev->name = priv->name; #endif sprintf(dev->name, "dmascc%i", 2*n+i); + SET_MODULE_OWNER(dev); dev->base_addr = card_base; dev->irq = irq; dev->open = scc_open; @@ -710,12 +690,9 @@ struct scc_info *info = priv->info; int card_base = priv->card_base; - MOD_INC_USE_COUNT; - /* Request IRQ if not already used by other channel */ if (!info->irq_used) { if (request_irq(dev->irq, scc_isr, 0, "dmascc", info)) { - MOD_DEC_USE_COUNT; return -EAGAIN; } } @@ -725,7 +702,6 @@ if (priv->param.dma >= 0) { if (request_dma(priv->param.dma, "dmascc")) { if (--info->irq_used == 0) free_irq(dev->irq, info); - MOD_DEC_USE_COUNT; return -EAGAIN; } else { unsigned long flags = claim_dma_lock(); @@ -869,7 +845,6 @@ } if (--info->irq_used == 0) free_irq(dev->irq, info); - MOD_DEC_USE_COUNT; return 0; } diff -Nru a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c --- a/drivers/net/hamradio/mkiss.c Mon Jun 9 23:16:19 2003 +++ b/drivers/net/hamradio/mkiss.c Mon Jun 9 23:16:19 2003 @@ -329,6 +329,12 @@ return; } ax->rcount -= 2; + /* dl9sau bugfix: the trailling two bytes flexnet crc + * will not be passed to the kernel. thus we have + * to correct the kissparm signature, because it + * indicates a crc but there's none + */ + *ax->rbuff &= ~0x20; } } diff -Nru a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c --- a/drivers/net/irda/ali-ircc.c Mon Jun 9 23:16:10 2003 +++ b/drivers/net/irda/ali-ircc.c Mon Jun 9 23:16:10 2003 @@ -390,11 +390,8 @@ iobase = self->io.fir_base; /* Remove netdevice */ - if (self->netdev) { - rtnl_lock(); - unregister_netdevice(self->netdev); - rtnl_unlock(); - } + if (self->netdev) + unregister_netdev(self->netdev); /* Release the PORT that this driver is using */ IRDA_DEBUG(4, "%s(), Releasing Region %03x\n", __FUNCTION__, self->io.fir_base); diff -Nru a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c --- a/drivers/net/irda/donauboe.c Mon Jun 9 23:16:10 2003 +++ b/drivers/net/irda/donauboe.c Mon Jun 9 23:16:10 2003 @@ -1579,12 +1579,7 @@ } if (self->netdev) - { - /* Remove netdevice */ - rtnl_lock (); - unregister_netdevice (self->netdev); - rtnl_unlock (); - } + unregister_netdev(self->netdev); kfree (self->ringbuf); self->ringbuf = NULL; diff -Nru a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c --- a/drivers/net/irda/irda-usb.c Mon Jun 9 23:16:12 2003 +++ b/drivers/net/irda/irda-usb.c Mon Jun 9 23:16:12 2003 @@ -1231,12 +1231,10 @@ ASSERT(self != NULL, return -1;); /* Remove netdevice */ - if (self->netdev) { - rtnl_lock(); - unregister_netdevice(self->netdev); - self->netdev = NULL; - rtnl_unlock(); - } + if (self->netdev) + unregister_netdev(self->netdev); + self->netdev = NULL; + /* Remove the speed buffer */ if (self->speed_buff != NULL) { kfree(self->speed_buff); @@ -1609,6 +1607,7 @@ * USB device callbacks */ static struct usb_driver irda_driver = { + .owner = THIS_MODULE, .name = "irda-usb", .probe = irda_usb_probe, .disconnect = irda_usb_disconnect, diff -Nru a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c --- a/drivers/net/irda/irport.c Mon Jun 9 23:16:15 2003 +++ b/drivers/net/irda/irport.c Mon Jun 9 23:16:15 2003 @@ -267,11 +267,8 @@ self->dongle = NULL; /* Remove netdevice */ - if (self->netdev) { - rtnl_lock(); - unregister_netdevice(self->netdev); - rtnl_unlock(); - } + if (self->netdev) + unregister_netdev(self->netdev); /* Release the IO-port that this driver is using */ IRDA_DEBUG(0 , "%s(), Releasing Region %03x\n", diff -Nru a/drivers/net/irda/irtty.c b/drivers/net/irda/irtty.c --- a/drivers/net/irda/irtty.c Mon Jun 9 23:16:08 2003 +++ b/drivers/net/irda/irtty.c Mon Jun 9 23:16:08 2003 @@ -282,11 +282,8 @@ self->dongle = NULL; /* Remove netdevice */ - if (self->netdev) { - rtnl_lock(); - unregister_netdevice(self->netdev); - rtnl_unlock(); - } + if (self->netdev) + unregister_netdev(self->netdev); self = hashbin_remove(irtty, (int) self, NULL); diff -Nru a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c --- a/drivers/net/irda/nsc-ircc.c Mon Jun 9 23:16:05 2003 +++ b/drivers/net/irda/nsc-ircc.c Mon Jun 9 23:16:05 2003 @@ -391,11 +391,8 @@ iobase = self->io.fir_base; /* Remove netdevice */ - if (self->netdev) { - rtnl_lock(); - unregister_netdevice(self->netdev); - rtnl_unlock(); - } + if (self->netdev) + unregister_netdev(self->netdev); /* Release the PORT that this driver is using */ IRDA_DEBUG(4, "%s(), Releasing Region %03x\n", diff -Nru a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c --- a/drivers/net/irda/sa1100_ir.c Mon Jun 9 23:16:10 2003 +++ b/drivers/net/irda/sa1100_ir.c Mon Jun 9 23:16:10 2003 @@ -1122,11 +1122,8 @@ { struct net_device *dev = dev_get_drvdata(&sa1100ir_device.dev); - if (dev) { - rtnl_lock(); - unregister_netdevice(dev); - rtnl_unlock(); - } + if (dev) + unregister_netdev(dev); sys_device_unregister(&sa1100ir_device); driver_unregister(&sa1100ir_driver); diff -Nru a/drivers/net/irda/toshoboe.c b/drivers/net/irda/toshoboe.c --- a/drivers/net/irda/toshoboe.c Mon Jun 9 23:16:05 2003 +++ b/drivers/net/irda/toshoboe.c Mon Jun 9 23:16:05 2003 @@ -679,12 +679,8 @@ self->recv_bufs[i] = NULL; } - if (self->netdev) { - /* Remove netdevice */ - rtnl_lock(); - unregister_netdevice(self->netdev); - rtnl_unlock(); - } + if (self->netdev) + unregister_netdev(self->netdev); kfree (self->taskfilebuf); self->taskfilebuf = NULL; diff -Nru a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c --- a/drivers/net/irda/w83977af_ir.c Mon Jun 9 23:16:10 2003 +++ b/drivers/net/irda/w83977af_ir.c Mon Jun 9 23:16:10 2003 @@ -299,11 +299,8 @@ #endif /* CONFIG_USE_W977_PNP */ /* Remove netdevice */ - if (self->netdev) { - rtnl_lock(); - unregister_netdevice(self->netdev); - rtnl_unlock(); - } + if (self->netdev) + unregister_netdev(self->netdev); /* Release the PORT that this driver is using */ IRDA_DEBUG(0 , "%s(), Releasing Region %03x\n", diff -Nru a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c --- a/drivers/net/ixgb/ixgb_main.c Mon Jun 9 23:16:08 2003 +++ b/drivers/net/ixgb/ixgb_main.c Mon Jun 9 23:16:08 2003 @@ -2315,7 +2315,7 @@ case SYS_DOWN: case SYS_HALT: case SYS_POWER_OFF: - pci_for_each_dev(pdev) { + while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { if (pci_dev_driver(pdev) == &ixgb_driver) ixgb_suspend(pdev, 3); } diff -Nru a/drivers/net/net_init.c b/drivers/net/net_init.c --- a/drivers/net/net_init.c Mon Jun 9 23:16:06 2003 +++ b/drivers/net/net_init.c Mon Jun 9 23:16:06 2003 @@ -178,17 +178,6 @@ return dev; } -#if defined(CONFIG_HIPPI) || defined(CONFIG_TR) || defined(CONFIG_NET_FC) -static int __register_netdev(struct net_device *dev) -{ - if (dev->init && dev->init(dev) != 0) { - unregister_netdev(dev); - return -EIO; - } - return 0; -} -#endif - /** * init_etherdev - Register ethernet device * @dev: An ethernet device structure to be filled in, or %NULL if a new @@ -252,28 +241,6 @@ #ifdef CONFIG_FDDI /** - * init_fddidev - Register FDDI device - * @dev: A FDDI device structure to be filled in, or %NULL if a new - * struct should be allocated. - * @sizeof_priv: Size of additional driver-private structure to be allocated - * for this ethernet device - * - * Fill in the fields of the device structure with FDDI-generic values. - * - * If no device structure is passed, a new one is constructed, complete with - * a private data area of size @sizeof_priv. A 32-byte (not bit) - * alignment is enforced for this private data area. - * - * If an empty string area is passed as dev->name, or a new structure is made, - * a new name string is constructed. - */ - -struct net_device *init_fddidev(struct net_device *dev, int sizeof_priv) -{ - return init_netdev(dev, sizeof_priv, "fddi%d", fddi_setup); -} - -/** * alloc_fddidev - Register FDDI device * @sizeof_priv: Size of additional driver-private structure to be allocated * for this FDDI device @@ -290,7 +257,6 @@ return alloc_netdev(sizeof_priv, "fddi%d", fddi_setup); } -EXPORT_SYMBOL(init_fddidev); EXPORT_SYMBOL(alloc_fddidev); static int fddi_change_mtu(struct net_device *dev, int new_mtu) @@ -330,27 +296,50 @@ return 0; } +static int hippi_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p) +{ + /* Never send broadcast/multicast ARP messages */ + p->mcast_probes = 0; + + /* In IPv6 unicast probes are valid even on NBMA, + * because they are encapsulated in normal IPv6 protocol. + * Should be a generic flag. + */ + if (p->tbl->family != AF_INET6) + p->ucast_probes = 0; + return 0; +} -/** - * init_hippi_dev - Register HIPPI device - * @dev: A HIPPI device structure to be filled in, or %NULL if a new - * struct should be allocated. - * @sizeof_priv: Size of additional driver-private structure to be allocated - * for this ethernet device - * - * Fill in the fields of the device structure with HIPPI-generic values. - * - * If no device structure is passed, a new one is constructed, complete with - * a private data area of size @sizeof_priv. A 32-byte (not bit) - * alignment is enforced for this private data area. - * - * If an empty string area is passed as dev->name, or a new structure is made, - * a new name string is constructed. - */ - -struct net_device *init_hippi_dev(struct net_device *dev, int sizeof_priv) +static void hippi_setup(struct net_device *dev) { - return init_netdev(dev, sizeof_priv, "hip%d", hippi_setup); + dev->set_multicast_list = NULL; + dev->change_mtu = hippi_change_mtu; + dev->hard_header = hippi_header; + dev->rebuild_header = hippi_rebuild_header; + dev->set_mac_address = hippi_mac_addr; + dev->hard_header_parse = NULL; + dev->hard_header_cache = NULL; + dev->header_cache_update = NULL; + dev->neigh_setup = hippi_neigh_setup_dev; + + /* + * We don't support HIPPI `ARP' for the time being, and probably + * never will unless someone else implements it. However we + * still need a fake ARPHRD to make ifconfig and friends play ball. + */ + dev->type = ARPHRD_HIPPI; + dev->hard_header_len = HIPPI_HLEN; + dev->mtu = 65280; + dev->addr_len = HIPPI_ALEN; + dev->tx_queue_len = 25 /* 5 */; + memset(dev->broadcast, 0xFF, HIPPI_ALEN); + + + /* + * HIPPI doesn't support broadcast+multicast and we only use + * static ARP tables. ARP is disabled by hippi_neigh_setup_dev. + */ + dev->flags = 0; } /** @@ -370,34 +359,7 @@ return alloc_netdev(sizeof_priv, "hip%d", hippi_setup); } -int register_hipdev(struct net_device *dev) -{ - return __register_netdev(dev); -} - -void unregister_hipdev(struct net_device *dev) -{ - unregister_netdev(dev); -} - -EXPORT_SYMBOL(init_hippi_dev); EXPORT_SYMBOL(alloc_hippi_dev); -EXPORT_SYMBOL(register_hipdev); -EXPORT_SYMBOL(unregister_hipdev); - -static int hippi_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p) -{ - /* Never send broadcast/multicast ARP messages */ - p->mcast_probes = 0; - - /* In IPv6 unicast probes are valid even on NBMA, - * because they are encapsulated in normal IPv6 protocol. - * Should be a generic flag. - */ - if (p->tbl->family != AF_INET6) - p->ucast_probes = 0; - return 0; -} #endif /* CONFIG_HIPPI */ @@ -455,41 +417,6 @@ #endif /* CONFIG_FDDI */ -#ifdef CONFIG_HIPPI -void hippi_setup(struct net_device *dev) -{ - dev->set_multicast_list = NULL; - dev->change_mtu = hippi_change_mtu; - dev->hard_header = hippi_header; - dev->rebuild_header = hippi_rebuild_header; - dev->set_mac_address = hippi_mac_addr; - dev->hard_header_parse = NULL; - dev->hard_header_cache = NULL; - dev->header_cache_update = NULL; - dev->neigh_setup = hippi_neigh_setup_dev; - - /* - * We don't support HIPPI `ARP' for the time being, and probably - * never will unless someone else implements it. However we - * still need a fake ARPHRD to make ifconfig and friends play ball. - */ - dev->type = ARPHRD_HIPPI; - dev->hard_header_len = HIPPI_HLEN; - dev->mtu = 65280; - dev->addr_len = HIPPI_ALEN; - dev->tx_queue_len = 25 /* 5 */; - memset(dev->broadcast, 0xFF, HIPPI_ALEN); - - - /* - * HIPPI doesn't support broadcast+multicast and we only use - * static ARP tables. ARP is disabled by hippi_neigh_setup_dev. - */ - dev->flags = 0; -} -EXPORT_SYMBOL(hippi_setup); -#endif /* CONFIG_HIPPI */ - #if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE) static int ltalk_change_mtu(struct net_device *dev, int mtu) @@ -598,28 +525,6 @@ } /** - * init_trdev - Register token ring device - * @dev: A token ring device structure to be filled in, or %NULL if a new - * struct should be allocated. - * @sizeof_priv: Size of additional driver-private structure to be allocated - * for this ethernet device - * - * Fill in the fields of the device structure with token ring-generic values. - * - * If no device structure is passed, a new one is constructed, complete with - * a private data area of size @sizeof_priv. A 32-byte (not bit) - * alignment is enforced for this private data area. - * - * If an empty string area is passed as dev->name, or a new structure is made, - * a new name string is constructed. - */ - -struct net_device *init_trdev(struct net_device *dev, int sizeof_priv) -{ - return init_netdev(dev, sizeof_priv, "tr%d", tr_setup); -} - -/** * alloc_trdev - Register token ring device * @sizeof_priv: Size of additional driver-private structure to be allocated * for this token ring device @@ -636,25 +541,11 @@ return alloc_netdev(sizeof_priv, "tr%d", tr_setup); } -int register_trdev(struct net_device *dev) -{ - return __register_netdev(dev); -} - -void unregister_trdev(struct net_device *dev) -{ - unregister_netdev(dev); -} - EXPORT_SYMBOL(tr_setup); -EXPORT_SYMBOL(init_trdev); EXPORT_SYMBOL(alloc_trdev); -EXPORT_SYMBOL(register_trdev); -EXPORT_SYMBOL(unregister_trdev); #endif /* CONFIG_TR */ - #ifdef CONFIG_NET_FC void fc_setup(struct net_device *dev) @@ -675,28 +566,6 @@ } /** - * init_fcdev - Register fibre channel device - * @dev: A fibre channel device structure to be filled in, or %NULL if a new - * struct should be allocated. - * @sizeof_priv: Size of additional driver-private structure to be allocated - * for this ethernet device - * - * Fill in the fields of the device structure with fibre channel-generic values. - * - * If no device structure is passed, a new one is constructed, complete with - * a private data area of size @sizeof_priv. A 32-byte (not bit) - * alignment is enforced for this private data area. - * - * If an empty string area is passed as dev->name, or a new structure is made, - * a new name string is constructed. - */ - -struct net_device *init_fcdev(struct net_device *dev, int sizeof_priv) -{ - return init_netdev(dev, sizeof_priv, "fc%d", fc_setup); -} - -/** * alloc_fcdev - Register fibre channel device * @sizeof_priv: Size of additional driver-private structure to be allocated * for this fibre channel device @@ -713,21 +582,8 @@ return alloc_netdev(sizeof_priv, "fc%d", fc_setup); } -int register_fcdev(struct net_device *dev) -{ - return __register_netdev(dev); -} - -void unregister_fcdev(struct net_device *dev) -{ - unregister_netdev(dev); -} - EXPORT_SYMBOL(fc_setup); -EXPORT_SYMBOL(init_fcdev); EXPORT_SYMBOL(alloc_fcdev); -EXPORT_SYMBOL(register_fcdev); -EXPORT_SYMBOL(unregister_fcdev); #endif /* CONFIG_NET_FC */ diff -Nru a/drivers/net/ns83820.c b/drivers/net/ns83820.c --- a/drivers/net/ns83820.c Mon Jun 9 23:16:19 2003 +++ b/drivers/net/ns83820.c Mon Jun 9 23:16:19 2003 @@ -1769,7 +1769,7 @@ int using_dac = 0; /* See if we can set the dma mask early on; failure is fatal. */ - if (TRY_DAC && !pci_set_dma_mask(pci_dev, 0xffffffffffffffff)) { + if (TRY_DAC && !pci_set_dma_mask(pci_dev, 0xffffffffffffffffULL)) { using_dac = 1; } else if (!pci_set_dma_mask(pci_dev, 0xffffffff)) { using_dac = 0; diff -Nru a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c --- a/drivers/net/pci-skeleton.c Mon Jun 9 23:16:05 2003 +++ b/drivers/net/pci-skeleton.c Mon Jun 9 23:16:05 2003 @@ -602,7 +602,7 @@ *ioaddr_out = NULL; *dev_out = NULL; - /* dev zeroed in init_etherdev */ + /* dev zeroed in alloc_etherdev */ dev = alloc_etherdev (sizeof (*tp)); if (dev == NULL) { printk (KERN_ERR PFX "unable to alloc new ethernet\n"); @@ -790,7 +790,7 @@ dev->irq = pdev->irq; dev->base_addr = (unsigned long) ioaddr; - /* dev->priv/tp zeroed and aligned in init_etherdev */ + /* dev->priv/tp zeroed and aligned in alloc_etherdev */ tp = dev->priv; /* note: tp->chipset set in netdrv_init_board */ diff -Nru a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c --- a/drivers/net/pcmcia/fmvj18x_cs.c Mon Jun 9 23:16:15 2003 +++ b/drivers/net/pcmcia/fmvj18x_cs.c Mon Jun 9 23:16:15 2003 @@ -923,8 +923,7 @@ htons(inw(ioaddr +14))); lp->stats.tx_errors++; /* ToDo: We should try to restart the adaptor... */ - cli(); - + local_irq_disable(); fjn_reset(dev); lp->tx_started = 0; @@ -932,7 +931,7 @@ lp->tx_queue_len = 0; lp->sent = 0; lp->open_time = jiffies; - sti(); + local_irq_enable(); netif_wake_queue(dev); } @@ -1361,9 +1360,8 @@ mc_filter[bit >> 3] |= (1 << bit); } } - - save_flags(flags); - cli(); + + local_irq_save(flags); if (memcmp(mc_filter, lp->mc_filter, sizeof(mc_filter))) { int saved_bank = inb(ioaddr + CONFIG_1); /* Switch to bank 1 and set the multicast table. */ @@ -1373,5 +1371,5 @@ memcpy(lp->mc_filter, mc_filter, sizeof(mc_filter)); outb(saved_bank, ioaddr + CONFIG_1); } - restore_flags(flags); + local_irq_restore(flags); } diff -Nru a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c --- a/drivers/net/pcmcia/ibmtr_cs.c Mon Jun 9 23:16:13 2003 +++ b/drivers/net/pcmcia/ibmtr_cs.c Mon Jun 9 23:16:13 2003 @@ -208,10 +208,13 @@ flush_stale_links(); /* Create new token-ring device */ - info = kmalloc(sizeof(*info), GFP_KERNEL); - if (!info) return NULL; - memset(info, 0, sizeof(*info)); - link = &info->link; link->priv = info; + dev = alloc_trdev(sizeof(*info)); + if (!dev) + return NULL; + info = dev->priv; + + link = &info->link; + link->priv = info; init_timer(&link->release); link->release.function = &ibmtr_release; @@ -232,12 +235,6 @@ link->conf.IntType = INT_MEMORY_AND_IO; link->conf.Present = PRESENT_OPTION; - dev = init_trdev(NULL,0); - if (dev == NULL) { - ibmtr_detach(link); - return NULL; - } - dev->priv = &info->ti; link->irq.Instance = info->dev = dev; dev->init = &ibmtr_probe; @@ -258,11 +255,16 @@ ret = CardServices(RegisterClient, &link->handle, &client_reg); if (ret != 0) { cs_error(link->handle, RegisterClient, ret); - ibmtr_detach(link); - return NULL; + goto out_detach; } +out: return link; + +out_detach: + ibmtr_detach(link); + link = NULL; + goto out; } /* ibmtr_attach */ /*====================================================================== @@ -307,12 +309,8 @@ /* Unlink device structure, free bits */ *linkp = link->next; - if (info->dev) { - unregister_trdev(info->dev); - kfree(info->dev); - } - kfree(info); - + unregister_netdev(dev); + kfree(dev); } /* ibmtr_detach */ /*====================================================================== @@ -413,10 +411,10 @@ Adapters Technical Reference" SC30-3585 for this info. */ ibmtr_hw_setup(dev, mmiobase); - i = register_trdev(dev); + i = register_netdev(dev); if (i != 0) { - printk(KERN_NOTICE "ibmtr_cs: register_trdev() failed\n"); + printk(KERN_NOTICE "ibmtr_cs: register_netdev() failed\n"); goto failed; } diff -Nru a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c --- a/drivers/net/pcmcia/pcnet_cs.c Mon Jun 9 23:16:17 2003 +++ b/drivers/net/pcmcia/pcnet_cs.c Mon Jun 9 23:16:17 2003 @@ -1620,16 +1620,7 @@ static int __init init_pcnet_cs(void) { - servinfo_t serv; - DEBUG(0, "%s\n", version); - CardServices(GetCardServicesInfo, &serv); - if (serv.Revision != CS_RELEASE_CODE) { - printk(KERN_NOTICE "pcnet_cs: Card Services release " - "does not match!\n"); - return -EINVAL; - } - pcmcia_register_driver(&pcnet_driver); - return 0; + return pcmcia_register_driver(&pcnet_driver); } static void __exit exit_pcnet_cs(void) diff -Nru a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c --- a/drivers/net/pcnet32.c Mon Jun 9 23:16:09 2003 +++ b/drivers/net/pcnet32.c Mon Jun 9 23:16:09 2003 @@ -1002,7 +1002,9 @@ } skb_reserve (rx_skbuff, 2); } - lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, rx_skbuff->tail, rx_skbuff->len, PCI_DMA_FROMDEVICE); + + if (lp->rx_dma_addr[i] == NULL) + lp->rx_dma_addr[i] = pci_map_single(lp->pci_dev, rx_skbuff->tail, rx_skbuff->len, PCI_DMA_FROMDEVICE); lp->rx_ring[i].base = (u32)le32_to_cpu(lp->rx_dma_addr[i]); lp->rx_ring[i].buf_length = le16_to_cpu(-PKT_BUF_SZ); lp->rx_ring[i].status = le16_to_cpu(0x8000); @@ -1037,7 +1039,7 @@ /* ReInit Ring */ lp->a.write_csr (ioaddr, 0, 1); i = 0; - while (i++ < 100) + while (i++ < 1000) if (lp->a.read_csr (ioaddr, 0) & 0x0100) break; @@ -1128,6 +1130,7 @@ lp->tx_skbuff[entry] = skb; lp->tx_dma_addr[entry] = pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE); lp->tx_ring[entry].base = (u32)le32_to_cpu(lp->tx_dma_addr[entry]); + wmb(); /* Make sure owner changes after all others are visible */ lp->tx_ring[entry].status = le16_to_cpu(status); lp->cur_tx++; diff -Nru a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c --- a/drivers/net/ppp_async.c Mon Jun 9 23:16:16 2003 +++ b/drivers/net/ppp_async.c Mon Jun 9 23:16:16 2003 @@ -427,12 +427,12 @@ break; case PPPIOCGXASYNCMAP: - if (copy_to_user((void *) arg, ap->xaccm, sizeof(ap->xaccm))) + if (copy_to_user((void __user *) arg, ap->xaccm, sizeof(ap->xaccm))) break; err = 0; break; case PPPIOCSXASYNCMAP: - if (copy_from_user(accm, (void *) arg, sizeof(accm))) + if (copy_from_user(accm, (void __user *) arg, sizeof(accm))) break; accm[2] &= ~0x40000000U; /* can't escape 0x5e */ accm[3] |= 0x60000000U; /* must escape 0x7d, 0x7e */ diff -Nru a/drivers/net/ppp_deflate.c b/drivers/net/ppp_deflate.c --- a/drivers/net/ppp_deflate.c Mon Jun 9 23:16:18 2003 +++ b/drivers/net/ppp_deflate.c Mon Jun 9 23:16:18 2003 @@ -57,29 +57,31 @@ #define DEFLATE_OVHD 2 /* Deflate overhead/packet */ -static void *z_comp_alloc __P((unsigned char *options, int opt_len)); -static void *z_decomp_alloc __P((unsigned char *options, int opt_len)); -static void z_comp_free __P((void *state)); -static void z_decomp_free __P((void *state)); -static int z_comp_init __P((void *state, unsigned char *options, +static void *z_comp_alloc(unsigned char *options, int opt_len); +static void *z_decomp_alloc(unsigned char *options, int opt_len); +static void z_comp_free(void *state); +static void z_decomp_free(void *state); +static int z_comp_init(void *state, unsigned char *options, int opt_len, - int unit, int hdrlen, int debug)); -static int z_decomp_init __P((void *state, unsigned char *options, + int unit, int hdrlen, int debug); +static int z_decomp_init(void *state, unsigned char *options, int opt_len, - int unit, int hdrlen, int mru, int debug)); -static int z_compress __P((void *state, unsigned char *rptr, + int unit, int hdrlen, int mru, int debug); +static int z_compress(void *state, unsigned char *rptr, unsigned char *obuf, - int isize, int osize)); -static void z_incomp __P((void *state, unsigned char *ibuf, int icnt)); -static int z_decompress __P((void *state, unsigned char *ibuf, - int isize, unsigned char *obuf, int osize)); -static void z_comp_reset __P((void *state)); -static void z_decomp_reset __P((void *state)); -static void z_comp_stats __P((void *state, struct compstat *stats)); - -static void -z_comp_free(arg) - void *arg; + int isize, int osize); +static void z_incomp(void *state, unsigned char *ibuf, int icnt); +static int z_decompress(void *state, unsigned char *ibuf, + int isize, unsigned char *obuf, int osize); +static void z_comp_reset(void *state); +static void z_decomp_reset(void *state); +static void z_comp_stats(void *state, struct compstat *stats); + +/** + * z_comp_free - free the memory used by a compressor + * @arg: pointer to the private state for the compressor. + */ +static void z_comp_free(void *arg) { struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; @@ -91,13 +93,21 @@ } } -/* - * Allocate space for a compressor. +/** + * z_comp_alloc - allocate space for a compressor. + * @options: pointer to CCP option data + * @opt_len: length of the CCP option at @options. + * + * The @options pointer points to the a buffer containing the + * CCP option data for the compression being negotiated. It is + * formatted according to RFC1979, and describes the window + * size that the peer is requesting that we use in compressing + * data to be sent to it. + * + * Returns the pointer to the private state for the compressor, + * or NULL if we could not allocate enough memory. */ -static void * -z_comp_alloc(options, opt_len) - unsigned char *options; - int opt_len; +static void *z_comp_alloc(unsigned char *options, int opt_len) { struct ppp_deflate_state *state; int w_size; @@ -135,11 +145,23 @@ return NULL; } -static int -z_comp_init(arg, options, opt_len, unit, hdrlen, debug) - void *arg; - unsigned char *options; - int opt_len, unit, hdrlen, debug; +/** + * z_comp_init - initialize a previously-allocated compressor. + * @arg: pointer to the private state for the compressor + * @options: pointer to the CCP option data describing the + * compression that was negotiated with the peer + * @opt_len: length of the CCP option data at @options + * @unit: PPP unit number for diagnostic messages + * @hdrlen: ignored (present for backwards compatibility) + * @debug: debug flag; if non-zero, debug messages are printed. + * + * The CCP options described by @options must match the options + * specified when the compressor was allocated. The compressor + * history is reset. Returns 0 for failure (CCP options don't + * match) or 1 for success. + */ +static int z_comp_init(void *arg, unsigned char *options, int opt_len, + int unit, int hdrlen, int debug) { struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; @@ -160,9 +182,14 @@ return 1; } -static void -z_comp_reset(arg) - void *arg; +/** + * z_comp_reset - reset a previously-allocated compressor. + * @arg: pointer to private state for the compressor. + * + * This clears the history for the compressor and makes it + * ready to start emitting a new compressed stream. + */ +static void z_comp_reset(void *arg) { struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; @@ -170,12 +197,19 @@ zlib_deflateReset(&state->strm); } -int -z_compress(arg, rptr, obuf, isize, osize) - void *arg; - unsigned char *rptr; /* uncompressed packet (in) */ - unsigned char *obuf; /* compressed packet (out) */ - int isize, osize; +/** + * z_compress - compress a PPP packet with Deflate compression. + * @arg: pointer to private state for the compressor + * @rptr: uncompressed packet (input) + * @obuf: compressed packet (output) + * @isize: size of uncompressed packet + * @osize: space available at @obuf + * + * Returns the length of the compressed packet, or 0 if the + * packet is incompressible. + */ +int z_compress(void *arg, unsigned char *rptr, unsigned char *obuf, + int isize, int osize) { struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; int r, proto, off, olen, oavail; @@ -251,19 +285,24 @@ return olen; } -static void -z_comp_stats(arg, stats) - void *arg; - struct compstat *stats; +/** + * z_comp_stats - return compression statistics for a compressor + * or decompressor. + * @arg: pointer to private space for the (de)compressor + * @stats: pointer to a struct compstat to receive the result. + */ +static void z_comp_stats(void *arg, struct compstat *stats) { struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; *stats = state->stats; } -static void -z_decomp_free(arg) - void *arg; +/** + * z_decomp_free - Free the memory used by a decompressor. + * @arg: pointer to private space for the decompressor. + */ +static void z_decomp_free(void *arg) { struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; @@ -275,13 +314,21 @@ } } -/* - * Allocate space for a decompressor. +/** + * z_decomp_alloc - allocate space for a decompressor. + * @options: pointer to CCP option data + * @opt_len: length of the CCP option at @options. + * + * The @options pointer points to the a buffer containing the + * CCP option data for the compression being negotiated. It is + * formatted according to RFC1979, and describes the window + * size that we are requesting the peer to use in compressing + * data to be sent to us. + * + * Returns the pointer to the private state for the decompressor, + * or NULL if we could not allocate enough memory. */ -static void * -z_decomp_alloc(options, opt_len) - unsigned char *options; - int opt_len; +static void *z_decomp_alloc(unsigned char *options, int opt_len) { struct ppp_deflate_state *state; int w_size; @@ -317,11 +364,24 @@ return NULL; } -static int -z_decomp_init(arg, options, opt_len, unit, hdrlen, mru, debug) - void *arg; - unsigned char *options; - int opt_len, unit, hdrlen, mru, debug; +/** + * z_decomp_init - initialize a previously-allocated decompressor. + * @arg: pointer to the private state for the decompressor + * @options: pointer to the CCP option data describing the + * compression that was negotiated with the peer + * @opt_len: length of the CCP option data at @options + * @unit: PPP unit number for diagnostic messages + * @hdrlen: ignored (present for backwards compatibility) + * @mru: maximum length of decompressed packets + * @debug: debug flag; if non-zero, debug messages are printed. + * + * The CCP options described by @options must match the options + * specified when the decompressor was allocated. The decompressor + * history is reset. Returns 0 for failure (CCP options don't + * match) or 1 for success. + */ +static int z_decomp_init(void *arg, unsigned char *options, int opt_len, + int unit, int hdrlen, int mru, int debug) { struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; @@ -343,9 +403,14 @@ return 1; } -static void -z_decomp_reset(arg) - void *arg; +/** + * z_decomp_reset - reset a previously-allocated decompressor. + * @arg: pointer to private state for the decompressor. + * + * This clears the history for the decompressor and makes it + * ready to receive a new compressed stream. + */ +static void z_decomp_reset(void *arg) { struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; @@ -353,8 +418,13 @@ zlib_inflateReset(&state->strm); } -/* - * Decompress a Deflate-compressed packet. +/** + * z_decompress - decompress a Deflate-compressed packet. + * @arg: pointer to private state for the decompressor + * @ibuf: pointer to input (compressed) packet data + * @isize: length of input packet + * @obuf: pointer to space for output (decompressed) packet + * @osize: amount of space available at @obuf * * Because of patent problems, we return DECOMP_ERROR for errors * found by inspecting the input data and for system problems, but @@ -369,13 +439,8 @@ * bug, so we return DECOMP_FATALERROR for them in order to turn off * compression, even though they are detected by inspecting the input. */ -int -z_decompress(arg, ibuf, isize, obuf, osize) - void *arg; - unsigned char *ibuf; - int isize; - unsigned char *obuf; - int osize; +int z_decompress(void *arg, unsigned char *ibuf, int isize, + unsigned char *obuf, int osize) { struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; int olen, seq, r; @@ -474,14 +539,13 @@ return olen; } -/* - * Incompressible data has arrived - add it to the history. +/** + * z_incomp - add incompressible input data to the history. + * @arg: pointer to private state for the decompressor + * @ibuf: pointer to input packet data + * @icnt: length of input data. */ -static void -z_incomp(arg, ibuf, icnt) - void *arg; - unsigned char *ibuf; - int icnt; +static void z_incomp(void *arg, unsigned char *ibuf, int icnt) { struct ppp_deflate_state *state = (struct ppp_deflate_state *) arg; int proto, r; diff -Nru a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c --- a/drivers/net/ppp_generic.c Mon Jun 9 23:16:18 2003 +++ b/drivers/net/ppp_generic.c Mon Jun 9 23:16:18 2003 @@ -387,7 +387,7 @@ return 0; } -static ssize_t ppp_read(struct file *file, char *buf, +static ssize_t ppp_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { struct ppp_file *pf = file->private_data; @@ -436,7 +436,7 @@ return ret; } -static ssize_t ppp_write(struct file *file, const char *buf, +static ssize_t ppp_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { struct ppp_file *pf = file->private_data; @@ -617,7 +617,7 @@ case PPPIOCGIDLE: idle.xmit_idle = (jiffies - ppp->last_xmit) / HZ; idle.recv_idle = (jiffies - ppp->last_recv) / HZ; - if (copy_to_user((void *) arg, &idle, sizeof(idle))) + if (copy_to_user((void __user *) arg, &idle, sizeof(idle))) break; err = 0; break; @@ -646,7 +646,7 @@ case PPPIOCGNPMODE: case PPPIOCSNPMODE: - if (copy_from_user(&npi, (void *) arg, sizeof(npi))) + if (copy_from_user(&npi, (void __user *) arg, sizeof(npi))) break; err = proto_to_npindex(npi.protocol); if (err < 0) @@ -655,7 +655,7 @@ if (cmd == PPPIOCGNPMODE) { err = -EFAULT; npi.mode = ppp->npmode[i]; - if (copy_to_user((void *) arg, &npi, sizeof(npi))) + if (copy_to_user((void __user *) arg, &npi, sizeof(npi))) break; } else { ppp->npmode[i] = npi.mode; @@ -673,22 +673,22 @@ struct sock_filter *code = NULL; int len; - if (copy_from_user(&uprog, (void *) arg, sizeof(uprog))) + if (copy_from_user(&uprog, (void __user *) arg, sizeof(uprog))) + break; + err = -ENOMEM; + len = uprog.len * sizeof(struct sock_filter); + code = kmalloc(len, GFP_KERNEL); + if (code == 0) + break; + err = -EFAULT; + if (copy_from_user(code, (void __user *) uprog.filter, len)) { + kfree(code); + break; + } + err = sk_chk_filter(code, uprog.len); + if (err) { + kfree(code); break; - if (uprog.len > 0 && uprog.len < 65536) { - err = -ENOMEM; - len = uprog.len * sizeof(struct sock_filter); - code = kmalloc(len, GFP_KERNEL); - if (code == 0) - break; - err = -EFAULT; - if (copy_from_user(code, uprog.filter, len)) - break; - err = sk_chk_filter(code, uprog.len); - if (err) { - kfree(code); - break; - } } filtp = (cmd == PPPIOCSPASS)? &ppp->pass_filter: &ppp->active_filter; ppp_lock(ppp); @@ -877,7 +877,7 @@ { struct ppp *ppp = dev->priv; int err = -EFAULT; - void *addr = (void *) ifr->ifr_ifru.ifru_data; + void __user *addr = (void __user *) ifr->ifr_ifru.ifru_data; struct ppp_stats stats; struct ppp_comp_stats cstats; char *vers; @@ -1950,9 +1950,9 @@ unsigned char ccp_option[CCP_MAX_OPTION_LENGTH]; err = -EFAULT; - if (copy_from_user(&data, (void *) arg, sizeof(data)) + if (copy_from_user(&data, (void __user *) arg, sizeof(data)) || (data.length <= CCP_MAX_OPTION_LENGTH - && copy_from_user(ccp_option, data.ptr, data.length))) + && copy_from_user(ccp_option, (void __user *) data.ptr, data.length))) goto out; err = -EINVAL; if (data.length > CCP_MAX_OPTION_LENGTH diff -Nru a/drivers/net/pppoe.c b/drivers/net/pppoe.c --- a/drivers/net/pppoe.c Mon Jun 9 23:16:15 2003 +++ b/drivers/net/pppoe.c Mon Jun 9 23:16:15 2003 @@ -277,11 +277,12 @@ lock_sock(sk); - if (sk->state & (PPPOX_CONNECTED|PPPOX_BOUND)){ + if (sk->sk_state & + (PPPOX_CONNECTED | PPPOX_BOUND)) { pppox_unbind_sock(sk); dev_put(dev); - sk->state = PPPOX_ZOMBIE; - sk->state_change(sk); + sk->sk_state = PPPOX_ZOMBIE; + sk->sk_state_change(sk); } release_sock(sk); @@ -347,16 +348,16 @@ struct pppox_opt *po = pppox_sk(sk); struct pppox_opt *relay_po = NULL; - if (sk->state & PPPOX_BOUND) { + if (sk->sk_state & PPPOX_BOUND) { skb_pull(skb, sizeof(struct pppoe_hdr)); ppp_input(&po->chan, skb); - } else if (sk->state & PPPOX_RELAY) { + } else if (sk->sk_state & PPPOX_RELAY) { relay_po = get_item_by_addr(&po->pppoe_relay); if (relay_po == NULL) goto abort_kfree; - if ((relay_po->sk->state & PPPOX_CONNECTED) == 0) + if ((relay_po->sk->sk_state & PPPOX_CONNECTED) == 0) goto abort_put; skb_pull(skb, sizeof(struct pppoe_hdr)); @@ -447,7 +448,7 @@ /* We're no longer connect at the PPPOE layer, * and must wait for ppp channel to disconnect us. */ - sk->state = PPPOX_ZOMBIE; + sk->sk_state = PPPOX_ZOMBIE; } bh_unlock_sock(sk); @@ -503,12 +504,12 @@ sock->state = SS_UNCONNECTED; sock->ops = &pppoe_ops; - sk->backlog_rcv = pppoe_rcv_core; - sk->state = PPPOX_NONE; - sk->type = SOCK_STREAM; - sk->family = PF_PPPOX; - sk->protocol = PX_PROTO_OE; - sk->destruct = pppoe_sk_free; + sk->sk_backlog_rcv = pppoe_rcv_core; + sk->sk_state = PPPOX_NONE; + sk->sk_type = SOCK_STREAM; + sk->sk_family = PF_PPPOX; + sk->sk_protocol = PX_PROTO_OE; + sk->sk_destruct = pppoe_sk_free; po = pppox_sk(sk) = kmalloc(sizeof(*po), GFP_KERNEL); if (!po) @@ -530,13 +531,13 @@ if (!sk) return 0; - if (test_bit(SOCK_DEAD, &sk->flags)) + if (sock_flag(sk, SOCK_DEAD)) return -EBADF; pppox_unbind_sock(sk); /* Signal the death of the socket. */ - sk->state = PPPOX_DEAD; + sk->sk_state = PPPOX_DEAD; po = pppox_sk(sk); if (po->pppoe_pa.sid) { @@ -551,7 +552,7 @@ sock_orphan(sk); sock->sk = NULL; - skb_queue_purge(&sk->receive_queue); + skb_queue_purge(&sk->sk_receive_queue); sock_put(sk); return error; @@ -575,12 +576,12 @@ /* Check for already bound sockets */ error = -EBUSY; - if ((sk->state & PPPOX_CONNECTED) && sp->sa_addr.pppoe.sid) + if ((sk->sk_state & PPPOX_CONNECTED) && sp->sa_addr.pppoe.sid) goto end; /* Check for already disconnected sockets, on attempts to disconnect */ error = -EALREADY; - if((sk->state & PPPOX_DEAD) && !sp->sa_addr.pppoe.sid ) + if ((sk->sk_state & PPPOX_DEAD) && !sp->sa_addr.pppoe.sid ) goto end; error = 0; @@ -596,7 +597,7 @@ memset(po, 0, sizeof(struct pppox_opt)); po->sk = sk; - sk->state = PPPOX_NONE; + sk->sk_state = PPPOX_NONE; } /* Don't re-bind if sid==0 */ @@ -630,7 +631,7 @@ if (error) goto err_put; - sk->state = PPPOX_CONNECTED; + sk->sk_state = PPPOX_CONNECTED; } po->num = sp->sa_addr.pppoe.sid; @@ -678,7 +679,7 @@ case PPPIOCGMRU: err = -ENXIO; - if (!(sk->state & PPPOX_CONNECTED)) + if (!(sk->sk_state & PPPOX_CONNECTED)) break; err = -EFAULT; @@ -692,7 +693,7 @@ case PPPIOCSMRU: err = -ENXIO; - if (!(sk->state & PPPOX_CONNECTED)) + if (!(sk->sk_state & PPPOX_CONNECTED)) break; err = -EFAULT; @@ -719,11 +720,11 @@ struct pppox_opt *relay_po; err = -EBUSY; - if (sk->state & (PPPOX_BOUND|PPPOX_ZOMBIE|PPPOX_DEAD)) + if (sk->sk_state & (PPPOX_BOUND | PPPOX_ZOMBIE | PPPOX_DEAD)) break; err = -ENOTCONN; - if (!(sk->state & PPPOX_CONNECTED)) + if (!(sk->sk_state & PPPOX_CONNECTED)) break; /* PPPoE address from the user specifies an outbound @@ -747,17 +748,17 @@ break; sock_put(relay_po->sk); - sk->state |= PPPOX_RELAY; + sk->sk_state |= PPPOX_RELAY; err = 0; break; } case PPPOEIOCDFWD: err = -EALREADY; - if (!(sk->state & PPPOX_RELAY)) + if (!(sk->sk_state & PPPOX_RELAY)) break; - sk->state &= ~PPPOX_RELAY; + sk->sk_state &= ~PPPOX_RELAY; err = 0; break; @@ -780,7 +781,7 @@ struct net_device *dev; char *start; - if (test_bit(SOCK_DEAD, &sk->flags) || !(sk->state & PPPOX_CONNECTED)) { + if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) { error = -ENOTCONN; goto end; } @@ -812,7 +813,7 @@ skb->dev = dev; - skb->priority = sk->priority; + skb->priority = sk->sk_priority; skb->protocol = __constant_htons(ETH_P_PPP_SES); ph = (struct pppoe_hdr *) skb_put(skb, total_len + sizeof(struct pppoe_hdr)); @@ -856,7 +857,7 @@ int data_len = skb->len; struct sk_buff *skb2; - if (test_bit(SOCK_DEAD, &sk->flags) || !(sk->state & PPPOX_CONNECTED)) + if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) goto abort; hdr.ver = 1; @@ -938,7 +939,7 @@ int len; struct pppoe_hdr *ph = NULL; - if (sk->state & PPPOX_BOUND) { + if (sk->sk_state & PPPOX_BOUND) { error = -EIO; goto end; } @@ -1129,7 +1130,9 @@ dev_remove_pack(&pppoes_ptype); dev_remove_pack(&pppoed_ptype); unregister_netdevice_notifier(&pppoe_notifier); +#ifdef CONFIG_PROC_FS remove_proc_entry("pppoe", proc_net); +#endif } module_init(pppoe_init); diff -Nru a/drivers/net/pppox.c b/drivers/net/pppox.c --- a/drivers/net/pppox.c Mon Jun 9 23:16:18 2003 +++ b/drivers/net/pppox.c Mon Jun 9 23:16:18 2003 @@ -58,9 +58,9 @@ { /* Clear connection to ppp device, if attached. */ - if (sk->state & (PPPOX_BOUND|PPPOX_ZOMBIE)) { + if (sk->sk_state & (PPPOX_BOUND | PPPOX_ZOMBIE)) { ppp_unregister_channel(&pppox_sk(sk)->chan); - sk->state = PPPOX_DEAD; + sk->sk_state = PPPOX_DEAD; } } @@ -81,7 +81,7 @@ case PPPIOCGCHAN: { int index; rc = -ENOTCONN; - if (!(sk->state & PPPOX_CONNECTED)) + if (!(sk->sk_state & PPPOX_CONNECTED)) break; rc = -EINVAL; @@ -90,12 +90,13 @@ break; rc = 0; - sk->state |= PPPOX_BOUND; + sk->sk_state |= PPPOX_BOUND; break; } default: - if (pppox_protos[sk->protocol]->ioctl) - rc = pppox_protos[sk->protocol]->ioctl(sock, cmd, arg); + if (pppox_protos[sk->sk_protocol]->ioctl) + rc = pppox_protos[sk->sk_protocol]->ioctl(sock, cmd, + arg); break; }; diff -Nru a/drivers/net/ptifddi.c b/drivers/net/ptifddi.c --- a/drivers/net/ptifddi.c Mon Jun 9 23:16:05 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,259 +0,0 @@ -/* $Id: ptifddi.c,v 1.14 2001/04/14 01:12:04 davem Exp $ - * ptifddi.c: Network driver for Performance Technologies single-attach - * and dual-attach FDDI sbus cards. - * - * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) - */ - -static char *version = - "ptifddi.c:v1.0 10/Dec/96 David S. Miller (davem@caipfs.rutgers.edu)\n"; - -#include <linux/string.h> -#include <linux/init.h> - -#include "ptifddi.h" - -#include "ptifddi_asm.h" - -#ifdef MODULE -static struct ptifddi *root_pti_dev; -#endif - -static inline void pti_reset(struct ptifddi *pp) -{ - pp->reset = 1; -} - -static inline void pti_unreset(struct ptifddi *pp) -{ - pp->unreset = 1; -} - -static inline void pti_load_code_base(struct dfddi_ram *rp, unsigned short addr) -{ - rp->loader_addr = ((addr << 8) & 0xff00) | ((addr >> 8) & 0x00ff); -} - -static inline void pti_clear_dpram(struct ptifddi *pp) -{ - memset(pp->dpram, 0, DPRAM_SIZE); -} - -#define CARD_TEST_TIMEOUT 100000 - -static inline int pti_card_test(struct ptifddi *pp) -{ - struct dfddi_ram *rp = pp->dpram; - unsigned char *code = &rp->loader; - unsigned char *status = (unsigned char *) rp; - int clicks = CARD_TEST_TIMEOUT; - - /* Clear it out. */ - pti_clear_dpram(pp); - - /* Load test data. */ - for(i = 0; i < test_firmware_size; i++) - code[i] = test_firmware[i]; - - /* Tell card where to execute the code. */ - pti_load_code_base(pp, test_firmware_dev_addr); - - /* Clear test run status in dpram. */ - *status = 0; - - /* Reset single attach state machine before the test. */ - rp->reset = 1; - - /* Unreset, to get the test code running. */ - pti_unreset(pp); - - /* Wait for dpram status to become 5, else fail if we time out. */ - while(--clicks) { - if(*status == 5) { - pti_reset(pp); - return 0; - } - udelay(20); - } - return 1; -} - -static inline void pti_init_firmware_loader(struct ptifddi *pp) -{ - struct dfddi_ram *rp = pp->dpram; - int i; - - for(i = 0; i < firmware_loader_size; i++) - rp->loader.loader_firmware[i] = firmware_loader[i]; -} - -static inline void pti_load_main_firmware(struct ptifddi *pp) -{ - struct dfddi_ram *rp = pp->dpram; - struct dpram_loader *lp = &rp.loader; - int i; - - -} - -static void pti_init_rings(struct ptifddi *pp, int from_irq) -{ -} - -static int pti_init(struct ptifddi *pp, int from_irq) -{ -} - -static void pti_is_not_so_happy(struct ptifddi *pp) -{ -} - -static inline void pti_tx(struct ptifddi *pp, struct net_device *dev) -{ -} - -static inline void myri_rx(struct ptifddi *pp, struct net_device *dev) -{ -} - -static void pti_interrupt(int irq, void *dev_id, struct pt_regs *regs) -{ - struct net_device *dev = (struct net_device *) dev_id; - struct ptifddi *pp = (struct ptifddi *) dev->priv; - -} - -static int pti_open(struct net_device *dev) -{ - struct ptifddi *pp = (struct ptifddi *) dev->priv; - - return pti_init(pp, in_interrupt()); -} - -static int pti_close(struct net_device *dev) -{ - struct ptifddi *pp = (struct ptifddi *) dev->priv; - - return 0; -} - -static int pti_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct ptifddi *pp = (struct ptifddi *) dev->priv; -} - -static struct net_device_stats *pti_get_stats(struct net_device *dev) -{ return &(((struct ptifddi *)dev->priv)->enet_stats); } - -static void pti_set_multicast(struct net_device *dev) -{ -} - -static inline int pti_fddi_init(struct net_device *dev, struct sbus_dev *sdev, int num) -{ - static unsigned version_printed; - struct ptifddi *pp; - int i; - - dev = init_fddidev(0, sizeof(struct ptifddi)); - - if(version_printed++ == 0) - printk(version); - - /* Register 0 mapping contains DPRAM. */ - pp->dpram = (struct dfddi_ram *) sbus_ioremap( - &sdep->resource[0], 0, sizeof(sturct dfddi_ram), "PTI FDDI DPRAM"); - if(!pp->dpram) { - printk("ptiFDDI: Cannot map DPRAM I/O area.\n"); - return -ENODEV; - } - - /* Next, register 1 contains reset byte. */ - pp->reset = (unsigned char *) sbus_ioremap( - &sdep->resource[1], 0, 1, "PTI FDDI RESET Byte"); - if(!pp->reset) { - printk("ptiFDDI: Cannot map RESET byte.\n"); - return -ENODEV; - } - - /* Register 2 contains unreset byte. */ - pp->unreset = (unsigned char *) sbus_ioremap( - &sdep->resource[2], 0, 1, "PTI FDDI UNRESET Byte"); - if(!pp->unreset) { - printk("ptiFDDI: Cannot map UNRESET byte.\n"); - return -ENODEV; - } - - /* Reset the card. */ - pti_reset(pp); - - /* Run boot-up card tests. */ - i = pti_card_test(pp); - if(i) { - printk("ptiFDDI: Bootup card test fails.\n"); - return -ENODEV; - } - - /* Clear DPRAM, start afresh. */ - pti_clear_dpram(pp); - - /* Init the firmware loader. */ - pti_init_firmware_loader(pp); - - /* Now load main card FDDI firmware, using the loader. */ - pti_load_main_firmware(pp); -} - -int __init ptifddi_sbus_probe(struct net_device *dev) -{ - struct sbus_bus *bus; - struct sbus_dev *sdev = 0; - static int called; - int cards = 0, v; - - if(called) - return -ENODEV; - called++; - - for_each_sbus(bus) { - for_each_sbusdev(sdev, bus) { - if(cards) dev = NULL; - if(!strcmp(sdev->prom_name, "PTI,sbs600") || - !strcmp(sdev->prom_name, "DPV,fddid")) { - cards++; - DET(("Found PTI FDDI as %s\n", sdev->prom_name)); - if((v = pti_fddi_init(dev, sdev, (cards - 1)))) - return v; - } - } - } - if(!cards) - return -ENODEV; - return 0; -} - - -#ifdef MODULE - -int -init_module(void) -{ - root_pti_dev = NULL; - return ptifddi_sbus_probe(NULL); -} - -void -cleanup_module(void) -{ - struct ptifddi *pp; - - while (root_pti_dev) { - pp = root_pti_dev->next_module; - - unregister_netdev(root_pti_dev->dev); - kfree(root_pti_dev->dev); - root_pti_dev = mp; - } -} - -#endif /* MODULE */ diff -Nru a/drivers/net/ptifddi.h b/drivers/net/ptifddi.h --- a/drivers/net/ptifddi.h Mon Jun 9 23:16:10 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,77 +0,0 @@ -/* $Id: ptifddi.h,v 1.3 1999/08/20 00:31:08 davem Exp $ - * ptifddi.c: Defines for Performance Technologies FDDI sbus cards. - * - * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) - */ - -#ifndef _PTIFDDI_H -#define _PTIFDDI_H - -struct dpram_loader { - volatile unsigned char dpram_stat; - volatile unsigned char _unused; - volatile unsigned char addr_low; - volatile unsigned char addr_hi; - volatile unsigned char num_bytes; - volatile unsigned char data[0x3b]; - - volatile unsigned char loader_firmware[0xc0]; -}; - -struct dfddi_ram { -/*0x000*/ unsigned char _unused0[0x100]; -/*0x100*/ struct dpram_loader loader; -/*0x200*/ unsigned char instructions[0x400]; -/*0x600*/ unsigned char msg_in[0x20]; -/*0x620*/ unsigned char msg_out[0x20]; -/*0x640*/ unsigned char _unused2[0x50]; -/*0x690*/ unsigned char smsg_in[0x20]; -/*0x6b0*/ unsigned char _unused3[0x30]; -/*0x6e0*/ unsigned char beacom_frame[0x20]; -/*0x700*/ unsigned char re_sync; -/*0x701*/ unsigned char _unused4; -/*0x702*/ unsigned short tswitch; -/*0x704*/ unsigned char evq_lost; -/*0x705*/ unsigned char _unused6; -/*0x706*/ unsigned char signal_lost; -/*0x707*/ unsigned char _unused7; -/*0x708*/ unsigned char lerror; -/*0x709*/ unsigned char _unused8; -/*0x70a*/ unsigned char rstate; -/*0x70b*/ unsigned char _unused9[0x13]; -/*0x716*/ unsigned short dswitch; -/*0x718*/ unsigned char _unused10[0x48]; -/*0x750*/ unsigned char cbusy; -/*0x751*/ unsigned char hbusy; -/*0x752*/ unsigned short istat; -/*0x754*/ unsigned char _unused11[]; -/*0x756*/ unsigned char disable; -/*0x757*/ unsigned char _unused12[]; -/*0x78e*/ unsigned char ucvalid; -/*0x78f*/ unsigned char _unused13; -/*0x790*/ unsigned int u0addr; -/*0x794*/ unsigned char _unused14[]; -/*0x7a8*/ unsigned int P_player; -/*0x7ac*/ unsigned int Q_player; -/*0x7b0*/ unsigned int macsi; -/*0x7b4*/ unsigned char _unused15[]; -/*0x7be*/ unsigned short reset; -/*0x7c0*/ unsigned char _unused16[]; -/*0x7fc*/ unsigned short iack; -/*0x7fe*/ unsigned short loader_addr; -}; - -#define DPRAM_SIZE 0x800 - -#define DPRAM_STAT_VALID 0x80 -#define DPRAM_STAT_EMPTY 0x00 - -struct ptifddi { - struct dfddi_ram *dpram; - unsigned char *reset; - unsigned char *unreset; - struct net_device *dev; - struct ptifddi *next_module; -}; - -#endif /* !(_PTIFDDI_H) */ diff -Nru a/drivers/net/ptifddi_asm.h b/drivers/net/ptifddi_asm.h --- a/drivers/net/ptifddi_asm.h Mon Jun 9 23:16:10 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,2543 +0,0 @@ -/* $Id: ptifddi_asm.h,v 1.3 1997/04/16 10:27:28 jj Exp $ */ -#ifndef _PTIFDDI_ASM_H -#define _PTIFDDI_ASM_H - -/* This is the code for the DPRAM firmware loader. */ -const unsigned short firmware_loader_code_addr = 0x140; /* Offset from dpram base. */ -const unsigned short firmware_loader_dev_addr = 0xf940; /* Offset as seen by device. */ -const unsigned short firmware_loader_size = 0x6f; /* Size of fware loader code.*/ - -static unsigned char firmware_loader[] __initdata = { - 0xb7, 0x01, 0xc0, 0xc4, 0x97, 0x14, 0xc0, 0xb7, 0xf9, 0x02, 0x12, 0x03, 0x30, - 0x2c, 0x8b, 0x0d, 0x30, 0x28, 0x8b, 0x0c, 0x30, 0x24, 0x8b, 0x11, 0x82, 0x00, - 0x11, 0xdc, 0x56, 0x30, 0x1b, 0x86, 0xff, 0xfc, 0x0c, 0xfc, 0x49, 0x86, 0xff, - 0xfd, 0x0c, 0xfc, 0x43, 0xad, 0x0c, 0x8b, 0xa9, 0x0c, 0x8a, 0x11, 0x75, 0x83, - 0x00, 0xf9, 0x00, 0xab, 0x95, 0x31, 0x03, 0x40, 0xb6, 0xf9, 0x00, 0xa8, 0x96, - 0xc8, 0x17, 0x41, 0x68, 0xad, 0x12, 0x88, 0xa9, 0x12, 0x86, 0xf9, 0x16, 0x12, - 0xfc, 0x47, 0x86, 0xf9, 0x16, 0x12, 0xfd, 0x41, 0x3c, 0x83, 0x00, 0xf9, 0x00, - 0xab, 0xb7, 0xf9, 0x02, 0x12, 0x3c, 0x83, 0x00, 0xf9, 0x00, 0xab, 0xb7, 0xf9, - 0x02, 0x12, 0x03, 0x95, 0x2f -}; - -/* This is test code which we run at boot time to go and verify the proper - * functioning of the PTI fddi card. - */ -const unsigned short test_firmware_code_addr = 0x100; /* Offset from dpram base. */ -const unsigned short test_firmware_dev_addr = 0xfa00; /* Offset as seen by device. */ -const unsigned short test_firmware_size = 0x414; /* Size of card test code. */ - -static unsigned char test_firmware[] __initdata = { - 0x97, 0x00, 0xd0, 0x90, 0x01, 0x8b, 0xd4, 0x8b, 0xf4, 0x97, 0x1f, 0xe2, 0x97, - 0x1f, 0xf2, 0x97, 0x14, 0xc0, 0xb7, 0x01, 0xc0, 0xc4, 0x00, 0x8b, 0x0b, 0x00, - 0x8b, 0x03, 0x8b, 0x0a, 0xab, 0x08, 0x90, 0x00, 0x8b, 0x04, 0x90, 0x40, 0x8b, - 0x05, 0x90, 0xff, 0x8b, 0x06, 0x90, 0xf7, 0x8b, 0x07, 0x90, 0x00, 0x8b, 0x0c, - 0x33, 0x8d, 0x82, 0x00, 0x0a, 0xdd, 0x94, 0x57, 0x89, 0x0c, 0x89, 0x0b, 0x33, - 0x81, 0x82, 0x00, 0x0a, 0xdd, 0x94, 0x4b, 0x89, 0x0c, 0x33, 0x77, 0x82, 0x00, - 0x0a, 0xdd, 0x94, 0x41, 0x91, 0x01, 0x30, 0xc4, 0x00, 0x30, 0xd2, 0x9c, 0x00, - 0x91, 0x02, 0x9d, 0x00, 0x91, 0x42, 0x30, 0xb7, 0xb6, 0x01, 0x04, 0x88, 0x96, - 0xc8, 0x10, 0x41, 0x4e, 0x90, 0x01, 0x30, 0xbb, 0x9c, 0x00, 0x91, 0x03, 0x9d, - 0x00, 0x91, 0x43, 0x30, 0xa0, 0x31, 0x97, 0x9c, 0x00, 0x91, 0x04, 0x9d, 0x00, - 0x91, 0x44, 0x30, 0x94, 0x32, 0x6b, 0x9c, 0x00, 0x91, 0x05, 0x9d, 0x00, 0x91, - 0x45, 0x30, 0x88, 0x60, 0x91, 0x41, 0x95, 0x41, 0xab, 0xce, 0xe1, 0x41, 0x3c, - 0x82, 0x02, 0x0c, 0xdc, 0x49, 0xa8, 0xce, 0x03, 0xf7, 0x07, 0xb8, 0x00, 0x01, - 0x72, 0xa8, 0xcc, 0x75, 0xab, 0xce, 0xc1, 0x41, 0x3c, 0x82, 0x02, 0x0c, 0xdc, - 0x4b, 0xa8, 0xce, 0x03, 0xf7, 0x96, 0xc9, 0x10, 0xb8, 0x00, 0x01, 0x74, 0xa8, - 0xcc, 0x77, 0xab, 0xce, 0xe0, 0x41, 0x3c, 0x96, 0xce, 0xfc, 0x42, 0x30, 0x46, - 0x82, 0x02, 0x0c, 0xdc, 0x4b, 0xae, 0xce, 0x03, 0xf7, 0x07, 0xb8, 0x00, 0x01, - 0xae, 0xce, 0x78, 0xac, 0xcc, 0xce, 0x7c, 0xab, 0xce, 0xc0, 0x41, 0x3c, 0xaf, - 0xc8, 0x96, 0xce, 0xfb, 0x99, 0xff, 0x9c, 0x00, 0x45, 0x3f, 0xc8, 0x30, 0x1b, - 0x42, 0x3f, 0xc8, 0x82, 0x02, 0x0c, 0xdc, 0x4e, 0xae, 0xce, 0x03, 0xf7, 0x96, - 0xc9, 0x10, 0xb8, 0x00, 0x01, 0xae, 0xce, 0x95, 0x25, 0xac, 0xcc, 0xce, 0x95, - 0x2a, 0x97, 0x01, 0x0a, 0x3c, 0x97, 0x01, 0x0a, 0x3c, 0x82, 0x05, 0xca, 0xfd, - 0x46, 0xa1, 0xca, 0xf8, 0x00, 0x8b, 0x3c, 0xa1, 0xca, 0xf8, 0x00, 0x8b, 0x60, - 0xb7, 0x20, 0x00, 0x10, 0x9d, 0x00, 0xb7, 0x28, 0x00, 0x10, 0xac, 0x10, 0xcc, - 0x97, 0x37, 0x12, 0x30, 0x64, 0xac, 0x10, 0xcc, 0x97, 0x37, 0x12, 0x30, 0x87, - 0x30, 0x0a, 0x82, 0x00, 0x0a, 0xdd, 0x42, 0x00, 0x3c, 0x90, 0x01, 0x3c, 0xac, - 0x10, 0xcc, 0x97, 0x00, 0x12, 0x97, 0x01, 0x03, 0x44, 0xeb, 0x58, 0x24, 0x3c, - 0xb7, 0xfb, 0x5b, 0x14, 0x91, 0x01, 0xad, 0x14, 0x88, 0x96, 0xca, 0xf9, 0xae, - 0xca, 0x03, 0xf7, 0xae, 0xca, 0x9d, 0x00, 0x30, 0x15, 0xa9, 0xcc, 0xa9, 0xcc, - 0x86, 0x01, 0x00, 0xca, 0xfc, 0x41, 0x7a, 0xa9, 0x14, 0x86, 0xfb, 0x5f, 0x14, - 0xfc, 0x3c, 0x95, 0x25, 0xc4, 0x88, 0x12, 0xc6, 0xc4, 0x96, 0x12, 0xdc, 0x3c, - 0x80, 0x12, 0xce, 0xab, 0xa9, 0xcc, 0x34, 0x87, 0xae, 0xcc, 0x05, 0xae, 0xcc, - 0x3c, 0xb7, 0xfb, 0x5b, 0x14, 0x91, 0x01, 0xad, 0x14, 0x88, 0x96, 0xca, 0xf9, - 0xae, 0xca, 0x03, 0xf7, 0xae, 0xca, 0x9d, 0x00, 0x30, 0x40, 0xa9, 0xcc, 0xa9, - 0xcc, 0x86, 0x01, 0x00, 0xca, 0xfc, 0x41, 0x7a, 0xa9, 0x14, 0x86, 0xfb, 0x5f, - 0x14, 0xfc, 0x3c, 0x95, 0x25, 0xb7, 0xfb, 0x5b, 0x14, 0x91, 0x01, 0xad, 0x14, - 0x88, 0x96, 0xca, 0xf9, 0xae, 0xca, 0x03, 0xf7, 0xae, 0xca, 0x9d, 0x00, 0x30, - 0x1c, 0xa9, 0xcc, 0xa9, 0xcc, 0x86, 0x01, 0x00, 0xca, 0xfc, 0x41, 0x7a, 0xa9, - 0x14, 0x86, 0xfb, 0x5f, 0x14, 0xfc, 0x3c, 0x95, 0x25, 0xc4, 0x88, 0x12, 0xc6, - 0x89, 0x12, 0x3c, 0xc4, 0x96, 0x12, 0xdc, 0x4d, 0x80, 0x12, 0xce, 0xab, 0xa9, - 0xcc, 0x34, 0xf7, 0xae, 0xcc, 0x05, 0xae, 0xcc, 0x89, 0x12, 0x3c, 0xb2, 0x10, - 0x00, 0x00, 0xc6, 0xb2, 0x10, 0x00, 0x97, 0x55, 0x12, 0x30, 0x61, 0xb2, 0x10, - 0x00, 0x97, 0x55, 0x12, 0x30, 0x84, 0x82, 0x00, 0x0a, 0xdd, 0x44, 0x30, 0x05, - 0x00, 0x3c, 0x90, 0x01, 0x3c, 0xb2, 0x10, 0x00, 0x97, 0x00, 0x12, 0x97, 0x01, - 0x03, 0x58, 0x02, 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x5e, 0xef, - 0x01, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xb7, 0xfc, 0x3e, 0x14, 0x91, 0x01, 0xad, 0x14, 0x88, 0x96, 0xca, 0xf9, 0xae, - 0xca, 0x03, 0xf7, 0xae, 0xca, 0x9d, 0x00, 0x34, 0xe0, 0xa9, 0xcc, 0xa9, 0xcc, - 0x86, 0x01, 0x00, 0xca, 0xfc, 0x41, 0x7a, 0xa9, 0x14, 0x86, 0xfc, 0x56, 0x14, - 0xfc, 0x3c, 0x95, 0x25, 0xb7, 0xfc, 0x3e, 0x14, 0x91, 0x01, 0xad, 0x14, 0x88, - 0x96, 0xca, 0xf9, 0xae, 0xca, 0x03, 0xf7, 0xae, 0xca, 0x9d, 0x00, 0x30, 0x40, - 0xa9, 0xcc, 0xa9, 0xcc, 0x86, 0x01, 0x00, 0xca, 0xfc, 0x41, 0x7a, 0xa9, 0x14, - 0x86, 0xfc, 0x56, 0x14, 0xfc, 0x3c, 0x95, 0x25, 0xb7, 0xfc, 0x3e, 0x14, 0x91, - 0x01, 0xad, 0x14, 0x88, 0x96, 0xca, 0xf9, 0xae, 0xca, 0x03, 0xf7, 0xae, 0xca, - 0x9d, 0x00, 0x30, 0x1c, 0xa9, 0xcc, 0xa9, 0xcc, 0x86, 0x01, 0x00, 0xca, 0xfc, - 0x41, 0x7a, 0xa9, 0x14, 0x86, 0xfc, 0x56, 0x14, 0xfc, 0x3c, 0x95, 0x25, 0xc4, - 0x88, 0x12, 0xc6, 0x89, 0x12, 0x3c, 0xc4, 0x96, 0x12, 0xdc, 0x4d, 0x80, 0x12, - 0xce, 0xab, 0xa9, 0xcc, 0x35, 0xd7, 0xae, 0xcc, 0x05, 0xae, 0xcc, 0x89, 0x12, - 0x3c, 0xb2, 0x12, 0x00, 0x00, 0xc6, 0xb2, 0x12, 0x00, 0x97, 0x55, 0x12, 0x30, - 0x51, 0xb2, 0x12, 0x00, 0x97, 0x55, 0x12, 0x30, 0x74, 0x82, 0x00, 0x0a, 0xdd, - 0x48, 0x30, 0x09, 0x82, 0x00, 0x0a, 0xdc, 0x00, 0x3c, 0x90, 0x01, 0x3c, 0xb2, - 0x12, 0x00, 0x97, 0x00, 0x12, 0x97, 0x01, 0x03, 0x44, 0x02, 0xa8, 0x0f, 0x80, - 0xb7, 0xfd, 0x22, 0x14, 0x91, 0x01, 0xad, 0x14, 0x88, 0x96, 0xca, 0xf9, 0xae, - 0xca, 0x03, 0xf7, 0xae, 0xca, 0x9d, 0x00, 0x35, 0xb0, 0xa9, 0xcc, 0xa9, 0xcc, - 0x86, 0x01, 0x00, 0xca, 0xfc, 0x41, 0x7a, 0xa9, 0x14, 0x86, 0xfd, 0x26, 0x14, - 0xfc, 0x3c, 0x95, 0x25, 0xb7, 0xfd, 0x22, 0x14, 0x91, 0x01, 0xad, 0x14, 0x88, - 0x96, 0xca, 0xf9, 0xae, 0xca, 0x03, 0xf7, 0xae, 0xca, 0x9d, 0x00, 0x30, 0x40, - 0xa9, 0xcc, 0xa9, 0xcc, 0x86, 0x01, 0x00, 0xca, 0xfc, 0x41, 0x7a, 0xa9, 0x14, - 0x86, 0xfd, 0x26, 0x14, 0xfc, 0x3c, 0x95, 0x25, 0xb7, 0xfd, 0x22, 0x14, 0x91, - 0x01, 0xad, 0x14, 0x88, 0x96, 0xca, 0xf9, 0xae, 0xca, 0x03, 0xf7, 0xae, 0xca, - 0x9d, 0x00, 0x30, 0x1c, 0xa9, 0xcc, 0xa9, 0xcc, 0x86, 0x01, 0x00, 0xca, 0xfc, - 0x41, 0x7a, 0xa9, 0x14, 0x86, 0xfd, 0x26, 0x14, 0xfc, 0x3c, 0x95, 0x25, 0xc4, - 0x88, 0x12, 0xc6, 0x89, 0x12, 0x3c, 0xc4, 0x96, 0x12, 0xdc, 0x4d, 0x80, 0x12, - 0xce, 0xab, 0xa9, 0xcc, 0x36, 0xa7, 0xae, 0xcc, 0x05, 0xae, 0xcc, 0x89, 0x12, - 0x3c, 0xac, 0x04, 0xcc, 0xac, 0x06, 0xca, 0xb0, 0xff, 0x7f, 0x82, 0x00, 0x0c, - 0xdc, 0xb0, 0x04, 0x01, 0x82, 0x02, 0x0c, 0xdc, 0x90, 0x05, 0x82, 0x00, 0x0b, - 0xdc, 0x37, 0x30, 0x82, 0x00, 0x0b, 0xdd, 0x37, 0x4c, 0x00, 0xaa, 0xc8, 0x62, - 0xaa, 0xc8, 0x62, 0xaa, 0xc8, 0x62, 0xac, 0x04, 0xcc, 0xac, 0x06, 0xca, 0xb0, - 0xff, 0x7f, 0x82, 0x00, 0x0c, 0xdc, 0xb0, 0x04, 0x01, 0x82, 0x02, 0x0c, 0xdc, - 0x90, 0x05, 0x82, 0x00, 0x0b, 0xdc, 0x37, 0x25, 0x82, 0x00, 0x0b, 0xdd, 0x37, - 0x4a,0x3c -}; - -/* This is the main firmware which implements the FDDI PHY transactions and talks - * to the MAC chipsets. - */ -const unsigned short main_firmware_dev_addr = 0xf000; /* Offset as seen by device. */ -const unsigned short main_firmware_size = 0x1000; /* Size of main firmware. */ - -static unsigned char main_firmware[] __initdata = { - 0x00, 0xaa, 0xc8, 0x62, 0xab, 0x00, 0xab, 0xbe, 0x8b, 0xba, 0x97, 0x3c, 0xd0, - 0x90, 0x01, 0x8b, 0xd4, 0x8b, 0xf4, 0xb7, 0x02, 0x03, 0xe2, 0xb7, 0x02, 0x03, - 0xf2, 0x97, 0x14, 0xc0, 0xb2, 0x20, 0x3c, 0xb3, 0x01, 0x52, 0x00, 0xf3, 0xa7, - 0x01, 0x92, 0x01, 0x82, 0x90, 0x0c, 0xe3, 0xb0, 0xcc, 0xcc, 0xf6, 0xe6, 0xb6, - 0x01, 0x5c, 0x08, 0xf1, 0xb0, 0x88, 0xcc, 0xe3, 0xb0, 0x21, 0x52, 0xe3, 0x00, - 0x05, 0xe3, 0x63, 0x8f, 0x08, 0x8d, 0x00, 0x07, 0xe4, 0x04, 0xe6, 0xb3, 0xff, - 0x80, 0xf1, 0x00, 0xaa, 0xca, 0x64, 0xb7, 0x3e, 0x80, 0xb6, 0x91, 0x16, 0xf1, - 0xa8, 0xb6, 0x82, 0x80, 0xb7, 0xdb, 0xaa, 0xca, 0x69, 0xb0, 0x3f, 0xff, 0xf1, - 0xf0, 0xb2, 0x20, 0x3c, 0xb7, 0x01, 0xc0, 0xc4, 0xb6, 0xff, 0xfe, 0xa8, 0x27, - 0x90, 0xf7, 0x92, 0xba, 0x17, 0x20, 0x1f, 0x00, 0x8b, 0xd2, 0xab, 0xaa, 0x05, - 0xf3, 0x9c, 0x00, 0x55, 0xb6, 0x01, 0x04, 0x10, 0x9a, 0x04, 0xab, 0xbe, 0x83, - 0x01, 0xff, 0x16, 0xab, 0x96, 0xc8, 0x12, 0x83, 0x02, 0xff, 0x16, 0xab, 0x90, - 0x01, 0xb6, 0x01, 0x04, 0x11, 0x04, 0xb6, 0xff, 0x02, 0xab, 0x92, 0xce, 0xb3, - 0x20, 0x30, 0x30, 0x26, 0xb3, 0x28, 0x30, 0x96, 0xbe, 0x12, 0x30, 0x1e, 0xb2, - 0x20, 0x2e, 0x30, 0x06, 0xb6, 0xff, 0x00, 0x89, 0x94, 0x2b, 0x00, 0xc6, 0xc4, - 0x99, 0x01, 0x9d, 0x00, 0x4a, 0x90, 0x40, 0xc6, 0xa8, 0xe2, 0xb9, 0xfd, 0xff, - 0xab, 0xe2, 0x3c, 0xd4, 0x9d, 0x11, 0x3c, 0xc7, 0x0e, 0x90, 0x01, 0x06, 0xd6, - 0x0b, 0x09, 0x8f, 0x0e, 0x3c, 0xb6, 0xff, 0x8e, 0xae, 0xb6, 0xff, 0x8c, 0xab, - 0x0e, 0x96, 0xd0, 0x18, 0xb6, 0x01, 0x20, 0x11, 0x26, 0x92, 0xaa, 0x18, 0x13, - 0x25, 0xb6, 0xff, 0x8e, 0xa8, 0xda, 0x8b, 0xab, 0xdb, 0xe7, 0xe7, 0xb8, 0xff, - 0x90, 0xab, 0xb4, 0xab, 0xce, 0xf0, 0xab, 0xac, 0x8f, 0xfb, 0x05, 0xbd, 0x7f, - 0xfe, 0x94, 0x40, 0xa8, 0xac, 0xbd, 0x3f, 0xff, 0xb4, 0x01, 0x8a, 0x04, 0xab, - 0xb2, 0x05, 0xe7, 0xe7, 0xab, 0xce, 0xf0, 0xab, 0xae, 0xf4, 0xab, 0xb0, 0xb3, - 0xff, 0x82, 0xf0, 0xe7, 0x07, 0x28, 0x92, 0xba, 0x16, 0x24, 0x92, 0xaa, 0xa8, - 0xb0, 0xbd, 0x7f, 0xff, 0xb4, 0x01, 0x9d, 0xbd, 0x07, 0xff, 0xb4, 0x01, 0xf0, - 0x9d, 0x08, 0xb4, 0x02, 0xbf, 0xb4, 0x01, 0x06, 0xa8, 0xb2, 0xad, 0xb4, 0xab, - 0x92, 0xaa, 0x90, 0x08, 0xdd, 0x96, 0xd0, 0x08, 0x95, 0x6f, 0x90, 0x08, 0x2d, - 0x97, 0xfb, 0xd2, 0xb3, 0x10, 0x5e, 0xb2, 0x12, 0x0a, 0x00, 0xd5, 0x8b, 0xb6, - 0x00, 0xc5, 0x96, 0xbe, 0x10, 0x5a, 0x8b, 0xb7, 0xb3, 0x18, 0x5e, 0xb2, 0x1a, - 0x0a, 0x00, 0xd5, 0x8b, 0xb8, 0x00, 0xc5, 0xc5, 0x88, 0xb8, 0xd5, 0xb2, 0x12, - 0x0a, 0xb3, 0x10, 0x5e, 0x88, 0xb7, 0xc5, 0x88, 0xb6, 0xd5, 0x92, 0xaa, 0x57, - 0x90, 0x06, 0x2d, 0xb3, 0x20, 0x06, 0x00, 0xd5, 0xd5, 0x4d, 0x90, 0x07, 0x2d, - 0xb3, 0x28, 0x06, 0x6a, 0x90, 0x05, 0x42, 0x90, 0x09, 0x2d, 0x1e, 0xa5, 0xff, - 0x8c, 0xff, 0x8e, 0xab, 0x3c, 0xab, 0xca, 0xb9, 0x07, 0xff, 0xbd, 0x03, 0xff, - 0x41, 0x5a, 0x92, 0xcb, 0x97, 0x7c, 0xc9, 0xe7, 0x11, 0x43, 0x10, 0x46, 0x3c, - 0x10, 0x47, 0xad, 0xc8, 0xa9, 0xad, 0xc8, 0xa8, 0x50, 0xab, 0xcc, 0xe4, 0x05, - 0xe6, 0x04, 0x49, 0x1e, 0x17, 0x42, 0x94, 0x59, 0x1f, 0x16, 0x67, 0x57, 0x92, - 0xc9, 0xbd, 0x03, 0xff, 0x6d, 0xbd, 0x02, 0xdf, 0x94, 0x29, 0xe7, 0x12, 0x51, - 0x11, 0x48, 0xe7, 0x11, 0x0b, 0x10, 0x0c, 0x0e, 0xc7, 0x53, 0xbd, 0x03, 0xbe, - 0x53, 0xb8, 0xfa, 0x00, 0xb8, 0x14, 0x00, 0x10, 0x41, 0x46, 0x96, 0xc8, 0x17, - 0xb8, 0x00, 0x80, 0x96, 0xaa, 0x08, 0x3c, 0xc7, 0xb8, 0x2e, 0x40, 0x68, 0x10, - 0x55, 0x96, 0xc8, 0x14, 0x4d, 0xbd, 0x02, 0xe0, 0xb0, 0x34, 0x00, 0xbc, 0x02, - 0xe0, 0xb0, 0x30, 0x00, 0x7b, 0xb8, 0xfd, 0xc9, 0x4a, 0x96, 0xc8, 0x17, 0x43, - 0x99, 0x7f, 0x6b, 0xb8, 0x1c, 0x80, 0xe7, 0x3c, 0xa8, 0xae, 0x96, 0xc9, 0x17, - 0x41, 0x3c, 0x2b, 0xab, 0xcc, 0xc4, 0x96, 0xaa, 0x10, 0x41, 0xe4, 0xae, 0xca, - 0x88, 0xc9, 0xe7, 0x3b, 0x99, 0x0f, 0x96, 0xca, 0xf8, 0x3c, 0xcc, 0x09, 0x1c, - 0x0d, 0x16, 0x38, 0x37, 0x4d, 0x63, 0x6e, 0xa1, 0xae, 0xff, 0xbe, 0xab, 0x2f, - 0x17, 0x4a, 0x0f, 0xa5, 0xff, 0x8e, 0xff, 0x8a, 0xab, 0x44, 0x17, 0x41, 0x5d, - 0x1f, 0x2a, 0xab, 0xcc, 0x99, 0x0f, 0x9d, 0x0b, 0x4a, 0x9c, 0x0b, 0xb6, 0xff, - 0x8a, 0xa8, 0xb6, 0xff, 0x8e, 0xab, 0xa8, 0xcc, 0x82, 0x02, 0xb0, 0xdc, 0xb6, - 0xff, 0xfc, 0xab, 0xb4, 0xfe, 0xbd, 0x2a, 0xae, 0xb2, 0x92, 0xaa, 0x15, 0x96, - 0xc9, 0x0e, 0x96, 0xb0, 0x10, 0x0d, 0xaf, 0xc8, 0x96, 0xb3, 0x16, 0x41, 0x76, - 0xa8, 0xb2, 0x2c, 0x3f, 0xc8, 0x92, 0xc9, 0x17, 0x4c, 0x16, 0x43, 0x96, 0xaa, - 0x1d, 0x1e, 0xab, 0xb2, 0x95, 0x28, 0xe7, 0xe7, 0x92, 0xaa, 0xaf, 0xc8, 0x3c, - 0x2a, 0x92, 0xc9, 0x1f, 0x16, 0x0f, 0xa0, 0xc8, 0xb2, 0xf8, 0x95, 0x3b, 0x88, - 0xaf, 0x97, 0x7c, 0xc9, 0xe7, 0xad, 0xc8, 0xaa, 0xad, 0xc8, 0xa8, 0x9c, 0x00, - 0x95, 0x4b, 0x94, 0x4a, 0x96, 0xb1, 0x16, 0x08, 0x2b, 0x92, 0xaa, 0xab, 0xce, - 0x10, 0x41, 0xf4, 0xd4, 0x93, 0xb6, 0xf6, 0x88, 0xaf, 0x96, 0xb1, 0x16, 0x4a, - 0x97, 0x7c, 0xc9, 0xe7, 0xad, 0xc8, 0xa8, 0x10, 0x99, 0xff, 0x8d, 0xb8, 0x00, - 0xe6, 0x88, 0xb1, 0x3b, 0x99, 0x03, 0xcc, 0x04, 0x07, 0x0a, 0x0d, 0xf4, 0xfc, - 0x4e, 0x50, 0xf4, 0xfd, 0x4a, 0x4c, 0xf4, 0xfd, 0x46, 0x6a, 0xf4, 0xf9, 0x9d, - 0x00, 0x43, 0x96, 0xca, 0x0b, 0x88, 0xb1, 0x96, 0xca, 0xf9, 0x9c, 0x00, 0x4c, - 0x88, 0xae, 0x96, 0xc8, 0x17, 0xba, 0xff, 0x00, 0xa0, 0xc8, 0xb2, 0xf8, 0xb4, - 0xfe, 0x18, 0x2b, 0xab, 0xce, 0xab, 0xb6, 0x88, 0xb1, 0x9d, 0x77, 0x46, 0x92, - 0xb8, 0xac, 0xae, 0xb8, 0x4f, 0x96, 0xaf, 0x17, 0x76, 0xa8, 0xae, 0xbd, 0x77, - 0xff, 0x6f, 0x2b, 0xab, 0xcc, 0x88, 0xaf, 0xe7, 0x3b, 0x99, 0x0f, 0x96, 0xaa, - 0x10, 0x96, 0xc8, 0x0c, 0x02, 0xcc, 0x4f, 0x1f, 0x20, 0x22, 0x24, 0x28, 0x2a, - 0x2d, 0x2f, 0x31, 0x33, 0x36, 0x3a, 0x3c, 0x3e, 0x40, 0x77, 0x47, 0x48, 0x4a, - 0x4c, 0x4e, 0x50, 0x53, 0x55, 0x59, 0x5b, 0x5e, 0x62, 0x64, 0x66, 0x68, 0xe4, - 0x4d, 0xf4, 0xe5, 0x4a, 0xf4, 0xf8, 0x47, 0xf4, 0xf8, 0x00, 0xf7, 0x42, 0xf4, - 0xeb, 0x58, 0xe4, 0x8f, 0xeb, 0x54, 0xf4, 0xfe, 0x5b, 0xf4, 0xfe, 0x49, 0xf4, - 0xff, 0x55, 0xe4, 0x8f, 0xff, 0x51, 0xf4, 0xff, 0xa8, 0xce, 0x4c, 0xf4, 0xf9, - 0x4c, 0xf4, 0xfa, 0x49, 0xf4, 0xfb, 0x46, 0xf4, 0x23, 0x43, 0xac, 0xb6, 0xce, - 0xf6, 0x94, 0x36, 0xc4, 0x4b, 0xd4, 0xc5, 0x48, 0xd4, 0xd8, 0x45, 0xd4, 0xd8, - 0x4c, 0xd4, 0xcb, 0x5a, 0xc4, 0x8f, 0xcb, 0x56, 0xd4, 0xde, 0x5d, 0xd4, 0xde, - 0x88, 0xc9, 0x58, 0xd4, 0xdf, 0x55, 0xc4, 0x8f, 0xdf, 0x51, 0xd4, 0xdf, 0xa8, - 0xce, 0x4c, 0xd4, 0xd9, 0x4c, 0xd4, 0xda, 0x49, 0xd4, 0xdb, 0x46, 0xd4, 0x23, - 0x43, 0xac, 0xb6, 0xce, 0xd6, 0xb4, 0xfd, 0x5c, 0xae, 0xca, 0xc4, 0x99, 0x0f, - 0xae, 0xca, 0x82, 0x00, 0xca, 0xfc, 0x3c, 0x14, 0x45, 0xe7, 0xaa, 0xca, 0x63, - 0x3c, 0xc7, 0xaa, 0xca, 0x63, 0x3c, 0xbd, 0x03, 0xff, 0x5e, 0x92, 0xc9, 0xb3, - 0x12, 0x10, 0x10, 0xb3, 0x1a, 0x10, 0x96, 0xc8, 0x17, 0x94, 0x72, 0xa8, 0xae, - 0x17, 0x4c, 0x16, 0x94, 0x5e, 0x15, 0x94, 0x3f, 0x9c, 0x80, 0x94, 0x1f, 0x9d, - 0x00, 0xb4, 0xfd, 0x1f, 0xa8, 0xce, 0xb8, 0xff, 0x2e, 0xab, 0xcc, 0x9a, 0x28, - 0xab, 0xca, 0xb8, 0xfe, 0xf2, 0xab, 0xce, 0x00, 0xe1, 0x62, 0x00, 0xd6, 0x97, - 0x38, 0xce, 0xd6, 0x7c, 0xa8, 0xce, 0xb8, 0xfe, 0x80, 0xab, 0xcc, 0x9a, 0x0c, - 0xab, 0xca, 0x22, 0x97, 0xb0, 0xcc, 0x97, 0xfe, 0xca, 0x22, 0x74, 0x00, 0x96, - 0xcc, 0x14, 0x05, 0xe1, 0x66, 0x3c, 0x04, 0x97, 0x7c, 0xc9, 0xe7, 0xab, 0xcc, - 0x91, 0x04, 0xe2, 0xab, 0xb8, 0xe4, 0xab, 0xb6, 0x97, 0x04, 0xce, 0x00, 0xf1, - 0x92, 0xb9, 0xc2, 0xd6, 0xaa, 0xca, 0x64, 0x4b, 0xac, 0xce, 0xcc, 0x97, 0x04, - 0xce, 0x99, 0x1f, 0xd6, 0x18, 0x10, 0x5c, 0x62, 0x3b, 0x99, 0xf0, 0x8b, 0xb6, - 0x2a, 0x96, 0xc9, 0x10, 0x96, 0xb6, 0x08, 0xac, 0xce, 0xcc, 0x97, 0x1a, 0xce, - 0x11, 0x41, 0x62, 0xd6, 0xf3, 0x88, 0xb6, 0xd6, 0x19, 0xb4, 0xfc, 0xa2, 0x8d, - 0xab, 0xb2, 0xc0, 0x3b, 0x3c, 0xe7, 0x07, 0x45, 0x82, 0x06, 0xb0, 0xfd, 0x3c, - 0xe7, 0xf4, 0x07, 0x2c, 0xb6, 0xff, 0x86, 0xa8, 0xb9, 0x03, 0xff, 0xe7, 0xe7, - 0xe7, 0xba, 0x60, 0x00, 0xab, 0xce, 0x29, 0x3b, 0x3b, 0x97, 0x80, 0xc8, 0xf1, - 0xe0, 0x62, 0xb6, 0xff, 0x86, 0xa9, 0x3c, 0x20, 0x21, 0x27, 0x9c, 0xf6, 0x65, - 0x92, 0xba, 0x9d, 0xef, 0x4f, 0x93, 0xbd, 0x9d, 0x2f, 0x9d, 0x3f, 0x42, 0x9a, - 0xf0, 0xd3, 0x20, 0x21, 0xd5, 0x94, 0x69, 0xac, 0xbc, 0xce, 0x99, 0x0f, 0xcc, - 0x44, 0x2a, 0x38, 0x33, 0x2e, 0x1c, 0x3e, 0x09, 0x12, 0x0f, 0x10, 0x0d, 0x30, - 0x37, 0x36, 0x35, 0x0f, 0x1c, 0xa1, 0xce, 0xff, 0xbe, 0xab, 0x2f, 0x0d, 0x41, - 0x1d, 0x0e, 0x96, 0xc8, 0x11, 0x41, 0x3c, 0x90, 0xf0, 0x96, 0xaa, 0x14, 0x4a, - 0x96, 0xaa, 0x0b, 0x3c, 0x90, 0xf1, 0x20, 0x21, 0x8e, 0xbb, 0x55, 0x88, 0xbb, - 0xd5, 0x51, 0x88, 0xbb, 0xd6, 0x4d, 0xd4, 0x4b, 0x1e, 0x14, 0x3f, 0xc8, 0x1c, - 0x90, 0xfc, 0x43, 0x29, 0x92, 0xba, 0x5b, 0x1b, 0x0c, 0x90, 0x0a, 0xb6, 0xff, - 0x8e, 0xae, 0xb6, 0xff, 0x88, 0xab, 0xa1, 0xbc, 0xff, 0xb8, 0xab, 0x2e, 0x1c, - 0xa5, 0xff, 0x88, 0xff, 0x8e, 0xab, 0x90, 0xf5, 0xb6, 0x01, 0x20, 0x10, 0x41, - 0x65, 0xb6, 0x01, 0x26, 0x8b, 0x3c, 0xb6, 0x01, 0x20, 0x11, 0x41, 0x65, 0xb6, - 0x01, 0x24, 0x88, 0x3c, 0x15, 0x45, 0x82, 0x06, 0xb0, 0xfd, 0x3c, 0x0c, 0x90, - 0x80, 0x20, 0x21, 0x9c, 0xff, 0x42, 0x26, 0x69, 0x1c, 0x29, 0x20, 0x21, 0xc0, - 0x63, 0x3c, 0x40, 0x40, 0x40, 0x40, 0x3c, 0x40, 0x40, 0x40, 0x40, 0x3c, 0x3c, - 0x3c, 0x91, 0x00, 0xb6, 0x12, 0x08, 0x88, 0x96, 0xc8, 0x13, 0x30, 0x55, 0x96, - 0xc8, 0x14, 0x30, 0x41, 0x96, 0xc8, 0x16, 0x94, 0x2b, 0x96, 0xc8, 0x17, 0x5c, - 0xa8, 0xca, 0x96, 0xc8, 0x13, 0x30, 0x2b, 0x00, 0xb6, 0x12, 0x08, 0x8b, 0xb6, - 0x10, 0x5c, 0x88, 0x96, 0xc8, 0x10, 0x30, 0x5d, 0x82, 0x00, 0xca, 0xfc, 0x3c, - 0x94, 0x77, 0x00, 0xb6, 0x12, 0x0e, 0x8b, 0x82, 0x08, 0xca, 0xfa, 0x95, 0x25, - 0x00, 0xb6, 0x12, 0x16, 0x8b, 0x82, 0x08, 0xca, 0xfa, 0x95, 0x30, 0x00, 0xb6, - 0x12, 0x0a, 0x8b, 0x3c, 0xae, 0xce, 0xb6, 0x12, 0x1c, 0x88, 0x99, 0x55, 0xb6, - 0x12, 0x1c, 0x8b, 0xae, 0xce, 0x3c, 0xae, 0xce, 0xb6, 0x12, 0x28, 0x88, 0x96, - 0xc8, 0x10, 0x54, 0x96, 0xc8, 0x14, 0x50, 0x96, 0xc8, 0x12, 0x4c, 0x83, 0x00, - 0x12, 0x2a, 0x8b, 0x82, 0x08, 0xca, 0xfa, 0xae, 0xce, 0x3c, 0x99, 0xea, 0xb6, - 0x12, 0x28, 0x8b, 0x82, 0x02, 0xca, 0xfa, 0xae, 0xce, 0x3c, 0xb6, 0x10, 0x1c, - 0x88, 0xb6, 0xff, 0x0a, 0x8b, 0xb6, 0x10, 0x20, 0x88, 0x99, 0xfc, 0xb6, 0x10, - 0x20, 0x8b, 0xb6, 0x10, 0x5c, 0x88, 0x99, 0xfe, 0xb6, 0x10, 0x5c, 0x8b, 0x82, - 0x04, 0xca, 0xfa, 0x3c, 0xb3, 0xff, 0x50, 0xa2, 0x01, 0xce, 0x88, 0x9d, 0x00, - 0x66, 0x90, 0x01, 0xd6, 0xa2, 0x01, 0xce, 0x88, 0x9d, 0x00, 0x5b, 0xb6, 0xff, - 0x52, 0xa8, 0x96, 0xca, 0xfa, 0xb6, 0xff, 0x52, 0xab, 0xb6, 0xff, 0xfc, 0xa8, - 0x83, 0x00, 0xff, 0x56, 0xfd, 0xb6, 0xff, 0xfc, 0xab, 0x00, 0xd6, 0x3c, 0x00, - 0xd6, 0x95, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb4, 0xfe, - 0x93, 0x40, 0xb4, 0xfe, 0x8e, 0x40, 0xb4, 0xfe, 0x8c, 0x40, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0xf9, 0x01, - 0x12, 0x30, 0x1f, 0x8b, 0x11, 0x30, 0x1b, 0x8b, 0x0d, 0x30, 0x17, 0x8b, 0x0c, - 0x82, 0x00, 0x11, 0xdc, 0x4a, 0x30, 0x0e, 0xad, 0x0c, 0x8b, 0xa9, 0x0c, 0x8a, - 0x11, 0x69, 0x83, 0x00, 0xf9, 0x00, 0xab, 0x3c, 0xb6, 0xf9, 0x00, 0xa8, 0x96, - 0xc8, 0x17, 0x41, 0x68, 0xad, 0x12, 0x88, 0xa9, 0x12, 0x3c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, 0xf5, 0x68, 0xf5, 0x5c, 0xf4, 0xf1, 0xf3, - 0x73, 0xf5, 0x42, 0xf5, 0xdc, 0xf4, 0x6e, 0xf5, 0xb1, 0xf4, 0xab, 0xf4, 0x37, - 0xf2, 0xb2, 0xf1, 0xb7, 0xf2, 0xe2, 0xf0, 0xeb, 0xf0, 0x0a, 0xf0, 0x0a, 0xf0, - 0xa7, 0xf1, 0xa4, 0xf1, 0x9d, 0xf1, 0x93, 0xf1, 0x5c, 0xf1, 0x00, 0x00, 0x00, - 0xf0 -}; - -/* This is the FDDI station management firmware. */ -const unsigned short smt_firmware_dev_addr = 0x4000; /* Offset as seen by device. */ -const unsigned short smt_firmware_size = 0x72b0; /* Size of SMT firmware. */ - -static unsigned char smt_firmware[] __initdata = { - 0x94, 0xaa, 0x00, 0x00, 0x94, 0x5d, 0x00, 0x00, 0x5d, 0x00, 0x00, 0x00, 0x94, 0x2c, - 0x00, 0x00, 0xb4, 0x5d, 0xfa, 0x00, 0x94, 0xc4, 0x00, 0x00, 0x94, 0xc8, 0x00, 0x00, - 0x94, 0xcc, 0x00, 0x00, 0xb4, 0x01, 0xbc, 0x00, 0x00, 0x00, 0xb2, 0xfe, 0x20, 0xc4, - 0x96, 0xc8, 0x17, 0x41, 0x3c, 0xb5, 0x56, 0xa7, 0xb2, 0xfe, 0x20, 0x00, 0xe6, 0xb4, - 0x04, 0x1a, 0x83, 0x00, 0xfe, 0x94, 0xab, 0xb2, 0xfe, 0x20, 0xe4, 0x96, 0xc8, 0x17, - 0x41, 0x45, 0x99, 0x3f, 0x9c, 0x03, 0x46, 0x83, 0x00, 0xfe, 0x20, 0xab, 0x3c, 0x82, - 0x02, 0xcc, 0xf8, 0xb3, 0xfe, 0x90, 0xb5, 0x3b, 0x12, 0x83, 0xe0, 0xfe, 0x94, 0xab, - 0x75, 0xac, 0x74, 0xce, 0x92, 0x00, 0xb5, 0x35, 0xdf, 0x92, 0x0e, 0xb6, 0x10, 0x00, - 0x88, 0x99, 0xfe, 0xb6, 0x10, 0x00, 0x8b, 0xb5, 0x35, 0xc3, 0x90, 0x01, 0xb5, 0x35, - 0xd8, 0xb5, 0x35, 0x1e, 0xb6, 0x10, 0x00, 0x88, 0x9a, 0x01, 0xb6, 0x10, 0x00, 0x8b, - 0x89, 0x7d, 0xac, 0x6e, 0x02, 0xac, 0x70, 0x04, 0xb7, 0x04, 0x00, 0x06, 0xac, 0x74, - 0xcc, 0x82, 0x34, 0xcc, 0xf8, 0x00, 0xb5, 0x2c, 0xf0, 0x90, 0x01, 0xb5, 0x34, 0x80, - 0xb5, 0x34, 0xf5, 0x3c, 0xa7, 0xb8, 0x00, 0xda, 0xda, 0x00, 0xe1, 0x62, 0x8d, 0x02, - 0x80, 0x00, 0xe1, 0x62, 0xa8, 0xbe, 0x99, 0x0c, 0xc7, 0xc7, 0x04, 0x8b, 0x7e, 0xb7, - 0xb8, 0x0c, 0x72, 0xb7, 0xb8, 0x44, 0x74, 0xb7, 0xb8, 0xa4, 0x76, 0xb7, 0xba, 0x8a, - 0x78, 0xb5, 0x02, 0xf4, 0xb4, 0x03, 0x1b, 0x3c, 0xb5, 0x2e, 0xf4, 0xb4, 0x03, 0x74, - 0x40, 0x40, 0xb7, 0x00, 0x00, 0x08, 0xb2, 0x20, 0x00, 0x4c, 0x82, 0x01, 0x7e, 0xdc, - 0x3c, 0xb7, 0x00, 0x01, 0x08, 0xb2, 0x28, 0x00, 0xa2, 0x04, 0xcc, 0x88, 0xa2, 0x06, - 0xcc, 0xd9, 0x8b, 0x0a, 0x99, 0x60, 0x9c, 0x00, 0x94, 0x56, 0xa8, 0x08, 0xb5, 0x33, - 0x33, 0xab, 0xca, 0x99, 0x20, 0x9c, 0x00, 0x57, 0xb7, 0x02, 0x0a, 0x02, 0xac, 0xca, - 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa8, 0x08, 0xb5, 0x04, 0x98, 0x90, 0x20, 0x01, 0xa0, - 0xc8, 0xca, 0xf9, 0xa8, 0xca, 0x99, 0x02, 0x9c, 0x00, 0x57, 0xa8, 0x08, 0xb5, 0x02, - 0xed, 0xa2, 0x4e, 0x76, 0xa8, 0x9c, 0x03, 0x4b, 0xaf, 0xca, 0xa8, 0x08, 0x91, 0x02, - 0xb5, 0x33, 0x86, 0x3f, 0xca, 0x82, 0x00, 0xca, 0xfc, 0x50, 0xb7, 0x02, 0x09, 0x02, - 0xac, 0xca, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa8, 0x08, 0xb5, 0x04, 0x5e, 0x88, 0x0a, - 0x99, 0x10, 0x9c, 0x00, 0x55, 0xa8, 0x08, 0x32, 0x11, 0xb7, 0x05, 0x05, 0x02, 0xb7, - 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa8, 0x08, 0xb5, 0x04, 0x42, 0x90, 0x80, - 0xa2, 0x04, 0xcc, 0x8e, 0xb4, 0x02, 0xd3, 0x00, 0xb6, 0xff, 0x44, 0xa9, 0xb6, 0x12, - 0x0e, 0x8b, 0x82, 0x08, 0xca, 0xfa, 0x94, 0x6d, 0x00, 0xb6, 0xff, 0x42, 0xa9, 0xb6, - 0x12, 0x16, 0x8b, 0x82, 0x08, 0xca, 0xfa, 0x94, 0x5e, 0x00, 0xb6, 0x12, 0x0a, 0x8b, - 0x3c, 0xae, 0xce, 0xb6, 0x12, 0x1c, 0x88, 0x99, 0x55, 0xb6, 0x12, 0x1c, 0x8b, 0xae, - 0xce, 0x3c, 0xae, 0xce, 0xb6, 0x12, 0x28, 0x88, 0x96, 0xc8, 0x10, 0x54, 0x96, 0xc8, - 0x14, 0x50, 0x96, 0xc8, 0x12, 0x4c, 0x83, 0x00, 0x12, 0x2a, 0x8b, 0x82, 0x08, 0xca, - 0xfa, 0xae, 0xce, 0x3c, 0x99, 0xea, 0xb6, 0x12, 0x28, 0x8b, 0x82, 0x02, 0xca, 0xfa, - 0xae, 0xce, 0x3c, 0xb7, 0x00, 0x00, 0x0c, 0x91, 0x00, 0xb6, 0x12, 0x08, 0x88, 0x96, - 0xc8, 0x13, 0x34, 0x38, 0x96, 0xc8, 0x14, 0x34, 0x4c, 0x96, 0xc8, 0x16, 0x95, 0x66, - 0x96, 0xc8, 0x17, 0x95, 0x7a, 0xa8, 0xca, 0x96, 0xc8, 0x13, 0x34, 0x63, 0x00, 0xb6, - 0x12, 0x08, 0x8b, 0xac, 0xca, 0x0c, 0x97, 0x00, 0x09, 0xb6, 0x10, 0x5c, 0x88, 0xb6, - 0x10, 0x5e, 0xd9, 0x8b, 0x0a, 0x99, 0x01, 0x9c, 0x00, 0x94, 0x7f, 0xb6, 0x10, 0x24, - 0x88, 0x99, 0x23, 0x9c, 0x00, 0x94, 0x3f, 0xab, 0xca, 0x99, 0x20, 0x9c, 0x00, 0x46, - 0x97, 0x01, 0x09, 0x97, 0x20, 0x08, 0xa8, 0xca, 0x99, 0x02, 0x9c, 0x00, 0x47, 0x82, - 0x02, 0x09, 0xda, 0x97, 0x02, 0x08, 0xa8, 0xca, 0x99, 0x01, 0x9c, 0x00, 0x48, 0x82, - 0x04, 0x09, 0xda, 0x82, 0x01, 0x08, 0xda, 0xa8, 0xca, 0x01, 0xab, 0xca, 0xb6, 0x10, - 0x26, 0x88, 0x96, 0xca, 0xf9, 0xb6, 0x10, 0x26, 0x8b, 0x00, 0xb6, 0x10, 0x24, 0x8b, - 0xb6, 0x10, 0x20, 0x88, 0x99, 0x03, 0x9c, 0x00, 0x94, 0x2c, 0xb6, 0x10, 0x1c, 0x88, - 0x99, 0x80, 0x9c, 0x00, 0x48, 0x90, 0x40, 0xb5, 0x5b, 0x18, 0x90, 0x80, 0x41, 0x00, - 0xb6, 0xff, 0x0a, 0x8b, 0x82, 0x04, 0x0c, 0xfa, 0xb7, 0x04, 0x03, 0x02, 0xab, 0x04, - 0xb7, 0x00, 0x00, 0x06, 0x00, 0xb6, 0x10, 0x20, 0x8b, 0xb5, 0x03, 0x1c, 0x88, 0x0a, - 0x99, 0x02, 0x9c, 0x00, 0x94, 0x3f, 0xb6, 0x10, 0x28, 0x88, 0x99, 0x10, 0x9c, 0x00, - 0x5a, 0x82, 0x08, 0x09, 0xda, 0x90, 0x10, 0x01, 0xab, 0xca, 0xb6, 0x10, 0x2a, 0x88, - 0x96, 0xca, 0xf9, 0xb6, 0x10, 0x2a, 0x8b, 0x00, 0xb6, 0x10, 0x28, 0x8b, 0x40, 0xb6, - 0x10, 0x28, 0x88, 0x99, 0x40, 0x9c, 0x00, 0x53, 0xb5, 0x33, 0x96, 0x90, 0x40, 0x01, - 0xab, 0xca, 0xb6, 0x10, 0x2a, 0x88, 0x96, 0xca, 0xf9, 0xb6, 0x10, 0x2a, 0x8b, 0x88, - 0x0a, 0x99, 0x08, 0x9c, 0x00, 0x47, 0x30, 0x40, 0x00, 0xb6, 0x10, 0x38, 0x8b, 0x00, - 0xb6, 0x10, 0x5c, 0x8e, 0x82, 0x00, 0x09, 0xdc, 0x50, 0xb7, 0x04, 0x04, 0x02, 0x80, - 0x09, 0x04, 0xab, 0xb7, 0x00, 0x00, 0x06, 0x00, 0xb5, 0x02, 0xad, 0x82, 0x00, 0x0c, - 0xfc, 0xb4, 0x01, 0x40, 0xac, 0x0c, 0xca, 0xb5, 0xb3, 0x29, 0xb4, 0x01, 0x37, 0x88, - 0x09, 0x9a, 0x20, 0x8b, 0x09, 0xb6, 0x10, 0x20, 0x88, 0x99, 0xbf, 0xb6, 0x10, 0x20, - 0x8b, 0x3c, 0xb2, 0x10, 0x38, 0x00, 0xc5, 0xab, 0xca, 0x93, 0x5a, 0x96, 0xca, 0x10, - 0x30, 0x36, 0x82, 0x02, 0xce, 0xf8, 0x96, 0xca, 0x11, 0x30, 0x2d, 0x82, 0x02, 0xce, - 0xf8, 0x96, 0xca, 0x12, 0x30, 0x24, 0x82, 0x02, 0xce, 0xf8, 0x96, 0xca, 0x13, 0x30, - 0x1b, 0x82, 0x02, 0xce, 0xf8, 0x96, 0xca, 0x14, 0x30, 0x12, 0x82, 0x02, 0xce, 0xf8, - 0x96, 0xca, 0x15, 0x30, 0x09, 0x82, 0x02, 0xce, 0xf8, 0x96, 0xca, 0x16, 0x30, 0x00, - 0xf4, 0xb8, 0x00, 0x10, 0xf6, 0x3c, 0xb2, 0x28, 0x00, 0x9c, 0x00, 0xb2, 0x20, 0x00, - 0xe7, 0x99, 0x02, 0x93, 0x54, 0xa0, 0xc8, 0xce, 0xf8, 0xf4, 0x9c, 0x00, 0x4f, 0x9d, - 0xff, 0x90, 0xff, 0x02, 0xf5, 0x8f, 0xeb, 0xf5, 0xa2, 0x2a, 0xcc, 0x8e, 0x00, 0x3c, - 0x90, 0x64, 0xa2, 0x2a, 0xcc, 0x8e, 0x90, 0x01, 0x3c, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x80, - 0x01, 0x43, 0x00, 0x80, 0x00, 0x80, 0x01, 0x43, 0x00, 0x80, 0x08, 0x80, 0x01, 0x43, - 0x00, 0x80, 0x0c, 0x00, 0xb5, 0x00, 0x7d, 0xb5, 0x00, 0x80, 0xb7, 0x00, 0x01, 0x02, - 0x82, 0x00, 0x02, 0xfc, 0x4b, 0xa8, 0x02, 0xb5, 0x28, 0x06, 0xae, 0x02, 0x05, 0xae, - 0x02, 0x6f, 0xb5, 0x5a, 0x0d, 0xb5, 0x01, 0x16, 0xb5, 0x29, 0x45, 0x3c, 0x90, 0x00, - 0xb6, 0xb8, 0x00, 0xab, 0xb5, 0x01, 0x33, 0xb5, 0x59, 0xfa, 0xb5, 0x00, 0x53, 0xb5, - 0x29, 0x51, 0xb5, 0x27, 0xe1, 0xb5, 0x59, 0x84, 0x30, 0x04, 0xb5, 0xfc, 0xce, 0x3c, - 0x3c, 0x40, 0x96, 0x7a, 0xdc, 0x3c, 0x8b, 0x7a, 0xb7, 0xb8, 0x44, 0x74, 0x04, 0xaa, - 0xc8, 0x41, 0x3c, 0x82, 0x60, 0x74, 0xf8, 0x68, 0x96, 0x7b, 0xdc, 0x3c, 0x8b, 0x7b, - 0xb7, 0xb8, 0xa4, 0x76, 0x04, 0xaa, 0xc8, 0x41, 0x3c, 0x82, 0xa2, 0x76, 0xf8, 0x68, - 0x96, 0x7c, 0xdc, 0x3c, 0x8b, 0x7c, 0xb7, 0xba, 0x8a, 0x78, 0x04, 0xaa, 0xc8, 0x41, - 0x3c, 0x82, 0x16, 0x78, 0xf8, 0x68, 0xb7, 0xb8, 0x0c, 0x72, 0x3c, 0x00, 0x97, 0x00, - 0x43, 0x3c, 0x82, 0x00, 0x43, 0xdd, 0x3c, 0xa2, 0x0e, 0x72, 0x88, 0x9c, 0x00, 0x94, - 0x4f, 0x97, 0x01, 0x43, 0x56, 0x88, 0xd2, 0x96, 0xc8, 0x12, 0x94, 0x4c, 0x96, 0xc8, - 0x15, 0x94, 0x65, 0x96, 0xc8, 0x13, 0x94, 0x68, 0x96, 0xc8, 0x14, 0x94, 0x74, 0xb5, - 0x00, 0xe4, 0xbc, 0x03, 0x01, 0x94, 0x29, 0xb0, 0x44, 0x65, 0xaf, 0xc8, 0xa8, 0x44, - 0xb9, 0xff, 0x00, 0xbc, 0x01, 0x00, 0xb4, 0x0d, 0x5a, 0xbc, 0x02, 0x00, 0xb4, 0x60, - 0xbb, 0xbc, 0x04, 0x00, 0xb4, 0x3d, 0x1a, 0xbc, 0x03, 0x00, 0xb4, 0x23, 0xc1, 0xbc, - 0x05, 0x00, 0xb4, 0x06, 0x02, 0x3c, 0x97, 0x00, 0x43, 0x3c, 0xb5, 0x00, 0xaf, 0xbc, - 0x03, 0x01, 0x6a, 0x67, 0xb5, 0xfb, 0x65, 0x97, 0xfb, 0xd2, 0x00, 0xb6, 0x12, 0x0a, - 0x8e, 0xab, 0xca, 0x00, 0xb6, 0x10, 0x5e, 0x8e, 0xb6, 0x10, 0x5e, 0x8e, 0xae, 0xca, - 0xb6, 0x12, 0x0a, 0x8e, 0x95, 0x6f, 0x97, 0xdf, 0xd2, 0xb5, 0xfb, 0x38, 0x95, 0x77, - 0xb5, 0xfb, 0x37, 0x97, 0xf7, 0xd2, 0x00, 0xb6, 0x20, 0x06, 0x8e, 0xb6, 0x20, 0x06, - 0x8e, 0x95, 0x72, 0xb5, 0xfb, 0x2a, 0x97, 0xef, 0xd2, 0x00, 0xb6, 0x28, 0x06, 0x8e, - 0xb6, 0x28, 0x06, 0x8e, 0x95, 0x83, 0x00, 0xab, 0x4e, 0xab, 0x50, 0xb1, 0x01, 0xf4, - 0xb2, 0xba, 0xb6, 0x00, 0xe6, 0xa2, 0x02, 0xcc, 0xab, 0xa2, 0x04, 0xcc, 0xab, 0xa2, - 0x06, 0xcc, 0xab, 0xa2, 0x08, 0xcc, 0xab, 0xae, 0xca, 0xaa, 0xc8, 0x41, 0x3c, 0xae, - 0xca, 0x82, 0x0a, 0xcc, 0xf8, 0x7d, 0xb1, 0x01, 0xf4, 0xb2, 0xba, 0xb6, 0x00, 0xa1, - 0x08, 0xb8, 0x00, 0xfc, 0x41, 0x51, 0xe6, 0xa2, 0x02, 0xcc, 0xab, 0xa2, 0x04, 0xcc, - 0xab, 0xa2, 0x06, 0xcc, 0xab, 0xa2, 0x08, 0xcc, 0xab, 0xae, 0xca, 0xaa, 0xc8, 0x41, - 0x3c, 0xae, 0xca, 0x82, 0x0a, 0xcc, 0xf8, 0x95, 0x24, 0xa8, 0x4e, 0x96, 0x50, 0xfc, - 0x42, 0x00, 0x3c, 0x90, 0x01, 0x63, 0x34, 0x0b, 0x9c, 0x00, 0x44, 0xb0, 0x03, 0x01, - 0x3c, 0xa8, 0xc4, 0xb6, 0xff, 0x38, 0xab, 0xb2, 0xba, 0xb6, 0xa0, 0x4e, 0xcc, 0xf8, - 0xe4, 0xab, 0x44, 0xb6, 0xff, 0x32, 0xab, 0xa2, 0x02, 0xcc, 0xa8, 0xab, 0x46, 0xb6, - 0xff, 0x34, 0xab, 0xa2, 0x04, 0xcc, 0xa8, 0xab, 0x48, 0xb6, 0xff, 0x36, 0xab, 0xa2, - 0x06, 0xcc, 0xa8, 0xab, 0x4a, 0xa2, 0x08, 0xcc, 0xa8, 0xab, 0x4c, 0xa8, 0x4e, 0xb6, - 0xff, 0x30, 0xab, 0xbc, 0x13, 0x7e, 0x47, 0xb8, 0x00, 0x0a, 0xab, 0x4e, 0x00, 0x3c, - 0xb7, 0x00, 0x00, 0x4e, 0x66, 0x83, 0x00, 0xb8, 0x00, 0xab, 0xac, 0xcc, 0x28, 0xac, - 0xca, 0x2a, 0xab, 0xca, 0xa8, 0x50, 0xb8, 0x00, 0x0a, 0x96, 0x4e, 0xfc, 0x94, 0x2e, - 0xb2, 0xba, 0xb6, 0xa0, 0x50, 0xcc, 0xf8, 0xa8, 0x02, 0xe6, 0xa8, 0xca, 0xa2, 0x02, - 0xcc, 0xab, 0xa8, 0x04, 0xa2, 0x04, 0xcc, 0xab, 0xa8, 0x06, 0xa2, 0x06, 0xcc, 0xab, - 0xa8, 0x50, 0xb8, 0x00, 0x0a, 0xbc, 0x13, 0x7e, 0x00, 0xab, 0x50, 0xac, 0x28, 0xcc, - 0xac, 0x2a, 0xca, 0x3c, 0xb6, 0xff, 0x06, 0xa9, 0x6b, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x5c, 0xc5, 0x2f, 0x14, 0x2b, 0x02, 0x45, 0x00, 0x0e, 0x00, - 0x06, 0x00, 0x06, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, 0x05, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x50, 0x00, - 0x00, 0x00, 0x20, 0x03, 0x00, 0x00, 0x40, 0x1f, 0x00, 0x00, 0x80, 0x38, 0x01, 0x00, - 0x00, 0x35, 0x0c, 0x00, 0x00, 0x12, 0x7a, 0x00, 0x00, 0xb4, 0xc4, 0x04, 0x00, 0x08, - 0xaf, 0x2f, 0x0a, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0xe8, 0x03, 0x00, 0x00, - 0x10, 0x27, 0x00, 0x00, 0xa0, 0x86, 0x01, 0x00, 0x40, 0x42, 0x0f, 0x00, 0x80, 0x96, - 0x98, 0x00, 0x00, 0xe1, 0xf5, 0x05, 0x00, 0xca, 0x9a, 0x3b, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xaf, 0x02, 0xb7, 0x00, 0x00, 0x02, 0x82, 0x0b, 0x02, 0xfc, - 0x94, 0x20, 0xae, 0xca, 0xa2, 0x02, 0xcc, 0xfc, 0x53, 0xa2, 0x02, 0xcc, 0xfd, 0x41, - 0x53, 0xae, 0xca, 0xa9, 0x02, 0xa9, 0xcc, 0xa9, 0xcc, 0xa9, 0xcc, 0xa9, 0xcc, 0x7f, - 0xae, 0xca, 0xfc, 0x6e, 0xfd, 0x70, 0xa8, 0x02, 0x3f, 0x02, 0x3c, 0x90, 0x00, 0xa2, - 0x76, 0xce, 0xab, 0x90, 0x00, 0xb5, 0x32, 0x51, 0xb7, 0x00, 0x00, 0x02, 0xb7, 0x00, - 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0x00, 0xac, 0xce, 0xcc, 0x82, 0x70, 0xcc, 0xf8, - 0xb4, 0x26, 0xc8, 0xb7, 0x00, 0x00, 0x02, 0xac, 0xce, 0xcc, 0x82, 0x7a, 0xcc, 0xf8, - 0x82, 0x05, 0x02, 0xfc, 0x55, 0x00, 0xe6, 0xa2, 0x02, 0xcc, 0xab, 0xa2, 0x04, 0xcc, - 0xab, 0xa2, 0x06, 0xcc, 0xab, 0xa9, 0x02, 0x82, 0x08, 0xcc, 0xf8, 0x79, 0x00, 0xa2, - 0x78, 0xce, 0x8b, 0x90, 0x01, 0xa2, 0x76, 0xce, 0xab, 0xa2, 0x10, 0xce, 0x88, 0xe7, - 0xb8, 0x46, 0x00, 0xad, 0xc8, 0xa8, 0xa2, 0x72, 0xce, 0xab, 0xb5, 0x31, 0x9c, 0x90, - 0x01, 0xb5, 0x31, 0xf3, 0xb7, 0x5e, 0x10, 0x02, 0xb7, 0x00, 0x5f, 0x04, 0xb7, 0x05, - 0x00, 0x06, 0xac, 0xce, 0xcc, 0x82, 0x70, 0xcc, 0xf8, 0xa2, 0x22, 0xce, 0x88, 0xb4, - 0x26, 0x67, 0xb5, 0x31, 0xb1, 0xab, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xa2, 0x72, 0xce, - 0xa8, 0x02, 0x96, 0x02, 0xeb, 0xab, 0x02, 0x90, 0x00, 0x96, 0x04, 0xeb, 0xab, 0x04, - 0xa2, 0x10, 0xce, 0x88, 0xe7, 0xb8, 0x46, 0x00, 0xad, 0xc8, 0xa8, 0xa2, 0x72, 0xce, - 0xab, 0xb5, 0x31, 0x51, 0xaf, 0x02, 0xaf, 0x04, 0xb7, 0x5e, 0x10, 0x02, 0xb7, 0x00, - 0x5f, 0x04, 0xb7, 0x05, 0x00, 0x06, 0xac, 0xce, 0xcc, 0x82, 0x70, 0xcc, 0xf8, 0xa2, - 0x22, 0xce, 0x88, 0xb5, 0x26, 0x1d, 0x3f, 0x04, 0x3f, 0x02, 0xac, 0x76, 0xce, 0xb7, - 0x00, 0x00, 0x06, 0xb7, 0x00, 0x00, 0x08, 0xb7, 0x00, 0x00, 0x0a, 0xb7, 0x00, 0x00, - 0x0c, 0xb7, 0x00, 0x00, 0x0e, 0xac, 0xce, 0xcc, 0x82, 0x7a, 0xcc, 0xf8, 0x82, 0x05, - 0x0e, 0xfc, 0x94, 0x2b, 0xe4, 0x03, 0x96, 0x06, 0xf8, 0xab, 0x06, 0xa2, 0x02, 0xcc, - 0xa8, 0x96, 0x08, 0xe8, 0xab, 0x08, 0xa2, 0x04, 0xcc, 0xa8, 0x03, 0x96, 0x0a, 0xf8, - 0xab, 0x0a, 0xa2, 0x06, 0xcc, 0xa8, 0x96, 0x0c, 0xe8, 0xab, 0x0c, 0xa9, 0x0e, 0x82, - 0x08, 0xcc, 0xf8, 0x95, 0x2f, 0xa2, 0x78, 0xce, 0x88, 0xac, 0xce, 0xcc, 0x9e, 0x08, - 0xac, 0xcc, 0xce, 0xa0, 0xc8, 0xcc, 0xf8, 0x82, 0x7a, 0xcc, 0xf8, 0xe4, 0xa2, 0x02, - 0xcc, 0xf8, 0x9d, 0x00, 0x94, 0x88, 0xa2, 0x06, 0xcc, 0xa8, 0x9d, 0x1e, 0x94, 0x53, - 0x9c, 0x1e, 0x94, 0x41, 0xe4, 0xa2, 0x02, 0xcc, 0xfa, 0x9d, 0x00, 0x94, 0x73, 0xa8, - 0x02, 0x96, 0x04, 0xfa, 0x9c, 0x00, 0x94, 0x6a, 0x96, 0xc9, 0x17, 0x94, 0x65, 0xa2, - 0x06, 0xcc, 0xa8, 0x9d, 0x00, 0x94, 0x30, 0x9c, 0x00, 0x41, 0x4c, 0xa2, 0x04, 0xcc, - 0xa8, 0x9c, 0x40, 0x94, 0x24, 0x9d, 0x40, 0x94, 0x20, 0xa8, 0x0c, 0x9d, 0x00, 0x5b, - 0x9c, 0x00, 0x42, 0x94, 0x43, 0xa8, 0x0a, 0xbd, 0x02, 0x00, 0x50, 0x94, 0x3b, 0xa2, - 0x04, 0xcc, 0xa8, 0xbc, 0x84, 0x80, 0x46, 0xbd, 0x84, 0x80, 0x42, 0x95, 0x4d, 0xa2, - 0x78, 0xce, 0x88, 0x04, 0x9c, 0x05, 0x00, 0x9d, 0x05, 0x00, 0xa2, 0x78, 0xce, 0x8b, - 0xac, 0xce, 0xcc, 0x9e, 0x08, 0xac, 0xcc, 0xce, 0xa0, 0xc8, 0xcc, 0xf8, 0x82, 0x7a, - 0xcc, 0xf8, 0x00, 0xa2, 0x04, 0xcc, 0xab, 0xa2, 0x06, 0xcc, 0xab, 0xe6, 0xa2, 0x02, - 0xcc, 0xab, 0xe4, 0x03, 0x96, 0x02, 0xf8, 0xe6, 0xa2, 0x02, 0xcc, 0xa8, 0x96, 0x04, - 0xe8, 0xa2, 0x02, 0xcc, 0xab, 0xa2, 0x04, 0xcc, 0xa8, 0x03, 0xb8, 0x00, 0x04, 0xa2, - 0x04, 0xcc, 0xab, 0xa2, 0x06, 0xcc, 0xa8, 0x82, 0x00, 0xc8, 0xe8, 0xa2, 0x06, 0xcc, - 0xab, 0xa8, 0x06, 0x03, 0x96, 0x02, 0xf8, 0xab, 0x06, 0xa8, 0x08, 0x96, 0x04, 0xe8, - 0xab, 0x08, 0xa8, 0x0a, 0x03, 0xb8, 0x00, 0x04, 0xab, 0x0a, 0xa8, 0x0c, 0x82, 0x00, - 0xc8, 0xe8, 0xab, 0x0c, 0xa2, 0x74, 0xce, 0x88, 0xab, 0x0e, 0xa8, 0x06, 0xac, 0x08, - 0xca, 0xb2, 0x46, 0x4c, 0x36, 0x4c, 0xab, 0x10, 0xa8, 0x0a, 0xac, 0x0c, 0xca, 0xb2, - 0x46, 0x20, 0x36, 0x58, 0xab, 0x12, 0x02, 0x96, 0x10, 0xeb, 0xb8, 0x00, 0x06, 0xa2, - 0x74, 0xce, 0x8b, 0xa2, 0x11, 0xce, 0x88, 0xa2, 0x74, 0xce, 0xdd, 0x94, 0xe9, 0xa2, - 0x74, 0xce, 0xdc, 0x94, 0xe3, 0xa8, 0x02, 0x96, 0x04, 0xfa, 0x9c, 0x00, 0x94, 0x23, - 0xa2, 0x6c, 0xce, 0xa8, 0x03, 0x96, 0x02, 0xf8, 0xa2, 0x6c, 0xce, 0xab, 0xa2, 0x6e, - 0xce, 0xa8, 0x96, 0x04, 0xe8, 0xa2, 0x6e, 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, - 0x18, 0xb0, 0x40, 0x35, 0xb5, 0x40, 0x59, 0xa8, 0x0e, 0xa2, 0x74, 0xce, 0xdc, 0x4c, - 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x33, 0xb5, 0x40, 0x46, 0xa2, 0x10, - 0xce, 0x88, 0xa2, 0x74, 0xce, 0xdd, 0x94, 0x46, 0xa2, 0x74, 0xce, 0xdc, 0x94, 0x40, - 0xa2, 0x11, 0xce, 0x88, 0xa2, 0x74, 0xce, 0xdd, 0x5e, 0xa2, 0x74, 0xce, 0xdc, 0x59, - 0xa2, 0x12, 0xce, 0x88, 0x9c, 0x00, 0x3c, 0x90, 0x00, 0xa2, 0x12, 0xce, 0x8b, 0xa2, - 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x40, 0xb4, 0x40, 0x0f, 0xa2, 0x12, 0xce, - 0x88, 0x9d, 0x00, 0x7f, 0x90, 0x01, 0xa2, 0x12, 0xce, 0x8b, 0xa2, 0x22, 0xce, 0x88, - 0xab, 0x18, 0xb0, 0x40, 0x40, 0xb4, 0x3f, 0xf6, 0x90, 0x01, 0xa2, 0x40, 0xce, 0x8b, - 0xb6, 0xff, 0x08, 0xa9, 0xa2, 0x68, 0xce, 0xa8, 0x03, 0xb8, 0x00, 0x01, 0xa2, 0x68, - 0xce, 0xab, 0xa2, 0x6a, 0xce, 0xa8, 0x82, 0x00, 0xc8, 0xe8, 0xa2, 0x6a, 0xce, 0xab, - 0xb7, 0x05, 0x02, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, - 0xce, 0x88, 0xb5, 0xfc, 0x07, 0xb7, 0x02, 0x11, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, - 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xfb, 0xf4, 0xa2, 0x22, 0xce, 0x88, - 0xab, 0x18, 0xb0, 0x40, 0x34, 0xb4, 0x3f, 0xa2, 0x90, 0x00, 0x96, 0x08, 0xfd, 0x4e, - 0x96, 0x08, 0xfc, 0x42, 0x95, 0xed, 0x90, 0x05, 0x96, 0x06, 0xfd, 0x42, 0x95, 0xf5, - 0x90, 0x0f, 0xa2, 0x11, 0xce, 0xdd, 0x47, 0xa2, 0x74, 0xce, 0x8b, 0xb4, 0xfe, 0xfb, - 0xa2, 0x11, 0xce, 0x88, 0x04, 0x6c, 0xa2, 0x6c, 0x76, 0xa8, 0x03, 0xa2, 0x72, 0x76, - 0xf8, 0xa2, 0x6c, 0x76, 0xab, 0xa2, 0x6e, 0x76, 0xa8, 0x82, 0x00, 0xc8, 0xe8, 0xa2, - 0x6e, 0x76, 0xab, 0xa2, 0x10, 0x76, 0x88, 0xa2, 0x74, 0x76, 0x8b, 0xa2, 0x22, 0x76, - 0x88, 0xab, 0x18, 0xb0, 0x40, 0x35, 0xb5, 0x3f, 0x4d, 0xa2, 0x22, 0x76, 0x88, 0xab, - 0x18, 0xb0, 0x40, 0x33, 0xb5, 0x3f, 0x41, 0x90, 0x01, 0xa2, 0x40, 0x76, 0x8b, 0xa2, - 0x68, 0x76, 0xa8, 0x03, 0xb8, 0x00, 0x01, 0xa2, 0x68, 0x76, 0xab, 0xa2, 0x6a, 0x76, - 0xa8, 0x82, 0x00, 0xc8, 0xe8, 0xa2, 0x6a, 0x76, 0xab, 0xb7, 0x05, 0x02, 0x02, 0xb7, - 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0x76, 0x88, 0xb5, 0xfb, 0x56, - 0xb7, 0x02, 0x11, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, - 0x76, 0x88, 0xb5, 0xfb, 0x43, 0xa2, 0x22, 0x76, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x34, - 0xb4, 0x3e, 0xf1, 0x90, 0x03, 0xb5, 0x2e, 0x21, 0x90, 0x01, 0xb5, 0x2e, 0x78, 0xa2, - 0x0c, 0x76, 0x88, 0x99, 0x01, 0x9c, 0x00, 0x4a, 0xa2, 0x0f, 0x72, 0x88, 0x9c, 0x00, - 0x43, 0xb5, 0x2e, 0xab, 0x90, 0x02, 0xa2, 0x76, 0x76, 0xab, 0x90, 0x01, 0xa2, 0x42, - 0x76, 0x8b, 0x3c, 0xa8, 0x46, 0xb5, 0xf9, 0x70, 0xa8, 0x44, 0xbc, 0x05, 0xff, 0x53, - 0xac, 0x76, 0xce, 0xa2, 0x76, 0x76, 0xa8, 0x9c, 0x00, 0x59, 0x9c, 0x01, 0x94, 0x23, - 0x9c, 0x02, 0x94, 0x33, 0x3c, 0xa2, 0x70, 0x76, 0xa8, 0x96, 0x48, 0xfc, 0x41, 0x3c, - 0x00, 0xa2, 0x70, 0x76, 0xab, 0x95, 0x21, 0xa8, 0x44, 0xbc, 0x05, 0x01, 0xb4, 0xfb, - 0xe8, 0xbc, 0x05, 0x03, 0x95, 0x63, 0x3c, 0xa8, 0x44, 0xbc, 0x05, 0x02, 0xb4, 0xfb, - 0xb8, 0xbc, 0x05, 0x05, 0x95, 0xfa, 0xbc, 0x05, 0xff, 0xb4, 0xfc, 0x30, 0x3c, 0xa8, - 0x44, 0xbc, 0x05, 0x05, 0x49, 0xbc, 0x05, 0x02, 0x50, 0xbc, 0x05, 0x04, 0x4c, 0x3c, - 0x90, 0x00, 0xa2, 0x42, 0x76, 0x8b, 0x90, 0x00, 0xb4, 0x2d, 0xee, 0xb5, 0xfb, 0x8f, - 0xa2, 0x0c, 0x76, 0x88, 0x99, 0x01, 0x9c, 0x00, 0x4a, 0xa2, 0x0f, 0x72, 0x88, 0x9c, - 0x00, 0x43, 0xb5, 0x2e, 0x1f, 0xa8, 0x44, 0xbc, 0x05, 0x04, 0x41, 0x3c, 0xa2, 0x42, - 0x76, 0x88, 0x9c, 0x00, 0x4e, 0x00, 0xa2, 0x40, 0x76, 0x8b, 0xa2, 0x30, 0x76, 0xab, - 0xa2, 0x32, 0x76, 0xab, 0x3c, 0xa2, 0x30, 0x76, 0xa8, 0x03, 0xb8, 0x00, 0x01, 0xa2, - 0x30, 0x76, 0xab, 0xa2, 0x32, 0x76, 0xa8, 0x82, 0x00, 0xc8, 0xe8, 0xa2, 0x32, 0x76, - 0xab, 0xa2, 0x22, 0x76, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x2a, 0xb4, 0x3e, 0x07, 0x00, - 0xab, 0xca, 0xa2, 0x15, 0x72, 0x88, 0x9c, 0x00, 0x3c, 0xa8, 0xca, 0xa2, 0x14, 0x72, - 0x8b, 0xb7, 0x00, 0x00, 0x18, 0xb0, 0x10, 0x2b, 0xb5, 0x3d, 0xed, 0xb7, 0x02, 0x12, - 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x10, 0x72, 0x88, 0xb5, - 0xfa, 0x20, 0xb7, 0x02, 0x12, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, - 0xa2, 0x11, 0x72, 0x88, 0xb5, 0xfa, 0x0d, 0xb7, 0x00, 0x00, 0x08, 0x82, 0x01, 0x08, - 0xfc, 0x3c, 0xa8, 0x08, 0xb5, 0xf8, 0x53, 0xa2, 0x00, 0x74, 0xa8, 0x9c, 0x00, 0x51, - 0xb7, 0x04, 0x0c, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa8, 0x08, - 0xb5, 0xf9, 0xe7, 0xa9, 0x08, 0x95, 0x24, 0xac, 0x02, 0x0a, 0xac, 0x04, 0x0c, 0xb7, - 0x00, 0x00, 0x10, 0xa8, 0x02, 0xb5, 0xf8, 0x28, 0xa8, 0x04, 0x9c, 0x02, 0x94, 0x40, - 0xa8, 0x0a, 0xb5, 0xf8, 0x31, 0xa2, 0x66, 0x76, 0xa8, 0x9c, 0x00, 0x52, 0x9c, 0x04, - 0x55, 0x9c, 0x02, 0x5a, 0x9c, 0x01, 0x5d, 0x9c, 0x05, 0x94, 0x1f, 0x9c, 0x03, 0x5c, - 0x94, 0x49, 0xb7, 0x00, 0x01, 0x10, 0x94, 0x43, 0xa2, 0x0a, 0x76, 0xa8, 0xab, 0x0e, - 0x94, 0x3b, 0xb7, 0x00, 0x02, 0x0e, 0x94, 0x35, 0xb7, 0x00, 0x01, 0x0e, 0x94, 0x2f, - 0xa2, 0x06, 0x76, 0xa8, 0x9c, 0x00, 0x72, 0x6d, 0xa2, 0x56, 0x74, 0xa8, 0x9c, 0x00, - 0x5b, 0x9c, 0x04, 0x51, 0x9c, 0x02, 0x49, 0x9c, 0x01, 0x41, 0x56, 0xb7, 0x00, 0x01, - 0x0e, 0x51, 0xb7, 0x00, 0x02, 0x0e, 0x4c, 0xa2, 0x06, 0x74, 0xa8, 0xab, 0x0e, 0x45, - 0xb7, 0x00, 0x01, 0x10, 0x40, 0x82, 0x00, 0x10, 0xfd, 0x94, 0xf1, 0xa8, 0x0e, 0x05, - 0xab, 0x12, 0x82, 0x02, 0x0c, 0xfc, 0x5c, 0xa8, 0x12, 0x9e, 0x04, 0xac, 0x76, 0xcc, - 0x82, 0x1a, 0xcc, 0xf8, 0xa0, 0xc8, 0xcc, 0xf8, 0xa2, 0x02, 0xcc, 0x88, 0xab, 0x0a, - 0xa2, 0x03, 0xcc, 0x88, 0xab, 0x0c, 0x5b, 0xa8, 0x12, 0x9e, 0x04, 0xac, 0x74, 0xcc, - 0x82, 0x58, 0xcc, 0xf8, 0xa0, 0xc8, 0xcc, 0xf8, 0xa2, 0x02, 0xcc, 0x88, 0xab, 0x0a, - 0xa2, 0x03, 0xcc, 0x88, 0xab, 0x0c, 0x82, 0x02, 0x0c, 0xfc, 0x94, 0x71, 0xa8, 0x0a, - 0xb5, 0xf7, 0x7d, 0xa2, 0x66, 0x76, 0xa8, 0x9c, 0x00, 0x5a, 0x9c, 0x04, 0x51, 0x9c, - 0x02, 0x5a, 0x9c, 0x01, 0x94, 0x20, 0x9c, 0x05, 0x94, 0x26, 0x9c, 0x03, 0x94, 0x45, - 0x95, 0x6b, 0xa8, 0x0e, 0xa2, 0x0a, 0x76, 0xfc, 0xb7, 0x00, 0x01, 0x10, 0x95, 0x77, - 0x82, 0x02, 0x0e, 0xfc, 0xb7, 0x00, 0x01, 0x10, 0x95, 0x81, 0x82, 0x01, 0x0e, 0xfc, - 0xb7, 0x00, 0x01, 0x10, 0x95, 0x8b, 0xa2, 0x06, 0x76, 0xa8, 0x9c, 0x00, 0x4b, 0x82, - 0x02, 0x0e, 0xfc, 0x51, 0xb7, 0x00, 0x02, 0x0e, 0x95, 0x9d, 0x82, 0x01, 0x0e, 0xfc, - 0x46, 0xb7, 0x00, 0x01, 0x0e, 0x95, 0xa8, 0xb7, 0x00, 0x01, 0x10, 0x95, 0xae, 0x90, - 0x03, 0x02, 0x96, 0x0e, 0xeb, 0x9d, 0x00, 0xb7, 0x00, 0x01, 0x10, 0x95, 0xbc, 0xa8, - 0x0a, 0xb5, 0xf6, 0xf8, 0xa2, 0x56, 0x74, 0xa8, 0x9c, 0x00, 0x95, 0xc9, 0x9c, 0x04, - 0x48, 0x9c, 0x02, 0x52, 0x9c, 0x01, 0x59, 0x95, 0xd4, 0xa2, 0x06, 0x74, 0xa8, 0x96, - 0x0e, 0xfc, 0xb7, 0x00, 0x01, 0x10, 0x95, 0xe1, 0x82, 0x02, 0x0e, 0xfc, 0xb7, 0x00, - 0x01, 0x10, 0x95, 0xeb, 0x82, 0x01, 0x0e, 0xfc, 0xb7, 0x00, 0x01, 0x10, 0x95, 0xf5, - 0xac, 0x0a, 0x06, 0xac, 0x0c, 0x08, 0x3c, 0xab, 0x22, 0xb5, 0xf6, 0xcc, 0xa2, 0x54, - 0x76, 0x88, 0x9c, 0x00, 0x5e, 0xa2, 0x32, 0x72, 0xa8, 0x05, 0xa2, 0x32, 0x72, 0xab, - 0x90, 0x00, 0xa2, 0x54, 0x76, 0x8b, 0xb7, 0x00, 0x00, 0x06, 0xac, 0x76, 0xcc, 0x82, - 0x52, 0xcc, 0xf8, 0x00, 0xb5, 0x20, 0x10, 0xa2, 0x30, 0x72, 0xa8, 0x02, 0xa2, 0x32, - 0x72, 0xeb, 0x9c, 0x00, 0x3c, 0x96, 0xc9, 0x17, 0x3c, 0xab, 0x0a, 0xa8, 0x22, 0x96, - 0x7e, 0xdd, 0xb0, 0xff, 0xff, 0x04, 0xab, 0x0c, 0xb7, 0x00, 0x00, 0x0e, 0x80, 0x7e, - 0x0e, 0xfc, 0x3c, 0x82, 0x00, 0x0a, 0xfc, 0x3c, 0xa8, 0x0c, 0xb5, 0xf6, 0x77, 0xa2, - 0x0e, 0x76, 0xa8, 0x9c, 0x00, 0x94, 0x2c, 0xa2, 0x55, 0x76, 0x88, 0x9c, 0x00, 0x94, - 0x24, 0xa2, 0x06, 0x76, 0xa8, 0x9c, 0x03, 0x41, 0x5c, 0x90, 0x00, 0xa2, 0x55, 0x76, - 0x8b, 0xb7, 0x02, 0x14, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa8, - 0x0c, 0xb5, 0xf7, 0xe0, 0xa8, 0x0a, 0x05, 0xab, 0x0a, 0xa8, 0x0c, 0x96, 0x7e, 0xdd, - 0xb0, 0xff, 0xff, 0x04, 0xab, 0x0c, 0x95, 0x4e, 0xa2, 0x1e, 0x72, 0x88, 0x9c, 0x02, - 0x94, 0x44, 0xa2, 0x20, 0x72, 0xa8, 0x9c, 0x04, 0x94, 0x3c, 0xb5, 0x23, 0x0b, 0x9c, - 0x00, 0x94, 0x2f, 0x90, 0x02, 0xa2, 0x1e, 0x72, 0x8b, 0x00, 0x96, 0x7e, 0xdc, 0x94, - 0x29, 0xab, 0x0a, 0xb5, 0xf6, 0x22, 0xa2, 0x12, 0x78, 0xa8, 0x9c, 0x00, 0x52, 0x90, - 0x00, 0xa2, 0x12, 0x78, 0xab, 0xb0, 0x32, 0x0e, 0xa2, 0x10, 0x78, 0x88, 0xab, 0x18, - 0xb5, 0x3b, 0x47, 0xa8, 0x0a, 0x04, 0x95, 0x26, 0x90, 0x03, 0xa2, 0x1e, 0x72, 0x8b, - 0x90, 0x00, 0xa2, 0x20, 0x72, 0xab, 0xb0, 0x10, 0x29, 0xb7, 0x00, 0x00, 0x18, 0xb4, - 0x3b, 0x2c, 0x90, 0x01, 0xa2, 0x20, 0x72, 0xab, 0xb0, 0x10, 0x29, 0xb7, 0x00, 0x00, - 0x18, 0xb5, 0x3b, 0x1c, 0x90, 0x01, 0x36, 0xec, 0xb7, 0x00, 0x00, 0x0a, 0x82, 0x01, - 0x0a, 0xfc, 0x94, 0x2b, 0xa8, 0x0a, 0xb5, 0xf5, 0xa3, 0xa2, 0x00, 0x74, 0xa8, 0x9c, - 0x00, 0x5b, 0xb7, 0x04, 0x0e, 0x02, 0xb7, 0x00, 0x01, 0x04, 0xb7, 0x00, 0x00, 0x06, - 0xa8, 0x0a, 0xb5, 0xf7, 0x37, 0xaf, 0x0a, 0xac, 0x74, 0xce, 0xb5, 0x18, 0xa3, 0x3f, - 0x0a, 0xa9, 0x0a, 0x95, 0x2f, 0xb7, 0x00, 0x00, 0x0a, 0x80, 0x7e, 0x0a, 0xfc, 0x3c, - 0xa8, 0x0a, 0xb5, 0xf5, 0x83, 0xa2, 0x0e, 0x76, 0xa8, 0x9c, 0x00, 0x51, 0xb7, 0x02, - 0x01, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa8, 0x0a, 0xb5, 0xf7, - 0x03, 0xa9, 0x0a, 0x95, 0x24, 0x90, 0x02, 0xa2, 0x20, 0x72, 0xab, 0xb0, 0x10, 0x29, - 0xb7, 0x00, 0x00, 0x18, 0xb5, 0x3a, 0xa9, 0xa2, 0x02, 0x72, 0xa8, 0xab, 0x02, 0xa2, - 0x04, 0x72, 0xa8, 0xab, 0x04, 0xb7, 0x01, 0x00, 0x06, 0xac, 0x72, 0xcc, 0x82, 0x18, - 0xcc, 0xf8, 0x00, 0xb4, 0x1e, 0xad, 0x90, 0x03, 0xa2, 0x20, 0x72, 0xab, 0xb0, 0x10, - 0x29, 0xb7, 0x00, 0x00, 0x18, 0xb5, 0x3a, 0x7e, 0xb7, 0x00, 0x00, 0x0a, 0x80, 0x7e, - 0x0a, 0xfc, 0x94, 0x21, 0xa8, 0x0a, 0xb5, 0xf5, 0x1d, 0xa2, 0x0e, 0x76, 0xa8, 0x9c, - 0x00, 0x51, 0xb7, 0x02, 0x04, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, - 0xa8, 0x0a, 0xb5, 0xf6, 0x9d, 0xa9, 0x0a, 0x95, 0x25, 0xb7, 0x00, 0x00, 0x0a, 0x82, - 0x01, 0x0a, 0xfc, 0x94, 0x21, 0xa8, 0x0a, 0xb5, 0xf4, 0xde, 0xa2, 0x00, 0x74, 0xa8, - 0x9c, 0x00, 0x51, 0xb7, 0x04, 0x0e, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, - 0x06, 0xa8, 0x0a, 0xb5, 0xf6, 0x72, 0xa9, 0x0a, 0x95, 0x25, 0xb7, 0x1e, 0x84, 0x02, - 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x01, 0x00, 0x06, 0xac, 0x72, 0xcc, 0x82, 0x18, 0xcc, - 0xf8, 0x00, 0xb4, 0x1e, 0x30, 0x90, 0x04, 0xa2, 0x20, 0x72, 0xab, 0xb0, 0x10, 0x29, - 0xb7, 0x00, 0x00, 0x18, 0xb5, 0x3a, 0x01, 0x90, 0x01, 0xa2, 0x1e, 0x72, 0x8b, 0xb5, - 0x21, 0x8e, 0x9c, 0x00, 0x94, 0x3b, 0xb7, 0x01, 0x04, 0x02, 0xb7, 0x00, 0x02, 0x04, - 0xb7, 0x00, 0x00, 0x06, 0x00, 0xb5, 0xf6, 0x2a, 0xb7, 0x00, 0x00, 0x0a, 0x80, 0x7e, - 0x0a, 0xfc, 0x3c, 0xa8, 0x0a, 0xb5, 0xf4, 0x98, 0xa2, 0x12, 0x78, 0xa8, 0x9c, 0x00, - 0x52, 0x90, 0x00, 0xa2, 0x12, 0x78, 0xab, 0xb0, 0x32, 0x0e, 0xa2, 0x10, 0x78, 0x88, - 0xab, 0x18, 0xb5, 0x39, 0xbd, 0xa9, 0x0a, 0x95, 0x25, 0xb7, 0x01, 0x04, 0x02, 0xb7, - 0x00, 0x03, 0x04, 0xb7, 0x00, 0x00, 0x06, 0x00, 0xb4, 0xf5, 0xef, 0x90, 0x05, 0xa2, - 0x20, 0x72, 0xab, 0xb0, 0x10, 0x29, 0xb7, 0x00, 0x00, 0x18, 0xb5, 0x39, 0x99, 0x90, - 0x00, 0xb5, 0x22, 0xc4, 0xb7, 0xf4, 0x24, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x01, - 0x00, 0x06, 0xac, 0x72, 0xcc, 0x82, 0x18, 0xcc, 0xf8, 0x00, 0xb4, 0x1d, 0x9c, 0xa2, - 0x1e, 0x72, 0x88, 0x9c, 0x02, 0x42, 0x95, 0x9b, 0xa2, 0x0a, 0x72, 0x88, 0x9c, 0x02, - 0x49, 0x90, 0x00, 0xa2, 0x16, 0x72, 0x8b, 0xb4, 0xfe, 0x38, 0x90, 0x06, 0xa2, 0x2e, - 0xce, 0xf9, 0x9d, 0x00, 0x94, 0x33, 0xa2, 0x16, 0x72, 0x88, 0x9c, 0x00, 0x3c, 0x90, - 0x41, 0xa2, 0x2e, 0xce, 0xf9, 0x9c, 0x00, 0x50, 0x90, 0x02, 0xa2, 0x2e, 0xcc, 0xf9, - 0x9c, 0x00, 0x47, 0x90, 0x01, 0xa2, 0x16, 0x72, 0x8b, 0x3c, 0x90, 0x02, 0xa2, 0x2e, - 0xce, 0xf9, 0x9c, 0x00, 0x3c, 0x90, 0x41, 0xa2, 0x2e, 0xcc, 0xf9, 0x9c, 0x00, 0x3c, - 0x79, 0x90, 0x06, 0xa2, 0x2e, 0xcc, 0xf9, 0x9c, 0x00, 0x95, 0x3b, 0x90, 0x00, 0xa2, - 0x16, 0x72, 0x8b, 0xb4, 0xfd, 0xe8, 0xa2, 0x20, 0x72, 0xa8, 0x9c, 0x06, 0x50, 0x90, - 0x06, 0xa2, 0x20, 0x72, 0xab, 0xb0, 0x10, 0x29, 0xb7, 0x00, 0x00, 0x18, 0xb5, 0x38, - 0xfd, 0xa2, 0x10, 0x72, 0x88, 0xb5, 0xf3, 0xa4, 0xac, 0x76, 0x24, 0xa2, 0x11, 0x72, - 0x88, 0xb5, 0xf3, 0x9a, 0xac, 0x76, 0x26, 0xa2, 0x0e, 0x24, 0xa8, 0x9c, 0x00, 0x57, - 0xa2, 0x22, 0x24, 0x88, 0xb5, 0x23, 0xa5, 0xa2, 0x2e, 0x24, 0xab, 0xa2, 0x22, 0x24, - 0x88, 0xb5, 0x23, 0x9a, 0xa2, 0x2e, 0x24, 0xab, 0x46, 0x90, 0x02, 0xa2, 0x2e, 0x24, - 0xab, 0xa2, 0x0e, 0x26, 0xa8, 0x9c, 0x00, 0x56, 0xa2, 0x22, 0x26, 0x88, 0xb5, 0x23, - 0x81, 0xa2, 0x2e, 0x26, 0xab, 0xa2, 0x22, 0x26, 0x88, 0xb5, 0x23, 0x76, 0xa2, 0x2e, - 0x26, 0xab, 0x90, 0x02, 0xa2, 0x2e, 0x26, 0xab, 0xac, 0x24, 0xce, 0xac, 0x26, 0xcc, - 0x34, 0xe1, 0xa2, 0x16, 0x72, 0x88, 0x9c, 0x00, 0x3c, 0xb7, 0xc4, 0xb4, 0x02, 0xb7, - 0x00, 0x04, 0x04, 0xb7, 0x01, 0x00, 0x06, 0xac, 0x72, 0xcc, 0x82, 0x18, 0xcc, 0xf8, - 0x00, 0xb4, 0x1c, 0x9b, 0x90, 0x07, 0xa2, 0x20, 0x72, 0xab, 0xb0, 0x10, 0x29, 0xb7, - 0x00, 0x00, 0x18, 0xb5, 0x38, 0x6c, 0x90, 0x01, 0xb5, 0x21, 0x97, 0xb7, 0x98, 0x96, - 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x01, 0x00, 0x06, 0xac, 0x72, 0xcc, 0x82, 0x18, - 0xcc, 0xf8, 0x00, 0xb4, 0x1c, 0x6f, 0x82, 0x02, 0x04, 0xfc, 0x42, 0x94, 0x22, 0xa8, - 0x02, 0xb5, 0xf2, 0xde, 0xa2, 0x54, 0x74, 0xa8, 0xaf, 0xc8, 0xb5, 0xf2, 0xfd, 0xa2, - 0x12, 0x78, 0xa8, 0x9a, 0x01, 0xa2, 0x12, 0x78, 0xab, 0x3f, 0xc8, 0xab, 0x18, 0xb0, - 0x32, 0x0e, 0xb5, 0x38, 0x27, 0xb5, 0xfa, 0x87, 0x82, 0x02, 0x08, 0xfc, 0x94, 0x32, - 0xa8, 0x06, 0xb5, 0xf2, 0xc7, 0xa2, 0x64, 0x76, 0xa8, 0xaf, 0xc8, 0xb5, 0xf2, 0xd2, - 0xa2, 0x12, 0x78, 0xa8, 0x9a, 0x02, 0xa2, 0x12, 0x78, 0xab, 0x3f, 0xc8, 0xab, 0x18, - 0xb0, 0x32, 0x0e, 0xb5, 0x37, 0xfc, 0xb7, 0x02, 0x03, 0x02, 0xac, 0x08, 0x04, 0xa8, - 0x06, 0xb7, 0x00, 0x00, 0x06, 0xb4, 0xf4, 0x32, 0xa8, 0x06, 0xb5, 0xf2, 0x81, 0xa2, - 0x54, 0x74, 0xa8, 0xaf, 0xc8, 0xb5, 0xf2, 0xa0, 0xa2, 0x12, 0x78, 0xa8, 0x9a, 0x04, - 0xa2, 0x12, 0x78, 0xab, 0x3f, 0xc8, 0xab, 0x18, 0xb0, 0x32, 0x0e, 0xb5, 0x37, 0xca, - 0xb7, 0x01, 0x04, 0x02, 0xb7, 0x00, 0x04, 0x04, 0xb7, 0x00, 0x00, 0x06, 0x00, 0xb4, - 0xf4, 0x00, 0x36, 0xd4, 0xb7, 0x00, 0x00, 0x0a, 0x80, 0x7e, 0x0a, 0xfc, 0x3c, 0xa8, - 0x0a, 0xb5, 0xf2, 0x6c, 0x90, 0x03, 0xa2, 0x12, 0x78, 0xf9, 0x9d, 0x00, 0x43, 0xa9, - 0x0a, 0x75, 0xa2, 0x12, 0x78, 0xa8, 0x9a, 0x08, 0xa2, 0x12, 0x78, 0xab, 0xa2, 0x10, - 0x78, 0x88, 0xab, 0x18, 0xb0, 0x32, 0x0e, 0xb5, 0x37, 0x88, 0x79, 0xa8, 0x44, 0xbc, - 0x01, 0x04, 0xb4, 0x01, 0xd8, 0xa8, 0x44, 0xbc, 0x01, 0xff, 0xb4, 0x01, 0xc0, 0xa2, - 0x20, 0x72, 0xa8, 0x9c, 0x00, 0xb4, 0x01, 0x8e, 0x9c, 0x01, 0xb4, 0x01, 0x0a, 0x9c, - 0x02, 0x94, 0xc3, 0x9c, 0x03, 0x51, 0x9c, 0x04, 0x94, 0x98, 0x9c, 0x05, 0x94, 0x6e, - 0x9c, 0x06, 0x94, 0x43, 0x9c, 0x07, 0x94, 0x75, 0x3c, 0xa8, 0x44, 0xbc, 0x01, 0xff, - 0x4a, 0xbc, 0x01, 0x01, 0x5b, 0xbc, 0x01, 0x02, 0x94, 0x20, 0x3c, 0xa2, 0x1e, 0x72, - 0x88, 0x9c, 0x04, 0xb4, 0xfd, 0x27, 0xa2, 0x00, 0x72, 0x88, 0x9c, 0x00, 0xb4, 0xfb, - 0xa7, 0xb4, 0xfe, 0xb0, 0xa2, 0x1e, 0x72, 0x88, 0x9c, 0x02, 0xb4, 0xfb, 0xf7, 0x3c, - 0xa2, 0x1e, 0x72, 0x88, 0x9c, 0x04, 0x41, 0x3c, 0x90, 0x05, 0xa2, 0x1e, 0x72, 0x8b, - 0x3c, 0xa8, 0x44, 0xbc, 0x01, 0xff, 0xb4, 0xfd, 0xf7, 0xbc, 0x01, 0x02, 0xb4, 0xfe, - 0x89, 0x3c, 0xa2, 0x10, 0x72, 0x88, 0xb5, 0xf1, 0xab, 0xaf, 0x76, 0xa2, 0x11, 0x72, - 0x88, 0xb5, 0xf1, 0xa2, 0xac, 0x76, 0xcc, 0x3f, 0xce, 0xb4, 0xfd, 0x6f, 0xa8, 0x44, - 0xbc, 0x01, 0xff, 0xb4, 0xfd, 0xd0, 0xbc, 0x01, 0x02, 0xb4, 0xfe, 0x62, 0x3c, 0xa8, - 0x44, 0xbc, 0x01, 0xff, 0xb4, 0xfb, 0x4d, 0xbc, 0x01, 0x01, 0x41, 0x3c, 0xa2, 0x1e, - 0x72, 0x88, 0x9c, 0x02, 0xb4, 0xfd, 0x1e, 0x3c, 0xa8, 0x44, 0xbc, 0x01, 0x04, 0x45, - 0xbc, 0x01, 0x02, 0x4e, 0x3c, 0xa2, 0x1e, 0x72, 0x88, 0x9c, 0x03, 0x46, 0x9c, 0x02, - 0xb4, 0xfb, 0x83, 0x3c, 0xa2, 0x00, 0x72, 0x88, 0x9d, 0x00, 0xb4, 0xfe, 0x29, 0xb4, - 0xfb, 0x1a, 0xa8, 0x44, 0xbc, 0x01, 0x03, 0x53, 0xbc, 0x01, 0x02, 0x58, 0xbc, 0x01, - 0x04, 0x5d, 0xbc, 0x01, 0xff, 0x94, 0x22, 0xbc, 0x01, 0x07, 0x94, 0x26, 0x3c, 0xac, - 0x46, 0x02, 0xac, 0x48, 0x04, 0xb4, 0xfe, 0x30, 0x90, 0x05, 0xa2, 0x1e, 0x72, 0x8b, - 0xb4, 0xfb, 0xe9, 0xa2, 0x1e, 0x72, 0x88, 0x9c, 0x04, 0xb4, 0xfb, 0xe0, 0x3c, 0x90, - 0x04, 0xa2, 0x1e, 0x72, 0x8b, 0xb4, 0xfe, 0xaa, 0xa8, 0x46, 0xb4, 0xfa, 0x3c, 0xa8, - 0x44, 0xbc, 0x01, 0x06, 0x94, 0x26, 0xbc, 0x01, 0x03, 0x57, 0xbc, 0x01, 0x02, 0x50, - 0xbc, 0x01, 0x07, 0x47, 0xbc, 0x01, 0x04, 0xb4, 0xfb, 0xb8, 0x3c, 0xa8, 0x46, 0xb4, - 0xfa, 0x1d, 0xb4, 0xfb, 0xaf, 0xac, 0x46, 0x02, 0xac, 0x48, 0x04, 0x36, 0x19, 0xb4, - 0xfb, 0x79, 0xa2, 0x14, 0x72, 0x88, 0x9c, 0x00, 0x5d, 0xa2, 0x15, 0x72, 0x88, 0x9c, - 0x00, 0x56, 0xa2, 0x1a, 0x72, 0x88, 0x9d, 0x00, 0x4f, 0xa2, 0x1c, 0x72, 0x88, 0x9d, - 0x00, 0x48, 0xa2, 0x22, 0x72, 0xa8, 0x9c, 0x0c, 0x94, 0x29, 0xa2, 0x14, 0x72, 0x88, - 0x9d, 0x00, 0x3c, 0xa2, 0x15, 0x72, 0x88, 0x9c, 0x00, 0x4e, 0xa2, 0x1a, 0x72, 0x88, - 0x9c, 0x00, 0x4c, 0xa2, 0x1c, 0x72, 0x88, 0x9c, 0x00, 0x45, 0x90, 0x01, 0xb4, 0xf7, - 0xe7, 0xa2, 0x22, 0x72, 0xa8, 0x9c, 0x0c, 0x3c, 0x6c, 0x90, 0x00, 0xb4, 0xf7, 0xda, - 0xa8, 0x44, 0xbc, 0x01, 0x01, 0x4f, 0xbc, 0x01, 0x04, 0x41, 0x3c, 0xa2, 0x1e, 0x72, - 0x88, 0x9c, 0x04, 0xb4, 0xfa, 0x44, 0x3c, 0xa2, 0x1e, 0x72, 0x88, 0x9c, 0x02, 0x41, - 0x3c, 0xa2, 0x00, 0x72, 0x88, 0x9c, 0x00, 0xb4, 0xfa, 0x8e, 0xb4, 0xfc, 0x0e, 0xa8, - 0x48, 0xa2, 0x18, 0x72, 0xfc, 0x41, 0x3c, 0x00, 0xa2, 0x18, 0x72, 0xab, 0xb4, 0xfe, - 0x30, 0xa8, 0x48, 0xa2, 0x1e, 0x72, 0x8b, 0xb4, 0xfe, 0x1f, 0xaf, 0xce, 0xac, 0x74, - 0xce, 0xb6, 0xb8, 0x02, 0x88, 0x99, 0x05, 0x9c, 0x00, 0x5a, 0xa2, 0x52, 0xce, 0xa8, - 0x9c, 0x03, 0x41, 0x52, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0x21, 0xbd, 0x90, 0x05, 0x01, - 0xb6, 0xb8, 0x02, 0xd9, 0xb6, 0xb8, 0x02, 0x8b, 0xb6, 0xb8, 0x02, 0x88, 0x99, 0x06, - 0x9c, 0x00, 0x5a, 0xa2, 0x52, 0xce, 0xa8, 0x9c, 0x02, 0x41, 0x52, 0xa2, 0x22, 0xce, - 0x88, 0xb5, 0x21, 0x9a, 0x90, 0x06, 0x01, 0xb6, 0xb8, 0x02, 0xd9, 0xb6, 0xb8, 0x02, - 0x8b, 0xb6, 0xb8, 0x02, 0x88, 0x99, 0x08, 0x9c, 0x00, 0x94, 0x1f, 0xa2, 0x52, 0xce, - 0xa8, 0x9c, 0x01, 0x41, 0x57, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0x21, 0x76, 0x90, 0x08, - 0x01, 0xb6, 0xb8, 0x02, 0xd9, 0xb6, 0xb8, 0x02, 0x8b, 0x00, 0xb6, 0xb8, 0x04, 0xab, - 0x3f, 0xce, 0x3c, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x0b, 0x00, 0x00, 0x05, 0x00, - 0x01, 0x09, 0x06, 0x00, 0x07, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x02, 0x00, 0x05, 0x00, 0x03, 0x09, 0x0a, 0x00, - 0x00, 0x00, 0x0a, 0x00, 0xb7, 0x00, 0x00, 0x0a, 0x80, 0x7e, 0x0a, 0xfc, 0x3c, 0xa8, - 0x0a, 0xb5, 0xef, 0xb0, 0xa2, 0x14, 0x78, 0x88, 0x9c, 0x00, 0x4b, 0x90, 0x00, 0xa2, - 0x14, 0x78, 0x8b, 0xa8, 0x0a, 0xb5, 0x24, 0xb5, 0xa9, 0x0a, 0x7e, 0x90, 0x00, 0xa2, - 0x66, 0xce, 0xab, 0x90, 0x00, 0xa2, 0x62, 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, - 0x18, 0xb0, 0x40, 0x10, 0xb5, 0x34, 0xc1, 0x90, 0x04, 0xa2, 0x28, 0xce, 0x8b, 0xa2, - 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x0d, 0xb4, 0x34, 0xaf, 0x90, 0x01, 0xa2, - 0x66, 0xce, 0xab, 0x90, 0x03, 0xa2, 0x62, 0xce, 0xab, 0x90, 0x00, 0xa2, 0x64, 0xce, - 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x10, 0xb5, 0x34, 0x91, 0xa2, - 0x06, 0xce, 0xa8, 0x9c, 0x03, 0x41, 0x3c, 0xa2, 0x28, 0x72, 0xa8, 0xa2, 0x28, 0x72, - 0xa9, 0x9c, 0x01, 0xb4, 0x13, 0x33, 0x3c, 0x90, 0x02, 0xa2, 0x66, 0xce, 0xab, 0x90, - 0x02, 0xa2, 0x62, 0xce, 0xab, 0x90, 0x01, 0xa2, 0x64, 0xce, 0xab, 0xa2, 0x22, 0xce, - 0x88, 0xab, 0x18, 0xb0, 0x40, 0x10, 0xb5, 0x34, 0x5d, 0xa2, 0x06, 0xce, 0xa8, 0x9c, - 0x03, 0x41, 0x3c, 0xa2, 0x2a, 0x72, 0xa8, 0xa2, 0x2a, 0x72, 0xa9, 0x9c, 0x01, 0xb4, - 0x12, 0xff, 0x3c, 0x90, 0x03, 0xa2, 0x66, 0xce, 0xab, 0x90, 0x05, 0xa2, 0x62, 0xce, - 0xab, 0xa2, 0x06, 0xce, 0xa8, 0x9c, 0x00, 0x52, 0x90, 0x00, 0xa2, 0x64, 0xce, 0xab, - 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x10, 0xb4, 0x34, 0x22, 0x90, 0x01, - 0x72, 0x90, 0x04, 0xa2, 0x66, 0xce, 0xab, 0x90, 0x01, 0xa2, 0x62, 0xce, 0xab, 0xa2, - 0x0a, 0xce, 0xa8, 0x05, 0xa2, 0x64, 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, - 0xb0, 0x40, 0x10, 0xb4, 0x33, 0xfe, 0x90, 0x05, 0xa2, 0x66, 0xce, 0xab, 0x90, 0x04, - 0xa2, 0x62, 0xce, 0xab, 0xa2, 0x06, 0xce, 0xa8, 0x9c, 0x00, 0x52, 0x90, 0x00, 0xa2, - 0x64, 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x10, 0xb4, 0x33, - 0xd9, 0x90, 0x01, 0x72, 0xa2, 0x54, 0xce, 0xa8, 0xb5, 0xee, 0x91, 0xa2, 0x0c, 0x78, - 0xa8, 0xa2, 0x42, 0x74, 0xab, 0xa2, 0x0e, 0x78, 0xa8, 0xa2, 0x44, 0x74, 0xab, 0xa2, - 0x08, 0x78, 0xa8, 0xa2, 0x3e, 0x74, 0xab, 0xa2, 0x0a, 0x78, 0xa8, 0xa2, 0x40, 0x74, - 0xab, 0xa2, 0x04, 0x78, 0xa8, 0xa2, 0x46, 0x74, 0xab, 0xa2, 0x06, 0x78, 0xa8, 0xa2, - 0x48, 0x74, 0xab, 0xa2, 0x10, 0xce, 0xa8, 0xa2, 0x44, 0xce, 0xfd, 0x94, 0x52, 0xa2, - 0x44, 0xce, 0xfc, 0x94, 0x2f, 0xa2, 0x0c, 0xce, 0xa8, 0xa2, 0x40, 0xce, 0xfd, 0x94, - 0x3b, 0xa2, 0x40, 0xce, 0xfc, 0x94, 0x2a, 0xa2, 0x24, 0xce, 0xa8, 0xab, 0xca, 0x90, - 0x00, 0xa2, 0x24, 0xce, 0xab, 0x96, 0xca, 0xfc, 0x94, 0x31, 0xa2, 0x22, 0xce, 0x88, - 0xab, 0x18, 0xb0, 0x2f, 0x07, 0xb5, 0x33, 0x62, 0x94, 0x23, 0xa2, 0x0e, 0xce, 0xa8, - 0xa2, 0x42, 0xce, 0xfd, 0x54, 0x95, 0x38, 0xa2, 0x0a, 0xce, 0xa8, 0xa2, 0x3e, 0xce, - 0xfd, 0x42, 0x95, 0x33, 0x90, 0x02, 0xa2, 0x24, 0xce, 0xab, 0x46, 0x90, 0x01, 0xa2, - 0x24, 0xce, 0xab, 0xa2, 0x24, 0xce, 0xa8, 0x9c, 0x00, 0x3c, 0xb7, 0x04, 0x02, 0x02, - 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xef, - 0x69, 0xb7, 0x04, 0x01, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, - 0x22, 0xce, 0x88, 0xb5, 0xef, 0x56, 0x90, 0x00, 0xa2, 0x56, 0xce, 0xab, 0x90, 0x00, - 0xa2, 0x52, 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x2f, 0x07, 0xb4, - 0x32, 0xf8, 0xb7, 0x04, 0x02, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, - 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xef, 0x2b, 0xb7, 0x04, 0x01, 0x02, 0xb7, 0x00, 0x00, - 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xef, 0x18, 0x90, 0x00, - 0xa2, 0x56, 0xce, 0xab, 0x90, 0x00, 0xa2, 0x52, 0xce, 0xab, 0xa2, 0x24, 0xce, 0xa8, - 0x9c, 0x00, 0x52, 0x90, 0x00, 0xa2, 0x24, 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, - 0x18, 0xb0, 0x2f, 0x07, 0xb5, 0x32, 0xad, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, - 0x20, 0x17, 0xb4, 0x32, 0xa1, 0x90, 0x01, 0xa2, 0x56, 0xce, 0xab, 0x90, 0x03, 0xa2, - 0x52, 0xce, 0xab, 0x90, 0x00, 0xa2, 0x54, 0xce, 0xab, 0x35, 0x47, 0xa2, 0x22, 0xce, - 0x88, 0xab, 0x18, 0xb0, 0x20, 0x17, 0xb5, 0x32, 0x81, 0xa2, 0x52, 0xce, 0xa8, 0x9c, - 0x03, 0x41, 0x3c, 0xb7, 0x04, 0x02, 0x02, 0xb7, 0x00, 0x01, 0x04, 0xb7, 0x00, 0x00, - 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xee, 0xac, 0xa2, 0x2c, 0x72, 0xa8, 0xa2, 0x2c, - 0x72, 0xa9, 0x9c, 0x01, 0xb4, 0x11, 0x10, 0x3c, 0x90, 0x02, 0xa2, 0x56, 0xce, 0xab, - 0x90, 0x02, 0xa2, 0x52, 0xce, 0xab, 0x90, 0x01, 0xa2, 0x54, 0xce, 0xab, 0x35, 0x90, - 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x20, 0x17, 0xb5, 0x32, 0x38, 0xa2, 0x52, - 0xce, 0xa8, 0x9c, 0x02, 0x41, 0x3c, 0xb7, 0x04, 0x02, 0x02, 0xb7, 0x00, 0x01, 0x04, - 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xee, 0x63, 0xa2, 0x2e, 0x72, - 0xa8, 0xa2, 0x2e, 0x72, 0xa9, 0x9c, 0x01, 0xb4, 0x10, 0xc7, 0x3c, 0x90, 0x04, 0xa2, - 0x56, 0xce, 0xab, 0x90, 0x01, 0xa2, 0x52, 0xce, 0xab, 0xa2, 0x06, 0xce, 0xa8, 0x05, - 0xa2, 0x54, 0xce, 0xab, 0x35, 0xdc, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x20, - 0x17, 0xb5, 0x31, 0xec, 0xa2, 0x52, 0xce, 0xa8, 0x9c, 0x01, 0x41, 0x3c, 0xb7, 0x04, - 0x01, 0x02, 0xb7, 0x00, 0x01, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, - 0xb4, 0xee, 0x17, 0xa2, 0x66, 0xcc, 0xa8, 0xaf, 0xce, 0x9e, 0x06, 0x3f, 0xce, 0xab, - 0xca, 0xa2, 0x66, 0xce, 0xa8, 0x96, 0xca, 0xf8, 0xb8, 0x54, 0x54, 0xad, 0xc8, 0x88, - 0xab, 0x0c, 0xa2, 0x22, 0x72, 0xab, 0xb7, 0x00, 0x00, 0x18, 0xb0, 0x10, 0x2a, 0xb5, - 0x31, 0xa8, 0xb7, 0x00, 0x00, 0x0a, 0xa2, 0x29, 0xce, 0x88, 0x9c, 0x02, 0x42, 0x94, - 0x25, 0x82, 0x05, 0x0c, 0xfc, 0x4b, 0x82, 0x09, 0x0c, 0xfc, 0x46, 0x82, 0x07, 0x0c, - 0xfc, 0x41, 0x55, 0xb7, 0x00, 0x01, 0x0a, 0x57, 0x82, 0x06, 0x0c, 0xfc, 0x69, 0x82, - 0x0a, 0x0c, 0xfc, 0x6e, 0x82, 0x07, 0x0c, 0xfc, 0x73, 0x47, 0xa2, 0x29, 0xcc, 0x88, - 0x9c, 0x02, 0x76, 0xa2, 0x27, 0x72, 0x88, 0xa0, 0xc8, 0x0a, 0xfc, 0x50, 0xa8, 0x0a, - 0xa2, 0x27, 0x72, 0x8b, 0xb7, 0x00, 0x00, 0x18, 0xb0, 0x10, 0x2e, 0xb5, 0x31, 0x56, - 0xa2, 0x15, 0x72, 0x88, 0x9c, 0x00, 0x3c, 0xb7, 0x01, 0x06, 0x02, 0xb7, 0x00, 0x00, - 0x04, 0xb7, 0x00, 0x00, 0x06, 0x00, 0xb4, 0xed, 0x85, 0xa2, 0x66, 0xce, 0xa8, 0xb8, - 0x54, 0x4e, 0xad, 0xc8, 0x88, 0xa2, 0x22, 0x72, 0xab, 0xab, 0x0a, 0xb7, 0x00, 0x00, - 0x18, 0xb0, 0x10, 0x2a, 0xb5, 0x31, 0x25, 0xb7, 0x00, 0x00, 0x0c, 0xa2, 0x29, 0xce, - 0x88, 0x9c, 0x02, 0x57, 0xa2, 0x27, 0x72, 0x88, 0x9c, 0x0c, 0x3c, 0xa8, 0x0c, 0xa2, - 0x27, 0x72, 0x8b, 0xb7, 0x00, 0x00, 0x18, 0xb0, 0x10, 0x2e, 0xb4, 0x31, 0x03, 0xa2, - 0x28, 0xce, 0x88, 0x9c, 0x02, 0x7d, 0x82, 0x08, 0x0a, 0xfc, 0x47, 0x82, 0x0b, 0x0a, - 0xfc, 0x42, 0x95, 0x28, 0xb7, 0x00, 0x01, 0x0c, 0x95, 0x2e, 0xa2, 0x66, 0xce, 0xa8, - 0x9c, 0x00, 0x56, 0x9c, 0x02, 0x94, 0xaa, 0x9c, 0x03, 0xb4, 0x01, 0x0c, 0x9c, 0x04, - 0xb4, 0x01, 0x66, 0x9c, 0x05, 0xb4, 0x01, 0x8d, 0xb4, 0x01, 0xf4, 0xa2, 0x3a, 0xce, - 0x88, 0x9c, 0x00, 0x56, 0xa2, 0x57, 0xce, 0x88, 0x9c, 0x00, 0x4f, 0x37, 0xbc, 0xb6, - 0xb8, 0x02, 0x88, 0x9a, 0x02, 0xb6, 0xb8, 0x02, 0x8b, 0xb4, 0x01, 0xd7, 0xa2, 0x3a, - 0xce, 0x88, 0x9c, 0x00, 0x5d, 0xa2, 0x56, 0xce, 0x88, 0x9c, 0x00, 0x56, 0xa2, 0x3a, - 0xcc, 0x88, 0x9c, 0x00, 0x4f, 0x37, 0xac, 0xb6, 0xb8, 0x02, 0x88, 0x9a, 0x02, 0xb6, - 0xb8, 0x02, 0x8b, 0xb4, 0x01, 0xb3, 0xa2, 0x39, 0xce, 0x88, 0x9c, 0x00, 0x5e, 0xa2, - 0x5e, 0xce, 0x88, 0x9c, 0x00, 0x57, 0x37, 0xa1, 0xb6, 0xb8, 0x02, 0x88, 0x9a, 0x08, - 0xb6, 0xb8, 0x02, 0x8b, 0xa2, 0x0a, 0xce, 0xa8, 0xb6, 0xb8, 0x04, 0xab, 0xb4, 0x01, - 0x8e, 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, 0xb4, 0x01, 0x85, 0xa2, 0x58, 0xce, 0x88, - 0x9c, 0x00, 0xb4, 0x01, 0x7c, 0x37, 0xa9, 0xb6, 0xb8, 0x02, 0x88, 0x9a, 0x04, 0xb6, - 0xb8, 0x02, 0x8b, 0xb4, 0x01, 0x6d, 0x90, 0x01, 0xb5, 0xeb, 0x03, 0x90, 0x01, 0xa2, - 0x14, 0x78, 0x8b, 0xb5, 0xfb, 0x5f, 0xb4, 0x01, 0x5c, 0xa2, 0x3a, 0xce, 0x88, 0x9c, - 0x00, 0x77, 0xa2, 0x3c, 0xce, 0x88, 0x9d, 0x00, 0x7e, 0xa2, 0x3a, 0xce, 0x88, 0x9c, - 0x00, 0x94, 0x1f, 0xa2, 0x56, 0xce, 0x88, 0x9c, 0x00, 0x58, 0xa2, 0x3a, 0xcc, 0x88, - 0x9c, 0x00, 0x51, 0x90, 0x01, 0xb5, 0xea, 0xce, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, - 0xb5, 0xfb, 0xbc, 0xb4, 0x01, 0x27, 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, 0xb4, 0x01, - 0x1e, 0xa2, 0x58, 0xce, 0x88, 0x9c, 0x00, 0xb4, 0x01, 0x15, 0xb5, 0xfb, 0xed, 0xb6, - 0xb8, 0x02, 0x88, 0x9a, 0x04, 0xb6, 0xb8, 0x02, 0x8b, 0xb4, 0x01, 0x05, 0x90, 0x01, - 0xb5, 0xea, 0x9b, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xb5, 0xfa, 0xf7, 0x94, 0xf5, - 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, 0x76, 0xa2, 0x3c, 0xce, 0x88, 0x9d, 0x00, 0x7d, - 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, 0x57, 0xa2, 0x57, 0xce, 0x88, 0x9c, 0x00, 0x50, - 0x90, 0x01, 0xb5, 0xea, 0x6f, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xb5, 0xfb, 0x29, - 0x94, 0xc9, 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, 0x94, 0xc1, 0xa2, 0x58, 0xce, 0x88, - 0x9c, 0x00, 0x94, 0xb9, 0x90, 0x01, 0xb5, 0xea, 0x4f, 0x90, 0x01, 0xa2, 0x14, 0x78, - 0x8b, 0xb5, 0xfb, 0x86, 0x94, 0xa9, 0xa2, 0x0a, 0xce, 0xa8, 0x05, 0xb5, 0xea, 0x3c, - 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xb5, 0xfa, 0x98, 0x94, 0x96, 0xa2, 0x39, 0xce, - 0x88, 0x9c, 0x00, 0x79, 0xa2, 0x5e, 0xce, 0x88, 0x9c, 0x00, 0x95, 0x20, 0x94, 0x85, - 0x90, 0x00, 0xb5, 0xea, 0x1b, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0x90, 0x01, 0xb5, - 0xea, 0x10, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xb5, 0xfa, 0x6c, 0x94, 0x6a, 0xa2, - 0x3a, 0xce, 0x88, 0x9c, 0x00, 0x95, 0x21, 0xa2, 0x3c, 0xce, 0x88, 0x9d, 0x00, 0x95, - 0x29, 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, 0x94, 0x22, 0xa2, 0x57, 0xce, 0x88, 0x9c, - 0x00, 0x5b, 0x90, 0x00, 0xb5, 0xe9, 0xe1, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0x90, - 0x01, 0xb5, 0xe9, 0xd6, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xb5, 0xfa, 0x90, 0x94, - 0x30, 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, 0x94, 0x28, 0xa2, 0x56, 0xce, 0x88, 0x9c, - 0x00, 0x94, 0x20, 0xa2, 0x3a, 0xcc, 0x88, 0x9c, 0x00, 0x59, 0x90, 0x00, 0xb5, 0xe9, - 0xaf, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0x90, 0x01, 0xb5, 0xe9, 0xa4, 0x90, 0x01, - 0xa2, 0x14, 0x78, 0x8b, 0xb5, 0xfa, 0x92, 0xa2, 0x66, 0xcc, 0xa8, 0x9c, 0x00, 0x54, - 0x9c, 0x01, 0x94, 0xae, 0x9c, 0x03, 0xb4, 0x01, 0x0e, 0x9c, 0x04, 0xb4, 0x01, 0x69, - 0x9c, 0x05, 0xb4, 0x01, 0x90, 0x3c, 0xa2, 0x3a, 0xcc, 0x88, 0x9c, 0x00, 0x58, 0xa2, - 0x57, 0xcc, 0x88, 0x9c, 0x00, 0x51, 0xac, 0xcc, 0xce, 0xb5, 0xf9, 0xfb, 0xb6, 0xb8, - 0x02, 0x88, 0x9a, 0x01, 0xb6, 0xb8, 0x02, 0x8b, 0x3c, 0xa2, 0x3a, 0xcc, 0x88, 0x9c, - 0x00, 0x94, 0x1f, 0xa2, 0x56, 0xcc, 0x88, 0x9c, 0x00, 0x58, 0xa2, 0x3a, 0xce, 0x88, - 0x9c, 0x00, 0x51, 0xac, 0xcc, 0xce, 0xb5, 0xfa, 0x3c, 0xb6, 0xb8, 0x02, 0x88, 0x9a, - 0x01, 0xb6, 0xb8, 0x02, 0x8b, 0x3c, 0xa2, 0x39, 0xcc, 0x88, 0x9c, 0x00, 0x94, 0x20, - 0xa2, 0x5e, 0xcc, 0x88, 0x9c, 0x00, 0x59, 0xac, 0xcc, 0xce, 0xb5, 0xfa, 0x44, 0xb6, - 0xb8, 0x02, 0x88, 0x9a, 0x08, 0xb6, 0xb8, 0x02, 0x8b, 0xa2, 0x0a, 0xcc, 0xa8, 0xb6, - 0xb8, 0x04, 0xab, 0x3c, 0xa2, 0x3a, 0xcc, 0x88, 0x9c, 0x00, 0x3c, 0xa2, 0x58, 0xcc, - 0x88, 0x9c, 0x00, 0x3c, 0xac, 0xcc, 0xce, 0xb5, 0xfa, 0x3e, 0xb6, 0xb8, 0x02, 0x88, - 0x9a, 0x04, 0xb6, 0xb8, 0x02, 0x8b, 0x3c, 0x90, 0x00, 0xb5, 0xe8, 0xee, 0x90, 0x01, - 0xa2, 0x14, 0x78, 0x8b, 0xac, 0xcc, 0xce, 0xb4, 0xf9, 0x47, 0xa2, 0x3a, 0xcc, 0x88, - 0x9c, 0x00, 0x77, 0xa2, 0x3c, 0xcc, 0x88, 0x9d, 0x00, 0x7e, 0xa2, 0x3a, 0xcc, 0x88, - 0x9c, 0x00, 0x94, 0x1f, 0xa2, 0x56, 0xcc, 0x88, 0x9c, 0x00, 0x58, 0xa2, 0x3a, 0xce, - 0x88, 0x9c, 0x00, 0x51, 0x90, 0x00, 0xb5, 0xe8, 0xb9, 0x90, 0x01, 0xa2, 0x14, 0x78, - 0x8b, 0xac, 0xcc, 0xce, 0xb4, 0xf9, 0xa4, 0xa2, 0x3a, 0xcc, 0x88, 0x9c, 0x00, 0x3c, - 0xa2, 0x58, 0xcc, 0x88, 0x9c, 0x00, 0x3c, 0xac, 0xcc, 0xce, 0xb5, 0xf9, 0xd9, 0xb6, - 0xb8, 0x02, 0x88, 0x9a, 0x04, 0xb6, 0xb8, 0x02, 0x8b, 0x3c, 0x90, 0x00, 0xb5, 0xe8, - 0x89, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xac, 0xcc, 0xce, 0xb4, 0xf8, 0xe2, 0xa2, - 0x3a, 0xcc, 0x88, 0x9c, 0x00, 0x77, 0xa2, 0x3c, 0xcc, 0x88, 0x9d, 0x00, 0x7e, 0xa2, - 0x3a, 0xcc, 0x88, 0x9c, 0x00, 0x58, 0xa2, 0x57, 0xcc, 0x88, 0x9c, 0x00, 0x51, 0x90, - 0x00, 0xb5, 0xe8, 0x5c, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xac, 0xcc, 0xce, 0xb4, - 0xf8, 0xdf, 0xa2, 0x3a, 0xcc, 0x88, 0x9c, 0x00, 0x3c, 0xa2, 0x58, 0xcc, 0x88, 0x9c, - 0x00, 0x3c, 0x90, 0x00, 0xb5, 0xe8, 0x3d, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xac, - 0xcc, 0xce, 0xb4, 0xf9, 0x71, 0xa2, 0x0a, 0xcc, 0xa8, 0x05, 0xb5, 0xe8, 0x29, 0x90, - 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xac, 0xcc, 0xce, 0xb4, 0xf8, 0x82, 0xa2, 0x39, 0xcc, - 0x88, 0x9c, 0x00, 0x7a, 0xa2, 0x5e, 0xcc, 0x88, 0x9c, 0x00, 0x95, 0x21, 0x3c, 0x90, - 0x00, 0xb5, 0xe8, 0x08, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0x90, 0x01, 0xb5, 0xe7, - 0xfd, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xac, 0xcc, 0xce, 0xb4, 0xf8, 0x56, 0xa2, - 0x3a, 0xcc, 0x88, 0x9c, 0x00, 0x95, 0x22, 0xa2, 0x3c, 0xcc, 0x88, 0x9d, 0x00, 0x95, - 0x2a, 0xa2, 0x3a, 0xcc, 0x88, 0x9c, 0x00, 0x94, 0x23, 0xa2, 0x57, 0xcc, 0x88, 0x9c, - 0x00, 0x5c, 0x90, 0x00, 0xb5, 0xe7, 0xcd, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0x90, - 0x01, 0xb5, 0xe7, 0xc2, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xac, 0xcc, 0xce, 0xb4, - 0xf8, 0x45, 0xa2, 0x3a, 0xcc, 0x88, 0x9c, 0x00, 0x3c, 0xa2, 0x56, 0xcc, 0x88, 0x9c, - 0x00, 0x3c, 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, 0x3c, 0x90, 0x00, 0xb5, 0xe7, 0x9c, - 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0x90, 0x01, 0xb5, 0xe7, 0x91, 0x90, 0x01, 0xa2, - 0x14, 0x78, 0x8b, 0xac, 0xcc, 0xce, 0xb4, 0xf8, 0x7c, 0xa2, 0x66, 0xce, 0xa8, 0x9c, - 0x00, 0x4e, 0x9c, 0x01, 0x94, 0x84, 0x9c, 0x02, 0x94, 0xd9, 0x9c, 0x04, 0xb4, 0x01, - 0x1a, 0x3c, 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, 0x55, 0xa2, 0x59, 0xce, 0x88, 0x9c, - 0x00, 0x4e, 0xb5, 0xf7, 0xee, 0xb6, 0xb8, 0x02, 0x88, 0x9a, 0x01, 0xb6, 0xb8, 0x02, - 0x8b, 0x3c, 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, 0x55, 0xa2, 0x5a, 0xce, 0x88, 0x9c, - 0x00, 0x4e, 0xb5, 0xf8, 0x06, 0xb6, 0xb8, 0x02, 0x88, 0x9a, 0x02, 0xb6, 0xb8, 0x02, - 0x8b, 0x3c, 0xa2, 0x39, 0xce, 0x88, 0x9c, 0x00, 0x3c, 0xa2, 0x5e, 0xce, 0x88, 0x9c, - 0x00, 0x3c, 0xb5, 0xf8, 0x46, 0xb6, 0xb8, 0x02, 0x88, 0x9a, 0x08, 0xb6, 0xb8, 0x02, - 0x8b, 0xa2, 0x0a, 0xce, 0xa8, 0xb6, 0xb8, 0x04, 0xab, 0x3c, 0x90, 0x00, 0xb5, 0xe7, - 0x0f, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xb5, 0xf7, 0x6b, 0xa2, 0x28, 0x72, 0xa8, - 0x05, 0xa2, 0x28, 0x72, 0xab, 0x04, 0x9c, 0x00, 0xb4, 0x0a, 0xec, 0x3c, 0xa2, 0x3a, - 0xce, 0x88, 0x9c, 0x00, 0x95, 0x24, 0xa2, 0x3c, 0xce, 0x88, 0x9d, 0x00, 0x95, 0x2c, - 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, 0x3c, 0xa2, 0x5a, 0xce, 0x88, 0x9c, 0x00, 0x3c, - 0xb5, 0xf7, 0x98, 0xb6, 0xb8, 0x02, 0x88, 0x9a, 0x02, 0xb6, 0xb8, 0x02, 0x8b, 0xa2, - 0x28, 0x72, 0xa8, 0x05, 0xa2, 0x28, 0x72, 0xab, 0x04, 0x9c, 0x00, 0xb4, 0x0a, 0xb1, - 0x3c, 0x90, 0x01, 0xb5, 0xe6, 0xb6, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xb5, 0xf7, - 0x12, 0xa2, 0x2a, 0x72, 0xa8, 0x05, 0xa2, 0x2a, 0x72, 0xab, 0x04, 0x9c, 0x00, 0xb4, - 0x0a, 0x93, 0x3c, 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, 0x95, 0x24, 0xa2, 0x3c, 0xce, - 0x88, 0x9d, 0x00, 0x95, 0x2c, 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, 0x3c, 0xa2, 0x59, - 0xce, 0x88, 0x9c, 0x00, 0x3c, 0x90, 0x01, 0xb5, 0xe6, 0x7a, 0x90, 0x01, 0xa2, 0x14, - 0x78, 0x8b, 0xb5, 0xf7, 0x00, 0xb6, 0xb8, 0x02, 0x88, 0x9a, 0x01, 0xb6, 0xb8, 0x02, - 0x8b, 0xa2, 0x2a, 0x72, 0xa8, 0x05, 0xa2, 0x2a, 0x72, 0xab, 0x04, 0x9c, 0x00, 0xb4, - 0x0a, 0x4d, 0x3c, 0xa2, 0x39, 0xce, 0x88, 0x9c, 0x00, 0x48, 0xa2, 0x5e, 0xce, 0x88, - 0x9c, 0x00, 0x41, 0x3c, 0xa2, 0x0a, 0xce, 0xa8, 0x05, 0xb5, 0xe6, 0x40, 0x90, 0x01, - 0xa2, 0x14, 0x78, 0x8b, 0xb4, 0xf6, 0x9c, 0xa2, 0x66, 0xce, 0xa8, 0x9c, 0x00, 0x4d, - 0x9c, 0x01, 0x94, 0x73, 0x9c, 0x04, 0x94, 0x99, 0x9c, 0x05, 0x94, 0xce, 0x3c, 0xa2, - 0x3a, 0xce, 0x88, 0x9c, 0x00, 0x55, 0xa2, 0x57, 0xce, 0x88, 0x9c, 0x00, 0x4e, 0xb5, - 0xf6, 0xa1, 0xb6, 0xb8, 0x02, 0x88, 0x9a, 0x01, 0xb6, 0xb8, 0x02, 0x8b, 0x3c, 0xa2, - 0x39, 0xce, 0x88, 0x9c, 0x00, 0x5d, 0xa2, 0x5e, 0xce, 0x88, 0x9c, 0x00, 0x56, 0xb5, - 0xf7, 0x15, 0xb6, 0xb8, 0x02, 0x88, 0x9a, 0x08, 0xb6, 0xb8, 0x02, 0x8b, 0xa2, 0x0a, - 0xce, 0xa8, 0xb6, 0xb8, 0x04, 0xab, 0x3c, 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, 0x3c, - 0xa2, 0x58, 0xce, 0x88, 0x9c, 0x00, 0x3c, 0xb5, 0xf7, 0x12, 0xb6, 0xb8, 0x02, 0x88, - 0x9a, 0x04, 0xb6, 0xb8, 0x02, 0x8b, 0x3c, 0x90, 0x00, 0xb5, 0xe5, 0xc2, 0x90, 0x01, - 0xa2, 0x14, 0x78, 0x8b, 0xb4, 0xf6, 0x1e, 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, 0x74, - 0xa2, 0x3c, 0xce, 0x88, 0x9d, 0x00, 0x7b, 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, 0x3c, - 0xa2, 0x58, 0xce, 0x88, 0x9c, 0x00, 0x3c, 0xb5, 0xf6, 0xda, 0xb6, 0xb8, 0x02, 0x88, - 0x9a, 0x01, 0xb6, 0xb8, 0x02, 0x8b, 0x3c, 0xa2, 0x39, 0xce, 0x88, 0x9c, 0x00, 0x48, - 0xa2, 0x5e, 0xce, 0x88, 0x9c, 0x00, 0x41, 0x3c, 0xa2, 0x0a, 0xce, 0xa8, 0x05, 0xb5, - 0xe5, 0x78, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xb4, 0xf5, 0xd4, 0x90, 0x00, 0xb5, - 0xe5, 0x6a, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0x90, 0x01, 0xb5, 0xe5, 0x5f, 0x90, - 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xb4, 0xf5, 0xbb, 0xa2, 0x3a, 0xce, 0x88, 0x9c, 0x00, - 0x7f, 0xa2, 0x3c, 0xce, 0x88, 0x9d, 0x00, 0x95, 0x26, 0xa2, 0x3a, 0xce, 0x88, 0x9c, - 0x00, 0x3c, 0xa2, 0x57, 0xce, 0x88, 0x9c, 0x00, 0x3c, 0x90, 0x00, 0xb5, 0xe5, 0x34, - 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0x90, 0x01, 0xb5, 0xe5, 0x29, 0x90, 0x01, 0xa2, - 0x14, 0x78, 0x8b, 0xb4, 0xf5, 0xaf, 0xa2, 0x56, 0xce, 0xa8, 0x9c, 0x00, 0x4e, 0x9c, - 0x01, 0x94, 0x28, 0x9c, 0x02, 0xb4, 0x01, 0x19, 0x9c, 0x04, 0x94, 0x9a, 0x3c, 0xa2, - 0x4a, 0xce, 0x88, 0x9c, 0x00, 0x43, 0xb4, 0xf7, 0x9e, 0xa2, 0x4b, 0xce, 0x88, 0x9c, - 0x00, 0x43, 0xb4, 0xf7, 0xdd, 0xa2, 0x4c, 0xce, 0x88, 0x9c, 0x00, 0x3c, 0xb4, 0xf8, - 0x1c, 0xa2, 0x4a, 0xce, 0x88, 0xa2, 0x4b, 0xce, 0xda, 0x9c, 0x00, 0x94, 0x51, 0xa2, - 0x4b, 0xce, 0x88, 0x9c, 0x00, 0x3c, 0xb7, 0x04, 0x02, 0x02, 0xb7, 0x00, 0x00, 0x04, - 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xe6, 0x4b, 0x90, 0x00, 0xb5, - 0xe4, 0xc2, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xb5, 0xf7, 0x9f, 0xa2, 0x2c, 0x72, - 0xa8, 0x05, 0xa2, 0x2c, 0x72, 0xab, 0x04, 0x9c, 0x00, 0xb5, 0x08, 0x9f, 0xa2, 0x2f, - 0xce, 0x88, 0x9c, 0x00, 0x3c, 0xa2, 0x1a, 0x72, 0xa8, 0x05, 0xa2, 0x1a, 0x72, 0xab, - 0xa2, 0x1c, 0x72, 0xa8, 0x04, 0xa2, 0x1c, 0x72, 0xab, 0x3c, 0x90, 0x00, 0xb5, 0xe4, - 0x8b, 0x90, 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xb5, 0xf6, 0xc8, 0xa2, 0x2c, 0x72, 0xa8, - 0x05, 0xa2, 0x2c, 0x72, 0xab, 0x04, 0x9c, 0x00, 0xb4, 0x08, 0x68, 0x3c, 0xa2, 0x4a, - 0xce, 0x88, 0xa2, 0x4b, 0xce, 0xda, 0x9c, 0x00, 0x94, 0x51, 0xa2, 0x4a, 0xce, 0x88, - 0x9c, 0x00, 0x3c, 0xb7, 0x04, 0x02, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, - 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xe5, 0xd0, 0x90, 0x01, 0xb5, 0xe4, 0x47, 0x90, - 0x01, 0xa2, 0x14, 0x78, 0x8b, 0xb5, 0xf6, 0xdb, 0xa2, 0x2e, 0x72, 0xa8, 0x05, 0xa2, - 0x2e, 0x72, 0xab, 0x04, 0x9c, 0x00, 0xb5, 0x08, 0x24, 0xa2, 0x2f, 0xce, 0x88, 0x9c, - 0x00, 0x3c, 0xa2, 0x1a, 0x72, 0xa8, 0x04, 0xa2, 0x1a, 0x72, 0xab, 0xa2, 0x1c, 0x72, - 0xa8, 0x05, 0xa2, 0x1c, 0x72, 0xab, 0x3c, 0x90, 0x01, 0xb5, 0xe4, 0x10, 0x90, 0x01, - 0xa2, 0x14, 0x78, 0x8b, 0xb5, 0xf6, 0xed, 0xa2, 0x2e, 0x72, 0xa8, 0x05, 0xa2, 0x2e, - 0x72, 0xab, 0x04, 0x9c, 0x00, 0xb4, 0x07, 0xed, 0x3c, 0xa2, 0x4c, 0xce, 0x88, 0x9d, - 0x00, 0x3c, 0xa2, 0x06, 0xce, 0xa8, 0x05, 0xb5, 0xe3, 0xe8, 0x90, 0x01, 0xa2, 0x14, - 0x78, 0x8b, 0xb4, 0xf6, 0x25, 0x00, 0xb6, 0xb8, 0x02, 0x8b, 0xb6, 0xb8, 0x04, 0xab, - 0xa2, 0x06, 0xce, 0xa8, 0x9c, 0x00, 0xb4, 0x05, 0x1e, 0x9c, 0x01, 0xb4, 0x05, 0x19, - 0x9c, 0x02, 0xb4, 0x03, 0x4d, 0x9c, 0x03, 0xb4, 0x06, 0x18, 0xa2, 0x06, 0xce, 0xa8, - 0x9c, 0x00, 0x4e, 0x9c, 0x01, 0x4b, 0x9c, 0x02, 0xb4, 0x02, 0x1a, 0x9c, 0x03, 0xb4, - 0x02, 0xa1, 0x3c, 0xa2, 0x26, 0x72, 0x88, 0x9c, 0x00, 0x59, 0xa2, 0x3a, 0x0c, 0x88, - 0x9c, 0x00, 0x52, 0x90, 0x01, 0xa2, 0x56, 0x0a, 0x8b, 0x90, 0x00, 0xa2, 0x58, 0x0a, - 0x8b, 0xa2, 0x57, 0x0a, 0x8b, 0x94, 0xa2, 0xa2, 0x5b, 0x0c, 0x88, 0x9c, 0x00, 0x5b, - 0xa2, 0x3a, 0x0c, 0x88, 0x9c, 0x00, 0x54, 0x94, 0x2f, 0x90, 0x00, 0xa2, 0x56, 0x0a, - 0x8b, 0xa2, 0x57, 0x0a, 0x8b, 0x90, 0x01, 0xa2, 0x58, 0x0a, 0x8b, 0x94, 0x80, 0xa2, - 0x5b, 0x0a, 0x88, 0x9d, 0x00, 0x78, 0xa2, 0x5f, 0x0a, 0x88, 0x9c, 0x00, 0x4f, 0xa2, - 0x5f, 0x0c, 0x88, 0x9c, 0x00, 0x94, 0x20, 0xa2, 0x3a, 0x0c, 0x88, 0x9c, 0x00, 0x59, - 0xa2, 0x5b, 0x0c, 0x88, 0x9c, 0x00, 0x48, 0xa2, 0x3a, 0x0c, 0x88, 0x9c, 0x00, 0x41, - 0x5c, 0xa2, 0x5d, 0x0a, 0x88, 0x9d, 0x00, 0x94, 0x3b, 0x94, 0x22, 0xa2, 0x5c, 0x0c, - 0x88, 0x9c, 0x00, 0x95, 0x4e, 0xa2, 0x3a, 0x0c, 0x88, 0x9c, 0x00, 0x95, 0x56, 0x95, - 0x29, 0x90, 0x00, 0xa2, 0x56, 0x0a, 0x8b, 0xa2, 0x58, 0x0a, 0x8b, 0xa2, 0x57, 0x0a, - 0x8b, 0x94, 0x28, 0xa2, 0x61, 0x0a, 0x88, 0x9c, 0x00, 0x76, 0xa2, 0x5f, 0x0c, 0x88, - 0x9c, 0x00, 0x49, 0xa2, 0x3a, 0x0c, 0x88, 0x9c, 0x00, 0x42, 0x95, 0x25, 0x90, 0x00, - 0xa2, 0x56, 0x0a, 0x8b, 0xa2, 0x58, 0x0a, 0x8b, 0x90, 0x01, 0xa2, 0x57, 0x0a, 0x8b, - 0x40, 0xa2, 0x3c, 0x0a, 0x88, 0xab, 0x0e, 0xa2, 0x56, 0x0a, 0x88, 0xa2, 0x57, 0x0a, - 0xda, 0xa2, 0x58, 0x0a, 0xda, 0x9c, 0x00, 0x94, 0x3b, 0x90, 0x00, 0xa2, 0x3c, 0x0a, - 0x8b, 0x96, 0x0e, 0xfc, 0x51, 0xb7, 0x02, 0x13, 0x02, 0xab, 0x04, 0xb7, 0x00, 0x00, - 0x06, 0xa2, 0x22, 0x0a, 0x88, 0xb5, 0xe4, 0x3a, 0xa2, 0x26, 0x72, 0x88, 0x9c, 0x00, - 0x5d, 0xa2, 0x3a, 0x0a, 0x88, 0x9c, 0x00, 0x56, 0x90, 0x01, 0xa2, 0x56, 0x0c, 0x8b, - 0x90, 0x00, 0xa2, 0x58, 0x0c, 0x8b, 0xa2, 0x57, 0x0c, 0x8b, 0x94, 0x90, 0x90, 0x01, - 0x95, 0x3b, 0xa2, 0x5b, 0x0c, 0x88, 0x9d, 0x00, 0x58, 0xa2, 0x5f, 0x0c, 0x88, 0x9c, - 0x00, 0x94, 0x30, 0xa2, 0x5b, 0x0a, 0x88, 0x9c, 0x00, 0x5b, 0xa2, 0x3a, 0x0a, 0x88, - 0x9c, 0x00, 0x54, 0x94, 0x20, 0x90, 0x00, 0xa2, 0x56, 0x0c, 0x8b, 0xa2, 0x57, 0x0c, - 0x8b, 0x90, 0x01, 0xa2, 0x58, 0x0c, 0x8b, 0x94, 0x5b, 0xa2, 0x5d, 0x0a, 0x88, 0x9c, - 0x00, 0x78, 0xa2, 0x3a, 0x0a, 0x88, 0x9c, 0x00, 0x7f, 0xa2, 0x3a, 0x0a, 0x88, 0x9c, - 0x00, 0x48, 0xa2, 0x5b, 0x0a, 0x88, 0x9c, 0x00, 0x41, 0x5e, 0xa2, 0x5c, 0x0c, 0x88, - 0x9d, 0x00, 0x94, 0x25, 0xa2, 0x60, 0x0c, 0x88, 0x9c, 0x00, 0x4f, 0xa2, 0x5f, 0x0a, - 0x88, 0x9c, 0x00, 0x57, 0xa2, 0x3a, 0x0a, 0x88, 0x9c, 0x00, 0x50, 0x40, 0x90, 0x00, - 0xa2, 0x56, 0x0c, 0x8b, 0xa2, 0x58, 0x0c, 0x8b, 0xa2, 0x57, 0x0c, 0x8b, 0x51, 0x90, - 0x00, 0xa2, 0x56, 0x0c, 0x8b, 0xa2, 0x58, 0x0c, 0x8b, 0x90, 0x01, 0xa2, 0x57, 0x0c, - 0x8b, 0x40, 0xa2, 0x3c, 0x0c, 0x88, 0xab, 0x0e, 0xa2, 0x56, 0x0c, 0x88, 0xa2, 0x57, - 0x0c, 0xda, 0xa2, 0x58, 0x0c, 0xda, 0x9c, 0x00, 0x94, 0x57, 0x90, 0x00, 0xa2, 0x3c, - 0x0c, 0x8b, 0x96, 0x0e, 0xfc, 0x51, 0xb7, 0x02, 0x13, 0x02, 0xab, 0x04, 0xb7, 0x00, - 0x00, 0x06, 0xa2, 0x22, 0x0c, 0x88, 0xb5, 0xe3, 0x59, 0xa2, 0x66, 0x0a, 0xa8, 0xaf, - 0xc8, 0xa2, 0x66, 0x0c, 0xa8, 0xaf, 0xc8, 0xac, 0x0a, 0xce, 0xac, 0x0c, 0xcc, 0xb5, - 0xf6, 0x14, 0x3f, 0xc8, 0xa2, 0x66, 0x0c, 0xfc, 0x58, 0x3f, 0xc8, 0xac, 0x0a, 0xce, - 0xac, 0x0c, 0xcc, 0xb5, 0xf5, 0x1b, 0xb5, 0xf1, 0xed, 0xa2, 0x22, 0x72, 0xa8, 0xb5, - 0x10, 0x93, 0xb4, 0xf1, 0x41, 0x3f, 0xc8, 0xa2, 0x66, 0x0a, 0xfc, 0x3c, 0x7d, 0x90, - 0x01, 0x95, 0x57, 0xa2, 0x5b, 0xce, 0x88, 0xa2, 0x5f, 0xce, 0xda, 0x9c, 0x00, 0x4e, - 0x90, 0x01, 0xa2, 0x58, 0xce, 0x8b, 0x90, 0x00, 0xa2, 0x57, 0xce, 0x8b, 0x94, 0x22, - 0xa2, 0x5c, 0xce, 0x88, 0xa2, 0x60, 0xce, 0xda, 0x9c, 0x00, 0x4d, 0x90, 0x00, 0xa2, - 0x58, 0xce, 0x8b, 0x90, 0x01, 0xa2, 0x57, 0xce, 0x8b, 0x4a, 0x90, 0x00, 0xa2, 0x58, - 0xce, 0x8b, 0xa2, 0x57, 0xce, 0x8b, 0xa2, 0x3c, 0xce, 0x88, 0xab, 0x0e, 0xa2, 0x57, - 0xce, 0x88, 0xa2, 0x58, 0xce, 0xda, 0x9c, 0x00, 0x94, 0x3b, 0x90, 0x00, 0xa2, 0x3c, - 0xce, 0x8b, 0x96, 0x0e, 0xfc, 0x51, 0xb7, 0x02, 0x13, 0x02, 0xab, 0x04, 0xb7, 0x00, - 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xe2, 0xb1, 0xa2, 0x66, 0xce, 0xa8, 0xaf, - 0xc8, 0xb5, 0xfa, 0xed, 0x3f, 0xc8, 0xa2, 0x66, 0xce, 0xfc, 0x3c, 0xb5, 0xf5, 0x19, - 0xb5, 0xf1, 0x59, 0xa2, 0x22, 0x72, 0xa8, 0xb5, 0x0f, 0xff, 0xb4, 0xf0, 0xad, 0x90, - 0x01, 0x95, 0x3b, 0xa2, 0x5c, 0xce, 0x88, 0x9d, 0x00, 0x4e, 0xa2, 0x60, 0xce, 0x88, - 0x9c, 0x00, 0x55, 0xa2, 0x5d, 0xce, 0x88, 0x9d, 0x00, 0x4e, 0x90, 0x01, 0xa2, 0x59, - 0xce, 0x8b, 0x90, 0x00, 0xa2, 0x5a, 0xce, 0x8b, 0x94, 0x22, 0xa2, 0x5d, 0xce, 0x88, - 0xa2, 0x61, 0xce, 0xda, 0x9c, 0x00, 0x4d, 0x90, 0x00, 0xa2, 0x59, 0xce, 0x8b, 0x90, - 0x01, 0xa2, 0x5a, 0xce, 0x8b, 0x4a, 0x90, 0x00, 0xa2, 0x59, 0xce, 0x8b, 0xa2, 0x5a, - 0xce, 0x8b, 0xa2, 0x3c, 0xce, 0x88, 0xab, 0x0e, 0xa2, 0x59, 0xce, 0x88, 0xa2, 0x5a, - 0xce, 0xda, 0x9c, 0x00, 0x94, 0x38, 0x90, 0x00, 0xa2, 0x3c, 0xce, 0x8b, 0x96, 0x0e, - 0xfc, 0x51, 0xb7, 0x02, 0x13, 0x02, 0xab, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, - 0xce, 0x88, 0xb5, 0xe2, 0x1b, 0xa2, 0x66, 0xce, 0xa8, 0xaf, 0xc8, 0xb5, 0xf9, 0x09, - 0x3f, 0xc8, 0xa2, 0x66, 0xce, 0xfc, 0x3c, 0xb5, 0xf0, 0xc6, 0xa2, 0x22, 0xce, 0x88, - 0xb5, 0x05, 0x95, 0xb4, 0xf0, 0x1a, 0x90, 0x01, 0x95, 0x38, 0x90, 0x00, 0xa2, 0x26, - 0x72, 0x8b, 0xa2, 0x2c, 0x72, 0xa8, 0x9c, 0x00, 0xb4, 0x01, 0x9c, 0x90, 0x00, 0xa2, - 0x24, 0x72, 0x8b, 0xa2, 0x2e, 0x72, 0xa8, 0x9c, 0x00, 0xb4, 0x01, 0x9b, 0x90, 0x00, - 0xa2, 0x25, 0x72, 0x8b, 0xa1, 0xce, 0xb8, 0x0a, 0xab, 0x30, 0x0b, 0x30, 0x4f, 0x30, - 0x93, 0x30, 0xc5, 0x31, 0x5f, 0xb4, 0xfc, 0x82, 0xaf, 0xce, 0xa4, 0xb8, 0x0a, 0xce, - 0xab, 0xa2, 0x17, 0xce, 0x88, 0x99, 0x01, 0x9c, 0x00, 0x94, 0x32, 0xa2, 0x17, 0xce, - 0x88, 0x99, 0x02, 0x9c, 0x00, 0x94, 0x28, 0xa8, 0xce, 0xb8, 0x00, 0x13, 0xa2, 0x29, - 0xce, 0xd8, 0xad, 0xc8, 0x88, 0x99, 0x40, 0x9c, 0x00, 0x57, 0xa2, 0x24, 0x72, 0x88, - 0x9c, 0x00, 0x47, 0xa2, 0x25, 0x72, 0x88, 0x9d, 0x00, 0x49, 0x90, 0x01, 0xa2, 0x5b, - 0xce, 0x8b, 0x3f, 0xce, 0x3c, 0x90, 0x00, 0x69, 0xaf, 0xce, 0xa4, 0xb8, 0x0a, 0xce, - 0xab, 0xa2, 0x17, 0xce, 0x88, 0x99, 0x01, 0x9c, 0x00, 0x94, 0x32, 0xa2, 0x17, 0xce, - 0x88, 0x99, 0x02, 0x9c, 0x00, 0x94, 0x28, 0xa8, 0xce, 0xb8, 0x00, 0x13, 0xa2, 0x29, - 0xce, 0xd8, 0xad, 0xc8, 0x88, 0x99, 0x08, 0x9c, 0x00, 0x57, 0xa2, 0x24, 0x72, 0x88, - 0x9c, 0x00, 0x47, 0xa2, 0x25, 0x72, 0x88, 0x9d, 0x00, 0x49, 0x90, 0x01, 0xa2, 0x5f, - 0xce, 0x8b, 0x3f, 0xce, 0x3c, 0x90, 0x00, 0x69, 0xaf, 0xce, 0xa4, 0xb8, 0x0a, 0xce, - 0xab, 0xa2, 0x17, 0xce, 0x88, 0x99, 0x01, 0x9c, 0x00, 0x5b, 0xa8, 0xce, 0xb8, 0x00, - 0x13, 0xa2, 0x29, 0xce, 0xd8, 0xad, 0xc8, 0x88, 0x99, 0x20, 0x9c, 0x00, 0x4a, 0xa2, - 0x24, 0x72, 0x88, 0x9d, 0x00, 0x43, 0x90, 0x01, 0x42, 0x90, 0x00, 0xa2, 0x5c, 0xce, - 0x8b, 0x3f, 0xce, 0x3c, 0xaf, 0xce, 0xa4, 0xb8, 0x0a, 0xce, 0xab, 0xa2, 0x17, 0xce, - 0x88, 0x99, 0x01, 0x9c, 0x00, 0x5b, 0xa8, 0xce, 0xb8, 0x00, 0x13, 0xa2, 0x29, 0xce, - 0xd8, 0xad, 0xc8, 0x88, 0x99, 0x04, 0x9c, 0x00, 0x4a, 0xa2, 0x24, 0x72, 0x88, 0x9d, - 0x00, 0x43, 0x90, 0x01, 0x42, 0x90, 0x00, 0xa2, 0x60, 0xce, 0x8b, 0x3f, 0xce, 0x3c, - 0xaf, 0xce, 0xa4, 0xb8, 0x0a, 0xce, 0xab, 0xa2, 0x17, 0xce, 0x88, 0x99, 0x02, 0x9c, - 0x00, 0x5b, 0xa8, 0xce, 0xb8, 0x00, 0x13, 0xa2, 0x29, 0xce, 0xd8, 0xad, 0xc8, 0x88, - 0x99, 0x10, 0x9c, 0x00, 0x4a, 0xa2, 0x25, 0x72, 0x88, 0x9d, 0x00, 0x43, 0x90, 0x01, - 0x42, 0x90, 0x00, 0xa2, 0x5d, 0xce, 0x8b, 0x3f, 0xce, 0x3c, 0xaf, 0xce, 0xa4, 0xb8, - 0x0a, 0xce, 0xab, 0xa2, 0x17, 0xce, 0x88, 0x99, 0x02, 0x9c, 0x00, 0x5b, 0xa8, 0xce, - 0xb8, 0x00, 0x13, 0xa2, 0x29, 0xce, 0xd8, 0xad, 0xc8, 0x88, 0x99, 0x02, 0x9c, 0x00, - 0x4a, 0xa2, 0x25, 0x72, 0x88, 0x9d, 0x00, 0x43, 0x90, 0x01, 0x42, 0x90, 0x00, 0xa2, - 0x61, 0xce, 0x8b, 0x3f, 0xce, 0x3c, 0xaf, 0xce, 0xa4, 0xb8, 0x0a, 0xce, 0xab, 0xa2, - 0x17, 0xce, 0x88, 0x99, 0x04, 0x9c, 0x00, 0x42, 0x90, 0x01, 0xa2, 0x5e, 0xce, 0x8b, - 0x3f, 0xce, 0x3c, 0xa2, 0x28, 0x72, 0xa8, 0x9d, 0x00, 0xb4, 0xfe, 0x5b, 0x90, 0x01, - 0xb4, 0xfe, 0x58, 0xa2, 0x2a, 0x72, 0xa8, 0x9d, 0x00, 0xb4, 0xfe, 0x5c, 0x90, 0x01, - 0xb4, 0xfe, 0x59, 0x9c, 0x00, 0x4e, 0xac, 0xce, 0x0c, 0xa2, 0x10, 0x72, 0x88, 0xb5, - 0xde, 0x8e, 0xac, 0x76, 0x0a, 0x4d, 0xac, 0xce, 0x0a, 0xa2, 0x11, 0x72, 0x88, 0xb5, - 0xde, 0x80, 0xac, 0x76, 0x0c, 0xa2, 0x10, 0x72, 0x88, 0xb5, 0xde, 0x76, 0xa8, 0x76, - 0xb6, 0xb8, 0x06, 0xab, 0xa2, 0x11, 0x72, 0x88, 0xb5, 0xde, 0x69, 0xa8, 0x76, 0xb6, - 0xb8, 0x08, 0xab, 0xa2, 0x17, 0x0a, 0x88, 0x99, 0x01, 0x9c, 0x00, 0x94, 0x53, 0xa2, - 0x17, 0x0c, 0x88, 0x99, 0x01, 0x9c, 0x00, 0x94, 0x49, 0xa2, 0x17, 0x0a, 0x88, 0x99, - 0x02, 0x9c, 0x00, 0x94, 0x3f, 0xa2, 0x17, 0x0c, 0x88, 0x99, 0x02, 0x9c, 0x00, 0x94, - 0x35, 0xa2, 0x29, 0x0a, 0x88, 0x9c, 0x02, 0x42, 0x94, 0x2c, 0xa2, 0x29, 0x0c, 0x88, - 0x9c, 0x02, 0x42, 0x94, 0x23, 0xa8, 0x0a, 0xb8, 0x00, 0x13, 0xb8, 0x00, 0x02, 0xad, - 0xc8, 0x88, 0x99, 0x80, 0x9c, 0x00, 0x53, 0xa8, 0x0c, 0xb8, 0x00, 0x13, 0xb8, 0x00, - 0x02, 0xad, 0xc8, 0x88, 0x99, 0x80, 0x9c, 0x00, 0x43, 0x90, 0x01, 0x42, 0x90, 0x00, - 0xa2, 0x26, 0x72, 0x8b, 0x40, 0xa2, 0x2c, 0x72, 0xa8, 0x9c, 0x00, 0x43, 0x90, 0x00, - 0x51, 0xa2, 0x28, 0x72, 0xa8, 0x9c, 0x00, 0x41, 0x6a, 0xa2, 0x26, 0x72, 0x88, 0x9d, - 0x00, 0x71, 0x90, 0x01, 0xa2, 0x24, 0x72, 0x8b, 0xa2, 0x2e, 0x72, 0xa8, 0x9c, 0x00, - 0x43, 0x90, 0x00, 0x51, 0xa2, 0x2a, 0x72, 0xa8, 0x9c, 0x00, 0x41, 0x6a, 0xa2, 0x26, - 0x72, 0x88, 0x9d, 0x00, 0x71, 0x90, 0x01, 0xa2, 0x25, 0x72, 0x8b, 0xb6, 0xb8, 0x06, - 0xa8, 0xb6, 0xb8, 0x0a, 0xab, 0x36, 0x73, 0x36, 0x2f, 0x35, 0xeb, 0x35, 0xb9, 0x35, - 0x87, 0x35, 0x55, 0x35, 0x23, 0xb6, 0xb8, 0x08, 0xa8, 0xb6, 0xb8, 0x0a, 0xab, 0x36, - 0x89, 0x36, 0x45, 0x36, 0x01, 0x35, 0xcf, 0x35, 0x9d, 0x35, 0x6b, 0x35, 0x39, 0xb4, - 0xf9, 0xe8, 0xa2, 0x17, 0xce, 0x88, 0x99, 0x01, 0x9c, 0x00, 0x54, 0xa8, 0xce, 0xb8, - 0x00, 0x13, 0xa2, 0x29, 0xce, 0xd8, 0xad, 0xc8, 0x88, 0x99, 0x20, 0x9c, 0x00, 0x43, - 0x90, 0x01, 0x42, 0x90, 0x00, 0xa2, 0x5c, 0xce, 0x8b, 0xa2, 0x17, 0xce, 0x88, 0x99, - 0x01, 0x9c, 0x00, 0x54, 0xa8, 0xce, 0xb8, 0x00, 0x13, 0xa2, 0x29, 0xce, 0xd8, 0xad, - 0xc8, 0x88, 0x99, 0x04, 0x9c, 0x00, 0x43, 0x90, 0x01, 0x42, 0x90, 0x00, 0xa2, 0x60, - 0xce, 0x8b, 0xa2, 0x17, 0xce, 0x88, 0x99, 0x02, 0x9c, 0x00, 0x54, 0xa8, 0xce, 0xb8, - 0x00, 0x13, 0xa2, 0x29, 0xce, 0xd8, 0xad, 0xc8, 0x88, 0x99, 0x10, 0x9c, 0x00, 0x43, - 0x90, 0x01, 0x42, 0x90, 0x00, 0xa2, 0x5d, 0xce, 0x8b, 0xa2, 0x17, 0xce, 0x88, 0x99, - 0x02, 0x9c, 0x00, 0x54, 0xa8, 0xce, 0xb8, 0x00, 0x13, 0xa2, 0x29, 0xce, 0xd8, 0xad, - 0xc8, 0x88, 0x99, 0x02, 0x9c, 0x00, 0x43, 0x90, 0x01, 0x42, 0x90, 0x00, 0xa2, 0x61, - 0xce, 0x8b, 0xa2, 0x17, 0xce, 0x88, 0x99, 0x04, 0x9c, 0x00, 0x42, 0x90, 0x01, 0xa2, - 0x5e, 0xce, 0x8b, 0xb4, 0xf9, 0x4a, 0xa2, 0x1e, 0xce, 0x88, 0x99, 0x01, 0x9c, 0x00, - 0x4b, 0xa2, 0x08, 0xce, 0x88, 0x99, 0x20, 0x9c, 0x00, 0x42, 0x90, 0x01, 0xa2, 0x4d, - 0xce, 0x8b, 0xa2, 0x1e, 0xce, 0x88, 0x99, 0x01, 0x9c, 0x00, 0x4b, 0xa2, 0x08, 0xce, - 0x88, 0x99, 0x04, 0x9c, 0x00, 0x42, 0x90, 0x01, 0xa2, 0x50, 0xce, 0x8b, 0xa2, 0x1e, - 0xce, 0x88, 0x99, 0x02, 0x9c, 0x00, 0x4b, 0xa2, 0x08, 0xce, 0x88, 0x99, 0x10, 0x9c, - 0x00, 0x42, 0x90, 0x01, 0xa2, 0x4e, 0xce, 0x8b, 0xa2, 0x1e, 0xce, 0x88, 0x99, 0x02, - 0x9c, 0x00, 0x4b, 0xa2, 0x08, 0xce, 0x88, 0x99, 0x02, 0x9c, 0x00, 0x42, 0x90, 0x01, - 0xa2, 0x51, 0xce, 0x8b, 0xa2, 0x1e, 0xce, 0x88, 0x99, 0x04, 0x9c, 0x00, 0x4b, 0xa2, - 0x08, 0xce, 0x88, 0x99, 0x01, 0x9c, 0x00, 0x42, 0x90, 0x01, 0xa2, 0x4f, 0xce, 0x8b, - 0xa2, 0x28, 0xce, 0x88, 0x9c, 0x00, 0x57, 0xa2, 0x4d, 0xce, 0x88, 0x9d, 0x00, 0x94, - 0x62, 0xa2, 0x50, 0xce, 0x88, 0x9c, 0x00, 0x48, 0xa2, 0x4e, 0xce, 0x88, 0x9c, 0x00, - 0x94, 0x53, 0xa2, 0x28, 0xce, 0x88, 0x9c, 0x00, 0x5d, 0xa2, 0x4e, 0xce, 0x88, 0xa2, - 0x51, 0xce, 0xda, 0x9c, 0x00, 0x52, 0x90, 0x01, 0xa2, 0x4b, 0xce, 0x8b, 0x90, 0x00, - 0xa2, 0x4a, 0xce, 0x8b, 0xa2, 0x4c, 0xce, 0x8b, 0x94, 0x40, 0xa2, 0x28, 0xce, 0x88, - 0x9c, 0x00, 0x59, 0xa2, 0x4f, 0xce, 0x88, 0x9c, 0x00, 0x52, 0x90, 0x00, 0xa2, 0x4a, - 0xce, 0x8b, 0xa2, 0x4b, 0xce, 0x8b, 0x90, 0x01, 0xa2, 0x4c, 0xce, 0x8b, 0x94, 0x20, - 0x90, 0x00, 0xa2, 0x4a, 0xce, 0x8b, 0xa2, 0x4b, 0xce, 0x8b, 0xa2, 0x4c, 0xce, 0x8b, - 0x51, 0x90, 0x01, 0xa2, 0x4a, 0xce, 0x8b, 0x90, 0x00, 0xa2, 0x4b, 0xce, 0x8b, 0xa2, - 0x4c, 0xce, 0x8b, 0x40, 0xb4, 0xf6, 0xeb, 0xa2, 0x0a, 0x72, 0x88, 0x9c, 0x01, 0x44, - 0x9c, 0x02, 0x51, 0x3c, 0xa2, 0x12, 0x72, 0x88, 0x9c, 0x02, 0x3c, 0xb5, 0xdb, 0xe2, - 0xac, 0x76, 0xce, 0xb4, 0xf8, 0x11, 0xa2, 0x10, 0x72, 0x88, 0x9c, 0x02, 0x49, 0xb5, - 0xdb, 0xd2, 0xac, 0x76, 0xce, 0xb4, 0xf8, 0x01, 0xa2, 0x11, 0x72, 0x88, 0x9c, 0x02, - 0x3c, 0xb5, 0xdb, 0xc2, 0xac, 0x76, 0xce, 0xb4, 0xf7, 0xf1, 0x00, 0xb6, 0xb8, 0x02, - 0x8b, 0xb6, 0xb8, 0x04, 0xab, 0xa8, 0x46, 0xb5, 0xdb, 0xae, 0xa8, 0x44, 0xbc, 0x03, - 0x02, 0x58, 0xbc, 0x03, 0x01, 0x5b, 0xa2, 0x06, 0x76, 0xa8, 0x9c, 0x03, 0x5c, 0x9c, - 0x02, 0x94, 0x38, 0x9c, 0x00, 0x94, 0x57, 0x9c, 0x01, 0x94, 0x53, 0x3c, 0xa8, 0x48, - 0xa2, 0x3a, 0x76, 0x8b, 0x7a, 0xa8, 0x48, 0xa2, 0x39, 0x76, 0x8b, 0x95, 0x21, 0xac, - 0x76, 0xce, 0xa2, 0x66, 0xce, 0xa8, 0xaf, 0xc8, 0xb5, 0xf4, 0x04, 0x3f, 0xc8, 0xa2, - 0x66, 0xce, 0xfc, 0x3c, 0xb5, 0xeb, 0xc1, 0xac, 0x76, 0xce, 0xa8, 0x46, 0x30, 0x90, - 0xb4, 0xeb, 0x15, 0xac, 0x76, 0xce, 0xa2, 0x66, 0xce, 0xa8, 0xaf, 0xc8, 0xb5, 0xf5, - 0x32, 0x3f, 0xc8, 0xa2, 0x66, 0xce, 0xfc, 0x3c, 0xb5, 0xef, 0x5e, 0xb5, 0xeb, 0x9e, - 0xa2, 0x22, 0x72, 0xa8, 0xb5, 0x0a, 0x44, 0xb4, 0xea, 0xf2, 0xa8, 0x44, 0xbc, 0x03, - 0x02, 0x94, 0x51, 0xa2, 0x06, 0x76, 0xa8, 0x9c, 0x00, 0x94, 0x4f, 0xac, 0x76, 0xcc, - 0xa2, 0x10, 0x72, 0x88, 0xb5, 0xdb, 0x25, 0xac, 0x76, 0xce, 0x43, 0xac, 0x76, 0xcc, - 0xa2, 0x66, 0xce, 0xa8, 0xaf, 0xc8, 0xa2, 0x66, 0xcc, 0xa8, 0xaf, 0xc8, 0xaf, 0xce, - 0xaf, 0xcc, 0xb5, 0xef, 0x73, 0x3f, 0xcc, 0x3f, 0xce, 0x3f, 0xc8, 0xa2, 0x66, 0xce, - 0xfc, 0x52, 0x3f, 0xc8, 0xb5, 0xee, 0x7c, 0xb5, 0xeb, 0x4e, 0xa2, 0x22, 0x72, 0xa8, - 0xb5, 0x09, 0xf4, 0xb4, 0xea, 0xa2, 0x3f, 0xc8, 0xa2, 0x66, 0xcc, 0xfc, 0x3c, 0x77, - 0xac, 0x76, 0xce, 0xb4, 0xf7, 0x15, 0xac, 0x76, 0xce, 0xa2, 0x11, 0x72, 0x88, 0xb5, - 0xda, 0xd6, 0x95, 0x4b, 0xaf, 0xc8, 0xa2, 0x66, 0xce, 0xa8, 0xb5, 0x09, 0x9c, 0xa2, - 0x30, 0x72, 0x88, 0x3f, 0xca, 0x9c, 0x00, 0x3c, 0xb7, 0x01, 0x07, 0x02, 0xb7, 0x00, - 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa8, 0xca, 0xb4, 0xdc, 0x49, 0x00, 0x90, 0x00, - 0xf6, 0x90, 0x00, 0xa2, 0x02, 0xce, 0x8b, 0xa2, 0x04, 0xce, 0xab, 0x90, 0x03, 0xa2, - 0x06, 0xce, 0xab, 0x90, 0x00, 0xa2, 0x08, 0xce, 0x8b, 0x90, 0x04, 0xa2, 0x20, 0xce, - 0xab, 0xb7, 0x00, 0x00, 0x0a, 0xac, 0xce, 0xcc, 0x82, 0x58, 0xcc, 0xf8, 0xa8, 0x0a, - 0x96, 0x7e, 0xdc, 0x5a, 0xa2, 0x22, 0xce, 0x88, 0xc6, 0xa2, 0x02, 0xcc, 0x8b, 0x90, - 0x02, 0xa2, 0x01, 0xcc, 0x8b, 0xa2, 0x03, 0xcc, 0x8b, 0x82, 0x04, 0xcc, 0xf8, 0xa9, - 0x0a, 0x7f, 0x00, 0xa2, 0x26, 0xce, 0x8b, 0xa2, 0x27, 0xce, 0x8b, 0xa2, 0x28, 0xce, - 0x8b, 0x90, 0x00, 0xa2, 0x3a, 0xce, 0xab, 0x90, 0x00, 0xa2, 0x24, 0xce, 0xab, 0x3c, - 0x00, 0xa2, 0x0a, 0xce, 0xab, 0xa2, 0x0c, 0xce, 0xab, 0xa2, 0x0e, 0xce, 0xab, 0xa2, - 0x10, 0xce, 0xab, 0xac, 0xce, 0xcc, 0x82, 0x12, 0xcc, 0xf8, 0xb1, 0x43, 0xb1, 0x33, - 0x11, 0xac, 0xce, 0xcc, 0x82, 0x18, 0xcc, 0xf8, 0xb1, 0x43, 0xb1, 0x33, 0x05, 0x90, - 0x00, 0xa2, 0x1e, 0xce, 0x8b, 0x00, 0xa2, 0x29, 0xce, 0x8b, 0xa2, 0x2a, 0xce, 0x8b, - 0xa2, 0x2b, 0xce, 0x8b, 0xa2, 0x2c, 0xce, 0x8b, 0xa2, 0x2d, 0xce, 0x8b, 0xa2, 0x2e, - 0xce, 0x8b, 0xa2, 0x30, 0xce, 0x8b, 0xa2, 0x31, 0xce, 0x8b, 0xa2, 0x32, 0xce, 0x8b, - 0xa2, 0x33, 0xce, 0x8b, 0xa2, 0x34, 0xce, 0xab, 0xa2, 0x36, 0xce, 0xab, 0xa2, 0x38, - 0xce, 0xab, 0x90, 0x01, 0xa2, 0x2f, 0xce, 0x8b, 0x00, 0xa2, 0x4a, 0xce, 0x8b, 0xa2, - 0x4b, 0xce, 0x8b, 0xa2, 0x4c, 0xce, 0x8b, 0xa2, 0x4d, 0xce, 0x8b, 0xa2, 0x4e, 0xce, - 0x8b, 0xa2, 0x4f, 0xce, 0x8b, 0xa2, 0x50, 0xce, 0x8b, 0xa2, 0x51, 0xce, 0x8b, 0xa2, - 0x54, 0xce, 0xab, 0x90, 0x00, 0xa2, 0x52, 0xce, 0xab, 0x90, 0x00, 0xa2, 0x56, 0xce, - 0xab, 0x3c, 0x00, 0xf6, 0xa2, 0x02, 0xce, 0xab, 0x90, 0x02, 0xa2, 0x04, 0xce, 0xab, - 0x90, 0x04, 0xa2, 0x06, 0xce, 0xab, 0x00, 0xa2, 0x08, 0xce, 0xab, 0x90, 0x03, 0xa2, - 0x0a, 0xce, 0xab, 0x90, 0x00, 0xa2, 0x0c, 0xce, 0x8b, 0x90, 0x00, 0xa2, 0x0e, 0xce, - 0xab, 0x90, 0x07, 0xa2, 0x10, 0xce, 0x8b, 0x90, 0x08, 0xa2, 0x11, 0xce, 0x8b, 0xac, - 0xce, 0xcc, 0x82, 0x13, 0xcc, 0xf8, 0x90, 0x00, 0xc6, 0xa2, 0x01, 0xcc, 0x8b, 0xa2, - 0x02, 0xcc, 0x8b, 0xb7, 0x00, 0x00, 0x0a, 0xac, 0xce, 0xcc, 0x82, 0x1a, 0xcc, 0xf8, - 0xa8, 0x0a, 0x96, 0x7e, 0xdc, 0x3c, 0xa2, 0x22, 0xce, 0x88, 0xc6, 0xa2, 0x02, 0xcc, - 0x8b, 0x90, 0x04, 0xa2, 0x01, 0xcc, 0x8b, 0xa2, 0x03, 0xcc, 0x8b, 0x82, 0x04, 0xcc, - 0xf8, 0xa9, 0x0a, 0x7f, 0x90, 0x00, 0xa2, 0x17, 0xce, 0x8b, 0x90, 0x00, 0xa2, 0x18, - 0xce, 0x8b, 0x00, 0xa2, 0x24, 0xce, 0xab, 0xa2, 0x26, 0xce, 0xab, 0x90, 0x04, 0xa2, - 0x28, 0xce, 0x8b, 0x90, 0x00, 0xa2, 0x29, 0xce, 0x8b, 0x90, 0x00, 0xa2, 0x2a, 0xce, - 0x8b, 0x90, 0x00, 0xa2, 0x2c, 0xce, 0xab, 0x00, 0xa2, 0x2e, 0xce, 0xab, 0xa2, 0x30, - 0xce, 0xab, 0xa2, 0x32, 0xce, 0xab, 0xa2, 0x34, 0xce, 0x8b, 0xa2, 0x35, 0xce, 0x8b, - 0xa2, 0x36, 0xce, 0x8b, 0xa2, 0x37, 0xce, 0x8b, 0xa2, 0x38, 0xce, 0x8b, 0xa2, 0x39, - 0xce, 0x8b, 0xa2, 0x3a, 0xce, 0x8b, 0xa2, 0x3b, 0xce, 0x8b, 0xa2, 0x3c, 0xce, 0x8b, - 0xa2, 0x3d, 0xce, 0x8b, 0xa2, 0x3e, 0xce, 0x8b, 0xa2, 0x3f, 0xce, 0x8b, 0xa2, 0x40, - 0xce, 0x8b, 0xa2, 0x41, 0xce, 0x8b, 0xa2, 0x42, 0xce, 0x8b, 0xa2, 0x44, 0xce, 0xab, - 0xa2, 0x46, 0xce, 0xab, 0xa2, 0x48, 0xce, 0xab, 0xa2, 0x4a, 0xce, 0xab, 0xa2, 0x4c, - 0xce, 0xab, 0x90, 0x00, 0xa2, 0x4e, 0xce, 0xab, 0x90, 0x00, 0xa2, 0x50, 0xce, 0xab, - 0x90, 0x00, 0xa2, 0x54, 0xce, 0x8b, 0xa2, 0x55, 0xce, 0x8b, 0xa2, 0x57, 0xce, 0x8b, - 0xa2, 0x58, 0xce, 0x8b, 0xa2, 0x59, 0xce, 0x8b, 0xa2, 0x5a, 0xce, 0x8b, 0xa2, 0x5b, - 0xce, 0x8b, 0xa2, 0x5c, 0xce, 0x8b, 0xa2, 0x5d, 0xce, 0x8b, 0xa2, 0x5e, 0xce, 0x8b, - 0xa2, 0x5f, 0xce, 0x8b, 0xa2, 0x60, 0xce, 0x8b, 0xa2, 0x61, 0xce, 0x8b, 0xa2, 0x64, - 0xce, 0xab, 0x90, 0x00, 0xa2, 0x62, 0xce, 0xab, 0x90, 0x04, 0xa2, 0x66, 0xce, 0xab, - 0x00, 0xa2, 0x68, 0xce, 0xab, 0xa2, 0x6a, 0xce, 0xab, 0xa2, 0x6c, 0xce, 0xab, 0xa2, - 0x6e, 0xce, 0xab, 0xa2, 0x70, 0xce, 0xab, 0xa2, 0x72, 0xce, 0xab, 0xa2, 0x74, 0xce, - 0x8b, 0x90, 0x00, 0xa2, 0x76, 0xce, 0xab, 0x3c, 0xb0, 0xe4, 0x9c, 0xa2, 0x02, 0x72, - 0xab, 0x90, 0xa6, 0xa2, 0x04, 0x72, 0xab, 0x90, 0x00, 0xa2, 0x06, 0x72, 0xab, 0xb0, - 0xff, 0xff, 0xa2, 0x08, 0x72, 0xab, 0xb0, 0xff, 0xff, 0xa2, 0x36, 0x72, 0xab, 0x00, - 0xa2, 0x0a, 0x72, 0x8b, 0xa2, 0x0b, 0x72, 0x8b, 0xa2, 0x0c, 0x72, 0x8b, 0x90, 0x00, - 0xa2, 0x0d, 0x72, 0x8b, 0x00, 0xa2, 0x0e, 0x72, 0x8b, 0xa2, 0x0f, 0x72, 0x8b, 0x90, - 0x02, 0xa2, 0x10, 0x72, 0x8b, 0xa2, 0x11, 0x72, 0x8b, 0xa2, 0x12, 0x72, 0x8b, 0x90, - 0x01, 0xa2, 0x14, 0x72, 0x8b, 0x90, 0x00, 0xa2, 0x00, 0x72, 0x8b, 0xa2, 0x15, 0x72, - 0x8b, 0xa2, 0x16, 0x72, 0x8b, 0xa2, 0x18, 0x72, 0x8b, 0xa2, 0x1a, 0x72, 0x8b, 0xa2, - 0x1c, 0x72, 0x8b, 0x90, 0x02, 0xa2, 0x1e, 0x72, 0x8b, 0x90, 0x00, 0xa2, 0x20, 0x72, - 0xab, 0x90, 0x00, 0xa2, 0x22, 0x72, 0xab, 0x90, 0x01, 0xa2, 0x24, 0x72, 0x8b, 0xa2, - 0x25, 0x72, 0x8b, 0x90, 0x00, 0xa2, 0x26, 0x72, 0x8b, 0xa2, 0x27, 0x72, 0x8b, 0xa2, - 0x28, 0x72, 0xab, 0xa2, 0x2a, 0x72, 0xab, 0xa2, 0x2c, 0x72, 0xab, 0xa2, 0x2e, 0x72, - 0xab, 0xb7, 0x00, 0x00, 0x0c, 0xa8, 0x0c, 0x9c, 0x01, 0x56, 0xb5, 0xd7, 0x7d, 0xa8, - 0x0c, 0xa2, 0x22, 0x74, 0x8b, 0xac, 0x74, 0xce, 0x37, 0x28, 0xac, 0x74, 0xce, 0x36, - 0xc9, 0xa9, 0x0c, 0x7a, 0xb7, 0x00, 0x00, 0x0c, 0xa8, 0x0c, 0x96, 0x7e, 0xdc, 0x94, - 0x34, 0xb5, 0xd7, 0x84, 0xa8, 0x0c, 0xa2, 0x10, 0x78, 0xab, 0x00, 0xa2, 0x00, 0x78, - 0xab, 0xa2, 0x02, 0x78, 0xab, 0xa2, 0x04, 0x78, 0xab, 0xa2, 0x06, 0x78, 0xab, 0xa2, - 0x08, 0x78, 0xab, 0xa2, 0x0a, 0x78, 0xab, 0xa2, 0x0c, 0x78, 0xab, 0xa2, 0x0e, 0x78, - 0xab, 0x90, 0x00, 0xa2, 0x12, 0x78, 0xab, 0xa9, 0x0c, 0x95, 0x39, 0xb7, 0x00, 0x00, - 0x0c, 0xa8, 0x0c, 0x9c, 0x03, 0x56, 0xb5, 0xd7, 0x33, 0xa8, 0x0c, 0xa2, 0x22, 0x76, - 0x8b, 0xac, 0x76, 0xce, 0x36, 0x86, 0xac, 0x76, 0xce, 0x36, 0x19, 0xa9, 0x0c, 0x7a, - 0x00, 0x3c, 0xad, 0xca, 0x88, 0xc6, 0xa9, 0xca, 0xa9, 0xcc, 0xad, 0xca, 0x88, 0xc6, - 0xa9, 0xca, 0xa9, 0xcc, 0xad, 0xca, 0x88, 0xc6, 0xa9, 0xca, 0xa9, 0xcc, 0xad, 0xca, - 0x88, 0xc6, 0xa9, 0xca, 0xa9, 0xcc, 0xad, 0xca, 0x88, 0xc6, 0xa9, 0xca, 0xa9, 0xcc, - 0xad, 0xca, 0x88, 0xc6, 0x3c, 0x00, 0xb7, 0x00, 0x00, 0x2e, 0xb7, 0x00, 0x00, 0x30, - 0xb7, 0x00, 0x00, 0x2c, 0x91, 0x00, 0xb2, 0xce, 0x3e, 0x00, 0xe6, 0x82, 0x0e, 0xcc, - 0xf8, 0xa9, 0xca, 0x82, 0x10, 0xca, 0xfc, 0x6b, 0x3c, 0x91, 0x00, 0xb2, 0xce, 0x3e, - 0x00, 0xfc, 0xb6, 0xb8, 0x00, 0xa8, 0xa2, 0x0c, 0xcc, 0xfc, 0x4c, 0x82, 0x0e, 0xcc, - 0xf8, 0xa9, 0xca, 0x82, 0x10, 0xca, 0xfc, 0x75, 0x3c, 0xa0, 0x30, 0xca, 0xfc, 0x4c, - 0x00, 0xe6, 0xa2, 0x0c, 0xcc, 0xab, 0xa8, 0x2e, 0x05, 0xab, 0x2e, 0x7c, 0x00, 0xa2, - 0x06, 0xcc, 0xab, 0x95, 0x22, 0x83, 0x00, 0xb8, 0x00, 0xab, 0x48, 0xb7, 0x00, 0x00, - 0x02, 0xb7, 0x00, 0x00, 0x04, 0xab, 0x3c, 0xac, 0xce, 0x3e, 0xa8, 0xcc, 0xae, 0xce, - 0xb7, 0xff, 0xff, 0x38, 0xb7, 0xff, 0xff, 0x3a, 0x82, 0x00, 0x2e, 0xfd, 0x5e, 0x32, - 0x0f, 0x00, 0xab, 0x34, 0xab, 0x36, 0xb2, 0xce, 0x3e, 0xa0, 0x30, 0xcc, 0xf8, 0x94, - 0x52, 0xa2, 0x02, 0xcc, 0xa8, 0xab, 0x34, 0xa2, 0x04, 0xcc, 0xa8, 0xab, 0x36, 0x94, - 0x44, 0x31, 0xfe, 0xab, 0x34, 0xac, 0xcc, 0x36, 0x31, 0xea, 0xb2, 0xce, 0x3e, 0xa0, - 0x30, 0xcc, 0xf8, 0xa8, 0x36, 0xa2, 0x04, 0xcc, 0xfd, 0x95, 0x24, 0xa2, 0x04, 0xcc, - 0xfc, 0x41, 0x4e, 0xa8, 0x34, 0xa2, 0x02, 0xcc, 0xfd, 0x95, 0x32, 0xa2, 0x02, 0xcc, - 0xfc, 0x95, 0x38, 0xa2, 0x02, 0xcc, 0xa8, 0x02, 0x96, 0x34, 0xeb, 0xab, 0x34, 0xa2, - 0x04, 0xcc, 0xa8, 0x96, 0x36, 0xeb, 0xab, 0x36, 0x96, 0x37, 0x17, 0x95, 0x50, 0x97, - 0x00, 0x42, 0xa8, 0x02, 0x96, 0x04, 0xfa, 0x9d, 0x00, 0x97, 0x01, 0x42, 0xa8, 0xcc, - 0xae, 0xce, 0xab, 0xcc, 0x00, 0xe5, 0xab, 0x32, 0x82, 0x00, 0x42, 0xdd, 0x5d, 0xa8, - 0xcc, 0xae, 0xce, 0xab, 0xcc, 0x91, 0x00, 0xb2, 0xce, 0x3e, 0xb7, 0x00, 0x00, 0x40, - 0xa8, 0x32, 0x9c, 0x00, 0x94, 0x50, 0xa2, 0x0a, 0xcc, 0xfc, 0x94, 0x39, 0x94, 0x48, - 0xa8, 0x04, 0x9d, 0x00, 0x95, 0x21, 0x9c, 0x00, 0x41, 0x46, 0xa8, 0x02, 0x9d, 0x00, - 0x95, 0x2b, 0x90, 0x00, 0xaa, 0xc8, 0x62, 0xa8, 0x2c, 0x04, 0xbd, 0x7f, 0xff, 0x90, - 0x01, 0xab, 0x2c, 0xab, 0x04, 0xe6, 0xac, 0x06, 0x02, 0x82, 0xff, 0x02, 0xfa, 0xa8, - 0x3c, 0xb7, 0x00, 0x00, 0x06, 0xb5, 0xd7, 0x44, 0x97, 0x00, 0x42, 0x95, 0x52, 0xc4, - 0x9c, 0x00, 0x4d, 0x00, 0xc6, 0xa2, 0x06, 0xcc, 0x8b, 0xab, 0x32, 0xa8, 0x2e, 0x05, - 0xab, 0x2e, 0xc4, 0x9c, 0x00, 0x94, 0x9d, 0x02, 0xa2, 0x02, 0xcc, 0xa8, 0x96, 0x34, - 0xeb, 0xa2, 0x02, 0xcc, 0xab, 0xa2, 0x04, 0xcc, 0xa8, 0x96, 0x36, 0xeb, 0xa2, 0x04, - 0xcc, 0xab, 0xa2, 0x05, 0xcc, 0x17, 0x94, 0x38, 0xa2, 0x04, 0xcc, 0xa8, 0x9d, 0x00, - 0x4e, 0x9c, 0x00, 0x42, 0x94, 0x2c, 0xa2, 0x02, 0xcc, 0xa8, 0x9d, 0x00, 0x42, 0x94, - 0x23, 0x00, 0xdc, 0x4e, 0xa8, 0x3a, 0xa2, 0x04, 0xcc, 0xfd, 0x94, 0x4f, 0xa2, 0x04, - 0xcc, 0xfc, 0x94, 0x40, 0xa9, 0xca, 0x82, 0x10, 0xca, 0xfc, 0x94, 0x95, 0x82, 0x0e, - 0x40, 0xf8, 0x82, 0x0e, 0xcc, 0xf8, 0x95, 0xae, 0xa2, 0x0a, 0xcc, 0xa8, 0xaf, 0x04, - 0xab, 0x04, 0xa2, 0x06, 0xcc, 0xa8, 0xaf, 0x02, 0x9a, 0xff, 0xab, 0x02, 0xaf, 0x06, - 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x08, 0xcc, 0xa8, 0xb5, 0xd6, 0xb5, 0x3f, 0x06, 0x3f, - 0x02, 0x3f, 0x04, 0x00, 0xc6, 0xa8, 0x2e, 0x05, 0xab, 0x2e, 0x95, 0x4f, 0xa8, 0x38, - 0xa2, 0x02, 0xcc, 0xfd, 0x42, 0x95, 0x47, 0xac, 0x40, 0x30, 0xa2, 0x02, 0xcc, 0xa8, - 0xab, 0x38, 0xa2, 0x04, 0xcc, 0xa8, 0xab, 0x3a, 0x95, 0x58, 0x96, 0x42, 0xdc, 0x95, - 0x6e, 0xa8, 0x02, 0xa2, 0x02, 0xcc, 0xab, 0xa8, 0x04, 0xa2, 0x04, 0xcc, 0xab, 0x90, - 0x01, 0xc6, 0xa8, 0x06, 0xa2, 0x06, 0xcc, 0xab, 0xa8, 0x3c, 0xa2, 0x08, 0xcc, 0xab, - 0xa8, 0x2c, 0x04, 0xbd, 0x7f, 0xff, 0x90, 0x01, 0xab, 0x2c, 0xa2, 0x0a, 0xcc, 0xab, - 0xae, 0xce, 0xae, 0xcc, 0xae, 0xce, 0xe6, 0xae, 0xce, 0xab, 0xcc, 0xa8, 0x2e, 0x04, - 0xab, 0x2e, 0x00, 0x8b, 0x42, 0x95, 0xac, 0xa8, 0x2e, 0x9c, 0x00, 0x4e, 0xa8, 0x38, - 0x96, 0x3a, 0xfa, 0x9c, 0x00, 0x46, 0x30, 0x1c, 0xac, 0x3e, 0xce, 0x3c, 0xac, 0x3e, - 0xce, 0x3c, 0x83, 0x44, 0x01, 0x91, 0x8b, 0x40, 0x40, 0x83, 0xcc, 0x01, 0x91, 0x8b, - 0x40, 0x40, 0x83, 0x44, 0x01, 0x91, 0x8b, 0x3c, 0x34, 0x14, 0xa1, 0x38, 0x01, 0x8c, - 0xab, 0xa1, 0x3a, 0x01, 0x88, 0xab, 0x87, 0xff, 0xff, 0x01, 0x8a, 0xab, 0x87, 0xff, - 0xff, 0x01, 0x86, 0xab, 0x83, 0x01, 0x01, 0x91, 0x8b, 0x3c, 0x34, 0x32, 0x83, 0x00, - 0x01, 0x88, 0xab, 0x83, 0x00, 0x01, 0x8c, 0xab, 0x3c, 0xb6, 0x01, 0x8c, 0xa8, 0xa4, - 0x01, 0x88, 0xcc, 0xab, 0x3c, 0x82, 0x00, 0x2e, 0xfc, 0x94, 0xdc, 0xb2, 0xce, 0x3e, - 0xa0, 0x30, 0xcc, 0xf8, 0xa2, 0x02, 0xcc, 0xa8, 0xab, 0x34, 0xa2, 0x04, 0xcc, 0xa8, - 0xab, 0x36, 0xb7, 0xff, 0xff, 0x38, 0xb7, 0xff, 0xff, 0x3a, 0xb2, 0xce, 0x3e, 0x91, - 0x00, 0xb7, 0x00, 0x00, 0x40, 0x00, 0xdc, 0x94, 0x93, 0xa8, 0x36, 0xa2, 0x04, 0xcc, - 0xfd, 0x48, 0xa2, 0x04, 0xcc, 0xfc, 0x94, 0x37, 0x94, 0x43, 0xa2, 0x06, 0xcc, 0xa8, - 0x9c, 0x00, 0x94, 0x23, 0xac, 0x02, 0x3c, 0xac, 0x04, 0x3e, 0xa8, 0x50, 0xa2, 0x06, - 0xcc, 0xa8, 0x9a, 0xff, 0xab, 0x02, 0xa2, 0x0a, 0xcc, 0xa8, 0xab, 0x04, 0xa2, 0x08, - 0xcc, 0xa8, 0xb5, 0xd5, 0x87, 0xac, 0x3c, 0x02, 0xac, 0x3e, 0x04, 0x90, 0x00, 0xc6, - 0xa8, 0x2e, 0x05, 0xab, 0x2e, 0x94, 0x4f, 0xa8, 0x34, 0xa2, 0x02, 0xcc, 0xfd, 0x95, - 0x3b, 0xa2, 0x02, 0xcc, 0xfc, 0x95, 0x41, 0x02, 0xa2, 0x02, 0xcc, 0xa8, 0x96, 0x34, - 0xeb, 0xa2, 0x02, 0xcc, 0xab, 0xa2, 0x04, 0xcc, 0xa8, 0x96, 0x36, 0xeb, 0xa2, 0x04, - 0xcc, 0xab, 0xa2, 0x05, 0xcc, 0x17, 0x95, 0x5e, 0xa8, 0x3a, 0xa2, 0x04, 0xcc, 0xfd, - 0x4e, 0xa2, 0x04, 0xcc, 0xfc, 0x41, 0x57, 0xa8, 0x38, 0xa2, 0x02, 0xcc, 0xfd, 0x41, - 0x4f, 0xac, 0x40, 0x30, 0xa2, 0x02, 0xcc, 0xa8, 0xab, 0x38, 0xa2, 0x04, 0xcc, 0xa8, - 0xab, 0x3a, 0xa9, 0xca, 0x82, 0x10, 0xca, 0xfc, 0x4a, 0x82, 0x0e, 0x40, 0xf8, 0x82, - 0x0e, 0xcc, 0xf8, 0x95, 0xa6, 0xa8, 0x2e, 0x9c, 0x00, 0x4b, 0xa8, 0x3a, 0x96, 0x38, - 0xfa, 0x9c, 0x00, 0x43, 0x35, 0x14, 0x3c, 0x35, 0x2b, 0x3c, 0xb6, 0xf9, 0xfa, 0xa8, - 0xb6, 0xf9, 0xfc, 0xfc, 0x5d, 0xb6, 0xf9, 0xfa, 0xa9, 0xb3, 0x01, 0x84, 0xf2, 0xf6, - 0xb3, 0x01, 0x90, 0x90, 0x40, 0xd6, 0x40, 0x40, 0x90, 0xc8, 0xd6, 0x40, 0x40, 0x97, - 0xdf, 0xd2, 0x90, 0x98, 0xd6, 0x3c, 0xb6, 0xf9, 0xfe, 0x88, 0x96, 0xc8, 0x10, 0x47, - 0x30, 0x0a, 0x91, 0x01, 0xb4, 0x85, 0x58, 0x99, 0xfe, 0x9c, 0xa4, 0x51, 0xb3, 0x01, - 0x90, 0x90, 0x40, 0xd6, 0x40, 0x40, 0x90, 0xc8, 0xd6, 0x40, 0x40, 0x97, 0xdf, 0xd2, - 0x3c, 0x00, 0xb6, 0xf9, 0xfa, 0xab, 0x34, 0x43, 0x95, 0x22, 0xb6, 0xff, 0x20, 0xa9, - 0x90, 0x01, 0xb6, 0x10, 0x00, 0x8e, 0x8b, 0x03, 0xaf, 0xcc, 0xaf, 0xce, 0xa2, 0x0a, - 0x72, 0x88, 0x9d, 0x01, 0x53, 0xa2, 0x12, 0x72, 0x88, 0xb5, 0xd2, 0xfa, 0xac, 0x76, - 0xce, 0xa2, 0x22, 0xce, 0x88, 0xb2, 0x20, 0x00, 0x94, 0x30, 0xa2, 0x10, 0x72, 0x88, - 0xb5, 0xd2, 0xe7, 0xac, 0x76, 0xce, 0xa2, 0x22, 0xce, 0x88, 0xb2, 0x28, 0x00, 0x9c, - 0x00, 0xb2, 0x20, 0x00, 0xaf, 0xcc, 0xa2, 0x11, 0x72, 0x88, 0xb5, 0xd2, 0xcf, 0xac, - 0x76, 0xce, 0xa2, 0x22, 0xce, 0x88, 0xb3, 0x28, 0x00, 0x9c, 0x00, 0xb3, 0x20, 0x00, - 0x3f, 0xcc, 0x90, 0x52, 0xa2, 0x02, 0xcc, 0x8e, 0x8b, 0x02, 0xa2, 0x0a, 0x72, 0x88, - 0x9c, 0x01, 0x48, 0x90, 0x10, 0xa2, 0x02, 0xce, 0x8e, 0xab, 0x04, 0xc4, 0x9a, 0x04, - 0xc6, 0x90, 0x00, 0xa2, 0x08, 0xcc, 0x8e, 0xab, 0x06, 0x31, 0x03, 0x9c, 0x00, 0x94, - 0xa4, 0xa2, 0x0a, 0x72, 0x88, 0x9c, 0x01, 0x52, 0x90, 0xdb, 0xa2, 0x02, 0xcc, 0x8e, - 0x90, 0x52, 0xa2, 0x02, 0xce, 0x8e, 0x30, 0xea, 0x9c, 0x00, 0x94, 0xac, 0x33, 0xf8, - 0x90, 0x10, 0xb6, 0x10, 0x04, 0x8b, 0x91, 0x00, 0xb6, 0x10, 0x20, 0x88, 0x99, 0x08, - 0x9c, 0x00, 0x94, 0x60, 0x91, 0x00, 0xb6, 0x10, 0x24, 0x88, 0x99, 0x20, 0x9c, 0x00, - 0x94, 0x5a, 0x90, 0x08, 0xb6, 0x10, 0x04, 0x8b, 0x91, 0x00, 0xb6, 0x10, 0x20, 0x88, - 0x99, 0x04, 0x9c, 0x00, 0x94, 0x3c, 0x91, 0x00, 0xb6, 0x10, 0x24, 0x88, 0x99, 0x02, - 0x9c, 0x00, 0x94, 0x2a, 0xc4, 0x99, 0xfb, 0xc6, 0xa8, 0x06, 0xa2, 0x08, 0xcc, 0x8e, - 0xa2, 0x0a, 0x72, 0x88, 0x9c, 0x01, 0x46, 0xa8, 0x04, 0xa2, 0x02, 0xce, 0x8e, 0x88, - 0x02, 0xa2, 0x02, 0xcc, 0x8e, 0x88, 0x03, 0xb6, 0x10, 0x00, 0x8b, 0x90, 0x01, 0x3f, - 0xce, 0x3f, 0xcc, 0x3c, 0x30, 0x16, 0x94, 0x4c, 0x95, 0x38, 0x30, 0x10, 0x94, 0x46, - 0x95, 0x4a, 0x30, 0x0a, 0x94, 0x40, 0x95, 0x6e, 0x30, 0x04, 0x94, 0x3a, 0x95, 0x68, - 0xae, 0xca, 0x05, 0xae, 0xca, 0x82, 0x00, 0xca, 0xfc, 0x3c, 0x3d, 0xa2, 0x0a, 0x72, - 0x88, 0x9c, 0x01, 0x4d, 0xa2, 0x10, 0x72, 0x88, 0xb5, 0xd1, 0xe3, 0x00, 0xa2, 0x0e, - 0x76, 0xab, 0x5e, 0xa2, 0x12, 0x72, 0x88, 0xb5, 0xd1, 0xd6, 0x00, 0xa2, 0x0e, 0x76, - 0xab, 0x51, 0xa2, 0x11, 0x72, 0x88, 0xb5, 0xd1, 0xc9, 0x00, 0xa2, 0x0e, 0x76, 0xab, - 0x00, 0xa2, 0x00, 0x74, 0xab, 0xc4, 0x99, 0xfb, 0xc6, 0xa8, 0x06, 0xa2, 0x08, 0xcc, - 0x8e, 0xa2, 0x0a, 0x72, 0x88, 0x9c, 0x01, 0x46, 0xa8, 0x04, 0xa2, 0x02, 0xce, 0x8e, - 0x88, 0x02, 0xa2, 0x02, 0xcc, 0x8e, 0x88, 0x03, 0xb6, 0x10, 0x00, 0x8b, 0x00, 0x3f, - 0xce, 0x3f, 0xcc, 0x3c, 0x33, 0x12, 0x91, 0x00, 0xae, 0xca, 0xaa, 0xc8, 0x41, 0x3c, - 0xae, 0xca, 0xb6, 0x10, 0x1c, 0x88, 0x96, 0xc8, 0x17, 0x41, 0x70, 0x9a, 0x01, 0x3c, - 0xaf, 0xcc, 0x9c, 0x00, 0x94, 0x21, 0xb2, 0x20, 0x2e, 0x30, 0x0f, 0xa2, 0x0a, 0x72, - 0x88, 0x9c, 0x01, 0x45, 0xb2, 0x28, 0x2e, 0x30, 0x03, 0x3f, 0xcc, 0x3c, 0x90, 0x40, - 0x01, 0xd9, 0xc6, 0xa8, 0xe2, 0xba, 0x02, 0x00, 0xab, 0xe2, 0x3c, 0xb2, 0x20, 0x2e, - 0x30, 0x0f, 0xa2, 0x0a, 0x72, 0x88, 0x9c, 0x01, 0x7b, 0xb2, 0x28, 0x2e, 0x30, 0x03, - 0x3f, 0xcc, 0x3c, 0x90, 0x40, 0xda, 0xc6, 0xa8, 0xe2, 0xb9, 0xfd, 0xff, 0xab, 0xe2, - 0x3c, 0xb2, 0x20, 0x2e, 0xc4, 0x01, 0x99, 0x01, 0x3c, 0xaf, 0xcc, 0xab, 0xca, 0xa2, - 0x22, 0xce, 0x88, 0xb2, 0x28, 0x00, 0x9c, 0x00, 0xb2, 0x20, 0x00, 0x82, 0x02, 0xcc, - 0xf8, 0x82, 0x00, 0xca, 0xfc, 0x50, 0x82, 0x01, 0xca, 0xfc, 0x4e, 0x82, 0x02, 0xca, - 0xfc, 0x4c, 0x90, 0x00, 0xc5, 0x3f, 0xcc, 0x3c, 0x90, 0x53, 0x66, 0x90, 0x71, 0x69, - 0x90, 0x71, 0x6c, 0xaf, 0xcc, 0xab, 0xca, 0xa2, 0x22, 0xce, 0x88, 0xb2, 0x28, 0x00, - 0x9c, 0x00, 0xb2, 0x20, 0x00, 0x82, 0x02, 0xcc, 0xf8, 0xa2, 0x0a, 0x72, 0x88, 0x9d, - 0x01, 0x55, 0x82, 0x00, 0xca, 0xfc, 0x4a, 0x82, 0x08, 0xca, 0xfc, 0x48, 0x41, 0xc5, - 0x3f, 0xcc, 0x3c, 0x90, 0x5e, 0x66, 0x90, 0x61, 0x69, 0x82, 0x00, 0xca, 0xfc, 0x94, - 0x26, 0x82, 0x05, 0xca, 0xfc, 0x94, 0x25, 0x82, 0x09, 0xca, 0xfc, 0x94, 0x24, 0x82, - 0x06, 0xca, 0xfc, 0x94, 0x23, 0x82, 0x0a, 0xca, 0xfc, 0x5e, 0x82, 0x07, 0xca, 0xfc, - 0x94, 0x22, 0x82, 0x0c, 0xca, 0xfc, 0x94, 0x21, 0x3f, 0xcc, 0x3c, 0x91, 0x52, 0x90, - 0xdb, 0x5d, 0x90, 0x61, 0x91, 0x10, 0x58, 0x90, 0xf9, 0x91, 0x52, 0x53, 0x90, 0xdb, - 0x91, 0x61, 0x4e, 0x90, 0xdb, 0x91, 0xed, 0x49, 0x90, 0xdb, 0x91, 0x61, 0x44, 0x90, - 0xf9, 0x91, 0x61, 0xb2, 0x20, 0x02, 0xc5, 0xb2, 0x28, 0x02, 0xa8, 0xca, 0xc5, 0x3f, - 0xcc, 0x3c, 0xab, 0xca, 0xaf, 0xcc, 0xa2, 0x22, 0xce, 0x88, 0xb2, 0x28, 0x00, 0x9c, - 0x00, 0xb2, 0x20, 0x00, 0x82, 0x00, 0xcc, 0xf8, 0x82, 0x00, 0xca, 0xfc, 0x47, 0xc4, - 0x9a, 0x20, 0xc6, 0x3f, 0xcc, 0x3c, 0x90, 0x20, 0x01, 0xd9, 0xc6, 0x3f, 0xcc, 0x3c, - 0xab, 0xca, 0xaf, 0xcc, 0xa2, 0x22, 0xce, 0x88, 0xb2, 0x28, 0x00, 0x9c, 0x00, 0xb2, - 0x20, 0x00, 0xa8, 0xca, 0x99, 0x08, 0x9c, 0x00, 0x4b, 0xa2, 0x18, 0xcc, 0x88, 0x9a, - 0x40, 0xa2, 0x18, 0xcc, 0x8b, 0x4b, 0x90, 0x40, 0x01, 0xa2, 0x18, 0xcc, 0xd9, 0xa2, - 0x18, 0xcc, 0x8b, 0x94, 0x30, 0xae, 0xca, 0x91, 0x00, 0xaf, 0xc8, 0x99, 0x01, 0x9d, - 0x00, 0x82, 0x02, 0xca, 0xfa, 0x3f, 0xc8, 0xaf, 0xc8, 0x99, 0x02, 0x9d, 0x00, 0x82, - 0x04, 0xca, 0xfa, 0x3f, 0xc8, 0xaf, 0xc8, 0x99, 0x04, 0x9d, 0x00, 0x82, 0x08, 0xca, - 0xfa, 0x3f, 0xc8, 0x99, 0x10, 0x9d, 0x00, 0x82, 0x20, 0xca, 0xfa, 0xa2, 0x16, 0xcc, - 0x88, 0x3f, 0xcc, 0x3c, 0xaf, 0xcc, 0xe7, 0xab, 0xca, 0x82, 0x68, 0xca, 0xf8, 0xb2, - 0x28, 0x00, 0x9c, 0x00, 0xb2, 0x20, 0x00, 0x00, 0xa2, 0x12, 0xcc, 0x8e, 0x8b, 0x10, - 0x00, 0xa2, 0x14, 0xcc, 0x8e, 0x8b, 0x11, 0x96, 0x10, 0x11, 0x96, 0x10, 0x0a, 0x82, - 0x2e, 0x10, 0xd9, 0x82, 0x40, 0x11, 0xd9, 0x88, 0x10, 0x96, 0x11, 0xda, 0xad, 0xca, - 0xfa, 0xab, 0x12, 0xa2, 0x10, 0xcc, 0x88, 0x99, 0x07, 0x9c, 0x01, 0xa2, 0x10, 0xcc, - 0x88, 0x99, 0x07, 0x9c, 0x01, 0x4e, 0x9c, 0x02, 0x51, 0x9c, 0x06, 0x4e, 0x9c, 0x04, - 0x48, 0x9c, 0x05, 0x4b, 0x00, 0x4f, 0x90, 0x40, 0x49, 0x90, 0x08, 0x46, 0x90, 0x02, - 0x43, 0x90, 0x04, 0x40, 0xad, 0xca, 0xab, 0xa0, 0xc8, 0x12, 0xfa, 0xad, 0xca, 0xa8, - 0x99, 0x02, 0x9c, 0x00, 0x55, 0x90, 0x03, 0x01, 0xab, 0xca, 0xa2, 0x16, 0xcc, 0x88, - 0x96, 0xca, 0xf9, 0xa2, 0x16, 0xcc, 0x8b, 0x3f, 0xcc, 0xa8, 0x12, 0x3c, 0xa2, 0x16, - 0xcc, 0x88, 0x9a, 0x03, 0x6f, 0xaf, 0xcc, 0xb2, 0x28, 0x00, 0x9c, 0x00, 0xb2, 0x20, - 0x00, 0x82, 0x02, 0xca, 0xfc, 0x58, 0x82, 0x04, 0xca, 0xfc, 0x56, 0x82, 0x01, 0xca, - 0xfc, 0x54, 0x82, 0x08, 0xca, 0xfc, 0x52, 0x86, 0x01, 0x00, 0xca, 0xfc, 0x4f, 0x3f, - 0xcc, 0x3c, 0x90, 0x06, 0x4b, 0x90, 0x05, 0x48, 0x90, 0x01, 0x45, 0x90, 0x04, 0x42, - 0x90, 0x00, 0xab, 0xca, 0x9c, 0x06, 0x30, 0x17, 0x90, 0x07, 0x01, 0xa2, 0x08, 0xcc, - 0xd9, 0x96, 0xca, 0xfa, 0xa2, 0x08, 0xcc, 0x8b, 0x82, 0x06, 0xca, 0xfc, 0x30, 0x08, - 0x3f, 0xcc, 0x3c, 0xc4, 0x9a, 0x40, 0xc6, 0x3c, 0x90, 0x40, 0x01, 0xd9, 0xc6, 0x3c, - 0xaf, 0xcc, 0xb2, 0x10, 0x00, 0xab, 0xca, 0xa2, 0x22, 0xcc, 0x88, 0x8b, 0x12, 0xa2, - 0x26, 0xcc, 0x88, 0x8b, 0x10, 0xa2, 0x2a, 0xcc, 0x88, 0x8b, 0x11, 0x82, 0x03, 0x12, - 0xda, 0x90, 0x20, 0x01, 0xa0, 0xc8, 0x10, 0xd9, 0x82, 0x00, 0xca, 0xfd, 0x82, 0x20, - 0x10, 0xda, 0x90, 0x02, 0x01, 0xa0, 0xc8, 0x10, 0xd9, 0x82, 0x00, 0xca, 0xfd, 0x82, - 0x02, 0x10, 0xda, 0x90, 0x01, 0x01, 0xa0, 0xc8, 0x10, 0xd9, 0x82, 0x00, 0xca, 0xfd, - 0x82, 0x01, 0x10, 0xda, 0x90, 0x10, 0x01, 0xa0, 0xc8, 0x11, 0xd9, 0x82, 0x00, 0xca, - 0xfd, 0x82, 0x10, 0x11, 0xda, 0x00, 0xa2, 0x24, 0xcc, 0x8e, 0x00, 0xa2, 0x28, 0xcc, - 0x8e, 0x88, 0x12, 0xa2, 0x22, 0xcc, 0x8b, 0x88, 0x10, 0xa2, 0x26, 0xcc, 0x8b, 0x88, - 0x11, 0xa2, 0x2a, 0xcc, 0x8b, 0x3f, 0xcc, 0x3c, 0xaf, 0xcc, 0x90, 0x04, 0xb2, 0x10, - 0x04, 0xc6, 0xc4, 0x96, 0xc8, 0x12, 0x64, 0x3f, 0xcc, 0x3c, 0xaf, 0xcc, 0x90, 0x04, - 0xb2, 0x10, 0x04, 0xc6, 0xc4, 0x96, 0xc8, 0x12, 0x64, 0xb6, 0x10, 0x00, 0x88, 0x9a, - 0x01, 0xb6, 0x10, 0x00, 0x8b, 0x90, 0x10, 0xc6, 0x3f, 0xcc, 0x3c, 0xc4, 0xa2, 0x01, - 0xcc, 0xda, 0xa2, 0x02, 0xcc, 0xda, 0xa2, 0x03, 0xcc, 0xda, 0xa2, 0x04, 0xcc, 0xda, - 0xa2, 0x05, 0xcc, 0xda, 0x9c, 0x00, 0x94, 0x85, 0xc4, 0xb6, 0xfe, 0xe0, 0x8b, 0xa2, - 0x01, 0xcc, 0x88, 0xb6, 0xfe, 0xe1, 0x8b, 0xa2, 0x02, 0xcc, 0x88, 0xb6, 0xfe, 0xe2, - 0x8b, 0xa2, 0x03, 0xcc, 0x88, 0xb6, 0xfe, 0xe3, 0x8b, 0xa2, 0x04, 0xcc, 0x88, 0xb6, - 0xfe, 0xe4, 0x8b, 0xa2, 0x05, 0xcc, 0x88, 0xb6, 0xfe, 0xe5, 0x8b, 0xa8, 0x02, 0xb6, - 0xfe, 0xe6, 0x8b, 0xa8, 0x0a, 0xb6, 0xfe, 0xe7, 0x8b, 0xa8, 0x04, 0xb6, 0xfe, 0xe8, - 0xab, 0xa8, 0x06, 0xb6, 0xfe, 0xea, 0xab, 0xa8, 0x08, 0xb6, 0xfe, 0xec, 0xab, 0x3c, - 0xab, 0x6e, 0xae, 0xca, 0xab, 0x70, 0x91, 0x10, 0xb4, 0x80, 0x06, 0xb6, 0x11, 0x26, - 0x88, 0x8b, 0x6c, 0xa8, 0xcc, 0xb6, 0x11, 0x26, 0x8b, 0x3c, 0xb6, 0x10, 0x3a, 0x88, - 0x8b, 0x6d, 0xa8, 0xcc, 0xb6, 0x10, 0x3a, 0x8b, 0x3c, 0xab, 0xca, 0x90, 0x08, 0x01, - 0xb6, 0x10, 0x02, 0xd9, 0x82, 0x00, 0xca, 0xfd, 0x9a, 0x08, 0xb6, 0x10, 0x02, 0x8b, - 0x3c, 0x82, 0x00, 0x7d, 0xdc, 0x3c, 0x00, 0x8b, 0x7d, 0x34, 0xd3, 0xb6, 0x10, 0x00, - 0x88, 0x99, 0xfe, 0xb6, 0x10, 0x00, 0x8b, 0x00, 0x80, 0x6c, 0xcc, 0xab, 0x34, 0x47, - 0x80, 0x6d, 0xcc, 0xab, 0x34, 0x40, 0x00, 0x34, 0x36, 0xb6, 0x10, 0x00, 0x88, 0x9a, - 0x01, 0xb6, 0x10, 0x00, 0x8b, 0x34, 0xf9, 0xb7, 0x00, 0x00, 0x02, 0xb7, 0x00, 0x00, - 0x04, 0xb7, 0x00, 0x00, 0x06, 0xac, 0x74, 0xcc, 0x82, 0x34, 0xcc, 0xf8, 0x00, 0xb5, - 0xf6, 0xe1, 0x91, 0x20, 0xb4, 0x7f, 0x8c, 0x90, 0x04, 0x3c, 0xb6, 0x10, 0x00, 0x88, - 0xb7, 0x00, 0x00, 0x12, 0x96, 0xc8, 0x10, 0x30, 0x40, 0xb1, 0x10, 0x80, 0xc4, 0xad, - 0xca, 0x8b, 0xa2, 0x01, 0xcc, 0x88, 0xa2, 0x02, 0xca, 0x8b, 0xa2, 0x02, 0xcc, 0x88, - 0xa2, 0x04, 0xca, 0x8b, 0xa2, 0x03, 0xcc, 0x88, 0xa2, 0x06, 0xca, 0x8b, 0xa2, 0x04, - 0xcc, 0x88, 0xa2, 0x08, 0xca, 0x8b, 0xa2, 0x05, 0xcc, 0x88, 0xa2, 0x0a, 0xca, 0x8b, - 0x82, 0x00, 0x12, 0xfc, 0x4a, 0xb6, 0x10, 0x00, 0x88, 0x9a, 0x01, 0xb6, 0x10, 0x00, - 0x8b, 0x00, 0x3c, 0xb6, 0x10, 0x00, 0x88, 0x99, 0xfe, 0xb6, 0x10, 0x00, 0x8b, 0xb7, - 0x00, 0x01, 0x12, 0x3c, 0x3c, 0xaf, 0xcc, 0xb2, 0x10, 0x00, 0xc4, 0xab, 0xca, 0x82, - 0x01, 0x02, 0xfc, 0x94, 0x25, 0x82, 0x00, 0x7d, 0xdd, 0x46, 0xa8, 0xca, 0xc6, 0x3f, - 0xcc, 0x3c, 0xaf, 0xca, 0x34, 0xc7, 0x3f, 0xca, 0x90, 0x40, 0x01, 0xb6, 0x10, 0x2a, - 0xd9, 0xb6, 0x10, 0x2a, 0x8b, 0x90, 0x01, 0x01, 0x96, 0xca, 0xf9, 0xab, 0xca, 0x7f, - 0x00, 0xc5, 0x40, 0xad, 0x0a, 0xa8, 0xb6, 0xda, 0xd6, 0xab, 0xa2, 0xa6, 0xcc, 0x8b, - 0x8c, 0xc9, 0xc8, 0xa2, 0xa4, 0xcc, 0x8b, 0xa2, 0x02, 0x0a, 0xa8, 0xb6, 0xda, 0xd8, - 0xab, 0xa2, 0xa2, 0xcc, 0x8b, 0x8c, 0xc9, 0xc8, 0xa2, 0xa0, 0xcc, 0x8b, 0xb7, 0x02, - 0x00, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xa6, 0x01, 0x2e, 0xcc, 0x88, 0x9c, 0x00, 0x4e, - 0xae, 0x02, 0x03, 0xe7, 0xae, 0x02, 0xae, 0x04, 0xf7, 0xae, 0x04, 0xaa, 0xc8, 0x6d, - 0xa8, 0x02, 0x01, 0x03, 0xb8, 0x00, 0x01, 0xab, 0x02, 0xa8, 0x04, 0x01, 0x82, 0x00, - 0xc8, 0xe8, 0xab, 0x04, 0xa2, 0x02, 0x06, 0xfd, 0x94, 0x61, 0xa2, 0x02, 0x06, 0xfc, - 0x94, 0x53, 0xad, 0x06, 0xa8, 0x01, 0x03, 0xb8, 0x00, 0x01, 0xab, 0x02, 0xa2, 0x02, - 0x06, 0xa8, 0x01, 0x82, 0x00, 0xc8, 0xe8, 0xab, 0x04, 0xb7, 0x00, 0x00, 0x06, 0x82, - 0x0f, 0x06, 0xfc, 0x94, 0x2c, 0xb7, 0x02, 0x00, 0x10, 0xb7, 0x00, 0x00, 0x12, 0xa8, - 0x06, 0xae, 0x10, 0x03, 0xe7, 0xae, 0x10, 0xae, 0x12, 0xf7, 0xae, 0x12, 0xaa, 0xc8, - 0x6d, 0xa0, 0x04, 0x12, 0xfd, 0x4f, 0xa0, 0x04, 0x12, 0xfc, 0x44, 0xa9, 0x06, 0x95, - 0x2a, 0xa0, 0x02, 0x10, 0xfd, 0x41, 0x69, 0xa8, 0x06, 0xa6, 0x01, 0x2e, 0xcc, 0x8b, - 0x48, 0xa8, 0x02, 0xad, 0x06, 0xfd, 0x42, 0x95, 0x59, 0xb7, 0x02, 0x00, 0x10, 0xb7, - 0x00, 0x00, 0x12, 0xa6, 0x01, 0x26, 0xcc, 0x88, 0x9c, 0x00, 0x4e, 0xae, 0x10, 0x03, - 0xe7, 0xae, 0x10, 0xae, 0x12, 0xf7, 0xae, 0x12, 0xaa, 0xc8, 0x6d, 0xa8, 0x10, 0x03, - 0x01, 0xb8, 0x00, 0x01, 0xab, 0x10, 0xa8, 0x12, 0x01, 0x82, 0x00, 0xc8, 0xe8, 0xab, - 0x12, 0xa2, 0x02, 0x08, 0xfd, 0x94, 0x58, 0xa2, 0x02, 0x08, 0xfc, 0x94, 0x59, 0xad, - 0x08, 0xa8, 0x03, 0x01, 0xb8, 0x00, 0x01, 0xab, 0x02, 0xa2, 0x02, 0x08, 0xa8, 0x01, - 0x82, 0x00, 0xc8, 0xe8, 0xab, 0x04, 0xb7, 0x00, 0x00, 0x0a, 0x82, 0x0f, 0x0a, 0xfc, - 0x94, 0x2c, 0xb7, 0x02, 0x00, 0x06, 0xb7, 0x00, 0x00, 0x08, 0xa8, 0x0a, 0xae, 0x06, - 0x03, 0xe7, 0xae, 0x06, 0xae, 0x08, 0xf7, 0xae, 0x08, 0xaa, 0xc8, 0x6d, 0xa0, 0x04, - 0x08, 0xfd, 0x4f, 0xa0, 0x04, 0x08, 0xfc, 0x44, 0xa9, 0x0a, 0x95, 0x2a, 0xa0, 0x02, - 0x06, 0xfd, 0x41, 0x69, 0xa8, 0x0a, 0xa6, 0x01, 0x26, 0xcc, 0x8b, 0x82, 0x01, 0xca, - 0xfa, 0xb4, 0xfe, 0x8c, 0xa8, 0x10, 0xad, 0x08, 0xfd, 0x6c, 0x95, 0x5f, 0x90, 0x00, - 0x3c, 0xaf, 0xcc, 0xab, 0xca, 0xa2, 0x22, 0xce, 0x88, 0xe7, 0xb8, 0x00, 0x54, 0xae, - 0xca, 0xad, 0xca, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xb2, 0x28, 0x00, 0x9c, 0x00, 0xb2, - 0x20, 0x00, 0xad, 0xca, 0xa8, 0x9d, 0xff, 0x90, 0xff, 0xa2, 0x2a, 0xcc, 0x8b, 0xab, - 0xcc, 0xad, 0xca, 0xa8, 0x02, 0x96, 0xcc, 0xeb, 0xad, 0xca, 0xab, 0x3f, 0xcc, 0x3c, - 0xaf, 0xcc, 0xa2, 0x22, 0xce, 0x88, 0xb2, 0x28, 0x00, 0x9c, 0x00, 0xb2, 0x20, 0x00, - 0xa2, 0x2c, 0xcc, 0x88, 0xab, 0xca, 0xa2, 0x22, 0xce, 0x88, 0xe7, 0xb8, 0x00, 0x54, - 0xad, 0xc8, 0xa8, 0x96, 0xca, 0xf8, 0x3f, 0xcc, 0x3c, 0xaf, 0xcc, 0xab, 0xca, 0xa2, - 0x22, 0xce, 0x88, 0xb2, 0x28, 0x00, 0x9c, 0x00, 0xb2, 0x20, 0x00, 0x82, 0x01, 0xca, - 0xfc, 0x5c, 0x90, 0x10, 0x82, 0x00, 0xca, 0xfc, 0x4b, 0xa2, 0x06, 0xcc, 0xda, 0xa2, - 0x06, 0xcc, 0x8b, 0x3f, 0xcc, 0x3c, 0x01, 0xa2, 0x06, 0xcc, 0xd9, 0xa2, 0x06, 0xcc, - 0x8b, 0x6c, 0xa2, 0x2a, 0xcc, 0x88, 0xa2, 0x2a, 0xcc, 0x8b, 0x90, 0x10, 0x01, 0xa2, - 0x04, 0xcc, 0xd9, 0xa2, 0x04, 0xcc, 0x8b, 0x95, 0x2f, 0x3c, 0x3c, 0xaf, 0xcc, 0xab, - 0xca, 0xb7, 0x00, 0x00, 0x10, 0xb7, 0x00, 0x00, 0x12, 0x80, 0x7e, 0x12, 0xfc, 0x94, - 0x4f, 0xa8, 0x12, 0xb5, 0xca, 0xbe, 0xa2, 0x4e, 0x76, 0xa8, 0x9c, 0x08, 0x43, 0xa9, - 0x12, 0x74, 0xa2, 0x64, 0x76, 0xa8, 0x96, 0xca, 0xfc, 0x4f, 0x90, 0x02, 0x96, 0xca, - 0xfd, 0x41, 0x71, 0xa2, 0x62, 0x76, 0xa8, 0x9c, 0x04, 0x41, 0x79, 0x91, 0x01, 0xa2, - 0x22, 0x76, 0x88, 0xb5, 0xfb, 0x3d, 0xb7, 0x15, 0x5c, 0x02, 0xb7, 0x00, 0x00, 0x04, - 0xb7, 0x02, 0x00, 0x06, 0xac, 0x76, 0xcc, 0x82, 0x4c, 0xcc, 0xf8, 0xa2, 0x22, 0x76, - 0x88, 0xb5, 0xf3, 0xeb, 0xb7, 0x00, 0x01, 0x10, 0x95, 0x41, 0x82, 0x00, 0x10, 0xfd, - 0x4c, 0x00, 0xb5, 0xca, 0x57, 0xa2, 0x54, 0x74, 0xa8, 0x96, 0xca, 0xfc, 0x43, 0x3f, - 0xcc, 0x3c, 0xb5, 0xfb, 0xeb, 0x66, 0x97, 0x00, 0xd0, 0x83, 0x44, 0x01, 0x91, 0x8b, - 0x40, 0x40, 0x83, 0xcc, 0x01, 0x91, 0x8b, 0x83, 0x00, 0x01, 0x86, 0xab, 0x83, 0x00, - 0x01, 0x8a, 0xab, 0x83, 0x00, 0x01, 0x88, 0xab, 0x83, 0x00, 0x01, 0x8c, 0xab, 0x83, - 0x44, 0x01, 0x91, 0x8b, 0x96, 0xd0, 0x0d, 0xa8, 0xbe, 0x99, 0x03, 0x9c, 0x00, 0x94, - 0x4c, 0xb2, 0x10, 0x00, 0x00, 0xc5, 0xb2, 0x10, 0x04, 0x90, 0x04, 0xc6, 0xc4, 0x96, - 0xc8, 0x12, 0x64, 0xb2, 0x10, 0x5e, 0x90, 0x0b, 0xc5, 0xb2, 0x10, 0x22, 0x90, 0x03, - 0xc5, 0xb2, 0x10, 0x26, 0x90, 0x23, 0xc5, 0xb2, 0x10, 0x2a, 0x90, 0x10, 0xc5, 0xb2, - 0x10, 0x3a, 0x90, 0x3f, 0xc5, 0xb2, 0x10, 0x32, 0x90, 0x20, 0xc5, 0x91, 0x20, 0xb2, - 0x11, 0x7e, 0x00, 0xc5, 0x02, 0x82, 0x02, 0xcc, 0xeb, 0xaa, 0xca, 0x69, 0xb2, 0x10, - 0x00, 0x90, 0x01, 0xc6, 0x96, 0xd0, 0x0a, 0xb0, 0x07, 0xef, 0x9e, 0x32, 0x03, 0xae, - 0xce, 0xd7, 0xae, 0xce, 0xd7, 0x03, 0xae, 0xce, 0xd7, 0xae, 0xce, 0xd7, 0xab, 0x58, - 0xa8, 0xbe, 0x99, 0x0c, 0xc7, 0xc7, 0x99, 0x03, 0x04, 0xab, 0xca, 0xb2, 0x20, 0x00, - 0x96, 0xd0, 0x1b, 0x96, 0xd0, 0x1c, 0x97, 0xe7, 0xd2, 0xb7, 0x00, 0x00, 0x02, 0xac, - 0xca, 0x04, 0xa8, 0xcc, 0x30, 0x51, 0xa9, 0x02, 0xb2, 0x28, 0x00, 0xac, 0x04, 0xca, - 0xaa, 0xca, 0x71, 0x96, 0xd0, 0x0b, 0xa8, 0xbe, 0x99, 0x0c, 0x9d, 0x00, 0x96, 0xd0, - 0x0c, 0xb0, 0x50, 0x06, 0xb6, 0xff, 0xa6, 0xab, 0x05, 0xb6, 0xff, 0xa4, 0xab, 0xb0, - 0x50, 0x07, 0xb6, 0xff, 0xaa, 0xab, 0x05, 0xb6, 0xff, 0xa8, 0xab, 0xb0, 0x50, 0x08, - 0xb6, 0xff, 0xae, 0xab, 0x05, 0xb6, 0xff, 0xac, 0xab, 0xb0, 0x50, 0x09, 0xb6, 0xff, - 0xb2, 0xab, 0x05, 0xb6, 0xff, 0xb0, 0xab, 0x3c, 0xae, 0xca, 0x05, 0x9c, 0x00, 0x59, - 0xae, 0xca, 0x4e, 0xab, 0xca, 0x00, 0xc5, 0xaf, 0xca, 0x91, 0xff, 0x90, 0x01, 0xa2, - 0x3c, 0xcc, 0x8e, 0xa2, 0x3c, 0xcc, 0x88, 0x96, 0xc8, 0x10, 0x7e, 0x3f, 0xca, 0xac, - 0xcc, 0xce, 0x82, 0x30, 0xce, 0xf8, 0x92, 0xce, 0xd4, 0x9d, 0x11, 0x4a, 0xc7, 0x0e, - 0x90, 0x01, 0x06, 0xd6, 0x0b, 0x09, 0x8f, 0x0e, 0xac, 0xca, 0xcc, 0xb6, 0xff, 0x02, - 0xa8, 0x9c, 0x02, 0x54, 0xa2, 0x78, 0xcc, 0x88, 0x9a, 0x08, 0xa2, 0x78, 0xcc, 0x8b, - 0xa2, 0x76, 0xcc, 0x88, 0x9a, 0x08, 0xa2, 0x76, 0xcc, 0x8b, 0x00, 0xa2, 0x4c, 0xcc, - 0x8b, 0x88, 0x59, 0x99, 0x7f, 0xa2, 0x1a, 0xcc, 0x8e, 0x90, 0xff, 0xa2, 0x1c, 0xcc, - 0x8e, 0x88, 0x59, 0xa2, 0x22, 0xcc, 0x8e, 0x90, 0xff, 0xa2, 0x24, 0xcc, 0x8e, 0xa8, - 0x02, 0xb5, 0xf9, 0x00, 0x90, 0x2f, 0xa2, 0x16, 0xcc, 0x8e, 0x00, 0xa2, 0x18, 0xcc, - 0x8e, 0x00, 0xa2, 0x12, 0xcc, 0x8e, 0x00, 0xa2, 0x14, 0xcc, 0x8e, 0x00, 0xa2, 0x04, - 0xcc, 0x8e, 0x90, 0x60, 0xa2, 0x06, 0xcc, 0x8e, 0x90, 0xa6, 0xa2, 0x08, 0xcc, 0x8e, - 0x90, 0x98, 0xa2, 0x02, 0xcc, 0x8e, 0xc4, 0x9a, 0x21, 0xc5, 0x3c, 0xa2, 0x06, 0xcc, - 0xa8, 0xb2, 0x10, 0x00, 0x91, 0x5a, 0xbc, 0x20, 0x33, 0xb4, 0x01, 0x28, 0xbc, 0x20, - 0x35, 0xb4, 0x01, 0x30, 0xbc, 0x20, 0x48, 0x94, 0x69, 0xbc, 0x20, 0x47, 0x94, 0x47, - 0xbc, 0x20, 0x34, 0x94, 0x20, 0xbc, 0x20, 0x36, 0xb4, 0x01, 0x22, 0xbc, 0x20, 0x49, - 0x94, 0x72, 0xbc, 0x20, 0x4a, 0x94, 0x8b, 0xbc, 0x20, 0x51, 0x94, 0xa4, 0xbc, 0x20, - 0x52, 0x94, 0xbd, 0xbc, 0x20, 0x54, 0x94, 0xd6, 0x3c, 0xa6, 0x01, 0x36, 0xcc, 0x88, - 0xd6, 0xa6, 0x01, 0x34, 0xcc, 0x88, 0xa2, 0x01, 0xce, 0x8b, 0xa6, 0x01, 0x32, 0xcc, - 0x88, 0xa2, 0x02, 0xce, 0x8b, 0xa6, 0x01, 0x30, 0xcc, 0x88, 0xa2, 0x03, 0xce, 0x8b, - 0x3c, 0xa6, 0x01, 0x46, 0xcc, 0x88, 0xab, 0x02, 0xa6, 0x01, 0x44, 0xcc, 0x88, 0x8b, - 0x03, 0xa8, 0x02, 0xf1, 0xa6, 0x01, 0x42, 0xcc, 0x88, 0x99, 0x0f, 0xad, 0xca, 0xfa, - 0xf1, 0x3c, 0xa6, 0x01, 0x5e, 0xcc, 0x88, 0xab, 0x02, 0xa6, 0x01, 0x5c, 0xcc, 0x88, - 0x8b, 0x03, 0xa8, 0x02, 0xf1, 0xa6, 0x01, 0x5a, 0xcc, 0x88, 0x99, 0x0f, 0xa2, 0x06, - 0xca, 0xfa, 0xf1, 0x3c, 0xa6, 0x01, 0x6e, 0xcc, 0x88, 0xab, 0x02, 0xa6, 0x01, 0x6c, - 0xcc, 0x88, 0x8b, 0x03, 0xa8, 0x02, 0xf1, 0xa6, 0x01, 0x6a, 0xcc, 0x88, 0x99, 0x0f, - 0xa2, 0x0a, 0xca, 0xfa, 0xf1, 0x3c, 0xa6, 0x01, 0x76, 0xcc, 0x88, 0xab, 0x02, 0xa6, - 0x01, 0x74, 0xcc, 0x88, 0x8b, 0x03, 0xa8, 0x02, 0xf1, 0xa6, 0x01, 0x72, 0xcc, 0x88, - 0x99, 0x0f, 0xa2, 0x0c, 0xca, 0xfa, 0xf1, 0x3c, 0xa6, 0x01, 0x4e, 0xcc, 0x88, 0xab, - 0x02, 0xa6, 0x01, 0x4c, 0xcc, 0x88, 0x8b, 0x03, 0xa8, 0x02, 0xf1, 0xa6, 0x01, 0x4a, - 0xcc, 0x88, 0x99, 0x0f, 0xa2, 0x02, 0xca, 0xfa, 0xf1, 0x3c, 0xa6, 0x01, 0x56, 0xcc, - 0x88, 0xab, 0x02, 0xa6, 0x01, 0x54, 0xcc, 0x88, 0x8b, 0x03, 0xa8, 0x02, 0xf1, 0xa6, - 0x01, 0x52, 0xcc, 0x88, 0x99, 0x0f, 0xa2, 0x04, 0xca, 0xfa, 0xf1, 0x3c, 0xa6, 0x01, - 0x66, 0xcc, 0x88, 0xab, 0x02, 0xa6, 0x01, 0x64, 0xcc, 0x88, 0x8b, 0x03, 0xa8, 0x02, - 0xf1, 0xa6, 0x01, 0x62, 0xcc, 0x88, 0x99, 0x0f, 0xa2, 0x08, 0xca, 0xfa, 0xf1, 0x3c, - 0xb6, 0xda, 0xd6, 0xa8, 0xb9, 0xff, 0x00, 0xf1, 0xb6, 0xda, 0xd8, 0xa8, 0xf1, 0x3c, - 0xa6, 0x01, 0x26, 0xcc, 0x88, 0xf1, 0x3c, 0xa6, 0x01, 0x2e, 0xcc, 0x88, 0xf1, 0x3c, - 0xb7, 0x02, 0x00, 0x02, 0xb7, 0x00, 0x00, 0x04, 0x9c, 0x00, 0x4e, 0xae, 0x02, 0x03, - 0xe7, 0xae, 0x02, 0xae, 0x04, 0xf7, 0xae, 0x04, 0xaa, 0xc8, 0x6d, 0xa8, 0x02, 0x01, - 0x03, 0xb8, 0x00, 0x01, 0xab, 0x02, 0xa8, 0x04, 0x01, 0x82, 0x00, 0xc8, 0xe8, 0xab, - 0x04, 0x3c, 0xa2, 0x2f, 0xce, 0xdc, 0x3c, 0xa2, 0x2f, 0xce, 0x8b, 0xab, 0xca, 0xa2, - 0x54, 0xce, 0xa8, 0x9c, 0x00, 0x94, 0x26, 0x9c, 0x01, 0x41, 0x3c, 0xa2, 0x1c, 0x72, - 0xa8, 0x82, 0x00, 0xca, 0xfd, 0x04, 0x82, 0x00, 0xca, 0xfc, 0x05, 0xa2, 0x1c, 0x72, - 0xab, 0xb7, 0x01, 0x06, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0x00, - 0xb4, 0xc8, 0x93, 0xa2, 0x1a, 0x72, 0xa8, 0x82, 0x00, 0xca, 0xfd, 0x04, 0x82, 0x00, - 0xca, 0xfc, 0x05, 0xa2, 0x1a, 0x72, 0xab, 0xb7, 0x01, 0x06, 0x02, 0xb7, 0x00, 0x00, - 0x04, 0xb7, 0x00, 0x00, 0x06, 0x00, 0xb4, 0xc8, 0x71, 0xa2, 0x15, 0x72, 0x88, 0x9c, - 0x00, 0x4d, 0xa2, 0x2f, 0xce, 0x88, 0x9d, 0x00, 0x46, 0x90, 0x01, 0xb5, 0xf7, 0xcc, - 0x45, 0x90, 0x00, 0xb5, 0xf7, 0xc6, 0xb7, 0x62, 0x5a, 0x02, 0xb7, 0x00, 0x02, 0x04, - 0xb7, 0x04, 0x00, 0x06, 0xac, 0xce, 0xcc, 0x82, 0x34, 0xcc, 0xf8, 0xa2, 0x22, 0xce, - 0x88, 0xb4, 0xf0, 0x17, 0xa2, 0x32, 0xce, 0x88, 0x9c, 0x00, 0x94, 0x25, 0xa2, 0x54, - 0xce, 0xa8, 0xb5, 0xc6, 0xab, 0xa2, 0x00, 0x78, 0xa8, 0xab, 0x02, 0xa2, 0x02, 0x78, - 0xa8, 0xab, 0x04, 0xb7, 0x04, 0x00, 0x06, 0xac, 0xce, 0xcc, 0x82, 0x34, 0xcc, 0xf8, - 0xa2, 0x22, 0xce, 0x88, 0xb4, 0xef, 0xea, 0xb7, 0x00, 0x00, 0x02, 0xb7, 0x00, 0x00, - 0x04, 0xb7, 0x04, 0x00, 0x06, 0xac, 0xce, 0xcc, 0x82, 0x34, 0xcc, 0xf8, 0xa2, 0x22, - 0xce, 0x88, 0xb4, 0xef, 0xd0, 0xa2, 0x2d, 0xce, 0x88, 0x9c, 0x00, 0x94, 0x1f, 0xb7, - 0xbc, 0x20, 0x02, 0xb7, 0x00, 0xbe, 0x04, 0xb7, 0x04, 0x00, 0x06, 0xac, 0xce, 0xcc, - 0x82, 0x34, 0xcc, 0xf8, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xef, 0xae, 0x90, 0x01, 0xb4, - 0xf7, 0x3e, 0xb7, 0x00, 0x00, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x04, 0x00, 0x06, - 0xac, 0xce, 0xcc, 0x82, 0x34, 0xcc, 0xf8, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xef, 0x8f, - 0x7f, 0xa2, 0x2d, 0xce, 0x88, 0x9c, 0x00, 0x94, 0x1f, 0xb7, 0xbc, 0x20, 0x02, 0xb7, - 0x00, 0xbe, 0x04, 0xb7, 0x04, 0x00, 0x06, 0xac, 0xce, 0xcc, 0x82, 0x34, 0xcc, 0xf8, - 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xef, 0x6c, 0x90, 0x01, 0xb4, 0xf6, 0xfc, 0xb7, 0x9a, - 0xca, 0x02, 0xb7, 0x00, 0x3b, 0x04, 0xb7, 0x04, 0x00, 0x06, 0xac, 0xce, 0xcc, 0x82, - 0x34, 0xcc, 0xf8, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xef, 0x4d, 0x7f, 0x90, 0x00, 0xb5, - 0xf8, 0xca, 0xb7, 0x00, 0x00, 0x02, 0xac, 0xce, 0xcc, 0x82, 0x12, 0xcc, 0xf8, 0xb7, - 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xb7, 0x00, 0x00, 0x08, 0xb7, 0x00, 0x00, - 0x0a, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xf7, 0x5f, 0x90, 0x29, 0xa2, 0x3a, 0xce, 0xab, - 0xb0, 0xd2, 0x4d, 0x91, 0x08, 0xb5, 0xf7, 0xb6, 0x3c, 0xb7, 0x00, 0x00, 0x02, 0xac, - 0xce, 0xcc, 0x82, 0x12, 0xcc, 0xf8, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, - 0xb7, 0x00, 0x00, 0x08, 0xb7, 0x00, 0x00, 0x0a, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xf7, - 0x2e, 0x90, 0x2a, 0xa2, 0x3a, 0xce, 0xab, 0xb0, 0xf4, 0x7d, 0x91, 0x01, 0xb5, 0xf7, - 0x85, 0x3c, 0xaf, 0xc8, 0xb7, 0x00, 0x01, 0x02, 0xa2, 0x54, 0xce, 0xa8, 0xab, 0x04, - 0xac, 0xce, 0x06, 0x82, 0x42, 0x06, 0xf8, 0xac, 0xce, 0x08, 0x82, 0x3e, 0x08, 0xf8, - 0xac, 0xce, 0x0a, 0x82, 0x3e, 0x0a, 0xf8, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xf8, 0x41, - 0x90, 0x01, 0xa2, 0x2b, 0xce, 0x8b, 0x3f, 0xc8, 0x9c, 0x02, 0x95, 0x99, 0x95, 0x65, - 0xb7, 0x01, 0x02, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0x00, 0xb4, - 0xc6, 0xc6, 0xac, 0xce, 0xcc, 0x82, 0x12, 0xcc, 0xf8, 0xb5, 0xf7, 0xb9, 0x9d, 0x00, - 0x94, 0x2c, 0xa2, 0x54, 0xce, 0xa8, 0xb5, 0xfa, 0x44, 0xa2, 0x2c, 0xce, 0x88, 0x9c, - 0x00, 0x52, 0x90, 0x00, 0xa2, 0x2c, 0xce, 0x8b, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, - 0xb0, 0x20, 0x70, 0xb5, 0x0a, 0x52, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x20, - 0x29, 0xb4, 0x0a, 0x46, 0x9c, 0x02, 0x95, 0x82, 0x9c, 0x03, 0x95, 0x86, 0x95, 0x52, - 0xb7, 0x00, 0x00, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xac, 0xce, 0x06, 0x82, 0x0e, 0x06, - 0xf8, 0xac, 0xce, 0x08, 0x82, 0x0a, 0x08, 0xf8, 0xac, 0xce, 0x0a, 0x82, 0x0a, 0x0a, - 0xf8, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xf7, 0xbb, 0x90, 0x00, 0xa2, 0x27, 0xce, 0x8b, - 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x20, 0x74, 0xb5, 0x0a, 0x06, 0x90, 0x00, - 0xa2, 0x26, 0xce, 0x8b, 0xa2, 0x2c, 0xce, 0x8b, 0xa2, 0x33, 0xce, 0x8b, 0xa2, 0x22, - 0xce, 0x88, 0xab, 0x18, 0xb0, 0x2f, 0x05, 0xb5, 0x09, 0xec, 0x90, 0x01, 0x36, 0x9c, - 0x90, 0x00, 0xa2, 0x3a, 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x20, - 0x6f, 0xb5, 0x09, 0xd6, 0x90, 0x00, 0xb4, 0xf5, 0x85, 0xb7, 0x00, 0x01, 0x02, 0xa2, - 0x54, 0xce, 0xa8, 0xab, 0x04, 0xac, 0xce, 0x06, 0x82, 0x42, 0x06, 0xf8, 0xac, 0xce, - 0x08, 0x82, 0x3e, 0x08, 0xf8, 0xac, 0xce, 0x0a, 0x82, 0x46, 0x0a, 0xf8, 0xa2, 0x22, - 0xce, 0x88, 0xb5, 0xf7, 0x4e, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xf5, 0xd0, 0xb4, 0xf5, - 0xdd, 0x90, 0x00, 0xa2, 0x27, 0xce, 0x8b, 0xa2, 0x26, 0xce, 0x8b, 0xa2, 0x33, 0xce, - 0x8b, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x20, 0x74, 0xb5, 0x09, 0x87, 0xa2, - 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x2f, 0x05, 0xb5, 0x09, 0x7b, 0x90, 0x01, 0xa2, - 0x3a, 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x20, 0x6f, 0xb5, 0x09, - 0x69, 0xa2, 0x2e, 0xce, 0x88, 0x9c, 0x00, 0xb4, 0xfd, 0x35, 0x40, 0x90, 0x00, 0x37, - 0x29, 0xa2, 0x29, 0xce, 0x88, 0x9c, 0x00, 0x46, 0x90, 0x01, 0xa2, 0x26, 0xce, 0x8b, - 0xa2, 0x2a, 0xce, 0x88, 0x9c, 0x00, 0x94, 0x26, 0x90, 0x01, 0xa2, 0x33, 0xce, 0x8b, - 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x2f, 0x05, 0xb5, 0x09, 0x34, 0xa2, 0x02, - 0xce, 0x88, 0xa2, 0x27, 0xce, 0x8b, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x20, - 0x74, 0xb5, 0x09, 0x20, 0x90, 0x02, 0xa2, 0x3a, 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, - 0xab, 0x18, 0xb0, 0x20, 0x6f, 0xb5, 0x09, 0x0e, 0x90, 0x00, 0xb5, 0xf4, 0xbd, 0xa2, - 0x22, 0xce, 0x88, 0xb5, 0xf8, 0x34, 0xa2, 0x32, 0xce, 0x8b, 0xb4, 0xfd, 0x03, 0x90, - 0x03, 0xa2, 0x3a, 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x20, 0x6f, - 0xb5, 0x08, 0xe9, 0xa2, 0x2e, 0xce, 0x88, 0x9c, 0x00, 0xb4, 0xfd, 0x2f, 0x95, 0x7f, - 0xa2, 0x2c, 0xce, 0x88, 0x9d, 0x00, 0x52, 0x90, 0x01, 0xa2, 0x2c, 0xce, 0x8b, 0xa2, - 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x20, 0x70, 0xb5, 0x08, 0xc5, 0x90, 0x00, 0xa2, - 0x2d, 0xce, 0x8b, 0xa2, 0x2b, 0xce, 0x8b, 0xa2, 0x20, 0xce, 0xa8, 0x9c, 0x01, 0xb4, - 0xfe, 0x32, 0x9c, 0x04, 0xb4, 0xfe, 0x1d, 0xb4, 0xfd, 0xe4, 0xa2, 0x2b, 0xce, 0x88, - 0x9c, 0x00, 0x4c, 0xa2, 0x20, 0xce, 0xa8, 0x9c, 0x02, 0xb4, 0xfd, 0x6d, 0xb4, 0xfd, - 0xa0, 0x90, 0x01, 0x37, 0xf1, 0xa2, 0x20, 0xce, 0xa8, 0x9c, 0x01, 0xb4, 0xfe, 0x0a, - 0x9c, 0x04, 0xb4, 0xfd, 0xf5, 0xb4, 0xfd, 0xbc, 0x90, 0x04, 0xa2, 0x3a, 0xce, 0xab, - 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x20, 0x6f, 0xb5, 0x08, 0x70, 0xa2, 0x2e, - 0xce, 0x88, 0x9d, 0x00, 0x95, 0xf5, 0xb4, 0xfc, 0xf6, 0x90, 0x05, 0xa2, 0x3a, 0xce, - 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x20, 0x6f, 0xb5, 0x08, 0x53, 0x90, - 0x00, 0xb5, 0xf4, 0x02, 0xb5, 0xf7, 0x7d, 0xa2, 0x32, 0xce, 0x8b, 0xb4, 0xfc, 0x4c, - 0xb7, 0x00, 0x01, 0x02, 0xb2, 0x43, 0xb7, 0xa2, 0x18, 0xce, 0xa8, 0xab, 0x04, 0xa2, - 0x1a, 0xce, 0xa8, 0xab, 0x06, 0xa2, 0x1c, 0xce, 0xa8, 0xab, 0x08, 0xb7, 0x00, 0x06, - 0x0a, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xf4, 0x79, 0x90, 0x06, 0xa2, 0x3a, 0xce, 0xab, - 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x20, 0x6f, 0xb5, 0x08, 0x0e, 0xb0, 0xd2, - 0x4d, 0x91, 0x08, 0xb5, 0xf4, 0xc4, 0x3c, 0xb7, 0x00, 0x00, 0x02, 0xb7, 0x00, 0x00, - 0x04, 0xb7, 0x04, 0x00, 0x06, 0xac, 0xce, 0xcc, 0x82, 0x34, 0xcc, 0xf8, 0xa2, 0x22, - 0xce, 0x88, 0xb5, 0xec, 0x0a, 0x90, 0x07, 0xa2, 0x3a, 0xce, 0xab, 0xa2, 0x22, 0xce, - 0x88, 0xab, 0x18, 0xb0, 0x20, 0x6f, 0xb5, 0x07, 0xd9, 0x90, 0x00, 0xb5, 0xf3, 0x88, - 0xb7, 0x01, 0x03, 0x02, 0xb7, 0x00, 0x02, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, - 0xce, 0x88, 0xb4, 0xc4, 0x07, 0xb5, 0xf3, 0xea, 0xb4, 0xf3, 0xf7, 0xa8, 0x46, 0xb5, - 0xc2, 0x50, 0xa2, 0x00, 0x74, 0xa8, 0x9c, 0x00, 0x3c, 0xa8, 0x44, 0xbc, 0x04, 0x01, - 0x94, 0xbf, 0xbc, 0x04, 0x02, 0x94, 0xc2, 0xbc, 0x04, 0x0e, 0x94, 0xc5, 0xa2, 0x3a, - 0x74, 0xa8, 0x9c, 0x00, 0x54, 0xa2, 0x29, 0x74, 0x88, 0x9d, 0x00, 0x4d, 0xa2, 0x2a, - 0x74, 0x88, 0x9d, 0x00, 0x46, 0xac, 0x74, 0xce, 0xb4, 0xfd, 0x47, 0xa8, 0x44, 0xbc, - 0x04, 0x03, 0x94, 0xaf, 0xbc, 0x04, 0xff, 0x94, 0x3a, 0xa2, 0x3a, 0x74, 0xa8, 0x9c, - 0x00, 0x94, 0xae, 0x9c, 0x01, 0x94, 0xcb, 0x9c, 0x02, 0xb4, 0x01, 0x67, 0x9c, 0x03, - 0xb4, 0x02, 0x1a, 0x9c, 0x04, 0xb4, 0x02, 0xec, 0x9c, 0x05, 0xb4, 0x03, 0x96, 0x9c, - 0x06, 0xb4, 0x04, 0x40, 0x9c, 0x07, 0xb4, 0x04, 0x8f, 0x9c, 0x29, 0xb4, 0x04, 0x8b, - 0x9c, 0x2a, 0xb4, 0x04, 0xa0, 0x9c, 0x2b, 0xb4, 0x04, 0xd6, 0x3c, 0xa2, 0x3a, 0x74, - 0xa8, 0x9c, 0x03, 0x50, 0xa2, 0x34, 0x74, 0xa8, 0x96, 0x48, 0xfc, 0x41, 0x3c, 0x00, - 0xa2, 0x34, 0x74, 0xab, 0x95, 0x4f, 0xa2, 0x36, 0x74, 0xa8, 0x96, 0x48, 0xfc, 0x94, - 0x23, 0xa2, 0x38, 0x74, 0xa8, 0x96, 0x48, 0xfc, 0x42, 0x95, 0x21, 0xa2, 0x2d, 0x74, - 0x88, 0x9d, 0x00, 0x95, 0x6a, 0x90, 0x01, 0xa2, 0x31, 0x74, 0x8b, 0x00, 0xa2, 0x38, - 0x74, 0xab, 0xac, 0x74, 0xce, 0xb4, 0xfb, 0x49, 0x90, 0x01, 0xa2, 0x30, 0x74, 0x8b, - 0x00, 0xa2, 0x36, 0x74, 0x8b, 0xac, 0x74, 0xce, 0xb4, 0xfb, 0x38, 0xa8, 0x48, 0xa2, - 0x29, 0x74, 0x8b, 0x95, 0xbb, 0xa8, 0x48, 0xa2, 0x2a, 0x74, 0x8b, 0x95, 0xc3, 0xa8, - 0x48, 0xa2, 0x28, 0x74, 0x8b, 0xac, 0x74, 0xce, 0xb4, 0xe4, 0x87, 0xa8, 0x48, 0x9d, - 0x00, 0x90, 0x01, 0xa2, 0x2e, 0x74, 0x8b, 0x95, 0xb4, 0xa8, 0x44, 0xbc, 0x04, 0x01, - 0x45, 0xbc, 0x04, 0x02, 0x41, 0x3c, 0xa2, 0x29, 0x74, 0x88, 0x9d, 0x00, 0x47, 0xa2, - 0x2a, 0x74, 0x88, 0x9c, 0x00, 0x3c, 0xac, 0x74, 0xce, 0x37, 0x2c, 0xb4, 0xfc, 0xff, - 0xa8, 0x44, 0xbc, 0x04, 0x03, 0x4a, 0xbc, 0x04, 0xff, 0x53, 0xbc, 0x04, 0x04, 0x94, - 0x79, 0x3c, 0xa2, 0x2e, 0x74, 0x88, 0x9c, 0x00, 0x3c, 0xac, 0x74, 0xce, 0x36, 0xd9, - 0x3c, 0x90, 0x00, 0xa2, 0x27, 0x74, 0x8b, 0xa2, 0x26, 0x74, 0x8b, 0xa2, 0x33, 0x74, - 0x8b, 0xa2, 0x2d, 0x74, 0x8b, 0xa2, 0x30, 0x74, 0x8b, 0xa2, 0x31, 0x74, 0x8b, 0xa2, - 0x22, 0x74, 0x88, 0xab, 0x18, 0xb0, 0x20, 0x74, 0xb5, 0x06, 0x5d, 0xa2, 0x22, 0x74, - 0x88, 0xab, 0x18, 0xb0, 0x2f, 0x05, 0xb5, 0x06, 0x51, 0xb7, 0x00, 0x00, 0x02, 0xb7, - 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xac, 0x74, 0xcc, 0x82, 0x36, 0xcc, 0xf8, - 0x00, 0xb5, 0xea, 0x59, 0xb7, 0x00, 0x00, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, - 0x00, 0x06, 0xac, 0x74, 0xcc, 0x82, 0x38, 0xcc, 0xf8, 0x00, 0xb5, 0xea, 0x42, 0x90, - 0x01, 0xac, 0x74, 0xce, 0xb5, 0xf9, 0x95, 0xb4, 0xfd, 0x1d, 0xa2, 0x2f, 0x74, 0x88, - 0x9d, 0x00, 0x3c, 0xa8, 0x48, 0x99, 0x0e, 0x9c, 0x00, 0x3c, 0x90, 0x01, 0xac, 0x74, - 0xce, 0xb5, 0xf9, 0x7c, 0xb4, 0xf9, 0xd4, 0xa8, 0x44, 0xbc, 0x04, 0x03, 0x54, 0xbc, - 0x04, 0x06, 0x5e, 0xbc, 0x04, 0x04, 0x94, 0x54, 0xbc, 0x04, 0xff, 0x94, 0x82, 0xbc, - 0x04, 0x0d, 0x94, 0x93, 0x3c, 0xa2, 0x2e, 0x74, 0x88, 0x9d, 0x00, 0x46, 0xac, 0x74, - 0xce, 0xb4, 0xfc, 0x37, 0x3c, 0xa8, 0x48, 0x9c, 0x02, 0x41, 0x3c, 0x90, 0x00, 0xa2, - 0x27, 0x74, 0x8b, 0xa2, 0x26, 0x74, 0x8b, 0xa2, 0x22, 0x74, 0x88, 0xab, 0x18, 0xb0, - 0x20, 0x74, 0xb5, 0x05, 0xbb, 0xa2, 0x2c, 0x74, 0x88, 0x9d, 0x00, 0x52, 0x90, 0x01, - 0xa2, 0x2c, 0x74, 0x8b, 0xa2, 0x22, 0x74, 0x88, 0xab, 0x18, 0xb0, 0x20, 0x70, 0xb5, - 0x05, 0xa2, 0xac, 0x74, 0xce, 0xb4, 0xfd, 0x37, 0xa8, 0x48, 0x99, 0x10, 0x9c, 0x00, - 0x3c, 0xa2, 0x54, 0x74, 0xa8, 0xb5, 0xc0, 0x50, 0xa2, 0x00, 0x78, 0xa8, 0xa2, 0x02, - 0x78, 0xfa, 0x9c, 0x00, 0x4c, 0x90, 0x01, 0xa2, 0x32, 0x74, 0x8b, 0xac, 0x74, 0xce, - 0xb4, 0xf9, 0x7f, 0x90, 0x00, 0xa2, 0x32, 0x74, 0x8b, 0xac, 0x74, 0xce, 0x36, 0x53, - 0xb4, 0xfb, 0xc8, 0x90, 0x00, 0xa2, 0x32, 0x74, 0x8b, 0xa8, 0x46, 0xb5, 0xf4, 0x90, - 0x9c, 0x00, 0x3c, 0xac, 0x74, 0xce, 0x36, 0x69, 0xb4, 0xfb, 0xb2, 0xa8, 0x48, 0xa2, - 0x02, 0x74, 0x8b, 0xac, 0x74, 0xce, 0xb4, 0xfb, 0xe8, 0xa8, 0x44, 0xbc, 0x04, 0x03, - 0x4a, 0xbc, 0x04, 0x04, 0x54, 0xbc, 0x04, 0xff, 0x94, 0xb4, 0x3c, 0xa2, 0x2e, 0x74, - 0x88, 0x9c, 0x00, 0x3c, 0xac, 0x74, 0xce, 0xb5, 0xfb, 0xcb, 0x3c, 0xa8, 0x48, 0x99, - 0x01, 0x9c, 0x00, 0x48, 0xa2, 0x30, 0x74, 0x88, 0x9d, 0x00, 0x94, 0x4b, 0xa8, 0x48, - 0x99, 0x02, 0x9c, 0x00, 0x48, 0xa2, 0x31, 0x74, 0x88, 0x9d, 0x00, 0x94, 0x3c, 0xa8, - 0x48, 0x99, 0x20, 0x9d, 0x00, 0x94, 0x34, 0xa8, 0x48, 0x99, 0x03, 0x9c, 0x00, 0x94, - 0x35, 0xa2, 0x2d, 0x74, 0x88, 0x9c, 0x00, 0x94, 0x2d, 0x90, 0x00, 0xa2, 0x2d, 0x74, - 0x8b, 0xb7, 0x15, 0xa4, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x04, 0x00, 0x06, 0xac, - 0x74, 0xcc, 0x82, 0x38, 0xcc, 0xf8, 0xa8, 0x46, 0xb5, 0xe8, 0xf4, 0xac, 0x74, 0xce, - 0xb4, 0xf9, 0x1e, 0xac, 0x74, 0xce, 0xb5, 0xfb, 0xeb, 0xb4, 0xfc, 0x44, 0xa8, 0x48, - 0x99, 0x08, 0x9c, 0x00, 0x94, 0x32, 0xa2, 0x2d, 0x74, 0x88, 0x9d, 0x00, 0x94, 0x2a, - 0xb7, 0x15, 0xa4, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x04, 0x00, 0x06, 0xac, 0x74, - 0xcc, 0x82, 0x36, 0xcc, 0xf8, 0xa8, 0x46, 0xb5, 0xe8, 0xbd, 0x90, 0x01, 0xa2, 0x2d, - 0x74, 0x8b, 0x90, 0x00, 0xa2, 0x31, 0x74, 0x8b, 0xac, 0x74, 0xce, 0xb4, 0xf8, 0xdb, - 0x90, 0x00, 0xac, 0x74, 0xce, 0xb4, 0xf0, 0x38, 0xa2, 0x2a, 0x74, 0x88, 0x9c, 0x00, - 0x3c, 0xa2, 0x2d, 0x74, 0x88, 0x9c, 0x00, 0x3c, 0xac, 0x74, 0xce, 0xb4, 0xfc, 0x2c, - 0xa8, 0x44, 0xbc, 0x04, 0x0b, 0x50, 0xbc, 0x04, 0x04, 0x94, 0x2f, 0xbc, 0x04, 0x03, - 0x94, 0x5e, 0xbc, 0x04, 0xff, 0x94, 0x7d, 0x3c, 0xa8, 0x48, 0xa2, 0x2c, 0x74, 0xdc, - 0x50, 0xa2, 0x2c, 0x74, 0x8b, 0xa2, 0x22, 0x74, 0x88, 0xab, 0x18, 0xb0, 0x20, 0x70, - 0xb5, 0x04, 0x43, 0xa2, 0x2c, 0x74, 0x88, 0x9d, 0x00, 0x3c, 0xac, 0x74, 0xce, 0xb4, - 0xfa, 0x95, 0xa8, 0x48, 0x99, 0x06, 0x9c, 0x00, 0x53, 0xa2, 0x2d, 0x74, 0x88, 0x9c, - 0x00, 0x4c, 0x90, 0x00, 0xa2, 0x2d, 0x74, 0x8b, 0xac, 0x74, 0xce, 0xb4, 0xf8, 0xad, - 0xa8, 0x48, 0x99, 0x08, 0x9c, 0x00, 0x3c, 0xa2, 0x2d, 0x74, 0x88, 0x9d, 0x00, 0x3c, - 0x90, 0x01, 0xa2, 0x2d, 0x74, 0x8b, 0xac, 0x74, 0xce, 0xb4, 0xf8, 0x93, 0xa2, 0x2e, - 0x74, 0x88, 0x9c, 0x00, 0x3c, 0x90, 0x00, 0xac, 0x74, 0xce, 0xb5, 0xf7, 0x6d, 0x90, - 0x01, 0xa2, 0x33, 0x74, 0x8b, 0xa2, 0x22, 0x74, 0x88, 0xab, 0x18, 0xb0, 0x2f, 0x05, - 0xb5, 0x03, 0xe1, 0xb4, 0xfb, 0x79, 0xa2, 0x2d, 0x74, 0x88, 0x9d, 0x00, 0x49, 0xac, - 0x74, 0xce, 0xb5, 0xfb, 0x27, 0xb4, 0xf8, 0x5f, 0xa2, 0x2a, 0x74, 0x88, 0x9c, 0x00, - 0x3c, 0xac, 0x74, 0xce, 0xb4, 0xfb, 0x7d, 0xa8, 0x44, 0xbc, 0x04, 0x06, 0x50, 0xbc, - 0x04, 0x03, 0x94, 0x32, 0xbc, 0x04, 0x04, 0x94, 0x54, 0xbc, 0x04, 0xff, 0x94, 0x83, - 0x3c, 0xa8, 0x48, 0x9c, 0x01, 0x41, 0x3c, 0xac, 0x74, 0xce, 0xa2, 0x2c, 0x74, 0x88, - 0x9d, 0x00, 0x30, 0x04, 0xb5, 0xfa, 0x38, 0x3c, 0x90, 0x00, 0xa2, 0x2c, 0x74, 0x8b, - 0xa2, 0x22, 0x74, 0x88, 0xab, 0x18, 0xb0, 0x20, 0x70, 0xb4, 0x03, 0x84, 0xa2, 0x2e, - 0x74, 0x88, 0x9d, 0x00, 0x3c, 0x90, 0x00, 0xa2, 0x2b, 0x74, 0x8b, 0xa2, 0x2d, 0x74, - 0x8b, 0xa2, 0x33, 0x74, 0x8b, 0xa2, 0x22, 0x74, 0x88, 0xab, 0x18, 0xb0, 0x2f, 0x05, - 0xb5, 0x03, 0x63, 0xac, 0x74, 0xce, 0xb4, 0xfa, 0xdb, 0xa8, 0x48, 0x99, 0x10, 0x9c, - 0x00, 0x3c, 0xa2, 0x54, 0x74, 0xa8, 0xb5, 0xbe, 0x11, 0xa2, 0x00, 0x74, 0xa8, 0xa2, - 0x00, 0x74, 0xfa, 0x9c, 0x00, 0x4c, 0x90, 0x01, 0xa2, 0x32, 0x74, 0x8b, 0xac, 0x74, - 0xce, 0xb4, 0xf7, 0x40, 0x90, 0x00, 0xa2, 0x32, 0x74, 0x8b, 0xac, 0x74, 0xce, 0xb5, - 0xfb, 0x6b, 0xb4, 0xfa, 0xa7, 0x90, 0x00, 0xa2, 0x32, 0x74, 0x8b, 0xa8, 0x46, 0xb5, - 0xf2, 0x50, 0x9c, 0x00, 0x3c, 0xac, 0x74, 0xce, 0xb5, 0xfb, 0x54, 0xb4, 0xfa, 0x90, - 0xa8, 0x44, 0xbc, 0x04, 0x04, 0x4b, 0xbc, 0x04, 0x0c, 0x94, 0x32, 0xbc, 0x04, 0xff, - 0x94, 0x2d, 0x3c, 0xa8, 0x48, 0x99, 0x06, 0x9c, 0x00, 0x3c, 0xa2, 0x2c, 0x74, 0x88, - 0x9d, 0x00, 0x4f, 0xb5, 0xef, 0xe7, 0x90, 0x00, 0xa2, 0x2d, 0x74, 0x8b, 0xac, 0x74, - 0xce, 0xb4, 0xf9, 0xe9, 0xb5, 0xef, 0xd8, 0x90, 0x00, 0xa2, 0x2d, 0x74, 0x8b, 0xac, - 0x74, 0xce, 0xb4, 0xfa, 0x53, 0xb5, 0xef, 0xc9, 0xa2, 0x14, 0x72, 0x88, 0x9c, 0x00, - 0x3c, 0xa2, 0x34, 0x74, 0xa8, 0x9d, 0x00, 0x3c, 0xac, 0x74, 0xce, 0xb4, 0xfa, 0xb9, - 0x3c, 0xa8, 0x44, 0xbc, 0x04, 0xff, 0x41, 0x3c, 0x90, 0x01, 0xac, 0x74, 0xce, 0xb5, - 0xf0, 0x50, 0xb5, 0xef, 0xa2, 0xa8, 0x46, 0xb5, 0xee, 0xd2, 0xb4, 0xfa, 0x21, 0xa8, - 0x44, 0xbc, 0x04, 0xff, 0x41, 0x3c, 0xb5, 0xef, 0x90, 0xb7, 0x00, 0x00, 0x02, 0xac, - 0xce, 0xcc, 0x82, 0x12, 0xcc, 0xf8, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, - 0xb7, 0x00, 0x00, 0x08, 0xb7, 0x00, 0x00, 0x0a, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xee, - 0xd0, 0xb0, 0xd2, 0x4d, 0x91, 0x08, 0xb5, 0xef, 0x2d, 0x90, 0x2b, 0xa2, 0x3a, 0x74, - 0xab, 0x3c, 0xa8, 0x44, 0xbc, 0x04, 0xff, 0x41, 0x3c, 0xb5, 0xef, 0x55, 0xac, 0x74, - 0xce, 0xb4, 0xf9, 0xd6, 0xa2, 0x28, 0xce, 0x88, 0xab, 0xca, 0x90, 0x01, 0x82, 0x00, - 0xca, 0xfc, 0x44, 0xe7, 0xaa, 0xca, 0x63, 0xab, 0x02, 0xa2, 0x06, 0xce, 0xa8, 0xe7, - 0xe7, 0xab, 0xca, 0xa8, 0x02, 0x82, 0x00, 0xca, 0xfc, 0x44, 0xe7, 0xaa, 0xca, 0x63, - 0xab, 0x02, 0xa2, 0x08, 0x72, 0xa8, 0x96, 0x02, 0xf9, 0x9c, 0x00, 0x42, 0x00, 0x3c, - 0x90, 0x01, 0x3c, 0xab, 0xca, 0x9c, 0x03, 0xb4, 0x01, 0x80, 0x05, 0xab, 0x02, 0xb7, - 0x00, 0x04, 0x04, 0x92, 0x00, 0xb7, 0x00, 0x00, 0x06, 0x82, 0x00, 0x06, 0xfd, 0xb4, - 0x01, 0x69, 0x82, 0x04, 0x04, 0xfc, 0xb4, 0x01, 0x46, 0xaf, 0xcc, 0xa8, 0x02, 0xe7, - 0xe7, 0xa0, 0xc8, 0xcc, 0xf8, 0x82, 0x58, 0xcc, 0xf8, 0xa2, 0x01, 0xcc, 0x88, 0xab, - 0x04, 0xc4, 0xab, 0x08, 0x3f, 0xcc, 0x82, 0x04, 0x04, 0xfc, 0x94, 0x41, 0xa8, 0x08, - 0xb5, 0xbc, 0x75, 0xac, 0x74, 0xcc, 0x82, 0x01, 0xca, 0xfc, 0x4c, 0x82, 0x02, 0xca, - 0xfc, 0x54, 0x82, 0x03, 0xca, 0xfc, 0x57, 0x95, 0x44, 0xa2, 0x4a, 0xcc, 0x88, 0x9c, - 0x00, 0x72, 0xb7, 0x00, 0x02, 0x06, 0x95, 0x51, 0xa2, 0x4b, 0xcc, 0x88, 0x9c, 0x00, - 0x7a, 0x6d, 0xa2, 0x4c, 0xcc, 0x88, 0x9c, 0x00, 0x95, 0x61, 0xa2, 0x06, 0xcc, 0xa8, - 0x05, 0x96, 0x02, 0xfc, 0x7e, 0x95, 0x6c, 0xa8, 0x08, 0xb5, 0xbc, 0x48, 0xac, 0x76, - 0xce, 0x82, 0x01, 0xca, 0xfc, 0x4e, 0x82, 0x02, 0xca, 0xfc, 0x94, 0x5d, 0x82, 0x03, - 0xca, 0xfc, 0x94, 0x76, 0x95, 0x87, 0xa2, 0x06, 0xce, 0xa8, 0x9c, 0x00, 0x4d, 0x9c, - 0x01, 0x58, 0x9c, 0x02, 0x94, 0x2b, 0x9c, 0x03, 0x94, 0x39, 0x95, 0x9b, 0xa2, 0x56, - 0xce, 0x88, 0x9c, 0x00, 0x95, 0xa3, 0xb7, 0x00, 0x04, 0x06, 0x95, 0xa9, 0xa2, 0x57, - 0xce, 0x88, 0x9d, 0x00, 0x6c, 0xa2, 0x58, 0xce, 0x88, 0x9d, 0x00, 0x73, 0xa2, 0x56, - 0xce, 0x88, 0x9d, 0x00, 0x7a, 0x95, 0xc0, 0xa2, 0x57, 0xce, 0x88, 0x9d, 0x00, 0x95, - 0x23, 0xa2, 0x58, 0xce, 0x88, 0x9d, 0x00, 0x95, 0x2b, 0x95, 0xd2, 0xa2, 0x59, 0xce, - 0x88, 0x9c, 0x00, 0x95, 0xda, 0x95, 0x37, 0xa2, 0x06, 0xce, 0xa8, 0x9c, 0x00, 0x95, - 0x39, 0x9c, 0x01, 0x95, 0x2f, 0x9c, 0x02, 0x95, 0x22, 0x9c, 0x03, 0x42, 0x95, 0xf1, - 0xa2, 0x5a, 0xce, 0x88, 0x9c, 0x00, 0x95, 0xf9, 0x95, 0x56, 0xa2, 0x0a, 0xce, 0xa8, - 0x05, 0x96, 0x02, 0xfc, 0x43, 0xb4, 0xfe, 0xf7, 0xa2, 0x06, 0xce, 0xa8, 0x9c, 0x03, - 0x94, 0x26, 0xa2, 0x5e, 0xce, 0x88, 0x9c, 0x00, 0xb4, 0xfe, 0xe6, 0xa2, 0x56, 0xce, - 0x88, 0x9d, 0x00, 0xb4, 0xfe, 0xdd, 0xa2, 0x57, 0xce, 0x88, 0x9d, 0x00, 0xb4, 0xfe, - 0xd4, 0xa2, 0x58, 0xce, 0x88, 0x9d, 0x00, 0xb4, 0xfe, 0xcb, 0x95, 0x90, 0xa2, 0x5e, - 0xce, 0x88, 0x9c, 0x00, 0xb4, 0xfe, 0xc0, 0xa2, 0x59, 0xce, 0x88, 0x9d, 0x00, 0xb4, - 0xfe, 0xb7, 0xa2, 0x5a, 0xce, 0x88, 0x9d, 0x00, 0xb4, 0xfe, 0xae, 0x95, 0xad, 0xaf, - 0xce, 0xa8, 0x02, 0xe7, 0xe7, 0xa0, 0xc8, 0xce, 0xf8, 0x82, 0x1a, 0xce, 0xf8, 0xa2, - 0x01, 0xce, 0x88, 0xab, 0x04, 0xd4, 0xab, 0x08, 0x3f, 0xce, 0xb4, 0xfe, 0xb7, 0xa8, - 0x06, 0x3c, 0xa2, 0x0a, 0xce, 0xa8, 0x05, 0xab, 0x02, 0xb4, 0xfe, 0x79, 0xb7, 0x00, - 0x01, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xa2, 0x06, 0xce, 0xa8, 0x9c, 0x00, 0x94, 0x24, - 0x9c, 0x01, 0x94, 0x47, 0x9c, 0x02, 0x94, 0x43, 0x9c, 0x03, 0x94, 0x59, 0x82, 0x00, - 0x04, 0xfc, 0x50, 0xaf, 0xce, 0xa8, 0x04, 0x35, 0xb6, 0x3f, 0xce, 0x9c, 0x02, 0x42, - 0x00, 0x3c, 0x90, 0x01, 0x3c, 0xa8, 0x02, 0x3c, 0xa2, 0x5b, 0xce, 0x88, 0xa2, 0x5f, - 0xce, 0xda, 0xa2, 0x5d, 0xce, 0xda, 0xa2, 0x61, 0xce, 0xda, 0x9c, 0x00, 0x46, 0xb7, - 0x00, 0x02, 0x04, 0x95, 0x2f, 0xa2, 0x5e, 0xce, 0x88, 0x9c, 0x00, 0x95, 0x37, 0xb7, - 0x00, 0x03, 0x04, 0x95, 0x3d, 0xa2, 0x5b, 0xce, 0x88, 0xa2, 0x5f, 0xce, 0xda, 0xa2, - 0x5c, 0xce, 0xda, 0xa2, 0x60, 0xce, 0xda, 0x9c, 0x00, 0x95, 0x20, 0xb7, 0x00, 0x01, - 0x04, 0x95, 0x57, 0xa2, 0x59, 0xce, 0x88, 0x9c, 0x00, 0x46, 0xb7, 0x00, 0x01, 0x04, - 0x95, 0x64, 0xa2, 0x5a, 0xce, 0x88, 0x9c, 0x00, 0x95, 0x3b, 0xb7, 0x00, 0x02, 0x04, - 0x95, 0x72, 0xab, 0x1a, 0xbc, 0x10, 0x29, 0x94, 0x80, 0xbc, 0x10, 0x2a, 0x94, 0x86, - 0xbc, 0x10, 0x2b, 0x94, 0x86, 0xbc, 0x10, 0x2e, 0x94, 0xad, 0xbc, 0x20, 0x17, 0x94, - 0xae, 0xbc, 0x20, 0x6f, 0x94, 0xb4, 0xbc, 0x20, 0x70, 0x94, 0xba, 0xbc, 0x20, 0x74, - 0x94, 0xc5, 0xbc, 0x20, 0x29, 0x94, 0xca, 0xbc, 0x2f, 0x07, 0x94, 0xe3, 0xbc, 0x2f, - 0x05, 0x94, 0xe9, 0xbc, 0x32, 0x0e, 0x94, 0xef, 0xbc, 0x40, 0x0d, 0xb4, 0x01, 0x00, - 0xbc, 0x40, 0x0f, 0xb4, 0x01, 0x11, 0xbc, 0x40, 0x10, 0xb4, 0x01, 0x4f, 0xbc, 0x40, - 0x21, 0xb4, 0x01, 0x61, 0xbc, 0x40, 0x2a, 0xb4, 0x01, 0x72, 0xbc, 0x40, 0x33, 0xb4, - 0x01, 0x8d, 0xbc, 0x40, 0x40, 0xb4, 0x01, 0x9f, 0xbc, 0x40, 0x34, 0xb4, 0x01, 0xb1, - 0xbc, 0x40, 0x35, 0xb4, 0x01, 0xcc, 0xbc, 0x40, 0x3d, 0xb4, 0x01, 0xe7, 0xbc, 0x40, - 0x3e, 0xb4, 0x01, 0xf9, 0xbc, 0x40, 0x3f, 0xb4, 0x02, 0x0b, 0x3c, 0xa2, 0x20, 0x72, - 0xa8, 0xab, 0x1c, 0x90, 0x02, 0xb4, 0x02, 0x17, 0xa2, 0x22, 0x72, 0xa8, 0x6b, 0xa2, - 0x14, 0x72, 0x88, 0x9c, 0x00, 0x43, 0x90, 0x00, 0x75, 0xb7, 0x00, 0x00, 0x1c, 0xa2, - 0x1a, 0x72, 0xa8, 0x9c, 0x00, 0x46, 0x90, 0x01, 0xa0, 0xc8, 0x1c, 0xfa, 0xa2, 0x1c, - 0x72, 0xa8, 0x9c, 0x00, 0x46, 0x90, 0x02, 0xa0, 0xc8, 0x1c, 0xfa, 0xa8, 0x1c, 0x95, - 0x36, 0xa2, 0x27, 0x72, 0x88, 0x94, 0x1f, 0xa8, 0x18, 0xb5, 0xb9, 0xcc, 0xa2, 0x52, - 0x74, 0xa8, 0x95, 0x47, 0xa8, 0x18, 0xb5, 0xb9, 0xc1, 0xa2, 0x3a, 0x74, 0xa8, 0x95, - 0x52, 0xa8, 0x18, 0xb5, 0xb9, 0xb6, 0xa2, 0x2c, 0x74, 0x88, 0xab, 0x1c, 0x90, 0x01, - 0xb4, 0x01, 0xba, 0xa8, 0x18, 0xb5, 0xb9, 0xa6, 0xa2, 0x27, 0x74, 0x88, 0x70, 0xa8, - 0x18, 0xb5, 0xb9, 0x9c, 0xaf, 0xcc, 0xaf, 0xca, 0xac, 0x74, 0xca, 0x82, 0x12, 0xca, - 0xf8, 0x92, 0x1c, 0xb5, 0xe2, 0x82, 0x3f, 0xca, 0x3f, 0xcc, 0x90, 0x06, 0xb4, 0x01, - 0x92, 0xa8, 0x18, 0xb5, 0xb9, 0x7e, 0xa2, 0x24, 0x74, 0xa8, 0x95, 0x95, 0xa8, 0x18, - 0xb5, 0xb9, 0x73, 0xa2, 0x33, 0x74, 0x88, 0x95, 0x43, 0x8c, 0x7c, 0x3c, 0xac, 0x78, - 0x3e, 0xa8, 0x18, 0xb5, 0xb9, 0x8a, 0xa2, 0x12, 0x78, 0xa8, 0x8c, 0x3c, 0x7c, 0xac, - 0x3e, 0x78, 0x95, 0xb7, 0x8c, 0x7b, 0x3c, 0xac, 0x76, 0x3e, 0xa8, 0x18, 0xb5, 0xb9, - 0x5f, 0xa2, 0x28, 0x76, 0x88, 0x8c, 0x3c, 0x7b, 0xac, 0x3e, 0x76, 0x95, 0xce, 0x8c, - 0x7b, 0x3c, 0xac, 0x76, 0x3e, 0xa8, 0x18, 0xb5, 0xb9, 0x48, 0xaf, 0xcc, 0xaf, 0xce, - 0xac, 0x76, 0xcc, 0x82, 0x46, 0xcc, 0xf8, 0x90, 0x09, 0xb5, 0x21, 0xe6, 0x94, 0x20, - 0x00, 0xab, 0x1c, 0xac, 0x76, 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0x90, 0x09, 0xb5, 0x21, - 0xd5, 0x54, 0x00, 0x96, 0x1c, 0xfa, 0x3f, 0xce, 0x3f, 0xcc, 0x8c, 0x3c, 0x7b, 0xac, - 0x3e, 0x76, 0x95, 0xae, 0x90, 0x02, 0x95, 0x21, 0x90, 0x01, 0x75, 0x8c, 0x7b, 0x3c, - 0xac, 0x76, 0x3e, 0xa8, 0x18, 0xb5, 0xb9, 0x04, 0xa2, 0x62, 0x76, 0xa8, 0x8c, 0x3c, - 0x7b, 0xac, 0x3e, 0x76, 0xb4, 0xfe, 0xd4, 0x8c, 0x7b, 0x3c, 0xac, 0x76, 0x3e, 0xa8, - 0x18, 0xb5, 0xb8, 0xec, 0xa2, 0x3f, 0x76, 0x88, 0x8c, 0x3c, 0x7b, 0xac, 0x3e, 0x76, - 0x95, 0xe4, 0x8c, 0x7b, 0x3c, 0xac, 0x76, 0x3e, 0xa8, 0x18, 0xb5, 0xb8, 0xd5, 0xa2, - 0x30, 0x76, 0xa8, 0xab, 0x1c, 0xa2, 0x32, 0x76, 0xa8, 0xab, 0x1e, 0x8c, 0x3c, 0x7b, - 0xac, 0x3e, 0x76, 0x90, 0x04, 0x94, 0xba, 0x8c, 0x7b, 0x3c, 0xac, 0x76, 0x3e, 0xa8, - 0x18, 0xb5, 0xb8, 0xb4, 0xa2, 0x74, 0x76, 0x88, 0x8c, 0x3c, 0x7b, 0xac, 0x3e, 0x76, - 0xb4, 0xfe, 0xe1, 0x8c, 0x7b, 0x3c, 0xac, 0x76, 0x3e, 0xa8, 0x18, 0xb5, 0xb8, 0x9c, - 0xa2, 0x12, 0x76, 0x88, 0x8c, 0x3c, 0x7b, 0xac, 0x3e, 0x76, 0xb4, 0xfe, 0xc9, 0x8c, - 0x7b, 0x3c, 0xac, 0x76, 0x3e, 0xa8, 0x18, 0xb5, 0xb8, 0x84, 0xa2, 0x68, 0x76, 0xa8, - 0xab, 0x1c, 0xa2, 0x6a, 0x76, 0xa8, 0xab, 0x1e, 0x8c, 0x3c, 0x7b, 0xac, 0x3e, 0x76, - 0x90, 0x04, 0x94, 0x69, 0x8c, 0x7b, 0x3c, 0xac, 0x76, 0x3e, 0xa8, 0x18, 0xb5, 0xb8, - 0x63, 0xa2, 0x6c, 0x76, 0xa8, 0xab, 0x1c, 0xa2, 0x6e, 0x76, 0xa8, 0xab, 0x1e, 0x8c, - 0x3c, 0x7b, 0xac, 0x3e, 0x76, 0x90, 0x04, 0x94, 0x48, 0x8c, 0x7b, 0x3c, 0xac, 0x76, - 0x3e, 0xa8, 0x18, 0xb5, 0xb8, 0x42, 0xa2, 0x2c, 0x76, 0xa8, 0x8c, 0x3c, 0x7b, 0xac, - 0x3e, 0x76, 0xb4, 0xfe, 0x12, 0x8c, 0x7b, 0x3c, 0xac, 0x76, 0x3e, 0xa8, 0x18, 0xb5, - 0xb8, 0x2a, 0xa2, 0x4e, 0x76, 0xa8, 0x8c, 0x3c, 0x7b, 0xac, 0x3e, 0x76, 0xb4, 0xfd, - 0xfa, 0x8c, 0x7b, 0x3c, 0xac, 0x76, 0x3e, 0xa8, 0x18, 0xb5, 0xb8, 0x12, 0xa2, 0x2a, - 0x76, 0x88, 0x8c, 0x3c, 0x7b, 0xac, 0x3e, 0x76, 0xb4, 0xfd, 0xe2, 0x9a, 0x20, 0xb4, - 0x11, 0x76, 0xa2, 0x06, 0xcc, 0xa8, 0xbc, 0x10, 0x1a, 0x94, 0x8b, 0xbc, 0x10, 0x1b, - 0x94, 0xa9, 0xbc, 0x10, 0x1f, 0x94, 0xed, 0xbc, 0x1f, 0x07, 0xb4, 0x00, 0xff, 0xbc, - 0x1f, 0x08, 0xb4, 0x01, 0x02, 0xbc, 0x20, 0x20, 0xb4, 0x01, 0x05, 0xbc, 0x20, 0x76, - 0xb4, 0x01, 0x47, 0xbc, 0x20, 0x18, 0xb4, 0x01, 0x56, 0xbc, 0x20, 0x1d, 0xb4, 0x01, - 0x6d, 0xbc, 0x2f, 0x01, 0xb4, 0x01, 0x7c, 0xbc, 0x2f, 0x03, 0xb4, 0x01, 0x86, 0xbc, - 0x32, 0x15, 0xb4, 0x01, 0xba, 0xbc, 0x32, 0x16, 0xb4, 0x01, 0xb4, 0xbc, 0x32, 0x17, - 0xb4, 0x01, 0xae, 0xbc, 0x32, 0x13, 0xb4, 0x02, 0x21, 0xbc, 0x40, 0x0e, 0xb4, 0x02, - 0x3a, 0xbc, 0x40, 0x11, 0xb4, 0x02, 0x44, 0xbc, 0x40, 0x3a, 0xb4, 0x02, 0x69, 0xbc, - 0x40, 0x3b, 0xb4, 0x02, 0x73, 0xbc, 0x40, 0x15, 0xb4, 0x02, 0x7d, 0xbc, 0x40, 0x1f, - 0xb4, 0x02, 0x96, 0xbc, 0x4f, 0x02, 0xb4, 0x02, 0xca, 0xbc, 0x60, 0x00, 0x41, 0x3c, - 0xb5, 0xed, 0x17, 0x90, 0x01, 0xa2, 0x0e, 0x72, 0x8b, 0x3c, 0xa2, 0x0e, 0xcc, 0xa8, - 0x99, 0x01, 0xa2, 0x15, 0x72, 0x8b, 0xb7, 0x01, 0x06, 0x02, 0xb7, 0x00, 0x00, 0x04, - 0xb7, 0x00, 0x00, 0x06, 0x00, 0xb5, 0xb8, 0xea, 0xa2, 0x0e, 0xcc, 0xa8, 0xa2, 0x06, - 0x72, 0xab, 0x3c, 0xa2, 0x0e, 0xcc, 0xa8, 0xa2, 0x08, 0x72, 0xab, 0xb7, 0x00, 0x00, - 0x0a, 0x80, 0x7e, 0x0a, 0xfc, 0x3c, 0xa8, 0x0a, 0xb5, 0xb7, 0x33, 0xa2, 0x4e, 0x76, - 0xa8, 0x9c, 0x00, 0x4d, 0x9c, 0x01, 0x4a, 0x9c, 0x02, 0x47, 0x9c, 0x03, 0x44, 0x9c, - 0x09, 0x41, 0x44, 0xa9, 0x0a, 0x95, 0x20, 0xac, 0x76, 0xce, 0xb5, 0xfa, 0x0f, 0x9d, - 0x00, 0x6c, 0xb7, 0x02, 0x01, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, - 0xa8, 0x0a, 0xb5, 0xb8, 0x99, 0x7e, 0xa2, 0x10, 0xcc, 0xa8, 0xab, 0xca, 0xa2, 0x0e, - 0xcc, 0xa8, 0xb5, 0x10, 0x45, 0xa2, 0x02, 0x72, 0xab, 0xa8, 0xca, 0xa2, 0x04, 0x72, - 0xab, 0x3c, 0xa2, 0x0e, 0xcc, 0xa8, 0xa2, 0x34, 0x72, 0xab, 0x3c, 0xa2, 0x0e, 0xcc, - 0x88, 0xa2, 0x30, 0x72, 0xab, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xb6, 0xbb, 0xa2, - 0x0e, 0xcc, 0x88, 0xa2, 0x08, 0x74, 0x8b, 0xac, 0x74, 0xce, 0xb5, 0xd9, 0xcd, 0xa2, - 0x12, 0x72, 0x88, 0x9c, 0x02, 0x4a, 0xb5, 0xb6, 0xb7, 0xac, 0x76, 0xce, 0xb5, 0xd2, - 0xe6, 0x3c, 0xa2, 0x10, 0x72, 0x88, 0x9c, 0x02, 0x4a, 0xb5, 0xb6, 0xa6, 0xac, 0x76, - 0xce, 0xb5, 0xd2, 0xd5, 0x3c, 0xa2, 0x11, 0x72, 0x88, 0x9c, 0x02, 0x3c, 0xb5, 0xb6, - 0x95, 0xac, 0x76, 0xce, 0xb5, 0xd2, 0xc4, 0x3c, 0xb7, 0x04, 0x0d, 0x02, 0xa2, 0x0e, - 0xcc, 0x88, 0xab, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x0a, 0xcc, 0xa8, 0xb4, 0xb8, - 0x11, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xb6, 0x5e, 0xac, 0xcc, 0xca, 0xaf, 0xcc, 0xac, - 0x74, 0xcc, 0x82, 0x18, 0xcc, 0xf8, 0x82, 0x0e, 0xca, 0xf8, 0xb5, 0xdf, 0x41, 0x3f, - 0xcc, 0x3c, 0xb7, 0x04, 0x06, 0x02, 0xa2, 0x0e, 0xcc, 0xa8, 0xab, 0x04, 0xb7, 0x00, - 0x00, 0x06, 0xa2, 0x0a, 0xcc, 0xa8, 0xb4, 0xb7, 0xdf, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, - 0xb6, 0x2c, 0xa2, 0x0e, 0xcc, 0xa8, 0xa2, 0x20, 0x74, 0xab, 0x3c, 0xa2, 0x0a, 0xcc, - 0xa8, 0xb5, 0xb6, 0x1c, 0xa2, 0x06, 0x74, 0xa8, 0xa2, 0x0e, 0xcc, 0xfc, 0x3c, 0xa2, - 0x06, 0x74, 0xab, 0xa2, 0x52, 0x74, 0xa8, 0x9c, 0x03, 0x44, 0x9d, 0x03, 0x41, 0x3c, - 0xa2, 0x1e, 0x74, 0xa8, 0xaf, 0xc8, 0x90, 0x00, 0xa2, 0x1e, 0x74, 0xab, 0xac, 0x74, - 0xce, 0xb5, 0xd9, 0x12, 0x3f, 0xc8, 0xa2, 0x1e, 0x74, 0xab, 0xb4, 0xd9, 0x09, 0xa2, - 0x0a, 0xcc, 0xa8, 0xb5, 0xb6, 0x0a, 0xb7, 0x00, 0x00, 0x0c, 0x82, 0x01, 0x0c, 0xfc, - 0x3c, 0xa8, 0x0c, 0xb5, 0xb5, 0xd4, 0xa2, 0x54, 0x74, 0xa8, 0xa2, 0x0a, 0xcc, 0xfc, - 0x43, 0xa9, 0x0c, 0x75, 0xa2, 0x0c, 0x78, 0xa8, 0xa2, 0x42, 0x74, 0xab, 0xa2, 0x0e, - 0x78, 0xa8, 0xa2, 0x44, 0x74, 0xab, 0xa2, 0x08, 0x78, 0xa8, 0xa2, 0x3e, 0x74, 0xab, - 0xa2, 0x0a, 0x78, 0xa8, 0xa2, 0x40, 0x74, 0xab, 0xa2, 0x04, 0x78, 0xa8, 0xa2, 0x46, - 0x74, 0xab, 0xa2, 0x04, 0x78, 0xa8, 0xa2, 0x46, 0x74, 0xab, 0x90, 0x01, 0xab, 0x02, - 0xa2, 0x54, 0x74, 0xa8, 0xab, 0x04, 0xac, 0x74, 0x06, 0x82, 0x42, 0x06, 0xf8, 0xac, - 0x74, 0x08, 0x82, 0x3e, 0x08, 0xf8, 0xac, 0x74, 0x0a, 0x82, 0x46, 0x0a, 0xf8, 0xa2, - 0x22, 0x74, 0x88, 0xb5, 0xe8, 0x7b, 0x95, 0x59, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xb5, - 0x91, 0xa2, 0x10, 0xcc, 0xa8, 0xab, 0xca, 0xa2, 0x0e, 0xcc, 0xa8, 0xb5, 0x0e, 0xc2, - 0xa2, 0x00, 0x78, 0xab, 0xa8, 0xca, 0xa2, 0x02, 0x78, 0xab, 0x3c, 0xa2, 0x0a, 0xcc, - 0xa8, 0xb5, 0xb5, 0x5e, 0xa2, 0x0e, 0xcc, 0x88, 0xa2, 0x0c, 0x76, 0xab, 0x3c, 0xa2, - 0x0a, 0xcc, 0xa8, 0xb5, 0xb5, 0x4e, 0xac, 0xcc, 0xce, 0x82, 0x0e, 0xce, 0xf8, 0xa9, - 0xce, 0xd4, 0xa2, 0x13, 0x76, 0x8b, 0xa2, 0x01, 0xce, 0x88, 0xa2, 0x14, 0x76, 0x8b, - 0xa2, 0x02, 0xce, 0x88, 0xa2, 0x15, 0x76, 0x8b, 0xac, 0x76, 0xce, 0xb4, 0xd1, 0x5f, - 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xb5, 0x23, 0xa2, 0x0e, 0xcc, 0x88, 0xa2, 0x10, 0x76, - 0x8b, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xb5, 0x13, 0xa2, 0x0e, 0xcc, 0x88, 0xa2, - 0x11, 0x76, 0x8b, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xb5, 0x03, 0xa2, 0x10, 0xcc, - 0xa8, 0xab, 0xca, 0xa2, 0x0e, 0xcc, 0xa8, 0xb5, 0x0e, 0x48, 0xa2, 0x00, 0x76, 0xab, - 0xa8, 0xca, 0xa2, 0x02, 0x76, 0xab, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xb4, 0xe4, - 0xa2, 0x0e, 0xcc, 0x88, 0x91, 0x00, 0x9c, 0x00, 0x91, 0x02, 0x9c, 0x01, 0x91, 0x01, - 0x9c, 0x02, 0x91, 0x08, 0x9c, 0x03, 0x91, 0x04, 0x9c, 0x04, 0xb1, 0x01, 0x00, 0xa8, - 0xca, 0xa2, 0x04, 0x76, 0xab, 0xb7, 0x02, 0x02, 0x02, 0xac, 0xca, 0x04, 0xb7, 0x00, - 0x00, 0x06, 0xa2, 0x0a, 0xcc, 0xa8, 0xb4, 0xb6, 0x49, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, - 0xb4, 0xaa, 0xa2, 0x0a, 0x76, 0xa8, 0xa2, 0x0e, 0xcc, 0xfc, 0x3c, 0xa2, 0x0e, 0xcc, - 0xa8, 0xa2, 0x0a, 0x76, 0xab, 0xa2, 0x62, 0x76, 0xa8, 0x9d, 0x03, 0x44, 0x9c, 0x03, - 0x41, 0x3c, 0xa2, 0x17, 0x76, 0xa8, 0xaf, 0xc8, 0x90, 0x00, 0xa2, 0x17, 0x76, 0xab, - 0xac, 0x76, 0xce, 0xb5, 0xd0, 0xb1, 0x3f, 0xc8, 0xa2, 0x17, 0x76, 0xab, 0xb4, 0xd0, - 0xa8, 0xa2, 0x0c, 0xcc, 0xa8, 0xb6, 0xb8, 0x00, 0xab, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, - 0xb4, 0x50, 0xa2, 0x04, 0xcc, 0xa8, 0xbc, 0x13, 0x13, 0x53, 0xbc, 0x13, 0x14, 0xb4, - 0x01, 0x5c, 0xbc, 0x13, 0x15, 0xb4, 0x01, 0xc3, 0xbc, 0x13, 0x16, 0xb4, 0x02, 0xf5, - 0x3c, 0xac, 0xcc, 0xce, 0x82, 0x16, 0xce, 0xf8, 0xa2, 0x04, 0x74, 0xa8, 0x9d, 0x00, - 0x3c, 0xd4, 0xa2, 0x08, 0x74, 0x8b, 0xa2, 0x02, 0xce, 0x88, 0xab, 0xca, 0xa2, 0x01, - 0xce, 0x88, 0x8c, 0xca, 0xc9, 0xa2, 0x04, 0x74, 0xab, 0xa2, 0x03, 0xce, 0x88, 0xa2, - 0x02, 0x74, 0x8b, 0xa2, 0x04, 0xce, 0xa8, 0xa2, 0x20, 0x74, 0xab, 0xa2, 0x06, 0xce, - 0xa8, 0xa2, 0x06, 0x74, 0xab, 0xb7, 0x00, 0x00, 0x02, 0xaf, 0xcc, 0xaf, 0xce, 0xac, - 0x74, 0xcc, 0x82, 0x58, 0xcc, 0xf8, 0x82, 0x08, 0xce, 0xf8, 0x80, 0x7e, 0x02, 0xfc, - 0x94, 0xf1, 0xd4, 0xc6, 0xa2, 0x01, 0xce, 0x88, 0xa2, 0x01, 0xcc, 0x8b, 0xa2, 0x02, - 0xce, 0x88, 0xa2, 0x02, 0xcc, 0x8b, 0xa2, 0x03, 0xce, 0x88, 0xa2, 0x03, 0xcc, 0x8b, - 0xa2, 0x01, 0xcc, 0x88, 0xa2, 0x22, 0x74, 0xdc, 0x94, 0x74, 0xa2, 0x01, 0xcc, 0x88, - 0x9c, 0x02, 0x94, 0xa0, 0xaf, 0x76, 0x88, 0x7b, 0xaf, 0xc8, 0xc4, 0xb5, 0xb3, 0xbe, - 0xac, 0x76, 0xca, 0x82, 0x1a, 0xca, 0xf8, 0xa8, 0x02, 0x9c, 0x00, 0x47, 0x82, 0x04, - 0xca, 0xf8, 0xaa, 0xc8, 0x66, 0x3f, 0xc8, 0x8b, 0x7b, 0x3f, 0x76, 0xa2, 0x22, 0x74, - 0x88, 0xa2, 0x02, 0xca, 0x8b, 0x90, 0x02, 0xa2, 0x03, 0xca, 0x8b, 0xa2, 0x03, 0xcc, - 0x88, 0x9c, 0x02, 0x94, 0x3f, 0xaf, 0x76, 0x88, 0x7b, 0xaf, 0xc8, 0xa2, 0x02, 0xcc, - 0x88, 0xb5, 0xb3, 0x82, 0xac, 0x76, 0xca, 0x82, 0x1a, 0xca, 0xf8, 0xa8, 0x02, 0x9c, - 0x00, 0x47, 0x82, 0x04, 0xca, 0xf8, 0xaa, 0xc8, 0x66, 0x3f, 0xc8, 0x8b, 0x7b, 0x3f, - 0x76, 0xa2, 0x22, 0x74, 0x88, 0xad, 0xca, 0x8b, 0x90, 0x02, 0xa2, 0x01, 0xca, 0x8b, - 0xa9, 0x02, 0x82, 0x04, 0xcc, 0xf8, 0x82, 0x04, 0xce, 0xf8, 0x95, 0xa8, 0xaf, 0x74, - 0x88, 0x7a, 0xaf, 0xc8, 0xa2, 0x02, 0xcc, 0x88, 0xb5, 0xb3, 0x2f, 0xac, 0x74, 0xca, - 0x82, 0x58, 0xca, 0xf8, 0xa8, 0x02, 0x9c, 0x00, 0x47, 0x82, 0x04, 0xca, 0xf8, 0xaa, - 0xc8, 0x66, 0x3f, 0xc8, 0x8b, 0x7a, 0x3f, 0x74, 0x95, 0x3f, 0xaf, 0x74, 0x88, 0x7a, - 0xaf, 0xc8, 0xc4, 0xb5, 0xb3, 0x0a, 0xac, 0x74, 0xca, 0x82, 0x58, 0xca, 0xf8, 0xa8, - 0x02, 0x9c, 0x00, 0x47, 0x82, 0x04, 0xca, 0xf8, 0xaa, 0xc8, 0x66, 0x3f, 0xc8, 0x8b, - 0x7a, 0x3f, 0x74, 0x95, 0xa0, 0x3f, 0xce, 0x3f, 0xcc, 0xa2, 0x0c, 0x72, 0x89, 0x3c, - 0xac, 0xcc, 0xce, 0x82, 0x16, 0xce, 0xf8, 0xa2, 0x04, 0x74, 0xa8, 0x9c, 0x00, 0x3c, - 0x90, 0x01, 0xa2, 0x00, 0x74, 0x8b, 0xf4, 0xa2, 0x0a, 0x74, 0xab, 0xa2, 0x02, 0xce, - 0xa8, 0xa2, 0x0c, 0x74, 0xab, 0xa2, 0x04, 0xce, 0xa8, 0xa2, 0x0e, 0x74, 0xab, 0xa2, - 0x06, 0xce, 0xa8, 0xa2, 0x10, 0x74, 0xab, 0xa2, 0x08, 0xce, 0x88, 0xa2, 0x1e, 0x74, - 0x8b, 0xac, 0xce, 0xca, 0x82, 0x09, 0xca, 0xf8, 0xaf, 0xcc, 0xac, 0x74, 0xcc, 0x82, - 0x12, 0xcc, 0xf8, 0xb5, 0xdb, 0x90, 0xa2, 0x20, 0x72, 0xa8, 0x9c, 0x01, 0x41, 0x3c, - 0xb7, 0x04, 0x0e, 0x02, 0xb7, 0x00, 0x01, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, - 0x74, 0x88, 0xb5, 0xb4, 0x2b, 0xac, 0x74, 0xce, 0xb4, 0xd5, 0x99, 0x90, 0x01, 0xa2, - 0x00, 0x74, 0xab, 0xa2, 0x52, 0x74, 0xa8, 0x9c, 0x03, 0xb4, 0x00, 0xff, 0x9c, 0x02, - 0xb4, 0x01, 0x0f, 0xb7, 0x00, 0x00, 0x02, 0xaf, 0xcc, 0xac, 0xcc, 0xce, 0x82, 0x16, - 0xcc, 0xf8, 0xac, 0x74, 0xcc, 0x82, 0x58, 0xcc, 0xf8, 0x82, 0x08, 0xce, 0xf8, 0x80, - 0x7e, 0x02, 0xfc, 0x94, 0xd4, 0xa2, 0x01, 0xcc, 0x88, 0xa2, 0x22, 0x74, 0xdc, 0x94, - 0x71, 0x9c, 0x02, 0x94, 0xa1, 0xaf, 0x76, 0x88, 0x7b, 0xaf, 0xc8, 0xc4, 0xb5, 0xb2, - 0x43, 0xac, 0x76, 0xca, 0x82, 0x1a, 0xca, 0xf8, 0xa8, 0x02, 0x9c, 0x00, 0x47, 0x82, - 0x04, 0xca, 0xf8, 0xaa, 0xc8, 0x66, 0x3f, 0xc8, 0x8b, 0x7b, 0x3f, 0x76, 0xa2, 0x02, - 0xcc, 0x88, 0xa2, 0x02, 0xca, 0x8b, 0xa2, 0x03, 0xcc, 0x88, 0xa2, 0x03, 0xca, 0x8b, - 0xa2, 0x03, 0xcc, 0x88, 0x9c, 0x02, 0x94, 0x3e, 0xaf, 0x76, 0x88, 0x7b, 0xaf, 0xc8, - 0xa2, 0x02, 0xcc, 0x88, 0xb5, 0xb2, 0x05, 0xac, 0x76, 0xca, 0x82, 0x1a, 0xca, 0xf8, - 0xa8, 0x02, 0x9c, 0x00, 0x47, 0x82, 0x04, 0xca, 0xf8, 0xaa, 0xc8, 0x66, 0x3f, 0xc8, - 0x8b, 0x7b, 0x3f, 0x76, 0xc4, 0xad, 0xca, 0x8b, 0xa2, 0x01, 0xcc, 0x88, 0xa2, 0x01, - 0xca, 0x8b, 0xa9, 0x02, 0x82, 0x04, 0xcc, 0xf8, 0x82, 0x04, 0xce, 0xf8, 0x95, 0x8b, - 0xaf, 0x74, 0x88, 0x7a, 0xaf, 0xc8, 0xa2, 0x02, 0xcc, 0x88, 0xb5, 0xb1, 0xb3, 0xac, - 0x74, 0xca, 0x82, 0x58, 0xca, 0xf8, 0xa8, 0x02, 0x9c, 0x00, 0x47, 0x82, 0x04, 0xca, - 0xf8, 0xaa, 0xc8, 0x66, 0x3f, 0xc8, 0x8b, 0x7a, 0x3f, 0x74, 0x95, 0x3e, 0xaf, 0x74, - 0x88, 0x7a, 0xaf, 0xc8, 0xc4, 0xb5, 0xb1, 0x8e, 0xac, 0x74, 0xca, 0x82, 0x58, 0xca, - 0xf8, 0xa8, 0x02, 0x9c, 0x00, 0x47, 0x82, 0x04, 0xca, 0xf8, 0xaa, 0xc8, 0x66, 0x3f, - 0xc8, 0x8b, 0x7a, 0x3f, 0x74, 0x95, 0xa1, 0x3f, 0xcc, 0xac, 0x74, 0xce, 0xb4, 0xd7, - 0x33, 0xa2, 0x2c, 0x72, 0xa8, 0x05, 0xa2, 0x2c, 0x72, 0xab, 0x04, 0x9d, 0x00, 0xb4, - 0xfe, 0xf7, 0xb5, 0xd5, 0x76, 0xb4, 0xfe, 0xf1, 0xa2, 0x2e, 0x72, 0xa8, 0x05, 0xa2, - 0x2e, 0x72, 0xab, 0x04, 0x9d, 0x00, 0xb4, 0xfe, 0xe2, 0xb5, 0xd5, 0x61, 0xb4, 0xfe, - 0xdc, 0xac, 0x74, 0xce, 0xb5, 0xd6, 0x9f, 0xa2, 0x0c, 0x72, 0x88, 0x05, 0xa2, 0x0c, - 0x72, 0x8b, 0x3c, 0xa2, 0x0c, 0xcc, 0xa8, 0xb6, 0xb8, 0x00, 0xab, 0xa2, 0x0a, 0xcc, - 0xa8, 0xb5, 0xb1, 0x36, 0xa2, 0x04, 0xcc, 0xa8, 0xbc, 0x13, 0x17, 0x53, 0xbc, 0x13, - 0x18, 0xb4, 0x02, 0x2c, 0xbc, 0x13, 0x19, 0xb4, 0x02, 0x48, 0xbc, 0x13, 0x1a, 0xb4, - 0x02, 0x85, 0x3c, 0xac, 0xcc, 0xce, 0x82, 0x16, 0xce, 0xf8, 0xa2, 0x08, 0x76, 0xa8, - 0x9d, 0x00, 0x3c, 0xf4, 0xa2, 0x06, 0x76, 0xab, 0x9c, 0x00, 0x4e, 0x9c, 0x01, 0x94, - 0x3c, 0x9c, 0x02, 0x94, 0x6a, 0x9c, 0x03, 0x94, 0x98, 0x94, 0xb6, 0xaf, 0xcc, 0xac, - 0x76, 0xcc, 0xa2, 0x03, 0xce, 0x88, 0x99, 0x01, 0xa2, 0x13, 0xcc, 0x8b, 0xa2, 0x04, - 0xce, 0x88, 0x99, 0x5b, 0xa2, 0x14, 0xcc, 0x8b, 0xa2, 0x05, 0xce, 0x88, 0x99, 0xdb, - 0xa2, 0x15, 0xcc, 0x8b, 0xa2, 0x0a, 0x72, 0x89, 0xa2, 0x22, 0x76, 0x88, 0xa2, 0x10, - 0x72, 0x8b, 0x3f, 0xcc, 0x3c, 0xaf, 0xcc, 0xac, 0x76, 0xcc, 0xa2, 0x03, 0xce, 0x88, - 0x99, 0x01, 0xa2, 0x13, 0xcc, 0x8b, 0xa2, 0x04, 0xce, 0x88, 0x99, 0x6d, 0xa2, 0x14, - 0xcc, 0x8b, 0xa2, 0x05, 0xce, 0x88, 0x99, 0xed, 0xa2, 0x15, 0xcc, 0x8b, 0xa2, 0x0a, - 0x72, 0x89, 0xa2, 0x22, 0x76, 0x88, 0xa2, 0x11, 0x72, 0x8b, 0x3f, 0xcc, 0x3c, 0xaf, - 0xcc, 0xac, 0x76, 0xcc, 0xa2, 0x03, 0xce, 0x88, 0x99, 0x01, 0xa2, 0x13, 0xcc, 0x8b, - 0xa2, 0x04, 0xce, 0x88, 0x99, 0x6d, 0xa2, 0x14, 0xcc, 0x8b, 0xa2, 0x05, 0xce, 0x88, - 0x99, 0x6d, 0xa2, 0x15, 0xcc, 0x8b, 0xa2, 0x0a, 0x72, 0x89, 0xa2, 0x22, 0x76, 0x88, - 0xa2, 0x12, 0x72, 0x8b, 0x3f, 0xcc, 0x3c, 0xaf, 0xcc, 0xac, 0x76, 0xcc, 0xa2, 0x03, - 0xce, 0x88, 0x99, 0x01, 0xa2, 0x13, 0xcc, 0x8b, 0xa2, 0x04, 0xce, 0x88, 0x99, 0x37, - 0xa2, 0x14, 0xcc, 0x8b, 0xa2, 0x0b, 0x72, 0x89, 0x3f, 0xcc, 0x3c, 0xa2, 0x06, 0xce, - 0xa8, 0xa2, 0x08, 0x76, 0xab, 0xa2, 0x08, 0xce, 0x88, 0xa2, 0x10, 0x76, 0x8b, 0xa2, - 0x09, 0xce, 0x88, 0xa2, 0x11, 0x76, 0x8b, 0xa2, 0x0a, 0xce, 0xa8, 0xa2, 0x0a, 0x76, - 0xab, 0xb7, 0x00, 0x00, 0x02, 0xaf, 0xcc, 0xaf, 0xce, 0xac, 0x76, 0xcc, 0x82, 0x1a, - 0xcc, 0xf8, 0x82, 0x0c, 0xce, 0xf8, 0x80, 0x7e, 0x02, 0xfc, 0x94, 0xef, 0xd4, 0xc6, - 0xa2, 0x01, 0xce, 0x88, 0xa2, 0x01, 0xcc, 0x8b, 0xa2, 0x02, 0xce, 0x88, 0xa2, 0x02, - 0xcc, 0x8b, 0xa2, 0x03, 0xce, 0x88, 0xa2, 0x03, 0xcc, 0x8b, 0xa2, 0x01, 0xcc, 0x88, - 0xa2, 0x22, 0x76, 0xdc, 0x94, 0xbf, 0x9c, 0x02, 0x94, 0x96, 0xaf, 0x76, 0x88, 0x7b, - 0xaf, 0xc8, 0xc4, 0xb5, 0xaf, 0xd6, 0xac, 0x76, 0xca, 0x82, 0x1a, 0xca, 0xf8, 0xa8, - 0x02, 0x9c, 0x00, 0x47, 0x82, 0x04, 0xca, 0xf8, 0xaa, 0xc8, 0x66, 0x3f, 0xc8, 0x8b, - 0x7b, 0x3f, 0x76, 0xa2, 0x22, 0x76, 0x88, 0xa2, 0x02, 0xca, 0x8b, 0x90, 0x04, 0xa2, - 0x03, 0xca, 0x8b, 0xa2, 0x03, 0xcc, 0x88, 0x9c, 0x02, 0x94, 0x35, 0xaf, 0x76, 0x88, - 0x7b, 0xaf, 0xc8, 0xa2, 0x02, 0xcc, 0x88, 0xb5, 0xaf, 0x9a, 0xac, 0x76, 0xca, 0x82, - 0x1a, 0xca, 0xf8, 0xa8, 0x02, 0x9c, 0x00, 0x47, 0x82, 0x04, 0xca, 0xf8, 0xaa, 0xc8, - 0x66, 0x3f, 0xc8, 0x8b, 0x7b, 0x3f, 0x76, 0xa2, 0x22, 0x76, 0x88, 0xad, 0xca, 0x8b, - 0x90, 0x04, 0xa2, 0x01, 0xca, 0x8b, 0x94, 0x4d, 0xaf, 0x74, 0x88, 0x7a, 0xaf, 0xc8, - 0xa2, 0x02, 0xcc, 0x88, 0xb5, 0xaf, 0x51, 0xac, 0x74, 0xca, 0x82, 0x58, 0xca, 0xf8, - 0xa8, 0x02, 0x9c, 0x00, 0x47, 0x82, 0x04, 0xca, 0xf8, 0xaa, 0xc8, 0x66, 0x3f, 0xc8, - 0x8b, 0x7a, 0x3f, 0x74, 0x95, 0x35, 0xaf, 0x74, 0x88, 0x7a, 0xaf, 0xc8, 0xc4, 0xb5, - 0xaf, 0x2c, 0xac, 0x74, 0xca, 0x82, 0x58, 0xca, 0xf8, 0xa8, 0x02, 0x9c, 0x00, 0x47, - 0x82, 0x04, 0xca, 0xf8, 0xaa, 0xc8, 0x66, 0x3f, 0xc8, 0x8b, 0x7a, 0x3f, 0x74, 0x95, - 0x96, 0xa9, 0x02, 0x82, 0x04, 0xcc, 0xf8, 0x82, 0x04, 0xce, 0xf8, 0x95, 0xf3, 0x3f, - 0xce, 0x3f, 0xcc, 0xa2, 0x14, 0xce, 0xa8, 0xa2, 0x00, 0x76, 0xab, 0xa2, 0x16, 0xce, - 0xa8, 0xa2, 0x02, 0x76, 0xab, 0xa2, 0x18, 0xce, 0xa8, 0xa2, 0x04, 0x76, 0xab, 0x3c, - 0xac, 0xcc, 0xce, 0x82, 0x16, 0xce, 0xf8, 0xa2, 0x08, 0x76, 0xa8, 0x9c, 0x00, 0x3c, - 0x90, 0x01, 0xa2, 0x0e, 0x76, 0xab, 0xd4, 0xa2, 0x17, 0x76, 0x8b, 0xa2, 0x01, 0xce, - 0x88, 0xa2, 0x18, 0x76, 0x8b, 0x3c, 0x90, 0x00, 0xa2, 0x0e, 0x76, 0xab, 0xa2, 0x06, - 0x76, 0xa8, 0x9c, 0x03, 0x46, 0xac, 0x76, 0xce, 0xb4, 0xd5, 0x89, 0xa2, 0x62, 0x76, - 0xa8, 0x9c, 0x03, 0x44, 0x9c, 0x02, 0x53, 0x70, 0xa2, 0x28, 0x72, 0xa8, 0x05, 0xa2, - 0x28, 0x72, 0xab, 0x04, 0x9d, 0x00, 0x7d, 0xb5, 0xd2, 0xb5, 0x95, 0x21, 0xa2, 0x2a, - 0x72, 0xa8, 0x05, 0xa2, 0x2a, 0x72, 0xab, 0x04, 0x9d, 0x00, 0x95, 0x2f, 0xb5, 0xd2, - 0xa2, 0x95, 0x34, 0xac, 0xcc, 0xce, 0x82, 0x16, 0xce, 0xf8, 0xa2, 0x06, 0x76, 0xa8, - 0x9c, 0x00, 0x4d, 0x9c, 0x01, 0x5b, 0x9c, 0x02, 0x94, 0x27, 0x9c, 0x03, 0x94, 0x33, - 0x94, 0x3a, 0x88, 0x7e, 0xa2, 0x10, 0x72, 0x8b, 0xa2, 0x0a, 0x72, 0x88, 0x05, 0xa2, - 0x0a, 0x72, 0x8b, 0x94, 0x29, 0x88, 0x7e, 0xa2, 0x11, 0x72, 0x8b, 0xa2, 0x0a, 0x72, - 0x88, 0x05, 0xa2, 0x0a, 0x72, 0x8b, 0x59, 0x88, 0x7e, 0xa2, 0x12, 0x72, 0x8b, 0xa2, - 0x0a, 0x72, 0x88, 0x05, 0xa2, 0x0a, 0x72, 0x8b, 0x49, 0xa2, 0x0b, 0x72, 0x88, 0x05, - 0xa2, 0x0b, 0x72, 0x8b, 0xb7, 0x00, 0x00, 0x02, 0xaf, 0xcc, 0xaf, 0xce, 0xac, 0x76, - 0xcc, 0x82, 0x1a, 0xcc, 0xf8, 0x82, 0x0c, 0xce, 0xf8, 0x80, 0x7e, 0x02, 0xfc, 0x94, - 0xd6, 0xa2, 0x01, 0xcc, 0x88, 0xa2, 0x22, 0x76, 0xdc, 0x94, 0xc0, 0x9c, 0x02, 0x94, - 0x97, 0xaf, 0x76, 0x88, 0x7b, 0xaf, 0xc8, 0xc4, 0xb5, 0xae, 0x11, 0xac, 0x76, 0xca, - 0x82, 0x1a, 0xca, 0xf8, 0xa8, 0x02, 0x9c, 0x00, 0x47, 0x82, 0x04, 0xca, 0xf8, 0xaa, - 0xc8, 0x66, 0x3f, 0xc8, 0x8b, 0x7b, 0x3f, 0x76, 0xa2, 0x02, 0xcc, 0x88, 0xa2, 0x02, - 0xca, 0x8b, 0xa2, 0x03, 0xcc, 0x88, 0xa2, 0x03, 0xca, 0x8b, 0xa2, 0x03, 0xcc, 0x88, - 0x9c, 0x02, 0x94, 0x34, 0xaf, 0x76, 0x88, 0x7b, 0xaf, 0xc8, 0xa2, 0x02, 0xcc, 0x88, - 0xb5, 0xad, 0xd3, 0xac, 0x76, 0xca, 0x82, 0x1a, 0xca, 0xf8, 0xa8, 0x02, 0x9c, 0x00, - 0x47, 0x82, 0x04, 0xca, 0xf8, 0xaa, 0xc8, 0x66, 0x3f, 0xc8, 0x8b, 0x7b, 0x3f, 0x76, - 0xc4, 0xad, 0xca, 0x8b, 0xa2, 0x01, 0xcc, 0x88, 0xa2, 0x01, 0xca, 0x8b, 0x94, 0x4d, - 0xaf, 0x74, 0x88, 0x7a, 0xaf, 0xc8, 0xa2, 0x02, 0xcc, 0x88, 0xb5, 0xad, 0x8b, 0xac, - 0x74, 0xca, 0x82, 0x58, 0xca, 0xf8, 0xa8, 0x02, 0x9c, 0x00, 0x47, 0x82, 0x04, 0xca, - 0xf8, 0xaa, 0xc8, 0x66, 0x3f, 0xc8, 0x8b, 0x7a, 0x3f, 0x74, 0x95, 0x34, 0xaf, 0x74, - 0x88, 0x7a, 0xaf, 0xc8, 0xc4, 0xb5, 0xad, 0x66, 0xac, 0x74, 0xca, 0x82, 0x58, 0xca, - 0xf8, 0xa8, 0x02, 0x9c, 0x00, 0x47, 0x82, 0x04, 0xca, 0xf8, 0xaa, 0xc8, 0x66, 0x3f, - 0xc8, 0x8b, 0x7a, 0x3f, 0x74, 0x95, 0x97, 0xa9, 0x02, 0x82, 0x04, 0xcc, 0xf8, 0x82, - 0x04, 0xce, 0xf8, 0x95, 0xda, 0x3f, 0xce, 0x3f, 0xcc, 0xac, 0x76, 0xce, 0xb4, 0xd3, - 0x99, 0xa2, 0x0c, 0xcc, 0xa8, 0xb6, 0xb8, 0x00, 0xab, 0x91, 0x00, 0xe4, 0x99, 0x3f, - 0x82, 0x02, 0xcc, 0xf8, 0x9c, 0x01, 0xb4, 0x01, 0xe0, 0xa2, 0x04, 0xcc, 0xa8, 0xbc, - 0x13, 0x11, 0x94, 0x35, 0xbc, 0x13, 0x13, 0x94, 0x33, 0xbc, 0x13, 0x14, 0x94, 0x2e, - 0xbc, 0x13, 0x15, 0x94, 0x29, 0xbc, 0x13, 0x16, 0x94, 0x24, 0xbc, 0x13, 0x17, 0x94, - 0x22, 0xbc, 0x13, 0x18, 0x5e, 0xbc, 0x13, 0x19, 0x5a, 0xbc, 0x13, 0x1a, 0x56, 0xbc, - 0x24, 0x11, 0x55, 0xbc, 0x24, 0x12, 0x3c, 0xbc, 0x24, 0x13, 0x94, 0xb6, 0xb4, 0x01, - 0xa1, 0xb4, 0xf4, 0xf2, 0xb4, 0xf8, 0x7c, 0xb4, 0xfb, 0xa7, 0xa2, 0x06, 0xcc, 0xa8, - 0x9c, 0x00, 0x55, 0x9c, 0x01, 0x94, 0x21, 0x9c, 0x02, 0x94, 0x2d, 0x9c, 0x04, 0x94, - 0x39, 0x9c, 0x05, 0x94, 0x57, 0x9c, 0x06, 0x94, 0x65, 0x3c, 0xb7, 0x01, 0x01, 0x02, - 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0x00, 0xb4, 0xae, 0x58, 0xb7, 0x01, - 0x02, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0x00, 0xb4, 0xae, 0x48, - 0xb7, 0x01, 0x04, 0x02, 0xb7, 0x00, 0x04, 0x04, 0xb7, 0x00, 0x00, 0x06, 0x00, 0xb4, - 0xae, 0x38, 0xa2, 0x10, 0x72, 0x88, 0xab, 0xca, 0xb5, 0xac, 0x97, 0xa2, 0x29, 0x76, - 0x88, 0x9c, 0x02, 0x41, 0x3c, 0xb7, 0x02, 0x10, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, - 0x00, 0x00, 0x06, 0xa8, 0xca, 0xb4, 0xae, 0x16, 0xa2, 0x11, 0x72, 0x88, 0xab, 0xca, - 0xb5, 0xac, 0x75, 0xa2, 0x29, 0x76, 0x88, 0x9c, 0x02, 0x95, 0x20, 0x3c, 0xb7, 0x00, - 0x00, 0x02, 0x80, 0x7e, 0x02, 0xfc, 0x3c, 0xa8, 0x02, 0xb5, 0xac, 0x5e, 0xa2, 0x06, - 0x76, 0xa8, 0x9c, 0x03, 0x43, 0xa9, 0x02, 0x73, 0xb7, 0x02, 0x10, 0x02, 0xb7, 0x00, - 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa8, 0x02, 0xb5, 0xad, 0xdb, 0x74, 0xa2, 0x06, - 0xcc, 0xa8, 0x9c, 0x00, 0x51, 0x9c, 0x01, 0x94, 0x7e, 0x9c, 0x02, 0x94, 0x8d, 0x9c, - 0x03, 0x94, 0x9c, 0x9c, 0x04, 0x94, 0xb3, 0x3c, 0xa2, 0x0e, 0xcc, 0x88, 0x9c, 0x00, - 0x51, 0x9c, 0x01, 0x5d, 0x9c, 0x02, 0x94, 0x28, 0x9c, 0x03, 0x94, 0x32, 0x9c, 0x04, - 0x94, 0x3c, 0x94, 0x48, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xac, 0x0b, 0x90, 0x02, 0xa2, - 0x04, 0x76, 0xab, 0x94, 0x39, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xab, 0xfc, 0x90, 0x01, - 0xa2, 0x04, 0x76, 0xab, 0x94, 0x2a, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xab, 0xed, 0x90, - 0x08, 0xa2, 0x04, 0x76, 0xab, 0x5c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xab, 0xdf, 0x90, - 0x04, 0xa2, 0x04, 0x76, 0xab, 0x4e, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xab, 0xd1, 0xb0, - 0x01, 0x00, 0xa2, 0x04, 0x76, 0xab, 0xab, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xb7, 0x02, - 0x02, 0x02, 0xa2, 0x0a, 0xcc, 0xa8, 0xb4, 0xad, 0x51, 0xb7, 0x00, 0x00, 0x04, 0xb7, - 0x00, 0x00, 0x06, 0xb7, 0x02, 0x0f, 0x02, 0xa2, 0x0a, 0xcc, 0xa8, 0xb4, 0xad, 0x3e, - 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xb7, 0x02, 0x10, 0x02, 0xa2, 0x0a, - 0xcc, 0xa8, 0xb4, 0xad, 0x2b, 0xa2, 0x20, 0x72, 0xa8, 0x9c, 0x01, 0x41, 0x3c, 0xb7, - 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xb7, 0x02, 0x01, 0x02, 0xa2, 0x0a, 0xcc, - 0xa8, 0xb4, 0xad, 0x10, 0xa2, 0x20, 0x72, 0xa8, 0x9c, 0x01, 0x41, 0x3c, 0xb7, 0x00, - 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xb7, 0x02, 0x04, 0x02, 0xa2, 0x0a, 0xcc, 0xa8, - 0xb4, 0xac, 0xf5, 0x90, 0x00, 0xa2, 0x0c, 0xcc, 0xab, 0xb4, 0xfe, 0x0b, 0x3c, 0xa2, - 0x02, 0xcc, 0xa8, 0xbc, 0x10, 0x15, 0xb4, 0x01, 0x40, 0xbc, 0x10, 0x16, 0xb4, 0x01, - 0x43, 0xbc, 0x10, 0x17, 0xb4, 0x01, 0x46, 0xbc, 0x10, 0x18, 0xb4, 0x01, 0x49, 0xbc, - 0x10, 0x1a, 0xb4, 0x01, 0x4c, 0xbc, 0x10, 0x1b, 0xb4, 0x01, 0x4f, 0xbc, 0x10, 0x22, - 0xb4, 0x01, 0x52, 0xbc, 0x10, 0x1f, 0xb4, 0x01, 0x5e, 0xbc, 0xf4, 0x07, 0xb4, 0x01, - 0x70, 0xbc, 0xf4, 0x08, 0xb4, 0x01, 0x73, 0xbc, 0x20, 0x20, 0xb4, 0x01, 0x7c, 0xbc, - 0x20, 0x22, 0xb4, 0x01, 0x88, 0xbc, 0x20, 0x75, 0xb4, 0x01, 0x92, 0xbc, 0x20, 0x76, - 0xb4, 0x01, 0x9c, 0xbc, 0xf4, 0x01, 0x94, 0x83, 0xbc, 0xf4, 0x04, 0xb4, 0x03, 0xd6, - 0xbc, 0x20, 0x0d, 0xb4, 0x01, 0x9b, 0xbc, 0x20, 0x0e, 0xb4, 0x01, 0xad, 0xbc, 0x20, - 0x16, 0xb4, 0x01, 0xbf, 0xbc, 0x20, 0x29, 0x94, 0x86, 0xbc, 0x32, 0x15, 0xb4, 0x01, - 0xe1, 0xbc, 0x32, 0x16, 0xb4, 0x01, 0xf3, 0xbc, 0x32, 0x17, 0xb4, 0x02, 0x05, 0xbc, - 0x32, 0x13, 0xb4, 0x02, 0x17, 0xbc, 0x40, 0x0c, 0xb4, 0x02, 0x29, 0xbc, 0x40, 0x0e, - 0xb4, 0x02, 0x33, 0xbc, 0x40, 0x11, 0xb4, 0x02, 0x3d, 0xbc, 0x40, 0x1d, 0xb4, 0x02, - 0xdc, 0xbc, 0x40, 0x3a, 0xb4, 0x02, 0xe6, 0xbc, 0x40, 0x3b, 0xb4, 0x02, 0xf0, 0xbc, - 0x40, 0x41, 0xb4, 0x02, 0xfa, 0xbc, 0x40, 0x15, 0xb4, 0x03, 0x04, 0xbc, 0xf4, 0x02, - 0x94, 0x29, 0xbc, 0x40, 0x1f, 0xb4, 0x03, 0x23, 0xbc, 0x40, 0x13, 0xb4, 0x03, 0x46, - 0xbc, 0x40, 0x17, 0xb4, 0x03, 0x50, 0xbc, 0xf4, 0x03, 0xb4, 0x03, 0x90, 0x3c, 0xa2, - 0x0a, 0xcc, 0xa8, 0xb5, 0xaa, 0x58, 0xa2, 0x0e, 0xcc, 0x88, 0xa2, 0x20, 0x74, 0x8b, - 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xaa, 0x5c, 0xa2, 0x0e, 0xcc, 0xa8, 0xa2, 0x0a, - 0x76, 0xab, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xaa, 0x38, 0xaf, 0xcc, 0xac, 0xcc, - 0xca, 0x82, 0x0e, 0xca, 0xf8, 0xac, 0x74, 0xcc, 0x82, 0x12, 0xcc, 0xf8, 0xb5, 0xd3, - 0x1b, 0xac, 0x74, 0xcc, 0x82, 0x12, 0xcc, 0xf8, 0xac, 0x74, 0xce, 0xb5, 0xdc, 0xc4, - 0xb2, 0x12, 0x10, 0xa8, 0xcc, 0xb8, 0xfe, 0x80, 0xab, 0xcc, 0x9a, 0x0c, 0xab, 0xca, - 0x30, 0x0b, 0x97, 0xb0, 0xcc, 0x97, 0xfe, 0xca, 0x30, 0x03, 0x3f, 0xcc, 0x3c, 0x00, - 0x96, 0xcc, 0x14, 0x05, 0xe1, 0x66, 0x3c, 0xa2, 0x0e, 0xcc, 0x88, 0xa2, 0x0c, 0x72, - 0x8b, 0x3c, 0xa2, 0x0e, 0xcc, 0x88, 0xa2, 0x0a, 0x72, 0x8b, 0x3c, 0xa2, 0x0e, 0xcc, - 0x88, 0xa2, 0x0b, 0x72, 0x8b, 0x3c, 0xa2, 0x0e, 0xcc, 0x88, 0xa2, 0x0d, 0x72, 0x8b, - 0x3c, 0xa2, 0x0e, 0xcc, 0xa8, 0xa2, 0x06, 0x72, 0xab, 0x3c, 0xa2, 0x0e, 0xcc, 0xa8, - 0xa2, 0x08, 0x72, 0xab, 0x3c, 0xa2, 0x0e, 0xcc, 0x88, 0xa2, 0x00, 0x72, 0x8b, 0x9d, - 0x00, 0xb5, 0xd8, 0x8f, 0xa2, 0x00, 0x72, 0x8b, 0x3c, 0xa2, 0x10, 0xcc, 0xa8, 0xab, - 0xca, 0xa2, 0x0e, 0xcc, 0xa8, 0xb5, 0x03, 0x06, 0xa2, 0x02, 0x72, 0xab, 0xa8, 0xca, - 0xa2, 0x04, 0x72, 0xab, 0x3c, 0xa2, 0x0e, 0xcc, 0x88, 0xa2, 0x34, 0x72, 0x8b, 0x3c, - 0xa2, 0x0e, 0xcc, 0xa8, 0xa2, 0x30, 0x72, 0xab, 0x90, 0x00, 0xa2, 0x0f, 0x72, 0x8b, - 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa9, 0x76, 0xa2, 0x0e, 0xcc, 0x88, 0x99, 0x37, - 0xa2, 0x08, 0x74, 0x8b, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa9, 0x64, 0xa2, 0x0e, - 0xcc, 0xa8, 0xa2, 0x04, 0x74, 0xab, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa9, 0x54, - 0xa2, 0x0e, 0xcc, 0xa8, 0xa2, 0x00, 0x74, 0xab, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, - 0xa9, 0x44, 0xa2, 0x0e, 0xcc, 0x88, 0xa2, 0x02, 0x74, 0x8b, 0x3c, 0xa2, 0x0a, 0xcc, - 0xa8, 0xb5, 0xa9, 0x34, 0xa2, 0x0e, 0xcc, 0xa8, 0xa2, 0x0a, 0x74, 0xab, 0xa2, 0x10, - 0xcc, 0xa8, 0xa2, 0x0c, 0x74, 0xab, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa9, 0x1c, - 0xa2, 0x0e, 0xcc, 0xa8, 0xa2, 0x0e, 0x74, 0xab, 0xa2, 0x10, 0xcc, 0xa8, 0xa2, 0x10, - 0x74, 0xab, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa9, 0x04, 0xa2, 0x0e, 0xcc, 0x88, - 0xa2, 0x1e, 0x74, 0x8b, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa8, 0xf4, 0xaf, 0xcc, - 0xac, 0xcc, 0xca, 0x82, 0x0e, 0xcc, 0xf8, 0xac, 0x74, 0xca, 0x82, 0x12, 0xca, 0xf8, - 0xb5, 0xd1, 0xd7, 0x3f, 0xcc, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa8, 0xff, 0xa2, - 0x0e, 0xcc, 0xa8, 0xa2, 0x0c, 0x78, 0xab, 0xa2, 0x10, 0xcc, 0xa8, 0xa2, 0x0e, 0x78, - 0xab, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa8, 0xe7, 0xa2, 0x0e, 0xcc, 0xa8, 0xa2, - 0x08, 0x78, 0xab, 0xa2, 0x10, 0xcc, 0xa8, 0xa2, 0x0a, 0x78, 0xab, 0x3c, 0xa2, 0x0a, - 0xcc, 0xa8, 0xb5, 0xa8, 0xcf, 0xa2, 0x0e, 0xcc, 0xa8, 0xa2, 0x04, 0x78, 0xab, 0xa2, - 0x10, 0xcc, 0xa8, 0xa2, 0x06, 0x78, 0xab, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa8, - 0xb7, 0xa2, 0x0e, 0xcc, 0xa8, 0xa2, 0x00, 0x78, 0xab, 0xa2, 0x10, 0xcc, 0xa8, 0xa2, - 0x02, 0x78, 0xab, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa8, 0x8b, 0xa2, 0x0e, 0xcc, - 0xa8, 0xa2, 0x06, 0x76, 0xab, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa8, 0x7b, 0xa2, - 0x0e, 0xcc, 0x88, 0xa2, 0x0c, 0x76, 0x8b, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa8, - 0x6b, 0xa2, 0x06, 0x76, 0xa8, 0x9c, 0x00, 0x4d, 0x9c, 0x01, 0x94, 0x30, 0x9c, 0x02, - 0x94, 0x53, 0x9c, 0x03, 0x94, 0x76, 0x3c, 0xa2, 0x0f, 0xcc, 0x88, 0x99, 0x01, 0xa2, - 0x13, 0x76, 0x8b, 0xa2, 0x10, 0xcc, 0x88, 0x99, 0x5b, 0xa2, 0x14, 0x76, 0x8b, 0xa2, - 0x11, 0xcc, 0x88, 0x99, 0xdb, 0xa2, 0x15, 0x76, 0x8b, 0xa2, 0x22, 0x76, 0x88, 0xa2, - 0x10, 0x72, 0x8b, 0x3c, 0xa2, 0x0f, 0xcc, 0x88, 0x99, 0x01, 0xa2, 0x13, 0x76, 0x8b, - 0xa2, 0x10, 0xcc, 0x88, 0x99, 0x6d, 0xa2, 0x14, 0x76, 0x8b, 0xa2, 0x11, 0xcc, 0x88, - 0x99, 0xed, 0xa2, 0x15, 0x76, 0x8b, 0xa2, 0x22, 0x76, 0x88, 0xa2, 0x11, 0x72, 0x8b, - 0x3c, 0xa2, 0x0f, 0xcc, 0x88, 0x99, 0x01, 0xa2, 0x13, 0x76, 0x8b, 0xa2, 0x10, 0xcc, - 0x88, 0x99, 0x6d, 0xa2, 0x14, 0x76, 0x8b, 0xa2, 0x11, 0xcc, 0x88, 0x99, 0x6d, 0xa2, - 0x15, 0x76, 0x8b, 0xa2, 0x22, 0x76, 0x88, 0xa2, 0x12, 0x72, 0x8b, 0x3c, 0xa2, 0x0f, - 0xcc, 0x88, 0x99, 0x01, 0xa2, 0x13, 0x76, 0x8b, 0xa2, 0x10, 0xcc, 0x88, 0x99, 0x37, - 0xa2, 0x14, 0x76, 0x8b, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa7, 0xc6, 0xa2, 0x0e, - 0xcc, 0xa8, 0xa2, 0x08, 0x76, 0xab, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa7, 0xb6, - 0xa2, 0x0e, 0xcc, 0x88, 0xa2, 0x10, 0x76, 0x8b, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, - 0xa7, 0xa6, 0xa2, 0x0e, 0xcc, 0x88, 0xa2, 0x11, 0x76, 0x8b, 0x3c, 0xa2, 0x0a, 0xcc, - 0xa8, 0xb5, 0xa7, 0x96, 0xa2, 0x0e, 0xcc, 0xa8, 0xa2, 0x0e, 0x76, 0xab, 0x3c, 0xa2, - 0x0a, 0xcc, 0xa8, 0xb5, 0xa7, 0x86, 0xa2, 0x0e, 0xcc, 0xa8, 0xa2, 0x00, 0x76, 0xab, - 0xa2, 0x10, 0xcc, 0xa8, 0xa2, 0x02, 0x76, 0xab, 0xa2, 0x0e, 0xcc, 0xfa, 0x9d, 0x00, - 0x3c, 0x90, 0x02, 0x01, 0xa2, 0x0c, 0x76, 0xd9, 0xa2, 0x0c, 0x76, 0x8b, 0x3c, 0xa2, - 0x0a, 0xcc, 0xa8, 0xb5, 0xa7, 0x5c, 0x91, 0x02, 0xa2, 0x0e, 0xcc, 0x88, 0x9c, 0x00, - 0x91, 0x02, 0x9c, 0x01, 0x91, 0x01, 0x9c, 0x02, 0x91, 0x08, 0x9c, 0x03, 0x91, 0x04, - 0x9c, 0x04, 0xb1, 0x01, 0x00, 0xa8, 0xca, 0xa2, 0x04, 0x76, 0xab, 0x3c, 0xa2, 0x0a, - 0xcc, 0xa8, 0xb5, 0xa7, 0x33, 0xa2, 0x0e, 0xcc, 0x88, 0xa2, 0x17, 0x76, 0x8b, 0x3c, - 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa7, 0x23, 0xa2, 0x0e, 0xcc, 0x88, 0xa2, 0x18, 0x76, - 0x8b, 0x3c, 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa6, 0xff, 0xac, 0x74, 0xce, 0x82, 0x58, - 0xce, 0xf8, 0xa2, 0x12, 0xcc, 0x88, 0xe7, 0xe7, 0xa0, 0xc8, 0xce, 0xf8, 0xa2, 0x0e, - 0xcc, 0x88, 0xd6, 0xa2, 0x0f, 0xcc, 0x88, 0xa2, 0x01, 0xce, 0x8b, 0xa2, 0x10, 0xcc, - 0x88, 0xa2, 0x02, 0xce, 0x8b, 0xa2, 0x11, 0xcc, 0x88, 0xa2, 0x03, 0xce, 0x8b, 0x3c, - 0xa2, 0x0a, 0xcc, 0xa8, 0xb5, 0xa6, 0xdd, 0xac, 0x76, 0xce, 0x82, 0x1a, 0xce, 0xf8, - 0xa2, 0x12, 0xcc, 0x88, 0xe7, 0xe7, 0xa0, 0xc8, 0xce, 0xf8, 0xa2, 0x0e, 0xcc, 0x88, - 0xd6, 0xa2, 0x0f, 0xcc, 0x88, 0xa2, 0x01, 0xce, 0x8b, 0xa2, 0x10, 0xcc, 0x88, 0xa2, - 0x02, 0xce, 0x8b, 0xa2, 0x11, 0xcc, 0x88, 0xa2, 0x03, 0xce, 0x8b, 0x3c, 0x03, 0xae, - 0xca, 0xd7, 0xae, 0xca, 0xd7, 0x03, 0xae, 0xca, 0xd7, 0xae, 0xca, 0xd7, 0x03, 0xae, - 0xca, 0xd7, 0xae, 0xca, 0xd7, 0x3c, 0x00, 0xb6, 0xfe, 0x20, 0xab, 0xb6, 0xfe, 0x00, - 0xab, 0xb6, 0xfe, 0x90, 0xab, 0x3c, 0xac, 0xcc, 0x28, 0xac, 0xce, 0x2a, 0xab, 0xce, - 0xa8, 0x16, 0xb8, 0x00, 0x0a, 0x96, 0x14, 0xfc, 0x94, 0x45, 0xb2, 0xcf, 0x1e, 0xa0, - 0x16, 0xcc, 0xf8, 0xa8, 0x1a, 0xa2, 0x02, 0xcc, 0xab, 0xa8, 0x18, 0xa2, 0x01, 0xcc, - 0x8b, 0xa8, 0xce, 0xc6, 0xa8, 0x1c, 0xa2, 0x04, 0xcc, 0xab, 0xa8, 0x1e, 0xa2, 0x06, - 0xcc, 0xab, 0xa8, 0x20, 0xa2, 0x08, 0xcc, 0xab, 0xa8, 0x16, 0xb8, 0x00, 0x0a, 0xbc, - 0x0b, 0xae, 0x00, 0xab, 0x16, 0xaf, 0xca, 0xb1, 0x04, 0x00, 0xb5, 0x58, 0x5e, 0x3f, - 0xca, 0x00, 0xac, 0x28, 0xcc, 0xac, 0x2a, 0xce, 0x3c, 0xb6, 0xff, 0x04, 0xa9, 0x76, - 0x00, 0xab, 0x14, 0xab, 0x16, 0xa7, 0xcf, 0x1e, 0xda, 0xd6, 0x00, 0xe1, 0x62, 0x3c, - 0xa8, 0x14, 0x96, 0x16, 0xfc, 0x42, 0x00, 0x3c, 0x90, 0x01, 0x63, 0x34, 0x0b, 0x9c, - 0x00, 0x44, 0xb0, 0xf0, 0x00, 0x3c, 0xb6, 0xfe, 0x00, 0x88, 0x96, 0xc8, 0x17, 0x94, - 0x35, 0xaf, 0xce, 0xaf, 0xcc, 0xa7, 0xfe, 0x00, 0xfe, 0x0e, 0xb3, 0xcf, 0x1e, 0xa0, - 0x14, 0xce, 0xf8, 0xf0, 0xb9, 0xff, 0x7f, 0xe1, 0xf0, 0xe1, 0xf0, 0xe1, 0xf0, 0xe1, - 0xf0, 0xe1, 0xa8, 0x14, 0xb8, 0x00, 0x0a, 0xbc, 0x0b, 0xae, 0x00, 0xab, 0x14, 0xb3, - 0xfe, 0x00, 0xd4, 0x9a, 0x80, 0xd6, 0x3f, 0xcc, 0x3f, 0xce, 0x00, 0x3c, 0xb0, 0xf0, - 0x01, 0x3c, 0xb7, 0x00, 0x00, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xac, 0xce, 0xcc, 0x82, - 0x48, 0xcc, 0xf8, 0xb7, 0x00, 0x00, 0x06, 0x00, 0xb4, 0xcf, 0x24, 0xa2, 0x35, 0xce, - 0x88, 0x9c, 0x00, 0x94, 0x22, 0xa2, 0x3f, 0xce, 0x88, 0x9c, 0x00, 0x94, 0x23, 0xb7, - 0x00, 0x00, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xac, 0xce, 0xcc, 0x82, 0x48, 0xcc, 0xf8, - 0xb7, 0x02, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb4, 0xce, 0xfa, 0xb7, 0x1e, 0x84, - 0x02, 0xb7, 0x00, 0x00, 0x04, 0x7a, 0xb7, 0x31, 0x2d, 0x02, 0xb7, 0x00, 0x01, 0x04, - 0x95, 0x23, 0xa2, 0x35, 0xce, 0x88, 0x9c, 0x00, 0x3c, 0xb7, 0x09, 0xc4, 0x02, 0xb7, - 0x00, 0x00, 0x04, 0xac, 0xce, 0xcc, 0x82, 0x48, 0xcc, 0xf8, 0xb7, 0x02, 0x00, 0x06, - 0xa2, 0x22, 0xce, 0x88, 0xb4, 0xce, 0xc6, 0xb7, 0x62, 0x5a, 0x08, 0xb7, 0x00, 0x02, - 0x0a, 0xa2, 0x35, 0xce, 0x88, 0x9c, 0x00, 0x94, 0x35, 0xa2, 0x36, 0xce, 0x88, 0x9c, - 0x00, 0x94, 0x77, 0xa2, 0x38, 0xce, 0x88, 0x9c, 0x00, 0x94, 0x25, 0xa2, 0x37, 0xce, - 0x88, 0x9d, 0x00, 0x5e, 0xa2, 0x34, 0xce, 0x88, 0x9c, 0x07, 0x4a, 0xf4, 0xab, 0x08, - 0xa2, 0x02, 0xce, 0xa8, 0xab, 0x0a, 0x4d, 0xa2, 0x24, 0xce, 0xa8, 0xab, 0x08, 0xa2, - 0x26, 0xce, 0xa8, 0xab, 0x0a, 0x40, 0xa2, 0x54, 0xce, 0x88, 0x9c, 0x00, 0x47, 0xa2, - 0x34, 0xce, 0x88, 0x9c, 0x07, 0x58, 0xac, 0x08, 0x02, 0xac, 0x0a, 0x04, 0xac, 0xce, - 0xcc, 0x82, 0x48, 0xcc, 0xf8, 0xb7, 0x02, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb4, - 0xce, 0x5b, 0x86, 0x12, 0x60, 0x08, 0xfc, 0x41, 0x7e, 0x86, 0x04, 0xa8, 0x0a, 0xfc, - 0x42, 0x95, 0x25, 0xb7, 0x01, 0x07, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, - 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xa6, 0x60, 0x95, 0x3a, 0xb7, 0x00, 0x4e, 0x08, - 0xb7, 0x00, 0x00, 0x0a, 0x95, 0x52, 0xa2, 0x35, 0xce, 0x88, 0x9c, 0x00, 0x5a, 0xb7, - 0x00, 0x4e, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xac, 0xce, 0xcc, 0x82, 0x48, 0xcc, 0xf8, - 0xb7, 0x02, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb4, 0xce, 0x0c, 0xb7, 0x62, 0x5a, - 0x02, 0xb7, 0x00, 0x02, 0x04, 0x7a, 0x95, 0x2a, 0x95, 0x2c, 0xa2, 0x35, 0xce, 0x88, - 0x9c, 0x00, 0x94, 0x21, 0xa2, 0x3a, 0xce, 0x88, 0x9d, 0x00, 0x5a, 0xb7, 0x00, 0x4e, - 0x02, 0xb7, 0x00, 0x00, 0x04, 0xac, 0xce, 0xcc, 0x82, 0x48, 0xcc, 0xf8, 0xb7, 0x02, - 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb4, 0xcd, 0xd6, 0xa2, 0x35, 0xce, 0x88, 0x9c, - 0x00, 0x4a, 0xb7, 0x00, 0x00, 0x02, 0xb7, 0x00, 0x00, 0x04, 0x95, 0x21, 0xb7, 0x62, - 0x5a, 0x02, 0xb7, 0x00, 0x02, 0x04, 0x95, 0x2b, 0x90, 0x00, 0xa2, 0x50, 0xce, 0xab, - 0xb5, 0xd3, 0xf7, 0x90, 0x00, 0xb5, 0xd3, 0xca, 0x91, 0x02, 0xa2, 0x22, 0xce, 0x88, - 0xb5, 0xd4, 0xdc, 0xb7, 0x03, 0x01, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, - 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xa5, 0xb8, 0xb7, 0x03, 0x02, 0x02, 0xb7, 0x00, - 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xa5, 0xa5, 0x90, - 0x00, 0xa2, 0x3f, 0xce, 0x8b, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x21, - 0xb5, 0xe9, 0x4d, 0x90, 0x00, 0xa2, 0x2a, 0xce, 0x8b, 0xa2, 0x22, 0xce, 0x88, 0xab, - 0x18, 0xb0, 0x40, 0x3f, 0xb5, 0xe9, 0x3b, 0x90, 0x00, 0xa2, 0x2c, 0xce, 0xab, 0xa2, - 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x3d, 0xb5, 0xe9, 0x29, 0x90, 0x00, 0xa2, - 0x4e, 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x3e, 0xb5, 0xe9, - 0x17, 0xb7, 0x05, 0x02, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, - 0x22, 0xce, 0x88, 0xb5, 0xa5, 0x4a, 0xb7, 0x00, 0x00, 0x02, 0xb7, 0x00, 0x00, 0x04, - 0xb7, 0x02, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xac, 0xce, 0xcc, 0x82, 0x4c, 0xcc, - 0xf8, 0xb5, 0xcd, 0x09, 0xb4, 0xfd, 0xcb, 0x90, 0x00, 0xb5, 0xd3, 0x1e, 0x91, 0x02, - 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xd4, 0x30, 0x90, 0x07, 0xa2, 0x50, 0xce, 0xab, 0xb5, - 0xd3, 0x34, 0xb7, 0x03, 0x01, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, - 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xa5, 0x03, 0xb7, 0x03, 0x02, 0x02, 0xb7, 0x00, 0x00, - 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xa4, 0xf0, 0x90, 0x00, - 0xa2, 0x3f, 0xce, 0x8b, 0xa2, 0x35, 0xce, 0x8b, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, - 0xb0, 0x40, 0x21, 0xb5, 0xe8, 0x94, 0x90, 0x00, 0xa2, 0x29, 0xce, 0x8b, 0xa2, 0x54, - 0xce, 0x88, 0x9c, 0x00, 0x94, 0x1f, 0xa2, 0x34, 0x72, 0xa8, 0x9c, 0x01, 0x41, 0x44, - 0xa2, 0x22, 0xce, 0x88, 0xb7, 0x01, 0x07, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, - 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xa4, 0xad, 0xa2, 0x2a, 0xce, 0x88, 0x9c, - 0x00, 0x94, 0x42, 0x90, 0x01, 0xa2, 0x4e, 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, - 0x18, 0xb0, 0x40, 0x3e, 0xb5, 0xe8, 0x4d, 0xb7, 0x05, 0x02, 0x02, 0xb7, 0x00, 0x00, - 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xa4, 0x80, 0xb7, 0x00, - 0x00, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x02, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, - 0xac, 0xce, 0xcc, 0x82, 0x4c, 0xcc, 0xf8, 0xb5, 0xcc, 0x3f, 0xb4, 0xfd, 0x18, 0xa2, - 0x2c, 0xce, 0xa8, 0x9c, 0x01, 0x95, 0x48, 0x90, 0x01, 0xa2, 0x2c, 0xce, 0xab, 0xa2, - 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x3d, 0xb5, 0xe8, 0x03, 0x95, 0x5c, 0xa2, - 0x14, 0x72, 0x88, 0x9d, 0x00, 0x95, 0xec, 0x90, 0x01, 0xa2, 0x41, 0xce, 0x8b, 0x3c, - 0x90, 0x30, 0x01, 0xab, 0xca, 0xa2, 0x50, 0xce, 0xa8, 0x96, 0xca, 0xf9, 0xa2, 0x50, - 0xce, 0xab, 0xb5, 0xd2, 0x43, 0x00, 0xa2, 0x35, 0xce, 0x8b, 0x90, 0x02, 0xa2, 0x4e, - 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x3e, 0xb5, 0xe7, 0xc8, - 0xb7, 0x05, 0x02, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, - 0xce, 0x88, 0xb5, 0xa3, 0xfb, 0xb7, 0x00, 0x00, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, - 0x02, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xac, 0xce, 0xcc, 0x82, 0x4c, 0xcc, 0xf8, - 0xb5, 0xcb, 0xba, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xd2, 0x5e, 0xa2, 0x2e, 0xce, 0xab, - 0xab, 0xca, 0x99, 0x06, 0x9c, 0x00, 0x48, 0xa2, 0x1e, 0x72, 0x88, 0x9c, 0x02, 0x94, - 0x2c, 0x82, 0x08, 0xca, 0xf9, 0x82, 0x00, 0xca, 0xfc, 0x94, 0x32, 0xa2, 0x3b, 0xce, - 0x88, 0x9d, 0x00, 0x94, 0x2a, 0x90, 0x01, 0xa2, 0x35, 0xce, 0x8b, 0xb7, 0x01, 0x03, - 0x02, 0xb7, 0x00, 0x04, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, - 0xa3, 0x9c, 0x50, 0xb7, 0x01, 0x04, 0x02, 0xb7, 0x00, 0x04, 0x04, 0xb7, 0x00, 0x00, - 0x06, 0x00, 0xb5, 0xa3, 0x8b, 0x91, 0x08, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xd2, 0x93, - 0x3c, 0x90, 0x00, 0xa2, 0x35, 0xce, 0x8b, 0xa2, 0x3f, 0xce, 0x8b, 0xa2, 0x22, 0xce, - 0x88, 0xab, 0x18, 0xb0, 0x40, 0x21, 0xb5, 0xe7, 0x25, 0x90, 0x08, 0xa2, 0x50, 0xce, - 0xfa, 0xa2, 0x50, 0xce, 0xab, 0xb5, 0xd1, 0x7c, 0x90, 0x03, 0xa2, 0x4e, 0xce, 0xab, - 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x3e, 0xb5, 0xe7, 0x06, 0xa2, 0x22, - 0xce, 0x88, 0xb5, 0xd1, 0xc9, 0xa2, 0x2e, 0xce, 0xab, 0xab, 0xca, 0x99, 0x04, 0x9d, - 0x00, 0x5c, 0x82, 0x40, 0xca, 0xf9, 0x82, 0x00, 0xca, 0xfd, 0xb4, 0xfe, 0x02, 0x90, - 0x01, 0xb5, 0xd1, 0x20, 0x91, 0x04, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xd2, 0x32, 0xb4, - 0xfc, 0x10, 0x90, 0x01, 0xa2, 0x35, 0xce, 0x8b, 0x77, 0x00, 0xa2, 0x35, 0xce, 0x8b, - 0xa2, 0x36, 0xce, 0x8b, 0xa2, 0x37, 0xce, 0x8b, 0xa2, 0x38, 0xce, 0x8b, 0x90, 0x04, - 0xa2, 0x4e, 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x3e, 0xb5, - 0xe6, 0xae, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xd1, 0x71, 0xa2, 0x2e, 0xce, 0xab, 0x99, - 0x40, 0x9c, 0x00, 0x54, 0x90, 0x08, 0x01, 0xa2, 0x50, 0xce, 0xf9, 0xa2, 0x50, 0xce, - 0xab, 0xb5, 0xd0, 0xf4, 0x90, 0x01, 0xa2, 0x35, 0xce, 0x8b, 0xa2, 0x22, 0xce, 0x88, - 0xb5, 0xd1, 0x4d, 0xa2, 0x2e, 0xce, 0xab, 0x99, 0x02, 0x9d, 0x00, 0xb4, 0xfd, 0x91, - 0xa2, 0x34, 0xce, 0x88, 0x9d, 0x04, 0x4c, 0x91, 0x01, 0xa2, 0x22, 0xce, 0x88, 0xb5, - 0xd1, 0xbf, 0xb4, 0xfb, 0xbe, 0xa2, 0x3c, 0xce, 0x88, 0x9d, 0x00, 0x72, 0xac, 0xce, - 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0x90, 0x04, 0xb5, 0x09, 0xae, 0x42, 0x95, 0x20, 0x90, - 0x05, 0xb5, 0x09, 0xa6, 0x42, 0x95, 0x28, 0x90, 0x03, 0xb5, 0x09, 0x9e, 0xb4, 0xfd, - 0x58, 0x95, 0x32, 0x00, 0xa2, 0x35, 0xce, 0x8b, 0x90, 0x05, 0xa2, 0x4e, 0xce, 0xab, - 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x3e, 0xb5, 0xe6, 0x26, 0xa2, 0x22, - 0xce, 0x88, 0xb5, 0xd0, 0xe9, 0xa2, 0x2e, 0xce, 0xab, 0xab, 0xca, 0x99, 0x04, 0x9c, - 0x00, 0x94, 0x40, 0x90, 0x01, 0xa2, 0x35, 0xce, 0x8b, 0xac, 0xce, 0xcc, 0x82, 0x46, - 0xcc, 0xf8, 0xa2, 0x34, 0xce, 0x88, 0xb5, 0x09, 0x4b, 0xac, 0xce, 0xcc, 0x82, 0x44, - 0xcc, 0xf8, 0xa2, 0x34, 0xce, 0x88, 0xb5, 0x09, 0x4d, 0x5a, 0x91, 0x08, 0xa2, 0x22, - 0xce, 0x88, 0xb5, 0xd1, 0x3e, 0xb5, 0xfb, 0xd6, 0x90, 0x08, 0xa2, 0x50, 0xce, 0xfa, - 0xa2, 0x50, 0xce, 0xab, 0xb5, 0xd0, 0x3b, 0x3c, 0x91, 0x04, 0x7a, 0x82, 0x08, 0xca, - 0xf9, 0x82, 0x00, 0xca, 0xfc, 0x95, 0x34, 0x90, 0x01, 0xa2, 0x35, 0xce, 0x8b, 0xac, - 0xce, 0xcc, 0x82, 0x46, 0xcc, 0xf8, 0xa2, 0x34, 0xce, 0x88, 0xb5, 0x09, 0x09, 0x95, - 0x4a, 0xa2, 0x06, 0xce, 0xa8, 0x9c, 0x03, 0x42, 0x94, 0x3e, 0xa2, 0x30, 0x72, 0xa8, - 0x9c, 0x00, 0x94, 0x36, 0xa2, 0x54, 0xce, 0x88, 0x9d, 0x00, 0x94, 0x2e, 0xa2, 0x24, - 0xce, 0xa8, 0xbc, 0x12, 0x60, 0x42, 0x94, 0x24, 0xa2, 0x26, 0xce, 0xa8, 0xbc, 0x04, - 0xa8, 0x41, 0x5b, 0xa2, 0x30, 0x72, 0xa8, 0xa2, 0x32, 0x72, 0xfd, 0x43, 0xb4, 0xfc, - 0x94, 0xa2, 0x32, 0x72, 0xa8, 0x04, 0xa2, 0x32, 0x72, 0xab, 0x90, 0x01, 0xa2, 0x54, - 0xce, 0x8b, 0x90, 0x00, 0xa2, 0x35, 0xce, 0x8b, 0x90, 0x06, 0xa2, 0x4e, 0xce, 0xab, - 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x3e, 0xb5, 0xe5, 0x54, 0xa2, 0x22, - 0xce, 0x88, 0xb5, 0xd0, 0x17, 0xa2, 0x2e, 0xce, 0xab, 0x99, 0x04, 0x9d, 0x00, 0x59, - 0x90, 0x08, 0xa2, 0x50, 0xce, 0xfa, 0xa2, 0x50, 0xce, 0xab, 0xb5, 0xcf, 0x9b, 0x91, - 0x04, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xd0, 0x85, 0xb4, 0xfb, 0x47, 0x90, 0x01, 0xa2, - 0x35, 0xce, 0x8b, 0x7f, 0x00, 0xa2, 0x35, 0xce, 0x8b, 0x90, 0x07, 0xa2, 0x4e, 0xce, - 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x3e, 0xb5, 0xe5, 0x0d, 0xa2, - 0x22, 0xce, 0x88, 0xb5, 0xcf, 0xd0, 0xa2, 0x2e, 0xce, 0xab, 0xab, 0xca, 0x99, 0x08, - 0x9d, 0x00, 0x4c, 0x82, 0x40, 0xca, 0xf9, 0x82, 0x00, 0xca, 0xfc, 0x4a, 0xb4, 0xfc, - 0x08, 0x90, 0x01, 0xa2, 0x35, 0xce, 0x8b, 0x40, 0x91, 0x08, 0xa2, 0x22, 0xce, 0x88, - 0xb5, 0xd0, 0x36, 0xb4, 0xfa, 0xfa, 0x00, 0xa2, 0x35, 0xce, 0x8b, 0xa2, 0x3b, 0xce, - 0x8b, 0x90, 0x03, 0xa2, 0x2c, 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, - 0x40, 0x3d, 0xb5, 0xe4, 0xc1, 0x00, 0xa2, 0x41, 0xce, 0x8b, 0xa2, 0x4c, 0xce, 0xab, - 0x90, 0x08, 0xa2, 0x4e, 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, - 0x3e, 0xb5, 0xe4, 0xa6, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xcf, 0x69, 0xa2, 0x2e, 0xce, - 0xab, 0x99, 0x40, 0x9c, 0x00, 0x54, 0x90, 0x01, 0xa2, 0x35, 0xce, 0x8b, 0x90, 0x08, - 0x01, 0xa2, 0x50, 0xce, 0xf9, 0xa2, 0x50, 0xce, 0xab, 0xb5, 0xce, 0xe6, 0x91, 0x01, - 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xcf, 0xd0, 0xb4, 0xfa, 0x96, 0x90, 0x00, 0xa2, 0x50, - 0xce, 0xab, 0xb5, 0xce, 0xd1, 0x90, 0x09, 0xa2, 0x4e, 0xce, 0xab, 0xa2, 0x22, 0xce, - 0x88, 0xab, 0x18, 0xb0, 0x40, 0x3e, 0xb5, 0xe4, 0x5b, 0xa2, 0x04, 0xce, 0xa8, 0x9c, - 0x02, 0x94, 0x2c, 0x90, 0x01, 0xb5, 0xce, 0x8a, 0xb7, 0x00, 0x00, 0x02, 0xb7, 0x00, - 0x00, 0x04, 0xb7, 0x02, 0x00, 0x06, 0xac, 0xce, 0xcc, 0x82, 0x4c, 0xcc, 0xf8, 0xa2, - 0x22, 0xce, 0x88, 0xb5, 0xc8, 0x53, 0xa2, 0x04, 0xce, 0xa8, 0xab, 0xca, 0xa2, 0x22, - 0xce, 0x88, 0xb4, 0xcf, 0x7e, 0x90, 0x00, 0xb5, 0xce, 0x5e, 0x95, 0x2c, 0xa8, 0x46, - 0xb5, 0x9e, 0xc9, 0xa2, 0x0e, 0x76, 0xa8, 0x9c, 0x00, 0x3c, 0xa8, 0x44, 0xbc, 0x02, - 0x09, 0x55, 0xbc, 0x02, 0xff, 0x59, 0xbc, 0x02, 0x01, 0x94, 0x46, 0xbc, 0x02, 0x04, - 0x94, 0x4e, 0xbc, 0x02, 0x10, 0x94, 0x79, 0x94, 0xb2, 0xa8, 0x48, 0xa2, 0x2e, 0x76, - 0xab, 0x94, 0xaa, 0xa8, 0x48, 0xa2, 0x48, 0x76, 0xfc, 0x94, 0x23, 0xa2, 0x4a, 0x76, - 0xfc, 0x46, 0xa2, 0x4c, 0x76, 0xfc, 0x4d, 0x3c, 0xb0, 0x02, 0x0b, 0xab, 0x44, 0x00, - 0xa2, 0x4a, 0x76, 0xab, 0x94, 0x8b, 0xb0, 0x02, 0x0d, 0xab, 0x44, 0x00, 0xa2, 0x4c, - 0x76, 0xab, 0x94, 0x7f, 0x00, 0xa2, 0x48, 0x76, 0xab, 0x94, 0x78, 0xa2, 0x4e, 0x76, - 0xa8, 0x9c, 0x09, 0x3c, 0xac, 0x76, 0xce, 0xb4, 0xfa, 0xcb, 0xa2, 0x4e, 0x76, 0xa8, - 0x9c, 0x09, 0x3c, 0xac, 0x76, 0xce, 0xb5, 0xfa, 0x09, 0xa2, 0x54, 0x76, 0x88, 0x9c, - 0x00, 0x3c, 0xa2, 0x34, 0x72, 0xa8, 0x9c, 0x01, 0x41, 0x43, 0xac, 0x76, 0xce, 0xb7, - 0x01, 0x07, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa8, 0x46, 0xb4, - 0x9f, 0xc8, 0xac, 0x76, 0xce, 0xb5, 0xf9, 0xe0, 0xa2, 0x54, 0x76, 0x88, 0x9c, 0x00, - 0x5c, 0xa2, 0x34, 0x72, 0xa8, 0x9c, 0x01, 0x41, 0x43, 0xac, 0x76, 0xce, 0xb7, 0x01, - 0x07, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa8, 0x46, 0xb5, 0x9f, - 0x9f, 0x90, 0x09, 0xa2, 0x4e, 0x76, 0xab, 0xa2, 0x22, 0x76, 0x88, 0xab, 0x18, 0xb0, - 0x40, 0x3e, 0xb4, 0xe3, 0x47, 0xa2, 0x4e, 0x76, 0xa8, 0x9c, 0x00, 0x94, 0x2b, 0x9c, - 0x01, 0x94, 0x3a, 0x9c, 0x02, 0x94, 0x93, 0x9c, 0x03, 0x94, 0xec, 0x9c, 0x04, 0xb4, - 0x01, 0x74, 0x9c, 0x05, 0xb4, 0x02, 0xad, 0x9c, 0x06, 0xb4, 0x03, 0x42, 0x9c, 0x07, - 0xb4, 0x03, 0xba, 0x9c, 0x08, 0xb4, 0x04, 0x1f, 0x9c, 0x09, 0xb4, 0x06, 0x44, 0x3c, - 0xa8, 0x44, 0xbc, 0x02, 0x02, 0x41, 0x3c, 0xa8, 0x48, 0xa2, 0x04, 0x76, 0xab, 0xac, - 0x76, 0xce, 0xb4, 0xfe, 0x8b, 0xa8, 0x44, 0xbc, 0x02, 0xff, 0x46, 0xbc, 0x02, 0x09, - 0x94, 0x35, 0x3c, 0xa2, 0x35, 0x76, 0x88, 0x9c, 0x00, 0x4f, 0x90, 0x01, 0xa2, 0x3f, - 0x76, 0x8b, 0xac, 0x46, 0x18, 0xb0, 0x40, 0x21, 0xb4, 0xe2, 0xdf, 0x90, 0x01, 0xa2, - 0x35, 0x76, 0x8b, 0xac, 0x76, 0xce, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xcd, 0x99, 0xa2, - 0x2e, 0x76, 0xab, 0x99, 0x06, 0x9c, 0x00, 0xb4, 0xf7, 0xbf, 0xb4, 0xfb, 0x86, 0xa2, - 0x35, 0x76, 0x88, 0x9c, 0x00, 0x3c, 0xac, 0x76, 0xce, 0xa2, 0x22, 0xce, 0x88, 0xb5, - 0xcd, 0x7a, 0xa2, 0x2e, 0x76, 0xab, 0x99, 0x06, 0x9c, 0x00, 0x3c, 0xb4, 0xfb, 0x69, - 0xa8, 0x44, 0xbc, 0x02, 0x09, 0x41, 0x3c, 0xa2, 0x2e, 0x76, 0xa8, 0x99, 0x06, 0x9c, - 0x00, 0x4f, 0xa2, 0x35, 0x76, 0x88, 0x9d, 0x00, 0x48, 0xa2, 0x1e, 0x72, 0x88, 0x9c, - 0x02, 0x94, 0x2e, 0xa2, 0x2e, 0x76, 0xa8, 0x99, 0x08, 0x9c, 0x00, 0x3c, 0xa2, 0x35, - 0x76, 0x88, 0x9d, 0x00, 0x3c, 0xa2, 0x3b, 0x76, 0x88, 0x9d, 0x00, 0x3c, 0x90, 0x01, - 0xa2, 0x35, 0x76, 0x8b, 0xb7, 0x01, 0x03, 0x02, 0xb7, 0x00, 0x04, 0x04, 0xb7, 0x00, - 0x00, 0x06, 0xa8, 0x46, 0xb4, 0x9e, 0x9d, 0xb7, 0x01, 0x04, 0x02, 0xb7, 0x00, 0x04, - 0x04, 0xb7, 0x00, 0x00, 0x06, 0x00, 0xb4, 0x9e, 0x8d, 0xa8, 0x44, 0xbc, 0x02, 0x09, - 0x4b, 0xbc, 0x02, 0x14, 0x94, 0x31, 0xbc, 0x02, 0xff, 0x94, 0x33, 0x3c, 0xa2, 0x35, - 0x76, 0x88, 0x9d, 0x00, 0x3c, 0xa2, 0x2e, 0x76, 0xa8, 0x99, 0x04, 0x9c, 0x00, 0x4c, - 0x90, 0x01, 0xa2, 0x35, 0x76, 0x8b, 0xac, 0x76, 0xce, 0xb4, 0xf7, 0x52, 0xa2, 0x2e, - 0x76, 0xa8, 0x99, 0x40, 0x9c, 0x00, 0x3c, 0xac, 0x76, 0xce, 0xb4, 0xf9, 0x24, 0xa2, - 0x48, 0x76, 0xa8, 0x9d, 0x00, 0x3c, 0xa2, 0x35, 0x76, 0x88, 0x9c, 0x00, 0x3c, 0xa2, - 0x06, 0x76, 0xa8, 0x9c, 0x03, 0x4b, 0x00, 0xa2, 0x34, 0x76, 0x8b, 0xac, 0x76, 0xce, - 0xb4, 0xfb, 0x1a, 0xa2, 0x30, 0x72, 0x88, 0x9c, 0x00, 0x71, 0xa2, 0x30, 0x72, 0xa8, - 0xa2, 0x32, 0x72, 0xfd, 0x47, 0x90, 0x01, 0xa2, 0x55, 0x76, 0x8b, 0x3c, 0xa2, 0x32, - 0x72, 0xa8, 0x04, 0xa2, 0x32, 0x72, 0xab, 0x90, 0x01, 0xa2, 0x55, 0x76, 0x8b, 0x00, - 0xa2, 0x34, 0x76, 0x8b, 0xac, 0x76, 0xce, 0xb4, 0xfa, 0xe9, 0xa8, 0x44, 0xbc, 0x02, - 0x09, 0x94, 0x3c, 0xbc, 0x02, 0xff, 0x94, 0x92, 0xbc, 0x02, 0x06, 0x4e, 0xbc, 0x02, - 0x05, 0x5a, 0xbc, 0x02, 0x07, 0x5c, 0xbc, 0x02, 0x13, 0x94, 0xf0, 0x3c, 0xb1, 0x01, - 0x00, 0xac, 0x76, 0xce, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xcc, 0xe6, 0xb4, 0xf6, 0xe5, - 0xac, 0x76, 0xce, 0xb4, 0xfb, 0x49, 0xac, 0x76, 0xce, 0xa2, 0x3c, 0x76, 0x88, 0x9d, - 0x00, 0xb4, 0xf8, 0x93, 0xb4, 0xfb, 0xc4, 0xac, 0x76, 0xce, 0xa2, 0x2e, 0x76, 0xa8, - 0x99, 0x02, 0x9d, 0x00, 0xb4, 0xf8, 0x82, 0xa2, 0x2e, 0x76, 0xa8, 0x99, 0x40, 0x9c, - 0x00, 0x5e, 0xa2, 0x35, 0x76, 0x88, 0x9d, 0x00, 0x57, 0x90, 0x08, 0x01, 0xa2, 0x50, - 0x76, 0xf9, 0xa2, 0x50, 0x76, 0xab, 0xb5, 0xcb, 0xaf, 0x90, 0x01, 0xa2, 0x35, 0x76, - 0x8b, 0xb4, 0xf6, 0x9b, 0xa2, 0x2e, 0x76, 0xa8, 0x99, 0x0c, 0x9c, 0x00, 0x3c, 0xa2, - 0x38, 0x76, 0x88, 0x9c, 0x00, 0x3c, 0xa2, 0x37, 0x76, 0x88, 0x9d, 0x00, 0x3c, 0x90, - 0x01, 0xa2, 0x37, 0x76, 0x8b, 0xac, 0x76, 0xce, 0xb5, 0x04, 0x87, 0xb4, 0xf6, 0x75, - 0xa2, 0x35, 0x76, 0x88, 0x9d, 0x00, 0x4d, 0xa2, 0x34, 0x76, 0x88, 0x9c, 0x00, 0x3c, - 0xac, 0x76, 0xce, 0xb4, 0xf8, 0x21, 0xac, 0x76, 0xce, 0xa2, 0x36, 0xce, 0x88, 0x9d, - 0x00, 0x94, 0x36, 0x90, 0x01, 0xa2, 0x36, 0xce, 0x8b, 0xb5, 0x07, 0x8e, 0xb5, 0xf6, - 0x4a, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xcb, 0xb4, 0xa2, 0x2e, 0xce, 0xab, 0x99, 0x0c, - 0x9c, 0x00, 0x3c, 0xa2, 0x38, 0xce, 0x88, 0x9c, 0x00, 0x3c, 0xa2, 0x37, 0xce, 0x88, - 0x9d, 0x00, 0x3c, 0x90, 0x01, 0xa2, 0x37, 0xce, 0x8b, 0xb5, 0x04, 0x32, 0xb4, 0xf6, - 0x20, 0xa2, 0x38, 0xce, 0x88, 0x9c, 0x00, 0x3c, 0xa2, 0x37, 0xce, 0x88, 0x9d, 0x00, - 0x3c, 0x90, 0x01, 0xa2, 0x37, 0xce, 0x8b, 0xb5, 0x04, 0x18, 0xb4, 0xf6, 0x06, 0xa2, - 0x34, 0x76, 0x88, 0x9d, 0x04, 0x41, 0x3c, 0xa2, 0x3c, 0x76, 0x88, 0x9d, 0x00, 0x3c, - 0xac, 0x76, 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0x90, 0x04, 0xb5, 0x03, 0xee, 0x41, 0x3c, - 0x90, 0x05, 0xb5, 0x03, 0xe7, 0x41, 0x3c, 0x90, 0x03, 0xb5, 0x03, 0xe0, 0x41, 0x3c, - 0xac, 0x76, 0xce, 0xb4, 0xf7, 0x95, 0xa8, 0x44, 0xbc, 0x02, 0x09, 0x46, 0xbc, 0x02, - 0xff, 0x94, 0x77, 0x3c, 0xac, 0x76, 0xce, 0xa2, 0x2e, 0x76, 0xa8, 0x99, 0x02, 0x9d, - 0x00, 0xb4, 0xf7, 0x7b, 0xa2, 0x35, 0x76, 0x88, 0x9d, 0x00, 0x3c, 0xa2, 0x2e, 0x76, - 0xa8, 0x99, 0x04, 0x9c, 0x00, 0x94, 0x27, 0x90, 0x01, 0xa2, 0x35, 0x76, 0x8b, 0xa2, - 0x34, 0x76, 0x88, 0xac, 0x76, 0xcc, 0x82, 0x46, 0xcc, 0xf8, 0xb5, 0x03, 0x89, 0xa2, - 0x50, 0x76, 0xa8, 0x9a, 0x08, 0xa2, 0x50, 0x76, 0xab, 0xac, 0x76, 0xce, 0xb5, 0xca, - 0x91, 0xb5, 0xf6, 0x1c, 0xa2, 0x2e, 0x76, 0xa8, 0x99, 0x08, 0x9c, 0x00, 0x3c, 0x90, - 0x01, 0xa2, 0x35, 0x76, 0x8b, 0xa2, 0x34, 0x76, 0x88, 0xac, 0x76, 0xcc, 0x82, 0x46, - 0xcc, 0xf8, 0xb5, 0x03, 0x61, 0xa2, 0x50, 0x76, 0xa8, 0x9a, 0x08, 0xa2, 0x50, 0x76, - 0xab, 0xac, 0x76, 0xce, 0xb5, 0xca, 0x61, 0xb4, 0xf5, 0xec, 0xac, 0x76, 0xce, 0xa2, - 0x35, 0x76, 0x88, 0x9c, 0x00, 0xb4, 0xf7, 0x07, 0xa2, 0x34, 0x76, 0x88, 0x04, 0xa2, - 0x34, 0x76, 0x8b, 0xb4, 0xf9, 0x11, 0xa8, 0x44, 0xbc, 0x02, 0x09, 0x4b, 0xbc, 0x02, - 0xff, 0x94, 0x4d, 0xbc, 0x02, 0x13, 0x94, 0x60, 0x3c, 0xac, 0x76, 0xce, 0xa2, 0x2e, - 0x76, 0xa8, 0x99, 0x02, 0x9d, 0x00, 0xb4, 0xf6, 0xdc, 0xa2, 0x35, 0x76, 0x88, 0x9d, - 0x00, 0x55, 0xa2, 0x2e, 0x76, 0xa8, 0x99, 0x04, 0x9c, 0x00, 0x4c, 0x90, 0x01, 0xa2, - 0x35, 0x76, 0x8b, 0xac, 0x76, 0xce, 0xb4, 0xf5, 0xc3, 0xac, 0x76, 0xce, 0xa2, 0x22, - 0xce, 0x88, 0xb5, 0xca, 0x67, 0xa2, 0x2e, 0x76, 0xab, 0x99, 0x40, 0x9c, 0x00, 0x3c, - 0xa2, 0x35, 0x76, 0x88, 0x9c, 0x00, 0x3c, 0xb4, 0xf6, 0xa3, 0xac, 0x76, 0xce, 0xa2, - 0x35, 0x76, 0x88, 0x9c, 0x00, 0xb4, 0xf6, 0x97, 0xa2, 0x3c, 0x76, 0x88, 0x9c, 0x00, - 0xb4, 0xfa, 0x51, 0xb4, 0xf6, 0x8b, 0xa2, 0x3c, 0x76, 0x88, 0x9c, 0x00, 0x3c, 0xac, - 0x76, 0xce, 0xb4, 0xf6, 0x7e, 0xa8, 0x44, 0xbc, 0x02, 0x09, 0x4b, 0xbc, 0x02, 0xff, - 0x94, 0x3a, 0xbc, 0x02, 0x13, 0x94, 0x4d, 0x3c, 0xac, 0x76, 0xce, 0xa2, 0x2e, 0x76, - 0xa8, 0x99, 0x02, 0x9c, 0x00, 0x43, 0xb4, 0xf6, 0x5e, 0xa2, 0x35, 0x76, 0x88, 0x9d, - 0x00, 0x3c, 0xa2, 0x2e, 0x76, 0xa8, 0x99, 0x08, 0x9c, 0x00, 0x49, 0x90, 0x01, 0xa2, - 0x35, 0x76, 0x8b, 0xb4, 0xf5, 0x4a, 0xa2, 0x2e, 0x76, 0xa8, 0x99, 0x40, 0x9c, 0x00, - 0x3c, 0xb4, 0xf6, 0x39, 0xac, 0x76, 0xce, 0xa2, 0x35, 0x76, 0x88, 0x9c, 0x00, 0xb4, - 0xf6, 0x2d, 0xa2, 0x3c, 0x76, 0x88, 0x9d, 0x00, 0xb4, 0xf6, 0x24, 0xb4, 0xfa, 0x2c, - 0xa2, 0x3c, 0x76, 0x88, 0x9c, 0x00, 0x3c, 0xac, 0x76, 0xce, 0xb4, 0xf6, 0x14, 0xa8, - 0x44, 0xbc, 0x02, 0xff, 0x94, 0x36, 0xbc, 0x02, 0x09, 0x94, 0x98, 0xbc, 0x02, 0x03, - 0xb4, 0x01, 0x6e, 0xbc, 0x02, 0x0a, 0xb4, 0x01, 0x6e, 0xbc, 0x02, 0x0b, 0xb4, 0x01, - 0x75, 0xbc, 0x02, 0x06, 0xb4, 0x01, 0x93, 0xbc, 0x02, 0x13, 0xb4, 0x01, 0xc2, 0xbc, - 0x02, 0x0d, 0xb4, 0x01, 0xc9, 0xbc, 0x02, 0x11, 0xb4, 0x01, 0xda, 0xbc, 0x02, 0x12, - 0xb4, 0x01, 0xe1, 0x3c, 0xa2, 0x35, 0x76, 0x88, 0x9d, 0x00, 0x4d, 0xa2, 0x3b, 0x76, - 0x88, 0x9d, 0x00, 0x46, 0xac, 0x76, 0xce, 0xb4, 0xf6, 0xa9, 0xa2, 0x35, 0x76, 0x88, - 0x9c, 0x00, 0x3c, 0xa2, 0x3a, 0x76, 0x88, 0x9d, 0x00, 0x3c, 0xac, 0x76, 0xce, 0xa2, - 0x22, 0xce, 0x88, 0xb5, 0xc9, 0x5c, 0xa2, 0x2e, 0x76, 0xab, 0x99, 0x08, 0x9c, 0x00, - 0x4d, 0xa2, 0x3b, 0x76, 0x88, 0x9d, 0x00, 0x46, 0xb5, 0xf5, 0x98, 0xb4, 0xf4, 0x9c, - 0xb7, 0x03, 0x02, 0x02, 0xb7, 0x00, 0x01, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa8, 0x46, - 0xb5, 0x9a, 0xb1, 0xb7, 0x02, 0x06, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, - 0x06, 0xa8, 0x46, 0xb5, 0x9a, 0xa0, 0xb4, 0xf4, 0x77, 0xa2, 0x3b, 0x76, 0x88, 0x9d, - 0x00, 0x51, 0xa2, 0x2e, 0x76, 0xa8, 0x99, 0x04, 0x9c, 0x00, 0x48, 0xac, 0x76, 0xce, - 0xb5, 0xf5, 0x5a, 0x94, 0x50, 0xa2, 0x3b, 0x76, 0x88, 0x9d, 0x00, 0x51, 0xa2, 0x2e, - 0x76, 0xa8, 0x99, 0x02, 0x9c, 0x00, 0x48, 0xac, 0x76, 0xce, 0xb5, 0xf6, 0x28, 0x94, - 0x38, 0xa2, 0x3a, 0x76, 0x88, 0x9c, 0x00, 0x94, 0x58, 0xa2, 0x3b, 0x76, 0x88, 0x9d, - 0x00, 0x94, 0x50, 0xa2, 0x2e, 0x76, 0xa8, 0x99, 0x08, 0x9c, 0x00, 0x94, 0x46, 0x90, - 0x01, 0xa2, 0x3b, 0x76, 0x8b, 0xb7, 0x01, 0x03, 0x02, 0xb7, 0x00, 0x04, 0x04, 0xb7, - 0x00, 0x00, 0x06, 0xa8, 0x46, 0xb5, 0x9a, 0x3c, 0xac, 0x76, 0xce, 0xb5, 0xf4, 0x10, - 0x40, 0xa2, 0x2e, 0x76, 0xa8, 0x99, 0x20, 0x9c, 0x00, 0x3c, 0xa2, 0x4a, 0x76, 0xa8, - 0x9d, 0x00, 0x3c, 0xb7, 0x07, 0xef, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x02, 0x00, - 0x06, 0xac, 0x76, 0xcc, 0x82, 0x4a, 0xcc, 0xf8, 0xa8, 0x46, 0xb4, 0xc1, 0xe6, 0xa2, - 0x2e, 0x76, 0xa8, 0x99, 0x40, 0x9c, 0x00, 0x95, 0x30, 0xa2, 0x4a, 0x76, 0xa8, 0x9c, - 0x00, 0x57, 0xb7, 0x00, 0x00, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, - 0xac, 0x76, 0xcc, 0x82, 0x4a, 0xcc, 0xf8, 0x00, 0xb5, 0xc1, 0xbe, 0xa2, 0x35, 0x76, - 0x88, 0x9d, 0x00, 0x95, 0x56, 0x90, 0x01, 0xa2, 0x35, 0x76, 0x8b, 0x90, 0x08, 0x01, - 0xa2, 0x50, 0x76, 0xf9, 0xa2, 0x50, 0x76, 0xab, 0xac, 0x76, 0xce, 0xb5, 0xc7, 0xe4, - 0xb5, 0xf3, 0x9d, 0x95, 0x72, 0xac, 0x76, 0xce, 0xb4, 0xf5, 0x83, 0xa2, 0x3b, 0x76, - 0x88, 0x9d, 0x00, 0x3c, 0xac, 0x76, 0xce, 0xb4, 0xf5, 0x67, 0xac, 0x76, 0xce, 0xa2, - 0x22, 0xce, 0x88, 0xb5, 0xc8, 0x28, 0xa2, 0x2e, 0x76, 0xab, 0x99, 0x41, 0x9d, 0x00, - 0x3c, 0xb7, 0x02, 0x0a, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa8, - 0x46, 0xb4, 0x99, 0x8a, 0xa2, 0x4c, 0x76, 0xa8, 0x9d, 0x00, 0x3c, 0xb1, 0x01, 0x00, - 0xac, 0x76, 0xce, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0xc8, 0x87, 0x90, 0x30, 0xa2, 0x50, - 0x76, 0xfa, 0xa2, 0x50, 0x76, 0xab, 0xb5, 0xc7, 0x87, 0xb7, 0x05, 0x01, 0x02, 0xb7, - 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa8, 0x46, 0xb5, 0x99, 0x58, 0xb4, 0xf3, - 0x2f, 0xa2, 0x3c, 0x76, 0x88, 0x9c, 0x00, 0x3c, 0xac, 0x76, 0xce, 0xb4, 0xf4, 0x1b, - 0xb7, 0x02, 0x06, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa8, 0x46, - 0xb5, 0x99, 0x37, 0xac, 0x76, 0xce, 0xb4, 0xf3, 0x0b, 0xa2, 0x3b, 0x76, 0x88, 0x9d, - 0x00, 0x3c, 0xac, 0x76, 0xce, 0xb4, 0xf4, 0xdd, 0xa2, 0x41, 0x76, 0x88, 0x9c, 0x00, - 0x3c, 0xac, 0x76, 0xce, 0xb4, 0xf3, 0xea, 0xa8, 0x44, 0xbc, 0x02, 0x02, 0x45, 0xbc, - 0x02, 0x0f, 0x4d, 0x3c, 0xa8, 0x48, 0xa2, 0x04, 0x76, 0xab, 0xac, 0x76, 0xce, 0xb4, - 0xf8, 0x44, 0xac, 0x76, 0xce, 0xb4, 0xf3, 0x18, 0xaf, 0xce, 0xab, 0xce, 0x39, 0x3f, - 0xce, 0x3c, 0xaf, 0xce, 0xab, 0xce, 0x38, 0x3f, 0xce, 0x3c, 0xaf, 0xce, 0xab, 0xce, - 0x3a, 0x43, 0x3f, 0xce, 0x3d, 0x3f, 0xce, 0x3c, 0xa2, 0x34, 0xce, 0x88, 0x9c, 0x00, - 0x94, 0x2a, 0x9c, 0x01, 0x94, 0x42, 0x9c, 0x02, 0x94, 0x79, 0x9c, 0x03, 0x94, 0xb0, - 0x9c, 0x04, 0x94, 0xe2, 0x9c, 0x05, 0xb4, 0x01, 0x89, 0x9c, 0x06, 0xb4, 0x01, 0x97, - 0x9c, 0x07, 0xb4, 0x01, 0xd0, 0x9c, 0x08, 0xb4, 0x02, 0x45, 0x9c, 0x09, 0xb4, 0x02, - 0x81, 0x3c, 0xac, 0xce, 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0x34, 0x4d, 0xb7, 0x02, 0x05, - 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb4, - 0x98, 0x90, 0xa2, 0x06, 0xce, 0xa8, 0x9c, 0x02, 0x94, 0x24, 0x9c, 0x03, 0x94, 0x20, - 0xa2, 0x34, 0xce, 0x88, 0xac, 0xce, 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0x34, 0x79, 0xb7, - 0x02, 0x05, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, - 0x88, 0xb4, 0x98, 0x64, 0xa2, 0x34, 0xce, 0x88, 0xac, 0xce, 0xcc, 0x82, 0x44, 0xcc, - 0xf8, 0x34, 0xa1, 0x95, 0x20, 0xa2, 0x06, 0xce, 0xa8, 0x9c, 0x01, 0x94, 0x24, 0x9c, - 0x03, 0x94, 0x20, 0xa2, 0x34, 0xce, 0x88, 0xac, 0xce, 0xcc, 0x82, 0x44, 0xcc, 0xf8, - 0x34, 0xb4, 0xb7, 0x02, 0x05, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, - 0xa2, 0x22, 0xce, 0x88, 0xb4, 0x98, 0x29, 0xa2, 0x34, 0xce, 0x88, 0xac, 0xce, 0xcc, - 0x82, 0x44, 0xcc, 0xf8, 0x34, 0xdc, 0x95, 0x20, 0xb5, 0xd9, 0x79, 0x9c, 0x00, 0x94, - 0x20, 0xa2, 0x34, 0xce, 0x88, 0xac, 0xce, 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0x34, 0xf2, - 0xb7, 0x02, 0x05, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, - 0xce, 0x88, 0xb4, 0x97, 0xf3, 0xa2, 0x34, 0xce, 0x88, 0xac, 0xce, 0xcc, 0x82, 0x44, - 0xcc, 0xf8, 0x35, 0x0a, 0x95, 0x20, 0xa2, 0x2a, 0xce, 0x88, 0x9c, 0x00, 0x94, 0x44, - 0xa2, 0x2c, 0xce, 0xa8, 0x9c, 0x02, 0x94, 0x26, 0x53, 0xb7, 0x02, 0x05, 0x02, 0xb7, - 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb4, 0x97, 0xc0, - 0x90, 0x02, 0xa2, 0x2c, 0xce, 0xab, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, - 0x3d, 0xb5, 0xdb, 0x68, 0xac, 0xce, 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0xa2, 0x34, 0xce, - 0x88, 0x35, 0x57, 0xa2, 0x34, 0xce, 0x88, 0x04, 0x35, 0x5e, 0x95, 0x39, 0xa2, 0x2c, - 0xce, 0xa8, 0x9c, 0x02, 0x52, 0x90, 0x01, 0xa2, 0x2c, 0xce, 0xab, 0xa2, 0x22, 0xce, - 0x88, 0xab, 0x18, 0xb0, 0x40, 0x3d, 0xb5, 0xdb, 0x39, 0xa2, 0x40, 0xce, 0x88, 0x9c, - 0x00, 0x56, 0xac, 0xce, 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0xa2, 0x34, 0xce, 0x88, 0x35, - 0x8d, 0xa2, 0x34, 0xce, 0x88, 0x04, 0x35, 0x8c, 0x95, 0x6f, 0xac, 0xce, 0xcc, 0x82, - 0x44, 0xcc, 0xf8, 0xa2, 0x34, 0xce, 0x88, 0x35, 0x9b, 0xa2, 0x30, 0xce, 0xa8, 0xa2, - 0x32, 0xce, 0xfa, 0x9c, 0x00, 0x49, 0xa2, 0x34, 0xce, 0x88, 0x04, 0x35, 0xb5, 0x95, - 0x90, 0xa2, 0x34, 0xce, 0x88, 0x04, 0x35, 0xb6, 0x95, 0x99, 0xb7, 0x02, 0x05, 0x02, - 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb4, 0x97, - 0x25, 0xa2, 0x0c, 0xce, 0x88, 0x99, 0x01, 0x9c, 0x00, 0x55, 0xa2, 0x0f, 0x72, 0x88, - 0x9c, 0x00, 0x4e, 0xac, 0xce, 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0xa2, 0x34, 0xce, 0x88, - 0x35, 0xf0, 0x4d, 0xac, 0xce, 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0xa2, 0x34, 0xce, 0x88, - 0x35, 0xf6, 0xb7, 0x02, 0x05, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, - 0xa2, 0x22, 0xce, 0x88, 0xb4, 0x96, 0xe7, 0xaf, 0xce, 0xb7, 0x05, 0x04, 0x44, 0xb7, - 0x00, 0x00, 0x48, 0xb7, 0x00, 0x00, 0x4a, 0xa2, 0x22, 0xce, 0x88, 0xab, 0x46, 0xb5, - 0x9b, 0xc3, 0x3f, 0xce, 0x90, 0x20, 0x01, 0xab, 0xca, 0xa2, 0x50, 0xce, 0xa8, 0x96, - 0xca, 0xf9, 0xa2, 0x50, 0xce, 0xab, 0xb5, 0xc4, 0xd9, 0xb7, 0x03, 0x01, 0x02, 0xb7, - 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0x96, 0xa8, - 0xa2, 0x30, 0xce, 0xa8, 0xa2, 0x32, 0xce, 0xfa, 0x9c, 0x00, 0x94, 0x20, 0xac, 0xce, - 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0xa2, 0x34, 0xce, 0x88, 0x36, 0x69, 0xb7, 0x02, 0x05, - 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb4, - 0x96, 0x7c, 0xac, 0xce, 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0xa2, 0x34, 0xce, 0x88, 0x36, - 0x81, 0x95, 0x20, 0xa2, 0x0c, 0xce, 0x88, 0x99, 0x02, 0x9c, 0x00, 0x94, 0x28, 0xa2, - 0x0f, 0x72, 0x88, 0x9c, 0x00, 0x94, 0x20, 0xac, 0xce, 0xcc, 0x82, 0x44, 0xcc, 0xf8, - 0xa2, 0x34, 0xce, 0x88, 0x36, 0xaa, 0xb7, 0x02, 0x05, 0x02, 0xb7, 0x00, 0x00, 0x04, - 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb4, 0x96, 0x3b, 0xac, 0xce, 0xcc, - 0x82, 0x44, 0xcc, 0xf8, 0xa2, 0x34, 0xce, 0x88, 0x36, 0xc2, 0x95, 0x20, 0xb7, 0x03, - 0x01, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, - 0xb5, 0x96, 0x19, 0x90, 0x20, 0x01, 0xab, 0xca, 0xa2, 0x50, 0xce, 0xa8, 0x96, 0xca, - 0xf9, 0xa2, 0x50, 0xce, 0xab, 0xb5, 0xc4, 0x24, 0xa2, 0x3c, 0xce, 0x88, 0x9d, 0x00, - 0x94, 0x30, 0xa2, 0x2a, 0xce, 0x88, 0x9c, 0x00, 0x42, 0x94, 0x27, 0xb5, 0xd9, 0x1c, - 0x9c, 0x00, 0x94, 0x33, 0xac, 0xce, 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0xa2, 0x34, 0xce, - 0x88, 0x37, 0x17, 0xb7, 0x02, 0x05, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, - 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb4, 0x95, 0xce, 0xb7, 0x02, 0x01, 0x02, 0xb7, 0x00, - 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb4, 0x95, 0xbb, 0xac, - 0xce, 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0xa2, 0x34, 0xce, 0x88, 0x37, 0x42, 0x95, 0x33, - 0xa2, 0x34, 0xce, 0x88, 0x9c, 0x00, 0x94, 0x2d, 0x9c, 0x01, 0x94, 0x2c, 0x9c, 0x02, - 0x94, 0x2b, 0x9c, 0x03, 0x94, 0x2a, 0x9c, 0x04, 0x94, 0x5b, 0x9c, 0x05, 0x94, 0xcb, - 0x9c, 0x06, 0x94, 0xca, 0x9c, 0x07, 0xb4, 0x01, 0x65, 0x9c, 0x08, 0xb4, 0x01, 0xc1, - 0x9c, 0x09, 0xb4, 0x01, 0xec, 0x9c, 0x0a, 0xb4, 0x02, 0x4d, 0x3c, 0xb4, 0xfc, 0x96, - 0xb4, 0xfc, 0x93, 0xb4, 0xfc, 0x90, 0xac, 0xce, 0xcc, 0x82, 0x46, 0xcc, 0xf8, 0x90, - 0x01, 0x37, 0x85, 0x4c, 0x90, 0x02, 0x37, 0x8a, 0x94, 0x20, 0x90, 0x00, 0x4a, 0x90, - 0x03, 0x47, 0x90, 0x02, 0x37, 0x96, 0x67, 0x90, 0x02, 0xa2, 0x28, 0xce, 0x8b, 0xa2, - 0x22, 0xce, 0x88, 0xab, 0x18, 0xb0, 0x40, 0x0d, 0xb5, 0xd8, 0xf9, 0xb4, 0xfc, 0x5e, - 0x90, 0x01, 0x75, 0xa2, 0x06, 0xce, 0xa8, 0x9c, 0x03, 0x5c, 0xac, 0xce, 0xcc, 0x82, - 0x44, 0xcc, 0xf8, 0x90, 0x03, 0x37, 0xc1, 0x94, 0x30, 0xac, 0xce, 0xcc, 0x82, 0x46, - 0xcc, 0xf8, 0x90, 0x03, 0x37, 0xce, 0x94, 0x23, 0x94, 0x4e, 0xa2, 0x28, 0xce, 0x88, - 0x9c, 0x03, 0x42, 0x95, 0x23, 0x90, 0x01, 0xa2, 0x2a, 0xce, 0x8b, 0xa2, 0x22, 0xce, - 0x88, 0xab, 0x18, 0xb0, 0x40, 0x3f, 0xb5, 0xd8, 0xb5, 0xb4, 0xfc, 0x1a, 0x90, 0x01, - 0x50, 0xa2, 0x06, 0xce, 0xa8, 0x9c, 0x03, 0x69, 0xa2, 0x28, 0xce, 0x88, 0x9c, 0x03, - 0x70, 0x90, 0x02, 0xa2, 0x29, 0xce, 0x8b, 0xaf, 0xce, 0xb5, 0xaf, 0x79, 0x3f, 0xce, - 0xa2, 0x3c, 0xce, 0x88, 0x9c, 0x00, 0x48, 0x90, 0x03, 0xa2, 0x2a, 0xce, 0x8b, 0x95, - 0x3a, 0x90, 0x00, 0x68, 0x90, 0x02, 0x6b, 0xb4, 0xfb, 0xe4, 0xac, 0xce, 0xcc, 0x82, - 0x44, 0xcc, 0xf8, 0x90, 0x04, 0xb5, 0xfb, 0xcc, 0x94, 0x48, 0xac, 0xce, 0xcc, 0x82, - 0x46, 0xcc, 0xf8, 0x90, 0x04, 0xb5, 0xfb, 0xbe, 0x94, 0x3a, 0xac, 0xce, 0xcc, 0x82, - 0x44, 0xcc, 0xf8, 0x90, 0x05, 0xb5, 0xfb, 0xb0, 0x5d, 0xac, 0xce, 0xcc, 0x82, 0x46, - 0xcc, 0xf8, 0x90, 0x05, 0xb5, 0xfb, 0xa3, 0x50, 0xb0, 0x2b, 0xc4, 0xa2, 0x24, 0xce, - 0xab, 0x90, 0x01, 0xa2, 0x26, 0xce, 0xab, 0xb4, 0xfb, 0x9e, 0xb0, 0xe6, 0x59, 0xa2, - 0x24, 0xce, 0xab, 0x90, 0x0b, 0xa2, 0x26, 0xce, 0xab, 0xb4, 0xfb, 0x8e, 0xac, 0xce, - 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0x90, 0x04, 0xb5, 0xfb, 0x76, 0x94, 0x23, 0xac, 0xce, - 0xcc, 0x82, 0x46, 0xcc, 0xf8, 0x90, 0x04, 0xb5, 0xfb, 0x68, 0x90, 0x05, 0xb5, 0xfb, - 0x63, 0x59, 0x40, 0xb0, 0x35, 0x20, 0xa2, 0x24, 0xce, 0xab, 0x90, 0x77, 0xa2, 0x26, - 0xce, 0xab, 0xb4, 0xfb, 0x5d, 0x90, 0x05, 0xb5, 0xfb, 0x4c, 0x42, 0x95, 0x29, 0xb0, - 0x12, 0x60, 0xa2, 0x24, 0xce, 0xab, 0xb0, 0x04, 0xa8, 0xa2, 0x26, 0xce, 0xab, 0xb4, - 0xfb, 0x44, 0xb7, 0x02, 0x06, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, - 0xa2, 0x22, 0xce, 0x88, 0xb5, 0x94, 0x0f, 0xac, 0xce, 0xcc, 0x82, 0x44, 0xcc, 0xf8, - 0x90, 0x06, 0xb5, 0xfb, 0x19, 0x41, 0x53, 0xb7, 0x03, 0x01, 0x02, 0xb7, 0x00, 0x01, - 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0x93, 0xee, 0xaf, 0xce, - 0xb7, 0x05, 0x03, 0x44, 0xb7, 0x00, 0x00, 0x48, 0xb7, 0x00, 0x00, 0x4a, 0xa2, 0x22, - 0xce, 0x88, 0xab, 0x46, 0xb5, 0x98, 0xca, 0x3f, 0xce, 0xa2, 0x50, 0xce, 0xa8, 0x9a, - 0x20, 0xa2, 0x50, 0xce, 0xab, 0xb5, 0xc1, 0xe6, 0x90, 0x01, 0xa2, 0x38, 0xce, 0x8b, - 0x3c, 0xac, 0xce, 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0x90, 0x07, 0xb5, 0xfa, 0xcb, 0x50, - 0xac, 0xce, 0xcc, 0x82, 0x46, 0xcc, 0xf8, 0x90, 0x07, 0xb5, 0xfa, 0xbe, 0x43, 0xb4, - 0xfa, 0xc6, 0xb7, 0x02, 0x01, 0x02, 0xb7, 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, - 0xa2, 0x22, 0xce, 0x88, 0xb4, 0x93, 0x91, 0xac, 0xce, 0xcc, 0x82, 0x44, 0xcc, 0xf8, - 0x90, 0x08, 0xb5, 0xfa, 0x9b, 0x50, 0xac, 0xce, 0xcc, 0x82, 0x46, 0xcc, 0xf8, 0x90, - 0x08, 0xb5, 0xfa, 0x8e, 0x43, 0xb4, 0xfa, 0x96, 0xb7, 0x02, 0x06, 0x02, 0xb7, 0x00, - 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0x93, 0x61, 0xac, - 0xce, 0xcc, 0x82, 0x44, 0xcc, 0xf8, 0x90, 0x08, 0xb5, 0xfa, 0x6b, 0x54, 0xa2, 0x50, - 0xce, 0xa8, 0x9a, 0x20, 0xa2, 0x50, 0xce, 0xab, 0xb5, 0xc1, 0x65, 0x90, 0x01, 0xa2, - 0x38, 0xce, 0x8b, 0x3c, 0xb7, 0x03, 0x01, 0x02, 0xb7, 0x00, 0x01, 0x04, 0xb7, 0x00, - 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb5, 0x93, 0x2d, 0x95, 0x27, 0xa2, 0x22, 0xce, - 0x88, 0xab, 0x18, 0xb0, 0x40, 0x0f, 0xb5, 0xd6, 0xd9, 0xb7, 0x02, 0x07, 0x02, 0xb7, - 0x00, 0x00, 0x04, 0xb7, 0x00, 0x00, 0x06, 0xa2, 0x22, 0xce, 0x88, 0xb4, 0x93, 0x0c, - 0x00, 0x00 -}; - -#endif /* !(_PTIFDDI_ASM_H) */ diff -Nru a/drivers/net/r8169.c b/drivers/net/r8169.c --- a/drivers/net/r8169.c Mon Jun 9 23:16:13 2003 +++ b/drivers/net/r8169.c Mon Jun 9 23:16:13 2003 @@ -365,8 +365,8 @@ *ioaddr_out = NULL; *dev_out = NULL; - // dev zeroed in init_etherdev - dev = init_etherdev(NULL, sizeof (*tp)); + // dev zeroed in alloc_etherdev + dev = alloc_etherdev(sizeof (*tp)); if (dev == NULL) { printk(KERN_ERR PFX "unable to alloc new ethernet\n"); return -ENOMEM; @@ -391,18 +391,18 @@ printk(KERN_ERR PFX "region #1 not an MMIO resource, aborting\n"); rc = -ENODEV; - goto err_out; + goto err_out_disable; } // check for weird/broken PCI region reporting if (mmio_len < RTL_MIN_IO_SIZE) { printk(KERN_ERR PFX "Invalid PCI region size(s), aborting\n"); rc = -ENODEV; - goto err_out; + goto err_out_disable; } rc = pci_request_regions(pdev, dev->name); if (rc) - goto err_out; + goto err_out_disable; // enable PCI bus-mastering pci_set_master(pdev); @@ -450,8 +450,10 @@ err_out_free_res: pci_release_regions(pdev); +err_out_disable: + pci_disable_device(pdev); + err_out: - unregister_netdev(dev); kfree(dev); return rc; } @@ -464,7 +466,7 @@ void *ioaddr = NULL; static int board_idx = -1; static int printed_version = 0; - int i; + int i, rc; int option = -1, Cap10_100 = 0, Cap1000 = 0; assert(pdev != NULL); @@ -477,20 +479,18 @@ printed_version = 1; } - i = rtl8169_init_board(pdev, &dev, &ioaddr); - if (i < 0) { - return i; - } + rc = rtl8169_init_board(pdev, &dev, &ioaddr); + if (rc) + return rc; tp = dev->priv; assert(ioaddr != NULL); assert(dev != NULL); assert(tp != NULL); - // Get MAC address // - for (i = 0; i < MAC_ADDR_LEN; i++) { + // Get MAC address. FIXME: read EEPROM + for (i = 0; i < MAC_ADDR_LEN; i++) dev->dev_addr[i] = RTL_R8(MAC0 + i); - } dev->open = rtl8169_open; dev->hard_start_xmit = rtl8169_start_xmit; @@ -507,11 +507,20 @@ tp->pci_dev = pdev; tp->mmio_addr = ioaddr; + spin_lock_init(&tp->lock); + + rc = register_netdev(dev); + if (rc) { + iounmap(ioaddr); + pci_release_regions(pdev); + pci_disable_device(pdev); + kfree(dev); + return rc; + } + printk(KERN_DEBUG "%s: Identified chip type is '%s'.\n", dev->name, rtl_chip_info[tp->chipset].name); - spin_lock_init(&tp->lock); - pci_set_drvdata(pdev, dev); printk(KERN_INFO "%s: %s at 0x%lx, " @@ -623,7 +632,7 @@ rtl8169_remove_one(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct rtl8169_private *tp = (struct rtl8169_private *) (dev->priv); + struct rtl8169_private *tp = dev->priv; assert(dev != NULL); assert(tp != NULL); @@ -636,6 +645,7 @@ memset(dev, 0xBC, sizeof (struct net_device) + sizeof (struct rtl8169_private)); + pci_disable_device(pdev); kfree(dev); pci_set_drvdata(pdev, NULL); } diff -Nru a/drivers/net/rrunner.c b/drivers/net/rrunner.c --- a/drivers/net/rrunner.c Mon Jun 9 23:16:08 2003 +++ b/drivers/net/rrunner.c Mon Jun 9 23:16:08 2003 @@ -97,13 +97,11 @@ struct rr_private *rrpriv; void *tmpptr; dma_addr_t ring_dma; - int ret; + int ret = -ENOMEM; - dev = init_hippi_dev(NULL, sizeof(struct rr_private)); - if (!dev) { - ret = -ENOMEM; - goto out2; - } + dev = alloc_hippi_dev(sizeof(struct rr_private)); + if (!dev) + goto out3; ret = pci_enable_device(pdev); if (ret) { @@ -210,6 +208,10 @@ rr_init(dev); dev->base_addr = 0; + + ret = register_netdev(dev); + if (ret) + goto out; return 0; out: @@ -225,12 +227,9 @@ pci_release_regions(pdev); pci_set_drvdata(pdev, NULL); } - out2: - if (dev) { - unregister_hipdev(dev); - kfree(dev); - } + kfree(dev); + out3: return ret; } @@ -252,7 +251,7 @@ rr->rx_ring_dma); pci_free_consistent(pdev, TX_TOTAL_SIZE, rr->tx_ring, rr->tx_ring_dma); - unregister_hipdev(dev); + unregister_netdev(dev); iounmap(rr->regs); kfree(dev); pci_release_regions(pdev); diff -Nru a/drivers/net/sb1000.c b/drivers/net/sb1000.c --- a/drivers/net/sb1000.c Mon Jun 9 23:16:06 2003 +++ b/drivers/net/sb1000.c Mon Jun 9 23:16:06 2003 @@ -162,10 +162,17 @@ irq = pnp_irq(pdev, 0); - if (!request_region(ioaddr[0], 16, dev->name)) + if (!request_region(ioaddr[0], 16, "sb1000")) goto out_disable; - if (!request_region(ioaddr[1], 16, dev->name)) + if (!request_region(ioaddr[1], 16, "sb1000")) goto out_release_region0; + + dev = alloc_etherdev(sizeof(struct sb1000_private)); + if (!dev) { + error = -ENOMEM; + goto out_release_regions; + } + dev->base_addr = ioaddr[0]; /* mem_start holds the second I/O address */ @@ -177,12 +184,6 @@ "S/N %#8.8x, IRQ %d.\n", dev->name, dev->base_addr, dev->mem_start, serial_number, dev->irq); - dev = alloc_etherdev(sizeof(struct sb1000_private)); - if (!dev) { - error = -ENOMEM; - goto out_release_regions; - } - /* * The SB1000 is an rx-only cable modem device. The uplink is a modem * and we do not want to arp on it. @@ -212,11 +213,9 @@ error = register_netdev(dev); if (error) - goto out_unregister; + goto out_release_regions; return 0; - out_unregister: - unregister_netdev(dev); out_release_regions: release_region(ioaddr[1], 16); out_release_region0: @@ -236,6 +235,7 @@ unregister_netdev(dev); release_region(dev->base_addr, 16); release_region(dev->mem_start, 16); + kfree(dev); } static struct pnp_driver sb1000_driver = { diff -Nru a/drivers/net/setup.c b/drivers/net/setup.c --- a/drivers/net/setup.c Mon Jun 9 23:16:18 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,69 +0,0 @@ - -/* - * New style setup code for the network devices - */ - -#include <linux/config.h> -#include <linux/netdevice.h> -#include <linux/errno.h> -#include <linux/init.h> -#include <linux/netlink.h> - -extern int dmascc_init(void); - -extern int scc_enet_init(void); -extern int fec_enet_init(void); -extern int sdla_setup(void); -extern int sdla_c_setup(void); -extern int lmc_setup(void); - -/* - * Devices in this list must do new style probing. That is they must - * allocate their own device objects and do their own bus scans. - */ - -struct net_probe -{ - int (*probe)(void); - int status; /* non-zero if autoprobe has failed */ -}; - -static struct net_probe pci_probes[] __initdata = { - /* - * Early setup devices - */ - -#if defined(CONFIG_DMASCC) - {dmascc_init, 0}, -#endif -#if defined(CONFIG_SDLA) - {sdla_c_setup, 0}, -#endif -#if defined(CONFIG_SCC_ENET) - {scc_enet_init, 0}, -#endif -#if defined(CONFIG_FEC_ENET) - {fec_enet_init, 0}, -#endif -#if defined(CONFIG_LANMEDIA) - {lmc_setup, 0}, -#endif - {NULL, 0}, -}; - - -/* - * Run the updated device probes. These do not need a device passed - * into them. - */ - -void __init net_device_init(void) -{ - struct net_probe *p = pci_probes; - - while (p->probe != NULL) - { - p->status = p->probe(); - p++; - } -} diff -Nru a/drivers/net/sis900.c b/drivers/net/sis900.c --- a/drivers/net/sis900.c Mon Jun 9 23:16:10 2003 +++ b/drivers/net/sis900.c Mon Jun 9 23:16:10 2003 @@ -211,7 +211,7 @@ static void sis900_set_mode (long ioaddr, int speed, int duplex); /** - * sis900_get_mac_addr: - Get MAC address for stand alone SiS900 model + * sis900_get_mac_addr - Get MAC address for stand alone SiS900 model * @pci_dev: the sis900 pci device * @net_dev: the net device to get address for * @@ -241,7 +241,7 @@ } /** - * sis630e_get_mac_addr: - Get MAC address for SiS630E model + * sis630e_get_mac_addr - Get MAC address for SiS630E model * @pci_dev: the sis900 pci device * @net_dev: the net device to get address for * @@ -274,7 +274,7 @@ /** - * sis635_get_mac_addr: - Get MAC address for SIS635 model + * sis635_get_mac_addr - Get MAC address for SIS635 model * @pci_dev: the sis900 pci device * @net_dev: the net device to get address for * @@ -310,7 +310,7 @@ } /** - * sis96x_get_mac_addr: - Get MAC address for SiS962 or SiS963 model + * sis96x_get_mac_addr - Get MAC address for SiS962 or SiS963 model * @pci_dev: the sis900 pci device * @net_dev: the net device to get address for * @@ -352,7 +352,7 @@ } /** - * sis900_probe: - Probe for sis900 device + * sis900_probe - Probe for sis900 device * @pci_dev: the sis900 pci device * @pci_id: the pci device ID * @@ -498,7 +498,7 @@ } /** - * sis900_mii_probe: - Probe MII PHY for sis900 + * sis900_mii_probe - Probe MII PHY for sis900 * @net_dev: the net device to probe for * * Search for total of 32 possible mii phy addresses. @@ -618,7 +618,7 @@ } /** - * sis900_default_phy: - Select default PHY for sis900 mac. + * sis900_default_phy - Select default PHY for sis900 mac. * @net_dev: the net device to probe for * * Select first detected PHY with link as default. @@ -671,7 +671,7 @@ /** - * sis900_set_capability: - set the media capability of network adapter. + * sis900_set_capability - set the media capability of network adapter. * @net_dev : the net device to probe for * @phy : default PHY * @@ -701,7 +701,7 @@ #define eeprom_delay() inl(ee_addr) /** - * read_eeprom: - Read Serial EEPROM + * read_eeprom - Read Serial EEPROM * @ioaddr: base i/o address * @location: the EEPROM location to read * @@ -776,7 +776,7 @@ } /** - * mdio_read: - read MII PHY register + * mdio_read - read MII PHY register * @net_dev: the net device to read * @phy_id: the phy address to read * @location: the phy regiester id to read @@ -818,7 +818,7 @@ } /** - * mdio_write: - write MII PHY register + * mdio_write - write MII PHY register * @net_dev: the net device to write * @phy_id: the phy address to write * @location: the phy regiester id to write @@ -872,7 +872,7 @@ /** - * sis900_reset_phy: - reset sis900 mii phy. + * sis900_reset_phy - reset sis900 mii phy. * @net_dev: the net device to write * @phy_addr: default phy address * @@ -895,7 +895,7 @@ } /** - * sis900_open: - open sis900 device + * sis900_open - open sis900 device * @net_dev: the net device to open * * Do some initialization and start net interface. @@ -952,7 +952,7 @@ } /** - * sis900_init_rxfilter: - Initialize the Rx filter + * sis900_init_rxfilter - Initialize the Rx filter * @net_dev: the net device to initialize for * * Set receive filter address to our MAC address @@ -990,7 +990,7 @@ } /** - * sis900_init_tx_ring: - Initialize the Tx descriptor ring + * sis900_init_tx_ring - Initialize the Tx descriptor ring * @net_dev: the net device to initialize for * * Initialize the Tx descriptor ring, @@ -1023,7 +1023,7 @@ } /** - * sis900_init_rx_ring: - Initialize the Rx descriptor ring + * sis900_init_rx_ring - Initialize the Rx descriptor ring * @net_dev: the net device to initialize for * * Initialize the Rx descriptor ring, @@ -1077,7 +1077,7 @@ } /** - * sis630_set_eq: - set phy equalizer value for 630 LAN + * sis630_set_eq - set phy equalizer value for 630 LAN * @net_dev: the net device to set equalizer value * @revision: 630 LAN revision number * @@ -1165,7 +1165,7 @@ } /** - * sis900_timer: - sis900 timer routine + * sis900_timer - sis900 timer routine * @data: pointer to sis900 net device * * On each timer ticks we check two things, @@ -1235,7 +1235,7 @@ } /** - * sis900_check_mode: - check the media mode for sis900 + * sis900_check_mode - check the media mode for sis900 * @net_dev: the net device to be checked * @mii_phy: the mii phy * @@ -1266,7 +1266,7 @@ } /** - * sis900_set_mode: - Set the media mode of mac register. + * sis900_set_mode - Set the media mode of mac register. * @ioaddr: the address of the device * @speed : the transmit speed to be determined * @duplex: the duplex mode to be determined @@ -1310,7 +1310,7 @@ } /** - * sis900_auto_negotiate: Set the Auto-Negotiation Enable/Reset bit. + * sis900_auto_negotiate - Set the Auto-Negotiation Enable/Reset bit. * @net_dev: the net device to read mode for * @phy_addr: mii phy address * @@ -1344,7 +1344,7 @@ /** - * sis900_read_mode: - read media mode for sis900 internal phy + * sis900_read_mode - read media mode for sis900 internal phy * @net_dev: the net device to read mode for * @speed : the transmit speed to be determined * @duplex : the duplex mode to be determined @@ -1401,7 +1401,7 @@ } /** - * sis900_tx_timeout: - sis900 transmit timeout routine + * sis900_tx_timeout - sis900 transmit timeout routine * @net_dev: the net device to transmit * * print transmit timeout status @@ -1456,7 +1456,7 @@ } /** - * sis900_start_xmit: - sis900 start transmit routine + * sis900_start_xmit - sis900 start transmit routine * @skb: socket buffer pointer to put the data being transmitted * @net_dev: the net device to transmit with * @@ -1526,7 +1526,7 @@ } /** - * sis900_interrupt: - sis900 interrupt handler + * sis900_interrupt - sis900 interrupt handler * @irq: the irq number * @dev_instance: the client data object * @regs: snapshot of processor context @@ -1587,7 +1587,7 @@ } /** - * sis900_rx: - sis900 receive routine + * sis900_rx - sis900 receive routine * @net_dev: the net device which receives data * * Process receive interrupt events, @@ -1726,7 +1726,7 @@ } /** - * sis900_finish_xmit: - finish up transmission of packets + * sis900_finish_xmit - finish up transmission of packets * @net_dev: the net device to be transmitted on * * Check for error condition and free socket buffer etc @@ -1796,7 +1796,7 @@ } /** - * sis900_close: - close sis900 device + * sis900_close - close sis900 device * @net_dev: the net device to be closed * * Disable interrupts, stop the Tx and Rx Status Machine @@ -1852,7 +1852,7 @@ } /** - * netdev_ethtool_ioctl: - For the basic support of ethtool + * netdev_ethtool_ioctl - For the basic support of ethtool * @net_dev: the net device to command for * @useraddr: start address of interface request * @@ -1886,7 +1886,7 @@ } /** - * mii_ioctl: - process MII i/o control command + * mii_ioctl - process MII i/o control command * @net_dev: the net device to command for * @rq: parameter for command * @cmd: the i/o command @@ -1922,7 +1922,7 @@ } /** - * sis900_get_stats: - Get sis900 read/write statistics + * sis900_get_stats - Get sis900 read/write statistics * @net_dev: the net device to get statistics for * * get tx/rx statistics for sis900 @@ -1937,7 +1937,7 @@ } /** - * sis900_set_config: - Set media type by net_device.set_config + * sis900_set_config - Set media type by net_device.set_config * @dev: the net device for media type change * @map: ifmap passed by ifconfig * @@ -2034,7 +2034,7 @@ } /** - * sis900_mcast_bitnr: - compute hashtable index + * sis900_mcast_bitnr - compute hashtable index * @addr: multicast address * @revision: revision id of chip * @@ -2057,7 +2057,7 @@ } /** - * set_rx_mode: - Set SiS900 receive mode + * set_rx_mode - Set SiS900 receive mode * @net_dev: the net device to be set * * Set SiS900 receive mode for promiscuous, multicast, or broadcast mode. @@ -2131,7 +2131,7 @@ } /** - * sis900_reset: - Reset sis900 MAC + * sis900_reset - Reset sis900 MAC * @net_dev: the net device to reset * * reset sis900 MAC and wait until finished @@ -2166,7 +2166,7 @@ } /** - * sis900_remove: - Remove sis900 device + * sis900_remove - Remove sis900 device * @pci_dev: the pci device to be removed * * remove and release SiS900 net device diff -Nru a/drivers/net/sk98lin/h/skdrv2nd.h b/drivers/net/sk98lin/h/skdrv2nd.h --- a/drivers/net/sk98lin/h/skdrv2nd.h Mon Jun 9 23:16:19 2003 +++ b/drivers/net/sk98lin/h/skdrv2nd.h Mon Jun 9 23:16:19 2003 @@ -383,6 +383,7 @@ int Mtu; int Up; SK_AC *pAC; + struct proc_dir_entry *proc; }; typedef struct s_TxPort TX_PORT; diff -Nru a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c --- a/drivers/net/sk98lin/skge.c Mon Jun 9 23:16:07 2003 +++ b/drivers/net/sk98lin/skge.c Mon Jun 9 23:16:07 2003 @@ -351,11 +351,7 @@ static const char SK_Root_Dir_entry[] = "sk98lin"; static struct proc_dir_entry *pSkRootDir; - -//extern struct proc_dir_entry Our_Proc_Dir; -extern int sk_proc_read(char *buffer, char **buffer_location, - off_t offset, int buffer_length, int *eof, void *data); - +extern struct file_operations sk_proc_fops; #ifdef DEBUG static void DumpMsg(struct sk_buff*, char*); @@ -399,7 +395,6 @@ struct pci_dev *pdev = NULL; unsigned long base_address; struct net_device *dev = NULL; - struct proc_dir_entry *pProcFile; if (probed) return -ENODEV; @@ -420,18 +415,18 @@ while((pdev = pci_find_device(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_GE, pdev)) != NULL) { - dev = NULL; pNet = NULL; if (pci_enable_device(pdev)) continue; /* Configure DMA attributes. */ - if (pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff) && + if (pci_set_dma_mask(pdev, (u64) 0xffffffffffffffffULL) && pci_set_dma_mask(pdev, (u64) 0xffffffff)) continue; - if ((dev = init_etherdev(dev, sizeof(DEV_NET))) == 0) { + dev = alloc_etherdev(sizeof(DEV_NET)); + if (!dev) { printk(KERN_ERR "Unable to allocate etherdev " "structure!\n"); break; @@ -440,7 +435,7 @@ pNet = dev->priv; pNet->pAC = kmalloc(sizeof(SK_AC), GFP_KERNEL); if (pNet->pAC == NULL){ - kfree(dev->priv); + kfree(dev); printk(KERN_ERR "Unable to allocate adapter " "structure!\n"); break; @@ -477,15 +472,6 @@ proc_root_initialized = 1; } - pProcFile = create_proc_entry(dev->name, - S_IFREG | 0444, pSkRootDir); - pProcFile->read_proc = sk_proc_read; - pProcFile->write_proc = NULL; - pProcFile->nlink = 1; - pProcFile->size = sizeof(dev->name+1); - pProcFile->data = (void*)pProcFile; - pProcFile->owner = THIS_MODULE; - /* * Dummy value. */ @@ -532,11 +518,29 @@ pNet->PortNr = 0; pNet->NetNr = 0; + if (register_netdev(dev) != 0) { + printk(KERN_ERR "Unable to register etherdev\n"); + sk98lin_root_dev = pAC->Next; + remove_proc_entry(dev->name, pSkRootDir); + FreeResources(dev); + kfree(dev); + continue; + } + + pNet->proc = create_proc_entry(dev->name, + S_IFREG | 0444, pSkRootDir); + if (pNet->proc) { + pNet->proc->data = dev; + pNet->proc->owner = THIS_MODULE; + pNet->proc->proc_fops = &sk_proc_fops; + } + boards_found++; /* More then one port found */ if ((pAC->GIni.GIMacsFound == 2 ) && (pAC->RlmtNets == 2)) { - if ((dev = init_etherdev(NULL, sizeof(DEV_NET))) == 0) { + dev = alloc_etherdev(sizeof(DEV_NET)); + if (!dev) { printk(KERN_ERR "Unable to allocate etherdev " "structure!\n"); break; @@ -559,20 +563,25 @@ dev->do_ioctl = &SkGeIoctl; dev->change_mtu = &SkGeChangeMtu; - pProcFile = create_proc_entry(dev->name, - S_IFREG | 0444, pSkRootDir); - pProcFile->read_proc = sk_proc_read; - pProcFile->write_proc = NULL; - pProcFile->nlink = 1; - pProcFile->size = sizeof(dev->name+1); - pProcFile->data = (void*)pProcFile; - pProcFile->owner = THIS_MODULE; - memcpy((caddr_t) &dev->dev_addr, (caddr_t) &pAC->Addr.Net[1].CurrentMacAddress, 6); printk("%s: %s\n", dev->name, pAC->DeviceStr); printk(" PrefPort:B RlmtMode:Dual Check Link State\n"); + + if (register_netdev(dev) != 0) { + printk(KERN_ERR "Unable to register etherdev\n"); + kfree(dev); + break; + } + + pNet->proc = create_proc_entry(dev->name, + S_IFREG | 0444, pSkRootDir); + if (pNet->proc) { + pNet->proc->data = dev; + pNet->proc->owner = THIS_MODULE; + pNet->proc->proc_fops = &sk_proc_fops; + } } @@ -740,6 +749,7 @@ return cards ? 0 : -ENODEV; } /* skge_init_module */ +spinlock_t sk_devs_lock = SPIN_LOCK_UNLOCKED; /***************************************************************************** * @@ -766,6 +776,11 @@ netif_stop_queue(sk98lin_root_dev); SkGeYellowLED(pAC, pAC->IoBase, 0); + if (pNet->proc) { + spin_lock(&sk_devs_lock); + pNet->proc->data = NULL; + spin_unlock(&sk_devs_lock); + } if(pAC->BoardLevel == 2) { /* board is still alive */ @@ -792,6 +807,12 @@ } if ((pAC->GIni.GIMacsFound == 2) && pAC->RlmtNets == 2){ + pNet = (DEV_NET*) pAC->dev[1]->priv; + if (pNet->proc) { + spin_lock(&sk_devs_lock); + pNet->proc->data = NULL; + spin_unlock(&sk_devs_lock); + } unregister_netdev(pAC->dev[1]); kfree(pAC->dev[1]); } diff -Nru a/drivers/net/sk98lin/skproc.c b/drivers/net/sk98lin/skproc.c --- a/drivers/net/sk98lin/skproc.c Mon Jun 9 23:16:06 2003 +++ b/drivers/net/sk98lin/skproc.c Mon Jun 9 23:16:06 2003 @@ -46,378 +46,168 @@ #include "h/skdrv1st.h" #include "h/skdrv2nd.h" -#define ZEROPAD 1 /* pad with zero */ -#define SIGN 2 /* unsigned/signed long */ -#define PLUS 4 /* show plus */ -#define SPACE 8 /* space if plus */ -#define LEFT 16 /* left justified */ -//#define SPECIAL 32 /* 0x */ -#define LARGE 64 - -extern char * SkNumber(char * str, long long num, int base, int size, - int precision ,int type); -int proc_read(char *buffer, - char **buffer_location, - off_t offset, - int buffer_length, - int *eof, - void *data); - - -extern struct net_device *sk98lin_root_dev; - -/***************************************************************************** - * - * proc_read - print "summaries" entry - * - * Description: - * This function fills the proc entry with statistic data about - * the ethernet device. - * - * - * Returns: buffer with statistic data - * - */ -int sk_proc_read(char *buffer, -char **buffer_location, -off_t offset, -int buffer_length, -int *eof, -void *data) + +extern spinlock_t sk_devs_lock; + +static int sk_show_dev(struct net_device *dev, char *buf) { + DEV_NET *pNet = (DEV_NET*) dev->priv; + SK_AC *pAC = pNet->pAC; + int t = pNet->PortNr; + SK_RLMT_NET *rlmt = &pAC->Rlmt.Net[t]; + unsigned long Flags; + unsigned Size; int len = 0; - int t; int i; - DEV_NET *pNet; - SK_AC *pAC; - char test_buf[100]; - unsigned long Flags; - unsigned int Size; - struct net_device *next; - struct net_device *SkgeProcDev = sk98lin_root_dev; - SK_PNMI_STRUCT_DATA *pPnmiStruct; + SK_PNMI_STRUCT_DATA *pPnmiStruct = &pAC->PnmiStruct; SK_PNMI_STAT *pPnmiStat; - struct proc_dir_entry *file = (struct proc_dir_entry*) data; - while (SkgeProcDev) { - pNet = (DEV_NET*) SkgeProcDev->priv; - pAC = pNet->pAC; - next = pAC->Next; - pPnmiStruct = &pAC->PnmiStruct; - /* NetIndex in GetStruct is now required, zero is only dummy */ - - for (t=pAC->GIni.GIMacsFound; t > 0; t--) { - if ((pAC->GIni.GIMacsFound == 2) && pAC->RlmtNets == 1) - t--; - - spin_lock_irqsave(&pAC->SlowPathLock, Flags); - Size = SK_PNMI_STRUCT_SIZE; - SkPnmiGetStruct(pAC, pAC->IoBase, - pPnmiStruct, &Size, t-1); - spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); - - if (strcmp(pAC->dev[t-1]->name, file->name) == 0) { - pPnmiStat = &pPnmiStruct->Stat[0]; - len = sprintf(buffer, - "\nDetailed statistic for device %s\n", - pAC->dev[t-1]->name); - len += sprintf(buffer + len, - "==================================\n"); - - /* Board statistics */ - len += sprintf(buffer + len, - "\nBoard statistics\n\n"); - len += sprintf(buffer + len, - "Active Port %c\n", - 'A' + pAC->Rlmt.Net[t-1].Port[pAC->Rlmt. - Net[t-1].PrefPort]->PortNumber); - len += sprintf(buffer + len, - "Preferred Port %c\n", - 'A' + pAC->Rlmt.Net[t-1].Port[pAC->Rlmt. - Net[t-1].PrefPort]->PortNumber); - - len += sprintf(buffer + len, - "Bus speed (Mhz) %d\n", - pPnmiStruct->BusSpeed); - - len += sprintf(buffer + len, - "Bus width (Bit) %d\n", - pPnmiStruct->BusWidth); - - for (i=0; i < SK_MAX_SENSORS; i ++) { - if (strcmp(pAC->I2c.SenTable[i].SenDesc, - "Temperature") == 0 ) { - len += sprintf(buffer + len, - "Temperature (C) %d.%d\n", - pAC->I2c.SenTable[i].SenValue / 10, - pAC->I2c.SenTable[i].SenValue % 10); - len += sprintf(buffer + len, - "Temperature (F) %d.%d\n", - ((((pAC->I2c.SenTable[i].SenValue) - *10)*9)/5 + 3200)/100, - ((((pAC->I2c.SenTable[i].SenValue) - *10)*9)/5 + 3200) % 10); - } else if (strcmp(pAC->I2c.SenTable[i].SenDesc, - "Speed Fan") == 0 ) { - len += sprintf(buffer + len, - "Speed Fan %d\n", - pAC->I2c.SenTable[i].SenValue); - } else { - len += sprintf(buffer + len, - "%-20s %d.%d\n", - pAC->I2c.SenTable[i].SenDesc, - pAC->I2c.SenTable[i].SenValue / 1000, - pAC->I2c.SenTable[i].SenValue % 1000); - } - } - - /*Receive statistics */ - - len += sprintf(buffer + len, - "\nReceive statistics\n\n"); - - len += sprintf(buffer + len, - "Received bytes %s\n", - SkNumber(test_buf, pPnmiStat->StatRxOctetsOkCts, - 10,0,-1,0)); - len += sprintf(buffer + len, - "Received packets %s\n", - SkNumber(test_buf, pPnmiStat->StatRxOkCts, - 10,0,-1,0)); - len += sprintf(buffer + len, - "Received errors %s\n", - SkNumber(test_buf, pPnmiStat->StatRxFcsCts, - 10,0,-1,0)); - len += sprintf(buffer + len, - "Received dropped %s\n", - SkNumber(test_buf, pPnmiStruct->RxNoBufCts, - 10,0,-1,0)); - len += sprintf(buffer + len, - "Received multicast %s\n", - SkNumber(test_buf, pPnmiStat->StatRxMulticastOkCts, - 10,0,-1,0)); - len += sprintf(buffer + len, - "Received errors types\n"); - len += sprintf(buffer + len, - " length errors %s\n", - SkNumber(test_buf, pPnmiStat->StatRxRuntCts, - 10, 0, -1, 0)); - len += sprintf(buffer + len, - " over errors %s\n", - SkNumber(test_buf, pPnmiStat->StatRxFifoOverflowCts, - 10, 0, -1, 0)); - len += sprintf(buffer + len, - " crc errors %s\n", - SkNumber(test_buf, pPnmiStat->StatRxFcsCts, - 10, 0, -1, 0)); - len += sprintf(buffer + len, - " frame errors %s\n", - SkNumber(test_buf, pPnmiStat->StatRxFramingCts, - 10, 0, -1, 0)); - len += sprintf(buffer + len, - " fifo errors %s\n", - SkNumber(test_buf, pPnmiStat->StatRxFifoOverflowCts, - 10, 0, -1, 0)); - len += sprintf(buffer + len, - " missed errors %s\n", - SkNumber(test_buf, pPnmiStat->StatRxMissedCts, - 10, 0, -1, 0)); - - /*Transmit statistics */ - len += sprintf(buffer + len, - "\nTransmit statistics\n\n"); - - len += sprintf(buffer + len, - "Transmit bytes %s\n", - SkNumber(test_buf, pPnmiStat->StatTxOctetsOkCts, - 10,0,-1,0)); - len += sprintf(buffer + len, - "Transmit packets %s\n", - SkNumber(test_buf, pPnmiStat->StatTxOkCts, - 10,0,-1,0)); - len += sprintf(buffer + len, - "Transmit errors %s\n", - SkNumber(test_buf, pPnmiStat->StatTxSingleCollisionCts, - 10,0,-1,0)); - len += sprintf(buffer + len, - "Transmit dropped %s\n", - SkNumber(test_buf, pPnmiStruct->TxNoBufCts, - 10,0,-1,0)); - len += sprintf(buffer + len, - "Transmit collisions %s\n", - SkNumber(test_buf, pPnmiStat->StatTxSingleCollisionCts, - 10,0,-1,0)); - len += sprintf(buffer + len, - "Transmited errors types\n"); - len += sprintf(buffer + len, - " aborted errors %ld\n", - pAC->stats.tx_aborted_errors); - len += sprintf(buffer + len, - " carrier errors %s\n", - SkNumber(test_buf, pPnmiStat->StatTxCarrierCts, - 10, 0, -1, 0)); - len += sprintf(buffer + len, - " fifo errors %s\n", - SkNumber(test_buf, pPnmiStat->StatTxFifoUnderrunCts, - 10, 0, -1, 0)); - len += sprintf(buffer + len, - " heartbeat errors %s\n", - SkNumber(test_buf, pPnmiStat->StatTxCarrierCts, - 10, 0, -1, 0)); - len += sprintf(buffer + len, - " window errors %ld\n", - pAC->stats.tx_window_errors); - } + spin_lock_irqsave(&pAC->SlowPathLock, Flags); + Size = SK_PNMI_STRUCT_SIZE; + SkPnmiGetStruct(pAC, pAC->IoBase, pPnmiStruct, &Size, t); + spin_unlock_irqrestore(&pAC->SlowPathLock, Flags); + + pPnmiStat = &pPnmiStruct->Stat[0]; + + len = sprintf(buf, "\nDetailed statistic for device %s\n", dev->name); + len += sprintf(buf + len, "==================================\n"); + + /* Board statistics */ + len += sprintf(buf + len, "\nBoard statistics\n\n"); + len += sprintf(buf + len, "Active Port %c\n", + 'A' + rlmt->Port[rlmt->ActivePort]->PortNumber); + len += sprintf(buf + len, "Preferred Port %c\n", + 'A' + rlmt->Port[rlmt->PrefPort]->PortNumber); + + len += sprintf(buf + len, "Bus speed (Mhz) %d\n", + pPnmiStruct->BusSpeed); + + len += sprintf(buf + len, "Bus width (Bit) %d\n", + pPnmiStruct->BusWidth); + + for (i=0; i < SK_MAX_SENSORS; i ++) { + SK_SENSOR *sens = &pAC->I2c.SenTable[i]; + SK_I32 val = sens->SenValue; + if (strcmp(sens->SenDesc, "Temperature") == 0 ) { + len += sprintf(buf + len, + "Temperature (C) %d.%d\n", + val / 10, val % 10); + val = val * 18 + 3200; + len += sprintf(buf + len, + "Temperature (F) %d.%d\n", + val/100, val % 10); + } else if (strcmp(sens->SenDesc, "Speed Fan") == 0 ) { + len += sprintf(buf + len, + "Speed Fan %d\n", + val); + } else { + len += sprintf(buf + len, + "%-20s %d.%d\n", + sens->SenDesc, val / 1000, val % 1000); } - SkgeProcDev = next; - } - if (offset >= len) { - *eof = 1; - return 0; } + + /*Receive statistics */ + + len += sprintf(buf + len, "\nReceive statistics\n\n"); - *buffer_location = buffer + offset; - if (buffer_length >= len - offset) { - *eof = 1; - } - return (min_t(int, buffer_length, len - offset)); + len += sprintf(buf + len, "Received bytes %Ld\n", + (unsigned long long) pPnmiStat->StatRxOctetsOkCts); + len += sprintf(buf + len, "Received packets %Ld\n", + (unsigned long long) pPnmiStat->StatRxOkCts); + len += sprintf(buf + len, "Received errors %Ld\n", + (unsigned long long) pPnmiStat->StatRxFcsCts); + len += sprintf(buf + len, "Received dropped %Ld\n", + (unsigned long long) pPnmiStruct->RxNoBufCts); + len += sprintf(buf + len, "Received multicast %Ld\n", + (unsigned long long) pPnmiStat->StatRxMulticastOkCts); + len += sprintf(buf + len, "Received errors types\n"); + len += sprintf(buf + len, " length errors %Ld\n", + (unsigned long long) pPnmiStat->StatRxRuntCts); + len += sprintf(buf + len, " over errors %Ld\n", + (unsigned long long) pPnmiStat->StatRxFifoOverflowCts); + len += sprintf(buf + len, " crc errors %Ld\n", + (unsigned long long) pPnmiStat->StatRxFcsCts); + len += sprintf(buf + len, " frame errors %Ld\n", + (unsigned long long) pPnmiStat->StatRxFramingCts); + len += sprintf(buf + len, " fifo errors %Ld\n", + (unsigned long long) pPnmiStat->StatRxFifoOverflowCts); + len += sprintf(buf + len, " missed errors %Ld\n", + (unsigned long long) pPnmiStat->StatRxMissedCts); + + /*Transmit statistics */ + len += sprintf(buf + len, "\nTransmit statistics\n\n"); + + len += sprintf(buf + len, "Transmit bytes %Ld\n", + (unsigned long long) pPnmiStat->StatTxOctetsOkCts); + len += sprintf(buf + len, "Transmit packets %Ld\n", + (unsigned long long) pPnmiStat->StatTxOkCts); + len += sprintf(buf + len, "Transmit errors %Ld\n", + (unsigned long long) pPnmiStat->StatTxSingleCollisionCts); + len += sprintf(buf + len, "Transmit dropped %Ld\n", + (unsigned long long) pPnmiStruct->TxNoBufCts); + len += sprintf(buf + len, "Transmit collisions %Ld\n", + (unsigned long long) pPnmiStat->StatTxSingleCollisionCts); + len += sprintf(buf + len, "Transmited errors types\n"); + len += sprintf(buf + len, " aborted errors %ld\n", + pAC->stats.tx_aborted_errors); + len += sprintf(buf + len, " carrier errors %Ld\n", + (unsigned long long) pPnmiStat->StatTxCarrierCts); + len += sprintf(buf + len, " fifo errors %Ld\n", + (unsigned long long) pPnmiStat->StatTxFifoUnderrunCts); + len += sprintf(buf + len, " heartbeat errors %Ld\n", + (unsigned long long) pPnmiStat->StatTxCarrierCts); + len += sprintf(buf + len, " window errors %ld\n", + pAC->stats.tx_window_errors); + return len; } - - - - -/***************************************************************************** - * - * SkDoDiv - convert 64bit number - * - * Description: - * This function "converts" a long long number. - * - * Returns: - * remainder of division - */ -static long SkDoDiv (long long Dividend, int Divisor, long long *pErg) +static ssize_t sk_read(struct file *file, char *buf, size_t nbytes, loff_t *ppos) { - long Rest; - long long Ergebnis; - long Akku; - - - Akku = Dividend >> 32; - - Ergebnis = ((long long) (Akku / Divisor)) << 32; - Rest = Akku % Divisor ; - - Akku = Rest << 16; - Akku |= ((Dividend & 0xFFFF0000) >> 16); - - - Ergebnis += ((long long) (Akku / Divisor)) << 16; - Rest = Akku % Divisor ; - - Akku = Rest << 16; - Akku |= (Dividend & 0xFFFF); + struct inode * inode = file->f_dentry->d_inode; + struct proc_dir_entry *entry = PDE(inode); + char *page = (char *)__get_free_page(GFP_KERNEL); + struct net_device *dev; + loff_t pos = *ppos; + ssize_t res = 0; + int len = 0; - Ergebnis += (Akku / Divisor); - Rest = Akku % Divisor ; + if (!page) + return -ENOMEM; - *pErg = Ergebnis; - return (Rest); + spin_lock(&sk_devs_lock); + dev = entry->data; + if (dev) + len = sk_show_dev(dev, page); + spin_unlock(&sk_devs_lock); + + if (pos >= 0 && pos < len) { + res = nbytes; + if (res > len - pos) + res = len - pos; + if (copy_to_user(page + pos, buf, nbytes)) + res = -EFAULT; + else + *ppos = pos + res; + } + free_page((unsigned long) page); + return nbytes; } - -#if 0 -#define do_div(n,base) ({ \ -long long __res; \ -__res = ((unsigned long long) n) % (unsigned) base; \ -n = ((unsigned long long) n) / (unsigned) base; \ -__res; }) - -#endif - - -/***************************************************************************** - * - * SkNumber - Print results - * - * Description: - * This function converts a long long number into a string. - * - * Returns: - * number as string - */ -char * SkNumber(char * str, long long num, int base, int size, int precision - ,int type) +static loff_t sk_lseek(struct file *file, loff_t offset, int orig) { - char c,sign,tmp[66], *strorg = str; - const char *digits="0123456789abcdefghijklmnopqrstuvwxyz"; - int i; - - if (type & LARGE) - digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - if (type & LEFT) - type &= ~ZEROPAD; - if (base < 2 || base > 36) - return 0; - c = (type & ZEROPAD) ? '0' : ' '; - sign = 0; - if (type & SIGN) { - if (num < 0) { - sign = '-'; - num = -num; - size--; - } else if (type & PLUS) { - sign = '+'; - size--; - } else if (type & SPACE) { - sign = ' '; - size--; - } - } - if (type & SPECIAL) { - if (base == 16) - size -= 2; - else if (base == 8) - size--; - } - i = 0; - if (num == 0) - tmp[i++]='0'; - else while (num != 0) - tmp[i++] = digits[SkDoDiv(num,base, &num)]; - - if (i > precision) - precision = i; - size -= precision; - if (!(type&(ZEROPAD+LEFT))) - while(size-->0) - *str++ = ' '; - if (sign) - *str++ = sign; - if (type & SPECIAL) { - if (base==8) - *str++ = '0'; - else if (base==16) { - *str++ = '0'; - *str++ = digits[33]; - } + switch (orig) { + case 1: + offset += file->f_pos; + case 0: + if (offset >= 0) + return file->f_pos = offset; } - if (!(type & LEFT)) - while (size-- > 0) - *str++ = c; - while (i < precision--) - *str++ = '0'; - while (i-- > 0) - *str++ = tmp[i]; - while (size-- > 0) - *str++ = ' '; - - str[0] = '\0'; - - return strorg; + return -EINVAL; } - - +struct file_operations sk_proc_fops = { + .read = sk_read, + .llseek = sk_lseek, +}; diff -Nru a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c --- a/drivers/net/skfp/skfddi.c Mon Jun 9 23:16:06 2003 +++ b/drivers/net/skfp/skfddi.c Mon Jun 9 23:16:06 2003 @@ -2539,72 +2539,25 @@ } // drv_reset_indication - -//--------------- functions for use as a module ---------------- - -#ifdef MODULE -/************************ - * - * Note now that module autoprobing is allowed under PCI. The - * IRQ lines will not be auto-detected; instead I'll rely on the BIOSes - * to "do the right thing". - * - ************************/ -#define LP(a) ((struct s_smc*)(a)) static struct net_device *mdev; -/************************ - * - * init_module - * - * If compiled as a module, find - * adapters and initialize them. - * - ************************/ -int init_module(void) +static int __init skfd_init(void) { struct net_device *p; - PRINTK(KERN_INFO "FDDI init module\n"); if ((mdev = insert_device(NULL, skfp_probe)) == NULL) return -ENOMEM; - for (p = mdev; p != NULL; p = LP(p->priv)->os.next_module) { - PRINTK(KERN_INFO "device to register: %s\n", p->name); + for (p = mdev; p != NULL; p = ((struct s_smc *)p->priv)->os.next_module) { if (register_netdev(p) != 0) { printk("skfddi init_module failed\n"); return -EIO; } } - PRINTK(KERN_INFO "+++++ exit with success +++++\n"); return 0; -} // init_module +} -/************************ - * - * cleanup_module - * - * Release all resources claimed by this module. - * - ************************/ -void cleanup_module(void) -{ - PRINTK(KERN_INFO "cleanup_module\n"); - while (mdev != NULL) { - mdev = unlink_modules(mdev); - } - return; -} // cleanup_module - - -/************************ - * - * unlink_modules - * - * Unregister devices and release their memory. - * - ************************/ static struct net_device *unlink_modules(struct net_device *p) { struct net_device *next = NULL; @@ -2638,5 +2591,11 @@ return next; } // unlink_modules +static void __exit skfd_exit(void) +{ + while (mdev) + mdev = unlink_modules(mdev); +} -#endif /* MODULE */ +module_init(skfd_init); +module_exit(skfd_exit); diff -Nru a/drivers/net/sundance.c b/drivers/net/sundance.c --- a/drivers/net/sundance.c Mon Jun 9 23:16:14 2003 +++ b/drivers/net/sundance.c Mon Jun 9 23:16:14 2003 @@ -84,11 +84,14 @@ - Fix bug of custom mac address (StationAddr register only accept word write) + Version LK1.09 (D-Link): + - Fix the flowctrl bug. + - Set Pause bit in MII ANAR if flow control enabled. */ #define DRV_NAME "sundance" -#define DRV_VERSION "1.01+LK1.08a" -#define DRV_RELDATE "23-Apr-2003" +#define DRV_VERSION "1.01+LK1.09a" +#define DRV_RELDATE "16-May-2003" /* The user-configurable values. @@ -671,8 +674,8 @@ np->an_enable = 1; } } - if (flowctrl == 0) - np->flowctrl = 0; + if (flowctrl == 1) + np->flowctrl = 1; } /* Fibre PHY? */ @@ -687,6 +690,9 @@ /* Reset PHY */ mdio_write (dev, np->phys[0], MII_BMCR, BMCR_RESET); mdelay (300); + /* If flow control enabled, we need to advertise it.*/ + if (np->flowctrl) + mdio_write (dev, np->phys[0], MII_ADVERTISE, np->mii_if.advertising | 0x0400); mdio_write (dev, np->phys[0], MII_BMCR, BMCR_ANENABLE|BMCR_ANRESTART); /* Force media type */ if (!np->an_enable) { @@ -935,7 +941,7 @@ printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d " "negotiated capability %4.4x.\n", dev->name, duplex ? "full" : "half", np->phys[0], negotiated); - writew(duplex ? 0x20 : 0, ioaddr + MACCtrl0); + writew(readw(ioaddr + MACCtrl0) | duplex ? 0x20 : 0, ioaddr + MACCtrl0); } } @@ -1455,9 +1461,12 @@ "full" : "half"); } check_duplex (dev); - if (np->flowctrl == 0) - writew(readw(ioaddr + MACCtrl0) & ~EnbFlowCtrl, + if (np->flowctrl && np->mii_if.full_duplex) { + writew(readw(ioaddr + MulticastFilter1+2) | 0x0200, + ioaddr + MulticastFilter1+2); + writew(readw(ioaddr + MACCtrl0) | EnbFlowCtrl, ioaddr + MACCtrl0); + } } if (intr_status & StatsMax) { get_stats(dev); @@ -1500,6 +1509,7 @@ static void set_rx_mode(struct net_device *dev) { long ioaddr = dev->base_addr; + struct netdev_private *np = dev->priv; u16 mc_filter[4]; /* Multicast hash filter */ u32 rx_mode; int i; @@ -1532,6 +1542,9 @@ writeb(AcceptBroadcast | AcceptMyPhys, ioaddr + RxMode); return; } + if (np->mii_if.full_duplex && np->flowctrl) + mc_filter[3] |= 0x0200; + for (i = 0; i < 4; i++) writew(mc_filter[i], ioaddr + MulticastFilter0 + i*2); writeb(rx_mode, ioaddr + RxMode); diff -Nru a/drivers/net/sungem.c b/drivers/net/sungem.c --- a/drivers/net/sungem.c Mon Jun 9 23:16:19 2003 +++ b/drivers/net/sungem.c Mon Jun 9 23:16:19 2003 @@ -48,7 +48,7 @@ #include <asm/pbm.h> #endif -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC #include <asm/pci-bridge.h> #include <asm/prom.h> #include <asm/machdep.h> @@ -1491,7 +1491,7 @@ mifcfg &= ~MIF_CFG_BBMODE; writel(mifcfg, gp->regs + MIF_CFG); -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) { int i, j; @@ -1525,7 +1525,7 @@ break; } } -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PMAC */ if (gp->pdev->vendor == PCI_VENDOR_ID_SUN && gp->pdev->device == PCI_DEVICE_ID_SUN_GEM) { @@ -1924,7 +1924,7 @@ } } -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC /* Enable the chip's clock and make sure it's config space is * setup properly. There appear to be no need to restore the * base addresses. @@ -1963,7 +1963,7 @@ pmac_call_feature(PMAC_FTR_GMAC_ENABLE, gp->of_node, 0, 0); } -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PMAC */ /* Must be invoked under gp->lock. */ static void gem_stop_phy(struct gem *gp) @@ -2028,10 +2028,10 @@ spin_unlock_irq(&gp->lock); -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC /* Power down the chip */ gem_apple_powerdown(gp); -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PMAC */ } else { gem_stop(gp); @@ -2085,13 +2085,13 @@ * etc. state so it is safe to do this bit without gp->lock */ if (!gp->hw_running) { -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC /* First, we need to bring up the chip */ if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) { gem_apple_powerup(gp); gem_check_invariants(gp); } -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PMAC */ /* Reset the chip */ spin_lock_irq(&gp->lock); @@ -2112,10 +2112,10 @@ printk(KERN_ERR "%s: failed to request irq !\n", gp->dev->name); -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC if (!hw_was_up && gp->pdev->vendor == PCI_VENDOR_ID_APPLE) gem_apple_powerdown(gp); -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PMAC */ /* Fire the PM timer that will shut us down in about 10 seconds */ gp->pm_timer.expires = jiffies + 10*HZ; add_timer(&gp->pm_timer); @@ -2227,13 +2227,13 @@ printk(KERN_INFO "%s: resuming\n", dev->name); if (gp->opened) { -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC /* First, we need to bring up the chip */ if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) { gem_apple_powerup(gp); gem_check_invariants(gp); } -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PMAC */ spin_lock_irq(&gp->lock); gem_stop(gp); @@ -2541,7 +2541,7 @@ return rc; } -#if (!defined(__sparc__) && !defined(CONFIG_ALL_PPC)) +#if (!defined(__sparc__) && !defined(CONFIG_PPC)) /* Fetch MAC address from vital product data of PCI ROM. */ static void find_eth_addr_in_vpd(void *rom_base, int len, unsigned char *dev_addr) { @@ -2604,7 +2604,7 @@ static int __devinit gem_get_device_address(struct gem *gp) { -#if defined(__sparc__) || defined(CONFIG_ALL_PPC) +#if defined(__sparc__) || defined(CONFIG_PPC_PMAC) struct net_device *dev = gp->dev; #endif @@ -2623,7 +2623,7 @@ } if (node == -1) memcpy(dev->dev_addr, idprom->id_ethaddr, 6); -#elif defined(CONFIG_ALL_PPC) +#elif defined(CONFIG_PPC_PMAC) unsigned char *addr; addr = get_property(gp->of_node, "local-mac-address", NULL); @@ -2748,7 +2748,7 @@ * invariants to work, but also because the firmware might * not have properly shut down the PHY. */ -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC if (pdev->vendor == PCI_VENDOR_ID_APPLE) gem_apple_powerup(gp); #endif @@ -2779,7 +2779,7 @@ goto err_out_iounmap; } -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC gp->of_node = pci_device_to_OF_node(pdev); #endif if (gem_get_device_address(gp)) diff -Nru a/drivers/net/sungem.h b/drivers/net/sungem.h --- a/drivers/net/sungem.h Mon Jun 9 23:16:13 2003 +++ b/drivers/net/sungem.h Mon Jun 9 23:16:13 2003 @@ -998,7 +998,7 @@ dma_addr_t gblock_dvma; struct pci_dev *pdev; struct net_device *dev; -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC struct device_node *of_node; #endif }; diff -Nru a/drivers/net/sunqe.c b/drivers/net/sunqe.c --- a/drivers/net/sunqe.c Mon Jun 9 23:16:10 2003 +++ b/drivers/net/sunqe.c Mon Jun 9 23:16:10 2003 @@ -124,7 +124,6 @@ qb->qe_rxd[i].rx_flags = (RXD_OWN | ((RXD_PKT_SZ) & RXD_LENGTH)); } - return IRQ_HANDLED; } static int qe_init(struct sunqe *qep, int from_irq) @@ -723,34 +722,31 @@ struct net_device *qe_devs[4]; struct sunqe *qeps[4]; struct sbus_dev *qesdevs[4]; + struct sbus_dev *child; struct sunqec *qecp = NULL; u8 bsizes, bsizes_more; - int i, j, res = ENOMEM; + int i, j, res = -ENOMEM; - dev = init_etherdev(0, sizeof(struct sunqe)); - qe_devs[0] = dev; - qeps[0] = (struct sunqe *) dev->priv; - qeps[0]->channel = 0; - spin_lock_init(&qeps[0]->lock); - for (j = 0; j < 6; j++) - qe_devs[0]->dev_addr[j] = idprom->id_ethaddr[j]; + for (i = 0; i < 4; i++) { + qe_devs[i] = alloc_etherdev(sizeof(struct sunqe)); + if (!qe_devs[i]) + goto out; + } if (version_printed++ == 0) printk(KERN_INFO "%s", version); - qe_devs[1] = qe_devs[2] = qe_devs[3] = NULL; - for (i = 1; i < 4; i++) { - qe_devs[i] = init_etherdev(0, sizeof(struct sunqe)); - if (qe_devs[i] == NULL || qe_devs[i]->priv == NULL) - goto qec_free_devs; + for (i = 0; i < 4; i++) { qeps[i] = (struct sunqe *) qe_devs[i]->priv; for (j = 0; j < 6; j++) qe_devs[i]->dev_addr[j] = idprom->id_ethaddr[j]; qeps[i]->channel = i; + spin_lock_init(&qeps[i]->lock); } + qecp = kmalloc(sizeof(struct sunqec), GFP_KERNEL); if (qecp == NULL) - goto qec_free_devs; + goto out1; qecp->qec_sdev = sdev; for (i = 0; i < 4; i++) { @@ -759,25 +755,15 @@ qeps[i]->parent = qecp; } - /* Link in channel 0. */ - i = prom_getintdefault(sdev->child->prom_node, "channel#", -1); - if (i == -1) { res=ENODEV; goto qec_free_devs; } - qesdevs[i] = sdev->child; - - /* Link in channel 1. */ - i = prom_getintdefault(sdev->child->next->prom_node, "channel#", -1); - if (i == -1) { res=ENODEV; goto qec_free_devs; } - qesdevs[i] = sdev->child->next; - - /* Link in channel 2. */ - i = prom_getintdefault(sdev->child->next->next->prom_node, "channel#", -1); - if (i == -1) { res=ENODEV; goto qec_free_devs; } - qesdevs[i] = sdev->child->next->next; - - /* Link in channel 3. */ - i = prom_getintdefault(sdev->child->next->next->next->prom_node, "channel#", -1); - if (i == -1) { res=ENODEV; goto qec_free_devs; } - qesdevs[i] = sdev->child->next->next->next; + res = -ENODEV; + + for (i = 0, child = sdev->child; i < 4; i++, child = child->next) { + /* Link in channel */ + j = prom_getintdefault(child->prom_node, "channel#", -1); + if (j == -1) + goto out2; + qesdevs[j] = child; + } for (i = 0; i < 4; i++) qeps[i]->qe_sdev = qesdevs[i]; @@ -787,22 +773,18 @@ GLOB_REG_SIZE, "QEC Global Registers"); if (!qecp->gregs) { printk(KERN_ERR "QuadEther: Cannot map QEC global registers.\n"); - res = ENODEV; - goto qec_free_devs; + goto out2; } /* Make sure the QEC is in MACE mode. */ if ((sbus_readl(qecp->gregs + GLOB_CTRL) & 0xf0000000) != GLOB_CTRL_MMODE) { printk(KERN_ERR "QuadEther: AIEEE, QEC is not in MACE mode!\n"); - res = ENODEV; - goto qec_free_devs; + goto out3; } /* Reset the QEC. */ - if (qec_global_reset(qecp->gregs)) { - res = ENODEV; - goto qec_free_devs; - } + if (qec_global_reset(qecp->gregs)) + goto out3; /* Find and set the burst sizes for the QEC, since it does * the actual dma for all 4 channels. @@ -825,40 +807,36 @@ qec_init_once(qecp, sdev); for (i = 0; i < 4; i++) { + struct sunqe *qe = qeps[i]; /* Map in QEC per-channel control registers. */ - qeps[i]->qcregs = sbus_ioremap(&qesdevs[i]->resource[0], 0, - CREG_REG_SIZE, "QEC Channel Registers"); - if (!qeps[i]->qcregs) { + qe->qcregs = sbus_ioremap(&qe->qe_sdev->resource[0], 0, + CREG_REG_SIZE, "QEC Channel Registers"); + if (!qe->qcregs) { printk(KERN_ERR "QuadEther: Cannot map QE %d's channel registers.\n", i); - res = ENODEV; - goto qec_free_devs; + goto out4; } /* Map in per-channel AMD MACE registers. */ - qeps[i]->mregs = sbus_ioremap(&qesdevs[i]->resource[1], 0, - MREGS_REG_SIZE, "QE MACE Registers"); - if (!qeps[i]->mregs) { + qe->mregs = sbus_ioremap(&qe->qe_sdev->resource[1], 0, + MREGS_REG_SIZE, "QE MACE Registers"); + if (!qe->mregs) { printk(KERN_ERR "QuadEther: Cannot map QE %d's MACE registers.\n", i); - res = ENODEV; - goto qec_free_devs; + goto out4; } - qeps[i]->qe_block = sbus_alloc_consistent(qesdevs[i], - PAGE_SIZE, - &qeps[i]->qblock_dvma); - qeps[i]->buffers = sbus_alloc_consistent(qesdevs[i], - sizeof(struct sunqe_buffers), - &qeps[i]->buffers_dvma); - if (qeps[i]->qe_block == NULL || - qeps[i]->qblock_dvma == 0 || - qeps[i]->buffers == NULL || - qeps[i]->buffers_dvma == 0) { - res = ENODEV; - goto qec_free_devs; + qe->qe_block = sbus_alloc_consistent(qe->qe_sdev, + PAGE_SIZE, + &qe->qblock_dvma); + qe->buffers = sbus_alloc_consistent(qe->qe_sdev, + sizeof(struct sunqe_buffers), + &qe->buffers_dvma); + if (qe->qe_block == NULL || qe->qblock_dvma == 0 || + qe->buffers == NULL || qe->buffers_dvma == 0) { + goto out4; } /* Stop this QE. */ - qe_stop(qeps[i]); + qe_stop(qe); } for (i = 0; i < 4; i++) { @@ -872,7 +850,6 @@ qe_devs[i]->watchdog_timeo = 5*HZ; qe_devs[i]->irq = sdev->irqs[0]; qe_devs[i]->dma = 0; - ether_setup(qe_devs[i]); } /* QEC receives interrupts from each QE, then it sends the actual @@ -883,8 +860,13 @@ if (request_irq(sdev->irqs[0], &qec_interrupt, SA_SHIRQ, "QuadEther", (void *) qecp)) { printk(KERN_ERR "QuadEther: Can't register QEC master irq handler.\n"); - res = EAGAIN; - goto qec_free_devs; + res = -EAGAIN; + goto out4; + } + + for (i = 0; i < 4; i++) { + if (register_netdev(qe_devs[i]) != 0) + goto out5; } /* Report the QE channels. */ @@ -900,42 +882,43 @@ /* We are home free at this point, link the qe's into * the master list for later driver exit. */ - for (i = 0; i < 4; i++) - qe_devs[i]->ifindex = dev_new_index(); qecp->next_module = root_qec_dev; root_qec_dev = qecp; return 0; -qec_free_devs: +out5: + while (i--) + unregister_netdev(qe_devs[i]); + free_irq(sdev->irqs[0], (void *)qecp); +out4: for (i = 0; i < 4; i++) { - if (qe_devs[i] != NULL) { - if (qe_devs[i]->priv) { - struct sunqe *qe = (struct sunqe *)qe_devs[i]->priv; - - if (qe->qcregs) - sbus_iounmap(qe->qcregs, CREG_REG_SIZE); - if (qe->mregs) - sbus_iounmap(qe->mregs, MREGS_REG_SIZE); - if (qe->qe_block != NULL) - sbus_free_consistent(qe->qe_sdev, - PAGE_SIZE, - qe->qe_block, - qe->qblock_dvma); - if (qe->buffers != NULL) - sbus_free_consistent(qe->qe_sdev, - sizeof(struct sunqe_buffers), - qe->buffers, - qe->buffers_dvma); - } - kfree(qe_devs[i]); - } - } - if (qecp != NULL) { - if (qecp->gregs) - sbus_iounmap(qecp->gregs, GLOB_REG_SIZE); - kfree(qecp); - } + struct sunqe *qe = (struct sunqe *)qe_devs[i]->priv; + + if (qe->qcregs) + sbus_iounmap(qe->qcregs, CREG_REG_SIZE); + if (qe->mregs) + sbus_iounmap(qe->mregs, MREGS_REG_SIZE); + if (qe->qe_block) + sbus_free_consistent(qe->qe_sdev, + PAGE_SIZE, + qe->qe_block, + qe->qblock_dvma); + if (qe->buffers) + sbus_free_consistent(qe->qe_sdev, + sizeof(struct sunqe_buffers), + qe->buffers, + qe->buffers_dvma); + } +out3: + sbus_iounmap(qecp->gregs, GLOB_REG_SIZE); +out2: + kfree(qecp); +out1: + i = 4; +out: + while (i--) + kfree(qe_devs[i]); return res; } diff -Nru a/drivers/net/tg3.c b/drivers/net/tg3.c --- a/drivers/net/tg3.c Mon Jun 9 23:16:13 2003 +++ b/drivers/net/tg3.c Mon Jun 9 23:16:13 2003 @@ -6400,8 +6400,7 @@ tw32(BUFMGR_MODE, 0); tw32(FTQ_RESET, 0); - /* pci_alloc_consistent gives only non-DAC addresses */ - test_desc.addr_hi = 0; + test_desc.addr_hi = ((u64) buf_dma) >> 32; test_desc.addr_lo = buf_dma & 0xffffffff; test_desc.nic_mbuf = 0x00002100; test_desc.len = size; @@ -6741,8 +6740,14 @@ } /* Configure DMA attributes. */ - if (!pci_set_dma_mask(pdev, (u64) 0xffffffffffffffff)) { + if (!pci_set_dma_mask(pdev, (u64) 0xffffffffffffffffULL)) { pci_using_dac = 1; + if (pci_set_consistent_dma_mask(pdev, + (u64) 0xffffffffffffffff)) { + printk(KERN_ERR PFX "Unable to obtain 64 bit DMA " + "for consistent allocations\n"); + goto err_out_free_res; + } } else { err = pci_set_dma_mask(pdev, (u64) 0xffffffff); if (err) { diff -Nru a/drivers/net/tlan.c b/drivers/net/tlan.c --- a/drivers/net/tlan.c Mon Jun 9 23:16:07 2003 +++ b/drivers/net/tlan.c Mon Jun 9 23:16:07 2003 @@ -346,6 +346,27 @@ static int TLan_EeReadByte( struct net_device *, u8, u8 * ); +static void +TLan_StoreSKB( struct tlan_list_tag *tag, struct sk_buff *skb) +{ + unsigned long addr = (unsigned long)skb; + tag->buffer[9].address = (u32)addr; + addr >>= 31; /* >>= 32 is undefined for 32bit arch, stupid C */ + addr >>= 1; + tag->buffer[8].address = (u32)addr; +} + +static struct sk_buff * +TLan_GetSKB( struct tlan_list_tag *tag) +{ + unsigned long addr = tag->buffer[8].address; + addr <<= 31; + addr <<= 1; + addr |= tag->buffer[9].address; + return (struct sk_buff *) addr; +} + + static TLanIntVectorFunc *TLanIntVector[TLAN_INT_NUMBER_OF_INTS] = { TLan_HandleInvalid, TLan_HandleTxEOF, @@ -424,7 +445,7 @@ pci_free_consistent(priv->pciDev, priv->dmaSize, priv->dmaStorage, priv->dmaStorageDMA ); } - release_region( dev->base_addr, 0x10 ); + pci_release_regions(pdev); kfree( dev ); @@ -510,15 +531,25 @@ TLanPrivateInfo *priv; u8 pci_rev; u16 device_id; - int reg; + int reg, rc = -ENODEV; + + if (pdev) { + rc = pci_enable_device(pdev); + if (rc) + return rc; - if (pdev && pci_enable_device(pdev)) - return -EIO; + rc = pci_request_regions(pdev, TLanSignature); + if (rc) { + printk(KERN_ERR "TLAN: Could not reserve IO regions\n"); + goto err_out; + } + } - dev = init_etherdev(NULL, sizeof(TLanPrivateInfo)); + dev = alloc_etherdev(sizeof(TLanPrivateInfo)); if (dev == NULL) { printk(KERN_ERR "TLAN: Could not allocate memory for device.\n"); - return -ENOMEM; + rc = -ENOMEM; + goto err_out_regions; } SET_MODULE_OWNER(dev); SET_NETDEV_DEV(dev, &pdev->dev); @@ -533,12 +564,10 @@ priv->adapter = &board_info[ent->driver_data]; - if(pci_set_dma_mask(pdev, 0xFFFFFFFF)) - { + rc = pci_set_dma_mask(pdev, 0xFFFFFFFF); + if (rc) { printk(KERN_ERR "TLAN: No suitable PCI mapping available.\n"); - unregister_netdev(dev); - kfree(dev); - return -ENODEV; + goto err_out_free_dev; } pci_read_config_byte ( pdev, PCI_REVISION_ID, &pci_rev); @@ -553,9 +582,8 @@ } if (!pci_io_base) { printk(KERN_ERR "TLAN: No IO mappings available\n"); - unregister_netdev(dev); - kfree(dev); - return -ENODEV; + rc = -EIO; + goto err_out_free_dev; } dev->base_addr = pci_io_base; @@ -605,12 +633,18 @@ spin_lock_init(&priv->lock); - if (TLan_Init(dev)) { + rc = TLan_Init(dev); + if (rc) { + printk(KERN_ERR "TLAN: Could not set up device.\n"); + goto err_out_free_dev; + } + + rc = register_netdev(dev); + if (rc) { printk(KERN_ERR "TLAN: Could not register device.\n"); - unregister_netdev(dev); - kfree(dev); - return -EAGAIN; - } else { + goto err_out_uninit; + } + TLanDevicesInstalled++; boards_found++; @@ -631,8 +665,19 @@ priv->adapter->deviceLabel, priv->adapterRev); return 0; - } +err_out_uninit: + pci_free_consistent(priv->pciDev, priv->dmaSize, priv->dmaStorage, + priv->dmaStorageDMA ); +err_out_free_dev: + kfree(dev); +err_out_regions: + if (pdev) + pci_release_regions(pdev); +err_out: + if (pdev) + pci_disable_device(pdev); + return rc; } @@ -798,15 +843,6 @@ priv = dev->priv; - if (!priv->is_eisa) /* EISA devices have already requested IO */ - if (!request_region( dev->base_addr, 0x10, TLanSignature )) { - printk(KERN_ERR "TLAN: %s: IO port region 0x%lx size 0x%x in use.\n", - dev->name, - dev->base_addr, - 0x10 ); - return -EIO; - } - if ( bbuf ) { dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS ) * ( sizeof(TLanList) + TLAN_MAX_FRAME_SIZE ); @@ -820,7 +856,6 @@ if ( priv->dmaStorage == NULL ) { printk(KERN_ERR "TLAN: Could not allocate lists and buffers for %s.\n", dev->name ); - release_region( dev->base_addr, 0x10 ); return -ENOMEM; } memset( priv->dmaStorage, 0, dma_size ); @@ -1039,7 +1074,7 @@ memcpy( tail_buffer, skb->data, skb->len ); } else { tail_list->buffer[0].address = pci_map_single(priv->pciDev, skb->data, skb->len, PCI_DMA_TODEVICE); - tail_list->buffer[9].address = (u32) skb; + TLan_StoreSKB(tail_list, skb); } pad = TLAN_MIN_FRAME_SIZE - skb->len; @@ -1365,9 +1400,10 @@ while (((tmpCStat = head_list->cStat ) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) { ack++; if ( ! bbuf ) { - struct sk_buff *skb = (struct sk_buff *) head_list->buffer[9].address; + struct sk_buff *skb = TLan_GetSKB(head_list); pci_unmap_single(priv->pciDev, head_list->buffer[0].address, skb->len, PCI_DMA_TODEVICE); dev_kfree_skb_any(skb); + head_list->buffer[8].address = 0; head_list->buffer[9].address = 0; } @@ -1523,7 +1559,7 @@ new_skb = dev_alloc_skb( TLAN_MAX_FRAME_SIZE + 7 ); if ( new_skb != NULL ) { - skb = (struct sk_buff *) head_list->buffer[9].address; + skb = TLan_GetSKB(head_list); pci_unmap_single(priv->pciDev, head_list->buffer[0].address, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); skb_trim( skb, frameSize ); @@ -1537,10 +1573,7 @@ t = (void *) skb_put( new_skb, TLAN_MAX_FRAME_SIZE ); head_list->buffer[0].address = pci_map_single(priv->pciDev, new_skb->data, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); head_list->buffer[8].address = (u32) t; -#if BITS_PER_LONG==64 -#error "Not 64bit clean" -#endif - head_list->buffer[9].address = (u32) new_skb; + TLan_StoreSKB(head_list, new_skb); } else printk(KERN_WARNING "TLAN: Couldn't allocate memory for received data.\n" ); } @@ -1926,6 +1959,7 @@ } list->buffer[2].count = 0; list->buffer[2].address = 0; + list->buffer[8].address = 0; list->buffer[9].address = 0; } @@ -1951,7 +1985,7 @@ } list->buffer[0].address = pci_map_single(priv->pciDev, t, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); list->buffer[8].address = (u32) t; - list->buffer[9].address = (u32) skb; + TLan_StoreSKB(list, skb); } list->buffer[1].count = 0; list->buffer[1].address = 0; @@ -1974,20 +2008,22 @@ if ( ! bbuf ) { for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) { list = priv->txList + i; - skb = (struct sk_buff *) list->buffer[9].address; + skb = TLan_GetSKB(list); if ( skb ) { pci_unmap_single(priv->pciDev, list->buffer[0].address, skb->len, PCI_DMA_TODEVICE); dev_kfree_skb_any( skb ); + list->buffer[8].address = 0; list->buffer[9].address = 0; } } for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ ) { list = priv->rxList + i; - skb = (struct sk_buff *) list->buffer[9].address; + skb = TLan_GetSKB(list); if ( skb ) { pci_unmap_single(priv->pciDev, list->buffer[0].address, TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); dev_kfree_skb_any( skb ); + list->buffer[8].address = 0; list->buffer[9].address = 0; } } diff -Nru a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c --- a/drivers/net/tokenring/3c359.c Mon Jun 9 23:16:19 2003 +++ b/drivers/net/tokenring/3c359.c Mon Jun 9 23:16:19 2003 @@ -1129,7 +1129,7 @@ netif_stop_queue(dev) ; xl_freemem(dev) ; free_irq(dev->irq,dev); - unregister_trdev(dev) ; + unregister_netdev(dev) ; kfree(dev) ; xl_reset(dev) ; writel(ACK_INTERRUPT | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; @@ -1783,7 +1783,7 @@ struct net_device *dev = pci_get_drvdata(pdev); struct xl_private *xl_priv=(struct xl_private *)dev->priv; - unregister_trdev(dev); + unregister_netdev(dev); iounmap(xl_priv->xl_mmio) ; pci_release_regions(pdev) ; pci_set_drvdata(pdev,NULL) ; diff -Nru a/drivers/net/tokenring/abyss.c b/drivers/net/tokenring/abyss.c --- a/drivers/net/tokenring/abyss.c Mon Jun 9 23:16:08 2003 +++ b/drivers/net/tokenring/abyss.c Mon Jun 9 23:16:08 2003 @@ -112,9 +112,10 @@ /* At this point we have found a valid card. */ - dev = init_trdev(NULL, 0); + dev = alloc_trdev(0); if (!dev) return -ENOMEM; + SET_MODULE_OWNER(dev); if (!request_region(pci_ioaddr, ABYSS_IO_EXTENT, dev->name)) { @@ -165,21 +166,21 @@ dev->open = abyss_open; dev->stop = abyss_close; - ret = register_trdev(dev); + pci_set_drvdata(pdev, dev); + + ret = register_netdev(dev); if (ret) goto err_out_tmsdev; - - pci_set_drvdata(pdev, dev); return 0; err_out_tmsdev: + pci_set_drvdata(pdev, NULL); tmsdev_term(dev); err_out_irq: free_irq(pdev->irq, dev); err_out_region: release_region(pci_ioaddr, ABYSS_IO_EXTENT); err_out_trdev: - unregister_netdev(dev); kfree(dev); return ret; } diff -Nru a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c --- a/drivers/net/tokenring/ibmtr.c Mon Jun 9 23:16:14 2003 +++ b/drivers/net/tokenring/ibmtr.c Mon Jun 9 23:16:15 2003 @@ -110,7 +110,6 @@ #include <linux/module.h> #ifdef PCMCIA -#undef MODULE #undef ENABLE_PAGING #else #define ENABLE_PAGING 1 @@ -352,7 +351,7 @@ unsigned char segment, intr=0, irq=0, i, j, cardpresent=NOTOK, temp=0; void * t_mmio = 0; - struct tok_info *ti = 0; + struct tok_info *ti = dev->priv; void *cd_chanid; unsigned char *tchanid, ctemp; #ifndef PCMCIA @@ -361,14 +360,6 @@ static int version_printed; #endif -#ifndef MODULE -#ifndef PCMCIA - dev = init_trdev(dev, 0); - if (!dev) - return -ENOMEM; -#endif -#endif - /* Query the adapter PIO base port which will return * indication of where MMIO was placed. We also have a * coded interrupt number. @@ -404,7 +395,6 @@ */ #ifdef PCMCIA iounmap(t_mmio); - ti = dev->priv; /*BMS moved up here */ t_mmio = (void *)ti->mmio; /*BMS to get virtual address */ irq = ti->irq; /*BMS to display the irq! */ #endif @@ -454,30 +444,20 @@ DPRINTK("Expected for MCA: "); PrtChanID(mcchannelid, 1); } - /* Now, allocate some of the pl0 buffers for this driver.. */ + /* Now, setup some of the pl0 buffers for this driver.. */ /* If called from PCMCIA, it is already set up, so no need to waste the memory, just use the existing structure */ #ifndef PCMCIA - ti = (struct tok_info *) kmalloc(sizeof(struct tok_info), GFP_KERNEL); - if (ti == NULL) { - iounmap(t_mmio); - return -ENOMEM; - } - memset(ti, 0, sizeof(struct tok_info)); ti->mmio = t_mmio; - dev->priv = ti; /* this seems like the logical use of the - field ... let's try some empirical tests - using the token-info structure -- that - should fit with out future hope of multiple - adapter support as well /dwm */ - for(i=0; i<IBMTR_MAX_ADAPTERS; i++) { - if (turbo_io[i] != PIOaddr) continue; + for (i = 0; i < IBMTR_MAX_ADAPTERS; i++) { + if (turbo_io[i] != PIOaddr) + continue; #if IBMTR_DEBUG_MESSAGES - printk("ibmtr::tr_probe1, setting PIOaddr %x to Turbo\n" , - PIOaddr); + printk("ibmtr::tr_probe1, setting PIOaddr %x to Turbo\n", + PIOaddr); #endif - ti->turbo=1; - t_irq=turbo_irq[i]; + ti->turbo = 1; + t_irq = turbo_irq[i]; } #endif /* !PCMCIA */ ti->readlog_pending = 0; @@ -826,11 +806,6 @@ dev->set_multicast_list = tok_set_multicast_list; dev->change_mtu = ibmtr_change_mtu; -#ifndef MODULE -#ifndef PCMCIA - tr_setup(dev); -#endif -#endif return 0; } @@ -1948,21 +1923,21 @@ int count=0; find_turbo_adapters(io); + for (i = 0; io[i] && (i < IBMTR_MAX_ADAPTERS); i++) { irq[i] = 0; mem[i] = 0; - dev_ibmtr[i] = NULL; - dev_ibmtr[i] = init_trdev(dev_ibmtr[i], 0); + dev_ibmtr[i] = alloc_trdev(sizeof(struct tok_info)); if (dev_ibmtr[i] == NULL) { - if (i==0) + if (i == 0) return -ENOMEM; - break ; + break; } dev_ibmtr[i]->base_addr = io[i]; dev_ibmtr[i]->irq = irq[i]; dev_ibmtr[i]->mem_start = mem[i]; dev_ibmtr[i]->init = &ibmtr_probe; - if (register_trdev(dev_ibmtr[i]) != 0) { + if (register_netdev(dev_ibmtr[i]) != 0) { kfree(dev_ibmtr[i]); dev_ibmtr[i] = NULL; continue; @@ -1970,7 +1945,7 @@ count++; } if (count) return 0; - printk("ibmtr: register_trdev() returned non-zero.\n"); + printk("ibmtr: register_netdev() returned non-zero.\n"); return -EIO; } /*init_module */ @@ -1979,24 +1954,25 @@ int i,j; for (i = 0; i < IBMTR_MAX_ADAPTERS; i++){ - if(!dev_ibmtr[i]) continue; + if (!dev_ibmtr[i]) + continue; if (dev_ibmtr[i]->base_addr) { outb(0,dev_ibmtr[i]->base_addr+ADAPTRESET); for(j=jiffies+TR_RST_TIME; time_before_eq(jiffies,j);) ; outb(0,dev_ibmtr[i]->base_addr+ADAPTRESETREL); } - unregister_trdev(dev_ibmtr[i]); + unregister_netdev(dev_ibmtr[i]); free_irq(dev_ibmtr[i]->irq, dev_ibmtr[i]); release_region(dev_ibmtr[i]->base_addr, IBMTR_IO_EXTENT); #ifndef PCMCIA { - struct tok_info *ti = (struct tok_info *)dev_ibmtr[i]->priv ; - iounmap((u32 *)ti->mmio) ; - iounmap((u32 *)ti->sram_virt) ; + struct tok_info *ti = (struct tok_info *) + dev_ibmtr[i]->priv; + iounmap((u32 *)ti->mmio); + iounmap((u32 *)ti->sram_virt); } #endif - kfree(dev_ibmtr[i]->priv); kfree(dev_ibmtr[i]); dev_ibmtr[i] = NULL; } diff -Nru a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c --- a/drivers/net/tokenring/lanstreamer.c Mon Jun 9 23:16:19 2003 +++ b/drivers/net/tokenring/lanstreamer.c Mon Jun 9 23:16:19 2003 @@ -221,213 +221,220 @@ static int __devinit streamer_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { - struct net_device *dev=NULL; + struct net_device *dev; struct streamer_private *streamer_priv; - __u32 pio_start, pio_end, pio_flags, pio_len; - __u32 mmio_start, mmio_end, mmio_flags, mmio_len; - int rc=0; - static int card_no=-1; - u16 pcr; - u8 cls = 0; + unsigned long pio_start, pio_end, pio_flags, pio_len; + unsigned long mmio_start, mmio_end, mmio_flags, mmio_len; + int rc = 0; + static int card_no=-1; + u16 pcr; + u8 cls = 0; #if STREAMER_DEBUG - printk("lanstreamer::streamer_init_one, entry pdev %p\n",pdev); + printk("lanstreamer::streamer_init_one, entry pdev %p\n",pdev); #endif - card_no++; - dev=init_trdev(dev, sizeof(*streamer_priv)); - if(dev==NULL) { - printk(KERN_ERR "lanstreamer: out of memory.\n"); - return -ENOMEM; - } - SET_MODULE_OWNER(dev); - streamer_priv=dev->priv; + card_no++; + dev = alloc_trdev(sizeof(*streamer_priv)); + if (dev==NULL) { + printk(KERN_ERR "lanstreamer: out of memory.\n"); + return -ENOMEM; + } + + SET_MODULE_OWNER(dev); + streamer_priv = dev->priv; #if STREAMER_NETWORK_MONITOR #ifdef CONFIG_PROC_FS - if (!dev_streamer) { - create_proc_read_entry("net/streamer_tr",0,0,streamer_proc_info,NULL); - } - streamer_priv->next=dev_streamer; - dev_streamer=streamer_priv; -#endif -#endif - - if(pci_set_dma_mask(pdev, 0xFFFFFFFF)) { - printk(KERN_ERR "%s: No suitable PCI mapping available.\n", dev->name); - rc = -ENODEV; - goto err_out; - } - - if (pci_enable_device(pdev)) { - printk(KERN_ERR "lanstreamer: unable to enable pci device\n"); - rc=-EIO; - goto err_out; - } - - pci_set_master(pdev); - - pio_start = pci_resource_start(pdev, 0); - pio_end = pci_resource_end(pdev, 0); - pio_flags = pci_resource_flags(pdev, 0); - pio_len = pci_resource_len(pdev, 0); - - mmio_start = pci_resource_start(pdev, 1); - mmio_end = pci_resource_end(pdev, 1); - mmio_flags = pci_resource_flags(pdev, 1); - mmio_len = pci_resource_len(pdev, 1); - + if (!dev_streamer) + create_proc_read_entry("net/streamer_tr", 0, 0, + streamer_proc_info, NULL); + streamer_priv->next = dev_streamer; + dev_streamer = streamer_priv; +#endif +#endif + + if (pci_set_dma_mask(pdev, 0xFFFFFFFF)) { + printk(KERN_ERR "%s: No suitable PCI mapping available.\n", + dev->name); + rc = -ENODEV; + goto err_out; + } + + if (pci_enable_device(pdev)) { + printk(KERN_ERR "lanstreamer: unable to enable pci device\n"); + rc=-EIO; + goto err_out; + } + + pci_set_master(pdev); + + pio_start = pci_resource_start(pdev, 0); + pio_end = pci_resource_end(pdev, 0); + pio_flags = pci_resource_flags(pdev, 0); + pio_len = pci_resource_len(pdev, 0); + + mmio_start = pci_resource_start(pdev, 1); + mmio_end = pci_resource_end(pdev, 1); + mmio_flags = pci_resource_flags(pdev, 1); + mmio_len = pci_resource_len(pdev, 1); + #if STREAMER_DEBUG - printk("lanstreamer: pio_start %x pio_end %x pio_len %x pio_flags %x\n", - pio_start, pio_end, pio_len, pio_flags); - printk("lanstreamer: mmio_start %x mmio_end %x mmio_len %x mmio_flags %x\n", - mmio_start, mmio_end, mmio_flags, mmio_len); -#endif - - if (!request_region(pio_start, pio_len, "lanstreamer")) { - printk(KERN_ERR "lanstreamer: unable to get pci io addr %x\n",pio_start); - rc= -EBUSY; - goto err_out; - } - - if (!request_mem_region(mmio_start, mmio_len, "lanstreamer")) { - printk(KERN_ERR "lanstreamer: unable to get pci mmio addr %x\n",mmio_start); - rc= -EBUSY; - goto err_out_free_pio; - } - - streamer_priv->streamer_mmio=ioremap(mmio_start, mmio_len); - if (streamer_priv->streamer_mmio == NULL) { - printk(KERN_ERR "lanstreamer: unable to remap MMIO %x\n",mmio_start); - rc= -EIO; - goto err_out_free_mmio; - } + printk("lanstreamer: pio_start %x pio_end %x pio_len %x pio_flags %x\n", + pio_start, pio_end, pio_len, pio_flags); + printk("lanstreamer: mmio_start %x mmio_end %x mmio_len %x mmio_flags %x\n", + mmio_start, mmio_end, mmio_flags, mmio_len); +#endif + + if (!request_region(pio_start, pio_len, "lanstreamer")) { + printk(KERN_ERR "lanstreamer: unable to get pci io addr %lx\n", + pio_start); + rc= -EBUSY; + goto err_out; + } - init_waitqueue_head(&streamer_priv->srb_wait); - init_waitqueue_head(&streamer_priv->trb_wait); + if (!request_mem_region(mmio_start, mmio_len, "lanstreamer")) { + printk(KERN_ERR "lanstreamer: unable to get pci mmio addr %lx\n", + mmio_start); + rc= -EBUSY; + goto err_out_free_pio; + } - dev->open = &streamer_open; - dev->hard_start_xmit = &streamer_xmit; - dev->change_mtu = &streamer_change_mtu; - dev->stop = &streamer_close; + streamer_priv->streamer_mmio=ioremap(mmio_start, mmio_len); + if (streamer_priv->streamer_mmio == NULL) { + printk(KERN_ERR "lanstreamer: unable to remap MMIO %lx\n", + mmio_start); + rc= -EIO; + goto err_out_free_mmio; + } + + init_waitqueue_head(&streamer_priv->srb_wait); + init_waitqueue_head(&streamer_priv->trb_wait); + + dev->open = &streamer_open; + dev->hard_start_xmit = &streamer_xmit; + dev->change_mtu = &streamer_change_mtu; + dev->stop = &streamer_close; #if STREAMER_IOCTL - dev->do_ioctl = &streamer_ioctl; + dev->do_ioctl = &streamer_ioctl; #else - dev->do_ioctl = NULL; + dev->do_ioctl = NULL; #endif - dev->set_multicast_list = &streamer_set_rx_mode; - dev->get_stats = &streamer_get_stats; - dev->set_mac_address = &streamer_set_mac_address; - dev->irq = pdev->irq; - dev->base_addr=pio_start; - - streamer_priv->streamer_card_name = (char *)pdev->resource[0].name; - streamer_priv->pci_dev=pdev; - - if ((pkt_buf_sz[card_no] < 100) || (pkt_buf_sz[card_no] > 18000)) - streamer_priv->pkt_buf_sz = PKT_BUF_SZ; - else - streamer_priv->pkt_buf_sz = pkt_buf_sz[card_no]; - - streamer_priv->streamer_ring_speed = ringspeed[card_no]; - streamer_priv->streamer_message_level = message_level[card_no]; - - pci_set_drvdata(pdev, dev); - - spin_lock_init(&streamer_priv->streamer_lock); - - pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cls); - cls <<= 2; - if (cls != SMP_CACHE_BYTES) { - printk(KERN_INFO " PCI cache line size set incorrectly " - "(%i bytes) by BIOS/FW, ", cls); - if (cls > SMP_CACHE_BYTES) - printk("expecting %i\n", SMP_CACHE_BYTES); - else { - printk("correcting to %i\n", SMP_CACHE_BYTES); - pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, - SMP_CACHE_BYTES >> 2); - } - } - - pci_read_config_word (pdev, PCI_COMMAND, &pcr); - - pcr |= (PCI_COMMAND_INVALIDATE | PCI_COMMAND_SERR); - - pci_write_config_word (pdev, PCI_COMMAND, pcr); - pci_read_config_word (pdev, PCI_COMMAND, &pcr); - - printk("%s \n", version); - printk("%s: %s. I/O at %hx, MMIO at %p, using irq %d\n",dev->name, - streamer_priv->streamer_card_name, - (unsigned int) dev->base_addr, - streamer_priv->streamer_mmio, - dev->irq); - - if (!streamer_reset(dev)) { - return 0; - } + dev->set_multicast_list = &streamer_set_rx_mode; + dev->get_stats = &streamer_get_stats; + dev->set_mac_address = &streamer_set_mac_address; + dev->irq = pdev->irq; + dev->base_addr=pio_start; + + streamer_priv->streamer_card_name = (char *)pdev->resource[0].name; + streamer_priv->pci_dev = pdev; + + if ((pkt_buf_sz[card_no] < 100) || (pkt_buf_sz[card_no] > 18000)) + streamer_priv->pkt_buf_sz = PKT_BUF_SZ; + else + streamer_priv->pkt_buf_sz = pkt_buf_sz[card_no]; + + streamer_priv->streamer_ring_speed = ringspeed[card_no]; + streamer_priv->streamer_message_level = message_level[card_no]; + + pci_set_drvdata(pdev, dev); + + spin_lock_init(&streamer_priv->streamer_lock); + + pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &cls); + cls <<= 2; + if (cls != SMP_CACHE_BYTES) { + printk(KERN_INFO " PCI cache line size set incorrectly " + "(%i bytes) by BIOS/FW, ", cls); + if (cls > SMP_CACHE_BYTES) + printk("expecting %i\n", SMP_CACHE_BYTES); + else { + printk("correcting to %i\n", SMP_CACHE_BYTES); + pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, + SMP_CACHE_BYTES >> 2); + } + } + + pci_read_config_word (pdev, PCI_COMMAND, &pcr); + + pcr |= (PCI_COMMAND_INVALIDATE | PCI_COMMAND_SERR); + + pci_write_config_word (pdev, PCI_COMMAND, pcr); + pci_read_config_word (pdev, PCI_COMMAND, &pcr); - iounmap(streamer_priv->streamer_mmio); + printk("%s \n", version); + printk("%s: %s. I/O at %hx, MMIO at %p, using irq %d\n",dev->name, + streamer_priv->streamer_card_name, + (unsigned int) dev->base_addr, + streamer_priv->streamer_mmio, + dev->irq); + + if (streamer_reset(dev)) + goto err_out_unmap; + + rc = register_netdev(dev); + if (rc) + goto err_out_unmap; + return 0; + +err_out_unmap: + iounmap(streamer_priv->streamer_mmio); err_out_free_mmio: - release_mem_region(mmio_start, mmio_len); + release_mem_region(mmio_start, mmio_len); err_out_free_pio: - release_region(pio_start, pio_len); + release_region(pio_start, pio_len); err_out: - unregister_trdev(dev); - kfree(dev); + kfree(dev); #if STREAMER_DEBUG - printk("lanstreamer: Exit error %x\n",rc); + printk("lanstreamer: Exit error %x\n",rc); #endif - return rc; + return rc; } -static void __devexit streamer_remove_one(struct pci_dev *pdev) { - struct net_device *dev=pci_get_drvdata(pdev); - struct streamer_private *streamer_priv; +static void __devexit streamer_remove_one(struct pci_dev *pdev) +{ + struct net_device *dev=pci_get_drvdata(pdev); + struct streamer_private *streamer_priv; #if STREAMER_DEBUG - printk("lanstreamer::streamer_remove_one entry pdev %p\n",pdev); + printk("lanstreamer::streamer_remove_one entry pdev %p\n",pdev); #endif - if (dev == NULL) { - printk(KERN_ERR "lanstreamer::streamer_remove_one, ERROR dev is NULL\n"); - return; - } + if (dev == NULL) { + printk(KERN_ERR "lanstreamer::streamer_remove_one, ERROR dev is NULL\n"); + return; + } - streamer_priv=dev->priv; - if (streamer_priv == NULL) { - printk(KERN_ERR "lanstreamer::streamer_remove_one, ERROR dev->priv is NULL\n"); - return; + streamer_priv=dev->priv; + if (streamer_priv == NULL) { + printk(KERN_ERR "lanstreamer::streamer_remove_one, ERROR dev->priv is NULL\n"); + return; } #if STREAMER_NETWORK_MONITOR #ifdef CONFIG_PROC_FS - { - struct streamer_private *slast; - struct streamer_private *scurrent; - if (streamer_priv == dev_streamer) { - dev_streamer=dev_streamer->next; - } else { - for(slast=scurrent=dev_streamer; dev_streamer; slast=scurrent, scurrent=scurrent->next) { - if (scurrent == streamer_priv) { - slast->next=scurrent->next; - break; - } - } - } - if (!dev_streamer) { - remove_proc_entry("net/streamer_tr", NULL); - } - } + { + struct streamer_private **p, **next; + + for (p = &dev_streamer; *p; p = next) { + next = &(*p)->next; + if (*p == streamer_priv) { + *p = *next; + break; + } + } + if (!dev_streamer) + remove_proc_entry("net/streamer_tr", NULL); + } #endif #endif - unregister_trdev(dev); - release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev,0)); - release_mem_region(pci_resource_start(pdev, 1), pci_resource_len(pdev,1)); - kfree(dev); - pci_set_drvdata(pdev, NULL); + unregister_netdev(dev); + /* shouldn't we do iounmap here? */ + release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev,0)); + release_mem_region(pci_resource_start(pdev, 1), pci_resource_len(pdev,1)); + kfree(dev); + pci_set_drvdata(pdev, NULL); } diff -Nru a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c --- a/drivers/net/tokenring/madgemc.c Mon Jun 9 23:16:19 2003 +++ b/drivers/net/tokenring/madgemc.c Mon Jun 9 23:16:19 2003 @@ -177,12 +177,14 @@ if (versionprinted++ == 0) printk("%s", version); - if ((dev = init_trdev(NULL, 0))==NULL) { + dev = alloc_trdev(0); + if (dev == NULL) { printk("madgemc: unable to allocate dev space\n"); if (madgemc_card_list) return 0; return -1; } + SET_MODULE_OWNER(dev); dev->dma = 0; @@ -195,7 +197,7 @@ card = kmalloc(sizeof(struct madgemc_card), GFP_KERNEL); if (card==NULL) { printk("madgemc: unable to allocate card struct\n"); - kfree(dev); /* release_trdev? */ + kfree(dev); if (madgemc_card_list) return 0; return -1; @@ -331,7 +333,7 @@ */ outb(0, dev->base_addr + MC_CONTROL_REG0); /* sanity */ madgemc_setsifsel(dev, 1); - if(request_irq(dev->irq, madgemc_interrupt, SA_SHIRQ, + if (request_irq(dev->irq, madgemc_interrupt, SA_SHIRQ, "madgemc", dev)) goto getout; @@ -382,33 +384,22 @@ dev->open = madgemc_open; dev->stop = madgemc_close; - - if (register_trdev(dev) == 0) { + + if (register_netdev(dev) == 0) { /* Enlist in the card list */ card->next = madgemc_card_list; madgemc_card_list = card; - } else { - printk("madgemc: register_trdev() returned non-zero.\n"); - release_region(dev->base_addr-MADGEMC_SIF_OFFSET, - MADGEMC_IO_EXTENT); - - kfree(card); - tmsdev_term(dev); - kfree(dev); - if (madgemc_card_list) - return 0; - return -1; + slot++; + continue; /* successful, try to find another */ } - - slot++; - continue; /* successful, try to find another */ + free_irq(dev->irq, dev); getout: release_region(dev->base_addr-MADGEMC_SIF_OFFSET, MADGEMC_IO_EXTENT); getout1: kfree(card); - kfree(dev); /* release_trdev? */ + kfree(dev); slot++; } @@ -779,7 +770,7 @@ while (madgemc_card_list) { dev = madgemc_card_list->dev; - unregister_trdev(dev); + unregister_netdev(dev); release_region(dev->base_addr-MADGEMC_SIF_OFFSET, MADGEMC_IO_EXTENT); free_irq(dev->irq, dev); tmsdev_term(dev); diff -Nru a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c --- a/drivers/net/tokenring/olympic.c Mon Jun 9 23:16:16 2003 +++ b/drivers/net/tokenring/olympic.c Mon Jun 9 23:16:16 2003 @@ -1773,7 +1773,7 @@ strcat(proc_name,dev->name) ; remove_proc_entry(proc_name,NULL); } - unregister_trdev(dev) ; + unregister_netdev(dev) ; iounmap(olympic_priv->olympic_mmio) ; iounmap(olympic_priv->olympic_lap) ; pci_release_regions(pdev) ; diff -Nru a/drivers/net/tokenring/proteon.c b/drivers/net/tokenring/proteon.c --- a/drivers/net/tokenring/proteon.c Mon Jun 9 23:16:19 2003 +++ b/drivers/net/tokenring/proteon.c Mon Jun 9 23:16:19 2003 @@ -121,6 +121,11 @@ int i,j; struct proteon_card *card; +#ifndef MODULE + netdev_boot_setup_check(dev); + tr_setup(dev); +#endif + SET_MODULE_OWNER(dev); if (!dev->base_addr) { @@ -158,20 +163,8 @@ if (versionprinted++ == 0) printk(KERN_DEBUG "%s", version); -#ifndef MODULE - dev = init_trdev(dev, 0); - if (!dev) - { - release_region(dev->base_addr, PROTEON_IO_EXTENT); - return -1; - } -#endif - if (tmsdev_init(dev, ISA_MAX_ADDRESS, NULL)) - { - release_region(dev->base_addr, PROTEON_IO_EXTENT); - return -1; - } + goto out4; dev->base_addr &= ~3; @@ -211,9 +204,7 @@ if(irqlist[j] == 0) { printk(KERN_INFO "%s: AutoSelect no IRQ available\n", dev->name); - release_region(dev->base_addr, PROTEON_IO_EXTENT); - tmsdev_term(dev); - return -1; + goto out3; } } else @@ -225,18 +216,14 @@ { printk(KERN_INFO "%s: Illegal IRQ %d specified\n", dev->name, dev->irq); - release_region(dev->base_addr, PROTEON_IO_EXTENT); - tmsdev_term(dev); - return -1; + goto out3; } if (request_irq(dev->irq, tms380tr_interrupt, 0, cardname, dev)) { printk(KERN_INFO "%s: Selected IRQ %d not available\n", dev->name, dev->irq); - release_region(dev->base_addr, PROTEON_IO_EXTENT); - tmsdev_term(dev); - return -1; + goto out3; } } @@ -252,10 +239,7 @@ if(dmalist[j] == 0) { printk(KERN_INFO "%s: AutoSelect no DMA available\n", dev->name); - release_region(dev->base_addr, PROTEON_IO_EXTENT); - free_irq(dev->irq, dev); - tmsdev_term(dev); - return -1; + goto out2; } } else @@ -267,52 +251,36 @@ { printk(KERN_INFO "%s: Illegal DMA %d specified\n", dev->name, dev->dma); - release_region(dev->base_addr, PROTEON_IO_EXTENT); - free_irq(dev->irq, dev); - tmsdev_term(dev); - return -1; + goto out2; } if (request_dma(dev->dma, cardname)) { printk(KERN_INFO "%s: Selected DMA %d not available\n", dev->name, dev->dma); - release_region(dev->base_addr, PROTEON_IO_EXTENT); - free_irq(dev->irq, dev); - tmsdev_term(dev); - return -1; + goto out2; } } printk(KERN_DEBUG "%s: IO: %#4lx IRQ: %d DMA: %d\n", dev->name, dev->base_addr, dev->irq, dev->dma); - if (register_trdev(dev) == 0) - { - /* Enlist in the card list */ - card = kmalloc(sizeof(struct proteon_card), GFP_KERNEL); - if (!card) { - unregister_trdev(dev); - release_region(dev->base_addr, PROTEON_IO_EXTENT); - free_irq(dev->irq, dev); - free_dma(dev->dma); - tmsdev_term(dev); - return -1; - } - card->next = proteon_card_list; - proteon_card_list = card; - card->dev = dev; - } - else - { - printk("KERN_INFO %s: register_trdev() returned non-zero.\n", dev->name); - release_region(dev->base_addr, PROTEON_IO_EXTENT); - free_irq(dev->irq, dev); - free_dma(dev->dma); - tmsdev_term(dev); - return -1; - } - + /* Enlist in the card list */ + card = kmalloc(sizeof(struct proteon_card), GFP_KERNEL); + if (!card) + goto out; + card->next = proteon_card_list; + proteon_card_list = card; + card->dev = dev; return 0; +out: + free_dma(dev->dma); +out2: + free_irq(dev->irq, dev); +out3: + tmsdev_term(dev); +out4: + release_region(dev->base_addr, PROTEON_IO_EXTENT); + return -1; } /* @@ -402,64 +370,51 @@ MODULE_PARM(irq, "1-" __MODULE_STRING(ISATR_MAX_ADAPTERS) "i"); MODULE_PARM(dma, "1-" __MODULE_STRING(ISATR_MAX_ADAPTERS) "i"); +static int __init setup_card(unsigned long io, unsigned irq, unsigned char dma) +{ + int res = -ENOMEM; + struct proteon_card *this_card; + struct net_device *dev = alloc_trdev(0); + + if (dev) { + dev->base_addr = io; + dev->irq = irq; + dev->dma = dma; + res = -ENODEV; + if (proteon_probe(dev) == 0) { + res = register_netdev(dev); + if (!res) + return 0; + release_region(dev->base_addr, PROTEON_IO_EXTENT); + free_irq(dev->irq, dev); + free_dma(dev->dma); + tmsdev_term(dev); + this_card = proteon_card_list; + proteon_card_list = this_card->next; + kfree(this_card); + } + kfree(dev); + } + return res; +} + int init_module(void) { int i, num; struct net_device *dev; num = 0; - if (io[0]) - { /* Only probe addresses from command line */ - dev = init_trdev(NULL, 0); - if (!dev) - return (-ENOMEM); - for (i = 0; i < ISATR_MAX_ADAPTERS; i++) - { - if (io[i] == 0) - continue; - - dev->base_addr = io[i]; - dev->irq = irq[i]; - dev->dma = dma[i]; - - if (!proteon_probe(dev)) - { + if (io[0]) { /* Only probe addresses from command line */ + for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { + if (io[i] && setup_card(io[i], irq[i], dma[i]) == 0) num++; - dev = init_trdev(NULL, 0); - if (!dev) - goto partial; - } } - unregister_netdev(dev); - kfree(dev); - } - else - { - dev = init_trdev(NULL, 0); - if (!dev) - return (-ENOMEM); - - for(i = 0; portlist[i]; i++) - { - if (num >= ISATR_MAX_ADAPTERS) - continue; - - dev->base_addr = portlist[i]; - dev->irq = irq[num]; - dev->dma = dma[num]; - - if (!proteon_probe(dev)) - { + } else { + for(i = 0; num < ISATR_MAX_ADAPTERS && portlist[i]; i++) { + if (setup_card(portlist[i], irq[i], dma[i])) num++; - dev = init_trdev(NULL, 0); - if (!dev) - goto partial; - } } - unregister_netdev(dev); - kfree(dev); } -partial: printk(KERN_NOTICE "proteon.c: %d cards found.\n", num); /* Probe for cards. */ if (num == 0) { diff -Nru a/drivers/net/tokenring/skisa.c b/drivers/net/tokenring/skisa.c --- a/drivers/net/tokenring/skisa.c Mon Jun 9 23:16:07 2003 +++ b/drivers/net/tokenring/skisa.c Mon Jun 9 23:16:07 2003 @@ -141,6 +141,11 @@ int i,j; struct sk_isa_card *card; +#ifndef MODULE + netdev_boot_setup_check(dev); + tr_setup(dev); +#endif + SET_MODULE_OWNER(dev); if (!dev->base_addr) { @@ -178,20 +183,8 @@ if (versionprinted++ == 0) printk(KERN_DEBUG "%s", version); -#ifndef MODULE - dev = init_trdev(dev, 0); - if (!dev) - { - release_region(dev->base_addr, SK_ISA_IO_EXTENT); - return -1; - } -#endif - if (tmsdev_init(dev, ISA_MAX_ADDRESS, NULL)) - { - release_region(dev->base_addr, SK_ISA_IO_EXTENT); - return -1; - } + goto out4; dev->base_addr &= ~3; @@ -231,9 +224,7 @@ if(irqlist[j] == 0) { printk(KERN_INFO "%s: AutoSelect no IRQ available\n", dev->name); - release_region(dev->base_addr, SK_ISA_IO_EXTENT); - tmsdev_term(dev); - return -1; + goto out3; } } else @@ -245,18 +236,14 @@ { printk(KERN_INFO "%s: Illegal IRQ %d specified\n", dev->name, dev->irq); - release_region(dev->base_addr, SK_ISA_IO_EXTENT); - tmsdev_term(dev); - return -1; + goto out3; } if (request_irq(dev->irq, tms380tr_interrupt, 0, isa_cardname, dev)) { printk(KERN_INFO "%s: Selected IRQ %d not available\n", dev->name, dev->irq); - release_region(dev->base_addr, SK_ISA_IO_EXTENT); - tmsdev_term(dev); - return -1; + goto out3; } } @@ -272,10 +259,7 @@ if(dmalist[j] == 0) { printk(KERN_INFO "%s: AutoSelect no DMA available\n", dev->name); - release_region(dev->base_addr, SK_ISA_IO_EXTENT); - free_irq(dev->irq, dev); - tmsdev_term(dev); - return -1; + goto out2; } } else @@ -287,52 +271,36 @@ { printk(KERN_INFO "%s: Illegal DMA %d specified\n", dev->name, dev->dma); - release_region(dev->base_addr, SK_ISA_IO_EXTENT); - free_irq(dev->irq, dev); - tmsdev_term(dev); - return -1; + goto out2; } if (request_dma(dev->dma, isa_cardname)) { printk(KERN_INFO "%s: Selected DMA %d not available\n", dev->name, dev->dma); - release_region(dev->base_addr, SK_ISA_IO_EXTENT); - free_irq(dev->irq, dev); - tmsdev_term(dev); - return -1; + goto out2; } } printk(KERN_DEBUG "%s: IO: %#4lx IRQ: %d DMA: %d\n", dev->name, dev->base_addr, dev->irq, dev->dma); - if (register_trdev(dev) == 0) - { - /* Enlist in the card list */ - card = kmalloc(sizeof(struct sk_isa_card), GFP_KERNEL); - if (!card) { - unregister_trdev(dev); - release_region(dev->base_addr, SK_ISA_IO_EXTENT); - free_irq(dev->irq, dev); - free_dma(dev->dma); - tmsdev_term(dev); - return -1; - } - card->next = sk_isa_card_list; - sk_isa_card_list = card; - card->dev = dev; - } - else - { - printk("KERN_INFO %s: register_trdev() returned non-zero.\n", dev->name); - release_region(dev->base_addr, SK_ISA_IO_EXTENT); - free_irq(dev->irq, dev); - free_dma(dev->dma); - tmsdev_term(dev); - return -1; - } - + /* Enlist in the card list */ + card = kmalloc(sizeof(struct sk_isa_card), GFP_KERNEL); + if (!card) + goto out; + card->next = sk_isa_card_list; + sk_isa_card_list = card; + card->dev = dev; return 0; +out: + free_dma(dev->dma); +out2: + free_irq(dev->irq, dev); +out3: + tmsdev_term(dev); +out4: + release_region(dev->base_addr, SK_ISA_IO_EXTENT); + return -1; } /* @@ -415,64 +383,51 @@ MODULE_PARM(irq, "1-" __MODULE_STRING(ISATR_MAX_ADAPTERS) "i"); MODULE_PARM(dma, "1-" __MODULE_STRING(ISATR_MAX_ADAPTERS) "i"); +static int __init setup_card(unsigned long io, unsigned irq, unsigned char dma) +{ + int res = -ENOMEM; + struct sk_isa_card *this_card; + struct net_device *dev = alloc_trdev(0); + + if (dev) { + dev->base_addr = io; + dev->irq = irq; + dev->dma = dma; + res = -ENODEV; + if (sk_isa_probe(dev) == 0) { + res = register_netdev(dev); + if (!res) + return 0; + release_region(dev->base_addr, SK_ISA_IO_EXTENT); + free_irq(dev->irq, dev); + free_dma(dev->dma); + tmsdev_term(dev); + this_card = sk_isa_card_list; + sk_isa_card_list = this_card->next; + kfree(this_card); + } + kfree(dev); + } + return res; +} + int init_module(void) { int i, num; struct net_device *dev; num = 0; - if (io[0]) - { /* Only probe addresses from command line */ - dev = init_trdev(NULL, 0); - if (!dev) - return (-ENOMEM); - for (i = 0; i < ISATR_MAX_ADAPTERS; i++) - { - if (io[i] == 0) - continue; - - dev->base_addr = io[i]; - dev->irq = irq[i]; - dev->dma = dma[i]; - - if (!sk_isa_probe(dev)) - { + if (io[0]) { /* Only probe addresses from command line */ + for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) { + if (io[i] && setup_card(io[i], irq[i], dma[i]) == 0) num++; - dev = init_trdev(NULL, 0); - if (!dev) - goto partial; - } } - unregister_netdev(dev); - kfree(dev); - } - else - { - dev = init_trdev(NULL, 0); - if (!dev) - return (-ENOMEM); - - for(i = 0; portlist[i]; i++) - { - if (num >= ISATR_MAX_ADAPTERS) - continue; - - dev->base_addr = portlist[i]; - dev->irq = irq[num]; - dev->dma = dma[num]; - - if (!sk_isa_probe(dev)) - { + } else { + for(i = 0; num < ISATR_MAX_ADAPTERS && portlist[i]; i++) { + if (setup_card(portlist[i], irq[i], dma[i])) num++; - dev = init_trdev(NULL, 0); - if (!dev) - goto partial; - } } - unregister_netdev(dev); - kfree(dev); } -partial: printk(KERN_NOTICE "skisa.c: %d cards found.\n", num); /* Probe for cards. */ if (num == 0) { diff -Nru a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c --- a/drivers/net/tokenring/smctr.c Mon Jun 9 23:16:12 2003 +++ b/drivers/net/tokenring/smctr.c Mon Jun 9 23:16:12 2003 @@ -143,7 +143,6 @@ /* I */ static int smctr_init_acbs(struct net_device *dev); static int smctr_init_adapter(struct net_device *dev); -static int __init smctr_init_card(struct net_device *dev); static int smctr_init_card_real(struct net_device *dev); static int smctr_init_rx_bdbs(struct net_device *dev); static int smctr_init_rx_fcbs(struct net_device *dev); @@ -541,25 +540,18 @@ dev->irq = 15; break; } - if(request_irq(dev->irq, smctr_interrupt, SA_SHIRQ, smctr_name, dev)) - return (-ENODEV); + if (request_irq(dev->irq, smctr_interrupt, SA_SHIRQ, smctr_name, dev)) { + release_region(dev->base_addr, SMCTR_IO_EXTENT); + return -ENODEV; + } /* Get RAM base */ r3 = mca_read_stored_pos(tp->slot_num, 3); - if(r3 & 0x8) - { - if(r3 & 0x80) - tp->ram_base = ((__u32)(r3 & 0x7) << 13) + 0xFD0000; - else - tp->ram_base = ((__u32)(r3 & 0x7) << 13) + 0x0D0000; - } - else - { - if(r3 & 0x80) - tp->ram_base = ((__u32)(r3 & 0x7) << 13) + 0xFC0000; - else - tp->ram_base = ((__u32)(r3 & 0x7) << 13) + 0x0C0000; - } + tp->ram_base = ((__u32)(r3 & 0x7) << 13) + 0x0C0000; + if (r3 & 0x8) + tp->ram_base += 0x010000; + if (r3 & 0x80) + tp->ram_base += 0xF00000; /* Get Ram Size */ r3 &= 0x30; @@ -570,26 +562,24 @@ tp->board_id |= TOKEN_MEDIA; r4 = mca_read_stored_pos(tp->slot_num, 4); - if(r4 & 0x8) - tp->rom_base = ((__u32)(r4 & 0x7) << 13) + 0xD0000; - else - tp->rom_base = ((__u32)(r4 & 0x7) << 13) + 0xC0000; + tp->rom_base = ((__u32)(r4 & 0x7) << 13) + 0x0C0000; + if (r4 & 0x8) + tp->rom_base += 0x010000; /* Get ROM size. */ r4 >>= 4; - if(r4 == 0) - tp->rom_size = CNFG_SIZE_8KB; - else - { - if(r4 == 1) + switch (r4) { + case 0: + tp->rom_size = CNFG_SIZE_8KB; + break; + case 1: tp->rom_size = CNFG_SIZE_16KB; - else - { - if(r4 == 2) - tp->rom_size = CNFG_SIZE_32KB; - else - tp->rom_size = ROM_DISABLE; - } + break; + case 2: + tp->rom_size = CNFG_SIZE_32KB; + break; + default: + tp->rom_size = ROM_DISABLE; } /* Get Media Type. */ @@ -953,12 +943,19 @@ __u8 r1, r2, b, chksum = 0; __u16 r; int i; + int err = -ENODEV; if(smctr_debug > 10) printk(KERN_DEBUG "%s: smctr_chk_isa %#4x\n", dev->name, ioaddr); if((ioaddr & 0x1F) != 0) - return (-ENODEV); + goto out; + + /* Grab the region so that no one else tries to probe our ioports. */ + if (!request_region(ioaddr, SMCTR_IO_EXTENT, smctr_name)) { + err = -EBUSY; + goto out; + } /* Checksum SMC node address */ for(i = 0; i < 8; i++) @@ -967,17 +964,14 @@ chksum += b; } - if(chksum != NODE_ADDR_CKSUM) - return (-ENODEV); /* Adapter Not Found */ - - /* Grab the region so that no one else tries to probe our ioports. */ - request_region(ioaddr, SMCTR_IO_EXTENT, smctr_name); + if (chksum != NODE_ADDR_CKSUM) + goto out2; b = inb(ioaddr + BDID); if(b != BRD_ID_8115T) { printk(KERN_ERR "%s: The adapter found is not supported\n", dev->name); - return (-1); + goto out2; } /* Check for 8115T Board ID */ @@ -990,7 +984,7 @@ /* value of RegF adds up the sum to 0xFF */ if((r2 != 0xFF) && (r2 != 0xEE)) - return (-1); + goto out2; /* Get adapter ID */ tp->board_id = smctr_get_boardid(dev, 0); @@ -1077,11 +1071,11 @@ default: printk(KERN_ERR "%s: No IRQ found aborting\n", dev->name); - return(-1); + goto out2; } - if(request_irq(dev->irq, smctr_interrupt, SA_SHIRQ, smctr_name, dev)) - return (-ENODEV); + if (request_irq(dev->irq, smctr_interrupt, SA_SHIRQ, smctr_name, dev)) + goto out2; /* Get 58x Rom Base */ r1 = inb(ioaddr + CNFG_BIO_583); @@ -1157,12 +1151,18 @@ if(smctr_read_584_chksum(ioaddr)) { printk(KERN_ERR "%s: EEPROM Checksum Failure\n", dev->name); - return(-1); + goto out3; } */ } return (0); +out3: + free_irq(dev->irq, dev); +out2: + release_region(ioaddr, SMCTR_IO_EXTENT); +out: + return err; } static int __init smctr_get_boardid(struct net_device *dev, int mca) @@ -1650,15 +1650,6 @@ return (0); } -/* Dummy function */ -static int __init smctr_init_card(struct net_device *dev) -{ - if(smctr_debug > 10) - printk(KERN_DEBUG "%s: smctr_init_card\n", dev->name); - - return (0); -} - static int smctr_init_card_real(struct net_device *dev) { struct net_local *tp = (struct net_local *)dev->priv; @@ -3608,8 +3599,14 @@ int __init smctr_probe (struct net_device *dev) { int i; - int base_addr = dev ? dev->base_addr : 0; + int base_addr; + +#ifndef MODULE + netdev_boot_setup_check(dev); + tr_setup(dev); +#endif + base_addr = dev->base_addr; if(base_addr > 0x1ff) /* Check a single specified location. */ return (smctr_probe1(dev, base_addr)); else if(base_addr != 0) /* Don't probe at all. */ @@ -3618,8 +3615,6 @@ for(i = 0; smctr_portlist[i]; i++) { int ioaddr = smctr_portlist[i]; - if(check_region(ioaddr, SMCTR_IO_EXTENT)) - continue; if (!smctr_probe1(dev, ioaddr)) return (0); } @@ -3627,6 +3622,20 @@ return (-ENODEV); } +static void cleanup_card(struct net_device *dev) +{ +#ifdef CONFIG_MCA + struct net_local *tp = (struct net_local *)dev->priv; + if (tp->slot_num) + mca_mark_as_unused(tp->slot_num); +#endif + release_region(dev->base_addr, SMCTR_IO_EXTENT); + if (dev->irq) + free_irq(dev->irq, dev); + if (dev->priv) + kfree(dev->priv); +} + static int __init smctr_probe1(struct net_device *dev, int ioaddr) { static unsigned version_printed; @@ -3637,12 +3646,6 @@ if(smctr_debug && version_printed++ == 0) printk(version); -#ifndef MODULE - dev = init_trdev(dev, 0); - if(dev == NULL) - return (-ENOMEM); -#endif - /* Setup this devices private information structure */ tp = (struct net_local *)kmalloc(sizeof(struct net_local), GFP_KERNEL); @@ -3677,8 +3680,9 @@ if(err != UCODE_PRESENT && err != SUCCESS) { printk(KERN_ERR "%s: Firmware load failed (%d)\n", dev->name, err); + cleanup_card(dev); err = -EIO; - goto out_tp; + goto out; } /* Allow user to specify ring speed on module insert. */ @@ -3692,8 +3696,6 @@ (unsigned int)dev->base_addr, dev->irq, tp->rom_base, tp->ram_base); - /* AKPM: there's no point in this */ - dev->init = smctr_init_card; dev->open = smctr_open; dev->stop = smctr_close; dev->hard_start_xmit = smctr_send_packet; @@ -5689,33 +5691,31 @@ { int i; - for(i = 0; i < SMCTR_MAX_ADAPTERS; i++) - { + for(i = 0; i < SMCTR_MAX_ADAPTERS; i++) { + struct net_device *dev = alloc_trdev(0); irq[i] = 0; mem[i] = 0; - dev_smctr[i] = NULL; - dev_smctr[i] = init_trdev(dev_smctr[i], 0); - if(dev_smctr[i] == NULL) - return (-ENOMEM); - - dev_smctr[i]->base_addr = io[i]; - dev_smctr[i]->irq = irq[i]; - dev_smctr[i]->mem_start = mem[i]; - dev_smctr[i]->init = &smctr_probe; - - if(register_trdev(dev_smctr[i]) != 0) - { - kfree(dev_smctr[i]); - dev_smctr[i] = NULL; - if(i == 0) - { - printk(KERN_ERR "%s: register_trdev() returned (<0).\n", + if (!dev) + return -ENOMEM; + dev->base_addr = io[i]; + dev->irq = irq[i]; + dev->mem_start = mem[i]; + + if (smctr_probe(dev) != 0) { + kfree(dev); + if (i == 0) { + printk(KERN_ERR "%s: smctr_probe failed.\n", cardname); - return (-EIO); + return -EIO; } - else - return (0); + return 0; } + if (register_netdev(dev) != 0) { + cleanup_card(dev); + kfree(dev); + continue; + } + dev_smctr[i] = dev; } return (0); @@ -5725,26 +5725,13 @@ { int i; - for(i = 0; i < SMCTR_MAX_ADAPTERS; i++) - { - if(dev_smctr[i]) - { -#ifdef CONFIG_MCA - struct net_local *tp - = (struct net_local *)dev_smctr[i]->priv; - if(tp->slot_num) - mca_mark_as_unused(tp->slot_num); -#endif - unregister_trdev(dev_smctr[i]); - release_region(dev_smctr[i]->base_addr, - SMCTR_IO_EXTENT); - if(dev_smctr[i]->irq) - free_irq(dev_smctr[i]->irq, dev_smctr[i]); - if(dev_smctr[i]->priv) - kfree(dev_smctr[i]->priv); - kfree(dev_smctr[i]); - dev_smctr[i] = NULL; - } + for(i = 0; i < SMCTR_MAX_ADAPTERS; i++) { + struct net_device *dev = dev_smctr[i]; + if (dev) { + unregister_netdev(dev); + cleanup_card(dev); + kfree(dev); + } } } #endif /* MODULE */ diff -Nru a/drivers/net/tokenring/tmspci.c b/drivers/net/tokenring/tmspci.c --- a/drivers/net/tokenring/tmspci.c Mon Jun 9 23:16:18 2003 +++ b/drivers/net/tokenring/tmspci.c Mon Jun 9 23:16:18 2003 @@ -112,11 +112,11 @@ pci_ioaddr = pci_resource_start (pdev, 0); /* At this point we have found a valid card. */ - dev = init_trdev(NULL, 0); + dev = alloc_trdev(0); if (!dev) return -ENOMEM; SET_MODULE_OWNER(dev); - + if (!request_region(pci_ioaddr, TMS_PCI_IO_EXTENT, dev->name)) { ret = -EBUSY; goto err_out_trdev; @@ -163,22 +163,22 @@ dev->open = tms380tr_open; dev->stop = tms380tr_close; + pci_set_drvdata(pdev, dev); - ret = register_trdev(dev); + ret = register_netdev(dev); if (ret) goto err_out_tmsdev; - pci_set_drvdata(pdev, dev); return 0; err_out_tmsdev: + pci_set_drvdata(pdev, NULL); tmsdev_term(dev); err_out_irq: free_irq(pdev->irq, dev); err_out_region: release_region(pci_ioaddr, TMS_PCI_IO_EXTENT); err_out_trdev: - unregister_netdev(dev); kfree(dev); return ret; } diff -Nru a/drivers/net/tun.c b/drivers/net/tun.c --- a/drivers/net/tun.c Mon Jun 9 23:16:11 2003 +++ b/drivers/net/tun.c Mon Jun 9 23:16:11 2003 @@ -551,10 +551,12 @@ if (!(tun->flags & TUN_PERSIST)) { dev_close(&tun->dev); unregister_netdevice(&tun->dev); - kfree(tun); } rtnl_unlock(); + + if (!(tun->flags & TUN_PERSIST)) + kfree(tun); return 0; } diff -Nru a/drivers/net/wan/lmc/lmc_debug.c b/drivers/net/wan/lmc/lmc_debug.c --- a/drivers/net/wan/lmc/lmc_debug.c Mon Jun 9 23:16:09 2003 +++ b/drivers/net/wan/lmc/lmc_debug.c Mon Jun 9 23:16:09 2003 @@ -2,9 +2,7 @@ #include <linux/types.h> #include <linux/netdevice.h> #include <linux/interrupt.h> -#include <linux/version.h> -#include "lmc_ver.h" #include "lmc_debug.h" /* diff -Nru a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c --- a/drivers/net/wan/lmc/lmc_main.c Mon Jun 9 23:16:09 2003 +++ b/drivers/net/wan/lmc/lmc_main.c Mon Jun 9 23:16:09 2003 @@ -11,7 +11,7 @@ * With Help By: * David Boggs * Ron Crane - * Allan Cox + * Alan Cox * * This software may be used and distributed according to the terms * of the GNU General Public License version 2, incorporated herein by reference. @@ -38,7 +38,6 @@ /* $Id: lmc_main.c,v 1.36 2000/04/11 05:25:25 asj Exp $ */ -#include <linux/version.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/string.h> @@ -51,9 +50,6 @@ #include <linux/pci.h> #include <linux/delay.h> #include <linux/init.h> -#if LINUX_VERSION_CODE < 0x20155 -#include <linux/bios32.h> -#endif #include <linux/in.h> #include <linux/if_arp.h> #include <linux/netdevice.h> @@ -67,12 +63,8 @@ #include <asm/bitops.h> #include <asm/io.h> #include <asm/dma.h> -#if LINUX_VERSION_CODE >= 0x20200 #include <asm/uaccess.h> //#include <asm/spinlock.h> -#else /* 2.0 kernel */ -#define ARPHRD_HDLC 513 -#endif #define DRIVER_MAJOR_VERSION 1 #define DRIVER_MINOR_VERSION 34 @@ -80,7 +72,6 @@ #define DRIVER_VERSION ((DRIVER_MAJOR_VERSION << 8) + DRIVER_MINOR_VERSION) -#include "lmc_ver.h" #include "lmc.h" #include "lmc_var.h" #include "lmc_ioctl.h" @@ -127,10 +118,8 @@ static int lmc_init(struct net_device * const); static void lmc_reset(lmc_softc_t * const sc); static void lmc_dec_reset(lmc_softc_t * const sc); -#if LINUX_VERSION_CODE >= 0x20363 static void lmc_driver_timeout(struct net_device *dev); int lmc_setup(void); -#endif /* @@ -165,7 +154,8 @@ * To date internally, just copy this out to the user. */ case LMCIOCGINFO: /*fold01*/ - LMC_COPY_TO_USER(ifr->ifr_data, &sc->ictl, sizeof (lmc_ctl_t)); + if (copy_to_user(ifr->ifr_data, &sc->ictl, sizeof (lmc_ctl_t))) + return -EFAULT; ret = 0; break; @@ -181,7 +171,8 @@ break; } - LMC_COPY_FROM_USER(&ctl, ifr->ifr_data, sizeof (lmc_ctl_t)); + if (copy_from_user(&ctl, ifr->ifr_data, sizeof (lmc_ctl_t))) + return -EFAULT; sc->lmc_media->set_status (sc, &ctl); @@ -211,7 +202,8 @@ break; } - LMC_COPY_FROM_USER(&new_type, ifr->ifr_data, sizeof(u_int16_t)); + if (copy_from_user(&new_type, ifr->ifr_data, sizeof(u_int16_t))) + return -EFAULT; if (new_type == old_type) @@ -248,8 +240,9 @@ sc->lmc_xinfo.Magic1 = 0xDEADBEEF; - LMC_COPY_TO_USER(ifr->ifr_data, &sc->lmc_xinfo, - sizeof (struct lmc_xinfo)); + if (copy_to_user(ifr->ifr_data, &sc->lmc_xinfo, + sizeof (struct lmc_xinfo))) + return -EFAULT; ret = 0; break; @@ -279,8 +272,9 @@ regVal & T1FRAMER_SEF_MASK; } - LMC_COPY_TO_USER(ifr->ifr_data, &sc->stats, - sizeof (struct lmc_statistics)); + if (copy_to_user(ifr->ifr_data, &sc->stats, + sizeof (struct lmc_statistics))) + return -EFAULT; ret = 0; break; @@ -310,7 +304,8 @@ break; } - LMC_COPY_FROM_USER(&ctl, ifr->ifr_data, sizeof (lmc_ctl_t)); + if (copy_from_user(&ctl, ifr->ifr_data, sizeof (lmc_ctl_t))) + return -EFAULT; sc->lmc_media->set_circuit_type(sc, ctl.circuit_type); sc->ictl.circuit_type = ctl.circuit_type; ret = 0; @@ -335,8 +330,10 @@ #ifdef DEBUG case LMCIOCDUMPEVENTLOG: - LMC_COPY_TO_USER(ifr->ifr_data, &lmcEventLogIndex, sizeof (u32)); - LMC_COPY_TO_USER(ifr->ifr_data + sizeof (u32), lmcEventLogBuf, sizeof (lmcEventLogBuf)); + if (copy_to_user(ifr->ifr_data, &lmcEventLogIndex, sizeof (u32))) + return -EFAULT; + if (copy_to_user(ifr->ifr_data + sizeof (u32), lmcEventLogBuf, sizeof (lmcEventLogBuf))) + return -EFAULT; ret = 0; break; @@ -359,9 +356,10 @@ /* * Stop the xwitter whlie we restart the hardware */ - LMC_XMITTER_BUSY(dev); + netif_stop_queue(dev); - LMC_COPY_FROM_USER(&xc, ifr->ifr_data, sizeof (struct lmc_xilinx_control)); + if (copy_from_user(&xc, ifr->ifr_data, sizeof (struct lmc_xilinx_control))) + return -EFAULT; switch(xc.command){ case lmc_xilinx_reset: /*fold02*/ { @@ -620,7 +618,7 @@ break; } - LMC_XMITTER_FREE(dev); + netif_wake_queue(dev); sc->lmc_txfull = 0; } @@ -646,7 +644,7 @@ lmc_softc_t *sc; int link_status; u_int32_t ticks; - LMC_SPIN_FLAGS; + unsigned long flags; sc = dev->priv; @@ -836,11 +834,7 @@ * Allocate our own device structure */ -#if LINUX_VERSION_CODE < 0x20363 - dev = kmalloc (sizeof (struct ppp_device)+8, GFP_KERNEL); -#else dev = kmalloc (sizeof (struct net_device)+8, GFP_KERNEL); -#endif if (dev == NULL){ printk (KERN_ERR "lmc: kmalloc for device failed\n"); return NULL; @@ -909,10 +903,8 @@ dev->get_stats = lmc_get_stats; dev->do_ioctl = lmc_ioctl; dev->set_config = lmc_set_config; -#if LINUX_VERSION_CODE >= 0x20363 dev->tx_timeout = lmc_driver_timeout; dev->watchdog_timeo = (HZ); /* 1 second */ -#endif /* * Why were we changing this??? @@ -923,8 +915,6 @@ spin_lock_init(&sc->lmc_lock); - LMC_SETUP_20_DEV; - printk ("%s: detected at %lx, irq %d\n", dev->name, ioaddr, dev->irq); if (register_netdev (dev) != 0) { @@ -1048,7 +1038,7 @@ * PCI bus, we are in trouble. */ - if (!LMC_PCI_PRESENT()) { + if (!pci_present()) { /* printk ("%s: We really want a pci bios!\n", dev->name);*/ return -1; } @@ -1124,11 +1114,7 @@ if (cards_found < 1) return -1; -#if LINUX_VERSION_CODE >= 0x20200 return foundaddr; -#else - return 0; -#endif } /* After this is called, packets can be sent. @@ -1199,11 +1185,7 @@ dev->do_ioctl = lmc_ioctl; - LMC_XMITTER_INIT(dev); - -#if LINUX_VERSION_CODE < 0x20363 - dev->start = 1; -#endif + netif_start_queue(dev); sc->stats.tx_tbusy0++ ; @@ -1277,7 +1259,7 @@ //dev->flags |= IFF_RUNNING; - LMC_XMITTER_FREE(dev); + netif_wake_queue(dev); sc->lmc_txfull = 0; sc->stats.tx_tbusy0++ ; @@ -1327,7 +1309,7 @@ /* Don't let anything else go on right now */ // dev->start = 0; - LMC_XMITTER_BUSY(dev); + netif_stop_queue(dev); sc->stats.tx_tbusy1++ ; /* stop interrupts */ @@ -1360,23 +1342,20 @@ sc->lmc_rxring[i].length = 0; sc->lmc_rxring[i].buffer1 = 0xDEADBEEF; if (skb != NULL) - { - LMC_SKB_FREE(skb, 1); - LMC_DEV_KFREE_SKB (skb); - } + dev_kfree_skb(skb); sc->lmc_rxq[i] = NULL; } for (i = 0; i < LMC_TXDESCS; i++) { if (sc->lmc_txq[i] != NULL) - LMC_DEV_KFREE_SKB (sc->lmc_txq[i]); + dev_kfree_skb(sc->lmc_txq[i]); sc->lmc_txq[i] = NULL; } lmc_led_off (sc, LMC_MII16_LED_ALL); - LMC_XMITTER_FREE(dev); + netif_wake_queue(dev); sc->stats.tx_tbusy0++ ; lmc_trace(dev, "lmc_ifdown out"); @@ -1496,14 +1475,12 @@ } else { -#if LINUX_VERSION_CODE >= 0x20200 sc->stats.tx_bytes += sc->lmc_txring[i].length & 0x7ff; -#endif sc->stats.tx_packets++; } - // LMC_DEV_KFREE_SKB (sc->lmc_txq[i]); + // dev_kfree_skb(sc->lmc_txq[i]); dev_kfree_skb_irq(sc->lmc_txq[i]); sc->lmc_txq[i] = 0; @@ -1518,20 +1495,14 @@ } LMC_EVENT_LOG(LMC_EVENT_TBUSY0, n_compl, 0); sc->lmc_txfull = 0; - LMC_XMITTER_FREE(dev); + netif_wake_queue(dev); sc->stats.tx_tbusy0++ ; -#if LINUX_VERSION_CODE < 0x20363 - mark_bh (NET_BH); /* Tell Linux to give me more packets */ -#endif #ifdef DEBUG sc->stats.dirtyTx = badtx; sc->stats.lmc_next_tx = sc->lmc_next_tx; sc->stats.lmc_txfull = sc->lmc_txfull; -#if LINUX_VERSION_CODE < 0x20363 - sc->stats.tbusy = dev->tbusy; -#endif #endif sc->lmc_taint_tx = badtx; @@ -1592,7 +1563,7 @@ u32 flag; int entry; int ret = 0; - LMC_SPIN_FLAGS; + unsigned long flags; lmc_trace(dev, "lmc_start_xmit in"); @@ -1600,60 +1571,6 @@ spin_lock_irqsave(&sc->lmc_lock, flags); - /* - * If the transmitter is busy - * this must be the 5 second polling - * from the kernel which called us. - * Poke the chip and try to get it running - * - */ -#if LINUX_VERSION_CODE < 0x20363 - if(dev->tbusy != 0){ - u32 csr6; - - printk("%s: Xmitter busy|\n", dev->name); - - sc->stats.tx_tbusy_calls++ ; - if (jiffies - dev->trans_start < TX_TIMEOUT) { - ret = 1; - goto lmc_start_xmit_bug_out; - } - - /* - * Chip seems to have locked up - * Reset it - * This whips out all our decriptor - * table and starts from scartch - */ - - LMC_EVENT_LOG(LMC_EVENT_XMTPRCTMO, - LMC_CSR_READ (sc, csr_status), - sc->stats.tx_ProcTimeout); - - lmc_running_reset (dev); - - LMC_EVENT_LOG(LMC_EVENT_RESET1, LMC_CSR_READ (sc, csr_status), 0); - LMC_EVENT_LOG(LMC_EVENT_RESET2, - lmc_mii_readreg (sc, 0, 16), - lmc_mii_readreg (sc, 0, 17)); - - /* restart the tx processes */ - csr6 = LMC_CSR_READ (sc, csr_command); - LMC_CSR_WRITE (sc, csr_command, csr6 | 0x0002); - LMC_CSR_WRITE (sc, csr_command, csr6 | 0x2002); - - /* immediate transmit */ - LMC_CSR_WRITE (sc, csr_txpoll, 0); - - sc->stats.tx_errors++; - sc->stats.tx_ProcTimeout++; /* -baz */ - - dev->trans_start = jiffies; - - ret = 1; - goto lmc_start_xmit_bug_out; - } -#endif /* normal path, tbusy known to be zero */ entry = sc->lmc_next_tx % LMC_TXDESCS; @@ -1669,26 +1586,26 @@ { /* Do not interrupt on completion of this packet */ flag = 0x60000000; - LMC_XMITTER_FREE(dev); + netif_wake_queue(dev); } else if (sc->lmc_next_tx - sc->lmc_taint_tx == LMC_TXDESCS / 2) { /* This generates an interrupt on completion of this packet */ flag = 0xe0000000; - LMC_XMITTER_FREE(dev); + netif_wake_queue(dev); } else if (sc->lmc_next_tx - sc->lmc_taint_tx < LMC_TXDESCS - 1) { /* Do not interrupt on completion of this packet */ flag = 0x60000000; - LMC_XMITTER_FREE(dev); + netif_wake_queue(dev); } else { /* This generates an interrupt on completion of this packet */ flag = 0xe0000000; sc->lmc_txfull = 1; - LMC_XMITTER_BUSY(dev); + netif_stop_queue(dev); } #else flag = LMC_TDES_INTERRUPT_ON_COMPLETION; @@ -1696,7 +1613,7 @@ if (sc->lmc_next_tx - sc->lmc_taint_tx >= LMC_TXDESCS - 1) { /* ring full, go busy */ sc->lmc_txfull = 1; - LMC_XMITTER_BUSY(dev); + netif_stop_queue(dev); sc->stats.tx_tbusy1++ ; LMC_EVENT_LOG(LMC_EVENT_TBUSY1, entry, 0); } @@ -1726,10 +1643,6 @@ dev->trans_start = jiffies; -#if LINUX_VERSION_CODE < 0x20363 -lmc_start_xmit_bug_out: -#endif - spin_unlock_irqrestore(&sc->lmc_lock, flags); lmc_trace(dev, "lmc_start_xmit_out"); @@ -1815,7 +1728,6 @@ if(skb == 0x0){ nsb = dev_alloc_skb (LMC_PKT_BUF_SZ + 2); if (nsb) { - LMC_SKB_FREE(nsb, 1); sc->lmc_rxq[i] = nsb; nsb->dev = dev; sc->lmc_rxring[i].buffer1 = virt_to_bus (nsb->tail); @@ -1859,7 +1771,6 @@ */ nsb = dev_alloc_skb (LMC_PKT_BUF_SZ + 2); if (nsb) { - LMC_SKB_FREE(nsb, 1); sc->lmc_rxq[i] = nsb; nsb->dev = dev; sc->lmc_rxring[i].buffer1 = virt_to_bus (nsb->tail); @@ -1948,7 +1859,7 @@ static struct net_device_stats *lmc_get_stats (struct net_device *dev) /*fold00*/ { lmc_softc_t *sc; - LMC_SPIN_FLAGS; + unsigned long flags; lmc_trace(dev, "lmc_get_stats in"); @@ -1965,9 +1876,7 @@ return (struct net_device_stats *) &sc->stats; } -#ifdef MODULE - -int init_module (void) /*fold00*/ +static int __init init_lmc(void) { printk ("lmc: module loaded\n"); @@ -1978,7 +1887,7 @@ return 0; } -void cleanup_module (void) /*fold00*/ +static void __exit exit_lmc(void) { struct net_device *dev, *next; lmc_softc_t *sc; @@ -2020,7 +1929,9 @@ Lmc_root_dev = NULL; printk ("lmc module unloaded\n"); } -#endif + +module_init(init_lmc); +module_exit(exit_lmc); unsigned lmc_mii_readreg (lmc_softc_t * const sc, unsigned devaddr, unsigned regno) /*fold00*/ { @@ -2148,7 +2059,6 @@ } skb->dev = sc->lmc_device; - LMC_SKB_FREE(skb, 1); /* owned by 21140 */ sc->lmc_rxring[i].status = 0x80000000; @@ -2367,11 +2277,10 @@ lmc_trace(sc->lmc_device, "lmc_initcsrs out"); } -#if LINUX_VERSION_CODE >= 0x20363 static void lmc_driver_timeout(struct net_device *dev) { /*fold00*/ lmc_softc_t *sc; u32 csr6; - LMC_SPIN_FLAGS; + unsigned long flags; lmc_trace(dev, "lmc_driver_timeout in"); @@ -2430,4 +2339,3 @@ return lmc_probe(NULL); } -#endif diff -Nru a/drivers/net/wan/lmc/lmc_media.c b/drivers/net/wan/lmc/lmc_media.c --- a/drivers/net/wan/lmc/lmc_media.c Mon Jun 9 23:16:18 2003 +++ b/drivers/net/wan/lmc/lmc_media.c Mon Jun 9 23:16:18 2003 @@ -1,6 +1,5 @@ /* $Id: lmc_media.c,v 1.13 2000/04/11 05:25:26 asj Exp $ */ -#include <linux/version.h> #include <linux/config.h> #include <linux/kernel.h> #include <linux/string.h> @@ -11,9 +10,6 @@ #include <linux/slab.h> #include <linux/interrupt.h> #include <linux/pci.h> -#if LINUX_VERSION_CODE < 0x20155 -#include <linux/bios32.h> -#endif #include <linux/in.h> #include <linux/if_arp.h> #include <linux/netdevice.h> @@ -28,11 +24,8 @@ #include <asm/io.h> #include <asm/dma.h> -#if LINUX_VERSION_CODE >= 0x20200 #include <asm/uaccess.h> -#endif -#include "lmc_ver.h" #include "lmc.h" #include "lmc_var.h" #include "lmc_ioctl.h" diff -Nru a/drivers/net/wan/lmc/lmc_proto.c b/drivers/net/wan/lmc/lmc_proto.c --- a/drivers/net/wan/lmc/lmc_proto.c Mon Jun 9 23:16:13 2003 +++ b/drivers/net/wan/lmc/lmc_proto.c Mon Jun 9 23:16:13 2003 @@ -19,7 +19,6 @@ * Driver for the LanMedia LMC5200, LMC5245, LMC1000, LMC1200 cards. */ -#include <linux/version.h> #include <linux/kernel.h> #include <linux/string.h> #include <linux/timer.h> @@ -46,7 +45,6 @@ #include <asm/dma.h> #include <asm/smp.h> -#include "lmc_ver.h" #include "lmc.h" #include "lmc_var.h" #include "lmc_debug.h" @@ -66,14 +64,6 @@ #define SPPP_attach(d) (void)0 #define SPPP_do_ioctl(d,i,c) -EOPNOTSUPP #else -#if LINUX_VERSION_CODE < 0x20363 -#define SPPP_attach(x) sppp_attach((struct ppp_device *)(x)->lmc_device) -#define SPPP_detach(x) sppp_detach((x)->lmc_device) -#define SPPP_open(x) sppp_open((x)->lmc_device) -#define SPPP_reopen(x) sppp_reopen((x)->lmc_device) -#define SPPP_close(x) sppp_close((x)->lmc_device) -#define SPPP_do_ioctl(x, y, z) sppp_do_ioctl((x)->lmc_device, (y), (z)) -#else #define SPPP_attach(x) sppp_attach((x)->pd) #define SPPP_detach(x) sppp_detach((x)->pd->dev) #define SPPP_open(x) sppp_open((x)->pd->dev) @@ -81,7 +71,6 @@ #define SPPP_close(x) sppp_close((x)->pd->dev) #define SPPP_do_ioctl(x, y, z) sppp_do_ioctl((x)->pd->dev, (y), (z)) #endif -#endif // init void lmc_proto_init(lmc_softc_t *sc) /*FOLD00*/ @@ -89,15 +78,12 @@ lmc_trace(sc->lmc_device, "lmc_proto_init in"); switch(sc->if_type){ case LMC_PPP: - -#if LINUX_VERSION_CODE >= 0x20363 sc->pd = kmalloc(sizeof(struct ppp_device), GFP_KERNEL); if (!sc->pd) { printk("lmc_proto_init(): kmalloc failure!\n"); return; } sc->pd->dev = sc->lmc_device; -#endif sc->if_ptr = sc->pd; break; case LMC_RAW: diff -Nru a/drivers/net/wan/lmc/lmc_var.h b/drivers/net/wan/lmc/lmc_var.h --- a/drivers/net/wan/lmc/lmc_var.h Mon Jun 9 23:16:11 2003 +++ b/drivers/net/wan/lmc/lmc_var.h Mon Jun 9 23:16:11 2003 @@ -48,9 +48,6 @@ #define u_int16_t u16 #define u_int8_t u8 #define tulip_uint32_t u32 -#if LINUX_VERSION_CODE < 0x20155 -#define u_int32_t u32 -#endif #define LMC_REG_RANGE 0x80 @@ -410,9 +407,7 @@ u32 last_int; u32 num_int; -#if LINUX_VERSION_CODE >= 0x20200 spinlock_t lmc_lock; -#endif u_int16_t if_type; /* PPP or NET */ struct ppp_device *pd; @@ -549,10 +544,6 @@ #define LMC_CRC_LEN_16 2 /* 16-bit CRC */ #define LMC_CRC_LEN_32 4 - -#if LINUX_VERSION_CODE < 0x20100 -#define test_and_set_bit(val, addr) set_bit(val, addr) -#endif #ifdef LMC_HDLC /* definition of an hdlc header. */ diff -Nru a/drivers/net/wan/pc300_tty.c b/drivers/net/wan/pc300_tty.c --- a/drivers/net/wan/pc300_tty.c Mon Jun 9 23:16:10 2003 +++ b/drivers/net/wan/pc300_tty.c Mon Jun 9 23:16:10 2003 @@ -113,7 +113,7 @@ static struct tty_struct *cpc_tty_serial_table[CPC_TTY_NPORTS]; static struct termios *cpc_tty_serial_termios[CPC_TTY_NPORTS]; static struct termios *cpc_tty_serial_termios_locked[CPC_TTY_NPORTS]; -static struct tty_driver serial_drv, callout_drv; +static struct tty_driver serial_drv; /* local variables */ st_cpc_tty_area cpc_tty_area[CPC_TTY_NPORTS]; @@ -244,15 +244,6 @@ serial_drv.flush_buffer = cpc_tty_flush_buffer; serial_drv.hangup = cpc_tty_hangup; - /* the callout device is just like normal device except for major */ - /* number and the subtype code */ - callout_drv = serial_drv; - callout_drv.name = "cucp"; - callout_drv.major = CPC_TTY_MAJOR + 1; - callout_drv.subtype = SERIAL_TYPE_CALLOUT; - callout_drv.read_proc = 0; - callout_drv.proc_entry = 0; - /* register the TTY driver */ if (tty_register_driver(&serial_drv)) { printk("%s-tty: Failed to register serial driver! ", @@ -260,11 +251,6 @@ return; } - if (tty_register_driver(&callout_drv)) { - CPC_TTY_DBG("%s-tty: Failed to register callout driver! ", - ((struct net_device*)(pc300dev->hdlc))->name); - return; - } memset((void *)cpc_tty_area, 0, sizeof(st_cpc_tty_area) * CPC_TTY_NPORTS); } @@ -436,10 +422,6 @@ CPC_TTY_DBG("%s: ERROR ->unregister the tty driver error=%d\n", cpc_tty->name,res); } - if ((res=tty_unregister_driver(&callout_drv))) { - CPC_TTY_DBG("%s: ERROR ->unregister the tty driver error=%d\n", - cpc_tty->name,res); - } } return; } @@ -688,10 +670,6 @@ CPC_TTY_DBG("%s: ERROR ->unregister the tty driver error=%d\n", cpc_tty->name,res); } - if ((res=tty_unregister_driver(&callout_drv))) { - CPC_TTY_DBG("%s: ERROR ->unregister the tty driver error=%d\n", - cpc_tty->name,res); - } } cpc_tty_dtr_off(cpc_tty->pc300dev); } @@ -1092,10 +1070,6 @@ CPC_TTY_DBG("%s: ERROR ->unregister the tty driver error=%d\n", cpc_tty->name,res); } - if ((res=tty_unregister_driver(&callout_drv))) { - CPC_TTY_DBG("%s: ERROR ->unregister the tty driver error=%d\n", - cpc_tty->name,res); - } } } CPC_TTY_LOCK(pc300dev->chan->card,flags); @@ -1130,7 +1104,6 @@ CPC_TTY_DBG("hdlcX-tty: reset variables\n"); /* reset the tty_driver structure - serial_drv */ memset(&serial_drv, 0, sizeof(struct tty_driver)); - memset(&callout_drv, 0, sizeof(struct tty_driver)); for (i=0; i < CPC_TTY_NPORTS; i++){ memset(&cpc_tty_area[i],0, sizeof(st_cpc_tty_area)); } diff -Nru a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c --- a/drivers/net/wan/sdla.c Mon Jun 9 23:16:20 2003 +++ b/drivers/net/wan/sdla.c Mon Jun 9 23:16:20 2003 @@ -1667,25 +1667,31 @@ .name = "sdla0", .init = sdla_init }; +#endif /* MODULE */ -MODULE_LICENSE("GPL"); - -int init_module(void) +static int __init init_sdla(void) { - int result; + int result = 0; sdla_c_setup(); - if ((result = register_netdev(&sdla0)) != 0) - return result; - return 0; +#ifdef MODULE + result = register_netdev(&sdla0); +#endif + return result; } -void cleanup_module(void) +static void __exit exit_sdla(void) { +#ifdef MODULE unregister_netdev(&sdla0); if (sdla0.priv) kfree(sdla0.priv); if (sdla0.irq) free_irq(sdla0.irq, &sdla0); +#endif } -#endif /* MODULE */ + +MODULE_LICENSE("GPL"); + +module_init(init_sdla); +module_exit(exit_sdla); diff -Nru a/drivers/net/wan/sdla_chdlc.c b/drivers/net/wan/sdla_chdlc.c --- a/drivers/net/wan/sdla_chdlc.c Mon Jun 9 23:16:12 2003 +++ b/drivers/net/wan/sdla_chdlc.c Mon Jun 9 23:16:12 2003 @@ -284,7 +284,7 @@ static void wanpipe_tty_receive(sdla_t *, unsigned, unsigned int); static void wanpipe_tty_trigger_poll(sdla_t *card); -static struct tty_driver serial_driver, callout_driver; +static struct tty_driver serial_driver; static int serial_refcount=1; static int tty_init_cnt=0; @@ -1056,15 +1056,12 @@ if (card->tty_opt){ struct serial_state * state; if (!(--tty_init_cnt)){ - int e1,e2; + int e1; *serial_driver.refcount=0; if ((e1 = tty_unregister_driver(&serial_driver))) printk("SERIAL: failed to unregister serial driver (%d)\n", e1); - if ((e2 = tty_unregister_driver(&callout_driver))) - printk("SERIAL: failed to unregister callout driver (%d)\n", - e2); printk(KERN_INFO "%s: Unregistering TTY Driver, Major %i\n", card->devname,WAN_TTY_MAJOR); } @@ -4444,27 +4441,10 @@ serial_driver.wait_until_sent = wanpipe_tty_wait_until_sent; serial_driver.read_proc = wanpipe_tty_read_proc; - /* - * The callout device is just like normal device except for - * major number and the subtype code. - */ - callout_driver = serial_driver; - callout_driver.name = "cuw"; - callout_driver.major = TTYAUX_MAJOR; - callout_driver.subtype = SERIAL_TYPE_CALLOUT; - callout_driver.read_proc = 0; - callout_driver.proc_entry = 0; - if (tty_register_driver(&serial_driver)){ printk(KERN_INFO "%s: Failed to register serial driver!\n", card->devname); } - - if (tty_register_driver(&callout_driver)){ - printk(KERN_INFO "%s: Failed to register callout driver!\n", - card->devname); - } - } @@ -4493,7 +4473,6 @@ state->custom_divisor = 0; state->close_delay = 5*HZ/10; state->closing_wait = 30*HZ; - state->callout_termios = callout_driver.init_termios; state->normal_termios = serial_driver.init_termios; state->icount.cts = state->icount.dsr = state->icount.rng = state->icount.dcd = 0; diff -Nru a/drivers/net/wan/z85230.h b/drivers/net/wan/z85230.h --- a/drivers/net/wan/z85230.h Mon Jun 9 23:16:15 2003 +++ b/drivers/net/wan/z85230.h Mon Jun 9 23:16:15 2003 @@ -334,14 +334,11 @@ struct tty_struct *tty; /* Attached terminal */ int line; /* Minor number */ struct termios normal_termios; /* Terminal settings */ - struct termios callout_termios; wait_queue_head_t open_wait; /* Tasks waiting to open */ wait_queue_head_t close_wait; /* and for close to end */ unsigned long event; /* Pending events */ int fdcount; /* # of fd on device */ int blocked_open; /* # of blocked opens */ - long session; /* Session of opening process */ - long pgrp; /* pgrp of opening process */ int x_char; /* XON/XOF char */ unsigned char *xmit_buf; /* Transmit pointer */ int xmit_head; /* Transmit ring */ diff -Nru a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig --- a/drivers/net/wireless/Kconfig Mon Jun 9 23:16:08 2003 +++ b/drivers/net/wireless/Kconfig Mon Jun 9 23:16:08 2003 @@ -149,7 +149,7 @@ unsure, say N. comment "Wireless 802.11b ISA/PCI cards support" - depends on NET_RADIO && (ISA || PCI || ALL_PPC || PCMCIA) + depends on NET_RADIO && (ISA || PCI || PPC_PMAC || PCMCIA) config AIRO tristate "Cisco/Aironet 34X/35X/4500/4800 ISA and PCI cards" @@ -169,7 +169,7 @@ config HERMES tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)" - depends on NET_RADIO && (ALL_PPC || PCI || PCMCIA) + depends on NET_RADIO && (PPC_PMAC || PCI || PCMCIA) ---help--- A driver for 802.11b wireless cards based based on the "Hermes" or Intersil HFA384x (Prism 2) MAC controller. This includes the vast @@ -191,7 +191,7 @@ config APPLE_AIRPORT tristate "Apple Airport support (built-in)" - depends on ALL_PPC && HERMES + depends on PPC_PMAC && HERMES help Say Y here to support the Airport 802.11b wireless Ethernet hardware built into the Macintosh iBook and other recent PowerPC-based @@ -203,7 +203,7 @@ depends on PCI && HERMES && EXPERIMENTAL help Enable support for PCMCIA cards supported by the "Hermes" (aka - orinoco_cs) driver when used in PLX9052 based PCI adaptors. These + orinoco) 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 @@ -212,6 +212,19 @@ Support for these adaptors is so far still incomplete and buggy. You have been warned. +config TMD_HERMES + tristate "Hermes in TMD7160 based PCI adaptor support (EXPERIMENTAL)" + depends on PCI && HERMES && EXPERIMENTAL + help + Enable support for PCMCIA cards supported by the "Hermes" (aka + orinoco) driver when used in TMD7160 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. + + Support for these adaptors is so far still incomplete and buggy. + You have been warned. + config PCI_HERMES tristate "Prism 2.5 PCI 802.11b adaptor support (EXPERIMENTAL)" depends on PCI && HERMES && EXPERIMENTAL @@ -268,10 +281,25 @@ for location). You also want to check out the PCMCIA-HOWTO, available from <http://www.tldp.org/docs.html#howto>. +config PCMCIA_ATMEL + tristate "Atmel at76c502/at76c504 PCMCIA cards" + depends on NET_RADIO && EXPERIMENTAL && PCMCIA + ---help--- + A driver for PCMCIA 802.11 wireless cards based on the + Atmel fast-vnet chips. This driver supports standard + Linux wireless extensions. + + Many cards based on this chipset do not have flash memory + and need their firmware loaded at start-up. If yours is + one of these, you will need to provide a firmware image + to be loaded into the card by the driver. The Atmel + firmware package can be downloaded from + http://www.thekelleys.org.uk/atmel/atmel_firmware.tar.gz + # yes, this works even when no drivers are selected config NET_WIRELESS bool - depends on NET_RADIO && (ISA || PCI || ALL_PPC || PCMCIA) + depends on NET_RADIO && (ISA || PCI || PPC_PMAC || PCMCIA) default y endmenu diff -Nru a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile --- a/drivers/net/wireless/Makefile Mon Jun 9 23:16:20 2003 +++ b/drivers/net/wireless/Makefile Mon Jun 9 23:16:20 2003 @@ -15,10 +15,12 @@ obj-$(CONFIG_APPLE_AIRPORT) += airport.o obj-$(CONFIG_PLX_HERMES) += orinoco_plx.o obj-$(CONFIG_PCI_HERMES) += orinoco_pci.o +obj-$(CONFIG_TMD_HERMES) += orinoco_tmd.o obj-$(CONFIG_AIRO) += airo.o obj-$(CONFIG_AIRO_CS) += airo_cs.o airo.o # 16-bit wireless PCMCIA client drivers obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o +obj-$(CONFIG_PCMCIA_ATMEL) += atmel_cs.o atmel.o diff -Nru a/drivers/net/wireless/airport.c b/drivers/net/wireless/airport.c --- a/drivers/net/wireless/airport.c Mon Jun 9 23:16:19 2003 +++ b/drivers/net/wireless/airport.c Mon Jun 9 23:16:19 2003 @@ -1,4 +1,4 @@ -/* airport.c 0.13a +/* airport.c 0.13e * * A driver for "Hermes" chipset based Apple Airport wireless * card. @@ -12,6 +12,7 @@ */ #include <linux/config.h> + #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> @@ -20,7 +21,6 @@ #include <linux/string.h> #include <linux/timer.h> #include <linux/ioport.h> -#include <linux/proc_fs.h> #include <linux/netdevice.h> #include <linux/if_arp.h> #include <linux/etherdevice.h> @@ -95,7 +95,7 @@ netif_device_detach(dev); - priv->hw_unavailable = 1; + priv->hw_unavailable++; orinoco_unlock(priv, &flags); @@ -121,14 +121,15 @@ netif_device_attach(dev); - if (priv->open) { + priv->hw_unavailable--; + + if (priv->open && (! priv->hw_unavailable)) { err = __orinoco_up(dev); if (err) printk(KERN_ERR "%s: Error %d restarting card on PBOOK_WAKE\n", dev->name, err); } - priv->hw_unavailable = 0; spin_unlock_irqrestore(&priv->lock, flags); @@ -138,6 +139,37 @@ } #endif /* CONFIG_PMAC_PBOOK */ +static int airport_hard_reset(struct orinoco_private *priv) +{ + /* It would be nice to power cycle the Airport for a real hard + * reset, but for some reason although it appears to + * re-initialize properly, it falls in a screaming heap + * shortly afterwards. */ +#if 0 + struct net_device *dev = priv->ndev; + struct airport *card = priv->card; + + /* Vitally important. If we don't do this it seems we get an + * interrupt somewhere during the power cycle, since + * hw_unavailable is already set it doesn't get ACKed, we get + * into an interrupt loop and the the PMU decides to turn us + * off. */ + disable_irq(dev->irq); + + pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ); + pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 1); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ); + + enable_irq(dev->irq); + schedule_timeout(HZ); +#endif + + return 0; +} + static struct net_device * airport_attach(struct device_node *of_node) { @@ -153,7 +185,7 @@ } /* Allocate space for private device-specific data */ - dev = alloc_orinocodev(sizeof(*card), NULL); + dev = alloc_orinocodev(sizeof(*card), airport_hard_reset); if (! dev) { printk(KERN_ERR "airport: can't allocate device datas\n"); return NULL; @@ -195,7 +227,7 @@ /* Reset it before we get the interrupt */ hermes_init(hw); - if (request_irq(dev->irq, orinoco_interrupt, 0, "Airport", (void *)priv)) { + if (request_irq(dev->irq, orinoco_interrupt, 0, "Airport", dev)) { printk(KERN_ERR "airport: Couldn't get IRQ %d\n", dev->irq); goto failed; } @@ -209,11 +241,6 @@ printk(KERN_DEBUG "airport: card registered for interface %s\n", dev->name); card->ndev_registered = 1; - /* And give us the proc nodes for debugging */ - if (orinoco_proc_dev_init(dev) != 0) - printk(KERN_ERR "airport: Failed to create /proc node for %s\n", - dev->name); - #ifdef CONFIG_PMAC_PBOOK pmu_register_sleep_notifier(&airport_sleep_notifier); #endif @@ -234,9 +261,6 @@ struct orinoco_private *priv = dev->priv; struct airport *card = priv->card; - /* Unregister proc entry */ - orinoco_proc_dev_cleanup(dev); - #ifdef CONFIG_PMAC_PBOOK pmu_unregister_sleep_notifier(&airport_sleep_notifier); #endif @@ -245,7 +269,7 @@ card->ndev_registered = 0; if (card->irq_requested) - free_irq(dev->irq, priv); + free_irq(dev->irq, dev); card->irq_requested = 0; if (card->vaddr) @@ -263,7 +287,7 @@ kfree(dev); } /* airport_detach */ -static char version[] __initdata = "airport.c 0.13a (Benjamin Herrenschmidt <benh@kernel.crashing.org>)"; +static char version[] __initdata = "airport.c 0.13e (Benjamin Herrenschmidt <benh@kernel.crashing.org>)"; MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); MODULE_DESCRIPTION("Driver for the Apple Airport wireless card."); MODULE_LICENSE("Dual MPL/GPL"); diff -Nru a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atmel.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,3943 @@ +/*** -*- linux-c -*- ********************************************************** + + Driver for Atmel at76c502 at76c504 and at76c506 wireless cards. + + Copyright 2000-2001 ATMEL Corporation. + Copyright 2003 Simon Kelley. + + This code was developed from version 2.1.1 of the Atmel drivers, + released by Atmel corp. under the GPL in December 2002. It also + includes code from the Linux aironet drivers (C) Benjamin Reed, + and the Linux PCMCIA package, (C) David Hinds and the Linux wireless + extensions, (C) Jean Tourrilhes. + + The firmware module for reading the MAC address of the card comes from + net.russotto.AtmelMACFW, written by Matthew T. Russotto and copyright + by him. net.russotto.AtmelMACFW is used under the GPL license version 2. + This file contains the module in binary form and, under the terms + of the GPL, in source form. The source is located at the end of the file. + + For all queries about this code, please contact the current author, + Simon Kelley <simon@thekelleys.org.uk> and not Atmel 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 software 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 Atmel wireless lan drivers; 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/version.h> +#include <linux/init.h> + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/ptrace.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <asm/io.h> +#include <asm/system.h> +#include <asm/uaccess.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/etherdevice.h> +#include <linux/skbuff.h> +#include <linux/if_arp.h> +#include <linux/ioport.h> +#include <linux/fcntl.h> +#include <linux/delay.h> +#include <linux/wireless.h> +#include <net/iw_handler.h> +#include <linux/byteorder/generic.h> +#include <linux/crc32.h> +#include <linux/proc_fs.h> +#include <linux/device.h> +#include <linux/moduleparam.h> +#ifdef CONFIG_FW_LOADER +#include <linux/firmware.h> +#endif +#include "ieee802_11.h" + +#define DRIVER_MAJOR 0 +#define DRIVER_MINOR 7 + +MODULE_AUTHOR("Simon Kelley"); +MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethernet cards."); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("Atmel at76c50x wireless cards"); + +/* The name of the firmware file to be loaded + over-rides any automatic selection */ +static char *firmware = NULL; +module_param(firmware, charp, 0); + +#define MAX_SSID_LENGTH 32 +#define MGMT_JIFFIES (256 * HZ / 100) + +#define MAX_BSS_ENTRIES 64 + +/* registers */ +#define GCR 0x00 // (SIR0) General Configuration Register +#define BSR 0x02 // (SIR1) Bank Switching Select Register +#define AR 0x04 +#define DR 0x08 +#define MR1 0x12 // Mirror Register 1 +#define MR2 0x14 // Mirror Register 2 +#define MR3 0x16 // Mirror Register 3 +#define MR4 0x18 // Mirror Register 4 + +#define GPR1 0x0c +#define GPR2 0x0e +#define GPR3 0x10 +// +// Constants for the GCR register. +// +#define GCR_REMAP 0x0400 // Remap internal SRAM to 0 +#define GCR_SWRES 0x0080 // BIU reset (ARM and PAI are NOT reset) +#define GCR_CORES 0x0060 // Core Reset (ARM and PAI are reset) +#define GCR_ENINT 0x0002 // Enable Interrupts +#define GCR_ACKINT 0x0008 // Acknowledge Interrupts + +#define BSS_SRAM 0x0200 // AMBA module selection --> SRAM +#define BSS_IRAM 0x0100 // AMBA module selection --> IRAM +// +// Constants for the MR registers. +// +#define MAC_INIT_COMPLETE 0x0001 // MAC init has been completed +#define MAC_BOOT_COMPLETE 0x0010 // MAC boot has been completed +#define MAC_INIT_OK 0x0002 // MAC boot has been completed + +#define C80211_SUBTYPE_MGMT_ASS_REQUEST 0x00 +#define C80211_SUBTYPE_MGMT_ASS_RESPONSE 0x10 +#define C80211_SUBTYPE_MGMT_REASS_REQUEST 0x20 +#define C80211_SUBTYPE_MGMT_REASS_RESPONSE 0x30 +#define C80211_SUBTYPE_MGMT_ProbeRequest 0x40 +#define C80211_SUBTYPE_MGMT_ProbeResponse 0x50 +#define C80211_SUBTYPE_MGMT_BEACON 0x80 +#define C80211_SUBTYPE_MGMT_ATIM 0x90 +#define C80211_SUBTYPE_MGMT_DISASSOSIATION 0xA0 +#define C80211_SUBTYPE_MGMT_Authentication 0xB0 +#define C80211_SUBTYPE_MGMT_Deauthentication 0xC0 + +#define C80211_MGMT_AAN_OPENSYSTEM 0x0000 +#define C80211_MGMT_AAN_SHAREDKEY 0x0001 + +#define C80211_MGMT_CAPABILITY_ESS 0x0001 // see 802.11 p.58 +#define C80211_MGMT_CAPABILITY_IBSS 0x0002 // - " - +#define C80211_MGMT_CAPABILITY_CFPollable 0x0004 // - " - +#define C80211_MGMT_CAPABILITY_CFPollRequest 0x0008 // - " - +#define C80211_MGMT_CAPABILITY_Privacy 0x0010 // - " - + +#define C80211_MGMT_SC_Success 0 +#define C80211_MGMT_SC_Unspecified 1 +#define C80211_MGMT_SC_SupportCapabilities 10 +#define C80211_MGMT_SC_ReassDenied 11 +#define C80211_MGMT_SC_AssDenied 12 +#define C80211_MGMT_SC_AuthAlgNotSupported 13 +#define C80211_MGMT_SC_AuthTransSeqNumError 14 +#define C80211_MGMT_SC_AuthRejectChallenge 15 +#define C80211_MGMT_SC_AuthRejectTimeout 16 +#define C80211_MGMT_SC_AssDeniedHandleAP 17 +#define C80211_MGMT_SC_AssDeniedBSSRate 18 + +#define C80211_MGMT_ElementID_SSID 0 +#define C80211_MGMT_ElementID_SupportedRates 1 +#define C80211_MGMT_ElementID_ChallengeText 16 +#define C80211_MGMT_CAPABILITY_ShortPreamble 0x0020 + +struct get_set_mib { + u8 type; + u8 size; + u8 index; + u8 reserved; + u8 data[72]; +}; + +struct rx_desc { + u32 Next; + u16 MsduPos; + u16 MsduSize; + + u8 State; + u8 Status; + u8 Rate; + u8 Rssi; + u8 LinkQuality; + u8 PreambleType; + u16 Duration; + u32 RxTime; + +}; + +#define RX_DESC_FLAG_VALID 0x80 +#define RX_DESC_FLAG_CONSUMED 0x40 +#define RX_DESC_FLAG_IDLE 0x00 + +#define RX_STATUS_SUCCESS 0x00 + +#define RX_DESC_MSDU_POS_OFFSET 4 +#define RX_DESC_MSDU_SIZE_OFFSET 6 +#define RX_DESC_FLAGS_OFFSET 8 +#define RX_DESC_STATUS_OFFSET 9 +#define RX_DESC_RSSI_OFFSET 11 +#define RX_DESC_LINK_QUALITY_OFFSET 12 +#define RX_DESC_PREAMBLE_TYPE_OFFSET 13 +#define RX_DESC_DURATION_OFFSET 14 +#define RX_DESC_RX_TIME_OFFSET 16 + + +struct tx_desc { + u32 NextDescriptor; + u16 TxStartOfFrame; + u16 TxLength; + + u8 TxState; + u8 TxStatus; + u8 RetryCount; + + u8 TxRate; + u32 TxTime; + u8 Reserved; + u8 PacketType; + u16 HostTxLength; + +}; + + +#define TX_DESC_NEXT_OFFSET 0 +#define TX_DESC_POS_OFFSET 4 +#define TX_DESC_SIZE_OFFSET 6 +#define TX_DESC_FLAGS_OFFSET 8 +#define TX_DESC_STATUS_OFFSET 9 +#define TX_DESC_RETRY_OFFSET 10 +#define TX_DESC_RATE_OFFSET 11 +#define TX_DESC_PACKET_TYPE_OFFSET 17 +#define TX_DESC_HOST_LENGTH_OFFSET 18 + + + +/////////////////////////////////////////////////////// +// Host-MAC interface +/////////////////////////////////////////////////////// + +#define TX_STATUS_SUCCESS 0x00 + +#define TX_FIRM_OWN 0x80 +#define TX_DONE 0x40 + + +#define TX_ERROR 0x01 + +#define TX_PACKET_TYPE_DATA 0x01 +#define TX_PACKET_TYPE_MGMT 0x02 + +#define ISR_EMPTY 0x00 // no bits set in ISR +#define ISR_TxCOMPLETE 0x01 // packet transmitted +#define ISR_RxCOMPLETE 0x02 // packet received +#define ISR_RxFRAMELOST 0x04 // Rx Frame lost +#define ISR_FATAL_ERROR 0x08 // Fatal error +#define ISR_COMMAND_COMPLETE 0x10 // command completed +#define ISR_OUT_OF_RANGE 0x20 // command completed +#define ISR_IBSS_MERGE 0x40 // (4.1.2.30): IBSS merge +#define ISR_GENERIC_IRQ 0x80 + + +#define Local_Mib_Type 0x01 +#define Mac_Address_Mib_Type 0x02 +#define Mac_Mib_Type 0x03 +#define Statistics_Mib_Type 0x04 +#define Mac_Mgmt_Mib_Type 0x05 +#define Mac_Wep_Mib_Type 0x06 +#define Phy_Mib_Type 0x07 +#define Multi_Domain_MIB 0x08 + +#define MAC_MGMT_MIB_CUR_BSSID_POS 14 +#define MAC_MIB_FRAG_THRESHOLD_POS 8 +#define MAC_MIB_RTS_THRESHOLD_POS 10 +#define MAC_MIB_SHORT_RETRY_POS 16 +#define MAC_MIB_LONG_RETRY_POS 17 +#define MAC_MIB_SHORT_RETRY_LIMIT_POS 16 +#define MAC_MGMT_MIB_BEACON_PER_POS 0 +#define MAC_MGMT_MIB_STATION_ID_POS 6 +#define MAC_MGMT_MIB_CUR_PRIVACY_POS 11 +#define MAC_MGMT_MIB_CUR_BSSID_POS 14 +#define MAC_MGMT_MIB_PS_MODE_POS 53 +#define MAC_MGMT_MIB_LISTEN_INTERVAL_POS 54 +#define MAC_MGMT_MIB_MULTI_DOMAIN_IMPLEMENTED 56 +#define MAC_MGMT_MIB_MULTI_DOMAIN_ENABLED 57 +#define PHY_MIB_CHANNEL_POS 14 +#define PHY_MIB_RATE_SET_POS 20 +#define PHY_MIB_REG_DOMAIN_POS 26 +#define LOCAL_MIB_AUTO_TX_RATE_POS 3 +#define LOCAL_MIB_SSID_SIZE 5 +#define LOCAL_MIB_TX_PROMISCUOUS_POS 6 +#define LOCAL_MIB_TX_MGMT_RATE_POS 7 +#define LOCAL_MIB_TX_CONTROL_RATE_POS 8 +#define LOCAL_MIB_PREAMBLE_TYPE 9 +#define MAC_ADDR_MIB_MAC_ADDR_POS 0 + + +#define CMD_Set_MIB_Vars 0x01 +#define CMD_Get_MIB_Vars 0x02 +#define CMD_Scan 0x03 +#define CMD_Join 0x04 +#define CMD_Start 0x05 +#define CMD_EnableRadio 0x06 +#define CMD_DisableRadio 0x07 +#define CMD_SiteSurvey 0x0B + +#define CMD_STATUS_IDLE 0x00 +#define CMD_STATUS_COMPLETE 0x01 +#define CMD_STATUS_UNKNOWN 0x02 +#define CMD_STATUS_INVALID_PARAMETER 0x03 +#define CMD_STATUS_FUNCTION_NOT_SUPPORTED 0x04 +#define CMD_STATUS_TIME_OUT 0x07 +#define CMD_STATUS_IN_PROGRESS 0x08 +#define CMD_STATUS_REJECTED_RADIO_OFF 0x09 +#define CMD_STATUS_HOST_ERROR 0xFF +#define CMD_STATUS_BUSY 0xFE + + +#define CMD_BLOCK_COMMAND_OFFSET 0 +#define CMD_BLOCK_STATUS_OFFSET 1 +#define CMD_BLOCK_PARAMETERS_OFFSET 4 + +#define SCAN_OPTIONS_SITE_SURVEY 0x80 + +#define MGMT_FRAME_BODY_OFFSET 24 +#define MAX_AUTHENTICATION_RETRIES 3 +#define MAX_ASSOCIATION_RETRIES 3 + +#define AUTHENTICATION_RESPONSE_TIME_OUT 1000 + +#define MAX_WIRELESS_BODY 2316 /* mtu is 2312, CRC is 4 */ +#define LOOP_RETRY_LIMIT 500000 + +#define ACTIVE_MODE 1 +#define PS_MODE 2 + +/////////////////////////////////////////////////////////////////////////// +// 802.11 related definitions +/////////////////////////////////////////////////////////////////////////// + +// +// Regulatory Domains +// + +#define REG_DOMAIN_FCC 0x10 //Channels 1-11 USA +#define REG_DOMAIN_DOC 0x20 //Channel 1-11 Canada +#define REG_DOMAIN_ETSI 0x30 //Channel 1-13 Europe (ex Spain/France) +#define REG_DOMAIN_SPAIN 0x31 //Channel 10-11 Spain +#define REG_DOMAIN_FRANCE 0x32 //Channel 10-13 France +#define REG_DOMAIN_MKK 0x40 //Channel 14 Japan +#define REG_DOMAIN_MKK1 0x41 //Channel 1-14 Japan(MKK1) +#define REG_DOMAIN_ISRAEL 0x50 //Channel 3-9 ISRAEL + +#define BSS_TYPE_AD_HOC 1 +#define BSS_TYPE_INFRASTRUCTURE 2 + +#define SCAN_TYPE_ACTIVE 0 +#define SCAN_TYPE_PASSIVE 1 + +#define LONG_PREAMBLE 0 +#define SHORT_PREAMBLE 1 +#define AUTO_PREAMBLE 2 + +#define DATA_FRAME_WS_HEADER_SIZE 30 + +/* promiscuous mode control */ +#define PROM_MODE_OFF 0x0 +#define PROM_MODE_UNKNOWN 0x1 +#define PROM_MODE_CRC_FAILED 0x2 +#define PROM_MODE_DUPLICATED 0x4 +#define PROM_MODE_MGMT 0x8 +#define PROM_MODE_CTRL 0x10 +#define PROM_MODE_BAD_PROTOCOL 0x20 + + +#define IFACE_INT_STATUS_OFFSET 0 +#define IFACE_INT_MASK_OFFSET 1 +#define IFACE_LOCKOUT_HOST_OFFSET 2 +#define IFACE_LOCKOUT_MAC_OFFSET 3 +#define IFACE_FUNC_CTRL_OFFSET 28 +#define IFACE_MAC_STAT_OFFSET 30 +#define IFACE_GENERIC_INT_TYPE_OFFSET 32 +// +// IFACE MACROS & definitions +// +// + +// FuncCtrl field: +// +#define FUNC_CTRL_TxENABLE 0x10 +#define FUNC_CTRL_RxENABLE 0x20 +#define FUNC_CTRL_INIT_COMPLETE 0x01 + +/* A stub firmware image which reads the MAC address from NVRAM on the card. + For copyright information and source see the end of this file. */ +static u8 mac_reader[] = { + 0x06,0x00,0x00,0xea,0x04,0x00,0x00,0xea,0x03,0x00,0x00,0xea,0x02,0x00,0x00,0xea, + 0x01,0x00,0x00,0xea,0x00,0x00,0x00,0xea,0xff,0xff,0xff,0xea,0xfe,0xff,0xff,0xea, + 0xd3,0x00,0xa0,0xe3,0x00,0xf0,0x21,0xe1,0x0e,0x04,0xa0,0xe3,0x00,0x10,0xa0,0xe3, + 0x81,0x11,0xa0,0xe1,0x00,0x10,0x81,0xe3,0x00,0x10,0x80,0xe5,0x1c,0x10,0x90,0xe5, + 0x10,0x10,0xc1,0xe3,0x1c,0x10,0x80,0xe5,0x01,0x10,0xa0,0xe3,0x08,0x10,0x80,0xe5, + 0x02,0x03,0xa0,0xe3,0x00,0x10,0xa0,0xe3,0xb0,0x10,0xc0,0xe1,0xb4,0x10,0xc0,0xe1, + 0xb8,0x10,0xc0,0xe1,0xbc,0x10,0xc0,0xe1,0x56,0xdc,0xa0,0xe3,0x21,0x00,0x00,0xeb, + 0x0a,0x00,0xa0,0xe3,0x1a,0x00,0x00,0xeb,0x10,0x00,0x00,0xeb,0x07,0x00,0x00,0xeb, + 0x02,0x03,0xa0,0xe3,0x02,0x14,0xa0,0xe3,0xb4,0x10,0xc0,0xe1,0x4c,0x10,0x9f,0xe5, + 0xbc,0x10,0xc0,0xe1,0x10,0x10,0xa0,0xe3,0xb8,0x10,0xc0,0xe1,0xfe,0xff,0xff,0xea, + 0x00,0x40,0x2d,0xe9,0x00,0x20,0xa0,0xe3,0x02,0x3c,0xa0,0xe3,0x00,0x10,0xa0,0xe3, + 0x28,0x00,0x9f,0xe5,0x37,0x00,0x00,0xeb,0x00,0x40,0xbd,0xe8,0x1e,0xff,0x2f,0xe1, + 0x00,0x40,0x2d,0xe9,0x12,0x2e,0xa0,0xe3,0x06,0x30,0xa0,0xe3,0x00,0x10,0xa0,0xe3, + 0x02,0x04,0xa0,0xe3,0x2f,0x00,0x00,0xeb,0x00,0x40,0xbd,0xe8,0x1e,0xff,0x2f,0xe1, + 0x00,0x02,0x00,0x02,0x80,0x01,0x90,0xe0,0x01,0x00,0x00,0x0a,0x01,0x00,0x50,0xe2, + 0xfc,0xff,0xff,0xea,0x1e,0xff,0x2f,0xe1,0x80,0x10,0xa0,0xe3,0xf3,0x06,0xa0,0xe3, + 0x00,0x10,0x80,0xe5,0x00,0x10,0xa0,0xe3,0x00,0x10,0x80,0xe5,0x01,0x10,0xa0,0xe3, + 0x04,0x10,0x80,0xe5,0x00,0x10,0x80,0xe5,0x0e,0x34,0xa0,0xe3,0x1c,0x10,0x93,0xe5, + 0x02,0x1a,0x81,0xe3,0x1c,0x10,0x83,0xe5,0x58,0x11,0x9f,0xe5,0x30,0x10,0x80,0xe5, + 0x54,0x11,0x9f,0xe5,0x34,0x10,0x80,0xe5,0x38,0x10,0x80,0xe5,0x3c,0x10,0x80,0xe5, + 0x10,0x10,0x90,0xe5,0x08,0x00,0x90,0xe5,0x1e,0xff,0x2f,0xe1,0xf3,0x16,0xa0,0xe3, + 0x08,0x00,0x91,0xe5,0x05,0x00,0xa0,0xe3,0x0c,0x00,0x81,0xe5,0x10,0x00,0x91,0xe5, + 0x02,0x00,0x10,0xe3,0xfc,0xff,0xff,0x0a,0xff,0x00,0xa0,0xe3,0x0c,0x00,0x81,0xe5, + 0x10,0x00,0x91,0xe5,0x02,0x00,0x10,0xe3,0xfc,0xff,0xff,0x0a,0x08,0x00,0x91,0xe5, + 0x10,0x00,0x91,0xe5,0x01,0x00,0x10,0xe3,0xfc,0xff,0xff,0x0a,0x08,0x00,0x91,0xe5, + 0xff,0x00,0x00,0xe2,0x1e,0xff,0x2f,0xe1,0x30,0x40,0x2d,0xe9,0x00,0x50,0xa0,0xe1, + 0x03,0x40,0xa0,0xe1,0xa2,0x02,0xa0,0xe1,0x08,0x00,0x00,0xe2,0x03,0x00,0x80,0xe2, + 0xd8,0x10,0x9f,0xe5,0x00,0x00,0xc1,0xe5,0x01,0x20,0xc1,0xe5,0xe2,0xff,0xff,0xeb, + 0x01,0x00,0x10,0xe3,0xfc,0xff,0xff,0x1a,0x14,0x00,0xa0,0xe3,0xc4,0xff,0xff,0xeb, + 0x04,0x20,0xa0,0xe1,0x05,0x10,0xa0,0xe1,0x02,0x00,0xa0,0xe3,0x01,0x00,0x00,0xeb, + 0x30,0x40,0xbd,0xe8,0x1e,0xff,0x2f,0xe1,0x70,0x40,0x2d,0xe9,0xf3,0x46,0xa0,0xe3, + 0x00,0x30,0xa0,0xe3,0x00,0x00,0x50,0xe3,0x08,0x00,0x00,0x9a,0x8c,0x50,0x9f,0xe5, + 0x03,0x60,0xd5,0xe7,0x0c,0x60,0x84,0xe5,0x10,0x60,0x94,0xe5,0x02,0x00,0x16,0xe3, + 0xfc,0xff,0xff,0x0a,0x01,0x30,0x83,0xe2,0x00,0x00,0x53,0xe1,0xf7,0xff,0xff,0x3a, + 0xff,0x30,0xa0,0xe3,0x0c,0x30,0x84,0xe5,0x08,0x00,0x94,0xe5,0x10,0x00,0x94,0xe5, + 0x01,0x00,0x10,0xe3,0xfc,0xff,0xff,0x0a,0x08,0x00,0x94,0xe5,0x00,0x00,0xa0,0xe3, + 0x00,0x00,0x52,0xe3,0x0b,0x00,0x00,0x9a,0x10,0x50,0x94,0xe5,0x02,0x00,0x15,0xe3, + 0xfc,0xff,0xff,0x0a,0x0c,0x30,0x84,0xe5,0x10,0x50,0x94,0xe5,0x01,0x00,0x15,0xe3, + 0xfc,0xff,0xff,0x0a,0x08,0x50,0x94,0xe5,0x01,0x50,0xc1,0xe4,0x01,0x00,0x80,0xe2, + 0x02,0x00,0x50,0xe1,0xf3,0xff,0xff,0x3a,0xc8,0x00,0xa0,0xe3,0x98,0xff,0xff,0xeb, + 0x70,0x40,0xbd,0xe8,0x1e,0xff,0x2f,0xe1,0x01,0x0c,0x00,0x02,0x01,0x02,0x00,0x02, + 0x00,0x01,0x00,0x02 +}; + +struct atmel_private { + void *card; /* Bus dependent stucture varies for PCcard */ + int (*present_callback)(void *); /* And callback which uses it */ + char firmware_id[32]; + unsigned char *firmware; + int firmware_length; + struct timer_list management_timer; + struct net_device *dev; + struct device *sys_dev; + struct iw_statistics wstats; + struct net_device_stats stats; // device stats + spinlock_t irqlock, timerlock; // spinlocks + enum { BUS_TYPE_PCCARD, BUS_TYPE_PCI } bus_type; + enum { + CARD_TYPE_PARALLEL_FLASH, + CARD_TYPE_SPI_FLASH, + CARD_TYPE_EEPROM + } card_type; + int is3com; /* is this a 3com card? they are uniquely borken */ + int do_rx_crc; /* If we need to CRC incoming packets */ + int probe_crc; /* set if we don't yet know */ + int crc_ok_cnt, crc_ko_cnt; /* counters for probing */ + u16 rx_desc_head; + u16 tx_desc_free, tx_desc_head, tx_desc_tail, tx_desc_previous; + u16 tx_free_mem, tx_buff_head, tx_buff_tail; + + u16 frag_seq, frag_len, frag_no; + u8 frag_source[6]; + + int wep_key_len[4]; /* need to know these and not stored in Mib. */ + struct { /* NB this is matched to the hardware, don't change. */ + u8 wep_is_on; + u8 default_key; /* 0..3 */ + u8 reserved; + u8 exclude_unencrypted; + + u32 WEPICV_error_count; + u32 WEP_excluded_count; + + u8 wep_keys[4][13]; + u8 encryption_level; /* 0, 1, 2 */ + u8 reserved2[3]; + } wep; + + u16 host_info_base; + struct host_info_struct { + /* NB this is matched to the hardware, don't change. */ + u8 volatile int_status; + u8 volatile int_mask; + u8 volatile lockout_host; + u8 volatile lockout_mac; + + u16 tx_buff_pos; + u16 tx_buff_size; + u16 tx_desc_pos; + u16 tx_desc_count; + + u16 rx_buff_pos; + u16 rx_buff_size; + u16 rx_desc_pos; + u16 rx_desc_count; + + u16 build_version; + u16 command_pos; + + u16 major_version; + u16 minor_version; + + u16 func_ctrl; + u16 mac_status; + u16 generic_IRQ_type; + u8 reserved[2]; + } host_info; + + enum { + STATION_STATE_INITIALIZING, + STATION_STATE_SCANNING, + STATION_STATE_JOINNING, + STATION_STATE_AUTHENTICATING, + STATION_STATE_ASSOCIATING, + STATION_STATE_READY, + STATION_STATE_REASSOCIATING, + STATION_STATE_FORCED_JOINNING, + STATION_STATE_FORCED_JOIN_FAILURE, + STATION_STATE_DOWN, + STATION_STATE_NO_CARD, + STATION_STATE_MGMT_ERROR + } station_state; + + int operating_mode, power_mode; + time_t last_qual; + int beacons_this_sec; + u64 last_beacon_timestamp; + int channel; + int reg_domain; + int tx_rate; + int auto_tx_rate;; + int rts_threshold; + int frag_threshold; + int long_retry, short_retry; + int preamble; + int default_beacon_period, beacon_period, listen_interval; + int CurrentAuthentTransactionSeqNum, ExpectedAuthentTransactionSeqNum; + int AuthenticationRequestRetryCnt, AssociationRequestRetryCnt, ReAssociationRequestRetryCnt; + enum { + SITE_SURVEY_IDLE, + SITE_SURVEY_IN_PROGRESS, + SITE_SURVEY_COMPLETED + } site_survey_state; + time_t last_survey; + + int station_was_associated, station_is_associated; + int fast_scan; + + struct bss_info { + int channel; + int SSIDsize; + int RSSI; + int UsingWEP; + int preamble; + int beacon_period; + int BSStype; + u8 BSSID[6]; + u8 SSID[MAX_SSID_LENGTH]; + } BSSinfo[MAX_BSS_ENTRIES]; + int BSS_list_entries, current_BSS; + int connect_to_any_BSS; + int SSID_size, new_SSID_size; + u8 CurrentBSSID[6], BSSID[6]; + u8 SSID[MAX_SSID_LENGTH], new_SSID[MAX_SSID_LENGTH]; + u8 rx_buf[MAX_WIRELESS_BODY]; + +}; + +static u8 atmel_basic_rates[4] = {0x82,0x84,0x0b,0x16}; + +static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); +static void atmel_copy_to_card(struct net_device *dev, u16 dest, unsigned char *src, u16 len); +static void atmel_copy_to_host(struct net_device *dev, unsigned char *dest, u16 src, u16 len); +static void atmel_set_gcr(struct net_device *dev, u16 mask); +static void atmel_clear_gcr(struct net_device *dev, u16 mask); +static int atmel_lock_mac(struct atmel_private *priv); +static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data); +static void atmel_command_irq(struct atmel_private *priv); +static int atmel_validate_channel(struct atmel_private *priv, int channel); +static void atmel_management_frame(struct atmel_private *priv, struct ieee802_11_hdr *header, + u16 frame_len, u8 rssi); +static void atmel_management_timer(u_long a); +static void atmel_send_command(struct atmel_private *priv, int command, void *cmd, int cmd_size); +static int atmel_send_command_wait(struct atmel_private *priv, int command, void *cmd, int cmd_size); +static void atmel_transmit_management_frame(struct atmel_private *priv, struct ieee802_11_hdr *header, + u8 *body, int body_len); + +static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index); +static void atmel_set_mib8(struct atmel_private *priv, u8 type, u8 index, u8 data); +static void atmel_set_mib16(struct atmel_private *priv, u8 type, u8 index, u16 data); +static void atmel_set_mib(struct atmel_private *priv, u8 type, u8 index, u8 *data, int data_len); +static void atmel_get_mib(struct atmel_private *priv, u8 type, u8 index, u8 *data, int data_len); +static void atmel_scan(struct atmel_private *priv, int specific_ssid); +static void atmel_join_bss(struct atmel_private *priv, int bss_index); +static void atmel_smooth_qual(struct atmel_private *priv); +static void atmel_writeAR(struct net_device *dev, u16 data); +static int probe_atmel_card(struct net_device *dev); +int reset_atmel_card(struct net_device *dev ); +static void atmel_enter_state(struct atmel_private *priv, int new_state); + +static inline u16 atmel_hi(struct atmel_private *priv, u16 offset) +{ + return priv->host_info_base + offset; +} + +static inline u16 atmel_co(struct atmel_private *priv, u16 offset) +{ + return priv->host_info.command_pos + offset; +} + +static inline u16 atmel_rx(struct atmel_private *priv, u16 offset, u16 desc) +{ + return priv->host_info.rx_desc_pos + (sizeof(struct rx_desc) * desc) + offset; +} + +static inline u16 atmel_tx(struct atmel_private *priv, u16 offset, u16 desc) +{ + return priv->host_info.tx_desc_pos + (sizeof(struct tx_desc) * desc) + offset; +} + +static inline u8 atmel_read8(struct net_device *dev, u16 offset) +{ + return inb(dev->base_addr + offset); +} + +static inline void atmel_write8(struct net_device *dev, u16 offset, u8 data) +{ + outb(data, dev->base_addr + offset); +} + +static inline u16 atmel_read16(struct net_device *dev, u16 offset) +{ + return inw(dev->base_addr + offset); +} + +static inline void atmel_write16(struct net_device *dev, u16 offset, u16 data) +{ + outw(data, dev->base_addr + offset); +} + + +static inline u8 atmel_rmem8(struct atmel_private *priv, u16 pos) +{ + atmel_writeAR(priv->dev, pos); + return atmel_read8(priv->dev, DR); +} + +static inline void atmel_wmem8(struct atmel_private *priv, u16 pos, u16 data) +{ + atmel_writeAR(priv->dev, pos); + atmel_write8(priv->dev, DR, data); +} + +static inline u16 atmel_rmem16(struct atmel_private *priv, u16 pos) +{ + atmel_writeAR(priv->dev, pos); + return atmel_read16(priv->dev, DR); +} + +static inline void atmel_wmem16(struct atmel_private *priv, u16 pos, u16 data) +{ + atmel_writeAR(priv->dev, pos); + atmel_write16(priv->dev, DR, data); +} + +static const struct iw_handler_def atmel_handler_def; + +static void tx_done_irq(struct atmel_private *priv) +{ + int i; + + for (i = 0; + atmel_rmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_head)) == TX_DONE && + i < priv->host_info.tx_desc_count; + i++) { + + u8 status = atmel_rmem8(priv, atmel_tx(priv, TX_DESC_STATUS_OFFSET, priv->tx_desc_head)); + u16 msdu_size = atmel_rmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, priv->tx_desc_head)); + u8 type = atmel_rmem8(priv, atmel_tx(priv, TX_DESC_PACKET_TYPE_OFFSET, priv->tx_desc_head)); + + atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_head), 0); + + priv->tx_free_mem += msdu_size; + priv->tx_desc_free++; + + if (priv->tx_buff_head + msdu_size > (priv->host_info.tx_buff_pos + priv->host_info.tx_buff_size)) + priv->tx_buff_head = 0; + else + priv->tx_buff_head += msdu_size; + + if (priv->tx_desc_head < (priv->host_info.tx_desc_count - 1)) + priv->tx_desc_head++ ; + else + priv->tx_desc_head = 0; + + if (type == TX_PACKET_TYPE_DATA) { + if (status == TX_STATUS_SUCCESS) + priv->stats.tx_packets++; + else + priv->stats.tx_errors++; + netif_wake_queue(priv->dev); + } + } +} + +static u16 find_tx_buff(struct atmel_private *priv, u16 len) +{ + u16 bottom_free = priv->host_info.tx_buff_size - priv->tx_buff_tail; + + if (priv->tx_desc_free == 3 || priv->tx_free_mem < len) + return 0; + + if (bottom_free >= len) + return priv->host_info.tx_buff_pos + priv->tx_buff_tail; + + if (priv->tx_free_mem - bottom_free >= len) { + priv->tx_buff_tail = 0; + return priv->host_info.tx_buff_pos; + } + + return 0; +} + +static void tx_update_descriptor(struct atmel_private *priv, u16 len, u16 buff, u8 type) +{ + atmel_wmem16(priv, atmel_tx(priv, TX_DESC_POS_OFFSET, priv->tx_desc_tail), buff); + atmel_wmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, priv->tx_desc_tail), len); + atmel_wmem16(priv, atmel_tx(priv, TX_DESC_HOST_LENGTH_OFFSET, priv->tx_desc_tail), len); + atmel_wmem8(priv, atmel_tx(priv, TX_DESC_PACKET_TYPE_OFFSET, priv->tx_desc_tail), type); + atmel_wmem8(priv, atmel_tx(priv, TX_DESC_RATE_OFFSET, priv->tx_desc_tail), priv->tx_rate); + atmel_wmem8(priv, atmel_tx(priv, TX_DESC_RETRY_OFFSET, priv->tx_desc_tail), 0); + atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, priv->tx_desc_tail), 0x80000000L); + atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, priv->tx_desc_tail), TX_FIRM_OWN); + if (priv->tx_desc_previous != priv->tx_desc_tail) + atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, priv->tx_desc_previous), 0); + priv->tx_desc_previous = priv->tx_desc_tail; + if (priv->tx_desc_tail < (priv->host_info.tx_desc_count -1 )) + priv->tx_desc_tail++; + else + priv->tx_desc_tail = 0; + priv->tx_desc_free--; + priv->tx_free_mem -= len; + +} + +static int start_tx (struct sk_buff *skb, struct net_device *dev) +{ + struct atmel_private *priv = (struct atmel_private *)dev->priv; + struct ieee802_11_hdr header; + unsigned long flags; + u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; + + if(priv->station_state != STATION_STATE_READY) { + priv->stats.tx_errors++; + return 0; + } + + if (priv->card && priv->present_callback && + !(*priv->present_callback)(priv->card)) { + priv->stats.tx_errors++; + return 0; + } + + /* first ensure the timer func cannot run */ + spin_lock_bh(&priv->timerlock); + /* then stop the hardware ISR */ + spin_lock_irqsave(&priv->irqlock, flags); + /* nb doing the above in the opposite order will deadlock */ + + /* The Wireless Header is 30 bytes. In the Ethernet packet we "cut" the + 12 first bytes (containing DA/SA) and put them in the appropriate fields of + the Wireless Header. Thus the packet length is then the initial + 18 (+30-12) */ + + if (!(buff = find_tx_buff(priv, len + 18))) { + priv->stats.tx_dropped++; + spin_unlock_irqrestore(&priv->irqlock, flags); + spin_unlock_bh(&priv->timerlock); + netif_stop_queue(dev); + return 1; + } + + frame_ctl = IEEE802_11_FTYPE_DATA; + header.duration_id = 0; + header.seq_ctl = 0; + if (priv->wep.wep_is_on) + frame_ctl |= IEEE802_11_FCTL_WEP; + if (priv->operating_mode == IW_MODE_ADHOC) { + memcpy(&header.addr1, skb->data, 6); + memcpy(&header.addr2, dev->dev_addr, 6); + memcpy(&header.addr3, priv->BSSID, 6); + } else { + frame_ctl |= IEEE802_11_FCTL_TODS; + memcpy(&header.addr1, priv->CurrentBSSID, 6); + memcpy(&header.addr2, dev->dev_addr, 6); + memcpy(&header.addr3, skb->data, 6); + } + + header.frame_ctl = cpu_to_le16(frame_ctl); + /* Copy the wireless header into the card */ + atmel_copy_to_card(dev, buff, (unsigned char *)&header, DATA_FRAME_WS_HEADER_SIZE); + /* Copy the packet sans its 802.3 header addresses which have been replaced */ + atmel_copy_to_card(dev, buff + DATA_FRAME_WS_HEADER_SIZE, skb->data + 12, len - 12); + priv->tx_buff_tail += len - 12 + DATA_FRAME_WS_HEADER_SIZE; + + tx_update_descriptor(priv, len + 18, buff, TX_PACKET_TYPE_DATA); + dev->trans_start = jiffies; + priv->stats.tx_bytes += len; + + spin_unlock_irqrestore(&priv->irqlock, flags); + spin_unlock_bh(&priv->timerlock); + dev_kfree_skb(skb); + + return 0; +} + +static void atmel_transmit_management_frame(struct atmel_private *priv, + struct ieee802_11_hdr *header, + u8 *body, int body_len) +{ + u16 buff; + int len = MGMT_FRAME_BODY_OFFSET + body_len; + + if (!(buff = find_tx_buff(priv, len))) + return; + + atmel_copy_to_card(priv->dev, buff, (u8 *)header, MGMT_FRAME_BODY_OFFSET); + atmel_copy_to_card(priv->dev, buff + MGMT_FRAME_BODY_OFFSET, body, body_len); + priv->tx_buff_tail += len; + tx_update_descriptor(priv, len, buff, TX_PACKET_TYPE_MGMT); +} + +static void fast_rx_path(struct atmel_private *priv, struct ieee802_11_hdr *header, + u16 msdu_size, u16 rx_packet_loc, u32 crc) +{ + /* fast path: unfragmented packet copy directly into skbuf */ + u8 mac4[6]; + struct sk_buff *skb; + unsigned char *skbp; + + /* get the final, mac 4 header field, this tells us encapsulation */ + atmel_copy_to_host(priv->dev, mac4, rx_packet_loc + 24, 6); + msdu_size -= 6; + + if (priv->do_rx_crc) { + crc = crc32_le(crc, mac4, 6); + msdu_size -= 4; + } + + if (!(skb = dev_alloc_skb(msdu_size + 14))) { + priv->stats.rx_dropped++; + return; + } + + skb_reserve(skb, 2); + skbp = skb_put(skb, msdu_size + 12); + atmel_copy_to_host(priv->dev, skbp + 12, rx_packet_loc + 30, msdu_size); + + if (priv->do_rx_crc) { + u32 netcrc; + crc = crc32_le(crc, skbp + 12, msdu_size); + atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + 30 + msdu_size, 4); + if ((crc ^ 0xffffffff) != netcrc) { + priv->stats.rx_crc_errors++; + dev_kfree_skb(skb); + return; + } + } + + memcpy(skbp, header->addr1, 6); /* destination address */ + if (le16_to_cpu(header->frame_ctl) & IEEE802_11_FCTL_FROMDS) + memcpy(&skbp[6], header->addr3, 6); + else + memcpy(&skbp[6], header->addr2, 6); /* source address */ + + priv->dev->last_rx=jiffies; + skb->dev = priv->dev; + skb->protocol = eth_type_trans(skb, priv->dev); + skb->ip_summed = CHECKSUM_NONE; + netif_rx(skb); + priv->stats.rx_bytes += 12 + msdu_size; + priv->stats.rx_packets++; +} + +/* Test to see if the packet in card memory at packet_loc has a valid CRC + It doesn't matter that this is slow: it is only used to proble the first few packets. */ +static int probe_crc(struct atmel_private *priv, u16 packet_loc, u16 msdu_size) +{ + int i = msdu_size - 4; + u32 netcrc, crc = 0xffffffff; + + if (msdu_size < 4) + return 0; + + atmel_copy_to_host(priv->dev, (void *)&netcrc, packet_loc + i, 4); + + atmel_writeAR(priv->dev, packet_loc); + while (i--) { + u8 octet = atmel_read8(priv->dev, DR); + crc = crc32_le(crc, &octet, 1); + } + + return (crc ^ 0xffffffff) == netcrc; +} + +static void frag_rx_path(struct atmel_private *priv, struct ieee802_11_hdr *header, + u16 msdu_size, u16 rx_packet_loc, u32 crc, u16 seq_no, u8 frag_no, int more_frags) +{ + u8 mac4[6]; + u8 source[6]; + struct sk_buff *skb; + + if (le16_to_cpu(header->frame_ctl) & IEEE802_11_FCTL_FROMDS) + memcpy(source, header->addr3, 6); + else + memcpy(source, header->addr2, 6); + + rx_packet_loc += 24; /* skip header */ + + if (priv->do_rx_crc) + msdu_size -= 4; + + if (frag_no == 0) { /* first fragment */ + atmel_copy_to_host(priv->dev, mac4, rx_packet_loc, 6); + msdu_size -= 6; + rx_packet_loc += 6; + + if (priv->do_rx_crc) + crc = crc32_le(crc, mac4, 6); + + priv->frag_seq = seq_no; + priv->frag_no = 1; + priv->frag_len = msdu_size; + memcpy(priv->frag_source, source, 6); + memcpy(&priv->rx_buf[6], source, 6); + memcpy(priv->rx_buf, header->addr1, 6); + + atmel_copy_to_host(priv->dev, &priv->rx_buf[12], rx_packet_loc, msdu_size); + + if (priv->do_rx_crc) { + u32 netcrc; + crc = crc32_le(crc, &priv->rx_buf[12], msdu_size); + atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4); + if ((crc ^ 0xffffffff) != netcrc) { + priv->stats.rx_crc_errors++; + memset(priv->frag_source, 0xff, 6); + } + } + + } else if (priv->frag_no == frag_no && + priv->frag_seq == seq_no && + memcmp(priv->frag_source, source, 6) == 0) { + + atmel_copy_to_host(priv->dev, &priv->rx_buf[12 + priv->frag_len], + rx_packet_loc, msdu_size); + if (priv->do_rx_crc) { + u32 netcrc; + crc = crc32_le(crc, + &priv->rx_buf[12 + priv->frag_len], + msdu_size); + atmel_copy_to_host(priv->dev, (void *)&netcrc, rx_packet_loc + msdu_size, 4); + if ((crc ^ 0xffffffff) != netcrc) { + priv->stats.rx_crc_errors++; + memset(priv->frag_source, 0xff, 6); + more_frags = 1; /* don't send broken assembly */ + } + } + + priv->frag_len += msdu_size; + priv->frag_no++; + + if (!more_frags) { /* last one */ + memset(priv->frag_source, 0xff, 6); + if (!(skb = dev_alloc_skb(priv->frag_len + 14))) { + priv->stats.rx_dropped++; + } else { + skb_reserve(skb, 2); + memcpy(skb_put(skb, priv->frag_len + 12), + priv->rx_buf, + priv->frag_len + 12); + priv->dev->last_rx = jiffies; + skb->dev = priv->dev; + skb->protocol = eth_type_trans(skb, priv->dev); + skb->ip_summed = CHECKSUM_NONE; + netif_rx(skb); + priv->stats.rx_bytes += priv->frag_len + 12; + priv->stats.rx_packets++; + } + } + + } else + priv->wstats.discard.fragment++; +} + +static void rx_done_irq(struct atmel_private *priv) +{ + int i; + struct ieee802_11_hdr header; + + for (i = 0; + atmel_rmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head)) == RX_DESC_FLAG_VALID && + i < priv->host_info.rx_desc_count; + i++) { + + u16 msdu_size, rx_packet_loc, frame_ctl, seq_control; + u8 status = atmel_rmem8(priv, atmel_rx(priv, RX_DESC_STATUS_OFFSET, priv->rx_desc_head)); + u32 crc = 0xffffffff; + + if (status != RX_STATUS_SUCCESS) { + if (status == 0xc1) /* determined by experiment */ + priv->wstats.discard.nwid++; + else + priv->stats.rx_errors++; + goto next; + } + + msdu_size = atmel_rmem16(priv, atmel_rx(priv, RX_DESC_MSDU_SIZE_OFFSET, priv->rx_desc_head)); + rx_packet_loc = atmel_rmem16(priv, atmel_rx(priv, RX_DESC_MSDU_POS_OFFSET, priv->rx_desc_head)); + + if (msdu_size < 30) { + priv->stats.rx_errors++; + goto next; + } + + /* Get header as far as end of seq_ctl */ + atmel_copy_to_host(priv->dev, (char *)&header, rx_packet_loc, 24); + frame_ctl = le16_to_cpu(header.frame_ctl); + seq_control = le16_to_cpu(header.seq_ctl); + + /* probe for CRC use here if needed once five packets have arrived with + the same crc status, we assume we know what's happening and stop probing */ + if (priv->probe_crc) { + if (!priv->wep.wep_is_on || !(frame_ctl & IEEE802_11_FCTL_WEP)) { + priv->do_rx_crc = probe_crc(priv, rx_packet_loc, msdu_size); + } else { + priv->do_rx_crc = probe_crc(priv, rx_packet_loc + 24, msdu_size - 24); + } + if (priv->do_rx_crc) { + if (priv->crc_ok_cnt++ > 5) + priv->probe_crc = 0; + } else { + if (priv->crc_ko_cnt++ > 5) + priv->probe_crc = 0; + } + } + + /* don't CRC header when WEP in use */ + if (priv->do_rx_crc && (!priv->wep.wep_is_on || !(frame_ctl & IEEE802_11_FCTL_WEP))) { + crc = crc32_le(0xffffffff, (unsigned char *)&header, 24); + } + msdu_size -= 24; /* header */ + + if ((frame_ctl & IEEE802_11_FCTL_FTYPE) == IEEE802_11_FTYPE_DATA) { + + int more_fragments = frame_ctl & IEEE802_11_FCTL_MOREFRAGS; + u8 packet_fragment_no = seq_control & IEEE802_11_SCTL_FRAG; + u16 packet_sequence_no = (seq_control & IEEE802_11_SCTL_SEQ) >> 4; + + if (!more_fragments && packet_fragment_no == 0 ) { + fast_rx_path(priv, &header, msdu_size, rx_packet_loc, crc); + } else { + frag_rx_path(priv, &header, msdu_size, rx_packet_loc, crc, + packet_sequence_no, packet_fragment_no, more_fragments); + } + } + + if ((frame_ctl & IEEE802_11_FCTL_FTYPE) == IEEE802_11_FTYPE_MGMT) { + /* copy rest of packet into buffer */ + atmel_copy_to_host(priv->dev, (unsigned char *)&priv->rx_buf, rx_packet_loc + 24, msdu_size); + + /* we use the same buffer for frag reassembly and control packets */ + memset(priv->frag_source, 0xff, 6); + + if (priv->do_rx_crc) { + /* last 4 octets is crc */ + msdu_size -= 4; + crc = crc32_le(crc, (unsigned char *)&priv->rx_buf, msdu_size); + if ((crc ^ 0xffffffff) != (*((u32 *)&priv->rx_buf[msdu_size]))) { + priv->stats.rx_crc_errors++; + goto next; + } + } + + atmel_management_frame(priv, &header, msdu_size, + atmel_rmem8(priv, atmel_rx(priv, RX_DESC_RSSI_OFFSET, priv->rx_desc_head))); + } + + next: + /* release descriptor */ + atmel_wmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head), RX_DESC_FLAG_CONSUMED); + + if (priv->rx_desc_head < (priv->host_info.rx_desc_count - 1)) + priv->rx_desc_head++; + else + priv->rx_desc_head = 0; + } +} + +static void reset_irq_status(struct atmel_private *priv, u8 mask) +{ + u8 isr; + + atmel_lock_mac(priv); + isr = atmel_rmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET)); + isr ^= mask; + atmel_wmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET), isr); + atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); +} + +static irqreturn_t service_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = (struct net_device *) dev_id; + struct atmel_private *priv = (struct atmel_private *) dev->priv; + u8 isr; + + if (priv->card && priv->present_callback && + !(*priv->present_callback)(priv->card)) + return IRQ_HANDLED; + + atmel_clear_gcr(dev, GCR_ENINT); /* disable interrupts */ + + while (1) { + if (!atmel_lock_mac(priv)) { + printk(KERN_ALERT "%s: MAC gone away in ISR.\n", dev->name); + /* bad things - don't re-enable interrupts */ + return IRQ_HANDLED; + } + + isr = atmel_rmem8(priv, atmel_hi(priv, IFACE_INT_STATUS_OFFSET)); + atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); + if (isr) + atmel_set_gcr(dev, GCR_ACKINT); /* acknowledge interrupt */ + else + break; /* no pending irqs */ + + if (isr & ISR_OUT_OF_RANGE) { + reset_irq_status(priv, ISR_OUT_OF_RANGE); + if(priv->operating_mode == IW_MODE_INFRA && + priv->station_state == STATION_STATE_READY) { + priv->station_is_associated = 0; + atmel_scan(priv, 1); + } + } else if (isr & ISR_RxCOMPLETE) { + reset_irq_status(priv, ISR_RxCOMPLETE); + rx_done_irq(priv); + } else if (isr & ISR_TxCOMPLETE) { + reset_irq_status(priv, ISR_TxCOMPLETE); + tx_done_irq(priv); + } else if (isr & ISR_RxFRAMELOST) { + reset_irq_status(priv, ISR_RxFRAMELOST); + priv->wstats.discard.misc++; + rx_done_irq(priv); + } else if (isr & ISR_FATAL_ERROR) { + reset_irq_status(priv, ISR_FATAL_ERROR); + printk(KERN_ALERT "%s: *** FATAL error interrupt ***\n", dev->name); + atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); + } else if (isr & ISR_COMMAND_COMPLETE) { + reset_irq_status(priv, ISR_COMMAND_COMPLETE); + atmel_command_irq(priv); + } else if (isr & ISR_IBSS_MERGE) { + reset_irq_status(priv, ISR_IBSS_MERGE); + atmel_get_mib(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_BSSID_POS, + priv->CurrentBSSID, 6); + } else if (isr & ISR_GENERIC_IRQ) { + reset_irq_status(priv, ISR_GENERIC_IRQ); + printk(KERN_INFO "%s: Generic_irq recieved.\n", dev->name); + } + } + + atmel_set_gcr(dev, GCR_ENINT); /* enable interrupts */ + return IRQ_HANDLED; +} + + +static struct net_device_stats *atmel_get_stats (struct net_device *dev) +{ + struct atmel_private *priv = (struct atmel_private *)dev->priv; + return &priv->stats; +} + +static struct iw_statistics *atmel_get_wireless_stats (struct net_device *dev) +{ + struct atmel_private *priv = (struct atmel_private *)dev->priv; + + /* update the link quality here in case we are seeing no beacons + at all to drive the process */ + atmel_smooth_qual(priv); + + priv->wstats.status = priv->station_state; + + if (priv->operating_mode == IW_MODE_INFRA) { + if (priv->station_state != STATION_STATE_READY) { + priv->wstats.qual.qual = 0; + priv->wstats.qual.level = 0; + } + priv->wstats.qual.noise = 0; + priv->wstats.qual.updated = 7; + } else { + // Quality levels cannot be determined in ad-hoc mode, + // because we can 'hear' more that one remote station. + priv->wstats.qual.qual = 0; + priv->wstats.qual.level = 0; + priv->wstats.qual.noise = 0; + priv->wstats.qual.updated = 0; + priv->wstats.miss.beacon = 0; + } + + return (&priv->wstats); +} + +static int atmel_change_mtu(struct net_device *dev, int new_mtu) +{ + if ((new_mtu < 68) || (new_mtu > 2312)) + return -EINVAL; + dev->mtu = new_mtu; + return 0; +} + +static int atmel_set_mac_address(struct net_device *dev, void *p) +{ + struct sockaddr *addr = p; + + memcpy (dev->dev_addr, addr->sa_data, dev->addr_len); + reset_atmel_card(dev); + return 0; +} + +static int atmel_open (struct net_device *dev) +{ + struct atmel_private *priv = (struct atmel_private *) dev->priv; + priv->station_state = STATION_STATE_INITIALIZING; + if (!reset_atmel_card(dev)) { + priv->station_state = STATION_STATE_DOWN; + return -EAGAIN; + } + return 0; +} + +static int atmel_close (struct net_device *dev) +{ + struct atmel_private *priv = (struct atmel_private *) dev->priv; + + if (netif_running(dev)) + netif_stop_queue(dev); + + priv->station_state = STATION_STATE_DOWN; + if (priv->bus_type == BUS_TYPE_PCCARD) + atmel_write16(dev, GCR, 0x0060); + atmel_write16(dev, GCR, 0x0040); + return 0; +} + +static int atmel_proc_output (char *buf, struct atmel_private *priv) +{ + char *p = buf; + char *s, *r, *c; + + p += sprintf(p, "Driver version:\t\t%d.%d\n", DRIVER_MAJOR, DRIVER_MINOR); + + if (priv->station_state != STATION_STATE_DOWN) { + p += sprintf(p, "Firmware version:\t%d.%d build %d ", + priv->host_info.major_version, + priv->host_info.minor_version, + priv->host_info.build_version); + + if (priv->card_type != CARD_TYPE_EEPROM) + p += sprintf(p, "[built-in]\n"); + else if (priv->firmware) + p += sprintf(p, "[%s loaded by host]\n", priv->firmware_id); + else + p += sprintf(p, "[%s loaded by hotplug]\n", priv->firmware_id); + + switch(priv->card_type) { + case CARD_TYPE_PARALLEL_FLASH: c = "Parallel flash"; break; + case CARD_TYPE_SPI_FLASH: c = "SPI flash\n"; break; + case CARD_TYPE_EEPROM: c = "EEPROM"; break; + default: c = "<unknown>"; + } + + switch (priv->reg_domain) { + case REG_DOMAIN_FCC: r = "USA"; break; + case REG_DOMAIN_DOC: r = "Canada"; break; + case REG_DOMAIN_ETSI: r = "Europe"; break; + case REG_DOMAIN_SPAIN: r = "Spain"; break; + case REG_DOMAIN_FRANCE: r = "France"; break; + case REG_DOMAIN_MKK: r = "Japan (MKK)"; break; + case REG_DOMAIN_MKK1: r = "Japan (MKK1)"; break; + case REG_DOMAIN_ISRAEL: r = "Israel"; break; + default: r = "<unknown>"; + } + p += sprintf(p, "MAC memory type:\t%s\n", c); + p += sprintf(p, "Regulatory domain:\t%s\n", r); + p += sprintf(p, "Host CRC checking:\t%s\n", + priv->do_rx_crc ? "On" : "Off"); + } + + switch(priv->station_state) { + case STATION_STATE_INITIALIZING: s = "Initialising"; break; + case STATION_STATE_SCANNING: s = "Scanning"; break; + case STATION_STATE_JOINNING: s = "Joining"; break; + case STATION_STATE_AUTHENTICATING: s = "Authenticating"; break; + case STATION_STATE_ASSOCIATING: s = "Associating"; break; + case STATION_STATE_READY: s = "Ready"; break; + case STATION_STATE_REASSOCIATING: s = "Reassociating"; break; + case STATION_STATE_FORCED_JOINNING: s = "Forced joining"; break; + case STATION_STATE_FORCED_JOIN_FAILURE: s = "Forced join failure"; break; + case STATION_STATE_NO_CARD: s = "No card"; break; + case STATION_STATE_MGMT_ERROR: s = "Management error"; break; + case STATION_STATE_DOWN: s = "Down"; break; + default: s = "<unknown>"; + } + + p += sprintf(p, "Current state:\t\t%s\n", s); + return p - buf; +} + +static int atmel_read_proc(char *page, char **start, off_t off, + int count, int *eof, void *data) +{ + struct atmel_private *priv = (struct atmel_private *)data; + int len = atmel_proc_output (page, priv); + if (len <= off+count) *eof = 1; + *start = page + off; + len -= off; + if (len>count) len = count; + if (len<0) len = 0; + return len; +} + +struct net_device *init_atmel_card( unsigned short irq, int port, char *firmware_id, int is3com, + struct device *sys_dev, int (*card_present)(void *), void *card) +{ + struct net_device *dev; + struct atmel_private *priv; + int rc; + + /* Create the network device object. */ + dev = alloc_etherdev(sizeof(*priv)); + if (!dev) { + printk(KERN_ERR "atmel: Couldn't alloc_etherdev\n"); + return NULL; + } + if (dev_alloc_name(dev, dev->name) < 0) { + printk(KERN_ERR "atmel: Couldn't get name!\n"); + goto err_out_free; + } + + priv = dev->priv; + priv->dev = dev; + priv->sys_dev = sys_dev; + priv->present_callback = card_present; + priv->card = card; + priv->firmware = NULL; + if (firmware) /* module parameter */ + strcpy(priv->firmware_id, firmware); + else if (firmware_id) /* from PCMCIA card-matching or PCI */ + strcpy(priv->firmware_id, firmware_id); + else + priv->firmware_id[0] = '\0'; + priv->bus_type = card_present ? BUS_TYPE_PCCARD : BUS_TYPE_PCI; + priv->station_state = STATION_STATE_DOWN; + priv->is3com = is3com; + priv->do_rx_crc = 0; + /* For PCMCIA cards, some chips need CRC, some don't + so we have to probe. */ + if (priv->bus_type == BUS_TYPE_PCCARD) { + priv->probe_crc = 1; + priv->crc_ok_cnt = priv->crc_ko_cnt = 0; + } else + priv->probe_crc = 0; + memset(&priv->stats, 0, sizeof(priv->stats)); + memset(&priv->wstats, 0, sizeof(priv->wstats)); + priv->last_qual = jiffies; + priv->last_beacon_timestamp = 0; + memset(priv->frag_source, 0xff, sizeof(priv->frag_source)); + memset(priv->BSSID, 0, 6); + priv->CurrentBSSID[0] = 0xFF; /* Initialize to something invalid.... */ + priv->station_was_associated = 0; + + priv->last_survey = jiffies; + priv->preamble = LONG_PREAMBLE; + priv->operating_mode = IW_MODE_INFRA; + priv->connect_to_any_BSS = 0; + priv->tx_rate = 3; + priv->auto_tx_rate = 1; + priv->channel = 4; + priv->power_mode = 0; + priv->SSID[0] = '\0'; + priv->SSID_size = 0; + priv->new_SSID_size = 0; + priv->frag_threshold = 2346; + priv->rts_threshold = 2347; + priv->short_retry = 7; + priv->long_retry = 4; + priv->wep.wep_is_on = 0; + priv->wep.default_key = 0; + priv->wep.encryption_level = 0; + priv->default_beacon_period = priv->beacon_period = 100; + priv->listen_interval = 1; + + init_timer(&priv->management_timer); + spin_lock_init(&priv->irqlock); + spin_lock_init(&priv->timerlock); + priv->management_timer.function = atmel_management_timer; + priv->management_timer.data = (unsigned long) dev; + + dev->open = atmel_open; + dev->stop = atmel_close; + dev->change_mtu = atmel_change_mtu; + dev->set_mac_address = atmel_set_mac_address; + dev->hard_start_xmit = start_tx; + dev->get_stats = atmel_get_stats; + dev->get_wireless_stats = atmel_get_wireless_stats; + dev->wireless_handlers = (struct iw_handler_def *)&atmel_handler_def; + dev->do_ioctl = atmel_ioctl; + dev->irq = irq; + dev->base_addr = port; + + if ((rc = request_irq(dev->irq, service_interrupt, SA_SHIRQ, dev->name, dev))) { + printk(KERN_ERR "%s: register interrupt %d failed, rc %d\n", dev->name, irq, rc ); + goto err_out_free; + } + + if (priv->bus_type == BUS_TYPE_PCI && + !request_region( dev->base_addr, 64, dev->name )) { + goto err_out_irq; + } + + if (register_netdev(dev)) + goto err_out_res; + + if (!probe_atmel_card(dev)) + goto err_out_res; + + create_proc_read_entry ("driver/atmel", 0, 0, atmel_read_proc, priv); + + printk(KERN_INFO "%s: Atmel at76c50x wireless. Version %d.%d simon@thekelleys.org.uk\n", + dev->name, DRIVER_MAJOR, DRIVER_MINOR); + + SET_MODULE_OWNER(dev); + return dev; + + err_out_res: + if (priv->bus_type == BUS_TYPE_PCI) + release_region( dev->base_addr, 64 ); + err_out_irq: + free_irq(dev->irq, dev); + err_out_free: + kfree(dev); + return NULL; +} + +EXPORT_SYMBOL(init_atmel_card); + +void stop_atmel_card(struct net_device *dev, int freeres) +{ + struct atmel_private *priv = dev->priv; + unregister_netdev(dev); + + /* put a brick on it... */ + + if (priv->bus_type == BUS_TYPE_PCCARD) + atmel_write16(dev, GCR, 0x0060); + atmel_write16(dev, GCR, 0x0040); + + remove_proc_entry("driver/atmel", NULL); + del_timer_sync(&priv->management_timer); + free_irq(dev->irq, dev); + if (priv->firmware) + kfree(priv->firmware); + if (freeres) { + /* PCMCIA frees this stuff, so only for PCI */ + release_region(dev->base_addr, 64); + } + kfree(dev); +} + +EXPORT_SYMBOL(stop_atmel_card); + +static const struct { + int reg_domain; + int min, max; +} channel_table[] = { { REG_DOMAIN_FCC, 1, 11}, + { REG_DOMAIN_DOC, 1, 11}, + { REG_DOMAIN_ETSI, 1, 13}, + { REG_DOMAIN_SPAIN, 10, 11}, + { REG_DOMAIN_FRANCE, 10, 13}, + { REG_DOMAIN_MKK, 14, 14}, + { REG_DOMAIN_MKK1, 1, 14}, + { REG_DOMAIN_ISRAEL, 9} }; + + +static int atmel_validate_channel(struct atmel_private *priv, int channel) +{ + /* check that channel is OK, if so return zero, + else return suitable default channel */ + int i; + + for (i = 0; i < sizeof(channel_table)/sizeof(channel_table[0]); i++) + if (priv->reg_domain == channel_table[i].reg_domain) { + if (channel >= channel_table[i].min && + channel <= channel_table[i].max) + return 0; + else + return channel_table[i].min; + } + return 1; +} + +static int atmel_set_essid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + /* Check if we asked for `any' */ + if(dwrq->flags == 0) { + priv->connect_to_any_BSS = 1; + } else { + int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + + priv->connect_to_any_BSS = 0; + + /* Check the size of the string */ + if (dwrq->length > MAX_SSID_LENGTH + 1) + return -E2BIG ; + if (index != 0) + return -EINVAL; + + memcpy(priv->new_SSID, extra, dwrq->length - 1); + priv->new_SSID_size = dwrq->length - 1; + } + + return -EINPROGRESS; +} + +static int atmel_get_essid(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + /* Get the current SSID */ + if (priv->SSID_size == 0) { + memcpy(extra, priv->new_SSID, priv->new_SSID_size); + extra[priv->new_SSID_size] = '\0'; + dwrq->length = priv->new_SSID_size + 1; + } else { + memcpy(extra, priv->SSID, priv->SSID_size); + extra[priv->SSID_size] = '\0'; + dwrq->length = priv->SSID_size + 1; + } + + dwrq->flags = !priv->connect_to_any_BSS; /* active */ + + return 0; +} + +static int atmel_get_wap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *awrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + memcpy(awrq->sa_data, priv->CurrentBSSID, 6); + awrq->sa_family = ARPHRD_ETHER; + + return 0; +} + +static int atmel_set_encode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + /* Basic checking: do we have a key to set ? + * Note : with the new API, it's impossible to get a NULL pointer. + * Therefore, we need to check a key size == 0 instead. + * New version of iwconfig properly set the IW_ENCODE_NOKEY flag + * when no key is present (only change flags), but older versions + * don't do it. - Jean II */ + if (dwrq->length > 0) { + int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + int current_index = priv->wep.default_key; + /* Check the size of the key */ + if (dwrq->length > 13) { + return -EINVAL; + } + /* Check the index (none -> use current) */ + if (index < 0 || index >= 4) + index = current_index; + else + priv->wep.default_key = index; + /* Set the length */ + if (dwrq->length > 5) + priv->wep_key_len[index] = 13; + else + if (dwrq->length > 0) + priv->wep_key_len[index] = 5; + else + /* Disable the key */ + priv->wep_key_len[index] = 0; + /* Check if the key is not marked as invalid */ + if(!(dwrq->flags & IW_ENCODE_NOKEY)) { + /* Cleanup */ + memset(priv->wep.wep_keys[index], 0, 13); + /* Copy the key in the driver */ + memcpy(priv->wep.wep_keys[index], extra, dwrq->length); + } + /* WE specify that if a valid key is set, encryption + * should be enabled (user may turn it off later) + * This is also how "iwconfig ethX key on" works */ + if (index == current_index && + priv->wep_key_len[index] > 0) { + priv->wep.wep_is_on = 1; + priv->wep.exclude_unencrypted = 1; + if (priv->wep_key_len[index] > 5) + priv->wep.encryption_level = 2; + else + priv->wep.encryption_level = 1; + } + } else { + /* Do we want to just set the transmit key index ? */ + int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + if ( index>=0 && index < 4 ) { + priv->wep.default_key = index; + } else + /* Don't complain if only change the mode */ + if(!dwrq->flags & IW_ENCODE_MODE) { + return -EINVAL; + } + } + /* Read the flags */ + if(dwrq->flags & IW_ENCODE_DISABLED) { + priv->wep.wep_is_on = 0; + priv->wep.encryption_level = 0; + } else { + priv->wep.wep_is_on = 1; + if (priv->wep_key_len[priv->wep.default_key] > 5) + priv->wep.encryption_level = 2; + else + priv->wep.encryption_level = 1; + } + if(dwrq->flags & IW_ENCODE_RESTRICTED) + priv->wep.exclude_unencrypted = 1; + if(dwrq->flags & IW_ENCODE_OPEN) + priv->wep.exclude_unencrypted = 0; + + return -EINPROGRESS; /* Call commit handler */ +} + + +static int atmel_get_encode(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; + + if (!priv->wep.wep_is_on) + dwrq->flags = IW_ENCODE_DISABLED; + else if (priv->wep.exclude_unencrypted) + dwrq->flags = IW_ENCODE_RESTRICTED; + else + dwrq->flags = IW_ENCODE_OPEN; + + /* Which key do we want ? -1 -> tx index */ + if (index < 0 || index >= 4) + index = priv->wep.default_key; + dwrq->flags |= index + 1; + /* Copy the key to the user buffer */ + dwrq->length = priv->wep_key_len[index]; + if (dwrq->length > 16) { + dwrq->length=0; + } else { + memset(extra, 0, 16); + memcpy(extra, priv->wep.wep_keys[index], dwrq->length); + } + + return 0; +} + +static int atmel_get_name(struct net_device *dev, + struct iw_request_info *info, + char *cwrq, + char *extra) +{ + strcpy(cwrq, "IEEE 802.11-DS"); + return 0; +} + +static int atmel_set_rate(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + if (vwrq->fixed == 0) { + priv->tx_rate = 3; + priv->auto_tx_rate = 1; + } else { + priv->auto_tx_rate = 0; + + /* Which type of value ? */ + if((vwrq->value < 4) && (vwrq->value >= 0)) { + /* Setting by rate index */ + priv->tx_rate = vwrq->value; + } else { + /* Setting by frequency value */ + switch (vwrq->value) { + case (int)1e6: priv->tx_rate = 0; break; + case (int)2e6: priv->tx_rate = 1; break; + case (int)5.5e6: priv->tx_rate = 2; break; + case (int)11e6: priv->tx_rate = 3; break; + default: return -EINVAL; + } + } + } + + return -EINPROGRESS; +} + +static int atmel_set_mode(struct net_device *dev, + struct iw_request_info *info, + __u32 *uwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + if (*uwrq != IW_MODE_ADHOC && *uwrq != IW_MODE_INFRA) + return -EINVAL; + + priv->operating_mode = *uwrq; + return -EINPROGRESS; +} + +static int atmel_get_mode(struct net_device *dev, + struct iw_request_info *info, + __u32 *uwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + *uwrq = priv->operating_mode; + return 0; +} + +static int atmel_get_rate(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + if (priv->auto_tx_rate) { + vwrq->fixed = 0; + vwrq->value = 11e6; + } else { + vwrq->fixed = 1; + switch(priv->tx_rate) { + case 0: vwrq->value = 1e6; break; + case 1: vwrq->value = 2e6; break; + case 2: vwrq->value = 5.5e6; break; + case 3: vwrq->value = 11e6; break; + } + } + return 0; +} + +static int atmel_set_power(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + priv->power_mode = vwrq->disabled ? 0 : 1; + return -EINPROGRESS; +} + +static int atmel_get_power(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + vwrq->disabled = priv->power_mode ? 0 : 1; + vwrq->flags = IW_POWER_ON; + return 0; +} + +static int atmel_set_retry(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + if(!vwrq->disabled && (vwrq->flags & IW_RETRY_LIMIT)) { + if(vwrq->flags & IW_RETRY_MAX) + priv->long_retry = vwrq->value; + else if (vwrq->flags & IW_RETRY_MIN) + priv->short_retry = vwrq->value; + else { + /* No modifier : set both */ + priv->long_retry = vwrq->value; + priv->short_retry = vwrq->value; + } + return -EINPROGRESS; + } + + return -EINVAL; +} + +static int atmel_get_retry(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + vwrq->disabled = 0; /* Can't be disabled */ + + /* Note : by default, display the min retry number */ + if((vwrq->flags & IW_RETRY_MAX)) { + vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; + vwrq->value = priv->long_retry; + } else { + vwrq->flags = IW_RETRY_LIMIT; + vwrq->value = priv->short_retry; + if(priv->long_retry != priv->short_retry) + vwrq->flags |= IW_RETRY_MIN; + } + + return 0; +} + +static int atmel_set_rts(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + int rthr = vwrq->value; + + if(vwrq->disabled) + rthr = 2347; + if((rthr < 0) || (rthr > 2347)) { + return -EINVAL; + } + priv->rts_threshold = rthr; + + return -EINPROGRESS; /* Call commit handler */ +} + +static int atmel_get_rts(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + vwrq->value = priv->rts_threshold; + vwrq->disabled = (vwrq->value >= 2347); + vwrq->fixed = 1; + + return 0; +} + +static int atmel_set_frag(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + int fthr = vwrq->value; + + if(vwrq->disabled) + fthr = 2346; + if((fthr < 256) || (fthr > 2346)) { + return -EINVAL; + } + fthr &= ~0x1; /* Get an even value - is it really needed ??? */ + priv->frag_threshold = fthr; + + return -EINPROGRESS; /* Call commit handler */ +} + +static int atmel_get_frag(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + vwrq->value = priv->frag_threshold; + vwrq->disabled = (vwrq->value >= 2346); + vwrq->fixed = 1; + + return 0; +} + +const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442, + 2447, 2452, 2457, 2462, 2467, 2472, 2484 }; + +static int atmel_set_freq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *fwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + int rc = -EINPROGRESS; /* Call commit handler */ + + /* If setting by frequency, convert to a channel */ + if((fwrq->e == 1) && + (fwrq->m >= (int) 2.412e8) && + (fwrq->m <= (int) 2.487e8)) { + int f = fwrq->m / 100000; + int c = 0; + while((c < 14) && (f != frequency_list[c])) + c++; + /* Hack to fall through... */ + fwrq->e = 0; + fwrq->m = c + 1; + } + /* Setting by channel number */ + if((fwrq->m > 1000) || (fwrq->e > 0)) + rc = -EOPNOTSUPP; + else { + int channel = fwrq->m; + if (atmel_validate_channel(priv, channel) == 0) { + priv->channel = channel; + } else { + rc = -EINVAL; + } + } + return rc; +} + +static int atmel_get_freq(struct net_device *dev, + struct iw_request_info *info, + struct iw_freq *fwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + fwrq->m = priv->channel; + fwrq->e = 0; + return 0; +} + +static int atmel_set_scan(struct net_device *dev, + struct iw_request_info *info, + struct iw_param *vwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + + /* Note : you may have realised that, as this is a SET operation, + * this is privileged and therefore a normal user can't + * perform scanning. + * This is not an error, while the device perform scanning, + * traffic doesn't flow, so it's a perfect DoS... + * Jean II */ + + if (priv->station_state == STATION_STATE_DOWN || + priv->station_state == STATION_STATE_NO_CARD) + return -EAGAIN; + + /* Timeout old surveys. */ + if ((jiffies - priv->last_survey) > (20 * HZ)) + priv->site_survey_state = SITE_SURVEY_IDLE; + priv->last_survey = jiffies; + + /* Initiate a scan command */ + if (priv->site_survey_state == SITE_SURVEY_IN_PROGRESS) + return -EBUSY; + + priv->site_survey_state = SITE_SURVEY_IN_PROGRESS; + + atmel_clear_gcr(dev, GCR_ENINT); /* disable interrupts */ + del_timer_sync(&priv->management_timer); + atmel_scan(priv, 0); + atmel_set_gcr(dev, GCR_ENINT); /* enable interrupts */ + + return 0; +} + +static int atmel_get_scan(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + int i; + char *current_ev = extra; + struct iw_event iwe; + + if (priv->site_survey_state != SITE_SURVEY_COMPLETED) + return -EAGAIN; + + for(i=0; i<priv->BSS_list_entries; i++) { + iwe.cmd = SIOCGIWAP; + iwe.u.ap_addr.sa_family = ARPHRD_ETHER; + memcpy(iwe.u.ap_addr.sa_data, priv->BSSinfo[i].BSSID, 6); + current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_ADDR_LEN); + + iwe.u.data.length = priv->BSSinfo[i].SSIDsize; + if (iwe.u.data.length > 32) + iwe.u.data.length = 32; + iwe.cmd = SIOCGIWESSID; + iwe.u.data.flags = 1; + current_ev = iwe_stream_add_point(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, priv->BSSinfo[i].SSID); + + iwe.cmd = SIOCGIWMODE; + iwe.u.mode = priv->BSSinfo[i].BSStype; + current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_UINT_LEN); + + iwe.cmd = SIOCGIWFREQ; + iwe.u.freq.m = priv->BSSinfo[i].channel; + iwe.u.freq.e = 0; + current_ev = iwe_stream_add_event(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, IW_EV_FREQ_LEN); + + iwe.cmd = SIOCGIWENCODE; + if (priv->BSSinfo[i].UsingWEP) + iwe.u.data.flags = IW_ENCODE_ENABLED | IW_ENCODE_NOKEY; + else + iwe.u.data.flags = IW_ENCODE_DISABLED; + iwe.u.data.length = 0; + current_ev = iwe_stream_add_point(current_ev, extra + IW_SCAN_MAX_DATA, &iwe, NULL); + + } + + /* Length of data */ + dwrq->length = (current_ev - extra); + dwrq->flags = 0; /* todo */ + + return 0; +} + +static int atmel_get_range(struct net_device *dev, + struct iw_request_info *info, + struct iw_point *dwrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + struct iw_range *range = (struct iw_range *) extra; + int k,i,j; + + dwrq->length = sizeof(struct iw_range); + memset(range, 0, sizeof(range)); + range->min_nwid = 0x0000; + range->max_nwid = 0x0000; + range->num_channels = 0; + for (j = 0; j < sizeof(channel_table)/sizeof(channel_table[0]); j++) + if (priv->reg_domain == channel_table[j].reg_domain) { + range->num_channels = channel_table[j].max - channel_table[j].min + 1; + } + if (range->num_channels != 0) { + for(k = 0, i = channel_table[j].min; i <= channel_table[j].max; i++) { + range->freq[k].i = i + 1; /* List index */ + range->freq[k].m = frequency_list[i] * 100000; + range->freq[k++].e = 1; /* Values in table in MHz -> * 10^5 * 10 */ + } + range->num_frequency = k; + } + + range->max_qual.qual = 100; + range->max_qual.level = 100; + range->max_qual.noise = 0; + range->sensitivity = 0; + + range->bitrate[0] = 1e6; + range->bitrate[1] = 2e6; + range->bitrate[2] = 5.5e6; + range->bitrate[3] = 11e6; + range->num_bitrates = 4; + + range->min_rts = 0; + range->max_rts = 2347; + range->min_frag = 256; + range->max_frag = 2346; + + range->encoding_size[0] = 5; + range->encoding_size[1] = 13; + range->num_encoding_sizes = 2; + range->max_encoding_tokens = 4; + + range->pmp_flags = IW_POWER_ON; + range->pmt_flags = IW_POWER_ON; + range->pm_capa = 0; + + range->we_version_source = WIRELESS_EXT; + range->we_version_compiled = WIRELESS_EXT; + range->retry_capa = IW_RETRY_LIMIT ; + range->retry_flags = IW_RETRY_LIMIT; + range->r_time_flags = 0; + range->min_retry = 1; + range->max_retry = 65535; + range->avg_qual.qual = 50; + range->avg_qual.level = 50; + range->avg_qual.noise = 0; + + return 0; +} + +static int atmel_set_wap(struct net_device *dev, + struct iw_request_info *info, + struct sockaddr *awrq, + char *extra) +{ + struct atmel_private *priv = dev->priv; + int i; + static const u8 bcast[] = { 255, 255, 255, 255, 255, 255 }; + + if (awrq->sa_family != ARPHRD_ETHER) + return -EINVAL; + + if (memcmp(bcast, awrq->sa_data, 6) == 0) { + atmel_clear_gcr(dev, GCR_ENINT); /* disable interrupts */ + del_timer_sync(&priv->management_timer); + atmel_scan(priv, 1); + atmel_set_gcr(dev, GCR_ENINT); /* enable interrupts */ + return 0; + } + + for(i=0; i<priv->BSS_list_entries; i++) { + if (memcmp(priv->BSSinfo[i].BSSID, awrq->sa_data, 6) == 0) { + if (!priv->wep.wep_is_on && priv->BSSinfo[i].UsingWEP) { + return -EINVAL; + } else if (priv->wep.wep_is_on && !priv->BSSinfo[i].UsingWEP) { + return -EINVAL; + } else + atmel_join_bss(priv, i); + return 0; + } + } + + return -EINVAL; +} + +static int atmel_config_commit(struct net_device *dev, + struct iw_request_info *info, /* NULL */ + void *zwrq, /* NULL */ + char *extra) /* NULL */ +{ + reset_atmel_card(dev); + return 0; +} + +static const iw_handler atmel_handler[] = +{ + (iw_handler) atmel_config_commit, /* SIOCSIWCOMMIT */ + (iw_handler) atmel_get_name, /* SIOCGIWNAME */ + (iw_handler) NULL, /* SIOCSIWNWID */ + (iw_handler) NULL, /* SIOCGIWNWID */ + (iw_handler) atmel_set_freq, /* SIOCSIWFREQ */ + (iw_handler) atmel_get_freq, /* SIOCGIWFREQ */ + (iw_handler) atmel_set_mode, /* SIOCSIWMODE */ + (iw_handler) atmel_get_mode, /* SIOCGIWMODE */ + (iw_handler) NULL, /* SIOCSIWSENS */ + (iw_handler) NULL, /* SIOCGIWSENS */ + (iw_handler) NULL, /* SIOCSIWRANGE */ + (iw_handler) atmel_get_range, /* SIOCGIWRANGE */ + (iw_handler) NULL, /* SIOCSIWPRIV */ + (iw_handler) NULL, /* SIOCGIWPRIV */ + (iw_handler) NULL, /* SIOCSIWSTATS */ + (iw_handler) NULL, /* SIOCGIWSTATS */ + (iw_handler) NULL, /* SIOCSIWSPY */ + (iw_handler) NULL, /* SIOCGIWSPY */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) atmel_set_wap, /* SIOCSIWAP */ + (iw_handler) atmel_get_wap, /* SIOCGIWAP */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* SIOCGIWAPLIST */ + (iw_handler) atmel_set_scan, /* SIOCSIWSCAN */ + (iw_handler) atmel_get_scan, /* SIOCGIWSCAN */ + (iw_handler) atmel_set_essid, /* SIOCSIWESSID */ + (iw_handler) atmel_get_essid, /* SIOCGIWESSID */ + (iw_handler) NULL, /* SIOCSIWNICKN */ + (iw_handler) NULL, /* SIOCGIWNICKN */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) NULL, /* -- hole -- */ + (iw_handler) atmel_set_rate, /* SIOCSIWRATE */ + (iw_handler) atmel_get_rate, /* SIOCGIWRATE */ + (iw_handler) atmel_set_rts, /* SIOCSIWRTS */ + (iw_handler) atmel_get_rts, /* SIOCGIWRTS */ + (iw_handler) atmel_set_frag, /* SIOCSIWFRAG */ + (iw_handler) atmel_get_frag, /* SIOCGIWFRAG */ + (iw_handler) NULL, /* SIOCSIWTXPOW */ + (iw_handler) NULL, /* SIOCGIWTXPOW */ + (iw_handler) atmel_set_retry, /* SIOCSIWRETRY */ + (iw_handler) atmel_get_retry, /* SIOCGIWRETRY */ + (iw_handler) atmel_set_encode, /* SIOCSIWENCODE */ + (iw_handler) atmel_get_encode, /* SIOCGIWENCODE */ + (iw_handler) atmel_set_power, /* SIOCSIWPOWER */ + (iw_handler) atmel_get_power, /* SIOCGIWPOWER */ +}; + + +static const iw_handler atmel_private_handler[] = +{ + NULL, /* SIOCIWFIRSTPRIV */ +}; + +typedef struct atmel_priv_ioctl { + char id[32]; + unsigned char *data; + unsigned short len; +} atmel_priv_ioctl; + + +#define ATMELFWL SIOCIWFIRSTPRIV +#define ATMELIDIFC ATMELFWL + 1 +#define ATMELMAGIC 0x51807 + +static const struct iw_priv_args atmel_private_args[] = { +/*{ cmd, set_args, get_args, name } */ + { ATMELFWL, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof (atmel_priv_ioctl), IW_PRIV_TYPE_NONE, "atmelfwl" }, + { ATMELIDIFC, IW_PRIV_TYPE_NONE, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, "atmelidifc" }, +}; + +static const struct iw_handler_def atmel_handler_def = +{ + .num_standard = sizeof(atmel_handler)/sizeof(iw_handler), + .num_private = sizeof(atmel_private_handler)/sizeof(iw_handler), + .num_private_args = sizeof(atmel_private_args)/sizeof(struct iw_priv_args), + .standard = (iw_handler *) atmel_handler, + .private = (iw_handler *) atmel_private_handler, + .private_args = (struct iw_priv_args *) atmel_private_args +}; + +static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + int rc = 0; + struct atmel_private *priv = (struct atmel_private *) dev->priv; + atmel_priv_ioctl com; + struct iwreq *wrq = (struct iwreq *) rq; + unsigned char *new_firmware; + + switch (cmd) { + case SIOCGIWPRIV: + if(wrq->u.data.pointer) { + /* Set the number of ioctl available */ + wrq->u.data.length = sizeof(atmel_private_args) / sizeof(atmel_private_args[0]); + + /* Copy structure to the user buffer */ + if (copy_to_user(wrq->u.data.pointer, + (u_char *) atmel_private_args, + sizeof(atmel_private_args))) + rc = -EFAULT; + } + break; + + case ATMELIDIFC: + wrq->u.param.value = ATMELMAGIC; + break; + + case ATMELFWL: + if (copy_from_user(&com, rq->ifr_data, sizeof(com))) { + rc = -EFAULT; + break; + } + + if (!capable(CAP_NET_ADMIN)) { + rc = -EPERM; + break; + } + + if (!(new_firmware = kmalloc(com.len, GFP_KERNEL))) { + rc = -ENOMEM; + break; + } + + if (copy_from_user(new_firmware, com.data, com.len)) { + rc = -EFAULT; + break; + } + + if (priv->firmware) + kfree(priv->firmware); + + priv->firmware = new_firmware; + priv->firmware_length = com.len; + strncpy(priv->firmware_id, com.id, 31); + priv->firmware_id[31] = '\0'; + break; + + default: + rc = -EOPNOTSUPP; + } + + return rc; +} + +struct auth_body { + u16 alg; + u16 trans_seq; + u16 status; + u8 el_id; + u8 chall_text_len; + u8 chall_text[253]; +}; + +static void atmel_enter_state(struct atmel_private *priv, int new_state) +{ + int old_state = priv->station_state; + + if (new_state == old_state) + return; + + if (new_state == STATION_STATE_READY) + netif_start_queue(priv->dev); + + if (old_state == STATION_STATE_READY) { + netif_stop_queue(priv->dev); + priv->last_beacon_timestamp = 0; + } + + priv->station_state = new_state; + +} + +static void atmel_scan(struct atmel_private *priv, int specific_ssid) +{ + struct { + u8 BSSID[6]; + u8 SSID[MAX_SSID_LENGTH]; + u8 scan_type; + u8 channel; + u16 BSS_type; + u16 min_channel_time; + u16 max_channel_time; + u8 options; + u8 SSID_size; + } cmd; + + atmel_enter_state(priv, STATION_STATE_SCANNING); + + memset(cmd.BSSID, 0xff, 6); + + if (priv->fast_scan) { + cmd.SSID_size = priv->SSID_size; + memcpy(cmd.SSID, priv->SSID, priv->SSID_size); + cmd.min_channel_time = cpu_to_le16(10); + cmd.max_channel_time = cpu_to_le16(50); + } else { + priv->BSS_list_entries = 0; + cmd.SSID_size = 0; + cmd.min_channel_time = cpu_to_le16(10); + cmd.max_channel_time = cpu_to_le16(120); + } + + cmd.options = 0; + + if (!specific_ssid) + cmd.options |= SCAN_OPTIONS_SITE_SURVEY; + + cmd.channel = (priv->channel & 0x7f); + cmd.scan_type = SCAN_TYPE_ACTIVE; + cmd.BSS_type = cpu_to_le16(priv->operating_mode == IW_MODE_ADHOC ? + BSS_TYPE_AD_HOC : BSS_TYPE_INFRASTRUCTURE); + + atmel_send_command(priv, CMD_Scan, &cmd, sizeof(cmd)); +} + +static void join(struct atmel_private *priv, int type) +{ + struct { + u8 BSSID[6]; + u8 SSID[MAX_SSID_LENGTH]; + u8 BSS_type; /* this is a short in a scan command - wierd */ + u8 channel; + u16 timeout; + u8 SSID_size; + u8 reserved; + } cmd; + + cmd.SSID_size = priv->SSID_size; + memcpy(cmd.SSID, priv->SSID, priv->SSID_size); + memcpy(cmd.BSSID, priv->CurrentBSSID, 6); + cmd.channel = (priv->channel & 0x7f); + cmd.BSS_type = type; + cmd.timeout = cpu_to_le16(2000); + + atmel_send_command(priv, CMD_Join, &cmd, sizeof(cmd)); +} + + +static void start(struct atmel_private *priv, int type) +{ + struct { + u8 BSSID[6]; + u8 SSID[MAX_SSID_LENGTH]; + u8 BSS_type; + u8 channel; + u8 SSID_size; + u8 reserved[3]; + } cmd; + + cmd.SSID_size = priv->SSID_size; + memcpy(cmd.SSID, priv->SSID, priv->SSID_size); + memcpy(cmd.BSSID, priv->BSSID, 6); + cmd.BSS_type = type; + cmd.channel = (priv->channel & 0x7f); + + atmel_send_command(priv, CMD_Start, &cmd, sizeof(cmd)); +} + +static void handle_beacon_probe(struct atmel_private *priv, u16 capability, u8 channel) +{ + int rejoin = 0; + int new = capability & C80211_MGMT_CAPABILITY_ShortPreamble ? + SHORT_PREAMBLE : LONG_PREAMBLE; + + if (priv->preamble != new) { + priv->preamble = new; + rejoin = 1; + atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_PREAMBLE_TYPE, new); + } + + if (priv->channel != channel) { + priv->channel = channel; + rejoin = 1; + atmel_set_mib8(priv, Phy_Mib_Type, PHY_MIB_CHANNEL_POS, channel); + } + + if (rejoin) { + priv->station_is_associated = 0; + atmel_enter_state(priv, STATION_STATE_JOINNING); + + if (priv->operating_mode == IW_MODE_INFRA) + join(priv, BSS_TYPE_INFRASTRUCTURE); + else + join(priv, BSS_TYPE_AD_HOC); + } +} + + +static void send_authentication_request(struct atmel_private *priv, u8 *challenge, int challenge_len) +{ + struct ieee802_11_hdr header; + struct auth_body auth; + + header.frame_ctl = cpu_to_le16(IEEE802_11_FTYPE_MGMT | IEEE802_11_STYPE_AUTH); + header.duration_id = cpu_to_le16(0x8000); + header.seq_ctl = 0; + memcpy(header.addr1, priv->CurrentBSSID, 6); + memcpy(header.addr2, priv->dev->dev_addr, 6); + memcpy(header.addr3, priv->CurrentBSSID, 6); + + if (priv->wep.wep_is_on) { + auth.alg = C80211_MGMT_AAN_SHAREDKEY; + /* no WEP for authentication frames with TrSeqNo 1 */ + if (priv->CurrentAuthentTransactionSeqNum != 1) + header.frame_ctl |= cpu_to_le16(IEEE802_11_FCTL_WEP); + } else { + auth.alg = C80211_MGMT_AAN_OPENSYSTEM; + } + + auth.status = 0; + auth.trans_seq = cpu_to_le16(priv->CurrentAuthentTransactionSeqNum); + priv->ExpectedAuthentTransactionSeqNum = priv->CurrentAuthentTransactionSeqNum+1; + priv->CurrentAuthentTransactionSeqNum += 2; + + if (challenge_len != 0) { + auth.el_id = 16; /* challenge_text */ + auth.chall_text_len = challenge_len; + memcpy(auth.chall_text, challenge, challenge_len); + atmel_transmit_management_frame(priv, &header, (u8 *)&auth, 8 + challenge_len); + } else { + atmel_transmit_management_frame(priv, &header, (u8 *)&auth, 6); + } +} + +static void send_association_request(struct atmel_private *priv, int is_reassoc) +{ + u8 *ssid_el_p; + int bodysize; + struct ieee802_11_hdr header; + struct ass_req_format { + u16 capability; + u16 listen_interval; + u8 ap[6]; /* nothing after here directly accessible */ + u8 ssid_el_id; + u8 ssid_len; + u8 ssid[MAX_SSID_LENGTH]; + u8 sup_rates_el_id; + u8 sup_rates_len; + u8 rates[4]; + } body; + + header.frame_ctl = cpu_to_le16(IEEE802_11_FTYPE_MGMT | + (is_reassoc ? IEEE802_11_STYPE_REASSOC_REQ : IEEE802_11_STYPE_ASSOC_REQ)); + header.duration_id = cpu_to_le16(0x8000); + header.seq_ctl = 0; + + memcpy(header.addr1, priv->CurrentBSSID, 6); + memcpy(header.addr2, priv->dev->dev_addr, 6); + memcpy(header.addr3, priv->CurrentBSSID, 6); + + body.capability = cpu_to_le16(C80211_MGMT_CAPABILITY_ESS); + if (priv->wep.wep_is_on) + body.capability |= cpu_to_le16(C80211_MGMT_CAPABILITY_Privacy); + if (priv->preamble == SHORT_PREAMBLE) + body.capability |= cpu_to_le16(C80211_MGMT_CAPABILITY_ShortPreamble); + + body.listen_interval = cpu_to_le16(priv->listen_interval * priv->beacon_period); + + /* current AP address - only in reassoc frame */ + if (is_reassoc) { + memcpy(body.ap, priv->CurrentBSSID, 6); + ssid_el_p = (u8 *)&body.ssid_el_id; + bodysize = 18 + priv->SSID_size; + } else { + ssid_el_p = (u8 *)&body.ap[0]; + bodysize = 12 + priv->SSID_size; + } + + ssid_el_p[0]= C80211_MGMT_ElementID_SSID; + ssid_el_p[1] = priv->SSID_size; + memcpy(ssid_el_p + 2, priv->SSID, priv->SSID_size); + ssid_el_p[2 + priv->SSID_size] = C80211_MGMT_ElementID_SupportedRates; + ssid_el_p[3 + priv->SSID_size] = 4; /* len of suported rates */ + memcpy(ssid_el_p + 4 + priv->SSID_size, atmel_basic_rates, 4); + + atmel_transmit_management_frame(priv, &header, (void *)&body, bodysize); +} + +static int is_frame_from_current_bss(struct atmel_private *priv, struct ieee802_11_hdr *header) +{ + if (le16_to_cpu(header->frame_ctl) & IEEE802_11_FCTL_FROMDS) + return memcmp(header->addr3, priv->CurrentBSSID, 6) == 0; + else + return memcmp(header->addr2, priv->CurrentBSSID, 6) == 0; +} + +static int retrieve_bss(struct atmel_private *priv) +{ + int i; + int max_rssi = -128; + int max_index = -1; + + if (priv->BSS_list_entries == 0) + return -1; + + if (priv->connect_to_any_BSS) { + /* Select a BSS with the max-RSSI but of the same type and of the same WEP mode + and that it is not marked as 'bad' (i.e. we had previously failed to connect to + this BSS with the settings that we currently use) */ + priv->current_BSS = 0; + for(i=0; i<priv->BSS_list_entries; i++) { + if (priv->operating_mode == priv->BSSinfo[i].BSStype && + ((!priv->wep.wep_is_on && !priv->BSSinfo[i].UsingWEP) || + (priv->wep.wep_is_on && priv->BSSinfo[i].UsingWEP)) && + !(priv->BSSinfo[i].channel & 0x80)) { + max_rssi = priv->BSSinfo[i].RSSI; + priv->current_BSS = max_index = i; + } + + } + return max_index; + } + + for(i=0; i<priv->BSS_list_entries; i++) { + if (priv->SSID_size == priv->BSSinfo[i].SSIDsize && + memcmp(priv->SSID, priv->BSSinfo[i].SSID, priv->SSID_size) == 0 && + priv->operating_mode == priv->BSSinfo[i].BSStype && + atmel_validate_channel(priv, priv->BSSinfo[i].channel) == 0) { + if (priv->BSSinfo[i].RSSI >= max_rssi) { + max_rssi = priv->BSSinfo[i].RSSI; + max_index = i; + } + } + } + return max_index; +} + + +static void store_bss_info(struct atmel_private *priv, struct ieee802_11_hdr *header, + u16 capability, u16 beacon_period, u8 channel, u8 rssi, + u8 ssid_len, u8 *ssid, int is_beacon) +{ + u8 *bss = capability & C80211_MGMT_CAPABILITY_ESS ? header->addr2 : header->addr3; + int i, index; + + for (index = -1, i = 0; i < priv->BSS_list_entries; i++) + if (memcmp(bss, priv->BSSinfo[i].BSSID, 6) == 0) + index = i; + + /* If we process a probe and an entry from this BSS exists + we will update the BSS entry with the info from this BSS. + If we process a beacon we will only update RSSI */ + + if (index == -1) { + if (priv->BSS_list_entries == MAX_BSS_ENTRIES) + return; + index = priv->BSS_list_entries++; + memcpy(priv->BSSinfo[index].BSSID, bss, 6); + priv->BSSinfo[index].RSSI = rssi; + } else { + if (rssi > priv->BSSinfo[index].RSSI) + priv->BSSinfo[index].RSSI = rssi; + if (is_beacon) + return; + } + + priv->BSSinfo[index].channel = channel; + priv->BSSinfo[index].beacon_period = beacon_period; + priv->BSSinfo[index].UsingWEP = capability & C80211_MGMT_CAPABILITY_Privacy; + memcpy(priv->BSSinfo[index].SSID, ssid, ssid_len); + priv->BSSinfo[index].SSIDsize = ssid_len; + + if (capability & C80211_MGMT_CAPABILITY_IBSS) + priv->BSSinfo[index].BSStype = IW_MODE_ADHOC; + else if (capability & C80211_MGMT_CAPABILITY_ESS) + priv->BSSinfo[index].BSStype =IW_MODE_INFRA; + + priv->BSSinfo[index].preamble = capability & C80211_MGMT_CAPABILITY_ShortPreamble ? + SHORT_PREAMBLE : LONG_PREAMBLE; +} + +static void authenticate(struct atmel_private *priv, u16 frame_len) +{ + struct auth_body *auth = (struct auth_body *)priv->rx_buf; + u16 status = le16_to_cpu(auth->status); + u16 trans_seq_no = le16_to_cpu(auth->trans_seq); + + if (status == C80211_MGMT_SC_Success && !priv->wep.wep_is_on) { + /* no WEP */ + if (priv->station_was_associated) { + atmel_enter_state(priv, STATION_STATE_REASSOCIATING); + send_association_request(priv, 1); + return; + } else { + atmel_enter_state(priv, STATION_STATE_ASSOCIATING); + send_association_request(priv, 0); + return; + } + } + + if (status == C80211_MGMT_SC_Success && priv->wep.wep_is_on) { + /* WEP */ + if (trans_seq_no != priv->ExpectedAuthentTransactionSeqNum) + return; + + if (trans_seq_no == 0x0002 && + auth->el_id == C80211_MGMT_ElementID_ChallengeText) { + send_authentication_request(priv, auth->chall_text, auth->chall_text_len); + return; + } + + if (trans_seq_no == 0x0004) { + if(priv->station_was_associated) { + atmel_enter_state(priv, STATION_STATE_REASSOCIATING); + send_association_request(priv, 1); + return; + } else { + atmel_enter_state(priv, STATION_STATE_ASSOCIATING); + send_association_request(priv, 0); + return; + } + } + } + + if (status == C80211_MGMT_SC_AuthAlgNotSupported && priv->connect_to_any_BSS) { + int bss_index; + + priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80; + + if ((bss_index = retrieve_bss(priv)) != -1) { + atmel_join_bss(priv, bss_index); + return; + } + } + + + priv->AuthenticationRequestRetryCnt = 0; + atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); + priv->station_is_associated = 0; +} + +static void associate(struct atmel_private *priv, u16 frame_len, u16 subtype) +{ + struct ass_resp_format { + u16 capability; + u16 status; + u16 ass_id; + u8 el_id; + u8 length; + u8 rates[4]; + } *ass_resp = (struct ass_resp_format *)priv->rx_buf; + + u16 status = le16_to_cpu(ass_resp->status); + u16 ass_id = le16_to_cpu(ass_resp->ass_id); + u16 rates_len = ass_resp->length > 4 ? 4 : ass_resp->length; + + if (frame_len < 8 + rates_len) + return; + + if (status == C80211_MGMT_SC_Success) { + if (subtype == C80211_SUBTYPE_MGMT_ASS_RESPONSE) + priv->AssociationRequestRetryCnt = 0; + else + priv->ReAssociationRequestRetryCnt = 0; + + atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_STATION_ID_POS, ass_id & 0x3fff); + atmel_set_mib(priv, Phy_Mib_Type, PHY_MIB_RATE_SET_POS, ass_resp->rates, rates_len); + if (priv->power_mode == 0) { + priv->listen_interval = 1; + atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE); + atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1); + } else { + priv->listen_interval = 2; + atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_PS_MODE_POS, PS_MODE); + atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 2); + } + + priv->station_is_associated = 1; + priv->station_was_associated = 1; + atmel_enter_state(priv, STATION_STATE_READY); + return; + } + + if (subtype == C80211_SUBTYPE_MGMT_ASS_RESPONSE && + status != C80211_MGMT_SC_AssDeniedBSSRate && + status != C80211_MGMT_SC_SupportCapabilities && + priv->AssociationRequestRetryCnt < MAX_ASSOCIATION_RETRIES) { + mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); + priv->AssociationRequestRetryCnt++; + send_association_request(priv, 0); + return; + } + + if (subtype == C80211_SUBTYPE_MGMT_REASS_RESPONSE && + status != C80211_MGMT_SC_AssDeniedBSSRate && + status != C80211_MGMT_SC_SupportCapabilities && + priv->AssociationRequestRetryCnt < MAX_ASSOCIATION_RETRIES) { + mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); + priv->ReAssociationRequestRetryCnt++; + send_association_request(priv, 1); + return; + } + + atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); + priv->station_is_associated = 0; + + if(priv->connect_to_any_BSS) { + int bss_index; + priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80; + + if ((bss_index = retrieve_bss(priv)) != -1) + atmel_join_bss(priv, bss_index); + + } +} + +void atmel_join_bss(struct atmel_private *priv, int bss_index) +{ + struct bss_info *bss = &priv->BSSinfo[bss_index]; + + memcpy(priv->CurrentBSSID, bss->BSSID, 6); + memcpy(priv->SSID, bss->SSID, priv->SSID_size = bss->SSIDsize); + + /* When switching to AdHoc turn OFF Power Save if needed */ + + if (bss->BSStype == IW_MODE_ADHOC && + priv->operating_mode != IW_MODE_ADHOC && + priv->power_mode) { + priv->power_mode = 0; + priv->listen_interval = 1; + atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE); + atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1); + } + + priv->operating_mode = bss->BSStype; + priv->channel = bss->channel & 0x7f; + priv->beacon_period = bss->beacon_period; + + if (priv->preamble != bss->preamble) { + priv->preamble = bss->preamble; + atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_PREAMBLE_TYPE, bss->preamble); + } + + if (!priv->wep.wep_is_on && bss->UsingWEP) { + atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); + priv->station_is_associated = 0; + return; + } + + if (priv->wep.wep_is_on && !bss->UsingWEP) { + atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); + priv->station_is_associated = 0; + return; + } + + atmel_enter_state(priv, STATION_STATE_JOINNING); + + if (priv->operating_mode == IW_MODE_INFRA) + join(priv, BSS_TYPE_INFRASTRUCTURE); + else + join(priv, BSS_TYPE_AD_HOC); +} + + +static void restart_search(struct atmel_private *priv) +{ + int bss_index; + + if (!priv->connect_to_any_BSS) { + atmel_scan(priv, 1); + } else { + priv->BSSinfo[(int)(priv->current_BSS)].channel |= 0x80; + + if ((bss_index = retrieve_bss(priv)) != -1) + atmel_join_bss(priv, bss_index); + else + atmel_scan(priv, 0); + + } +} + +static void smooth_rssi(struct atmel_private *priv, u8 rssi) +{ + u8 old = priv->wstats.qual.level; + + /* 502-rmfd-revd gives max signal level as 42, by experiment. + This is going to break for other hardware variants. */ + + rssi = rssi * 100 / 42; + if((rssi + old) % 2) + priv->wstats.qual.level = ((rssi + old)/2) + 1; + else + priv->wstats.qual.level = ((rssi + old)/2); + +} + +static void atmel_smooth_qual(struct atmel_private *priv) +{ + unsigned long time_diff = (jiffies - priv->last_qual)/HZ; + while (time_diff--) { + priv->last_qual += HZ; + priv->wstats.qual.qual = priv->wstats.qual.qual/2; + priv->wstats.qual.qual += + priv->beacons_this_sec * priv->beacon_period * (priv->wstats.qual.level + 100) / 4000; + priv->beacons_this_sec = 0; + } +} + +/* deals with incoming managment frames. */ +static void atmel_management_frame(struct atmel_private *priv, struct ieee802_11_hdr *header, + u16 frame_len, u8 rssi) +{ + u16 subtype; + + switch (subtype = le16_to_cpu(header->frame_ctl) & IEEE802_11_FCTL_STYPE) { + case C80211_SUBTYPE_MGMT_BEACON : + case C80211_SUBTYPE_MGMT_ProbeResponse: + + /* beacon frame has multiple variable-length fields - + never let an engineer loose with a data structure design. */ + { + struct beacon_format { + u64 timestamp; + u16 interval; + u16 capability; + u8 ssid_el_id; + u8 ssid_length; + /* ssid here */ + u8 rates_el_id; + u8 rates_length; + /* rates here */ + u8 ds_el_id; + u8 ds_length; + /* ds here */ + } *beacon = (struct beacon_format *)priv->rx_buf; + + u8 channel, rates_length, ssid_length; + u64 timestamp = le64_to_cpu(beacon->timestamp); + u16 beacon_interval = le16_to_cpu(beacon->interval); + u16 capability = le16_to_cpu(beacon->capability); + u8 *beaconp = priv->rx_buf; + ssid_length = beacon->ssid_length; + /* this blows chunks. */ + if (frame_len < 14 || frame_len < ssid_length + 15) + return; + rates_length = beaconp[beacon->ssid_length + 15]; + if (frame_len < ssid_length + rates_length + 18) + return; + if (ssid_length > MAX_SSID_LENGTH) + return; + channel = beaconp[ssid_length + rates_length + 18]; + + if (priv->station_state == STATION_STATE_READY) { + smooth_rssi(priv, rssi); + if (is_frame_from_current_bss(priv, header)) { + priv->beacons_this_sec++; + atmel_smooth_qual(priv); + if (priv->last_beacon_timestamp) { + /* Note truncate this to 32 bits - kernel can't divide a long long */ + u32 beacon_delay = timestamp - priv->last_beacon_timestamp; + int beacons = beacon_delay / (beacon_interval * 1000); + if (beacons > 1) + priv->wstats.miss.beacon += beacons - 1; + } + priv->last_beacon_timestamp = timestamp; + handle_beacon_probe(priv, capability, channel); + } + } + + if (priv->station_state == STATION_STATE_SCANNING ) + store_bss_info(priv, header, capability, beacon_interval, channel, + rssi, ssid_length, &beacon->rates_el_id, + subtype == C80211_SUBTYPE_MGMT_BEACON) ; + } + break; + + case C80211_SUBTYPE_MGMT_Authentication: + + if (priv->station_state == STATION_STATE_AUTHENTICATING) + authenticate(priv, frame_len); + + break; + + case C80211_SUBTYPE_MGMT_ASS_RESPONSE: + case C80211_SUBTYPE_MGMT_REASS_RESPONSE: + + if (priv->station_state == STATION_STATE_ASSOCIATING || + priv->station_state == STATION_STATE_REASSOCIATING) + associate(priv, frame_len, subtype); + + break; + + case C80211_SUBTYPE_MGMT_DISASSOSIATION: + if (priv->station_is_associated && + priv->operating_mode == IW_MODE_INFRA && + is_frame_from_current_bss(priv, header)) { + priv->station_was_associated = 0; + priv->station_is_associated = 0; + + atmel_enter_state(priv, STATION_STATE_JOINNING); + join(priv, BSS_TYPE_INFRASTRUCTURE); + } + + break; + + case C80211_SUBTYPE_MGMT_Deauthentication: + if (priv->operating_mode == IW_MODE_INFRA && + is_frame_from_current_bss(priv, header)) { + priv->station_was_associated = 0; + + atmel_enter_state(priv, STATION_STATE_JOINNING); + join(priv, BSS_TYPE_INFRASTRUCTURE); + } + + break; + } +} + +/* run when timer expires */ +static void atmel_management_timer(u_long a) +{ + struct net_device *dev = (struct net_device *) a; + struct atmel_private *priv = (struct atmel_private *)dev->priv; + unsigned long flags; + + /* Check if the card has been yanked. */ + if (priv->card && priv->present_callback && + !(*priv->present_callback)(priv->card)) + return; + + if (priv->station_state == STATION_STATE_NO_CARD) + return; + + spin_lock_irqsave(&priv->irqlock, flags); + + switch (priv->station_state) { + + case STATION_STATE_AUTHENTICATING: + + if (priv->AuthenticationRequestRetryCnt >= MAX_AUTHENTICATION_RETRIES) { + atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); + priv->station_is_associated = 0; + priv->AuthenticationRequestRetryCnt = 0; + restart_search(priv); + } else { + priv->AuthenticationRequestRetryCnt++; + priv->CurrentAuthentTransactionSeqNum = 0x0001; + mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); + send_authentication_request(priv, NULL, 0); + } + + break; + + case STATION_STATE_ASSOCIATING: + + if (priv->AssociationRequestRetryCnt == MAX_ASSOCIATION_RETRIES) { + atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); + priv->station_is_associated = 0; + priv->AssociationRequestRetryCnt = 0; + restart_search(priv); + } else { + priv->AssociationRequestRetryCnt++; + mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); + send_association_request(priv, 0); + } + + break; + + case STATION_STATE_REASSOCIATING: + + if (priv->ReAssociationRequestRetryCnt == MAX_ASSOCIATION_RETRIES) { + atmel_enter_state(priv, STATION_STATE_MGMT_ERROR); + priv->station_is_associated = 0; + priv->ReAssociationRequestRetryCnt = 0; + restart_search(priv); + } else { + priv->ReAssociationRequestRetryCnt++; + mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); + send_association_request(priv, 1); + } + + break; + + default: + break; + } + + spin_unlock_irqrestore(&priv->irqlock, flags); +} + +static void atmel_command_irq(struct atmel_private *priv) +{ + u8 status = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET)); + u8 command = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_COMMAND_OFFSET)); + int fast_scan; + + if (status == CMD_STATUS_IDLE || + status == CMD_STATUS_IN_PROGRESS) + return; + + switch (command){ + + case CMD_Start: + if (status == CMD_STATUS_COMPLETE) { + priv->station_was_associated = priv->station_is_associated; + atmel_get_mib(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_BSSID_POS, + (u8 *)priv->CurrentBSSID, 6); + atmel_enter_state(priv, STATION_STATE_READY); + } + break; + + case CMD_Scan: + fast_scan = priv->fast_scan; + priv->fast_scan = 0; + + if (status != CMD_STATUS_COMPLETE) { + atmel_scan(priv, 1); + } else { + int bss_index = retrieve_bss(priv); + if (bss_index != -1) { + atmel_join_bss(priv, bss_index); + } else if (priv->operating_mode == IW_MODE_ADHOC && + priv->SSID_size != 0) { + start(priv, BSS_TYPE_AD_HOC); + } else { + priv->fast_scan = !fast_scan; + atmel_scan(priv, 1); + } + } + break; + + case CMD_SiteSurvey: + priv->fast_scan = 0; + + if (status != CMD_STATUS_COMPLETE) + return; + + priv->site_survey_state = SITE_SURVEY_COMPLETED; + if (priv->station_is_associated) { + atmel_enter_state(priv, STATION_STATE_READY); + } else { + atmel_scan(priv, 1); + } + break; + + case CMD_Join: + if (status == CMD_STATUS_COMPLETE) { + if (priv->operating_mode == IW_MODE_ADHOC) { + priv->station_was_associated = priv->station_is_associated; + atmel_enter_state(priv, STATION_STATE_READY); + } else { + priv->AuthenticationRequestRetryCnt = 0; + atmel_enter_state(priv, STATION_STATE_AUTHENTICATING); + + mod_timer(&priv->management_timer, jiffies + MGMT_JIFFIES); + priv->CurrentAuthentTransactionSeqNum = 0x0001; + send_authentication_request(priv, NULL, 0); + } + return; + } + + + if (priv->station_state == STATION_STATE_FORCED_JOINNING) { + atmel_enter_state(priv, STATION_STATE_FORCED_JOIN_FAILURE); + } else { + atmel_scan(priv, 1); + } + } +} + +static int atmel_wakeup_firmware(struct atmel_private *priv) +{ + struct host_info_struct *iface = &priv->host_info; + u16 mr1, mr3; + int i; + + if (priv->card_type == CARD_TYPE_SPI_FLASH) + atmel_set_gcr(priv->dev, GCR_REMAP); + + /* wake up on-board processor */ + atmel_clear_gcr(priv->dev, 0x0040); + atmel_write16(priv->dev, BSR, BSS_SRAM); + + if (priv->card_type == CARD_TYPE_SPI_FLASH) + mdelay(100); + + /* and wait for it */ + for (i = LOOP_RETRY_LIMIT; i; i--) { + mr1 = atmel_read16(priv->dev, MR1); + mr3 = atmel_read16(priv->dev, MR3); + + if (mr3 & MAC_BOOT_COMPLETE) + break; + if (mr1 & MAC_BOOT_COMPLETE && + priv->bus_type == BUS_TYPE_PCCARD) + break; + } + + if (i == 0) { + printk(KERN_ALERT "%s: MAC failed to boot.\n", priv->dev->name); + return 0; + } + + if ((priv->host_info_base = atmel_read16(priv->dev, MR2)) == 0xffff) { + printk(KERN_ALERT "%s: card missing.\n", priv->dev->name); + priv->station_state = STATION_STATE_NO_CARD; + return 0; + } + + /* now check for completion of MAC initialization through + the FunCtrl field of the IFACE, poll MR1 to detect completion of + MAC initialization, check completion status, set interrupt mask, + enables interrupts and calls Tx and Rx initialization functions */ + + atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET), FUNC_CTRL_INIT_COMPLETE); + + for (i = LOOP_RETRY_LIMIT; i; i--) { + mr1 = atmel_read16(priv->dev, MR1); + mr3 = atmel_read16(priv->dev, MR3); + + if (mr3 & MAC_INIT_COMPLETE) + break; + if (mr1 & MAC_INIT_COMPLETE && + priv->bus_type == BUS_TYPE_PCCARD) + break; + } + + if (i == 0) { + printk(KERN_ALERT "%s: MAC failed to initialise.\n", priv->dev->name); + return 0; + } + + /* Check for MAC_INIT_OK only on the register that the MAC_INIT_OK was set */ + if ((mr3 & MAC_INIT_COMPLETE) && + !(atmel_read16(priv->dev, MR3) & MAC_INIT_OK)) { + printk(KERN_ALERT "%s: MAC failed MR3 self-test.\n", priv->dev->name); + return 0; + } + if ((mr1 & MAC_INIT_COMPLETE) && + !(atmel_read16(priv->dev, MR1) & MAC_INIT_OK)) { + printk(KERN_ALERT "%s: MAC failed MR1 self-test.\n", priv->dev->name); + return 0; + } + + atmel_copy_to_host(priv->dev, (unsigned char *)iface, + priv->host_info_base, sizeof(*iface)); + + iface->tx_buff_pos = le16_to_cpu(iface->tx_buff_pos); + iface->tx_buff_size = le16_to_cpu(iface->tx_buff_size); + iface->tx_desc_pos = le16_to_cpu(iface->tx_desc_pos); + iface->tx_desc_count = le16_to_cpu(iface->tx_desc_count); + iface->rx_buff_pos = le16_to_cpu(iface->rx_buff_pos); + iface->rx_buff_size = le16_to_cpu(iface->rx_buff_size); + iface->rx_desc_pos = le16_to_cpu(iface->rx_desc_pos); + iface->rx_desc_count = le16_to_cpu(iface->rx_desc_count); + iface->build_version = le16_to_cpu(iface->build_version); + iface->command_pos = le16_to_cpu(iface->command_pos); + iface->major_version = le16_to_cpu(iface->major_version); + iface->minor_version = le16_to_cpu(iface->minor_version); + iface->func_ctrl = le16_to_cpu(iface->func_ctrl); + iface->mac_status = le16_to_cpu(iface->mac_status); + + return 1; +} + +/* determine type of memory and MAC address */ +static int probe_atmel_card(struct net_device *dev) +{ + int rc = 0; + struct atmel_private *priv = dev->priv; + + /* reset pccard */ + if (priv->bus_type == BUS_TYPE_PCCARD) + atmel_write16(dev, GCR, 0x0060); + + atmel_write16(dev, GCR, 0x0040); + mdelay(500); + + if (atmel_read16(dev, MR2) == 0) { + /* No stored firmware so load a small stub which just + tells us the MAC address */ + int i; + priv->card_type = CARD_TYPE_EEPROM; + atmel_write16(dev, BSR, BSS_IRAM); + atmel_copy_to_card(dev, 0, mac_reader, sizeof(mac_reader)); + atmel_set_gcr(dev, GCR_REMAP); + atmel_clear_gcr(priv->dev, 0x0040); + atmel_write16(dev, BSR, BSS_SRAM); + for (i = LOOP_RETRY_LIMIT; i; i--) + if (atmel_read16(dev, MR3) & MAC_BOOT_COMPLETE) + break; + if (i == 0) { + printk(KERN_ALERT "%s: MAC failed to boot MAC address reader.\n", dev->name); + } else { + atmel_copy_to_host(dev, dev->dev_addr, atmel_read16(dev, MR2), 6); + + /* got address, now squash it again until the network + interface is opened */ + if (priv->bus_type == BUS_TYPE_PCCARD) + atmel_write16(dev, GCR, 0x0060); + atmel_write16(dev, GCR, 0x0040); + rc = 1; + } + } else if (atmel_read16(dev, MR4) == 0) { + /* Mac address easy in this case. */ + priv->card_type = CARD_TYPE_PARALLEL_FLASH; + atmel_write16(dev, BSR, 1); + atmel_copy_to_host(dev, dev->dev_addr, 0xc000, 6); + atmel_write16(dev, BSR, 0x200); + rc = 1; + } else { + /* Standard firmware in flash, boot it up and ask + for the Mac Address */ + priv->card_type = CARD_TYPE_SPI_FLASH; + if (atmel_wakeup_firmware(priv)) { + atmel_get_mib(priv, Mac_Address_Mib_Type, 0, dev->dev_addr, 6); + + /* got address, now squash it again until the network + interface is opened */ + if (priv->bus_type == BUS_TYPE_PCCARD) + atmel_write16(dev, GCR, 0x0060); + atmel_write16(dev, GCR, 0x0040); + rc = 1; + } + } + + if (rc) { + if (dev->dev_addr[0] == 0xFF) { + u8 default_mac[] = {0x00,0x04, 0x25, 0x00, 0x00, 0x00}; + printk(KERN_ALERT "%s: *** Invalid MAC address. UPGRADE Firmware ****\n", dev->name); + memcpy(dev->dev_addr, default_mac, 6); + } + printk(KERN_INFO "%s: MAC address %x:%x:%x:%x:%x:%x\n", + dev->name, + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5] ); + + } + + return rc; +} + +int reset_atmel_card(struct net_device *dev) +{ + /* do everything necessary to wake up the hardware, including + waiting for the lightning strike and throwing the knife switch.... + + set all the Mib values which matter in the card to match + their settings in the atmel_private structure. Some of these + can be altered on the fly, but many (WEP, infrastucture or ad-hoc) + can only be changed by tearing down the world and coming back through + here. + + This routine is also responsible for initialising some + hardware-specific fields in the atmel_private structure, + including a copy of the firmware's hostinfo stucture + which is the route into the rest of the firmare datastructures. */ + + int channel; + struct atmel_private *priv = dev->priv; + u8 configuration; + + if (priv->station_state == STATION_STATE_NO_CARD || + priv->station_state == STATION_STATE_DOWN) + return 0; + + /* reset pccard */ + if (priv->bus_type == BUS_TYPE_PCCARD) + atmel_write16(priv->dev, GCR, 0x0060); + + /* stop card , disable interrupts */ + atmel_write16(priv->dev, GCR, 0x0040); + + /* any scheduled timer is no longer needed and might screw things up.. */ + del_timer_sync(&priv->management_timer); + if (priv->new_SSID_size) { + memcpy(priv->SSID, priv->new_SSID, priv->new_SSID_size); + priv->SSID_size = priv->new_SSID_size; + priv->new_SSID_size = 0; + } + priv->BSS_list_entries = 0; + + priv->AuthenticationRequestRetryCnt = 0; + priv->AssociationRequestRetryCnt = 0; + priv->ReAssociationRequestRetryCnt = 0; + priv->CurrentAuthentTransactionSeqNum = 0x0001; + priv->ExpectedAuthentTransactionSeqNum = 0x0002; + + priv->station_state = STATION_STATE_INITIALIZING; + priv->site_survey_state = SITE_SURVEY_IDLE; + priv->station_is_associated = 0; + + if (priv->card_type == CARD_TYPE_EEPROM) { + /* copy in firmware if needed */ +#ifdef CONFIG_FW_LOADER + const struct firmware *fw_entry = NULL; +#endif + unsigned char *fw; + int len = priv->firmware_length; + if (!(fw = priv->firmware)) { +#ifdef CONFIG_FW_LOADER + if (strlen(priv->firmware_id) == 0) { + printk(KERN_INFO + "%s: card type is unknown: assuming at76c502 firmware is OK.\n", + dev->name); + printk(KERN_INFO + "%s: if not, use the firmware= module parameter.\n", + dev->name); + strcpy(priv->firmware_id, "atmel_at76c502.bin"); + } + if (request_firmware(&fw_entry, priv->firmware_id, priv->sys_dev) != 0) { + printk(KERN_ALERT + "%s: firmware %s is missing, cannot start.\n", + dev->name, priv->firmware_id); + return 0; + } + fw = fw_entry->data; + len = fw_entry->size; +#else + printk(KERN_ALERT + "%s: no firmware supplied, cannot start.\n", dev->name); + return 0; +#endif + } + + if (len <= 0x6000) { + atmel_write16(priv->dev, BSR, BSS_IRAM); + atmel_copy_to_card(priv->dev, 0, fw, len); + atmel_set_gcr(priv->dev, GCR_REMAP); + } else { + /* Remap */ + atmel_set_gcr(priv->dev, GCR_REMAP); + atmel_write16(priv->dev, BSR, BSS_IRAM); + atmel_copy_to_card(priv->dev, 0, fw, 0x6000); + atmel_write16(priv->dev, BSR, 0x2ff); + atmel_copy_to_card(priv->dev, 0x8000, &fw[0x6000], len - 0x6000); + } + +#ifdef CONFIG_FW_LOADER + if (fw_entry) + release_firmware(fw_entry); +#endif + } + + if (!atmel_wakeup_firmware(priv)) + return 0; + + /* unmask all irq sources */ + atmel_wmem8(priv, atmel_hi(priv, IFACE_INT_MASK_OFFSET), 0xff); + + /* int Tx system and enable Tx */ + atmel_wmem8(priv, atmel_tx(priv, TX_DESC_FLAGS_OFFSET, 0), 0); + atmel_wmem32(priv, atmel_tx(priv, TX_DESC_NEXT_OFFSET, 0), 0x80000000L); + atmel_wmem16(priv, atmel_tx(priv, TX_DESC_POS_OFFSET, 0), 0); + atmel_wmem16(priv, atmel_tx(priv, TX_DESC_SIZE_OFFSET, 0), 0); + + priv->tx_desc_free = priv->host_info.tx_desc_count; + priv->tx_desc_head = 0; + priv->tx_desc_tail = 0; + priv->tx_desc_previous = 0; + priv->tx_free_mem = priv->host_info.tx_buff_size; + priv->tx_buff_head = 0; + priv->tx_buff_tail = 0; + + configuration = atmel_rmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET)); + atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET), + configuration | FUNC_CTRL_TxENABLE); + + /* init Rx system and enable */ + priv->rx_desc_head = 0; + + configuration = atmel_rmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET)); + atmel_wmem8(priv, atmel_hi(priv, IFACE_FUNC_CTRL_OFFSET), + configuration | FUNC_CTRL_RxENABLE); + + priv->reg_domain = atmel_get_mib8(priv, Phy_Mib_Type, PHY_MIB_REG_DOMAIN_POS); + if (priv->reg_domain != REG_DOMAIN_FCC && + priv->reg_domain != REG_DOMAIN_DOC && + priv->reg_domain != REG_DOMAIN_ETSI && + priv->reg_domain != REG_DOMAIN_SPAIN && + priv->reg_domain != REG_DOMAIN_FRANCE && + priv->reg_domain != REG_DOMAIN_MKK && + priv->reg_domain != REG_DOMAIN_MKK1 && + priv->reg_domain != REG_DOMAIN_ISRAEL) { + priv->reg_domain = REG_DOMAIN_MKK1; + printk(KERN_ALERT "%s: failed to get regulatory domain: assuming MKK1.\n", dev->name); + } + if ((channel = atmel_validate_channel(priv, priv->channel))) + priv->channel = channel; + + if (!priv->is3com) { + if (atmel_send_command_wait(priv, CMD_EnableRadio, NULL, 0) == + CMD_STATUS_REJECTED_RADIO_OFF) { + printk(KERN_INFO + "%s: cannot turn the radio on. (Hey radio, you're beautiful!)\n", + dev->name); + return 0; + } + } + + /* set up enough MIB values to run. */ + atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_AUTO_TX_RATE_POS, priv->auto_tx_rate); + atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_TX_PROMISCUOUS_POS, PROM_MODE_OFF); + atmel_set_mib16(priv, Mac_Mib_Type, MAC_MIB_RTS_THRESHOLD_POS, priv->rts_threshold); + atmel_set_mib16(priv, Mac_Mib_Type, MAC_MIB_FRAG_THRESHOLD_POS, priv->frag_threshold); + atmel_set_mib8(priv, Mac_Mib_Type, MAC_MIB_SHORT_RETRY_POS, priv->short_retry); + atmel_set_mib8(priv, Mac_Mib_Type, MAC_MIB_LONG_RETRY_POS, priv->long_retry); + atmel_set_mib8(priv, Local_Mib_Type, LOCAL_MIB_PREAMBLE_TYPE, priv->preamble); + atmel_set_mib(priv, Mac_Address_Mib_Type, MAC_ADDR_MIB_MAC_ADDR_POS, + priv->dev->dev_addr, 6); + atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_PS_MODE_POS, ACTIVE_MODE); + atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_LISTEN_INTERVAL_POS, 1); + atmel_set_mib16(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_BEACON_PER_POS, priv->default_beacon_period); + atmel_set_mib(priv, Phy_Mib_Type, PHY_MIB_RATE_SET_POS, atmel_basic_rates, 4); + atmel_set_mib8(priv, Mac_Mgmt_Mib_Type, MAC_MGMT_MIB_CUR_PRIVACY_POS, priv->wep.wep_is_on); + atmel_set_mib(priv, Mac_Wep_Mib_Type, 0, (u8 *)&priv->wep, sizeof(priv->wep)); + + atmel_scan(priv, 1); + + atmel_set_gcr(priv->dev, GCR_ENINT); /* enable interrupts */ + + return 1; +} + +EXPORT_SYMBOL(reset_atmel_card); + +static void atmel_send_command(struct atmel_private *priv, int command, void *cmd, int cmd_size) +{ + if (cmd) + atmel_copy_to_card(priv->dev, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET), + cmd, cmd_size); + + atmel_wmem8(priv, atmel_co(priv, CMD_BLOCK_COMMAND_OFFSET), command); + atmel_wmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET), 0); +} + +static int atmel_send_command_wait(struct atmel_private *priv, int command, void *cmd, int cmd_size) +{ + int i, status; + + atmel_send_command(priv, command, cmd, cmd_size); + + for (i = LOOP_RETRY_LIMIT; i; i--) { + status = atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_STATUS_OFFSET)); + if (status != CMD_STATUS_IDLE && + status != CMD_STATUS_IN_PROGRESS) + break; + } + + if (i == 0) { + printk(KERN_ALERT "%s: command %d failed to complete.\n", priv->dev->name, command); + status = CMD_STATUS_HOST_ERROR; + } else { + if (command != CMD_EnableRadio) + status = CMD_STATUS_COMPLETE; + } + + return status; +} + +static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index) +{ + struct get_set_mib m; + m.type = type; + m.size = 1; + m.index = index; + + atmel_send_command_wait(priv, CMD_Get_MIB_Vars, &m, sizeof(m)); + return atmel_rmem8(priv, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET + 4)); +} + +static void atmel_set_mib8(struct atmel_private *priv, u8 type, u8 index, u8 data) +{ + struct get_set_mib m; + m.type = type; + m.size = 1; + m.index = index; + m.data[0] = data; + + atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, sizeof(m)); +} + +static void atmel_set_mib16(struct atmel_private *priv, u8 type, u8 index, u16 data) +{ + struct get_set_mib m; + m.type = type; + m.size = 2; + m.index = index; + m.data[0] = data; + m.data[1] = data >> 8; + + atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, sizeof(m)); +} + +static void atmel_set_mib(struct atmel_private *priv, u8 type, u8 index, u8 *data, int data_len) +{ + struct get_set_mib m; + m.type = type; + m.size = data_len; + m.index = index; + + memcpy(m.data, data, data_len); + atmel_send_command_wait(priv, CMD_Set_MIB_Vars, &m, sizeof(m)); +} + +static void atmel_get_mib(struct atmel_private *priv, u8 type, u8 index, u8 *data, int data_len) +{ + struct get_set_mib m; + m.type = type; + m.size = data_len; + m.index = index; + + atmel_send_command_wait(priv, CMD_Get_MIB_Vars, &m, sizeof(m)); + atmel_copy_to_host(priv->dev, data, atmel_co(priv, CMD_BLOCK_PARAMETERS_OFFSET + 4), data_len); +} + +static void atmel_writeAR(struct net_device *dev, u16 data) +{ + int i; + outw(data, dev->base_addr + AR); + /* Address register appears to need some convincing..... */ + for (i = 0; data != inw(dev->base_addr + AR) && i<10; i++) + outw(data, dev->base_addr + AR); +} + +static void atmel_copy_to_card(struct net_device *dev, u16 dest, unsigned char *src, u16 len) +{ + int i; + atmel_writeAR(dev, dest); + if (dest % 2) { + atmel_write8(dev, DR, *src); + src++; len--; + } + for (i = len; i > 1 ; i -= 2) { + u8 lb = *src++; + u8 hb = *src++; + atmel_write16(dev, DR, lb | (hb << 8)); + } + if (i) + atmel_write8(dev, DR, *src); +} + +static void atmel_copy_to_host(struct net_device *dev, unsigned char *dest, u16 src, u16 len) +{ + int i; + atmel_writeAR(dev, src); + if (src % 2) { + *dest = atmel_read8(dev, DR); + dest++; len--; + } + for (i = len; i > 1 ; i -= 2) { + u16 hw = atmel_read16(dev, DR); + *dest++ = hw; + *dest++ = hw >> 8; + } + if (i) + *dest = atmel_read8(dev, DR); +} + +static void atmel_set_gcr(struct net_device *dev, u16 mask) +{ + outw(inw(dev->base_addr + GCR) | mask, dev->base_addr + GCR); +} + +static void atmel_clear_gcr(struct net_device *dev, u16 mask) +{ + outw(inw(dev->base_addr + GCR) & ~mask, dev->base_addr + GCR); +} + +static int atmel_lock_mac(struct atmel_private *priv) +{ + int i, j = 100; + retry: + for (i = LOOP_RETRY_LIMIT ; atmel_rmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_HOST_OFFSET)) && i ; i--); + + if (!i) return 0; /* timed out */ + + atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 1); + if (atmel_rmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_HOST_OFFSET))) { + atmel_wmem8(priv, atmel_hi(priv, IFACE_LOCKOUT_MAC_OFFSET), 0); + if (!j--) return 0; /* timed out */ + goto retry; + } + + return 1; +} + +static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data) +{ + atmel_writeAR(priv->dev, pos); + atmel_write16(priv->dev, DR, data); /* card is little-endian */ + atmel_write16(priv->dev, DR, data >> 16); +} + + +/***************************************************************************/ +/* There follows the source form of the MAC address reading firmware */ +/***************************************************************************/ +#if 0 + +/* Copyright 2003 Matthew T. Russotto */ +/* But derived from the Atmel 76C502 firmware written by Atmel and */ +/* included in "atmel wireless lan drivers" package */ +/** + This file is part of net.russotto.AtmelMACFW, hereto referred to + as AtmelMACFW + + AtmelMACFW is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation. + + AtmelMACFW 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 AtmelMACFW; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +****************************************************************************/ +/* This firmware should work on the 76C502 RFMD, RFMD_D, and RFMD_E */ +/* It will probably work on the 76C504 and 76C502 RFMD_3COM */ +/* It only works on SPI EEPROM versions of the card. */ + +/* This firmware initializes the SPI controller and clock, reads the MAC */ +/* address from the EEPROM into SRAM, and puts the SRAM offset of the MAC */ +/* address in MR2, and sets MR3 to 0x10 to indicate it is done */ +/* It also puts a complete copy of the EEPROM in SRAM with the offset in */ +/* MR4, for investigational purposes (maybe we can determine chip type */ +/* from that?) */ + + .org 0 + .set MRBASE, 0x8000000 + .set CPSR_INITIAL, 0xD3 /* IRQ/FIQ disabled, ARM mode, Supervisor state */ + .set CPSR_USER, 0xD1 /* IRQ/FIQ disabled, ARM mode, USER state */ + .set SRAM_BASE, 0x02000000 + .set SP_BASE, 0x0F300000 + .set UNK_BASE, 0x0F000000 /* Some internal device, but which one? */ + .set SPI_CGEN_BASE, 0x0E000000 /* Some internal device, but which one? */ + .set UNK3_BASE, 0x02014000 /* Some internal device, but which one? */ + .set STACK_BASE, 0x5600 + .set SP_SR, 0x10 + .set SP_TDRE, 2 /* status register bit -- TDR empty */ + .set SP_RDRF, 1 /* status register bit -- RDR full */ + .set SP_SWRST, 0x80 + .set SP_SPIEN, 0x1 + .set SP_CR, 0 /* control register */ + .set SP_MR, 4 /* mode register */ + .set SP_RDR, 0x08 /* Read Data Register */ + .set SP_TDR, 0x0C /* Transmit Data Register */ + .set SP_CSR0, 0x30 /* chip select registers */ + .set SP_CSR1, 0x34 + .set SP_CSR2, 0x38 + .set SP_CSR3, 0x3C + .set NVRAM_CMD_RDSR, 5 /* read status register */ + .set NVRAM_CMD_READ, 3 /* read data */ + .set NVRAM_SR_RDY, 1 /* RDY bit. This bit is inverted */ + .set SPI_8CLOCKS, 0xFF /* Writing this to the TDR doesn't do anything to the + serial output, since SO is normally high. But it + does cause 8 clock cycles and thus 8 bits to be + clocked in to the chip. See Atmel's SPI + controller (e.g. AT91M55800) timing and 4K + SPI EEPROM manuals */ + + .set NVRAM_SCRATCH, 0x02000100 /* arbitrary area for scratchpad memory */ + .set NVRAM_IMAGE, 0x02000200 + .set NVRAM_LENGTH, 0x0200 + .set MAC_ADDRESS_MIB, SRAM_BASE + .set MAC_ADDRESS_LENGTH, 6 + .set MAC_BOOT_FLAG, 0x10 + .set MR1, 0 + .set MR2, 4 + .set MR3, 8 + .set MR4, 0xC +RESET_VECTOR: + b RESET_HANDLER +UNDEF_VECTOR: + b HALT1 +SWI_VECTOR: + b HALT1 +IABORT_VECTOR: + b HALT1 +DABORT_VECTOR: +RESERVED_VECTOR: + b HALT1 +IRQ_VECTOR: + b HALT1 +FIQ_VECTOR: + b HALT1 +HALT1: b HALT1 +RESET_HANDLER: + mov r0, #CPSR_INITIAL + msr CPSR_c, r0 /* This is probably unnecessary */ + +/* I'm guessing this is initializing clock generator electronics for SPI */ + ldr r0, =SPI_CGEN_BASE + mov r1, #0 + mov r1, r1, lsl #3 + orr r1,r1, #0 + str r1, [r0] + ldr r1, [r0, #28] + bic r1, r1, #16 + str r1, [r0, #28] + mov r1, #1 + str r1, [r0, #8] + + ldr r0, =MRBASE + mov r1, #0 + strh r1, [r0, #MR1] + strh r1, [r0, #MR2] + strh r1, [r0, #MR3] + strh r1, [r0, #MR4] + + mov sp, #STACK_BASE + bl SP_INIT + mov r0, #10 + bl DELAY9 + bl GET_MAC_ADDR + bl GET_WHOLE_NVRAM + ldr r0, =MRBASE + ldr r1, =MAC_ADDRESS_MIB + strh r1, [r0, #MR2] + ldr r1, =NVRAM_IMAGE + strh r1, [r0, #MR4] + mov r1, #MAC_BOOT_FLAG + strh r1, [r0, #MR3] +HALT2: b HALT2 +.func Get_Whole_NVRAM, GET_WHOLE_NVRAM +GET_WHOLE_NVRAM: + stmdb sp!, {lr} + mov r2, #0 /* 0th bytes of NVRAM */ + mov r3, #NVRAM_LENGTH + mov r1, #0 /* not used in routine */ + ldr r0, =NVRAM_IMAGE + bl NVRAM_XFER + ldmia sp!, {lr} + bx lr +.endfunc + +.func Get_MAC_Addr, GET_MAC_ADDR +GET_MAC_ADDR: + stmdb sp!, {lr} + mov r2, #0x120 /* address of MAC Address within NVRAM */ + mov r3, #MAC_ADDRESS_LENGTH + mov r1, #0 /* not used in routine */ + ldr r0, =MAC_ADDRESS_MIB + bl NVRAM_XFER + ldmia sp!, {lr} + bx lr +.endfunc +.ltorg +.func Delay9, DELAY9 +DELAY9: + adds r0, r0, r0, LSL #3 /* r0 = r0 * 9 */ +DELAYLOOP: + beq DELAY9_done + subs r0, r0, #1 + b DELAYLOOP +DELAY9_done: + bx lr +.endfunc + +.func SP_Init, SP_INIT +SP_INIT: + mov r1, #SP_SWRST + ldr r0, =SP_BASE + str r1, [r0, #SP_CR] /* reset the SPI */ + mov r1, #0 + str r1, [r0, #SP_CR] /* release SPI from reset state */ + mov r1, #SP_SPIEN + str r1, [r0, #SP_MR] /* set the SPI to MASTER mode*/ + str r1, [r0, #SP_CR] /* enable the SPI */ + +/* My guess would be this turns on the SPI clock */ + ldr r3, =SPI_CGEN_BASE + ldr r1, [r3, #28] + orr r1, r1, #0x2000 + str r1, [r3, #28] + + ldr r1, =0x2000c01 + str r1, [r0, #SP_CSR0] + ldr r1, =0x2000201 + str r1, [r0, #SP_CSR1] + str r1, [r0, #SP_CSR2] + str r1, [r0, #SP_CSR3] + ldr r1, [r0, #SP_SR] + ldr r0, [r0, #SP_RDR] + bx lr +.endfunc +.func NVRAM_Init, NVRAM_INIT +NVRAM_INIT: + ldr r1, =SP_BASE + ldr r0, [r1, #SP_RDR] + mov r0, #NVRAM_CMD_RDSR + str r0, [r1, #SP_TDR] +SP_loop1: + ldr r0, [r1, #SP_SR] + tst r0, #SP_TDRE + beq SP_loop1 + + mov r0, #SPI_8CLOCKS + str r0, [r1, #SP_TDR] +SP_loop2: + ldr r0, [r1, #SP_SR] + tst r0, #SP_TDRE + beq SP_loop2 + + ldr r0, [r1, #SP_RDR] +SP_loop3: + ldr r0, [r1, #SP_SR] + tst r0, #SP_RDRF + beq SP_loop3 + + ldr r0, [r1, #SP_RDR] + and r0, r0, #255 + bx lr +.endfunc + +.func NVRAM_Xfer, NVRAM_XFER + /* r0 = dest address */ + /* r1 = not used */ + /* r2 = src address within NVRAM */ + /* r3 = length */ +NVRAM_XFER: + stmdb sp!, {r4, r5, lr} + mov r5, r0 /* save r0 (dest address) */ + mov r4, r3 /* save r3 (length) */ + mov r0, r2, LSR #5 /* SPI memories put A8 in the command field */ + and r0, r0, #8 + add r0, r0, #NVRAM_CMD_READ + ldr r1, =NVRAM_SCRATCH + strb r0, [r1, #0] /* save command in NVRAM_SCRATCH[0] */ + strb r2, [r1, #1] /* save low byte of source address in NVRAM_SCRATCH[1] */ +_local1: + bl NVRAM_INIT + tst r0, #NVRAM_SR_RDY + bne _local1 + mov r0, #20 + bl DELAY9 + mov r2, r4 /* length */ + mov r1, r5 /* dest address */ + mov r0, #2 /* bytes to transfer in command */ + bl NVRAM_XFER2 + ldmia sp!, {r4, r5, lr} + bx lr +.endfunc + +.func NVRAM_Xfer2, NVRAM_XFER2 +NVRAM_XFER2: + stmdb sp!, {r4, r5, r6, lr} + ldr r4, =SP_BASE + mov r3, #0 + cmp r0, #0 + bls _local2 + ldr r5, =NVRAM_SCRATCH +_local4: + ldrb r6, [r5, r3] + str r6, [r4, #SP_TDR] +_local3: + ldr r6, [r4, #SP_SR] + tst r6, #SP_TDRE + beq _local3 + add r3, r3, #1 + cmp r3, r0 /* r0 is # of bytes to send out (command+addr) */ + blo _local4 +_local2: + mov r3, #SPI_8CLOCKS + str r3, [r4, #SP_TDR] + ldr r0, [r4, #SP_RDR] +_local5: + ldr r0, [r4, #SP_SR] + tst r0, #SP_RDRF + beq _local5 + ldr r0, [r4, #SP_RDR] /* what's this byte? It's the byte read while writing the TDR -- nonsense, because the NVRAM doesn't read and write at the same time */ + mov r0, #0 + cmp r2, #0 /* r2 is # of bytes to copy in */ + bls _local6 +_local7: + ldr r5, [r4, #SP_SR] + tst r5, #SP_TDRE + beq _local7 + str r3, [r4, #SP_TDR] /* r3 has SPI_8CLOCKS */ +_local8: + ldr r5, [r4, #SP_SR] + tst r5, #SP_RDRF + beq _local8 + ldr r5, [r4, #SP_RDR] /* but didn't we read this byte above? */ + strb r5, [r1], #1 /* postindexed */ + add r0, r0, #1 + cmp r0, r2 + blo _local7 /* since we don't send another address, the NVRAM must be capable of sequential reads */ +_local6: + mov r0, #200 + bl DELAY9 + ldmia sp!, {r4, r5, r6, lr} + bx lr +#endif diff -Nru a/drivers/net/wireless/atmel_cs.c b/drivers/net/wireless/atmel_cs.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/atmel_cs.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,768 @@ +/*** -*- linux-c -*- ********************************************************** + + Driver for Atmel at76c502 at76c504 and at76c506 wireless cards. + + Copyright 2000-2001 ATMEL Corporation. + Copyright 2003 Simon Kelley. + + This code was developed from version 2.1.1 of the Atmel drivers, + released by Atmel corp. under the GPL in December 2002. It also + includes code from the Linux aironet drivers (C) Benjamin Reed, + and the Linux PCMCIA package, (C) David Hinds. + + For all queries about this code, please contact the current author, + Simon Kelley <simon@thekelleys.org.uk> and not Atmel 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 software 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 Atmel wireless lan drivers; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +******************************************************************************/ + +#include <linux/config.h> +#ifdef __IN_PCMCIA_PACKAGE__ +#include <pcmcia/k_compat.h> +#endif +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/ptrace.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/netdevice.h> +#include <linux/moduleparam.h> +#include <linux/device.h> + +#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> +#include <pcmcia/ciscode.h> + +#include <asm/io.h> +#include <asm/system.h> +#include <linux/wireless.h> +#include <linux/802_11.h> + + +/* + All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If + you do not define PCMCIA_DEBUG at all, all the debug code will be + left out. If you compile with PCMCIA_DEBUG=0, the debug code will + be present but disabled -- but it can then be enabled for specific + modules at load time with a 'pc_debug=#' option to insmod. +*/ +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +static char *version = "$Revision: 1.2 $"; +#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args); +#else +#define DEBUG(n, args...) +#endif + +/*====================================================================*/ + +/* Parameters that can be set with 'insmod' */ + +/* The old way: bit map of interrupts to choose from */ +/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */ +static u_int irq_mask = 0xdeb8; +/* Newer, simpler way of listing specific interrupts */ +static int irq_list[4] = { -1 }; + +MODULE_AUTHOR("Simon Kelley"); +MODULE_DESCRIPTION("Support for Atmel at76c50x 802.11 wireless ethnet cards."); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("Atmel at76c50x PCMCIA cards"); +MODULE_PARM(irq_mask, "i"); +MODULE_PARM(irq_list, "1-4i"); + +/*====================================================================*/ + +/* + The event() function is this driver's Card Services event handler. + It will be called by Card Services when an appropriate card status + event is received. The config() and release() entry points are + used to configure or release a socket, in response to card + insertion and ejection events. They are invoked from the atmel_cs + event handler. +*/ + +struct net_device *init_atmel_card(int, int, char *, int, struct device *, + int (*present_func)(void *), void * ); +void stop_atmel_card( struct net_device *, int ); +int reset_atmel_card( struct net_device * ); + +static void atmel_config(dev_link_t *link); +static void atmel_release(u_long arg); +static int atmel_event(event_t event, int priority, + event_callback_args_t *args); + +/* + The attach() and detach() entry points are used to create and destroy + "instances" of the driver, where each instance represents everything + needed to manage one actual PCMCIA card. +*/ + +static dev_link_t *atmel_attach(void); +static void atmel_detach(dev_link_t *); + +/* + You'll also need to prototype all the functions that will actually + be used to talk to your device. See 'pcmem_cs' for a good example + of a fully self-sufficient driver; the other drivers rely more or + less on other parts of the kernel. +*/ + +/* + The dev_info variable is the "key" that is used to match up this + device driver with appropriate cards, through the card configuration + database. +*/ + +static dev_info_t dev_info = "atmel_cs"; + +/* + A linked list of "instances" of the atmelnet device. Each actual + PCMCIA card corresponds to one device instance, and is described + by one dev_link_t structure (defined in ds.h). + + You may not want to use a linked list for this -- for example, the + memory card driver uses an array of dev_link_t pointers, where minor + device numbers are used to derive the corresponding array index. +*/ + +static dev_link_t *dev_list = NULL; + +/* + A dev_link_t structure has fields for most things that are needed + to keep track of a socket, but there will usually be some device + specific information that also needs to be kept track of. The + 'priv' pointer in a dev_link_t structure can be used to point to + a device-specific private data structure, like this. + + A driver needs to provide a dev_node_t structure for each device + on a card. In some cases, there is only one device per card (for + example, ethernet cards, modems). In other cases, there may be + many actual or logical devices (SCSI adapters, memory cards with + multiple partitions). The dev_node_t structures need to be kept + in a linked list starting at the 'dev' field of a dev_link_t + structure. We allocate them in the card's private data structure, + because they generally shouldn't be allocated dynamically. + + In this case, we also provide a flag to indicate if a device is + "stopped" due to a power management event, or card ejection. The + device IO routines can use a flag like this to throttle IO to a + card that is not ready to accept it. +*/ + +typedef struct local_info_t { + dev_node_t node; + struct net_device *eth_dev; +} local_info_t; + +/*====================================================================== + + This bit of code is used to avoid unregistering network devices + at inappropriate times. 2.2 and later kernels are fairly picky + about when this can happen. + + ======================================================================*/ + +static void flush_stale_links(void) +{ + dev_link_t *link, *next; + for (link = dev_list; link; link = next) { + next = link->next; + if (link->state & DEV_STALE_LINK) + atmel_detach(link); + } +} + +/*====================================================================== + + atmel_attach() creates an "instance" of the driver, allocating + local data structures for one device. The device is registered + with Card Services. + + The dev_link structure is initialized, but we don't actually + configure the card at this point -- we wait until we receive a + card insertion event. + + ======================================================================*/ + +static dev_link_t *atmel_attach(void) +{ + client_reg_t client_reg; + dev_link_t *link; + local_info_t *local; + int ret, i; + + DEBUG(0, "atmel_attach()\n"); + flush_stale_links(); + + /* Initialize the dev_link_t structure */ + link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL); + if (!link) { + printk(KERN_ERR "atmel_cs: no memory for new device\n"); + return NULL; + } + memset(link, 0, sizeof(struct dev_link_t)); + init_timer(&link->release); + link->release.function = &atmel_release; + link->release.data = (u_long)link; + + /* Interrupt setup */ + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; + link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID; + if (irq_list[0] == -1) + link->irq.IRQInfo2 = irq_mask; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << irq_list[i]; + link->irq.Handler = NULL; + + /* + General socket configuration defaults can go here. In this + client, we assume very little, and rely on the CIS for almost + everything. In most clients, many details (i.e., number, sizes, + and attributes of IO windows) are fixed by the nature of the + device, and can be hard-wired here. + */ + link->conf.Attributes = 0; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + + /* Allocate space for private device-specific data */ + local = kmalloc(sizeof(local_info_t), GFP_KERNEL); + if (!local) { + printk(KERN_ERR "atmel_cs: no memory for new device\n"); + kfree (link); + return NULL; + } + memset(local, 0, sizeof(local_info_t)); + link->priv = local; + + /* Register with Card Services */ + link->next = dev_list; + dev_list = link; + client_reg.dev_info = &dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL | + CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET | + CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME; + client_reg.event_handler = &atmel_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != 0) { + cs_error(link->handle, RegisterClient, ret); + atmel_detach(link); + return NULL; + } + + return link; +} /* atmel_attach */ + +/*====================================================================== + + This deletes a driver "instance". The device is de-registered + with Card Services. If it has been released, all local data + structures are freed. Otherwise, the structures will be freed + when the device is released. + + ======================================================================*/ + +static void atmel_detach(dev_link_t *link) +{ + dev_link_t **linkp; + + DEBUG(0, "atmel_detach(0x%p)\n", link); + + /* Locate device structure */ + for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) break; + if (*linkp == NULL) + return; + + del_timer(&link->release); + if ( link->state & DEV_CONFIG ) { + atmel_release( (int)link ); + if ( link->state & DEV_STALE_CONFIG ) { + link->state |= DEV_STALE_LINK; + return; + } + } + + + /* Break the link with Card Services */ + if (link->handle) + CardServices(DeregisterClient, link->handle); + + + + /* Unlink device structure, free pieces */ + *linkp = link->next; + if (link->priv) { + kfree(link->priv); + } + kfree(link); + +} /* atmel_detach */ + +/*====================================================================== + + atmel_config() is scheduled to run after a CARD_INSERTION event + is received, to configure the PCMCIA socket, and to make the + device available to the system. + + ======================================================================*/ + +#define CS_CHECK(fn, args...) \ +while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed + +#define CFG_CHECK(fn, args...) \ +if (CardServices(fn, args) != 0) goto next_entry + +/* Call-back function to interrogate PCMCIA-specific information + about the current existance of the card */ +static int card_present(void *arg) +{ + dev_link_t *link = (dev_link_t *)arg; + if (link->state & DEV_SUSPEND) + return 0; + else if (link->state & DEV_PRESENT) + return 1; + + return 0; +} + +/* list of cards we know about and their firmware requirements. + Go either by Manfid or version strings. + Cards not in this list will need a firmware parameter to the module + in all probability. Note that the SMC 2632 V2 and V3 have the same + manfids, so we ignore those and use the version1 strings. */ + +static struct { + int manf, card; + char *ver1; + char *firmware; + char *name; +} card_table[] = { + { 0, 0, "WLAN/802.11b PC CARD", "atmel_at76c502d.bin", "Actiontec 802CAT1" }, + { 0, 0, "ATMEL/AT76C502AR", "atmel_at76c502.bin", "NoName-RFMD" }, + { 0, 0, "ATMEL/AT76C502AR_D", "atmel_at76c502d.bin", "NoName-revD" }, + { 0, 0, "ATMEL/AT76C502AR_E", "atmel_at76c502e.bin", "NoName-revE" }, + { 0, 0, "ATMEL/AT76C504", "atmel_at76c504.bin", "NoName-504" }, + { MANFID_3COM, 0x0620, NULL, "atmel_at76c502_3com.bin", "3com 3CRWE62092B" }, + { MANFID_3COM, 0x0696, NULL, "atmel_at76c502_3com.bin", "3com 3CRSHPW_96" }, + { 0, 0, "SMC/2632W-V2", "atmel_at76c502.bin", "SMC 2632W-V2" }, + { 0, 0, "SMC/2632W", "atmel_at76c502d.bin", "SMC 2632W-V3" }, + { 0xd601, 0x0007, NULL, "atmel_at76c502.bin", "Sitecom WLAN-011"}, /* suspect - from a usenet posting. */ + { 0x01bf, 0x3302, NULL, "atmel_at76c502d.bin", "Belkin F5D6060u"}, /* " " " " " */ +}; + +/* This is strictly temporary, until PCMCIA devices get integrated into the device model. */ +static struct device atmel_device = { + .name = "Atmel at76c50x wireless", + .bus_id = "pcmcia", +}; + +static void atmel_config(dev_link_t *link) +{ + client_handle_t handle; + tuple_t tuple; + cisparse_t parse; + local_info_t *dev; + int last_fn, last_ret; + u_char buf[64]; + int card_index = -1; + + handle = link->handle; + dev = link->priv; + + DEBUG(0, "atmel_config(0x%p)\n", link); + + tuple.Attributes = 0; + tuple.TupleData = buf; + tuple.TupleDataMax = sizeof(buf); + tuple.TupleOffset = 0; + + tuple.DesiredTuple = CISTPL_MANFID; + if (CardServices(GetFirstTuple, handle, &tuple) == 0) { + int i; + cistpl_manfid_t *manfid; + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + manfid = &(parse.manfid); + for (i = 0; i < sizeof(card_table)/sizeof(card_table[0]); i++) { + if (!card_table[i].ver1 && + manfid->manf == card_table[i].manf && + manfid->card == card_table[i].card) { + card_index = i; + goto done; + } + } + } + + tuple.DesiredTuple = CISTPL_VERS_1; + if (CardServices(GetFirstTuple, handle, &tuple) == 0) { + int i, j, k; + cistpl_vers_1_t *ver1; + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + ver1 = &(parse.version_1); + + for (i = 0; i < sizeof(card_table)/sizeof(card_table[0]); i++) { + for (j = 0; j < ver1->ns; j++) { + char *p = card_table[i].ver1; + char *q = &ver1->str[ver1->ofs[j]]; + if (!p) + goto mismatch; + for (k = 0; k < j; k++) { + while ((*p != '\0') && (*p != '/')) p++; + if (*p == '\0') + goto mismatch; + p++; + } + while((*q != '\0') && (*p != '\0') && + (*p != '/') && (*p == *q)) p++, q++; + if (((*p != '\0') && *p != '/') || *q != '\0') + goto mismatch; + } + card_index = i; + goto done; + + mismatch: + + } + done: + } + + /* + This reads the card's CONFIG tuple to find its configuration + registers. + */ + tuple.DesiredTuple = CISTPL_CONFIG; + CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigBase = parse.config.base; + link->conf.Present = parse.config.rmask[0]; + + /* Configure card */ + link->state |= DEV_CONFIG; + + /* + In this loop, we scan the CIS for configuration table entries, + each of which describes a valid card configuration, including + voltage, IO window, memory window, and interrupt settings. + + We make no assumptions about the card to be configured: we use + just the information available in the CIS. In an ideal world, + this would work for any PCMCIA card, but it requires a complete + and accurate CIS. In practice, a driver usually "knows" most of + these things without consulting the CIS, and most client drivers + will only use the CIS to fill in implementation-defined details. + */ + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + CS_CHECK(GetFirstTuple, handle, &tuple); + while (1) { + cistpl_cftable_entry_t dflt = { 0 }; + cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); + CFG_CHECK(GetTupleData, handle, &tuple); + CFG_CHECK(ParseTuple, handle, &tuple, &parse); + + if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; + if (cfg->index == 0) goto next_entry; + link->conf.ConfigIndex = cfg->index; + + /* Does this card need audio output? */ + if (cfg->flags & CISTPL_CFTABLE_AUDIO) { + link->conf.Attributes |= CONF_ENABLE_SPKR; + link->conf.Status = CCSR_AUDIO_ENA; + } + + /* Use power settings for Vcc and Vpp if present */ + /* Note that the CIS values need to be rescaled */ + if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) + link->conf.Vcc = cfg->vcc.param[CISTPL_POWER_VNOM]/10000; + else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) + link->conf.Vcc = dflt.vcc.param[CISTPL_POWER_VNOM]/10000; + + if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM)) + link->conf.Vpp1 = link->conf.Vpp2 = + cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; + else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM)) + link->conf.Vpp1 = link->conf.Vpp2 = + dflt.vpp1.param[CISTPL_POWER_VNOM]/10000; + + /* Do we need to allocate an interrupt? */ + if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) + link->conf.Attributes |= CONF_ENABLE_IRQ; + + /* IO window settings */ + link->io.NumPorts1 = link->io.NumPorts2 = 0; + if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { + cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + if (!(io->flags & CISTPL_IO_8BIT)) + link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; + if (!(io->flags & CISTPL_IO_16BIT)) + link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; + link->io.BasePort1 = io->win[0].base; + link->io.NumPorts1 = io->win[0].len; + if (io->nwin > 1) { + link->io.Attributes2 = link->io.Attributes1; + link->io.BasePort2 = io->win[1].base; + link->io.NumPorts2 = io->win[1].len; + } + } + + /* This reserves IO space but doesn't actually enable it */ + CFG_CHECK(RequestIO, link->handle, &link->io); + /* If we got this far, we're cool! */ + break; + + next_entry: + CS_CHECK(GetNextTuple, handle, &tuple); + } + + /* + Allocate an interrupt line. Note that this does not assign a + handler to the interrupt, unless the 'Handler' member of the + irq structure is initialized. + */ + if (link->conf.Attributes & CONF_ENABLE_IRQ) + CS_CHECK(RequestIRQ, link->handle, &link->irq); + + /* + This actually configures the PCMCIA socket -- setting up + the I/O windows and the interrupt mapping, and putting the + card and host interface into "Memory and IO" mode. + */ + CS_CHECK(RequestConfiguration, link->handle, &link->conf); + + if (link->irq.AssignedIRQ == 0) { + printk(KERN_ALERT + "atmel: cannot assign IRQ: check that CONFIG_ISA is set in kernel config."); + goto cs_failed; + } + + ((local_info_t*)link->priv)->eth_dev = + init_atmel_card(link->irq.AssignedIRQ, + link->io.BasePort1, + card_index == -1 ? NULL : card_table[card_index].firmware, + card_index == -1 ? 0 : (card_table[card_index].manf == MANFID_3COM), + &atmel_device, + card_present, + link); + if (!((local_info_t*)link->priv)->eth_dev) + goto cs_failed; + + /* + At this point, the dev_node_t structure(s) need to be + initialized and arranged in a linked list at link->dev. + */ + strcpy(dev->node.dev_name, ((local_info_t*)link->priv)->eth_dev->name ); + dev->node.major = dev->node.minor = 0; + link->dev = &dev->node; + + /* Finally, report what we've done */ + printk(KERN_INFO "%s: %s%sindex 0x%02x: Vcc %d.%d", + dev->node.dev_name, + card_index == -1 ? "" : card_table[card_index].name, + card_index == -1 ? "" : " ", + link->conf.ConfigIndex, + link->conf.Vcc/10, link->conf.Vcc%10); + if (link->conf.Vpp1) + printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10); + if (link->conf.Attributes & CONF_ENABLE_IRQ) + printk(", irq %d", link->irq.AssignedIRQ); + if (link->io.NumPorts1) + printk(", io 0x%04x-0x%04x", link->io.BasePort1, + link->io.BasePort1+link->io.NumPorts1-1); + if (link->io.NumPorts2) + printk(" & 0x%04x-0x%04x", link->io.BasePort2, + link->io.BasePort2+link->io.NumPorts2-1); + printk("\n"); + + link->state &= ~DEV_CONFIG_PENDING; + return; + + cs_failed: + cs_error(link->handle, last_fn, last_ret); + atmel_release((u_long)link); + +} /* atmel_config */ + +/*====================================================================== + + After a card is removed, atmel_release() will unregister the + device, and release the PCMCIA configuration. If the device is + still open, this will be postponed until it is closed. + + ======================================================================*/ + +static void atmel_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + struct net_device *dev = ((local_info_t*)link->priv)->eth_dev; + + DEBUG(0, "atmel_release(0x%p)\n", link); + + /* Unlink the device chain */ + link->dev = NULL; + + if (dev) + stop_atmel_card(dev, 0); + ((local_info_t*)link->priv)->eth_dev = 0; + + /* Don't bother checking to see if these succeed or not */ + CardServices(ReleaseConfiguration, link->handle); + if (link->io.NumPorts1) + CardServices(ReleaseIO, link->handle, &link->io); + if (link->irq.AssignedIRQ) + CardServices(ReleaseIRQ, link->handle, &link->irq); + link->state &= ~DEV_CONFIG; + +} /* atmel_release */ + +/*====================================================================== + + The card status event handler. Mostly, this schedules other + stuff to run after an event is received. + + When a CARD_REMOVAL event is received, we immediately set a + private flag to block future accesses to this device. All the + functions that actually access the device should check this flag + to make sure the card is still present. + + ======================================================================*/ + +static int atmel_event(event_t event, int priority, + event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + local_info_t *local = link->priv; + + DEBUG(1, "atmel_event(0x%06x)\n", event); + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + netif_device_detach(local->eth_dev); + mod_timer(&link->release, jiffies + HZ/20); + } + break; + case CS_EVENT_CARD_INSERTION: + link->state |= DEV_PRESENT | DEV_CONFIG_PENDING; + atmel_config(link); + break; + case CS_EVENT_PM_SUSPEND: + link->state |= DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + if (link->state & DEV_CONFIG) { + netif_device_detach(local->eth_dev); + CardServices(ReleaseConfiguration, link->handle); + } + break; + case CS_EVENT_PM_RESUME: + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + if (link->state & DEV_CONFIG) { + CardServices(RequestConfiguration, link->handle, &link->conf); + reset_atmel_card(local->eth_dev); + netif_device_attach(local->eth_dev); + } + break; + } + return 0; +} /* atmel_event */ + +/*====================================================================*/ +static struct pcmcia_driver atmel_driver = { + .owner = THIS_MODULE, + .drv = { + .name = "atmel_cs", + }, + .attach = atmel_attach, + .detach = atmel_detach, +}; + +static int atmel_cs_init(void) +{ + return pcmcia_register_driver(&atmel_driver); +} + +static void atmel_cs_cleanup(void) +{ + pcmcia_unregister_driver(&atmel_driver); + + /* XXX: this really needs to move into generic code.. */ + while (dev_list != NULL) { + if (dev_list->state & DEV_CONFIG) + atmel_release((u_long)dev_list); + atmel_detach(dev_list); + } +} + +/* + This program is free software; you can redistribute it and/or + modify it under the terms of the 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. + + In addition: + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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. +*/ + +module_init(atmel_cs_init); +module_exit(atmel_cs_cleanup); diff -Nru a/drivers/net/wireless/hermes.c b/drivers/net/wireless/hermes.c --- a/drivers/net/wireless/hermes.c Mon Jun 9 23:16:08 2003 +++ b/drivers/net/wireless/hermes.c Mon Jun 9 23:16:08 2003 @@ -52,7 +52,6 @@ #include "hermes.h" -static char version[] __initdata = "hermes.c: 4 Jul 2002 David Gibson <hermes@gibson.dropbear.id.au>"; MODULE_DESCRIPTION("Low-level driver helper for Lucent Hermes chipset and Prism II HFA384x wireless MAC controller"); MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>"); #ifdef MODULE_LICENSE @@ -226,7 +225,8 @@ * Returns: < 0 on internal error, 0 on success, > 0 on error returned by the firmware * * Callable from any context, but locking is your problem. */ -int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, hermes_response_t *resp) +int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, + hermes_response_t *resp) { int err; int k; @@ -402,7 +402,7 @@ * * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware */ -int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len, +int hermes_bap_pread(hermes_t *hw, int bap, void *buf, unsigned len, u16 id, u16 offset) { int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; @@ -428,7 +428,7 @@ * * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware */ -int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len, +int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, unsigned len, u16 id, u16 offset) { int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; @@ -456,26 +456,30 @@ * practice. * * Callable from user or bh context. */ -int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, int bufsize, +int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize, u16 *length, void *buf) { int err = 0; int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; u16 rlength, rtype; - int nwords; + unsigned nwords; if ( (bufsize < 0) || (bufsize % 2) ) return -EINVAL; err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL); if (err) - goto out; + return err; err = hermes_bap_seek(hw, bap, rid, 0); if (err) - goto out; + return err; rlength = hermes_read_reg(hw, dreg); + + if (! rlength) + return -ENOENT; + rtype = hermes_read_reg(hw, dreg); if (length) @@ -492,11 +496,10 @@ IO_TYPE(hw), hw->iobase, HERMES_RECLEN_TO_BYTES(rlength), bufsize, rid, rlength); - nwords = min_t(int, rlength - 1, bufsize / 2); + nwords = min((unsigned)rlength - 1, bufsize / 2); hermes_read_words(hw, dreg, buf, nwords); - out: - return err; + return 0; } int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, @@ -504,11 +507,14 @@ { int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; int err = 0; - int count; - + unsigned count; + + if (length == 0) + return -EINVAL; + err = hermes_bap_seek(hw, bap, rid, 0); if (err) - goto out; + return err; hermes_write_reg(hw, dreg, length); hermes_write_reg(hw, dreg, rid); @@ -520,7 +526,6 @@ err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, rid, NULL); - out: return err; } @@ -536,9 +541,12 @@ static int __init init_hermes(void) { - printk(KERN_DEBUG "%s\n", version); - return 0; } +static void __exit exit_hermes(void) +{ +} + module_init(init_hermes); +module_exit(exit_hermes); diff -Nru a/drivers/net/wireless/hermes.h b/drivers/net/wireless/hermes.h --- a/drivers/net/wireless/hermes.h Mon Jun 9 23:16:07 2003 +++ b/drivers/net/wireless/hermes.h Mon Jun 9 23:16:07 2003 @@ -250,7 +250,6 @@ u16 scanreason; /* ??? */ struct hermes_scan_apinfo aps[35]; /* Scan result */ } __attribute__ ((packed)); - #define HERMES_LINKSTATUS_NOT_CONNECTED (0x0000) #define HERMES_LINKSTATUS_CONNECTED (0x0001) #define HERMES_LINKSTATUS_DISCONNECTED (0x0002) @@ -278,7 +277,7 @@ /* Basic control structure */ typedef struct hermes { - ulong iobase; + unsigned long iobase; int io_space; /* 1 if we IO-mapped IO, 0 for memory-mapped IO? */ #define HERMES_IO 1 #define HERMES_MEM 0 @@ -316,11 +315,11 @@ int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, hermes_response_t *resp); int hermes_allocate(hermes_t *hw, u16 size, u16 *fid); -int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len, +int hermes_bap_pread(hermes_t *hw, int bap, void *buf, unsigned len, u16 id, u16 offset); -int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len, +int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, unsigned len, u16 id, u16 offset); -int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, int buflen, +int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned buflen, u16 *length, void *buf); int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, u16 length, const void *value); @@ -361,39 +360,58 @@ #define HERMES_RECLEN_TO_BYTES(n) ( ((n)-1) * 2 ) /* Note that for the next two, the count is in 16-bit words, not bytes */ -static inline void hermes_read_words(struct hermes *hw, int off, void *buf, int count) +static inline void hermes_read_words(struct hermes *hw, int off, void *buf, unsigned count) { off = off << hw->reg_spacing;; if (hw->io_space) { insw(hw->iobase + off, buf, count); } else { - int i; + unsigned i; u16 *p; - /* This need to *not* byteswap (like insw()) but - * readw() does byteswap hence the conversion */ + /* This needs to *not* byteswap (like insw()) but + * readw() does byteswap hence the conversion. I hope + * gcc is smart enough to fold away the two swaps on + * big-endian platforms. */ for (i = 0, p = buf; i < count; i++) { *p++ = cpu_to_le16(readw(hw->iobase + off)); } } } -static inline void hermes_write_words(struct hermes *hw, int off, const void *buf, int count) +static inline void hermes_write_words(struct hermes *hw, int off, const void *buf, unsigned count) { off = off << hw->reg_spacing;; if (hw->io_space) { outsw(hw->iobase + off, buf, count); } else { - int i; + unsigned i; const u16 *p; - /* This need to *not* byteswap (like outsw()) but - * writew() does byteswap hence the conversion */ + /* This needs to *not* byteswap (like outsw()) but + * writew() does byteswap hence the conversion. I + * hope gcc is smart enough to fold away the two swaps + * on big-endian platforms. */ for (i = 0, p = buf; i < count; i++) { writew(le16_to_cpu(*p++), hw->iobase + off); } + } +} + +static inline void hermes_clear_words(struct hermes *hw, int off, unsigned count) +{ + unsigned i; + + off = off << hw->reg_spacing;; + + if (hw->io_space) { + for (i = 0; i < count; i++) + outw(0, hw->iobase + off); + } else { + for (i = 0; i < count; i++) + writew(0, hw->iobase + off); } } diff -Nru a/drivers/net/wireless/ieee802_11.h b/drivers/net/wireless/ieee802_11.h --- a/drivers/net/wireless/ieee802_11.h Mon Jun 9 23:16:13 2003 +++ b/drivers/net/wireless/ieee802_11.h Mon Jun 9 23:16:13 2003 @@ -2,9 +2,15 @@ #define _IEEE802_11_H #define IEEE802_11_DATA_LEN 2304 -/* Actually, the standard seems to be inconsistent about what the - maximum frame size really is. Section 6.2.1.1.2 says 2304 octets, - but the figure in Section 7.1.2 says 2312 octects. */ +/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section + 6.2.1.1.2. + + The figure in section 7.1.2 suggests a body size of up to 2312 + bytes is allowed, which is a bit confusing, I suspect this + represents the 2304 bytes of real data, plus a possible 8 bytes of + WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */ + + #define IEEE802_11_HLEN 30 #define IEEE802_11_FRAME_LEN (IEEE802_11_DATA_LEN + IEEE802_11_HLEN) diff -Nru a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c --- a/drivers/net/wireless/orinoco.c Mon Jun 9 23:16:20 2003 +++ b/drivers/net/wireless/orinoco.c Mon Jun 9 23:16:20 2003 @@ -1,4 +1,4 @@ -/* orinoco.c 0.13a - (formerly known as dldwd_cs.c and orinoco_cs.c) +/* orinoco.c 0.13e - (formerly known as dldwd_cs.c and orinoco_cs.c) * * A driver for Hermes or Prism 2 chipset based PCMCIA wireless * adaptors, with Lucent/Agere, Intersil or Symbol firmware. @@ -323,7 +323,7 @@ * the card from hard sleep. * * v0.13beta1 -> v0.13 - 27 Sep 2002 - David Gibson - * o Re-introduced full resets (via schedule_work()) on Tx + * o Re-introduced full resets (via schedule_task()) on Tx * timeout. * * v0.13 -> v0.13a - 30 Sep 2002 - David Gibson @@ -332,15 +332,70 @@ * o Include required kernel headers in orinoco.h, to avoid * compile problems. * + * v0.13a -> v0.13b - 10 Feb 2003 - David Gibson + * o Implemented hard reset for Airport cards + * o Experimental suspend/resume implementation for orinoco_pci + * o Abolished /proc debugging support, replaced with a debugging + * iwpriv. Now it's ugly and simple instead of ugly and complex. + * o Bugfix in hermes.c if the firmware returned a record length + * of 0, we could go clobbering memory. + * o Bugfix in orinoco_stop() - it used to fail if hw_unavailable + * was set, which was usually true on PCMCIA hot removes. + * o Track LINKSTATUS messages, silently drop Tx packets before + * we are connected (avoids cofusing the firmware), and only + * give LINKSTATUS printk()s if the status has changed. + * + * v0.13b -> v0.13c - 11 Mar 2003 - David Gibson + * o Cleanup: use dev instead of priv in various places. + * o Bug fix: Don't ReleaseConfiguration on RESET_PHYSICAL event + * if we're in the middle of a (driver initiated) hard reset. + * o Bug fix: ETH_ZLEN is supposed to include the header + * (Dionysus Blazakis & Manish Karir) + * o Convert to using workqueues instead of taskqueues (and + * backwards compatibility macros for pre 2.5.41 kernels). + * o Drop redundant (I think...) MOD_{INC,DEC}_USE_COUNT in + * airport.c + * o New orinoco_tmd.c init module from Joerg Dorchain for + * TMD7160 based PCI to PCMCIA bridges (similar to + * orinoco_plx.c). + * + * v0.13c -> v0.13d - 22 Apr 2003 - David Gibson + * o Make hw_unavailable a counter, rather than just a flag, this + * is necessary to avoid some races (such as a card being + * removed in the middle of orinoco_reset(). + * o Restore Release/RequestConfiguration in the PCMCIA event handler + * when dealing with a driver initiated hard reset. This is + * necessary to prevent hangs due to a spurious interrupt while + * the reset is in progress. + * o Clear the 802.11 header when transmitting, even though we + * don't use it. This fixes a long standing bug on some + * firmwares, which seem to get confused if that isn't done. + * o Be less eager to de-encapsulate SNAP frames, only do so if + * the OUI is 00:00:00 or 00:00:f8, leave others alone. The old + * behaviour broke CDP (Cisco Discovery Protocol). + * o Use dev instead of priv for free_irq() as well as + * request_irq() (oops). + * o Attempt to reset rather than giving up if we get too many + * IRQs. + * o Changed semantics of __orinoco_down() so it can be called + * safely with hw_unavailable set. It also now clears the + * linkstatus (since we're going to have to reassociate). + * + * v0.13d -> v0.13e - 12 May 2003 - David Gibson + * o Support for post-2.5.68 return values from irq handler. + * o Fixed bug where underlength packets would be double counted + * in the rx_dropped statistics. + * o Provided a module parameter to suppress linkstatus messages. + * * TODO - * o New wireless extensions API (patch forthcoming from Moustafa - * Youssef). + * o New wireless extensions API (patch from Moustafa + * Youssef, updated by Jim Carter and Pavel Roskin). * o Handle de-encapsulation within network layer, provide 802.11 * headers (patch from Thomas 'Dent' Mirlacher) + * o RF monitor mode support * o Fix possible races in SPY handling. * o Disconnect wireless extensions from fundamental configuration. * o (maybe) Software WEP support (patch from Stano Meduna). - * o (maybe) Convert /proc debugging stuff to seqfile * o (maybe) Use multiple Tx buffers - driver handling queue * rather than firmware. */ @@ -357,7 +412,9 @@ * the middle of a hard reset). This flag is protected by the * spinlock. All code which touches the hardware should check the * flag after taking the lock, and if it is set, give up on whatever - * they are doing and drop the lock again. */ + * they are doing and drop the lock again. The orinoco_lock() + * function handles this (it unlocks and returns -EBUSY if + * hw_unavailable is non-zero). */ #include <linux/config.h> @@ -369,12 +426,10 @@ #include <linux/string.h> #include <linux/timer.h> #include <linux/ioport.h> -#include <linux/proc_fs.h> #include <linux/netdevice.h> #include <linux/if_arp.h> #include <linux/etherdevice.h> #include <linux/wireless.h> -#include <linux/workqueue.h> #include <asm/uaccess.h> #include <asm/io.h> @@ -402,6 +457,9 @@ EXPORT_SYMBOL(orinoco_debug); #endif +static int suppress_linkstatus; /* = 0 */ +MODULE_PARM(suppress_linkstatus, "i"); + /********************************************************************/ /* Compile time configuration and compatibility stuff */ /********************************************************************/ @@ -429,8 +487,10 @@ #define USER_BAP 0 #define IRQ_BAP 1 #define MAX_IRQLOOPS_PER_IRQ 10 -#define MAX_IRQLOOPS_PER_JIFFY (20000/HZ) /* Based on a guestimate of how many events the - device can legitimately generate */ +#define MAX_IRQLOOPS_PER_JIFFY (20000/HZ) /* Based on a guestimate of + * how many events the + * device could + * legitimately generate */ #define SMALL_KEY_SIZE 5 #define LARGE_KEY_SIZE 13 #define TX_NICBUF_SIZE_BUG 1585 /* Bug in Symbol firmware */ @@ -456,7 +516,7 @@ /* This tables gives the actual meanings of the bitrate IDs returned by the firmware. */ struct { - int bitrate; /* in 100s of kilbits */ + int bitrate; /* in 100s of kilobits */ int automatic; u16 agere_txratectrl; u16 intersil_txratectrl; @@ -466,8 +526,8 @@ {10, 1, 1, 1}, {20, 0, 2, 2}, {20, 1, 6, 3}, - {55, 0, 4, 4}, - {55, 1, 7, 7}, + {55, 0, 4, 4}, + {55, 1, 7, 7}, {110, 0, 5, 8}, }; #define BITRATE_TABLE_SIZE (sizeof(bitrate_table) / sizeof(bitrate_table[0])) @@ -508,7 +568,7 @@ /* Hardware control routines */ -static int __orinoco_program_rids(struct orinoco_private *priv); +static int __orinoco_program_rids(struct net_device *dev); static int __orinoco_hw_set_bitrate(struct orinoco_private *priv); static int __orinoco_hw_setup_wep(struct orinoco_private *priv); @@ -521,39 +581,21 @@ static void __orinoco_set_multicast_list(struct net_device *dev); /* Interrupt handling routines */ -static void __orinoco_ev_tick(struct orinoco_private *priv, hermes_t *hw); -static void __orinoco_ev_wterr(struct orinoco_private *priv, hermes_t *hw); -static void __orinoco_ev_infdrop(struct orinoco_private *priv, hermes_t *hw); -static void __orinoco_ev_info(struct orinoco_private *priv, hermes_t *hw); -static void __orinoco_ev_rx(struct orinoco_private *priv, hermes_t *hw); -static void __orinoco_ev_txexc(struct orinoco_private *priv, hermes_t *hw); -static void __orinoco_ev_tx(struct orinoco_private *priv, hermes_t *hw); -static void __orinoco_ev_alloc(struct orinoco_private *priv, hermes_t *hw); +static void __orinoco_ev_tick(struct net_device *dev, hermes_t *hw); +static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw); +static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw); +static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw); +static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw); +static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw); +static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw); +static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw); /* ioctl() routines */ -static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq); -static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq); -static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq); -static int orinoco_ioctl_setessid(struct net_device *dev, struct iw_point *erq); -static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq); -static int orinoco_ioctl_setnick(struct net_device *dev, struct iw_point *nrq); -static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq); -static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq); -static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq); -static int orinoco_ioctl_setsens(struct net_device *dev, struct iw_param *srq); -static int orinoco_ioctl_setrts(struct net_device *dev, struct iw_param *rrq); -static int orinoco_ioctl_setfrag(struct net_device *dev, struct iw_param *frq); -static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_param *frq); -static int orinoco_ioctl_setrate(struct net_device *dev, struct iw_param *frq); -static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *frq); -static int orinoco_ioctl_setpower(struct net_device *dev, struct iw_param *prq); -static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq); -static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq); -static int orinoco_ioctl_getport3(struct net_device *dev, struct iwreq *wrq); - -/* /proc debugging stuff */ -static int orinoco_proc_init(void); -static void orinoco_proc_cleanup(void); +static int orinoco_debug_dump_recs(struct net_device *dev); + +/********************************************************************/ +/* Function prototypes */ +/********************************************************************/ int __orinoco_up(struct net_device *dev) { @@ -561,7 +603,7 @@ struct hermes *hw = &priv->hw; int err; - err = __orinoco_program_rids(priv); + err = __orinoco_program_rids(dev); if (err) { printk(KERN_ERR "%s: Error %d configuring card\n", dev->name, err); @@ -590,14 +632,25 @@ netif_stop_queue(dev); - err = hermes_disable_port(hw, 0); - if (err) { - printk(KERN_ERR "%s: Error %d disabling MAC port\n", - dev->name, err); - return err; + if (! priv->hw_unavailable) { + if (! priv->broken_disableport) { + err = hermes_disable_port(hw, 0); + if (err) { + /* Some firmwares (e.g. Intersil 1.3.x) seem + * to have problems disabling the port, oh + * well, too bad. */ + printk(KERN_WARNING "%s: Error %d disabling MAC port\n", + dev->name, err); + priv->broken_disableport = 1; + } + } + hermes_set_irqmask(hw, 0); + hermes_write_regn(hw, EVACK, 0xffff); } - hermes_set_irqmask(hw, 0); - hermes_write_regn(hw, EVACK, 0xffff); + + /* firmware will have to reassociate */ + priv->last_linkstatus = 0xffff; + priv->connected = 0; return 0; } @@ -640,37 +693,38 @@ if (err) return err; - priv->open = 1; - err = __orinoco_up(dev); + if (! err) + priv->open = 1; + orinoco_unlock(priv, &flags); return err; } -static int orinoco_stop(struct net_device *dev) +int orinoco_stop(struct net_device *dev) { struct orinoco_private *priv = dev->priv; - unsigned long flags; - int err; + int err = 0; - err = orinoco_lock(priv, &flags); - if (err) - return err; + /* We mustn't use orinoco_lock() here, because we need to be + able to close the interface even if hw_unavailable is set + (e.g. as we're released after a PC Card removal) */ + spin_lock_irq(&priv->lock); priv->open = 0; err = __orinoco_down(dev); - orinoco_unlock(priv, &flags); + spin_unlock_irq(&priv->lock); return err; } -static int __orinoco_program_rids(struct orinoco_private *priv) +static int __orinoco_program_rids(struct net_device *dev) { - struct net_device *dev = priv->ndev; + struct orinoco_private *priv = dev->priv; hermes_t *hw = &priv->hw; int err; struct hermes_idstring idbuf; @@ -856,33 +910,52 @@ } /* xyzzy */ -static int orinoco_reconfigure(struct orinoco_private *priv) +static int orinoco_reconfigure(struct net_device *dev) { + struct orinoco_private *priv = dev->priv; struct hermes *hw = &priv->hw; unsigned long flags; int err = 0; - orinoco_lock(priv, &flags); + if (priv->broken_disableport) { + schedule_work(&priv->reset_work); + return 0; + } + + err = orinoco_lock(priv, &flags); + if (err) + return err; + err = hermes_disable_port(hw, 0); if (err) { - printk(KERN_ERR "%s: Unable to disable port in orinco_reconfigure()\n", - priv->ndev->name); + printk(KERN_WARNING "%s: Unable to disable port while reconfiguring card\n", + dev->name); + priv->broken_disableport = 1; goto out; } - err = __orinoco_program_rids(priv); - if (err) + err = __orinoco_program_rids(dev); + if (err) { + printk(KERN_WARNING "%s: Unable to reconfigure card\n", + dev->name); goto out; + } err = hermes_enable_port(hw, 0); if (err) { - printk(KERN_ERR "%s: Unable to enable port in orinco_reconfigure()\n", - priv->ndev->name); + printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n", + dev->name); goto out; } out: + if (err) { + printk(KERN_WARNING "%s: Resetting instead...\n", dev->name); + schedule_work(&priv->reset_work); + err = 0; + } + orinoco_unlock(priv, &flags); return err; @@ -893,16 +966,28 @@ static void orinoco_reset(struct net_device *dev) { struct orinoco_private *priv = dev->priv; + struct hermes *hw = &priv->hw; int err; unsigned long flags; - printk(KERN_INFO "%s: orinoco_reset()\n", dev->name); - err = orinoco_lock(priv, &flags); if (err) + /* When the hardware becomes available again, whatever + * detects that is responsible for re-initializing + * it. So no need for anything further*/ return; - priv->hw_unavailable = 1; + netif_stop_queue(dev); + + /* Shut off interrupts. Depending on what state the hardware + * is in, this might not work, but we'll try anyway */ + hermes_set_irqmask(hw, 0); + hermes_write_regn(hw, EVACK, 0xffff); + + priv->hw_unavailable++; + priv->last_linkstatus = 0xffff; /* firmware will have to reassociate */ + priv->connected = 0; + orinoco_unlock(priv, &flags); if (priv->hard_reset) @@ -921,18 +1006,22 @@ return; } - spin_lock_irqsave(&priv->lock, flags); + spin_lock_irq(&priv->lock); /* This has to be called from user context */ - priv->hw_unavailable = 0; + priv->hw_unavailable--; - err = __orinoco_up(dev); - if (err) { - printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n", - dev->name, err); - } else - dev->trans_start = jiffies; + /* priv->open or priv->hw_unavailable might have changed while + * we dropped the lock */ + if (priv->open && (! priv->hw_unavailable)) { + err = __orinoco_up(dev); + if (err) { + printk(KERN_ERR "%s: orinoco_reset: Error %d reenabling card\n", + dev->name, err); + } else + dev->trans_start = jiffies; + } - orinoco_unlock(priv, &flags); + spin_unlock_irq(&priv->lock); return; } @@ -964,10 +1053,18 @@ } } +/* Does the frame have a SNAP header indicating it should be + * de-encapsulated to Ethernet-II? */ static inline int -is_snap(struct header_struct *hdr) +is_ethersnap(struct header_struct *hdr) { - return (hdr->dsap == 0xAA) && (hdr->ssap == 0xAA) && (hdr->ctrl == 0x3); + /* We de-encapsulate all packets which, a) have SNAP headers + * (i.e. SSAP=DSAP=0xaa and CTRL=0x3 in the 802.2 LLC header + * and where b) the OUI of the SNAP header is 00:00:00 or + * 00:00:f8 - we need both because different APs appear to use + * different OUIs for some reason */ + return (memcmp(&hdr->dsap, &encaps_hdr, 5) == 0) + && ( (hdr->oui[2] == 0x00) || (hdr->oui[2] == 0xf8) ); } static void @@ -1125,7 +1222,8 @@ return 0; } -static int orinoco_hw_get_bssid(struct orinoco_private *priv, char buf[ETH_ALEN]) +static int orinoco_hw_get_bssid(struct orinoco_private *priv, + char buf[ETH_ALEN]) { hermes_t *hw = &priv->hw; int err = 0; @@ -1144,7 +1242,7 @@ } static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, - char buf[IW_ESSID_MAX_SIZE+1]) + char buf[IW_ESSID_MAX_SIZE+1]) { hermes_t *hw = &priv->hw; int err = 0; @@ -1221,9 +1319,8 @@ } if ( (channel < 1) || (channel > NUM_CHANNELS) ) { - struct net_device *dev = priv->ndev; - - printk(KERN_WARNING "%s: Channel out of range (%d)!\n", dev->name, channel); + printk(KERN_WARNING "%s: Channel out of range (%d)!\n", + priv->ndev->name, channel); err = -EBUSY; goto out; @@ -1238,8 +1335,8 @@ return err ? err : freq; } -static int orinoco_hw_get_bitratelist(struct orinoco_private *priv, int *numrates, - s32 *rates, int max) +static int orinoco_hw_get_bitratelist(struct orinoco_private *priv, + int *numrates, s32 *rates, int max) { hermes_t *hw = &priv->hw; struct hermes_idstring list; @@ -1272,9 +1369,6 @@ } #if 0 -#ifndef ORINOCO_DEBUG -static inline void show_rx_frame(struct orinoco_rxframe_hdr *frame) {} -#else static void show_rx_frame(struct orinoco_rxframe_hdr *frame) { printk(KERN_DEBUG "RX descriptor:\n"); @@ -1331,17 +1425,16 @@ frame->p8022.oui[0], frame->p8022.oui[1], frame->p8022.oui[2]); printk(KERN_DEBUG " ethertype = 0x%04x\n", frame->ethertype); } -#endif -#endif +#endif /* 0 */ /* * Interrupt handler */ irqreturn_t orinoco_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - struct orinoco_private *priv = (struct orinoco_private *) dev_id; + struct net_device *dev = (struct net_device *)dev_id; + struct orinoco_private *priv = dev->priv; hermes_t *hw = &priv->hw; - struct net_device *dev = priv->ndev; int count = MAX_IRQLOOPS_PER_IRQ; u16 evstat, events; /* These are used to detect a runaway interrupt situation */ @@ -1352,12 +1445,17 @@ unsigned long flags; if (orinoco_lock(priv, &flags) != 0) { - /* If hw is unavailable */ - return IRQ_NONE; + /* If hw is unavailable - we don't know if the irq was + * for us or not */ + return IRQ_HANDLED; } evstat = hermes_read_regn(hw, EVSTAT); events = evstat & hw->inten; + if (! events) { + orinoco_unlock(priv, &flags); + return IRQ_NONE; + } if (jiffies != last_irq_jiffy) loops_this_jiffy = 0; @@ -1365,11 +1463,11 @@ while (events && count--) { if (++loops_this_jiffy > MAX_IRQLOOPS_PER_JIFFY) { - printk(KERN_CRIT "%s: IRQ handler is looping too \ -much! Shutting down.\n", - dev->name); - /* Perform an emergency shutdown */ + printk(KERN_WARNING "%s: IRQ handler is looping too " + "much! Resetting.\n", dev->name); + /* Disable interrupts for now */ hermes_set_irqmask(hw, 0); + schedule_work(&priv->reset_work); break; } @@ -1380,21 +1478,21 @@ } if (events & HERMES_EV_TICK) - __orinoco_ev_tick(priv, hw); + __orinoco_ev_tick(dev, hw); if (events & HERMES_EV_WTERR) - __orinoco_ev_wterr(priv, hw); + __orinoco_ev_wterr(dev, hw); if (events & HERMES_EV_INFDROP) - __orinoco_ev_infdrop(priv, hw); + __orinoco_ev_infdrop(dev, hw); if (events & HERMES_EV_INFO) - __orinoco_ev_info(priv, hw); + __orinoco_ev_info(dev, hw); if (events & HERMES_EV_RX) - __orinoco_ev_rx(priv, hw); + __orinoco_ev_rx(dev, hw); if (events & HERMES_EV_TXEXC) - __orinoco_ev_txexc(priv, hw); + __orinoco_ev_txexc(dev, hw); if (events & HERMES_EV_TX) - __orinoco_ev_tx(priv, hw); + __orinoco_ev_tx(dev, hw); if (events & HERMES_EV_ALLOC) - __orinoco_ev_alloc(priv, hw); + __orinoco_ev_alloc(dev, hw); hermes_write_regn(hw, EVACK, events); @@ -1403,31 +1501,67 @@ }; orinoco_unlock(priv, &flags); - return IRQ_HANDLED; } -static void __orinoco_ev_tick(struct orinoco_private *priv, hermes_t *hw) +static void __orinoco_ev_tick(struct net_device *dev, hermes_t *hw) { - printk(KERN_DEBUG "%s: TICK\n", priv->ndev->name); + printk(KERN_DEBUG "%s: TICK\n", dev->name); } -static void __orinoco_ev_wterr(struct orinoco_private *priv, hermes_t *hw) +static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw) { /* This seems to happen a fair bit under load, but ignoring it seems to work fine...*/ printk(KERN_DEBUG "%s: MAC controller error (WTERR). Ignoring.\n", - priv->ndev->name); + dev->name); } -static void __orinoco_ev_infdrop(struct orinoco_private *priv, hermes_t *hw) +static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw) { - printk(KERN_WARNING "%s: Information frame lost.\n", priv->ndev->name); + printk(KERN_WARNING "%s: Information frame lost.\n", dev->name); +} + +static void print_linkstatus(struct net_device *dev, u16 status) +{ + char * s; + + if (suppress_linkstatus) + return; + + switch (status) { + case HERMES_LINKSTATUS_NOT_CONNECTED: + s = "Not Connected"; + break; + case HERMES_LINKSTATUS_CONNECTED: + s = "Connected"; + break; + case HERMES_LINKSTATUS_DISCONNECTED: + s = "Disconnected"; + break; + case HERMES_LINKSTATUS_AP_CHANGE: + s = "AP Changed"; + break; + case HERMES_LINKSTATUS_AP_OUT_OF_RANGE: + s = "AP Out of Range"; + break; + case HERMES_LINKSTATUS_AP_IN_RANGE: + s = "AP In Range"; + break; + case HERMES_LINKSTATUS_ASSOC_FAILED: + s = "Association Failed"; + break; + default: + s = "UNKNOWN"; + } + + printk(KERN_INFO "%s: New link status: %s (%04x)\n", + dev->name, s, status); } -static void __orinoco_ev_info(struct orinoco_private *priv, hermes_t *hw) +static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) { - struct net_device *dev = priv->ndev; + struct orinoco_private *priv = dev->priv; u16 infofid; struct { u16 len; @@ -1491,7 +1625,6 @@ case HERMES_INQ_LINKSTATUS: { struct hermes_linkstatus linkstatus; u16 newstatus; - const char *s; if (len != sizeof(linkstatus)) { printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n", @@ -1503,34 +1636,20 @@ len / 2); newstatus = le16_to_cpu(linkstatus.linkstatus); - switch (newstatus) { - case HERMES_LINKSTATUS_NOT_CONNECTED: - s = "Not Connected"; - break; - case HERMES_LINKSTATUS_CONNECTED: - s = "Connected"; - break; - case HERMES_LINKSTATUS_DISCONNECTED: - s = "Disconnected"; - break; - case HERMES_LINKSTATUS_AP_CHANGE: - s = "AP Changed"; - break; - case HERMES_LINKSTATUS_AP_OUT_OF_RANGE: - s = "AP Out of Range"; - break; - case HERMES_LINKSTATUS_AP_IN_RANGE: - s = "AP In Range"; - break; - case HERMES_LINKSTATUS_ASSOC_FAILED: - s = "Association Failed"; - break; - default: - s = "UNKNOWN"; - } + if ( (newstatus == HERMES_LINKSTATUS_CONNECTED) + || (newstatus == HERMES_LINKSTATUS_AP_CHANGE) + || (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE) ) + priv->connected = 1; + else if ( (newstatus == HERMES_LINKSTATUS_NOT_CONNECTED) + || (newstatus == HERMES_LINKSTATUS_DISCONNECTED) + || (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE) + || (newstatus == HERMES_LINKSTATUS_ASSOC_FAILED) ) + priv->connected = 0; + + if (newstatus != priv->last_linkstatus) + print_linkstatus(dev, newstatus); - printk(KERN_INFO "%s: New link status: %s (%04x)\n", - dev->name, s, newstatus); + priv->last_linkstatus = newstatus; } break; default: @@ -1541,9 +1660,9 @@ } } -static void __orinoco_ev_rx(struct orinoco_private *priv, hermes_t *hw) +static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) { - struct net_device *dev = priv->ndev; + struct orinoco_private *priv = dev->priv; struct net_device_stats *stats = &priv->stats; struct iw_statistics *wstats = &priv->wstats; struct sk_buff *skb = NULL; @@ -1632,14 +1751,13 @@ * So, check ourselves */ if(((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) || ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) || - is_snap(&hdr)) { + is_ethersnap(&hdr)) { /* These indicate a SNAP within 802.2 LLC within 802.11 frame which we'll need to de-encapsulate to the original EthernetII frame. */ if (length < ENCAPS_OVERHEAD) { /* No room for full LLC+SNAP */ stats->rx_length_errors++; - stats->rx_dropped++; goto drop; } @@ -1694,9 +1812,9 @@ return; } -static void __orinoco_ev_txexc(struct orinoco_private *priv, hermes_t *hw) +static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw) { - struct net_device *dev = priv->ndev; + struct orinoco_private *priv = dev->priv; struct net_device_stats *stats = &priv->stats; u16 fid = hermes_read_regn(hw, TXCOMPLFID); struct hermes_tx_descriptor desc; @@ -1720,8 +1838,9 @@ hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); } -static void __orinoco_ev_tx(struct orinoco_private *priv, hermes_t *hw) +static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw) { + struct orinoco_private *priv = dev->priv; struct net_device_stats *stats = &priv->stats; stats->tx_packets++; @@ -1729,9 +1848,10 @@ hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); } -static void __orinoco_ev_alloc(struct orinoco_private *priv, hermes_t *hw) +static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw) { - struct net_device *dev = priv->ndev; + struct orinoco_private *priv = dev->priv; + u16 fid = hermes_read_regn(hw, ALLOCFID); if (fid != priv->txfid) { @@ -1913,7 +2033,7 @@ TRACE_ENTER(dev->name); - /* No need to lock, the resetting flag is already set in + /* No need to lock, the hw_unavailable flag is already set in * alloc_orinocodev() */ priv->nicbuf_size = IEEE802_11_FRAME_LEN + ETH_HLEN; @@ -2049,8 +2169,6 @@ priv->wep_on = 0; priv->tx_key = 0; - priv->hw_unavailable = 0; - err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid); if (err == -EIO) { /* Try workaround for old Symbol firmware bug */ @@ -2070,6 +2188,12 @@ goto out; } + /* Make the hardware available, as long as it hasn't been + * removed elsewhere (e.g. by PCMCIA hot unplug) */ + spin_lock_irq(&priv->lock); + priv->hw_unavailable--; + spin_unlock_irq(&priv->lock); + printk(KERN_DEBUG "%s: ready\n", dev->name); out: @@ -2222,9 +2346,20 @@ return 1; } + if (! priv->connected) { + /* Oops, the firmware hasn't established a connection, + silently drop the packet (this seems to be the + safest approach). */ + stats->tx_errors++; + orinoco_unlock(priv, &flags); + dev_kfree_skb(skb); + TRACE_EXIT(dev->name); + return 0; + } + /* Length of the packet body */ /* FIXME: what if the skb is smaller than this? */ - len = max_t(int,skb->len - ETH_HLEN, ETH_ZLEN); + len = max_t(int,skb->len - ETH_HLEN, ETH_ZLEN - ETH_HLEN); eh = (struct ethhdr *)skb->data; @@ -2238,6 +2373,12 @@ goto fail; } + /* Clear the 802.11 header and data length fields - some + * firmwares (e.g. Lucent/Agere 8.xx) appear to get confused + * if this isn't done. */ + hermes_clear_words(hw, HERMES_DATA0, + HERMES_802_3_OFFSET - HERMES_802_11_OFFSET); + /* Encapsulate Ethernet-II frames */ if (ntohs(eh->h_proto) > 1500) { /* Ethernet-II frame */ struct header_struct hdr; @@ -2319,7 +2460,7 @@ stats->tx_errors++; - schedule_work(&priv->timeout_task); + schedule_work(&priv->reset_work); } static int @@ -2489,7 +2630,7 @@ } err = orinoco_hw_get_bitratelist(priv, &numrates, - range.bitrate, IW_MAX_BITRATES); + range.bitrate, IW_MAX_BITRATES); if (err) return err; range.num_bitrates = numrates; @@ -2756,7 +2897,7 @@ erq->flags = 1; erq->length = strlen(essidbuf) + 1; if (erq->pointer) - if ( copy_to_user(erq->pointer, essidbuf, erq->length) ) + if (copy_to_user(erq->pointer, essidbuf, erq->length)) return -EFAULT; TRACE_EXIT(dev->name); @@ -3085,7 +3226,7 @@ rrq->value = 5500000; else rrq->value = val * 1000000; - break; + break; case FIRMWARE_TYPE_INTERSIL: /* Intersil style rate */ case FIRMWARE_TYPE_SYMBOL: /* Symbol style rate */ for (i = 0; i < BITRATE_TABLE_SIZE; i++) @@ -3688,7 +3829,8 @@ 0, "set_ibssport" }, { SIOCIWFIRSTPRIV + 0x7, 0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, - "get_ibssport" } + "get_ibssport" }, + { SIOCIWLASTPRIV, 0, 0, "dump_recs" }, }; err = verify_area(VERIFY_WRITE, wrq->u.data.pointer, sizeof(privtab)); @@ -3710,7 +3852,7 @@ printk(KERN_DEBUG "%s: Force scheduling reset!\n", dev->name); - schedule_work(&priv->timeout_task); + schedule_work(&priv->reset_work); break; case SIOCIWFIRSTPRIV + 0x2: /* set_port3 */ @@ -3782,13 +3924,20 @@ err = orinoco_ioctl_getibssport(dev, wrq); break; + case SIOCIWLASTPRIV: + err = orinoco_debug_dump_recs(dev); + if (err) + printk(KERN_ERR "%s: Unable to dump records (%d)\n", + dev->name, err); + break; + default: err = -EOPNOTSUPP; } if (! err && changed && netif_running(dev)) { - err = orinoco_reconfigure(priv); + err = orinoco_reconfigure(dev); } TRACE_EXIT(dev->name); @@ -3796,81 +3945,6 @@ return err; } -/********************************************************************/ -/* procfs stuff */ -/********************************************************************/ - -static struct proc_dir_entry *dir_base = NULL; - -#define PROC_LTV_SIZE 128 - -/* - * This function updates the total amount of data printed so far. It then - * determines if the amount of data printed into a buffer has reached the - * offset requested. If it hasn't, then the buffer is shifted over so that - * the next bit of data can be printed over the old bit. If the total - * amount printed so far exceeds the total amount requested, then this - * function returns 1, otherwise 0. - */ -static int -shift_buffer(char *buffer, int requested_offset, int requested_len, - int *total, int *slop, char **buf) -{ - int printed; - - printed = *buf - buffer; - if (*total + printed <= requested_offset) { - *total += printed; - *buf = buffer; - } - else { - if (*total < requested_offset) { - *slop = requested_offset - *total; - } - *total = requested_offset + printed - *slop; - } - if (*total > requested_offset + requested_len) { - return 1; - } - else { - return 0; - } -} - -/* - * This function calculates the actual start of the requested data - * in the buffer. It also calculates actual length of data returned, - * which could be less that the amount of data requested. - */ -#define PROC_BUFFER_SIZE 4096 -#define PROC_SAFE_SIZE 3072 - -static int -calc_start_len(char *buffer, char **start, int requested_offset, - int requested_len, int total, char *buf) -{ - int return_len, buffer_len; - - buffer_len = buf - buffer; - if (buffer_len >= PROC_BUFFER_SIZE - 1) { - printk(KERN_ERR "calc_start_len: exceeded /proc buffer size\n"); - } - - /* - * There may be bytes before and after the - * chunk that was actually requested. - */ - return_len = total - requested_offset; - if (return_len < 0) { - return_len = 0; - } - *start = buf - return_len; - if (return_len > requested_len) { - return_len = requested_len; - } - return return_len; -} - struct { u16 rid; char *name; @@ -3880,140 +3954,135 @@ #define DISPLAY_STRING 2 #define DISPLAY_XSTRING 3 } record_table[] = { -#define PROC_REC(name,type) { HERMES_RID_##name, #name, DISPLAY_##type } - PROC_REC(CNFPORTTYPE,WORDS), - PROC_REC(CNFOWNMACADDR,BYTES), - PROC_REC(CNFDESIREDSSID,STRING), - PROC_REC(CNFOWNCHANNEL,WORDS), - PROC_REC(CNFOWNSSID,STRING), - PROC_REC(CNFOWNATIMWINDOW,WORDS), - PROC_REC(CNFSYSTEMSCALE,WORDS), - PROC_REC(CNFMAXDATALEN,WORDS), - PROC_REC(CNFPMENABLED,WORDS), - PROC_REC(CNFPMEPS,WORDS), - PROC_REC(CNFMULTICASTRECEIVE,WORDS), - PROC_REC(CNFMAXSLEEPDURATION,WORDS), - PROC_REC(CNFPMHOLDOVERDURATION,WORDS), - PROC_REC(CNFOWNNAME,STRING), - PROC_REC(CNFOWNDTIMPERIOD,WORDS), - PROC_REC(CNFMULTICASTPMBUFFERING,WORDS), - PROC_REC(CNFWEPENABLED_AGERE,WORDS), - PROC_REC(CNFMANDATORYBSSID_SYMBOL,WORDS), - PROC_REC(CNFWEPDEFAULTKEYID,WORDS), - PROC_REC(CNFDEFAULTKEY0,BYTES), - PROC_REC(CNFDEFAULTKEY1,BYTES), - PROC_REC(CNFMWOROBUST_AGERE,WORDS), - PROC_REC(CNFDEFAULTKEY2,BYTES), - PROC_REC(CNFDEFAULTKEY3,BYTES), - PROC_REC(CNFWEPFLAGS_INTERSIL,WORDS), - PROC_REC(CNFWEPKEYMAPPINGTABLE,WORDS), - PROC_REC(CNFAUTHENTICATION,WORDS), - PROC_REC(CNFMAXASSOCSTA,WORDS), - PROC_REC(CNFKEYLENGTH_SYMBOL,WORDS), - PROC_REC(CNFTXCONTROL,WORDS), - PROC_REC(CNFROAMINGMODE,WORDS), - PROC_REC(CNFHOSTAUTHENTICATION,WORDS), - PROC_REC(CNFRCVCRCERROR,WORDS), - PROC_REC(CNFMMLIFE,WORDS), - PROC_REC(CNFALTRETRYCOUNT,WORDS), - PROC_REC(CNFBEACONINT,WORDS), - PROC_REC(CNFAPPCFINFO,WORDS), - PROC_REC(CNFSTAPCFINFO,WORDS), - PROC_REC(CNFPRIORITYQUSAGE,WORDS), - PROC_REC(CNFTIMCTRL,WORDS), - PROC_REC(CNFTHIRTY2TALLY,WORDS), - PROC_REC(CNFENHSECURITY,WORDS), - PROC_REC(CNFGROUPADDRESSES,BYTES), - PROC_REC(CNFCREATEIBSS,WORDS), - PROC_REC(CNFFRAGMENTATIONTHRESHOLD,WORDS), - PROC_REC(CNFRTSTHRESHOLD,WORDS), - PROC_REC(CNFTXRATECONTROL,WORDS), - PROC_REC(CNFPROMISCUOUSMODE,WORDS), - PROC_REC(CNFBASICRATES_SYMBOL,WORDS), - PROC_REC(CNFPREAMBLE_SYMBOL,WORDS), - PROC_REC(CNFSHORTPREAMBLE,WORDS), - PROC_REC(CNFWEPKEYS_AGERE,BYTES), - PROC_REC(CNFEXCLUDELONGPREAMBLE,WORDS), - PROC_REC(CNFTXKEY_AGERE,WORDS), - PROC_REC(CNFAUTHENTICATIONRSPTO,WORDS), - PROC_REC(CNFBASICRATES,WORDS), - PROC_REC(CNFSUPPORTEDRATES,WORDS), - PROC_REC(CNFTICKTIME,WORDS), - PROC_REC(CNFSCANREQUEST,WORDS), - PROC_REC(CNFJOINREQUEST,WORDS), - PROC_REC(CNFAUTHENTICATESTATION,WORDS), - PROC_REC(CNFCHANNELINFOREQUEST,WORDS), - PROC_REC(MAXLOADTIME,WORDS), - PROC_REC(DOWNLOADBUFFER,WORDS), - PROC_REC(PRIID,WORDS), - PROC_REC(PRISUPRANGE,WORDS), - PROC_REC(CFIACTRANGES,WORDS), - PROC_REC(NICSERNUM,WORDS), - PROC_REC(NICID,WORDS), - PROC_REC(MFISUPRANGE,WORDS), - PROC_REC(CFISUPRANGE,WORDS), - PROC_REC(CHANNELLIST,WORDS), - PROC_REC(REGULATORYDOMAINS,WORDS), - PROC_REC(TEMPTYPE,WORDS), -/* PROC_REC(CIS,BYTES), */ - PROC_REC(STAID,WORDS), - PROC_REC(CURRENTSSID,STRING), - PROC_REC(CURRENTBSSID,BYTES), - PROC_REC(COMMSQUALITY,WORDS), - PROC_REC(CURRENTTXRATE,WORDS), - PROC_REC(CURRENTBEACONINTERVAL,WORDS), - PROC_REC(CURRENTSCALETHRESHOLDS,WORDS), - PROC_REC(PROTOCOLRSPTIME,WORDS), - PROC_REC(SHORTRETRYLIMIT,WORDS), - PROC_REC(LONGRETRYLIMIT,WORDS), - PROC_REC(MAXTRANSMITLIFETIME,WORDS), - PROC_REC(MAXRECEIVELIFETIME,WORDS), - PROC_REC(CFPOLLABLE,WORDS), - PROC_REC(AUTHENTICATIONALGORITHMS,WORDS), - PROC_REC(PRIVACYOPTIONIMPLEMENTED,WORDS), - PROC_REC(OWNMACADDR,BYTES), - PROC_REC(SCANRESULTSTABLE,WORDS), - PROC_REC(PHYTYPE,WORDS), - PROC_REC(CURRENTCHANNEL,WORDS), - PROC_REC(CURRENTPOWERSTATE,WORDS), - PROC_REC(CCAMODE,WORDS), - PROC_REC(SUPPORTEDDATARATES,WORDS), - PROC_REC(BUILDSEQ,BYTES), - PROC_REC(FWID,XSTRING) -#undef PROC_REC +#define DEBUG_REC(name,type) { HERMES_RID_##name, #name, DISPLAY_##type } + DEBUG_REC(CNFPORTTYPE,WORDS), + DEBUG_REC(CNFOWNMACADDR,BYTES), + DEBUG_REC(CNFDESIREDSSID,STRING), + DEBUG_REC(CNFOWNCHANNEL,WORDS), + DEBUG_REC(CNFOWNSSID,STRING), + DEBUG_REC(CNFOWNATIMWINDOW,WORDS), + DEBUG_REC(CNFSYSTEMSCALE,WORDS), + DEBUG_REC(CNFMAXDATALEN,WORDS), + DEBUG_REC(CNFPMENABLED,WORDS), + DEBUG_REC(CNFPMEPS,WORDS), + DEBUG_REC(CNFMULTICASTRECEIVE,WORDS), + DEBUG_REC(CNFMAXSLEEPDURATION,WORDS), + DEBUG_REC(CNFPMHOLDOVERDURATION,WORDS), + DEBUG_REC(CNFOWNNAME,STRING), + DEBUG_REC(CNFOWNDTIMPERIOD,WORDS), + DEBUG_REC(CNFMULTICASTPMBUFFERING,WORDS), + DEBUG_REC(CNFWEPENABLED_AGERE,WORDS), + DEBUG_REC(CNFMANDATORYBSSID_SYMBOL,WORDS), + DEBUG_REC(CNFWEPDEFAULTKEYID,WORDS), + DEBUG_REC(CNFDEFAULTKEY0,BYTES), + DEBUG_REC(CNFDEFAULTKEY1,BYTES), + DEBUG_REC(CNFMWOROBUST_AGERE,WORDS), + DEBUG_REC(CNFDEFAULTKEY2,BYTES), + DEBUG_REC(CNFDEFAULTKEY3,BYTES), + DEBUG_REC(CNFWEPFLAGS_INTERSIL,WORDS), + DEBUG_REC(CNFWEPKEYMAPPINGTABLE,WORDS), + DEBUG_REC(CNFAUTHENTICATION,WORDS), + DEBUG_REC(CNFMAXASSOCSTA,WORDS), + DEBUG_REC(CNFKEYLENGTH_SYMBOL,WORDS), + DEBUG_REC(CNFTXCONTROL,WORDS), + DEBUG_REC(CNFROAMINGMODE,WORDS), + DEBUG_REC(CNFHOSTAUTHENTICATION,WORDS), + DEBUG_REC(CNFRCVCRCERROR,WORDS), + DEBUG_REC(CNFMMLIFE,WORDS), + DEBUG_REC(CNFALTRETRYCOUNT,WORDS), + DEBUG_REC(CNFBEACONINT,WORDS), + DEBUG_REC(CNFAPPCFINFO,WORDS), + DEBUG_REC(CNFSTAPCFINFO,WORDS), + DEBUG_REC(CNFPRIORITYQUSAGE,WORDS), + DEBUG_REC(CNFTIMCTRL,WORDS), + DEBUG_REC(CNFTHIRTY2TALLY,WORDS), + DEBUG_REC(CNFENHSECURITY,WORDS), + DEBUG_REC(CNFGROUPADDRESSES,BYTES), + DEBUG_REC(CNFCREATEIBSS,WORDS), + DEBUG_REC(CNFFRAGMENTATIONTHRESHOLD,WORDS), + DEBUG_REC(CNFRTSTHRESHOLD,WORDS), + DEBUG_REC(CNFTXRATECONTROL,WORDS), + DEBUG_REC(CNFPROMISCUOUSMODE,WORDS), + DEBUG_REC(CNFBASICRATES_SYMBOL,WORDS), + DEBUG_REC(CNFPREAMBLE_SYMBOL,WORDS), + DEBUG_REC(CNFSHORTPREAMBLE,WORDS), + DEBUG_REC(CNFWEPKEYS_AGERE,BYTES), + DEBUG_REC(CNFEXCLUDELONGPREAMBLE,WORDS), + DEBUG_REC(CNFTXKEY_AGERE,WORDS), + DEBUG_REC(CNFAUTHENTICATIONRSPTO,WORDS), + DEBUG_REC(CNFBASICRATES,WORDS), + DEBUG_REC(CNFSUPPORTEDRATES,WORDS), + DEBUG_REC(CNFTICKTIME,WORDS), + DEBUG_REC(CNFSCANREQUEST,WORDS), + DEBUG_REC(CNFJOINREQUEST,WORDS), + DEBUG_REC(CNFAUTHENTICATESTATION,WORDS), + DEBUG_REC(CNFCHANNELINFOREQUEST,WORDS), + DEBUG_REC(MAXLOADTIME,WORDS), + DEBUG_REC(DOWNLOADBUFFER,WORDS), + DEBUG_REC(PRIID,WORDS), + DEBUG_REC(PRISUPRANGE,WORDS), + DEBUG_REC(CFIACTRANGES,WORDS), + DEBUG_REC(NICSERNUM,XSTRING), + DEBUG_REC(NICID,WORDS), + DEBUG_REC(MFISUPRANGE,WORDS), + DEBUG_REC(CFISUPRANGE,WORDS), + DEBUG_REC(CHANNELLIST,WORDS), + DEBUG_REC(REGULATORYDOMAINS,WORDS), + DEBUG_REC(TEMPTYPE,WORDS), +/* DEBUG_REC(CIS,BYTES), */ + DEBUG_REC(STAID,WORDS), + DEBUG_REC(CURRENTSSID,STRING), + DEBUG_REC(CURRENTBSSID,BYTES), + DEBUG_REC(COMMSQUALITY,WORDS), + DEBUG_REC(CURRENTTXRATE,WORDS), + DEBUG_REC(CURRENTBEACONINTERVAL,WORDS), + DEBUG_REC(CURRENTSCALETHRESHOLDS,WORDS), + DEBUG_REC(PROTOCOLRSPTIME,WORDS), + DEBUG_REC(SHORTRETRYLIMIT,WORDS), + DEBUG_REC(LONGRETRYLIMIT,WORDS), + DEBUG_REC(MAXTRANSMITLIFETIME,WORDS), + DEBUG_REC(MAXRECEIVELIFETIME,WORDS), + DEBUG_REC(CFPOLLABLE,WORDS), + DEBUG_REC(AUTHENTICATIONALGORITHMS,WORDS), + DEBUG_REC(PRIVACYOPTIONIMPLEMENTED,WORDS), + DEBUG_REC(OWNMACADDR,BYTES), + DEBUG_REC(SCANRESULTSTABLE,WORDS), + DEBUG_REC(PHYTYPE,WORDS), + DEBUG_REC(CURRENTCHANNEL,WORDS), + DEBUG_REC(CURRENTPOWERSTATE,WORDS), + DEBUG_REC(CCAMODE,WORDS), + DEBUG_REC(SUPPORTEDDATARATES,WORDS), + DEBUG_REC(BUILDSEQ,BYTES), + DEBUG_REC(FWID,XSTRING) +#undef DEBUG_REC }; -#define NUM_RIDS ( sizeof(record_table) / sizeof(record_table[0]) ) -static int -orinoco_proc_get_hermes_recs(char *page, char **start, off_t requested_offset, - int requested_len, int *eof, void *data) +#define DEBUG_LTV_SIZE 128 + +static int orinoco_debug_dump_recs(struct net_device *dev) { - struct orinoco_private *priv = (struct orinoco_private *)data; - struct net_device *dev = priv->ndev; + struct orinoco_private *priv = dev->priv; hermes_t *hw = &priv->hw; - char *buf = page; - int total = 0, slop = 0; u8 *val8; u16 *val16; int i,j; u16 length; int err; - if (! netif_device_present(dev)) - return -ENODEV; - - val8 = kmalloc(PROC_LTV_SIZE + 2, GFP_KERNEL); + /* I'm not sure: we might have a lock here, so we'd better go + atomic, just in case. */ + val8 = kmalloc(DEBUG_LTV_SIZE + 2, GFP_ATOMIC); if (! val8) return -ENOMEM; val16 = (u16 *)val8; - for (i = 0; i < NUM_RIDS; i++) { + for (i = 0; i < ARRAY_SIZE(record_table); i++) { u16 rid = record_table[i].rid; int len; - memset(val8, 0, PROC_LTV_SIZE + 2); + memset(val8, 0, DEBUG_LTV_SIZE + 2); - err = hermes_read_ltv(hw, USER_BAP, rid, PROC_LTV_SIZE, + err = hermes_read_ltv(hw, USER_BAP, rid, DEBUG_LTV_SIZE, &length, val8); if (err) { DEBUG(0, "Error %d reading RID 0x%04x\n", err, rid); @@ -4023,190 +4092,39 @@ if (length == 0) continue; - buf += sprintf(buf, "%-15s (0x%04x): length=%d (%d bytes)\tvalue=", record_table[i].name, - rid, length, (length-1)*2); - len = min(((int)length-1)*2, PROC_LTV_SIZE); + printk(KERN_DEBUG "%-15s (0x%04x): length=%d (%d bytes)\tvalue=", + record_table[i].name, + rid, length, (length-1)*2); + len = min(((int)length-1)*2, DEBUG_LTV_SIZE); switch (record_table[i].displaytype) { case DISPLAY_WORDS: - for (j = 0; j < len / 2; j++) { - buf += sprintf(buf, "%04X-", le16_to_cpu(val16[j])); - } - buf--; + for (j = 0; j < len / 2; j++) + printk("%04X-", le16_to_cpu(val16[j])); break; case DISPLAY_BYTES: default: - for (j = 0; j < len; j++) { - buf += sprintf(buf, "%02X:", val8[j]); - } - buf--; + for (j = 0; j < len; j++) + printk("%02X:", val8[j]); break; case DISPLAY_STRING: len = min(len, le16_to_cpu(val16[0])+2); val8[len] = '\0'; - buf += sprintf(buf, "\"%s\"", (char *)&val16[1]); + printk("\"%s\"", (char *)&val16[1]); break; case DISPLAY_XSTRING: - buf += sprintf(buf, "'%s'", (char *)val8); + printk("'%s'", (char *)val8); } - buf += sprintf(buf, "\n"); - - if (shift_buffer(page, requested_offset, requested_len, - &total, &slop, &buf)) - break; - - if ( (buf - page) > PROC_SAFE_SIZE ) - break; + printk("\n"); } kfree(val8); - return calc_start_len(page, start, requested_offset, requested_len, - total, buf); -} - -#ifdef HERMES_DEBUG_BUFFER -static int -orinoco_proc_get_hermes_buf(char *page, char **start, off_t requested_offset, - int requested_len, int *eof, void *data) -{ - struct orinoco_private *priv = (struct orinoco_private *)data; - hermes_t *hw = &priv->hw; - char *buf = page; - int total = 0, slop = 0; - int i; - - for (i = 0; i < min_t(int,hw->dbufp, HERMES_DEBUG_BUFSIZE); i++) { - memcpy(buf, &hw->dbuf[i], sizeof(hw->dbuf[i])); - buf += sizeof(hw->dbuf[i]); - - if (shift_buffer(page, requested_offset, requested_len, - &total, &slop, &buf)) - break; - - if ( (buf - page) > PROC_SAFE_SIZE ) - break; - } - - return calc_start_len(page, start, requested_offset, requested_len, - total, buf); -} - -static int -orinoco_proc_get_hermes_prof(char *page, char **start, off_t requested_offset, - int requested_len, int *eof, void *data) -{ - struct orinoco_private *priv = (struct orinoco_private *)data; - hermes_t *hw = &priv->hw; - char *buf = page; - int total = 0, slop = 0; - int i; - - for (i = 0; i < (HERMES_BAP_BUSY_TIMEOUT+1); i++) { - memcpy(buf, &hw->profile[i], sizeof(hw->profile[i])); - buf += sizeof(hw->profile[i]); - - if (shift_buffer(page, requested_offset, requested_len, - &total, &slop, &buf)) - break; - - if ( (buf - page) > PROC_SAFE_SIZE ) - break; - } - - return calc_start_len(page, start, requested_offset, requested_len, - total, buf); -} -#endif /* HERMES_DEBUG_BUFFER */ - -/* initialise the /proc subsystem for the hermes driver, creating the - * separate entries */ -static int -orinoco_proc_init(void) -{ - int err = 0; - - /* create the directory for it to sit in */ - dir_base = create_proc_entry("hermes", S_IFDIR, &proc_root); - if (dir_base == NULL) { - printk(KERN_ERR "Unable to initialise /proc/hermes.\n"); - orinoco_proc_cleanup(); - err = -ENOMEM; - } - - return err; -} - -int -orinoco_proc_dev_init(struct net_device *dev) -{ - struct orinoco_private *priv = dev->priv; - struct proc_dir_entry *e; - - priv->dir_dev = NULL; - - /* create the directory for it to sit in */ - priv->dir_dev = create_proc_entry(dev->name, S_IFDIR | S_IRUGO | S_IXUGO, - dir_base); - if (! priv->dir_dev) { - printk(KERN_ERR "Unable to initialize /proc/hermes/%s\n", dev->name); - goto fail; - } - - e = create_proc_read_entry("recs", S_IFREG | S_IRUGO, - priv->dir_dev, orinoco_proc_get_hermes_recs, priv); - if (! e) { - printk(KERN_ERR "Unable to initialize /proc/hermes/%s/recs\n", dev->name); - goto fail; - } - -#ifdef HERMES_DEBUG_BUFFER - e = create_proc_read_entry("buf", S_IFREG | S_IRUGO, - priv->dir_dev, orinoco_proc_get_hermes_buf, priv); - if (! e) { - printk(KERN_ERR "Unable to initialize /proc/hermes/%s/buf\n", dev->name); - goto fail; - } - - e = create_proc_read_entry("prof", S_IFREG | S_IRUGO, - priv->dir_dev, orinoco_proc_get_hermes_prof, priv); - if (! e) { - printk(KERN_ERR "Unable to intialize /proc/hermes/%s/prof\n", dev->name); - goto fail; - } -#endif /* HERMES_DEBUG_BUFFER */ - return 0; - fail: - orinoco_proc_dev_cleanup(dev); - return -ENOMEM; -} - -void -orinoco_proc_dev_cleanup(struct net_device *dev) -{ - struct orinoco_private *priv = dev->priv; - - if (priv->dir_dev) { - remove_proc_entry("prof", priv->dir_dev); - remove_proc_entry("buf", priv->dir_dev); - remove_proc_entry("recs", priv->dir_dev); - remove_proc_entry(dev->name, dir_base); - priv->dir_dev = NULL; - } -} - -static void -orinoco_proc_cleanup(void) -{ - if (dir_base) { - remove_proc_entry("hermes", &proc_root); - dir_base = NULL; - } } struct net_device *alloc_orinocodev(int sizeof_card, int (*hard_reset)(struct orinoco_private *)) @@ -4232,6 +4150,7 @@ dev->do_ioctl = orinoco_ioctl; dev->change_mtu = orinoco_change_mtu; dev->set_multicast_list = orinoco_set_multicast_list; + /* we use the default eth_mac_addr for setting the MAC addr */ /* Set up default callbacks */ dev->open = orinoco_open; @@ -4243,7 +4162,10 @@ priv->hw_unavailable = 1; /* orinoco_init() must clear this * before anything else touches the * hardware */ - INIT_WORK(&priv->timeout_task, (void (*)(void *))orinoco_reset, dev); + INIT_WORK(&priv->reset_work, (void (*)(void *))orinoco_reset, dev); + + priv->last_linkstatus = 0xffff; + priv->connected = 0; return dev; @@ -4257,25 +4179,23 @@ EXPORT_SYMBOL(__orinoco_up); EXPORT_SYMBOL(__orinoco_down); +EXPORT_SYMBOL(orinoco_stop); EXPORT_SYMBOL(orinoco_reinit_firmware); -EXPORT_SYMBOL(orinoco_proc_dev_init); -EXPORT_SYMBOL(orinoco_proc_dev_cleanup); EXPORT_SYMBOL(orinoco_interrupt); /* Can't be declared "const" or the whole __initdata section will * become const */ -static char version[] __initdata = "orinoco.c 0.13a (David Gibson <hermes@gibson.dropbear.id.au> and others)"; +static char version[] __initdata = "orinoco.c 0.13e (David Gibson <hermes@gibson.dropbear.id.au> and others)"; static int __init init_orinoco(void) { printk(KERN_DEBUG "%s\n", version); - return orinoco_proc_init(); + return 0; } static void __exit exit_orinoco(void) { - orinoco_proc_cleanup(); } module_init(init_orinoco); diff -Nru a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco.h --- a/drivers/net/wireless/orinoco.h Mon Jun 9 23:16:09 2003 +++ b/drivers/net/wireless/orinoco.h Mon Jun 9 23:16:09 2003 @@ -11,9 +11,29 @@ #include <linux/spinlock.h> #include <linux/netdevice.h> #include <linux/wireless.h> -#include <linux/workqueue.h> +#include <linux/version.h> #include "hermes.h" +/* Workqueue / task queue backwards compatibility stuff */ + +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41) +#include <linux/workqueue.h> +#else +#include <linux/tqueue.h> +#define work_struct tq_struct +#define INIT_WORK INIT_TQUEUE +#define schedule_work schedule_task +#endif + +/* Interrupt handler backwards compatibility stuff */ +#ifndef IRQ_NONE + +#define IRQ_NONE +#define IRQ_HANDLED +typedef void irqreturn_t; + +#endif + /* To enable debug messages */ //#define ORINOCO_DEBUG 3 @@ -42,9 +62,12 @@ /* Synchronisation stuff */ spinlock_t lock; int hw_unavailable; - struct work_struct timeout_task; + struct work_struct reset_work; + /* driver state */ int open; + u16 last_linkstatus; + int connected; /* Net device stuff */ struct net_device *ndev; @@ -55,6 +78,7 @@ hermes_t hw; u16 txfid; + /* Capabilities of the hardware/firmware */ int firmware_type; #define FIRMWARE_TYPE_AGERE 1 @@ -68,6 +92,7 @@ int has_sensitivity; int nicbuf_size; u16 channel_mask; + int broken_disableport; /* Configuration paramaters */ u32 iw_mode; @@ -91,9 +116,6 @@ /* Configuration dependent variables */ int port_type, createibss; int promiscuous, mc_count; - - /* /proc based debugging stuff */ - struct proc_dir_entry *dir_dev; }; #ifdef ORINOCO_DEBUG @@ -110,10 +132,8 @@ int (*hard_reset)(struct orinoco_private *)); extern int __orinoco_up(struct net_device *dev); extern int __orinoco_down(struct net_device *dev); -int orinoco_reinit_firmware(struct net_device *dev); - -extern int orinoco_proc_dev_init(struct net_device *dev); -extern void orinoco_proc_dev_cleanup(struct net_device *dev); +extern int orinoco_stop(struct net_device *dev); +extern int orinoco_reinit_firmware(struct net_device *dev); extern irqreturn_t orinoco_interrupt(int irq, void * dev_id, struct pt_regs *regs); /********************************************************************/ diff -Nru a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c --- a/drivers/net/wireless/orinoco_cs.c Mon Jun 9 23:16:18 2003 +++ b/drivers/net/wireless/orinoco_cs.c Mon Jun 9 23:16:18 2003 @@ -1,4 +1,4 @@ -/* orinoco_cs.c 0.13a - (formerly known as dldwd_cs.c) +/* orinoco_cs.c 0.13e - (formerly known as dldwd_cs.c) * * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ @@ -14,6 +14,7 @@ #ifdef __IN_PCMCIA_PACKAGE__ #include <pcmcia/k_compat.h> #endif /* __IN_PCMCIA_PACKAGE__ */ + #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> @@ -21,9 +22,7 @@ #include <linux/ptrace.h> #include <linux/slab.h> #include <linux/string.h> -#include <linux/timer.h> #include <linux/ioport.h> -#include <linux/proc_fs.h> #include <linux/netdevice.h> #include <linux/if_arp.h> #include <linux/etherdevice.h> @@ -90,8 +89,9 @@ dev_node_t node; /* Used to handle hard reset */ - wait_queue_head_t hard_reset_queue; - int hard_reset_flag; + /* yuck, we need this hack to work around the insanity of the + * PCMCIA layer */ + unsigned long hard_reset_in_progress; }; /* @@ -128,14 +128,14 @@ dev_link_t *link = &card->link; int err; - card->hard_reset_flag = 0; + /* We need atomic ops here, because we're not holding the lock */ + set_bit(0, &card->hard_reset_in_progress); err = CardServices(ResetCard, link->handle, NULL); if (err) return err; - wait_event_interruptible(card->hard_reset_queue, - card->hard_reset_flag); + clear_bit(0, &card->hard_reset_in_progress); return 0; } @@ -144,6 +144,16 @@ /* PCMCIA stuff */ /********************************************************************/ +/* In 2.5 (as of 2.5.69 at least) there is a cs_error exported which + * does this, but it's not in 2.4 so we do our own for now. */ +static void +orinoco_cs_error(client_handle_t handle, int func, int ret) +{ + error_info_t err = { func, ret }; + CardServices(ReportError, handle, &err); +} + + /* Remove zombie instances (card removed, detach pending) */ static void flush_stale_links(void) @@ -187,7 +197,6 @@ return NULL; priv = dev->priv; card = priv->card; - init_waitqueue_head(&card->hard_reset_queue); /* Link both structures together */ link = &card->link; @@ -233,7 +242,7 @@ ret = CardServices(RegisterClient, &link->handle, &client_reg); if (ret != CS_SUCCESS) { - cs_error(link->handle, RegisterClient, ret); + orinoco_cs_error(link->handle, RegisterClient, ret); orinoco_cs_detach(link); return NULL; } @@ -262,19 +271,12 @@ return; } - /* - If the device is currently configured and active, we won't - actually delete it yet. Instead, it is marked so that when - the release() function is called, that will trigger a proper - detach(). - */ if (link->state & DEV_CONFIG) { -#ifdef PCMCIA_DEBUG - printk(KERN_DEBUG "orinoco_cs: detach postponed, '%s' " - "still locked\n", link->dev->dev_name); -#endif - link->state |= DEV_STALE_LINK; - return; + orinoco_cs_release((u_long)link); + if (link->state & DEV_CONFIG) { + link->state |= DEV_STALE_LINK; + return; + } } /* Break the link with Card Services */ @@ -465,7 +467,7 @@ link->irq.IRQInfo2 |= 1 << irq_list[i]; link->irq.Handler = orinoco_interrupt; - link->irq.Instance = priv; + link->irq.Instance = dev; CS_CHECK(RequestIRQ, link->handle, &link->irq); } @@ -522,18 +524,10 @@ link->io.BasePort2 + link->io.NumPorts2 - 1); printk("\n"); - /* And give us the proc nodes for debugging */ - if (orinoco_proc_dev_init(dev) != 0) { - printk(KERN_ERR "orinoco_cs: Failed to create /proc node for %s\n", - dev->name); - goto failed; - } - - return; cs_failed: - cs_error(link->handle, last_fn, last_ret); + orinoco_cs_error(link->handle, last_fn, last_ret); failed: orinoco_cs_release((u_long) link); @@ -550,21 +544,13 @@ dev_link_t *link = (dev_link_t *) arg; struct net_device *dev = link->priv; struct orinoco_private *priv = dev->priv; + unsigned long flags; - /* - If the device is currently in use, we won't release until it - is actually closed, because until then, we can't be sure that - no one will try to access the device or its data structures. - */ - if (priv->open) { - DEBUG(0, "orinoco_cs: release postponed, '%s' still open\n", - link->dev->dev_name); - link->state |= DEV_STALE_CONFIG; - return; - } - - /* Unregister proc entry */ - orinoco_proc_dev_cleanup(dev); + /* We're committed to taking the device away now, so mark the + * hardware as unavailable */ + spin_lock_irqsave(&priv->lock, flags); + priv->hw_unavailable++; + spin_unlock_irqrestore(&priv->lock, flags); /* Don't bother checking to see if these succeed or not */ CardServices(ReleaseConfiguration, link->handle); @@ -586,6 +572,7 @@ dev_link_t *link = args->client_data; struct net_device *dev = link->priv; struct orinoco_private *priv = dev->priv; + struct orinoco_pccard *card = priv->card; int err = 0; unsigned long flags; @@ -596,14 +583,9 @@ orinoco_lock(priv, &flags); netif_device_detach(dev); - priv->hw_unavailable = 1; + priv->hw_unavailable++; orinoco_unlock(priv, &flags); - -/* if (link->open) */ -/* orinoco_cs_stop(dev); */ - - mod_timer(&link->release, jiffies + HZ / 20); } break; @@ -618,24 +600,24 @@ case CS_EVENT_RESET_PHYSICAL: /* Mark the device as stopped, to block IO until later */ if (link->state & DEV_CONFIG) { - err = orinoco_lock(priv, &flags); - if (err) { - printk(KERN_ERR "%s: hw_unavailable on SUSPEND/RESET_PHYSICAL\n", - dev->name); - break; - } - - err = __orinoco_down(dev); - if (err) - printk(KERN_WARNING "%s: %s: Error %d downing interface\n", - dev->name, - event == CS_EVENT_PM_SUSPEND ? "SUSPEND" : "RESET_PHYSICAL", - err); + /* This is probably racy, but I can't think of + a better way, short of rewriting the PCMCIA + layer to not suck :-( */ + if (! test_bit(0, &card->hard_reset_in_progress)) { + spin_lock_irqsave(&priv->lock, flags); - netif_device_detach(dev); - priv->hw_unavailable = 1; + err = __orinoco_down(dev); + if (err) + printk(KERN_WARNING "%s: %s: Error %d downing interface\n", + dev->name, + event == CS_EVENT_PM_SUSPEND ? "SUSPEND" : "RESET_PHYSICAL", + err); + + netif_device_detach(dev); + priv->hw_unavailable++; - orinoco_unlock(priv, &flags); + spin_unlock_irqrestore(&priv->lock, flags); + } CardServices(ReleaseConfiguration, link->handle); } @@ -646,32 +628,34 @@ /* Fall through... */ case CS_EVENT_CARD_RESET: if (link->state & DEV_CONFIG) { - CardServices(RequestConfiguration, link->handle, - &link->conf); - /* FIXME: should we double check that this is * the same card as we had before */ - err = orinoco_reinit_firmware(dev); - if (err) { - printk(KERN_ERR "%s: Error %d re-initializing firmware\n", - dev->name, err); - break; - } - - spin_lock_irqsave(&priv->lock, flags); - - netif_device_attach(dev); - priv->hw_unavailable = 0; + CardServices(RequestConfiguration, link->handle, + &link->conf); - if (priv->open) { - err = __orinoco_up(dev); - if (err) - printk(KERN_ERR "%s: Error %d restarting card\n", + if (! test_bit(0, &card->hard_reset_in_progress)) { + err = orinoco_reinit_firmware(dev); + if (err) { + printk(KERN_ERR "%s: Error %d re-initializing firmware\n", dev->name, err); + break; + } + + spin_lock_irqsave(&priv->lock, flags); + + netif_device_attach(dev); + priv->hw_unavailable--; + + if (priv->open && ! priv->hw_unavailable) { + err = __orinoco_up(dev); + if (err) + printk(KERN_ERR "%s: Error %d restarting card\n", + dev->name, err); + + } + spin_unlock_irqrestore(&priv->lock, flags); } - - orinoco_unlock(priv, &flags); } break; } @@ -685,7 +669,7 @@ /* Can't be declared "const" or the whole __initdata section will * become const */ -static char version[] __initdata = "orinoco_cs.c 0.13a (David Gibson <hermes@gibson.dropbear.id.au> and others)"; +static char version[] __initdata = "orinoco_cs.c 0.13e (David Gibson <hermes@gibson.dropbear.id.au> and others)"; static struct pcmcia_driver orinoco_driver = { .owner = THIS_MODULE, @@ -712,7 +696,6 @@ if (dev_list) DEBUG(0, "orinoco_cs: Removing leftover devices.\n"); while (dev_list != NULL) { - del_timer(&dev_list->release); if (dev_list->state & DEV_CONFIG) orinoco_cs_release((u_long) dev_list); orinoco_cs_detach(dev_list); diff -Nru a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco_pci.c --- a/drivers/net/wireless/orinoco_pci.c Mon Jun 9 23:16:15 2003 +++ b/drivers/net/wireless/orinoco_pci.c Mon Jun 9 23:16:15 2003 @@ -1,4 +1,4 @@ -/* orinoco_pci.c 0.13a +/* orinoco_pci.c 0.13e * * Driver for Prism II devices that have a direct PCI interface * (i.e., not in a Pcmcia or PLX bridge) @@ -10,8 +10,10 @@ * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing * has been copied from it. linux-wlan-ng-0.1.10 is originally : * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. - * The rest is : + * This file originally written by: * Copyright (C) 2001 Jean Tourrilhes <jt@hpl.hp.com> + * And is now maintained by: + * Copyright (C) 2002 David Gibson, IBM Corporation <herme@gibson.dropbear.id.au> * * The contents of this file are subject to the Mozilla Public License * Version 1.1 (the "License"); you may not use this file except in @@ -84,6 +86,7 @@ */ #include <linux/config.h> + #include <linux/module.h> #include <linux/kernel.h> #include <linux/init.h> @@ -93,7 +96,6 @@ #include <linux/string.h> #include <linux/timer.h> #include <linux/ioport.h> -#include <linux/proc_fs.h> #include <linux/netdevice.h> #include <linux/if_arp.h> #include <linux/etherdevice.h> @@ -142,8 +144,6 @@ unsigned long timeout; u16 reg; - TRACE_ENTER(priv->ndev->name); - /* Assert the reset until the card notice */ hermes_write_regn(hw, PCI_COR, HERMES_PCI_COR_MASK); printk(KERN_NOTICE "Reset done"); @@ -180,8 +180,6 @@ } printk(KERN_NOTICE "pci_cor : reg = 0x%X - %lX - %lX\n", reg, timeout, jiffies); - TRACE_EXIT(priv->ndev->name); - return 0; } @@ -197,7 +195,6 @@ unsigned long pci_iolen; struct orinoco_private *priv = NULL; struct net_device *dev = NULL; - int netdev_registered = 0; err = pci_enable_device(pdev); if (err) @@ -218,9 +215,9 @@ } priv = dev->priv; - dev->base_addr = (int) pci_ioaddr; - dev->mem_start = (unsigned long) pci_iorange; - dev->mem_end = ((unsigned long) pci_iorange) + pci_iolen - 1; + dev->base_addr = (unsigned long) pci_ioaddr; + dev->mem_start = pci_iorange; + dev->mem_end = pci_iorange + pci_iolen - 1; SET_MODULE_OWNER(dev); @@ -228,12 +225,15 @@ "Detected Orinoco/Prism2 PCI device at %s, mem:0x%lX to 0x%lX -> 0x%p, irq:%d\n", pdev->slot_name, dev->mem_start, dev->mem_end, pci_ioaddr, pdev->irq); - hermes_struct_init(&(priv->hw), dev->base_addr, HERMES_MEM, HERMES_32BIT_REGSPACING); + hermes_struct_init(&priv->hw, dev->base_addr, + HERMES_MEM, HERMES_32BIT_REGSPACING); pci_set_drvdata(pdev, dev); - err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, dev->name, priv); + err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, + dev->name, dev); if (err) { - printk(KERN_ERR "orinoco_pci: Error allocating IRQ %d.\n", pdev->irq); + printk(KERN_ERR "orinoco_pci: Error allocating IRQ %d.\n", + pdev->irq); err = -EBUSY; goto fail; } @@ -254,24 +254,12 @@ printk(KERN_ERR "%s: Failed to register net device\n", dev->name); goto fail; } - netdev_registered = 1; - - err = orinoco_proc_dev_init(dev); - if (err) { - printk(KERN_ERR "%s: Failed to create /proc node\n", dev->name); - err = -EIO; - goto fail; - } return 0; /* succeeded */ fail: if (dev) { - orinoco_proc_dev_cleanup(dev); - if (netdev_registered) - unregister_netdev(dev); - if (dev->irq) - free_irq(dev->irq, priv); + free_irq(dev->irq, dev); kfree(dev); } @@ -279,6 +267,8 @@ if (pci_ioaddr) iounmap(pci_ioaddr); + pci_disable_device(pdev); + return err; } @@ -290,21 +280,85 @@ if (! dev) BUG(); - orinoco_proc_dev_cleanup(dev); - unregister_netdev(dev); if (dev->irq) - free_irq(dev->irq, priv); + free_irq(dev->irq, dev); if (priv->hw.iobase) iounmap((unsigned char *) priv->hw.iobase); + pci_set_drvdata(pdev, NULL); kfree(dev); pci_disable_device(pdev); } +static int orinoco_pci_suspend(struct pci_dev *pdev, u32 state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct orinoco_private *priv = dev->priv; + unsigned long flags; + int err; + + printk(KERN_DEBUG "%s: Orinoco-PCI entering sleep mode (state=%d)\n", + dev->name, state); + + err = orinoco_lock(priv, &flags); + if (err) { + printk(KERN_ERR "%s: hw_unavailable on orinoco_pci_suspend\n", + dev->name); + return err; + } + + err = __orinoco_down(dev); + if (err) + printk(KERN_WARNING "%s: orinoco_pci_suspend(): Error %d downing interface\n", + dev->name, err); + + netif_device_detach(dev); + + priv->hw_unavailable++; + + orinoco_unlock(priv, &flags); + + return 0; +} + +static int orinoco_pci_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct orinoco_private *priv = dev->priv; + unsigned long flags; + int err; + + printk(KERN_DEBUG "%s: Orinoco-PCI waking up\n", dev->name); + + err = orinoco_reinit_firmware(dev); + if (err) { + printk(KERN_ERR "%s: Error %d re-initializing firmware on orinoco_pci_resume()\n", + dev->name, err); + return err; + } + + spin_lock_irqsave(&priv->lock, flags); + + netif_device_attach(dev); + + priv->hw_unavailable--; + + if (priv->open && (! priv->hw_unavailable)) { + err = __orinoco_up(dev); + if (err) + printk(KERN_ERR "%s: Error %d restarting card on orinoco_pci_resume()\n", + dev->name, err); + } + + spin_unlock_irqrestore(&priv->lock, flags); + + return 0; +} + static struct pci_device_id orinoco_pci_pci_id_table[] __devinitdata = { {0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID,}, {0,}, @@ -317,12 +371,12 @@ .id_table = orinoco_pci_pci_id_table, .probe = orinoco_pci_init_one, .remove = __devexit_p(orinoco_pci_remove_one), - .suspend = 0, - .resume = 0 + .suspend = orinoco_pci_suspend, + .resume = orinoco_pci_resume, }; -static char version[] __initdata = "orinoco_pci.c 0.13a (Jean Tourrilhes <jt@hpl.hp.com>)"; -MODULE_AUTHOR("Jean Tourrilhes <jt@hpl.hp.com>"); +static char version[] __initdata = "orinoco_pci.c 0.13e (David Gibson <hermes@gibson.dropbear.id.au> & Jean Tourrilhes <jt@hpl.hp.com>)"; +MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>"); MODULE_DESCRIPTION("Driver for wireless LAN cards using direct PCI interface"); MODULE_LICENSE("Dual MPL/GPL"); diff -Nru a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c --- a/drivers/net/wireless/orinoco_plx.c Mon Jun 9 23:16:19 2003 +++ b/drivers/net/wireless/orinoco_plx.c Mon Jun 9 23:16:19 2003 @@ -1,4 +1,4 @@ -/* orinoco_plx.c 0.13a +/* orinoco_plx.c 0.13e * * Driver for Prism II devices which would usually be driven by orinoco_cs, * but are connected to the PCI bus by a PLX9052. @@ -119,7 +119,6 @@ #include <asm/uaccess.h> #include <asm/io.h> #include <asm/system.h> -#include <linux/proc_fs.h> #include <linux/netdevice.h> #include <linux/if_arp.h> #include <linux/etherdevice.h> @@ -156,7 +155,6 @@ unsigned long pccard_ioaddr = 0; unsigned long pccard_iolen = 0; struct net_device *dev = NULL; - int netdev_registered = 0; int i; err = pci_enable_device(pdev); @@ -201,7 +199,7 @@ addr = pci_resource_start(pdev, 1); reg = 0; reg = inl(addr+PLX_INTCSR); - if(reg & PLX_INTCSR_INTEN) + if (reg & PLX_INTCSR_INTEN) printk(KERN_DEBUG "orinoco_plx: " "Local Interrupt already enabled\n"); else { @@ -244,7 +242,7 @@ HERMES_IO, HERMES_16BIT_REGSPACING); pci_set_drvdata(pdev, dev); - err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, dev->name, priv); + err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, dev->name, dev); if (err) { printk(KERN_ERR "orinoco_plx: Error allocating IRQ %d.\n", pdev->irq); err = -EBUSY; @@ -255,27 +253,17 @@ err = register_netdev(dev); if (err) goto fail; - netdev_registered = 1; - - err = orinoco_proc_dev_init(dev); - if (err) - goto fail; return 0; /* succeeded */ fail: printk(KERN_DEBUG "orinoco_plx: init_one(), FAIL!\n"); - if (priv) { - orinoco_proc_dev_cleanup(dev); - - if (netdev_registered) - unregister_netdev(dev); - + if (dev) { if (dev->irq) - free_irq(dev->irq, priv); + free_irq(dev->irq, dev); - kfree(priv); + kfree(dev); } if (pccard_ioaddr) @@ -292,18 +280,17 @@ static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct orinoco_private *priv = dev->priv; if (! dev) BUG(); - orinoco_proc_dev_cleanup(dev); - unregister_netdev(dev); if (dev->irq) - free_irq(dev->irq, priv); + free_irq(dev->irq, dev); + pci_set_drvdata(pdev, NULL); + kfree(dev); release_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3)); @@ -341,7 +328,7 @@ .resume = 0, }; -static char version[] __initdata = "orinoco_plx.c 0.13a (Daniel Barlow <dan@telent.net>, David Gibson <hermes@gibson.dropbear.id.au>)"; +static char version[] __initdata = "orinoco_plx.c 0.13e (Daniel Barlow <dan@telent.net>, David Gibson <hermes@gibson.dropbear.id.au>)"; MODULE_AUTHOR("Daniel Barlow <dan@telent.net>"); MODULE_DESCRIPTION("Driver for wireless LAN cards using the PLX9052 PCI bridge"); #ifdef MODULE_LICENSE diff -Nru a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco_tmd.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/net/wireless/orinoco_tmd.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,238 @@ +/* orinoco_tmd.c 0.01 + * + * Driver for Prism II devices which would usually be driven by orinoco_cs, + * but are connected to the PCI bus by a TMD7160. + * + * Copyright (C) 2003 Joerg Dorchain <joerg@dorchain.net> + * based heavily upon orinoco_plx.c Copyright (C) 2001 Daniel Barlow <dan@telent.net> + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License version 2 (the "GPL"), in + * which case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use your + * version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + + * Caution: this is experimental and probably buggy. For success and + * failure reports for different cards and adaptors, see + * orinoco_tmd_pci_id_table near the end of the file. If you have a + * card we don't have the PCI id for, and looks like it should work, + * drop me mail with the id and "it works"/"it doesn't work". + * + * Note: if everything gets detected fine but it doesn't actually send + * or receive packets, your first port of call should probably be to + * try newer firmware in the card. Especially if you're doing Ad-Hoc + * modes + * + * The actual driving is done by orinoco.c, this is just resource + * allocation stuff. + * + * This driver is modeled after the orinoco_plx driver. The main + * difference is that the TMD chip has only IO port ranges and no + * memory space, i.e. no access to the CIS. Compared to the PLX chip, + * the io range functionalities are exchanged. + * + * Pheecom sells cards with the TMD chip as "ASIC version" + */ + +#include <linux/config.h> + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/ptrace.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/ioport.h> +#include <asm/uaccess.h> +#include <asm/io.h> +#include <asm/system.h> +#include <linux/netdevice.h> +#include <linux/if_arp.h> +#include <linux/etherdevice.h> +#include <linux/wireless.h> +#include <linux/list.h> +#include <linux/pci.h> +#include <linux/wireless.h> +#include <linux/fcntl.h> + +#include <pcmcia/cisreg.h> + +#include "hermes.h" +#include "orinoco.h" + +static char dev_info[] = "orinoco_tmd"; + +#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA | COR_FUNC_ENA) /* Enable PC card with level triggered irqs and irq requests */ + + +static int orinoco_tmd_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int err = 0; + u32 reg, addr; + struct orinoco_private *priv = NULL; + unsigned long pccard_ioaddr = 0; + unsigned long pccard_iolen = 0; + struct net_device *dev = NULL; + + err = pci_enable_device(pdev); + if (err) + return -EIO; + + printk(KERN_DEBUG "TMD setup\n"); + pccard_ioaddr = pci_resource_start(pdev, 2); + pccard_iolen = pci_resource_len(pdev, 2); + if (! request_region(pccard_ioaddr, pccard_iolen, dev_info)) { + printk(KERN_ERR "orinoco_tmd: I/O resource at 0x%lx len 0x%lx busy\n", + pccard_ioaddr, pccard_iolen); + pccard_ioaddr = 0; + err = -EBUSY; + goto fail; + } + addr = pci_resource_start(pdev, 1); + outb(COR_VALUE, addr); + mdelay(1); + reg = inb(addr); + if (reg != COR_VALUE) { + printk(KERN_ERR "orinoco_tmd: Error setting TMD COR values %x should be %x\n", reg, COR_VALUE); + err = -EIO; + goto fail; + } + + dev = alloc_orinocodev(0, NULL); + if (! dev) { + err = -ENOMEM; + goto fail; + } + + priv = dev->priv; + dev->base_addr = pccard_ioaddr; + SET_MODULE_OWNER(dev); + + printk(KERN_DEBUG + "Detected Orinoco/Prism2 TMD device at %s irq:%d, io addr:0x%lx\n", + pdev->slot_name, pdev->irq, pccard_ioaddr); + + hermes_struct_init(&(priv->hw), dev->base_addr, + HERMES_IO, HERMES_16BIT_REGSPACING); + pci_set_drvdata(pdev, dev); + + err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, dev->name, + dev); + if (err) { + printk(KERN_ERR "orinoco_tmd: Error allocating IRQ %d.\n", + pdev->irq); + err = -EBUSY; + goto fail; + } + dev->irq = pdev->irq; + + err = register_netdev(dev); + if (err) + goto fail; + + return 0; /* succeeded */ + + fail: + printk(KERN_DEBUG "orinoco_tmd: init_one(), FAIL!\n"); + + if (dev) { + if (dev->irq) + free_irq(dev->irq, dev); + + kfree(dev); + } + + if (pccard_ioaddr) + release_region(pccard_ioaddr, pccard_iolen); + + pci_disable_device(pdev); + + return err; +} + +static void __devexit orinoco_tmd_remove_one(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + + if (! dev) + BUG(); + + unregister_netdev(dev); + + if (dev->irq) + free_irq(dev->irq, dev); + + pci_set_drvdata(pdev, NULL); + + kfree(dev); + + release_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2)); + + pci_disable_device(pdev); +} + + +static struct pci_device_id orinoco_tmd_pci_id_table[] __devinitdata = { + {0x15e8, 0x0131, PCI_ANY_ID, PCI_ANY_ID,}, /* NDC and OEMs, e.g. pheecom */ + {0,}, +}; + +MODULE_DEVICE_TABLE(pci, orinoco_tmd_pci_id_table); + +static struct pci_driver orinoco_tmd_driver = { + .name = "orinoco_tmd", + .id_table = orinoco_tmd_pci_id_table, + .probe = orinoco_tmd_init_one, + .remove = __devexit_p(orinoco_tmd_remove_one), + .suspend = 0, + .resume = 0, +}; + +static char version[] __initdata = "orinoco_tmd.c 0.01 (Joerg Dorchain <joerg@dorchain.net>)"; +MODULE_AUTHOR("Joerg Dorchain <joerg@dorchain.net>"); +MODULE_DESCRIPTION("Driver for wireless LAN cards using the TMD7160 PCI bridge"); +#ifdef MODULE_LICENSE +MODULE_LICENSE("Dual MPL/GPL"); +#endif + +static int __init orinoco_tmd_init(void) +{ + printk(KERN_DEBUG "%s\n", version); + return pci_module_init(&orinoco_tmd_driver); +} + +extern void __exit orinoco_tmd_exit(void) +{ + pci_unregister_driver(&orinoco_tmd_driver); + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(HZ); +} + +module_init(orinoco_tmd_init); +module_exit(orinoco_tmd_exit); + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff -Nru a/drivers/parport/parport_cs.c b/drivers/parport/parport_cs.c --- a/drivers/parport/parport_cs.c Mon Jun 9 23:16:19 2003 +++ b/drivers/parport/parport_cs.c Mon Jun 9 23:16:19 2003 @@ -390,28 +390,27 @@ return 0; } /* parport_event */ -/*====================================================================*/ +static struct pcmcia_driver parport_cs_driver = { + .owner = THIS_MODULE, + .drv = { + .name = "parport_cs", + }, + .attach = parport_attach, + .detach = parport_detach, +}; static int __init init_parport_cs(void) { - servinfo_t serv; - DEBUG(0, "%s\n", version); - CardServices(GetCardServicesInfo, &serv); - if (serv.Revision != CS_RELEASE_CODE) { - printk(KERN_NOTICE "parport_cs: Card Services release " - "does not match!\n"); - return -EINVAL; - } - register_pccard_driver(&dev_info, &parport_attach, &parport_detach); - return 0; + return pcmcia_register_driver(&parport_cs_driver); } static void __exit exit_parport_cs(void) { - DEBUG(0, "parport_cs: unloading\n"); - unregister_pccard_driver(&dev_info); - while (dev_list != NULL) - parport_detach(dev_list); + pcmcia_unregister_driver(&parport_cs_driver); + + /* XXX: this really needs to move into generic code.. */ + while (dev_list != NULL) + parport_detach(dev_list); } module_init(init_parport_cs); diff -Nru a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c --- a/drivers/parport/parport_pc.c Mon Jun 9 23:16:19 2003 +++ b/drivers/parport/parport_pc.c Mon Jun 9 23:16:19 2003 @@ -2979,10 +2979,10 @@ static int __init parport_pc_init_superio (int autoirq, int autodma) { const struct pci_device_id *id; - struct pci_dev *pdev; + struct pci_dev *pdev = NULL; int ret = 0; - pci_for_each_dev(pdev) { + while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { id = pci_match_device (parport_pc_pci_tbl, pdev); if (id == NULL || id->driver_data >= last_sio) continue; diff -Nru a/drivers/pci/Makefile b/drivers/pci/Makefile --- a/drivers/pci/Makefile Mon Jun 9 23:16:18 2003 +++ b/drivers/pci/Makefile Mon Jun 9 23:16:18 2003 @@ -12,6 +12,9 @@ obj-$(CONFIG_PCI) += setup-res.o endif +# Build the PCI Hotplug drivers if we were asked to +obj-$(CONFIG_HOTPLUG_PCI) += hotplug/ + # # Some architectures use the generic PCI setup functions # diff -Nru a/drivers/pci/access.c b/drivers/pci/access.c --- a/drivers/pci/access.c Mon Jun 9 23:16:20 2003 +++ b/drivers/pci/access.c Mon Jun 9 23:16:20 2003 @@ -7,7 +7,7 @@ * configuration space. */ -spinlock_t pci_lock = SPIN_LOCK_UNLOCKED; +static spinlock_t pci_lock = SPIN_LOCK_UNLOCKED; /* * Wrappers for all PCI configuration access functions. They just check @@ -60,4 +60,3 @@ EXPORT_SYMBOL(pci_bus_write_config_byte); EXPORT_SYMBOL(pci_bus_write_config_word); EXPORT_SYMBOL(pci_bus_write_config_dword); -EXPORT_SYMBOL(pci_lock); diff -Nru a/drivers/pci/bus.c b/drivers/pci/bus.c --- a/drivers/pci/bus.c Mon Jun 9 23:16:19 2003 +++ b/drivers/pci/bus.c Mon Jun 9 23:16:19 2003 @@ -94,9 +94,7 @@ device_add(&dev->dev); list_add_tail(&dev->global_list, &pci_devices); -#ifdef CONFIG_PROC_FS pci_proc_attach_device(dev); -#endif pci_create_sysfs_dev_files(dev); } @@ -129,6 +127,5 @@ } } -EXPORT_SYMBOL(pci_bus_alloc_resource); EXPORT_SYMBOL(pci_bus_add_devices); EXPORT_SYMBOL(pci_enable_bridges); diff -Nru a/drivers/pci/hotplug/Kconfig b/drivers/pci/hotplug/Kconfig --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pci/hotplug/Kconfig Mon Jun 9 23:16:10 2003 @@ -0,0 +1,120 @@ +# +# PCI Hotplug support +# + +menu "PCI Hotplug Support" + depends on HOTPLUG + +config HOTPLUG_PCI + tristate "Support for PCI Hotplug (EXPERIMENTAL)" + depends on PCI && EXPERIMENTAL + ---help--- + Say Y here if you have a motherboard with a PCI Hotplug controller. + This allows you to add and remove PCI cards while the machine is + powered up and running. The file system pcihpfs must be mounted + in order to interact with any PCI Hotplug controllers. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called pci_hotplug. If you want to compile it + as a module, say M here and read <file:Documentation/modules.txt>. + + When in doubt, say N. + +config HOTPLUG_PCI_COMPAQ + tristate "Compaq PCI Hotplug driver" + depends on HOTPLUG_PCI && X86 + help + Say Y here if you have a motherboard with a Compaq PCI Hotplug + controller. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called cpqphp. If you want to compile it + as a module, say M here and read <file:Documentation/modules.txt>. + + When in doubt, say N. + +config HOTPLUG_PCI_COMPAQ_NVRAM + bool "Save configuration into NVRAM on Compaq servers" + depends on HOTPLUG_PCI_COMPAQ + help + Say Y here if you have a Compaq server that has a PCI Hotplug + controller. This will allow the PCI Hotplug driver to store the PCI + system configuration options in NVRAM. + + When in doubt, say N. + +config HOTPLUG_PCI_IBM + tristate "IBM PCI Hotplug driver" + depends on HOTPLUG_PCI && X86_IO_APIC && X86 + help + Say Y here if you have a motherboard with a IBM PCI Hotplug + controller. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called cpqphp. If you want to compile it + as a module, say M here and read <file:Documentation/modules.txt>. + + When in doubt, say N. + +config HOTPLUG_PCI_ACPI + tristate "ACPI PCI Hotplug driver" + depends on ACPI_BUS && HOTPLUG_PCI + help + Say Y here if you have a system that supports PCI Hotplug using + ACPI. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called acpiphp. If you want to compile it + as a module, say M here and read <file:Documentation/modules.txt>. + + When in doubt, say N. + +config HOTPLUG_PCI_CPCI + tristate "CompactPCI Hotplug driver" + depends on HOTPLUG_PCI + help + Say Y here if you have a CompactPCI system card with CompactPCI + hotswap support per the PICMG 2.1 specification. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called cpci_hotplug. If you want to compile it + as a module, say M here and read <file:Documentation/modules.txt>. + + When in doubt, say N. + +config HOTPLUG_PCI_CPCI_ZT5550 + tristate "Ziatech ZT5550 CompactPCI Hotplug driver" + depends on HOTPLUG_PCI_CPCI && X86 + help + Say Y here if you have an Performance Technologies (formerly Intel, + formerly just Ziatech) Ziatech ZT5550 CompactPCI system card. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called cpcihp_zt5550. If you want to compile it + as a module, say M here and read <file:Documentation/modules.txt>. + + When in doubt, say N. + +config HOTPLUG_PCI_CPCI_GENERIC + tristate "Generic port I/O CompactPCI Hotplug driver" + depends on HOTPLUG_PCI_CPCI && X86 + help + Say Y here if you have a CompactPCI system card that exposes the #ENUM + hotswap signal as a bit in a system register that can be read through + standard port I/O. + + This code is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called cpcihp_generic. If you want to compile it + as a module, say M here and read <file:Documentation/modules.txt>. + + When in doubt, say N. + +endmenu + diff -Nru a/drivers/pci/hotplug/Makefile b/drivers/pci/hotplug/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pci/hotplug/Makefile Mon Jun 9 23:16:15 2003 @@ -0,0 +1,44 @@ +# +# Makefile for the Linux kernel pci hotplug controller drivers. +# + +obj-$(CONFIG_HOTPLUG_PCI) += pci_hotplug.o +obj-$(CONFIG_HOTPLUG_PCI_COMPAQ) += cpqphp.o +obj-$(CONFIG_HOTPLUG_PCI_IBM) += ibmphp.o +obj-$(CONFIG_HOTPLUG_PCI_ACPI) += acpiphp.o +obj-$(CONFIG_HOTPLUG_PCI_CPCI_ZT5550) += cpcihp_zt5550.o +obj-$(CONFIG_HOTPLUG_PCI_CPCI_GENERIC) += cpcihp_generic.o + +pci_hotplug-objs := pci_hotplug_core.o + +ifdef CONFIG_HOTPLUG_PCI_CPCI +pci_hotplug-objs += cpci_hotplug_core.o \ + cpci_hotplug_pci.o +endif + +cpqphp-objs := cpqphp_core.o \ + cpqphp_ctrl.o \ + cpqphp_sysfs.o \ + cpqphp_pci.o + +ibmphp-objs := ibmphp_core.o \ + ibmphp_ebda.o \ + ibmphp_pci.o \ + ibmphp_res.o \ + ibmphp_hpc.o + +acpiphp-objs := acpiphp_core.o \ + acpiphp_glue.o \ + acpiphp_pci.o \ + acpiphp_res.o + +ifdef CONFIG_HOTPLUG_PCI_ACPI + EXTRA_CFLAGS += -D_LINUX -I$(TOPDIR)/drivers/acpi + ifdef CONFIG_ACPI_DEBUG + EXTRA_CFLAGS += -DACPI_DEBUG_OUTPUT + endif +endif + +ifeq ($(CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM),y) + cpqphp-objs += cpqphp_nvram.o +endif diff -Nru a/drivers/pci/hotplug/acpiphp.h b/drivers/pci/hotplug/acpiphp.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pci/hotplug/acpiphp.h Mon Jun 9 23:16:19 2003 @@ -0,0 +1,262 @@ +/* + * ACPI PCI Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) + * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) + * Copyright (c) 2002 NEC Corporation + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Send feedback to <gregkh@us.ibm.com>, + * <h-aono@ap.jp.nec.com>, + * <t-kouchi@cq.jp.nec.com> + * + */ + +#ifndef _ACPIPHP_H +#define _ACPIPHP_H + +#include <linux/acpi.h> +#include "pci_hotplug.h" + +#define dbg(format, arg...) \ + do { \ + if (acpiphp_debug) \ + printk(KERN_DEBUG "%s: " format, \ + MY_NAME , ## arg); \ + } while (0) +#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format, MY_NAME , ## arg) + +#define SLOT_MAGIC 0x67267322 +/* name size which is used for entries in pcihpfs */ +#define SLOT_NAME_SIZE 32 /* ACPI{_SUN}-{BUS}:{DEV} */ + +struct acpiphp_bridge; +struct acpiphp_slot; +struct pci_resource; + +/* + * struct slot - slot information for each *physical* slot + */ +struct slot { + u32 magic; + u8 number; + struct hotplug_slot *hotplug_slot; + struct list_head slot_list; + + struct acpiphp_slot *acpi_slot; +}; + +/* + * struct pci_resource - describes pci resource (mem, pfmem, io, bus) + */ +struct pci_resource { + struct pci_resource * next; + u64 base; + u32 length; +}; + +/** + * struct hpp_param - ACPI 2.0 _HPP Hot Plug Parameters + * @cache_line_size in DWORD + * @latency_timer in PCI clock + * @enable_SERR 0 or 1 + * @enable_PERR 0 or 1 + */ +struct hpp_param { + u8 cache_line_size; + u8 latency_timer; + u8 enable_SERR; + u8 enable_PERR; +}; + + +/** + * struct acpiphp_bridge - PCI bridge information + * + * for each bridge device in ACPI namespace + */ +struct acpiphp_bridge { + struct list_head list; + acpi_handle handle; + struct acpiphp_slot *slots; + int type; + int nr_slots; + + u8 seg; + u8 bus; + u8 sub; + + u32 flags; + + /* This bus (host bridge) or Secondary bus (PCI-to-PCI bridge) */ + struct pci_bus *pci_bus; + + /* PCI-to-PCI bridge device */ + struct pci_dev *pci_dev; + + /* ACPI 2.0 _HPP parameters */ + struct hpp_param hpp; + + spinlock_t res_lock; + + /* available resources on this bus */ + struct pci_resource *mem_head; + struct pci_resource *p_mem_head; + struct pci_resource *io_head; + struct pci_resource *bus_head; +}; + + +/** + * struct acpiphp_slot - PCI slot information + * + * PCI slot information for each *physical* PCI slot + */ +struct acpiphp_slot { + struct acpiphp_slot *next; + struct acpiphp_bridge *bridge; /* parent */ + struct list_head funcs; /* one slot may have different + objects (i.e. for each function) */ + struct semaphore crit_sect; + + u32 id; /* slot id (serial #) for hotplug core */ + u8 device; /* pci device# */ + + u32 sun; /* ACPI _SUN (slot unique number) */ + u32 slotno; /* slot number relative to bridge */ + u32 flags; /* see below */ +}; + + +/** + * struct acpiphp_func - PCI function information + * + * PCI function information for each object in ACPI namespace + * typically 8 objects per slot (i.e. for each PCI function) + */ +struct acpiphp_func { + struct acpiphp_slot *slot; /* parent */ + + struct list_head sibling; + struct pci_dev *pci_dev; + + acpi_handle handle; + + u8 function; /* pci function# */ + u32 flags; /* see below */ + + /* resources used for this function */ + struct pci_resource *mem_head; + struct pci_resource *p_mem_head; + struct pci_resource *io_head; + struct pci_resource *bus_head; +}; + + +/* PCI bus bridge HID */ +#define ACPI_PCI_HOST_HID "PNP0A03" + +/* PCI BRIDGE type */ +#define BRIDGE_TYPE_HOST 0 +#define BRIDGE_TYPE_P2P 1 + +/* ACPI _STA method value (ignore bit 4; battery present) */ +#define ACPI_STA_PRESENT (0x00000001) +#define ACPI_STA_ENABLED (0x00000002) +#define ACPI_STA_SHOW_IN_UI (0x00000004) +#define ACPI_STA_FUNCTIONING (0x00000008) +#define ACPI_STA_ALL (0x0000000f) + +/* bridge flags */ +#define BRIDGE_HAS_STA (0x00000001) +#define BRIDGE_HAS_EJ0 (0x00000002) +#define BRIDGE_HAS_HPP (0x00000004) +#define BRIDGE_HAS_PS0 (0x00000010) +#define BRIDGE_HAS_PS1 (0x00000020) +#define BRIDGE_HAS_PS2 (0x00000040) +#define BRIDGE_HAS_PS3 (0x00000080) + +/* slot flags */ + +#define SLOT_POWEREDON (0x00000001) +#define SLOT_ENABLED (0x00000002) +#define SLOT_MULTIFUNCTION (x000000004) + +/* function flags */ + +#define FUNC_HAS_STA (0x00000001) +#define FUNC_HAS_EJ0 (0x00000002) +#define FUNC_HAS_PS0 (0x00000010) +#define FUNC_HAS_PS1 (0x00000020) +#define FUNC_HAS_PS2 (0x00000040) +#define FUNC_HAS_PS3 (0x00000080) + +/* not yet */ +#define SLOT_SUPPORT_66MHZ (0x00010000) +#define SLOT_SUPPORT_100MHZ (0x00020000) +#define SLOT_SUPPORT_133MHZ (0x00040000) +#define SLOT_SUPPORT_PCIX (0x00080000) + +/* function prototypes */ + +/* acpiphp_glue.c */ +extern int acpiphp_glue_init (void); +extern void acpiphp_glue_exit (void); +extern int acpiphp_get_num_slots (void); +extern struct acpiphp_slot *get_slot_from_id (int id); +typedef int (*acpiphp_callback)(struct acpiphp_slot *slot, void *data); +extern int acpiphp_for_each_slot (acpiphp_callback fn, void *data); + +extern int acpiphp_check_bridge (struct acpiphp_bridge *bridge); +extern int acpiphp_enable_slot (struct acpiphp_slot *slot); +extern int acpiphp_disable_slot (struct acpiphp_slot *slot); +extern u8 acpiphp_get_power_status (struct acpiphp_slot *slot); +extern u8 acpiphp_get_attention_status (struct acpiphp_slot *slot); +extern u8 acpiphp_get_latch_status (struct acpiphp_slot *slot); +extern u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot); + +/* acpiphp_pci.c */ +extern struct pci_dev *acpiphp_allocate_pcidev (struct pci_bus *pbus, int dev, int fn); +extern int acpiphp_configure_slot (struct acpiphp_slot *slot); +extern int acpiphp_configure_function (struct acpiphp_func *func); +extern int acpiphp_unconfigure_function (struct acpiphp_func *func); +extern int acpiphp_detect_pci_resource (struct acpiphp_bridge *bridge); +extern int acpiphp_init_func_resource (struct acpiphp_func *func); + +/* acpiphp_res.c */ +extern struct pci_resource *acpiphp_get_io_resource (struct pci_resource **head, u32 size); +extern struct pci_resource *acpiphp_get_max_resource (struct pci_resource **head, u32 size); +extern struct pci_resource *acpiphp_get_resource (struct pci_resource **head, u32 size); +extern struct pci_resource *acpiphp_get_resource_with_base (struct pci_resource **head, u64 base, u32 size); +extern int acpiphp_resource_sort_and_combine (struct pci_resource **head); +extern struct pci_resource *acpiphp_make_resource (u64 base, u32 length); +extern void acpiphp_move_resource (struct pci_resource **from, struct pci_resource **to); +extern void acpiphp_free_resource (struct pci_resource **res); +extern void acpiphp_dump_resource (struct acpiphp_bridge *bridge); /* debug */ +extern void acpiphp_dump_func_resource (struct acpiphp_func *func); /* debug */ + +/* variables */ +extern int acpiphp_debug; + +#endif /* _ACPIPHP_H */ diff -Nru a/drivers/pci/hotplug/acpiphp_core.c b/drivers/pci/hotplug/acpiphp_core.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pci/hotplug/acpiphp_core.c Mon Jun 9 23:16:14 2003 @@ -0,0 +1,505 @@ +/* + * ACPI PCI Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) + * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) + * Copyright (c) 2002 NEC Corporation + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Send feedback to <gregkh@us.ibm.com>, + * <h-aono@ap.jp.nec.com>, + * <t-kouchi@cq.jp.nec.com> + * + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/slab.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> +#include <linux/init.h> +#include "pci_hotplug.h" +#include "acpiphp.h" + +static LIST_HEAD(slot_list); + +#if !defined(CONFIG_HOTPLUG_PCI_ACPI_MODULE) + #define MY_NAME "acpiphp" +#else + #define MY_NAME THIS_MODULE->name +#endif + +static int debug; +int acpiphp_debug; + +/* local variables */ +static int num_slots; + +#define DRIVER_VERSION "0.4" +#define DRIVER_AUTHOR "Greg Kroah-Hartman <gregkh@us.ibm.com>, Takayoshi Kochi <t-kouchi@cq.jp.nec.com>" +#define DRIVER_DESC "ACPI Hot Plug PCI Controller Driver" + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); + +static int enable_slot (struct hotplug_slot *slot); +static int disable_slot (struct hotplug_slot *slot); +static int set_attention_status (struct hotplug_slot *slot, u8 value); +static int hardware_test (struct hotplug_slot *slot, u32 value); +static int get_power_status (struct hotplug_slot *slot, u8 *value); +static int get_attention_status (struct hotplug_slot *slot, u8 *value); +static int get_latch_status (struct hotplug_slot *slot, u8 *value); +static int get_adapter_status (struct hotplug_slot *slot, u8 *value); +static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value); +static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value); + +static struct hotplug_slot_ops acpi_hotplug_slot_ops = { + .owner = THIS_MODULE, + .enable_slot = enable_slot, + .disable_slot = disable_slot, + .set_attention_status = set_attention_status, + .hardware_test = hardware_test, + .get_power_status = get_power_status, + .get_attention_status = get_attention_status, + .get_latch_status = get_latch_status, + .get_adapter_status = get_adapter_status, + .get_max_bus_speed = get_max_bus_speed, + .get_cur_bus_speed = get_cur_bus_speed, +}; + + +/* Inline functions to check the sanity of a pointer that is passed to us */ +static inline int slot_paranoia_check (struct slot *slot, const char *function) +{ + if (!slot) { + dbg("%s - slot == NULL\n", function); + return -1; + } + if (slot->magic != SLOT_MAGIC) { + dbg("%s - bad magic number for slot\n", function); + return -1; + } + if (!slot->hotplug_slot) { + dbg("%s - slot->hotplug_slot == NULL!\n", function); + return -1; + } + return 0; +} + + +static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function) +{ + struct slot *slot; + + if (!hotplug_slot) { + dbg("%s - hotplug_slot == NULL\n", function); + return NULL; + } + + slot = (struct slot *)hotplug_slot->private; + if (slot_paranoia_check(slot, function)) + return NULL; + return slot; +} + + +/** + * enable_slot - power on and enable a slot + * @hotplug_slot: slot to enable + * + * Actual tasks are done in acpiphp_enable_slot() + * + */ +static int enable_slot (struct hotplug_slot *hotplug_slot) +{ + struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + /* enable the specified slot */ + retval = acpiphp_enable_slot(slot->acpi_slot); + + return retval; +} + + +/** + * disable_slot - disable and power off a slot + * @hotplug_slot: slot to disable + * + * Actual tasks are done in acpiphp_disable_slot() + * + */ +static int disable_slot (struct hotplug_slot *hotplug_slot) +{ + struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + /* disable the specified slot */ + retval = acpiphp_disable_slot(slot->acpi_slot); + + return retval; +} + + +/** + * set_attention_status - set attention LED + * + * TBD: + * ACPI doesn't have known method to manipulate + * attention status LED. + * + */ +static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status) +{ + int retval = 0; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + switch (status) { + case 0: + /* FIXME turn light off */ + hotplug_slot->info->attention_status = 0; + break; + + case 1: + default: + /* FIXME turn light on */ + hotplug_slot->info->attention_status = 1; + break; + } + + return retval; +} + + +/** + * hardware_test - hardware test + * + * We have nothing to do for now... + * + */ +static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value) +{ + struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + err("No hardware tests are defined for this driver\n"); + retval = -ENODEV; + + return retval; +} + + +/** + * get_power_status - get power status of a slot + * @hotplug_slot: slot to get status + * @value: pointer to store status + * + * Some platforms may not implement _STA method properly. + * In that case, the value returned may not be reliable. + * + */ +static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + *value = acpiphp_get_power_status(slot->acpi_slot); + + return retval; +} + + +/** + * get_attention_status - get attention LED status + * + * TBD: + * ACPI doesn't provide any formal means to access attention LED status. + * + */ +static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + int retval = 0; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + *value = hotplug_slot->info->attention_status; + + return retval; +} + + +/** + * get_latch_status - get latch status of a slot + * @hotplug_slot: slot to get status + * @value: pointer to store status + * + * ACPI doesn't provide any formal means to access latch status. + * Instead, we fake latch status from _STA + * + */ +static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + *value = acpiphp_get_latch_status(slot->acpi_slot); + + return retval; +} + + +/** + * get_adapter_status - get adapter status of a slot + * @hotplug_slot: slot to get status + * @value: pointer to store status + * + * ACPI doesn't provide any formal means to access adapter status. + * Instead, we fake adapter status from _STA + * + */ +static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + *value = acpiphp_get_adapter_status(slot->acpi_slot); + + return retval; +} + + +/* return dummy value because ACPI doesn't provide any method... */ +static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) +{ + struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + + if (slot == NULL) + return -ENODEV; + + *value = PCI_SPEED_UNKNOWN; + + return 0; +} + + +/* return dummy value because ACPI doesn't provide any method... */ +static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) +{ + struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + + if (slot == NULL) + return -ENODEV; + + *value = PCI_SPEED_UNKNOWN; + + return 0; +} + + +static int init_acpi (void) +{ + int retval; + + /* initialize internal data structure etc. */ + retval = acpiphp_glue_init(); + + /* read initial number of slots */ + if (!retval) { + num_slots = acpiphp_get_num_slots(); + if (num_slots == 0) + retval = -ENODEV; + } + + return retval; +} + + +/** + * make_slot_name - make a slot name that appears in pcihpfs + * @slot: slot to name + * + */ +static void make_slot_name (struct slot *slot) +{ + snprintf(slot->hotplug_slot->name, SLOT_NAME_SIZE, "ACPI%d-%02x:%02x", + slot->acpi_slot->sun, + slot->acpi_slot->bridge->bus, + slot->acpi_slot->device); +} + +/** + * init_slots - initialize 'struct slot' structures for each slot + * + */ +static int init_slots (void) +{ + struct slot *slot; + int retval = 0; + int i; + + for (i = 0; i < num_slots; ++i) { + slot = kmalloc(sizeof(struct slot), GFP_KERNEL); + if (!slot) + return -ENOMEM; + memset(slot, 0, sizeof(struct slot)); + + slot->hotplug_slot = kmalloc(sizeof(struct hotplug_slot), GFP_KERNEL); + if (!slot->hotplug_slot) { + kfree(slot); + return -ENOMEM; + } + memset(slot->hotplug_slot, 0, sizeof(struct hotplug_slot)); + + slot->hotplug_slot->info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL); + if (!slot->hotplug_slot->info) { + kfree(slot->hotplug_slot); + kfree(slot); + return -ENOMEM; + } + memset(slot->hotplug_slot->info, 0, sizeof(struct hotplug_slot_info)); + + slot->hotplug_slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL); + if (!slot->hotplug_slot->name) { + kfree(slot->hotplug_slot->info); + kfree(slot->hotplug_slot); + kfree(slot); + return -ENOMEM; + } + + slot->magic = SLOT_MAGIC; + slot->number = i; + + slot->hotplug_slot->private = slot; + slot->hotplug_slot->ops = &acpi_hotplug_slot_ops; + + slot->acpi_slot = get_slot_from_id(i); + slot->hotplug_slot->info->power_status = acpiphp_get_power_status(slot->acpi_slot); + slot->hotplug_slot->info->attention_status = acpiphp_get_attention_status(slot->acpi_slot); + slot->hotplug_slot->info->latch_status = acpiphp_get_latch_status(slot->acpi_slot); + slot->hotplug_slot->info->adapter_status = acpiphp_get_adapter_status(slot->acpi_slot); + + make_slot_name(slot); + + retval = pci_hp_register(slot->hotplug_slot); + if (retval) { + err("pci_hp_register failed with error %d\n", retval); + kfree(slot->hotplug_slot->info); + kfree(slot->hotplug_slot->name); + kfree(slot->hotplug_slot); + kfree(slot); + return retval; + } + + /* add slot to our internal list */ + list_add(&slot->slot_list, &slot_list); + info("Slot [%s] registered\n", slot->hotplug_slot->name); + } + + return retval; +} + + +static void cleanup_slots (void) +{ + struct list_head *tmp, *n; + struct slot *slot; + + list_for_each_safe (tmp, n, &slot_list) { + slot = list_entry(tmp, struct slot, slot_list); + list_del(&slot->slot_list); + pci_hp_deregister(slot->hotplug_slot); + kfree(slot->hotplug_slot->info); + kfree(slot->hotplug_slot->name); + kfree(slot->hotplug_slot); + kfree(slot); + } + + return; +} + + +static int __init acpiphp_init(void) +{ + int retval; + + info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); + + acpiphp_debug = debug; + + /* read all the ACPI info from the system */ + retval = init_acpi(); + if (retval) + return retval; + + retval = init_slots(); + if (retval) + return retval; + + return 0; +} + + +static void __exit acpiphp_exit(void) +{ + cleanup_slots(); + /* deallocate internal data structures etc. */ + acpiphp_glue_exit(); +} + +module_init(acpiphp_init); +module_exit(acpiphp_exit); diff -Nru a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pci/hotplug/acpiphp_glue.c Mon Jun 9 23:16:09 2003 @@ -0,0 +1,1336 @@ +/* + * ACPI PCI HotPlug glue functions to ACPI CA subsystem + * + * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) + * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) + * Copyright (c) 2002 NEC Corporation + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Send feedback to <t-kouchi@cq.jp.nec.com> + * + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/smp_lock.h> +#include <linux/init.h> +#include <asm/semaphore.h> + +#include "../pci.h" +#include "pci_hotplug.h" +#include "acpiphp.h" + +static LIST_HEAD(bridge_list); + +#define MY_NAME "acpiphp_glue" + +static void handle_hotplug_event_bridge (acpi_handle, u32, void *); +static void handle_hotplug_event_func (acpi_handle, u32, void *); + +/* + * initialization & terminatation routines + */ + +/** + * is_ejectable - determine if a slot is ejectable + * @handle: handle to acpi namespace + * + * Ejectable slot should satisfy at least these conditions: + * + * 1. has _ADR method + * 2. has _EJ0 method + * + * optionally + * + * 1. has _STA method + * 2. has _PS0 method + * 3. has _PS3 method + * 4. .. + * + */ +static int is_ejectable (acpi_handle handle) +{ + acpi_status status; + acpi_handle tmp; + + status = acpi_get_handle(handle, "_ADR", &tmp); + if (ACPI_FAILURE(status)) { + return 0; + } + + status = acpi_get_handle(handle, "_EJ0", &tmp); + if (ACPI_FAILURE(status)) { + return 0; + } + + return 1; +} + + +/* callback routine to check the existence of ejectable slots */ +static acpi_status +is_ejectable_slot (acpi_handle handle, u32 lvl, void *context, void **rv) +{ + int *count = (int *)context; + + if (is_ejectable(handle)) { + (*count)++; + /* only one ejectable slot is enough */ + return AE_CTRL_TERMINATE; + } else { + return AE_OK; + } +} + + +/* callback routine to register each ACPI PCI slot object */ +static acpi_status +register_slot (acpi_handle handle, u32 lvl, void *context, void **rv) +{ + struct acpiphp_bridge *bridge = (struct acpiphp_bridge *)context; + struct acpiphp_slot *slot; + struct acpiphp_func *newfunc; + acpi_handle tmp; + acpi_status status = AE_OK; + unsigned long adr, sun; + int device, function; + static int num_slots = 0; /* XXX if we support I/O node hotplug... */ + + status = acpi_evaluate_integer(handle, "_ADR", NULL, &adr); + + if (ACPI_FAILURE(status)) + return AE_OK; + + status = acpi_get_handle(handle, "_EJ0", &tmp); + + if (ACPI_FAILURE(status)) + return AE_OK; + + device = (adr >> 16) & 0xffff; + function = adr & 0xffff; + + newfunc = kmalloc(sizeof(struct acpiphp_func), GFP_KERNEL); + if (!newfunc) + return AE_NO_MEMORY; + memset(newfunc, 0, sizeof(struct acpiphp_func)); + + INIT_LIST_HEAD(&newfunc->sibling); + newfunc->handle = handle; + newfunc->function = function; + newfunc->flags = FUNC_HAS_EJ0; + + if (ACPI_SUCCESS(acpi_get_handle(handle, "_STA", &tmp))) + newfunc->flags |= FUNC_HAS_STA; + + if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS0", &tmp))) + newfunc->flags |= FUNC_HAS_PS0; + + if (ACPI_SUCCESS(acpi_get_handle(handle, "_PS3", &tmp))) + newfunc->flags |= FUNC_HAS_PS3; + + status = acpi_evaluate_integer(handle, "_SUN", NULL, &sun); + if (ACPI_FAILURE(status)) + sun = -1; + + /* search for objects that share the same slot */ + for (slot = bridge->slots; slot; slot = slot->next) + if (slot->device == device) { + if (slot->sun != sun) + warn("sibling found, but _SUN doesn't match!\n"); + break; + } + + if (!slot) { + slot = kmalloc(sizeof(struct acpiphp_slot), GFP_KERNEL); + if (!slot) { + kfree(newfunc); + return AE_NO_MEMORY; + } + + memset(slot, 0, sizeof(struct acpiphp_slot)); + slot->bridge = bridge; + slot->id = num_slots++; + slot->device = device; + slot->sun = sun; + INIT_LIST_HEAD(&slot->funcs); + init_MUTEX(&slot->crit_sect); + + slot->next = bridge->slots; + bridge->slots = slot; + + bridge->nr_slots++; + + dbg("found ACPI PCI Hotplug slot at PCI %02x:%02x Slot:%d\n", + slot->bridge->bus, slot->device, slot->sun); + } + + newfunc->slot = slot; + list_add_tail(&newfunc->sibling, &slot->funcs); + + /* associate corresponding pci_dev */ + newfunc->pci_dev = pci_find_slot(bridge->bus, + PCI_DEVFN(device, function)); + if (newfunc->pci_dev) { + if (acpiphp_init_func_resource(newfunc) < 0) { + kfree(newfunc); + return AE_ERROR; + } + slot->flags |= (SLOT_ENABLED | SLOT_POWEREDON); + } + + /* install notify handler */ + status = acpi_install_notify_handler(handle, + ACPI_SYSTEM_NOTIFY, + handle_hotplug_event_func, + newfunc); + + if (ACPI_FAILURE(status)) { + err("failed to register interrupt notify handler\n"); + kfree(newfunc); + return status; + } + + return AE_OK; +} + + +/* see if it's worth looking at this bridge */ +static int detect_ejectable_slots (acpi_handle *bridge_handle) +{ + acpi_status status; + int count; + + count = 0; + + /* only check slots defined directly below bridge object */ + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge_handle, (u32)1, + is_ejectable_slot, (void *)&count, NULL); + + return count; +} + + +/* decode ACPI _CRS data and convert into our internal resource list + * TBD: _TRA, etc. + */ +static acpi_status +decode_acpi_resource (struct acpi_resource *resource, void *context) +{ + struct acpiphp_bridge *bridge = (struct acpiphp_bridge *) context; + struct acpi_resource_address64 address; + struct pci_resource *res; + + if (resource->id != ACPI_RSTYPE_ADDRESS16 && + resource->id != ACPI_RSTYPE_ADDRESS32 && + resource->id != ACPI_RSTYPE_ADDRESS64) + return AE_OK; + + acpi_resource_to_address64(resource, &address); + + if (address.producer_consumer == ACPI_PRODUCER && address.address_length > 0) { + dbg("resource type: %d: 0x%llx - 0x%llx\n", address.resource_type, address.min_address_range, address.max_address_range); + res = acpiphp_make_resource(address.min_address_range, + address.address_length); + if (!res) { + err("out of memory\n"); + return AE_OK; + } + + switch (address.resource_type) { + case ACPI_MEMORY_RANGE: + if (address.attribute.memory.cache_attribute == ACPI_PREFETCHABLE_MEMORY) { + res->next = bridge->p_mem_head; + bridge->p_mem_head = res; + } else { + res->next = bridge->mem_head; + bridge->mem_head = res; + } + break; + case ACPI_IO_RANGE: + res->next = bridge->io_head; + bridge->io_head = res; + break; + case ACPI_BUS_NUMBER_RANGE: + res->next = bridge->bus_head; + bridge->bus_head = res; + break; + default: + /* invalid type */ + kfree(res); + break; + } + } + + return AE_OK; +} + +/* decode ACPI 2.0 _HPP hot plug parameters */ +static void decode_hpp(struct acpiphp_bridge *bridge) +{ + acpi_status status; + struct acpi_buffer buffer = { .length = ACPI_ALLOCATE_BUFFER, + .pointer = NULL}; + union acpi_object *package; + int i; + + /* default numbers */ + bridge->hpp.cache_line_size = 0x10; + bridge->hpp.latency_timer = 0x40; + bridge->hpp.enable_SERR = 0; + bridge->hpp.enable_PERR = 0; + + status = acpi_evaluate_object(bridge->handle, "_HPP", NULL, &buffer); + + if (ACPI_FAILURE(status)) { + dbg("_HPP evaluation failed\n"); + return; + } + + package = (union acpi_object *) buffer.pointer; + + if (!package || package->type != ACPI_TYPE_PACKAGE || + package->package.count != 4 || !package->package.elements) { + err("invalid _HPP object; ignoring\n"); + goto err_exit; + } + + for (i = 0; i < 4; i++) { + if (package->package.elements[i].type != ACPI_TYPE_INTEGER) { + err("invalid _HPP parameter type; ignoring\n"); + goto err_exit; + } + } + + bridge->hpp.cache_line_size = package->package.elements[0].integer.value; + bridge->hpp.latency_timer = package->package.elements[1].integer.value; + bridge->hpp.enable_SERR = package->package.elements[2].integer.value; + bridge->hpp.enable_PERR = package->package.elements[3].integer.value; + + dbg("_HPP parameter = (%02x, %02x, %02x, %02x)\n", + bridge->hpp.cache_line_size, + bridge->hpp.latency_timer, + bridge->hpp.enable_SERR, + bridge->hpp.enable_PERR); + + bridge->flags |= BRIDGE_HAS_HPP; + + err_exit: + kfree(buffer.pointer); +} + + +/* initialize miscellaneous stuff for both root and PCI-to-PCI bridge */ +static void init_bridge_misc (struct acpiphp_bridge *bridge) +{ + acpi_status status; + + /* decode ACPI 2.0 _HPP (hot plug parameters) */ + decode_hpp(bridge); + + /* subtract all resources already allocated */ + acpiphp_detect_pci_resource(bridge); + + /* register all slot objects under this bridge */ + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, bridge->handle, (u32)1, + register_slot, bridge, NULL); + + /* install notify handler */ + status = acpi_install_notify_handler(bridge->handle, + ACPI_SYSTEM_NOTIFY, + handle_hotplug_event_bridge, + bridge); + + if (ACPI_FAILURE(status)) { + err("failed to register interrupt notify handler\n"); + } + + list_add(&bridge->list, &bridge_list); + + dbg("Bridge resource:\n"); + acpiphp_dump_resource(bridge); +} + + +/* allocate and initialize host bridge data structure */ +static void add_host_bridge (acpi_handle *handle, int seg, int bus) +{ + acpi_status status; + struct acpiphp_bridge *bridge; + + bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); + if (bridge == NULL) + return; + + memset(bridge, 0, sizeof(struct acpiphp_bridge)); + + bridge->type = BRIDGE_TYPE_HOST; + bridge->handle = handle; + bridge->seg = seg; + bridge->bus = bus; + + bridge->pci_bus = pci_find_bus(bus); + + bridge->res_lock = SPIN_LOCK_UNLOCKED; + + /* to be overridden when we decode _CRS */ + bridge->sub = bridge->bus; + + /* decode resources */ + + status = acpi_walk_resources(handle, METHOD_NAME__CRS, + decode_acpi_resource, bridge); + + if (ACPI_FAILURE(status)) { + err("failed to decode bridge resources\n"); + kfree(bridge); + return; + } + + acpiphp_resource_sort_and_combine(&bridge->io_head); + acpiphp_resource_sort_and_combine(&bridge->mem_head); + acpiphp_resource_sort_and_combine(&bridge->p_mem_head); + acpiphp_resource_sort_and_combine(&bridge->bus_head); + + dbg("ACPI _CRS resource:\n"); + acpiphp_dump_resource(bridge); + + if (bridge->bus_head) { + bridge->bus = bridge->bus_head->base; + bridge->sub = bridge->bus_head->base + bridge->bus_head->length - 1; + } + + init_bridge_misc(bridge); +} + + +/* allocate and initialize PCI-to-PCI bridge data structure */ +static void add_p2p_bridge (acpi_handle *handle, int seg, int bus, int dev, int fn) +{ + struct acpiphp_bridge *bridge; + u8 tmp8; + u16 tmp16; + u64 base64, limit64; + u32 base, limit, base32u, limit32u; + + bridge = kmalloc(sizeof(struct acpiphp_bridge), GFP_KERNEL); + if (bridge == NULL) { + err("out of memory\n"); + return; + } + + memset(bridge, 0, sizeof(struct acpiphp_bridge)); + + bridge->type = BRIDGE_TYPE_P2P; + bridge->handle = handle; + bridge->seg = seg; + + bridge->pci_dev = pci_find_slot(bus, PCI_DEVFN(dev, fn)); + if (!bridge->pci_dev) { + err("Can't get pci_dev\n"); + kfree(bridge); + return; + } + + bridge->pci_bus = bridge->pci_dev->subordinate; + if (!bridge->pci_bus) { + err("This is not a PCI-to-PCI bridge!\n"); + kfree(bridge); + return; + } + + bridge->res_lock = SPIN_LOCK_UNLOCKED; + + bridge->bus = bridge->pci_bus->number; + bridge->sub = bridge->pci_bus->subordinate; + + /* + * decode resources under this P2P bridge + */ + + /* I/O resources */ + pci_read_config_byte(bridge->pci_dev, PCI_IO_BASE, &tmp8); + base = tmp8; + pci_read_config_byte(bridge->pci_dev, PCI_IO_LIMIT, &tmp8); + limit = tmp8; + + switch (base & PCI_IO_RANGE_TYPE_MASK) { + case PCI_IO_RANGE_TYPE_16: + base = (base << 8) & 0xf000; + limit = ((limit << 8) & 0xf000) + 0xfff; + bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1); + if (!bridge->io_head) { + err("out of memory\n"); + kfree(bridge); + return; + } + dbg("16bit I/O range: %04x-%04x\n", + (u32)bridge->io_head->base, + (u32)(bridge->io_head->base + bridge->io_head->length - 1)); + break; + case PCI_IO_RANGE_TYPE_32: + pci_read_config_word(bridge->pci_dev, PCI_IO_BASE_UPPER16, &tmp16); + base = ((u32)tmp16 << 16) | ((base << 8) & 0xf000); + pci_read_config_word(bridge->pci_dev, PCI_IO_LIMIT_UPPER16, &tmp16); + limit = (((u32)tmp16 << 16) | ((limit << 8) & 0xf000)) + 0xfff; + bridge->io_head = acpiphp_make_resource((u64)base, limit - base + 1); + if (!bridge->io_head) { + err("out of memory\n"); + kfree(bridge); + return; + } + dbg("32bit I/O range: %08x-%08x\n", + (u32)bridge->io_head->base, + (u32)(bridge->io_head->base + bridge->io_head->length - 1)); + break; + case 0x0f: + dbg("I/O space unsupported\n"); + break; + default: + warn("Unknown I/O range type\n"); + } + + /* Memory resources (mandatory for P2P bridge) */ + pci_read_config_word(bridge->pci_dev, PCI_MEMORY_BASE, &tmp16); + base = (tmp16 & 0xfff0) << 16; + pci_read_config_word(bridge->pci_dev, PCI_MEMORY_LIMIT, &tmp16); + limit = ((tmp16 & 0xfff0) << 16) | 0xfffff; + bridge->mem_head = acpiphp_make_resource((u64)base, limit - base + 1); + if (!bridge->mem_head) { + err("out of memory\n"); + kfree(bridge); + return; + } + dbg("32bit Memory range: %08x-%08x\n", + (u32)bridge->mem_head->base, + (u32)(bridge->mem_head->base + bridge->mem_head->length-1)); + + /* Prefetchable Memory resources (optional) */ + pci_read_config_word(bridge->pci_dev, PCI_PREF_MEMORY_BASE, &tmp16); + base = tmp16; + pci_read_config_word(bridge->pci_dev, PCI_PREF_MEMORY_LIMIT, &tmp16); + limit = tmp16; + + switch (base & PCI_MEMORY_RANGE_TYPE_MASK) { + case PCI_PREF_RANGE_TYPE_32: + base = (base & 0xfff0) << 16; + limit = ((limit & 0xfff0) << 16) | 0xfffff; + bridge->p_mem_head = acpiphp_make_resource((u64)base, limit - base + 1); + if (!bridge->p_mem_head) { + err("out of memory\n"); + kfree(bridge); + return; + } + dbg("32bit Prefetchable memory range: %08x-%08x\n", + (u32)bridge->p_mem_head->base, + (u32)(bridge->p_mem_head->base + bridge->p_mem_head->length - 1)); + break; + case PCI_PREF_RANGE_TYPE_64: + pci_read_config_dword(bridge->pci_dev, PCI_PREF_BASE_UPPER32, &base32u); + pci_read_config_dword(bridge->pci_dev, PCI_PREF_LIMIT_UPPER32, &limit32u); + base64 = ((u64)base32u << 32) | ((base & 0xfff0) << 16); + limit64 = (((u64)limit32u << 32) | ((limit & 0xfff0) << 16)) + 0xfffff; + + bridge->p_mem_head = acpiphp_make_resource(base64, limit64 - base64 + 1); + if (!bridge->p_mem_head) { + err("out of memory\n"); + kfree(bridge); + return; + } + dbg("64bit Prefetchable memory range: %08x%08x-%08x%08x\n", + (u32)(bridge->p_mem_head->base >> 32), + (u32)(bridge->p_mem_head->base & 0xffffffff), + (u32)((bridge->p_mem_head->base + bridge->p_mem_head->length - 1) >> 32), + (u32)((bridge->p_mem_head->base + bridge->p_mem_head->length - 1) & 0xffffffff)); + break; + case 0x0f: + break; + default: + warn("Unknown prefetchale memory type\n"); + } + + init_bridge_misc(bridge); +} + + +/* callback routine to find P2P bridges */ +static acpi_status +find_p2p_bridge (acpi_handle handle, u32 lvl, void *context, void **rv) +{ + acpi_status status; + acpi_handle dummy_handle; + unsigned long *segbus = context; + unsigned long tmp; + int seg, bus, device, function; + struct pci_dev *dev; + + /* get PCI address */ + seg = (*segbus >> 8) & 0xff; + bus = *segbus & 0xff; + + status = acpi_get_handle(handle, "_ADR", &dummy_handle); + if (ACPI_FAILURE(status)) + return AE_OK; /* continue */ + + status = acpi_evaluate_integer(handle, "_ADR", NULL, &tmp); + if (ACPI_FAILURE(status)) { + dbg("%s: _ADR evaluation failure\n", __FUNCTION__); + return AE_OK; + } + + device = (tmp >> 16) & 0xffff; + function = tmp & 0xffff; + + dev = pci_find_slot(bus, PCI_DEVFN(device, function)); + + if (!dev) + return AE_OK; + + if (!dev->subordinate) + return AE_OK; + + /* check if this bridge has ejectable slots */ + if (detect_ejectable_slots(handle) > 0) { + dbg("found PCI-to-PCI bridge at PCI %s\n", dev->slot_name); + add_p2p_bridge(handle, seg, bus, device, function); + } + + return AE_OK; +} + + +/* find hot-pluggable slots, and then find P2P bridge */ +static int add_bridges(struct acpi_device *device) +{ + acpi_handle *handle = device->handle; + acpi_status status; + unsigned long tmp; + int seg, bus; + acpi_handle dummy_handle; + + /* if the bridge doesn't have _STA, we assume it is always there */ + status = acpi_get_handle(handle, "_STA", &dummy_handle); + if (ACPI_SUCCESS(status)) { + status = acpi_evaluate_integer(handle, "_STA", NULL, &tmp); + if (ACPI_FAILURE(status)) { + dbg("%s: _STA evaluation failure\n", __FUNCTION__); + return 0; + } + if ((tmp & ACPI_STA_FUNCTIONING) == 0) + /* don't register this object */ + return 0; + } + + /* get PCI segment number */ + status = acpi_evaluate_integer(handle, "_SEG", NULL, &tmp); + + seg = ACPI_SUCCESS(status) ? tmp : 0; + + /* get PCI bus number */ + status = acpi_evaluate_integer(handle, "_BBN", NULL, &tmp); + + if (ACPI_SUCCESS(status)) { + bus = tmp; + } else { + warn("can't get bus number, assuming 0\n"); + bus = 0; + } + + /* check if this bridge has ejectable slots */ + if (detect_ejectable_slots(handle) > 0) { + dbg("found PCI host-bus bridge with hot-pluggable slots\n"); + add_host_bridge(handle, seg, bus); + return 0; + } + + tmp = seg << 8 | bus; + + /* search P2P bridges under this host bridge */ + status = acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, (u32)1, + find_p2p_bridge, &tmp, NULL); + + if (ACPI_FAILURE(status)) + warn("find_p2p_bridge faied (error code = 0x%x)\n",status); + + return 0; +} + + +static int power_on_slot (struct acpiphp_slot *slot) +{ + acpi_status status; + struct acpiphp_func *func; + struct list_head *l; + int retval = 0; + + /* is this already enabled? */ + if (slot->flags & SLOT_POWEREDON) + goto err_exit; + + list_for_each (l, &slot->funcs) { + func = list_entry(l, struct acpiphp_func, sibling); + + if (func->flags & FUNC_HAS_PS0) { + dbg("%s: executing _PS0 on %s\n", __FUNCTION__, + func->pci_dev->slot_name); + status = acpi_evaluate_object(func->handle, "_PS0", NULL, NULL); + if (ACPI_FAILURE(status)) { + warn("%s: _PS0 failed\n", __FUNCTION__); + retval = -1; + goto err_exit; + } + } + } + + /* TBD: evaluate _STA to check if the slot is enabled */ + + slot->flags |= SLOT_POWEREDON; + + err_exit: + return retval; +} + + +static int power_off_slot (struct acpiphp_slot *slot) +{ + acpi_status status; + struct acpiphp_func *func; + struct list_head *l; + struct acpi_object_list arg_list; + union acpi_object arg; + + int retval = 0; + + /* is this already enabled? */ + if ((slot->flags & SLOT_POWEREDON) == 0) + goto err_exit; + + list_for_each (l, &slot->funcs) { + func = list_entry(l, struct acpiphp_func, sibling); + + if (func->flags & FUNC_HAS_PS3) { + dbg("%s: executing _PS3 on %s\n", __FUNCTION__, + func->pci_dev->slot_name); + status = acpi_evaluate_object(func->handle, "_PS3", NULL, NULL); + if (ACPI_FAILURE(status)) { + warn("%s: _PS3 failed\n", __FUNCTION__); + retval = -1; + goto err_exit; + } + } + } + + list_for_each (l, &slot->funcs) { + func = list_entry(l, struct acpiphp_func, sibling); + + if (func->flags & FUNC_HAS_EJ0) { + dbg("%s: executing _EJ0 on %s\n", __FUNCTION__, + func->pci_dev->slot_name); + + /* _EJ0 method take one argument */ + arg_list.count = 1; + arg_list.pointer = &arg; + arg.type = ACPI_TYPE_INTEGER; + arg.integer.value = 1; + + status = acpi_evaluate_object(func->handle, "_EJ0", &arg_list, NULL); + if (ACPI_FAILURE(status)) { + warn("%s: _EJ0 failed\n", __FUNCTION__); + retval = -1; + goto err_exit; + } + } + } + + /* TBD: evaluate _STA to check if the slot is disabled */ + + slot->flags &= (~SLOT_POWEREDON); + + err_exit: + return retval; +} + + +/** + * enable_device - enable, configure a slot + * @slot: slot to be enabled + * + * This function should be called per *physical slot*, + * not per each slot object in ACPI namespace. + * + */ +static int enable_device (struct acpiphp_slot *slot) +{ + u8 bus; + struct pci_dev *dev; + struct pci_bus *child; + struct list_head *l; + struct acpiphp_func *func; + int retval = 0; + int num; + + if (slot->flags & SLOT_ENABLED) + goto err_exit; + + /* sanity check: dev should be NULL when hot-plugged in */ + dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0)); + if (dev) { + /* This case shouldn't happen */ + err("pci_dev structure already exists.\n"); + retval = -1; + goto err_exit; + } + + /* allocate resources to device */ + retval = acpiphp_configure_slot(slot); + if (retval) + goto err_exit; + + /* returned `dev' is the *first function* only! */ + num = pci_scan_slot(slot->bridge->pci_bus, PCI_DEVFN(slot->device, 0)); + if (num) + pci_bus_add_devices(slot->bridge->pci_bus); + dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0)); + + if (!dev) { + err("No new device found\n"); + retval = -1; + goto err_exit; + } + + if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + pci_read_config_byte(dev, PCI_SECONDARY_BUS, &bus); + child = (struct pci_bus*) pci_add_new_bus(dev->bus, dev, bus); + pci_do_scan_bus(child); + } + + /* associate pci_dev to our representation */ + list_for_each (l, &slot->funcs) { + func = list_entry(l, struct acpiphp_func, sibling); + + func->pci_dev = pci_find_slot(slot->bridge->bus, + PCI_DEVFN(slot->device, + func->function)); + if (!func->pci_dev) + continue; + + /* configure device */ + retval = acpiphp_configure_function(func); + if (retval) + goto err_exit; + } + + slot->flags |= SLOT_ENABLED; + + dbg("Available resources:\n"); + acpiphp_dump_resource(slot->bridge); + + err_exit: + return retval; +} + + +/** + * disable_device - disable a slot + */ +static int disable_device (struct acpiphp_slot *slot) +{ + int retval = 0; + struct acpiphp_func *func; + struct list_head *l; + + /* is this slot already disabled? */ + if (!(slot->flags & SLOT_ENABLED)) + goto err_exit; + + list_for_each (l, &slot->funcs) { + func = list_entry(l, struct acpiphp_func, sibling); + + if (func->pci_dev) { + if (acpiphp_unconfigure_function(func) == 0) { + func->pci_dev = NULL; + } else { + err("failed to unconfigure device\n"); + retval = -1; + goto err_exit; + } + } + } + + slot->flags &= (~SLOT_ENABLED); + + err_exit: + return retval; +} + + +/** + * get_slot_status - get ACPI slot status + * + * if a slot has _STA for each function and if any one of them + * returned non-zero status, return it + * + * if a slot doesn't have _STA and if any one of its functions' + * configuration space is configured, return 0x0f as a _STA + * + * otherwise return 0 + */ +static unsigned int get_slot_status (struct acpiphp_slot *slot) +{ + acpi_status status; + unsigned long sta = 0; + u32 dvid; + struct list_head *l; + struct acpiphp_func *func; + + list_for_each (l, &slot->funcs) { + func = list_entry(l, struct acpiphp_func, sibling); + + if (func->flags & FUNC_HAS_STA) { + status = acpi_evaluate_integer(func->handle, "_STA", NULL, &sta); + if (ACPI_SUCCESS(status) && sta) + break; + } else { + pci_bus_read_config_dword(slot->bridge->pci_bus, + PCI_DEVFN(slot->device, + func->function), + PCI_VENDOR_ID, &dvid); + if (dvid != 0xffffffff) { + sta = ACPI_STA_ALL; + break; + } + } + } + + return (unsigned int)sta; +} + + +/* + * ACPI event handlers + */ + +/** + * handle_hotplug_event_bridge - handle ACPI event on bridges + * + * @handle: Notify()'ed acpi_handle + * @type: Notify code + * @context: pointer to acpiphp_bridge structure + * + * handles ACPI event notification on {host,p2p} bridges + * + */ +static void handle_hotplug_event_bridge (acpi_handle handle, u32 type, void *context) +{ + struct acpiphp_bridge *bridge; + char objname[64]; + struct acpi_buffer buffer = { .length = sizeof(objname), + .pointer = objname }; + + bridge = (struct acpiphp_bridge *)context; + + acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); + + switch (type) { + case ACPI_NOTIFY_BUS_CHECK: + /* bus re-enumerate */ + dbg("%s: Bus check notify on %s\n", __FUNCTION__, objname); + acpiphp_check_bridge(bridge); + break; + + case ACPI_NOTIFY_DEVICE_CHECK: + /* device check */ + dbg("%s: Device check notify on %s\n", __FUNCTION__, objname); + acpiphp_check_bridge(bridge); + break; + + case ACPI_NOTIFY_DEVICE_WAKE: + /* wake event */ + dbg("%s: Device wake notify on %s\n", __FUNCTION__, objname); + break; + + case ACPI_NOTIFY_EJECT_REQUEST: + /* request device eject */ + dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname); + break; + + default: + warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); + break; + } +} + + +/** + * handle_hotplug_event_func - handle ACPI event on functions (i.e. slots) + * + * @handle: Notify()'ed acpi_handle + * @type: Notify code + * @context: pointer to acpiphp_func structure + * + * handles ACPI event notification on slots + * + */ +static void handle_hotplug_event_func (acpi_handle handle, u32 type, void *context) +{ + struct acpiphp_func *func; + char objname[64]; + struct acpi_buffer buffer = { .length = sizeof(objname), + .pointer = objname }; + + acpi_get_name(handle, ACPI_FULL_PATHNAME, &buffer); + + func = (struct acpiphp_func *)context; + + switch (type) { + case ACPI_NOTIFY_BUS_CHECK: + /* bus re-enumerate */ + dbg("%s: Bus check notify on %s\n", __FUNCTION__, objname); + acpiphp_enable_slot(func->slot); + break; + + case ACPI_NOTIFY_DEVICE_CHECK: + /* device check : re-enumerate from parent bus */ + dbg("%s: Device check notify on %s\n", __FUNCTION__, objname); + acpiphp_check_bridge(func->slot->bridge); + break; + + case ACPI_NOTIFY_DEVICE_WAKE: + /* wake event */ + dbg("%s: Device wake notify on %s\n", __FUNCTION__, objname); + break; + + case ACPI_NOTIFY_EJECT_REQUEST: + /* request device eject */ + dbg("%s: Device eject notify on %s\n", __FUNCTION__, objname); + acpiphp_disable_slot(func->slot); + break; + + default: + warn("notify_handler: unknown event type 0x%x for %s\n", type, objname); + break; + } +} + +static struct acpi_driver acpi_pci_hp_driver = { + .name = "pci_hp", + .class = "", + .ids = ACPI_PCI_HOST_HID, + .ops = { + .add = add_bridges, + } +}; + +/** + * acpiphp_glue_init - initializes all PCI hotplug - ACPI glue data structures + * + */ +int acpiphp_glue_init (void) +{ + acpi_status status; + + if (list_empty(&pci_root_buses)) + return -1; + + status = acpi_bus_register_driver(&acpi_pci_hp_driver); + + if (ACPI_FAILURE(status)) { + err("%s: acpi_walk_namespace() failed\n", __FUNCTION__); + return -1; + } + + return 0; +} + + +/** + * acpiphp_glue_exit - terminates all PCI hotplug - ACPI glue data structures + * + * This function frees all data allocated in acpiphp_glue_init() + */ +void acpiphp_glue_exit (void) +{ + struct list_head *l1, *l2, *n1, *n2; + struct acpiphp_bridge *bridge; + struct acpiphp_slot *slot, *next; + struct acpiphp_func *func; + acpi_status status; + + list_for_each_safe (l1, n1, &bridge_list) { + bridge = (struct acpiphp_bridge *)l1; + slot = bridge->slots; + while (slot) { + next = slot->next; + list_for_each_safe (l2, n2, &slot->funcs) { + func = list_entry(l2, struct acpiphp_func, sibling); + acpiphp_free_resource(&func->io_head); + acpiphp_free_resource(&func->mem_head); + acpiphp_free_resource(&func->p_mem_head); + acpiphp_free_resource(&func->bus_head); + status = acpi_remove_notify_handler(func->handle, + ACPI_SYSTEM_NOTIFY, + handle_hotplug_event_func); + if (ACPI_FAILURE(status)) + err("failed to remove notify handler\n"); + kfree(func); + } + kfree(slot); + slot = next; + } + status = acpi_remove_notify_handler(bridge->handle, ACPI_SYSTEM_NOTIFY, + handle_hotplug_event_bridge); + if (ACPI_FAILURE(status)) + err("failed to remove notify handler\n"); + + acpiphp_free_resource(&bridge->io_head); + acpiphp_free_resource(&bridge->mem_head); + acpiphp_free_resource(&bridge->p_mem_head); + acpiphp_free_resource(&bridge->bus_head); + + kfree(bridge); + } +} + + +/** + * acpiphp_get_num_slots - count number of slots in a system + */ +int acpiphp_get_num_slots (void) +{ + struct list_head *node; + struct acpiphp_bridge *bridge; + int num_slots; + + num_slots = 0; + + list_for_each (node, &bridge_list) { + bridge = (struct acpiphp_bridge *)node; + dbg("Bus%d %dslot(s)\n", bridge->bus, bridge->nr_slots); + num_slots += bridge->nr_slots; + } + + dbg("Total %dslots\n", num_slots); + return num_slots; +} + + +/** + * acpiphp_for_each_slot - call function for each slot + * @fn: callback function + * @data: context to be passed to callback function + * + */ +int acpiphp_for_each_slot(acpiphp_callback fn, void *data) +{ + struct list_head *node; + struct acpiphp_bridge *bridge; + struct acpiphp_slot *slot; + int retval = 0; + + list_for_each (node, &bridge_list) { + bridge = (struct acpiphp_bridge *)node; + for (slot = bridge->slots; slot; slot = slot->next) { + retval = fn(slot, data); + if (!retval) + goto err_exit; + } + } + + err_exit: + return retval; +} + + +/* search matching slot from id */ +struct acpiphp_slot *get_slot_from_id (int id) +{ + struct list_head *node; + struct acpiphp_bridge *bridge; + struct acpiphp_slot *slot; + + list_for_each (node, &bridge_list) { + bridge = (struct acpiphp_bridge *)node; + for (slot = bridge->slots; slot; slot = slot->next) + if (slot->id == id) + return slot; + } + + /* should never happen! */ + err("%s: no object for id %d\n",__FUNCTION__, id); + return 0; +} + + +/** + * acpiphp_enable_slot - power on slot + */ +int acpiphp_enable_slot (struct acpiphp_slot *slot) +{ + int retval; + + down(&slot->crit_sect); + + /* wake up all functions */ + retval = power_on_slot(slot); + if (retval) + goto err_exit; + + if (get_slot_status(slot) == ACPI_STA_ALL) + /* configure all functions */ + retval = enable_device(slot); + + err_exit: + up(&slot->crit_sect); + return retval; +} + + +/** + * acpiphp_disable_slot - power off slot + */ +int acpiphp_disable_slot (struct acpiphp_slot *slot) +{ + int retval = 0; + + down(&slot->crit_sect); + + /* unconfigure all functions */ + retval = disable_device(slot); + if (retval) + goto err_exit; + + /* power off all functions */ + retval = power_off_slot(slot); + if (retval) + goto err_exit; + + acpiphp_resource_sort_and_combine(&slot->bridge->io_head); + acpiphp_resource_sort_and_combine(&slot->bridge->mem_head); + acpiphp_resource_sort_and_combine(&slot->bridge->p_mem_head); + acpiphp_resource_sort_and_combine(&slot->bridge->bus_head); + dbg("Available resources:\n"); + acpiphp_dump_resource(slot->bridge); + + err_exit: + up(&slot->crit_sect); + return retval; +} + + +/** + * acpiphp_check_bridge - re-enumerate devices + */ +int acpiphp_check_bridge (struct acpiphp_bridge *bridge) +{ + struct acpiphp_slot *slot; + unsigned int sta; + int retval = 0; + int enabled, disabled; + + enabled = disabled = 0; + + for (slot = bridge->slots; slot; slot = slot->next) { + sta = get_slot_status(slot); + if (slot->flags & SLOT_ENABLED) { + /* if enabled but not present, disable */ + if (sta != ACPI_STA_ALL) { + retval = acpiphp_disable_slot(slot); + if (retval) { + err("Error occurred in enabling\n"); + up(&slot->crit_sect); + goto err_exit; + } + enabled++; + } + } else { + /* if disabled but present, enable */ + if (sta == ACPI_STA_ALL) { + retval = acpiphp_enable_slot(slot); + if (retval) { + err("Error occurred in enabling\n"); + up(&slot->crit_sect); + goto err_exit; + } + disabled++; + } + } + } + + dbg("%s: %d enabled, %d disabled\n", __FUNCTION__, enabled, disabled); + + err_exit: + return retval; +} + + +/* + * slot enabled: 1 + * slot disabled: 0 + */ +u8 acpiphp_get_power_status (struct acpiphp_slot *slot) +{ + unsigned int sta; + + sta = get_slot_status(slot); + + return (sta & ACPI_STA_ENABLED) ? 1 : 0; +} + + +/* + * attention LED ON: 1 + * OFF: 0 + * + * TBD + * no direct attention led status information via ACPI + * + */ +u8 acpiphp_get_attention_status (struct acpiphp_slot *slot) +{ + return 0; +} + + +/* + * latch closed: 1 + * latch open: 0 + */ +u8 acpiphp_get_latch_status (struct acpiphp_slot *slot) +{ + unsigned int sta; + + sta = get_slot_status(slot); + + return (sta & ACPI_STA_SHOW_IN_UI) ? 1 : 0; +} + + +/* + * adapter presence : 1 + * absence : 0 + */ +u8 acpiphp_get_adapter_status (struct acpiphp_slot *slot) +{ + unsigned int sta; + + sta = get_slot_status(slot); + + return (sta == 0) ? 0 : 1; +} diff -Nru a/drivers/pci/hotplug/acpiphp_pci.c b/drivers/pci/hotplug/acpiphp_pci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pci/hotplug/acpiphp_pci.c Mon Jun 9 23:16:05 2003 @@ -0,0 +1,511 @@ +/* + * ACPI PCI HotPlug PCI configuration space management + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001,2002 IBM Corp. + * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) + * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) + * Copyright (c) 2002 NEC Corporation + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Send feedback to <t-kouchi@cq.jp.nec.com> + * + */ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/acpi.h> +#include "../pci.h" +#include "pci_hotplug.h" +#include "acpiphp.h" + +#define MY_NAME "acpiphp_pci" + + +/* allocate mem/pmem/io resource to a new function */ +static int init_config_space (struct acpiphp_func *func) +{ + u32 bar, len; + u32 address[] = { + PCI_BASE_ADDRESS_0, + PCI_BASE_ADDRESS_1, + PCI_BASE_ADDRESS_2, + PCI_BASE_ADDRESS_3, + PCI_BASE_ADDRESS_4, + PCI_BASE_ADDRESS_5, + 0 + }; + int count; + struct acpiphp_bridge *bridge; + struct pci_resource *res; + struct pci_bus *pbus; + int bus, device, function; + unsigned int devfn; + u16 tmp; + + bridge = func->slot->bridge; + pbus = bridge->pci_bus; + bus = bridge->bus; + device = func->slot->device; + function = func->function; + devfn = PCI_DEVFN(device, function); + + for (count = 0; address[count]; count++) { /* for 6 BARs */ + pci_bus_write_config_dword(pbus, devfn, + address[count], 0xFFFFFFFF); + pci_bus_read_config_dword(pbus, devfn, address[count], &bar); + + if (!bar) /* This BAR is not implemented */ + continue; + + dbg("Device %02x.%02x BAR %d wants %x\n", device, function, count, bar); + + if (bar & PCI_BASE_ADDRESS_SPACE_IO) { + /* This is IO */ + + len = bar & 0xFFFFFFFC; + len = ~len + 1; + + dbg("len in IO %x, BAR %d\n", len, count); + + spin_lock(&bridge->res_lock); + res = acpiphp_get_io_resource(&bridge->io_head, len); + spin_unlock(&bridge->res_lock); + + if (!res) { + err("cannot allocate requested io for %02x:%02x.%d len %x\n", + bus, device, function, len); + return -1; + } + pci_bus_write_config_dword(pbus, devfn, + address[count], + (u32)res->base); + res->next = func->io_head; + func->io_head = res; + + } else { + /* This is Memory */ + if (bar & PCI_BASE_ADDRESS_MEM_PREFETCH) { + /* pfmem */ + + len = bar & 0xFFFFFFF0; + len = ~len + 1; + + dbg("len in PFMEM %x, BAR %d\n", len, count); + + spin_lock(&bridge->res_lock); + res = acpiphp_get_resource(&bridge->p_mem_head, len); + spin_unlock(&bridge->res_lock); + + if (!res) { + err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n", + bus, device, function, len); + return -1; + } + + pci_bus_write_config_dword(pbus, devfn, + address[count], + (u32)res->base); + + if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */ + dbg("inside the pfmem 64 case, count %d\n", count); + count += 1; + pci_bus_write_config_dword(pbus, devfn, + address[count], + (u32)(res->base >> 32)); + } + + res->next = func->p_mem_head; + func->p_mem_head = res; + + } else { + /* regular memory */ + + len = bar & 0xFFFFFFF0; + len = ~len + 1; + + dbg("len in MEM %x, BAR %d\n", len, count); + + spin_lock(&bridge->res_lock); + res = acpiphp_get_resource(&bridge->mem_head, len); + spin_unlock(&bridge->res_lock); + + if (!res) { + err("cannot allocate requested pfmem for %02x:%02x.%d len %x\n", + bus, device, function, len); + return -1; + } + + pci_bus_write_config_dword(pbus, devfn, + address[count], + (u32)res->base); + + if (bar & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + dbg("inside mem 64 case, reg. mem, count %d\n", count); + count += 1; + pci_bus_write_config_dword(pbus, devfn, + address[count], + (u32)(res->base >> 32)); + } + + res->next = func->mem_head; + func->mem_head = res; + + } + } + } + + /* disable expansion rom */ + pci_bus_write_config_dword(pbus, devfn, PCI_ROM_ADDRESS, 0x00000000); + + /* set PCI parameters from _HPP */ + pci_bus_write_config_byte(pbus, devfn, PCI_CACHE_LINE_SIZE, + bridge->hpp.cache_line_size); + pci_bus_write_config_byte(pbus, devfn, PCI_LATENCY_TIMER, + bridge->hpp.latency_timer); + + pci_bus_read_config_word(pbus, devfn, PCI_COMMAND, &tmp); + if (bridge->hpp.enable_SERR) + tmp |= PCI_COMMAND_SERR; + if (bridge->hpp.enable_PERR) + tmp |= PCI_COMMAND_PARITY; + pci_bus_write_config_word(pbus, devfn, PCI_COMMAND, tmp); + + return 0; +} + +/* detect_used_resource - subtract resource under dev from bridge */ +static int detect_used_resource (struct acpiphp_bridge *bridge, struct pci_dev *dev) +{ + u32 bar, len; + u64 base; + u32 address[] = { + PCI_BASE_ADDRESS_0, + PCI_BASE_ADDRESS_1, + PCI_BASE_ADDRESS_2, + PCI_BASE_ADDRESS_3, + PCI_BASE_ADDRESS_4, + PCI_BASE_ADDRESS_5, + 0 + }; + int count; + struct pci_resource *res; + + dbg("Device %s\n", dev->slot_name); + + for (count = 0; address[count]; count++) { /* for 6 BARs */ + pci_read_config_dword(dev, address[count], &bar); + + if (!bar) /* This BAR is not implemented */ + continue; + + pci_write_config_dword(dev, address[count], 0xFFFFFFFF); + pci_read_config_dword(dev, address[count], &len); + + if (len & PCI_BASE_ADDRESS_SPACE_IO) { + /* This is IO */ + base = bar & 0xFFFFFFFC; + len &= 0xFFFFFFFC; + len = ~len + 1; + + dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1); + + spin_lock(&bridge->res_lock); + res = acpiphp_get_resource_with_base(&bridge->io_head, base, len); + spin_unlock(&bridge->res_lock); + if (res) + kfree(res); + } else { + /* This is Memory */ + base = bar & 0xFFFFFFF0; + if (len & PCI_BASE_ADDRESS_MEM_PREFETCH) { + /* pfmem */ + + len &= 0xFFFFFFF0; + len = ~len + 1; + + if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */ + dbg("prefetch mem 64\n"); + count += 1; + } + dbg("BAR[%d] %08x - %08x (PMEM)\n", count, (u32)base, (u32)base + len - 1); + spin_lock(&bridge->res_lock); + res = acpiphp_get_resource_with_base(&bridge->p_mem_head, base, len); + spin_unlock(&bridge->res_lock); + if (res) + kfree(res); + } else { + /* regular memory */ + + len &= 0xFFFFFFF0; + len = ~len + 1; + + if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + dbg("mem 64\n"); + count += 1; + } + dbg("BAR[%d] %08x - %08x (MEM)\n", count, (u32)base, (u32)base + len - 1); + spin_lock(&bridge->res_lock); + res = acpiphp_get_resource_with_base(&bridge->mem_head, base, len); + spin_unlock(&bridge->res_lock); + if (res) + kfree(res); + } + } + + pci_write_config_dword(dev, address[count], bar); + } + + return 0; +} + + +/* detect_pci_resource_bus - subtract resource under pci_bus */ +static void detect_used_resource_bus(struct acpiphp_bridge *bridge, struct pci_bus *bus) +{ + struct list_head *l; + struct pci_dev *dev; + + list_for_each (l, &bus->devices) { + dev = pci_dev_b(l); + detect_used_resource(bridge, dev); + /* XXX recursive call */ + if (dev->subordinate) + detect_used_resource_bus(bridge, dev->subordinate); + } +} + + +/** + * acpiphp_detect_pci_resource - detect resources under bridge + * @bridge: detect all resources already used under this bridge + * + * collect all resources already allocated for all devices under a bridge. + */ +int acpiphp_detect_pci_resource (struct acpiphp_bridge *bridge) +{ + detect_used_resource_bus(bridge, bridge->pci_bus); + + return 0; +} + + +/** + * acpiphp_init_slot_resource - gather resource usage information of a slot + * @slot: ACPI slot object to be checked, should have valid pci_dev member + * + * TBD: PCI-to-PCI bridge case + * use pci_dev->resource[] + */ +int acpiphp_init_func_resource (struct acpiphp_func *func) +{ + u64 base; + u32 bar, len; + u32 address[] = { + PCI_BASE_ADDRESS_0, + PCI_BASE_ADDRESS_1, + PCI_BASE_ADDRESS_2, + PCI_BASE_ADDRESS_3, + PCI_BASE_ADDRESS_4, + PCI_BASE_ADDRESS_5, + 0 + }; + int count; + struct pci_resource *res; + struct pci_dev *dev; + + dev = func->pci_dev; + dbg("Hot-pluggable device %s\n", dev->slot_name); + + for (count = 0; address[count]; count++) { /* for 6 BARs */ + pci_read_config_dword(dev, address[count], &bar); + + if (!bar) /* This BAR is not implemented */ + continue; + + pci_write_config_dword(dev, address[count], 0xFFFFFFFF); + pci_read_config_dword(dev, address[count], &len); + + if (len & PCI_BASE_ADDRESS_SPACE_IO) { + /* This is IO */ + base = bar & 0xFFFFFFFC; + len &= 0xFFFFFFFC; + len = ~len + 1; + + dbg("BAR[%d] %08x - %08x (IO)\n", count, (u32)base, (u32)base + len - 1); + + res = acpiphp_make_resource(base, len); + if (!res) + goto no_memory; + + res->next = func->io_head; + func->io_head = res; + + } else { + /* This is Memory */ + base = bar & 0xFFFFFFF0; + if (len & PCI_BASE_ADDRESS_MEM_PREFETCH) { + /* pfmem */ + + len &= 0xFFFFFFF0; + len = ~len + 1; + + if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */ + dbg("prefetch mem 64\n"); + count += 1; + } + dbg("BAR[%d] %08x - %08x (PMEM)\n", count, (u32)base, (u32)base + len - 1); + res = acpiphp_make_resource(base, len); + if (!res) + goto no_memory; + + res->next = func->p_mem_head; + func->p_mem_head = res; + + } else { + /* regular memory */ + + len &= 0xFFFFFFF0; + len = ~len + 1; + + if (len & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + dbg("mem 64\n"); + count += 1; + } + dbg("BAR[%d] %08x - %08x (MEM)\n", count, (u32)base, (u32)base + len - 1); + res = acpiphp_make_resource(base, len); + if (!res) + goto no_memory; + + res->next = func->mem_head; + func->mem_head = res; + + } + } + + pci_write_config_dword(dev, address[count], bar); + } +#if 1 + acpiphp_dump_func_resource(func); +#endif + + return 0; + + no_memory: + err("out of memory\n"); + acpiphp_free_resource(&func->io_head); + acpiphp_free_resource(&func->mem_head); + acpiphp_free_resource(&func->p_mem_head); + + return -1; +} + + +/** + * acpiphp_configure_slot - allocate PCI resources + * @slot: slot to be configured + * + * initializes a PCI functions on a device inserted + * into the slot + * + */ +int acpiphp_configure_slot (struct acpiphp_slot *slot) +{ + struct acpiphp_func *func; + struct list_head *l; + u8 hdr; + u32 dvid; + int retval = 0; + int is_multi = 0; + + pci_bus_read_config_byte(slot->bridge->pci_bus, + PCI_DEVFN(slot->device, 0), + PCI_HEADER_TYPE, &hdr); + + if (hdr & 0x80) + is_multi = 1; + + list_for_each (l, &slot->funcs) { + func = list_entry(l, struct acpiphp_func, sibling); + if (is_multi || func->function == 0) { + pci_bus_read_config_dword(slot->bridge->pci_bus, + PCI_DEVFN(slot->device, + func->function), + PCI_VENDOR_ID, &dvid); + if (dvid != 0xffffffff) { + retval = init_config_space(func); + if (retval) + break; + } + } + } + + return retval; +} + +/** + * acpiphp_configure_function - configure PCI function + * @func: function to be configured + * + * initializes a PCI functions on a device inserted + * into the slot + * + */ +int acpiphp_configure_function (struct acpiphp_func *func) +{ + /* all handled by the pci core now */ + return 0; +} + +/** + * acpiphp_unconfigure_function - unconfigure PCI function + * @func: function to be unconfigured + * + */ +int acpiphp_unconfigure_function (struct acpiphp_func *func) +{ + struct acpiphp_bridge *bridge; + int retval = 0; + + /* if pci_dev is NULL, ignore it */ + if (!func->pci_dev) + goto err_exit; + + pci_remove_bus_device(func->pci_dev); + + /* free all resources */ + bridge = func->slot->bridge; + + spin_lock(&bridge->res_lock); + acpiphp_move_resource(&func->io_head, &bridge->io_head); + acpiphp_move_resource(&func->mem_head, &bridge->mem_head); + acpiphp_move_resource(&func->p_mem_head, &bridge->p_mem_head); + acpiphp_move_resource(&func->bus_head, &bridge->bus_head); + spin_unlock(&bridge->res_lock); + + err_exit: + return retval; +} diff -Nru a/drivers/pci/hotplug/acpiphp_res.c b/drivers/pci/hotplug/acpiphp_res.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pci/hotplug/acpiphp_res.c Mon Jun 9 23:16:10 2003 @@ -0,0 +1,699 @@ +/* + * ACPI PCI HotPlug Utility functions + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * Copyright (c) 2002 Hiroshi Aono (h-aono@ap.jp.nec.com) + * Copyright (c) 2002 Takayoshi Kochi (t-kouchi@cq.jp.nec.com) + * Copyright (c) 2002 NEC Corporation + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Send feedback to <gregkh@us.ibm.com>,<h-aono@ap.jp.nec.com> + * + */ + +#include <linux/config.h> +#include <linux/module.h> + +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/proc_fs.h> +#include <linux/sysctl.h> +#include <linux/pci.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> +#include <linux/init.h> + +#include <linux/string.h> +#include <linux/mm.h> +#include <linux/errno.h> +#include <linux/ioport.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/timer.h> + +#include <linux/ioctl.h> +#include <linux/fcntl.h> + +#include <linux/list.h> + +#include "pci_hotplug.h" +#include "acpiphp.h" + +#define MY_NAME "acpiphp_res" + + +/* + * sort_by_size - sort nodes by their length, smallest first + */ +static int sort_by_size(struct pci_resource **head) +{ + struct pci_resource *current_res; + struct pci_resource *next_res; + int out_of_order = 1; + + if (!(*head)) + return 1; + + if (!((*head)->next)) + return 0; + + while (out_of_order) { + out_of_order = 0; + + /* Special case for swapping list head */ + if (((*head)->next) && + ((*head)->length > (*head)->next->length)) { + out_of_order++; + current_res = *head; + *head = (*head)->next; + current_res->next = (*head)->next; + (*head)->next = current_res; + } + + current_res = *head; + + while (current_res->next && current_res->next->next) { + if (current_res->next->length > current_res->next->next->length) { + out_of_order++; + next_res = current_res->next; + current_res->next = current_res->next->next; + current_res = current_res->next; + next_res->next = current_res->next; + current_res->next = next_res; + } else + current_res = current_res->next; + } + } /* End of out_of_order loop */ + + return 0; +} + + +/* + * sort_by_max_size - sort nodes by their length, largest first + */ +static int sort_by_max_size(struct pci_resource **head) +{ + struct pci_resource *current_res; + struct pci_resource *next_res; + int out_of_order = 1; + + if (!(*head)) + return 1; + + if (!((*head)->next)) + return 0; + + while (out_of_order) { + out_of_order = 0; + + /* Special case for swapping list head */ + if (((*head)->next) && + ((*head)->length < (*head)->next->length)) { + out_of_order++; + current_res = *head; + *head = (*head)->next; + current_res->next = (*head)->next; + (*head)->next = current_res; + } + + current_res = *head; + + while (current_res->next && current_res->next->next) { + if (current_res->next->length < current_res->next->next->length) { + out_of_order++; + next_res = current_res->next; + current_res->next = current_res->next->next; + current_res = current_res->next; + next_res->next = current_res->next; + current_res->next = next_res; + } else + current_res = current_res->next; + } + } /* End of out_of_order loop */ + + return 0; +} + +/** + * get_io_resource - get resource for I/O ports + * + * this function sorts the resource list by size and then + * returns the first node of "size" length that is not in the + * ISA aliasing window. If it finds a node larger than "size" + * it will split it up. + * + * size must be a power of two. + * + * difference from get_resource is handling of ISA aliasing space. + * + */ +struct pci_resource *acpiphp_get_io_resource (struct pci_resource **head, u32 size) +{ + struct pci_resource *prevnode; + struct pci_resource *node; + struct pci_resource *split_node; + u64 temp_qword; + + if (!(*head)) + return NULL; + + if (acpiphp_resource_sort_and_combine(head)) + return NULL; + + if (sort_by_size(head)) + return NULL; + + for (node = *head; node; node = node->next) { + if (node->length < size) + continue; + + if (node->base & (size - 1)) { + /* this one isn't base aligned properly + so we'll make a new entry and split it up */ + temp_qword = (node->base | (size-1)) + 1; + + /* Short circuit if adjusted size is too small */ + if ((node->length - (temp_qword - node->base)) < size) + continue; + + split_node = acpiphp_make_resource(node->base, temp_qword - node->base); + + if (!split_node) + return NULL; + + node->base = temp_qword; + node->length -= split_node->length; + + /* Put it in the list */ + split_node->next = node->next; + node->next = split_node; + } /* End of non-aligned base */ + + /* Don't need to check if too small since we already did */ + if (node->length > size) { + /* this one is longer than we need + so we'll make a new entry and split it up */ + split_node = acpiphp_make_resource(node->base + size, node->length - size); + + if (!split_node) + return NULL; + + node->length = size; + + /* Put it in the list */ + split_node->next = node->next; + node->next = split_node; + } /* End of too big on top end */ + + /* For IO make sure it's not in the ISA aliasing space */ + if (node->base & 0x300L) + continue; + + /* If we got here, then it is the right size + Now take it out of the list */ + if (*head == node) { + *head = node->next; + } else { + prevnode = *head; + while (prevnode->next != node) + prevnode = prevnode->next; + + prevnode->next = node->next; + } + node->next = NULL; + /* Stop looping */ + break; + } + + return node; +} + + +/** + * get_max_resource - get the largest resource + * + * Gets the largest node that is at least "size" big from the + * list pointed to by head. It aligns the node on top and bottom + * to "size" alignment before returning it. + */ +struct pci_resource *acpiphp_get_max_resource (struct pci_resource **head, u32 size) +{ + struct pci_resource *max; + struct pci_resource *temp; + struct pci_resource *split_node; + u64 temp_qword; + + if (!(*head)) + return NULL; + + if (acpiphp_resource_sort_and_combine(head)) + return NULL; + + if (sort_by_max_size(head)) + return NULL; + + for (max = *head;max; max = max->next) { + + /* If not big enough we could probably just bail, + instead we'll continue to the next. */ + if (max->length < size) + continue; + + if (max->base & (size - 1)) { + /* this one isn't base aligned properly + so we'll make a new entry and split it up */ + temp_qword = (max->base | (size-1)) + 1; + + /* Short circuit if adjusted size is too small */ + if ((max->length - (temp_qword - max->base)) < size) + continue; + + split_node = acpiphp_make_resource(max->base, temp_qword - max->base); + + if (!split_node) + return NULL; + + max->base = temp_qword; + max->length -= split_node->length; + + /* Put it next in the list */ + split_node->next = max->next; + max->next = split_node; + } + + if ((max->base + max->length) & (size - 1)) { + /* this one isn't end aligned properly at the top + so we'll make a new entry and split it up */ + temp_qword = ((max->base + max->length) & ~(size - 1)); + + split_node = acpiphp_make_resource(temp_qword, + max->length + max->base - temp_qword); + + if (!split_node) + return NULL; + + max->length -= split_node->length; + + /* Put it in the list */ + split_node->next = max->next; + max->next = split_node; + } + + /* Make sure it didn't shrink too much when we aligned it */ + if (max->length < size) + continue; + + /* Now take it out of the list */ + temp = (struct pci_resource*) *head; + if (temp == max) { + *head = max->next; + } else { + while (temp && temp->next != max) { + temp = temp->next; + } + + temp->next = max->next; + } + + max->next = NULL; + return max; + } + + /* If we get here, we couldn't find one */ + return NULL; +} + + +/** + * get_resource - get resource (mem, pfmem) + * + * this function sorts the resource list by size and then + * returns the first node of "size" length. If it finds a node + * larger than "size" it will split it up. + * + * size must be a power of two. + * + */ +struct pci_resource *acpiphp_get_resource (struct pci_resource **head, u32 size) +{ + struct pci_resource *prevnode; + struct pci_resource *node; + struct pci_resource *split_node; + u64 temp_qword; + + if (!(*head)) + return NULL; + + if (acpiphp_resource_sort_and_combine(head)) + return NULL; + + if (sort_by_size(head)) + return NULL; + + for (node = *head; node; node = node->next) { + dbg("%s: req_size =%x node=%p, base=%x, length=%x\n", + __FUNCTION__, size, node, (u32)node->base, node->length); + if (node->length < size) + continue; + + if (node->base & (size - 1)) { + dbg("%s: not aligned\n", __FUNCTION__); + /* this one isn't base aligned properly + so we'll make a new entry and split it up */ + temp_qword = (node->base | (size-1)) + 1; + + /* Short circuit if adjusted size is too small */ + if ((node->length - (temp_qword - node->base)) < size) + continue; + + split_node = acpiphp_make_resource(node->base, temp_qword - node->base); + + if (!split_node) + return NULL; + + node->base = temp_qword; + node->length -= split_node->length; + + /* Put it in the list */ + split_node->next = node->next; + node->next = split_node; + } /* End of non-aligned base */ + + /* Don't need to check if too small since we already did */ + if (node->length > size) { + dbg("%s: too big\n", __FUNCTION__); + /* this one is longer than we need + so we'll make a new entry and split it up */ + split_node = acpiphp_make_resource(node->base + size, node->length - size); + + if (!split_node) + return NULL; + + node->length = size; + + /* Put it in the list */ + split_node->next = node->next; + node->next = split_node; + } /* End of too big on top end */ + + dbg("%s: got one!!!\n", __FUNCTION__); + /* If we got here, then it is the right size + Now take it out of the list */ + if (*head == node) { + *head = node->next; + } else { + prevnode = *head; + while (prevnode->next != node) + prevnode = prevnode->next; + + prevnode->next = node->next; + } + node->next = NULL; + /* Stop looping */ + break; + } + return node; +} + +/** + * get_resource_with_base - get resource with specific base address + * + * this function + * returns the first node of "size" length located at specified base address. + * If it finds a node larger than "size" it will split it up. + * + * size must be a power of two. + * + */ +struct pci_resource *acpiphp_get_resource_with_base (struct pci_resource **head, u64 base, u32 size) +{ + struct pci_resource *prevnode; + struct pci_resource *node; + struct pci_resource *split_node; + u64 temp_qword; + + if (!(*head)) + return NULL; + + if (acpiphp_resource_sort_and_combine(head)) + return NULL; + + for (node = *head; node; node = node->next) { + dbg(": 1st req_base=%x req_size =%x node=%p, base=%x, length=%x\n", + (u32)base, size, node, (u32)node->base, node->length); + if (node->base > base) + continue; + + if ((node->base + node->length) < (base + size)) + continue; + + if (node->base < base) { + dbg(": split 1\n"); + /* this one isn't base aligned properly + so we'll make a new entry and split it up */ + temp_qword = base; + + /* Short circuit if adjusted size is too small */ + if ((node->length - (temp_qword - node->base)) < size) + continue; + + split_node = acpiphp_make_resource(node->base, temp_qword - node->base); + + if (!split_node) + return NULL; + + node->base = temp_qword; + node->length -= split_node->length; + + /* Put it in the list */ + split_node->next = node->next; + node->next = split_node; + } + + dbg(": 2nd req_base=%x req_size =%x node=%p, base=%x, length=%x\n", + (u32)base, size, node, (u32)node->base, node->length); + + /* Don't need to check if too small since we already did */ + if (node->length > size) { + dbg(": split 2\n"); + /* this one is longer than we need + so we'll make a new entry and split it up */ + split_node = acpiphp_make_resource(node->base + size, node->length - size); + + if (!split_node) + return NULL; + + node->length = size; + + /* Put it in the list */ + split_node->next = node->next; + node->next = split_node; + } /* End of too big on top end */ + + dbg(": got one!!!\n"); + /* If we got here, then it is the right size + Now take it out of the list */ + if (*head == node) { + *head = node->next; + } else { + prevnode = *head; + while (prevnode->next != node) + prevnode = prevnode->next; + + prevnode->next = node->next; + } + node->next = NULL; + /* Stop looping */ + break; + } + return node; +} + + +/** + * acpiphp_resource_sort_and_combine + * + * Sorts all of the nodes in the list in ascending order by + * their base addresses. Also does garbage collection by + * combining adjacent nodes. + * + * returns 0 if success + */ +int acpiphp_resource_sort_and_combine (struct pci_resource **head) +{ + struct pci_resource *node1; + struct pci_resource *node2; + int out_of_order = 1; + + if (!(*head)) + return 1; + + dbg("*head->next = %p\n",(*head)->next); + + if (!(*head)->next) + return 0; /* only one item on the list, already sorted! */ + + dbg("*head->base = 0x%x\n",(u32)(*head)->base); + dbg("*head->next->base = 0x%x\n", (u32)(*head)->next->base); + while (out_of_order) { + out_of_order = 0; + + /* Special case for swapping list head */ + if (((*head)->next) && + ((*head)->base > (*head)->next->base)) { + node1 = *head; + (*head) = (*head)->next; + node1->next = (*head)->next; + (*head)->next = node1; + out_of_order++; + } + + node1 = (*head); + + while (node1->next && node1->next->next) { + if (node1->next->base > node1->next->next->base) { + out_of_order++; + node2 = node1->next; + node1->next = node1->next->next; + node1 = node1->next; + node2->next = node1->next; + node1->next = node2; + } else + node1 = node1->next; + } + } /* End of out_of_order loop */ + + node1 = *head; + + while (node1 && node1->next) { + if ((node1->base + node1->length) == node1->next->base) { + /* Combine */ + dbg("8..\n"); + node1->length += node1->next->length; + node2 = node1->next; + node1->next = node1->next->next; + kfree(node2); + } else + node1 = node1->next; + } + + return 0; +} + + +/** + * acpiphp_make_resource - make resource structure + * @base: base address of a resource + * @length: length of a resource + */ +struct pci_resource *acpiphp_make_resource (u64 base, u32 length) +{ + struct pci_resource *res; + + res = kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (res) { + memset(res, 0, sizeof(struct pci_resource)); + res->base = base; + res->length = length; + } + + return res; +} + + +/** + * acpiphp_move_resource - move linked resources from one to another + * @from: head of linked resource list + * @to: head of linked resource list + */ +void acpiphp_move_resource (struct pci_resource **from, struct pci_resource **to) +{ + struct pci_resource *tmp; + + while (*from) { + tmp = (*from)->next; + (*from)->next = *to; + *to = *from; + *from = tmp; + } + + /* *from = NULL is guaranteed */ +} + + +/** + * acpiphp_free_resource - free all linked resources + * @res: head of linked resource list + */ +void acpiphp_free_resource (struct pci_resource **res) +{ + struct pci_resource *tmp; + + while (*res) { + tmp = (*res)->next; + kfree(*res); + *res = tmp; + } + + /* *res = NULL is guaranteed */ +} + + +/* debug support functions; will go away sometime :) */ +static void dump_resource(struct pci_resource *head) +{ + struct pci_resource *p; + int cnt; + + p = head; + cnt = 0; + + while (p) { + dbg("[%02d] %08x - %08x\n", + cnt++, (u32)p->base, (u32)p->base + p->length - 1); + p = p->next; + } +} + +void acpiphp_dump_resource(struct acpiphp_bridge *bridge) +{ + dbg("I/O resource:\n"); + dump_resource(bridge->io_head); + dbg("MEM resource:\n"); + dump_resource(bridge->mem_head); + dbg("PMEM resource:\n"); + dump_resource(bridge->p_mem_head); + dbg("BUS resource:\n"); + dump_resource(bridge->bus_head); +} + +void acpiphp_dump_func_resource(struct acpiphp_func *func) +{ + dbg("I/O resource:\n"); + dump_resource(func->io_head); + dbg("MEM resource:\n"); + dump_resource(func->mem_head); + dbg("PMEM resource:\n"); + dump_resource(func->p_mem_head); + dbg("BUS resource:\n"); + dump_resource(func->bus_head); +} diff -Nru a/drivers/pci/hotplug/cpci_hotplug.h b/drivers/pci/hotplug/cpci_hotplug.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pci/hotplug/cpci_hotplug.h Mon Jun 9 23:16:08 2003 @@ -0,0 +1,100 @@ +/* + * CompactPCI Hot Plug Core Functions + * + * Copyright (c) 2002 SOMA Networks, Inc. + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Send feedback to <scottm@somanetworks.com> + */ + +#ifndef _CPCI_HOTPLUG_H +#define _CPCI_HOTPLUG_H + +#include <linux/types.h> +#include <linux/pci.h> + +/* PICMG 2.12 R2.0 HS CSR bits: */ +#define HS_CSR_INS 0x0080 +#define HS_CSR_EXT 0x0040 +#define HS_CSR_PI 0x0030 +#define HS_CSR_LOO 0x0008 +#define HS_CSR_PIE 0x0004 +#define HS_CSR_EIM 0x0002 +#define HS_CSR_DHA 0x0001 + +#define SLOT_MAGIC 0x67267322 +struct slot { + u32 magic; + u8 number; + unsigned int devfn; + struct pci_bus *bus; + struct pci_dev *dev; + unsigned int extracting; + struct hotplug_slot *hotplug_slot; + struct list_head slot_list; +}; + +struct cpci_hp_controller_ops { + int (*query_enum) (void); + int (*enable_irq) (void); + int (*disable_irq) (void); + int (*check_irq) (void *dev_id); + int (*hardware_test) (struct slot* slot, u32 value); + u8 (*get_power) (struct slot* slot); + int (*set_power) (struct slot* slot, int value); +}; + +struct cpci_hp_controller { + unsigned int irq; + unsigned long irq_flags; + char *devname; + void *dev_id; + char *name; + struct cpci_hp_controller_ops *ops; +}; + +extern int cpci_hp_register_controller(struct cpci_hp_controller *controller); +extern int cpci_hp_unregister_controller(struct cpci_hp_controller *controller); +extern int cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last); +extern int cpci_hp_unregister_bus(struct pci_bus *bus); +extern struct slot *cpci_find_slot(struct pci_bus *bus, unsigned int devfn); +extern int cpci_hp_start(void); +extern int cpci_hp_stop(void); + +/* + * Internal function prototypes, these functions should not be used by + * board/chassis drivers. + */ +extern u8 cpci_get_attention_status(struct slot *slot); +extern u8 cpci_get_latch_status(struct slot *slot); +extern u8 cpci_get_adapter_status(struct slot *slot); +extern u16 cpci_get_hs_csr(struct slot * slot); +extern u16 cpci_set_hs_csr(struct slot * slot, u16 hs_csr); +extern int cpci_set_attention_status(struct slot *slot, int status); +extern int cpci_check_and_clear_ins(struct slot * slot); +extern int cpci_check_ext(struct slot * slot); +extern int cpci_clear_ext(struct slot * slot); +extern int cpci_led_on(struct slot * slot); +extern int cpci_led_off(struct slot * slot); +extern int cpci_configure_slot(struct slot *slot); +extern int cpci_unconfigure_slot(struct slot *slot); + +#endif /* _CPCI_HOTPLUG_H */ diff -Nru a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pci/hotplug/cpci_hotplug_core.c Mon Jun 9 23:16:10 2003 @@ -0,0 +1,919 @@ +/* + * CompactPCI Hot Plug Driver + * + * Copyright (c) 2002 SOMA Networks, Inc. + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Send feedback to <scottm@somanetworks.com> + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/smp_lock.h> +#include "pci_hotplug.h" +#include "cpci_hotplug.h" + +#define DRIVER_VERSION "0.2" +#define DRIVER_AUTHOR "Scott Murray <scottm@somanetworks.com>" +#define DRIVER_DESC "CompactPCI Hot Plug Core" + +#if !defined(CONFIG_HOTPLUG_CPCI_MODULE) +#define MY_NAME "cpci_hotplug" +#else +#define MY_NAME THIS_MODULE->name +#endif + +#define dbg(format, arg...) \ + do { \ + if(cpci_debug) \ + printk (KERN_DEBUG "%s: " format "\n", \ + MY_NAME , ## arg); \ + } while(0) +#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) + +/* local variables */ +static spinlock_t list_lock; +static LIST_HEAD(slot_list); +static int slots; +int cpci_debug; +static struct cpci_hp_controller *controller; +static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ +static struct semaphore thread_exit; /* guard ensure thread has exited before calling it quits */ +static int thread_finished = 1; + +static int enable_slot(struct hotplug_slot *slot); +static int disable_slot(struct hotplug_slot *slot); +static int set_attention_status(struct hotplug_slot *slot, u8 value); +static int get_power_status(struct hotplug_slot *slot, u8 * value); +static int get_attention_status(struct hotplug_slot *slot, u8 * value); +static int get_latch_status(struct hotplug_slot *slot, u8 * value); +static int get_adapter_status(struct hotplug_slot *slot, u8 * value); + +static struct hotplug_slot_ops cpci_hotplug_slot_ops = { + .owner = THIS_MODULE, + .enable_slot = enable_slot, + .disable_slot = disable_slot, + .set_attention_status = set_attention_status, + .hardware_test = NULL, + .get_power_status = get_power_status, + .get_attention_status = get_attention_status, + .get_latch_status = get_latch_status, + .get_adapter_status = get_adapter_status, +}; + +/* Inline functions to check the sanity of a pointer that is passed to us */ +static inline int +slot_paranoia_check(struct slot *slot, const char *function) +{ + if(!slot) { + dbg("%s - slot == NULL", function); + return -1; + } + if(slot->magic != SLOT_MAGIC) { + dbg("%s - bad magic number for slot", function); + return -1; + } + if(!slot->hotplug_slot) { + dbg("%s - slot->hotplug_slot == NULL!", function); + return -1; + } + return 0; +} + +static inline struct slot * +get_slot(struct hotplug_slot *hotplug_slot, const char *function) +{ + struct slot *slot; + + if(!hotplug_slot) { + dbg("%s - hotplug_slot == NULL", function); + return NULL; + } + + slot = (struct slot *) hotplug_slot->private; + if(slot_paranoia_check(slot, function)) + return NULL; + return slot; +} + +static int +update_latch_status(struct hotplug_slot *hotplug_slot, u8 value) +{ + struct hotplug_slot_info info; + + if(!(hotplug_slot && hotplug_slot->info)) + return -EINVAL; + memcpy(&info, hotplug_slot->info, sizeof(struct hotplug_slot_info)); + info.latch_status = value; + return pci_hp_change_slot_info(hotplug_slot, &info); +} + +static int +update_adapter_status(struct hotplug_slot *hotplug_slot, u8 value) +{ + struct hotplug_slot_info info; + + if(!(hotplug_slot && hotplug_slot->info)) + return -EINVAL; + memcpy(&info, hotplug_slot->info, sizeof(struct hotplug_slot_info)); + info.adapter_status = value; + return pci_hp_change_slot_info(hotplug_slot, &info); +} + +static int +enable_slot(struct hotplug_slot *hotplug_slot) +{ + struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + int retval = 0; + + if(slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name); + + if(controller->ops->set_power) { + retval = controller->ops->set_power(slot, 1); + } + + return retval; +} + +static int +disable_slot(struct hotplug_slot *hotplug_slot) +{ + struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + int retval = 0; + + if(slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s", __FUNCTION__, hotplug_slot->name); + + /* Unconfigure device */ + dbg("%s - unconfiguring slot %s", + __FUNCTION__, slot->hotplug_slot->name); + if((retval = cpci_unconfigure_slot(slot))) { + err("%s - could not unconfigure slot %s", + __FUNCTION__, slot->hotplug_slot->name); + return retval; + } + dbg("%s - finished unconfiguring slot %s", + __FUNCTION__, slot->hotplug_slot->name); + + /* Clear EXT (by setting it) */ + if(cpci_clear_ext(slot)) { + err("%s - could not clear EXT for slot %s", + __FUNCTION__, slot->hotplug_slot->name); + retval = -ENODEV; + } + cpci_led_on(slot); + + if(controller->ops->set_power) { + retval = controller->ops->set_power(slot, 0); + } + + if(update_adapter_status(slot->hotplug_slot, 0)) { + warn("failure to update adapter file"); + } + + slot->extracting = 0; + + return retval; +} + +static u8 +cpci_get_power_status(struct slot *slot) +{ + u8 power = 1; + + if(controller->ops->get_power) { + power = controller->ops->get_power(slot); + } + return power; +} + +static int +get_power_status(struct hotplug_slot *hotplug_slot, u8 * value) +{ + struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + + if(slot == NULL) + return -ENODEV; + *value = cpci_get_power_status(slot); + return 0; +} + +static int +get_attention_status(struct hotplug_slot *hotplug_slot, u8 * value) +{ + struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + + if(slot == NULL) + return -ENODEV; + *value = cpci_get_attention_status(slot); + return 0; +} + +static int +set_attention_status(struct hotplug_slot *hotplug_slot, u8 status) +{ + struct slot *slot = get_slot(hotplug_slot, __FUNCTION__); + + if(slot == NULL) + return -ENODEV; + switch (status) { + case 0: + cpci_set_attention_status(slot, 0); + break; + + case 1: + default: + cpci_set_attention_status(slot, 1); + break; + } + + return 0; +} + +static int +get_latch_status(struct hotplug_slot *hotplug_slot, u8 * value) +{ + if(hotplug_slot == NULL || hotplug_slot->info == NULL) + return -ENODEV; + *value = hotplug_slot->info->latch_status; + return 0; +} + +static int +get_adapter_status(struct hotplug_slot *hotplug_slot, u8 * value) +{ + if(hotplug_slot == NULL || hotplug_slot->info == NULL) + return -ENODEV; + *value = hotplug_slot->info->adapter_status; + return 0; +} + +#define SLOT_NAME_SIZE 6 +static void +make_slot_name(struct slot *slot) +{ + snprintf(slot->hotplug_slot->name, + SLOT_NAME_SIZE, "%02x:%02x", slot->bus->number, slot->number); +} + +int +cpci_hp_register_bus(struct pci_bus *bus, u8 first, u8 last) +{ + struct slot *slot; + struct hotplug_slot *hotplug_slot; + struct hotplug_slot_info *info; + char *name; + int status = 0; + int i; + + if(!(controller && bus)) { + return -ENODEV; + } + if(last < first) { + return -EINVAL; + } + + /* + * Create a structure for each slot, and register that slot + * with the pci_hotplug subsystem. + */ + for (i = first; i <= last; ++i) { + slot = kmalloc(sizeof (struct slot), GFP_KERNEL); + if(!slot) + return -ENOMEM; + memset(slot, 0, sizeof (struct slot)); + + hotplug_slot = + kmalloc(sizeof (struct hotplug_slot), GFP_KERNEL); + if(!hotplug_slot) { + kfree(slot); + return -ENOMEM; + } + memset(hotplug_slot, 0, sizeof (struct hotplug_slot)); + slot->hotplug_slot = hotplug_slot; + + info = kmalloc(sizeof (struct hotplug_slot_info), GFP_KERNEL); + if(!info) { + kfree(hotplug_slot); + kfree(slot); + return -ENOMEM; + } + memset(info, 0, sizeof (struct hotplug_slot_info)); + hotplug_slot->info = info; + + name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL); + if(!name) { + kfree(info); + kfree(hotplug_slot); + kfree(slot); + return -ENOMEM; + } + hotplug_slot->name = name; + + slot->magic = SLOT_MAGIC; + slot->bus = bus; + slot->number = i; + slot->devfn = PCI_DEVFN(i, 0); + + hotplug_slot->private = slot; + make_slot_name(slot); + hotplug_slot->ops = &cpci_hotplug_slot_ops; + + /* + * Initialize the slot info structure with some known + * good values. + */ + dbg("initializing slot %s", slot->hotplug_slot->name); + info->power_status = cpci_get_power_status(slot); + info->attention_status = cpci_get_attention_status(slot); + + dbg("registering slot %s", slot->hotplug_slot->name); + status = pci_hp_register(slot->hotplug_slot); + if(status) { + err("pci_hp_register failed with error %d", status); + kfree(info); + kfree(name); + kfree(hotplug_slot); + kfree(slot); + return status; + } + + /* Add slot to our internal list */ + spin_lock(&list_lock); + list_add(&slot->slot_list, &slot_list); + slots++; + spin_unlock(&list_lock); + } + return status; +} + +int +cpci_hp_unregister_bus(struct pci_bus *bus) +{ + struct slot *slot; + struct list_head *tmp; + int status; + + if(!bus) { + return -ENODEV; + } + + spin_lock(&list_lock); + if(!slots) { + spin_unlock(&list_lock); + return -1; + } + list_for_each(tmp, &slot_list) { + slot = list_entry(tmp, struct slot, slot_list); + if(slot->bus == bus) { + dbg("deregistering slot %s", slot->hotplug_slot->name); + status = pci_hp_deregister(slot->hotplug_slot); + if(status) { + err("pci_hp_deregister failed with error %d", + status); + return status; + } + + list_del(&slot->slot_list); + kfree(slot->hotplug_slot->info); + kfree(slot->hotplug_slot->name); + kfree(slot->hotplug_slot); + kfree(slot); + + slots--; + } + } + spin_unlock(&list_lock); + return 0; +} + +struct slot * +cpci_find_slot(struct pci_bus *bus, unsigned int devfn) +{ + struct slot *slot; + struct slot *found; + struct list_head *tmp; + + if(!bus) { + return NULL; + } + + spin_lock(&list_lock); + if(!slots) { + spin_unlock(&list_lock); + return NULL; + } + found = NULL; + list_for_each(tmp, &slot_list) { + slot = list_entry(tmp, struct slot, slot_list); + if(slot->bus == bus && slot->devfn == devfn) { + found = slot; + break; + } + } + spin_unlock(&list_lock); + return found; +} + +/* This is the interrupt mode interrupt handler */ +irqreturn_t +cpci_hp_intr(int irq, void *data, struct pt_regs *regs) +{ + dbg("entered cpci_hp_intr"); + + /* Check to see if it was our interrupt */ + if((controller->irq_flags & SA_SHIRQ) && + !controller->ops->check_irq(controller->dev_id)) { + dbg("exited cpci_hp_intr, not our interrupt"); + return IRQ_NONE; + } + + /* Disable ENUM interrupt */ + controller->ops->disable_irq(); + + /* Trigger processing by the event thread */ + dbg("Signal event_semaphore"); + up(&event_semaphore); + dbg("exited cpci_hp_intr"); + return IRQ_HANDLED; +} + +/* + * According to PICMG 2.12 R2.0, section 6.3.2, upon + * initialization, the system driver shall clear the + * INS bits of the cold-inserted devices. + */ +static int +init_slots(void) +{ + struct slot *slot; + struct list_head *tmp; + struct pci_dev* dev; + + dbg("%s - enter", __FUNCTION__); + spin_lock(&list_lock); + if(!slots) { + spin_unlock(&list_lock); + return -1; + } + list_for_each(tmp, &slot_list) { + slot = list_entry(tmp, struct slot, slot_list); + dbg("%s - looking at slot %s", + __FUNCTION__, slot->hotplug_slot->name); + if(cpci_check_and_clear_ins(slot)) { + dbg("%s - cleared INS for slot %s", + __FUNCTION__, slot->hotplug_slot->name); + dev = pci_find_slot(slot->bus->number, PCI_DEVFN(slot->number, 0)); + if(dev) { + if(update_adapter_status(slot->hotplug_slot, 1)) { + warn("failure to update adapter file"); + } + if(update_latch_status(slot->hotplug_slot, 1)) { + warn("failure to update latch file"); + } + slot->dev = dev; + } else { + err("%s - no driver attached to device in slot %s", + __FUNCTION__, slot->hotplug_slot->name); + } + } + } + spin_unlock(&list_lock); + dbg("%s - exit", __FUNCTION__); + return 0; +} + +static int +check_slots(void) +{ + struct slot *slot; + struct list_head *tmp; + int extracted; + int inserted; + + spin_lock(&list_lock); + if(!slots) { + spin_unlock(&list_lock); + err("no slots registered, shutting down"); + return -1; + } + extracted = inserted = 0; + list_for_each(tmp, &slot_list) { + slot = list_entry(tmp, struct slot, slot_list); + dbg("%s - looking at slot %s", + __FUNCTION__, slot->hotplug_slot->name); + if(cpci_check_and_clear_ins(slot)) { + u16 hs_csr; + + /* Some broken hardware (e.g. PLX 9054AB) asserts ENUM# twice... */ + if(slot->dev) { + warn("slot %s already inserted", slot->hotplug_slot->name); + inserted++; + continue; + } + + /* Process insertion */ + dbg("%s - slot %s inserted", + __FUNCTION__, slot->hotplug_slot->name); + + /* GSM, debug */ + hs_csr = cpci_get_hs_csr(slot); + dbg("%s - slot %s HS_CSR (1) = %04x", + __FUNCTION__, slot->hotplug_slot->name, hs_csr); + + /* Configure device */ + dbg("%s - configuring slot %s", + __FUNCTION__, slot->hotplug_slot->name); + if(cpci_configure_slot(slot)) { + err("%s - could not configure slot %s", + __FUNCTION__, slot->hotplug_slot->name); + continue; + } + dbg("%s - finished configuring slot %s", + __FUNCTION__, slot->hotplug_slot->name); + + /* GSM, debug */ + hs_csr = cpci_get_hs_csr(slot); + dbg("%s - slot %s HS_CSR (2) = %04x", + __FUNCTION__, slot->hotplug_slot->name, hs_csr); + + if(update_latch_status(slot->hotplug_slot, 1)) { + warn("failure to update latch file"); + } + + if(update_adapter_status(slot->hotplug_slot, 1)) { + warn("failure to update adapter file"); + } + + cpci_led_off(slot); + + /* GSM, debug */ + hs_csr = cpci_get_hs_csr(slot); + dbg("%s - slot %s HS_CSR (3) = %04x", + __FUNCTION__, slot->hotplug_slot->name, hs_csr); + + inserted++; + } else if(cpci_check_ext(slot)) { + u16 hs_csr; + + /* Process extraction request */ + dbg("%s - slot %s extracted", + __FUNCTION__, slot->hotplug_slot->name); + + /* GSM, debug */ + hs_csr = cpci_get_hs_csr(slot); + dbg("%s - slot %s HS_CSR = %04x", + __FUNCTION__, slot->hotplug_slot->name, hs_csr); + + if(!slot->extracting) { + if(update_latch_status(slot->hotplug_slot, 0)) { + warn("failure to update latch file"); + } + slot->extracting = 1; + } + extracted++; + } + } + spin_unlock(&list_lock); + if(inserted || extracted) { + return extracted; + } + else { + err("cannot find ENUM# source, shutting down"); + return -1; + } +} + +/* This is the interrupt mode worker thread body */ +static int +event_thread(void *data) +{ + int rc; + struct slot *slot; + struct list_head *tmp; + + lock_kernel(); + daemonize("cpci_hp_eventd"); + unlock_kernel(); + + dbg("%s - event thread started", __FUNCTION__); + while(1) { + dbg("event thread sleeping"); + down_interruptible(&event_semaphore); + dbg("event thread woken, thread_finished = %d", + thread_finished); + if(thread_finished || signal_pending(current)) + break; + while(controller->ops->query_enum()) { + rc = check_slots(); + if(rc > 0) { + /* Give userspace a chance to handle extraction */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ / 2); + } else if(rc < 0) { + dbg("%s - error checking slots", __FUNCTION__); + thread_finished = 1; + break; + } + } + /* Check for someone yanking out a board */ + list_for_each(tmp, &slot_list) { + slot = list_entry(tmp, struct slot, slot_list); + if(slot->extracting) { + /* + * Hmmm, we're likely hosed at this point, should we + * bother trying to tell the driver or not? + */ + err("card in slot %s was improperly removed", + slot->hotplug_slot->name); + if(update_adapter_status(slot->hotplug_slot, 0)) { + warn("failure to update adapter file"); + } + slot->extracting = 0; + } + } + + /* Re-enable ENUM# interrupt */ + dbg("%s - re-enabling irq", __FUNCTION__); + controller->ops->enable_irq(); + } + + dbg("%s - event thread signals exit", __FUNCTION__); + up(&thread_exit); + return 0; +} + +/* This is the polling mode worker thread body */ +static int +poll_thread(void *data) +{ + int rc; + struct slot *slot; + struct list_head *tmp; + + lock_kernel(); + daemonize("cpci_hp_polld"); + unlock_kernel(); + + while(1) { + if(thread_finished || signal_pending(current)) + break; + + while(controller->ops->query_enum()) { + rc = check_slots(); + if(rc > 0) { + /* Give userspace a chance to handle extraction */ + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ / 2); + } else if(rc < 0) { + dbg("%s - error checking slots", __FUNCTION__); + thread_finished = 1; + break; + } + } + /* Check for someone yanking out a board */ + list_for_each(tmp, &slot_list) { + slot = list_entry(tmp, struct slot, slot_list); + if(slot->extracting) { + /* + * Hmmm, we're likely hosed at this point, should we + * bother trying to tell the driver or not? + */ + err("card in slot %s was improperly removed", + slot->hotplug_slot->name); + if(update_adapter_status(slot->hotplug_slot, 0)) { + warn("failure to update adapter file"); + } + slot->extracting = 0; + } + } + + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(HZ / 10); + } + dbg("poll thread signals exit"); + up(&thread_exit); + return 0; +} + +static int +cpci_start_thread(void) +{ + int pid; + + /* initialize our semaphores */ + init_MUTEX_LOCKED(&event_semaphore); + init_MUTEX_LOCKED(&thread_exit); + thread_finished = 0; + + if(controller->irq) { + pid = kernel_thread(event_thread, 0, 0); + } else { + pid = kernel_thread(poll_thread, 0, 0); + } + if(pid < 0) { + err("Can't start up our thread"); + return -1; + } + dbg("Our thread pid = %d", pid); + return 0; +} + +static void +cpci_stop_thread(void) +{ + thread_finished = 1; + dbg("thread finish command given"); + if(controller->irq) { + up(&event_semaphore); + } + dbg("wait for thread to exit"); + down(&thread_exit); +} + +int +cpci_hp_register_controller(struct cpci_hp_controller *new_controller) +{ + int status = 0; + + if(!controller) { + controller = new_controller; + if(controller->irq) { + if(request_irq(controller->irq, + cpci_hp_intr, + controller->irq_flags, + MY_NAME, controller->dev_id)) { + err("Can't get irq %d for the hotplug cPCI controller", controller->irq); + status = -ENODEV; + } + dbg("%s - acquired controller irq %d", __FUNCTION__, + controller->irq); + } + } else { + err("cPCI hotplug controller already registered"); + status = -1; + } + return status; +} + +int +cpci_hp_unregister_controller(struct cpci_hp_controller *old_controller) +{ + int status = 0; + + if(controller) { + if(!thread_finished) { + cpci_stop_thread(); + } + if(controller->irq) { + free_irq(controller->irq, controller->dev_id); + } + controller = NULL; + } else { + status = -ENODEV; + } + return status; +} + +int +cpci_hp_start(void) +{ + static int first = 1; + int status; + + dbg("%s - enter", __FUNCTION__); + if(!controller) { + return -ENODEV; + } + + spin_lock(&list_lock); + if(!slots) { + spin_unlock(&list_lock); + return -ENODEV; + } + spin_unlock(&list_lock); + + if(first) { + status = init_slots(); + if(status) { + return status; + } + first = 0; + } + + status = cpci_start_thread(); + if(status) { + return status; + } + dbg("%s - thread started", __FUNCTION__); + + if(controller->irq) { + /* Start enum interrupt processing */ + dbg("%s - enabling irq", __FUNCTION__); + controller->ops->enable_irq(); + } + dbg("%s - exit", __FUNCTION__); + return 0; +} + +int +cpci_hp_stop(void) +{ + if(!controller) { + return -ENODEV; + } + + if(controller->irq) { + /* Stop enum interrupt processing */ + dbg("%s - disabling irq", __FUNCTION__); + controller->ops->disable_irq(); + } + cpci_stop_thread(); + return 0; +} + +static void __exit +cleanup_slots(void) +{ + struct list_head *tmp; + struct slot *slot; + + /* + * Unregister all of our slots with the pci_hotplug subsystem, + * and free up all memory that we had allocated. + */ + spin_lock(&list_lock); + if(!slots) { + goto null_cleanup; + } + list_for_each(tmp, &slot_list) { + slot = list_entry(tmp, struct slot, slot_list); + list_del(&slot->slot_list); + pci_hp_deregister(slot->hotplug_slot); + kfree(slot->hotplug_slot->info); + kfree(slot->hotplug_slot->name); + kfree(slot->hotplug_slot); + kfree(slot); + } + null_cleanup: + spin_unlock(&list_lock); + return; +} + +int __init +cpci_hotplug_init(int debug) +{ + spin_lock_init(&list_lock); + cpci_debug = debug; + + info(DRIVER_DESC " version: " DRIVER_VERSION); + return 0; +} + +void __exit +cpci_hotplug_exit(void) +{ + /* + * Clean everything up. + */ + cleanup_slots(); +} + + +EXPORT_SYMBOL_GPL(cpci_hp_register_controller); +EXPORT_SYMBOL_GPL(cpci_hp_unregister_controller); +EXPORT_SYMBOL_GPL(cpci_hp_register_bus); +EXPORT_SYMBOL_GPL(cpci_hp_unregister_bus); +EXPORT_SYMBOL_GPL(cpci_find_slot); +EXPORT_SYMBOL_GPL(cpci_hp_start); +EXPORT_SYMBOL_GPL(cpci_hp_stop); diff -Nru a/drivers/pci/hotplug/cpci_hotplug_pci.c b/drivers/pci/hotplug/cpci_hotplug_pci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pci/hotplug/cpci_hotplug_pci.c Mon Jun 9 23:16:15 2003 @@ -0,0 +1,647 @@ +/* + * CompactPCI Hot Plug Driver PCI functions + * + * Copyright (c) 2002 by SOMA Networks, Inc. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Send feedback to <scottm@somanetworks.com> + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/pci.h> +#include <linux/proc_fs.h> +#include "../pci.h" +#include "pci_hotplug.h" +#include "cpci_hotplug.h" + +#if !defined(CONFIG_HOTPLUG_CPCI_MODULE) +#define MY_NAME "cpci_hotplug" +#else +#define MY_NAME THIS_MODULE->name +#endif + +extern int cpci_debug; + +#define dbg(format, arg...) \ + do { \ + if(cpci_debug) \ + printk (KERN_DEBUG "%s: " format "\n", \ + MY_NAME , ## arg); \ + } while(0) +#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) + +#define ROUND_UP(x, a) (((x) + (a) - 1) & ~((a) - 1)) + + +u8 cpci_get_attention_status(struct slot* slot) +{ + int hs_cap; + u16 hs_csr; + + hs_cap = pci_bus_find_capability(slot->bus, + slot->devfn, + PCI_CAP_ID_CHSWP); + if(!hs_cap) { + return 0; + } + + if(pci_bus_read_config_word(slot->bus, + slot->devfn, + hs_cap + 2, + &hs_csr)) { + return 0; + } + return hs_csr & 0x0008 ? 1 : 0; +} + +int cpci_set_attention_status(struct slot* slot, int status) +{ + int hs_cap; + u16 hs_csr; + + hs_cap = pci_bus_find_capability(slot->bus, + slot->devfn, + PCI_CAP_ID_CHSWP); + if(!hs_cap) { + return 0; + } + + if(pci_bus_read_config_word(slot->bus, + slot->devfn, + hs_cap + 2, + &hs_csr)) { + return 0; + } + if(status) { + hs_csr |= HS_CSR_LOO; + } else { + hs_csr &= ~HS_CSR_LOO; + } + if(pci_bus_write_config_word(slot->bus, + slot->devfn, + hs_cap + 2, + hs_csr)) { + return 0; + } + return 1; +} + +u16 cpci_get_hs_csr(struct slot* slot) +{ + int hs_cap; + u16 hs_csr; + + hs_cap = pci_bus_find_capability(slot->bus, + slot->devfn, + PCI_CAP_ID_CHSWP); + if(!hs_cap) { + return 0xFFFF; + } + + if(pci_bus_read_config_word(slot->bus, + slot->devfn, + hs_cap + 2, + &hs_csr)) { + return 0xFFFF; + } + return hs_csr; +} + +u16 cpci_set_hs_csr(struct slot* slot, u16 hs_csr) +{ + int hs_cap; + u16 new_hs_csr; + + hs_cap = pci_bus_find_capability(slot->bus, + slot->devfn, + PCI_CAP_ID_CHSWP); + if(!hs_cap) { + return 0xFFFF; + } + + /* Write out the new value */ + if(pci_bus_write_config_word(slot->bus, + slot->devfn, + hs_cap + 2, + hs_csr)) { + return 0xFFFF; + } + + /* Read back what we just wrote out */ + if(pci_bus_read_config_word(slot->bus, + slot->devfn, + hs_cap + 2, + &new_hs_csr)) { + return 0xFFFF; + } + return new_hs_csr; +} + +int cpci_check_and_clear_ins(struct slot* slot) +{ + int hs_cap; + u16 hs_csr; + int ins = 0; + + hs_cap = pci_bus_find_capability(slot->bus, + slot->devfn, + PCI_CAP_ID_CHSWP); + if(!hs_cap) { + return 0; + } + if(pci_bus_read_config_word(slot->bus, + slot->devfn, + hs_cap + 2, + &hs_csr)) { + return 0; + } + if(hs_csr & HS_CSR_INS) { + /* Clear INS (by setting it) */ + if(pci_bus_write_config_word(slot->bus, + slot->devfn, + hs_cap + 2, + hs_csr)) { + ins = 0; + } + ins = 1; + } + return ins; +} + +int cpci_check_ext(struct slot* slot) +{ + int hs_cap; + u16 hs_csr; + int ext = 0; + + hs_cap = pci_bus_find_capability(slot->bus, + slot->devfn, + PCI_CAP_ID_CHSWP); + if(!hs_cap) { + return 0; + } + if(pci_bus_read_config_word(slot->bus, + slot->devfn, + hs_cap + 2, + &hs_csr)) { + return 0; + } + if(hs_csr & HS_CSR_EXT) { + ext = 1; + } + return ext; +} + +int cpci_clear_ext(struct slot* slot) +{ + int hs_cap; + u16 hs_csr; + + hs_cap = pci_bus_find_capability(slot->bus, + slot->devfn, + PCI_CAP_ID_CHSWP); + if(!hs_cap) { + return -ENODEV; + } + if(pci_bus_read_config_word(slot->bus, + slot->devfn, + hs_cap + 2, + &hs_csr)) { + return -ENODEV; + } + if(hs_csr & HS_CSR_EXT) { + /* Clear EXT (by setting it) */ + if(pci_bus_write_config_word(slot->bus, + slot->devfn, + hs_cap + 2, + hs_csr)) { + return -ENODEV; + } + } + return 0; +} + +int cpci_led_on(struct slot* slot) +{ + int hs_cap; + u16 hs_csr; + + hs_cap = pci_bus_find_capability(slot->bus, + slot->devfn, + PCI_CAP_ID_CHSWP); + if(!hs_cap) { + return -ENODEV; + } + if(pci_bus_read_config_word(slot->bus, + slot->devfn, + hs_cap + 2, + &hs_csr)) { + return -ENODEV; + } + if((hs_csr & HS_CSR_LOO) != HS_CSR_LOO) { + /* Set LOO */ + hs_csr |= HS_CSR_LOO; + if(pci_bus_write_config_word(slot->bus, + slot->devfn, + hs_cap + 2, + hs_csr)) { + err("Could not set LOO for slot %s", + slot->hotplug_slot->name); + return -ENODEV; + } + } + return 0; +} + +int cpci_led_off(struct slot* slot) +{ + int hs_cap; + u16 hs_csr; + + hs_cap = pci_bus_find_capability(slot->bus, + slot->devfn, + PCI_CAP_ID_CHSWP); + if(!hs_cap) { + return -ENODEV; + } + if(pci_bus_read_config_word(slot->bus, + slot->devfn, + hs_cap + 2, + &hs_csr)) { + return -ENODEV; + } + if(hs_csr & HS_CSR_LOO) { + /* Clear LOO */ + hs_csr &= ~HS_CSR_LOO; + if(pci_bus_write_config_word(slot->bus, + slot->devfn, + hs_cap + 2, + hs_csr)) { + err("Could not clear LOO for slot %s", + slot->hotplug_slot->name); + return -ENODEV; + } + } + return 0; +} + + +/* + * Device configuration functions + */ + +static int cpci_configure_dev(struct pci_bus *bus, struct pci_dev *dev) +{ + u8 irq_pin; + int r; + + dbg("%s - enter", __FUNCTION__); + + /* NOTE: device already setup from prior scan */ + + /* FIXME: How would we know if we need to enable the expansion ROM? */ + pci_write_config_word(dev, PCI_ROM_ADDRESS, 0x00L); + + /* Assign resources */ + dbg("assigning resources for %02x:%02x.%x", + dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + for (r = 0; r < 6; r++) { + struct resource *res = dev->resource + r; + if(res->flags) + pci_assign_resource(dev, r); + } + dbg("finished assigning resources for %02x:%02x.%x", + dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + + /* Does this function have an interrupt at all? */ + dbg("checking for function interrupt"); + pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq_pin); + if(irq_pin) { + dbg("function uses interrupt pin %d", irq_pin); + } + + /* + * Need to explicitly set irq field to 0 so that it'll get assigned + * by the pcibios platform dependent code called by pci_enable_device. + */ + dev->irq = 0; + + dbg("enabling device"); + pci_enable_device(dev); /* XXX check return */ + dbg("now dev->irq = %d", dev->irq); + if(irq_pin && dev->irq) { + pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq); + } + + /* Can't use pci_insert_device at the moment, do it manually for now */ + pci_proc_attach_device(dev); + dbg("notifying drivers"); + //pci_announce_device_to_drivers(dev); + dbg("%s - exit", __FUNCTION__); + return 0; +} + +static int cpci_configure_bridge(struct pci_bus* bus, struct pci_dev* dev) +{ + int rc; + struct pci_bus* child; + struct resource* r; + u8 max, n; + u16 command; + + dbg("%s - enter", __FUNCTION__); + + /* Do basic bridge initialization */ + rc = pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x40); + if(rc) { + printk(KERN_ERR "%s - write of PCI_LATENCY_TIMER failed\n", __FUNCTION__); + } + rc = pci_write_config_byte(dev, PCI_SEC_LATENCY_TIMER, 0x40); + if(rc) { + printk(KERN_ERR "%s - write of PCI_SEC_LATENCY_TIMER failed\n", __FUNCTION__); + } + rc = pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, L1_CACHE_BYTES / 4); + if(rc) { + printk(KERN_ERR "%s - write of PCI_CACHE_LINE_SIZE failed\n", __FUNCTION__); + } + + /* + * Set parent bridge's subordinate field so that configuration space + * access will work in pci_scan_bridge and friends. + */ + max = pci_max_busnr(); + bus->subordinate = max + 1; + pci_write_config_byte(bus->self, PCI_SUBORDINATE_BUS, max + 1); + + /* Scan behind bridge */ + n = pci_scan_bridge(bus, dev, max, 2); + child = pci_find_bus(max + 1); + if (!child) + return -ENODEV; + pci_proc_attach_bus(child); + + /* + * Update parent bridge's subordinate field if there were more bridges + * behind the bridge that was scanned. + */ + if(n > max) { + bus->subordinate = n; + pci_write_config_byte(bus->self, PCI_SUBORDINATE_BUS, n); + } + + /* + * Update the bridge resources of the bridge to accommodate devices + * behind it. + */ + pci_bus_size_bridges(child); + pci_bus_assign_resources(child); + + /* Enable resource mapping via command register */ + command = PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | PCI_COMMAND_SERR; + r = child->resource[0]; + if(r && r->start) { + command |= PCI_COMMAND_IO; + } + r = child->resource[1]; + if(r && r->start) { + command |= PCI_COMMAND_MEMORY; + } + r = child->resource[2]; + if(r && r->start) { + command |= PCI_COMMAND_MEMORY; + } + rc = pci_write_config_word(dev, PCI_COMMAND, command); + if(rc) { + err("Error setting command register"); + return rc; + } + + /* Set bridge control register */ + command = PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR | PCI_BRIDGE_CTL_NO_ISA; + rc = pci_write_config_word(dev, PCI_BRIDGE_CONTROL, command); + if(rc) { + err("Error setting bridge control register"); + return rc; + } + dbg("%s - exit", __FUNCTION__); + return 0; +} + +static int configure_visit_pci_dev(struct pci_dev_wrapped *wrapped_dev, + struct pci_bus_wrapped *wrapped_bus) +{ + int rc; + struct pci_dev *dev = wrapped_dev->dev; + struct pci_bus *bus = wrapped_bus->bus; + struct slot* slot; + + dbg("%s - enter", __FUNCTION__); + + /* + * We need to fix up the hotplug representation with the Linux + * representation. + */ + slot = cpci_find_slot(dev->bus, dev->devfn); + if(slot) { + slot->dev = dev; + } + + /* If it's a bridge, scan behind it for devices */ + if(dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + rc = cpci_configure_bridge(bus, dev); + if(rc) + return rc; + } + + /* Actually configure device */ + if(dev) { + rc = cpci_configure_dev(bus, dev); + if(rc) + return rc; + } + dbg("%s - exit", __FUNCTION__); + return 0; +} + +static int unconfigure_visit_pci_dev_phase2(struct pci_dev_wrapped *wrapped_dev, + struct pci_bus_wrapped *wrapped_bus) +{ + struct pci_dev *dev = wrapped_dev->dev; + struct slot* slot; + + dbg("%s - enter", __FUNCTION__); + if(!dev) + return -ENODEV; + + /* Remove the Linux representation */ + if(pci_remove_device_safe(dev) == 0) { + kfree(dev); + } else { + err("Could not remove device\n"); + return -1; + } + + /* + * Now remove the hotplug representation. + */ + slot = cpci_find_slot(dev->bus, dev->devfn); + if(slot) { + slot->dev = NULL; + } else { + dbg("No hotplug representation for %02x:%02x.%x", + dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn)); + } + dbg("%s - exit", __FUNCTION__); + return 0; +} + +static int unconfigure_visit_pci_bus_phase2(struct pci_bus_wrapped *wrapped_bus, + struct pci_dev_wrapped *wrapped_dev) +{ + struct pci_bus *bus = wrapped_bus->bus; + struct pci_bus *parent = bus->self->bus; + + dbg("%s - enter", __FUNCTION__); + + /* The cleanup code for proc entries regarding buses should be in the kernel... */ + if(bus->procdir) + dbg("detach_pci_bus %s", bus->procdir->name); + pci_proc_detach_bus(bus); + + /* The cleanup code should live in the kernel... */ + bus->self->subordinate = NULL; + + /* unlink from parent bus */ + list_del(&bus->node); + + /* Now, remove */ + if(bus) + kfree(bus); + + /* Update parent's subordinate field */ + if(parent) { + u8 n = pci_bus_max_busnr(parent); + if(n < parent->subordinate) { + parent->subordinate = n; + pci_write_config_byte(parent->self, PCI_SUBORDINATE_BUS, n); + } + } + dbg("%s - exit", __FUNCTION__); + return 0; +} + +static struct pci_visit configure_functions = { + .visit_pci_dev = configure_visit_pci_dev, +}; + +static struct pci_visit unconfigure_functions_phase2 = { + .post_visit_pci_bus = unconfigure_visit_pci_bus_phase2, + .post_visit_pci_dev = unconfigure_visit_pci_dev_phase2 +}; + + +int cpci_configure_slot(struct slot* slot) +{ + int rc = 0; + + dbg("%s - enter", __FUNCTION__); + + if(slot->dev == NULL) { + dbg("pci_dev null, finding %02x:%02x:%x", + slot->bus->number, PCI_SLOT(slot->devfn), PCI_FUNC(slot->devfn)); + slot->dev = pci_find_slot(slot->bus->number, slot->devfn); + } + + /* Still NULL? Well then scan for it! */ + if(slot->dev == NULL) { + dbg("pci_dev still null"); + + /* + * This will generate pci_dev structures for all functions, but + * we will only call this case when lookup fails. + */ + slot->dev = pci_scan_slot(slot->bus, slot->devfn); + if(slot->dev == NULL) { + err("Could not find PCI device for slot %02x", slot->number); + return 0; + } + } + dbg("slot->dev = %p", slot->dev); + if(slot->dev) { + struct pci_dev *dev; + struct pci_dev_wrapped wrapped_dev; + struct pci_bus_wrapped wrapped_bus; + int i; + + memset(&wrapped_dev, 0, sizeof (struct pci_dev_wrapped)); + memset(&wrapped_bus, 0, sizeof (struct pci_bus_wrapped)); + + for (i = 0; i < 8; i++) { + dev = pci_find_slot(slot->bus->number, + PCI_DEVFN(PCI_SLOT(slot->dev->devfn), i)); + if(!dev) + continue; + wrapped_dev.dev = dev; + wrapped_bus.bus = slot->dev->bus; + rc = pci_visit_dev(&configure_functions, &wrapped_dev, &wrapped_bus); + } + } + + dbg("%s - exit, rc = %d", __FUNCTION__, rc); + return rc; +} + +int cpci_unconfigure_slot(struct slot* slot) +{ + int rc = 0; + int i; + struct pci_dev_wrapped wrapped_dev; + struct pci_bus_wrapped wrapped_bus; + struct pci_dev *dev; + + dbg("%s - enter", __FUNCTION__); + + if(!slot->dev) { + err("No device for slot %02x\n", slot->number); + return -ENODEV; + } + + memset(&wrapped_dev, 0, sizeof (struct pci_dev_wrapped)); + memset(&wrapped_bus, 0, sizeof (struct pci_bus_wrapped)); + + for (i = 0; i < 8; i++) { + dev = pci_find_slot(slot->bus->number, + PCI_DEVFN(PCI_SLOT(slot->devfn), i)); + if(dev) { + wrapped_dev.dev = dev; + wrapped_bus.bus = dev->bus; + dbg("%s - unconfigure phase 2", __FUNCTION__); + rc = pci_visit_dev(&unconfigure_functions_phase2, + &wrapped_dev, &wrapped_bus); + if(rc) + break; + } + } + dbg("%s - exit, rc = %d", __FUNCTION__, rc); + return rc; +} diff -Nru a/drivers/pci/hotplug/cpcihp_generic.c b/drivers/pci/hotplug/cpcihp_generic.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pci/hotplug/cpcihp_generic.c Mon Jun 9 23:16:13 2003 @@ -0,0 +1,290 @@ +/* + * cpcihp_generic.c + * + * Generic port I/O CompactPCI driver + * + * Copyright 2002 SOMA Networks, Inc. + * Copyright 2001 Intel San Luis Obispo + * Copyright 2000,2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License 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. + * + * This generic CompactPCI hotplug driver should allow using the PCI hotplug + * mechanism on any CompactPCI board that exposes the #ENUM signal as a bit + * in a system register that can be read through standard port I/O. + * + * Send feedback to <scottm@somanetworks.com> + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/pci.h> +#include "cpci_hotplug.h" + +#define DRIVER_VERSION "0.1" +#define DRIVER_AUTHOR "Scott Murray <scottm@somanetworks.com>" +#define DRIVER_DESC "Generic port I/O CompactPCI Hot Plug Driver" + +#if !defined(CONFIG_HOTPLUG_CPCI_GENERIC_MODULE) +#define MY_NAME "cpcihp_generic" +#else +#define MY_NAME THIS_MODULE->name +#endif + +#define dbg(format, arg...) \ + do { \ + if(debug) \ + printk (KERN_DEBUG "%s: " format "\n", \ + MY_NAME , ## arg); \ + } while(0) +#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) + +/* local variables */ +static int debug; +static char* bridge; +static u8 bridge_busnr; +static u8 bridge_slot; +static struct pci_bus *bus; +static u8 first_slot; +static u8 last_slot; +static u16 port; +static unsigned int enum_bit; +static u8 enum_mask; + +static struct cpci_hp_controller_ops generic_hpc_ops; +static struct cpci_hp_controller generic_hpc; + +/* The following allows configuring the driver when it's compiled into the kernel */ +#ifndef MODULE +static int __init cpcihp_generic_setup(char* str) +{ + char* p; + unsigned long tmp; + + if(!str) + return -EINVAL; + bridge = str; + + p = strchr(str, ','); + str = p + 1; + if(!(p && *str && *p == ',')) + goto setup_error; + tmp = simple_strtoul(str, &p, 0); + if(p == str || tmp > 0xff) { + err("hotplug bus first slot number out of range"); + goto setup_error; + } + first_slot = (u8) tmp; + + str = p + 1; + if(!(*str && *p == ',')) + return -EINVAL; + tmp = simple_strtoul(str, &p, 0); + if(p == str || tmp > 0xff) { + err("hotplug bus last slot number out of range"); + goto setup_error; + } + last_slot = (u8) tmp; + + str = p + 1; + if(!(*str && *p == ',')) + goto setup_error; + tmp = simple_strtoul(str, &p, 0); + if(p == str || tmp > 0xffff) { + err("port number out of range"); + goto setup_error; + } + port = (u16) tmp; + + str = p + 1; + if(!(*str && *p == ',')) + goto setup_error; + tmp = simple_strtoul(str, &p, 0); + if(p == str) { + err("invalid #ENUM bit number"); + goto setup_error; + } + enum_bit = (u8) tmp; + + str = p + 1; + if(*str && *p == ',') { + tmp = simple_strtoul(str, &p, 0); + if(p != str) + debug = (int) tmp; + } + return 0; +setup_error: + bridge = NULL; + return -EINVAL; +} + +__setup("cpcihp_generic=", cpcihp_generic_setup); +#endif + +static int __init validate_parameters(void) +{ + char* str; + char* p; + unsigned long tmp; + + if(!bridge) { + info("not configured, disabling."); + return 1; + } + str = bridge; + if(!*str) + return -EINVAL; + + tmp = simple_strtoul(str, &p, 16); + if(p == str || tmp > 0xff) { + err("Invalid hotplug bus bridge device bus number"); + return -EINVAL; + } + bridge_busnr = (u8) tmp; + dbg("bridge_busnr = 0x%02x", bridge_busnr); + if(*p != ':') { + err("Invalid hotplug bus bridge device"); + return -EINVAL; + } + str = p + 1; + tmp = simple_strtoul(str, &p, 16); + if(p == str || tmp > 0x1f) { + err("Invalid hotplug bus bridge device slot number"); + return -EINVAL; + } + bridge_slot = (u8) tmp; + dbg("bridge_slot = 0x%02x", bridge_slot); + + dbg("first_slot = 0x%02x", first_slot); + dbg("last_slot = 0x%02x", last_slot); + if(!(first_slot && last_slot)) { + err("Need to specify first_slot and last_slot"); + return -EINVAL; + } + if(last_slot < first_slot) { + err("first_slot must be less than last_slot"); + return -EINVAL; + } + + dbg("port = 0x%04x", port); + dbg("enum_bit = 0x%02x", enum_bit); + if(enum_bit > 7) { + err("Invalid #ENUM bit"); + return -EINVAL; + } + enum_mask = 1 << enum_bit; + return 0; +} + +static int query_enum(void) +{ + u8 value; + + value = inb_p(port); + return ((value & enum_mask) == enum_mask); +} + +static int __init cpcihp_generic_init(void) +{ + int status; + struct resource* r; + struct pci_dev* dev; + + info(DRIVER_DESC " version: " DRIVER_VERSION); + status = validate_parameters(); + if(status != 0) + return status; + + r = request_region(port, 1, "#ENUM hotswap signal register"); + if(!r) + return -EBUSY; + + dev = pci_find_slot(bridge_busnr, PCI_DEVFN(bridge_slot, 0)); + if(!dev || dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) { + err("Invalid bridge device %s", bridge); + return -EINVAL; + } + bus = dev->subordinate; + + memset(&generic_hpc, 0, sizeof (struct cpci_hp_controller)); + generic_hpc_ops.query_enum = query_enum; + generic_hpc.ops = &generic_hpc_ops; + + status = cpci_hp_register_controller(&generic_hpc); + if(status != 0) { + err("Could not register cPCI hotplug controller"); + return -ENODEV; + } + dbg("registered controller"); + + status = cpci_hp_register_bus(bus, first_slot, last_slot); + if(status != 0) { + err("Could not register cPCI hotplug bus"); + goto init_bus_register_error; + } + dbg("registered bus"); + + status = cpci_hp_start(); + if(status != 0) { + err("Could not started cPCI hotplug system"); + goto init_start_error; + } + dbg("started cpci hp system"); + return 0; +init_start_error: + cpci_hp_unregister_bus(bus); +init_bus_register_error: + cpci_hp_unregister_controller(&generic_hpc); + err("status = %d", status); + return status; + +} + +static void __exit cpcihp_generic_exit(void) +{ + cpci_hp_stop(); + cpci_hp_unregister_bus(bus); + cpci_hp_unregister_controller(&generic_hpc); + release_region(port, 1); +} + +module_init(cpcihp_generic_init); +module_exit(cpcihp_generic_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); +MODULE_PARM(bridge, "s"); +MODULE_PARM_DESC(bridge, "Hotswap bus bridge device, <bus>:<slot> (bus and slot are in hexadecimal)"); +MODULE_PARM(first_slot, "b"); +MODULE_PARM_DESC(first_slot, "Hotswap bus first slot number"); +MODULE_PARM(last_slot, "b"); +MODULE_PARM_DESC(last_slot, "Hotswap bus last slot number"); +MODULE_PARM(port, "h"); +MODULE_PARM_DESC(port, "#ENUM signal I/O port"); +MODULE_PARM(enum_bit, "i"); +MODULE_PARM_DESC(enum_bit, "#ENUM signal bit (0-7)"); diff -Nru a/drivers/pci/hotplug/cpcihp_zt5550.c b/drivers/pci/hotplug/cpcihp_zt5550.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pci/hotplug/cpcihp_zt5550.c Mon Jun 9 23:16:14 2003 @@ -0,0 +1,306 @@ +/* + * cpcihp_zt5550.c + * + * Intel/Ziatech ZT5550 CompactPCI Host Controller driver + * + * Copyright 2002 SOMA Networks, Inc. + * Copyright 2001 Intel San Luis Obispo + * Copyright 2000,2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License 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. + * + * Send feedback to <scottm@somanetworks.com> + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/pci.h> +#include "cpci_hotplug.h" +#include "cpcihp_zt5550.h" + +#define DRIVER_VERSION "0.2" +#define DRIVER_AUTHOR "Scott Murray <scottm@somanetworks.com>" +#define DRIVER_DESC "ZT5550 CompactPCI Hot Plug Driver" + +#if !defined(CONFIG_HOTPLUG_PCI_CPCI_ZT5550_MODULE) +#define MY_NAME "cpcihp_zt5550" +#else +#define MY_NAME THIS_MODULE->name +#endif + +#define dbg(format, arg...) \ + do { \ + if(debug) \ + printk (KERN_DEBUG "%s: " format "\n", \ + MY_NAME , ## arg); \ + } while(0) +#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) + +/* local variables */ +static int debug; +static int poll; +static struct cpci_hp_controller_ops zt5550_hpc_ops; +static struct cpci_hp_controller zt5550_hpc; + +/* Primary cPCI bus bridge device */ +static struct pci_dev *bus0_dev; +static struct pci_bus *bus0; + +/* Host controller device */ +static struct pci_dev *hc_dev; + +/* Host controller register addresses */ +static void *hc_registers; +static void *csr_hc_index; +static void *csr_hc_data; +static void *csr_int_status; +static void *csr_int_mask; + + +static int zt5550_hc_config(struct pci_dev *pdev) +{ + /* Since we know that no boards exist with two HC chips, treat it as an error */ + if(hc_dev) { + err("too many host controller devices?"); + return -EBUSY; + } + hc_dev = pdev; + dbg("hc_dev = %p", hc_dev); + dbg("pci resource start %lx", pci_resource_start(hc_dev, 1)); + dbg("pci resource len %lx", pci_resource_len(hc_dev, 1)); + + if(!request_mem_region(pci_resource_start(hc_dev, 1), + pci_resource_len(hc_dev, 1), MY_NAME)) { + err("cannot reserve MMIO region"); + return -ENOMEM; + } + + hc_registers = + ioremap(pci_resource_start(hc_dev, 1), pci_resource_len(hc_dev, 1)); + if(!hc_registers) { + err("cannot remap MMIO region %lx @ %lx", + pci_resource_len(hc_dev, 1), pci_resource_start(hc_dev, 1)); + release_mem_region(pci_resource_start(hc_dev, 1), + pci_resource_len(hc_dev, 1)); + return -ENODEV; + } + + csr_hc_index = hc_registers + CSR_HCINDEX; + csr_hc_data = hc_registers + CSR_HCDATA; + csr_int_status = hc_registers + CSR_INTSTAT; + csr_int_mask = hc_registers + CSR_INTMASK; + + /* + * Disable host control, fault and serial interrupts + */ + dbg("disabling host control, fault and serial interrupts"); + writeb((u8) HC_INT_MASK_REG, csr_hc_index); + writeb((u8) ALL_INDEXED_INTS_MASK, csr_hc_data); + dbg("disabled host control, fault and serial interrupts"); + + /* + * Disable timer0, timer1 and ENUM interrupts + */ + dbg("disabling timer0, timer1 and ENUM interrupts"); + writeb((u8) ALL_DIRECT_INTS_MASK, csr_int_mask); + dbg("disabled timer0, timer1 and ENUM interrupts"); + return 0; +} + +static int zt5550_hc_cleanup(void) +{ + if(!hc_dev) + return -ENODEV; + release_mem_region(pci_resource_start(hc_dev, 1), + pci_resource_len(hc_dev, 1)); + return 0; +} + +static int zt5550_hc_query_enum(void) +{ + u8 value; + + value = inb_p(ENUM_PORT); + return ((value & ENUM_MASK) == ENUM_MASK); +} + +static int zt5550_hc_check_irq(void *dev_id) +{ + int ret; + u8 reg; + + ret = 0; + if(dev_id == zt5550_hpc.dev_id) { + reg = readb(csr_int_status); + if(reg) + ret = 1; + } + return ret; +} + +static int zt5550_hc_enable_irq(void) +{ + u8 reg; + + if(hc_dev == NULL) { + return -ENODEV; + } + reg = readb(csr_int_mask); + reg = reg & ~ENUM_INT_MASK; + writeb(reg, csr_int_mask); + return 0; +} + +int zt5550_hc_disable_irq(void) +{ + u8 reg; + + if(hc_dev == NULL) { + return -ENODEV; + } + + reg = readb(csr_int_mask); + reg = reg | ENUM_INT_MASK; + writeb(reg, csr_int_mask); + return 0; +} + +static int __devinit zt5550_hc_init_one (struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int status; + + status = zt5550_hc_config(pdev); + if(status != 0) { + return status; + } + dbg("returned from zt5550_hc_config"); + + memset(&zt5550_hpc, 0, sizeof (struct cpci_hp_controller)); + zt5550_hpc_ops.query_enum = zt5550_hc_query_enum; + zt5550_hpc.ops = &zt5550_hpc_ops; + if(!poll) { + zt5550_hpc.irq = hc_dev->irq; + zt5550_hpc.irq_flags = SA_SHIRQ; + zt5550_hpc.dev_id = hc_dev; + + zt5550_hpc_ops.enable_irq = zt5550_hc_enable_irq; + zt5550_hpc_ops.disable_irq = zt5550_hc_disable_irq; + zt5550_hpc_ops.check_irq = zt5550_hc_check_irq; + } else { + info("using ENUM# polling mode"); + } + + status = cpci_hp_register_controller(&zt5550_hpc); + if(status != 0) { + err("could not register cPCI hotplug controller"); + goto init_hc_error; + } + dbg("registered controller"); + + /* Look for first device matching cPCI bus's bridge vendor and device IDs */ + if(!(bus0_dev = pci_find_device(PCI_VENDOR_ID_DEC, + PCI_DEVICE_ID_DEC_21154, NULL))) { + status = -ENODEV; + goto init_register_error; + } + bus0 = bus0_dev->subordinate; + + status = cpci_hp_register_bus(bus0, 0x0a, 0x0f); + if(status != 0) { + err("could not register cPCI hotplug bus"); + goto init_register_error; + } + dbg("registered bus"); + + status = cpci_hp_start(); + if(status != 0) { + err("could not started cPCI hotplug system"); + cpci_hp_unregister_bus(bus0); + goto init_register_error; + } + dbg("started cpci hp system"); + + return 0; +init_register_error: + cpci_hp_unregister_controller(&zt5550_hpc); +init_hc_error: + err("status = %d", status); + zt5550_hc_cleanup(); + return status; + +} + +static void __devexit zt5550_hc_remove_one(struct pci_dev *pdev) +{ + cpci_hp_stop(); + cpci_hp_unregister_bus(bus0); + cpci_hp_unregister_controller(&zt5550_hpc); + zt5550_hc_cleanup(); +} + + +static struct pci_device_id zt5550_hc_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_ZIATECH, PCI_DEVICE_ID_ZIATECH_5550_HC, PCI_ANY_ID, PCI_ANY_ID, }, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, zt5550_hc_pci_tbl); + +static struct pci_driver zt5550_hc_driver = { + .name = "zt5550_hc", + .id_table = zt5550_hc_pci_tbl, + .probe = zt5550_hc_init_one, + .remove = __devexit_p(zt5550_hc_remove_one), +}; + +static int __init zt5550_init(void) +{ + struct resource* r; + + info(DRIVER_DESC " version: " DRIVER_VERSION); + r = request_region(ENUM_PORT, 1, "#ENUM hotswap signal register"); + if(!r) + return -EBUSY; + + return pci_module_init(&zt5550_hc_driver); +} + +static void __exit +zt5550_exit(void) +{ + pci_unregister_driver(&zt5550_hc_driver); + release_region(ENUM_PORT, 1); +} + +module_init(zt5550_init); +module_exit(zt5550_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); +MODULE_PARM(poll, "i"); +MODULE_PARM_DESC(poll, "#ENUM polling mode enabled or not"); diff -Nru a/drivers/pci/hotplug/cpcihp_zt5550.h b/drivers/pci/hotplug/cpcihp_zt5550.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pci/hotplug/cpcihp_zt5550.h Mon Jun 9 23:16:06 2003 @@ -0,0 +1,79 @@ +/* + * cpcihp_zt5550.h + * + * Intel/Ziatech ZT5550 CompactPCI Host Controller driver definitions + * + * Copyright 2002 SOMA Networks, Inc. + * Copyright 2001 Intel San Luis Obispo + * Copyright 2000,2001 MontaVista Software Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License 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. + * + * Send feedback to <scottm@somanetworks.com> + */ + +#ifndef _CPCIHP_ZT5550_H +#define _CPCIHP_ZT5550_H + +/* Direct registers */ +#define CSR_HCINDEX 0x00 +#define CSR_HCDATA 0x04 +#define CSR_INTSTAT 0x08 +#define CSR_INTMASK 0x09 +#define CSR_CNT0CMD 0x0C +#define CSR_CNT1CMD 0x0E +#define CSR_CNT0 0x10 +#define CSR_CNT1 0x14 + +/* Masks for interrupt bits in CSR_INTMASK direct register */ +#define CNT0_INT_MASK 0x01 +#define CNT1_INT_MASK 0x02 +#define ENUM_INT_MASK 0x04 +#define ALL_DIRECT_INTS_MASK 0x07 + +/* Indexed registers (through CSR_INDEX, CSR_DATA) */ +#define HC_INT_MASK_REG 0x04 +#define HC_STATUS_REG 0x08 +#define HC_CMD_REG 0x0C +#define ARB_CONFIG_GNT_REG 0x10 +#define ARB_CONFIG_CFG_REG 0x12 +#define ARB_CONFIG_REG 0x10 +#define ISOL_CONFIG_REG 0x18 +#define FAULT_STATUS_REG 0x20 +#define FAULT_CONFIG_REG 0x24 +#define WD_CONFIG_REG 0x2C +#define HC_DIAG_REG 0x30 +#define SERIAL_COMM_REG 0x34 +#define SERIAL_OUT_REG 0x38 +#define SERIAL_IN_REG 0x3C + +/* Masks for interrupt bits in HC_INT_MASK_REG indexed register */ +#define SERIAL_INT_MASK 0x01 +#define FAULT_INT_MASK 0x02 +#define HCF_INT_MASK 0x04 +#define ALL_INDEXED_INTS_MASK 0x07 + +/* Digital I/O port storing ENUM# */ +#define ENUM_PORT 0xE1 +/* Mask to get to the ENUM# bit on the bus */ +#define ENUM_MASK 0x40 + +#endif /* _CPCIHP_ZT5550_H */ diff -Nru a/drivers/pci/hotplug/cpqphp.h b/drivers/pci/hotplug/cpqphp.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pci/hotplug/cpqphp.h Mon Jun 9 23:16:17 2003 @@ -0,0 +1,912 @@ +/* + * Compaq Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Send feedback to <greg@kroah.com> + * + */ +#ifndef _CPQPHP_H +#define _CPQPHP_H + +#include "pci_hotplug.h" +#include <linux/interrupt.h> +#include <asm/io.h> /* for read? and write? functions */ +#include <linux/delay.h> /* for delays */ + +#if !defined(CONFIG_HOTPLUG_PCI_COMPAQ_MODULE) + #define MY_NAME "cpqphp.o" +#else + #define MY_NAME THIS_MODULE->name +#endif + +#define dbg(fmt, arg...) do { if (cpqhp_debug) printk(KERN_DEBUG "%s: " fmt , MY_NAME , ## arg); } while (0) +#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg) + + + +struct smbios_system_slot { + u8 type; + u8 length; + u16 handle; + u8 name_string_num; + u8 slot_type; + u8 slot_width; + u8 slot_current_usage; + u8 slot_length; + u16 slot_number; + u8 properties1; + u8 properties2; +} __attribute__ ((packed)); + +/* offsets to the smbios generic type based on the above structure layout */ +enum smbios_system_slot_offsets { + SMBIOS_SLOT_GENERIC_TYPE = offsetof(struct smbios_system_slot, type), + SMBIOS_SLOT_GENERIC_LENGTH = offsetof(struct smbios_system_slot, length), + SMBIOS_SLOT_GENERIC_HANDLE = offsetof(struct smbios_system_slot, handle), + SMBIOS_SLOT_NAME_STRING_NUM = offsetof(struct smbios_system_slot, name_string_num), + SMBIOS_SLOT_TYPE = offsetof(struct smbios_system_slot, slot_type), + SMBIOS_SLOT_WIDTH = offsetof(struct smbios_system_slot, slot_width), + SMBIOS_SLOT_CURRENT_USAGE = offsetof(struct smbios_system_slot, slot_current_usage), + SMBIOS_SLOT_LENGTH = offsetof(struct smbios_system_slot, slot_length), + SMBIOS_SLOT_NUMBER = offsetof(struct smbios_system_slot, slot_number), + SMBIOS_SLOT_PROPERTIES1 = offsetof(struct smbios_system_slot, properties1), + SMBIOS_SLOT_PROPERTIES2 = offsetof(struct smbios_system_slot, properties2), +}; + +struct smbios_generic { + u8 type; + u8 length; + u16 handle; +} __attribute__ ((packed)); + +/* offsets to the smbios generic type based on the above structure layout */ +enum smbios_generic_offsets { + SMBIOS_GENERIC_TYPE = offsetof(struct smbios_generic, type), + SMBIOS_GENERIC_LENGTH = offsetof(struct smbios_generic, length), + SMBIOS_GENERIC_HANDLE = offsetof(struct smbios_generic, handle), +}; + +struct smbios_entry_point { + char anchor[4]; + u8 ep_checksum; + u8 ep_length; + u8 major_version; + u8 minor_version; + u16 max_size_entry; + u8 ep_rev; + u8 reserved[5]; + char int_anchor[5]; + u8 int_checksum; + u16 st_length; + u32 st_address; + u16 number_of_entrys; + u8 bcd_rev; +} __attribute__ ((packed)); + +/* offsets to the smbios entry point based on the above structure layout */ +enum smbios_entry_point_offsets { + ANCHOR = offsetof(struct smbios_entry_point, anchor[0]), + EP_CHECKSUM = offsetof(struct smbios_entry_point, ep_checksum), + EP_LENGTH = offsetof(struct smbios_entry_point, ep_length), + MAJOR_VERSION = offsetof(struct smbios_entry_point, major_version), + MINOR_VERSION = offsetof(struct smbios_entry_point, minor_version), + MAX_SIZE_ENTRY = offsetof(struct smbios_entry_point, max_size_entry), + EP_REV = offsetof(struct smbios_entry_point, ep_rev), + INT_ANCHOR = offsetof(struct smbios_entry_point, int_anchor[0]), + INT_CHECKSUM = offsetof(struct smbios_entry_point, int_checksum), + ST_LENGTH = offsetof(struct smbios_entry_point, st_length), + ST_ADDRESS = offsetof(struct smbios_entry_point, st_address), + NUMBER_OF_ENTRYS = offsetof(struct smbios_entry_point, number_of_entrys), + BCD_REV = offsetof(struct smbios_entry_point, bcd_rev), +}; + +struct ctrl_reg { /* offset */ + u8 slot_RST; /* 0x00 */ + u8 slot_enable; /* 0x01 */ + u16 misc; /* 0x02 */ + u32 led_control; /* 0x04 */ + u32 int_input_clear; /* 0x08 */ + u32 int_mask; /* 0x0a */ + u8 reserved0; /* 0x10 */ + u8 reserved1; /* 0x11 */ + u8 reserved2; /* 0x12 */ + u8 gen_output_AB; /* 0x13 */ + u32 non_int_input; /* 0x14 */ + u32 reserved3; /* 0x18 */ + u32 reserved4; /* 0x1a */ + u32 reserved5; /* 0x20 */ + u8 reserved6; /* 0x24 */ + u8 reserved7; /* 0x25 */ + u16 reserved8; /* 0x26 */ + u8 slot_mask; /* 0x28 */ + u8 reserved9; /* 0x29 */ + u8 reserved10; /* 0x2a */ + u8 reserved11; /* 0x2b */ + u8 slot_SERR; /* 0x2c */ + u8 slot_power; /* 0x2d */ + u8 reserved12; /* 0x2e */ + u8 reserved13; /* 0x2f */ + u8 next_curr_freq; /* 0x30 */ + u8 reset_freq_mode; /* 0x31 */ +} __attribute__ ((packed)); + +/* offsets to the controller registers based on the above structure layout */ +enum ctrl_offsets { + SLOT_RST = offsetof(struct ctrl_reg, slot_RST), + SLOT_ENABLE = offsetof(struct ctrl_reg, slot_enable), + MISC = offsetof(struct ctrl_reg, misc), + LED_CONTROL = offsetof(struct ctrl_reg, led_control), + INT_INPUT_CLEAR = offsetof(struct ctrl_reg, int_input_clear), + INT_MASK = offsetof(struct ctrl_reg, int_mask), + CTRL_RESERVED0 = offsetof(struct ctrl_reg, reserved0), + CTRL_RESERVED1 = offsetof(struct ctrl_reg, reserved1), + CTRL_RESERVED2 = offsetof(struct ctrl_reg, reserved1), + GEN_OUTPUT_AB = offsetof(struct ctrl_reg, gen_output_AB), + NON_INT_INPUT = offsetof(struct ctrl_reg, non_int_input), + CTRL_RESERVED3 = offsetof(struct ctrl_reg, reserved3), + CTRL_RESERVED4 = offsetof(struct ctrl_reg, reserved4), + CTRL_RESERVED5 = offsetof(struct ctrl_reg, reserved5), + CTRL_RESERVED6 = offsetof(struct ctrl_reg, reserved6), + CTRL_RESERVED7 = offsetof(struct ctrl_reg, reserved7), + CTRL_RESERVED8 = offsetof(struct ctrl_reg, reserved8), + SLOT_MASK = offsetof(struct ctrl_reg, slot_mask), + CTRL_RESERVED9 = offsetof(struct ctrl_reg, reserved9), + CTRL_RESERVED10 = offsetof(struct ctrl_reg, reserved10), + CTRL_RESERVED11 = offsetof(struct ctrl_reg, reserved11), + SLOT_SERR = offsetof(struct ctrl_reg, slot_SERR), + SLOT_POWER = offsetof(struct ctrl_reg, slot_power), + NEXT_CURR_FREQ = offsetof(struct ctrl_reg, next_curr_freq), + RESET_FREQ_MODE = offsetof(struct ctrl_reg, reset_freq_mode), +}; + +struct hrt { + char sig0; + char sig1; + char sig2; + char sig3; + u16 unused_IRQ; + u16 PCIIRQ; + u8 number_of_entries; + u8 revision; + u16 reserved1; + u32 reserved2; +} __attribute__ ((packed)); + +/* offsets to the hotplug resource table registers based on the above structure layout */ +enum hrt_offsets { + SIG0 = offsetof(struct hrt, sig0), + SIG1 = offsetof(struct hrt, sig1), + SIG2 = offsetof(struct hrt, sig2), + SIG3 = offsetof(struct hrt, sig3), + UNUSED_IRQ = offsetof(struct hrt, unused_IRQ), + PCIIRQ = offsetof(struct hrt, PCIIRQ), + NUMBER_OF_ENTRIES = offsetof(struct hrt, number_of_entries), + REVISION = offsetof(struct hrt, revision), + HRT_RESERVED1 = offsetof(struct hrt, reserved1), + HRT_RESERVED2 = offsetof(struct hrt, reserved2), +}; + +struct slot_rt { + u8 dev_func; + u8 primary_bus; + u8 secondary_bus; + u8 max_bus; + u16 io_base; + u16 io_length; + u16 mem_base; + u16 mem_length; + u16 pre_mem_base; + u16 pre_mem_length; +} __attribute__ ((packed)); + +/* offsets to the hotplug slot resource table registers based on the above structure layout */ +enum slot_rt_offsets { + DEV_FUNC = offsetof(struct slot_rt, dev_func), + PRIMARY_BUS = offsetof(struct slot_rt, primary_bus), + SECONDARY_BUS = offsetof(struct slot_rt, secondary_bus), + MAX_BUS = offsetof(struct slot_rt, max_bus), + IO_BASE = offsetof(struct slot_rt, io_base), + IO_LENGTH = offsetof(struct slot_rt, io_length), + MEM_BASE = offsetof(struct slot_rt, mem_base), + MEM_LENGTH = offsetof(struct slot_rt, mem_length), + PRE_MEM_BASE = offsetof(struct slot_rt, pre_mem_base), + PRE_MEM_LENGTH = offsetof(struct slot_rt, pre_mem_length), +}; + +struct pci_func { + struct pci_func *next; + u8 bus; + u8 device; + u8 function; + u8 is_a_board; + u16 status; + u8 configured; + u8 switch_save; + u8 presence_save; + u32 base_length[0x06]; + u8 base_type[0x06]; + u16 reserved2; + u32 config_space[0x20]; + struct pci_resource *mem_head; + struct pci_resource *p_mem_head; + struct pci_resource *io_head; + struct pci_resource *bus_head; + struct timer_list *p_task_event; + struct pci_dev* pci_dev; +}; + +#define SLOT_MAGIC 0x67267321 +struct slot { + u32 magic; + struct slot *next; + u8 bus; + u8 device; + u8 number; + u8 is_a_board; + u8 configured; + u8 state; + u8 switch_save; + u8 presence_save; + u32 capabilities; + u16 reserved2; + struct timer_list task_event; + u8 hp_slot; + struct controller *ctrl; + void *p_sm_slot; + struct hotplug_slot *hotplug_slot; +}; + +struct pci_resource { + struct pci_resource * next; + u32 base; + u32 length; +}; + +struct event_info { + u32 event_type; + u8 hp_slot; +}; + +struct controller { + struct controller *next; + u32 ctrl_int_comp; + struct semaphore crit_sect; /* critical section semaphore */ + void *hpc_reg; /* cookie for our pci controller location */ + struct pci_resource *mem_head; + struct pci_resource *p_mem_head; + struct pci_resource *io_head; + struct pci_resource *bus_head; + struct pci_dev *pci_dev; + struct pci_bus *pci_bus; + struct event_info event_queue[10]; + struct slot *slot; + u8 next_event; + u8 interrupt; + u8 cfgspc_irq; + u8 bus; /* bus number for the pci hotplug controller */ + u8 rev; + u8 slot_device_offset; + u8 first_slot; + u8 add_support; + u8 push_flag; + enum pci_bus_speed speed; + enum pci_bus_speed speed_capability; + u8 push_button; /* 0 = no pushbutton, 1 = pushbutton present */ + u8 slot_switch_type; /* 0 = no switch, 1 = switch present */ + u8 defeature_PHP; /* 0 = PHP not supported, 1 = PHP supported */ + u8 alternate_base_address; /* 0 = not supported, 1 = supported */ + u8 pci_config_space; /* Index/data access to working registers 0 = not supported, 1 = supported */ + u8 pcix_speed_capability; /* PCI-X */ + u8 pcix_support; /* PCI-X */ + u16 vendor_id; + struct work_struct int_task_event; + wait_queue_head_t queue; /* sleep & wake process */ +}; + +struct irq_mapping { + u8 barber_pole; + u8 valid_INT; + u8 interrupt[4]; +}; + +struct resource_lists { + struct pci_resource *mem_head; + struct pci_resource *p_mem_head; + struct pci_resource *io_head; + struct pci_resource *bus_head; + struct irq_mapping *irqs; +}; + +#define ROM_PHY_ADDR 0x0F0000 +#define ROM_PHY_LEN 0x00ffff + +#define PCI_HPC_ID 0xA0F7 +#define PCI_SUB_HPC_ID 0xA2F7 +#define PCI_SUB_HPC_ID2 0xA2F8 +#define PCI_SUB_HPC_ID3 0xA2F9 +#define PCI_SUB_HPC_ID_INTC 0xA2FA +#define PCI_SUB_HPC_ID4 0xA2FD + +#define INT_BUTTON_IGNORE 0 +#define INT_PRESENCE_ON 1 +#define INT_PRESENCE_OFF 2 +#define INT_SWITCH_CLOSE 3 +#define INT_SWITCH_OPEN 4 +#define INT_POWER_FAULT 5 +#define INT_POWER_FAULT_CLEAR 6 +#define INT_BUTTON_PRESS 7 +#define INT_BUTTON_RELEASE 8 +#define INT_BUTTON_CANCEL 9 + +#define STATIC_STATE 0 +#define BLINKINGON_STATE 1 +#define BLINKINGOFF_STATE 2 +#define POWERON_STATE 3 +#define POWEROFF_STATE 4 + +#define PCISLOT_INTERLOCK_CLOSED 0x00000001 +#define PCISLOT_ADAPTER_PRESENT 0x00000002 +#define PCISLOT_POWERED 0x00000004 +#define PCISLOT_66_MHZ_OPERATION 0x00000008 +#define PCISLOT_64_BIT_OPERATION 0x00000010 +#define PCISLOT_REPLACE_SUPPORTED 0x00000020 +#define PCISLOT_ADD_SUPPORTED 0x00000040 +#define PCISLOT_INTERLOCK_SUPPORTED 0x00000080 +#define PCISLOT_66_MHZ_SUPPORTED 0x00000100 +#define PCISLOT_64_BIT_SUPPORTED 0x00000200 + + + +#define PCI_TO_PCI_BRIDGE_CLASS 0x00060400 + + +#define INTERLOCK_OPEN 0x00000002 +#define ADD_NOT_SUPPORTED 0x00000003 +#define CARD_FUNCTIONING 0x00000005 +#define ADAPTER_NOT_SAME 0x00000006 +#define NO_ADAPTER_PRESENT 0x00000009 +#define NOT_ENOUGH_RESOURCES 0x0000000B +#define DEVICE_TYPE_NOT_SUPPORTED 0x0000000C +#define POWER_FAILURE 0x0000000E + +#define REMOVE_NOT_SUPPORTED 0x00000003 + + +/* + * error Messages + */ +#define msg_initialization_err "Initialization failure, error=%d\n" +#define msg_HPC_rev_error "Unsupported revision of the PCI hot plug controller found.\n" +#define msg_HPC_non_compaq_or_intel "The PCI hot plug controller is not supported by this driver.\n" +#define msg_HPC_not_supported "this system is not supported by this version of cpqphpd. Upgrade to a newer version of cpqphpd\n" +#define msg_unable_to_save "unable to store PCI hot plug add resource information. This system must be rebooted before adding any PCI devices.\n" +#define msg_button_on "PCI slot #%d - powering on due to button press.\n" +#define msg_button_off "PCI slot #%d - powering off due to button press.\n" +#define msg_button_cancel "PCI slot #%d - action canceled due to button press.\n" +#define msg_button_ignore "PCI slot #%d - button press ignored. (action in progress...)\n" + + +/* sysfs functions for the hotplug controller info */ +extern void cpqhp_create_ctrl_files (struct controller *ctrl); + +/* controller functions */ +extern void cpqhp_pushbutton_thread (unsigned long event_pointer); +extern irqreturn_t cpqhp_ctrl_intr (int IRQ, void *data, struct pt_regs *regs); +extern int cpqhp_find_available_resources (struct controller *ctrl, void *rom_start); +extern int cpqhp_event_start_thread (void); +extern void cpqhp_event_stop_thread (void); +extern struct pci_func *cpqhp_slot_create (unsigned char busnumber); +extern struct pci_func *cpqhp_slot_find (unsigned char bus, unsigned char device, unsigned char index); +extern int cpqhp_process_SI (struct controller *ctrl, struct pci_func *func); +extern int cpqhp_process_SS (struct controller *ctrl, struct pci_func *func); +extern int cpqhp_hardware_test (struct controller *ctrl, int test_num); + +/* resource functions */ +extern int cpqhp_resource_sort_and_combine (struct pci_resource **head); + +/* pci functions */ +extern int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num); +extern int cpqhp_get_bus_dev (struct controller *ctrl, u8 *bus_num, u8 *dev_num, u8 slot); +extern int cpqhp_save_config (struct controller *ctrl, int busnumber, int is_hot_plug); +extern int cpqhp_save_base_addr_length (struct controller *ctrl, struct pci_func * func); +extern int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func); +extern int cpqhp_configure_board (struct controller *ctrl, struct pci_func * func); +extern int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot); +extern int cpqhp_valid_replace (struct controller *ctrl, struct pci_func * func); +extern void cpqhp_destroy_board_resources (struct pci_func * func); +extern int cpqhp_return_board_resources (struct pci_func * func, struct resource_lists * resources); +extern void cpqhp_destroy_resource_list (struct resource_lists * resources); +extern int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func); +extern int cpqhp_unconfigure_device (struct pci_func* func); +extern struct slot *cpqhp_find_slot (struct controller *ctrl, u8 device); + +/* Global variables */ +extern int cpqhp_debug; +extern struct controller *cpqhp_ctrl_list; +extern struct pci_func *cpqhp_slot_list[256]; + +/* these can be gotten rid of, but for debugging they are purty */ +extern u8 cpqhp_nic_irq; +extern u8 cpqhp_disk_irq; + + + +/* inline functions */ + + +/* Inline functions to check the sanity of a pointer that is passed to us */ +static inline int slot_paranoia_check (struct slot *slot, const char *function) +{ + if (!slot) { + dbg("%s - slot == NULL", function); + return -1; + } + if (slot->magic != SLOT_MAGIC) { + dbg("%s - bad magic number for slot", function); + return -1; + } + if (!slot->hotplug_slot) { + dbg("%s - slot->hotplug_slot == NULL!", function); + return -1; + } + return 0; +} + +static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function) +{ + struct slot *slot; + + if (!hotplug_slot) { + dbg("%s - hotplug_slot == NULL\n", function); + return NULL; + } + + slot = (struct slot *)hotplug_slot->private; + if (slot_paranoia_check (slot, function)) + return NULL; + return slot; +} + +/* + * return_resource + * + * Puts node back in the resource list pointed to by head + * + */ +static inline void return_resource (struct pci_resource **head, struct pci_resource *node) +{ + if (!node || !head) + return; + node->next = *head; + *head = node; +} + +static inline void set_SOGO (struct controller *ctrl) +{ + u16 misc; + + misc = readw(ctrl->hpc_reg + MISC); + misc = (misc | 0x0001) & 0xFFFB; + writew(misc, ctrl->hpc_reg + MISC); +} + + +static inline void amber_LED_on (struct controller *ctrl, u8 slot) +{ + u32 led_control; + + led_control = readl(ctrl->hpc_reg + LED_CONTROL); + led_control |= (0x01010000L << slot); + writel(led_control, ctrl->hpc_reg + LED_CONTROL); +} + + +static inline void amber_LED_off (struct controller *ctrl, u8 slot) +{ + u32 led_control; + + led_control = readl(ctrl->hpc_reg + LED_CONTROL); + led_control &= ~(0x01010000L << slot); + writel(led_control, ctrl->hpc_reg + LED_CONTROL); +} + + +static inline int read_amber_LED (struct controller *ctrl, u8 slot) +{ + u32 led_control; + + led_control = readl(ctrl->hpc_reg + LED_CONTROL); + led_control &= (0x01010000L << slot); + + return led_control ? 1 : 0; +} + + +static inline void green_LED_on (struct controller *ctrl, u8 slot) +{ + u32 led_control; + + led_control = readl(ctrl->hpc_reg + LED_CONTROL); + led_control |= 0x0101L << slot; + writel(led_control, ctrl->hpc_reg + LED_CONTROL); +} + +static inline void green_LED_off (struct controller *ctrl, u8 slot) +{ + u32 led_control; + + led_control = readl(ctrl->hpc_reg + LED_CONTROL); + led_control &= ~(0x0101L << slot); + writel(led_control, ctrl->hpc_reg + LED_CONTROL); +} + + +static inline void green_LED_blink (struct controller *ctrl, u8 slot) +{ + u32 led_control; + + led_control = readl(ctrl->hpc_reg + LED_CONTROL); + led_control &= ~(0x0101L << slot); + led_control |= (0x0001L << slot); + writel(led_control, ctrl->hpc_reg + LED_CONTROL); +} + + +static inline void slot_disable (struct controller *ctrl, u8 slot) +{ + u8 slot_enable; + + slot_enable = readb(ctrl->hpc_reg + SLOT_ENABLE); + slot_enable &= ~(0x01 << slot); + writeb(slot_enable, ctrl->hpc_reg + SLOT_ENABLE); +} + + +static inline void slot_enable (struct controller *ctrl, u8 slot) +{ + u8 slot_enable; + + slot_enable = readb(ctrl->hpc_reg + SLOT_ENABLE); + slot_enable |= (0x01 << slot); + writeb(slot_enable, ctrl->hpc_reg + SLOT_ENABLE); +} + + +static inline u8 is_slot_enabled (struct controller *ctrl, u8 slot) +{ + u8 slot_enable; + + slot_enable = readb(ctrl->hpc_reg + SLOT_ENABLE); + slot_enable &= (0x01 << slot); + return slot_enable ? 1 : 0; +} + + +static inline u8 read_slot_enable (struct controller *ctrl) +{ + return readb(ctrl->hpc_reg + SLOT_ENABLE); +} + + +/* + * get_controller_speed - find the current frequency/mode of controller. + * + * @ctrl: controller to get frequency/mode for. + * + * Returns controller speed. + * + */ +static inline u8 get_controller_speed (struct controller *ctrl) +{ + u8 curr_freq; + u16 misc; + + if (ctrl->pcix_support) { + curr_freq = readb(ctrl->hpc_reg + NEXT_CURR_FREQ); + if ((curr_freq & 0xB0) == 0xB0) + return PCI_SPEED_133MHz_PCIX; + if ((curr_freq & 0xA0) == 0xA0) + return PCI_SPEED_100MHz_PCIX; + if ((curr_freq & 0x90) == 0x90) + return PCI_SPEED_66MHz_PCIX; + if (curr_freq & 0x10) + return PCI_SPEED_66MHz; + + return PCI_SPEED_33MHz; + } + + misc = readw(ctrl->hpc_reg + MISC); + return (misc & 0x0800) ? PCI_SPEED_66MHz : PCI_SPEED_33MHz; +} + + +/* + * get_adapter_speed - find the max supported frequency/mode of adapter. + * + * @ctrl: hotplug controller. + * @hp_slot: hotplug slot where adapter is installed. + * + * Returns adapter speed. + * + */ +static inline u8 get_adapter_speed (struct controller *ctrl, u8 hp_slot) +{ + u32 temp_dword = readl(ctrl->hpc_reg + NON_INT_INPUT); + dbg("slot: %d, PCIXCAP: %8x\n", hp_slot, temp_dword); + if (ctrl->pcix_support) { + if (temp_dword & (0x10000 << hp_slot)) + return PCI_SPEED_133MHz_PCIX; + if (temp_dword & (0x100 << hp_slot)) + return PCI_SPEED_66MHz_PCIX; + } + + if (temp_dword & (0x01 << hp_slot)) + return PCI_SPEED_66MHz; + + return PCI_SPEED_33MHz; +} + +static inline void enable_slot_power (struct controller *ctrl, u8 slot) +{ + u8 slot_power; + + slot_power = readb(ctrl->hpc_reg + SLOT_POWER); + slot_power |= (0x01 << slot); + writeb(slot_power, ctrl->hpc_reg + SLOT_POWER); +} + +static inline void disable_slot_power (struct controller *ctrl, u8 slot) +{ + u8 slot_power; + + slot_power = readb(ctrl->hpc_reg + SLOT_POWER); + slot_power &= ~(0x01 << slot); + writeb(slot_power, ctrl->hpc_reg + SLOT_POWER); +} + + +static inline int cpq_get_attention_status (struct controller *ctrl, struct slot *slot) +{ + u8 hp_slot; + + if (slot == NULL) + return 1; + + hp_slot = slot->device - ctrl->slot_device_offset; + + return read_amber_LED (ctrl, hp_slot); +} + + +static inline int get_slot_enabled (struct controller *ctrl, struct slot *slot) +{ + u8 hp_slot; + + if (slot == NULL) + return 1; + + hp_slot = slot->device - ctrl->slot_device_offset; + + return is_slot_enabled (ctrl, hp_slot); +} + + +static inline int cpq_get_latch_status (struct controller *ctrl, struct slot *slot) +{ + u32 status; + u8 hp_slot; + + if (slot == NULL) + return 1; + + hp_slot = slot->device - ctrl->slot_device_offset; + dbg("%s: slot->device = %d, ctrl->slot_device_offset = %d \n", + __FUNCTION__, slot->device, ctrl->slot_device_offset); + + status = (readl(ctrl->hpc_reg + INT_INPUT_CLEAR) & (0x01L << hp_slot)); + + return(status == 0) ? 1 : 0; +} + + +static inline int get_presence_status (struct controller *ctrl, struct slot *slot) +{ + int presence_save = 0; + u8 hp_slot; + u32 tempdword; + + if (slot == NULL) + return 0; + + hp_slot = slot->device - ctrl->slot_device_offset; + + tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); + presence_save = (int) ((((~tempdword) >> 23) | ((~tempdword) >> 15)) >> hp_slot) & 0x02; + + return presence_save; +} + +#define SLOT_NAME_SIZE 10 + +static inline void make_slot_name (char *buffer, int buffer_size, struct slot *slot) +{ + snprintf (buffer, buffer_size, "%d", slot->number); +} + + +static inline int wait_for_ctrl_irq (struct controller *ctrl) +{ + DECLARE_WAITQUEUE(wait, current); + int retval = 0; + + dbg("%s - start\n", __FUNCTION__); + add_wait_queue(&ctrl->queue, &wait); + set_current_state(TASK_INTERRUPTIBLE); + /* Sleep for up to 1 second to wait for the LED to change. */ + schedule_timeout(1*HZ); + set_current_state(TASK_RUNNING); + remove_wait_queue(&ctrl->queue, &wait); + if (signal_pending(current)) + retval = -EINTR; + + dbg("%s - end\n", __FUNCTION__); + return retval; +} + + +/** + * set_controller_speed - set the frequency and/or mode of a specific + * controller segment. + * + * @ctrl: controller to change frequency/mode for. + * @adapter_speed: the speed of the adapter we want to match. + * @hp_slot: the slot number where the adapter is installed. + * + * Returns 0 if we successfully change frequency and/or mode to match the + * adapter speed. + * + */ +static inline u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_slot) +{ + struct slot *slot; + u8 reg; + u8 slot_power = readb(ctrl->hpc_reg + SLOT_POWER); + u16 reg16; + u32 leds = readl(ctrl->hpc_reg + LED_CONTROL); + + if (ctrl->speed == adapter_speed) + return 0; + + /* We don't allow freq/mode changes if we find another adapter running + * in another slot on this controller */ + for(slot = ctrl->slot; slot; slot = slot->next) { + if (slot->device == (hp_slot + ctrl->slot_device_offset)) + continue; + if (!slot->hotplug_slot && !slot->hotplug_slot->info) + continue; + if (slot->hotplug_slot->info->adapter_status == 0) + continue; + /* If another adapter is running on the same segment but at a + * lower speed/mode, we allow the new adapter to function at + * this rate if supported */ + if (ctrl->speed < adapter_speed) + return 0; + + return 1; + } + + /* If the controller doesn't support freq/mode changes and the + * controller is running at a higher mode, we bail */ + if ((ctrl->speed > adapter_speed) && (!ctrl->pcix_speed_capability)) + return 1; + + /* But we allow the adapter to run at a lower rate if possible */ + if ((ctrl->speed < adapter_speed) && (!ctrl->pcix_speed_capability)) + return 0; + + /* We try to set the max speed supported by both the adapter and + * controller */ + if (ctrl->speed_capability < adapter_speed) { + if (ctrl->speed == ctrl->speed_capability) + return 0; + adapter_speed = ctrl->speed_capability; + } + + writel(0x0L, ctrl->hpc_reg + LED_CONTROL); + writeb(0x00, ctrl->hpc_reg + SLOT_ENABLE); + + set_SOGO(ctrl); + wait_for_ctrl_irq(ctrl); + + if (adapter_speed != PCI_SPEED_133MHz_PCIX) + reg = 0xF5; + else + reg = 0xF4; + pci_write_config_byte(ctrl->pci_dev, 0x41, reg); + + reg16 = readw(ctrl->hpc_reg + NEXT_CURR_FREQ); + reg16 &= ~0x000F; + switch(adapter_speed) { + case(PCI_SPEED_133MHz_PCIX): + reg = 0x75; + reg16 |= 0xB; + break; + case(PCI_SPEED_100MHz_PCIX): + reg = 0x74; + reg16 |= 0xA; + break; + case(PCI_SPEED_66MHz_PCIX): + reg = 0x73; + reg16 |= 0x9; + break; + case(PCI_SPEED_66MHz): + reg = 0x73; + reg16 |= 0x1; + break; + default: /* 33MHz PCI 2.2 */ + reg = 0x71; + break; + + } + reg16 |= 0xB << 12; + writew(reg16, ctrl->hpc_reg + NEXT_CURR_FREQ); + + mdelay(5); + + /* Reenable interrupts */ + writel(0, ctrl->hpc_reg + INT_MASK); + + pci_write_config_byte(ctrl->pci_dev, 0x41, reg); + + /* Restart state machine */ + reg = ~0xF; + pci_read_config_byte(ctrl->pci_dev, 0x43, ®); + pci_write_config_byte(ctrl->pci_dev, 0x43, reg); + + /* Only if mode change...*/ + if (((ctrl->speed == PCI_SPEED_66MHz) && (adapter_speed == PCI_SPEED_66MHz_PCIX)) || + ((ctrl->speed == PCI_SPEED_66MHz_PCIX) && (adapter_speed == PCI_SPEED_66MHz))) + set_SOGO(ctrl); + + wait_for_ctrl_irq(ctrl); + mdelay(1100); + + /* Restore LED/Slot state */ + writel(leds, ctrl->hpc_reg + LED_CONTROL); + writeb(slot_power, ctrl->hpc_reg + SLOT_ENABLE); + + set_SOGO(ctrl); + wait_for_ctrl_irq(ctrl); + + ctrl->speed = adapter_speed; + slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); + + info("Successfully changed frequency/mode for adapter in slot %d\n", + slot->number); + return 0; +} + +#endif + diff -Nru a/drivers/pci/hotplug/cpqphp_core.c b/drivers/pci/hotplug/cpqphp_core.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pci/hotplug/cpqphp_core.c Mon Jun 9 23:16:05 2003 @@ -0,0 +1,1541 @@ +/* + * Compaq Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Send feedback to <greg@kroah.com> + * + * Jan 12, 2003 - Added 66/100/133MHz PCI-X support, + * Torben Mathiasen <torben.mathiasen@hp.com> + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/proc_fs.h> +#include <linux/miscdevice.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <linux/interrupt.h> + +#include <asm/uaccess.h> + +#include "cpqphp.h" +#include "cpqphp_nvram.h" +#include "../../../arch/i386/pci/pci.h" /* horrible hack showing how processor dependent we are... */ + + +/* Global variables */ +int cpqhp_debug; +struct controller *cpqhp_ctrl_list; /* = NULL */ +struct pci_func *cpqhp_slot_list[256]; + +/* local variables */ +static void *smbios_table; +static void *smbios_start; +static void *cpqhp_rom_start; +static u8 power_mode; +static int debug; + +#define DRIVER_VERSION "0.9.7" +#define DRIVER_AUTHOR "Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>" +#define DRIVER_DESC "Compaq Hot Plug PCI Controller Driver" + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); + +MODULE_PARM(power_mode, "b"); +MODULE_PARM_DESC(power_mode, "Power mode enabled or not"); + +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); + +#define CPQHPC_MODULE_MINOR 208 + +static int one_time_init (void); +static int set_attention_status (struct hotplug_slot *slot, u8 value); +static int process_SI (struct hotplug_slot *slot); +static int process_SS (struct hotplug_slot *slot); +static int hardware_test (struct hotplug_slot *slot, u32 value); +static int get_power_status (struct hotplug_slot *slot, u8 *value); +static int get_attention_status (struct hotplug_slot *slot, u8 *value); +static int get_latch_status (struct hotplug_slot *slot, u8 *value); +static int get_adapter_status (struct hotplug_slot *slot, u8 *value); +static int get_max_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); +static int get_cur_bus_speed (struct hotplug_slot *slot, enum pci_bus_speed *value); + +static struct hotplug_slot_ops cpqphp_hotplug_slot_ops = { + .owner = THIS_MODULE, + .set_attention_status = set_attention_status, + .enable_slot = process_SI, + .disable_slot = process_SS, + .hardware_test = hardware_test, + .get_power_status = get_power_status, + .get_attention_status = get_attention_status, + .get_latch_status = get_latch_status, + .get_adapter_status = get_adapter_status, + .get_max_bus_speed = get_max_bus_speed, + .get_cur_bus_speed = get_cur_bus_speed, +}; + + +static inline int is_slot64bit (struct slot *slot) +{ + if (!slot || !slot->p_sm_slot) + return 0; + + if (readb(slot->p_sm_slot + SMBIOS_SLOT_WIDTH) == 0x06) + return 1; + + return 0; +} + +static inline int is_slot66mhz (struct slot *slot) +{ + if (!slot || !slot->p_sm_slot) + return 0; + + if (readb(slot->p_sm_slot + SMBIOS_SLOT_TYPE) == 0x0E) + return 1; + + return 0; +} + +/** + * detect_SMBIOS_pointer - find the system Management BIOS Table in the specified region of memory. + * + * @begin: begin pointer for region to be scanned. + * @end: end pointer for region to be scanned. + * + * Returns pointer to the head of the SMBIOS tables (or NULL) + * + */ +static void * detect_SMBIOS_pointer(void *begin, void *end) +{ + void *fp; + void *endp; + u8 temp1, temp2, temp3, temp4; + int status = 0; + + endp = (end - sizeof(u32) + 1); + + for (fp = begin; fp <= endp; fp += 16) { + temp1 = readb(fp); + temp2 = readb(fp+1); + temp3 = readb(fp+2); + temp4 = readb(fp+3); + if (temp1 == '_' && + temp2 == 'S' && + temp3 == 'M' && + temp4 == '_') { + status = 1; + break; + } + } + + if (!status) + fp = NULL; + + dbg("Discovered SMBIOS Entry point at %p\n", fp); + + return fp; +} + +/** + * init_SERR - Initializes the per slot SERR generation. + * + * For unexpected switch opens + * + */ +static int init_SERR(struct controller * ctrl) +{ + u32 tempdword; + u32 number_of_slots; + u8 physical_slot; + + if (!ctrl) + return 1; + + tempdword = ctrl->first_slot; + + number_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F; + // Loop through slots + while (number_of_slots) { + physical_slot = tempdword; + writeb(0, ctrl->hpc_reg + SLOT_SERR); + tempdword++; + number_of_slots--; + } + + return 0; +} + + +/* nice debugging output */ +static int pci_print_IRQ_route (void) +{ + struct irq_routing_table *routing_table; + int len; + int loop; + + u8 tbus, tdevice, tslot; + + routing_table = pcibios_get_irq_routing_table(); + if (routing_table == NULL) { + err("No BIOS Routing Table??? Not good\n"); + return -ENOMEM; + } + + len = (routing_table->size - sizeof(struct irq_routing_table)) / sizeof(struct irq_info); + // Make sure I got at least one entry + if (len == 0) { + kfree(routing_table); + return -1; + } + + dbg("bus dev func slot\n"); + + for (loop = 0; loop < len; ++loop) { + tbus = routing_table->slots[loop].bus; + tdevice = routing_table->slots[loop].devfn; + tslot = routing_table->slots[loop].slot; + dbg("%d %d %d %d\n", tbus, tdevice >> 3, tdevice & 0x7, tslot); + + } + kfree(routing_table); + return 0; +} + + +/* + * get_subsequent_smbios_entry + * + * Gets the first entry if previous == NULL + * Otherwise, returns the next entry + * Uses global SMBIOS Table pointer + * + * @curr: %NULL or pointer to previously returned structure + * + * returns a pointer to an SMBIOS structure or NULL if none found + */ +static void * get_subsequent_smbios_entry(void *smbios_start, void *smbios_table, void *curr) +{ + u8 bail = 0; + u8 previous_byte = 1; + void *p_temp; + void *p_max; + + if (!smbios_table || !curr) + return(NULL); + + // set p_max to the end of the table + p_max = smbios_start + readw(smbios_table + ST_LENGTH); + + p_temp = curr; + p_temp += readb(curr + SMBIOS_GENERIC_LENGTH); + + while ((p_temp < p_max) && !bail) { + // Look for the double NULL terminator + // The first condition is the previous byte and the second is the curr + if (!previous_byte && !(readb(p_temp))) { + bail = 1; + } + + previous_byte = readb(p_temp); + p_temp++; + } + + if (p_temp < p_max) { + return p_temp; + } else { + return NULL; + } +} + + +/** + * get_SMBIOS_entry + * + * @type:SMBIOS structure type to be returned + * @previous: %NULL or pointer to previously returned structure + * + * Gets the first entry of the specified type if previous == NULL + * Otherwise, returns the next entry of the given type. + * Uses global SMBIOS Table pointer + * Uses get_subsequent_smbios_entry + * + * returns a pointer to an SMBIOS structure or %NULL if none found + */ +static void *get_SMBIOS_entry (void *smbios_start, void *smbios_table, u8 type, void * previous) +{ + if (!smbios_table) + return NULL; + + if (!previous) { + previous = smbios_start; + } else { + previous = get_subsequent_smbios_entry(smbios_start, smbios_table, previous); + } + + while (previous) { + if (readb(previous + SMBIOS_GENERIC_TYPE) != type) { + previous = get_subsequent_smbios_entry(smbios_start, smbios_table, previous); + } else { + break; + } + } + + return previous; +} + + +static int ctrl_slot_setup (struct controller * ctrl, void *smbios_start, void *smbios_table) +{ + struct slot *new_slot; + u8 number_of_slots; + u8 slot_device; + u8 slot_number; + u8 ctrl_slot; + u32 tempdword; + void *slot_entry= NULL; + int result; + + dbg("%s\n", __FUNCTION__); + + tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); + + number_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F; + slot_device = readb(ctrl->hpc_reg + SLOT_MASK) >> 4; + slot_number = ctrl->first_slot; + + while (number_of_slots) { + new_slot = (struct slot *) kmalloc(sizeof(struct slot), GFP_KERNEL); + if (!new_slot) + return -ENOMEM; + + memset(new_slot, 0, sizeof(struct slot)); + new_slot->hotplug_slot = kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL); + if (!new_slot->hotplug_slot) { + kfree (new_slot); + return -ENOMEM; + } + memset(new_slot->hotplug_slot, 0, sizeof (struct hotplug_slot)); + + new_slot->hotplug_slot->info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); + if (!new_slot->hotplug_slot->info) { + kfree (new_slot->hotplug_slot); + kfree (new_slot); + return -ENOMEM; + } + memset(new_slot->hotplug_slot->info, 0, sizeof (struct hotplug_slot_info)); + new_slot->hotplug_slot->name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL); + if (!new_slot->hotplug_slot->name) { + kfree (new_slot->hotplug_slot->info); + kfree (new_slot->hotplug_slot); + kfree (new_slot); + return -ENOMEM; + } + + new_slot->magic = SLOT_MAGIC; + new_slot->ctrl = ctrl; + new_slot->bus = ctrl->bus; + new_slot->device = slot_device; + new_slot->number = slot_number; + dbg("slot->number = %d\n",new_slot->number); + + slot_entry = get_SMBIOS_entry(smbios_start, smbios_table, 9, slot_entry); + + while (slot_entry && (readw(slot_entry + SMBIOS_SLOT_NUMBER) != new_slot->number)) { + slot_entry = get_SMBIOS_entry(smbios_start, smbios_table, 9, slot_entry); + } + + new_slot->p_sm_slot = slot_entry; + + init_timer(&new_slot->task_event); + new_slot->task_event.expires = jiffies + 5 * HZ; + new_slot->task_event.function = cpqhp_pushbutton_thread; + + //FIXME: these capabilities aren't used but if they are + // they need to be correctly implemented + new_slot->capabilities |= PCISLOT_REPLACE_SUPPORTED; + new_slot->capabilities |= PCISLOT_INTERLOCK_SUPPORTED; + + if (is_slot64bit(new_slot)) + new_slot->capabilities |= PCISLOT_64_BIT_SUPPORTED; + if (is_slot66mhz(new_slot)) + new_slot->capabilities |= PCISLOT_66_MHZ_SUPPORTED; + if (ctrl->speed == PCI_SPEED_66MHz) + new_slot->capabilities |= PCISLOT_66_MHZ_OPERATION; + + ctrl_slot = slot_device - (readb(ctrl->hpc_reg + SLOT_MASK) >> 4); + + // Check presence + new_slot->capabilities |= ((((~tempdword) >> 23) | ((~tempdword) >> 15)) >> ctrl_slot) & 0x02; + // Check the switch state + new_slot->capabilities |= ((~tempdword & 0xFF) >> ctrl_slot) & 0x01; + // Check the slot enable + new_slot->capabilities |= ((read_slot_enable(ctrl) << 2) >> ctrl_slot) & 0x04; + + /* register this slot with the hotplug pci core */ + new_slot->hotplug_slot->private = new_slot; + make_slot_name (new_slot->hotplug_slot->name, SLOT_NAME_SIZE, new_slot); + new_slot->hotplug_slot->ops = &cpqphp_hotplug_slot_ops; + + new_slot->hotplug_slot->info->power_status = get_slot_enabled(ctrl, new_slot); + new_slot->hotplug_slot->info->attention_status = cpq_get_attention_status(ctrl, new_slot); + new_slot->hotplug_slot->info->latch_status = cpq_get_latch_status(ctrl, new_slot); + new_slot->hotplug_slot->info->adapter_status = get_presence_status(ctrl, new_slot); + + dbg ("registering bus %d, dev %d, number %d, ctrl->slot_device_offset %d, slot %d\n", + new_slot->bus, new_slot->device, new_slot->number, ctrl->slot_device_offset, slot_number); + result = pci_hp_register (new_slot->hotplug_slot); + if (result) { + err ("pci_hp_register failed with error %d\n", result); + kfree (new_slot->hotplug_slot->info); + kfree (new_slot->hotplug_slot->name); + kfree (new_slot->hotplug_slot); + kfree (new_slot); + return result; + } + + new_slot->next = ctrl->slot; + ctrl->slot = new_slot; + + number_of_slots--; + slot_device++; + slot_number++; + } + + return(0); +} + + +static int ctrl_slot_cleanup (struct controller * ctrl) +{ + struct slot *old_slot, *next_slot; + + old_slot = ctrl->slot; + ctrl->slot = NULL; + + while (old_slot) { + next_slot = old_slot->next; + pci_hp_deregister (old_slot->hotplug_slot); + kfree(old_slot->hotplug_slot->info); + kfree(old_slot->hotplug_slot->name); + kfree(old_slot->hotplug_slot); + kfree(old_slot); + old_slot = next_slot; + } + + //Free IRQ associated with hot plug device + free_irq(ctrl->interrupt, ctrl); + //Unmap the memory + iounmap(ctrl->hpc_reg); + //Finally reclaim PCI mem + release_mem_region(pci_resource_start(ctrl->pci_dev, 0), + pci_resource_len(ctrl->pci_dev, 0)); + + return(0); +} + + +//============================================================================ +// function: get_slot_mapping +// +// Description: Attempts to determine a logical slot mapping for a PCI +// device. Won't work for more than one PCI-PCI bridge +// in a slot. +// +// Input: u8 bus_num - bus number of PCI device +// u8 dev_num - device number of PCI device +// u8 *slot - Pointer to u8 where slot number will +// be returned +// +// Output: SUCCESS or FAILURE +//============================================================================= +static int get_slot_mapping (struct pci_bus *bus, u8 bus_num, u8 dev_num, u8 *slot) +{ + struct irq_routing_table *PCIIRQRoutingInfoLength; + u32 work; + long len; + long loop; + + u8 tbus, tdevice, tslot, bridgeSlot; + + dbg("%s: %p, %d, %d, %p\n", __FUNCTION__, bus, bus_num, dev_num, slot); + + bridgeSlot = 0xFF; + + PCIIRQRoutingInfoLength = pcibios_get_irq_routing_table(); + if (!PCIIRQRoutingInfoLength) + return -1; + + len = (PCIIRQRoutingInfoLength->size - + sizeof(struct irq_routing_table)) / sizeof(struct irq_info); + // Make sure I got at least one entry + if (len == 0) { + if (PCIIRQRoutingInfoLength != NULL) kfree(PCIIRQRoutingInfoLength ); + return -1; + } + + for (loop = 0; loop < len; ++loop) { + tbus = PCIIRQRoutingInfoLength->slots[loop].bus; + tdevice = PCIIRQRoutingInfoLength->slots[loop].devfn >> 3; + tslot = PCIIRQRoutingInfoLength->slots[loop].slot; + + if ((tbus == bus_num) && (tdevice == dev_num)) { + *slot = tslot; + + if (PCIIRQRoutingInfoLength != NULL) + kfree(PCIIRQRoutingInfoLength); + return 0; + } else { + // Didn't get a match on the target PCI device. Check if the + // current IRQ table entry is a PCI-to-PCI bridge device. If so, + // and it's secondary bus matches the bus number for the target + // device, I need to save the bridge's slot number. If I can't + // find an entry for the target device, I will have to assume it's + // on the other side of the bridge, and assign it the bridge's slot. + bus->number = tbus; + pci_bus_read_config_dword (bus, PCI_DEVFN(tdevice, 0), PCI_REVISION_ID, &work); + + if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) { + pci_bus_read_config_dword (bus, PCI_DEVFN(tdevice, 0), PCI_PRIMARY_BUS, &work); + // See if bridge's secondary bus matches target bus. + if (((work >> 8) & 0x000000FF) == (long) bus_num) { + bridgeSlot = tslot; + } + } + } + + } + + // If we got here, we didn't find an entry in the IRQ mapping table + // for the target PCI device. If we did determine that the target + // device is on the other side of a PCI-to-PCI bridge, return the + // slot number for the bridge. + if (bridgeSlot != 0xFF) { + *slot = bridgeSlot; + if (PCIIRQRoutingInfoLength != NULL) kfree(PCIIRQRoutingInfoLength ); + return 0; + } + if (PCIIRQRoutingInfoLength != NULL) kfree(PCIIRQRoutingInfoLength ); + // Couldn't find an entry in the routing table for this PCI device + return -1; +} + + +/** + * cpqhp_set_attention_status - Turns the Amber LED for a slot on or off + * + */ +static int cpqhp_set_attention_status (struct controller *ctrl, struct pci_func *func, u32 status) +{ + u8 hp_slot; + + hp_slot = func->device - ctrl->slot_device_offset; + + if (func == NULL) + return(1); + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + if (status == 1) { + amber_LED_on (ctrl, hp_slot); + } else if (status == 0) { + amber_LED_off (ctrl, hp_slot); + } else { + // Done with exclusive hardware access + up(&ctrl->crit_sect); + return(1); + } + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + return(0); +} + + +/** + * set_attention_status - Turns the Amber LED for a slot on or off + * + */ +static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status) +{ + struct pci_func *slot_func; + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + u8 bus; + u8 devfn; + u8 device; + u8 function; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1) + return -ENODEV; + + device = devfn >> 3; + function = devfn & 0x7; + dbg("bus, dev, fn = %d, %d, %d\n", bus, device, function); + + slot_func = cpqhp_slot_find(bus, device, function); + if (!slot_func) { + return -ENODEV; + } + + return cpqhp_set_attention_status(ctrl, slot_func, status); +} + + +static int process_SI (struct hotplug_slot *hotplug_slot) +{ + struct pci_func *slot_func; + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + u8 bus; + u8 devfn; + u8 device; + u8 function; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1) + return -ENODEV; + + device = devfn >> 3; + function = devfn & 0x7; + dbg("bus, dev, fn = %d, %d, %d\n", bus, device, function); + + slot_func = cpqhp_slot_find(bus, device, function); + if (!slot_func) { + return -ENODEV; + } + + slot_func->bus = bus; + slot_func->device = device; + slot_func->function = function; + slot_func->configured = 0; + dbg("board_added(%p, %p)\n", slot_func, ctrl); + return cpqhp_process_SI(ctrl, slot_func); +} + + +static int process_SS (struct hotplug_slot *hotplug_slot) +{ + struct pci_func *slot_func; + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + u8 bus; + u8 devfn; + u8 device; + u8 function; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + if (cpqhp_get_bus_dev(ctrl, &bus, &devfn, slot->number) == -1) + return -ENODEV; + + device = devfn >> 3; + function = devfn & 0x7; + dbg("bus, dev, fn = %d, %d, %d\n", bus, device, function); + + slot_func = cpqhp_slot_find(bus, device, function); + if (!slot_func) { + return -ENODEV; + } + + dbg("In power_down_board, slot_func = %p, ctrl = %p\n", slot_func, ctrl); + return cpqhp_process_SS(ctrl, slot_func); +} + + +static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + if (slot == NULL) + return -ENODEV; + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + return cpqhp_hardware_test (ctrl, value); +} + + +static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + *value = get_slot_enabled(ctrl, slot); + return 0; +} + +static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + *value = cpq_get_attention_status(ctrl, slot); + return 0; +} + +static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + *value = cpq_get_latch_status (ctrl, slot); + + return 0; +} + +static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + *value = get_presence_status (ctrl, slot); + + return 0; +} + +static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + *value = ctrl->speed_capability; + + return 0; +} + +static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + struct controller *ctrl; + + if (slot == NULL) + return -ENODEV; + + dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + ctrl = slot->ctrl; + if (ctrl == NULL) + return -ENODEV; + + *value = ctrl->speed; + + return 0; +} + +static int cpqhpc_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +{ + u8 num_of_slots = 0; + u8 hp_slot = 0; + u8 device; + u8 rev; + u8 bus_cap; + u16 temp_word; + u16 vendor_id; + u16 subsystem_vid; + u16 subsystem_deviceid; + u32 rc; + struct controller *ctrl; + struct pci_func *func; + + // Need to read VID early b/c it's used to differentiate CPQ and INTC discovery + rc = pci_read_config_word(pdev, PCI_VENDOR_ID, &vendor_id); + if (rc || ((vendor_id != PCI_VENDOR_ID_COMPAQ) && (vendor_id != PCI_VENDOR_ID_INTEL))) { + err(msg_HPC_non_compaq_or_intel); + return -ENODEV; + } + dbg("Vendor ID: %x\n", vendor_id); + + rc = pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); + dbg("revision: %d\n", rev); + if (rc || ((vendor_id == PCI_VENDOR_ID_COMPAQ) && (!rev))) { + err(msg_HPC_rev_error); + return -ENODEV; + } + + /* Check for the proper subsytem ID's + * Intel uses a different SSID programming model than Compaq. + * For Intel, each SSID bit identifies a PHP capability. + * Also Intel HPC's may have RID=0. + */ + if ((rev > 2) || (vendor_id == PCI_VENDOR_ID_INTEL)) { + // TODO: This code can be made to support non-Compaq or Intel subsystem IDs + rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vid); + if (rc) { + err("%s : pci_read_config_word failed\n", __FUNCTION__); + return rc; + } + dbg("Subsystem Vendor ID: %x\n", subsystem_vid); + if ((subsystem_vid != PCI_VENDOR_ID_COMPAQ) && (subsystem_vid != PCI_VENDOR_ID_INTEL)) { + err(msg_HPC_non_compaq_or_intel); + return -ENODEV; + } + + ctrl = (struct controller *) kmalloc(sizeof(struct controller), GFP_KERNEL); + if (!ctrl) { + err("%s : out of memory\n", __FUNCTION__); + return -ENOMEM; + } + memset(ctrl, 0, sizeof(struct controller)); + + rc = pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &subsystem_deviceid); + if (rc) { + err("%s : pci_read_config_word failed\n", __FUNCTION__); + goto err_free_ctrl; + } + + info("Hot Plug Subsystem Device ID: %x\n", subsystem_deviceid); + + /* Set Vendor ID, so it can be accessed later from other functions */ + ctrl->vendor_id = vendor_id; + + switch (subsystem_vid) { + case PCI_VENDOR_ID_COMPAQ: + if (rev >= 0x13) { /* CIOBX */ + ctrl->push_flag = 1; + ctrl->slot_switch_type = 1; // Switch is present + ctrl->push_button = 1; // Pushbutton is present + ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported + ctrl->defeature_PHP = 1; // PHP is supported + ctrl->pcix_support = 1; // PCI-X supported + ctrl->pcix_speed_capability = 1; + pci_read_config_byte(pdev, 0x41, &bus_cap); + if (bus_cap & 0x80) { + dbg("bus max supports 133MHz PCI-X\n"); + ctrl->speed_capability = PCI_SPEED_133MHz_PCIX; + break; + } + if (bus_cap & 0x40) { + dbg("bus max supports 100MHz PCI-X\n"); + ctrl->speed_capability = PCI_SPEED_100MHz_PCIX; + break; + } + if (bus_cap & 20) { + dbg("bus max supports 66MHz PCI-X\n"); + ctrl->speed_capability = PCI_SPEED_66MHz_PCIX; + break; + } + if (bus_cap & 10) { + dbg("bus max supports 66MHz PCI\n"); + ctrl->speed_capability = PCI_SPEED_66MHz; + break; + } + + break; + } + + switch (subsystem_deviceid) { + case PCI_SUB_HPC_ID: + /* Original 6500/7000 implementation */ + ctrl->slot_switch_type = 1; // Switch is present + ctrl->speed_capability = PCI_SPEED_33MHz; + ctrl->push_button = 0; // No pushbutton + ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported + ctrl->defeature_PHP = 1; // PHP is supported + ctrl->pcix_support = 0; // PCI-X not supported + ctrl->pcix_speed_capability = 0; // N/A since PCI-X not supported + break; + case PCI_SUB_HPC_ID2: + /* First Pushbutton implementation */ + ctrl->push_flag = 1; + ctrl->slot_switch_type = 1; // Switch is present + ctrl->speed_capability = PCI_SPEED_33MHz; + ctrl->push_button = 1; // Pushbutton is present + ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported + ctrl->defeature_PHP = 1; // PHP is supported + ctrl->pcix_support = 0; // PCI-X not supported + ctrl->pcix_speed_capability = 0; // N/A since PCI-X not supported + break; + case PCI_SUB_HPC_ID_INTC: + /* Third party (6500/7000) */ + ctrl->slot_switch_type = 1; // Switch is present + ctrl->speed_capability = PCI_SPEED_33MHz; + ctrl->push_button = 0; // No pushbutton + ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported + ctrl->defeature_PHP = 1; // PHP is supported + ctrl->pcix_support = 0; // PCI-X not supported + ctrl->pcix_speed_capability = 0; // N/A since PCI-X not supported + break; + case PCI_SUB_HPC_ID3: + /* First 66 Mhz implementation */ + ctrl->push_flag = 1; + ctrl->slot_switch_type = 1; // Switch is present + ctrl->speed_capability = PCI_SPEED_66MHz; + ctrl->push_button = 1; // Pushbutton is present + ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported + ctrl->defeature_PHP = 1; // PHP is supported + ctrl->pcix_support = 0; // PCI-X not supported + ctrl->pcix_speed_capability = 0; // N/A since PCI-X not supported + break; + case PCI_SUB_HPC_ID4: + /* First PCI-X implementation, 100MHz */ + ctrl->push_flag = 1; + ctrl->slot_switch_type = 1; // Switch is present + ctrl->speed_capability = PCI_SPEED_100MHz_PCIX; + ctrl->push_button = 1; // Pushbutton is present + ctrl->pci_config_space = 1; // Index/data access to working registers 0 = not supported, 1 = supported + ctrl->defeature_PHP = 1; // PHP is supported + ctrl->pcix_support = 1; // PCI-X supported + ctrl->pcix_speed_capability = 0; + break; + default: + err(msg_HPC_not_supported); + rc = -ENODEV; + goto err_free_ctrl; + } + break; + + case PCI_VENDOR_ID_INTEL: + /* Check for speed capability (0=33, 1=66) */ + if (subsystem_deviceid & 0x0001) { + ctrl->speed_capability = PCI_SPEED_66MHz; + } else { + ctrl->speed_capability = PCI_SPEED_33MHz; + } + + /* Check for push button */ + if (subsystem_deviceid & 0x0002) { + /* no push button */ + ctrl->push_button = 0; + } else { + /* push button supported */ + ctrl->push_button = 1; + } + + /* Check for slot switch type (0=mechanical, 1=not mechanical) */ + if (subsystem_deviceid & 0x0004) { + /* no switch */ + ctrl->slot_switch_type = 0; + } else { + /* switch */ + ctrl->slot_switch_type = 1; + } + + /* PHP Status (0=De-feature PHP, 1=Normal operation) */ + if (subsystem_deviceid & 0x0008) { + ctrl->defeature_PHP = 1; // PHP supported + } else { + ctrl->defeature_PHP = 0; // PHP not supported + } + + /* Alternate Base Address Register Interface (0=not supported, 1=supported) */ + if (subsystem_deviceid & 0x0010) { + ctrl->alternate_base_address = 1; // supported + } else { + ctrl->alternate_base_address = 0; // not supported + } + + /* PCI Config Space Index (0=not supported, 1=supported) */ + if (subsystem_deviceid & 0x0020) { + ctrl->pci_config_space = 1; // supported + } else { + ctrl->pci_config_space = 0; // not supported + } + + /* PCI-X support */ + if (subsystem_deviceid & 0x0080) { + /* PCI-X capable */ + ctrl->pcix_support = 1; + /* Frequency of operation in PCI-X mode */ + if (subsystem_deviceid & 0x0040) { + /* 133MHz PCI-X if bit 7 is 1 */ + ctrl->pcix_speed_capability = 1; + } else { + /* 100MHz PCI-X if bit 7 is 1 and bit 0 is 0, */ + /* 66MHz PCI-X if bit 7 is 1 and bit 0 is 1 */ + ctrl->pcix_speed_capability = 0; + } + } else { + /* Conventional PCI */ + ctrl->pcix_support = 0; + ctrl->pcix_speed_capability = 0; + } + break; + + default: + err(msg_HPC_not_supported); + rc = -ENODEV; + goto err_free_ctrl; + } + + } else { + err(msg_HPC_not_supported); + return -ENODEV; + } + + // Tell the user that we found one. + info("Initializing the PCI hot plug controller residing on PCI bus %d\n", pdev->bus->number); + + dbg ("Hotplug controller capabilities:\n"); + dbg (" speed_capability %d\n", ctrl->speed_capability); + dbg (" slot_switch_type %s\n", ctrl->slot_switch_type == 0 ? "no switch" : "switch present"); + dbg (" defeature_PHP %s\n", ctrl->defeature_PHP == 0 ? "PHP not supported" : "PHP supported"); + dbg (" alternate_base_address %s\n", ctrl->alternate_base_address == 0 ? "not supported" : "supported"); + dbg (" pci_config_space %s\n", ctrl->pci_config_space == 0 ? "not supported" : "supported"); + dbg (" pcix_speed_capability %s\n", ctrl->pcix_speed_capability == 0 ? "not supported" : "supported"); + dbg (" pcix_support %s\n", ctrl->pcix_support == 0 ? "not supported" : "supported"); + + ctrl->pci_dev = pdev; + pci_set_drvdata(pdev, ctrl); + + /* make our own copy of the pci bus structure, as we like tweaking it a lot */ + ctrl->pci_bus = kmalloc (sizeof (*ctrl->pci_bus), GFP_KERNEL); + if (!ctrl->pci_bus) { + err("out of memory\n"); + rc = -ENOMEM; + goto err_free_ctrl; + } + memcpy (ctrl->pci_bus, pdev->bus, sizeof (*ctrl->pci_bus)); + + ctrl->bus = pdev->bus->number; + ctrl->rev = rev; + dbg("bus device function rev: %d %d %d %d\n", ctrl->bus, + PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), ctrl->rev); + + init_MUTEX(&ctrl->crit_sect); + init_waitqueue_head(&ctrl->queue); + + /* initialize our threads if they haven't already been started up */ + rc = one_time_init(); + if (rc) { + goto err_free_bus; + } + + dbg("pdev = %p\n", pdev); + dbg("pci resource start %lx\n", pci_resource_start(pdev, 0)); + dbg("pci resource len %lx\n", pci_resource_len(pdev, 0)); + + if (!request_mem_region(pci_resource_start(pdev, 0), + pci_resource_len(pdev, 0), MY_NAME)) { + err("cannot reserve MMIO region\n"); + rc = -ENOMEM; + goto err_free_bus; + } + + ctrl->hpc_reg = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); + if (!ctrl->hpc_reg) { + err("cannot remap MMIO region %lx @ %lx\n", pci_resource_len(pdev, 0), pci_resource_start(pdev, 0)); + rc = -ENODEV; + goto err_free_mem_region; + } + + // Check for 66Mhz operation + ctrl->speed = get_controller_speed(ctrl); + + + //************************************************** + // + // Save configuration headers for this and + // subordinate PCI buses + // + //************************************************** + + // find the physical slot number of the first hot plug slot + + // Get slot won't work for devices behind bridges, but + // in this case it will always be called for the "base" + // bus/dev/func of a slot. + // CS: this is leveraging the PCIIRQ routing code from the kernel (pci-pc.c: get_irq_routing_table) + rc = get_slot_mapping(ctrl->pci_bus, pdev->bus->number, (readb(ctrl->hpc_reg + SLOT_MASK) >> 4), &(ctrl->first_slot)); + dbg("get_slot_mapping: first_slot = %d, returned = %d\n", ctrl->first_slot, rc); + if (rc) { + err(msg_initialization_err, rc); + goto err_iounmap; + } + + // Store PCI Config Space for all devices on this bus + rc = cpqhp_save_config(ctrl, ctrl->bus, readb(ctrl->hpc_reg + SLOT_MASK)); + if (rc) { + err("%s: unable to save PCI configuration data, error %d\n", __FUNCTION__, rc); + goto err_iounmap; + } + + /* + * Get IO, memory, and IRQ resources for new devices + */ + // The next line is required for cpqhp_find_available_resources + ctrl->interrupt = pdev->irq; + + ctrl->cfgspc_irq = 0; + pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &ctrl->cfgspc_irq); + + rc = cpqhp_find_available_resources(ctrl, cpqhp_rom_start); + ctrl->add_support = !rc; + if (rc) { + dbg("cpqhp_find_available_resources = 0x%x\n", rc); + err("unable to locate PCI configuration resources for hot plug add.\n"); + goto err_iounmap; + } + + /* + * Finish setting up the hot plug ctrl device + */ + ctrl->slot_device_offset = readb(ctrl->hpc_reg + SLOT_MASK) >> 4; + dbg("NumSlots %d \n", ctrl->slot_device_offset); + + ctrl->next_event = 0; + + /* Setup the slot information structures */ + rc = ctrl_slot_setup(ctrl, smbios_start, smbios_table); + if (rc) { + err(msg_initialization_err, 6); + err("%s: unable to save PCI configuration data, error %d\n", __FUNCTION__, rc); + goto err_iounmap; + } + + /* Mask all general input interrupts */ + writel(0xFFFFFFFFL, ctrl->hpc_reg + INT_MASK); + + /* set up the interrupt */ + dbg("HPC interrupt = %d \n", ctrl->interrupt); + if (request_irq(ctrl->interrupt, cpqhp_ctrl_intr, + SA_SHIRQ, MY_NAME, ctrl)) { + err("Can't get irq %d for the hotplug pci controller\n", ctrl->interrupt); + rc = -ENODEV; + goto err_iounmap; + } + + /* Enable Shift Out interrupt and clear it, also enable SERR on power fault */ + temp_word = readw(ctrl->hpc_reg + MISC); + temp_word |= 0x4006; + writew(temp_word, ctrl->hpc_reg + MISC); + + // Changed 05/05/97 to clear all interrupts at start + writel(0xFFFFFFFFL, ctrl->hpc_reg + INT_INPUT_CLEAR); + + ctrl->ctrl_int_comp = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); + + writel(0x0L, ctrl->hpc_reg + INT_MASK); + + if (!cpqhp_ctrl_list) { + cpqhp_ctrl_list = ctrl; + ctrl->next = NULL; + } else { + ctrl->next = cpqhp_ctrl_list; + cpqhp_ctrl_list = ctrl; + } + + // turn off empty slots here unless command line option "ON" set + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + num_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0F; + + // find first device number for the ctrl + device = readb(ctrl->hpc_reg + SLOT_MASK) >> 4; + + while (num_of_slots) { + dbg("num_of_slots: %d\n", num_of_slots); + func = cpqhp_slot_find(ctrl->bus, device, 0); + if (!func) + break; + + hp_slot = func->device - ctrl->slot_device_offset; + dbg("hp_slot: %d\n", hp_slot); + + // We have to save the presence info for these slots + temp_word = ctrl->ctrl_int_comp >> 16; + func->presence_save = (temp_word >> hp_slot) & 0x01; + func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; + + if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) { + func->switch_save = 0; + } else { + func->switch_save = 0x10; + } + + if (!power_mode) { + if (!func->is_a_board) { + green_LED_off (ctrl, hp_slot); + slot_disable (ctrl, hp_slot); + } + } + + device++; + num_of_slots--; + } + + if (!power_mode) { + set_SOGO(ctrl); + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + } + + rc = init_SERR(ctrl); + if (rc) { + err("init_SERR failed\n"); + up(&ctrl->crit_sect); + goto err_free_irq; + } + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + cpqhp_create_ctrl_files (ctrl); + + return 0; + +err_free_irq: + free_irq(ctrl->interrupt, ctrl); +err_iounmap: + iounmap(ctrl->hpc_reg); +err_free_mem_region: + release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); +err_free_bus: + kfree(ctrl->pci_bus); +err_free_ctrl: + kfree(ctrl); + return rc; +} + + +static int one_time_init(void) +{ + int loop; + int retval = 0; + static int initialized = 0; + + if (initialized) + return 0; + + power_mode = 0; + + retval = pci_print_IRQ_route(); + if (retval) + goto error; + + dbg("Initialize + Start the notification mechanism \n"); + + retval = cpqhp_event_start_thread(); + if (retval) + goto error; + + dbg("Initialize slot lists\n"); + for (loop = 0; loop < 256; loop++) { + cpqhp_slot_list[loop] = NULL; + } + + // FIXME: We also need to hook the NMI handler eventually. + // this also needs to be worked with Christoph + // register_NMI_handler(); + + // Map rom address + cpqhp_rom_start = ioremap(ROM_PHY_ADDR, ROM_PHY_LEN); + if (!cpqhp_rom_start) { + err ("Could not ioremap memory region for ROM\n"); + retval = -EIO;; + goto error; + } + + /* Now, map the int15 entry point if we are on compaq specific hardware */ + compaq_nvram_init(cpqhp_rom_start); + + /* Map smbios table entry point structure */ + smbios_table = detect_SMBIOS_pointer(cpqhp_rom_start, cpqhp_rom_start + ROM_PHY_LEN); + if (!smbios_table) { + err ("Could not find the SMBIOS pointer in memory\n"); + retval = -EIO;; + goto error; + } + + smbios_start = ioremap(readl(smbios_table + ST_ADDRESS), readw(smbios_table + ST_LENGTH)); + if (!smbios_start) { + err ("Could not ioremap memory region taken from SMBIOS values\n"); + retval = -EIO;; + goto error; + } + + initialized = 1; + + return retval; + +error: + if (cpqhp_rom_start) + iounmap(cpqhp_rom_start); + if (smbios_start) + iounmap(smbios_start); + + return retval; +} + + +static void unload_cpqphpd(void) +{ + struct pci_func *next; + struct pci_func *TempSlot; + int loop; + u32 rc; + struct controller *ctrl; + struct controller *tctrl; + struct pci_resource *res; + struct pci_resource *tres; + + rc = compaq_nvram_store(cpqhp_rom_start); + + ctrl = cpqhp_ctrl_list; + + while (ctrl) { + if (ctrl->hpc_reg) { + u16 misc; + rc = read_slot_enable (ctrl); + + writeb(0, ctrl->hpc_reg + SLOT_SERR); + writel(0xFFFFFFC0L | ~rc, ctrl->hpc_reg + INT_MASK); + + misc = readw(ctrl->hpc_reg + MISC); + misc &= 0xFFFD; + writew(misc, ctrl->hpc_reg + MISC); + } + + ctrl_slot_cleanup(ctrl); + + res = ctrl->io_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = ctrl->mem_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = ctrl->p_mem_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = ctrl->bus_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + kfree (ctrl->pci_bus); + + tctrl = ctrl; + ctrl = ctrl->next; + kfree(tctrl); + } + + for (loop = 0; loop < 256; loop++) { + next = cpqhp_slot_list[loop]; + while (next != NULL) { + res = next->io_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = next->mem_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = next->p_mem_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = next->bus_head; + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + TempSlot = next; + next = next->next; + kfree(TempSlot); + } + } + + // Stop the notification mechanism + cpqhp_event_stop_thread(); + + //unmap the rom address + if (cpqhp_rom_start) + iounmap(cpqhp_rom_start); + if (smbios_start) + iounmap(smbios_start); +} + + + +static struct pci_device_id hpcd_pci_tbl[] __devinitdata = { + { + /* handle any PCI Hotplug controller */ + .class = ((PCI_CLASS_SYSTEM_PCI_HOTPLUG << 8) | 0x00), + .class_mask = ~0, + + /* no matter who makes it */ + .vendor = PCI_ANY_ID, + .device = PCI_ANY_ID, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + + }, { /* end: all zeroes */ } +}; + +MODULE_DEVICE_TABLE(pci, hpcd_pci_tbl); + + + +static struct pci_driver cpqhpc_driver = { + .name = "pci_hotplug", + .id_table = hpcd_pci_tbl, + .probe = cpqhpc_probe, + /* remove: cpqhpc_remove_one, */ +}; + + + +static int __init cpqhpc_init(void) +{ + int result; + + cpqhp_debug = debug; + + result = pci_module_init(&cpqhpc_driver); + dbg("pci_module_init = %d\n", result); + if (result) + return result; + info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); + return 0; +} + + +static void __exit cpqhpc_cleanup(void) +{ + dbg("unload_cpqphpd()\n"); + unload_cpqphpd(); + + dbg("pci_unregister_driver\n"); + pci_unregister_driver(&cpqhpc_driver); +} + + +module_init(cpqhpc_init); +module_exit(cpqhpc_cleanup); + + diff -Nru a/drivers/pci/hotplug/cpqphp_ctrl.c b/drivers/pci/hotplug/cpqphp_ctrl.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pci/hotplug/cpqphp_ctrl.c Mon Jun 9 23:16:10 2003 @@ -0,0 +1,3084 @@ +/* + * Compaq Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Send feedback to <greg@kroah.com> + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/wait.h> +#include <linux/smp_lock.h> +#include <linux/pci.h> +#include "cpqphp.h" + +static u32 configure_new_device(struct controller* ctrl, struct pci_func *func,u8 behind_bridge, struct resource_lists *resources); +static int configure_new_function(struct controller* ctrl, struct pci_func *func,u8 behind_bridge, struct resource_lists *resources); +static void interrupt_event_handler(struct controller *ctrl); + +static struct semaphore event_semaphore; /* mutex for process loop (up if something to process) */ +static struct semaphore event_exit; /* guard ensure thread has exited before calling it quits */ +static int event_finished; +static unsigned long pushbutton_pending; /* = 0 */ + +/* things needed for the long_delay function */ +static struct semaphore delay_sem; +static wait_queue_head_t delay_wait; + +/* delay is in jiffies to wait for */ +static void long_delay (int delay) +{ + DECLARE_WAITQUEUE(wait, current); + + /* only allow 1 customer into the delay queue at once + * yes this makes some people wait even longer, but who really cares? + * this is for _huge_ delays to make the hardware happy as the + * signals bounce around + */ + down (&delay_sem); + + init_waitqueue_head (&delay_wait); + + add_wait_queue(&delay_wait, &wait); + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(delay); + remove_wait_queue(&delay_wait, &wait); + set_current_state(TASK_RUNNING); + + up (&delay_sem); +} + + +//FIXME: The following line needs to be somewhere else... +#define WRONG_BUS_FREQUENCY 0x07 +static u8 handle_switch_change(u8 change, struct controller * ctrl) +{ + int hp_slot; + u8 rc = 0; + u16 temp_word; + struct pci_func *func; + struct event_info *taskInfo; + + if (!change) + return 0; + + // Switch Change + dbg("cpqsbd: Switch interrupt received.\n"); + + for (hp_slot = 0; hp_slot < 6; hp_slot++) { + if (change & (0x1L << hp_slot)) { + //********************************* + // this one changed. + //********************************* + func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0); + + //this is the structure that tells the worker thread + //what to do + taskInfo = &(ctrl->event_queue[ctrl->next_event]); + ctrl->next_event = (ctrl->next_event + 1) % 10; + taskInfo->hp_slot = hp_slot; + + rc++; + + temp_word = ctrl->ctrl_int_comp >> 16; + func->presence_save = (temp_word >> hp_slot) & 0x01; + func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; + + if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) { + //********************************* + // Switch opened + //********************************* + + func->switch_save = 0; + + taskInfo->event_type = INT_SWITCH_OPEN; + } else { + //********************************* + // Switch closed + //********************************* + + func->switch_save = 0x10; + + taskInfo->event_type = INT_SWITCH_CLOSE; + } + } + } + + return rc; +} + + +/* + * cpqhp_find_slot + */ +struct slot *cpqhp_find_slot (struct controller * ctrl, u8 device) +{ + struct slot *slot; + + if (!ctrl) + return NULL; + + slot = ctrl->slot; + + while (slot && (slot->device != device)) { + slot = slot->next; + } + + return slot; +} + + +static u8 handle_presence_change(u16 change, struct controller * ctrl) +{ + int hp_slot; + u8 rc = 0; + u8 temp_byte; + u16 temp_word; + struct pci_func *func; + struct event_info *taskInfo; + struct slot *p_slot; + + if (!change) + return 0; + + //********************************* + // Presence Change + //********************************* + dbg("cpqsbd: Presence/Notify input change.\n"); + dbg(" Changed bits are 0x%4.4x\n", change ); + + for (hp_slot = 0; hp_slot < 6; hp_slot++) { + if (change & (0x0101 << hp_slot)) { + //********************************* + // this one changed. + //********************************* + func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0); + + taskInfo = &(ctrl->event_queue[ctrl->next_event]); + ctrl->next_event = (ctrl->next_event + 1) % 10; + taskInfo->hp_slot = hp_slot; + + rc++; + + p_slot = cpqhp_find_slot(ctrl, hp_slot + (readb(ctrl->hpc_reg + SLOT_MASK) >> 4)); + if (!p_slot) + return 0; + + // If the switch closed, must be a button + // If not in button mode, nevermind + if (func->switch_save && (ctrl->push_button == 1)) { + temp_word = ctrl->ctrl_int_comp >> 16; + temp_byte = (temp_word >> hp_slot) & 0x01; + temp_byte |= (temp_word >> (hp_slot + 7)) & 0x02; + + if (temp_byte != func->presence_save) { + //********************************* + // button Pressed (doesn't do anything) + //********************************* + dbg("hp_slot %d button pressed\n", hp_slot); + taskInfo->event_type = INT_BUTTON_PRESS; + } else { + //********************************* + // button Released - TAKE ACTION!!!! + //********************************* + dbg("hp_slot %d button released\n", hp_slot); + taskInfo->event_type = INT_BUTTON_RELEASE; + + // Cancel if we are still blinking + if ((p_slot->state == BLINKINGON_STATE) + || (p_slot->state == BLINKINGOFF_STATE)) { + taskInfo->event_type = INT_BUTTON_CANCEL; + dbg("hp_slot %d button cancel\n", hp_slot); + } else if ((p_slot->state == POWERON_STATE) + || (p_slot->state == POWEROFF_STATE)) { + //info(msg_button_ignore, p_slot->number); + taskInfo->event_type = INT_BUTTON_IGNORE; + dbg("hp_slot %d button ignore\n", hp_slot); + } + } + } else { + // Switch is open, assume a presence change + // Save the presence state + temp_word = ctrl->ctrl_int_comp >> 16; + func->presence_save = (temp_word >> hp_slot) & 0x01; + func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; + + if ((!(ctrl->ctrl_int_comp & (0x010000 << hp_slot))) || + (!(ctrl->ctrl_int_comp & (0x01000000 << hp_slot)))) { + //********************************* + // Present + //********************************* + taskInfo->event_type = INT_PRESENCE_ON; + } else { + //********************************* + // Not Present + //********************************* + taskInfo->event_type = INT_PRESENCE_OFF; + } + } + } + } + + return rc; +} + + +static u8 handle_power_fault(u8 change, struct controller * ctrl) +{ + int hp_slot; + u8 rc = 0; + struct pci_func *func; + struct event_info *taskInfo; + + if (!change) + return 0; + + //********************************* + // power fault + //********************************* + + info("power fault interrupt\n"); + + for (hp_slot = 0; hp_slot < 6; hp_slot++) { + if (change & (0x01 << hp_slot)) { + //********************************* + // this one changed. + //********************************* + func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0); + + taskInfo = &(ctrl->event_queue[ctrl->next_event]); + ctrl->next_event = (ctrl->next_event + 1) % 10; + taskInfo->hp_slot = hp_slot; + + rc++; + + if (ctrl->ctrl_int_comp & (0x00000100 << hp_slot)) { + //********************************* + // power fault Cleared + //********************************* + func->status = 0x00; + + taskInfo->event_type = INT_POWER_FAULT_CLEAR; + } else { + //********************************* + // power fault + //********************************* + taskInfo->event_type = INT_POWER_FAULT; + + if (ctrl->rev < 4) { + amber_LED_on (ctrl, hp_slot); + green_LED_off (ctrl, hp_slot); + set_SOGO (ctrl); + + // this is a fatal condition, we want to crash the + // machine to protect from data corruption + // simulated_NMI shouldn't ever return + //FIXME + //simulated_NMI(hp_slot, ctrl); + + //The following code causes a software crash just in + //case simulated_NMI did return + //FIXME + //panic(msg_power_fault); + } else { + // set power fault status for this board + func->status = 0xFF; + info("power fault bit %x set\n", hp_slot); + } + } + } + } + + return rc; +} + + +/* + * sort_by_size + * + * Sorts nodes on the list by their length. + * Smallest first. + * + */ +static int sort_by_size(struct pci_resource **head) +{ + struct pci_resource *current_res; + struct pci_resource *next_res; + int out_of_order = 1; + + if (!(*head)) + return(1); + + if (!((*head)->next)) + return(0); + + while (out_of_order) { + out_of_order = 0; + + // Special case for swapping list head + if (((*head)->next) && + ((*head)->length > (*head)->next->length)) { + out_of_order++; + current_res = *head; + *head = (*head)->next; + current_res->next = (*head)->next; + (*head)->next = current_res; + } + + current_res = *head; + + while (current_res->next && current_res->next->next) { + if (current_res->next->length > current_res->next->next->length) { + out_of_order++; + next_res = current_res->next; + current_res->next = current_res->next->next; + current_res = current_res->next; + next_res->next = current_res->next; + current_res->next = next_res; + } else + current_res = current_res->next; + } + } // End of out_of_order loop + + return(0); +} + + +/* + * sort_by_max_size + * + * Sorts nodes on the list by their length. + * Largest first. + * + */ +static int sort_by_max_size(struct pci_resource **head) +{ + struct pci_resource *current_res; + struct pci_resource *next_res; + int out_of_order = 1; + + if (!(*head)) + return(1); + + if (!((*head)->next)) + return(0); + + while (out_of_order) { + out_of_order = 0; + + // Special case for swapping list head + if (((*head)->next) && + ((*head)->length < (*head)->next->length)) { + out_of_order++; + current_res = *head; + *head = (*head)->next; + current_res->next = (*head)->next; + (*head)->next = current_res; + } + + current_res = *head; + + while (current_res->next && current_res->next->next) { + if (current_res->next->length < current_res->next->next->length) { + out_of_order++; + next_res = current_res->next; + current_res->next = current_res->next->next; + current_res = current_res->next; + next_res->next = current_res->next; + current_res->next = next_res; + } else + current_res = current_res->next; + } + } // End of out_of_order loop + + return(0); +} + + +/* + * do_pre_bridge_resource_split + * + * Returns zero or one node of resources that aren't in use + * + */ +static struct pci_resource *do_pre_bridge_resource_split (struct pci_resource **head, struct pci_resource **orig_head, u32 alignment) +{ + struct pci_resource *prevnode = NULL; + struct pci_resource *node; + struct pci_resource *split_node; + u32 rc; + u32 temp_dword; + dbg("do_pre_bridge_resource_split\n"); + + if (!(*head) || !(*orig_head)) + return(NULL); + + rc = cpqhp_resource_sort_and_combine(head); + + if (rc) + return(NULL); + + if ((*head)->base != (*orig_head)->base) + return(NULL); + + if ((*head)->length == (*orig_head)->length) + return(NULL); + + + // If we got here, there the bridge requires some of the resource, but + // we may be able to split some off of the front + + node = *head; + + if (node->length & (alignment -1)) { + // this one isn't an aligned length, so we'll make a new entry + // and split it up. + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + temp_dword = (node->length | (alignment-1)) + 1 - alignment; + + split_node->base = node->base; + split_node->length = temp_dword; + + node->length -= temp_dword; + node->base += split_node->length; + + // Put it in the list + *head = split_node; + split_node->next = node; + } + + if (node->length < alignment) { + return(NULL); + } + + // Now unlink it + if (*head == node) { + *head = node->next; + node->next = NULL; + } else { + prevnode = *head; + while (prevnode->next != node) + prevnode = prevnode->next; + + prevnode->next = node->next; + node->next = NULL; + } + + return(node); +} + + +/* + * do_bridge_resource_split + * + * Returns zero or one node of resources that aren't in use + * + */ +static struct pci_resource *do_bridge_resource_split (struct pci_resource **head, u32 alignment) +{ + struct pci_resource *prevnode = NULL; + struct pci_resource *node; + u32 rc; + u32 temp_dword; + + if (!(*head)) + return(NULL); + + rc = cpqhp_resource_sort_and_combine(head); + + if (rc) + return(NULL); + + node = *head; + + while (node->next) { + prevnode = node; + node = node->next; + kfree(prevnode); + } + + if (node->length < alignment) { + kfree(node); + return(NULL); + } + + if (node->base & (alignment - 1)) { + // Short circuit if adjusted size is too small + temp_dword = (node->base | (alignment-1)) + 1; + if ((node->length - (temp_dword - node->base)) < alignment) { + kfree(node); + return(NULL); + } + + node->length -= (temp_dword - node->base); + node->base = temp_dword; + } + + if (node->length & (alignment - 1)) { + // There's stuff in use after this node + kfree(node); + return(NULL); + } + + return(node); +} + + +/* + * get_io_resource + * + * this function sorts the resource list by size and then + * returns the first node of "size" length that is not in the + * ISA aliasing window. If it finds a node larger than "size" + * it will split it up. + * + * size must be a power of two. + */ +static struct pci_resource *get_io_resource (struct pci_resource **head, u32 size) +{ + struct pci_resource *prevnode; + struct pci_resource *node; + struct pci_resource *split_node; + u32 temp_dword; + + if (!(*head)) + return(NULL); + + if ( cpqhp_resource_sort_and_combine(head) ) + return(NULL); + + if ( sort_by_size(head) ) + return(NULL); + + for (node = *head; node; node = node->next) { + if (node->length < size) + continue; + + if (node->base & (size - 1)) { + // this one isn't base aligned properly + // so we'll make a new entry and split it up + temp_dword = (node->base | (size-1)) + 1; + + // Short circuit if adjusted size is too small + if ((node->length - (temp_dword - node->base)) < size) + continue; + + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base; + split_node->length = temp_dword - node->base; + node->base = temp_dword; + node->length -= split_node->length; + + // Put it in the list + split_node->next = node->next; + node->next = split_node; + } // End of non-aligned base + + // Don't need to check if too small since we already did + if (node->length > size) { + // this one is longer than we need + // so we'll make a new entry and split it up + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base + size; + split_node->length = node->length - size; + node->length = size; + + // Put it in the list + split_node->next = node->next; + node->next = split_node; + } // End of too big on top end + + // For IO make sure it's not in the ISA aliasing space + if (node->base & 0x300L) + continue; + + // If we got here, then it is the right size + // Now take it out of the list + if (*head == node) { + *head = node->next; + } else { + prevnode = *head; + while (prevnode->next != node) + prevnode = prevnode->next; + + prevnode->next = node->next; + } + node->next = NULL; + // Stop looping + break; + } + + return(node); +} + + +/* + * get_max_resource + * + * Gets the largest node that is at least "size" big from the + * list pointed to by head. It aligns the node on top and bottom + * to "size" alignment before returning it. + */ +static struct pci_resource *get_max_resource (struct pci_resource **head, u32 size) +{ + struct pci_resource *max; + struct pci_resource *temp; + struct pci_resource *split_node; + u32 temp_dword; + + if (!(*head)) + return(NULL); + + if (cpqhp_resource_sort_and_combine(head)) + return(NULL); + + if (sort_by_max_size(head)) + return(NULL); + + for (max = *head;max; max = max->next) { + + // If not big enough we could probably just bail, + // instead we'll continue to the next. + if (max->length < size) + continue; + + if (max->base & (size - 1)) { + // this one isn't base aligned properly + // so we'll make a new entry and split it up + temp_dword = (max->base | (size-1)) + 1; + + // Short circuit if adjusted size is too small + if ((max->length - (temp_dword - max->base)) < size) + continue; + + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = max->base; + split_node->length = temp_dword - max->base; + max->base = temp_dword; + max->length -= split_node->length; + + // Put it next in the list + split_node->next = max->next; + max->next = split_node; + } + + if ((max->base + max->length) & (size - 1)) { + // this one isn't end aligned properly at the top + // so we'll make a new entry and split it up + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + temp_dword = ((max->base + max->length) & ~(size - 1)); + split_node->base = temp_dword; + split_node->length = max->length + max->base + - split_node->base; + max->length -= split_node->length; + + // Put it in the list + split_node->next = max->next; + max->next = split_node; + } + + // Make sure it didn't shrink too much when we aligned it + if (max->length < size) + continue; + + // Now take it out of the list + temp = (struct pci_resource*) *head; + if (temp == max) { + *head = max->next; + } else { + while (temp && temp->next != max) { + temp = temp->next; + } + + temp->next = max->next; + } + + max->next = NULL; + return(max); + } + + // If we get here, we couldn't find one + return(NULL); +} + + +/* + * get_resource + * + * this function sorts the resource list by size and then + * returns the first node of "size" length. If it finds a node + * larger than "size" it will split it up. + * + * size must be a power of two. + */ +static struct pci_resource *get_resource (struct pci_resource **head, u32 size) +{ + struct pci_resource *prevnode; + struct pci_resource *node; + struct pci_resource *split_node; + u32 temp_dword; + + if (!(*head)) + return(NULL); + + if ( cpqhp_resource_sort_and_combine(head) ) + return(NULL); + + if ( sort_by_size(head) ) + return(NULL); + + for (node = *head; node; node = node->next) { + dbg("%s: req_size =%x node=%p, base=%x, length=%x\n", + __FUNCTION__, size, node, node->base, node->length); + if (node->length < size) + continue; + + if (node->base & (size - 1)) { + dbg("%s: not aligned\n", __FUNCTION__); + // this one isn't base aligned properly + // so we'll make a new entry and split it up + temp_dword = (node->base | (size-1)) + 1; + + // Short circuit if adjusted size is too small + if ((node->length - (temp_dword - node->base)) < size) + continue; + + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base; + split_node->length = temp_dword - node->base; + node->base = temp_dword; + node->length -= split_node->length; + + // Put it in the list + split_node->next = node->next; + node->next = split_node; + } // End of non-aligned base + + // Don't need to check if too small since we already did + if (node->length > size) { + dbg("%s: too big\n", __FUNCTION__); + // this one is longer than we need + // so we'll make a new entry and split it up + split_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!split_node) + return(NULL); + + split_node->base = node->base + size; + split_node->length = node->length - size; + node->length = size; + + // Put it in the list + split_node->next = node->next; + node->next = split_node; + } // End of too big on top end + + dbg("%s: got one!!!\n", __FUNCTION__); + // If we got here, then it is the right size + // Now take it out of the list + if (*head == node) { + *head = node->next; + } else { + prevnode = *head; + while (prevnode->next != node) + prevnode = prevnode->next; + + prevnode->next = node->next; + } + node->next = NULL; + // Stop looping + break; + } + return(node); +} + + +/* + * cpqhp_resource_sort_and_combine + * + * Sorts all of the nodes in the list in ascending order by + * their base addresses. Also does garbage collection by + * combining adjacent nodes. + * + * returns 0 if success + */ +int cpqhp_resource_sort_and_combine(struct pci_resource **head) +{ + struct pci_resource *node1; + struct pci_resource *node2; + int out_of_order = 1; + + dbg("%s: head = %p, *head = %p\n", __FUNCTION__, head, *head); + + if (!(*head)) + return(1); + + dbg("*head->next = %p\n",(*head)->next); + + if (!(*head)->next) + return(0); /* only one item on the list, already sorted! */ + + dbg("*head->base = 0x%x\n",(*head)->base); + dbg("*head->next->base = 0x%x\n",(*head)->next->base); + while (out_of_order) { + out_of_order = 0; + + // Special case for swapping list head + if (((*head)->next) && + ((*head)->base > (*head)->next->base)) { + node1 = *head; + (*head) = (*head)->next; + node1->next = (*head)->next; + (*head)->next = node1; + out_of_order++; + } + + node1 = (*head); + + while (node1->next && node1->next->next) { + if (node1->next->base > node1->next->next->base) { + out_of_order++; + node2 = node1->next; + node1->next = node1->next->next; + node1 = node1->next; + node2->next = node1->next; + node1->next = node2; + } else + node1 = node1->next; + } + } // End of out_of_order loop + + node1 = *head; + + while (node1 && node1->next) { + if ((node1->base + node1->length) == node1->next->base) { + // Combine + dbg("8..\n"); + node1->length += node1->next->length; + node2 = node1->next; + node1->next = node1->next->next; + kfree(node2); + } else + node1 = node1->next; + } + + return(0); +} + + +irqreturn_t cpqhp_ctrl_intr(int IRQ, void *data, struct pt_regs *regs) +{ + struct controller *ctrl = data; + u8 schedule_flag = 0; + u8 reset; + u16 misc; + u32 Diff; + u32 temp_dword; + + + misc = readw(ctrl->hpc_reg + MISC); + //********************************* + // Check to see if it was our interrupt + //********************************* + if (!(misc & 0x000C)) { + return IRQ_NONE; + } + + if (misc & 0x0004) { + //********************************* + // Serial Output interrupt Pending + //********************************* + + // Clear the interrupt + misc |= 0x0004; + writew(misc, ctrl->hpc_reg + MISC); + + // Read to clear posted writes + misc = readw(ctrl->hpc_reg + MISC); + + dbg ("%s - waking up\n", __FUNCTION__); + wake_up_interruptible(&ctrl->queue); + } + + if (misc & 0x0008) { + // General-interrupt-input interrupt Pending + Diff = readl(ctrl->hpc_reg + INT_INPUT_CLEAR) ^ ctrl->ctrl_int_comp; + + ctrl->ctrl_int_comp = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); + + // Clear the interrupt + writel(Diff, ctrl->hpc_reg + INT_INPUT_CLEAR); + + // Read it back to clear any posted writes + temp_dword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); + + if (!Diff) { + // Clear all interrupts + writel(0xFFFFFFFF, ctrl->hpc_reg + INT_INPUT_CLEAR); + } + + schedule_flag += handle_switch_change((u8)(Diff & 0xFFL), ctrl); + schedule_flag += handle_presence_change((u16)((Diff & 0xFFFF0000L) >> 16), ctrl); + schedule_flag += handle_power_fault((u8)((Diff & 0xFF00L) >> 8), ctrl); + } + + reset = readb(ctrl->hpc_reg + RESET_FREQ_MODE); + if (reset & 0x40) { + /* Bus reset has completed */ + reset &= 0xCF; + writeb(reset, ctrl->hpc_reg + RESET_FREQ_MODE); + reset = readb(ctrl->hpc_reg + RESET_FREQ_MODE); + wake_up_interruptible(&ctrl->queue); + } + + if (schedule_flag) { + up(&event_semaphore); + dbg("Signal event_semaphore\n"); + } + return IRQ_HANDLED; +} + + +/** + * cpqhp_slot_create - Creates a node and adds it to the proper bus. + * @busnumber - bus where new node is to be located + * + * Returns pointer to the new node or NULL if unsuccessful + */ +struct pci_func *cpqhp_slot_create(u8 busnumber) +{ + struct pci_func *new_slot; + struct pci_func *next; + + new_slot = (struct pci_func *) kmalloc(sizeof(struct pci_func), GFP_KERNEL); + + if (new_slot == NULL) { + // I'm not dead yet! + // You will be. + return(new_slot); + } + + memset(new_slot, 0, sizeof(struct pci_func)); + + new_slot->next = NULL; + new_slot->configured = 1; + + if (cpqhp_slot_list[busnumber] == NULL) { + cpqhp_slot_list[busnumber] = new_slot; + } else { + next = cpqhp_slot_list[busnumber]; + while (next->next != NULL) + next = next->next; + next->next = new_slot; + } + return(new_slot); +} + + +/* + * slot_remove - Removes a node from the linked list of slots. + * @old_slot: slot to remove + * + * Returns 0 if successful, !0 otherwise. + */ +static int slot_remove(struct pci_func * old_slot) +{ + struct pci_func *next; + + if (old_slot == NULL) + return(1); + + next = cpqhp_slot_list[old_slot->bus]; + + if (next == NULL) { + return(1); + } + + if (next == old_slot) { + cpqhp_slot_list[old_slot->bus] = old_slot->next; + cpqhp_destroy_board_resources(old_slot); + kfree(old_slot); + return(0); + } + + while ((next->next != old_slot) && (next->next != NULL)) { + next = next->next; + } + + if (next->next == old_slot) { + next->next = old_slot->next; + cpqhp_destroy_board_resources(old_slot); + kfree(old_slot); + return(0); + } else + return(2); +} + + +/** + * bridge_slot_remove - Removes a node from the linked list of slots. + * @bridge: bridge to remove + * + * Returns 0 if successful, !0 otherwise. + */ +static int bridge_slot_remove(struct pci_func *bridge) +{ + u8 subordinateBus, secondaryBus; + u8 tempBus; + struct pci_func *next; + + if (bridge == NULL) + return(1); + + secondaryBus = (bridge->config_space[0x06] >> 8) & 0xFF; + subordinateBus = (bridge->config_space[0x06] >> 16) & 0xFF; + + for (tempBus = secondaryBus; tempBus <= subordinateBus; tempBus++) { + next = cpqhp_slot_list[tempBus]; + + while (!slot_remove(next)) { + next = cpqhp_slot_list[tempBus]; + } + } + + next = cpqhp_slot_list[bridge->bus]; + + if (next == NULL) { + return(1); + } + + if (next == bridge) { + cpqhp_slot_list[bridge->bus] = bridge->next; + kfree(bridge); + return(0); + } + + while ((next->next != bridge) && (next->next != NULL)) { + next = next->next; + } + + if (next->next == bridge) { + next->next = bridge->next; + kfree(bridge); + return(0); + } else + return(2); +} + + +/** + * cpqhp_slot_find - Looks for a node by bus, and device, multiple functions accessed + * @bus: bus to find + * @device: device to find + * @index: is 0 for first function found, 1 for the second... + * + * Returns pointer to the node if successful, %NULL otherwise. + */ +struct pci_func *cpqhp_slot_find(u8 bus, u8 device, u8 index) +{ + int found = -1; + struct pci_func *func; + + func = cpqhp_slot_list[bus]; + + if ((func == NULL) || ((func->device == device) && (index == 0))) + return(func); + + if (func->device == device) + found++; + + while (func->next != NULL) { + func = func->next; + + if (func->device == device) + found++; + + if (found == index) + return(func); + } + + return(NULL); +} + + +// DJZ: I don't think is_bridge will work as is. +//FIXME +static int is_bridge(struct pci_func * func) +{ + // Check the header type + if (((func->config_space[0x03] >> 16) & 0xFF) == 0x01) + return 1; + else + return 0; +} + + +/* the following routines constitute the bulk of the + hotplug controller logic + */ + + +/** + * board_replaced - Called after a board has been replaced in the system. + * + * This is only used if we don't have resources for hot add + * Turns power on for the board + * Checks to see if board is the same + * If board is same, reconfigures it + * If board isn't same, turns it back off. + * + */ +static u32 board_replaced(struct pci_func * func, struct controller * ctrl) +{ + u8 hp_slot; + u8 temp_byte; + u8 adapter_speed; + u32 index; + u32 rc = 0; + u32 src = 8; + + hp_slot = func->device - ctrl->slot_device_offset; + + if (readl(ctrl->hpc_reg + INT_INPUT_CLEAR) & (0x01L << hp_slot)) { + //********************************* + // The switch is open. + //********************************* + rc = INTERLOCK_OPEN; + } else if (is_slot_enabled (ctrl, hp_slot)) { + //********************************* + // The board is already on + //********************************* + rc = CARD_FUNCTIONING; + } else { + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + // turn on board without attaching to the bus + enable_slot_power (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Change bits in slot power register to force another shift out + // NOTE: this is to work around the timer bug + temp_byte = readb(ctrl->hpc_reg + SLOT_POWER); + writeb(0x00, ctrl->hpc_reg + SLOT_POWER); + writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + adapter_speed = get_adapter_speed(ctrl, hp_slot); + if (ctrl->speed != adapter_speed) + if (set_controller_speed(ctrl, adapter_speed, hp_slot)) + rc = WRONG_BUS_FREQUENCY; + + // turn off board without attaching to the bus + disable_slot_power (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + if (rc) + return(rc); + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + slot_enable (ctrl, hp_slot); + green_LED_blink (ctrl, hp_slot); + + amber_LED_off (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + // Wait for ~1 second because of hot plug spec + long_delay(1*HZ); + + // Check for a power fault + if (func->status == 0xFF) { + // power fault occurred, but it was benign + rc = POWER_FAILURE; + func->status = 0; + } else + rc = cpqhp_valid_replace(ctrl, func); + + if (!rc) { + // It must be the same board + + rc = cpqhp_configure_board(ctrl, func); + + if (rc || src) { + // If configuration fails, turn it off + // Get slot won't work for devices behind bridges, but + // in this case it will always be called for the "base" + // bus/dev/func of an adapter. + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + amber_LED_on (ctrl, hp_slot); + green_LED_off (ctrl, hp_slot); + slot_disable (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + if (rc) + return(rc); + else + return(1); + } + + func->status = 0; + func->switch_save = 0x10; + + index = 1; + while (((func = cpqhp_slot_find(func->bus, func->device, index)) != NULL) && !rc) { + rc |= cpqhp_configure_board(ctrl, func); + index++; + } + + if (rc) { + // If configuration fails, turn it off + // Get slot won't work for devices behind bridges, but + // in this case it will always be called for the "base" + // bus/dev/func of an adapter. + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + amber_LED_on (ctrl, hp_slot); + green_LED_off (ctrl, hp_slot); + slot_disable (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + return(rc); + } + // Done configuring so turn LED on full time + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + green_LED_on (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + rc = 0; + } else { + // Something is wrong + + // Get slot won't work for devices behind bridges, but + // in this case it will always be called for the "base" + // bus/dev/func of an adapter. + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + amber_LED_on (ctrl, hp_slot); + green_LED_off (ctrl, hp_slot); + slot_disable (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + } + + } + return(rc); + +} + + +/** + * board_added - Called after a board has been added to the system. + * + * Turns power on for the board + * Configures board + * + */ +static u32 board_added(struct pci_func * func, struct controller * ctrl) +{ + u8 hp_slot; + u8 temp_byte; + u8 adapter_speed; + int index; + u32 temp_register = 0xFFFFFFFF; + u32 rc = 0; + struct pci_func *new_slot = NULL; + struct slot *p_slot; + struct resource_lists res_lists; + + hp_slot = func->device - ctrl->slot_device_offset; + dbg("%s: func->device, slot_offset, hp_slot = %d, %d ,%d\n", + __FUNCTION__, func->device, ctrl->slot_device_offset, hp_slot); + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + // turn on board without attaching to the bus + enable_slot_power (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Change bits in slot power register to force another shift out + // NOTE: this is to work around the timer bug + temp_byte = readb(ctrl->hpc_reg + SLOT_POWER); + writeb(0x00, ctrl->hpc_reg + SLOT_POWER); + writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + adapter_speed = get_adapter_speed(ctrl, hp_slot); + if (ctrl->speed != adapter_speed) + if (set_controller_speed(ctrl, adapter_speed, hp_slot)) + rc = WRONG_BUS_FREQUENCY; + + // turn off board without attaching to the bus + disable_slot_power (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + if (rc) + return(rc); + + p_slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); + + // turn on board and blink green LED + + // Wait for exclusive access to hardware + dbg("%s: before down\n", __FUNCTION__); + down(&ctrl->crit_sect); + dbg("%s: after down\n", __FUNCTION__); + + dbg("%s: before slot_enable\n", __FUNCTION__); + slot_enable (ctrl, hp_slot); + + dbg("%s: before green_LED_blink\n", __FUNCTION__); + green_LED_blink (ctrl, hp_slot); + + dbg("%s: before amber_LED_blink\n", __FUNCTION__); + amber_LED_off (ctrl, hp_slot); + + dbg("%s: before set_SOGO\n", __FUNCTION__); + set_SOGO(ctrl); + + // Wait for SOBS to be unset + dbg("%s: before wait_for_ctrl_irq\n", __FUNCTION__); + wait_for_ctrl_irq (ctrl); + dbg("%s: after wait_for_ctrl_irq\n", __FUNCTION__); + + // Done with exclusive hardware access + dbg("%s: before up\n", __FUNCTION__); + up(&ctrl->crit_sect); + dbg("%s: after up\n", __FUNCTION__); + + // Wait for ~1 second because of hot plug spec + dbg("%s: before long_delay\n", __FUNCTION__); + long_delay(1*HZ); + dbg("%s: after long_delay\n", __FUNCTION__); + + dbg("%s: func status = %x\n", __FUNCTION__, func->status); + // Check for a power fault + if (func->status == 0xFF) { + // power fault occurred, but it was benign + temp_register = 0xFFFFFFFF; + dbg("%s: temp register set to %x by power fault\n", __FUNCTION__, temp_register); + rc = POWER_FAILURE; + func->status = 0; + } else { + // Get vendor/device ID u32 + ctrl->pci_bus->number = func->bus; + rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(func->device, func->function), PCI_VENDOR_ID, &temp_register); + dbg("%s: pci_read_config_dword returns %d\n", __FUNCTION__, rc); + dbg("%s: temp_register is %x\n", __FUNCTION__, temp_register); + + if (rc != 0) { + // Something's wrong here + temp_register = 0xFFFFFFFF; + dbg("%s: temp register set to %x by error\n", __FUNCTION__, temp_register); + } + // Preset return code. It will be changed later if things go okay. + rc = NO_ADAPTER_PRESENT; + } + + // All F's is an empty slot or an invalid board + if (temp_register != 0xFFFFFFFF) { // Check for a board in the slot + res_lists.io_head = ctrl->io_head; + res_lists.mem_head = ctrl->mem_head; + res_lists.p_mem_head = ctrl->p_mem_head; + res_lists.bus_head = ctrl->bus_head; + res_lists.irqs = NULL; + + rc = configure_new_device(ctrl, func, 0, &res_lists); + + dbg("%s: back from configure_new_device\n", __FUNCTION__); + ctrl->io_head = res_lists.io_head; + ctrl->mem_head = res_lists.mem_head; + ctrl->p_mem_head = res_lists.p_mem_head; + ctrl->bus_head = res_lists.bus_head; + + cpqhp_resource_sort_and_combine(&(ctrl->mem_head)); + cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head)); + cpqhp_resource_sort_and_combine(&(ctrl->io_head)); + cpqhp_resource_sort_and_combine(&(ctrl->bus_head)); + + if (rc) { + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + amber_LED_on (ctrl, hp_slot); + green_LED_off (ctrl, hp_slot); + slot_disable (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + return(rc); + } else { + cpqhp_save_slot_config(ctrl, func); + } + + + func->status = 0; + func->switch_save = 0x10; + func->is_a_board = 0x01; + + //next, we will instantiate the linux pci_dev structures (with appropriate driver notification, if already present) + dbg("%s: configure linux pci_dev structure\n", __FUNCTION__); + index = 0; + do { + new_slot = cpqhp_slot_find(ctrl->bus, func->device, index++); + if (new_slot && !new_slot->pci_dev) { + cpqhp_configure_device(ctrl, new_slot); + } + } while (new_slot); + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + green_LED_on (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + } else { + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + amber_LED_on (ctrl, hp_slot); + green_LED_off (ctrl, hp_slot); + slot_disable (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + return(rc); + } + return 0; +} + + +/** + * remove_board - Turns off slot and LED's + * + */ +static u32 remove_board(struct pci_func * func, u32 replace_flag, struct controller * ctrl) +{ + int index; + u8 skip = 0; + u8 device; + u8 hp_slot; + u8 temp_byte; + u32 rc; + struct resource_lists res_lists; + struct pci_func *temp_func; + + if (func == NULL) + return(1); + + if (cpqhp_unconfigure_device(func)) + return(1); + + device = func->device; + + hp_slot = func->device - ctrl->slot_device_offset; + dbg("In %s, hp_slot = %d\n", __FUNCTION__, hp_slot); + + // When we get here, it is safe to change base Address Registers. + // We will attempt to save the base Address Register Lengths + if (replace_flag || !ctrl->add_support) + rc = cpqhp_save_base_addr_length(ctrl, func); + else if (!func->bus_head && !func->mem_head && + !func->p_mem_head && !func->io_head) { + // Here we check to see if we've saved any of the board's + // resources already. If so, we'll skip the attempt to + // determine what's being used. + index = 0; + temp_func = cpqhp_slot_find(func->bus, func->device, index++); + while (temp_func) { + if (temp_func->bus_head || temp_func->mem_head + || temp_func->p_mem_head || temp_func->io_head) { + skip = 1; + break; + } + temp_func = cpqhp_slot_find(temp_func->bus, temp_func->device, index++); + } + + if (!skip) + rc = cpqhp_save_used_resources(ctrl, func); + } + // Change status to shutdown + if (func->is_a_board) + func->status = 0x01; + func->configured = 0; + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + green_LED_off (ctrl, hp_slot); + slot_disable (ctrl, hp_slot); + + set_SOGO(ctrl); + + // turn off SERR for slot + temp_byte = readb(ctrl->hpc_reg + SLOT_SERR); + temp_byte &= ~(0x01 << hp_slot); + writeb(temp_byte, ctrl->hpc_reg + SLOT_SERR); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + + if (!replace_flag && ctrl->add_support) { + while (func) { + res_lists.io_head = ctrl->io_head; + res_lists.mem_head = ctrl->mem_head; + res_lists.p_mem_head = ctrl->p_mem_head; + res_lists.bus_head = ctrl->bus_head; + + cpqhp_return_board_resources(func, &res_lists); + + ctrl->io_head = res_lists.io_head; + ctrl->mem_head = res_lists.mem_head; + ctrl->p_mem_head = res_lists.p_mem_head; + ctrl->bus_head = res_lists.bus_head; + + cpqhp_resource_sort_and_combine(&(ctrl->mem_head)); + cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head)); + cpqhp_resource_sort_and_combine(&(ctrl->io_head)); + cpqhp_resource_sort_and_combine(&(ctrl->bus_head)); + + if (is_bridge(func)) { + bridge_slot_remove(func); + } else + slot_remove(func); + + func = cpqhp_slot_find(ctrl->bus, device, 0); + } + + // Setup slot structure with entry for empty slot + func = cpqhp_slot_create(ctrl->bus); + + if (func == NULL) { + // Out of memory + return(1); + } + + func->bus = ctrl->bus; + func->device = device; + func->function = 0; + func->configured = 0; + func->switch_save = 0x10; + func->is_a_board = 0; + func->p_task_event = NULL; + } + + return 0; +} + + +static void pushbutton_helper_thread (unsigned long data) +{ + pushbutton_pending = data; + up(&event_semaphore); +} + + +// this is the main worker thread +static int event_thread(void* data) +{ + struct controller *ctrl; + lock_kernel(); + daemonize("phpd_event"); + + unlock_kernel(); + + while (1) { + dbg("!!!!event_thread sleeping\n"); + down_interruptible (&event_semaphore); + dbg("event_thread woken finished = %d\n", event_finished); + if (event_finished) break; + /* Do stuff here */ + if (pushbutton_pending) + cpqhp_pushbutton_thread(pushbutton_pending); + else + for (ctrl = cpqhp_ctrl_list; ctrl; ctrl=ctrl->next) + interrupt_event_handler(ctrl); + } + dbg("event_thread signals exit\n"); + up(&event_exit); + return 0; +} + + +int cpqhp_event_start_thread (void) +{ + int pid; + + /* initialize our semaphores */ + init_MUTEX(&delay_sem); + init_MUTEX_LOCKED(&event_semaphore); + init_MUTEX_LOCKED(&event_exit); + event_finished=0; + + pid = kernel_thread(event_thread, 0, 0); + if (pid < 0) { + err ("Can't start up our event thread\n"); + return -1; + } + dbg("Our event thread pid = %d\n", pid); + return 0; +} + + +void cpqhp_event_stop_thread (void) +{ + event_finished = 1; + dbg("event_thread finish command given\n"); + up(&event_semaphore); + dbg("wait for event_thread to exit\n"); + down(&event_exit); +} + + +static int update_slot_info (struct controller *ctrl, struct slot *slot) +{ + struct hotplug_slot_info *info; + int result; + + info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); + if (!info) + return -ENOMEM; + + info->power_status = get_slot_enabled(ctrl, slot); + info->attention_status = cpq_get_attention_status(ctrl, slot); + info->latch_status = cpq_get_latch_status(ctrl, slot); + info->adapter_status = get_presence_status(ctrl, slot); + result = pci_hp_change_slot_info(slot->hotplug_slot, info); + kfree (info); + return result; +} + +static void interrupt_event_handler(struct controller *ctrl) +{ + int loop = 0; + int change = 1; + struct pci_func *func; + u8 hp_slot; + struct slot *p_slot; + + while (change) { + change = 0; + + for (loop = 0; loop < 10; loop++) { + //dbg("loop %d\n", loop); + if (ctrl->event_queue[loop].event_type != 0) { + hp_slot = ctrl->event_queue[loop].hp_slot; + + func = cpqhp_slot_find(ctrl->bus, (hp_slot + ctrl->slot_device_offset), 0); + if (!func) + return; + + p_slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset); + if (!p_slot) + return; + + dbg("hp_slot %d, func %p, p_slot %p\n", + hp_slot, func, p_slot); + + if (ctrl->event_queue[loop].event_type == INT_BUTTON_PRESS) { + dbg("button pressed\n"); + } else if (ctrl->event_queue[loop].event_type == + INT_BUTTON_CANCEL) { + dbg("button cancel\n"); + del_timer(&p_slot->task_event); + + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + if (p_slot->state == BLINKINGOFF_STATE) { + // slot is on + // turn on green LED + dbg("turn on green LED\n"); + green_LED_on (ctrl, hp_slot); + } else if (p_slot->state == BLINKINGON_STATE) { + // slot is off + // turn off green LED + dbg("turn off green LED\n"); + green_LED_off (ctrl, hp_slot); + } + + info(msg_button_cancel, p_slot->number); + + p_slot->state = STATIC_STATE; + + amber_LED_off (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + } + // ***********button Released (No action on press...) + else if (ctrl->event_queue[loop].event_type == INT_BUTTON_RELEASE) { + dbg("button release\n"); + + if (is_slot_enabled (ctrl, hp_slot)) { + // slot is on + dbg("slot is on\n"); + p_slot->state = BLINKINGOFF_STATE; + info(msg_button_off, p_slot->number); + } else { + // slot is off + dbg("slot is off\n"); + p_slot->state = BLINKINGON_STATE; + info(msg_button_on, p_slot->number); + } + // Wait for exclusive access to hardware + down(&ctrl->crit_sect); + + dbg("blink green LED and turn off amber\n"); + + amber_LED_off (ctrl, hp_slot); + green_LED_blink (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + + // Done with exclusive hardware access + up(&ctrl->crit_sect); + init_timer(&p_slot->task_event); + p_slot->hp_slot = hp_slot; + p_slot->ctrl = ctrl; +// p_slot->physical_slot = physical_slot; + p_slot->task_event.expires = jiffies + 5 * HZ; // 5 second delay + p_slot->task_event.function = pushbutton_helper_thread; + p_slot->task_event.data = (u32) p_slot; + + dbg("add_timer p_slot = %p\n", p_slot); + add_timer(&p_slot->task_event); + } + // ***********POWER FAULT + else if (ctrl->event_queue[loop].event_type == INT_POWER_FAULT) { + dbg("power fault\n"); + } else { + /* refresh notification */ + if (p_slot) + update_slot_info(ctrl, p_slot); + } + + ctrl->event_queue[loop].event_type = 0; + + change = 1; + } + } // End of FOR loop + } + + return; +} + + +/** + * cpqhp_pushbutton_thread + * + * Scheduled procedure to handle blocking stuff for the pushbuttons + * Handles all pending events and exits. + * + */ +void cpqhp_pushbutton_thread (unsigned long slot) +{ + u8 hp_slot; + u8 device; + struct pci_func *func; + struct slot *p_slot = (struct slot *) slot; + struct controller *ctrl = (struct controller *) p_slot->ctrl; + + pushbutton_pending = 0; + hp_slot = p_slot->hp_slot; + + device = p_slot->device; + + if (is_slot_enabled (ctrl, hp_slot)) { + p_slot->state = POWEROFF_STATE; + // power Down board + func = cpqhp_slot_find(p_slot->bus, p_slot->device, 0); + dbg("In power_down_board, func = %p, ctrl = %p\n", func, ctrl); + if (!func) { + dbg("Error! func NULL in %s\n", __FUNCTION__); + return ; + } + + if (func != NULL && ctrl != NULL) { + if (cpqhp_process_SS(ctrl, func) != 0) { + amber_LED_on (ctrl, hp_slot); + green_LED_on (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + } + } + + p_slot->state = STATIC_STATE; + } else { + p_slot->state = POWERON_STATE; + // slot is off + + func = cpqhp_slot_find(p_slot->bus, p_slot->device, 0); + dbg("In add_board, func = %p, ctrl = %p\n", func, ctrl); + if (!func) { + dbg("Error! func NULL in %s\n", __FUNCTION__); + return ; + } + + if (func != NULL && ctrl != NULL) { + if (cpqhp_process_SI(ctrl, func) != 0) { + amber_LED_on (ctrl, hp_slot); + green_LED_off (ctrl, hp_slot); + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + } + } + + p_slot->state = STATIC_STATE; + } + + return; +} + + +int cpqhp_process_SI (struct controller *ctrl, struct pci_func *func) +{ + u8 device, hp_slot; + u16 temp_word; + u32 tempdword; + int rc; + struct slot* p_slot; + int physical_slot = 0; + + if (!ctrl) + return(1); + + tempdword = 0; + + device = func->device; + hp_slot = device - ctrl->slot_device_offset; + p_slot = cpqhp_find_slot(ctrl, device); + if (p_slot) { + physical_slot = p_slot->number; + } + + // Check to see if the interlock is closed + tempdword = readl(ctrl->hpc_reg + INT_INPUT_CLEAR); + + if (tempdword & (0x01 << hp_slot)) { + return(1); + } + + if (func->is_a_board) { + rc = board_replaced(func, ctrl); + } else { + // add board + slot_remove(func); + + func = cpqhp_slot_create(ctrl->bus); + if (func == NULL) { + return(1); + } + + func->bus = ctrl->bus; + func->device = device; + func->function = 0; + func->configured = 0; + func->is_a_board = 1; + + // We have to save the presence info for these slots + temp_word = ctrl->ctrl_int_comp >> 16; + func->presence_save = (temp_word >> hp_slot) & 0x01; + func->presence_save |= (temp_word >> (hp_slot + 7)) & 0x02; + + if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) { + func->switch_save = 0; + } else { + func->switch_save = 0x10; + } + + rc = board_added(func, ctrl); + if (rc) { + if (is_bridge(func)) { + bridge_slot_remove(func); + } else + slot_remove(func); + + // Setup slot structure with entry for empty slot + func = cpqhp_slot_create(ctrl->bus); + + if (func == NULL) { + // Out of memory + return(1); + } + + func->bus = ctrl->bus; + func->device = device; + func->function = 0; + func->configured = 0; + func->is_a_board = 0; + + // We have to save the presence info for these slots + temp_word = ctrl->ctrl_int_comp >> 16; + func->presence_save = (temp_word >> hp_slot) & 0x01; + func->presence_save |= + (temp_word >> (hp_slot + 7)) & 0x02; + + if (ctrl->ctrl_int_comp & (0x1L << hp_slot)) { + func->switch_save = 0; + } else { + func->switch_save = 0x10; + } + } + } + + if (rc) { + dbg("%s: rc = %d\n", __FUNCTION__, rc); + } + + if (p_slot) + update_slot_info(ctrl, p_slot); + + return rc; +} + + +int cpqhp_process_SS (struct controller *ctrl, struct pci_func *func) +{ + u8 device, class_code, header_type, BCR; + u8 index = 0; + u8 replace_flag; + u32 rc = 0; + unsigned int devfn; + struct slot* p_slot; + struct pci_bus *pci_bus = ctrl->pci_bus; + int physical_slot=0; + + device = func->device; + func = cpqhp_slot_find(ctrl->bus, device, index++); + p_slot = cpqhp_find_slot(ctrl, device); + if (p_slot) { + physical_slot = p_slot->number; + } + + // Make sure there are no video controllers here + while (func && !rc) { + pci_bus->number = func->bus; + devfn = PCI_DEVFN(func->device, func->function); + + // Check the Class Code + rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); + if (rc) + return rc; + + if (class_code == PCI_BASE_CLASS_DISPLAY) { + /* Display/Video adapter (not supported) */ + rc = REMOVE_NOT_SUPPORTED; + } else { + // See if it's a bridge + rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); + if (rc) + return rc; + + // If it's a bridge, check the VGA Enable bit + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_BRIDGE_CONTROL, &BCR); + if (rc) + return rc; + + // If the VGA Enable bit is set, remove isn't supported + if (BCR & PCI_BRIDGE_CTL_VGA) { + rc = REMOVE_NOT_SUPPORTED; + } + } + } + + func = cpqhp_slot_find(ctrl->bus, device, index++); + } + + func = cpqhp_slot_find(ctrl->bus, device, 0); + if ((func != NULL) && !rc) { + //FIXME: Replace flag should be passed into process_SS + replace_flag = !(ctrl->add_support); + rc = remove_board(func, replace_flag, ctrl); + } else if (!rc) { + rc = 1; + } + + if (p_slot) + update_slot_info(ctrl, p_slot); + + return(rc); +} + + + +/** + * hardware_test - runs hardware tests + * + * For hot plug ctrl folks to play with. + * test_num is the number entered in the GUI + * + */ +int cpqhp_hardware_test(struct controller *ctrl, int test_num) +{ + u32 save_LED; + u32 work_LED; + int loop; + int num_of_slots; + + num_of_slots = readb(ctrl->hpc_reg + SLOT_MASK) & 0x0f; + + switch (test_num) { + case 1: + // Do stuff here! + + // Do that funky LED thing + save_LED = readl(ctrl->hpc_reg + LED_CONTROL); // so we can restore them later + work_LED = 0x01010101; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + for (loop = 0; loop < num_of_slots; loop++) { + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + work_LED = work_LED << 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + long_delay((2*HZ)/10); + } + for (loop = 0; loop < num_of_slots; loop++) { + work_LED = work_LED >> 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + long_delay((2*HZ)/10); + } + for (loop = 0; loop < num_of_slots; loop++) { + work_LED = work_LED << 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + long_delay((2*HZ)/10); + } + for (loop = 0; loop < num_of_slots; loop++) { + work_LED = work_LED >> 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + long_delay((2*HZ)/10); + } + + work_LED = 0x01010000; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + for (loop = 0; loop < num_of_slots; loop++) { + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + work_LED = work_LED << 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + long_delay((2*HZ)/10); + } + for (loop = 0; loop < num_of_slots; loop++) { + work_LED = work_LED >> 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + long_delay((2*HZ)/10); + } + work_LED = 0x00000101; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + for (loop = 0; loop < num_of_slots; loop++) { + work_LED = work_LED << 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + long_delay((2*HZ)/10); + } + for (loop = 0; loop < num_of_slots; loop++) { + work_LED = work_LED >> 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + long_delay((2*HZ)/10); + } + + + work_LED = 0x01010000; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + for (loop = 0; loop < num_of_slots; loop++) { + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + long_delay((3*HZ)/10); + work_LED = work_LED >> 16; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + + set_SOGO(ctrl); + + // Wait for SOGO interrupt + wait_for_ctrl_irq (ctrl); + + // Get ready for next iteration + long_delay((3*HZ)/10); + work_LED = work_LED << 16; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + work_LED = work_LED << 1; + writel(work_LED, ctrl->hpc_reg + LED_CONTROL); + } + + writel (save_LED, ctrl->hpc_reg + LED_CONTROL); // put it back the way it was + + set_SOGO(ctrl); + + // Wait for SOBS to be unset + wait_for_ctrl_irq (ctrl); + break; + case 2: + // Do other stuff here! + break; + case 3: + // and more... + break; + } + return 0; +} + + +/** + * configure_new_device - Configures the PCI header information of one board. + * + * @ctrl: pointer to controller structure + * @func: pointer to function structure + * @behind_bridge: 1 if this is a recursive call, 0 if not + * @resources: pointer to set of resource lists + * + * Returns 0 if success + * + */ +static u32 configure_new_device (struct controller * ctrl, struct pci_func * func, + u8 behind_bridge, struct resource_lists * resources) +{ + u8 temp_byte, function, max_functions, stop_it; + int rc; + u32 ID; + struct pci_func *new_slot; + int index; + + new_slot = func; + + dbg("%s\n", __FUNCTION__); + // Check for Multi-function device + ctrl->pci_bus->number = func->bus; + rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(func->device, func->function), 0x0E, &temp_byte); + if (rc) { + dbg("%s: rc = %d\n", __FUNCTION__, rc); + return rc; + } + + if (temp_byte & 0x80) // Multi-function device + max_functions = 8; + else + max_functions = 1; + + function = 0; + + do { + rc = configure_new_function(ctrl, new_slot, behind_bridge, resources); + + if (rc) { + dbg("configure_new_function failed %d\n",rc); + index = 0; + + while (new_slot) { + new_slot = cpqhp_slot_find(new_slot->bus, new_slot->device, index++); + + if (new_slot) + cpqhp_return_board_resources(new_slot, resources); + } + + return(rc); + } + + function++; + + stop_it = 0; + + // The following loop skips to the next present function + // and creates a board structure + + while ((function < max_functions) && (!stop_it)) { + pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(func->device, function), 0x00, &ID); + + if (ID == 0xFFFFFFFF) { // There's nothing there. + function++; + } else { // There's something there + // Setup slot structure. + new_slot = cpqhp_slot_create(func->bus); + + if (new_slot == NULL) { + // Out of memory + return(1); + } + + new_slot->bus = func->bus; + new_slot->device = func->device; + new_slot->function = function; + new_slot->is_a_board = 1; + new_slot->status = 0; + + stop_it++; + } + } + + } while (function < max_functions); + dbg("returning from configure_new_device\n"); + + return 0; +} + + +/* + Configuration logic that involves the hotplug data structures and + their bookkeeping + */ + + +/** + * configure_new_function - Configures the PCI header information of one device + * + * @ctrl: pointer to controller structure + * @func: pointer to function structure + * @behind_bridge: 1 if this is a recursive call, 0 if not + * @resources: pointer to set of resource lists + * + * Calls itself recursively for bridged devices. + * Returns 0 if success + * + */ +static int configure_new_function (struct controller * ctrl, struct pci_func * func, + u8 behind_bridge, struct resource_lists * resources) +{ + int cloop; + u8 IRQ; + u8 temp_byte; + u8 device; + u8 class_code; + u16 command; + u16 temp_word; + u32 temp_dword; + u32 rc; + u32 temp_register; + u32 base; + u32 ID; + unsigned int devfn; + struct pci_resource *mem_node; + struct pci_resource *p_mem_node; + struct pci_resource *io_node; + struct pci_resource *bus_node; + struct pci_resource *hold_mem_node; + struct pci_resource *hold_p_mem_node; + struct pci_resource *hold_IO_node; + struct pci_resource *hold_bus_node; + struct irq_mapping irqs; + struct pci_func *new_slot; + struct pci_bus *pci_bus; + struct resource_lists temp_resources; + + pci_bus = ctrl->pci_bus; + pci_bus->number = func->bus; + devfn = PCI_DEVFN(func->device, func->function); + + // Check for Bridge + rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &temp_byte); + if (rc) + return rc; + + if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge + // set Primary bus + dbg("set Primary bus = %d\n", func->bus); + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_PRIMARY_BUS, func->bus); + if (rc) + return rc; + + // find range of busses to use + dbg("find ranges of buses to use\n"); + bus_node = get_max_resource(&resources->bus_head, 1); + + // If we don't have any busses to allocate, we can't continue + if (!bus_node) + return -ENOMEM; + + // set Secondary bus + temp_byte = bus_node->base; + dbg("set Secondary bus = %d\n", bus_node->base); + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, temp_byte); + if (rc) + return rc; + + // set subordinate bus + temp_byte = bus_node->base + bus_node->length - 1; + dbg("set subordinate bus = %d\n", bus_node->base + bus_node->length - 1); + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte); + if (rc) + return rc; + + // set subordinate Latency Timer and base Latency Timer + temp_byte = 0x40; + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SEC_LATENCY_TIMER, temp_byte); + if (rc) + return rc; + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte); + if (rc) + return rc; + + // set Cache Line size + temp_byte = 0x08; + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte); + if (rc) + return rc; + + // Setup the IO, memory, and prefetchable windows + + io_node = get_max_resource(&(resources->io_head), 0x1000); + if (!io_node) + return -ENOMEM; + mem_node = get_max_resource(&(resources->mem_head), 0x100000); + if (!mem_node) + return -ENOMEM; + p_mem_node = get_max_resource(&(resources->p_mem_head), 0x100000); + if (!p_mem_node) + return -ENOMEM; + dbg("Setup the IO, memory, and prefetchable windows\n"); + dbg("io_node\n"); + dbg("(base, len, next) (%x, %x, %p)\n", io_node->base, io_node->length, io_node->next); + dbg("mem_node\n"); + dbg("(base, len, next) (%x, %x, %p)\n", mem_node->base, mem_node->length, mem_node->next); + dbg("p_mem_node\n"); + dbg("(base, len, next) (%x, %x, %p)\n", p_mem_node->base, p_mem_node->length, p_mem_node->next); + + // set up the IRQ info + if (!resources->irqs) { + irqs.barber_pole = 0; + irqs.interrupt[0] = 0; + irqs.interrupt[1] = 0; + irqs.interrupt[2] = 0; + irqs.interrupt[3] = 0; + irqs.valid_INT = 0; + } else { + irqs.barber_pole = resources->irqs->barber_pole; + irqs.interrupt[0] = resources->irqs->interrupt[0]; + irqs.interrupt[1] = resources->irqs->interrupt[1]; + irqs.interrupt[2] = resources->irqs->interrupt[2]; + irqs.interrupt[3] = resources->irqs->interrupt[3]; + irqs.valid_INT = resources->irqs->valid_INT; + } + + // set up resource lists that are now aligned on top and bottom + // for anything behind the bridge. + temp_resources.bus_head = bus_node; + temp_resources.io_head = io_node; + temp_resources.mem_head = mem_node; + temp_resources.p_mem_head = p_mem_node; + temp_resources.irqs = &irqs; + + // Make copies of the nodes we are going to pass down so that + // if there is a problem,we can just use these to free resources + hold_bus_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + hold_IO_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + hold_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + hold_p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!hold_bus_node || !hold_IO_node || !hold_mem_node || !hold_p_mem_node) { + if (hold_bus_node) + kfree(hold_bus_node); + if (hold_IO_node) + kfree(hold_IO_node); + if (hold_mem_node) + kfree(hold_mem_node); + if (hold_p_mem_node) + kfree(hold_p_mem_node); + + return(1); + } + + memcpy(hold_bus_node, bus_node, sizeof(struct pci_resource)); + + bus_node->base += 1; + bus_node->length -= 1; + bus_node->next = NULL; + + // If we have IO resources copy them and fill in the bridge's + // IO range registers + if (io_node) { + memcpy(hold_IO_node, io_node, sizeof(struct pci_resource)); + io_node->next = NULL; + + // set IO base and Limit registers + temp_byte = io_node->base >> 8; + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_BASE, temp_byte); + + temp_byte = (io_node->base + io_node->length - 1) >> 8; + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte); + } else { + kfree(hold_IO_node); + hold_IO_node = NULL; + } + + // If we have memory resources copy them and fill in the bridge's + // memory range registers. Otherwise, fill in the range + // registers with values that disable them. + if (mem_node) { + memcpy(hold_mem_node, mem_node, sizeof(struct pci_resource)); + mem_node->next = NULL; + + // set Mem base and Limit registers + temp_word = mem_node->base >> 16; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word); + + temp_word = (mem_node->base + mem_node->length - 1) >> 16; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); + } else { + temp_word = 0xFFFF; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word); + + temp_word = 0x0000; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); + + kfree(hold_mem_node); + hold_mem_node = NULL; + } + + // If we have prefetchable memory resources copy them and + // fill in the bridge's memory range registers. Otherwise, + // fill in the range registers with values that disable them. + if (p_mem_node) { + memcpy(hold_p_mem_node, p_mem_node, sizeof(struct pci_resource)); + p_mem_node->next = NULL; + + // set Pre Mem base and Limit registers + temp_word = p_mem_node->base >> 16; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word); + + temp_word = (p_mem_node->base + p_mem_node->length - 1) >> 16; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); + } else { + temp_word = 0xFFFF; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word); + + temp_word = 0x0000; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); + + kfree(hold_p_mem_node); + hold_p_mem_node = NULL; + } + + // Adjust this to compensate for extra adjustment in first loop + irqs.barber_pole--; + + rc = 0; + + // Here we actually find the devices and configure them + for (device = 0; (device <= 0x1F) && !rc; device++) { + irqs.barber_pole = (irqs.barber_pole + 1) & 0x03; + + ID = 0xFFFFFFFF; + pci_bus->number = hold_bus_node->base; + pci_bus_read_config_dword (pci_bus, PCI_DEVFN(device, 0), 0x00, &ID); + pci_bus->number = func->bus; + + if (ID != 0xFFFFFFFF) { // device Present + // Setup slot structure. + new_slot = cpqhp_slot_create(hold_bus_node->base); + + if (new_slot == NULL) { + // Out of memory + rc = -ENOMEM; + continue; + } + + new_slot->bus = hold_bus_node->base; + new_slot->device = device; + new_slot->function = 0; + new_slot->is_a_board = 1; + new_slot->status = 0; + + rc = configure_new_device(ctrl, new_slot, 1, &temp_resources); + dbg("configure_new_device rc=0x%x\n",rc); + } // End of IF (device in slot?) + } // End of FOR loop + + if (rc) { + cpqhp_destroy_resource_list(&temp_resources); + + return_resource(&(resources->bus_head), hold_bus_node); + return_resource(&(resources->io_head), hold_IO_node); + return_resource(&(resources->mem_head), hold_mem_node); + return_resource(&(resources->p_mem_head), hold_p_mem_node); + return(rc); + } + // save the interrupt routing information + if (resources->irqs) { + resources->irqs->interrupt[0] = irqs.interrupt[0]; + resources->irqs->interrupt[1] = irqs.interrupt[1]; + resources->irqs->interrupt[2] = irqs.interrupt[2]; + resources->irqs->interrupt[3] = irqs.interrupt[3]; + resources->irqs->valid_INT = irqs.valid_INT; + } else if (!behind_bridge) { + // We need to hook up the interrupts here + for (cloop = 0; cloop < 4; cloop++) { + if (irqs.valid_INT & (0x01 << cloop)) { + rc = cpqhp_set_irq(func->bus, func->device, + 0x0A + cloop, irqs.interrupt[cloop]); + if (rc) { + cpqhp_destroy_resource_list (&temp_resources); + + return_resource(&(resources-> bus_head), hold_bus_node); + return_resource(&(resources-> io_head), hold_IO_node); + return_resource(&(resources-> mem_head), hold_mem_node); + return_resource(&(resources-> p_mem_head), hold_p_mem_node); + return rc; + } + } + } // end of for loop + } + // Return unused bus resources + // First use the temporary node to store information for the board + if (hold_bus_node && bus_node && temp_resources.bus_head) { + hold_bus_node->length = bus_node->base - hold_bus_node->base; + + hold_bus_node->next = func->bus_head; + func->bus_head = hold_bus_node; + + temp_byte = temp_resources.bus_head->base - 1; + + // set subordinate bus + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, temp_byte); + + if (temp_resources.bus_head->length == 0) { + kfree(temp_resources.bus_head); + temp_resources.bus_head = NULL; + } else { + return_resource(&(resources->bus_head), temp_resources.bus_head); + } + } + + // If we have IO space available and there is some left, + // return the unused portion + if (hold_IO_node && temp_resources.io_head) { + io_node = do_pre_bridge_resource_split(&(temp_resources.io_head), + &hold_IO_node, 0x1000); + + // Check if we were able to split something off + if (io_node) { + hold_IO_node->base = io_node->base + io_node->length; + + temp_byte = (hold_IO_node->base) >> 8; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_IO_BASE, temp_byte); + + return_resource(&(resources->io_head), io_node); + } + + io_node = do_bridge_resource_split(&(temp_resources.io_head), 0x1000); + + // Check if we were able to split something off + if (io_node) { + // First use the temporary node to store information for the board + hold_IO_node->length = io_node->base - hold_IO_node->base; + + // If we used any, add it to the board's list + if (hold_IO_node->length) { + hold_IO_node->next = func->io_head; + func->io_head = hold_IO_node; + + temp_byte = (io_node->base - 1) >> 8; + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_IO_LIMIT, temp_byte); + + return_resource(&(resources->io_head), io_node); + } else { + // it doesn't need any IO + temp_word = 0x0000; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_IO_LIMIT, temp_word); + + return_resource(&(resources->io_head), io_node); + kfree(hold_IO_node); + } + } else { + // it used most of the range + hold_IO_node->next = func->io_head; + func->io_head = hold_IO_node; + } + } else if (hold_IO_node) { + // it used the whole range + hold_IO_node->next = func->io_head; + func->io_head = hold_IO_node; + } + // If we have memory space available and there is some left, + // return the unused portion + if (hold_mem_node && temp_resources.mem_head) { + mem_node = do_pre_bridge_resource_split(&(temp_resources. mem_head), + &hold_mem_node, 0x100000); + + // Check if we were able to split something off + if (mem_node) { + hold_mem_node->base = mem_node->base + mem_node->length; + + temp_word = (hold_mem_node->base) >> 16; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_BASE, temp_word); + + return_resource(&(resources->mem_head), mem_node); + } + + mem_node = do_bridge_resource_split(&(temp_resources.mem_head), 0x100000); + + // Check if we were able to split something off + if (mem_node) { + // First use the temporary node to store information for the board + hold_mem_node->length = mem_node->base - hold_mem_node->base; + + if (hold_mem_node->length) { + hold_mem_node->next = func->mem_head; + func->mem_head = hold_mem_node; + + // configure end address + temp_word = (mem_node->base - 1) >> 16; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); + + // Return unused resources to the pool + return_resource(&(resources->mem_head), mem_node); + } else { + // it doesn't need any Mem + temp_word = 0x0000; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, temp_word); + + return_resource(&(resources->mem_head), mem_node); + kfree(hold_mem_node); + } + } else { + // it used most of the range + hold_mem_node->next = func->mem_head; + func->mem_head = hold_mem_node; + } + } else if (hold_mem_node) { + // it used the whole range + hold_mem_node->next = func->mem_head; + func->mem_head = hold_mem_node; + } + // If we have prefetchable memory space available and there is some + // left at the end, return the unused portion + if (hold_p_mem_node && temp_resources.p_mem_head) { + p_mem_node = do_pre_bridge_resource_split(&(temp_resources.p_mem_head), + &hold_p_mem_node, 0x100000); + + // Check if we were able to split something off + if (p_mem_node) { + hold_p_mem_node->base = p_mem_node->base + p_mem_node->length; + + temp_word = (hold_p_mem_node->base) >> 16; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, temp_word); + + return_resource(&(resources->p_mem_head), p_mem_node); + } + + p_mem_node = do_bridge_resource_split(&(temp_resources.p_mem_head), 0x100000); + + // Check if we were able to split something off + if (p_mem_node) { + // First use the temporary node to store information for the board + hold_p_mem_node->length = p_mem_node->base - hold_p_mem_node->base; + + // If we used any, add it to the board's list + if (hold_p_mem_node->length) { + hold_p_mem_node->next = func->p_mem_head; + func->p_mem_head = hold_p_mem_node; + + temp_word = (p_mem_node->base - 1) >> 16; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); + + return_resource(&(resources->p_mem_head), p_mem_node); + } else { + // it doesn't need any PMem + temp_word = 0x0000; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, temp_word); + + return_resource(&(resources->p_mem_head), p_mem_node); + kfree(hold_p_mem_node); + } + } else { + // it used the most of the range + hold_p_mem_node->next = func->p_mem_head; + func->p_mem_head = hold_p_mem_node; + } + } else if (hold_p_mem_node) { + // it used the whole range + hold_p_mem_node->next = func->p_mem_head; + func->p_mem_head = hold_p_mem_node; + } + // We should be configuring an IRQ and the bridge's base address + // registers if it needs them. Although we have never seen such + // a device + + // enable card + command = 0x0157; // = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | PCI_COMMAND_SERR + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_COMMAND, command); + + // set Bridge Control Register + command = 0x07; // = PCI_BRIDGE_CTL_PARITY | PCI_BRIDGE_CTL_SERR | PCI_BRIDGE_CTL_NO_ISA + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_BRIDGE_CONTROL, command); + } else if ((temp_byte & 0x7F) == PCI_HEADER_TYPE_NORMAL) { + // Standard device + rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); + + if (class_code == PCI_BASE_CLASS_DISPLAY) { + // Display (video) adapter (not supported) + return(DEVICE_TYPE_NOT_SUPPORTED); + } + // Figure out IO and memory needs + for (cloop = 0x10; cloop <= 0x24; cloop += 4) { + temp_register = 0xFFFFFFFF; + + dbg("CND: bus=%d, devfn=%d, offset=%d\n", pci_bus->number, devfn, cloop); + rc = pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); + + rc = pci_bus_read_config_dword (pci_bus, devfn, cloop, &temp_register); + dbg("CND: base = 0x%x\n", temp_register); + + if (temp_register) { // If this register is implemented + if ((temp_register & 0x03L) == 0x01) { + // Map IO + + // set base = amount of IO space + base = temp_register & 0xFFFFFFFC; + base = ~base + 1; + + dbg("CND: length = 0x%x\n", base); + io_node = get_io_resource(&(resources->io_head), base); + dbg("Got io_node start = %8.8x, length = %8.8x next (%p)\n", + io_node->base, io_node->length, io_node->next); + dbg("func (%p) io_head (%p)\n", func, func->io_head); + + // allocate the resource to the board + if (io_node) { + base = io_node->base; + + io_node->next = func->io_head; + func->io_head = io_node; + } else + return -ENOMEM; + } else if ((temp_register & 0x0BL) == 0x08) { + // Map prefetchable memory + base = temp_register & 0xFFFFFFF0; + base = ~base + 1; + + dbg("CND: length = 0x%x\n", base); + p_mem_node = get_resource(&(resources->p_mem_head), base); + + // allocate the resource to the board + if (p_mem_node) { + base = p_mem_node->base; + + p_mem_node->next = func->p_mem_head; + func->p_mem_head = p_mem_node; + } else + return -ENOMEM; + } else if ((temp_register & 0x0BL) == 0x00) { + // Map memory + base = temp_register & 0xFFFFFFF0; + base = ~base + 1; + + dbg("CND: length = 0x%x\n", base); + mem_node = get_resource(&(resources->mem_head), base); + + // allocate the resource to the board + if (mem_node) { + base = mem_node->base; + + mem_node->next = func->mem_head; + func->mem_head = mem_node; + } else + return -ENOMEM; + } else if ((temp_register & 0x0BL) == 0x04) { + // Map memory + base = temp_register & 0xFFFFFFF0; + base = ~base + 1; + + dbg("CND: length = 0x%x\n", base); + mem_node = get_resource(&(resources->mem_head), base); + + // allocate the resource to the board + if (mem_node) { + base = mem_node->base; + + mem_node->next = func->mem_head; + func->mem_head = mem_node; + } else + return -ENOMEM; + } else if ((temp_register & 0x0BL) == 0x06) { + // Those bits are reserved, we can't handle this + return(1); + } else { + // Requesting space below 1M + return(NOT_ENOUGH_RESOURCES); + } + + rc = pci_bus_write_config_dword (pci_bus, devfn, cloop, base); + + // Check for 64-bit base + if ((temp_register & 0x07L) == 0x04) { + cloop += 4; + + // Upper 32 bits of address always zero on today's systems + // FIXME this is probably not true on Alpha and ia64??? + base = 0; + rc = pci_bus_write_config_dword (pci_bus, devfn, cloop, base); + } + } + } // End of base register loop + + // Figure out which interrupt pin this function uses + rc = pci_bus_read_config_byte (pci_bus, devfn, PCI_INTERRUPT_PIN, &temp_byte); + + // If this function needs an interrupt and we are behind a bridge + // and the pin is tied to something that's alread mapped, + // set this one the same + if (temp_byte && resources->irqs && + (resources->irqs->valid_INT & + (0x01 << ((temp_byte + resources->irqs->barber_pole - 1) & 0x03)))) { + // We have to share with something already set up + IRQ = resources->irqs->interrupt[(temp_byte + resources->irqs->barber_pole - 1) & 0x03]; + } else { + // Program IRQ based on card type + rc = pci_bus_read_config_byte (pci_bus, devfn, 0x0B, &class_code); + + if (class_code == PCI_BASE_CLASS_STORAGE) { + IRQ = cpqhp_disk_irq; + } else { + IRQ = cpqhp_nic_irq; + } + } + + // IRQ Line + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_INTERRUPT_LINE, IRQ); + + if (!behind_bridge) { + rc = cpqhp_set_irq(func->bus, func->device, temp_byte + 0x09, IRQ); + if (rc) + return(1); + } else { + //TBD - this code may also belong in the other clause of this If statement + resources->irqs->interrupt[(temp_byte + resources->irqs->barber_pole - 1) & 0x03] = IRQ; + resources->irqs->valid_INT |= 0x01 << (temp_byte + resources->irqs->barber_pole - 1) & 0x03; + } + + // Latency Timer + temp_byte = 0x40; + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_LATENCY_TIMER, temp_byte); + + // Cache Line size + temp_byte = 0x08; + rc = pci_bus_write_config_byte (pci_bus, devfn, PCI_CACHE_LINE_SIZE, temp_byte); + + // disable ROM base Address + temp_dword = 0x00L; + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_ROM_ADDRESS, temp_dword); + + // enable card + temp_word = 0x0157; // = PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE | PCI_COMMAND_PARITY | PCI_COMMAND_SERR + rc = pci_bus_write_config_word (pci_bus, devfn, PCI_COMMAND, temp_word); + } // End of Not-A-Bridge else + else { + // It's some strange type of PCI adapter (Cardbus?) + return(DEVICE_TYPE_NOT_SUPPORTED); + } + + func->configured = 1; + + return 0; +} + diff -Nru a/drivers/pci/hotplug/cpqphp_nvram.c b/drivers/pci/hotplug/cpqphp_nvram.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pci/hotplug/cpqphp_nvram.c Mon Jun 9 23:16:18 2003 @@ -0,0 +1,667 @@ +/* + * Compaq Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Send feedback to <greg@kroah.com> + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/proc_fs.h> +#include <linux/miscdevice.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#include <linux/pci.h> +#include <linux/init.h> +#include <asm/uaccess.h> +#include "cpqphp.h" +#include "cpqphp_nvram.h" + + +#define ROM_INT15_PHY_ADDR 0x0FF859 +#define READ_EV 0xD8A4 +#define WRITE_EV 0xD8A5 + +struct register_foo { + union { + unsigned long lword; /* eax */ + unsigned short word; /* ax */ + + struct { + unsigned char low; /* al */ + unsigned char high; /* ah */ + } byte; + } data; + + unsigned char opcode; /* see below */ + unsigned long length; /* if the reg. is a pointer, how much data */ +} __attribute__ ((packed)); + +struct all_reg { + struct register_foo eax_reg; + struct register_foo ebx_reg; + struct register_foo ecx_reg; + struct register_foo edx_reg; + struct register_foo edi_reg; + struct register_foo esi_reg; + struct register_foo eflags_reg; +} __attribute__ ((packed)); + + +struct ev_hrt_header { + u8 Version; + u8 num_of_ctrl; + u8 next; +}; + +struct ev_hrt_ctrl { + u8 bus; + u8 device; + u8 function; + u8 mem_avail; + u8 p_mem_avail; + u8 io_avail; + u8 bus_avail; + u8 next; +}; + + +static u8 evbuffer_init; +static u8 evbuffer_length; +static u8 evbuffer[1024]; + +static void *compaq_int15_entry_point; + +static spinlock_t int15_lock; /* lock for ordering int15_bios_call() */ + + +/* This is a series of function that deals with + setting & getting the hotplug resource table in some environment variable. +*/ + +/* + * We really shouldn't be doing this unless there is a _very_ good reason to!!! + * greg k-h + */ + + +static u32 add_byte( u32 **p_buffer, u8 value, u32 *used, u32 *avail) +{ + u8 **tByte; + + if ((*used + 1) > *avail) + return(1); + + *((u8*)*p_buffer) = value; + tByte = (u8**)p_buffer; + (*tByte)++; + *used+=1; + return(0); +} + + +static u32 add_dword( u32 **p_buffer, u32 value, u32 *used, u32 *avail) +{ + if ((*used + 4) > *avail) + return(1); + + **p_buffer = value; + (*p_buffer)++; + *used+=4; + return(0); +} + + +/* + * check_for_compaq_ROM + * + * this routine verifies that the ROM OEM string is 'COMPAQ' + * + * returns 0 for non-Compaq ROM, 1 for Compaq ROM + */ +static int check_for_compaq_ROM (void *rom_start) +{ + u8 temp1, temp2, temp3, temp4, temp5, temp6; + int result = 0; + + temp1 = readb(rom_start + 0xffea + 0); + temp2 = readb(rom_start + 0xffea + 1); + temp3 = readb(rom_start + 0xffea + 2); + temp4 = readb(rom_start + 0xffea + 3); + temp5 = readb(rom_start + 0xffea + 4); + temp6 = readb(rom_start + 0xffea + 5); + if ((temp1 == 'C') && + (temp2 == 'O') && + (temp3 == 'M') && + (temp4 == 'P') && + (temp5 == 'A') && + (temp6 == 'Q')) { + result = 1; + } + dbg ("%s - returned %d\n", __FUNCTION__, result); + return result; +} + + +static u32 access_EV (u16 operation, u8 *ev_name, u8 *buffer, u32 *buf_size) +{ + unsigned long flags; + int op = operation; + int ret_val; + + if (!compaq_int15_entry_point) + return -ENODEV; + + spin_lock_irqsave(&int15_lock, flags); + __asm__ ( + "xorl %%ebx,%%ebx\n" \ + "xorl %%edx,%%edx\n" \ + "pushf\n" \ + "push %%cs\n" \ + "cli\n" \ + "call *%6\n" + : "=c" (*buf_size), "=a" (ret_val) + : "a" (op), "c" (*buf_size), "S" (ev_name), + "D" (buffer), "m" (compaq_int15_entry_point) + : "%ebx", "%edx"); + spin_unlock_irqrestore(&int15_lock, flags); + + return((ret_val & 0xFF00) >> 8); +} + + +/* + * load_HRT + * + * Read the hot plug Resource Table from NVRAM + */ +static int load_HRT (void *rom_start) +{ + u32 available; + u32 temp_dword; + u8 temp_byte = 0xFF; + u32 rc; + + if (!check_for_compaq_ROM(rom_start)) { + return -ENODEV; + } + + available = 1024; + + // Now load the EV + temp_dword = available; + + rc = access_EV(READ_EV, "CQTHPS", evbuffer, &temp_dword); + + evbuffer_length = temp_dword; + + // We're maintaining the resource lists so write FF to invalidate old info + temp_dword = 1; + + rc = access_EV(WRITE_EV, "CQTHPS", &temp_byte, &temp_dword); + + return rc; +} + + +/* + * store_HRT + * + * Save the hot plug Resource Table in NVRAM + */ +static u32 store_HRT (void *rom_start) +{ + u32 *buffer; + u32 *pFill; + u32 usedbytes; + u32 available; + u32 temp_dword; + u32 rc; + u8 loop; + u8 numCtrl = 0; + struct controller *ctrl; + struct pci_resource *resNode; + struct ev_hrt_header *p_EV_header; + struct ev_hrt_ctrl *p_ev_ctrl; + + available = 1024; + + if (!check_for_compaq_ROM(rom_start)) { + return(1); + } + + buffer = (u32*) evbuffer; + + if (!buffer) + return(1); + + pFill = buffer; + usedbytes = 0; + + p_EV_header = (struct ev_hrt_header *) pFill; + + ctrl = cpqhp_ctrl_list; + + // The revision of this structure + rc = add_byte( &pFill, 1 + ctrl->push_flag, &usedbytes, &available); + if (rc) + return(rc); + + // The number of controllers + rc = add_byte( &pFill, 1, &usedbytes, &available); + if (rc) + return(rc); + + while (ctrl) { + p_ev_ctrl = (struct ev_hrt_ctrl *) pFill; + + numCtrl++; + + // The bus number + rc = add_byte( &pFill, ctrl->bus, &usedbytes, &available); + if (rc) + return(rc); + + // The device Number + rc = add_byte( &pFill, PCI_SLOT(ctrl->pci_dev->devfn), &usedbytes, &available); + if (rc) + return(rc); + + // The function Number + rc = add_byte( &pFill, PCI_FUNC(ctrl->pci_dev->devfn), &usedbytes, &available); + if (rc) + return(rc); + + // Skip the number of available entries + rc = add_dword( &pFill, 0, &usedbytes, &available); + if (rc) + return(rc); + + // Figure out memory Available + + resNode = ctrl->mem_head; + + loop = 0; + + while (resNode) { + loop ++; + + // base + rc = add_dword( &pFill, resNode->base, &usedbytes, &available); + if (rc) + return(rc); + + // length + rc = add_dword( &pFill, resNode->length, &usedbytes, &available); + if (rc) + return(rc); + + resNode = resNode->next; + } + + // Fill in the number of entries + p_ev_ctrl->mem_avail = loop; + + // Figure out prefetchable memory Available + + resNode = ctrl->p_mem_head; + + loop = 0; + + while (resNode) { + loop ++; + + // base + rc = add_dword( &pFill, resNode->base, &usedbytes, &available); + if (rc) + return(rc); + + // length + rc = add_dword( &pFill, resNode->length, &usedbytes, &available); + if (rc) + return(rc); + + resNode = resNode->next; + } + + // Fill in the number of entries + p_ev_ctrl->p_mem_avail = loop; + + // Figure out IO Available + + resNode = ctrl->io_head; + + loop = 0; + + while (resNode) { + loop ++; + + // base + rc = add_dword( &pFill, resNode->base, &usedbytes, &available); + if (rc) + return(rc); + + // length + rc = add_dword( &pFill, resNode->length, &usedbytes, &available); + if (rc) + return(rc); + + resNode = resNode->next; + } + + // Fill in the number of entries + p_ev_ctrl->io_avail = loop; + + // Figure out bus Available + + resNode = ctrl->bus_head; + + loop = 0; + + while (resNode) { + loop ++; + + // base + rc = add_dword( &pFill, resNode->base, &usedbytes, &available); + if (rc) + return(rc); + + // length + rc = add_dword( &pFill, resNode->length, &usedbytes, &available); + if (rc) + return(rc); + + resNode = resNode->next; + } + + // Fill in the number of entries + p_ev_ctrl->bus_avail = loop; + + ctrl = ctrl->next; + } + + p_EV_header->num_of_ctrl = numCtrl; + + // Now store the EV + + temp_dword = usedbytes; + + rc = access_EV(WRITE_EV, "CQTHPS", (u8*) buffer, &temp_dword); + + dbg("usedbytes = 0x%x, length = 0x%x\n", usedbytes, temp_dword); + + evbuffer_length = temp_dword; + + if (rc) { + err(msg_unable_to_save); + return(1); + } + + return(0); +} + + +void compaq_nvram_init (void *rom_start) +{ + if (rom_start) { + compaq_int15_entry_point = (rom_start + ROM_INT15_PHY_ADDR - ROM_PHY_ADDR); + } + dbg("int15 entry = %p\n", compaq_int15_entry_point); + + /* initialize our int15 lock */ + spin_lock_init(&int15_lock); +} + + +int compaq_nvram_load (void *rom_start, struct controller *ctrl) +{ + u8 bus, device, function; + u8 nummem, numpmem, numio, numbus; + u32 rc; + u8 *p_byte; + struct pci_resource *mem_node; + struct pci_resource *p_mem_node; + struct pci_resource *io_node; + struct pci_resource *bus_node; + struct ev_hrt_ctrl *p_ev_ctrl; + struct ev_hrt_header *p_EV_header; + + if (!evbuffer_init) { + // Read the resource list information in from NVRAM + if (load_HRT(rom_start)) + memset (evbuffer, 0, 1024); + + evbuffer_init = 1; + } + + // If we saved information in NVRAM, use it now + p_EV_header = (struct ev_hrt_header *) evbuffer; + + // The following code is for systems where version 1.0 of this + // driver has been loaded, but doesn't support the hardware. + // In that case, the driver would incorrectly store something + // in NVRAM. + if ((p_EV_header->Version == 2) || + ((p_EV_header->Version == 1) && !ctrl->push_flag)) { + p_byte = &(p_EV_header->next); + + p_ev_ctrl = (struct ev_hrt_ctrl *) &(p_EV_header->next); + + p_byte += 3; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return 2; + + bus = p_ev_ctrl->bus; + device = p_ev_ctrl->device; + function = p_ev_ctrl->function; + + while ((bus != ctrl->bus) || + (device != PCI_SLOT(ctrl->pci_dev->devfn)) || + (function != PCI_FUNC(ctrl->pci_dev->devfn))) { + nummem = p_ev_ctrl->mem_avail; + numpmem = p_ev_ctrl->p_mem_avail; + numio = p_ev_ctrl->io_avail; + numbus = p_ev_ctrl->bus_avail; + + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return 2; + + // Skip forward to the next entry + p_byte += (nummem + numpmem + numio + numbus) * 8; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return 2; + + p_ev_ctrl = (struct ev_hrt_ctrl *) p_byte; + + p_byte += 3; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return 2; + + bus = p_ev_ctrl->bus; + device = p_ev_ctrl->device; + function = p_ev_ctrl->function; + } + + nummem = p_ev_ctrl->mem_avail; + numpmem = p_ev_ctrl->p_mem_avail; + numio = p_ev_ctrl->io_avail; + numbus = p_ev_ctrl->bus_avail; + + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) + return 2; + + while (nummem--) { + mem_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!mem_node) + break; + + mem_node->base = *(u32*)p_byte; + dbg("mem base = %8.8x\n",mem_node->base); + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) { + kfree(mem_node); + return 2; + } + + mem_node->length = *(u32*)p_byte; + dbg("mem length = %8.8x\n",mem_node->length); + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) { + kfree(mem_node); + return 2; + } + + mem_node->next = ctrl->mem_head; + ctrl->mem_head = mem_node; + } + + while (numpmem--) { + p_mem_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!p_mem_node) + break; + + p_mem_node->base = *(u32*)p_byte; + dbg("pre-mem base = %8.8x\n",p_mem_node->base); + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) { + kfree(p_mem_node); + return 2; + } + + p_mem_node->length = *(u32*)p_byte; + dbg("pre-mem length = %8.8x\n",p_mem_node->length); + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) { + kfree(p_mem_node); + return 2; + } + + p_mem_node->next = ctrl->p_mem_head; + ctrl->p_mem_head = p_mem_node; + } + + while (numio--) { + io_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!io_node) + break; + + io_node->base = *(u32*)p_byte; + dbg("io base = %8.8x\n",io_node->base); + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) { + kfree(io_node); + return 2; + } + + io_node->length = *(u32*)p_byte; + dbg("io length = %8.8x\n",io_node->length); + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) { + kfree(io_node); + return 2; + } + + io_node->next = ctrl->io_head; + ctrl->io_head = io_node; + } + + while (numbus--) { + bus_node = (struct pci_resource*) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + + if (!bus_node) + break; + + bus_node->base = *(u32*)p_byte; + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) { + kfree(bus_node); + return 2; + } + + bus_node->length = *(u32*)p_byte; + p_byte += 4; + + if (p_byte > ((u8*)p_EV_header + evbuffer_length)) { + kfree(bus_node); + return 2; + } + + bus_node->next = ctrl->bus_head; + ctrl->bus_head = bus_node; + } + + // If all of the following fail, we don't have any resources for + // hot plug add + rc = 1; + rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head)); + rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head)); + rc &= cpqhp_resource_sort_and_combine(&(ctrl->io_head)); + rc &= cpqhp_resource_sort_and_combine(&(ctrl->bus_head)); + + if (rc) + return(rc); + } else { + if ((evbuffer[0] != 0) && (!ctrl->push_flag)) + return 1; + } + + return 0; +} + + +int compaq_nvram_store (void *rom_start) +{ + int rc = 1; + + if (rom_start == NULL) + return -ENODEV; + + if (evbuffer_init) { + rc = store_HRT(rom_start); + if (rc) { + err(msg_unable_to_save); + } + } + return rc; +} + diff -Nru a/drivers/pci/hotplug/cpqphp_nvram.h b/drivers/pci/hotplug/cpqphp_nvram.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pci/hotplug/cpqphp_nvram.h Mon Jun 9 23:16:14 2003 @@ -0,0 +1,57 @@ +/* + * Compaq Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Send feedback to <greg@kroah.com> + * + */ + +#ifndef _CPQPHP_NVRAM_H +#define _CPQPHP_NVRAM_H + +#ifndef CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM + +static inline void compaq_nvram_init (void *rom_start) +{ + return; +} + +static inline int compaq_nvram_load (void *rom_start, struct controller *ctrl) +{ + return 0; +} + +static inline int compaq_nvram_store (void *rom_start) +{ + return 0; +} + +#else + +extern void compaq_nvram_init (void *rom_start); +extern int compaq_nvram_load (void *rom_start, struct controller *ctrl); +extern int compaq_nvram_store (void *rom_start); + +#endif + +#endif + diff -Nru a/drivers/pci/hotplug/cpqphp_pci.c b/drivers/pci/hotplug/cpqphp_pci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pci/hotplug/cpqphp_pci.c Mon Jun 9 23:16:18 2003 @@ -0,0 +1,1549 @@ +/* + * Compaq Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Send feedback to <greg@kroah.com> + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#include <linux/proc_fs.h> +#include <linux/pci.h> +#include "../pci.h" +#include "cpqphp.h" +#include "cpqphp_nvram.h" +#include "../../../arch/i386/pci/pci.h" /* horrible hack showing how processor dependent we are... */ + + +u8 cpqhp_nic_irq; +u8 cpqhp_disk_irq; + +static u16 unused_IRQ; + +/* + * detect_HRT_floating_pointer + * + * find the Hot Plug Resource Table in the specified region of memory. + * + */ +static void *detect_HRT_floating_pointer(void *begin, void *end) +{ + void *fp; + void *endp; + u8 temp1, temp2, temp3, temp4; + int status = 0; + + endp = (end - sizeof(struct hrt) + 1); + + for (fp = begin; fp <= endp; fp += 16) { + temp1 = readb(fp + SIG0); + temp2 = readb(fp + SIG1); + temp3 = readb(fp + SIG2); + temp4 = readb(fp + SIG3); + if (temp1 == '$' && + temp2 == 'H' && + temp3 == 'R' && + temp4 == 'T') { + status = 1; + break; + } + } + + if (!status) + fp = NULL; + + dbg("Discovered Hotplug Resource Table at %p\n", fp); + return fp; +} + + +int cpqhp_configure_device (struct controller* ctrl, struct pci_func* func) +{ + unsigned char bus; + struct pci_bus *child; + int num; + + if (func->pci_dev == NULL) + func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function)); + + /* No pci device, we need to create it then */ + if (func->pci_dev == NULL) { + dbg("INFO: pci_dev still null\n"); + + num = pci_scan_slot(ctrl->pci_dev->bus, PCI_DEVFN(func->device, func->function)); + if (num) + pci_bus_add_devices(ctrl->pci_dev->bus); + + func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function)); + if (func->pci_dev == NULL) { + dbg("ERROR: pci_dev still null\n"); + return 0; + } + } + + if (func->pci_dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) { + pci_read_config_byte(func->pci_dev, PCI_SECONDARY_BUS, &bus); + child = (struct pci_bus*) pci_add_new_bus(func->pci_dev->bus, (func->pci_dev), bus); + pci_do_scan_bus(child); + } + + return 0; +} + + +int cpqhp_unconfigure_device(struct pci_func* func) +{ + int j; + + dbg("%s: bus/dev/func = %x/%x/%x\n", __FUNCTION__, func->bus, func->device, func->function); + + for (j=0; j<8 ; j++) { + struct pci_dev* temp = pci_find_slot(func->bus, (func->device << 3) | j); + if (temp) + pci_remove_bus_device(temp); + } + return 0; +} + +static int PCI_RefinedAccessConfig(struct pci_bus *bus, unsigned int devfn, u8 offset, u32 *value) +{ + u32 vendID = 0; + + if (pci_bus_read_config_dword (bus, devfn, PCI_VENDOR_ID, &vendID) == -1) + return -1; + if (vendID == 0xffffffff) + return -1; + return pci_bus_read_config_dword (bus, devfn, offset, value); +} + + +/* + * cpqhp_set_irq + * + * @bus_num: bus number of PCI device + * @dev_num: device number of PCI device + * @slot: pointer to u8 where slot number will be returned + */ +int cpqhp_set_irq (u8 bus_num, u8 dev_num, u8 int_pin, u8 irq_num) +{ + int rc; + u16 temp_word; + struct pci_dev fakedev; + struct pci_bus fakebus; + + fakedev.devfn = dev_num << 3; + fakedev.bus = &fakebus; + fakebus.number = bus_num; + dbg("%s: dev %d, bus %d, pin %d, num %d\n", + __FUNCTION__, dev_num, bus_num, int_pin, irq_num); + rc = pcibios_set_irq_routing(&fakedev, int_pin - 0x0a, irq_num); + dbg("%s: rc %d\n", __FUNCTION__, rc); + if (!rc) + return !rc; + + // set the Edge Level Control Register (ELCR) + temp_word = inb(0x4d0); + temp_word |= inb(0x4d1) << 8; + + temp_word |= 0x01 << irq_num; + + // This should only be for x86 as it sets the Edge Level Control Register + outb((u8) (temp_word & 0xFF), 0x4d0); + outb((u8) ((temp_word & 0xFF00) >> 8), 0x4d1); + + return 0; +} + + +/* + * WTF??? This function isn't in the code, yet a function calls it, but the + * compiler optimizes it away? strange. Here as a placeholder to keep the + * compiler happy. + */ +static int PCI_ScanBusNonBridge (u8 bus, u8 device) +{ + return 0; +} + +static int PCI_ScanBusForNonBridge(struct controller *ctrl, u8 bus_num, u8 * dev_num) +{ + u8 tdevice; + u32 work; + u8 tbus; + + ctrl->pci_bus->number = bus_num; + + for (tdevice = 0; tdevice < 0x100; tdevice++) { + //Scan for access first + if (PCI_RefinedAccessConfig(ctrl->pci_bus, tdevice, 0x08, &work) == -1) + continue; + dbg("Looking for nonbridge bus_num %d dev_num %d\n", bus_num, tdevice); + //Yep we got one. Not a bridge ? + if ((work >> 8) != PCI_TO_PCI_BRIDGE_CLASS) { + *dev_num = tdevice; + dbg("found it !\n"); + return 0; + } + } + for (tdevice = 0; tdevice < 0x100; tdevice++) { + //Scan for access first + if (PCI_RefinedAccessConfig(ctrl->pci_bus, tdevice, 0x08, &work) == -1) + continue; + dbg("Looking for bridge bus_num %d dev_num %d\n", bus_num, tdevice); + //Yep we got one. bridge ? + if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) { + pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(tdevice, 0), PCI_SECONDARY_BUS, &tbus); + dbg("Recurse on bus_num %d tdevice %d\n", tbus, tdevice); + if (PCI_ScanBusNonBridge(tbus, tdevice) == 0) + return 0; + } + } + + return -1; +} + + +static int PCI_GetBusDevHelper(struct controller *ctrl, u8 *bus_num, u8 *dev_num, u8 slot, u8 nobridge) +{ + struct irq_routing_table *PCIIRQRoutingInfoLength; + long len; + long loop; + u32 work; + + u8 tbus, tdevice, tslot; + + PCIIRQRoutingInfoLength = pcibios_get_irq_routing_table(); + if (!PCIIRQRoutingInfoLength) + return -1; + + len = (PCIIRQRoutingInfoLength->size - + sizeof(struct irq_routing_table)) / sizeof(struct irq_info); + // Make sure I got at least one entry + if (len == 0) { + if (PCIIRQRoutingInfoLength != NULL) + kfree(PCIIRQRoutingInfoLength ); + return -1; + } + + for (loop = 0; loop < len; ++loop) { + tbus = PCIIRQRoutingInfoLength->slots[loop].bus; + tdevice = PCIIRQRoutingInfoLength->slots[loop].devfn; + tslot = PCIIRQRoutingInfoLength->slots[loop].slot; + + if (tslot == slot) { + *bus_num = tbus; + *dev_num = tdevice; + ctrl->pci_bus->number = tbus; + pci_bus_read_config_dword (ctrl->pci_bus, *dev_num, PCI_VENDOR_ID, &work); + if (!nobridge || (work == 0xffffffff)) { + if (PCIIRQRoutingInfoLength != NULL) + kfree(PCIIRQRoutingInfoLength ); + return 0; + } + + dbg("bus_num %d devfn %d\n", *bus_num, *dev_num); + pci_bus_read_config_dword (ctrl->pci_bus, *dev_num, PCI_CLASS_REVISION, &work); + dbg("work >> 8 (%x) = BRIDGE (%x)\n", work >> 8, PCI_TO_PCI_BRIDGE_CLASS); + + if ((work >> 8) == PCI_TO_PCI_BRIDGE_CLASS) { + pci_bus_read_config_byte (ctrl->pci_bus, *dev_num, PCI_SECONDARY_BUS, &tbus); + dbg("Scan bus for Non Bridge: bus %d\n", tbus); + if (PCI_ScanBusForNonBridge(ctrl, tbus, dev_num) == 0) { + *bus_num = tbus; + if (PCIIRQRoutingInfoLength != NULL) + kfree(PCIIRQRoutingInfoLength ); + return 0; + } + } else { + if (PCIIRQRoutingInfoLength != NULL) + kfree(PCIIRQRoutingInfoLength ); + return 0; + } + + } + } + if (PCIIRQRoutingInfoLength != NULL) + kfree(PCIIRQRoutingInfoLength ); + return -1; +} + + +int cpqhp_get_bus_dev (struct controller *ctrl, u8 * bus_num, u8 * dev_num, u8 slot) +{ + return PCI_GetBusDevHelper(ctrl, bus_num, dev_num, slot, 0); //plain (bridges allowed) +} + + +/* More PCI configuration routines; this time centered around hotplug controller */ + + +/* + * cpqhp_save_config + * + * Reads configuration for all slots in a PCI bus and saves info. + * + * Note: For non-hot plug busses, the slot # saved is the device # + * + * returns 0 if success + */ +int cpqhp_save_config(struct controller *ctrl, int busnumber, int is_hot_plug) +{ + long rc; + u8 class_code; + u8 header_type; + u32 ID; + u8 secondary_bus; + struct pci_func *new_slot; + int sub_bus; + int FirstSupported; + int LastSupported; + int max_functions; + int function; + u8 DevError; + int device = 0; + int cloop = 0; + int stop_it; + int index; + + // Decide which slots are supported + + if (is_hot_plug) { + //********************************* + // is_hot_plug is the slot mask + //********************************* + FirstSupported = is_hot_plug >> 4; + LastSupported = FirstSupported + (is_hot_plug & 0x0F) - 1; + } else { + FirstSupported = 0; + LastSupported = 0x1F; + } + + // Save PCI configuration space for all devices in supported slots + ctrl->pci_bus->number = busnumber; + for (device = FirstSupported; device <= LastSupported; device++) { + ID = 0xFFFFFFFF; + rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_VENDOR_ID, &ID); + + if (ID != 0xFFFFFFFF) { // device in slot + rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, 0), 0x0B, &class_code); + if (rc) + return rc; + + rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, 0), PCI_HEADER_TYPE, &header_type); + if (rc) + return rc; + + // If multi-function device, set max_functions to 8 + if (header_type & 0x80) + max_functions = 8; + else + max_functions = 1; + + function = 0; + + do { + DevError = 0; + + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // P-P Bridge + // Recurse the subordinate bus + // get the subordinate bus number + rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_SECONDARY_BUS, &secondary_bus); + if (rc) { + return rc; + } else { + sub_bus = (int) secondary_bus; + + // Save secondary bus cfg spc + // with this recursive call. + rc = cpqhp_save_config(ctrl, sub_bus, 0); + if (rc) + return rc; + ctrl->pci_bus->number = busnumber; + } + } + + index = 0; + new_slot = cpqhp_slot_find(busnumber, device, index++); + while (new_slot && + (new_slot->function != (u8) function)) + new_slot = cpqhp_slot_find(busnumber, device, index++); + + if (!new_slot) { + // Setup slot structure. + new_slot = cpqhp_slot_create(busnumber); + + if (new_slot == NULL) + return(1); + } + + new_slot->bus = (u8) busnumber; + new_slot->device = (u8) device; + new_slot->function = (u8) function; + new_slot->is_a_board = 1; + new_slot->switch_save = 0x10; + // In case of unsupported board + new_slot->status = DevError; + new_slot->pci_dev = pci_find_slot(new_slot->bus, (new_slot->device << 3) | new_slot->function); + + for (cloop = 0; cloop < 0x20; cloop++) { + rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop])); + if (rc) + return rc; + } + + function++; + + stop_it = 0; + + // this loop skips to the next present function + // reading in Class Code and Header type. + + while ((function < max_functions)&&(!stop_it)) { + rc = pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_VENDOR_ID, &ID); + if (ID == 0xFFFFFFFF) { // nothing there. + function++; + } else { // Something there + rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), 0x0B, &class_code); + if (rc) + return rc; + + rc = pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(device, function), PCI_HEADER_TYPE, &header_type); + if (rc) + return rc; + + stop_it++; + } + } + + } while (function < max_functions); + } // End of IF (device in slot?) + else if (is_hot_plug) { + // Setup slot structure with entry for empty slot + new_slot = cpqhp_slot_create(busnumber); + + if (new_slot == NULL) { + return(1); + } + + new_slot->bus = (u8) busnumber; + new_slot->device = (u8) device; + new_slot->function = 0; + new_slot->is_a_board = 0; + new_slot->presence_save = 0; + new_slot->switch_save = 0; + } + } // End of FOR loop + + return(0); +} + + +/* + * cpqhp_save_slot_config + * + * Saves configuration info for all PCI devices in a given slot + * including subordinate busses. + * + * returns 0 if success + */ +int cpqhp_save_slot_config (struct controller *ctrl, struct pci_func * new_slot) +{ + long rc; + u8 class_code; + u8 header_type; + u32 ID; + u8 secondary_bus; + int sub_bus; + int max_functions; + int function; + int cloop = 0; + int stop_it; + + ID = 0xFFFFFFFF; + + ctrl->pci_bus->number = new_slot->bus; + pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_VENDOR_ID, &ID); + + if (ID != 0xFFFFFFFF) { // device in slot + pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), 0x0B, &class_code); + pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, 0), PCI_HEADER_TYPE, &header_type); + + if (header_type & 0x80) // Multi-function device + max_functions = 8; + else + max_functions = 1; + + function = 0; + + do { + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge + // Recurse the subordinate bus + pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_SECONDARY_BUS, &secondary_bus); + + sub_bus = (int) secondary_bus; + + // Save the config headers for the secondary bus. + rc = cpqhp_save_config(ctrl, sub_bus, 0); + if (rc) + return(rc); + ctrl->pci_bus->number = new_slot->bus; + + } // End of IF + + new_slot->status = 0; + + for (cloop = 0; cloop < 0x20; cloop++) { + pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), cloop << 2, (u32 *) & (new_slot-> config_space [cloop])); + } + + function++; + + stop_it = 0; + + // this loop skips to the next present function + // reading in the Class Code and the Header type. + + while ((function < max_functions) && (!stop_it)) { + pci_bus_read_config_dword (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_VENDOR_ID, &ID); + + if (ID == 0xFFFFFFFF) { // nothing there. + function++; + } else { // Something there + pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), 0x0B, &class_code); + + pci_bus_read_config_byte (ctrl->pci_bus, PCI_DEVFN(new_slot->device, function), PCI_HEADER_TYPE, &header_type); + + stop_it++; + } + } + + } while (function < max_functions); + } // End of IF (device in slot?) + else { + return(2); + } + + return(0); +} + + +/* + * cpqhp_save_base_addr_length + * + * Saves the length of all base address registers for the + * specified slot. this is for hot plug REPLACE + * + * returns 0 if success + */ +int cpqhp_save_base_addr_length(struct controller *ctrl, struct pci_func * func) +{ + u8 cloop; + u8 header_type; + u8 secondary_bus; + u8 type; + int sub_bus; + u32 temp_register; + u32 base; + u32 rc; + struct pci_func *next; + int index = 0; + struct pci_bus *pci_bus = ctrl->pci_bus; + unsigned int devfn; + + func = cpqhp_slot_find(func->bus, func->device, index++); + + while (func != NULL) { + pci_bus->number = func->bus; + devfn = PCI_DEVFN(func->device, func->function); + + // Check for Bridge + pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); + + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { + // PCI-PCI Bridge + pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); + + sub_bus = (int) secondary_bus; + + next = cpqhp_slot_list[sub_bus]; + + while (next != NULL) { + rc = cpqhp_save_base_addr_length(ctrl, next); + + if (rc) + return(rc); + + next = next->next; + } + pci_bus->number = func->bus; + + //FIXME: this loop is duplicated in the non-bridge case. The two could be rolled together + // Figure out IO and memory base lengths + for (cloop = 0x10; cloop <= 0x14; cloop += 4) { + temp_register = 0xFFFFFFFF; + pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); + pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); + + if (base) { // If this register is implemented + if (base & 0x01L) { + // IO base + // set base = amount of IO space requested + base = base & 0xFFFFFFFE; + base = (~base) + 1; + + type = 1; + } else { + // memory base + base = base & 0xFFFFFFF0; + base = (~base) + 1; + + type = 0; + } + } else { + base = 0x0L; + type = 0; + } + + // Save information in slot structure + func->base_length[(cloop - 0x10) >> 2] = + base; + func->base_type[(cloop - 0x10) >> 2] = type; + + } // End of base register loop + + + } else if ((header_type & 0x7F) == 0x00) { // PCI-PCI Bridge + // Figure out IO and memory base lengths + for (cloop = 0x10; cloop <= 0x24; cloop += 4) { + temp_register = 0xFFFFFFFF; + pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); + pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); + + if (base) { // If this register is implemented + if (base & 0x01L) { + // IO base + // base = amount of IO space requested + base = base & 0xFFFFFFFE; + base = (~base) + 1; + + type = 1; + } else { + // memory base + // base = amount of memory space requested + base = base & 0xFFFFFFF0; + base = (~base) + 1; + + type = 0; + } + } else { + base = 0x0L; + type = 0; + } + + // Save information in slot structure + func->base_length[(cloop - 0x10) >> 2] = base; + func->base_type[(cloop - 0x10) >> 2] = type; + + } // End of base register loop + + } else { // Some other unknown header type + } + + // find the next device in this slot + func = cpqhp_slot_find(func->bus, func->device, index++); + } + + return(0); +} + + +/* + * cpqhp_save_used_resources + * + * Stores used resource information for existing boards. this is + * for boards that were in the system when this driver was loaded. + * this function is for hot plug ADD + * + * returns 0 if success + */ +int cpqhp_save_used_resources (struct controller *ctrl, struct pci_func * func) +{ + u8 cloop; + u8 header_type; + u8 secondary_bus; + u8 temp_byte; + u8 b_base; + u8 b_length; + u16 command; + u16 save_command; + u16 w_base; + u16 w_length; + u32 temp_register; + u32 save_base; + u32 base; + int index = 0; + struct pci_resource *mem_node; + struct pci_resource *p_mem_node; + struct pci_resource *io_node; + struct pci_resource *bus_node; + struct pci_bus *pci_bus = ctrl->pci_bus; + unsigned int devfn; + + func = cpqhp_slot_find(func->bus, func->device, index++); + + while ((func != NULL) && func->is_a_board) { + pci_bus->number = func->bus; + devfn = PCI_DEVFN(func->device, func->function); + + // Save the command register + pci_bus_read_config_word (pci_bus, devfn, PCI_COMMAND, &save_command); + + // disable card + command = 0x00; + pci_bus_write_config_word (pci_bus, devfn, PCI_COMMAND, command); + + // Check for Bridge + pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); + + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge + // Clear Bridge Control Register + command = 0x00; + pci_bus_write_config_word (pci_bus, devfn, PCI_BRIDGE_CONTROL, command); + pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); + pci_bus_read_config_byte (pci_bus, devfn, PCI_SUBORDINATE_BUS, &temp_byte); + + bus_node =(struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!bus_node) + return -ENOMEM; + + bus_node->base = secondary_bus; + bus_node->length = temp_byte - secondary_bus + 1; + + bus_node->next = func->bus_head; + func->bus_head = bus_node; + + // Save IO base and Limit registers + pci_bus_read_config_byte (pci_bus, devfn, PCI_IO_BASE, &b_base); + pci_bus_read_config_byte (pci_bus, devfn, PCI_IO_LIMIT, &b_length); + + if ((b_base <= b_length) && (save_command & 0x01)) { + io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!io_node) + return -ENOMEM; + + io_node->base = (b_base & 0xF0) << 8; + io_node->length = (b_length - b_base + 0x10) << 8; + + io_node->next = func->io_head; + func->io_head = io_node; + } + + // Save memory base and Limit registers + pci_bus_read_config_word (pci_bus, devfn, PCI_MEMORY_BASE, &w_base); + pci_bus_read_config_word (pci_bus, devfn, PCI_MEMORY_LIMIT, &w_length); + + if ((w_base <= w_length) && (save_command & 0x02)) { + mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!mem_node) + return -ENOMEM; + + mem_node->base = w_base << 16; + mem_node->length = (w_length - w_base + 0x10) << 16; + + mem_node->next = func->mem_head; + func->mem_head = mem_node; + } + + // Save prefetchable memory base and Limit registers + pci_bus_read_config_word (pci_bus, devfn, PCI_PREF_MEMORY_BASE, &w_base); + pci_bus_read_config_word (pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &w_length); + + if ((w_base <= w_length) && (save_command & 0x02)) { + p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!p_mem_node) + return -ENOMEM; + + p_mem_node->base = w_base << 16; + p_mem_node->length = (w_length - w_base + 0x10) << 16; + + p_mem_node->next = func->p_mem_head; + func->p_mem_head = p_mem_node; + } + // Figure out IO and memory base lengths + for (cloop = 0x10; cloop <= 0x14; cloop += 4) { + pci_bus_read_config_dword (pci_bus, devfn, cloop, &save_base); + + temp_register = 0xFFFFFFFF; + pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); + pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); + + temp_register = base; + + if (base) { // If this register is implemented + if (((base & 0x03L) == 0x01) + && (save_command & 0x01)) { + // IO base + // set temp_register = amount of IO space requested + temp_register = base & 0xFFFFFFFE; + temp_register = (~temp_register) + 1; + + io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!io_node) + return -ENOMEM; + + io_node->base = + save_base & (~0x03L); + io_node->length = temp_register; + + io_node->next = func->io_head; + func->io_head = io_node; + } else + if (((base & 0x0BL) == 0x08) + && (save_command & 0x02)) { + // prefetchable memory base + temp_register = base & 0xFFFFFFF0; + temp_register = (~temp_register) + 1; + + p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!p_mem_node) + return -ENOMEM; + + p_mem_node->base = save_base & (~0x0FL); + p_mem_node->length = temp_register; + + p_mem_node->next = func->p_mem_head; + func->p_mem_head = p_mem_node; + } else + if (((base & 0x0BL) == 0x00) + && (save_command & 0x02)) { + // prefetchable memory base + temp_register = base & 0xFFFFFFF0; + temp_register = (~temp_register) + 1; + + mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!mem_node) + return -ENOMEM; + + mem_node->base = save_base & (~0x0FL); + mem_node->length = temp_register; + + mem_node->next = func->mem_head; + func->mem_head = mem_node; + } else + return(1); + } + } // End of base register loop + } else if ((header_type & 0x7F) == 0x00) { // Standard header + // Figure out IO and memory base lengths + for (cloop = 0x10; cloop <= 0x24; cloop += 4) { + pci_bus_read_config_dword (pci_bus, devfn, cloop, &save_base); + + temp_register = 0xFFFFFFFF; + pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); + pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); + + temp_register = base; + + if (base) { // If this register is implemented + if (((base & 0x03L) == 0x01) + && (save_command & 0x01)) { + // IO base + // set temp_register = amount of IO space requested + temp_register = base & 0xFFFFFFFE; + temp_register = (~temp_register) + 1; + + io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!io_node) + return -ENOMEM; + + io_node->base = save_base & (~0x01L); + io_node->length = temp_register; + + io_node->next = func->io_head; + func->io_head = io_node; + } else + if (((base & 0x0BL) == 0x08) + && (save_command & 0x02)) { + // prefetchable memory base + temp_register = base & 0xFFFFFFF0; + temp_register = (~temp_register) + 1; + + p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!p_mem_node) + return -ENOMEM; + + p_mem_node->base = save_base & (~0x0FL); + p_mem_node->length = temp_register; + + p_mem_node->next = func->p_mem_head; + func->p_mem_head = p_mem_node; + } else + if (((base & 0x0BL) == 0x00) + && (save_command & 0x02)) { + // prefetchable memory base + temp_register = base & 0xFFFFFFF0; + temp_register = (~temp_register) + 1; + + mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!mem_node) + return -ENOMEM; + + mem_node->base = save_base & (~0x0FL); + mem_node->length = temp_register; + + mem_node->next = func->mem_head; + func->mem_head = mem_node; + } else + return(1); + } + } // End of base register loop + } else { // Some other unknown header type + } + + // find the next device in this slot + func = cpqhp_slot_find(func->bus, func->device, index++); + } + + return(0); +} + + +/* + * cpqhp_configure_board + * + * Copies saved configuration information to one slot. + * this is called recursively for bridge devices. + * this is for hot plug REPLACE! + * + * returns 0 if success + */ +int cpqhp_configure_board(struct controller *ctrl, struct pci_func * func) +{ + int cloop; + u8 header_type; + u8 secondary_bus; + int sub_bus; + struct pci_func *next; + u32 temp; + u32 rc; + int index = 0; + struct pci_bus *pci_bus = ctrl->pci_bus; + unsigned int devfn; + + func = cpqhp_slot_find(func->bus, func->device, index++); + + while (func != NULL) { + pci_bus->number = func->bus; + devfn = PCI_DEVFN(func->device, func->function); + + // Start at the top of config space so that the control + // registers are programmed last + for (cloop = 0x3C; cloop > 0; cloop -= 4) { + pci_bus_write_config_dword (pci_bus, devfn, cloop, func->config_space[cloop >> 2]); + } + + pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); + + // If this is a bridge device, restore subordinate devices + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge + pci_bus_read_config_byte (pci_bus, devfn, PCI_SECONDARY_BUS, &secondary_bus); + + sub_bus = (int) secondary_bus; + + next = cpqhp_slot_list[sub_bus]; + + while (next != NULL) { + rc = cpqhp_configure_board(ctrl, next); + + if (rc) + return rc; + + next = next->next; + } + } else { + + // Check all the base Address Registers to make sure + // they are the same. If not, the board is different. + + for (cloop = 16; cloop < 40; cloop += 4) { + pci_bus_read_config_dword (pci_bus, devfn, cloop, &temp); + + if (temp != func->config_space[cloop >> 2]) { + dbg("Config space compare failure!!! offset = %x\n", cloop); + dbg("bus = %x, device = %x, function = %x\n", func->bus, func->device, func->function); + dbg("temp = %x, config space = %x\n\n", temp, func->config_space[cloop >> 2]); + return 1; + } + } + } + + func->configured = 1; + + func = cpqhp_slot_find(func->bus, func->device, index++); + } + + return 0; +} + + +/* + * cpqhp_valid_replace + * + * this function checks to see if a board is the same as the + * one it is replacing. this check will detect if the device's + * vendor or device id's are the same + * + * returns 0 if the board is the same nonzero otherwise + */ +int cpqhp_valid_replace(struct controller *ctrl, struct pci_func * func) +{ + u8 cloop; + u8 header_type; + u8 secondary_bus; + u8 type; + u32 temp_register = 0; + u32 base; + u32 rc; + struct pci_func *next; + int index = 0; + struct pci_bus *pci_bus = ctrl->pci_bus; + unsigned int devfn; + + if (!func->is_a_board) + return(ADD_NOT_SUPPORTED); + + func = cpqhp_slot_find(func->bus, func->device, index++); + + while (func != NULL) { + pci_bus->number = func->bus; + devfn = PCI_DEVFN(func->device, func->function); + + pci_bus_read_config_dword (pci_bus, devfn, PCI_VENDOR_ID, &temp_register); + + // No adapter present + if (temp_register == 0xFFFFFFFF) + return(NO_ADAPTER_PRESENT); + + if (temp_register != func->config_space[0]) + return(ADAPTER_NOT_SAME); + + // Check for same revision number and class code + pci_bus_read_config_dword (pci_bus, devfn, PCI_CLASS_REVISION, &temp_register); + + // Adapter not the same + if (temp_register != func->config_space[0x08 >> 2]) + return(ADAPTER_NOT_SAME); + + // Check for Bridge + pci_bus_read_config_byte (pci_bus, devfn, PCI_HEADER_TYPE, &header_type); + + if ((header_type & 0x7F) == PCI_HEADER_TYPE_BRIDGE) { // PCI-PCI Bridge + // In order to continue checking, we must program the + // bus registers in the bridge to respond to accesses + // for it's subordinate bus(es) + + temp_register = func->config_space[0x18 >> 2]; + pci_bus_write_config_dword (pci_bus, devfn, PCI_PRIMARY_BUS, temp_register); + + secondary_bus = (temp_register >> 8) & 0xFF; + + next = cpqhp_slot_list[secondary_bus]; + + while (next != NULL) { + rc = cpqhp_valid_replace(ctrl, next); + + if (rc) + return(rc); + + next = next->next; + } + + } + // Check to see if it is a standard config header + else if ((header_type & 0x7F) == PCI_HEADER_TYPE_NORMAL) { + // Check subsystem vendor and ID + pci_bus_read_config_dword (pci_bus, devfn, PCI_SUBSYSTEM_VENDOR_ID, &temp_register); + + if (temp_register != func->config_space[0x2C >> 2]) { + // If it's a SMART-2 and the register isn't filled + // in, ignore the difference because + // they just have an old rev of the firmware + + if (!((func->config_space[0] == 0xAE100E11) + && (temp_register == 0x00L))) + return(ADAPTER_NOT_SAME); + } + // Figure out IO and memory base lengths + for (cloop = 0x10; cloop <= 0x24; cloop += 4) { + temp_register = 0xFFFFFFFF; + pci_bus_write_config_dword (pci_bus, devfn, cloop, temp_register); + pci_bus_read_config_dword (pci_bus, devfn, cloop, &base); + if (base) { // If this register is implemented + if (base & 0x01L) { + // IO base + // set base = amount of IO space requested + base = base & 0xFFFFFFFE; + base = (~base) + 1; + + type = 1; + } else { + // memory base + base = base & 0xFFFFFFF0; + base = (~base) + 1; + + type = 0; + } + } else { + base = 0x0L; + type = 0; + } + + // Check information in slot structure + if (func->base_length[(cloop - 0x10) >> 2] != base) + return(ADAPTER_NOT_SAME); + + if (func->base_type[(cloop - 0x10) >> 2] != type) + return(ADAPTER_NOT_SAME); + + } // End of base register loop + + } // End of (type 0 config space) else + else { + // this is not a type 0 or 1 config space header so + // we don't know how to do it + return(DEVICE_TYPE_NOT_SUPPORTED); + } + + // Get the next function + func = cpqhp_slot_find(func->bus, func->device, index++); + } + + + return(0); +} + + +/* + * cpqhp_find_available_resources + * + * Finds available memory, IO, and IRQ resources for programming + * devices which may be added to the system + * this function is for hot plug ADD! + * + * returns 0 if success + */ +int cpqhp_find_available_resources (struct controller *ctrl, void *rom_start) +{ + u8 temp; + u8 populated_slot; + u8 bridged_slot; + void *one_slot; + struct pci_func *func = NULL; + int i = 10, index; + u32 temp_dword, rc; + struct pci_resource *mem_node; + struct pci_resource *p_mem_node; + struct pci_resource *io_node; + struct pci_resource *bus_node; + void *rom_resource_table; + + rom_resource_table = detect_HRT_floating_pointer(rom_start, rom_start+0xffff); + dbg("rom_resource_table = %p\n", rom_resource_table); + + if (rom_resource_table == NULL) { + return -ENODEV; + } + // Sum all resources and setup resource maps + unused_IRQ = readl(rom_resource_table + UNUSED_IRQ); + dbg("unused_IRQ = %x\n", unused_IRQ); + + temp = 0; + while (unused_IRQ) { + if (unused_IRQ & 1) { + cpqhp_disk_irq = temp; + break; + } + unused_IRQ = unused_IRQ >> 1; + temp++; + } + + dbg("cpqhp_disk_irq= %d\n", cpqhp_disk_irq); + unused_IRQ = unused_IRQ >> 1; + temp++; + + while (unused_IRQ) { + if (unused_IRQ & 1) { + cpqhp_nic_irq = temp; + break; + } + unused_IRQ = unused_IRQ >> 1; + temp++; + } + + dbg("cpqhp_nic_irq= %d\n", cpqhp_nic_irq); + unused_IRQ = readl(rom_resource_table + PCIIRQ); + + temp = 0; + + if (!cpqhp_nic_irq) { + cpqhp_nic_irq = ctrl->cfgspc_irq; + } + + if (!cpqhp_disk_irq) { + cpqhp_disk_irq = ctrl->cfgspc_irq; + } + + dbg("cpqhp_disk_irq, cpqhp_nic_irq= %d, %d\n", cpqhp_disk_irq, cpqhp_nic_irq); + + rc = compaq_nvram_load(rom_start, ctrl); + if (rc) + return rc; + + one_slot = rom_resource_table + sizeof (struct hrt); + + i = readb(rom_resource_table + NUMBER_OF_ENTRIES); + dbg("number_of_entries = %d\n", i); + + if (!readb(one_slot + SECONDARY_BUS)) { + return(1); + } + + dbg("dev|IO base|length|Mem base|length|Pre base|length|PB SB MB\n"); + + while (i && readb(one_slot + SECONDARY_BUS)) { + u8 dev_func = readb(one_slot + DEV_FUNC); + u8 primary_bus = readb(one_slot + PRIMARY_BUS); + u8 secondary_bus = readb(one_slot + SECONDARY_BUS); + u8 max_bus = readb(one_slot + MAX_BUS); + u16 io_base = readw(one_slot + IO_BASE); + u16 io_length = readw(one_slot + IO_LENGTH); + u16 mem_base = readw(one_slot + MEM_BASE); + u16 mem_length = readw(one_slot + MEM_LENGTH); + u16 pre_mem_base = readw(one_slot + PRE_MEM_BASE); + u16 pre_mem_length = readw(one_slot + PRE_MEM_LENGTH); + + dbg("%2.2x | %4.4x | %4.4x | %4.4x | %4.4x | %4.4x | %4.4x |%2.2x %2.2x %2.2x\n", + dev_func, io_base, io_length, mem_base, mem_length, pre_mem_base, pre_mem_length, + primary_bus, secondary_bus, max_bus); + + // If this entry isn't for our controller's bus, ignore it + if (primary_bus != ctrl->bus) { + i--; + one_slot += sizeof (struct slot_rt); + continue; + } + // find out if this entry is for an occupied slot + ctrl->pci_bus->number = primary_bus; + pci_bus_read_config_dword (ctrl->pci_bus, dev_func, PCI_VENDOR_ID, &temp_dword); + dbg("temp_D_word = %x\n", temp_dword); + + if (temp_dword != 0xFFFFFFFF) { + index = 0; + func = cpqhp_slot_find(primary_bus, dev_func >> 3, 0); + + while (func && (func->function != (dev_func & 0x07))) { + dbg("func = %p (bus, dev, fun) = (%d, %d, %d)\n", func, primary_bus, dev_func >> 3, index); + func = cpqhp_slot_find(primary_bus, dev_func >> 3, index++); + } + + // If we can't find a match, skip this table entry + if (!func) { + i--; + one_slot += sizeof (struct slot_rt); + continue; + } + // this may not work and shouldn't be used + if (secondary_bus != primary_bus) + bridged_slot = 1; + else + bridged_slot = 0; + + populated_slot = 1; + } else { + populated_slot = 0; + bridged_slot = 0; + } + + + // If we've got a valid IO base, use it + + temp_dword = io_base + io_length; + + if ((io_base) && (temp_dword < 0x10000)) { + io_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!io_node) + return -ENOMEM; + + io_node->base = io_base; + io_node->length = io_length; + + dbg("found io_node(base, length) = %x, %x\n", io_node->base, io_node->length); + dbg("populated slot =%d \n", populated_slot); + if (!populated_slot) { + io_node->next = ctrl->io_head; + ctrl->io_head = io_node; + } else { + io_node->next = func->io_head; + func->io_head = io_node; + } + } + + // If we've got a valid memory base, use it + temp_dword = mem_base + mem_length; + if ((mem_base) && (temp_dword < 0x10000)) { + mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!mem_node) + return -ENOMEM; + + mem_node->base = mem_base << 16; + + mem_node->length = mem_length << 16; + + dbg("found mem_node(base, length) = %x, %x\n", mem_node->base, mem_node->length); + dbg("populated slot =%d \n", populated_slot); + if (!populated_slot) { + mem_node->next = ctrl->mem_head; + ctrl->mem_head = mem_node; + } else { + mem_node->next = func->mem_head; + func->mem_head = mem_node; + } + } + + // If we've got a valid prefetchable memory base, and + // the base + length isn't greater than 0xFFFF + temp_dword = pre_mem_base + pre_mem_length; + if ((pre_mem_base) && (temp_dword < 0x10000)) { + p_mem_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!p_mem_node) + return -ENOMEM; + + p_mem_node->base = pre_mem_base << 16; + + p_mem_node->length = pre_mem_length << 16; + dbg("found p_mem_node(base, length) = %x, %x\n", p_mem_node->base, p_mem_node->length); + dbg("populated slot =%d \n", populated_slot); + + if (!populated_slot) { + p_mem_node->next = ctrl->p_mem_head; + ctrl->p_mem_head = p_mem_node; + } else { + p_mem_node->next = func->p_mem_head; + func->p_mem_head = p_mem_node; + } + } + + // If we've got a valid bus number, use it + // The second condition is to ignore bus numbers on + // populated slots that don't have PCI-PCI bridges + if (secondary_bus && (secondary_bus != primary_bus)) { + bus_node = (struct pci_resource *) kmalloc(sizeof(struct pci_resource), GFP_KERNEL); + if (!bus_node) + return -ENOMEM; + + bus_node->base = secondary_bus; + bus_node->length = max_bus - secondary_bus + 1; + dbg("found bus_node(base, length) = %x, %x\n", bus_node->base, bus_node->length); + dbg("populated slot =%d \n", populated_slot); + if (!populated_slot) { + bus_node->next = ctrl->bus_head; + ctrl->bus_head = bus_node; + } else { + bus_node->next = func->bus_head; + func->bus_head = bus_node; + } + } + + i--; + one_slot += sizeof (struct slot_rt); + } + + // If all of the following fail, we don't have any resources for + // hot plug add + rc = 1; + rc &= cpqhp_resource_sort_and_combine(&(ctrl->mem_head)); + rc &= cpqhp_resource_sort_and_combine(&(ctrl->p_mem_head)); + rc &= cpqhp_resource_sort_and_combine(&(ctrl->io_head)); + rc &= cpqhp_resource_sort_and_combine(&(ctrl->bus_head)); + + return(rc); +} + + +/* + * cpqhp_return_board_resources + * + * this routine returns all resources allocated to a board to + * the available pool. + * + * returns 0 if success + */ +int cpqhp_return_board_resources(struct pci_func * func, struct resource_lists * resources) +{ + int rc = 0; + struct pci_resource *node; + struct pci_resource *t_node; + dbg("%s\n", __FUNCTION__); + + if (!func) + return(1); + + node = func->io_head; + func->io_head = NULL; + while (node) { + t_node = node->next; + return_resource(&(resources->io_head), node); + node = t_node; + } + + node = func->mem_head; + func->mem_head = NULL; + while (node) { + t_node = node->next; + return_resource(&(resources->mem_head), node); + node = t_node; + } + + node = func->p_mem_head; + func->p_mem_head = NULL; + while (node) { + t_node = node->next; + return_resource(&(resources->p_mem_head), node); + node = t_node; + } + + node = func->bus_head; + func->bus_head = NULL; + while (node) { + t_node = node->next; + return_resource(&(resources->bus_head), node); + node = t_node; + } + + rc |= cpqhp_resource_sort_and_combine(&(resources->mem_head)); + rc |= cpqhp_resource_sort_and_combine(&(resources->p_mem_head)); + rc |= cpqhp_resource_sort_and_combine(&(resources->io_head)); + rc |= cpqhp_resource_sort_and_combine(&(resources->bus_head)); + + return(rc); +} + + +/* + * cpqhp_destroy_resource_list + * + * Puts node back in the resource list pointed to by head + */ +void cpqhp_destroy_resource_list (struct resource_lists * resources) +{ + struct pci_resource *res, *tres; + + res = resources->io_head; + resources->io_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = resources->mem_head; + resources->mem_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = resources->p_mem_head; + resources->p_mem_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = resources->bus_head; + resources->bus_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } +} + + +/* + * cpqhp_destroy_board_resources + * + * Puts node back in the resource list pointed to by head + */ +void cpqhp_destroy_board_resources (struct pci_func * func) +{ + struct pci_resource *res, *tres; + + res = func->io_head; + func->io_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = func->mem_head; + func->mem_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = func->p_mem_head; + func->p_mem_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } + + res = func->bus_head; + func->bus_head = NULL; + + while (res) { + tres = res; + res = res->next; + kfree(tres); + } +} + diff -Nru a/drivers/pci/hotplug/cpqphp_sysfs.c b/drivers/pci/hotplug/cpqphp_sysfs.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pci/hotplug/cpqphp_sysfs.c Mon Jun 9 23:16:19 2003 @@ -0,0 +1,143 @@ +/* + * Compaq Hot Plug Controller Driver + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001,2003 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Send feedback to <greg@kroah.com> + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/proc_fs.h> +#include <linux/workqueue.h> +#include <linux/pci.h> +#include "cpqphp.h" + + +/* A few routines that create sysfs entries for the hot plug controller */ + +static int show_ctrl (struct device *dev, char *buf) +{ + struct pci_dev *pci_dev; + struct controller *ctrl; + char * out = buf; + int index; + struct pci_resource *res; + + pci_dev = container_of (dev, struct pci_dev, dev); + ctrl = pci_get_drvdata(pci_dev); + + out += sprintf(buf, "Free resources: memory\n"); + index = 11; + res = ctrl->mem_head; + while (res && index--) { + out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); + res = res->next; + } + out += sprintf(out, "Free resources: prefetchable memory\n"); + index = 11; + res = ctrl->p_mem_head; + while (res && index--) { + out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); + res = res->next; + } + out += sprintf(out, "Free resources: IO\n"); + index = 11; + res = ctrl->io_head; + while (res && index--) { + out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); + res = res->next; + } + out += sprintf(out, "Free resources: bus numbers\n"); + index = 11; + res = ctrl->bus_head; + while (res && index--) { + out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); + res = res->next; + } + + return out - buf; +} +static DEVICE_ATTR (ctrl, S_IRUGO, show_ctrl, NULL); + +static int show_dev (struct device *dev, char *buf) +{ + struct pci_dev *pci_dev; + struct controller *ctrl; + char * out = buf; + int index; + struct pci_resource *res; + struct pci_func *new_slot; + struct slot *slot; + + pci_dev = container_of (dev, struct pci_dev, dev); + ctrl = pci_get_drvdata(pci_dev); + + slot=ctrl->slot; + + while (slot) { + new_slot = cpqhp_slot_find(slot->bus, slot->device, 0); + if (!new_slot) + break; + out += sprintf(out, "assigned resources: memory\n"); + index = 11; + res = new_slot->mem_head; + while (res && index--) { + out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); + res = res->next; + } + out += sprintf(out, "assigned resources: prefetchable memory\n"); + index = 11; + res = new_slot->p_mem_head; + while (res && index--) { + out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); + res = res->next; + } + out += sprintf(out, "assigned resources: IO\n"); + index = 11; + res = new_slot->io_head; + while (res && index--) { + out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); + res = res->next; + } + out += sprintf(out, "assigned resources: bus numbers\n"); + index = 11; + res = new_slot->bus_head; + while (res && index--) { + out += sprintf(out, "start = %8.8x, length = %8.8x\n", res->base, res->length); + res = res->next; + } + slot=slot->next; + } + + return out - buf; +} +static DEVICE_ATTR (dev, S_IRUGO, show_dev, NULL); + +void cpqhp_create_ctrl_files (struct controller *ctrl) +{ + device_create_file (&ctrl->pci_dev->dev, &dev_attr_ctrl); + device_create_file (&ctrl->pci_dev->dev, &dev_attr_dev); +} diff -Nru a/drivers/pci/hotplug/ibmphp.h b/drivers/pci/hotplug/ibmphp.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pci/hotplug/ibmphp.h Mon Jun 9 23:16:07 2003 @@ -0,0 +1,772 @@ +#ifndef __IBMPHP_H +#define __IBMPHP_H + +/* + * IBM Hot Plug Controller Driver + * + * Written By: Jyoti Shah, Tong Yu, Irene Zubarev, IBM Corporation + * + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001,2002 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Send feedback to <gregkh@us.ibm.com> + * + */ + +#include "pci_hotplug.h" + +extern int ibmphp_debug; + +#if !defined(CONFIG_HOTPLUG_PCI_IBM_MODULE) + #define MY_NAME "ibmphpd" +#else + #define MY_NAME THIS_MODULE->name +#endif +#define debug(fmt, arg...) do { if (ibmphp_debug == 1) printk(KERN_DEBUG "%s: " fmt , MY_NAME , ## arg); } while (0) +#define debug_pci(fmt, arg...) do { if (ibmphp_debug) printk(KERN_DEBUG "%s: " fmt , MY_NAME , ## arg); } while (0) +#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg) + + +/* EBDA stuff */ + +/*********************************************************** +* SLOT CAPABILITY * +***********************************************************/ + +#define EBDA_SLOT_133_MAX 0x20 +#define EBDA_SLOT_100_MAX 0x10 +#define EBDA_SLOT_66_MAX 0x02 +#define EBDA_SLOT_PCIX_CAP 0x08 + + +/************************************************************ +* RESOURE TYPE * +************************************************************/ + +#define EBDA_RSRC_TYPE_MASK 0x03 +#define EBDA_IO_RSRC_TYPE 0x00 +#define EBDA_MEM_RSRC_TYPE 0x01 +#define EBDA_PFM_RSRC_TYPE 0x03 +#define EBDA_RES_RSRC_TYPE 0x02 + + +/************************************************************* +* IO RESTRICTION TYPE * +*************************************************************/ + +#define EBDA_IO_RESTRI_MASK 0x0c +#define EBDA_NO_RESTRI 0x00 +#define EBDA_AVO_VGA_ADDR 0x04 +#define EBDA_AVO_VGA_ADDR_AND_ALIA 0x08 +#define EBDA_AVO_ISA_ADDR 0x0c + + +/************************************************************** +* DEVICE TYPE DEF * +**************************************************************/ + +#define EBDA_DEV_TYPE_MASK 0x10 +#define EBDA_PCI_DEV 0x10 +#define EBDA_NON_PCI_DEV 0x00 + + +/*************************************************************** +* PRIMARY DEF DEFINITION * +***************************************************************/ + +#define EBDA_PRI_DEF_MASK 0x20 +#define EBDA_PRI_PCI_BUS_INFO 0x20 +#define EBDA_NORM_DEV_RSRC_INFO 0x00 + + +//-------------------------------------------------------------- +// RIO TABLE DATA STRUCTURE +//-------------------------------------------------------------- + +struct rio_table_hdr { + u8 ver_num; + u8 scal_count; + u8 riodev_count; + u16 offset; +}; + +//------------------------------------------------------------- +// SCALABILITY DETAIL +//------------------------------------------------------------- + +struct scal_detail { + u8 node_id; + u32 cbar; + u8 port0_node_connect; + u8 port0_port_connect; + u8 port1_node_connect; + u8 port1_port_connect; + u8 port2_node_connect; + u8 port2_port_connect; + u8 chassis_num; +// struct list_head scal_detail_list; +}; + +//-------------------------------------------------------------- +// RIO DETAIL +//-------------------------------------------------------------- + +struct rio_detail { + u8 rio_node_id; + u32 bbar; + u8 rio_type; + u8 owner_id; + u8 port0_node_connect; + u8 port0_port_connect; + u8 port1_node_connect; + u8 port1_port_connect; + u8 first_slot_num; + u8 status; + u8 wpindex; + u8 chassis_num; + struct list_head rio_detail_list; +}; + +struct opt_rio { + u8 rio_type; + u8 chassis_num; + u8 first_slot_num; + u8 middle_num; + struct list_head opt_rio_list; +}; + +struct opt_rio_lo { + u8 rio_type; + u8 chassis_num; + u8 first_slot_num; + u8 middle_num; + u8 pack_count; + struct list_head opt_rio_lo_list; +}; + +/**************************************************************** +* HPC DESCRIPTOR NODE * +****************************************************************/ + +struct ebda_hpc_list { + u8 format; + u16 num_ctlrs; + short phys_addr; +// struct list_head ebda_hpc_list; +}; +/***************************************************************** +* IN HPC DATA STRUCTURE, THE ASSOCIATED SLOT AND BUS * +* STRUCTURE * +*****************************************************************/ + +struct ebda_hpc_slot { + u8 slot_num; + u32 slot_bus_num; + u8 ctl_index; + u8 slot_cap; +}; + +struct ebda_hpc_bus { + u32 bus_num; + u8 slots_at_33_conv; + u8 slots_at_66_conv; + u8 slots_at_66_pcix; + u8 slots_at_100_pcix; + u8 slots_at_133_pcix; +}; + + +/******************************************************************** +* THREE TYPE OF HOT PLUG CONTROLER * +********************************************************************/ + +struct isa_ctlr_access { + u16 io_start; + u16 io_end; +}; + +struct pci_ctlr_access { + u8 bus; + u8 dev_fun; +}; + +struct wpeg_i2c_ctlr_access { + ulong wpegbbar; + u8 i2c_addr; +}; + +#define HPC_DEVICE_ID 0x0246 +#define HPC_SUBSYSTEM_ID 0x0247 +#define HPC_PCI_OFFSET 0x40 +/************************************************************************* +* RSTC DESCRIPTOR NODE * +*************************************************************************/ + +struct ebda_rsrc_list { + u8 format; + u16 num_entries; + u16 phys_addr; + struct ebda_rsrc_list *next; +}; + + +/*************************************************************************** +* PCI RSRC NODE * +***************************************************************************/ + +struct ebda_pci_rsrc { + u8 rsrc_type; + u8 bus_num; + u8 dev_fun; + u32 start_addr; + u32 end_addr; + u8 marked; /* for NVRAM */ + struct list_head ebda_pci_rsrc_list; +}; + + +/*********************************************************** +* BUS_INFO DATE STRUCTURE * +***********************************************************/ + +struct bus_info { + u8 slot_min; + u8 slot_max; + u8 slot_count; + u8 busno; + u8 controller_id; + u8 current_speed; + u8 current_bus_mode; + u8 index; + u8 slots_at_33_conv; + u8 slots_at_66_conv; + u8 slots_at_66_pcix; + u8 slots_at_100_pcix; + u8 slots_at_133_pcix; + struct list_head bus_info_list; +}; + + +/*********************************************************** +* GLOBAL VARIABLES * +***********************************************************/ +extern struct list_head ibmphp_ebda_pci_rsrc_head; +extern struct list_head ibmphp_slot_head; +extern struct list_head ibmphp_res_head; +/*********************************************************** +* FUNCTION PROTOTYPES * +***********************************************************/ + +extern void ibmphp_free_ebda_hpc_queue (void); +extern int ibmphp_access_ebda (void); +extern struct slot *ibmphp_get_slot_from_physical_num (u8); +extern int ibmphp_get_total_hp_slots (void); +extern void ibmphp_free_ibm_slot (struct slot *); +extern void ibmphp_free_bus_info_queue (void); +extern void ibmphp_free_ebda_pci_rsrc_queue (void); +extern struct bus_info *ibmphp_find_same_bus_num (u32); +extern int ibmphp_get_bus_index (u8); +extern u16 ibmphp_get_total_controllers (void); +extern int ibmphp_register_pci (void); + +/* passed parameters */ +#define MEM 0 +#define IO 1 +#define PFMEM 2 + +/* bit masks */ +#define RESTYPE 0x03 +#define IOMASK 0x00 /* will need to take its complement */ +#define MMASK 0x01 +#define PFMASK 0x03 +#define PCIDEVMASK 0x10 /* we should always have PCI devices */ +#define PRIMARYBUSMASK 0x20 + +/* pci specific defines */ +#define PCI_VENDOR_ID_NOTVALID 0xFFFF +#define PCI_HEADER_TYPE_MULTIDEVICE 0x80 +#define PCI_HEADER_TYPE_MULTIBRIDGE 0x81 + +#define LATENCY 0x64 +#define CACHE 64 +#define DEVICEENABLE 0x015F /* CPQ has 0x0157 */ + +#define IOBRIDGE 0x1000 /* 4k */ +#define MEMBRIDGE 0x100000 /* 1M */ + +/* irqs */ +#define SCSI_IRQ 0x09 +#define LAN_IRQ 0x0A +#define OTHER_IRQ 0x0B + +/* Data Structures */ + +/* type is of the form x x xx xx + * | | | |_ 00 - I/O, 01 - Memory, 11 - PFMemory + * | | - 00 - No Restrictions, 01 - Avoid VGA, 10 - Avoid + * | | VGA and their aliases, 11 - Avoid ISA + * | - 1 - PCI device, 0 - non pci device + * - 1 - Primary PCI Bus Information (0 if Normal device) + * the IO restrictions [2:3] are only for primary buses + */ + + +/* we need this struct because there could be several resource blocks + * allocated per primary bus in the EBDA + */ +struct range_node { + int rangeno; + u32 start; + u32 end; + struct range_node *next; +}; + +struct bus_node { + u8 busno; + int noIORanges; + struct range_node *rangeIO; + int noMemRanges; + struct range_node *rangeMem; + int noPFMemRanges; + struct range_node *rangePFMem; + int needIOUpdate; + int needMemUpdate; + int needPFMemUpdate; + struct resource_node *firstIO; /* first IO resource on the Bus */ + struct resource_node *firstMem; /* first memory resource on the Bus */ + struct resource_node *firstPFMem; /* first prefetchable memory resource on the Bus */ + struct resource_node *firstPFMemFromMem; /* when run out of pfmem available, taking from Mem */ + struct list_head bus_list; +}; + +struct resource_node { + int rangeno; + u8 busno; + u8 devfunc; + u32 start; + u32 end; + u32 len; + int type; /* MEM, IO, PFMEM */ + u8 fromMem; /* this is to indicate that the range is from + * from the Memory bucket rather than from PFMem */ + struct resource_node *next; + struct resource_node *nextRange; /* for the other mem range on bus */ +}; + +struct res_needed { + u32 mem; + u32 pfmem; + u32 io; + u8 not_correct; /* needed for return */ + int devices[32]; /* for device numbers behind this bridge */ +}; + +/* functions */ + +extern int ibmphp_rsrc_init (void); +extern int ibmphp_add_resource (struct resource_node *); +extern int ibmphp_remove_resource (struct resource_node *); +extern int ibmphp_find_resource (struct bus_node *, u32, struct resource_node **, int); +extern int ibmphp_check_resource (struct resource_node *, u8); +extern int ibmphp_remove_bus (struct bus_node *, u8); +extern void ibmphp_free_resources (void); +extern int ibmphp_add_pfmem_from_mem (struct resource_node *); +extern struct bus_node *ibmphp_find_res_bus (u8); +extern void ibmphp_print_test (void); /* for debugging purposes */ + +extern void ibmphp_hpc_initvars (void); +extern int ibmphp_hpc_readslot (struct slot *, u8, u8 *); +extern int ibmphp_hpc_writeslot (struct slot *, u8); +extern void ibmphp_lock_operations (void); +extern void ibmphp_unlock_operations (void); +extern int ibmphp_hpc_fillhpslotinfo (struct hotplug_slot *); +extern int ibmphp_hpc_start_poll_thread (void); +extern void ibmphp_hpc_stop_poll_thread (void); + +//---------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------- +// HPC return codes +//---------------------------------------------------------------------------- +#define FALSE 0x00 +#define TRUE 0x01 +#define HPC_ERROR 0xFF + +//----------------------------------------------------------------------------- +// BUS INFO +//----------------------------------------------------------------------------- +#define BUS_SPEED 0x30 +#define BUS_MODE 0x40 +#define BUS_MODE_PCIX 0x01 +#define BUS_MODE_PCI 0x00 +#define BUS_SPEED_2 0x20 +#define BUS_SPEED_1 0x10 +#define BUS_SPEED_33 0x00 +#define BUS_SPEED_66 0x01 +#define BUS_SPEED_100 0x02 +#define BUS_SPEED_133 0x03 +#define BUS_SPEED_66PCIX 0x04 +#define BUS_SPEED_66UNKNOWN 0x05 +#define BUS_STATUS_AVAILABLE 0x01 +#define BUS_CONTROL_AVAILABLE 0x02 +#define SLOT_LATCH_REGS_SUPPORTED 0x10 + +#define PRGM_MODEL_REV_LEVEL 0xF0 +#define MAX_ADAPTER_NONE 0x09 + +//---------------------------------------------------------------------------- +// HPC 'write' operations/commands +//---------------------------------------------------------------------------- +// Command Code State Write to reg +// Machine at index +//------------------------- ---- ------- ------------ +#define HPC_CTLR_ENABLEIRQ 0x00 // N 15 +#define HPC_CTLR_DISABLEIRQ 0x01 // N 15 +#define HPC_SLOT_OFF 0x02 // Y 0-14 +#define HPC_SLOT_ON 0x03 // Y 0-14 +#define HPC_SLOT_ATTNOFF 0x04 // N 0-14 +#define HPC_SLOT_ATTNON 0x05 // N 0-14 +#define HPC_CTLR_CLEARIRQ 0x06 // N 15 +#define HPC_CTLR_RESET 0x07 // Y 15 +#define HPC_CTLR_IRQSTEER 0x08 // N 15 +#define HPC_BUS_33CONVMODE 0x09 // Y 31-34 +#define HPC_BUS_66CONVMODE 0x0A // Y 31-34 +#define HPC_BUS_66PCIXMODE 0x0B // Y 31-34 +#define HPC_BUS_100PCIXMODE 0x0C // Y 31-34 +#define HPC_BUS_133PCIXMODE 0x0D // Y 31-34 +#define HPC_ALLSLOT_OFF 0x11 // Y 15 +#define HPC_ALLSLOT_ON 0x12 // Y 15 +#define HPC_SLOT_BLINKLED 0x13 // N 0-14 + +//---------------------------------------------------------------------------- +// read commands +//---------------------------------------------------------------------------- +#define READ_SLOTSTATUS 0x01 +#define READ_EXTSLOTSTATUS 0x02 +#define READ_BUSSTATUS 0x03 +#define READ_CTLRSTATUS 0x04 +#define READ_ALLSTAT 0x05 +#define READ_ALLSLOT 0x06 +#define READ_SLOTLATCHLOWREG 0x07 +#define READ_REVLEVEL 0x08 +#define READ_HPCOPTIONS 0x09 +//---------------------------------------------------------------------------- +// slot status +//---------------------------------------------------------------------------- +#define HPC_SLOT_POWER 0x01 +#define HPC_SLOT_CONNECT 0x02 +#define HPC_SLOT_ATTN 0x04 +#define HPC_SLOT_PRSNT2 0x08 +#define HPC_SLOT_PRSNT1 0x10 +#define HPC_SLOT_PWRGD 0x20 +#define HPC_SLOT_BUS_SPEED 0x40 +#define HPC_SLOT_LATCH 0x80 + +//---------------------------------------------------------------------------- +// HPC_SLOT_POWER status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_POWER_OFF 0x00 +#define HPC_SLOT_POWER_ON 0x01 + +//---------------------------------------------------------------------------- +// HPC_SLOT_CONNECT status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_CONNECTED 0x00 +#define HPC_SLOT_DISCONNECTED 0x01 + +//---------------------------------------------------------------------------- +// HPC_SLOT_ATTN status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_ATTN_OFF 0x00 +#define HPC_SLOT_ATTN_ON 0x01 +#define HPC_SLOT_ATTN_BLINK 0x02 + +//---------------------------------------------------------------------------- +// HPC_SLOT_PRSNT status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_EMPTY 0x00 +#define HPC_SLOT_PRSNT_7 0x01 +#define HPC_SLOT_PRSNT_15 0x02 +#define HPC_SLOT_PRSNT_25 0x03 + +//---------------------------------------------------------------------------- +// HPC_SLOT_PWRGD status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_PWRGD_FAULT_NONE 0x00 +#define HPC_SLOT_PWRGD_GOOD 0x01 + +//---------------------------------------------------------------------------- +// HPC_SLOT_BUS_SPEED status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_BUS_SPEED_OK 0x00 +#define HPC_SLOT_BUS_SPEED_MISM 0x01 + +//---------------------------------------------------------------------------- +// HPC_SLOT_LATCH status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_LATCH_OPEN 0x01 // NOTE : in PCI spec bit off = open +#define HPC_SLOT_LATCH_CLOSED 0x00 // NOTE : in PCI spec bit on = closed + + +//---------------------------------------------------------------------------- +// extended slot status +//---------------------------------------------------------------------------- +#define HPC_SLOT_PCIX 0x01 +#define HPC_SLOT_SPEED1 0x02 +#define HPC_SLOT_SPEED2 0x04 +#define HPC_SLOT_BLINK_ATTN 0x08 +#define HPC_SLOT_RSRVD1 0x10 +#define HPC_SLOT_RSRVD2 0x20 +#define HPC_SLOT_BUS_MODE 0x40 +#define HPC_SLOT_RSRVD3 0x80 + +//---------------------------------------------------------------------------- +// HPC_XSLOT_PCIX_CAP status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_PCIX_NO 0x00 +#define HPC_SLOT_PCIX_YES 0x01 + +//---------------------------------------------------------------------------- +// HPC_XSLOT_SPEED status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_SPEED_33 0x00 +#define HPC_SLOT_SPEED_66 0x01 +#define HPC_SLOT_SPEED_133 0x02 + +//---------------------------------------------------------------------------- +// HPC_XSLOT_ATTN_BLINK status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_ATTN_BLINK_OFF 0x00 +#define HPC_SLOT_ATTN_BLINK_ON 0x01 + +//---------------------------------------------------------------------------- +// HPC_XSLOT_BUS_MODE status return codes +//---------------------------------------------------------------------------- +#define HPC_SLOT_BUS_MODE_OK 0x00 +#define HPC_SLOT_BUS_MODE_MISM 0x01 + +//---------------------------------------------------------------------------- +// Controller status +//---------------------------------------------------------------------------- +#define HPC_CTLR_WORKING 0x01 +#define HPC_CTLR_FINISHED 0x02 +#define HPC_CTLR_RESULT0 0x04 +#define HPC_CTLR_RESULT1 0x08 +#define HPC_CTLR_RESULE2 0x10 +#define HPC_CTLR_RESULT3 0x20 +#define HPC_CTLR_IRQ_ROUTG 0x40 +#define HPC_CTLR_IRQ_PENDG 0x80 + +//---------------------------------------------------------------------------- +// HPC_CTLR_WROKING status return codes +//---------------------------------------------------------------------------- +#define HPC_CTLR_WORKING_NO 0x00 +#define HPC_CTLR_WORKING_YES 0x01 + +//---------------------------------------------------------------------------- +// HPC_CTLR_FINISHED status return codes +//---------------------------------------------------------------------------- +#define HPC_CTLR_FINISHED_NO 0x00 +#define HPC_CTLR_FINISHED_YES 0x01 + +//---------------------------------------------------------------------------- +// HPC_CTLR_RESULT status return codes +//---------------------------------------------------------------------------- +#define HPC_CTLR_RESULT_SUCCESS 0x00 +#define HPC_CTLR_RESULT_FAILED 0x01 +#define HPC_CTLR_RESULT_RSVD 0x02 +#define HPC_CTLR_RESULT_NORESP 0x03 + + +//---------------------------------------------------------------------------- +// macro for slot info +//---------------------------------------------------------------------------- +#define SLOT_POWER(s) ((u8) ((s & HPC_SLOT_POWER) \ + ? HPC_SLOT_POWER_ON : HPC_SLOT_POWER_OFF)) + +#define SLOT_CONNECT(s) ((u8) ((s & HPC_SLOT_CONNECT) \ + ? HPC_SLOT_DISCONNECTED : HPC_SLOT_CONNECTED)) + +#define SLOT_ATTN(s,es) ((u8) ((es & HPC_SLOT_BLINK_ATTN) \ + ? HPC_SLOT_ATTN_BLINK \ + : ((s & HPC_SLOT_ATTN) ? HPC_SLOT_ATTN_ON : HPC_SLOT_ATTN_OFF))) + +#define SLOT_PRESENT(s) ((u8) ((s & HPC_SLOT_PRSNT1) \ + ? ((s & HPC_SLOT_PRSNT2) ? HPC_SLOT_EMPTY : HPC_SLOT_PRSNT_15) \ + : ((s & HPC_SLOT_PRSNT2) ? HPC_SLOT_PRSNT_25 : HPC_SLOT_PRSNT_7))) + +#define SLOT_PWRGD(s) ((u8) ((s & HPC_SLOT_PWRGD) \ + ? HPC_SLOT_PWRGD_GOOD : HPC_SLOT_PWRGD_FAULT_NONE)) + +#define SLOT_BUS_SPEED(s) ((u8) ((s & HPC_SLOT_BUS_SPEED) \ + ? HPC_SLOT_BUS_SPEED_MISM : HPC_SLOT_BUS_SPEED_OK)) + +#define SLOT_LATCH(s) ((u8) ((s & HPC_SLOT_LATCH) \ + ? HPC_SLOT_LATCH_CLOSED : HPC_SLOT_LATCH_OPEN)) + +#define SLOT_PCIX(es) ((u8) ((es & HPC_SLOT_PCIX) \ + ? HPC_SLOT_PCIX_YES : HPC_SLOT_PCIX_NO)) + +#define SLOT_SPEED(es) ((u8) ((es & HPC_SLOT_SPEED2) \ + ? ((es & HPC_SLOT_SPEED1) ? HPC_SLOT_SPEED_133 \ + : HPC_SLOT_SPEED_66) \ + : HPC_SLOT_SPEED_33)) + +#define SLOT_BUS_MODE(es) ((u8) ((es & HPC_SLOT_BUS_MODE) \ + ? HPC_SLOT_BUS_MODE_MISM : HPC_SLOT_BUS_MODE_OK)) + +//-------------------------------------------------------------------------- +// macro for bus info +//--------------------------------------------------------------------------- +#define CURRENT_BUS_SPEED(s) ((u8) (s & BUS_SPEED_2) \ + ? ((s & BUS_SPEED_1) ? BUS_SPEED_133 : BUS_SPEED_100) \ + : ((s & BUS_SPEED_1) ? BUS_SPEED_66 : BUS_SPEED_33)) + +#define CURRENT_BUS_MODE(s) ((u8) (s & BUS_MODE) ? BUS_MODE_PCIX : BUS_MODE_PCI) + +#define READ_BUS_STATUS(s) ((u8) (s->options & BUS_STATUS_AVAILABLE)) + +#define READ_BUS_MODE(s) ((s->revision & PRGM_MODEL_REV_LEVEL) >= 0x20) + +#define SET_BUS_STATUS(s) ((u8) (s->options & BUS_CONTROL_AVAILABLE)) + +#define READ_SLOT_LATCH(s) ((u8) (s->options & SLOT_LATCH_REGS_SUPPORTED)) + +//---------------------------------------------------------------------------- +// macro for controller info +//---------------------------------------------------------------------------- +#define CTLR_WORKING(c) ((u8) ((c & HPC_CTLR_WORKING) \ + ? HPC_CTLR_WORKING_YES : HPC_CTLR_WORKING_NO)) +#define CTLR_FINISHED(c) ((u8) ((c & HPC_CTLR_FINISHED) \ + ? HPC_CTLR_FINISHED_YES : HPC_CTLR_FINISHED_NO)) +#define CTLR_RESULT(c) ((u8) ((c & HPC_CTLR_RESULT1) \ + ? ((c & HPC_CTLR_RESULT0) ? HPC_CTLR_RESULT_NORESP \ + : HPC_CTLR_RESULT_RSVD) \ + : ((c & HPC_CTLR_RESULT0) ? HPC_CTLR_RESULT_FAILED \ + : HPC_CTLR_RESULT_SUCCESS))) + +// command that affect the state machine of HPC +#define NEEDTOCHECK_CMDSTATUS(c) ((c == HPC_SLOT_OFF) || \ + (c == HPC_SLOT_ON) || \ + (c == HPC_CTLR_RESET) || \ + (c == HPC_BUS_33CONVMODE) || \ + (c == HPC_BUS_66CONVMODE) || \ + (c == HPC_BUS_66PCIXMODE) || \ + (c == HPC_BUS_100PCIXMODE) || \ + (c == HPC_BUS_133PCIXMODE) || \ + (c == HPC_ALLSLOT_OFF) || \ + (c == HPC_ALLSLOT_ON)) + + +/* Core part of the driver */ + +#define ENABLE 1 +#define DISABLE 0 + +#define CARD_INFO 0x07 +#define PCIX133 0x07 +#define PCIX66 0x05 +#define PCI66 0x04 + +extern struct pci_bus *ibmphp_pci_bus; + +/* Variables */ + +struct pci_func { + struct pci_dev *dev; /* from the OS */ + u8 busno; + u8 device; + u8 function; + struct resource_node *io[6]; + struct resource_node *mem[6]; + struct resource_node *pfmem[6]; + struct pci_func *next; + int devices[32]; /* for bridge config */ + u8 irq[4]; /* for interrupt config */ + u8 bus; /* flag for unconfiguring, to say if PPB */ +}; + +struct slot { + u8 bus; + u8 device; + u8 number; + u8 real_physical_slot_num; + char name[100]; + u32 capabilities; + u8 supported_speed; + u8 supported_bus_mode; + struct hotplug_slot *hotplug_slot; + struct controller *ctrl; + struct pci_func *func; + u8 irq[4]; + u8 flag; /* this is for disable slot and polling */ + int bit_mode; /* 0 = 32, 1 = 64 */ + u8 ctlr_index; + struct bus_info *bus_on; + struct list_head ibm_slot_list; + u8 status; + u8 ext_status; + u8 busstatus; +}; + +struct controller { + struct ebda_hpc_slot *slots; + struct ebda_hpc_bus *buses; + struct pci_dev *ctrl_dev; /* in case where controller is PCI */ + u8 starting_slot_num; /* starting and ending slot #'s this ctrl controls*/ + u8 ending_slot_num; + u8 revision; + u8 options; /* which options HPC supports */ + u8 status; + u8 ctlr_id; + u8 slot_count; + u8 bus_count; + u8 ctlr_relative_id; + u32 irq; + union { + struct isa_ctlr_access isa_ctlr; + struct pci_ctlr_access pci_ctlr; + struct wpeg_i2c_ctlr_access wpeg_ctlr; + } u; + u8 ctlr_type; + struct list_head ebda_hpc_list; +}; + +/* Functions */ + +extern int ibmphp_init_devno (struct slot **); /* This function is called from EBDA, so we need it not be static */ +extern int ibmphp_disable_slot (struct hotplug_slot *); /* This function is called from HPC, so we need it to not be static */ +extern int ibmphp_do_disable_slot (struct slot *slot_cur); +extern int ibmphp_update_slot_info (struct slot *); /* This function is called from HPC, so we need it to not be be static */ +extern int ibmphp_configure_card (struct pci_func *, u8); +extern int ibmphp_unconfigure_card (struct slot **, int); +extern struct hotplug_slot_ops ibmphp_hotplug_slot_ops; + +static inline void long_delay (int delay) +{ + set_current_state (TASK_INTERRUPTIBLE); + schedule_timeout (delay); +} + +#endif //__IBMPHP_H + diff -Nru a/drivers/pci/hotplug/ibmphp_core.c b/drivers/pci/hotplug/ibmphp_core.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pci/hotplug/ibmphp_core.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,1416 @@ +/* + * IBM Hot Plug Controller Driver + * + * Written By: Chuck Cole, Jyoti Shah, Tong Yu, Irene Zubarev, IBM Corporation + * + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001,2002 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Send feedback to <gregkh@us.ibm.com> + * + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/pci.h> +#include <linux/interrupt.h> +#include <linux/delay.h> +#include <linux/wait.h> +#include <linux/smp_lock.h> +#include "../pci.h" +#include "../../../arch/i386/pci/pci.h" /* for struct irq_routing_table */ +#include "ibmphp.h" + +#define attn_on(sl) ibmphp_hpc_writeslot (sl, HPC_SLOT_ATTNON) +#define attn_off(sl) ibmphp_hpc_writeslot (sl, HPC_SLOT_ATTNOFF) +#define attn_LED_blink(sl) ibmphp_hpc_writeslot (sl, HPC_SLOT_BLINKLED) +#define get_ctrl_revision(sl, rev) ibmphp_hpc_readslot (sl, READ_REVLEVEL, rev) +#define get_hpc_options(sl, opt) ibmphp_hpc_readslot (sl, READ_HPCOPTIONS, opt) + +#define DRIVER_VERSION "0.6" +#define DRIVER_DESC "IBM Hot Plug PCI Controller Driver" + +int ibmphp_debug; + +static int debug; +MODULE_PARM (debug, "i"); +MODULE_PARM_DESC (debug, "Debugging mode enabled or not"); +MODULE_LICENSE ("GPL"); +MODULE_DESCRIPTION (DRIVER_DESC); + +struct pci_bus *ibmphp_pci_bus; +static int max_slots; + +static int irqs[16]; /* PIC mode IRQ's we're using so far (in case MPS tables don't provide default info for empty slots */ + +static int init_flag; + +/* +static int get_max_adapter_speed_1 (struct hotplug_slot *, u8 *, u8); + +static inline int get_max_adapter_speed (struct hotplug_slot *hs, u8 *value) +{ + return get_max_adapter_speed_1 (hs, value, 1); +} +*/ +static inline int get_cur_bus_info (struct slot **sl) +{ + int rc = 1; + struct slot * slot_cur = *sl; + + debug ("options = %x\n", slot_cur->ctrl->options); + debug ("revision = %x\n", slot_cur->ctrl->revision); + + if (READ_BUS_STATUS (slot_cur->ctrl)) + rc = ibmphp_hpc_readslot (slot_cur, READ_BUSSTATUS, NULL); + + if (rc) + return rc; + + slot_cur->bus_on->current_speed = CURRENT_BUS_SPEED (slot_cur->busstatus); + if (READ_BUS_MODE (slot_cur->ctrl)) + slot_cur->bus_on->current_bus_mode = CURRENT_BUS_MODE (slot_cur->busstatus); + else + slot_cur->bus_on->current_bus_mode = 0xFF; + + debug ("busstatus = %x, bus_speed = %x, bus_mode = %x\n", slot_cur->busstatus, slot_cur->bus_on->current_speed, slot_cur->bus_on->current_bus_mode); + + *sl = slot_cur; + return 0; +} + +static inline int slot_update (struct slot **sl) +{ + int rc; + rc = ibmphp_hpc_readslot (*sl, READ_ALLSTAT, NULL); + if (rc) + return rc; + if (!init_flag) + return get_cur_bus_info (sl); + return rc; +} + +static int __init get_max_slots (void) +{ + struct slot * slot_cur; + struct list_head * tmp; + u8 slot_count = 0; + + list_for_each (tmp, &ibmphp_slot_head) { + slot_cur = list_entry (tmp, struct slot, ibm_slot_list); + /* sometimes the hot-pluggable slots start with 4 (not always from 1 */ + slot_count = max (slot_count, slot_cur->number); + } + return slot_count; +} + +/* This routine will put the correct slot->device information per slot. It's + * called from initialization of the slot structures. It will also assign + * interrupt numbers per each slot. + * Parameters: struct slot + * Returns 0 or errors + */ +int ibmphp_init_devno (struct slot **cur_slot) +{ + struct irq_routing_table *rtable; + int len; + int loop; + int i; + + rtable = pcibios_get_irq_routing_table (); + if (!rtable) { + err ("no BIOS routing table...\n"); + return -ENOMEM; + } + + len = (rtable->size - sizeof (struct irq_routing_table)) / sizeof (struct irq_info); + + if (!len) + return -1; + for (loop = 0; loop < len; loop++) { + if ((*cur_slot)->number == rtable->slots[loop].slot) { + if ((*cur_slot)->bus == rtable->slots[loop].bus) { + (*cur_slot)->device = PCI_SLOT (rtable->slots[loop].devfn); + for (i = 0; i < 4; i++) + (*cur_slot)->irq[i] = IO_APIC_get_PCI_irq_vector ((int) (*cur_slot)->bus, (int) (*cur_slot)->device, i); + + debug ("(*cur_slot)->irq[0] = %x\n", (*cur_slot)->irq[0]); + debug ("(*cur_slot)->irq[1] = %x\n", (*cur_slot)->irq[1]); + debug ("(*cur_slot)->irq[2] = %x\n", (*cur_slot)->irq[2]); + debug ("(*cur_slot)->irq[3] = %x\n", (*cur_slot)->irq[3]); + + debug ("rtable->exlusive_irqs = %x\n", rtable->exclusive_irqs); + debug ("rtable->slots[loop].irq[0].bitmap = %x\n", rtable->slots[loop].irq[0].bitmap); + debug ("rtable->slots[loop].irq[1].bitmap = %x\n", rtable->slots[loop].irq[1].bitmap); + debug ("rtable->slots[loop].irq[2].bitmap = %x\n", rtable->slots[loop].irq[2].bitmap); + debug ("rtable->slots[loop].irq[3].bitmap = %x\n", rtable->slots[loop].irq[3].bitmap); + + debug ("rtable->slots[loop].irq[0].link= %x\n", rtable->slots[loop].irq[0].link); + debug ("rtable->slots[loop].irq[1].link = %x\n", rtable->slots[loop].irq[1].link); + debug ("rtable->slots[loop].irq[2].link = %x\n", rtable->slots[loop].irq[2].link); + debug ("rtable->slots[loop].irq[3].link = %x\n", rtable->slots[loop].irq[3].link); + debug ("end of init_devno\n"); + return 0; + } + } + } + + return -1; +} + +static inline int power_on (struct slot *slot_cur) +{ + u8 cmd = HPC_SLOT_ON; + int retval; + + retval = ibmphp_hpc_writeslot (slot_cur, cmd); + if (retval) { + err ("power on failed\n"); + return retval; + } + if (CTLR_RESULT (slot_cur->ctrl->status)) { + err ("command not completed successfully in power_on \n"); + return -EIO; + } + long_delay (3 * HZ); /* For ServeRAID cards, and some 66 PCI */ + return 0; +} + +static inline int power_off (struct slot *slot_cur) +{ + u8 cmd = HPC_SLOT_OFF; + int retval; + + retval = ibmphp_hpc_writeslot (slot_cur, cmd); + if (retval) { + err ("power off failed \n"); + return retval; + } + if (CTLR_RESULT (slot_cur->ctrl->status)) { + err ("command not completed successfully in power_off \n"); + return -EIO; + } + return 0; +} + +static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 value) +{ + int rc = 0; + struct slot *pslot; + u8 cmd; + int hpcrc = 0; + + debug ("set_attention_status - Entry hotplug_slot[%lx] value[%x]\n", (ulong) hotplug_slot, value); + ibmphp_lock_operations (); + cmd = 0x00; // avoid compiler warning + + if (hotplug_slot) { + switch (value) { + case HPC_SLOT_ATTN_OFF: + cmd = HPC_SLOT_ATTNOFF; + break; + case HPC_SLOT_ATTN_ON: + cmd = HPC_SLOT_ATTNON; + break; + case HPC_SLOT_ATTN_BLINK: + cmd = HPC_SLOT_BLINKLED; + break; + default: + rc = -ENODEV; + err ("set_attention_status - Error : invalid input [%x]\n", value); + break; + } + if (rc == 0) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) + hpcrc = ibmphp_hpc_writeslot (pslot, cmd); + else + rc = -ENODEV; + } + } else + rc = -ENODEV; + + if (hpcrc) + rc = hpcrc; + + ibmphp_unlock_operations (); + + debug ("set_attention_status - Exit rc[%d]\n", rc); + return rc; +} + +static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 * value) +{ + int rc = -ENODEV; + struct slot *pslot; + int hpcrc = 0; + struct slot myslot; + + debug ("get_attention_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); + + ibmphp_lock_operations (); + if (hotplug_slot && value) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) { + memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); + hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status)); + if (!hpcrc) + hpcrc = ibmphp_hpc_readslot (pslot, READ_EXTSLOTSTATUS, &(myslot.ext_status)); + if (!hpcrc) { + *value = SLOT_ATTN (myslot.status, myslot.ext_status); + rc = 0; + } + } + } else + rc = -ENODEV; + + if (hpcrc) + rc = hpcrc; + + ibmphp_unlock_operations (); + debug ("get_attention_status - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value); + return rc; +} + +static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 * value) +{ + int rc = -ENODEV; + struct slot *pslot; + int hpcrc = 0; + struct slot myslot; + + debug ("get_latch_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); + ibmphp_lock_operations (); + if (hotplug_slot && value) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) { + memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); + hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status)); + if (!hpcrc) { + *value = SLOT_LATCH (myslot.status); + rc = 0; + } + } + } else + rc = -ENODEV; + + if (hpcrc) + rc = hpcrc; + + ibmphp_unlock_operations (); + debug ("get_latch_status - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value); + return rc; +} + + +static int get_power_status (struct hotplug_slot *hotplug_slot, u8 * value) +{ + int rc = -ENODEV; + struct slot *pslot; + int hpcrc = 0; + struct slot myslot; + + debug ("get_power_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); + ibmphp_lock_operations (); + if (hotplug_slot && value) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) { + memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); + hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status)); + if (!hpcrc) { + *value = SLOT_PWRGD (myslot.status); + rc = 0; + } + } + } else + rc = -ENODEV; + + if (hpcrc) + rc = hpcrc; + + ibmphp_unlock_operations (); + debug ("get_power_status - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value); + return rc; +} + +static int get_adapter_present (struct hotplug_slot *hotplug_slot, u8 * value) +{ + int rc = -ENODEV; + struct slot *pslot; + u8 present; + int hpcrc = 0; + struct slot myslot; + + debug ("get_adapter_status - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong) hotplug_slot, (ulong) value); + ibmphp_lock_operations (); + if (hotplug_slot && value) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) { + memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); + hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status)); + if (!hpcrc) { + present = SLOT_PRESENT (myslot.status); + if (present == HPC_SLOT_EMPTY) + *value = 0; + else + *value = 1; + rc = 0; + } + } + } else + rc = -ENODEV; + if (hpcrc) + rc = hpcrc; + + ibmphp_unlock_operations (); + debug ("get_adapter_present - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value); + return rc; +} + +static int get_max_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) +{ + int rc = -ENODEV; + struct slot *pslot; + u8 mode = 0; + + debug ("%s - Entry hotplug_slot[%p] pvalue[%p]\n", __FUNCTION__, + hotplug_slot, value); + + ibmphp_lock_operations (); + + if (hotplug_slot && value) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) { + rc = 0; + mode = pslot->supported_bus_mode; + *value = pslot->supported_speed; + switch (*value) { + case BUS_SPEED_33: + break; + case BUS_SPEED_66: + if (mode == BUS_MODE_PCIX) + *value += 0x01; + break; + case BUS_SPEED_100: + case BUS_SPEED_133: + *value = pslot->supported_speed + 0x01; + break; + default: + /* Note (will need to change): there would be soon 256, 512 also */ + rc = -ENODEV; + } + } + } else + rc = -ENODEV; + + ibmphp_unlock_operations (); + debug ("%s - Exit rc[%d] value[%x]\n", __FUNCTION__, rc, *value); + return rc; +} + +static int get_cur_bus_speed (struct hotplug_slot *hotplug_slot, enum pci_bus_speed *value) +{ + int rc = -ENODEV; + struct slot *pslot; + u8 mode = 0; + + debug ("%s - Entry hotplug_slot[%p] pvalue[%p]\n", __FUNCTION__, + hotplug_slot, value); + + ibmphp_lock_operations (); + + if (hotplug_slot && value) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) { + rc = get_cur_bus_info (&pslot); + if (!rc) { + mode = pslot->bus_on->current_bus_mode; + *value = pslot->bus_on->current_speed; + switch (*value) { + case BUS_SPEED_33: + break; + case BUS_SPEED_66: + if (mode == BUS_MODE_PCIX) + *value += 0x01; + else if (mode == BUS_MODE_PCI) + ; + else + *value = PCI_SPEED_UNKNOWN; + break; + case BUS_SPEED_100: + case BUS_SPEED_133: + *value += 0x01; + break; + default: + /* Note of change: there would also be 256, 512 soon */ + rc = -ENODEV; + } + } + } + } else + rc = -ENODEV; + + ibmphp_unlock_operations (); + debug ("%s - Exit rc[%d] value[%x]\n", __FUNCTION__, rc, *value); + return rc; +} +/* +static int get_max_adapter_speed_1 (struct hotplug_slot *hotplug_slot, u8 * value, u8 flag) +{ + int rc = -ENODEV; + struct slot *pslot; + int hpcrc = 0; + struct slot myslot; + + debug ("get_max_adapter_speed_1 - Entry hotplug_slot[%lx] pvalue[%lx]\n", (ulong)hotplug_slot, (ulong) value); + + if (flag) + ibmphp_lock_operations (); + + if (hotplug_slot && value) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) { + memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); + hpcrc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &(myslot.status)); + + if (!(SLOT_LATCH (myslot.status)) && (SLOT_PRESENT (myslot.status))) { + hpcrc = ibmphp_hpc_readslot (pslot, READ_EXTSLOTSTATUS, &(myslot.ext_status)); + if (!hpcrc) { + *value = SLOT_SPEED (myslot.ext_status); + rc = 0; + } + } else { + *value = MAX_ADAPTER_NONE; + rc = 0; + } + } + } else + rc = -ENODEV; + + if (hpcrc) + rc = hpcrc; + + if (flag) + ibmphp_unlock_operations (); + + debug ("get_max_adapter_speed_1 - Exit rc[%d] hpcrc[%x] value[%x]\n", rc, hpcrc, *value); + return rc; +} + +static int get_bus_name (struct hotplug_slot *hotplug_slot, char * value) +{ + int rc = -ENODEV; + struct slot *pslot = NULL; + + debug ("get_bus_name - Entry hotplug_slot[%lx] \n", (ulong)hotplug_slot); + + ibmphp_lock_operations (); + + if (hotplug_slot) { + pslot = (struct slot *) hotplug_slot->private; + if (pslot) { + rc = 0; + snprintf (value, 100, "Bus %x", pslot->bus); + } + } else + rc = -ENODEV; + + ibmphp_unlock_operations (); + debug ("get_bus_name - Exit rc[%d] value[%x]\n", rc, *value); + return rc; +} +*/ + +/******************************************************************************* + * This routine will initialize the ops data structure used in the validate + * function. It will also power off empty slots that are powered on since BIOS + * leaves those on, albeit disconnected + ******************************************************************************/ +static int __init init_ops (void) +{ + struct slot *slot_cur; + struct list_head *tmp; + int retval; + int rc; + + list_for_each (tmp, &ibmphp_slot_head) { + slot_cur = list_entry (tmp, struct slot, ibm_slot_list); + + if (!slot_cur) + return -ENODEV; + + debug ("BEFORE GETTING SLOT STATUS, slot # %x\n", slot_cur->number); + if (slot_cur->ctrl->revision == 0xFF) + if (get_ctrl_revision (slot_cur, &slot_cur->ctrl->revision)) + return -1; + + if (slot_cur->bus_on->current_speed == 0xFF) + if (get_cur_bus_info (&slot_cur)) + return -1; + + if (slot_cur->ctrl->options == 0xFF) + if (get_hpc_options (slot_cur, &slot_cur->ctrl->options)) + return -1; + + retval = slot_update (&slot_cur); + if (retval) + return retval; + + debug ("status = %x\n", slot_cur->status); + debug ("ext_status = %x\n", slot_cur->ext_status); + debug ("SLOT_POWER = %x\n", SLOT_POWER (slot_cur->status)); + debug ("SLOT_PRESENT = %x\n", SLOT_PRESENT (slot_cur->status)); + debug ("SLOT_LATCH = %x\n", SLOT_LATCH (slot_cur->status)); + + if ((SLOT_PWRGD (slot_cur->status)) && + !(SLOT_PRESENT (slot_cur->status)) && + !(SLOT_LATCH (slot_cur->status))) { + debug ("BEFORE POWER OFF COMMAND\n"); + rc = power_off (slot_cur); + if (rc) + return rc; + + /* retval = slot_update (&slot_cur); + * if (retval) + * return retval; + * ibmphp_update_slot_info (slot_cur); + */ + } + } + init_flag = 0; + return 0; +} + +/* This operation will check whether the slot is within the bounds and + * the operation is valid to perform on that slot + * Parameters: slot, operation + * Returns: 0 or error codes + */ +static int validate (struct slot *slot_cur, int opn) +{ + int number; + int retval; + + if (!slot_cur) + return -ENODEV; + number = slot_cur->number; + if ((number > max_slots) || (number < 0)) + return -EBADSLT; + debug ("slot_number in validate is %d\n", slot_cur->number); + + retval = slot_update (&slot_cur); + if (retval) + return retval; + + switch (opn) { + case ENABLE: + if (!(SLOT_PWRGD (slot_cur->status)) && + (SLOT_PRESENT (slot_cur->status)) && + !(SLOT_LATCH (slot_cur->status))) + return 0; + break; + case DISABLE: + if ((SLOT_PWRGD (slot_cur->status)) && + (SLOT_PRESENT (slot_cur->status)) && + !(SLOT_LATCH (slot_cur->status))) + return 0; + break; + default: + break; + } + err ("validate failed....\n"); + return -EINVAL; +} + +/******************************************************************************** + * This routine is for updating the data structures in the hotplug core + * Parameters: struct slot + * Returns: 0 or error + *******************************************************************************/ +int ibmphp_update_slot_info (struct slot *slot_cur) +{ + struct hotplug_slot_info *info; + int rc; + u8 bus_speed; + u8 mode; + + info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); + if (!info) { + err ("out of system memory \n"); + return -ENOMEM; + } + + info->power_status = SLOT_PWRGD (slot_cur->status); + info->attention_status = SLOT_ATTN (slot_cur->status, slot_cur->ext_status); + info->latch_status = SLOT_LATCH (slot_cur->status); + if (!SLOT_PRESENT (slot_cur->status)) { + info->adapter_status = 0; +// info->max_adapter_speed_status = MAX_ADAPTER_NONE; + } else { + info->adapter_status = 1; +// get_max_adapter_speed_1 (slot_cur->hotplug_slot, &info->max_adapter_speed_status, 0); + } + + bus_speed = slot_cur->bus_on->current_speed; + mode = slot_cur->bus_on->current_bus_mode; + + switch (bus_speed) { + case BUS_SPEED_33: + break; + case BUS_SPEED_66: + if (mode == BUS_MODE_PCIX) + bus_speed += 0x01; + else if (mode == BUS_MODE_PCI) + ; + else + bus_speed = PCI_SPEED_UNKNOWN; + break; + case BUS_SPEED_100: + case BUS_SPEED_133: + bus_speed += 0x01; + break; + default: + bus_speed = PCI_SPEED_UNKNOWN; + } + + info->cur_bus_speed = bus_speed; + info->max_bus_speed = slot_cur->hotplug_slot->info->max_bus_speed; + // To do: bus_names + + rc = pci_hp_change_slot_info (slot_cur->hotplug_slot, info); + kfree (info); + return rc; +} + + +/****************************************************************************** + * This function will return the pci_func, given bus and devfunc, or NULL. It + * is called from visit routines + ******************************************************************************/ + +static struct pci_func *ibm_slot_find (u8 busno, u8 device, u8 function) +{ + struct pci_func *func_cur; + struct slot *slot_cur; + struct list_head * tmp; + list_for_each (tmp, &ibmphp_slot_head) { + slot_cur = list_entry (tmp, struct slot, ibm_slot_list); + if (slot_cur->func) { + func_cur = slot_cur->func; + while (func_cur) { + if ((func_cur->busno == busno) && (func_cur->device == device) && (func_cur->function == function)) + return func_cur; + func_cur = func_cur->next; + } + } + } + return NULL; +} + +/************************************************************* + * This routine frees up memory used by struct slot, including + * the pointers to pci_func, bus, hotplug_slot, controller, + * and deregistering from the hotplug core + *************************************************************/ +static void free_slots (void) +{ + struct slot *slot_cur; + struct list_head * tmp; + struct list_head * next; + + debug ("%s -- enter\n", __FUNCTION__); + + list_for_each_safe (tmp, next, &ibmphp_slot_head) { + + slot_cur = list_entry (tmp, struct slot, ibm_slot_list); + + pci_hp_deregister (slot_cur->hotplug_slot); + + if (slot_cur->hotplug_slot) { + kfree (slot_cur->hotplug_slot); + slot_cur->hotplug_slot = NULL; + } + + if (slot_cur->ctrl) + slot_cur->ctrl = NULL; + + if (slot_cur->bus_on) + slot_cur->bus_on = NULL; + + ibmphp_unconfigure_card (&slot_cur, -1); /* we don't want to actually remove the resources, since free_resources will do just that */ + + kfree (slot_cur); + slot_cur = NULL; + } + debug ("%s -- exit\n", __FUNCTION__); +} + +static int ibm_unconfigure_device (struct pci_func *func) +{ + struct pci_dev *temp; + u8 j; + + debug ("inside %s\n", __FUNCTION__); + debug ("func->device = %x, func->function = %x\n", func->device, func->function); + debug ("func->device << 3 | 0x0 = %x\n", func->device << 3 | 0x0); + + for (j = 0; j < 0x08; j++) { + temp = pci_find_slot (func->busno, (func->device << 3) | j); + if (temp) + pci_remove_bus_device(temp); + } + return 0; +} + +/* + * The following function is to fix kernel bug regarding + * getting bus entries, here we manually add those primary + * bus entries to kernel bus structure whenever apply + */ + +static u8 bus_structure_fixup (u8 busno) +{ + struct pci_bus *bus; + struct pci_dev *dev; + u16 l; + + if (pci_find_bus(busno) || !(ibmphp_find_same_bus_num (busno))) + return 1; + + bus = kmalloc (sizeof (*bus), GFP_KERNEL); + if (!bus) { + err ("%s - out of memory\n", __FUNCTION__); + return 1; + } + dev = kmalloc (sizeof (*dev), GFP_KERNEL); + if (!dev) { + kfree (bus); + err ("%s - out of memory\n", __FUNCTION__); + return 1; + } + + bus->number = busno; + bus->ops = ibmphp_pci_bus->ops; + dev->bus = bus; + for (dev->devfn = 0; dev->devfn < 256; dev->devfn += 8) { + if (!pci_read_config_word (dev, PCI_VENDOR_ID, &l) && l != 0x0000 && l != 0xffff) { + debug ("%s - Inside bus_struture_fixup() \n", __FUNCTION__); + pci_scan_bus (busno, ibmphp_pci_bus->ops, NULL); + break; + } + } + + kfree (dev); + kfree (bus); + + return 0; +} + +static int ibm_configure_device (struct pci_func *func) +{ + unsigned char bus; + struct pci_bus *child; + int num; + int flag = 0; /* this is to make sure we don't double scan the bus, for bridged devices primarily */ + + if (!(bus_structure_fixup (func->busno))) + flag = 1; + if (func->dev == NULL) + func->dev = pci_find_slot (func->busno, PCI_DEVFN(func->device, func->function)); + + if (func->dev == NULL) { + struct pci_bus *bus = pci_find_bus(func->busno); + if (!bus) + return 0; + + num = pci_scan_slot(bus, PCI_DEVFN(func->device, func->function)); + if (num) + pci_bus_add_devices(bus); + + func->dev = pci_find_slot(func->busno, PCI_DEVFN(func->device, func->function)); + if (func->dev == NULL) { + err ("ERROR... : pci_dev still NULL \n"); + return 0; + } + } + if (!(flag) && (func->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE)) { + pci_read_config_byte (func->dev, PCI_SECONDARY_BUS, &bus); + child = (struct pci_bus *) pci_add_new_bus (func->dev->bus, (func->dev), bus); + pci_do_scan_bus (child); + } + + return 0; +} + +/******************************************************* + * Returns whether the bus is empty or not + *******************************************************/ +static int is_bus_empty (struct slot * slot_cur) +{ + int rc; + struct slot * tmp_slot; + u8 i = slot_cur->bus_on->slot_min; + + while (i <= slot_cur->bus_on->slot_max) { + if (i == slot_cur->number) { + i++; + continue; + } + tmp_slot = ibmphp_get_slot_from_physical_num (i); + if (!tmp_slot) + return 0; + rc = slot_update (&tmp_slot); + if (rc) + return 0; + if (SLOT_PRESENT (tmp_slot->status) && SLOT_PWRGD (tmp_slot->status)) + return 0; + i++; + } + return 1; +} + +/*********************************************************** + * If the HPC permits and the bus currently empty, tries to set the + * bus speed and mode at the maximum card and bus capability + * Parameters: slot + * Returns: bus is set (0) or error code + ***********************************************************/ +static int set_bus (struct slot * slot_cur) +{ + int rc; + u8 speed; + u8 cmd = 0x0; + struct pci_dev *dev = NULL; + int retval; + + debug ("%s - entry slot # %d \n", __FUNCTION__, slot_cur->number); + if (SET_BUS_STATUS (slot_cur->ctrl) && is_bus_empty (slot_cur)) { + rc = slot_update (&slot_cur); + if (rc) + return rc; + speed = SLOT_SPEED (slot_cur->ext_status); + debug ("ext_status = %x, speed = %x\n", slot_cur->ext_status, speed); + switch (speed) { + case HPC_SLOT_SPEED_33: + cmd = HPC_BUS_33CONVMODE; + break; + case HPC_SLOT_SPEED_66: + if (SLOT_PCIX (slot_cur->ext_status)) { + if ((slot_cur->supported_speed >= BUS_SPEED_66) && (slot_cur->supported_bus_mode == BUS_MODE_PCIX)) + cmd = HPC_BUS_66PCIXMODE; + else if (!SLOT_BUS_MODE (slot_cur->ext_status)) + /* if max slot/bus capability is 66 pci + and there's no bus mode mismatch, then + the adapter supports 66 pci */ + cmd = HPC_BUS_66CONVMODE; + else + cmd = HPC_BUS_33CONVMODE; + } else { + if (slot_cur->supported_speed >= BUS_SPEED_66) + cmd = HPC_BUS_66CONVMODE; + else + cmd = HPC_BUS_33CONVMODE; + } + break; + case HPC_SLOT_SPEED_133: + switch (slot_cur->supported_speed) { + case BUS_SPEED_33: + cmd = HPC_BUS_33CONVMODE; + break; + case BUS_SPEED_66: + if (slot_cur->supported_bus_mode == BUS_MODE_PCIX) + cmd = HPC_BUS_66PCIXMODE; + else + cmd = HPC_BUS_66CONVMODE; + break; + case BUS_SPEED_100: + cmd = HPC_BUS_100PCIXMODE; + break; + case BUS_SPEED_133: + /* This is to take care of the bug in CIOBX chip */ + while ((dev = pci_find_device(PCI_VENDOR_ID_SERVERWORKS, + 0x0101, dev)) != NULL) + ibmphp_hpc_writeslot (slot_cur, HPC_BUS_100PCIXMODE); + cmd = HPC_BUS_133PCIXMODE; + break; + default: + err ("Wrong bus speed \n"); + return -ENODEV; + } + break; + default: + err ("wrong slot speed \n"); + return -ENODEV; + } + debug ("setting bus speed for slot %d, cmd %x\n", slot_cur->number, cmd); + retval = ibmphp_hpc_writeslot (slot_cur, cmd); + if (retval) { + err ("setting bus speed failed\n"); + return retval; + } + if (CTLR_RESULT (slot_cur->ctrl->status)) { + err ("command not completed successfully in set_bus \n"); + return -EIO; + } + } + /* This is for x440, once Brandon fixes the firmware, + will not need this delay */ + long_delay (1 * HZ); + debug ("%s -Exit \n", __FUNCTION__); + return 0; +} + +/* This routine checks the bus limitations that the slot is on from the BIOS. + * This is used in deciding whether or not to power up the slot. + * (electrical/spec limitations. For example, >1 133 MHz or >2 66 PCI cards on + * same bus) + * Parameters: slot + * Returns: 0 = no limitations, -EINVAL = exceeded limitations on the bus + */ +static int check_limitations (struct slot *slot_cur) +{ + u8 i; + struct slot * tmp_slot; + u8 count = 0; + u8 limitation = 0; + + for (i = slot_cur->bus_on->slot_min; i <= slot_cur->bus_on->slot_max; i++) { + tmp_slot = ibmphp_get_slot_from_physical_num (i); + if (!tmp_slot) + return -ENODEV; + if ((SLOT_PWRGD (tmp_slot->status)) && !(SLOT_CONNECT (tmp_slot->status))) + count++; + } + get_cur_bus_info (&slot_cur); + switch (slot_cur->bus_on->current_speed) { + case BUS_SPEED_33: + limitation = slot_cur->bus_on->slots_at_33_conv; + break; + case BUS_SPEED_66: + if (slot_cur->bus_on->current_bus_mode == BUS_MODE_PCIX) + limitation = slot_cur->bus_on->slots_at_66_pcix; + else + limitation = slot_cur->bus_on->slots_at_66_conv; + break; + case BUS_SPEED_100: + limitation = slot_cur->bus_on->slots_at_100_pcix; + break; + case BUS_SPEED_133: + limitation = slot_cur->bus_on->slots_at_133_pcix; + break; + } + + if ((count + 1) > limitation) + return -EINVAL; + return 0; +} + +static inline void print_card_capability (struct slot *slot_cur) +{ + info ("capability of the card is "); + if ((slot_cur->ext_status & CARD_INFO) == PCIX133) + info (" 133 MHz PCI-X \n"); + else if ((slot_cur->ext_status & CARD_INFO) == PCIX66) + info (" 66 MHz PCI-X \n"); + else if ((slot_cur->ext_status & CARD_INFO) == PCI66) + info (" 66 MHz PCI \n"); + else + info (" 33 MHz PCI \n"); + +} + +/* This routine will power on the slot, configure the device(s) and find the + * drivers for them. + * Parameters: hotplug_slot + * Returns: 0 or failure codes + */ +static int enable_slot (struct hotplug_slot *hs) +{ + int rc, i, rcpr; + struct slot *slot_cur; + u8 function; + struct pci_func *tmp_func; + + ibmphp_lock_operations (); + + debug ("ENABLING SLOT........ \n"); + slot_cur = (struct slot *) hs->private; + + if ((rc = validate (slot_cur, ENABLE))) { + err ("validate function failed \n"); + goto error_nopower; + } + + attn_LED_blink (slot_cur); + + rc = set_bus (slot_cur); + if (rc) { + err ("was not able to set the bus \n"); + goto error_nopower; + } + + /*-----------------debugging------------------------------*/ + get_cur_bus_info (&slot_cur); + debug ("the current bus speed right after set_bus = %x \n", slot_cur->bus_on->current_speed); + /*----------------------------------------------------------*/ + + rc = check_limitations (slot_cur); + if (rc) { + err ("Adding this card exceeds the limitations of this bus.\n"); + err ("(i.e., >1 133MHz cards running on same bus, or " + ">2 66 PCI cards running on same bus\n."); + err ("Try hot-adding into another bus \n"); + rc = -EINVAL; + goto error_nopower; + } + + rc = power_on (slot_cur); + + if (rc) { + err ("something wrong when powering up... please see below for details\n"); + /* need to turn off before on, otherwise, blinking overwrites */ + attn_off(slot_cur); + attn_on (slot_cur); + if (slot_update (&slot_cur)) { + attn_off (slot_cur); + attn_on (slot_cur); + rc = -ENODEV; + goto exit; + } + /* Check to see the error of why it failed */ + if ((SLOT_POWER (slot_cur->status)) && !(SLOT_PWRGD (slot_cur->status))) + err ("power fault occurred trying to power up \n"); + else if (SLOT_BUS_SPEED (slot_cur->status)) { + err ("bus speed mismatch occurred. please check current bus speed and card capability \n"); + print_card_capability (slot_cur); + } else if (SLOT_BUS_MODE (slot_cur->ext_status)) { + err ("bus mode mismatch occurred. please check current bus mode and card capability \n"); + print_card_capability (slot_cur); + } + ibmphp_update_slot_info (slot_cur); + goto exit; + } + debug ("after power_on\n"); + /*-----------------------debugging---------------------------*/ + get_cur_bus_info (&slot_cur); + debug ("the current bus speed right after power_on = %x \n", slot_cur->bus_on->current_speed); + /*----------------------------------------------------------*/ + + rc = slot_update (&slot_cur); + if (rc) + goto error_power; + + rc = -EINVAL; + if (SLOT_POWER (slot_cur->status) && !(SLOT_PWRGD (slot_cur->status))) { + err ("power fault occurred trying to power up... \n"); + goto error_power; + } + if (SLOT_POWER (slot_cur->status) && (SLOT_BUS_SPEED (slot_cur->status))) { + err ("bus speed mismatch occurred. please check current bus speed and card capability \n"); + print_card_capability (slot_cur); + goto error_power; + } + /* Don't think this case will happen after above checks... but just in case, for paranoia sake */ + if (!(SLOT_POWER (slot_cur->status))) { + err ("power on failed... \n"); + goto error_power; + } + + slot_cur->func = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); + if (!slot_cur->func) { + /* We cannot do update_slot_info here, since no memory for + * kmalloc n.e.ways, and update_slot_info allocates some */ + err ("out of system memory \n"); + rc = -ENOMEM; + goto error_power; + } + memset (slot_cur->func, 0, sizeof (struct pci_func)); + slot_cur->func->busno = slot_cur->bus; + slot_cur->func->device = slot_cur->device; + for (i = 0; i < 4; i++) + slot_cur->func->irq[i] = slot_cur->irq[i]; + + debug ("b4 configure_card, slot_cur->bus = %x, slot_cur->device = %x\n", slot_cur->bus, slot_cur->device); + + if (ibmphp_configure_card (slot_cur->func, slot_cur->number)) { + err ("configure_card was unsuccessful... \n"); + ibmphp_unconfigure_card (&slot_cur, 1); /* true because don't need to actually deallocate resources, just remove references */ + debug ("after unconfigure_card\n"); + slot_cur->func = NULL; + rc = -ENOMEM; + goto error_power; + } + + function = 0x00; + do { + tmp_func = ibm_slot_find (slot_cur->bus, slot_cur->func->device, function++); + if (tmp_func && !(tmp_func->dev)) + ibm_configure_device (tmp_func); + } while (tmp_func); + + attn_off (slot_cur); + if (slot_update (&slot_cur)) { + rc = -EFAULT; + goto exit; + } + ibmphp_print_test (); + rc = ibmphp_update_slot_info (slot_cur); +exit: + ibmphp_unlock_operations(); + return rc; + +error_nopower: + attn_off (slot_cur); /* need to turn off if was blinking b4 */ + attn_on (slot_cur); +error_cont: + rcpr = slot_update (&slot_cur); + if (rcpr) { + rc = rcpr; + goto exit; + } + ibmphp_update_slot_info (slot_cur); + goto exit; + +error_power: + attn_off (slot_cur); /* need to turn off if was blinking b4 */ + attn_on (slot_cur); + rcpr = power_off (slot_cur); + if (rcpr) { + rc = rcpr; + goto exit; + } + goto error_cont; +} + +/************************************************************** +* HOT REMOVING ADAPTER CARD * +* INPUT: POINTER TO THE HOTPLUG SLOT STRUCTURE * +* OUTPUT: SUCCESS 0 ; FAILURE: UNCONFIGURE , VALIDATE * + DISABLE POWER , * +**************************************************************/ +int ibmphp_disable_slot (struct hotplug_slot *hotplug_slot) +{ + struct slot *slot = hotplug_slot->private; + int rc; + + ibmphp_lock_operations(); + rc = ibmphp_do_disable_slot(slot); + ibmphp_unlock_operations(); + return rc; +} + +int ibmphp_do_disable_slot (struct slot *slot_cur) +{ + int rc; + u8 flag; + int parm = 0; + + debug ("DISABLING SLOT... \n"); + + if ((slot_cur == NULL) || (slot_cur->ctrl == NULL)) { + return -ENODEV; + } + + flag = slot_cur->flag; + slot_cur->flag = TRUE; + + if (flag == TRUE) { + rc = validate (slot_cur, DISABLE); /* checking if powered off already & valid slot # */ + if (rc) + goto error; + } + attn_LED_blink (slot_cur); + + if (slot_cur->func == NULL) { + /* We need this for fncs's that were there on bootup */ + slot_cur->func = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); + if (!slot_cur->func) { + err ("out of system memory \n"); + rc = -ENOMEM; + goto error; + } + memset (slot_cur->func, 0, sizeof (struct pci_func)); + slot_cur->func->busno = slot_cur->bus; + slot_cur->func->device = slot_cur->device; + } + + if ((rc = ibm_unconfigure_device (slot_cur->func))) { + err ("removing from kernel failed... \n"); + err ("Please check to see if it was statically linked or is " + "in use otherwise. (perhaps the driver is not 'hot-removable')\n"); + goto error; + } + + /* If we got here from latch suddenly opening on operating card or + a power fault, there's no power to the card, so cannot + read from it to determine what resources it occupied. This operation + is forbidden anyhow. The best we can do is remove it from kernel + lists at least */ + + if (!flag) { + attn_off (slot_cur); + return 0; + } + + rc = ibmphp_unconfigure_card (&slot_cur, parm); + slot_cur->func = NULL; + debug ("in disable_slot. after unconfigure_card\n"); + if (rc) { + err ("could not unconfigure card.\n"); + goto error; + } + + rc = ibmphp_hpc_writeslot (slot_cur, HPC_SLOT_OFF); + if (rc) + goto error; + + attn_off (slot_cur); + rc = slot_update (&slot_cur); + if (rc) + goto exit; + + rc = ibmphp_update_slot_info (slot_cur); + ibmphp_print_test (); +exit: + return rc; + +error: + /* Need to turn off if was blinking b4 */ + attn_off (slot_cur); + attn_on (slot_cur); + if (slot_update (&slot_cur)) { + rc = -EFAULT; + goto exit; + } + if (flag) + ibmphp_update_slot_info (slot_cur); + goto exit; +} + +struct hotplug_slot_ops ibmphp_hotplug_slot_ops = { + .owner = THIS_MODULE, + .set_attention_status = set_attention_status, + .enable_slot = enable_slot, + .disable_slot = ibmphp_disable_slot, + .hardware_test = NULL, + .get_power_status = get_power_status, + .get_attention_status = get_attention_status, + .get_latch_status = get_latch_status, + .get_adapter_status = get_adapter_present, + .get_max_bus_speed = get_max_bus_speed, + .get_cur_bus_speed = get_cur_bus_speed, +/* .get_max_adapter_speed = get_max_adapter_speed, + .get_bus_name_status = get_bus_name, +*/ +}; + +static void ibmphp_unload (void) +{ + free_slots (); + debug ("after slots \n"); + ibmphp_free_resources (); + debug ("after resources \n"); + ibmphp_free_bus_info_queue (); + debug ("after bus info \n"); + ibmphp_free_ebda_hpc_queue (); + debug ("after ebda hpc \n"); + ibmphp_free_ebda_pci_rsrc_queue (); + debug ("after ebda pci rsrc \n"); + kfree (ibmphp_pci_bus); +} + +static int __init ibmphp_init (void) +{ + struct pci_bus *bus; + int i = 0; + int rc = 0; + + init_flag = 1; + + info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); + + ibmphp_pci_bus = kmalloc (sizeof (*ibmphp_pci_bus), GFP_KERNEL); + if (!ibmphp_pci_bus) { + err ("out of memory\n"); + rc = -ENOMEM; + goto exit; + } + + bus = pci_find_bus(0); + if (!bus) { + err ("Can't find the root pci bus, can not continue\n"); + rc = -ENODEV; + goto error; + } + memcpy (ibmphp_pci_bus, bus, sizeof (*ibmphp_pci_bus)); + + ibmphp_debug = debug; + + ibmphp_hpc_initvars (); + + for (i = 0; i < 16; i++) + irqs[i] = 0; + + if ((rc = ibmphp_access_ebda ())) + goto error; + debug ("after ibmphp_access_ebda ()\n"); + + if ((rc = ibmphp_rsrc_init ())) + goto error; + debug ("AFTER Resource & EBDA INITIALIZATIONS\n"); + + max_slots = get_max_slots (); + + if ((rc = ibmphp_register_pci ())) + goto error; + + if (init_ops ()) { + rc = -ENODEV; + goto error; + } + + ibmphp_print_test (); + if ((rc = ibmphp_hpc_start_poll_thread ())) { + goto error; + } + + /* lock ourselves into memory with a module + * count of -1 so that no one can unload us. */ + module_put(THIS_MODULE); + +exit: + return rc; + +error: + ibmphp_unload (); + goto exit; +} + +static void __exit ibmphp_exit (void) +{ + ibmphp_hpc_stop_poll_thread (); + debug ("after polling\n"); + ibmphp_unload (); + debug ("done\n"); +} + +module_init (ibmphp_init); +module_exit (ibmphp_exit); diff -Nru a/drivers/pci/hotplug/ibmphp_ebda.c b/drivers/pci/hotplug/ibmphp_ebda.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pci/hotplug/ibmphp_ebda.c Mon Jun 9 23:16:08 2003 @@ -0,0 +1,1228 @@ +/* + * IBM Hot Plug Controller Driver + * + * Written By: Tong Yu, IBM Corporation + * + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001,2002 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Send feedback to <gregkh@us.ibm.com> + * + */ + +#include <linux/module.h> +#include <linux/sched.h> +#include <linux/errno.h> +#include <linux/mm.h> +#include <linux/slab.h> +#include <linux/pci.h> +#include <linux/list.h> +#include <linux/init.h> +#include "ibmphp.h" + +/* + * POST builds data blocks(in this data block definition, a char-1 + * byte, short(or word)-2 byte, long(dword)-4 byte) in the Extended + * BIOS Data Area which describe the configuration of the hot-plug + * controllers and resources used by the PCI Hot-Plug devices. + * + * This file walks EBDA, maps data block from physical addr, + * reconstruct linked lists about all system resource(MEM, PFM, IO) + * already assigned by POST, as well as linked lists about hot plug + * controllers (ctlr#, slot#, bus&slot features...) + */ + +/* Global lists */ +LIST_HEAD (ibmphp_ebda_pci_rsrc_head); +LIST_HEAD (ibmphp_slot_head); + +/* Local variables */ +static struct ebda_hpc_list *hpc_list_ptr; +static struct ebda_rsrc_list *rsrc_list_ptr; +static struct rio_table_hdr *rio_table_ptr = NULL; +static LIST_HEAD (ebda_hpc_head); +static LIST_HEAD (bus_info_head); +static LIST_HEAD (rio_vg_head); +static LIST_HEAD (rio_lo_head); +static LIST_HEAD (opt_vg_head); +static LIST_HEAD (opt_lo_head); +static void *io_mem; + +/* Local functions */ +static int ebda_rsrc_controller (void); +static int ebda_rsrc_rsrc (void); +static int ebda_rio_table (void); + +static struct ebda_hpc_list * __init alloc_ebda_hpc_list (void) +{ + struct ebda_hpc_list *list; + + list = kmalloc (sizeof (struct ebda_hpc_list), GFP_KERNEL); + if (!list) + return NULL; + memset (list, 0, sizeof (*list)); + return list; +} + +static struct controller *alloc_ebda_hpc (u32 slot_count, u32 bus_count) +{ + struct controller *controller; + struct ebda_hpc_slot *slots; + struct ebda_hpc_bus *buses; + + controller = kmalloc (sizeof (struct controller), GFP_KERNEL); + if (!controller) + return NULL; + memset (controller, 0, sizeof (*controller)); + + slots = kmalloc (sizeof (struct ebda_hpc_slot) * slot_count, GFP_KERNEL); + if (!slots) { + kfree (controller); + return NULL; + } + memset (slots, 0, sizeof (*slots) * slot_count); + controller->slots = slots; + + buses = kmalloc (sizeof (struct ebda_hpc_bus) * bus_count, GFP_KERNEL); + if (!buses) { + kfree (controller->slots); + kfree (controller); + return NULL; + } + memset (buses, 0, sizeof (*buses) * bus_count); + controller->buses = buses; + + return controller; +} + +static void free_ebda_hpc (struct controller *controller) +{ + kfree (controller->slots); + controller->slots = NULL; + kfree (controller->buses); + controller->buses = NULL; + controller->ctrl_dev = NULL; + kfree (controller); +} + +static struct ebda_rsrc_list * __init alloc_ebda_rsrc_list (void) +{ + struct ebda_rsrc_list *list; + + list = kmalloc (sizeof (struct ebda_rsrc_list), GFP_KERNEL); + if (!list) + return NULL; + memset (list, 0, sizeof (*list)); + return list; +} + +static struct ebda_pci_rsrc *alloc_ebda_pci_rsrc (void) +{ + struct ebda_pci_rsrc *resource; + + resource = kmalloc (sizeof (struct ebda_pci_rsrc), GFP_KERNEL); + if (!resource) + return NULL; + memset (resource, 0, sizeof (*resource)); + return resource; +} + +static void __init print_bus_info (void) +{ + struct bus_info *ptr; + struct list_head *ptr1; + + list_for_each (ptr1, &bus_info_head) { + ptr = list_entry (ptr1, struct bus_info, bus_info_list); + debug ("%s - slot_min = %x\n", __FUNCTION__, ptr->slot_min); + debug ("%s - slot_max = %x\n", __FUNCTION__, ptr->slot_max); + debug ("%s - slot_count = %x\n", __FUNCTION__, ptr->slot_count); + debug ("%s - bus# = %x\n", __FUNCTION__, ptr->busno); + debug ("%s - current_speed = %x\n", __FUNCTION__, ptr->current_speed); + debug ("%s - controller_id = %x\n", __FUNCTION__, ptr->controller_id); + + debug ("%s - slots_at_33_conv = %x\n", __FUNCTION__, ptr->slots_at_33_conv); + debug ("%s - slots_at_66_conv = %x\n", __FUNCTION__, ptr->slots_at_66_conv); + debug ("%s - slots_at_66_pcix = %x\n", __FUNCTION__, ptr->slots_at_66_pcix); + debug ("%s - slots_at_100_pcix = %x\n", __FUNCTION__, ptr->slots_at_100_pcix); + debug ("%s - slots_at_133_pcix = %x\n", __FUNCTION__, ptr->slots_at_133_pcix); + + } +} + +static void print_lo_info (void) +{ + struct rio_detail *ptr; + struct list_head *ptr1; + debug ("print_lo_info ---- \n"); + list_for_each (ptr1, &rio_lo_head) { + ptr = list_entry (ptr1, struct rio_detail, rio_detail_list); + debug ("%s - rio_node_id = %x\n", __FUNCTION__, ptr->rio_node_id); + debug ("%s - rio_type = %x\n", __FUNCTION__, ptr->rio_type); + debug ("%s - owner_id = %x\n", __FUNCTION__, ptr->owner_id); + debug ("%s - first_slot_num = %x\n", __FUNCTION__, ptr->first_slot_num); + debug ("%s - wpindex = %x\n", __FUNCTION__, ptr->wpindex); + debug ("%s - chassis_num = %x\n", __FUNCTION__, ptr->chassis_num); + + } +} + +static void print_vg_info (void) +{ + struct rio_detail *ptr; + struct list_head *ptr1; + debug ("%s --- \n", __FUNCTION__); + list_for_each (ptr1, &rio_vg_head) { + ptr = list_entry (ptr1, struct rio_detail, rio_detail_list); + debug ("%s - rio_node_id = %x\n", __FUNCTION__, ptr->rio_node_id); + debug ("%s - rio_type = %x\n", __FUNCTION__, ptr->rio_type); + debug ("%s - owner_id = %x\n", __FUNCTION__, ptr->owner_id); + debug ("%s - first_slot_num = %x\n", __FUNCTION__, ptr->first_slot_num); + debug ("%s - wpindex = %x\n", __FUNCTION__, ptr->wpindex); + debug ("%s - chassis_num = %x\n", __FUNCTION__, ptr->chassis_num); + + } +} + +static void __init print_ebda_pci_rsrc (void) +{ + struct ebda_pci_rsrc *ptr; + struct list_head *ptr1; + + list_for_each (ptr1, &ibmphp_ebda_pci_rsrc_head) { + ptr = list_entry (ptr1, struct ebda_pci_rsrc, ebda_pci_rsrc_list); + debug ("%s - rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n", + __FUNCTION__, ptr->rsrc_type ,ptr->bus_num, ptr->dev_fun,ptr->start_addr, ptr->end_addr); + } +} + +static void __init print_ibm_slot (void) +{ + struct slot *ptr; + struct list_head *ptr1; + + list_for_each (ptr1, &ibmphp_slot_head) { + ptr = list_entry (ptr1, struct slot, ibm_slot_list); + debug ("%s - slot_number: %x \n", __FUNCTION__, ptr->number); + } +} + +static void __init print_opt_vg (void) +{ + struct opt_rio *ptr; + struct list_head *ptr1; + debug ("%s --- \n", __FUNCTION__); + list_for_each (ptr1, &opt_vg_head) { + ptr = list_entry (ptr1, struct opt_rio, opt_rio_list); + debug ("%s - rio_type %x \n", __FUNCTION__, ptr->rio_type); + debug ("%s - chassis_num: %x \n", __FUNCTION__, ptr->chassis_num); + debug ("%s - first_slot_num: %x \n", __FUNCTION__, ptr->first_slot_num); + debug ("%s - middle_num: %x \n", __FUNCTION__, ptr->middle_num); + } +} + +static void __init print_ebda_hpc (void) +{ + struct controller *hpc_ptr; + struct list_head *ptr1; + u16 index; + + list_for_each (ptr1, &ebda_hpc_head) { + + hpc_ptr = list_entry (ptr1, struct controller, ebda_hpc_list); + + for (index = 0; index < hpc_ptr->slot_count; index++) { + debug ("%s - physical slot#: %x\n", __FUNCTION__, hpc_ptr->slots[index].slot_num); + debug ("%s - pci bus# of the slot: %x\n", __FUNCTION__, hpc_ptr->slots[index].slot_bus_num); + debug ("%s - index into ctlr addr: %x\n", __FUNCTION__, hpc_ptr->slots[index].ctl_index); + debug ("%s - cap of the slot: %x\n", __FUNCTION__, hpc_ptr->slots[index].slot_cap); + } + + for (index = 0; index < hpc_ptr->bus_count; index++) { + debug ("%s - bus# of each bus controlled by this ctlr: %x\n", __FUNCTION__, hpc_ptr->buses[index].bus_num); + } + + debug ("%s - type of hpc: %x\n", __FUNCTION__, hpc_ptr->ctlr_type); + switch (hpc_ptr->ctlr_type) { + case 1: + debug ("%s - bus: %x\n", __FUNCTION__, hpc_ptr->u.pci_ctlr.bus); + debug ("%s - dev_fun: %x\n", __FUNCTION__, hpc_ptr->u.pci_ctlr.dev_fun); + debug ("%s - irq: %x\n", __FUNCTION__, hpc_ptr->irq); + break; + + case 0: + debug ("%s - io_start: %x\n", __FUNCTION__, hpc_ptr->u.isa_ctlr.io_start); + debug ("%s - io_end: %x\n", __FUNCTION__, hpc_ptr->u.isa_ctlr.io_end); + debug ("%s - irq: %x\n", __FUNCTION__, hpc_ptr->irq); + break; + + case 2: + case 4: + debug ("%s - wpegbbar: %lx\n", __FUNCTION__, hpc_ptr->u.wpeg_ctlr.wpegbbar); + debug ("%s - i2c_addr: %x\n", __FUNCTION__, hpc_ptr->u.wpeg_ctlr.i2c_addr); + debug ("%s - irq: %x\n", __FUNCTION__, hpc_ptr->irq); + break; + } + } +} + +int __init ibmphp_access_ebda (void) +{ + u8 format, num_ctlrs, rio_complete, hs_complete; + u16 ebda_seg, num_entries, next_offset, offset, blk_id, sub_addr, rc, re, rc_id, re_id, base; + + + rio_complete = 0; + hs_complete = 0; + + io_mem = ioremap ((0x40 << 4) + 0x0e, 2); + if (!io_mem ) + return -ENOMEM; + ebda_seg = readw (io_mem); + iounmap (io_mem); + debug ("returned ebda segment: %x\n", ebda_seg); + + io_mem = ioremap (ebda_seg<<4, 65000); + if (!io_mem ) + return -ENOMEM; + next_offset = 0x180; + + for (;;) { + offset = next_offset; + next_offset = readw (io_mem + offset); /* offset of next blk */ + + offset += 2; + if (next_offset == 0) /* 0 indicate it's last blk */ + break; + blk_id = readw (io_mem + offset); /* this blk id */ + + offset += 2; + /* check if it is hot swap block or rio block */ + if (blk_id != 0x4853 && blk_id != 0x4752) + continue; + /* found hs table */ + if (blk_id == 0x4853) { + debug ("now enter hot swap block---\n"); + debug ("hot blk id: %x\n", blk_id); + format = readb (io_mem + offset); + + offset += 1; + if (format != 4) { + iounmap (io_mem); + return -ENODEV; + } + debug ("hot blk format: %x\n", format); + /* hot swap sub blk */ + base = offset; + + sub_addr = base; + re = readw (io_mem + sub_addr); /* next sub blk */ + + sub_addr += 2; + rc_id = readw (io_mem + sub_addr); /* sub blk id */ + + sub_addr += 2; + if (rc_id != 0x5243) { + iounmap (io_mem); + return -ENODEV; + } + /* rc sub blk signature */ + num_ctlrs = readb (io_mem + sub_addr); + + sub_addr += 1; + hpc_list_ptr = alloc_ebda_hpc_list (); + if (!hpc_list_ptr) { + iounmap (io_mem); + return -ENOMEM; + } + hpc_list_ptr->format = format; + hpc_list_ptr->num_ctlrs = num_ctlrs; + hpc_list_ptr->phys_addr = sub_addr; /* offset of RSRC_CONTROLLER blk */ + debug ("info about hpc descriptor---\n"); + debug ("hot blk format: %x\n", format); + debug ("num of controller: %x\n", num_ctlrs); + debug ("offset of hpc data structure enteries: %x\n ", sub_addr); + + sub_addr = base + re; /* re sub blk */ + rc = readw (io_mem + sub_addr); /* next sub blk */ + + sub_addr += 2; + re_id = readw (io_mem + sub_addr); /* sub blk id */ + + sub_addr += 2; + if (re_id != 0x5245) { + iounmap (io_mem); + return -ENODEV; + } + + /* signature of re */ + num_entries = readw (io_mem + sub_addr); + + sub_addr += 2; /* offset of RSRC_ENTRIES blk */ + rsrc_list_ptr = alloc_ebda_rsrc_list (); + if (!rsrc_list_ptr ) { + iounmap (io_mem); + return -ENOMEM; + } + rsrc_list_ptr->format = format; + rsrc_list_ptr->num_entries = num_entries; + rsrc_list_ptr->phys_addr = sub_addr; + + debug ("info about rsrc descriptor---\n"); + debug ("format: %x\n", format); + debug ("num of rsrc: %x\n", num_entries); + debug ("offset of rsrc data structure enteries: %x\n ", sub_addr); + + hs_complete = 1; + } + /* found rio table */ + else if (blk_id == 0x4752) { + debug ("now enter io table ---\n"); + debug ("rio blk id: %x\n", blk_id); + + rio_table_ptr = kmalloc (sizeof (struct rio_table_hdr), GFP_KERNEL); + if (!rio_table_ptr) + return -ENOMEM; + memset (rio_table_ptr, 0, sizeof (struct rio_table_hdr) ); + rio_table_ptr->ver_num = readb (io_mem + offset); + rio_table_ptr->scal_count = readb (io_mem + offset + 1); + rio_table_ptr->riodev_count = readb (io_mem + offset + 2); + rio_table_ptr->offset = offset +3 ; + + debug ("info about rio table hdr ---\n"); + debug ("ver_num: %x\nscal_count: %x\nriodev_count: %x\noffset of rio table: %x\n ", rio_table_ptr->ver_num, rio_table_ptr->scal_count, rio_table_ptr->riodev_count, rio_table_ptr->offset); + + rio_complete = 1; + } + } + + if (!hs_complete && !rio_complete) { + iounmap (io_mem); + return -ENODEV; + } + + if (rio_table_ptr) { + if (rio_complete == 1 && rio_table_ptr->ver_num == 3) { + rc = ebda_rio_table (); + if (rc) { + iounmap (io_mem); + return rc; + } + } + } + rc = ebda_rsrc_controller (); + if (rc) { + iounmap (io_mem); + return rc; + } + + rc = ebda_rsrc_rsrc (); + if (rc) { + iounmap (io_mem); + return rc; + } + + iounmap (io_mem); + return 0; +} + +/* + * map info of scalability details and rio details from physical address + */ +static int __init ebda_rio_table (void) +{ + u16 offset; + u8 i; + struct rio_detail *rio_detail_ptr; + + offset = rio_table_ptr->offset; + offset += 12 * rio_table_ptr->scal_count; + + // we do concern about rio details + for (i = 0; i < rio_table_ptr->riodev_count; i++) { + rio_detail_ptr = kmalloc (sizeof (struct rio_detail), GFP_KERNEL); + if (!rio_detail_ptr) + return -ENOMEM; + memset (rio_detail_ptr, 0, sizeof (struct rio_detail)); + rio_detail_ptr->rio_node_id = readb (io_mem + offset); + rio_detail_ptr->bbar = readl (io_mem + offset + 1); + rio_detail_ptr->rio_type = readb (io_mem + offset + 5); + rio_detail_ptr->owner_id = readb (io_mem + offset + 6); + rio_detail_ptr->port0_node_connect = readb (io_mem + offset + 7); + rio_detail_ptr->port0_port_connect = readb (io_mem + offset + 8); + rio_detail_ptr->port1_node_connect = readb (io_mem + offset + 9); + rio_detail_ptr->port1_port_connect = readb (io_mem + offset + 10); + rio_detail_ptr->first_slot_num = readb (io_mem + offset + 11); + rio_detail_ptr->status = readb (io_mem + offset + 12); + rio_detail_ptr->wpindex = readb (io_mem + offset + 13); + rio_detail_ptr->chassis_num = readb (io_mem + offset + 14); +// debug ("rio_node_id: %x\nbbar: %x\nrio_type: %x\nowner_id: %x\nport0_node: %x\nport0_port: %x\nport1_node: %x\nport1_port: %x\nfirst_slot_num: %x\nstatus: %x\n", rio_detail_ptr->rio_node_id, rio_detail_ptr->bbar, rio_detail_ptr->rio_type, rio_detail_ptr->owner_id, rio_detail_ptr->port0_node_connect, rio_detail_ptr->port0_port_connect, rio_detail_ptr->port1_node_connect, rio_detail_ptr->port1_port_connect, rio_detail_ptr->first_slot_num, rio_detail_ptr->status); + //create linked list of chassis + if (rio_detail_ptr->rio_type == 4 || rio_detail_ptr->rio_type == 5) + list_add (&rio_detail_ptr->rio_detail_list, &rio_vg_head); + //create linked list of expansion box + else if (rio_detail_ptr->rio_type == 6 || rio_detail_ptr->rio_type == 7) + list_add (&rio_detail_ptr->rio_detail_list, &rio_lo_head); + else + // not in my concern + kfree (rio_detail_ptr); + offset += 15; + } + print_lo_info (); + print_vg_info (); + return 0; +} + +/* + * reorganizing linked list of chassis + */ +static struct opt_rio *search_opt_vg (u8 chassis_num) +{ + struct opt_rio *ptr; + struct list_head *ptr1; + list_for_each (ptr1, &opt_vg_head) { + ptr = list_entry (ptr1, struct opt_rio, opt_rio_list); + if (ptr->chassis_num == chassis_num) + return ptr; + } + return NULL; +} + +static int __init combine_wpg_for_chassis (void) +{ + struct opt_rio *opt_rio_ptr = NULL; + struct rio_detail *rio_detail_ptr = NULL; + struct list_head *list_head_ptr = NULL; + + list_for_each (list_head_ptr, &rio_vg_head) { + rio_detail_ptr = list_entry (list_head_ptr, struct rio_detail, rio_detail_list); + opt_rio_ptr = search_opt_vg (rio_detail_ptr->chassis_num); + if (!opt_rio_ptr) { + opt_rio_ptr = (struct opt_rio *) kmalloc (sizeof (struct opt_rio), GFP_KERNEL); + if (!opt_rio_ptr) + return -ENOMEM; + memset (opt_rio_ptr, 0, sizeof (struct opt_rio)); + opt_rio_ptr->rio_type = rio_detail_ptr->rio_type; + opt_rio_ptr->chassis_num = rio_detail_ptr->chassis_num; + opt_rio_ptr->first_slot_num = rio_detail_ptr->first_slot_num; + opt_rio_ptr->middle_num = rio_detail_ptr->first_slot_num; + list_add (&opt_rio_ptr->opt_rio_list, &opt_vg_head); + } else { + opt_rio_ptr->first_slot_num = min (opt_rio_ptr->first_slot_num, rio_detail_ptr->first_slot_num); + opt_rio_ptr->middle_num = max (opt_rio_ptr->middle_num, rio_detail_ptr->first_slot_num); + } + } + print_opt_vg (); + return 0; +} + +/* + * reorgnizing linked list of expansion box + */ +static struct opt_rio_lo *search_opt_lo (u8 chassis_num) +{ + struct opt_rio_lo *ptr; + struct list_head *ptr1; + list_for_each (ptr1, &opt_lo_head) { + ptr = list_entry (ptr1, struct opt_rio_lo, opt_rio_lo_list); + if (ptr->chassis_num == chassis_num) + return ptr; + } + return NULL; +} + +static int combine_wpg_for_expansion (void) +{ + struct opt_rio_lo *opt_rio_lo_ptr = NULL; + struct rio_detail *rio_detail_ptr = NULL; + struct list_head *list_head_ptr = NULL; + + list_for_each (list_head_ptr, &rio_lo_head) { + rio_detail_ptr = list_entry (list_head_ptr, struct rio_detail, rio_detail_list); + opt_rio_lo_ptr = search_opt_lo (rio_detail_ptr->chassis_num); + if (!opt_rio_lo_ptr) { + opt_rio_lo_ptr = (struct opt_rio_lo *) kmalloc (sizeof (struct opt_rio_lo), GFP_KERNEL); + if (!opt_rio_lo_ptr) + return -ENOMEM; + memset (opt_rio_lo_ptr, 0, sizeof (struct opt_rio_lo)); + opt_rio_lo_ptr->rio_type = rio_detail_ptr->rio_type; + opt_rio_lo_ptr->chassis_num = rio_detail_ptr->chassis_num; + opt_rio_lo_ptr->first_slot_num = rio_detail_ptr->first_slot_num; + opt_rio_lo_ptr->middle_num = rio_detail_ptr->first_slot_num; + opt_rio_lo_ptr->pack_count = 1; + + list_add (&opt_rio_lo_ptr->opt_rio_lo_list, &opt_lo_head); + } else { + opt_rio_lo_ptr->first_slot_num = min (opt_rio_lo_ptr->first_slot_num, rio_detail_ptr->first_slot_num); + opt_rio_lo_ptr->middle_num = max (opt_rio_lo_ptr->middle_num, rio_detail_ptr->first_slot_num); + opt_rio_lo_ptr->pack_count = 2; + } + } + return 0; +} + + +/* Since we don't know the max slot number per each chassis, hence go + * through the list of all chassis to find out the range + * Arguments: slot_num, 1st slot number of the chassis we think we are on, + * var (0 = chassis, 1 = expansion box) + */ +static int first_slot_num (u8 slot_num, u8 first_slot, u8 var) +{ + struct opt_rio *opt_vg_ptr = NULL; + struct opt_rio_lo *opt_lo_ptr = NULL; + struct list_head *ptr = NULL; + int rc = 0; + + if (!var) { + list_for_each (ptr, &opt_vg_head) { + opt_vg_ptr = list_entry (ptr, struct opt_rio, opt_rio_list); + if ((first_slot < opt_vg_ptr->first_slot_num) && (slot_num >= opt_vg_ptr->first_slot_num)) { + rc = -ENODEV; + break; + } + } + } else { + list_for_each (ptr, &opt_lo_head) { + opt_lo_ptr = list_entry (ptr, struct opt_rio_lo, opt_rio_lo_list); + if ((first_slot < opt_lo_ptr->first_slot_num) && (slot_num >= opt_lo_ptr->first_slot_num)) { + rc = -ENODEV; + break; + } + } + } + return rc; +} + +static struct opt_rio_lo * find_rxe_num (u8 slot_num) +{ + struct opt_rio_lo *opt_lo_ptr; + struct list_head *ptr; + + list_for_each (ptr, &opt_lo_head) { + opt_lo_ptr = list_entry (ptr, struct opt_rio_lo, opt_rio_lo_list); + //check to see if this slot_num belongs to expansion box + if ((slot_num >= opt_lo_ptr->first_slot_num) && (!first_slot_num (slot_num, opt_lo_ptr->first_slot_num, 1))) + return opt_lo_ptr; + } + return NULL; +} + +static struct opt_rio * find_chassis_num (u8 slot_num) +{ + struct opt_rio *opt_vg_ptr; + struct list_head *ptr; + + list_for_each (ptr, &opt_vg_head) { + opt_vg_ptr = list_entry (ptr, struct opt_rio, opt_rio_list); + //check to see if this slot_num belongs to chassis + if ((slot_num >= opt_vg_ptr->first_slot_num) && (!first_slot_num (slot_num, opt_vg_ptr->first_slot_num, 0))) + return opt_vg_ptr; + } + return NULL; +} + +/* This routine will find out how many slots are in the chassis, so that + * the slot numbers for rxe100 would start from 1, and not from 7, or 6 etc + */ +static u8 calculate_first_slot (u8 slot_num) +{ + u8 first_slot = 1; + struct list_head * list; + struct slot * slot_cur; + + list_for_each (list, &ibmphp_slot_head) { + slot_cur = list_entry (list, struct slot, ibm_slot_list); + if (slot_cur->ctrl) { + if ((slot_cur->ctrl->ctlr_type != 4) && (slot_cur->ctrl->ending_slot_num > first_slot) && (slot_num > slot_cur->ctrl->ending_slot_num)) + first_slot = slot_cur->ctrl->ending_slot_num; + } + } + return first_slot + 1; + +} +static char *create_file_name (struct slot * slot_cur) +{ + struct opt_rio *opt_vg_ptr = NULL; + struct opt_rio_lo *opt_lo_ptr = NULL; + static char str[30]; + int which = 0; /* rxe = 1, chassis = 0 */ + u8 number = 1; /* either chassis or rxe # */ + u8 first_slot = 1; + u8 slot_num; + u8 flag = 0; + + if (!slot_cur) { + err ("Structure passed is empty \n"); + return NULL; + } + + slot_num = slot_cur->number; + + memset (str, 0, sizeof(str)); + + if (rio_table_ptr) { + if (rio_table_ptr->ver_num == 3) { + opt_vg_ptr = find_chassis_num (slot_num); + opt_lo_ptr = find_rxe_num (slot_num); + } + } + if (opt_vg_ptr) { + if (opt_lo_ptr) { + if ((slot_num - opt_vg_ptr->first_slot_num) > (slot_num - opt_lo_ptr->first_slot_num)) { + number = opt_lo_ptr->chassis_num; + first_slot = opt_lo_ptr->first_slot_num; + which = 1; /* it is RXE */ + } else { + first_slot = opt_vg_ptr->first_slot_num; + number = opt_vg_ptr->chassis_num; + which = 0; + } + } else { + first_slot = opt_vg_ptr->first_slot_num; + number = opt_vg_ptr->chassis_num; + which = 0; + } + ++flag; + } else if (opt_lo_ptr) { + number = opt_lo_ptr->chassis_num; + first_slot = opt_lo_ptr->first_slot_num; + which = 1; + ++flag; + } else if (rio_table_ptr) { + if (rio_table_ptr->ver_num == 3) { + /* if both NULL and we DO have correct RIO table in BIOS */ + return NULL; + } + } + if (!flag) { + if (slot_cur->ctrl->ctlr_type == 4) { + first_slot = calculate_first_slot (slot_num); + which = 1; + } else { + which = 0; + } + } + + sprintf(str, "%s%dslot%d", + which == 0 ? "chassis" : "rxe", + number, slot_num - first_slot + 1); + return str; +} + +static struct pci_driver ibmphp_driver; + +/* + * map info (ctlr-id, slot count, slot#.. bus count, bus#, ctlr type...) of + * each hpc from physical address to a list of hot plug controllers based on + * hpc descriptors. + */ +static int __init ebda_rsrc_controller (void) +{ + u16 addr, addr_slot, addr_bus; + u8 ctlr_id, temp, bus_index; + u16 ctlr, slot, bus; + u16 slot_num, bus_num, index; + struct hotplug_slot *hp_slot_ptr; + struct controller *hpc_ptr; + struct ebda_hpc_bus *bus_ptr; + struct ebda_hpc_slot *slot_ptr; + struct bus_info *bus_info_ptr1, *bus_info_ptr2; + int rc; + struct slot *tmp_slot; + struct list_head *list; + + addr = hpc_list_ptr->phys_addr; + for (ctlr = 0; ctlr < hpc_list_ptr->num_ctlrs; ctlr++) { + bus_index = 1; + ctlr_id = readb (io_mem + addr); + addr += 1; + slot_num = readb (io_mem + addr); + + addr += 1; + addr_slot = addr; /* offset of slot structure */ + addr += (slot_num * 4); + + bus_num = readb (io_mem + addr); + + addr += 1; + addr_bus = addr; /* offset of bus */ + addr += (bus_num * 9); /* offset of ctlr_type */ + temp = readb (io_mem + addr); + + addr += 1; + /* init hpc structure */ + hpc_ptr = alloc_ebda_hpc (slot_num, bus_num); + if (!hpc_ptr ) { + rc = -ENOMEM; + goto error_no_hpc; + } + hpc_ptr->ctlr_id = ctlr_id; + hpc_ptr->ctlr_relative_id = ctlr; + hpc_ptr->slot_count = slot_num; + hpc_ptr->bus_count = bus_num; + debug ("now enter ctlr data struture ---\n"); + debug ("ctlr id: %x\n", ctlr_id); + debug ("ctlr_relative_id: %x\n", hpc_ptr->ctlr_relative_id); + debug ("count of slots controlled by this ctlr: %x\n", slot_num); + debug ("count of buses controlled by this ctlr: %x\n", bus_num); + + /* init slot structure, fetch slot, bus, cap... */ + slot_ptr = hpc_ptr->slots; + for (slot = 0; slot < slot_num; slot++) { + slot_ptr->slot_num = readb (io_mem + addr_slot); + slot_ptr->slot_bus_num = readb (io_mem + addr_slot + slot_num); + slot_ptr->ctl_index = readb (io_mem + addr_slot + 2*slot_num); + slot_ptr->slot_cap = readb (io_mem + addr_slot + 3*slot_num); + + // create bus_info lined list --- if only one slot per bus: slot_min = slot_max + + bus_info_ptr2 = ibmphp_find_same_bus_num (slot_ptr->slot_bus_num); + if (!bus_info_ptr2) { + bus_info_ptr1 = (struct bus_info *) kmalloc (sizeof (struct bus_info), GFP_KERNEL); + if (!bus_info_ptr1) { + rc = -ENOMEM; + goto error_no_hp_slot; + } + memset (bus_info_ptr1, 0, sizeof (struct bus_info)); + bus_info_ptr1->slot_min = slot_ptr->slot_num; + bus_info_ptr1->slot_max = slot_ptr->slot_num; + bus_info_ptr1->slot_count += 1; + bus_info_ptr1->busno = slot_ptr->slot_bus_num; + bus_info_ptr1->index = bus_index++; + bus_info_ptr1->current_speed = 0xff; + bus_info_ptr1->current_bus_mode = 0xff; + + bus_info_ptr1->controller_id = hpc_ptr->ctlr_id; + + list_add_tail (&bus_info_ptr1->bus_info_list, &bus_info_head); + + } else { + bus_info_ptr2->slot_min = min (bus_info_ptr2->slot_min, slot_ptr->slot_num); + bus_info_ptr2->slot_max = max (bus_info_ptr2->slot_max, slot_ptr->slot_num); + bus_info_ptr2->slot_count += 1; + + } + + // end of creating the bus_info linked list + + slot_ptr++; + addr_slot += 1; + } + + /* init bus structure */ + bus_ptr = hpc_ptr->buses; + for (bus = 0; bus < bus_num; bus++) { + bus_ptr->bus_num = readb (io_mem + addr_bus + bus); + bus_ptr->slots_at_33_conv = readb (io_mem + addr_bus + bus_num + 8 * bus); + bus_ptr->slots_at_66_conv = readb (io_mem + addr_bus + bus_num + 8 * bus + 1); + + bus_ptr->slots_at_66_pcix = readb (io_mem + addr_bus + bus_num + 8 * bus + 2); + + bus_ptr->slots_at_100_pcix = readb (io_mem + addr_bus + bus_num + 8 * bus + 3); + + bus_ptr->slots_at_133_pcix = readb (io_mem + addr_bus + bus_num + 8 * bus + 4); + + bus_info_ptr2 = ibmphp_find_same_bus_num (bus_ptr->bus_num); + if (bus_info_ptr2) { + bus_info_ptr2->slots_at_33_conv = bus_ptr->slots_at_33_conv; + bus_info_ptr2->slots_at_66_conv = bus_ptr->slots_at_66_conv; + bus_info_ptr2->slots_at_66_pcix = bus_ptr->slots_at_66_pcix; + bus_info_ptr2->slots_at_100_pcix = bus_ptr->slots_at_100_pcix; + bus_info_ptr2->slots_at_133_pcix = bus_ptr->slots_at_133_pcix; + } + bus_ptr++; + } + + hpc_ptr->ctlr_type = temp; + + switch (hpc_ptr->ctlr_type) { + case 1: + hpc_ptr->u.pci_ctlr.bus = readb (io_mem + addr); + hpc_ptr->u.pci_ctlr.dev_fun = readb (io_mem + addr + 1); + hpc_ptr->irq = readb (io_mem + addr + 2); + addr += 3; + debug ("ctrl bus = %x, ctlr devfun = %x, irq = %x\n", + hpc_ptr->u.pci_ctlr.bus, + hpc_ptr->u.pci_ctlr.dev_fun, hpc_ptr->irq); + break; + + case 0: + hpc_ptr->u.isa_ctlr.io_start = readw (io_mem + addr); + hpc_ptr->u.isa_ctlr.io_end = readw (io_mem + addr + 2); + if (!request_region (hpc_ptr->u.isa_ctlr.io_start, + (hpc_ptr->u.isa_ctlr.io_end - hpc_ptr->u.isa_ctlr.io_start + 1), + "ibmphp")) { + rc = -ENODEV; + goto error_no_hp_slot; + } + hpc_ptr->irq = readb (io_mem + addr + 4); + addr += 5; + break; + + case 2: + case 4: + hpc_ptr->u.wpeg_ctlr.wpegbbar = readl (io_mem + addr); + hpc_ptr->u.wpeg_ctlr.i2c_addr = readb (io_mem + addr + 4); + hpc_ptr->irq = readb (io_mem + addr + 5); + addr += 6; + break; + default: + rc = -ENODEV; + goto error_no_hp_slot; + } + + //reorganize chassis' linked list + combine_wpg_for_chassis (); + combine_wpg_for_expansion (); + hpc_ptr->revision = 0xff; + hpc_ptr->options = 0xff; + hpc_ptr->starting_slot_num = hpc_ptr->slots[0].slot_num; + hpc_ptr->ending_slot_num = hpc_ptr->slots[slot_num-1].slot_num; + + // register slots with hpc core as well as create linked list of ibm slot + for (index = 0; index < hpc_ptr->slot_count; index++) { + + hp_slot_ptr = (struct hotplug_slot *) kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL); + if (!hp_slot_ptr) { + rc = -ENOMEM; + goto error_no_hp_slot; + } + memset (hp_slot_ptr, 0, sizeof (struct hotplug_slot)); + + hp_slot_ptr->info = (struct hotplug_slot_info *) kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); + if (!hp_slot_ptr->info) { + rc = -ENOMEM; + goto error_no_hp_info; + } + memset (hp_slot_ptr->info, 0, sizeof (struct hotplug_slot_info)); + + hp_slot_ptr->name = (char *) kmalloc (30, GFP_KERNEL); + if (!hp_slot_ptr->name) { + rc = -ENOMEM; + goto error_no_hp_name; + } + + tmp_slot = kmalloc (sizeof (struct slot), GFP_KERNEL); + if (!tmp_slot) { + rc = -ENOMEM; + goto error_no_slot; + } + memset (tmp_slot, 0, sizeof (*tmp_slot)); + + tmp_slot->flag = TRUE; + + tmp_slot->capabilities = hpc_ptr->slots[index].slot_cap; + if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_133_MAX) == EBDA_SLOT_133_MAX) + tmp_slot->supported_speed = 3; + else if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_100_MAX) == EBDA_SLOT_100_MAX) + tmp_slot->supported_speed = 2; + else if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_66_MAX) == EBDA_SLOT_66_MAX) + tmp_slot->supported_speed = 1; + + if ((hpc_ptr->slots[index].slot_cap & EBDA_SLOT_PCIX_CAP) == EBDA_SLOT_PCIX_CAP) + tmp_slot->supported_bus_mode = 1; + else + tmp_slot->supported_bus_mode = 0; + + + tmp_slot->bus = hpc_ptr->slots[index].slot_bus_num; + + bus_info_ptr1 = ibmphp_find_same_bus_num (hpc_ptr->slots[index].slot_bus_num); + if (!bus_info_ptr1) { + rc = -ENODEV; + goto error; + } + tmp_slot->bus_on = bus_info_ptr1; + bus_info_ptr1 = NULL; + tmp_slot->ctrl = hpc_ptr; + + tmp_slot->ctlr_index = hpc_ptr->slots[index].ctl_index; + tmp_slot->number = hpc_ptr->slots[index].slot_num; + tmp_slot->hotplug_slot = hp_slot_ptr; + + hp_slot_ptr->private = tmp_slot; + + rc = ibmphp_hpc_fillhpslotinfo (hp_slot_ptr); + if (rc) + goto error; + + rc = ibmphp_init_devno ((struct slot **) &hp_slot_ptr->private); + if (rc) + goto error; + hp_slot_ptr->ops = &ibmphp_hotplug_slot_ops; + + // end of registering ibm slot with hotplug core + + list_add (& ((struct slot *)(hp_slot_ptr->private))->ibm_slot_list, &ibmphp_slot_head); + } + + print_bus_info (); + list_add (&hpc_ptr->ebda_hpc_list, &ebda_hpc_head ); + + } /* each hpc */ + + list_for_each (list, &ibmphp_slot_head) { + tmp_slot = list_entry (list, struct slot, ibm_slot_list); + + snprintf (tmp_slot->hotplug_slot->name, 30, "%s", create_file_name (tmp_slot)); + pci_hp_register (tmp_slot->hotplug_slot); + } + + print_ebda_hpc (); + print_ibm_slot (); + return 0; + +error: + kfree (hp_slot_ptr->private); +error_no_slot: + kfree (hp_slot_ptr->name); +error_no_hp_name: + kfree (hp_slot_ptr->info); +error_no_hp_info: + kfree (hp_slot_ptr); +error_no_hp_slot: + free_ebda_hpc (hpc_ptr); +error_no_hpc: + iounmap (io_mem); + return rc; +} + +/* + * map info (bus, devfun, start addr, end addr..) of i/o, memory, + * pfm from the physical addr to a list of resource. + */ +static int __init ebda_rsrc_rsrc (void) +{ + u16 addr; + short rsrc; + u8 type, rsrc_type; + struct ebda_pci_rsrc *rsrc_ptr; + + addr = rsrc_list_ptr->phys_addr; + debug ("now entering rsrc land\n"); + debug ("offset of rsrc: %x\n", rsrc_list_ptr->phys_addr); + + for (rsrc = 0; rsrc < rsrc_list_ptr->num_entries; rsrc++) { + type = readb (io_mem + addr); + + addr += 1; + rsrc_type = type & EBDA_RSRC_TYPE_MASK; + + if (rsrc_type == EBDA_IO_RSRC_TYPE) { + rsrc_ptr = alloc_ebda_pci_rsrc (); + if (!rsrc_ptr) { + iounmap (io_mem); + return -ENOMEM; + } + rsrc_ptr->rsrc_type = type; + + rsrc_ptr->bus_num = readb (io_mem + addr); + rsrc_ptr->dev_fun = readb (io_mem + addr + 1); + rsrc_ptr->start_addr = readw (io_mem + addr + 2); + rsrc_ptr->end_addr = readw (io_mem + addr + 4); + addr += 6; + + debug ("rsrc from io type ----\n"); + debug ("rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n", + rsrc_ptr->rsrc_type, rsrc_ptr->bus_num, rsrc_ptr->dev_fun, rsrc_ptr->start_addr, rsrc_ptr->end_addr); + + list_add (&rsrc_ptr->ebda_pci_rsrc_list, &ibmphp_ebda_pci_rsrc_head); + } + + if (rsrc_type == EBDA_MEM_RSRC_TYPE || rsrc_type == EBDA_PFM_RSRC_TYPE) { + rsrc_ptr = alloc_ebda_pci_rsrc (); + if (!rsrc_ptr ) { + iounmap (io_mem); + return -ENOMEM; + } + rsrc_ptr->rsrc_type = type; + + rsrc_ptr->bus_num = readb (io_mem + addr); + rsrc_ptr->dev_fun = readb (io_mem + addr + 1); + rsrc_ptr->start_addr = readl (io_mem + addr + 2); + rsrc_ptr->end_addr = readl (io_mem + addr + 6); + addr += 10; + + debug ("rsrc from mem or pfm ---\n"); + debug ("rsrc type: %x bus#: %x dev_func: %x start addr: %x end addr: %x\n", + rsrc_ptr->rsrc_type, rsrc_ptr->bus_num, rsrc_ptr->dev_fun, rsrc_ptr->start_addr, rsrc_ptr->end_addr); + + list_add (&rsrc_ptr->ebda_pci_rsrc_list, &ibmphp_ebda_pci_rsrc_head); + } + } + kfree (rsrc_list_ptr); + rsrc_list_ptr = NULL; + print_ebda_pci_rsrc (); + return 0; +} + +u16 ibmphp_get_total_controllers (void) +{ + return hpc_list_ptr->num_ctlrs; +} + +struct slot *ibmphp_get_slot_from_physical_num (u8 physical_num) +{ + struct slot *slot; + struct list_head *list; + + list_for_each (list, &ibmphp_slot_head) { + slot = list_entry (list, struct slot, ibm_slot_list); + if (slot->number == physical_num) + return slot; + } + return NULL; +} + +/* To find: + * - the smallest slot number + * - the largest slot number + * - the total number of the slots based on each bus + * (if only one slot per bus slot_min = slot_max ) + */ +struct bus_info *ibmphp_find_same_bus_num (u32 num) +{ + struct bus_info *ptr; + struct list_head *ptr1; + + list_for_each (ptr1, &bus_info_head) { + ptr = list_entry (ptr1, struct bus_info, bus_info_list); + if (ptr->busno == num) + return ptr; + } + return NULL; +} + +/* Finding relative bus number, in order to map corresponding + * bus register + */ +int ibmphp_get_bus_index (u8 num) +{ + struct bus_info *ptr; + struct list_head *ptr1; + + list_for_each (ptr1, &bus_info_head) { + ptr = list_entry (ptr1, struct bus_info, bus_info_list); + if (ptr->busno == num) + return ptr->index; + } + return -ENODEV; +} + +void ibmphp_free_bus_info_queue (void) +{ + struct bus_info *bus_info; + struct list_head *list; + struct list_head *next; + + list_for_each_safe (list, next, &bus_info_head ) { + bus_info = list_entry (list, struct bus_info, bus_info_list); + kfree (bus_info); + } +} + +void ibmphp_free_ebda_hpc_queue (void) +{ + struct controller *controller = NULL; + struct list_head *list; + struct list_head *next; + int pci_flag = 0; + + list_for_each_safe (list, next, &ebda_hpc_head) { + controller = list_entry (list, struct controller, ebda_hpc_list); + if (controller->ctlr_type == 0) + release_region (controller->u.isa_ctlr.io_start, (controller->u.isa_ctlr.io_end - controller->u.isa_ctlr.io_start + 1)); + else if ((controller->ctlr_type == 1) && (!pci_flag)) { + ++pci_flag; + pci_unregister_driver (&ibmphp_driver); + } + free_ebda_hpc (controller); + } +} + +void ibmphp_free_ebda_pci_rsrc_queue (void) +{ + struct ebda_pci_rsrc *resource; + struct list_head *list; + struct list_head *next; + + list_for_each_safe (list, next, &ibmphp_ebda_pci_rsrc_head) { + resource = list_entry (list, struct ebda_pci_rsrc, ebda_pci_rsrc_list); + kfree (resource); + resource = NULL; + } +} + +static struct pci_device_id id_table[] __devinitdata = { + { + .vendor = PCI_VENDOR_ID_IBM, + .device = HPC_DEVICE_ID, + .subvendor = PCI_VENDOR_ID_IBM, + .subdevice = HPC_SUBSYSTEM_ID, + .class = ((PCI_CLASS_SYSTEM_PCI_HOTPLUG << 8) | 0x00), + }, {} +}; + +MODULE_DEVICE_TABLE(pci, id_table); + +static int ibmphp_probe (struct pci_dev *, const struct pci_device_id *); +static struct pci_driver ibmphp_driver = { + .name = "ibmphp", + .id_table = id_table, + .probe = ibmphp_probe, +}; + +int ibmphp_register_pci (void) +{ + struct controller *ctrl; + struct list_head *tmp; + int rc = 0; + + list_for_each (tmp, &ebda_hpc_head) { + ctrl = list_entry (tmp, struct controller, ebda_hpc_list); + if (ctrl->ctlr_type == 1) { + rc = pci_module_init (&ibmphp_driver); + break; + } + } + return rc; +} +static int ibmphp_probe (struct pci_dev * dev, const struct pci_device_id *ids) +{ + struct controller *ctrl; + struct list_head *tmp; + + debug ("inside ibmphp_probe \n"); + + list_for_each (tmp, &ebda_hpc_head) { + ctrl = list_entry (tmp, struct controller, ebda_hpc_list); + if (ctrl->ctlr_type == 1) { + if ((dev->devfn == ctrl->u.pci_ctlr.dev_fun) && (dev->bus->number == ctrl->u.pci_ctlr.bus)) { + ctrl->ctrl_dev = dev; + debug ("found device!!! \n"); + debug ("dev->device = %x, dev->subsystem_device = %x\n", dev->device, dev->subsystem_device); + return 0; + } + } + } + return -ENODEV; +} + diff -Nru a/drivers/pci/hotplug/ibmphp_hpc.c b/drivers/pci/hotplug/ibmphp_hpc.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pci/hotplug/ibmphp_hpc.c Mon Jun 9 23:16:08 2003 @@ -0,0 +1,1228 @@ +/* + * IBM Hot Plug Controller Driver + * + * Written By: Jyoti Shah, IBM Corporation + * + * Copyright (c) 2001-2002 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Send feedback to <gregkh@us.ibm.com> + * <jshah@us.ibm.com> + * + */ + +#include <linux/wait.h> +#include <linux/time.h> +#include <linux/module.h> +#include <linux/pci.h> +#include <linux/smp_lock.h> +#include <linux/init.h> +#include "ibmphp.h" + +static int to_debug = FALSE; +#define debug_polling(fmt, arg...) do { if (to_debug) debug (fmt, arg); } while (0) + +//---------------------------------------------------------------------------- +// timeout values +//---------------------------------------------------------------------------- +#define CMD_COMPLETE_TOUT_SEC 60 // give HPC 60 sec to finish cmd +#define HPC_CTLR_WORKING_TOUT 60 // give HPC 60 sec to finish cmd +#define HPC_GETACCESS_TIMEOUT 60 // seconds +#define POLL_INTERVAL_SEC 2 // poll HPC every 2 seconds +#define POLL_LATCH_CNT 5 // poll latch 5 times, then poll slots + +//---------------------------------------------------------------------------- +// Winnipeg Architected Register Offsets +//---------------------------------------------------------------------------- +#define WPG_I2CMBUFL_OFFSET 0x08 // I2C Message Buffer Low +#define WPG_I2CMOSUP_OFFSET 0x10 // I2C Master Operation Setup Reg +#define WPG_I2CMCNTL_OFFSET 0x20 // I2C Master Control Register +#define WPG_I2CPARM_OFFSET 0x40 // I2C Parameter Register +#define WPG_I2CSTAT_OFFSET 0x70 // I2C Status Register + +//---------------------------------------------------------------------------- +// Winnipeg Store Type commands (Add this commands to the register offset) +//---------------------------------------------------------------------------- +#define WPG_I2C_AND 0x1000 // I2C AND operation +#define WPG_I2C_OR 0x2000 // I2C OR operation + +//---------------------------------------------------------------------------- +// Command set for I2C Master Operation Setup Regisetr +//---------------------------------------------------------------------------- +#define WPG_READATADDR_MASK 0x00010000 // read,bytes,I2C shifted,index +#define WPG_WRITEATADDR_MASK 0x40010000 // write,bytes,I2C shifted,index +#define WPG_READDIRECT_MASK 0x10010000 +#define WPG_WRITEDIRECT_MASK 0x60010000 + + +//---------------------------------------------------------------------------- +// bit masks for I2C Master Control Register +//---------------------------------------------------------------------------- +#define WPG_I2CMCNTL_STARTOP_MASK 0x00000002 // Start the Operation + +//---------------------------------------------------------------------------- +// +//---------------------------------------------------------------------------- +#define WPG_I2C_IOREMAP_SIZE 0x2044 // size of linear address interval + +//---------------------------------------------------------------------------- +// command index +//---------------------------------------------------------------------------- +#define WPG_1ST_SLOT_INDEX 0x01 // index - 1st slot for ctlr +#define WPG_CTLR_INDEX 0x0F // index - ctlr +#define WPG_1ST_EXTSLOT_INDEX 0x10 // index - 1st ext slot for ctlr +#define WPG_1ST_BUS_INDEX 0x1F // index - 1st bus for ctlr + +//---------------------------------------------------------------------------- +// macro utilities +//---------------------------------------------------------------------------- +// if bits 20,22,25,26,27,29,30 are OFF return TRUE +#define HPC_I2CSTATUS_CHECK(s) ((u8)((s & 0x00000A76) ? FALSE : TRUE)) + +//---------------------------------------------------------------------------- +// global variables +//---------------------------------------------------------------------------- +static int ibmphp_shutdown; +static int tid_poll; +static struct semaphore sem_hpcaccess; // lock access to HPC +static struct semaphore semOperations; // lock all operations and + // access to data structures +static struct semaphore sem_exit; // make sure polling thread goes away +//---------------------------------------------------------------------------- +// local function prototypes +//---------------------------------------------------------------------------- +static u8 i2c_ctrl_read (struct controller *, void *, u8); +static u8 i2c_ctrl_write (struct controller *, void *, u8, u8); +static u8 hpc_writecmdtoindex (u8, u8); +static u8 hpc_readcmdtoindex (u8, u8); +static void get_hpc_access (void); +static void free_hpc_access (void); +static void poll_hpc (void); +static int update_slot (struct slot *, u8); +static int process_changeinstatus (struct slot *, struct slot *); +static int process_changeinlatch (u8, u8, struct controller *); +static int hpc_poll_thread (void *); +static int hpc_wait_ctlr_notworking (int, struct controller *, void *, u8 *); +//---------------------------------------------------------------------------- + + +/*---------------------------------------------------------------------- +* Name: ibmphp_hpc_initvars +* +* Action: initialize semaphores and variables +*---------------------------------------------------------------------*/ +void __init ibmphp_hpc_initvars (void) +{ + debug ("%s - Entry\n", __FUNCTION__); + + init_MUTEX (&sem_hpcaccess); + init_MUTEX (&semOperations); + init_MUTEX_LOCKED (&sem_exit); + to_debug = FALSE; + ibmphp_shutdown = FALSE; + tid_poll = 0; + + debug ("%s - Exit\n", __FUNCTION__); +} + +/*---------------------------------------------------------------------- +* Name: i2c_ctrl_read +* +* Action: read from HPC over I2C +* +*---------------------------------------------------------------------*/ +static u8 i2c_ctrl_read (struct controller *ctlr_ptr, void *WPGBbar, u8 index) +{ + u8 status; + int i; + void *wpg_addr; // base addr + offset + ulong wpg_data, // data to/from WPG LOHI format + ultemp, data; // actual data HILO format + + + debug_polling ("%s - Entry WPGBbar[%lx] index[%x] \n", __FUNCTION__, (ulong) WPGBbar, index); + + //-------------------------------------------------------------------- + // READ - step 1 + // read at address, byte length, I2C address (shifted), index + // or read direct, byte length, index + if (ctlr_ptr->ctlr_type == 0x02) { + data = WPG_READATADDR_MASK; + // fill in I2C address + ultemp = (ulong) ctlr_ptr->u.wpeg_ctlr.i2c_addr; + ultemp = ultemp >> 1; + data |= (ultemp << 8); + + // fill in index + data |= (ulong) index; + } else if (ctlr_ptr->ctlr_type == 0x04) { + data = WPG_READDIRECT_MASK; + + // fill in index + ultemp = (ulong) index; + ultemp = ultemp << 8; + data |= ultemp; + } else { + err ("this controller type is not supported \n"); + return HPC_ERROR; + } + + wpg_data = swab32 (data); // swap data before writing + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMOSUP_OFFSET; + writel (wpg_data, wpg_addr); + + //-------------------------------------------------------------------- + // READ - step 2 : clear the message buffer + data = 0x00000000; + wpg_data = swab32 (data); + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMBUFL_OFFSET; + writel (wpg_data, wpg_addr); + + //-------------------------------------------------------------------- + // READ - step 3 : issue start operation, I2C master control bit 30:ON + // 2020 : [20] OR operation at [20] offset 0x20 + data = WPG_I2CMCNTL_STARTOP_MASK; + wpg_data = swab32 (data); + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET + (ulong) WPG_I2C_OR; + writel (wpg_data, wpg_addr); + + //-------------------------------------------------------------------- + // READ - step 4 : wait until start operation bit clears + i = CMD_COMPLETE_TOUT_SEC; + while (i) { + long_delay (1 * HZ / 100); + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET; + wpg_data = readl (wpg_addr); + data = swab32 (wpg_data); + if (!(data & WPG_I2CMCNTL_STARTOP_MASK)) + break; + i--; + } + if (i == 0) { + debug ("%s - Error : WPG timeout\n", __FUNCTION__); + return HPC_ERROR; + } + //-------------------------------------------------------------------- + // READ - step 5 : read I2C status register + i = CMD_COMPLETE_TOUT_SEC; + while (i) { + long_delay (1 * HZ / 100); + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CSTAT_OFFSET; + wpg_data = readl (wpg_addr); + data = swab32 (wpg_data); + if (HPC_I2CSTATUS_CHECK (data)) + break; + i--; + } + if (i == 0) { + debug ("ctrl_read - Exit Error:I2C timeout\n"); + return HPC_ERROR; + } + + //-------------------------------------------------------------------- + // READ - step 6 : get DATA + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMBUFL_OFFSET; + wpg_data = readl (wpg_addr); + data = swab32 (wpg_data); + + status = (u8) data; + + debug_polling ("%s - Exit index[%x] status[%x]\n", __FUNCTION__, index, status); + + return (status); +} + +/*---------------------------------------------------------------------- +* Name: i2c_ctrl_write +* +* Action: write to HPC over I2C +* +* Return 0 or error codes +*---------------------------------------------------------------------*/ +static u8 i2c_ctrl_write (struct controller *ctlr_ptr, void *WPGBbar, u8 index, u8 cmd) +{ + u8 rc; + void *wpg_addr; // base addr + offset + ulong wpg_data, // data to/from WPG LOHI format + ultemp, data; // actual data HILO format + int i; + + + debug_polling ("%s - Entry WPGBbar[%lx] index[%x] cmd[%x]\n", __FUNCTION__, (ulong) WPGBbar, index, cmd); + + rc = 0; + //-------------------------------------------------------------------- + // WRITE - step 1 + // write at address, byte length, I2C address (shifted), index + // or write direct, byte length, index + data = 0x00000000; + + if (ctlr_ptr->ctlr_type == 0x02) { + data = WPG_WRITEATADDR_MASK; + // fill in I2C address + ultemp = (ulong) ctlr_ptr->u.wpeg_ctlr.i2c_addr; + ultemp = ultemp >> 1; + data |= (ultemp << 8); + + // fill in index + data |= (ulong) index; + } else if (ctlr_ptr->ctlr_type == 0x04) { + data = WPG_WRITEDIRECT_MASK; + + // fill in index + ultemp = (ulong) index; + ultemp = ultemp << 8; + data |= ultemp; + } else { + err ("this controller type is not supported \n"); + return HPC_ERROR; + } + + wpg_data = swab32 (data); // swap data before writing + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMOSUP_OFFSET; + writel (wpg_data, wpg_addr); + + //-------------------------------------------------------------------- + // WRITE - step 2 : clear the message buffer + data = 0x00000000 | (ulong) cmd; + wpg_data = swab32 (data); + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMBUFL_OFFSET; + writel (wpg_data, wpg_addr); + + //-------------------------------------------------------------------- + // WRITE - step 3 : issue start operation,I2C master control bit 30:ON + // 2020 : [20] OR operation at [20] offset 0x20 + data = WPG_I2CMCNTL_STARTOP_MASK; + wpg_data = swab32 (data); + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET + (ulong) WPG_I2C_OR; + writel (wpg_data, wpg_addr); + + //-------------------------------------------------------------------- + // WRITE - step 4 : wait until start operation bit clears + i = CMD_COMPLETE_TOUT_SEC; + while (i) { + long_delay (1 * HZ / 100); + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CMCNTL_OFFSET; + wpg_data = readl (wpg_addr); + data = swab32 (wpg_data); + if (!(data & WPG_I2CMCNTL_STARTOP_MASK)) + break; + i--; + } + if (i == 0) { + debug ("%s - Exit Error:WPG timeout\n", __FUNCTION__); + rc = HPC_ERROR; + } + + //-------------------------------------------------------------------- + // WRITE - step 5 : read I2C status register + i = CMD_COMPLETE_TOUT_SEC; + while (i) { + long_delay (1 * HZ / 100); + (ulong) wpg_addr = (ulong) WPGBbar + (ulong) WPG_I2CSTAT_OFFSET; + wpg_data = readl (wpg_addr); + data = swab32 (wpg_data); + if (HPC_I2CSTATUS_CHECK (data)) + break; + i--; + } + if (i == 0) { + debug ("ctrl_read - Error : I2C timeout\n"); + rc = HPC_ERROR; + } + + debug_polling ("%s Exit rc[%x]\n", __FUNCTION__, rc); + return (rc); +} + +//------------------------------------------------------------ +// Read from ISA type HPC +//------------------------------------------------------------ +static u8 isa_ctrl_read (struct controller *ctlr_ptr, u8 offset) +{ + u16 start_address; + u16 end_address; + u8 data; + + start_address = ctlr_ptr->u.isa_ctlr.io_start; + end_address = ctlr_ptr->u.isa_ctlr.io_end; + data = inb (start_address + offset); + return data; +} + +//-------------------------------------------------------------- +// Write to ISA type HPC +//-------------------------------------------------------------- +static void isa_ctrl_write (struct controller *ctlr_ptr, u8 offset, u8 data) +{ + u16 start_address; + u16 port_address; + + start_address = ctlr_ptr->u.isa_ctlr.io_start; + port_address = start_address + (u16) offset; + outb (data, port_address); +} + +static u8 pci_ctrl_read (struct controller *ctrl, u8 offset) +{ + u8 data = 0x00; + debug ("inside pci_ctrl_read\n"); + if (ctrl->ctrl_dev) + pci_read_config_byte (ctrl->ctrl_dev, HPC_PCI_OFFSET + offset, &data); + return data; +} + +static u8 pci_ctrl_write (struct controller *ctrl, u8 offset, u8 data) +{ + u8 rc = -ENODEV; + debug ("inside pci_ctrl_write\n"); + if (ctrl->ctrl_dev) { + pci_write_config_byte (ctrl->ctrl_dev, HPC_PCI_OFFSET + offset, data); + rc = 0; + } + return rc; +} + +static u8 ctrl_read (struct controller *ctlr, void *base, u8 offset) +{ + u8 rc; + switch (ctlr->ctlr_type) { + case 0: + rc = isa_ctrl_read (ctlr, offset); + break; + case 1: + rc = pci_ctrl_read (ctlr, offset); + break; + case 2: + case 4: + rc = i2c_ctrl_read (ctlr, base, offset); + break; + default: + return -ENODEV; + } + return rc; +} + +static u8 ctrl_write (struct controller *ctlr, void *base, u8 offset, u8 data) +{ + u8 rc = 0; + switch (ctlr->ctlr_type) { + case 0: + isa_ctrl_write(ctlr, offset, data); + break; + case 1: + rc = pci_ctrl_write (ctlr, offset, data); + break; + case 2: + case 4: + rc = i2c_ctrl_write(ctlr, base, offset, data); + break; + default: + return -ENODEV; + } + return rc; +} +/*---------------------------------------------------------------------- +* Name: hpc_writecmdtoindex() +* +* Action: convert a write command to proper index within a controller +* +* Return index, HPC_ERROR +*---------------------------------------------------------------------*/ +static u8 hpc_writecmdtoindex (u8 cmd, u8 index) +{ + u8 rc; + + switch (cmd) { + case HPC_CTLR_ENABLEIRQ: // 0x00.N.15 + case HPC_CTLR_CLEARIRQ: // 0x06.N.15 + case HPC_CTLR_RESET: // 0x07.N.15 + case HPC_CTLR_IRQSTEER: // 0x08.N.15 + case HPC_CTLR_DISABLEIRQ: // 0x01.N.15 + case HPC_ALLSLOT_ON: // 0x11.N.15 + case HPC_ALLSLOT_OFF: // 0x12.N.15 + rc = 0x0F; + break; + + case HPC_SLOT_OFF: // 0x02.Y.0-14 + case HPC_SLOT_ON: // 0x03.Y.0-14 + case HPC_SLOT_ATTNOFF: // 0x04.N.0-14 + case HPC_SLOT_ATTNON: // 0x05.N.0-14 + case HPC_SLOT_BLINKLED: // 0x13.N.0-14 + rc = index; + break; + + case HPC_BUS_33CONVMODE: + case HPC_BUS_66CONVMODE: + case HPC_BUS_66PCIXMODE: + case HPC_BUS_100PCIXMODE: + case HPC_BUS_133PCIXMODE: + rc = index + WPG_1ST_BUS_INDEX - 1; + break; + + default: + err ("hpc_writecmdtoindex - Error invalid cmd[%x]\n", cmd); + rc = HPC_ERROR; + } + + return rc; +} + +/*---------------------------------------------------------------------- +* Name: hpc_readcmdtoindex() +* +* Action: convert a read command to proper index within a controller +* +* Return index, HPC_ERROR +*---------------------------------------------------------------------*/ +static u8 hpc_readcmdtoindex (u8 cmd, u8 index) +{ + u8 rc; + + switch (cmd) { + case READ_CTLRSTATUS: + rc = 0x0F; + break; + case READ_SLOTSTATUS: + case READ_ALLSTAT: + rc = index; + break; + case READ_EXTSLOTSTATUS: + rc = index + WPG_1ST_EXTSLOT_INDEX; + break; + case READ_BUSSTATUS: + rc = index + WPG_1ST_BUS_INDEX - 1; + break; + case READ_SLOTLATCHLOWREG: + rc = 0x28; + break; + case READ_REVLEVEL: + rc = 0x25; + break; + case READ_HPCOPTIONS: + rc = 0x27; + break; + default: + rc = HPC_ERROR; + } + return rc; +} + +/*---------------------------------------------------------------------- +* Name: HPCreadslot() +* +* Action: issue a READ command to HPC +* +* Input: pslot - can not be NULL for READ_ALLSTAT +* pstatus - can be NULL for READ_ALLSTAT +* +* Return 0 or error codes +*---------------------------------------------------------------------*/ +int ibmphp_hpc_readslot (struct slot * pslot, u8 cmd, u8 * pstatus) +{ + void *wpg_bbar = NULL; + struct controller *ctlr_ptr; + struct list_head *pslotlist; + u8 index, status; + int rc = 0; + int busindex; + + debug_polling ("%s - Entry pslot[%lx] cmd[%x] pstatus[%lx]\n", __FUNCTION__, (ulong) pslot, cmd, (ulong) pstatus); + + if ((pslot == NULL) + || ((pstatus == NULL) && (cmd != READ_ALLSTAT) && (cmd != READ_BUSSTATUS))) { + rc = -EINVAL; + err ("%s - Error invalid pointer, rc[%d]\n", __FUNCTION__, rc); + return rc; + } + + if (cmd == READ_BUSSTATUS) { + busindex = ibmphp_get_bus_index (pslot->bus); + if (busindex < 0) { + rc = -EINVAL; + err ("%s - Exit Error:invalid bus, rc[%d]\n", __FUNCTION__, rc); + return rc; + } else + index = (u8) busindex; + } else + index = pslot->ctlr_index; + + index = hpc_readcmdtoindex (cmd, index); + + if (index == HPC_ERROR) { + rc = -EINVAL; + err ("%s - Exit Error:invalid index, rc[%d]\n", __FUNCTION__, rc); + return rc; + } + + ctlr_ptr = pslot->ctrl; + + get_hpc_access (); + + //-------------------------------------------------------------------- + // map physical address to logical address + //-------------------------------------------------------------------- + if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4)) + wpg_bbar = ioremap (ctlr_ptr->u.wpeg_ctlr.wpegbbar, WPG_I2C_IOREMAP_SIZE); + + //-------------------------------------------------------------------- + // check controller status before reading + //-------------------------------------------------------------------- + rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, &status); + if (!rc) { + switch (cmd) { + case READ_ALLSTAT: + // update the slot structure + pslot->ctrl->status = status; + pslot->status = ctrl_read (ctlr_ptr, wpg_bbar, index); + rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, + &status); + if (!rc) + pslot->ext_status = ctrl_read (ctlr_ptr, wpg_bbar, index + WPG_1ST_EXTSLOT_INDEX); + + break; + + case READ_SLOTSTATUS: + // DO NOT update the slot structure + *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); + break; + + case READ_EXTSLOTSTATUS: + // DO NOT update the slot structure + *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); + break; + + case READ_CTLRSTATUS: + // DO NOT update the slot structure + *pstatus = status; + break; + + case READ_BUSSTATUS: + pslot->busstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); + break; + case READ_REVLEVEL: + *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); + break; + case READ_HPCOPTIONS: + *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); + break; + case READ_SLOTLATCHLOWREG: + // DO NOT update the slot structure + *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, index); + break; + + // Not used + case READ_ALLSLOT: + list_for_each (pslotlist, &ibmphp_slot_head) { + pslot = list_entry (pslotlist, struct slot, ibm_slot_list); + index = pslot->ctlr_index; + rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, + wpg_bbar, &status); + if (!rc) { + pslot->status = ctrl_read (ctlr_ptr, wpg_bbar, index); + rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, + ctlr_ptr, wpg_bbar, &status); + if (!rc) + pslot->ext_status = + ctrl_read (ctlr_ptr, wpg_bbar, + index + WPG_1ST_EXTSLOT_INDEX); + } else { + err ("%s - Error ctrl_read failed\n", __FUNCTION__); + rc = -EINVAL; + break; + } + } + break; + default: + rc = -EINVAL; + break; + } + } + //-------------------------------------------------------------------- + // cleanup + //-------------------------------------------------------------------- + + // remove physical to logical address mapping + if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4)) + iounmap (wpg_bbar); + + free_hpc_access (); + + debug_polling ("%s - Exit rc[%d]\n", __FUNCTION__, rc); + return rc; +} + +/*---------------------------------------------------------------------- +* Name: ibmphp_hpc_writeslot() +* +* Action: issue a WRITE command to HPC +*---------------------------------------------------------------------*/ +int ibmphp_hpc_writeslot (struct slot * pslot, u8 cmd) +{ + void *wpg_bbar = NULL; + struct controller *ctlr_ptr; + u8 index, status; + int busindex; + u8 done; + int rc = 0; + int timeout; + + debug_polling ("%s - Entry pslot[%lx] cmd[%x]\n", __FUNCTION__, (ulong) pslot, cmd); + if (pslot == NULL) { + rc = -EINVAL; + err ("%s - Error Exit rc[%d]\n", __FUNCTION__, rc); + return rc; + } + + if ((cmd == HPC_BUS_33CONVMODE) || (cmd == HPC_BUS_66CONVMODE) || + (cmd == HPC_BUS_66PCIXMODE) || (cmd == HPC_BUS_100PCIXMODE) || + (cmd == HPC_BUS_133PCIXMODE)) { + busindex = ibmphp_get_bus_index (pslot->bus); + if (busindex < 0) { + rc = -EINVAL; + err ("%s - Exit Error:invalid bus, rc[%d]\n", __FUNCTION__, rc); + return rc; + } else + index = (u8) busindex; + } else + index = pslot->ctlr_index; + + index = hpc_writecmdtoindex (cmd, index); + + if (index == HPC_ERROR) { + rc = -EINVAL; + err ("%s - Error Exit rc[%d]\n", __FUNCTION__, rc); + return rc; + } + + ctlr_ptr = pslot->ctrl; + + get_hpc_access (); + + //-------------------------------------------------------------------- + // map physical address to logical address + //-------------------------------------------------------------------- + if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4)) { + wpg_bbar = ioremap (ctlr_ptr->u.wpeg_ctlr.wpegbbar, WPG_I2C_IOREMAP_SIZE); + + debug ("%s - ctlr id[%x] physical[%lx] logical[%lx] i2c[%x]\n", __FUNCTION__, + ctlr_ptr->ctlr_id, (ulong) (ctlr_ptr->u.wpeg_ctlr.wpegbbar), (ulong) wpg_bbar, + ctlr_ptr->u.wpeg_ctlr.i2c_addr); + } + //-------------------------------------------------------------------- + // check controller status before writing + //-------------------------------------------------------------------- + rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, &status); + if (!rc) { + + ctrl_write (ctlr_ptr, wpg_bbar, index, cmd); + + //-------------------------------------------------------------------- + // check controller is still not working on the command + //-------------------------------------------------------------------- + timeout = CMD_COMPLETE_TOUT_SEC; + done = FALSE; + while (!done) { + rc = hpc_wait_ctlr_notworking (HPC_CTLR_WORKING_TOUT, ctlr_ptr, wpg_bbar, + &status); + if (!rc) { + if (NEEDTOCHECK_CMDSTATUS (cmd)) { + if (CTLR_FINISHED (status) == HPC_CTLR_FINISHED_YES) + done = TRUE; + } else + done = TRUE; + } + if (!done) { + long_delay (1 * HZ); + if (timeout < 1) { + done = TRUE; + err ("%s - Error command complete timeout\n", __FUNCTION__); + rc = -EFAULT; + } else + timeout--; + } + } + ctlr_ptr->status = status; + } + // cleanup + + // remove physical to logical address mapping + if ((ctlr_ptr->ctlr_type == 2) || (ctlr_ptr->ctlr_type == 4)) + iounmap (wpg_bbar); + free_hpc_access (); + + debug_polling ("%s - Exit rc[%d]\n", __FUNCTION__, rc); + return rc; +} + +/*---------------------------------------------------------------------- +* Name: get_hpc_access() +* +* Action: make sure only one process can access HPC at one time +*---------------------------------------------------------------------*/ +static void get_hpc_access (void) +{ + down (&sem_hpcaccess); +} + +/*---------------------------------------------------------------------- +* Name: free_hpc_access() +*---------------------------------------------------------------------*/ +void free_hpc_access (void) +{ + up (&sem_hpcaccess); +} + +/*---------------------------------------------------------------------- +* Name: ibmphp_lock_operations() +* +* Action: make sure only one process can change the data structure +*---------------------------------------------------------------------*/ +void ibmphp_lock_operations (void) +{ + down (&semOperations); + to_debug = TRUE; +} + +/*---------------------------------------------------------------------- +* Name: ibmphp_unlock_operations() +*---------------------------------------------------------------------*/ +void ibmphp_unlock_operations (void) +{ + debug ("%s - Entry\n", __FUNCTION__); + up (&semOperations); + to_debug = FALSE; + debug ("%s - Exit\n", __FUNCTION__); +} + +/*---------------------------------------------------------------------- +* Name: poll_hpc() +*---------------------------------------------------------------------*/ +#define POLL_LATCH_REGISTER 0 +#define POLL_SLOTS 1 +#define POLL_SLEEP 2 +static void poll_hpc (void) +{ + struct slot myslot; + struct slot *pslot = NULL; + struct list_head *pslotlist; + int rc; + int poll_state = POLL_LATCH_REGISTER; + u8 oldlatchlow = 0x00; + u8 curlatchlow = 0x00; + int poll_count = 0; + u8 ctrl_count = 0x00; + + debug ("%s - Entry\n", __FUNCTION__); + + while (!ibmphp_shutdown) { + if (ibmphp_shutdown) + break; + + /* try to get the lock to do some kind of harware access */ + down (&semOperations); + + switch (poll_state) { + case POLL_LATCH_REGISTER: + oldlatchlow = curlatchlow; + ctrl_count = 0x00; + list_for_each (pslotlist, &ibmphp_slot_head) { + if (ctrl_count >= ibmphp_get_total_controllers()) + break; + pslot = list_entry (pslotlist, struct slot, ibm_slot_list); + if (pslot->ctrl->ctlr_relative_id == ctrl_count) { + ctrl_count++; + if (READ_SLOT_LATCH (pslot->ctrl)) { + rc = ibmphp_hpc_readslot (pslot, + READ_SLOTLATCHLOWREG, + &curlatchlow); + if (oldlatchlow != curlatchlow) + process_changeinlatch (oldlatchlow, + curlatchlow, + pslot->ctrl); + } + } + } + ++poll_count; + poll_state = POLL_SLEEP; + break; + case POLL_SLOTS: + list_for_each (pslotlist, &ibmphp_slot_head) { + pslot = list_entry (pslotlist, struct slot, ibm_slot_list); + // make a copy of the old status + memcpy ((void *) &myslot, (void *) pslot, + sizeof (struct slot)); + rc = ibmphp_hpc_readslot (pslot, READ_ALLSTAT, NULL); + if ((myslot.status != pslot->status) + || (myslot.ext_status != pslot->ext_status)) + process_changeinstatus (pslot, &myslot); + } + ctrl_count = 0x00; + list_for_each (pslotlist, &ibmphp_slot_head) { + if (ctrl_count >= ibmphp_get_total_controllers()) + break; + pslot = list_entry (pslotlist, struct slot, ibm_slot_list); + if (pslot->ctrl->ctlr_relative_id == ctrl_count) { + ctrl_count++; + if (READ_SLOT_LATCH (pslot->ctrl)) + rc = ibmphp_hpc_readslot (pslot, + READ_SLOTLATCHLOWREG, + &curlatchlow); + } + } + ++poll_count; + poll_state = POLL_SLEEP; + break; + case POLL_SLEEP: + /* don't sleep with a lock on the hardware */ + up (&semOperations); + long_delay (POLL_INTERVAL_SEC * HZ); + + if (ibmphp_shutdown) + break; + + down (&semOperations); + + if (poll_count >= POLL_LATCH_CNT) { + poll_count = 0; + poll_state = POLL_SLOTS; + } else + poll_state = POLL_LATCH_REGISTER; + break; + } + /* give up the harware semaphore */ + up (&semOperations); + /* sleep for a short time just for good measure */ + set_current_state (TASK_INTERRUPTIBLE); + schedule_timeout (HZ/10); + } + up (&sem_exit); + debug ("%s - Exit\n", __FUNCTION__); +} + + +/* ---------------------------------------------------------------------- + * Name: ibmphp_hpc_fillhpslotinfo(hotplug_slot * phpslot) + * + * Action: fill out the hotplug_slot info + * + * Input: pointer to hotplug_slot + * + * Return + * Value: 0 or error codes + *-----------------------------------------------------------------------*/ +int ibmphp_hpc_fillhpslotinfo (struct hotplug_slot *phpslot) +{ + int rc = 0; + struct slot *pslot; + + if (phpslot && phpslot->private) { + pslot = (struct slot *) phpslot->private; + rc = update_slot (pslot, (u8) TRUE); + if (!rc) { + + // power - enabled:1 not:0 + phpslot->info->power_status = SLOT_POWER (pslot->status); + + // attention - off:0, on:1, blinking:2 + phpslot->info->attention_status = SLOT_ATTN (pslot->status, pslot->ext_status); + + // latch - open:1 closed:0 + phpslot->info->latch_status = SLOT_LATCH (pslot->status); + + // pci board - present:1 not:0 + if (SLOT_PRESENT (pslot->status)) + phpslot->info->adapter_status = 1; + else + phpslot->info->adapter_status = 0; +/* + if (pslot->bus_on->supported_bus_mode + && (pslot->bus_on->supported_speed == BUS_SPEED_66)) + phpslot->info->max_bus_speed_status = BUS_SPEED_66PCIX; + else + phpslot->info->max_bus_speed_status = pslot->bus_on->supported_speed; +*/ } else + rc = -EINVAL; + } else + rc = -EINVAL; + + return rc; +} + +/*---------------------------------------------------------------------- +* Name: update_slot +* +* Action: fill out slot status and extended status, controller status +* +* Input: pointer to slot struct +*---------------------------------------------------------------------*/ +static int update_slot (struct slot *pslot, u8 update) +{ + int rc = 0; + + debug ("%s - Entry pslot[%lx]\n", __FUNCTION__, (ulong) pslot); + rc = ibmphp_hpc_readslot (pslot, READ_ALLSTAT, NULL); + debug ("%s - Exit rc[%d]\n", __FUNCTION__, rc); + return rc; +} + +/*---------------------------------------------------------------------- +* Name: process_changeinstatus +* +* Action: compare old and new slot status, process the change in status +* +* Input: pointer to slot struct, old slot struct +* +* Return 0 or error codes +* Value: +* +* Side +* Effects: None. +* +* Notes: +*---------------------------------------------------------------------*/ +static int process_changeinstatus (struct slot *pslot, struct slot *poldslot) +{ + u8 status; + int rc = 0; + u8 disable = FALSE; + u8 update = FALSE; + + debug ("process_changeinstatus - Entry pslot[%lx], poldslot[%lx]\n", (ulong) pslot, + (ulong) poldslot); + + // bit 0 - HPC_SLOT_POWER + if ((pslot->status & 0x01) != (poldslot->status & 0x01)) + update = TRUE; + + // bit 1 - HPC_SLOT_CONNECT + // ignore + + // bit 2 - HPC_SLOT_ATTN + if ((pslot->status & 0x04) != (poldslot->status & 0x04)) + update = TRUE; + + // bit 3 - HPC_SLOT_PRSNT2 + // bit 4 - HPC_SLOT_PRSNT1 + if (((pslot->status & 0x08) != (poldslot->status & 0x08)) + || ((pslot->status & 0x10) != (poldslot->status & 0x10))) + update = TRUE; + + // bit 5 - HPC_SLOT_PWRGD + if ((pslot->status & 0x20) != (poldslot->status & 0x20)) + // OFF -> ON: ignore, ON -> OFF: disable slot + if ((poldslot->status & 0x20) && (SLOT_CONNECT (poldslot->status) == HPC_SLOT_CONNECTED) && (SLOT_PRESENT (poldslot->status))) + disable = TRUE; + + // bit 6 - HPC_SLOT_BUS_SPEED + // ignore + + // bit 7 - HPC_SLOT_LATCH + if ((pslot->status & 0x80) != (poldslot->status & 0x80)) { + update = TRUE; + // OPEN -> CLOSE + if (pslot->status & 0x80) { + if (SLOT_PWRGD (pslot->status)) { + // power goes on and off after closing latch + // check again to make sure power is still ON + long_delay (1 * HZ); + rc = ibmphp_hpc_readslot (pslot, READ_SLOTSTATUS, &status); + if (SLOT_PWRGD (status)) + update = TRUE; + else // overwrite power in pslot to OFF + pslot->status &= ~HPC_SLOT_POWER; + } + } + // CLOSE -> OPEN + else if ((SLOT_PWRGD (poldslot->status) == HPC_SLOT_PWRGD_GOOD) + && (SLOT_CONNECT (poldslot->status) == HPC_SLOT_CONNECTED) && (SLOT_PRESENT (poldslot->status))) { + disable = TRUE; + } + // else - ignore + } + // bit 4 - HPC_SLOT_BLINK_ATTN + if ((pslot->ext_status & 0x08) != (poldslot->ext_status & 0x08)) + update = TRUE; + + if (disable) { + debug ("process_changeinstatus - disable slot\n"); + pslot->flag = FALSE; + rc = ibmphp_do_disable_slot (pslot); + } + + if (update || disable) { + ibmphp_update_slot_info (pslot); + } + + debug ("%s - Exit rc[%d] disable[%x] update[%x]\n", __FUNCTION__, rc, disable, update); + + return rc; +} + +/*---------------------------------------------------------------------- +* Name: process_changeinlatch +* +* Action: compare old and new latch reg status, process the change +* +* Input: old and current latch register status +* +* Return 0 or error codes +* Value: +*---------------------------------------------------------------------*/ +static int process_changeinlatch (u8 old, u8 new, struct controller *ctrl) +{ + struct slot myslot, *pslot; + u8 i; + u8 mask; + int rc = 0; + + debug ("%s - Entry old[%x], new[%x]\n", __FUNCTION__, old, new); + // bit 0 reserved, 0 is LSB, check bit 1-6 for 6 slots + + for (i = ctrl->starting_slot_num; i <= ctrl->ending_slot_num; i++) { + mask = 0x01 << i; + if ((mask & old) != (mask & new)) { + pslot = ibmphp_get_slot_from_physical_num (i); + if (pslot) { + memcpy ((void *) &myslot, (void *) pslot, sizeof (struct slot)); + rc = ibmphp_hpc_readslot (pslot, READ_ALLSTAT, NULL); + debug ("%s - call process_changeinstatus for slot[%d]\n", __FUNCTION__, i); + process_changeinstatus (pslot, &myslot); + } else { + rc = -EINVAL; + err ("%s - Error bad pointer for slot[%d]\n", __FUNCTION__, i); + } + } + } + debug ("%s - Exit rc[%d]\n", __FUNCTION__, rc); + return rc; +} + +/*---------------------------------------------------------------------- +* Name: hpc_poll_thread +* +* Action: polling +* +* Return 0 +* Value: +*---------------------------------------------------------------------*/ +static int hpc_poll_thread (void *data) +{ + debug ("%s - Entry\n", __FUNCTION__); + + daemonize("hpc_poll"); + allow_signal(SIGKILL); + + poll_hpc (); + + tid_poll = 0; + debug ("%s - Exit\n", __FUNCTION__); + return 0; +} + + +/*---------------------------------------------------------------------- +* Name: ibmphp_hpc_start_poll_thread +* +* Action: start polling thread +*---------------------------------------------------------------------*/ +int __init ibmphp_hpc_start_poll_thread (void) +{ + int rc = 0; + + debug ("%s - Entry\n", __FUNCTION__); + + tid_poll = kernel_thread (hpc_poll_thread, 0, 0); + if (tid_poll < 0) { + err ("%s - Error, thread not started\n", __FUNCTION__); + rc = -1; + } + + debug ("%s - Exit tid_poll[%d] rc[%d]\n", __FUNCTION__, tid_poll, rc); + return rc; +} + +/*---------------------------------------------------------------------- +* Name: ibmphp_hpc_stop_poll_thread +* +* Action: stop polling thread and cleanup +*---------------------------------------------------------------------*/ +void __exit ibmphp_hpc_stop_poll_thread (void) +{ + debug ("%s - Entry\n", __FUNCTION__); + + ibmphp_shutdown = TRUE; + debug ("before locking operations \n"); + ibmphp_lock_operations (); + debug ("after locking operations \n"); + + // wait for poll thread to exit + debug ("before sem_exit down \n"); + down (&sem_exit); + debug ("after sem_exit down \n"); + + // cleanup + debug ("before free_hpc_access \n"); + free_hpc_access (); + debug ("after free_hpc_access \n"); + ibmphp_unlock_operations (); + debug ("after unlock operations \n"); + up (&sem_exit); + debug ("after sem exit up\n"); + + debug ("%s - Exit\n", __FUNCTION__); +} + +/*---------------------------------------------------------------------- +* Name: hpc_wait_ctlr_notworking +* +* Action: wait until the controller is in a not working state +* +* Return 0, HPC_ERROR +* Value: +*---------------------------------------------------------------------*/ +static int hpc_wait_ctlr_notworking (int timeout, struct controller *ctlr_ptr, void *wpg_bbar, + u8 * pstatus) +{ + int rc = 0; + u8 done = FALSE; + + debug_polling ("hpc_wait_ctlr_notworking - Entry timeout[%d]\n", timeout); + + while (!done) { + *pstatus = ctrl_read (ctlr_ptr, wpg_bbar, WPG_CTLR_INDEX); + if (*pstatus == HPC_ERROR) { + rc = HPC_ERROR; + done = TRUE; + } + if (CTLR_WORKING (*pstatus) == HPC_CTLR_WORKING_NO) + done = TRUE; + if (!done) { + long_delay (1 * HZ); + if (timeout < 1) { + done = TRUE; + err ("HPCreadslot - Error ctlr timeout\n"); + rc = HPC_ERROR; + } else + timeout--; + } + } + debug_polling ("hpc_wait_ctlr_notworking - Exit rc[%x] status[%x]\n", rc, *pstatus); + return rc; +} diff -Nru a/drivers/pci/hotplug/ibmphp_pci.c b/drivers/pci/hotplug/ibmphp_pci.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pci/hotplug/ibmphp_pci.c Mon Jun 9 23:16:05 2003 @@ -0,0 +1,1758 @@ +/* + * IBM Hot Plug Controller Driver + * + * Written By: Irene Zubarev, IBM Corporation + * + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001,2002 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Send feedback to <gregkh@us.ibm.com> + * + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/pci.h> +#include <linux/list.h> +#include "ibmphp.h" + + +static int configure_device(struct pci_func *); +static int configure_bridge(struct pci_func **, u8); +static struct res_needed *scan_behind_bridge(struct pci_func *, u8); +static int add_new_bus (struct bus_node *, struct resource_node *, struct resource_node *, struct resource_node *, u8); +static u8 find_sec_number (u8 primary_busno, u8 slotno); + +/* + * NOTE..... If BIOS doesn't provide default routing, we assign: + * 9 for SCSI, 10 for LAN adapters, and 11 for everything else. + * If adapter is bridged, then we assign 11 to it and devices behind it. + * We also assign the same irq numbers for multi function devices. + * These are PIC mode, so shouldn't matter n.e.ways (hopefully) + */ +static void assign_alt_irq (struct pci_func * cur_func, u8 class_code) +{ + int j = 0; + for (j = 0; j < 4; j++) { + if (cur_func->irq[j] == 0xff) { + switch (class_code) { + case PCI_BASE_CLASS_STORAGE: + cur_func->irq[j] = SCSI_IRQ; + break; + case PCI_BASE_CLASS_NETWORK: + cur_func->irq[j] = LAN_IRQ; + break; + default: + cur_func->irq[j] = OTHER_IRQ; + break; + } + } + } +} + +/* + * Configures the device to be added (will allocate needed resources if it + * can), the device can be a bridge or a regular pci device, can also be + * multi-functional + * + * Input: function to be added + * + * TO DO: The error case with Multifunction device or multi function bridge, + * if there is an error, will need to go through all previous functions and + * unconfigure....or can add some code into unconfigure_card.... + */ +int ibmphp_configure_card (struct pci_func *func, u8 slotno) +{ + u16 vendor_id; + u32 class; + u8 class_code; + u8 hdr_type, device, sec_number; + u8 function; + struct pci_func *newfunc; /* for multi devices */ + struct pci_func *cur_func, *prev_func; + int rc, i, j; + int cleanup_count; + u8 flag; + u8 valid_device = 0x00; /* to see if we are able to read from card any device info at all */ + + debug ("inside configure_card, func->busno = %x \n", func->busno); + + device = func->device; + cur_func = func; + + /* We only get bus and device from IRQ routing table. So at this point, + * func->busno is correct, and func->device contains only device (at the 5 + * highest bits) + */ + + /* For every function on the card */ + for (function = 0x00; function < 0x08; function++) { + unsigned int devfn = PCI_DEVFN(device, function); + ibmphp_pci_bus->number = cur_func->busno; + + cur_func->function = function; + + debug ("inside the loop, cur_func->busno = %x, cur_func->device = %x, cur_func->funcion = %x\n", + cur_func->busno, cur_func->device, cur_func->function); + + pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id); + + debug ("vendor_id is %x\n", vendor_id); + if (vendor_id != PCI_VENDOR_ID_NOTVALID) { + /* found correct device!!! */ + debug ("found valid device, vendor_id = %x\n", vendor_id); + + ++valid_device; + + /* header: x x x x x x x x + * | |___________|=> 1=PPB bridge, 0=normal device, 2=CardBus Bridge + * |_=> 0 = single function device, 1 = multi-function device + */ + + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type); + pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_CLASS_REVISION, &class); + + class_code = class >> 24; + debug ("hrd_type = %x, class = %x, class_code %x \n", hdr_type, class, class_code); + class >>= 8; /* to take revision out, class = class.subclass.prog i/f */ + if (class == PCI_CLASS_NOT_DEFINED_VGA) { + err ("The device %x is VGA compatible and as is not supported for hot plugging. " + "Please choose another device.\n", cur_func->device); + return -ENODEV; + } else if (class == PCI_CLASS_DISPLAY_VGA) { + err ("The device %x is not supported for hot plugging. " + "Please choose another device.\n", cur_func->device); + return -ENODEV; + } + switch (hdr_type) { + case PCI_HEADER_TYPE_NORMAL: + debug ("single device case.... vendor id = %x, hdr_type = %x, class = %x\n", vendor_id, hdr_type, class); + assign_alt_irq (cur_func, class_code); + if ((rc = configure_device (cur_func)) < 0) { + /* We need to do this in case some other BARs were properly inserted */ + err ("was not able to configure devfunc %x on bus %x. \n", + cur_func->device, cur_func->busno); + cleanup_count = 6; + goto error; + } + cur_func->next = NULL; + function = 0x8; + break; + case PCI_HEADER_TYPE_MULTIDEVICE: + assign_alt_irq (cur_func, class_code); + if ((rc = configure_device (cur_func)) < 0) { + /* We need to do this in case some other BARs were properly inserted */ + err ("was not able to configure devfunc %x on bus %x...bailing out\n", + cur_func->device, cur_func->busno); + cleanup_count = 6; + goto error; + } + newfunc = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); + if (!newfunc) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (newfunc, 0, sizeof (struct pci_func)); + newfunc->busno = cur_func->busno; + newfunc->device = device; + cur_func->next = newfunc; + cur_func = newfunc; + for (j = 0; j < 4; j++) + newfunc->irq[j] = cur_func->irq[j]; + break; + case PCI_HEADER_TYPE_MULTIBRIDGE: + class >>= 8; + if (class != PCI_CLASS_BRIDGE_PCI) { + err ("This %x is not PCI-to-PCI bridge, and as is not supported for hot-plugging. " + "Please insert another card.\n", cur_func->device); + return -ENODEV; + } + assign_alt_irq (cur_func, class_code); + rc = configure_bridge (&cur_func, slotno); + if (rc == -ENODEV) { + err ("You chose to insert Single Bridge, or nested bridges, this is not supported...\n"); + err ("Bus %x, devfunc %x \n", cur_func->busno, cur_func->device); + return rc; + } + if (rc) { + /* We need to do this in case some other BARs were properly inserted */ + err ("was not able to hot-add PPB properly.\n"); + func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */ + cleanup_count = 2; + goto error; + } + + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number); + flag = FALSE; + for (i = 0; i < 32; i++) { + if (func->devices[i]) { + newfunc = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); + if (!newfunc) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (newfunc, 0, sizeof (struct pci_func)); + newfunc->busno = sec_number; + newfunc->device = (u8) i; + for (j = 0; j < 4; j++) + newfunc->irq[j] = cur_func->irq[j]; + + if (flag) { + for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next) ; + prev_func->next = newfunc; + } else + cur_func->next = newfunc; + + rc = ibmphp_configure_card (newfunc, slotno); + /* This could only happen if kmalloc failed */ + if (rc) { + /* We need to do this in case bridge itself got configured properly, but devices behind it failed */ + func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */ + cleanup_count = 2; + goto error; + } + flag = TRUE; + } + } + + newfunc = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); + if (!newfunc) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (newfunc, 0, sizeof (struct pci_func)); + newfunc->busno = cur_func->busno; + newfunc->device = device; + for (j = 0; j < 4; j++) + newfunc->irq[j] = cur_func->irq[j]; + for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next) ; + prev_func->next = newfunc; + cur_func = newfunc; + break; + case PCI_HEADER_TYPE_BRIDGE: + class >>= 8; + debug ("class now is %x\n", class); + if (class != PCI_CLASS_BRIDGE_PCI) { + err ("This %x is not PCI-to-PCI bridge, and as is not supported for hot-plugging. " + "Please insert another card.\n", cur_func->device); + return -ENODEV; + } + + assign_alt_irq (cur_func, class_code); + + debug ("cur_func->busno b4 configure_bridge is %x\n", cur_func->busno); + rc = configure_bridge (&cur_func, slotno); + if (rc == -ENODEV) { + err ("You chose to insert Single Bridge, or nested bridges, this is not supported...\n"); + err ("Bus %x, devfunc %x \n", cur_func->busno, cur_func->device); + return rc; + } + if (rc) { + /* We need to do this in case some other BARs were properly inserted */ + func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */ + err ("was not able to hot-add PPB properly.\n"); + cleanup_count = 2; + goto error; + } + debug ("cur_func->busno = %x, device = %x, function = %x\n", + cur_func->busno, device, function); + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number); + debug ("after configuring bridge..., sec_number = %x\n", sec_number); + flag = FALSE; + for (i = 0; i < 32; i++) { + if (func->devices[i]) { + debug ("inside for loop, device is %x\n", i); + newfunc = (struct pci_func *) kmalloc (sizeof (struct pci_func), GFP_KERNEL); + if (!newfunc) { + err (" out of system memory \n"); + return -ENOMEM; + } + memset (newfunc, 0, sizeof (struct pci_func)); + newfunc->busno = sec_number; + newfunc->device = (u8) i; + for (j = 0; j < 4; j++) + newfunc->irq[j] = cur_func->irq[j]; + + if (flag) { + for (prev_func = cur_func; prev_func->next; prev_func = prev_func->next) ; + prev_func->next = newfunc; + } else + cur_func->next = newfunc; + + rc = ibmphp_configure_card (newfunc, slotno); + + /* Again, this case should not happen... For complete paranoia, will need to call remove_bus */ + if (rc) { + /* We need to do this in case some other BARs were properly inserted */ + func->bus = 1; /* To indicate to the unconfigure function that this is a PPB */ + cleanup_count = 2; + goto error; + } + flag = TRUE; + } + } + + function = 0x8; + break; + default: + err ("MAJOR PROBLEM!!!!, header type not supported? %x\n", hdr_type); + return -ENXIO; + break; + } /* end of switch */ + } /* end of valid device */ + } /* end of for */ + + if (!valid_device) { + err ("Cannot find any valid devices on the card. Or unable to read from card.\n"); + return -ENODEV; + } + + return 0; + +error: + for (i = 0; i < cleanup_count; i++) { + if (cur_func->io[i]) { + ibmphp_remove_resource (cur_func->io[i]); + cur_func->io[i] = NULL; + } else if (cur_func->pfmem[i]) { + ibmphp_remove_resource (cur_func->pfmem[i]); + cur_func->pfmem[i] = NULL; + } else if (cur_func->mem[i]) { + ibmphp_remove_resource (cur_func->mem[i]); + cur_func->mem[i] = NULL; + } + } + return rc; +} + +/* + * This function configures the pci BARs of a single device. + * Input: pointer to the pci_func + * Output: configured PCI, 0, or error + */ +static int configure_device (struct pci_func *func) +{ + u32 bar[6]; + u32 address[] = { + PCI_BASE_ADDRESS_0, + PCI_BASE_ADDRESS_1, + PCI_BASE_ADDRESS_2, + PCI_BASE_ADDRESS_3, + PCI_BASE_ADDRESS_4, + PCI_BASE_ADDRESS_5, + 0 + }; + u8 irq; + int count; + int len[6]; + struct resource_node *io[6]; + struct resource_node *mem[6]; + struct resource_node *mem_tmp; + struct resource_node *pfmem[6]; + unsigned int devfn; + + debug ("%s - inside\n", __FUNCTION__); + + devfn = PCI_DEVFN(func->device, func->function); + ibmphp_pci_bus->number = func->busno; + + for (count = 0; address[count]; count++) { /* for 6 BARs */ + + /* not sure if i need this. per scott, said maybe need smth like this + if devices don't adhere 100% to the spec, so don't want to write + to the reserved bits + + pcibios_read_config_byte(cur_func->busno, cur_func->device, + PCI_BASE_ADDRESS_0 + 4 * count, &tmp); + if (tmp & 0x01) // IO + pcibios_write_config_dword(cur_func->busno, cur_func->device, + PCI_BASE_ADDRESS_0 + 4 * count, 0xFFFFFFFD); + else // Memory + pcibios_write_config_dword(cur_func->busno, cur_func->device, + PCI_BASE_ADDRESS_0 + 4 * count, 0xFFFFFFFF); + */ + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF); + pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]); + + if (!bar[count]) /* This BAR is not implemented */ + continue; + + debug ("Device %x BAR %d wants %x\n", func->device, count, bar[count]); + + if (bar[count] & PCI_BASE_ADDRESS_SPACE_IO) { + /* This is IO */ + debug ("inside IO SPACE\n"); + + len[count] = bar[count] & 0xFFFFFFFC; + len[count] = ~len[count] + 1; + + debug ("len[count] in IO %x, count %d\n", len[count], count); + + io[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + + if (!io[count]) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (io[count], 0, sizeof (struct resource_node)); + io[count]->type = IO; + io[count]->busno = func->busno; + io[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); + io[count]->len = len[count]; + if (ibmphp_check_resource(io[count], 0) == 0) { + ibmphp_add_resource (io[count]); + func->io[count] = io[count]; + } else { + err ("cannot allocate requested io for bus %x device %x function %x len %x\n", + func->busno, func->device, func->function, len[count]); + kfree (io[count]); + return -EIO; + } + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->io[count]->start); + + /* _______________This is for debugging purposes only_____________________ */ + debug ("b4 writing, the IO address is %x\n", func->io[count]->start); + pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]); + debug ("after writing.... the start address is %x\n", bar[count]); + /* _________________________________________________________________________*/ + + } else { + /* This is Memory */ + if (bar[count] & PCI_BASE_ADDRESS_MEM_PREFETCH) { + /* pfmem */ + debug ("PFMEM SPACE\n"); + + len[count] = bar[count] & 0xFFFFFFF0; + len[count] = ~len[count] + 1; + + debug ("len[count] in PFMEM %x, count %d\n", len[count], count); + + pfmem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!pfmem[count]) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (pfmem[count], 0, sizeof (struct resource_node)); + pfmem[count]->type = PFMEM; + pfmem[count]->busno = func->busno; + pfmem[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); + pfmem[count]->len = len[count]; + pfmem[count]->fromMem = FALSE; + if (ibmphp_check_resource (pfmem[count], 0) == 0) { + ibmphp_add_resource (pfmem[count]); + func->pfmem[count] = pfmem[count]; + } else { + mem_tmp = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!mem_tmp) { + err ("out of system memory \n"); + kfree (pfmem[count]); + return -ENOMEM; + } + memset (mem_tmp, 0, sizeof (struct resource_node)); + mem_tmp->type = MEM; + mem_tmp->busno = pfmem[count]->busno; + mem_tmp->devfunc = pfmem[count]->devfunc; + mem_tmp->len = pfmem[count]->len; + debug ("there's no pfmem... going into mem.\n"); + if (ibmphp_check_resource (mem_tmp, 0) == 0) { + ibmphp_add_resource (mem_tmp); + pfmem[count]->fromMem = TRUE; + pfmem[count]->rangeno = mem_tmp->rangeno; + pfmem[count]->start = mem_tmp->start; + pfmem[count]->end = mem_tmp->end; + ibmphp_add_pfmem_from_mem (pfmem[count]); + func->pfmem[count] = pfmem[count]; + } else { + err ("cannot allocate requested pfmem for bus %x, device %x, len %x\n", + func->busno, func->device, len[count]); + kfree (mem_tmp); + kfree (pfmem[count]); + return -EIO; + } + } + + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->pfmem[count]->start); + + /*_______________This is for debugging purposes only______________________________*/ + debug ("b4 writing, start address is %x\n", func->pfmem[count]->start); + pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]); + debug ("after writing, start address is %x\n", bar[count]); + /*_________________________________________________________________________________*/ + + if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) { /* takes up another dword */ + debug ("inside the mem 64 case, count %d\n", count); + count += 1; + /* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */ + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0x00000000); + } + } else { + /* regular memory */ + debug ("REGULAR MEM SPACE\n"); + + len[count] = bar[count] & 0xFFFFFFF0; + len[count] = ~len[count] + 1; + + debug ("len[count] in Mem %x, count %d\n", len[count], count); + + mem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!mem[count]) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (mem[count], 0, sizeof (struct resource_node)); + mem[count]->type = MEM; + mem[count]->busno = func->busno; + mem[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); + mem[count]->len = len[count]; + if (ibmphp_check_resource (mem[count], 0) == 0) { + ibmphp_add_resource (mem[count]); + func->mem[count] = mem[count]; + } else { + err ("cannot allocate requested mem for bus %x, device %x, len %x\n", + func->busno, func->device, len[count]); + kfree (mem[count]); + return -EIO; + } + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->mem[count]->start); + /* _______________________This is for debugging purposes only _______________________*/ + debug ("b4 writing, start address is %x\n", func->mem[count]->start); + pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]); + debug ("after writing, the address is %x\n", bar[count]); + /* __________________________________________________________________________________*/ + + if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + debug ("inside mem 64 case, reg. mem, count %d\n", count); + count += 1; + /* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */ + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0x00000000); + } + } + } /* end of mem */ + } /* end of for */ + + func->bus = 0; /* To indicate that this is not a PPB */ + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_INTERRUPT_PIN, &irq); + if ((irq > 0x00) && (irq < 0x05)) + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_INTERRUPT_LINE, func->irq[irq - 1]); + + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_CACHE_LINE_SIZE, CACHE); + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_LATENCY_TIMER, LATENCY); + + pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_ROM_ADDRESS, 0x00L); + pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_COMMAND, DEVICEENABLE); + + return 0; +} + +/****************************************************************************** + * This routine configures a PCI-2-PCI bridge and the functions behind it + * Parameters: pci_func + * Returns: + ******************************************************************************/ +static int configure_bridge (struct pci_func **func_passed, u8 slotno) +{ + int count; + int i; + int rc; + u8 sec_number; + u8 io_base; + u16 pfmem_base; + u32 bar[2]; + u32 len[2]; + u8 flag_io = FALSE; + u8 flag_mem = FALSE; + u8 flag_pfmem = FALSE; + u8 need_io_upper = FALSE; + u8 need_pfmem_upper = FALSE; + struct res_needed *amount_needed = NULL; + struct resource_node *io = NULL; + struct resource_node *bus_io[2] = {NULL, NULL}; + struct resource_node *mem = NULL; + struct resource_node *bus_mem[2] = {NULL, NULL}; + struct resource_node *mem_tmp = NULL; + struct resource_node *pfmem = NULL; + struct resource_node *bus_pfmem[2] = {NULL, NULL}; + struct bus_node *bus; + u32 address[] = { + PCI_BASE_ADDRESS_0, + PCI_BASE_ADDRESS_1, + 0 + }; + struct pci_func *func = *func_passed; + unsigned int devfn; + u8 irq; + int retval; + + debug ("%s - enter\n", __FUNCTION__); + + devfn = PCI_DEVFN(func->function, func->device); + ibmphp_pci_bus->number = func->busno; + + /* Configuring necessary info for the bridge so that we could see the devices + * behind it + */ + + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_PRIMARY_BUS, func->busno); + + /* _____________________For debugging purposes only __________________________ + pci_bus_config_byte (ibmphp_pci_bus, devfn, PCI_PRIMARY_BUS, &pri_number); + debug ("primary # written into the bridge is %x\n", pri_number); + ___________________________________________________________________________*/ + + /* in EBDA, only get allocated 1 additional bus # per slot */ + sec_number = find_sec_number (func->busno, slotno); + if (sec_number == 0xff) { + err ("cannot allocate secondary bus number for the bridged device \n"); + return -EINVAL; + } + + debug ("after find_sec_number, the number we got is %x\n", sec_number); + debug ("AFTER FIND_SEC_NUMBER, func->busno IS %x\n", func->busno); + + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, sec_number); + + /* __________________For debugging purposes only __________________________________ + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number); + debug ("sec_number after write/read is %x\n", sec_number); + ________________________________________________________________________________*/ + + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_SUBORDINATE_BUS, sec_number); + + /* __________________For debugging purposes only ____________________________________ + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SUBORDINATE_BUS, &sec_number); + debug ("subordinate number after write/read is %x\n", sec_number); + __________________________________________________________________________________*/ + + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_CACHE_LINE_SIZE, CACHE); + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_LATENCY_TIMER, LATENCY); + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_SEC_LATENCY_TIMER, LATENCY); + + debug ("func->busno is %x\n", func->busno); + debug ("sec_number after writing is %x\n", sec_number); + + + /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + !!!!!!!!!!!!!!!NEED TO ADD!!! FAST BACK-TO-BACK ENABLE!!!!!!!!!!!!!!!!!!!! + !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ + + + /* First we need to allocate mem/io for the bridge itself in case it needs it */ + for (count = 0; address[count]; count++) { /* for 2 BARs */ + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF); + pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]); + + if (!bar[count]) { + /* This BAR is not implemented */ + debug ("so we come here then, eh?, count = %d\n", count); + continue; + } + // tmp_bar = bar[count]; + + debug ("Bar %d wants %x\n", count, bar[count]); + + if (bar[count] & PCI_BASE_ADDRESS_SPACE_IO) { + /* This is IO */ + len[count] = bar[count] & 0xFFFFFFFC; + len[count] = ~len[count] + 1; + + debug ("len[count] in IO = %x\n", len[count]); + + bus_io[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + + if (!bus_io[count]) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (bus_io[count], 0, sizeof (struct resource_node)); + bus_io[count]->type = IO; + bus_io[count]->busno = func->busno; + bus_io[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); + bus_io[count]->len = len[count]; + if (ibmphp_check_resource (bus_io[count], 0) == 0) { + ibmphp_add_resource (bus_io[count]); + func->io[count] = bus_io[count]; + } else { + err ("cannot allocate requested io for bus %x, device %x, len %x\n", + func->busno, func->device, len[count]); + kfree (bus_io[count]); + return -EIO; + } + + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->io[count]->start); + + } else { + /* This is Memory */ + if (bar[count] & PCI_BASE_ADDRESS_MEM_PREFETCH) { + /* pfmem */ + len[count] = bar[count] & 0xFFFFFFF0; + len[count] = ~len[count] + 1; + + debug ("len[count] in PFMEM = %x\n", len[count]); + + bus_pfmem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!bus_pfmem[count]) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (bus_pfmem[count], 0, sizeof (struct resource_node)); + bus_pfmem[count]->type = PFMEM; + bus_pfmem[count]->busno = func->busno; + bus_pfmem[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); + bus_pfmem[count]->len = len[count]; + bus_pfmem[count]->fromMem = FALSE; + if (ibmphp_check_resource (bus_pfmem[count], 0) == 0) { + ibmphp_add_resource (bus_pfmem[count]); + func->pfmem[count] = bus_pfmem[count]; + } else { + mem_tmp = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!mem_tmp) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (mem_tmp, 0, sizeof (struct resource_node)); + mem_tmp->type = MEM; + mem_tmp->busno = bus_pfmem[count]->busno; + mem_tmp->devfunc = bus_pfmem[count]->devfunc; + mem_tmp->len = bus_pfmem[count]->len; + if (ibmphp_check_resource (mem_tmp, 0) == 0) { + ibmphp_add_resource (mem_tmp); + bus_pfmem[count]->fromMem = TRUE; + bus_pfmem[count]->rangeno = mem_tmp->rangeno; + ibmphp_add_pfmem_from_mem (bus_pfmem[count]); + func->pfmem[count] = bus_pfmem[count]; + } else { + err ("cannot allocate requested pfmem for bus %x, device %x, len %x\n", + func->busno, func->device, len[count]); + kfree (mem_tmp); + kfree (bus_pfmem[count]); + return -EIO; + } + } + + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->pfmem[count]->start); + + if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + count += 1; + /* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */ + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0x00000000); + + } + } else { + /* regular memory */ + len[count] = bar[count] & 0xFFFFFFF0; + len[count] = ~len[count] + 1; + + debug ("len[count] in Memory is %x\n", len[count]); + + bus_mem[count] = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!bus_mem[count]) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (bus_mem[count], 0, sizeof (struct resource_node)); + bus_mem[count]->type = MEM; + bus_mem[count]->busno = func->busno; + bus_mem[count]->devfunc = ((func->device << 3) | (func->function & 0x7)); + bus_mem[count]->len = len[count]; + if (ibmphp_check_resource (bus_mem[count], 0) == 0) { + ibmphp_add_resource (bus_mem[count]); + func->mem[count] = bus_mem[count]; + } else { + err ("cannot allocate requested mem for bus %x, device %x, len %x\n", + func->busno, func->device, len[count]); + kfree (bus_mem[count]); + return -EIO; + } + + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], func->mem[count]->start); + + if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + count += 1; + /* on the 2nd dword, write all 0s, since we can't handle them n.e.ways */ + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0x00000000); + + } + } + } /* end of mem */ + } /* end of for */ + + /* Now need to see how much space the devices behind the bridge needed */ + amount_needed = scan_behind_bridge (func, sec_number); + if (amount_needed == NULL) + return -ENOMEM; + + ibmphp_pci_bus->number = func->busno; + debug ("after coming back from scan_behind_bridge\n"); + debug ("amount_needed->not_correct = %x\n", amount_needed->not_correct); + debug ("amount_needed->io = %x\n", amount_needed->io); + debug ("amount_needed->mem = %x\n", amount_needed->mem); + debug ("amount_needed->pfmem = %x\n", amount_needed->pfmem); + + if (amount_needed->not_correct) { + debug ("amount_needed is not correct \n"); + for (count = 0; address[count]; count++) { + /* for 2 BARs */ + if (bus_io[count]) { + ibmphp_remove_resource (bus_io[count]); + func->io[count] = NULL; + } else if (bus_pfmem[count]) { + ibmphp_remove_resource (bus_pfmem[count]); + func->pfmem[count] = NULL; + } else if (bus_mem[count]) { + ibmphp_remove_resource (bus_mem[count]); + func->mem[count] = NULL; + } + } + kfree (amount_needed); + return -ENODEV; + } + + if (!amount_needed->io) { + debug ("it doesn't want IO?\n"); + flag_io = TRUE; + } else { + debug ("it wants %x IO behind the bridge \n", amount_needed->io); + io = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + + if (!io) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (io, 0, sizeof (struct resource_node)); + io->type = IO; + io->busno = func->busno; + io->devfunc = ((func->device << 3) | (func->function & 0x7)); + io->len = amount_needed->io; + if (ibmphp_check_resource (io, 1) == 0) { + debug ("were we able to add io\n"); + ibmphp_add_resource (io); + flag_io = TRUE; + } + } + + if (!amount_needed->mem) { + debug ("it doesn't want n.e.memory?\n"); + flag_mem = TRUE; + } else { + debug ("it wants %x memory behind the bridge\n", amount_needed->mem); + mem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!mem) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (mem, 0, sizeof (struct resource_node)); + mem->type = MEM; + mem->busno = func->busno; + mem->devfunc = ((func->device << 3) | (func->function & 0x7)); + mem->len = amount_needed->mem; + if (ibmphp_check_resource (mem, 1) == 0) { + ibmphp_add_resource (mem); + flag_mem = TRUE; + debug ("were we able to add mem\n"); + } + } + + if (!amount_needed->pfmem) { + debug ("it doesn't want n.e.pfmem mem?\n"); + flag_pfmem = TRUE; + } else { + debug ("it wants %x pfmemory behind the bridge\n", amount_needed->pfmem); + pfmem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!pfmem) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (pfmem, 0, sizeof (struct resource_node)); + pfmem->type = PFMEM; + pfmem->busno = func->busno; + pfmem->devfunc = ((func->device << 3) | (func->function & 0x7)); + pfmem->len = amount_needed->pfmem; + pfmem->fromMem = FALSE; + if (ibmphp_check_resource (pfmem, 1) == 0) { + ibmphp_add_resource (pfmem); + flag_pfmem = TRUE; + } else { + mem_tmp = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!mem_tmp) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (mem_tmp, 0, sizeof (struct resource_node)); + mem_tmp->type = MEM; + mem_tmp->busno = pfmem->busno; + mem_tmp->devfunc = pfmem->devfunc; + mem_tmp->len = pfmem->len; + if (ibmphp_check_resource (mem_tmp, 1) == 0) { + ibmphp_add_resource (mem_tmp); + pfmem->fromMem = TRUE; + pfmem->rangeno = mem_tmp->rangeno; + ibmphp_add_pfmem_from_mem (pfmem); + flag_pfmem = TRUE; + } + } + } + + debug ("b4 if (flag_io && flag_mem && flag_pfmem)\n"); + debug ("flag_io = %x, flag_mem = %x, flag_pfmem = %x\n", flag_io, flag_mem, flag_pfmem); + + if (flag_io && flag_mem && flag_pfmem) { + /* If on bootup, there was a bridged card in this slot, + * then card was removed and ibmphp got unloaded and loaded + * back again, there's no way for us to remove the bus + * struct, so no need to kmalloc, can use existing node + */ + bus = ibmphp_find_res_bus (sec_number); + if (!bus) { + bus = kmalloc (sizeof (struct bus_node), GFP_KERNEL); + if (!bus) { + err ("out of system memory \n"); + retval = -ENOMEM; + goto error; + } + memset (bus, 0, sizeof (struct bus_node)); + bus->busno = sec_number; + debug ("b4 adding new bus\n"); + rc = add_new_bus (bus, io, mem, pfmem, func->busno); + } else if (!(bus->rangeIO) && !(bus->rangeMem) && !(bus->rangePFMem)) + rc = add_new_bus (bus, io, mem, pfmem, 0xFF); + else { + err ("expected bus structure not empty? \n"); + retval = -EIO; + goto error; + } + if (rc) { + if (rc == -ENOMEM) { + ibmphp_remove_bus (bus, func->busno); + kfree (amount_needed); + return rc; + } + retval = rc; + goto error; + } + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, &io_base); + pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, &pfmem_base); + + if ((io_base & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) { + debug ("io 32\n"); + need_io_upper = TRUE; + } + if ((io_base & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) { + debug ("pfmem 64\n"); + need_pfmem_upper = TRUE; + } + + if (bus->noIORanges) { + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, 0x00 | bus->rangeIO->start >> 8); + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_IO_LIMIT, 0x00 | bus->rangeIO->end >> 8); + + /* _______________This is for debugging purposes only ____________________ + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, &temp); + debug ("io_base = %x\n", (temp & PCI_IO_RANGE_TYPE_MASK) << 8); + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_LIMIT, &temp); + debug ("io_limit = %x\n", (temp & PCI_IO_RANGE_TYPE_MASK) << 8); + ________________________________________________________________________*/ + + if (need_io_upper) { /* since can't support n.e.ways */ + pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_IO_BASE_UPPER16, 0x0000); + pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_IO_LIMIT_UPPER16, 0x0000); + } + } else { + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, 0x00); + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_IO_LIMIT, 0x00); + } + + if (bus->noMemRanges) { + pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_BASE, 0x0000 | bus->rangeMem->start >> 16); + pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_LIMIT, 0x0000 | bus->rangeMem->end >> 16); + + /* ____________________This is for debugging purposes only ________________________ + pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_BASE, &temp); + debug ("mem_base = %x\n", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16); + pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_LIMIT, &temp); + debug ("mem_limit = %x\n", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16); + __________________________________________________________________________________*/ + + } else { + pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_BASE, 0xffff); + pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_LIMIT, 0x0000); + } + if (bus->noPFMemRanges) { + pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, 0x0000 | bus->rangePFMem->start >> 16); + pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, 0x0000 | bus->rangePFMem->end >> 16); + + /* __________________________This is for debugging purposes only _______________________ + pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, &temp); + debug ("pfmem_base = %x", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16); + pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &temp); + debug ("pfmem_limit = %x\n", (temp & PCI_MEMORY_RANGE_TYPE_MASK) << 16); + ______________________________________________________________________________________*/ + + if (need_pfmem_upper) { /* since can't support n.e.ways */ + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, PCI_PREF_BASE_UPPER32, 0x00000000); + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, PCI_PREF_LIMIT_UPPER32, 0x00000000); + } + } else { + pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, 0xffff); + pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, 0x0000); + } + + debug ("b4 writing control information\n"); + + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_INTERRUPT_PIN, &irq); + if ((irq > 0x00) && (irq < 0x05)) + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_INTERRUPT_LINE, func->irq[irq - 1]); + /* + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_BRIDGE_CONTROL, ctrl); + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_PARITY); + pci_bus_write_config_byte (ibmphp_pci_bus, devfn, PCI_BRIDGE_CONTROL, PCI_BRIDGE_CTL_SERR); + */ + + pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_COMMAND, DEVICEENABLE); + pci_bus_write_config_word (ibmphp_pci_bus, devfn, PCI_BRIDGE_CONTROL, 0x07); + for (i = 0; i < 32; i++) { + if (amount_needed->devices[i]) { + debug ("device where devices[i] is 1 = %x\n", i); + func->devices[i] = 1; + } + } + func->bus = 1; /* For unconfiguring, to indicate it's PPB */ + func_passed = &func; + debug ("func->busno b4 returning is %x\n", func->busno); + debug ("func->busno b4 returning in the other structure is %x\n", (*func_passed)->busno); + kfree (amount_needed); + return 0; + } else { + err ("Configuring bridge was unsuccessful... \n"); + mem_tmp = NULL; + retval = -EIO; + goto error; + } + +error: + if (amount_needed) + kfree (amount_needed); + if (pfmem) + ibmphp_remove_resource (pfmem); + if (io) + ibmphp_remove_resource (io); + if (mem) + ibmphp_remove_resource (mem); + for (i = 0; i < 2; i++) { /* for 2 BARs */ + if (bus_io[i]) { + ibmphp_remove_resource (bus_io[i]); + func->io[i] = NULL; + } else if (bus_pfmem[i]) { + ibmphp_remove_resource (bus_pfmem[i]); + func->pfmem[i] = NULL; + } else if (bus_mem[i]) { + ibmphp_remove_resource (bus_mem[i]); + func->mem[i] = NULL; + } + } + return retval; +} + +/***************************************************************************** + * This function adds up the amount of resources needed behind the PPB bridge + * and passes it to the configure_bridge function + * Input: bridge function + * Ouput: amount of resources needed + *****************************************************************************/ +static struct res_needed *scan_behind_bridge (struct pci_func * func, u8 busno) +{ + int count, len[6]; + u16 vendor_id; + u8 hdr_type; + u8 device, function; + unsigned int devfn; + int howmany = 0; /*this is to see if there are any devices behind the bridge */ + + u32 bar[6], class; + u32 address[] = { + PCI_BASE_ADDRESS_0, + PCI_BASE_ADDRESS_1, + PCI_BASE_ADDRESS_2, + PCI_BASE_ADDRESS_3, + PCI_BASE_ADDRESS_4, + PCI_BASE_ADDRESS_5, + 0 + }; + struct res_needed *amount; + + amount = kmalloc (sizeof (struct res_needed), GFP_KERNEL); + if (amount == NULL) + return NULL; + memset (amount, 0, sizeof (struct res_needed)); + + ibmphp_pci_bus->number = busno; + + debug ("the bus_no behind the bridge is %x\n", busno); + debug ("scanning devices behind the bridge...\n"); + for (device = 0; device < 32; device++) { + amount->devices[device] = 0; + for (function = 0; function < 8; function++) { + devfn = PCI_DEVFN(device, function); + + pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id); + + if (vendor_id != PCI_VENDOR_ID_NOTVALID) { + /* found correct device!!! */ + howmany++; + + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type); + pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_CLASS_REVISION, &class); + + debug ("hdr_type behind the bridge is %x\n", hdr_type); + if (hdr_type & PCI_HEADER_TYPE_BRIDGE) { + err ("embedded bridges not supported for hot-plugging.\n"); + amount->not_correct = TRUE; + return amount; + } + + class >>= 8; /* to take revision out, class = class.subclass.prog i/f */ + if (class == PCI_CLASS_NOT_DEFINED_VGA) { + err ("The device %x is VGA compatible and as is not supported for hot plugging. " + "Please choose another device.\n", device); + amount->not_correct = TRUE; + return amount; + } else if (class == PCI_CLASS_DISPLAY_VGA) { + err ("The device %x is not supported for hot plugging. " + "Please choose another device.\n", device); + amount->not_correct = TRUE; + return amount; + } + + amount->devices[device] = 1; + + for (count = 0; address[count]; count++) { + /* for 6 BARs */ + /* + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, address[count], &tmp); + if (tmp & 0x01) // IO + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFD); + else // MEMORY + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF); + */ + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF); + pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &bar[count]); + + debug ("what is bar[count]? %x, count = %d\n", bar[count], count); + + if (!bar[count]) /* This BAR is not implemented */ + continue; + + //tmp_bar = bar[count]; + + debug ("count %d device %x function %x wants %x resources \n", count, device, function, bar[count]); + + if (bar[count] & PCI_BASE_ADDRESS_SPACE_IO) { + /* This is IO */ + len[count] = bar[count] & 0xFFFFFFFC; + len[count] = ~len[count] + 1; + amount->io += len[count]; + } else { + /* This is Memory */ + if (bar[count] & PCI_BASE_ADDRESS_MEM_PREFETCH) { + /* pfmem */ + len[count] = bar[count] & 0xFFFFFFF0; + len[count] = ~len[count] + 1; + amount->pfmem += len[count]; + if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) + /* takes up another dword */ + count += 1; + + } else { + /* regular memory */ + len[count] = bar[count] & 0xFFFFFFF0; + len[count] = ~len[count] + 1; + amount->mem += len[count]; + if (bar[count] & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + count += 1; + } + } + } + } /* end for */ + } /* end if (valid) */ + } /* end for */ + } /* end for */ + + if (!howmany) + amount->not_correct = TRUE; + else + amount->not_correct = FALSE; + if ((amount->io) && (amount->io < IOBRIDGE)) + amount->io = IOBRIDGE; + if ((amount->mem) && (amount->mem < MEMBRIDGE)) + amount->mem = MEMBRIDGE; + if ((amount->pfmem) && (amount->pfmem < MEMBRIDGE)) + amount->pfmem = MEMBRIDGE; + return amount; +} + +/* The following 3 unconfigure_boot_ routines deal with the case when we had the card + * upon bootup in the system, since we don't allocate func to such case, we need to read + * the start addresses from pci config space and then find the corresponding entries in + * our resource lists. The functions return either 0, -ENODEV, or -1 (general failure) + * Change: we also call these functions even if we configured the card ourselves (i.e., not + * the bootup case), since it should work same way + */ +static int unconfigure_boot_device (u8 busno, u8 device, u8 function) +{ + u32 start_address; + u32 address[] = { + PCI_BASE_ADDRESS_0, + PCI_BASE_ADDRESS_1, + PCI_BASE_ADDRESS_2, + PCI_BASE_ADDRESS_3, + PCI_BASE_ADDRESS_4, + PCI_BASE_ADDRESS_5, + 0 + }; + int count; + struct resource_node *io; + struct resource_node *mem; + struct resource_node *pfmem; + struct bus_node *bus; + u32 end_address; + u32 temp_end; + u32 size; + u32 tmp_address; + unsigned int devfn; + + debug ("%s - enter\n", __FUNCTION__); + + bus = ibmphp_find_res_bus (busno); + if (!bus) { + debug ("cannot find corresponding bus.\n"); + return -EINVAL; + } + + devfn = PCI_DEVFN(device, function); + ibmphp_pci_bus->number = busno; + for (count = 0; address[count]; count++) { /* for 6 BARs */ + pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &start_address); + + /* We can do this here, b/c by that time the device driver of the card has been stopped */ + + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], 0xFFFFFFFF); + pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &size); + pci_bus_write_config_dword (ibmphp_pci_bus, devfn, address[count], start_address); + + debug ("start_address is %x\n", start_address); + debug ("busno, device, function %x %x %x\n", busno, device, function); + if (!size) { + /* This BAR is not implemented */ + debug ("is this bar no implemented?, count = %d\n", count); + continue; + } + tmp_address = start_address; + if (start_address & PCI_BASE_ADDRESS_SPACE_IO) { + /* This is IO */ + start_address &= PCI_BASE_ADDRESS_IO_MASK; + size = size & 0xFFFFFFFC; + size = ~size + 1; + end_address = start_address + size - 1; + if (ibmphp_find_resource (bus, start_address, &io, IO) < 0) { + err ("cannot find corresponding IO resource to remove\n"); + return -EIO; + } + debug ("io->start = %x\n", io->start); + temp_end = io->end; + start_address = io->end + 1; + ibmphp_remove_resource (io); + /* This is needed b/c of the old I/O restrictions in the BIOS */ + while (temp_end < end_address) { + if (ibmphp_find_resource (bus, start_address, &io, IO) < 0) { + err ("cannot find corresponding IO resource to remove\n"); + return -EIO; + } + debug ("io->start = %x\n", io->start); + temp_end = io->end; + start_address = io->end + 1; + ibmphp_remove_resource (io); + } + + /* ????????? DO WE NEED TO WRITE ANYTHING INTO THE PCI CONFIG SPACE BACK ?????????? */ + } else { + /* This is Memory */ + if (start_address & PCI_BASE_ADDRESS_MEM_PREFETCH) { + /* pfmem */ + start_address &= PCI_BASE_ADDRESS_MEM_MASK; + debug ("start address of pfmem is %x\n", start_address); + + if (ibmphp_find_resource (bus, start_address, &pfmem, PFMEM) < 0) { + err ("cannot find corresponding PFMEM resource to remove\n"); + return -EIO; + } + if (pfmem) + debug ("pfmem->start = %x\n", pfmem->start); + + ibmphp_remove_resource (pfmem); + + if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + count += 1; + } + + } else { + /* regular memory */ + start_address &= PCI_BASE_ADDRESS_MEM_MASK; + debug ("start address of mem is %x\n", start_address); + if (ibmphp_find_resource (bus, start_address, &mem, MEM) < 0) { + err ("cannot find corresponding MEM resource to remove\n"); + return -EIO; + } + if (mem) + debug ("mem->start = %x\n", mem->start); + + ibmphp_remove_resource (mem); + + if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + count += 1; + } + } + } /* end of mem */ + } /* end of for */ + + return 0; +} + +static int unconfigure_boot_bridge (u8 busno, u8 device, u8 function) +{ + int count; + int bus_no, pri_no, sub_no, sec_no = 0; + u32 start_address, tmp_address; + u8 sec_number, sub_number, pri_number; + struct resource_node *io = NULL; + struct resource_node *mem = NULL; + struct resource_node *pfmem = NULL; + struct bus_node *bus; + u32 address[] = { + PCI_BASE_ADDRESS_0, + PCI_BASE_ADDRESS_1, + 0 + }; + unsigned int devfn; + + devfn = PCI_DEVFN(device, function); + ibmphp_pci_bus->number = busno; + bus_no = (int) busno; + debug ("busno is %x\n", busno); + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_PRIMARY_BUS, &pri_number); + debug ("%s - busno = %x, primary_number = %x\n", __FUNCTION__, busno, pri_number); + + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number); + debug ("sec_number is %x\n", sec_number); + sec_no = (int) sec_number; + pri_no = (int) pri_number; + if (pri_no != bus_no) { + err ("primary numbers in our structures and pci config space don't match.\n"); + return -EINVAL; + } + + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_number); + sec_no = (int) sec_no; + + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SUBORDINATE_BUS, &sub_number); + sub_no = (int) sub_number; + debug ("sub_no is %d, sec_no is %d\n", sub_no, sec_no); + if (sec_no != sub_number) { + err ("there're more buses behind this bridge. Hot removal is not supported. Please choose another card\n"); + return -ENODEV; + } + + bus = ibmphp_find_res_bus (sec_number); + debug ("bus->busno is %x\n", bus->busno); + debug ("sec_number is %x\n", sec_number); + if (!bus) { + err ("cannot find Bus structure for the bridged device\n"); + return -EINVAL; + } + + ibmphp_remove_bus (bus, busno); + + for (count = 0; address[count]; count++) { + /* for 2 BARs */ + pci_bus_read_config_dword (ibmphp_pci_bus, devfn, address[count], &start_address); + + if (!start_address) { + /* This BAR is not implemented */ + continue; + } + + tmp_address = start_address; + + if (start_address & PCI_BASE_ADDRESS_SPACE_IO) { + /* This is IO */ + start_address &= PCI_BASE_ADDRESS_IO_MASK; + if (ibmphp_find_resource (bus, start_address, &io, IO) < 0) { + err ("cannot find corresponding IO resource to remove\n"); + return -EIO; + } + if (io) + debug ("io->start = %x\n", io->start); + + ibmphp_remove_resource (io); + + /* ????????? DO WE NEED TO WRITE ANYTHING INTO THE PCI CONFIG SPACE BACK ?????????? */ + } else { + /* This is Memory */ + if (start_address & PCI_BASE_ADDRESS_MEM_PREFETCH) { + /* pfmem */ + start_address &= PCI_BASE_ADDRESS_MEM_MASK; + if (ibmphp_find_resource (bus, start_address, &pfmem, PFMEM) < 0) { + err ("cannot find corresponding PFMEM resource to remove\n"); + return -EINVAL; + } + if (pfmem) + debug ("pfmem->start = %x\n", pfmem->start); + + ibmphp_remove_resource (pfmem); + + if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + count += 1; + } + + } else { + /* regular memory */ + start_address &= PCI_BASE_ADDRESS_MEM_MASK; + if (ibmphp_find_resource (bus, start_address, &mem, MEM) < 0) { + err ("cannot find corresponding MEM resource to remove\n"); + return -EINVAL; + } + if (mem) + debug ("mem->start = %x\n", mem->start); + + ibmphp_remove_resource (mem); + + if (tmp_address & PCI_BASE_ADDRESS_MEM_TYPE_64) { + /* takes up another dword */ + count += 1; + } + } + } /* end of mem */ + } /* end of for */ + debug ("%s - exiting, returning success\n", __FUNCTION__); + return 0; +} + +static int unconfigure_boot_card (struct slot *slot_cur) +{ + u16 vendor_id; + u32 class; + u8 hdr_type; + u8 device; + u8 busno; + u8 function; + int rc; + unsigned int devfn; + u8 valid_device = 0x00; /* To see if we are ever able to find valid device and read it */ + + debug ("%s - enter\n", __FUNCTION__); + + device = slot_cur->device; + busno = slot_cur->bus; + + debug ("b4 for loop, device is %x\n", device); + /* For every function on the card */ + for (function = 0x0; function < 0x08; function++) { + devfn = PCI_DEVFN(device, function); + ibmphp_pci_bus->number = busno; + + pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id); + + if (vendor_id != PCI_VENDOR_ID_NOTVALID) { + /* found correct device!!! */ + ++valid_device; + + debug ("%s - found correct device\n", __FUNCTION__); + + /* header: x x x x x x x x + * | |___________|=> 1=PPB bridge, 0=normal device, 2=CardBus Bridge + * |_=> 0 = single function device, 1 = multi-function device + */ + + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type); + pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_CLASS_REVISION, &class); + + debug ("hdr_type %x, class %x\n", hdr_type, class); + class >>= 8; /* to take revision out, class = class.subclass.prog i/f */ + if (class == PCI_CLASS_NOT_DEFINED_VGA) { + err ("The device %x function %x is VGA compatible and is not supported for hot removing. " + "Please choose another device.\n", device, function); + return -ENODEV; + } else if (class == PCI_CLASS_DISPLAY_VGA) { + err ("The device %x function %x is not supported for hot removing. " + "Please choose another device.\n", device, function); + return -ENODEV; + } + + switch (hdr_type) { + case PCI_HEADER_TYPE_NORMAL: + rc = unconfigure_boot_device (busno, device, function); + if (rc) { + err ("was not able to unconfigure device %x func %x on bus %x. bailing out... \n", + device, function, busno); + return rc; + } + function = 0x8; + break; + case PCI_HEADER_TYPE_MULTIDEVICE: + rc = unconfigure_boot_device (busno, device, function); + if (rc) { + err ("was not able to unconfigure device %x func %x on bus %x. bailing out... \n", + device, function, busno); + return rc; + } + break; + case PCI_HEADER_TYPE_BRIDGE: + class >>= 8; + if (class != PCI_CLASS_BRIDGE_PCI) { + err ("This device %x function %x is not PCI-to-PCI bridge, " + "and is not supported for hot-removing. " + "Please try another card.\n", device, function); + return -ENODEV; + } + rc = unconfigure_boot_bridge (busno, device, function); + if (rc != 0) { + err ("was not able to hot-remove PPB properly.\n"); + return rc; + } + + function = 0x8; + break; + case PCI_HEADER_TYPE_MULTIBRIDGE: + class >>= 8; + if (class != PCI_CLASS_BRIDGE_PCI) { + err ("This device %x function %x is not PCI-to-PCI bridge, " + "and is not supported for hot-removing. " + "Please try another card.\n", device, function); + return -ENODEV; + } + rc = unconfigure_boot_bridge (busno, device, function); + if (rc != 0) { + err ("was not able to hot-remove PPB properly.\n"); + return rc; + } + break; + default: + err ("MAJOR PROBLEM!!!! Cannot read device's header \n"); + return -1; + break; + } /* end of switch */ + } /* end of valid device */ + } /* end of for */ + + if (!valid_device) { + err ("Could not find device to unconfigure. Or could not read the card. \n"); + return -1; + } + return 0; +} + +/* + * free the resources of the card (multi, single, or bridged) + * Parameters: slot, flag to say if this is for removing entire module or just + * unconfiguring the device + * TO DO: will probably need to add some code in case there was some resource, + * to remove it... this is from when we have errors in the configure_card... + * !!!!!!!!!!!!!!!!!!!!!!!!!FOR BUSES!!!!!!!!!!!! + * Returns: 0, -1, -ENODEV + */ +int ibmphp_unconfigure_card (struct slot **slot_cur, int the_end) +{ + int i; + int count; + int rc; + struct slot *sl = *slot_cur; + struct pci_func *cur_func = NULL; + struct pci_func *temp_func; + + debug ("%s - enter\n", __FUNCTION__); + + if (!the_end) { + /* Need to unconfigure the card */ + rc = unconfigure_boot_card (sl); + if ((rc == -ENODEV) || (rc == -EIO) || (rc == -EINVAL)) { + /* In all other cases, will still need to get rid of func structure if it exists */ + return rc; + } + } + + if (sl->func) { + cur_func = sl->func; + while (cur_func) { + /* TO DO: WILL MOST LIKELY NEED TO GET RID OF THE BUS STRUCTURE FROM RESOURCES AS WELL */ + if (cur_func->bus) { + /* in other words, it's a PPB */ + count = 2; + } else { + count = 6; + } + + for (i = 0; i < count; i++) { + if (cur_func->io[i]) { + debug ("io[%d] exists \n", i); + if (the_end > 0) + ibmphp_remove_resource (cur_func->io[i]); + cur_func->io[i] = NULL; + } + if (cur_func->mem[i]) { + debug ("mem[%d] exists \n", i); + if (the_end > 0) + ibmphp_remove_resource (cur_func->mem[i]); + cur_func->mem[i] = NULL; + } + if (cur_func->pfmem[i]) { + debug ("pfmem[%d] exists \n", i); + if (the_end > 0) + ibmphp_remove_resource (cur_func->pfmem[i]); + cur_func->pfmem[i] = NULL; + } + } + + temp_func = cur_func->next; + kfree (cur_func); + cur_func = temp_func; + } + } + + sl->func = NULL; + *slot_cur = sl; + debug ("%s - exit\n", __FUNCTION__); + return 0; +} + +/* + * add a new bus resulting from hot-plugging a PPB bridge with devices + * + * Input: bus and the amount of resources needed (we know we can assign those, + * since they've been checked already + * Output: bus added to the correct spot + * 0, -1, error + */ +static int add_new_bus (struct bus_node *bus, struct resource_node *io, struct resource_node *mem, struct resource_node *pfmem, u8 parent_busno) +{ + struct range_node *io_range = NULL; + struct range_node *mem_range = NULL; + struct range_node *pfmem_range = NULL; + struct bus_node *cur_bus = NULL; + + /* Trying to find the parent bus number */ + if (parent_busno != 0xFF) { + cur_bus = ibmphp_find_res_bus (parent_busno); + if (!cur_bus) { + err ("strange, cannot find bus which is supposed to be at the system... something is terribly wrong...\n"); + return -ENODEV; + } + + list_add (&bus->bus_list, &cur_bus->bus_list); + } + if (io) { + io_range = kmalloc (sizeof (struct range_node), GFP_KERNEL); + if (!io_range) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (io_range, 0, sizeof (struct range_node)); + io_range->start = io->start; + io_range->end = io->end; + io_range->rangeno = 1; + bus->noIORanges = 1; + bus->rangeIO = io_range; + } + if (mem) { + mem_range = kmalloc (sizeof (struct range_node), GFP_KERNEL); + if (!mem_range) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (mem_range, 0, sizeof (struct range_node)); + mem_range->start = mem->start; + mem_range->end = mem->end; + mem_range->rangeno = 1; + bus->noMemRanges = 1; + bus->rangeMem = mem_range; + } + if (pfmem) { + pfmem_range = kmalloc (sizeof (struct range_node), GFP_KERNEL); + if (!pfmem_range) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (pfmem_range, 0, sizeof (struct range_node)); + pfmem_range->start = pfmem->start; + pfmem_range->end = pfmem->end; + pfmem_range->rangeno = 1; + bus->noPFMemRanges = 1; + bus->rangePFMem = pfmem_range; + } + return 0; +} + +/* + * find the 1st available bus number for PPB to set as its secondary bus + * Parameters: bus_number of the primary bus + * Returns: bus_number of the secondary bus or 0xff in case of failure + */ +static u8 find_sec_number (u8 primary_busno, u8 slotno) +{ + int min, max; + u8 busno; + struct bus_info *bus; + struct bus_node *bus_cur; + + bus = ibmphp_find_same_bus_num (primary_busno); + if (!bus) { + err ("cannot get slot range of the bus from the BIOS\n"); + return 0xff; + } + max = bus->slot_max; + min = bus->slot_min; + if ((slotno > max) || (slotno < min)) { + err ("got the wrong range\n"); + return 0xff; + } + busno = (u8) (slotno - (u8) min); + busno += primary_busno + 0x01; + bus_cur = ibmphp_find_res_bus (busno); + /* either there is no such bus number, or there are no ranges, which + * can only happen if we removed the bridged device in previous load + * of the driver, and now only have the skeleton bus struct + */ + if ((!bus_cur) || (!(bus_cur->rangeIO) && !(bus_cur->rangeMem) && !(bus_cur->rangePFMem))) + return busno; + return 0xff; +} + diff -Nru a/drivers/pci/hotplug/ibmphp_res.c b/drivers/pci/hotplug/ibmphp_res.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pci/hotplug/ibmphp_res.c Mon Jun 9 23:16:17 2003 @@ -0,0 +1,2157 @@ +/* + * IBM Hot Plug Controller Driver + * + * Written By: Irene Zubarev, IBM Corporation + * + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001,2002 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Send feedback to <gregkh@us.ibm.com> + * + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/pci.h> +#include <linux/list.h> +#include <linux/init.h> +#include "ibmphp.h" + +static int flags = 0; /* for testing */ + +static void update_resources (struct bus_node *bus_cur, int type, int rangeno); +static int once_over (void); +static int remove_ranges (struct bus_node *, struct bus_node *); +static int update_bridge_ranges (struct bus_node **); +static int add_range (int type, struct range_node *, struct bus_node *); +static void fix_resources (struct bus_node *); +static inline struct bus_node *find_bus_wprev (u8, struct bus_node **, u8); + +static LIST_HEAD(gbuses); +LIST_HEAD(ibmphp_res_head); + +static struct bus_node * __init alloc_error_bus (struct ebda_pci_rsrc * curr, u8 busno, int flag) +{ + struct bus_node * newbus; + + if (!(curr) && !(flag)) { + err ("NULL pointer passed \n"); + return NULL; + } + + newbus = kmalloc (sizeof (struct bus_node), GFP_KERNEL); + if (!newbus) { + err ("out of system memory \n"); + return NULL; + } + + memset (newbus, 0, sizeof (struct bus_node)); + if (flag) + newbus->busno = busno; + else + newbus->busno = curr->bus_num; + list_add_tail (&newbus->bus_list, &gbuses); + return newbus; +} + +static struct resource_node * __init alloc_resources (struct ebda_pci_rsrc * curr) +{ + struct resource_node *rs; + + if (!curr) { + err ("NULL passed to allocate \n"); + return NULL; + } + + rs = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!rs) { + err ("out of system memory \n"); + return NULL; + } + memset (rs, 0, sizeof (struct resource_node)); + rs->busno = curr->bus_num; + rs->devfunc = curr->dev_fun; + rs->start = curr->start_addr; + rs->end = curr->end_addr; + rs->len = curr->end_addr - curr->start_addr + 1; + return rs; +} + +static int __init alloc_bus_range (struct bus_node **new_bus, struct range_node **new_range, struct ebda_pci_rsrc *curr, int flag, u8 first_bus) +{ + struct bus_node * newbus; + struct range_node *newrange; + u8 num_ranges = 0; + + if (first_bus) { + newbus = kmalloc (sizeof (struct bus_node), GFP_KERNEL); + if (!newbus) { + err ("out of system memory. \n"); + return -ENOMEM; + } + memset (newbus, 0, sizeof (struct bus_node)); + newbus->busno = curr->bus_num; + } else { + newbus = *new_bus; + switch (flag) { + case MEM: + num_ranges = newbus->noMemRanges; + break; + case PFMEM: + num_ranges = newbus->noPFMemRanges; + break; + case IO: + num_ranges = newbus->noIORanges; + break; + } + } + + newrange = kmalloc (sizeof (struct range_node), GFP_KERNEL); + if (!newrange) { + if (first_bus) + kfree (newbus); + err ("out of system memory \n"); + return -ENOMEM; + } + memset (newrange, 0, sizeof (struct range_node)); + newrange->start = curr->start_addr; + newrange->end = curr->end_addr; + + if (first_bus || (!num_ranges)) + newrange->rangeno = 1; + else { + /* need to insert our range */ + add_range (flag, newrange, newbus); + debug ("%d resource Primary Bus inserted on bus %x [%x - %x]\n", flag, newbus->busno, newrange->start, newrange->end); + } + + switch (flag) { + case MEM: + newbus->rangeMem = newrange; + if (first_bus) + newbus->noMemRanges = 1; + else { + debug ("First Memory Primary on bus %x, [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + ++newbus->noMemRanges; + fix_resources (newbus); + } + break; + case IO: + newbus->rangeIO = newrange; + if (first_bus) + newbus->noIORanges = 1; + else { + debug ("First IO Primary on bus %x, [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + ++newbus->noIORanges; + fix_resources (newbus); + } + break; + case PFMEM: + newbus->rangePFMem = newrange; + if (first_bus) + newbus->noPFMemRanges = 1; + else { + debug ("1st PFMemory Primary on Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + ++newbus->noPFMemRanges; + fix_resources (newbus); + } + + break; + } + + *new_bus = newbus; + *new_range = newrange; + return 0; +} + + +/* Notes: + * 1. The ranges are ordered. The buses are not ordered. (First come) + * + * 2. If cannot allocate out of PFMem range, allocate from Mem ranges. PFmemFromMem + * are not sorted. (no need since use mem node). To not change the entire code, we + * also add mem node whenever this case happens so as not to change + * ibmphp_check_mem_resource etc (and since it really is taking Mem resource) + */ + +/***************************************************************************** + * This is the Resource Management initialization function. It will go through + * the Resource list taken from EBDA and fill in this module's data structures + * + * THIS IS NOT TAKING INTO CONSIDERATION IO RESTRICTIONS OF PRIMARY BUSES, + * SINCE WE'RE GOING TO ASSUME FOR NOW WE DON'T HAVE THOSE ON OUR BUSES FOR NOW + * + * Input: ptr to the head of the resource list from EBDA + * Output: 0, -1 or error codes + ***************************************************************************/ +int __init ibmphp_rsrc_init (void) +{ + struct ebda_pci_rsrc *curr; + struct range_node *newrange = NULL; + struct bus_node *newbus = NULL; + struct bus_node *bus_cur; + struct bus_node *bus_prev; + struct list_head *tmp; + struct resource_node *new_io = NULL; + struct resource_node *new_mem = NULL; + struct resource_node *new_pfmem = NULL; + int rc; + struct list_head *tmp_ebda; + + list_for_each (tmp_ebda, &ibmphp_ebda_pci_rsrc_head) { + curr = list_entry (tmp_ebda, struct ebda_pci_rsrc, ebda_pci_rsrc_list); + if (!(curr->rsrc_type & PCIDEVMASK)) { + /* EBDA still lists non PCI devices, so ignore... */ + debug ("this is not a PCI DEVICE in rsrc_init, please take care\n"); + // continue; + } + + /* this is a primary bus resource */ + if (curr->rsrc_type & PRIMARYBUSMASK) { + /* memory */ + if ((curr->rsrc_type & RESTYPE) == MMASK) { + /* no bus structure exists in place yet */ + if (list_empty (&gbuses)) { + if ((rc = alloc_bus_range (&newbus, &newrange, curr, MEM, 1))) + return rc; + list_add_tail (&newbus->bus_list, &gbuses); + debug ("gbuses = NULL, Memory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + } else { + bus_cur = find_bus_wprev (curr->bus_num, &bus_prev, 1); + /* found our bus */ + if (bus_cur) { + rc = alloc_bus_range (&bus_cur, &newrange, curr, MEM, 0); + if (rc) + return rc; + } else { + /* went through all the buses and didn't find ours, need to create a new bus node */ + if ((rc = alloc_bus_range (&newbus, &newrange, curr, MEM, 1))) + return rc; + + list_add_tail (&newbus->bus_list, &gbuses); + debug ("New Bus, Memory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + } + } + } else if ((curr->rsrc_type & RESTYPE) == PFMASK) { + /* prefetchable memory */ + if (list_empty (&gbuses)) { + /* no bus structure exists in place yet */ + if ((rc = alloc_bus_range (&newbus, &newrange, curr, PFMEM, 1))) + return rc; + list_add_tail (&newbus->bus_list, &gbuses); + debug ("gbuses = NULL, PFMemory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + } else { + bus_cur = find_bus_wprev (curr->bus_num, &bus_prev, 1); + if (bus_cur) { + /* found our bus */ + rc = alloc_bus_range (&bus_cur, &newrange, curr, PFMEM, 0); + if (rc) + return rc; + } else { + /* went through all the buses and didn't find ours, need to create a new bus node */ + if ((rc = alloc_bus_range (&newbus, &newrange, curr, PFMEM, 1))) + return rc; + list_add_tail (&newbus->bus_list, &gbuses); + debug ("1st Bus, PFMemory Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + } + } + } else if ((curr->rsrc_type & RESTYPE) == IOMASK) { + /* IO */ + if (list_empty (&gbuses)) { + /* no bus structure exists in place yet */ + if ((rc = alloc_bus_range (&newbus, &newrange, curr, IO, 1))) + return rc; + list_add_tail (&newbus->bus_list, &gbuses); + debug ("gbuses = NULL, IO Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + } else { + bus_cur = find_bus_wprev (curr->bus_num, &bus_prev, 1); + if (bus_cur) { + rc = alloc_bus_range (&bus_cur, &newrange, curr, IO, 0); + if (rc) + return rc; + } else { + /* went through all the buses and didn't find ours, need to create a new bus node */ + if ((rc = alloc_bus_range (&newbus, &newrange, curr, IO, 1))) + return rc; + list_add_tail (&newbus->bus_list, &gbuses); + debug ("1st Bus, IO Primary Bus %x [%x - %x]\n", newbus->busno, newrange->start, newrange->end); + } + } + + } else { + ; /* type is reserved WHAT TO DO IN THIS CASE??? + NOTHING TO DO??? */ + } + } else { + /* regular pci device resource */ + if ((curr->rsrc_type & RESTYPE) == MMASK) { + /* Memory resource */ + new_mem = alloc_resources (curr); + if (!new_mem) + return -ENOMEM; + new_mem->type = MEM; + /* + * if it didn't find the bus, means PCI dev + * came b4 the Primary Bus info, so need to + * create a bus rangeno becomes a problem... + * assign a -1 and then update once the range + * actually appears... + */ + if (ibmphp_add_resource (new_mem) < 0) { + newbus = alloc_error_bus (curr, 0, 0); + if (!newbus) + return -ENOMEM; + newbus->firstMem = new_mem; + ++newbus->needMemUpdate; + new_mem->rangeno = -1; + } + debug ("Memory resource for device %x, bus %x, [%x - %x]\n", new_mem->devfunc, new_mem->busno, new_mem->start, new_mem->end); + + } else if ((curr->rsrc_type & RESTYPE) == PFMASK) { + /* PFMemory resource */ + new_pfmem = alloc_resources (curr); + if (!new_pfmem) + return -ENOMEM; + new_pfmem->type = PFMEM; + new_pfmem->fromMem = FALSE; + if (ibmphp_add_resource (new_pfmem) < 0) { + newbus = alloc_error_bus (curr, 0, 0); + if (!newbus) + return -ENOMEM; + newbus->firstPFMem = new_pfmem; + ++newbus->needPFMemUpdate; + new_pfmem->rangeno = -1; + } + + debug ("PFMemory resource for device %x, bus %x, [%x - %x]\n", new_pfmem->devfunc, new_pfmem->busno, new_pfmem->start, new_pfmem->end); + } else if ((curr->rsrc_type & RESTYPE) == IOMASK) { + /* IO resource */ + new_io = alloc_resources (curr); + if (!new_io) + return -ENOMEM; + new_io->type = IO; + + /* + * if it didn't find the bus, means PCI dev + * came b4 the Primary Bus info, so need to + * create a bus rangeno becomes a problem... + * Can assign a -1 and then update once the + * range actually appears... + */ + if (ibmphp_add_resource (new_io) < 0) { + newbus = alloc_error_bus (curr, 0, 0); + if (!newbus) + return -ENOMEM; + newbus->firstIO = new_io; + ++newbus->needIOUpdate; + new_io->rangeno = -1; + } + debug ("IO resource for device %x, bus %x, [%x - %x]\n", new_io->devfunc, new_io->busno, new_io->start, new_io->end); + } + } + } + + list_for_each (tmp, &gbuses) { + bus_cur = list_entry (tmp, struct bus_node, bus_list); + /* This is to get info about PPB resources, since EBDA doesn't put this info into the primary bus info */ + rc = update_bridge_ranges (&bus_cur); + if (rc) + return rc; + } + rc = once_over (); /* This is to align ranges (so no -1) */ + if (rc) + return rc; + return 0; +} + +/******************************************************************************** + * This function adds a range into a sorted list of ranges per bus for a particular + * range type, it then calls another routine to update the range numbers on the + * pci devices' resources for the appropriate resource + * + * Input: type of the resource, range to add, current bus + * Output: 0 or -1, bus and range ptrs + ********************************************************************************/ +static int add_range (int type, struct range_node *range, struct bus_node *bus_cur) +{ + struct range_node *range_cur = NULL; + struct range_node *range_prev; + int count = 0, i_init; + int noRanges = 0; + + switch (type) { + case MEM: + range_cur = bus_cur->rangeMem; + noRanges = bus_cur->noMemRanges; + break; + case PFMEM: + range_cur = bus_cur->rangePFMem; + noRanges = bus_cur->noPFMemRanges; + break; + case IO: + range_cur = bus_cur->rangeIO; + noRanges = bus_cur->noIORanges; + break; + } + + range_prev = NULL; + while (range_cur) { + if (range->start < range_cur->start) + break; + range_prev = range_cur; + range_cur = range_cur->next; + count = count + 1; + } + if (!count) { + /* our range will go at the beginning of the list */ + switch (type) { + case MEM: + bus_cur->rangeMem = range; + break; + case PFMEM: + bus_cur->rangePFMem = range; + break; + case IO: + bus_cur->rangeIO = range; + break; + } + range->next = range_cur; + range->rangeno = 1; + i_init = 0; + } else if (!range_cur) { + /* our range will go at the end of the list */ + range->next = NULL; + range_prev->next = range; + range->rangeno = range_prev->rangeno + 1; + return 0; + } else { + /* the range is in the middle */ + range_prev->next = range; + range->next = range_cur; + range->rangeno = range_cur->rangeno; + i_init = range_prev->rangeno; + } + + for (count = i_init; count < noRanges; ++count) { + ++range_cur->rangeno; + range_cur = range_cur->next; + } + + update_resources (bus_cur, type, i_init + 1); + return 0; +} + +/******************************************************************************* + * This routine goes through the list of resources of type 'type' and updates + * the range numbers that they correspond to. It was called from add_range fnc + * + * Input: bus, type of the resource, the rangeno starting from which to update + ******************************************************************************/ +static void update_resources (struct bus_node *bus_cur, int type, int rangeno) +{ + struct resource_node *res = NULL; + u8 eol = FALSE; /* end of list indicator */ + + switch (type) { + case MEM: + if (bus_cur->firstMem) + res = bus_cur->firstMem; + break; + case PFMEM: + if (bus_cur->firstPFMem) + res = bus_cur->firstPFMem; + break; + case IO: + if (bus_cur->firstIO) + res = bus_cur->firstIO; + break; + } + + if (res) { + while (res) { + if (res->rangeno == rangeno) + break; + if (res->next) + res = res->next; + else if (res->nextRange) + res = res->nextRange; + else { + eol = TRUE; + break; + } + } + + if (!eol) { + /* found the range */ + while (res) { + ++res->rangeno; + res = res->next; + } + } + } +} + +static void fix_me (struct resource_node *res, struct bus_node *bus_cur, struct range_node *range) +{ + char * str = ""; + switch (res->type) { + case IO: + str = "io"; + break; + case MEM: + str = "mem"; + break; + case PFMEM: + str = "pfmem"; + break; + } + + while (res) { + if (res->rangeno == -1) { + while (range) { + if ((res->start >= range->start) && (res->end <= range->end)) { + res->rangeno = range->rangeno; + debug ("%s->rangeno in fix_resources is %d\n", str, res->rangeno); + switch (res->type) { + case IO: + --bus_cur->needIOUpdate; + break; + case MEM: + --bus_cur->needMemUpdate; + break; + case PFMEM: + --bus_cur->needPFMemUpdate; + break; + } + break; + } + range = range->next; + } + } + if (res->next) + res = res->next; + else + res = res->nextRange; + } + +} + +/***************************************************************************** + * This routine reassigns the range numbers to the resources that had a -1 + * This case can happen only if upon initialization, resources taken by pci dev + * appear in EBDA before the resources allocated for that bus, since we don't + * know the range, we assign -1, and this routine is called after a new range + * is assigned to see the resources with unknown range belong to the added range + * + * Input: current bus + * Output: none, list of resources for that bus are fixed if can be + *******************************************************************************/ +static void fix_resources (struct bus_node *bus_cur) +{ + struct range_node *range; + struct resource_node *res; + + debug ("%s - bus_cur->busno = %d\n", __FUNCTION__, bus_cur->busno); + + if (bus_cur->needIOUpdate) { + res = bus_cur->firstIO; + range = bus_cur->rangeIO; + fix_me (res, bus_cur, range); + } + if (bus_cur->needMemUpdate) { + res = bus_cur->firstMem; + range = bus_cur->rangeMem; + fix_me (res, bus_cur, range); + } + if (bus_cur->needPFMemUpdate) { + res = bus_cur->firstPFMem; + range = bus_cur->rangePFMem; + fix_me (res, bus_cur, range); + } +} + +/******************************************************************************* + * This routine adds a resource to the list of resources to the appropriate bus + * based on their resource type and sorted by their starting addresses. It assigns + * the ptrs to next and nextRange if needed. + * + * Input: resource ptr + * Output: ptrs assigned (to the node) + * 0 or -1 + *******************************************************************************/ +int ibmphp_add_resource (struct resource_node *res) +{ + struct resource_node *res_cur; + struct resource_node *res_prev; + struct bus_node *bus_cur; + struct range_node *range_cur = NULL; + struct resource_node *res_start = NULL; + + debug ("%s - enter\n", __FUNCTION__); + + if (!res) { + err ("NULL passed to add \n"); + return -ENODEV; + } + + bus_cur = find_bus_wprev (res->busno, NULL, 0); + + if (!bus_cur) { + /* didn't find a bus, smth's wrong!!! */ + debug ("no bus in the system, either pci_dev's wrong or allocation failed\n"); + return -ENODEV; + } + + /* Normal case */ + switch (res->type) { + case IO: + range_cur = bus_cur->rangeIO; + res_start = bus_cur->firstIO; + break; + case MEM: + range_cur = bus_cur->rangeMem; + res_start = bus_cur->firstMem; + break; + case PFMEM: + range_cur = bus_cur->rangePFMem; + res_start = bus_cur->firstPFMem; + break; + default: + err ("cannot read the type of the resource to add... problem \n"); + return -EINVAL; + } + while (range_cur) { + if ((res->start >= range_cur->start) && (res->end <= range_cur->end)) { + res->rangeno = range_cur->rangeno; + break; + } + range_cur = range_cur->next; + } + + /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * this is again the case of rangeno = -1 + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + */ + + if (!range_cur) { + switch (res->type) { + case IO: + ++bus_cur->needIOUpdate; + break; + case MEM: + ++bus_cur->needMemUpdate; + break; + case PFMEM: + ++bus_cur->needPFMemUpdate; + break; + } + res->rangeno = -1; + } + + debug ("The range is %d\n", res->rangeno); + if (!res_start) { + /* no first{IO,Mem,Pfmem} on the bus, 1st IO/Mem/Pfmem resource ever */ + switch (res->type) { + case IO: + bus_cur->firstIO = res; + break; + case MEM: + bus_cur->firstMem = res; + break; + case PFMEM: + bus_cur->firstPFMem = res; + break; + } + res->next = NULL; + res->nextRange = NULL; + } else { + res_cur = res_start; + res_prev = NULL; + + debug ("res_cur->rangeno is %d\n", res_cur->rangeno); + + while (res_cur) { + if (res_cur->rangeno >= res->rangeno) + break; + res_prev = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + } + + if (!res_cur) { + /* at the end of the resource list */ + debug ("i should be here, [%x - %x]\n", res->start, res->end); + res_prev->nextRange = res; + res->next = NULL; + res->nextRange = NULL; + } else if (res_cur->rangeno == res->rangeno) { + /* in the same range */ + while (res_cur) { + if (res->start < res_cur->start) + break; + res_prev = res_cur; + res_cur = res_cur->next; + } + if (!res_cur) { + /* the last resource in this range */ + res_prev->next = res; + res->next = NULL; + res->nextRange = res_prev->nextRange; + res_prev->nextRange = NULL; + } else if (res->start < res_cur->start) { + /* at the beginning or middle of the range */ + if (!res_prev) { + switch (res->type) { + case IO: + bus_cur->firstIO = res; + break; + case MEM: + bus_cur->firstMem = res; + break; + case PFMEM: + bus_cur->firstPFMem = res; + break; + } + } else if (res_prev->rangeno == res_cur->rangeno) + res_prev->next = res; + else + res_prev->nextRange = res; + + res->next = res_cur; + res->nextRange = NULL; + } + } else { + /* this is the case where it is 1st occurrence of the range */ + if (!res_prev) { + /* at the beginning of the resource list */ + res->next = NULL; + switch (res->type) { + case IO: + res->nextRange = bus_cur->firstIO; + bus_cur->firstIO = res; + break; + case MEM: + res->nextRange = bus_cur->firstMem; + bus_cur->firstMem = res; + break; + case PFMEM: + res->nextRange = bus_cur->firstPFMem; + bus_cur->firstPFMem = res; + break; + } + } else if (res_cur->rangeno > res->rangeno) { + /* in the middle of the resource list */ + res_prev->nextRange = res; + res->next = NULL; + res->nextRange = res_cur; + } + } + } + + debug ("%s - exit\n", __FUNCTION__); + return 0; +} + +/**************************************************************************** + * This routine will remove the resource from the list of resources + * + * Input: io, mem, and/or pfmem resource to be deleted + * Ouput: modified resource list + * 0 or error code + ****************************************************************************/ +int ibmphp_remove_resource (struct resource_node *res) +{ + struct bus_node *bus_cur; + struct resource_node *res_cur = NULL; + struct resource_node *res_prev; + struct resource_node *mem_cur; + char * type = ""; + + if (!res) { + err ("resource to remove is NULL \n"); + return -ENODEV; + } + + bus_cur = find_bus_wprev (res->busno, NULL, 0); + + if (!bus_cur) { + err ("cannot find corresponding bus of the io resource to remove " + "bailing out...\n"); + return -ENODEV; + } + + switch (res->type) { + case IO: + res_cur = bus_cur->firstIO; + type = "io"; + break; + case MEM: + res_cur = bus_cur->firstMem; + type = "mem"; + break; + case PFMEM: + res_cur = bus_cur->firstPFMem; + type = "pfmem"; + break; + default: + err ("unknown type for resource to remove \n"); + return -EINVAL; + } + res_prev = NULL; + + while (res_cur) { + if ((res_cur->start == res->start) && (res_cur->end == res->end)) + break; + res_prev = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + } + + if (!res_cur) { + if (res->type == PFMEM) { + /* + * case where pfmem might be in the PFMemFromMem list + * so will also need to remove the corresponding mem + * entry + */ + res_cur = bus_cur->firstPFMemFromMem; + res_prev = NULL; + + while (res_cur) { + if ((res_cur->start == res->start) && (res_cur->end == res->end)) { + mem_cur = bus_cur->firstMem; + while (mem_cur) { + if ((mem_cur->start == res_cur->start) + && (mem_cur->end == res_cur->end)) + break; + if (mem_cur->next) + mem_cur = mem_cur->next; + else + mem_cur = mem_cur->nextRange; + } + if (!mem_cur) { + err ("cannot find corresponding mem node for pfmem...\n"); + return -EINVAL; + } + + ibmphp_remove_resource (mem_cur); + if (!res_prev) + bus_cur->firstPFMemFromMem = res_cur->next; + else + res_prev->next = res_cur->next; + kfree (res_cur); + return 0; + } + res_prev = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + } + if (!res_cur) { + err ("cannot find pfmem to delete...\n"); + return -EINVAL; + } + } else { + err ("the %s resource is not in the list to be deleted...\n", type); + return -EINVAL; + } + } + if (!res_prev) { + /* first device to be deleted */ + if (res_cur->next) { + switch (res->type) { + case IO: + bus_cur->firstIO = res_cur->next; + break; + case MEM: + bus_cur->firstMem = res_cur->next; + break; + case PFMEM: + bus_cur->firstPFMem = res_cur->next; + break; + } + } else if (res_cur->nextRange) { + switch (res->type) { + case IO: + bus_cur->firstIO = res_cur->nextRange; + break; + case MEM: + bus_cur->firstMem = res_cur->nextRange; + break; + case PFMEM: + bus_cur->firstPFMem = res_cur->nextRange; + break; + } + } else { + switch (res->type) { + case IO: + bus_cur->firstIO = NULL; + break; + case MEM: + bus_cur->firstMem = NULL; + break; + case PFMEM: + bus_cur->firstPFMem = NULL; + break; + } + } + kfree (res_cur); + return 0; + } else { + if (res_cur->next) { + if (res_prev->rangeno == res_cur->rangeno) + res_prev->next = res_cur->next; + else + res_prev->nextRange = res_cur->next; + } else if (res_cur->nextRange) { + res_prev->next = NULL; + res_prev->nextRange = res_cur->nextRange; + } else { + res_prev->next = NULL; + res_prev->nextRange = NULL; + } + kfree (res_cur); + return 0; + } + + return 0; +} + +static struct range_node * find_range (struct bus_node *bus_cur, struct resource_node * res) +{ + struct range_node * range = NULL; + + switch (res->type) { + case IO: + range = bus_cur->rangeIO; + break; + case MEM: + range = bus_cur->rangeMem; + break; + case PFMEM: + range = bus_cur->rangePFMem; + break; + default: + err ("cannot read resource type in find_range \n"); + } + + while (range) { + if (res->rangeno == range->rangeno) + break; + range = range->next; + } + return range; +} + +/***************************************************************************** + * This routine will check to make sure the io/mem/pfmem->len that the device asked for + * can fit w/i our list of available IO/MEM/PFMEM resources. If cannot, returns -EINVAL, + * otherwise, returns 0 + * + * Input: resource + * Ouput: the correct start and end address are inputted into the resource node, + * 0 or -EINVAL + *****************************************************************************/ +int ibmphp_check_resource (struct resource_node *res, u8 bridge) +{ + struct bus_node *bus_cur; + struct range_node *range = NULL; + struct resource_node *res_prev; + struct resource_node *res_cur = NULL; + u32 len_cur = 0, start_cur = 0, len_tmp = 0; + int noranges = 0; + u32 tmp_start; /* this is to make sure start address is divisible by the length needed */ + u32 tmp_divide; + u8 flag = FALSE; + + if (!res) + return -EINVAL; + + if (bridge) { + /* The rules for bridges are different, 4K divisible for IO, 1M for (pf)mem*/ + if (res->type == IO) + tmp_divide = IOBRIDGE; + else + tmp_divide = MEMBRIDGE; + } else + tmp_divide = res->len; + + bus_cur = find_bus_wprev (res->busno, NULL, 0); + + if (!bus_cur) { + /* didn't find a bus, smth's wrong!!! */ + debug ("no bus in the system, either pci_dev's wrong or allocation failed \n"); + return -EINVAL; + } + + debug ("%s - enter\n", __FUNCTION__); + debug ("bus_cur->busno is %d\n", bus_cur->busno); + + /* This is a quick fix to not mess up with the code very much. i.e., + * 2000-2fff, len = 1000, but when we compare, we need it to be fff */ + res->len -= 1; + + switch (res->type) { + case IO: + res_cur = bus_cur->firstIO; + noranges = bus_cur->noIORanges; + break; + case MEM: + res_cur = bus_cur->firstMem; + noranges = bus_cur->noMemRanges; + break; + case PFMEM: + res_cur = bus_cur->firstPFMem; + noranges = bus_cur->noPFMemRanges; + break; + default: + err ("wrong type of resource to check \n"); + return -EINVAL; + } + res_prev = NULL; + + while (res_cur) { + range = find_range (bus_cur, res_cur); + debug ("%s - rangeno = %d\n", __FUNCTION__, res_cur->rangeno); + + if (!range) { + err ("no range for the device exists... bailing out...\n"); + return -EINVAL; + } + + /* found our range */ + if (!res_prev) { + /* first time in the loop */ + if ((res_cur->start != range->start) && ((len_tmp = res_cur->start - 1 - range->start) >= res->len)) { + debug ("len_tmp = %x\n", len_tmp); + + if ((len_tmp < len_cur) || (len_cur == 0)) { + + if ((range->start % tmp_divide) == 0) { + /* just perfect, starting address is divisible by length */ + flag = TRUE; + len_cur = len_tmp; + start_cur = range->start; + } else { + /* Needs adjusting */ + tmp_start = range->start; + flag = FALSE; + + while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) { + if ((tmp_start % tmp_divide) == 0) { + flag = TRUE; + len_cur = len_tmp; + start_cur = tmp_start; + break; + } + tmp_start += tmp_divide - tmp_start % tmp_divide; + if (tmp_start >= res_cur->start - 1) + break; + } + } + + if (flag && len_cur == res->len) { + debug ("but we are not here, right?\n"); + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } + } + } + } + if (!res_cur->next) { + /* last device on the range */ + if ((range->end != res_cur->end) && ((len_tmp = range->end - (res_cur->end + 1)) >= res->len)) { + debug ("len_tmp = %x\n", len_tmp); + if ((len_tmp < len_cur) || (len_cur == 0)) { + + if (((res_cur->end + 1) % tmp_divide) == 0) { + /* just perfect, starting address is divisible by length */ + flag = TRUE; + len_cur = len_tmp; + start_cur = res_cur->end + 1; + } else { + /* Needs adjusting */ + tmp_start = res_cur->end + 1; + flag = FALSE; + + while ((len_tmp = range->end - tmp_start) >= res->len) { + if ((tmp_start % tmp_divide) == 0) { + flag = TRUE; + len_cur = len_tmp; + start_cur = tmp_start; + break; + } + tmp_start += tmp_divide - tmp_start % tmp_divide; + if (tmp_start >= range->end) + break; + } + } + if (flag && len_cur == res->len) { + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } + } + } + } + + if (res_prev) { + if (res_prev->rangeno != res_cur->rangeno) { + /* 1st device on this range */ + if ((res_cur->start != range->start) && + ((len_tmp = res_cur->start - 1 - range->start) >= res->len)) { + if ((len_tmp < len_cur) || (len_cur == 0)) { + if ((range->start % tmp_divide) == 0) { + /* just perfect, starting address is divisible by length */ + flag = TRUE; + len_cur = len_tmp; + start_cur = range->start; + } else { + /* Needs adjusting */ + tmp_start = range->start; + flag = FALSE; + + while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) { + if ((tmp_start % tmp_divide) == 0) { + flag = TRUE; + len_cur = len_tmp; + start_cur = tmp_start; + break; + } + tmp_start += tmp_divide - tmp_start % tmp_divide; + if (tmp_start >= res_cur->start - 1) + break; + } + } + + if (flag && len_cur == res->len) { + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } + } + } + } else { + /* in the same range */ + if ((len_tmp = res_cur->start - 1 - res_prev->end - 1) >= res->len) { + if ((len_tmp < len_cur) || (len_cur == 0)) { + if (((res_prev->end + 1) % tmp_divide) == 0) { + /* just perfect, starting address's divisible by length */ + flag = TRUE; + len_cur = len_tmp; + start_cur = res_prev->end + 1; + } else { + /* Needs adjusting */ + tmp_start = res_prev->end + 1; + flag = FALSE; + + while ((len_tmp = res_cur->start - 1 - tmp_start) >= res->len) { + if ((tmp_start % tmp_divide) == 0) { + flag = TRUE; + len_cur = len_tmp; + start_cur = tmp_start; + break; + } + tmp_start += tmp_divide - tmp_start % tmp_divide; + if (tmp_start >= res_cur->start - 1) + break; + } + } + + if (flag && len_cur == res->len) { + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } + } + } + } + } + /* end if (res_prev) */ + res_prev = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + } /* end of while */ + + + if (!res_prev) { + /* 1st device ever */ + /* need to find appropriate range */ + switch (res->type) { + case IO: + range = bus_cur->rangeIO; + break; + case MEM: + range = bus_cur->rangeMem; + break; + case PFMEM: + range = bus_cur->rangePFMem; + break; + } + while (range) { + if ((len_tmp = range->end - range->start) >= res->len) { + if ((len_tmp < len_cur) || (len_cur == 0)) { + if ((range->start % tmp_divide) == 0) { + /* just perfect, starting address's divisible by length */ + flag = TRUE; + len_cur = len_tmp; + start_cur = range->start; + } else { + /* Needs adjusting */ + tmp_start = range->start; + flag = FALSE; + + while ((len_tmp = range->end - tmp_start) >= res->len) { + if ((tmp_start % tmp_divide) == 0) { + flag = TRUE; + len_cur = len_tmp; + start_cur = tmp_start; + break; + } + tmp_start += tmp_divide - tmp_start % tmp_divide; + if (tmp_start >= range->end) + break; + } + } + + if (flag && len_cur == res->len) { + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } + } + } + range = range->next; + } /* end of while */ + + if ((!range) && (len_cur == 0)) { + /* have gone through the list of devices and ranges and haven't found n.e.thing */ + err ("no appropriate range.. bailing out...\n"); + return -EINVAL; + } else if (len_cur) { + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } + } + + if (!res_cur) { + debug ("prev->rangeno = %d, noranges = %d\n", res_prev->rangeno, noranges); + if (res_prev->rangeno < noranges) { + /* if there're more ranges out there to check */ + switch (res->type) { + case IO: + range = bus_cur->rangeIO; + break; + case MEM: + range = bus_cur->rangeMem; + break; + case PFMEM: + range = bus_cur->rangePFMem; + break; + } + while (range) { + if ((len_tmp = range->end - range->start) >= res->len) { + if ((len_tmp < len_cur) || (len_cur == 0)) { + if ((range->start % tmp_divide) == 0) { + /* just perfect, starting address's divisible by length */ + flag = TRUE; + len_cur = len_tmp; + start_cur = range->start; + } else { + /* Needs adjusting */ + tmp_start = range->start; + flag = FALSE; + + while ((len_tmp = range->end - tmp_start) >= res->len) { + if ((tmp_start % tmp_divide) == 0) { + flag = TRUE; + len_cur = len_tmp; + start_cur = tmp_start; + break; + } + tmp_start += tmp_divide - tmp_start % tmp_divide; + if (tmp_start >= range->end) + break; + } + } + + if (flag && len_cur == res->len) { + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } + } + } + range = range->next; + } /* end of while */ + + if ((!range) && (len_cur == 0)) { + /* have gone through the list of devices and ranges and haven't found n.e.thing */ + err ("no appropriate range.. bailing out...\n"); + return -EINVAL; + } else if (len_cur) { + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } + } else { + /* no more ranges to check on */ + if (len_cur) { + res->start = start_cur; + res->len += 1; /* To restore the balance */ + res->end = res->start + res->len - 1; + return 0; + } else { + /* have gone through the list of devices and haven't found n.e.thing */ + err ("no appropriate range.. bailing out...\n"); + return -EINVAL; + } + } + } /* end if(!res_cur) */ + return -EINVAL; +} + +/******************************************************************************** + * This routine is called from remove_card if the card contained PPB. + * It will remove all the resources on the bus as well as the bus itself + * Input: Bus + * Ouput: 0, -ENODEV + ********************************************************************************/ +int ibmphp_remove_bus (struct bus_node *bus, u8 parent_busno) +{ + struct resource_node *res_cur; + struct resource_node *res_tmp; + struct bus_node *prev_bus; + int rc; + + prev_bus = find_bus_wprev (parent_busno, NULL, 0); + + if (!prev_bus) { + debug ("something terribly wrong. Cannot find parent bus to the one to remove\n"); + return -ENODEV; + } + + debug ("In ibmphp_remove_bus... prev_bus->busno is %x\n", prev_bus->busno); + + rc = remove_ranges (bus, prev_bus); + if (rc) + return rc; + + if (bus->firstIO) { + res_cur = bus->firstIO; + while (res_cur) { + res_tmp = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + kfree (res_tmp); + res_tmp = NULL; + } + bus->firstIO = NULL; + } + if (bus->firstMem) { + res_cur = bus->firstMem; + while (res_cur) { + res_tmp = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + kfree (res_tmp); + res_tmp = NULL; + } + bus->firstMem = NULL; + } + if (bus->firstPFMem) { + res_cur = bus->firstPFMem; + while (res_cur) { + res_tmp = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + kfree (res_tmp); + res_tmp = NULL; + } + bus->firstPFMem = NULL; + } + + if (bus->firstPFMemFromMem) { + res_cur = bus->firstPFMemFromMem; + while (res_cur) { + res_tmp = res_cur; + res_cur = res_cur->next; + + kfree (res_tmp); + res_tmp = NULL; + } + bus->firstPFMemFromMem = NULL; + } + + list_del (&bus->bus_list); + kfree (bus); + return 0; +} + +/****************************************************************************** + * This routine deletes the ranges from a given bus, and the entries from the + * parent's bus in the resources + * Input: current bus, previous bus + * Output: 0, -EINVAL + ******************************************************************************/ +static int remove_ranges (struct bus_node *bus_cur, struct bus_node *bus_prev) +{ + struct range_node *range_cur; + struct range_node *range_tmp; + int i; + struct resource_node *res = NULL; + + if (bus_cur->noIORanges) { + range_cur = bus_cur->rangeIO; + for (i = 0; i < bus_cur->noIORanges; i++) { + if (ibmphp_find_resource (bus_prev, range_cur->start, &res, IO) < 0) + return -EINVAL; + ibmphp_remove_resource (res); + + range_tmp = range_cur; + range_cur = range_cur->next; + kfree (range_tmp); + range_tmp = NULL; + } + bus_cur->rangeIO = NULL; + } + if (bus_cur->noMemRanges) { + range_cur = bus_cur->rangeMem; + for (i = 0; i < bus_cur->noMemRanges; i++) { + if (ibmphp_find_resource (bus_prev, range_cur->start, &res, MEM) < 0) + return -EINVAL; + + ibmphp_remove_resource (res); + range_tmp = range_cur; + range_cur = range_cur->next; + kfree (range_tmp); + range_tmp = NULL; + } + bus_cur->rangeMem = NULL; + } + if (bus_cur->noPFMemRanges) { + range_cur = bus_cur->rangePFMem; + for (i = 0; i < bus_cur->noPFMemRanges; i++) { + if (ibmphp_find_resource (bus_prev, range_cur->start, &res, PFMEM) < 0) + return -EINVAL; + + ibmphp_remove_resource (res); + range_tmp = range_cur; + range_cur = range_cur->next; + kfree (range_tmp); + range_tmp = NULL; + } + bus_cur->rangePFMem = NULL; + } + return 0; +} + +/* + * find the resource node in the bus + * Input: Resource needed, start address of the resource, type of resource + */ +int ibmphp_find_resource (struct bus_node *bus, u32 start_address, struct resource_node **res, int flag) +{ + struct resource_node *res_cur = NULL; + char * type = ""; + + if (!bus) { + err ("The bus passed in NULL to find resource \n"); + return -ENODEV; + } + + switch (flag) { + case IO: + res_cur = bus->firstIO; + type = "io"; + break; + case MEM: + res_cur = bus->firstMem; + type = "mem"; + break; + case PFMEM: + res_cur = bus->firstPFMem; + type = "pfmem"; + break; + default: + err ("wrong type of flag \n"); + return -EINVAL; + } + + while (res_cur) { + if (res_cur->start == start_address) { + *res = res_cur; + break; + } + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + } + + if (!res_cur) { + if (flag == PFMEM) { + res_cur = bus->firstPFMemFromMem; + while (res_cur) { + if (res_cur->start == start_address) { + *res = res_cur; + break; + } + res_cur = res_cur->next; + } + if (!res_cur) { + debug ("SOS...cannot find %s resource in the bus. \n", type); + return -EINVAL; + } + } else { + debug ("SOS... cannot find %s resource in the bus. \n", type); + return -EINVAL; + } + } + + if (*res) + debug ("*res->start = %x \n", (*res)->start); + + return 0; +} + +/*********************************************************************** + * This routine will free the resource structures used by the + * system. It is called from cleanup routine for the module + * Parameters: none + * Returns: none + ***********************************************************************/ +void ibmphp_free_resources (void) +{ + struct bus_node *bus_cur = NULL; + struct bus_node *bus_tmp; + struct range_node *range_cur; + struct range_node *range_tmp; + struct resource_node *res_cur; + struct resource_node *res_tmp; + struct list_head *tmp; + struct list_head *next; + int i = 0; + flags = 1; + + list_for_each_safe (tmp, next, &gbuses) { + bus_cur = list_entry (tmp, struct bus_node, bus_list); + if (bus_cur->noIORanges) { + range_cur = bus_cur->rangeIO; + for (i = 0; i < bus_cur->noIORanges; i++) { + if (!range_cur) + break; + range_tmp = range_cur; + range_cur = range_cur->next; + kfree (range_tmp); + range_tmp = NULL; + } + } + if (bus_cur->noMemRanges) { + range_cur = bus_cur->rangeMem; + for (i = 0; i < bus_cur->noMemRanges; i++) { + if (!range_cur) + break; + range_tmp = range_cur; + range_cur = range_cur->next; + kfree (range_tmp); + range_tmp = NULL; + } + } + if (bus_cur->noPFMemRanges) { + range_cur = bus_cur->rangePFMem; + for (i = 0; i < bus_cur->noPFMemRanges; i++) { + if (!range_cur) + break; + range_tmp = range_cur; + range_cur = range_cur->next; + kfree (range_tmp); + range_tmp = NULL; + } + } + + if (bus_cur->firstIO) { + res_cur = bus_cur->firstIO; + while (res_cur) { + res_tmp = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + kfree (res_tmp); + res_tmp = NULL; + } + bus_cur->firstIO = NULL; + } + if (bus_cur->firstMem) { + res_cur = bus_cur->firstMem; + while (res_cur) { + res_tmp = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + kfree (res_tmp); + res_tmp = NULL; + } + bus_cur->firstMem = NULL; + } + if (bus_cur->firstPFMem) { + res_cur = bus_cur->firstPFMem; + while (res_cur) { + res_tmp = res_cur; + if (res_cur->next) + res_cur = res_cur->next; + else + res_cur = res_cur->nextRange; + kfree (res_tmp); + res_tmp = NULL; + } + bus_cur->firstPFMem = NULL; + } + + if (bus_cur->firstPFMemFromMem) { + res_cur = bus_cur->firstPFMemFromMem; + while (res_cur) { + res_tmp = res_cur; + res_cur = res_cur->next; + + kfree (res_tmp); + res_tmp = NULL; + } + bus_cur->firstPFMemFromMem = NULL; + } + + bus_tmp = bus_cur; + list_del (&bus_cur->bus_list); + kfree (bus_tmp); + bus_tmp = NULL; + } +} + +/********************************************************************************* + * This function will go over the PFmem resources to check if the EBDA allocated + * pfmem out of memory buckets of the bus. If so, it will change the range numbers + * and a flag to indicate that this resource is out of memory. It will also move the + * Pfmem out of the pfmem resource list to the PFMemFromMem list, and will create + * a new Mem node + * This routine is called right after initialization + *******************************************************************************/ +static int __init once_over (void) +{ + struct resource_node *pfmem_cur; + struct resource_node *pfmem_prev; + struct resource_node *mem; + struct bus_node *bus_cur; + struct list_head *tmp; + + list_for_each (tmp, &gbuses) { + bus_cur = list_entry (tmp, struct bus_node, bus_list); + if ((!bus_cur->rangePFMem) && (bus_cur->firstPFMem)) { + for (pfmem_cur = bus_cur->firstPFMem, pfmem_prev = NULL; pfmem_cur; pfmem_prev = pfmem_cur, pfmem_cur = pfmem_cur->next) { + pfmem_cur->fromMem = TRUE; + if (pfmem_prev) + pfmem_prev->next = pfmem_cur->next; + else + bus_cur->firstPFMem = pfmem_cur->next; + + if (!bus_cur->firstPFMemFromMem) + pfmem_cur->next = NULL; + else + /* we don't need to sort PFMemFromMem since we're using mem node for + all the real work anyways, so just insert at the beginning of the + list + */ + pfmem_cur->next = bus_cur->firstPFMemFromMem; + + bus_cur->firstPFMemFromMem = pfmem_cur; + + mem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!mem) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (mem, 0, sizeof (struct resource_node)); + mem->type = MEM; + mem->busno = pfmem_cur->busno; + mem->devfunc = pfmem_cur->devfunc; + mem->start = pfmem_cur->start; + mem->end = pfmem_cur->end; + mem->len = pfmem_cur->len; + if (ibmphp_add_resource (mem) < 0) + err ("Trouble...trouble... EBDA allocated pfmem from mem, but system doesn't display it has this space... unless not PCI device...\n"); + pfmem_cur->rangeno = mem->rangeno; + } /* end for pfmem */ + } /* end if */ + } /* end list_for_each bus */ + return 0; +} + +int ibmphp_add_pfmem_from_mem (struct resource_node *pfmem) +{ + struct bus_node *bus_cur = find_bus_wprev (pfmem->busno, NULL, 0); + + if (!bus_cur) { + err ("cannot find bus of pfmem to add...\n"); + return -ENODEV; + } + + if (bus_cur->firstPFMemFromMem) + pfmem->next = bus_cur->firstPFMemFromMem; + else + pfmem->next = NULL; + + bus_cur->firstPFMemFromMem = pfmem; + + return 0; +} + +/* This routine just goes through the buses to see if the bus already exists. + * It is called from ibmphp_find_sec_number, to find out a secondary bus number for + * bridged cards + * Parameters: bus_number + * Returns: Bus pointer or NULL + */ +struct bus_node *ibmphp_find_res_bus (u8 bus_number) +{ + return find_bus_wprev (bus_number, NULL, 0); +} + +static inline struct bus_node *find_bus_wprev (u8 bus_number, struct bus_node **prev, u8 flag) +{ + struct bus_node *bus_cur; + struct list_head *tmp; + struct list_head *tmp_prev; + + list_for_each (tmp, &gbuses) { + tmp_prev = tmp->prev; + bus_cur = list_entry (tmp, struct bus_node, bus_list); + if (flag) + *prev = list_entry (tmp_prev, struct bus_node, bus_list); + if (bus_cur->busno == bus_number) + return bus_cur; + } + + return NULL; +} + +void ibmphp_print_test (void) +{ + int i = 0; + struct bus_node *bus_cur = NULL; + struct range_node *range; + struct resource_node *res; + struct list_head *tmp; + + debug_pci ("*****************START**********************\n"); + + if ((!list_empty(&gbuses)) && flags) { + err ("The GBUSES is not NULL?!?!?!?!?\n"); + return; + } + + list_for_each (tmp, &gbuses) { + bus_cur = list_entry (tmp, struct bus_node, bus_list); + debug_pci ("This is bus # %d. There are \n", bus_cur->busno); + debug_pci ("IORanges = %d\t", bus_cur->noIORanges); + debug_pci ("MemRanges = %d\t", bus_cur->noMemRanges); + debug_pci ("PFMemRanges = %d\n", bus_cur->noPFMemRanges); + debug_pci ("The IO Ranges are as follows:\n"); + if (bus_cur->rangeIO) { + range = bus_cur->rangeIO; + for (i = 0; i < bus_cur->noIORanges; i++) { + debug_pci ("rangeno is %d\n", range->rangeno); + debug_pci ("[%x - %x]\n", range->start, range->end); + range = range->next; + } + } + + debug_pci ("The Mem Ranges are as follows:\n"); + if (bus_cur->rangeMem) { + range = bus_cur->rangeMem; + for (i = 0; i < bus_cur->noMemRanges; i++) { + debug_pci ("rangeno is %d\n", range->rangeno); + debug_pci ("[%x - %x]\n", range->start, range->end); + range = range->next; + } + } + + debug_pci ("The PFMem Ranges are as follows:\n"); + + if (bus_cur->rangePFMem) { + range = bus_cur->rangePFMem; + for (i = 0; i < bus_cur->noPFMemRanges; i++) { + debug_pci ("rangeno is %d\n", range->rangeno); + debug_pci ("[%x - %x]\n", range->start, range->end); + range = range->next; + } + } + + debug_pci ("The resources on this bus are as follows\n"); + + debug_pci ("IO...\n"); + if (bus_cur->firstIO) { + res = bus_cur->firstIO; + while (res) { + debug_pci ("The range # is %d\n", res->rangeno); + debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc); + debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len); + if (res->next) + res = res->next; + else if (res->nextRange) + res = res->nextRange; + else + break; + } + } + debug_pci ("Mem...\n"); + if (bus_cur->firstMem) { + res = bus_cur->firstMem; + while (res) { + debug_pci ("The range # is %d\n", res->rangeno); + debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc); + debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len); + if (res->next) + res = res->next; + else if (res->nextRange) + res = res->nextRange; + else + break; + } + } + debug_pci ("PFMem...\n"); + if (bus_cur->firstPFMem) { + res = bus_cur->firstPFMem; + while (res) { + debug_pci ("The range # is %d\n", res->rangeno); + debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc); + debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len); + if (res->next) + res = res->next; + else if (res->nextRange) + res = res->nextRange; + else + break; + } + } + + debug_pci ("PFMemFromMem...\n"); + if (bus_cur->firstPFMemFromMem) { + res = bus_cur->firstPFMemFromMem; + while (res) { + debug_pci ("The range # is %d\n", res->rangeno); + debug_pci ("The bus, devfnc is %d, %x\n", res->busno, res->devfunc); + debug_pci ("[%x - %x], len=%x\n", res->start, res->end, res->len); + res = res->next; + } + } + } + debug_pci ("***********************END***********************\n"); +} + +static int range_exists_already (struct range_node * range, struct bus_node * bus_cur, u8 type) +{ + struct range_node * range_cur = NULL; + switch (type) { + case IO: + range_cur = bus_cur->rangeIO; + break; + case MEM: + range_cur = bus_cur->rangeMem; + break; + case PFMEM: + range_cur = bus_cur->rangePFMem; + break; + default: + err ("wrong type passed to find out if range already exists \n"); + return -ENODEV; + } + + while (range_cur) { + if ((range_cur->start == range->start) && (range_cur->end == range->end)) + return 1; + range_cur = range_cur->next; + } + + return 0; +} + +/* This routine will read the windows for any PPB we have and update the + * range info for the secondary bus, and will also input this info into + * primary bus, since BIOS doesn't. This is for PPB that are in the system + * on bootup. For bridged cards that were added during previous load of the + * driver, only the ranges and the bus structure are added, the devices are + * added from NVRAM + * Input: primary busno + * Returns: none + * Note: this function doesn't take into account IO restrictions etc, + * so will only work for bridges with no video/ISA devices behind them It + * also will not work for onboard PPB's that can have more than 1 *bus + * behind them All these are TO DO. + * Also need to add more error checkings... (from fnc returns etc) + */ +static int __init update_bridge_ranges (struct bus_node **bus) +{ + u8 sec_busno, device, function, hdr_type, start_io_address, end_io_address; + u16 vendor_id, upper_io_start, upper_io_end, start_mem_address, end_mem_address; + u32 start_address, end_address, upper_start, upper_end; + struct bus_node *bus_sec; + struct bus_node *bus_cur; + struct resource_node *io; + struct resource_node *mem; + struct resource_node *pfmem; + struct range_node *range; + unsigned int devfn; + + bus_cur = *bus; + if (!bus_cur) + return -ENODEV; + ibmphp_pci_bus->number = bus_cur->busno; + + debug ("inside %s \n", __FUNCTION__); + debug ("bus_cur->busno = %x\n", bus_cur->busno); + + for (device = 0; device < 32; device++) { + for (function = 0x00; function < 0x08; function++) { + devfn = PCI_DEVFN(device, function); + pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_VENDOR_ID, &vendor_id); + + if (vendor_id != PCI_VENDOR_ID_NOTVALID) { + /* found correct device!!! */ + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_HEADER_TYPE, &hdr_type); + + switch (hdr_type) { + case PCI_HEADER_TYPE_NORMAL: + function = 0x8; + break; + case PCI_HEADER_TYPE_MULTIDEVICE: + break; + case PCI_HEADER_TYPE_BRIDGE: + function = 0x8; + case PCI_HEADER_TYPE_MULTIBRIDGE: + /* We assume here that only 1 bus behind the bridge + TO DO: add functionality for several: + temp = secondary; + while (temp < subordinate) { + ... + temp++; + } + */ + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_SECONDARY_BUS, &sec_busno); + bus_sec = find_bus_wprev (sec_busno, NULL, 0); + /* this bus structure doesn't exist yet, PPB was configured during previous loading of ibmphp */ + if (!bus_sec) { + bus_sec = alloc_error_bus (NULL, sec_busno, 1); + /* the rest will be populated during NVRAM call */ + return 0; + } + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_BASE, &start_io_address); + pci_bus_read_config_byte (ibmphp_pci_bus, devfn, PCI_IO_LIMIT, &end_io_address); + pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_IO_BASE_UPPER16, &upper_io_start); + pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_IO_LIMIT_UPPER16, &upper_io_end); + start_address = (start_io_address & PCI_IO_RANGE_MASK) << 8; + start_address |= (upper_io_start << 16); + end_address = (end_io_address & PCI_IO_RANGE_MASK) << 8; + end_address |= (upper_io_end << 16); + + if ((start_address) && (start_address <= end_address)) { + range = kmalloc (sizeof (struct range_node), GFP_KERNEL); + if (!range) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (range, 0, sizeof (struct range_node)); + range->start = start_address; + range->end = end_address + 0xfff; + + if (bus_sec->noIORanges > 0) { + if (!range_exists_already (range, bus_sec, IO)) { + add_range (IO, range, bus_sec); + ++bus_sec->noIORanges; + } else { + kfree (range); + range = NULL; + } + } else { + /* 1st IO Range on the bus */ + range->rangeno = 1; + bus_sec->rangeIO = range; + ++bus_sec->noIORanges; + } + fix_resources (bus_sec); + + if (ibmphp_find_resource (bus_cur, start_address, &io, IO)) { + io = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!io) { + kfree (range); + err ("out of system memory \n"); + return -ENOMEM; + } + memset (io, 0, sizeof (struct resource_node)); + io->type = IO; + io->busno = bus_cur->busno; + io->devfunc = ((device << 3) | (function & 0x7)); + io->start = start_address; + io->end = end_address + 0xfff; + io->len = io->end - io->start + 1; + ibmphp_add_resource (io); + } + } + + pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_BASE, &start_mem_address); + pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_MEMORY_LIMIT, &end_mem_address); + + start_address = 0x00000000 | (start_mem_address & PCI_MEMORY_RANGE_MASK) << 16; + end_address = 0x00000000 | (end_mem_address & PCI_MEMORY_RANGE_MASK) << 16; + + if ((start_address) && (start_address <= end_address)) { + + range = kmalloc (sizeof (struct range_node), GFP_KERNEL); + if (!range) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (range, 0, sizeof (struct range_node)); + range->start = start_address; + range->end = end_address + 0xfffff; + + if (bus_sec->noMemRanges > 0) { + if (!range_exists_already (range, bus_sec, MEM)) { + add_range (MEM, range, bus_sec); + ++bus_sec->noMemRanges; + } else { + kfree (range); + range = NULL; + } + } else { + /* 1st Mem Range on the bus */ + range->rangeno = 1; + bus_sec->rangeMem = range; + ++bus_sec->noMemRanges; + } + + fix_resources (bus_sec); + + if (ibmphp_find_resource (bus_cur, start_address, &mem, MEM)) { + mem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!mem) { + kfree (range); + err ("out of system memory \n"); + return -ENOMEM; + } + memset (mem, 0, sizeof (struct resource_node)); + mem->type = MEM; + mem->busno = bus_cur->busno; + mem->devfunc = ((device << 3) | (function & 0x7)); + mem->start = start_address; + mem->end = end_address + 0xfffff; + mem->len = mem->end - mem->start + 1; + ibmphp_add_resource (mem); + } + } + pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_BASE, &start_mem_address); + pci_bus_read_config_word (ibmphp_pci_bus, devfn, PCI_PREF_MEMORY_LIMIT, &end_mem_address); + pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_PREF_BASE_UPPER32, &upper_start); + pci_bus_read_config_dword (ibmphp_pci_bus, devfn, PCI_PREF_LIMIT_UPPER32, &upper_end); + start_address = 0x00000000 | (start_mem_address & PCI_MEMORY_RANGE_MASK) << 16; + end_address = 0x00000000 | (end_mem_address & PCI_MEMORY_RANGE_MASK) << 16; +#if BITS_PER_LONG == 64 + start_address |= ((long) upper_start) << 32; + end_address |= ((long) upper_end) << 32; +#endif + + if ((start_address) && (start_address <= end_address)) { + + range = kmalloc (sizeof (struct range_node), GFP_KERNEL); + if (!range) { + err ("out of system memory \n"); + return -ENOMEM; + } + memset (range, 0, sizeof (struct range_node)); + range->start = start_address; + range->end = end_address + 0xfffff; + + if (bus_sec->noPFMemRanges > 0) { + if (!range_exists_already (range, bus_sec, PFMEM)) { + add_range (PFMEM, range, bus_sec); + ++bus_sec->noPFMemRanges; + } else { + kfree (range); + range = NULL; + } + } else { + /* 1st PFMem Range on the bus */ + range->rangeno = 1; + bus_sec->rangePFMem = range; + ++bus_sec->noPFMemRanges; + } + + fix_resources (bus_sec); + if (ibmphp_find_resource (bus_cur, start_address, &pfmem, PFMEM)) { + pfmem = kmalloc (sizeof (struct resource_node), GFP_KERNEL); + if (!pfmem) { + kfree (range); + err ("out of system memory \n"); + return -ENOMEM; + } + memset (pfmem, 0, sizeof (struct resource_node)); + pfmem->type = PFMEM; + pfmem->busno = bus_cur->busno; + pfmem->devfunc = ((device << 3) | (function & 0x7)); + pfmem->start = start_address; + pfmem->end = end_address + 0xfffff; + pfmem->len = pfmem->end - pfmem->start + 1; + pfmem->fromMem = FALSE; + + ibmphp_add_resource (pfmem); + } + } + break; + } /* end of switch */ + } /* end if vendor */ + } /* end for function */ + } /* end for device */ + + bus = &bus_cur; + return 0; +} diff -Nru a/drivers/pci/hotplug/pci_hotplug.h b/drivers/pci/hotplug/pci_hotplug.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pci/hotplug/pci_hotplug.h Mon Jun 9 23:16:10 2003 @@ -0,0 +1,146 @@ +/* + * PCI HotPlug Core Functions + * + * Copyright (c) 1995,2001 Compaq Computer Corporation + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Send feedback to <greg@kroah.com> + * + */ +#ifndef _PCI_HOTPLUG_H +#define _PCI_HOTPLUG_H + + +/* These values come from the PCI Hotplug Spec */ +enum pci_bus_speed { + PCI_SPEED_33MHz = 0x00, + PCI_SPEED_66MHz = 0x01, + PCI_SPEED_66MHz_PCIX = 0x02, + PCI_SPEED_100MHz_PCIX = 0x03, + PCI_SPEED_133MHz_PCIX = 0x04, + PCI_SPEED_66MHz_PCIX_266 = 0x09, + PCI_SPEED_100MHz_PCIX_266 = 0x0a, + PCI_SPEED_133MHz_PCIX_266 = 0x0b, + PCI_SPEED_66MHz_PCIX_533 = 0x11, + PCI_SPEED_100MHz_PCIX_533 = 0X12, + PCI_SPEED_133MHz_PCIX_533 = 0x13, + PCI_SPEED_UNKNOWN = 0xff, +}; + +struct hotplug_slot; +struct hotplug_slot_attribute { + struct attribute attr; + ssize_t (*show)(struct hotplug_slot *, char *); + ssize_t (*store)(struct hotplug_slot *, const char *, size_t); +}; +/** + * struct hotplug_slot_ops -the callbacks that the hotplug pci core can use + * @owner: The module owner of this structure + * @enable_slot: Called when the user wants to enable a specific pci slot + * @disable_slot: Called when the user wants to disable a specific pci slot + * @set_attention_status: Called to set the specific slot's attention LED to + * the specified value + * @hardware_test: Called to run a specified hardware test on the specified + * slot. + * @get_power_status: Called to get the current power status of a slot. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * @get_attention_status: Called to get the current attention status of a slot. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * @get_latch_status: Called to get the current latch status of a slot. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * @get_adapter_status: Called to get see if an adapter is present in the slot or not. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * @get_max_bus_speed: Called to get the max bus speed for a slot. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * @get_cur_bus_speed: Called to get the current bus speed for a slot. + * If this field is NULL, the value passed in the struct hotplug_slot_info + * will be used when this value is requested by a user. + * + * The table of function pointers that is passed to the hotplug pci core by a + * hotplug pci driver. These functions are called by the hotplug pci core when + * the user wants to do something to a specific slot (query it for information, + * set an LED, enable / disable power, etc.) + */ +struct hotplug_slot_ops { + struct module *owner; + int (*enable_slot) (struct hotplug_slot *slot); + int (*disable_slot) (struct hotplug_slot *slot); + int (*set_attention_status) (struct hotplug_slot *slot, u8 value); + int (*hardware_test) (struct hotplug_slot *slot, u32 value); + int (*get_power_status) (struct hotplug_slot *slot, u8 *value); + int (*get_attention_status) (struct hotplug_slot *slot, u8 *value); + int (*get_latch_status) (struct hotplug_slot *slot, u8 *value); + int (*get_adapter_status) (struct hotplug_slot *slot, u8 *value); + int (*get_max_bus_speed) (struct hotplug_slot *slot, enum pci_bus_speed *value); + int (*get_cur_bus_speed) (struct hotplug_slot *slot, enum pci_bus_speed *value); +}; + +/** + * struct hotplug_slot_info - used to notify the hotplug pci core of the state of the slot + * @power: if power is enabled or not (1/0) + * @attention_status: if the attention light is enabled or not (1/0) + * @latch_status: if the latch (if any) is open or closed (1/0) + * @adapter_present: if there is a pci board present in the slot or not (1/0) + * + * Used to notify the hotplug pci core of the status of a specific slot. + */ +struct hotplug_slot_info { + u8 power_status; + u8 attention_status; + u8 latch_status; + u8 adapter_status; + enum pci_bus_speed max_bus_speed; + enum pci_bus_speed cur_bus_speed; +}; + +/** + * struct hotplug_slot - used to register a physical slot with the hotplug pci core + * @name: the name of the slot being registered. This string must + * be unique amoung slots registered on this system. + * @ops: pointer to the &struct hotplug_slot_ops to be used for this slot + * @info: pointer to the &struct hotplug_slot_info for the inital values for + * this slot. + * @private: used by the hotplug pci controller driver to store whatever it + * needs. + */ +struct hotplug_slot { + char *name; + struct hotplug_slot_ops *ops; + struct hotplug_slot_info *info; + void *private; + + /* Variables below this are for use only by the hotplug pci core. */ + struct list_head slot_list; + struct kobject kobj; +}; + +extern int pci_hp_register (struct hotplug_slot *slot); +extern int pci_hp_deregister (struct hotplug_slot *slot); +extern int pci_hp_change_slot_info (struct hotplug_slot *slot, + struct hotplug_slot_info *info); + +#endif + diff -Nru a/drivers/pci/hotplug/pci_hotplug_core.c b/drivers/pci/hotplug/pci_hotplug_core.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pci/hotplug/pci_hotplug_core.c Mon Jun 9 23:16:17 2003 @@ -0,0 +1,666 @@ +/* + * PCI HotPlug Controller Core + * + * Copyright (c) 2001-2002 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001-2002 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Send feedback to <greg@kroah.com> + * + * Filesystem portion based on work done by Pat Mochel on ddfs/driverfs + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/list.h> +#include <linux/pagemap.h> +#include <linux/slab.h> +#include <linux/smp_lock.h> +#include <linux/init.h> +#include <linux/mount.h> +#include <linux/namei.h> +#include <linux/pci.h> +#include <asm/uaccess.h> +#include <linux/kobject.h> +#include <linux/sysfs.h> +#include "pci_hotplug.h" + + +#if !defined(CONFIG_HOTPLUG_PCI_MODULE) + #define MY_NAME "pci_hotplug" +#else + #define MY_NAME THIS_MODULE->name +#endif + +#define dbg(fmt, arg...) do { if (debug) printk(KERN_DEBUG "%s: %s: " fmt , MY_NAME , __FUNCTION__ , ## arg); } while (0) +#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format , MY_NAME , ## arg) + + +/* local variables */ +static int debug; + +#define DRIVER_VERSION "0.5" +#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Scott Murray <scottm@somanetworks.com>" +#define DRIVER_DESC "PCI Hot Plug PCI Core" + + +////////////////////////////////////////////////////////////////// + +static LIST_HEAD(pci_hotplug_slot_list); + +static struct subsystem hotplug_slots_subsys; + +static ssize_t hotplug_slot_attr_show(struct kobject *kobj, + struct attribute *attr, char *buf) +{ + struct hotplug_slot *slot=container_of(kobj, + struct hotplug_slot,kobj); + struct hotplug_slot_attribute *attribute = + container_of(attr, struct hotplug_slot_attribute, attr); + return attribute->show ? attribute->show(slot, buf) : 0; +} + +static ssize_t hotplug_slot_attr_store(struct kobject *kobj, + struct attribute *attr, const char *buf, size_t len) +{ + struct hotplug_slot *slot=container_of(kobj, + struct hotplug_slot,kobj); + struct hotplug_slot_attribute *attribute = + container_of(attr, struct hotplug_slot_attribute, attr); + return attribute->store ? attribute->store(slot, buf, len) : 0; +} + +static struct sysfs_ops hotplug_slot_sysfs_ops = { + .show = hotplug_slot_attr_show, + .store = hotplug_slot_attr_store, +}; + +static struct kobj_type hotplug_slot_ktype = { + .sysfs_ops = &hotplug_slot_sysfs_ops +}; + +static decl_subsys(hotplug_slots, &hotplug_slot_ktype, NULL); + + +/* these strings match up with the values in pci_bus_speed */ +static char *pci_bus_speed_strings[] = { + "33 MHz PCI", /* 0x00 */ + "66 MHz PCI", /* 0x01 */ + "66 MHz PCIX", /* 0x02 */ + "100 MHz PCIX", /* 0x03 */ + "133 MHz PCIX", /* 0x04 */ + NULL, /* 0x05 */ + NULL, /* 0x06 */ + NULL, /* 0x07 */ + NULL, /* 0x08 */ + "66 MHz PCIX 266", /* 0x09 */ + "100 MHz PCIX 266", /* 0x0a */ + "133 MHz PCIX 266", /* 0x0b */ + NULL, /* 0x0c */ + NULL, /* 0x0d */ + NULL, /* 0x0e */ + NULL, /* 0x0f */ + NULL, /* 0x10 */ + "66 MHz PCIX 533", /* 0x11 */ + "100 MHz PCIX 533", /* 0x12 */ + "133 MHz PCIX 533", /* 0x13 */ +}; + +#ifdef CONFIG_HOTPLUG_PCI_CPCI +extern int cpci_hotplug_init(int debug); +extern void cpci_hotplug_exit(void); +#else +static inline int cpci_hotplug_init(int debug) { return 0; } +static inline void cpci_hotplug_exit(void) { } +#endif + +/* Weee, fun with macros... */ +#define GET_STATUS(name,type) \ +static int get_##name (struct hotplug_slot *slot, type *value) \ +{ \ + struct hotplug_slot_ops *ops = slot->ops; \ + int retval = 0; \ + if (try_module_get(ops->owner)) { \ + if (ops->get_##name) \ + retval = ops->get_##name (slot, value); \ + else \ + *value = slot->info->name; \ + module_put(ops->owner); \ + } \ + return retval; \ +} + +GET_STATUS(power_status, u8) +GET_STATUS(attention_status, u8) +GET_STATUS(latch_status, u8) +GET_STATUS(adapter_status, u8) +GET_STATUS(max_bus_speed, enum pci_bus_speed) +GET_STATUS(cur_bus_speed, enum pci_bus_speed) + +static ssize_t power_read_file (struct hotplug_slot *slot, char *buf) +{ + int retval; + u8 value; + + retval = get_power_status (slot, &value); + if (retval) + goto exit; + retval = sprintf (buf, "%d\n", value); +exit: + return retval; +} + +static ssize_t power_write_file (struct hotplug_slot *slot, const char *buf, + size_t count) +{ + unsigned long lpower; + u8 power; + int retval = 0; + + lpower = simple_strtoul (buf, NULL, 10); + power = (u8)(lpower & 0xff); + dbg ("power = %d\n", power); + + if (!try_module_get(slot->ops->owner)) { + retval = -ENODEV; + goto exit; + } + switch (power) { + case 0: + if (slot->ops->disable_slot) + retval = slot->ops->disable_slot(slot); + break; + + case 1: + if (slot->ops->enable_slot) + retval = slot->ops->enable_slot(slot); + break; + + default: + err ("Illegal value specified for power\n"); + retval = -EINVAL; + } + module_put(slot->ops->owner); + +exit: + if (retval) + return retval; + return count; +} + +static struct hotplug_slot_attribute hotplug_slot_attr_power = { + .attr = {.name = "power", .mode = S_IFREG | S_IRUGO | S_IWUSR}, + .show = power_read_file, + .store = power_write_file +}; + +static ssize_t attention_read_file (struct hotplug_slot *slot, char *buf) +{ + int retval; + u8 value; + + retval = get_attention_status (slot, &value); + if (retval) + goto exit; + retval = sprintf (buf, "%d\n", value); + +exit: + return retval; +} + +static ssize_t attention_write_file (struct hotplug_slot *slot, const char *buf, + size_t count) +{ + unsigned long lattention; + u8 attention; + int retval = 0; + + lattention = simple_strtoul (buf, NULL, 10); + attention = (u8)(lattention & 0xff); + dbg (" - attention = %d\n", attention); + + if (!try_module_get(slot->ops->owner)) { + retval = -ENODEV; + goto exit; + } + if (slot->ops->set_attention_status) + retval = slot->ops->set_attention_status(slot, attention); + module_put(slot->ops->owner); + +exit: + if (retval) + return retval; + return count; +} + +static struct hotplug_slot_attribute hotplug_slot_attr_attention = { + .attr = {.name = "attention", .mode = S_IFREG | S_IRUGO | S_IWUSR}, + .show = attention_read_file, + .store = attention_write_file +}; + +static ssize_t latch_read_file (struct hotplug_slot *slot, char *buf) +{ + int retval; + u8 value; + + retval = get_latch_status (slot, &value); + if (retval) + goto exit; + retval = sprintf (buf, "%d\n", value); + +exit: + return retval; +} + +static struct hotplug_slot_attribute hotplug_slot_attr_latch = { + .attr = {.name = "latch", .mode = S_IFREG | S_IRUGO | S_IWUSR}, + .show = latch_read_file, +}; + +static ssize_t presence_read_file (struct hotplug_slot *slot, char *buf) +{ + int retval; + u8 value; + + retval = get_adapter_status (slot, &value); + if (retval) + goto exit; + retval = sprintf (buf, "%d\n", value); + +exit: + return retval; +} + +static struct hotplug_slot_attribute hotplug_slot_attr_presence = { + .attr = {.name = "adapter", .mode = S_IFREG | S_IRUGO | S_IWUSR}, + .show = presence_read_file, +}; + +static char *unknown_speed = "Unknown bus speed"; + +static ssize_t max_bus_speed_read_file (struct hotplug_slot *slot, char *buf) +{ + char *speed_string; + int retval; + enum pci_bus_speed value; + + retval = get_max_bus_speed (slot, &value); + if (retval) + goto exit; + + if (value == PCI_SPEED_UNKNOWN) + speed_string = unknown_speed; + else + speed_string = pci_bus_speed_strings[value]; + + retval = sprintf (buf, "%s\n", speed_string); + +exit: + return retval; +} + +static struct hotplug_slot_attribute hotplug_slot_attr_max_bus_speed = { + .attr = {.name = "max_bus_speed", .mode = S_IFREG | S_IRUGO | S_IWUSR}, + .show = max_bus_speed_read_file, +}; + +static ssize_t cur_bus_speed_read_file (struct hotplug_slot *slot, char *buf) +{ + char *speed_string; + int retval; + enum pci_bus_speed value; + + retval = get_cur_bus_speed (slot, &value); + if (retval) + goto exit; + + if (value == PCI_SPEED_UNKNOWN) + speed_string = unknown_speed; + else + speed_string = pci_bus_speed_strings[value]; + + retval = sprintf (buf, "%s\n", speed_string); + +exit: + return retval; +} + +static struct hotplug_slot_attribute hotplug_slot_attr_cur_bus_speed = { + .attr = {.name = "cur_bus_speed", .mode = S_IFREG | S_IRUGO | S_IWUSR}, + .show = cur_bus_speed_read_file, +}; + +static ssize_t test_write_file (struct hotplug_slot *slot, const char *buf, + size_t count) +{ + unsigned long ltest; + u32 test; + int retval = 0; + + ltest = simple_strtoul (buf, NULL, 10); + test = (u32)(ltest & 0xffffffff); + dbg ("test = %d\n", test); + + if (!try_module_get(slot->ops->owner)) { + retval = -ENODEV; + goto exit; + } + if (slot->ops->hardware_test) + retval = slot->ops->hardware_test(slot, test); + module_put(slot->ops->owner); + +exit: + if (retval) + return retval; + return count; +} + +static struct hotplug_slot_attribute hotplug_slot_attr_test = { + .attr = {.name = "test", .mode = S_IFREG | S_IRUGO | S_IWUSR}, + .store = test_write_file +}; + +static int has_power_file (struct hotplug_slot *slot) +{ + if ((!slot) || (!slot->ops)) + return -ENODEV; + if ((slot->ops->enable_slot) || + (slot->ops->disable_slot) || + (slot->ops->get_power_status)) + return 0; + return -ENOENT; +} + +static int has_attention_file (struct hotplug_slot *slot) +{ + if ((!slot) || (!slot->ops)) + return -ENODEV; + if ((slot->ops->set_attention_status) || + (slot->ops->get_attention_status)) + return 0; + return -ENOENT; +} + +static int has_latch_file (struct hotplug_slot *slot) +{ + if ((!slot) || (!slot->ops)) + return -ENODEV; + if (slot->ops->get_latch_status) + return 0; + return -ENOENT; +} + +static int has_adapter_file (struct hotplug_slot *slot) +{ + if ((!slot) || (!slot->ops)) + return -ENODEV; + if (slot->ops->get_adapter_status) + return 0; + return -ENOENT; +} + +static int has_max_bus_speed_file (struct hotplug_slot *slot) +{ + if ((!slot) || (!slot->ops)) + return -ENODEV; + if (slot->ops->get_max_bus_speed) + return 0; + return -ENOENT; +} + +static int has_cur_bus_speed_file (struct hotplug_slot *slot) +{ + if ((!slot) || (!slot->ops)) + return -ENODEV; + if (slot->ops->get_cur_bus_speed) + return 0; + return -ENOENT; +} + +static int has_test_file (struct hotplug_slot *slot) +{ + if ((!slot) || (!slot->ops)) + return -ENODEV; + if (slot->ops->hardware_test) + return 0; + return -ENOENT; +} + +static int fs_add_slot (struct hotplug_slot *slot) +{ + if (has_power_file(slot) == 0) + sysfs_create_file(&slot->kobj, &hotplug_slot_attr_power.attr); + + if (has_attention_file(slot) == 0) + sysfs_create_file(&slot->kobj, &hotplug_slot_attr_attention.attr); + + if (has_latch_file(slot) == 0) + sysfs_create_file(&slot->kobj, &hotplug_slot_attr_latch.attr); + + if (has_adapter_file(slot) == 0) + sysfs_create_file(&slot->kobj, &hotplug_slot_attr_presence.attr); + + if (has_max_bus_speed_file(slot) == 0) + sysfs_create_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); + + if (has_cur_bus_speed_file(slot) == 0) + sysfs_create_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr); + + if (has_test_file(slot) == 0) + sysfs_create_file(&slot->kobj, &hotplug_slot_attr_test.attr); + + return 0; +} + +static void fs_remove_slot (struct hotplug_slot *slot) +{ + if (has_power_file(slot) == 0) + sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_power.attr); + + if (has_attention_file(slot) == 0) + sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_attention.attr); + + if (has_latch_file(slot) == 0) + sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_latch.attr); + + if (has_adapter_file(slot) == 0) + sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_presence.attr); + + if (has_max_bus_speed_file(slot) == 0) + sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); + + if (has_cur_bus_speed_file(slot) == 0) + sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr); + + if (has_test_file(slot) == 0) + sysfs_remove_file(&slot->kobj, &hotplug_slot_attr_test.attr); +} + +static struct hotplug_slot *get_slot_from_name (const char *name) +{ + struct hotplug_slot *slot; + struct list_head *tmp; + + list_for_each (tmp, &pci_hotplug_slot_list) { + slot = list_entry (tmp, struct hotplug_slot, slot_list); + if (strcmp(slot->name, name) == 0) + return slot; + } + return NULL; +} + +/** + * pci_hp_register - register a hotplug_slot with the PCI hotplug subsystem + * @slot: pointer to the &struct hotplug_slot to register + * + * Registers a hotplug slot with the pci hotplug subsystem, which will allow + * userspace interaction to the slot. + * + * Returns 0 if successful, anything else for an error. + */ +int pci_hp_register (struct hotplug_slot *slot) +{ + int result; + + if (slot == NULL) + return -ENODEV; + if ((slot->info == NULL) || (slot->ops == NULL)) + return -EINVAL; + + strlcpy(slot->kobj.name, slot->name, KOBJ_NAME_LEN); + kobj_set_kset_s(slot, hotplug_slots_subsys); + + /* this can fail if we have already registered a slot with the same name */ + if (kobject_register(&slot->kobj)) { + err("Unable to register kobject"); + return -EINVAL; + } + + list_add (&slot->slot_list, &pci_hotplug_slot_list); + + result = fs_add_slot (slot); + dbg ("Added slot %s to the list\n", slot->name); + return result; +} + +/** + * pci_hp_deregister - deregister a hotplug_slot with the PCI hotplug subsystem + * @slot: pointer to the &struct hotplug_slot to deregister + * + * The @slot must have been registered with the pci hotplug subsystem + * previously with a call to pci_hp_register(). + * + * Returns 0 if successful, anything else for an error. + */ +int pci_hp_deregister (struct hotplug_slot *slot) +{ + struct hotplug_slot *temp; + + if (slot == NULL) + return -ENODEV; + + temp = get_slot_from_name (slot->name); + if (temp != slot) { + return -ENODEV; + } + list_del (&slot->slot_list); + + fs_remove_slot (slot); + dbg ("Removed slot %s from the list\n", slot->name); + kobject_unregister(&slot->kobj); + return 0; +} + +/** + * pci_hp_change_slot_info - changes the slot's information structure in the core + * @slot: pointer to the slot whose info has changed + * @info: pointer to the info copy into the slot's info structure + * + * @slot must have been registered with the pci + * hotplug subsystem previously with a call to pci_hp_register(). + * + * Returns 0 if successful, anything else for an error. + */ +int pci_hp_change_slot_info (struct hotplug_slot *slot, struct hotplug_slot_info *info) +{ + if ((slot == NULL) || (info == NULL)) + return -ENODEV; + + /* + * check all fields in the info structure, and update timestamps + * for the files referring to the fields that have now changed. + */ + if ((has_power_file(slot) == 0) && + (slot->info->power_status != info->power_status)) + sysfs_update_file(&slot->kobj, &hotplug_slot_attr_power.attr); + + if ((has_attention_file(slot) == 0) && + (slot->info->attention_status != info->attention_status)) + sysfs_update_file(&slot->kobj, &hotplug_slot_attr_attention.attr); + + if ((has_latch_file(slot) == 0) && + (slot->info->latch_status != info->latch_status)) + sysfs_update_file(&slot->kobj, &hotplug_slot_attr_latch.attr); + + if ((has_adapter_file(slot) == 0) && + (slot->info->adapter_status != info->adapter_status)) + sysfs_update_file(&slot->kobj, &hotplug_slot_attr_presence.attr); + + if ((has_max_bus_speed_file(slot) == 0) && + (slot->info->max_bus_speed != info->max_bus_speed)) + sysfs_update_file(&slot->kobj, &hotplug_slot_attr_max_bus_speed.attr); + + if ((has_cur_bus_speed_file(slot) == 0) && + (slot->info->cur_bus_speed != info->cur_bus_speed)) + sysfs_update_file(&slot->kobj, &hotplug_slot_attr_cur_bus_speed.attr); + + memcpy (slot->info, info, sizeof (struct hotplug_slot_info)); + + return 0; +} + +static int __init pci_hotplug_init (void) +{ + int result; + + kset_set_kset_s(&hotplug_slots_subsys, pci_bus_type.subsys); + result = subsystem_register(&hotplug_slots_subsys); + if (result) { + err("Register subsys with error %d\n", result); + goto exit; + } + result = cpci_hotplug_init(debug); + if (result) { + err ("cpci_hotplug_init with error %d\n", result); + goto err_subsys; + } + + info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); + goto exit; + +err_subsys: + subsystem_unregister(&hotplug_slots_subsys); +exit: + return result; +} + +static void __exit pci_hotplug_exit (void) +{ + cpci_hotplug_exit(); + subsystem_unregister(&hotplug_slots_subsys); +} + +module_init(pci_hotplug_init); +module_exit(pci_hotplug_exit); + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); + +EXPORT_SYMBOL_GPL(pci_hp_register); +EXPORT_SYMBOL_GPL(pci_hp_deregister); +EXPORT_SYMBOL_GPL(pci_hp_change_slot_info); diff -Nru a/drivers/pci/hotplug/pcihp_skeleton.c b/drivers/pci/hotplug/pcihp_skeleton.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/drivers/pci/hotplug/pcihp_skeleton.c Mon Jun 9 23:16:13 2003 @@ -0,0 +1,432 @@ +/* + * PCI Hot Plug Controller Skeleton Driver - 0.1 + * + * Copyright (c) 2001 Greg Kroah-Hartman (greg@kroah.com) + * Copyright (c) 2001 IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * This driver is to be used as a skeleton driver to be show how to interface + * with the pci hotplug core easily. + * + * Send feedback to <greg@kroah.com> + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/pci.h> +#include <linux/init.h> +#include "pci_hotplug.h" + + +#define SLOT_MAGIC 0x67267322 +struct slot { + u32 magic; + u8 number; + struct hotplug_slot *hotplug_slot; + struct list_head slot_list; +}; + +static LIST_HEAD(slot_list); + +#if !defined(CONFIG_HOTPLUG_PCI_SKELETON_MODULE) + #define MY_NAME "pcihp_skeleton" +#else + #define MY_NAME THIS_MODULE->name +#endif + +#define dbg(format, arg...) \ + do { \ + if (debug) \ + printk (KERN_DEBUG "%s: " format "\n", \ + MY_NAME , ## arg); \ + } while (0) +#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME , ## arg) +#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME , ## arg) +#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME , ## arg) + + + +/* local variables */ +static int debug; +static int num_slots; + +#define DRIVER_VERSION "0.1" +#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>" +#define DRIVER_DESC "Hot Plug PCI Controller Skeleton Driver" + +MODULE_AUTHOR(DRIVER_AUTHOR); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Debugging mode enabled or not"); + +static int enable_slot (struct hotplug_slot *slot); +static int disable_slot (struct hotplug_slot *slot); +static int set_attention_status (struct hotplug_slot *slot, u8 value); +static int hardware_test (struct hotplug_slot *slot, u32 value); +static int get_power_status (struct hotplug_slot *slot, u8 *value); +static int get_attention_status (struct hotplug_slot *slot, u8 *value); +static int get_latch_status (struct hotplug_slot *slot, u8 *value); +static int get_adapter_status (struct hotplug_slot *slot, u8 *value); + +static struct hotplug_slot_ops skel_hotplug_slot_ops = { + .owner = THIS_MODULE, + .enable_slot = enable_slot, + .disable_slot = disable_slot, + .set_attention_status = set_attention_status, + .hardware_test = hardware_test, + .get_power_status = get_power_status, + .get_attention_status = get_attention_status, + .get_latch_status = get_latch_status, + .get_adapter_status = get_adapter_status, +}; + + +/* Inline functions to check the sanity of a pointer that is passed to us */ +static inline int slot_paranoia_check (struct slot *slot, const char *function) +{ + if (!slot) { + dbg("%s - slot == NULL", function); + return -1; + } + if (slot->magic != SLOT_MAGIC) { + dbg("%s - bad magic number for slot", function); + return -1; + } + if (!slot->hotplug_slot) { + dbg("%s - slot->hotplug_slot == NULL!", function); + return -1; + } + return 0; +} + +static inline struct slot *get_slot (struct hotplug_slot *hotplug_slot, const char *function) +{ + struct slot *slot; + + if (!hotplug_slot) { + dbg("%s - hotplug_slot == NULL\n", function); + return NULL; + } + + slot = (struct slot *)hotplug_slot->private; + if (slot_paranoia_check (slot, function)) + return NULL; + return slot; +} + + +static int enable_slot (struct hotplug_slot *hotplug_slot) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg ("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + /* + * Fill in code here to enable the specified slot + */ + + return retval; +} + + +static int disable_slot (struct hotplug_slot *hotplug_slot) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg ("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + /* + * Fill in code here to disable the specified slot + */ + + return retval; +} + +static int set_attention_status (struct hotplug_slot *hotplug_slot, u8 status) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg ("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + switch (status) { + case 0: + /* + * Fill in code here to turn light off + */ + break; + + case 1: + default: + /* + * Fill in code here to turn light on + */ + break; + } + + return retval; +} + +static int hardware_test (struct hotplug_slot *hotplug_slot, u32 value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg ("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name); + + err ("No hardware tests are defined for this driver"); + retval = -ENODEV; + + /* Or you can specify a test if you want to */ + + return retval; +} + +static int get_power_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name); + + /* + * Fill in logic to get the current power status of the specific + * slot and store it in the *value location. + */ + + return retval; +} + +static int get_attention_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name); + + /* + * Fill in logic to get the current attention status of the specific + * slot and store it in the *value location. + */ + + return retval; +} + +static int get_latch_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name); + + /* + * Fill in logic to get the current latch status of the specific + * slot and store it in the *value location. + */ + + return retval; +} + +static int get_adapter_status (struct hotplug_slot *hotplug_slot, u8 *value) +{ + struct slot *slot = get_slot (hotplug_slot, __FUNCTION__); + int retval = 0; + + if (slot == NULL) + return -ENODEV; + + dbg(__FUNCTION__" - physical_slot = %s\n", hotplug_slot->name); + + /* + * Fill in logic to get the current adapter status of the specific + * slot and store it in the *value location. + */ + + return retval; +} + +#define SLOT_NAME_SIZE 10 +static void make_slot_name (struct slot *slot) +{ + /* + * Stupid way to make a filename out of the slot name. + * replace this if your hardware provides a better way to name slots. + */ + snprintf (slot->hotplug_slot->name, SLOT_NAME_SIZE, "%d", slot->number); +} + +static int init_slots (void) +{ + struct slot *slot; + struct hotplug_slot *hotplug_slot; + struct hotplug_slot_info *info; + char *name; + int retval = 0; + int i; + + /* + * Create a structure for each slot, and register that slot + * with the pci_hotplug subsystem. + */ + for (i = 0; i < num_slots; ++i) { + slot = kmalloc (sizeof (struct slot), GFP_KERNEL); + if (!slot) + return -ENOMEM; + memset(slot, 0, sizeof(struct slot)); + + hotplug_slot = kmalloc (sizeof (struct hotplug_slot), GFP_KERNEL); + if (!hotplug_slot) { + kfree (slot); + return -ENOMEM; + } + memset(hotplug_slot, 0, sizeof (struct hotplug_slot)); + slot->hotplug_slot = hotplug_slot; + + info = kmalloc (sizeof (struct hotplug_slot_info), GFP_KERNEL); + if (!info) { + kfree (hotplug_slot); + kfree (slot); + return -ENOMEM; + } + memset(info, 0, sizeof (struct hotplug_slot_info)); + hotplug_slot->info = info; + + name = kmalloc (SLOT_NAME_SIZE, GFP_KERNEL); + if (!name) { + kfree (info); + kfree (hotplug_slot); + kfree (slot); + return -ENOMEM; + } + hotplug_slot->name = name; + + slot->magic = SLOT_MAGIC; + slot->number = i; + + hotplug_slot->private = slot; + make_slot_name (slot); + hotplug_slot->ops = &skel_hotplug_slot_ops; + + /* + * Initilize the slot info structure with some known + * good values. + */ + info->power_status = get_skel_power_status(slot); + info->attention_status = get_skel_attention_status(slot); + info->latch_status = get_skel_latch_status(slot); + info->adapter_status = get_skel_adapter_status(slot); + + dbg ("registering slot %d\n", i); + retval = pci_hp_register (slot->hotplug_slot); + if (retval) { + err ("pci_hp_register failed with error %d\n", retval); + kfree (info); + kfree (name); + kfree (hotplug_slot); + kfree (slot); + return retval; + } + + /* add slot to our internal list */ + list_add (&slot->slot_list, &slot_list); + } + + return retval; +} + +static void cleanup_slots (void) +{ + struct list_head *tmp; + struct slot *slot; + + /* + * Unregister all of our slots with the pci_hotplug subsystem, + * and free up all memory that we had allocated. + */ + list_for_each (tmp, &slot_list) { + slot = list_entry (tmp, struct slot, slot_list); + list_del (&slot->slot_list); + pci_hp_deregister (slot->hotplug_slot); + kfree (slot->hotplug_slot->info); + kfree (slot->hotplug_slot->name); + kfree (slot->hotplug_slot); + kfree (slot); + } + + return; +} + +static int __init pcihp_skel_init(void) +{ + int retval; + + /* + * Do specific initialization stuff for your driver here + * Like initilizing your controller hardware (if any) and + * determining the number of slots you have in the system + * right now. + */ + num_slots = 5; + + retval = init_slots(); + if (retval) + return retval; + + info (DRIVER_DESC " version: " DRIVER_VERSION "\n"); + return 0; +} + +static void __exit pcihp_skel_exit(void) +{ + /* + * Clean everything up. + */ + cleanup_slots(); +} + +module_init(pcihp_skel_init); +module_exit(pcihp_skel_exit); + diff -Nru a/drivers/pci/hotplug.c b/drivers/pci/hotplug.c --- a/drivers/pci/hotplug.c Mon Jun 9 23:16:18 2003 +++ b/drivers/pci/hotplug.c Mon Jun 9 23:16:18 2003 @@ -190,9 +190,7 @@ list_del(&dev->bus_list); list_del(&dev->global_list); pci_free_resources(dev); -#ifdef CONFIG_PROC_FS pci_proc_detach_device(dev); -#endif return 0; } EXPORT_SYMBOL(pci_remove_device_safe); @@ -237,10 +235,7 @@ struct pci_bus *b = dev->subordinate; pci_remove_behind_bridge(dev); - -#ifdef CONFIG_PROC_FS pci_proc_detach_bus(b); -#endif list_del(&b->node); kfree(b); @@ -251,10 +246,7 @@ list_del(&dev->bus_list); list_del(&dev->global_list); pci_free_resources(dev); -#ifdef CONFIG_PROC_FS pci_proc_detach_device(dev); -#endif - pci_put_dev(dev); } diff -Nru a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c --- a/drivers/pci/pci-driver.c Mon Jun 9 23:16:15 2003 +++ b/drivers/pci/pci-driver.c Mon Jun 9 23:16:15 2003 @@ -138,10 +138,11 @@ drv = to_pci_driver(dev->driver); pci_dev = to_pci_dev(dev); - if (get_device(dev)) { - error = __pci_device_probe(drv, pci_dev); - put_device(dev); - } + pci_get_dev(pci_dev); + error = __pci_device_probe(drv, pci_dev); + if (error) + pci_put_dev(pci_dev); + return error; } @@ -155,6 +156,7 @@ drv->remove(pci_dev); pci_dev->driver = NULL; } + pci_put_dev(pci_dev); return 0; } @@ -235,7 +237,7 @@ driver_data : 0UL; spin_lock(&pdrv->dynids.lock); - list_add(&pdrv->dynids.list, &dynid->node); + list_add_tail(&pdrv->dynids.list, &dynid->node); spin_unlock(&pdrv->dynids.lock); bus = get_bus(pdrv->driver.bus); @@ -315,6 +317,22 @@ INIT_LIST_HEAD(&dynids->list); } +static void +pci_free_dynids(struct pci_driver *drv) +{ + struct list_head *pos, *n; + struct dynid *dynid; + + spin_lock(&drv->dynids.lock); + list_for_each_safe(pos, n, &drv->dynids.list) { + dynid = list_entry(pos, struct dynid, node); + list_del(&dynid->node); + kfree(dynid); + } + spin_unlock(&drv->dynids.lock); +} + + /** * pci_register_driver - register a new pci driver * @drv: the driver structure to register @@ -363,6 +381,7 @@ pci_unregister_driver(struct pci_driver *drv) { driver_unregister(&drv->driver); + pci_free_dynids(drv); } static struct pci_driver pci_compat_driver = { diff -Nru a/drivers/pci/pci.c b/drivers/pci/pci.c --- a/drivers/pci/pci.c Mon Jun 9 23:16:09 2003 +++ b/drivers/pci/pci.c Mon Jun 9 23:16:09 2003 @@ -701,11 +701,22 @@ return 0; } +int +pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask) +{ + if (!pci_dma_supported(dev, mask)) + return -EIO; + + dev->consistent_dma_mask = mask; + + return 0; +} + static int __devinit pci_init(void) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { pci_fixup_device(PCI_FIXUP_FINAL, dev); } return 0; @@ -751,6 +762,7 @@ EXPORT_SYMBOL(pci_clear_mwi); EXPORT_SYMBOL(pci_set_dma_mask); EXPORT_SYMBOL(pci_dac_set_dma_mask); +EXPORT_SYMBOL(pci_set_consistent_dma_mask); EXPORT_SYMBOL(pci_assign_resource); EXPORT_SYMBOL(pci_find_parent_resource); diff -Nru a/drivers/pci/pci.h b/drivers/pci/pci.h --- a/drivers/pci/pci.h Mon Jun 9 23:16:10 2003 +++ b/drivers/pci/pci.h Mon Jun 9 23:16:10 2003 @@ -3,3 +3,58 @@ extern int pci_hotplug (struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size); extern void pci_create_sysfs_dev_files(struct pci_dev *pdev); +extern int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, + unsigned long size, unsigned long align, + unsigned long min, unsigned int type_mask, + void (*alignf)(void *, struct resource *, + unsigned long, unsigned long), + void *alignf_data); +/* PCI /proc functions */ +#ifdef CONFIG_PROC_FS +extern int pci_proc_attach_device(struct pci_dev *dev); +extern int pci_proc_detach_device(struct pci_dev *dev); +extern int pci_proc_attach_bus(struct pci_bus *bus); +extern int pci_proc_detach_bus(struct pci_bus *bus); +#else +static inline int pci_proc_attach_device(struct pci_dev *dev) { return 0; } +static inline int pci_proc_detach_device(struct pci_dev *dev) { return 0; } +static inline int pci_proc_attach_bus(struct pci_bus *bus) { return 0; } +static inline int pci_proc_detach_bus(struct pci_bus *bus) { return 0; } +#endif + +/* Functions for PCI Hotplug drivers to use */ +extern struct pci_bus * pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr); +extern unsigned int pci_do_scan_bus(struct pci_bus *bus); +extern int pci_remove_device_safe(struct pci_dev *dev); +extern unsigned char pci_max_busnr(void); +extern unsigned char pci_bus_max_busnr(struct pci_bus *bus); +extern int pci_bus_find_capability (struct pci_bus *bus, unsigned int devfn, int cap); +extern struct pci_bus *pci_find_bus(unsigned char busnr); + +struct pci_dev_wrapped { + struct pci_dev *dev; + void *data; +}; + +struct pci_bus_wrapped { + struct pci_bus *bus; + void *data; +}; + +struct pci_visit { + int (* pre_visit_pci_bus) (struct pci_bus_wrapped *, + struct pci_dev_wrapped *); + int (* post_visit_pci_bus) (struct pci_bus_wrapped *, + struct pci_dev_wrapped *); + + int (* pre_visit_pci_dev) (struct pci_dev_wrapped *, + struct pci_bus_wrapped *); + int (* visit_pci_dev) (struct pci_dev_wrapped *, + struct pci_bus_wrapped *); + int (* post_visit_pci_dev) (struct pci_dev_wrapped *, + struct pci_bus_wrapped *); +}; + +extern int pci_visit_dev(struct pci_visit *fn, + struct pci_dev_wrapped *wrapped_dev, + struct pci_bus_wrapped *wrapped_parent); diff -Nru a/drivers/pci/pci.ids b/drivers/pci/pci.ids --- a/drivers/pci/pci.ids Mon Jun 9 23:16:13 2003 +++ b/drivers/pci/pci.ids Mon Jun 9 23:16:13 2003 @@ -3745,19 +3745,26 @@ 11fc Silicon Magic 11fd High Street Consultants 11fe Comtrol Corporation - 0001 RocketPort 8 Oct - 0002 RocketPort 8 Intf - 0003 RocketPort 16 Intf - 0004 RocketPort 32 Intf - 0005 RocketPort Octacable - 0006 RocketPort 8J - 0007 RocketPort 4-port - 0008 RocketPort 8-port - 0009 RocketPort 16-port - 000a RocketPort Plus Quadcable - 000b RocketPort Plus Octacable - 000c RocketPort 8-port Modem - 8015 RocketPort 4-port UART 16954 + 0001 Rocketport 32 port w/external I/F + 0002 Rocketport 8 port w/external I/F + 0003 Rocketport 16 port w/external I/F + 0004 Rocketport 4 port w/quad cable + 0005 Rocketport 8 port w/octa cable + 0006 Rocketport 8 port w/RJ11 connectors + 0007 Rocketport 4 port w/RJ11 connectors + 000a Rocketport Plus 4 port + 000b Rocketport Plus 8 port + 000c RocketModem 6 port + 000d RocketModem 4-port + 000e Rocketport Plus 2 port RS232 + 000f Rocketport Plus 2 port RS422 + 0801 Rocketport UPCI 32 port w/external I/F + 0802 Rocketport UPCI 8 port w/external I/F + 0803 Rocketport UPCI 16 port w/external I/F + 0805 Rocketport UPCI 8 port w/octa cable + 080C RocketModem III 8 port + 080D RocketModem III 4 port + 0903 Rocketport Compact PCI 16 port w/external I/F 11ff Scion Corporation 1200 CSS Corporation 1201 Vista Controls Corp diff -Nru a/drivers/pci/pool.c b/drivers/pci/pool.c --- a/drivers/pci/pool.c Mon Jun 9 23:16:18 2003 +++ b/drivers/pci/pool.c Mon Jun 9 23:16:18 2003 @@ -31,7 +31,7 @@ #define POOL_TIMEOUT_JIFFIES ((100 /* msec */ * HZ) / 1000) #define POOL_POISON_BYTE 0xa7 -DECLARE_MUTEX (pools_lock); +static DECLARE_MUTEX (pools_lock); static ssize_t show_pools (struct device *dev, char *buf) diff -Nru a/drivers/pci/probe.c b/drivers/pci/probe.c --- a/drivers/pci/probe.c Mon Jun 9 23:16:15 2003 +++ b/drivers/pci/probe.c Mon Jun 9 23:16:15 2003 @@ -396,7 +396,7 @@ * Returns 0 on success and -1 if unknown type of device (not normal, bridge * or CardBus). */ -int pci_setup_device(struct pci_dev * dev) +static int pci_setup_device(struct pci_dev * dev) { u32 class; @@ -517,6 +517,7 @@ /* Assume 32-bit PCI; let 64-bit PCI cards (which are far rarer) set this higher, assuming the system even supports it. */ dev->dma_mask = 0xffffffff; + dev->consistent_dma_mask = 0xffffffff; if (pci_setup_device(dev) < 0) { kfree(dev); return NULL; @@ -641,7 +642,7 @@ return 0; } -struct pci_bus * __devinit pci_alloc_primary_bus_parented(struct device *parent, int bus) +static struct pci_bus * __devinit pci_alloc_primary_bus_parented(struct device *parent, int bus) { struct pci_bus *b; @@ -688,11 +689,9 @@ } EXPORT_SYMBOL(pci_scan_bus_parented); -EXPORT_SYMBOL(pci_devices); EXPORT_SYMBOL(pci_root_buses); #ifdef CONFIG_HOTPLUG -EXPORT_SYMBOL(pci_setup_device); EXPORT_SYMBOL(pci_add_new_bus); EXPORT_SYMBOL(pci_do_scan_bus); EXPORT_SYMBOL(pci_scan_slot); diff -Nru a/drivers/pci/proc.c b/drivers/pci/proc.c --- a/drivers/pci/proc.c Mon Jun 9 23:16:14 2003 +++ b/drivers/pci/proc.c Mon Jun 9 23:16:14 2003 @@ -581,13 +581,13 @@ { if (pci_present()) { struct proc_dir_entry *entry; - struct pci_dev *dev; + struct pci_dev *dev = NULL; proc_bus_pci_dir = proc_mkdir("pci", proc_bus); entry = create_proc_entry("devices", 0, proc_bus_pci_dir); if (entry) entry->proc_fops = &proc_bus_pci_dev_operations; proc_initialized = 1; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { pci_proc_attach_device(dev); } legacy_proc_init(); @@ -599,7 +599,6 @@ #ifdef CONFIG_HOTPLUG EXPORT_SYMBOL(pci_proc_attach_device); -EXPORT_SYMBOL(pci_proc_detach_device); EXPORT_SYMBOL(pci_proc_attach_bus); EXPORT_SYMBOL(pci_proc_detach_bus); EXPORT_SYMBOL(proc_bus_pci_dir); diff -Nru a/drivers/pci/search.c b/drivers/pci/search.c --- a/drivers/pci/search.c Mon Jun 9 23:16:05 2003 +++ b/drivers/pci/search.c Mon Jun 9 23:16:05 2003 @@ -55,9 +55,9 @@ struct pci_dev * pci_find_slot(unsigned int bus, unsigned int devfn) { - struct pci_dev *dev; + struct pci_dev *dev = NULL; - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { if (dev->bus->number == bus && dev->devfn == devfn) return dev; } @@ -118,6 +118,34 @@ /** + * pci_find_device_reverse - begin or continue searching for a PCI device by vendor/device id + * @vendor: PCI vendor id to match, or %PCI_ANY_ID to match all vendor ids + * @device: PCI device id to match, or %PCI_ANY_ID to match all device ids + * @from: Previous PCI device found in search, or %NULL for new search. + * + * Iterates through the list of known PCI devices in the reverse order of pci_find_device(). + * If a PCI device is found with a matching @vendor and @device, a pointer to + * its device structure is returned. Otherwise, %NULL is returned. + * A new search is initiated by passing %NULL to the @from argument. + * Otherwise if @from is not %NULL, searches continue from previous device on the global list. + */ +struct pci_dev * +pci_find_device_reverse(unsigned int vendor, unsigned int device, const struct pci_dev *from) +{ + struct list_head *n = from ? from->global_list.prev : pci_devices.prev; + + while (n != &pci_devices) { + struct pci_dev *dev = pci_dev_g(n); + if ((vendor == PCI_ANY_ID || dev->vendor == vendor) && + (device == PCI_ANY_ID || dev->device == device)) + return dev; + n = n->prev; + } + return NULL; +} + + +/** * pci_find_class - begin or continue searching for a PCI device by class * @class: search for a PCI device with this class designation * @from: Previous PCI device found in search, or %NULL for new search. @@ -143,8 +171,20 @@ return NULL; } +/** + * pci_present - determine if there are any pci devices on this system + * + * Returns 0 if no pci devices are present, 1 if pci devices are present. + */ +int pci_present(void) +{ + return !list_empty(&pci_devices); +} + EXPORT_SYMBOL(pci_find_bus); EXPORT_SYMBOL(pci_find_class); EXPORT_SYMBOL(pci_find_device); +EXPORT_SYMBOL(pci_find_device_reverse); EXPORT_SYMBOL(pci_find_slot); EXPORT_SYMBOL(pci_find_subsys); +EXPORT_SYMBOL(pci_present); diff -Nru a/drivers/pci/setup-irq.c b/drivers/pci/setup-irq.c --- a/drivers/pci/setup-irq.c Mon Jun 9 23:16:11 2003 +++ b/drivers/pci/setup-irq.c Mon Jun 9 23:16:11 2003 @@ -64,8 +64,8 @@ pci_fixup_irqs(u8 (*swizzle)(struct pci_dev *, u8 *), int (*map_irq)(struct pci_dev *, u8, u8)) { - struct pci_dev *dev; - pci_for_each_dev(dev) { + struct pci_dev *dev = NULL; + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { pdev_fixup_irq(dev, swizzle, map_irq); } } diff -Nru a/drivers/pci/setup-res.c b/drivers/pci/setup-res.c --- a/drivers/pci/setup-res.c Mon Jun 9 23:16:18 2003 +++ b/drivers/pci/setup-res.c Mon Jun 9 23:16:18 2003 @@ -23,7 +23,7 @@ #include <linux/ioport.h> #include <linux/cache.h> #include <linux/slab.h> - +#include "pci.h" #define DEBUG_CONFIG 0 #if DEBUG_CONFIG diff -Nru a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c --- a/drivers/pcmcia/cs.c Mon Jun 9 23:16:08 2003 +++ b/drivers/pcmcia/cs.c Mon Jun 9 23:16:08 2003 @@ -48,6 +48,7 @@ #include <linux/pm.h> #include <linux/pci.h> #include <linux/device.h> +#include <linux/suspend.h> #include <asm/system.h> #include <asm/irq.h> @@ -783,6 +784,9 @@ } schedule(); + if (current->flags & PF_FREEZE) + refrigerator(PF_IOTHREAD); + if (!skt->thread) break; } diff -Nru a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c --- a/drivers/pcmcia/ds.c Mon Jun 9 23:16:16 2003 +++ b/drivers/pcmcia/ds.c Mon Jun 9 23:16:16 2003 @@ -182,50 +182,6 @@ } EXPORT_SYMBOL(pcmcia_unregister_driver); - -int register_pccard_driver(dev_info_t *dev_info, - dev_link_t *(*attach)(void), - void (*detach)(dev_link_t *)) -{ - struct pcmcia_driver *driver; - - DEBUG(0, "ds: register_pccard_driver('%s')\n", (char *)dev_info); - driver = get_pcmcia_driver(dev_info); - if (driver) - return -EBUSY; - - driver = kmalloc(sizeof(struct pcmcia_driver), GFP_KERNEL); - if (!driver) return -ENOMEM; - memset(driver, 0, sizeof(struct pcmcia_driver)); - driver->drv.name = (char *)dev_info; - pcmcia_register_driver(driver); - - driver->attach = attach; - driver->detach = detach; - - return 0; -} /* register_pccard_driver */ - -/*====================================================================*/ - -int unregister_pccard_driver(dev_info_t *dev_info) -{ - struct pcmcia_driver *driver; - - DEBUG(0, "ds: unregister_pccard_driver('%s')\n", - (char *)dev_info); - - driver = get_pcmcia_driver(dev_info); - if (!driver) - return -ENODEV; - - pcmcia_unregister_driver(driver); - kfree(driver); - return 0; -} /* unregister_pccard_driver */ - -/*====================================================================*/ - #ifdef CONFIG_PROC_FS static int proc_read_drivers_callback(struct device_driver *driver, void *d) { @@ -875,11 +831,6 @@ .write = ds_write, .poll = ds_poll, }; - -EXPORT_SYMBOL(register_pccard_driver); -EXPORT_SYMBOL(unregister_pccard_driver); - -/*====================================================================*/ static int __devinit pcmcia_bus_add_socket(struct device *dev, unsigned int socket_nr) { diff -Nru a/drivers/pcmcia/pci_socket.c b/drivers/pcmcia/pci_socket.c --- a/drivers/pcmcia/pci_socket.c Mon Jun 9 23:16:19 2003 +++ b/drivers/pcmcia/pci_socket.c Mon Jun 9 23:16:19 2003 @@ -196,9 +196,9 @@ pci_socket_t *socket = pci_get_drvdata(dev); /* note: we are already unregistered from the cs core */ + class_device_unregister(&socket->cls_d.class_dev); if (socket->op && socket->op->close) socket->op->close(socket); - class_device_unregister(&socket->cls_d.class_dev); pci_set_drvdata(dev, NULL); } diff -Nru a/drivers/pnp/pnpbios/proc.c b/drivers/pnp/pnpbios/proc.c --- a/drivers/pnp/pnpbios/proc.c Mon Jun 9 23:16:19 2003 +++ b/drivers/pnp/pnpbios/proc.c Mon Jun 9 23:16:19 2003 @@ -29,6 +29,8 @@ #include <linux/pnpbios.h> #include <linux/init.h> +#include <asm/uaccess.h> + static struct proc_dir_entry *proc_pnp = NULL; static struct proc_dir_entry *proc_pnp_boot = NULL; @@ -178,18 +180,31 @@ struct pnp_bios_node *node; int boot = (long)data >> 8; u8 nodenum = (long)data; + int ret = count; node = pnpbios_kmalloc(node_info.max_node_size, GFP_KERNEL); - if (!node) return -ENOMEM; - if ( pnp_bios_get_dev_node(&nodenum, boot, node) ) - return -EIO; - if (count != node->size - sizeof(struct pnp_bios_node)) - return -EINVAL; - memcpy(node->data, buf, count); - if (pnp_bios_set_dev_node(node->handle, boot, node) != 0) - return -EINVAL; + if (!node) + return -ENOMEM; + if (pnp_bios_get_dev_node(&nodenum, boot, node)) { + ret = -EIO; + goto out; + } + if (count != node->size - sizeof(struct pnp_bios_node)) { + ret = -EINVAL; + goto out; + } + if (copy_from_user(node->data, buf, count)) { + ret = -EFAULT; + goto out; + } + if (pnp_bios_set_dev_node(node->handle, boot, node) != 0) { + ret = -EINVAL; + goto out; + } + ret = count; +out: kfree(node); - return count; + return ret; } int pnpbios_interface_attach_device(struct pnp_bios_node * node) diff -Nru a/drivers/pnp/resource.c b/drivers/pnp/resource.c --- a/drivers/pnp/resource.c Mon Jun 9 23:16:14 2003 +++ b/drivers/pnp/resource.c Mon Jun 9 23:16:14 2003 @@ -455,8 +455,8 @@ #ifdef CONFIG_PCI /* check if the resource is being used by a pci device */ if (!pnp_skip_pci_scan) { - struct pci_dev * pci; - pci_for_each_dev(pci) { + struct pci_dev * pci = NULL; + while ((pci = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci)) != NULL) { if (pci->irq == *irq) return CONFLICT_TYPE_PCI; } diff -Nru a/drivers/s390/net/ctctty.c b/drivers/s390/net/ctctty.c --- a/drivers/s390/net/ctctty.c Mon Jun 9 23:16:13 2003 +++ b/drivers/s390/net/ctctty.c Mon Jun 9 23:16:13 2003 @@ -28,9 +28,7 @@ #include <linux/serial_reg.h> #include <linux/interrupt.h> #include <asm/uaccess.h> -#ifdef CONFIG_DEVFS_FS -# include <linux/devfs_fs_kernel.h> -#endif +#include <linux/devfs_fs_kernel.h> #include "ctctty.h" #define CTC_TTY_MAJOR 43 @@ -48,7 +46,6 @@ #define CTC_ASYNC_SPLIT_TERMIOS 0x0008 /* Sep. termios for dialin/out */ #define CTC_TTY_XMIT_SIZE 1024 /* Default bufsize for write */ #define CTC_SERIAL_XMIT_MAX 4000 /* Maximum bufsize for write */ -#define CTC_SERIAL_TYPE_NORMAL 1 /* Private data (similar to async_struct in <linux/serial.h>) */ typedef struct { @@ -90,12 +87,6 @@ #define CTC_TTY_NAME "ctctty" -#ifdef CONFIG_DEVFS_FS -static char *ctc_ttyname = "ctc/" CTC_TTY_NAME "%d"; -#else -static char *ctc_ttyname = CTC_TTY_NAME; -#endif - static __u32 ctc_tty_magic = CTC_ASYNC_MAGIC; static int ctc_tty_shuttingdown = 0; @@ -1171,12 +1162,13 @@ device = &driver->ctc_tty_device; device->magic = TTY_DRIVER_MAGIC; - device->name = ctc_ttyname; + device->devfs_name = "ctc/" CTC_TTY_NAME; + device->name = CTC_TTY_NAME; device->major = CTC_TTY_MAJOR; device->minor_start = 0; device->num = CTC_TTY_MAX_DEVICES; device->type = TTY_DRIVER_TYPE_SERIAL; - device->subtype = CTC_SERIAL_TYPE_NORMAL; + device->subtype = SERIAL_TYPE_NORMAL; device->init_termios = tty_std_termios; device->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; device->flags = TTY_DRIVER_REAL_RAW; diff -Nru a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c --- a/drivers/s390/net/lcs.c Mon Jun 9 23:16:07 2003 +++ b/drivers/s390/net/lcs.c Mon Jun 9 23:16:07 2003 @@ -1751,30 +1751,29 @@ #ifdef CONFIG_NET_ETHERNET case LCS_FRAME_TYPE_ENET: card->lan_type_trans = eth_type_trans; - dev = init_etherdev(NULL,0); + dev = alloc_etherdev(0); break; #endif #ifdef CONFIG_TR case LCS_FRAME_TYPE_TR: card->lan_type_trans = tr_type_trans; - dev = init_trdev(NULL,0); + dev = alloc_trdev(0); break; #endif #ifdef CONFIG_FDDI case LCS_FRAME_TYPE_FDDI: card->lan_type_trans = fddi_type_trans; - dev = init_fddidev(NULL,0); + dev = alloc_fddidev(0); break; #endif default: LCS_DBF_TEXT(3, setup, "errinit"); PRINT_ERR("LCS: Initialization failed\n"); PRINT_ERR("LCS: No device found!\n"); - lcs_cleanup_channel(&card->read); - lcs_cleanup_channel(&card->write); - lcs_free_card(card); - return -ENODEV; + goto out; } + if (!dev) + goto out; memcpy(dev->dev_addr, card->mac, LCS_MAC_LENGTH); card->dev = dev; dev->priv = card; @@ -1787,9 +1786,16 @@ #endif dev->get_stats = lcs_getstats; SET_MODULE_OWNER(&tun->dev); + if (register_netdev(dev) != 0) + goto out; netif_stop_queue(dev); lcs_stopcard(card); return 0; +out: + lcs_cleanup_channel(&card->read); + lcs_cleanup_channel(&card->write); + lcs_free_card(card); + return -ENODEV; } /** diff -Nru a/drivers/sbus/char/aurora.c b/drivers/sbus/char/aurora.c --- a/drivers/sbus/char/aurora.c Mon Jun 9 23:16:07 2003 +++ b/drivers/sbus/char/aurora.c Mon Jun 9 23:16:07 2003 @@ -85,8 +85,6 @@ #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif -#define AURORA_TYPE_NORMAL 1 - static struct tty_driver aurora_driver; static struct Aurora_board aurora_board[AURORA_NBOARD] = { {0,}, @@ -661,8 +659,7 @@ if (mcr & MCR_CDCHG) { if (sbus_readb(&bp->r[chip]->r[CD180_MSVR]) & MSVR_CD) wake_up_interruptible(&port->open_wait); - else if (!((port->flags & ASYNC_CALLOUT_ACTIVE) && - (port->flags & ASYNC_CALLOUT_NOHUP))) + else schedule_task(&port->tqueue_hangup); } @@ -1334,19 +1331,12 @@ */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { - if (port->flags & ASYNC_CALLOUT_ACTIVE) - return -EBUSY; port->flags |= ASYNC_NORMAL_ACTIVE; return 0; } - if (port->flags & ASYNC_CALLOUT_ACTIVE) { - if (port->normal_termios.c_cflag & CLOCAL) - do_clocal = 1; - } else { - if (C_CLOCAL(tty)) - do_clocal = 1; - } + if (C_CLOCAL(tty)) + do_clocal = 1; /* Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). While we are in @@ -1367,13 +1357,10 @@ &bp->r[chip]->r[CD180_CAR]); udelay(1); CD = sbus_readb(&bp->r[chip]->r[CD180_MSVR]) & MSVR_CD; - if (!(port->flags & ASYNC_CALLOUT_ACTIVE)) { - port->MSVR=bp->RTS; + port->MSVR=bp->RTS; - /* auto drops DTR */ - sbus_writeb(port->MSVR, - &bp->r[chip]->r[CD180_MSVR]); - } + /* auto drops DTR */ + sbus_writeb(port->MSVR, &bp->r[chip]->r[CD180_MSVR]); sti(); set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || @@ -1384,8 +1371,7 @@ retval = -ERESTARTSYS; break; } - if (/*!(port->flags & ASYNC_CALLOUT_ACTIVE) &&*/ - !(port->flags & ASYNC_CLOSING) && + if (!(port->flags & ASYNC_CLOSING) && (do_clocal || CD)) break; if (signal_pending(current)) { @@ -1465,8 +1451,6 @@ restore_flags(flags); } - port->session = current->session; - port->pgrp = current->pgrp; #ifdef AURORA_DEBUG printk("aurora_open: end\n"); #endif @@ -1520,8 +1504,6 @@ */ if (port->flags & ASYNC_NORMAL_ACTIVE) port->normal_termios = *tty->termios; -/* if (port->flags & ASYNC_CALLOUT_ACTIVE) - port->callout_termios = *tty->termios;*/ /* Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. @@ -1578,8 +1560,7 @@ } wake_up_interruptible(&port->open_wait); } - port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| - ASYNC_CLOSING); + port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&port->close_wait); restore_flags(flags); #ifdef AURORA_DEBUG @@ -2223,7 +2204,7 @@ aurora_shutdown_port(bp, port); port->event = 0; port->count = 0; - port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + port->flags &= ~ASYNC_NORMAL_ACTIVE; port->tty = 0; wake_up_interruptible(&port->open_wait); #ifdef AURORA_DEBUG @@ -2310,7 +2291,7 @@ aurora_driver.major = AURORA_MAJOR; aurora_driver.num = AURORA_TNPORTS; aurora_driver.type = TTY_DRIVER_TYPE_SERIAL; - aurora_driver.subtype = AURORA_TYPE_NORMAL; + aurora_driver.subtype = SERIAL_TYPE_NORMAL; aurora_driver.init_termios = tty_std_termios; aurora_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; diff -Nru a/drivers/sbus/char/aurora.h b/drivers/sbus/char/aurora.h --- a/drivers/sbus/char/aurora.h Mon Jun 9 23:16:16 2003 +++ b/drivers/sbus/char/aurora.h Mon Jun 9 23:16:16 2003 @@ -247,8 +247,6 @@ long event; int timeout; int close_delay; - long session; - long pgrp; unsigned char * xmit_buf; int custom_divisor; int xmit_head; diff -Nru a/drivers/sbus/char/bbc_envctrl.c b/drivers/sbus/char/bbc_envctrl.c --- a/drivers/sbus/char/bbc_envctrl.c Mon Jun 9 23:16:10 2003 +++ b/drivers/sbus/char/bbc_envctrl.c Mon Jun 9 23:16:10 2003 @@ -571,12 +571,13 @@ set_fan_speeds(fp); } -void bbc_envctrl_init(void) +int bbc_envctrl_init(void) { struct linux_ebus_child *echild; int temp_index = 0; int fan_index = 0; int devidx = 0; + int err = 0; while ((echild = bbc_i2c_getdev(devidx++)) != NULL) { if (!strcmp(echild->prom_name, "temperature")) @@ -585,7 +586,8 @@ attach_one_fan(echild, fan_index++); } if (temp_index != 0 && fan_index != 0) - kernel_thread(kenvctrld, NULL, CLONE_FS | CLONE_FILES); + err = kernel_thread(kenvctrld, NULL, CLONE_FS | CLONE_FILES); + return err; } static void destroy_one_temp(struct bbc_cpu_temperature *tp) diff -Nru a/drivers/sbus/char/bbc_i2c.c b/drivers/sbus/char/bbc_i2c.c --- a/drivers/sbus/char/bbc_i2c.c Mon Jun 9 23:16:16 2003 +++ b/drivers/sbus/char/bbc_i2c.c Mon Jun 9 23:16:16 2003 @@ -430,14 +430,15 @@ return 0; } -extern void bbc_envctrl_init(void); +extern int bbc_envctrl_init(void); extern void bbc_envctrl_cleanup(void); +static void bbc_i2c_cleanup(void); static int __init bbc_i2c_init(void) { struct linux_ebus *ebus = NULL; struct linux_ebus_device *edev = NULL; - int index = 0; + int err, index = 0; if (tlb_type != cheetah || !bbc_present()) return -ENODEV; @@ -454,11 +455,13 @@ if (!index) return -ENODEV; - bbc_envctrl_init(); - return 0; + err = bbc_envctrl_init(); + if (err) + bbc_i2c_cleanup(); + return err; } -static void __exit bbc_i2c_cleanup(void) +static void bbc_i2c_cleanup(void) { struct bbc_i2c_bus *bp = all_bbc_i2c; diff -Nru a/drivers/sbus/char/envctrl.c b/drivers/sbus/char/envctrl.c --- a/drivers/sbus/char/envctrl.c Mon Jun 9 23:16:08 2003 +++ b/drivers/sbus/char/envctrl.c Mon Jun 9 23:16:08 2003 @@ -1053,7 +1053,7 @@ struct linux_ebus *ebus = NULL; struct linux_ebus_device *edev = NULL; struct linux_ebus_child *edev_child = NULL; - int i = 0; + int err, i = 0; for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { @@ -1108,9 +1108,11 @@ udelay(200); /* Register the device as a minor miscellaneous device. */ - if (misc_register(&envctrl_dev)) { + err = misc_register(&envctrl_dev); + if (err) { printk("envctrl: Unable to get misc minor %d\n", envctrl_dev.minor); + goto out_iounmap; } /* Note above traversal routine post-incremented 'i' to accommodate @@ -1125,9 +1127,21 @@ i2c_childlist[i].addr, (0 == i) ? ("\n") : (" ")); } - kernel_thread(kenvctrld, NULL, CLONE_FS | CLONE_FILES); + err = kernel_thread(kenvctrld, NULL, CLONE_FS | CLONE_FILES); + if (err) + goto out_deregister; return 0; + +out_deregister: + misc_deregister(&envctrl_dev); +out_iounmap: + iounmap(i2c); + for (i = 0; i < ENVCTRL_MAX_CPU * 2; i++) { + if (i2c_childlist[i].tables) + kfree(i2c_childlist[i].tables); + } + return err; #else return -ENODEV; #endif diff -Nru a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c --- a/drivers/scsi/3w-xxxx.c Mon Jun 9 23:16:18 2003 +++ b/drivers/scsi/3w-xxxx.c Mon Jun 9 23:16:18 2003 @@ -2497,7 +2497,8 @@ } /* End tw_scsi_eh_reset() */ /* This function handles input and output from /proc/scsi/3w-xxxx/x */ -int tw_scsi_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout) +int tw_scsi_proc_info(struct Scsi_Host *shost, char *buffer, char **start, + off_t offset, int length, int inout) { TW_Device_Extension *tw_dev = NULL; TW_Info info; @@ -2508,7 +2509,7 @@ /* Find the correct device extension */ for (i=0;i<tw_device_extension_count;i++) - if (tw_device_extension_list[i]->host->host_no == hostno) + if (tw_device_extension_list[i]->host->host_no == shost->host_no) tw_dev = tw_device_extension_list[i]; if (tw_dev == NULL) { printk(KERN_WARNING "3w-xxxx: tw_scsi_proc_info(): Couldn't locate device extension.\n"); @@ -2544,7 +2545,7 @@ if (start) { *start = buffer; } - tw_copy_info(&info, "scsi%d: 3ware Storage Controller\n", hostno); + tw_copy_info(&info, "scsi%d: 3ware Storage Controller\n", shost->host_no); tw_copy_info(&info, "Driver version: %s\n", tw_driver_version); tw_copy_info(&info, "Current commands posted: %3d\n", tw_dev->posted_request_count); tw_copy_info(&info, "Max commands posted: %3d\n", tw_dev->max_posted_request_count); diff -Nru a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h --- a/drivers/scsi/3w-xxxx.h Mon Jun 9 23:16:08 2003 +++ b/drivers/scsi/3w-xxxx.h Mon Jun 9 23:16:08 2003 @@ -474,7 +474,6 @@ int tw_scsi_detect(Scsi_Host_Template *tw_host); int tw_scsi_eh_abort(Scsi_Cmnd *SCpnt); int tw_scsi_eh_reset(Scsi_Cmnd *SCpnt); -int tw_scsi_proc_info(char *buffer, char **start, off_t offset, int length, int inode, int inout); int tw_scsi_queue(Scsi_Cmnd *cmd, void (*done) (Scsi_Cmnd *)); int tw_scsi_release(struct Scsi_Host *tw_host); int tw_scsiop_inquiry(TW_Device_Extension *tw_dev, int request_id); diff -Nru a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c --- a/drivers/scsi/53c700.c Mon Jun 9 23:16:08 2003 +++ b/drivers/scsi/53c700.c Mon Jun 9 23:16:08 2003 @@ -124,6 +124,7 @@ #include <linux/spinlock.h> #include <linux/completion.h> #include <linux/sched.h> +#include <linux/init.h> #include <linux/proc_fs.h> #include <asm/dma.h> #include <asm/system.h> @@ -167,12 +168,14 @@ STATIC int NCR_700_bus_reset(Scsi_Cmnd * SCpnt); STATIC int NCR_700_dev_reset(Scsi_Cmnd * SCpnt); STATIC int NCR_700_host_reset(Scsi_Cmnd * SCpnt); -STATIC int NCR_700_proc_directory_info(char *, char **, off_t, int, int, int); +STATIC int NCR_700_proc_directory_info(struct Scsi_Host *, char *, char **, off_t, int, int); STATIC void NCR_700_chip_setup(struct Scsi_Host *host); STATIC void NCR_700_chip_reset(struct Scsi_Host *host); STATIC int NCR_700_slave_configure(Scsi_Device *SDpnt); STATIC void NCR_700_slave_destroy(Scsi_Device *SDpnt); +static struct device_attribute **NCR_700_dev_attrs = NULL; + static char *NCR_700_phase[] = { "", "after selection", @@ -247,6 +250,9 @@ static int banner = 0; int j; + if(tpnt->sdev_attrs == NULL) + tpnt->sdev_attrs = NCR_700_dev_attrs; + memory = dma_alloc_noncoherent(hostdata->dev, TOTAL_MEM_SIZE, &pScript, GFP_KERNEL); if(memory == NULL) { @@ -1703,23 +1709,15 @@ return IRQ_RETVAL(handled); } -/* FIXME: Need to put some proc information in and plumb it - * into the scsi proc system */ STATIC int -NCR_700_proc_directory_info(char *proc_buf, char **startp, - off_t offset, int bytes_available, - int host_no, int write) +NCR_700_proc_directory_info(struct Scsi_Host *host, char *proc_buf, char **startp, + off_t offset, int bytes_available, int write) { static char buf[4096]; /* 1 page should be sufficient */ int len = 0; - struct Scsi_Host *host; struct NCR_700_Host_Parameters *hostdata; Scsi_Device *SDp; - host = scsi_host_hn_get(host_no); - if(host == NULL) - return 0; - if(write) { /* FIXME: Clear internal statistics here */ return 0; @@ -2023,6 +2021,56 @@ /* to do here: deallocate memory */ } +static ssize_t +NCR_700_store_queue_depth(struct device *dev, const char *buf, size_t count) +{ + int depth; + + struct scsi_device *SDp = to_scsi_device(dev); + depth = simple_strtoul(buf, NULL, 0); + if(depth > NCR_700_MAX_TAGS) + return -EINVAL; + scsi_adjust_queue_depth(SDp, MSG_ORDERED_TAG, depth); + + return count; +} + +static ssize_t +NCR_700_show_active_tags(struct device *dev, char *buf) +{ + struct scsi_device *SDp = to_scsi_device(dev); + + return snprintf(buf, 20, "%d\n", NCR_700_get_depth(SDp)); +} + +static struct device_attribute NCR_700_queue_depth_attr = { + .attr = { + .name = "queue_depth", + .mode = S_IWUSR, + }, + .store = NCR_700_store_queue_depth, +}; + +static struct device_attribute NCR_700_active_tags_attr = { + .attr = { + .name = "active_tags", + .mode = S_IRUGO, + }, + .show = NCR_700_show_active_tags, +}; + +STATIC int __init +NCR_700_init(void) +{ + scsi_sysfs_modify_sdev_attribute(&NCR_700_dev_attrs, + &NCR_700_queue_depth_attr); + scsi_sysfs_modify_sdev_attribute(&NCR_700_dev_attrs, + &NCR_700_active_tags_attr); + return 0; +} + EXPORT_SYMBOL(NCR_700_detect); EXPORT_SYMBOL(NCR_700_release); EXPORT_SYMBOL(NCR_700_intr); + +module_init(NCR_700_init); diff -Nru a/drivers/scsi/AM53C974.c b/drivers/scsi/AM53C974.c --- a/drivers/scsi/AM53C974.c Mon Jun 9 23:16:12 2003 +++ b/drivers/scsi/AM53C974.c Mon Jun 9 23:16:12 2003 @@ -732,6 +732,12 @@ hostdata->disconnecting = 0; hostdata->dma_busy = 0; + if (!request_region (instance->io_port, 128, "AM53C974")) { + printk ("AM53C974 (scsi%d): Could not get IO region %04lx.\n", + instance->host_no, instance->io_port); + scsi_unregister(instance); + return 0; + } /* Set up an interrupt handler if we aren't already sharing an IRQ with another board */ for (search = first_host; search && (((the_template != NULL) && (search->hostt != the_template)) || @@ -2442,6 +2448,7 @@ static int AM53C974_release(struct Scsi_Host *shp) { free_irq(shp->irq, shp); + release_region(shp->io_port, 128); scsi_unregister(shp); return 0; } diff -Nru a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c --- a/drivers/scsi/BusLogic.c Mon Jun 9 23:16:19 2003 +++ b/drivers/scsi/BusLogic.c Mon Jun 9 23:16:19 2003 @@ -4327,9 +4327,9 @@ BugLogic_ProcDirectoryInfo implements /proc/scsi/BusLogic/<N>. */ -int BusLogic_ProcDirectoryInfo(char *ProcBuffer, char **StartPointer, +int BusLogic_ProcDirectoryInfo(struct Scsi_Host *shost, char *ProcBuffer, char **StartPointer, off_t Offset, int BytesAvailable, - int HostNumber, int WriteFlag) + int WriteFlag) { BusLogic_HostAdapter_T *HostAdapter; BusLogic_TargetStatistics_T *TargetStatistics; @@ -4338,11 +4338,11 @@ for (HostAdapter = BusLogic_FirstRegisteredHostAdapter; HostAdapter != NULL; HostAdapter = HostAdapter->Next) - if (HostAdapter->HostNumber == HostNumber) break; + if (HostAdapter->HostNumber == shost->host_no) break; if (HostAdapter == NULL) { BusLogic_Error("Cannot find Host Adapter for SCSI Host %d\n", - NULL, HostNumber); + NULL, shost->host_no); return 0; } TargetStatistics = HostAdapter->TargetStatistics; diff -Nru a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h --- a/drivers/scsi/BusLogic.h Mon Jun 9 23:16:11 2003 +++ b/drivers/scsi/BusLogic.h Mon Jun 9 23:16:11 2003 @@ -56,7 +56,7 @@ void (*CompletionRoutine)(SCSI_Command_T *)); extern int BusLogic_BIOSDiskParameters(struct scsi_device *, struct block_device *, sector_t, int *); -extern int BusLogic_ProcDirectoryInfo(char *, char **, off_t, int, int, int); +extern int BusLogic_ProcDirectoryInfo(struct Scsi_Host *, char *, char **, off_t, int, int); extern int BusLogic_SlaveConfigure(SCSI_Device_T *); #ifdef BusLogic_DriverVersion diff -Nru a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig --- a/drivers/scsi/Kconfig Mon Jun 9 23:16:18 2003 +++ b/drivers/scsi/Kconfig Mon Jun 9 23:16:18 2003 @@ -1559,7 +1559,7 @@ config SCSI_MESH tristate "MESH (Power Mac internal SCSI) support" - depends on ALL_PPC && SCSI + depends on PPC_PMAC && SCSI help Many Power Macintoshes and clones have a MESH (Macintosh Enhanced SCSI Hardware) SCSI bus adaptor (the 7200 doesn't, but all of the @@ -1590,7 +1590,7 @@ config SCSI_MAC53C94 tristate "53C94 (Power Mac external SCSI) support" - depends on ALL_PPC && SCSI + depends on PPC_PMAC && SCSI help On Power Macintoshes (and clones) with two SCSI buses, the external SCSI bus is usually controlled by a 53C94 SCSI bus adaptor. Older diff -Nru a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c --- a/drivers/scsi/NCR5380.c Mon Jun 9 23:16:08 2003 +++ b/drivers/scsi/NCR5380.c Mon Jun 9 23:16:08 2003 @@ -824,7 +824,7 @@ NCR5380_dprint(NDEBUG_ANY, instance); NCR5380_dprint_phase(NDEBUG_ANY, instance); - len = NCR5380_proc_info(pr_bfr, &start, 0, sizeof(pr_bfr), instance->host_no, 0); + len = NCR5380_proc_info(instance, pr_bfr, &start, 0, sizeof(pr_bfr), 0); pr_bfr[len] = 0; printk("\n%s\n", pr_bfr); } @@ -855,16 +855,12 @@ #ifndef NCR5380_proc_info static #endif -int NCR5380_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout) +int NCR5380_proc_info(struct Scsi_Host *instance, char *buffer, char **start, off_t offset, int length, int inout) { char *pos = buffer; - struct Scsi_Host *instance; struct NCR5380_hostdata *hostdata; Scsi_Cmnd *ptr; - instance = scsi_host_hn_get(hostno); - if (!instance) - return (-ESRCH); hostdata = (struct NCR5380_hostdata *) instance->hostdata; if (inout) { /* Has data been written to the file ? */ diff -Nru a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h --- a/drivers/scsi/NCR5380.h Mon Jun 9 23:16:13 2003 +++ b/drivers/scsi/NCR5380.h Mon Jun 9 23:16:13 2003 @@ -310,7 +310,10 @@ static int NCR5380_host_reset(Scsi_Cmnd * cmd); static int NCR5380_device_reset(Scsi_Cmnd * cmd); static int NCR5380_queue_command(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)); - +#ifdef NCR5380_proc_info +int NCR5380_proc_info(struct Scsi_Host *instance, char *buffer, char **start, +off_t offset, int length, int inout); +#endif static void NCR5380_reselect(struct Scsi_Host *instance); static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag); diff -Nru a/drivers/scsi/NCR53C9x.c b/drivers/scsi/NCR53C9x.c --- a/drivers/scsi/NCR53C9x.c Mon Jun 9 23:16:08 2003 +++ b/drivers/scsi/NCR53C9x.c Mon Jun 9 23:16:08 2003 @@ -890,24 +890,15 @@ } /* ESP proc filesystem code. */ -int esp_proc_info(char *buffer, char **start, off_t offset, int length, - int hostno, int inout) +int esp_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset, int length, + int inout) { - struct NCR_ESP *esp; + struct NCR_ESP *esp = (struct NCR_ESP *) SCpnt->device->host->hostdata; if(inout) return -EINVAL; /* not yet */ - - for_each_esp(esp) { - if(esp->ehost->host_no == hostno) - break; - } - if(!esp) - return -EINVAL; - if(start) *start = buffer; - return esp_host_info(esp, buffer, offset, length); } diff -Nru a/drivers/scsi/NCR53C9x.h b/drivers/scsi/NCR53C9x.h --- a/drivers/scsi/NCR53C9x.h Mon Jun 9 23:16:09 2003 +++ b/drivers/scsi/NCR53C9x.h Mon Jun 9 23:16:09 2003 @@ -664,6 +664,6 @@ extern int esp_command(Scsi_Cmnd *); extern int esp_abort(Scsi_Cmnd *); extern int esp_reset(Scsi_Cmnd *); -extern int esp_proc_info(char *buffer, char **start, off_t offset, int length, - int hostno, int inout); +extern int esp_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset, int length, + int inout); #endif /* !(NCR53C9X_H) */ diff -Nru a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c --- a/drivers/scsi/NCR_D700.c Mon Jun 9 23:16:07 2003 +++ b/drivers/scsi/NCR_D700.c Mon Jun 9 23:16:07 2003 @@ -385,6 +385,7 @@ static void __exit NCR_D700_exit(void) { mca_unregister_driver(&NCR_D700_driver); + scsi_sysfs_release_attributes(&NCR_D700_driver_template); } module_init(NCR_D700_init); diff -Nru a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c --- a/drivers/scsi/aacraid/linit.c Mon Jun 9 23:16:10 2003 +++ b/drivers/scsi/aacraid/linit.c Mon Jun 9 23:16:10 2003 @@ -137,7 +137,6 @@ static int aac_queuecommand(Scsi_Cmnd *, void (*CompletionRoutine)(Scsi_Cmnd *)); static int aac_biosparm(struct scsi_device *, struct block_device *, sector_t, int *); -static int aac_procinfo(char *, char **, off_t, int, int, int); static int aac_ioctl(Scsi_Device *, int, void *); static int aac_eh_abort(Scsi_Cmnd * cmd); static int aac_eh_device_reset(Scsi_Cmnd* cmd); @@ -616,7 +615,6 @@ static Scsi_Host_Template driver_template = { .module = THIS_MODULE, .name = "AAC", - .proc_info = aac_procinfo, .detect = aac_detect, .release = aac_release, .info = aac_driverinfo, @@ -682,35 +680,3 @@ #include "scsi_module.c" - -/** - * aac_procinfo - Implement /proc/scsi/<drivername>/<n> - * @proc_buffer: memory buffer for I/O - * @start_ptr: pointer to first valid data - * @offset: offset into file - * @bytes_available: space left - * @host_no: scsi host ident - * @write: direction of I/O - * - * Used to export driver statistics and other infos to the world outside - * the kernel using the proc file system. Also provides an interface to - * feed the driver with information. - * - * For reads - * - if offset > 0 return 0 - * - if offset == 0 write data to proc_buffer and set the start_ptr to - * beginning of proc_buffer, return the number of characters written. - * For writes - * - writes currently not supported, return 0 - * - * Bugs: Only offset zero is handled - */ - -static int aac_procinfo(char *proc_buffer, char **start_ptr,off_t offset, - int bytes_available, int host_no, int write) -{ - if(write || offset > 0) - return 0; - *start_ptr = proc_buffer; - return sprintf(proc_buffer, "%s %d\n", "Raid Controller, scsi hba number", host_no); -} diff -Nru a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c --- a/drivers/scsi/advansys.c Mon Jun 9 23:16:09 2003 +++ b/drivers/scsi/advansys.c Mon Jun 9 23:16:09 2003 @@ -4290,14 +4290,14 @@ * user just won't get all the available statistics. */ int -advansys_proc_info(char *buffer, char **start, off_t offset, int length, - int hostno, int inout) +advansys_proc_info(struct Scsi_Host *shost, char *buffer, char **start, + off_t offset, int length, int inout) { struct Scsi_Host *shp; asc_board_t *boardp; int i; char *cp; - int cplen; + int cplen; int cnt; int totcnt; int leftlen; @@ -4322,7 +4322,7 @@ /* Find the specified board. */ for (i = 0; i < asc_board_count; i++) { - if (asc_host[i]->host_no == hostno) { + if (asc_host[i]->host_no == shost->host_no) { break; } } @@ -4767,7 +4767,7 @@ scsi_set_device(shp, &pci_devp->dev); - /* Save a pointer to the Scsi_host of each board found. */ + /* Save a pointer to the Scsi_Host of each board found. */ asc_host[asc_board_count++] = shp; /* Initialize private per board data */ diff -Nru a/drivers/scsi/advansys.h b/drivers/scsi/advansys.h --- a/drivers/scsi/advansys.h Mon Jun 9 23:16:19 2003 +++ b/drivers/scsi/advansys.h Mon Jun 9 23:16:19 2003 @@ -55,14 +55,6 @@ int advansys_biosparam(struct scsi_device *, struct block_device *, sector_t, int[]); static int advansys_slave_configure(Scsi_Device *); -#ifdef CONFIG_PROC_FS -#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,3,28) -extern struct proc_dir_entry proc_scsi_advansys; -#endif /* version < v2.3.28 */ -int advansys_proc_info(char *, char **, off_t, int, int, int); -#else /* !defined(CONFIG_PROC_FS) */ -#define advansys_proc_info NULL -#endif /* !defined(CONFIG_PROC_FS) */ /* init/main.c setup function */ void advansys_setup(char *, int *); diff -Nru a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c --- a/drivers/scsi/aha152x.c Mon Jun 9 23:16:06 2003 +++ b/drivers/scsi/aha152x.c Mon Jun 9 23:16:06 2003 @@ -3734,26 +3734,18 @@ #define SPRINTF(args...) \ do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0) -static int aha152x_proc_info(char *buffer, char **start, - off_t offset, int length, int hostno, int inout) +static int aha152x_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start, + off_t offset, int length, int inout) { int i; char *pos = buffer; - struct Scsi_Host *shpnt; Scsi_Cmnd *ptr; unsigned long flags; int thislength; - for (i = 0, shpnt = (struct Scsi_Host *) NULL; i<ARRAY_SIZE(aha152x_host); i++) - if (aha152x_host[i] && aha152x_host[i]->host_no == hostno) - shpnt = aha152x_host[i]; - - if (!shpnt) - return -ESRCH; - DPRINTK(debug_procinfo, KERN_DEBUG "aha152x_proc_info: buffer=%p offset=%ld length=%d hostno=%d inout=%d\n", - buffer, offset, length, hostno, inout); + buffer, offset, length, shpnt->host_no, inout); if (inout) diff -Nru a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c --- a/drivers/scsi/aha1740.c Mon Jun 9 23:16:08 2003 +++ b/drivers/scsi/aha1740.c Mon Jun 9 23:16:08 2003 @@ -76,21 +76,15 @@ /* One for each IRQ level (9-15) */ static struct Scsi_Host * aha_host[8] = {NULL, }; -static int aha1740_proc_info(char *buffer, char **start, off_t offset, - int length, int hostno, int inout) +static int aha1740_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start, off_t offset, + int length, int inout) { int len; - struct Scsi_Host * shpnt; struct aha1740_hostdata *host; if (inout) return-ENOSYS; - for (len = 0; len < 8; len++) { - shpnt = aha_host[len]; - if (shpnt && shpnt->host_no == hostno) - break; - } host = HOSTDATA(shpnt); len = sprintf(buffer, "aha174x at IO:%lx, IRQ %d, SLOT %d.\n" @@ -108,7 +102,6 @@ if (len > length) len = length; return len; -} static int aha1740_makecode(unchar *sense, unchar *status) diff -Nru a/drivers/scsi/aha1740.h b/drivers/scsi/aha1740.h --- a/drivers/scsi/aha1740.h Mon Jun 9 23:16:14 2003 +++ b/drivers/scsi/aha1740.h Mon Jun 9 23:16:14 2003 @@ -156,7 +156,6 @@ static int aha1740_command(Scsi_Cmnd *); static int aha1740_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); static int aha1740_biosparam(struct scsi_device *, struct block_device *, sector_t, int *); -static int aha1740_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout); #define AHA1740_ECBS 32 #define AHA1740_SCATTER 16 diff -Nru a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h --- a/drivers/scsi/aic7xxx/aic79xx.h Mon Jun 9 23:16:15 2003 +++ b/drivers/scsi/aic7xxx/aic79xx.h Mon Jun 9 23:16:15 2003 @@ -37,7 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.h#89 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.h#90 $ * * $FreeBSD$ */ @@ -1225,20 +1225,20 @@ int seltime; /* - * Interrupt coalessing settings. + * Interrupt coalescing settings. */ -#define AHD_INT_COALESSING_TIMER_DEFAULT 250 /*us*/ -#define AHD_INT_COALESSING_MAXCMDS_DEFAULT 10 -#define AHD_INT_COALESSING_MAXCMDS_MAX 127 -#define AHD_INT_COALESSING_MINCMDS_DEFAULT 5 -#define AHD_INT_COALESSING_MINCMDS_MAX 127 -#define AHD_INT_COALESSING_THRESHOLD_DEFAULT 2000 -#define AHD_INT_COALESSING_STOP_THRESHOLD_DEFAULT 1000 - u_int int_coalessing_timer; - u_int int_coalessing_maxcmds; - u_int int_coalessing_mincmds; - u_int int_coalessing_threshold; - u_int int_coalessing_stop_threshold; +#define AHD_INT_COALESCING_TIMER_DEFAULT 250 /*us*/ +#define AHD_INT_COALESCING_MAXCMDS_DEFAULT 10 +#define AHD_INT_COALESCING_MAXCMDS_MAX 127 +#define AHD_INT_COALESCING_MINCMDS_DEFAULT 5 +#define AHD_INT_COALESCING_MINCMDS_MAX 127 +#define AHD_INT_COALESCING_THRESHOLD_DEFAULT 2000 +#define AHD_INT_COALESCING_STOP_THRESHOLD_DEFAULT 1000 + u_int int_coalescing_timer; + u_int int_coalescing_maxcmds; + u_int int_coalescing_mincmds; + u_int int_coalescing_threshold; + u_int int_coalescing_stop_threshold; uint16_t user_discenable;/* Disconnection allowed */ uint16_t user_tagenable;/* Tagged Queuing allowed */ @@ -1362,11 +1362,11 @@ int ahd_parse_cfgdata(struct ahd_softc *ahd, struct seeprom_config *sc); void ahd_intr_enable(struct ahd_softc *ahd, int enable); -void ahd_update_coalessing_values(struct ahd_softc *ahd, +void ahd_update_coalescing_values(struct ahd_softc *ahd, u_int timer, u_int maxcmds, u_int mincmds); -void ahd_enable_coalessing(struct ahd_softc *ahd, +void ahd_enable_coalescing(struct ahd_softc *ahd, int enable); void ahd_pause_and_flushwork(struct ahd_softc *ahd); int ahd_suspend(struct ahd_softc *ahd); @@ -1514,7 +1514,7 @@ #define AHD_SHOW_QUEUE 0x02000 #define AHD_SHOW_TQIN 0x04000 #define AHD_SHOW_SG 0x08000 -#define AHD_SHOW_INT_COALESSING 0x10000 +#define AHD_SHOW_INT_COALESCING 0x10000 #define AHD_DEBUG_SEQUENCER 0x20000 #endif void ahd_print_scb(struct scb *scb); diff -Nru a/drivers/scsi/aic7xxx/aic79xx.reg b/drivers/scsi/aic7xxx/aic79xx.reg --- a/drivers/scsi/aic7xxx/aic79xx.reg Mon Jun 9 23:16:18 2003 +++ b/drivers/scsi/aic7xxx/aic79xx.reg Mon Jun 9 23:16:18 2003 @@ -39,7 +39,7 @@ * * $FreeBSD$ */ -VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#67 $" +VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#69 $" /* * This file is processed by the aic7xxx_asm utility for use in assembling @@ -286,7 +286,7 @@ address 0x00B access_mode RW mask HOST_TQINPOS 0x80 /* Boundary at either 0 or 128 */ - mask ENINT_COALESS 0x40 /* Perform interrupt coalessing */ + mask ENINT_COALESCE 0x40 /* Perform interrupt coalescing */ } /* @@ -3704,28 +3704,28 @@ } /* - * The maximum amount of time to wait, when interrupt coalessing + * The maximum amount of time to wait, when interrupt coalescing * is enabled, before issueing a CMDCMPLT interrupt for a completed * command. */ - INT_COALESSING_TIMER { + INT_COALESCING_TIMER { size 2 } /* - * The maximum number of commands to coaless into a single interrupt. + * The maximum number of commands to coalesce into a single interrupt. * Actually the 2's complement of that value to simplify sequencer * code. */ - INT_COALESSING_MAXCMDS { + INT_COALESCING_MAXCMDS { size 1 } /* * The minimum number of commands still outstanding required - * to continue coalessing (2's complement of value). + * to continue coalescing (2's complement of value). */ - INT_COALESSING_MINCMDS { + INT_COALESCING_MINCMDS { size 1 } @@ -3737,9 +3737,9 @@ } /* - * The count of commands that have been coalessed. + * The count of commands that have been coalesced. */ - INT_COALESSING_CMDCOUNT { + INT_COALESCING_CMDCOUNT { size 1 } @@ -3842,10 +3842,15 @@ } SCB_LUN { size 1 - field LID 0xff + field LID 0xff } SCB_TASK_ATTRIBUTE { size 1 + /* + * Overloaded field for non-packetized + * ignore wide residue message handling. + */ + field SCB_XFERLEN_ODD 0x01 } SCB_CDB_LEN { size 1 diff -Nru a/drivers/scsi/aic7xxx/aic79xx.seq b/drivers/scsi/aic7xxx/aic79xx.seq --- a/drivers/scsi/aic7xxx/aic79xx.seq Mon Jun 9 23:16:17 2003 +++ b/drivers/scsi/aic7xxx/aic79xx.seq Mon Jun 9 23:16:17 2003 @@ -40,7 +40,7 @@ * $FreeBSD$ */ -VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#91 $" +VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#94 $" PATCH_ARG_LIST = "struct ahd_softc *ahd" PREFIX = "ahd_" @@ -212,44 +212,44 @@ qoutfifo_updated: /* * If there are more commands waiting to be dma'ed - * to the host, always coaless. Otherwise honor the + * to the host, always coalesce. Otherwise honor the * host's wishes. */ - cmp COMPLETE_DMA_SCB_HEAD[1], SCB_LIST_NULL jne coaless_by_count; - cmp COMPLETE_SCB_HEAD[1], SCB_LIST_NULL jne coaless_by_count; - test LOCAL_HS_MAILBOX, ENINT_COALESS jz issue_cmdcmplt; + cmp COMPLETE_DMA_SCB_HEAD[1], SCB_LIST_NULL jne coalesce_by_count; + cmp COMPLETE_SCB_HEAD[1], SCB_LIST_NULL jne coalesce_by_count; + test LOCAL_HS_MAILBOX, ENINT_COALESCE jz issue_cmdcmplt; /* * If we have relatively few commands outstanding, don't * bother waiting for another command to complete. */ - test CMDS_PENDING[1], 0xFF jnz coaless_by_count; + test CMDS_PENDING[1], 0xFF jnz coalesce_by_count; /* Add -1 so that jnc means <= not just < */ - add A, -1, INT_COALESSING_MINCMDS; + add A, -1, INT_COALESCING_MINCMDS; add NONE, A, CMDS_PENDING; jnc issue_cmdcmplt; /* - * If coalessing, only coaless up to the limit + * If coalescing, only coalesce up to the limit * provided by the host driver. */ -coaless_by_count: - mov A, INT_COALESSING_MAXCMDS; - add NONE, A, INT_COALESSING_CMDCOUNT; +coalesce_by_count: + mov A, INT_COALESCING_MAXCMDS; + add NONE, A, INT_COALESCING_CMDCOUNT; jc issue_cmdcmplt; /* * If the timer is not currently active, * fire it up. */ test INTCTL, SWTMINTMASK jz return; - bmov SWTIMER, INT_COALESSING_TIMER, 2; + bmov SWTIMER, INT_COALESCING_TIMER, 2; mvi CLRSEQINTSTAT, CLRSEQ_SWTMRTO; or INTCTL, SWTMINTEN|SWTIMER_START; and INTCTL, ~SWTMINTMASK ret; issue_cmdcmplt: mvi INTSTAT, CMDCMPLT; - clr INT_COALESSING_CMDCOUNT; + clr INT_COALESCING_CMDCOUNT; or INTCTL, SWTMINTMASK ret; BEGIN_CRITICAL; @@ -261,6 +261,15 @@ clr A; add CMDS_PENDING, 1; adc CMDS_PENDING[1], A; + if ((ahd->bugs & AHD_PKT_LUN_BUG) != 0) { + /* + * "Short Luns" are not placed into outgoing LQ + * packets in the correct byte order. Use a full + * sized lun field instead and fill it with the + * one byte of lun information we support. + */ + mov SCB_PKT_LUN[6], SCB_LUN; + } /* * The FIFO use count field is shared with the * tag set by the host so that our SCB dma engine @@ -324,7 +333,7 @@ mov CCSCBRAM, SCBPTR; or CCSCBRAM, A, SCBPTR[1]; mov NONE, SDSCB_QOFF; - inc INT_COALESSING_CMDCOUNT; + inc INT_COALESCING_CMDCOUNT; add CMDS_PENDING, -1; adc CMDS_PENDING[1], -1; cmp SCB_NEXT_COMPLETE[1], SCB_LIST_NULL je fill_qoutfifo_done; @@ -863,7 +872,8 @@ mvi REG0 call inb_next; cmp REG0, 0x01 jne mesgin_reject; test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 2; - test DATA_COUNT_ODD, 0x1 jz mesgin_done; + test SCB_TASK_ATTRIBUTE, SCB_XFERLEN_ODD jnz mesgin_done; + SET_SEQINTCODE(IGN_WIDE_RES) jmp mesgin_done; mesgin_proto_violation: @@ -1308,8 +1318,6 @@ bmov HADDR, CCSGRAM, 4; } bmov HCNT, CCSGRAM, 3; - test HCNT[0], 0x1 jz . + 2; - xor DATA_COUNT_ODD, 0x1; bmov SCB_RESIDUAL_DATACNT[3], CCSGRAM, 1; if ((ahd->flags & AHD_39BIT_ADDRESSING) != 0) { and HADDR[4], SG_HIGH_ADDR_BITS, SCB_RESIDUAL_DATACNT[3]; @@ -1325,8 +1333,6 @@ adc SCB_RESIDUAL_SGPTR[2],A; adc SCB_RESIDUAL_SGPTR[3],A; mov SINDEX, SCB_RESIDUAL_SGPTR[0]; - test DATA_COUNT_ODD, 0x1 jz . + 2; - or SINDEX, ODD_SEG; test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 3; or SINDEX, LAST_SEG; clr SG_STATE; @@ -1352,12 +1358,9 @@ */ load_first_seg: bmov HADDR, SCB_DATAPTR, 11; - and DATA_COUNT_ODD, 0x1, SCB_DATACNT[0]; and REG_ISR, ~SG_FULL_RESID, SCB_SGPTR[0]; test SCB_DATACNT[3], SG_LAST_SEG jz . + 2; or REG_ISR, LAST_SEG; - test DATA_COUNT_ODD, 0x1 jz . + 2; - or REG_ISR, ODD_SEG; mov SG_CACHE_PRE, REG_ISR; mvi DFCNTRL, (PRELOADEN|SCSIEN|HDMAEN); /* @@ -1507,7 +1510,7 @@ * send Ignore Wide Residue messages for data-in phases. test DFCNTRL, DIRECTION jz target_ITloop; test SSTAT1, REQINIT jnz .; - test DATA_COUNT_ODD, 0x1 jz target_ITloop; + test SCB_TASK_ATTRIBUTE, SCB_XFERLEN_ODD jz target_ITloop; SET_MODE(M_SCSI, M_SCSI) test NEGCONOPTS, WIDEXFER jz target_ITloop; */ @@ -1577,9 +1580,6 @@ adc SCB_RESIDUAL_SGPTR[3], -1; sgptr_fixup_done: and SCB_RESIDUAL_SGPTR[0], SG_ADDR_MASK, SG_CACHE_SHADOW; - clr DATA_COUNT_ODD; - test SG_CACHE_SHADOW, ODD_SEG jz . + 2; - or DATA_COUNT_ODD, 0x1; clr SCB_RESIDUAL_DATACNT[3]; /* We are not the last seg */ bmov SCB_RESIDUAL_DATACNT, SHCNT, 3 ret; diff -Nru a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c --- a/drivers/scsi/aic7xxx/aic79xx_core.c Mon Jun 9 23:16:05 2003 +++ b/drivers/scsi/aic7xxx/aic79xx_core.c Mon Jun 9 23:16:05 2003 @@ -37,7 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#190 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#194 $ * * $FreeBSD$ */ @@ -4401,7 +4401,7 @@ sgptr = ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR); if ((sgptr & SG_LIST_NULL) != 0 - && ahd_inb(ahd, DATA_COUNT_ODD) == 1) { + && (ahd_inb(ahd, SCB_TASK_ATTRIBUTE) & SCB_XFERLEN_ODD) != 0) { /* * If the residual occurred on the last * transfer and the transfer request was @@ -4414,29 +4414,20 @@ uint32_t sglen; /* Pull in the rest of the sgptr */ - sgptr |= - (ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR + 3) << 24) - | (ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR + 2) << 16) - | (ahd_inb_scbram(ahd, SCB_RESIDUAL_SGPTR + 1) << 8); - sgptr &= SG_PTR_MASK; - data_cnt = - (ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT+3) << 24) - | (ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT+2) << 16) - | (ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT+1) << 8) - | (ahd_inb_scbram(ahd, SCB_RESIDUAL_DATACNT)); - - data_addr = (((uint64_t)ahd_inb(ahd, SHADDR + 7)) << 56) - | (((uint64_t)ahd_inb(ahd, SHADDR + 6)) << 48) - | (((uint64_t)ahd_inb(ahd, SHADDR + 5)) << 40) - | (((uint64_t)ahd_inb(ahd, SHADDR + 4)) << 32) - | (ahd_inb(ahd, SHADDR + 3) << 24) - | (ahd_inb(ahd, SHADDR + 2) << 16) - | (ahd_inb(ahd, SHADDR + 1) << 8) - | (ahd_inb(ahd, SHADDR)); - + sgptr = ahd_inl_scbram(ahd, SCB_RESIDUAL_SGPTR); + data_cnt = ahd_inl_scbram(ahd, SCB_RESIDUAL_DATACNT); + if ((sgptr & SG_LIST_NULL) != 0) { + /* + * The residual data count is not updated + * for the command run to completion case. + * Explicitly zero the count. + */ + data_cnt &= ~AHD_SG_LEN_MASK; + } + data_addr = ahd_inq(ahd, SHADDR); data_cnt += 1; data_addr -= 1; - + sgptr &= SG_PTR_MASK; if ((ahd->flags & AHD_64BIT_ADDRESSING) != 0) { struct ahd_dma64_seg *sg; @@ -4504,16 +4495,17 @@ sg); } } - ahd_outb(ahd, SCB_RESIDUAL_SGPTR + 3, sgptr >> 24); - ahd_outb(ahd, SCB_RESIDUAL_SGPTR + 2, sgptr >> 16); - ahd_outb(ahd, SCB_RESIDUAL_SGPTR + 1, sgptr >> 8); - ahd_outb(ahd, SCB_RESIDUAL_SGPTR, sgptr); - - ahd_outb(ahd, SCB_RESIDUAL_DATACNT + 3, data_cnt >> 24); - ahd_outb(ahd, SCB_RESIDUAL_DATACNT + 2, data_cnt >> 16); - ahd_outb(ahd, SCB_RESIDUAL_DATACNT + 1, data_cnt >> 8); - ahd_outb(ahd, SCB_RESIDUAL_DATACNT, data_cnt); + /* + * Toggle the "oddness" of the transfer length + * to handle this mid-transfer ignore wide + * residue. This ensures that the oddness is + * correct for subsequent data transfers. + */ + ahd_outb(ahd, SCB_TASK_ATTRIBUTE, + ahd_inb(ahd, SCB_TASK_ATTRIBUTE) ^ SCB_XFERLEN_ODD); + ahd_outl(ahd, SCB_RESIDUAL_SGPTR, sgptr); + ahd_outl(ahd, SCB_RESIDUAL_DATACNT, data_cnt); /* * The FIFO's pointers will be updated if/when the * sequencer re-enters a data phase. @@ -4806,12 +4798,12 @@ | AHD_EXTENDED_TRANS_A|AHD_STPWLEVEL_A; ahd_timer_init(&ahd->reset_timer); ahd_timer_init(&ahd->stat_timer); - ahd->int_coalessing_timer = AHD_INT_COALESSING_TIMER_DEFAULT; - ahd->int_coalessing_maxcmds = AHD_INT_COALESSING_MAXCMDS_DEFAULT; - ahd->int_coalessing_mincmds = AHD_INT_COALESSING_MINCMDS_DEFAULT; - ahd->int_coalessing_threshold = AHD_INT_COALESSING_THRESHOLD_DEFAULT; - ahd->int_coalessing_stop_threshold = - AHD_INT_COALESSING_STOP_THRESHOLD_DEFAULT; + ahd->int_coalescing_timer = AHD_INT_COALESCING_TIMER_DEFAULT; + ahd->int_coalescing_maxcmds = AHD_INT_COALESCING_MAXCMDS_DEFAULT; + ahd->int_coalescing_mincmds = AHD_INT_COALESCING_MINCMDS_DEFAULT; + ahd->int_coalescing_threshold = AHD_INT_COALESCING_THRESHOLD_DEFAULT; + ahd->int_coalescing_stop_threshold = + AHD_INT_COALESCING_STOP_THRESHOLD_DEFAULT; if (ahd_platform_alloc(ahd, platform_arg) != 0) { ahd_free(ahd); @@ -5722,6 +5714,7 @@ next_scb->sg_list = segs; next_scb->sense_data = sense_data; next_scb->sense_busaddr = sense_busaddr; + memset(hscb, 0, sizeof(*hscb)); next_scb->hscb = hscb; hscb->hscb_busaddr = ahd_htole32(hscb_busaddr); @@ -6341,14 +6334,14 @@ ahd_outb(ahd, NEXT_QUEUED_SCB_ADDR + 3, (busaddr >> 24) & 0xFF); /* - * Default to coalessing disabled. + * Default to coalescing disabled. */ - ahd_outw(ahd, INT_COALESSING_CMDCOUNT, 0); + ahd_outw(ahd, INT_COALESCING_CMDCOUNT, 0); ahd_outw(ahd, CMDS_PENDING, 0); - ahd_update_coalessing_values(ahd, ahd->int_coalessing_timer, - ahd->int_coalessing_maxcmds, - ahd->int_coalessing_mincmds); - ahd_enable_coalessing(ahd, FALSE); + ahd_update_coalescing_values(ahd, ahd->int_coalescing_timer, + ahd->int_coalescing_maxcmds, + ahd->int_coalescing_mincmds); + ahd_enable_coalescing(ahd, FALSE); ahd_loadseq(ahd); ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI); @@ -6601,30 +6594,30 @@ } void -ahd_update_coalessing_values(struct ahd_softc *ahd, u_int timer, u_int maxcmds, +ahd_update_coalescing_values(struct ahd_softc *ahd, u_int timer, u_int maxcmds, u_int mincmds) { if (timer > AHD_TIMER_MAX_US) timer = AHD_TIMER_MAX_US; - ahd->int_coalessing_timer = timer; + ahd->int_coalescing_timer = timer; - if (maxcmds > AHD_INT_COALESSING_MAXCMDS_MAX) - maxcmds = AHD_INT_COALESSING_MAXCMDS_MAX; - if (mincmds > AHD_INT_COALESSING_MINCMDS_MAX) - mincmds = AHD_INT_COALESSING_MINCMDS_MAX; - ahd->int_coalessing_maxcmds = maxcmds; - ahd_outw(ahd, INT_COALESSING_TIMER, timer / AHD_TIMER_US_PER_TICK); - ahd_outb(ahd, INT_COALESSING_MAXCMDS, -maxcmds); - ahd_outb(ahd, INT_COALESSING_MINCMDS, -mincmds); + if (maxcmds > AHD_INT_COALESCING_MAXCMDS_MAX) + maxcmds = AHD_INT_COALESCING_MAXCMDS_MAX; + if (mincmds > AHD_INT_COALESCING_MINCMDS_MAX) + mincmds = AHD_INT_COALESCING_MINCMDS_MAX; + ahd->int_coalescing_maxcmds = maxcmds; + ahd_outw(ahd, INT_COALESCING_TIMER, timer / AHD_TIMER_US_PER_TICK); + ahd_outb(ahd, INT_COALESCING_MAXCMDS, -maxcmds); + ahd_outb(ahd, INT_COALESCING_MINCMDS, -mincmds); } void -ahd_enable_coalessing(struct ahd_softc *ahd, int enable) +ahd_enable_coalescing(struct ahd_softc *ahd, int enable) { - ahd->hs_mailbox &= ~ENINT_COALESS; + ahd->hs_mailbox &= ~ENINT_COALESCE; if (enable) - ahd->hs_mailbox |= ENINT_COALESS; + ahd->hs_mailbox |= ENINT_COALESCE; ahd_outb(ahd, HS_MAILBOX, ahd->hs_mailbox); ahd_flush_device_writes(ahd); ahd_run_qoutfifo(ahd); @@ -7718,20 +7711,20 @@ } ahd_lock(ahd, &s); - enint_coal = ahd->hs_mailbox & ENINT_COALESS; - if (ahd->cmdcmplt_total > ahd->int_coalessing_threshold) - enint_coal |= ENINT_COALESS; - else if (ahd->cmdcmplt_total < ahd->int_coalessing_stop_threshold) - enint_coal &= ~ENINT_COALESS; + enint_coal = ahd->hs_mailbox & ENINT_COALESCE; + if (ahd->cmdcmplt_total > ahd->int_coalescing_threshold) + enint_coal |= ENINT_COALESCE; + else if (ahd->cmdcmplt_total < ahd->int_coalescing_stop_threshold) + enint_coal &= ~ENINT_COALESCE; - if (enint_coal != (ahd->hs_mailbox & ENINT_COALESS)) { - ahd_enable_coalessing(ahd, enint_coal); + if (enint_coal != (ahd->hs_mailbox & ENINT_COALESCE)) { + ahd_enable_coalescing(ahd, enint_coal); #ifdef AHD_DEBUG - if ((ahd_debug & AHD_SHOW_INT_COALESSING) != 0) - printf("%s: Interrupt coalessing " + if ((ahd_debug & AHD_SHOW_INT_COALESCING) != 0) + printf("%s: Interrupt coalescing " "now %sabled. Cmds %d\n", ahd_name(ahd), - (enint_coal & ENINT_COALESS) ? "en" : "dis", + (enint_coal & ENINT_COALESCE) ? "en" : "dis", ahd->cmdcmplt_total); #endif } @@ -8279,8 +8272,6 @@ download_consts[PKT_OVERRUN_BUFOFFSET] = (ahd->overrun_buf - (uint8_t *)ahd->qoutfifo) / 256; download_consts[SCB_TRANSFER_SIZE] = SCB_TRANSFER_SIZE_1BYTE_LUN; - if ((ahd->bugs & AHD_PKT_LUN_BUG) != 0) - download_consts[SCB_TRANSFER_SIZE] = SCB_TRANSFER_SIZE_FULL_LUN; cur_patch = patches; downloaded = 0; skip_addr = 0; @@ -8509,7 +8500,7 @@ } void -ahd_dump_all_cards_state() +ahd_dump_all_cards_state(void) { struct ahd_softc *list_ahd; diff -Nru a/drivers/scsi/aic7xxx/aic79xx_inline.h b/drivers/scsi/aic7xxx/aic79xx_inline.h --- a/drivers/scsi/aic7xxx/aic79xx_inline.h Mon Jun 9 23:16:11 2003 +++ b/drivers/scsi/aic7xxx/aic79xx_inline.h Mon Jun 9 23:16:11 2003 @@ -37,7 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#48 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#50 $ * * $FreeBSD$ */ @@ -271,11 +271,12 @@ scb->crc_retry_count = 0; if ((scb->flags & SCB_PACKETIZED) != 0) { /* XXX what about ACA?? It is type 4, but TAG_TYPE == 0x3. */ - scb->hscb->task_attribute= scb->hscb->control & SCB_TAG_TYPE; - /* - * For Rev A short lun workaround. - */ - scb->hscb->pkt_long_lun[6] = scb->hscb->lun; + scb->hscb->task_attribute = scb->hscb->control & SCB_TAG_TYPE; + } else { + if (ahd_get_transfer_length(scb) & 0x01) + scb->hscb->task_attribute = SCB_XFERLEN_ODD; + else + scb->hscb->task_attribute = 0; } if (scb->hscb->cdb_len <= MAX_CDB_LEN_WITH_SENSE_ADDR diff -Nru a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c --- a/drivers/scsi/aic7xxx/aic79xx_osm.c Mon Jun 9 23:16:13 2003 +++ b/drivers/scsi/aic7xxx/aic79xx_osm.c Mon Jun 9 23:16:13 2003 @@ -1,7 +1,7 @@ /* * Adaptec AIC79xx device driver for Linux. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.c#160 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.c#169 $ * * -------------------------------------------------------------------------- * Copyright (c) 1994-2000 Justin T. Gibbs. @@ -62,11 +62,6 @@ #include <linux/mm.h> /* For fetching system memory size */ -#define __KERNEL_SYSCALLS__ - -#include <linux/unistd.h> -static int errno; - /* * Lock protecting manipulation of the ahd softc list. */ @@ -755,31 +750,11 @@ consumed = 1; sg->addr = ahd_htole32(addr & 0xFFFFFFFF); scb->platform_data->xfer_len += len; + if (sizeof(bus_addr_t) > 4 - && (ahd->flags & AHD_39BIT_ADDRESSING) != 0) { - /* - * Due to DAC restrictions, we can't - * cross a 4GB boundary. - */ - if ((addr ^ (addr + len - 1)) & ~0xFFFFFFFF) { - struct ahd_dma_seg *next_sg; - uint32_t next_len; - - printf("Crossed Seg\n"); - if ((scb->sg_count + 2) > AHD_NSEG) - panic("Too few segs for dma mapping. " - "Increase AHD_NSEG\n"); - - consumed++; - next_sg = sg + 1; - next_sg->addr = 0; - next_len = 0x100000000 - (addr & 0xFFFFFFFF); - len -= next_len; - next_len |= ((addr >> 8) + 0x1000000) & 0x7F000000; - next_sg->len = ahd_htole32(next_len); - } - len |= (addr >> 8) & 0x7F000000; - } + && (ahd->flags & AHD_39BIT_ADDRESSING) != 0) + len |= (addr >> 8) & AHD_SG_HIGH_ADDR_MASK; + sg->len = ahd_htole32(len); return (consumed); } @@ -796,14 +771,18 @@ static int ahd_linux_slave_alloc(Scsi_Device *); static int ahd_linux_slave_configure(Scsi_Device *); static void ahd_linux_slave_destroy(Scsi_Device *); +#if defined(__i386__) static int ahd_linux_biosparam(struct scsi_device*, struct block_device*, sector_t, int[]); +#endif #else static int ahd_linux_release(struct Scsi_Host *); static void ahd_linux_select_queue_depth(struct Scsi_Host *host, Scsi_Device *scsi_devs); +#if defined(__i386__) static int ahd_linux_biosparam(Disk *, kdev_t, int[]); #endif +#endif static int ahd_linux_bus_reset(Scsi_Cmnd *); static int ahd_linux_dev_reset(Scsi_Cmnd *); static int ahd_linux_abort(Scsi_Cmnd *); @@ -1211,6 +1190,7 @@ } #endif +#if defined(__i386__) /* * Return the disk geometry for the given SCSI device. */ @@ -1273,6 +1253,7 @@ geom[2] = cylinders; return (0); } +#endif /* * Abort the current SCSI command(s). @@ -2198,7 +2179,7 @@ } uint64_t -ahd_linux_get_memsize() +ahd_linux_get_memsize(void) { struct sysinfo si; @@ -2213,7 +2194,7 @@ * scenario. */ static int -ahd_linux_next_unit() +ahd_linux_next_unit(void) { struct ahd_softc *ahd; int unit; @@ -2955,13 +2936,11 @@ struct ahd_devinfo *devinfo, struct ahd_linux_target *targ) { - cam_status cam_status; u_int32_t status; - u_int scsi_status; - scsi_status = ahd_cmd_get_scsi_status(cmd); - cam_status = ahd_cmd_get_transaction_status(cmd); - status = aic_error_action(cmd, targ->inq_data, cam_status, scsi_status); + status = aic_error_action(cmd, targ->inq_data, + ahd_cmd_get_transaction_status(cmd), + ahd_cmd_get_scsi_status(cmd)); #ifdef AHD_DEBUG @@ -4211,7 +4190,7 @@ /* * SCSI controller interrupt handler. */ -AIC_LINUX_IRQRETURN_T +irqreturn_t ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs) { struct ahd_softc *ahd; @@ -4225,7 +4204,7 @@ ahd_schedule_runq(ahd); ahd_linux_run_complete_queue(ahd); ahd_unlock(ahd, &flags); - AIC_LINUX_IRQRETURN(ours); + return IRQ_RETVAL(ours); } void diff -Nru a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h --- a/drivers/scsi/aic7xxx/aic79xx_osm.h Mon Jun 9 23:16:14 2003 +++ b/drivers/scsi/aic7xxx/aic79xx_osm.h Mon Jun 9 23:16:14 2003 @@ -36,7 +36,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.h#130 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.h#133 $ * */ #ifndef _AIC79XX_LINUX_H_ @@ -293,7 +293,7 @@ #define AHD_SCSI_HAS_HOST_LOCK 0 #endif -#define AIC79XX_DRIVER_VERSION "1.3.8" +#define AIC79XX_DRIVER_VERSION "1.3.9" /**************************** Front End Queues ********************************/ /* @@ -1006,7 +1006,7 @@ (((dev_softc)->dma_mask = mask) && 0) #endif /**************************** Proc FS Support *********************************/ -int ahd_linux_proc_info(char *, char **, off_t, int, int, int); +int ahd_linux_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int); /*************************** Domain Validation ********************************/ #define AHD_DV_CMD(cmd) ((cmd)->scsi_done == ahd_linux_dv_complete) @@ -1211,7 +1211,7 @@ int ahd_platform_abort_scbs(struct ahd_softc *ahd, int target, char channel, int lun, u_int tag, role_t role, uint32_t status); -AIC_LINUX_IRQRETURN_T +irqreturn_t ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs); void ahd_platform_flushwork(struct ahd_softc *ahd); int ahd_softc_comp(struct ahd_softc *, struct ahd_softc *); diff -Nru a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c --- a/drivers/scsi/aic7xxx/aic79xx_osm_pci.c Mon Jun 9 23:16:09 2003 +++ b/drivers/scsi/aic7xxx/aic79xx_osm_pci.c Mon Jun 9 23:16:09 2003 @@ -36,7 +36,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm_pci.c#21 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm_pci.c#23 $ */ #include "aic79xx_osm.h" @@ -156,19 +156,21 @@ pci_set_master(pdev); if (sizeof(bus_addr_t) > 4) { - uint64_t memsize; + uint64_t memsize; + bus_addr_t mask_64bit; + bus_addr_t mask_39bit; memsize = ahd_linux_get_memsize(); - if (memsize >= 0x8000000000 - && ahd_pci_set_dma_mask(pdev, 0xFFFFFFFFFFFFFFFFULL) == 0) { + mask_64bit = (bus_addr_t)(0xFFFFFFFFFFFFFFFFULL&(bus_addr_t)~0); + mask_39bit = (bus_addr_t)(0x7FFFFFFFFFULL&(bus_addr_t)~0); + if (memsize >= 0x8000000000ULL + && ahd_pci_set_dma_mask(pdev, mask_64bit) == 0) { ahd->flags |= AHD_64BIT_ADDRESSING; - ahd->platform_data->hw_dma_mask = - (bus_addr_t)(0xFFFFFFFFFFFFFFFFULL&(bus_addr_t)~0); + ahd->platform_data->hw_dma_mask = mask_64bit; } else if (memsize > 0x80000000 - && ahd_pci_set_dma_mask(pdev, 0x7FFFFFFFFFULL) == 0) { + && ahd_pci_set_dma_mask(pdev, mask_39bit) == 0) { ahd->flags |= AHD_39BIT_ADDRESSING; - ahd->platform_data->hw_dma_mask = - (bus_addr_t)(0x7FFFFFFFFFULL & (bus_addr_t)~0); + ahd->platform_data->hw_dma_mask = mask_39bit; } } else { ahd_pci_set_dma_mask(pdev, 0xFFFFFFFF); diff -Nru a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c --- a/drivers/scsi/aic7xxx/aic79xx_pci.c Mon Jun 9 23:16:11 2003 +++ b/drivers/scsi/aic7xxx/aic79xx_pci.c Mon Jun 9 23:16:11 2003 @@ -38,7 +38,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#71 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#73 $ * * $FreeBSD$ */ @@ -65,28 +65,29 @@ } #define ID_ALL_MASK 0xFFFFFFFFFFFFFFFFull +#define ID_ALL_IROC_MASK 0xFFFFFF7FFFFFFFFFull #define ID_DEV_VENDOR_MASK 0xFFFFFFFF00000000ull #define ID_9005_GENERIC_MASK 0xFFF0FFFF00000000ull +#define ID_9005_GENERIC_IROC_MASK 0xFFF0FF7F00000000ull #define ID_AIC7901 0x800F9005FFFF9005ull -#define ID_AIC7901A 0x801E9005FFFF9005ull -#define ID_AIC7901A_IROC 0x809E9005FFFF9005ull #define ID_AHA_29320A 0x8000900500609005ull +#define ID_AHA_29320ALP 0x8017900500449005ull + +#define ID_AIC7901A 0x801E9005FFFF9005ull +#define ID_AHA_29320 0x8012900500429005ull +#define ID_AHA_29320B 0x8013900500439005ull #define ID_AHA_29320LP 0x8014900500449005ull -#define ID_AHA_29320LP_IROC 0x8094900500449005ull #define ID_AIC7902 0x801F9005FFFF9005ull -#define ID_AIC7902_IROC 0x809F9005FFFF9005ull #define ID_AIC7902_B 0x801D9005FFFF9005ull -#define ID_AIC7902_B_IROC 0x809D9005FFFF9005ull #define ID_AHA_39320 0x8010900500409005ull +#define ID_AHA_39320_B 0x8015900500409005ull #define ID_AHA_39320A 0x8016900500409005ull #define ID_AHA_39320D 0x8011900500419005ull #define ID_AHA_39320D_B 0x801C900500419005ull #define ID_AHA_39320D_HP 0x8011900500AC0E11ull #define ID_AHA_39320D_B_HP 0x801C900500AC0E11ull -#define ID_AHA_29320 0x8012900500429005ull -#define ID_AHA_29320B 0x8013900500439005ull #define ID_AIC7902_PCI_REV_A4 0x3 #define ID_AIC7902_PCI_REV_B0 0x10 #define SUBID_HP 0x0E11 @@ -113,22 +114,42 @@ #define SUBID_9005_SEEPTYPE_NONE 0x0 #define SUBID_9005_SEEPTYPE_4K 0x1 +static ahd_device_setup_t ahd_aic7901_setup; static ahd_device_setup_t ahd_aic7901A_setup; static ahd_device_setup_t ahd_aic7902_setup; struct ahd_pci_identity ahd_pci_ident_table [] = { + /* aic7901 based controllers */ + { + ID_AHA_29320A, + ID_ALL_MASK, + "Adaptec 29320A Ultra320 SCSI adapter", + ahd_aic7901_setup + }, + { + ID_AHA_29320ALP, + ID_ALL_MASK, + "Adaptec 29320ALP Ultra320 SCSI adapter", + ahd_aic7901_setup + }, /* aic7901A based controllers */ { - ID_AHA_29320LP, + ID_AHA_29320, ID_ALL_MASK, - "Adaptec 29320LP Ultra320 SCSI adapter", + "Adaptec 29320 Ultra320 SCSI adapter", ahd_aic7901A_setup }, { - ID_AHA_29320A, + ID_AHA_29320B, ID_ALL_MASK, - "Adaptec 29320A Ultra320 SCSI adapter", + "Adaptec 29320B Ultra320 SCSI adapter", + ahd_aic7901A_setup + }, + { + ID_AHA_29320LP, + ID_ALL_MASK, + "Adaptec 29320LP Ultra320 SCSI adapter", ahd_aic7901A_setup }, /* aic7902 based controllers */ @@ -139,6 +160,12 @@ ahd_aic7902_setup }, { + ID_AHA_39320_B, + ID_ALL_MASK, + "Adaptec 39320 Ultra320 SCSI adapter", + ahd_aic7902_setup + }, + { ID_AHA_39320A, ID_ALL_MASK, "Adaptec 39320A Ultra320 SCSI adapter", @@ -182,6 +209,12 @@ }, /* Generic chip probes for devices we don't know 'exactly' */ { + ID_AIC7901 & ID_DEV_VENDOR_MASK, + ID_DEV_VENDOR_MASK, + "Adaptec AIC7901 Ultra320 SCSI adapter", + ahd_aic7901_setup + }, + { ID_AIC7901A & ID_DEV_VENDOR_MASK, ID_DEV_VENDOR_MASK, "Adaptec AIC7901A Ultra320 SCSI adapter", @@ -332,9 +365,9 @@ } /* Ensure busmastering is enabled */ - command = ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/1); + command = ahd_pci_read_config(ahd->dev_softc, PCIR_COMMAND, /*bytes*/2); command |= PCIM_CMD_BUSMASTEREN; - ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, command, /*bytes*/1); + ahd_pci_write_config(ahd->dev_softc, PCIR_COMMAND, command, /*bytes*/2); error = ahd_softc_init(ahd); if (error != 0) @@ -868,6 +901,18 @@ } static int +ahd_aic7901_setup(struct ahd_softc *ahd) +{ + int error; + + error = ahd_aic7902_setup(ahd); + if (error != 0) + return (error); + ahd->chip = AHD_AIC7901; + return (0); +} + +static int ahd_aic7901A_setup(struct ahd_softc *ahd) { int error; @@ -890,7 +935,7 @@ if (rev < ID_AIC7902_PCI_REV_A4) { printf("%s: Unable to attach to unsupported chip revision %d\n", ahd_name(ahd), rev); - ahd_pci_write_config(pci, PCIR_COMMAND, 0, /*bytes*/1); + ahd_pci_write_config(pci, PCIR_COMMAND, 0, /*bytes*/2); return (ENXIO); } ahd->channel = ahd_get_pci_function(pci) + 'A'; diff -Nru a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c --- a/drivers/scsi/aic7xxx/aic79xx_proc.c Mon Jun 9 23:16:16 2003 +++ b/drivers/scsi/aic7xxx/aic79xx_proc.c Mon Jun 9 23:16:16 2003 @@ -278,8 +278,8 @@ * Return information to handle /proc support for the driver. */ int -ahd_linux_proc_info(char *buffer, char **start, off_t offset, - int length, int hostno, int inout) +ahd_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset, + int length, int inout) { struct ahd_softc *ahd; struct info_str info; @@ -292,7 +292,7 @@ retval = -EINVAL; ahd_list_lock(&l); TAILQ_FOREACH(ahd, &ahd_tailq, links) { - if (ahd->platform_data->host->host_no == hostno) + if (ahd->platform_data->host == shost) break; } diff -Nru a/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped b/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped --- a/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped Mon Jun 9 23:16:19 2003 +++ b/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped Mon Jun 9 23:16:19 2003 @@ -2,8 +2,8 @@ * DO NOT EDIT - This file is automatically generated * from the following source files: * - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#91 $ - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#67 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#94 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#69 $ */ typedef int (ahd_reg_print_t)(u_int, u_int *, u_int); typedef struct ahd_reg_parse_entry { @@ -2134,24 +2134,24 @@ #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_int_coalessing_timer_print; +ahd_reg_print_t ahd_int_coalescing_timer_print; #else -#define ahd_int_coalessing_timer_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "INT_COALESSING_TIMER", 0x14a, regvalue, cur_col, wrap) +#define ahd_int_coalescing_timer_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "INT_COALESCING_TIMER", 0x14a, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_int_coalessing_maxcmds_print; +ahd_reg_print_t ahd_int_coalescing_maxcmds_print; #else -#define ahd_int_coalessing_maxcmds_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "INT_COALESSING_MAXCMDS", 0x14c, regvalue, cur_col, wrap) +#define ahd_int_coalescing_maxcmds_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "INT_COALESCING_MAXCMDS", 0x14c, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_int_coalessing_mincmds_print; +ahd_reg_print_t ahd_int_coalescing_mincmds_print; #else -#define ahd_int_coalessing_mincmds_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "INT_COALESSING_MINCMDS", 0x14d, regvalue, cur_col, wrap) +#define ahd_int_coalescing_mincmds_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "INT_COALESCING_MINCMDS", 0x14d, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS @@ -2162,10 +2162,10 @@ #endif #if AIC_DEBUG_REGISTERS -ahd_reg_print_t ahd_int_coalessing_cmdcount_print; +ahd_reg_print_t ahd_int_coalescing_cmdcount_print; #else -#define ahd_int_coalessing_cmdcount_print(regvalue, cur_col, wrap) \ - ahd_print_register(NULL, 0, "INT_COALESSING_CMDCOUNT", 0x150, regvalue, cur_col, wrap) +#define ahd_int_coalescing_cmdcount_print(regvalue, cur_col, wrap) \ + ahd_print_register(NULL, 0, "INT_COALESCING_CMDCOUNT", 0x150, regvalue, cur_col, wrap) #endif #if AIC_DEBUG_REGISTERS @@ -2432,7 +2432,7 @@ #define HS_MAILBOX 0x0b #define HOST_TQINPOS 0x80 -#define ENINT_COALESS 0x40 +#define ENINT_COALESCE 0x40 #define CLRSEQINTSTAT 0x0c #define CLRSEQ_SWTMRTO 0x10 @@ -3612,15 +3612,15 @@ #define ALLOCFIFO_SCBPTR 0x148 -#define INT_COALESSING_TIMER 0x14a +#define INT_COALESCING_TIMER 0x14a -#define INT_COALESSING_MAXCMDS 0x14c +#define INT_COALESCING_MAXCMDS 0x14c -#define INT_COALESSING_MINCMDS 0x14d +#define INT_COALESCING_MINCMDS 0x14d #define CMDS_PENDING 0x14e -#define INT_COALESSING_CMDCOUNT 0x150 +#define INT_COALESCING_CMDCOUNT 0x150 #define LOCAL_HS_MAILBOX 0x151 @@ -3683,6 +3683,7 @@ #define LID 0xff #define SCB_TASK_ATTRIBUTE 0x1ab +#define SCB_XFERLEN_ODD 0x01 #define SCB_CDB_LEN 0x1ac #define SCB_CDB_LEN_PTR 0x80 @@ -3768,5 +3769,5 @@ /* Exported Labels */ -#define LABEL_seq_isr 0x270 -#define LABEL_timer_isr 0x26c +#define LABEL_seq_isr 0x269 +#define LABEL_timer_isr 0x265 diff -Nru a/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped b/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped --- a/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped Mon Jun 9 23:16:05 2003 +++ b/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped Mon Jun 9 23:16:05 2003 @@ -2,8 +2,8 @@ * DO NOT EDIT - This file is automatically generated * from the following source files: * - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#91 $ - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#67 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#93 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#68 $ */ #include "aic79xx_osm.h" @@ -161,7 +161,7 @@ } static ahd_reg_parse_entry_t HS_MAILBOX_parse_table[] = { - { "ENINT_COALESS", 0x40, 0x40 }, + { "ENINT_COALESCE", 0x40, 0x40 }, { "HOST_TQINPOS", 0x80, 0x80 } }; @@ -3375,23 +3375,23 @@ } int -ahd_int_coalessing_timer_print(u_int regvalue, u_int *cur_col, u_int wrap) +ahd_int_coalescing_timer_print(u_int regvalue, u_int *cur_col, u_int wrap) { - return (ahd_print_register(NULL, 0, "INT_COALESSING_TIMER", + return (ahd_print_register(NULL, 0, "INT_COALESCING_TIMER", 0x14a, regvalue, cur_col, wrap)); } int -ahd_int_coalessing_maxcmds_print(u_int regvalue, u_int *cur_col, u_int wrap) +ahd_int_coalescing_maxcmds_print(u_int regvalue, u_int *cur_col, u_int wrap) { - return (ahd_print_register(NULL, 0, "INT_COALESSING_MAXCMDS", + return (ahd_print_register(NULL, 0, "INT_COALESCING_MAXCMDS", 0x14c, regvalue, cur_col, wrap)); } int -ahd_int_coalessing_mincmds_print(u_int regvalue, u_int *cur_col, u_int wrap) +ahd_int_coalescing_mincmds_print(u_int regvalue, u_int *cur_col, u_int wrap) { - return (ahd_print_register(NULL, 0, "INT_COALESSING_MINCMDS", + return (ahd_print_register(NULL, 0, "INT_COALESCING_MINCMDS", 0x14d, regvalue, cur_col, wrap)); } @@ -3403,9 +3403,9 @@ } int -ahd_int_coalessing_cmdcount_print(u_int regvalue, u_int *cur_col, u_int wrap) +ahd_int_coalescing_cmdcount_print(u_int regvalue, u_int *cur_col, u_int wrap) { - return (ahd_print_register(NULL, 0, "INT_COALESSING_CMDCOUNT", + return (ahd_print_register(NULL, 0, "INT_COALESCING_CMDCOUNT", 0x150, regvalue, cur_col, wrap)); } diff -Nru a/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped b/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped --- a/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped Mon Jun 9 23:16:19 2003 +++ b/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped Mon Jun 9 23:16:19 2003 @@ -2,30 +2,30 @@ * DO NOT EDIT - This file is automatically generated * from the following source files: * - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#91 $ - * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#67 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#94 $ + * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#69 $ */ static uint8_t seqprog[] = { 0xff, 0x02, 0x06, 0x78, - 0x00, 0xea, 0x4e, 0x59, + 0x00, 0xea, 0x50, 0x59, 0x01, 0xea, 0x04, 0x30, 0xff, 0x04, 0x0c, 0x78, - 0x19, 0xea, 0x4e, 0x59, + 0x19, 0xea, 0x50, 0x59, 0x19, 0xea, 0x04, 0x00, - 0x33, 0xea, 0x42, 0x59, + 0x33, 0xea, 0x44, 0x59, 0x33, 0xea, 0x00, 0x00, 0x60, 0x3a, 0x1a, 0x68, 0x04, 0x47, 0x1b, 0x68, 0xff, 0x21, 0x1b, 0x70, - 0x40, 0x4b, 0x90, 0x69, - 0x00, 0xe2, 0x52, 0x59, - 0x40, 0x4b, 0x90, 0x69, - 0x20, 0x4b, 0x80, 0x69, + 0x40, 0x4b, 0x92, 0x69, + 0x00, 0xe2, 0x54, 0x59, + 0x40, 0x4b, 0x92, 0x69, + 0x20, 0x4b, 0x82, 0x69, 0xfc, 0x42, 0x24, 0x78, 0x10, 0x40, 0x24, 0x78, - 0x00, 0xe2, 0xd2, 0x5d, + 0x00, 0xe2, 0xc4, 0x5d, 0x20, 0x4d, 0x28, 0x78, - 0x00, 0xe2, 0xd2, 0x5d, + 0x00, 0xe2, 0xc4, 0x5d, 0x30, 0x3f, 0xc0, 0x09, 0x30, 0xe0, 0x30, 0x60, 0x7f, 0x4a, 0x94, 0x08, @@ -35,7 +35,7 @@ 0x00, 0xe2, 0x56, 0x58, 0x00, 0xe2, 0x66, 0x58, 0x00, 0xe2, 0x06, 0x40, - 0x33, 0xea, 0x42, 0x59, + 0x33, 0xea, 0x44, 0x59, 0x33, 0xea, 0x00, 0x00, 0x01, 0x52, 0x64, 0x78, 0x02, 0x58, 0x50, 0x31, @@ -43,26 +43,26 @@ 0xff, 0xad, 0x4f, 0x78, 0x50, 0x4b, 0x4a, 0x68, 0xbf, 0x3a, 0x74, 0x08, - 0x14, 0xea, 0x4e, 0x59, + 0x14, 0xea, 0x50, 0x59, 0x14, 0xea, 0x04, 0x00, 0x08, 0xa8, 0x51, 0x03, 0xff, 0xae, 0x3f, 0x68, - 0x00, 0xe2, 0x50, 0x5b, + 0x00, 0xe2, 0x56, 0x5b, 0x00, 0xe2, 0x3e, 0x40, - 0x00, 0xea, 0x42, 0x59, + 0x00, 0xea, 0x44, 0x59, 0x01, 0xea, 0x00, 0x30, 0x80, 0xf9, 0x5e, 0x68, - 0x00, 0xe2, 0x40, 0x59, - 0x11, 0xea, 0x42, 0x59, + 0x00, 0xe2, 0x42, 0x59, + 0x11, 0xea, 0x44, 0x59, 0x11, 0xea, 0x00, 0x00, - 0x80, 0xf9, 0x40, 0x79, + 0x80, 0xf9, 0x42, 0x79, 0xff, 0xea, 0xd4, 0x0d, - 0x22, 0xea, 0x42, 0x59, + 0x22, 0xea, 0x44, 0x59, 0x22, 0xea, 0x00, 0x00, 0x10, 0x16, 0x70, 0x78, 0x01, 0x0b, 0xa2, 0x32, 0x10, 0x16, 0x2c, 0x00, - 0x18, 0xad, 0xfe, 0x78, + 0x18, 0xad, 0x00, 0x79, 0x04, 0xad, 0xca, 0x68, 0x80, 0xad, 0x64, 0x78, 0x10, 0xad, 0x98, 0x78, @@ -71,15 +71,15 @@ 0x02, 0x8c, 0x59, 0x32, 0x02, 0x28, 0x19, 0x33, 0x02, 0xa8, 0x50, 0x36, - 0x33, 0xea, 0x42, 0x59, + 0x33, 0xea, 0x44, 0x59, 0x33, 0xea, 0x00, 0x00, 0x40, 0x3a, 0x64, 0x68, 0x50, 0x4b, 0x64, 0x68, - 0x22, 0xea, 0x42, 0x59, + 0x22, 0xea, 0x44, 0x59, 0x22, 0xea, 0x00, 0x00, 0xe7, 0xad, 0x5a, 0x09, 0x02, 0x8c, 0x59, 0x32, - 0x1a, 0xea, 0x4e, 0x59, + 0x1a, 0xea, 0x50, 0x59, 0x1a, 0xea, 0x04, 0x00, 0xff, 0xea, 0xd4, 0x0d, 0xe7, 0xad, 0x5a, 0x09, @@ -113,29 +113,30 @@ 0xff, 0xea, 0xc0, 0x09, 0x01, 0x4e, 0x9d, 0x1a, 0x00, 0x4f, 0x9f, 0x22, + 0x01, 0xaa, 0x6d, 0x33, 0x01, 0xea, 0x5c, 0x33, 0x04, 0xa4, 0x49, 0x32, 0xff, 0xea, 0x4a, 0x03, 0xff, 0xea, 0x4e, 0x03, 0x01, 0x10, 0xd4, 0x31, - 0x10, 0xa8, 0xf3, 0x68, + 0x10, 0xa8, 0xf5, 0x68, 0x3d, 0xa9, 0xc5, 0x29, 0xfe, 0xe2, 0xc4, 0x09, 0x01, 0xea, 0xc6, 0x01, 0x02, 0xe2, 0xc8, 0x31, 0x02, 0xec, 0x50, 0x31, 0x02, 0xa0, 0xda, 0x31, - 0xff, 0xa9, 0xf2, 0x70, + 0xff, 0xa9, 0xf4, 0x70, 0x02, 0xa0, 0x48, 0x37, - 0xff, 0x21, 0xfb, 0x70, + 0xff, 0x21, 0xfd, 0x70, 0x02, 0x22, 0x51, 0x31, 0x02, 0xa0, 0x4c, 0x33, 0x02, 0xa0, 0x44, 0x36, 0x02, 0xa0, 0x40, 0x32, 0x02, 0xa0, 0x44, 0x36, - 0x04, 0x47, 0x03, 0x69, - 0x40, 0x16, 0x2e, 0x69, - 0xff, 0x2d, 0x33, 0x61, + 0x04, 0x47, 0x05, 0x69, + 0x40, 0x16, 0x30, 0x69, + 0xff, 0x2d, 0x35, 0x61, 0xff, 0x29, 0x65, 0x70, 0x01, 0x37, 0xc1, 0x31, 0x02, 0x28, 0x55, 0x32, @@ -148,20 +149,20 @@ 0x01, 0x50, 0xa1, 0x1a, 0xff, 0x4e, 0x9d, 0x1a, 0xff, 0x4f, 0x9f, 0x22, - 0xff, 0x8d, 0x27, 0x71, - 0x80, 0xac, 0x26, 0x71, - 0x20, 0x16, 0x26, 0x69, + 0xff, 0x8d, 0x29, 0x71, + 0x80, 0xac, 0x28, 0x71, + 0x20, 0x16, 0x28, 0x69, 0x02, 0x8c, 0x51, 0x31, - 0x00, 0xe2, 0x10, 0x41, + 0x00, 0xe2, 0x12, 0x41, 0x01, 0xac, 0x08, 0x31, 0x09, 0xea, 0x5a, 0x01, 0x02, 0x8c, 0x51, 0x32, 0xff, 0xea, 0x1a, 0x07, 0x04, 0x24, 0xf9, 0x30, - 0x1d, 0xea, 0x38, 0x41, + 0x1d, 0xea, 0x3a, 0x41, 0x02, 0x2c, 0x51, 0x31, 0x04, 0xa0, 0xf9, 0x30, - 0x19, 0xea, 0x38, 0x41, + 0x19, 0xea, 0x3a, 0x41, 0x06, 0xea, 0x08, 0x81, 0x01, 0xe2, 0x5a, 0x35, 0x02, 0xf2, 0xf0, 0x35, @@ -179,23 +180,23 @@ 0x02, 0x20, 0xb9, 0x30, 0x02, 0x20, 0x51, 0x31, 0x4c, 0xa9, 0xd7, 0x28, - 0x10, 0xa8, 0x61, 0x79, + 0x10, 0xa8, 0x63, 0x79, 0x01, 0x6b, 0xc0, 0x30, 0x02, 0x64, 0xc8, 0x00, 0x40, 0x3a, 0x74, 0x04, 0x00, 0xe2, 0x56, 0x58, - 0x33, 0xea, 0x42, 0x59, + 0x33, 0xea, 0x44, 0x59, 0x33, 0xea, 0x00, 0x00, 0x30, 0x3f, 0xc0, 0x09, - 0x30, 0xe0, 0x62, 0x61, - 0x20, 0x3f, 0x78, 0x69, - 0x10, 0x3f, 0x62, 0x79, + 0x30, 0xe0, 0x64, 0x61, + 0x20, 0x3f, 0x7a, 0x69, + 0x10, 0x3f, 0x64, 0x79, 0x02, 0xea, 0x7e, 0x00, - 0x00, 0xea, 0x42, 0x59, + 0x00, 0xea, 0x44, 0x59, 0x01, 0xea, 0x00, 0x30, 0x02, 0x48, 0x51, 0x35, 0x01, 0xea, 0x7e, 0x00, - 0x11, 0xea, 0x42, 0x59, + 0x11, 0xea, 0x44, 0x59, 0x11, 0xea, 0x00, 0x00, 0x02, 0x48, 0x51, 0x35, 0x08, 0xea, 0x98, 0x00, @@ -205,11 +206,11 @@ 0x0f, 0x67, 0xc0, 0x09, 0x00, 0x34, 0x69, 0x02, 0x20, 0xea, 0x96, 0x00, - 0x00, 0xe2, 0xf6, 0x41, - 0x40, 0x3a, 0xac, 0x69, + 0x00, 0xe2, 0xf8, 0x41, + 0x40, 0x3a, 0xae, 0x69, 0x02, 0x55, 0x06, 0x68, - 0x02, 0x56, 0xac, 0x69, - 0xff, 0x5b, 0xac, 0x61, + 0x02, 0x56, 0xae, 0x69, + 0xff, 0x5b, 0xae, 0x61, 0x02, 0x20, 0x51, 0x31, 0x80, 0xea, 0xb2, 0x01, 0x44, 0xea, 0x00, 0x00, @@ -217,36 +218,36 @@ 0x33, 0xea, 0x00, 0x00, 0xff, 0xea, 0xb2, 0x09, 0xff, 0xe0, 0xc0, 0x19, - 0xff, 0xe0, 0xae, 0x79, + 0xff, 0xe0, 0xb0, 0x79, 0x02, 0xa4, 0x51, 0x31, - 0x00, 0xe2, 0xa4, 0x41, + 0x00, 0xe2, 0xa6, 0x41, 0x02, 0x5e, 0x50, 0x31, 0x02, 0xa8, 0xb8, 0x30, 0x02, 0x5c, 0x50, 0x31, - 0xff, 0xa5, 0xbf, 0x71, + 0xff, 0xa5, 0xc1, 0x71, 0x02, 0xa4, 0x41, 0x31, 0x02, 0x22, 0x51, 0x31, 0x02, 0xa0, 0x4c, 0x33, 0x02, 0xa0, 0x44, 0x32, - 0x00, 0xe2, 0xc8, 0x41, - 0x10, 0xa8, 0xc9, 0x69, + 0x00, 0xe2, 0xca, 0x41, + 0x10, 0xa8, 0xcb, 0x69, 0x3d, 0xa9, 0xc9, 0x29, 0x01, 0xe4, 0xc8, 0x01, 0x01, 0xea, 0xca, 0x01, 0xff, 0xea, 0xda, 0x01, 0x02, 0x20, 0x51, 0x31, 0x02, 0xa6, 0x41, 0x32, - 0xff, 0x21, 0xd1, 0x61, + 0xff, 0x21, 0xd3, 0x61, 0xff, 0xea, 0x46, 0x02, 0x02, 0x5c, 0x50, 0x31, 0x40, 0xea, 0x96, 0x00, - 0x02, 0x56, 0xda, 0x6d, - 0x01, 0x55, 0xda, 0x6d, - 0x10, 0xa8, 0xdd, 0x79, - 0x10, 0x40, 0xe6, 0x69, - 0x01, 0x56, 0xe6, 0x79, + 0x02, 0x56, 0xcc, 0x6d, + 0x01, 0x55, 0xcc, 0x6d, + 0x10, 0xa8, 0xdf, 0x79, + 0x10, 0x40, 0xe8, 0x69, + 0x01, 0x56, 0xe8, 0x79, 0xff, 0xad, 0x07, 0x78, - 0x13, 0xea, 0x4e, 0x59, + 0x13, 0xea, 0x50, 0x59, 0x13, 0xea, 0x04, 0x00, 0x00, 0xe2, 0x06, 0x40, 0xbf, 0x3a, 0x74, 0x08, @@ -257,104 +258,106 @@ 0x40, 0xea, 0x66, 0x02, 0x08, 0x3c, 0x78, 0x00, 0x80, 0xea, 0x62, 0x02, - 0x00, 0xe2, 0xb2, 0x5b, + 0x00, 0xe2, 0xb8, 0x5b, 0x01, 0x36, 0xc1, 0x31, - 0x9f, 0xe0, 0x54, 0x7c, - 0x80, 0xe0, 0x0a, 0x72, - 0xa0, 0xe0, 0x42, 0x72, - 0xc0, 0xe0, 0x38, 0x72, - 0xe0, 0xe0, 0x72, 0x72, - 0x01, 0xea, 0x4e, 0x59, + 0x9f, 0xe0, 0x4c, 0x7c, + 0x80, 0xe0, 0x0c, 0x72, + 0xa0, 0xe0, 0x44, 0x72, + 0xc0, 0xe0, 0x3a, 0x72, + 0xe0, 0xe0, 0x74, 0x72, + 0x01, 0xea, 0x50, 0x59, 0x01, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xf6, 0x41, - 0x80, 0x33, 0x11, 0x7a, - 0x03, 0xea, 0x4e, 0x59, + 0x00, 0xe2, 0xf8, 0x41, + 0x80, 0x33, 0x13, 0x7a, + 0x03, 0xea, 0x50, 0x59, 0x03, 0xea, 0x04, 0x00, - 0xee, 0x00, 0x18, 0x6a, + 0xee, 0x00, 0x1a, 0x6a, 0x05, 0xea, 0xb4, 0x00, - 0x33, 0xea, 0x42, 0x59, + 0x33, 0xea, 0x44, 0x59, 0x33, 0xea, 0x00, 0x00, 0x02, 0xa8, 0x90, 0x32, - 0x00, 0xe2, 0x68, 0x59, + 0x00, 0xe2, 0x6a, 0x59, 0xef, 0xac, 0xd5, 0x19, - 0x00, 0xe2, 0x28, 0x52, + 0x00, 0xe2, 0x2a, 0x52, 0x09, 0x80, 0xe1, 0x30, 0x02, 0xea, 0x36, 0x00, 0xa8, 0xea, 0x32, 0x00, - 0x00, 0xe2, 0x2e, 0x42, + 0x00, 0xe2, 0x30, 0x42, 0x01, 0xac, 0xd1, 0x30, 0x10, 0x80, 0x89, 0x31, 0x20, 0xea, 0x32, 0x00, 0xbf, 0x33, 0x67, 0x0a, - 0x20, 0x19, 0x30, 0x6a, - 0x02, 0x4d, 0xf6, 0x69, + 0x20, 0x19, 0x32, 0x6a, + 0x02, 0x4d, 0xf8, 0x69, 0x40, 0x33, 0x67, 0x02, - 0x00, 0xe2, 0xf6, 0x41, - 0x80, 0x33, 0xaf, 0x6a, + 0x00, 0xe2, 0xf8, 0x41, + 0x80, 0x33, 0xb5, 0x6a, 0x01, 0x44, 0x10, 0x33, 0x08, 0xa8, 0x51, 0x03, - 0x00, 0xe2, 0xf6, 0x41, + 0x00, 0xe2, 0xf8, 0x41, 0x10, 0xea, 0x80, 0x00, 0x01, 0x31, 0xc5, 0x31, - 0x80, 0xe2, 0x5e, 0x62, - 0x10, 0xa8, 0x83, 0x6a, + 0x80, 0xe2, 0x60, 0x62, + 0x10, 0xa8, 0x85, 0x6a, 0xc0, 0xaa, 0xc5, 0x01, - 0x40, 0xa8, 0x4f, 0x6a, + 0x40, 0xa8, 0x51, 0x6a, 0xbf, 0xe2, 0xc4, 0x09, - 0x20, 0xa8, 0x63, 0x7a, + 0x20, 0xa8, 0x65, 0x7a, 0x01, 0xe2, 0x88, 0x30, - 0x00, 0xe2, 0xb2, 0x5b, - 0xa0, 0x36, 0x6b, 0x62, + 0x00, 0xe2, 0xb8, 0x5b, + 0xa0, 0x36, 0x6d, 0x62, 0x23, 0xa8, 0x89, 0x08, - 0x00, 0xe2, 0xb2, 0x5b, - 0xa0, 0x36, 0x6b, 0x62, - 0x00, 0xa8, 0x62, 0x42, - 0xff, 0xe2, 0x62, 0x62, - 0x00, 0xe2, 0x82, 0x42, + 0x00, 0xe2, 0xb8, 0x5b, + 0xa0, 0x36, 0x6d, 0x62, + 0x00, 0xa8, 0x64, 0x42, + 0xff, 0xe2, 0x64, 0x62, + 0x00, 0xe2, 0x84, 0x42, 0x40, 0xea, 0x98, 0x00, 0x01, 0xe2, 0x88, 0x30, - 0x00, 0xe2, 0xb2, 0x5b, - 0xa0, 0x36, 0x41, 0x72, + 0x00, 0xe2, 0xb8, 0x5b, + 0xa0, 0x36, 0x43, 0x72, 0x40, 0xea, 0x98, 0x00, 0x01, 0x31, 0x89, 0x32, 0x08, 0xea, 0x62, 0x02, - 0x00, 0xe2, 0xf6, 0x41, - 0xe0, 0xea, 0xce, 0x5b, - 0x80, 0xe0, 0xba, 0x6a, - 0x04, 0xe0, 0x60, 0x73, - 0x02, 0xe0, 0x90, 0x73, - 0x00, 0xea, 0x18, 0x73, - 0x03, 0xe0, 0xa0, 0x73, - 0x23, 0xe0, 0x94, 0x72, - 0x08, 0xe0, 0xb6, 0x72, - 0x00, 0xe2, 0xb2, 0x5b, - 0x07, 0xea, 0x4e, 0x59, + 0x00, 0xe2, 0xf8, 0x41, + 0xe0, 0xea, 0xd4, 0x5b, + 0x80, 0xe0, 0xc0, 0x6a, + 0x04, 0xe0, 0x66, 0x73, + 0x02, 0xe0, 0x96, 0x73, + 0x00, 0xea, 0x1e, 0x73, + 0x03, 0xe0, 0xa6, 0x73, + 0x23, 0xe0, 0x96, 0x72, + 0x08, 0xe0, 0xbc, 0x72, + 0x00, 0xe2, 0xb8, 0x5b, + 0x07, 0xea, 0x50, 0x59, 0x07, 0xea, 0x04, 0x00, - 0x08, 0x42, 0xf7, 0x71, - 0x04, 0x42, 0x91, 0x62, + 0x08, 0x42, 0xf9, 0x71, + 0x04, 0x42, 0x93, 0x62, 0x01, 0x43, 0x89, 0x30, - 0x00, 0xe2, 0x82, 0x42, + 0x00, 0xe2, 0x84, 0x42, 0x01, 0x44, 0xd4, 0x31, - 0x00, 0xe2, 0x82, 0x42, + 0x00, 0xe2, 0x84, 0x42, 0x01, 0x00, 0x60, 0x32, - 0x33, 0xea, 0x42, 0x59, + 0x33, 0xea, 0x44, 0x59, 0x33, 0xea, 0x00, 0x00, 0x4c, 0x34, 0xc1, 0x28, 0x01, 0x64, 0xc0, 0x31, - 0x00, 0x30, 0x43, 0x59, + 0x00, 0x30, 0x45, 0x59, 0x01, 0x30, 0x01, 0x30, - 0x01, 0xe0, 0xb4, 0x7a, - 0xa0, 0xea, 0xc4, 0x5b, - 0x01, 0xa0, 0xb4, 0x62, - 0x01, 0x84, 0xad, 0x7a, - 0x01, 0xa7, 0xb6, 0x7a, - 0x00, 0xe2, 0xb6, 0x42, - 0x03, 0xea, 0x4e, 0x59, + 0x01, 0xe0, 0xba, 0x7a, + 0xa0, 0xea, 0xca, 0x5b, + 0x01, 0xa0, 0xba, 0x62, + 0x01, 0x84, 0xaf, 0x7a, + 0x01, 0xab, 0xbd, 0x6a, + 0x05, 0xea, 0x50, 0x59, + 0x05, 0xea, 0x04, 0x00, + 0x00, 0xe2, 0xbc, 0x42, + 0x03, 0xea, 0x50, 0x59, 0x03, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xb6, 0x42, - 0x07, 0xea, 0xd6, 0x5b, + 0x00, 0xe2, 0xbc, 0x42, + 0x07, 0xea, 0xdc, 0x5b, 0x01, 0x44, 0xd4, 0x31, - 0x00, 0xe2, 0xf6, 0x41, + 0x00, 0xe2, 0xf8, 0x41, 0x3f, 0xe0, 0x6a, 0x0a, 0xc0, 0x34, 0xc1, 0x09, 0x00, 0x35, 0x51, 0x01, @@ -365,54 +368,54 @@ 0x01, 0xea, 0xc6, 0x01, 0x02, 0xe2, 0xc8, 0x31, 0x02, 0xec, 0x40, 0x31, - 0xff, 0xa1, 0xd6, 0x72, + 0xff, 0xa1, 0xdc, 0x72, 0x02, 0xe8, 0xda, 0x31, 0x02, 0xa0, 0x50, 0x31, - 0x00, 0xe2, 0xf8, 0x42, + 0x00, 0xe2, 0xfe, 0x42, 0x80, 0x33, 0x67, 0x02, 0x01, 0x44, 0xd4, 0x31, - 0x00, 0xe2, 0xb2, 0x5b, + 0x00, 0xe2, 0xb8, 0x5b, 0x01, 0x33, 0x67, 0x02, - 0xe0, 0x36, 0x13, 0x63, + 0xe0, 0x36, 0x19, 0x63, 0x02, 0x33, 0x67, 0x02, - 0x20, 0x46, 0x0c, 0x63, + 0x20, 0x46, 0x12, 0x63, 0xff, 0xea, 0x52, 0x09, - 0xa8, 0xea, 0xc4, 0x5b, - 0x04, 0xa8, 0xf3, 0x7a, + 0xa8, 0xea, 0xca, 0x5b, + 0x04, 0xa8, 0xf9, 0x7a, 0x01, 0x34, 0xc1, 0x31, - 0x00, 0xa9, 0xf3, 0x62, + 0x00, 0xa9, 0xf9, 0x62, 0x01, 0x35, 0xc1, 0x31, - 0x00, 0xaa, 0xfd, 0x72, + 0x00, 0xaa, 0x03, 0x73, 0x01, 0xa9, 0x52, 0x11, - 0xff, 0xa9, 0xe8, 0x6a, - 0x00, 0xe2, 0x0c, 0x43, + 0xff, 0xa9, 0xee, 0x6a, + 0x00, 0xe2, 0x12, 0x43, 0x10, 0x33, 0x67, 0x02, - 0x04, 0xa8, 0x0d, 0x7b, + 0x04, 0xa8, 0x13, 0x7b, 0xfb, 0xa8, 0x51, 0x0b, 0xff, 0xea, 0x66, 0x0a, - 0x01, 0x9c, 0x07, 0x6b, + 0x01, 0x9c, 0x0d, 0x6b, 0x02, 0xa8, 0x90, 0x32, - 0x00, 0xe2, 0x68, 0x59, - 0x10, 0xa8, 0xb7, 0x7a, - 0xff, 0xea, 0xd6, 0x5b, - 0x00, 0xe2, 0xb6, 0x42, - 0x04, 0xea, 0x4e, 0x59, + 0x00, 0xe2, 0x6a, 0x59, + 0x10, 0xa8, 0xbd, 0x7a, + 0xff, 0xea, 0xdc, 0x5b, + 0x00, 0xe2, 0xbc, 0x42, + 0x04, 0xea, 0x50, 0x59, 0x04, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xb6, 0x42, - 0x04, 0xea, 0x4e, 0x59, + 0x00, 0xe2, 0xbc, 0x42, + 0x04, 0xea, 0x50, 0x59, 0x04, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xf6, 0x41, - 0x08, 0xa8, 0xaf, 0x7a, - 0xc0, 0x33, 0x23, 0x7b, - 0x80, 0x33, 0xaf, 0x6a, - 0xff, 0x88, 0x23, 0x6b, - 0x40, 0x33, 0xaf, 0x6a, - 0x10, 0xa8, 0x29, 0x7b, - 0x0a, 0xea, 0x4e, 0x59, + 0x00, 0xe2, 0xf8, 0x41, + 0x08, 0xa8, 0xb5, 0x7a, + 0xc0, 0x33, 0x29, 0x7b, + 0x80, 0x33, 0xb5, 0x6a, + 0xff, 0x88, 0x29, 0x6b, + 0x40, 0x33, 0xb5, 0x6a, + 0x10, 0xa8, 0x2f, 0x7b, + 0x0a, 0xea, 0x50, 0x59, 0x0a, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0x48, 0x5b, - 0x00, 0xe2, 0x7c, 0x43, - 0x50, 0x4b, 0x30, 0x6b, + 0x00, 0xe2, 0x4e, 0x5b, + 0x00, 0xe2, 0x82, 0x43, + 0x50, 0x4b, 0x36, 0x6b, 0xbf, 0x3a, 0x74, 0x08, 0x01, 0xe0, 0xf4, 0x31, 0xff, 0xea, 0xc0, 0x09, @@ -422,25 +425,25 @@ 0x01, 0xfa, 0xc0, 0x35, 0x02, 0xa8, 0x84, 0x32, 0x02, 0xea, 0xb4, 0x00, - 0x33, 0xea, 0x42, 0x59, + 0x33, 0xea, 0x44, 0x59, 0x33, 0xea, 0x00, 0x00, 0x02, 0x42, 0x51, 0x31, 0xff, 0xae, 0x65, 0x68, - 0xff, 0x88, 0x55, 0x6b, - 0x01, 0x9c, 0x51, 0x6b, - 0x02, 0x9c, 0x59, 0x6b, - 0x01, 0x84, 0x59, 0x7b, + 0xff, 0x88, 0x5b, 0x6b, + 0x01, 0x9c, 0x57, 0x6b, + 0x02, 0x9c, 0x5f, 0x6b, + 0x01, 0x84, 0x5f, 0x7b, 0x02, 0x28, 0x19, 0x33, 0x02, 0xa8, 0x50, 0x36, - 0xff, 0x88, 0x59, 0x73, - 0x00, 0xe2, 0x2c, 0x5b, + 0xff, 0x88, 0x5f, 0x73, + 0x00, 0xe2, 0x32, 0x5b, 0x02, 0xa8, 0x5c, 0x33, 0x02, 0x2c, 0x19, 0x33, 0x02, 0xa8, 0x58, 0x32, 0x04, 0x9c, 0x39, 0x07, - 0xc0, 0x33, 0xaf, 0x6a, + 0xc0, 0x33, 0xb5, 0x6a, 0x04, 0xa8, 0x51, 0x03, - 0x20, 0xa8, 0x7d, 0x6b, + 0x20, 0xa8, 0x83, 0x6b, 0x02, 0xa8, 0x40, 0x31, 0xc0, 0x34, 0xc1, 0x09, 0x00, 0x35, 0x51, 0x01, @@ -455,56 +458,56 @@ 0xf7, 0x57, 0xae, 0x08, 0x08, 0xea, 0x98, 0x00, 0x01, 0x44, 0xd4, 0x31, - 0xee, 0x00, 0x86, 0x6b, + 0xee, 0x00, 0x8c, 0x6b, 0x02, 0xea, 0xb4, 0x00, - 0x00, 0xe2, 0xae, 0x5b, - 0x09, 0x4c, 0x88, 0x7b, + 0x00, 0xe2, 0xb4, 0x5b, + 0x09, 0x4c, 0x8e, 0x7b, 0x08, 0x4c, 0x06, 0x68, - 0x0b, 0xea, 0x4e, 0x59, + 0x0b, 0xea, 0x50, 0x59, 0x0b, 0xea, 0x04, 0x00, 0x01, 0x44, 0xd4, 0x31, - 0x20, 0x33, 0xf7, 0x79, - 0x00, 0xe2, 0x98, 0x5b, - 0x00, 0xe2, 0xf6, 0x41, - 0x01, 0x84, 0x9d, 0x7b, + 0x20, 0x33, 0xf9, 0x79, + 0x00, 0xe2, 0x9e, 0x5b, + 0x00, 0xe2, 0xf8, 0x41, + 0x01, 0x84, 0xa3, 0x7b, 0x01, 0x9c, 0x39, 0x07, 0x08, 0x60, 0x20, 0x33, 0x08, 0x80, 0x31, 0x37, 0xdf, 0x33, 0x67, 0x0a, - 0xee, 0x00, 0xaa, 0x6b, + 0xee, 0x00, 0xb0, 0x6b, 0x05, 0xea, 0xb4, 0x00, - 0x33, 0xea, 0x42, 0x59, + 0x33, 0xea, 0x44, 0x59, 0x33, 0xea, 0x00, 0x00, - 0x00, 0xe2, 0x68, 0x59, - 0x00, 0xe2, 0xb6, 0x42, + 0x00, 0xe2, 0x6a, 0x59, + 0x00, 0xe2, 0xbc, 0x42, 0x01, 0xea, 0x6c, 0x02, 0xc0, 0xea, 0x66, 0x06, - 0xff, 0x42, 0xbe, 0x6b, - 0x01, 0x41, 0xb2, 0x6b, - 0x02, 0x41, 0xb2, 0x7b, - 0xff, 0x42, 0xbe, 0x6b, - 0x01, 0x41, 0xb2, 0x6b, - 0x02, 0x41, 0xb2, 0x7b, - 0xff, 0x42, 0xbe, 0x7b, - 0x04, 0x4c, 0xb2, 0x6b, + 0xff, 0x42, 0xc4, 0x6b, + 0x01, 0x41, 0xb8, 0x6b, + 0x02, 0x41, 0xb8, 0x7b, + 0xff, 0x42, 0xc4, 0x6b, + 0x01, 0x41, 0xb8, 0x6b, + 0x02, 0x41, 0xb8, 0x7b, + 0xff, 0x42, 0xc4, 0x7b, + 0x04, 0x4c, 0xb8, 0x6b, 0xe0, 0x41, 0x6c, 0x0e, 0x01, 0x44, 0xd4, 0x31, - 0xff, 0x42, 0xc6, 0x7b, - 0x04, 0x4c, 0xc6, 0x6b, + 0xff, 0x42, 0xcc, 0x7b, + 0x04, 0x4c, 0xcc, 0x6b, 0xe0, 0x41, 0x6c, 0x0a, - 0xe0, 0x36, 0xf7, 0x61, + 0xe0, 0x36, 0xf9, 0x61, 0xff, 0xea, 0xca, 0x09, 0x01, 0xe2, 0xc8, 0x31, 0x01, 0x46, 0xda, 0x35, 0x01, 0x44, 0xd4, 0x35, 0x10, 0xea, 0x80, 0x00, 0x01, 0xe2, 0x62, 0x36, - 0x04, 0xa6, 0xde, 0x7b, + 0x04, 0xa6, 0xe4, 0x7b, 0xff, 0xea, 0x5a, 0x09, 0xff, 0xea, 0x4c, 0x0d, - 0x01, 0xa6, 0xfc, 0x6b, + 0x01, 0xa6, 0x02, 0x6c, 0x10, 0xad, 0x64, 0x78, - 0x80, 0xad, 0xf4, 0x6b, + 0x80, 0xad, 0xfa, 0x6b, 0x08, 0xad, 0x64, 0x68, 0x04, 0x84, 0xf9, 0x30, 0x00, 0xea, 0x08, 0x81, @@ -521,8 +524,6 @@ 0x08, 0xb0, 0xe0, 0x30, 0x04, 0xb0, 0xe0, 0x30, 0x03, 0xb0, 0xf0, 0x30, - 0x01, 0x78, 0x0a, 0x7c, - 0x01, 0xa7, 0x4e, 0x11, 0x01, 0xb0, 0x06, 0x33, 0x7f, 0x83, 0xe9, 0x08, 0x04, 0xac, 0x58, 0x19, @@ -532,9 +533,7 @@ 0x00, 0x86, 0x0d, 0x23, 0x00, 0x87, 0x0f, 0x23, 0x01, 0x84, 0xc5, 0x31, - 0x01, 0xa7, 0x20, 0x7c, - 0x04, 0xe2, 0xc4, 0x01, - 0x80, 0x83, 0x27, 0x7c, + 0x80, 0x83, 0x25, 0x7c, 0x02, 0xe2, 0xc4, 0x01, 0xff, 0xea, 0x4c, 0x09, 0x01, 0xe2, 0x36, 0x30, @@ -544,86 +543,80 @@ 0x00, 0xe2, 0x64, 0x50, 0xfe, 0xa6, 0x4c, 0x0d, 0x0b, 0x90, 0xe1, 0x30, - 0x01, 0x98, 0x4f, 0x09, 0xfd, 0x9c, 0x49, 0x09, - 0x80, 0x9b, 0x3d, 0x7c, + 0x80, 0x9b, 0x39, 0x7c, 0x02, 0xa4, 0x48, 0x01, - 0x01, 0xa7, 0x40, 0x7c, - 0x04, 0xa4, 0x48, 0x01, 0x01, 0xa4, 0x36, 0x30, 0xa8, 0xea, 0x32, 0x00, 0xfd, 0x9c, 0x39, 0x0b, 0x05, 0x9b, 0x07, 0x33, - 0x80, 0x83, 0x4d, 0x6c, + 0x80, 0x83, 0x45, 0x6c, 0x02, 0xea, 0x4c, 0x05, 0xff, 0xea, 0x4c, 0x0d, - 0x00, 0xe2, 0x3c, 0x59, - 0x02, 0xa6, 0xe0, 0x6b, + 0x00, 0xe2, 0x3e, 0x59, + 0x02, 0xa6, 0xe6, 0x6b, 0x80, 0xf9, 0xf2, 0x05, - 0xc0, 0x33, 0x5b, 0x7c, - 0x03, 0xea, 0x4e, 0x59, + 0xc0, 0x33, 0x53, 0x7c, + 0x03, 0xea, 0x50, 0x59, 0x03, 0xea, 0x04, 0x00, - 0x20, 0x33, 0x7f, 0x7c, - 0x01, 0x84, 0x65, 0x6c, - 0x06, 0xea, 0x4e, 0x59, + 0x20, 0x33, 0x77, 0x7c, + 0x01, 0x84, 0x5d, 0x6c, + 0x06, 0xea, 0x50, 0x59, 0x06, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0x82, 0x44, + 0x00, 0xe2, 0x7a, 0x44, 0x01, 0x00, 0x60, 0x32, - 0xee, 0x00, 0x6e, 0x6c, + 0xee, 0x00, 0x66, 0x6c, 0x05, 0xea, 0xb4, 0x00, - 0x33, 0xea, 0x42, 0x59, + 0x33, 0xea, 0x44, 0x59, 0x33, 0xea, 0x00, 0x00, 0x80, 0x3d, 0x7a, 0x00, - 0xfc, 0x42, 0x70, 0x7c, + 0xfc, 0x42, 0x68, 0x7c, 0x7f, 0x3d, 0x7a, 0x08, - 0x00, 0x30, 0x43, 0x59, + 0x00, 0x30, 0x45, 0x59, 0x01, 0x30, 0x01, 0x30, - 0x09, 0xea, 0x4e, 0x59, + 0x09, 0xea, 0x50, 0x59, 0x09, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xf6, 0x41, - 0x01, 0x9c, 0x65, 0x6c, - 0x00, 0xe2, 0x32, 0x5c, + 0x00, 0xe2, 0xf8, 0x41, + 0x01, 0x9c, 0x5d, 0x6c, + 0x00, 0xe2, 0x30, 0x5c, 0x20, 0x33, 0x67, 0x02, 0x01, 0x00, 0x60, 0x32, - 0x02, 0xa6, 0x8a, 0x7c, - 0x00, 0xe2, 0x4e, 0x5c, + 0x02, 0xa6, 0x82, 0x7c, + 0x00, 0xe2, 0x46, 0x5c, 0x00, 0xe2, 0x56, 0x58, 0x00, 0xe2, 0x66, 0x58, 0x00, 0xe2, 0x3a, 0x58, - 0x00, 0x30, 0x43, 0x59, + 0x00, 0x30, 0x45, 0x59, 0x01, 0x30, 0x01, 0x30, - 0x20, 0x19, 0x8a, 0x6c, - 0x00, 0xe2, 0xba, 0x5c, - 0x04, 0x19, 0xa4, 0x6c, + 0x20, 0x19, 0x82, 0x6c, + 0x00, 0xe2, 0xb2, 0x5c, + 0x04, 0x19, 0x9c, 0x6c, 0x02, 0x19, 0x32, 0x00, - 0x01, 0x84, 0xa5, 0x7c, - 0x01, 0x1b, 0x9e, 0x7c, - 0x01, 0x1a, 0xa4, 0x6c, - 0x00, 0xe2, 0x54, 0x44, - 0x80, 0x4b, 0xaa, 0x6c, - 0x01, 0x4c, 0xa6, 0x7c, - 0x03, 0x42, 0x54, 0x6c, - 0x00, 0xe2, 0xda, 0x5b, + 0x01, 0x84, 0x9d, 0x7c, + 0x01, 0x1b, 0x96, 0x7c, + 0x01, 0x1a, 0x9c, 0x6c, + 0x00, 0xe2, 0x4c, 0x44, + 0x80, 0x4b, 0xa2, 0x6c, + 0x01, 0x4c, 0x9e, 0x7c, + 0x03, 0x42, 0x4c, 0x6c, + 0x00, 0xe2, 0xe0, 0x5b, 0x80, 0xf9, 0xf2, 0x01, - 0x04, 0x33, 0xf7, 0x79, - 0x00, 0xe2, 0xf6, 0x41, - 0x08, 0x5d, 0xc2, 0x6c, + 0x04, 0x33, 0xf9, 0x79, + 0x00, 0xe2, 0xf8, 0x41, + 0x08, 0x5d, 0xba, 0x6c, 0x00, 0xe2, 0x56, 0x58, - 0x00, 0x30, 0x43, 0x59, + 0x00, 0x30, 0x45, 0x59, 0x01, 0x30, 0x01, 0x30, - 0x02, 0x1b, 0xb2, 0x7c, - 0x08, 0x5d, 0xc0, 0x7c, + 0x02, 0x1b, 0xaa, 0x7c, + 0x08, 0x5d, 0xb8, 0x7c, 0x03, 0x68, 0x00, 0x37, 0x01, 0x84, 0x09, 0x07, - 0x80, 0x1b, 0xcc, 0x7c, - 0x80, 0x84, 0xcd, 0x6c, + 0x80, 0x1b, 0xc4, 0x7c, + 0x80, 0x84, 0xc5, 0x6c, 0xff, 0x85, 0x0b, 0x1b, 0xff, 0x86, 0x0d, 0x23, 0xff, 0x87, 0x0f, 0x23, 0xf8, 0x1b, 0x08, 0x0b, - 0xff, 0xea, 0x4e, 0x09, - 0x04, 0x1b, 0xd4, 0x7c, - 0x01, 0xa7, 0x4e, 0x01, 0xff, 0xea, 0x06, 0x0b, 0x03, 0x68, 0x00, 0x37, 0x00, 0xe2, 0xc4, 0x58, @@ -631,161 +624,161 @@ 0xf9, 0xd9, 0xb2, 0x0d, 0x01, 0xd9, 0xb2, 0x05, 0x01, 0x52, 0x48, 0x31, - 0x20, 0xa4, 0xfc, 0x7c, - 0x20, 0x5b, 0xfc, 0x7c, - 0x80, 0xf9, 0x0a, 0x7d, + 0x20, 0xa4, 0xee, 0x7c, + 0x20, 0x5b, 0xee, 0x7c, + 0x80, 0xf9, 0xfc, 0x7c, 0x02, 0xea, 0xb4, 0x00, 0x11, 0x00, 0x00, 0x10, - 0x04, 0x19, 0x16, 0x7d, + 0x04, 0x19, 0x08, 0x7d, 0xdf, 0x19, 0x32, 0x08, - 0x60, 0x5b, 0xf4, 0x6c, - 0x01, 0x4c, 0xf0, 0x7c, + 0x60, 0x5b, 0xe6, 0x6c, + 0x01, 0x4c, 0xe2, 0x7c, 0x20, 0x19, 0x32, 0x00, 0x01, 0xd9, 0xb2, 0x05, 0x02, 0xea, 0xb4, 0x00, 0x01, 0xd9, 0xb2, 0x05, - 0x10, 0x5b, 0x0e, 0x6d, - 0x08, 0x5b, 0x18, 0x6d, - 0x20, 0x5b, 0x08, 0x6d, - 0x02, 0x5b, 0x38, 0x6d, - 0x0e, 0xea, 0x4e, 0x59, + 0x10, 0x5b, 0x00, 0x6d, + 0x08, 0x5b, 0x0a, 0x6d, + 0x20, 0x5b, 0xfa, 0x6c, + 0x02, 0x5b, 0x2a, 0x6d, + 0x0e, 0xea, 0x50, 0x59, 0x0e, 0xea, 0x04, 0x00, - 0x80, 0xf9, 0xf8, 0x6c, + 0x80, 0xf9, 0xea, 0x6c, 0xdf, 0x5c, 0xb8, 0x08, 0x01, 0xd9, 0xb2, 0x05, - 0x01, 0x9c, 0xf3, 0x6d, - 0x00, 0xe2, 0x32, 0x5c, - 0x00, 0xe2, 0x42, 0x5d, + 0x01, 0x9c, 0xe5, 0x6d, + 0x00, 0xe2, 0x30, 0x5c, + 0x00, 0xe2, 0x34, 0x5d, 0x01, 0xae, 0x5d, 0x1b, 0x01, 0xd9, 0xb2, 0x05, - 0x00, 0xe2, 0x2c, 0x5b, + 0x00, 0xe2, 0x32, 0x5b, 0xf3, 0xac, 0xd5, 0x19, - 0x00, 0xe2, 0x26, 0x55, - 0x80, 0xac, 0x27, 0x6d, - 0x0f, 0xea, 0x4e, 0x59, + 0x00, 0xe2, 0x18, 0x55, + 0x80, 0xac, 0x19, 0x6d, + 0x0f, 0xea, 0x50, 0x59, 0x0f, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0x2e, 0x45, + 0x00, 0xe2, 0x20, 0x45, 0x04, 0x8c, 0xe1, 0x30, 0x01, 0xea, 0xf2, 0x00, 0x02, 0xea, 0x36, 0x00, 0xa8, 0xea, 0x32, 0x00, - 0xff, 0xad, 0x35, 0x7d, - 0x14, 0xea, 0x4e, 0x59, + 0xff, 0xad, 0x27, 0x7d, + 0x14, 0xea, 0x50, 0x59, 0x14, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xa4, 0x5d, + 0x00, 0xe2, 0x96, 0x5d, 0x01, 0xd9, 0xb2, 0x05, 0x09, 0x80, 0xe1, 0x30, 0x02, 0xea, 0x36, 0x00, 0xa8, 0xea, 0x32, 0x00, - 0x00, 0xe2, 0x9c, 0x5d, + 0x00, 0xe2, 0x8e, 0x5d, 0x01, 0xd9, 0xb2, 0x05, - 0x02, 0xa6, 0x52, 0x7d, - 0x00, 0xe2, 0x3c, 0x59, - 0x20, 0x5b, 0x60, 0x6d, - 0xfc, 0x42, 0x4c, 0x7d, - 0x10, 0x40, 0x4e, 0x6d, - 0x20, 0x4d, 0x50, 0x7d, - 0x08, 0x5d, 0x60, 0x6d, - 0x02, 0xa6, 0xe0, 0x6b, - 0x00, 0xe2, 0x3c, 0x59, - 0x20, 0x5b, 0x60, 0x6d, - 0x01, 0x1b, 0x80, 0x6d, - 0xfc, 0x42, 0x5c, 0x7d, - 0x10, 0x40, 0x5e, 0x6d, + 0x02, 0xa6, 0x44, 0x7d, + 0x00, 0xe2, 0x3e, 0x59, + 0x20, 0x5b, 0x52, 0x6d, + 0xfc, 0x42, 0x3e, 0x7d, + 0x10, 0x40, 0x40, 0x6d, + 0x20, 0x4d, 0x42, 0x7d, + 0x08, 0x5d, 0x52, 0x6d, + 0x02, 0xa6, 0xe6, 0x6b, + 0x00, 0xe2, 0x3e, 0x59, + 0x20, 0x5b, 0x52, 0x6d, + 0x01, 0x1b, 0x72, 0x6d, + 0xfc, 0x42, 0x4e, 0x7d, + 0x10, 0x40, 0x50, 0x6d, 0x20, 0x4d, 0x64, 0x78, 0x08, 0x5d, 0x64, 0x78, 0x02, 0x19, 0x32, 0x00, 0x01, 0x5b, 0x40, 0x31, - 0x00, 0xe2, 0xba, 0x5c, - 0x00, 0xe2, 0x98, 0x5b, + 0x00, 0xe2, 0xb2, 0x5c, + 0x00, 0xe2, 0x9e, 0x5b, 0x20, 0xea, 0xb6, 0x00, - 0x00, 0xe2, 0xda, 0x5b, + 0x00, 0xe2, 0xe0, 0x5b, 0x20, 0x5c, 0xb8, 0x00, - 0x04, 0x19, 0x76, 0x6d, - 0x01, 0x1a, 0x76, 0x6d, - 0x00, 0xe2, 0x3c, 0x59, + 0x04, 0x19, 0x68, 0x6d, + 0x01, 0x1a, 0x68, 0x6d, + 0x00, 0xe2, 0x3e, 0x59, 0x01, 0x1a, 0x64, 0x78, 0x80, 0xf9, 0xf2, 0x01, - 0x20, 0xa0, 0xda, 0x7d, + 0x20, 0xa0, 0xcc, 0x7d, 0xff, 0xae, 0x5d, 0x1b, - 0x08, 0xa8, 0x3d, 0x6b, + 0x08, 0xa8, 0x43, 0x6b, 0x02, 0xea, 0xb4, 0x04, 0x01, 0x9c, 0x39, 0x03, - 0x40, 0x5b, 0x90, 0x6d, - 0x00, 0xe2, 0x3c, 0x59, - 0x40, 0x5b, 0x90, 0x6d, - 0x04, 0x5d, 0xf4, 0x7d, - 0x01, 0x1a, 0xf4, 0x7d, + 0x40, 0x5b, 0x82, 0x6d, + 0x00, 0xe2, 0x3e, 0x59, + 0x40, 0x5b, 0x82, 0x6d, + 0x04, 0x5d, 0xe6, 0x7d, + 0x01, 0x1a, 0xe6, 0x7d, 0x20, 0x4d, 0x64, 0x78, - 0x40, 0x5b, 0xda, 0x7d, - 0x04, 0x5d, 0xf4, 0x7d, - 0x01, 0x1a, 0xf4, 0x7d, + 0x40, 0x5b, 0xcc, 0x7d, + 0x04, 0x5d, 0xe6, 0x7d, + 0x01, 0x1a, 0xe6, 0x7d, 0x80, 0xf9, 0xf2, 0x01, 0xff, 0xae, 0x5d, 0x1b, - 0x08, 0xa8, 0x3d, 0x6b, + 0x08, 0xa8, 0x43, 0x6b, 0x02, 0xea, 0xb4, 0x04, - 0x00, 0xe2, 0x3c, 0x59, + 0x00, 0xe2, 0x3e, 0x59, 0x01, 0x1b, 0x64, 0x78, 0x80, 0xf9, 0xf2, 0x01, 0x02, 0xea, 0xb4, 0x04, - 0x00, 0xe2, 0x3c, 0x59, - 0x01, 0x1b, 0xb8, 0x6d, - 0x40, 0x5b, 0xc6, 0x7d, - 0x01, 0x1b, 0xb8, 0x6d, + 0x00, 0xe2, 0x3e, 0x59, + 0x01, 0x1b, 0xaa, 0x6d, + 0x40, 0x5b, 0xb8, 0x7d, + 0x01, 0x1b, 0xaa, 0x6d, 0x02, 0x19, 0x32, 0x00, 0x01, 0x1a, 0x64, 0x78, 0x80, 0xf9, 0xf2, 0x01, 0xff, 0xea, 0x10, 0x03, 0x08, 0xa8, 0x51, 0x03, - 0x00, 0xe2, 0x3c, 0x43, - 0x01, 0x1a, 0xc2, 0x7d, - 0x40, 0x5b, 0xbe, 0x7d, - 0x01, 0x1a, 0xac, 0x6d, + 0x00, 0xe2, 0x42, 0x43, + 0x01, 0x1a, 0xb4, 0x7d, + 0x40, 0x5b, 0xb0, 0x7d, + 0x01, 0x1a, 0x9e, 0x6d, 0xfc, 0x42, 0x64, 0x78, - 0x01, 0x1a, 0xc6, 0x6d, - 0x10, 0xea, 0x4e, 0x59, + 0x01, 0x1a, 0xb8, 0x6d, + 0x10, 0xea, 0x50, 0x59, 0x10, 0xea, 0x04, 0x00, 0xfc, 0x42, 0x64, 0x78, - 0x10, 0x40, 0xcc, 0x6d, + 0x10, 0x40, 0xbe, 0x6d, 0x20, 0x4d, 0x64, 0x78, - 0x40, 0x5b, 0xac, 0x6d, + 0x40, 0x5b, 0x9e, 0x6d, 0x01, 0x1a, 0x64, 0x78, 0x01, 0xae, 0x5d, 0x1b, 0x30, 0x3f, 0xc0, 0x09, 0x30, 0xe0, 0x64, 0x60, 0x40, 0x4b, 0x64, 0x68, 0xff, 0xea, 0x52, 0x01, - 0xee, 0x00, 0xe0, 0x6d, + 0xee, 0x00, 0xd2, 0x6d, 0x80, 0xf9, 0xf2, 0x01, 0xff, 0xae, 0x5d, 0x1b, 0x02, 0xea, 0xb4, 0x00, 0x20, 0xea, 0x9a, 0x00, - 0xf3, 0x42, 0xec, 0x6d, - 0x12, 0xea, 0x4e, 0x59, + 0xf3, 0x42, 0xde, 0x6d, + 0x12, 0xea, 0x50, 0x59, 0x12, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xf6, 0x41, - 0x0d, 0xea, 0x4e, 0x59, + 0x00, 0xe2, 0xf8, 0x41, + 0x0d, 0xea, 0x50, 0x59, 0x0d, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0xf6, 0x41, + 0x00, 0xe2, 0xf8, 0x41, 0x01, 0xae, 0x5d, 0x1b, - 0x11, 0xea, 0x4e, 0x59, + 0x11, 0xea, 0x50, 0x59, 0x11, 0xea, 0x04, 0x00, - 0x00, 0xe2, 0x2c, 0x5b, + 0x00, 0xe2, 0x32, 0x5b, 0x08, 0x5a, 0xb4, 0x00, - 0x00, 0xe2, 0x1a, 0x5e, + 0x00, 0xe2, 0x0c, 0x5e, 0xa8, 0xea, 0x32, 0x00, - 0x00, 0xe2, 0x3c, 0x59, - 0x80, 0x1a, 0x08, 0x7e, - 0x00, 0xe2, 0x1a, 0x5e, + 0x00, 0xe2, 0x3e, 0x59, + 0x80, 0x1a, 0xfa, 0x7d, + 0x00, 0xe2, 0x0c, 0x5e, 0x80, 0x19, 0x32, 0x00, - 0x40, 0x5b, 0x0e, 0x6e, - 0x08, 0x5a, 0x0e, 0x7e, + 0x40, 0x5b, 0x00, 0x6e, + 0x08, 0x5a, 0x00, 0x7e, 0x20, 0x4d, 0x64, 0x78, 0x02, 0x84, 0x09, 0x03, - 0x40, 0x5b, 0xda, 0x7d, + 0x40, 0x5b, 0xcc, 0x7d, 0xff, 0xae, 0x5d, 0x1b, 0x80, 0xf9, 0xf2, 0x01, - 0x08, 0xa8, 0x3d, 0x6b, + 0x08, 0xa8, 0x43, 0x6b, 0x02, 0xea, 0xb4, 0x04, 0x01, 0x38, 0xe1, 0x30, 0x05, 0x39, 0xe3, 0x98, @@ -801,12 +794,20 @@ }; typedef int ahd_patch_func_t (struct ahd_softc *ahd); +static ahd_patch_func_t ahd_patch22_func; + +static int +ahd_patch22_func(struct ahd_softc *ahd) +{ + return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0); +} + static ahd_patch_func_t ahd_patch21_func; static int ahd_patch21_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0); + return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) == 0); } static ahd_patch_func_t ahd_patch20_func; @@ -814,7 +815,7 @@ static int ahd_patch20_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) == 0); + return ((ahd->features & AHD_RTI) == 0); } static ahd_patch_func_t ahd_patch19_func; @@ -822,7 +823,7 @@ static int ahd_patch19_func(struct ahd_softc *ahd) { - return ((ahd->features & AHD_RTI) == 0); + return ((ahd->flags & AHD_INITIATORROLE) != 0); } static ahd_patch_func_t ahd_patch18_func; @@ -830,7 +831,7 @@ static int ahd_patch18_func(struct ahd_softc *ahd) { - return ((ahd->flags & AHD_INITIATORROLE) != 0); + return ((ahd->flags & AHD_TARGETROLE) != 0); } static ahd_patch_func_t ahd_patch17_func; @@ -838,7 +839,7 @@ static int ahd_patch17_func(struct ahd_softc *ahd) { - return ((ahd->flags & AHD_TARGETROLE) != 0); + return ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0); } static ahd_patch_func_t ahd_patch16_func; @@ -846,7 +847,7 @@ static int ahd_patch16_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0); + return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) != 0); } static ahd_patch_func_t ahd_patch15_func; @@ -854,7 +855,7 @@ static int ahd_patch15_func(struct ahd_softc *ahd) { - return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) != 0); + return ((ahd->flags & AHD_39BIT_ADDRESSING) != 0); } static ahd_patch_func_t ahd_patch14_func; @@ -862,7 +863,7 @@ static int ahd_patch14_func(struct ahd_softc *ahd) { - return ((ahd->flags & AHD_39BIT_ADDRESSING) != 0); + return ((ahd->flags & AHD_64BIT_ADDRESSING) != 0); } static ahd_patch_func_t ahd_patch13_func; @@ -870,7 +871,7 @@ static int ahd_patch13_func(struct ahd_softc *ahd) { - return ((ahd->flags & AHD_64BIT_ADDRESSING) != 0); + return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) == 0); } static ahd_patch_func_t ahd_patch12_func; @@ -878,7 +879,7 @@ static int ahd_patch12_func(struct ahd_softc *ahd) { - return ((ahd->features & AHD_NEW_DFCNTRL_OPTS) == 0); + return ((ahd->bugs & AHD_REG_SLOW_SETTLE_BUG) != 0); } static ahd_patch_func_t ahd_patch11_func; @@ -886,7 +887,7 @@ static int ahd_patch11_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_REG_SLOW_SETTLE_BUG) != 0); + return ((ahd->bugs & AHD_EARLY_REQ_BUG) != 0); } static ahd_patch_func_t ahd_patch10_func; @@ -894,7 +895,7 @@ static int ahd_patch10_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_EARLY_REQ_BUG) != 0); + return ((ahd->bugs & AHD_BUSFREEREV_BUG) == 0); } static ahd_patch_func_t ahd_patch9_func; @@ -902,7 +903,7 @@ static int ahd_patch9_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_BUSFREEREV_BUG) == 0); + return ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0); } static ahd_patch_func_t ahd_patch8_func; @@ -910,7 +911,7 @@ static int ahd_patch8_func(struct ahd_softc *ahd) { - return ((ahd->flags & AHD_SEQUENCER_DEBUG) != 0); + return ((ahd->bugs & AHD_LQO_ATNO_BUG) != 0); } static ahd_patch_func_t ahd_patch7_func; @@ -918,7 +919,7 @@ static int ahd_patch7_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_LQO_ATNO_BUG) != 0); + return ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0); } static ahd_patch_func_t ahd_patch6_func; @@ -926,7 +927,7 @@ static int ahd_patch6_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_BUSFREEREV_BUG) != 0); + return ((ahd->bugs & AHD_NONPACKFIFO_BUG) != 0); } static ahd_patch_func_t ahd_patch5_func; @@ -934,7 +935,7 @@ static int ahd_patch5_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_NONPACKFIFO_BUG) != 0); + return ((ahd->bugs & AHD_SENT_SCB_UPDATE_BUG) != 0); } static ahd_patch_func_t ahd_patch4_func; @@ -942,7 +943,7 @@ static int ahd_patch4_func(struct ahd_softc *ahd) { - return ((ahd->bugs & AHD_SENT_SCB_UPDATE_BUG) != 0); + return ((ahd->bugs & AHD_PKT_LUN_BUG) != 0); } static ahd_patch_func_t ahd_patch3_func; @@ -1008,109 +1009,112 @@ { ahd_patch0_func, 70, 1, 1 }, { ahd_patch1_func, 73, 1, 2 }, { ahd_patch0_func, 74, 1, 1 }, - { ahd_patch2_func, 161, 6, 1 }, - { ahd_patch1_func, 167, 2, 1 }, - { ahd_patch4_func, 169, 1, 1 }, - { ahd_patch2_func, 178, 1, 2 }, - { ahd_patch0_func, 179, 1, 1 }, - { ahd_patch5_func, 180, 2, 2 }, - { ahd_patch0_func, 182, 6, 3 }, - { ahd_patch2_func, 185, 1, 2 }, - { ahd_patch0_func, 186, 1, 1 }, - { ahd_patch2_func, 189, 1, 2 }, - { ahd_patch0_func, 190, 1, 1 }, - { ahd_patch6_func, 192, 2, 1 }, - { ahd_patch4_func, 200, 16, 2 }, - { ahd_patch0_func, 216, 1, 1 }, - { ahd_patch7_func, 236, 2, 1 }, - { ahd_patch1_func, 240, 1, 2 }, - { ahd_patch0_func, 241, 1, 1 }, - { ahd_patch6_func, 244, 2, 1 }, - { ahd_patch1_func, 258, 1, 2 }, - { ahd_patch0_func, 259, 1, 1 }, - { ahd_patch1_func, 262, 1, 2 }, - { ahd_patch0_func, 263, 1, 1 }, - { ahd_patch2_func, 266, 1, 2 }, - { ahd_patch0_func, 267, 1, 1 }, - { ahd_patch1_func, 322, 1, 2 }, - { ahd_patch0_func, 323, 1, 1 }, - { ahd_patch2_func, 331, 1, 2 }, - { ahd_patch0_func, 332, 1, 1 }, - { ahd_patch2_func, 335, 1, 2 }, - { ahd_patch0_func, 336, 1, 1 }, + { ahd_patch4_func, 107, 1, 1 }, + { ahd_patch2_func, 162, 6, 1 }, + { ahd_patch1_func, 168, 2, 1 }, + { ahd_patch5_func, 170, 1, 1 }, + { ahd_patch2_func, 179, 1, 2 }, + { ahd_patch0_func, 180, 1, 1 }, + { ahd_patch6_func, 181, 2, 2 }, + { ahd_patch0_func, 183, 6, 3 }, + { ahd_patch2_func, 186, 1, 2 }, + { ahd_patch0_func, 187, 1, 1 }, + { ahd_patch2_func, 190, 1, 2 }, + { ahd_patch0_func, 191, 1, 1 }, + { ahd_patch7_func, 193, 2, 1 }, + { ahd_patch5_func, 201, 16, 2 }, + { ahd_patch0_func, 217, 1, 1 }, + { ahd_patch8_func, 237, 2, 1 }, + { ahd_patch1_func, 241, 1, 2 }, + { ahd_patch0_func, 242, 1, 1 }, + { ahd_patch7_func, 245, 2, 1 }, + { ahd_patch1_func, 259, 1, 2 }, + { ahd_patch0_func, 260, 1, 1 }, + { ahd_patch1_func, 263, 1, 2 }, + { ahd_patch0_func, 264, 1, 1 }, + { ahd_patch2_func, 267, 1, 2 }, + { ahd_patch0_func, 268, 1, 1 }, + { ahd_patch1_func, 323, 1, 2 }, + { ahd_patch0_func, 324, 1, 1 }, + { ahd_patch2_func, 332, 1, 2 }, + { ahd_patch0_func, 333, 1, 1 }, + { ahd_patch2_func, 336, 1, 2 }, + { ahd_patch0_func, 337, 1, 1 }, { ahd_patch1_func, 343, 1, 2 }, { ahd_patch0_func, 344, 1, 1 }, - { ahd_patch8_func, 363, 1, 1 }, - { ahd_patch8_func, 366, 1, 1 }, - { ahd_patch8_func, 368, 1, 1 }, - { ahd_patch8_func, 380, 1, 1 }, - { ahd_patch1_func, 390, 1, 2 }, - { ahd_patch0_func, 391, 1, 1 }, + { ahd_patch1_func, 346, 1, 2 }, + { ahd_patch0_func, 347, 1, 1 }, + { ahd_patch9_func, 366, 1, 1 }, + { ahd_patch9_func, 369, 1, 1 }, + { ahd_patch9_func, 371, 1, 1 }, + { ahd_patch9_func, 383, 1, 1 }, { ahd_patch1_func, 393, 1, 2 }, { ahd_patch0_func, 394, 1, 1 }, - { ahd_patch1_func, 402, 1, 2 }, - { ahd_patch0_func, 403, 1, 1 }, - { ahd_patch2_func, 416, 1, 2 }, - { ahd_patch0_func, 417, 1, 1 }, - { ahd_patch9_func, 447, 1, 1 }, - { ahd_patch1_func, 454, 1, 2 }, - { ahd_patch0_func, 455, 1, 1 }, - { ahd_patch2_func, 467, 1, 2 }, - { ahd_patch0_func, 468, 1, 1 }, - { ahd_patch10_func, 473, 6, 2 }, - { ahd_patch0_func, 479, 1, 1 }, - { ahd_patch11_func, 502, 1, 1 }, - { ahd_patch12_func, 511, 1, 1 }, - { ahd_patch13_func, 512, 1, 2 }, - { ahd_patch0_func, 513, 1, 1 }, - { ahd_patch14_func, 518, 1, 1 }, - { ahd_patch13_func, 519, 1, 1 }, - { ahd_patch15_func, 532, 1, 2 }, - { ahd_patch0_func, 533, 1, 1 }, + { ahd_patch1_func, 396, 1, 2 }, + { ahd_patch0_func, 397, 1, 1 }, + { ahd_patch1_func, 405, 1, 2 }, + { ahd_patch0_func, 406, 1, 1 }, + { ahd_patch2_func, 419, 1, 2 }, + { ahd_patch0_func, 420, 1, 1 }, + { ahd_patch10_func, 450, 1, 1 }, + { ahd_patch1_func, 457, 1, 2 }, + { ahd_patch0_func, 458, 1, 1 }, + { ahd_patch2_func, 470, 1, 2 }, + { ahd_patch0_func, 471, 1, 1 }, + { ahd_patch11_func, 476, 6, 2 }, + { ahd_patch0_func, 482, 1, 1 }, + { ahd_patch12_func, 505, 1, 1 }, + { ahd_patch13_func, 514, 1, 1 }, + { ahd_patch14_func, 515, 1, 2 }, + { ahd_patch0_func, 516, 1, 1 }, + { ahd_patch15_func, 519, 1, 1 }, + { ahd_patch14_func, 520, 1, 1 }, + { ahd_patch16_func, 531, 1, 2 }, + { ahd_patch0_func, 532, 1, 1 }, + { ahd_patch1_func, 551, 1, 2 }, + { ahd_patch0_func, 552, 1, 1 }, { ahd_patch1_func, 555, 1, 2 }, { ahd_patch0_func, 556, 1, 1 }, - { ahd_patch1_func, 559, 1, 2 }, - { ahd_patch0_func, 560, 1, 1 }, - { ahd_patch2_func, 565, 1, 2 }, - { ahd_patch0_func, 566, 1, 1 }, - { ahd_patch2_func, 570, 1, 2 }, - { ahd_patch0_func, 571, 1, 1 }, - { ahd_patch1_func, 572, 1, 2 }, - { ahd_patch0_func, 573, 1, 1 }, - { ahd_patch2_func, 584, 1, 2 }, - { ahd_patch0_func, 585, 1, 1 }, - { ahd_patch16_func, 589, 1, 1 }, - { ahd_patch17_func, 594, 1, 1 }, - { ahd_patch18_func, 595, 2, 1 }, - { ahd_patch17_func, 599, 1, 2 }, + { ahd_patch2_func, 561, 1, 2 }, + { ahd_patch0_func, 562, 1, 1 }, + { ahd_patch2_func, 566, 1, 2 }, + { ahd_patch0_func, 567, 1, 1 }, + { ahd_patch1_func, 568, 1, 2 }, + { ahd_patch0_func, 569, 1, 1 }, + { ahd_patch2_func, 580, 1, 2 }, + { ahd_patch0_func, 581, 1, 1 }, + { ahd_patch17_func, 585, 1, 1 }, + { ahd_patch18_func, 590, 1, 1 }, + { ahd_patch19_func, 591, 2, 1 }, + { ahd_patch18_func, 595, 1, 2 }, + { ahd_patch0_func, 596, 1, 1 }, + { ahd_patch2_func, 599, 1, 2 }, { ahd_patch0_func, 600, 1, 1 }, - { ahd_patch2_func, 603, 1, 2 }, - { ahd_patch0_func, 604, 1, 1 }, - { ahd_patch2_func, 622, 1, 2 }, - { ahd_patch0_func, 623, 1, 1 }, - { ahd_patch19_func, 624, 14, 1 }, - { ahd_patch1_func, 642, 1, 2 }, - { ahd_patch0_func, 643, 1, 1 }, - { ahd_patch19_func, 644, 1, 1 }, - { ahd_patch1_func, 656, 1, 2 }, - { ahd_patch0_func, 657, 1, 1 }, - { ahd_patch1_func, 664, 1, 2 }, - { ahd_patch0_func, 665, 1, 1 }, - { ahd_patch16_func, 688, 1, 1 }, - { ahd_patch16_func, 726, 1, 1 }, - { ahd_patch1_func, 737, 1, 2 }, - { ahd_patch0_func, 738, 1, 1 }, + { ahd_patch2_func, 615, 1, 2 }, + { ahd_patch0_func, 616, 1, 1 }, + { ahd_patch20_func, 617, 14, 1 }, + { ahd_patch1_func, 635, 1, 2 }, + { ahd_patch0_func, 636, 1, 1 }, + { ahd_patch20_func, 637, 1, 1 }, + { ahd_patch1_func, 649, 1, 2 }, + { ahd_patch0_func, 650, 1, 1 }, + { ahd_patch1_func, 657, 1, 2 }, + { ahd_patch0_func, 658, 1, 1 }, + { ahd_patch17_func, 681, 1, 1 }, + { ahd_patch17_func, 719, 1, 1 }, + { ahd_patch1_func, 730, 1, 2 }, + { ahd_patch0_func, 731, 1, 1 }, + { ahd_patch1_func, 748, 1, 2 }, + { ahd_patch0_func, 749, 1, 1 }, + { ahd_patch1_func, 751, 1, 2 }, + { ahd_patch0_func, 752, 1, 1 }, { ahd_patch1_func, 755, 1, 2 }, { ahd_patch0_func, 756, 1, 1 }, - { ahd_patch1_func, 758, 1, 2 }, - { ahd_patch0_func, 759, 1, 1 }, - { ahd_patch1_func, 762, 1, 2 }, - { ahd_patch0_func, 763, 1, 1 }, - { ahd_patch20_func, 765, 1, 2 }, - { ahd_patch0_func, 766, 2, 1 }, - { ahd_patch21_func, 769, 4, 2 }, - { ahd_patch0_func, 773, 1, 1 }, - { ahd_patch21_func, 781, 11, 1 } + { ahd_patch21_func, 758, 1, 2 }, + { ahd_patch0_func, 759, 2, 1 }, + { ahd_patch22_func, 762, 4, 2 }, + { ahd_patch0_func, 766, 1, 1 }, + { ahd_patch22_func, 774, 11, 1 } }; static struct cs { @@ -1121,14 +1125,14 @@ { 13, 14 }, { 29, 42 }, { 56, 59 }, - { 101, 127 }, - { 128, 156 }, - { 158, 161 }, - { 169, 177 }, - { 200, 249 }, - { 688, 704 }, - { 704, 718 }, - { 728, 732 } + { 101, 128 }, + { 129, 157 }, + { 159, 162 }, + { 170, 178 }, + { 201, 250 }, + { 681, 697 }, + { 697, 711 }, + { 721, 725 } }; static const int num_critical_sections = sizeof(critical_sections) diff -Nru a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h --- a/drivers/scsi/aic7xxx/aic7xxx.h Mon Jun 9 23:16:13 2003 +++ b/drivers/scsi/aic7xxx/aic7xxx.h Mon Jun 9 23:16:13 2003 @@ -37,7 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.h#75 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.h#77 $ * * $FreeBSD$ */ @@ -93,7 +93,7 @@ #define SCB_GET_CHANNEL(ahc, scb) \ SCSIID_CHANNEL(ahc, (scb)->hscb->scsiid) #define SCB_GET_LUN(scb) \ - ((scb)->hscb->lun) + ((scb)->hscb->lun & LID) #define SCB_GET_TARGET_OFFSET(ahc, scb) \ (SCB_GET_TARGET(ahc, scb) + (SCB_IS_SCSIBUS_B(ahc, scb) ? 8 : 0)) #define SCB_GET_TARGET_MASK(ahc, scb) \ @@ -1045,6 +1045,11 @@ */ struct target_cmd *targetcmds; uint8_t tqinfifonext; + + /* + * Cached copy of the sequencer control register. + */ + uint8_t seqctl; /* * Incoming and outgoing message handling. diff -Nru a/drivers/scsi/aic7xxx/aic7xxx.reg b/drivers/scsi/aic7xxx/aic7xxx.reg --- a/drivers/scsi/aic7xxx/aic7xxx.reg Mon Jun 9 23:16:19 2003 +++ b/drivers/scsi/aic7xxx/aic7xxx.reg Mon Jun 9 23:16:19 2003 @@ -39,7 +39,7 @@ * * $FreeBSD$ */ -VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#38 $" +VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#39 $" /* * This file is processed by the aic7xxx_asm utility for use in assembling @@ -1080,7 +1080,8 @@ mask OID 0x0f } SCB_LUN { - mask LID 0xff + field SCB_XFERLEN_ODD 0x80 + mask LID 0x3f size 1 } SCB_TAG { @@ -1239,7 +1240,6 @@ access_mode WO address 0x0fc mask SG_ADDR_MASK 0xf8 - field ODD_SEG 0x04 field LAST_SEG 0x02 field LAST_SEG_DONE 0x01 } @@ -1248,7 +1248,6 @@ access_mode RO address 0x0fc mask SG_ADDR_MASK 0xf8 - field ODD_SEG 0x04 field LAST_SEG 0x02 field LAST_SEG_DONE 0x01 } @@ -1477,14 +1476,6 @@ field ENAUTOATNO 0x08 field ENAUTOATNI 0x04 field ENAUTOATNP 0x02 - } - - /* - * Track whether the transfer byte count for - * the current data phase is odd. - */ - DATA_COUNT_ODD { - size 1 } } diff -Nru a/drivers/scsi/aic7xxx/aic7xxx.seq b/drivers/scsi/aic7xxx/aic7xxx.seq --- a/drivers/scsi/aic7xxx/aic7xxx.seq Mon Jun 9 23:16:16 2003 +++ b/drivers/scsi/aic7xxx/aic7xxx.seq Mon Jun 9 23:16:16 2003 @@ -40,7 +40,7 @@ * $FreeBSD$ */ -VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#54 $" +VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#56 $" PATCH_ARG_LIST = "struct ahc_softc *ahc" PREFIX = "ahc_" @@ -437,7 +437,7 @@ mov SCBPTR, WAITING_SCBH; mov WAITING_SCBH,SCB_NEXT; mov SAVED_SCSIID, SCB_SCSIID; - mov SAVED_LUN, SCB_LUN; + and SAVED_LUN, LID, SCB_LUN; call set_transfer_settings; if ((ahc->flags & AHC_TARGETROLE) != 0) { test SSTAT0, TARGET jz initiator_select; @@ -461,7 +461,7 @@ /* * Start out with a simple identify message. */ - or SCB_LUN, MSG_IDENTIFYFLAG call target_outb; + or SAVED_LUN, MSG_IDENTIFYFLAG call target_outb; /* * If we are the result of a tagged command, send @@ -768,16 +768,12 @@ /* Does the hardware have space for another SG entry? */ test DFSTATUS, PRELOAD_AVAIL jz return; bmov HADDR, CCSGRAM, 7; - test HCNT[0], 0x1 jz . + 2; - xor DATA_COUNT_ODD, 0x1; bmov SCB_RESIDUAL_DATACNT[3], CCSGRAM, 1; if ((ahc->flags & AHC_39BIT_ADDRESSING) != 0) { mov SCB_RESIDUAL_DATACNT[3] call set_hhaddr; } call sg_advance; mov SINDEX, SCB_RESIDUAL_SGPTR[0]; - test DATA_COUNT_ODD, 0x1 jz . + 2; - or SINDEX, ODD_SEG; test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2; or SINDEX, LAST_SEG; mov SG_CACHE_PRE, SINDEX; @@ -875,7 +871,6 @@ call calc_mwi_residual; } and SCB_RESIDUAL_SGPTR[0], ~SG_FULL_RESID; - and DATA_COUNT_ODD, 0x1, HCNT[0]; if ((ahc->features & AHC_ULTRA2) == 0) { if ((ahc->features & AHC_CMD_CHAN) != 0) { @@ -910,8 +905,6 @@ mov SINDEX, SCB_RESIDUAL_SGPTR[0]; test SCB_RESIDUAL_DATACNT[3], SG_LAST_SEG jz . + 2; or SINDEX, LAST_SEG; - test DATA_COUNT_ODD, 0x1 jz . + 2; - or SINDEX, ODD_SEG; mov SG_CACHE_PRE, SINDEX; mov DFCNTRL, DMAPARAMS; ultra2_dma_loop: @@ -1006,10 +999,8 @@ adc SCB_RESIDUAL_SGPTR[3], -1; sgptr_fixup_done: and SCB_RESIDUAL_SGPTR[0], SG_ADDR_MASK, SG_CACHE_SHADOW; - clr DATA_COUNT_ODD; - test SG_CACHE_SHADOW, ODD_SEG jz . + 2; - or DATA_COUNT_ODD, 0x1; - clr SCB_RESIDUAL_DATACNT[3]; /* We are not the last seg */ + /* We are not the last seg */ + and SCB_RESIDUAL_DATACNT[3], ~SG_LAST_SEG; residuals_correct: /* * Go ahead and shut down the DMA engine now. @@ -1053,11 +1044,19 @@ * LAST_SEG_DONE to come true on a completed transfer * and then test to see if the data FIFO is non-empty. */ - test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 4; + test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL + jz ultra2_wait_fifoemp; test SG_CACHE_SHADOW, LAST_SEG_DONE jz .; + /* + * FIFOEMP can lag LAST_SEG_DONE. Wait a few + * clocks before calling this an overrun. + */ + test DFSTATUS, FIFOEMP jnz ultra2_fifoempty; + test DFSTATUS, FIFOEMP jnz ultra2_fifoempty; test DFSTATUS, FIFOEMP jnz ultra2_fifoempty; /* Overrun */ jmp data_phase_loop; +ultra2_wait_fifoemp: test DFSTATUS, FIFOEMP jz .; } ultra2_fifoempty: @@ -1246,9 +1245,6 @@ } else { call set_stcnt_from_hcnt; } - /* Track odd'ness */ - test HCNT[0], 0x1 jz . + 2; - xor DATA_COUNT_ODD, 0x1; if ((ahc->flags & AHC_TARGETROLE) != 0) { test SSTAT0, TARGET jnz data_phase_loop; @@ -1350,7 +1346,7 @@ */ test DFCNTRL, DIRECTION jz target_ITloop; test SSTAT1, REQINIT jnz .; - test DATA_COUNT_ODD, 0x1 jz target_ITloop; + test SCB_LUN, SCB_XFERLEN_ODD jz target_ITloop; test SCSIRATE, WIDEXFER jz target_ITloop; /* * Issue an Ignore Wide Residue Message. @@ -1510,7 +1506,7 @@ cmp SINDEX, MSG_IDENTIFYFLAG jne p_mesgout_from_host; test SCB_CONTROL,MK_MESSAGE jnz host_message_loop; p_mesgout_identify: - or SINDEX, MSG_IDENTIFYFLAG|DISCENB, SCB_LUN; + or SINDEX, MSG_IDENTIFYFLAG|DISCENB, SAVED_LUN; test SCB_CONTROL, DISCENB jnz . + 2; and SINDEX, ~DISCENB; /* @@ -1587,7 +1583,7 @@ mvi ARG_1 call inb_next; cmp ARG_1, 0x01 jne mesgin_reject; test SCB_RESIDUAL_SGPTR[0], SG_LIST_NULL jz . + 2; - test DATA_COUNT_ODD, 0x1 jz mesgin_done; + test SCB_LUN, SCB_XFERLEN_ODD jnz mesgin_done; mvi IGN_WIDE_RES call set_seqint; jmp mesgin_done; } @@ -1716,7 +1712,7 @@ } test SCB_CONTROL, TAG_ENB jnz await_busfree; mov ARG_1, SCB_TAG; - mov SAVED_LUN, SCB_LUN; + and SAVED_LUN, LID, SCB_LUN; mov SCB_SCSIID call set_busy_target; jmp await_busfree; @@ -1859,7 +1855,7 @@ * at a time. So, if the lun doesn't match, look * for a tag message. */ - mov A, SCB_LUN; + and A, LID, SCB_LUN; cmp SAVED_LUN, A je setup_SCB_id_lun_okay; if ((ahc->flags & AHC_PAGESCBS) != 0) { /* @@ -1917,7 +1913,7 @@ or SEQ_FLAGS, 0x8; } setup_SCB_id_okay: - mov A, SCB_LUN; + and A, LID, SCB_LUN; cmp SAVED_LUN, A jne not_found_cleanup_scb; setup_SCB_id_lun_okay: if ((ahc->flags & AHC_SEQUENCER_DEBUG) != 0) { diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c --- a/drivers/scsi/aic7xxx/aic7xxx_core.c Mon Jun 9 23:16:11 2003 +++ b/drivers/scsi/aic7xxx/aic7xxx_core.c Mon Jun 9 23:16:11 2003 @@ -37,7 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#128 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#131 $ * * $FreeBSD$ */ @@ -202,7 +202,7 @@ struct ahc_devinfo *devinfo, cam_status status, char *message, int verbose_level); -#if AHC_TARGET_MODE +#ifdef AHC_TARGET_MODE static void ahc_setup_target_msgin(struct ahc_softc *ahc, struct ahc_devinfo *devinfo, struct scb *scb); @@ -291,7 +291,7 @@ ahc_inb(ahc, SEQ_FLAGS2) & ~SCB_DMA); } ahc_outb(ahc, MWI_RESIDUAL, 0); - ahc_outb(ahc, SEQCTL, FASTMODE); + ahc_outb(ahc, SEQCTL, ahc->seqctl); ahc_outb(ahc, SEQADDR0, 0); ahc_outb(ahc, SEQADDR1, 0); ahc_unpause(ahc); @@ -705,7 +705,7 @@ ahc->msgin_index = 0; } } -#if AHC_TARGET_MODE +#ifdef AHC_TARGET_MODE else { if (bus_phase == P_MESGOUT) { ahc->msg_type = @@ -1467,7 +1467,7 @@ else ahc_outb(ahc, SIMODE1, 0); ahc_outb(ahc, CLRINT, CLRSCSIINT); - ahc_outb(ahc, SEQCTL, ahc_inb(ahc, SEQCTL) | STEP); + ahc_outb(ahc, SEQCTL, ahc->seqctl | STEP); stepping = TRUE; } if ((ahc->features & AHC_DT) != 0) { @@ -1481,7 +1481,7 @@ if (stepping) { ahc_outb(ahc, SIMODE0, simode0); ahc_outb(ahc, SIMODE1, simode1); - ahc_outb(ahc, SEQCTL, ahc_inb(ahc, SEQCTL) & ~STEP); + ahc_outb(ahc, SEQCTL, ahc->seqctl); } } @@ -3573,7 +3573,7 @@ sgptr = ahc_inb(ahc, SCB_RESIDUAL_SGPTR); if ((sgptr & SG_LIST_NULL) != 0 - && ahc_inb(ahc, DATA_COUNT_ODD) == 1) { + && (ahc_inb(ahc, SCB_LUN) & SCB_XFERLEN_ODD) != 0) { /* * If the residual occurred on the last * transfer and the transfer request was @@ -3586,25 +3586,27 @@ uint32_t data_addr; uint32_t sglen; - /* Pull in the rest of the sgptr */ - sgptr |= (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 3) << 24) - | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 2) << 16) - | (ahc_inb(ahc, SCB_RESIDUAL_SGPTR + 1) << 8); - sgptr &= SG_PTR_MASK; - data_cnt = (ahc_inb(ahc, SCB_RESIDUAL_DATACNT+3) << 24) - | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT+2) << 16) - | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT+1) << 8) - | (ahc_inb(ahc, SCB_RESIDUAL_DATACNT)); - - data_addr = (ahc_inb(ahc, SHADDR + 3) << 24) - | (ahc_inb(ahc, SHADDR + 2) << 16) - | (ahc_inb(ahc, SHADDR + 1) << 8) - | (ahc_inb(ahc, SHADDR)); + /* Pull in all of the sgptr */ + sgptr = ahc_inl(ahc, SCB_RESIDUAL_SGPTR); + data_cnt = ahc_inl(ahc, SCB_RESIDUAL_DATACNT); + + if ((sgptr & SG_LIST_NULL) != 0) { + /* + * The residual data count is not updated + * for the command run to completion case. + * Explicitly zero the count. + */ + data_cnt &= ~AHC_SG_LEN_MASK; + } + + data_addr = ahc_inl(ahc, SHADDR); data_cnt += 1; data_addr -= 1; + sgptr &= SG_PTR_MASK; sg = ahc_sg_bus_to_virt(scb, sgptr); + /* * The residual sg ptr points to the next S/G * to load so we must go back one. @@ -3630,19 +3632,17 @@ */ sg++; sgptr = ahc_sg_virt_to_bus(scb, sg); - ahc_outb(ahc, SCB_RESIDUAL_SGPTR + 3, - sgptr >> 24); - ahc_outb(ahc, SCB_RESIDUAL_SGPTR + 2, - sgptr >> 16); - ahc_outb(ahc, SCB_RESIDUAL_SGPTR + 1, - sgptr >> 8); - ahc_outb(ahc, SCB_RESIDUAL_SGPTR, sgptr); } - - ahc_outb(ahc, SCB_RESIDUAL_DATACNT + 3, data_cnt >> 24); - ahc_outb(ahc, SCB_RESIDUAL_DATACNT + 2, data_cnt >> 16); - ahc_outb(ahc, SCB_RESIDUAL_DATACNT + 1, data_cnt >> 8); - ahc_outb(ahc, SCB_RESIDUAL_DATACNT, data_cnt); + ahc_outl(ahc, SCB_RESIDUAL_SGPTR, sgptr); + ahc_outl(ahc, SCB_RESIDUAL_DATACNT, data_cnt); + /* + * Toggle the "oddness" of the transfer length + * to handle this mid-transfer ignore wide + * residue. This ensures that the oddness is + * correct for subsequent data transfers. + */ + ahc_outb(ahc, SCB_LUN, + ahc_inb(ahc, SCB_LUN) ^ SCB_XFERLEN_ODD); } } } @@ -3826,6 +3826,12 @@ ahc->features = AHC_FENONE; ahc->bugs = AHC_BUGNONE; ahc->flags = AHC_FNONE; + /* + * Default to all error reporting enabled with the + * sequencer operating at its fastest speed. + * The bus attach code may modify this. + */ + ahc->seqctl = FASTMODE; for (i = 0; i < AHC_NUM_TARGETS; i++) TAILQ_INIT(&ahc->untagged_queues[i]); @@ -3986,7 +3992,7 @@ tstate = ahc->enabled_targets[i]; if (tstate != NULL) { -#if AHC_TARGET_MODE +#ifdef AHC_TARGET_MODE int j; for (j = 0; j < AHC_NUM_LUNS; j++) { @@ -4002,7 +4008,7 @@ free(tstate, M_DEVBUF); } } -#if AHC_TARGET_MODE +#ifdef AHC_TARGET_MODE if (ahc->black_hole != NULL) { xpt_free_path(ahc->black_hole->path); free(ahc->black_hole, M_DEVBUF); @@ -5120,7 +5126,7 @@ return (EBUSY); } -#if AHC_TARGET_MODE +#ifdef AHC_TARGET_MODE /* * XXX What about ATIOs that have not yet been serviced? * Perhaps we should just refuse to be suspended if we @@ -5221,7 +5227,7 @@ if (match != 0) match = ((lun == slun) || (lun == CAM_LUN_WILDCARD)); if (match != 0) { -#if AHC_TARGET_MODE +#ifdef AHC_TARGET_MODE int group; group = XPT_FC_GROUP(scb->io_ctx->ccb_h.func_code); @@ -5964,7 +5970,7 @@ * before the reset occurred. */ ahc_run_qoutfifo(ahc); -#if AHC_TARGET_MODE +#ifdef AHC_TARGET_MODE /* * XXX - In Twin mode, the tqinfifo may have commands * for an unaffected channel in it. However, if @@ -5996,7 +6002,7 @@ */ ahc_outb(ahc, SBLKCTL, sblkctl ^ SELBUSB); simode1 = ahc_inb(ahc, SIMODE1) & ~(ENBUSFREE|ENSCSIRST); -#if AHC_TARGET_MODE +#ifdef AHC_TARGET_MODE /* * Bus resets clear ENSELI, so we cannot * defer re-enabling bus reset interrupts @@ -6015,7 +6021,7 @@ } else { /* Case 2: A command from this bus is active or we're idle */ simode1 = ahc_inb(ahc, SIMODE1) & ~(ENBUSFREE|ENSCSIRST); -#if AHC_TARGET_MODE +#ifdef AHC_TARGET_MODE /* * Bus resets clear ENSELI, so we cannot * defer re-enabling bus reset interrupts diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_inline.h b/drivers/scsi/aic7xxx/aic7xxx_inline.h --- a/drivers/scsi/aic7xxx/aic7xxx_inline.h Mon Jun 9 23:16:20 2003 +++ b/drivers/scsi/aic7xxx/aic7xxx_inline.h Mon Jun 9 23:16:20 2003 @@ -37,7 +37,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_inline.h#42 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_inline.h#43 $ * * $FreeBSD$ */ @@ -453,6 +453,13 @@ || scb->hscb->next == SCB_LIST_NULL) panic("Attempt to queue invalid SCB tag %x:%x\n", scb->hscb->tag, scb->hscb->next); + + /* + * Setup data "oddness". + */ + scb->hscb->lun &= LID; + if (ahc_get_transfer_length(scb) & 0x1) + scb->hscb->lun |= SCB_XFERLEN_ODD; /* * Keep a history of SCBs we've downloaded in the qinfifo. diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c Mon Jun 9 23:16:07 2003 +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c Mon Jun 9 23:16:07 2003 @@ -1,7 +1,7 @@ /* * Adaptec AIC7xxx device driver for Linux. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.c#221 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.c#232 $ * * Copyright (c) 1994 John Aycock * The University of Calgary Department of Computer Science. @@ -141,11 +141,6 @@ #include <linux/mm.h> /* For fetching system memory size */ #include <linux/blk.h> /* For block_size() */ -#define __KERNEL_SYSCALLS__ - -#include <linux/unistd.h> -static int errno; - /* * Lock protecting manipulation of the ahc softc list. */ @@ -746,31 +741,11 @@ consumed = 1; sg->addr = ahc_htole32(addr & 0xFFFFFFFF); scb->platform_data->xfer_len += len; + if (sizeof(bus_addr_t) > 4 - && (ahc->flags & AHC_39BIT_ADDRESSING) != 0) { - /* - * Due to DAC restrictions, we can't - * cross a 4GB boundary. - */ - if ((addr ^ (addr + len - 1)) & ~0xFFFFFFFF) { - struct ahc_dma_seg *next_sg; - uint32_t next_len; - - printf("Crossed Seg\n"); - if ((scb->sg_count + 2) > AHC_NSEG) - panic("Too few segs for dma mapping. " - "Increase AHC_NSEG\n"); - - consumed++; - next_sg = sg + 1; - next_sg->addr = 0; - next_len = 0x100000000 - (addr & 0xFFFFFFFF); - len -= next_len; - next_len |= ((addr >> 8) + 0x1000000) & 0x7F000000; - next_sg->len = ahc_htole32(next_len); - } - len |= (addr >> 8) & 0x7F000000; - } + && (ahc->flags & AHC_39BIT_ADDRESSING) != 0) + len |= (addr >> 8) & AHC_SG_HIGH_ADDR_MASK; + sg->len = ahc_htole32(len); return (consumed); } @@ -1195,10 +1170,10 @@ } #endif +#if defined(__i386__) /* * Return the disk geometry for the given SCSI device. */ -#if defined(__i386__) static int #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) ahc_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev, @@ -1747,7 +1722,7 @@ struct Scsi_Host *host; char *new_name; u_long s; - u_int target; + u_int targ_offset; template->name = ahc->description; host = scsi_register(template, sizeof(struct ahc_softc *)); @@ -1802,14 +1777,19 @@ * negotiation will occur for the first command, and DV * will comence should that first command be successful. */ - for (target = 0; - target < host->max_id * (host->max_channel + 1); target++) { + for (targ_offset = 0; + targ_offset < host->max_id * (host->max_channel + 1); + targ_offset++) { u_int channel; + u_int target; channel = 0; + target = targ_offset; if (target > 7 - && (ahc->features & AHC_TWIN) != 0) + && (ahc->features & AHC_TWIN) != 0) { channel = 1; + target &= 0x7; + } /* * Skip our own ID. Some Compaq/HP storage devices * have enclosure management devices that respond to @@ -2443,8 +2423,10 @@ ahc_unlock(ahc, &s); return; } - ahc_compile_devinfo(&devinfo, ahc->our_id, targ->target, /*lun*/0, - targ->channel + 'A', ROLE_INITIATOR); + ahc_compile_devinfo(&devinfo, + targ->channel == 0 ? ahc->our_id : ahc->our_id_b, + targ->target, /*lun*/0, targ->channel + 'A', + ROLE_INITIATOR); #ifdef AHC_DEBUG if (ahc_debug & AHC_SHOW_DV) { ahc_print_devinfo(ahc, &devinfo); @@ -2616,14 +2598,11 @@ struct ahc_devinfo *devinfo, struct ahc_linux_target *targ) { - cam_status cam_status; u_int32_t status; - u_int scsi_status; - - scsi_status = ahc_cmd_get_scsi_status(cmd); - cam_status = ahc_cmd_get_transaction_status(cmd); - status = aic_error_action(cmd, targ->inq_data, cam_status, scsi_status); + status = aic_error_action(cmd, targ->inq_data, + ahc_cmd_get_transaction_status(cmd), + ahc_cmd_get_scsi_status(cmd)); #ifdef AHC_DEBUG if (ahc_debug & AHC_SHOW_DV) { @@ -3777,7 +3756,7 @@ cur_seg = (struct scatterlist *)cmd->request_buffer; nseg = pci_map_sg(ahc->dev_softc, cur_seg, cmd->use_sg, - scsi_to_pci_dma_dir(cmd ->sc_data_direction)); + scsi_to_pci_dma_dir(cmd->sc_data_direction)); end_seg = cur_seg + nseg; /* Copy the segments into the SG list. */ sg = scb->sg_list; @@ -3881,7 +3860,7 @@ /* * SCSI controller interrupt handler. */ -AIC_LINUX_IRQRETURN_T +irqreturn_t ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs) { struct ahc_softc *ahc; @@ -3895,7 +3874,7 @@ ahc_schedule_runq(ahc); ahc_linux_run_complete_queue(ahc); ahc_unlock(ahc, &flags); - AIC_LINUX_IRQRETURN(ours); + return IRQ_RETVAL(ours); } void @@ -4910,7 +4889,7 @@ disconnected = FALSE; else if (flag != SCB_ABORT && ahc_inb(ahc, SAVED_SCSIID) == pending_scb->hscb->scsiid - && ahc_inb(ahc, SAVED_LUN) == pending_scb->hscb->lun) + && ahc_inb(ahc, SAVED_LUN) == SCB_GET_LUN(pending_scb)) disconnected = FALSE; } diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h --- a/drivers/scsi/aic7xxx/aic7xxx_osm.h Mon Jun 9 23:16:10 2003 +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h Mon Jun 9 23:16:10 2003 @@ -53,7 +53,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h#142 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h#147 $ * */ #ifndef _AIC7XXX_LINUX_H_ @@ -305,7 +305,7 @@ #define AHC_SCSI_HAS_HOST_LOCK 0 #endif -#define AIC7XXX_DRIVER_VERSION "6.2.33" +#define AIC7XXX_DRIVER_VERSION "6.2.35" /**************************** Front End Queues ********************************/ /* @@ -963,7 +963,7 @@ (((dev_softc)->dma_mask = mask) && 0) #endif /**************************** Proc FS Support *********************************/ -int ahc_linux_proc_info(char *, char **, off_t, int, int, int); +int ahc_linux_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int); /*************************** Domain Validation ********************************/ #define AHC_DV_CMD(cmd) ((cmd)->scsi_done == ahc_linux_dv_complete) @@ -1165,7 +1165,7 @@ int ahc_platform_abort_scbs(struct ahc_softc *ahc, int target, char channel, int lun, u_int tag, role_t role, uint32_t status); -AIC_LINUX_IRQRETURN_T +irqreturn_t ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs); void ahc_platform_flushwork(struct ahc_softc *ahc); int ahc_softc_comp(struct ahc_softc *, struct ahc_softc *); diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c --- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c Mon Jun 9 23:16:09 2003 +++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c Mon Jun 9 23:16:09 2003 @@ -36,7 +36,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c#44 $ + * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c#45 $ */ #include "aic7xxx_osm.h" @@ -110,6 +110,7 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { char buf[80]; + bus_addr_t mask_39bit; struct ahc_softc *ahc; ahc_dev_softc_t pci; struct ahc_pci_identity *entry; @@ -160,12 +161,12 @@ } pci_set_master(pdev); + mask_39bit = (bus_addr_t)(0x7FFFFFFFFFULL & (bus_addr_t)~0); if (sizeof(bus_addr_t) > 4 && ahc_linux_get_memsize() > 0x80000000 - && ahc_pci_set_dma_mask(pdev, 0x7FFFFFFFFFULL) == 0) { + && ahc_pci_set_dma_mask(pdev, mask_39bit) == 0) { ahc->flags |= AHC_39BIT_ADDRESSING; - ahc->platform_data->hw_dma_mask = - (bus_addr_t)(0x7FFFFFFFFFULL & (bus_addr_t)~0); + ahc->platform_data->hw_dma_mask = mask_39bit; } else { ahc_pci_set_dma_mask(pdev, 0xFFFFFFFF); ahc->platform_data->hw_dma_mask = 0xFFFFFFFF; diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c --- a/drivers/scsi/aic7xxx/aic7xxx_pci.c Mon Jun 9 23:16:06 2003 +++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c Mon Jun 9 23:16:06 2003 @@ -39,7 +39,7 @@ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_pci.c#63 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_pci.c#66 $ * * $FreeBSD$ */ @@ -834,10 +834,10 @@ ahc_pci_write_config(ahc->dev_softc, DEVCONFIG, devconfig, /*bytes*/4); /* Ensure busmastering is enabled */ - command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1); + command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/2); command |= PCIM_CMD_BUSMASTEREN; - ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, /*bytes*/1); + ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, /*bytes*/2); /* On all PCI adapters, we allow SCB paging */ ahc->flags |= AHC_PAGESCBS; @@ -854,10 +854,8 @@ * error reporting when doing this, so CIO bus, scb ram, and * scratch ram parity errors will be ignored too. */ - if ((ahc->flags & AHC_DISABLE_PCI_PERR) != 0) { - ahc->pause |= FAILDIS; - ahc->unpause |= FAILDIS; - } + if ((ahc->flags & AHC_DISABLE_PCI_PERR) != 0) + ahc->seqctl |= FAILDIS; ahc->bus_intr = ahc_pci_intr; ahc->bus_chip_init = ahc_pci_chip_init; @@ -2044,8 +2042,8 @@ "%s: WARNING WARNING WARNING WARNING\n", ahc_name(ahc), ahc_name(ahc), ahc_name(ahc), ahc_name(ahc), ahc_name(ahc), ahc_name(ahc)); - ahc->pause |= FAILDIS; - ahc->unpause |= FAILDIS; + ahc->seqctl |= FAILDIS; + ahc_outb(ahc, SEQCTL, ahc->seqctl); } ahc_unpause(ahc); } diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_proc.c b/drivers/scsi/aic7xxx/aic7xxx_proc.c --- a/drivers/scsi/aic7xxx/aic7xxx_proc.c Mon Jun 9 23:16:05 2003 +++ b/drivers/scsi/aic7xxx/aic7xxx_proc.c Mon Jun 9 23:16:05 2003 @@ -289,8 +289,8 @@ * Return information to handle /proc support for the driver. */ int -ahc_linux_proc_info(char *buffer, char **start, off_t offset, - int length, int hostno, int inout) +ahc_linux_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset, + int length, int inout) { struct ahc_softc *ahc; struct info_str info; @@ -303,7 +303,7 @@ retval = -EINVAL; ahc_list_lock(&s); TAILQ_FOREACH(ahc, &ahc_tailq, links) { - if (ahc->platform_data->host->host_no == hostno) + if (ahc->platform_data->host == shost) break; } diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped b/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped --- a/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped Mon Jun 9 23:16:14 2003 +++ b/drivers/scsi/aic7xxx/aic7xxx_reg.h_shipped Mon Jun 9 23:16:14 2003 @@ -2,8 +2,8 @@ * DO NOT EDIT - This file is automatically generated * from the following source files: * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#54 $ - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#38 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#56 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#39 $ */ typedef int (ahc_reg_print_t)(u_int, u_int *, u_int); typedef struct ahc_reg_parse_entry { @@ -433,13 +433,6 @@ #endif #if AIC_DEBUG_REGISTERS -ahc_reg_print_t ahc_data_count_odd_print; -#else -#define ahc_data_count_odd_print(regvalue, cur_col, wrap) \ - ahc_print_register(NULL, 0, "DATA_COUNT_ODD", 0x55, regvalue, cur_col, wrap) -#endif - -#if AIC_DEBUG_REGISTERS ahc_reg_print_t ahc_ha_274_biosglobal_print; #else #define ahc_ha_274_biosglobal_print(regvalue, cur_col, wrap) \ @@ -1396,8 +1389,6 @@ #define ENAUTOATNI 0x04 #define ENAUTOATNP 0x02 -#define DATA_COUNT_ODD 0x55 - #define HA_274_BIOSGLOBAL 0x56 #define INITIATOR_TAG 0x56 #define HA_274_EXTENDED_TRANS 0x01 @@ -1655,7 +1646,8 @@ #define TWIN_CHNLB 0x80 #define SCB_LUN 0xba -#define LID 0xff +#define LID 0x3f +#define SCB_XFERLEN_ODD 0x80 #define SCB_TAG 0xbb @@ -1749,7 +1741,6 @@ #define SG_CACHE_SHADOW 0xfc #define SG_ADDR_MASK 0xf8 -#define ODD_SEG 0x04 #define LAST_SEG 0x02 #define LAST_SEG_DONE 0x01 diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped b/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped --- a/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped Mon Jun 9 23:16:20 2003 +++ b/drivers/scsi/aic7xxx/aic7xxx_seq.h_shipped Mon Jun 9 23:16:20 2003 @@ -2,8 +2,8 @@ * DO NOT EDIT - This file is automatically generated * from the following source files: * - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#54 $ - * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#38 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.seq#56 $ + * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.reg#39 $ */ static uint8_t seqprog[] = { 0xb2, 0x00, 0x00, 0x08, @@ -21,15 +21,15 @@ 0x01, 0x4d, 0xc8, 0x30, 0x00, 0x4c, 0x12, 0x70, 0x01, 0x39, 0xa2, 0x30, - 0x00, 0x6a, 0xd4, 0x5e, + 0x00, 0x6a, 0xc0, 0x5e, 0x01, 0x51, 0x20, 0x31, 0x01, 0x57, 0xae, 0x00, 0x0d, 0x6a, 0x76, 0x00, - 0x00, 0x51, 0x26, 0x5e, + 0x00, 0x51, 0x12, 0x5e, 0x01, 0x51, 0xc8, 0x30, 0x00, 0x39, 0xc8, 0x60, 0x00, 0xbb, 0x30, 0x70, - 0xc1, 0x6a, 0xec, 0x5e, + 0xc1, 0x6a, 0xd8, 0x5e, 0x01, 0xbf, 0x72, 0x30, 0x01, 0x40, 0x7e, 0x31, 0x01, 0x90, 0x80, 0x30, @@ -49,10 +49,10 @@ 0x08, 0x6a, 0x78, 0x00, 0x01, 0x50, 0xc8, 0x30, 0xe0, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0x10, 0x5e, + 0x48, 0x6a, 0xfc, 0x5d, 0x01, 0x6a, 0xdc, 0x01, 0x88, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0x10, 0x5e, + 0x48, 0x6a, 0xfc, 0x5d, 0x01, 0x6a, 0x26, 0x01, 0xf0, 0x19, 0x7a, 0x08, 0x0f, 0x18, 0xc8, 0x08, @@ -93,7 +93,7 @@ 0x00, 0x65, 0x20, 0x41, 0x02, 0x57, 0xae, 0x00, 0x00, 0x65, 0x9e, 0x40, - 0x61, 0x6a, 0xec, 0x5e, + 0x61, 0x6a, 0xd8, 0x5e, 0x08, 0x51, 0x20, 0x71, 0x02, 0x0b, 0xb2, 0x78, 0x00, 0x65, 0xae, 0x40, @@ -106,7 +106,7 @@ 0x80, 0x3d, 0x7a, 0x00, 0x20, 0x6a, 0x16, 0x00, 0x00, 0x65, 0xcc, 0x41, - 0x00, 0x65, 0xc6, 0x5e, + 0x00, 0x65, 0xb2, 0x5e, 0x00, 0x65, 0x12, 0x40, 0x20, 0x11, 0xd2, 0x68, 0x20, 0x6a, 0x18, 0x00, @@ -135,20 +135,20 @@ 0x01, 0x40, 0x20, 0x31, 0x01, 0xbf, 0x80, 0x30, 0x01, 0xb9, 0x7a, 0x30, - 0x01, 0xba, 0x7c, 0x30, + 0x3f, 0xba, 0x7c, 0x08, 0x00, 0x65, 0xea, 0x58, 0x80, 0x0b, 0xc4, 0x79, 0x12, 0x01, 0x02, 0x00, 0x01, 0xab, 0xac, 0x30, - 0xe4, 0x6a, 0x82, 0x5d, + 0xe4, 0x6a, 0x6e, 0x5d, 0x40, 0x6a, 0x16, 0x00, - 0x80, 0xba, 0x98, 0x5d, + 0x80, 0x3e, 0x84, 0x5d, 0x20, 0xb8, 0x18, 0x79, - 0x20, 0x6a, 0x98, 0x5d, - 0x00, 0xab, 0x98, 0x5d, + 0x20, 0x6a, 0x84, 0x5d, + 0x00, 0xab, 0x84, 0x5d, 0x01, 0xa9, 0x78, 0x30, 0x10, 0xb8, 0x20, 0x79, - 0xe4, 0x6a, 0x82, 0x5d, + 0xe4, 0x6a, 0x6e, 0x5d, 0x00, 0x65, 0xae, 0x40, 0x10, 0x03, 0x3c, 0x69, 0x08, 0x3c, 0x5a, 0x69, @@ -157,10 +157,10 @@ 0x01, 0x3c, 0x44, 0x79, 0xff, 0x6a, 0x70, 0x00, 0x00, 0x65, 0xa4, 0x59, - 0x00, 0x6a, 0xd4, 0x5e, + 0x00, 0x6a, 0xc0, 0x5e, 0xff, 0x38, 0x30, 0x71, 0x0d, 0x6a, 0x76, 0x00, - 0x00, 0x38, 0x26, 0x5e, + 0x00, 0x38, 0x12, 0x5e, 0x00, 0x65, 0xea, 0x58, 0x12, 0x01, 0x02, 0x00, 0x00, 0x65, 0x18, 0x41, @@ -168,10 +168,10 @@ 0x00, 0x65, 0xf2, 0x58, 0xfd, 0x57, 0xae, 0x08, 0x00, 0x65, 0xae, 0x40, - 0xe4, 0x6a, 0x82, 0x5d, + 0xe4, 0x6a, 0x6e, 0x5d, 0x20, 0x3c, 0x4a, 0x79, - 0x02, 0x6a, 0x98, 0x5d, - 0x04, 0x6a, 0x98, 0x5d, + 0x02, 0x6a, 0x84, 0x5d, + 0x04, 0x6a, 0x84, 0x5d, 0x01, 0x03, 0x4c, 0x69, 0xf7, 0x11, 0x22, 0x08, 0xff, 0x6a, 0x24, 0x08, @@ -182,13 +182,13 @@ 0x80, 0x86, 0xc8, 0x08, 0x01, 0x4f, 0xc8, 0x30, 0x00, 0x50, 0x6c, 0x61, - 0xc4, 0x6a, 0x82, 0x5d, + 0xc4, 0x6a, 0x6e, 0x5d, 0x40, 0x3c, 0x68, 0x79, - 0x28, 0x6a, 0x98, 0x5d, + 0x28, 0x6a, 0x84, 0x5d, 0x00, 0x65, 0x4c, 0x41, - 0x08, 0x6a, 0x98, 0x5d, + 0x08, 0x6a, 0x84, 0x5d, 0x00, 0x65, 0x4c, 0x41, - 0x84, 0x6a, 0x82, 0x5d, + 0x84, 0x6a, 0x6e, 0x5d, 0x00, 0x65, 0xf2, 0x58, 0x01, 0x66, 0xc8, 0x30, 0x01, 0x64, 0xd8, 0x31, @@ -208,16 +208,16 @@ 0xf7, 0x3c, 0x78, 0x08, 0x00, 0x65, 0x20, 0x41, 0x40, 0xaa, 0x7e, 0x10, - 0x04, 0xaa, 0x82, 0x5d, - 0x00, 0x65, 0x5e, 0x42, - 0xc4, 0x6a, 0x82, 0x5d, + 0x04, 0xaa, 0x6e, 0x5d, + 0x00, 0x65, 0x56, 0x42, + 0xc4, 0x6a, 0x6e, 0x5d, 0xc0, 0x6a, 0x7e, 0x00, - 0x00, 0xa8, 0x98, 0x5d, + 0x00, 0xa8, 0x84, 0x5d, 0xe4, 0x6a, 0x06, 0x00, - 0x00, 0x6a, 0x98, 0x5d, + 0x00, 0x6a, 0x84, 0x5d, 0x00, 0x65, 0x4c, 0x41, 0x10, 0x3c, 0xa8, 0x69, - 0x00, 0xbb, 0x9e, 0x44, + 0x00, 0xbb, 0x8a, 0x44, 0x18, 0x6a, 0xda, 0x01, 0x01, 0x69, 0xd8, 0x31, 0x1c, 0x6a, 0xd0, 0x01, @@ -227,23 +227,23 @@ 0x01, 0x93, 0x26, 0x01, 0x03, 0x6a, 0x2a, 0x01, 0x01, 0x69, 0x32, 0x31, - 0x1c, 0x6a, 0xf4, 0x5d, + 0x1c, 0x6a, 0xe0, 0x5d, 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0xbc, 0x5e, + 0x00, 0x65, 0xa8, 0x5e, 0x01, 0x50, 0xa0, 0x18, 0x02, 0x6a, 0x22, 0x05, 0x1a, 0x01, 0x02, 0x00, 0x80, 0x6a, 0x74, 0x00, 0x40, 0x6a, 0x78, 0x00, 0x40, 0x6a, 0x16, 0x00, - 0x00, 0x65, 0xec, 0x5d, + 0x00, 0x65, 0xd8, 0x5d, 0x01, 0x3f, 0xc8, 0x30, - 0xbf, 0x64, 0x5e, 0x7a, - 0x80, 0x64, 0xb2, 0x73, - 0xa0, 0x64, 0x14, 0x74, - 0xc0, 0x64, 0x08, 0x74, - 0xe0, 0x64, 0x44, 0x74, - 0x01, 0x6a, 0xec, 0x5e, + 0xbf, 0x64, 0x56, 0x7a, + 0x80, 0x64, 0x9e, 0x73, + 0xa0, 0x64, 0x00, 0x74, + 0xc0, 0x64, 0xf4, 0x73, + 0xe0, 0x64, 0x30, 0x74, + 0x01, 0x6a, 0xd8, 0x5e, 0x00, 0x65, 0xcc, 0x41, 0xf7, 0x11, 0x22, 0x08, 0x01, 0x06, 0xd4, 0x30, @@ -251,7 +251,7 @@ 0xf7, 0x01, 0x02, 0x08, 0x09, 0x0c, 0xe6, 0x79, 0x08, 0x0c, 0x04, 0x68, - 0xb1, 0x6a, 0xec, 0x5e, + 0xb1, 0x6a, 0xd8, 0x5e, 0xff, 0x6a, 0x26, 0x09, 0x12, 0x01, 0x02, 0x00, 0x02, 0x6a, 0x08, 0x30, @@ -264,33 +264,29 @@ 0x00, 0xa5, 0x4a, 0x21, 0x00, 0xa6, 0x4c, 0x21, 0x00, 0xa7, 0x4e, 0x25, - 0x08, 0xeb, 0xf0, 0x7e, + 0x08, 0xeb, 0xdc, 0x7e, 0x80, 0xeb, 0x06, 0x7a, 0xff, 0x6a, 0xd6, 0x09, 0x08, 0xeb, 0x0a, 0x6a, 0xff, 0x6a, 0xd4, 0x0c, - 0x80, 0xa3, 0xf0, 0x6e, + 0x80, 0xa3, 0xdc, 0x6e, 0x88, 0xeb, 0x20, 0x72, - 0x08, 0xeb, 0xf0, 0x6e, + 0x08, 0xeb, 0xdc, 0x6e, 0x04, 0xea, 0x24, 0xe2, - 0x08, 0xee, 0xf0, 0x6e, + 0x08, 0xee, 0xdc, 0x6e, 0x04, 0x6a, 0xd0, 0x81, 0x05, 0xa4, 0xc0, 0x89, 0x03, 0xa5, 0xc2, 0x31, 0x09, 0x6a, 0xd6, 0x05, 0x00, 0x65, 0x08, 0x5a, 0x06, 0xa4, 0xd4, 0x89, - 0x80, 0x94, 0xf0, 0x7e, + 0x80, 0x94, 0xdc, 0x7e, 0x07, 0xe9, 0x10, 0x31, - 0x01, 0x8c, 0x2c, 0x7a, - 0x01, 0x55, 0xaa, 0x10, 0x01, 0xe9, 0x46, 0x31, - 0x00, 0xa3, 0xce, 0x5e, + 0x00, 0xa3, 0xba, 0x5e, 0x00, 0x65, 0xfa, 0x59, 0x01, 0xa4, 0xca, 0x30, - 0x01, 0x55, 0x38, 0x7a, - 0x04, 0x65, 0xca, 0x00, - 0x80, 0xa3, 0x3c, 0x7a, + 0x80, 0xa3, 0x34, 0x7a, 0x02, 0x65, 0xca, 0x00, 0x01, 0x65, 0xf8, 0x31, 0x80, 0x93, 0x26, 0x01, @@ -298,168 +294,162 @@ 0x01, 0x8c, 0xc8, 0x30, 0x00, 0x88, 0xc8, 0x18, 0x02, 0x64, 0xc8, 0x88, - 0xff, 0x64, 0xf0, 0x7e, - 0xff, 0x8d, 0x52, 0x6a, - 0xff, 0x8e, 0x52, 0x6a, + 0xff, 0x64, 0xdc, 0x7e, + 0xff, 0x8d, 0x4a, 0x6a, + 0xff, 0x8e, 0x4a, 0x6a, 0x03, 0x8c, 0xd4, 0x98, - 0x00, 0x65, 0xf0, 0x56, + 0x00, 0x65, 0xdc, 0x56, 0x01, 0x64, 0x70, 0x30, 0xff, 0x64, 0xc8, 0x10, 0x01, 0x64, 0xc8, 0x18, 0x00, 0x8c, 0x18, 0x19, 0xff, 0x8d, 0x1a, 0x21, 0xff, 0x8e, 0x1c, 0x25, - 0xc0, 0x3c, 0x62, 0x7a, - 0x21, 0x6a, 0xec, 0x5e, + 0xc0, 0x3c, 0x5a, 0x7a, + 0x21, 0x6a, 0xd8, 0x5e, 0xa8, 0x6a, 0x76, 0x00, 0x79, 0x6a, 0x76, 0x00, - 0x40, 0x3f, 0x6a, 0x6a, + 0x40, 0x3f, 0x62, 0x6a, 0x04, 0x3b, 0x76, 0x00, 0x04, 0x6a, 0xd4, 0x81, - 0x20, 0x3c, 0x72, 0x7a, - 0x51, 0x6a, 0xec, 0x5e, - 0x00, 0x65, 0x8c, 0x42, + 0x20, 0x3c, 0x6a, 0x7a, + 0x51, 0x6a, 0xd8, 0x5e, + 0x00, 0x65, 0x82, 0x42, 0x20, 0x3c, 0x78, 0x00, - 0x00, 0xb3, 0xce, 0x5e, + 0x00, 0xb3, 0xba, 0x5e, 0x07, 0xac, 0x10, 0x31, 0x05, 0xb3, 0x46, 0x31, 0x88, 0x6a, 0xcc, 0x00, - 0xac, 0x6a, 0x02, 0x5e, + 0xac, 0x6a, 0xee, 0x5d, 0xa3, 0x6a, 0xcc, 0x00, - 0xb3, 0x6a, 0x06, 0x5e, - 0x00, 0x65, 0x42, 0x5a, + 0xb3, 0x6a, 0xf2, 0x5d, + 0x00, 0x65, 0x3a, 0x5a, 0xfd, 0xa4, 0x48, 0x09, - 0x01, 0x8c, 0xaa, 0x08, 0x03, 0x8c, 0x10, 0x30, - 0x00, 0x65, 0xfa, 0x5d, - 0x01, 0xa4, 0x9e, 0x7a, + 0x00, 0x65, 0xe6, 0x5d, + 0x01, 0xa4, 0x94, 0x7a, 0x04, 0x3b, 0x76, 0x08, 0x01, 0x3b, 0x26, 0x31, 0x80, 0x02, 0x04, 0x00, - 0x10, 0x0c, 0x94, 0x7a, - 0x03, 0x9e, 0x96, 0x6a, + 0x10, 0x0c, 0x8a, 0x7a, + 0x03, 0x9e, 0x8c, 0x6a, 0x7f, 0x02, 0x04, 0x08, - 0x91, 0x6a, 0xec, 0x5e, + 0x91, 0x6a, 0xd8, 0x5e, 0x00, 0x65, 0xcc, 0x41, 0x01, 0xa4, 0xca, 0x30, - 0x80, 0xa3, 0xa4, 0x7a, + 0x80, 0xa3, 0x9a, 0x7a, 0x02, 0x65, 0xca, 0x00, - 0x01, 0x55, 0xa8, 0x7a, - 0x04, 0x65, 0xca, 0x00, 0x01, 0x65, 0xf8, 0x31, 0x01, 0x3b, 0x26, 0x31, 0x00, 0x65, 0x0e, 0x5a, - 0x01, 0xfc, 0xb6, 0x6a, - 0x80, 0x0b, 0xac, 0x6a, - 0x10, 0x0c, 0xac, 0x7a, - 0x20, 0x93, 0xac, 0x6a, + 0x01, 0xfc, 0xa8, 0x6a, + 0x80, 0x0b, 0x9e, 0x6a, + 0x10, 0x0c, 0x9e, 0x7a, + 0x20, 0x93, 0x9e, 0x6a, 0x02, 0x93, 0x26, 0x01, - 0x02, 0xfc, 0xc0, 0x7a, - 0x40, 0x0d, 0xda, 0x6a, - 0x01, 0xa4, 0x48, 0x01, - 0x00, 0x65, 0xda, 0x42, + 0x02, 0xfc, 0xb2, 0x7a, 0x40, 0x0d, 0xc6, 0x6a, + 0x01, 0xa4, 0x48, 0x01, + 0x00, 0x65, 0xc6, 0x42, + 0x40, 0x0d, 0xb8, 0x6a, 0x00, 0x65, 0x0e, 0x5a, - 0x00, 0x65, 0xb8, 0x42, - 0x80, 0xfc, 0xd0, 0x7a, - 0x80, 0xa4, 0xd0, 0x6a, + 0x00, 0x65, 0xaa, 0x42, + 0x80, 0xfc, 0xc2, 0x7a, + 0x80, 0xa4, 0xc2, 0x6a, 0xff, 0xa5, 0x4a, 0x19, 0xff, 0xa6, 0x4c, 0x21, 0xff, 0xa7, 0x4e, 0x21, 0xf8, 0xfc, 0x48, 0x09, - 0xff, 0x6a, 0xaa, 0x08, - 0x04, 0xfc, 0xd8, 0x7a, - 0x01, 0x55, 0xaa, 0x00, - 0xff, 0x6a, 0x46, 0x09, - 0x04, 0x3b, 0xf2, 0x6a, + 0x7f, 0xa3, 0x46, 0x09, + 0x04, 0x3b, 0xe2, 0x6a, 0x02, 0x93, 0x26, 0x01, - 0x01, 0x94, 0xdc, 0x7a, - 0x01, 0x94, 0xdc, 0x7a, - 0x01, 0x94, 0xdc, 0x7a, - 0x01, 0x94, 0xdc, 0x7a, - 0x01, 0x94, 0xdc, 0x7a, - 0x01, 0xa4, 0xf0, 0x7a, - 0x01, 0xfc, 0xea, 0x7a, - 0x01, 0x94, 0xf2, 0x6a, - 0x00, 0x65, 0x8c, 0x42, - 0x01, 0x94, 0xf0, 0x7a, - 0x10, 0x94, 0xf2, 0x6a, + 0x01, 0x94, 0xc8, 0x7a, + 0x01, 0x94, 0xc8, 0x7a, + 0x01, 0x94, 0xc8, 0x7a, + 0x01, 0x94, 0xc8, 0x7a, + 0x01, 0x94, 0xc8, 0x7a, + 0x01, 0xa4, 0xe0, 0x7a, + 0x01, 0xfc, 0xd6, 0x7a, + 0x01, 0x94, 0xe2, 0x6a, + 0x01, 0x94, 0xe2, 0x6a, + 0x01, 0x94, 0xe2, 0x6a, + 0x00, 0x65, 0x82, 0x42, + 0x01, 0x94, 0xe0, 0x7a, + 0x10, 0x94, 0xe2, 0x6a, 0xd7, 0x93, 0x26, 0x09, - 0x28, 0x93, 0xf6, 0x6a, + 0x28, 0x93, 0xe6, 0x6a, 0x01, 0x85, 0x0a, 0x01, - 0x02, 0xfc, 0xfe, 0x6a, + 0x02, 0xfc, 0xee, 0x6a, 0x01, 0x14, 0x46, 0x31, 0xff, 0x6a, 0x10, 0x09, 0xfe, 0x85, 0x0a, 0x09, - 0xff, 0x38, 0x0c, 0x6b, - 0x80, 0xa3, 0x0c, 0x7b, - 0x80, 0x0b, 0x0a, 0x7b, - 0x04, 0x3b, 0x0c, 0x7b, + 0xff, 0x38, 0xfc, 0x6a, + 0x80, 0xa3, 0xfc, 0x7a, + 0x80, 0x0b, 0xfa, 0x7a, + 0x04, 0x3b, 0xfc, 0x7a, 0xbf, 0x3b, 0x76, 0x08, 0x01, 0x3b, 0x26, 0x31, 0x00, 0x65, 0x0e, 0x5a, - 0x01, 0x0b, 0x1a, 0x6b, - 0x10, 0x0c, 0x0e, 0x7b, - 0x04, 0x93, 0x18, 0x6b, - 0x01, 0x94, 0x16, 0x7b, - 0x10, 0x94, 0x18, 0x6b, + 0x01, 0x0b, 0x0a, 0x6b, + 0x10, 0x0c, 0xfe, 0x7a, + 0x04, 0x93, 0x08, 0x6b, + 0x01, 0x94, 0x06, 0x7b, + 0x10, 0x94, 0x08, 0x6b, 0xc7, 0x93, 0x26, 0x09, 0x01, 0x99, 0xd4, 0x30, - 0x38, 0x93, 0x1c, 0x6b, - 0xff, 0x08, 0x6e, 0x6b, - 0xff, 0x09, 0x6e, 0x6b, - 0xff, 0x0a, 0x6e, 0x6b, - 0xff, 0x38, 0x38, 0x7b, + 0x38, 0x93, 0x0c, 0x6b, + 0xff, 0x08, 0x5a, 0x6b, + 0xff, 0x09, 0x5a, 0x6b, + 0xff, 0x0a, 0x5a, 0x6b, + 0xff, 0x38, 0x28, 0x7b, 0x04, 0x14, 0x10, 0x31, 0x01, 0x38, 0x18, 0x31, 0x02, 0x6a, 0x1a, 0x31, 0x88, 0x6a, 0xcc, 0x00, - 0x14, 0x6a, 0x08, 0x5e, - 0x00, 0x38, 0xf4, 0x5d, + 0x14, 0x6a, 0xf4, 0x5d, + 0x00, 0x38, 0xe0, 0x5d, 0xff, 0x6a, 0x70, 0x08, - 0x00, 0x65, 0x64, 0x43, - 0x80, 0xa3, 0x3e, 0x7b, + 0x00, 0x65, 0x54, 0x43, + 0x80, 0xa3, 0x2e, 0x7b, 0x01, 0xa4, 0x48, 0x01, - 0x00, 0x65, 0x6e, 0x43, - 0x08, 0xeb, 0x44, 0x7b, + 0x00, 0x65, 0x5a, 0x43, + 0x08, 0xeb, 0x34, 0x7b, 0x00, 0x65, 0x0e, 0x5a, - 0x08, 0xeb, 0x40, 0x6b, + 0x08, 0xeb, 0x30, 0x6b, 0x07, 0xe9, 0x10, 0x31, 0x01, 0xe9, 0xca, 0x30, 0x01, 0x65, 0x46, 0x31, - 0x00, 0x6a, 0xce, 0x5e, + 0x00, 0x6a, 0xba, 0x5e, 0x88, 0x6a, 0xcc, 0x00, - 0xa4, 0x6a, 0x08, 0x5e, - 0x08, 0x6a, 0xf4, 0x5d, + 0xa4, 0x6a, 0xf4, 0x5d, + 0x08, 0x6a, 0xe0, 0x5d, 0x0d, 0x93, 0x26, 0x01, - 0x00, 0x65, 0xbc, 0x5e, + 0x00, 0x65, 0xa8, 0x5e, 0x88, 0x6a, 0xcc, 0x00, - 0x00, 0x65, 0x9e, 0x5e, + 0x00, 0x65, 0x8a, 0x5e, 0x01, 0x99, 0x46, 0x31, - 0x00, 0xa3, 0xce, 0x5e, + 0x00, 0xa3, 0xba, 0x5e, 0x01, 0x88, 0x10, 0x31, - 0x00, 0x65, 0x42, 0x5a, + 0x00, 0x65, 0x3a, 0x5a, 0x00, 0x65, 0xfa, 0x59, 0x03, 0x8c, 0x10, 0x30, - 0x00, 0x65, 0xfa, 0x5d, - 0x01, 0x8c, 0x6c, 0x7b, - 0x01, 0x55, 0xaa, 0x10, - 0x80, 0x0b, 0x8c, 0x6a, - 0x80, 0x0b, 0x76, 0x6b, - 0x01, 0x0c, 0x70, 0x7b, - 0x10, 0x0c, 0x8c, 0x7a, - 0x03, 0x9e, 0x8c, 0x6a, + 0x00, 0x65, 0xe6, 0x5d, + 0x80, 0x0b, 0x82, 0x6a, + 0x80, 0x0b, 0x62, 0x6b, + 0x01, 0x0c, 0x5c, 0x7b, + 0x10, 0x0c, 0x82, 0x7a, + 0x03, 0x9e, 0x82, 0x6a, 0x00, 0x65, 0x04, 0x5a, - 0x00, 0x6a, 0xce, 0x5e, - 0x01, 0xa4, 0x96, 0x6b, - 0xff, 0x38, 0x8c, 0x7b, + 0x00, 0x6a, 0xba, 0x5e, + 0x01, 0xa4, 0x82, 0x6b, + 0xff, 0x38, 0x78, 0x7b, 0x01, 0x38, 0xc8, 0x30, 0x00, 0x08, 0x40, 0x19, 0xff, 0x6a, 0xc8, 0x08, 0x00, 0x09, 0x42, 0x21, 0x00, 0x0a, 0x44, 0x21, 0xff, 0x6a, 0x70, 0x08, - 0x00, 0x65, 0x8e, 0x43, + 0x00, 0x65, 0x7a, 0x43, 0x03, 0x08, 0x40, 0x31, 0x03, 0x08, 0x40, 0x31, 0x01, 0x08, 0x40, 0x31, @@ -471,16 +461,16 @@ 0x04, 0x3c, 0xcc, 0x79, 0xfb, 0x3c, 0x78, 0x08, 0x04, 0x93, 0x20, 0x79, - 0x01, 0x0c, 0xa2, 0x6b, - 0x01, 0x55, 0x20, 0x79, + 0x01, 0x0c, 0x8e, 0x6b, + 0x80, 0xba, 0x20, 0x79, 0x80, 0x04, 0x20, 0x79, - 0xe4, 0x6a, 0x82, 0x5d, - 0x23, 0x6a, 0x98, 0x5d, - 0x01, 0x6a, 0x98, 0x5d, + 0xe4, 0x6a, 0x6e, 0x5d, + 0x23, 0x6a, 0x84, 0x5d, + 0x01, 0x6a, 0x84, 0x5d, 0x00, 0x65, 0x20, 0x41, 0x00, 0x65, 0xcc, 0x41, - 0x80, 0x3c, 0xb6, 0x7b, - 0x21, 0x6a, 0xec, 0x5e, + 0x80, 0x3c, 0xa2, 0x7b, + 0x21, 0x6a, 0xd8, 0x5e, 0x01, 0xbc, 0x18, 0x31, 0x02, 0x6a, 0x1a, 0x31, 0x02, 0x6a, 0xf8, 0x01, @@ -490,16 +480,16 @@ 0xff, 0x6a, 0x12, 0x08, 0xff, 0x6a, 0x14, 0x08, 0xf3, 0xbc, 0xd4, 0x18, - 0xa0, 0x6a, 0xdc, 0x53, + 0xa0, 0x6a, 0xc8, 0x53, 0x04, 0xa0, 0x10, 0x31, 0xac, 0x6a, 0x26, 0x01, 0x04, 0xa0, 0x10, 0x31, 0x03, 0x08, 0x18, 0x31, 0x88, 0x6a, 0xcc, 0x00, - 0xa0, 0x6a, 0x08, 0x5e, - 0x00, 0xbc, 0xf4, 0x5d, + 0xa0, 0x6a, 0xf4, 0x5d, + 0x00, 0xbc, 0xe0, 0x5d, 0x3d, 0x6a, 0x26, 0x01, - 0x00, 0x65, 0xf4, 0x43, + 0x00, 0x65, 0xe0, 0x43, 0xff, 0x6a, 0x10, 0x09, 0xa4, 0x6a, 0x26, 0x01, 0x0c, 0xa0, 0x32, 0x31, @@ -509,128 +499,128 @@ 0x36, 0x6a, 0x26, 0x01, 0x02, 0x93, 0x26, 0x01, 0x35, 0x6a, 0x26, 0x01, - 0x00, 0x65, 0xb0, 0x5e, - 0x00, 0x65, 0xb0, 0x5e, + 0x00, 0x65, 0x9c, 0x5e, + 0x00, 0x65, 0x9c, 0x5e, 0x02, 0x93, 0x26, 0x01, 0xbf, 0x3c, 0x78, 0x08, - 0x04, 0x0b, 0xfa, 0x6b, - 0x10, 0x0c, 0xf6, 0x7b, - 0x01, 0x03, 0xfa, 0x6b, - 0x20, 0x93, 0xfc, 0x6b, - 0x04, 0x0b, 0x02, 0x6c, + 0x04, 0x0b, 0xe6, 0x6b, + 0x10, 0x0c, 0xe2, 0x7b, + 0x01, 0x03, 0xe6, 0x6b, + 0x20, 0x93, 0xe8, 0x6b, + 0x04, 0x0b, 0xee, 0x6b, 0x40, 0x3c, 0x78, 0x00, 0xc7, 0x93, 0x26, 0x09, - 0x38, 0x93, 0x04, 0x6c, + 0x38, 0x93, 0xf0, 0x6b, 0x00, 0x65, 0xcc, 0x41, - 0x80, 0x3c, 0x6a, 0x6c, + 0x80, 0x3c, 0x56, 0x6c, 0x01, 0x06, 0x50, 0x31, 0x80, 0xb8, 0x70, 0x01, 0x00, 0x65, 0xcc, 0x41, 0x10, 0x3f, 0x06, 0x00, 0x10, 0x6a, 0x06, 0x00, 0x01, 0x3a, 0xca, 0x30, - 0x80, 0x65, 0x30, 0x64, - 0x10, 0xb8, 0x54, 0x6c, - 0xc0, 0xba, 0xca, 0x00, - 0x40, 0xb8, 0x20, 0x6c, + 0x80, 0x65, 0x1c, 0x64, + 0x10, 0xb8, 0x40, 0x6c, + 0xc0, 0x3e, 0xca, 0x00, + 0x40, 0xb8, 0x0c, 0x6c, 0xbf, 0x65, 0xca, 0x08, - 0x20, 0xb8, 0x34, 0x7c, + 0x20, 0xb8, 0x20, 0x7c, 0x01, 0x65, 0x0c, 0x30, - 0x00, 0x65, 0xec, 0x5d, - 0xa0, 0x3f, 0x3c, 0x64, + 0x00, 0x65, 0xd8, 0x5d, + 0xa0, 0x3f, 0x28, 0x64, 0x23, 0xb8, 0x0c, 0x08, - 0x00, 0x65, 0xec, 0x5d, - 0xa0, 0x3f, 0x3c, 0x64, - 0x00, 0xbb, 0x34, 0x44, - 0xff, 0x65, 0x34, 0x64, - 0x00, 0x65, 0x54, 0x44, + 0x00, 0x65, 0xd8, 0x5d, + 0xa0, 0x3f, 0x28, 0x64, + 0x00, 0xbb, 0x20, 0x44, + 0xff, 0x65, 0x20, 0x64, + 0x00, 0x65, 0x40, 0x44, 0x40, 0x6a, 0x18, 0x00, 0x01, 0x65, 0x0c, 0x30, - 0x00, 0x65, 0xec, 0x5d, - 0xa0, 0x3f, 0x10, 0x74, + 0x00, 0x65, 0xd8, 0x5d, + 0xa0, 0x3f, 0xfc, 0x73, 0x40, 0x6a, 0x18, 0x00, 0x01, 0x3a, 0xa6, 0x30, 0x08, 0x6a, 0x74, 0x00, 0x00, 0x65, 0xcc, 0x41, - 0x64, 0x6a, 0x7c, 0x5d, - 0x80, 0x64, 0xec, 0x6c, - 0x04, 0x64, 0xae, 0x74, - 0x02, 0x64, 0xbe, 0x74, - 0x00, 0x6a, 0x74, 0x74, - 0x03, 0x64, 0xdc, 0x74, - 0x23, 0x64, 0x5c, 0x74, - 0x08, 0x64, 0x70, 0x74, - 0x61, 0x6a, 0xec, 0x5e, - 0x00, 0x65, 0xec, 0x5d, + 0x64, 0x6a, 0x68, 0x5d, + 0x80, 0x64, 0xd8, 0x6c, + 0x04, 0x64, 0x9a, 0x74, + 0x02, 0x64, 0xaa, 0x74, + 0x00, 0x6a, 0x60, 0x74, + 0x03, 0x64, 0xc8, 0x74, + 0x23, 0x64, 0x48, 0x74, + 0x08, 0x64, 0x5c, 0x74, + 0x61, 0x6a, 0xd8, 0x5e, + 0x00, 0x65, 0xd8, 0x5d, 0x08, 0x51, 0xce, 0x71, - 0x00, 0x65, 0x54, 0x44, - 0x80, 0x04, 0x6e, 0x7c, - 0x51, 0x6a, 0x72, 0x5d, - 0x01, 0x51, 0x6e, 0x64, - 0x01, 0xa4, 0x66, 0x7c, - 0x01, 0x55, 0x70, 0x7c, - 0x41, 0x6a, 0xec, 0x5e, - 0x00, 0x65, 0x70, 0x44, - 0x21, 0x6a, 0xec, 0x5e, - 0x00, 0x65, 0x70, 0x44, - 0x07, 0x6a, 0x68, 0x5d, + 0x00, 0x65, 0x40, 0x44, + 0x80, 0x04, 0x5a, 0x7c, + 0x51, 0x6a, 0x5e, 0x5d, + 0x01, 0x51, 0x5a, 0x64, + 0x01, 0xa4, 0x52, 0x7c, + 0x80, 0xba, 0x5c, 0x6c, + 0x41, 0x6a, 0xd8, 0x5e, + 0x00, 0x65, 0x5c, 0x44, + 0x21, 0x6a, 0xd8, 0x5e, + 0x00, 0x65, 0x5c, 0x44, + 0x07, 0x6a, 0x54, 0x5d, 0x01, 0x06, 0xd4, 0x30, 0x00, 0x65, 0xcc, 0x41, - 0x80, 0xb8, 0x6a, 0x7c, - 0xc0, 0x3c, 0x7e, 0x7c, - 0x80, 0x3c, 0x6a, 0x6c, - 0xff, 0xa8, 0x7e, 0x6c, - 0x40, 0x3c, 0x6a, 0x6c, - 0x10, 0xb8, 0x82, 0x7c, - 0xa1, 0x6a, 0xec, 0x5e, - 0x01, 0xb4, 0x88, 0x6c, - 0x02, 0xb4, 0x8a, 0x6c, - 0x01, 0xa4, 0x8a, 0x7c, - 0xff, 0xa8, 0x9a, 0x7c, + 0x80, 0xb8, 0x56, 0x7c, + 0xc0, 0x3c, 0x6a, 0x7c, + 0x80, 0x3c, 0x56, 0x6c, + 0xff, 0xa8, 0x6a, 0x6c, + 0x40, 0x3c, 0x56, 0x6c, + 0x10, 0xb8, 0x6e, 0x7c, + 0xa1, 0x6a, 0xd8, 0x5e, + 0x01, 0xb4, 0x74, 0x6c, + 0x02, 0xb4, 0x76, 0x6c, + 0x01, 0xa4, 0x76, 0x7c, + 0xff, 0xa8, 0x86, 0x7c, 0x04, 0xb4, 0x68, 0x01, 0x01, 0x6a, 0x76, 0x00, - 0x00, 0xbb, 0x26, 0x5e, - 0xff, 0xa8, 0x9a, 0x7c, - 0x71, 0x6a, 0xec, 0x5e, - 0x40, 0x51, 0x9a, 0x64, - 0x00, 0x65, 0xc6, 0x5e, + 0x00, 0xbb, 0x12, 0x5e, + 0xff, 0xa8, 0x86, 0x7c, + 0x71, 0x6a, 0xd8, 0x5e, + 0x40, 0x51, 0x86, 0x64, + 0x00, 0x65, 0xb2, 0x5e, 0x00, 0x65, 0xde, 0x41, - 0x00, 0xbb, 0x9e, 0x5c, + 0x00, 0xbb, 0x8a, 0x5c, 0x00, 0x65, 0xde, 0x41, - 0x00, 0x65, 0xc6, 0x5e, + 0x00, 0x65, 0xb2, 0x5e, 0x01, 0x65, 0xa2, 0x30, 0x01, 0xf8, 0xc8, 0x30, 0x01, 0x4e, 0xc8, 0x30, - 0x00, 0x6a, 0xca, 0xdd, - 0x00, 0x51, 0xdc, 0x5d, + 0x00, 0x6a, 0xb6, 0xdd, + 0x00, 0x51, 0xc8, 0x5d, 0x01, 0x4e, 0x9c, 0x18, 0x02, 0x6a, 0x22, 0x05, - 0xc0, 0x3c, 0x6a, 0x6c, + 0xc0, 0x3c, 0x56, 0x6c, 0x04, 0xb8, 0x70, 0x01, - 0x00, 0x65, 0xe8, 0x5e, + 0x00, 0x65, 0xd4, 0x5e, 0x20, 0xb8, 0xde, 0x69, 0x01, 0xbb, 0xa2, 0x30, - 0x01, 0xba, 0x7c, 0x30, - 0x00, 0xb9, 0xe2, 0x5c, + 0x3f, 0xba, 0x7c, 0x08, + 0x00, 0xb9, 0xce, 0x5c, 0x00, 0x65, 0xde, 0x41, 0x01, 0x06, 0xd4, 0x30, 0x20, 0x3c, 0xcc, 0x79, - 0x20, 0x3c, 0x70, 0x7c, - 0x01, 0xa4, 0xcc, 0x7c, + 0x20, 0x3c, 0x5c, 0x7c, + 0x01, 0xa4, 0xb8, 0x7c, 0x01, 0xb4, 0x68, 0x01, 0x00, 0x65, 0xcc, 0x41, - 0x00, 0x65, 0x70, 0x44, + 0x00, 0x65, 0x5c, 0x44, 0x04, 0x14, 0x58, 0x31, 0x01, 0x06, 0xd4, 0x30, 0x08, 0xa0, 0x60, 0x31, 0xac, 0x6a, 0xcc, 0x00, - 0x14, 0x6a, 0x08, 0x5e, + 0x14, 0x6a, 0xf4, 0x5d, 0x01, 0x06, 0xd4, 0x30, - 0xa0, 0x6a, 0x00, 0x5e, + 0xa0, 0x6a, 0xec, 0x5d, 0x00, 0x65, 0xcc, 0x41, 0xdf, 0x3c, 0x78, 0x08, 0x12, 0x01, 0x02, 0x00, - 0x00, 0x65, 0x70, 0x44, + 0x00, 0x65, 0x5c, 0x44, 0x4c, 0x65, 0xcc, 0x28, 0x01, 0x3e, 0x20, 0x31, 0xd0, 0x66, 0xcc, 0x18, @@ -641,102 +631,102 @@ 0xd0, 0x65, 0xca, 0x18, 0x01, 0x3e, 0x20, 0x31, 0x30, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0xfa, 0x4c, + 0x00, 0x65, 0xe6, 0x4c, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0x20, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0x02, 0x55, + 0x00, 0x65, 0xee, 0x54, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0x20, 0x65, 0xca, 0x18, 0xe0, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0x0c, 0x4d, + 0x00, 0x65, 0xf8, 0x4c, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0xd0, 0x65, 0xd4, 0x18, - 0x00, 0x65, 0x14, 0x55, + 0x00, 0x65, 0x00, 0x55, 0xe1, 0x6a, 0x22, 0x01, 0xff, 0x6a, 0xd4, 0x08, 0x01, 0x6c, 0xa2, 0x30, - 0xff, 0x51, 0x26, 0x75, - 0x00, 0x51, 0xa2, 0x5d, + 0xff, 0x51, 0x12, 0x75, + 0x00, 0x51, 0x8e, 0x5d, 0x01, 0x51, 0x20, 0x31, - 0x00, 0x65, 0x48, 0x45, - 0x01, 0xba, 0xc8, 0x30, - 0x00, 0x3e, 0x48, 0x75, - 0x00, 0x65, 0xc4, 0x5e, + 0x00, 0x65, 0x34, 0x45, + 0x3f, 0xba, 0xc8, 0x08, + 0x00, 0x3e, 0x34, 0x75, + 0x00, 0x65, 0xb0, 0x5e, 0x80, 0x3c, 0x78, 0x00, 0x01, 0x06, 0xd4, 0x30, - 0x00, 0x65, 0xec, 0x5d, + 0x00, 0x65, 0xd8, 0x5d, 0x01, 0x3c, 0x78, 0x00, - 0xe0, 0x3f, 0x64, 0x65, + 0xe0, 0x3f, 0x50, 0x65, 0x02, 0x3c, 0x78, 0x00, - 0x20, 0x12, 0x64, 0x65, - 0x51, 0x6a, 0x72, 0x5d, - 0x00, 0x51, 0xa2, 0x5d, - 0x51, 0x6a, 0x72, 0x5d, + 0x20, 0x12, 0x50, 0x65, + 0x51, 0x6a, 0x5e, 0x5d, + 0x00, 0x51, 0x8e, 0x5d, + 0x51, 0x6a, 0x5e, 0x5d, 0x01, 0x51, 0x20, 0x31, 0x04, 0x3c, 0x78, 0x00, 0x01, 0xb9, 0xc8, 0x30, - 0x00, 0x3d, 0x62, 0x65, + 0x00, 0x3d, 0x4e, 0x65, 0x08, 0x3c, 0x78, 0x00, - 0x01, 0xba, 0xc8, 0x30, - 0x00, 0x3e, 0x62, 0x65, + 0x3f, 0xba, 0xc8, 0x08, + 0x00, 0x3e, 0x4e, 0x65, 0x10, 0x3c, 0x78, 0x00, - 0x04, 0xb8, 0x62, 0x7d, + 0x04, 0xb8, 0x4e, 0x7d, 0xfb, 0xb8, 0x70, 0x09, - 0x20, 0xb8, 0x58, 0x6d, + 0x20, 0xb8, 0x44, 0x6d, 0x01, 0x90, 0xc8, 0x30, 0xff, 0x6a, 0xa2, 0x00, - 0x00, 0x3d, 0xe2, 0x5c, + 0x00, 0x3d, 0xce, 0x5c, 0x01, 0x64, 0x20, 0x31, 0xff, 0x6a, 0x78, 0x08, 0x00, 0x65, 0xea, 0x58, - 0x10, 0xb8, 0x70, 0x7c, - 0xff, 0x6a, 0x68, 0x5d, - 0x00, 0x65, 0x70, 0x44, - 0x00, 0x65, 0xc4, 0x5e, - 0x31, 0x6a, 0xec, 0x5e, - 0x00, 0x65, 0x70, 0x44, + 0x10, 0xb8, 0x5c, 0x7c, + 0xff, 0x6a, 0x54, 0x5d, + 0x00, 0x65, 0x5c, 0x44, + 0x00, 0x65, 0xb0, 0x5e, + 0x31, 0x6a, 0xd8, 0x5e, + 0x00, 0x65, 0x5c, 0x44, 0x10, 0x3f, 0x06, 0x00, 0x10, 0x6a, 0x06, 0x00, 0x01, 0x65, 0x74, 0x34, - 0x81, 0x6a, 0xec, 0x5e, - 0x00, 0x65, 0x74, 0x45, + 0x81, 0x6a, 0xd8, 0x5e, + 0x00, 0x65, 0x60, 0x45, 0x01, 0x06, 0xd4, 0x30, - 0x01, 0x0c, 0x74, 0x7d, - 0x04, 0x0c, 0x6e, 0x6d, + 0x01, 0x0c, 0x60, 0x7d, + 0x04, 0x0c, 0x5a, 0x6d, 0xe0, 0x03, 0x7e, 0x08, 0xe0, 0x3f, 0xcc, 0x61, 0x01, 0x65, 0xcc, 0x30, 0x01, 0x12, 0xda, 0x34, 0x01, 0x06, 0xd4, 0x34, - 0x01, 0x03, 0x82, 0x6d, + 0x01, 0x03, 0x6e, 0x6d, 0x40, 0x03, 0xcc, 0x08, 0x01, 0x65, 0x06, 0x30, 0x40, 0x65, 0xc8, 0x08, - 0x00, 0x66, 0x90, 0x75, - 0x40, 0x65, 0x90, 0x7d, - 0x00, 0x65, 0x90, 0x5d, + 0x00, 0x66, 0x7c, 0x75, + 0x40, 0x65, 0x7c, 0x7d, + 0x00, 0x65, 0x7c, 0x5d, 0xff, 0x6a, 0xd4, 0x08, 0xff, 0x6a, 0xd4, 0x08, 0xff, 0x6a, 0xd4, 0x08, 0xff, 0x6a, 0xd4, 0x0c, 0x08, 0x01, 0x02, 0x00, - 0x02, 0x0b, 0x9a, 0x7d, + 0x02, 0x0b, 0x86, 0x7d, 0x01, 0x65, 0x0c, 0x30, - 0x02, 0x0b, 0x9e, 0x7d, + 0x02, 0x0b, 0x8a, 0x7d, 0xf7, 0x01, 0x02, 0x0c, 0x01, 0x65, 0xc8, 0x30, - 0xff, 0x41, 0xc2, 0x75, + 0xff, 0x41, 0xae, 0x75, 0x01, 0x41, 0x20, 0x31, 0xff, 0x6a, 0xa4, 0x00, - 0x00, 0x65, 0xb2, 0x45, - 0xff, 0xbf, 0xc2, 0x75, + 0x00, 0x65, 0x9e, 0x45, + 0xff, 0xbf, 0xae, 0x75, 0x01, 0x90, 0xa4, 0x30, 0x01, 0xbf, 0x20, 0x31, - 0x00, 0xbb, 0xac, 0x65, - 0xff, 0x52, 0xc0, 0x75, + 0x00, 0xbb, 0x98, 0x65, + 0xff, 0x52, 0xac, 0x75, 0x01, 0xbf, 0xcc, 0x30, 0x01, 0x90, 0xca, 0x30, 0x01, 0x52, 0x20, 0x31, @@ -744,28 +734,28 @@ 0x01, 0x65, 0x20, 0x35, 0x01, 0xbf, 0x82, 0x34, 0x01, 0x64, 0xa2, 0x30, - 0x00, 0x6a, 0xd4, 0x5e, + 0x00, 0x6a, 0xc0, 0x5e, 0x0d, 0x6a, 0x76, 0x00, - 0x00, 0x51, 0x26, 0x46, + 0x00, 0x51, 0x12, 0x46, 0x01, 0x65, 0xa4, 0x30, 0xe0, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0x1a, 0x5e, + 0x48, 0x6a, 0x06, 0x5e, 0x01, 0x6a, 0xd0, 0x01, 0x01, 0x6a, 0xdc, 0x05, 0x88, 0x6a, 0xcc, 0x00, - 0x48, 0x6a, 0x1a, 0x5e, - 0x01, 0x6a, 0xf4, 0x5d, + 0x48, 0x6a, 0x06, 0x5e, + 0x01, 0x6a, 0xe0, 0x5d, 0x01, 0x6a, 0x26, 0x05, 0x01, 0x65, 0xd8, 0x31, 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0xe0, 0x7d, + 0x80, 0xee, 0xcc, 0x7d, 0xff, 0x6a, 0xdc, 0x0d, 0x01, 0x65, 0x32, 0x31, 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0xbc, 0x46, - 0x81, 0x6a, 0xec, 0x5e, - 0x01, 0x0c, 0xec, 0x7d, - 0x04, 0x0c, 0xea, 0x6d, + 0x00, 0x65, 0xa8, 0x46, + 0x81, 0x6a, 0xd8, 0x5e, + 0x01, 0x0c, 0xd8, 0x7d, + 0x04, 0x0c, 0xd6, 0x6d, 0xe0, 0x03, 0x06, 0x08, 0xe0, 0x03, 0x7e, 0x0c, 0x01, 0x65, 0x18, 0x31, @@ -784,7 +774,7 @@ 0x01, 0x6c, 0xda, 0x34, 0x3d, 0x64, 0xa4, 0x28, 0x55, 0x64, 0xc8, 0x28, - 0x00, 0x65, 0x1a, 0x46, + 0x00, 0x65, 0x06, 0x46, 0x2e, 0x64, 0xa4, 0x28, 0x66, 0x64, 0xc8, 0x28, 0x00, 0x6c, 0xda, 0x18, @@ -795,63 +785,63 @@ 0x00, 0x6c, 0xda, 0x24, 0x01, 0x65, 0xc8, 0x30, 0xe0, 0x6a, 0xcc, 0x00, - 0x44, 0x6a, 0x16, 0x5e, + 0x44, 0x6a, 0x02, 0x5e, 0x01, 0x90, 0xe2, 0x31, - 0x04, 0x3b, 0x3a, 0x7e, + 0x04, 0x3b, 0x26, 0x7e, 0x30, 0x6a, 0xd0, 0x01, 0x20, 0x6a, 0xd0, 0x01, 0x1d, 0x6a, 0xdc, 0x01, - 0xdc, 0xee, 0x36, 0x66, - 0x00, 0x65, 0x52, 0x46, + 0xdc, 0xee, 0x22, 0x66, + 0x00, 0x65, 0x3e, 0x46, 0x20, 0x6a, 0xd0, 0x01, 0x01, 0x6a, 0xdc, 0x01, 0x20, 0xa0, 0xd8, 0x31, 0x09, 0xee, 0xdc, 0x01, - 0x80, 0xee, 0x42, 0x7e, + 0x80, 0xee, 0x2e, 0x7e, 0x11, 0x6a, 0xdc, 0x01, - 0x50, 0xee, 0x46, 0x66, + 0x50, 0xee, 0x32, 0x66, 0x20, 0x6a, 0xd0, 0x01, 0x09, 0x6a, 0xdc, 0x01, - 0x88, 0xee, 0x4c, 0x66, + 0x88, 0xee, 0x38, 0x66, 0x19, 0x6a, 0xdc, 0x01, - 0xd8, 0xee, 0x50, 0x66, + 0xd8, 0xee, 0x3c, 0x66, 0xff, 0x6a, 0xdc, 0x09, - 0x18, 0xee, 0x54, 0x6e, + 0x18, 0xee, 0x40, 0x6e, 0xff, 0x6a, 0xd4, 0x0c, 0x88, 0x6a, 0xcc, 0x00, - 0x44, 0x6a, 0x16, 0x5e, - 0x20, 0x6a, 0xf4, 0x5d, + 0x44, 0x6a, 0x02, 0x5e, + 0x20, 0x6a, 0xe0, 0x5d, 0x01, 0x3b, 0x26, 0x31, - 0x04, 0x3b, 0x6e, 0x6e, + 0x04, 0x3b, 0x5a, 0x6e, 0xa0, 0x6a, 0xca, 0x00, 0x20, 0x65, 0xc8, 0x18, - 0x00, 0x65, 0xac, 0x5e, - 0x00, 0x65, 0x66, 0x66, + 0x00, 0x65, 0x98, 0x5e, + 0x00, 0x65, 0x52, 0x66, 0x0a, 0x93, 0x26, 0x01, - 0x00, 0x65, 0xbc, 0x46, + 0x00, 0x65, 0xa8, 0x46, 0xa0, 0x6a, 0xcc, 0x00, 0xff, 0x6a, 0xc8, 0x08, - 0x20, 0x94, 0x72, 0x6e, - 0x10, 0x94, 0x74, 0x6e, - 0x08, 0x94, 0x8e, 0x6e, - 0x08, 0x94, 0x8e, 0x6e, - 0x08, 0x94, 0x8e, 0x6e, + 0x20, 0x94, 0x5e, 0x6e, + 0x10, 0x94, 0x60, 0x6e, + 0x08, 0x94, 0x7a, 0x6e, + 0x08, 0x94, 0x7a, 0x6e, + 0x08, 0x94, 0x7a, 0x6e, 0xff, 0x8c, 0xc8, 0x10, 0xc1, 0x64, 0xc8, 0x18, 0xf8, 0x64, 0xc8, 0x08, 0x01, 0x99, 0xda, 0x30, - 0x00, 0x66, 0x82, 0x66, - 0xc0, 0x66, 0xbe, 0x76, + 0x00, 0x66, 0x6e, 0x66, + 0xc0, 0x66, 0xaa, 0x76, 0x60, 0x66, 0xc8, 0x18, 0x3d, 0x64, 0xc8, 0x28, - 0x00, 0x65, 0x72, 0x46, + 0x00, 0x65, 0x5e, 0x46, 0xf7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0x90, 0x6e, + 0x08, 0x93, 0x7c, 0x6e, 0x00, 0x62, 0xc4, 0x18, - 0x00, 0x65, 0xbc, 0x5e, - 0x00, 0x65, 0x9c, 0x5e, - 0x00, 0x65, 0x9c, 0x5e, - 0x00, 0x65, 0x9c, 0x5e, + 0x00, 0x65, 0xa8, 0x5e, + 0x00, 0x65, 0x88, 0x5e, + 0x00, 0x65, 0x88, 0x5e, + 0x00, 0x65, 0x88, 0x5e, 0x01, 0x99, 0xda, 0x30, 0x01, 0x99, 0xda, 0x30, 0x01, 0x99, 0xda, 0x30, @@ -868,11 +858,11 @@ 0x01, 0x6c, 0x32, 0x31, 0x01, 0x6c, 0x32, 0x31, 0x01, 0x6c, 0x32, 0x35, - 0x08, 0x94, 0xbc, 0x7e, + 0x08, 0x94, 0xa8, 0x7e, 0xf7, 0x93, 0x26, 0x09, - 0x08, 0x93, 0xc0, 0x6e, + 0x08, 0x93, 0xac, 0x6e, 0xff, 0x6a, 0xd4, 0x0c, - 0x04, 0xb8, 0xe8, 0x6e, + 0x04, 0xb8, 0xd4, 0x6e, 0x01, 0x42, 0x7e, 0x31, 0xff, 0x6a, 0x76, 0x01, 0x01, 0x90, 0x84, 0x34, @@ -880,14 +870,14 @@ 0x01, 0x85, 0x0a, 0x01, 0x7f, 0x65, 0x10, 0x09, 0xfe, 0x85, 0x0a, 0x0d, - 0xff, 0x42, 0xe4, 0x66, - 0xff, 0x41, 0xdc, 0x66, - 0xd1, 0x6a, 0xec, 0x5e, + 0xff, 0x42, 0xd0, 0x66, + 0xff, 0x41, 0xc8, 0x66, + 0xd1, 0x6a, 0xd8, 0x5e, 0xff, 0x6a, 0xca, 0x04, 0x01, 0x41, 0x20, 0x31, 0x01, 0xbf, 0x82, 0x30, 0x01, 0x6a, 0x76, 0x00, - 0x00, 0xbb, 0x26, 0x46, + 0x00, 0xbb, 0x12, 0x46, 0x01, 0x42, 0x20, 0x31, 0x01, 0xbf, 0x84, 0x34, 0x01, 0x41, 0x7e, 0x31, @@ -1157,147 +1147,147 @@ { ahc_patch1_func, 248, 1, 2 }, { ahc_patch0_func, 249, 2, 2 }, { ahc_patch11_func, 250, 1, 1 }, - { ahc_patch9_func, 258, 31, 3 }, - { ahc_patch1_func, 274, 14, 2 }, - { ahc_patch13_func, 279, 1, 1 }, - { ahc_patch14_func, 289, 14, 1 }, - { ahc_patch1_func, 305, 1, 2 }, - { ahc_patch0_func, 306, 1, 1 }, - { ahc_patch9_func, 309, 1, 1 }, - { ahc_patch13_func, 314, 1, 1 }, - { ahc_patch9_func, 315, 2, 2 }, - { ahc_patch0_func, 317, 4, 1 }, - { ahc_patch14_func, 321, 1, 1 }, - { ahc_patch15_func, 324, 2, 3 }, - { ahc_patch9_func, 324, 1, 2 }, - { ahc_patch0_func, 325, 1, 1 }, - { ahc_patch6_func, 330, 1, 2 }, - { ahc_patch0_func, 331, 1, 1 }, - { ahc_patch1_func, 335, 50, 11 }, - { ahc_patch6_func, 344, 2, 4 }, - { ahc_patch7_func, 344, 1, 1 }, - { ahc_patch8_func, 345, 1, 1 }, - { ahc_patch0_func, 346, 1, 1 }, - { ahc_patch16_func, 347, 1, 1 }, - { ahc_patch6_func, 366, 6, 3 }, - { ahc_patch16_func, 366, 5, 1 }, - { ahc_patch0_func, 372, 5, 1 }, - { ahc_patch13_func, 380, 5, 1 }, - { ahc_patch0_func, 385, 54, 17 }, - { ahc_patch14_func, 385, 1, 1 }, - { ahc_patch7_func, 387, 2, 2 }, - { ahc_patch17_func, 388, 1, 1 }, - { ahc_patch9_func, 391, 1, 1 }, - { ahc_patch18_func, 398, 1, 1 }, - { ahc_patch14_func, 403, 9, 3 }, - { ahc_patch9_func, 404, 3, 2 }, - { ahc_patch0_func, 407, 3, 1 }, - { ahc_patch9_func, 415, 6, 2 }, - { ahc_patch0_func, 421, 9, 2 }, - { ahc_patch13_func, 421, 1, 1 }, - { ahc_patch13_func, 430, 2, 1 }, - { ahc_patch14_func, 432, 1, 1 }, - { ahc_patch9_func, 434, 1, 2 }, - { ahc_patch0_func, 435, 1, 1 }, - { ahc_patch7_func, 438, 1, 1 }, - { ahc_patch7_func, 439, 1, 1 }, - { ahc_patch8_func, 440, 3, 3 }, - { ahc_patch6_func, 441, 1, 2 }, - { ahc_patch0_func, 442, 1, 1 }, - { ahc_patch9_func, 443, 1, 1 }, - { ahc_patch15_func, 444, 1, 2 }, - { ahc_patch13_func, 444, 1, 1 }, - { ahc_patch14_func, 446, 9, 4 }, - { ahc_patch9_func, 446, 1, 1 }, - { ahc_patch9_func, 453, 2, 1 }, - { ahc_patch0_func, 455, 4, 3 }, - { ahc_patch9_func, 455, 1, 2 }, - { ahc_patch0_func, 456, 3, 1 }, - { ahc_patch1_func, 460, 2, 1 }, - { ahc_patch7_func, 462, 10, 2 }, - { ahc_patch0_func, 472, 1, 1 }, - { ahc_patch8_func, 473, 118, 22 }, - { ahc_patch1_func, 475, 3, 2 }, - { ahc_patch0_func, 478, 5, 3 }, - { ahc_patch9_func, 478, 2, 2 }, - { ahc_patch0_func, 480, 3, 1 }, + { ahc_patch9_func, 258, 27, 3 }, + { ahc_patch1_func, 274, 10, 2 }, + { ahc_patch13_func, 277, 1, 1 }, + { ahc_patch14_func, 285, 14, 1 }, + { ahc_patch1_func, 301, 1, 2 }, + { ahc_patch0_func, 302, 1, 1 }, + { ahc_patch9_func, 305, 1, 1 }, + { ahc_patch13_func, 310, 1, 1 }, + { ahc_patch9_func, 311, 2, 2 }, + { ahc_patch0_func, 313, 4, 1 }, + { ahc_patch14_func, 317, 1, 1 }, + { ahc_patch15_func, 319, 2, 3 }, + { ahc_patch9_func, 319, 1, 2 }, + { ahc_patch0_func, 320, 1, 1 }, + { ahc_patch6_func, 325, 1, 2 }, + { ahc_patch0_func, 326, 1, 1 }, + { ahc_patch1_func, 330, 47, 11 }, + { ahc_patch6_func, 337, 2, 4 }, + { ahc_patch7_func, 337, 1, 1 }, + { ahc_patch8_func, 338, 1, 1 }, + { ahc_patch0_func, 339, 1, 1 }, + { ahc_patch16_func, 340, 1, 1 }, + { ahc_patch6_func, 356, 6, 3 }, + { ahc_patch16_func, 356, 5, 1 }, + { ahc_patch0_func, 362, 7, 1 }, + { ahc_patch13_func, 372, 5, 1 }, + { ahc_patch0_func, 377, 52, 17 }, + { ahc_patch14_func, 377, 1, 1 }, + { ahc_patch7_func, 379, 2, 2 }, + { ahc_patch17_func, 380, 1, 1 }, + { ahc_patch9_func, 383, 1, 1 }, + { ahc_patch18_func, 390, 1, 1 }, + { ahc_patch14_func, 395, 9, 3 }, + { ahc_patch9_func, 396, 3, 2 }, + { ahc_patch0_func, 399, 3, 1 }, + { ahc_patch9_func, 407, 6, 2 }, + { ahc_patch0_func, 413, 9, 2 }, + { ahc_patch13_func, 413, 1, 1 }, + { ahc_patch13_func, 422, 2, 1 }, + { ahc_patch14_func, 424, 1, 1 }, + { ahc_patch9_func, 426, 1, 2 }, + { ahc_patch0_func, 427, 1, 1 }, + { ahc_patch7_func, 428, 1, 1 }, + { ahc_patch7_func, 429, 1, 1 }, + { ahc_patch8_func, 430, 3, 3 }, + { ahc_patch6_func, 431, 1, 2 }, + { ahc_patch0_func, 432, 1, 1 }, + { ahc_patch9_func, 433, 1, 1 }, + { ahc_patch15_func, 434, 1, 2 }, + { ahc_patch13_func, 434, 1, 1 }, + { ahc_patch14_func, 436, 9, 4 }, + { ahc_patch9_func, 436, 1, 1 }, + { ahc_patch9_func, 443, 2, 1 }, + { ahc_patch0_func, 445, 4, 3 }, + { ahc_patch9_func, 445, 1, 2 }, + { ahc_patch0_func, 446, 3, 1 }, + { ahc_patch1_func, 450, 2, 1 }, + { ahc_patch7_func, 452, 10, 2 }, + { ahc_patch0_func, 462, 1, 1 }, + { ahc_patch8_func, 463, 118, 22 }, + { ahc_patch1_func, 465, 3, 2 }, + { ahc_patch0_func, 468, 5, 3 }, + { ahc_patch9_func, 468, 2, 2 }, + { ahc_patch0_func, 470, 3, 1 }, + { ahc_patch1_func, 475, 2, 2 }, + { ahc_patch0_func, 477, 6, 3 }, + { ahc_patch9_func, 477, 2, 2 }, + { ahc_patch0_func, 479, 3, 1 }, { ahc_patch1_func, 485, 2, 2 }, - { ahc_patch0_func, 487, 6, 3 }, - { ahc_patch9_func, 487, 2, 2 }, - { ahc_patch0_func, 489, 3, 1 }, - { ahc_patch1_func, 495, 2, 2 }, - { ahc_patch0_func, 497, 9, 7 }, - { ahc_patch9_func, 497, 5, 6 }, - { ahc_patch19_func, 497, 1, 2 }, - { ahc_patch0_func, 498, 1, 1 }, - { ahc_patch19_func, 500, 1, 2 }, - { ahc_patch0_func, 501, 1, 1 }, - { ahc_patch0_func, 502, 4, 1 }, - { ahc_patch6_func, 507, 3, 2 }, - { ahc_patch0_func, 510, 1, 1 }, - { ahc_patch6_func, 520, 1, 2 }, - { ahc_patch0_func, 521, 1, 1 }, - { ahc_patch20_func, 558, 7, 1 }, - { ahc_patch3_func, 593, 1, 2 }, - { ahc_patch0_func, 594, 1, 1 }, - { ahc_patch21_func, 597, 1, 1 }, - { ahc_patch8_func, 599, 106, 33 }, - { ahc_patch4_func, 601, 1, 1 }, - { ahc_patch1_func, 607, 2, 2 }, - { ahc_patch0_func, 609, 1, 1 }, - { ahc_patch1_func, 612, 1, 2 }, - { ahc_patch0_func, 613, 1, 1 }, - { ahc_patch9_func, 614, 3, 3 }, - { ahc_patch15_func, 615, 1, 1 }, - { ahc_patch0_func, 617, 4, 1 }, - { ahc_patch19_func, 626, 2, 2 }, - { ahc_patch0_func, 628, 1, 1 }, - { ahc_patch19_func, 632, 10, 3 }, - { ahc_patch5_func, 634, 8, 1 }, - { ahc_patch0_func, 642, 9, 2 }, - { ahc_patch5_func, 643, 8, 1 }, - { ahc_patch4_func, 653, 1, 2 }, - { ahc_patch0_func, 654, 1, 1 }, - { ahc_patch19_func, 655, 1, 2 }, - { ahc_patch0_func, 656, 3, 2 }, - { ahc_patch4_func, 658, 1, 1 }, - { ahc_patch5_func, 659, 1, 1 }, - { ahc_patch5_func, 662, 1, 1 }, - { ahc_patch5_func, 664, 1, 1 }, - { ahc_patch4_func, 666, 2, 2 }, - { ahc_patch0_func, 668, 2, 1 }, - { ahc_patch5_func, 670, 1, 1 }, - { ahc_patch5_func, 673, 1, 1 }, - { ahc_patch5_func, 676, 1, 1 }, - { ahc_patch19_func, 680, 1, 1 }, - { ahc_patch19_func, 683, 1, 1 }, - { ahc_patch4_func, 689, 1, 1 }, - { ahc_patch6_func, 692, 1, 2 }, - { ahc_patch0_func, 693, 1, 1 }, - { ahc_patch7_func, 705, 16, 1 }, - { ahc_patch4_func, 721, 20, 1 }, - { ahc_patch9_func, 742, 4, 2 }, - { ahc_patch0_func, 746, 4, 1 }, - { ahc_patch9_func, 750, 4, 2 }, - { ahc_patch0_func, 754, 3, 1 }, - { ahc_patch6_func, 760, 1, 1 }, - { ahc_patch22_func, 762, 14, 1 }, - { ahc_patch7_func, 776, 3, 1 }, - { ahc_patch9_func, 788, 24, 8 }, - { ahc_patch19_func, 792, 1, 2 }, - { ahc_patch0_func, 793, 1, 1 }, - { ahc_patch15_func, 798, 4, 2 }, - { ahc_patch0_func, 802, 7, 3 }, - { ahc_patch23_func, 802, 5, 2 }, - { ahc_patch0_func, 807, 2, 1 }, - { ahc_patch0_func, 812, 42, 3 }, - { ahc_patch18_func, 824, 18, 2 }, - { ahc_patch0_func, 842, 1, 1 }, - { ahc_patch4_func, 866, 1, 1 }, - { ahc_patch4_func, 867, 3, 2 }, - { ahc_patch0_func, 870, 1, 1 }, - { ahc_patch13_func, 871, 3, 1 }, - { ahc_patch4_func, 874, 12, 1 } + { ahc_patch0_func, 487, 9, 7 }, + { ahc_patch9_func, 487, 5, 6 }, + { ahc_patch19_func, 487, 1, 2 }, + { ahc_patch0_func, 488, 1, 1 }, + { ahc_patch19_func, 490, 1, 2 }, + { ahc_patch0_func, 491, 1, 1 }, + { ahc_patch0_func, 492, 4, 1 }, + { ahc_patch6_func, 497, 3, 2 }, + { ahc_patch0_func, 500, 1, 1 }, + { ahc_patch6_func, 510, 1, 2 }, + { ahc_patch0_func, 511, 1, 1 }, + { ahc_patch20_func, 548, 7, 1 }, + { ahc_patch3_func, 583, 1, 2 }, + { ahc_patch0_func, 584, 1, 1 }, + { ahc_patch21_func, 587, 1, 1 }, + { ahc_patch8_func, 589, 106, 33 }, + { ahc_patch4_func, 591, 1, 1 }, + { ahc_patch1_func, 597, 2, 2 }, + { ahc_patch0_func, 599, 1, 1 }, + { ahc_patch1_func, 602, 1, 2 }, + { ahc_patch0_func, 603, 1, 1 }, + { ahc_patch9_func, 604, 3, 3 }, + { ahc_patch15_func, 605, 1, 1 }, + { ahc_patch0_func, 607, 4, 1 }, + { ahc_patch19_func, 616, 2, 2 }, + { ahc_patch0_func, 618, 1, 1 }, + { ahc_patch19_func, 622, 10, 3 }, + { ahc_patch5_func, 624, 8, 1 }, + { ahc_patch0_func, 632, 9, 2 }, + { ahc_patch5_func, 633, 8, 1 }, + { ahc_patch4_func, 643, 1, 2 }, + { ahc_patch0_func, 644, 1, 1 }, + { ahc_patch19_func, 645, 1, 2 }, + { ahc_patch0_func, 646, 3, 2 }, + { ahc_patch4_func, 648, 1, 1 }, + { ahc_patch5_func, 649, 1, 1 }, + { ahc_patch5_func, 652, 1, 1 }, + { ahc_patch5_func, 654, 1, 1 }, + { ahc_patch4_func, 656, 2, 2 }, + { ahc_patch0_func, 658, 2, 1 }, + { ahc_patch5_func, 660, 1, 1 }, + { ahc_patch5_func, 663, 1, 1 }, + { ahc_patch5_func, 666, 1, 1 }, + { ahc_patch19_func, 670, 1, 1 }, + { ahc_patch19_func, 673, 1, 1 }, + { ahc_patch4_func, 679, 1, 1 }, + { ahc_patch6_func, 682, 1, 2 }, + { ahc_patch0_func, 683, 1, 1 }, + { ahc_patch7_func, 695, 16, 1 }, + { ahc_patch4_func, 711, 20, 1 }, + { ahc_patch9_func, 732, 4, 2 }, + { ahc_patch0_func, 736, 4, 1 }, + { ahc_patch9_func, 740, 4, 2 }, + { ahc_patch0_func, 744, 3, 1 }, + { ahc_patch6_func, 750, 1, 1 }, + { ahc_patch22_func, 752, 14, 1 }, + { ahc_patch7_func, 766, 3, 1 }, + { ahc_patch9_func, 778, 24, 8 }, + { ahc_patch19_func, 782, 1, 2 }, + { ahc_patch0_func, 783, 1, 1 }, + { ahc_patch15_func, 788, 4, 2 }, + { ahc_patch0_func, 792, 7, 3 }, + { ahc_patch23_func, 792, 5, 2 }, + { ahc_patch0_func, 797, 2, 1 }, + { ahc_patch0_func, 802, 42, 3 }, + { ahc_patch18_func, 814, 18, 2 }, + { ahc_patch0_func, 832, 1, 1 }, + { ahc_patch4_func, 856, 1, 1 }, + { ahc_patch4_func, 857, 3, 2 }, + { ahc_patch0_func, 860, 1, 1 }, + { ahc_patch13_func, 861, 3, 1 }, + { ahc_patch4_func, 864, 12, 1 } }; static struct cs { @@ -1306,11 +1296,11 @@ } critical_sections[] = { { 11, 18 }, { 21, 30 }, - { 721, 737 }, - { 867, 870 }, - { 874, 880 }, - { 882, 884 }, - { 884, 886 } + { 711, 727 }, + { 857, 860 }, + { 864, 870 }, + { 872, 874 }, + { 874, 876 } }; static const int num_critical_sections = sizeof(critical_sections) diff -Nru a/drivers/scsi/aic7xxx/aiclib.h b/drivers/scsi/aic7xxx/aiclib.h --- a/drivers/scsi/aic7xxx/aiclib.h Mon Jun 9 23:16:06 2003 +++ b/drivers/scsi/aic7xxx/aiclib.h Mon Jun 9 23:16:06 2003 @@ -60,12 +60,9 @@ /* * Linux Interrupt Support. */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) -#define AIC_LINUX_IRQRETURN_T irqreturn_t -#define AIC_LINUX_IRQRETURN(ours) return (IRQ_RETVAL(ours)) -#else -#define AIC_LINUX_IRQRETURN_T void -#define AIC_LINUX_IRQRETURN(ours) return +#ifndef IRQ_RETVAL +typedef void irqreturn_t; +#define IRQ_RETVAL(x) #endif /* diff -Nru a/drivers/scsi/aic7xxx_old/aic7xxx_proc.c b/drivers/scsi/aic7xxx_old/aic7xxx_proc.c --- a/drivers/scsi/aic7xxx_old/aic7xxx_proc.c Mon Jun 9 23:16:18 2003 +++ b/drivers/scsi/aic7xxx_old/aic7xxx_proc.c Mon Jun 9 23:16:18 2003 @@ -80,10 +80,9 @@ * Return information to handle /proc support for the driver. *-F*************************************************************************/ int -aic7xxx_proc_info ( char *buffer, char **start, off_t offset, int length, - int hostno, int inout) +aic7xxx_proc_info ( struct Scsi_Host *HBAptr, char *buffer, char **start, off_t offset, int length, + int inout) { - struct Scsi_Host *HBAptr; struct aic7xxx_host *p; struct aic_dev_data *aic_dev; struct scsi_device *sdptr; @@ -93,12 +92,12 @@ HBAptr = NULL; - for(p=first_aic7xxx; p->host->host_no != hostno; p=p->next) + for(p=first_aic7xxx; p->host != HBAptr; p=p->next) ; if (!p) { - size += sprintf(buffer, "Can't find adapter for host number %d\n", hostno); + size += sprintf(buffer, "Can't find adapter for host number %d\n", HBAptr->host_no); if (size > length) { return (size); @@ -108,8 +107,6 @@ return (length); } } - - HBAptr = p->host; if (inout == TRUE) /* Has data been written to the file? */ { diff -Nru a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c --- a/drivers/scsi/arm/acornscsi.c Mon Jun 9 23:16:13 2003 +++ b/drivers/scsi/arm/acornscsi.c Mon Jun 9 23:16:13 2003 @@ -2857,18 +2857,15 @@ return string; } -int acornscsi_proc_info(char *buffer, char **start, off_t offset, - int length, int host_no, int inout) +int acornscsi_proc_info(struct Scsi_Host *instance, char *buffer, char **start, off_t offset, + int length, int inout) { int pos, begin = 0, devidx; - struct Scsi_Host *instance; Scsi_Device *scd; AS_Host *host; char *p = buffer; - instance = scsi_host_hn_get(host_no); - - if (inout == 1 || !instance) + if (inout == 1) return -EINVAL; host = (AS_Host *)instance->hostdata; diff -Nru a/drivers/scsi/arm/arxescsi.c b/drivers/scsi/arm/arxescsi.c --- a/drivers/scsi/arm/arxescsi.c Mon Jun 9 23:16:13 2003 +++ b/drivers/scsi/arm/arxescsi.c Mon Jun 9 23:16:13 2003 @@ -236,17 +236,12 @@ * Returns : length of data written to buffer. */ static int -arxescsi_proc_info(char *buffer, char **start, off_t offset, int length, +arxescsi_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int host_no, int inout) { - struct Scsi_Host *host; struct arxescsi_info *info; char *p = buffer; int pos; - - host = scsi_host_hn_get(host_no); - if (!host) - return 0; info = (struct arxescsi_info *)host->hostdata; if (inout == 1) diff -Nru a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c --- a/drivers/scsi/arm/cumana_1.c Mon Jun 9 23:16:07 2003 +++ b/drivers/scsi/arm/cumana_1.c Mon Jun 9 23:16:07 2003 @@ -35,9 +35,6 @@ #define NCR5380_queue_command cumanascsi_queue_command #define NCR5380_proc_info cumanascsi_proc_info -int NCR5380_proc_info(char *buffer, char **start, off_t offset, - int length, int hostno, int inout); - #define BOARD_NORMAL 0 #define BOARD_NCR53C400 1 diff -Nru a/drivers/scsi/arm/cumana_2.c b/drivers/scsi/arm/cumana_2.c --- a/drivers/scsi/arm/cumana_2.c Mon Jun 9 23:16:15 2003 +++ b/drivers/scsi/arm/cumana_2.c Mon Jun 9 23:16:15 2003 @@ -353,17 +353,12 @@ * inout - 0 for reading, 1 for writing. * Returns : length of data written to buffer. */ -int cumanascsi_2_proc_info (char *buffer, char **start, off_t offset, - int length, int host_no, int inout) +int cumanascsi_2_proc_info (struct Scsi_Host *host, char *buffer, char **start, off_t offset, + int length, int inout) { - struct Scsi_Host *host; struct cumanascsi2_info *info; char *p = buffer; int pos; - - host = scsi_host_hn_get(host_no); - if (!host) - return 0; if (inout == 1) return cumanascsi_2_set_proc_info(host, buffer, length); diff -Nru a/drivers/scsi/arm/ecoscsi.c b/drivers/scsi/arm/ecoscsi.c --- a/drivers/scsi/arm/ecoscsi.c Mon Jun 9 23:16:19 2003 +++ b/drivers/scsi/arm/ecoscsi.c Mon Jun 9 23:16:19 2003 @@ -21,26 +21,6 @@ * 1+ (800) 334-5454 */ -/* - * Options : - * - * PARITY - enable parity checking. Not supported. - * - * SCSI2 - enable support for SCSI-II tagged queueing. Untested. - * - * USLEEP - enable support for devices that don't disconnect. Untested. - */ - -/* - * $Log: ecoscsi.c,v $ - * Revision 1.2 1998/03/08 05:49:47 davem - * Merge to 2.1.89 - * - * Revision 1.1 1998/02/23 02:45:24 davem - * Merge to 2.1.88 - * - */ - #include <linux/module.h> #include <linux/signal.h> #include <linux/sched.h> @@ -94,71 +74,8 @@ * */ -void ecoscsi_setup(char *str, int *ints) { -} - -/* - * Function : int ecoscsi_detect(Scsi_Host_Template * tpnt) - * - * Purpose : initializes ecoscsi NCR5380 driver based on the - * command line / compile time port and irq definitions. - * - * Inputs : tpnt - template for this SCSI adapter. - * - * Returns : 1 if a host adapter was found, 0 if not. - * - */ - -int ecoscsi_detect(Scsi_Host_Template * tpnt) +void ecoscsi_setup(char *str, int *ints) { - struct Scsi_Host *host; - - tpnt->proc_name = "ecoscsi"; - - host = scsi_register (tpnt, sizeof(struct NCR5380_hostdata)); - if (!host) - return 0; - - host->io_port = 0x80ce8000; - host->n_io_port = 144; - host->irq = IRQ_NONE; - - if ( !(request_region(host->io_port, host->n_io_port, "ecoscsi")) ) - goto unregister_scsi; - - ecoscsi_write (host, MODE_REG, 0x20); /* Is it really SCSI? */ - if (ecoscsi_read (host, MODE_REG) != 0x20) /* Write to a reg. */ - goto release_reg; - - ecoscsi_write( host, MODE_REG, 0x00 ); /* it back. */ - if (ecoscsi_read (host, MODE_REG) != 0x00) - goto release_reg; - - NCR5380_init(host, 0); - - printk("scsi%d: at port 0x%08lx irqs disabled", host->host_no, host->io_port); - printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", - host->can_queue, host->cmd_per_lun, ECOSCSI_PUBLIC_RELEASE); - printk("\nscsi%d:", host->host_no); - NCR5380_print_options(host); - printk("\n"); - - return 1; - -release_reg: - release_region(host->io_port, host->n_io_port); -unregister_scsi: - scsi_unregister(host); - return 0; -} - -int ecoscsi_release (struct Scsi_Host *shpnt) -{ - if (shpnt->irq != IRQ_NONE) - free_irq (shpnt->irq, NULL); - if (shpnt->io_port) - release_region (shpnt->io_port, shpnt->n_io_port); - return 0; } const char * ecoscsi_info (struct Scsi_Host *spnt) @@ -233,9 +150,6 @@ #endif #undef STAT -int NCR5380_proc_info(char *buffer, char **start, off_t offset, - int length, int hostno, int inout); - #define BOARD_NORMAL 0 #define BOARD_NCR53C400 1 @@ -244,8 +158,7 @@ static Scsi_Host_Template ecoscsi_template = { .module = THIS_MODULE, .name = "Serial Port EcoSCSI NCR5380", - .detect = ecoscsi_detect, - .release = ecoscsi_release, + .proc_name = "ecoscsi", .info = ecoscsi_info, .queuecommand = ecoscsi_queue_command, .eh_abort_handler = NCR5380_abort, @@ -259,19 +172,60 @@ .use_clustering = DISABLE_CLUSTERING }; +static struct Scsi_Host *host; + static int __init ecoscsi_init(void) { - scsi_register_host(&ecoscsi_template); - if (ecoscsi_template.present) + + host = scsi_register(tpnt, sizeof(struct NCR5380_hostdata)); + if (!host) return 0; - scsi_unregister_host(&ecoscsi_template); + host->io_port = 0x80ce8000; + host->n_io_port = 144; + host->irq = IRQ_NONE; + + if (!(request_region(host->io_port, host->n_io_port, "ecoscsi")) ) + goto unregister_scsi; + + ecoscsi_write(host, MODE_REG, 0x20); /* Is it really SCSI? */ + if (ecoscsi_read(host, MODE_REG) != 0x20) /* Write to a reg. */ + goto release_reg; + + ecoscsi_write(host, MODE_REG, 0x00 ); /* it back. */ + if (ecoscsi_read(host, MODE_REG) != 0x00) + goto release_reg; + + NCR5380_init(host, 0); + + printk("scsi%d: at port 0x%08lx irqs disabled", host->host_no, host->io_port); + printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", + host->can_queue, host->cmd_per_lun, ECOSCSI_PUBLIC_RELEASE); + printk("\nscsi%d:", host->host_no); + NCR5380_print_options(host); + printk("\n"); + + scsi_add_host(host, NULL); + return 0; + +release_reg: + release_region(host->io_port, host->n_io_port); +unregister_scsi: + scsi_unregister(host); return -ENODEV; } static void __exit ecoscsi_exit(void) { - scsi_unregister_host(&ecoscsi_template); + scsi_remove_host(host); + + if (shpnt->irq != IRQ_NONE) + free_irq(shpnt->irq, NULL); + if (shpnt->io_port) + release_region(shpnt->io_port, shpnt->n_io_port); + + scsi_unregister(host); + return 0; } module_init(ecoscsi_init); diff -Nru a/drivers/scsi/arm/eesox.c b/drivers/scsi/arm/eesox.c --- a/drivers/scsi/arm/eesox.c Mon Jun 9 23:16:19 2003 +++ b/drivers/scsi/arm/eesox.c Mon Jun 9 23:16:19 2003 @@ -427,17 +427,12 @@ * inout - 0 for reading, 1 for writing. * Returns : length of data written to buffer. */ -int eesoxscsi_proc_info(char *buffer, char **start, off_t offset, - int length, int host_no, int inout) +int eesoxscsi_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, + int length, int inout) { - struct Scsi_Host *host; struct eesoxscsi_info *info; char *p = buffer; int pos; - - host = scsi_host_hn_get(host_no); - if (!host) - return 0; if (inout == 1) return eesoxscsi_set_proc_info(host, buffer, length); diff -Nru a/drivers/scsi/arm/oak.c b/drivers/scsi/arm/oak.c --- a/drivers/scsi/arm/oak.c Mon Jun 9 23:16:05 2003 +++ b/drivers/scsi/arm/oak.c Mon Jun 9 23:16:05 2003 @@ -30,9 +30,6 @@ #define NCR5380_queue_command oakscsi_queue_command #define NCR5380_proc_info oakscsi_proc_info -int NCR5380_proc_info(char *buffer, char **start, off_t offset, - int length, int hostno, int inout); - #define NCR5380_implementation_fields int port, ctrl #define NCR5380_local_declare() struct Scsi_Host *_instance #define NCR5380_setup(instance) _instance = instance diff -Nru a/drivers/scsi/arm/powertec.c b/drivers/scsi/arm/powertec.c --- a/drivers/scsi/arm/powertec.c Mon Jun 9 23:16:15 2003 +++ b/drivers/scsi/arm/powertec.c Mon Jun 9 23:16:15 2003 @@ -239,19 +239,14 @@ * inout - 0 for reading, 1 for writing. * Returns : length of data written to buffer. */ -int powertecscsi_proc_info(char *buffer, char **start, off_t offset, +int powertecscsi_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int host_no, int inout) { - struct Scsi_Host *host; struct powertec_info *info; char *p = buffer; int pos; - host = scsi_host_hn_get(host_no); - if (!host) - return 0; - - if (inout == 1) + If (inout == 1) return powertecscsi_set_proc_info(host, buffer, length); info = (struct powertec_info *)host->hostdata; diff -Nru a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c --- a/drivers/scsi/atari_NCR5380.c Mon Jun 9 23:16:14 2003 +++ b/drivers/scsi/atari_NCR5380.c Mon Jun 9 23:16:14 2003 @@ -746,11 +746,10 @@ #ifndef NCR5380_proc_info static #endif -int NCR5380_proc_info (char *buffer, char **start, off_t offset, - int length, int hostno, int inout) +int NCR5380_proc_info (struct Scsi_Host *instance, char *buffer, char **start, off_t offset, + int length, int inout) { char *pos = buffer; - struct Scsi_Host *instance; struct NCR5380_hostdata *hostdata; Scsi_Cmnd *ptr; unsigned long flags; @@ -763,9 +762,6 @@ } \ } while (0) - instance = scsi_host_hn_get(hostno); - if (!instance) - return(-ESRCH); hostdata = (struct NCR5380_hostdata *)instance->hostdata; if (inout) { /* Has data been written to the file ? */ diff -Nru a/drivers/scsi/atari_scsi.h b/drivers/scsi/atari_scsi.h --- a/drivers/scsi/atari_scsi.h Mon Jun 9 23:16:13 2003 +++ b/drivers/scsi/atari_scsi.h Mon Jun 9 23:16:13 2003 @@ -21,7 +21,6 @@ int atari_scsi_detect (Scsi_Host_Template *); const char *atari_scsi_info (struct Scsi_Host *); int atari_scsi_reset (Scsi_Cmnd *, unsigned int); -int atari_scsi_proc_info (char *, char **, off_t, int, int, int); #ifdef MODULE int atari_scsi_release (struct Scsi_Host *); #else diff -Nru a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c --- a/drivers/scsi/atp870u.c Mon Jun 9 23:16:10 2003 +++ b/drivers/scsi/atp870u.c Mon Jun 9 23:16:10 2003 @@ -2657,33 +2657,14 @@ } #define BLS buffer + len + size -int atp870u_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout) +int atp870u_proc_info(struct Scsi_Host *HBAptr, char *buffer, char **start, off_t offset, int length, int inout) { - struct Scsi_Host *HBAptr; static u8 buff[512]; - int i; int size = 0; int len = 0; off_t begin = 0; off_t pos = 0; - HBAptr = NULL; - for (i = 0; i < MAX_ATP; i++) { - if ((HBAptr = atp_host[i]) != NULL) { - if (HBAptr->host_no == hostno) { - break; - } - HBAptr = NULL; - } - } - - if (HBAptr == NULL) { - size += sprintf(BLS, "Can't find adapter for host number %d\n", hostno); - len += size; - pos = begin + len; - size = 0; - goto stop_output; - } if (inout == TRUE) { /* Has data been written to the file? */ return (atp870u_set_info(buffer, length, HBAptr)); } @@ -2701,9 +2682,7 @@ size += sprintf(BLS, " IRQ: %d\n", HBAptr->irq); len += size; pos = begin + len; - size = 0; -stop_output: *start = buffer + (offset - begin); /* Start of wanted data */ len -= (offset - begin); /* Start slop */ if (len > length) { diff -Nru a/drivers/scsi/atp870u.h b/drivers/scsi/atp870u.h --- a/drivers/scsi/atp870u.h Mon Jun 9 23:16:06 2003 +++ b/drivers/scsi/atp870u.h Mon Jun 9 23:16:06 2003 @@ -35,6 +35,4 @@ extern const char *atp870u_info(struct Scsi_Host *); -extern int atp870u_proc_info(char *, char **, off_t, int, int, int); - #endif diff -Nru a/drivers/scsi/cpqfcTS.h b/drivers/scsi/cpqfcTS.h --- a/drivers/scsi/cpqfcTS.h Mon Jun 9 23:16:10 2003 +++ b/drivers/scsi/cpqfcTS.h Mon Jun 9 23:16:10 2003 @@ -6,7 +6,7 @@ extern int cpqfcTS_detect(Scsi_Host_Template *); extern int cpqfcTS_release(struct Scsi_Host *); extern const char * cpqfcTS_info(struct Scsi_Host *); -extern int cpqfcTS_proc_info(char *, char **, off_t, int, int, int); +extern int cpqfcTS_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int); extern int cpqfcTS_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); extern int cpqfcTS_abort(Scsi_Cmnd *); extern int cpqfcTS_reset(Scsi_Cmnd *, unsigned int); diff -Nru a/drivers/scsi/cpqfcTSinit.c b/drivers/scsi/cpqfcTSinit.c --- a/drivers/scsi/cpqfcTSinit.c Mon Jun 9 23:16:06 2003 +++ b/drivers/scsi/cpqfcTSinit.c Mon Jun 9 23:16:06 2003 @@ -921,10 +921,9 @@ // Routine to get data for /proc RAM filesystem // -int cpqfcTS_proc_info (char *buffer, char **start, off_t offset, int length, - int hostno, int inout) +int cpqfcTS_proc_info (struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, + int inout) { - struct Scsi_Host *host; Scsi_Cmnd DumCmnd; int Chan, Targ, i; struct info_str info; @@ -933,11 +932,6 @@ PFC_LOGGEDIN_PORT pLoggedInPort; char buf[81]; - // Search the Scsi host list for our controller - host = scsi_host_hn_get(hostno); - - if (!host) return -ESRCH; - if (inout) return -EINVAL; // get the pointer to our Scsi layer HBA buffer @@ -969,7 +963,7 @@ NULL, // DON'T search list for FC WWN NULL))){ // DON'T care about end of list copy_info(&info, "Host: scsi%d Channel: %02d TargetId: %02d -> WWN: ", - hostno, Chan, Targ); + host->host_no, Chan, Targ); for( i=3; i>=0; i--) // copy the LOGIN port's WWN copy_info(&info, "%02X", pLoggedInPort->u.ucWWN[i]); for( i=7; i>3; i--) // copy the LOGIN port's WWN diff -Nru a/drivers/scsi/dc390.h b/drivers/scsi/dc390.h --- a/drivers/scsi/dc390.h Mon Jun 9 23:16:08 2003 +++ b/drivers/scsi/dc390.h Mon Jun 9 23:16:08 2003 @@ -33,8 +33,6 @@ # define USE_NEW_EH #endif -#if defined(HOSTS_C) || defined(MODULE) || LINUX_VERSION_CODE > KERNEL_VERSION(2,3,99) - extern int DC390_detect(Scsi_Host_Template *psht); extern int DC390_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)); extern int DC390_abort(Scsi_Cmnd *cmd); @@ -47,7 +45,5 @@ #else # define DC390_release NULL #endif - -extern int DC390_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout); #endif /* DC390_H */ diff -Nru a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c --- a/drivers/scsi/dc395x.c Mon Jun 9 23:16:07 2003 +++ b/drivers/scsi/dc395x.c Mon Jun 9 23:16:07 2003 @@ -46,8 +46,8 @@ * ************************************************************************ */ - #include <linux/module.h> +#include <linux/moduleparam.h> #include <linux/delay.h> #include <linux/ctype.h> #include <linux/blk.h> @@ -60,109 +60,147 @@ #include <linux/init.h> #include <linux/spinlock.h> -/* Debugging */ -/*#define DC395x_DEBUG_KG */ -/*#define DC395x_DEBUG0*/ -/*#define DC395x_DEBUG1*/ -/*#define DC395x_DEBUGDCB*/ -#define DC395x_DEBUGTRACE -/*#define DC395x_DEBUGTRACEALL*/ -/*#define DC395x_DEBUGPARSE*/ -/*#define DC395x_SGPARANOIA*/ -/*#define DC395x_DEBUGFIFO*/ -/*#define DC395x_DEBUGRECURSION*/ -/*#define DC395x_DEBUGPIO*/ -/*#define DC395x_DEBUGMALLOC*/ - -/* DISable features */ +/*--------------------------------------------------------------------------- + Features + ---------------------------------------------------------------------------*/ +/* + * Set to disable parts of the driver + */ /*#define DC395x_NO_DISCONNECT*/ /*#define DC395x_NO_TAGQ*/ /*#define DC395x_NO_SYNC*/ /*#define DC395x_NO_WIDE*/ -#ifdef DC395x_DEBUG0 -# define DEBUG0(x) x -#else -# define DEBUG0(x) -#endif +/*--------------------------------------------------------------------------- + Debugging + ---------------------------------------------------------------------------*/ +/* + * Types of debugging that can be enabled and disabled + */ +#define DBG_KG 0x0001 +#define DBG_0 0x0002 +#define DBG_1 0x0004 +#define DBG_DCB 0x0008 +#define DBG_PARSE 0x0010 /* debug command line parsing */ +#define DBG_SGPARANOIA 0x0020 +#define DBG_FIFO 0x0040 +#define DBG_PIO 0x0080 +#define DBG_RECURSION 0x0100 /* check for excessive recursion */ +#define DBG_MALLOC 0x0200 /* report on memory allocations */ +#define DBG_TRACE 0x0400 +#define DBG_TRACEALL 0x0800 -#ifdef DC395x_DEBUG1 -# define DEBUG1(x) x -#else -# define DEBUG1(x) -#endif -#ifdef DC395x_DEBUGDCB -# define DCBDEBUG(x) x -#else -# define DCBDEBUG(x) -#endif +/* + * Set set of things to output debugging for. + * Undefine to remove all debugging + */ +/*#define DEBUG_MASK (DBG_0|DBG_1|DBG_DCB|DBG_PARSE|DBG_SGPARANOIA|DBG_FIFO|DBG_PIO|DBG_TRACE|DBG_TRACEALL)*/ +/*#define DEBUG_MASK DBG_0*/ + + +/* + * Output a kernel mesage at the specified level and append the + * driver name and a ": " to the start of the message + */ +#define dprintkl(level, format, arg...) \ + printk(level DC395X_NAME ": " format , ## arg) + + +#ifdef DEBUG_MASK +/* + * print a debug message - this is formated with KERN_DEBUG, then the + * driver name followed by a ": " and then the message is output. + * This also checks that the specified debug level is enabled before + * outputing the message + */ +#define dprintkdbg(type, format, arg...) \ + do { \ + if ((type) & (DEBUG_MASK)) \ + dprintkl(KERN_DEBUG , format , ## arg); \ + } while (0) + +/* + * Check if the specified type of debugging is enabled + */ +#define debug_enabled(type) ((DEBUG_MASK) & (type)) -#ifdef DC395x_DEBUGPARSE -# define PARSEDEBUG(x) x #else -# define PARSEDEBUG(x) +/* + * No debugging. Do nothing + */ +#define dprintkdbg(type, format, arg...) \ + do {} while (0) +#define debug_enabled(type) (0) + #endif -#ifdef DC395x_DEBUGRECURSION -# define DEBUGRECURSION(x) x -#else -# define DEBUGRECURSION(x) + +/* + * The recursion debugging just counts entries into the driver and + * prints out a messge if it exceeds a certain limit. This variable + * hold the count. + */ +#if debug_enabled(DBG_RECURSION) +static int dbg_in_driver = 0; #endif -#ifdef DC395x_DEBUGPIO -# define DEBUGPIO(x) x + +/* + * Memory allocation debugging + * Just reports when memory is allocated and/or released. + */ +#if debug_enabled(DBG_MALLOC) +inline void *dc395x_kmalloc(size_t sz, int fl) +{ + void *ptr = kmalloc(sz, fl); + dprintkl(KERN_DEBUG, "Alloc %i bytes @ %p w/ fl %08x\n", sz, ptr, fl); + return ptr; +} +inline void dc395x_kfree(const void *adr) +{ + dprintkl(KERN_DEBUG, "Free mem @ %p\n", adr); + kfree(adr); +} #else -# define DEBUGPIO(x) +#define dc395x_kmalloc(sz, fl) kmalloc(sz, fl) +#define dc395x_kfree(adr) kfree(adr) #endif -/* Here comes the joker of all debugging facilities! */ -#ifdef DC395x_DEBUGTRACEALL -# ifndef DC395x_DEBUGTRACE -# define DC395x_DEBUGTRACE -# endif + +/* + * Debug/trace stuff + */ +#if debug_enabled(DBG_TRACEALL) # define TRACEOUTALL(x...) printk ( x) #else # define TRACEOUTALL(x...) do {} while (0) #endif -#ifdef DC395x_DEBUGTRACE + +#if debug_enabled(DBG_TRACE|DBG_TRACEALL) # define DEBUGTRACEBUFSZ 512 char DC395x_tracebuf[64]; char DC395x_traceoverflow[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; # define TRACEPRINTF(x...) \ -do { int ln = sprintf (DC395x_tracebuf, x); \ - if (pSRB->debugpos + ln >= DEBUGTRACEBUFSZ) \ - { pSRB->debugtrace[pSRB->debugpos] = 0; pSRB->debugpos = DEBUGTRACEBUFSZ/5; pSRB->debugtrace[pSRB->debugpos++] = '>'; }; \ - sprintf (pSRB->debugtrace + pSRB->debugpos, "%s", DC395x_tracebuf); \ - pSRB->debugpos += ln - 1; \ - } while (0) -# define TRACEOUT(x...) printk ( x) + do { \ + int ln = sprintf(DC395x_tracebuf, x); \ + if (pSRB->debugpos + ln >= DEBUGTRACEBUFSZ) { \ + pSRB->debugtrace[pSRB->debugpos] = 0; \ + pSRB->debugpos = DEBUGTRACEBUFSZ/5; \ + pSRB->debugtrace[pSRB->debugpos++] = '>'; \ + } \ + sprintf(pSRB->debugtrace + pSRB->debugpos, "%s", DC395x_tracebuf); \ + pSRB->debugpos += ln - 1; \ + } while (0) +# define TRACEOUT(x...) printk (x) #else # define TRACEPRINTF(x...) do {} while (0) # define TRACEOUT(x...) do {} while (0) #endif -#ifdef DC395x_DEBUGMALLOC -inline void *dc395x_kmalloc(size_t sz, int fl) -{ - void *ptr = kmalloc(sz, fl); - printk(KERN_DEBUG DC395X_NAME ": Alloc %i bytes @ %p w/ fl %08x\n", - sz, ptr, fl); - return ptr; -} -inline void dc395x_kfree(const void *adr) -{ - printk(KERN_DEBUG DC395X_NAME ": Free mem @ %p\n", adr); - kfree(adr); -} - -# define KMALLOC(sz,fl) dc395x_kmalloc(sz,fl) -# define KFREE(adr) dc395x_kfree(adr) -#else -# define KMALLOC(sz,fl) kmalloc(sz,fl) -# define KFREE(adr) kfree(adr) -#endif +/*--------------------------------------------------------------------------- + ---------------------------------------------------------------------------*/ #ifndef PCI_VENDOR_ID_TEKRAM @@ -172,16 +210,6 @@ #define PCI_DEVICE_ID_TEKRAM_TRMS1040 0x0391 /* Device ID */ #endif -static struct pci_device_id dc395x_pci_tbl[] __devinitdata = { - { - .vendor = PCI_VENDOR_ID_TEKRAM, - .device = PCI_DEVICE_ID_TEKRAM_TRMS1040, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - }, - {} /* Terminating entry */ -}; -MODULE_DEVICE_TABLE(pci, dc395x_pci_tbl); #define DC395x_LOCK_IO(dev) spin_lock_irqsave(((struct Scsi_Host *)dev)->host_lock, flags) @@ -284,7 +312,7 @@ u8 padding; u16 debugpos; /* Offset 0x58/0x40 */ -#ifdef DC395x_DEBUGTRACE +#if debug_enabled(DBG_TRACE|DBG_TRACEALL) char *debugtrace; /* Offset 0x60/0x44 */ #endif @@ -509,7 +537,6 @@ struct DeviceCtlBlk *pDCB); void DC395x_initDCB(struct AdapterCtlBlk *pACB, struct DeviceCtlBlk **ppDCB, u8 target, u8 lun); -int DC395x_shutdown(struct Scsi_Host *host); static void DC395x_remove_dev(struct AdapterCtlBlk *pACB, struct DeviceCtlBlk *pDCB); @@ -519,8 +546,6 @@ static u16 DC395x_adapterCnt = 0; static u16 DC395x_CurrSyncOffset = 0; -DEBUGRECURSION(static char in_driver = 0; - ) static char DC395x_monitor_next_IRQ = 0; /* @@ -578,119 +603,203 @@ static u16 dc395x_clock_speed[] = { 200, 133, 100, 80, 67, 58, 50, 40 }; /* real period:48ns,72ns,100ns,124ns,148ns,172ns,200ns,248ns */ + + +/*--------------------------------------------------------------------------- + Configuration + ---------------------------------------------------------------------------*/ + /* - * Override defaults on cmdline: - * dc395x_trm = AdaptID, MaxSpeed (Index), DevMode (Bitmapped), AdaptMode (Bitmapped), Tags (log2-1), DelayReset + * Command line parameters are stored in a structure below. + * These are the index's into the strcuture for the various + * command line options. */ -int dc395x_trm[] = { -2, -2, -2, -2, -2, -2 }; +#define CFG_ADAPTER_ID 0 +#define CFG_MAX_SPEED 1 +#define CFG_DEV_MODE 2 +#define CFG_ADAPTER_MODE 3 +#define CFG_TAGS 4 +#define CFG_RESET_DELAY 5 + +#define CFG_NUM 6 /* number of configuration items */ -#if defined(MODULE) -MODULE_PARM(dc395x_trm, "1-6i"); -MODULE_PARM_DESC(dc395x_trm, - "Host SCSI ID, Speed (0=20MHz), Device Flags, Adapter Flags, Max Tags (log2(tags)-1), DelayReset (s)"); + +/* + * Value used to indicate that a command line override + * hasn't been used to modify the value. + */ +#define CFG_PARAM_UNSET -1 + + +/* + * Hold command line parameters. + */ +struct dc395x_config_data { + int value; /* value of this setting */ + int min; /* minimum value */ + int max; /* maximum value */ + int def; /* default value */ + int safe; /* safe value */ +}; +struct dc395x_config_data __initdata cfg_data[] = { + { /* adapter id */ + CFG_PARAM_UNSET, + 0, + 15, + 7, + 7 + }, + { /* max speed */ + CFG_PARAM_UNSET, + 0, + 7, + 1, /* 13.3Mhz */ + 4, /* 6.7Hmz */ + }, + { /* dev mode */ + CFG_PARAM_UNSET, + 0, + 0x3f, + NTC_DO_PARITY_CHK | NTC_DO_DISCONNECT | NTC_DO_SYNC_NEGO | + NTC_DO_WIDE_NEGO | NTC_DO_TAG_QUEUEING | + NTC_DO_SEND_START, + NTC_DO_PARITY_CHK | NTC_DO_SEND_START + }, + { /* adapter mode */ + CFG_PARAM_UNSET, + 0, + 0x2f, +#ifdef CONFIG_SCSI_MULTI_LUN + NAC_SCANLUN | #endif + NAC_GT2DRIVES | NAC_GREATER_1G | NAC_POWERON_SCSI_RESET + /*| NAC_ACTIVE_NEG*/, + NAC_GT2DRIVES | NAC_GREATER_1G | NAC_POWERON_SCSI_RESET | 0x08 + }, + { /* tags */ + CFG_PARAM_UNSET, + 0, + 5, + 3, /* 16 tags (??) */ + 2, + }, + { /* reset delay */ + CFG_PARAM_UNSET, + 0, + 180, + 1, /* 1 second */ + 10, /* 10 seconds */ + } +}; -MODULE_AUTHOR("C.L. Huang / Erich Chen / Kurt Garloff"); -MODULE_DESCRIPTION - ("SCSI host adapter driver for Tekram TRM-S1040 based adapters: Tekram DC395 and DC315 series"); -MODULE_SUPPORTED_DEVICE("sd,sr,sg,st"); -MODULE_LICENSE("GPL"); +/* + * Safe settings. If set to zero the the BIOS/default values with command line + * overrides will be used. If set to 1 then safe and slow settings will be used. + */ +static int dc395x_safe = 0; +module_param_named(safe, dc395x_safe, bool, 0); +MODULE_PARM_DESC(safe, "Use safe and slow settings only. Default: false"); -/* Delaying after a reset */ -static char __initdata DC395x_interpd[] = { 1, 3, 5, 10, 16, 30, 60, 120 }; -/* Convert EEprom value to seconds */ -static void __init DC395x_interpret_delay(struct NvRamType *eeprom) -{ - /*printk (DC395X_NAME ": Debug: Delay: %i\n", eeprom->NvramDelayTime); */ - eeprom->NvramDelayTime = DC395x_interpd[eeprom->NvramDelayTime]; -} +module_param_named(adapter_id, cfg_data[CFG_ADAPTER_ID].value, int, 0); +MODULE_PARM_DESC(adapter_id, "Adapter SCSI ID. Default 7 (0-15)"); + +module_param_named(max_speed, cfg_data[CFG_MAX_SPEED].value, int, 0); +MODULE_PARM_DESC(max_speed, "Maximum bus speed. Default 1 (0-7) Speeds: 0=20, 1=13.3, 2=10, 3=8, 4=6.7, 5=5.8, 6=5, 7=4 Mhz"); + +module_param_named(dev_mode, cfg_data[CFG_DEV_MODE].value, int, 0); +MODULE_PARM_DESC(dev_mode, "Device mode."); -/* seconds to EEProm value */ -static int __init DC395x_uninterpret_delay(int delay) +module_param_named(adapter_mode, cfg_data[CFG_ADAPTER_MODE].value, int, 0); +MODULE_PARM_DESC(adapter_mode, "Adapter mode."); + +module_param_named(tags, cfg_data[CFG_TAGS].value, int, 0); +MODULE_PARM_DESC(tags, "Number of tags (1<<x). Default 3 (0-5)"); + +module_param_named(reset_delay, cfg_data[CFG_RESET_DELAY].value, int, 0); +MODULE_PARM_DESC(reset_delay, "Reset delay in seconds. Default 1 (0-180)"); + + +/** + * set_safe_settings - if the safe parameter is set then + * set all values to the safe and slow values. + **/ +static +void __init set_safe_settings(void) { - u8 idx = 0; - while (idx < 7 && DC395x_interpd[idx] < delay) - idx++; - return idx; + if (dc395x_safe) + { + int i; + + dprintkl(KERN_INFO, "Using sage settings.\n"); + for (i = 0; i < CFG_NUM; i++) + { + cfg_data[i].value = cfg_data[i].safe; + } + } } -/* Handle "-1" case */ -static void __init DC395x_check_for_safe_settings(void) +/** + * fix_settings - reset any boot parmeters which are out of range + * back to the default values. + **/ +static +void __init fix_settings(void) { - if (dc395x_trm[0] == -1 || dc395x_trm[0] > 15) { /* modules-2.0.0 passes -1 as string */ - dc395x_trm[0] = 7; - dc395x_trm[1] = 4; - dc395x_trm[2] = 0x09; - dc395x_trm[3] = 0x0f; - dc395x_trm[4] = 2; - dc395x_trm[5] = 10; - printk(KERN_INFO DC395X_NAME ": Using safe settings.\n"); + int i; + + dprintkdbg(DBG_PARSE, "setup %08x %08x %08x %08x %08x %08x\n", + cfg_data[CFG_ADAPTER_ID].value, + cfg_data[CFG_MAX_SPEED].value, + cfg_data[CFG_DEV_MODE].value, + cfg_data[CFG_ADAPTER_MODE].value, + cfg_data[CFG_TAGS].value, + cfg_data[CFG_RESET_DELAY].value); + for (i = 0; i < CFG_NUM; i++) + { + if (cfg_data[i].value < cfg_data[i].min || + cfg_data[i].value > cfg_data[i].max) + { + cfg_data[i].value = cfg_data[i].def; + } } } -/* Defaults, to be overriden by (a) BIOS and (b) Cmnd line (kernel/module) args */ -int __initdata dc395x_def[] = { 7, 1 /* 13.3MHz */ , - NTC_DO_PARITY_CHK | NTC_DO_DISCONNECT | NTC_DO_SYNC_NEGO | - NTC_DO_WIDE_NEGO | NTC_DO_TAG_QUEUEING | NTC_DO_SEND_START, - NAC_GT2DRIVES | NAC_GREATER_1G | NAC_POWERON_SCSI_RESET - /* | NAC_ACTIVE_NEG */ -#ifdef CONFIG_SCSI_MULTI_LUN - | NAC_SCANLUN -#endif - , 3 /* 16 Tags per LUN */ , 1 /* s delay after Reset */ -}; -/* Copy defaults over set values where missing */ -static void __init DC395x_fill_with_defaults(void) + +/* + * Mapping from the eeprom value (index into this array) to the + * the number of actual seconds that the delay should be for. + */ +static +char __initdata eeprom_index_to_delay_map[] = { 1, 3, 5, 10, 16, 30, 60, 120 }; + + +/** + * eeprom_index_to_delay - Take the eeprom delay setting and convert it + * into a number of seconds. + */ +static void __init eeprom_index_to_delay(struct NvRamType *eeprom) { - int i; - PARSEDEBUG(printk - (KERN_INFO DC395X_NAME - ": setup %08x %08x %08x %08x %08x %08x\n", - dc395x_trm[0], dc395x_trm[1], dc395x_trm[2], - dc395x_trm[3], dc395x_trm[4], dc395x_trm[5]); - ) - for (i = 0; i < 6; i++) { - if (dc395x_trm[i] < 0 || dc395x_trm[i] > 255) - dc395x_trm[i] = dc395x_def[i]; - } - /* Sanity checks */ - if (dc395x_trm[0] > 15) - dc395x_trm[0] = 7; - if (dc395x_trm[1] > 7) - dc395x_trm[1] = 4; - if (dc395x_trm[4] > 5) - dc395x_trm[4] = 4; - if (dc395x_trm[5] > 180) - dc395x_trm[5] = 180; + eeprom->NvramDelayTime = eeprom_index_to_delay_map[eeprom->NvramDelayTime]; } -/* Read the parameters from the command line */ -#if !defined(MODULE) -static int DC395x_trm_setup(char *str) +/** + * delay_to_eeprom_index - Take a delay in seconds and return the closest + * eeprom index which will delay for at least that amount of seconds. + */ +static int __init delay_to_eeprom_index(int delay) { - int i; - int im; - int ints[8]; - (void) get_options(str, ARRAY_SIZE(ints), ints); - im = ints[0]; - if (im > 6) { - printk(KERN_NOTICE DC395X_NAME ": ignore extra params!\n"); - im = 6; + u8 idx = 0; + while (idx < 7 && eeprom_index_to_delay_map[idx] < delay) { + idx++; } - for (i = 0; i < im; i++) - dc395x_trm[i] = ints[i + 1]; - - return 1; + return idx; } -__setup(DC395X_NAME "=", DC395x_trm_setup); - -#endif /* !MODULE */ /* Overrride BIOS values with the set ones */ static void __init DC395x_EEprom_Override(struct NvRamType *eeprom) @@ -698,21 +807,32 @@ u8 id; /* Adapter Settings */ - if (dc395x_trm[0] != -2) - eeprom->NvramScsiId = (u8) dc395x_trm[0]; /* Adapter ID */ - if (dc395x_trm[3] != -2) - eeprom->NvramChannelCfg = (u8) dc395x_trm[3]; - if (dc395x_trm[5] != -2) - eeprom->NvramDelayTime = DC395x_uninterpret_delay(dc395x_trm[5]); /* Reset delay */ - if (dc395x_trm[4] != -2) - eeprom->NvramMaxTag = (u8) dc395x_trm[4]; /* Tagged Cmds */ + if (cfg_data[CFG_ADAPTER_ID].value != CFG_PARAM_UNSET) { + eeprom->NvramScsiId = + (u8)cfg_data[CFG_ADAPTER_ID].value; + } + if (cfg_data[CFG_ADAPTER_MODE].value != CFG_PARAM_UNSET) { + eeprom->NvramChannelCfg = + (u8)cfg_data[CFG_ADAPTER_MODE].value; + } + if (cfg_data[CFG_RESET_DELAY].value != CFG_PARAM_UNSET) { + eeprom->NvramDelayTime = + delay_to_eeprom_index(cfg_data[CFG_RESET_DELAY].value); + } + if (cfg_data[CFG_TAGS].value != CFG_PARAM_UNSET) { + eeprom->NvramMaxTag = (u8)cfg_data[CFG_TAGS].value; + } /* Device Settings */ for (id = 0; id < DC395x_MAX_SCSI_ID; id++) { - if (dc395x_trm[2] != -2) - eeprom->NvramTarget[id].NvmTarCfg0 = (u8) dc395x_trm[2]; /* Cfg0 */ - if (dc395x_trm[1] != -2) - eeprom->NvramTarget[id].NvmTarPeriod = (u8) dc395x_trm[1]; /* Speed */ + if (cfg_data[CFG_DEV_MODE].value != CFG_PARAM_UNSET) { + eeprom->NvramTarget[id].NvmTarCfg0 = + (u8)cfg_data[CFG_DEV_MODE].value; + } + if (cfg_data[CFG_MAX_SPEED].value != CFG_PARAM_UNSET) { + eeprom->NvramTarget[id].NvmTarPeriod = + (u8)cfg_data[CFG_MAX_SPEED].value; + } } } @@ -763,10 +883,9 @@ static void DC395x_Query_append(Scsi_Cmnd * cmd, struct AdapterCtlBlk *pACB) { - DEBUG0(printk(DC395X_NAME ": Append cmd %li to Query\n", cmd->pid); - ) + dprintkdbg(DBG_0, "Append cmd %li to Query\n", cmd->pid); - cmd->host_scribble = NULL; + cmd->host_scribble = NULL; if (!pACB->QueryCnt) pACB->pQueryHead = cmd; @@ -787,9 +906,8 @@ pcmd = pACB->pQueryHead; if (!pcmd) return pcmd; - DEBUG0(printk(DC395X_NAME ": Get cmd %li from Query\n", pcmd->pid); - ) - pACB->pQueryHead = (void *) pcmd->host_scribble; + dprintkdbg(DBG_0, "Get cmd %li from Query\n", pcmd->pid); + pACB->pQueryHead = (void *) pcmd->host_scribble; pcmd->host_scribble = NULL; if (!pACB->pQueryHead) pACB->pQueryTail = NULL; @@ -807,7 +925,7 @@ /*DC395x_Free_integrity (pACB); */ pSRB = pACB->pFreeSRB; if (!pSRB) - printk(DC395X_NAME ": Out of Free SRBs :-(\n"); + dprintkl(KERN_ERR, "Out of Free SRBs :-(\n"); if (pSRB) { pACB->pFreeSRB = pSRB->pNextSRB; pSRB->pNextSRB = NULL; @@ -821,9 +939,8 @@ static __inline__ void DC395x_Free_insert(struct AdapterCtlBlk *pACB, struct ScsiReqBlk *pSRB) { - DEBUG0(printk(DC395X_NAME ": Free SRB %p\n", pSRB); - ) - pSRB->pNextSRB = pACB->pFreeSRB; + dprintkdbg(DBG_0, "Free SRB %p\n", pSRB); + pSRB->pNextSRB = pACB->pFreeSRB; pACB->pFreeSRB = pSRB; } @@ -832,11 +949,8 @@ static __inline__ void DC395x_Waiting_insert(struct DeviceCtlBlk *pDCB, struct ScsiReqBlk *pSRB) { - DEBUG0(printk - (DC395X_NAME ": Insert pSRB %p cmd %li to Waiting\n", pSRB, - pSRB->pcmd->pid); - ) - pSRB->pNextSRB = pDCB->pWaitingSRB; + dprintkdbg(DBG_0, "Insert pSRB %p cmd %li to Waiting\n", pSRB, pSRB->pcmd->pid); + pSRB->pNextSRB = pDCB->pWaitingSRB; if (!pDCB->pWaitingSRB) pDCB->pWaitLast = pSRB; pDCB->pWaitingSRB = pSRB; @@ -848,11 +962,8 @@ static __inline__ void DC395x_Waiting_append(struct DeviceCtlBlk *pDCB, struct ScsiReqBlk *pSRB) { - DEBUG0(printk - (DC395X_NAME ": Append pSRB %p cmd %li to Waiting\n", pSRB, - pSRB->pcmd->pid); - ) - if (pDCB->pWaitingSRB) + dprintkdbg(DBG_0, "Append pSRB %p cmd %li to Waiting\n", pSRB, pSRB->pcmd->pid); + if (pDCB->pWaitingSRB) pDCB->pWaitLast->pNextSRB = pSRB; else pDCB->pWaitingSRB = pSRB; @@ -868,10 +979,9 @@ static __inline__ void DC395x_Going_append(struct DeviceCtlBlk *pDCB, struct ScsiReqBlk *pSRB) { - DEBUG0(printk(DC395X_NAME ": Append SRB %p to Going\n", pSRB); - ) - /* Append to the list of Going commands */ - if (pDCB->pGoingSRB) + dprintkdbg(DBG_0, "Append SRB %p to Going\n", pSRB); + /* Append to the list of Going commands */ + if (pDCB->pGoingSRB) pDCB->pGoingLast->pNextSRB = pSRB; else pDCB->pGoingSRB = pSRB; @@ -908,8 +1018,7 @@ if (pre->pNextSRB != pSRB) pre = DC395x_find_SRBpre(pSRB, pre); if (!pre) { - printk(DC395X_NAME - ": Internal ERROR: SRB to rmv not found in Q!\n"); + dprintkl(KERN_ERR, "Internal ERROR: SRB to rmv not found in Q!\n"); return 0; } pre->pNextSRB = pSRB->pNextSRB; @@ -924,10 +1033,9 @@ struct ScsiReqBlk *hint) { struct ScsiReqBlk *pre = 0; - DEBUG0(printk(DC395X_NAME ": Remove SRB %p from Going\n", pSRB); - ) - if (!pSRB) - printk(DC395X_NAME ": Going_remove %p!\n", pSRB); + dprintkdbg(DBG_0, "Remove SRB %p from Going\n", pSRB); + if (!pSRB) + dprintkl(KERN_ERR, "Going_remove %p!\n", pSRB); if (pSRB == pDCB->pGoingSRB) pDCB->pGoingSRB = pSRB->pNextSRB; else if (hint && hint->pNextSRB == pSRB) @@ -946,10 +1054,9 @@ struct ScsiReqBlk *hint) { struct ScsiReqBlk *pre = 0; - DEBUG0(printk(DC395X_NAME ": Remove SRB %p from Waiting\n", pSRB); - ) - if (!pSRB) - printk(DC395X_NAME ": Waiting_remove %p!\n", pSRB); + dprintkdbg(DBG_0, "Remove SRB %p from Waiting\n", pSRB); + if (!pSRB) + dprintkl(KERN_ERR, "Waiting_remove %p!\n", pSRB); if (pSRB == pDCB->pWaitingSRB) pDCB->pWaitingSRB = pSRB->pNextSRB; else if (hint && hint->pNextSRB == pSRB) @@ -966,13 +1073,9 @@ static void DC395x_Going_to_Waiting(struct DeviceCtlBlk *pDCB, struct ScsiReqBlk *pSRB) { - DEBUG0(printk - (KERN_INFO DC395X_NAME - ": Going_to_Waiting (SRB %p) pid = %li\n", pSRB, - pSRB->pcmd->pid); - ) - /* Remove SRB from Going */ - DC395x_Going_remove(pDCB, pSRB, 0); + dprintkdbg(DBG_0, "Going_to_Waiting (SRB %p) pid = %li\n", pSRB, pSRB->pcmd->pid); + /* Remove SRB from Going */ + DC395x_Going_remove(pDCB, pSRB, 0); TRACEPRINTF("GtW *"); /* Insert on top of Waiting */ DC395x_Waiting_insert(pDCB, pSRB); @@ -985,11 +1088,8 @@ DC395x_Waiting_to_Going(struct DeviceCtlBlk *pDCB, struct ScsiReqBlk *pSRB) { /* Remove from waiting list */ - DEBUG0(printk - (DC395X_NAME ": Remove SRB %p from head of Waiting\n", - pSRB); - ) - DC395x_Waiting_remove(pDCB, pSRB, 0); + dprintkdbg(DBG_0, "Remove SRB %p from head of Waiting\n", pSRB); + DC395x_Waiting_remove(pDCB, pSRB, 0); TRACEPRINTF("WtG *"); DC395x_Going_append(pDCB, pSRB); } @@ -1059,9 +1159,7 @@ { unsigned long flags; struct AdapterCtlBlk *pACB = (struct AdapterCtlBlk *) ptr; -#ifdef DC395x_DEBUG_KG - printk(DC395X_NAME ": Debug: Waiting queue woken up by timer.\n"); -#endif + dprintkdbg(DBG_KG, "Debug: Waiting queue woken up by timer.\n"); DC395x_LOCK_IO(pACB->pScsiHost); DC395x_Waiting_process(pACB); DC395x_UNLOCK_IO(pACB->pScsiHost); @@ -1138,9 +1236,7 @@ u32 request_size; int dir; -#ifdef DC395x_DEBUG0 - printk(KERN_INFO DC395X_NAME ": DC395x_BuildSRB..............\n "); -#endif + dprintkdbg(DBG_0, "DC395x_BuildSRB..............\n"); /*memset (pSRB, 0, sizeof (struct ScsiReqBlk)); */ pSRB->pSRBDCB = pDCB; pSRB->pcmd = pcmd; @@ -1157,15 +1253,13 @@ pcmd->use_sg, dir); sgp = pSRB->SegmentX; request_size = pcmd->request_bufflen; -#ifdef DC395x_SGPARANOIA - printk(KERN_INFO DC395X_NAME - ": BuildSRB: Bufflen = %d, buffer = %p, use_sg = %d\n", + dprintkdbg(DBG_SGPARANOIA, + "BuildSRB: Bufflen = %d, buffer = %p, use_sg = %d\n", pcmd->request_bufflen, pcmd->request_buffer, pcmd->use_sg); - printk(KERN_INFO DC395X_NAME - ": Mapped %i Segments to %i\n", pcmd->use_sg, + dprintkdbg(DBG_SGPARANOIA, + "Mapped %i Segments to %i\n", pcmd->use_sg, pSRB->SRBSGCount); -#endif sl = (struct scatterlist *) pcmd->request_buffer; pSRB->virt_addr = page_address(sl->page); @@ -1175,18 +1269,16 @@ sgp[i].address = busaddr; sgp[i].length = seglen; len += seglen; -#ifdef DC395x_SGPARANOIA - printk(KERN_INFO DC395X_NAME - ": Setting up sgp %d, address = 0x%08x, length = %d, tot len = %d\n", + dprintkdbg(DBG_SGPARANOIA, + "Setting up sgp %d, address = 0x%08x, length = %d, tot len = %d\n", i, busaddr, seglen, len); -#endif } sgp += max - 1; /* Fixup for last buffer too big as it is allocated on even page boundaries */ if (len > request_size) { -#if defined(DC395x_DEBUG_KG) || defined (DC395x_SGPARANOIA) - printk(KERN_INFO DC395X_NAME - ": Fixup SG total length: %d->%d, last seg %d->%d\n", +#if debug_enabled(DBG_KG) || debug_enabled(DBG_SGPARANOIA) + dprintkdbg(DBG_KG|DBG_SGPARANOIA, + "Fixup SG total length: %d->%d, last seg %d->%d\n", len, request_size, sgp->length, sgp->length - (len - request_size)); #endif @@ -1205,13 +1297,11 @@ sizeof(struct SGentry) * DC395x_MAX_SG_LISTENTRY, PCI_DMA_TODEVICE); -#ifdef DC395x_SGPARANOIA - printk(DC395X_NAME - ": Map SG descriptor list %p (%05x) to %08x\n", + dprintkdbg(DBG_SGPARANOIA, + "Map SG descriptor list %p (%05x) to %08x\n", pSRB->SegmentX, sizeof(struct SGentry) * DC395x_MAX_SG_LISTENTRY, pSRB->SRBSGBusAddr); -#endif } else { if (pcmd->request_buffer && dir != PCI_DMA_NONE) { u32 len = pcmd->request_bufflen; /* Actual request size */ @@ -1226,23 +1316,19 @@ pSRB->SRBTotalXferLength = len; pSRB->virt_addr = pcmd->request_buffer; pSRB->SRBSGBusAddr = 0; -#ifdef DC395x_SGPARANOIA - printk(KERN_INFO DC395X_NAME - ": BuildSRB: len = %d, buffer = %p, use_sg = %d, map %08x\n", + dprintkdbg(DBG_SGPARANOIA, + "BuildSRB: len = %d, buffer = %p, use_sg = %d, map %08x\n", len, pcmd->request_buffer, pcmd->use_sg, pSRB->SegmentX[0].address); -#endif } else { pSRB->SRBSGCount = 0; pSRB->SRBTotalXferLength = 0; pSRB->SRBSGBusAddr = 0; pSRB->virt_addr = 0; -#ifdef DC395x_SGPARANOIA - printk(KERN_INFO DC395X_NAME - ": BuildSRB: buflen = %d, buffer = %p, use_sg = %d, NOMAP %08x\n", + dprintkdbg(DBG_SGPARANOIA, + "BuildSRB: buflen = %d, buffer = %p, use_sg = %d, NOMAP %08x\n", pcmd->bufflen, pcmd->request_buffer, pcmd->use_sg, pSRB->SegmentX[0].address); -#endif } } @@ -1255,16 +1341,15 @@ pSRB->SRBState = 0; pSRB->RetryCnt = 0; -#if DC395x_SGPARANOIA - if ((unsigned long) pSRB->debugtrace & (DEBUGTRACEBUFSZ - 1)) { - printk(DC395X_NAME - ": SRB %i (%p): debugtrace %p corrupt!\n", - (pSRB - - pDCB->pDCBACB->SRB_array) / +#if debug_enabled(DBG_TRACE|DBG_TRACEALL) && debug_enabled(DBG_SGPARANOIA) + if ((unsigned long)pSRB->debugtrace & (DEBUGTRACEBUFSZ - 1)) { + dprintkdbg(DBG_SGPARANOIA, + "SRB %i (%p): debugtrace %p corrupt!\n", + (pSRB - pDCB->pDCBACB->SRB_array) / sizeof(struct ScsiReqBlk), pSRB, pSRB->debugtrace); } #endif -#ifdef DC395x_TRACEDEBUG +#if debug_enabled(DBG_TRACE|DBG_TRACEALL) pSRB->debugpos = 0; pSRB->debugtrace = 0; #endif @@ -1303,8 +1388,7 @@ pcmd->device->lun); if (!pDCB) { DC395x_Free_insert(pACB, pSRB); - printk(KERN_ERR DC395X_NAME - ": Command in queue to non-existing device!\n"); + dprintkl(KERN_ERR, "Command in queue to non-existing device!\n"); pcmd->result = MK_RES(DRIVER_ERROR, DID_ERROR, 0, 0); /*DC395x_UNLOCK_ACB_NI; */ @@ -1343,55 +1427,55 @@ (struct AdapterCtlBlk *) cmd->device->host->hostdata; - DEBUG0( /* if(pACB->scan_devices) */ - printk(KERN_INFO DC395X_NAME - ": Queue Cmd=%02x,Tgt=%d,LUN=%d (pid=%li)\n", - cmd->cmnd[0], cmd->device->id, - cmd->device->lun, cmd->pid); - ) - - DEBUGRECURSION(if (in_driver++ > NORM_REC_LVL) - printk(DC395X_NAME - ": %i queue_command () recursion? (pid=%li)\n", - in_driver, cmd->pid);) + dprintkdbg(DBG_0, "Queue Cmd=%02x,Tgt=%d,LUN=%d (pid=%li)\n", + cmd->cmnd[0], cmd->device->id, + cmd->device->lun, cmd->pid); + +#if debug_enabled(DBG_RECURSION) + if (dbg_in_driver++ > NORM_REC_LVL) { + dprintkl(KERN_DEBUG, + "%i queue_command () recursion? (pid=%li)\n", + dbg_in_driver, cmd->pid); + } +#endif - /* Assume BAD_TARGET; will be cleared later */ - cmd->result = DID_BAD_TARGET << 16; + /* Assume BAD_TARGET; will be cleared later */ + cmd->result = DID_BAD_TARGET << 16; if ((cmd->device->id >= pACB->pScsiHost->max_id) || (cmd->device->lun >= pACB->pScsiHost->max_lun) || (cmd->device->lun >31)) { - /* printk (KERN_INFO DC395X_NAME "Ignore target %d lun %d\n", + /* dprintkl(KERN_INFO, "Ignore target %d lun %d\n", cmd->device->id, cmd->device->lun); */ - DEBUGRECURSION(in_driver--; - ) - /*return 1; */ - done(cmd); +#if debug_enabled(DBG_RECURSION) + dbg_in_driver-- +#endif + /*return 1; */ + done(cmd); return 0; } if (!(pACB->DCBmap[cmd->device->id] & (1 << cmd->device->lun))) { - printk(KERN_INFO DC395X_NAME - ": Ignore target %02x lun %02x\n", cmd->device->id, + dprintkl(KERN_INFO, "Ignore target %02x lun %02x\n", cmd->device->id, cmd->device->lun); /*return 1; */ - DEBUGRECURSION(in_driver--; - ) - done(cmd); +#if debug_enabled(DBG_RECURSION) + dbg_in_driver-- +#endif + done(cmd); return 0; } else { pDCB = DC395x_findDCB(pACB, cmd->device->id, cmd->device->lun); if (!pDCB) { /* should never happen */ - printk(KERN_ERR DC395X_NAME - ": no DCB failed, target %02x lun %02x\n", + dprintkl(KERN_ERR, "no DCB failed, target %02x lun %02x\n", cmd->device->id, cmd->device->lun); - printk(DC395X_NAME - ": No DCB in queuecommand (2)!\n"); - DEBUGRECURSION(in_driver--; - ) - return 1; + dprintkl(KERN_ERR, "No DCB in queuecommand (2)!\n"); +#if debug_enabled(DBG_RECURSION) + dbg_in_driver-- +#endif + return 1; } } @@ -1403,52 +1487,49 @@ if (pACB->QueryCnt) { /* Unsent commands ? */ - DEBUG0(printk(DC395X_NAME ": QueryCnt != 0\n"); - ) - DC395x_Query_append(cmd, pACB); + dprintkdbg(DBG_0, "QueryCnt != 0\n"); + DC395x_Query_append(cmd, pACB); DC395x_Waiting_process(pACB); } else { if (pDCB->pWaitingSRB) { pSRB = DC395x_Free_get(pACB); - DEBUG0(if (!pSRB) - printk(DC395X_NAME - ": No free SRB but Waiting\n"); - else - printk(DC395X_NAME - ": Free SRB w/ Waiting\n");) - if (!pSRB) { - DC395x_Query_append(cmd, pACB); - } else { - DC395x_BuildSRB(cmd, pDCB, pSRB); - DC395x_Waiting_append(pDCB, pSRB); - } + if (debug_enabled(DBG_0)) { + if (!pSRB) + dprintkdbg(DBG_0, "No free SRB but Waiting\n"); + else + dprintkdbg(DBG_0, "Free SRB w/ Waiting\n"); + } + if (!pSRB) { + DC395x_Query_append(cmd, pACB); + } else { + DC395x_BuildSRB(cmd, pDCB, pSRB); + DC395x_Waiting_append(pDCB, pSRB); + } DC395x_Waiting_process(pACB); } else { pSRB = DC395x_Free_get(pACB); - DEBUG0(if (!pSRB) - printk(DC395X_NAME - ": No free SRB w/o Waiting\n"); - else - printk(DC395X_NAME - ": Free SRB w/o Waiting\n");) - if (!pSRB) { - DC395x_Query_append(cmd, pACB); - DC395x_Waiting_process(pACB); - } else { - DC395x_BuildSRB(cmd, pDCB, pSRB); - DC395x_SendSRB(pACB, pSRB); - } + if (debug_enabled(DBG_0)) { + if (!pSRB) + dprintkdbg(DBG_0, "No free SRB w/o Waiting\n"); + else + dprintkdbg(DBG_0, "Free SRB w/o Waiting\n"); + } + if (!pSRB) { + DC395x_Query_append(cmd, pACB); + DC395x_Waiting_process(pACB); + } else { + DC395x_BuildSRB(cmd, pDCB, pSRB); + DC395x_SendSRB(pACB, pSRB); + } } } /*DC395x_ACB_LOCK(pACB,acb_flags); */ - DEBUG1(printk - (KERN_DEBUG " ... command (pid %li) queued successfully.\n", - cmd->pid); - ) - DEBUGRECURSION(in_driver--; - ) - return 0; + dprintkdbg(DBG_1, "... command (pid %li) queued successfully.\n", cmd->pid); +#if debug_enabled(DBG_RECURSION) + dbg_in_driver-- +#endif + return 0; } @@ -1546,10 +1627,7 @@ struct AdapterCtlBlk *pACB; int size = capacity; -#ifdef DC395x_DEBUG0 - printk(KERN_INFO DC395X_NAME - ":DC395x_bios_param..............\n "); -#endif + dprintkdbg(DBG_0, "DC395x_bios_param..............\n"); pACB = (struct AdapterCtlBlk *) sdev->host->hostdata; heads = 64; sectors = 32; @@ -1586,12 +1664,10 @@ pSRB = pDCB->pActiveSRB; if (pSRB) { if (!(pSRB->pcmd)) - printk(DC395X_NAME - ": dump: SRB %p: cmd %p OOOPS!\n", pSRB, + dprintkl(KERN_INFO, "dump: SRB %p: cmd %p OOOPS!\n", pSRB, pSRB->pcmd); else - printk(DC395X_NAME - ": dump: SRB %p: cmd %p pid %li: %02x (%02i-%i)\n", + dprintkl(KERN_INFO, "dump: SRB %p: cmd %p pid %li: %02x (%02i-%i)\n", pSRB, pSRB->pcmd, pSRB->pcmd->pid, pSRB->pcmd->cmnd[0], pSRB->pcmd->device->id, pSRB->pcmd->device->lun); @@ -1604,7 +1680,7 @@ (pACB->pActiveDCB) ? "" : "not"); TRACEOUT(" %s\n", pSRB->debugtrace); } - printk(DC395X_NAME ": dump: SCSI block\n"); + dprintkl(KERN_INFO, "dump: SCSI block\n"); printk (" Status %04x FIFOCnt %02x Signals %02x IRQStat %02x\n", DC395x_read16(TRM_S1040_SCSI_STATUS), @@ -1624,7 +1700,7 @@ DC395x_read8(TRM_S1040_SCSI_CONFIG2), DC395x_read8(TRM_S1040_SCSI_COMMAND), DC395x_read8(TRM_S1040_SCSI_TIMEOUT)); - printk(DC395X_NAME ": dump: DMA block\n"); + dprintkl(KERN_INFO, "dump: DMA block\n"); printk (" Cmd %04x FIFOCnt %02x FStat %02x IRQStat %02x IRQEn %02x Cfg %04x\n", DC395x_read16(TRM_S1040_DMA_COMMAND), @@ -1638,12 +1714,11 @@ DC395x_read32(TRM_S1040_DMA_CXCNT), DC395x_read32(TRM_S1040_DMA_XHIGHADDR), DC395x_read32(TRM_S1040_DMA_XLOWADDR)); - printk(DC395X_NAME - ": dump: Misc: GCtrl %02x GStat %02x GTmr %02x\n", + dprintkl(KERN_INFO, "dump: Misc: GCtrl %02x GStat %02x GTmr %02x\n", DC395x_read8(TRM_S1040_GEN_CONTROL), DC395x_read8(TRM_S1040_GEN_STATUS), DC395x_read8(TRM_S1040_GEN_TIMER)); - printk(DC395X_NAME ": dump: PCI Status %04x\n", pstat); + dprintkl(KERN_INFO, "dump: PCI Status %04x\n", pstat); } @@ -1651,18 +1726,20 @@ static inline void DC395x_clrfifo(struct AdapterCtlBlk *pACB, char *txt) { -#ifdef DC395x_DEBUGFIFO +#if debug_enabled(DBG_FIFO) u8 lines = DC395x_read8(TRM_S1040_SCSI_SIGNAL); u8 fifocnt = DC395x_read8(TRM_S1040_SCSI_FIFOCNT); if (!(fifocnt & 0x40)) - printk(DC395X_NAME - ": Clr FIFO (%i bytes) on phase %02x in %s\n", - fifocnt & 0x3f, lines, txt); + dprintkdbg(DBG_FIFO, + "Clr FIFO (%i bytes) on phase %02x in %s\n", + fifocnt & 0x3f, lines, txt); #endif +#if debug_enabled(DBG_TRACE) if (pACB->pActiveDCB && pACB->pActiveDCB->pActiveSRB) { struct ScsiReqBlk *pSRB = pACB->pActiveDCB->pActiveSRB; TRACEPRINTF("#*"); } +#endif DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_CLRFIFO); } @@ -1682,10 +1759,7 @@ u8 PeriodIndex; u16 index; -#ifdef DC395x_DEBUG0 - printk(KERN_INFO DC395X_NAME - ": DC395x_ResetDevParam..............\n "); -#endif + dprintkdbg(DBG_0, "DC395x_ResetDevParam..............\n"); pDCB = pACB->pLinkDCB; if (pDCB == NULL) return; @@ -1728,7 +1802,7 @@ struct AdapterCtlBlk *pACB; /*u32 acb_flags=0; */ - printk(KERN_INFO DC395X_NAME ": reset requested!\n"); + dprintkl(KERN_INFO, "reset requested!\n"); pACB = (struct AdapterCtlBlk *) cmd->device->host->hostdata; /* mid level guarantees no recursion */ /*DC395x_ACB_LOCK(pACB,acb_flags); */ @@ -1797,7 +1871,7 @@ int cnt = pACB->QueryCnt; Scsi_Cmnd *pcmd; Scsi_Cmnd *last = 0; - printk(DC395X_NAME ": DC395x_eh_abort: cmd %p (pid %li, %02i-%i) ", + dprintkl(KERN_INFO, "eh abort: cmd %p (pid %li, %02i-%i) ", cmd, cmd->pid, cmd->device->id, cmd->device->lun); for (pcmd = pACB->pQueryHead; cnt--; last = pcmd, pcmd = (Scsi_Cmnd *) pcmd->host_scribble) { @@ -1821,7 +1895,7 @@ } pDCB = DC395x_findDCB(pACB, cmd->device->id, cmd->device->lun); if (!pDCB) { - printk("no DCB !\n"); + printk("no DCB!\n"); return FAILED; } @@ -1863,8 +1937,8 @@ { u8 *ptr = pSRB->MsgOutBuf + pSRB->MsgCnt; if (pSRB->MsgCnt > 1) { - printk(DC395X_NAME - ": Build_SDTR: MsgOutBuf BUSY (%i: %02x %02x)\n", + dprintkl(KERN_INFO, + "Build_SDTR: MsgOutBuf BUSY (%i: %02x %02x)\n", pSRB->MsgCnt, pSRB->MsgOutBuf[0], pSRB->MsgOutBuf[1]); return; @@ -1897,8 +1971,8 @@ ? 1 : 0; u8 *ptr = pSRB->MsgOutBuf + pSRB->MsgCnt; if (pSRB->MsgCnt > 1) { - printk(DC395X_NAME - ": Build_WDTR: MsgOutBuf BUSY (%i: %02x %02x)\n", + dprintkl(KERN_INFO, + "Build_WDTR: MsgOutBuf BUSY (%i: %02x %02x)\n", pSRB->MsgCnt, pSRB->MsgOutBuf[0], pSRB->MsgOutBuf[1]); return; @@ -1940,9 +2014,9 @@ unsigned long flags; struct AdapterCtlBlk *pACB = (struct AdapterCtlBlk *) ptr; struct ScsiReqBlk *pSRB; - printk(DC395X_NAME ": Debug: Chip forgot to produce SelTO IRQ!\n"); + dprintkl(KERN_DEBUG, "Chip forgot to produce SelTO IRQ!\n"); if (!pACB->pActiveDCB || !pACB->pActiveDCB->pActiveSRB) { - printk(DC395X_NAME ": ... but no cmd pending? Oops!\n"); + dprintkl(KERN_DEBUG, "... but no cmd pending? Oops!\n"); return; } DC395x_LOCK_IO(pACB->pScsiHost); @@ -1967,10 +2041,7 @@ u8 s_stat, scsicommand, i, identify_message; u8 *ptr; -#ifdef DC395x_DEBUG0 - printk(KERN_INFO DC395X_NAME - ": DC395x_StartSCSI..............\n "); -#endif + dprintkdbg(DBG_0, "DC395x_StartSCSI..............\n"); pSRB->TagNumber = TAG_NONE; /* pACB->TagMaxNum: had error read in eeprom */ s_stat = DC395x_read8(TRM_S1040_SCSI_SIGNAL); @@ -1979,12 +2050,10 @@ TRACEPRINTF("Start %02x *", s_stat); #if 1 if (s_stat & 0x20 /* s_stat2 & 0x02000 */ ) { -#ifdef DC395x_DEBUG_KG - printk(DC395X_NAME - ": Debug: StartSCSI: pid %li(%02i-%i): BUSY %02x %04x\n", + dprintkdbg(DBG_KG, + "StartSCSI: pid %li(%02i-%i): BUSY %02x %04x\n", pSRB->pcmd->pid, pDCB->TargetID, pDCB->TargetLUN, s_stat, s_stat2); -#endif /* * Try anyway? * @@ -2002,11 +2071,9 @@ } #endif if (pACB->pActiveDCB) { - printk(DC395X_NAME - ": We try to start a SCSI command (%li)!\n", + dprintkl(KERN_DEBUG, "We try to start a SCSI command (%li)!\n", pSRB->pcmd->pid); - printk(DC395X_NAME - ": While another one (%li) is active!!\n", + dprintkl(KERN_DEBUG, "While another one (%li) is active!!\n", (pACB->pActiveDCB->pActiveSRB ? pACB->pActiveDCB-> pActiveSRB->pcmd->pid : 0)); TRACEOUT(" %s\n", pSRB->debugtrace); @@ -2016,21 +2083,17 @@ return 1; } if (DC395x_read16(TRM_S1040_SCSI_STATUS) & SCSIINTERRUPT) { -#ifdef DC395x_DEBUG_KG - printk(DC395X_NAME - ": Debug: StartSCSI failed (busy) for pid %li(%02i-%i)\n", + dprintkdbg(DBG_KG, + "StartSCSI failed (busy) for pid %li(%02i-%i)\n", pSRB->pcmd->pid, pDCB->TargetID, pDCB->TargetLUN); -#endif TRACEPRINTF("°*"); return 1; } /* Allow starting of SCSI commands half a second before we allow the mid-level * to queue them again after a reset */ if (time_before(jiffies, pACB->pScsiHost->last_reset - HZ / 2)) { -#ifdef DC395x_DEBUG_KG - printk(DC395X_NAME - ": We were just reset and don't accept commands yet!\n"); -#endif + dprintkdbg(DBG_KG, + "We were just reset and don't accept commands yet!\n"); return 1; } @@ -2098,8 +2161,8 @@ tag_number++; } if (tag_number >= pDCB->MaxCommand) { - printk(KERN_WARNING DC395X_NAME - ": Start_SCSI: Out of tags for pid %li (%i-%i)\n", + dprintkl(KERN_WARNING, + "Start_SCSI: Out of tags for pid %li (%i-%i)\n", pSRB->pcmd->pid, pSRB->pcmd->device->id, pSRB->pcmd->device->lun); pSRB->SRBState = SRB_READY; @@ -2124,13 +2187,11 @@ /* * Send CDB ..command block ......... */ -#ifdef DC395x_DEBUG_KG - printk(KERN_INFO DC395X_NAME - ": StartSCSI (pid %li) %02x (%i-%i): Tag %i\n", + dprintkdbg(DBG_KG, + "StartSCSI (pid %li) %02x (%i-%i): Tag %i\n", pSRB->pcmd->pid, pSRB->pcmd->cmnd[0], pSRB->pcmd->device->id, pSRB->pcmd->device->lun, pSRB->TagNumber); -#endif if (pSRB->SRBFlag & AUTO_REQSENSE) { DC395x_write8(TRM_S1040_SCSI_FIFO, REQUEST_SENSE); DC395x_write8(TRM_S1040_SCSI_FIFO, (pDCB->TargetLUN << 5)); @@ -2153,14 +2214,11 @@ * we caught an interrupt (must be reset or reselection ... ) * : Let's process it first! */ - DEBUG0(printk - (DC395X_NAME - ": Debug: StartSCSI failed (busy) for pid %li(%02i-%i)!\n", + dprintkdbg(DBG_0, "Debug: StartSCSI failed (busy) for pid %li(%02i-%i)!\n", pSRB->pcmd->pid, pDCB->TargetID, pDCB->TargetLUN); - ) - /*DC395x_clrfifo (pACB, "Start2"); */ - /*DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_HWRESELECT | DO_DATALATCH); */ - pSRB->SRBState = SRB_READY; + /*DC395x_clrfifo (pACB, "Start2"); */ + /*DC395x_write16 (TRM_S1040_SCSI_CONTROL, DO_HWRESELECT | DO_DATALATCH); */ + pSRB->SRBState = SRB_READY; DC395x_freetag(pDCB, pSRB); pSRB->MsgCnt = 0; return_code = 1; @@ -2216,22 +2274,22 @@ /* This acknowledges the IRQ */ scsi_intstatus = DC395x_read8(TRM_S1040_SCSI_INTSTATUS); if ((scsi_status & 0x2007) == 0x2002) - printk(DC395X_NAME ": COP after COP completed? %04x\n", + dprintkl(KERN_DEBUG, "COP after COP completed? %04x\n", scsi_status); -#if 1 /*def DC395x_DEBUG0 */ +#if 1 /*def DBG_0 */ if (DC395x_monitor_next_IRQ) { - printk(KERN_INFO DC395X_NAME - ": status=%04x intstatus=%02x\n", scsi_status, + dprintkl(KERN_INFO, + "status=%04x intstatus=%02x\n", scsi_status, scsi_intstatus); DC395x_monitor_next_IRQ--; } #endif /*DC395x_ACB_LOCK(pACB,acb_flags); */ -#ifdef DC395x_DEBUG_KG - if (scsi_intstatus & INT_SELTIMEOUT) - printk(KERN_INFO DC395X_NAME ": Sel Timeout IRQ\n"); -#endif - /*printk (DC395X_NAME ": DC395x_IRQ: intstatus = %02x ", scsi_intstatus); */ + if (debug_enabled(DBG_KG)) { + if (scsi_intstatus & INT_SELTIMEOUT) + dprintkdbg(DBG_KG, "Sel Timeout IRQ\n"); + } + /*dprintkl(KERN_DEBUG, "DC395x_IRQ: intstatus = %02x ", scsi_intstatus); */ if (timer_pending(&pACB->SelTO_Timer)) del_timer(&pACB->SelTO_Timer); @@ -2245,8 +2303,7 @@ goto out_unlock; } if (scsi_intstatus & INT_SELECT) { - printk(KERN_INFO DC395X_NAME - ": Host does not support target mode!\n"); + dprintkl(KERN_INFO, "Host does not support target mode!\n"); goto out_unlock; } if (scsi_intstatus & INT_SCSIRESET) { @@ -2256,16 +2313,14 @@ if (scsi_intstatus & (INT_BUSSERVICE | INT_CMDDONE)) { pDCB = pACB->pActiveDCB; if (!pDCB) { - printk(DC395X_NAME - ": Oops: BusService (%04x %02x) w/o ActiveDCB!\n", + dprintkl(KERN_DEBUG, + "Oops: BusService (%04x %02x) w/o ActiveDCB!\n", scsi_status, scsi_intstatus); goto out_unlock; } pSRB = pDCB->pActiveSRB; if (pDCB->DCBFlag & ABORT_DEV_) { -#ifdef DC395x_DEBUG0 - printk(KERN_INFO "MsgOut Abort Device..... "); -#endif + dprintkdbg(DBG_0, "MsgOut Abort Device.....\n"); DC395x_EnableMsgOut_Abort(pACB, pSRB); } /* @@ -2320,7 +2375,6 @@ return; } -/*inline */ irqreturn_t DC395x_Interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct AdapterCtlBlk *pACB = DC395x_pACB_start; @@ -2328,12 +2382,12 @@ u8 dma_status; irqreturn_t handled = IRQ_NONE; -#ifdef DC395x_DEBUG0 - printk(KERN_INFO DC395X_NAME ": DC395x_Interrupt..............\n "); + dprintkdbg(DBG_0, "DC395x_Interrupt..............\n"); +#if debug_enabled(DBG_RECURSION) + if (dbg_in_driver++ > NORM_REC_LVL) { + dprintkl(KERN_DEBUG, "%i interrupt recursion?\n", dbg_in_driver); + } #endif - DEBUGRECURSION(if (in_driver++ > NORM_REC_LVL) - printk(DC395X_NAME ": %i interrupt recursion?\n", - in_driver);) /* * Find which card generated the interrupt. Note that it may have @@ -2362,10 +2416,10 @@ } else if (dma_status & 0x20) { /* Error from the DMA engine */ - printk(DC395X_NAME ": Interrupt from DMA engine: %02x!\n", + dprintkl(KERN_INFO, "Interrupt from DMA engine: %02x!\n", dma_status); #if 0 - printk(DC395X_NAME ": This means DMA error! Try to handle ...\n"); + dprintkl(KERN_INFO, "This means DMA error! Try to handle ...\n"); if (pACB->pActiveDCB) { pACB->pActiveDCB-> DCBFlag |= ABORT_DEV_; if (pACB->pActiveDCB->pActiveSRB) @@ -2373,14 +2427,16 @@ } DC395x_write8(TRM_S1040_DMA_CONTROL, ABORTXFER | CLRXFIFO); #else - printk(DC395X_NAME ": Ignoring DMA error (probably a bad thing) ...\n"); + dprintkl(KERN_INFO, "Ignoring DMA error (probably a bad thing) ...\n"); pACB = (struct AdapterCtlBlk *)NULL; #endif handled = IRQ_HANDLED; } } - DEBUGRECURSION(in_driver--;) +#if debug_enabled(DBG_RECURSION) + dbg_in_driver-- +#endif return handled; } @@ -2397,9 +2453,7 @@ DC395x_MsgOutPhase0(struct AdapterCtlBlk *pACB, struct ScsiReqBlk *pSRB, u16 * pscsi_status) { -#ifdef DC395x_DEBUG0 - printk(KERN_INFO DC395X_NAME ": DC395x_MsgOutPhase0..... "); -#endif + dprintkdbg(DBG_0, "DC395x_MsgOutPhase0.....\n"); if (pSRB->SRBState & (SRB_UNEXPECT_RESEL + SRB_ABORT_SENT)) { *pscsi_status = PH_BUS_FREE; /*.. initial phase */ } @@ -2425,24 +2479,18 @@ u8 *ptr; struct DeviceCtlBlk *pDCB; -#ifdef DC395x_DEBUG0 - printk(KERN_INFO DC395X_NAME - ": DC395x_MsgOutPhase1..............\n "); -#endif + dprintkdbg(DBG_0, "DC395x_MsgOutPhase1..............\n"); TRACEPRINTF("MOP1*"); pDCB = pACB->pActiveDCB; DC395x_clrfifo(pACB, "MOP1"); if (!(pSRB->SRBState & SRB_MSGOUT)) { pSRB->SRBState |= SRB_MSGOUT; - printk(DC395X_NAME ": Debug: pid %li: MsgOut Phase unexpected.\n", pSRB->pcmd->pid); /* So what ? */ + dprintkl(KERN_DEBUG, "Debug: pid %li: MsgOut Phase unexpected.\n", pSRB->pcmd->pid); /* So what ? */ } if (!pSRB->MsgCnt) { - DEBUG0(printk - (DC395X_NAME - ": Debug: pid %li: NOP Msg (no output message there).\n", + dprintkdbg(DBG_0, "Debug: pid %li: NOP Msg (no output message there).\n", pSRB->pcmd->pid); - ) - DC395x_write8(TRM_S1040_SCSI_FIFO, MSG_NOP); + DC395x_write8(TRM_S1040_SCSI_FIFO, MSG_NOP); DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ DC395x_write8(TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT); TRACEPRINTF("\\*"); @@ -2451,15 +2499,15 @@ } ptr = (u8 *) pSRB->MsgOutBuf; TRACEPRINTF("(*"); - /*printk (DC395X_NAME ": Send msg: "); DC395x_printMsg (ptr, pSRB->MsgCnt); */ - /*printk (DC395X_NAME ": MsgOut: "); */ + /*dprintkl(KERN_DEBUG, "Send msg: "); DC395x_printMsg (ptr, pSRB->MsgCnt); */ + /*dprintkl(KERN_DEBUG, "MsgOut: "); */ for (i = 0; i < pSRB->MsgCnt; i++) { TRACEPRINTF("%02x *", *ptr); DC395x_write8(TRM_S1040_SCSI_FIFO, *ptr++); } TRACEPRINTF(")*"); pSRB->MsgCnt = 0; - /*printk ("\n"); */ + /*printk("\n"); */ if ( /*(pDCB->DCBFlag & ABORT_DEV_) && */ (pSRB->MsgOutBuf[0] == MSG_ABORT)) pSRB->SRBState = SRB_ABORT_SENT; @@ -2509,10 +2557,7 @@ u8 *ptr; u16 i; -#ifdef DC395x_DEBUG0 - printk(KERN_INFO DC395X_NAME - ": DC395x_CommandPhase1..............\n "); -#endif + dprintkdbg(DBG_0, "DC395x_CommandPhase1..............\n"); TRACEPRINTF("COP1*"); DC395x_clrfifo(pACB, "COP1"); DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_CLRATN); @@ -2543,24 +2588,20 @@ /* Do sanity checks for S/G list */ -#ifdef DC395x_SGPARANOIA static inline void DC395x_check_SG(struct ScsiReqBlk *pSRB) { - unsigned Length = 0; - unsigned Idx = pSRB->SRBSGIndex; - struct SGentry *psge = pSRB->SegmentX + Idx; - for (; Idx < pSRB->SRBSGCount; psge++, Idx++) - Length += psge->length; - if (Length != pSRB->SRBTotalXferLength) - printk(DC395X_NAME - ": Inconsistent SRB S/G lengths (Tot=%i, Count=%i) !!\n", - pSRB->SRBTotalXferLength, Length); + if (debug_enabled(DBG_SGPARANOIA)) { + unsigned Length = 0; + unsigned Idx = pSRB->SRBSGIndex; + struct SGentry *psge = pSRB->SegmentX + Idx; + for (; Idx < pSRB->SRBSGCount; psge++, Idx++) + Length += psge->length; + if (Length != pSRB->SRBTotalXferLength) + dprintkdbg(DBG_SGPARANOIA, + "Inconsistent SRB S/G lengths (Tot=%i, Count=%i) !!\n", + pSRB->SRBTotalXferLength, Length); + } } -#else -static inline void DC395x_check_SG(struct ScsiReqBlk *pSRB) -{ -} -#endif /* @@ -2576,10 +2617,8 @@ struct scatterlist *sg; int segment = pcmd->use_sg; -#ifdef DC395x_DEBUG_KG - printk(DC395X_NAME ": Update SG: Total %i, Left %i\n", + dprintkdbg(DBG_KG, "Update SG: Total %i, Left %i\n", pSRB->SRBTotalXferLength, Left); -#endif DC395x_check_SG(pSRB); psge = pSRB->SegmentX + pSRB->SRBSGIndex; /* data that has already been transferred */ @@ -2612,28 +2651,28 @@ DC395x_check_SG(pSRB); } /* We need the corresponding virtual address sg_to_virt */ - /*printk (DC395X_NAME ": sg_to_virt: bus %08x -> virt ", psge->address); */ + /*dprintkl(KERN_DEBUG, "sg_to_virt: bus %08x -> virt ", psge->address); */ if (!segment) { pSRB->virt_addr += Xferred; - /*printk ("%p\n", pSRB->virt_addr); */ + /*printk("%p\n", pSRB->virt_addr); */ return; } /* We have to walk the scatterlist to find it */ sg = (struct scatterlist *) pcmd->request_buffer; while (segment--) { - /*printk ("(%08x)%p ", BUS_ADDR(*sg), PAGE_ADDRESS(sg)); */ + /*printk("(%08x)%p ", BUS_ADDR(*sg), PAGE_ADDRESS(sg)); */ unsigned long mask = ~((unsigned long) sg->length - 1) & PAGE_MASK; if ((BUS_ADDR(*sg) & mask) == (psge->address & mask)) { pSRB->virt_addr = (PAGE_ADDRESS(sg) + psge->address - (psge->address & PAGE_MASK)); - /*printk ("%p\n", pSRB->virt_addr); */ + /*printk("%p\n", pSRB->virt_addr); */ return; } ++sg; } - printk(DC395X_NAME ": sg_to_virt failed!\n"); + dprintkl(KERN_ERR, "sg_to_virt failed!\n"); pSRB->virt_addr = 0; } @@ -2692,9 +2731,7 @@ u32 dLeftCounter = 0; struct DeviceCtlBlk *pDCB = pSRB->pSRBDCB; -#ifdef DC395x_DEBUG0 - printk(KERN_INFO DC395X_NAME ": DC395x_DataOutPhase0.....\n "); -#endif + dprintkdbg(DBG_0, "DC395x_DataOutPhase0.....\n"); TRACEPRINTF("DOP0*"); pDCB = pSRB->pSRBDCB; scsi_status = *pscsi_status; @@ -2711,16 +2748,12 @@ * KG: Stop DMA engine pushing more data into the SCSI FIFO * If we need more data, the DMA SG list will be freshly set up, anyway */ -#ifdef DC395x_DEBUGPIO - printk(DC395X_NAME - ": DOP0: DMA_FCNT: %02x, DMA_FSTAT: %02x, SCSI_FCNT: %02x, CTR %06x, stat %04x, Tot: %06x\n", + dprintkdbg(DBG_PIO, "DOP0: DMA_FCNT: %02x, DMA_FSTAT: %02x, SCSI_FCNT: %02x, CTR %06x, stat %04x, Tot: %06x\n", DC395x_read8(TRM_S1040_DMA_FIFOCNT), DC395x_read8(TRM_S1040_DMA_FIFOSTAT), DC395x_read8(TRM_S1040_SCSI_FIFOCNT), DC395x_read32(TRM_S1040_SCSI_COUNTER), scsi_status, pSRB->SRBTotalXferLength); - /*DC395x_dumpinfo(pACB, pDCB, pSRB); */ -#endif DC395x_write8(TRM_S1040_DMA_CONTROL, STOPDMAXFER | CLRXFIFO); if (!(pSRB->SRBState & SRB_XFERPAD)) { @@ -2744,23 +2777,22 @@ if (pDCB->SyncPeriod & WIDE_SYNC) dLeftCounter <<= 1; -#ifdef DC395x_DEBUG_KG - printk(DC395X_NAME - ": Debug: SCSI FIFO contains %i %s in DOP0\n", + dprintkdbg(DBG_KG, + "Debug: SCSI FIFO contains %i %s in DOP0\n", DC395x_read8(TRM_S1040_SCSI_FIFOCNT), (pDCB-> SyncPeriod & WIDE_SYNC) ? "words" : "bytes"); - printk(DC395X_NAME - ": SCSI FIFOCNT %02x, SCSI CTR %08x\n", + dprintkdbg(DBG_KG, + "SCSI FIFOCNT %02x, SCSI CTR %08x\n", DC395x_read8(TRM_S1040_SCSI_FIFOCNT), DC395x_read32(TRM_S1040_SCSI_COUNTER)); - printk(DC395X_NAME - ": DMA FIFOCNT %04x, FIFOSTAT %02x, DMA CTR %08x\n", + dprintkdbg(DBG_KG, + "DMA FIFOCNT %04x, FIFOSTAT %02x, DMA CTR %08x\n", DC395x_read8(TRM_S1040_DMA_FIFOCNT), DC395x_read8(TRM_S1040_DMA_FIFOSTAT), DC395x_read32(TRM_S1040_DMA_CXCNT)); -#endif + /* * if WIDE scsi SCSI FIFOCNT unit is word !!! * so need to *= 2 @@ -2786,8 +2818,7 @@ if (dLeftCounter == 1 && pDCB->SyncPeriod & WIDE_SYNC && pSRB->pcmd->request_bufflen % 2) { dLeftCounter = 0; - printk(DC395X_NAME - ": DOP0: Discard 1 byte. (%02x)\n", + dprintkl(KERN_INFO, "DOP0: Discard 1 byte. (%02x)\n", scsi_status); } /* @@ -2808,8 +2839,8 @@ * { * TempDMAstatus = DC395x_read8(TRM_S1040_DMA_STATUS); * } while( !(TempDMAstatus & DMAXFERCOMP) && --ctr); - * if (ctr < 6000000-1) printk (DC395X_NAME ": DMA should be complete ... in DOP1\n"); - * if (!ctr) printk (KERN_ERR DC395X_NAME ": Deadlock in DataOutPhase0 !!\n"); + * if (ctr < 6000000-1) dprintkl(KERN_DEBUG, "DMA should be complete ... in DOP1\n"); + * if (!ctr) dprintkl(KERN_ERR, "Deadlock in DataOutPhase0 !!\n"); */ pSRB->SRBTotalXferLength = 0; } else { /* Update SG list */ @@ -2829,9 +2860,8 @@ || ((oldXferred & ~PAGE_MASK) == (PAGE_SIZE - diff)) ) { - printk(DC395X_NAME - ": Work around chip bug (%i)?\n", - diff); + dprintkl(KERN_INFO, + "Work around chip bug (%i)?\n", diff); dLeftCounter = pSRB->SRBTotalXferLength - diff; DC395x_update_SGlist(pSRB, dLeftCounter); @@ -2844,16 +2874,16 @@ } #if 0 if (!(DC395x_read8(TRM_S1040_SCSI_FIFOCNT) & 0x40)) - printk(DC395X_NAME - ": DOP0(%li): %i bytes in SCSI FIFO! (Clear!)\n", - pSRB->pcmd->pid, - DC395x_read8(TRM_S1040_SCSI_FIFOCNT) & 0x1f); + dprintkl(KERN_DEBUG, + "DOP0(%li): %i bytes in SCSI FIFO! (Clear!)\n", + pSRB->pcmd->pid, + DC395x_read8(TRM_S1040_SCSI_FIFOCNT) & 0x1f); #endif /*DC395x_clrfifo (pACB, "DOP0"); */ /*DC395x_write8 (TRM_S1040_DMA_CONTROL, CLRXFIFO | ABORTXFER); */ #if 1 if ((*pscsi_status & PHASEMASK) != PH_DATA_OUT) { - /*printk (DC395X_NAME ": Debug: Clean up after Data Out ...\n"); */ + /*dprintkl(KERN_DEBUG, "Debug: Clean up after Data Out ...\n"); */ DC395x_cleanup_after_transfer(pACB, pSRB); } #endif @@ -2875,9 +2905,7 @@ u16 * pscsi_status) { -#ifdef DC395x_DEBUG0 - printk(KERN_INFO DC395X_NAME ": DC395x_DataOutPhase1.....\n"); -#endif + dprintkdbg(DBG_0, "DC395x_DataOutPhase1.....\n"); /*1.25 */ TRACEPRINTF("DOP1*"); DC395x_clrfifo(pACB, "DOP1"); @@ -2906,10 +2934,7 @@ /*struct DeviceCtlBlk* pDCB = pSRB->pSRBDCB; */ /*u8 bval; */ -#ifdef DC395x_DEBUG0 - printk(KERN_INFO DC395X_NAME - ": DC395x_DataInPhase0..............\n "); -#endif + dprintkdbg(DBG_0, "DC395x_DataInPhase0..............\n"); TRACEPRINTF("DIP0*"); scsi_status = *pscsi_status; @@ -2928,8 +2953,8 @@ */ if (!(pSRB->SRBState & SRB_XFERPAD)) { if (scsi_status & PARITYERROR) { - printk(DC395X_NAME - ": Parity Error (pid %li, target %02i-%i)\n", + dprintkl(KERN_INFO, + "Parity Error (pid %li, target %02i-%i)\n", pSRB->pcmd->pid, pSRB->pcmd->device->id, pSRB->pcmd->device->lun); pSRB->SRBStatus |= PARITY_ERROR; @@ -2943,8 +2968,8 @@ if (!(DC395x_read8(TRM_S1040_DMA_FIFOSTAT) & 0x80)) { #if 0 int ctr = 6000000; - printk(DC395X_NAME - ": DIP0: Wait for DMA FIFO to flush ...\n"); + dprintkl(KERN_DEBUG, + "DIP0: Wait for DMA FIFO to flush ...\n"); /*DC395x_write8 (TRM_S1040_DMA_CONTROL, STOPDMAXFER); */ /*DC395x_write32 (TRM_S1040_SCSI_COUNTER, 7); */ /*DC395x_write8 (TRM_S1040_SCSI_COMMAND, SCMD_DMA_IN); */ @@ -2952,18 +2977,16 @@ (DC395x_read16(TRM_S1040_DMA_FIFOSTAT) & 0x80) && --ctr); if (ctr < 6000000 - 1) - printk(DC395X_NAME - ": Debug: DIP0: Had to wait for DMA ...\n"); + dprintkl(KERN_DEBUG + "DIP0: Had to wait for DMA ...\n"); if (!ctr) - printk(KERN_ERR DC395X_NAME - ": Deadlock in DIP0 waiting for DMA FIFO empty!!\n"); + dprintkl(KERN_ERR, + "Deadlock in DIP0 waiting for DMA FIFO empty!!\n"); /*DC395x_write32 (TRM_S1040_SCSI_COUNTER, 0); */ #endif -#ifdef DC395x_DEBUG_KG - printk(DC395X_NAME ": DIP0: DMA_FIFO: %02x %02x\n", + dprintkdbg(DBG_KG, "DIP0: DMA_FIFO: %02x %02x\n", DC395x_read8(TRM_S1040_DMA_FIFOCNT), DC395x_read8(TRM_S1040_DMA_FIFOSTAT)); -#endif } /* Now: Check remainig data: The SCSI counters should tell us ... */ dLeftCounter = DC395x_read32(TRM_S1040_SCSI_COUNTER) @@ -2971,42 +2994,34 @@ << ((pSRB->pSRBDCB->SyncPeriod & WIDE_SYNC) ? 1 : 0)); -#ifdef DC395x_DEBUG_KG - printk(DC395X_NAME - ": Debug: SCSI FIFO contains %i %s in DIP0\n", - DC395x_read8(TRM_S1040_SCSI_FIFOCNT) & 0x1f, - (pSRB->pSRBDCB-> - SyncPeriod & WIDE_SYNC) ? "words" : "bytes"); - printk(DC395X_NAME ": SCSI FIFOCNT %02x, SCSI CTR %08x\n", - DC395x_read8(TRM_S1040_SCSI_FIFOCNT), - DC395x_read32(TRM_S1040_SCSI_COUNTER)); - printk(DC395X_NAME - ": DMA FIFOCNT %02x,%02x DMA CTR %08x\n", - DC395x_read8(TRM_S1040_DMA_FIFOCNT), - DC395x_read8(TRM_S1040_DMA_FIFOSTAT), - DC395x_read32(TRM_S1040_DMA_CXCNT)); - printk(DC395X_NAME - ": Remaining: TotXfer: %i, SCSI FIFO+Ctr: %i\n", - pSRB->SRBTotalXferLength, dLeftCounter); -#endif + dprintkdbg(DBG_KG, "SCSI FIFO contains %i %s in DIP0\n", + DC395x_read8(TRM_S1040_SCSI_FIFOCNT) & 0x1f, + (pSRB->pSRBDCB-> + SyncPeriod & WIDE_SYNC) ? "words" : "bytes"); + dprintkdbg(DBG_KG, "SCSI FIFOCNT %02x, SCSI CTR %08x\n", + DC395x_read8(TRM_S1040_SCSI_FIFOCNT), + DC395x_read32(TRM_S1040_SCSI_COUNTER)); + dprintkdbg(DBG_KG, "DMA FIFOCNT %02x,%02x DMA CTR %08x\n", + DC395x_read8(TRM_S1040_DMA_FIFOCNT), + DC395x_read8(TRM_S1040_DMA_FIFOSTAT), + DC395x_read32(TRM_S1040_DMA_CXCNT)); + dprintkdbg(DBG_KG, "Remaining: TotXfer: %i, SCSI FIFO+Ctr: %i\n", + pSRB->SRBTotalXferLength, dLeftCounter); #if DC395x_LASTPIO /* KG: Less than or equal to 4 bytes can not be transfered via DMA, it seems. */ if (dLeftCounter && pSRB->SRBTotalXferLength <= DC395x_LASTPIO) { /*u32 addr = (pSRB->SegmentX[pSRB->SRBSGIndex].address); */ /*DC395x_update_SGlist (pSRB, dLeftCounter); */ - DEBUGPIO(printk - (DC395X_NAME - ": DIP0: PIO (%i %s) to %p for remaining %i bytes:", + dprintkdbg(DBG_PIO, "DIP0: PIO (%i %s) to %p for remaining %i bytes:", DC395x_read8(TRM_S1040_SCSI_FIFOCNT) & 0x1f, (pSRB->pSRBDCB-> SyncPeriod & WIDE_SYNC) ? "words" : "bytes", pSRB->virt_addr, pSRB->SRBTotalXferLength); - ) - if (pSRB->pSRBDCB->SyncPeriod & WIDE_SYNC) + if (pSRB->pSRBDCB->SyncPeriod & WIDE_SYNC) DC395x_write8(TRM_S1040_SCSI_CONFIG2, CFG2_WIDEFIFO); @@ -3015,17 +3030,17 @@ u8 byte = DC395x_read8(TRM_S1040_SCSI_FIFO); *(pSRB->virt_addr)++ = byte; - DEBUGPIO(printk(" %02x", byte); - ) - pSRB->SRBTotalXferLength--; + if (debug_enabled(DBG_PIO)) + printk(" %02x", byte); + pSRB->SRBTotalXferLength--; dLeftCounter--; pSRB->SegmentX[pSRB->SRBSGIndex].length--; if (pSRB->SRBTotalXferLength && !pSRB->SegmentX[pSRB->SRBSGIndex]. length) { - DEBUGPIO(printk(" (next segment)"); - ) - pSRB->SRBSGIndex++; + if (debug_enabled(DBG_PIO)) + printk(" (next segment)"); + pSRB->SRBSGIndex++; DC395x_update_SGlist(pSRB, dLeftCounter); } @@ -3038,16 +3053,16 @@ (TRM_S1040_SCSI_FIFO); *(pSRB->virt_addr)++ = byte; pSRB->SRBTotalXferLength--; - DEBUGPIO(printk(" %02x", byte); - ) + if (debug_enabled(DBG_PIO)) + printk(" %02x", byte); } #endif DC395x_write8(TRM_S1040_SCSI_CONFIG2, 0); } - /*printk (" %08x", *(u32*)(bus_to_virt (addr))); */ + /*printk(" %08x", *(u32*)(bus_to_virt (addr))); */ /*pSRB->SRBTotalXferLength = 0; */ - DEBUGPIO(printk("\n"); - ) + if (debug_enabled(DBG_PIO)) + printk("\n"); } #endif /* DC395x_LASTPIO */ @@ -3075,12 +3090,12 @@ #endif /*dLeftCounter += DC395x_read32(TRM_S1040_SCSI_COUNTER); */ #if 0 - printk(DC395X_NAME - ": DIP0: ctr=%08x, DMA_FIFO=%02x,%02x SCSI_FIFO=%02x\n", + dprintkl(KERN_DEBUG, + "DIP0: ctr=%08x, DMA_FIFO=%02x,%02x SCSI_FIFO=%02x\n", dLeftCounter, DC395x_read8(TRM_S1040_DMA_FIFOCNT), DC395x_read8(TRM_S1040_DMA_FIFOSTAT), DC395x_read8(TRM_S1040_SCSI_FIFOCNT)); - printk(DC395X_NAME ": DIP0: DMAStat %02x\n", + dprintkl(KERN_DEBUG, "DIP0: DMAStat %02x\n", DC395x_read8(TRM_S1040_DMA_STATUS)); #endif @@ -3095,13 +3110,13 @@ DC395x_read8(TRM_S1040_DMA_STATUS); } while (!(TempDMAstatus & DMAXFERCOMP) && --ctr); if (!ctr) - printk(KERN_ERR DC395X_NAME - ": Deadlock in DataInPhase0 waiting for DMA!!\n"); + dprintkl(KERN_ERR, + "Deadlock in DataInPhase0 waiting for DMA!!\n"); pSRB->SRBTotalXferLength = 0; #endif -#if 0 /*def DC395x_DEBUG_KG */ - printk(DC395X_NAME - ": DIP0: DMA not yet ready: %02x: %i -> %i bytes\n", +#if 0 /*def DBG_KG */ + dprintkl(KERN_DEBUG, + "DIP0: DMA not yet ready: %02x: %i -> %i bytes\n", DC395x_read8(TRM_S1040_DMA_STATUS), pSRB->SRBTotalXferLength, dLeftCounter); #endif @@ -3120,7 +3135,7 @@ } /* KG: The target may decide to disconnect: Empty FIFO before! */ if ((*pscsi_status & PHASEMASK) != PH_DATA_IN) { - /*printk (DC395X_NAME ": Debug: Clean up after Data In ...\n"); */ + /*dprintkl(KERN_DEBUG, "Debug: Clean up after Data In ...\n"); */ DC395x_cleanup_after_transfer(pACB, pSRB); } #if 0 @@ -3128,13 +3143,13 @@ bval = DC395x_read8(TRM_S1040_SCSI_FIFOCNT); if (!(bval & 0x40)) { bval &= 0x1f; - printk(DC395X_NAME - ": DIP0(%li): %i bytes in SCSI FIFO (stat %04x) (left %08x)!!\n", + dprintkl(KERN_DEBUG, + "DIP0(%li): %i bytes in SCSI FIFO (stat %04x) (left %08x)!!\n", pSRB->pcmd->pid, bval & 0x1f, scsi_status, dLeftCounter); if ((dLeftCounter == 0) || (scsi_status & SCSIXFERCNT_2_ZERO)) { - printk(DC395X_NAME ": Clear FIFO!\n"); + dprintkl(KERN_DEBUG, "Clear FIFO!\n"); DC395x_clrfifo(pACB, "DIP0"); } } @@ -3159,9 +3174,7 @@ DC395x_DataInPhase1(struct AdapterCtlBlk *pACB, struct ScsiReqBlk *pSRB, u16 * pscsi_status) { -#ifdef DC395x_DEBUG0 - printk(KERN_INFO DC395X_NAME ": DC395x_DataInPhase1..... "); -#endif + dprintkdbg(DBG_0, "DC395x_DataInPhase1.....\n"); /* FIFO should be cleared, if previous phase was not DataPhase */ /*DC395x_clrfifo (pACB, "DIP1"); */ /* Allow data in! */ @@ -3189,19 +3202,15 @@ u8 bval; struct DeviceCtlBlk *pDCB; -#ifdef DC395x_DEBUG0 - printk(KERN_INFO DC395X_NAME - ": DataIO_transfer %c (pid %li): len = %i, SG: %i/%i\n", + dprintkdbg(DBG_0, "DataIO_transfer %c (pid %li): len = %i, SG: %i/%i\n", ((ioDir & DMACMD_DIR) ? 'r' : 'w'), pSRB->pcmd->pid, pSRB->SRBTotalXferLength, pSRB->SRBSGIndex, pSRB->SRBSGCount); -#endif TRACEPRINTF("%05x(%i/%i)*", pSRB->SRBTotalXferLength, pSRB->SRBSGIndex, pSRB->SRBSGCount); pDCB = pSRB->pSRBDCB; if (pSRB == pACB->pTmpSRB) { - printk(DC395X_NAME - ": ERROR! Using TmpSRB in DataPhase!\n"); + dprintkl(KERN_ERR, "Using TmpSRB in DataPhase!\n"); } if (pSRB->SRBSGIndex < pSRB->SRBSGCount) { if (pSRB->SRBTotalXferLength > DC395x_LASTPIO) { @@ -3211,8 +3220,7 @@ * Maybe, even ABORTXFER would be appropriate */ if (dma_status & XFERPENDING) { - printk(DC395X_NAME - ": Xfer pending! Expect trouble!!\n"); + dprintkl(KERN_DEBUG, "Xfer pending! Expect trouble!!\n"); DC395x_dumpinfo(pACB, pDCB, pSRB); DC395x_write8(TRM_S1040_DMA_CONTROL, CLRXFIFO); @@ -3280,19 +3288,13 @@ DC395x_write8 (TRM_S1040_SCSI_CONFIG2, CFG2_WIDEFIFO); - DEBUGPIO(printk - (DC395X_NAME - ": DOP1: PIO %i bytes from %p:", + dprintkdbg(DBG_PIO, "DOP1: PIO %i bytes from %p:", pSRB->SRBTotalXferLength, pSRB->virt_addr); - ) - while (pSRB->SRBTotalXferLength) { - DEBUGPIO(printk - (" %02x", - (unsigned char) *(pSRB-> - virt_addr)); - ) - DC395x_write8 + while (pSRB->SRBTotalXferLength) { + if (debug_enabled(DBG_PIO)) + printk(" %02x", (unsigned char) *(pSRB->virt_addr)); + DC395x_write8 (TRM_S1040_SCSI_FIFO, *(pSRB->virt_addr)++); pSRB->SRBTotalXferLength--; @@ -3302,10 +3304,9 @@ && !pSRB->SegmentX[pSRB-> SRBSGIndex]. length) { - DEBUGPIO(printk - (" (next segment)"); - ) - pSRB->SRBSGIndex++; + if (debug_enabled(DBG_PIO)) + printk(" (next segment)"); + pSRB->SRBSGIndex++; DC395x_update_SGlist(pSRB, pSRB-> SRBTotalXferLength); @@ -3313,19 +3314,17 @@ } if (pSRB->pSRBDCB->SyncPeriod & WIDE_SYNC) { if (ln % 2) { - DC395x_write8 - (TRM_S1040_SCSI_FIFO, - 0); - DEBUGPIO(printk(" |00"); - ) + DC395x_write8(TRM_S1040_SCSI_FIFO, 0); + if (debug_enabled(DBG_PIO)) + printk(" |00"); } DC395x_write8 (TRM_S1040_SCSI_CONFIG2, 0); } /*DC395x_write32(TRM_S1040_SCSI_COUNTER, ln); */ - DEBUGPIO(printk("\n"); - ) - DC395x_write8(TRM_S1040_SCSI_COMMAND, + if (debug_enabled(DBG_PIO)) + printk("\n"); + DC395x_write8(TRM_S1040_SCSI_COMMAND, SCMD_FIFO_OUT); } } @@ -3353,7 +3352,7 @@ data2 = DC395x_read8 (TRM_S1040_SCSI_FIFO); - /*printk (DC395X_NAME ": DataIO: Xfer pad: %02x %02x\n", data, data2); */ + /*dprintkl(KERN_DEBUG, "DataIO: Xfer pad: %02x %02x\n", data, data2); */ } else { /* Danger, Robinson: If you find KGs scattered over the wide * disk, the driver or chip is to blame :-( */ @@ -3371,7 +3370,7 @@ data = DC395x_read8 (TRM_S1040_SCSI_FIFO); - /*printk (DC395X_NAME ": DataIO: Xfer pad: %02x\n", data); */ + /*dprintkl(KERN_DEBUG, "DataIO: Xfer pad: %02x\n", data); */ } else { DC395x_write8(TRM_S1040_SCSI_FIFO, 'K'); @@ -3389,7 +3388,7 @@ } } /*DC395x_monitor_next_IRQ = 2; */ - /*printk (" done\n"); */ + /*printk(" done\n"); */ } @@ -3405,10 +3404,7 @@ DC395x_StatusPhase0(struct AdapterCtlBlk *pACB, struct ScsiReqBlk *pSRB, u16 * pscsi_status) { -#ifdef DC395x_DEBUG0 - printk(KERN_INFO DC395X_NAME ": StatusPhase0 (pid %li)\n", - pSRB->pcmd->pid); -#endif + dprintkdbg(DBG_0, "StatusPhase0 (pid %li)\n", pSRB->pcmd->pid); TRACEPRINTF("STP0 *"); pSRB->TargetStatus = DC395x_read8(TRM_S1040_SCSI_FIFO); pSRB->EndMessage = DC395x_read8(TRM_S1040_SCSI_FIFO); /* get message */ @@ -3436,10 +3432,7 @@ DC395x_StatusPhase1(struct AdapterCtlBlk *pACB, struct ScsiReqBlk *pSRB, u16 * pscsi_status) { -#ifdef DC395x_DEBUG0 - printk(KERN_INFO DC395X_NAME ": StatusPhase1 (pid=%li)\n", - pSRB->pcmd->pid); -#endif + dprintkdbg(DBG_0, "StatusPhase1 (pid=%li)\n", pSRB->pcmd->pid); TRACEPRINTF("STP1 *"); /* Cleanup is now done at the end of DataXXPhase0 */ /*DC395x_cleanup_after_transfer (pACB, pSRB); */ @@ -3494,8 +3487,8 @@ DC395x_ENABLE_MSGOUT; pSRB->SRBState &= ~SRB_MSGIN; pSRB->SRBState |= SRB_MSGOUT; - printk(KERN_INFO DC395X_NAME - ": Reject message %02x from %02i-%i\n", pSRB->MsgInBuf[0], + dprintkl(KERN_INFO, + "Reject message %02x from %02i-%i\n", pSRB->MsgInBuf[0], pSRB->pSRBDCB->TargetID, pSRB->pSRBDCB->TargetLUN); TRACEPRINTF("\\*"); } @@ -3525,12 +3518,10 @@ { struct ScsiReqBlk *lastSRB = pDCB->pGoingLast; struct ScsiReqBlk *pSRB = pDCB->pGoingSRB; -#ifdef DC395x_DEBUG0 - printk(DC395X_NAME ": QTag Msg (SRB %p): %i ", pSRB, tag); -#endif + dprintkdbg(DBG_0, "QTag Msg (SRB %p): %i\n", pSRB, tag); if (!(pDCB->TagMask & (1 << tag))) - printk(DC395X_NAME - ": MsgIn_QTag: TagMask (%08x) does not reserve tag %i!\n", + dprintkl(KERN_DEBUG, + "MsgIn_QTag: TagMask (%08x) does not reserve tag %i!\n", pDCB->TagMask, tag); if (!pSRB) @@ -3542,10 +3533,8 @@ goto mingx0; pSRB = pSRB->pNextSRB; } -#ifdef DC395x_DEBUG0 - printk("pid %li (%i-%i)\n", pSRB->pcmd->pid, + dprintkdbg(DBG_0, "pid %li (%i-%i)\n", pSRB->pcmd->pid, pSRB->pSRBDCB->TargetID, pSRB->pSRBDCB->TargetLUN); -#endif if (pDCB->DCBFlag & ABORT_DEV_) { /*pSRB->SRBState = SRB_ABORT_SENT; */ DC395x_EnableMsgOut_Abort(pACB, pSRB); @@ -3578,7 +3567,7 @@ pSRB->MsgCnt = 1; DC395x_ENABLE_MSGOUT; TRACEPRINTF("?*"); - printk(DC395X_NAME ": Unknown tag received: %i: abort !!\n", tag); + dprintkl(KERN_DEBUG, "Unknown tag received: %i: abort !!\n", tag); return pSRB; } @@ -3599,8 +3588,7 @@ DC395x_MsgIn_set_async(struct AdapterCtlBlk *pACB, struct ScsiReqBlk *pSRB) { struct DeviceCtlBlk *pDCB = pSRB->pSRBDCB; - printk(DC395X_NAME ": Target %02i: No sync transfers\n", - pDCB->TargetID); + dprintkl(KERN_DEBUG, "Target %02i: No sync transfers\n", pDCB->TargetID); TRACEPRINTF("!S *"); pDCB->SyncMode &= ~(SYNC_NEGO_ENABLE); pDCB->SyncMode |= SYNC_NEGO_DONE; @@ -3613,9 +3601,7 @@ && !(pDCB->SyncMode & WIDE_NEGO_DONE)) { DC395x_Build_WDTR(pACB, pDCB, pSRB); DC395x_ENABLE_MSGOUT; - DEBUG0(printk - (DC395X_NAME ": SDTR(rej): Try WDTR anyway ...\n"); - ) + dprintkdbg(DBG_0, "SDTR(rej): Try WDTR anyway ...\n"); } } @@ -3630,14 +3616,11 @@ /*u8 oldsyncperiod = pDCB->SyncPeriod; */ /*u8 oldsyncoffset = pDCB->SyncOffset; */ -#ifdef DC395x_DEBUG1 - printk(KERN_INFO DC395X_NAME - ": Target %02i: Sync: %ins (%02i.%01i MHz) Offset %i\n", + dprintkdbg(DBG_1, "Target %02i: Sync: %ins (%02i.%01i MHz) Offset %i\n", pDCB->TargetID, pSRB->MsgInBuf[3] << 2, (250 / pSRB->MsgInBuf[3]), ((250 % pSRB->MsgInBuf[3]) * 10) / pSRB->MsgInBuf[3], pSRB->MsgInBuf[4]); -#endif if (pSRB->MsgInBuf[4] > 15) pSRB->MsgInBuf[4] = 15; @@ -3655,8 +3638,8 @@ dc395x_clock_period[bval])) bval++; if (pSRB->MsgInBuf[3] < dc395x_clock_period[bval]) - printk(KERN_INFO DC395X_NAME - ": Increase sync nego period to %ins\n", + dprintkl(KERN_INFO, + "Increase sync nego period to %ins\n", dc395x_clock_period[bval] << 2); pSRB->MsgInBuf[3] = dc395x_clock_period[bval]; pDCB->SyncPeriod &= 0xf0; @@ -3668,8 +3651,8 @@ else fact = 250; - printk(KERN_INFO DC395X_NAME - ": Target %02i: %s Sync: %ins Offset %i (%02i.%01i MB/s)\n", + dprintkl(KERN_INFO, + "Target %02i: %s Sync: %ins Offset %i (%02i.%01i MB/s)\n", pDCB->TargetID, (fact == 500) ? "Wide16" : "", pDCB->MinNegoPeriod << 2, pDCB->SyncOffset, (fact / pDCB->MinNegoPeriod), @@ -3679,7 +3662,7 @@ TRACEPRINTF("S%i *", pDCB->MinNegoPeriod << 2); if (!(pSRB->SRBState & SRB_DO_SYNC_NEGO)) { /* Reply with corrected SDTR Message */ - printk(DC395X_NAME ": .. answer w/ %ins %i\n", + dprintkl(KERN_DEBUG, " .. answer w/ %ins %i\n", pSRB->MsgInBuf[3] << 2, pSRB->MsgInBuf[4]); memcpy(pSRB->MsgOutBuf, pSRB->MsgInBuf, 5); @@ -3691,9 +3674,7 @@ && !(pDCB->SyncMode & WIDE_NEGO_DONE)) { DC395x_Build_WDTR(pACB, pDCB, pSRB); DC395x_ENABLE_MSGOUT; - DEBUG0(printk - (DC395X_NAME ": SDTR: Also try WDTR ...\n"); - ) + dprintkdbg(DBG_0, "SDTR: Also try WDTR ...\n"); } } pSRB->SRBState &= ~SRB_DO_SYNC_NEGO; @@ -3708,10 +3689,8 @@ struct ScsiReqBlk *pSRB) { struct DeviceCtlBlk *pDCB = pSRB->pSRBDCB; -#ifdef DC395x_DEBUG_KG - printk(DC395X_NAME ": WDTR got rejected from target %02i\n", + dprintkdbg(DBG_KG, "WDTR got rejected from target %02i\n", pDCB->TargetID); -#endif TRACEPRINTF("!W *"); pDCB->SyncPeriod &= ~WIDE_SYNC; pDCB->SyncMode &= ~(WIDE_NEGO_ENABLE); @@ -3722,9 +3701,7 @@ && !(pDCB->SyncMode & SYNC_NEGO_DONE)) { DC395x_Build_SDTR(pACB, pDCB, pSRB); DC395x_ENABLE_MSGOUT; - DEBUG0(printk - (DC395X_NAME ": WDTR(rej): Try SDTR anyway ...\n"); - ) + dprintkdbg(DBG_0, "WDTR(rej): Try SDTR anyway ...\n"); } } @@ -3738,8 +3715,8 @@ pSRB->MsgInBuf[3] = wide; /* Completed */ if (!(pSRB->SRBState & SRB_DO_WIDE_NEGO)) { - printk(DC395X_NAME - ": Target %02i initiates Wide Nego ...\n", + dprintkl(KERN_DEBUG, + "Target %02i initiates Wide Nego ...\n", pDCB->TargetID); memcpy(pSRB->MsgOutBuf, pSRB->MsgInBuf, 4); pSRB->MsgCnt = 4; @@ -3755,18 +3732,15 @@ pSRB->SRBState &= ~SRB_DO_WIDE_NEGO; TRACEPRINTF("W%i *", (pDCB->SyncPeriod & WIDE_SYNC ? 1 : 0)); /*pDCB->SyncMode &= ~(WIDE_NEGO_ENABLE+WIDE_NEGO_DONE); */ -#ifdef DC395x_DEBUG_KG - printk(DC395X_NAME - ": Wide transfers (%i bit) negotiated with target %02i\n", + dprintkdbg(DBG_KG, + "Wide transfers (%i bit) negotiated with target %02i\n", (8 << pSRB->MsgInBuf[3]), pDCB->TargetID); -#endif DC395x_reprog(pACB, pDCB); if ((pDCB->SyncMode & SYNC_NEGO_ENABLE) && !(pDCB->SyncMode & SYNC_NEGO_DONE)) { DC395x_Build_SDTR(pACB, pDCB, pSRB); DC395x_ENABLE_MSGOUT; - DEBUG0(printk(DC395X_NAME ": WDTR: Also try SDTR ...\n"); - ) + dprintkdbg(DBG_0, "WDTR: Also try SDTR ...\n"); } } @@ -3797,17 +3771,14 @@ { struct DeviceCtlBlk *pDCB; -#ifdef DC395x_DEBUG0 - printk(KERN_INFO DC395X_NAME - ": DC395x_MsgInPhase0..............\n "); -#endif + dprintkdbg(DBG_0, "DC395x_MsgInPhase0..............\n"); TRACEPRINTF("MIP0*"); pDCB = pACB->pActiveDCB; pSRB->MsgInBuf[pACB->MsgLen++] = DC395x_read8(TRM_S1040_SCSI_FIFO); if (DC395x_MsgIn_complete(pSRB->MsgInBuf, pACB->MsgLen)) { TRACEPRINTF("(%02x)*", pSRB->MsgInBuf[0]); - /*printk (KERN_INFO DC395X_NAME ": MsgIn:"); */ + /*dprintkl(KERN_INFO, "MsgIn:"); */ /*DC395x_printMsg (pSRB->MsgInBuf, pACB->MsgLen); */ /* Now eval the msg */ @@ -3860,12 +3831,10 @@ /* Discard wide residual */ case MSG_IGNOREWIDE: - DEBUG0(printk - (DC395X_NAME ": Ignore Wide Residual!\n"); - ) - /*DC395x_write32 (TRM_S1040_SCSI_COUNTER, 1); */ - /*DC395x_read8 (TRM_S1040_SCSI_FIFO); */ - break; + dprintkdbg(DBG_0, "Ignore Wide Residual!\n"); + /*DC395x_write32 (TRM_S1040_SCSI_COUNTER, 1); */ + /*DC395x_read8 (TRM_S1040_SCSI_FIFO); */ + break; /* nothing has to be done */ case COMMAND_COMPLETE: @@ -3876,22 +3845,19 @@ * scsi command. Thanks, Gérard, for pointing it out. */ case SAVE_POINTERS: -#ifdef DC395x_DEBUG0 - printk(DC395X_NAME - ": SAVE POINTER message received (pid %li: rem.%i) ... ignore :-(\n", + dprintkdbg(DBG_0, "SAVE POINTER message received (pid %li: rem.%i) ... ignore :-(\n", pSRB->pcmd->pid, pSRB->SRBTotalXferLength); -#endif /*pSRB->Saved_Ptr = pSRB->TotalXferredLen; */ break; /* The device might want to restart transfer with a RESTORE */ case RESTORE_POINTERS: - printk(DC395X_NAME - ": RESTORE POINTER message received ... ignore :-(\n"); + dprintkl(KERN_DEBUG, + "RESTORE POINTER message received ... ignore :-(\n"); /*dc395x_restore_ptr (pACB, pSRB); */ break; case ABORT: - printk(DC395X_NAME - ": ABORT msg received (pid %li %02i-%i)\n", + dprintkl(KERN_DEBUG, + "ABORT msg received (pid %li %02i-%i)\n", pSRB->pcmd->pid, pDCB->TargetID, pDCB->TargetLUN); pDCB->DCBFlag |= ABORT_DEV_; @@ -3900,8 +3866,7 @@ /* reject unknown messages */ default: if (pSRB->MsgInBuf[0] & IDENTIFY_BASE) { - printk(DC395X_NAME - ": Identify Message received?\n"); + dprintkl(KERN_DEBUG, "Identify Message received?\n"); /*TRACEOUT (" %s\n", pSRB->debugtrace); */ pSRB->MsgCnt = 1; pSRB->MsgOutBuf[0] = pDCB->IdentifyMsg; @@ -3944,10 +3909,7 @@ DC395x_MsgInPhase1(struct AdapterCtlBlk *pACB, struct ScsiReqBlk *pSRB, u16 * pscsi_status) { -#ifdef DC395x_DEBUG0 - printk(KERN_INFO DC395X_NAME - ": DC395x_MsgInPhase1..............\n "); -#endif + dprintkdbg(DBG_0, "DC395x_MsgInPhase1..............\n"); TRACEPRINTF("MIP1 *"); DC395x_clrfifo(pACB, "MIP1"); DC395x_write32(TRM_S1040_SCSI_COUNTER, 1); @@ -4050,14 +4012,10 @@ struct DeviceCtlBlk *pDCB; struct ScsiReqBlk *pSRB; -#ifdef DC395x_DEBUG0 - printk(KERN_INFO DC395X_NAME ": Disconnect (pid=%li)\n", - pACB->pActiveDCB->pActiveSRB->pcmd->pid); -#endif + dprintkdbg(DBG_0, "Disconnect (pid=%li)\n", pACB->pActiveDCB->pActiveSRB->pcmd->pid); pDCB = pACB->pActiveDCB; if (!pDCB) { - printk(KERN_ERR DC395X_NAME - ": Disc: Exception Disconnect pDCB=NULL !!\n "); + dprintkl(KERN_ERR, "Disc: Exception Disconnect pDCB=NULL !!\n "); udelay(500); /* Suspend queue for a while */ pACB->pScsiHost->last_reset = @@ -4077,8 +4035,7 @@ DC395x_clrfifo(pACB, "Disc"); DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_HWRESELECT); if (pSRB->SRBState & SRB_UNEXPECT_RESEL) { - printk(KERN_ERR DC395X_NAME - ": Disc: Unexpected Reselection (%i-%i)\n", + dprintkl(KERN_ERR, "Disc: Unexpected Reselection (%i-%i)\n", pDCB->TargetID, pDCB->TargetLUN); pSRB->SRBState = 0; DC395x_Waiting_process(pACB); @@ -4086,7 +4043,7 @@ /*Scsi_Cmnd* pcmd = pSRB->pcmd; */ pDCB->DCBFlag &= ~ABORT_DEV_; pACB->pScsiHost->last_reset = jiffies + HZ / 2 + 1; - printk(KERN_ERR DC395X_NAME ": Disc: SRB_ABORT_SENT!\n"); + dprintkl(KERN_ERR, "Disc: SRB_ABORT_SENT!\n"); DC395x_DoingSRB_Done(pACB, DID_ABORT, pSRB->pcmd, 1); DC395x_Query_to_Waiting(pACB); DC395x_Waiting_process(pACB); @@ -4102,8 +4059,7 @@ if (pSRB->SRBState != SRB_START_ && pSRB->SRBState != SRB_MSGOUT) { pSRB->SRBState = SRB_READY; - printk(DC395X_NAME - ": Unexpected Disconnection (pid %li)!\n", + dprintkl(KERN_DEBUG, "Unexpected Disconnection (pid %li)!\n", pSRB->pcmd->pid); pSRB->TargetStatus = SCSI_STAT_SEL_TIMEOUT; TRACEPRINTF("UnExpD *"); @@ -4112,12 +4068,10 @@ } else { /* Normal selection timeout */ TRACEPRINTF("SlTO *"); -#ifdef DC395x_DEBUG_KG - printk(DC395X_NAME - ": Disc: SelTO (pid=%li) for dev %02i-%i\n", + dprintkdbg(DBG_KG, + "Disc: SelTO (pid=%li) for dev %02i-%i\n", pSRB->pcmd->pid, pDCB->TargetID, pDCB->TargetLUN); -#endif if (pSRB->RetryCnt++ > DC395x_MAX_RETRIES || pACB->scan_devices) { pSRB->TargetStatus = @@ -4126,10 +4080,8 @@ } DC395x_freetag(pDCB, pSRB); DC395x_Going_to_Waiting(pDCB, pSRB); -#ifdef DC395x_DEBUG_KG - printk(DC395X_NAME ": Retry pid %li ...\n", + dprintkdbg(DBG_KG, "Retry pid %li ...\n", pSRB->pcmd->pid); -#endif DC395x_waiting_timer(pACB, HZ / 20); } } else if (pSRB->SRBState & SRB_DISCONNECT) { @@ -4137,16 +4089,13 @@ /* * SRB_DISCONNECT (This is what we expect!) */ - /* printk (DC395X_NAME ": DoWaitingSRB (pid=%li)\n", pSRB->pcmd->pid); */ + /* dprintkl(KERN_DEBUG, "DoWaitingSRB (pid=%li)\n", pSRB->pcmd->pid); */ TRACEPRINTF("+*"); if (bval & 0x40) { - DEBUG0(printk - (DC395X_NAME - ": Debug: DISC: SCSI bus stat %02x: ACK set! Other controllers?\n", + dprintkdbg(DBG_0, "Debug: DISC: SCSI bus stat %02x: ACK set! Other controllers?\n", bval); - ) - /* It could come from another initiator, therefore don't do much ! */ - TRACEPRINTF("ACK(%02x) *", bval); + /* It could come from another initiator, therefore don't do much ! */ + TRACEPRINTF("ACK(%02x) *", bval); /*DC395x_dumpinfo (pACB, pDCB, pSRB); */ /*TRACEOUT (" %s\n", pSRB->debugtrace); */ /*pDCB->DCBFlag |= ABORT_DEV_; */ @@ -4162,7 +4111,7 @@ DC395x_freetag(pDCB, pSRB); pDCB->pActiveSRB = 0; pSRB->SRBState = SRB_FREE; - /*printk (DC395X_NAME ": done (pid=%li)\n", pSRB->pcmd->pid); */ + /*dprintkl(KERN_DEBUG, "done (pid=%li)\n", pSRB->pcmd->pid); */ DC395x_SRBdone(pACB, pDCB, pSRB); } } @@ -4184,9 +4133,7 @@ u8 id, lun; u8 arblostflag = 0; -#ifdef DC395x_DEBUG0 - printk(KERN_INFO DC395X_NAME ": DC395x_Reselect..............\n "); -#endif + dprintkdbg(DBG_0, "DC395x_Reselect..............\n"); DC395x_clrfifo(pACB, "Resel"); /*DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_HWRESELECT | DO_DATALATCH); */ @@ -4196,20 +4143,17 @@ if (pDCB) { /* Arbitration lost but Reselection win */ pSRB = pDCB->pActiveSRB; if (!pSRB) { - printk(DC395X_NAME - ": Arb lost Resel won, but pActiveSRB == 0!\n"); + dprintkl(KERN_DEBUG, "Arb lost Resel won, but pActiveSRB == 0!\n"); DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ return; } /* Why the if ? */ if (!(pACB->scan_devices)) { -#ifdef DC395x_DEBUG_KG - printk(DC395X_NAME - ": Arb lost but Resel win pid %li (%02i-%i) Rsel %04x Stat %04x\n", + dprintkdbg(DBG_KG, + "Arb lost but Resel win pid %li (%02i-%i) Rsel %04x Stat %04x\n", pSRB->pcmd->pid, pDCB->TargetID, pDCB->TargetLUN, RselTarLunId, DC395x_read16(TRM_S1040_SCSI_STATUS)); -#endif TRACEPRINTF("ArbLResel!*"); /*TRACEOUT (" %s\n", pSRB->debugtrace); */ arblostflag = 1; @@ -4225,15 +4169,13 @@ } /* Read Reselected Target Id and LUN */ if (!(RselTarLunId & (IDENTIFY_BASE << 8))) - printk(DC395X_NAME - ": Resel expects identify msg! Got %04x!\n", + dprintkl(KERN_DEBUG, "Resel expects identify msg! Got %04x!\n", RselTarLunId); id = RselTarLunId & 0xff; lun = (RselTarLunId >> 8) & 7; pDCB = DC395x_findDCB(pACB, id, lun); if (!pDCB) { - printk(KERN_ERR DC395X_NAME - ": Reselect from non existing device (%02i-%i)\n", + dprintkl(KERN_ERR, "Reselect from non existing device (%02i-%i)\n", id, lun); DC395x_write16(TRM_S1040_SCSI_CONTROL, DO_DATALATCH); /* it's important for atn stop */ return; @@ -4242,21 +4184,20 @@ pACB->pActiveDCB = pDCB; if (!(pDCB->DevMode & NTC_DO_DISCONNECT)) - printk(DC395X_NAME - ": Reselection in spite of forbidden disconnection? (%02i-%i)\n", + dprintkl(KERN_DEBUG, "Reselection in spite of forbidden disconnection? (%02i-%i)\n", pDCB->TargetID, pDCB->TargetLUN); if ((pDCB->SyncMode & EN_TAG_QUEUEING) /*&& !arblostflag */ ) { struct ScsiReqBlk *oldSRB = pSRB; pSRB = pACB->pTmpSRB; -#ifdef DC395x_DEBUGTRACE +#if debug_enabled(DBG_TRACE|DBG_TRACEALL) pSRB->debugpos = 0; pSRB->debugtrace[0] = 0; #endif pDCB->pActiveSRB = pSRB; if (oldSRB) TRACEPRINTF("ArbLResel(%li):*", oldSRB->pcmd->pid); - /*if (arblostflag) printk (DC395X_NAME ": Reselect: Wait for Tag ... \n"); */ + /*if (arblostflag) dprintkl(KERN_DEBUG, "Reselect: Wait for Tag ... \n"); */ } else { /* There can be only one! */ pSRB = pDCB->pActiveSRB; @@ -4266,8 +4207,8 @@ /* * abort command */ - printk(DC395X_NAME - ": Reselected w/o disconnected cmds from %02i-%i?\n", + dprintkl(KERN_DEBUG, + "Reselected w/o disconnected cmds from %02i-%i?\n", pDCB->TargetID, pDCB->TargetLUN); pSRB = pACB->pTmpSRB; pSRB->SRBState = SRB_UNEXPECT_RESEL; @@ -4307,14 +4248,12 @@ { struct DeviceCtlBlk *pPrevDCB = pACB->pLinkDCB; + dprintkdbg(DBG_0, "remove_dev\n"); if (pDCB->GoingSRBCnt > 1) { - DCBDEBUG(printk - (KERN_INFO DC395X_NAME - ": Driver won't free DCB (ID %i, LUN %i): 0x%08x because of SRBCnt %i\n", + dprintkdbg(DBG_DCB, "Driver won't free DCB (ID %i, LUN %i): 0x%08x because of SRBCnt %i\n", pDCB->TargetID, pDCB->TargetLUN, (int) pDCB, pDCB->GoingSRBCnt); - ) - return; + return; } pACB->DCBmap[pDCB->TargetID] &= ~(1 << pDCB->TargetLUN); pACB->children[pDCB->TargetID][pDCB->TargetLUN] = NULL; @@ -4335,19 +4274,16 @@ pACB->pLastDCB = pPrevDCB; } - DCBDEBUG(printk - (KERN_INFO DC395X_NAME - ": Driver about to free DCB (ID %i, LUN %i): %p\n", + dprintkdbg(DBG_DCB, "Driver about to free DCB (ID %i, LUN %i): %p\n", pDCB->TargetID, pDCB->TargetLUN, pDCB); - ) - if (pDCB == pACB->pActiveDCB) + if (pDCB == pACB->pActiveDCB) pACB->pActiveDCB = 0; if (pDCB == pACB->pLinkDCB) pACB->pLinkDCB = pDCB->pNextDCB; if (pDCB == pACB->pDCBRunRobin) pACB->pDCBRunRobin = pDCB->pNextDCB; pACB->DCBCnt--; - KFREE(pDCB); + dc395x_kfree(pDCB); /* pACB->DeviceCnt--; */ } @@ -4414,29 +4350,23 @@ dir = scsi_to_pci_dma_dir(pcmd->sc_data_direction); if (pcmd->use_sg && dir != PCI_DMA_NONE) { /* unmap DC395x SG list */ -#ifdef DC395x_SGPARANOIA - printk(DC395X_NAME - ": Unmap SG descriptor list %08x (%05x)\n", + dprintkdbg(DBG_SGPARANOIA, + "Unmap SG descriptor list %08x (%05x)\n", pSRB->SRBSGBusAddr, sizeof(struct SGentry) * DC395x_MAX_SG_LISTENTRY); -#endif pci_unmap_single(pACB->pdev, pSRB->SRBSGBusAddr, sizeof(struct SGentry) * DC395x_MAX_SG_LISTENTRY, PCI_DMA_TODEVICE); -#ifdef DC395x_SGPARANOIA - printk(DC395X_NAME ": Unmap %i SG segments from %p\n", + dprintkdbg(DBG_SGPARANOIA, "Unmap %i SG segments from %p\n", pcmd->use_sg, pcmd->request_buffer); -#endif /* unmap the sg segments */ pci_unmap_sg(pACB->pdev, (struct scatterlist *) pcmd->request_buffer, pcmd->use_sg, dir); } else if (pcmd->request_buffer && dir != PCI_DMA_NONE) { -#ifdef DC395x_SGPARANOIA - printk(DC395X_NAME ": Unmap buffer at %08x (%05x)\n", + dprintkdbg(DBG_SGPARANOIA, "Unmap buffer at %08x (%05x)\n", pSRB->SegmentX[0].address, pcmd->request_bufflen); -#endif pci_unmap_single(pACB->pdev, pSRB->SegmentX[0].address, pcmd->request_bufflen, dir); } @@ -4454,10 +4384,8 @@ if (!(pSRB->SRBFlag & AUTO_REQSENSE)) return; /* Unmap sense buffer */ -#ifdef DC395x_SGPARANOIA - printk(DC395X_NAME ": Unmap sense buffer from %08x (%05x)\n", - pSRB->SegmentX[0].address, sizeof(pcmd->sense_buffer)); -#endif + dprintkdbg(DBG_SGPARANOIA, "Unmap sense buffer from %08x\n", + pSRB->SegmentX[0].address); pci_unmap_single(pACB->pdev, pSRB->SegmentX[0].address, pSRB->SegmentX[0].length, PCI_DMA_FROMDEVICE); /* Restore SG stuff */ @@ -4497,22 +4425,16 @@ ptr = (struct ScsiInqData *) CPU_ADDR(*(struct scatterlist *) ptr); -#ifdef DC395x_SGPARANOIA - printk(KERN_INFO DC395X_NAME - ": SRBdone SG=%i (%i/%i), req_buf = %p, adr = %p\n", + dprintkdbg(DBG_SGPARANOIA, + "SRBdone SG=%i (%i/%i), req_buf = %p, adr = %p\n", pcmd->use_sg, pSRB->SRBSGIndex, pSRB->SRBSGCount, pcmd->request_buffer, ptr); -#endif -#ifdef DC395x_DEBUG_KG - printk(KERN_INFO DC395X_NAME - ": SRBdone (pid %li, target %02i-%i): ", pSRB->pcmd->pid, + dprintkdbg(DBG_KG, + "SRBdone (pid %li, target %02i-%i): ", pSRB->pcmd->pid, pSRB->pcmd->device->id, pSRB->pcmd->device->lun); -#endif status = pSRB->TargetStatus; if (pSRB->SRBFlag & AUTO_REQSENSE) { -#ifdef DC395x_DEBUG0 - printk(KERN_INFO "AUTO_REQSENSE1..............\n "); -#endif + dprintkdbg(DBG_0, "AUTO_REQSENSE1..............\n"); DC395x_pci_unmap_sense(pACB, pSRB); /* ** target status.......................... @@ -4520,60 +4442,58 @@ pSRB->SRBFlag &= ~AUTO_REQSENSE; pSRB->AdaptStatus = 0; pSRB->TargetStatus = CHECK_CONDITION << 1; -#ifdef DC395x_DEBUG_KG - switch (pcmd->sense_buffer[2] & 0x0f) { - case NOT_READY: - printk - ("\nDC395x: ReqSense: NOT_READY (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i) ", - pcmd->cmnd[0], pDCB->TargetID, - pDCB->TargetLUN, status, pACB->scan_devices); - break; - case UNIT_ATTENTION: - printk - ("\nDC395x: ReqSense: UNIT_ATTENTION (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i) ", - pcmd->cmnd[0], pDCB->TargetID, - pDCB->TargetLUN, status, pACB->scan_devices); - break; - case ILLEGAL_REQUEST: - printk - ("\nDC395x: ReqSense: ILLEGAL_REQUEST (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i) ", - pcmd->cmnd[0], pDCB->TargetID, - pDCB->TargetLUN, status, pACB->scan_devices); - break; - case MEDIUM_ERROR: - printk - ("\nDC395x: ReqSense: MEDIUM_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i) ", - pcmd->cmnd[0], pDCB->TargetID, - pDCB->TargetLUN, status, pACB->scan_devices); - break; - case HARDWARE_ERROR: - printk - ("\nDC395x: ReqSense: HARDWARE_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i) ", - pcmd->cmnd[0], pDCB->TargetID, - pDCB->TargetLUN, status, pACB->scan_devices); - break; + if (debug_enabled(DBG_KG)) { + switch (pcmd->sense_buffer[2] & 0x0f) { + case NOT_READY: + dprintkl(KERN_DEBUG, + "ReqSense: NOT_READY (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i) ", + pcmd->cmnd[0], pDCB->TargetID, + pDCB->TargetLUN, status, pACB->scan_devices); + break; + case UNIT_ATTENTION: + dprintkl(KERN_DEBUG, + "ReqSense: UNIT_ATTENTION (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i) ", + pcmd->cmnd[0], pDCB->TargetID, + pDCB->TargetLUN, status, pACB->scan_devices); + break; + case ILLEGAL_REQUEST: + dprintkl(KERN_DEBUG, + "ReqSense: ILLEGAL_REQUEST (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i) ", + pcmd->cmnd[0], pDCB->TargetID, + pDCB->TargetLUN, status, pACB->scan_devices); + break; + case MEDIUM_ERROR: + dprintkl(KERN_DEBUG, + "ReqSense: MEDIUM_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i) ", + pcmd->cmnd[0], pDCB->TargetID, + pDCB->TargetLUN, status, pACB->scan_devices); + break; + case HARDWARE_ERROR: + dprintkl(KERN_DEBUG, + "ReqSense: HARDWARE_ERROR (Cmnd = 0x%02x, Dev = %i-%i, Stat = %i, Scan = %i) ", + pcmd->cmnd[0], pDCB->TargetID, + pDCB->TargetLUN, status, pACB->scan_devices); + break; + } + if (pcmd->sense_buffer[7] >= 6) + dprintkl(KERN_DEBUG, + "Sense=%02x, ASC=%02x, ASCQ=%02x (%08x %08x) ", + pcmd->sense_buffer[2], pcmd->sense_buffer[12], + pcmd->sense_buffer[13], + *((unsigned int *) (pcmd->sense_buffer + 3)), + *((unsigned int *) (pcmd->sense_buffer + 8))); + else + dprintkl(KERN_DEBUG, + "Sense=%02x, No ASC/ASCQ (%08x) ", + pcmd->sense_buffer[2], + *((unsigned int *) (pcmd->sense_buffer + 3))); } - if (pcmd->sense_buffer[7] >= 6) - printk - ("\nDC395x: Sense=%02x, ASC=%02x, ASCQ=%02x (%08x %08x) ", - pcmd->sense_buffer[2], pcmd->sense_buffer[12], - pcmd->sense_buffer[13], - *((unsigned int *) (pcmd->sense_buffer + 3)), - *((unsigned int *) (pcmd->sense_buffer + 8))); - else - printk - ("\nDC395x: Sense=%02x, No ASC/ASCQ (%08x) ", - pcmd->sense_buffer[2], - *((unsigned int *) (pcmd->sense_buffer + 3))); -#endif if (status == (CHECK_CONDITION << 1)) { pcmd->result = DID_BAD_TARGET << 16; goto ckc_e; } -#ifdef DC395x_DEBUG0 - printk(KERN_INFO "AUTO_REQSENSE2..............\n "); -#endif + dprintkdbg(DBG_0, "AUTO_REQSENSE2..............\n"); if ((pSRB->SRBTotalXferLength) && (pSRB->SRBTotalXferLength >= pcmd->underflow)) @@ -4680,28 +4600,24 @@ /* This may be interpreted by sb. or not ... */ pcmd->SCp.this_residual = pSRB->SRBTotalXferLength; pcmd->SCp.buffers_residual = 0; -#ifdef DC395x_DEBUG_KG - if (pSRB->SRBTotalXferLength) - printk - ("\nDC395x: pid %li: %02x (%02i-%i): Missed %i bytes\n", - pcmd->pid, pcmd->cmnd[0], pcmd->device->id, - pcmd->device->lun, pSRB->SRBTotalXferLength); -#endif + if (debug_enabled(DBG_KG)) { + if (pSRB->SRBTotalXferLength) + dprintkdbg(DBG_KG, "pid %li: %02x (%02i-%i): Missed %i bytes\n", + pcmd->pid, pcmd->cmnd[0], pcmd->device->id, + pcmd->device->lun, pSRB->SRBTotalXferLength); + } DC395x_Going_remove(pDCB, pSRB, 0); /* Add to free list */ if (pSRB == pACB->pTmpSRB) - printk("\nDC395x: ERROR! Completed Cmnd with TmpSRB!\n"); + dprintkl(KERN_ERR, "ERROR! Completed Cmnd with TmpSRB!\n"); else DC395x_Free_insert(pACB, pSRB); - DEBUG0(printk - (KERN_DEBUG DC395X_NAME ": SRBdone: done pid %li\n", - pcmd->pid); - ) -#ifdef DC395x_DEBUG_KG - printk(" 0x%08x\n", pcmd->result); -#endif + dprintkdbg(DBG_0, "SRBdone: done pid %li\n", pcmd->pid); + if (debug_enabled(DBG_KG)) { + printk(" 0x%08x\n", pcmd->result); + } TRACEPRINTF("%08x(%li)*", pcmd->result, jiffies); DC395x_pci_unmap(pACB, pSRB); /*DC395x_UNLOCK_ACB_NI; */ @@ -4735,7 +4651,7 @@ pDCB = pACB->pLinkDCB; if (!pDCB) return; - printk(KERN_INFO DC395X_NAME ": DC395x_DoingSRB_Done: pids "); + dprintkl(KERN_INFO, "DC395x_DoingSRB_Done: pids "); do { /* As the ML may queue cmnds again, cache old values */ struct ScsiReqBlk *pWaitingSRB = pDCB->pWaitingSRB; @@ -4779,12 +4695,12 @@ pSRB = pSRBTemp; } if (pDCB->pGoingSRB) - printk(DC395X_NAME - ": How could the ML send cmnds to the Going queue? (%02i-%i)!!\n", + dprintkl(KERN_DEBUG, + "How could the ML send cmnds to the Going queue? (%02i-%i)!!\n", pDCB->TargetID, pDCB->TargetLUN); if (pDCB->TagMask) - printk(DC395X_NAME - ": TagMask for %02i-%i should be empty, is %08x!\n", + dprintkl(KERN_DEBUG, + "TagMask for %02i-%i should be empty, is %08x!\n", pDCB->TargetID, pDCB->TargetLUN, pDCB->TagMask); /*pDCB->GoingSRBCnt = 0;; */ @@ -4850,10 +4766,7 @@ { /*u32 drv_flags=0; */ -#ifdef DC395x_DEBUG0 - printk(KERN_INFO DC395X_NAME - ": DC395x_ResetSCSIBus..............\n "); -#endif + dprintkdbg(DBG_0, "DC395x_ResetSCSIBus..............\n"); /*DC395x_DRV_LOCK(drv_flags); */ pACB->ACBFlag |= RESET_DEV; /* RESET_DETECT, RESET_DONE, RESET_DEV */ @@ -4892,7 +4805,7 @@ wval = DC395x_read16(TRM_S1040_DMA_CONFIG) & ~DMA_FIFO_CTRL; wval |= DMA_FIFO_HALF_HALF | DMA_ENHANCE /*| DMA_MEM_MULTI_READ */ ; - /*printk (KERN_INFO DC395X_NAME "DMA_Config: %04x\n", wval); */ + /*dprintkl(KERN_INFO, "DMA_Config: %04x\n", wval); */ DC395x_write16(TRM_S1040_DMA_CONFIG, wval); /* Clear pending interrupt status */ DC395x_read8(TRM_S1040_SCSI_INTSTATUS); @@ -4912,7 +4825,7 @@ */ static void DC395x_ScsiRstDetect(struct AdapterCtlBlk *pACB) { - printk(KERN_INFO DC395X_NAME ": DC395x_ScsiRstDetect\n"); + dprintkl(KERN_INFO, "DC395x_ScsiRstDetect\n"); /* delay half a second */ if (timer_pending(&pACB->Waiting_Timer)) del_timer(&pACB->Waiting_Timer); @@ -4960,11 +4873,9 @@ Scsi_Cmnd *pcmd; pcmd = pSRB->pcmd; -#ifdef DC395x_DEBUG_KG - printk(KERN_INFO DC395X_NAME - ": DC395x_RequestSense for pid %li, target %02i-%i\n", + dprintkdbg(DBG_KG, + "DC395x_RequestSense for pid %li, target %02i-%i\n", pcmd->pid, pcmd->device->id, pcmd->device->lun); -#endif TRACEPRINTF("RqSn*"); pSRB->SRBFlag |= AUTO_REQSENSE; pSRB->AdaptStatus = 0; @@ -4986,17 +4897,15 @@ pSRB->SegmentX[0].address = pci_map_single(pACB->pdev, pcmd->sense_buffer, sizeof(pcmd->sense_buffer), PCI_DMA_FROMDEVICE); -#ifdef DC395x_SGPARANOIA - printk(DC395X_NAME ": Map sense buffer at %p (%05x) to %08x\n", + dprintkdbg(DBG_SGPARANOIA, "Map sense buffer at %p (%05x) to %08x\n", pcmd->sense_buffer, sizeof(pcmd->sense_buffer), pSRB->SegmentX[0].address); -#endif pSRB->SRBSGCount = 1; pSRB->SRBSGIndex = 0; if (DC395x_StartSCSI(pACB, pDCB, pSRB)) { /* Should only happen, if sb. else grabs the bus */ - printk(DC395X_NAME - ": Request Sense failed for pid %li (%02i-%i)!\n", + dprintkl(KERN_DEBUG, + "Request Sense failed for pid %li (%02i-%i)!\n", pSRB->pcmd->pid, pDCB->TargetID, pDCB->TargetLUN); TRACEPRINTF("?*"); DC395x_Going_to_Waiting(pDCB, pSRB); @@ -5025,10 +4934,8 @@ struct DeviceCtlBlk *pDCB; struct DeviceCtlBlk *pDCB2; -#ifdef DC395x_DEBUG0 - printk(KERN_INFO DC395X_NAME ": DC395x_initDCB..............\n "); -#endif - pDCB = KMALLOC(sizeof(struct DeviceCtlBlk), GFP_ATOMIC); + dprintkdbg(DBG_0, "DC395x_initDCB..............\n"); + pDCB = dc395x_kmalloc(sizeof(struct DeviceCtlBlk), GFP_ATOMIC); /*pDCB = DC395x_findDCB (pACB, target, lun); */ *ppDCB = pDCB; pDCB2 = 0; @@ -5098,12 +5005,10 @@ struct DeviceCtlBlk *prevDCB = pACB->pLinkDCB; while (prevDCB->TargetID != pDCB->TargetID) prevDCB = prevDCB->pNextDCB; -#ifdef DC395x_DEBUG_KG - printk(DC395X_NAME - ": Copy settings from %02i-%02i to %02i-%02i\n", + dprintkdbg(DBG_KG, + "Copy settings from %02i-%02i to %02i-%02i\n", prevDCB->TargetID, prevDCB->TargetLUN, pDCB->TargetID, pDCB->TargetLUN); -#endif pDCB->SyncMode = prevDCB->SyncMode; pDCB->SyncPeriod = prevDCB->SyncPeriod; pDCB->MinNegoPeriod = prevDCB->MinNegoPeriod; @@ -5116,18 +5021,18 @@ } -/* Dynamically allocated memory handling */ - -#ifdef DC395x_DEBUGTRACE -/* Memory for trace buffers */ +#if debug_enabled(DBG_TRACE|DBG_TRACEALL) +/* + * Memory for trace buffers + */ void DC395x_free_tracebufs(struct AdapterCtlBlk *pACB, int SRBIdx) { int srbidx; const unsigned bufs_per_page = PAGE_SIZE / DEBUGTRACEBUFSZ; for (srbidx = 0; srbidx < SRBIdx; srbidx += bufs_per_page) { - /*printk (DC395X_NAME ": Free tracebuf %p (for %i)\n", */ + /*dprintkl(KERN_DEBUG, "Free tracebuf %p (for %i)\n", */ /* pACB->SRB_array[srbidx].debugtrace, srbidx); */ - KFREE(pACB->SRB_array[srbidx].debugtrace); + dc395x_kfree(pACB->SRB_array[srbidx].debugtrace); } } @@ -5141,14 +5046,14 @@ int SRBIdx = 0; unsigned i = 0; unsigned char *ptr; - /*printk (DC395X_NAME ": Alloc %i pages for tracebufs\n", pages); */ + /*dprintkl(KERN_DEBUG, "Alloc %i pages for tracebufs\n", pages); */ while (pages--) { - ptr = KMALLOC(PAGE_SIZE, GFP_KERNEL); + ptr = dc395x_kmalloc(PAGE_SIZE, GFP_KERNEL); if (!ptr) { DC395x_free_tracebufs(pACB, SRBIdx); return 1; } - /*printk (DC395X_NAME ": Alloc %li bytes at %p for tracebuf %i\n", */ + /*dprintkl(KERN_DEBUG, "Alloc %li bytes at %p for tracebuf %i\n", */ /* PAGE_SIZE, ptr, SRBIdx); */ i = 0; while (i < bufs_per_page && SRBIdx < DC395x_MAX_SRB_CNT) @@ -5159,23 +5064,23 @@ pACB->TmpSRB.debugtrace = ptr + (i * DEBUGTRACEBUFSZ); pACB->TmpSRB.debugtrace[0] = 0; } else - printk(DC395X_NAME - ": No space for tmpSRB tracebuf reserved?!\n"); + dprintkl(KERN_DEBUG, "No space for tmpSRB tracebuf reserved?!\n"); return 0; } #endif /* Free SG tables */ +static void DC395x_free_SG_tables(struct AdapterCtlBlk *pACB, int SRBIdx) { int srbidx; const unsigned SRBs_per_page = PAGE_SIZE / (DC395x_MAX_SG_LISTENTRY * sizeof(struct SGentry)); for (srbidx = 0; srbidx < SRBIdx; srbidx += SRBs_per_page) { - /*printk (DC395X_NAME ": Free SG segs %p (for %i)\n", */ + /*dprintkl(KERN_DEBUG, "Free SG segs %p (for %i)\n", */ /* pACB->SRB_array[srbidx].SegmentX, srbidx); */ - KFREE(pACB->SRB_array[srbidx].SegmentX); + dc395x_kfree(pACB->SRB_array[srbidx].SegmentX); } } @@ -5194,14 +5099,14 @@ int SRBIdx = 0; unsigned i = 0; struct SGentry *ptr; - /*printk (DC395X_NAME ": Alloc %i pages for SG tables\n", pages); */ + /*dprintkl(KERN_DEBUG, "Alloc %i pages for SG tables\n", pages); */ while (pages--) { - ptr = (struct SGentry *) KMALLOC(PAGE_SIZE, GFP_KERNEL); + ptr = (struct SGentry *) dc395x_kmalloc(PAGE_SIZE, GFP_KERNEL); if (!ptr) { DC395x_free_SG_tables(pACB, SRBIdx); return 1; } - /*printk (DC395X_NAME ": Alloc %li bytes at %p for SG segments %i\n", */ + /*dprintkl(KERN_DEBUG, "Alloc %li bytes at %p for SG segments %i\n", */ /* PAGE_SIZE, ptr, SRBIdx); */ i = 0; while (i < SRBs_per_page && SRBIdx < DC395x_MAX_SRB_CNT) @@ -5212,8 +5117,7 @@ pACB->TmpSRB.SegmentX = ptr + (i * DC395x_MAX_SG_LISTENTRY); else - printk(DC395X_NAME - ": No space for tmpSRB SG table reserved?!\n"); + dprintkl(KERN_DEBUG, "No space for tmpSRB SG table reserved?!\n"); return 0; } @@ -5306,13 +5210,12 @@ * link all device's SRB Q of this adapter */ if (DC395x_alloc_SG_tables(pACB)) { - printk(DC395X_NAME ": SG table allocation failed!\n"); + dprintkl(KERN_DEBUG, "SG table allocation failed!\n"); return 1; } -#ifdef DC395x_DEBUGTRACE +#if debug_enabled(DBG_TRACE|DBG_TRACEALL) if (DC395x_alloc_tracebufs(pACB)) { - printk(DC395X_NAME - ": SG trace buffer allocation failed!\n"); + dprintkl(KERN_DEBUG, "SG trace buffer allocation failed!\n"); DC395x_free_SG_tables(pACB, DC395x_MAX_SRB_CNT); return 1; } @@ -5329,15 +5232,11 @@ for (i = 0; i < DC395x_MAX_SCSI_ID; i++) pACB->DCBmap[i] = 0; -#ifdef DC395x_DEBUG0 - printk(KERN_INFO DC395X_NAME - ": pACB = %p, pDCBmap = %p, pSRB_array = %p\n", pACB, + dprintkdbg(DBG_0, "pACB = %p, pDCBmap = %p, pSRB_array = %p\n", pACB, pACB->DCBmap, pACB->SRB_array); - printk(KERN_INFO DC395X_NAME - ": ACB size= %04lx, DCB size= %04lx, SRB size= %04lx\n", + dprintkdbg(DBG_0, "ACB size= %04x, DCB size= %04x, SRB size= %04x\n", sizeof(struct AdapterCtlBlk), sizeof(struct DeviceCtlBlk), sizeof(struct ScsiReqBlk)); -#endif return 0; } @@ -5364,7 +5263,7 @@ eeprom = &dc395x_trm_eepromBuf[index]; pTempACB = DC395x_pACB_start; if (pTempACB != NULL) { - for (; (pTempACB != (struct AdapterCtlBlk *) -1);) { + while (pTempACB) { if (pTempACB->IRQLevel == irq) { used_irq = 1; break; @@ -5374,16 +5273,14 @@ } if (!request_region(io_port, host->n_io_port, DC395X_NAME)) { - printk(KERN_ERR DC395X_NAME - ": Failed to reserve IO region 0x%x\n", io_port); + dprintkl(KERN_ERR, "Failed to reserve IO region 0x%x\n", io_port); return -1; } if (!used_irq) { if (request_irq (irq, DC395x_Interrupt, SA_SHIRQ, DC395X_NAME, (void *) host->hostdata)) { - printk(KERN_INFO DC395X_NAME - ": Failed to register IRQ!\n"); + dprintkl(KERN_INFO, "Failed to register IRQ!\n"); return -1; } } @@ -5414,8 +5311,7 @@ pACB->Config |= HCC_SCSI_RESET; if (pACB->Config & HCC_SCSI_RESET) { - printk(KERN_INFO DC395X_NAME - ": Performing initial SCSI bus reset\n"); + dprintkl(KERN_INFO, "Performing initial SCSI bus reset\n"); DC395x_write8(TRM_S1040_SCSI_CONTROL, DO_RSTSCSI); /*while (!( DC395x_read8(TRM_S1040_SCSI_INTSTATUS) & INT_SCSIRESET )); */ @@ -5691,11 +5587,11 @@ cksum += *w_eeprom; if (cksum != 0x1234) { /* - * Checksum is wrong. + * Checksum is wrong. * Load a set of defaults into the eeprom buffer */ - printk(KERN_WARNING DC395X_NAME - ": EEProm checksum error: using default values and options.\n"); + dprintkl(KERN_WARNING, + "EEProm checksum error: using default values and options.\n"); eeprom->NvramSubVendorID[0] = (u8) PCI_VENDOR_ID_TEKRAM; eeprom->NvramSubVendorID[1] = (u8) (PCI_VENDOR_ID_TEKRAM >> 8); @@ -5723,8 +5619,8 @@ *d_eeprom = 0x00; /* Now load defaults (maybe set by boot/module params) */ - DC395x_check_for_safe_settings(); - DC395x_fill_with_defaults(); + set_safe_settings(); + fix_settings(); DC395x_EEprom_Override(eeprom); eeprom->NvramCheckSum = 0x00; @@ -5734,16 +5630,16 @@ *w_eeprom = 0x1234 - cksum; TRM_S1040_write_all(eeprom, io_port); - eeprom->NvramDelayTime = dc395x_trm[5]; + eeprom->NvramDelayTime = cfg_data[CFG_RESET_DELAY].value; } else { - DC395x_check_for_safe_settings(); - DC395x_interpret_delay(eeprom); + set_safe_settings(); + eeprom_index_to_delay(eeprom); DC395x_EEprom_Override(eeprom); } } -/* +/* * adapter - print connection and terminiation config * * @param pACB - adapter control block @@ -5753,7 +5649,7 @@ u8 bval; bval = DC395x_read8(TRM_S1040_GEN_STATUS); - printk(KERN_INFO DC395X_NAME "%c: Connectors: ", + dprintkl(KERN_INFO, "%c: Connectors: ", ((bval & WIDESCSI) ? 'W' : ' ')); if (!(bval & CON5068)) printk("ext%s ", !(bval & EXT68HIGH) ? "68" : "50"); @@ -5780,6 +5676,29 @@ } +/** + * DC395x_print_eeprom_settings - output the eeprom settings + * to the kernel log so people can see what they were. + * + * @index: Adapter number + **/ +static void __init +DC395x_print_eeprom_settings(u16 index) +{ + dprintkl(KERN_INFO, "Used settings: AdapterID=%02i, Speed=%i(%02i.%01iMHz), DevMode=0x%02x\n", + dc395x_trm_eepromBuf[index].NvramScsiId, + dc395x_trm_eepromBuf[index].NvramTarget[0].NvmTarPeriod, + dc395x_clock_speed[dc395x_trm_eepromBuf[index].NvramTarget[0].NvmTarPeriod] / 10, + dc395x_clock_speed[dc395x_trm_eepromBuf[index].NvramTarget[0].NvmTarPeriod] % 10, + dc395x_trm_eepromBuf[index].NvramTarget[0].NvmTarCfg0); + dprintkl(KERN_INFO, " AdaptMode=0x%02x, Tags=%i(%02i), DelayReset=%is\n", + dc395x_trm_eepromBuf[index].NvramChannelCfg, + dc395x_trm_eepromBuf[index].NvramMaxTag, + 1 << dc395x_trm_eepromBuf[index].NvramMaxTag, + dc395x_trm_eepromBuf[index].NvramDelayTime); +} + + /* ********************************************************************* * DC395x_detect @@ -5804,124 +5723,44 @@ */ DC395x_check_eeprom(&dc395x_trm_eepromBuf[index], (u16) io_port); - /*$$$$$$$$$$$ MEMORY ALLOCATE FOR ADAPTER CONTROL BLOCK $$$$$$$$$$$$ */ + /* + *$$$$$$$$$$$ MEMORY ALLOCATE FOR ADAPTER CONTROL BLOCK $$$$$$$$$$$$ + */ host = scsi_register(host_template, sizeof(struct AdapterCtlBlk)); if (!host) { - printk(KERN_INFO DC395X_NAME - " : pSH scsi_register ERROR\n"); + dprintkl(KERN_INFO, "pSH scsi_register ERROR\n"); return 0; } - printk(KERN_INFO DC395X_NAME - ": Used settings: AdapterID=%02i, Speed=%i(%02i.%01iMHz), DevMode=0x%02x\n", - dc395x_trm_eepromBuf[index].NvramScsiId, - dc395x_trm_eepromBuf[index].NvramTarget[0].NvmTarPeriod, - dc395x_clock_speed[dc395x_trm_eepromBuf[index]. - NvramTarget[0].NvmTarPeriod] / 10, - dc395x_clock_speed[dc395x_trm_eepromBuf[index]. - NvramTarget[0].NvmTarPeriod] % 10, - dc395x_trm_eepromBuf[index].NvramTarget[0].NvmTarCfg0); - printk(KERN_INFO DC395X_NAME - ": AdaptMode=0x%02x, Tags=%i(%02i), DelayReset=%is\n", - dc395x_trm_eepromBuf[index].NvramChannelCfg, - dc395x_trm_eepromBuf[index].NvramMaxTag, - 1 << dc395x_trm_eepromBuf[index].NvramMaxTag, - dc395x_trm_eepromBuf[index].NvramDelayTime); + DC395x_print_eeprom_settings(index); pACB = (struct AdapterCtlBlk *) host->hostdata; - /*DC395x_ACB_INITLOCK(pACB); */ - /*DC395x_ACB_LOCK(pACB,acb_flags); */ - /*$$$$$$$$ INITIAL ADAPTER CONTROL BLOCK $$$$$$$$$$$$ */ + if (DC395x_initACB(host, io_port, irq, index)) { scsi_unregister(host); - /*DC395x_ACB_UNLOCK(pACB,acb_flags); */ return 0; } DC395x_print_config(pACB); - /*$$$$$$$$$$$$$$$$$ INITIAL ADAPTER $$$$$$$$$$$$$$$$$ */ + + /* + *$$$$$$$$$$$$$$$$$ INITIAL ADAPTER $$$$$$$$$$$$$$$$$ + */ if (!DC395x_initAdapter(host, io_port, irq, index)) { if (!DC395x_pACB_start) { DC395x_pACB_start = pACB; - DC395x_pACB_current = pACB; - pACB->pNextACB = (struct AdapterCtlBlk *) -1; } else { DC395x_pACB_current->pNextACB = pACB; - DC395x_pACB_current = pACB; - pACB->pNextACB = (struct AdapterCtlBlk *) -1; } - /*DC395x_ACB_UNLOCK(pACB,acb_flags); */ - return host; + DC395x_pACB_current = pACB; + pACB->pNextACB = NULL; + } else { - printk(KERN_INFO DC395X_NAME - ": DC395x_initAdapter initial ERROR\n"); + dprintkl(KERN_INFO, "DC395x_initAdapter initial ERROR\n"); scsi_unregister(host); - /*DC395x_ACB_UNLOCK(pACB,acb_flags); */ - return 0; + host = NULL; } + return host; } - -/* - * DC395x_detect - * - * Detect TRM-S1040 cards, acquire resources and initialise the card. - * Argument is a pointer to the host driver's scsi_hosts entry. - * - * Returns the number of adapters found. - * - * This function is called during system initialization and must not - * call SCSI mid-level functions including scsi_malloc() and - * scsi_free(). - */ -static int __init DC395x_detect(Scsi_Host_Template * host_template) -{ - struct pci_dev *pdev = NULL; - unsigned int io_port; - u8 irq; - DC395x_pACB_start = NULL; - - /* without PCI we cannot do anything */ - if (pci_present() == 0) { - printk(KERN_INFO DC395X_NAME ": PCI not present\n"); - return 0; - } - printk(KERN_INFO DC395X_NAME ": %s %s\n", DC395X_BANNER, - DC395X_VERSION); - - while ((pdev = - pci_find_device(PCI_VENDOR_ID_TEKRAM, - PCI_DEVICE_ID_TEKRAM_TRMS1040, pdev))) { - struct Scsi_Host *scsi_host; - if (pci_enable_device(pdev)) - continue; - - io_port = - pci_resource_start(pdev, 0) & PCI_BASE_ADDRESS_IO_MASK; - irq = pdev->irq; -#ifdef DC395x_DEBUG0 - printk(KERN_INFO DC395X_NAME ": IO_PORT=%04x,IRQ=%x\n", - (unsigned int) io_port, irq); -#endif - if ((scsi_host = - DC395x_init(host_template, io_port, irq, - DC395x_adapterCnt))) { - pci_set_master(pdev); - ((struct AdapterCtlBlk *) (scsi_host->hostdata))-> - pdev = pdev; - /*DC395x_set_pci_cfg(pdev); */ - DC395x_adapterCnt++; - } - } - - if (DC395x_adapterCnt) { - host_template->proc_name = DC395X_NAME; - } - printk(KERN_INFO DC395X_NAME ": %s: %i adapters found\n", - DC395X_BANNER, DC395x_adapterCnt); - - return DC395x_adapterCnt; -} - - /* * Functions: DC395x_inquiry(), DC395x_inquiry_done() * @@ -5935,11 +5774,11 @@ (struct AdapterCtlBlk *) cmd->device->host->hostdata; struct DeviceCtlBlk *pDCB = DC395x_findDCB(pACB, cmd->device->id, cmd->device->lun); -#ifdef DC395x_DEBUGTRACE +#if debug_enabled(DBG_TRACE|DBG_TRACEALL) struct ScsiReqBlk *pSRB = pACB->pFreeSRB; #endif - printk(KERN_INFO DC395X_NAME - ": INQUIRY (%02i-%i) returned %08x: %02x %02x %02x %02x ...\n", + dprintkl(KERN_INFO, + "INQUIRY (%02i-%i) returned %08x: %02x %02x %02x %02x ...\n", cmd->device->id, cmd->device->lun, cmd->result, ((u8 *) cmd->request_buffer)[0], ((u8 *) cmd->request_buffer)[1], @@ -5947,7 +5786,7 @@ ((u8 *) cmd->request_buffer)[3]); /*TRACEOUT ("%s\n", pSRB->debugtrace); */ if (cmd->result) { - printk(DC395X_NAME ": Unsetting Wide, Sync and TagQ!\n"); + dprintkl(KERN_INFO, "Unsetting Wide, Sync and TagQ!\n"); if (pDCB) { TRACEOUT("%s\n", pSRB->debugtrace); pDCB->DevMode &= @@ -5965,8 +5804,8 @@ pDCB->SyncMode &= ~WIDE_NEGO_ENABLE; } } else { - printk(DC395X_NAME - ": ERROR! No DCB existent for %02i-%i ?\n", + dprintkl(KERN_ERR, + "ERROR! No DCB existent for %02i-%i ?\n", cmd->device->id, cmd->device->lun); } kfree(cmd->buffer); @@ -5981,15 +5820,15 @@ { char *buffer; Scsi_Cmnd *cmd; - cmd = KMALLOC(sizeof(Scsi_Cmnd), GFP_ATOMIC); + cmd = dc395x_kmalloc(sizeof(Scsi_Cmnd), GFP_ATOMIC); if (!cmd) { - printk(DC395X_NAME ": kmalloc failed in inquiry!\n"); + dprintkl(KERN_ERR, "kmalloc failed in inquiry!\n"); return; } buffer = kmalloc(256, GFP_ATOMIC); if (!buffer) { kfree(cmd); - printk(DC395X_NAME ": kmalloc failed in inquiry!\n"); + dprintkl(KERN_ERR, "kmalloc failed in inquiry!\n"); return; } @@ -6022,8 +5861,8 @@ pDCB->SyncMode |= SYNC_NEGO_ENABLE; pDCB->SyncMode &= ~WIDE_NEGO_DONE; pDCB->SyncMode |= WIDE_NEGO_ENABLE; - printk(KERN_INFO DC395X_NAME - ": Queue INQUIRY command to dev %02i-%i\n", pDCB->TargetID, + dprintkl(KERN_INFO, + "Queue INQUIRY command to dev %02i-%i\n", pDCB->TargetID, pDCB->TargetLUN); DC395x_queue_command(cmd, DC395x_inquiry_done); } @@ -6062,12 +5901,11 @@ else SPRINTF(" No ") static int -DC395x_proc_info(char *buffer, char **start, off_t offset, int length, - int hostno, int inout) +DC395x_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start, off_t offset, int length, + int inout) { int dev, spd, spd1; char *pos = buffer; - struct Scsi_Host *shpnt = NULL; struct AdapterCtlBlk *pACB; struct DeviceCtlBlk *pDCB; unsigned long flags; @@ -6077,16 +5915,12 @@ pACB = DC395x_pACB_start; - while (pACB != (struct AdapterCtlBlk *) -1) { - shpnt = pACB->pScsiHost; - if (shpnt->host_no == hostno) + while (pACB) { + if (pACB->pScsiHost == shpnt) break; pACB = pACB->pNextACB; } - if (pACB == (struct AdapterCtlBlk *) -1) - return -ESRCH; - - if (!shpnt) + if (!pACB) return -ESRCH; if (inout) /* Has data been written to the file ? */ @@ -6187,7 +6021,7 @@ pDCB->TargetID, pDCB->TargetLUN, pDCB->GoingSRBCnt); for (pSRB = pDCB->pGoingSRB; pSRB; pSRB = pSRB->pNextSRB) -#ifdef DC395x_DEBUGTRACE +#if debug_enabled(DBG_TRACE|DBG_TRACEALL) SPRINTF("\n %s", pSRB->debugtrace); #else SPRINTF(" %li", pSRB->pcmd->pid); @@ -6197,14 +6031,14 @@ pDCB = pDCB->pNextDCB; } -#ifdef DC395x_DEBUGDCB - SPRINTF("DCB list for ACB %p:\n", pACB); - pDCB = pACB->pLinkDCB; - SPRINTF("%p", pDCB); - for (dev = 0; dev < pACB->DCBCnt; dev++, pDCB = pDCB->pNextDCB) - SPRINTF("->%p", pDCB->pNextDCB); - SPRINTF("\n"); -#endif + if (debug_enabled(DBG_DCB)) { + SPRINTF("DCB list for ACB %p:\n", pACB); + pDCB = pACB->pLinkDCB; + SPRINTF("%p", pDCB); + for (dev = 0; dev < pACB->DCBCnt; dev++, pDCB = pDCB->pNextDCB) + SPRINTF("->%p", pDCB->pNextDCB); + SPRINTF("\n"); + } *start = buffer + offset; DC395x_UNLOCK_IO(pACB->pScsiHost); @@ -6218,135 +6052,224 @@ } -/* - * Function : int DC395x_shutdown (struct Scsi_Host *host) - * Purpose : does a clean (we hope) shutdown of the SCSI chip. - * Use prior to dumping core, unloading the driver, etc. - * Returns : 0 on success - */ -int DC395x_shutdown(struct Scsi_Host *host) +/** + * DC395x_chip_shutdown - cleanly shut down the scsi controller chip, + * stopping all operations and disablig interrupt generation on the + * card. + * + * @acb: The scsi adapter control block of the adapter to shut down. + **/ +static +void DC395x_chip_shutdown(struct AdapterCtlBlk *pACB) { - struct AdapterCtlBlk *pACB; - pACB = (struct AdapterCtlBlk *) (host->hostdata); - - /* pACB->soft_reset(host); */ - /* disable interrupt */ DC395x_write8(TRM_S1040_DMA_INTEN, 0); DC395x_write8(TRM_S1040_SCSI_INTEN, 0); + + /* remove timers */ if (timer_pending(&pACB->Waiting_Timer)) del_timer(&pACB->Waiting_Timer); if (timer_pending(&pACB->SelTO_Timer)) del_timer(&pACB->SelTO_Timer); - if (1 || pACB->Config & HCC_SCSI_RESET) + /* reset the scsi bus */ + if (pACB->Config & HCC_SCSI_RESET) DC395x_ResetSCSIBus(pACB); + /* clear any pending interupt state */ DC395x_read8(TRM_S1040_SCSI_INTSTATUS); -#ifdef DC395x_DEBUGTRACE + + /* release chip resources */ +#if debug_enabled(DBG_TRACE|DBG_TRACEALL) DC395x_free_tracebufs(pACB, DC395x_MAX_SRB_CNT); #endif DC395x_free_SG_tables(pACB, DC395x_MAX_SRB_CNT); - return 0; } -/* - * Free all DCBs - */ -void DC395x_freeDCBs(struct Scsi_Host *host) +/** + * DC395x_free_DCBs - Free all of the DCBs. + * + * @pACB: Adapter to remove the DCBs for. + **/ +static +void DC395x_free_DCBs(struct AdapterCtlBlk* pACB) { - struct DeviceCtlBlk *pDCB; - struct DeviceCtlBlk *nDCB; - struct AdapterCtlBlk *pACB = - (struct AdapterCtlBlk *) (host->hostdata); + struct DeviceCtlBlk *dcb; + struct DeviceCtlBlk *dcb_next; + + dprintkdbg(DBG_DCB, "Free %i DCBs\n", pACB->DCBCnt); + + for (dcb = pACB->pLinkDCB; dcb != NULL; dcb = dcb_next) + { + dcb_next = dcb->pNextDCB; + dprintkdbg(DBG_DCB, "Free DCB (ID %i, LUN %i): %p\n", + dcb->TargetID, dcb->TargetLUN, dcb); + /* + * Free the DCB. This removes the entry from the + * pLinkDCB list and decrements the count in DCBCnt + */ + DC395x_remove_dev(pACB, dcb); - DCBDEBUG(printk - (KERN_INFO DC395X_NAME ": Free %i DCBs\n", pACB->DCBCnt); - ) - pDCB = pACB->pLinkDCB; - if (pDCB) { - do { - nDCB = pDCB->pNextDCB; - DCBDEBUG(printk - (KERN_INFO DC395X_NAME - ": Free DCB (ID %i, LUN %i): %p\n", - pDCB->TargetID, pDCB->TargetLUN, pDCB); - ) - DC395x_remove_dev(pACB, pDCB); /* includes a KFREE(pDCB); */ - printk("."); - pDCB = nDCB; - } while (pDCB && pACB->pLinkDCB); } } - -/* - * Release method +/** + * DC395x_release - shutdown device and release resources that were + * allocate for it. Called once for each card as it is shutdown. * - * Called when we are to shutdown the controller and release all of - * it's resources. - */ -static int DC395x_release(struct Scsi_Host *host) + * @host: The adapter instance to shutdown. + **/ +static +void DC395x_release(struct Scsi_Host *host) { - struct AdapterCtlBlk *pACB = - (struct AdapterCtlBlk *) (host->hostdata); + struct AdapterCtlBlk *pACB = (struct AdapterCtlBlk *) (host->hostdata); unsigned long flags; - printk(DC395X_NAME ": release"); + dprintkl(KERN_DEBUG, "DC395x release\n"); DC395x_LOCK_IO(pACB->pScsiHost); - DC395x_shutdown(host); - DC395x_freeDCBs(host); + DC395x_chip_shutdown(pACB); + DC395x_free_DCBs(pACB); if (host->irq != NO_IRQ) { - /* - * Find the IRQ to release. XXX Why didn't we just store the - * appropriate IRQ details when we request_irq it? - */ - int irq_count; - for (irq_count = 0, pACB = DC395x_pACB_start; - pACB != (struct AdapterCtlBlk *) -1; - pACB = pACB->pNextACB) { - if (pACB->IRQLevel == host->irq) - ++irq_count; - } - if (irq_count == 1) - free_irq(host->irq, DC395x_pACB_start); + free_irq(host->irq, DC395x_pACB_start); } release_region(host->io_port, host->n_io_port); DC395x_UNLOCK_IO(pACB->pScsiHost); - - return 1; } /* * SCSI host template */ -static Scsi_Host_Template driver_template = { - .proc_name = DC395X_NAME, - .proc_info = DC395x_proc_info, - .name = DC395X_BANNER " " DC395X_VERSION, - .detect = DC395x_detect, - .release = DC395x_release, - .queuecommand = DC395x_queue_command, - .bios_param = DC395x_bios_param, - .slave_alloc = DC395x_slave_alloc, - .slave_destroy = DC395x_slave_destroy, - .can_queue = DC395x_MAX_CAN_QUEUE, - .this_id = 7, - .sg_tablesize = DC395x_MAX_SG_TABLESIZE, - .cmd_per_lun = DC395x_MAX_CMD_PER_LUN, - .eh_abort_handler = DC395x_eh_abort, - .eh_bus_reset_handler = DC395x_eh_bus_reset, - .unchecked_isa_dma = 0, - .use_clustering = DISABLE_CLUSTERING, +static Scsi_Host_Template dc395x_driver_template = { + .module = THIS_MODULE, + .proc_name = DC395X_NAME, + .proc_info = DC395x_proc_info, + .name = DC395X_BANNER " " DC395X_VERSION, + .queuecommand = DC395x_queue_command, + .bios_param = DC395x_bios_param, + .slave_alloc = DC395x_slave_alloc, + .slave_destroy = DC395x_slave_destroy, + .can_queue = DC395x_MAX_CAN_QUEUE, + .this_id = 7, + .sg_tablesize = DC395x_MAX_SG_TABLESIZE, + .cmd_per_lun = DC395x_MAX_CMD_PER_LUN, + .eh_abort_handler = DC395x_eh_abort, + .eh_bus_reset_handler = DC395x_eh_bus_reset, + .unchecked_isa_dma = 0, + .use_clustering = DISABLE_CLUSTERING, +}; + +/* + * Called to initialise a single instance of the adaptor + */ + +static +int __devinit dc395x_init_one(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + unsigned int io_port; + u8 irq; + struct Scsi_Host *scsi_host; + static int banner_done = 0; + + dprintkdbg(DBG_0, "Init one instance of the dc395x\n"); + if (!banner_done) + { + dprintkl(KERN_INFO, "%s %s\n", DC395X_BANNER, DC395X_VERSION); + banner_done = 1; + } + + if (pci_enable_device(pdev)) + { + dprintkl(KERN_INFO, "PCI Enable device failed.\n"); + return -ENODEV; + } + + dprintkdbg(DBG_0, "Get resources...\n"); + io_port = pci_resource_start(pdev, 0) & PCI_BASE_ADDRESS_IO_MASK; + irq = pdev->irq; + dprintkdbg(DBG_0, "IO_PORT=%04x,IRQ=%x\n", (unsigned int) io_port, irq); + + scsi_host = DC395x_init(&dc395x_driver_template, io_port, irq, DC395x_adapterCnt); + if (!scsi_host) + { + dprintkdbg(DBG_0, "DC395x_init failed\n"); + return -ENOMEM; + } + + pci_set_master(pdev); + + /* store pci devices in out host data object. */ + ((struct AdapterCtlBlk *)(scsi_host->hostdata))->pdev = pdev; + + /* increment adaptor count */ + DC395x_adapterCnt++; + + /* store ptr to scsi host in the PCI device structure */ + pci_set_drvdata(pdev, scsi_host); + + /* get the scsi mid level to scan for new devices on the bus */ + scsi_add_host(scsi_host, &pdev->dev); + + return 0; +} + + +/* + * Called to remove a single instance of the adaptor + */ +static void __devexit dc395x_remove_one(struct pci_dev *pdev) +{ + struct Scsi_Host *host = pci_get_drvdata(pdev); + dprintkdbg(DBG_0, "Removing instance\n"); + scsi_remove_host(host); + DC395x_release(host); + pci_set_drvdata(pdev, NULL); +} + +/* + * Table which identifies the PCI devices which + * are handled by this device driver. + */ +static struct pci_device_id dc395x_pci_table[] __devinitdata = { + { + .vendor = PCI_VENDOR_ID_TEKRAM, + .device = PCI_DEVICE_ID_TEKRAM_TRMS1040, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + }, + {} /* Terminating entry */ }; +MODULE_DEVICE_TABLE(pci, dc395x_pci_table); + /* - * The following code deals with registering the above scsi host - * template with the higher level scsi code and results in the detect - * method from the template being called during initialisation. + * PCI driver operations. + * Tells the PCI sub system what can be done with the card. */ -#include "scsi_module.c" +static struct pci_driver dc395x_driver = { + .name = DC395X_NAME, + .id_table = dc395x_pci_table, + .probe = dc395x_init_one, + .remove = __devexit_p(dc395x_remove_one), +}; + +static int __init dc395x_module_init(void) +{ + return pci_module_init(&dc395x_driver); +} + +static void __exit dc395x_module_exit(void) +{ + pci_unregister_driver(&dc395x_driver); +} + +module_init(dc395x_module_init); +module_exit(dc395x_module_exit); + +MODULE_AUTHOR("C.L. Huang / Erich Chen / Kurt Garloff"); +MODULE_DESCRIPTION("SCSI host adapter driver for Tekram TRM-S1040 based adapters: Tekram DC395 and DC315 series"); +MODULE_LICENSE("GPL"); diff -Nru a/drivers/scsi/dmx3191d.h b/drivers/scsi/dmx3191d.h --- a/drivers/scsi/dmx3191d.h Mon Jun 9 23:16:12 2003 +++ b/drivers/scsi/dmx3191d.h Mon Jun 9 23:16:12 2003 @@ -1,4 +1,3 @@ - /* dmx3191d.h - defines for the Domex DMX3191D SCSI card. Copyright (C) 2000 by Massimo Piccioni <dafastidio@libero.it> @@ -23,7 +22,6 @@ static int dmx3191d_abort(Scsi_Cmnd *); static int dmx3191d_detect(Scsi_Host_Template *); static const char* dmx3191d_info(struct Scsi_Host *); -static int dmx3191d_proc_info(char *, char **, off_t, int, int, int); static int dmx3191d_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); static int dmx3191d_release_resources(struct Scsi_Host *); static int dmx3191d_bus_reset(Scsi_Cmnd *); diff -Nru a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c --- a/drivers/scsi/dpt_i2o.c Mon Jun 9 23:16:17 2003 +++ b/drivers/scsi/dpt_i2o.c Mon Jun 9 23:16:17 2003 @@ -505,8 +505,8 @@ return (char *) (pHba->detail); } -static int adpt_proc_info(char *buffer, char **start, off_t offset, - int length, int hostno, int inout) +static int adpt_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, + int length, int inout) { struct adpt_device* d; int id; @@ -515,7 +515,6 @@ int begin = 0; int pos = 0; adpt_hba* pHba; - struct Scsi_Host *host; int unit; *start = buffer; @@ -539,7 +538,7 @@ // Find HBA (host bus adapter) we are looking for down(&adpt_configuration_lock); for (pHba = hba_chain; pHba; pHba = pHba->next) { - if (pHba->host->host_no == hostno) { + if (pHba->host == host) { break; /* found adapter */ } } diff -Nru a/drivers/scsi/dpti.h b/drivers/scsi/dpti.h --- a/drivers/scsi/dpti.h Mon Jun 9 23:16:05 2003 +++ b/drivers/scsi/dpti.h Mon Jun 9 23:16:05 2003 @@ -37,8 +37,6 @@ * SCSI interface function Prototypes */ -static int adpt_proc_info(char *buffer, char **start, off_t offset, - int length, int inode, int inout); static int adpt_detect(Scsi_Host_Template * sht); static int adpt_queue(Scsi_Cmnd * cmd, void (*cmdcomplete) (Scsi_Cmnd *)); static int adpt_abort(Scsi_Cmnd * cmd); diff -Nru a/drivers/scsi/dtc.h b/drivers/scsi/dtc.h --- a/drivers/scsi/dtc.h Mon Jun 9 23:16:07 2003 +++ b/drivers/scsi/dtc.h Mon Jun 9 23:16:07 2003 @@ -36,8 +36,6 @@ static int dtc_bus_reset(Scsi_Cmnd *); static int dtc_device_reset(Scsi_Cmnd *); static int dtc_host_reset(Scsi_Cmnd *); -static int dtc_proc_info (char *buffer, char **start, off_t offset, - int length, int hostno, int inout); #ifndef CMD_PER_LUN #define CMD_PER_LUN 2 diff -Nru a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c --- a/drivers/scsi/eata_pio.c Mon Jun 9 23:16:15 2003 +++ b/drivers/scsi/eata_pio.c Mon Jun 9 23:16:15 2003 @@ -102,20 +102,15 @@ * length: If inout==FALSE max number of bytes to be written into the buffer * else number of bytes in the buffer */ -static int eata_pio_proc_info(char *buffer, char **start, off_t offset, - int length, int hostno, int rw) +static int eata_pio_proc_info(struct Scsi_Host *shost, char *buffer, char **start, off_t offset, + int length, int rw) { - struct Scsi_Host *shost; static u8 buff[512]; int size, len = 0; off_t begin = 0, pos = 0; if (rw) return -ENOSYS; - shost = scsi_host_hn_get(hostno); - if (!shost) - return -EINVAL; - if (offset == 0) memset(buff, 0, sizeof(buff)); diff -Nru a/drivers/scsi/esp.c b/drivers/scsi/esp.c --- a/drivers/scsi/esp.c Mon Jun 9 23:16:19 2003 +++ b/drivers/scsi/esp.c Mon Jun 9 23:16:19 2003 @@ -1408,8 +1408,8 @@ } /* ESP proc filesystem code. */ -static int esp_proc_info(char *buffer, char **start, off_t offset, - int length, int hostno, int inout) +static int esp_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, + int length, int inout) { struct esp *esp; @@ -1417,7 +1417,7 @@ return -EINVAL; /* not yet */ for_each_esp(esp) { - if (esp->ehost->host_no == hostno) + if (esp->ehost == host) break; } if (!esp) diff -Nru a/drivers/scsi/fcal.c b/drivers/scsi/fcal.c --- a/drivers/scsi/fcal.c Mon Jun 9 23:16:06 2003 +++ b/drivers/scsi/fcal.c Mon Jun 9 23:16:06 2003 @@ -209,17 +209,12 @@ #undef SPRINTF #define SPRINTF(args...) { if (pos < (buffer + length)) pos += sprintf (pos, ## args); } -int fcal_proc_info (char *buffer, char **start, off_t offset, int length, int hostno, int inout) +int fcal_proc_info (struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int inout) { - struct Scsi_Host *host = NULL; struct fcal *fcal; fc_channel *fc; char *pos = buffer; int i, j; - - host = scsi_host_hn_get(hostno); - - if (!host) return -ESRCH; if (inout) return length; diff -Nru a/drivers/scsi/fcal.h b/drivers/scsi/fcal.h --- a/drivers/scsi/fcal.h Mon Jun 9 23:16:05 2003 +++ b/drivers/scsi/fcal.h Mon Jun 9 23:16:05 2003 @@ -22,7 +22,6 @@ int fcal_detect(Scsi_Host_Template *); int fcal_release(struct Scsi_Host *); -int fcal_proc_info (char *, char **, off_t, int, int, int); int fcal_slave_configure(Scsi_Device *); #endif /* !(_FCAL_H) */ diff -Nru a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c --- a/drivers/scsi/fd_mcs.c Mon Jun 9 23:16:10 2003 +++ b/drivers/scsi/fd_mcs.c Mon Jun 9 23:16:10 2003 @@ -586,9 +586,8 @@ * length: If inout==FALSE max number of bytes to be written into the buffer * else number of bytes in the buffer */ -static int fd_mcs_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout) +static int fd_mcs_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start, off_t offset, int length, int inout) { - struct Scsi_Host *shpnt; int len = 0; int i; @@ -597,20 +596,10 @@ *start = buffer + offset; - for (i = 0; hosts[i] && hosts[i]->host_no != hostno; i++); - shpnt = hosts[i]; - - if (!shpnt) { - return (-ENOENT); - } else { - len += sprintf(buffer + len, "Future Domain MCS-600/700 Driver %s\n", DRIVER_VERSION); - - len += sprintf(buffer + len, "HOST #%d: %s\n", hostno, adapter_name); - - len += sprintf(buffer + len, "FIFO Size=0x%x, FIFO Count=%d\n", FIFO_Size, FIFO_COUNT); - - len += sprintf(buffer + len, "DriverCalls=%d, Interrupts=%d, BytesRead=%d, BytesWrite=%d\n\n", TOTAL_INTR, INTR_Processed, Bytes_Read, Bytes_Written); - } + len += sprintf(buffer + len, "Future Domain MCS-600/700 Driver %s\n", DRIVER_VERSION); + len += sprintf(buffer + len, "HOST #%d: %s\n", shpnt->host_no, adapter_name); + len += sprintf(buffer + len, "FIFO Size=0x%x, FIFO Count=%d\n", FIFO_Size, FIFO_COUNT); + len += sprintf(buffer + len, "DriverCalls=%d, Interrupts=%d, BytesRead=%d, BytesWrite=%d\n\n", TOTAL_INTR, INTR_Processed, Bytes_Read, Bytes_Written); if ((len -= offset) <= 0) return 0; diff -Nru a/drivers/scsi/fd_mcs.h b/drivers/scsi/fd_mcs.h --- a/drivers/scsi/fd_mcs.h Mon Jun 9 23:16:08 2003 +++ b/drivers/scsi/fd_mcs.h Mon Jun 9 23:16:08 2003 @@ -32,7 +32,6 @@ static int fd_mcs_queue(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); static int fd_mcs_biosparam(struct scsi_device *, struct block_device *, sector_t, int *); -static int fd_mcs_proc_info(char *, char **, off_t, int, int, int); static const char *fd_mcs_info(struct Scsi_Host *); #endif /* _FD_MCS_H */ diff -Nru a/drivers/scsi/fdomain.c b/drivers/scsi/fdomain.c --- a/drivers/scsi/fdomain.c Mon Jun 9 23:16:15 2003 +++ b/drivers/scsi/fdomain.c Mon Jun 9 23:16:15 2003 @@ -1068,45 +1068,6 @@ return buffer; } - /* First pass at /proc information routine. */ -/* - * inout : decides on the direction of the dataflow and the meaning of the - * variables - * buffer: If inout==FALSE data is being written to it else read from it - * *start: If inout==FALSE start of the valid data in the buffer - * offset: If inout==FALSE offset from the beginning of the imaginary file - * from which we start writing into the buffer - * length: If inout==FALSE max number of bytes to be written into the buffer - * else number of bytes in the buffer - */ -static int fdomain_16x0_proc_info( char *buffer, char **start, off_t offset, - int length, int hostno, int inout ) -{ - const char *info = fdomain_16x0_info( NULL ); - int len; - int pos; - int begin; - - if (inout) return(-EINVAL); - - begin = 0; - strcpy( buffer, info ); - strcat( buffer, "\n" ); - - pos = len = strlen( buffer ); - - if(pos < offset) { - len = 0; - begin = pos; - } - - *start = buffer + (offset - begin); /* Start of wanted data */ - len -= (offset - begin); - if(len > length) len = length; - - return(len); -} - #if 0 static int fdomain_arbitrate( void ) { @@ -1870,7 +1831,6 @@ .module = THIS_MODULE, .name = "fdomain", .proc_name = "fdomain", - .proc_info = fdomain_16x0_proc_info, .detect = fdomain_16x0_detect, .info = fdomain_16x0_info, .command = fdomain_16x0_command, diff -Nru a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c --- a/drivers/scsi/g_NCR5380.c Mon Jun 9 23:16:08 2003 +++ b/drivers/scsi/g_NCR5380.c Mon Jun 9 23:16:08 2003 @@ -770,14 +770,13 @@ * Locks: global cli/lock for queue walk */ -int generic_NCR5380_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout) +int generic_NCR5380_proc_info(struct Scsi_Host *scsi_ptr, char *buffer, char **start, off_t offset, int length, int inout) { int len = 0; NCR5380_local_declare(); unsigned long flags; unsigned char status; int i; - struct Scsi_Host *scsi_ptr; Scsi_Cmnd *ptr; struct NCR5380_hostdata *hostdata; #ifdef NCR5380_STATS @@ -785,9 +784,6 @@ extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE]; #endif - /* For now this is constant so we may walk it */ - scsi_ptr = scsi_host_hn_get(hostno); - NCR5380_setup(scsi_ptr); hostdata = (struct NCR5380_hostdata *) scsi_ptr->hostdata; diff -Nru a/drivers/scsi/g_NCR5380.h b/drivers/scsi/g_NCR5380.h --- a/drivers/scsi/g_NCR5380.h Mon Jun 9 23:16:05 2003 +++ b/drivers/scsi/g_NCR5380.h Mon Jun 9 23:16:05 2003 @@ -51,11 +51,8 @@ static int generic_NCR5380_bus_reset(Scsi_Cmnd *); static int generic_NCR5380_host_reset(Scsi_Cmnd *); static int generic_NCR5380_device_reset(Scsi_Cmnd *); -static int notyet_generic_proc_info (char *buffer ,char **start, off_t offset, - int length, int hostno, int inout); static const char* generic_NCR5380_info(struct Scsi_Host *); static int generic_NCR5380_biosparam(struct scsi_device *, struct block_device *, sector_t, int *); -static int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int length, int hostno, int inout); #ifndef CMD_PER_LUN #define CMD_PER_LUN 2 @@ -102,7 +99,7 @@ #define NCR5380_region_size 0x3a00 #define NCR5380_read(reg) isa_readb(NCR5380_map_name + NCR53C400_mem_base + (reg)) -#define NCR5380_write(reg, value) isa_writeb(NCR5380_map_name + NCR53C400_mem_base + (reg), value) +#define NCR5380_write(reg, value) isa_writeb(value, NCR5380_map_name + NCR53C400_mem_base + (reg)) #endif #define NCR5380_implementation_fields \ diff -Nru a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h --- a/drivers/scsi/gdth.h Mon Jun 9 23:16:10 2003 +++ b/drivers/scsi/gdth.h Mon Jun 9 23:16:10 2003 @@ -978,7 +978,7 @@ #if LINUX_VERSION_CODE >= 0x020501 int gdth_bios_param(struct scsi_device *,struct block_device *,sector_t,int *); -int gdth_proc_info(char *,char **,off_t,int,int,int); +int gdth_proc_info(struct Scsi_Host *, char *,char **,off_t,int,int); int gdth_eh_abort(Scsi_Cmnd *scp); int gdth_eh_device_reset(Scsi_Cmnd *scp); int gdth_eh_bus_reset(Scsi_Cmnd *scp); diff -Nru a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c --- a/drivers/scsi/gdth_proc.c Mon Jun 9 23:16:12 2003 +++ b/drivers/scsi/gdth_proc.c Mon Jun 9 23:16:12 2003 @@ -6,31 +6,24 @@ #include <linux/completion.h> #endif -int gdth_proc_info(char *buffer,char **start,off_t offset,int length, - int hostno,int inout) +int gdth_proc_info(struct Scsi_Host *host, char *buffer,char **start,off_t offset,int length, + int inout) { - int hanum,busnum,i; + int hanum,busnum; TRACE2(("gdth_proc_info() length %d ha %d offs %d inout %d\n", length,hostno,(int)offset,inout)); - for (i=0; i<gdth_ctr_vcount; ++i) { - if (gdth_ctr_vtab[i]->host_no == hostno) - break; - } - if (i==gdth_ctr_vcount) - return(-EINVAL); - - hanum = NUMDATA(gdth_ctr_vtab[i])->hanum; - busnum= NUMDATA(gdth_ctr_vtab[i])->busnum; + hanum = NUMDATA(host)->hanum; + busnum= NUMDATA(host)->busnum; if (inout) - return(gdth_set_info(buffer,length,i,hanum,busnum)); + return(gdth_set_info(buffer,length,hanum,busnum)); else - return(gdth_get_info(buffer,start,offset,length,i,hanum,busnum)); + return(gdth_get_info(buffer,start,offset,length,hanum,busnum)); } -static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum) +static int gdth_set_info(char *buffer,int length,int hanum,int busnum) { int ret_val = -EINVAL; #if LINUX_VERSION_CODE >= 0x020503 @@ -763,7 +756,7 @@ #endif static int gdth_get_info(char *buffer,char **start,off_t offset, - int length,int vh,int hanum,int busnum) + int length,int hanum,int busnum) { int size = 0,len = 0; off_t begin = 0,pos = 0; diff -Nru a/drivers/scsi/gdth_proc.h b/drivers/scsi/gdth_proc.h --- a/drivers/scsi/gdth_proc.h Mon Jun 9 23:16:15 2003 +++ b/drivers/scsi/gdth_proc.h Mon Jun 9 23:16:15 2003 @@ -5,9 +5,9 @@ * $Id: gdth_proc.h,v 1.13 2003/02/27 14:59:25 achim Exp $ */ -static int gdth_set_info(char *buffer,int length,int vh,int hanum,int busnum); +static int gdth_set_info(char *buffer,int length,int hanum,int busnum); static int gdth_get_info(char *buffer,char **start,off_t offset, - int length,int vh,int hanum,int busnum); + int length,int hanum,int busnum); #if LINUX_VERSION_CODE >= 0x020503 static void gdth_do_req(Scsi_Request *srp, gdth_cmd_str *cmd, diff -Nru a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c --- a/drivers/scsi/hosts.c Mon Jun 9 23:16:06 2003 +++ b/drivers/scsi/hosts.c Mon Jun 9 23:16:06 2003 @@ -216,6 +216,10 @@ scsi_proc_host_rm(shost); scsi_forget_host(shost); scsi_sysfs_remove_host(shost); + + if (shost->hostt->release) + (*shost->hostt->release)(shost); + return 0; } @@ -230,27 +234,18 @@ int scsi_add_host(struct Scsi_Host *shost, struct device *dev) { Scsi_Host_Template *sht = shost->hostt; - struct scsi_device *sdev; - int error = 0, saved_error = 0; + int error; printk(KERN_INFO "scsi%d : %s\n", shost->host_no, sht->info ? sht->info(shost) : sht->name); error = scsi_sysfs_add_host(shost, dev); - if (error) - return error; - - scsi_proc_host_add(shost); - - scsi_scan_host(shost); + if (!error) { + scsi_proc_host_add(shost); + scsi_scan_host(shost); + }; - list_for_each_entry (sdev, &shost->my_devices, siblings) { - error = scsi_attach_device(sdev); - if (error) - saved_error = error; - } - - return saved_error; + return error; } /** @@ -318,7 +313,12 @@ shost_tp->eh_host_reset_handler == NULL) { printk(KERN_ERR "ERROR: SCSI host `%s' has no error handling\nERROR: This is not a safe way to run your SCSI host\nERROR: The error handling must be added to this driver\n", shost_tp->proc_name); dump_stack(); - } + } + if(shost_tp->shost_attrs == NULL) + /* if its not set in the template, use the default */ + shost_tp->shost_attrs = scsi_sysfs_shost_attrs; + if(shost_tp->sdev_attrs == NULL) + shost_tp->sdev_attrs = scsi_sysfs_sdev_attrs; gfp_mask = GFP_KERNEL; if (shost_tp->unchecked_isa_dma && xtr_bytes) gfp_mask |= __GFP_DMA; @@ -491,60 +491,43 @@ } /** - * *scsi_host_get_next - get scsi host and inc ref count - * @shost: pointer to a Scsi_Host or NULL to start. + * scsi_host_lookup - get a reference to a Scsi_Host by host no + * + * @hostnum: host number to locate * * Return value: - * A pointer to next Scsi_Host in list or NULL. + * A pointer to located Scsi_Host or NULL. **/ -struct Scsi_Host *scsi_host_get_next(struct Scsi_Host *shost) +struct Scsi_Host *scsi_host_lookup(unsigned short hostnum) { - struct list_head *lh = NULL; - - spin_lock(&scsi_host_list_lock); - if (shost) { - /* XXX Dec ref on cur shost */ - lh = shost->sh_list.next; - } else { - lh = scsi_host_list.next; - } - - if (lh == &scsi_host_list) { - shost = (struct Scsi_Host *)NULL; - goto done; + struct class *class = class_get(&shost_class); + struct class_device *cdev; + struct Scsi_Host *shost = NULL, *p; + + if (class) { + down_read(&class->subsys.rwsem); + list_for_each_entry(cdev, &class->children, node) { + p = class_to_shost(cdev); + if (p->host_no == hostnum) { + scsi_host_get(p); + shost = p; + break; + } + } + up_read(&class->subsys.rwsem); } - shost = list_entry(lh, struct Scsi_Host, sh_list); - /* XXX Inc ref count */ - -done: - spin_unlock(&scsi_host_list_lock); return shost; } /** - * scsi_host_hn_get - get a Scsi_Host by host no and inc ref count - * @host_no: host number to locate - * - * Return value: - * A pointer to located Scsi_Host or NULL. - **/ -struct Scsi_Host *scsi_host_hn_get(unsigned short host_no) -{ - /* XXX Inc ref count */ - return scsi_find_host_by_num(host_no); -} - -/** * *scsi_host_get - inc a Scsi_Host ref count * @shost: Pointer to Scsi_Host to inc. **/ void scsi_host_get(struct Scsi_Host *shost) { - get_device(&shost->host_gendev); class_device_get(&shost->class_dev); - return; } /** @@ -556,7 +539,6 @@ class_device_put(&shost->class_dev); put_device(&shost->host_gendev); - return; } /** diff -Nru a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h --- a/drivers/scsi/hosts.h Mon Jun 9 23:16:09 2003 +++ b/drivers/scsi/hosts.h Mon Jun 9 23:16:09 2003 @@ -68,7 +68,7 @@ * outside the kernel ie. userspace and it also provides an interface * to feed the driver with information. Check eata_dma_proc.c for reference */ - int (*proc_info)(char *, char **, off_t, int, int, int); + int (*proc_info)(struct Scsi_Host *, char *, char **, off_t, int, int); /* * The name pointer is a pointer to the name of the SCSI @@ -356,6 +356,16 @@ * FIXME: This should probably be a value in the template */ #define SCSI_DEFAULT_HOST_BLOCKED 7 + /* + * pointer to the sysfs class properties for this host + */ + struct class_device_attribute **shost_attrs; + + /* + * Pointer to the SCSI device properties for this host + */ + struct device_attribute **sdev_attrs; + } Scsi_Host_Template; /* @@ -532,25 +542,23 @@ return shost->host_gendev.parent; } -struct Scsi_Device_Template -{ - struct list_head list; - const char * name; - struct module * module; /* Used for loadable modules */ - unsigned char scsi_type; - int (*attach)(Scsi_Device *); /* Attach devices to arrays */ - void (*detach)(Scsi_Device *); - int (*init_command)(Scsi_Cmnd *); /* Used by new queueing code. - Selects command for blkdevs */ - void (*rescan)(Scsi_Device *); - struct device_driver scsi_driverfs_driver; +struct scsi_driver { + struct module *owner; + struct device_driver gendrv; + + int (*init_command)(struct scsi_cmnd *); + void (*rescan)(struct device *); }; +#define to_scsi_driver(drv) \ + container_of((drv), struct scsi_driver, gendrv) -/* - * Highlevel driver registration/unregistration. - */ -extern int scsi_register_device(struct Scsi_Device_Template *); -extern int scsi_unregister_device(struct Scsi_Device_Template *); +extern int scsi_register_driver(struct device_driver *); +#define scsi_unregister_driver(drv) \ + driver_unregister(drv); + +extern int scsi_register_interface(struct class_interface *); +#define scsi_unregister_interface(intf) \ + class_interface_unregister(intf) /* * HBA allocation/freeing. @@ -570,9 +578,6 @@ extern int scsi_register_host(Scsi_Host_Template *); extern int scsi_unregister_host(Scsi_Host_Template *); -extern struct Scsi_Host *scsi_host_hn_get(unsigned short); -extern void scsi_host_put(struct Scsi_Host *); - /** * scsi_find_device - find a device given the host * @shost: SCSI host pointer @@ -590,5 +595,7 @@ return sdev; return NULL; } + +extern void scsi_sysfs_release_attributes(struct SHT *hostt); #endif diff -Nru a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c --- a/drivers/scsi/ibmmca.c Mon Jun 9 23:16:07 2003 +++ b/drivers/scsi/ibmmca.c Mon Jun 9 23:16:07 2003 @@ -2384,7 +2384,7 @@ } /* routine to display info in the proc-fs-structure (a deluxe feature) */ -static int ibmmca_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout) +static int ibmmca_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start, off_t offset, int length, int inout) { int len = 0; int i, id, lun, host_index; @@ -2392,13 +2392,13 @@ unsigned long flags; int max_pun; - for (i = 0; hosts[i] && hosts[i]->host_no != hostno; i++); + for (i = 0; hosts[i] && hosts[i] != shpnt; i++); spin_lock_irqsave(hosts[i]->host_lock, flags); /* Check it */ - shpnt = hosts[i]; host_index = i; if (!shpnt) { - len += sprintf(buffer + len, "\nIBM MCA SCSI: Can't find adapter for host number %d\n", hostno); + len += sprintf(buffer + len, "\nIBM MCA SCSI: Can't find adapter for host number %d\n", + shpnt->host_no); return len; } max_pun = subsystem_maxid(host_index); @@ -2411,7 +2411,7 @@ #else len += sprintf(buffer + len, " Multiple LUN probing.....: No\n"); #endif - len += sprintf(buffer + len, " This Hostnumber..........: %d\n", hostno); + len += sprintf(buffer + len, " This Hostnumber..........: %d\n", shpnt->host_no); len += sprintf(buffer + len, " Base I/O-Port............: 0x%x\n", (unsigned int) (IM_CMD_REG(host_index))); len += sprintf(buffer + len, " (Shared) IRQ.............: %d\n", IM_IRQ); len += sprintf(buffer + len, " Total Interrupts.........: %d\n", IBM_DS(host_index).total_interrupts); diff -Nru a/drivers/scsi/ibmmca.h b/drivers/scsi/ibmmca.h --- a/drivers/scsi/ibmmca.h Mon Jun 9 23:16:15 2003 +++ b/drivers/scsi/ibmmca.h Mon Jun 9 23:16:15 2003 @@ -11,7 +11,6 @@ /* Common forward declarations for all Linux-versions: */ /* Interfaces to the midlevel Linux SCSI driver */ -static int ibmmca_proc_info (char *, char **, off_t, int, int, int); static int ibmmca_detect (Scsi_Host_Template *); static int ibmmca_release (struct Scsi_Host *); static int ibmmca_command (Scsi_Cmnd *); diff -Nru a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c --- a/drivers/scsi/ide-scsi.c Mon Jun 9 23:16:15 2003 +++ b/drivers/scsi/ide-scsi.c Mon Jun 9 23:16:15 2003 @@ -771,6 +771,10 @@ static inline int should_transform(ide_drive_t *drive, Scsi_Cmnd *cmd) { idescsi_scsi_t *scsi = drive_to_idescsi(drive); + + /* this was a layering violation and we can't support it + anymore, sorry. */ +#if 0 struct gendisk *disk = cmd->request->rq_disk; if (disk) { @@ -778,6 +782,7 @@ if (strcmp((*p)->scsi_driverfs_driver.name, "sg") == 0) return test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform); } +#endif return test_bit(IDESCSI_TRANSFORM, &scsi->transform); } diff -Nru a/drivers/scsi/imm.c b/drivers/scsi/imm.c --- a/drivers/scsi/imm.c Mon Jun 9 23:16:19 2003 +++ b/drivers/scsi/imm.c Mon Jun 9 23:16:19 2003 @@ -253,14 +253,14 @@ return (-EINVAL); } -int imm_proc_info(char *buffer, char **start, off_t offset, - int length, int hostno, int inout) +int imm_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, + int length, int inout) { int i; int len = 0; for (i = 0; i < 4; i++) - if (imm_hosts[i].host == hostno) + if (imm_hosts[i].host == host->host_no) break; if (inout) diff -Nru a/drivers/scsi/imm.h b/drivers/scsi/imm.h --- a/drivers/scsi/imm.h Mon Jun 9 23:16:05 2003 +++ b/drivers/scsi/imm.h Mon Jun 9 23:16:05 2003 @@ -159,7 +159,7 @@ int imm_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); int imm_abort(Scsi_Cmnd *); int imm_reset(Scsi_Cmnd *); -int imm_proc_info(char *, char **, off_t, int, int, int); +int imm_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int); int imm_biosparam(struct scsi_device *, struct block_device *, sector_t, int *); diff -Nru a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c --- a/drivers/scsi/in2000.c Mon Jun 9 23:16:15 2003 +++ b/drivers/scsi/in2000.c Mon Jun 9 23:16:16 2003 @@ -2154,7 +2154,7 @@ } -static int in2000_proc_info(char *buf, char **start, off_t off, int len, int hn, int in) +static int in2000_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off, int len, int in) { #ifdef PROC_INTERFACE @@ -2162,17 +2162,11 @@ char *bp; char tbuf[128]; unsigned long flags; - struct Scsi_Host *instance; struct IN2000_hostdata *hd; Scsi_Cmnd *cmd; int x, i; static int stop = 0; - instance = scsi_host_hn_get(hn); - if (!instance) { - printk("*** Hmm... Can't find host #%d!\n", hn); - return (-ESRCH); - } hd = (struct IN2000_hostdata *) instance->hostdata; /* If 'in' is TRUE we need to _read_ the proc file. We accept the following diff -Nru a/drivers/scsi/in2000.h b/drivers/scsi/in2000.h --- a/drivers/scsi/in2000.h Mon Jun 9 23:16:05 2003 +++ b/drivers/scsi/in2000.h Mon Jun 9 23:16:05 2003 @@ -401,7 +401,6 @@ static int in2000_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); static int in2000_abort(Scsi_Cmnd *); static void in2000_setup(char *, int *) in2000__INIT; -static int in2000_proc_info(char *, char **, off_t, int, int, int); static int in2000_biosparam(struct scsi_device *, struct block_device *, sector_t, int *); static int in2000_host_reset(Scsi_Cmnd *); diff -Nru a/drivers/scsi/ips.c b/drivers/scsi/ips.c --- a/drivers/scsi/ips.c Mon Jun 9 23:16:05 2003 +++ b/drivers/scsi/ips.c Mon Jun 9 23:16:05 2003 @@ -488,7 +488,7 @@ static void ips_scmd_buf_write(Scsi_Cmnd *scmd, void *data, unsigned int count); static void ips_scmd_buf_read(Scsi_Cmnd *scmd, void *data, unsigned int count); -int ips_proc_info(char *, char **, off_t, int, int, int); +int ips_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int); static int ips_host_info(ips_ha_t *, char *, off_t, int); static void copy_mem_info(IPS_INFOSTR *, char *, int); static int copy_info(IPS_INFOSTR *, char *, ...); @@ -1496,8 +1496,8 @@ /* */ /****************************************************************************/ int -ips_proc_info(char *buffer, char **start, off_t offset, - int length, int hostno, int func) { +ips_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, + int length, int func) { int i; int ret; ips_ha_t *ha = NULL; @@ -1507,7 +1507,7 @@ /* Find our host structure */ for (i = 0; i < ips_next_controller; i++) { if (ips_sh[i]) { - if (ips_sh[i]->host_no == hostno) { + if (ips_sh[i] == host) { ha = (ips_ha_t *) ips_sh[i]->hostdata; break; } diff -Nru a/drivers/scsi/mac_NCR5380.c b/drivers/scsi/mac_NCR5380.c --- a/drivers/scsi/mac_NCR5380.c Mon Jun 9 23:16:17 2003 +++ b/drivers/scsi/mac_NCR5380.c Mon Jun 9 23:16:17 2003 @@ -740,7 +740,7 @@ printk("NCR5380_print_status: no memory for print buffer\n"); return; } - len = NCR5380_proc_info(pr_bfr, &start, 0, PAGE_SIZE, HOSTNO, 0); + len = NCR5380_proc_info(instance, pr_bfr, &start, 0, PAGE_SIZE, 0); pr_bfr[len] = 0; printk("\n%s\n", pr_bfr); free_page((unsigned long) pr_bfr); @@ -771,11 +771,10 @@ #ifndef NCR5380_proc_info static #endif -int NCR5380_proc_info (char *buffer, char **start, off_t offset, - int length, int hostno, int inout) +int NCR5380_proc_info (struct Scsi_Host *instance, char *buffer, char **start, off_t offset, + int length, int inout) { char *pos = buffer; - struct Scsi_Host *instance; struct NCR5380_hostdata *hostdata; Scsi_Cmnd *ptr; unsigned long flags; @@ -787,13 +786,6 @@ pos = buffer; \ } \ } while (0) - - for (instance = first_instance; instance && HOSTNO != hostno; - instance = instance->next) - ; - if (!instance) - return(-ESRCH); - hostdata = (struct NCR5380_hostdata *)instance->hostdata; if (inout) { /* Has data been written to the file ? */ return(-ENOSYS); /* Currently this is a no-op */ diff -Nru a/drivers/scsi/mac_scsi.h b/drivers/scsi/mac_scsi.h --- a/drivers/scsi/mac_scsi.h Mon Jun 9 23:16:14 2003 +++ b/drivers/scsi/mac_scsi.h Mon Jun 9 23:16:14 2003 @@ -32,9 +32,6 @@ #define MACSCSI_PUBLIC_RELEASE 2 #ifndef ASM -int macscsi_proc_info (char *buffer, char **start, off_t offset, - int length, int hostno, int inout); - #ifndef NULL #define NULL 0 #endif diff -Nru a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c --- a/drivers/scsi/megaraid.c Mon Jun 9 23:16:05 2003 +++ b/drivers/scsi/megaraid.c Mon Jun 9 23:16:05 2003 @@ -723,7 +723,7 @@ { dma_addr_t prod_info_dma_handle; mega_inquiry3 *inquiry3; - u8 raw_mbox[16]; + u8 raw_mbox[sizeof(mbox_t)]; mbox_t *mbox; int retval; @@ -732,7 +732,7 @@ mbox = (mbox_t *)raw_mbox; memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE); - memset(mbox, 0, 16); + memset(mbox, 0, sizeof(*mbox)); /* * Try to issue Inquiry3 command @@ -2392,21 +2392,6 @@ enquiry3->pdrv_state[i] = inquiry->pdrv_info.pdrv_state[i]; } - -/* - * megaraid_proc_info() - * - * Returns data to be displayed in /proc/scsi/megaraid/X - */ -static int -megaraid_proc_info(char *buffer, char **start, off_t offset, int length, - int host_no, int inout) -{ - *start = buffer; - return 0; -} - - /* * Release the controller's resources */ @@ -2415,7 +2400,7 @@ { adapter_t *adapter; mbox_t *mbox; - u_char raw_mbox[16]; + u_char raw_mbox[sizeof(mbox_t)]; char buf[12] = { 0 }; adapter = (adapter_t *)host->hostdata; @@ -2424,7 +2409,7 @@ printk(KERN_NOTICE "megaraid: being unloaded..."); /* Flush adapter cache */ - memset(mbox, 0, 16); + memset(mbox, 0, sizeof(*mbox)); raw_mbox[0] = FLUSH_ADAPTER; irq_disable(adapter); @@ -2434,7 +2419,7 @@ issue_scb_block(adapter, raw_mbox); /* Flush disks cache */ - memset(mbox, 0, 16); + memset(mbox, 0, sizeof(*mbox)); raw_mbox[0] = FLUSH_SYSTEM; /* Issue a blocking (interrupts disabled) command to the card */ @@ -3896,7 +3881,7 @@ { adapter_t *adapter; struct Scsi_Host *host; - u8 raw_mbox[16]; + u8 raw_mbox[sizeof(mbox_t)]; mbox_t *mbox; int i,j; @@ -3912,7 +3897,7 @@ mbox = (mbox_t *)raw_mbox; /* Flush adapter cache */ - memset(mbox, 0, 16); + memset(mbox, 0, sizeof(*mbox)); raw_mbox[0] = FLUSH_ADAPTER; irq_disable(adapter); @@ -3925,7 +3910,7 @@ issue_scb_block(adapter, raw_mbox); /* Flush disks cache */ - memset(mbox, 0, 16); + memset(mbox, 0, sizeof(*mbox)); raw_mbox[0] = FLUSH_SYSTEM; issue_scb_block(adapter, raw_mbox); @@ -4658,7 +4643,7 @@ static int mega_is_bios_enabled(adapter_t *adapter) { - unsigned char raw_mbox[16]; + unsigned char raw_mbox[sizeof(mbox_t)]; mbox_t *mbox; int ret; @@ -4691,7 +4676,7 @@ static void mega_enum_raid_scsi(adapter_t *adapter) { - unsigned char raw_mbox[16]; + unsigned char raw_mbox[sizeof(mbox_t)]; mbox_t *mbox; int i; @@ -4746,7 +4731,7 @@ mega_get_boot_drv(adapter_t *adapter) { struct private_bios_data *prv_bios_data; - unsigned char raw_mbox[16]; + unsigned char raw_mbox[sizeof(mbox_t)]; mbox_t *mbox; u16 cksum = 0; u8 *cksum_p; @@ -4812,7 +4797,7 @@ static int mega_support_random_del(adapter_t *adapter) { - unsigned char raw_mbox[16]; + unsigned char raw_mbox[sizeof(mbox_t)]; mbox_t *mbox; int rval; @@ -4841,7 +4826,7 @@ static int mega_support_ext_cdb(adapter_t *adapter) { - unsigned char raw_mbox[16]; + unsigned char raw_mbox[sizeof(mbox_t)]; mbox_t *mbox; int rval; @@ -4959,7 +4944,7 @@ static void mega_get_max_sgl(adapter_t *adapter) { - unsigned char raw_mbox[16]; + unsigned char raw_mbox[sizeof(mbox_t)]; mbox_t *mbox; mbox = (mbox_t *)raw_mbox; @@ -5004,7 +4989,7 @@ static int mega_support_cluster(adapter_t *adapter) { - unsigned char raw_mbox[16]; + unsigned char raw_mbox[sizeof(mbox_t)]; mbox_t *mbox; mbox = (mbox_t *)raw_mbox; @@ -5379,7 +5364,6 @@ static Scsi_Host_Template driver_template = { .name = "MegaRAID", - .proc_info = megaraid_proc_info, .detect = megaraid_detect, .release = megaraid_release, .info = megaraid_info, diff -Nru a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h --- a/drivers/scsi/megaraid.h Mon Jun 9 23:16:13 2003 +++ b/drivers/scsi/megaraid.h Mon Jun 9 23:16:13 2003 @@ -1007,7 +1007,6 @@ static int megaraid_abort_and_reset(adapter_t *, Scsi_Cmnd *, int); static int megaraid_biosparam(struct scsi_device *, struct block_device *, sector_t, int []); -static int megaraid_proc_info (char *, char **, off_t, int, int, int); static int mega_print_inquiry(char *, char *); static int mega_build_sglist (adapter_t *adapter, scb_t *scb, diff -Nru a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c --- a/drivers/scsi/ncr53c8xx.c Mon Jun 9 23:16:09 2003 +++ b/drivers/scsi/ncr53c8xx.c Mon Jun 9 23:16:09 2003 @@ -399,8 +399,8 @@ static irqreturn_t ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs); static void ncr53c8xx_timeout(unsigned long np); -static int ncr53c8xx_proc_info(char *buffer, char **start, off_t offset, - int length, int hostno, int func); +static int ncr53c8xx_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, + int length, int func); #define initverbose (driver_setup.verbose) #define bootverbose (np->verbose) @@ -9249,21 +9249,17 @@ ** - func = 1 means write (parse user control command) */ -static int ncr53c8xx_proc_info(char *buffer, char **start, off_t offset, - int length, int hostno, int func) +static int ncr53c8xx_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, + int length, int func) { - struct Scsi_Host *host; struct host_data *host_data; ncb_p ncb = 0; int retv; #ifdef DEBUG_PROC_INFO -printk("ncr53c8xx_proc_info: hostno=%d, func=%d\n", hostno, func); +printk("ncr53c8xx_proc_info: hostno=%d, func=%d\n", host->host_no, func); #endif - if((host = scsi_host_hn_get(hostno))==NULL) - return -EINVAL; - host_data = (struct host_data *) host->hostdata; ncb = host_data->ncb; diff -Nru a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c --- a/drivers/scsi/nsp32.c Mon Jun 9 23:16:10 2003 +++ b/drivers/scsi/nsp32.c Mon Jun 9 23:16:10 2003 @@ -278,15 +278,13 @@ /* * function declaration */ -static int nsp32_detect(Scsi_Host_Template *); static int nsp32_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); static const char *nsp32_info(struct Scsi_Host *); static int nsp32_eh_abort(Scsi_Cmnd *); static int nsp32_eh_bus_reset(Scsi_Cmnd *); static int nsp32_eh_host_reset(Scsi_Cmnd *); static int nsp32_reset(Scsi_Cmnd *, unsigned int); -static int nsp32_release(struct Scsi_Host *); -static int nsp32_proc_info(char *, char **, off_t, int, int, int); +static int nsp32_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int); static int __devinit nsp32_probe(struct pci_dev *, const struct pci_device_id *); static void __devexit nsp32_remove(struct pci_dev *); static int __init init_nsp32(void); @@ -335,11 +333,10 @@ /* * max_sectors is currently limited up to 128. */ -static Scsi_Host_Template driver_template = { - .proc_name = "nsp32", +static Scsi_Host_Template nsp32_template = { .name = "Workbit NinjaSCSI-32Bi/UDE", + .proc_name = "nsp32", .proc_info = nsp32_proc_info, - .detect = nsp32_detect, .info = nsp32_info, .queuecommand = nsp32_queuecommand, .can_queue = 1, @@ -352,12 +349,6 @@ .eh_device_reset_handler = NULL, .eh_bus_reset_handler = nsp32_eh_bus_reset, .eh_host_reset_handler = nsp32_eh_host_reset, - .release = nsp32_release, -#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,2)) - .use_new_eh_code = 1, -#else - /* .highmem_io = 1, */ -#endif }; #include "nsp32_io.h" @@ -1555,18 +1546,16 @@ #undef SPRINTF #define SPRINTF(args...) \ do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0) -static int nsp32_proc_info(char *buffer, +static int nsp32_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, - int hostno, int inout) { char *pos = buffer; int thislength; unsigned long flags; nsp32_hw_data *data; - struct Scsi_Host *host = NULL; unsigned int base; unsigned char mode_reg; @@ -1575,19 +1564,12 @@ return -EINVAL; } - /* search this HBA host */ - - host = scsi_host_hn_get(hostno); - - if (host == NULL) { - return -ESRCH; - } data = (nsp32_hw_data *)host->hostdata; base = host->io_port; SPRINTF("NinjaSCSI-32 status\n\n"); SPRINTF("Driver version: %s\n", nsp32_release_version); - SPRINTF("SCSI host No.: %d\n", hostno); + SPRINTF("SCSI host No.: %d\n", host->host_no); SPRINTF("IRQ: %d\n", host->irq); SPRINTF("IO: 0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1); SPRINTF("MMIO(virtual address): 0x%lx\n", host->base); @@ -1627,7 +1609,7 @@ * 0x900-0xbff: (map same 0x800-0x8ff I/O port image repeatedly) * 0xc00-0xfff: CardBus status registers */ -static int nsp32_detect(Scsi_Host_Template *sht) +static int nsp32_detect(struct pci_dev *pdev) { struct Scsi_Host *host; /* registered host structure */ int ret; @@ -1639,7 +1621,7 @@ /* * register this HBA as SCSI device */ - host = scsi_register(sht, sizeof(nsp32_hw_data)); + host = scsi_register(&nsp32_template, sizeof(nsp32_hw_data)); if (host == NULL) { nsp32_msg (KERN_ERR, "failed to scsi register"); goto err; @@ -1802,8 +1784,6 @@ "NinjaSCSI-32Bi/UDE: irq %d, io 0x%lx+0x%x", host->irq, host->io_port, host->n_io_port); - sht->name = data->info_str; - /* * SCSI bus reset * @@ -1841,7 +1821,9 @@ goto free_irq; } - return 1; + scsi_add_host(host, &pdev->dev); + pci_set_drvdata(pdev, host); + return 0; free_irq: free_irq(host->irq, data); @@ -1861,43 +1843,7 @@ scsi_unregister(host); err: - return 0; -} - -static int nsp32_release(struct Scsi_Host *shpnt) -{ - nsp32_hw_data *data = (nsp32_hw_data *)shpnt->hostdata; - - if (data->lunt_list) { - kfree(data->lunt_list); - } - - if (data->autoparam) { - pci_free_consistent(data->Pci, AUTOPARAM_SIZE, - data->autoparam, data->apaddr); - } - - if (data->sg_list) { - pci_free_consistent(data->Pci, - (sizeof(struct nsp32_sgtable) * NSP_SG_SIZE * MAX_TARGET * MAX_LUN), - data->sg_list, data->sgaddr); - } - - DEBUG(0, "free irq\n"); - if (shpnt->irq) { - free_irq(shpnt->irq, data); - } - - DEBUG(0, "free io\n"); - if (shpnt->io_port && shpnt->n_io_port) { - release_region(shpnt->io_port, shpnt->n_io_port); - } - - if (data->MmioAddress != 0) { - iounmap((void *)(data->MmioAddress)); - } - - return 0; + return 1; } static const char *nsp32_info(struct Scsi_Host *shpnt) @@ -2040,11 +1986,7 @@ pci_set_master(pdev); -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)) - scsi_register_host(&driver_template); -#else - scsi_register_module(MODULE_SCSI_HA, &driver_template); -#endif + ret = nsp32_detect(pdev); nsp32_msg(KERN_INFO, "nsp32 irq: %i mmio: 0x%lx slot: %s model: %s", pdev->irq, data->MmioAddress, pdev->slot_name, @@ -2052,18 +1994,23 @@ nsp32_dbg(NSP32_DEBUG_REGISTER, "exit"); - return 0; + return ret; } static void __devexit nsp32_remove(struct pci_dev *pdev) { - nsp32_dbg(NSP32_DEBUG_REGISTER, "enter"); - -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2)) - scsi_unregister_host(&driver_template); -#else - scsi_unregister_module(MODULE_SCSI_HA, &driver_template); -#endif + struct Scsi_Host *shpnt = pci_get_drvdata(pdev); + nsp32_hw_data *data = (nsp32_hw_data *)shpnt->hostdata; + + kfree(data->lunt_list); + pci_free_consistent(data->Pci, AUTOPARAM_SIZE, + data->autoparam, data->apaddr); + pci_free_consistent(data->Pci, + (sizeof(struct nsp32_sgtable) * NSP_SG_SIZE*MAX_TARGET*MAX_LUN), + data->sg_list, data->sgaddr); + free_irq(shpnt->irq, data); + release_region(shpnt->io_port, shpnt->n_io_port); + iounmap((void *)(data->MmioAddress)); } static struct pci_device_id nsp32_pci_table[] __devinitdata = { diff -Nru a/drivers/scsi/osst.c b/drivers/scsi/osst.c --- a/drivers/scsi/osst.c Mon Jun 9 23:16:11 2003 +++ b/drivers/scsi/osst.c Mon Jun 9 23:16:11 2003 @@ -160,19 +160,15 @@ static int osst_copy_to_buffer(OSST_buffer *, unsigned char *); static int osst_copy_from_buffer(OSST_buffer *, unsigned char *); -static int osst_attach(Scsi_Device *); -static void osst_detach(Scsi_Device *); +static int osst_probe(struct device *); +static int osst_remove(struct device *); -struct Scsi_Device_Template osst_template = -{ - .module = THIS_MODULE, - .list = LIST_HEAD_INIT(osst_template.list), - .name = "OnStream Tape", - .scsi_type = TYPE_TAPE, - .attach = osst_attach, - .detach = osst_detach, - .scsi_driverfs_driver = { - .name = "osst", +struct scsi_driver osst_template = { + .owner = THIS_MODULE, + .gendrv = { + .name = "osst", + .probe = osst_probe, + .remove = osst_remove, } }; @@ -5326,22 +5322,6 @@ #endif -/* Driverfs file support */ -static ssize_t osst_device_kdev_read(struct device *driverfs_dev, char *page) -{ - kdev_t kdev; - kdev.value=(int)(long)driverfs_dev->driver_data; - return sprintf(page, "%x\n",kdev.value); -} -static DEVICE_ATTR(kdev,S_IRUGO,osst_device_kdev_read,NULL); - -static ssize_t osst_device_type_read(struct device *driverfs_dev, char *page) -{ - return sprintf (page, "CHR\n"); -} -static DEVICE_ATTR(type,S_IRUGO,osst_device_type_read,NULL); - - static struct file_operations osst_fops = { .owner = THIS_MODULE, .read = osst_read, @@ -5384,8 +5364,9 @@ * osst startup / cleanup code */ -static int osst_attach(Scsi_Device * SDp) +static int osst_probe(struct device *dev) { + Scsi_Device * SDp = to_scsi_device(dev); OS_Scsi_Tape * tpnt; ST_mode * STm; ST_partstat * STps; @@ -5394,12 +5375,12 @@ int i, mode, dev_num; if (SDp->type != TYPE_TAPE || !osst_supports(SDp)) - return 1; + return -ENODEV; drive = alloc_disk(1); if (!drive) { printk(KERN_ERR "osst :E: Out of memory. Device not attached.\n"); - return 1; + return -ENODEV; } /* if this is the first attach, build the infrastructure */ @@ -5521,45 +5502,12 @@ write_unlock(&os_scsi_tapes_lock); for (mode = 0; mode < ST_NBR_MODES; ++mode) { - char name[8]; - /* Rewind entry */ - sprintf(name, "ot%s", osst_formats[mode]); - - sprintf(tpnt->driverfs_dev_r[mode].bus_id, "%s:%s", - SDp->sdev_driverfs_dev.bus_id, name); - sprintf(tpnt->driverfs_dev_r[mode].name, "%s%s", - SDp->sdev_driverfs_dev.name, name); - tpnt->driverfs_dev_r[mode].parent = &SDp->sdev_driverfs_dev; - tpnt->driverfs_dev_r[mode].bus = SDp->sdev_driverfs_dev.bus; - tpnt->driverfs_dev_r[mode].driver_data = - (void *)(long)__mkdev(OSST_MAJOR, dev_num + (mode << 5)); - device_register(&tpnt->driverfs_dev_r[mode]); - device_create_file(&tpnt->driverfs_dev_r[mode], - &dev_attr_type); - device_create_file(&tpnt->driverfs_dev_r[mode], &dev_attr_kdev); - 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 */ - sprintf (name, "ot%sn", osst_formats[mode]); - - sprintf(tpnt->driverfs_dev_n[mode].bus_id, "%s:%s", - SDp->sdev_driverfs_dev.bus_id, name); - sprintf(tpnt->driverfs_dev_n[mode].name, "%s%s", - SDp->sdev_driverfs_dev.name, name); - tpnt->driverfs_dev_n[mode].parent= &SDp->sdev_driverfs_dev; - tpnt->driverfs_dev_n[mode].bus = SDp->sdev_driverfs_dev.bus; - tpnt->driverfs_dev_n[mode].driver_data = - (void *)(long)__mkdev(OSST_MAJOR, dev_num + (mode << 5) + 128); - device_register(&tpnt->driverfs_dev_n[mode]); - device_create_file(&tpnt->driverfs_dev_n[mode], - &dev_attr_type); - device_create_file(&tpnt->driverfs_dev_n[mode], - &dev_attr_kdev); - 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]); @@ -5574,16 +5522,17 @@ out_put_disk: put_disk(drive); - return 1; + return -ENODEV; }; -static void osst_detach(Scsi_Device * SDp) +static int osst_remove(struct device *dev) { + Scsi_Device * SDp = to_scsi_device(dev); OS_Scsi_Tape * tpnt; int i, mode; if ((SDp->type != TYPE_TAPE) || (osst_nr_dev <= 0)) - return; + return 0; write_lock(&os_scsi_tapes_lock); for(i=0; i < osst_max_dev; i++) { @@ -5598,29 +5547,17 @@ os_scsi_tapes[i] = NULL; osst_nr_dev--; write_unlock(&os_scsi_tapes_lock); - for (mode = 0; mode < ST_NBR_MODES; ++mode) { - device_remove_file(&tpnt->driverfs_dev_r[mode], - &dev_attr_type); - device_remove_file(&tpnt->driverfs_dev_r[mode], - &dev_attr_kdev); - device_unregister(&tpnt->driverfs_dev_r[mode]); - device_remove_file(&tpnt->driverfs_dev_n[mode], - &dev_attr_type); - device_remove_file(&tpnt->driverfs_dev_n[mode], - &dev_attr_kdev); - device_unregister(&tpnt->driverfs_dev_n[mode]); - } if (tpnt->header_cache != NULL) vfree(tpnt->header_cache); if (tpnt->buffer) { normalize_buffer(tpnt->buffer); kfree(tpnt->buffer); } kfree(tpnt); - return; + return 0; } } write_unlock(&os_scsi_tapes_lock); - return; + return 0; } static int __init init_osst(void) @@ -5629,7 +5566,7 @@ validate_options(); - if ((register_chrdev(OSST_MAJOR,"osst", &osst_fops) < 0) || scsi_register_device(&osst_template)) { + if ((register_chrdev(OSST_MAJOR,"osst", &osst_fops) < 0) || scsi_register_driver(&osst_template.gendrv)) { printk(KERN_ERR "osst :E: Unable to register major %d for OnStream tapes\n", OSST_MAJOR); return 1; } @@ -5642,7 +5579,7 @@ int i; OS_Scsi_Tape * STp; - scsi_unregister_device(&osst_template); + scsi_unregister_driver(&osst_template.gendrv); unregister_chrdev(OSST_MAJOR, "osst"); if (os_scsi_tapes) { diff -Nru a/drivers/scsi/osst.h b/drivers/scsi/osst.h --- a/drivers/scsi/osst.h Mon Jun 9 23:16:15 2003 +++ b/drivers/scsi/osst.h Mon Jun 9 23:16:15 2003 @@ -530,7 +530,7 @@ /* The OnStream tape drive descriptor */ typedef struct { - struct Scsi_Device_Template *driver; + struct scsi_driver *driver; unsigned capacity; Scsi_Device* device; struct semaphore lock; /* for serialization */ @@ -555,8 +555,6 @@ /* Mode characteristics */ ST_mode modes[ST_NBR_MODES]; int current_mode; - struct device driverfs_dev_r[ST_NBR_MODES]; - struct device driverfs_dev_n[ST_NBR_MODES]; /* Status variables */ int partition; diff -Nru a/drivers/scsi/pas16.h b/drivers/scsi/pas16.h --- a/drivers/scsi/pas16.h Mon Jun 9 23:16:15 2003 +++ b/drivers/scsi/pas16.h Mon Jun 9 23:16:15 2003 @@ -122,8 +122,6 @@ static int pas16_bus_reset(Scsi_Cmnd *); static int pas16_host_reset(Scsi_Cmnd *); static int pas16_device_reset(Scsi_Cmnd *); -static int pas16_proc_info (char *buffer ,char **start, off_t offset, - int length, int hostno, int inout); #ifndef NULL #define NULL 0 diff -Nru a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c --- a/drivers/scsi/pcmcia/nsp_cs.c Mon Jun 9 23:16:19 2003 +++ b/drivers/scsi/pcmcia/nsp_cs.c Mon Jun 9 23:16:19 2003 @@ -1291,11 +1291,10 @@ #undef SPRINTF #define SPRINTF(args...) \ do { if(pos < buffer + length) pos += sprintf(pos, ## args); } while(0) -static int nsp_proc_info(char *buffer, +static int nsp_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, - int hostno, int inout) { int id; @@ -1304,29 +1303,14 @@ int speed; unsigned long flags; nsp_hw_data *data = &nsp_data; - struct Scsi_Host *host = NULL; if (inout) { return -EINVAL; } - /* search this HBA host */ -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,45)) - host = scsi_host_hn_get(hostno); -#else - for (host=scsi_hostlist; host; host=host->next) { - if (host->host_no == hostno) { - break; - } - } -#endif - if (host == NULL) { - return -ESRCH; - } - SPRINTF("NinjaSCSI status\n\n"); SPRINTF("Driver version: $Revision: 1.5 $\n"); - SPRINTF("SCSI host No.: %d\n", hostno); + SPRINTF("SCSI host No.: %d\n", host->host_no); SPRINTF("IRQ: %d\n", host->irq); SPRINTF("IO: 0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1); SPRINTF("MMIO(virtual address): 0x%lx\n", host->base); diff -Nru a/drivers/scsi/pcmcia/nsp_cs.h b/drivers/scsi/pcmcia/nsp_cs.h --- a/drivers/scsi/pcmcia/nsp_cs.h Mon Jun 9 23:16:10 2003 +++ b/drivers/scsi/pcmcia/nsp_cs.h Mon Jun 9 23:16:10 2003 @@ -281,8 +281,8 @@ static void nsp_start_timer(Scsi_Cmnd *SCpnt, nsp_hw_data *data, int time); static const char *nsp_info(struct Scsi_Host *shpnt); -static int nsp_proc_info(char *buffer, char **start, off_t offset, - int length, int hostno, int inout); +static int nsp_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, + int length, int inout); static int nsp_queuecommand(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *)); /*static int nsp_eh_abort(Scsi_Cmnd * SCpnt);*/ diff -Nru a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c --- a/drivers/scsi/ppa.c Mon Jun 9 23:16:14 2003 +++ b/drivers/scsi/ppa.c Mon Jun 9 23:16:14 2003 @@ -270,14 +270,14 @@ return (-EINVAL); } -int ppa_proc_info(char *buffer, char **start, off_t offset, - int length, int hostno, int inout) +int ppa_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, + int length, int inout) { int i; int len = 0; for (i = 0; i < 4; i++) - if (ppa_hosts[i].host == hostno) + if (ppa_hosts[i].host == host->host_no) break; if (inout) diff -Nru a/drivers/scsi/ppa.h b/drivers/scsi/ppa.h --- a/drivers/scsi/ppa.h Mon Jun 9 23:16:17 2003 +++ b/drivers/scsi/ppa.h Mon Jun 9 23:16:17 2003 @@ -167,7 +167,7 @@ int ppa_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); int ppa_abort(Scsi_Cmnd *); int ppa_reset(Scsi_Cmnd *); -int ppa_proc_info(char *, char **, off_t, int, int, int); +int ppa_proc_info(struct Scsi_Host *host, char *, char **, off_t, int, int); int ppa_biosparam(struct scsi_device *, struct block_device *, sector_t, int *); diff -Nru a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c --- a/drivers/scsi/qla1280.c Mon Jun 9 23:16:20 2003 +++ b/drivers/scsi/qla1280.c Mon Jun 9 23:16:20 2003 @@ -332,6 +332,23 @@ #define pci_dma_lo32(a) (a & 0xffffffff) #define pci_dma_hi32(a) 0 #endif +/* MACROS for managing the endian addresses */ +static inline uint16_t qla1280_addr0_15(dma_addr_t dma) +{ + return ((uint16_t)(dma & 0xffff)); +} +static inline uint16_t qla1280_addr16_31(dma_addr_t dma) +{ + return ((uint16_t)((dma >> 16) & 0xffff)); +} +static inline uint16_t qla1280_addr32_47(dma_addr_t dma) +{ + return ((uint16_t)(pci_dma_hi32(dma) & 0xffff)); +} +static inline uint16_t qla1280_addr48_63(dma_addr_t dma) +{ + return ((uint16_t)((pci_dma_hi32(dma) >> 16) & 0xffff)); +} #define NVRAM_DELAY() udelay(500) /* 2 microsecond delay */ @@ -442,6 +459,35 @@ static void qla12160_get_target_parameters(struct scsi_qla_host *, uint32_t, uint32_t, uint32_t); +/* convert scsi data direction to request_t control flags + */ +static inline uint16_t +qla1280_data_direction(struct scsi_cmnd *cmnd) +{ + uint16_t flags = 0; + + switch(cmnd->sc_data_direction) { + + case SCSI_DATA_NONE: + flags = 0; + break; + + case SCSI_DATA_READ: + flags = BIT_5; + break; + + case SCSI_DATA_WRITE: + flags = BIT_6; + break; + + case SCSI_DATA_UNKNOWN: + default: + flags = BIT_5 | BIT_6; + break; + } + return flags; +} + #if QL1280_LUN_SUPPORT static void qla1280_enable_lun(struct scsi_qla_host *, int, int); #endif @@ -623,11 +669,10 @@ #define PROC_BUF &qla1280_buffer[len] int -qla1280_proc_info(char *buffer, char **start, off_t offset, int length, - int hostno, int inout) +qla1280_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, + int inout) { #if QLA1280_PROFILE - struct Scsi_Host *host; struct scsi_qla_host *ha; int size = 0; scsi_lu_t *up; @@ -637,22 +682,9 @@ host = NULL; /* Find the host that was specified */ - for (ha = qla1280_hostlist; (ha != NULL) && ha->host->host_no != hostno; + for (ha = qla1280_hostlist; (ha != NULL) && ha->host != host; ha = ha->next) ; - /* if host wasn't found then exit */ - if (!ha) { - size = sprintf(buffer, "Can't find adapter for host " - "number %d\n", hostno); - if (size > length) { - return size; - } else { - return 0; - } - } - - host = ha->host; - if (inout == TRUE) { /* Has data been written to the file? */ printk(KERN_INFO "qla1280_proc: has data been written to the file.\n"); @@ -1226,280 +1258,36 @@ return 0; } -/************************************************************************** - * qla1200_abort - * Abort the speciifed SCSI command(s). - **************************************************************************/ -int -qla1280_abort(Scsi_Cmnd * cmd) -{ - struct scsi_qla_host *ha; - srb_t *sp; - struct Scsi_Host *host; - unsigned int bus, target, lun; - scsi_lu_t *q; - int return_status = SCSI_ABORT_SUCCESS; - int found = 0; - int i; - unsigned char *handle; - u16 data; - - ENTER("qla1280_abort"); - ha = (struct scsi_qla_host *)cmd->device->host->hostdata; - host = cmd->device->host; - - /* Get the SCSI request ptr */ - sp = (srb_t *)CMD_SP(cmd); - handle = CMD_HANDLE(cmd); - if (qla1280_verbose) - printk(KERN_ERR "scsi(%li): ABORT Command=0x%p, handle=0x%p\n", - ha->host_no, (void *) cmd, (void *) handle); - - /* Check for pending interrupts. */ - if (handle == NULL) { - /* we never got this command */ - printk(KERN_INFO "qla1280: Aborting a NULL handle\n"); - return SCSI_ABORT_NOT_RUNNING; /* no action - we don't have command */ - } - data = qla1280_debounce_register(&ha->iobase->istatus); - /* - * The io_request_lock is held when the reset handler is called, hence - * the interrupt handler cannot be running in parallel as it also - * grabs the lock. No reason to play funny games with set_bit() in - * order to test for interrupt handler entry as the driver used to - * do here. - * /Jes - */ - if (data & RISC_INT) { - /* put any pending command in done queue */ - qla1280_isr(ha, &ha->done_q_first, &ha->done_q_last); - } +typedef enum { + ABORT_COMMAND, + ABORT_DEVICE, + DEVICE_RESET, + BUS_RESET, + ADAPTER_RESET, + FAIL +} action_t; - /* - * This seems unnecessary, it's not used below! / Jes - */ -#ifdef UNUSED - handle = CMD_HANDLE(cmd); -#endif - - /* Generate LU queue on bus, target, LUN */ - bus = SCSI_BUS_32(cmd); - target = SCSI_TCN_32(cmd); - lun = SCSI_LUN_32(cmd); - if ((q = LU_Q(ha, bus, target, lun)) == NULL) { - /* No lun queue -- command must not be active */ - printk(KERN_WARNING "qla1280 (%d:%d:%d): No LUN queue for the " - "specified device\n", bus, target, lun); - return SCSI_ABORT_NOT_RUNNING; /* no action - we don't have command */ - } -#if AUTO_ESCALATE_ABORT - if ((sp->flags & SRB_ABORTED)) { - dprintk(1, "qla1280_abort: Abort escalayted - returning " - "SCSI_ABORT_SNOOZE.\n"); - return SCSI_ABORT_SNOOZE; - } -#endif - - if ((sp->flags & SRB_ABORT_PENDING)) { - if (qla1280_verbose) - printk(KERN_WARNING - "scsi(): Command has a pending abort " - "message - ABORT_PENDING.\n"); - - return SCSI_ABORT_PENDING; - } -#if STOP_ON_ABORT - printk(KERN_WARNING "Scsi layer issued a ABORT command= 0x%p\n", cmd); - qla1280_print_scsi_cmd(2, cmd); -#endif - - /* - * Normally, would would need to search our queue for the specified command - * but; since our sp contains the cmd ptr, we can just remove it from our - * LUN queue. - */ - if (!(sp->flags & SRB_SENT)) { - found++; - if (qla1280_verbose) - printk(KERN_WARNING - "scsi(): Command returned from queue " - "aborted.\n"); - - /* Remove srb from SCSI LU queue. */ - qla1280_removeq(q, sp); - sp->flags |= SRB_ABORTED; - CMD_RESULT(cmd) = DID_ABORT << 16; - qla1280_done_q_put(sp, &ha->done_q_first, &ha->done_q_last); - return_status = SCSI_ABORT_SUCCESS; - } else { /* find the command in our active list */ - for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) { - if (sp == ha->outstanding_cmds[i]) { - found++; - dprintk(1, - "qla1280: RISC aborting command.\n"); - qla1280_abort_command(ha, sp); - return_status = SCSI_ABORT_PENDING; - break; - } - } - } - -#if STOP_ON_ABORT - qla1280_panic("qla1280_abort", ha->host); -#endif - if (found == 0) - return_status = SCSI_ABORT_NOT_RUNNING; /* no action - we don't have command */ - - dprintk(1, "qla1280_abort: Aborted status returned = 0x%x.\n", - return_status); - - if (ha->done_q_first) - qla1280_done(ha, &ha->done_q_first, &ha->done_q_last); - if (found) - qla1280_restart_queues(ha); - - LEAVE("qla1280_abort"); - return return_status; -} - -int -qla1280_new_abort(Scsi_Cmnd * cmd) +/* timer action for error action processor */ +static void qla1280_error_wait_timeout(unsigned long __data) { - struct scsi_qla_host *ha; - srb_t *sp; - struct Scsi_Host *host; - int bus, target, lun; - scsi_lu_t *q; - unsigned long cpu_flags; - int return_status = SCSI_ABORT_SUCCESS; - int found = 0; - int i; - unsigned char *handle; - u16 data; - - ENTER("qla1280_abort"); - host = cmd->device->host; - ha = (struct scsi_qla_host *)host->hostdata; - - /* Get the SCSI request ptr */ - sp = (srb_t *) CMD_SP(cmd); - handle = CMD_HANDLE(cmd); - if (qla1280_verbose) - printk(KERN_ERR "scsi(%li): ABORT Command=0x%p, handle=0x%p\n", - ha->host_no, cmd, handle); - - /* Check for pending interrupts. */ - if (handle == NULL) { - /* we never got this command */ - printk(KERN_INFO "qla1280: Aborting a NULL handle\n"); - return SUCCESS; /* no action - we don't have command */ - } + struct scsi_cmnd *cmd = (struct scsi_cmnd *)__data; + srb_t *sp = (srb_t *)CMD_SP(cmd); - spin_lock_irqsave (ha->host->host_lock, cpu_flags); - data = qla1280_debounce_register(&ha->iobase->istatus); - /* - * We grab the host lock in the interrupt handler to - * prevent racing here. - * - * Then again, running the interrupt handler from here is somewhat - * questionable. - * /Jes - */ - if (data & RISC_INT) { - /* put any pending command in done queue */ - qla1280_isr(ha, &ha->done_q_first, &ha->done_q_last); - } - - /* Generate LU queue on bus, target, LUN */ - bus = SCSI_BUS_32(cmd); - target = SCSI_TCN_32(cmd); - lun = SCSI_LUN_32(cmd); - if ((q = LU_Q(ha, bus, target, lun)) == NULL) { - /* No lun queue -- command must not be active */ - printk(KERN_WARNING "qla1280 (%d:%d:%d): No LUN queue for the " - "specified device\n", bus, target, lun); - return_status = SUCCESS; /* no action - we don't have command */ - goto out; - } - - if ((sp->flags & SRB_ABORT_PENDING)) { - if (qla1280_verbose) - printk(KERN_WARNING - "scsi(): Command has a pending abort " - "message - ABORT_PENDING.\n"); - - return_status = SCSI_ABORT_PENDING; - goto out; - } -#if STOP_ON_ABORT - printk(KERN_WARNING "Scsi layer issued a ABORT command= 0x%p\n", cmd); - qla1280_print_scsi_cmd(2, cmd); -#endif - - /* - * Normally, would would need to search our queue for the specified command - * but; since our sp contains the cmd ptr, we can just remove it from our - * LUN queue. - */ - if (!(sp->flags & SRB_SENT)) { - found++; - if (qla1280_verbose) - printk(KERN_WARNING - "scsi(): Command returned from queue " - "aborted.\n"); - - /* Remove srb from SCSI LU queue. */ - qla1280_removeq(q, sp); - sp->flags |= SRB_ABORTED; - CMD_RESULT(cmd) = DID_ABORT << 16; - qla1280_done_q_put(sp, &ha->done_q_first, &ha->done_q_last); - return_status = SUCCESS; - } else { /* find the command in our active list */ - for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) { - if (sp == ha->outstanding_cmds[i]) { - found++; - dprintk(1, - "qla1280: RISC aborting command.\n"); - qla1280_abort_command(ha, sp); - return_status = SCSI_ABORT_PENDING; - break; - } - } - } - -#if STOP_ON_ABORT - qla1280_panic("qla1280_abort", ha->host); -#endif - if (found == 0) - return_status = SUCCESS; /* no action - we don't have the command */ - - dprintk(1, "qla1280_abort: Aborted status returned = 0x%x.\n", - return_status); - - if (ha->done_q_first) - qla1280_done(ha, &ha->done_q_first, &ha->done_q_last); - if (found) - qla1280_restart_queues(ha); - - out: - spin_unlock_irqrestore(ha->host->host_lock, cpu_flags); - - LEAVE("qla1280_abort"); - return return_status; + complete(sp->wait); } /************************************************************************** - * qla1200_reset - * The reset function will reset the SCSI bus and abort any executing - * commands. + * qla1200_error_action + * The function will attempt to perform a specified error action and + * wait for the results (or time out). * * Input: * cmd = Linux SCSI command packet of the command that cause the * bus reset. - * flags = SCSI bus reset option flags (see scsi.h) + * action = error action to take (see action_t) * * Returns: - * DID_RESET in cmd.host_byte of aborted command(s) + * SUCCESS or FAIL * * Note: * Resetting the bus always succeeds - is has to, otherwise the @@ -1508,36 +1296,34 @@ * the SCSI bus reset line. **************************************************************************/ int -qla1280_reset(Scsi_Cmnd * cmd, unsigned int flags) +qla1280_error_action(Scsi_Cmnd * cmd, action_t action) { struct scsi_qla_host *ha; int bus, target, lun; srb_t *sp; - typedef enum { - ABORT_DEVICE = 1, - DEVICE_RESET = 2, - BUS_RESET = 3, - ADAPTER_RESET = 4, - RESET_DELAYED = 5, - FAIL = 6 - } action_t; - action_t action = ADAPTER_RESET; - u16 data; + uint16_t data; + unsigned char *handle; scsi_lu_t *q; int result; + DECLARE_COMPLETION(wait); + struct timer_list timer; - ENTER("qla1280_reset"); + ENTER("qla1280_error_action"); if (qla1280_verbose) printk(KERN_INFO "scsi(): Resetting Cmnd=0x%p, Handle=0x%p, " - "flags=0x%x\n", cmd, CMD_HANDLE(cmd), flags); + "action=0x%x\n", cmd, CMD_HANDLE(cmd), action); + if (cmd == NULL) { printk(KERN_WARNING "(scsi?:?:?:?) Reset called with NULL Scsi_Cmnd " "pointer, failing.\n"); - return SCSI_RESET_SNOOZE; + LEAVE("qla1280_error_action"); + return FAIL; } + ha = (struct scsi_qla_host *)cmd->device->host->hostdata; sp = (srb_t *)CMD_SP(cmd); + handle = CMD_HANDLE(cmd); #if STOP_ON_RESET qla1280_panic("qla1280_reset", ha->host); @@ -1557,27 +1343,14 @@ * Determine the suggested action that the mid-level driver wants * us to perform. */ - if (CMD_HANDLE(cmd) == NULL) { - /* - * if mid-level driver called reset with a orphan SCSI_Cmnd - * (i.e. a command that's not pending), so perform the - * function specified. - */ - if (flags & SCSI_RESET_SUGGEST_HOST_RESET) - action = ADAPTER_RESET; - else - action = BUS_RESET; + if (handle == NULL) { + if(action == ABORT_COMMAND) { + /* we never got this command */ + printk(KERN_INFO "qla1280: Aborting a NULL handle\n"); + return SUCCESS; /* no action - we don't have command */ + } } else { - /* - * Mid-level driver has called reset with this SCSI_Cmnd and - * its pending. - */ - if (flags & SCSI_RESET_SUGGEST_HOST_RESET) - action = ADAPTER_RESET; - else if (flags & SCSI_RESET_SUGGEST_BUS_RESET) - action = BUS_RESET; - else - action = DEVICE_RESET; + sp->wait = &wait; } bus = SCSI_BUS_32(cmd); @@ -1585,36 +1358,67 @@ lun = SCSI_LUN_32(cmd); q = LU_Q(ha, bus, target, lun); -#if AUTO_ESCALATE_RESET - if ((action & DEVICE_RESET) && (q->q_flag & QLA1280_QRESET)) { - printk(KERN_INFO - "qla1280(%ld): Bus device reset already sent to " - "device, escalating.\n", ha->host_no); - action = BUS_RESET; - } - if ((action & DEVICE_RESET) && (sp->flags & SRB_ABORT_PENDING)) { - printk(KERN_INFO - "qla1280(%ld):Have already attempted to reach " - "device with abort device\n", ha->host_no); - printk(KERN_INFO "qla1280(%ld):message, will escalate to BUS " - "RESET.\n", ha->host_no); - action = BUS_RESET; - } -#endif - - /* - * By this point, we want to already know what we are going to do, - * so we only need to perform the course of action. - */ - result = SCSI_RESET_ERROR; + /* Overloading result. Here it means the success or fail of the + * *issue* of the action. When we return from the routine, it must + * mean the actual success or fail of the action */ + result = FAIL; switch (action) { case FAIL: break; - case RESET_DELAYED: - result = SCSI_RESET_PENDING; + case ABORT_COMMAND: + if (q == NULL) { + /* No lun queue -- command must not be active */ + printk(KERN_WARNING "qla1280 (%d:%d:%d): No LUN queue for the " + "specified device\n", bus, target, lun); + break; + } + if ((sp->flags & SRB_ABORT_PENDING)) { + printk(KERN_WARNING + "scsi(): Command has a pending abort " + "message - ABORT_PENDING.\n"); + /* This should technically be impossible since we + * now wait for abort completion */ + break; + } + + /* + * Normally, would would need to search our queue for + * the specified command but; since our sp contains + * the cmd ptr, we can just remove it from our LUN + * queue. + */ + if (!(sp->flags & SRB_SENT)) { + if (qla1280_verbose) + printk(KERN_WARNING + "scsi(): Command returned from queue " + "aborted.\n"); + + /* Remove srb from SCSI LU queue. */ + qla1280_removeq(q, sp); + sp->flags |= SRB_ABORTED; + CMD_RESULT(cmd) = DID_ABORT << 16; + qla1280_done_q_put(sp, &ha->done_q_first, &ha->done_q_last); + if (ha->done_q_first) + qla1280_done(ha, &ha->done_q_first, &ha->done_q_last); + + qla1280_restart_queues(ha); + + } else { /* find the command in our active list */ + int i; + + for (i = 1; i < MAX_OUTSTANDING_COMMANDS; i++) { + if (sp == ha->outstanding_cmds[i]) { + dprintk(1, + "qla1280: RISC aborting command.\n"); + qla1280_abort_command(ha, sp); + } + } + } break; + + case ABORT_DEVICE: ha->flags.in_reset = TRUE; if (qla1280_verbose) @@ -1623,7 +1427,7 @@ "command.\n", ha->host_no, bus, target, lun); qla1280_abort_queue_single(ha, bus, target, lun, DID_ABORT); if (qla1280_abort_device(ha, bus, target, lun) == 0) - result = SCSI_RESET_PENDING; + result = SUCCESS; break; case DEVICE_RESET: @@ -1636,7 +1440,7 @@ qla1280_abort_queue_single(ha, bus, target, lun, DID_ABORT); if (qla1280_device_reset(ha, bus, target) == 0) - result = SCSI_RESET_PENDING; + result = SUCCESS; q->q_flag |= QLA1280_QRESET; break; @@ -1651,24 +1455,12 @@ qla1280_abort_queue_single(ha, bus, target, lun, DID_RESET); qla1280_bus_reset(ha, bus); - /* - * The bus reset routine returns all the outstanding commands - * back with "DID_RESET" in the status field after a short - * delay by the firmware. If the mid-level time out the SCSI - * reset before our delay we may need to ignore it. - */ - /* result = SCSI_RESET_PENDING | SCSI_RESET_BUS_RESET; */ - result = SCSI_RESET_SUCCESS | SCSI_RESET_BUS_RESET; - /* - * Wheeeee!!! - */ - mdelay(4 * 1000); - barrier(); - if (flags & SCSI_RESET_SYNCHRONOUS) { - CMD_RESULT(cmd) = DID_BUS_BUSY << 16; - (*(cmd)->scsi_done)(cmd); - } - /* ha->reset_start = jiffies; */ + + /* wait 4 seconds */ + schedule_timeout(4*HZ); + + result = SUCCESS; + break; case ADAPTER_RESET: @@ -1688,7 +1480,7 @@ * mid-level code can expect completions momentitarily. */ if (qla1280_abort_isp(ha) == 0) - result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET; + result = SUCCESS; ha->flags.reset_active = FALSE; } @@ -1698,13 +1490,81 @@ qla1280_restart_queues(ha); ha->flags.in_reset = FALSE; + /* If we didn't manage to issue the action, or we have no + * command to wait for, exit here */ + if(result == FAIL || handle == NULL) + goto leave; + + /* set up a timer just in case we're really jammed */ + init_timer(&timer); + timer.expires = jiffies + 4*HZ; + timer.data = (unsigned long)cmd; + timer.function = qla1280_error_wait_timeout; + add_timer(&timer); + + /* wait for the action to complete (or the timer to expire) */ + spin_unlock_irq(ha->host->host_lock); + wait_for_completion(&wait); + del_timer_sync(&timer); + spin_lock_irq(ha->host->host_lock); + sp->wait = NULL; + + /* the only action we might get a fail for is abort */ + if(action == ABORT_COMMAND) { + if(sp->flags & SRB_ABORTED) + result = SUCCESS; + else + result = FAILED; + } + + leave: dprintk(1, "RESET returning %d\n", result); - LEAVE("qla1280_reset"); + LEAVE("qla1280_error_action"); return result; } /************************************************************************** + * qla1200_abort + * Abort the specified SCSI command(s). + **************************************************************************/ +int +qla1280_eh_abort(struct scsi_cmnd * cmd) +{ + return qla1280_error_action(cmd, ABORT_COMMAND); +} + +/************************************************************************** + * qla1200_device_reset + * Reset the specified SCSI device + **************************************************************************/ +int +qla1280_eh_device_reset(struct scsi_cmnd *cmd) +{ + return qla1280_error_action(cmd, DEVICE_RESET); +} + +/************************************************************************** + * qla1200_bus_reset + * Reset the specified bus. + **************************************************************************/ +int +qla1280_eh_bus_reset(struct scsi_cmnd *cmd) +{ + return qla1280_error_action(cmd, BUS_RESET); +} + +/************************************************************************** + * qla1200_adapter_reset + * Reset the specified adapter (both channels) + **************************************************************************/ +int +qla1280_eh_adapter_reset(struct scsi_cmnd *cmd) +{ + return qla1280_error_action(cmd, ADAPTER_RESET); +} + +/************************************************************************** * qla1280_biosparam * Return the disk geometry for the given SCSI device. **************************************************************************/ @@ -1934,6 +1794,9 @@ (*(cmd)->scsi_done)(cmd); + if(sp->wait != NULL) + complete(sp->wait); + qla1280_next(ha, q, bus); } LEAVE("qla1280_done"); @@ -2537,11 +2400,11 @@ dprintk(1, "qla1280_isp_firmware: Completed Reading NVRAM\n"); dprintk(3, "qla1280_isp_firmware: NVRAM Magic ID= %c %c %c\n", - (char *)nv->id[0], nv->id[1], nv->id[2]); + nv->id0, nv->id1, nv->id2); /* Bad NVRAM data, load RISC code. */ - if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || - nv->id[2] != 'P' || nv->id[3] != ' ' || nv->version < 1) { + if (chksum || nv->id0 != 'I' || nv->id1 != 'S' || + nv->id2 != 'P' || nv->id3 != ' ' || nv->version < 1) { printk(KERN_INFO "qla1280_isp_firmware: Bad checksum or magic " "number or version in NVRAM.\n"); ha->flags.disable_risc_code_load = FALSE; @@ -2791,7 +2654,7 @@ * Returns: * 0 = success. */ -#define DUMP_IT_BACK 0 /* for debug of RISC loading */ +#define DUMP_IT_BACK 1 /* for debug of RISC loading */ static int qla1280_setup_chip(struct scsi_qla_host *ha) { @@ -2806,11 +2669,7 @@ int i; uint8_t *sp; uint8_t *tbuf; -#ifdef QLA_64BIT_PTR dma_addr_t p_tbuf; -#else - uint32_t p_tbuf; -#endif #endif ENTER("qla1280_setup_chip"); @@ -2831,6 +2690,8 @@ num = 0; while (risc_code_size > 0 && !status) { + int warn __attribute__((unused)) = 0; + cnt = 2000 >> 1; if (cnt > risc_code_size) @@ -2839,20 +2700,22 @@ dprintk(1, "qla1280_setup_chip: loading risc @ =(0x%p)," "%d,%d(0x%x)\n", risc_code_address, cnt, num, risc_address); - memcpy(ha->request_ring, risc_code_address, (cnt << 1)); + for(i = 0; i < cnt; i++) + ((uint16_t *)ha->request_ring)[i] = + cpu_to_le16(risc_code_address[i]); flush_cache_all(); mb[0] = MBC_LOAD_RAM; mb[1] = risc_address; mb[4] = cnt; - mb[3] = ha->request_dma & 0xffff; - mb[2] = (ha->request_dma >> 16) & 0xffff; - mb[7] = pci_dma_hi32(ha->request_dma) & 0xffff; - mb[6] = pci_dma_hi32(ha->request_dma) >> 16; + mb[3] = qla1280_addr0_15(ha->request_dma); + mb[2] = qla1280_addr16_31(ha->request_dma); + mb[7] = qla1280_addr32_47(ha->request_dma); + mb[6] = qla1280_addr48_63(ha->request_dma); dprintk(1, "qla1280_setup_chip: op=%d 0x%p = 0x%4x,0x%4x," "0x%4x,0x%4x\n", - mb[0], ha->request_dma, mb[6], mb[7], mb[2], mb[3]); + mb[0], (void *)ha->request_dma, mb[6], mb[7], mb[2], mb[3]); if ((status = qla1280_mailbox_command(ha, BIT_4 | BIT_3 | BIT_2 | BIT_1 | BIT_0, &mb[0]))) { @@ -2860,14 +2723,15 @@ "Failed to load partial segment of f/w\n"); break; } + #if DUMP_IT_BACK - mb[0] = MBC_READ_RAM_WORD; + mb[0] = MBC_DUMP_RAM; mb[1] = risc_address; mb[4] = cnt; - mb[3] = p_tbuf & 0xffff; - mb[2] = (p_tbuf >> 16) & 0xffff; - mb[7] = pci_dma_hi32(p_tbuf) & 0xffff; - mb[6] = pci_dma_hi32(p_tbuf) >> 16; + mb[3] = qla1280_addr0_15(p_tbuf); + mb[2] = qla1280_addr16_31(p_tbuf); + mb[7] = qla1280_addr32_47(p_tbuf); + mb[6] = qla1280_addr48_63(p_tbuf); if ((status = qla1280_mailbox_command(ha, BIT_4 | BIT_3 | BIT_2 | @@ -2879,7 +2743,7 @@ } sp = (uint8_t *)ha->request_ring; for (i = 0; i < (cnt << 1); i++) { - if (tbuf[i] != sp[i]) { + if (tbuf[i] != sp[i] &&warn++ < 10) { printk(KERN_ERR "qla1280_setup_chip: FW " "compare error @ byte(0x%x) loop#=%x\n", i, num); @@ -3044,8 +2908,8 @@ #endif /* Bad NVRAM data, set defaults parameters. */ - if (chksum || nv->id[0] != 'I' || nv->id[1] != 'S' || - nv->id[2] != 'P' || nv->id[3] != ' ' || nv->version < 1) { + if (chksum || nv->id0 != 'I' || nv->id1 != 'S' || + nv->id2 != 'P' || nv->id3 != ' ' || nv->version < 1) { #if USE_NVRAM_DEFAULTS dprintk(1, "Using defaults for NVRAM\n"); #else @@ -3262,14 +3126,14 @@ ha->device_id == PCI_DEVICE_ID_QLOGIC_ISP10160) { nvram160_t *nv2 = (nvram160_t *) nv; mb[2] |= - nv2->bus[bus].target[target].flags. + nv2->bus[bus].target[target].flags2. enable_ppr << 5; mb[6] = - nv2->bus[bus].target[target].flags. + nv2->bus[bus].target[target].flags2. ppr_options << 8; mb[6] |= - nv2->bus[bus].target[target].flags. + nv2->bus[bus].target[target].flags2. ppr_bus_width; mr |= BIT_6; } @@ -3885,13 +3749,13 @@ pkt->entry_type = COMMAND_A64_TYPE; pkt->entry_count = (uint8_t) req_cnt; pkt->sys_define = (uint8_t) ha->req_ring_index; - pkt->handle = (uint32_t) cnt; + pkt->handle = cpu_to_le32(cnt); /* Zero out remaining portion of packet. */ memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8)); /* Set ISP command timeout. */ - pkt->timeout = 30; + pkt->timeout = cpu_to_le16(30); /* Set device target ID and LUN */ pkt->lun = SCSI_LUN_32(cmd); @@ -3900,28 +3764,24 @@ /* Enable simple tag queuing if device supports it. */ if (cmd->device->tagged_queue) - pkt->control_flags |= BIT_3; + pkt->control_flags |= cpu_to_le16(BIT_3); /* Load SCSI command packet. */ - pkt->cdb_len = (uint16_t)CMD_CDBLEN(cmd); - memcpy(pkt->scsi_cdb, &(CMD_CDBP(cmd)), pkt->cdb_len); + pkt->cdb_len = cpu_to_le16(CMD_CDBLEN(cmd)); + memcpy(pkt->scsi_cdb, &(CMD_CDBP(cmd)), CMD_CDBLEN(cmd)); /* dprintk(1, "Build packet for command[0]=0x%x\n",pkt->scsi_cdb[0]); */ + /* Set transfer direction. */ + sp->dir = qla1280_data_direction(cmd); + pkt->control_flags |= cpu_to_le16(sp->dir); + + /* Set total data segment count. */ + pkt->dseg_count = cpu_to_le16(seg_cnt); + /* * Load data segments. */ if (seg_cnt) { /* If data transfer. */ - /* Set transfer direction. */ - if ((cmd->data_cmnd[0] == WRITE_6)) - pkt->control_flags |= BIT_6; - else - pkt->control_flags |= (BIT_5 | BIT_6); - - sp->dir = pkt->control_flags & (BIT_5 | BIT_6); - - /* Set total data segment count. */ - pkt->dseg_count = seg_cnt; - /* Setup packet address segment pointer. */ dword_ptr = (u32 *)&pkt->dseg_0_address; @@ -4198,13 +4058,13 @@ pkt->entry_type = COMMAND_TYPE; pkt->entry_count = (uint8_t) req_cnt; pkt->sys_define = (uint8_t) ha->req_ring_index; - pkt->handle = (uint32_t) cnt; + pkt->handle = cpu_to_le32(cnt); /* Zero out remaining portion of packet. */ memset(((char *)pkt + 8), 0, (REQUEST_ENTRY_SIZE - 8)); /* Set ISP command timeout. */ - pkt->timeout = 30; + pkt->timeout = cpu_to_le16(30); /* Set device target ID and LUN */ pkt->lun = SCSI_LUN_32(cmd); @@ -4213,35 +4073,24 @@ /* Enable simple tag queuing if device supports it. */ if (cmd->device->tagged_queue) - pkt->control_flags |= BIT_3; + pkt->control_flags |= cpu_to_le16(BIT_3); /* Load SCSI command packet. */ - pkt->cdb_len = (uint16_t) CMD_CDBLEN(cmd); - memcpy(pkt->scsi_cdb, &(CMD_CDBP(cmd)), pkt->cdb_len); + pkt->cdb_len = cpu_to_le16(CMD_CDBLEN(cmd)); + memcpy(pkt->scsi_cdb, &(CMD_CDBP(cmd)), CMD_CDBLEN(cmd)); /*dprintk(1, "Build packet for command[0]=0x%x\n",pkt->scsi_cdb[0]); */ + /* Set transfer direction. */ + sp->dir = qla1280_data_direction(cmd); + pkt->control_flags |= cpu_to_le16(sp->dir); + + /* Set total data segment count. */ + pkt->dseg_count = cpu_to_le16(seg_cnt); + /* * Load data segments. */ if (seg_cnt) { - /* Set transfer direction (READ and WRITE) */ - /* Linux doesn't tell us */ - /* - * For block devices, cmd->request->cmd has the operation - * For character devices, this isn't always set properly, so - * we need to check data_cmnd[0]. This catches the conditions - * for st.c, but not sg. Generic commands are pass down to us. - */ - if ((cmd->data_cmnd[0] == WRITE_6)) - pkt->control_flags |= BIT_6; - else - pkt->control_flags |= (BIT_5 | BIT_6); - - sp->dir = pkt->control_flags & (BIT_5 | BIT_6); - - /* Set total data segment count. */ - pkt->dseg_count = seg_cnt; - /* Setup packet address segment pointer. */ dword_ptr = &pkt->dseg_0_address; @@ -4258,7 +4107,7 @@ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) *dword_ptr++ = cpu_to_le32(virt_to_bus(sg->address)); - *dword_ptr++ = sg->length; + *dword_ptr++ = cpu_to_le32(sg->length); dprintk(1, "S/G Segment phys_addr=0x%x, len=0x%x\n", cpu_to_le32(virt_to_bus(sg->address)), @@ -4269,8 +4118,8 @@ *dword_ptr++ = cpu_to_le32(sg_dma_len(sg)); dprintk(1, "S/G Segment phys_addr=0x%x, len=0x%x\n", - cpu_to_le32(pci_dma_lo32(sg_dma_address(sg))), - cpu_to_le32(sg_dma_len(sg))); + (pci_dma_lo32(sg_dma_address(sg))), + (sg_dma_len(sg))); #endif sg++; } @@ -4321,7 +4170,7 @@ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,18) *dword_ptr++ = cpu_to_le32(virt_to_bus(sg->address)); - *dword_ptr++ = sg->length; + *dword_ptr++ = cpu_to_le32(sg->length); dprintk(1, "S/G Segment Cont. phys_addr=0x%x, len=0x%x\n", cpu_to_le32(pci_dma_lo32(virt_to_bus(sg->address))), sg->length); @@ -4366,13 +4215,15 @@ cpu_to_le32(pci_dma_lo32(dma_handle)); #endif *dword_ptr = - (uint32_t)cmd->request_bufflen; + cpu_to_le32(cmd->request_bufflen); + qla1280_dump_buffer(1,(char *)pkt, + REQUEST_ENTRY_SIZE); } } else { /* No data transfer at all */ - dword_ptr = (uint32_t *)(pkt + 1); - *dword_ptr++ = 0; - *dword_ptr = 0; + //dword_ptr = (uint32_t *)(pkt + 1); + //*dword_ptr++ = 0; + //*dword_ptr = 0; dprintk(5, "qla1280_32bit_start_scsi: No data, command " "packet data - \n"); @@ -4543,12 +4394,12 @@ if (pkt = (elun_entry_t *)qla1280_req_pkt(ha)) { pkt->entry_type = ENABLE_LUN_TYPE; - pkt->lun = (uint16_t)(bus ? lun | BIT_15 : lun); + pkt->lun = cpu_to_le16(bus ? lun | BIT_15 : lun); pkt->command_count = 32; pkt->immed_notify_count = 1; pkt->group_6_length = MAX_CMDSZ; pkt->group_7_length = MAX_CMDSZ; - pkt->timeout = 0x30; + pkt->timeout = cpu_to_le16(0x30); qla1280_isp_cmd(ha); } @@ -4593,7 +4444,7 @@ if (inotify->seq_id == 0) pkt->event = BIT_7; else - pkt->seq_id = inotify->seq_id; + pkt->seq_id = cpu_to_le16(inotify->seq_id); /* Issue command to ISP */ qla1280_isp_cmd(ha); @@ -4697,17 +4548,17 @@ pkt->lun = atio->lun; pkt->initiator_id = atio->initiator_id; pkt->target_id = atio->target_id; - pkt->option_flags = atio->option_flags; + pkt->option_flags = cpu_to_le32(atio->option_flags); pkt->tag_value = atio->tag_value; pkt->scsi_status = atio->scsi_status; if (len) { - pkt->dseg_count = 1; - pkt->transfer_length = len; - pkt->dseg_0_length = len; + pkt->dseg_count = cpu_to_le16(1); + pkt->transfer_length = cpu_to_le32(len); + pkt->dseg_0_length = cpu_to_le32(len); dword_ptr = (uint32_t *) addr; - pkt->dseg_0_address[0] = *dword_ptr++; - pkt->dseg_0_address[1] = *dword_ptr; + pkt->dseg_0_address[0] = cpu_to_le32(*dword_ptr++); + pkt->dseg_0_address[1] = cpu_to_le32(*dword_ptr); } /* Issue command to ISP */ @@ -4745,16 +4596,16 @@ pkt->lun = atio->lun; pkt->initiator_id = atio->initiator_id; pkt->target_id = atio->target_id; - pkt->option_flags = atio->option_flags; + pkt->option_flags = cpu_to_le32(atio->option_flags); pkt->tag_value = atio->tag_value; pkt->scsi_status = atio->scsi_status; if (len) { - pkt->dseg_count = 1; - pkt->transfer_length = len; - pkt->dseg_0_length = len; - dword_ptr = (uint32_t *) addr; - pkt->dseg_0_address = *dword_ptr; + pkt->dseg_count = cpu_to_le16(1); + pkt->transfer_length = cpu_to_le32(len); + pkt->dseg_0_length = cpu_to_le32(len); + dword_ptr = (uint32_t *)addr; + pkt->dseg_0_address = cpu_to_le32(*dword_ptr); } /* Issue command to ISP */ @@ -4967,7 +4818,7 @@ RESPONSE_ENTRY_SIZE); if (pkt->entry_type == STATUS_TYPE) { - if ((pkt->scsi_status & 0xff) + if ((le16_to_cpu(pkt->scsi_status) & 0xff) || pkt->comp_status || pkt->entry_status) { dprintk(2, @@ -4976,8 +4827,8 @@ "scsi_status = 0x%x\n", ha->rsp_ring_index, mailbox[5], - pkt->comp_status, - pkt->scsi_status); + le16_to_cpu(pkt->comp_status), + le16_to_cpu(pkt->scsi_status)); } } else { dprintk(2, @@ -5169,7 +5020,7 @@ *(sense_ptr + 12) = SC_SELFAIL; } pkt->scsi_status = S_CKCON; - pkt->option_flags |= OF_SSTS | OF_NO_DATA; + pkt->option_flags |= cpu_to_le32(OF_SSTS | OF_NO_DATA); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,18) if (ha->flags.enable_64bit_addressing) @@ -5212,7 +5063,7 @@ pkt->scsi_status = S_CKCON; } - pkt->option_flags |= (OF_SSTS | OF_NO_DATA); + pkt->option_flags |= cpu_to_le32(OF_SSTS | OF_NO_DATA); break; case SS_REQSEN: @@ -5226,7 +5077,7 @@ else len = pkt->cdb[4]; pkt->scsi_status = S_GOOD; - pkt->option_flags |= (OF_SSTS | OF_DATA_IN); + pkt->option_flags |= cpu_to_le32(OF_SSTS | OF_DATA_IN); break; case SS_INQUIR: @@ -5250,7 +5101,7 @@ else len = pkt->cdb[4]; pkt->scsi_status = S_GOOD; - pkt->option_flags |= (OF_SSTS | OF_DATA_IN); + pkt->option_flags |= cpu_to_le32(OF_SSTS | OF_DATA_IN); break; case SM_WRDB: @@ -5281,12 +5132,12 @@ *(sense_ptr + 12) = SC_ILLCDB; pkt->scsi_status = S_CKCON; pkt->option_flags |= - (OF_SSTS | OF_NO_DATA); + cpu_to_le32(OF_SSTS | OF_NO_DATA); len = 0; } else if (len) { pkt->scsi_status = S_GOOD; pkt->option_flags |= - (OF_SSTS | OF_DATA_OUT); + cpu_to_le32(OF_SSTS | OF_DATA_OUT); dprintk(3, "qla1280_atio_entry: Issuing " "SDI_TARMOD_WRCOMP\n"); @@ -5301,7 +5152,7 @@ pkt->scsi_status = S_GOOD; pkt->option_flags |= - (OF_SSTS | OF_NO_DATA); + cpu_to_le32(OF_SSTS | OF_NO_DATA); } break; @@ -5327,11 +5178,11 @@ len = 0; pkt->scsi_status = S_CKCON; pkt->option_flags |= - (OF_SSTS | OF_NO_DATA); + cpu_to_le32(OF_SSTS | OF_NO_DATA); } else if (len) { pkt->scsi_status = S_GOOD; pkt->option_flags |= - (OF_SSTS | OF_DATA_OUT); + cpu_to_le32(OF_SSTS | OF_DATA_OUT); dprintk(3, "qla1280_atio_entry: Issuing " "SDI_TARMOD_WRCOMP\n"); @@ -5346,7 +5197,7 @@ pkt->scsi_status = S_GOOD; pkt->option_flags |= - (OF_SSTS | OF_NO_DATA); + cpu_to_le32(OF_SSTS | OF_NO_DATA); } break; @@ -5360,7 +5211,7 @@ *(sense_ptr + 12) = SC_ILLCDB; len = 0; pkt->scsi_status = S_CKCON; - pkt->option_flags |= (OF_SSTS | OF_NO_DATA); + pkt->option_flags |= cpu_to_le32(OF_SSTS | OF_NO_DATA); break; } break; @@ -5393,7 +5244,7 @@ len = TARGET_DATA_SIZE + 4; pkt->scsi_status = S_GOOD; pkt->option_flags |= - (OF_SSTS | OF_DATA_IN); + cpu_to_le32(OF_SSTS | OF_DATA_IN); } else { dprintk(2, "qla1280_atio_entry: SM_RDDB, " @@ -5401,7 +5252,7 @@ pkt->scsi_status = S_GOOD; pkt->option_flags |= - (OF_SSTS | OF_NO_DATA); + cpu_to_le32(OF_SSTS | OF_NO_DATA); } break; case RW_BUF_DATA: @@ -5424,7 +5275,7 @@ len = 0; pkt->scsi_status = S_CKCON; pkt->option_flags |= - (OF_SSTS | OF_NO_DATA); + cpu_to_le32(OF_SSTS | OF_NO_DATA); } else { if (*a64 + len > *end_a64) len = *end_a64 - *a64; @@ -5439,7 +5290,7 @@ pkt->scsi_status = S_GOOD; pkt->option_flags |= - (OF_SSTS | OF_NO_DATA); + cpu_to_le32(OF_SSTS | OF_NO_DATA); } } break; @@ -5468,7 +5319,7 @@ } pkt->scsi_status = S_GOOD; pkt->option_flags |= - (OF_SSTS | OF_DATA_IN); + cpu_to_le32(OF_SSTS | OF_DATA_IN); } else { dprintk(2, "qla1280_atio_entry: SM_RDDB," @@ -5476,7 +5327,7 @@ pkt->scsi_status = S_GOOD; pkt->option_flags |= - (OF_SSTS | OF_NO_DATA); + cpu_to_le32(OF_SSTS | OF_NO_DATA); } break; default: @@ -5489,7 +5340,7 @@ *(sense_ptr + 12) = SC_ILLCDB; len = 0; pkt->scsi_status = S_CKCON; - pkt->option_flags |= (OF_SSTS | OF_NO_DATA); + pkt->option_flags |= cpu_to_le32(OF_SSTS | OF_NO_DATA); break; } break; @@ -5506,7 +5357,7 @@ *(sense_ptr + 12) = SC_INVOPCODE; len = 0; pkt->scsi_status = S_CKCON; - pkt->option_flags |= (OF_SSTS | OF_NO_DATA); + pkt->option_flags |= cpu_to_le32(OF_SSTS | OF_NO_DATA); break; } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,18) @@ -5568,18 +5419,21 @@ srb_t *sp; scsi_lu_t *q; Scsi_Cmnd *cmd; + uint32_t handle = le32_to_cpu(pkt->handle); + uint16_t scsi_status = le16_to_cpu(pkt->scsi_status); + uint16_t comp_status = le16_to_cpu(pkt->comp_status); ENTER("qla1280_status_entry"); /* Validate handle. */ - if (pkt->handle < MAX_OUTSTANDING_COMMANDS) - sp = ha->outstanding_cmds[pkt->handle]; + if (handle < MAX_OUTSTANDING_COMMANDS) + sp = ha->outstanding_cmds[handle]; else sp = 0; if (sp) { /* Free outstanding command slot. */ - ha->outstanding_cmds[pkt->handle] = 0; + ha->outstanding_cmds[handle] = 0; cmd = sp->cmd; @@ -5589,27 +5443,29 @@ lun = SCSI_LUN_32(cmd); q = LU_Q(ha, bus, target, lun); - if (pkt->comp_status || pkt->scsi_status) { + if (comp_status || scsi_status) { dprintk(1, "scsi: comp_status = 0x%x, scsi_status = " - "0x%x, handle = 0x%x\n", pkt->comp_status, - pkt->scsi_status, pkt->handle); + "0x%x, handle = 0x%lx\n", comp_status, + scsi_status, handle); } /* Target busy */ - if (pkt->scsi_status & SS_BUSY_CONDITION && - pkt->scsi_status != SS_RESERVE_CONFLICT) { + if (scsi_status & SS_BUSY_CONDITION && + scsi_status != SS_RESERVE_CONFLICT) { CMD_RESULT(cmd) = - DID_BUS_BUSY << 16 | (pkt->scsi_status & 0xff); + DID_BUS_BUSY << 16 | (scsi_status & 0xff); } else { /* Save ISP completion status */ CMD_RESULT(cmd) = qla1280_return_status(pkt, cmd); - if (pkt->scsi_status & SS_CHECK_CONDITION) { - if (pkt->comp_status != CS_ARS_FAILED) { - if (pkt->req_sense_length < + if (scsi_status & SS_CHECK_CONDITION) { + if (comp_status != CS_ARS_FAILED) { + uint16_t req_sense_length = + le16_to_cpu(pkt->req_sense_length); + if (req_sense_length < CMD_SNSLEN(cmd)) - sense_sz = pkt->req_sense_length; + sense_sz = req_sense_length; else /* * Scsi_Cmnd->sense_buffer is @@ -5658,6 +5514,7 @@ srb_t ** done_q_first, srb_t ** done_q_last) { srb_t *sp; + uint32_t handle = le32_to_cpu(pkt->handle); ENTER("qla1280_error_entry"); @@ -5671,14 +5528,14 @@ dprintk(2, "qla1280_error_entry: UNKNOWN flag error\n"); /* Validate handle. */ - if (pkt->handle < MAX_OUTSTANDING_COMMANDS) - sp = ha->outstanding_cmds[pkt->handle]; + if (handle < MAX_OUTSTANDING_COMMANDS) + sp = ha->outstanding_cmds[handle]; else sp = 0; if (sp) { /* Free outstanding command slot. */ - ha->outstanding_cmds[pkt->handle] = 0; + ha->outstanding_cmds[handle] = 0; /* Bad payload or header */ if (pkt->entry_status & (BIT_3 + BIT_2)) { @@ -5946,8 +5803,10 @@ .release = qla1280_release, .info = qla1280_info, .queuecommand = qla1280_queuecommand, - .abort = qla1280_abort, - .reset = qla1280_reset, + .eh_abort_handler = qla1280_eh_abort, + .eh_device_reset_handler = qla1280_eh_device_reset, + .eh_bus_reset_handler = qla1280_eh_bus_reset, + .eh_host_reset_handler = qla1280_eh_adapter_reset, .slave_configure = qla1280_slave_configure, .bios_param = qla1280_biosparam, .can_queue = 255, diff -Nru a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h --- a/drivers/scsi/qla1280.h Mon Jun 9 23:16:19 2003 +++ b/drivers/scsi/qla1280.h Mon Jun 9 23:16:19 2003 @@ -158,6 +158,9 @@ uint8_t dir; /* direction of transfer */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,18) dma_addr_t saved_dma_handle; /* for unmap of single transfers */ + /* NOTE: the sp->cmd will be NULL when this completion is + * called, so you should know the scsi_cmnd when using this */ + struct completion *wait; #endif } srb_t; @@ -317,6 +320,7 @@ #define MBC_NOP 0 /* No Operation. */ #define MBC_LOAD_RAM 1 /* Load RAM. */ #define MBC_EXECUTE_FIRMWARE 2 /* Execute firmware. */ +#define MBC_DUMP_RAM 3 /* Dump RAM contents */ #define MBC_WRITE_RAM_WORD 4 /* Write ram word. */ #define MBC_READ_RAM_WORD 5 /* Read ram word. */ #define MBC_MAILBOX_REGISTER_TEST 6 /* Wrap incoming mailboxes */ @@ -371,9 +375,170 @@ /* * QLogic ISP1280 NVRAM structure definition. + * + * NOTE: the firmware structure is byte reversed on big-endian systems + * because it is read a word at a time from the chip, so the in-memory + * representation becomes correct */ typedef struct { - uint8_t id[4]; /* 0, 1, 2, 3 */ +#if defined(__BIG_ENDIAN) + uint8_t id1; /* 1 */ + uint8_t id0; /* 0 */ + + uint8_t id3; /* 3 */ + uint8_t id2; /* 2 */ + + struct { + uint8_t bios_configuration_mode:2; + uint8_t bios_disable:1; + uint8_t selectable_scsi_boot_enable:1; + uint8_t cd_rom_boot_enable:1; + uint8_t disable_loading_risc_code:1; + uint8_t enable_64bit_addressing:1; + uint8_t unused_7:1; + } cntr_flags_1; /* 5 */ + uint8_t version; /* 4 */ + + struct { + uint8_t boot_lun_number:5; + uint8_t scsi_bus_number:1; + uint8_t unused_6:1; + uint8_t unused_7:1; + uint8_t boot_target_number:4; + uint8_t unused_12:1; + uint8_t unused_13:1; + uint8_t unused_14:1; + uint8_t unused_15:1; + } cntr_flags_2; /* 6, 7 */ + + uint16_t unused_8; /* 8, 9 */ + uint16_t unused_10; /* 10, 11 */ + uint16_t unused_12; /* 12, 13 */ + uint16_t unused_14; /* 14, 15 */ + + /* Termination + * 0 = Disable, 1 = high only, 3 = Auto term + */ + union { + uint8_t c; + struct { + uint8_t scsi_bus_1_control:2; + uint8_t scsi_bus_0_control:2; + uint8_t unused_0:1; + uint8_t unused_1:1; + uint8_t unused_2:1; + uint8_t auto_term_support:1; + } f; + } termination; /* 17 */ + union { + uint8_t c; + struct { + uint8_t reserved:2; + uint8_t burst_enable:1; + uint8_t reserved_1:1; + uint8_t fifo_threshold:4; + } f; + } isp_config; /* 16 */ + + + uint16_t isp_parameter; /* 18, 19 */ + + union { + uint16_t w; + struct { + uint16_t enable_fast_posting:1; + uint16_t report_lvd_bus_transition:1; + uint16_t unused_2:1; + uint16_t unused_3:1; + uint16_t unused_4:1; + uint16_t unused_5:1; + uint16_t unused_6:1; + uint16_t unused_7:1; + uint16_t unused_8:1; + uint16_t unused_9:1; + uint16_t unused_10:1; + uint16_t unused_11:1; + uint16_t unused_12:1; + uint16_t unused_13:1; + uint16_t unused_14:1; + uint16_t unused_15:1; + } f; + } firmware_feature; /* 20, 21 */ + + uint16_t unused_22; /* 22, 23 */ + + struct { + uint8_t bus_reset_delay; /* 25 */ + struct { + uint8_t initiator_id:4; + uint8_t scsi_reset_disable:1; + uint8_t scsi_bus_size:1; + uint8_t scsi_bus_type:1; + uint8_t unused_7:1; + } config_1; /* 24 */ + + uint8_t retry_delay; /* 27 */ + uint8_t retry_count; /* 26 */ + + uint8_t unused_29; /* 29 */ + struct { + uint8_t async_data_setup_time:4; + uint8_t req_ack_active_negation:1; + uint8_t data_line_active_negation:1; + uint8_t unused_6:1; + uint8_t unused_7:1; + } config_2; /* 28 */ + + + uint16_t selection_timeout; /* 30, 31 */ + uint16_t max_queue_depth; /* 32, 33 */ + + uint16_t unused_34; /* 34, 35 */ + uint16_t unused_36; /* 36, 37 */ + uint16_t unused_38; /* 38, 39 */ + + struct { + uint8_t execution_throttle; /* 41 */ + union { + uint8_t c; + struct { + uint8_t renegotiate_on_error:1; + uint8_t stop_queue_on_check:1; + uint8_t auto_request_sense:1; + uint8_t tag_queuing:1; + uint8_t sync_data_transfers:1; + uint8_t wide_data_transfers:1; + uint8_t parity_checking:1; + uint8_t disconnect_allowed:1; + } f; + } parameter; /* 40 */ + + struct { + uint8_t sync_offset:4; + uint8_t device_enable:1; + uint8_t lun_disable:1; + uint8_t unused_6:1; + uint8_t unused_7:1; + } flags; /* 43 */ + uint8_t sync_period; /* 42 */ + + + uint16_t unused_44; /* 44, 45 */ + } target[MAX_TARGETS]; + } bus[MAX_BUSES]; + + uint16_t unused_248; /* 248, 249 */ + + uint16_t subsystem_id[2]; /* 250, 251, 252, 253 */ + + uint8_t chksum; /* 255 */ + uint8_t unused_254; /* 254 */ + +#elif defined(__LITTLE_ENDIAN) + uint8_t id0; /* 0 */ + uint8_t id1; /* 1 */ + uint8_t id2; /* 2 */ + uint8_t id3; /* 3 */ uint8_t version; /* 4 */ struct { @@ -521,14 +686,26 @@ uint8_t unused_254; /* 254 */ uint8_t chksum; /* 255 */ +#else +#error neither __BIG_ENDIAN nor __LITTLE_ENDIAN is defined +#endif } nvram_t; /* * QLogic ISP12160 NVRAM structure definition. + * + * NOTE: the firmware structure is byte reversed on big-endian systems + * because it is read a word at a time from the chip, so the in-memory + * representation becomes correct */ typedef struct { - uint8_t id[4]; /* 0, 1, 2, 3 */ - uint8_t version; /* 4 */ +#if defined(__BIG_ENDIAN) + uint8_t id1; /* 1 */ + uint8_t id0; /* 0 */ + + uint8_t id3; /* 3 */ + uint8_t id2; /* 2 */ + /* Host/Bios Flags */ struct { uint8_t bios_configuration_mode:2; @@ -539,17 +716,179 @@ uint8_t unused_6:1; uint8_t unused_7:1; } cntr_flags_1; /* 5 */ + uint8_t version; /* 4 */ + /* Selectable Boot Support */ struct { - uint8_t boot_lun_number:5; - uint8_t scsi_bus_number:1; + uint16_t boot_lun_number:5; + uint16_t scsi_bus_number:1; + uint16_t unused_6:1; + uint16_t unused_7:1; + uint16_t boot_target_number:4; + uint16_t unused_12:1; + uint16_t unused_13:1; + uint16_t unused_14:1; + uint16_t unused_15:1; + } cntr_flags_2; /* 6, 7 */ + + uint16_t unused_8; /* 8, 9 */ + uint16_t unused_10; /* 10, 11 */ + uint16_t unused_12; /* 12, 13 */ + uint16_t unused_14; /* 14, 15 */ + + /* Termination + * 0 = Disable, 1 = high only, 3 = Auto term + */ + union { + uint8_t c; + struct { + uint8_t scsi_bus_1_control:2; + uint8_t scsi_bus_0_control:2; + uint8_t unused_0:1; + uint8_t unused_1:1; + uint8_t unused_2:1; + uint8_t auto_term_support:1; + } f; + } termination; /* 17 */ + /* Auto Term - 3 */ + /* High Only - 1 (GPIO2 = 1 & GPIO3 = 0) */ + /* Disable - 0 (GPIO2 = 0 & GPIO3 = X) */ + /* ISP Config Parameters */ + union { + uint8_t c; + struct { + uint8_t reserved:2; + uint8_t burst_enable:1; + uint8_t reserved_1:1; + uint8_t fifo_threshold:4; + } f; + } isp_config; /* 16 */ + + uint16_t isp_parameter; /* 18, 19 */ + + union { + uint16_t w; + struct { + uint16_t enable_fast_posting:1; + uint16_t report_lvd_bus_transition:1; + uint16_t unused_2:1; + uint16_t unused_3:1; + uint16_t unused_4:1; + uint16_t unused_5:1; + uint16_t unused_6:1; + uint16_t unused_7:1; + uint16_t unused_8:1; + uint16_t unused_9:1; + uint16_t unused_10:1; + uint16_t unused_11:1; + uint16_t unused_12:1; + uint16_t unused_13:1; + uint16_t unused_14:1; + uint16_t unused_15:1; + } f; + } firmware_feature; /* 20, 21 */ + + uint16_t unused_22; /* 22, 23 */ + + struct { + uint8_t bus_reset_delay; /* 25 */ + struct { + uint8_t initiator_id:4; + uint8_t scsi_reset_disable:1; + uint8_t scsi_bus_size:1; + uint8_t scsi_bus_type:1; + uint8_t unused_7:1; + } config_1; /* 24 */ + + uint8_t retry_delay; /* 27 */ + uint8_t retry_count; /* 26 */ + + uint8_t unused_29; /* 29 */ + /* Adapter Capabilities bits */ + struct { + uint8_t async_data_setup_time:4; + uint8_t req_ack_active_negation:1; + uint8_t data_line_active_negation:1; + uint8_t unused_6:1; + uint8_t unused_7:1; + } config_2; /* 28 */ + + uint16_t selection_timeout; /* 30, 31 */ + uint16_t max_queue_depth; /* 32, 33 */ + + uint16_t unused_34; /* 34, 35 */ + uint16_t unused_36; /* 36, 37 */ + uint16_t unused_38; /* 38, 39 */ + + struct { + uint8_t execution_throttle; /* 41 */ + union { + uint8_t c; + struct { + uint8_t renegotiate_on_error:1; + uint8_t stop_queue_on_check:1; + uint8_t auto_request_sense:1; + uint8_t tag_queuing:1; + uint8_t sync_data_transfers:1; + uint8_t wide_data_transfers:1; + uint8_t parity_checking:1; + uint8_t disconnect_allowed:1; + } f; + } parameter; /* 40 */ + + struct { + uint8_t sync_offset:5; + uint8_t device_enable:1; + uint8_t unused_6:1; + uint8_t unused_7:1; + } flags1; /* 43 */ + uint8_t sync_period; /* 42 */ + + uint8_t unused_45; /* 45 */ + struct { + uint8_t ppr_options:4; + uint8_t ppr_bus_width:2; + uint8_t unused_8:1; + uint8_t enable_ppr:1; + } flags2; /* 44 */ + + } target[MAX_TARGETS]; + } bus[MAX_BUSES]; + + uint16_t unused_248; /* 248, 249 */ + + uint16_t subsystem_id[2]; /* 250, 251, 252, 253 */ + + uint8_t chksum; /* 255 */ + uint8_t System_Id_Pointer; /* 254 */ + +#elif defined(__LITTLE_ENDIAN) + uint8_t id0; /* 0 */ + uint8_t id1; /* 1 */ + uint8_t id2; /* 2 */ + uint8_t id3; /* 3 */ + uint8_t version; /* 4 */ + /* Host/Bios Flags */ + struct { + uint8_t bios_configuration_mode:2; + uint8_t bios_disable:1; + uint8_t selectable_scsi_boot_enable:1; + uint8_t cd_rom_boot_enable:1; + uint8_t disable_loading_risc_code:1; uint8_t unused_6:1; uint8_t unused_7:1; - uint8_t boot_target_number:4; - uint8_t unused_12:1; - uint8_t unused_13:1; - uint8_t unused_14:1; - uint8_t unused_15:1; + } cntr_flags_1; /* 5 */ + /* Selectable Boot Support */ + struct { + uint16_t boot_lun_number:5; + uint16_t scsi_bus_number:1; + uint16_t unused_6:1; + uint16_t unused_7:1; + uint16_t boot_target_number:4; + uint16_t unused_12:1; + uint16_t unused_13:1; + uint16_t unused_14:1; + uint16_t unused_15:1; } cntr_flags_2; /* 6, 7 */ uint16_t unused_8; /* 8, 9 */ @@ -591,22 +930,22 @@ union { uint16_t w; struct { - uint8_t enable_fast_posting:1; - uint8_t report_lvd_bus_transition:1; - uint8_t unused_2:1; - uint8_t unused_3:1; - uint8_t unused_4:1; - uint8_t unused_5:1; - uint8_t unused_6:1; - uint8_t unused_7:1; - uint8_t unused_8:1; - uint8_t unused_9:1; - uint8_t unused_10:1; - uint8_t unused_11:1; - uint8_t unused_12:1; - uint8_t unused_13:1; - uint8_t unused_14:1; - uint8_t unused_15:1; + uint16_t enable_fast_posting:1; + uint16_t report_lvd_bus_transition:1; + uint16_t unused_2:1; + uint16_t unused_3:1; + uint16_t unused_4:1; + uint16_t unused_5:1; + uint16_t unused_6:1; + uint16_t unused_7:1; + uint16_t unused_8:1; + uint16_t unused_9:1; + uint16_t unused_10:1; + uint16_t unused_11:1; + uint16_t unused_12:1; + uint16_t unused_13:1; + uint16_t unused_14:1; + uint16_t unused_15:1; } f; } firmware_feature; /* 20, 21 */ @@ -665,11 +1004,14 @@ uint8_t device_enable:1; uint8_t unused_6:1; uint8_t unused_7:1; + } flags1; /* 43 */ + + struct { uint8_t ppr_options:4; uint8_t ppr_bus_width:2; uint8_t unused_8:1; uint8_t enable_ppr:1; - } flags; /* 43, 44 */ + } flags2; /* 43 */ uint8_t unused_45; /* 45 */ } target[MAX_TARGETS]; @@ -682,6 +1024,9 @@ uint8_t System_Id_Pointer; /* 254 */ uint8_t chksum; /* 255 */ +#else +#error neither __BIG_ENDIAN nor __LITTLE_ENDIAN is defined +#endif } nvram160_t; /* @@ -1306,7 +1651,6 @@ /* * Linux - SCSI Driver Interface Function Prototypes. */ -int qla1280_proc_info(char *, char **, off_t, int, int, int); const char *qla1280_info(struct Scsi_Host *host); int qla1280_detect(Scsi_Host_Template *); int qla1280_release(struct Scsi_Host *); diff -Nru a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c --- a/drivers/scsi/scsi.c Mon Jun 9 23:16:12 2003 +++ b/drivers/scsi/scsi.c Mon Jun 9 23:16:12 2003 @@ -86,12 +86,6 @@ static unsigned long serial_number; /* - * List of all highlevel drivers. - */ -LIST_HEAD(scsi_devicelist); -static DECLARE_RWSEM(scsi_devicelist_mutex); - -/* * Note - the initial logging level can be set here to log events at boot time. * After the system is up, you may enable logging via the /proc interface. */ @@ -931,50 +925,6 @@ return depth; } -int scsi_attach_device(struct scsi_device *sdev) -{ - struct Scsi_Device_Template *sdt; - - down_read(&scsi_devicelist_mutex); - list_for_each_entry(sdt, &scsi_devicelist, list) { - if (!try_module_get(sdt->module)) - continue; - (*sdt->attach)(sdev); - module_put(sdt->module); - } - up_read(&scsi_devicelist_mutex); - return 0; -} - -void scsi_detach_device(struct scsi_device *sdev) -{ - struct Scsi_Device_Template *sdt; - - down_read(&scsi_devicelist_mutex); - list_for_each_entry(sdt, &scsi_devicelist, list) { - if (!try_module_get(sdt->module)) - continue; - (*sdt->detach)(sdev); - module_put(sdt->module); - } - up_read(&scsi_devicelist_mutex); -} - -void scsi_rescan_device(struct scsi_device *sdev) -{ - struct Scsi_Device_Template *sdt; - - down_read(&scsi_devicelist_mutex); - list_for_each_entry(sdt, &scsi_devicelist, list) { - if (!try_module_get(sdt->module)) - continue; - if (*sdt->rescan) - (*sdt->rescan)(sdev); - module_put(sdt->module); - } - up_read(&scsi_devicelist_mutex); -} - int scsi_device_get(struct scsi_device *sdev) { if (!try_module_get(sdev->host->hostt->module)) @@ -1028,71 +978,6 @@ } else { /* FIXME: Send online state change hotplug event */ } -} - -/* - * This entry point is called from the upper level module's module_init() - * routine. That implies that when this function is called, the - * scsi_mod module is locked down because of upper module layering and - * that the high level driver module is locked down by being in it's - * init routine. So, the *only* thing we have to do to protect adds - * we perform in this function is to make sure that all call's - * to the high level driver's attach() and detach() call in points, other - * than via scsi_register_device and scsi_unregister_device which are in - * the module_init and module_exit code respectively and therefore already - * locked down by the kernel module loader, are wrapped by try_module_get() - * and module_put() to avoid races on device adds and removes. - */ -int scsi_register_device(struct Scsi_Device_Template *tpnt) -{ - struct scsi_device *sdev; - struct Scsi_Host *shpnt; - -#ifdef CONFIG_KMOD - if (scsi_host_get_next(NULL) == NULL) - request_module("scsi_hostadapter"); -#endif - - if (!list_empty(&tpnt->list)) - return 1; - - down_write(&scsi_devicelist_mutex); - list_add_tail(&tpnt->list, &scsi_devicelist); - up_write(&scsi_devicelist_mutex); - - scsi_upper_driver_register(tpnt); - - for (shpnt = scsi_host_get_next(NULL); shpnt; - shpnt = scsi_host_get_next(shpnt)) - list_for_each_entry(sdev, &shpnt->my_devices, siblings) - (*tpnt->attach)(sdev); - - return 0; -} - -int scsi_unregister_device(struct Scsi_Device_Template *tpnt) -{ - struct scsi_device *sdev; - struct Scsi_Host *shpnt; - - /* - * Next, detach the devices from the driver. - */ - for (shpnt = scsi_host_get_next(NULL); shpnt; - shpnt = scsi_host_get_next(shpnt)) { - list_for_each_entry(sdev, &shpnt->my_devices, siblings) - (*tpnt->detach)(sdev); - } - - /* - * Extract the template from the linked list. - */ - down_write(&scsi_devicelist_mutex); - list_del(&tpnt->list); - up_write(&scsi_devicelist_mutex); - - scsi_upper_driver_unregister(tpnt); - return 0; } MODULE_DESCRIPTION("SCSI core"); diff -Nru a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h --- a/drivers/scsi/scsi.h Mon Jun 9 23:16:08 2003 +++ b/drivers/scsi/scsi.h Mon Jun 9 23:16:08 2003 @@ -316,6 +316,7 @@ */ struct scsi_device { + struct class_device sdev_classdev; /* * This information is private to the scsi mid-layer. */ @@ -383,12 +384,14 @@ * time. */ unsigned was_reset:1; /* There was a bus reset on the bus for * this device */ - unsigned expecting_cc_ua:1; /* Expecting a CHECK_CONDITION/UNIT_ATTN - * because we did a bus reset. */ - unsigned ten:1; /* support ten byte read / write */ + unsigned expecting_cc_ua:1; /* Expecting a CHECK_CONDITION/UNIT_ATTN + * because we did a bus reset. */ + unsigned use_10_for_rw:1; /* first try 10-byte read / write */ + unsigned use_10_for_ms:1; /* first try 10-byte mode sense/select */ unsigned remap:1; /* support remapping */ // unsigned sync:1; /* Sync transfer state, managed by host */ // unsigned wide:1; /* WIDE transfer state, managed by host */ + unsigned no_start_on_add:1; /* do not issue start on add */ unsigned int device_blocked; /* Device returned QUEUE_FULL. */ @@ -402,10 +405,6 @@ container_of(d, struct scsi_device, sdev_driverfs_dev) -/* - * The Scsi_Cmnd structure is used by scsi.c internally, and for communication - * with low level drivers that support multiple outstanding commands. - */ typedef struct scsi_pointer { char *ptr; /* data pointer */ int this_residual; /* left in this buffer */ @@ -458,12 +457,13 @@ }; /* - * FIXME(eric) - one of the great regrets that I have is that I failed to define - * these structure elements as something like sc_foo instead of foo. This would - * make it so much easier to grep through sources and so forth. I propose that - * all new elements that get added to these structures follow this convention. - * As time goes on and as people have the stomach for it, it should be possible to - * go back and retrofit at least some of the elements here with with the prefix. + * FIXME(eric) - one of the great regrets that I have is that I failed to + * define these structure elements as something like sc_foo instead of foo. + * This would make it so much easier to grep through sources and so forth. + * I propose that all new elements that get added to these structures follow + * this convention. As time goes on and as people have the stomach for it, + * it should be possible to go back and retrofit at least some of the elements + * here with with the prefix. */ struct scsi_cmnd { int sc_magic; @@ -682,5 +682,10 @@ } int scsi_set_medium_removal(Scsi_Device *dev, char state); + +extern int scsi_sysfs_modify_sdev_attribute(struct device_attribute ***dev_attrs, + struct device_attribute *attr); +extern int scsi_sysfs_modify_shost_attribute(struct class_device_attribute ***class_attrs, + struct class_device_attribute *attr); #endif /* _SCSI_H */ diff -Nru a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c --- a/drivers/scsi/scsi_debug.c Mon Jun 9 23:16:14 2003 +++ b/drivers/scsi/scsi_debug.c Mon Jun 9 23:16:14 2003 @@ -1259,8 +1259,8 @@ /* scsi_debug_proc_info * Used if the driver currently has no own support for /proc/scsi */ -static int scsi_debug_proc_info(char *buffer, char **start, off_t offset, - int length, int inode, int inout) +static int scsi_debug_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, + int length, int inout) { int len, pos, begin; int orig_length; diff -Nru a/drivers/scsi/scsi_debug.h b/drivers/scsi/scsi_debug.h --- a/drivers/scsi/scsi_debug.h Mon Jun 9 23:16:12 2003 +++ b/drivers/scsi/scsi_debug.h Mon Jun 9 23:16:12 2003 @@ -14,7 +14,7 @@ static int scsi_debug_bus_reset(struct scsi_cmnd *); static int scsi_debug_device_reset(struct scsi_cmnd *); static int scsi_debug_host_reset(struct scsi_cmnd *); -static int scsi_debug_proc_info(char *, char **, off_t, int, int, int); +static int scsi_debug_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int); static const char * scsi_debug_info(struct Scsi_Host *); /* diff -Nru a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c --- a/drivers/scsi/scsi_devinfo.c Mon Jun 9 23:16:09 2003 +++ b/drivers/scsi/scsi_devinfo.c Mon Jun 9 23:16:09 2003 @@ -131,7 +131,7 @@ {"EMULEX", "MD21/S2 ESDI", NULL, BLIST_SINGLELUN}, {"CANON", "IPUBJD", NULL, BLIST_SPARSELUN}, {"nCipher", "Fastness Crypto", NULL, BLIST_FORCELUN}, - {"DEC", "HSG80", NULL, BLIST_FORCELUN}, + {"DEC", "HSG80", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, {"COMPAQ", "LOGICAL VOLUME", NULL, BLIST_FORCELUN}, {"COMPAQ", "CR3500", NULL, BLIST_FORCELUN}, {"NEC", "PD-1 ODX654P", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, @@ -159,7 +159,10 @@ {"HP", "NetRAID-4M", NULL, BLIST_FORCELUN}, {"ADAPTEC", "AACRAID", NULL, BLIST_FORCELUN}, {"ADAPTEC", "Adaptec 5400S", NULL, BLIST_FORCELUN}, - {"COMPAQ", "MSA1000", NULL, BLIST_FORCELUN}, + {"COMPAQ", "MSA1000", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, + {"COMPAQ", "MSA1000 VOLUME", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, + {"COMPAQ", "HSV110", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, + {"HP", "HSV100", NULL, BLIST_SPARSELUN | BLIST_NOSTARTONADD}, {"HP", "C1557A", NULL, BLIST_FORCELUN}, {"IBM", "AuSaV1S2", NULL, BLIST_FORCELUN}, {"FSC", "CentricStor", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, diff -Nru a/drivers/scsi/scsi_devinfo.h b/drivers/scsi/scsi_devinfo.h --- a/drivers/scsi/scsi_devinfo.h Mon Jun 9 23:16:05 2003 +++ b/drivers/scsi/scsi_devinfo.h Mon Jun 9 23:16:05 2003 @@ -14,3 +14,4 @@ #define BLIST_LARGELUN 0x200 /* LUNs past 7 on a SCSI-2 device */ #define BLIST_INQUIRY_36 0x400 /* override additional length field */ #define BLIST_INQUIRY_58 0x800 /* ... for broken inquiry responses */ +#define BLIST_NOSTARTONADD 0x1000 /* do not do automatic start on add */ diff -Nru a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c --- a/drivers/scsi/scsi_lib.c Mon Jun 9 23:16:12 2003 +++ b/drivers/scsi/scsi_lib.c Mon Jun 9 23:16:12 2003 @@ -613,29 +613,6 @@ } /* - * Function: scsi_get_request_dev() - * - * Purpose: Find the upper-level driver that is responsible for this - * request - * - * Arguments: request - I/O request we are preparing to queue. - * - * Lock status: No locks assumed to be held, but as it happens the - * q->queue_lock is held when this is called. - * - * Returns: Nothing - * - * Notes: The requests in the request queue may have originated - * from any block device driver. We need to find out which - * one so that we can later form the appropriate command. - */ -static struct Scsi_Device_Template *scsi_get_request_dev(struct request *req) -{ - struct gendisk *p = req->rq_disk; - return p ? *(struct Scsi_Device_Template **)p->private_data : NULL; -} - -/* * Function: scsi_io_completion() * * Purpose: Completion processing for block device I/O requests. @@ -662,7 +639,6 @@ * * b) We can just use scsi_requeue_command() here. This would * be used if we just wanted to retry, for example. - * */ void scsi_io_completion(struct scsi_cmnd *cmd, int good_sectors, int block_sectors) @@ -796,17 +772,20 @@ } } } - /* If we had an ILLEGAL REQUEST returned, then we may have - * performed an unsupported command. The only thing this should be - * would be a ten byte read where only a six byte read was supported. - * Also, on a system where READ CAPACITY failed, we have have read - * past the end of the disk. + /* + * If we had an ILLEGAL REQUEST returned, then we may have + * performed an unsupported command. The only thing this + * should be would be a ten byte read where only a six byte + * read was supported. Also, on a system where READ CAPACITY + * failed, we may have read past the end of the disk. */ switch (cmd->sense_buffer[2]) { case ILLEGAL_REQUEST: - if (cmd->device->ten) { - cmd->device->ten = 0; + if (cmd->device->use_10_for_rw && + (cmd->cmnd[0] == READ_10 || + cmd->cmnd[0] == WRITE_10)) { + cmd->device->use_10_for_rw = 0; /* * This will cause a retry with a 6-byte * command. @@ -847,11 +826,7 @@ return; } if (result) { - struct Scsi_Device_Template *sdt; - - sdt = scsi_get_request_dev(cmd->request); - printk("SCSI %s error : <%d %d %d %d> return code = 0x%x\n", - (sdt ? sdt->name : "device"), + printk("SCSI error : <%d %d %d %d> return code = 0x%x\n", cmd->device->host->host_no, cmd->device->channel, cmd->device->id, @@ -945,7 +920,6 @@ static int scsi_prep_fn(struct request_queue *q, struct request *req) { - struct Scsi_Device_Template *sdt; struct scsi_device *sdev = q->queuedata; struct scsi_cmnd *cmd; @@ -1001,6 +975,7 @@ * happening now. */ if (req->flags & (REQ_CMD | REQ_BLOCK_PC)) { + struct scsi_driver *drv; int ret; /* @@ -1015,8 +990,6 @@ * some kinds of consistency checking may cause the * request to be rejected immediately. */ - sdt = scsi_get_request_dev(req); - BUG_ON(!sdt); /* * This sets up the scatter-gather table (allocating if @@ -1029,7 +1002,8 @@ /* * Initialize the actual SCSI command for this request. */ - if (unlikely(!sdt->init_command(cmd))) { + drv = *(struct scsi_driver **)req->rq_disk->private_data; + if (unlikely(!drv->init_command(cmd))) { scsi_release_buffers(cmd); scsi_put_command(cmd); return BLKPREP_KILL; diff -Nru a/drivers/scsi/scsi_pc98.c b/drivers/scsi/scsi_pc98.c --- a/drivers/scsi/scsi_pc98.c Mon Jun 9 23:16:05 2003 +++ b/drivers/scsi/scsi_pc98.c Mon Jun 9 23:16:05 2003 @@ -15,21 +15,6 @@ #include "hosts.h" -/* XXX - For now, we assume the first (i.e. having the least host_no) - real (i.e. non-emulated) host adapter shall be BIOS-controlled one. - We *SHOULD* invent another way. */ -static inline struct Scsi_Host *first_real_host(void) -{ - struct Scsi_Host *shost = NULL; - - while ((shost = scsi_host_get_next(shost))) { - if (!shost->hostt->emulated) - break; - } - - return shost; -} - static int pc98_first_bios_param(struct scsi_device *sdev, int *ip) { const u8 *p = (&__PC9800SCA(u8, PC9800SCA_SCSI_PARAMS) + sdev->id * 4); @@ -50,7 +35,16 @@ { struct Scsi_Host *first_real = first_real_host(); - if (sdev->host == first_real && sdev->id < 7 && + /* + * XXX + * XXX This needs to become a sysfs attribute that's set + * XXX by code that knows which host is the first one. + * XXX + * XXX Currently we support only one host on with a + * XXX PC98ish HBA. + * XXX + */ + if (1 || sdev->host == first_real && sdev->id < 7 && __PC9800SCA_TEST_BIT(PC9800SCA_DISK_EQUIPS, sdev->id)) return pc98_first_bios_param(sdev, ip); diff -Nru a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h --- a/drivers/scsi/scsi_priv.h Mon Jun 9 23:16:15 2003 +++ b/drivers/scsi/scsi_priv.h Mon Jun 9 23:16:15 2003 @@ -41,9 +41,6 @@ #define SCSI_SENSE_VALID(scmd) \ (((scmd)->sense_buffer[0] & 0x70) == 0x70) -struct Scsi_Device_Template; - - /* * scsi_target: representation of a scsi target, for now, this is only * used for single_lun devices. If no one has active IO to the target, @@ -58,7 +55,8 @@ /* hosts.c */ extern void scsi_host_busy_inc(struct Scsi_Host *, Scsi_Device *); extern void scsi_host_busy_dec_and_test(struct Scsi_Host *, Scsi_Device *); -extern struct Scsi_Host *scsi_host_get_next(struct Scsi_Host *); +extern struct Scsi_Host *scsi_host_lookup(unsigned short); +extern void scsi_host_put(struct Scsi_Host *); extern void scsi_host_init(void); /* scsi.c */ @@ -68,9 +66,6 @@ extern void scsi_done(struct scsi_cmnd *cmd); extern void scsi_finish_command(struct scsi_cmnd *cmd); extern int scsi_retry_command(struct scsi_cmnd *cmd); -extern int scsi_attach_device(struct scsi_device *sdev); -extern void scsi_detach_device(struct scsi_device *sdev); -extern void scsi_rescan_device(struct scsi_device *sdev); extern int scsi_insert_special_req(struct scsi_request *sreq, int); extern void scsi_init_cmd_from_req(struct scsi_cmnd *cmd, struct scsi_request *sreq); @@ -108,7 +103,7 @@ # define scsi_proc_host_add(shost) do { } while (0) # define scsi_proc_host_rm(shost) do { } while (0) # define scsi_init_procfs() (0) -# define scsi_exit_procfs do { } while (0) +# define scsi_exit_procfs() do { } while (0) #endif /* CONFIG_PROC_FS */ /* scsi_scan.c */ @@ -117,16 +112,23 @@ extern void scsi_free_sdev(struct scsi_device *); extern void scsi_free_shost(struct Scsi_Host *); extern void scsi_host_get(struct Scsi_Host *); +extern void scsi_rescan_device(struct device *dev); /* scsi_sysfs.c */ extern int scsi_device_register(struct scsi_device *); extern void scsi_device_unregister(struct scsi_device *); -extern int scsi_upper_driver_register(struct Scsi_Device_Template *); -extern void scsi_upper_driver_unregister(struct Scsi_Device_Template *); extern void scsi_sysfs_init_host(struct Scsi_Host *); extern int scsi_sysfs_add_host(struct Scsi_Host *, struct device *); extern void scsi_sysfs_remove_host(struct Scsi_Host *); extern int scsi_sysfs_register(void); extern void scsi_sysfs_unregister(void); + +/* definitions for the linker default sections covering the host + * class and device attributes */ +extern struct class_device_attribute *scsi_sysfs_shost_attrs[]; +extern struct device_attribute *scsi_sysfs_sdev_attrs[]; + +extern struct class shost_class; +extern struct bus_type scsi_bus_type; #endif /* _SCSI_PRIV_H */ diff -Nru a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c --- a/drivers/scsi/scsi_proc.c Mon Jun 9 23:16:07 2003 +++ b/drivers/scsi/scsi_proc.c Mon Jun 9 23:16:07 2003 @@ -24,6 +24,7 @@ #include <linux/proc_fs.h> #include <linux/errno.h> #include <linux/blk.h> +#include <linux/seq_file.h> #include <asm/uaccess.h> #include "scsi.h" @@ -79,14 +80,14 @@ n = generic_proc_info(buffer, start, offset, length, shost->hostt->info, shost); else - n = (shost->hostt->proc_info(buffer, start, offset, - length, shost->host_no, 0)); + n = shost->hostt->proc_info(shost, buffer, start, offset, + length, 0); *eof = (n < length); return n; } -static int proc_scsi_write(struct file *file, const char *buf, +static int proc_scsi_write_proc(struct file *file, const char *buf, unsigned long count, void *data) { struct Scsi_Host *shost = data; @@ -104,8 +105,7 @@ ret = -EFAULT; if (copy_from_user(page, buf, count)) goto out; - ret = shost->hostt->proc_info(page, &start, 0, count, - shost->host_no, 1); + ret = shost->hostt->proc_info(shost, page, &start, 0, count, 1); } out: free_page((unsigned long)page); @@ -138,7 +138,7 @@ return; } - p->write_proc = proc_scsi_write; + p->write_proc = proc_scsi_write_proc; p->owner = shost->hostt->module; } @@ -153,96 +153,52 @@ remove_proc_entry(shost->hostt->proc_name, proc_scsi); } -static void proc_print_scsidevice(struct scsi_device* sdev, char *buffer, - int *size, int len) +static int proc_print_scsidevice(struct device *dev, void *data) { - - int x, y = *size; - extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE]; - - y = sprintf(buffer + len, - "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n Vendor: ", - sdev->host->host_no, sdev->channel, sdev->id, sdev->lun); - for (x = 0; x < 8; x++) { - if (sdev->vendor[x] >= 0x20) - y += sprintf(buffer + len + y, "%c", sdev->vendor[x]); + struct scsi_device *sdev = to_scsi_device(dev); + struct seq_file *s = data; + int i; + + seq_printf(s, + "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n Vendor: ", + sdev->host->host_no, sdev->channel, sdev->id, sdev->lun); + for (i = 0; i < 8; i++) { + if (sdev->vendor[i] >= 0x20) + seq_printf(s, "%c", sdev->vendor[i]); else - y += sprintf(buffer + len + y, " "); + seq_printf(s, " "); } - y += sprintf(buffer + len + y, " Model: "); - for (x = 0; x < 16; x++) { - if (sdev->model[x] >= 0x20) - y += sprintf(buffer + len + y, "%c", sdev->model[x]); + + seq_printf(s, " Model: "); + for (i = 0; i < 16; i++) { + if (sdev->model[i] >= 0x20) + seq_printf(s, "%c", sdev->model[i]); else - y += sprintf(buffer + len + y, " "); + seq_printf(s, " "); } - y += sprintf(buffer + len + y, " Rev: "); - for (x = 0; x < 4; x++) { - if (sdev->rev[x] >= 0x20) - y += sprintf(buffer + len + y, "%c", sdev->rev[x]); + + seq_printf(s, " Rev: "); + for (i = 0; i < 4; i++) { + if (sdev->rev[i] >= 0x20) + seq_printf(s, "%c", sdev->rev[i]); else - y += sprintf(buffer + len + y, " "); + seq_printf(s, " "); } - y += sprintf(buffer + len + y, "\n"); - y += sprintf(buffer + len + y, " Type: %s ", + seq_printf(s, "\n"); + + seq_printf(s, " Type: %s ", sdev->type < MAX_SCSI_DEVICE_CODE ? scsi_device_types[(int) sdev->type] : "Unknown "); - y += sprintf(buffer + len + y, " ANSI" + seq_printf(s, " ANSI" " SCSI revision: %02x", (sdev->scsi_level - 1) ? sdev->scsi_level - 1 : 1); if (sdev->scsi_level == 2) - y += sprintf(buffer + len + y, " CCS\n"); + seq_printf(s, " CCS\n"); else - y += sprintf(buffer + len + y, "\n"); + seq_printf(s, "\n"); - *size = y; - return; -} - -static int scsi_proc_info(char *buffer, char **start, off_t offset, int length) -{ - struct Scsi_Host *shost; - Scsi_Device *sdev; - int size, len = 0; - off_t begin = 0; - off_t pos = 0; - - /* - * First, see if there are any attached devices or not. - */ - for (shost = scsi_host_get_next(NULL); shost; - shost = scsi_host_get_next(shost)) { - if (!list_empty(&shost->my_devices)) { - break; - } - } - size = sprintf(buffer + len, "Attached devices: %s\n", - (shost) ? "" : "none"); - len += size; - pos = begin + len; - for (shost = scsi_host_get_next(NULL); shost; - shost = scsi_host_get_next(shost)) { - list_for_each_entry(sdev, &shost->my_devices, siblings) { - proc_print_scsidevice(sdev, buffer, &size, len); - len += size; - pos = begin + len; - - if (pos < offset) { - len = 0; - begin = pos; - } - if (pos > offset + length) - goto stop_output; - } - } - -stop_output: - *start = buffer + (offset - begin); /* Start of wanted data */ - len -= (offset - begin); /* Start slop */ - if (len > length) - len = length; /* Ending slop */ - return (len); + return 0; } static int scsi_add_single_device(uint host, uint channel, uint id, uint lun) @@ -251,7 +207,7 @@ struct scsi_device *sdev; int error = -ENODEV; - shost = scsi_host_hn_get(host); + shost = scsi_host_lookup(host); if (!shost) return -ENODEV; @@ -273,7 +229,7 @@ struct Scsi_Host *shost; int error = -ENODEV; - shost = scsi_host_hn_get(host); + shost = scsi_host_lookup(host); if (!shost) return -ENODEV; sdev = scsi_find_device(shost, channel, id, lun); @@ -288,8 +244,8 @@ return error; } -static int proc_scsi_gen_write(struct file * file, const char * buf, - unsigned long length, void *data) +static int proc_scsi_write(struct file *file, const char* buf, + size_t length, loff_t *ppos) { int host, channel, id, lun; char *buffer, *p; @@ -432,6 +388,30 @@ return err; } +static int proc_scsi_show(struct seq_file *s, void *p) +{ + seq_printf(s, "Attached devices:\n"); + bus_for_each_dev(&scsi_bus_type, NULL, s, proc_print_scsidevice); + return 0; +} + +static int proc_scsi_open(struct inode *inode, struct file *file) +{ + /* + * We don't really needs this for the write case but it doesn't + * harm either. + */ + return single_open(file, proc_scsi_show, NULL); +} + +static struct file_operations proc_scsi_operations = { + .open = proc_scsi_open, + .read = seq_read, + .write = proc_scsi_write, + .llseek = seq_lseek, + .release = single_release, +}; + int __init scsi_init_procfs(void) { struct proc_dir_entry *pde; @@ -440,10 +420,10 @@ if (!proc_scsi) goto err1; - pde = create_proc_info_entry("scsi/scsi", 0, 0, scsi_proc_info); + pde = create_proc_entry("scsi/scsi", 0, NULL); if (!pde) goto err2; - pde->write_proc = proc_scsi_gen_write; + pde->proc_fops = &proc_scsi_operations; return 0; diff -Nru a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c --- a/drivers/scsi/scsi_scan.c Mon Jun 9 23:16:16 2003 +++ b/drivers/scsi/scsi_scan.c Mon Jun 9 23:16:16 2003 @@ -641,6 +641,13 @@ sdev->borken = 0; /* + * Some devices may not want to have a start command automatically + * issued when a device is added. + */ + if (*bflags & BLIST_NOSTARTONADD) + sdev->no_start_on_add = 1; + + /* * If we need to allow I/O to only one of the luns attached to * this target id at a time set single_lun, and allocate or modify * sdev_target. @@ -1091,22 +1098,29 @@ uint channel, uint id, uint lun) { struct scsi_device *sdev; - int error = -ENODEV, res; + int res; res = scsi_probe_and_add_lun(shost, channel, id, lun, NULL, &sdev); - if (res == SCSI_SCAN_LUN_PRESENT) - error = scsi_attach_device(sdev); - - if (error) - sdev = ERR_PTR(error); + if (res != SCSI_SCAN_LUN_PRESENT) + sdev = ERR_PTR(-ENODEV); return sdev; } int scsi_remove_device(struct scsi_device *sdev) { - scsi_detach_device(sdev); scsi_device_unregister(sdev); return 0; +} + +void scsi_rescan_device(struct device *dev) +{ + struct scsi_driver *drv = to_scsi_driver(dev->driver); + + if (try_module_get(drv->owner)) { + if (drv->rescan) + drv->rescan(dev); + module_put(drv->owner); + } } /** diff -Nru a/drivers/scsi/scsi_syms.c b/drivers/scsi/scsi_syms.c --- a/drivers/scsi/scsi_syms.c Mon Jun 9 23:16:12 2003 +++ b/drivers/scsi/scsi_syms.c Mon Jun 9 23:16:12 2003 @@ -29,8 +29,8 @@ * This source file contains the symbol table used by scsi loadable * modules. */ -EXPORT_SYMBOL(scsi_register_device); -EXPORT_SYMBOL(scsi_unregister_device); +EXPORT_SYMBOL(scsi_register_driver); +EXPORT_SYMBOL(scsi_register_interface); EXPORT_SYMBOL(scsi_register_host); EXPORT_SYMBOL(scsi_unregister_host); EXPORT_SYMBOL(scsi_add_host); @@ -89,11 +89,6 @@ */ EXPORT_SYMBOL(scsi_reset_provider); -/* - * These are here only while I debug the rest of the scsi stuff. - */ -EXPORT_SYMBOL(scsi_host_hn_get); -EXPORT_SYMBOL(scsi_host_put); EXPORT_SYMBOL(scsi_device_types); /* diff -Nru a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c --- a/drivers/scsi/scsi_sysfs.c Mon Jun 9 23:16:08 2003 +++ b/drivers/scsi/scsi_sysfs.c Mon Jun 9 23:16:08 2003 @@ -45,45 +45,30 @@ shost_rd_attr(sg_tablesize, "%hu\n"); shost_rd_attr(unchecked_isa_dma, "%d\n"); -static struct class_device_attribute *const shost_attrs[] = { +struct class_device_attribute *scsi_sysfs_shost_attrs[] = { &class_device_attr_unique_id, &class_device_attr_host_busy, &class_device_attr_cmd_per_lun, &class_device_attr_sg_tablesize, &class_device_attr_unchecked_isa_dma, + NULL }; -static struct class shost_class = { +struct class shost_class = { .name = "scsi_host", }; -/** - * scsi_bus_match: - * @dev: - * @dev_driver: - * - * Return value: - **/ -static int scsi_bus_match(struct device *dev, - struct device_driver *dev_driver) +static struct class sdev_class = { + .name = "scsi_device", +}; + +/* all probing is done in the individual ->probe routines */ +static int scsi_bus_match(struct device *dev, struct device_driver *gendrv) { - if (!strcmp("sg", dev_driver->name)) { - if (strstr(dev->bus_id, ":gen")) - return 1; - } else if (!strcmp("st",dev_driver->name)) { - if (strstr(dev->bus_id,":mt")) - return 1; - } else if (!strcmp("sd", dev_driver->name)) { - if ((!strstr(dev->bus_id, ":gen")) && - (!strstr(dev->bus_id, ":mt"))) { - return 1; - } - } - return 0; + return 1; } - -static struct bus_type scsi_bus_type = { +struct bus_type scsi_bus_type = { .name = "scsi", .match = scsi_bus_match, }; @@ -98,45 +83,26 @@ return error; error = class_register(&shost_class); if (error) - return error; + goto bus_unregister; + error = class_register(&sdev_class); + if (error) + goto class_unregister; + return 0; + class_unregister: + class_unregister(&shost_class); + bus_unregister: + bus_unregister(&scsi_bus_type); return error; } void scsi_sysfs_unregister(void) { + class_unregister(&sdev_class); class_unregister(&shost_class); bus_unregister(&scsi_bus_type); } -/** - * scsi_upper_driver_register - register upper level driver. - * @sdev_tp: Upper level driver to register with the scsi bus. - * - * Return value: - * 0 on Success / non-zero on Failure - **/ -int scsi_upper_driver_register(struct Scsi_Device_Template *sdev_tp) -{ - int error = 0; - - sdev_tp->scsi_driverfs_driver.bus = &scsi_bus_type; - error = driver_register(&sdev_tp->scsi_driverfs_driver); - - return error; -} - -/** - * scsi_upper_driver_unregister - unregister upper level driver - * @sdev_tp: Upper level driver to unregister with the scsi bus. - * - **/ -void scsi_upper_driver_unregister(struct Scsi_Device_Template *sdev_tp) -{ - driver_unregister(&sdev_tp->scsi_driverfs_driver); -} - - /* * sdev_show_function: macro to create an attr function that can be used to * show a non-bit field. @@ -237,13 +203,14 @@ static ssize_t store_rescan_field (struct device *dev, const char *buf, size_t count) { - scsi_rescan_device(to_scsi_device(dev)); + scsi_rescan_device(dev); return 0; } static DEVICE_ATTR(rescan, S_IRUGO | S_IWUSR, show_rescan_field, store_rescan_field) -static struct device_attribute * const sdev_attrs[] = { +/* Default template for device attributes. May NOT be modified */ +struct device_attribute *scsi_sysfs_sdev_attrs[] = { &dev_attr_device_blocked, &dev_attr_queue_depth, &dev_attr_type, @@ -254,6 +221,7 @@ &dev_attr_rev, &dev_attr_online, &dev_attr_rescan, + NULL }; static void scsi_device_release(struct device *dev) @@ -277,19 +245,34 @@ { int error = 0, i; + device_initialize(&sdev->sdev_driverfs_dev); sprintf(sdev->sdev_driverfs_dev.bus_id,"%d:%d:%d:%d", sdev->host->host_no, sdev->channel, sdev->id, sdev->lun); sdev->sdev_driverfs_dev.parent = &sdev->host->host_gendev; sdev->sdev_driverfs_dev.bus = &scsi_bus_type; sdev->sdev_driverfs_dev.release = scsi_device_release; - error = device_register(&sdev->sdev_driverfs_dev); - if (error) + class_device_initialize(&sdev->sdev_classdev); + sdev->sdev_classdev.dev = &sdev->sdev_driverfs_dev; + sdev->sdev_classdev.class = &sdev_class; + snprintf(sdev->sdev_classdev.class_id, BUS_ID_SIZE, "%d:%d:%d:%d", + sdev->host->host_no, sdev->channel, sdev->id, sdev->lun); + + error = device_add(&sdev->sdev_driverfs_dev); + if (error) { + printk(KERN_INFO "error 1\n"); + return error; + } + error = class_device_add(&sdev->sdev_classdev); + if (error) { + printk(KERN_INFO "error 2\n"); + device_unregister(&sdev->sdev_driverfs_dev); return error; + } - for (i = 0; !error && i < ARRAY_SIZE(sdev_attrs); i++) + for (i = 0; !error && sdev->host->hostt->sdev_attrs[i] != NULL; i++) error = device_create_file(&sdev->sdev_driverfs_dev, - sdev_attrs[i]); + sdev->host->hostt->sdev_attrs[i]); if (error) scsi_device_unregister(sdev); @@ -305,11 +288,26 @@ { int i; - for (i = 0; i < ARRAY_SIZE(sdev_attrs); i++) - device_remove_file(&sdev->sdev_driverfs_dev, sdev_attrs[i]); + for (i = 0; sdev->host->hostt->sdev_attrs[i] != NULL; i++) + device_remove_file(&sdev->sdev_driverfs_dev, sdev->host->hostt->sdev_attrs[i]); + class_device_unregister(&sdev->sdev_classdev); device_unregister(&sdev->sdev_driverfs_dev); } +int scsi_register_driver(struct device_driver *drv) +{ + drv->bus = &scsi_bus_type; + + return driver_register(drv); +} + +int scsi_register_interface(struct class_interface *intf) +{ + intf->class = &sdev_class; + + return class_interface_register(intf); +} + static void scsi_host_release(struct device *dev) { struct Scsi_Host *shost; @@ -347,7 +345,7 @@ int i, error; if (!shost->host_gendev.parent) - shost->host_gendev.parent = (dev) ? dev : &legacy_bus; + shost->host_gendev.parent = dev ? dev : &legacy_bus; error = device_add(&shost->host_gendev); if (error) @@ -357,9 +355,9 @@ if (error) goto clean_device; - for (i = 0; !error && i < ARRAY_SIZE(shost_attrs); i++) + for (i = 0; !error && shost->hostt->shost_attrs[i] != NULL; i++) error = class_device_create_file(&shost->class_dev, - shost_attrs[i]); + shost->hostt->shost_attrs[i]); if (error) goto clean_class; @@ -383,3 +381,118 @@ device_del(&shost->host_gendev); } +/** scsi_sysfs_modify_shost_attribute - modify or add a host class attribute + * + * @class_attrs:host class attribute list to be added to or modified + * @attr: individual attribute to change or added + * + * returns zero if successful or error if not + **/ +int scsi_sysfs_modify_shost_attribute(struct class_device_attribute ***class_attrs, + struct class_device_attribute *attr) +{ + int modify = 0; + int num_attrs; + + if(*class_attrs == NULL) + *class_attrs = scsi_sysfs_shost_attrs; + + for(num_attrs=0; (*class_attrs)[num_attrs] != NULL; num_attrs++) + if(strcmp((*class_attrs)[num_attrs]->attr.name, attr->attr.name) == 0) + modify = num_attrs; + + if(*class_attrs == scsi_sysfs_shost_attrs || !modify) { + /* note: need space for null at the end as well */ + struct class_device_attribute **tmp_attrs = kmalloc(sizeof(struct class_device_attribute)*(num_attrs + (modify ? 1 : 2)), GFP_KERNEL); + if(tmp_attrs == NULL) + return -ENOMEM; + memcpy(tmp_attrs, *class_attrs, sizeof(struct class_device_attribute)*num_attrs); + if(*class_attrs != scsi_sysfs_shost_attrs) + kfree(*class_attrs); + *class_attrs = tmp_attrs; + } + if(modify) { + /* spare the caller from having to copy things it's + * not interested in */ + struct class_device_attribute *old_attr = + (*class_attrs)[modify]; + /* extend permissions */ + attr->attr.mode |= old_attr->attr.mode; + + /* override null show/store with default */ + if(attr->show == NULL) + attr->show = old_attr->show; + if(attr->store == NULL) + attr->store = old_attr->store; + (*class_attrs)[modify] = attr; + } else { + (*class_attrs)[num_attrs++] = attr; + (*class_attrs)[num_attrs] = NULL; + } + + return 0; +} +EXPORT_SYMBOL(scsi_sysfs_modify_shost_attribute); + +/** scsi_sysfs_modify_sdev_attribute - modify or add a host device attribute + * + * @dev_attrs: pointer to the attribute list to be added to or modified + * @attr: individual attribute to change or added + * + * returns zero if successful or error if not + **/ +int scsi_sysfs_modify_sdev_attribute(struct device_attribute ***dev_attrs, + struct device_attribute *attr) +{ + int modify = 0; + int num_attrs; + + if(*dev_attrs == NULL) + *dev_attrs = scsi_sysfs_sdev_attrs; + + for(num_attrs=0; (*dev_attrs)[num_attrs] != NULL; num_attrs++) + if(strcmp((*dev_attrs)[num_attrs]->attr.name, attr->attr.name) == 0) + modify = num_attrs; + + if(*dev_attrs == scsi_sysfs_sdev_attrs || !modify) { + /* note: need space for null at the end as well */ + struct device_attribute **tmp_attrs = kmalloc(sizeof(struct device_attribute)*(num_attrs + (modify ? 1 : 2)), GFP_KERNEL); + if(tmp_attrs == NULL) + return -ENOMEM; + memcpy(tmp_attrs, *dev_attrs, sizeof(struct device_attribute)*num_attrs); + if(*dev_attrs != scsi_sysfs_sdev_attrs) + kfree(*dev_attrs); + *dev_attrs = tmp_attrs; + } + if(modify) { + /* spare the caller from having to copy things it's + * not interested in */ + struct device_attribute *old_attr = + (*dev_attrs)[modify]; + /* extend permissions */ + attr->attr.mode |= old_attr->attr.mode; + + /* override null show/store with default */ + if(attr->show == NULL) + attr->show = old_attr->show; + if(attr->store == NULL) + attr->store = old_attr->store; + (*dev_attrs)[modify] = attr; + } else { + (*dev_attrs)[num_attrs++] = attr; + (*dev_attrs)[num_attrs] = NULL; + } + + return 0; +} +EXPORT_SYMBOL(scsi_sysfs_modify_sdev_attribute); + +void scsi_sysfs_release_attributes(struct SHT *hostt) +{ + if(hostt->sdev_attrs != scsi_sysfs_sdev_attrs) + kfree(hostt->sdev_attrs); + + if(hostt->shost_attrs != scsi_sysfs_shost_attrs) + kfree(hostt->shost_attrs); +} +EXPORT_SYMBOL(scsi_sysfs_release_attributes); diff -Nru a/drivers/scsi/sd.c b/drivers/scsi/sd.c --- a/drivers/scsi/sd.c Mon Jun 9 23:16:16 2003 +++ b/drivers/scsi/sd.c Mon Jun 9 23:16:16 2003 @@ -73,8 +73,7 @@ #define SD_MAX_RETRIES 5 struct scsi_disk { - struct list_head list; /* list of all scsi_disks */ - struct Scsi_Device_Template *driver; /* always &sd_template */ + struct scsi_driver *driver; /* always &sd_template */ struct scsi_device *device; struct gendisk *disk; sector_t capacity; /* size in 512-byte sectors */ @@ -85,37 +84,31 @@ unsigned RCD : 1; /* state of disk RCD bit, unused */ }; -static LIST_HEAD(sd_devlist); -static spinlock_t sd_devlist_lock = SPIN_LOCK_UNLOCKED; - static unsigned long sd_index_bits[SD_DISKS / BITS_PER_LONG]; static spinlock_t sd_index_lock = SPIN_LOCK_UNLOCKED; static void sd_init_onedisk(struct scsi_disk * sdkp, struct gendisk *disk); static void sd_rw_intr(struct scsi_cmnd * SCpnt); -static int sd_attach(struct scsi_device *); -static void sd_detach(struct scsi_device *); -static void sd_rescan(struct scsi_device *); +static int sd_probe(struct device *); +static int sd_remove(struct device *); +static void sd_shutdown(struct device *dev); +static void sd_rescan(struct device *); static int sd_init_command(struct scsi_cmnd *); static int sd_synchronize_cache(struct scsi_disk *, int); -static int sd_notifier(struct notifier_block *, unsigned long, void *); static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname, struct scsi_request *SRpnt, unsigned char *buffer); -static struct notifier_block sd_notifier_block = {sd_notifier, NULL, 0}; -static struct Scsi_Device_Template sd_template = { - .module = THIS_MODULE, - .list = LIST_HEAD_INIT(sd_template.list), - .name = "disk", - .scsi_type = TYPE_DISK, - .attach = sd_attach, - .detach = sd_detach, - .rescan = sd_rescan, - .init_command = sd_init_command, - .scsi_driverfs_driver = { - .name = "sd", +static struct scsi_driver sd_template = { + .owner = THIS_MODULE, + .gendrv = { + .name = "sd", + .probe = sd_probe, + .remove = sd_remove, + .shutdown = sd_shutdown, }, + .rescan = sd_rescan, + .init_command = sd_init_command, }; static int sd_major(int major_idx) @@ -133,36 +126,6 @@ } } -static struct scsi_disk *sd_find_by_sdev(Scsi_Device *sd) -{ - struct scsi_disk *sdkp; - - spin_lock(&sd_devlist_lock); - list_for_each_entry(sdkp, &sd_devlist, list) { - if (sdkp->device == sd) { - spin_unlock(&sd_devlist_lock); - return sdkp; - } - } - - spin_unlock(&sd_devlist_lock); - return NULL; -} - -static inline void sd_devlist_insert(struct scsi_disk *sdkp) -{ - spin_lock(&sd_devlist_lock); - list_add(&sdkp->list, &sd_devlist); - spin_unlock(&sd_devlist_lock); -} - -static inline void sd_devlist_remove(struct scsi_disk *sdkp) -{ - spin_lock(&sd_devlist_lock); - list_del(&sdkp->list); - spin_unlock(&sd_devlist_lock); -} - static inline struct scsi_disk *scsi_disk(struct gendisk *disk) { return container_of(disk->private_data, struct scsi_disk, driver); @@ -320,7 +283,8 @@ SCpnt->cmnd[12] = (unsigned char) (this_count >> 8) & 0xff; SCpnt->cmnd[13] = (unsigned char) this_count & 0xff; SCpnt->cmnd[14] = SCpnt->cmnd[15] = 0; - } else if (((this_count > 0xff) || (block > 0x1fffff)) || SCpnt->device->ten) { + } else if ((this_count > 0xff) || (block > 0x1fffff) || + SCpnt->device->use_10_for_rw) { if (this_count > 0xffff) this_count = 0xffff; @@ -635,12 +599,13 @@ return 1; } -static void sd_rescan(struct scsi_device * sdp) +static void sd_rescan(struct device *dev) { - unsigned char *buffer; - struct scsi_disk *sdkp = sd_find_by_sdev(sdp); + struct scsi_device *sdp = to_scsi_device(dev); + struct scsi_disk *sdkp = dev_get_drvdata(dev); struct gendisk *gd; struct scsi_request *SRpnt; + unsigned char *buffer; if (!sdkp || sdp->online == FALSE || !sdkp->media_present) return; @@ -768,11 +733,14 @@ break; case ILLEGAL_REQUEST: - if (SCpnt->device->ten == 1) { - if (SCpnt->cmnd[0] == READ_10 || - SCpnt->cmnd[0] == WRITE_10) - SCpnt->device->ten = 0; - } + if (SCpnt->device->use_10_for_rw && + (SCpnt->cmnd[0] == READ_10 || + SCpnt->cmnd[0] == WRITE_10)) + SCpnt->device->use_10_for_rw = 0; + if (SCpnt->device->use_10_for_ms && + (SCpnt->cmnd[0] == MODE_SENSE_10 || + SCpnt->cmnd[0] == MODE_SELECT_10)) + SCpnt->device->use_10_for_ms = 0; break; default: @@ -835,9 +803,10 @@ the_result = SRpnt->sr_result; retries++; - } while (retries < 3 && !scsi_status_is_good(the_result) - && ((driver_byte(the_result) & DRIVER_SENSE) - && SRpnt->sr_sense_buffer[2] == UNIT_ATTENTION)); + } while (retries < 3 && + (!scsi_status_is_good(the_result) || + ((driver_byte(the_result) & DRIVER_SENSE) && + SRpnt->sr_sense_buffer[2] == UNIT_ATTENTION))); /* * If the drive has indicated to us that it doesn't have @@ -855,7 +824,12 @@ break; } - + /* + * The device does not want the automatic start to be issued. + */ + if (sdkp->device->no_start_on_add) { + break; + } /* * If manual intervention is required, or this is an @@ -1093,16 +1067,29 @@ sdkp->device->sector_size = sector_size; } +/* called with buffer of length 512 */ static int -sd_do_mode_sense6(struct scsi_device *sdp, struct scsi_request *SRpnt, - int dbd, int modepage, unsigned char *buffer, int len) { - unsigned char cmd[8]; +sd_do_mode_sense(struct scsi_request *SRpnt, int dbd, int modepage, + unsigned char *buffer, int len) { + unsigned char cmd[12]; - memset((void *) &cmd[0], 0, 8); - cmd[0] = MODE_SENSE; + memset((void *) &cmd[0], 0, 12); cmd[1] = dbd; cmd[2] = modepage; - cmd[4] = len; + + if (SRpnt->sr_device->use_10_for_ms) { + if (len < 8) + len = 8; + + cmd[0] = MODE_SENSE_10; + cmd[8] = len; + } else { + if (len < 4) + len = 4; + + cmd[0] = MODE_SENSE; + cmd[4] = len; + } SRpnt->sr_cmd_len = 0; SRpnt->sr_sense_buffer[0] = 0; @@ -1119,11 +1106,11 @@ /* * read write protect setting, if possible - called only in sd_init_onedisk() + * called with buffer of length 512 */ static void sd_read_write_protect_flag(struct scsi_disk *sdkp, char *diskname, struct scsi_request *SRpnt, unsigned char *buffer) { - struct scsi_device *sdp = sdkp->device; int res; /* @@ -1131,7 +1118,7 @@ * We have to start carefully: some devices hang if we ask * for more than is available. */ - res = sd_do_mode_sense6(sdp, SRpnt, 0, 0x3F, buffer, 4); + res = sd_do_mode_sense(SRpnt, 0, 0x3F, buffer, 4); /* * Second attempt: ask for page 0 @@ -1139,13 +1126,13 @@ * Sense Key 5: Illegal Request, Sense Code 24: Invalid field in CDB. */ if (res) - res = sd_do_mode_sense6(sdp, SRpnt, 0, 0, buffer, 4); + res = sd_do_mode_sense(SRpnt, 0, 0, buffer, 4); /* * Third attempt: ask 255 bytes, as we did earlier. */ if (res) - res = sd_do_mode_sense6(sdp, SRpnt, 0, 0x3F, buffer, 255); + res = sd_do_mode_sense(SRpnt, 0, 0x3F, buffer, 255); if (res) { printk(KERN_WARNING @@ -1161,25 +1148,25 @@ /* * sd_read_cache_type - called only from sd_init_onedisk() + * called with buffer of length 512 */ static void sd_read_cache_type(struct scsi_disk *sdkp, char *diskname, struct scsi_request *SRpnt, unsigned char *buffer) { - struct scsi_device *sdp = sdkp->device; int len = 0, res; const int dbd = 0x08; /* DBD */ const int modepage = 0x08; /* current values, cache page */ /* cautiously ask */ - res = sd_do_mode_sense6(sdp, SRpnt, dbd, modepage, buffer, 4); + res = sd_do_mode_sense(SRpnt, dbd, modepage, buffer, 4); if (res == 0) { /* that went OK, now ask for the proper length */ len = buffer[0] + 1; if (len > 128) len = 128; - res = sd_do_mode_sense6(sdp, SRpnt, dbd, modepage, buffer, len); + res = sd_do_mode_sense(SRpnt, dbd, modepage, buffer, len); } if (res == 0 && buffer[3] + 6 < len) { @@ -1278,7 +1265,8 @@ if (sdkp->media_present) sd_read_cache_type(sdkp, disk->disk_name, SRpnt, buffer); - SRpnt->sr_device->ten = 1; + SRpnt->sr_device->use_10_for_rw = 1; + SRpnt->sr_device->use_10_for_ms = 0; SRpnt->sr_device->remap = 1; leave: @@ -1288,10 +1276,10 @@ } /** - * sd_attach - called during driver initialization and whenever a + * sd_probe - called during driver initialization and whenever a * new scsi device is attached to the system. It is called once * for each scsi device (not just disks) present. - * @sdp: pointer to mid level scsi device object + * @dev: pointer to device object * * Returns 0 if successful (or not interested in this scsi device * (e.g. scanner)); 1 when there is an error. @@ -1303,17 +1291,19 @@ * and minor number that is chosen here. * * Assume sd_attach is not re-entrant (for time being) - * Also think about sd_attach() and sd_detach() running coincidentally. + * Also think about sd_attach() and sd_remove() running coincidentally. **/ -static int sd_attach(struct scsi_device * sdp) +static int sd_probe(struct device *dev) { + struct scsi_device *sdp = to_scsi_device(dev); struct scsi_disk *sdkp; struct gendisk *gd; u32 index; int error; + error = -ENODEV; if ((sdp->type != TYPE_DISK) && (sdp->type != TYPE_MOD)) - return 1; + goto out; SCSI_LOG_HLQUEUE(3, printk("sd_attach: scsi device: <%d,%d,%d,%d>\n", sdp->host->host_no, sdp->channel, sdp->id, sdp->lun)); @@ -1365,8 +1355,8 @@ gd->private_data = &sdkp->driver; gd->queue = sdkp->device->request_queue; - sd_devlist_insert(sdkp); set_capacity(gd, sdkp->capacity); + dev_set_drvdata(dev, sdkp); add_disk(gd); printk(KERN_NOTICE "Attached scsi %sdisk %s at scsi%d, channel %d, " @@ -1385,44 +1375,42 @@ } /** - * sd_detach - called whenever a scsi disk (previously recognized by - * sd_attach) is detached from the system. It is called (potentially + * sd_remove - called whenever a scsi disk (previously recognized by + * sd_probe) is detached from the system. It is called (potentially * multiple times) during sd module unload. * @sdp: pointer to mid level scsi device object * * Note: this function is invoked from the scsi mid-level. * This function potentially frees up a device name (e.g. /dev/sdc) - * that could be re-used by a subsequent sd_attach(). + * that could be re-used by a subsequent sd_probe(). * This function is not called when the built-in sd driver is "exit-ed". **/ -static void sd_detach(struct scsi_device * sdp) +static int sd_remove(struct device *dev) { - struct scsi_disk *sdkp; - - SCSI_LOG_HLQUEUE(3, printk("sd_detach: <%d,%d,%d,%d>\n", - sdp->host->host_no, sdp->channel, sdp->id, - sdp->lun)); - - sdkp = sd_find_by_sdev(sdp); - if (!sdkp) - return; - - /* check that we actually have a write back cache to synchronize */ - if (sdkp->WCE) { - printk(KERN_NOTICE "Synchronizing SCSI cache: "); - sd_synchronize_cache(sdkp, 1); - printk("\n"); - } + struct scsi_disk *sdkp = dev_get_drvdata(dev); - sd_devlist_remove(sdkp); del_gendisk(sdkp->disk); spin_lock(&sd_index_lock); clear_bit(sdkp->index, sd_index_bits); spin_unlock(&sd_index_lock); + sd_shutdown(dev); put_disk(sdkp->disk); kfree(sdkp); + + return 0; +} + +static void sd_shutdown(struct device *dev) +{ + struct scsi_disk *sdkp = dev_get_drvdata(dev); + + if (sdkp->WCE) { + printk(KERN_NOTICE "Synchronizing SCSI cache: "); + sd_synchronize_cache(sdkp, 1); + printk("\n"); + } } /** @@ -1433,7 +1421,7 @@ **/ static int __init init_sd(void) { - int majors = 0, rc = -ENODEV, i; + int majors = 0, i; SCSI_LOG_HLQUEUE(3, printk("init_sd: sd driver entry point\n")); @@ -1444,11 +1432,7 @@ if (!majors) return -ENODEV; - rc = scsi_register_device(&sd_template); - if (rc) - return rc; - register_reboot_notifier(&sd_notifier_block); - return rc; + return scsi_register_driver(&sd_template.gendrv); } /** @@ -1462,35 +1446,9 @@ SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n")); - unregister_reboot_notifier(&sd_notifier_block); - scsi_unregister_device(&sd_template); + scsi_unregister_driver(&sd_template.gendrv); for (i = 0; i < SD_MAJORS; i++) unregister_blkdev(sd_major(i), "sd"); -} - -/* - * XXX: this function does not take sd_devlist_lock to synchronize - * access to sd_devlist. This should be safe as no other reboot - * notifier can access it. - */ -static int sd_notifier(struct notifier_block *n, unsigned long event, void *p) -{ - if (event != SYS_RESTART && - event != SYS_HALT && - event != SYS_POWER_OFF) - return NOTIFY_DONE; - - if (!list_empty(&sd_devlist)) { - struct scsi_disk *sdkp; - - printk(KERN_NOTICE "Synchronizing SCSI caches: "); - list_for_each_entry(sdkp, &sd_devlist, list) - if (sdkp->WCE) - sd_synchronize_cache(sdkp, 1); - printk("\n"); - } - - return NOTIFY_OK; } /* send a SYNCHRONIZE CACHE instruction down to the device through the diff -Nru a/drivers/scsi/sg.c b/drivers/scsi/sg.c --- a/drivers/scsi/sg.c Mon Jun 9 23:16:11 2003 +++ b/drivers/scsi/sg.c Mon Jun 9 23:16:11 2003 @@ -18,8 +18,8 @@ * */ #include <linux/config.h> -static char *sg_version_str = "3.5.28 [20030308]"; -static int sg_version_num = 30528; /* 2 digits for each component */ +static char *sg_version_str = "3.5.29 [20030529]"; +static int sg_version_num = 30529; /* 2 digits for each component */ /* * D. P. Gilbert (dgilbert@interlog.com, dougg@triode.net.au), notes: * - scsi logging is available via SCSI_LOG_TIMEOUT macros. First @@ -112,24 +112,17 @@ #define SG_DEV_ARR_LUMP 6 /* amount to over allocate sg_dev_arr by */ -static int sg_attach(Scsi_Device *); -static void sg_detach(Scsi_Device *); +static int sg_add(struct class_device *); +static void sg_remove(struct class_device *); static Scsi_Request *dummy_cmdp; /* only used for sizeof */ static rwlock_t sg_dev_arr_lock = RW_LOCK_UNLOCKED; /* Also used to lock file descriptor list for device */ -static struct Scsi_Device_Template sg_template = { - .module = THIS_MODULE, - .list = LIST_HEAD_INIT(sg_template.list), - .name = "generic", - .scsi_type = 0xff, - .attach = sg_attach, - .detach = sg_detach, - .scsi_driverfs_driver = { - .name = "sg", - }, +static struct class_interface sg_interface = { + .add = sg_add, + .remove = sg_remove, }; typedef struct sg_scatter_hold { /* holding area for scsi scatter gather info */ @@ -180,15 +173,13 @@ } Sg_fd; typedef struct sg_device { /* holds the state of each scsi generic device */ - struct Scsi_Device_Template *driver; - Scsi_Device *device; + struct scsi_device *device; wait_queue_head_t o_excl_wait; /* queue open() when O_EXCL in use */ int sg_tablesize; /* adapter's max scatter-gather table size */ Sg_fd *headfp; /* first open fd belonging to this device */ volatile char detached; /* 0->attached, 1->detached pending removal */ volatile char exclude; /* opened for exclusive access */ char sgdebug; /* 0->off, 1->sense, 9->dump dev, 10-> all devs */ - struct device sg_driverfs_dev; struct gendisk *disk; } Sg_device; @@ -1328,27 +1319,10 @@ .fasync = sg_fasync, }; -/* Driverfs file support */ -static ssize_t -sg_device_kdev_read(struct device *driverfs_dev, char *page) -{ - Sg_device *sdp = list_entry(driverfs_dev, Sg_device, sg_driverfs_dev); - return sprintf(page, "%x\n", MKDEV(sdp->disk->major, - sdp->disk->first_minor)); -} -static DEVICE_ATTR(kdev,S_IRUGO,sg_device_kdev_read,NULL); - -static ssize_t -sg_device_type_read(struct device *driverfs_dev, char *page) -{ - return sprintf(page, "CHR\n"); -} - -static DEVICE_ATTR(type,S_IRUGO,sg_device_type_read,NULL); - static int -sg_attach(Scsi_Device * scsidp) +sg_add(struct class_device *cdev) { + struct scsi_device *scsidp = to_scsi_device(cdev->dev); struct gendisk *disk; Sg_device *sdp = NULL; unsigned long iflags; @@ -1416,8 +1390,6 @@ SCSI_LOG_TIMEOUT(3, printk("sg_attach: dev=%d \n", k)); memset(sdp, 0, sizeof(*sdp)); - sdp->driver = &sg_template; - disk->private_data = &sdp->driver; sprintf(disk->disk_name, "sg%d", k); disk->major = SCSI_GENERIC_MAJOR; disk->first_minor = k; @@ -1430,40 +1402,20 @@ sdp->detached = 0; sdp->sg_tablesize = scsidp->host ? scsidp->host->sg_tablesize : 0; - memset(&sdp->sg_driverfs_dev, 0, sizeof (struct device)); - snprintf(sdp->sg_driverfs_dev.bus_id, BUS_ID_SIZE, "%s:gen", - scsidp->sdev_driverfs_dev.bus_id); - snprintf(sdp->sg_driverfs_dev.name, DEVICE_NAME_SIZE, "%sgeneric", - scsidp->sdev_driverfs_dev.name); - sdp->sg_driverfs_dev.parent = &scsidp->sdev_driverfs_dev; - sdp->sg_driverfs_dev.bus = scsidp->sdev_driverfs_dev.bus; - sg_nr_dev++; sg_dev_arr[k] = sdp; write_unlock_irqrestore(&sg_dev_arr_lock, iflags); - device_register(&sdp->sg_driverfs_dev); - device_create_file(&sdp->sg_driverfs_dev, &dev_attr_type); - device_create_file(&sdp->sg_driverfs_dev, &dev_attr_kdev); - devfs_mk_cdev(MKDEV(SCSI_GENERIC_MAJOR, k), S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, "%s/generic", scsidp->devfs_name); - switch (scsidp->type) { - case TYPE_DISK: - case TYPE_MOD: - case TYPE_ROM: - case TYPE_WORM: - case TYPE_TAPE: - break; - default: - printk(KERN_NOTICE - "Attached scsi generic sg%d at scsi%d, channel" - " %d, id %d, lun %d, type %d\n", k, - scsidp->host->host_no, scsidp->channel, scsidp->id, - scsidp->lun, scsidp->type); - } + printk(KERN_NOTICE + "Attached scsi generic sg%d at scsi%d, channel" + " %d, id %d, lun %d, type %d\n", k, + scsidp->host->host_no, scsidp->channel, scsidp->id, + scsidp->lun, scsidp->type); + return 0; out: @@ -1472,8 +1424,9 @@ } static void -sg_detach(Scsi_Device * scsidp) +sg_remove(struct class_device *cdev) { + struct scsi_device *scsidp = to_scsi_device(cdev->dev); Sg_device *sdp = NULL; unsigned long iflags; Sg_fd *sfp; @@ -1524,9 +1477,6 @@ if (sdp) { devfs_remove("%s/generic", scsidp->devfs_name); - device_remove_file(&sdp->sg_driverfs_dev, &dev_attr_type); - device_remove_file(&sdp->sg_driverfs_dev, &dev_attr_kdev); - device_unregister(&sdp->sg_driverfs_dev); put_disk(sdp->disk); sdp->disk = NULL; if (NULL == sdp->headfp) @@ -1550,64 +1500,6 @@ MODULE_PARM_DESC(def_reserved_size, "size of buffer reserved for each fd"); -static ssize_t sg_allow_dio_show(struct device_driver * ddp, char * buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", sg_allow_dio); -} -static ssize_t sg_allow_dio_store(struct device_driver * ddp, - const char * buf, size_t count) -{ - if (1 == sscanf(buf, "%d", &sg_allow_dio)) { - sg_allow_dio = sg_allow_dio ? 1 : 0; - return count; - } - return -EINVAL; -} -DRIVER_ATTR(allow_dio, S_IRUGO | S_IWUSR, sg_allow_dio_show, - sg_allow_dio_store) - -static ssize_t sg_def_reserved_show(struct device_driver * ddp, char * buf) -{ - return snprintf(buf, PAGE_SIZE, "%d\n", sg_big_buff); -} -static ssize_t sg_def_reserved_store(struct device_driver * ddp, - const char * buf, size_t count) -{ - if (1 == sscanf(buf, "%d", &def_reserved_size)) { - if (def_reserved_size >= 0) { - sg_big_buff = def_reserved_size; - return count; - } - } - return -EINVAL; -} -DRIVER_ATTR(def_reserved_size, S_IRUGO | S_IWUSR, sg_def_reserved_show, - sg_def_reserved_store) - -static ssize_t sg_version_show(struct device_driver * ddp, char * buf) -{ - return snprintf(buf, PAGE_SIZE, "%s\n", sg_version_str); -} -DRIVER_ATTR(version, S_IRUGO, sg_version_show, NULL) - -static void do_create_driverfs_files(void) -{ - struct device_driver * driverfs = &sg_template.scsi_driverfs_driver; - - driver_create_file(driverfs, &driver_attr_allow_dio); - driver_create_file(driverfs, &driver_attr_def_reserved_size); - driver_create_file(driverfs, &driver_attr_version); -} - -static void do_remove_driverfs_files(void) -{ - struct device_driver * driverfs = &sg_template.scsi_driverfs_driver; - - driver_remove_file(driverfs, &driver_attr_version); - driver_remove_file(driverfs, &driver_attr_def_reserved_size); - driver_remove_file(driverfs, &driver_attr_allow_dio); -} - static int __init init_sg(void) { @@ -1619,24 +1511,22 @@ rc = register_chrdev(SCSI_GENERIC_MAJOR, "sg", &sg_fops); if (rc) return rc; - rc = scsi_register_device(&sg_template); + rc = scsi_register_interface(&sg_interface); if (rc) return rc; #ifdef CONFIG_PROC_FS sg_proc_init(); #endif /* CONFIG_PROC_FS */ - do_create_driverfs_files(); return 0; } static void __exit exit_sg(void) { - do_remove_driverfs_files(); #ifdef CONFIG_PROC_FS sg_proc_cleanup(); #endif /* CONFIG_PROC_FS */ - scsi_unregister_device(&sg_template); + scsi_unregister_interface(&sg_interface); unregister_chrdev(SCSI_GENERIC_MAJOR, "sg"); if (sg_dev_arr != NULL) { vfree((char *) sg_dev_arr); @@ -1994,11 +1884,8 @@ if (res) return res; - for (; k < schp->k_use_sg; ++k, ++sclp) { - ksglen = (int) sclp->length; - p = sg_scatg2virt(sclp); - if (NULL == p) - break; + for (; p; ++sclp, ksglen = (int) sclp->length, + p = sg_scatg2virt(sclp)) { if (usglen <= 0) break; if (ksglen > usglen) { @@ -2025,6 +1912,9 @@ up += ksglen; usglen -= ksglen; } + ++k; + if (k >= schp->k_use_sg) + return 0; } } } @@ -2151,11 +2041,8 @@ if (res) return res; - for (; k < schp->k_use_sg; ++k, ++sclp) { - ksglen = (int) sclp->length; - p = sg_scatg2virt(sclp); - if (NULL == p) - break; + for (; p; ++sclp, ksglen = (int) sclp->length, + p = sg_scatg2virt(sclp)) { if (usglen <= 0) break; if (ksglen > usglen) { @@ -2182,6 +2069,9 @@ up += ksglen; usglen -= ksglen; } + ++k; + if (k >= schp->k_use_sg) + return 0; } } } diff -Nru a/drivers/scsi/sr.c b/drivers/scsi/sr.c --- a/drivers/scsi/sr.c Mon Jun 9 23:16:08 2003 +++ b/drivers/scsi/sr.c Mon Jun 9 23:16:08 2003 @@ -67,26 +67,20 @@ CDC_PLAY_AUDIO|CDC_RESET|CDC_IOCTLS|CDC_DRIVE_STATUS| \ CDC_CD_R|CDC_CD_RW|CDC_DVD|CDC_DVD_R|CDC_GENERIC_PACKET) -static int sr_attach(struct scsi_device *); -static void sr_detach(struct scsi_device *); +static int sr_probe(struct device *); +static int sr_remove(struct device *); static int sr_init_command(struct scsi_cmnd *); -static struct Scsi_Device_Template sr_template = { - .module = THIS_MODULE, - .list = LIST_HEAD_INIT(sr_template.list), - .name = "cdrom", - .scsi_type = TYPE_ROM, - .attach = sr_attach, - .detach = sr_detach, - .init_command = sr_init_command, - .scsi_driverfs_driver = { - .name = "sr", +static struct scsi_driver sr_template = { + .owner = THIS_MODULE, + .gendrv = { + .name = "sr", + .probe = sr_probe, + .remove = sr_remove, }, + .init_command = sr_init_command, }; -static LIST_HEAD(sr_devlist); -static spinlock_t sr_devlist_lock = SPIN_LOCK_UNLOCKED; - static unsigned long sr_index_bits[SR_DISKS / BITS_PER_LONG]; static spinlock_t sr_index_lock = SPIN_LOCK_UNLOCKED; @@ -99,37 +93,6 @@ static int sr_media_change(struct cdrom_device_info *, int); static int sr_packet(struct cdrom_device_info *, struct cdrom_generic_command *); -static Scsi_CD *sr_find_by_sdev(Scsi_Device *sd) -{ - struct list_head *p; - Scsi_CD *cd; - - spin_lock(&sr_devlist_lock); - list_for_each(p, &sr_devlist) { - cd = list_entry(p, Scsi_CD, list); - if (cd->device == sd) { - spin_unlock(&sr_devlist_lock); - return cd; - } - } - spin_unlock(&sr_devlist_lock); - return NULL; -} - -static inline void sr_devlist_insert(Scsi_CD *cd) -{ - spin_lock(&sr_devlist_lock); - list_add(&cd->list, &sr_devlist); - spin_unlock(&sr_devlist_lock); -} - -static inline void sr_devlist_remove(Scsi_CD *cd) -{ - spin_lock(&sr_devlist_lock); - list_del(&cd->list); - spin_unlock(&sr_devlist_lock); -} - static struct cdrom_device_ops sr_dops = { .open = sr_open, .release = sr_release, @@ -506,14 +469,16 @@ scsi_device_put(cd->device); } -static int sr_attach(struct scsi_device *sdev) +static int sr_probe(struct device *dev) { + struct scsi_device *sdev = to_scsi_device(dev); struct gendisk *disk; struct scsi_cd *cd; int minor, error; + error = -ENODEV; if (sdev->type != TYPE_ROM && sdev->type != TYPE_WORM) - return 1; + goto fail; error = -ENOMEM; cd = kmalloc(sizeof(*cd), GFP_KERNEL); @@ -559,7 +524,8 @@ sprintf(cd->cdi.name, "sr%d", minor); sdev->sector_size = 2048; /* A guess, just in case */ - sdev->ten = 1; + sdev->use_10_for_rw = 1; + sdev->use_10_for_ms = 0; sdev->remap = 1; /* FIXME: need to handle a get_capabilities failure properly ?? */ @@ -574,8 +540,8 @@ disk->private_data = &cd->driver; disk->queue = sdev->request_queue; + dev_set_drvdata(dev, cd); add_disk(disk); - sr_devlist_insert(cd); printk(KERN_DEBUG "Attached scsi CD-ROM %s at scsi%d, channel %d, id %d, lun %d\n", @@ -806,15 +772,10 @@ return cgc->stat; } -static void sr_detach(struct scsi_device * SDp) +static int sr_remove(struct device *dev) { - struct scsi_cd *cd; + struct scsi_cd *cd = dev_get_drvdata(dev); - cd = sr_find_by_sdev(SDp); - if (!cd) - return; - - sr_devlist_remove(cd); del_gendisk(cd->disk); spin_lock(&sr_index_lock); @@ -824,6 +785,8 @@ put_disk(cd->disk); unregister_cdrom(&cd->cdi); kfree(cd); + + return 0; } static int __init init_sr(void) @@ -833,12 +796,12 @@ rc = register_blkdev(SCSI_CDROM_MAJOR, "sr"); if (rc) return rc; - return scsi_register_device(&sr_template); + return scsi_register_driver(&sr_template.gendrv); } static void __exit exit_sr(void) { - scsi_unregister_device(&sr_template); + scsi_unregister_driver(&sr_template.gendrv); unregister_blkdev(SCSI_CDROM_MAJOR, "sr"); } diff -Nru a/drivers/scsi/sr.h b/drivers/scsi/sr.h --- a/drivers/scsi/sr.h Mon Jun 9 23:16:10 2003 +++ b/drivers/scsi/sr.h Mon Jun 9 23:16:10 2003 @@ -25,8 +25,7 @@ #define IOCTL_TIMEOUT 30*HZ typedef struct scsi_cd { - struct Scsi_Device_Template *driver; - struct list_head list; + struct scsi_driver *driver; unsigned capacity; /* size in blocks */ Scsi_Device *device; unsigned int vendor; /* vendor code, see sr_vendor.c */ diff -Nru a/drivers/scsi/st.c b/drivers/scsi/st.c --- a/drivers/scsi/st.c Mon Jun 9 23:16:15 2003 +++ b/drivers/scsi/st.c Mon Jun 9 23:16:15 2003 @@ -170,22 +170,19 @@ unsigned long, size_t, int); static int sgl_unmap_user_pages(struct scatterlist *, const unsigned int, int); -static int st_attach(Scsi_Device *); -static void st_detach(Scsi_Device *); +static int st_probe(struct device *); +static int st_remove(struct device *); static void do_create_driverfs_files(void); static void do_remove_driverfs_files(void); -static struct Scsi_Device_Template st_template = { - .module = THIS_MODULE, - .list = LIST_HEAD_INIT(st_template.list), - .name = "tape", - .scsi_type = TYPE_TAPE, - .attach = st_attach, - .detach = st_detach, - .scsi_driverfs_driver = { - .name = "st", +static struct scsi_driver st_template = { + .owner = THIS_MODULE, + .gendrv = { + .name = "st", + .probe = st_probe, + .remove = st_remove, }, }; @@ -3704,8 +3701,9 @@ .release = st_release, }; -static int st_attach(Scsi_Device * SDp) +static int st_probe(struct device *dev) { + struct scsi_device *SDp = to_scsi_device(dev); struct gendisk *disk; Scsi_Tape *tpnt; ST_mode *STm; @@ -3716,13 +3714,13 @@ u64 bounce_limit; if (SDp->type != TYPE_TAPE) - return 1; + return -ENODEV; if ((stp = st_incompatible(SDp))) { printk(KERN_INFO "st: Found incompatible tape at scsi%d, channel %d, id %d, lun %d\n", SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); printk(KERN_INFO "st: The suggested driver is %s.\n", stp); - return 1; + return -ENODEV; } i = SDp->host->sg_tablesize; @@ -3862,43 +3860,11 @@ write_unlock(&st_dev_arr_lock); for (mode = 0; mode < ST_NBR_MODES; ++mode) { - char name[8]; - /* Rewind entry */ - sprintf(name, "mt%s", st_formats[mode]); - - sprintf(tpnt->driverfs_dev_r[mode].bus_id, "%s:%s", - SDp->sdev_driverfs_dev.bus_id, name); - sprintf(tpnt->driverfs_dev_r[mode].name, "%s%s", - SDp->sdev_driverfs_dev.name, name); - tpnt->driverfs_dev_r[mode].parent = &SDp->sdev_driverfs_dev; - tpnt->driverfs_dev_r[mode].bus = SDp->sdev_driverfs_dev.bus; - tpnt->driverfs_dev_r[mode].driver_data = - (void *)(long)__mkdev(SCSI_TAPE_MAJOR, dev_num + (mode << 5)); - device_register(&tpnt->driverfs_dev_r[mode]); - device_create_file(&tpnt->driverfs_dev_r[mode], - &dev_attr_type); - device_create_file(&tpnt->driverfs_dev_r[mode], &dev_attr_kdev); devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, dev_num + (mode << 5)), S_IFCHR | S_IRUGO | S_IWUGO, "%s/mt%s", SDp->devfs_name, st_formats[mode]); - /* No-rewind entry */ - sprintf (name, "mt%sn", st_formats[mode]); - - sprintf(tpnt->driverfs_dev_n[mode].bus_id, "%s:%s", - SDp->sdev_driverfs_dev.bus_id, name); - sprintf(tpnt->driverfs_dev_n[mode].name, "%s%s", - SDp->sdev_driverfs_dev.name, name); - tpnt->driverfs_dev_n[mode].parent= &SDp->sdev_driverfs_dev; - tpnt->driverfs_dev_n[mode].bus = SDp->sdev_driverfs_dev.bus; - tpnt->driverfs_dev_n[mode].driver_data = - (void *)(long)__mkdev(SCSI_TAPE_MAJOR, dev_num + (mode << 5) + 128); - device_register(&tpnt->driverfs_dev_n[mode]); - device_create_file(&tpnt->driverfs_dev_n[mode], - &dev_attr_type); - device_create_file(&tpnt->driverfs_dev_n[mode], - &dev_attr_kdev); devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, dev_num + (mode << 5) + 128), S_IFCHR | S_IRUGO | S_IWUGO, "%s/mt%sn", SDp->devfs_name, st_formats[mode]); @@ -3918,11 +3884,12 @@ out_buffer_free: kfree(buffer); out: - return 1; + return -ENODEV; }; -static void st_detach(Scsi_Device * SDp) +static int st_remove(struct device *dev) { + Scsi_Device *SDp = to_scsi_device(dev); Scsi_Tape *tpnt; int i, mode; @@ -3937,16 +3904,6 @@ for (mode = 0; mode < ST_NBR_MODES; ++mode) { devfs_remove("%s/mt%s", SDp->devfs_name, st_formats[mode]); devfs_remove("%s/mt%sn", SDp->devfs_name, st_formats[mode]); - device_remove_file(&tpnt->driverfs_dev_r[mode], - &dev_attr_type); - device_remove_file(&tpnt->driverfs_dev_r[mode], - &dev_attr_kdev); - device_unregister(&tpnt->driverfs_dev_r[mode]); - device_remove_file(&tpnt->driverfs_dev_n[mode], - &dev_attr_type); - device_remove_file(&tpnt->driverfs_dev_n[mode], - &dev_attr_kdev); - device_unregister(&tpnt->driverfs_dev_n[mode]); } tpnt->device = NULL; @@ -3957,12 +3914,12 @@ } put_disk(tpnt->disk); kfree(tpnt); - return; + return 0; } } write_unlock(&st_dev_arr_lock); - return; + return 0; } static int __init init_st(void) @@ -3974,7 +3931,7 @@ verstr, st_fixed_buffer_size, st_max_sg_segs); if (register_chrdev(SCSI_TAPE_MAJOR, "st", &st_fops) >= 0) { - if (scsi_register_device(&st_template) == 0) { + if (scsi_register_driver(&st_template.gendrv) == 0) { do_create_driverfs_files(); return 0; } @@ -3987,20 +3944,10 @@ static void __exit exit_st(void) { - int i; - do_remove_driverfs_files(); - scsi_unregister_device(&st_template); + scsi_unregister_driver(&st_template.gendrv); unregister_chrdev(SCSI_TAPE_MAJOR, "st"); - if (scsi_tapes != NULL) { - for (i=0; i < st_dev_max; ++i) - if (scsi_tapes[i]) { - printk(KERN_WARNING "st: scsi_tapes[] not " - "empty after scsi_unregister_device\n"); - st_detach(scsi_tapes[i]->device); - } - kfree(scsi_tapes); - } + kfree(scsi_tapes); printk(KERN_INFO "st: Unloaded.\n"); } @@ -4035,7 +3982,7 @@ static void do_create_driverfs_files(void) { - struct device_driver *driverfs = &st_template.scsi_driverfs_driver; + struct device_driver *driverfs = &st_template.gendrv; driver_create_file(driverfs, &driver_attr_try_direct_io); driver_create_file(driverfs, &driver_attr_fixed_buffer_size); @@ -4045,7 +3992,7 @@ static void do_remove_driverfs_files(void) { - struct device_driver *driverfs = &st_template.scsi_driverfs_driver; + struct device_driver *driverfs = &st_template.gendrv; driver_remove_file(driverfs, &driver_attr_version); driver_remove_file(driverfs, &driver_attr_max_sg_segs); diff -Nru a/drivers/scsi/st.h b/drivers/scsi/st.h --- a/drivers/scsi/st.h Mon Jun 9 23:16:17 2003 +++ b/drivers/scsi/st.h Mon Jun 9 23:16:17 2003 @@ -70,7 +70,7 @@ /* The tape drive descriptor */ typedef struct { - struct Scsi_Device_Template *driver; + struct scsi_driver *driver; Scsi_Device *device; struct semaphore lock; /* For serialization */ struct completion wait; /* For SCSI commands */ @@ -103,8 +103,6 @@ /* Mode characteristics */ ST_mode modes[ST_NBR_MODES]; int current_mode; - struct device driverfs_dev_r[ST_NBR_MODES]; - struct device driverfs_dev_n[ST_NBR_MODES]; /* Status variables */ int partition; diff -Nru a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c --- a/drivers/scsi/sun3_NCR5380.c Mon Jun 9 23:16:07 2003 +++ b/drivers/scsi/sun3_NCR5380.c Mon Jun 9 23:16:07 2003 @@ -726,7 +726,7 @@ printk("NCR5380_print_status: no memory for print buffer\n"); return; } - len = NCR5380_proc_info(pr_bfr, &start, 0, PAGE_SIZE, HOSTNO, 0); + len = NCR5380_proc_info(instance, pr_bfr, &start, 0, PAGE_SIZE, 0); pr_bfr[len] = 0; printk("\n%s\n", pr_bfr); free_page((unsigned long) pr_bfr); @@ -754,11 +754,10 @@ static char *lprint_Scsi_Cmnd (Scsi_Cmnd *cmd, char *pos, char *buffer, int length); -static int NCR5380_proc_info (char *buffer, char **start, off_t offset, - int length, int hostno, int inout) +static int NCR5380_proc_info (struct Scsi_Host *instance, char *buffer, char **start, off_t offset, + int length, int inout) { char *pos = buffer; - struct Scsi_Host *instance; struct NCR5380_hostdata *hostdata; Scsi_Cmnd *ptr; unsigned long flags; @@ -771,9 +770,6 @@ } \ } while (0) - instance = scsi_host_hn_get(hostno); - if (!instance) - return(-ESRCH); hostdata = (struct NCR5380_hostdata *)instance->hostdata; if (inout) { /* Has data been written to the file ? */ diff -Nru a/drivers/scsi/sun3_scsi.h b/drivers/scsi/sun3_scsi.h --- a/drivers/scsi/sun3_scsi.h Mon Jun 9 23:16:07 2003 +++ b/drivers/scsi/sun3_scsi.h Mon Jun 9 23:16:07 2003 @@ -57,8 +57,6 @@ static const char *sun3scsi_info (struct Scsi_Host *); static int sun3scsi_bus_reset(Scsi_Cmnd *); static int sun3scsi_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); -static int sun3scsi_proc_info (char *buffer, char **start, off_t offset, - int length, int hostno, int inout); #ifdef MODULE static int sun3scsi_release (struct Scsi_Host *); #else diff -Nru a/drivers/scsi/sym53c8xx.c b/drivers/scsi/sym53c8xx.c --- a/drivers/scsi/sym53c8xx.c Mon Jun 9 23:16:15 2003 +++ b/drivers/scsi/sym53c8xx.c Mon Jun 9 23:16:15 2003 @@ -1288,8 +1288,8 @@ }; #endif #ifdef SCSI_NCR_PROC_INFO_SUPPORT -static int sym53c8xx_proc_info(char *buffer, char **start, off_t offset, - int length, int hostno, int func); +static int sym53c8xx_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, + int length, int func); #endif /* @@ -14226,22 +14226,17 @@ ** - func = 1 means write (parse user control command) */ -static int sym53c8xx_proc_info(char *buffer, char **start, off_t offset, - int length, int hostno, int func) +static int sym53c8xx_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, + int length, int func) { - struct Scsi_Host *host; struct host_data *host_data; ncb_p ncb = 0; int retv; #ifdef DEBUG_PROC_INFO -printk("sym53c8xx_proc_info: hostno=%d, func=%d\n", hostno, func); +printk("sym53c8xx_proc_info: hostno=%d, func=%d\n", host->host_no, func); #endif - host = scsi_host_hn_get(hostno); - if (!host) - return -EINVAL; - host_data = (struct host_data *) host->hostdata; ncb = host_data->ncb; retv = -EINVAL; @@ -14261,7 +14256,6 @@ } out: - scsi_host_put(host); return retv; } diff -Nru a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c --- a/drivers/scsi/sym53c8xx_2/sym_glue.c Mon Jun 9 23:16:20 2003 +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c Mon Jun 9 23:16:20 2003 @@ -1787,18 +1787,13 @@ * - func = 0 means read (returns adapter infos) * - func = 1 means write (not yet merget from sym53c8xx) */ -static int sym53c8xx_proc_info(char *buffer, char **start, off_t offset, - int length, int hostno, int func) +static int sym53c8xx_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, + int length, int func) { - struct Scsi_Host *host; struct host_data *host_data; hcb_p np = 0; int retv; - host = scsi_host_hn_get(hostno); - if (!host) - return -EINVAL; - host_data = (struct host_data *) host->hostdata; np = host_data->ncb; if (!np) @@ -1821,7 +1816,6 @@ #endif } - scsi_host_put(host); return retv; } #endif /* SYM_LINUX_PROC_INFO_SUPPORT */ diff -Nru a/drivers/scsi/t128.h b/drivers/scsi/t128.h --- a/drivers/scsi/t128.h Mon Jun 9 23:16:08 2003 +++ b/drivers/scsi/t128.h Mon Jun 9 23:16:08 2003 @@ -99,8 +99,6 @@ static int t128_host_reset(Scsi_Cmnd *); static int t128_bus_reset(Scsi_Cmnd *); static int t128_device_reset(Scsi_Cmnd *); -static int t128_proc_info (char *buffer, char **start, off_t offset, - int length, int hostno, int inout); #ifndef NULL #define NULL 0 diff -Nru a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c --- a/drivers/scsi/tmscsim.c Mon Jun 9 23:16:20 2003 +++ b/drivers/scsi/tmscsim.c Mon Jun 9 23:16:20 2003 @@ -2855,12 +2855,11 @@ else SPRINTF(" No ") -int DC390_proc_info (char *buffer, char **start, - off_t offset, int length, int hostno, int inout) +int DC390_proc_info (struct Scsi_Host *shpnt, char *buffer, char **start, + off_t offset, int length, int inout) { int dev, spd, spd1; char *pos = buffer; - PSH shpnt = 0; PACB pACB; PDCB pDCB; PSCSICMD pcmd; @@ -2870,13 +2869,12 @@ while(pACB != (PACB)-1) { - shpnt = pACB->pScsiHost; - if (shpnt->host_no == hostno) break; + if (shpnt == pACB->pScsiHost) + break; pACB = pACB->pNextACB; } if (pACB == (PACB)-1) return(-ESRCH); - if(!shpnt) return(-ESRCH); if(inout) /* Has data been written to the file ? */ return dc390_set_info(buffer, length, pACB); diff -Nru a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c --- a/drivers/scsi/wd33c93.c Mon Jun 9 23:16:15 2003 +++ b/drivers/scsi/wd33c93.c Mon Jun 9 23:16:15 2003 @@ -1913,7 +1913,7 @@ } int -wd33c93_proc_info(char *buf, char **start, off_t off, int len, int hn, int in) +wd33c93_proc_info(struct Scsi_Host *instance, char *buf, char **start, off_t off, int len, int in) { #ifdef PROC_INTERFACE @@ -1921,16 +1921,10 @@ char *bp; char tbuf[128]; struct Scsi_Host *instance; - struct WD33C93_hostdata *hd; Scsi_Cmnd *cmd; int x, i; static int stop = 0; - instance = scsi_host_hn_get(hn); - if (!instance) { - printk("*** Hmm... Can't find host #%d!\n", hn); - return (-ESRCH); - } hd = (struct WD33C93_hostdata *) instance->hostdata; /* If 'in' is TRUE we need to _read_ the proc file. We accept the following diff -Nru a/drivers/scsi/wd33c93.h b/drivers/scsi/wd33c93.h --- a/drivers/scsi/wd33c93.h Mon Jun 9 23:16:08 2003 +++ b/drivers/scsi/wd33c93.h Mon Jun 9 23:16:08 2003 @@ -338,7 +338,7 @@ int wd33c93_abort (Scsi_Cmnd *cmd); int wd33c93_queuecommand (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)); void wd33c93_intr (struct Scsi_Host *instance); -int wd33c93_proc_info(char *, char **, off_t, int, int, int); +int wd33c93_proc_info(struct Scsi_Host *, char *, char **, off_t, int, int); int wd33c93_host_reset (Scsi_Cmnd *); void wd33c93_release(void); diff -Nru a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c --- a/drivers/scsi/wd7000.c Mon Jun 9 23:16:19 2003 +++ b/drivers/scsi/wd7000.c Mon Jun 9 23:16:19 2003 @@ -1372,45 +1372,24 @@ } -static int wd7000_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout) +static int wd7000_proc_info(struct Scsi_Host *host, char *buffer, char **start, off_t offset, int length, int inout) { - struct Scsi_Host *host = NULL; - Adapter *adapter; + Adapter *adapter = (Adapter *)host->hostdata; unsigned long flags; char *pos = buffer; - short i; - #ifdef WD7000_DEBUG Mailbox *ogmbs, *icmbs; short count; #endif /* - * Find the specified host board. - */ - for (i = 0; i < UNITS; i++) - if (wd7000_host[i] && (wd7000_host[i]->host_no == hostno)) { - host = wd7000_host[i]; - - break; - } - - /* - * Host not found! - */ - if (!host) - return (-ESRCH); - - /* * Has data been written to the file ? */ if (inout) return (wd7000_set_info(buffer, length, host)); - adapter = (Adapter *) host->hostdata; - spin_lock_irqsave(host->host_lock, flags); - SPRINTF("Host scsi%d: Western Digital WD-7000 (rev %d.%d)\n", hostno, adapter->rev1, adapter->rev2); + SPRINTF("Host scsi%d: Western Digital WD-7000 (rev %d.%d)\n", host->host_no, adapter->rev1, adapter->rev2); SPRINTF(" IO base: 0x%x\n", adapter->iobase); SPRINTF(" IRQ: %d\n", adapter->irq); SPRINTF(" DMA channel: %d\n", adapter->dma); diff -Nru a/drivers/serial/68328serial.c b/drivers/serial/68328serial.c --- a/drivers/serial/68328serial.c Mon Jun 9 23:16:19 2003 +++ b/drivers/serial/68328serial.c Mon Jun 9 23:16:19 2003 @@ -83,13 +83,12 @@ extern wait_queue_head_t keypress_wait; #endif -struct tty_driver serial_driver, callout_driver; +struct tty_driver serial_driver; static int serial_refcount; /* serial subtype definitions */ #define SERIAL_TYPE_NORMAL 1 -#define SERIAL_TYPE_CALLOUT 2 - + /* number of characters left in xmit buffer before we ask for more */ #define WAKEUP_CHARS 256 @@ -1178,8 +1177,6 @@ */ if (info->flags & S_NORMAL_ACTIVE) info->normal_termios = *tty->termios; - if (info->flags & S_CALLOUT_ACTIVE) - info->callout_termios = *tty->termios; /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. @@ -1220,8 +1217,7 @@ } wake_up_interruptible(&info->open_wait); } - info->flags &= ~(S_NORMAL_ACTIVE|S_CALLOUT_ACTIVE| - S_CLOSING); + info->flags &= ~(S_NORMAL_ACTIVE|S_CLOSING); wake_up_interruptible(&info->close_wait); restore_flags(flags); } @@ -1240,7 +1236,7 @@ shutdown(info); info->event = 0; info->count = 0; - info->flags &= ~(S_NORMAL_ACTIVE|S_CALLOUT_ACTIVE); + info->flags &= ~S_NORMAL_ACTIVE; info->tty = 0; wake_up_interruptible(&info->open_wait); } @@ -1272,25 +1268,6 @@ return -EAGAIN; #endif } - - /* - * If this is a callout device, then just make sure the normal - * device isn't being used. - */ - if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) { - if (info->flags & S_NORMAL_ACTIVE) - return -EBUSY; - if ((info->flags & S_CALLOUT_ACTIVE) && - (info->flags & S_SESSION_LOCKOUT) && - (info->session != current->session)) - return -EBUSY; - if ((info->flags & S_CALLOUT_ACTIVE) && - (info->flags & S_PGRP_LOCKOUT) && - (info->pgrp != current->pgrp)) - return -EBUSY; - info->flags |= S_CALLOUT_ACTIVE; - return 0; - } /* * If non-blocking mode is set, or the port is not enabled, @@ -1298,20 +1275,13 @@ */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { - if (info->flags & S_CALLOUT_ACTIVE) - return -EBUSY; info->flags |= S_NORMAL_ACTIVE; return 0; } - if (info->flags & S_CALLOUT_ACTIVE) { - if (info->normal_termios.c_cflag & CLOCAL) - do_clocal = 1; - } else { - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - } - + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + /* * Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). While we are in @@ -1326,8 +1296,7 @@ info->blocked_open++; while (1) { cli(); - if (!(info->flags & S_CALLOUT_ACTIVE)) - m68k_rtsdtr(info, 1); + m68k_rtsdtr(info, 1); sti(); current->state = TASK_INTERRUPTIBLE; if (tty_hung_up_p(filp) || @@ -1342,8 +1311,7 @@ #endif break; } - if (!(info->flags & S_CALLOUT_ACTIVE) && - !(info->flags & S_CLOSING) && do_clocal) + if (!(info->flags & S_CLOSING) && do_clocal) break; if (signal_pending(current)) { retval = -ERESTARTSYS; @@ -1401,16 +1369,10 @@ } if ((info->count == 1) && (info->flags & S_SPLIT_TERMIOS)) { - if (tty->driver->subtype == SERIAL_TYPE_NORMAL) - *tty->termios = info->normal_termios; - else - *tty->termios = info->callout_termios; + *tty->termios = info->normal_termios; change_speed(info); } - info->session = current->session; - info->pgrp = current->pgrp; - return 0; } @@ -1519,20 +1481,9 @@ serial_driver.hangup = rs_hangup; serial_driver.set_ldisc = rs_set_ldisc; - /* - * The callout device is just like normal device except for - * major number and the subtype code. - */ - callout_driver = serial_driver; - callout_driver.name = "cua"; - callout_driver.major = TTYAUX_MAJOR; - callout_driver.subtype = SERIAL_TYPE_CALLOUT; - if (tty_register_driver(&serial_driver)) panic("Couldn't register serial driver\n"); - if (tty_register_driver(&callout_driver)) - panic("Couldn't register callout driver\n"); - + save_flags(flags); cli(); for(i=0;i<NR_PORTS;i++) { @@ -1551,7 +1502,6 @@ info->blocked_open = 0; INIT_WORK(&info->tqueue, do_softint, info); INIT_WORK(&info->tqueue_hangup, do_serial_hangup, info); - info->callout_termios =callout_driver.init_termios; info->normal_termios = serial_driver.init_termios; init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); diff -Nru a/drivers/serial/68328serial.h b/drivers/serial/68328serial.h --- a/drivers/serial/68328serial.h Mon Jun 9 23:16:18 2003 +++ b/drivers/serial/68328serial.h Mon Jun 9 23:16:18 2003 @@ -155,8 +155,6 @@ 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 */ unsigned char *xmit_buf; int xmit_head; int xmit_tail; @@ -164,7 +162,6 @@ struct work_struct tqueue; struct work_struct tqueue_hangup; struct termios normal_termios; - struct termios callout_termios; wait_queue_head_t open_wait; wait_queue_head_t close_wait; }; diff -Nru a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c --- a/drivers/serial/68360serial.c Mon Jun 9 23:16:19 2003 +++ b/drivers/serial/68360serial.c Mon Jun 9 23:16:19 2003 @@ -73,7 +73,7 @@ static char *serial_name = "CPM UART driver"; static char *serial_version = "0.03"; -static struct tty_driver serial_driver, callout_driver; +static struct tty_driver serial_driver; static int serial_refcount; int serial_console_setup(struct console *co, char *options); @@ -164,7 +164,6 @@ unsigned short closing_wait; /* time to wait before closing */ struct async_icount_24 icount; struct termios normal_termios; - struct termios callout_termios; int io_type; struct async_struct *info; }; @@ -256,8 +255,6 @@ unsigned long event; unsigned long last_active; int blocked_open; /* # of blocked opens */ - long session; /* Session of opening process */ - long pgrp; /* pgrp of opening process */ struct work_struct tqueue; struct work_struct tqueue_hangup; wait_queue_head_t open_wait; @@ -610,8 +607,7 @@ #endif if (status & UART_MSR_DCD) wake_up_interruptible(&info->open_wait); - else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_CALLOUT_NOHUP))) { + else { #ifdef SERIAL_DEBUG_OPEN printk("scheduling hangup..."); #endif @@ -1718,8 +1714,6 @@ */ if (info->flags & ASYNC_NORMAL_ACTIVE) info->state->normal_termios = *tty->termios; - if (info->flags & ASYNC_CALLOUT_ACTIVE) - info->state->callout_termios = *tty->termios; /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. @@ -1768,8 +1762,7 @@ } wake_up_interruptible(&info->open_wait); } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| - ASYNC_CLOSING); + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); MOD_DEC_USE_COUNT; local_irq_restore(flags); @@ -1861,7 +1854,7 @@ shutdown(info); info->event = 0; state->count = 0; - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->flags &= ~ASYNC_NORMAL_ACTIVE; info->tty = 0; wake_up_interruptible(&info->open_wait); } @@ -1899,28 +1892,6 @@ #endif } - -#if 0 /* FIXME */ - /* - * If this is a callout device, then just make sure the normal - * device isn't being used. - */ - if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) { - if (info->flags & ASYNC_NORMAL_ACTIVE) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_SESSION_LOCKOUT) && - (info->session != current->session)) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_PGRP_LOCKOUT) && - (info->pgrp != current->pgrp)) - return -EBUSY; - info->flags |= ASYNC_CALLOUT_ACTIVE; - return 0; - } -#endif - /* * If non-blocking mode is set, or the port is not enabled, * then make the check up front and then exit. @@ -1930,19 +1901,12 @@ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR)) || !(info->state->smc_scc_num & NUM_IS_SCC)) { - if (info->flags & ASYNC_CALLOUT_ACTIVE) - return -EBUSY; info->flags |= ASYNC_NORMAL_ACTIVE; return 0; } - if (info->flags & ASYNC_CALLOUT_ACTIVE) { - if (state->normal_termios.c_cflag & CLOCAL) - do_clocal = 1; - } else { - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - } + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; /* * Block waiting for the carrier detect and the line to become @@ -1965,8 +1929,7 @@ info->blocked_open++; while (1) { local_irq_disable(); - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - (tty->termios->c_cflag & CBAUD)) + if (tty->termios->c_cflag & CBAUD) serial_out(info, UART_MCR, serial_inp(info, UART_MCR) | (UART_MCR_DTR | UART_MCR_RTS)); @@ -1984,8 +1947,7 @@ #endif break; } - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - !(info->flags & ASYNC_CLOSING) && + if (!(info->flags & ASYNC_CLOSING) && (do_clocal || (serial_in(info, UART_MSR) & UART_MSR_DCD))) break; @@ -2076,16 +2038,10 @@ if ((info->state->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver->subtype == SERIAL_TYPE_NORMAL) - *tty->termios = info->state->normal_termios; - else - *tty->termios = info->state->callout_termios; + *tty->termios = info->state->normal_termios; change_speed(info); } - info->session = current->session; - info->pgrp = current->pgrp; - #ifdef SERIAL_DEBUG_OPEN printk("rs_open %s successful...", tty->name); #endif @@ -2617,22 +2573,9 @@ /* serial_driver.wait_until_sent = rs_360_wait_until_sent; */ /* serial_driver.read_proc = rs_360_read_proc; */ - /* - * The callout device is just like normal device except for - * major number and the subtype code. - */ - callout_driver = serial_driver; - callout_driver.name = "cua"; - callout_driver.major = TTYAUX_MAJOR; - callout_driver.subtype = SERIAL_TYPE_CALLOUT; - /* callout_driver.read_proc = 0; */ - /* callout_driver.proc_entry = 0; */ - if (tty_register_driver(&serial_driver)) panic("Couldn't register serial driver\n"); - if (tty_register_driver(&callout_driver)) - panic("Couldn't register callout driver\n"); - + cp = pquicc; /* Get pointer to Communication Processor */ /* immap = (immap_t *)IMAP_ADDR; */ /* and to internal registers */ @@ -2690,7 +2633,6 @@ state->custom_divisor = 0; state->close_delay = 5*HZ/10; state->closing_wait = 30*HZ; - state->callout_termios = callout_driver.init_termios; state->normal_termios = serial_driver.init_termios; state->icount.cts = state->icount.dsr = state->icount.rng = state->icount.dcd = 0; diff -Nru a/drivers/serial/8250.c b/drivers/serial/8250.c --- a/drivers/serial/8250.c Mon Jun 9 23:16:06 2003 +++ b/drivers/serial/8250.c Mon Jun 9 23:16:06 2003 @@ -1999,11 +1999,8 @@ static struct uart_driver serial8250_reg = { .owner = THIS_MODULE, .driver_name = "serial", -#ifdef CONFIG_DEVFS_FS - .dev_name = "tts/", -#else + .devfs_name = "tts/", .dev_name = "ttyS", -#endif .major = TTY_MAJOR, .minor = 64, .nr = UART_NR, diff -Nru a/drivers/serial/core.c b/drivers/serial/core.c --- a/drivers/serial/core.c Mon Jun 9 23:16:08 2003 +++ b/drivers/serial/core.c Mon Jun 9 23:16:08 2003 @@ -2115,6 +2115,7 @@ normal->magic = TTY_DRIVER_MAGIC; normal->owner = drv->owner; normal->driver_name = drv->driver_name; + normal->devfs_name = drv->devfs_name; normal->name = drv->dev_name; normal->major = drv->major; normal->minor_start = drv->minor; diff -Nru a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c --- a/drivers/serial/mcfserial.c Mon Jun 9 23:16:10 2003 +++ b/drivers/serial/mcfserial.c Mon Jun 9 23:16:10 2003 @@ -76,12 +76,11 @@ /* * Driver data structures. */ -struct tty_driver mcfrs_serial_driver, mcfrs_callout_driver; +struct tty_driver mcfrs_serial_driver; static int mcfrs_serial_refcount; /* serial subtype definitions */ #define SERIAL_TYPE_NORMAL 1 -#define SERIAL_TYPE_CALLOUT 2 /* number of characters left in xmit buffer before we ask for more */ #define WAKEUP_CHARS 256 @@ -450,12 +449,10 @@ return; if (info->flags & ASYNC_CHECK_CD) { - if (dcd) { + if (dcd) wake_up_interruptible(&info->open_wait); - } else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_CALLOUT_NOHUP))) { + else schedule_work(&info->tqueue_hangup); - } } } @@ -1198,8 +1195,6 @@ */ if (info->flags & ASYNC_NORMAL_ACTIVE) info->normal_termios = *tty->termios; - if (info->flags & ASYNC_CALLOUT_ACTIVE) - info->callout_termios = *tty->termios; /* * Now we wait for the transmit buffer to clear; and we notify @@ -1248,8 +1243,7 @@ } wake_up_interruptible(&info->open_wait); } - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| - ASYNC_CLOSING); + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); local_irq_restore(flags); } @@ -1268,7 +1262,7 @@ shutdown(info); info->event = 0; info->count = 0; - info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->flags &= ~ASYNC_NORMAL_ACTIVE; info->tty = 0; wake_up_interruptible(&info->open_wait); } @@ -1300,25 +1294,6 @@ return -EAGAIN; #endif } - - /* - * If this is a callout device, then just make sure the normal - * device isn't being used. - */ - if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) { - if (info->flags & ASYNC_NORMAL_ACTIVE) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_SESSION_LOCKOUT) && - (info->session != current->session)) - return -EBUSY; - if ((info->flags & ASYNC_CALLOUT_ACTIVE) && - (info->flags & ASYNC_PGRP_LOCKOUT) && - (info->pgrp != current->pgrp)) - return -EBUSY; - info->flags |= ASYNC_CALLOUT_ACTIVE; - return 0; - } /* * If non-blocking mode is set, or the port is not enabled, @@ -1326,20 +1301,13 @@ */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { - if (info->flags & ASYNC_CALLOUT_ACTIVE) - return -EBUSY; info->flags |= ASYNC_NORMAL_ACTIVE; return 0; } - if (info->flags & ASYNC_CALLOUT_ACTIVE) { - if (info->normal_termios.c_cflag & CLOCAL) - do_clocal = 1; - } else { - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - } - + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + /* * Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). While we are in @@ -1357,8 +1325,7 @@ info->blocked_open++; while (1) { local_irq_disable(); - if (!(info->flags & ASYNC_CALLOUT_ACTIVE)) - mcfrs_setsignals(info, 1, 1); + mcfrs_setsignals(info, 1, 1); local_irq_enable(); current->state = TASK_INTERRUPTIBLE; if (tty_hung_up_p(filp) || @@ -1373,8 +1340,7 @@ #endif break; } - if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && - !(info->flags & ASYNC_CLOSING) && + if (!(info->flags & ASYNC_CLOSING) && (do_clocal || (mcfrs_getsignals(info) & TIOCM_CD))) break; if (signal_pending(current)) { @@ -1443,16 +1409,10 @@ } if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { - if (tty->driver->subtype == SERIAL_TYPE_NORMAL) - *tty->termios = info->normal_termios; - else - *tty->termios = info->callout_termios; + *tty->termios = info->normal_termios; mcfrs_change_speed(info); } - info->session = current->session; - info->pgrp = current->pgrp; - #ifdef SERIAL_DEBUG_OPEN printk("mcfrs_open %s successful...\n", tty->name); #endif @@ -1658,26 +1618,11 @@ mcfrs_serial_driver.read_proc = mcfrs_readproc; mcfrs_serial_driver.driver_name = "serial"; - /* - * The callout device is just like normal device except for - * major number and the subtype code. - */ - mcfrs_callout_driver = mcfrs_serial_driver; - mcfrs_callout_driver.name = "cua"; - mcfrs_callout_driver.major = TTYAUX_MAJOR; - mcfrs_callout_driver.subtype = SERIAL_TYPE_CALLOUT; - mcfrs_callout_driver.read_proc = 0; - mcfrs_callout_driver.proc_entry = 0; - if (tty_register_driver(&mcfrs_serial_driver)) { printk("MCFRS: Couldn't register serial driver\n"); return(-EBUSY); } - if (tty_register_driver(&mcfrs_callout_driver)) { - printk("MCFRS: Couldn't register callout driver\n"); - return(-EBUSY); - } - + local_irq_save(flags); /* @@ -1696,7 +1641,6 @@ info->blocked_open = 0; INIT_WORK(&info->tqueue, mcfrs_offintr, info); INIT_WORK(&info->tqueue_hangup, do_serial_hangup, info); - info->callout_termios = mcfrs_callout_driver.init_termios; info->normal_termios = mcfrs_serial_driver.init_termios; init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); diff -Nru a/drivers/serial/mcfserial.h b/drivers/serial/mcfserial.h --- a/drivers/serial/mcfserial.h Mon Jun 9 23:16:07 2003 +++ b/drivers/serial/mcfserial.h Mon Jun 9 23:16:07 2003 @@ -58,8 +58,6 @@ 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 */ unsigned char *xmit_buf; int xmit_head; int xmit_tail; @@ -68,7 +66,6 @@ struct work_struct tqueue; struct work_struct tqueue_hangup; struct termios normal_termios; - struct termios callout_termios; wait_queue_head_t open_wait; wait_queue_head_t close_wait; diff -Nru a/drivers/serial/nb85e_uart.c b/drivers/serial/nb85e_uart.c --- a/drivers/serial/nb85e_uart.c Mon Jun 9 23:16:17 2003 +++ b/drivers/serial/nb85e_uart.c Mon Jun 9 23:16:17 2003 @@ -524,11 +524,8 @@ static struct uart_driver nb85e_uart_driver = { .owner = THIS_MODULE, .driver_name = "nb85e_uart", -#ifdef CONFIG_DEVFS_FS - .dev_name = "tts/", -#else + .devfs_name = "tts/", .dev_name = "ttyS", -#endif .major = TTY_MAJOR, .minor = NB85E_UART_MINOR_BASE, .nr = NB85E_UART_NUM_CHANNELS, diff -Nru a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c --- a/drivers/serial/sunsab.c Mon Jun 9 23:16:10 2003 +++ b/drivers/serial/sunsab.c Mon Jun 9 23:16:10 2003 @@ -231,8 +231,10 @@ set_bit(SAB82532_ALLS, &up->irqflags); } +#if 0 /* bde@nwlink.com says this check causes problems */ if (!(stat->sreg.isr1 & SAB82532_ISR1_XPR)) return; +#endif if (!(readb(&up->regs->r.star) & SAB82532_STAR_XFW)) return; @@ -242,6 +244,7 @@ if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) { up->interrupt_mask1 |= SAB82532_IMR1_XPR; writeb(up->interrupt_mask1, &up->regs->w.imr1); + uart_write_wakeup(&up->port); return; } @@ -827,11 +830,8 @@ static struct uart_driver sunsab_reg = { .owner = THIS_MODULE, .driver_name = "serial", -#ifdef CONFIG_DEVFS_FS - .dev_name = "tts/", -#else + .devfs_name = "tts/", .dev_name = "ttyS", -#endif .major = TTY_MAJOR, }; diff -Nru a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c --- a/drivers/serial/sunsu.c Mon Jun 9 23:16:08 2003 +++ b/drivers/serial/sunsu.c Mon Jun 9 23:16:08 2003 @@ -1285,11 +1285,8 @@ static struct uart_driver sunsu_reg = { .owner = THIS_MODULE, .driver_name = "serial", -#ifdef CONFIG_DEVFS_FS - .dev_name = "tts/", -#else + .devfs_name = "tts/", .dev_name = "ttyS", -#endif .major = TTY_MAJOR, }; diff -Nru a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c --- a/drivers/serial/sunzilog.c Mon Jun 9 23:16:19 2003 +++ b/drivers/serial/sunzilog.c Mon Jun 9 23:16:19 2003 @@ -1030,11 +1030,8 @@ static struct uart_driver sunzilog_reg = { .owner = THIS_MODULE, .driver_name = "ttyS", -#ifdef CONFIG_DEVFS_FS - .dev_name = "tts/", -#else + .devfs_name = "tts/", .dev_name = "ttyS", -#endif .major = TTY_MAJOR, }; diff -Nru a/drivers/sgi/char/sgiserial.c b/drivers/sgi/char/sgiserial.c --- a/drivers/sgi/char/sgiserial.c Mon Jun 9 23:16:08 2003 +++ b/drivers/sgi/char/sgiserial.c Mon Jun 9 23:16:08 2003 @@ -97,14 +97,13 @@ DECLARE_TASK_QUEUE(tq_serial); -struct tty_driver serial_driver, callout_driver; +struct tty_driver serial_driver; struct console *sgisercon; static int serial_refcount; /* serial subtype definitions */ #define SERIAL_TYPE_NORMAL 1 -#define SERIAL_TYPE_CALLOUT 2 - + /* number of characters left in xmit buffer before we ask for more */ #define WAKEUP_CHARS 256 @@ -1514,8 +1513,6 @@ */ if (info->flags & ZILOG_NORMAL_ACTIVE) info->normal_termios = *tty->termios; - if (info->flags & ZILOG_CALLOUT_ACTIVE) - info->callout_termios = *tty->termios; /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. @@ -1561,8 +1558,7 @@ } wake_up_interruptible(&info->open_wait); } - info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE| - ZILOG_CLOSING); + info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CLOSING); wake_up_interruptible(&info->close_wait); restore_flags(flags); } @@ -1581,7 +1577,7 @@ shutdown(info); info->event = 0; info->count = 0; - info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE); + info->flags &= ~ZILOG_NORMAL_ACTIVE; info->tty = 0; wake_up_interruptible(&info->open_wait); } @@ -1615,44 +1611,18 @@ } /* - * If this is a callout device, then just make sure the normal - * device isn't being used. - */ - if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) { - if (info->flags & ZILOG_NORMAL_ACTIVE) - return -EBUSY; - if ((info->flags & ZILOG_CALLOUT_ACTIVE) && - (info->flags & ZILOG_SESSION_LOCKOUT) && - (info->session != current->session)) - return -EBUSY; - if ((info->flags & ZILOG_CALLOUT_ACTIVE) && - (info->flags & ZILOG_PGRP_LOCKOUT) && - (info->pgrp != current->pgrp)) - return -EBUSY; - info->flags |= ZILOG_CALLOUT_ACTIVE; - return 0; - } - - /* * If non-blocking mode is set, or the port is not enabled, * then make the check up front and then exit. */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { - if (info->flags & ZILOG_CALLOUT_ACTIVE) - return -EBUSY; info->flags |= ZILOG_NORMAL_ACTIVE; return 0; } - if (info->flags & ZILOG_CALLOUT_ACTIVE) { - if (info->normal_termios.c_cflag & CLOCAL) - do_clocal = 1; - } else { - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - } - + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + /* * Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). While we are in @@ -1670,8 +1640,7 @@ info->blocked_open++; while (1) { cli(); - if (!(info->flags & ZILOG_CALLOUT_ACTIVE)) - zs_rtsdtr(info, 1); + zs_rtsdtr(info, 1); sti(); set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || @@ -1686,8 +1655,7 @@ #endif break; } - if (!(info->flags & ZILOG_CALLOUT_ACTIVE) && - !(info->flags & ZILOG_CLOSING) && do_clocal) + if (!(info->flags & ZILOG_CLOSING) && do_clocal) break; if (signal_pending(current)) { retval = -ERESTARTSYS; @@ -1761,10 +1729,7 @@ } if ((info->count == 1) && (info->flags & ZILOG_SPLIT_TERMIOS)) { - if (tty->driver->subtype == SERIAL_TYPE_NORMAL) - *tty->termios = info->normal_termios; - else - *tty->termios = info->callout_termios; + *tty->termios = info->normal_termios; change_speed(info); } @@ -1776,9 +1741,6 @@ change_speed(info); } - info->session = current->session; - info->pgrp = current->pgrp; - #ifdef SERIAL_DEBUG_OPEN printk("rs_open %s successful...\n", tty->name); #endif @@ -1899,20 +1861,9 @@ serial_driver.start = rs_start; serial_driver.hangup = rs_hangup; - /* - * The callout device is just like normal device except for - * major number and the subtype code. - */ - callout_driver = serial_driver; - callout_driver.name = "cua"; - callout_driver.major = TTYAUX_MAJOR; - callout_driver.subtype = SERIAL_TYPE_CALLOUT; - if (tty_register_driver(&serial_driver)) panic("Couldn't register serial driver\n"); - if (tty_register_driver(&callout_driver)) - panic("Couldn't register callout driver\n"); - + save_flags(flags); cli(); /* Set up our interrupt linked list */ @@ -1999,7 +1950,6 @@ info->tqueue.data = info; info->tqueue_hangup.routine = do_serial_hangup; info->tqueue_hangup.data = info; - info->callout_termios =callout_driver.init_termios; info->normal_termios = serial_driver.init_termios; init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); diff -Nru a/drivers/sgi/char/sgiserial.h b/drivers/sgi/char/sgiserial.h --- a/drivers/sgi/char/sgiserial.h Mon Jun 9 23:16:10 2003 +++ b/drivers/sgi/char/sgiserial.h Mon Jun 9 23:16:10 2003 @@ -148,8 +148,6 @@ 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 */ unsigned char *xmit_buf; int xmit_head; int xmit_tail; @@ -157,7 +155,6 @@ struct tq_struct tqueue; struct tq_struct tqueue_hangup; struct termios normal_termios; - struct termios callout_termios; wait_queue_head_t open_wait; wait_queue_head_t close_wait; }; diff -Nru a/drivers/tc/zs.c b/drivers/tc/zs.c --- a/drivers/tc/zs.c Mon Jun 9 23:16:17 2003 +++ b/drivers/tc/zs.c Mon Jun 9 23:16:17 2003 @@ -180,12 +180,11 @@ DECLARE_TASK_QUEUE(tq_zs_serial); -struct tty_driver serial_driver, callout_driver; +struct tty_driver serial_driver; static int serial_refcount; /* serial subtype definitions */ #define SERIAL_TYPE_NORMAL 1 -#define SERIAL_TYPE_CALLOUT 2 /* number of characters left in xmit buffer before we ask for more */ #define WAKEUP_CHARS 256 @@ -526,7 +525,7 @@ && info->tty && !C_CLOCAL(info->tty)) { if (stat & DCD) { wake_up_interruptible(&info->open_wait); - } else if (!(info->flags & ZILOG_CALLOUT_ACTIVE)) { + } else { tty_hangup(info->tty); } } @@ -1397,8 +1396,6 @@ */ if (info->flags & ZILOG_NORMAL_ACTIVE) info->normal_termios = *tty->termios; - if (info->flags & ZILOG_CALLOUT_ACTIVE) - info->callout_termios = *tty->termios; /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. @@ -1438,8 +1435,7 @@ } wake_up_interruptible(&info->open_wait); } - info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE| - ZILOG_CLOSING); + info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CLOSING); wake_up_interruptible(&info->close_wait); restore_flags(flags); } @@ -1492,7 +1488,7 @@ shutdown(info); info->event = 0; info->count = 0; - info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE); + info->flags &= ~ZILOG_NORMAL_ACTIVE; info->tty = 0; wake_up_interruptible(&info->open_wait); } @@ -1527,20 +1523,6 @@ * If this is a callout device, then just make sure the normal * device isn't being used. */ - if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) { - if (info->flags & ZILOG_NORMAL_ACTIVE) - return -EBUSY; - if ((info->flags & ZILOG_CALLOUT_ACTIVE) && - (info->flags & ZILOG_SESSION_LOCKOUT) && - (info->session != current->session)) - return -EBUSY; - if ((info->flags & ZILOG_CALLOUT_ACTIVE) && - (info->flags & ZILOG_PGRP_LOCKOUT) && - (info->pgrp != current->pgrp)) - return -EBUSY; - info->flags |= ZILOG_CALLOUT_ACTIVE; - return 0; - } /* * If non-blocking mode is set, or the port is not enabled, @@ -1548,20 +1530,13 @@ */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { - if (info->flags & ZILOG_CALLOUT_ACTIVE) - return -EBUSY; info->flags |= ZILOG_NORMAL_ACTIVE; return 0; } - if (info->flags & ZILOG_CALLOUT_ACTIVE) { - if (info->normal_termios.c_cflag & CLOCAL) - do_clocal = 1; - } else { - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - } - + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + /* * Block waiting for the carrier detect and the line to become * free (i.e., not in use by the callout). While we are in @@ -1582,8 +1557,7 @@ info->blocked_open++; while (1) { cli(); - if (!(info->flags & ZILOG_CALLOUT_ACTIVE) && - (tty->termios->c_cflag & CBAUD)) + if (tty->termios->c_cflag & CBAUD) zs_rtsdtr(info, RTS | DTR, 1); sti(); set_current_state(TASK_INTERRUPTIBLE); @@ -1599,8 +1573,7 @@ #endif break; } - if (!(info->flags & ZILOG_CALLOUT_ACTIVE) && - !(info->flags & ZILOG_CLOSING) && + if (!(info->flags & ZILOG_CLOSING) && (do_clocal || (read_zsreg(info->zs_channel, 0) & DCD))) break; if (signal_pending(current)) { @@ -1689,10 +1662,7 @@ } if ((info->count == 1) && (info->flags & ZILOG_SPLIT_TERMIOS)) { - if (tty->driver->subtype == SERIAL_TYPE_NORMAL) - *tty->termios = info->normal_termios; - else - *tty->termios = info->callout_termios; + *tty->termios = info->normal_termios; change_speed(info); } #ifdef CONFIG_SERIAL_CONSOLE @@ -1703,9 +1673,6 @@ } #endif - info->session = current->session; - info->pgrp = current->pgrp; - #ifdef SERIAL_DEBUG_OPEN printk("rs_open %s successful...", tty->name); #endif @@ -1873,11 +1840,8 @@ memset(&serial_driver, 0, sizeof(struct tty_driver)); serial_driver.magic = TTY_DRIVER_MAGIC; serial_driver.owner = THIS_MODULE; -#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) - serial_driver.name = "tts/"; -#else + serial_driver.devfs_name = "tts/"; serial_driver.name = "ttyS"; -#endif serial_driver.major = TTY_MAJOR; serial_driver.minor_start = 64; serial_driver.num = zs_channels_found; @@ -1910,23 +1874,8 @@ serial_driver.break_ctl = rs_break; serial_driver.wait_until_sent = rs_wait_until_sent; - /* - * The callout device is just like normal device except for - * major number and the subtype code. - */ - callout_driver = serial_driver; -#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) - callout_driver.name = "cua/"; -#else - callout_driver.name = "cua"; -#endif - callout_driver.major = TTYAUX_MAJOR; - callout_driver.subtype = SERIAL_TYPE_CALLOUT; - if (tty_register_driver(&serial_driver)) panic("Couldn't register serial driver\n"); - if (tty_register_driver(&callout_driver)) - panic("Couldn't register callout driver\n"); save_flags(flags); cli(); @@ -1964,7 +1913,6 @@ info->blocked_open = 0; info->tqueue.routine = do_softint; info->tqueue.data = info; - info->callout_termios = callout_driver.init_termios; info->normal_termios = serial_driver.init_termios; init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); @@ -1972,8 +1920,6 @@ info->port, info->irq); printk(" is a Z85C30 SCC\n"); tty_register_device(&serial_driver, info->line, NULL); - tty_register_device(&callout_driver, info->line, NULL); - } restore_flags(flags); diff -Nru a/drivers/tc/zs.h b/drivers/tc/zs.h --- a/drivers/tc/zs.h Mon Jun 9 23:16:09 2003 +++ b/drivers/tc/zs.h Mon Jun 9 23:16:09 2003 @@ -144,8 +144,6 @@ 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 */ unsigned char *xmit_buf; int xmit_head; int xmit_tail; @@ -153,7 +151,6 @@ struct tq_struct tqueue; struct tq_struct tqueue_hangup; struct termios normal_termios; - struct termios callout_termios; wait_queue_head_t open_wait; wait_queue_head_t close_wait; }; diff -Nru a/drivers/usb/class/audio.c b/drivers/usb/class/audio.c --- a/drivers/usb/class/audio.c Mon Jun 9 23:16:19 2003 +++ b/drivers/usb/class/audio.c Mon Jun 9 23:16:19 2003 @@ -2753,6 +2753,7 @@ MODULE_DEVICE_TABLE (usb, usb_audio_ids); static struct usb_driver usb_audio_driver = { + .owner = THIS_MODULE, .name = "audio", .probe = usb_audio_probe, .disconnect = usb_audio_disconnect, diff -Nru a/drivers/usb/class/bluetty.c b/drivers/usb/class/bluetty.c --- a/drivers/usb/class/bluetty.c Mon Jun 9 23:16:16 2003 +++ b/drivers/usb/class/bluetty.c Mon Jun 9 23:16:16 2003 @@ -234,6 +234,7 @@ MODULE_DEVICE_TABLE (usb, usb_bluetooth_ids); static struct usb_driver usb_bluetooth_driver = { + .owner = THIS_MODULE, .name = "bluetty", .probe = usb_bluetooth_probe, .disconnect = usb_bluetooth_disconnect, diff -Nru a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c --- a/drivers/usb/class/cdc-acm.c Mon Jun 9 23:16:15 2003 +++ b/drivers/usb/class/cdc-acm.c Mon Jun 9 23:16:15 2003 @@ -725,6 +725,7 @@ MODULE_DEVICE_TABLE (usb, acm_ids); static struct usb_driver acm_driver = { + .owner = THIS_MODULE, .name = "acm", .probe = acm_probe, .disconnect = acm_disconnect, diff -Nru a/drivers/usb/class/usb-midi.c b/drivers/usb/class/usb-midi.c --- a/drivers/usb/class/usb-midi.c Mon Jun 9 23:16:05 2003 +++ b/drivers/usb/class/usb-midi.c Mon Jun 9 23:16:05 2003 @@ -55,8 +55,6 @@ #undef HAVE_SUPPORT_ALSA -#undef MOD_INC_EACH_PROBE - /* ------------------------------------------------------------------------- */ static int singlebyte = 0; @@ -925,11 +923,6 @@ printk(KERN_INFO "usb-midi: Open Succeeded. minor= %d.\n", minor); #endif - /** Side-effect: module cannot be removed until USE_COUNT is 0. **/ -#ifndef MOD_INC_EACH_PROBE - MOD_INC_USE_COUNT; -#endif - return 0; /** Success. **/ } @@ -978,15 +971,11 @@ wake_up(&open_wait); file->private_data = 0; - /** Sideeffect: Module cannot be removed until usecount is 0. */ -#ifndef MOD_INC_EACH_PROBE - MOD_DEC_USE_COUNT; -#endif - return 0; } static struct file_operations usb_midi_fops = { + .owner = THIS_MODULE, .llseek = usb_midi_llseek, .read = usb_midi_read, .write = usb_midi_write, @@ -2040,10 +2029,6 @@ list_add_tail(&s->mididev, &mididevs); up(&open_sem); -#ifdef MOD_INC_EACH_PROBE - MOD_INC_USE_COUNT; -#endif - usb_set_intfdata (intf, s); return 0; } @@ -2081,11 +2066,6 @@ } release_midi_device(s); wake_up(&open_wait); -#ifdef MOD_INC_EACH_PROBE - MOD_DEC_USE_COUNT; -#endif - - return; } /* we want to look at all devices by hand */ @@ -2095,6 +2075,7 @@ }; static struct usb_driver usb_midi_driver = { + .owner = THIS_MODULE, .name = "midi", .probe = usb_midi_probe, .disconnect = usb_midi_disconnect, diff -Nru a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig --- a/drivers/usb/core/Kconfig Mon Jun 9 23:16:18 2003 +++ b/drivers/usb/core/Kconfig Mon Jun 9 23:16:18 2003 @@ -19,13 +19,11 @@ If you say Y here (and to "/proc file system support" in the "File systems" section, above), you will get a file /proc/bus/usb/devices which lists the devices currently connected to your USB bus or - busses, a file /proc/bus/usb/drivers which lists the USB kernel - client drivers currently loaded, and for every connected device a - file named "/proc/bus/usb/xxx/yyy", where xxx is the bus number and - yyy the device number; the latter files can be used by user space - programs to talk directly to the device. These files are "virtual", - meaning they are generated on the fly and not stored on the hard - drive. + busses, and for every connected device a file named + "/proc/bus/usb/xxx/yyy", where xxx is the bus number and yyy the + device number; the latter files can be used by user space programs + to talk directly to the device. These files are "virtual", meaning + they are generated on the fly and not stored on the hard drive. You may need to mount the usbfs file system to see the files, use mount -t usbfs none /proc/bus/usb diff -Nru a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c --- a/drivers/usb/core/devio.c Mon Jun 9 23:16:12 2003 +++ b/drivers/usb/core/devio.c Mon Jun 9 23:16:12 2003 @@ -342,6 +342,7 @@ } struct usb_driver usbdevfs_driver = { + .owner = THIS_MODULE, .name = "usbfs", .probe = driver_probe, .disconnect = driver_disconnect, diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c --- a/drivers/usb/core/hcd.c Mon Jun 9 23:16:14 2003 +++ b/drivers/usb/core/hcd.c Mon Jun 9 23:16:14 2003 @@ -720,6 +720,7 @@ int retval; sprintf (&usb_dev->dev.bus_id[0], "usb%d", usb_dev->bus->busnum); + usb_dev->state = USB_STATE_DEFAULT; retval = usb_new_device (usb_dev, parent_dev); if (retval) dev_err (parent_dev, "can't register root hub for %s, %d\n", diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c --- a/drivers/usb/core/hub.c Mon Jun 9 23:16:11 2003 +++ b/drivers/usb/core/hub.c Mon Jun 9 23:16:11 2003 @@ -737,6 +737,9 @@ if (status != -1) { usb_clear_port_feature(hub, port + 1, USB_PORT_FEAT_C_RESET); + dev->state = status + ? USB_STATE_NOTATTACHED + : USB_STATE_DEFAULT; return status; } @@ -753,7 +756,7 @@ return -1; } -void usb_hub_port_disable(struct usb_device *hub, int port) +int usb_hub_port_disable(struct usb_device *hub, int port) { int ret; @@ -761,6 +764,8 @@ if (ret) dev_err(hubdev(hub), "cannot disable port %d (err = %d)\n", port + 1, ret); + + return ret; } /* USB 2.0 spec, 7.1.7.3 / fig 7-29: @@ -1114,6 +1119,7 @@ MODULE_DEVICE_TABLE (usb, hub_id_table); static struct usb_driver hub_driver = { + .owner = THIS_MODULE, .name = "hub", .probe = hub_probe, .disconnect = hub_disconnect, @@ -1198,12 +1204,18 @@ if (port < 0) return -ENOENT; + descriptor = kmalloc(sizeof *descriptor, GFP_NOIO); + if (!descriptor) { + return -ENOMEM; + } + down(&usb_address0_sem); /* Send a reset to the device */ if (usb_hub_port_reset(parent, port, dev, HUB_SHORT_RESET_TIME)) { usb_hub_port_disable(parent, port); up(&usb_address0_sem); + kfree(descriptor); return(-ENODEV); } @@ -1213,6 +1225,7 @@ err("USB device not accepting new address (error=%d)", ret); usb_hub_port_disable(parent, port); up(&usb_address0_sem); + kfree(descriptor); return ret; } @@ -1230,10 +1243,7 @@ * If nothing changed, we reprogram the configuration and then * the alternate settings. */ - descriptor = kmalloc(sizeof *descriptor, GFP_NOIO); - if (!descriptor) { - return -ENOMEM; - } + ret = usb_get_descriptor(dev, USB_DT_DEVICE, 0, descriptor, sizeof(*descriptor)); if (ret < 0) { @@ -1260,7 +1270,7 @@ "(expected %Zi, got %i)", dev->devpath, sizeof(dev->descriptor), ret); - + clear_bit(dev->devnum, dev->bus->devmap.devicemap); dev->devnum = -1; return -EIO; diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c --- a/drivers/usb/core/usb.c Mon Jun 9 23:16:12 2003 +++ b/drivers/usb/core/usb.c Mon Jun 9 23:16:12 2003 @@ -731,6 +731,70 @@ } +static struct usb_device *match_device(struct usb_device *dev, + u16 vendor_id, u16 product_id) +{ + struct usb_device *ret_dev = NULL; + int child; + + dbg("looking at vendor %d, product %d", + dev->descriptor.idVendor, + dev->descriptor.idProduct); + + /* see if this device matches */ + if ((dev->descriptor.idVendor == vendor_id) && + (dev->descriptor.idProduct == product_id)) { + dbg ("found the device!"); + ret_dev = usb_get_dev(dev); + goto exit; + } + + /* look through all of the children of this device */ + for (child = 0; child < dev->maxchild; ++child) { + if (dev->children[child]) { + ret_dev = match_device(dev->children[child], + vendor_id, product_id); + if (ret_dev) + goto exit; + } + } +exit: + return ret_dev; +} + +/** + * usb_find_device - find a specific usb device in the system + * @vendor_id: the vendor id of the device to find + * @product_id: the product id of the device to find + * + * Returns a pointer to a struct usb_device if such a specified usb + * device is present in the system currently. The usage count of the + * device will be incremented if a device is found. Make sure to call + * usb_put_dev() when the caller is finished with the device. + * + * If a device with the specified vendor and product id is not found, + * NULL is returned. + */ +struct usb_device *usb_find_device(u16 vendor_id, u16 product_id) +{ + struct list_head *buslist; + struct usb_bus *bus; + struct usb_device *dev = NULL; + + down(&usb_bus_list_lock); + for (buslist = usb_bus_list.next; + buslist != &usb_bus_list; + buslist = buslist->next) { + bus = container_of(buslist, struct usb_bus, bus_list); + dev = match_device(bus->root_hub, vendor_id, product_id); + if (dev) + goto exit; + } +exit: + up(&usb_bus_list_lock); + return dev; +} + /** * usb_get_current_frame_number - return current bus frame number * @dev: the device whose bus is being queried @@ -1017,9 +1081,6 @@ /* dma masks come from the controller; readonly, except to hcd */ dev->dev.dma_mask = parent->dma_mask; - /* it's not usable yet */ - dev->state = USB_STATE_DEFAULT; - /* USB 2.0 section 5.5.3 talks about ep0 maxpacket ... * it's fixed size except for full speed devices. */ @@ -1513,6 +1574,7 @@ EXPORT_SYMBOL(__usb_get_extra_descriptor); +EXPORT_SYMBOL(usb_find_device); EXPORT_SYMBOL(usb_get_current_frame_number); EXPORT_SYMBOL (usb_buffer_alloc); diff -Nru a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c --- a/drivers/usb/gadget/ether.c Mon Jun 9 23:16:19 2003 +++ b/drivers/usb/gadget/ether.c Mon Jun 9 23:16:19 2003 @@ -76,6 +76,7 @@ #define MIN_PACKET sizeof(struct ethhdr) #define MAX_PACKET ETH_DATA_LEN /* biggest packet we'll rx/tx */ +#define RX_EXTRA 20 /* guard against rx overflows */ /* FIXME allow high speed jumbograms */ @@ -1226,7 +1227,7 @@ int retval = 0; size_t size; - size = (sizeof (struct ethhdr) + dev->net.mtu); + size = (sizeof (struct ethhdr) + dev->net.mtu + RX_EXTRA); if ((skb = alloc_skb (size, gfp_flags)) == 0) { DEBUG (dev, "no rx skb\n"); diff -Nru a/drivers/usb/image/hpusbscsi.c b/drivers/usb/image/hpusbscsi.c --- a/drivers/usb/image/hpusbscsi.c Mon Jun 9 23:16:19 2003 +++ b/drivers/usb/image/hpusbscsi.c Mon Jun 9 23:16:19 2003 @@ -22,65 +22,56 @@ #define TRACE_STATE printk(KERN_DEBUG"hpusbscsi->state = %s at line %d\n", states[hpusbscsi->state], __LINE__) -/* global variables */ - -struct list_head hpusbscsi_devices; -//LIST_HEAD(hpusbscsi_devices); - -/* USB related parts */ +static Scsi_Host_Template hpusbscsi_scsi_host_template = { + .module = THIS_MODULE, + .name = "hpusbscsi", + .proc_name = "hpusbscsi", + .queuecommand = hpusbscsi_scsi_queuecommand, + .eh_abort_handler = hpusbscsi_scsi_abort, + .eh_host_reset_handler = hpusbscsi_scsi_host_reset, + .sg_tablesize = SG_ALL, + .can_queue = 1, + .this_id = -1, + .cmd_per_lun = 1, + .use_clustering = 1, + .emulated = 1, +}; static int -hpusbscsi_usb_probe (struct usb_interface *intf, - const struct usb_device_id *id) +hpusbscsi_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) { + struct usb_device *dev = interface_to_usbdev(intf); + struct usb_host_interface *altsetting = intf->altsetting; struct hpusbscsi *new; - struct usb_device *dev = interface_to_usbdev (intf); - struct usb_host_interface *altsetting = - &(intf->altsetting[0]); - + int error = -ENOMEM; int i, result; - /* basic check */ - if (altsetting->desc.bNumEndpoints != 3) { printk (KERN_ERR "Wrong number of endpoints\n"); return -ENODEV; } - /* descriptor allocation */ - - new = - (struct hpusbscsi *) kmalloc (sizeof (struct hpusbscsi), - GFP_KERNEL); - if (new == NULL) + new = kmalloc(sizeof(struct hpusbscsi), GFP_KERNEL); + if (!new) return -ENOMEM; - DEBUG ("Allocated memory\n"); - memset (new, 0, sizeof (struct hpusbscsi)); + memset(new, 0, sizeof(struct hpusbscsi)); new->dataurb = usb_alloc_urb(0, GFP_KERNEL); - if (!new->dataurb) { - kfree (new); - return -ENOMEM; - } + if (!new->dataurb) + goto out_kfree; new->controlurb = usb_alloc_urb(0, GFP_KERNEL); - if (!new->controlurb) { - usb_free_urb (new->dataurb); - kfree (new); - return -ENOMEM; - } - new->dev = dev; - init_waitqueue_head (&new->pending); - init_waitqueue_head (&new->deathrow); - INIT_LIST_HEAD (&new->lh); - + if (!new->controlurb) + goto out_free_dataurb; + new->dev = dev; + init_waitqueue_head(&new->pending); + init_waitqueue_head(&new->deathrow); - /* finding endpoints */ - + error = -ENODEV; for (i = 0; i < altsetting->desc.bNumEndpoints; i++) { - if ( - (altsetting->endpoint[i].desc. + if ((altsetting->endpoint[i].desc. bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == - USB_ENDPOINT_XFER_BULK) { + USB_ENDPOINT_XFER_BULK) { if (altsetting->endpoint[i].desc. bEndpointAddress & USB_DIR_IN) { new->ep_in = @@ -97,57 +88,60 @@ new->ep_int = altsetting->endpoint[i].desc. bEndpointAddress & USB_ENDPOINT_NUMBER_MASK; - new->interrupt_interval= altsetting->endpoint[i].desc.bInterval; + new->interrupt_interval= altsetting->endpoint[i].desc. + bInterval; } } - /* USB initialisation magic for the simple case */ - - result = usb_set_interface (dev, altsetting->desc.bInterfaceNumber, 0); - - switch (result) { - case 0: /* no error */ - break; - default: - printk (KERN_ERR "unknown error %d from usb_set_interface\n", - result); - goto err_out; - } + /* build and submit an interrupt URB for status byte handling */ + usb_fill_int_urb(new->controlurb, new->dev, + usb_rcvintpipe(new->dev, new->ep_int), + &new->scsi_state_byte, 1, + control_interrupt_callback,new, + new->interrupt_interval); - /* making a template for the scsi layer to fake detection of a scsi device */ + if (usb_submit_urb(new->controlurb, GFP_KERNEL) < 0) + goto out_free_controlurb; - memcpy (&(new->ctempl), &hpusbscsi_scsi_host_template, - sizeof (hpusbscsi_scsi_host_template)); - (struct hpusbscsi *) new->ctempl.proc_dir = new; - new->ctempl.module = THIS_MODULE; + /* In host->hostdata we store a pointer to desc */ + new->host = scsi_register(&hpusbscsi_scsi_host_template, sizeof(new)); + if (!new->host) + goto out_unlink_controlurb; - if (scsi_register_host(&new->ctempl)) - goto err_out; + new->host->hostdata[0] = (unsigned long)new; + scsi_add_host(new->host, &intf->dev); new->sense_command[0] = REQUEST_SENSE; new->sense_command[4] = HPUSBSCSI_SENSE_LENGTH; - /* adding to list for module unload */ - list_add (&hpusbscsi_devices, &new->lh); - usb_set_intfdata(intf, new); return 0; - err_out: - usb_free_urb (new->controlurb); - usb_free_urb (new->dataurb); - kfree (new); - return -ENODEV; + out_unlink_controlurb: + usb_unlink_urb(new->controlurb); + out_free_controlurb: + usb_free_urb(new->controlurb); + out_free_dataurb: + usb_free_urb(new->dataurb); + out_kfree: + kfree(new); + return error; } static void -hpusbscsi_usb_disconnect (struct usb_interface *intf) +hpusbscsi_usb_disconnect(struct usb_interface *intf) { struct hpusbscsi *desc = usb_get_intfdata(intf); usb_set_intfdata(intf, NULL); - if (desc) - usb_unlink_urb(desc->controlurb); + + scsi_remove_host(desc->host); + usb_unlink_urb(desc->controlurb); + scsi_unregister(desc->host); + + usb_free_urb(desc->controlurb); + usb_free_urb(desc->dataurb); + kfree(desc); } static struct usb_device_id hpusbscsi_usb_ids[] = { @@ -169,6 +163,7 @@ static struct usb_driver hpusbscsi_usb_driver = { + .owner = THIS_MODULE, .name ="hpusbscsi", .probe =hpusbscsi_usb_probe, .disconnect =hpusbscsi_usb_disconnect, @@ -177,100 +172,20 @@ /* module initialisation */ -int __init +static int __init hpusbscsi_init (void) { - int result; - - INIT_LIST_HEAD (&hpusbscsi_devices); - DEBUG ("Driver loaded\n"); - - if ((result = usb_register (&hpusbscsi_usb_driver)) < 0) { - printk (KERN_ERR "hpusbscsi: driver registration failed\n"); - return -1; - } else { - return 0; - } + return usb_register(&hpusbscsi_usb_driver); } -void __exit +static void __exit hpusbscsi_exit (void) { - struct list_head *tmp; - struct list_head *old; - struct hpusbscsi * o; - - for (tmp = hpusbscsi_devices.next; tmp != &hpusbscsi_devices;/*nothing */) { - old = tmp; - tmp = tmp->next; - o = (struct hpusbscsi *)old; - usb_unlink_urb(o->controlurb); - scsi_unregister_host(&o->ctempl); - usb_free_urb(o->controlurb); - usb_free_urb(o->dataurb); - kfree(old); - } - - usb_deregister (&hpusbscsi_usb_driver); + usb_deregister(&hpusbscsi_usb_driver); } module_init (hpusbscsi_init); module_exit (hpusbscsi_exit); - -/* interface to the scsi layer */ - -static int -hpusbscsi_scsi_detect (struct SHT *sht) -{ - /* Whole function stolen from usb-storage */ - - struct hpusbscsi *desc = (struct hpusbscsi *) sht->proc_dir; - /* What a hideous hack! */ - - char local_name[48]; - - - /* set up the name of our subdirectory under /proc/scsi/ */ - sprintf (local_name, "hpusbscsi-%d", desc->number); - sht->proc_name = kmalloc (strlen (local_name) + 1, GFP_KERNEL); - /* FIXME: where is this freed ? */ - - if (!sht->proc_name) { - return 0; - } - - strcpy (sht->proc_name, local_name); - - sht->proc_dir = NULL; - - /* build and submit an interrupt URB for status byte handling */ - usb_fill_int_urb(desc->controlurb, - desc->dev, - usb_rcvintpipe(desc->dev,desc->ep_int), - &desc->scsi_state_byte, - 1, - control_interrupt_callback, - desc, - desc->interrupt_interval - ); - - if ( 0 > usb_submit_urb(desc->controlurb, GFP_KERNEL)) { - kfree(sht->proc_name); - return 0; - } - - /* In host->hostdata we store a pointer to desc */ - desc->host = scsi_register (sht, sizeof (desc)); - if (desc->host == NULL) { - kfree (sht->proc_name); - usb_unlink_urb(desc->controlurb); - return 0; - } - desc->host->hostdata[0] = (unsigned long) desc; - - - return 1; -} static int hpusbscsi_scsi_queuecommand (Scsi_Cmnd *srb, scsi_callback callback) { diff -Nru a/drivers/usb/image/hpusbscsi.h b/drivers/usb/image/hpusbscsi.h --- a/drivers/usb/image/hpusbscsi.h Mon Jun 9 23:16:07 2003 +++ b/drivers/usb/image/hpusbscsi.h Mon Jun 9 23:16:07 2003 @@ -13,7 +13,6 @@ struct hpusbscsi { - struct list_head lh; struct usb_device *dev; /* NULL indicates unplugged device */ int ep_out; int ep_in; @@ -36,7 +35,6 @@ int state; int current_data_pipe; - Scsi_Host_Template ctempl; u8 sense_command[SENSE_COMMAND_SIZE]; u8 scsi_state_byte; }; @@ -52,7 +50,6 @@ #define DIRECTION_IS_IN(x) ((scsi_command_direction[x>>3] >> (x & 7)) & 1) -static int hpusbscsi_scsi_detect (struct SHT * sht); static void simple_command_callback(struct urb *u, struct pt_regs *regs); static void scatter_gather_callback(struct urb *u, struct pt_regs *regs); static void simple_payload_callback (struct urb *u, struct pt_regs *regs); @@ -63,25 +60,6 @@ static int hpusbscsi_scsi_host_reset (Scsi_Cmnd *srb); static int hpusbscsi_scsi_abort (Scsi_Cmnd *srb); static void issue_request_sense (struct hpusbscsi *hpusbscsi); - -static Scsi_Host_Template hpusbscsi_scsi_host_template = { - .name = "hpusbscsi", - .detect = hpusbscsi_scsi_detect, -// .release = hpusbscsi_scsi_release, - .queuecommand = hpusbscsi_scsi_queuecommand, - - .eh_abort_handler = hpusbscsi_scsi_abort, - .eh_host_reset_handler = hpusbscsi_scsi_host_reset, - - .sg_tablesize = SG_ALL, - .can_queue = 1, - .this_id = -1, - .cmd_per_lun = 1, - .present = 0, - .unchecked_isa_dma = FALSE, - .use_clustering = TRUE, - .emulated = TRUE -}; /* defines for internal driver state */ #define HP_STATE_FREE 0 /*ready for next request */ diff -Nru a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c --- a/drivers/usb/image/microtek.c Mon Jun 9 23:16:20 2003 +++ b/drivers/usb/image/microtek.c Mon Jun 9 23:16:20 2003 @@ -160,6 +160,7 @@ static struct usb_device_id mts_usb_ids []; static struct usb_driver mts_usb_driver = { + .owner = THIS_MODULE, .name = "microtekX6", .probe = mts_usb_probe, .disconnect = mts_usb_disconnect, @@ -326,76 +327,6 @@ usb_unlink_urb( desc->urb ); } -static struct mts_desc * mts_list; /* list of active scanners */ -struct semaphore mts_list_semaphore; - -/* Internal list operations */ - -static -void mts_remove_nolock( struct mts_desc* to_remove ) -{ - MTS_DEBUG( "removing 0x%x from list\n", - (int)to_remove ); - - lock_kernel(); - mts_urb_abort(to_remove); - - MTS_DEBUG_GOT_HERE(); - - if ( to_remove != mts_list ) { - MTS_DEBUG_GOT_HERE(); - if (to_remove->prev && to_remove->next) - to_remove->prev->next = to_remove->next; - } else { - MTS_DEBUG_GOT_HERE(); - mts_list = to_remove->next; - if (mts_list) { - MTS_DEBUG_GOT_HERE(); - mts_list->prev = 0; - } - } - - if ( to_remove->next ) { - MTS_DEBUG_GOT_HERE(); - to_remove->next->prev = to_remove->prev; - } - - MTS_DEBUG_GOT_HERE(); - scsi_unregister_host(&to_remove->ctempl); - unlock_kernel(); - - usb_free_urb(to_remove->urb); - kfree( to_remove ); -} - -static -void mts_add_nolock( struct mts_desc* to_add ) -{ - MTS_DEBUG( "adding 0x%x to list\n", (int)to_add ); - - to_add->prev = 0; - to_add->next = mts_list; - if ( mts_list ) { - mts_list->prev = to_add; - } - - mts_list = to_add; -} - - - - -/* SCSI driver interface */ - -/* scsi related functions - dummies for now mostly */ - -static int mts_scsi_release(struct Scsi_Host *psh) -{ - MTS_DEBUG_GOT_HERE(); - - return 0; -} - static int mts_scsi_abort (Scsi_Cmnd *srb) { struct mts_desc* desc = (struct mts_desc*)(srb->device->host->hostdata[0]); @@ -418,54 +349,6 @@ return 0; /* RANT why here 0 and not SUCCESS */ } -/* the core of the scsi part */ - -/* faking a detection - which can't fail :-) */ - -static int mts_scsi_detect (struct SHT * sht) -{ - /* Whole function stolen from usb-storage */ - - struct mts_desc * desc = (struct mts_desc *)sht->proc_dir; - /* What a hideous hack! */ - - char local_name[48]; - - MTS_DEBUG_GOT_HERE(); - - /* set up the name of our subdirectory under /proc/scsi/ */ - sprintf(local_name, "microtek-%d", desc->host_number); - sht->proc_name = kmalloc (strlen(local_name) + 1, GFP_KERNEL); - /* FIXME: where is this freed ? */ - - if (!sht->proc_name) { - MTS_ERROR( "unable to allocate memory for proc interface!!\n" ); - return 0; - } - - strcpy(sht->proc_name, local_name); - - sht->proc_dir = NULL; - - /* In host->hostdata we store a pointer to desc */ - desc->host = scsi_register(sht, sizeof(desc)); - if (desc->host == NULL) { - MTS_ERROR("Cannot register due to low memory"); - kfree(sht->proc_name); - return 0; - } - desc->host->hostdata[0] = (unsigned long)desc; -/* FIXME: what if sizeof(void*) != sizeof(unsigned long)? */ - - return 1; -} - - - -/* Main entrypoint: SCSI commands are dispatched to here */ - - - static int mts_scsi_queuecommand (Scsi_Cmnd *srb, mts_scsi_cmnd_callback callback ); @@ -743,52 +626,22 @@ out: return err; } -/* - * this defines our 'host' - */ - -/* NOTE: This is taken from usb-storage, should be right. */ - static Scsi_Host_Template mts_scsi_host_template = { - .name = "microtekX6", - .detect = mts_scsi_detect, - .release = mts_scsi_release, - .queuecommand = mts_scsi_queuecommand, - - .eh_abort_handler = mts_scsi_abort, - .eh_host_reset_handler =mts_scsi_host_reset, - + .module = THIS_MODULE, + .name = "microtekX6", + .proc_name = "microtekX6", + .queuecommand = mts_scsi_queuecommand, + .eh_abort_handler = mts_scsi_abort, + .eh_host_reset_handler = mts_scsi_host_reset, .sg_tablesize = SG_ALL, .can_queue = 1, .this_id = -1, .cmd_per_lun = 1, - .present = 0, - .unchecked_isa_dma = FALSE, - .use_clustering = TRUE, - .emulated = TRUE + .use_clustering = 1, + .emulated = 1, }; - -/* USB layer driver interface implementation */ - -static void mts_usb_disconnect (struct usb_interface *intf) -{ - struct mts_desc* to_remove = usb_get_intfdata(intf); - - MTS_DEBUG_GOT_HERE(); - - usb_set_intfdata(intf, NULL); - if (to_remove) { - /* leave the list - lock it */ - down(&mts_list_semaphore); - - mts_remove_nolock(to_remove); - - up(&mts_list_semaphore); - } -} - struct vendor_product { char* name; @@ -836,8 +689,8 @@ MODULE_DEVICE_TABLE (usb, mts_usb_ids); -static int mts_usb_probe (struct usb_interface *intf, - const struct usb_device_id *id) +static int mts_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) { int i; int result; @@ -929,39 +782,23 @@ } - /* allocating a new descriptor */ - new_desc = (struct mts_desc *)kmalloc(sizeof(struct mts_desc), GFP_KERNEL); - if (new_desc == NULL) - { - MTS_ERROR("couldn't allocate scanner desc, bailing out!\n"); - return -ENOMEM; - } + new_desc = kmalloc(sizeof(struct mts_desc), GFP_KERNEL); + if (!new_desc) + goto out; - memset( new_desc, 0, sizeof(*new_desc) ); + memset(new_desc, 0, sizeof(*new_desc)); new_desc->urb = usb_alloc_urb(0, GFP_KERNEL); - if (!new_desc->urb) { - kfree(new_desc); - return -ENOMEM; - } - - /* initialising that descriptor */ - new_desc->usb_dev = dev; + if (!new_desc->urb) + goto out_kfree; + new_desc->usb_dev = dev; init_MUTEX(&new_desc->lock); - if(mts_list){ - new_desc->host_number = mts_list->host_number+1; - } else { - new_desc->host_number = 0; - } - /* endpoints */ - new_desc->ep_out = ep_out; new_desc->ep_response = ep_in_set[0]; new_desc->ep_image = ep_in_set[1]; - if ( new_desc->ep_out != MTS_EP_OUT ) MTS_WARNING( "will this work? Command EP is not usually %d\n", (int)new_desc->ep_out ); @@ -974,87 +811,48 @@ MTS_WARNING( "will this work? Image data EP is not usually %d\n", (int)new_desc->ep_image ); + new_desc->host = scsi_register(&mts_scsi_host_template, + sizeof(new_desc)); + if (!new_desc->host) + goto out_free_urb; - /* Initialize the host template based on the default one */ - memcpy(&(new_desc->ctempl), &mts_scsi_host_template, sizeof(mts_scsi_host_template)); - /* HACK from usb-storage - this is needed for scsi detection */ - (struct mts_desc *)new_desc->ctempl.proc_dir = new_desc; /* FIXME */ - - MTS_DEBUG("registering SCSI module\n"); - - new_desc->ctempl.module = THIS_MODULE; - result = scsi_register_host(&new_desc->ctempl); - /* Will get hit back in microtek_detect by this func */ - if ( result ) - { - MTS_ERROR( "error %d from scsi_register_host! Help!\n", - (int)result ); - - /* FIXME: need more cleanup? */ - kfree( new_desc ); - return -ENOMEM; - } - MTS_DEBUG_GOT_HERE(); - - /* FIXME: the bomb is armed, must the host be registered under lock ? */ - /* join the list - lock it */ - down(&mts_list_semaphore); - - mts_add_nolock( new_desc ); - - up(&mts_list_semaphore); - - - MTS_DEBUG("completed probe and exiting happily\n"); + new_desc->host->hostdata[0] = (unsigned long)new_desc; + scsi_add_host(new_desc->host, NULL); usb_set_intfdata(intf, new_desc); return 0; -} - + out_free_urb: + usb_free_urb(new_desc->urb); + out_kfree: + kfree(new_desc); + out: + return -ENOMEM; +} -/* get us noticed by the rest of the kernel */ - -int __init microtek_drv_init(void) +static void mts_usb_disconnect (struct usb_interface *intf) { - int result; - - MTS_DEBUG_GOT_HERE(); - init_MUTEX(&mts_list_semaphore); + struct mts_desc *desc = usb_get_intfdata(intf); - if ((result = usb_register(&mts_usb_driver)) < 0) { - MTS_DEBUG("usb_register returned %d\n", result ); - return -1; - } else { - MTS_DEBUG("driver registered.\n"); - } + usb_set_intfdata(intf, NULL); - info(DRIVER_VERSION ":" DRIVER_DESC); + scsi_remove_host(desc->host); + usb_unlink_urb(desc->urb); + scsi_unregister(desc->host); - return 0; + usb_free_urb(desc->urb); + kfree(desc); } -void __exit microtek_drv_exit(void) -{ - struct mts_desc* next; - MTS_DEBUG_GOT_HERE(); +static int __init microtek_drv_init(void) +{ + return usb_register(&mts_usb_driver); +} +static void __exit microtek_drv_exit(void) +{ usb_deregister(&mts_usb_driver); - - down(&mts_list_semaphore); - - while (mts_list) { - /* keep track of where the next one is */ - next = mts_list->next; - - mts_remove_nolock( mts_list ); - - /* advance the list pointer */ - mts_list = next; - } - - up(&mts_list_semaphore); } module_init(microtek_drv_init); diff -Nru a/drivers/usb/image/microtek.h b/drivers/usb/image/microtek.h --- a/drivers/usb/image/microtek.h Mon Jun 9 23:16:08 2003 +++ b/drivers/usb/image/microtek.h Mon Jun 9 23:16:08 2003 @@ -38,9 +38,6 @@ u8 ep_image; struct Scsi_Host * host; - Scsi_Host_Template ctempl; - int host_number; - struct semaphore lock; struct urb *urb; diff -Nru a/drivers/usb/image/scanner.c b/drivers/usb/image/scanner.c --- a/drivers/usb/image/scanner.c Mon Jun 9 23:16:08 2003 +++ b/drivers/usb/image/scanner.c Mon Jun 9 23:16:08 2003 @@ -359,6 +359,11 @@ * - Fixed endpoint detection. The endpoints were numbered from 1 to n but * that assumption is not correct in all cases. * + * 0.4.13 2003-05-30 + * - Added vendor/product ids for Genius, Hewlett-Packard, Microtek, + * Mustek, Pacific Image Electronics, Plustek, and Visioneer scanners. + * Fixed names of some other scanners. + * * TODO * - Performance * - Select/poll methods @@ -1106,6 +1111,9 @@ scn->scn_minor = intf->minor; scn->isopen = 0; + snprintf(name, sizeof(name), scanner_class.name, + intf->minor - scanner_class.minor_base); + info ("USB scanner device (0x%04x/0x%04x) now attached to %s", dev->descriptor.idVendor, dev->descriptor.idProduct, name); @@ -1144,6 +1152,7 @@ static struct usb_driver scanner_driver = { + .owner = THIS_MODULE, .name = "usbscanner", .probe = probe_scanner, .disconnect = disconnect_scanner, diff -Nru a/drivers/usb/image/scanner.h b/drivers/usb/image/scanner.h --- a/drivers/usb/image/scanner.h Mon Jun 9 23:16:10 2003 +++ b/drivers/usb/image/scanner.h Mon Jun 9 23:16:10 2003 @@ -43,7 +43,7 @@ // #define DEBUG -#define DRIVER_VERSION "0.4.11" +#define DRIVER_VERSION "0.4.13" #define DRIVER_DESC "USB Scanner Driver" #include <linux/usb.h> @@ -70,7 +70,7 @@ static struct usb_device_id scanner_device_ids [] = { /* Acer (now Benq) */ - { USB_DEVICE(0x04a5, 0x1a20) }, /* Unknown - Oliver Schwartz */ + { USB_DEVICE(0x04a5, 0x1a20) }, /* Prisa 310U */ { USB_DEVICE(0x04a5, 0x1a2a) }, /* Another 620U */ { USB_DEVICE(0x04a5, 0x2022) }, /* 340U */ { USB_DEVICE(0x04a5, 0x2040) }, /* 620U (!) */ @@ -101,6 +101,7 @@ { USB_DEVICE(0x05d8, 0x4003) }, /* E+ 48U */ { USB_DEVICE(0x05d8, 0x4004) }, /* E+ Pro */ /* Avision */ + { USB_DEVICE(0x0638, 0x0268) }, /* iVina 1200U */ { USB_DEVICE(0x0638, 0x0a10) }, /* iVina FB1600 (=Umax Astra 4500) */ /* Benq: see Acer */ /* Brother */ @@ -138,6 +139,7 @@ { USB_DEVICE(0x0458, 0x2013) }, /* ColorPage HR7 */ { USB_DEVICE(0x0458, 0x2015) }, /* ColorPage HR7LE */ { USB_DEVICE(0x0458, 0x2016) }, /* ColorPage HR6X */ + { USB_DEVICE(0x0458, 0x2018) }, /* ColorPage HR7X */ /* Hewlett Packard */ { USB_DEVICE(0x03f0, 0x0101) }, /* ScanJet 4100C */ { USB_DEVICE(0x03f0, 0x0102) }, /* PhotoSmart S20 */ @@ -157,10 +159,10 @@ { USB_DEVICE(0x03F0, 0x1005) }, /* ScanJet 5400C */ { USB_DEVICE(0x03F0, 0x1105) }, /* ScanJet 5470C */ { USB_DEVICE(0x03f0, 0x1305) }, /* Scanjet 4570c */ + { USB_DEVICE(0x03f0, 0x1411) }, /* PSC 750 */ { USB_DEVICE(0x03f0, 0x2005) }, /* ScanJet 3570c */ { USB_DEVICE(0x03f0, 0x2205) }, /* ScanJet 3500c */ - /* iVina */ - { USB_DEVICE(0x0638, 0x0268) }, /* 1200U */ + { USB_DEVICE(0x03f0, 0x2f11) }, /* PSC 1210 */ /* Lexmark */ { USB_DEVICE(0x043d, 0x002d) }, /* X70/X73 */ { USB_DEVICE(0x043d, 0x003d) }, /* X83 */ @@ -173,6 +175,7 @@ /* Microtek */ { USB_DEVICE(0x05da, 0x30ce) }, /* ScanMaker 3800 */ { USB_DEVICE(0x05da, 0x30cf) }, /* ScanMaker 4800 */ + { USB_DEVICE(0x04a7, 0x0224) }, /* Scanport 3000 (actually Visioneer?)*/ /* The following SCSI-over-USB Microtek devices are supported by the microtek driver: Enable SCSI and USB Microtek in kernel config */ // { USB_DEVICE(0x05da, 0x0099) }, /* ScanMaker X6 - X6U */ @@ -205,25 +208,30 @@ { USB_DEVICE(0x055f, 0x021d) }, /* Bearpaw 2400 CU Plus */ { USB_DEVICE(0x055f, 0x021e) }, /* BearPaw 1200 TA/CS */ { USB_DEVICE(0x055f, 0x0400) }, /* BearPaw 2400 TA PRO */ + { USB_DEVICE(0x055f, 0x0401) }, /* P 3600 A3 Pro */ { USB_DEVICE(0x055f, 0x0873) }, /* ScanExpress 600 USB */ { USB_DEVICE(0x055f, 0x1000) }, /* BearPaw 4800 TA PRO */ // { USB_DEVICE(0x05d8, 0x4002) }, /* BearPaw 1200 CU and ScanExpress 1200 UB Plus (see Artec) */ /* Nikon */ { USB_DEVICE(0x04b0, 0x4000) }, /* Coolscan LS 40 ED */ + /* Pacific Image Electronics */ + { USB_DEVICE(0x05e3, 0x0120) }, /* PrimeFilm 1800u */ /* Plustek */ + { USB_DEVICE(0x07b3, 0x0001) }, /* 1212U */ { USB_DEVICE(0x07b3, 0x0005) }, /* Unknown */ { USB_DEVICE(0x07b3, 0x0007) }, /* Unknown */ { USB_DEVICE(0x07b3, 0x000F) }, /* Unknown */ { USB_DEVICE(0x07b3, 0x0010) }, /* OpticPro U12 */ { USB_DEVICE(0x07b3, 0x0011) }, /* OpticPro U24 */ { USB_DEVICE(0x07b3, 0x0012) }, /* Unknown */ - { USB_DEVICE(0x07b3, 0x0013) }, /* Unknown */ + { USB_DEVICE(0x07b3, 0x0013) }, /* UT12 */ { USB_DEVICE(0x07b3, 0x0014) }, /* Unknown */ { USB_DEVICE(0x07b3, 0x0015) }, /* OpticPro U24 */ { USB_DEVICE(0x07b3, 0x0016) }, /* Unknown */ { USB_DEVICE(0x07b3, 0x0017) }, /* OpticPro UT12/UT16/UT24 */ { USB_DEVICE(0x07b3, 0x0400) }, /* OpticPro 1248U */ { USB_DEVICE(0x07b3, 0x0401) }, /* OpticPro 1248U (another one) */ + { USB_DEVICE(0x07b3, 0x0403) }, /* U16B */ /* Primax/Colorado */ { USB_DEVICE(0x0461, 0x0300) }, /* G2-300 #1 */ { USB_DEVICE(0x0461, 0x0301) }, /* G2E-300 #1 */ @@ -281,6 +289,8 @@ /* Visioneer */ { USB_DEVICE(0x04a7, 0x0211) }, /* OneTouch 7600 USB */ { USB_DEVICE(0x04a7, 0x0221) }, /* OneTouch 5300 USB */ + { USB_DEVICE(0x04a7, 0x0224) }, /* OneTouch 4800 USB */ + { USB_DEVICE(0x04a7, 0x0226) }, /* OneTouch 5300 USB */ { USB_DEVICE(0x04a7, 0x0231) }, /* 6100 USB */ { USB_DEVICE(0x04a7, 0x0311) }, /* 6200 EPP/USB */ { USB_DEVICE(0x04a7, 0x0321) }, /* OneTouch 8100 EPP/USB */ diff -Nru a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c --- a/drivers/usb/input/aiptek.c Mon Jun 9 23:16:16 2003 +++ b/drivers/usb/input/aiptek.c Mon Jun 9 23:16:16 2003 @@ -357,6 +357,7 @@ } static struct usb_driver aiptek_driver = { + .owner = THIS_MODULE, .name = "aiptek", .probe = aiptek_probe, .disconnect = aiptek_disconnect, diff -Nru a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c --- a/drivers/usb/input/hid-core.c Mon Jun 9 23:16:14 2003 +++ b/drivers/usb/input/hid-core.c Mon Jun 9 23:16:14 2003 @@ -1387,9 +1387,9 @@ { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_HIDDEV }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_HIDDEV }, { USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD }, - { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD }, - { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD }, - { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD }, + { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD|HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD|HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD|HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100, HID_QUIRK_IGNORE }, { USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE }, @@ -1629,8 +1629,6 @@ hid_init_reports(hid); hid_dump_device(hid); - hid_ff_init(hid); - if (!hidinput_connect(hid)) hid->claimed |= HID_CLAIMED_INPUT; if (!hiddev_connect(hid)) @@ -1680,6 +1678,7 @@ MODULE_DEVICE_TABLE (usb, hid_usb_ids); static struct usb_driver hid_driver = { + .owner = THIS_MODULE, .name = "hid", .probe = hid_probe, .disconnect = hid_disconnect, diff -Nru a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c --- a/drivers/usb/input/hid-input.c Mon Jun 9 23:16:10 2003 +++ b/drivers/usb/input/hid-input.c Mon Jun 9 23:16:10 2003 @@ -60,9 +60,39 @@ __s32 y; } hid_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; -static void hidinput_configure_usage(struct hid_device *device, struct hid_field *field, struct hid_usage *usage) +static struct input_dev *find_input(struct hid_device *hid, struct hid_field *field) { - struct input_dev *input = &device->input; + struct list_head *lh; + struct hid_input *hidinput; + + list_for_each (lh, &hid->inputs) { + int i; + + hidinput = list_entry(lh, struct hid_input, list); + + if (! hidinput->report) + continue; + + for (i = 0; i < hidinput->report->maxfield; i++) + if (hidinput->report->field[i] == field) + return &hidinput->input; + } + + /* Assume we only have one input and use it */ + if (!list_empty(&hid->inputs)) { + hidinput = list_entry(hid->inputs.next, struct hid_input, list); + return &hidinput->input; + } + + /* This is really a bug */ + return NULL; +} + +static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field, + struct hid_usage *usage) +{ + struct input_dev *input = &hidinput->input; + struct hid_device *device = hidinput->input.private; int max; int is_abs = 0; unsigned long *bit; @@ -388,9 +418,12 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value, struct pt_regs *regs) { - struct input_dev *input = &hid->input; + struct input_dev *input = find_input(hid, field); int *quirks = &hid->quirks; + if (!input) + return; + input_regs(input, regs); if (usage->hat_min != usage->hat_max) { @@ -443,7 +476,13 @@ void hidinput_report_event(struct hid_device *hid, struct hid_report *report) { - input_sync(&hid->input); + struct list_head *lh; + struct hid_input *hidinput; + + list_for_each (lh, &hid->inputs) { + hidinput = list_entry(lh, struct hid_input, list); + input_sync(&hidinput->input); + } } static int hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) @@ -490,8 +529,11 @@ struct hid_report_enum *report_enum; struct hid_report *report; struct list_head *list; + struct hid_input *hidinput = NULL; int i, j, k; + INIT_LIST_HEAD(&hid->inputs); + for (i = 0; i < hid->maxcollection; i++) if (hid->collection[i].type == HID_COLLECTION_APPLICATION && IS_INPUT_APPLICATION(hid->collection[i].usage)) @@ -500,37 +542,79 @@ if (i == hid->maxcollection) return -1; - hid->input.private = hid; - hid->input.event = hidinput_input_event; - hid->input.open = hidinput_open; - hid->input.close = hidinput_close; - - hid->input.name = hid->name; - hid->input.phys = hid->phys; - hid->input.uniq = hid->uniq; - hid->input.id.bustype = BUS_USB; - hid->input.id.vendor = dev->descriptor.idVendor; - hid->input.id.product = dev->descriptor.idProduct; - hid->input.id.version = dev->descriptor.bcdDevice; - for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) { report_enum = hid->report_enum + k; list = report_enum->report_list.next; while (list != &report_enum->report_list) { report = (struct hid_report *) list; + + if (!report->maxfield) + continue; + + if (!hidinput) { + hidinput = kmalloc(sizeof(*hidinput), GFP_KERNEL); + if (!hidinput) { + err("Out of memory during hid input probe"); + return -1; + } + memset(hidinput, 0, sizeof(*hidinput)); + + list_add_tail(&hidinput->list, &hid->inputs); + + hidinput->input.private = hid; + hidinput->input.event = hidinput_input_event; + hidinput->input.open = hidinput_open; + hidinput->input.close = hidinput_close; + + hidinput->input.name = hid->name; + hidinput->input.phys = hid->phys; + hidinput->input.uniq = hid->uniq; + hidinput->input.id.bustype = BUS_USB; + hidinput->input.id.vendor = dev->descriptor.idVendor; + hidinput->input.id.product = dev->descriptor.idProduct; + hidinput->input.id.version = dev->descriptor.bcdDevice; + } + for (i = 0; i < report->maxfield; i++) for (j = 0; j < report->field[i]->maxusage; j++) - hidinput_configure_usage(hid, report->field[i], report->field[i]->usage + j); + hidinput_configure_usage(hidinput, report->field[i], + report->field[i]->usage + j); + + if (hid->quirks & HID_QUIRK_MULTI_INPUT) { + /* This will leave hidinput NULL, so that it + * allocates another one if we have more inputs on + * the same interface. Some devices (e.g. Happ's + * UGCI) cram a lot of unrelated inputs into the + * same interface. */ + hidinput->report = report; + input_register_device(&hidinput->input); + hidinput = NULL; + } + list = list->next; } } - input_register_device(&hid->input); + /* This only gets called when we are a single-input (most of the + * time). IOW, not a HID_QUIRK_MULTI_INPUT. The hid_ff_init() is + * only useful in this case, and not for multi-input quirks. */ + if (hidinput) { + hid_ff_init(hid); + input_register_device(&hidinput->input); + } return 0; } void hidinput_disconnect(struct hid_device *hid) { - input_unregister_device(&hid->input); + struct list_head *lh, *next; + struct hid_input *hidinput; + + list_for_each_safe (lh, next, &hid->inputs) { + hidinput = list_entry(lh, struct hid_input, list); + input_unregister_device(&hidinput->input); + list_del(&hidinput->list); + kfree(hidinput); + } } diff -Nru a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c --- a/drivers/usb/input/hid-lgff.c Mon Jun 9 23:16:16 2003 +++ b/drivers/usb/input/hid-lgff.c Mon Jun 9 23:16:16 2003 @@ -254,6 +254,7 @@ signed short* ff; u16 idVendor = hid->dev->descriptor.idVendor; u16 idProduct = hid->dev->descriptor.idProduct; + struct hid_input *hidinput = list_entry(&hid->inputs, struct hid_input, list); while (dev->idVendor && (idVendor != dev->idVendor || idProduct != dev->idProduct)) dev++; @@ -261,15 +262,15 @@ ff = dev->ff; while (*ff >= 0) { - set_bit(*ff, hid->input.ffbit); + set_bit(*ff, hidinput->input.ffbit); ++ff; } - hid->input.upload_effect = hid_lgff_upload_effect; - hid->input.flush = hid_lgff_flush; + hidinput->input.upload_effect = hid_lgff_upload_effect; + hidinput->input.flush = hid_lgff_flush; - set_bit(EV_FF, hid->input.evbit); - hid->input.ff_effects_max = LGFF_EFFECTS; + set_bit(EV_FF, hidinput->input.evbit); + hidinput->input.ff_effects_max = LGFF_EFFECTS; } static void hid_lgff_exit(struct hid_device* hid) diff -Nru a/drivers/usb/input/hid-tmff.c b/drivers/usb/input/hid-tmff.c --- a/drivers/usb/input/hid-tmff.c Mon Jun 9 23:16:15 2003 +++ b/drivers/usb/input/hid-tmff.c Mon Jun 9 23:16:15 2003 @@ -110,6 +110,7 @@ { struct tmff_device *private; struct list_head *pos; + struct hid_input *hidinput = list_entry(&hid->inputs, struct hid_input, list); private = kmalloc(sizeof(struct tmff_device), GFP_KERNEL); if (!private) @@ -154,7 +155,7 @@ private->report = report; private->rumble = field; - set_bit(FF_RUMBLE, hid->input.ffbit); + set_bit(FF_RUMBLE, hidinput->input.ffbit); break; default: @@ -163,11 +164,11 @@ } /* Fallthrough to here only when a valid usage is found */ - hid->input.upload_effect = hid_tmff_upload_effect; - hid->input.flush = hid_tmff_flush; + hidinput->input.upload_effect = hid_tmff_upload_effect; + hidinput->input.flush = hid_tmff_flush; - set_bit(EV_FF, hid->input.evbit); - hid->input.ff_effects_max = TMFF_EFFECTS; + set_bit(EV_FF, hidinput->input.evbit); + hidinput->input.ff_effects_max = TMFF_EFFECTS; } } diff -Nru a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h --- a/drivers/usb/input/hid.h Mon Jun 9 23:16:05 2003 +++ b/drivers/usb/input/hid.h Mon Jun 9 23:16:05 2003 @@ -207,6 +207,7 @@ #define HID_QUIRK_NOGET 0x08 #define HID_QUIRK_HIDDEV 0x10 #define HID_QUIRK_BADPAD 0x20 +#define HID_QUIRK_MULTI_INPUT 0x40 /* * This is the global environment of the parser. This information is @@ -321,6 +322,12 @@ #define HID_CTRL_RUNNING 1 #define HID_OUT_RUNNING 2 +struct hid_input { + struct list_head list; + struct hid_report *report; + struct input_dev input; +}; + struct hid_device { /* device report descriptor */ __u8 *rdesc; unsigned rsize; @@ -360,7 +367,7 @@ unsigned claimed; /* Claimed by hidinput, hiddev? */ unsigned quirks; /* Various quirks the device can pull on us */ - struct input_dev input; /* The input structure */ + struct list_head inputs; /* The list of inputs */ void *hiddev; /* The hiddev structure */ int minor; /* Hiddev minor number */ diff -Nru a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c --- a/drivers/usb/input/hiddev.c Mon Jun 9 23:16:10 2003 +++ b/drivers/usb/input/hiddev.c Mon Jun 9 23:16:10 2003 @@ -777,6 +777,7 @@ static /* const */ struct usb_driver hiddev_driver = { + .owner = THIS_MODULE, .name = "hiddev", .probe = hiddev_usbd_probe, }; diff -Nru a/drivers/usb/input/kbtab.c b/drivers/usb/input/kbtab.c --- a/drivers/usb/input/kbtab.c Mon Jun 9 23:16:05 2003 +++ b/drivers/usb/input/kbtab.c Mon Jun 9 23:16:05 2003 @@ -207,6 +207,7 @@ } static struct usb_driver kbtab_driver = { + .owner = THIS_MODULE, .name = "kbtab", .probe = kbtab_probe, .disconnect = kbtab_disconnect, diff -Nru a/drivers/usb/input/pid.c b/drivers/usb/input/pid.c --- a/drivers/usb/input/pid.c Mon Jun 9 23:16:18 2003 +++ b/drivers/usb/input/pid.c Mon Jun 9 23:16:18 2003 @@ -269,7 +269,8 @@ int hid_pid_init(struct hid_device *hid) { struct hid_ff_pid *private; - + struct hid_input *hidinput = list_entry(&hid->inputs, struct hid_input, list); + private = hid->ff_private = kmalloc(sizeof(struct hid_ff_pid), GFP_KERNEL); if (!private) return -1; @@ -289,11 +290,11 @@ } usb_fill_control_urb(private->urbffout, hid->dev,0,(void *) &private->ffcr,private->ctrl_buffer,8,hid_pid_ctrl_out,hid); - hid->input.upload_effect = hid_pid_upload_effect; - hid->input.flush = hid_pid_flush; - hid->input.ff_effects_max = 8; // A random default - set_bit(EV_FF, hid->input.evbit); - set_bit(EV_FF_STATUS, hid->input.evbit); + hidinput->input.upload_effect = hid_pid_upload_effect; + hidinput->input.flush = hid_pid_flush; + hidinput->input.ff_effects_max = 8; // A random default + set_bit(EV_FF, hidinput->input.evbit); + set_bit(EV_FF_STATUS, hidinput->input.evbit); spin_lock_init(&private->lock); diff -Nru a/drivers/usb/input/powermate.c b/drivers/usb/input/powermate.c --- a/drivers/usb/input/powermate.c Mon Jun 9 23:16:14 2003 +++ b/drivers/usb/input/powermate.c Mon Jun 9 23:16:14 2003 @@ -426,6 +426,7 @@ MODULE_DEVICE_TABLE (usb, powermate_devices); static struct usb_driver powermate_driver = { + .owner = THIS_MODULE, .name = "powermate", .probe = powermate_probe, .disconnect = powermate_disconnect, diff -Nru a/drivers/usb/input/usbkbd.c b/drivers/usb/input/usbkbd.c --- a/drivers/usb/input/usbkbd.c Mon Jun 9 23:16:19 2003 +++ b/drivers/usb/input/usbkbd.c Mon Jun 9 23:16:19 2003 @@ -356,6 +356,7 @@ MODULE_DEVICE_TABLE (usb, usb_kbd_id_table); static struct usb_driver usb_kbd_driver = { + .owner = THIS_MODULE, .name = "usbkbd", .probe = usb_kbd_probe, .disconnect = usb_kbd_disconnect, diff -Nru a/drivers/usb/input/usbmouse.c b/drivers/usb/input/usbmouse.c --- a/drivers/usb/input/usbmouse.c Mon Jun 9 23:16:18 2003 +++ b/drivers/usb/input/usbmouse.c Mon Jun 9 23:16:18 2003 @@ -238,6 +238,7 @@ MODULE_DEVICE_TABLE (usb, usb_mouse_id_table); static struct usb_driver usb_mouse_driver = { + .owner = THIS_MODULE, .name = "usbmouse", .probe = usb_mouse_probe, .disconnect = usb_mouse_disconnect, diff -Nru a/drivers/usb/input/wacom.c b/drivers/usb/input/wacom.c --- a/drivers/usb/input/wacom.c Mon Jun 9 23:16:06 2003 +++ b/drivers/usb/input/wacom.c Mon Jun 9 23:16:06 2003 @@ -620,6 +620,7 @@ } static struct usb_driver wacom_driver = { + .owner = THIS_MODULE, .name = "wacom", .probe = wacom_probe, .disconnect = wacom_disconnect, diff -Nru a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c --- a/drivers/usb/input/xpad.c Mon Jun 9 23:16:12 2003 +++ b/drivers/usb/input/xpad.c Mon Jun 9 23:16:12 2003 @@ -333,6 +333,7 @@ } static struct usb_driver xpad_driver = { + .owner = THIS_MODULE, .name = "xpad", .probe = xpad_probe, .disconnect = xpad_disconnect, diff -Nru a/drivers/usb/media/dabusb.c b/drivers/usb/media/dabusb.c --- a/drivers/usb/media/dabusb.c Mon Jun 9 23:16:14 2003 +++ b/drivers/usb/media/dabusb.c Mon Jun 9 23:16:14 2003 @@ -767,7 +767,6 @@ } dbg("bound to interface: %d", ifnum); up (&s->mutex); - MOD_INC_USE_COUNT; usb_set_intfdata (intf, s); return 0; @@ -792,7 +791,6 @@ sleep_on (&s->remove_ok); s->usbdev = NULL; s->overruns = 0; - MOD_DEC_USE_COUNT; } } @@ -804,8 +802,8 @@ MODULE_DEVICE_TABLE (usb, dabusb_ids); -static struct usb_driver dabusb_driver = -{ +static struct usb_driver dabusb_driver = { + .owner = THIS_MODULE, .name = "dabusb", .probe = dabusb_probe, .disconnect = dabusb_disconnect, diff -Nru a/drivers/usb/media/dsbr100.c b/drivers/usb/media/dsbr100.c --- a/drivers/usb/media/dsbr100.c Mon Jun 9 23:16:10 2003 +++ b/drivers/usb/media/dsbr100.c Mon Jun 9 23:16:10 2003 @@ -137,6 +137,7 @@ MODULE_DEVICE_TABLE (usb, usb_dsbr100_table); static struct usb_driver usb_dsbr100_driver = { + .owner = THIS_MODULE, .name = "dsbr100", .probe = usb_dsbr100_probe, .disconnect = usb_dsbr100_disconnect, diff -Nru a/drivers/usb/media/ibmcam.c b/drivers/usb/media/ibmcam.c --- a/drivers/usb/media/ibmcam.c Mon Jun 9 23:16:08 2003 +++ b/drivers/usb/media/ibmcam.c Mon Jun 9 23:16:08 2003 @@ -12,18 +12,6 @@ * 5/24/00 Removed optional (and unnecessary) locking of the driver while * the device remains plugged in. Corrected race conditions in ibmcam_open * and ibmcam_probe() routines using this as a guideline: - * - * (2) The big kernel lock is automatically released when a process sleeps - * in the kernel and is automatically reacquired on reschedule if the - * process had the lock originally. Any code that can be compiled as - * a module and is entered with the big kernel lock held *MUST* - * increment the use count to activate the indirect module protection - * before doing anything that might sleep. - * - * In practice, this means that all routines that live in modules and - * are invoked under the big kernel lock should do MOD_INC_USE_COUNT - * as their very first action. And all failure paths from that - * routine must do MOD_DEC_USE_COUNT before returning. */ #include <linux/kernel.h> @@ -3865,8 +3853,6 @@ return -ENODEV; } - /* Code below may sleep, need to lock module while we are here */ - MOD_INC_USE_COUNT; uvd = usbvideo_AllocateDevice(cams); if (uvd != NULL) { /* Here uvd is a fully allocated uvd object */ @@ -3896,7 +3882,6 @@ uvd = NULL; } } - MOD_DEC_USE_COUNT; usb_set_intfdata (intf, uvd); return 0; } diff -Nru a/drivers/usb/media/konicawc.c b/drivers/usb/media/konicawc.c --- a/drivers/usb/media/konicawc.c Mon Jun 9 23:16:05 2003 +++ b/drivers/usb/media/konicawc.c Mon Jun 9 23:16:05 2003 @@ -794,8 +794,6 @@ DEBUG(1, "Selecting requested active setting=%d. maxPS=%d.", actInterface, maxPS); - /* Code below may sleep, need to lock module while we are here */ - MOD_INC_USE_COUNT; uvd = usbvideo_AllocateDevice(cams); if (uvd != NULL) { struct konicawc *cam = (struct konicawc *)(uvd->user_data); @@ -857,7 +855,6 @@ info("konicawc: %s on %s\n", cam->input.name, cam->input.phys); #endif } - MOD_DEC_USE_COUNT; if (uvd) { usb_set_intfdata (intf, uvd); diff -Nru a/drivers/usb/media/ov511.c b/drivers/usb/media/ov511.c --- a/drivers/usb/media/ov511.c Mon Jun 9 23:16:09 2003 +++ b/drivers/usb/media/ov511.c Mon Jun 9 23:16:09 2003 @@ -400,6 +400,7 @@ unsigned long); static struct file_operations ov511_control_fops = { + .owner = THIS_MODULE, .ioctl = ov51x_control_ioctl, }; @@ -6455,8 +6456,6 @@ } } - MOD_INC_USE_COUNT; - unlock_kernel(); return 0; @@ -6481,8 +6480,6 @@ else ov511_decomp_ops = NULL; } - - MOD_DEC_USE_COUNT; unlock_kernel(); } diff -Nru a/drivers/usb/media/pwc-if.c b/drivers/usb/media/pwc-if.c --- a/drivers/usb/media/pwc-if.c Mon Jun 9 23:16:16 2003 +++ b/drivers/usb/media/pwc-if.c Mon Jun 9 23:16:16 2003 @@ -92,8 +92,8 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id); static void usb_pwc_disconnect(struct usb_interface *intf); -static struct usb_driver pwc_driver = -{ +static struct usb_driver pwc_driver = { + .owner = THIS_MODULE, .name = "Philips webcam", /* name */ .id_table = pwc_device_table, .probe = usb_pwc_probe, /* probe() */ @@ -1804,7 +1804,7 @@ } memcpy(vdev, &pwc_template, sizeof(pwc_template)); strcpy(vdev->name, name); - SET_MODULE_OWNER(vdev); + vdev->owner = THIS_MODULE; pdev->vdev = vdev; vdev->priv = pdev; diff -Nru a/drivers/usb/media/se401.c b/drivers/usb/media/se401.c --- a/drivers/usb/media/se401.c Mon Jun 9 23:16:09 2003 +++ b/drivers/usb/media/se401.c Mon Jun 9 23:16:09 2003 @@ -1548,6 +1548,7 @@ } static struct usb_driver se401_driver = { + .owner = THIS_MODULE, .name = "se401", .id_table = device_table, .probe = se401_probe, diff -Nru a/drivers/usb/media/stv680.c b/drivers/usb/media/stv680.c --- a/drivers/usb/media/stv680.c Mon Jun 9 23:16:15 2003 +++ b/drivers/usb/media/stv680.c Mon Jun 9 23:16:15 2003 @@ -1549,6 +1549,7 @@ } static struct usb_driver stv680_driver = { + .owner = THIS_MODULE, .name = "stv680", .probe = stv680_probe, .disconnect = stv680_disconnect, diff -Nru a/drivers/usb/media/ultracam.c b/drivers/usb/media/ultracam.c --- a/drivers/usb/media/ultracam.c Mon Jun 9 23:16:08 2003 +++ b/drivers/usb/media/ultracam.c Mon Jun 9 23:16:08 2003 @@ -600,8 +600,6 @@ return -ENODEV; } - /* Code below may sleep, need to lock module while we are here */ - MOD_INC_USE_COUNT; uvd = usbvideo_AllocateDevice(cams); if (uvd != NULL) { /* Here uvd is a fully allocated uvd object */ @@ -631,7 +629,6 @@ uvd = NULL; } } - MOD_DEC_USE_COUNT; if (uvd) { usb_set_intfdata (intf, uvd); diff -Nru a/drivers/usb/media/vicam.c b/drivers/usb/media/vicam.c --- a/drivers/usb/media/vicam.c Mon Jun 9 23:16:09 2003 +++ b/drivers/usb/media/vicam.c Mon Jun 9 23:16:09 2003 @@ -1210,6 +1210,7 @@ MODULE_DEVICE_TABLE(usb, vicam_table); static struct usb_driver vicam_driver = { + .owner = THIS_MODULE, .name = "vicam", .probe = vicam_probe, .disconnect = vicam_disconnect, diff -Nru a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c --- a/drivers/usb/misc/auerswald.c Mon Jun 9 23:16:10 2003 +++ b/drivers/usb/misc/auerswald.c Mon Jun 9 23:16:10 2003 @@ -2129,6 +2129,7 @@ /* Standard usb driver struct */ static struct usb_driver auerswald_driver = { + .owner = THIS_MODULE, .name = "auerswald", .probe = auerswald_probe, .disconnect = auerswald_disconnect, diff -Nru a/drivers/usb/misc/emi26.c b/drivers/usb/misc/emi26.c --- a/drivers/usb/misc/emi26.c Mon Jun 9 23:16:09 2003 +++ b/drivers/usb/misc/emi26.c Mon Jun 9 23:16:09 2003 @@ -227,10 +227,11 @@ } struct usb_driver emi26_driver = { -.name = "emi26 - firmware loader", -.probe = emi26_probe, -.disconnect = emi26_disconnect, -.id_table = NULL, + .owner = THIS_MODULE, + .name = "emi26 - firmware loader", + .probe = emi26_probe, + .disconnect = emi26_disconnect, + .id_table = NULL, }; static int __init emi26_init (void) diff -Nru a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c --- a/drivers/usb/misc/rio500.c Mon Jun 9 23:16:15 2003 +++ b/drivers/usb/misc/rio500.c Mon Jun 9 23:16:15 2003 @@ -23,6 +23,9 @@ * * Based upon mouse.c (Brad Keryan) and printer.c (Michael Gee). * + * Changelog: + * 30/05/2003 replaced lock/unlock kernel with up/down + * Daniele Bellucci bellucda@tiscali.it * */ #include <linux/module.h> @@ -75,17 +78,17 @@ { struct rio_usb_data *rio = &rio_instance; - lock_kernel(); + down(&(rio->lock)); if (rio->isopen || !rio->present) { - unlock_kernel(); + up(&(rio->lock)); return -EBUSY; } rio->isopen = 1; init_waitqueue_head(&rio->wait_q); - unlock_kernel(); + up(&(rio->lock)); info("Rio opened."); @@ -460,7 +463,6 @@ return -ENOMEM; } - rio->present = 1; rio->rio_dev = dev; if (!(rio->obuf = (char *) kmalloc(OBUF_SIZE, GFP_KERNEL))) { @@ -481,6 +483,8 @@ init_MUTEX(&(rio->lock)); usb_set_intfdata (intf, rio); + rio->present = 1; + return 0; } @@ -518,13 +522,14 @@ MODULE_DEVICE_TABLE (usb, rio_table); static struct usb_driver rio_driver = { + .owner = THIS_MODULE, .name = "rio500", .probe = probe_rio, .disconnect = disconnect_rio, .id_table = rio_table, }; -int usb_rio_init(void) +static int __init usb_rio_init(void) { if (usb_register(&rio_driver) < 0) return -1; @@ -535,7 +540,7 @@ } -void usb_rio_cleanup(void) +static void __exit usb_rio_cleanup(void) { struct rio_usb_data *rio = &rio_instance; diff -Nru a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c --- a/drivers/usb/misc/usblcd.c Mon Jun 9 23:16:05 2003 +++ b/drivers/usb/misc/usblcd.c Mon Jun 9 23:16:05 2003 @@ -332,8 +332,8 @@ MODULE_DEVICE_TABLE (usb, id_table); -static struct -usb_driver lcd_driver = { +static struct usb_driver lcd_driver = { + .owner = THIS_MODULE, .name = "usblcd", .probe = (void *)probe_lcd, .disconnect = disconnect_lcd, diff -Nru a/drivers/usb/net/catc.c b/drivers/usb/net/catc.c --- a/drivers/usb/net/catc.c Mon Jun 9 23:16:11 2003 +++ b/drivers/usb/net/catc.c Mon Jun 9 23:16:11 2003 @@ -795,7 +795,7 @@ memset(catc, 0, sizeof(struct catc)); - netdev = init_etherdev(0, 0); + netdev = alloc_etherdev(0); if (!netdev) { kfree(catc); return -EIO; @@ -933,6 +933,17 @@ for (i = 0; i < 5; i++) printk("%2.2x:", netdev->dev_addr[i]); printk("%2.2x.\n", netdev->dev_addr[i]); usb_set_intfdata(intf, catc); + + if (register_netdev(netdev) != 0) { + usb_set_intfdata(intf, NULL); + usb_free_urb(catc->ctrl_urb); + usb_free_urb(catc->tx_urb); + usb_free_urb(catc->rx_urb); + usb_free_urb(catc->irq_urb); + kfree(netdev); + kfree(catc); + return -EIO; + } return 0; } @@ -966,6 +977,7 @@ MODULE_DEVICE_TABLE(usb, catc_id_table); static struct usb_driver catc_driver = { + .owner = THIS_MODULE, .name = "catc", .probe = catc_probe, .disconnect = catc_disconnect, diff -Nru a/drivers/usb/net/cdc-ether.c b/drivers/usb/net/cdc-ether.c --- a/drivers/usb/net/cdc-ether.c Mon Jun 9 23:16:06 2003 +++ b/drivers/usb/net/cdc-ether.c Mon Jun 9 23:16:06 2003 @@ -1216,7 +1216,7 @@ } // Now we need to get a kernel Ethernet interface. - net = init_etherdev( NULL, 0 ); + net = alloc_etherdev(0); if ( !net ) { // Hmm... The kernel is not sharing today... // Fine, we didn't want it anyway... @@ -1263,6 +1263,11 @@ // TODO - last minute HACK ether_dev->comm_ep_in = 5; + if (register_netdev(net) != 0) { + usb_put_dev(usb); + goto out; + } + /* FIXME!!! This driver needs to be fixed to work with the new USB interface logic * this is not the correct thing to be doing here, we need to set the interface * driver specific data field. @@ -1270,6 +1275,13 @@ // Okay, we are finally done... return 0; + +out: + usb_driver_release_interface( &CDCEther_driver, + &(usb->config[ether_dev->configuration_num].interface[ether_dev->comm_interface]) ); + + usb_driver_release_interface( &CDCEther_driver, + &(usb->config[ether_dev->configuration_num].interface[ether_dev->data_interface]) ); // bailing out with our tail between our knees error_all: usb_free_urb(ether_dev->tx_urb); @@ -1342,6 +1354,7 @@ ////////////////////////////////////////////////////////////////////////////// static struct usb_driver CDCEther_driver = { + .owner = THIS_MODULE, .name = "CDCEther", .probe = CDCEther_probe, .disconnect = CDCEther_disconnect, diff -Nru a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c --- a/drivers/usb/net/kaweth.c Mon Jun 9 23:16:15 2003 +++ b/drivers/usb/net/kaweth.c Mon Jun 9 23:16:15 2003 @@ -1016,7 +1016,7 @@ kaweth_dbg("Initializing net device."); - if(!(netdev = kmalloc(sizeof(struct net_device), GFP_KERNEL))) { + if (!(netdev = alloc_etherdev(0))) { kfree(kaweth); return -ENOMEM; } @@ -1054,18 +1054,21 @@ SET_MODULE_OWNER(netdev); - if (!init_etherdev(netdev, 0)) { + usb_set_intfdata(intf, kaweth); + + if (register_netdev(netdev) != 0) { kaweth_err("Error calling init_etherdev."); - goto err_tx_and_rx; + goto err_intfdata; } kaweth_info("kaweth interface created at %s", kaweth->net->name); kaweth_dbg("Kaweth probe returning."); - usb_set_intfdata(intf, kaweth); return 0; +err_intfdata: + usb_set_intfdata(intf, NULL); err_tx_and_rx: usb_free_urb(kaweth->rx_urb); err_only_tx: @@ -1113,6 +1116,7 @@ kaweth_dbg("Unregistering net device"); unregister_netdev(kaweth->net); + kfree(kaweth->net); } usb_free_urb(kaweth->rx_urb); diff -Nru a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c --- a/drivers/usb/net/pegasus.c Mon Jun 9 23:16:19 2003 +++ b/drivers/usb/net/pegasus.c Mon Jun 9 23:16:19 2003 @@ -865,8 +865,6 @@ if (!pegasus->rx_skb) return -ENOMEM; - down(&pegasus->sem); - set_registers(pegasus, EthID, 6, net->dev_addr); usb_fill_bulk_urb(pegasus->rx_urb, pegasus->usb, @@ -894,8 +892,6 @@ set_carrier(net); res = 0; exit: - up(&pegasus->sem); - return res; } @@ -903,13 +899,11 @@ { pegasus_t *pegasus = net->priv; - down(&pegasus->sem); pegasus->flags &= ~PEGASUS_RUNNING; netif_stop_queue(net); if (!(pegasus->flags & PEGASUS_UNPLUG)) disable_net_traffic(pegasus); unlink_all_urbs(pegasus); - up(&pegasus->sem); return 0; } @@ -1068,7 +1062,6 @@ pegasus_t *pegasus = net->priv; int res; - down(&pegasus->sem); switch (cmd) { case SIOCETHTOOL: res = pegasus_ethtool_ioctl(net, rq->ifr_data); @@ -1080,17 +1073,14 @@ res = 0; break; case SIOCDEVPRIVATE + 2: - if (!capable(CAP_NET_ADMIN)) { - up(&pegasus->sem); + if (!capable(CAP_NET_ADMIN)) return -EPERM; - } write_mii_word(pegasus, pegasus->phy, data[1] & 0x1f, data[2]); res = 0; break; default: res = -EOPNOTSUPP; } - up(&pegasus->sem); return res; } @@ -1170,33 +1160,27 @@ struct net_device *net; pegasus_t *pegasus; int dev_index = id - pegasus_ids; + int res = -ENOMEM; + usb_get_dev(dev); if (!(pegasus = kmalloc(sizeof (struct pegasus), GFP_KERNEL))) { err("out of memory allocating device structure"); - return -ENOMEM; + goto out; } - usb_get_dev(dev); memset(pegasus, 0, sizeof (struct pegasus)); pegasus->dev_index = dev_index; init_waitqueue_head(&pegasus->ctrl_wait); - if (!alloc_urbs(pegasus)) { - kfree(pegasus); - return -ENOMEM; - } + if (!alloc_urbs(pegasus)) + goto out1; - net = init_etherdev(NULL, 0); - if (!net) { - free_all_urbs(pegasus); - kfree(pegasus); - return -ENODEV; - } + net = alloc_etherdev(0); + if (!net) + goto out2; - init_MUTEX(&pegasus->sem); tasklet_init(&pegasus->rx_tl, rx_fixup, (unsigned long) pegasus); - down(&pegasus->sem); pegasus->usb = dev; pegasus->net = net; SET_MODULE_OWNER(net); @@ -1221,12 +1205,8 @@ get_interrupt_interval(pegasus); if (reset_mac(pegasus)) { err("can't reset MAC"); - unregister_netdev(pegasus->net); - free_all_urbs(pegasus); - kfree(pegasus->net); - kfree(pegasus); - pegasus = NULL; - goto exit; + res = -EIO; + goto out3; } set_ethernet_addr(pegasus); fill_skb_pool(pegasus); @@ -1240,13 +1220,24 @@ warn("can't locate MII phy, using default"); pegasus->phy = 1; } -exit: - up(&pegasus->sem); - if (pegasus) { - usb_set_intfdata(intf, pegasus); - return 0; - } - return -EIO; + usb_set_intfdata(intf, pegasus); + res = register_netdev(net); + if (res) + goto out4; + return 0; + +out4: + usb_set_intfdata(intf, NULL); + free_skb_pool(pegasus); +out3: + kfree(net); +out2: + free_all_urbs(pegasus); +out1: + kfree(pegasus); +out: + usb_put_dev(dev); + return res; } static void pegasus_disconnect(struct usb_interface *intf) @@ -1269,10 +1260,10 @@ dev_kfree_skb(pegasus->rx_skb); kfree(pegasus->net); kfree(pegasus); - pegasus = NULL; } static struct usb_driver pegasus_driver = { + .owner = THIS_MODULE, .name = driver_name, .probe = pegasus_probe, .disconnect = pegasus_disconnect, diff -Nru a/drivers/usb/net/pegasus.h b/drivers/usb/net/pegasus.h --- a/drivers/usb/net/pegasus.h Mon Jun 9 23:16:19 2003 +++ b/drivers/usb/net/pegasus.h Mon Jun 9 23:16:19 2003 @@ -98,7 +98,6 @@ struct sk_buff *rx_skb; struct usb_ctrlrequest dr; wait_queue_head_t ctrl_wait; - struct semaphore sem; spinlock_t rx_pool_lock; int chip; unsigned char intr_buff[8]; diff -Nru a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c --- a/drivers/usb/net/rtl8150.c Mon Jun 9 23:16:14 2003 +++ b/drivers/usb/net/rtl8150.c Mon Jun 9 23:16:14 2003 @@ -88,7 +88,6 @@ struct rtl8150 { unsigned long flags; struct usb_device *udev; - struct semaphore sem; struct tasklet_struct tl; struct net_device_stats stats; struct net_device *netdev; @@ -115,6 +114,7 @@ const struct usb_device_id *id); static struct usb_driver rtl8150_driver = { + .owner = THIS_MODULE, .name = "rtl8150", .probe = rtl8150_probe, .disconnect = rtl8150_disconnect, @@ -637,8 +637,6 @@ if (!dev->rx_skb) return -ENOMEM; - down(&dev->sem); - set_registers(dev, IDR, 6, netdev->dev_addr); usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1), @@ -652,7 +650,6 @@ warn("%s: intr_urb submit failed: %d", __FUNCTION__, res); netif_start_queue(netdev); enable_net_traffic(dev); - up(&dev->sem); return res; } @@ -666,12 +663,10 @@ if (!dev) return -ENODEV; - down(&dev->sem); netif_stop_queue(netdev); if (!test_bit(RTL8150_UNPLUG, &dev->flags)) disable_net_traffic(dev); unlink_all_urbs(dev); - up(&dev->sem); return res; } @@ -759,7 +754,6 @@ data = (u16 *) & rq->ifr_data; res = 0; - down(&dev->sem); switch (cmd) { case SIOCETHTOOL: res = rtl8150_ethtool_ioctl(netdev, rq->ifr_data); @@ -770,16 +764,13 @@ read_mii_word(dev, dev->phy, (data[1] & 0x1f), &data[3]); break; case SIOCDEVPRIVATE + 2: - if (!capable(CAP_NET_ADMIN)) { - up(&dev->sem); + if (!capable(CAP_NET_ADMIN)) return -EPERM; - } write_mii_word(dev, dev->phy, (data[1] & 0x1f), data[2]); break; default: res = -EOPNOTSUPP; } - up(&dev->sem); return res; } @@ -797,18 +788,16 @@ } else memset(dev, 0, sizeof(rtl8150_t)); - netdev = init_etherdev(NULL, 0); + netdev = alloc_etherdev(0); if (!netdev) { kfree(dev); err("Oh boy, out of memory again?!?"); return -ENOMEM; } - init_MUTEX(&dev->sem); tasklet_init(&dev->tl, rx_fixup, (unsigned long)dev); spin_lock_init(&dev->rx_pool_lock); - down(&dev->sem); dev->udev = udev; dev->netdev = netdev; SET_MODULE_OWNER(netdev); @@ -827,23 +816,30 @@ if (!alloc_all_urbs(dev)) { err("out of memory"); - goto err; + goto out; } if (!rtl8150_reset(dev)) { err("couldn't reset the device"); - free_all_urbs(dev); - goto err; + goto out1; } fill_skb_pool(dev); set_ethernet_addr(dev); info("%s: rtl8150 is detected", netdev->name); - up(&dev->sem); usb_set_intfdata(intf, dev); + + if (register_netdev(netdev) != 0) { + err("couldn't register the device"); + goto out2; + } return 0; -err: - unregister_netdev(dev->netdev); - up(&dev->sem); + +out2: + usb_set_intfdata(intf, NULL); + free_skb_pool(dev); +out1: + free_all_urbs(dev); +out: kfree(netdev); kfree(dev); return -EIO; @@ -864,8 +860,6 @@ dev_kfree_skb(dev->rx_skb); kfree(dev->netdev); kfree(dev); - dev->netdev = NULL; - dev = NULL; } } diff -Nru a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c --- a/drivers/usb/net/usbnet.c Mon Jun 9 23:16:13 2003 +++ b/drivers/usb/net/usbnet.c Mon Jun 9 23:16:13 2003 @@ -205,7 +205,6 @@ // housekeeping struct usb_device *udev; struct driver_info *driver_info; - struct semaphore mutex; wait_queue_head_t *wait; // i/o info: pipes etc @@ -214,7 +213,7 @@ struct timer_list delay; // protocol/interface state - struct net_device net; + struct net_device *net; struct net_device_stats stats; int msg_level; unsigned long data [5]; @@ -295,27 +294,24 @@ MODULE_PARM_DESC (msg_level, "Initial message level (default = 1)"); -#define mutex_lock(x) down(x) -#define mutex_unlock(x) up(x) - #define RUN_CONTEXT (in_irq () ? "in_irq" \ : (in_interrupt () ? "in_interrupt" : "can sleep")) #ifdef DEBUG #define devdbg(usbnet, fmt, arg...) \ - printk(KERN_DEBUG "%s: " fmt "\n" , (usbnet)->net.name , ## arg) + printk(KERN_DEBUG "%s: " fmt "\n" , (usbnet)->net->name , ## arg) #else #define devdbg(usbnet, fmt, arg...) do {} while(0) #endif #define deverr(usbnet, fmt, arg...) \ - printk(KERN_ERR "%s: " fmt "\n" , (usbnet)->net.name , ## arg) + printk(KERN_ERR "%s: " fmt "\n" , (usbnet)->net->name , ## arg) #define devwarn(usbnet, fmt, arg...) \ - printk(KERN_WARNING "%s: " fmt "\n" , (usbnet)->net.name , ## arg) + printk(KERN_WARNING "%s: " fmt "\n" , (usbnet)->net->name , ## arg) #define devinfo(usbnet, fmt, arg...) \ do { if ((usbnet)->msg_level >= 1) \ - printk(KERN_INFO "%s: " fmt "\n" , (usbnet)->net.name , ## arg); \ + printk(KERN_INFO "%s: " fmt "\n" , (usbnet)->net->name , ## arg); \ } while (0) /*-------------------------------------------------------------------------*/ @@ -505,7 +501,7 @@ else if (tmp != 12) return -EINVAL; for (i = tmp = 0; i < 6; i++, tmp += 2) - dev->net.dev_addr [i] = + dev->net->dev_addr [i] = (nibble (buf [tmp]) << 4) + nibble (buf [tmp + 1]); return 0; } @@ -605,7 +601,7 @@ * in routine cases. info->ether describes the multicast support. */ - dev->net.mtu = cpu_to_le16p (&info->ether->wMaxSegmentSize) + dev->net->mtu = cpu_to_le16p (&info->ether->wMaxSegmentSize) - ETH_HLEN; return 0; @@ -806,18 +802,18 @@ // detect whether another side is connected if ((retval = gl_control_write (dev, GENELINK_CONNECT_WRITE, 0)) != 0) { dbg ("%s: genelink_check_connect write fail - %X", - dev->net.name, retval); + dev->net->name, retval); return retval; } // usb interrupt read to ack another side if ((retval = gl_interrupt_read (dev)) != 0) { dbg ("%s: genelink_check_connect read fail - %X", - dev->net.name, retval); + dev->net->name, retval); return retval; } - dbg ("%s: genelink_check_connect read success", dev->net.name); + dbg ("%s: genelink_check_connect read success", dev->net->name); return 0; } @@ -829,14 +825,14 @@ // allocate the private data structure if ((priv = kmalloc (sizeof *priv, GFP_KERNEL)) == 0) { dbg ("%s: cannot allocate private data per device", - dev->net.name); + dev->net->name); return -ENOMEM; } // allocate irq urb if ((priv->irq_urb = usb_alloc_urb (0, GFP_KERNEL)) == 0) { dbg ("%s: cannot allocate private irq urb per device", - dev->net.name); + dev->net->name); kfree (priv); return -ENOMEM; } @@ -920,14 +916,11 @@ if (gl_skb) { // copy the packet data to the new skb - memcpy (gl_skb->data, packet->packet_data, size); - - // set skb data size - gl_skb->len = size; - gl_skb->dev = &dev->net; + memcpy(skb_put(gl_skb, size), packet->packet_data, size); + gl_skb->dev = dev->net; // determine the packet's protocol ID - gl_skb->protocol = eth_type_trans (gl_skb, &dev->net); + gl_skb->protocol = eth_type_trans (gl_skb, dev->net); // update the status dev->stats.rx_packets++; @@ -1143,7 +1136,7 @@ return; } - dbg ("%s registers:", dev->net.name); + dbg ("%s registers:", dev->net->name); for (reg = 0; reg < 0x20; reg++) { int retval; @@ -1156,10 +1149,10 @@ retval = nc_register_read (dev, reg, vp); if (retval < 0) dbg ("%s reg [0x%x] ==> error %d", - dev->net.name, reg, retval); + dev->net->name, reg, retval); else dbg ("%s reg [0x%x] = 0x%x", - dev->net.name, reg, *vp); + dev->net->name, reg, *vp); } kfree (vp); } @@ -1321,7 +1314,7 @@ nc_register_write (dev, REG_TTL, MK_TTL (NC_READ_TTL_MS, TTL_OTHER (ttl)) ); - dbg ("%s: assigned TTL, %d ms", dev->net.name, NC_READ_TTL_MS); + dbg ("%s: assigned TTL, %d ms", dev->net->name, NC_READ_TTL_MS); if (dev->msg_level >= 2) devinfo (dev, "port %c, peer %sconnected", @@ -1347,7 +1340,7 @@ status = *vp; kfree (vp); if (retval != 0) { - dbg ("%s net1080_check_conn read - %d", dev->net.name, retval); + dbg ("%s net1080_check_conn read - %d", dev->net->name, retval); return retval; } if ((status & STATUS_CONN_OTHER) != STATUS_CONN_OTHER) @@ -1416,11 +1409,11 @@ if (!(skb->len & 0x01) || MIN_FRAMED > skb->len - || skb->len > FRAMED_SIZE (dev->net.mtu)) { + || skb->len > FRAMED_SIZE (dev->net->mtu)) { dev->stats.rx_frame_errors++; dbg ("rx framesize %d range %d..%d mtu %d", skb->len, - (int)MIN_FRAMED, (int)FRAMED_SIZE (dev->net.mtu), - dev->net.mtu); + (int)MIN_FRAMED, (int)FRAMED_SIZE (dev->net->mtu), + dev->net->mtu); nc_ensure_sync (dev); return 0; } @@ -1795,7 +1788,7 @@ #ifdef CONFIG_USB_NET1080 if (dev->driver_info->flags & FLAG_FRAMING_NC) - size = FRAMED_SIZE (dev->net.mtu); + size = FRAMED_SIZE (dev->net->mtu); else #endif #ifdef CONFIG_USB_GENESYS @@ -1805,10 +1798,10 @@ #endif #ifdef CONFIG_USB_ZAURUS if (dev->driver_info->flags & FLAG_FRAMING_Z) - size = 6 + (sizeof (struct ethhdr) + dev->net.mtu); + size = 6 + (sizeof (struct ethhdr) + dev->net->mtu); else #endif - size = (sizeof (struct ethhdr) + dev->net.mtu); + size = (sizeof (struct ethhdr) + dev->net->mtu); if ((skb = alloc_skb (size, flags)) == 0) { devdbg (dev, "no rx skb"); @@ -1829,8 +1822,8 @@ spin_lock_irqsave (&dev->rxq.lock, lockflags); - if (netif_running (&dev->net) - && netif_device_present (&dev->net) + if (netif_running (dev->net) + && netif_device_present (dev->net) && !test_bit (EVENT_RX_HALT, &dev->flags)) { switch (retval = usb_submit_urb (urb, GFP_ATOMIC)){ case -EPIPE: @@ -1841,7 +1834,7 @@ break; case -ENODEV: devdbg (dev, "device gone"); - netif_device_detach (&dev->net); + netif_device_detach (dev->net); break; default: devdbg (dev, "rx submit, %d", retval); @@ -1874,8 +1867,8 @@ if (skb->len) { int status; - skb->dev = &dev->net; - skb->protocol = eth_type_trans (skb, &dev->net); + skb->dev = dev->net; + skb->protocol = eth_type_trans (skb, dev->net); dev->stats.rx_packets++; dev->stats.rx_bytes += skb->len; @@ -1968,7 +1961,7 @@ defer_bh (dev, skb); if (urb) { - if (netif_running (&dev->net) + if (netif_running (dev->net) && !test_bit (EVENT_RX_HALT, &dev->flags)) { rx_submit (dev, urb, GFP_ATOMIC); return; @@ -2024,7 +2017,6 @@ DECLARE_WAIT_QUEUE_HEAD (unlink_wakeup); DECLARE_WAITQUEUE (wait, current); - mutex_lock (&dev->mutex); netif_stop_queue (net); if (dev->msg_level >= 2) @@ -2054,7 +2046,6 @@ del_timer_sync (&dev->delay); tasklet_kill (&dev->bh); - mutex_unlock (&dev->mutex); return 0; } @@ -2070,8 +2061,6 @@ int retval = 0; struct driver_info *info = dev->driver_info; - mutex_lock (&dev->mutex); - // put into "known safe" state if (info->reset && (retval = info->reset (dev)) < 0) { devinfo (dev, "open reset fail (%d) usbnet usb-%s-%s, %s", @@ -2091,7 +2080,7 @@ if (dev->msg_level >= 2) devinfo (dev, "open: enable queueing " "(rx %d, tx %d) mtu %d %s framing", - RX_QLEN (dev), TX_QLEN (dev), dev->net.mtu, + RX_QLEN (dev), TX_QLEN (dev), dev->net->mtu, (info->flags & (FLAG_FRAMING_NC | FLAG_FRAMING_GL)) ? ((info->flags & FLAG_FRAMING_NC) ? "NetChip" @@ -2102,7 +2091,6 @@ // delay posting reads until we're fully open tasklet_schedule (&dev->bh); done: - mutex_unlock (&dev->mutex); return retval; } @@ -2201,7 +2189,7 @@ status); else { clear_bit (EVENT_TX_HALT, &dev->flags); - netif_wake_queue (&dev->net); + netif_wake_queue (dev->net); } } if (test_bit (EVENT_RX_HALT, &dev->flags)) { @@ -2220,7 +2208,7 @@ if (test_bit (EVENT_RX_MEMORY, &dev->flags)) { struct urb *urb = 0; - if (netif_running (&dev->net)) + if (netif_running (dev->net)) urb = usb_alloc_urb (0, GFP_KERNEL); else clear_bit (EVENT_RX_MEMORY, &dev->flags); @@ -2265,7 +2253,7 @@ jiffies + THROTTLE_JIFFIES); devdbg (dev, "tx throttle %d", urb->status); } - netif_stop_queue (&dev->net); + netif_stop_queue (dev->net); break; default: devdbg (dev, "tx err %d", entry->urb->status); @@ -2438,8 +2426,8 @@ } // or are we maybe short a few urbs? - } else if (netif_running (&dev->net) - && netif_device_present (&dev->net) + } else if (netif_running (dev->net) + && netif_device_present (dev->net) && !timer_pending (&dev->delay) && !test_bit (EVENT_RX_HALT, &dev->flags)) { int temp = dev->rxq.qlen; @@ -2461,7 +2449,7 @@ tasklet_schedule (&dev->bh); } if (dev->txq.qlen < TX_QLEN (dev)) - netif_wake_queue (&dev->net); + netif_wake_queue (dev->net); } } @@ -2491,11 +2479,12 @@ xdev->bus->bus_name, xdev->devpath, dev->driver_info->description); - unregister_netdev (&dev->net); + unregister_netdev (dev->net); if (dev->driver_info->unbind) dev->driver_info->unbind (dev, intf); + kfree(dev->net); kfree (dev); usb_put_dev (xdev); } @@ -2523,15 +2512,17 @@ xdev = interface_to_usbdev (udev); interface = &udev->altsetting [udev->act_altsetting]; + usb_get_dev (xdev); + + status = -ENOMEM; + // set up our own records if (!(dev = kmalloc (sizeof *dev, GFP_KERNEL))) { dbg ("can't kmalloc dev"); - return -ENOMEM; + goto out; } memset (dev, 0, sizeof *dev); - init_MUTEX_LOCKED (&dev->mutex); - usb_get_dev (xdev); dev->udev = xdev; dev->driver_info = info; dev->msg_level = msg_level; @@ -2546,16 +2537,16 @@ init_timer (&dev->delay); // set up network interface records - net = &dev->net; + net = alloc_etherdev(0); + if (!net) + goto out1; + SET_MODULE_OWNER (net); + dev->net = net; net->priv = dev; strcpy (net->name, "usb%d"); memcpy (net->dev_addr, node_id, sizeof node_id); - // point-to-point link ... we always use Ethernet headers - // supports win32 interop (some devices) and the bridge driver. - ether_setup (net); - // possible with some EHCI controllers if (dma_supported (&udev->dev, 0xffffffffffffffffULL)) net->features |= NETIF_F_HIGHDMA; @@ -2592,26 +2583,37 @@ status = 0; } - if (status < 0) { - kfree (dev); - return status; - } + if (status < 0) + goto out2; + dev->maxpacket = usb_maxpacket (dev->udev, dev->out, 1); - SET_NETDEV_DEV(&dev->net, &dev->udev->dev); - register_netdev (&dev->net); + SET_NETDEV_DEV(dev->net, &dev->udev->dev); + status = register_netdev (dev->net); + if (status) + goto out3; devinfo (dev, "register usbnet at usb-%s-%s, %s", xdev->bus->bus_name, xdev->devpath, dev->driver_info->description); // ok, it's ready to go. usb_set_intfdata (udev, dev); - mutex_unlock (&dev->mutex); // start as if the link is up - netif_device_attach (&dev->net); + netif_device_attach (dev->net); return 0; + +out3: + if (info->unbind) + info->unbind (dev, udev); +out2: + kfree(net); +out1: + kfree(dev); +out: + usb_put_dev(xdev); + return status; } @@ -2780,6 +2782,7 @@ MODULE_DEVICE_TABLE (usb, products); static struct usb_driver usbnet_driver = { + .owner = THIS_MODULE, .name = driver_name, .id_table = products, .probe = usbnet_probe, diff -Nru a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig --- a/drivers/usb/serial/Kconfig Mon Jun 9 23:16:16 2003 +++ b/drivers/usb/serial/Kconfig Mon Jun 9 23:16:16 2003 @@ -351,6 +351,7 @@ - USB TWIN - KAAN Standard Plus + - KAAN SIM - SecOVID Reader Plus - B1 Professional - KAAN Professional diff -Nru a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c --- a/drivers/usb/serial/belkin_sa.c Mon Jun 9 23:16:14 2003 +++ b/drivers/usb/serial/belkin_sa.c Mon Jun 9 23:16:14 2003 @@ -118,6 +118,7 @@ MODULE_DEVICE_TABLE (usb, id_table_combined); static struct usb_driver belkin_driver = { + .owner = THIS_MODULE, .name = "belkin", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, diff -Nru a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c --- a/drivers/usb/serial/cyberjack.c Mon Jun 9 23:16:18 2003 +++ b/drivers/usb/serial/cyberjack.c Mon Jun 9 23:16:18 2003 @@ -74,6 +74,7 @@ MODULE_DEVICE_TABLE (usb, id_table); static struct usb_driver cyberjack_driver = { + .owner = THIS_MODULE, .name = "cyberjack", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, diff -Nru a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c --- a/drivers/usb/serial/digi_acceleport.c Mon Jun 9 23:16:11 2003 +++ b/drivers/usb/serial/digi_acceleport.c Mon Jun 9 23:16:11 2003 @@ -499,6 +499,7 @@ MODULE_DEVICE_TABLE (usb, id_table_combined); static struct usb_driver digi_driver = { + .owner = THIS_MODULE, .name = "digi_acceleport", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, diff -Nru a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c --- a/drivers/usb/serial/empeg.c Mon Jun 9 23:16:19 2003 +++ b/drivers/usb/serial/empeg.c Mon Jun 9 23:16:19 2003 @@ -111,6 +111,7 @@ MODULE_DEVICE_TABLE (usb, id_table); static struct usb_driver empeg_driver = { + .owner = THIS_MODULE, .name = "empeg", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, @@ -459,14 +460,15 @@ static int empeg_startup (struct usb_serial *serial) { + int r; dbg("%s", __FUNCTION__); dbg("%s - Set config to 1", __FUNCTION__); - usb_set_configuration (serial->dev, 1); + r = usb_set_configuration (serial->dev, 1); /* continue on with initialization */ - return 0; + return r; } diff -Nru a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c --- a/drivers/usb/serial/ftdi_sio.c Mon Jun 9 23:16:16 2003 +++ b/drivers/usb/serial/ftdi_sio.c Mon Jun 9 23:16:16 2003 @@ -152,6 +152,7 @@ MODULE_DEVICE_TABLE (usb, id_table_combined); static struct usb_driver ftdi_driver = { + .owner = THIS_MODULE, .name = "ftdi_sio", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, diff -Nru a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c --- a/drivers/usb/serial/io_edgeport.c Mon Jun 9 23:16:06 2003 +++ b/drivers/usb/serial/io_edgeport.c Mon Jun 9 23:16:06 2003 @@ -464,6 +464,7 @@ #include "io_tables.h" /* all of the devices that this driver supports */ static struct usb_driver io_driver = { + .owner = THIS_MODULE, .name = "io_edgeport", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, diff -Nru a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c --- a/drivers/usb/serial/io_ti.c Mon Jun 9 23:16:19 2003 +++ b/drivers/usb/serial/io_ti.c Mon Jun 9 23:16:19 2003 @@ -162,6 +162,7 @@ MODULE_DEVICE_TABLE (usb, id_table_combined); static struct usb_driver io_driver = { + .owner = THIS_MODULE, .name = "io_ti", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, diff -Nru a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c --- a/drivers/usb/serial/ipaq.c Mon Jun 9 23:16:17 2003 +++ b/drivers/usb/serial/ipaq.c Mon Jun 9 23:16:17 2003 @@ -138,6 +138,7 @@ MODULE_DEVICE_TABLE (usb, ipaq_id_table); static struct usb_driver ipaq_driver = { + .owner = THIS_MODULE, .name = "ipaq", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, diff -Nru a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c --- a/drivers/usb/serial/ir-usb.c Mon Jun 9 23:16:11 2003 +++ b/drivers/usb/serial/ir-usb.c Mon Jun 9 23:16:11 2003 @@ -130,6 +130,7 @@ MODULE_DEVICE_TABLE (usb, id_table); static struct usb_driver ir_driver = { + .owner = THIS_MODULE, .name = "ir-usb", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, diff -Nru a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h --- a/drivers/usb/serial/keyspan.h Mon Jun 9 23:16:15 2003 +++ b/drivers/usb/serial/keyspan.h Mon Jun 9 23:16:15 2003 @@ -477,6 +477,7 @@ MODULE_DEVICE_TABLE(usb, keyspan_ids_combined); static struct usb_driver keyspan_driver = { + .owner = THIS_MODULE, .name = "keyspan", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, diff -Nru a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c --- a/drivers/usb/serial/keyspan_pda.c Mon Jun 9 23:16:15 2003 +++ b/drivers/usb/serial/keyspan_pda.c Mon Jun 9 23:16:15 2003 @@ -155,6 +155,7 @@ MODULE_DEVICE_TABLE (usb, id_table_combined); static struct usb_driver keyspan_pda_driver = { + .owner = THIS_MODULE, .name = "keyspan_pda", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, diff -Nru a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c --- a/drivers/usb/serial/kl5kusb105.c Mon Jun 9 23:16:14 2003 +++ b/drivers/usb/serial/kl5kusb105.c Mon Jun 9 23:16:14 2003 @@ -123,6 +123,7 @@ MODULE_DEVICE_TABLE (usb, id_table); static struct usb_driver kl5kusb105d_driver = { + .owner = THIS_MODULE, .name = "kl5kusb105d", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, diff -Nru a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c --- a/drivers/usb/serial/kobil_sct.c Mon Jun 9 23:16:18 2003 +++ b/drivers/usb/serial/kobil_sct.c Mon Jun 9 23:16:18 2003 @@ -21,7 +21,8 @@ * Supported readers: USB TWIN, KAAN Standard Plus and SecOVID Reader Plus * (Adapter K), B1 Professional and KAAN Professional (Adapter B) * - * TODO: High baudrates + * (28/05/2003) tw + * Add support for KAAN SIM * * (12/09/2002) tw * Adapted to 2.5. @@ -58,7 +59,7 @@ #include "usb-serial.h" /* Version Information */ -#define DRIVER_VERSION "12/09/2002" +#define DRIVER_VERSION "28/05/2003" #define DRIVER_AUTHOR "KOBIL Systems GmbH - http://www.kobil.com" #define DRIVER_DESC "KOBIL USB Smart Card Terminal Driver (experimental)" @@ -66,6 +67,7 @@ #define KOBIL_ADAPTER_B_PRODUCT_ID 0x2011 #define KOBIL_ADAPTER_K_PRODUCT_ID 0x2012 #define KOBIL_USBTWIN_PRODUCT_ID 0x0078 +#define KOBIL_KAAN_SIM_PRODUCT_ID 0x0081 #define KOBIL_TIMEOUT 500 #define KOBIL_BUF_LENGTH 300 @@ -92,12 +94,22 @@ { USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_ADAPTER_B_PRODUCT_ID) }, { USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_ADAPTER_K_PRODUCT_ID) }, { USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_USBTWIN_PRODUCT_ID) }, + { USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_KAAN_SIM_PRODUCT_ID) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, id_table); +static struct usb_driver kobil_driver = { + .owner = THIS_MODULE, + .name = "kobil", + .probe = usb_serial_probe, + .disconnect = usb_serial_disconnect, + .id_table = id_table, +}; + + struct usb_serial_device_type kobil_device = { .owner = THIS_MODULE, .name = "KOBIL USB smart card terminal", @@ -161,6 +173,9 @@ case KOBIL_USBTWIN_PRODUCT_ID: printk(KERN_DEBUG "KOBIL USBTWIN detected\n"); break; + case KOBIL_KAAN_SIM_PRODUCT_ID: + printk(KERN_DEBUG "KOBIL KAAN SIM detected\n"); + break; } usb_set_serial_port_data(serial->port, priv); @@ -353,7 +368,7 @@ struct usb_serial_port *port = (struct usb_serial_port *) purb->context; struct tty_struct *tty; unsigned char *data = purb->transfer_buffer; - char *dbg_data; +// char *dbg_data; dbg("%s - port %d", __FUNCTION__, port->number); @@ -366,16 +381,18 @@ if (purb->actual_length) { // BEGIN DEBUG - dbg_data = (unsigned char *) kmalloc((3 * purb->actual_length + 10) * sizeof(char), GFP_KERNEL); - if (! dbg_data) { - return; - } - memset(dbg_data, 0, (3 * purb->actual_length + 10)); - for (i = 0; i < purb->actual_length; i++) { - sprintf(dbg_data +3*i, "%02X ", data[i]); - } - dbg(" <-- %s", dbg_data ); - kfree(dbg_data); + /* + dbg_data = (unsigned char *) kmalloc((3 * purb->actual_length + 10) * sizeof(char), GFP_KERNEL); + if (! dbg_data) { + return; + } + memset(dbg_data, 0, (3 * purb->actual_length + 10)); + for (i = 0; i < purb->actual_length; i++) { + sprintf(dbg_data +3*i, "%02X ", data[i]); + } + dbg(" <-- %s", dbg_data ); + kfree(dbg_data); + */ // END DEBUG for (i = 0; i < purb->actual_length; ++i) { @@ -438,7 +455,7 @@ priv->filled = priv->filled + count; - // only send complete block. TWIN and adapter K use the same protocol. + // only send complete block. TWIN, KAAN SIM and adapter K use the same protocol. if ( ((priv->device_type != KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 2) && (priv->filled >= (priv->buf[1] + 3))) || ((priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID) && (priv->filled > 3) && (priv->filled >= (priv->buf[2] + 4))) ) { @@ -503,7 +520,7 @@ int transfer_buffer_length = 8; priv = usb_get_serial_port_data(port); - if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID) { + if ((priv->device_type == KOBIL_USBTWIN_PRODUCT_ID) || (priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)) { // This device doesn't support ioctl calls return -EINVAL; } @@ -549,7 +566,7 @@ int transfer_buffer_length = 8; priv = usb_get_serial_port_data(port); - if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID) { + if ((priv->device_type == KOBIL_USBTWIN_PRODUCT_ID) || (priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)) { // This device doesn't support ioctl calls return -EINVAL; } @@ -616,7 +633,7 @@ char *settings; priv = usb_get_serial_port_data(port); - if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID) { + if ((priv->device_type == KOBIL_USBTWIN_PRODUCT_ID) || (priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)) { // This device doesn't support ioctl calls return 0; } @@ -727,6 +744,7 @@ static int __init kobil_init (void) { usb_serial_register (&kobil_device); + usb_register (&kobil_driver); info(DRIVER_VERSION " " DRIVER_AUTHOR); info(DRIVER_DESC); @@ -737,6 +755,7 @@ static void __exit kobil_exit (void) { + usb_deregister (&kobil_driver); usb_serial_deregister (&kobil_device); } diff -Nru a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c --- a/drivers/usb/serial/mct_u232.c Mon Jun 9 23:16:15 2003 +++ b/drivers/usb/serial/mct_u232.c Mon Jun 9 23:16:15 2003 @@ -144,6 +144,7 @@ MODULE_DEVICE_TABLE (usb, id_table_combined); static struct usb_driver mct_u232_driver = { + .owner = THIS_MODULE, .name = "mct_u232", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, diff -Nru a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c --- a/drivers/usb/serial/omninet.c Mon Jun 9 23:16:18 2003 +++ b/drivers/usb/serial/omninet.c Mon Jun 9 23:16:18 2003 @@ -84,6 +84,7 @@ MODULE_DEVICE_TABLE (usb, id_table); static struct usb_driver omninet_driver = { + .owner = THIS_MODULE, .name = "omninet", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, diff -Nru a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c --- a/drivers/usb/serial/pl2303.c Mon Jun 9 23:16:11 2003 +++ b/drivers/usb/serial/pl2303.c Mon Jun 9 23:16:11 2003 @@ -84,6 +84,7 @@ MODULE_DEVICE_TABLE (usb, id_table); static struct usb_driver pl2303_driver = { + .owner = THIS_MODULE, .name = "pl2303", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, diff -Nru a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c --- a/drivers/usb/serial/safe_serial.c Mon Jun 9 23:16:08 2003 +++ b/drivers/usb/serial/safe_serial.c Mon Jun 9 23:16:08 2003 @@ -162,6 +162,7 @@ MODULE_DEVICE_TABLE (usb, id_table); static struct usb_driver safe_driver = { + .owner = THIS_MODULE, .name = "safe_serial", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, diff -Nru a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c --- a/drivers/usb/serial/usb-serial.c Mon Jun 9 23:16:10 2003 +++ b/drivers/usb/serial/usb-serial.c Mon Jun 9 23:16:10 2003 @@ -366,6 +366,7 @@ /* Driver structure we register with the USB core */ static struct usb_driver usb_serial_driver = { + .owner = THIS_MODULE, .name = "usbserial", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, @@ -1303,11 +1304,8 @@ .magic = TTY_DRIVER_MAGIC, .owner = THIS_MODULE, .driver_name = "usbserial", -#ifndef CONFIG_DEVFS_FS + .devfs_name = "usb/tts/", .name = "ttyUSB", -#else - .name = "usb/tts/", -#endif .major = SERIAL_TTY_MAJOR, .minor_start = 0, .num = SERIAL_TTY_MINORS, diff -Nru a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c --- a/drivers/usb/serial/visor.c Mon Jun 9 23:16:09 2003 +++ b/drivers/usb/serial/visor.c Mon Jun 9 23:16:09 2003 @@ -256,6 +256,7 @@ MODULE_DEVICE_TABLE (usb, id_table_combined); static struct usb_driver visor_driver = { + .owner = THIS_MODULE, .name = "visor", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, diff -Nru a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c --- a/drivers/usb/serial/whiteheat.c Mon Jun 9 23:16:09 2003 +++ b/drivers/usb/serial/whiteheat.c Mon Jun 9 23:16:10 2003 @@ -127,6 +127,7 @@ MODULE_DEVICE_TABLE (usb, id_table_combined); static struct usb_driver whiteheat_driver = { + .owner = THIS_MODULE, .name = "whiteheat", .probe = usb_serial_probe, .disconnect = usb_serial_disconnect, diff -Nru a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c --- a/drivers/usb/storage/datafab.c Mon Jun 9 23:16:19 2003 +++ b/drivers/usb/storage/datafab.c Mon Jun 9 23:16:19 2003 @@ -670,7 +670,7 @@ srb->result = SUCCESS; } else { info->sense_key = UNIT_ATTENTION; - srb->result = CHECK_CONDITION << 1; + srb->result = SAM_STAT_CHECK_CONDITION; } return rc; } diff -Nru a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c --- a/drivers/usb/storage/freecom.c Mon Jun 9 23:16:19 2003 +++ b/drivers/usb/storage/freecom.c Mon Jun 9 23:16:19 2003 @@ -399,7 +399,7 @@ } } - result = usb_control_msg(us->pusb_dev, us->recv_ctrl_pipe, + result = usb_stor_control_msg(us, us->recv_ctrl_pipe, 0x4c, 0xc0, 0x4346, 0x0, buffer, 0x20, 3*HZ); buffer[32] = '\0'; US_DEBUGP("String returned from FC init is: %s\n", buffer); @@ -411,7 +411,7 @@ */ /* send reset */ - result = usb_control_msg(us->pusb_dev, us->send_ctrl_pipe, + result = usb_stor_control_msg(us, us->send_ctrl_pipe, 0x4d, 0x40, 0x24d8, 0x0, NULL, 0x0, 3*HZ); US_DEBUGP("result from activate reset is %d\n", result); @@ -419,7 +419,7 @@ mdelay(250); /* clear reset */ - result = usb_control_msg(us->pusb_dev, us->send_ctrl_pipe, + result = usb_stor_control_msg(us, us->send_ctrl_pipe, 0x4d, 0x40, 0x24f8, 0x0, NULL, 0x0, 3*HZ); US_DEBUGP("result from clear reset is %d\n", result); diff -Nru a/drivers/usb/storage/initializers.c b/drivers/usb/storage/initializers.c --- a/drivers/usb/storage/initializers.c Mon Jun 9 23:16:10 2003 +++ b/drivers/usb/storage/initializers.c Mon Jun 9 23:16:10 2003 @@ -50,7 +50,7 @@ int result; US_DEBUGP("Attempting to init eUSCSI bridge...\n"); - result = usb_control_msg(us->pusb_dev, us->send_ctrl_pipe, + result = usb_stor_control_msg(us, us->send_ctrl_pipe, 0x0C, USB_RECIP_INTERFACE | USB_TYPE_VENDOR, 0x01, 0x0, &data, 0x1, 5*HZ); US_DEBUGP("-- result is %d\n", result); diff -Nru a/drivers/usb/storage/initializers.h b/drivers/usb/storage/initializers.h --- a/drivers/usb/storage/initializers.h Mon Jun 9 23:16:12 2003 +++ b/drivers/usb/storage/initializers.h Mon Jun 9 23:16:12 2003 @@ -39,6 +39,7 @@ #include <linux/config.h> #include "usb.h" +#include "transport.h" /* This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target * mode */ diff -Nru a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c --- a/drivers/usb/storage/isd200.c Mon Jun 9 23:16:12 2003 +++ b/drivers/usb/storage/isd200.c Mon Jun 9 23:16:12 2003 @@ -558,7 +558,7 @@ case USB_STOR_TRANSPORT_GOOD: /* Indicate a good result */ - srb->result = GOOD << 1; + srb->result = SAM_STAT_GOOD; break; case USB_STOR_TRANSPORT_FAILED: @@ -598,11 +598,11 @@ } if (result == ISD200_GOOD) { isd200_build_sense(us, srb); - srb->result = CHECK_CONDITION << 1; + srb->result = SAM_STAT_CHECK_CONDITION; /* If things are really okay, then let's show that */ if ((srb->sense_buffer[2] & 0xf) == 0x0) - srb->result = GOOD << 1; + srb->result = SAM_STAT_GOOD; } else srb->result = DID_ERROR << 16; } @@ -611,7 +611,7 @@ * condition, show that in the result code */ if (transferStatus == USB_STOR_TRANSPORT_FAILED) - srb->result = CHECK_CONDITION << 1; + srb->result = SAM_STAT_CHECK_CONDITION; } #ifdef CONFIG_USB_STORAGE_DEBUG @@ -1185,7 +1185,7 @@ /* copy InquiryData */ isd200_data_copy(srb, (char *) &info->InquiryData, srb->request_bufflen); - srb->result = GOOD << 1; + srb->result = SAM_STAT_GOOD; sendToTransport = FALSE; break; @@ -1205,7 +1205,7 @@ srb->request_bufflen = 0; } else { US_DEBUGP(" Media Status not supported, just report okay\n"); - srb->result = GOOD << 1; + srb->result = SAM_STAT_GOOD; sendToTransport = FALSE; } break; @@ -1226,7 +1226,7 @@ srb->request_bufflen = 0; } else { US_DEBUGP(" Media Status not supported, just report okay\n"); - srb->result = GOOD << 1; + srb->result = SAM_STAT_GOOD; sendToTransport = FALSE; } break; @@ -1252,7 +1252,7 @@ srb->request_bufflen = sizeof(struct read_capacity_data); isd200_data_copy(srb, (char *) &readCapacityData, srb->request_bufflen); - srb->result = GOOD << 1; + srb->result = SAM_STAT_GOOD; sendToTransport = FALSE; } break; @@ -1336,7 +1336,7 @@ srb->request_bufflen = 0; } else { US_DEBUGP(" Not removeable media, just report okay\n"); - srb->result = GOOD << 1; + srb->result = SAM_STAT_GOOD; sendToTransport = FALSE; } break; @@ -1365,7 +1365,7 @@ srb->request_bufflen = 0; } else { US_DEBUGP(" Nothing to do, just report okay\n"); - srb->result = GOOD << 1; + srb->result = SAM_STAT_GOOD; sendToTransport = FALSE; } break; diff -Nru a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c --- a/drivers/usb/storage/jumpshot.c Mon Jun 9 23:16:06 2003 +++ b/drivers/usb/storage/jumpshot.c Mon Jun 9 23:16:06 2003 @@ -611,7 +611,7 @@ srb->result = SUCCESS; } else { info->sense_key = UNIT_ATTENTION; - srb->result = CHECK_CONDITION << 1; + srb->result = SAM_STAT_CHECK_CONDITION; } return rc; } diff -Nru a/drivers/usb/storage/protocol.c b/drivers/usb/storage/protocol.c --- a/drivers/usb/storage/protocol.c Mon Jun 9 23:16:05 2003 +++ b/drivers/usb/storage/protocol.c Mon Jun 9 23:16:05 2003 @@ -137,8 +137,7 @@ /* send the command to the transport layer */ usb_stor_invoke_transport(srb, us); - if (srb->result == GOOD << 1) { - + if (srb->result == SAM_STAT_GOOD) { /* fix the INQUIRY data if necessary */ fix_inquiry_data(srb); } @@ -210,7 +209,7 @@ /* send the command to the transport layer */ usb_stor_invoke_transport(srb, us); - if (srb->result == GOOD << 1) { + if (srb->result == SAM_STAT_GOOD) { /* Fix the MODE_SENSE data if we translated the command */ if (old_cmnd == MODE_SENSE) @@ -307,7 +306,7 @@ /* send the command to the transport layer */ usb_stor_invoke_transport(srb, us); - if (srb->result == GOOD << 1) { + if (srb->result == SAM_STAT_GOOD) { /* Fix the MODE_SENSE data if we translated the command */ if (old_cmnd == MODE_SENSE) @@ -376,7 +375,7 @@ /* send the command to the transport layer */ usb_stor_invoke_transport(srb, us); - if (srb->result == GOOD << 1) { + if (srb->result == SAM_STAT_GOOD) { /* Fix the MODE_SENSE data if we translated the command */ if ((us->flags & US_FL_MODE_XLATE) && (old_cmnd == MODE_SENSE)) diff -Nru a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c --- a/drivers/usb/storage/scsiglue.c Mon Jun 9 23:16:12 2003 +++ b/drivers/usb/storage/scsiglue.c Mon Jun 9 23:16:12 2003 @@ -171,9 +171,11 @@ /* This is always called with scsi_lock(srb->host) held */ static int usb_storage_command_abort( Scsi_Cmnd *srb ) { - struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; + struct Scsi_Host *host = srb->device->host; + struct us_data *us = (struct us_data *) host->hostdata[0]; + int state = atomic_read(&us->sm_state); - US_DEBUGP("command_abort() called\n"); + US_DEBUGP("%s called\n", __FUNCTION__); /* Is this command still active? */ if (us->srb != srb) { @@ -181,7 +183,31 @@ return FAILED; } - return usb_stor_abort_transport(us); + /* Normally the current state is RUNNING. If the control thread + * hasn't even started processing this command, the state will be + * IDLE. Anything else is a bug. */ + if (state != US_STATE_RUNNING && state != US_STATE_IDLE) { + printk(KERN_ERR USB_STORAGE "Error in %s: " + "invalid state %d\n", __FUNCTION__, state); + return FAILED; + } + + /* Set state to ABORTING, set the ABORTING bit, and release the lock */ + atomic_set(&us->sm_state, US_STATE_ABORTING); + set_bit(US_FLIDX_ABORTING, &us->flags); + scsi_unlock(host); + + /* If the state was RUNNING, stop an ongoing USB transfer */ + if (state == US_STATE_RUNNING) + usb_stor_stop_transport(us); + + /* Wait for the aborted command to finish */ + wait_for_completion(&us->notify); + + /* Reacquire the lock and allow USB transfers to resume */ + scsi_lock(host); + clear_bit(US_FLIDX_ABORTING, &us->flags); + return SUCCESS; } /* This invokes the transport reset mechanism to reset the state of the @@ -193,7 +219,7 @@ int state = atomic_read(&us->sm_state); int result; - US_DEBUGP("device_reset() called\n" ); + US_DEBUGP("%s called\n", __FUNCTION__); if (state != US_STATE_IDLE) { printk(KERN_ERR USB_STORAGE "Error in %s: " "invalid state %d\n", __FUNCTION__, state); @@ -219,39 +245,49 @@ return result; } -/* This resets the device port */ +/* This resets the device's USB port. */ /* It refuses to work if there's more than one interface in - this device, so that other users are not affected. */ + * the device, so that other users are not affected. */ /* This is always called with scsi_lock(srb->host) held */ - static int usb_storage_bus_reset( Scsi_Cmnd *srb ) { - struct us_data *us; + struct us_data *us = (struct us_data *)srb->device->host->hostdata[0]; + int state = atomic_read(&us->sm_state); int result; - /* we use the usb_reset_device() function to handle this for us */ - US_DEBUGP("bus_reset() called\n"); + US_DEBUGP("%s called\n", __FUNCTION__); + if (state != US_STATE_IDLE) { + printk(KERN_ERR USB_STORAGE "Error in %s: " + "invalid state %d\n", __FUNCTION__, state); + return FAILED; + } + + /* set the state and release the lock */ + atomic_set(&us->sm_state, US_STATE_RESETTING); scsi_unlock(srb->device->host); - us = (struct us_data *)srb->device->host->hostdata[0]; /* The USB subsystem doesn't handle synchronisation between a device's several drivers. Therefore we reset only devices - with one interface which we of course own. + with just one interface, which we of course own. */ - + //FIXME: needs locking against config changes - - if ( us->pusb_dev->actconfig->desc.bNumInterfaces == 1) { - /* attempt to reset the port */ + + if (us->pusb_dev->actconfig->desc.bNumInterfaces == 1) { + + /* lock the device and attempt to reset the port */ + down(&(us->dev_semaphore)); result = usb_reset_device(us->pusb_dev); + up(&(us->dev_semaphore)); US_DEBUGP("usb_reset_device returns %d\n", result); } else { result = -EBUSY; - US_DEBUGP("cannot reset a multiinterface device. failing to reset.\n"); + US_DEBUGP("Refusing to reset a multi-interface device\n"); } - US_DEBUGP("bus_reset() complete\n"); + /* lock access to the state and clear it */ scsi_lock(srb->device->host); + atomic_set(&us->sm_state, US_STATE_IDLE); return result < 0 ? FAILED : SUCCESS; } @@ -264,33 +300,21 @@ #define SPRINTF(args...) \ do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0) -static int usb_storage_proc_info (char *buffer, char **start, off_t offset, - int length, int hostno, int inout) +static int usb_storage_proc_info (struct Scsi_Host *hostptr, char *buffer, char **start, off_t offset, + int length, int inout) { struct us_data *us; char *pos = buffer; - struct Scsi_Host *hostptr; unsigned long f; /* if someone is sending us data, just throw it away */ if (inout) return length; - /* find our data from the given hostno */ - hostptr = scsi_host_hn_get(hostno); - if (!hostptr) { /* if we couldn't find it, we return an error */ - return -ESRCH; - } us = (struct us_data*)hostptr->hostdata[0]; - /* if we couldn't find it, we return an error */ - if (!us) { - scsi_host_put(hostptr); - return -ESRCH; - } - /* print the controller name */ - SPRINTF(" Host scsi%d: usb-storage\n", hostno); + SPRINTF(" Host scsi%d: usb-storage\n", hostptr->host_no); /* print product, vendor, and serial number strings */ SPRINTF(" Vendor: %s\n", us->vendor); @@ -318,9 +342,6 @@ *(pos++) = '\n'; } - - /* release the reference count on this host */ - scsi_host_put(hostptr); /* * Calculate start of next buffer, and return value. diff -Nru a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c --- a/drivers/usb/storage/transport.c Mon Jun 9 23:16:10 2003 +++ b/drivers/usb/storage/transport.c Mon Jun 9 23:16:10 2003 @@ -69,32 +69,35 @@ * as those occurring during device-specific initialization, must be handled * by a separate code path.) * - * The abort function first sets the machine state, then atomically - * tests-and-clears the CAN_CANCEL bit in us->flags to see if the current_urb - * needs to be aborted. - * - * The submit function first verifies that the submission completed without - * errors, and only then sets the CAN_CANCEL bit. This prevents the abort - * function from trying to cancel the URB while the submit call is underway. - * Next, the submit function must test the state to see if we got aborted - * before the submission or before setting the CAN_CANCEL bit. If so, it's - * essential to abort the URB if it hasn't been cancelled already (i.e., - * if the CAN_CANCEL bit is still set). Either way, the function must then - * wait for the URB to finish. Note that because the URB_ASYNC_UNLINK flag - * is set, the URB can still be in progress even after a call to - * usb_unlink_urb() returns. - * - * (It's also permissible, but not necessary, to test the state -before- - * submitting the URB. Doing so would prevent an unnecessary submission if - * the transaction had already been aborted, but this is very unlikely to - * happen, because the abort would have to have been requested during actual - * kernel processing rather than during an I/O delay.) - * - * The idea is that (1) once the state is changed to ABORTING, either the - * aborting function or the submitting function is guaranteed to call - * usb_unlink_urb() for an active URB, and (2) test_and_clear_bit() prevents - * usb_unlink_urb() from being called more than once or from being called - * during usb_submit_urb(). + * The abort function (usb_storage_command_abort() in scsiglue.c) first + * sets the machine state and the ABORTING bit in us->flags to prevent + * new URBs from being submitted. It then calls usb_stor_stop_transport() + * below, which atomically tests-and-clears the URB_ACTIVE bit in us->flags + * to see if the current_urb needs to be stopped. Likewise, the SG_ACTIVE + * bit is tested to see if the current_sg scatter-gather request needs to be + * stopped. The timeout callback routine does much the same thing. + * + * When a disconnect occurs, the DISCONNECTING bit in us->flags is set to + * prevent new URBs from being submitted, and usb_stor_stop_transport() is + * called to stop any ongoing requests. + * + * The submit function first verifies that the submitting is allowed + * (neither ABORTING nor DISCONNECTING bits are set) and that the submit + * completes without errors, and only then sets the URB_ACTIVE bit. This + * prevents the stop_transport() function from trying to cancel the URB + * while the submit call is underway. Next, the submit function must test + * the flags to see if an abort or disconnect occurred during the submission + * or before the URB_ACTIVE bit was set. If so, it's essential to cancel + * the URB if it hasn't been cancelled already (i.e., if the URB_ACTIVE bit + * is still set). Either way, the function must then wait for the URB to + * finish. Note that because the URB_ASYNC_UNLINK flag is set, the URB can + * still be in progress even after a call to usb_unlink_urb() returns. + * + * The idea is that (1) once the ABORTING or DISCONNECTING bit is set, + * either the stop_transport() function or the submitting function + * is guaranteed to call usb_unlink_urb() for an active URB, + * and (2) test_and_clear_bit() prevents usb_unlink_urb() from being + * called more than once or from being called during usb_submit_urb(). */ /* This is the completion handler which will wake us up when an URB @@ -106,6 +109,19 @@ complete(urb_done_ptr); } + +/* This is the timeout handler which will cancel an URB when its timeout + * expires. + */ +static void timeout_handler(unsigned long us_) +{ + struct us_data *us = (struct us_data *) us_; + + if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->flags)) { + US_DEBUGP("Timeout -- cancelling URB\n"); + usb_unlink_urb(us->current_urb); + } +} /* This is the common part of the URB message submission code * @@ -113,11 +129,16 @@ * command _must_ pass through this function (or something like it) for the * abort mechanisms to work properly. */ -static int usb_stor_msg_common(struct us_data *us) +static int usb_stor_msg_common(struct us_data *us, int timeout) { struct completion urb_done; + struct timer_list to_timer; int status; + /* don't submit URBS during abort/disconnect processing */ + if (us->flags & DONT_SUBMIT) + return -ECONNRESET; + /* set up data structures for the wakeup system */ init_completion(&urb_done); @@ -137,35 +158,53 @@ /* since the URB has been submitted successfully, it's now okay * to cancel it */ - set_bit(US_FLIDX_CAN_CANCEL, &us->flags); + set_bit(US_FLIDX_URB_ACTIVE, &us->flags); - /* has the current command been aborted? */ - if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { + /* did an abort/disconnect occur during the submission? */ + if (us->flags & DONT_SUBMIT) { /* cancel the URB, if it hasn't been cancelled already */ - if (test_and_clear_bit(US_FLIDX_CAN_CANCEL, &us->flags)) { + if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->flags)) { US_DEBUGP("-- cancelling URB\n"); usb_unlink_urb(us->current_urb); } } + + /* submit the timeout timer, if a timeout was requested */ + if (timeout > 0) { + init_timer(&to_timer); + to_timer.expires = jiffies + timeout; + to_timer.function = timeout_handler; + to_timer.data = (unsigned long) us; + add_timer(&to_timer); + } /* wait for the completion of the URB */ wait_for_completion(&urb_done); - clear_bit(US_FLIDX_CAN_CANCEL, &us->flags); + clear_bit(US_FLIDX_URB_ACTIVE, &us->flags); + + /* clean up the timeout timer */ + if (timeout > 0) + del_timer_sync(&to_timer); /* return the URB status */ return us->current_urb->status; } -/* This is our function to emulate usb_control_msg() with enough control - * to make aborts/resets/timeouts work +/* + * Transfer one control message, with timeouts, and allowing early + * termination. Return codes are usual -Exxx, *not* USB_STOR_XFER_xxx. */ int usb_stor_control_msg(struct us_data *us, unsigned int pipe, - u8 request, u8 requesttype, u16 value, u16 index, - void *data, u16 size) + u8 request, u8 requesttype, u16 value, u16 index, + void *data, u16 size, int timeout) { int status; + US_DEBUGP("%s: rq=%02x rqtype=%02x value=%04x index=%02x len=%u\n", + __FUNCTION__, request, requesttype, + value, index, size); + /* fill in the devrequest structure */ us->dr->bRequestType = requesttype; us->dr->bRequest = request; @@ -177,7 +216,7 @@ usb_fill_control_urb(us->current_urb, us->pusb_dev, pipe, (unsigned char*) us->dr, data, size, usb_stor_blocking_completion, NULL); - status = usb_stor_msg_common(us); + status = usb_stor_msg_common(us, timeout); /* return the actual length of the data transferred if no error */ if (status == 0) @@ -185,56 +224,9 @@ return status; } -/* This is our function to emulate usb_bulk_msg() with enough control - * to make aborts/resets/timeouts work - */ -int usb_stor_bulk_msg(struct us_data *us, void *data, unsigned int pipe, - unsigned int len, unsigned int *act_len) -{ - int status; - - /* fill and submit the URB */ - usb_fill_bulk_urb(us->current_urb, us->pusb_dev, pipe, data, len, - usb_stor_blocking_completion, NULL); - status = usb_stor_msg_common(us); - - /* store the actual length of the data transferred */ - *act_len = us->current_urb->actual_length; - return status; -} - -/* This is our function to submit interrupt URBs with enough control - * to make aborts/resets/timeouts work - * - * This routine always uses us->recv_intr_pipe as the pipe and - * us->ep_bInterval as the interrupt interval. - */ -int usb_stor_interrupt_msg(struct us_data *us, void *data, - unsigned int len, unsigned int *act_len) -{ - unsigned int pipe = us->recv_intr_pipe; - unsigned int maxp; - int status; - - /* calculate the max packet size */ - maxp = usb_maxpacket(us->pusb_dev, pipe, usb_pipeout(pipe)); - if (maxp > len) - maxp = len; - - /* fill and submit the URB */ - usb_fill_int_urb(us->current_urb, us->pusb_dev, pipe, data, - maxp, usb_stor_blocking_completion, NULL, - us->ep_bInterval); - status = usb_stor_msg_common(us); - - /* store the actual length of the data transferred */ - *act_len = us->current_urb->actual_length; - return status; -} - -/* This is a version of usb_clear_halt() that doesn't read the status from - * the device -- this is because some devices crash their internal firmware - * when the status is requested after a halt. +/* This is a version of usb_clear_halt() that allows early termination and + * doesn't read the status from the device -- this is because some devices + * crash their internal firmware when the status is requested after a halt. * * A definitive list of these 'bad' devices is too difficult to maintain or * make complete enough to be useful. This problem was first observed on the @@ -254,12 +246,7 @@ result = usb_stor_control_msg(us, us->send_ctrl_pipe, USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, - endp, NULL, 0); /* note: no 3*HZ timeout */ - US_DEBUGP("usb_stor_clear_halt: result=%d\n", result); - - /* this is a failure case */ - if (result < 0) - return result; + endp, NULL, 0, 3*HZ); /* reset the toggles and endpoint flags */ usb_endpoint_running(us->pusb_dev, usb_pipeendpoint(pipe), @@ -267,7 +254,8 @@ usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0); - return 0; + US_DEBUGP("%s: result = %d\n", __FUNCTION__, result); + return result; } @@ -275,12 +263,12 @@ * Interpret the results of a URB transfer * * This function prints appropriate debugging messages, clears halts on - * bulk endpoints, and translates the status to the corresponding + * 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) { - + unsigned int length, int result, unsigned int partial) +{ US_DEBUGP("Status code %d; transferred %u/%u\n", result, partial, length); switch (result) { @@ -333,95 +321,109 @@ } /* - * Transfer one control message - * - * This function does basically the same thing as usb_stor_control_msg() - * above, except that return codes are USB_STOR_XFER_xxx rather than the - * urb status or transfer length. + * Transfer one control message, without timeouts, but allowing early + * termination. Return codes are USB_STOR_XFER_xxx. */ int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe, u8 request, u8 requesttype, u16 value, u16 index, - void *data, u16 size) { + void *data, u16 size) +{ int result; - unsigned int partial = 0; - US_DEBUGP("usb_stor_ctrl_transfer(): rq=%02x rqtype=%02x " - "value=%04x index=%02x len=%u\n", - request, requesttype, value, index, size); - result = usb_stor_control_msg(us, pipe, request, requesttype, - value, index, data, size); + US_DEBUGP("%s: rq=%02x rqtype=%02x value=%04x index=%02x len=%u\n", + __FUNCTION__, request, requesttype, + value, index, size); - if (result > 0) { /* Separate out the amount transferred */ - partial = result; - result = 0; - } - return interpret_urb_result(us, pipe, size, result, partial); + /* fill in the devrequest structure */ + us->dr->bRequestType = requesttype; + us->dr->bRequest = request; + us->dr->wValue = cpu_to_le16(value); + us->dr->wIndex = cpu_to_le16(index); + us->dr->wLength = cpu_to_le16(size); + + /* fill and submit the URB */ + usb_fill_control_urb(us->current_urb, us->pusb_dev, pipe, + (unsigned char*) us->dr, data, size, + usb_stor_blocking_completion, NULL); + result = usb_stor_msg_common(us, 0); + + return interpret_urb_result(us, pipe, size, result, + us->current_urb->actual_length); } /* - * Receive one buffer via interrupt transfer + * Receive one interrupt buffer, without timeouts, but allowing early + * termination. Return codes are USB_STOR_XFER_xxx. * - * This function does basically the same thing as usb_stor_interrupt_msg() - * above, except that return codes are USB_STOR_XFER_xxx rather than the - * urb status. + * This routine always uses us->recv_intr_pipe as the pipe and + * us->ep_bInterval as the interrupt interval. */ -int usb_stor_intr_transfer(struct us_data *us, void *buf, - unsigned int length, unsigned int *act_len) +int usb_stor_intr_transfer(struct us_data *us, void *buf, unsigned int length) { int result; - unsigned int partial; + unsigned int pipe = us->recv_intr_pipe; + unsigned int maxp; - /* transfer the data */ - US_DEBUGP("usb_stor_intr_transfer(): xfer %u bytes\n", length); - result = usb_stor_interrupt_msg(us, buf, length, &partial); - if (act_len) - *act_len = partial; + US_DEBUGP("%s: xfer %u bytes\n", __FUNCTION__, length); - return interpret_urb_result(us, us->recv_intr_pipe, - length, result, partial); + /* calculate the max packet size */ + maxp = usb_maxpacket(us->pusb_dev, pipe, usb_pipeout(pipe)); + if (maxp > length) + maxp = length; + + /* fill and submit the URB */ + usb_fill_int_urb(us->current_urb, us->pusb_dev, pipe, buf, + maxp, usb_stor_blocking_completion, NULL, + us->ep_bInterval); + result = usb_stor_msg_common(us, 0); + + return interpret_urb_result(us, pipe, length, result, + us->current_urb->actual_length); } /* - * Transfer one buffer via bulk transfer - * - * This function does basically the same thing as usb_stor_bulk_msg() - * above, except that: - * - * 1. If the bulk pipe stalls during the transfer, the halt is - * automatically cleared; - * 2. Return codes are USB_STOR_XFER_xxx rather than the - * urb status or transfer length. + * Transfer one buffer via bulk pipe, without timeouts, but allowing early + * termination. Return codes are USB_STOR_XFER_xxx. If the bulk pipe + * stalls during the transfer, the halt is automatically cleared. */ int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe, void *buf, unsigned int length, unsigned int *act_len) { int result; - unsigned int partial; - /* transfer the data */ - US_DEBUGP("usb_stor_bulk_transfer_buf(): xfer %u bytes\n", length); - result = usb_stor_bulk_msg(us, buf, pipe, length, &partial); + US_DEBUGP("%s: xfer %u bytes\n", __FUNCTION__, length); + + /* fill and submit the URB */ + usb_fill_bulk_urb(us->current_urb, us->pusb_dev, pipe, buf, length, + usb_stor_blocking_completion, NULL); + result = usb_stor_msg_common(us, 0); + + /* store the actual length of the data transferred */ if (act_len) - *act_len = partial; - return interpret_urb_result(us, pipe, length, result, partial); + *act_len = us->current_urb->actual_length; + return interpret_urb_result(us, pipe, length, result, + us->current_urb->actual_length); } /* * Transfer a scatter-gather list via bulk transfer * * This function does basically the same thing as usb_stor_bulk_transfer_buf() - * above, but it uses the usbcore scatter-gather primitives + * 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; - unsigned int partial; + + /* don't submit s-g requests during abort/disconnect processing */ + if (us->flags & DONT_SUBMIT) + return USB_STOR_XFER_ERROR; /* initialize the scatter-gather request block */ - US_DEBUGP("usb_stor_bulk_transfer_sglist(): xfer %u bytes, " - "%d entries\n", length, num_sg); + 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) { @@ -431,13 +433,13 @@ /* since the block has been initialized successfully, it's now * okay to cancel it */ - set_bit(US_FLIDX_CANCEL_SG, &us->flags); + set_bit(US_FLIDX_SG_ACTIVE, &us->flags); - /* has the current command been aborted? */ - if (atomic_read(&us->sm_state) == US_STATE_ABORTING) { + /* did an abort/disconnect occur during the submission? */ + if (us->flags & DONT_SUBMIT) { /* cancel the request, if it hasn't been cancelled already */ - if (test_and_clear_bit(US_FLIDX_CANCEL_SG, &us->flags)) { + if (test_and_clear_bit(US_FLIDX_SG_ACTIVE, &us->flags)) { US_DEBUGP("-- cancelling sg request\n"); usb_sg_cancel(us->current_sg); } @@ -445,13 +447,13 @@ /* wait for the completion of the transfer */ usb_sg_wait(us->current_sg); - clear_bit(US_FLIDX_CANCEL_SG, &us->flags); + clear_bit(US_FLIDX_SG_ACTIVE, &us->flags); result = us->current_sg->status; - partial = us->current_sg->bytes; if (act_len) - *act_len = partial; - return interpret_urb_result(us, pipe, length, result, partial); + *act_len = us->current_sg->bytes; + return interpret_urb_result(us, pipe, length, result, + us->current_sg->bytes); } /* @@ -516,7 +518,6 @@ } /* if there is a transport error, reset and don't auto-sense */ - /* What if we want to abort during the reset? */ if (result == USB_STOR_TRANSPORT_ERROR) { US_DEBUGP("-- transport indicates error, resetting\n"); us->transport_reset(us); @@ -585,6 +586,7 @@ unsigned char old_sc_data_direction; unsigned char old_cmd_len; unsigned char old_cmnd[MAX_COMMAND_SIZE]; + unsigned long old_serial_number; US_DEBUGP("Issuing auto-REQUEST_SENSE\n"); @@ -620,6 +622,10 @@ old_sg = srb->use_sg; srb->use_sg = 0; + /* change the serial number -- toggle the high bit*/ + old_serial_number = srb->serial_number; + srb->serial_number ^= 0x80000000; + /* issue the auto-sense command */ temp_result = us->transport(us->srb, us); @@ -627,6 +633,7 @@ srb->request_buffer = old_request_buffer; srb->request_bufflen = old_request_bufflen; srb->use_sg = old_sg; + srb->serial_number = old_serial_number; srb->sc_data_direction = old_sc_data_direction; srb->cmd_len = old_cmd_len; memcpy(srb->cmnd, old_cmnd, MAX_COMMAND_SIZE); @@ -642,10 +649,8 @@ * multi-target device, since failure of an * auto-sense is perfectly valid */ - if (!(us->flags & US_FL_SCM_MULT_TARG)) { - /* What if we try to abort during the reset? */ + if (!(us->flags & US_FL_SCM_MULT_TARG)) us->transport_reset(us); - } srb->result = DID_ERROR << 16; return; } @@ -664,19 +669,19 @@ #endif /* set the result so the higher layers expect this data */ - srb->result = CHECK_CONDITION << 1; + srb->result = SAM_STAT_CHECK_CONDITION; /* If things are really okay, then let's show that */ if ((srb->sense_buffer[2] & 0xf) == 0x0) - srb->result = GOOD << 1; + srb->result = SAM_STAT_GOOD; } else /* if (need_auto_sense) */ - srb->result = GOOD << 1; + srb->result = SAM_STAT_GOOD; /* Regardless of auto-sense, if we _know_ we have an error * condition, show that in the result code */ if (result == USB_STOR_TRANSPORT_FAILED) - srb->result = CHECK_CONDITION << 1; + srb->result = SAM_STAT_CHECK_CONDITION; /* If we think we're good, then make sure the sense data shows it. * This is necessary because the auto-sense for some devices always @@ -693,56 +698,32 @@ Handle_Abort: srb->result = DID_ABORT << 16; if (us->protocol == US_PR_BULK) { + + /* permit the reset transfer to take place */ + clear_bit(US_FLIDX_ABORTING, &us->flags); us->transport_reset(us); } } -/* Abort the currently running scsi command or device reset. - * This must be called with scsi_lock(us->srb->host) held */ -int usb_stor_abort_transport(struct us_data *us) -{ - struct Scsi_Host *host; - int state = atomic_read(&us->sm_state); - - US_DEBUGP("usb_stor_abort_transport called\n"); - - /* Normally the current state is RUNNING. If the control thread - * hasn't even started processing this command, the state will be - * IDLE. Anything else is a bug. */ - if (state != US_STATE_RUNNING && state != US_STATE_IDLE) { - printk(KERN_ERR USB_STORAGE "Error in %s: " - "invalid state %d\n", __FUNCTION__, state); - return FAILED; - } - - /* set state to abort and release the lock */ - atomic_set(&us->sm_state, US_STATE_ABORTING); - host = us->srb->device->host; - scsi_unlock(host); +/* Stop the current URB transfer */ +void usb_stor_stop_transport(struct us_data *us) +{ + US_DEBUGP("%s called\n", __FUNCTION__); /* If the state machine is blocked waiting for an URB, - * let's wake it up */ - - /* If we have an URB pending, cancel it. The test_and_clear_bit() - * call guarantees that if a URB has just been submitted, it - * won't be cancelled more than once. */ - if (test_and_clear_bit(US_FLIDX_CAN_CANCEL, &us->flags)) { + * let's wake it up. The test_and_clear_bit() call + * guarantees that if a URB has just been submitted, + * it won't be cancelled more than once. */ + if (test_and_clear_bit(US_FLIDX_URB_ACTIVE, &us->flags)) { US_DEBUGP("-- cancelling URB\n"); usb_unlink_urb(us->current_urb); } /* If we are waiting for a scatter-gather operation, cancel it. */ - if (test_and_clear_bit(US_FLIDX_CANCEL_SG, &us->flags)) { + 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 aborted command to finish */ - wait_for_completion(&us->notify); - - /* Reacquire the lock: note that us->srb is now NULL */ - scsi_lock(host); - return SUCCESS; } /* @@ -788,8 +769,7 @@ } /* STATUS STAGE */ - result = usb_stor_intr_transfer(us, us->irqdata, - sizeof(us->irqdata), NULL); + result = usb_stor_intr_transfer(us, us->irqdata, sizeof(us->irqdata)); US_DEBUGP("Got interrupt data (0x%x, 0x%x)\n", us->irqdata[0], us->irqdata[1]); if (result != USB_STOR_XFER_GOOD) @@ -895,11 +875,8 @@ unsigned char data; int result; - /* Issue the command -- use usb_control_msg() because this is - * not a scsi queued-command. Also note that at this point the - * cached pipe values have not yet been stored. */ - result = usb_control_msg(us->pusb_dev, - usb_rcvctrlpipe(us->pusb_dev, 0), + /* issue the command */ + result = usb_stor_control_msg(us, us->recv_ctrl_pipe, US_BULK_GET_MAX_LUN, USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE, @@ -1033,43 +1010,40 @@ u16 value, u16 index, void *data, u16 size) { int result; + int result2; /* A 20-second timeout may seem rather long, but a LaCie * StudioDrive USB2 device takes 16+ seconds to get going * following a powerup or USB attach event. */ - /* Use usb_control_msg() because this is not a queued-command */ - result = usb_control_msg(us->pusb_dev, us->send_ctrl_pipe, + result = usb_stor_control_msg(us, us->send_ctrl_pipe, request, requesttype, value, index, data, size, 20*HZ); - if (result < 0) - goto Done; + if (result < 0) { + US_DEBUGP("Soft reset failed: %d\n", result); + return FAILED; + } - /* long wait for reset */ + /* long wait for reset, so unlock to allow disconnects */ + up(&us->dev_semaphore); set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ*6); set_current_state(TASK_RUNNING); + down(&us->dev_semaphore); - /* Use usb_clear_halt() because this is not a queued-command */ US_DEBUGP("Soft reset: clearing bulk-in endpoint halt\n"); - result = usb_clear_halt(us->pusb_dev, us->recv_bulk_pipe); - if (result < 0) - goto Done; + result = usb_stor_clear_halt(us, us->recv_bulk_pipe); US_DEBUGP("Soft reset: clearing bulk-out endpoint halt\n"); - result = usb_clear_halt(us->pusb_dev, us->send_bulk_pipe); - - Done: + result2 = usb_stor_clear_halt(us, us->send_bulk_pipe); /* return a result code based on the result of the control message */ - if (result < 0) { - US_DEBUGP("Soft reset failed: %d\n", result); - result = FAILED; - } else { - US_DEBUGP("Soft reset done\n"); - result = SUCCESS; + if (result < 0 || result2 < 0) { + US_DEBUGP("Soft reset failed\n"); + return FAILED; } - return result; + US_DEBUGP("Soft reset done\n"); + return SUCCESS; } /* This issues a CB[I] Reset to the device in question diff -Nru a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h --- a/drivers/usb/storage/transport.h Mon Jun 9 23:16:10 2003 +++ b/drivers/usb/storage/transport.h Mon Jun 9 23:16:10 2003 @@ -156,22 +156,18 @@ extern int usb_stor_Bulk_reset(struct us_data*); extern void usb_stor_invoke_transport(Scsi_Cmnd*, struct us_data*); -extern int usb_stor_abort_transport(struct us_data*); +extern void usb_stor_stop_transport(struct us_data*); -extern int usb_stor_bulk_msg(struct us_data *us, void *data, - unsigned int pipe, unsigned int len, unsigned int *act_len); extern int usb_stor_control_msg(struct us_data *us, unsigned int pipe, u8 request, u8 requesttype, u16 value, u16 index, - void *data, u16 size); -extern int usb_stor_interrupt_msg(struct us_data *us, void *data, - unsigned int len, unsigned int *act_len); + void *data, u16 size, int timeout); +extern int usb_stor_clear_halt(struct us_data *us, unsigned int pipe); -extern int usb_stor_clear_halt(struct us_data*, unsigned int pipe); extern int usb_stor_ctrl_transfer(struct us_data *us, unsigned int pipe, u8 request, u8 requesttype, u16 value, u16 index, void *data, u16 size); extern int usb_stor_intr_transfer(struct us_data *us, void *buf, - unsigned int length, unsigned int *act_len); + unsigned int length); extern int usb_stor_bulk_transfer_buf(struct us_data *us, unsigned int pipe, void *buf, unsigned int length, unsigned int *act_len); extern int usb_stor_bulk_transfer_sglist(struct us_data *us, unsigned int pipe, diff -Nru a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h --- a/drivers/usb/storage/unusual_devs.h Mon Jun 9 23:16:16 2003 +++ b/drivers/usb/storage/unusual_devs.h Mon Jun 9 23:16:16 2003 @@ -314,33 +314,18 @@ * Submitted by James Courtier-Dutton <James@superbug.demon.co.uk> */ UNUSUAL_DEV( 0x0a17, 0x0004, 0x1000, 0x1000, - "ASAHI PENTAX", - "PENTAX OPTIO 430", + "Pentax", + "Optio 2/3/400", US_SC_8070, US_PR_CBI, NULL, US_FL_FIX_INQUIRY ), -/* This Pentax still camera is not conformant - * to the USB storage specification: - - * - It does not like the INQUIRY command. So we must handle this command - * of the SCSI layer ourselves. - * Tested on Rev. 10.00 (0x1000) - * Submitted by James Courtier-Dutton <James@superbug.demon.co.uk> - */ -UNUSUAL_DEV( 0x0a17, 0x0004, 0x1000, 0x1000, - "ASAHI PENTAX", - "PENTAX OPTIO 430", +/* Submitted by Per Winkvist <per.winkvist@uk.com> */ +UNUSUAL_DEV( 0x0a17, 0x006, 0x1000, 0x9009, + "Pentax", + "Optio S", US_SC_8070, US_PR_CBI, NULL, US_FL_FIX_INQUIRY ), -/* Pentax Optio S digital camera - * submitted by Stefan M. Brandl <smb@smbnet.de> - */ -UNUSUAL_DEV( 0x0a17, 0x0006, 0x0000, 0xffff, - "Pentax", - "Optio S", - US_SC_8070, US_PR_CB, NULL, - US_FL_MODE_XLATE|US_FL_FIX_INQUIRY), - #ifdef CONFIG_USB_STORAGE_ISD200 UNUSUAL_DEV( 0x05ab, 0x0031, 0x0100, 0x0110, "In-System", @@ -606,6 +591,13 @@ US_SC_SCSI, US_PR_BULK, NULL, US_FL_FIX_CAPACITY ), +/* Submitted by Hartmut Wahl <hwahl@hwahl.de>*/ +UNUSUAL_DEV( 0x0839, 0x000a, 0x0001, 0x0001, + "Samsung", + "Digimax 410", + US_SC_SCSI, US_PR_BULK, NULL, + US_FL_FIX_INQUIRY), + UNUSUAL_DEV( 0x097a, 0x0001, 0x0000, 0x0001, "Minds@Work", "Digital Wallet", @@ -638,26 +630,6 @@ "EasyDisk EDxxxx", US_SC_SCSI, US_PR_BULK, NULL, US_FL_MODE_XLATE | US_FL_START_STOP | US_FL_FIX_INQUIRY ), - -/* This Pentax still camera is not conformant - * to the USB storage specification: - - * - It does not like the INQUIRY command. So we must handle this command - * of the SCSI layer ourselves. - * Tested on Rev. 10.00 (0x1000) - * Submitted by James Courtier-Dutton <James@superbug.demon.co.uk> - */ -UNUSUAL_DEV( 0x0a17, 0x0004, 0x1000, 0x1000, - "Pentax", - "Optio 2/3/400", - US_SC_8070, US_PR_CBI, NULL, - US_FL_FIX_INQUIRY ), - -/* Submitted by Per Winkvist <per.winkvist@uk.com> */ -UNUSUAL_DEV( 0x0a17, 0x006, 0x1000, 0x9009, - "Pentax", - "Optio S", - US_SC_8070, US_PR_CBI, NULL, - US_FL_FIX_INQUIRY ), /* Submitted by Brian Hall <brihall@pcisys.net> * Needed for START_STOP flag */ diff -Nru a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c --- a/drivers/usb/storage/usb.c Mon Jun 9 23:16:08 2003 +++ b/drivers/usb/storage/usb.c Mon Jun 9 23:16:08 2003 @@ -218,6 +218,7 @@ }; struct usb_driver usb_storage_driver = { + .owner = THIS_MODULE, .name = "usb-storage", .probe = storage_probe, .disconnect = storage_disconnect, @@ -373,7 +374,7 @@ memcpy(us->srb->sense_buffer, usb_stor_sense_invalidCDB, sizeof(usb_stor_sense_invalidCDB)); - us->srb->result = CHECK_CONDITION << 1; + us->srb->result = SAM_STAT_CHECK_CONDITION; } /* Handle those devices which need us to fake @@ -386,7 +387,7 @@ US_DEBUGP("Faking INQUIRY command\n"); fill_inquiry_response(us, data_ptr, 36); - us->srb->result = GOOD << 1; + us->srb->result = SAM_STAT_GOOD; } /* we've got a command, let's do it! */ @@ -411,9 +412,11 @@ US_DEBUGP("scsi command aborted\n"); } - /* in case an abort request was received after the command - * completed, we must use a separate test to see whether - * we need to signal that the abort has finished */ + /* If an abort request was received we need to signal that + * the abort has finished. The proper test for this is + * sm_state == US_STATE_ABORTING, not srb->result == DID_ABORT, + * because an abort request might be received after all the + * USB processing was complete. */ if (atomic_read(&us->sm_state) == US_STATE_ABORTING) complete(&(us->notify)); @@ -714,7 +717,6 @@ us->transport_name = "Bulk"; us->transport = usb_stor_Bulk_transport; us->transport_reset = usb_stor_Bulk_reset; - us->max_lun = usb_stor_Bulk_max_lun(us); break; #ifdef CONFIG_USB_STORAGE_HP8200e @@ -841,6 +843,10 @@ if (usb_stor_allocate_urbs(us)) goto BadDevice; + /* For bulk-only devices, determine the max LUN value */ + if (us->protocol == US_PR_BULK) + us->max_lun = usb_stor_Bulk_max_lun(us); + /* * Since this is a new device, we need to generate a scsi * host definition, and register with the higher SCSI layers @@ -886,11 +892,8 @@ /* set the hostdata to prepare for scanning */ us->host->hostdata[0] = (unsigned long)us; - /* associate this host with our interface */ - scsi_set_device(us->host, &intf->dev); - /* now add the host */ - result = scsi_add_host(us->host, NULL); + result = scsi_add_host(us->host, &intf->dev); if (result) { printk(KERN_WARNING USB_STORAGE "Unable to add the scsi host\n"); @@ -941,15 +944,12 @@ sdev->online = 0; scsi_unlock(us->host); + /* prevent new USB transfers and stop the current command */ + set_bit(US_FLIDX_DISCONNECTING, &us->flags); + usb_stor_stop_transport(us); + /* lock device access -- no need to unlock, as we're going away */ down(&(us->dev_semaphore)); - - /* Complete all pending commands with * cmd->result = DID_ERROR << 16. - * Since we only queue one command at a time, this is pretty easy. */ - if (us->srb) { - us->srb->result = DID_ERROR << 16; - us->srb->scsi_done(us->srb); - } /* TODO: somehow, wait for the device to * be 'idle' (tasklet completion) */ diff -Nru a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h --- a/drivers/usb/storage/usb.h Mon Jun 9 23:16:15 2003 +++ b/drivers/usb/storage/usb.h Mon Jun 9 23:16:15 2003 @@ -67,7 +67,7 @@ unsigned int flags; }; -/* Flag definitions */ +/* Flag definitions: these entries are static */ #define US_FL_SINGLE_LUN 0x00000001 /* allow access to only LUN 0 */ #define US_FL_MODE_XLATE 0x00000002 /* translate _6 to _10 commands for Win/MacOS compatibility */ @@ -77,8 +77,13 @@ #define US_FL_FIX_INQUIRY 0x00000040 /* INQUIRY response needs fixing */ #define US_FL_FIX_CAPACITY 0x00000080 /* READ CAPACITY response too big */ -#define US_FLIDX_CAN_CANCEL 18 /* 0x00040000 okay to cancel current_urb? */ -#define US_FLIDX_CANCEL_SG 19 /* 0x00080000 okay to cancel current_sg? */ +/* 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 DONT_SUBMIT ((1UL << US_FLIDX_ABORTING) | \ + (1UL << US_FLIDX_DISCONNECTING)) /* processing state machine states */ diff -Nru a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c --- a/drivers/usb/usb-skeleton.c Mon Jun 9 23:16:11 2003 +++ b/drivers/usb/usb-skeleton.c Mon Jun 9 23:16:11 2003 @@ -172,6 +172,7 @@ /* usb specific object needed to register this driver with the usb subsystem */ static struct usb_driver skel_driver = { + .owner = THIS_MODULE, .name = "skeleton", .probe = skel_probe, .disconnect = skel_disconnect, diff -Nru a/drivers/video/Kconfig b/drivers/video/Kconfig --- a/drivers/video/Kconfig Mon Jun 9 23:16:05 2003 +++ b/drivers/video/Kconfig Mon Jun 9 23:16:05 2003 @@ -235,28 +235,28 @@ config FB_OF bool "Open Firmware frame buffer device support" - depends on FB && (PPC64 || (PPC && ALL_PPC)) + depends on FB && (PPC64 || PPC_OF) help Say Y if you want support with Open Firmware for your graphics board. config FB_CONTROL bool "Apple \"control\" display support" - depends on FB && PPC && ALL_PPC + depends on FB && PPC_PMAC help This driver supports a frame buffer for the graphics adapter in the Power Macintosh 7300 and others. config FB_PLATINUM bool "Apple \"platinum\" display support" - depends on FB && PPC && ALL_PPC + depends on FB && PPC_PMAC help This driver supports a frame buffer for the "platinum" graphics adapter in some Power Macintoshes. config FB_VALKYRIE bool "Apple \"valkyrie\" display support" - depends on FB && (MAC || PPC && ALL_PPC) + depends on FB && (MAC || PPC_PMAC) help This driver supports a frame buffer for the "valkyrie" graphics adapter in some Power Macintoshes. diff -Nru a/drivers/video/Makefile b/drivers/video/Makefile --- a/drivers/video/Makefile Mon Jun 9 23:16:07 2003 +++ b/drivers/video/Makefile Mon Jun 9 23:16:07 2003 @@ -55,7 +55,7 @@ obj-$(CONFIG_FB_MAXINE) += maxinefb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_TX3912) += tx3912fb.o cfbfillrect.o cfbcopyarea.o cfbimgblt.o -obj-$(CONFIG_FB_MATROX) += matrox/ +obj-$(CONFIG_FB_MATROX) += matrox/ cfbfillrect.o cfbcopyarea.o cfbimgblt.o obj-$(CONFIG_FB_RIVA) += riva/ cfbimgblt.o vgastate.o obj-$(CONFIG_FB_SIS) += sis/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o obj-$(CONFIG_FB_ATY) += aty/ cfbcopyarea.o cfbfillrect.o cfbimgblt.o diff -Nru a/drivers/video/aty/aty128fb.c b/drivers/video/aty/aty128fb.c --- a/drivers/video/aty/aty128fb.c Mon Jun 9 23:16:12 2003 +++ b/drivers/video/aty/aty128fb.c Mon Jun 9 23:16:12 2003 @@ -59,7 +59,7 @@ #include <linux/ioport.h> #include <asm/io.h> -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC #include <asm/prom.h> #include <asm/pci-bridge.h> #include "../macmodes.h" @@ -93,7 +93,7 @@ #define DBG(fmt, args...) #endif -#ifndef CONFIG_ALL_PPC +#ifndef CONFIG_PPC_PMAC /* default mode */ static struct fb_var_screeninfo default_var __initdata = { /* 640x480, 60 Hz, Non-Interlaced (25.175 MHz dotclock) */ @@ -103,7 +103,7 @@ 0, FB_VMODE_NONINTERLACED }; -#else /* CONFIG_ALL_PPC */ +#else /* CONFIG_PPC_PMAC */ /* default to 1024x768 at 75Hz on PPC - this will work * on the iMac, the usual 640x480 @ 60Hz doesn't. */ static struct fb_var_screeninfo default_var = { @@ -114,7 +114,7 @@ FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED }; -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PMAC */ /* default modedb mode */ /* 640x480, 60 Hz, Non-Interlaced (25.172 MHz dotclock) */ @@ -259,7 +259,7 @@ static char *mode_option __initdata = NULL; -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC static int default_vmode __initdata = VMODE_1024_768_60; static int default_cmode __initdata = CMODE_8; #endif @@ -1434,7 +1434,7 @@ continue; } #endif -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC /* vmode and cmode deprecated */ if (!strncmp(this_opt, "vmode:", 6)) { unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0); @@ -1459,7 +1459,7 @@ } continue; } -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PMAC */ mode_option = this_opt; } return 0; @@ -1543,7 +1543,7 @@ #endif var = default_var; -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC if (_machine == _MACH_Pmac) { if (mode_option) { if (!mac_find_mode(&var, info, mode_option, 8)) @@ -1582,7 +1582,7 @@ var = default_var; } } else -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PMAC */ { if (fb_find_mode(&var, info, mode_option, NULL, 0, &defaultmode, 8) == 0) @@ -1872,7 +1872,7 @@ static void __init aty128_timings(struct aty128fb_par *par) { -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_OF /* instead of a table lookup, assume OF has properly * setup the PLL registers and use their values * to set the XCLK values and reference divider values */ @@ -1886,7 +1886,7 @@ if (!par->constants.dotclock) par->constants.dotclock = 2950; -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_OF x_mpll_ref_fb_div = aty_ld_pll(X_MPLL_REF_FB_DIV); xclk_cntl = aty_ld_pll(XCLK_CNTL) & 0x7; Nx = (x_mpll_ref_fb_div & 0x00ff00) >> 8; diff -Nru a/drivers/video/cirrusfb.c b/drivers/video/cirrusfb.c --- a/drivers/video/cirrusfb.c Mon Jun 9 23:16:18 2003 +++ b/drivers/video/cirrusfb.c Mon Jun 9 23:16:18 2003 @@ -56,7 +56,7 @@ #ifdef CONFIG_AMIGA #include <asm/amigahw.h> #endif -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PREP #include <asm/processor.h> #define isPReP (_machine == _MACH_prep) #else @@ -2395,7 +2395,7 @@ -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PREP #define PREP_VIDEO_BASE ((volatile unsigned long) 0xC0000000) #define PREP_IO_BASE ((volatile unsigned char *) 0x80000000) static void __init get_prep_addrs (unsigned long *display, unsigned long *registers) @@ -2408,7 +2408,7 @@ DPRINTK ("EXIT\n"); } -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PREP */ @@ -2543,7 +2543,7 @@ pcibios_write_config_dword (0, pdev->devfn, PCI_BASE_ADDRESS_0, 0x00000000); -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PREP get_prep_addrs (&board_addr, &info->fbregs_phys); #endif } else { diff -Nru a/drivers/video/fbmon.c b/drivers/video/fbmon.c --- a/drivers/video/fbmon.c Mon Jun 9 23:16:18 2003 +++ b/drivers/video/fbmon.c Mon Jun 9 23:16:18 2003 @@ -29,7 +29,7 @@ #include <linux/tty.h> #include <linux/fb.h> #include <linux/module.h> -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_OF #include <linux/pci.h> #include <asm/prom.h> #endif @@ -828,7 +828,7 @@ printk("========================================\n"); } -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_OF char *get_EDID_from_OF(struct pci_dev *pdev) { static char *propnames[] = @@ -1256,7 +1256,7 @@ #ifdef CONFIG_X86 EXPORT_SYMBOL(get_EDID_from_BIOS); #endif -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_OF EXPORT_SYMBOL(get_EDID_from_OF); #endif EXPORT_SYMBOL(fb_get_monitor_limits); diff -Nru a/drivers/video/i810/i810.h b/drivers/video/i810/i810.h --- a/drivers/video/i810/i810.h Mon Jun 9 23:16:18 2003 +++ b/drivers/video/i810/i810.h Mon Jun 9 23:16:18 2003 @@ -203,8 +203,8 @@ #define LOCKUP 8 struct gtt_data { - agp_memory *i810_fb_memory; - agp_memory *i810_cursor_memory; + struct agp_memory *i810_fb_memory; + struct agp_memory *i810_cursor_memory; }; struct mode_registers { diff -Nru a/drivers/video/i810/i810_main.c b/drivers/video/i810/i810_main.c --- a/drivers/video/i810/i810_main.c Mon Jun 9 23:16:09 2003 +++ b/drivers/video/i810/i810_main.c Mon Jun 9 23:16:09 2003 @@ -1926,11 +1926,6 @@ #ifndef MODULE int __init i810fb_init(void) { - if (agp_init()) { - printk("i810fb_init: cannot initialize agpgart\n"); - return -ENODEV; - } - if (agp_intel_init()) { printk("i810fb_init: cannot initialize intel agpgart\n"); return -ENODEV; diff -Nru a/drivers/video/i810/i810_main.h b/drivers/video/i810/i810_main.h --- a/drivers/video/i810/i810_main.h Mon Jun 9 23:16:14 2003 +++ b/drivers/video/i810/i810_main.h Mon Jun 9 23:16:14 2003 @@ -111,7 +111,6 @@ /* Initialization */ static void i810fb_release_resource (struct fb_info *info, struct i810fb_par *par); extern int __init agp_intel_init(void); -extern int __init agp_init(void); /* Video Timings */ diff -Nru a/drivers/video/matrox/i2c-matroxfb.c b/drivers/video/matrox/i2c-matroxfb.c --- a/drivers/video/matrox/i2c-matroxfb.c Mon Jun 9 23:16:11 2003 +++ b/drivers/video/matrox/i2c-matroxfb.c Mon Jun 9 23:16:11 2003 @@ -113,7 +113,7 @@ b->adapter = matrox_i2c_adapter_template; snprintf(b->adapter.dev.name, DEVICE_NAME_SIZE, name, minfo->fbcon.node); - b->adapter.data = b; + i2c_set_adapdata(&b->adapter, b); b->adapter.algo_data = &b->bac; b->bac = matrox_i2c_algo_template; b->bac.data = b; diff -Nru a/drivers/video/matrox/matroxfb_DAC1064.c b/drivers/video/matrox/matroxfb_DAC1064.c --- a/drivers/video/matrox/matroxfb_DAC1064.c Mon Jun 9 23:16:11 2003 +++ b/drivers/video/matrox/matroxfb_DAC1064.c Mon Jun 9 23:16:11 2003 @@ -35,132 +35,11 @@ #define DAC1064_OPT_MDIV2 0x00 #define DAC1064_OPT_RESERVED 0x10 -static void matroxfb_DAC1064_flashcursor(unsigned long ptr) { - unsigned long flags; - -#define minfo ((struct matrox_fb_info*)ptr) - matroxfb_DAC_lock_irqsave(flags); - outDAC1064(PMINFO M1064_XCURCTRL, inDAC1064(PMINFO M1064_XCURCTRL) ^ M1064_XCURCTRL_DIS ^ M1064_XCURCTRL_XGA); - ACCESS_FBINFO(cursor.timer.expires) = jiffies + HZ/2; - add_timer(&ACCESS_FBINFO(cursor.timer)); - matroxfb_DAC_unlock_irqrestore(flags); -#undef minfo -} - -static void matroxfb_DAC1064_createcursor(WPMINFO struct display* p) { - vaddr_t cursorbase; - u_int32_t xline; - unsigned int i; - unsigned int h, to; - CRITFLAGS - - if (ACCESS_FBINFO(currcon_display) != p) - return; - - matroxfb_createcursorshape(PMINFO p, p->var.vmode); - - xline = (~0) << (32 - ACCESS_FBINFO(cursor.w)); - cursorbase = ACCESS_FBINFO(video.vbase); - h = ACCESS_FBINFO(features.DAC1064.cursorimage); - - CRITBEGIN - -#ifdef __BIG_ENDIAN - WaitTillIdle(); - mga_outl(M_OPMODE, M_OPMODE_32BPP); -#endif - to = ACCESS_FBINFO(cursor.u); - for (i = 0; i < to; i++) { - mga_writel(cursorbase, h, 0); - mga_writel(cursorbase, h+4, 0); - mga_writel(cursorbase, h+8, ~0); - mga_writel(cursorbase, h+12, ~0); - h += 16; - } - to = ACCESS_FBINFO(cursor.d); - for (; i < to; i++) { - mga_writel(cursorbase, h, 0); - mga_writel(cursorbase, h+4, xline); - mga_writel(cursorbase, h+8, ~0); - mga_writel(cursorbase, h+12, ~0); - h += 16; - } - for (; i < 64; i++) { - mga_writel(cursorbase, h, 0); - mga_writel(cursorbase, h+4, 0); - mga_writel(cursorbase, h+8, ~0); - mga_writel(cursorbase, h+12, ~0); - h += 16; - } -#ifdef __BIG_ENDIAN - mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode)); -#endif - - CRITEND -} - -static void matroxfb_DAC1064_cursor(struct display* p, int mode, int x, int y) { - unsigned long flags; - MINFO_FROM_DISP(p); - - if (ACCESS_FBINFO(currcon_display) != p) - return; - - if (mode == CM_ERASE) { - if (ACCESS_FBINFO(cursor.state) != CM_ERASE) { - del_timer_sync(&ACCESS_FBINFO(cursor.timer)); - matroxfb_DAC_lock_irqsave(flags); - ACCESS_FBINFO(cursor.state) = CM_ERASE; - outDAC1064(PMINFO M1064_XCURCTRL, M1064_XCURCTRL_DIS); - matroxfb_DAC_unlock_irqrestore(flags); - } - return; - } - if ((p->conp->vc_cursor_type & CUR_HWMASK) != ACCESS_FBINFO(cursor.type)) - matroxfb_DAC1064_createcursor(PMINFO p); - x *= fontwidth(p); - y *= fontheight(p); - y -= p->var.yoffset; - if (p->var.vmode & FB_VMODE_DOUBLE) - y *= 2; - del_timer_sync(&ACCESS_FBINFO(cursor.timer)); - matroxfb_DAC_lock_irqsave(flags); - if ((x != ACCESS_FBINFO(cursor.x)) || (y != ACCESS_FBINFO(cursor.y)) || ACCESS_FBINFO(cursor.redraw)) { - ACCESS_FBINFO(cursor.redraw) = 0; - ACCESS_FBINFO(cursor.x) = x; - ACCESS_FBINFO(cursor.y) = y; - x += 64; - y += 64; - outDAC1064(PMINFO M1064_XCURCTRL, M1064_XCURCTRL_DIS); - mga_outb(M_RAMDAC_BASE+M1064_CURPOSXL, x); - mga_outb(M_RAMDAC_BASE+M1064_CURPOSXH, x >> 8); - mga_outb(M_RAMDAC_BASE+M1064_CURPOSYL, y); - mga_outb(M_RAMDAC_BASE+M1064_CURPOSYH, y >> 8); - } - ACCESS_FBINFO(cursor.state) = CM_DRAW; - if (ACCESS_FBINFO(devflags.blink)) - mod_timer(&ACCESS_FBINFO(cursor.timer), jiffies + HZ/2); - outDAC1064(PMINFO M1064_XCURCTRL, M1064_XCURCTRL_XGA); - matroxfb_DAC_unlock_irqrestore(flags); -} - -static int matroxfb_DAC1064_setfont(struct display* p, int width, int height) { - if (p && p->conp) - matroxfb_DAC1064_createcursor(PMXINFO(p) p); - return 0; -} - -static int DAC1064_selhwcursor(WPMINFO2) { - ACCESS_FBINFO(dispsw.cursor) = matroxfb_DAC1064_cursor; - ACCESS_FBINFO(dispsw.set_font) = matroxfb_DAC1064_setfont; - return 0; -} - static void DAC1064_calcclock(CPMINFO unsigned int freq, unsigned int fmax, unsigned int* in, unsigned int* feed, unsigned int* post) { unsigned int fvco; unsigned int p; - DBG("DAC1064_calcclock") + DBG(__FUNCTION__) /* only for devices older than G450 */ @@ -206,7 +85,7 @@ static void DAC1064_setpclk(WPMINFO unsigned long fout) { unsigned int m, n, p; - DBG("DAC1064_setpclk") + DBG(__FUNCTION__) DAC1064_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p); ACCESS_FBINFO(hw).DACclk[0] = m; @@ -218,7 +97,7 @@ u_int32_t mx; struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG("DAC1064_setmclk") + DBG(__FUNCTION__) if (ACCESS_FBINFO(devflags.noinit)) { /* read MCLK and give up... */ @@ -461,15 +340,10 @@ static int DAC1064_init_1(WPMINFO struct my_timming* m) { struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG("DAC1064_init_1") + DBG(__FUNCTION__) memcpy(hw->DACreg, MGA1064_DAC, sizeof(MGA1064_DAC_regs)); - if (ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT) { - hw->DACreg[POS1064_XMISCCTRL] = M1064_XMISCCTRL_DAC_6BIT; - hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP - | M1064_XMULCTRL_GRAPHICS_PALETIZED; - } else { - switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) { + switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) { /* case 4: not supported by MGA1064 DAC */ case 8: hw->DACreg[POS1064_XMULCTRL] = M1064_XMULCTRL_DEPTH_8BPP | M1064_XMULCTRL_GRAPHICS_PALETIZED; @@ -488,13 +362,12 @@ break; default: return 1; /* unsupported depth */ - } } hw->DACreg[POS1064_XVREFCTRL] = ACCESS_FBINFO(features.DAC1064.xvrefctrl); hw->DACreg[POS1064_XGENCTRL] &= ~M1064_XGENCTRL_SYNC_ON_GREEN_MASK; hw->DACreg[POS1064_XGENCTRL] |= (m->sync & FB_SYNC_ON_GREEN)?M1064_XGENCTRL_SYNC_ON_GREEN:M1064_XGENCTRL_NO_SYNC_ON_GREEN; - hw->DACreg[POS1064_XCURADDL] = ACCESS_FBINFO(features.DAC1064.cursorimage) >> 10; - hw->DACreg[POS1064_XCURADDH] = ACCESS_FBINFO(features.DAC1064.cursorimage) >> 18; + hw->DACreg[POS1064_XCURADDL] = 0; + hw->DACreg[POS1064_XCURADDH] = 0; DAC1064_global_init(PMINFO2); return 0; @@ -503,7 +376,7 @@ static int DAC1064_init_2(WPMINFO struct my_timming* m) { struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG("DAC1064_init_2") + DBG(__FUNCTION__) if (ACCESS_FBINFO(fbcon).var.bits_per_pixel > 16) { /* 256 entries */ int i; @@ -547,7 +420,7 @@ CRITFLAGS - DBG("DAC1064_restore_1") + DBG(__FUNCTION__) CRITBEGIN @@ -572,14 +445,13 @@ CRITEND }; -static void DAC1064_restore_2(WPMINFO struct display* p) { +static void DAC1064_restore_2(WPMINFO2) { #ifdef DEBUG unsigned int i; #endif - DBG("DAC1064_restore_2") + DBG(__FUNCTION__) - matrox_init_putc(PMINFO p, matroxfb_DAC1064_createcursor); #ifdef DEBUG dprintk(KERN_DEBUG "DAC1064regs "); for (i = 0; i < sizeof(MGA1064_DAC_regs); i++) { @@ -648,13 +520,13 @@ #endif /* NEED_DAC1064 */ #ifdef CONFIG_FB_MATROX_MYSTIQUE -static int MGA1064_init(WPMINFO struct my_timming* m, struct display* p) { +static int MGA1064_init(WPMINFO struct my_timming* m) { struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG("MGA1064_init") + DBG(__FUNCTION__) if (DAC1064_init_1(PMINFO m)) return 1; - if (matroxfb_vgaHWinit(PMINFO m, p)) return 1; + if (matroxfb_vgaHWinit(PMINFO m)) return 1; hw->MiscOutReg = 0xCB; if (m->sync & FB_SYNC_HOR_HIGH_ACT) @@ -670,14 +542,14 @@ #endif #ifdef CONFIG_FB_MATROX_G100 -static int MGAG100_init(WPMINFO struct my_timming* m, struct display* p) { +static int MGAG100_init(WPMINFO struct my_timming* m) { struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG("MGAG100_init") + DBG(__FUNCTION__) if (DAC1064_init_1(PMINFO m)) return 1; hw->MXoptionReg &= ~0x2000; - if (matroxfb_vgaHWinit(PMINFO m, p)) return 1; + if (matroxfb_vgaHWinit(PMINFO m)) return 1; hw->MiscOutReg = 0xEF; if (m->sync & FB_SYNC_HOR_HIGH_ACT) @@ -695,7 +567,7 @@ #ifdef CONFIG_FB_MATROX_MYSTIQUE static void MGA1064_ramdac_init(WPMINFO2) { - DBG("MGA1064_ramdac_init"); + DBG(__FUNCTION__) /* ACCESS_FBINFO(features.DAC1064.vco_freq_min) = 120000; */ ACCESS_FBINFO(features.pll.vco_freq_min) = 62000; @@ -724,7 +596,7 @@ int selClk; int clk; - DBG("MGAG100_progPixClock") + DBG(__FUNCTION__) outDAC1064(PMINFO M1064_XPIXCLKCTRL, inDAC1064(PMINFO M1064_XPIXCLKCTRL) | M1064_XPIXCLKCTRL_DIS | M1064_XPIXCLKCTRL_PLL_UP); @@ -766,7 +638,7 @@ static void MGAG100_setPixClock(CPMINFO int flags, int freq) { unsigned int m, n, p; - DBG("MGAG100_setPixClock") + DBG(__FUNCTION__) DAC1064_calcclock(PMINFO freq, ACCESS_FBINFO(max_pixel_clock), &m, &n, &p); MGAG100_progPixClock(PMINFO flags, m, n, p); @@ -780,13 +652,12 @@ 2048, 0}; struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG("MGA1064_preinit") + DBG(__FUNCTION__) /* ACCESS_FBINFO(capable.cfb4) = 0; ... preinitialized by 0 */ ACCESS_FBINFO(capable.text) = 1; ACCESS_FBINFO(capable.vxres) = vxres_mystique; ACCESS_FBINFO(features.accel.has_cacheflush) = 1; - ACCESS_FBINFO(cursor.timer.function) = matroxfb_DAC1064_flashcursor; ACCESS_FBINFO(outputs[0]).output = &m1064; ACCESS_FBINFO(outputs[0]).src = MATROXFB_SRC_CRTC1; @@ -815,12 +686,8 @@ static void MGA1064_reset(WPMINFO2) { - DBG("MGA1064_reset"); + DBG(__FUNCTION__); - ACCESS_FBINFO(features.DAC1064.cursorimage) = ACCESS_FBINFO(video.len_usable) - 1024; - if (ACCESS_FBINFO(devflags.hwcursor)) - ACCESS_FBINFO(video.len_usable) -= 1024; - matroxfb_fastfont_init(MINFO); MGA1064_ramdac_init(PMINFO2); } #endif @@ -960,7 +827,7 @@ u_int32_t q; #endif - DBG("MGAG100_preinit") + DBG(__FUNCTION__) /* there are some instabilities if in_div > 19 && vco < 61000 */ if (ACCESS_FBINFO(devflags.g450dac)) { @@ -981,7 +848,6 @@ ACCESS_FBINFO(capable.text) = 1; ACCESS_FBINFO(capable.vxres) = vxres_g100; ACCESS_FBINFO(features.accel.has_cacheflush) = 1; - ACCESS_FBINFO(cursor.timer.function) = matroxfb_DAC1064_flashcursor; ACCESS_FBINFO(capable.plnwt) = ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG100 ? ACCESS_FBINFO(devflags.sgram) : 1; @@ -1099,12 +965,7 @@ u_int8_t b; struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG("MGAG100_reset") - - ACCESS_FBINFO(features.DAC1064.cursorimage) = ACCESS_FBINFO(video.len_usable) - 1024; - if (ACCESS_FBINFO(devflags.hwcursor)) - ACCESS_FBINFO(video.len_usable) -= 1024; - matroxfb_fastfont_init(MINFO); + DBG(__FUNCTION__) { #ifdef G100_BROKEN_IBM_82351 @@ -1157,13 +1018,13 @@ #endif #ifdef CONFIG_FB_MATROX_MYSTIQUE -static void MGA1064_restore(WPMINFO struct display* p) { +static void MGA1064_restore(WPMINFO2) { int i; struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); CRITFLAGS - DBG("MGA1064_restore") + DBG(__FUNCTION__) CRITBEGIN @@ -1177,18 +1038,18 @@ matroxfb_vgaHWrestore(PMINFO2); for (i = 0; i < 6; i++) mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]); - DAC1064_restore_2(PMINFO p); + DAC1064_restore_2(PMINFO2); } #endif #ifdef CONFIG_FB_MATROX_G100 -static void MGAG100_restore(WPMINFO struct display* p) { +static void MGAG100_restore(WPMINFO2) { int i; struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); CRITFLAGS - DBG("MGAG100_restore") + DBG(__FUNCTION__) CRITBEGIN @@ -1203,20 +1064,20 @@ #endif for (i = 0; i < 6; i++) mga_setr(M_EXTVGA_INDEX, i, hw->CRTCEXT[i]); - DAC1064_restore_2(PMINFO p); + DAC1064_restore_2(PMINFO2); } #endif #ifdef CONFIG_FB_MATROX_MYSTIQUE struct matrox_switch matrox_mystique = { - MGA1064_preinit, MGA1064_reset, MGA1064_init, MGA1064_restore, DAC1064_selhwcursor + MGA1064_preinit, MGA1064_reset, MGA1064_init, MGA1064_restore, }; EXPORT_SYMBOL(matrox_mystique); #endif #ifdef CONFIG_FB_MATROX_G100 struct matrox_switch matrox_G100 = { - MGAG100_preinit, MGAG100_reset, MGAG100_init, MGAG100_restore, DAC1064_selhwcursor + MGAG100_preinit, MGAG100_reset, MGAG100_init, MGAG100_restore, }; EXPORT_SYMBOL(matrox_G100); #endif diff -Nru a/drivers/video/matrox/matroxfb_Ti3026.c b/drivers/video/matrox/matroxfb_Ti3026.c --- a/drivers/video/matrox/matroxfb_Ti3026.c Mon Jun 9 23:16:05 2003 +++ b/drivers/video/matrox/matroxfb_Ti3026.c Mon Jun 9 23:16:05 2003 @@ -281,138 +281,11 @@ TVP3026_XCOLKEYCTRL_ZOOM1, 0x00, 0x00, TVP3026_XCURCTRL_DIS }; -static void matroxfb_ti3026_flashcursor(unsigned long ptr) { - unsigned long flags; - -#define minfo ((struct matrox_fb_info*)ptr) - matroxfb_DAC_lock_irqsave(flags); - outTi3026(PMINFO TVP3026_XCURCTRL, inTi3026(PMINFO TVP3026_XCURCTRL) ^ TVP3026_XCURCTRL_DIS ^ TVP3026_XCURCTRL_XGA); - ACCESS_FBINFO(cursor.timer.expires) = jiffies + HZ/2; - add_timer(&ACCESS_FBINFO(cursor.timer)); - matroxfb_DAC_unlock_irqrestore(flags); -#undef minfo -} - -static void matroxfb_ti3026_createcursor(WPMINFO struct display* p) { - unsigned long flags; - u_int32_t xline; - unsigned int i; - unsigned int to; - - if (ACCESS_FBINFO(currcon_display) != p) - return; - - DBG("matroxfb_ti3026_createcursor"); - - matroxfb_createcursorshape(PMINFO p, p->var.vmode); - - xline = (~0) << (32 - ACCESS_FBINFO(cursor.w)); - matroxfb_DAC_lock_irqsave(flags); - mga_outb(M_RAMDAC_BASE+TVP3026_INDEX, 0); - to = ACCESS_FBINFO(cursor.u); - for (i = 0; i < to; i++) { - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - } - to = ACCESS_FBINFO(cursor.d); - for (; i < to; i++) { - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline >> 24); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline >> 16); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline >> 8); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, xline); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - } - for (; i < 64; i++) { - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0); - } - for (i = 0; i < 512; i++) - mga_outb(M_RAMDAC_BASE+TVP3026_CURRAMDATA, 0xFF); - matroxfb_DAC_unlock_irqrestore(flags); -} - -static void matroxfb_ti3026_cursor(struct display* p, int mode, int x, int y) { - unsigned long flags; - MINFO_FROM_DISP(p); - - DBG("matroxfb_ti3026_cursor") - - if (ACCESS_FBINFO(currcon_display) != p) - return; - - if (mode == CM_ERASE) { - if (ACCESS_FBINFO(cursor.state) != CM_ERASE) { - del_timer_sync(&ACCESS_FBINFO(cursor.timer)); - matroxfb_DAC_lock_irqsave(flags); - ACCESS_FBINFO(cursor.state) = CM_ERASE; - outTi3026(PMINFO TVP3026_XCURCTRL, ACCESS_FBINFO(hw.DACreg[POS3026_XCURCTRL])); - matroxfb_DAC_unlock_irqrestore(flags); - } - return; - } - if ((p->conp->vc_cursor_type & CUR_HWMASK) != ACCESS_FBINFO(cursor.type)) - matroxfb_ti3026_createcursor(PMINFO p); - x *= fontwidth(p); - y *= fontheight(p); - y -= p->var.yoffset; - if (p->var.vmode & FB_VMODE_DOUBLE) - y *= 2; - del_timer_sync(&ACCESS_FBINFO(cursor.timer)); - matroxfb_DAC_lock_irqsave(flags); - if ((x != ACCESS_FBINFO(cursor.x)) || (y != ACCESS_FBINFO(cursor.y)) || ACCESS_FBINFO(cursor.redraw)) { - ACCESS_FBINFO(cursor.redraw) = 0; - ACCESS_FBINFO(cursor.x) = x; - ACCESS_FBINFO(cursor.y) = y; - x += 64; - y += 64; - outTi3026(PMINFO TVP3026_XCURCTRL, ACCESS_FBINFO(hw.DACreg[POS3026_XCURCTRL])); - mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSXL, x); - mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSXH, x >> 8); - mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSYL, y); - mga_outb(M_RAMDAC_BASE+TVP3026_CURPOSYH, y >> 8); - } - ACCESS_FBINFO(cursor.state) = CM_DRAW; - if (ACCESS_FBINFO(devflags.blink)) - mod_timer(&ACCESS_FBINFO(cursor.timer), jiffies + HZ/2); - outTi3026(PMINFO TVP3026_XCURCTRL, ACCESS_FBINFO(hw.DACreg[POS3026_XCURCTRL]) | TVP3026_XCURCTRL_XGA); - matroxfb_DAC_unlock_irqrestore(flags); -} - -static int matroxfb_ti3026_setfont(struct display* p, int width, int height) { - - DBG("matrox_ti3026_setfont"); - - if (p && p->conp) - matroxfb_ti3026_createcursor(PMXINFO(p) p); - return 0; -} - -static int matroxfb_ti3026_selhwcursor(WPMINFO2) { - ACCESS_FBINFO(dispsw.cursor) = matroxfb_ti3026_cursor; - ACCESS_FBINFO(dispsw.set_font) = matroxfb_ti3026_setfont; - return 0; -} - static int Ti3026_calcclock(CPMINFO unsigned int freq, unsigned int fmax, int* in, int* feed, int* post) { unsigned int fvco; unsigned int lin, lfeed, lpost; - DBG("Ti3026_calcclock") + DBG(__FUNCTION__) fvco = PLL_calcclock(PMINFO freq, fmax, &lin, &lfeed, &lpost); fvco >>= (*post = lpost); @@ -421,12 +294,12 @@ return fvco; } -static int Ti3026_setpclk(WPMINFO int clk, struct display* p) { +static int Ti3026_setpclk(WPMINFO int clk) { unsigned int f_pll; unsigned int pixfeed, pixin, pixpost; struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG("Ti3026_setpclk") + DBG(__FUNCTION__) f_pll = Ti3026_calcclock(PMINFO clk, ACCESS_FBINFO(max_pixel_clock), &pixin, &pixfeed, &pixpost); @@ -434,18 +307,13 @@ hw->DACclk[1] = pixfeed; hw->DACclk[2] = pixpost | 0xB0; - if (ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT) { - hw->DACreg[POS3026_XMEMPLLCTRL] = TVP3026_XMEMPLLCTRL_MCLK_MCLKPLL | TVP3026_XMEMPLLCTRL_RCLK_PIXPLL; - hw->DACclk[3] = 0xFD; - hw->DACclk[4] = 0x3D; - hw->DACclk[5] = 0x70; - } else { + { unsigned int loopfeed, loopin, looppost, loopdiv, z; unsigned int Bpp; Bpp = ACCESS_FBINFO(curr.final_bppShift); - if (p->var.bits_per_pixel == 24) { + if (ACCESS_FBINFO(fbcon).var.bits_per_pixel == 24) { loopfeed = 3; /* set lm to any possible value */ loopin = 3 * 32 / Bpp; } else { @@ -464,7 +332,7 @@ looppost = 3; loopdiv = z/16; } - if (p->var.bits_per_pixel == 24) { + if (ACCESS_FBINFO(fbcon).var.bits_per_pixel == 24) { hw->DACclk[3] = ((65 - loopin) & 0x3F) | 0xC0; hw->DACclk[4] = (65 - loopfeed) | 0x80; if (ACCESS_FBINFO(accel.ramdac_rev) > 0x20) { @@ -495,22 +363,14 @@ return 0; } -static int Ti3026_init(WPMINFO struct my_timming* m, struct display* p) { +static int Ti3026_init(WPMINFO struct my_timming* m) { u_int8_t muxctrl = isInterleave(MINFO) ? TVP3026_XMUXCTRL_MEMORY_64BIT : TVP3026_XMUXCTRL_MEMORY_32BIT; struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG("Ti3026_init") + DBG(__FUNCTION__) memcpy(hw->DACreg, MGADACbpp32, sizeof(hw->DACreg)); - if (ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT) { - hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_8_1; - hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR; - hw->DACreg[POS3026_XMUXCTRL] = TVP3026_XMUXCTRL_VGA; - hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | - TVP3026_XCLKCTRL_DIV4; - hw->DACreg[POS3026_XMISCCTRL] = TVP3026_XMISCCTRL_DAC_PUP | TVP3026_XMISCCTRL_DAC_6BIT | TVP3026_XMISCCTRL_PSEL_DIS | TVP3026_XMISCCTRL_PSEL_LOW; - } else { - switch (p->var.bits_per_pixel) { + switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) { case 4: hw->DACreg[POS3026_XLATCHCTRL] = TVP3026_XLATCHCTRL_16_1; /* or _8_1, they are same */ hw->DACreg[POS3026_XTRUECOLORCTRL] = TVP3026_XTRUECOLORCTRL_PSEUDOCOLOR; hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_4BIT; @@ -525,7 +385,7 @@ break; case 16: /* XLATCHCTRL should be _4_1 / _2_1... Why is not? (_2_1 is used everytime) */ - hw->DACreg[POS3026_XTRUECOLORCTRL] = (p->var.green.length == 5)? (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_ORGB_1555 ) : (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_RGB_565); + hw->DACreg[POS3026_XTRUECOLORCTRL] = (ACCESS_FBINFO(fbcon).var.green.length == 5)? (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_ORGB_1555 ) : (TVP3026_XTRUECOLORCTRL_DIRECTCOLOR | TVP3026_XTRUECOLORCTRL_RGB_565); hw->DACreg[POS3026_XMUXCTRL] = muxctrl | TVP3026_XMUXCTRL_PIXEL_16BIT; hw->DACreg[POS3026_XCLKCTRL] = TVP3026_XCLKCTRL_SRC_PLL | TVP3026_XCLKCTRL_DIV2; break; @@ -541,9 +401,8 @@ break; default: return 1; /* TODO: failed */ - } } - if (matroxfb_vgaHWinit(PMINFO m, p)) return 1; + if (matroxfb_vgaHWinit(PMINFO m)) return 1; /* set SYNC */ hw->MiscOutReg = 0xCB; @@ -569,10 +428,10 @@ /* set interleaving */ hw->MXoptionReg &= ~0x00001000; - if ((ACCESS_FBINFO(fbcon).fix.type != FB_TYPE_TEXT) && isInterleave(MINFO)) hw->MXoptionReg |= 0x00001000; + if (isInterleave(MINFO)) hw->MXoptionReg |= 0x00001000; /* set DAC */ - Ti3026_setpclk(PMINFO m->pixclock, p); + Ti3026_setpclk(PMINFO m->pixclock); return 0; } @@ -583,7 +442,7 @@ unsigned int rfhcnt, mclk_ctl; int tmout; - DBG("ti3026_setMCLK") + DBG(__FUNCTION__) f_pll = Ti3026_calcclock(PMINFO fout, ACCESS_FBINFO(max_pixel_clock), &mclk_n, &mclk_m, &mclk_p); @@ -677,7 +536,7 @@ static void ti3026_ramdac_init(WPMINFO2) { - DBG("ti3026_ramdac_init") + DBG(__FUNCTION__) ACCESS_FBINFO(features.pll.vco_freq_min) = 110000; ACCESS_FBINFO(features.pll.ref_freq) = 114545; @@ -691,13 +550,13 @@ ti3026_setMCLK(PMINFO 60000); } -static void Ti3026_restore(WPMINFO struct display* p) { +static void Ti3026_restore(WPMINFO2) { int i; unsigned char progdac[6]; struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); CRITFLAGS - DBG("Ti3026_restore") + DBG(__FUNCTION__) #ifdef DEBUG dprintk(KERN_INFO "EXTVGA regs: "); @@ -788,7 +647,6 @@ dprintk(KERN_INFO "LoopPLL: %d\n", 500000-tmout); } } - matrox_init_putc(PMINFO p, matroxfb_ti3026_createcursor); #ifdef DEBUG dprintk(KERN_DEBUG "3026DACregs "); @@ -805,9 +663,7 @@ static void Ti3026_reset(WPMINFO2) { - DBG("Ti3026_reset") - - matroxfb_fastfont_init(MINFO); + DBG(__FUNCTION__) ti3026_ramdac_init(PMINFO2); } @@ -825,14 +681,13 @@ 2048, 0}; struct matrox_hw_state* hw = &ACCESS_FBINFO(hw); - DBG("Ti3026_preinit") + DBG(__FUNCTION__) ACCESS_FBINFO(millenium) = 1; ACCESS_FBINFO(milleniumII) = (ACCESS_FBINFO(pcidev)->device != PCI_DEVICE_ID_MATROX_MIL); ACCESS_FBINFO(capable.cfb4) = 1; ACCESS_FBINFO(capable.text) = 1; /* isMilleniumII(MINFO); */ ACCESS_FBINFO(capable.vxres) = isMilleniumII(MINFO)?vxres_mill2:vxres_mill1; - ACCESS_FBINFO(cursor.timer.function) = matroxfb_ti3026_flashcursor; ACCESS_FBINFO(outputs[0]).data = MINFO; ACCESS_FBINFO(outputs[0]).output = &ti3026_output; @@ -876,7 +731,7 @@ } struct matrox_switch matrox_millennium = { - Ti3026_preinit, Ti3026_reset, Ti3026_init, Ti3026_restore, matroxfb_ti3026_selhwcursor + Ti3026_preinit, Ti3026_reset, Ti3026_init, Ti3026_restore }; EXPORT_SYMBOL(matrox_millennium); #endif diff -Nru a/drivers/video/matrox/matroxfb_accel.c b/drivers/video/matrox/matroxfb_accel.c --- a/drivers/video/matrox/matroxfb_accel.c Mon Jun 9 23:16:14 2003 +++ b/drivers/video/matrox/matroxfb_accel.c Mon Jun 9 23:16:14 2003 @@ -85,44 +85,101 @@ #define mga_ydstlen(y,l) mga_outl(M_YDSTLEN | M_EXEC, ((y) << 16) | (l)) +static inline void matrox_cfb4_pal(u_int32_t* pal) { + unsigned int i; + + for (i = 0; i < 16; i++) { + pal[i] = i * 0x11111111U; + } + pal[i] = 0xFFFFFFFF; +} + +static inline void matrox_cfb8_pal(u_int32_t* pal) { + unsigned int i; + + for (i = 0; i < 16; i++) { + pal[i] = i * 0x01010101U; + } + pal[i] = 0x0F0F0F0F; +} + +static void matroxfb_copyarea(struct fb_info* info, const struct fb_copyarea* area); +static void matroxfb_fillrect(struct fb_info* info, const struct fb_fillrect* rect); +static void matroxfb_imageblit(struct fb_info* info, const struct fb_image* image); +static void matroxfb_cfb4_fillrect(struct fb_info* info, const struct fb_fillrect* rect); +static void matroxfb_cfb4_copyarea(struct fb_info* info, const struct fb_copyarea* area); + void matrox_cfbX_init(WPMINFO2) { u_int32_t maccess; u_int32_t mpitch; u_int32_t mopmode; + int accel; - DBG("matrox_cfbX_init") + DBG(__FUNCTION__) mpitch = ACCESS_FBINFO(fbcon).var.xres_virtual; - if (ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT) { - maccess = 0x00000000; - mpitch = (mpitch >> 4) | 0x8000; /* set something */ - mopmode = M_OPMODE_8BPP; - } else { - switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) { + ACCESS_FBINFO(fbops).fb_copyarea = cfb_copyarea; + ACCESS_FBINFO(fbops).fb_fillrect = cfb_fillrect; + ACCESS_FBINFO(fbops).fb_imageblit = cfb_imageblit; + ACCESS_FBINFO(fbops).fb_cursor = soft_cursor; + + accel = (ACCESS_FBINFO(fbcon).var.accel_flags & FB_ACCELF_TEXT) == FB_ACCELF_TEXT; + + switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) { case 4: maccess = 0x00000000; /* accelerate as 8bpp video */ mpitch = (mpitch >> 1) | 0x8000; /* disable linearization */ mopmode = M_OPMODE_4BPP; + matrox_cfb4_pal(ACCESS_FBINFO(cmap)); + if (accel && !(mpitch & 1)) { + ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_cfb4_copyarea; + ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_cfb4_fillrect; + } break; case 8: maccess = 0x00000000; mopmode = M_OPMODE_8BPP; + matrox_cfb8_pal(ACCESS_FBINFO(cmap)); + if (accel) { + ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea; + ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_fillrect; + ACCESS_FBINFO(fbops).fb_imageblit = matroxfb_imageblit; + } break; - case 16: if (ACCESS_FBINFO(fbcon).var.green.length == 5) + case 16: if (ACCESS_FBINFO(fbcon).var.green.length == 5) { maccess = 0xC0000001; - else + ACCESS_FBINFO(cmap[16]) = 0x7FFF7FFF; + } else { maccess = 0x40000001; + ACCESS_FBINFO(cmap[16]) = 0xFFFFFFFF; + } mopmode = M_OPMODE_16BPP; + if (accel) { + ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea; + ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_fillrect; + ACCESS_FBINFO(fbops).fb_imageblit = matroxfb_imageblit; + } break; case 24: maccess = 0x00000003; mopmode = M_OPMODE_24BPP; + ACCESS_FBINFO(cmap[16]) = 0xFFFFFFFF; + if (accel) { + ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea; + ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_fillrect; + ACCESS_FBINFO(fbops).fb_imageblit = matroxfb_imageblit; + } break; case 32: maccess = 0x00000002; mopmode = M_OPMODE_32BPP; + ACCESS_FBINFO(cmap[16]) = 0xFFFFFFFF; + if (accel) { + ACCESS_FBINFO(fbops).fb_copyarea = matroxfb_copyarea; + ACCESS_FBINFO(fbops).fb_fillrect = matroxfb_fillrect; + ACCESS_FBINFO(fbops).fb_imageblit = matroxfb_imageblit; + } break; default: maccess = 0x00000000; mopmode = 0x00000000; break; /* turn off acceleration!!! */ - } } mga_fifo(8); mga_outl(M_PITCH, mpitch); @@ -145,36 +202,29 @@ EXPORT_SYMBOL(matrox_cfbX_init); -static void matrox_cfbX_bmove(struct display* p, int sy, int sx, int dy, int dx, int height, int width) { - int pixx = p->var.xres_virtual, start, end; +static void matrox_accel_bmove(WPMINFO int vxres, int sy, int sx, int dy, int dx, int height, int width) { + int start, end; CRITFLAGS - MINFO_FROM_DISP(p); - DBG("matrox_cfbX_bmove") + DBG(__FUNCTION__) CRITBEGIN - sx *= fontwidth(p); - dx *= fontwidth(p); - width *= fontwidth(p); - height *= fontheight(p); - sy *= fontheight(p); - dy *= fontheight(p); if ((dy < sy) || ((dy == sy) && (dx <= sx))) { mga_fifo(2); mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO | M_DWG_BFCOL | M_DWG_REPLACE); - mga_outl(M_AR5, pixx); + mga_outl(M_AR5, vxres); width--; - start = sy*pixx+sx+curr_ydstorg(MINFO); + start = sy*vxres+sx+curr_ydstorg(MINFO); end = start+width; } else { mga_fifo(3); mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE); mga_outl(M_SGN, 5); - mga_outl(M_AR5, -pixx); + mga_outl(M_AR5, -vxres); width--; - end = (sy+height-1)*pixx+sx+curr_ydstorg(MINFO); + end = (sy+height-1)*vxres+sx+curr_ydstorg(MINFO); start = end+width; dy += height-1; } @@ -188,47 +238,29 @@ CRITEND } -#ifdef FBCON_HAS_CFB4 -static void matrox_cfb4_bmove(struct display* p, int sy, int sx, int dy, int dx, int height, int width) { - int pixx, start, end; +static void matrox_accel_bmove_lin(WPMINFO int vxres, int sy, int sx, int dy, int dx, int height, int width) { + int start, end; CRITFLAGS - MINFO_FROM_DISP(p); - /* both (sx or dx or width) and fontwidth() are odd, so their multiply is - also odd, that means that we cannot use acceleration */ - DBG("matrox_cfb4_bmove") + DBG(__FUNCTION__) CRITBEGIN - if ((sx | dx | width) & fontwidth(p) & 1) { - fbcon_cfb4_bmove(p, sy, sx, dy, dx, height, width); - return; - } - sx *= fontwidth(p); - dx *= fontwidth(p); - width *= fontwidth(p); - height *= fontheight(p); - sy *= fontheight(p); - dy *= fontheight(p); - pixx = p->var.xres_virtual >> 1; - sx >>= 1; - dx >>= 1; - width >>= 1; if ((dy < sy) || ((dy == sy) && (dx <= sx))) { mga_fifo(2); - mga_outl(M_AR5, pixx); mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_SGNZERO | M_DWG_BFCOL | M_DWG_REPLACE); + mga_outl(M_AR5, vxres); width--; - start = sy*pixx+sx+curr_ydstorg(MINFO); + start = sy*vxres+sx+curr_ydstorg(MINFO); end = start+width; } else { mga_fifo(3); - mga_outl(M_SGN, 5); - mga_outl(M_AR5, -pixx); mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SHIFTZERO | M_DWG_BFCOL | M_DWG_REPLACE); + mga_outl(M_SGN, 5); + mga_outl(M_AR5, -vxres); width--; - end = (sy+height-1)*pixx+sx+curr_ydstorg(MINFO); + end = (sy+height-1)*vxres+sx+curr_ydstorg(MINFO); start = end+width; dy += height-1; } @@ -236,19 +268,33 @@ mga_outl(M_AR0, end); mga_outl(M_AR3, start); mga_outl(M_FXBNDRY, ((dx+width)<<16) | dx); - mga_outl(M_YDST, dy*pixx >> 5); + mga_outl(M_YDST, dy*vxres >> 5); mga_outl(M_LEN | M_EXEC, height); WaitTillIdle(); CRITEND } -#endif + +static void matroxfb_cfb4_copyarea(struct fb_info* info, const struct fb_copyarea* area) { + MINFO_FROM_INFO(info); + + if ((area->sx | area->dx | area->width) & 1) + cfb_copyarea(info, area); + else + matrox_accel_bmove_lin(PMINFO ACCESS_FBINFO(fbcon.var.xres_virtual) >> 1, area->sy, area->sx >> 1, area->dy, area->dx >> 1, area->height, area->width >> 1); +} + +static void matroxfb_copyarea(struct fb_info* info, const struct fb_copyarea* area) { + MINFO_FROM_INFO(info); + + matrox_accel_bmove(PMINFO ACCESS_FBINFO(fbcon.var.xres_virtual), area->sy, area->sx, area->dy, area->dx, area->height, area->width); +} static void matroxfb_accel_clear(WPMINFO u_int32_t color, int sy, int sx, int height, int width) { CRITFLAGS - DBG("matroxfb_accel_clear") + DBG(__FUNCTION__) CRITBEGIN @@ -262,34 +308,25 @@ CRITEND } -static void matrox_cfbX_clear(u_int32_t color, struct display* p, int sy, int sx, int height, int width) { - - DBG("matrox_cfbX_clear") +static void matroxfb_fillrect(struct fb_info* info, const struct fb_fillrect* rect) { + MINFO_FROM_INFO(info); - matroxfb_accel_clear(PMXINFO(p) color, sy * fontheight(p), sx * fontwidth(p), - height * fontheight(p), width * fontwidth(p)); + switch (rect->rop) { + case ROP_COPY: + matroxfb_accel_clear(PMINFO ((u_int32_t*)info->pseudo_palette)[rect->color], rect->dy, rect->dx, rect->height, rect->width); + break; + } } -#ifdef FBCON_HAS_CFB4 -static void matrox_cfb4_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) { - u_int32_t bgx; +static void matroxfb_cfb4_clear(WPMINFO u_int32_t bgx, int sy, int sx, int height, int width) { int whattodo; CRITFLAGS - MINFO_FROM_DISP(p); - DBG("matrox_cfb4_clear") + DBG(__FUNCTION__) CRITBEGIN whattodo = 0; - bgx = attr_bgcol_ec(p, conp); - bgx |= bgx << 4; - bgx |= bgx << 8; - bgx |= bgx << 16; - sy *= fontheight(p); - sx *= fontwidth(p); - height *= fontheight(p); - width *= fontwidth(p); if (sx & 1) { sx ++; if (!width) return; @@ -306,12 +343,12 @@ mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_REPLACE2); mga_outl(M_FCOL, bgx); mga_outl(M_FXBNDRY, ((sx + width) << 16) | sx); - mga_outl(M_YDST, sy * p->var.xres_virtual >> 6); + mga_outl(M_YDST, sy * ACCESS_FBINFO(fbcon).var.xres_virtual >> 6); mga_outl(M_LEN | M_EXEC, height); WaitTillIdle(); } if (whattodo) { - u_int32_t step = p->var.xres_virtual >> 1; + u_int32_t step = ACCESS_FBINFO(fbcon).var.xres_virtual >> 1; vaddr_t vbase = ACCESS_FBINFO(video.vbase); if (whattodo & 1) { unsigned int uaddr = sy * step + sx - 1; @@ -335,227 +372,19 @@ CRITEND } -#endif -#ifdef FBCON_HAS_CFB8 -static void matrox_cfb8_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) { - u_int32_t bgx; - - DBG("matrox_cfb8_clear") - - bgx = attr_bgcol_ec(p, conp); - bgx |= bgx << 8; - bgx |= bgx << 16; - matrox_cfbX_clear(bgx, p, sy, sx, height, width); -} -#endif +static void matroxfb_cfb4_fillrect(struct fb_info* info, const struct fb_fillrect* rect) { + MINFO_FROM_INFO(info); -#ifdef FBCON_HAS_CFB16 -static void matrox_cfb16_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) { - u_int32_t bgx; - - DBG("matrox_cfb16_clear") - - bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)]; - matrox_cfbX_clear((bgx << 16) | bgx, p, sy, sx, height, width); -} -#endif - -#if defined(FBCON_HAS_CFB32) || defined(FBCON_HAS_CFB24) -static void matrox_cfb32_clear(struct vc_data* conp, struct display* p, int sy, int sx, int height, int width) { - u_int32_t bgx; - - DBG("matrox_cfb32_clear") - - bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol_ec(p, conp)]; - matrox_cfbX_clear(bgx, p, sy, sx, height, width); -} -#endif - -static void matrox_cfbX_fastputc(u_int32_t fgx, u_int32_t bgx, struct display* p, int c, int yy, int xx) { - unsigned int charcell; - unsigned int ar3; - CRITFLAGS - MINFO_FROM_DISP(p); - - charcell = fontwidth(p) * fontheight(p); - yy *= fontheight(p); - xx *= fontwidth(p); - - CRITBEGIN - - mga_fifo(8); - mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE); - - mga_outl(M_FCOL, fgx); - mga_outl(M_BCOL, bgx); - mga_outl(M_FXBNDRY, ((xx + fontwidth(p) - 1) << 16) | xx); - ar3 = ACCESS_FBINFO(fastfont.mgabase) + (c & p->charmask) * charcell; - mga_outl(M_AR3, ar3); - mga_outl(M_AR0, (ar3 + charcell - 1) & 0x0003FFFF); - mga_ydstlen(yy, fontheight(p)); - WaitTillIdle(); - - CRITEND -} - -static void matrox_cfbX_putc(u_int32_t fgx, u_int32_t bgx, struct display* p, int c, int yy, int xx) { - u_int32_t ar0; - u_int32_t step; - CRITFLAGS - MINFO_FROM_DISP(p); - - DBG_HEAVY("matrox_cfbX_putc"); - - yy *= fontheight(p); - xx *= fontwidth(p); - - CRITBEGIN - -#ifdef __BIG_ENDIAN - WaitTillIdle(); - mga_outl(M_OPMODE, M_OPMODE_8BPP); -#else - mga_fifo(7); -#endif - ar0 = fontwidth(p) - 1; - mga_outl(M_FXBNDRY, ((xx+ar0)<<16) | xx); - if (fontwidth(p) <= 8) - step = 1; - else if (fontwidth(p) <= 16) - step = 2; - else - step = 4; - if (fontwidth(p) == step << 3) { - size_t charcell = fontheight(p)*step; - /* TODO: Align charcell to 4B for BE */ - mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE); - mga_outl(M_FCOL, fgx); - mga_outl(M_BCOL, bgx); - mga_outl(M_AR3, 0); - mga_outl(M_AR0, fontheight(p)*fontwidth(p)-1); - mga_ydstlen(yy, fontheight(p)); - mga_memcpy_toio(ACCESS_FBINFO(mmio.vbase), 0, p->fontdata+(c&p->charmask)*charcell, charcell); - } else { - u8* chardata = p->fontdata+(c&p->charmask)*fontheight(p)*step; - int i; - - mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_REPLACE); - mga_outl(M_FCOL, fgx); - mga_outl(M_BCOL, bgx); - mga_outl(M_AR5, 0); - mga_outl(M_AR3, 0); - mga_outl(M_AR0, ar0); - mga_ydstlen(yy, fontheight(p)); - - switch (step) { - case 1: - for (i = fontheight(p); i > 0; i--) { -#ifdef __LITTLE_ENDIAN - mga_outl(0, *chardata++); -#else - mga_outl(0, (*chardata++) << 24); -#endif - } - break; - case 2: - for (i = fontheight(p); i > 0; i--) { -#ifdef __LITTLE_ENDIAN - mga_outl(0, *(u_int16_t*)chardata); -#else - mga_outl(0, (*(u_int16_t*)chardata) << 16); -#endif - chardata += 2; - } + switch (rect->rop) { + case ROP_COPY: + matroxfb_cfb4_clear(PMINFO ((u_int32_t*)info->pseudo_palette)[rect->color], rect->dy, rect->dx, rect->height, rect->width); break; - case 4: - mga_memcpy_toio(ACCESS_FBINFO(mmio.vbase), 0, chardata, fontheight(p) * 4); - break; - } } - WaitTillIdle(); -#ifdef __BIG_ENDIAN - mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode)); -#endif - CRITEND -} - -#ifdef FBCON_HAS_CFB8 -static void matrox_cfb8_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) { - u_int32_t fgx, bgx; - MINFO_FROM_DISP(p); - - DBG_HEAVY("matroxfb_cfb8_putc"); - - fgx = attr_fgcol(p, c); - bgx = attr_bgcol(p, c); - fgx |= (fgx << 8); - fgx |= (fgx << 16); - bgx |= (bgx << 8); - bgx |= (bgx << 16); - ACCESS_FBINFO(curr.putc)(fgx, bgx, p, c, yy, xx); -} -#endif - -#ifdef FBCON_HAS_CFB16 -static void matrox_cfb16_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) { - u_int32_t fgx, bgx; - MINFO_FROM_DISP(p); - - DBG_HEAVY("matroxfb_cfb16_putc"); - - fgx = ((u_int16_t*)p->dispsw_data)[attr_fgcol(p, c)]; - bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol(p, c)]; - fgx |= (fgx << 16); - bgx |= (bgx << 16); - ACCESS_FBINFO(curr.putc)(fgx, bgx, p, c, yy, xx); } -#endif -#if defined(FBCON_HAS_CFB32) || defined(FBCON_HAS_CFB24) -static void matrox_cfb32_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) { - u_int32_t fgx, bgx; - MINFO_FROM_DISP(p); - - DBG_HEAVY("matroxfb_cfb32_putc"); - - fgx = ((u_int32_t*)p->dispsw_data)[attr_fgcol(p, c)]; - bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol(p, c)]; - ACCESS_FBINFO(curr.putc)(fgx, bgx, p, c, yy, xx); -} -#endif - -static void matrox_cfbX_fastputcs(u_int32_t fgx, u_int32_t bgx, struct display* p, const unsigned short* s, int count, int yy, int xx) { - unsigned int charcell; - CRITFLAGS - MINFO_FROM_DISP(p); - - yy *= fontheight(p); - xx *= fontwidth(p); - charcell = fontwidth(p) * fontheight(p); - - CRITBEGIN - - mga_fifo(3); - mga_outl(M_DWGCTL, M_DWG_BITBLT | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_LINEAR | M_DWG_REPLACE); - mga_outl(M_FCOL, fgx); - mga_outl(M_BCOL, bgx); - while (count--) { - u_int32_t ar3 = ACCESS_FBINFO(fastfont.mgabase) + (scr_readw(s++) & p->charmask)*charcell; - - mga_fifo(4); - mga_outl(M_FXBNDRY, ((xx + fontwidth(p) - 1) << 16) | xx); - mga_outl(M_AR3, ar3); - mga_outl(M_AR0, (ar3 + charcell - 1) & 0x0003FFFF); - mga_ydstlen(yy, fontheight(p)); - xx += fontwidth(p); - } - WaitTillIdle(); - - CRITEND -} - -static void matrox_cfbX_putcs(u_int32_t fgx, u_int32_t bgx, struct display* p, const unsigned short* s, int count, int yy, int xx) { +static void matroxfb_1bpp_imageblit(WPMINFO u_int32_t fgx, u_int32_t bgx, + const u_int8_t* chardata, int width, int height, int yy, int xx) { u_int32_t step; u_int32_t ydstlen; u_int32_t xlen; @@ -565,26 +394,18 @@ vaddr_t mmio; int easy; CRITFLAGS - MINFO_FROM_DISP(p); - DBG_HEAVY("matroxfb_cfbX_putcs"); + DBG_HEAVY(__FUNCTION__); - yy *= fontheight(p); - xx *= fontwidth(p); - if (fontwidth(p) <= 8) - step = 1; - else if (fontwidth(p) <= 16) - step = 2; - else - step = 4; - charcell = fontheight(p)*step; + step = (width + 7) >> 3; + charcell = height * step; xlen = (charcell + 3) & ~3; - ydstlen = (yy << 16) | fontheight(p); - if (fontwidth(p) == step << 3) { - ar0 = fontheight(p)*fontwidth(p) - 1; + ydstlen = (yy << 16) | height; + if (width == step << 3) { + ar0 = height * width - 1; easy = 1; } else { - ar0 = fontwidth(p) - 1; + ar0 = width - 1; easy = 0; } @@ -602,50 +423,55 @@ mga_outl(M_DWGCTL, M_DWG_ILOAD | M_DWG_SGNZERO | M_DWG_SHIFTZERO | M_DWG_BMONOWF | M_DWG_REPLACE); mga_outl(M_FCOL, fgx); mga_outl(M_BCOL, bgx); - fxbndry = ((xx + fontwidth(p) - 1) << 16) | xx; + fxbndry = ((xx + width - 1) << 16) | xx; mmio = ACCESS_FBINFO(mmio.vbase); - while (count--) { - u_int8_t* chardata = p->fontdata + (scr_readw(s++) & p->charmask)*charcell; - mga_fifo(6); - mga_writel(mmio, M_FXBNDRY, fxbndry); - mga_writel(mmio, M_AR0, ar0); - mga_writel(mmio, M_AR3, 0); - if (easy) { - mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen); - mga_memcpy_toio(mmio, 0, chardata, xlen); - } else { - mga_writel(mmio, M_AR5, 0); - mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen); - switch (step) { - case 1: { - u_int8_t* charend = chardata + charcell; - for (; chardata != charend; chardata++) { + mga_fifo(6); + mga_writel(mmio, M_FXBNDRY, fxbndry); + mga_writel(mmio, M_AR0, ar0); + mga_writel(mmio, M_AR3, 0); + if (easy) { + mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen); + mga_memcpy_toio(mmio, 0, chardata, xlen); + } else { + mga_writel(mmio, M_AR5, 0); + mga_writel(mmio, M_YDSTLEN | M_EXEC, ydstlen); + if ((step & 3) == 0) { + /* Great. Source has 32bit aligned lines, so we can feed them + directly to the accelerator. */ + mga_memcpy_toio(mmio, 0, chardata, charcell); + } else if (step == 1) { + /* Special case for 1..8bit widths */ + while (height--) { #ifdef __LITTLE_ENDIAN - mga_writel(mmio, 0, *chardata); + mga_writel(mmio, 0, *chardata); #else - mga_writel(mmio, 0, (*chardata) << 24); + mga_writel(mmio, 0, (*chardata) << 24); #endif - } - } - break; - case 2: { - u_int8_t* charend = chardata + charcell; - for (; chardata != charend; chardata += 2) { + chardata++; + } + } else if (step == 2) { + /* Special case for 9..15bit widths */ + while (height--) { #ifdef __LITTLE_ENDIAN - mga_writel(mmio, 0, *(u_int16_t*)chardata); + mga_writel(mmio, 0, *(u_int16_t*)chardata); #else - mga_writel(mmio, 0, (*(u_int16_t*)chardata) << 16); + mga_writel(mmio, 0, (*(u_int16_t*)chardata) << 16); #endif - } - } - break; - default: - mga_memcpy_toio(mmio, 0, chardata, charcell); - break; + chardata += 2; + } + } else { + /* Tell... well, why bother... */ + while (height--) { + size_t i; + + for (i = 0; i < step; i += 4) { + /* Hope that there are at least three readable bytes beyond the end of bitmap */ + mga_writel(mmio, 0, get_unaligned((u_int32_t*)(chardata + i))); + } + chardata += step; } } - fxbndry += fontwidth(p) + (fontwidth(p) << 16); } WaitTillIdle(); #ifdef __BIG_ENDIAN @@ -654,606 +480,26 @@ CRITEND } -#ifdef FBCON_HAS_CFB8 -static void matrox_cfb8_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, int count, int yy, int xx) { - u_int16_t c; - u_int32_t fgx, bgx; - MINFO_FROM_DISP(p); - - DBG_HEAVY("matroxfb_cfb8_putcs"); - - c = scr_readw(s); - fgx = attr_fgcol(p, c); - bgx = attr_bgcol(p, c); - fgx |= (fgx << 8); - fgx |= (fgx << 16); - bgx |= (bgx << 8); - bgx |= (bgx << 16); - ACCESS_FBINFO(curr.putcs)(fgx, bgx, p, s, count, yy, xx); -} -#endif - -#ifdef FBCON_HAS_CFB16 -static void matrox_cfb16_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, int count, int yy, int xx) { - u_int16_t c; - u_int32_t fgx, bgx; - MINFO_FROM_DISP(p); - - DBG_HEAVY("matroxfb_cfb16_putcs"); - - c = scr_readw(s); - fgx = ((u_int16_t*)p->dispsw_data)[attr_fgcol(p, c)]; - bgx = ((u_int16_t*)p->dispsw_data)[attr_bgcol(p, c)]; - fgx |= (fgx << 16); - bgx |= (bgx << 16); - ACCESS_FBINFO(curr.putcs)(fgx, bgx, p, s, count, yy, xx); -} -#endif - -#if defined(FBCON_HAS_CFB32) || defined(FBCON_HAS_CFB24) -static void matrox_cfb32_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, int count, int yy, int xx) { - u_int16_t c; - u_int32_t fgx, bgx; - MINFO_FROM_DISP(p); - - DBG_HEAVY("matroxfb_cfb32_putcs"); - - c = scr_readw(s); - fgx = ((u_int32_t*)p->dispsw_data)[attr_fgcol(p, c)]; - bgx = ((u_int32_t*)p->dispsw_data)[attr_bgcol(p, c)]; - ACCESS_FBINFO(curr.putcs)(fgx, bgx, p, s, count, yy, xx); -} -#endif - -#ifdef FBCON_HAS_CFB4 -static void matrox_cfb4_revc(struct display* p, int xx, int yy) { - CRITFLAGS - MINFO_FROM_DISP(p); - - DBG_LOOP("matroxfb_cfb4_revc"); - - if (fontwidth(p) & 1) { - fbcon_cfb4_revc(p, xx, yy); - return; - } - yy *= fontheight(p); - xx *= fontwidth(p); - xx |= (xx + fontwidth(p)) << 16; - xx >>= 1; - - CRITBEGIN - - mga_fifo(5); - mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR); - mga_outl(M_FCOL, 0xFFFFFFFF); - mga_outl(M_FXBNDRY, xx); - mga_outl(M_YDST, yy * p->var.xres_virtual >> 6); - mga_outl(M_LEN | M_EXEC, fontheight(p)); - WaitTillIdle(); - - CRITEND -} -#endif - -#ifdef FBCON_HAS_CFB8 -static void matrox_cfb8_revc(struct display* p, int xx, int yy) { - CRITFLAGS - MINFO_FROM_DISP(p); - - DBG_LOOP("matrox_cfb8_revc") - - yy *= fontheight(p); - xx *= fontwidth(p); - - CRITBEGIN - - mga_fifo(4); - mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR); - mga_outl(M_FCOL, 0x0F0F0F0F); - mga_outl(M_FXBNDRY, ((xx + fontwidth(p)) << 16) | xx); - mga_ydstlen(yy, fontheight(p)); - WaitTillIdle(); - - CRITEND -} -#endif - -#if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB24) || defined(FBCON_HAS_CFB32) -static void matrox_cfbX_revc(struct display* p, int xx, int yy) { - CRITFLAGS - MINFO_FROM_DISP(p); - - DBG_LOOP("matrox_cfbX_revc") - - yy *= fontheight(p); - xx *= fontwidth(p); - - CRITBEGIN - - mga_fifo(4); - mga_outl(M_DWGCTL, ACCESS_FBINFO(accel.m_dwg_rect) | M_DWG_XOR); - mga_outl(M_FCOL, 0xFFFFFFFF); - mga_outl(M_FXBNDRY, ((xx + fontwidth(p)) << 16) | xx); - mga_ydstlen(yy, fontheight(p)); - WaitTillIdle(); - - CRITEND -} -#endif - -static void matrox_cfbX_clear_margins(struct vc_data* conp, struct display* p, int bottom_only) { - unsigned int bottom_height, right_width; - unsigned int bottom_start, right_start; - unsigned int cell_h, cell_w; - - DBG("matrox_cfbX_clear_margins") - - cell_w = fontwidth(p); - if (!cell_w) return; /* PARANOID */ - right_width = p->var.xres % cell_w; - right_start = p->var.xres - right_width; - if (!bottom_only && right_width) { - /* clear whole right margin, not only visible portion */ - matroxfb_accel_clear( PMXINFO(p) - /* color */ 0x00000000, - /* y */ 0, - /* x */ p->var.xoffset + right_start, - /* height */ p->var.yres_virtual, - /* width */ right_width); - } - cell_h = fontheight(p); - if (!cell_h) return; /* PARANOID */ - bottom_height = p->var.yres % cell_h; - if (bottom_height) { - bottom_start = p->var.yres - bottom_height; - matroxfb_accel_clear( PMXINFO(p) - /* color */ 0x00000000, - /* y */ p->var.yoffset + bottom_start, - /* x */ p->var.xoffset, - /* height */ bottom_height, - /* width */ right_start); - } -} - -static void matrox_text_setup(struct display* p) { - MINFO_FROM_DISP(p); - - p->next_line = ACCESS_FBINFO(fbcon).fix.line_length ? ACCESS_FBINFO(fbcon).fix.line_length : ((p->var.xres_virtual / (fontwidth(p)?fontwidth(p):8)) * ACCESS_FBINFO(devflags.textstep)); - p->next_plane = 0; -} - -static void matrox_text_bmove(struct display* p, int sy, int sx, int dy, int dx, - int height, int width) { - unsigned int srcoff; - unsigned int dstoff; - unsigned int step; - CRITFLAGS - MINFO_FROM_DISP(p); - - CRITBEGIN - - step = ACCESS_FBINFO(devflags.textstep); - srcoff = (sy * p->next_line) + (sx * step); - dstoff = (dy * p->next_line) + (dx * step); - if (dstoff < srcoff) { - while (height > 0) { - int i; - for (i = width; i > 0; dstoff += step, srcoff += step, i--) - mga_writew(ACCESS_FBINFO(video.vbase), dstoff, mga_readw(ACCESS_FBINFO(video.vbase), srcoff)); - height--; - dstoff += p->next_line - width * step; - srcoff += p->next_line - width * step; - } - } else { - unsigned int off; - - off = (height - 1) * p->next_line + (width - 1) * step; - srcoff += off; - dstoff += off; - while (height > 0) { - int i; - for (i = width; i > 0; dstoff -= step, srcoff -= step, i--) - mga_writew(ACCESS_FBINFO(video.vbase), dstoff, mga_readw(ACCESS_FBINFO(video.vbase), srcoff)); - dstoff -= p->next_line - width * step; - srcoff -= p->next_line - width * step; - height--; - } - } - CRITEND -} - -static void matrox_text_clear(struct vc_data* conp, struct display* p, int sy, int sx, - int height, int width) { - unsigned int offs; - unsigned int val; - unsigned int step; - CRITFLAGS - MINFO_FROM_DISP(p); - - step = ACCESS_FBINFO(devflags.textstep); - offs = sy * p->next_line + sx * step; - val = ntohs((attr_bgcol(p, conp->vc_video_erase_char) << 4) | attr_fgcol(p, conp->vc_video_erase_char) | (' ' << 8)); - - CRITBEGIN - - while (height > 0) { - int i; - for (i = width; i > 0; offs += step, i--) - mga_writew(ACCESS_FBINFO(video.vbase), offs, val); - offs += p->next_line - width * step; - height--; - } - CRITEND -} - -static void matrox_text_putc(struct vc_data* conp, struct display* p, int c, int yy, int xx) { - unsigned int offs; - unsigned int chr; - unsigned int step; - CRITFLAGS - MINFO_FROM_DISP(p); - - step = ACCESS_FBINFO(devflags.textstep); - offs = yy * p->next_line + xx * step; - chr = attr_fgcol(p,c) | (attr_bgcol(p,c) << 4) | ((c & p->charmask) << 8); - if (chr & 0x10000) chr |= 0x08; - - CRITBEGIN - - mga_writew(ACCESS_FBINFO(video.vbase), offs, ntohs(chr)); - - CRITEND -} - -static void matrox_text_putcs(struct vc_data* conp, struct display* p, const unsigned short* s, - int count, int yy, int xx) { - unsigned int offs; - unsigned int attr; - unsigned int step; - u_int16_t c; - CRITFLAGS - MINFO_FROM_DISP(p); - - step = ACCESS_FBINFO(devflags.textstep); - offs = yy * p->next_line + xx * step; - c = scr_readw(s); - attr = attr_fgcol(p, c) | (attr_bgcol(p, c) << 4); - - CRITBEGIN - - while (count-- > 0) { - unsigned int chr = ((scr_readw(s++)) & p->charmask) << 8; - if (chr & 0x10000) chr ^= 0x10008; - mga_writew(ACCESS_FBINFO(video.vbase), offs, ntohs(attr|chr)); - offs += step; - } - - CRITEND -} - -static void matrox_text_revc(struct display* p, int xx, int yy) { - unsigned int offs; - unsigned int step; - CRITFLAGS - MINFO_FROM_DISP(p); - - step = ACCESS_FBINFO(devflags.textstep); - offs = yy * p->next_line + xx * step + 1; - - CRITBEGIN - - mga_writeb(ACCESS_FBINFO(video.vbase), offs, mga_readb(ACCESS_FBINFO(video.vbase), offs) ^ 0x77); - - CRITEND -} - -static void matrox_text_createcursor(WPMINFO struct display* p) { - CRITFLAGS - - if (ACCESS_FBINFO(currcon_display) != p) - return; - - matroxfb_createcursorshape(PMINFO p, 0); - - CRITBEGIN - - mga_setr(M_CRTC_INDEX, 0x0A, ACCESS_FBINFO(cursor.u)); - mga_setr(M_CRTC_INDEX, 0x0B, ACCESS_FBINFO(cursor.d) - 1); - - CRITEND -} - -static void matrox_text_cursor(struct display* p, int mode, int x, int y) { - unsigned int pos; - CRITFLAGS - MINFO_FROM_DISP(p); - - if (ACCESS_FBINFO(currcon_display) != p) - return; - - if (mode == CM_ERASE) { - if (ACCESS_FBINFO(cursor.state) != CM_ERASE) { - - CRITBEGIN - - mga_setr(M_CRTC_INDEX, 0x0A, 0x20); - - CRITEND - ACCESS_FBINFO(cursor.state) = CM_ERASE; - } - return; - } - if ((p->conp->vc_cursor_type & CUR_HWMASK) != ACCESS_FBINFO(cursor.type)) - matrox_text_createcursor(PMINFO p); - - /* DO NOT CHECK cursor.x != x because of matroxfb_vgaHWinit moves cursor to 0,0 */ - ACCESS_FBINFO(cursor.x) = x; - ACCESS_FBINFO(cursor.y) = y; - pos = p->next_line / ACCESS_FBINFO(devflags.textstep) * y + x; - - CRITBEGIN +static void matroxfb_imageblit(struct fb_info* info, const struct fb_image* image) { + MINFO_FROM_INFO(info); - mga_setr(M_CRTC_INDEX, 0x0F, pos); - mga_setr(M_CRTC_INDEX, 0x0E, pos >> 8); - - mga_setr(M_CRTC_INDEX, 0x0A, ACCESS_FBINFO(cursor.u)); - - CRITEND - - ACCESS_FBINFO(cursor.state) = CM_DRAW; -} + DBG_HEAVY(__FUNCTION__); -void matrox_text_round(CPMINFO struct fb_var_screeninfo* var, struct display* p) { - unsigned hf; - unsigned vf; - unsigned vxres; - unsigned ych; - - hf = fontwidth(p); - if (!hf) hf = 8; - /* do not touch xres */ - vxres = (var->xres_virtual + hf - 1) / hf; - if (vxres >= 256) - vxres = 255; - if (vxres < 16) - vxres = 16; - vxres = (vxres + 1) & ~1; /* must be even */ - vf = fontheight(p); - if (!vf) vf = 16; - if (var->yres < var->yres_virtual) { - ych = ACCESS_FBINFO(devflags.textvram) / vxres; - var->yres_virtual = ych * vf; - } else - ych = var->yres_virtual / vf; - if (vxres * ych > ACCESS_FBINFO(devflags.textvram)) { - ych = ACCESS_FBINFO(devflags.textvram) / vxres; - var->yres_virtual = ych * vf; - } - var->xres_virtual = vxres * hf; -} - -EXPORT_SYMBOL(matrox_text_round); - -static int matrox_text_setfont(struct display* p, int width, int height) { - DBG("matrox_text_setfont"); - - if (p) { - MINFO_FROM_DISP(p); - - matrox_text_round(PMINFO &p->var, p); - p->next_line = ACCESS_FBINFO(fbcon).fix.line_length = ((p->var.xres_virtual / (fontwidth(p)?fontwidth(p):8)) * ACCESS_FBINFO(devflags.textstep)); - - if (p->conp) - matrox_text_createcursor(PMINFO p); - } - return 0; -} - -#define matrox_cfb16_revc matrox_cfbX_revc -#define matrox_cfb24_revc matrox_cfbX_revc -#define matrox_cfb32_revc matrox_cfbX_revc - -#define matrox_cfb24_clear matrox_cfb32_clear -#define matrox_cfb24_putc matrox_cfb32_putc -#define matrox_cfb24_putcs matrox_cfb32_putcs - -#ifdef FBCON_HAS_VGATEXT -static struct display_switch matroxfb_text = { - .setup = matrox_text_setup, - .bmove = matrox_text_bmove, - .clear = matrox_text_clear, - .putc = matrox_text_putc, - .putcs = matrox_text_putcs, - .revc = matrox_text_revc, - .cursor = matrox_text_cursor, - .set_font = matrox_text_setfont, - .fontwidthmask =FONTWIDTH(8)|FONTWIDTH(9) -}; -#endif - -#ifdef FBCON_HAS_CFB4 -static struct display_switch matroxfb_cfb4 = { - .setup = fbcon_cfb4_setup, - .bmove = matrox_cfb4_bmove, - .clear = matrox_cfb4_clear, - .putc = fbcon_cfb4_putc, - .putcs = fbcon_cfb4_putcs, - .revc = matrox_cfb4_revc, - .fontwidthmask =FONTWIDTH(8) /* fix, fix, fix it */ -}; -#endif - -#ifdef FBCON_HAS_CFB8 -static struct display_switch matroxfb_cfb8 = { - .setup = fbcon_cfb8_setup, - .bmove = matrox_cfbX_bmove, - .clear = matrox_cfb8_clear, - .putc = matrox_cfb8_putc, - .putcs = matrox_cfb8_putcs, - .revc = matrox_cfb8_revc, - .clear_margins =matrox_cfbX_clear_margins, - .fontwidthmask =~1 /* FONTWIDTHS */ -}; -#endif - -#ifdef FBCON_HAS_CFB16 -static struct display_switch matroxfb_cfb16 = { - .setup = fbcon_cfb16_setup, - .bmove = matrox_cfbX_bmove, - .clear = matrox_cfb16_clear, - .putc = matrox_cfb16_putc, - .putcs = matrox_cfb16_putcs, - .revc = matrox_cfb16_revc, - .clear_margins =matrox_cfbX_clear_margins, - .fontwidthmask =~1 /* FONTWIDTHS */ -}; -#endif - -#ifdef FBCON_HAS_CFB24 -static struct display_switch matroxfb_cfb24 = { - .setup = fbcon_cfb24_setup, - .bmove = matrox_cfbX_bmove, - .clear = matrox_cfb24_clear, - .putc = matrox_cfb24_putc, - .putcs = matrox_cfb24_putcs, - .revc = matrox_cfb24_revc, - .clear_margins =matrox_cfbX_clear_margins, - .fontwidthmask =~1 /* FONTWIDTHS */ /* TODO: and what about non-aligned access on BE? I think that there are no in my code */ -}; -#endif + if (image->depth == 0) { + u_int32_t fgx, bgx; -#ifdef FBCON_HAS_CFB32 -static struct display_switch matroxfb_cfb32 = { - .setup = fbcon_cfb32_setup, - .bmove = matrox_cfbX_bmove, - .clear = matrox_cfb32_clear, - .putc = matrox_cfb32_putc, - .putcs = matrox_cfb32_putcs, - .revc = matrox_cfb32_revc, - .clear_margins =matrox_cfbX_clear_margins, - .fontwidthmask =~1 /* FONTWIDTHS */ -}; -#endif - -void initMatrox(WPMINFO struct display* p) { - struct display_switch *swtmp; - - DBG("initMatrox") - - if (ACCESS_FBINFO(currcon_display) != p) - return; - if (p->dispsw && p->conp) - fb_con.con_cursor(p->conp, CM_ERASE); - p->dispsw_data = NULL; - if ((ACCESS_FBINFO(fbcon).var.accel_flags & FB_ACCELF_TEXT) != FB_ACCELF_TEXT) { - if (ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT) { - swtmp = &matroxfb_text; - } else { - switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) { -#ifdef FBCON_HAS_CFB4 - case 4: - swtmp = &fbcon_cfb4; - break; -#endif -#ifdef FBCON_HAS_CFB8 - case 8: - swtmp = &fbcon_cfb8; - break; -#endif -#ifdef FBCON_HAS_CFB16 - case 16: - p->dispsw_data = &ACCESS_FBINFO(cmap.cfb16); - swtmp = &fbcon_cfb16; - break; -#endif -#ifdef FBCON_HAS_CFB24 - case 24: - p->dispsw_data = &ACCESS_FBINFO(cmap.cfb24); - swtmp = &fbcon_cfb24; - break; -#endif -#ifdef FBCON_HAS_CFB32 - case 32: - p->dispsw_data = &ACCESS_FBINFO(cmap.cfb32); - swtmp = &fbcon_cfb32; - break; -#endif - default: - p->dispsw = &fbcon_dummy; - return; - } - } - dprintk(KERN_INFO "matroxfb: acceleration disabled\n"); - } else if (ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT) { - swtmp = &matroxfb_text; - } else { - switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) { -#ifdef FBCON_HAS_CFB4 - case 4: - swtmp = &matroxfb_cfb4; - break; -#endif -#ifdef FBCON_HAS_CFB8 - case 8: - swtmp = &matroxfb_cfb8; - break; -#endif -#ifdef FBCON_HAS_CFB16 - case 16: - p->dispsw_data = &ACCESS_FBINFO(cmap.cfb16); - swtmp = &matroxfb_cfb16; - break; -#endif -#ifdef FBCON_HAS_CFB24 - case 24: - p->dispsw_data = &ACCESS_FBINFO(cmap.cfb24); - swtmp = &matroxfb_cfb24; - break; -#endif -#ifdef FBCON_HAS_CFB32 - case 32: - p->dispsw_data = &ACCESS_FBINFO(cmap.cfb32); - swtmp = &matroxfb_cfb32; - break; -#endif - default: - p->dispsw = &fbcon_dummy; - return; - } - } - memcpy(&ACCESS_FBINFO(dispsw), swtmp, sizeof(ACCESS_FBINFO(dispsw))); - p->dispsw = &ACCESS_FBINFO(dispsw); - if ((ACCESS_FBINFO(fbcon).fix.type != FB_TYPE_TEXT) && ACCESS_FBINFO(devflags.hwcursor)) { - ACCESS_FBINFO(hw_switch)->selhwcursor(PMINFO2); - } -} - -EXPORT_SYMBOL(initMatrox); - -void matrox_init_putc(WPMINFO struct display* p, void (*dac_createcursor)(WPMINFO struct display* p)) { - int i; - - if (p && p->conp) { - if (ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT) { - matrox_text_createcursor(PMINFO p); - matrox_text_loadfont(PMINFO p); - i = 0; - } else { - dac_createcursor(PMINFO p); - i = matroxfb_fastfont_tryset(PMINFO p); - } - } else - i = 0; - if (i) { - ACCESS_FBINFO(curr.putc) = matrox_cfbX_fastputc; - ACCESS_FBINFO(curr.putcs) = matrox_cfbX_fastputcs; + fgx = ((u_int32_t*)info->pseudo_palette)[image->fg_color]; + bgx = ((u_int32_t*)info->pseudo_palette)[image->bg_color]; + matroxfb_1bpp_imageblit(PMINFO fgx, bgx, image->data, image->width, image->height, image->dy, image->dx); } else { - ACCESS_FBINFO(curr.putc) = matrox_cfbX_putc; - ACCESS_FBINFO(curr.putcs) = matrox_cfbX_putcs; + /* Danger! image->depth is useless: logo painting code always + passes framebuffer color depth here, although logo data are + always 8bpp and info->pseudo_palette is changed to contain + logo palette to be used (but only for true/direct-color... sic...). + So do it completely in software... */ + cfb_imageblit(info, image); } } - -EXPORT_SYMBOL(matrox_init_putc); MODULE_LICENSE("GPL"); diff -Nru a/drivers/video/matrox/matroxfb_accel.h b/drivers/video/matrox/matroxfb_accel.h --- a/drivers/video/matrox/matroxfb_accel.h Mon Jun 9 23:16:16 2003 +++ b/drivers/video/matrox/matroxfb_accel.h Mon Jun 9 23:16:16 2003 @@ -3,9 +3,6 @@ #include "matroxfb_base.h" -void matrox_init_putc(WPMINFO struct display* p, void (*)(WPMINFO struct display *p)); void matrox_cfbX_init(WPMINFO2); -void matrox_text_round(CPMINFO struct fb_var_screeninfo* var, struct display* p); -void initMatrox(WPMINFO struct display* p); #endif diff -Nru a/drivers/video/matrox/matroxfb_base.c b/drivers/video/matrox/matroxfb_base.c --- a/drivers/video/matrox/matroxfb_base.c Mon Jun 9 23:16:15 2003 +++ b/drivers/video/matrox/matroxfb_base.c Mon Jun 9 23:16:15 2003 @@ -101,6 +101,7 @@ /* make checkconfig does not check included files... */ #include <linux/config.h> +#include <linux/version.h> #include "matroxfb_base.h" #include "matroxfb_misc.h" @@ -111,9 +112,10 @@ #include "matroxfb_crtc2.h" #include "matroxfb_g450.h" #include <linux/matroxfb.h> +#include <linux/interrupt.h> #include <asm/uaccess.h> -#ifdef CONFIG_PPC +#ifdef CONFIG_PPC_PMAC unsigned char nvram_read_byte(int); static int default_vmode = VMODE_NVRAM; static int default_cmode = CMODE_NVRAM; @@ -145,25 +147,136 @@ 39721L,48L,16L,33L,10L, 96L,2L,~0, /* No sync info */ FB_VMODE_NONINTERLACED, - {0,0,0,0,0,0} + 0, {0,0,0,0,0} }; /* --------------------------------------------------------------------- */ -static inline void my_install_cmap(WPMINFO2) +static void update_crtc2(WPMINFO unsigned int pos) { + struct matroxfb_dh_fb_info* info = ACCESS_FBINFO(crtc2.info); + + /* Make sure that displays are compatible */ + if (info && (info->fbcon.var.bits_per_pixel == ACCESS_FBINFO(fbcon).var.bits_per_pixel) + && (info->fbcon.var.xres_virtual == ACCESS_FBINFO(fbcon).var.xres_virtual) + && (info->fbcon.var.green.length == ACCESS_FBINFO(fbcon).var.green.length) + ) { + switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) { + case 16: + case 32: + pos = pos * 8; + if (info->interlaced) { + mga_outl(0x3C2C, pos); + mga_outl(0x3C28, pos + ACCESS_FBINFO(fbcon).var.xres_virtual * ACCESS_FBINFO(fbcon).var.bits_per_pixel / 8); + } else { + mga_outl(0x3C28, pos); + } + break; + } + } +} + +static irqreturn_t matrox_irq(int irq, void *dev_id, struct pt_regs *fp) { - /* Do not touch this code if you do not understand what it does! */ - /* Never try to use do_install_cmap() instead. It is crap. */ - struct fb_cmap* cmap = &ACCESS_FBINFO(currcon_display)->cmap; + u_int32_t status; + int handled = 0; + + MINFO_FROM(dev_id); + + status = mga_inl(M_STATUS); + + if (status & 0x20) { + mga_outl(M_ICLEAR, 0x20); + ACCESS_FBINFO(crtc1.vsync.cnt)++; + wake_up_interruptible(&ACCESS_FBINFO(crtc1.vsync.wait)); + handled = 1; + } + if (status & 0x200) { + mga_outl(M_ICLEAR, 0x200); + ACCESS_FBINFO(crtc2.vsync.cnt)++; + wake_up_interruptible(&ACCESS_FBINFO(crtc2.vsync.wait)); + handled = 1; + } + return IRQ_RETVAL(handled); +} - if (cmap->len) - fb_set_cmap(cmap, 1, &ACCESS_FBINFO(fbcon)); +int matroxfb_enable_irq(WPMINFO int reenable) { + u_int32_t bm; + + if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400) + bm = 0x220; else - fb_set_cmap(fb_default_cmap(ACCESS_FBINFO(curr.cmap_len)), - 1, &ACCESS_FBINFO(fbcon)); + bm = 0x020; + + if (!test_and_set_bit(0, &ACCESS_FBINFO(irq_flags))) { + printk(KERN_DEBUG "matroxfb: enabling IRQ\n"); + if (request_irq(ACCESS_FBINFO(pcidev)->irq, matrox_irq, + SA_SHIRQ, "MGA Vertical Sync", MINFO)) { + clear_bit(0, &ACCESS_FBINFO(irq_flags)); + return -EINVAL; + } + mga_outl(M_IEN, mga_inl(M_IEN) | bm); + } else if (reenable) { + u_int32_t ien; + + ien = mga_inl(M_IEN); + if ((ien & bm) != bm) { + printk(KERN_DEBUG "matroxfb: someone disabled IRQ [%08X]\n", ien); + mga_outl(M_IEN, ien | bm); + } + } + return 0; +} + +static void matroxfb_disable_irq(WPMINFO2) { + if (test_and_clear_bit(0, &ACCESS_FBINFO(irq_flags))) { + printk(KERN_DEBUG "matroxfb: disabling IRQ\n"); + if (ACCESS_FBINFO(devflags.accelerator) == FB_ACCEL_MATROX_MGAG400) + mga_outl(M_IEN, mga_inl(M_IEN) & ~0x220); + else + mga_outl(M_IEN, mga_inl(M_IEN) & ~0x20); + free_irq(ACCESS_FBINFO(pcidev)->irq, MINFO); + } +} + +int matroxfb_wait_for_sync(WPMINFO u_int32_t crtc) { + wait_queue_t __wait; + struct matrox_vsync *vs; + unsigned int cnt; + int ret; + + switch (crtc) { + case 0: + vs = &ACCESS_FBINFO(crtc1.vsync); + break; + case 1: + if (ACCESS_FBINFO(devflags.accelerator) != FB_ACCEL_MATROX_MGAG400) { + return -ENODEV; + } + vs = &ACCESS_FBINFO(crtc2.vsync); + break; + default: + return -ENODEV; + } + ret = matroxfb_enable_irq(PMINFO 0); + if (ret) { + return ret; + } + init_waitqueue_entry(&__wait, current); + + cnt = vs->cnt; + ret = wait_event_interruptible_timeout(vs->wait, cnt != vs->cnt, HZ/10); + if (ret < 0) { + return ret; + } + if (ret == 0) { + matroxfb_enable_irq(PMINFO 1); + return -ETIMEDOUT; + } + return 0; } +/* --------------------------------------------------------------------- */ static void matrox_pan_var(WPMINFO struct fb_var_screeninfo *var) { unsigned int pos; @@ -171,23 +284,17 @@ #ifdef CONFIG_FB_MATROX_32MB unsigned int p3; #endif - struct display *disp; CRITFLAGS - DBG("matrox_pan_var") + DBG(__FUNCTION__) if (ACCESS_FBINFO(dead)) return; ACCESS_FBINFO(fbcon).var.xoffset = var->xoffset; ACCESS_FBINFO(fbcon).var.yoffset = var->yoffset; - disp = ACCESS_FBINFO(currcon_display); - if (ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT) { - pos = ACCESS_FBINFO(fbcon).var.yoffset / fontheight(disp) * disp->next_line / ACCESS_FBINFO(devflags.textstep) + ACCESS_FBINFO(fbcon).var.xoffset / (fontwidth(disp)?fontwidth(disp):8); - } else { - pos = (ACCESS_FBINFO(fbcon).var.yoffset * ACCESS_FBINFO(fbcon).var.xres_virtual + ACCESS_FBINFO(fbcon).var.xoffset) * ACCESS_FBINFO(curr.final_bppShift) / 32; - pos += ACCESS_FBINFO(curr.ydstorg.chunks); - } + pos = (ACCESS_FBINFO(fbcon).var.yoffset * ACCESS_FBINFO(fbcon).var.xres_virtual + ACCESS_FBINFO(fbcon).var.xoffset) * ACCESS_FBINFO(curr.final_bppShift) / 32; + pos += ACCESS_FBINFO(curr.ydstorg.chunks); p0 = ACCESS_FBINFO(hw).CRTC[0x0D] = pos & 0xFF; p1 = ACCESS_FBINFO(hw).CRTC[0x0C] = (pos & 0xFF00) >> 8; p2 = ACCESS_FBINFO(hw).CRTCEXT[0] = (ACCESS_FBINFO(hw).CRTCEXT[0] & 0xB0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40); @@ -204,6 +311,8 @@ mga_setr(M_EXTVGA_INDEX, 0x08, p3); #endif mga_setr(M_EXTVGA_INDEX, 0x00, p2); + + update_crtc2(PMINFO pos); CRITEND } @@ -225,7 +334,6 @@ matroxfb_unregister_device(MINFO); unregister_framebuffer(&ACCESS_FBINFO(fbcon)); matroxfb_g450_shutdown(PMINFO2); - del_timer_sync(&ACCESS_FBINFO(cursor.timer)); #ifdef CONFIG_MTRR if (ACCESS_FBINFO(mtrr.vram_valid)) mtrr_del(ACCESS_FBINFO(mtrr.vram), ACCESS_FBINFO(video.base), ACCESS_FBINFO(video.len)); @@ -235,7 +343,6 @@ release_mem_region(ACCESS_FBINFO(video.base), ACCESS_FBINFO(video.len_maximum)); release_mem_region(ACCESS_FBINFO(mmio.base), 16384); #ifdef CONFIG_FB_MATROX_MULTIHEAD - kfree(ACCESS_FBINFO(fbcon.disp)); kfree(minfo); #endif } @@ -246,69 +353,51 @@ static int matroxfb_open(struct fb_info *info, int user) { -#define minfo (container_of(info, struct matrox_fb_info, fbcon)) - DBG_LOOP("matroxfb_open") + MINFO_FROM_INFO(info); + + DBG_LOOP(__FUNCTION__) if (ACCESS_FBINFO(dead)) { return -ENXIO; } ACCESS_FBINFO(usecount)++; -#undef minfo + if (user) { + ACCESS_FBINFO(userusecount)++; + } return(0); } static int matroxfb_release(struct fb_info *info, int user) { -#define minfo (container_of(info, struct matrox_fb_info, fbcon)) - DBG_LOOP("matroxfb_release") - + MINFO_FROM_INFO(info); + + DBG_LOOP(__FUNCTION__) + + if (user) { + if (0 == --ACCESS_FBINFO(userusecount)) { + matroxfb_disable_irq(PMINFO2); + } + } if (!(--ACCESS_FBINFO(usecount)) && ACCESS_FBINFO(dead)) { matroxfb_remove(PMINFO 0); } -#undef minfo return(0); } -static int matroxfb_pan_display(struct fb_var_screeninfo *var, int con, +static int matroxfb_pan_display(struct fb_var_screeninfo *var, struct fb_info* info) { -#define minfo (container_of(info, struct matrox_fb_info, fbcon)) - - DBG("matroxfb_pan_display") + MINFO_FROM_INFO(info); - if (var->vmode & FB_VMODE_YWRAP) { - if (var->yoffset < 0 || var->yoffset >= fb_display[con].var.yres_virtual || var->xoffset) - return -EINVAL; - } else { - if (var->xoffset+fb_display[con].var.xres > fb_display[con].var.xres_virtual || - var->yoffset+fb_display[con].var.yres > fb_display[con].var.yres_virtual) - return -EINVAL; - } - if (con == ACCESS_FBINFO(fbcon.currcon)) - matrox_pan_var(PMINFO var); - fb_display[con].var.xoffset = var->xoffset; - fb_display[con].var.yoffset = var->yoffset; - if (var->vmode & FB_VMODE_YWRAP) - fb_display[con].var.vmode |= FB_VMODE_YWRAP; - else - fb_display[con].var.vmode &= ~FB_VMODE_YWRAP; - return 0; -#undef minfo -} + DBG(__FUNCTION__) -static int matroxfb_updatevar(int con, struct fb_info *info) -{ -#define minfo (container_of(info, struct matrox_fb_info, fbcon)) - DBG("matroxfb_updatevar"); - - matrox_pan_var(PMINFO &fb_display[con].var); + matrox_pan_var(PMINFO var); return 0; -#undef minfo } static int matroxfb_get_final_bppShift(CPMINFO int bpp) { int bppshft2; - DBG("matroxfb_get_final_bppShift") + DBG(__FUNCTION__) bppshft2 = bpp; if (!bppshft2) { @@ -325,7 +414,7 @@ int over; int rounding; - DBG("matroxfb_test_and_set_rounding") + DBG(__FUNCTION__) switch (bpp) { case 0: return xres; @@ -356,7 +445,7 @@ const int* width; int xres_new; - DBG("matroxfb_pitch_adjust") + DBG(__FUNCTION__) if (!bpp) return xres; @@ -382,41 +471,27 @@ static int matroxfb_get_cmap_len(struct fb_var_screeninfo *var) { - DBG("matroxfb_get_cmap_len") + DBG(__FUNCTION__) switch (var->bits_per_pixel) { -#ifdef FBCON_HAS_VGATEXT - case 0: - return 16; /* pseudocolor... 16 entries HW palette */ -#endif -#ifdef FBCON_HAS_CFB4 case 4: return 16; /* pseudocolor... 16 entries HW palette */ -#endif -#ifdef FBCON_HAS_CFB8 case 8: return 256; /* pseudocolor... 256 entries HW palette */ -#endif -#ifdef FBCON_HAS_CFB16 case 16: return 16; /* directcolor... 16 entries SW palette */ /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */ -#endif -#ifdef FBCON_HAS_CFB24 case 24: return 16; /* directcolor... 16 entries SW palette */ /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */ -#endif -#ifdef FBCON_HAS_CFB32 case 32: return 16; /* directcolor... 16 entries SW palette */ /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */ -#endif } return 16; /* return something reasonable... or panic()? */ } -static int matroxfb_decode_var(CPMINFO struct display* p, struct fb_var_screeninfo *var, int *visual, int *video_cmap_len, unsigned int* ydstorg) { +static int matroxfb_decode_var(CPMINFO struct fb_var_screeninfo *var, int *visual, int *video_cmap_len, unsigned int* ydstorg) { struct RGBT { unsigned char bpp; struct { @@ -429,51 +504,26 @@ signed char visual; }; static const struct RGBT table[]= { -#if defined FBCON_HAS_VGATEXT - { 0,{ 0,6},{0,6},{0,6},{ 0,0},MX_VISUAL_PSEUDOCOLOR}, -#endif -#if defined FBCON_HAS_CFB4 || defined FBCON_HAS_CFB8 { 8,{ 0,8},{0,8},{0,8},{ 0,0},MX_VISUAL_PSEUDOCOLOR}, -#endif -#if defined FBCON_HAS_CFB16 {15,{10,5},{5,5},{0,5},{15,1},MX_VISUAL_DIRECTCOLOR}, {16,{11,5},{5,6},{0,5},{ 0,0},MX_VISUAL_DIRECTCOLOR}, -#endif -#if defined FBCON_HAS_CFB24 {24,{16,8},{8,8},{0,8},{ 0,0},MX_VISUAL_DIRECTCOLOR}, -#endif -#if defined FBCON_HAS_CFB32 {32,{16,8},{8,8},{0,8},{24,8},MX_VISUAL_DIRECTCOLOR} -#endif }; struct RGBT const *rgbt; unsigned int bpp = var->bits_per_pixel; unsigned int vramlen; unsigned int memlen; - DBG("matroxfb_decode_var") + DBG(__FUNCTION__) switch (bpp) { -#ifdef FBCON_HAS_VGATEXT - case 0: if (!ACCESS_FBINFO(capable.text)) return -EINVAL; - break; -#endif -#ifdef FBCON_HAS_CFB4 case 4: if (!ACCESS_FBINFO(capable.cfb4)) return -EINVAL; break; -#endif -#ifdef FBCON_HAS_CFB8 case 8: break; -#endif -#ifdef FBCON_HAS_CFB16 case 16: break; -#endif -#ifdef FBCON_HAS_CFB24 case 24: break; -#endif -#ifdef FBCON_HAS_CFB32 case 32: break; -#endif default: return -EINVAL; } *ydstorg = 0; @@ -482,50 +532,39 @@ var->yres_virtual = var->yres; if (var->xres_virtual < var->xres) var->xres_virtual = var->xres; - if (bpp) { - var->xres_virtual = matroxfb_pitch_adjust(PMINFO var->xres_virtual, bpp); + + var->xres_virtual = matroxfb_pitch_adjust(PMINFO var->xres_virtual, bpp); + memlen = var->xres_virtual * bpp * var->yres_virtual / 8; + if (memlen > vramlen) { + var->yres_virtual = vramlen * 8 / (var->xres_virtual * bpp); memlen = var->xres_virtual * bpp * var->yres_virtual / 8; - if (memlen > vramlen) { - var->yres_virtual = vramlen * 8 / (var->xres_virtual * bpp); - memlen = var->xres_virtual * bpp * var->yres_virtual / 8; - } - /* There is hardware bug that no line can cross 4MB boundary */ - /* give up for CFB24, it is impossible to easy workaround it */ - /* for other try to do something */ - if (!ACCESS_FBINFO(capable.cross4MB) && (memlen > 0x400000)) { - if (bpp == 24) { - /* sorry */ - } else { - unsigned int linelen; - unsigned int m1 = linelen = var->xres_virtual * bpp / 8; - unsigned int m2 = PAGE_SIZE; /* or 128 if you do not need PAGE ALIGNED address */ - unsigned int max_yres; - - while (m1) { - int t; - - while (m2 >= m1) m2 -= m1; - t = m1; - m1 = m2; - m2 = t; - } - m2 = linelen * PAGE_SIZE / m2; - *ydstorg = m2 = 0x400000 % m2; - max_yres = (vramlen - m2) / linelen; - if (var->yres_virtual > max_yres) - var->yres_virtual = max_yres; - } + } + /* There is hardware bug that no line can cross 4MB boundary */ + /* give up for CFB24, it is impossible to easy workaround it */ + /* for other try to do something */ + if (!ACCESS_FBINFO(capable.cross4MB) && (memlen > 0x400000)) { + if (bpp == 24) { + /* sorry */ + } else { + unsigned int linelen; + unsigned int m1 = linelen = var->xres_virtual * bpp / 8; + unsigned int m2 = PAGE_SIZE; /* or 128 if you do not need PAGE ALIGNED address */ + unsigned int max_yres; + + while (m1) { + int t; + + while (m2 >= m1) m2 -= m1; + t = m1; + m1 = m2; + m2 = t; + } + m2 = linelen * PAGE_SIZE / m2; + *ydstorg = m2 = 0x400000 % m2; + max_yres = (vramlen - m2) / linelen; + if (var->yres_virtual > max_yres) + var->yres_virtual = max_yres; } - } else { - matrox_text_round(PMINFO var, p); -#if 0 -/* we must limit pixclock by mclk... - Millennium I: 66 MHz = 15000 - Millennium II: 61 MHz = 16300 - Millennium G200: 83 MHz = 12000 */ - if (var->pixclock < 15000) - var->pixclock = 15000; /* limit for "normal" gclk & mclk */ -#endif } /* YDSTLEN contains only signed 16bit value */ if (var->yres_virtual > 32767) @@ -576,7 +615,7 @@ struct matrox_fb_info* minfo = container_of(fb_info, struct matrox_fb_info, fbcon); #endif - DBG("matroxfb_setcolreg") + DBG(__FUNCTION__) /* * Set a single color register. The values supplied are @@ -604,61 +643,42 @@ transp = CNVT_TOHW(transp, ACCESS_FBINFO(fbcon).var.transp.length); switch (ACCESS_FBINFO(fbcon).var.bits_per_pixel) { -#if defined(FBCON_HAS_CFB8) || defined(FBCON_HAS_CFB4) || defined(FBCON_HAS_VGATEXT) -#ifdef FBCON_HAS_VGATEXT - case 0: -#endif -#ifdef FBCON_HAS_CFB4 case 4: -#endif -#ifdef FBCON_HAS_CFB8 case 8: -#endif mga_outb(M_DAC_REG, regno); mga_outb(M_DAC_VAL, red); mga_outb(M_DAC_VAL, green); mga_outb(M_DAC_VAL, blue); break; -#endif -#ifdef FBCON_HAS_CFB16 case 16: - ACCESS_FBINFO(cmap.cfb16[regno]) = - (red << ACCESS_FBINFO(fbcon).var.red.offset) | - (green << ACCESS_FBINFO(fbcon).var.green.offset) | - (blue << ACCESS_FBINFO(fbcon).var.blue.offset) | - (transp << ACCESS_FBINFO(fbcon).var.transp.offset); /* for 1:5:5:5 */ + { + u_int16_t col = + (red << ACCESS_FBINFO(fbcon).var.red.offset) | + (green << ACCESS_FBINFO(fbcon).var.green.offset) | + (blue << ACCESS_FBINFO(fbcon).var.blue.offset) | + (transp << ACCESS_FBINFO(fbcon).var.transp.offset); /* for 1:5:5:5 */ + ACCESS_FBINFO(cmap[regno]) = col | (col << 16); + } break; -#endif -#ifdef FBCON_HAS_CFB24 case 24: - ACCESS_FBINFO(cmap.cfb24[regno]) = - (red << ACCESS_FBINFO(fbcon).var.red.offset) | - (green << ACCESS_FBINFO(fbcon).var.green.offset) | - (blue << ACCESS_FBINFO(fbcon).var.blue.offset); - break; -#endif -#ifdef FBCON_HAS_CFB32 case 32: - ACCESS_FBINFO(cmap.cfb32[regno]) = + ACCESS_FBINFO(cmap[regno]) = (red << ACCESS_FBINFO(fbcon).var.red.offset) | (green << ACCESS_FBINFO(fbcon).var.green.offset) | (blue << ACCESS_FBINFO(fbcon).var.blue.offset) | (transp << ACCESS_FBINFO(fbcon).var.transp.offset); /* 8:8:8:8 */ break; -#endif } return 0; } -static void matroxfb_update_fix(WPMINFO2) +static void matroxfb_init_fix(WPMINFO2) { struct fb_fix_screeninfo *fix = &ACCESS_FBINFO(fbcon).fix; - DBG("matroxfb_get_fix") + DBG(__FUNCTION__) strcpy(fix->id,"MATROX"); - fix->smem_start = ACCESS_FBINFO(video.base) + ACCESS_FBINFO(curr.ydstorg.bytes); - fix->smem_len = ACCESS_FBINFO(video.len_usable) - ACCESS_FBINFO(curr.ydstorg.bytes); fix->xpanstep = 8; /* 8 for 8bpp, 4 for 16bpp, 2 for 32bpp */ fix->ypanstep = 1; fix->ywrapstep = 0; @@ -667,91 +687,66 @@ fix->accel = ACCESS_FBINFO(devflags.accelerator); } -static int matroxfb_set_var(struct fb_var_screeninfo *var, int con, - struct fb_info *info) +static void matroxfb_update_fix(WPMINFO2) +{ + struct fb_fix_screeninfo *fix = &ACCESS_FBINFO(fbcon).fix; + DBG(__FUNCTION__) + + fix->smem_start = ACCESS_FBINFO(video.base) + ACCESS_FBINFO(curr.ydstorg.bytes); + fix->smem_len = ACCESS_FBINFO(video.len_usable) - ACCESS_FBINFO(curr.ydstorg.bytes); +} + +static int matroxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) +{ + int err; + int visual; + int cmap_len; + unsigned int ydstorg; + MINFO_FROM_INFO(info); + + if (ACCESS_FBINFO(dead)) { + return -ENXIO; + } + if ((err = matroxfb_decode_var(PMINFO var, &visual, &cmap_len, &ydstorg)) != 0) + return err; + return 0; +} + +static int matroxfb_set_par(struct fb_info *info) { -#define minfo (container_of(info, struct matrox_fb_info, fbcon)) int err; int visual; int cmap_len; unsigned int ydstorg; - struct display* display; - int chgvar; + struct fb_var_screeninfo *var; + MINFO_FROM_INFO(info); - DBG("matroxfb_set_var") + DBG(__FUNCTION__) if (ACCESS_FBINFO(dead)) { return -ENXIO; } - if (con >= 0) - display = fb_display + con; - else - display = ACCESS_FBINFO(fbcon.disp); - if ((err = matroxfb_decode_var(PMINFO display, var, &visual, &cmap_len, &ydstorg)) != 0) + var = &info->var; + if ((err = matroxfb_decode_var(PMINFO var, &visual, &cmap_len, &ydstorg)) != 0) return err; - switch (var->activate & FB_ACTIVATE_MASK) { - case FB_ACTIVATE_TEST: return 0; - case FB_ACTIVATE_NXTOPEN: /* ?? */ - case FB_ACTIVATE_NOW: break; /* continue */ - default: return -EINVAL; /* unknown */ - } - if (con >= 0) { - chgvar = ((display->var.xres != var->xres) || - (display->var.yres != var->yres) || - (display->var.xres_virtual != var->xres_virtual) || - (display->var.yres_virtual != var->yres_virtual) || - (display->var.bits_per_pixel != var->bits_per_pixel) || - memcmp(&display->var.red, &var->red, sizeof(var->red)) || - memcmp(&display->var.green, &var->green, sizeof(var->green)) || - memcmp(&display->var.blue, &var->blue, sizeof(var->blue))); - } else { - chgvar = 0; - } - display->var = *var; - /* cmap */ ACCESS_FBINFO(fbcon.screen_base) = vaddr_va(ACCESS_FBINFO(video.vbase)) + ydstorg; - if (display == ACCESS_FBINFO(currcon_display)) { - ACCESS_FBINFO(fbcon).var = *var; - matroxfb_update_fix(PMINFO2); - ACCESS_FBINFO(fbcon).fix.visual = visual; - if (var->bits_per_pixel) { - ACCESS_FBINFO(fbcon).fix.type = FB_TYPE_PACKED_PIXELS; - ACCESS_FBINFO(fbcon).fix.type_aux = 0; - display->next_line = ACCESS_FBINFO(fbcon).fix.line_length = (var->xres_virtual * var->bits_per_pixel) >> 3; - } else { - ACCESS_FBINFO(fbcon).fix.type = FB_TYPE_TEXT; - ACCESS_FBINFO(fbcon).fix.type_aux = ACCESS_FBINFO(devflags.text_type_aux); - display->next_line = ACCESS_FBINFO(fbcon).fix.line_length = (var->xres_virtual / (fontwidth(display)?fontwidth(display):8)) * ACCESS_FBINFO(devflags.textstep); - } - } - display->can_soft_blank = 1; - display->inverse = ACCESS_FBINFO(devflags.inverse); - /* conp, fb_info, vrows, cursor_x, cursor_y, fgcol, bgcol */ - /* next_plane, fontdata, _font*, userfont */ - initMatrox(PMINFO display); /* dispsw */ - /* dispsw, scrollmode, yscroll */ - /* fgshift, bgshift, charmask */ - if (chgvar && info && info->changevar) - info->changevar(con); - if (con == ACCESS_FBINFO(fbcon.currcon)) { + matroxfb_update_fix(PMINFO2); + ACCESS_FBINFO(fbcon).fix.visual = visual; + ACCESS_FBINFO(fbcon).fix.type = FB_TYPE_PACKED_PIXELS; + ACCESS_FBINFO(fbcon).fix.type_aux = 0; + ACCESS_FBINFO(fbcon).fix.line_length = (var->xres_virtual * var->bits_per_pixel) >> 3; + { unsigned int pos; ACCESS_FBINFO(curr.cmap_len) = cmap_len; - if (ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT) { - /* textmode must be in first megabyte, so no ydstorg allowed */ - ACCESS_FBINFO(curr.ydstorg.bytes) = 0; - ACCESS_FBINFO(curr.ydstorg.chunks) = 0; - ACCESS_FBINFO(curr.ydstorg.pixels) = 0; - } else { - ydstorg += ACCESS_FBINFO(devflags.ydstorg); - ACCESS_FBINFO(curr.ydstorg.bytes) = ydstorg; - ACCESS_FBINFO(curr.ydstorg.chunks) = ydstorg >> (isInterleave(MINFO)?3:2); - if (var->bits_per_pixel == 4) - ACCESS_FBINFO(curr.ydstorg.pixels) = ydstorg; - else - ACCESS_FBINFO(curr.ydstorg.pixels) = (ydstorg * 8) / var->bits_per_pixel; - } + ydstorg += ACCESS_FBINFO(devflags.ydstorg); + ACCESS_FBINFO(curr.ydstorg.bytes) = ydstorg; + ACCESS_FBINFO(curr.ydstorg.chunks) = ydstorg >> (isInterleave(MINFO)?3:2); + if (var->bits_per_pixel == 4) + ACCESS_FBINFO(curr.ydstorg.pixels) = ydstorg; + else + ACCESS_FBINFO(curr.ydstorg.pixels) = (ydstorg * 8) / var->bits_per_pixel; ACCESS_FBINFO(curr.final_bppShift) = matroxfb_get_final_bppShift(PMINFO var->bits_per_pixel); if (visual == MX_VISUAL_PSEUDOCOLOR) { int i; @@ -783,9 +778,6 @@ hw = &ACCESS_FBINFO(hw); - del_timer_sync(&ACCESS_FBINFO(cursor.timer)); - ACCESS_FBINFO(cursor.state) = CM_ERASE; - down_read(&ACCESS_FBINFO(altout).lock); for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) { if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC1 && @@ -796,22 +788,16 @@ up_read(&ACCESS_FBINFO(altout).lock); ACCESS_FBINFO(crtc1).pixclock = mt.pixclock; ACCESS_FBINFO(crtc1).mnp = mt.mnp; - ACCESS_FBINFO(hw_switch->init(PMINFO &mt, display)); - if (ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT) { - if (fontheight(display)) - pos = var->yoffset / fontheight(display) * display->next_line / ACCESS_FBINFO(devflags.textstep) + var->xoffset / (fontwidth(display)?fontwidth(display):8); - else - pos = 0; - } else { - pos = (var->yoffset * var->xres_virtual + var->xoffset) * ACCESS_FBINFO(curr.final_bppShift) / 32; - pos += ACCESS_FBINFO(curr.ydstorg.chunks); - } + ACCESS_FBINFO(hw_switch->init(PMINFO &mt)); + pos = (var->yoffset * var->xres_virtual + var->xoffset) * ACCESS_FBINFO(curr.final_bppShift) / 32; + pos += ACCESS_FBINFO(curr.ydstorg.chunks); hw->CRTC[0x0D] = pos & 0xFF; hw->CRTC[0x0C] = (pos & 0xFF00) >> 8; hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40); hw->CRTCEXT[8] = pos >> 21; - ACCESS_FBINFO(hw_switch->restore(PMINFO display)); + ACCESS_FBINFO(hw_switch->restore(PMINFO2)); + update_crtc2(PMINFO pos); down_read(&ACCESS_FBINFO(altout).lock); for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) { if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC1 && @@ -819,7 +805,6 @@ ACCESS_FBINFO(outputs[out]).output->program(ACCESS_FBINFO(outputs[out]).data); } } - ACCESS_FBINFO(cursor.redraw) = 1; for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) { if (ACCESS_FBINFO(outputs[out]).src == MATROXFB_SRC_CRTC1 && ACCESS_FBINFO(outputs[out]).output->start) { @@ -828,94 +813,16 @@ } up_read(&ACCESS_FBINFO(altout).lock); matrox_cfbX_init(PMINFO2); - my_install_cmap(PMINFO2); } } return 0; -#undef minfo -} - -static int matrox_getcolreg(unsigned regno, unsigned *red, unsigned *green, - unsigned *blue, unsigned *transp, - struct fb_info *info) -{ - - DBG("matrox_getcolreg") - -#define minfo (container_of(info, struct matrox_fb_info, fbcon)) - /* - * Read a single color register and split it into colors/transparent. - * Return != 0 for invalid regno. - */ - - if (regno >= ACCESS_FBINFO(curr.cmap_len)) - return 1; - - *red = ACCESS_FBINFO(palette[regno].red); - *green = ACCESS_FBINFO(palette[regno].green); - *blue = ACCESS_FBINFO(palette[regno].blue); - *transp = ACCESS_FBINFO(palette[regno].transp); - return 0; -#undef minfo -} - -static int matroxfb_get_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info) -{ -#define minfo (container_of(info, struct matrox_fb_info, fbcon)) - struct display* dsp = (con < 0) ? ACCESS_FBINFO(fbcon.disp) - : fb_display + con; - - DBG("matroxfb_get_cmap") - - if (ACCESS_FBINFO(dead)) { - return -ENXIO; - } - - if (con == ACCESS_FBINFO(fbcon.currcon)) /* current console? */ - return fb_get_cmap(cmap, kspc, matrox_getcolreg, info); - else if (dsp->cmap.len) /* non default colormap? */ - fb_copy_cmap(&dsp->cmap, cmap, kspc ? 0 : 2); - else - fb_copy_cmap(fb_default_cmap(matroxfb_get_cmap_len(&dsp->var)), - cmap, kspc ? 0 : 2); - return 0; -#undef minfo -} - -static int matroxfb_set_cmap(struct fb_cmap *cmap, int kspc, int con, - struct fb_info *info) -{ - unsigned int cmap_len; - struct display* dsp = (con < 0) ? info->disp : (fb_display + con); -#define minfo (container_of(info, struct matrox_fb_info, fbcon)) - - DBG("matroxfb_set_cmap") - - if (ACCESS_FBINFO(dead)) { - return -ENXIO; - } - - cmap_len = matroxfb_get_cmap_len(&dsp->var); - if (dsp->cmap.len != cmap_len) { - int err; - - err = fb_alloc_cmap(&dsp->cmap, cmap_len, 0); - if (err) - return err; - } - if (con == ACCESS_FBINFO(fbcon.currcon)) { /* current console? */ - return fb_set_cmap(cmap, kspc, info); - } else - fb_copy_cmap(cmap, &dsp->cmap, kspc ? 0 : 1); - return 0; -#undef minfo } -static int matroxfb_get_vblank(CPMINFO struct fb_vblank *vblank) +static int matroxfb_get_vblank(WPMINFO struct fb_vblank *vblank) { unsigned int sts1; + matroxfb_enable_irq(PMINFO 0); memset(vblank, 0, sizeof(*vblank)); vblank->flags = FB_VBLANK_HAVE_VCOUNT | FB_VBLANK_HAVE_VSYNC | FB_VBLANK_HAVE_VBLANK | FB_VBLANK_HAVE_HBLANK; @@ -930,8 +837,12 @@ vblank->flags |= FB_VBLANK_VSYNCING; if (vblank->vcount >= ACCESS_FBINFO(fbcon).var.yres) vblank->flags |= FB_VBLANK_VBLANKING; - vblank->hcount = 0; - vblank->count = 0; + if (test_bit(0, &ACCESS_FBINFO(irq_flags))) { + vblank->flags |= FB_VBLANK_HAVE_COUNT; + /* Only one writer, aligned int value... + it should work without lock and without atomic_t */ + vblank->count = ACCESS_FBINFO(crtc1).vsync.cnt; + } return 0; } @@ -940,11 +851,12 @@ }; static int matroxfb_ioctl(struct inode *inode, struct file *file, - unsigned int cmd, unsigned long arg, int con, + unsigned int cmd, unsigned long arg, struct fb_info *info) { -#define minfo (container_of(info, struct matrox_fb_info, fbcon)) - DBG("matroxfb_ioctl") + MINFO_FROM_INFO(info); + + DBG(__FUNCTION__) if (ACCESS_FBINFO(dead)) { return -ENXIO; @@ -963,6 +875,15 @@ return -EFAULT; return 0; } + case FBIO_WAITFORVSYNC: + { + u_int32_t crt; + + if (get_user(crt, (u_int32_t *)arg)) + return -EFAULT; + + return matroxfb_wait_for_sync(PMINFO crt); + } case MATROXFB_SET_OUTPUT_MODE: { struct matroxioc_output_mode mom; @@ -997,7 +918,7 @@ return val; switch (ACCESS_FBINFO(outputs[mom.output]).src) { case MATROXFB_SRC_CRTC1: - matroxfb_switch(ACCESS_FBINFO(fbcon.currcon), info); + matroxfb_set_par(info); break; case MATROXFB_SRC_CRTC2: { @@ -1006,7 +927,7 @@ down_read(&ACCESS_FBINFO(crtc2.lock)); crtc2 = ACCESS_FBINFO(crtc2.info); if (crtc2) - crtc2->fbcon.switch_con(crtc2->fbcon.currcon, &crtc2->fbcon); + crtc2->fbcon.fbops->fb_set_par(&crtc2->fbcon); up_read(&ACCESS_FBINFO(crtc2.lock)); } break; @@ -1086,7 +1007,7 @@ } if (!changes) return 0; - matroxfb_switch(ACCESS_FBINFO(fbcon.currcon), info); + matroxfb_set_par(info); return 0; } case MATROXFB_GET_OUTPUT_CONNECTION: @@ -1142,21 +1063,98 @@ return -EFAULT; return 0; } + case VIDIOC_QUERYCAP: + { + struct v4l2_capability r; + + memset(&r, 0, sizeof(r)); + strcpy(r.driver, "matroxfb"); + strcpy(r.card, "Matrox"); + sprintf(r.bus_info, "PCI:%s", ACCESS_FBINFO(pcidev)->slot_name); + r.version = KERNEL_VERSION(1,0,0); + r.capabilities = V4L2_CAP_VIDEO_OUTPUT; + if (copy_to_user((void*)arg, &r, sizeof(r))) + return -EFAULT; + return 0; + + } + case VIDIOC_QUERYCTRL: + { + struct v4l2_queryctrl qctrl; + int err; + + if (copy_from_user(&qctrl, (struct v4l2_queryctrl*)arg, sizeof(qctrl))) + return -EFAULT; + + down_read(&ACCESS_FBINFO(altout).lock); + if (!ACCESS_FBINFO(outputs[1]).output) { + err = -ENXIO; + } else if (ACCESS_FBINFO(outputs[1]).output->getqueryctrl) { + err = ACCESS_FBINFO(outputs[1]).output->getqueryctrl(ACCESS_FBINFO(outputs[1]).data, &qctrl); + } else { + err = -EINVAL; + } + up_read(&ACCESS_FBINFO(altout).lock); + if (err >= 0 && + copy_to_user((struct v4l2_queryctrl*)arg, &qctrl, sizeof(qctrl))) + return -EFAULT; + return err; + } + case VIDIOC_G_CTRL: + { + struct v4l2_control ctrl; + int err; + + if (copy_from_user(&ctrl, (struct v4l2_control*)arg, sizeof(ctrl))) + return -EFAULT; + + down_read(&ACCESS_FBINFO(altout).lock); + if (!ACCESS_FBINFO(outputs[1]).output) { + err = -ENXIO; + } else if (ACCESS_FBINFO(outputs[1]).output->getctrl) { + err = ACCESS_FBINFO(outputs[1]).output->getctrl(ACCESS_FBINFO(outputs[1]).data, &ctrl); + } else { + err = -EINVAL; + } + up_read(&ACCESS_FBINFO(altout).lock); + if (err >= 0 && + copy_to_user((struct v4l2_control*)arg, &ctrl, sizeof(ctrl))) + return -EFAULT; + return err; + } + case VIDIOC_S_CTRL: + { + struct v4l2_control ctrl; + int err; + + if (copy_from_user(&ctrl, (struct v4l2_control*)arg, sizeof(ctrl))) + return -EFAULT; + + down_read(&ACCESS_FBINFO(altout).lock); + if (!ACCESS_FBINFO(outputs[1]).output) { + err = -ENXIO; + } else if (ACCESS_FBINFO(outputs[1]).output->setctrl) { + err = ACCESS_FBINFO(outputs[1]).output->setctrl(ACCESS_FBINFO(outputs[1]).data, &ctrl); + } else { + err = -EINVAL; + } + up_read(&ACCESS_FBINFO(altout).lock); + return err; + } } return -ENOTTY; -#undef minfo } /* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */ static int matroxfb_blank(int blank, struct fb_info *info) { -#define minfo (container_of(info, struct matrox_fb_info, fbcon)) int seq; int crtc; CRITFLAGS + MINFO_FROM_INFO(info); - DBG("matroxfb_blank") + DBG(__FUNCTION__) if (ACCESS_FBINFO(dead)) return 1; @@ -1178,72 +1176,24 @@ CRITEND return 0; -#undef minfo } static struct fb_ops matroxfb_ops = { .owner = THIS_MODULE, .fb_open = matroxfb_open, .fb_release = matroxfb_release, - .fb_set_var = matroxfb_set_var, - .fb_get_cmap = matroxfb_get_cmap, - .fb_set_cmap = matroxfb_set_cmap, + .fb_check_var = matroxfb_check_var, + .fb_set_par = matroxfb_set_par, .fb_setcolreg = matroxfb_setcolreg, .fb_pan_display =matroxfb_pan_display, .fb_blank = matroxfb_blank, .fb_ioctl = matroxfb_ioctl, +/* .fb_fillrect = <set by matrox_cfbX_init>, */ +/* .fb_copyarea = <set by matrox_cfbX_init>, */ +/* .fb_imageblit = <set by matrox_cfbX_init>, */ +/* .fb_cursor = <set by matrox_cfbX_init>, */ }; -int matroxfb_switch(int con, struct fb_info *info) -{ -#define minfo (container_of(info, struct matrox_fb_info, fbcon)) - struct fb_cmap* cmap; - struct display *p; - - DBG("matroxfb_switch"); - - if (ACCESS_FBINFO(fbcon.currcon) >= 0) { - /* Do we have to save the colormap? */ - cmap = &(ACCESS_FBINFO(currcon_display)->cmap); - dprintk(KERN_DEBUG "switch1: con = %d, cmap.len = %d\n", ACCESS_FBINFO(fbcon.currcon), cmap->len); - - if (cmap->len) { - dprintk(KERN_DEBUG "switch1a: %p %p %p %p\n", cmap->red, cmap->green, cmap->blue, cmap->transp); - fb_get_cmap(cmap, 1, matrox_getcolreg, info); -#ifdef DEBUG - if (cmap->red) { - dprintk(KERN_DEBUG "switch1r: %X\n", cmap->red[0]); - } -#endif - } - } - ACCESS_FBINFO(fbcon.currcon) = con; - if (con < 0) - p = ACCESS_FBINFO(fbcon.disp); - else - p = fb_display + con; - ACCESS_FBINFO(currcon_display) = p; - p->var.activate = FB_ACTIVATE_NOW; -#ifdef DEBUG - cmap = &p->cmap; - dprintk(KERN_DEBUG "switch2: con = %d, cmap.len = %d\n", con, cmap->len); - dprintk(KERN_DEBUG "switch2a: %p %p %p %p\n", cmap->red, cmap->green, cmap->blue, cmap->transp); - if (p->cmap.red) { - dprintk(KERN_DEBUG "switch2r: %X\n", cmap->red[0]); - } -#endif - matroxfb_set_var(&p->var, con, info); -#ifdef DEBUG - dprintk(KERN_DEBUG "switch3: con = %d, cmap.len = %d\n", con, cmap->len); - dprintk(KERN_DEBUG "switch3a: %p %p %p %p\n", cmap->red, cmap->green, cmap->blue, cmap->transp); - if (p->cmap.red) { - dprintk(KERN_DEBUG "switch3r: %X\n", cmap->red[0]); - } -#endif - return 0; -#undef minfo -} - #define RSDepth(X) (((X) >> 8) & 0x0F) #define RS8bpp 0x1 #define RS15bpp 0x2 @@ -1278,14 +1228,11 @@ static int nobios; /* "matrox:nobios" */ static int noinit = 1; /* "matrox:init" */ static int inverse; /* "matrox:inverse" */ -static int hwcursor = 1; /* "matrox:nohwcursor" */ -static int blink = 1; /* "matrox:noblink" */ static int sgram; /* "matrox:sgram" */ #ifdef CONFIG_MTRR static int mtrr = 1; /* "matrox:nomtrr" */ #endif static int grayscale; /* "matrox:grayscale" */ -static unsigned int fastfont; /* "matrox:fastfont:xxxxx" */ static int dev = -1; /* "matrox:dev:xxxxx" */ static unsigned int vesa = ~0; /* "matrox:vesa:xxxxx" */ static int depth = -1; /* "matrox:depth:xxxxx" */ @@ -1305,7 +1252,6 @@ static int dfp; /* "matrox:dfp */ static int dfp_type = -1; /* "matrox:dfp:xxx */ static int memtype = -1; /* "matrox:memtype:xxx" */ -static char fontname[64]; /* "matrox:font:xxxxx" */ #ifndef MODULE static char videomode[64]; /* "matrox:mode:xxxxx" or "matrox:xxxxx" */ @@ -1319,7 +1265,7 @@ unsigned char bytes[32]; unsigned char* tmp; - DBG("matroxfb_getmemory") + DBG(__FUNCTION__) vm = ACCESS_FBINFO(video.vbase); maxSize &= ~0x1FFFFF; /* must be X*2MB (really it must be 2 or X*4MB) */ @@ -1571,13 +1517,13 @@ static int hotplug = 0; -static int initMatrox2(WPMINFO struct display* d, struct board* b){ +static int initMatrox2(WPMINFO struct board* b){ unsigned long ctrlptr_phys = 0; unsigned long video_base_phys = 0; unsigned int memsize; int err; - DBG("initMatrox2") + DBG(__FUNCTION__) /* set default values... */ vesafb_defined.accel_flags = FB_ACCELF_TEXT; @@ -1713,7 +1659,6 @@ ACCESS_FBINFO(devflags.ydstorg) = 0; ACCESS_FBINFO(fbcon.currcon) = -1; - ACCESS_FBINFO(currcon_display) = d; ACCESS_FBINFO(video.base) = video_base_phys; ACCESS_FBINFO(video.len_usable) = ACCESS_FBINFO(video.len); if (ACCESS_FBINFO(video.len_usable) > b->base->maxdisplayable) @@ -1738,9 +1683,6 @@ ACCESS_FBINFO(fbcon.monspecs.dpms) = 0; /* TBD */ /* static settings */ - if ((depth == RSText8) && (!*ACCESS_FBINFO(fbcon.fontname))) { - strcpy(ACCESS_FBINFO(fbcon.fontname), "VGA8x8"); - } vesafb_defined.red = colors[depth-1].red; vesafb_defined.green = colors[depth-1].green; vesafb_defined.blue = colors[depth-1].blue; @@ -1750,12 +1692,9 @@ if (noaccel) vesafb_defined.accel_flags &= ~FB_ACCELF_TEXT; - strcpy(ACCESS_FBINFO(fbcon.modename), "MATROX VGA"); - ACCESS_FBINFO(fbcon.changevar) = NULL; - ACCESS_FBINFO(fbcon.fbops) = &matroxfb_ops; - ACCESS_FBINFO(fbcon.disp) = d; - ACCESS_FBINFO(fbcon.switch_con) = &matroxfb_switch; - ACCESS_FBINFO(fbcon.updatevar) = &matroxfb_updatevar; + ACCESS_FBINFO(fbops) = matroxfb_ops; + ACCESS_FBINFO(fbcon.fbops) = &ACCESS_FBINFO(fbops); + ACCESS_FBINFO(fbcon.pseudo_palette) = ACCESS_FBINFO(cmap); /* after __init time we are like module... no logo */ ACCESS_FBINFO(fbcon.flags) = hotplug ? FBINFO_FLAG_MODULE : FBINFO_FLAG_DEFAULT; ACCESS_FBINFO(video.len_usable) &= PAGE_MASK; @@ -1824,7 +1763,7 @@ } /* FIXME: Where to move this?! */ -#if defined(CONFIG_ALL_PPC) +#if defined(CONFIG_PPC_PMAC) #ifndef MODULE if (_machine == _MACH_Pmac) { struct fb_var_screeninfo var; @@ -1844,7 +1783,7 @@ } } #endif /* !MODULE */ -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PMAC */ vesafb_defined.xres_virtual = vesafb_defined.xres; if (nopan) { vesafb_defined.yres_virtual = vesafb_defined.yres; @@ -1852,11 +1791,8 @@ vesafb_defined.yres_virtual = 65536; /* large enough to be INF, but small enough to yres_virtual * xres_virtual < 2^32 */ } + matroxfb_init_fix(PMINFO2); err = -EINVAL; - if (matroxfb_set_var(&vesafb_defined, -2, &ACCESS_FBINFO(fbcon))) { - printk(KERN_ERR "matroxfb: cannot set required parameters\n"); - goto failVideoIO; - } printk(KERN_INFO "matroxfb: %dx%dx%dbpp (virtual: %dx%d)\n", vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel, @@ -1871,13 +1807,13 @@ goto failVideoIO; } printk("fb%d: %s frame buffer device\n", - ACCESS_FBINFO(fbcon.node), ACCESS_FBINFO(fbcon.modename)); + ACCESS_FBINFO(fbcon.node), ACCESS_FBINFO(fbcon.fix.id)); if (ACCESS_FBINFO(fbcon.currcon) < 0) { /* there is no console on this fb... but we have to initialize hardware * until someone tells me what is proper thing to do */ printk(KERN_INFO "fb%d: initializing hardware\n", ACCESS_FBINFO(fbcon.node)); - matroxfb_set_var(&vesafb_defined, -1, &ACCESS_FBINFO(fbcon)); + fb_set_var(&ACCESS_FBINFO(fbcon), &vesafb_defined); } return 0; failVideoIO:; @@ -1977,14 +1913,12 @@ u_int16_t svid; u_int16_t sid; struct matrox_fb_info* minfo; - struct display* d; int err; u_int32_t cmd; #ifndef CONFIG_FB_MATROX_MULTIHEAD static int registered = 0; - static struct display global_disp; #endif - DBG("matroxfb_probe") + DBG(__FUNCTION__) pci_read_config_byte(pdev, PCI_REVISION_ID, &rev); svid = pdev->subsystem_vendor; @@ -2012,28 +1946,20 @@ minfo = (struct matrox_fb_info*)kmalloc(sizeof(*minfo), GFP_KERNEL); if (!minfo) return -1; - d = (struct display*)kmalloc(sizeof(*d), GFP_KERNEL); - if (!d) { - kfree(minfo); - return -1; - } #else if (registered) /* singlehead driver... */ return -1; minfo = &matroxfb_global_mxinfo; - d = &global_disp; #endif memset(MINFO, 0, sizeof(*MINFO)); - memset(d, 0, sizeof(*d)); ACCESS_FBINFO(pcidev) = pdev; ACCESS_FBINFO(dead) = 0; ACCESS_FBINFO(usecount) = 0; + ACCESS_FBINFO(userusecount) = 0; + pci_set_drvdata(pdev, MINFO); - /* CMDLINE */ - memcpy(ACCESS_FBINFO(fbcon.fontname), fontname, sizeof(ACCESS_FBINFO(fbcon.fontname))); /* DEVFLAGS */ - ACCESS_FBINFO(devflags.inverse) = inverse; ACCESS_FBINFO(devflags.memtype) = memtype; if (memtype != -1) noinit = 0; @@ -2054,22 +1980,18 @@ ACCESS_FBINFO(devflags.nopciretry) = no_pci_retry; ACCESS_FBINFO(devflags.mga_24bpp_fix) = inv24; ACCESS_FBINFO(devflags.precise_width) = option_precise_width; - ACCESS_FBINFO(devflags.hwcursor) = hwcursor; - ACCESS_FBINFO(devflags.blink) = blink; ACCESS_FBINFO(devflags.sgram) = sgram; ACCESS_FBINFO(capable.cross4MB) = cross4MB; - ACCESS_FBINFO(fastfont.size) = fastfont; - - ACCESS_FBINFO(cursor.state) = CM_ERASE; - init_timer (&ACCESS_FBINFO(cursor.timer)); - ACCESS_FBINFO(cursor.timer.data) = (unsigned long)MINFO; spin_lock_init(&ACCESS_FBINFO(lock.DAC)); spin_lock_init(&ACCESS_FBINFO(lock.accel)); init_rwsem(&ACCESS_FBINFO(crtc2.lock)); init_rwsem(&ACCESS_FBINFO(altout.lock)); + ACCESS_FBINFO(irq_flags) = 0; + init_waitqueue_head(&ACCESS_FBINFO(crtc1.vsync.wait)); + init_waitqueue_head(&ACCESS_FBINFO(crtc2.vsync.wait)); - err = initMatrox2(PMINFO d, b); + err = initMatrox2(PMINFO b); if (!err) { #ifndef CONFIG_FB_MATROX_MULTIHEAD registered = 1; @@ -2078,7 +2000,6 @@ return 0; } #ifdef CONFIG_FB_MATROX_MULTIHEAD - kfree(d); kfree(minfo); #endif return -1; @@ -2172,7 +2093,6 @@ #define RSCreate(X,Y) ((X) | ((Y) << 8)) static struct { unsigned int vesa; unsigned int info; } *RSptr, vesamap[] __initdata = { /* default must be first */ -#ifdef FBCON_HAS_CFB8 { ~0, RSCreate(RSNoxNo, RS8bpp ) }, { 0x101, RSCreate(RS640x480, RS8bpp ) }, { 0x100, RSCreate(RS640x400, RS8bpp ) }, @@ -2184,9 +2104,6 @@ { 0x107, RSCreate(RS1280x1024, RS8bpp ) }, { 0x198, RSCreate(RS1408x1056, RS8bpp ) }, { 0x11C, RSCreate(RS1600x1200, RS8bpp ) }, -#endif -#ifdef FBCON_HAS_CFB16 - { ~0, RSCreate(RSNoxNo, RS15bpp) }, { 0x110, RSCreate(RS640x480, RS15bpp) }, { 0x181, RSCreate(RS768x576, RS15bpp) }, { 0x113, RSCreate(RS800x600, RS15bpp) }, @@ -2205,9 +2122,6 @@ { 0x11A, RSCreate(RS1280x1024, RS16bpp) }, { 0x19A, RSCreate(RS1408x1056, RS16bpp) }, { 0x11E, RSCreate(RS1600x1200, RS16bpp) }, -#endif -#ifdef FBCON_HAS_CFB24 - { ~0, RSCreate(RSNoxNo, RS24bpp) }, { 0x1B2, RSCreate(RS640x480, RS24bpp) }, { 0x184, RSCreate(RS768x576, RS24bpp) }, { 0x1B5, RSCreate(RS800x600, RS24bpp) }, @@ -2217,9 +2131,6 @@ { 0x1BB, RSCreate(RS1280x1024, RS24bpp) }, { 0x19C, RSCreate(RS1408x1056, RS24bpp) }, { 0x1BF, RSCreate(RS1600x1200, RS24bpp) }, -#endif -#ifdef FBCON_HAS_CFB32 - { ~0, RSCreate(RSNoxNo, RS32bpp) }, { 0x112, RSCreate(RS640x480, RS32bpp) }, { 0x183, RSCreate(RS768x576, RS32bpp) }, { 0x115, RSCreate(RS800x600, RS32bpp) }, @@ -2229,27 +2140,11 @@ { 0x11B, RSCreate(RS1280x1024, RS32bpp) }, { 0x19B, RSCreate(RS1408x1056, RS32bpp) }, { 0x11F, RSCreate(RS1600x1200, RS32bpp) }, -#endif -#ifdef FBCON_HAS_VGATEXT - { ~0, RSCreate(RSNoxNo, RSText ) }, - { 0x002, RSCreate(RS640x400, RSText ) }, /* 80x25 */ - { 0x003, RSCreate(RS640x400, RSText ) }, /* 80x25 */ - { 0x007, RSCreate(RS640x400, RSText ) }, /* 80x25 */ - { 0x1C0, RSCreate(RS640x400, RSText8) }, /* 80x50 */ - { 0x108, RSCreate(RS640x480, RSText8) }, /* 80x60 */ - { 0x109, RSCreate(RS1056x400, RSText ) }, /* 132x25 */ - { 0x10A, RSCreate(RS1056x344, RSText8) }, /* 132x43 */ - { 0x10B, RSCreate(RS1056x400, RSText8) }, /* 132x50 */ - { 0x10C, RSCreate(RS1056x480, RSText8) }, /* 132x60 */ -#endif -#ifdef FBCON_HAS_CFB4 - { ~0, RSCreate(RSNoxNo, RS4bpp ) }, { 0x010, RSCreate(RS640x350, RS4bpp ) }, { 0x012, RSCreate(RS640x480, RS4bpp ) }, { 0x102, RSCreate(RS800x600, RS4bpp ) }, { 0x104, RSCreate(RS1024x768, RS4bpp ) }, { 0x106, RSCreate(RS1280x1024, RS4bpp ) }, -#endif { 0, 0 }}; static void __init matroxfb_init_params(void) { @@ -2315,9 +2210,7 @@ int __init matroxfb_setup(char *options) { char *this_opt; - DBG("matroxfb_setup") - - fontname[0] = '\0'; + DBG(__FUNCTION__) if (!options || !*options) return 0; @@ -2363,8 +2256,6 @@ sync = simple_strtoul(this_opt+5, NULL, 0); else if (!strncmp(this_opt, "vesa:", 5)) vesa = simple_strtoul(this_opt+5, NULL, 0); - else if (!strncmp(this_opt, "font:", 5)) - strlcpy(fontname, this_opt+5, sizeof(fontname)); else if (!strncmp(this_opt, "maxclk:", 7)) maxclk = simple_strtoul(this_opt+7, NULL, 0); else if (!strncmp(this_opt, "fh:", 3)) @@ -2379,7 +2270,7 @@ dfp_type = simple_strtoul(this_opt+4, NULL, 0); dfp = 1; } -#ifdef CONFIG_PPC +#ifdef CONFIG_PPC_PMAC else if (!strncmp(this_opt, "vmode:", 6)) { unsigned int vmode = simple_strtoul(this_opt+6, NULL, 0); if (vmode > 0 && vmode <= VMODE_MAX) @@ -2402,10 +2293,6 @@ } } #endif - else if (!strncmp(this_opt, "fastfont:", 9)) - fastfont = simple_strtoul(this_opt+9, NULL, 0); - else if (!strcmp(this_opt, "nofastfont")) /* fastfont:N and nofastfont (nofastfont = fastfont:0) */ - fastfont = 0; else if (!strcmp(this_opt, "disabled")) /* nodisabled does not exist */ disabled = 1; else if (!strcmp(this_opt, "enabled")) /* noenabled does not exist */ @@ -2445,10 +2332,6 @@ inv24 = value; else if (!strcmp(this_opt, "cross4MB")) cross4MB = value; - else if (!strcmp(this_opt, "hwcursor")) - hwcursor = value; - else if (!strcmp(this_opt, "blink")) - blink = value; else if (!strcmp(this_opt, "grayscale")) grayscale = value; else if (!strcmp(this_opt, "dfp")) @@ -2465,7 +2348,7 @@ int __init matroxfb_init(void) { - DBG("matroxfb_init") + DBG(__FUNCTION__) if (disabled) return -ENXIO; @@ -2550,12 +2433,6 @@ MODULE_PARM(fv, "i"); MODULE_PARM_DESC(fv, "Startup vertical frequency, 0-INF Hz\n" "You should specify \"fv:max_monitor_vsync,fh:max_monitor_hsync,maxclk:max_monitor_dotclock\"\n"); -MODULE_PARM(hwcursor, "i"); -MODULE_PARM_DESC(hwcursor, "Enables hardware cursor (0 or 1) (default=0)"); -MODULE_PARM(blink, "i"); -MODULE_PARM_DESC(blink, "Enables hardware cursor blinking (0 or 1) (default=1)"); -MODULE_PARM(fastfont, "i"); -MODULE_PARM_DESC(fastfont, "Specifies, how much memory should be used for font data (0, 1024-65536 are reasonable) (default=0)"); MODULE_PARM(grayscale, "i"); MODULE_PARM_DESC(grayscale, "Sets display into grayscale. Works perfectly with paletized videomode (4, 8bpp), some limitations apply to 16, 24 and 32bpp videomodes (default=nograyscale)"); MODULE_PARM(cross4MB, "i"); @@ -2564,7 +2441,7 @@ MODULE_PARM_DESC(dfp, "Specifies whether to use digital flat panel interface of G200/G400 (0 or 1) (default=0)"); MODULE_PARM(dfp_type, "i"); MODULE_PARM_DESC(dfp_type, "Specifies DFP interface type (0 to 255) (default=read from hardware)"); -#ifdef CONFIG_PPC +#ifdef CONFIG_PPC_PMAC MODULE_PARM(vmode, "i"); MODULE_PARM_DESC(vmode, "Specify the vmode mode number that should be used (640x480 default)"); MODULE_PARM(cmode, "i"); @@ -2573,7 +2450,7 @@ int __init init_module(void){ - DBG("init_module") + DBG(__FUNCTION__) if (disabled) return -ENXIO; @@ -2605,7 +2482,7 @@ module_exit(matrox_done); EXPORT_SYMBOL(matroxfb_register_driver); EXPORT_SYMBOL(matroxfb_unregister_driver); -EXPORT_SYMBOL(matroxfb_switch); +EXPORT_SYMBOL(matroxfb_wait_for_sync); /* * Overrides for Emacs so that we follow Linus's tabbing style. @@ -2614,3 +2491,4 @@ * c-basic-offset: 8 * End: */ + diff -Nru a/drivers/video/matrox/matroxfb_base.h b/drivers/video/matrox/matroxfb_base.h --- a/drivers/video/matrox/matroxfb_base.h Mon Jun 9 23:16:12 2003 +++ b/drivers/video/matrox/matroxfb_base.h Mon Jun 9 23:16:12 2003 @@ -42,6 +42,7 @@ #include <linux/timer.h> #include <linux/pci.h> #include <linux/spinlock.h> +#include <linux/kd.h> #include <asm/io.h> #include <asm/unaligned.h> @@ -49,14 +50,9 @@ #include <asm/mtrr.h> #endif -#include <video/fbcon.h> -#include <video/fbcon-cfb4.h> -#include <video/fbcon-cfb8.h> -#include <video/fbcon-cfb16.h> -#include <video/fbcon-cfb24.h> -#include <video/fbcon-cfb32.h> +#include "../console/fbcon.h" -#if defined(CONFIG_PPC) +#if defined(CONFIG_PPC_PMAC) #include <asm/prom.h> #include <asm/pci-bridge.h> #include <video/macmodes.h> @@ -65,8 +61,6 @@ /* always compile support for 32MB... It cost almost nothing */ #define CONFIG_FB_MATROX_32MB -#define FBCON_HAS_VGATEXT - #ifdef MATROXFB_DEBUG #define DEBUG @@ -338,8 +332,6 @@ unsigned int pixels; unsigned int chunks; } ydstorg; - void (*putc)(u_int32_t, u_int32_t, struct display*, int, int, int); - void (*putcs)(u_int32_t, u_int32_t, struct display*, const unsigned short*, int, int, int); }; struct matrox_fb_info; @@ -347,7 +339,6 @@ struct matrox_DAC1064_features { u_int8_t xvrefctrl; u_int8_t xmiscctrl; - unsigned int cursorimage; }; struct matrox_accel_features { @@ -398,12 +389,21 @@ u_int32_t m_opmode; }; +struct v4l2_queryctrl; +struct v4l2_control; + struct matrox_altout { const char *name; int (*compute)(void* altout_dev, struct my_timming* input); int (*program)(void* altout_dev); int (*start)(void* altout_dev); int (*verifymode)(void* altout_dev, u_int32_t mode); + int (*getqueryctrl)(void* altout_dev, + struct v4l2_queryctrl* ctrl); + int (*getctrl)(void* altout_dev, + struct v4l2_control* ctrl); + int (*setctrl)(void* altout_dev, + struct v4l2_control* ctrl); }; #define MATROXFB_SRC_NONE 0 @@ -424,10 +424,17 @@ } output; }; +extern struct display fb_display[]; + struct matrox_switch; struct matroxfb_driver; struct matroxfb_dh_fb_info; +struct matrox_vsync { + wait_queue_head_t wait; + unsigned int cnt; +}; + struct matrox_fb_info { struct fb_info fbcon; @@ -436,6 +443,9 @@ int dead; unsigned int usecount; + unsigned int userusecount; + unsigned long irq_flags; + struct matroxfb_par curr; struct matrox_hw_state hw; @@ -444,17 +454,23 @@ struct pci_dev* pcidev; struct { + struct matrox_vsync vsync; unsigned int pixclock; int mnp; } crtc1; struct { + struct matrox_vsync vsync; unsigned int pixclock; int mnp; struct matroxfb_dh_fb_info* info; struct rw_semaphore lock; } crtc2; struct { - struct rw_semaphore lock; + struct rw_semaphore lock; + struct { + int brightness, contrast, saturation, hue, gamma; + int testout, deflicker; + } tvo_params; } altout; #define MATROXFB_MAX_OUTPUTS 3 struct { @@ -486,7 +502,6 @@ unsigned int max_pixel_clock; struct matrox_switch* hw_switch; - struct display* currcon_display; struct { struct matrox_pll_features pll; @@ -511,11 +526,6 @@ int plnwt; int srcorg; } capable; - struct { - unsigned int size; - unsigned int mgabase; - vaddr_t vbase; - } fastfont; #ifdef CONFIG_MTRR struct { int vram; @@ -529,9 +539,6 @@ int nobios; int nopciretry; int noinit; - int inverse; - int hwcursor; - int blink; int sgram; #ifdef CONFIG_FB_MATROX_32MB int support32MB; @@ -555,18 +562,7 @@ int dualhead; unsigned int fbResource; } devflags; - struct display_switch dispsw; - struct { - int x; - int y; - unsigned int w; - unsigned int u; - unsigned int d; - unsigned int type; - int state; - int redraw; - struct timer_list timer; - } cursor; + struct fb_ops fbops; struct matrox_bios bios; struct { struct matrox_pll_limits pixel; @@ -600,22 +596,11 @@ } memory; } values; struct { unsigned red, green, blue, transp; } palette[256]; -/* These ifdefs must be last! They differ for module & non-module compiles */ -#if defined(FBCON_HAS_CFB16) || defined(FBCON_HAS_CFB24) || defined(FBCON_HAS_CFB32) - union { -#ifdef FBCON_HAS_CFB16 - u_int16_t cfb16[16]; -#endif -#ifdef FBCON_HAS_CFB24 - u_int32_t cfb24[16]; -#endif -#ifdef FBCON_HAS_CFB32 - u_int32_t cfb32[16]; -#endif - } cmap; -#endif + u_int32_t cmap[17]; }; +#define info2minfo(info) container_of(info, struct matrox_fb_info, fbcon) + #ifdef CONFIG_FB_MATROX_MULTIHEAD #define ACCESS_FBINFO2(info, x) (info->x) #define ACCESS_FBINFO(x) ACCESS_FBINFO2(minfo,x) @@ -629,14 +614,7 @@ #define PMINFO2 minfo #define PMINFO PMINFO2 , -static inline struct matrox_fb_info* mxinfo(const struct display* p) { - return container_of(p->fb_info, struct matrox_fb_info, fbcon); -} - -#define PMXINFO(p) mxinfo(p), #define MINFO_FROM(x) struct matrox_fb_info* minfo = x -#define MINFO_FROM_DISP(x) MINFO_FROM(mxinfo(x)) - #else extern struct matrox_fb_info matroxfb_global_mxinfo; @@ -653,24 +631,17 @@ #define PMINFO2 #define PMINFO -#if 0 -static inline struct matrox_fb_info* mxinfo(const struct display* p) { - return &matroxfb_global_mxinfo; -} -#endif - -#define PMXINFO(p) #define MINFO_FROM(x) -#define MINFO_FROM_DISP(x) #endif +#define MINFO_FROM_INFO(x) MINFO_FROM(info2minfo(x)) + struct matrox_switch { int (*preinit)(WPMINFO2); void (*reset)(WPMINFO2); - int (*init)(WPMINFO struct my_timming*, struct display*); - void (*restore)(WPMINFO struct display*); - int (*selhwcursor)(WPMINFO2); + int (*init)(WPMINFO struct my_timming*); + void (*restore)(WPMINFO2); }; struct matroxfb_driver { @@ -746,7 +717,7 @@ #define M_FIFOSTATUS 0x1E10 #define M_STATUS 0x1E14 - +#define M_ICLEAR 0x1E18 #define M_IEN 0x1E1C #define M_VCOUNT 0x1E20 @@ -868,7 +839,8 @@ extern int matroxfb_DAC_in(CPMINFO int reg); extern struct list_head matroxfb_list; extern void matroxfb_var2my(struct fb_var_screeninfo* fvsi, struct my_timming* mt); -extern int matroxfb_switch(int con, struct fb_info *); +extern int matroxfb_wait_for_sync(WPMINFO u_int32_t crtc); +extern int matroxfb_enable_irq(WPMINFO int reenable); #ifdef MATROXFB_USE_SPINLOCKS #define CRITBEGIN spin_lock_irqsave(&ACCESS_FBINFO(lock.accel), critflags); diff -Nru a/drivers/video/matrox/matroxfb_crtc2.c b/drivers/video/matrox/matroxfb_crtc2.c --- a/drivers/video/matrox/matroxfb_crtc2.c Mon Jun 9 23:16:17 2003 +++ b/drivers/video/matrox/matroxfb_crtc2.c Mon Jun 9 23:16:17 2003 @@ -26,21 +26,9 @@ /* **************************************************** */ -static int matroxfb_dh_getcolreg(unsigned regno, unsigned *red, unsigned *green, - unsigned *blue, unsigned *transp, struct fb_info* info) { -#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon)) - if (regno >= 16) - return 1; - *red = m2info->palette[regno].red; - *blue = m2info->palette[regno].blue; - *green = m2info->palette[regno].green; - *transp = m2info->palette[regno].transp; - return 0; -#undef m2info -} - static int matroxfb_dh_setcolreg(unsigned regno, unsigned red, unsigned green, unsigned blue, unsigned transp, struct fb_info* info) { + u_int32_t col; #define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon)) if (regno >= 16) @@ -58,43 +46,23 @@ blue = CNVT_TOHW(blue, m2info->fbcon.var.blue.length); transp = CNVT_TOHW(transp, m2info->fbcon.var.transp.length); + col = (red << m2info->fbcon.var.red.offset) | + (green << m2info->fbcon.var.green.offset) | + (blue << m2info->fbcon.var.blue.offset) | + (transp << m2info->fbcon.var.transp.offset); + switch (m2info->fbcon.var.bits_per_pixel) { -#ifdef FBCON_HAS_CFB16 case 16: - m2info->cmap.cfb16[regno] = - (red << m2info->fbcon.var.red.offset) | - (green << m2info->fbcon.var.green.offset) | - (blue << m2info->fbcon.var.blue.offset) | - (transp << m2info->fbcon.var.transp.offset); + m2info->cmap[regno] = col | (col << 16); break; -#endif -#ifdef FBCON_HAS_CFB32 case 32: - m2info->cmap.cfb32[regno] = - (red << m2info->fbcon.var.red.offset) | - (green << m2info->fbcon.var.green.offset) | - (blue << m2info->fbcon.var.blue.offset) | - (transp << m2info->fbcon.var.transp.offset); + m2info->cmap[regno] = col; break; -#endif } return 0; #undef m2info } -static inline void my_install_cmap(struct matroxfb_dh_fb_info* m2info) -{ - /* Do not touch this code if you do not understand what it does! */ - /* Never try to use do_install_cmap() instead. It is crap. */ - struct fb_cmap* cmap = &m2info->currcon_display->cmap; - - if (cmap->len) - fb_set_cmap(cmap, 1, &m2info->fbcon); - else - fb_set_cmap(fb_default_cmap(16), 1, &m2info->fbcon); -} - - static void matroxfb_dh_restore(struct matroxfb_dh_fb_info* m2info, struct my_timming* mt, int mode, @@ -201,6 +169,7 @@ static void matroxfb_dh_cfbX_init(struct matroxfb_dh_fb_info* m2info) { /* no acceleration for secondary head... */ + m2info->cmap[16] = 0xFFFFFFFF; } static void matroxfb_dh_pan_var(struct matroxfb_dh_fb_info* m2info, @@ -234,14 +203,10 @@ unsigned int vramlen; switch (var->bits_per_pixel) { -#ifdef FBCON_HAS_CFB16 case 16: mask = 0x1F; break; -#endif -#ifdef FBCON_HAS_CFB32 case 32: mask = 0x0F; break; -#endif default: return -EINVAL; } vramlen = m2info->video.len_usable; @@ -302,35 +267,20 @@ return 0; } -static void initMatroxDH(struct matroxfb_dh_fb_info* m2info, struct display* p) { - switch (m2info->fbcon.var.bits_per_pixel) { -#ifdef FBCON_HAS_CFB16 - case 16: - p->dispsw_data = m2info->cmap.cfb16; - p->dispsw = &fbcon_cfb16; - break; -#endif -#ifdef FBCON_HAS_CFB32 - case 32: - p->dispsw_data = m2info->cmap.cfb32; - p->dispsw = &fbcon_cfb32; - break; -#endif - default: - p->dispsw_data = NULL; - p->dispsw = &fbcon_dummy; - break; - } -} - static int matroxfb_dh_open(struct fb_info* info, int user) { #define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon)) MINFO_FROM(m2info->primary_dev); if (MINFO) { + int err; + if (ACCESS_FBINFO(dead)) { return -ENXIO; } + err = ACCESS_FBINFO(fbops).fb_open(&ACCESS_FBINFO(fbcon), user); + if (err) { + return err; + } } return 0; #undef m2info @@ -338,15 +288,17 @@ static int matroxfb_dh_release(struct fb_info* info, int user) { #define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon)) + int err = 0; MINFO_FROM(m2info->primary_dev); if (MINFO) { + err = ACCESS_FBINFO(fbops).fb_release(&ACCESS_FBINFO(fbcon), user); } - return 0; + return err; #undef m2info } -static void matroxfb_dh_update_fix(struct matroxfb_dh_fb_info *m2info) { +static void matroxfb_dh_init_fix(struct matroxfb_dh_fb_info *m2info) { struct fb_fix_screeninfo *fix = &m2info->fbcon.fix; strcpy(fix->id, "MATROX DH"); @@ -361,57 +313,36 @@ fix->accel = 0; /* no accel... */ } -static int matroxfb_dh_set_var(struct fb_var_screeninfo* var, int con, - struct fb_info* info) { +static int matroxfb_dh_check_var(struct fb_var_screeninfo* var, struct fb_info* info) { +#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon)) + int visual; + int cmap_len; + int mode; + + return matroxfb_dh_decode_var(m2info, var, &visual, &cmap_len, &mode); +#undef m2info +} + +static int matroxfb_dh_set_par(struct fb_info* info) { #define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon)) - struct display* p; - int chgvar; int visual; int cmap_len; int mode; int err; + struct fb_var_screeninfo* var = &info->var; MINFO_FROM(m2info->primary_dev); - if (con < 0) - p = m2info->fbcon.disp; - else - p = fb_display + con; if ((err = matroxfb_dh_decode_var(m2info, var, &visual, &cmap_len, &mode)) != 0) return err; - switch (var->activate & FB_ACTIVATE_MASK) { - case FB_ACTIVATE_TEST: return 0; - case FB_ACTIVATE_NXTOPEN: - case FB_ACTIVATE_NOW: break; - default: return -EINVAL; - } - if (con >= 0) { - chgvar = (p->var.xres != var->xres) || - (p->var.yres != var->yres) || - (p->var.xres_virtual != var->xres_virtual) || - (p->var.yres_virtual != var->yres_virtual) || - (p->var.bits_per_pixel != var->bits_per_pixel) || - memcmp(&p->var.red, &var->red, sizeof(var->red)) || - memcmp(&p->var.green, &var->green, sizeof(var->green)) || - memcmp(&p->var.blue, &var->blue, sizeof(var->blue)); - } else - chgvar = 0; - p->var = *var; /* cmap */ - if (con == m2info->fbcon.currcon) { + { m2info->fbcon.screen_base = vaddr_va(m2info->video.vbase); - m2info->fbcon.var = *var; m2info->fbcon.fix.visual = visual; m2info->fbcon.fix.type = FB_TYPE_PACKED_PIXELS; m2info->fbcon.fix.type_aux = 0; - p->next_line = m2info->fbcon.fix.line_length = (var->xres_virtual * var->bits_per_pixel) >> 3; - matroxfb_dh_update_fix(m2info); + m2info->fbcon.fix.line_length = (var->xres_virtual * var->bits_per_pixel) >> 3; } - p->can_soft_blank = 0; - p->inverse = 0; /* TBD */ - initMatroxDH(m2info, p); - if (chgvar && info && info->changevar) - info->changevar(con); - if (con == m2info->fbcon.currcon) { + { struct my_timming mt; unsigned int pos; int out; @@ -459,74 +390,22 @@ } up_read(&ACCESS_FBINFO(altout).lock); matroxfb_dh_cfbX_init(m2info); - my_install_cmap(m2info); - } - return 0; -#undef m2info -} - -static int matroxfb_dh_get_cmap(struct fb_cmap* cmap, int kspc, int con, - struct fb_info* info) { -#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon)) - struct display* dsp; - - if (con < 0) - dsp = m2info->fbcon.disp; - else - dsp = fb_display + con; - if (con == m2info->fbcon.currcon) - return fb_get_cmap(cmap, kspc, matroxfb_dh_getcolreg, info); - else if (dsp->cmap.len) - fb_copy_cmap(&dsp->cmap, cmap, kspc ? 0 : 2); - else - fb_copy_cmap(fb_default_cmap(16), cmap, kspc ? 0 : 2); - return 0; -#undef m2info -} - -static int matroxfb_dh_set_cmap(struct fb_cmap* cmap, int kspc, int con, - struct fb_info* info) { -#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon)) - struct display* dsp; - - if (con < 0) - dsp = m2info->fbcon.disp; - else - dsp = fb_display + con; - if (dsp->cmap.len != 16) { - int err; - - err = fb_alloc_cmap(&dsp->cmap, 16, 0); - if (err) - return err; } - if (con == m2info->fbcon.currcon) - return fb_set_cmap(cmap, kspc, info); - else - fb_copy_cmap(cmap, &dsp->cmap, kspc ? 0 : 1); return 0; #undef m2info } -static int matroxfb_dh_pan_display(struct fb_var_screeninfo* var, int con, - struct fb_info* info) { +static int matroxfb_dh_pan_display(struct fb_var_screeninfo* var, struct fb_info* info) { #define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon)) - if (var->xoffset + fb_display[con].var.xres > fb_display[con].var.xres_virtual || - var->yoffset + fb_display[con].var.yres > fb_display[con].var.yres_virtual) - return -EINVAL; - if (con == m2info->fbcon.currcon) - matroxfb_dh_pan_var(m2info, var); - fb_display[con].var.xoffset = var->xoffset; - fb_display[con].var.yoffset = var->yoffset; + matroxfb_dh_pan_var(m2info, var); return 0; #undef m2info } -static int matroxfb_dh_switch(int con, struct fb_info* info); - static int matroxfb_dh_get_vblank(const struct matroxfb_dh_fb_info* m2info, struct fb_vblank* vblank) { MINFO_FROM(m2info->primary_dev); + matroxfb_enable_irq(PMINFO 0); memset(vblank, 0, sizeof(*vblank)); vblank->flags = FB_VBLANK_HAVE_VCOUNT | FB_VBLANK_HAVE_VBLANK; /* mask out reserved bits + field number (odd/even) */ @@ -534,6 +413,12 @@ /* compatibility stuff */ if (vblank->vcount >= m2info->fbcon.var.yres) vblank->flags |= FB_VBLANK_VBLANKING; + if (test_bit(0, &ACCESS_FBINFO(irq_flags))) { + vblank->flags |= FB_VBLANK_HAVE_COUNT; + /* Only one writer, aligned int value... + it should work without lock and without atomic_t */ + vblank->count = ACCESS_FBINFO(crtc2).vsync.cnt; + } return 0; } @@ -541,12 +426,11 @@ struct file* file, unsigned int cmd, unsigned long arg, - int con, struct fb_info* info) { #define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon)) MINFO_FROM(m2info->primary_dev); - DBG("matroxfb_crtc2_ioctl") + DBG(__FUNCTION__) switch (cmd) { case FBIOGET_VBLANK: @@ -561,11 +445,22 @@ return -EFAULT; return 0; } + case FBIO_WAITFORVSYNC: + { + u_int32_t crt; + + if (get_user(crt, (u_int32_t *)arg)) + return -EFAULT; + + if (crt != 0) + return -ENODEV; + return matroxfb_wait_for_sync(PMINFO 1); + } case MATROXFB_SET_OUTPUT_MODE: case MATROXFB_GET_OUTPUT_MODE: case MATROXFB_GET_ALL_OUTPUTS: { - return ACCESS_FBINFO(fbcon.fbops)->fb_ioctl(inode, file, cmd, arg, con, &ACCESS_FBINFO(fbcon)); + return ACCESS_FBINFO(fbcon.fbops)->fb_ioctl(inode, file, cmd, arg, &ACCESS_FBINFO(fbcon)); } case MATROXFB_SET_OUTPUT_CONNECTION: { @@ -610,7 +505,7 @@ } if (!changes) return 0; - matroxfb_dh_switch(m2info->fbcon.currcon, info); + matroxfb_dh_set_par(info); return 0; } case MATROXFB_GET_OUTPUT_CONNECTION: @@ -675,45 +570,18 @@ .owner = THIS_MODULE, .fb_open = matroxfb_dh_open, .fb_release = matroxfb_dh_release, - .fb_set_var = matroxfb_dh_set_var, - .fb_get_cmap = matroxfb_dh_get_cmap, - .fb_set_cmap = matroxfb_dh_set_cmap, + .fb_check_var = matroxfb_dh_check_var, + .fb_set_par = matroxfb_dh_set_par, .fb_setcolreg = matroxfb_dh_setcolreg, .fb_pan_display =matroxfb_dh_pan_display, .fb_blank = matroxfb_dh_blank, .fb_ioctl = matroxfb_dh_ioctl, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_cursor = soft_cursor, }; -static int matroxfb_dh_switch(int con, struct fb_info* info) { -#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon)) - struct fb_cmap* cmap; - struct display* p; - - if (m2info->fbcon.currcon >= 0) { - cmap = &m2info->currcon_display->cmap; - if (cmap->len) { - fb_get_cmap(cmap, 1, matroxfb_dh_getcolreg, info); - } - } - m2info->fbcon.currcon = con; - if (con < 0) - p = m2info->fbcon.disp; - else - p = fb_display + con; - m2info->currcon_display = p; - p->var.activate = FB_ACTIVATE_NOW; - matroxfb_dh_set_var(&p->var, con, info); - return 0; -#undef m2info -} - -static int matroxfb_dh_updatevar(int con, struct fb_info* info) { -#define m2info (container_of(info, struct matroxfb_dh_fb_info, fbcon)) - matroxfb_dh_pan_var(m2info, &fb_display[con].var); - return 0; -#undef m2info -} - static struct fb_var_screeninfo matroxfb_dh_defined = { 640,480,640,480,/* W,H, virtual W,H */ 0,0, /* offset */ @@ -730,30 +598,17 @@ 39721L,48L,16L,33L,10L, 96L,2,0, /* no sync info */ FB_VMODE_NONINTERLACED, - {0,0,0,0,0,0} + 0, {0,0,0,0,0} }; static int matroxfb_dh_regit(CPMINFO struct matroxfb_dh_fb_info* m2info) { #define minfo (m2info->primary_dev) - struct display* d; void* oldcrtc2; - d = kmalloc(sizeof(*d), GFP_KERNEL); - if (!d) { - return -ENOMEM; - } - - memset(d, 0, sizeof(*d)); - - strcpy(m2info->fbcon.modename, "MATROX CRTC2"); - m2info->fbcon.changevar = NULL; m2info->fbcon.fbops = &matroxfb_dh_ops; - m2info->fbcon.disp = d; - m2info->fbcon.switch_con = &matroxfb_dh_switch; - m2info->fbcon.updatevar = &matroxfb_dh_updatevar; m2info->fbcon.flags = FBINFO_FLAG_DEFAULT; m2info->fbcon.currcon = -1; - m2info->currcon_display = d; + m2info->fbcon.pseudo_palette = m2info->cmap; if (mem < 64) mem *= 1024; @@ -763,7 +618,6 @@ if (ACCESS_FBINFO(video.len_usable) + mem <= ACCESS_FBINFO(video.len)) m2info->video.offbase = ACCESS_FBINFO(video.len) - mem; else if (ACCESS_FBINFO(video.len) < mem) { - kfree(d); return -ENOMEM; } else { /* check yres on first head... */ m2info->video.borrowed = mem; @@ -786,13 +640,12 @@ ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_CRTC2; } - matroxfb_dh_set_var(&matroxfb_dh_defined, -2, &m2info->fbcon); + matroxfb_dh_init_fix(m2info); if (register_framebuffer(&m2info->fbcon)) { - kfree(d); return -ENXIO; } if (m2info->fbcon.currcon < 0) { - matroxfb_dh_set_var(&matroxfb_dh_defined, -1, &m2info->fbcon); + fb_set_var(&m2info->fbcon, &matroxfb_dh_defined); } down_write(&ACCESS_FBINFO(crtc2.lock)); oldcrtc2 = ACCESS_FBINFO(crtc2.info); @@ -840,7 +693,6 @@ } id = m2info->fbcon.node; unregister_framebuffer(&m2info->fbcon); - kfree(m2info->fbcon.disp); /* return memory back to primary head */ ACCESS_FBINFO(video.len_usable) += m2info->video.borrowed; printk(KERN_INFO "matroxfb_crtc2: fb%u unregistered\n", id); diff -Nru a/drivers/video/matrox/matroxfb_crtc2.h b/drivers/video/matrox/matroxfb_crtc2.h --- a/drivers/video/matrox/matroxfb_crtc2.h Mon Jun 9 23:16:07 2003 +++ b/drivers/video/matrox/matroxfb_crtc2.h Mon Jun 9 23:16:07 2003 @@ -27,19 +27,10 @@ unsigned int len; } mmio; - struct display* currcon_display; - int interlaced:1; - union { -#ifdef FBCON_HAS_CFB16 - u_int16_t cfb16[16]; -#endif -#ifdef FBCON_HAS_CFB32 - u_int32_t cfb32[16]; -#endif - } cmap; - struct { unsigned red, green, blue, transp; } palette[16]; + u_int32_t cmap[17]; + struct { unsigned red, green, blue, transp; } palette[17]; }; #endif /* __MATROXFB_CRTC2_H__ */ diff -Nru a/drivers/video/matrox/matroxfb_g450.c b/drivers/video/matrox/matroxfb_g450.c --- a/drivers/video/matrox/matroxfb_g450.c Mon Jun 9 23:16:17 2003 +++ b/drivers/video/matrox/matroxfb_g450.c Mon Jun 9 23:16:17 2003 @@ -6,7 +6,7 @@ * * Portions Copyright (c) 2001 Matrox Graphics Inc. * - * Version: 1.64 2002/06/02 + * Version: 1.65 2002/08/14 * * See matroxfb_base.c for contributors. * @@ -20,6 +20,88 @@ #include <asm/uaccess.h> #include <asm/div64.h> +/* Definition of the various controls */ +struct mctl { + struct v4l2_queryctrl desc; + size_t control; +}; + +#define BLMIN 0xF3 +#define WLMAX 0x3FF + +static const struct mctl g450_controls[] = +{ { { V4L2_CID_BRIGHTNESS, V4L2_CTRL_TYPE_INTEGER, + "brightness", + 0, WLMAX-BLMIN, 1, 370-BLMIN, + 0, + }, offsetof(struct matrox_fb_info, altout.tvo_params.brightness) }, + { { V4L2_CID_CONTRAST, V4L2_CTRL_TYPE_INTEGER, + "contrast", + 0, 1023, 1, 127, + 0, + }, offsetof(struct matrox_fb_info, altout.tvo_params.contrast) }, + { { V4L2_CID_SATURATION, V4L2_CTRL_TYPE_INTEGER, + "saturation", + 0, 255, 1, 165, + 0, + }, offsetof(struct matrox_fb_info, altout.tvo_params.saturation) }, + { { V4L2_CID_HUE, V4L2_CTRL_TYPE_INTEGER, + "hue", + 0, 255, 1, 0, + 0, + }, offsetof(struct matrox_fb_info, altout.tvo_params.hue) }, + { { MATROXFB_CID_TESTOUT, V4L2_CTRL_TYPE_BOOLEAN, + "test output", + 0, 1, 1, 0, + 0, + }, offsetof(struct matrox_fb_info, altout.tvo_params.testout) }, +}; + +#define G450CTRLS (sizeof(g450_controls)/sizeof(g450_controls[0])) + +/* Return: positive number: id found + -EINVAL: id not found, return failure + -ENOENT: id not found, create fake disabled control */ +static int get_ctrl_id(__u32 v4l2_id) { + int i; + + for (i = 0; i < G450CTRLS; i++) { + if (v4l2_id < g450_controls[i].desc.id) { + if (g450_controls[i].desc.id == 0x08000000) { + return -EINVAL; + } + return -ENOENT; + } + if (v4l2_id == g450_controls[i].desc.id) { + return i; + } + } + return -EINVAL; +} + +static inline int* get_ctrl_ptr(WPMINFO unsigned int idx) { + return (int*)((char*)MINFO + g450_controls[idx].control); +} + +static void tvo_fill_defaults(WPMINFO2) { + unsigned int i; + + for (i = 0; i < G450CTRLS; i++) { + *get_ctrl_ptr(PMINFO i) = g450_controls[i].desc.default_value; + } +} + +static int cve2_get_reg(WPMINFO int reg) { + unsigned long flags; + int val; + + matroxfb_DAC_lock_irqsave(flags); + matroxfb_DAC_out(PMINFO 0x87, reg); + val = matroxfb_DAC_in(PMINFO 0x88); + matroxfb_DAC_unlock_irqrestore(flags); + return val; +} + static void cve2_set_reg(WPMINFO int reg, int val) { unsigned long flags; @@ -29,6 +111,110 @@ matroxfb_DAC_unlock_irqrestore(flags); } +static void cve2_set_reg10(WPMINFO int reg, int val) { + unsigned long flags; + + matroxfb_DAC_lock_irqsave(flags); + matroxfb_DAC_out(PMINFO 0x87, reg); + matroxfb_DAC_out(PMINFO 0x88, val >> 2); + matroxfb_DAC_out(PMINFO 0x87, reg + 1); + matroxfb_DAC_out(PMINFO 0x88, val & 3); + matroxfb_DAC_unlock_irqrestore(flags); +} + +static void g450_compute_bwlevel(CPMINFO int *bl, int *wl) { + const int b = ACCESS_FBINFO(altout.tvo_params.brightness) + BLMIN; + const int c = ACCESS_FBINFO(altout.tvo_params.contrast); + + *bl = max(b - c, BLMIN); + *wl = min(b + c, WLMAX); +} + +static int g450_query_ctrl(void* md, struct v4l2_queryctrl *p) { + int i; + + i = get_ctrl_id(p->id); + if (i >= 0) { + *p = g450_controls[i].desc; + return 0; + } + if (i == -ENOENT) { + static const struct v4l2_queryctrl disctrl = + { .flags = V4L2_CTRL_FLAG_DISABLED }; + + i = p->id; + *p = disctrl; + p->id = i; + sprintf(p->name, "Ctrl #%08X", i); + return 0; + } + return -EINVAL; +} + +static int g450_set_ctrl(void* md, struct v4l2_control *p) { + int i; + MINFO_FROM(md); + + i = get_ctrl_id(p->id); + if (i < 0) return -EINVAL; + + /* + * Check if changed. + */ + if (p->value == *get_ctrl_ptr(PMINFO i)) return 0; + + /* + * Check limits. + */ + if (p->value > g450_controls[i].desc.maximum) return -EINVAL; + if (p->value < g450_controls[i].desc.minimum) return -EINVAL; + + /* + * Store new value. + */ + *get_ctrl_ptr(PMINFO i) = p->value; + + switch (p->id) { + case V4L2_CID_BRIGHTNESS: + case V4L2_CID_CONTRAST: + { + int blacklevel, whitelevel; + g450_compute_bwlevel(PMINFO &blacklevel, &whitelevel); + cve2_set_reg10(PMINFO 0x0e, blacklevel); + cve2_set_reg10(PMINFO 0x1e, whitelevel); + } + break; + case V4L2_CID_SATURATION: + cve2_set_reg(PMINFO 0x20, p->value); + cve2_set_reg(PMINFO 0x22, p->value); + break; + case V4L2_CID_HUE: + cve2_set_reg(PMINFO 0x25, p->value); + break; + case MATROXFB_CID_TESTOUT: + { + unsigned char val = cve2_get_reg (PMINFO 0x05); + if (p->value) val |= 0x02; + else val &= ~0x02; + cve2_set_reg(PMINFO 0x05, val); + } + break; + } + + + return 0; +} + +static int g450_get_ctrl(void* md, struct v4l2_control *p) { + int i; + MINFO_FROM(md); + + i = get_ctrl_id(p->id); + if (i < 0) return -EINVAL; + p->value = *get_ctrl_ptr(PMINFO i); + return 0; +} + struct output_desc { unsigned int h_vis; unsigned int h_f_porch; @@ -329,6 +515,23 @@ const struct output_desc* outd; cve2_init_TVdata(ACCESS_FBINFO(outputs[1]).mode, &ACCESS_FBINFO(hw).maven, &outd); + { + int blacklevel, whitelevel; + g450_compute_bwlevel(PMINFO &blacklevel, &whitelevel); + ACCESS_FBINFO(hw).maven.regs[0x0E] = blacklevel >> 2; + ACCESS_FBINFO(hw).maven.regs[0x0F] = blacklevel & 3; + ACCESS_FBINFO(hw).maven.regs[0x1E] = whitelevel >> 2; + ACCESS_FBINFO(hw).maven.regs[0x1F] = whitelevel & 3; + + ACCESS_FBINFO(hw).maven.regs[0x20] = + ACCESS_FBINFO(hw).maven.regs[0x22] = ACCESS_FBINFO(altout.tvo_params.saturation); + + ACCESS_FBINFO(hw).maven.regs[0x25] = ACCESS_FBINFO(altout.tvo_params.hue); + + if (ACCESS_FBINFO(altout.tvo_params.testout)) { + ACCESS_FBINFO(hw).maven.regs[0x05] |= 0x02; + } + } computeRegs(PMINFO &ACCESS_FBINFO(hw).maven, mt, outd); } else if (mt->mnp < 0) { /* We must program clocks before CRTC2, otherwise interlaced mode @@ -374,6 +577,9 @@ .compute = matroxfb_g450_compute, .program = matroxfb_g450_program, .verifymode = matroxfb_g450_verify_mode, + .getqueryctrl = g450_query_ctrl, + .getctrl = g450_get_ctrl, + .setctrl = g450_set_ctrl, }; static struct matrox_altout matroxfb_g450_dvi = { @@ -384,6 +590,7 @@ void matroxfb_g450_connect(WPMINFO2) { if (ACCESS_FBINFO(devflags.g450dac)) { down_write(&ACCESS_FBINFO(altout.lock)); + tvo_fill_defaults(PMINFO2); ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_CRTC1; ACCESS_FBINFO(outputs[1]).data = MINFO; ACCESS_FBINFO(outputs[1]).output = &matroxfb_g450_altout; diff -Nru a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c --- a/drivers/video/matrox/matroxfb_maven.c Mon Jun 9 23:16:05 2003 +++ b/drivers/video/matrox/matroxfb_maven.c Mon Jun 9 23:16:05 2003 @@ -6,7 +6,7 @@ * * Portions Copyright (c) 2001 Matrox Graphics Inc. * - * Version: 1.64 2002/06/10 + * Version: 1.65 2002/08/14 * * See matroxfb_base.c for contributors. * @@ -25,12 +25,118 @@ #define MGATVO_B 1 #define MGATVO_C 2 +static const struct maven_gamma { + unsigned char reg83; + unsigned char reg84; + unsigned char reg85; + unsigned char reg86; + unsigned char reg87; + unsigned char reg88; + unsigned char reg89; + unsigned char reg8a; + unsigned char reg8b; +} maven_gamma[] = { + { 131, 57, 223, 15, 117, 212, 251, 91, 156}, + { 133, 61, 128, 63, 180, 147, 195, 100, 180}, + { 131, 19, 63, 31, 50, 66, 171, 64, 176}, + { 0, 0, 0, 31, 16, 16, 16, 100, 200}, + { 8, 23, 47, 73, 147, 244, 220, 80, 195}, + { 22, 43, 64, 80, 147, 115, 58, 85, 168}, + { 34, 60, 80, 214, 147, 212, 188, 85, 167}, + { 45, 77, 96, 216, 147, 99, 91, 85, 159}, + { 56, 76, 112, 107, 147, 212, 148, 64, 144}, + { 65, 91, 128, 137, 147, 196, 17, 69, 148}, + { 72, 104, 136, 138, 147, 180, 245, 73, 147}, + { 87, 116, 143, 126, 16, 83, 229, 77, 144}, + { 95, 119, 152, 254, 244, 83, 221, 77, 151}, + { 100, 129, 159, 156, 244, 148, 197, 77, 160}, + { 105, 141, 167, 247, 244, 132, 181, 84, 166}, + { 105, 147, 168, 247, 244, 245, 181, 90, 170}, + { 120, 153, 175, 248, 212, 229, 165, 90, 180}, + { 119, 156, 176, 248, 244, 229, 84, 74, 160}, + { 119, 158, 183, 248, 244, 229, 149, 78, 165} +}; + +/* Definition of the various controls */ +struct mctl { + struct v4l2_queryctrl desc; + size_t control; +}; + +#define BLMIN 0x0FF +#define WLMAX 0x3FF + +static const struct mctl maven_controls[] = +{ { { V4L2_CID_BRIGHTNESS, V4L2_CTRL_TYPE_INTEGER, + "brightness", + 0, WLMAX - BLMIN, 1, 379 - BLMIN, + 0, + }, offsetof(struct matrox_fb_info, altout.tvo_params.brightness) }, + { { V4L2_CID_CONTRAST, V4L2_CTRL_TYPE_INTEGER, + "contrast", + 0, 1023, 1, 127, + 0, + }, offsetof(struct matrox_fb_info, altout.tvo_params.contrast) }, + { { V4L2_CID_SATURATION, V4L2_CTRL_TYPE_INTEGER, + "saturation", + 0, 255, 1, 155, + 0, + }, offsetof(struct matrox_fb_info, altout.tvo_params.saturation) }, + { { V4L2_CID_HUE, V4L2_CTRL_TYPE_INTEGER, + "hue", + 0, 255, 1, 0, + 0, + }, offsetof(struct matrox_fb_info, altout.tvo_params.hue) }, + { { V4L2_CID_GAMMA, V4L2_CTRL_TYPE_INTEGER, + "gamma", + 0, sizeof(maven_gamma)/sizeof(maven_gamma[0])-1, 1, 3, + 0, + }, offsetof(struct matrox_fb_info, altout.tvo_params.gamma) }, + { { MATROXFB_CID_TESTOUT, V4L2_CTRL_TYPE_BOOLEAN, + "test output", + 0, 1, 1, 0, + 0, + }, offsetof(struct matrox_fb_info, altout.tvo_params.testout) }, + { { MATROXFB_CID_DEFLICKER, V4L2_CTRL_TYPE_INTEGER, + "deflicker mode", + 0, 2, 1, 0, + 0, + }, offsetof(struct matrox_fb_info, altout.tvo_params.deflicker) }, + +}; + +#define MAVCTRLS (sizeof(maven_controls)/sizeof(maven_controls[0])) + +/* Return: positive number: id found + -EINVAL: id not found, return failure + -ENOENT: id not found, create fake disabled control */ +static int get_ctrl_id(__u32 v4l2_id) { + int i; + + for (i = 0; i < MAVCTRLS; i++) { + if (v4l2_id < maven_controls[i].desc.id) { + if (maven_controls[i].desc.id == 0x08000000) { + return -EINVAL; + } + return -ENOENT; + } + if (v4l2_id == maven_controls[i].desc.id) { + return i; + } + } + return -EINVAL; +} + struct maven_data { struct matrox_fb_info* primary_head; struct i2c_client* client; int version; }; +static int* get_ctrl_ptr(struct maven_data* md, int idx) { + return (int*)((char*)(md->primary_head) + maven_controls[idx].control); +} + static int maven_get_reg(struct i2c_client* c, char reg) { char dst; struct i2c_msg msgs[] = {{ c->addr, I2C_M_REV_DIR_ADDR, sizeof(reg), ® }, @@ -115,7 +221,7 @@ unsigned int scrlen; unsigned int fmax; - DBG("PLL_calcclock") + DBG(__FUNCTION__) scrlen = htotal * (vtotal - 1); fwant = htotal * vtotal; @@ -219,9 +325,34 @@ unsigned char df; df = (md->version == MGATVO_B?0x40:0x00); + switch (md->primary_head->altout.tvo_params.deflicker) { + case 0: +/* df |= 0x00; */ + break; + case 1: + df |= 0xB1; + break; + case 2: + df |= 0xA2; + break; + } return df; } +static void maven_compute_bwlevel (const struct maven_data* md, + int *bl, int *wl) { + const int b = md->primary_head->altout.tvo_params.brightness + BLMIN; + const int c = md->primary_head->altout.tvo_params.contrast; + + *bl = max(b - c, BLMIN); + *wl = min(b + c, WLMAX); +} + +static const struct maven_gamma* maven_compute_gamma (const struct maven_data* md) { + return maven_gamma + md->primary_head->altout.tvo_params.gamma; +} + + static void maven_init_TVdata(const struct maven_data* md, struct mavenregs* data) { static struct mavenregs palregs = { { 0x2A, 0x09, 0x8A, 0xCB, /* 00: chroma subcarrier */ @@ -336,18 +467,40 @@ /* Set deflicker */ data->regs[0x93] = maven_compute_deflicker(md); + + /* set gamma */ + { + const struct maven_gamma* g; + g = maven_compute_gamma(md); + data->regs[0x83] = g->reg83; + data->regs[0x84] = g->reg84; + data->regs[0x85] = g->reg85; + data->regs[0x86] = g->reg86; + data->regs[0x87] = g->reg87; + data->regs[0x88] = g->reg88; + data->regs[0x89] = g->reg89; + data->regs[0x8A] = g->reg8a; + data->regs[0x8B] = g->reg8b; + } + + /* Set contrast / brightness */ + { + int bl, wl; + maven_compute_bwlevel (md, &bl, &wl); + data->regs[0x0e] = bl >> 2; + data->regs[0x0f] = bl & 3; + data->regs[0x1e] = wl >> 2; + data->regs[0x1f] = wl & 3; + } - /* gamma correction registers */ - data->regs[0x83] = 0x00; - data->regs[0x84] = 0x00; - data->regs[0x85] = 0x00; - data->regs[0x86] = 0x1F; - data->regs[0x87] = 0x10; - data->regs[0x88] = 0x10; - data->regs[0x89] = 0x10; - data->regs[0x8A] = 0x64; /* 100 */ - data->regs[0x8B] = 0xC8; /* 200 */ - + /* Set saturation */ + { + data->regs[0x20] = + data->regs[0x22] = ACCESS_FBINFO(altout.tvo_params.saturation); + } + + /* Set HUE */ + data->regs[0x25] = ACCESS_FBINFO(altout.tvo_params.hue); return; } @@ -859,16 +1012,119 @@ return 0; } -static int maven_verify_output_mode(struct maven_data* md, u_int32_t arg) { - switch (arg) { - case MATROXFB_OUTPUT_MODE_PAL: - case MATROXFB_OUTPUT_MODE_NTSC: - case MATROXFB_OUTPUT_MODE_MONITOR: - return 0; +static int maven_get_queryctrl (struct maven_data* md, + struct v4l2_queryctrl *p) { + int i; + + i = get_ctrl_id(p->id); + if (i >= 0) { + *p = maven_controls[i].desc; + return 0; + } + if (i == -ENOENT) { + static const struct v4l2_queryctrl disctrl = + { .flags = V4L2_CTRL_FLAG_DISABLED }; + + i = p->id; + *p = disctrl; + p->id = i; + sprintf(p->name, "Ctrl #%08X", i); + return 0; } return -EINVAL; } +static int maven_set_control (struct maven_data* md, + struct v4l2_control *p) { + int i; + + i = get_ctrl_id(p->id); + if (i < 0) return -EINVAL; + + /* + * Check if changed. + */ + if (p->value == *get_ctrl_ptr(md, i)) return 0; + + /* + * Check limits. + */ + if (p->value > maven_controls[i].desc.maximum) return -EINVAL; + if (p->value < maven_controls[i].desc.minimum) return -EINVAL; + + /* + * Store new value. + */ + *get_ctrl_ptr(md, i) = p->value; + + switch (p->id) { + case V4L2_CID_BRIGHTNESS: + case V4L2_CID_CONTRAST: + { + int blacklevel, whitelevel; + maven_compute_bwlevel(md, &blacklevel, &whitelevel); + blacklevel = (blacklevel >> 2) | ((blacklevel & 3) << 8); + whitelevel = (whitelevel >> 2) | ((whitelevel & 3) << 8); + maven_set_reg_pair(md->client, 0x0e, blacklevel); + maven_set_reg_pair(md->client, 0x1e, whitelevel); + } + break; + case V4L2_CID_SATURATION: + { + maven_set_reg(md->client, 0x20, p->value); + maven_set_reg(md->client, 0x22, p->value); + } + break; + case V4L2_CID_HUE: + { + maven_set_reg(md->client, 0x25, p->value); + } + break; + case V4L2_CID_GAMMA: + { + const struct maven_gamma* g; + g = maven_compute_gamma(md); + maven_set_reg(md->client, 0x83, g->reg83); + maven_set_reg(md->client, 0x84, g->reg84); + maven_set_reg(md->client, 0x85, g->reg85); + maven_set_reg(md->client, 0x86, g->reg86); + maven_set_reg(md->client, 0x87, g->reg87); + maven_set_reg(md->client, 0x88, g->reg88); + maven_set_reg(md->client, 0x89, g->reg89); + maven_set_reg(md->client, 0x8a, g->reg8a); + maven_set_reg(md->client, 0x8b, g->reg8b); + } + break; + case MATROXFB_CID_TESTOUT: + { + unsigned char val + = maven_get_reg (md->client,0x8d); + if (p->value) val |= 0x10; + else val &= ~0x10; + maven_set_reg (md->client, 0x8d, val); + } + break; + case MATROXFB_CID_DEFLICKER: + { + maven_set_reg(md->client, 0x93, maven_compute_deflicker(md)); + } + break; + } + + + return 0; +} + +static int maven_get_control (struct maven_data* md, + struct v4l2_control *p) { + int i; + + i = get_ctrl_id(p->id); + if (i < 0) return -EINVAL; + p->value = *get_ctrl_ptr(md, i); + return 0; +} + /******************************************************/ static int maven_out_compute(void* md, struct my_timming* mt) { @@ -892,7 +1148,25 @@ } static int maven_out_verify_mode(void* md, u_int32_t arg) { - return maven_verify_output_mode(md, arg); + switch (arg) { + case MATROXFB_OUTPUT_MODE_PAL: + case MATROXFB_OUTPUT_MODE_NTSC: + case MATROXFB_OUTPUT_MODE_MONITOR: + return 0; + } + return -EINVAL; +} + +static int maven_out_get_queryctrl(void* md, struct v4l2_queryctrl* p) { + return maven_get_queryctrl(md, p); +} + +static int maven_out_get_ctrl(void* md, struct v4l2_control* p) { + return maven_get_control(md, p); +} + +static int maven_out_set_ctrl(void* md, struct v4l2_control* p) { + return maven_set_control(md, p); } static struct matrox_altout maven_altout = { @@ -901,12 +1175,14 @@ .program = maven_out_program, .start = maven_out_start, .verifymode = maven_out_verify_mode, + .getqueryctrl = maven_out_get_queryctrl, + .getctrl = maven_out_get_ctrl, + .setctrl = maven_out_set_ctrl, }; static int maven_init_client(struct i2c_client* clnt) { - struct i2c_adapter* a = clnt->adapter; - struct maven_data* md = clnt->data; - MINFO_FROM(container_of(a, struct i2c_bit_adapter, adapter)->minfo); + struct maven_data* md = i2c_get_clientdata(clnt); + MINFO_FROM(container_of(clnt->adapter, struct i2c_bit_adapter, adapter)->minfo); md->primary_head = MINFO; md->client = clnt; @@ -918,14 +1194,26 @@ up_write(&ACCESS_FBINFO(altout.lock)); if (maven_get_reg(clnt, 0xB2) < 0x14) { md->version = MGATVO_B; + /* Tweak some things for this old chip */ } else { md->version = MGATVO_C; } + /* + * Set all parameters to its initial values. + */ + { + unsigned int i; + + for (i = 0; i < MAVCTRLS; ++i) { + *get_ctrl_ptr(md, i) = maven_controls[i].desc.default_value; + } + } + return 0; } static int maven_shutdown_client(struct i2c_client* clnt) { - struct maven_data* md = clnt->data; + struct maven_data* md = i2c_get_clientdata(clnt); if (md->primary_head) { MINFO_FROM(md->primary_head); @@ -947,8 +1235,7 @@ static struct i2c_driver maven_driver; -static int maven_detect_client(struct i2c_adapter* adapter, int address, unsigned short flags, - int kind) { +static int maven_detect_client(struct i2c_adapter* adapter, int address, int kind) { int err = 0; struct i2c_client* new_client; struct maven_data* data; @@ -963,15 +1250,12 @@ goto ERROR0; } data = (struct maven_data*)(new_client + 1); - new_client->data = data; + i2c_set_clientdata(new_client, data); new_client->addr = address; new_client->adapter = adapter; new_client->driver = &maven_driver; new_client->flags = 0; - if (kind < 0) { - ; - } - strcpy(new_client->name, "maven client"); + strcpy(new_client->dev.name, "maven client"); if ((err = i2c_attach_client(new_client))) goto ERROR3; err = maven_init_client(new_client); @@ -1015,6 +1299,7 @@ .flags = I2C_DF_NOTIFY, .attach_adapter = maven_attach_adapter, .detach_client = maven_detach_client, + .command = maven_command, }; /* ************************** */ diff -Nru a/drivers/video/matrox/matroxfb_misc.c b/drivers/video/matrox/matroxfb_misc.c --- a/drivers/video/matrox/matroxfb_misc.c Mon Jun 9 23:16:15 2003 +++ b/drivers/video/matrox/matroxfb_misc.c Mon Jun 9 23:16:15 2003 @@ -88,52 +88,14 @@ #include <linux/interrupt.h> #include <linux/matroxfb.h> -void matroxfb_createcursorshape(WPMINFO struct display* p, int vmode) { - unsigned int h; - unsigned int cu, cd; - - h = fontheight(p); - - if (vmode & FB_VMODE_DOUBLE) - h *= 2; - cd = h; - if (cd >= 10) - cd--; - switch (ACCESS_FBINFO(cursor.type) = (p->conp->vc_cursor_type & CUR_HWMASK)) { - case CUR_NONE: - cu = cd; - break; - case CUR_UNDERLINE: - cu = cd - 2; - break; - case CUR_LOWER_THIRD: - cu = (h * 2) / 3; - break; - case CUR_LOWER_HALF: - cu = h / 2; - break; - case CUR_TWO_THIRDS: - cu = h / 3; - break; - case CUR_BLOCK: - default: - cu = 0; - cd = h; - break; - } - ACCESS_FBINFO(cursor.w) = fontwidth(p); - ACCESS_FBINFO(cursor.u) = cu; - ACCESS_FBINFO(cursor.d) = cd; -} - void matroxfb_DAC_out(CPMINFO int reg, int val) { - DBG_REG("outDAC"); + DBG_REG(__FUNCTION__) mga_outb(M_RAMDAC_BASE+M_X_INDEX, reg); mga_outb(M_RAMDAC_BASE+M_X_DATAREG, val); } int matroxfb_DAC_in(CPMINFO int reg) { - DBG_REG("inDAC"); + DBG_REG(__FUNCTION__) mga_outb(M_RAMDAC_BASE+M_X_INDEX, reg); return mga_inb(M_RAMDAC_BASE+M_X_DATAREG); } @@ -141,7 +103,7 @@ void matroxfb_var2my(struct fb_var_screeninfo* var, struct my_timming* mt) { unsigned int pixclock = var->pixclock; - DBG("var2my") + DBG(__FUNCTION__) if (!pixclock) pixclock = 10000; /* 10ns = 100MHz */ mt->pixclock = 1000000000 / pixclock; @@ -168,7 +130,7 @@ unsigned int fwant; unsigned int p; - DBG("PLL_calcclock") + DBG(__FUNCTION__) fwant = freq; @@ -221,23 +183,18 @@ return bestvco; } -int matroxfb_vgaHWinit(WPMINFO struct my_timming* m, struct display* p) { +int matroxfb_vgaHWinit(WPMINFO struct my_timming* m) { unsigned int hd, hs, he, hbe, ht; - unsigned int vd, vs, ve, vt; + unsigned int vd, vs, ve, vt, lc; unsigned int wd; unsigned int divider; int i; - int text = ACCESS_FBINFO(fbcon).fix.type == FB_TYPE_TEXT; int fwidth; struct matrox_hw_state * const hw = &ACCESS_FBINFO(hw); - if (text) { - fwidth = fontwidth(p); - if (!fwidth) fwidth = 8; - } else - fwidth = 8; + fwidth = 8; - DBG("vgaHWinit") + DBG(__FUNCTION__) hw->SEQ[0] = 0x00; if (fwidth == 9) @@ -246,10 +203,7 @@ hw->SEQ[1] = 0x01; /* or 0x09 */ hw->SEQ[2] = 0x0F; /* bitplanes */ hw->SEQ[3] = 0x00; - if (text) - hw->SEQ[4] = 0x02; - else - hw->SEQ[4] = 0x0E; + hw->SEQ[4] = 0x0E; /* CRTC 0..7, 9, 16..19, 21, 22 are reprogrammed by Matrox Millennium code... Hope that by MGA1064 too */ if (m->dblscan) { m->VTotal <<= 1; @@ -270,24 +224,15 @@ hw->GCTL[2] = 0x00; hw->GCTL[3] = 0x00; hw->GCTL[4] = 0x00; - if (text) { - hw->GCTL[5] = 0x10; - hw->GCTL[6] = 0x02; - } else { - hw->GCTL[5] = 0x40; - hw->GCTL[6] = 0x05; - } + hw->GCTL[5] = 0x40; + hw->GCTL[6] = 0x05; hw->GCTL[7] = 0x0F; hw->GCTL[8] = 0xFF; /* Whole ATTR is ignored in PowerGraphics mode */ for (i = 0; i < 16; i++) hw->ATTR[i] = i; - if (text) { - hw->ATTR[16] = 0x04; - } else { - hw->ATTR[16] = 0x41; - } + hw->ATTR[16] = 0x41; hw->ATTR[17] = 0xFF; hw->ATTR[18] = 0x0F; if (fwidth == 9) @@ -296,22 +241,14 @@ hw->ATTR[19] = 0x00; hw->ATTR[20] = 0x00; - if (text) { - hd = m->HDisplay / fwidth; - hs = m->HSyncStart / fwidth; - he = m->HSyncEnd / fwidth; - ht = m->HTotal / fwidth; - divider = 8; - } else { - hd = m->HDisplay >> 3; - hs = m->HSyncStart >> 3; - he = m->HSyncEnd >> 3; - ht = m->HTotal >> 3; - /* standard timmings are in 8pixels, but for interleaved we cannot */ - /* do it for 4bpp (because of (4bpp >> 1(interleaved))/4 == 0) */ - /* using 16 or more pixels per unit can save us */ - divider = ACCESS_FBINFO(curr.final_bppShift); - } + hd = m->HDisplay >> 3; + hs = m->HSyncStart >> 3; + he = m->HSyncEnd >> 3; + ht = m->HTotal >> 3; + /* standard timmings are in 8pixels, but for interleaved we cannot */ + /* do it for 4bpp (because of (4bpp >> 1(interleaved))/4 == 0) */ + /* using 16 or more pixels per unit can save us */ + divider = ACCESS_FBINFO(curr.final_bppShift); while (divider & 3) { hd >>= 1; hs >>= 1; @@ -336,16 +273,12 @@ vs = m->VSyncStart - 1; ve = m->VSyncEnd - 1; vt = m->VTotal - 2; + lc = vd; /* G200 cannot work with (ht & 7) == 6 */ if (((ht & 0x07) == 0x06) || ((ht & 0x0F) == 0x04)) ht++; - if (text) { - hbe = ht - 1; - wd = p->var.xres_virtual / (fwidth * 2); - } else { - hbe = ht; - wd = p->var.xres_virtual * ACCESS_FBINFO(curr.final_bppShift) / 64; - } + hbe = ht; + wd = ACCESS_FBINFO(fbcon).var.xres_virtual * ACCESS_FBINFO(curr.final_bppShift) / 64; hw->CRTCEXT[0] = 0; hw->CRTCEXT[5] = 0; @@ -367,11 +300,9 @@ hw->CRTCEXT[2] = ((vt & 0xC00) >> 10) | ((vd & 0x400) >> 8) | /* disp end */ ((vd & 0xC00) >> 7) | /* vblanking start */ - ((vs & 0xC00) >> 5); - if (text) - hw->CRTCEXT[3] = 0x00; - else - hw->CRTCEXT[3] = (divider - 1) | 0x80; + ((vs & 0xC00) >> 5) | + ((lc & 0x400) >> 3); + hw->CRTCEXT[3] = (divider - 1) | 0x80; hw->CRTCEXT[4] = 0; hw->CRTC[0] = ht-4; @@ -380,21 +311,18 @@ hw->CRTC[3] = (hbe & 0x1F) | 0x80; hw->CRTC[4] = hs; hw->CRTC[5] = ((hbe & 0x20) << 2) | (he & 0x1F); - if (text) - hw->CRTC[5] |= 0x60; /* delay sync for 3 clocks (to same picture position on MGA and VGA) */ hw->CRTC[6] = vt & 0xFF; hw->CRTC[7] = ((vt & 0x100) >> 8) | ((vd & 0x100) >> 7) | ((vs & 0x100) >> 6) | ((vd & 0x100) >> 5) | - 0x10 | + ((lc & 0x100) >> 4) | ((vt & 0x200) >> 4) | ((vd & 0x200) >> 3) | ((vs & 0x200) >> 2); hw->CRTC[8] = 0x00; - hw->CRTC[9] = ((vd & 0x200) >> 4) | 0x40; - if (text) - hw->CRTC[9] |= fontheight(p) - 1; + hw->CRTC[9] = ((vd & 0x200) >> 4) | + ((lc & 0x200) >> 3); if (m->dblscan && !m->interlaced) hw->CRTC[9] |= 0x80; for (i = 10; i < 16; i++) @@ -406,18 +334,8 @@ hw->CRTC[20] = 0x00; hw->CRTC[21] = vd /* & 0xFF */; hw->CRTC[22] = (vt + 1) /* & 0xFF */; - if (text) { - if (ACCESS_FBINFO(devflags.textmode) == 1) - hw->CRTC[23] = 0xC3; - else - hw->CRTC[23] = 0xA3; - if (ACCESS_FBINFO(devflags.textmode) == 4) - hw->CRTC[20] = 0x5F; - else - hw->CRTC[20] = 0x1F; - } else - hw->CRTC[23] = 0xC3; - hw->CRTC[24] = 0xFF; + hw->CRTC[23] = 0xC3; + hw->CRTC[24] = lc; return 0; }; @@ -426,7 +344,7 @@ struct matrox_hw_state * const hw = &ACCESS_FBINFO(hw); CRITFLAGS - DBG("vgaHWrestore") + DBG(__FUNCTION__) dprintk(KERN_INFO "MiscOutReg: %02X\n", hw->MiscOutReg); dprintk(KERN_INFO "SEQ regs: "); @@ -473,182 +391,6 @@ CRITEND } -void matroxfb_fastfont_init(struct matrox_fb_info* minfo){ - unsigned int size; - - size = ACCESS_FBINFO(fastfont.size); - ACCESS_FBINFO(fastfont.size) = 0; - if (size) { - unsigned int end = ACCESS_FBINFO(video.len_usable); - - if (size < end) { - unsigned int start; - - start = (end - size) & PAGE_MASK; - if (start >= 0x00100000) { - ACCESS_FBINFO(video.len_usable) = start; - ACCESS_FBINFO(fastfont.mgabase) = start * 8; - ACCESS_FBINFO(fastfont.vbase) = ACCESS_FBINFO(video.vbase); - vaddr_add(&ACCESS_FBINFO(fastfont.vbase), start); - ACCESS_FBINFO(fastfont.size) = end - start; - } - } - } -} - -#ifndef FNTCHARCNT -#define FNTCHARCNT(fd) (((int *)(fd))[-3]) -#endif - -int matrox_text_loadfont(WPMINFO struct display* p) { - unsigned int fsize; - unsigned int width; - vaddr_t dst; - unsigned int i; - u_int8_t* font; - CRITFLAGS - - if (!p || !p->fontdata) - return 0; - width = fontwidth(p); - fsize = p->userfont?FNTCHARCNT(p->fontdata):256; - - dst = ACCESS_FBINFO(video.vbase); - i = 2; - font = (u_int8_t*)p->fontdata; - - CRITBEGIN - - mga_setr(M_SEQ_INDEX, 0x02, 0x04); - while (fsize--) { - int l; - - for (l = 0; l < fontheight(p); l++) { - mga_writeb(dst, i, *font++); - if (fontwidth(p) > 8) font++; - i += ACCESS_FBINFO(devflags.vgastep); - } - i += (32 - fontheight(p)) * ACCESS_FBINFO(devflags.vgastep); - } - mga_setr(M_SEQ_INDEX, 0x02, 0x03); - - CRITEND - - return 1; -} - -int matroxfb_fastfont_tryset(WPMINFO struct display* p) { - unsigned int fsize; - unsigned int width; - CRITFLAGS - - if (!p || !p->fontdata) - return 0; - width = fontwidth(p); - if (width > 32) - return 0; - fsize = (p->userfont?FNTCHARCNT(p->fontdata):256) * fontheight(p); - if (((fsize * width + 31) / 32) * 4 > ACCESS_FBINFO(fastfont.size)) - return 0; - - CRITBEGIN - - mga_outl(M_OPMODE, M_OPMODE_8BPP); - if (width <= 8) { - if (width == 8) - mga_memcpy_toio(ACCESS_FBINFO(fastfont.vbase), 0, p->fontdata, fsize); - else { - vaddr_t dst; - unsigned int i; - u_int8_t* font; - u_int32_t mask, valid, reg; - - dst = ACCESS_FBINFO(fastfont.vbase); - font = (u_int8_t*)p->fontdata; - mask = ~0 << (8 - width); - valid = 0; - reg = 0; - i = 0; - while (fsize--) { - reg |= (*font++ & mask) << (8 - valid); - valid += width; - if (valid >= 8) { - mga_writeb(dst, i++, reg >> 8); - reg = reg << 8; - valid -= 8; - } - } - if (valid) - mga_writeb(dst, i, reg >> 8); - } - } else if (width <= 16) { - if (width == 16) - mga_memcpy_toio(ACCESS_FBINFO(fastfont.vbase), 0, p->fontdata, fsize*2); - else { - vaddr_t dst; - u_int16_t* font; - u_int32_t mask, valid, reg; - unsigned int i; - - dst = ACCESS_FBINFO(fastfont.vbase); - font = (u_int16_t*)p->fontdata; - mask = ~0 << (16 - width); - valid = 0; - reg = 0; - i = 0; - while (fsize--) { - reg |= (ntohs(*font++) & mask) << (16 - valid); - valid += width; - if (valid >= 16) { - mga_writew(dst, i, htons(reg >> 16)); - i += 2; - reg = reg << 16; - valid -= 16; - } - } - if (valid) - mga_writew(dst, i, htons(reg >> 16)); - } - } else { - if (width == 32) - mga_memcpy_toio(ACCESS_FBINFO(fastfont.vbase), 0, p->fontdata, fsize*4); - else { - vaddr_t dst; - u_int32_t* font; - u_int32_t mask, valid, reg; - unsigned int i; - - dst = ACCESS_FBINFO(fastfont.vbase); - font = (u_int32_t*)p->fontdata; - mask = ~0 << (32 - width); - valid = 0; - reg = 0; - i = 0; - while (fsize--) { - reg |= (ntohl(*font) & mask) >> valid; - valid += width; - if (valid >= 32) { - mga_writel(dst, i, htonl(reg)); - i += 4; - valid -= 32; - if (valid) - reg = (ntohl(*font) & mask) << (width - valid); - else - reg = 0; - } - font++; - } - if (valid) - mga_writel(dst, i, htonl(reg)); - } - } - mga_outl(M_OPMODE, ACCESS_FBINFO(accel.m_opmode)); - - CRITEND - - return 1; -} - static void get_pins(unsigned char* pins, struct matrox_bios* bd) { unsigned int b0 = readb(pins); @@ -994,6 +736,27 @@ parse_bios(vaddr_va(ACCESS_FBINFO(video).vbase), &ACCESS_FBINFO(bios)); pci_write_config_dword(pdev, PCI_ROM_ADDRESS, biosbase); pci_write_config_dword(pdev, PCI_OPTION_REG, opt); +#ifdef CONFIG_X86 + if (!ACCESS_FBINFO(bios).bios_valid) { + unsigned char* b; + + b = ioremap(0x000C0000, 65536); + if (!b) { + printk(KERN_INFO "matroxfb: Unable to map legacy BIOS\n"); + } else { + unsigned int ven = readb(b+0x64+0) | (readb(b+0x64+1) << 8); + unsigned int dev = readb(b+0x64+2) | (readb(b+0x64+3) << 8); + + if (ven != pdev->vendor || dev != pdev->device) { + printk(KERN_INFO "matroxfb: Legacy BIOS is for %04X:%04X, while this device is %04X:%04X\n", + ven, dev, pdev->vendor, pdev->device); + } else { + parse_bios(b, &ACCESS_FBINFO(bios)); + } + iounmap(b); + } + } +#endif matroxfb_set_limits(PMINFO &ACCESS_FBINFO(bios)); } @@ -1005,10 +768,6 @@ struct matrox_fb_info matroxfb_global_mxinfo; EXPORT_SYMBOL(matroxfb_global_mxinfo); #endif -EXPORT_SYMBOL(matrox_text_loadfont); /* for matroxfb_accel */ -EXPORT_SYMBOL(matroxfb_createcursorshape); /* accel, DAC1064, Ti3026 */ -EXPORT_SYMBOL(matroxfb_fastfont_tryset); /* accel */ -EXPORT_SYMBOL(matroxfb_fastfont_init); /* DAC1064, Ti3026 */ EXPORT_SYMBOL(matroxfb_vgaHWinit); /* DAC1064, Ti3026 */ EXPORT_SYMBOL(matroxfb_vgaHWrestore); /* DAC1064, Ti3026 */ EXPORT_SYMBOL(matroxfb_read_pins); diff -Nru a/drivers/video/matrox/matroxfb_misc.h b/drivers/video/matrox/matroxfb_misc.h --- a/drivers/video/matrox/matroxfb_misc.h Mon Jun 9 23:16:07 2003 +++ b/drivers/video/matrox/matroxfb_misc.h Mon Jun 9 23:16:07 2003 @@ -11,12 +11,8 @@ return matroxfb_PLL_calcclock(&ACCESS_FBINFO(features.pll), freq, fmax, in, feed, post); } -void matroxfb_createcursorshape(WPMINFO struct display* p, int vmode); -int matroxfb_vgaHWinit(WPMINFO struct my_timming* m, struct display* p); +int matroxfb_vgaHWinit(WPMINFO struct my_timming* m); void matroxfb_vgaHWrestore(WPMINFO2); -void matroxfb_fastfont_init(struct matrox_fb_info* minfo); -int matrox_text_loadfont(WPMINFO struct display* p); -int matroxfb_fastfont_tryset(WPMINFO struct display* p); void matroxfb_read_pins(WPMINFO2); #endif /* __MATROXFB_MISC_H__ */ diff -Nru a/drivers/video/pm2fb.c b/drivers/video/pm2fb.c --- a/drivers/video/pm2fb.c Mon Jun 9 23:16:20 2003 +++ b/drivers/video/pm2fb.c Mon Jun 9 23:16:20 2003 @@ -1178,7 +1178,7 @@ static int __init pm2pci_detect(struct pm2fb_info* p) { struct pm2pci_par* pci=&p->board_par.pci; - struct pci_dev* dev; + struct pci_dev* dev = NULL; int i; unsigned char* m; #ifdef __sparc__ @@ -1192,7 +1192,7 @@ } DPRINTK("scanning PCI bus for known chipsets...\n"); - pci_for_each_dev(dev) { + while ((dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) { for (i = 0; pm2pci_cards[i].vendor; i++) if (pm2pci_cards[i].vendor == dev->vendor && pm2pci_cards[i].device == dev->device) { diff -Nru a/drivers/video/radeonfb.c b/drivers/video/radeonfb.c --- a/drivers/video/radeonfb.c Mon Jun 9 23:16:19 2003 +++ b/drivers/video/radeonfb.c Mon Jun 9 23:16:19 2003 @@ -707,7 +707,7 @@ static int radeon_dfp_parse_EDID(struct radeonfb_info *rinfo); static void radeon_update_default_var(struct radeonfb_info *rinfo); -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_OF static int radeon_read_OF (struct radeonfb_info *rinfo); static int radeon_get_EDID_OF(struct radeonfb_info *rinfo); @@ -728,7 +728,7 @@ }; #endif /* CONFIG_PMAC_BACKLIGHT */ -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_OF */ static char *radeon_find_rom(struct radeonfb_info *rinfo) @@ -830,7 +830,7 @@ printk("radeonfb: ref_clk=%d, ref_div=%d, xclk=%d from BIOS\n", rinfo->pll.ref_clk, rinfo->pll.ref_div, rinfo->pll.xclk); } else { -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_OF if (radeon_read_OF(rinfo)) { unsigned int tmp, Nx, M, ref_div, xclk; @@ -965,7 +965,7 @@ static void radeon_get_EDID(struct radeonfb_info *rinfo) { -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_OF if (!radeon_get_EDID_OF(rinfo)) RTRACE("radeonfb: could not retrieve EDID from OF\n"); #else @@ -974,7 +974,7 @@ } -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_OF static int radeon_get_EDID_OF(struct radeonfb_info *rinfo) { struct device_node *dp; @@ -996,7 +996,7 @@ } return 0; } -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_OF */ static int radeon_dfp_parse_EDID(struct radeonfb_info *rinfo) @@ -1209,7 +1209,7 @@ } -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_OF static int radeon_read_OF (struct radeonfb_info *rinfo) { struct device_node *dp; @@ -1957,11 +1957,11 @@ } newmode.vclk_ecp_cntl = rinfo->init_state.vclk_ecp_cntl; -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_OF /* Gross hack for iBook with M7 until I find out a proper fix */ if (machine_is_compatible("PowerBook4,3") && rinfo->arch == RADEON_M7) newmode.ppll_div_3 = 0x000600ad; -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_OF */ RTRACE("post div = 0x%x\n", rinfo->post_div); RTRACE("fb_div = 0x%x\n", rinfo->fb_div); diff -Nru a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c --- a/drivers/video/riva/fbdev.c Mon Jun 9 23:16:15 2003 +++ b/drivers/video/riva/fbdev.c Mon Jun 9 23:16:15 2003 @@ -1606,7 +1606,7 @@ return 0; } -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_OF static int riva_get_EDID_OF(struct riva_par *par, struct pci_dev *pd) { struct device_node *dp; @@ -1621,7 +1621,7 @@ } else return 0; } -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_OF */ static int riva_dfp_parse_EDID(struct riva_par *par) { @@ -1699,7 +1699,7 @@ static void riva_get_EDID(struct fb_info *info, struct pci_dev *pdev) { -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_OF if (!riva_get_EDID_OF(info, pdev)) printk("rivafb: could not retrieve EDID from OF\n"); #else diff -Nru a/drivers/video/sa1100fb.c b/drivers/video/sa1100fb.c --- a/drivers/video/sa1100fb.c Mon Jun 9 23:16:08 2003 +++ b/drivers/video/sa1100fb.c Mon Jun 9 23:16:08 2003 @@ -1753,25 +1753,7 @@ return fbi; } -static struct device_driver sa1100fb_driver = { - .name = "sa1100fb", - .bus = &system_bus_type, - .suspend = sa1100fb_suspend, - .resume = sa1100fb_resume, -}; - -static struct sys_device sa1100fb_dev = { - .name = "LCD", - .id = 0, - .root = NULL, - .dev = { - .name = "Intel Corporation SA11x0 [LCD]", - .bus_id = "b0100000", - .driver = &sa1100fb_driver, - }, -}; - -int __init sa1100fb_init(void) +static int __init sa1100fb_probe(struct device *dev) { struct sa1100fb_info *fbi; int ret; @@ -1779,16 +1761,11 @@ if (!request_mem_region(0xb0100000, 0x10000, "LCD")) return -EBUSY; - driver_register(&sa1100fb_driver); - sys_device_register(&sa1100fb_dev); - fbi = sa1100fb_init_fbinfo(); ret = -ENOMEM; if (!fbi) goto failed; - dev_set_drvdata(&sa1100fb_dev.dev, fbi); - /* Initialize video memory */ ret = sa1100fb_map_video_memory(fbi); if (ret) @@ -1822,6 +1799,8 @@ */ sa1100fb_check_var(&fbi->fb.var, &fbi->fb); + dev_set_drvdata(dev, fbi); + ret = register_framebuffer(&fbi->fb); if (ret < 0) goto failed; @@ -1839,12 +1818,24 @@ return 0; failed: - sys_device_unregister(&sa1100fb_dev); - driver_unregister(&sa1100fb_driver); + dev_set_drvdata(dev, NULL); if (fbi) kfree(fbi); release_mem_region(0xb0100000, 0x10000); return ret; +} + +static struct device_driver sa1100fb_driver = { + .name = "sa11x0-fb", + .bus = &platform_bus_type, + .probe = sa1100fb_probe, + .suspend = sa1100fb_suspend, + .resume = sa1100fb_resume, +}; + +int __init sa1100fb_init(void) +{ + return driver_register(&sa1100fb_driver); } int __init sa1100fb_setup(char *options) diff -Nru a/drivers/video/sis/sis_main.c b/drivers/video/sis/sis_main.c --- a/drivers/video/sis/sis_main.c Mon Jun 9 23:16:15 2003 +++ b/drivers/video/sis/sis_main.c Mon Jun 9 23:16:15 2003 @@ -134,15 +134,9 @@ if (!init) { init = TRUE; - pci_for_each_dev(pdev) { - DPRINTK("sisfb: Current: 0x%x, target: 0x%x\n", - pdev->device, ivideo.chip_id); - if ((pdev->vendor == PCI_VENDOR_ID_SI) - && (pdev->device == ivideo.chip_id)) { - valid_pdev = TRUE; - break; - } - } + pdev = pci_find_device(PCI_VENDOR_ID_SI, ivideo.chip_id, pdev); + if (pdev) + valid_pdev = TRUE; } if (!valid_pdev) { @@ -192,15 +186,9 @@ break; } - pci_for_each_dev(pdev) { - DPRINTK("Current: 0x%x, target: 0x%x\n", - pdev->device, ivideo.chip_id); - if ((pdev->vendor == PCI_VENDOR_ID_SI) - && (pdev->device == nbridge_id)) { - valid_pdev = TRUE; - break; - } - } + pdev = pci_find_device(PCI_VENDOR_ID_SI, nbridge_id, pdev); + if (pdev) + valid_pdev = TRUE; } if (!valid_pdev) { @@ -2117,40 +2105,36 @@ } else { /* 540, 630, 730 */ - pci_for_each_dev(pdev) { - - if ((pdev->vendor == PCI_VENDOR_ID_SI) - && (pdev->device == nbridge_id)) { - pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS, &pci_data); - pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4; - ivideo.video_size = (unsigned int)(1 << (pci_data+21)); - pdev_valid = 1; - - reg = SIS_DATA_BUS_64 << 6; - switch (pci_data) { - case BRI_DRAM_SIZE_2MB: - reg |= SIS_DRAM_SIZE_2MB; - break; - case BRI_DRAM_SIZE_4MB: - reg |= SIS_DRAM_SIZE_4MB; - break; - case BRI_DRAM_SIZE_8MB: - reg |= SIS_DRAM_SIZE_8MB; - break; - case BRI_DRAM_SIZE_16MB: - reg |= SIS_DRAM_SIZE_16MB; - break; - case BRI_DRAM_SIZE_32MB: - reg |= SIS_DRAM_SIZE_32MB; - break; - case BRI_DRAM_SIZE_64MB: - reg |= SIS_DRAM_SIZE_64MB; - break; - } - outSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg); + pdev = pci_find_device(PCI_VENDOR_ID_SI, nbridge_id, pdev); + if (pdev) { + pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS, &pci_data); + pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4; + ivideo.video_size = (unsigned int)(1 << (pci_data+21)); + pdev_valid = 1; + + reg = SIS_DATA_BUS_64 << 6; + switch (pci_data) { + case BRI_DRAM_SIZE_2MB: + reg |= SIS_DRAM_SIZE_2MB; break; - } - } + case BRI_DRAM_SIZE_4MB: + reg |= SIS_DRAM_SIZE_4MB; + break; + case BRI_DRAM_SIZE_8MB: + reg |= SIS_DRAM_SIZE_8MB; + break; + case BRI_DRAM_SIZE_16MB: + reg |= SIS_DRAM_SIZE_16MB; + break; + case BRI_DRAM_SIZE_32MB: + reg |= SIS_DRAM_SIZE_32MB; + break; + case BRI_DRAM_SIZE_64MB: + reg |= SIS_DRAM_SIZE_64MB; + break; + } + outSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg); + } if (!pdev_valid) return -1; } @@ -2334,12 +2318,10 @@ #ifdef LINUXBIOS - pci_for_each_dev(pdev) { - - if ( (pdev->vendor == PCI_VENDOR_ID_SI) - && ( (pdev->device == PCI_DEVICE_ID_SI_550) || - (pdev->device == PCI_DEVICE_ID_SI_650) || - (pdev->device == PCI_DEVICE_ID_SI_740))) { + while ((pdev = pci_find_device(PCI_VENDOR_ID_SI, PCI_ANY_ID, pdev)) != NULL) { + if ((pdev->device == PCI_DEVICE_ID_SI_550) || + (pdev->device == PCI_DEVICE_ID_SI_650) || + (pdev->device == PCI_DEVICE_ID_SI_740)) { pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS, &pci_data); pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4; @@ -2408,11 +2390,7 @@ "now reading from PCI config\n"); pdev_valid = 0; - pci_for_each_dev(pdev) { - - if ( (pdev->vendor == PCI_VENDOR_ID_SI) - && (pdev->device == PCI_DEVICE_ID_SI_550) ) { - + while ((pdev = pci_find_device(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_550, pdev)) != NULL) { pci_read_config_byte(pdev, IND_BRI_DRAM_STATUS, &pci_data); pci_data = (pci_data & BRI_DRAM_SIZE_MASK) >> 4; @@ -2437,7 +2415,6 @@ return -1; } outSISIDXREG(SISSR, IND_SIS_DRAM_SIZE, reg); - } } if (!pdev_valid) { printk(KERN_INFO "sisfb: Total confusion - No SiS PCI VGA device found?!\n"); @@ -2868,8 +2845,8 @@ unsigned long *write_port = 0; SIS_CMDTYPE cmd_type; #ifndef AGPOFF - agp_kern_info *agp_info; - agp_memory *agp; + struct agp_kern_info *agp_info; + struct agp_memory *agp; u32 agp_phys; #endif #endif @@ -2946,8 +2923,8 @@ #ifndef AGPOFF if (sisfb_queuemode == AGP_CMD_QUEUE) { - agp_info = vmalloc(sizeof(agp_kern_info)); - memset((void*)agp_info, 0x00, sizeof(agp_kern_info)); + agp_info = vmalloc(sizeof(*agp_info)); + memset((void*)agp_info, 0x00, sizeof(*agp_info)); agp_copy_info(agp_info); agp_backend_acquire(); @@ -3785,7 +3762,7 @@ memset(&sis_disp, 0, sizeof(sis_disp)); #endif - pci_for_each_dev(pdev) { + while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { for (b = sisdev_list; b->vendor; b++) { if ((b->vendor == pdev->vendor) && (b->device == pdev->device)) { diff -Nru a/fs/Kconfig b/fs/Kconfig --- a/fs/Kconfig Mon Jun 9 23:16:14 2003 +++ b/fs/Kconfig Mon Jun 9 23:16:14 2003 @@ -1043,7 +1043,7 @@ config JFFS_PROC_FS bool "JFFS stats available in /proc filesystem" - depends on JFFS_FS + depends on JFFS_FS && PROC help Enabling this option will cause statistics from mounted JFFS file systems to be made available to the user in the /proc/fs/jffs/ directory. diff -Nru a/fs/aio.c b/fs/aio.c --- a/fs/aio.c Mon Jun 9 23:16:11 2003 +++ b/fs/aio.c Mon Jun 9 23:16:11 2003 @@ -252,7 +252,7 @@ return ctx; out_cleanup: - atomic_sub(ctx->max_reqs, &aio_nr); /* undone by __put_ioctx */ + atomic_sub(ctx->max_reqs, &aio_nr); ctx->max_reqs = 0; /* prevent __put_ioctx from sub'ing aio_nr */ __put_ioctx(ctx); return ERR_PTR(-EAGAIN); @@ -405,9 +405,6 @@ list_add(&req->ki_list, &ctx->active_reqs); get_ioctx(ctx); ctx->reqs_active++; - req->ki_user_obj = NULL; - req->ki_ctx = ctx; - req->ki_users = 1; okay = 1; } kunmap_atomic(ring, KM_USER0); @@ -949,7 +946,7 @@ goto out; ret = -EINVAL; - if (unlikely(ctx || !nr_events || (int)nr_events < 0)) { + if (unlikely(ctx || (int)nr_events <= 0)) { pr_debug("EINVAL: io_setup: ctx or nr_events > max\n"); goto out; } @@ -984,9 +981,7 @@ return -EINVAL; } -int FASTCALL(io_submit_one(struct kioctx *ctx, struct iocb *user_iocb, - struct iocb *iocb)); -int io_submit_one(struct kioctx *ctx, struct iocb *user_iocb, +int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb, struct iocb *iocb) { struct kiocb *req; @@ -1098,7 +1093,7 @@ * fail with -ENOSYS if not implemented. */ asmlinkage long sys_io_submit(aio_context_t ctx_id, long nr, - struct iocb **iocbpp) + struct iocb __user **iocbpp) { struct kioctx *ctx; long ret = 0; @@ -1116,8 +1111,13 @@ return -EINVAL; } + /* + * AKPM: should this return a partial result if some of the IOs were + * successfully submitted? + */ for (i=0; i<nr; i++) { - struct iocb *user_iocb, tmp; + struct iocb __user *user_iocb; + struct iocb tmp; if (unlikely(__get_user(user_iocb, iocbpp + i))) { ret = -EFAULT; diff -Nru a/fs/attr.c b/fs/attr.c --- a/fs/attr.c Mon Jun 9 23:16:07 2003 +++ b/fs/attr.c Mon Jun 9 23:16:07 2003 @@ -68,13 +68,19 @@ int error = 0; if (ia_valid & ATTR_SIZE) { - if (attr->ia_size != inode->i_size) + if (attr->ia_size != inode->i_size) { error = vmtruncate(inode, attr->ia_size); - if (error || (ia_valid == ATTR_SIZE)) - goto out; + if (error || (ia_valid == ATTR_SIZE)) + goto out; + } else { + /* + * We skipped the truncate but must still update + * timestamps + */ + ia_valid |= ATTR_MTIME|ATTR_CTIME; + } } - lock_kernel(); if (ia_valid & ATTR_UID) inode->i_uid = attr->ia_uid; if (ia_valid & ATTR_GID) @@ -86,12 +92,13 @@ if (ia_valid & ATTR_CTIME) inode->i_ctime = attr->ia_ctime; if (ia_valid & ATTR_MODE) { - inode->i_mode = attr->ia_mode; + umode_t mode = attr->ia_mode; + if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID)) - inode->i_mode &= ~S_ISGID; + mode &= ~S_ISGID; + inode->i_mode = mode; } mark_inode_dirty(inode); - unlock_kernel(); out: return error; } diff -Nru a/fs/binfmt_elf.c b/fs/binfmt_elf.c --- a/fs/binfmt_elf.c Mon Jun 9 23:16:11 2003 +++ b/fs/binfmt_elf.c Mon Jun 9 23:16:11 2003 @@ -135,6 +135,7 @@ int items; elf_addr_t elf_info[40]; int ei_index = 0; + struct task_struct *tsk = current; /* * If this architecture has a platform capability string, copy it @@ -186,10 +187,10 @@ NEW_AUX_ENT(AT_BASE, interp_load_addr); NEW_AUX_ENT(AT_FLAGS, 0); NEW_AUX_ENT(AT_ENTRY, exec->e_entry); - NEW_AUX_ENT(AT_UID, (elf_addr_t) current->uid); - NEW_AUX_ENT(AT_EUID, (elf_addr_t) current->euid); - NEW_AUX_ENT(AT_GID, (elf_addr_t) current->gid); - NEW_AUX_ENT(AT_EGID, (elf_addr_t) current->egid); + NEW_AUX_ENT(AT_UID, (elf_addr_t) tsk->uid); + NEW_AUX_ENT(AT_EUID, (elf_addr_t) tsk->euid); + NEW_AUX_ENT(AT_GID, (elf_addr_t) tsk->gid); + NEW_AUX_ENT(AT_EGID, (elf_addr_t) tsk->egid); if (k_platform) { NEW_AUX_ENT(AT_PLATFORM, (elf_addr_t)(long)u_platform); } diff -Nru a/fs/bio.c b/fs/bio.c --- a/fs/bio.c Mon Jun 9 23:16:14 2003 +++ b/fs/bio.c Mon Jun 9 23:16:14 2003 @@ -38,7 +38,7 @@ * basically we just need to survive */ #define BIO_SPLIT_ENTRIES 8 -static mempool_t *bio_split_pool; +mempool_t *bio_split_pool; struct biovec_pool { int nr_vecs; @@ -53,7 +53,7 @@ * unsigned short */ -#define BV(x) { x, "biovec-" #x } +#define BV(x) { .nr_vecs = x, .name = "biovec-" #x } static struct biovec_pool bvec_array[BIOVEC_NR_POOLS] = { BV(1), BV(4), BV(16), BV(64), BV(128), BV(BIO_MAX_PAGES), }; @@ -538,12 +538,6 @@ bio = __bio_map_user(bdev, uaddr, len, write_to_vm); if (bio) { - if (bio->bi_size < len) { - bio_endio(bio, bio->bi_size, 0); - bio_unmap_user(bio, 0); - return NULL; - } - /* * subtle -- if __bio_map_user() ended up bouncing a bio, * it would normally disappear when its bi_end_io is run. @@ -551,6 +545,12 @@ * reference to it */ bio_get(bio); + + if (bio->bi_size < len) { + bio_endio(bio, bio->bi_size, 0); + bio_unmap_user(bio, 0); + return NULL; + } } return bio; @@ -916,3 +916,4 @@ EXPORT_SYMBOL(bio_unmap_user); EXPORT_SYMBOL(bio_pair_release); EXPORT_SYMBOL(bio_split); +EXPORT_SYMBOL(bio_split_pool); diff -Nru a/fs/buffer.c b/fs/buffer.c --- a/fs/buffer.c Mon Jun 9 23:16:14 2003 +++ b/fs/buffer.c Mon Jun 9 23:16:14 2003 @@ -36,6 +36,7 @@ #include <linux/buffer_head.h> #include <linux/bio.h> #include <linux/notifier.h> +#include <linux/cpu.h> #include <asm/bitops.h> static void invalidate_bh_lrus(void); @@ -821,9 +822,6 @@ SetPageDirty(page); goto out; } - - if (!PageUptodate(page)) - buffer_error(); spin_lock(&mapping->private_lock); if (page_has_buffers(page)) { diff -Nru a/fs/char_dev.c b/fs/char_dev.c --- a/fs/char_dev.c Mon Jun 9 23:16:09 2003 +++ b/fs/char_dev.c Mon Jun 9 23:16:09 2003 @@ -89,6 +89,8 @@ if (cd == NULL) return ERR_PTR(-ENOMEM); + memset(cd, 0, sizeof(struct char_device_struct)); + write_lock_irq(&chrdevs_lock); /* temporary */ @@ -177,10 +179,10 @@ return PTR_ERR(cd); } -int alloc_chrdev_region(dev_t *dev, unsigned count, char *name) +int alloc_chrdev_region(dev_t *dev, unsigned baseminor, unsigned count, char *name) { struct char_device_struct *cd; - cd = __register_chrdev_region(0, 0, count, name); + cd = __register_chrdev_region(0, baseminor, count, name); if (IS_ERR(cd)) return PTR_ERR(cd); *dev = MKDEV(cd->major, cd->baseminor); diff -Nru a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c --- a/fs/cifs/cifsfs.c Mon Jun 9 23:16:13 2003 +++ b/fs/cifs/cifsfs.c Mon Jun 9 23:16:13 2003 @@ -94,13 +94,17 @@ sb->s_blocksize_bits = 14; /* default 2**14 = CIFS_MAX_MSGSIZE */ inode = iget(sb, ROOT_I); - if (!inode) + if (!inode) { + rc = -ENOMEM; goto out_no_root; + } sb->s_root = d_alloc_root(inode); - if (!sb->s_root) + if (!sb->s_root) { + rc = -ENOMEM; goto out_no_root; + } return 0; @@ -114,7 +118,7 @@ unload_nls(cifs_sb->local_nls); if(cifs_sb) kfree(cifs_sb); - return -EINVAL; + return rc; } void @@ -332,7 +336,7 @@ .release = cifs_close, .lock = cifs_lock, .fsync = cifs_fsync, - .flush = cifs_flush, + .flush = cifs_flush, .mmap = cifs_file_mmap, .sendfile = generic_file_sendfile, }; diff -Nru a/fs/cifs/connect.c b/fs/cifs/connect.c --- a/fs/cifs/connect.c Mon Jun 9 23:16:18 2003 +++ b/fs/cifs/connect.c Mon Jun 9 23:16:18 2003 @@ -346,6 +346,7 @@ { char *value; char *data; + int temp_len; memset(vol,0,sizeof(struct smb_vol)); vol->linux_uid = current->uid; /* current->euid instead? */ @@ -398,8 +399,9 @@ "CIFS: invalid path to network resource\n"); return 1; /* needs_arg; */ } - if (strnlen(value, 300) < 300) { - vol->UNC = value; + if ((temp_len = strnlen(value, 300)) < 300) { + vol->UNC = kmalloc(GFP_KERNEL, temp_len); + strcpy(vol->UNC,value); if (strncmp(vol->UNC, "//", 2) == 0) { vol->UNC[0] = '\\'; vol->UNC[1] = '\\'; @@ -472,8 +474,9 @@ printk(KERN_WARNING "CIFS: Missing UNC name for mount target\n"); return 1; } - if (strnlen(devname, 300) < 300) { - vol->UNC = devname; + if ((temp_len = strnlen(devname, 300)) < 300) { + vol->UNC = kmalloc(GFP_KERNEL, temp_len); + strcpy(vol->UNC,devname); if (strncmp(vol->UNC, "//", 2) == 0) { vol->UNC[0] = '\\'; vol->UNC[1] = '\\'; @@ -812,6 +815,8 @@ cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); if (parse_mount_options(mount_data, devname, &volume_info)) { + if(volume_info.UNC) + kfree(volume_info.UNC); FreeXid(xid); return -EINVAL; } @@ -852,6 +857,8 @@ ("Error connecting to IPv4 socket. Aborting operation")); if(csocket != NULL) sock_release(csocket); + if(volume_info.UNC) + kfree(volume_info.UNC); FreeXid(xid); return rc; } @@ -860,6 +867,8 @@ if (srvTcp == NULL) { rc = -ENOMEM; sock_release(csocket); + if(volume_info.UNC) + kfree(volume_info.UNC); FreeXid(xid); return rc; } else { @@ -943,6 +952,8 @@ "", cifs_sb-> local_nls); + if(volume_info.UNC) + kfree(volume_info.UNC); FreeXid(xid); return -ENODEV; } else { @@ -995,7 +1006,8 @@ if (tcon->ses->capabilities & CAP_UNIX) CIFSSMBQFSUnixInfo(xid, tcon, cifs_sb->local_nls); } - + if(volume_info.UNC) + kfree(volume_info.UNC); FreeXid(xid); return rc; } @@ -2293,7 +2305,7 @@ 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); + 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)) - diff -Nru a/fs/cifs/netmisc.c b/fs/cifs/netmisc.c --- a/fs/cifs/netmisc.c Mon Jun 9 23:16:18 2003 +++ b/fs/cifs/netmisc.c Mon Jun 9 23:16:18 2003 @@ -46,7 +46,7 @@ const struct smb_to_posix_error mapping_table_ERRDOS[] = { {ERRbadfunc, -EINVAL}, {ERRbadfile, -ENOENT}, - {ERRbadpath, -ENOENT}, + {ERRbadpath, -ENOTDIR}, {ERRnofids, -EMFILE}, {ERRnoaccess, -EACCES}, {ERRbadfid, -EBADF}, @@ -63,26 +63,29 @@ {ERRnofiles, -ENOENT}, {ERRbadshare, -ETXTBSY}, {ERRlock, -EACCES}, - {ERRfilexists, -EINVAL}, + {ERRunsup, -EINVAL}, + {ERRnosuchshare,-ENXIO}, + {ERRfilexists, -EEXIST}, {ERRinvparm, -EINVAL}, {ERRdiskfull, -ENOSPC}, - {ERRinvnum, -EINVAL}, + {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, -EACCES}, + {ERRbadpw, -EPERM}, {ERRbadtype, -EREMOTE}, {ERRaccess, -EACCES}, {ERRinvtid, -ENXIO}, - {ERRinvnetname, -ENOENT}, + {ERRinvnetname, -ENODEV}, {ERRinvdevice, -ENXIO}, {ERRqfull, -ENOSPC}, {ERRqtoobig, -ENOSPC}, @@ -617,7 +620,7 @@ ERRHRD, ERRgeneral, NT_STATUS_EVENTLOG_CANT_START}, { ERRDOS, ERRnoaccess, NT_STATUS_TRUST_FAILURE}, { ERRHRD, ERRgeneral, NT_STATUS_MUTANT_LIMIT_EXCEEDED}, { - ERRDOS, 2455, NT_STATUS_NETLOGON_NOT_STARTED}, { + 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}, { diff -Nru a/fs/cifs/smberr.h b/fs/cifs/smberr.h --- a/fs/cifs/smberr.h Mon Jun 9 23:16:15 2003 +++ b/fs/cifs/smberr.h Mon Jun 9 23:16:15 2003 @@ -59,7 +59,7 @@ #define ERRfilexists 80 /* The file named in the request already exists. */ #define ERRinvparm 87 #define ERRdiskfull 112 -#define ERRinvnum 123 +#define ERRinvname 123 #define ERRdirnotempty 145 #define ERRnotlocked 158 #define ERRalreadyexists 183 @@ -109,4 +109,5 @@ #define ERRbadclient 2240 #define ERRbadLogonTime 2241 #define ERRpasswordExpired 2242 +#define ERRnetlogonNotStarted 2455 #define ERRnosupport 0xFFFF diff -Nru a/fs/coda/inode.c b/fs/coda/inode.c --- a/fs/coda/inode.c Mon Jun 9 23:16:12 2003 +++ b/fs/coda/inode.c Mon Jun 9 23:16:12 2003 @@ -69,9 +69,9 @@ int coda_init_inodecache(void) { coda_inode_cachep = kmem_cache_create("coda_inode_cache", - sizeof(struct coda_inode_info), - 0, SLAB_HWCACHE_ALIGN||SLAB_RECLAIM_ACCOUNT, - init_once, NULL); + sizeof(struct coda_inode_info), + 0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT, + init_once, NULL); if (coda_inode_cachep == NULL) return -ENOMEM; return 0; diff -Nru a/fs/compat_ioctl.c b/fs/compat_ioctl.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/fs/compat_ioctl.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,2451 @@ +/* + * ioctl32.c: Conversion between 32bit and 64bit native ioctls. + * + * Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com) + * Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be) + * Copyright (C) 2001,2002 Andi Kleen, SuSE Labs + * Copyright (C) 2003 Pavel Machek (pavel@suse.cz) + * + * These routines maintain argument size conversion between 32bit and 64bit + * ioctls. + */ + +#ifdef INCLUDES +#include <linux/config.h> +#include <linux/types.h> +#include <linux/compat.h> +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> +#include <linux/ioctl.h> +#include <linux/if.h> +#include <linux/slab.h> +#include <linux/hdreg.h> +#include <linux/raid/md.h> +#include <linux/kd.h> +#include <linux/dirent.h> +#include <linux/route.h> +#include <linux/in6.h> +#include <linux/ipv6_route.h> +#include <linux/skbuff.h> +#include <linux/netlink.h> +#include <linux/vt.h> +#include <linux/fs.h> +#include <linux/file.h> +#include <linux/fd.h> +#include <linux/ppp_defs.h> +#include <linux/if_ppp.h> +#include <linux/if_pppox.h> +#include <linux/mtio.h> +#include <linux/cdrom.h> +#include <linux/loop.h> +#include <linux/auto_fs.h> +#include <linux/auto_fs4.h> +#include <linux/devfs_fs.h> +#include <linux/tty.h> +#include <linux/vt_kern.h> +#include <linux/fb.h> +#include <linux/ext2_fs.h> +#include <linux/videodev.h> +#include <linux/netdevice.h> +#include <linux/raw.h> +#include <linux/smb_fs.h> +#include <linux/blkpg.h> +#include <linux/blk.h> +#include <linux/elevator.h> +#include <linux/rtc.h> +#include <linux/pci.h> +#include <linux/rtc.h> +#include <linux/module.h> +#include <linux/serial.h> +#include <linux/reiserfs_fs.h> +#include <linux/if_tun.h> +#include <linux/dirent.h> +#include <linux/ctype.h> +#include <linux/ioctl32.h> + +#include <net/sock.h> /* siocdevprivate_ioctl */ +#include <net/bluetooth/bluetooth.h> +#include <net/bluetooth/rfcomm.h> +#include <net/bluetooth/hci.h> + +#include <scsi/scsi.h> +/* Ugly hack. */ +#undef __KERNEL__ +#include <scsi/scsi_ioctl.h> +#define __KERNEL__ +#include <scsi/sg.h> + +#include <asm/types.h> +#include <asm/uaccess.h> +#include <linux/ethtool.h> +#include <linux/mii.h> +#include <linux/if_bonding.h> +#include <linux/watchdog.h> +#include <linux/dm-ioctl.h> + +#include <asm/module.h> +#include <linux/soundcard.h> +#include <linux/lp.h> + +#include <linux/atm.h> +#include <linux/atmarp.h> +#include <linux/atmclip.h> +#include <linux/atmdev.h> +#include <linux/atmioc.h> +#include <linux/atmlec.h> +#include <linux/atmmpc.h> +#include <linux/atmsvc.h> +#include <linux/atm_tcp.h> +#include <linux/sonet.h> +#include <linux/atm_suni.h> +#include <linux/mtd/mtd.h> + +#include <linux/usb.h> +#include <linux/usbdevice_fs.h> +#include <linux/nbd.h> +#include <linux/random.h> +#include <linux/filter.h> + +#undef INCLUDES +#endif + +#ifdef CODE + +/* Aiee. Someone does not find a difference between int and long */ +#define EXT2_IOC32_GETFLAGS _IOR('f', 1, int) +#define EXT2_IOC32_SETFLAGS _IOW('f', 2, int) +#define EXT2_IOC32_GETVERSION _IOR('v', 1, int) +#define EXT2_IOC32_SETVERSION _IOW('v', 2, int) + +static int w_long(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + mm_segment_t old_fs = get_fs(); + int err; + unsigned long val; + + set_fs (KERNEL_DS); + err = sys_ioctl(fd, cmd, (unsigned long)&val); + set_fs (old_fs); + if (!err && put_user(val, (u32 *)arg)) + return -EFAULT; + return err; +} + +static int rw_long(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + mm_segment_t old_fs = get_fs(); + int err; + unsigned long val; + + if(get_user(val, (u32 *)arg)) + return -EFAULT; + set_fs (KERNEL_DS); + err = sys_ioctl(fd, cmd, (unsigned long)&val); + set_fs (old_fs); + if (!err && put_user(val, (u32 *)arg)) + return -EFAULT; + return err; +} + +static int do_ext2_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + /* These are just misnamed, they actually get/put from/to user an int */ + switch (cmd) { + case EXT2_IOC32_GETFLAGS: cmd = EXT2_IOC_GETFLAGS; break; + case EXT2_IOC32_SETFLAGS: cmd = EXT2_IOC_SETFLAGS; break; + case EXT2_IOC32_GETVERSION: cmd = EXT2_IOC_GETVERSION; break; + case EXT2_IOC32_SETVERSION: cmd = EXT2_IOC_SETVERSION; break; + } + return sys_ioctl(fd, cmd, arg); +} + +struct video_tuner32 { + compat_int_t tuner; + char name[32]; + compat_ulong_t rangelow, rangehigh; + u32 flags; /* It is really u32 in videodev.h */ + u16 mode, signal; +}; + +static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 *up) +{ + int i; + + if(get_user(kp->tuner, &up->tuner)) + return -EFAULT; + for(i = 0; i < 32; i++) + __get_user(kp->name[i], &up->name[i]); + __get_user(kp->rangelow, &up->rangelow); + __get_user(kp->rangehigh, &up->rangehigh); + __get_user(kp->flags, &up->flags); + __get_user(kp->mode, &up->mode); + __get_user(kp->signal, &up->signal); + return 0; +} + +static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 *up) +{ + int i; + + if(put_user(kp->tuner, &up->tuner)) + return -EFAULT; + for(i = 0; i < 32; i++) + __put_user(kp->name[i], &up->name[i]); + __put_user(kp->rangelow, &up->rangelow); + __put_user(kp->rangehigh, &up->rangehigh); + __put_user(kp->flags, &up->flags); + __put_user(kp->mode, &up->mode); + __put_user(kp->signal, &up->signal); + return 0; +} + +struct video_buffer32 { + compat_caddr_t base; + compat_int_t height, width, depth, bytesperline; +}; + +static int get_video_buffer32(struct video_buffer *kp, struct video_buffer32 *up) +{ + u32 tmp; + + if(get_user(tmp, &up->base)) + return -EFAULT; + kp->base = (void *) ((unsigned long)tmp); + __get_user(kp->height, &up->height); + __get_user(kp->width, &up->width); + __get_user(kp->depth, &up->depth); + __get_user(kp->bytesperline, &up->bytesperline); + return 0; +} + +static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 *up) +{ + u32 tmp = (u32)((unsigned long)kp->base); + + if(put_user(tmp, &up->base)) + return -EFAULT; + __put_user(kp->height, &up->height); + __put_user(kp->width, &up->width); + __put_user(kp->depth, &up->depth); + __put_user(kp->bytesperline, &up->bytesperline); + return 0; +} + +struct video_clip32 { + s32 x, y, width, height; /* Its really s32 in videodev.h */ + compat_caddr_t next; +}; + +struct video_window32 { + u32 x, y, width, height, chromakey, flags; + compat_caddr_t clips; + compat_int_t clipcount; +}; + +static void free_kvideo_clips(struct video_window *kp) +{ + struct video_clip *cp; + + cp = kp->clips; + if(cp != NULL) + kfree(cp); +} + +static int get_video_window32(struct video_window *kp, struct video_window32 *up) +{ + struct video_clip32 *ucp; + struct video_clip *kcp; + int nclips, err, i; + u32 tmp; + + if(get_user(kp->x, &up->x)) + return -EFAULT; + __get_user(kp->y, &up->y); + __get_user(kp->width, &up->width); + __get_user(kp->height, &up->height); + __get_user(kp->chromakey, &up->chromakey); + __get_user(kp->flags, &up->flags); + __get_user(kp->clipcount, &up->clipcount); + __get_user(tmp, &up->clips); + ucp = compat_ptr(tmp); + kp->clips = NULL; + + nclips = kp->clipcount; + if(nclips == 0) + return 0; + + if(ucp == 0) + return -EINVAL; + + /* Peculiar interface... */ + if(nclips < 0) + nclips = VIDEO_CLIPMAP_SIZE; + + kcp = kmalloc(nclips * sizeof(struct video_clip), GFP_KERNEL); + err = -ENOMEM; + if(kcp == NULL) + goto cleanup_and_err; + + kp->clips = kcp; + for(i = 0; i < nclips; i++) { + __get_user(kcp[i].x, &ucp[i].x); + __get_user(kcp[i].y, &ucp[i].y); + __get_user(kcp[i].width, &ucp[i].width); + __get_user(kcp[i].height, &ucp[i].height); + kcp[nclips].next = NULL; + } + + return 0; + +cleanup_and_err: + free_kvideo_clips(kp); + return err; +} + +/* You get back everything except the clips... */ +static int put_video_window32(struct video_window *kp, struct video_window32 *up) +{ + if(put_user(kp->x, &up->x)) + return -EFAULT; + __put_user(kp->y, &up->y); + __put_user(kp->width, &up->width); + __put_user(kp->height, &up->height); + __put_user(kp->chromakey, &up->chromakey); + __put_user(kp->flags, &up->flags); + __put_user(kp->clipcount, &up->clipcount); + return 0; +} + +#define VIDIOCGTUNER32 _IOWR('v',4, struct video_tuner32) +#define VIDIOCSTUNER32 _IOW('v',5, struct video_tuner32) +#define VIDIOCGWIN32 _IOR('v',9, struct video_window32) +#define VIDIOCSWIN32 _IOW('v',10, struct video_window32) +#define VIDIOCGFBUF32 _IOR('v',11, struct video_buffer32) +#define VIDIOCSFBUF32 _IOW('v',12, struct video_buffer32) +#define VIDIOCGFREQ32 _IOR('v',14, u32) +#define VIDIOCSFREQ32 _IOW('v',15, u32) + +static int do_video_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + union { + struct video_tuner vt; + struct video_buffer vb; + struct video_window vw; + unsigned long vx; + } karg; + mm_segment_t old_fs = get_fs(); + void *up = (void *)arg; + int err = 0; + + /* First, convert the command. */ + switch(cmd) { + case VIDIOCGTUNER32: cmd = VIDIOCGTUNER; break; + case VIDIOCSTUNER32: cmd = VIDIOCSTUNER; break; + case VIDIOCGWIN32: cmd = VIDIOCGWIN; break; + case VIDIOCSWIN32: cmd = VIDIOCSWIN; break; + case VIDIOCGFBUF32: cmd = VIDIOCGFBUF; break; + case VIDIOCSFBUF32: cmd = VIDIOCSFBUF; break; + case VIDIOCGFREQ32: cmd = VIDIOCGFREQ; break; + case VIDIOCSFREQ32: cmd = VIDIOCSFREQ; break; + }; + + switch(cmd) { + case VIDIOCSTUNER: + case VIDIOCGTUNER: + err = get_video_tuner32(&karg.vt, up); + break; + + case VIDIOCSWIN: + err = get_video_window32(&karg.vw, up); + break; + + case VIDIOCSFBUF: + err = get_video_buffer32(&karg.vb, up); + break; + + case VIDIOCSFREQ: + err = get_user(karg.vx, (u32 *)up); + break; + }; + if(err) + goto out; + + set_fs(KERNEL_DS); + err = sys_ioctl(fd, cmd, (unsigned long)&karg); + set_fs(old_fs); + + if(cmd == VIDIOCSWIN) + free_kvideo_clips(&karg.vw); + + if(err == 0) { + switch(cmd) { + case VIDIOCGTUNER: + err = put_video_tuner32(&karg.vt, up); + break; + + case VIDIOCGWIN: + err = put_video_window32(&karg.vw, up); + break; + + case VIDIOCGFBUF: + err = put_video_buffer32(&karg.vb, up); + break; + + case VIDIOCGFREQ: + err = put_user(((u32)karg.vx), (u32 *)up); + break; + }; + } +out: + return err; +} + +static int do_siocgstamp(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct compat_timeval *up = (struct compat_timeval *)arg; + struct timeval ktv; + mm_segment_t old_fs = get_fs(); + int err; + + set_fs(KERNEL_DS); + err = sys_ioctl(fd, cmd, (unsigned long)&ktv); + set_fs(old_fs); + if(!err) { + err = put_user(ktv.tv_sec, &up->tv_sec); + err |= __put_user(ktv.tv_usec, &up->tv_usec); + } + return err; +} + +struct ifmap32 { + compat_ulong_t mem_start; + compat_ulong_t mem_end; + unsigned short base_addr; + unsigned char irq; + unsigned char dma; + unsigned char port; +}; + +struct ifreq32 { +#define IFHWADDRLEN 6 +#define IFNAMSIZ 16 + union { + char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */ + } ifr_ifrn; + union { + struct sockaddr ifru_addr; + struct sockaddr ifru_dstaddr; + struct sockaddr ifru_broadaddr; + struct sockaddr ifru_netmask; + struct sockaddr ifru_hwaddr; + short ifru_flags; + compat_int_t ifru_ivalue; + compat_int_t ifru_mtu; + struct ifmap32 ifru_map; + char ifru_slave[IFNAMSIZ]; /* Just fits the size */ + char ifru_newname[IFNAMSIZ]; + compat_caddr_t ifru_data; + /* XXXX? ifru_settings should be here */ + } ifr_ifru; +}; + +struct ifconf32 { + compat_int_t ifc_len; /* size of buffer */ + compat_caddr_t ifcbuf; +}; + +#ifdef CONFIG_NET +static int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct net_device *dev; + struct ifreq32 ifr32; + int err; + + if (copy_from_user(&ifr32, (struct ifreq32 *)arg, sizeof(struct ifreq32))) + return -EFAULT; + + dev = dev_get_by_index(ifr32.ifr_ifindex); + if (!dev) + return -ENODEV; + + strlcpy(ifr32.ifr_name, dev->name, sizeof(ifr32.ifr_name)); + dev_put(dev); + + err = copy_to_user((struct ifreq32 *)arg, &ifr32, sizeof(struct ifreq32)); + return (err ? -EFAULT : 0); +} +#endif + +static int dev_ifconf(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct ifconf32 ifc32; + struct ifconf ifc; + struct ifreq32 *ifr32; + struct ifreq *ifr; + mm_segment_t old_fs; + unsigned int i, j; + int err; + + if (copy_from_user(&ifc32, (struct ifconf32 *)arg, sizeof(struct ifconf32))) + return -EFAULT; + + if(ifc32.ifcbuf == 0) { + ifc32.ifc_len = 0; + ifc.ifc_len = 0; + ifc.ifc_buf = NULL; + } else { + ifc.ifc_len = ((ifc32.ifc_len / sizeof (struct ifreq32)) + 1) * + sizeof (struct ifreq); + ifc.ifc_buf = kmalloc (ifc.ifc_len, GFP_KERNEL); + if (!ifc.ifc_buf) + return -ENOMEM; + } + ifr = ifc.ifc_req; + ifr32 = compat_ptr(ifc32.ifcbuf); + for (i = 0; i < ifc32.ifc_len; i += sizeof (struct ifreq32)) { + if (copy_from_user(ifr, ifr32, sizeof (struct ifreq32))) { + kfree (ifc.ifc_buf); + return -EFAULT; + } + ifr++; + ifr32++; + } + old_fs = get_fs(); set_fs (KERNEL_DS); + err = sys_ioctl (fd, SIOCGIFCONF, (unsigned long)&ifc); + set_fs (old_fs); + if (!err) { + ifr = ifc.ifc_req; + ifr32 = compat_ptr(ifc32.ifcbuf); + for (i = 0, j = 0; i < ifc32.ifc_len && j < ifc.ifc_len; + i += sizeof (struct ifreq32), j += sizeof (struct ifreq)) { + int k = copy_to_user(ifr32, ifr, sizeof (struct ifreq32)); + ifr32++; + ifr++; + if (k) { + err = -EFAULT; + break; + } + + } + if (!err) { + if (ifc32.ifcbuf == 0) { + /* Translate from 64-bit structure multiple to + * a 32-bit one. + */ + i = ifc.ifc_len; + i = ((i / sizeof(struct ifreq)) * sizeof(struct ifreq32)); + ifc32.ifc_len = i; + } else { + if (i <= ifc32.ifc_len) + ifc32.ifc_len = i; + else + ifc32.ifc_len = i - sizeof (struct ifreq32); + } + if (copy_to_user((struct ifconf32 *)arg, &ifc32, sizeof(struct ifconf32))) + err = -EFAULT; + } + } + if(ifc.ifc_buf != NULL) + kfree (ifc.ifc_buf); + return err; +} + +static int ethtool_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct ifreq *ifr; + struct ifreq32 *ifr32; + u32 data; + void *datap; + + ifr = compat_alloc_user_space(sizeof(*ifr)); + ifr32 = (struct ifreq32 *) arg; + + if (copy_in_user(&ifr->ifr_name, &ifr32->ifr_name, IFNAMSIZ)) + return -EFAULT; + + if (get_user(data, &ifr32->ifr_ifru.ifru_data)) + return -EFAULT; + + datap = (void *) (unsigned long) data; + if (put_user(datap, &ifr->ifr_ifru.ifru_data)) + return -EFAULT; + + return sys_ioctl(fd, cmd, (unsigned long) ifr); +} + +static int bond_ioctl(unsigned long fd, unsigned int cmd, unsigned long arg) +{ + struct ifreq ifr; + mm_segment_t old_fs; + int err, len; + u32 data; + + if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32))) + return -EFAULT; + ifr.ifr_data = (__kernel_caddr_t)get_zeroed_page(GFP_KERNEL); + if (!ifr.ifr_data) + return -EAGAIN; + + switch (cmd) { + case SIOCBONDENSLAVE: + case SIOCBONDRELEASE: + case SIOCBONDSETHWADDR: + case SIOCBONDCHANGEACTIVE: + len = IFNAMSIZ * sizeof(char); + break; + case SIOCBONDSLAVEINFOQUERY: + len = sizeof(struct ifslave); + break; + case SIOCBONDINFOQUERY: + len = sizeof(struct ifbond); + break; + default: + err = -EINVAL; + goto out; + }; + + __get_user(data, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_data)); + if (copy_from_user(ifr.ifr_data, compat_ptr(data), len)) { + err = -EFAULT; + goto out; + } + + old_fs = get_fs(); + set_fs (KERNEL_DS); + err = sys_ioctl (fd, cmd, (unsigned long)&ifr); + set_fs (old_fs); + if (!err) { + len = copy_to_user(compat_ptr(data), ifr.ifr_data, len); + if (len) + err = -EFAULT; + } + +out: + free_page((unsigned long)ifr.ifr_data); + return err; +} + +int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct ifreq *u_ifreq64; + struct ifreq32 *u_ifreq32 = (struct ifreq32 *) arg; + char tmp_buf[IFNAMSIZ]; + void *data64; + u32 data32; + + if (copy_from_user(&tmp_buf[0], &(u_ifreq32->ifr_ifrn.ifrn_name[0]), + IFNAMSIZ)) + return -EFAULT; + if (__get_user(data32, &u_ifreq32->ifr_ifru.ifru_data)) + return -EFAULT; + data64 = compat_ptr(data32); + + u_ifreq64 = compat_alloc_user_space(sizeof(*u_ifreq64)); + + /* Don't check these user accesses, just let that get trapped + * in the ioctl handler instead. + */ + copy_to_user(&u_ifreq64->ifr_ifrn.ifrn_name[0], &tmp_buf[0], IFNAMSIZ); + __put_user(data64, &u_ifreq64->ifr_ifru.ifru_data); + + return sys_ioctl(fd, cmd, (unsigned long) u_ifreq64); +} + +static int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct ifreq ifr; + mm_segment_t old_fs; + int err; + + switch (cmd) { + case SIOCSIFMAP: + err = copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(ifr.ifr_name)); + err |= __get_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_start)); + err |= __get_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_end)); + err |= __get_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.base_addr)); + err |= __get_user(ifr.ifr_map.irq, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.irq)); + err |= __get_user(ifr.ifr_map.dma, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.dma)); + err |= __get_user(ifr.ifr_map.port, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.port)); + if (err) + return -EFAULT; + break; + default: + if (copy_from_user(&ifr, (struct ifreq32 *)arg, sizeof(struct ifreq32))) + return -EFAULT; + break; + } + old_fs = get_fs(); + set_fs (KERNEL_DS); + err = sys_ioctl (fd, cmd, (unsigned long)&ifr); + set_fs (old_fs); + if (!err) { + switch (cmd) { + case SIOCGIFFLAGS: + case SIOCGIFMETRIC: + case SIOCGIFMTU: + case SIOCGIFMEM: + case SIOCGIFHWADDR: + case SIOCGIFINDEX: + case SIOCGIFADDR: + case SIOCGIFBRDADDR: + case SIOCGIFDSTADDR: + case SIOCGIFNETMASK: + case SIOCGIFTXQLEN: + if (copy_to_user((struct ifreq32 *)arg, &ifr, sizeof(struct ifreq32))) + return -EFAULT; + break; + case SIOCGIFMAP: + err = copy_to_user((struct ifreq32 *)arg, &ifr, sizeof(ifr.ifr_name)); + err |= __put_user(ifr.ifr_map.mem_start, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_start)); + err |= __put_user(ifr.ifr_map.mem_end, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.mem_end)); + err |= __put_user(ifr.ifr_map.base_addr, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.base_addr)); + err |= __put_user(ifr.ifr_map.irq, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.irq)); + err |= __put_user(ifr.ifr_map.dma, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.dma)); + err |= __put_user(ifr.ifr_map.port, &(((struct ifreq32 *)arg)->ifr_ifru.ifru_map.port)); + if (err) + err = -EFAULT; + break; + } + } + return err; +} + +struct rtentry32 { + u32 rt_pad1; + struct sockaddr rt_dst; /* target address */ + struct sockaddr rt_gateway; /* gateway addr (RTF_GATEWAY) */ + struct sockaddr rt_genmask; /* target network mask (IP) */ + unsigned short rt_flags; + short rt_pad2; + u32 rt_pad3; + unsigned char rt_tos; + unsigned char rt_class; + short rt_pad4; + short rt_metric; /* +1 for binary compatibility! */ + /* char * */ u32 rt_dev; /* forcing the device at add */ + u32 rt_mtu; /* per route MTU/Window */ + u32 rt_window; /* Window clamping */ + unsigned short rt_irtt; /* Initial RTT */ + +}; + +struct in6_rtmsg32 { + struct in6_addr rtmsg_dst; + struct in6_addr rtmsg_src; + struct in6_addr rtmsg_gateway; + u32 rtmsg_type; + u16 rtmsg_dst_len; + u16 rtmsg_src_len; + u32 rtmsg_metric; + u32 rtmsg_info; + u32 rtmsg_flags; + s32 rtmsg_ifindex; +}; + +static int routing_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + int ret; + void *r = NULL; + struct in6_rtmsg r6; + struct rtentry r4; + char devname[16]; + u32 rtdev; + mm_segment_t old_fs = get_fs(); + + struct socket *mysock = sockfd_lookup(fd, &ret); + + if (mysock && mysock->sk && mysock->sk->sk_family == AF_INET6) { /* ipv6 */ + ret = copy_from_user (&r6.rtmsg_dst, &(((struct in6_rtmsg32 *)arg)->rtmsg_dst), + 3 * sizeof(struct in6_addr)); + ret |= __get_user (r6.rtmsg_type, &(((struct in6_rtmsg32 *)arg)->rtmsg_type)); + ret |= __get_user (r6.rtmsg_dst_len, &(((struct in6_rtmsg32 *)arg)->rtmsg_dst_len)); + ret |= __get_user (r6.rtmsg_src_len, &(((struct in6_rtmsg32 *)arg)->rtmsg_src_len)); + ret |= __get_user (r6.rtmsg_metric, &(((struct in6_rtmsg32 *)arg)->rtmsg_metric)); + ret |= __get_user (r6.rtmsg_info, &(((struct in6_rtmsg32 *)arg)->rtmsg_info)); + ret |= __get_user (r6.rtmsg_flags, &(((struct in6_rtmsg32 *)arg)->rtmsg_flags)); + ret |= __get_user (r6.rtmsg_ifindex, &(((struct in6_rtmsg32 *)arg)->rtmsg_ifindex)); + + r = (void *) &r6; + } else { /* ipv4 */ + ret = copy_from_user (&r4.rt_dst, &(((struct rtentry32 *)arg)->rt_dst), 3 * sizeof(struct sockaddr)); + ret |= __get_user (r4.rt_flags, &(((struct rtentry32 *)arg)->rt_flags)); + ret |= __get_user (r4.rt_metric, &(((struct rtentry32 *)arg)->rt_metric)); + ret |= __get_user (r4.rt_mtu, &(((struct rtentry32 *)arg)->rt_mtu)); + ret |= __get_user (r4.rt_window, &(((struct rtentry32 *)arg)->rt_window)); + ret |= __get_user (r4.rt_irtt, &(((struct rtentry32 *)arg)->rt_irtt)); + ret |= __get_user (rtdev, &(((struct rtentry32 *)arg)->rt_dev)); + if (rtdev) { + ret |= copy_from_user (devname, compat_ptr(rtdev), 15); + r4.rt_dev = devname; devname[15] = 0; + } else + r4.rt_dev = 0; + + r = (void *) &r4; + } + + if (ret) + return -EFAULT; + + set_fs (KERNEL_DS); + ret = sys_ioctl (fd, cmd, (long) r); + set_fs (old_fs); + + if (mysock) + sockfd_put(mysock); + + return ret; +} + +struct hd_geometry32 { + unsigned char heads; + unsigned char sectors; + unsigned short cylinders; + u32 start; +}; + +static int hdio_getgeo(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + mm_segment_t old_fs = get_fs(); + struct hd_geometry geo; + int err; + + set_fs (KERNEL_DS); + err = sys_ioctl(fd, HDIO_GETGEO, (unsigned long)&geo); + set_fs (old_fs); + if (!err) { + err = copy_to_user ((struct hd_geometry32 *)arg, &geo, 4); + err |= __put_user (geo.start, &(((struct hd_geometry32 *)arg)->start)); + } + return err ? -EFAULT : 0; +} + +struct fb_fix_screeninfo32 { + char id[16]; + compat_caddr_t smem_start; + u32 smem_len; + u32 type; + u32 type_aux; + u32 visual; + u16 xpanstep; + u16 ypanstep; + u16 ywrapstep; + u32 line_length; + compat_caddr_t mmio_start; + u32 mmio_len; + u32 accel; + u16 reserved[3]; +}; + +struct fb_cmap32 { + u32 start; + u32 len; + compat_caddr_t red; + compat_caddr_t green; + compat_caddr_t blue; + compat_caddr_t transp; +}; + +static int do_cmap_ptr(__u16 **ptr64, __u32 *ptr32) +{ + __u32 data; + void *datap; + + if (get_user(data, ptr32)) + return -EFAULT; + datap = (void *) (unsigned long) data; + if (put_user(datap, ptr64)) + return -EFAULT; + return 0; +} + +static int fb_getput_cmap(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct fb_cmap *cmap; + struct fb_cmap32 *cmap32; + int err; + + cmap = compat_alloc_user_space(sizeof(*cmap)); + cmap32 = (struct fb_cmap32 *) arg; + + if (copy_in_user(&cmap->start, &cmap32->start, 2 * sizeof(__u32))) + return -EFAULT; + + if (do_cmap_ptr(&cmap->red, &cmap32->red) || + do_cmap_ptr(&cmap->green, &cmap32->green) || + do_cmap_ptr(&cmap->blue, &cmap32->blue) || + do_cmap_ptr(&cmap->transp, &cmap32->transp)) + return -EFAULT; + + err = sys_ioctl(fd, cmd, (unsigned long) cmap); + + if (!err) { + if (copy_in_user(&cmap32->start, + &cmap->start, + 2 * sizeof(__u32))) + err = -EFAULT; + } + return err; +} + +static int do_fscreeninfo_to_user(struct fb_fix_screeninfo *fix, + struct fb_fix_screeninfo32 *fix32) +{ + __u32 data; + int err; + + err = copy_to_user(&fix32->id, &fix->id, sizeof(fix32->id)); + + data = (__u32) (unsigned long) fix->smem_start; + err |= put_user(data, &fix32->smem_start); + + err |= put_user(fix->smem_len, &fix32->smem_len); + err |= put_user(fix->type, &fix32->type); + err |= put_user(fix->type_aux, &fix32->type_aux); + err |= put_user(fix->visual, &fix32->visual); + err |= put_user(fix->xpanstep, &fix32->xpanstep); + err |= put_user(fix->ypanstep, &fix32->ypanstep); + err |= put_user(fix->ywrapstep, &fix32->ywrapstep); + err |= put_user(fix->line_length, &fix32->line_length); + + data = (__u32) (unsigned long) fix->mmio_start; + err |= put_user(data, &fix32->mmio_start); + + err |= put_user(fix->mmio_len, &fix32->mmio_len); + err |= put_user(fix->accel, &fix32->accel); + err |= copy_to_user(fix32->reserved, fix->reserved, + sizeof(fix->reserved)); + + return err; +} + +static int fb_get_fscreeninfo(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + mm_segment_t old_fs; + struct fb_fix_screeninfo fix; + struct fb_fix_screeninfo32 *fix32; + int err; + + fix32 = (struct fb_fix_screeninfo32 *) arg; + + old_fs = get_fs(); + set_fs(KERNEL_DS); + err = sys_ioctl(fd, cmd, (unsigned long) &fix); + set_fs(old_fs); + + if (!err) + err = do_fscreeninfo_to_user(&fix, fix32); + + return err; +} + +static int fb_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + int err; + + switch (cmd) { + case FBIOGET_FSCREENINFO: + err = fb_get_fscreeninfo(fd,cmd, arg); + break; + + case FBIOGETCMAP: + case FBIOPUTCMAP: + err = fb_getput_cmap(fd, cmd, arg); + break; + + default: + do { + static int count; + if (++count <= 20) + printk("%s: Unknown fb ioctl cmd fd(%d) " + "cmd(%08x) arg(%08lx)\n", + __FUNCTION__, fd, cmd, arg); + } while(0); + err = -ENOSYS; + break; + }; + + return err; +} + +static int hdio_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + mm_segment_t old_fs = get_fs(); + unsigned long kval; + unsigned int *uvp; + int error; + + set_fs(KERNEL_DS); + error = sys_ioctl(fd, cmd, (long)&kval); + set_fs(old_fs); + + if(error == 0) { + uvp = (unsigned int *)arg; + if(put_user(kval, uvp)) + error = -EFAULT; + } + return error; +} + + +typedef struct sg_io_hdr32 { + compat_int_t interface_id; /* [i] 'S' for SCSI generic (required) */ + compat_int_t dxfer_direction; /* [i] data transfer direction */ + unsigned char cmd_len; /* [i] SCSI command length ( <= 16 bytes) */ + unsigned char mx_sb_len; /* [i] max length to write to sbp */ + unsigned short iovec_count; /* [i] 0 implies no scatter gather */ + compat_uint_t dxfer_len; /* [i] byte count of data transfer */ + compat_uint_t dxferp; /* [i], [*io] points to data transfer memory + or scatter gather list */ + compat_uptr_t cmdp; /* [i], [*i] points to command to perform */ + compat_uptr_t sbp; /* [i], [*o] points to sense_buffer memory */ + compat_uint_t timeout; /* [i] MAX_UINT->no timeout (unit: millisec) */ + compat_uint_t flags; /* [i] 0 -> default, see SG_FLAG... */ + compat_int_t pack_id; /* [i->o] unused internally (normally) */ + compat_uptr_t usr_ptr; /* [i->o] unused internally */ + unsigned char status; /* [o] scsi status */ + unsigned char masked_status; /* [o] shifted, masked scsi status */ + unsigned char msg_status; /* [o] messaging level data (optional) */ + unsigned char sb_len_wr; /* [o] byte count actually written to sbp */ + unsigned short host_status; /* [o] errors from host adapter */ + unsigned short driver_status; /* [o] errors from software driver */ + compat_int_t resid; /* [o] dxfer_len - actual_transferred */ + compat_uint_t duration; /* [o] time taken by cmd (unit: millisec) */ + compat_uint_t info; /* [o] auxiliary information */ +} sg_io_hdr32_t; /* 64 bytes long (on sparc32) */ + +typedef struct sg_iovec32 { + compat_uint_t iov_base; + compat_uint_t iov_len; +} sg_iovec32_t; + +static int sg_build_iovec(sg_io_hdr_t *sgio, void *dxferp, u16 iovec_count) +{ + sg_iovec_t *iov = (sg_iovec_t *) (sgio + 1); + sg_iovec32_t *iov32 = dxferp; + int i; + + for (i = 0; i < iovec_count; i++) { + u32 base, len; + + if (get_user(base, &iov32[i].iov_base) || + get_user(len, &iov32[i].iov_len) || + put_user((void *)(unsigned long)base, &iov[i].iov_base) || + put_user(len, &iov[i].iov_len)) + return -EFAULT; + } + + return 0; +} + +static int sg_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + sg_io_hdr_t *sgio; + sg_io_hdr32_t *sgio32; + u16 iovec_count; + u32 data; + void *dxferp; + int err; + + sgio32 = (sg_io_hdr32_t *) arg; + if (get_user(iovec_count, &sgio32->iovec_count)) + return -EFAULT; + + { + void *new, *top; + + top = compat_alloc_user_space(0); + new = compat_alloc_user_space(sizeof(sg_io_hdr_t) + + (iovec_count * + sizeof(sg_iovec_t))); + if (new > top) + return -EINVAL; + + sgio = new; + } + + /* Ok, now construct. */ + if (copy_in_user(&sgio->interface_id, &sgio32->interface_id, + (2 * sizeof(int)) + + (2 * sizeof(unsigned char)) + + (1 * sizeof(unsigned short)) + + (1 * sizeof(unsigned int)))) + return -EFAULT; + + if (get_user(data, &sgio32->dxferp)) + return -EFAULT; + dxferp = (void *) (unsigned long) data; + if (iovec_count) { + if (sg_build_iovec(sgio, dxferp, iovec_count)) + return -EFAULT; + } else { + if (put_user(dxferp, &sgio->dxferp)) + return -EFAULT; + } + + { + unsigned char *cmdp, *sbp; + + if (get_user(data, &sgio32->cmdp)) + return -EFAULT; + cmdp = (unsigned char *) (unsigned long) data; + + if (get_user(data, &sgio32->sbp)) + return -EFAULT; + sbp = (unsigned char *) (unsigned long) data; + + if (put_user(cmdp, &sgio->cmdp) || + put_user(sbp, &sgio->sbp)) + return -EFAULT; + } + + if (copy_in_user(&sgio->timeout, &sgio32->timeout, + 3 * sizeof(int))) + return -EFAULT; + + if (get_user(data, &sgio32->usr_ptr)) + return -EFAULT; + if (put_user((void *)(unsigned long)data, &sgio->usr_ptr)) + return -EFAULT; + + if (copy_in_user(&sgio->status, &sgio32->status, + (4 * sizeof(unsigned char)) + + (2 * sizeof(unsigned (short))) + + (3 * sizeof(int)))) + return -EFAULT; + + err = sys_ioctl(fd, cmd, (unsigned long) sgio); + + if (err >= 0) { + void *datap; + + if (copy_in_user(&sgio32->pack_id, &sgio->pack_id, + sizeof(int)) || + get_user(datap, &sgio->usr_ptr) || + put_user((u32)(unsigned long)datap, + &sgio32->usr_ptr) || + copy_in_user(&sgio32->status, &sgio->status, + (4 * sizeof(unsigned char)) + + (2 * sizeof(unsigned short)) + + (3 * sizeof(int)))) + err = -EFAULT; + } + + return err; +} + +struct sock_fprog32 { + unsigned short len; + compat_caddr_t filter; +}; + +#define PPPIOCSPASS32 _IOW('t', 71, struct sock_fprog32) +#define PPPIOCSACTIVE32 _IOW('t', 70, struct sock_fprog32) + +static int ppp_sock_fprog_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct sock_fprog32 *u_fprog32 = (struct sock_fprog32 *) arg; + struct sock_fprog *u_fprog64 = compat_alloc_user_space(sizeof(struct sock_fprog)); + void *fptr64; + u32 fptr32; + u16 flen; + + if (get_user(flen, &u_fprog32->len) || + get_user(fptr32, &u_fprog32->filter)) + return -EFAULT; + + fptr64 = compat_ptr(fptr32); + + if (put_user(flen, &u_fprog64->len) || + put_user(fptr64, &u_fprog64->filter)) + return -EFAULT; + + if (cmd == PPPIOCSPASS32) + cmd = PPPIOCSPASS; + else + cmd = PPPIOCSACTIVE; + + return sys_ioctl(fd, cmd, (unsigned long) u_fprog64); +} + +struct ppp_option_data32 { + compat_caddr_t ptr; + u32 length; + compat_int_t transmit; +}; +#define PPPIOCSCOMPRESS32 _IOW('t', 77, struct ppp_option_data32) + +struct ppp_idle32 { + compat_time_t xmit_idle; + compat_time_t recv_idle; +}; +#define PPPIOCGIDLE32 _IOR('t', 63, struct ppp_idle32) + +static int ppp_gidle(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct ppp_idle *idle; + struct ppp_idle32 *idle32; + __kernel_time_t xmit, recv; + int err; + + idle = compat_alloc_user_space(sizeof(*idle)); + idle32 = (struct ppp_idle32 *) arg; + + err = sys_ioctl(fd, PPPIOCGIDLE, (unsigned long) idle); + + if (!err) { + if (get_user(xmit, &idle->xmit_idle) || + get_user(recv, &idle->recv_idle) || + put_user(xmit, &idle32->xmit_idle) || + put_user(recv, &idle32->recv_idle)) + err = -EFAULT; + } + return err; +} + +static int ppp_scompress(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct ppp_option_data *odata; + struct ppp_option_data32 *odata32; + __u32 data; + void *datap; + + odata = compat_alloc_user_space(sizeof(*odata)); + odata32 = (struct ppp_option_data32 *) arg; + + if (get_user(data, &odata32->ptr)) + return -EFAULT; + + datap = (void *) (unsigned long) data; + if (put_user(datap, &odata->ptr)) + return -EFAULT; + + if (copy_in_user(&odata->length, &odata32->length, + sizeof(__u32) + sizeof(int))) + return -EFAULT; + + return sys_ioctl(fd, PPPIOCSCOMPRESS, (unsigned long) odata); +} + +static int ppp_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + int err; + + switch (cmd) { + case PPPIOCGIDLE32: + err = ppp_gidle(fd, cmd, arg); + break; + + case PPPIOCSCOMPRESS32: + err = ppp_scompress(fd, cmd, arg); + break; + + default: + do { + static int count; + if (++count <= 20) + printk("ppp_ioctl: Unknown cmd fd(%d) " + "cmd(%08x) arg(%08x)\n", + (int)fd, (unsigned int)cmd, (unsigned int)arg); + } while(0); + err = -EINVAL; + break; + }; + + return err; +} + + +struct mtget32 { + compat_long_t mt_type; + compat_long_t mt_resid; + compat_long_t mt_dsreg; + compat_long_t mt_gstat; + compat_long_t mt_erreg; + compat_daddr_t mt_fileno; + compat_daddr_t mt_blkno; +}; +#define MTIOCGET32 _IOR('m', 2, struct mtget32) + +struct mtpos32 { + compat_long_t mt_blkno; +}; +#define MTIOCPOS32 _IOR('m', 3, struct mtpos32) + +struct mtconfiginfo32 { + compat_long_t mt_type; + compat_long_t ifc_type; + unsigned short irqnr; + unsigned short dmanr; + unsigned short port; + compat_ulong_t debug; + compat_uint_t have_dens:1; + compat_uint_t have_bsf:1; + compat_uint_t have_fsr:1; + compat_uint_t have_bsr:1; + compat_uint_t have_eod:1; + compat_uint_t have_seek:1; + compat_uint_t have_tell:1; + compat_uint_t have_ras1:1; + compat_uint_t have_ras2:1; + compat_uint_t have_ras3:1; + compat_uint_t have_qfa:1; + compat_uint_t pad1:5; + char reserved[10]; +}; +#define MTIOCGETCONFIG32 _IOR('m', 4, struct mtconfiginfo32) +#define MTIOCSETCONFIG32 _IOW('m', 5, struct mtconfiginfo32) + +static int mt_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + mm_segment_t old_fs = get_fs(); + struct mtconfiginfo info; + struct mtget get; + struct mtpos pos; + unsigned long kcmd; + void *karg; + int err = 0; + + switch(cmd) { + case MTIOCPOS32: + kcmd = MTIOCPOS; + karg = &pos; + break; + case MTIOCGET32: + kcmd = MTIOCGET; + karg = &get; + break; + case MTIOCGETCONFIG32: + kcmd = MTIOCGETCONFIG; + karg = &info; + break; + case MTIOCSETCONFIG32: + kcmd = MTIOCSETCONFIG; + karg = &info; + err = __get_user(info.mt_type, &((struct mtconfiginfo32 *)arg)->mt_type); + err |= __get_user(info.ifc_type, &((struct mtconfiginfo32 *)arg)->ifc_type); + err |= __get_user(info.irqnr, &((struct mtconfiginfo32 *)arg)->irqnr); + err |= __get_user(info.dmanr, &((struct mtconfiginfo32 *)arg)->dmanr); + err |= __get_user(info.port, &((struct mtconfiginfo32 *)arg)->port); + err |= __get_user(info.debug, &((struct mtconfiginfo32 *)arg)->debug); + err |= __copy_from_user((char *)&info.debug + sizeof(info.debug), + (char *)&((struct mtconfiginfo32 *)arg)->debug + + sizeof(((struct mtconfiginfo32 *)arg)->debug), sizeof(__u32)); + if (err) + return -EFAULT; + break; + default: + do { + static int count; + if (++count <= 20) + printk("mt_ioctl: Unknown cmd fd(%d) " + "cmd(%08x) arg(%08x)\n", + (int)fd, (unsigned int)cmd, (unsigned int)arg); + } while(0); + return -EINVAL; + } + set_fs (KERNEL_DS); + err = sys_ioctl (fd, kcmd, (unsigned long)karg); + set_fs (old_fs); + if (err) + return err; + switch (cmd) { + case MTIOCPOS32: + err = __put_user(pos.mt_blkno, &((struct mtpos32 *)arg)->mt_blkno); + break; + case MTIOCGET32: + err = __put_user(get.mt_type, &((struct mtget32 *)arg)->mt_type); + err |= __put_user(get.mt_resid, &((struct mtget32 *)arg)->mt_resid); + err |= __put_user(get.mt_dsreg, &((struct mtget32 *)arg)->mt_dsreg); + err |= __put_user(get.mt_gstat, &((struct mtget32 *)arg)->mt_gstat); + err |= __put_user(get.mt_erreg, &((struct mtget32 *)arg)->mt_erreg); + err |= __put_user(get.mt_fileno, &((struct mtget32 *)arg)->mt_fileno); + err |= __put_user(get.mt_blkno, &((struct mtget32 *)arg)->mt_blkno); + break; + case MTIOCGETCONFIG32: + err = __put_user(info.mt_type, &((struct mtconfiginfo32 *)arg)->mt_type); + err |= __put_user(info.ifc_type, &((struct mtconfiginfo32 *)arg)->ifc_type); + err |= __put_user(info.irqnr, &((struct mtconfiginfo32 *)arg)->irqnr); + err |= __put_user(info.dmanr, &((struct mtconfiginfo32 *)arg)->dmanr); + err |= __put_user(info.port, &((struct mtconfiginfo32 *)arg)->port); + err |= __put_user(info.debug, &((struct mtconfiginfo32 *)arg)->debug); + err |= __copy_to_user((char *)&((struct mtconfiginfo32 *)arg)->debug + + sizeof(((struct mtconfiginfo32 *)arg)->debug), + (char *)&info.debug + sizeof(info.debug), sizeof(__u32)); + break; + case MTIOCSETCONFIG32: + break; + } + return err ? -EFAULT: 0; +} + +struct cdrom_read_audio32 { + union cdrom_addr addr; + u8 addr_format; + compat_int_t nframes; + compat_caddr_t buf; +}; + +struct cdrom_generic_command32 { + unsigned char cmd[CDROM_PACKET_SIZE]; + compat_caddr_t buffer; + compat_uint_t buflen; + compat_int_t stat; + compat_caddr_t sense; + unsigned char data_direction; + compat_int_t quiet; + compat_int_t timeout; + compat_caddr_t reserved[1]; +}; + +static int cdrom_do_read_audio(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct cdrom_read_audio *cdread_audio; + struct cdrom_read_audio32 *cdread_audio32; + __u32 data; + void *datap; + + cdread_audio = compat_alloc_user_space(sizeof(*cdread_audio)); + cdread_audio32 = (struct cdrom_read_audio32 *) arg; + + if (copy_in_user(&cdread_audio->addr, + &cdread_audio32->addr, + (sizeof(*cdread_audio32) - + sizeof(compat_caddr_t)))) + return -EFAULT; + + if (get_user(data, &cdread_audio32->buf)) + return -EFAULT; + datap = (void *) (unsigned long) data; + if (put_user(datap, &cdread_audio->buf)) + return -EFAULT; + + return sys_ioctl(fd, cmd, (unsigned long) cdread_audio); +} + +static int __cgc_do_ptr(void **ptr64, __u32 *ptr32) +{ + u32 data; + void *datap; + + if (get_user(data, ptr32)) + return -EFAULT; + datap = (void *) (unsigned long) data; + if (put_user(datap, ptr64)) + return -EFAULT; + + return 0; +} + +static int cdrom_do_generic_command(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct cdrom_generic_command *cgc; + struct cdrom_generic_command32 *cgc32; + unsigned char dir; + + cgc = compat_alloc_user_space(sizeof(*cgc)); + cgc32 = (struct cdrom_generic_command32 *) arg; + + if (copy_in_user(&cgc->cmd, &cgc32->cmd, sizeof(cgc->cmd)) || + __cgc_do_ptr((void **) &cgc->buffer, &cgc32->buffer) || + copy_in_user(&cgc->buflen, &cgc32->buflen, + (sizeof(unsigned int) + sizeof(int))) || + __cgc_do_ptr((void **) &cgc->sense, &cgc32->sense)) + return -EFAULT; + + if (get_user(dir, &cgc->data_direction) || + put_user(dir, &cgc32->data_direction)) + return -EFAULT; + + if (copy_in_user(&cgc->quiet, &cgc32->quiet, + 2 * sizeof(int))) + return -EFAULT; + + if (__cgc_do_ptr(&cgc->reserved[0], &cgc32->reserved[0])) + return -EFAULT; + + return sys_ioctl(fd, cmd, (unsigned long) cgc); +} + +static int cdrom_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + int err; + + switch(cmd) { + case CDROMREADAUDIO: + err = cdrom_do_read_audio(fd, cmd, arg); + break; + + case CDROM_SEND_PACKET: + err = cdrom_do_generic_command(fd, cmd, arg); + break; + + default: + do { + static int count; + if (++count <= 20) + printk("cdrom_ioctl: Unknown cmd fd(%d) " + "cmd(%08x) arg(%08x)\n", + (int)fd, (unsigned int)cmd, (unsigned int)arg); + } while(0); + err = -EINVAL; + break; + }; + + return err; +} + +struct loop_info32 { + compat_int_t lo_number; /* ioctl r/o */ + compat_dev_t lo_device; /* ioctl r/o */ + compat_ulong_t lo_inode; /* ioctl r/o */ + compat_dev_t lo_rdevice; /* ioctl r/o */ + compat_int_t lo_offset; + compat_int_t lo_encrypt_type; + compat_int_t lo_encrypt_key_size; /* ioctl w/o */ + compat_int_t lo_flags; /* ioctl r/o */ + char lo_name[LO_NAME_SIZE]; + unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */ + compat_ulong_t lo_init[2]; + char reserved[4]; +}; + +static int loop_status(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + mm_segment_t old_fs = get_fs(); + struct loop_info l; + int err = -EINVAL; + + switch(cmd) { + case LOOP_SET_STATUS: + err = get_user(l.lo_number, &((struct loop_info32 *)arg)->lo_number); + err |= __get_user(l.lo_device, &((struct loop_info32 *)arg)->lo_device); + err |= __get_user(l.lo_inode, &((struct loop_info32 *)arg)->lo_inode); + err |= __get_user(l.lo_rdevice, &((struct loop_info32 *)arg)->lo_rdevice); + err |= __copy_from_user((char *)&l.lo_offset, (char *)&((struct loop_info32 *)arg)->lo_offset, + 8 + (unsigned long)l.lo_init - (unsigned long)&l.lo_offset); + if (err) { + err = -EFAULT; + } else { + set_fs (KERNEL_DS); + err = sys_ioctl (fd, cmd, (unsigned long)&l); + set_fs (old_fs); + } + break; + case LOOP_GET_STATUS: + set_fs (KERNEL_DS); + err = sys_ioctl (fd, cmd, (unsigned long)&l); + set_fs (old_fs); + if (!err) { + err = put_user(l.lo_number, &((struct loop_info32 *)arg)->lo_number); + err |= __put_user(l.lo_device, &((struct loop_info32 *)arg)->lo_device); + err |= __put_user(l.lo_inode, &((struct loop_info32 *)arg)->lo_inode); + err |= __put_user(l.lo_rdevice, &((struct loop_info32 *)arg)->lo_rdevice); + err |= __copy_to_user((char *)&((struct loop_info32 *)arg)->lo_offset, + (char *)&l.lo_offset, (unsigned long)l.lo_init - (unsigned long)&l.lo_offset); + if (err) + err = -EFAULT; + } + break; + default: { + static int count; + if (++count <= 20) + printk("%s: Unknown loop ioctl cmd, fd(%d) " + "cmd(%08x) arg(%08lx)\n", + __FUNCTION__, fd, cmd, arg); + } + } + return err; +} + +extern int tty_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg); + +static int vt_check(struct file *file) +{ + struct tty_struct *tty; + struct inode *inode = file->f_dentry->d_inode; + + if (file->f_op->ioctl != tty_ioctl) + return -EINVAL; + + tty = (struct tty_struct *)file->private_data; + if (tty_paranoia_check(tty, inode->i_rdev, "tty_ioctl")) + return -EINVAL; + + if (tty->driver->ioctl != vt_ioctl) + return -EINVAL; + + /* + * To have permissions to do most of the vt ioctls, we either have + * to be the owner of the tty, or super-user. + */ + if (current->tty == tty || capable(CAP_SYS_ADMIN)) + return 1; + return 0; +} + +struct consolefontdesc32 { + unsigned short charcount; /* characters in font (256 or 512) */ + unsigned short charheight; /* scan lines per character (1-32) */ + compat_caddr_t chardata; /* font data in expanded form */ +}; + +static int do_fontx_ioctl(unsigned int fd, int cmd, struct consolefontdesc32 *user_cfd, struct file *file) +{ + struct consolefontdesc cfdarg; + struct console_font_op op; + int i, perm; + + perm = vt_check(file); + if (perm < 0) return perm; + + if (copy_from_user(&cfdarg, user_cfd, sizeof(struct consolefontdesc32))) + return -EFAULT; + + cfdarg.chardata = compat_ptr(((struct consolefontdesc32 *)&cfdarg)->chardata); + + switch (cmd) { + case PIO_FONTX: + if (!perm) + return -EPERM; + op.op = KD_FONT_OP_SET; + op.flags = 0; + op.width = 8; + op.height = cfdarg.charheight; + op.charcount = cfdarg.charcount; + op.data = cfdarg.chardata; + return con_font_op(fg_console, &op); + case GIO_FONTX: + if (!cfdarg.chardata) + return 0; + op.op = KD_FONT_OP_GET; + op.flags = 0; + op.width = 8; + op.height = cfdarg.charheight; + op.charcount = cfdarg.charcount; + op.data = cfdarg.chardata; + i = con_font_op(fg_console, &op); + if (i) + return i; + cfdarg.charheight = op.height; + cfdarg.charcount = op.charcount; + ((struct consolefontdesc32 *)&cfdarg)->chardata = (unsigned long)cfdarg.chardata; + if (copy_to_user(user_cfd, &cfdarg, sizeof(struct consolefontdesc32))) + return -EFAULT; + return 0; + } + return -EINVAL; +} + +struct console_font_op32 { + compat_uint_t op; /* operation code KD_FONT_OP_* */ + compat_uint_t flags; /* KD_FONT_FLAG_* */ + compat_uint_t width, height; /* font size */ + compat_uint_t charcount; + compat_caddr_t data; /* font data with height fixed to 32 */ +}; + +static int do_kdfontop_ioctl(unsigned int fd, unsigned int cmd, struct console_font_op32 *fontop, struct file *file) +{ + struct console_font_op op; + int perm = vt_check(file), i; + struct vt_struct *vt; + + if (perm < 0) return perm; + + if (copy_from_user(&op, (void *) fontop, sizeof(struct console_font_op32))) + return -EFAULT; + if (!perm && op.op != KD_FONT_OP_GET) + return -EPERM; + op.data = compat_ptr(((struct console_font_op32 *)&op)->data); + op.flags |= KD_FONT_FLAG_OLD; + vt = (struct vt_struct *)((struct tty_struct *)file->private_data)->driver_data; + i = con_font_op(vt->vc_num, &op); + if (i) return i; + ((struct console_font_op32 *)&op)->data = (unsigned long)op.data; + if (copy_to_user((void *) fontop, &op, sizeof(struct console_font_op32))) + return -EFAULT; + return 0; +} + +struct unimapdesc32 { + unsigned short entry_ct; + compat_caddr_t entries; +}; + +static int do_unimap_ioctl(unsigned int fd, unsigned int cmd, struct unimapdesc32 *user_ud, struct file *file) +{ + struct unimapdesc32 tmp; + int perm = vt_check(file); + + if (perm < 0) return perm; + if (copy_from_user(&tmp, user_ud, sizeof tmp)) + return -EFAULT; + switch (cmd) { + case PIO_UNIMAP: + if (!perm) return -EPERM; + return con_set_unimap(fg_console, tmp.entry_ct, compat_ptr(tmp.entries)); + case GIO_UNIMAP: + return con_get_unimap(fg_console, tmp.entry_ct, &(user_ud->entry_ct), compat_ptr(tmp.entries)); + } + return 0; +} + +static int do_smb_getmountuid(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + mm_segment_t old_fs = get_fs(); + __kernel_uid_t kuid; + int err; + + cmd = SMB_IOC_GETMOUNTUID; + + set_fs(KERNEL_DS); + err = sys_ioctl(fd, cmd, (unsigned long)&kuid); + set_fs(old_fs); + + if (err >= 0) + err = put_user(kuid, (compat_pid_t *)arg); + + return err; +} + +struct atmif_sioc32 { + compat_int_t number; + compat_int_t length; + compat_caddr_t arg; +}; + +struct atm_iobuf32 { + compat_int_t length; + compat_caddr_t buffer; +}; + +#define ATM_GETLINKRATE32 _IOW('a', ATMIOC_ITF+1, struct atmif_sioc32) +#define ATM_GETNAMES32 _IOW('a', ATMIOC_ITF+3, struct atm_iobuf32) +#define ATM_GETTYPE32 _IOW('a', ATMIOC_ITF+4, struct atmif_sioc32) +#define ATM_GETESI32 _IOW('a', ATMIOC_ITF+5, struct atmif_sioc32) +#define ATM_GETADDR32 _IOW('a', ATMIOC_ITF+6, struct atmif_sioc32) +#define ATM_RSTADDR32 _IOW('a', ATMIOC_ITF+7, struct atmif_sioc32) +#define ATM_ADDADDR32 _IOW('a', ATMIOC_ITF+8, struct atmif_sioc32) +#define ATM_DELADDR32 _IOW('a', ATMIOC_ITF+9, struct atmif_sioc32) +#define ATM_GETCIRANGE32 _IOW('a', ATMIOC_ITF+10, struct atmif_sioc32) +#define ATM_SETCIRANGE32 _IOW('a', ATMIOC_ITF+11, struct atmif_sioc32) +#define ATM_SETESI32 _IOW('a', ATMIOC_ITF+12, struct atmif_sioc32) +#define ATM_SETESIF32 _IOW('a', ATMIOC_ITF+13, struct atmif_sioc32) +#define ATM_GETSTAT32 _IOW('a', ATMIOC_SARCOM+0, struct atmif_sioc32) +#define ATM_GETSTATZ32 _IOW('a', ATMIOC_SARCOM+1, struct atmif_sioc32) +#define ATM_GETLOOP32 _IOW('a', ATMIOC_SARCOM+2, struct atmif_sioc32) +#define ATM_SETLOOP32 _IOW('a', ATMIOC_SARCOM+3, struct atmif_sioc32) +#define ATM_QUERYLOOP32 _IOW('a', ATMIOC_SARCOM+4, struct atmif_sioc32) + +static struct { + unsigned int cmd32; + unsigned int cmd; +} atm_ioctl_map[] = { + { ATM_GETLINKRATE32, ATM_GETLINKRATE }, + { ATM_GETNAMES32, ATM_GETNAMES }, + { ATM_GETTYPE32, ATM_GETTYPE }, + { ATM_GETESI32, ATM_GETESI }, + { ATM_GETADDR32, ATM_GETADDR }, + { ATM_RSTADDR32, ATM_RSTADDR }, + { ATM_ADDADDR32, ATM_ADDADDR }, + { ATM_DELADDR32, ATM_DELADDR }, + { ATM_GETCIRANGE32, ATM_GETCIRANGE }, + { ATM_SETCIRANGE32, ATM_SETCIRANGE }, + { ATM_SETESI32, ATM_SETESI }, + { ATM_SETESIF32, ATM_SETESIF }, + { ATM_GETSTAT32, ATM_GETSTAT }, + { ATM_GETSTATZ32, ATM_GETSTATZ }, + { ATM_GETLOOP32, ATM_GETLOOP }, + { ATM_SETLOOP32, ATM_SETLOOP }, + { ATM_QUERYLOOP32, ATM_QUERYLOOP } +}; + +#define NR_ATM_IOCTL (sizeof(atm_ioctl_map)/sizeof(atm_ioctl_map[0])) + + +static int do_atm_iobuf(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct atm_iobuf *iobuf; + struct atm_iobuf32 *iobuf32; + u32 data; + void *datap; + int len, err; + + iobuf = compat_alloc_user_space(sizeof(*iobuf)); + iobuf32 = (struct atm_iobuf32 *) arg; + + if (get_user(len, &iobuf32->length) || + get_user(data, &iobuf32->buffer)) + return -EFAULT; + datap = (void *) (unsigned long) data; + if (put_user(len, &iobuf->length) || + put_user(datap, &iobuf->buffer)) + return -EFAULT; + + err = sys_ioctl(fd, cmd, (unsigned long)iobuf); + + if (!err) { + if (copy_in_user(&iobuf32->length, &iobuf->length, + sizeof(int))) + err = -EFAULT; + } + + return err; +} + +static int do_atmif_sioc(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct atmif_sioc *sioc; + struct atmif_sioc32 *sioc32; + u32 data; + void *datap; + int err; + + sioc = compat_alloc_user_space(sizeof(*sioc)); + sioc32 = (struct atmif_sioc32 *) arg; + + if (copy_in_user(&sioc->number, &sioc32->number, 2 * sizeof(int)) || + get_user(data, &sioc32->arg)) + return -EFAULT; + datap = (void *) (unsigned long) data; + if (put_user(datap, &sioc->arg)) + return -EFAULT; + + err = sys_ioctl(fd, cmd, (unsigned long) sioc); + + if (!err) { + if (copy_in_user(&sioc32->length, &sioc->length, + sizeof(int))) + err = -EFAULT; + } + return err; +} + +static int do_atm_ioctl(unsigned int fd, unsigned int cmd32, unsigned long arg) +{ + int i; + unsigned int cmd = 0; + + switch (cmd32) { + case SONET_GETSTAT: + case SONET_GETSTATZ: + case SONET_GETDIAG: + case SONET_SETDIAG: + case SONET_CLRDIAG: + case SONET_SETFRAMING: + case SONET_GETFRAMING: + case SONET_GETFRSENSE: + return do_atmif_sioc(fd, cmd32, arg); + } + + for (i = 0; i < NR_ATM_IOCTL; i++) { + if (cmd32 == atm_ioctl_map[i].cmd32) { + cmd = atm_ioctl_map[i].cmd; + break; + } + } + if (i == NR_ATM_IOCTL) + return -EINVAL; + + switch (cmd) { + case ATM_GETNAMES: + return do_atm_iobuf(fd, cmd, arg); + + case ATM_GETLINKRATE: + case ATM_GETTYPE: + case ATM_GETESI: + case ATM_GETADDR: + case ATM_RSTADDR: + case ATM_ADDADDR: + case ATM_DELADDR: + case ATM_GETCIRANGE: + case ATM_SETCIRANGE: + case ATM_SETESI: + case ATM_SETESIF: + case ATM_GETSTAT: + case ATM_GETSTATZ: + case ATM_GETLOOP: + case ATM_SETLOOP: + case ATM_QUERYLOOP: + return do_atmif_sioc(fd, cmd, arg); + } + + return -EINVAL; +} + +static int ret_einval(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + return -EINVAL; +} + +static int broken_blkgetsize(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + /* The mkswap binary hard codes it to Intel value :-((( */ + return w_long(fd, BLKGETSIZE, arg); +} + +struct blkpg_ioctl_arg32 { + compat_int_t op; + compat_int_t flags; + compat_int_t datalen; + compat_caddr_t data; +}; + +static int blkpg_ioctl_trans(unsigned int fd, unsigned int cmd, struct blkpg_ioctl_arg32 *arg) +{ + struct blkpg_ioctl_arg a; + struct blkpg_partition p; + int err; + mm_segment_t old_fs = get_fs(); + + err = get_user(a.op, &arg->op); + err |= __get_user(a.flags, &arg->flags); + err |= __get_user(a.datalen, &arg->datalen); + err |= __get_user((long)a.data, &arg->data); + if (err) return err; + switch (a.op) { + case BLKPG_ADD_PARTITION: + case BLKPG_DEL_PARTITION: + if (a.datalen < sizeof(struct blkpg_partition)) + return -EINVAL; + if (copy_from_user(&p, a.data, sizeof(struct blkpg_partition))) + return -EFAULT; + a.data = &p; + set_fs (KERNEL_DS); + err = sys_ioctl(fd, cmd, (unsigned long)&a); + set_fs (old_fs); + default: + return -EINVAL; + } + return err; +} + +static int ioc_settimeout(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + return rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg); +} + +/* Fix sizeof(sizeof()) breakage */ +#define BLKBSZGET_32 _IOR(0x12,112,int) +#define BLKBSZSET_32 _IOW(0x12,113,int) +#define BLKGETSIZE64_32 _IOR(0x12,114,int) + +static int do_blkbszget(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + return sys_ioctl(fd, BLKBSZGET, arg); +} + +static int do_blkbszset(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + return sys_ioctl(fd, BLKBSZSET, arg); +} + +static int do_blkgetsize64(unsigned int fd, unsigned int cmd, + unsigned long arg) +{ + return sys_ioctl(fd, BLKGETSIZE64, arg); +} + +/* Bluetooth ioctls */ +#define HCIUARTSETPROTO _IOW('U', 200, int) +#define HCIUARTGETPROTO _IOR('U', 201, int) + +#define BNEPCONNADD _IOW('B', 200, int) +#define BNEPCONNDEL _IOW('B', 201, int) +#define BNEPGETCONNLIST _IOR('B', 210, int) +#define BNEPGETCONNINFO _IOR('B', 211, int) + +struct floppy_struct32 { + compat_uint_t size; + compat_uint_t sect; + compat_uint_t head; + compat_uint_t track; + compat_uint_t stretch; + unsigned char gap; + unsigned char rate; + unsigned char spec1; + unsigned char fmt_gap; + const compat_caddr_t name; +}; + +struct floppy_drive_params32 { + char cmos; + compat_ulong_t max_dtr; + compat_ulong_t hlt; + compat_ulong_t hut; + compat_ulong_t srt; + compat_ulong_t spinup; + compat_ulong_t spindown; + unsigned char spindown_offset; + unsigned char select_delay; + unsigned char rps; + unsigned char tracks; + compat_ulong_t timeout; + unsigned char interleave_sect; + struct floppy_max_errors max_errors; + char flags; + char read_track; + short autodetect[8]; + compat_int_t checkfreq; + compat_int_t native_format; +}; + +struct floppy_drive_struct32 { + signed char flags; + compat_ulong_t spinup_date; + compat_ulong_t select_date; + compat_ulong_t first_read_date; + short probed_format; + short track; + short maxblock; + short maxtrack; + compat_int_t generation; + compat_int_t keep_data; + compat_int_t fd_ref; + compat_int_t fd_device; + compat_int_t last_checked; + compat_caddr_t dmabuf; + compat_int_t bufblocks; +}; + +struct floppy_fdc_state32 { + compat_int_t spec1; + compat_int_t spec2; + compat_int_t dtr; + unsigned char version; + unsigned char dor; + compat_ulong_t address; + unsigned int rawcmd:2; + unsigned int reset:1; + unsigned int need_configure:1; + unsigned int perp_mode:2; + unsigned int has_fifo:1; + unsigned int driver_version; + unsigned char track[4]; +}; + +struct floppy_write_errors32 { + unsigned int write_errors; + compat_ulong_t first_error_sector; + compat_int_t first_error_generation; + compat_ulong_t last_error_sector; + compat_int_t last_error_generation; + compat_uint_t badness; +}; + +#define FDSETPRM32 _IOW(2, 0x42, struct floppy_struct32) +#define FDDEFPRM32 _IOW(2, 0x43, struct floppy_struct32) +#define FDGETPRM32 _IOR(2, 0x04, struct floppy_struct32) +#define FDSETDRVPRM32 _IOW(2, 0x90, struct floppy_drive_params32) +#define FDGETDRVPRM32 _IOR(2, 0x11, struct floppy_drive_params32) +#define FDGETDRVSTAT32 _IOR(2, 0x12, struct floppy_drive_struct32) +#define FDPOLLDRVSTAT32 _IOR(2, 0x13, struct floppy_drive_struct32) +#define FDGETFDCSTAT32 _IOR(2, 0x15, struct floppy_fdc_state32) +#define FDWERRORGET32 _IOR(2, 0x17, struct floppy_write_errors32) + +static struct { + unsigned int cmd32; + unsigned int cmd; +} fd_ioctl_trans_table[] = { + { FDSETPRM32, FDSETPRM }, + { FDDEFPRM32, FDDEFPRM }, + { FDGETPRM32, FDGETPRM }, + { FDSETDRVPRM32, FDSETDRVPRM }, + { FDGETDRVPRM32, FDGETDRVPRM }, + { FDGETDRVSTAT32, FDGETDRVSTAT }, + { FDPOLLDRVSTAT32, FDPOLLDRVSTAT }, + { FDGETFDCSTAT32, FDGETFDCSTAT }, + { FDWERRORGET32, FDWERRORGET } +}; + +#define NR_FD_IOCTL_TRANS (sizeof(fd_ioctl_trans_table)/sizeof(fd_ioctl_trans_table[0])) + +static int fd_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + mm_segment_t old_fs = get_fs(); + void *karg = NULL; + unsigned int kcmd = 0; + int i, err; + + for (i = 0; i < NR_FD_IOCTL_TRANS; i++) + if (cmd == fd_ioctl_trans_table[i].cmd32) { + kcmd = fd_ioctl_trans_table[i].cmd; + break; + } + if (!kcmd) + return -EINVAL; + + switch (cmd) { + case FDSETPRM32: + case FDDEFPRM32: + case FDGETPRM32: + { + struct floppy_struct *f; + + f = karg = kmalloc(sizeof(struct floppy_struct), GFP_KERNEL); + if (!karg) + return -ENOMEM; + if (cmd == FDGETPRM32) + break; + err = __get_user(f->size, &((struct floppy_struct32 *)arg)->size); + err |= __get_user(f->sect, &((struct floppy_struct32 *)arg)->sect); + err |= __get_user(f->head, &((struct floppy_struct32 *)arg)->head); + err |= __get_user(f->track, &((struct floppy_struct32 *)arg)->track); + err |= __get_user(f->stretch, &((struct floppy_struct32 *)arg)->stretch); + err |= __get_user(f->gap, &((struct floppy_struct32 *)arg)->gap); + err |= __get_user(f->rate, &((struct floppy_struct32 *)arg)->rate); + err |= __get_user(f->spec1, &((struct floppy_struct32 *)arg)->spec1); + err |= __get_user(f->fmt_gap, &((struct floppy_struct32 *)arg)->fmt_gap); + err |= __get_user((u64)f->name, &((struct floppy_struct32 *)arg)->name); + if (err) { + err = -EFAULT; + goto out; + } + break; + } + case FDSETDRVPRM32: + case FDGETDRVPRM32: + { + struct floppy_drive_params *f; + + f = karg = kmalloc(sizeof(struct floppy_drive_params), GFP_KERNEL); + if (!karg) + return -ENOMEM; + if (cmd == FDGETDRVPRM32) + break; + err = __get_user(f->cmos, &((struct floppy_drive_params32 *)arg)->cmos); + err |= __get_user(f->max_dtr, &((struct floppy_drive_params32 *)arg)->max_dtr); + err |= __get_user(f->hlt, &((struct floppy_drive_params32 *)arg)->hlt); + err |= __get_user(f->hut, &((struct floppy_drive_params32 *)arg)->hut); + err |= __get_user(f->srt, &((struct floppy_drive_params32 *)arg)->srt); + err |= __get_user(f->spinup, &((struct floppy_drive_params32 *)arg)->spinup); + err |= __get_user(f->spindown, &((struct floppy_drive_params32 *)arg)->spindown); + err |= __get_user(f->spindown_offset, &((struct floppy_drive_params32 *)arg)->spindown_offset); + err |= __get_user(f->select_delay, &((struct floppy_drive_params32 *)arg)->select_delay); + err |= __get_user(f->rps, &((struct floppy_drive_params32 *)arg)->rps); + err |= __get_user(f->tracks, &((struct floppy_drive_params32 *)arg)->tracks); + err |= __get_user(f->timeout, &((struct floppy_drive_params32 *)arg)->timeout); + err |= __get_user(f->interleave_sect, &((struct floppy_drive_params32 *)arg)->interleave_sect); + err |= __copy_from_user(&f->max_errors, &((struct floppy_drive_params32 *)arg)->max_errors, sizeof(f->max_errors)); + err |= __get_user(f->flags, &((struct floppy_drive_params32 *)arg)->flags); + err |= __get_user(f->read_track, &((struct floppy_drive_params32 *)arg)->read_track); + err |= __copy_from_user(f->autodetect, ((struct floppy_drive_params32 *)arg)->autodetect, sizeof(f->autodetect)); + err |= __get_user(f->checkfreq, &((struct floppy_drive_params32 *)arg)->checkfreq); + err |= __get_user(f->native_format, &((struct floppy_drive_params32 *)arg)->native_format); + if (err) { + err = -EFAULT; + goto out; + } + break; + } + case FDGETDRVSTAT32: + case FDPOLLDRVSTAT32: + karg = kmalloc(sizeof(struct floppy_drive_struct), GFP_KERNEL); + if (!karg) + return -ENOMEM; + break; + case FDGETFDCSTAT32: + karg = kmalloc(sizeof(struct floppy_fdc_state), GFP_KERNEL); + if (!karg) + return -ENOMEM; + break; + case FDWERRORGET32: + karg = kmalloc(sizeof(struct floppy_write_errors), GFP_KERNEL); + if (!karg) + return -ENOMEM; + break; + default: + return -EINVAL; + } + set_fs (KERNEL_DS); + err = sys_ioctl (fd, kcmd, (unsigned long)karg); + set_fs (old_fs); + if (err) + goto out; + switch (cmd) { + case FDGETPRM32: + { + struct floppy_struct *f = karg; + + err = __put_user(f->size, &((struct floppy_struct32 *)arg)->size); + err |= __put_user(f->sect, &((struct floppy_struct32 *)arg)->sect); + err |= __put_user(f->head, &((struct floppy_struct32 *)arg)->head); + err |= __put_user(f->track, &((struct floppy_struct32 *)arg)->track); + err |= __put_user(f->stretch, &((struct floppy_struct32 *)arg)->stretch); + err |= __put_user(f->gap, &((struct floppy_struct32 *)arg)->gap); + err |= __put_user(f->rate, &((struct floppy_struct32 *)arg)->rate); + err |= __put_user(f->spec1, &((struct floppy_struct32 *)arg)->spec1); + err |= __put_user(f->fmt_gap, &((struct floppy_struct32 *)arg)->fmt_gap); + err |= __put_user((u64)f->name, &((struct floppy_struct32 *)arg)->name); + break; + } + case FDGETDRVPRM32: + { + struct floppy_drive_params *f = karg; + + err = __put_user(f->cmos, &((struct floppy_drive_params32 *)arg)->cmos); + err |= __put_user(f->max_dtr, &((struct floppy_drive_params32 *)arg)->max_dtr); + err |= __put_user(f->hlt, &((struct floppy_drive_params32 *)arg)->hlt); + err |= __put_user(f->hut, &((struct floppy_drive_params32 *)arg)->hut); + err |= __put_user(f->srt, &((struct floppy_drive_params32 *)arg)->srt); + err |= __put_user(f->spinup, &((struct floppy_drive_params32 *)arg)->spinup); + err |= __put_user(f->spindown, &((struct floppy_drive_params32 *)arg)->spindown); + err |= __put_user(f->spindown_offset, &((struct floppy_drive_params32 *)arg)->spindown_offset); + err |= __put_user(f->select_delay, &((struct floppy_drive_params32 *)arg)->select_delay); + err |= __put_user(f->rps, &((struct floppy_drive_params32 *)arg)->rps); + err |= __put_user(f->tracks, &((struct floppy_drive_params32 *)arg)->tracks); + err |= __put_user(f->timeout, &((struct floppy_drive_params32 *)arg)->timeout); + err |= __put_user(f->interleave_sect, &((struct floppy_drive_params32 *)arg)->interleave_sect); + err |= __copy_to_user(&((struct floppy_drive_params32 *)arg)->max_errors, &f->max_errors, sizeof(f->max_errors)); + err |= __put_user(f->flags, &((struct floppy_drive_params32 *)arg)->flags); + err |= __put_user(f->read_track, &((struct floppy_drive_params32 *)arg)->read_track); + err |= __copy_to_user(((struct floppy_drive_params32 *)arg)->autodetect, f->autodetect, sizeof(f->autodetect)); + err |= __put_user(f->checkfreq, &((struct floppy_drive_params32 *)arg)->checkfreq); + err |= __put_user(f->native_format, &((struct floppy_drive_params32 *)arg)->native_format); + break; + } + case FDGETDRVSTAT32: + case FDPOLLDRVSTAT32: + { + struct floppy_drive_struct *f = karg; + + err = __put_user(f->flags, &((struct floppy_drive_struct32 *)arg)->flags); + err |= __put_user(f->spinup_date, &((struct floppy_drive_struct32 *)arg)->spinup_date); + err |= __put_user(f->select_date, &((struct floppy_drive_struct32 *)arg)->select_date); + err |= __put_user(f->first_read_date, &((struct floppy_drive_struct32 *)arg)->first_read_date); + err |= __put_user(f->probed_format, &((struct floppy_drive_struct32 *)arg)->probed_format); + err |= __put_user(f->track, &((struct floppy_drive_struct32 *)arg)->track); + err |= __put_user(f->maxblock, &((struct floppy_drive_struct32 *)arg)->maxblock); + err |= __put_user(f->maxtrack, &((struct floppy_drive_struct32 *)arg)->maxtrack); + err |= __put_user(f->generation, &((struct floppy_drive_struct32 *)arg)->generation); + err |= __put_user(f->keep_data, &((struct floppy_drive_struct32 *)arg)->keep_data); + err |= __put_user(f->fd_ref, &((struct floppy_drive_struct32 *)arg)->fd_ref); + err |= __put_user(f->fd_device, &((struct floppy_drive_struct32 *)arg)->fd_device); + err |= __put_user(f->last_checked, &((struct floppy_drive_struct32 *)arg)->last_checked); + err |= __put_user((u64)f->dmabuf, &((struct floppy_drive_struct32 *)arg)->dmabuf); + err |= __put_user((u64)f->bufblocks, &((struct floppy_drive_struct32 *)arg)->bufblocks); + break; + } + case FDGETFDCSTAT32: + { + struct floppy_fdc_state *f = karg; + + err = __put_user(f->spec1, &((struct floppy_fdc_state32 *)arg)->spec1); + err |= __put_user(f->spec2, &((struct floppy_fdc_state32 *)arg)->spec2); + err |= __put_user(f->dtr, &((struct floppy_fdc_state32 *)arg)->dtr); + err |= __put_user(f->version, &((struct floppy_fdc_state32 *)arg)->version); + err |= __put_user(f->dor, &((struct floppy_fdc_state32 *)arg)->dor); + err |= __put_user(f->address, &((struct floppy_fdc_state32 *)arg)->address); + err |= __copy_to_user((char *)&((struct floppy_fdc_state32 *)arg)->address + + sizeof(((struct floppy_fdc_state32 *)arg)->address), + (char *)&f->address + sizeof(f->address), sizeof(int)); + err |= __put_user(f->driver_version, &((struct floppy_fdc_state32 *)arg)->driver_version); + err |= __copy_to_user(((struct floppy_fdc_state32 *)arg)->track, f->track, sizeof(f->track)); + break; + } + case FDWERRORGET32: + { + struct floppy_write_errors *f = karg; + + err = __put_user(f->write_errors, &((struct floppy_write_errors32 *)arg)->write_errors); + err |= __put_user(f->first_error_sector, &((struct floppy_write_errors32 *)arg)->first_error_sector); + err |= __put_user(f->first_error_generation, &((struct floppy_write_errors32 *)arg)->first_error_generation); + err |= __put_user(f->last_error_sector, &((struct floppy_write_errors32 *)arg)->last_error_sector); + err |= __put_user(f->last_error_generation, &((struct floppy_write_errors32 *)arg)->last_error_generation); + err |= __put_user(f->badness, &((struct floppy_write_errors32 *)arg)->badness); + break; + } + default: + break; + } + if (err) + err = -EFAULT; + +out: if (karg) kfree(karg); + return err; +} + +struct mtd_oob_buf32 { + u_int32_t start; + u_int32_t length; + compat_caddr_t ptr; /* unsigned char* */ +}; + +#define MEMWRITEOOB32 _IOWR('M',3,struct mtd_oob_buf32) +#define MEMREADOOB32 _IOWR('M',4,struct mtd_oob_buf32) + +static int mtd_rw_oob(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct mtd_oob_buf *buf = compat_alloc_user_space(sizeof(*buf)); + struct mtd_oob_buf32 *buf32 = (struct mtd_oob_buf32 *) arg; + u32 data; + char *datap; + unsigned int real_cmd; + int err; + + real_cmd = (cmd == MEMREADOOB32) ? + MEMREADOOB : MEMWRITEOOB; + + if (copy_in_user(&buf->start, &buf32->start, + 2 * sizeof(u32)) || + get_user(data, &buf32->ptr)) + return -EFAULT; + datap = (void *) (unsigned long) data; + if (put_user(datap, &buf->ptr)) + return -EFAULT; + + err = sys_ioctl(fd, real_cmd, (unsigned long) buf); + + if (!err) { + if (copy_in_user(&buf32->start, &buf->start, + 2 * sizeof(u32))) + err = -EFAULT; + } + + return err; +} + +#undef CODE +#endif + +#ifdef DECLARES +HANDLE_IOCTL(MEMREADOOB32, mtd_rw_oob) +HANDLE_IOCTL(MEMWRITEOOB32, mtd_rw_oob) +#ifdef CONFIG_NET +HANDLE_IOCTL(SIOCGIFNAME, dev_ifname32) +#endif +HANDLE_IOCTL(SIOCGIFCONF, dev_ifconf) +HANDLE_IOCTL(SIOCGIFFLAGS, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFFLAGS, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFMETRIC, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFMETRIC, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFMTU, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFMTU, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFMEM, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFMEM, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFHWADDR, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFHWADDR, dev_ifsioc) +HANDLE_IOCTL(SIOCADDMULTI, dev_ifsioc) +HANDLE_IOCTL(SIOCDELMULTI, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFINDEX, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFMAP, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFMAP, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFADDR, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFADDR, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFBRDADDR, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFBRDADDR, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFDSTADDR, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFDSTADDR, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFNETMASK, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFNETMASK, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFPFLAGS, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFPFLAGS, dev_ifsioc) +HANDLE_IOCTL(SIOCGIFTXQLEN, dev_ifsioc) +HANDLE_IOCTL(SIOCSIFTXQLEN, dev_ifsioc) +HANDLE_IOCTL(SIOCETHTOOL, ethtool_ioctl) +HANDLE_IOCTL(SIOCBONDENSLAVE, bond_ioctl) +HANDLE_IOCTL(SIOCBONDRELEASE, bond_ioctl) +HANDLE_IOCTL(SIOCBONDSETHWADDR, bond_ioctl) +HANDLE_IOCTL(SIOCBONDSLAVEINFOQUERY, bond_ioctl) +HANDLE_IOCTL(SIOCBONDINFOQUERY, bond_ioctl) +HANDLE_IOCTL(SIOCBONDCHANGEACTIVE, bond_ioctl) +HANDLE_IOCTL(SIOCADDRT, routing_ioctl) +HANDLE_IOCTL(SIOCDELRT, routing_ioctl) +/* Note SIOCRTMSG is no longer, so this is safe and * the user would have seen just an -EINVAL anyways. */ +HANDLE_IOCTL(SIOCRTMSG, ret_einval) +HANDLE_IOCTL(SIOCGSTAMP, do_siocgstamp) +HANDLE_IOCTL(HDIO_GETGEO, hdio_getgeo) +HANDLE_IOCTL(BLKRAGET, w_long) +HANDLE_IOCTL(BLKGETSIZE, w_long) +HANDLE_IOCTL(0x1260, broken_blkgetsize) +HANDLE_IOCTL(BLKFRAGET, w_long) +HANDLE_IOCTL(BLKSECTGET, w_long) +HANDLE_IOCTL(FBIOGET_FSCREENINFO, fb_ioctl_trans) +HANDLE_IOCTL(BLKPG, blkpg_ioctl_trans) +HANDLE_IOCTL(FBIOGETCMAP, fb_ioctl_trans) +HANDLE_IOCTL(FBIOPUTCMAP, fb_ioctl_trans) +HANDLE_IOCTL(HDIO_GET_KEEPSETTINGS, hdio_ioctl_trans) +HANDLE_IOCTL(HDIO_GET_UNMASKINTR, hdio_ioctl_trans) +HANDLE_IOCTL(HDIO_GET_DMA, hdio_ioctl_trans) +HANDLE_IOCTL(HDIO_GET_32BIT, hdio_ioctl_trans) +HANDLE_IOCTL(HDIO_GET_MULTCOUNT, hdio_ioctl_trans) +HANDLE_IOCTL(HDIO_GET_NOWERR, hdio_ioctl_trans) +HANDLE_IOCTL(HDIO_GET_NICE, hdio_ioctl_trans) +HANDLE_IOCTL(FDSETPRM32, fd_ioctl_trans) +HANDLE_IOCTL(FDDEFPRM32, fd_ioctl_trans) +HANDLE_IOCTL(FDGETPRM32, fd_ioctl_trans) +HANDLE_IOCTL(FDSETDRVPRM32, fd_ioctl_trans) +HANDLE_IOCTL(FDGETDRVPRM32, fd_ioctl_trans) +HANDLE_IOCTL(FDGETDRVSTAT32, fd_ioctl_trans) +HANDLE_IOCTL(FDPOLLDRVSTAT32, fd_ioctl_trans) +HANDLE_IOCTL(FDGETFDCSTAT32, fd_ioctl_trans) +HANDLE_IOCTL(FDWERRORGET32, fd_ioctl_trans) +HANDLE_IOCTL(SG_IO,sg_ioctl_trans) +HANDLE_IOCTL(PPPIOCGIDLE32, ppp_ioctl_trans) +HANDLE_IOCTL(PPPIOCSCOMPRESS32, ppp_ioctl_trans) +HANDLE_IOCTL(PPPIOCSPASS32, ppp_sock_fprog_ioctl_trans) +HANDLE_IOCTL(PPPIOCSACTIVE32, ppp_sock_fprog_ioctl_trans) +HANDLE_IOCTL(MTIOCGET32, mt_ioctl_trans) +HANDLE_IOCTL(MTIOCPOS32, mt_ioctl_trans) +HANDLE_IOCTL(MTIOCGETCONFIG32, mt_ioctl_trans) +HANDLE_IOCTL(MTIOCSETCONFIG32, mt_ioctl_trans) +HANDLE_IOCTL(CDROMREADAUDIO, cdrom_ioctl_trans) +HANDLE_IOCTL(CDROM_SEND_PACKET, cdrom_ioctl_trans) +HANDLE_IOCTL(LOOP_SET_STATUS, loop_status) +HANDLE_IOCTL(LOOP_GET_STATUS, loop_status) +#define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int) +HANDLE_IOCTL(AUTOFS_IOC_SETTIMEOUT32, ioc_settimeout) +HANDLE_IOCTL(PIO_FONTX, do_fontx_ioctl) +HANDLE_IOCTL(GIO_FONTX, do_fontx_ioctl) +HANDLE_IOCTL(PIO_UNIMAP, do_unimap_ioctl) +HANDLE_IOCTL(GIO_UNIMAP, do_unimap_ioctl) +HANDLE_IOCTL(KDFONTOP, do_kdfontop_ioctl) +HANDLE_IOCTL(EXT2_IOC32_GETFLAGS, do_ext2_ioctl) +HANDLE_IOCTL(EXT2_IOC32_SETFLAGS, do_ext2_ioctl) +HANDLE_IOCTL(EXT2_IOC32_GETVERSION, do_ext2_ioctl) +HANDLE_IOCTL(EXT2_IOC32_SETVERSION, do_ext2_ioctl) +HANDLE_IOCTL(VIDIOCGTUNER32, do_video_ioctl) +HANDLE_IOCTL(VIDIOCSTUNER32, do_video_ioctl) +HANDLE_IOCTL(VIDIOCGWIN32, do_video_ioctl) +HANDLE_IOCTL(VIDIOCSWIN32, do_video_ioctl) +HANDLE_IOCTL(VIDIOCGFBUF32, do_video_ioctl) +HANDLE_IOCTL(VIDIOCSFBUF32, do_video_ioctl) +HANDLE_IOCTL(VIDIOCGFREQ32, do_video_ioctl) +HANDLE_IOCTL(VIDIOCSFREQ32, do_video_ioctl) +/* One SMB ioctl needs translations. */ +#define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, compat_pid_t) +HANDLE_IOCTL(SMB_IOC_GETMOUNTUID_32, do_smb_getmountuid) +HANDLE_IOCTL(ATM_GETLINKRATE32, do_atm_ioctl) +HANDLE_IOCTL(ATM_GETNAMES32, do_atm_ioctl) +HANDLE_IOCTL(ATM_GETTYPE32, do_atm_ioctl) +HANDLE_IOCTL(ATM_GETESI32, do_atm_ioctl) +HANDLE_IOCTL(ATM_GETADDR32, do_atm_ioctl) +HANDLE_IOCTL(ATM_RSTADDR32, do_atm_ioctl) +HANDLE_IOCTL(ATM_ADDADDR32, do_atm_ioctl) +HANDLE_IOCTL(ATM_DELADDR32, do_atm_ioctl) +HANDLE_IOCTL(ATM_GETCIRANGE32, do_atm_ioctl) +HANDLE_IOCTL(ATM_SETCIRANGE32, do_atm_ioctl) +HANDLE_IOCTL(ATM_SETESI32, do_atm_ioctl) +HANDLE_IOCTL(ATM_SETESIF32, do_atm_ioctl) +HANDLE_IOCTL(ATM_GETSTAT32, do_atm_ioctl) +HANDLE_IOCTL(ATM_GETSTATZ32, do_atm_ioctl) +HANDLE_IOCTL(ATM_GETLOOP32, do_atm_ioctl) +HANDLE_IOCTL(ATM_SETLOOP32, do_atm_ioctl) +HANDLE_IOCTL(ATM_QUERYLOOP32, do_atm_ioctl) +HANDLE_IOCTL(SONET_GETSTAT, do_atm_ioctl) +HANDLE_IOCTL(SONET_GETSTATZ, do_atm_ioctl) +HANDLE_IOCTL(SONET_GETDIAG, do_atm_ioctl) +HANDLE_IOCTL(SONET_SETDIAG, do_atm_ioctl) +HANDLE_IOCTL(SONET_CLRDIAG, do_atm_ioctl) +HANDLE_IOCTL(SONET_SETFRAMING, do_atm_ioctl) +HANDLE_IOCTL(SONET_GETFRAMING, do_atm_ioctl) +HANDLE_IOCTL(SONET_GETFRSENSE, do_atm_ioctl) +/* block stuff */ +HANDLE_IOCTL(BLKBSZGET_32, do_blkbszget) +HANDLE_IOCTL(BLKBSZSET_32, do_blkbszset) +HANDLE_IOCTL(BLKGETSIZE64_32, do_blkgetsize64) + +#undef DECLARES +#endif diff -Nru a/fs/dcache.c b/fs/dcache.c --- a/fs/dcache.c Mon Jun 9 23:16:07 2003 +++ b/fs/dcache.c Mon Jun 9 23:16:07 2003 @@ -983,8 +983,6 @@ struct dentry *dentry; unsigned long move_count; struct qstr * qstr; - - prefetch(node->next); smp_read_barrier_depends(); dentry = hlist_entry(node, struct dentry, d_hash); @@ -1072,7 +1070,6 @@ spin_lock(&dcache_lock); base = d_hash(dparent, dentry->d_name.hash); hlist_for_each(lhp,base) { - prefetch(lhp->next); /* read_barrier_depends() not required for d_hash list * as it is parsed under dcache_lock */ diff -Nru a/fs/devfs/base.c b/fs/devfs/base.c --- a/fs/devfs/base.c Mon Jun 9 23:16:08 2003 +++ b/fs/devfs/base.c Mon Jun 9 23:16:08 2003 @@ -1710,6 +1710,13 @@ if (n < 64 && buf[0]) { devfs_handle_t de = _devfs_find_entry(NULL, buf, 0); + if (!de) { + printk(KERN_ERR "%s: %s not found, cannot remove\n", + __FUNCTION__, buf); + dump_stack(); + return; + } + write_lock(&de->parent->u.dir.lock); _devfs_unregister(de->parent, de); devfs_put(de); diff -Nru a/fs/dquot.c b/fs/dquot.c --- a/fs/dquot.c Mon Jun 9 23:16:15 2003 +++ b/fs/dquot.c Mon Jun 9 23:16:15 2003 @@ -1348,25 +1348,91 @@ }; static ctl_table fs_dqstats_table[] = { - {FS_DQ_LOOKUPS, "lookups", &dqstats.lookups, sizeof(int), 0444, NULL, &proc_dointvec}, - {FS_DQ_DROPS, "drops", &dqstats.drops, sizeof(int), 0444, NULL, &proc_dointvec}, - {FS_DQ_READS, "reads", &dqstats.reads, sizeof(int), 0444, NULL, &proc_dointvec}, - {FS_DQ_WRITES, "writes", &dqstats.writes, sizeof(int), 0444, NULL, &proc_dointvec}, - {FS_DQ_CACHE_HITS, "cache_hits", &dqstats.cache_hits, sizeof(int), 0444, NULL, &proc_dointvec}, - {FS_DQ_ALLOCATED, "allocated_dquots", &dqstats.allocated_dquots, sizeof(int), 0444, NULL, &proc_dointvec}, - {FS_DQ_FREE, "free_dquots", &dqstats.free_dquots, sizeof(int), 0444, NULL, &proc_dointvec}, - {FS_DQ_SYNCS, "syncs", &dqstats.syncs, sizeof(int), 0444, NULL, &proc_dointvec}, - {}, + { + .ctl_name = FS_DQ_LOOKUPS, + .procname = "lookups", + .data = &dqstats.lookups, + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = FS_DQ_DROPS, + .procname = "drops", + .data = &dqstats.drops, + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = FS_DQ_READS, + .procname = "reads", + .data = &dqstats.reads, + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = FS_DQ_WRITES, + .procname = "writes", + .data = &dqstats.writes, + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = FS_DQ_CACHE_HITS, + .procname = "cache_hits", + .data = &dqstats.cache_hits, + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = FS_DQ_ALLOCATED, + .procname = "allocated_dquots", + .data = &dqstats.allocated_dquots, + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = FS_DQ_FREE, + .procname = "free_dquots", + .data = &dqstats.free_dquots, + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = FS_DQ_SYNCS, + .procname = "syncs", + .data = &dqstats.syncs, + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = &proc_dointvec, + }, + { .ctl_name = 0 }, }; static ctl_table fs_table[] = { - {FS_DQSTATS, "quota", NULL, 0, 0555, fs_dqstats_table}, - {}, + { + .ctl_name = FS_DQSTATS, + .procname = "quota", + .mode = 0555, + .child = fs_dqstats_table, + }, + { .ctl_name = 0 }, }; static ctl_table sys_table[] = { - {CTL_FS, "fs", NULL, 0, 0555, fs_table}, - {}, + { + .ctl_name = CTL_FS, + .procname = "fs", + .mode = 0555, + .child = fs_table, + }, + { .ctl_name = 0 }, }; /* SLAB cache for dquot structures */ diff -Nru a/fs/eventpoll.c b/fs/eventpoll.c --- a/fs/eventpoll.c Mon Jun 9 23:16:10 2003 +++ b/fs/eventpoll.c Mon Jun 9 23:16:10 2003 @@ -37,8 +37,41 @@ #include <asm/io.h> #include <asm/mman.h> #include <asm/atomic.h> +#include <asm/semaphore.h> +/* + * LOCKING: + * There are three level of locking required by epoll : + * + * 1) epsem (semaphore) + * 2) ep->sem (rw_semaphore) + * 3) ep->lock (rw_lock) + * + * The acquire order is the one listed above, from 1 to 3. + * We need a spinlock (ep->lock) because we manipulate objects + * from inside the poll callback, that might be triggered from + * a wake_up() that in turn might be called from IRQ context. + * So we can't sleep inside the poll callback and hence we need + * a spinlock. During the event transfer loop (from kernel to + * user space) we could end up sleeping due a copy_to_user(), so + * we need a lock that will allow us to sleep. This lock is a + * read-write semaphore (ep->sem). It is acquired on read during + * the event transfer loop and in write during epoll_ctl(EPOLL_CTL_DEL) + * and during eventpoll_release(). Then we also need a global + * semaphore to serialize eventpoll_release() and ep_free(). + * This semaphore is acquired by ep_free() during the epoll file + * cleanup path and it is also acquired by eventpoll_release() + * if a file has been pushed inside an epoll set and it is then + * close()d without a previous call toepoll_ctl(EPOLL_CTL_DEL). + * It is possible to drop the "ep->sem" and to use the global + * semaphore "epsem" (together with "ep->lock") to have it working, + * but having "ep->sem" will make the interface more scalable. + * Events that require holding "epsem" are very rare, while for + * normal operations the epoll private "ep->sem" will guarantee + * a greater scalability. + */ + #define EVENTPOLLFS_MAGIC 0x03111965 /* My birthday should work for this :) */ @@ -150,6 +183,14 @@ /* Protect the this structure access */ rwlock_t lock; + /* + * This semaphore is used to ensure that files are not removed + * while epoll is using them. This is read-held during the event + * collection loop and it is write-held during the file cleanup + * path, the epoll file exit code and the ctl operations. + */ + struct rw_semaphore sem; + /* Wait queue used by sys_epoll_wait() */ wait_queue_head_t wq; @@ -275,20 +316,14 @@ int flags, const char *dev_name, void *data); +/* + * This semaphore is used to serialize ep_free() and eventpoll_release(). + */ +struct semaphore epsem; /* Safe wake up implementation */ static struct poll_safewake psw; -/* - * This semaphore is used to ensure that files are not removed - * while epoll is using them. Namely the f_op->poll(), since - * it has to be called from outside the lock, must be protected. - * This is read-held during the event transfer loop to userspace - * and it is write-held during the file cleanup path and the epoll - * file exit code. - */ -static struct rw_semaphore epsem; - /* Slab cache used to allocate "struct epitem" */ static kmem_cache_t *epi_cache; @@ -357,15 +392,14 @@ list_for_each(lnk, lsthead) { tncur = list_entry(lnk, struct wake_task_node, llink); - if (tncur->task == this_task) { - if (tncur->wq == wq || ++wake_nests > EP_MAX_POLLWAKE_NESTS) { - /* - * Ops ... loop detected or maximum nest level reached. - * We abort this wake by breaking the cycle itself. - */ - spin_unlock_irqrestore(&psw->lock, flags); - return; - } + if (tncur->wq == wq || + (tncur->task == this_task && ++wake_nests > EP_MAX_POLLWAKE_NESTS)) { + /* + * Ops ... loop detected or maximum nest level reached. + * We abort this wake by breaking the cycle itself. + */ + spin_unlock_irqrestore(&psw->lock, flags); + return; } } @@ -417,6 +451,7 @@ void eventpoll_release(struct file *file) { struct list_head *lsthead = &file->f_ep_links; + struct eventpoll *ep; struct epitem *epi; /* @@ -435,16 +470,23 @@ * necessary. It is not necessary because we're in the "struct file" * cleanup path, and this means that noone is using this file anymore. * The only hit might come from ep_free() but by holding the semaphore - * will correctly serialize the operation. + * will correctly serialize the operation. We do need to acquire + * "ep->sem" after "epsem" because ep_remove() requires it when called + * from anywhere but ep_free(). */ - down_write(&epsem); + down(&epsem); + while (!list_empty(lsthead)) { epi = list_entry(lsthead->next, struct epitem, fllink); + ep = epi->ep; EP_LIST_DEL(&epi->fllink); - ep_remove(epi->ep, epi); + down_write(&ep->sem); + ep_remove(ep, epi); + up_write(&ep->sem); } - up_write(&epsem); + + up(&epsem); } @@ -547,14 +589,9 @@ */ ep = file->private_data; - /* - * Try to lookup the file inside our hash table. When an item is found - * ep_find() increases the usage count of the item so that it won't - * desappear underneath us. The only thing that might happen, if someone - * tries very hard, is a double insertion of the same file descriptor. - * This does not rapresent a problem though and we don't really want - * to put an extra syncronization object to deal with this harmless condition. - */ + down_write(&ep->sem); + + /* Try to lookup the file inside our hash table */ epi = ep_find(ep, tfile); error = -EINVAL; @@ -589,6 +626,8 @@ if (epi) ep_release_epitem(epi); + up_write(&ep->sem); + eexit_3: fput(tfile); eexit_2: @@ -703,10 +742,6 @@ file->f_vfsmnt = mntget(eventpoll_mnt); file->f_dentry = dget(dentry); - /* - * Initialize the file as read/write because it could be used - * with write() to add/remove/change interest sets. - */ file->f_pos = 0; file->f_flags = O_RDONLY; file->f_op = &eventpoll_fops; @@ -815,6 +850,7 @@ unsigned int i, hsize; rwlock_init(&ep->lock); + init_rwsem(&ep->sem); init_waitqueue_head(&ep->wq); init_waitqueue_head(&ep->poll_wait); INIT_LIST_HEAD(&ep->rdllist); @@ -841,11 +877,19 @@ struct list_head *lsthead, *lnk; struct epitem *epi; + /* We need to release all tasks waiting for these file */ + if (waitqueue_active(&ep->poll_wait)) + ep_poll_safewake(&psw, &ep->poll_wait); + /* * We need to lock this because we could be hit by * eventpoll_release() while we're freeing the "struct eventpoll". + * We do not need to hold "ep->sem" here because the epoll file + * is on the way to be removed and no one has references to it + * anymore. The only hit might come from eventpoll_release() but + * holding "epsem" is sufficent here. */ - down_write(&epsem); + down(&epsem); /* * Walks through the whole hash by unregistering poll callbacks. @@ -863,7 +907,7 @@ /* * Walks through the whole hash by freeing each "struct epitem". At this * point we are sure no poll callbacks will be lingering around, and also by - * write-holding "epsem" we can be sure that no file cleanup code will hit + * write-holding "sem" we can be sure that no file cleanup code will hit * us during this operation. So we can avoid the lock on "ep->lock". */ for (i = 0, hsize = 1 << ep->hashbits; i < hsize; i++) { @@ -876,7 +920,7 @@ } } - up_write(&epsem); + up(&epsem); /* Free hash pages */ ep_free_pages(ep->hpages, EP_HASH_PAGES(ep->hashbits)); @@ -1200,6 +1244,7 @@ { int error; unsigned long flags; + struct file *file = epi->file; /* * Removes poll wait queue hooks. We _have_ to do this without holding @@ -1212,10 +1257,10 @@ ep_unregister_pollwait(ep, epi); /* Remove the current item from the list of epoll hooks */ - spin_lock(&epi->file->f_ep_lock); + spin_lock(&file->f_ep_lock); if (EP_IS_LINKED(&epi->fllink)) EP_LIST_DEL(&epi->fllink); - spin_unlock(&epi->file->f_ep_lock); + spin_unlock(&file->f_ep_lock); /* We need to acquire the write IRQ lock before calling ep_unlink() */ write_lock_irqsave(&ep->lock, flags); @@ -1234,7 +1279,7 @@ error = 0; eexit_1: DNPRINTK(3, (KERN_INFO "[%p] eventpoll: ep_remove(%p, %p) = %d\n", - current, ep, epi->file, error)); + current, ep, file, error)); return error; } @@ -1338,20 +1383,6 @@ /* If this file is already in the ready list we exit soon */ if (!EP_IS_LINKED(&epi->txlink)) { /* - * We need to increase the usage count of the "struct epitem" because - * another thread might call EPOLL_CTL_DEL on this target and make the - * object to vanish underneath our nose. - */ - ep_use_epitem(epi); - - /* - * We need to increase the usage count of the "struct file" because - * another thread might call close() on this target and make the file - * to vanish before we will be able to call f_op->poll(). - */ - get_file(epi->file); - - /* * This is initialized in this way so that the default * behaviour of the reinjecting code will be to push back * the item inside the ready list. @@ -1389,19 +1420,21 @@ struct epitem *epi; struct epoll_event event[EP_MAX_BUF_EVENTS]; + /* + * We can loop without lock because this is a task private list. + * The test done during the collection loop will guarantee us that + * another task will not try to collect this file. Also, items + * cannot vanish during the loop because we are holding "sem". + */ list_for_each(lnk, txlist) { epi = list_entry(lnk, struct epitem, txlink); - /* Get the ready file event set */ - revents = epi->file->f_op->poll(epi->file, NULL); - /* - * Release the file usage before checking the event mask. - * In case this call will lead to the file removal, its - * ->event.events member has been already set to zero and - * this will make the event to be dropped. + * Get the ready file event set. We can safely use the file + * because we are holding the "sem" in read and this will + * guarantee that both the file and the item will not vanish. */ - fput(epi->file); + revents = epi->file->f_op->poll(epi->file, NULL); /* * Set the return event set for the current file descriptor. @@ -1416,17 +1449,8 @@ eventbuf++; if (eventbuf == EP_MAX_BUF_EVENTS) { if (__copy_to_user(&events[eventcnt], event, - eventbuf * sizeof(struct epoll_event))) { - /* - * We need to complete the loop to decrement the file - * usage before returning from this function. - */ - for (lnk = lnk->next; lnk != txlist; lnk = lnk->next) { - epi = list_entry(lnk, struct epitem, txlink); - fput(epi->file); - } + eventbuf * sizeof(struct epoll_event))) return -EFAULT; - } eventcnt += eventbuf; eventbuf = 0; } @@ -1447,7 +1471,8 @@ /* * Walk through the transfer list we collected with ep_collect_ready_items() * and, if 1) the item is still "alive" 2) its event set is not empty 3) it's - * not already linked, links it to the ready list. + * not already linked, links it to the ready list. Same as above, we are holding + * "sem" so items cannot vanish underneath our nose. */ static void ep_reinject_items(struct eventpoll *ep, struct list_head *txlist) { @@ -1475,8 +1500,6 @@ list_add_tail(&epi->rdllink, &ep->rdllist); ricnt++; } - - ep_release_epitem(epi); } if (ricnt) { @@ -1510,17 +1533,12 @@ /* * We need to lock this because we could be hit by - * eventpoll_release() while we're transfering - * events to userspace. Read-holding "epsem" will lock - * out eventpoll_release() during the whole - * transfer loop and this will garantie us that the - * file will not vanish underneath our nose when - * we will call f_op->poll() from ep_send_events(). + * eventpoll_release() and epoll_ctl(EPOLL_CTL_DEL). */ - down_read(&epsem); + down_read(&ep->sem); /* Collect/extract ready items */ - if (ep_collect_ready_items(ep, &txlist, maxevents)) { + if (ep_collect_ready_items(ep, &txlist, maxevents) > 0) { /* Build result set in userspace */ eventcnt = ep_send_events(ep, &txlist, events); @@ -1528,7 +1546,7 @@ ep_reinject_items(ep, &txlist); } - up_read(&epsem); + up_read(&ep->sem); return eventcnt; } @@ -1652,8 +1670,7 @@ { int error; - /* Initialize the semaphore used to syncronize the file cleanup code */ - init_rwsem(&epsem); + init_MUTEX(&epsem); /* Initialize the structure used to perform safe poll wait head wake ups */ ep_poll_safewake_init(&psw); diff -Nru a/fs/exec.c b/fs/exec.c --- a/fs/exec.c Mon Jun 9 23:16:10 2003 +++ b/fs/exec.c Mon Jun 9 23:16:10 2003 @@ -614,8 +614,6 @@ spin_unlock_irq(lock); schedule(); spin_lock_irq(lock); - if (oldsig->group_exit_task) - BUG(); } spin_unlock_irq(lock); diff -Nru a/fs/ext3/inode.c b/fs/ext3/inode.c --- a/fs/ext3/inode.c Mon Jun 9 23:16:15 2003 +++ b/fs/ext3/inode.c Mon Jun 9 23:16:15 2003 @@ -1262,6 +1262,13 @@ return 0; } +static int journal_dirty_data_fn(handle_t *handle, struct buffer_head *bh) +{ + if (buffer_mapped(bh)) + return ext3_journal_dirty_data(handle, bh); + return 0; +} + /* * Note that we always start a transaction even if we're not journalling * data. This is to preserve ordering: any hole instantiation within @@ -1381,7 +1388,7 @@ if (ret == 0) { err = walk_page_buffers(handle, page_bufs, 0, PAGE_CACHE_SIZE, NULL, - ext3_journal_dirty_data); + journal_dirty_data_fn); if (!ret) ret = err; } diff -Nru a/fs/fat/cache.c b/fs/fat/cache.c --- a/fs/fat/cache.c Mon Jun 9 23:16:17 2003 +++ b/fs/fat/cache.c Mon Jun 9 23:16:17 2003 @@ -12,9 +12,6 @@ #include <linux/msdos_fs.h> #include <linux/buffer_head.h> -static struct fat_cache *fat_cache,cache[FAT_CACHE]; -static spinlock_t fat_cache_lock = SPIN_LOCK_UNLOCKED; - int __fat_access(struct super_block *sb, int nr, int new_value) { struct msdos_sb_info *sbi = MSDOS_SB(sb); @@ -133,148 +130,163 @@ return next; } -void fat_cache_init(void) +void fat_cache_init(struct super_block *sb) { - static int initialized; + struct msdos_sb_info *sbi = MSDOS_SB(sb); int count; - spin_lock(&fat_cache_lock); - if (initialized) { - spin_unlock(&fat_cache_lock); - return; - } - fat_cache = &cache[0]; - for (count = 0; count < FAT_CACHE; count++) { - cache[count].sb = NULL; - cache[count].next = count == FAT_CACHE-1 ? NULL : - &cache[count+1]; - } - initialized = 1; - spin_unlock(&fat_cache_lock); -} + spin_lock_init(&sbi->cache_lock); + for (count = 0; count < FAT_CACHE_NR - 1; count++) { + sbi->cache_array[count].start_cluster = 0; + sbi->cache_array[count].next = &sbi->cache_array[count + 1]; + } + sbi->cache_array[count].start_cluster = 0; + sbi->cache_array[count].next = NULL; + sbi->cache = sbi->cache_array; +} -void fat_cache_lookup(struct inode *inode,int cluster,int *f_clu,int *d_clu) +void fat_cache_lookup(struct inode *inode, int cluster, int *f_clu, int *d_clu) { + struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); struct fat_cache *walk; - int first = MSDOS_I(inode)->i_start; + int first; + BUG_ON(cluster == 0); + + first = MSDOS_I(inode)->i_start; if (!first) return; - spin_lock(&fat_cache_lock); - for (walk = fat_cache; walk; walk = walk->next) - if (inode->i_sb == walk->sb - && walk->start_cluster == first + + spin_lock(&sbi->cache_lock); + + if (MSDOS_I(inode)->disk_cluster && + MSDOS_I(inode)->file_cluster <= cluster) { + *d_clu = MSDOS_I(inode)->disk_cluster; + *f_clu = MSDOS_I(inode)->file_cluster; + } + + for (walk = sbi->cache; walk; walk = walk->next) { + if (walk->start_cluster == first && walk->file_cluster <= cluster && walk->file_cluster > *f_clu) { *d_clu = walk->disk_cluster; + *f_clu = walk->file_cluster; #ifdef DEBUG -printk("cache hit: %d (%d)\n",walk->file_cluster,*d_clu); + printk("cache hit: %d (%d)\n", *f_clu, *d_clu); #endif - if ((*f_clu = walk->file_cluster) == cluster) { - spin_unlock(&fat_cache_lock); - return; - } + if (*f_clu == cluster) + goto out; } - spin_unlock(&fat_cache_lock); + } #ifdef DEBUG -printk("cache miss\n"); + printk("cache miss\n"); #endif +out: + spin_unlock(&sbi->cache_lock); } - #ifdef DEBUG -static void list_cache(void) +static void list_cache(struct super_block *sb) { + struct msdos_sb_info *sbi = MSDOS_SB(sb); struct fat_cache *walk; - for (walk = fat_cache; walk; walk = walk->next) { - if (walk->sb) - printk("<%s,%d>(%d,%d) ", walk->sb->s_id, + for (walk = sbi->cache; walk; walk = walk->next) { + if (walk->start_cluster) + printk("<%s,%d>(%d,%d) ", sb->s_id, walk->start_cluster, walk->file_cluster, walk->disk_cluster); - else printk("-- "); + else + printk("-- "); } printk("\n"); } #endif - -void fat_cache_add(struct inode *inode,int f_clu,int d_clu) +/* + * Cache invalidation occurs rarely, thus the LRU chain is not updated. It + * fixes itself after a while. + */ +static void __fat_cache_inval_inode(struct inode *inode) { - struct fat_cache *walk,*last; + struct fat_cache *walk; int first = MSDOS_I(inode)->i_start; + MSDOS_I(inode)->file_cluster = MSDOS_I(inode)->disk_cluster = 0; + for (walk = MSDOS_SB(inode->i_sb)->cache; walk; walk = walk->next) + if (walk->start_cluster == first) + walk->start_cluster = 0; +} + +void fat_cache_inval_inode(struct inode *inode) +{ + struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); + spin_lock(&sbi->cache_lock); + __fat_cache_inval_inode(inode); + spin_unlock(&sbi->cache_lock); +} + +void fat_cache_add(struct inode *inode, int f_clu, int d_clu) +{ + struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); + struct fat_cache *walk, *last; + int first, prev_f_clu, prev_d_clu; + + first = MSDOS_I(inode)->i_start; + if (!first) + return; last = NULL; - spin_lock(&fat_cache_lock); - for (walk = fat_cache; walk->next; walk = (last = walk)->next) - if (inode->i_sb == walk->sb - && walk->start_cluster == first - && walk->file_cluster == f_clu) { + spin_lock(&sbi->cache_lock); + + if (MSDOS_I(inode)->file_cluster == f_clu) + goto out; + else { + prev_f_clu = MSDOS_I(inode)->file_cluster; + prev_d_clu = MSDOS_I(inode)->disk_cluster; + MSDOS_I(inode)->file_cluster = f_clu; + MSDOS_I(inode)->disk_cluster = d_clu; + if (prev_f_clu == 0) + goto out; + f_clu = prev_f_clu; + d_clu = prev_d_clu; + } + + for (walk = sbi->cache; walk->next; walk = (last = walk)->next) { + if (walk->start_cluster == first && + walk->file_cluster == f_clu) { if (walk->disk_cluster != d_clu) { printk(KERN_ERR "FAT: cache corruption" " (ino %lu)\n", inode->i_ino); - spin_unlock(&fat_cache_lock); - fat_cache_inval_inode(inode); - return; + __fat_cache_inval_inode(inode); + goto out; } + if (last == NULL) + goto out; + /* update LRU */ - if (last == NULL) { - spin_unlock(&fat_cache_lock); - return; - } last->next = walk->next; - walk->next = fat_cache; - fat_cache = walk; + walk->next = sbi->cache; + sbi->cache = walk; #ifdef DEBUG -list_cache(); + list_cache(); #endif - spin_unlock(&fat_cache_lock); - return; + goto out; } - walk->sb = inode->i_sb; + } walk->start_cluster = first; walk->file_cluster = f_clu; walk->disk_cluster = d_clu; last->next = NULL; - walk->next = fat_cache; - fat_cache = walk; - spin_unlock(&fat_cache_lock); + walk->next = sbi->cache; + sbi->cache = walk; #ifdef DEBUG -list_cache(); + list_cache(); #endif +out: + spin_unlock(&sbi->cache_lock); } - -/* Cache invalidation occurs rarely, thus the LRU chain is not updated. It - fixes itself after a while. */ - -void fat_cache_inval_inode(struct inode *inode) -{ - struct fat_cache *walk; - int first = MSDOS_I(inode)->i_start; - - spin_lock(&fat_cache_lock); - for (walk = fat_cache; walk; walk = walk->next) - if (walk->sb == inode->i_sb - && walk->start_cluster == first) - walk->sb = NULL; - spin_unlock(&fat_cache_lock); -} - - -void fat_cache_inval_dev(struct super_block *sb) -{ - struct fat_cache *walk; - - spin_lock(&fat_cache_lock); - for (walk = fat_cache; walk; walk = walk->next) - if (walk->sb == sb) - walk->sb = 0; - spin_unlock(&fat_cache_lock); -} - - static int fat_get_cluster(struct inode *inode, int cluster) { struct super_block *sb = inode->i_sb; @@ -302,32 +314,36 @@ return nr; } -int fat_bmap(struct inode *inode, int sector) +int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys) { struct super_block *sb = inode->i_sb; struct msdos_sb_info *sbi = MSDOS_SB(sb); - int cluster, offset, last_block; + sector_t last_block; + int cluster, offset; + *phys = 0; if ((sbi->fat_bits != 32) && (inode->i_ino == MSDOS_ROOT_INO || (S_ISDIR(inode->i_mode) && !MSDOS_I(inode)->i_start))) { - if (sector >= sbi->dir_entries >> sbi->dir_per_block_bits) - return 0; - return sector + sbi->dir_start; + if (sector < (sbi->dir_entries >> sbi->dir_per_block_bits)) + *phys = sector + sbi->dir_start; + return 0; } last_block = (MSDOS_I(inode)->mmu_private + (sb->s_blocksize - 1)) >> sb->s_blocksize_bits; if (sector >= last_block) return 0; - cluster = sector / sbi->cluster_size; - offset = sector % sbi->cluster_size; + cluster = sector >> (sbi->cluster_bits - sb->s_blocksize_bits); + offset = sector & (sbi->cluster_size - 1); cluster = fat_get_cluster(inode, cluster); if (cluster < 0) return cluster; - else if (!cluster) - return 0; - return (cluster - 2) * sbi->cluster_size + sbi->data_start + offset; + else if (cluster) { + *phys = ((sector_t)cluster - 2) * sbi->cluster_size + + sbi->data_start + offset; + } + return 0; } diff -Nru a/fs/fat/dir.c b/fs/fat/dir.c --- a/fs/fat/dir.c Mon Jun 9 23:16:06 2003 +++ b/fs/fat/dir.c Mon Jun 9 23:16:06 2003 @@ -191,11 +191,11 @@ int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate; int utf8 = MSDOS_SB(sb)->options.utf8; unsigned short opt_shortname = MSDOS_SB(sb)->options.shortname; - int ino, chl, i, j, last_u, res = 0; - loff_t cpos = 0; + int chl, i, j, last_u, res = 0; + loff_t i_pos, cpos = 0; while(1) { - if (fat_get_entry(inode,&cpos,&bh,&de,&ino) == -1) + if (fat_get_entry(inode,&cpos,&bh,&de,&i_pos) == -1) goto EODir; parse_record: long_slots = 0; @@ -246,7 +246,7 @@ if (ds->id & 0x40) { unicode[offset + 13] = 0; } - if (fat_get_entry(inode,&cpos,&bh,&de,&ino)<0) + if (fat_get_entry(inode,&cpos,&bh,&de,&i_pos)<0) goto EODir; if (slot == 0) break; @@ -358,14 +358,15 @@ int utf8 = MSDOS_SB(sb)->options.utf8; int nocase = MSDOS_SB(sb)->options.nocase; unsigned short opt_shortname = MSDOS_SB(sb)->options.shortname; - int ino, inum, chi, chl, i, i2, j, last, last_u, dotoffset = 0; - loff_t cpos; + unsigned long inum; + int chi, chl, i, i2, j, last, last_u, dotoffset = 0; + loff_t i_pos, cpos; int ret = 0; lock_kernel(); cpos = filp->f_pos; -/* Fake . and .. for the root directory. */ + /* Fake . and .. for the root directory. */ if (inode->i_ino == MSDOS_ROOT_INO) { while (cpos < 2) { if (filldir(dirent, "..", cpos+1, cpos, MSDOS_ROOT_INO, DT_DIR) < 0) @@ -387,7 +388,7 @@ bh = NULL; GetNew: long_slots = 0; - if (fat_get_entry(inode,&cpos,&bh,&de,&ino) == -1) + if (fat_get_entry(inode,&cpos,&bh,&de,&i_pos) == -1) goto EODir; /* Check for long filename entry */ if (isvfat) { @@ -445,7 +446,7 @@ if (ds->id & 0x40) { unicode[offset + 13] = 0; } - if (fat_get_entry(inode,&cpos,&bh,&de,&ino) == -1) + if (fat_get_entry(inode,&cpos,&bh,&de,&i_pos) == -1) goto EODir; if (slot == 0) break; @@ -533,7 +534,7 @@ else if (!memcmp(de->name,MSDOS_DOTDOT,11)) { inum = parent_ino(filp->f_dentry); } else { - struct inode *tmp = fat_iget(sb, ino); + struct inode *tmp = fat_iget(sb, i_pos); if (tmp) { inum = tmp->i_ino; iput(tmp); @@ -591,23 +592,23 @@ return fat_readdirx(inode, filp, dirent, filldir, 0, 0); } -static int vfat_ioctl_fill( - void * buf, - const char * name, - int name_len, - loff_t offset, - ino_t ino, - unsigned int d_type) +struct fat_ioctl_filldir_callback { + struct dirent __user *dirent; + int result; +}; + +static int fat_ioctl_filldir(void *__buf, const char * name, int name_len, + loff_t offset, ino_t ino, unsigned int d_type) { - struct dirent *d1 = (struct dirent *)buf; - struct dirent *d2 = d1 + 1; + struct fat_ioctl_filldir_callback *buf = __buf; + struct dirent __user *d1 = buf->dirent; + struct dirent __user *d2 = d1 + 1; int len, slen; int dotdir; - get_user(len, &d1->d_reclen); - if (len != 0) { - return -1; - } + if (buf->result) + return -EINVAL; + buf->result++; if ((name_len == 1 && name[0] == '.') || (name_len == 2 && name[0] == '.' && name[1] == '.')) { @@ -618,73 +619,79 @@ len = strlen(name); } if (len != name_len) { - copy_to_user(d2->d_name, name, len); - put_user(0, d2->d_name + len); - put_user(len, &d2->d_reclen); - put_user(ino, &d2->d_ino); - put_user(offset, &d2->d_off); slen = name_len - len; - copy_to_user(d1->d_name, name+len+1, slen); - put_user(0, d1->d_name+slen); - put_user(slen, &d1->d_reclen); + if (copy_to_user(d2->d_name, name, len) || + put_user(0, d2->d_name + len) || + put_user(len, &d2->d_reclen) || + put_user(ino, &d2->d_ino) || + put_user(offset, &d2->d_off) || + copy_to_user(d1->d_name, name+len+1, slen) || + put_user(0, d1->d_name+slen) || + put_user(slen, &d1->d_reclen)) + goto efault; } else { - put_user(0, d2->d_name); - put_user(0, &d2->d_reclen); - copy_to_user(d1->d_name, name, len); - put_user(0, d1->d_name+len); - put_user(len, &d1->d_reclen); + if (put_user(0, d2->d_name) || + put_user(0, &d2->d_reclen) || + copy_to_user(d1->d_name, name, len) || + put_user(0, d1->d_name+len) || + put_user(len, &d1->d_reclen)) + goto efault; } - return 0; +efault: + buf->result = -EFAULT; + return -EFAULT; } int fat_dir_ioctl(struct inode * inode, struct file * filp, unsigned int cmd, unsigned long arg) { - int err; + struct fat_ioctl_filldir_callback buf; + struct dirent __user *d1 = (struct dirent *)arg; + int ret, shortname, both; + + if (!access_ok(VERIFY_WRITE, d1, sizeof(struct dirent[2]))) + return -EFAULT; /* - * We want to provide an interface for Samba to be able - * to get the short filename for a given long filename. - * Samba should use this ioctl instead of readdir() to - * get the information it needs. + * Yes, we don't need this put_user() absolutely. However old + * code didn't return the right value. So, app use this value, + * in order to check whether it is EOF. */ + if (put_user(0, &d1->d_reclen)) + return -EFAULT; + + buf.dirent = d1; + buf.result = 0; switch (cmd) { - case VFAT_IOCTL_READDIR_BOTH: { - struct dirent *d1 = (struct dirent *)arg; - err = verify_area(VERIFY_WRITE, d1, sizeof(struct dirent[2])); - if (err) - return err; - put_user(0, &d1->d_reclen); - return fat_readdirx(inode,filp,(void *)arg, - vfat_ioctl_fill, 0, 1); - } - case VFAT_IOCTL_READDIR_SHORT: { - struct dirent *d1 = (struct dirent *)arg; - put_user(0, &d1->d_reclen); - err = verify_area(VERIFY_WRITE, d1, sizeof(struct dirent[2])); - if (err) - return err; - return fat_readdirx(inode,filp,(void *)arg, - vfat_ioctl_fill, 1, 1); - } + case VFAT_IOCTL_READDIR_SHORT: + shortname = 1; + both = 1; + break; + case VFAT_IOCTL_READDIR_BOTH: + shortname = 0; + both = 1; + break; default: return -EINVAL; } - - return 0; + ret = fat_readdirx(inode, filp, &buf, fat_ioctl_filldir, + shortname, both); + if (ret >= 0) + ret = buf.result; + return ret; } /***** See if directory is empty */ int fat_dir_empty(struct inode *dir) { - loff_t pos; + loff_t pos, i_pos; struct buffer_head *bh; struct msdos_dir_entry *de; - int ino,result = 0; + int result = 0; pos = 0; bh = NULL; - while (fat_get_entry(dir,&pos,&bh,&de,&ino) > -1) { + while (fat_get_entry(dir,&pos,&bh,&de,&i_pos) > -1) { /* Ignore vfat longname entries */ if (de->attr == ATTR_EXT) continue; @@ -703,7 +710,7 @@ /* This assumes that size of cluster is above the 32*slots */ int fat_add_entries(struct inode *dir,int slots, struct buffer_head **bh, - struct msdos_dir_entry **de, int *ino) + struct msdos_dir_entry **de, loff_t *i_pos) { struct super_block *sb = dir->i_sb; loff_t offset, curr; @@ -713,7 +720,7 @@ offset = curr = 0; *bh = NULL; row = 0; - while (fat_get_entry(dir, &curr, bh, de, ino) > -1) { + while (fat_get_entry(dir, &curr, bh, de, i_pos) > -1) { /* check the maximum size of directory */ if (curr >= FAT_MAX_DIR_SIZE) { brelse(*bh); @@ -735,7 +742,7 @@ return PTR_ERR(new_bh); brelse(new_bh); do { - fat_get_entry(dir, &curr, bh, de, ino); + fat_get_entry(dir, &curr, bh, de, i_pos); } while (++row < slots); return offset; diff -Nru a/fs/fat/file.c b/fs/fat/file.c --- a/fs/fat/file.c Mon Jun 9 23:16:08 2003 +++ b/fs/fat/file.c Mon Jun 9 23:16:08 2003 @@ -32,11 +32,12 @@ struct buffer_head *bh_result, int create) { struct super_block *sb = inode->i_sb; - unsigned long phys; + sector_t phys; + int err; - phys = fat_bmap(inode, iblock); - if (phys < 0) - return phys; + err = fat_bmap(inode, iblock, &phys); + if (err) + return err; if (phys) { map_bh(bh_result, sb, phys); return 0; @@ -55,9 +56,9 @@ return error; } MSDOS_I(inode)->mmu_private += sb->s_blocksize; - phys = fat_bmap(inode, iblock); - if (phys < 0) - return phys; + err = fat_bmap(inode, iblock, &phys); + if (err) + return err; if (!phys) BUG(); set_buffer_new(bh_result); diff -Nru a/fs/fat/inode.c b/fs/fat/inode.c --- a/fs/fat/inode.c Mon Jun 9 23:16:10 2003 +++ b/fs/fat/inode.c Mon Jun 9 23:16:10 2003 @@ -60,17 +60,17 @@ } } -static inline unsigned long fat_hash(struct super_block *sb, int i_pos) +static inline unsigned long fat_hash(struct super_block *sb, loff_t i_pos) { unsigned long tmp = (unsigned long)i_pos | (unsigned long) sb; tmp = tmp + (tmp >> FAT_HASH_BITS) + (tmp >> FAT_HASH_BITS * 2); return tmp & FAT_HASH_MASK; } -void fat_attach(struct inode *inode, int i_pos) +void fat_attach(struct inode *inode, loff_t i_pos) { spin_lock(&fat_inode_lock); - MSDOS_I(inode)->i_location = i_pos; + MSDOS_I(inode)->i_pos = i_pos; list_add(&MSDOS_I(inode)->i_fat_hash, fat_inode_hashtable + fat_hash(inode->i_sb, i_pos)); spin_unlock(&fat_inode_lock); @@ -79,12 +79,12 @@ void fat_detach(struct inode *inode) { spin_lock(&fat_inode_lock); - MSDOS_I(inode)->i_location = 0; + MSDOS_I(inode)->i_pos = 0; list_del_init(&MSDOS_I(inode)->i_fat_hash); spin_unlock(&fat_inode_lock); } -struct inode *fat_iget(struct super_block *sb, int i_pos) +struct inode *fat_iget(struct super_block *sb, loff_t i_pos) { struct list_head *p = fat_inode_hashtable + fat_hash(sb, i_pos); struct list_head *walk; @@ -96,7 +96,7 @@ i = list_entry(walk, struct msdos_inode_info, i_fat_hash); if (i->vfs_inode.i_sb != sb) continue; - if (i->i_location != i_pos) + if (i->i_pos != i_pos) continue; inode = igrab(&i->vfs_inode); if (inode) @@ -109,11 +109,11 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de); struct inode *fat_build_inode(struct super_block *sb, - struct msdos_dir_entry *de, int ino, int *res) + struct msdos_dir_entry *de, loff_t i_pos, int *res) { struct inode *inode; *res = 0; - inode = fat_iget(sb, ino); + inode = fat_iget(sb, i_pos); if (inode) goto out; inode = new_inode(sb); @@ -128,7 +128,7 @@ inode = NULL; goto out; } - fat_attach(inode, ino); + fat_attach(inode, i_pos); insert_inode_hash(inode); out: return inode; @@ -160,7 +160,6 @@ struct msdos_sb_info *sbi = MSDOS_SB(sb); fat_clusters_flush(sb); - fat_cache_inval_dev(sb); if (sbi->nls_disk) { unload_nls(sbi->nls_disk); sbi->nls_disk = NULL; @@ -500,7 +499,7 @@ struct msdos_sb_info *sbi = MSDOS_SB(sb); int error; - MSDOS_I(inode)->i_location = 0; + MSDOS_I(inode)->i_pos = 0; inode->i_uid = sbi->options.fs_uid; inode->i_gid = sbi->options.fs_gid; inode->i_version++; @@ -537,9 +536,10 @@ * 0/ i_ino - for fast, reliable lookup if still in the cache * 1/ i_generation - to see if i_ino is still valid * bit 0 == 0 iff directory - * 2/ i_location - if ino has changed, but still in cache - * 3/ i_logstart - to semi-verify inode found at i_location - * 4/ parent->i_logstart - maybe used to hunt for the file on disc + * 2/ i_pos - if ino has changed, but still in cache (hi) + * 3/ i_pos - if ino has changed, but still in cache (low) + * 4/ i_logstart - to semi-verify inode found at i_location + * 5/ parent->i_logstart - maybe used to hunt for the file on disc * */ @@ -551,7 +551,7 @@ if (fhtype != 3) return ERR_PTR(-ESTALE); - if (len < 5) + if (len < 6) return ERR_PTR(-ESTALE); return sb->s_export_op->find_exported_dentry(sb, fh, NULL, acceptable, context); @@ -570,13 +570,15 @@ inode = NULL; } if (!inode) { - /* try 2 - see if i_location is in F-d-c + loff_t i_pos = ((loff_t)fh[2] << 32) | fh[3]; + + /* try 2 - see if i_pos is in F-d-c * require i_logstart to be the same * Will fail if you truncate and then re-write */ - inode = fat_iget(sb, fh[2]); - if (inode && MSDOS_I(inode)->i_logstart != fh[3]) { + inode = fat_iget(sb, i_pos); + if (inode && MSDOS_I(inode)->i_logstart != fh[4]) { iput(inode); inode = NULL; } @@ -616,15 +618,16 @@ int len = *lenp; struct inode *inode = de->d_inode; - if (len < 5) + if (len < 6) return 255; /* no room */ - *lenp = 5; + *lenp = 6; fh[0] = inode->i_ino; fh[1] = inode->i_generation; - fh[2] = MSDOS_I(inode)->i_location; - fh[3] = MSDOS_I(inode)->i_logstart; + fh[2] = (__u32)(MSDOS_I(inode)->i_pos >> 32); + fh[3] = (__u32)MSDOS_I(inode)->i_pos; + fh[4] = MSDOS_I(inode)->i_logstart; spin_lock(&de->d_lock); - fh[4] = MSDOS_I(de->d_parent->d_inode)->i_logstart; + fh[5] = MSDOS_I(de->d_parent->d_inode)->i_logstart; spin_unlock(&de->d_lock); return 3; } @@ -635,15 +638,15 @@ struct msdos_dir_entry *de = NULL; struct dentry *parent = NULL; int res; - int ino = 0; + loff_t i_pos = 0; struct inode *inode; lock_kernel(); - res = fat_scan(child->d_inode, MSDOS_DOTDOT, &bh, &de, &ino); + res = fat_scan(child->d_inode, MSDOS_DOTDOT, &bh, &de, &i_pos); if (res < 0) goto out; - inode = fat_build_inode(child->d_sb, de, ino, &res); + inode = fat_build_inode(child->d_sb, de, i_pos, &res); if (res) goto out; if (!inode) @@ -762,7 +765,7 @@ if (!parse_options(data, isvfat, &debug, &sbi->options)) goto out_fail; - fat_cache_init(); + fat_cache_init(sb); /* set up enough so that it can read an inode */ init_MUTEX(&sbi->fat_lock); @@ -1098,7 +1101,8 @@ struct msdos_sb_info *sbi = MSDOS_SB(sb); int error; - MSDOS_I(inode)->i_location = 0; + MSDOS_I(inode)->file_cluster = MSDOS_I(inode)->disk_cluster = 0; + MSDOS_I(inode)->i_pos = 0; inode->i_uid = sbi->options.fs_uid; inode->i_gid = sbi->options.fs_gid; inode->i_version++; @@ -1112,10 +1116,9 @@ inode->i_fop = &fat_dir_operations; MSDOS_I(inode)->i_start = CF_LE_W(de->start); - if (sbi->fat_bits == 32) { - MSDOS_I(inode)->i_start |= - (CF_LE_W(de->starthi) << 16); - } + if (sbi->fat_bits == 32) + MSDOS_I(inode)->i_start |= (CF_LE_W(de->starthi) << 16); + MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start; error = fat_calc_dir_size(inode); if (error < 0) @@ -1131,10 +1134,9 @@ ? S_IRUGO|S_IWUGO : S_IRWXUGO) & ~sbi->options.fs_fmask) | S_IFREG; MSDOS_I(inode)->i_start = CF_LE_W(de->start); - if (sbi->fat_bits == 32) { - MSDOS_I(inode)->i_start |= - (CF_LE_W(de->starthi) << 16); - } + if (sbi->fat_bits == 32) + MSDOS_I(inode)->i_start |= (CF_LE_W(de->starthi) << 16); + MSDOS_I(inode)->i_logstart = MSDOS_I(inode)->i_start; inode->i_size = CF_LE_L(de->size); inode->i_op = &fat_file_inode_operations; @@ -1168,22 +1170,22 @@ struct super_block *sb = inode->i_sb; struct buffer_head *bh; struct msdos_dir_entry *raw_entry; - unsigned int i_pos; + loff_t i_pos; retry: - i_pos = MSDOS_I(inode)->i_location; + i_pos = MSDOS_I(inode)->i_pos; if (inode->i_ino == MSDOS_ROOT_INO || !i_pos) { return; } lock_kernel(); if (!(bh = sb_bread(sb, i_pos >> MSDOS_SB(sb)->dir_per_block_bits))) { - fat_fs_panic(sb, "unable to read i-node block (ino %lu)", + fat_fs_panic(sb, "unable to read i-node block (i_pos %llu)", i_pos); unlock_kernel(); return; } spin_lock(&fat_inode_lock); - if (i_pos != MSDOS_I(inode)->i_location) { + if (i_pos != MSDOS_I(inode)->i_pos) { spin_unlock(&fat_inode_lock); brelse(bh); unlock_kernel(); diff -Nru a/fs/fat/misc.c b/fs/fat/misc.c --- a/fs/fat/misc.c Mon Jun 9 23:16:17 2003 +++ b/fs/fat/misc.c Mon Jun 9 23:16:17 2003 @@ -178,9 +178,9 @@ struct buffer_head *fat_extend_dir(struct inode *inode) { struct super_block *sb = inode->i_sb; - int nr, sector, last_sector; struct buffer_head *bh, *res = NULL; - int cluster_size = MSDOS_SB(sb)->cluster_size; + int nr, cluster_size = MSDOS_SB(sb)->cluster_size; + sector_t sector, last_sector; if (MSDOS_SB(sb)->fat_bits != 32) { if (inode->i_ino == MSDOS_ROOT_INO) @@ -191,7 +191,7 @@ if (nr < 0) return ERR_PTR(nr); - sector = MSDOS_SB(sb)->data_start + (nr - 2) * cluster_size; + sector = ((sector_t)nr - 2) * cluster_size + MSDOS_SB(sb)->data_start; last_sector = sector + cluster_size; for ( ; sector < last_sector; sector++) { if ((bh = sb_getblk(sb, sector))) { @@ -289,11 +289,13 @@ */ int fat__get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh, - struct msdos_dir_entry **de, int *ino) + struct msdos_dir_entry **de, loff_t *i_pos) { struct super_block *sb = dir->i_sb; struct msdos_sb_info *sbi = MSDOS_SB(sb); - int sector, offset, iblock; + sector_t phys, iblock; + loff_t offset; + int err; next: offset = *pos; @@ -302,14 +304,14 @@ *bh = NULL; iblock = *pos >> sb->s_blocksize_bits; - sector = fat_bmap(dir, iblock); - if (sector <= 0) + err = fat_bmap(dir, iblock, &phys); + if (err || !phys) return -1; /* beyond EOF or error */ - *bh = sb_bread(sb, sector); + *bh = sb_bread(sb, phys); if (*bh == NULL) { - printk(KERN_ERR "FAT: Directory bread(block %d) failed\n", - sector); + printk(KERN_ERR "FAT: Directory bread(block %llu) failed\n", + (unsigned long long)phys); /* skip this block */ *pos = (iblock + 1) << sb->s_blocksize_bits; goto next; @@ -318,7 +320,7 @@ offset &= sb->s_blocksize - 1; *pos += sizeof(struct msdos_dir_entry); *de = (struct msdos_dir_entry *)((*bh)->b_data + offset); - *ino = (sector << sbi->dir_per_block_bits) + (offset >> MSDOS_DIR_BITS); + *i_pos = ((loff_t)phys << sbi->dir_per_block_bits) + (offset >> MSDOS_DIR_BITS); return 0; } @@ -357,7 +359,7 @@ done = !IS_FREE(data[entry].name) \ && ( \ ( \ - (MSDOS_SB(sb)->fat_bits != 32) ? 0 : (CF_LE_W(data[entry].starthi) << 16) \ + (sbi->fat_bits != 32) ? 0 : (CF_LE_W(data[entry].starthi) << 16) \ ) \ | CF_LE_W(data[entry].start) \ ) == *number; @@ -374,35 +376,38 @@ (*number)++; \ } -static int raw_scan_sector(struct super_block *sb,int sector,const char *name, - int *number,int *ino,struct buffer_head **res_bh, - struct msdos_dir_entry **res_de) +static int raw_scan_sector(struct super_block *sb, sector_t sector, + const char *name, int *number, loff_t *i_pos, + struct buffer_head **res_bh, + struct msdos_dir_entry **res_de) { + struct msdos_sb_info *sbi = MSDOS_SB(sb); struct buffer_head *bh; struct msdos_dir_entry *data; int entry,start,done; - if (!(bh = sb_bread(sb,sector))) + if (!(bh = sb_bread(sb, sector))) return -EIO; data = (struct msdos_dir_entry *) bh->b_data; - for (entry = 0; entry < MSDOS_SB(sb)->dir_per_block; entry++) { + for (entry = 0; entry < sbi->dir_per_block; entry++) { /* RSS_COUNT: if (data[entry].name == name) done=true else done=false. */ if (name) { RSS_NAME } else { - if (!ino) RSS_COUNT + if (!i_pos) RSS_COUNT else { if (number) RSS_START else RSS_FREE } } if (done) { - if (ino) - *ino = sector * MSDOS_SB(sb)->dir_per_block + entry; + if (i_pos) { + *i_pos = ((loff_t)sector << sbi->dir_per_block_bits) + entry; + } start = CF_LE_W(data[entry].start); - if (MSDOS_SB(sb)->fat_bits == 32) { + if (sbi->fat_bits == 32) start |= (CF_LE_W(data[entry].starthi) << 16); - } + if (!res_bh) brelse(bh); else { @@ -422,16 +427,19 @@ * requested entry is found or the end of the directory is reached. */ -static int raw_scan_root(struct super_block *sb,const char *name,int *number,int *ino, - struct buffer_head **res_bh,struct msdos_dir_entry **res_de) +static int raw_scan_root(struct super_block *sb, const char *name, + int *number, loff_t *i_pos, + struct buffer_head **res_bh, + struct msdos_dir_entry **res_de) { int count,cluster; for (count = 0; count < MSDOS_SB(sb)->dir_entries / MSDOS_SB(sb)->dir_per_block; count++) { - if ((cluster = raw_scan_sector(sb,MSDOS_SB(sb)->dir_start+count, - name,number,ino,res_bh,res_de)) >= 0) + cluster = raw_scan_sector(sb, MSDOS_SB(sb)->dir_start + count, + name, number, i_pos, res_bh, res_de); + if (cluster >= 0) return cluster; } return -ENOENT; @@ -443,24 +451,29 @@ * requested entry is found or the end of the directory is reached. */ -static int raw_scan_nonroot(struct super_block *sb,int start,const char *name, - int *number,int *ino,struct buffer_head **res_bh,struct msdos_dir_entry - **res_de) +static int raw_scan_nonroot(struct super_block *sb, int start, const char *name, + int *number, loff_t *i_pos, + struct buffer_head **res_bh, + struct msdos_dir_entry **res_de) { + struct msdos_sb_info *sbi = MSDOS_SB(sb); int count, cluster; unsigned long dir_size = 0; + sector_t sector; #ifdef DEBUG printk("raw_scan_nonroot: start=%d\n",start); #endif do { - for (count = 0; count < MSDOS_SB(sb)->cluster_size; count++) { - if ((cluster = raw_scan_sector(sb,(start-2)* - MSDOS_SB(sb)->cluster_size+MSDOS_SB(sb)->data_start+ - count,name,number,ino,res_bh,res_de)) >= 0) + for (count = 0; count < sbi->cluster_size; count++) { + sector = ((sector_t)start - 2) * sbi->cluster_size + + count + sbi->data_start; + cluster = raw_scan_sector(sb, sector, name, number, + i_pos, res_bh, res_de); + if (cluster >= 0) return cluster; } - dir_size += 1 << MSDOS_SB(sb)->cluster_bits; + dir_size += 1 << sbi->cluster_bits; if (dir_size > FAT_MAX_DIR_SIZE) { fat_fs_panic(sb, "Directory %d: " "exceeded the maximum size of directory", @@ -492,13 +505,13 @@ */ static int raw_scan(struct super_block *sb, int start, const char *name, - int *number, int *ino, struct buffer_head **res_bh, - struct msdos_dir_entry **res_de) + loff_t *i_pos, struct buffer_head **res_bh, + struct msdos_dir_entry **res_de) { if (start) - return raw_scan_nonroot(sb,start,name,number,ino,res_bh,res_de); + return raw_scan_nonroot(sb,start,name,NULL,i_pos,res_bh,res_de); else - return raw_scan_root(sb,name,number,ino,res_bh,res_de); + return raw_scan_root(sb,name,NULL,i_pos,res_bh,res_de); } /* @@ -507,19 +520,21 @@ */ int fat_subdirs(struct inode *dir) { - int count; + struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb); + int number; - count = 0; - if ((dir->i_ino == MSDOS_ROOT_INO) && - (MSDOS_SB(dir->i_sb)->fat_bits != 32)) { - (void) raw_scan_root(dir->i_sb,NULL,&count,NULL,NULL,NULL); - } else { - if ((dir->i_ino != MSDOS_ROOT_INO) && - !MSDOS_I(dir)->i_start) return 0; /* in mkdir */ - else (void) raw_scan_nonroot(dir->i_sb,MSDOS_I(dir)->i_start, - NULL,&count,NULL,NULL,NULL); + number = 0; + if ((dir->i_ino == MSDOS_ROOT_INO) && (sbi->fat_bits != 32)) + raw_scan_root(dir->i_sb, NULL, &number, NULL, NULL, NULL); + else { + if ((dir->i_ino != MSDOS_ROOT_INO) && !MSDOS_I(dir)->i_start) + return 0; /* in mkdir */ + else { + raw_scan_nonroot(dir->i_sb, MSDOS_I(dir)->i_start, + NULL, &number, NULL, NULL, NULL); + } } - return count; + return number; } @@ -528,12 +543,12 @@ * for an empty directory slot (name is NULL). Returns an error code or zero. */ -int fat_scan(struct inode *dir,const char *name,struct buffer_head **res_bh, - struct msdos_dir_entry **res_de,int *ino) +int fat_scan(struct inode *dir, const char *name, struct buffer_head **res_bh, + struct msdos_dir_entry **res_de, loff_t *i_pos) { int res; - res = raw_scan(dir->i_sb,MSDOS_I(dir)->i_start, - name, NULL, ino, res_bh, res_de); - return res<0 ? res : 0; + res = raw_scan(dir->i_sb, MSDOS_I(dir)->i_start, name, i_pos, + res_bh, res_de); + return (res < 0) ? res : 0; } diff -Nru a/fs/fcntl.c b/fs/fcntl.c --- a/fs/fcntl.c Mon Jun 9 23:16:15 2003 +++ b/fs/fcntl.c Mon Jun 9 23:16:15 2003 @@ -12,6 +12,7 @@ #include <linux/slab.h> #include <linux/module.h> #include <linux/security.h> +#include <linux/ptrace.h> #include <asm/poll.h> #include <asm/siginfo.h> @@ -80,11 +81,11 @@ */ static int locate_fd(struct files_struct *files, - struct file *file, int orig_start) + struct file *file, unsigned int orig_start) { unsigned int newfd; + unsigned int start; int error; - int start; error = -EINVAL; if (orig_start >= current->rlim[RLIMIT_NOFILE].rlim_cur) @@ -129,7 +130,7 @@ return error; } -static int dupfd(struct file *file, int start) +static int dupfd(struct file *file, unsigned int start) { struct files_struct * files = current->files; int fd; @@ -286,10 +287,8 @@ switch (cmd) { case F_DUPFD: - if (arg < NR_OPEN) { - get_file(filp); - err = dupfd(filp, arg); - } + get_file(filp); + err = dupfd(filp, arg); break; case F_GETFD: err = get_close_on_exec(fd); @@ -320,6 +319,7 @@ * to fix this will be in libc. */ err = filp->f_owner.pid; + force_successful_syscall_return(); break; case F_SETOWN: err = f_setown(filp, arg, 1); diff -Nru a/fs/filesystems.c b/fs/filesystems.c --- a/fs/filesystems.c Mon Jun 9 23:16:16 2003 +++ b/fs/filesystems.c Mon Jun 9 23:16:16 2003 @@ -49,38 +49,6 @@ return p; } - -/* define fs_subsys */ -static decl_subsys(fs, NULL, NULL); - -static int register_fs_subsys(struct file_system_type * fs) -{ - struct subsystem *sub = &fs->subsys; - - snprintf(sub->kset.kobj.name, KOBJ_NAME_LEN, "%s", fs->name); - subsys_set_kset(fs, fs_subsys); - return subsystem_register(sub); -} - -static int unlink_fs(struct file_system_type * fs) -{ - struct file_system_type ** tmp; - - write_lock(&file_systems_lock); - tmp = &file_systems; - while (*tmp) { - if (fs == *tmp) { - *tmp = fs->next; - fs->next = NULL; - write_unlock(&file_systems_lock); - return 0; - } - tmp = &(*tmp)->next; - } - write_unlock(&file_systems_lock); - return -EINVAL; -} - /** * register_filesystem - register a new filesystem * @fs: the file system structure @@ -111,12 +79,6 @@ else *p = fs; write_unlock(&file_systems_lock); - - if (!res) { - /* we implicitly possess reference to @fs during registration, - * so it cannot be unregister from under us. */ - register_fs_subsys(fs); - } return res; } @@ -134,44 +96,21 @@ int unregister_filesystem(struct file_system_type * fs) { - int res; - - res = unlink_fs(fs); - if (!res) - subsystem_unregister(&fs->subsys); - return res; -} - -extern int sysfs_init(void); - -/** - * fs_subsys_init - initialize sysfs and fs subsystem. - * - * In order to register filesystems in sysfs, it has to be - * initialized. Also, we need the base fs filesystem, so the - * registered filesystems have a home. - * - * During sysfs_init(), the registration of sysfs into itself - * will fail, since it's not mounted yet. To make sure that - * sysfs does show up, we re-register sysfs's embedded subsystem, - * which will get added, since sysfs is now mounted. - */ - -void __init fs_subsys_init(void) -{ - struct file_system_type ** p; - - /* make sure sysfs is up and running */ - sysfs_init(); - - /* register fs_subsys */ - subsystem_register(&fs_subsys); - - p = find_filesystem("sysfs"); + struct file_system_type ** tmp; - if (p) - /* make sure it's registered */ - register_fs_subsys(*p); + write_lock(&file_systems_lock); + tmp = &file_systems; + while (*tmp) { + if (fs == *tmp) { + *tmp = fs->next; + fs->next = NULL; + write_unlock(&file_systems_lock); + return 0; + } + tmp = &(*tmp)->next; + } + write_unlock(&file_systems_lock); + return -EINVAL; } static int fs_index(const char __user * __name) diff -Nru a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c --- a/fs/hugetlbfs/inode.c Mon Jun 9 23:16:18 2003 +++ b/fs/hugetlbfs/inode.c Mon Jun 9 23:16:18 2003 @@ -48,9 +48,6 @@ loff_t len; int ret; - if (!capable(CAP_IPC_LOCK)) - return -EPERM; - if (vma->vm_start & ~HPAGE_MASK) return -EINVAL; @@ -231,6 +228,7 @@ spin_unlock(&inode_lock); if (inode->i_data.nrpages) truncate_hugepages(&inode->i_data, 0); + clear_inode(inode); destroy_inode(inode); } @@ -317,7 +315,6 @@ struct inode *inode = dentry->d_inode; int error; unsigned int ia_valid = attr->ia_valid; - unsigned long dn_mask; BUG_ON(!inode); @@ -335,26 +332,21 @@ if (error) goto out; attr->ia_valid &= ~ATTR_SIZE; - error = inode_setattr(inode, attr); } - if (error) - goto out; - dn_mask = setattr_mask(ia_valid); - if (dn_mask) - dnotify_parent(dentry, dn_mask); + error = inode_setattr(inode, attr); out: return error; } -static struct inode *hugetlbfs_get_inode(struct super_block *sb, - int mode, dev_t dev) +static struct inode *hugetlbfs_get_inode(struct super_block *sb, uid_t uid, + gid_t gid, int mode, dev_t dev) { struct inode * inode = new_inode(sb); if (inode) { inode->i_mode = mode; - inode->i_uid = current->fsuid; - inode->i_gid = current->fsgid; + inode->i_uid = uid; + inode->i_gid = gid; inode->i_blksize = PAGE_CACHE_SIZE; inode->i_blocks = 0; inode->i_rdev = NODEV; @@ -391,7 +383,8 @@ static int hugetlbfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) { - struct inode * inode = hugetlbfs_get_inode(dir->i_sb, mode, dev); + struct inode * inode = hugetlbfs_get_inode(dir->i_sb, current->fsuid, + current->fsgid, mode, dev); int error = -ENOSPC; if (inode) { @@ -421,7 +414,8 @@ struct inode *inode; int error = -ENOSPC; - inode = hugetlbfs_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0); + inode = hugetlbfs_get_inode(dir->i_sb, current->fsuid, + current->fsgid, S_IFLNK|S_IRWXUGO, 0); if (inode) { int l = strlen(symname)+1; error = page_symlink(inode, symname, l); @@ -478,16 +472,67 @@ }; static int -hugetlbfs_fill_super(struct super_block * sb, void * data, int silent) +hugetlbfs_parse_options(char *options, struct hugetlbfs_config *pconfig) +{ + char *opt, *value; + int ret = 0; + + if (!options) + goto out; + while ((opt = strsep(&options, ",")) != NULL) { + if (!*opt) + continue; + + value = strchr(opt, '='); + if (!value || !*value) { + ret = -EINVAL; + goto out; + } else { + *value++ = '\0'; + } + + if (!strcmp(opt, "uid")) + pconfig->uid = simple_strtoul(value, &value, 0); + else if (!strcmp(opt, "gid")) + pconfig->gid = simple_strtoul(value, &value, 0); + else if (!strcmp(opt, "mode")) + pconfig->mode = simple_strtoul(value,&value,0) & 0777U; + else { + ret = -EINVAL; + goto out; + } + + if (*value) { + ret = -EINVAL; + goto out; + } + } + return 0; +out: + pconfig->uid = current->fsuid; + pconfig->gid = current->fsgid; + pconfig->mode = 0755; + return ret; +} + +static int +hugetlbfs_fill_super(struct super_block *sb, void *data, int silent) { struct inode * inode; struct dentry * root; + int ret; + struct hugetlbfs_config config; + + ret = hugetlbfs_parse_options(data, &config); + if (ret) + return ret; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_magic = HUGETLBFS_MAGIC; sb->s_op = &hugetlbfs_ops; - inode = hugetlbfs_get_inode(sb, S_IFDIR | 0755, 0); + inode = hugetlbfs_get_inode(sb, config.uid, config.gid, + S_IFDIR | config.mode, 0); if (!inode) return -ENOMEM; @@ -548,7 +593,8 @@ goto out_dentry; error = -ENOSPC; - inode = hugetlbfs_get_inode(root->d_sb, S_IFREG | S_IRWXUGO, 0); + inode = hugetlbfs_get_inode(root->d_sb, current->fsuid, + current->fsgid, S_IFREG | S_IRWXUGO, 0); if (!inode) goto out_file; diff -Nru a/fs/inode.c b/fs/inode.c --- a/fs/inode.c Mon Jun 9 23:16:19 2003 +++ b/fs/inode.c Mon Jun 9 23:16:19 2003 @@ -484,7 +484,6 @@ repeat: hlist_for_each (node, head) { - prefetch(node->next); inode = hlist_entry(node, struct inode, i_hash); if (inode->i_sb != sb) continue; @@ -510,8 +509,7 @@ repeat: hlist_for_each (node, head) { - prefetch(node->next); - inode = list_entry(node, struct inode, i_hash); + inode = hlist_entry(node, struct inode, i_hash); if (inode->i_ino != ino) continue; if (inode->i_sb != sb) diff -Nru a/fs/jbd/journal.c b/fs/jbd/journal.c --- a/fs/jbd/journal.c Mon Jun 9 23:16:08 2003 +++ b/fs/jbd/journal.c Mon Jun 9 23:16:08 2003 @@ -916,7 +916,7 @@ __brelse(bh); } - fsync_bdev(journal->j_dev); + sync_blockdev(journal->j_dev); jbd_debug(1, "JBD: journal cleared.\n"); /* OK, fill in the initial static fields in the new superblock */ diff -Nru a/fs/jffs2/background.c b/fs/jffs2/background.c --- a/fs/jffs2/background.c Mon Jun 9 23:16:05 2003 +++ b/fs/jffs2/background.c Mon Jun 9 23:16:05 2003 @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: background.c,v 1.33 2002/11/12 09:44:30 dwmw2 Exp $ + * $Id: background.c,v 1.38 2003/05/26 09:50:38 dwmw2 Exp $ * */ @@ -16,9 +16,8 @@ #include <linux/kernel.h> #include <linux/jffs2.h> #include <linux/mtd/mtd.h> -#include <linux/interrupt.h> #include <linux/completion.h> -#include <linux/mtd/compatmac.h> /* recalc_sigpending() */ +#include <linux/sched.h> #include <linux/unistd.h> #include "nodelist.h" @@ -28,10 +27,10 @@ void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c) { - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); if (c->gc_task && thread_should_wake(c)) send_sig(SIGHUP, c->gc_task, 1); - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); } /* This must only ever be called when no GC thread is currently running */ @@ -69,12 +68,12 @@ flush_scheduled_work(); } - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); if (c->gc_task) { D1(printk(KERN_DEBUG "jffs2: Killing GC task %d\n", c->gc_task->pid)); send_sig(SIGKILL, c->gc_task, 1); } - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); wait_for_completion(&c->gc_thread_exit); } @@ -126,9 +125,9 @@ case SIGKILL: D1(printk(KERN_DEBUG "jffs2_garbage_collect_thread(): SIGKILL received.\n")); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); c->gc_task = NULL; - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); complete_and_exit(&c->gc_thread_exit, 0); case SIGHUP: @@ -152,6 +151,7 @@ static int thread_should_wake(struct jffs2_sb_info *c) { int ret = 0; + uint32_t dirty; if (c->unchecked_size) { D1(printk(KERN_DEBUG "thread_should_wake(): unchecked_size %d, checked_ino #%d\n", @@ -159,8 +159,18 @@ return 1; } + /* dirty_size contains blocks on erase_pending_list + * those blocks are counted in c->nr_erasing_blocks. + * If one block is actually erased, it is not longer counted as dirty_space + * but it is counted in c->nr_erasing_blocks, so we add it and subtract it + * with c->nr_erasing_blocks * c->sector_size again. + * Blocks on erasable_list are counted as dirty_size, but not in c->nr_erasing_blocks + * This helps us to force gc and pick eventually a clean block to spread the load. + */ + dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size; + if (c->nr_free_blocks + c->nr_erasing_blocks < JFFS2_RESERVED_BLOCKS_GCTRIGGER && - (c->dirty_size > c->sector_size)) + (dirty > c->sector_size)) ret = 1; D1(printk(KERN_DEBUG "thread_should_wake(): nr_free_blocks %d, nr_erasing_blocks %d, dirty_size 0x%x: %s\n", diff -Nru a/fs/jffs2/build.c b/fs/jffs2/build.c --- a/fs/jffs2/build.c Mon Jun 9 23:16:12 2003 +++ b/fs/jffs2/build.c Mon Jun 9 23:16:12 2003 @@ -7,19 +7,42 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: build.c,v 1.42 2002/09/09 16:29:08 dwmw2 Exp $ + * $Id: build.c,v 1.46 2003/04/29 17:12:26 gleixner Exp $ * */ #include <linux/kernel.h> +#include <linux/sched.h> #include <linux/slab.h> #include "nodelist.h" int jffs2_build_inode_pass1(struct jffs2_sb_info *, struct jffs2_inode_cache *); int jffs2_build_remove_unlinked_inode(struct jffs2_sb_info *, struct jffs2_inode_cache *); +static inline struct jffs2_inode_cache * +first_inode_chain(int *i, struct jffs2_sb_info *c) +{ + for (; *i < INOCACHE_HASHSIZE; (*i)++) { + if (c->inocache_list[*i]) + return c->inocache_list[*i]; + } + return NULL; +} + +static inline struct jffs2_inode_cache * +next_inode(int *i, struct jffs2_inode_cache *ic, struct jffs2_sb_info *c) +{ + /* More in this chain? */ + if (ic->next) + return ic->next; + (*i)++; + return first_inode_chain(i, c); +} -#define for_each_inode(i, c, ic) for (i=0; i<INOCACHE_HASHSIZE; i++) for (ic=c->inocache_list[i]; ic; ic=ic->next) +#define for_each_inode(i, c, ic) \ + for (i = 0, ic = first_inode_chain(&i, (c)); \ + ic; \ + ic = next_inode(&i, ic, (c))) /* Scan plan: - Scan physical nodes. Build map of inodes/dirents. Allocate inocaches as we go @@ -229,6 +252,7 @@ init_MUTEX(&c->alloc_sem); init_MUTEX(&c->erase_free_sem); init_waitqueue_head(&c->erase_wait); + init_waitqueue_head(&c->inocache_wq); spin_lock_init(&c->erase_completion_lock); spin_lock_init(&c->inocache_lock); diff -Nru a/fs/jffs2/compr.c b/fs/jffs2/compr.c --- a/fs/jffs2/compr.c Mon Jun 9 23:16:09 2003 +++ b/fs/jffs2/compr.c Mon Jun 9 23:16:09 2003 @@ -7,14 +7,15 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: compr.c,v 1.24 2002/05/20 14:56:37 dwmw2 Exp $ + * $Id: compr.c,v 1.26 2003/01/12 13:21:28 dwmw2 Exp $ * */ -#ifdef __KERNEL__ +#if defined(__KERNEL__) || defined (__ECOS) #include <linux/kernel.h> #include <linux/string.h> #include <linux/errno.h> +#include <linux/types.h> #else #define KERN_DEBUG #define KERN_NOTICE diff -Nru a/fs/jffs2/compr_rtime.c b/fs/jffs2/compr_rtime.c --- a/fs/jffs2/compr_rtime.c Mon Jun 9 23:16:15 2003 +++ b/fs/jffs2/compr_rtime.c Mon Jun 9 23:16:15 2003 @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: compr_rtime.c,v 1.9 2002/05/20 14:56:37 dwmw2 Exp $ + * $Id: compr_rtime.c,v 1.10 2003/05/11 10:47:13 dwmw2 Exp $ * * * Very simple lz77-ish encoder. @@ -30,7 +30,7 @@ int jffs2_rtime_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen) { - int positions[256]; + short positions[256]; int outpos = 0; int pos=0; @@ -70,7 +70,7 @@ void jffs2_rtime_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen) { - int positions[256]; + short positions[256]; int outpos = 0; int pos=0; diff -Nru a/fs/jffs2/compr_zlib.c b/fs/jffs2/compr_zlib.c --- a/fs/jffs2/compr_zlib.c Mon Jun 9 23:16:05 2003 +++ b/fs/jffs2/compr_zlib.c Mon Jun 9 23:16:05 2003 @@ -7,20 +7,22 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: compr_zlib.c,v 1.18 2002/05/20 14:56:37 dwmw2 Exp $ + * $Id: compr_zlib.c,v 1.23 2003/05/26 09:15:19 dwmw2 Exp $ * */ -#ifndef __KERNEL__ +#if !defined(__KERNEL__) && !defined(__ECOS) #error "The userspace support got too messy and was removed. Update your mkfs.jffs2" #endif #include <linux/config.h> #include <linux/kernel.h> -#include <linux/mtd/compatmac.h> /* for min() */ +#include <linux/vmalloc.h> +#include <linux/init.h> #include <linux/slab.h> -#include <linux/jffs2.h> #include <linux/zlib.h> +#include <linux/zutil.h> +#include <asm/semaphore.h> #include "nodelist.h" /* Plan: call deflate() with avail_in == *sourcelen, @@ -34,21 +36,21 @@ static DECLARE_MUTEX(deflate_sem); static DECLARE_MUTEX(inflate_sem); -static void *deflate_workspace; -static void *inflate_workspace; +static z_stream inf_strm, def_strm; +#ifdef __KERNEL__ /* Linux-only */ int __init jffs2_zlib_init(void) { - deflate_workspace = vmalloc(zlib_deflate_workspacesize()); - if (!deflate_workspace) { + def_strm.workspace = vmalloc(zlib_deflate_workspacesize()); + if (!def_strm.workspace) { printk(KERN_WARNING "Failed to allocate %d bytes for deflate workspace\n", zlib_deflate_workspacesize()); return -ENOMEM; } D1(printk(KERN_DEBUG "Allocated %d bytes for deflate workspace\n", zlib_deflate_workspacesize())); - inflate_workspace = vmalloc(zlib_inflate_workspacesize()); - if (!inflate_workspace) { + inf_strm.workspace = vmalloc(zlib_inflate_workspacesize()); + if (!inf_strm.workspace) { printk(KERN_WARNING "Failed to allocate %d bytes for inflate workspace\n", zlib_inflate_workspacesize()); - vfree(deflate_workspace); + vfree(def_strm.workspace); return -ENOMEM; } D1(printk(KERN_DEBUG "Allocated %d bytes for inflate workspace\n", zlib_inflate_workspacesize())); @@ -57,97 +59,120 @@ void jffs2_zlib_exit(void) { - vfree(deflate_workspace); - vfree(inflate_workspace); + vfree(def_strm.workspace); + vfree(inf_strm.workspace); } +#endif /* __KERNEL__ */ int jffs2_zlib_compress(unsigned char *data_in, unsigned char *cpage_out, uint32_t *sourcelen, uint32_t *dstlen) { - z_stream strm; int ret; if (*dstlen <= STREAM_END_SPACE) return -1; down(&deflate_sem); - strm.workspace = deflate_workspace; - if (Z_OK != zlib_deflateInit(&strm, 3)) { + if (Z_OK != zlib_deflateInit(&def_strm, 3)) { printk(KERN_WARNING "deflateInit failed\n"); up(&deflate_sem); return -1; } - strm.next_in = data_in; - strm.total_in = 0; + def_strm.next_in = data_in; + def_strm.total_in = 0; - strm.next_out = cpage_out; - strm.total_out = 0; + def_strm.next_out = cpage_out; + def_strm.total_out = 0; - while (strm.total_out < *dstlen - STREAM_END_SPACE && strm.total_in < *sourcelen) { - strm.avail_out = *dstlen - (strm.total_out + STREAM_END_SPACE); - strm.avail_in = min((unsigned)(*sourcelen-strm.total_in), strm.avail_out); + while (def_strm.total_out < *dstlen - STREAM_END_SPACE && def_strm.total_in < *sourcelen) { + def_strm.avail_out = *dstlen - (def_strm.total_out + STREAM_END_SPACE); + def_strm.avail_in = min((unsigned)(*sourcelen-def_strm.total_in), def_strm.avail_out); D1(printk(KERN_DEBUG "calling deflate with avail_in %d, avail_out %d\n", - strm.avail_in, strm.avail_out)); - ret = zlib_deflate(&strm, Z_PARTIAL_FLUSH); + def_strm.avail_in, def_strm.avail_out)); + ret = zlib_deflate(&def_strm, Z_PARTIAL_FLUSH); D1(printk(KERN_DEBUG "deflate returned with avail_in %d, avail_out %d, total_in %ld, total_out %ld\n", - strm.avail_in, strm.avail_out, strm.total_in, strm.total_out)); + def_strm.avail_in, def_strm.avail_out, def_strm.total_in, def_strm.total_out)); if (ret != Z_OK) { D1(printk(KERN_DEBUG "deflate in loop returned %d\n", ret)); - zlib_deflateEnd(&strm); + zlib_deflateEnd(&def_strm); up(&deflate_sem); return -1; } } - strm.avail_out += STREAM_END_SPACE; - strm.avail_in = 0; - ret = zlib_deflate(&strm, Z_FINISH); - zlib_deflateEnd(&strm); - up(&deflate_sem); + def_strm.avail_out += STREAM_END_SPACE; + def_strm.avail_in = 0; + ret = zlib_deflate(&def_strm, Z_FINISH); + zlib_deflateEnd(&def_strm); + if (ret != Z_STREAM_END) { D1(printk(KERN_DEBUG "final deflate returned %d\n", ret)); - return -1; + ret = -1; + goto out; } - D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld\n", - strm.total_in, strm.total_out)); + if (def_strm.total_out >= def_strm.total_in) { + D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld; failing\n", + def_strm.total_in, def_strm.total_out)); + ret = -1; + goto out; + } - if (strm.total_out >= strm.total_in) - return -1; + D1(printk(KERN_DEBUG "zlib compressed %ld bytes into %ld\n", + def_strm.total_in, def_strm.total_out)); - *dstlen = strm.total_out; - *sourcelen = strm.total_in; - return 0; + *dstlen = def_strm.total_out; + *sourcelen = def_strm.total_in; + ret = 0; + out: + up(&deflate_sem); + return ret; } void jffs2_zlib_decompress(unsigned char *data_in, unsigned char *cpage_out, uint32_t srclen, uint32_t destlen) { - z_stream strm; int ret; + int wbits = MAX_WBITS; down(&inflate_sem); - strm.workspace = inflate_workspace; - if (Z_OK != zlib_inflateInit(&strm)) { + inf_strm.next_in = data_in; + inf_strm.avail_in = srclen; + inf_strm.total_in = 0; + + inf_strm.next_out = cpage_out; + inf_strm.avail_out = destlen; + inf_strm.total_out = 0; + + /* If it's deflate, and it's got no preset dictionary, then + we can tell zlib to skip the adler32 check. */ + if (srclen > 2 && !(data_in[1] & PRESET_DICT) && + ((data_in[0] & 0x0f) == Z_DEFLATED) && + !(((data_in[0]<<8) + data_in[1]) % 31)) { + + D2(printk(KERN_DEBUG "inflate skipping adler32\n")); + wbits = -((data_in[0] >> 4) + 8); + inf_strm.next_in += 2; + inf_strm.avail_in -= 2; + } else { + /* Let this remain D1 for now -- it should never happen */ + D1(printk(KERN_DEBUG "inflate not skipping adler32\n")); + } + + + if (Z_OK != zlib_inflateInit2(&inf_strm, wbits)) { printk(KERN_WARNING "inflateInit failed\n"); up(&inflate_sem); return; } - strm.next_in = data_in; - strm.avail_in = srclen; - strm.total_in = 0; - - strm.next_out = cpage_out; - strm.avail_out = destlen; - strm.total_out = 0; - while((ret = zlib_inflate(&strm, Z_FINISH)) == Z_OK) + while((ret = zlib_inflate(&inf_strm, Z_FINISH)) == Z_OK) ; if (ret != Z_STREAM_END) { printk(KERN_NOTICE "inflate returned %d\n", ret); } - zlib_inflateEnd(&strm); + zlib_inflateEnd(&inf_strm); up(&inflate_sem); } diff -Nru a/fs/jffs2/dir.c b/fs/jffs2/dir.c --- a/fs/jffs2/dir.c Mon Jun 9 23:16:17 2003 +++ b/fs/jffs2/dir.c Mon Jun 9 23:16:17 2003 @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: dir.c,v 1.73 2002/08/26 15:00:51 dwmw2 Exp $ + * $Id: dir.c,v 1.76 2003/05/26 09:50:38 dwmw2 Exp $ * */ @@ -16,13 +16,20 @@ #include <linux/sched.h> #include <linux/fs.h> #include <linux/crc32.h> -#include <linux/mtd/compatmac.h> /* For completion */ #include <linux/jffs2.h> #include <linux/jffs2_fs_i.h> #include <linux/jffs2_fs_sb.h> #include <linux/time.h> #include "nodelist.h" +/* Urgh. Please tell me there's a nicer way of doing this. */ +#include <linux/version.h> +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,48) +typedef int mknod_arg_t; +#else +typedef dev_t mknod_arg_t; +#endif + static int jffs2_readdir (struct file *, void *, filldir_t); static int jffs2_create (struct inode *,struct dentry *,int); @@ -32,7 +39,7 @@ static int jffs2_symlink (struct inode *,struct dentry *,const char *); static int jffs2_mkdir (struct inode *,struct dentry *,int); static int jffs2_rmdir (struct inode *,struct dentry *); -static int jffs2_mknod (struct inode *,struct dentry *,int,dev_t); +static int jffs2_mknod (struct inode *,struct dentry *,int,mknod_arg_t); static int jffs2_rename (struct inode *, struct dentry *, struct inode *, struct dentry *); @@ -211,8 +218,7 @@ return ret; } - dir_i->i_mtime.tv_sec = dir_i->i_ctime.tv_sec = je32_to_cpu(ri->ctime); - dir_i->i_mtime.tv_nsec = dir_i->i_ctime.tv_nsec = 0; + dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(ri->ctime)); jffs2_free_raw_inode(ri); d_instantiate(dentry, inode); @@ -402,8 +408,7 @@ return PTR_ERR(fd); } - dir_i->i_mtime.tv_sec = dir_i->i_ctime.tv_sec = je32_to_cpu(rd->mctime); - dir_i->i_mtime.tv_nsec = dir_i->i_ctime.tv_nsec = 0; + dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); jffs2_free_raw_dirent(rd); @@ -540,8 +545,7 @@ return PTR_ERR(fd); } - dir_i->i_mtime.tv_sec = dir_i->i_ctime.tv_sec = je32_to_cpu(rd->mctime); - dir_i->i_mtime.tv_nsec = dir_i->i_ctime.tv_nsec = 0; + dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); dir_i->i_nlink++; jffs2_free_raw_dirent(rd); @@ -573,7 +577,7 @@ return ret; } -static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, dev_t rdev) +static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, int mode, mknod_arg_t rdev) { struct jffs2_inode_info *f, *dir_f; struct jffs2_sb_info *c; @@ -583,7 +587,7 @@ struct jffs2_full_dnode *fn; struct jffs2_full_dirent *fd; int namelen; - unsigned short dev; + jint16_t dev; int devlen = 0; uint32_t alloclen, phys_ofs; uint32_t writtenlen; @@ -596,7 +600,7 @@ c = JFFS2_SB_INFO(dir_i->i_sb); if (S_ISBLK(mode) || S_ISCHR(mode)) { - dev = (MAJOR(rdev) << 8) | MINOR(rdev); + dev = cpu_to_je16((MAJOR(rdev) << 8) | MINOR(rdev)); devlen = sizeof(dev); } @@ -704,8 +708,7 @@ return PTR_ERR(fd); } - dir_i->i_mtime.tv_sec = dir_i->i_ctime.tv_sec = je32_to_cpu(rd->mctime); - dir_i->i_mtime.tv_nsec = dir_i->i_ctime.tv_nsec = 0; + dir_i->i_mtime = dir_i->i_ctime = ITIME(je32_to_cpu(rd->mctime)); jffs2_free_raw_dirent(rd); diff -Nru a/fs/jffs2/erase.c b/fs/jffs2/erase.c --- a/fs/jffs2/erase.c Mon Jun 9 23:16:07 2003 +++ b/fs/jffs2/erase.c Mon Jun 9 23:16:07 2003 @@ -7,16 +7,17 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: erase.c,v 1.45 2002/10/09 08:27:08 dwmw2 Exp $ + * $Id: erase.c,v 1.51 2003/05/11 22:47:36 dwmw2 Exp $ * */ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/mtd/mtd.h> -#include <linux/interrupt.h> #include <linux/compiler.h> #include <linux/crc32.h> +#include <linux/sched.h> +#include <linux/pagemap.h> #include "nodelist.h" struct erase_priv_struct { @@ -24,7 +25,10 @@ struct jffs2_sb_info *c; }; +#ifndef __ECOS static void jffs2_erase_callback(struct erase_info *); +#endif +static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); static void jffs2_erase_succeeded(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); static void jffs2_free_all_node_refs(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); static void jffs2_mark_erased_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb); @@ -32,16 +36,25 @@ void jffs2_erase_block(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) { int ret; +#ifdef __ECOS + ret = jffs2_flash_erase(c, jeb); + if (!ret) { + jffs2_erase_succeeded(c, jeb); + return; + } +#else /* Linux */ struct erase_info *instr; instr = kmalloc(sizeof(struct erase_info) + sizeof(struct erase_priv_struct), GFP_KERNEL); if (!instr) { printk(KERN_WARNING "kmalloc for struct erase_info in jffs2_erase_block failed. Refiling block for later\n"); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); list_del(&jeb->list); list_add(&jeb->list, &c->erase_pending_list); c->erasing_size -= c->sector_size; - spin_unlock_bh(&c->erase_completion_lock); + c->dirty_size += c->sector_size; + jeb->dirty_size = c->sector_size; + spin_unlock(&c->erase_completion_lock); return; } @@ -65,15 +78,18 @@ return; kfree(instr); +#endif /* __ECOS */ if (ret == -ENOMEM || ret == -EAGAIN) { /* Erase failed immediately. Refile it on the list */ D1(printk(KERN_DEBUG "Erase at 0x%08x failed: %d. Refiling on erase_pending_list\n", jeb->offset, ret)); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); list_del(&jeb->list); list_add(&jeb->list, &c->erase_pending_list); c->erasing_size -= c->sector_size; - spin_unlock_bh(&c->erase_completion_lock); + c->dirty_size += c->sector_size; + jeb->dirty_size = c->sector_size; + spin_unlock(&c->erase_completion_lock); return; } @@ -82,20 +98,7 @@ else printk(KERN_WARNING "Erase at 0x%08x failed immediately: errno %d\n", jeb->offset, ret); - /* Note: This is almost identical to jffs2_erase_failed() except - for the fact that we used spin_lock_bh() not spin_lock(). If - we could use spin_lock_bh() from a BH, we could merge them. - Or if we abandon the idea that MTD drivers may call the erase - callback from a BH, I suppose :) - */ - spin_lock_bh(&c->erase_completion_lock); - c->erasing_size -= c->sector_size; - c->bad_size += c->sector_size; - list_del(&jeb->list); - list_add(&jeb->list, &c->bad_list); - c->nr_erasing_blocks--; - spin_unlock_bh(&c->erase_completion_lock); - wake_up(&c->erase_wait); + jffs2_erase_failed(c, jeb); } void jffs2_erase_pending_blocks(struct jffs2_sb_info *c) @@ -104,7 +107,7 @@ down(&c->erase_free_sem); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); while (!list_empty(&c->erase_complete_list) || !list_empty(&c->erase_pending_list)) { @@ -112,7 +115,7 @@ if (!list_empty(&c->erase_complete_list)) { jeb = list_entry(c->erase_complete_list.next, struct jffs2_eraseblock, list); list_del(&jeb->list); - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); jffs2_mark_erased_block(c, jeb); } else if (!list_empty(&c->erase_pending_list)) { @@ -126,7 +129,7 @@ jeb->used_size = jeb->dirty_size = jeb->free_size = 0; jffs2_free_all_node_refs(c, jeb); list_add(&jeb->list, &c->erasing_list); - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); jffs2_erase_block(c, jeb); @@ -136,10 +139,10 @@ /* Be nice */ cond_resched(); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); } - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); D1(printk(KERN_DEBUG "jffs2_erase_pending_blocks completed\n")); up(&c->erase_free_sem); @@ -156,8 +159,7 @@ jffs2_erase_pending_trigger(c); } - -static inline void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) +static void jffs2_erase_failed(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) { spin_lock(&c->erase_completion_lock); c->erasing_size -= c->sector_size; @@ -169,6 +171,7 @@ wake_up(&c->erase_wait); } +#ifndef __ECOS static void jffs2_erase_callback(struct erase_info *instr) { struct erase_priv_struct *priv = (void *)instr->priv; @@ -181,6 +184,7 @@ } kfree(instr); } +#endif /* !__ECOS */ /* Hmmm. Maybe we should accept the extra space it takes and make this a standard doubly-linked list? */ @@ -290,9 +294,9 @@ printk(KERN_WARNING "Failed to allocate raw node ref for clean marker\n"); /* Stick it back on the list from whence it came and come back later */ jffs2_erase_pending_trigger(c); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); list_add(&jeb->list, &c->erase_complete_list); - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); return; } } @@ -313,7 +317,7 @@ goto bad; } if (retlen != readlen) { - printk(KERN_WARNING "Short read from newly-erased block at 0x%08x. Wanted %d, got %d\n", ofs, readlen, retlen); + printk(KERN_WARNING "Short read from newly-erased block at 0x%08x. Wanted %d, got %zd\n", ofs, readlen, retlen); goto bad; } for (i=0; i<readlen; i += sizeof(unsigned long)) { @@ -328,13 +332,13 @@ jffs2_write_nand_badblock( c ,jeb ); kfree(ebuf); bad2: - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); c->erasing_size -= c->sector_size; c->bad_size += c->sector_size; list_add_tail(&jeb->list, &c->bad_list); c->nr_erasing_blocks--; - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); wake_up(&c->erase_wait); return; } @@ -374,7 +378,7 @@ goto bad2; } if (retlen != je32_to_cpu(marker.totlen)) { - printk(KERN_WARNING "Short write to newly-erased block at 0x%08x: Wanted %d, got %d\n", + printk(KERN_WARNING "Short write to newly-erased block at 0x%08x: Wanted %d, got %zd\n", jeb->offset, je32_to_cpu(marker.totlen), retlen); goto bad2; } @@ -392,7 +396,7 @@ jeb->wasted_size = 0; } - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); c->erasing_size -= c->sector_size; c->free_size += jeb->free_size; c->used_size += jeb->used_size; @@ -403,7 +407,7 @@ list_add_tail(&jeb->list, &c->free_list); c->nr_erasing_blocks--; c->nr_free_blocks++; - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); wake_up(&c->erase_wait); } diff -Nru a/fs/jffs2/file.c b/fs/jffs2/file.c --- a/fs/jffs2/file.c Mon Jun 9 23:16:19 2003 +++ b/fs/jffs2/file.c Mon Jun 9 23:16:19 2003 @@ -7,12 +7,11 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: file.c,v 1.81 2002/11/12 09:46:22 dwmw2 Exp $ + * $Id: file.c,v 1.85 2003/05/26 09:50:38 dwmw2 Exp $ * */ #include <linux/kernel.h> -#include <linux/mtd/compatmac.h> /* for min() */ #include <linux/slab.h> #include <linux/fs.h> #include <linux/time.h> @@ -153,17 +152,20 @@ if (ivalid & ATTR_MODE) if (iattr->ia_mode & S_ISGID && !in_group_p(je16_to_cpu(ri->gid)) && !capable(CAP_FSETID)) - ri->mode = cpu_to_je32(iattr->ia_mode & ~S_ISGID); + ri->mode = cpu_to_jemode(iattr->ia_mode & ~S_ISGID); else - ri->mode = cpu_to_je32(iattr->ia_mode); + ri->mode = cpu_to_jemode(iattr->ia_mode); else - ri->mode = cpu_to_je32(inode->i_mode); + ri->mode = cpu_to_jemode(inode->i_mode); ri->isize = cpu_to_je32((ivalid & ATTR_SIZE)?iattr->ia_size:inode->i_size); - ri->atime = cpu_to_je32((ivalid & ATTR_ATIME)?iattr->ia_atime.tv_sec:inode->i_atime.tv_sec); - ri->mtime = cpu_to_je32((ivalid & ATTR_MTIME)?iattr->ia_mtime.tv_sec:inode->i_mtime.tv_sec); - ri->ctime = cpu_to_je32((ivalid & ATTR_CTIME)?iattr->ia_ctime.tv_sec:inode->i_ctime.tv_sec); + ri->atime = cpu_to_je32(I_SEC((ivalid & ATTR_ATIME)?iattr->ia_atime:inode->i_atime)); + ri->mtime = cpu_to_je32(I_SEC((ivalid & ATTR_MTIME)?iattr->ia_mtime:inode->i_mtime)); + ri->ctime = cpu_to_je32(I_SEC((ivalid & ATTR_CTIME)?iattr->ia_ctime:inode->i_ctime)); + + ri->offset = cpu_to_je32(0); + ri->csize = ri->dsize = cpu_to_je32(mdatalen); ri->compr = JFFS2_COMPR_NONE; if (ivalid & ATTR_SIZE && inode->i_size < iattr->ia_size) { /* It's an extension. Make it a hole node */ @@ -188,13 +190,10 @@ return PTR_ERR(new_metadata); } /* It worked. Update the inode */ - inode->i_atime.tv_sec = je32_to_cpu(ri->atime); - inode->i_ctime.tv_sec = je32_to_cpu(ri->ctime); - inode->i_mtime.tv_sec = je32_to_cpu(ri->mtime); - inode->i_atime.tv_nsec = - inode->i_ctime.tv_nsec = - inode->i_mtime.tv_nsec = 0; - inode->i_mode = je32_to_cpu(ri->mode); + inode->i_atime = ITIME(je32_to_cpu(ri->atime)); + inode->i_ctime = ITIME(je32_to_cpu(ri->ctime)); + inode->i_mtime = ITIME(je32_to_cpu(ri->mtime)); + inode->i_mode = jemode_to_cpu(ri->mode); inode->i_uid = je16_to_cpu(ri->uid); inode->i_gid = je16_to_cpu(ri->gid); @@ -309,7 +308,7 @@ ri.ino = cpu_to_je32(f->inocache->ino); ri.version = cpu_to_je32(++f->highest_version); - ri.mode = cpu_to_je32(inode->i_mode); + ri.mode = cpu_to_jemode(inode->i_mode); ri.uid = cpu_to_je16(inode->i_uid); ri.gid = cpu_to_je16(inode->i_gid); ri.isize = cpu_to_je32(max((uint32_t)inode->i_size, pageofs)); @@ -390,7 +389,7 @@ /* Set the fields that the generic jffs2_write_inode_range() code can't find */ ri->ino = cpu_to_je32(inode->i_ino); - ri->mode = cpu_to_je32(inode->i_mode); + ri->mode = cpu_to_jemode(inode->i_mode); ri->uid = cpu_to_je16(inode->i_uid); ri->gid = cpu_to_je16(inode->i_gid); ri->isize = cpu_to_je32((uint32_t)inode->i_size); @@ -416,8 +415,7 @@ inode->i_size = (pg->index << PAGE_CACHE_SHIFT) + start + writtenlen; inode->i_blocks = (inode->i_size + 511) >> 9; - inode->i_ctime.tv_sec = inode->i_mtime.tv_sec = je32_to_cpu(ri->ctime); - inode->i_ctime.tv_nsec = inode->i_mtime.tv_nsec = 0; + inode->i_ctime = inode->i_mtime = ITIME(je32_to_cpu(ri->ctime)); } } diff -Nru a/fs/jffs2/fs.c b/fs/jffs2/fs.c --- a/fs/jffs2/fs.c Mon Jun 9 23:16:10 2003 +++ b/fs/jffs2/fs.c Mon Jun 9 23:16:10 2003 @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: fs.c,v 1.19 2002/11/12 09:53:40 dwmw2 Exp $ + * $Id: fs.c,v 1.24 2003/04/29 09:52:58 dwmw2 Exp $ * */ @@ -16,7 +16,6 @@ #include <linux/sched.h> #include <linux/fs.h> #include <linux/list.h> -#include <linux/interrupt.h> #include <linux/mtd/mtd.h> #include <linux/pagemap.h> #include <linux/slab.h> @@ -35,7 +34,7 @@ buf->f_ffree = 0; buf->f_namelen = JFFS2_MAX_NAME_LEN; - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); avail = c->dirty_size + c->free_size; if (avail > c->sector_size * JFFS2_RESERVED_BLOCKS_WRITE) @@ -47,7 +46,7 @@ D1(jffs2_dump_block_lists(c)); - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); return 0; } @@ -87,16 +86,13 @@ up(&f->sem); return; } - inode->i_mode = je32_to_cpu(latest_node.mode); + inode->i_mode = jemode_to_cpu(latest_node.mode); inode->i_uid = je16_to_cpu(latest_node.uid); inode->i_gid = je16_to_cpu(latest_node.gid); inode->i_size = je32_to_cpu(latest_node.isize); - inode->i_atime.tv_sec = je32_to_cpu(latest_node.atime); - inode->i_mtime.tv_sec = je32_to_cpu(latest_node.mtime); - inode->i_ctime.tv_sec = je32_to_cpu(latest_node.ctime); - inode->i_atime.tv_nsec = - inode->i_mtime.tv_nsec = - inode->i_ctime.tv_nsec = 0; + inode->i_atime = ITIME(je32_to_cpu(latest_node.atime)); + inode->i_mtime = ITIME(je32_to_cpu(latest_node.mtime)); + inode->i_ctime = ITIME(je32_to_cpu(latest_node.ctime)); inode->i_nlink = f->inocache->nlink; @@ -104,7 +100,7 @@ inode->i_blocks = (inode->i_size + 511) >> 9; switch (inode->i_mode & S_IFMT) { - unsigned short rdev; + jint16_t rdev; case S_IFLNK: inode->i_op = &jffs2_symlink_inode_operations; @@ -151,7 +147,7 @@ case S_IFSOCK: case S_IFIFO: inode->i_op = &jffs2_file_inode_operations; - init_special_inode(inode, inode->i_mode, kdev_t_to_nr(mk_kdev(rdev>>8, rdev&0xff))); + init_special_inode(inode, inode->i_mode, kdev_t_to_nr(mk_kdev(je16_to_cpu(rdev)>>8, je16_to_cpu(rdev)&0xff))); break; default: @@ -232,7 +228,7 @@ } else { ri->gid = cpu_to_je16(current->fsgid); } - ri->mode = cpu_to_je32(mode); + ri->mode = cpu_to_jemode(mode); ret = jffs2_do_new_inode (c, f, mode, ri); if (ret) { make_bad_inode(inode); @@ -241,12 +237,11 @@ } inode->i_nlink = 1; inode->i_ino = je32_to_cpu(ri->ino); - inode->i_mode = je32_to_cpu(ri->mode); + inode->i_mode = jemode_to_cpu(ri->mode); inode->i_gid = je16_to_cpu(ri->gid); inode->i_uid = je16_to_cpu(ri->uid); - inode->i_atime.tv_nsec = inode->i_ctime.tv_nsec = inode->i_mtime.tv_nsec = 0; - inode->i_atime.tv_sec = inode->i_ctime.tv_sec = inode->i_mtime.tv_sec = get_seconds(); - ri->atime = ri->mtime = ri->ctime = cpu_to_je32(inode->i_mtime.tv_sec); + inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME; + ri->atime = ri->mtime = ri->ctime = cpu_to_je32(I_SEC(inode->i_mtime)); inode->i_blksize = PAGE_SIZE; inode->i_blocks = 0; @@ -263,27 +258,32 @@ struct jffs2_sb_info *c; struct inode *root_i; int ret; + size_t blocks; c = JFFS2_SB_INFO(sb); - c->sector_size = c->mtd->erasesize; c->flash_size = c->mtd->size; -#if 0 - if (c->sector_size < 0x10000) { - printk(KERN_INFO "jffs2: Erase block size too small (%dKiB). Using 64KiB instead\n", - c->sector_size / 1024); - c->sector_size = 0x10000; - } -#endif + /* + * Check, if we have to concatenate physical blocks to larger virtual blocks + * to reduce the memorysize for c->blocks. (kmalloc allows max. 128K allocation) + */ + blocks = c->flash_size / c->mtd->erasesize; + while ((blocks * sizeof (struct jffs2_eraseblock)) > (128 * 1024)) + blocks >>= 1; + + c->sector_size = c->flash_size / blocks; + if (c->sector_size != c->mtd->erasesize) + printk(KERN_INFO "jffs2: Erase block size too small (%dKiB). Using virtual blocks size (%dKiB) instead\n", + c->mtd->erasesize / 1024, c->sector_size / 1024); + if (c->flash_size < 5*c->sector_size) { - printk(KERN_ERR "jffs2: Too few erase blocks (%d)\n", - c->flash_size / c->sector_size); + printk(KERN_ERR "jffs2: Too few erase blocks (%d)\n", c->flash_size / c->sector_size); return -EINVAL; } c->cleanmarker_size = sizeof(struct jffs2_unknown_node); - /* Jörn -- stick alignment for weird 8-byte-page flash here */ + /* Joern -- stick alignment for weird 8-byte-page flash here */ if (jffs2_cleanmarker_oob(c)) { /* Cleanmarker is out-of-band, so inline size zero */ diff -Nru a/fs/jffs2/gc.c b/fs/jffs2/gc.c --- a/fs/jffs2/gc.c Mon Jun 9 23:16:08 2003 +++ b/fs/jffs2/gc.c Mon Jun 9 23:16:09 2003 @@ -7,19 +7,22 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: gc.c,v 1.88 2002/10/08 16:56:08 dwmw2 Exp $ + * $Id: gc.c,v 1.103 2003/05/22 18:01:02 dwmw2 Exp $ * */ #include <linux/kernel.h> #include <linux/mtd/mtd.h> #include <linux/slab.h> -#include <linux/interrupt.h> #include <linux/pagemap.h> #include <linux/crc32.h> #include <linux/compiler.h> +#include <linux/stat.h> #include "nodelist.h" +static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, + struct jffs2_inode_cache *ic, + struct jffs2_raw_node_ref *raw); static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_inode_info *f, struct jffs2_full_dnode *fd); static int jffs2_garbage_collect_dirent(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, @@ -32,6 +35,8 @@ static int jffs2_garbage_collect_dnode(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn, uint32_t start, uint32_t end); +static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, + struct jffs2_raw_node_ref *raw, struct jffs2_inode_cache *ic); /* Called with erase_completion_lock held */ static struct jffs2_eraseblock *jffs2_find_gc_block(struct jffs2_sb_info *c) @@ -107,61 +112,87 @@ */ int jffs2_garbage_collect_pass(struct jffs2_sb_info *c) { + struct jffs2_inode_cache *ic; struct jffs2_eraseblock *jeb; - struct jffs2_inode_info *f; struct jffs2_raw_node_ref *raw; - struct jffs2_node_frag *frag; - struct jffs2_full_dnode *fn = NULL; - struct jffs2_full_dirent *fd; - uint32_t start = 0, end = 0, nrfrags = 0; uint32_t inum; - struct inode *inode; int ret = 0; if (down_interruptible(&c->alloc_sem)) return -EINTR; - spin_lock_bh(&c->erase_completion_lock); + for (;;) { + spin_lock(&c->erase_completion_lock); + if (!c->unchecked_size) + break; - while (c->unchecked_size) { /* We can't start doing GC yet. We haven't finished checking - the node CRCs etc. Do it now and wait for it. */ - struct jffs2_inode_cache *ic; - + the node CRCs etc. Do it now. */ + + /* checked_ino is protected by the alloc_sem */ if (c->checked_ino > c->highest_ino) { printk(KERN_CRIT "Checked all inodes but still 0x%x bytes of unchecked space?\n", c->unchecked_size); D1(jffs2_dump_block_lists(c)); + spin_unlock(&c->erase_completion_lock); BUG(); } + + spin_unlock(&c->erase_completion_lock); + + spin_lock(&c->inocache_lock); + ic = jffs2_get_ino_cache(c, c->checked_ino++); - if (!ic) + + if (!ic) { + spin_unlock(&c->inocache_lock); continue; + } + if (!ic->nlink) { D1(printk(KERN_DEBUG "Skipping check of ino #%d with nlink zero\n", ic->ino)); + spin_unlock(&c->inocache_lock); continue; } - if (ic->state != INO_STATE_UNCHECKED) { - D1(printk(KERN_DEBUG "Skipping check of ino #%d already in state %d\n", - ic->ino, ic->state)); + switch(ic->state) { + case INO_STATE_CHECKEDABSENT: + case INO_STATE_PRESENT: + D1(printk(KERN_DEBUG "Skipping ino #%u already checked\n", ic->ino)); + spin_unlock(&c->inocache_lock); continue; - } - spin_unlock_bh(&c->erase_completion_lock); + case INO_STATE_GC: + case INO_STATE_CHECKING: + printk(KERN_WARNING "Inode #%u is in state %d during CRC check phase!\n", ic->ino, ic->state); + spin_unlock(&c->inocache_lock); + BUG(); - D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() triggering inode scan of ino#%d\n", ic->ino)); - - { - /* XXX: This wants doing more sensibly -- split the core of jffs2_do_read_inode up */ - struct inode *i = iget(OFNI_BS_2SFFJ(c), ic->ino); - if (is_bad_inode(i)) { - printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u\n", ic->ino); - ret = -EIO; - } - iput(i); + case INO_STATE_READING: + /* We need to wait for it to finish, lest we move on + and trigger the BUG() above while we haven't yet + finished checking all its nodes */ + D1(printk(KERN_DEBUG "Waiting for ino #%u to finish reading\n", ic->ino)); + up(&c->alloc_sem); + sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); + return 0; + + default: + BUG(); + + case INO_STATE_UNCHECKED: + ; } + ic->state = INO_STATE_CHECKING; + spin_unlock(&c->inocache_lock); + D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() triggering inode scan of ino#%d\n", ic->ino)); + + ret = jffs2_do_crccheck_inode(c, ic); + if (ret) + printk(KERN_WARNING "Returned error for crccheck of ino #%u. Expect badness...\n", ic->ino); + + jffs2_set_inocache_state(c, ic, INO_STATE_CHECKEDABSENT); up(&c->alloc_sem); return ret; } @@ -174,7 +205,7 @@ if (!jeb) { printk(KERN_NOTICE "jffs2: Couldn't find erase block to garbage collect!\n"); - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); up(&c->alloc_sem); return -EIO; } @@ -197,7 +228,7 @@ printk(KERN_WARNING "eep. End of raw list while still supposedly nodes to GC\n"); printk(KERN_WARNING "erase block at 0x%08x. free_size 0x%08x, dirty_size 0x%08x, used_size 0x%08x\n", jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size); - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); up(&c->alloc_sem); BUG(); } @@ -207,7 +238,7 @@ /* Inode-less node. Clean marker, snapshot or something like that */ /* FIXME: If it's something that needs to be copied, including something we don't grok that has JFFS2_NODETYPE_RWCOMPAT_COPY, we should do so */ - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); jffs2_mark_node_obsolete(c, raw); up(&c->alloc_sem); goto eraseit_lock; @@ -216,13 +247,136 @@ inum = jffs2_raw_ref_to_inum(raw); D1(printk(KERN_DEBUG "Inode number is #%u\n", inum)); - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); + + D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass collecting from block @0x%08x. Node @0x%08x(%d), ino #%u\n", jeb->offset, ref_offset(raw), ref_flags(raw), inum)); + + /* Three possibilities: + 1. Inode is already in-core. We must iget it and do proper + updating to its fragtree, etc. + 2. Inode is not in-core, node is REF_PRISTINE. We lock the + inocache to prevent a read_inode(), copy the node intact. + 3. Inode is not in-core, node is not pristine. We must iget() + and take the slow path. + */ + spin_lock(&c->inocache_lock); + ic = jffs2_get_ino_cache(c, inum); + + /* This should never fail unless I'm particularly stupid. + So we don't check before dereferencing it */ + + switch(ic->state) { + case INO_STATE_CHECKEDABSENT: + /* It's been checked, but it's not currently in-core. + We can just copy any pristine nodes, but have + to prevent anyone else from doing read_inode() while + we're at it, so we set the state accordingly */ + if (ref_flags(raw) == REF_PRISTINE) + ic->state = INO_STATE_GC; + else { + D1(printk("Ino #%u is absent but node not REF_PRISTINE. Reading.\n", + inum)); + } + break; + + case INO_STATE_PRESENT: + case INO_STATE_UNCHECKED: + /* It's in-core or hasn't been checked. GC must iget() it. */ + break; + + case INO_STATE_CHECKING: + /* Should never happen. We should have finished checking + by the time we actually start doing any GC. */ + BUG(); + + + case INO_STATE_GC: + /* Should never happen. We are holding the alloc_sem, + no other garbage collection can happen. Note that we + do depend on this later when deciding to do a simple + node copy */ + BUG(); + + case INO_STATE_READING: + /* Someone's currently trying to read it. We must wait for + them to finish and then go through the full iget() route + to do the GC. However, sometimes read_inode() needs to get + the alloc_sem() (for marking nodes invalid) so we must + drop the alloc_sem before sleeping. */ + + up(&c->alloc_sem); + D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass() waiting for ino #%u in state %d\n", + inum, ic->state)); + sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); + /* And because we dropped the alloc_sem we must start again from the + beginning. Ponder chance of livelock here -- we're returning success + without actually making any progress. + + Q: What are the chances that the inode is back in INO_STATE_READING + again by the time we next enter this function? And that this happens + enough times to cause a real delay? + + A: Small enough that I don't care :) + */ + return 0; + + } + + spin_unlock(&c->inocache_lock); + + /* OK. Now if the inode is in state INO_STATE_GC, we are going to copy the + node intact, and we don't have to muck about with the fragtree etc. + because we know it's not in-core. If it _was_ in-core, we go through + all the iget() crap anyway */ + + if (ic->state == INO_STATE_GC) { + ret = jffs2_garbage_collect_pristine(c, ic, raw); + jffs2_set_inocache_state(c, ic, INO_STATE_CHECKEDABSENT); + + if (ret != -EBADFD) + goto release_sem; + + /* Fall through if it wanted us to */ + } + + ret = jffs2_garbage_collect_live(c, jeb, raw, ic); + + release_sem: + up(&c->alloc_sem); + + eraseit_lock: + /* If we've finished this block, start it erasing */ + spin_lock(&c->erase_completion_lock); + + eraseit: + if (c->gcblock && !c->gcblock->used_size) { + D1(printk(KERN_DEBUG "Block at 0x%08x completely obsoleted by GC. Moving to erase_pending_list\n", c->gcblock->offset)); + /* We're GC'ing an empty block? */ + list_add_tail(&c->gcblock->list, &c->erase_pending_list); + c->gcblock = NULL; + c->nr_erasing_blocks++; + jffs2_erase_pending_trigger(c); + } + spin_unlock(&c->erase_completion_lock); + + return ret; +} - D1(printk(KERN_DEBUG "jffs2_garbage_collect_pass collecting from block @0x%08x. Node @0x%08x, ino #%u\n", jeb->offset, ref_offset(raw), inum)); - inode = iget(OFNI_BS_2SFFJ(c), inum); +static int jffs2_garbage_collect_live(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, + struct jffs2_raw_node_ref *raw, struct jffs2_inode_cache *ic) +{ + struct jffs2_inode_info *f; + struct jffs2_node_frag *frag; + struct jffs2_full_dnode *fn = NULL; + struct jffs2_full_dirent *fd; + uint32_t start = 0, end = 0, nrfrags = 0; + struct inode *inode; + int ret = 0; + + inode = iget(OFNI_BS_2SFFJ(c), ic->ino); if (is_bad_inode(inode)) { - printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u\n", inum); + printk(KERN_NOTICE "Eep. read_inode() failed for ino #%u\n", ic->ino); /* NB. This will happen again. We need to do something appropriate here. */ up(&c->alloc_sem); iput(inode); @@ -254,16 +408,26 @@ end = frag->ofs + frag->size; #if 1 /* Temporary debugging sanity checks, till we're ready to _trust_ the REF_PRISTINE flag stuff */ if (!nrfrags && ref_flags(fn->raw) == REF_PRISTINE) { - if (fn->frags > 1) + if (fn->frags > 1) { printk(KERN_WARNING "REF_PRISTINE node at 0x%08x had %d frags. Tell dwmw2\n", ref_offset(raw), fn->frags); - - if (frag->ofs & (PAGE_CACHE_SIZE-1) && frag_prev(frag) && frag_prev(frag)->node) + mark_ref_normal(raw); + } + /* A hole node which isn't multi-page should be garbage-collected + and merged anyway, so we just check for the frag size here, + rather than mucking around with actually reading the node + and checking the compression type, which is the real way + to tell a hole node. */ + if (frag->ofs & (PAGE_CACHE_SIZE-1) && frag_prev(frag) && frag_prev(frag)->size < PAGE_CACHE_SIZE) { printk(KERN_WARNING "REF_PRISTINE node at 0x%08x had a previous non-hole frag in the same page. Tell dwmw2\n", ref_offset(raw)); + mark_ref_normal(raw); + } - if ((frag->ofs+frag->size) & (PAGE_CACHE_SIZE-1) && frag_next(frag) && frag_next(frag)->node) + if ((frag->ofs+frag->size) & (PAGE_CACHE_SIZE-1) && frag_next(frag) && frag_next(frag)->size < PAGE_CACHE_SIZE) { printk(KERN_WARNING "REF_PRISTINE node at 0x%08x (%08x-%08x) had a following non-hole frag in the same page. Tell dwmw2\n", ref_offset(raw), frag->ofs, frag->ofs+frag->size); + mark_ref_normal(raw); + } } #endif if (!nrfrags++) @@ -273,6 +437,15 @@ } } if (fn) { + if (ref_flags(raw) == REF_PRISTINE) { + ret = jffs2_garbage_collect_pristine(c, ic, raw); + if (!ret) { + /* Urgh. Return it sensibly. */ + frag->node->raw = ic->nodes; + } + if (ret != -EBADFD) + goto upnout; + } /* We found a datanode. Do the GC */ if((start >> PAGE_CACHE_SHIFT) < ((end-1) >> PAGE_CACHE_SHIFT)) { /* It crosses a page boundary. Therefore, it must be a hole. */ @@ -305,25 +478,145 @@ } upnout: up(&f->sem); - up(&c->alloc_sem); iput(inode); - eraseit_lock: - /* If we've finished this block, start it erasing */ - spin_lock_bh(&c->erase_completion_lock); + return ret; +} - eraseit: - if (c->gcblock && !c->gcblock->used_size) { - D1(printk(KERN_DEBUG "Block at 0x%08x completely obsoleted by GC. Moving to erase_pending_list\n", c->gcblock->offset)); - /* We're GC'ing an empty block? */ - list_add_tail(&c->gcblock->list, &c->erase_pending_list); - c->gcblock = NULL; - c->nr_erasing_blocks++; - jffs2_erase_pending_trigger(c); +static int jffs2_garbage_collect_pristine(struct jffs2_sb_info *c, + struct jffs2_inode_cache *ic, + struct jffs2_raw_node_ref *raw) +{ + union jffs2_node_union *node; + struct jffs2_raw_node_ref *nraw; + size_t retlen; + int ret; + uint32_t phys_ofs, alloclen; + uint32_t crc; + + D1(printk(KERN_DEBUG "Going to GC REF_PRISTINE node at 0x%08x\n", ref_offset(raw))); + + /* Ask for a small amount of space (or the totlen if smaller) because we + don't want to force wastage of the end of a block if splitting would + work. */ + ret = jffs2_reserve_space_gc(c, min_t(uint32_t, sizeof(struct jffs2_raw_inode) + JFFS2_MIN_DATA_LEN, raw->totlen), + &phys_ofs, &alloclen); + if (ret) + return ret; + + if (alloclen < raw->totlen) { + /* Doesn't fit untouched. We'll go the old route and split it */ + return -EBADFD; + } + + node = kmalloc(raw->totlen, GFP_KERNEL); + if (!node) + return -ENOMEM; + + ret = jffs2_flash_read(c, ref_offset(raw), raw->totlen, &retlen, (char *)node); + if (!ret && retlen != raw->totlen) + ret = -EIO; + if (ret) + goto out_node; + + crc = crc32(0, node, sizeof(struct jffs2_unknown_node)-4); + if (je32_to_cpu(node->u.hdr_crc) != crc) { + printk(KERN_WARNING "Header CRC failed on REF_PRISTINE node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", + ref_offset(raw), je32_to_cpu(node->u.hdr_crc), crc); + goto bail; + } + + switch(je16_to_cpu(node->u.nodetype)) { + case JFFS2_NODETYPE_INODE: + crc = crc32(0, node, sizeof(node->i)-8); + if (je32_to_cpu(node->i.node_crc) != crc) { + printk(KERN_WARNING "Node CRC failed on REF_PRISTINE data node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", + ref_offset(raw), je32_to_cpu(node->i.node_crc), crc); + goto bail; + } + + if (je32_to_cpu(node->i.dsize)) { + crc = crc32(0, node->i.data, je32_to_cpu(node->i.csize)); + if (je32_to_cpu(node->i.data_crc) != crc) { + printk(KERN_WARNING "Data CRC failed on REF_PRISTINE data node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", + ref_offset(raw), je32_to_cpu(node->i.data_crc), crc); + goto bail; + } + } + break; + + case JFFS2_NODETYPE_DIRENT: + crc = crc32(0, node, sizeof(node->d)-8); + if (je32_to_cpu(node->d.node_crc) != crc) { + printk(KERN_WARNING "Node CRC failed on REF_PRISTINE dirent node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", + ref_offset(raw), je32_to_cpu(node->d.node_crc), crc); + goto bail; + } + + if (node->d.nsize) { + crc = crc32(0, node->d.name, node->d.nsize); + if (je32_to_cpu(node->d.name_crc) != crc) { + printk(KERN_WARNING "Name CRC failed on REF_PRISTINE dirent ode at 0x%08x: Read 0x%08x, calculated 0x%08x\n", + ref_offset(raw), je32_to_cpu(node->d.name_crc), crc); + goto bail; + } + } + break; + default: + printk(KERN_WARNING "Unknown node type for REF_PRISTINE node at 0x%08x: 0x%04x\n", + ref_offset(raw), je16_to_cpu(node->u.nodetype)); + goto bail; + } + + nraw = jffs2_alloc_raw_node_ref(); + if (!nraw) { + ret = -ENOMEM; + goto out_node; + } + nraw->flash_offset = phys_ofs; + nraw->totlen = raw->totlen; + nraw->next_phys = NULL; + + /* OK, all the CRCs are good; this node can just be copied as-is. */ + + ret = jffs2_flash_write(c, phys_ofs, raw->totlen, &retlen, (char *)node); + if (ret || (retlen != raw->totlen)) { + printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %zd\n", + raw->totlen, phys_ofs, ret, retlen); + if (retlen) { + /* Doesn't belong to any inode */ + nraw->next_in_ino = NULL; + + nraw->flash_offset |= REF_OBSOLETE; + jffs2_add_physical_node_ref(c, nraw); + jffs2_mark_node_obsolete(c, nraw); + } else { + printk(KERN_NOTICE "Not marking the space at 0x%08x as dirty because the flash driver returned retlen zero\n", nraw->flash_offset); + jffs2_free_raw_node_ref(raw); + } + if (!ret) + ret = -EIO; + goto out_node; } - spin_unlock_bh(&c->erase_completion_lock); + nraw->flash_offset |= REF_PRISTINE; + jffs2_add_physical_node_ref(c, nraw); + + /* Link into per-inode list. This is safe because of the ic + state being INO_STATE_GC. Note that if we're doing this + for an inode which is in-code, the 'nraw' pointer is then + going to be fetched from ic->nodes by our caller. */ + nraw->next_in_ino = ic->nodes; + ic->nodes = nraw; + jffs2_mark_node_obsolete(c, raw); + D1(printk(KERN_DEBUG "WHEEE! GC REF_PRISTINE node at 0x%08x succeeded\n", ref_offset(raw))); + + out_node: + kfree(node); return ret; + bail: + ret = -EBADFD; + goto out_node; } static int jffs2_garbage_collect_metadata(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, @@ -331,7 +624,7 @@ { struct jffs2_full_dnode *new_fn; struct jffs2_raw_inode ri; - unsigned short dev; + jint16_t dev; char *mdata = NULL, mdatalen = 0; uint32_t alloclen, phys_ofs; int ret; @@ -340,8 +633,8 @@ S_ISCHR(JFFS2_F_I_MODE(f)) ) { /* For these, we don't actually need to read the old node */ /* FIXME: for minor or major > 255. */ - dev = ((JFFS2_F_I_RDEV_MAJ(f) << 8) | - JFFS2_F_I_RDEV_MIN(f)); + dev = cpu_to_je16(((JFFS2_F_I_RDEV_MAJ(f) << 8) | + JFFS2_F_I_RDEV_MIN(f))); mdata = (char *)&dev; mdatalen = sizeof(dev); D1(printk(KERN_DEBUG "jffs2_garbage_collect_metadata(): Writing %d bytes of kdev_t\n", mdatalen)); @@ -364,7 +657,7 @@ ret = jffs2_reserve_space_gc(c, sizeof(ri) + mdatalen, &phys_ofs, &alloclen); if (ret) { - printk(KERN_WARNING "jffs2_reserve_space_gc of %d bytes for garbage_collect_metadata failed: %d\n", + printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_metadata failed: %d\n", sizeof(ri)+ mdatalen, ret); goto out; } @@ -377,7 +670,7 @@ ri.ino = cpu_to_je32(f->inocache->ino); ri.version = cpu_to_je32(++f->highest_version); - ri.mode = cpu_to_je32(JFFS2_F_I_MODE(f)); + ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f)); ri.uid = cpu_to_je16(JFFS2_F_I_UID(f)); ri.gid = cpu_to_je16(JFFS2_F_I_GID(f)); ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f)); @@ -431,7 +724,7 @@ ret = jffs2_reserve_space_gc(c, sizeof(rd)+rd.nsize, &phys_ofs, &alloclen); if (ret) { - printk(KERN_WARNING "jffs2_reserve_space_gc of %d bytes for garbage_collect_dirent failed: %d\n", + printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dirent failed: %d\n", sizeof(rd)+rd.nsize, ret); return ret; } @@ -489,7 +782,7 @@ continue; } if (retlen != sizeof(struct jffs2_unknown_node)) { - printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%d not %d) reading header from obsolete node at %08x\n", + printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%zd not %zd) reading header from obsolete node at %08x\n", retlen, sizeof(struct jffs2_unknown_node), ref_offset(raw)); continue; } @@ -506,7 +799,7 @@ continue; } if (retlen != sizeof(rd)) { - printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%d not %d) reading from obsolete node at %08x\n", + printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%zd not %zd) reading from obsolete node at %08x\n", retlen, sizeof(rd), ref_offset(raw)); continue; } @@ -534,7 +827,7 @@ continue; } if (retlen != name_len+1) { - printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%d not %d) reading name from obsolete node at %08x\n", + printk(KERN_WARNING "jffs2_g_c_deletion_dirent(): Short read (%zd not %d) reading name from obsolete node at %08x\n", retlen, name_len+1, ref_offset(raw)); continue; } @@ -597,7 +890,7 @@ write it out again with the _same_ version as before */ ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(ri), &readlen, (char *)&ri); if (readlen != sizeof(ri) || ret) { - printk(KERN_WARNING "Node read failed in jffs2_garbage_collect_hole. Ret %d, retlen %d. Data will be lost by writing new hole node\n", ret, readlen); + printk(KERN_WARNING "Node read failed in jffs2_garbage_collect_hole. Ret %d, retlen %zd. Data will be lost by writing new hole node\n", ret, readlen); goto fill; } if (je16_to_cpu(ri.nodetype) != JFFS2_NODETYPE_INODE) { @@ -607,7 +900,7 @@ return -EIO; } if (je32_to_cpu(ri.totlen) != sizeof(ri)) { - printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had totlen 0x%x instead of expected 0x%x\n", + printk(KERN_WARNING "jffs2_garbage_collect_hole: Node at 0x%08x had totlen 0x%x instead of expected 0x%zx\n", ref_offset(fn->raw), je32_to_cpu(ri.totlen), sizeof(ri)); return -EIO; @@ -642,7 +935,7 @@ ri.csize = cpu_to_je32(0); ri.compr = JFFS2_COMPR_ZERO; } - ri.mode = cpu_to_je32(JFFS2_F_I_MODE(f)); + ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f)); ri.uid = cpu_to_je16(JFFS2_F_I_UID(f)); ri.gid = cpu_to_je16(JFFS2_F_I_GID(f)); ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f)); @@ -654,7 +947,7 @@ ret = jffs2_reserve_space_gc(c, sizeof(ri), &phys_ofs, &alloclen); if (ret) { - printk(KERN_WARNING "jffs2_reserve_space_gc of %d bytes for garbage_collect_hole failed: %d\n", + printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_hole failed: %d\n", sizeof(ri), ret); return ret; } @@ -762,8 +1055,11 @@ * page OK. We'll actually write it out again in commit_write, which is a little * suboptimal, but at least we're correct. */ +#ifdef __ECOS + pg = read_cache_page(start >> PAGE_CACHE_SHIFT, (void *)jffs2_do_readpage_unlock, inode); +#else pg = read_cache_page(inode->i_mapping, start >> PAGE_CACHE_SHIFT, (void *)jffs2_do_readpage_unlock, inode); - +#endif if (IS_ERR(pg)) { printk(KERN_WARNING "read_cache_page() returned error: %ld\n", PTR_ERR(pg)); return PTR_ERR(pg); @@ -780,11 +1076,11 @@ ret = jffs2_reserve_space_gc(c, sizeof(ri) + JFFS2_MIN_DATA_LEN, &phys_ofs, &alloclen); if (ret) { - printk(KERN_WARNING "jffs2_reserve_space_gc of %d bytes for garbage_collect_dnode failed: %d\n", + printk(KERN_WARNING "jffs2_reserve_space_gc of %zd bytes for garbage_collect_dnode failed: %d\n", sizeof(ri)+ JFFS2_MIN_DATA_LEN, ret); break; } - cdatalen = min(alloclen - sizeof(ri), end - offset); + cdatalen = min_t(uint32_t, alloclen - sizeof(ri), end - offset); datalen = end - offset; writebuf = pg_ptr + (offset & (PAGE_CACHE_SIZE -1)); @@ -804,7 +1100,7 @@ ri.ino = cpu_to_je32(f->inocache->ino); ri.version = cpu_to_je32(++f->highest_version); - ri.mode = cpu_to_je32(JFFS2_F_I_MODE(f)); + ri.mode = cpu_to_jemode(JFFS2_F_I_MODE(f)); ri.uid = cpu_to_je16(JFFS2_F_I_UID(f)); ri.gid = cpu_to_je16(JFFS2_F_I_GID(f)); ri.isize = cpu_to_je32(JFFS2_F_I_SIZE(f)); diff -Nru a/fs/jffs2/malloc.c b/fs/jffs2/malloc.c --- a/fs/jffs2/malloc.c Mon Jun 9 23:16:06 2003 +++ b/fs/jffs2/malloc.c Mon Jun 9 23:16:06 2003 @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: malloc.c,v 1.22 2002/05/20 14:56:38 dwmw2 Exp $ + * $Id: malloc.c,v 1.24 2003/03/11 17:30:29 gleixner Exp $ * */ @@ -23,6 +23,9 @@ #define JFFS2_SLAB_POISON 0 #endif +// replace this by #define D3 (x) x for cache debugging +#define D3(x) + /* These are initialised to NULL in the kernel startup code. If you're porting to other operating systems, beware */ static kmem_cache_t *full_dnode_slab; @@ -73,8 +76,7 @@ inode_cache_slab = kmem_cache_create("jffs2_inode_cache", sizeof(struct jffs2_inode_cache), - 0, JFFS2_SLAB_POISON|SLAB_RECLAIM_ACCOUNT, - NULL, NULL); + 0, JFFS2_SLAB_POISON, NULL, NULL); if (inode_cache_slab) return 0; err: @@ -112,75 +114,92 @@ struct jffs2_full_dnode *jffs2_alloc_full_dnode(void) { - void *ret = kmem_cache_alloc(full_dnode_slab, GFP_KERNEL); + struct jffs2_full_dnode *ret = kmem_cache_alloc(full_dnode_slab, GFP_KERNEL); + D3 (printk (KERN_DEBUG "alloc_full_dnode at %p\n", ret)); return ret; } void jffs2_free_full_dnode(struct jffs2_full_dnode *x) { + D3 (printk (KERN_DEBUG "free full_dnode at %p\n", x)); kmem_cache_free(full_dnode_slab, x); } struct jffs2_raw_dirent *jffs2_alloc_raw_dirent(void) { - return kmem_cache_alloc(raw_dirent_slab, GFP_KERNEL); + struct jffs2_raw_dirent *ret = kmem_cache_alloc(raw_dirent_slab, GFP_KERNEL); + D3 (printk (KERN_DEBUG "alloc_raw_dirent\n", ret)); + return ret; } void jffs2_free_raw_dirent(struct jffs2_raw_dirent *x) { + D3 (printk (KERN_DEBUG "free_raw_dirent at %p\n", x)); kmem_cache_free(raw_dirent_slab, x); } struct jffs2_raw_inode *jffs2_alloc_raw_inode(void) { - return kmem_cache_alloc(raw_inode_slab, GFP_KERNEL); + struct jffs2_raw_inode *ret = kmem_cache_alloc(raw_inode_slab, GFP_KERNEL); + D3 (printk (KERN_DEBUG "alloc_raw_inode at %p\n", ret)); + return ret; } void jffs2_free_raw_inode(struct jffs2_raw_inode *x) { + D3 (printk (KERN_DEBUG "free_raw_inode at %p\n", x)); kmem_cache_free(raw_inode_slab, x); } struct jffs2_tmp_dnode_info *jffs2_alloc_tmp_dnode_info(void) { - return kmem_cache_alloc(tmp_dnode_info_slab, GFP_KERNEL); + struct jffs2_tmp_dnode_info *ret = kmem_cache_alloc(tmp_dnode_info_slab, GFP_KERNEL); + D3 (printk (KERN_DEBUG "alloc_tmp_dnode_info at %p\n", ret)); + return ret; } void jffs2_free_tmp_dnode_info(struct jffs2_tmp_dnode_info *x) { + D3 (printk (KERN_DEBUG "free_tmp_dnode_info at %p\n", x)); kmem_cache_free(tmp_dnode_info_slab, x); } struct jffs2_raw_node_ref *jffs2_alloc_raw_node_ref(void) { - return kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL); + struct jffs2_raw_node_ref *ret = kmem_cache_alloc(raw_node_ref_slab, GFP_KERNEL); + D3 (printk (KERN_DEBUG "alloc_raw_node_ref at %p\n", ret)); + return ret; } void jffs2_free_raw_node_ref(struct jffs2_raw_node_ref *x) { + D3 (printk (KERN_DEBUG "free_raw_node_ref at %p\n", x)); kmem_cache_free(raw_node_ref_slab, x); } struct jffs2_node_frag *jffs2_alloc_node_frag(void) { - return kmem_cache_alloc(node_frag_slab, GFP_KERNEL); + struct jffs2_node_frag *ret = kmem_cache_alloc(node_frag_slab, GFP_KERNEL); + D3 (printk (KERN_DEBUG "alloc_node_frag at %p\n", ret)); + return ret; } void jffs2_free_node_frag(struct jffs2_node_frag *x) { + D3 (printk (KERN_DEBUG "free_node_frag at %p\n", x)); kmem_cache_free(node_frag_slab, x); } struct jffs2_inode_cache *jffs2_alloc_inode_cache(void) { struct jffs2_inode_cache *ret = kmem_cache_alloc(inode_cache_slab, GFP_KERNEL); - D1(printk(KERN_DEBUG "Allocated inocache at %p\n", ret)); + D3 (printk(KERN_DEBUG "Allocated inocache at %p\n", ret)); return ret; } void jffs2_free_inode_cache(struct jffs2_inode_cache *x) { - D1(printk(KERN_DEBUG "Freeing inocache at %p\n", x)); + D3 (printk(KERN_DEBUG "Freeing inocache at %p\n", x)); kmem_cache_free(inode_cache_slab, x); } diff -Nru a/fs/jffs2/nodelist.c b/fs/jffs2/nodelist.c --- a/fs/jffs2/nodelist.c Mon Jun 9 23:16:13 2003 +++ b/fs/jffs2/nodelist.c Mon Jun 9 23:16:13 2003 @@ -7,17 +7,18 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: nodelist.c,v 1.65 2002/11/12 09:50:13 dwmw2 Exp $ + * $Id: nodelist.c,v 1.79 2003/04/08 08:20:01 dwmw2 Exp $ * */ #include <linux/kernel.h> +#include <linux/sched.h> #include <linux/fs.h> #include <linux/mtd/mtd.h> -#include <linux/interrupt.h> #include <linux/rbtree.h> #include <linux/crc32.h> #include <linux/slab.h> +#include <linux/pagemap.h> #include "nodelist.h" void jffs2_add_fd_to_list(struct jffs2_sb_info *c, struct jffs2_full_dirent *new, struct jffs2_full_dirent **list) @@ -112,10 +113,10 @@ D1(printk(KERN_DEBUG "jffs2_get_inode_nodes(): ino #%lu\n", ino)); if (!f->inocache->nodes) { - printk(KERN_WARNING "Eep. no nodes for ino #%lu\n", ino); + printk(KERN_WARNING "Eep. no nodes for ino #%lu\n", (unsigned long)ino); } - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); for (ref = f->inocache->nodes; ref && ref->next_in_ino; ref = ref->next_in_ino) { /* Work out whether it's a data node or a dirent node */ @@ -127,12 +128,12 @@ /* We can hold a pointer to a non-obsolete node without the spinlock, but _obsolete_ nodes may disappear at any time, if the block they're in gets erased */ - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); cond_resched(); /* FIXME: point() */ - err = jffs2_flash_read(c, (ref_offset(ref)), min(ref->totlen, sizeof(node)), &retlen, (void *)&node); + err = jffs2_flash_read(c, (ref_offset(ref)), min_t(uint32_t, ref->totlen, sizeof(node)), &retlen, (void *)&node); if (err) { printk(KERN_WARNING "error %d reading node at 0x%08x in get_inode_nodes()\n", err, ref_offset(ref)); goto free_out; @@ -140,7 +141,7 @@ /* Check we've managed to read at least the common node header */ - if (retlen < min(ref->totlen, sizeof(node.u))) { + if (retlen < min_t(uint32_t, ref->totlen, sizeof(node.u))) { printk(KERN_WARNING "short read in get_inode_nodes()\n"); err = -EIO; goto free_out; @@ -158,6 +159,14 @@ err = -EIO; goto free_out; } + /* sanity check */ + if (PAD((node.d.nsize + sizeof (node.d))) != PAD(je32_to_cpu (node.d.totlen))) { + printk(KERN_NOTICE "jffs2_get_inode_nodes(): Illegal nsize in node at 0x%08x: nsize 0x%02x, totlen %04x\n", + ref_offset(ref), node.d.nsize, je32_to_cpu(node.d.totlen)); + jffs2_mark_node_obsolete(c, ref); + spin_lock(&c->erase_completion_lock); + continue; + } if (je32_to_cpu(node.d.version) > *highest_version) *highest_version = je32_to_cpu(node.d.version); if (ref_obsolete(ref)) { @@ -166,6 +175,7 @@ ref_offset(ref)); BUG(); } + fd = jffs2_alloc_full_dirent(node.d.nsize+1); if (!fd) { err = -ENOMEM; @@ -187,7 +197,7 @@ dirent we've already read from the flash */ if (retlen > sizeof(struct jffs2_raw_dirent)) - memcpy(&fd->name[0], &node.d.name[0], min((uint32_t)node.d.nsize, (retlen-sizeof(struct jffs2_raw_dirent)))); + memcpy(&fd->name[0], &node.d.name[0], min_t(uint32_t, node.d.nsize, (retlen-sizeof(struct jffs2_raw_dirent)))); /* Do we need to copy any more of the name directly from the flash? @@ -244,46 +254,95 @@ printk(KERN_NOTICE "jffs2_get_inode_nodes(): CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", ref_offset(ref), je32_to_cpu(node.i.node_crc), crc); jffs2_mark_node_obsolete(c, ref); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); + continue; + } + + /* sanity checks */ + if ( je32_to_cpu(node.i.offset) > je32_to_cpu(node.i.isize) || + PAD(je32_to_cpu(node.i.csize) + sizeof (node.i)) != PAD(je32_to_cpu(node.i.totlen))) { + printk(KERN_NOTICE "jffs2_get_inode_nodes(): Inode corrupted at 0x%08x, totlen %d, #ino %d, version %d, isize %d, csize %d, dsize %d \n", + ref_offset(ref), je32_to_cpu(node.i.totlen), je32_to_cpu(node.i.ino), + je32_to_cpu(node.i.version), je32_to_cpu(node.i.isize), + je32_to_cpu(node.i.csize), je32_to_cpu(node.i.dsize)); + jffs2_mark_node_obsolete(c, ref); + spin_lock(&c->erase_completion_lock); continue; } if (node.i.compr != JFFS2_COMPR_ZERO && je32_to_cpu(node.i.csize)) { - /* FIXME: point() */ - char *buf = kmalloc(je32_to_cpu(node.i.csize), GFP_KERNEL); - if (!buf) - return -ENOMEM; - - err = jffs2_flash_read(c, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize), - &retlen, buf); - if (!err && retlen != je32_to_cpu(node.i.csize)) - err = -EIO; - if (err) { - kfree(buf); - return err; + unsigned char *buf=NULL; + uint32_t pointed = 0; +#ifndef __ECOS + if (c->mtd->point) { + err = c->mtd->point (c->mtd, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize), + &retlen, &buf); + if (!err && retlen < je32_to_cpu(node.i.csize)) { + D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", retlen)); + c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize)); + } else if (err){ + D1(printk(KERN_DEBUG "MTD point failed %d\n", err)); + } else + pointed = 1; /* succefully pointed to device */ + } +#endif + if(!pointed){ + buf = kmalloc(je32_to_cpu(node.i.csize), GFP_KERNEL); + if (!buf) + return -ENOMEM; + + err = jffs2_flash_read(c, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize), + &retlen, buf); + if (!err && retlen != je32_to_cpu(node.i.csize)) + err = -EIO; + if (err) { + kfree(buf); + return err; + } } - crc = crc32(0, buf, je32_to_cpu(node.i.csize)); - kfree(buf); + if(!pointed) + kfree(buf); +#ifndef __ECOS + else + c->mtd->unpoint(c->mtd, buf, ref_offset(ref) + sizeof(node.i), je32_to_cpu(node.i.csize)); +#endif if (crc != je32_to_cpu(node.i.data_crc)) { printk(KERN_NOTICE "jffs2_get_inode_nodes(): Data CRC failed on node at 0x%08x: Read 0x%08x, calculated 0x%08x\n", ref_offset(ref), je32_to_cpu(node.i.data_crc), crc); jffs2_mark_node_obsolete(c, ref); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); continue; } } /* Mark the node as having been checked and fix the accounting accordingly */ + spin_lock(&c->erase_completion_lock); jeb = &c->blocks[ref->flash_offset / c->sector_size]; jeb->used_size += ref->totlen; jeb->unchecked_size -= ref->totlen; c->used_size += ref->totlen; c->unchecked_size -= ref->totlen; - mark_ref_normal(ref); + /* If node covers at least a whole page, or if it starts at the + beginning of a page and runs to the end of the file, or if + it's a hole node, mark it REF_PRISTINE, else REF_NORMAL. + + If it's actually overlapped, it'll get made NORMAL (or OBSOLETE) + when the overlapping node(s) get added to the tree anyway. + */ + if ((je32_to_cpu(node.i.dsize) >= PAGE_CACHE_SIZE) || + ( ((je32_to_cpu(node.i.offset)&(PAGE_CACHE_SIZE-1))==0) && + (je32_to_cpu(node.i.dsize)+je32_to_cpu(node.i.offset) == je32_to_cpu(node.i.isize)))) { + D1(printk(KERN_DEBUG "Marking node at 0x%08x REF_PRISTINE\n", ref_offset(ref))); + ref->flash_offset = ref_offset(ref) | REF_PRISTINE; + } else { + D1(printk(KERN_DEBUG "Marking node at 0x%08x REF_NORMAL\n", ref_offset(ref))); + ref->flash_offset = ref_offset(ref) | REF_NORMAL; + } + spin_unlock(&c->erase_completion_lock); } tn = jffs2_alloc_tmp_dnode_info(); @@ -323,13 +382,15 @@ je16_to_cpu(node.u.nodetype), ref_offset(ref)); /* Mark the node as having been checked and fix the accounting accordingly */ + spin_lock(&c->erase_completion_lock); jeb = &c->blocks[ref->flash_offset / c->sector_size]; jeb->used_size += ref->totlen; jeb->unchecked_size -= ref->totlen; c->used_size += ref->totlen; c->unchecked_size -= ref->totlen; - + mark_ref_normal(ref); + spin_unlock(&c->erase_completion_lock); } node.u.nodetype = cpu_to_je16(JFFS2_NODE_ACCURATE | je16_to_cpu(node.u.nodetype)); if (crc32(0, &node, sizeof(struct jffs2_unknown_node)-4) != je32_to_cpu(node.u.hdr_crc)) { @@ -361,10 +422,10 @@ } } - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); } - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); *tnp = ret_tn; *fdp = ret_fd; @@ -376,12 +437,24 @@ return err; } -struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, int ino) +void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state) +{ + spin_lock(&c->inocache_lock); + ic->state = state; + wake_up(&c->inocache_wq); + spin_unlock(&c->inocache_lock); +} + +/* During mount, this needs no locking. During normal operation, its + callers want to do other stuff while still holding the inocache_lock. + Rather than introducing special case get_ino_cache functions or + callbacks, we just let the caller do the locking itself. */ + +struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t ino) { struct jffs2_inode_cache *ret; D2(printk(KERN_DEBUG "jffs2_get_ino_cache(): ino %u\n", ino)); - spin_lock (&c->inocache_lock); ret = c->inocache_list[ino % INOCACHE_HASHSIZE]; while (ret && ret->ino < ino) { @@ -390,8 +463,6 @@ if (ret && ret->ino != ino) ret = NULL; - - spin_unlock(&c->inocache_lock); D2(printk(KERN_DEBUG "jffs2_get_ino_cache found %p for ino %u\n", ret, ino)); return ret; diff -Nru a/fs/jffs2/nodelist.h b/fs/jffs2/nodelist.h --- a/fs/jffs2/nodelist.h Mon Jun 9 23:16:20 2003 +++ b/fs/jffs2/nodelist.h Mon Jun 9 23:16:20 2003 @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: nodelist.h,v 1.87 2002/11/12 13:36:18 dwmw2 Exp $ + * $Id: nodelist.h,v 1.93 2003/02/24 21:47:28 dwmw2 Exp $ * */ @@ -16,12 +16,17 @@ #include <linux/config.h> #include <linux/fs.h> - -#include <linux/mtd/compatmac.h> /* For min/max in older kernels */ +#include <linux/types.h> #include <linux/jffs2.h> #include <linux/jffs2_fs_sb.h> #include <linux/jffs2_fs_i.h> + +#ifdef __ECOS +#include "os-ecos.h" +#else +#include <linux/mtd/compatmac.h> /* For min/max in older kernels */ #include "os-linux.h" +#endif #ifndef CONFIG_JFFS2_FS_DEBUG #define CONFIG_JFFS2_FS_DEBUG 2 @@ -98,13 +103,18 @@ uint32_t ino; int nlink; int state; -#define INO_STATE_UNCHECKED 0 -#define INO_STATE_CHECKING 1 -#define INO_STATE_CHECKEDABSENT 2 -#define INO_STATE_READINGINODE 3 -#define INO_STATE_PRESENT 5 }; +/* Inode states for 'state' above. We need the 'GC' state to prevent + someone from doing a read_inode() while we're moving a 'REF_PRISTINE' + node without going through all the iget() nonsense */ +#define INO_STATE_UNCHECKED 0 /* CRC checks not yet done */ +#define INO_STATE_CHECKING 1 /* CRC checks in progress */ +#define INO_STATE_PRESENT 2 /* In core */ +#define INO_STATE_CHECKEDABSENT 3 /* Checked, cleared again */ +#define INO_STATE_GC 4 /* GCing a 'pristine' node */ +#define INO_STATE_READING 5 /* In read_inode() */ + #define INOCACHE_HASHSIZE 128 struct jffs2_scan_info { @@ -281,7 +291,8 @@ struct jffs2_tmp_dnode_info **tnp, struct jffs2_full_dirent **fdp, uint32_t *highest_version, uint32_t *latest_mctime, uint32_t *mctime_ver); -struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, int ino); +void jffs2_set_inocache_state(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic, int state); +struct jffs2_inode_cache *jffs2_get_ino_cache(struct jffs2_sb_info *c, uint32_t ino); void jffs2_add_ino_cache (struct jffs2_sb_info *c, struct jffs2_inode_cache *new); void jffs2_del_ino_cache(struct jffs2_sb_info *c, struct jffs2_inode_cache *old); void jffs2_free_ino_caches(struct jffs2_sb_info *c); @@ -315,10 +326,10 @@ /* readinode.c */ void jffs2_truncate_fraglist (struct jffs2_sb_info *c, struct rb_root *list, uint32_t size); -int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_full_dnode *fn); int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn); int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint32_t ino, struct jffs2_raw_inode *latest_node); +int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic); void jffs2_do_clear_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f); /* malloc.c */ diff -Nru a/fs/jffs2/nodemgmt.c b/fs/jffs2/nodemgmt.c --- a/fs/jffs2/nodemgmt.c Mon Jun 9 23:16:08 2003 +++ b/fs/jffs2/nodemgmt.c Mon Jun 9 23:16:08 2003 @@ -7,14 +7,15 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: nodemgmt.c,v 1.84 2002/11/12 11:17:29 dwmw2 Exp $ + * $Id: nodemgmt.c,v 1.94 2003/02/19 17:50:26 gleixner Exp $ * */ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/mtd/mtd.h> -#include <linux/interrupt.h> +#include <linux/compiler.h> +#include <linux/sched.h> /* For cond_resched() */ #include "nodelist.h" /** @@ -54,26 +55,57 @@ D1(printk(KERN_DEBUG "jffs2_reserve_space(): alloc sem got\n")); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); - /* this needs a little more thought */ + /* this needs a little more thought (true <tglx> :)) */ while(ret == -EAGAIN) { while(c->nr_free_blocks + c->nr_erasing_blocks < blocksneeded) { int ret; + uint32_t dirty, avail; up(&c->alloc_sem); - if (c->dirty_size + c->unchecked_size < c->sector_size) { + /* calculate real dirty size + * dirty_size contains blocks on erase_pending_list + * those blocks are counted in c->nr_erasing_blocks. + * If one block is actually erased, it is not longer counted as dirty_space + * but it is counted in c->nr_erasing_blocks, so we add it and subtract it + * with c->nr_erasing_blocks * c->sector_size again. + * Blocks on erasable_list are counted as dirty_size, but not in c->nr_erasing_blocks + * This helps us to force gc and pick eventually a clean block to spread the load. + * We add unchecked_size here, as we hopefully will find some space to use. + * This will affect the sum only once, as gc first finishes checking + * of nodes. + */ + dirty = c->dirty_size + c->erasing_size - c->nr_erasing_blocks * c->sector_size + c->unchecked_size; + if (dirty < c->sector_size) { D1(printk(KERN_DEBUG "dirty size 0x%08x + unchecked_size 0x%08x < sector size 0x%08x, returning -ENOSPC\n", - c->dirty_size, c->unchecked_size, c->sector_size)); - spin_unlock_bh(&c->erase_completion_lock); + dirty, c->unchecked_size, c->sector_size)); + spin_unlock(&c->erase_completion_lock); + return -ENOSPC; + } + + /* Calc possibly available space. Possibly available means that we + * don't know, if unchecked size contains obsoleted nodes, which could give us some + * more usable space. This will affect the sum only once, as gc first finishes checking + * of nodes. + + Return -ENOSPC, if the maximum possibly available space is less or equal than + * blocksneeded * sector_size. + * This blocks endless gc looping on a filesystem, which is nearly full, even if + * the check above passes. + */ + avail = c->free_size + c->dirty_size + c->erasing_size + c->unchecked_size; + if ( (avail / c->sector_size) <= blocksneeded) { + D1(printk(KERN_DEBUG "max. available size 0x%08x < blocksneeded * sector_size 0x%08x, returning -ENOSPC\n", + avail, blocksneeded * c->sector_size)); + spin_unlock(&c->erase_completion_lock); return -ENOSPC; } D1(printk(KERN_DEBUG "Triggering GC pass. nr_free_blocks %d, nr_erasing_blocks %d, free_size 0x%08x, dirty_size 0x%08x, wasted_size 0x%08x, used_size 0x%08x, erasing_size 0x%08x, bad_size 0x%08x (total 0x%08x of 0x%08x)\n", c->nr_free_blocks, c->nr_erasing_blocks, c->free_size, c->dirty_size, c->wasted_size, c->used_size, c->erasing_size, c->bad_size, c->free_size + c->dirty_size + c->wasted_size + c->used_size + c->erasing_size + c->bad_size, c->flash_size)); - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); ret = jffs2_garbage_collect_pass(c); if (ret) @@ -85,7 +117,7 @@ return -EINTR; down(&c->alloc_sem); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); } ret = jffs2_do_reserve_space(c, minsize, ofs, len); @@ -93,7 +125,7 @@ D1(printk(KERN_DEBUG "jffs2_reserve_space: ret is %d\n", ret)); } } - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); if (ret) up(&c->alloc_sem); return ret; @@ -106,14 +138,14 @@ D1(printk(KERN_DEBUG "jffs2_reserve_space_gc(): Requested 0x%x bytes\n", minsize)); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); while(ret == -EAGAIN) { ret = jffs2_do_reserve_space(c, minsize, ofs, len); if (ret) { D1(printk(KERN_DEBUG "jffs2_reserve_space_gc: looping, ret is %d\n", ret)); } } - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); return ret; } @@ -127,10 +159,10 @@ /* Skip the end of this block and file it as having some dirty space */ /* If there's a pending write to it, flush now */ if (c->wbuf_len) { - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n")); jffs2_flush_wbuf(c, 1); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); /* We know nobody's going to have changed nextblock. Just continue */ } c->wasted_size += jeb->free_size; @@ -186,9 +218,9 @@ !list_empty(&c->erasable_pending_wbuf_list)) { D1(printk(KERN_DEBUG "jffs2_do_reserve_space: Flushing write buffer\n")); /* c->nextblock is NULL, no update to c->nextblock allowed */ - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); jffs2_flush_wbuf(c, 1); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); /* Have another go. It'll be on the erasable_list now */ return -EAGAIN; } @@ -203,6 +235,11 @@ } /* Make sure this can't deadlock. Someone has to start the erases of erase_pending blocks */ +#ifdef __ECOS + /* In eCos, we don't have a handy kernel thread doing the erases for + us. We do them ourselves right now. */ + jffs2_erase_pending_blocks(c); +#else set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&c->erase_wait, &wait); D1(printk(KERN_DEBUG "Waiting for erases to complete. erasing_blocks is %d. (erasableempty: %s, erasingempty: %s, erasependingempty: %s)\n", @@ -212,13 +249,14 @@ D1(printk(KERN_DEBUG "Triggering pending erases\n")); jffs2_erase_pending_trigger(c); } - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); schedule(); remove_wait_queue(&c->erase_wait, &wait); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); if (signal_pending(current)) { return -EINTR; } +#endif /* An erase may have failed, decreasing the amount of free space available. So we must restart from the beginning */ @@ -248,9 +286,9 @@ already set c->nextblock so that jffs2_mark_node_obsolete() won't try to refile it to the dirty_list. */ - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); jffs2_mark_node_obsolete(c, jeb->first_node); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); } D1(printk(KERN_DEBUG "jffs2_do_reserve_space(): Giving 0x%x bytes at 0x%x\n", *len, *ofs)); @@ -276,7 +314,7 @@ uint32_t len = new->totlen; jeb = &c->blocks[new->flash_offset / c->sector_size]; - D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x, size 0x%x\n", ref_offset(new), len)); + D1(printk(KERN_DEBUG "jffs2_add_physical_node_ref(): Node at 0x%x(%d), size 0x%x\n", ref_offset(new), ref_flags(new), len)); #if 1 if (jeb != c->nextblock || (ref_offset(new)) != jeb->offset + (c->sector_size - jeb->free_size)) { printk(KERN_WARNING "argh. node added in wrong place\n"); @@ -284,7 +322,7 @@ return -EINVAL; } #endif - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); if (!jeb->first_node) jeb->first_node = new; @@ -308,9 +346,9 @@ jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); if (c->wbuf_len) { /* Flush the last write in the block if it's outstanding */ - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); jffs2_flush_wbuf(c, 1); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); } list_add_tail(&jeb->list, &c->clean_list); @@ -319,7 +357,7 @@ ACCT_SANITY_CHECK(c,jeb); D1(ACCT_PARANOIA_CHECK(jeb)); - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); return 0; } @@ -337,7 +375,7 @@ struct jffs2_eraseblock *jeb; int blocknr; struct jffs2_unknown_node n; - int ret; + int ret, addedsize; size_t retlen; if(!ref) { @@ -355,7 +393,7 @@ } jeb = &c->blocks[blocknr]; - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); if (ref_flags(ref) == REF_UNCHECKED) { D1(if (unlikely(jeb->unchecked_size < ref->totlen)) { @@ -377,14 +415,17 @@ c->used_size -= ref->totlen; } + // Take care, that wasted size is taken into concern if ((jeb->dirty_size || ISDIRTY(jeb->wasted_size + ref->totlen)) && jeb != c->nextblock) { D1(printk("Dirtying\n")); - jeb->dirty_size += ref->totlen + jeb->wasted_size; - c->dirty_size += ref->totlen + jeb->wasted_size; + addedsize = ref->totlen + jeb->wasted_size; + jeb->dirty_size += addedsize; + c->dirty_size += addedsize; c->wasted_size -= jeb->wasted_size; jeb->wasted_size = 0; } else { D1(printk("Wasting\n")); + addedsize = 0; jeb->wasted_size += ref->totlen; c->wasted_size += ref->totlen; } @@ -400,7 +441,7 @@ obliterate nodes that look obsolete. If they weren't marked obsolete on the flash at the time they _became_ obsolete, there was probably a reason for that. */ - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); return; } @@ -417,6 +458,10 @@ if (c->wbuf_len) { D1(printk(KERN_DEBUG "...and adding to erasable_pending_wbuf_list\n")); list_add_tail(&jeb->list, &c->erasable_pending_wbuf_list); +#if 0 /* This check was added to allow us to find places where we added nodes to the lists + after dropping the alloc_sem, and it did that just fine. But it also caused us to + lock the alloc_sem in other places, like clear_inode(), when we wouldn't otherwise + have needed to. So I suspect it's outlived its usefulness. Thomas? */ /* We've changed the rules slightly. After writing a node you now mustn't drop the @@ -436,6 +481,7 @@ printk(KERN_CRIT "jffs2_mark_node_obsolete() called with wbuf active but alloc_sem not locked!\n"); BUG(); } +#endif } else { if (jiffies & 127) { /* Most of the time, we just erase it immediately. Otherwise we @@ -454,7 +500,7 @@ D1(printk(KERN_DEBUG "Done OK\n")); } else if (jeb == c->gcblock) { D2(printk(KERN_DEBUG "Not moving gcblock 0x%08x to dirty_list\n", jeb->offset)); - } else if (ISDIRTY(jeb->dirty_size) && !ISDIRTY(jeb->dirty_size - ref->totlen)) { + } else if (ISDIRTY(jeb->dirty_size) && !ISDIRTY(jeb->dirty_size - addedsize)) { D1(printk(KERN_DEBUG "Eraseblock at 0x%08x is freshly dirtied. Removing from clean list...\n", jeb->offset)); list_del(&jeb->list); D1(printk(KERN_DEBUG "...and adding to dirty_list\n")); @@ -470,7 +516,7 @@ jeb->offset, jeb->free_size, jeb->dirty_size, jeb->used_size)); } - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); if (!jffs2_can_mark_obsolete(c)) return; @@ -484,7 +530,7 @@ return; } if (retlen != sizeof(n)) { - printk(KERN_WARNING "Short read from obsoleted node at 0x%08x: %d\n", ref_offset(ref), retlen); + printk(KERN_WARNING "Short read from obsoleted node at 0x%08x: %zd\n", ref_offset(ref), retlen); return; } if (PAD(je32_to_cpu(n.totlen)) != PAD(ref->totlen)) { @@ -503,7 +549,7 @@ return; } if (retlen != sizeof(n)) { - printk(KERN_WARNING "Short write in obliterating obsoleted node at 0x%08x: %d\n", ref_offset(ref), retlen); + printk(KERN_WARNING "Short write in obliterating obsoleted node at 0x%08x: %zd\n", ref_offset(ref), retlen); return; } } diff -Nru a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h --- a/fs/jffs2/os-linux.h Mon Jun 9 23:16:07 2003 +++ b/fs/jffs2/os-linux.h Mon Jun 9 23:16:07 2003 @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: os-linux.h,v 1.21 2002/11/12 09:44:30 dwmw2 Exp $ + * $Id: os-linux.h,v 1.26 2003/05/16 18:45:25 dwmw2 Exp $ * */ @@ -15,6 +15,11 @@ #define __JFFS2_OS_LINUX_H__ #include <linux/version.h> +/* JFFS2 uses Linux mode bits natively -- no need for conversion */ +#define os_to_jffs2_mode(x) (x) +#define jffs2_to_os_mode(x) (x) + + #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2) #define JFFS2_INODE_INFO(i) (list_entry(i, struct jffs2_inode_info, vfs_inode)) #define OFNI_EDONI_2SFFJ(f) (&(f)->vfs_inode) @@ -37,9 +42,6 @@ #define JFFS2_F_I_MODE(f) (OFNI_EDONI_2SFFJ(f)->i_mode) #define JFFS2_F_I_UID(f) (OFNI_EDONI_2SFFJ(f)->i_uid) #define JFFS2_F_I_GID(f) (OFNI_EDONI_2SFFJ(f)->i_gid) -#define JFFS2_F_I_CTIME(f) (OFNI_EDONI_2SFFJ(f)->i_ctime.tv_sec) -#define JFFS2_F_I_MTIME(f) (OFNI_EDONI_2SFFJ(f)->i_mtime.tv_sec) -#define JFFS2_F_I_ATIME(f) (OFNI_EDONI_2SFFJ(f)->i_atime.tv_sec) #if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,1) #define JFFS2_F_I_RDEV_MIN(f) (minor(OFNI_EDONI_2SFFJ(f)->i_rdev)) @@ -49,6 +51,21 @@ #define JFFS2_F_I_RDEV_MAJ(f) (MAJOR(to_kdev_t(OFNI_EDONI_2SFFJ(f)->i_rdev))) #endif +/* Urgh. The things we do to keep the 2.4 build working */ +#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,47) +#define ITIME(sec) ((struct timespec){sec, 0}) +#define I_SEC(tv) ((tv).tv_sec) +#define JFFS2_F_I_CTIME(f) (OFNI_EDONI_2SFFJ(f)->i_ctime.tv_sec) +#define JFFS2_F_I_MTIME(f) (OFNI_EDONI_2SFFJ(f)->i_mtime.tv_sec) +#define JFFS2_F_I_ATIME(f) (OFNI_EDONI_2SFFJ(f)->i_atime.tv_sec) +#else +#define ITIME(x) (x) +#define I_SEC(x) (x) +#define JFFS2_F_I_CTIME(f) (OFNI_EDONI_2SFFJ(f)->i_ctime) +#define JFFS2_F_I_MTIME(f) (OFNI_EDONI_2SFFJ(f)->i_mtime) +#define JFFS2_F_I_ATIME(f) (OFNI_EDONI_2SFFJ(f)->i_atime) +#endif + /* Hmmm. P'raps generic code should only ever see versions of signal functions which do the locking automatically? */ #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,40) @@ -56,6 +73,16 @@ #else #define current_sig_lock current->sighand->siglock #endif + +#define sleep_on_spinunlock(wq, s) \ + do { \ + DECLARE_WAITQUEUE(__wait, current); \ + add_wait_queue((wq), &__wait); \ + set_current_state(TASK_UNINTERRUPTIBLE); \ + spin_unlock(s); \ + schedule(); \ + remove_wait_queue((wq), &__wait); \ + } while(0) static inline void jffs2_init_inode_info(struct jffs2_inode_info *f) { diff -Nru a/fs/jffs2/read.c b/fs/jffs2/read.c --- a/fs/jffs2/read.c Mon Jun 9 23:16:09 2003 +++ b/fs/jffs2/read.c Mon Jun 9 23:16:09 2003 @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: read.c,v 1.29 2002/11/12 09:51:22 dwmw2 Exp $ + * $Id: read.c,v 1.31 2003/01/14 14:06:22 dwmw2 Exp $ * */ @@ -39,7 +39,7 @@ } if (readlen != sizeof(*ri)) { jffs2_free_raw_inode(ri); - printk(KERN_WARNING "Short read from 0x%08x: wanted 0x%x bytes, got 0x%x\n", + printk(KERN_WARNING "Short read from 0x%08x: wanted 0x%zx bytes, got 0x%zx\n", ref_offset(fd->raw), sizeof(*ri), readlen); return -EIO; } @@ -197,8 +197,9 @@ fragofs = offset - frag->ofs; readlen = min(frag->size - fragofs, end - offset); - D1(printk(KERN_DEBUG "Reading %d-%d from node at 0x%x\n", frag->ofs+fragofs, frag->ofs+fragofs+readlen, - ref_offset(frag->node->raw))); + D1(printk(KERN_DEBUG "Reading %d-%d from node at 0x%08x (%d)\n", + frag->ofs+fragofs, frag->ofs+fragofs+readlen, + ref_offset(frag->node->raw), ref_flags(frag->node->raw))); ret = jffs2_read_dnode(c, frag->node, buf, fragofs + frag->ofs - frag->node->ofs, readlen); D2(printk(KERN_DEBUG "node read done\n")); if (ret) { diff -Nru a/fs/jffs2/readinode.c b/fs/jffs2/readinode.c --- a/fs/jffs2/readinode.c Mon Jun 9 23:16:06 2003 +++ b/fs/jffs2/readinode.c Mon Jun 9 23:16:06 2003 @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: readinode.c,v 1.95 2002/11/12 11:17:29 dwmw2 Exp $ + * $Id: readinode.c,v 1.106 2003/05/14 06:53:26 dwmw2 Exp $ * */ @@ -17,11 +17,13 @@ #include <linux/crc32.h> #include <linux/pagemap.h> #include <linux/mtd/mtd.h> -#include <linux/interrupt.h> +#include <linux/compiler.h> #include "nodelist.h" +static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_node_frag *newfrag); -D1(static void jffs2_print_fragtree(struct rb_root *list, int permitbug) +#if CONFIG_JFFS2_FS_DEBUG >= 1 +static void jffs2_print_fragtree(struct rb_root *list, int permitbug) { struct jffs2_node_frag *this = frag_first(list); uint32_t lastofs = 0; @@ -44,31 +46,17 @@ printk(KERN_CRIT "Frag tree got a hole in it\n"); BUG(); } -}) +} -D1(void jffs2_print_frag_list(struct jffs2_inode_info *f) +void jffs2_print_frag_list(struct jffs2_inode_info *f) { jffs2_print_fragtree(&f->fragtree, 0); if (f->metadata) { printk(KERN_DEBUG "metadata at 0x%08x\n", ref_offset(f->metadata->raw)); } -}) - - -/* Given an inode, probably with existing list of fragments, add the new node - * to the fragment list. - */ -int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn) -{ - int ret; - D1(printk(KERN_DEBUG "jffs2_add_full_dnode_to_inode(ino #%u, f %p, fn %p)\n", f->inocache->ino, f, fn)); - - ret = jffs2_add_full_dnode_to_fraglist(c, &f->fragtree, fn); - - D2(jffs2_print_frag_list(f)); - return ret; } +#endif /* D1 */ static void jffs2_obsolete_node_frag(struct jffs2_sb_info *c, struct jffs2_node_frag *this) { @@ -91,26 +79,24 @@ jffs2_free_node_frag(this); } -/* Doesn't set inode->i_size */ -int jffs2_add_full_dnode_to_fraglist(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_full_dnode *fn) +/* Given an inode, probably with existing list of fragments, add the new node + * to the fragment list. + */ +int jffs2_add_full_dnode_to_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, struct jffs2_full_dnode *fn) { - struct jffs2_node_frag *this; + int ret; struct jffs2_node_frag *newfrag; - uint32_t lastend; + + D1(printk(KERN_DEBUG "jffs2_add_full_dnode_to_inode(ino #%u, f %p, fn %p)\n", f->inocache->ino, f, fn)); newfrag = jffs2_alloc_node_frag(); - if (!newfrag) { + if (unlikely(!newfrag)) return -ENOMEM; - } - - if (!fn->raw) { - printk(KERN_WARNING "dwmw2 is stupid. j_a_f_d_t_f should never happen with ->raw == NULL\n"); - BUG(); - } - D2(printk(KERN_DEBUG "adding node %04x-%04x @0x%08x on flash, newfrag *%p\n", fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag)); + D2(printk(KERN_DEBUG "adding node %04x-%04x @0x%08x on flash, newfrag *%p\n", + fn->ofs, fn->ofs+fn->size, ref_offset(fn->raw), newfrag)); - if (!fn->size) { + if (unlikely(!fn->size)) { jffs2_free_node_frag(newfrag); return 0; } @@ -120,8 +106,42 @@ newfrag->node = fn; newfrag->node->frags = 1; + ret = jffs2_add_frag_to_fragtree(c, &f->fragtree, newfrag); + if (ret) + return ret; + + /* If we now share a page with other nodes, mark either previous + or next node REF_NORMAL, as appropriate. */ + if (newfrag->ofs & (PAGE_CACHE_SIZE-1)) { + struct jffs2_node_frag *prev = frag_prev(newfrag); + + mark_ref_normal(fn->raw); + /* If we don't start at zero there's _always_ a previous */ + if (prev->node) + mark_ref_normal(prev->node->raw); + } + + if ((newfrag->ofs+newfrag->size) & (PAGE_CACHE_SIZE-1)) { + struct jffs2_node_frag *next = frag_next(newfrag); + + if (next) { + mark_ref_normal(fn->raw); + if (next->node) + mark_ref_normal(next->node->raw); + } + } + D2(jffs2_print_frag_list(f)); + return 0; +} + +/* Doesn't set inode->i_size */ +static int jffs2_add_frag_to_fragtree(struct jffs2_sb_info *c, struct rb_root *list, struct jffs2_node_frag *newfrag) +{ + struct jffs2_node_frag *this; + uint32_t lastend; + /* Skip all the nodes which are completed before this one starts */ - this = jffs2_lookup_node_frag(list, fn->ofs); + this = jffs2_lookup_node_frag(list, newfrag->node->ofs); if (this) { D2(printk(KERN_DEBUG "j_a_f_d_t_f: Lookup gave frag 0x%04x-0x%04x; phys 0x%08x (*%p)\n", @@ -143,16 +163,18 @@ if ((lastend-1) >> PAGE_CACHE_SHIFT == newfrag->ofs >> PAGE_CACHE_SHIFT) { if (this->node) mark_ref_normal(this->node->raw); - mark_ref_normal(fn->raw); + mark_ref_normal(newfrag->node->raw); } - if (lastend < fn->ofs) { + if (lastend < newfrag->node->ofs) { /* ... and we need to put a hole in before the new node */ struct jffs2_node_frag *holefrag = jffs2_alloc_node_frag(); - if (!holefrag) + if (!holefrag) { + jffs2_free_node_frag(newfrag); return -ENOMEM; + } holefrag->ofs = lastend; - holefrag->size = fn->ofs - lastend; + holefrag->size = newfrag->node->ofs - lastend; holefrag->node = NULL; if (this) { /* By definition, the 'this' node has no right-hand child, @@ -190,9 +212,9 @@ if (newfrag->ofs > this->ofs) { /* This node isn't completely obsoleted. The start of it remains valid */ - /* Mark the new node and the partially covered node REF_NORMAL -- let + /* Mark the new node and the partially covered node REF_NORMAL -- let the GC take a look at them */ - mark_ref_normal(fn->raw); + mark_ref_normal(newfrag->node->raw); if (this->node) mark_ref_normal(this->node->raw); @@ -283,7 +305,7 @@ /* And mark them REF_NORMAL so the GC takes a look at them */ if (this->node) mark_ref_normal(this->node->raw); - mark_ref_normal(fn->raw); + mark_ref_normal(newfrag->node->raw); return 0; } @@ -314,24 +336,54 @@ /* Scan the list of all nodes present for this ino, build map of versions, etc. */ +static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, + struct jffs2_inode_info *f, + struct jffs2_raw_inode *latest_node); + int jffs2_do_read_inode(struct jffs2_sb_info *c, struct jffs2_inode_info *f, uint32_t ino, struct jffs2_raw_inode *latest_node) { - struct jffs2_tmp_dnode_info *tn_list, *tn; - struct jffs2_full_dirent *fd_list; - struct jffs2_full_dnode *fn = NULL; - uint32_t crc; - uint32_t latest_mctime, mctime_ver; - uint32_t mdata_ver = 0; - size_t retlen; - int ret; - D2(printk(KERN_DEBUG "jffs2_do_read_inode(): getting inocache\n")); + retry_inocache: + spin_lock(&c->inocache_lock); f->inocache = jffs2_get_ino_cache(c, ino); D2(printk(KERN_DEBUG "jffs2_do_read_inode(): Got inocache at %p\n", f->inocache)); + if (f->inocache) { + /* Check its state. We may need to wait before we can use it */ + switch(f->inocache->state) { + case INO_STATE_UNCHECKED: + case INO_STATE_CHECKEDABSENT: + f->inocache->state = INO_STATE_READING; + break; + + case INO_STATE_CHECKING: + case INO_STATE_GC: + /* If it's in either of these states, we need + to wait for whoever's got it to finish and + put it back. */ + D1(printk(KERN_DEBUG "jffs2_get_ino_cache_read waiting for ino #%u in state %d\n", + ino, f->inocache->state)); + sleep_on_spinunlock(&c->inocache_wq, &c->inocache_lock); + goto retry_inocache; + + case INO_STATE_READING: + case INO_STATE_PRESENT: + /* Eep. This should never happen. It can + happen if Linux calls read_inode() again + before clear_inode() has finished though. */ + printk(KERN_WARNING "Eep. Trying to read_inode #%u when it's already in state %d!\n", ino, f->inocache->state); + /* Fail. That's probably better than allowing it to succeed */ + f->inocache = NULL; + break; + + default: + BUG(); + } + } + spin_unlock(&c->inocache_lock); if (!f->inocache && ino == 1) { /* Special case - no root inode on medium */ f->inocache = jffs2_alloc_inode_cache(); @@ -343,19 +395,61 @@ memset(f->inocache, 0, sizeof(struct jffs2_inode_cache)); f->inocache->ino = f->inocache->nlink = 1; f->inocache->nodes = (struct jffs2_raw_node_ref *)f->inocache; + f->inocache->state = INO_STATE_READING; jffs2_add_ino_cache(c, f->inocache); } if (!f->inocache) { printk(KERN_WARNING "jffs2_do_read_inode() on nonexistent ino %u\n", ino); return -ENOENT; } - D1(printk(KERN_DEBUG "jffs2_do_read_inode(): ino #%u nlink is %d\n", ino, f->inocache->nlink)); + + return jffs2_do_read_inode_internal(c, f, latest_node); +} + +int jffs2_do_crccheck_inode(struct jffs2_sb_info *c, struct jffs2_inode_cache *ic) +{ + struct jffs2_raw_inode n; + struct jffs2_inode_info *f = kmalloc(sizeof(*f), GFP_KERNEL); + int ret; + + if (!f) + return -ENOMEM; + + memset(f, 0, sizeof(*f)); + init_MUTEX_LOCKED(&f->sem); + f->inocache = ic; + + ret = jffs2_do_read_inode_internal(c, f, &n); + if (!ret) { + up(&f->sem); + jffs2_do_clear_inode(c, f); + } + kfree (f); + return ret; +} + +static int jffs2_do_read_inode_internal(struct jffs2_sb_info *c, + struct jffs2_inode_info *f, + struct jffs2_raw_inode *latest_node) +{ + struct jffs2_tmp_dnode_info *tn_list, *tn; + struct jffs2_full_dirent *fd_list; + struct jffs2_full_dnode *fn = NULL; + uint32_t crc; + uint32_t latest_mctime, mctime_ver; + uint32_t mdata_ver = 0; + size_t retlen; + int ret; + + D1(printk(KERN_DEBUG "jffs2_do_read_inode_internal(): ino #%u nlink is %d\n", f->inocache->ino, f->inocache->nlink)); /* Grab all nodes relevant to this ino */ - ret = jffs2_get_inode_nodes(c, ino, f, &tn_list, &fd_list, &f->highest_version, &latest_mctime, &mctime_ver); + ret = jffs2_get_inode_nodes(c, f->inocache->ino, f, &tn_list, &fd_list, &f->highest_version, &latest_mctime, &mctime_ver); if (ret) { - printk(KERN_CRIT "jffs2_get_inode_nodes() for ino %u returned %d\n", ino, ret); + printk(KERN_CRIT "jffs2_get_inode_nodes() for ino %u returned %d\n", f->inocache->ino, ret); + if (f->inocache->state == INO_STATE_READING) + jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); return ret; } f->dents = fd_list; @@ -365,13 +459,21 @@ fn = tn->fn; - if (f->metadata && tn->version > mdata_ver) { - D1(printk(KERN_DEBUG "Obsoleting old metadata at 0x%08x\n", ref_offset(f->metadata->raw))); - jffs2_mark_node_obsolete(c, f->metadata->raw); - jffs2_free_full_dnode(f->metadata); - f->metadata = NULL; - - mdata_ver = 0; + if (f->metadata) { + if (tn->version > mdata_ver) { + D1(printk(KERN_DEBUG "Obsoleting old metadata at 0x%08x\n", ref_offset(f->metadata->raw))); + jffs2_mark_node_obsolete(c, f->metadata->raw); + jffs2_free_full_dnode(f->metadata); + f->metadata = NULL; + + mdata_ver = 0; + } else { + D1(printk(KERN_DEBUG "Er. New metadata at 0x%08x with ver %d is actually older than previous %d\n", + ref_offset(f->metadata->raw), tn->version, mdata_ver)); + jffs2_mark_node_obsolete(c, fn->raw); + jffs2_free_full_dnode(fn); + goto next_tn; + } } if (fn->size) { @@ -382,31 +484,36 @@ f->metadata = fn; mdata_ver = tn->version; } + next_tn: tn_list = tn->next; jffs2_free_tmp_dnode_info(tn); } if (!fn) { /* No data nodes for this inode. */ - if (ino != 1) { - printk(KERN_WARNING "jffs2_do_read_inode(): No data nodes found for ino #%u\n", ino); + if (f->inocache->ino != 1) { + printk(KERN_WARNING "jffs2_do_read_inode(): No data nodes found for ino #%u\n", f->inocache->ino); if (!fd_list) { + if (f->inocache->state == INO_STATE_READING) + jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); return -EIO; } printk(KERN_WARNING "jffs2_do_read_inode(): But it has children so we fake some modes for it\n"); } - latest_node->mode = cpu_to_je32(S_IFDIR|S_IRUGO|S_IWUSR|S_IXUGO); + latest_node->mode = cpu_to_jemode(S_IFDIR|S_IRUGO|S_IWUSR|S_IXUGO); latest_node->version = cpu_to_je32(0); latest_node->atime = latest_node->ctime = latest_node->mtime = cpu_to_je32(0); latest_node->isize = cpu_to_je32(0); latest_node->gid = cpu_to_je16(0); latest_node->uid = cpu_to_je16(0); + if (f->inocache->state == INO_STATE_READING) + jffs2_set_inocache_state(c, f->inocache, INO_STATE_PRESENT); return 0; } ret = jffs2_flash_read(c, ref_offset(fn->raw), sizeof(*latest_node), &retlen, (void *)latest_node); if (ret || retlen != sizeof(*latest_node)) { - printk(KERN_NOTICE "MTD read in jffs2_do_read_inode() failed: Returned %d, %ld of %d bytes read\n", - ret, (long)retlen, sizeof(*latest_node)); + printk(KERN_NOTICE "MTD read in jffs2_do_read_inode() failed: Returned %d, %zd of %zd bytes read\n", + ret, retlen, sizeof(*latest_node)); /* FIXME: If this fails, there seems to be a memory leak. Find it. */ up(&f->sem); jffs2_do_clear_inode(c, f); @@ -415,13 +522,13 @@ crc = crc32(0, latest_node, sizeof(*latest_node)-8); if (crc != je32_to_cpu(latest_node->node_crc)) { - printk(KERN_NOTICE "CRC failed for read_inode of inode %u at physical location 0x%x\n", ino, ref_offset(fn->raw)); + printk(KERN_NOTICE "CRC failed for read_inode of inode %u at physical location 0x%x\n", f->inocache->ino, ref_offset(fn->raw)); up(&f->sem); jffs2_do_clear_inode(c, f); return -EIO; } - switch(je32_to_cpu(latest_node->mode) & S_IFMT) { + switch(jemode_to_cpu(latest_node->mode) & S_IFMT) { case S_IFDIR: if (mctime_ver > je32_to_cpu(latest_node->version)) { /* The times in the latest_node are actually older than @@ -447,23 +554,26 @@ case S_IFBLK: case S_IFCHR: - /* Xertain inode types should have only one data node, and it's + /* Certain inode types should have only one data node, and it's kept as the metadata node */ if (f->metadata) { - printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o had metadata node\n", ino, je32_to_cpu(latest_node->mode)); + printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o had metadata node\n", + f->inocache->ino, jemode_to_cpu(latest_node->mode)); up(&f->sem); jffs2_do_clear_inode(c, f); return -EIO; } if (!frag_first(&f->fragtree)) { - printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o has no fragments\n", ino, je32_to_cpu(latest_node->mode)); + printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o has no fragments\n", + f->inocache->ino, jemode_to_cpu(latest_node->mode)); up(&f->sem); jffs2_do_clear_inode(c, f); return -EIO; } /* ASSERT: f->fraglist != NULL */ if (frag_next(frag_first(&f->fragtree))) { - printk(KERN_WARNING "Argh. Special inode #%u with mode 0%o had more than one node\n", ino, je32_to_cpu(latest_node->mode)); + printk(KERN_WARNING "Argh. Special inode #%u with mode 0x%x had more than one node\n", + f->inocache->ino, jemode_to_cpu(latest_node->mode)); /* FIXME: Deal with it - check crc32, check for duplicate node, check times and discard the older one */ up(&f->sem); jffs2_do_clear_inode(c, f); @@ -475,7 +585,8 @@ f->fragtree = RB_ROOT; break; } - f->inocache->state = INO_STATE_PRESENT; + if (f->inocache->state == INO_STATE_READING) + jffs2_set_inocache_state(c, f->inocache, INO_STATE_PRESENT); return 0; } @@ -494,7 +605,7 @@ the nodes are marked obsolete, and jffs2_g_c_pass() won't call iget() for the inode in question. - We also do this to keep the (maybe temporary) BUG() in + We also used to do this to keep the temporary BUG() in jffs2_mark_node_obsolete() from triggering. */ if(deleted) @@ -518,8 +629,8 @@ jffs2_free_full_dirent(fd); } - if (f->inocache) - f->inocache->state = INO_STATE_CHECKEDABSENT; + if (f->inocache && f->inocache->state != INO_STATE_CHECKING) + jffs2_set_inocache_state(c, f->inocache, INO_STATE_CHECKEDABSENT); up(&f->sem); diff -Nru a/fs/jffs2/scan.c b/fs/jffs2/scan.c --- a/fs/jffs2/scan.c Mon Jun 9 23:16:18 2003 +++ b/fs/jffs2/scan.c Mon Jun 9 23:16:18 2003 @@ -7,10 +7,11 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: scan.c,v 1.92 2002/09/09 16:29:08 dwmw2 Exp $ + * $Id: scan.c,v 1.99 2003/04/28 10:17:17 dwmw2 Exp $ * */ #include <linux/kernel.h> +#include <linux/sched.h> #include <linux/slab.h> #include <linux/mtd/mtd.h> #include <linux/pagemap.h> @@ -70,23 +71,21 @@ uint32_t empty_blocks = 0, bad_blocks = 0; unsigned char *flashbuf = NULL; uint32_t buf_size = 0; +#ifndef __ECOS size_t pointlen; - if (!c->blocks) { - printk(KERN_WARNING "EEEK! c->blocks is NULL!\n"); - return -EINVAL; - } if (c->mtd->point) { ret = c->mtd->point (c->mtd, 0, c->mtd->size, &pointlen, &flashbuf); if (!ret && pointlen < c->mtd->size) { /* Don't muck about if it won't let us point to the whole flash */ - D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%x\n", pointlen)); - c->mtd->unpoint(c->mtd, flashbuf); + D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", pointlen)); + c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size); flashbuf = NULL; } if (ret) D1(printk(KERN_DEBUG "MTD point failed %d\n", ret)); } +#endif if (!flashbuf) { /* For NAND it's quicker to read a whole eraseblock at a time, apparently */ @@ -237,9 +236,10 @@ } if (buf_size) kfree(flashbuf); +#ifndef __ECOS else - c->mtd->unpoint(c->mtd, flashbuf); - + c->mtd->unpoint(c->mtd, flashbuf, 0, c->mtd->size); +#endif return 0; } @@ -255,7 +255,7 @@ return ret; } if (retlen < len) { - D1(printk(KERN_WARNING "Read at 0x%x gave only 0x%x bytes\n", ofs, retlen)); + D1(printk(KERN_WARNING "Read at 0x%x gave only 0x%zx bytes\n", ofs, retlen)); return -EIO; } D2(printk(KERN_DEBUG "Read 0x%x bytes from 0x%08x into buf\n", len, ofs)); @@ -366,7 +366,7 @@ prevofs = ofs; if (jeb->offset + c->sector_size < ofs + sizeof(*node)) { - D1(printk(KERN_DEBUG "Fewer than %d bytes left to end of block. (%x+%x<%x+%x) Not reading\n", sizeof(struct jffs2_unknown_node), + D1(printk(KERN_DEBUG "Fewer than %zd bytes left to end of block. (%x+%x<%x+%zx) Not reading\n", sizeof(struct jffs2_unknown_node), jeb->offset, c->sector_size, ofs, sizeof(*node))); DIRTY_SPACE((jeb->offset + c->sector_size)-ofs); break; @@ -374,7 +374,7 @@ if (buf_ofs + buf_len < ofs + sizeof(*node)) { buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs); - D1(printk(KERN_DEBUG "Fewer than %d bytes (node header) left to end of buf. Reading 0x%x at 0x%08x\n", + D1(printk(KERN_DEBUG "Fewer than %zd bytes (node header) left to end of buf. Reading 0x%x at 0x%08x\n", sizeof(struct jffs2_unknown_node), buf_len, ofs)); err = jffs2_fill_scan_buf(c, buf, ofs, buf_len); if (err) @@ -410,8 +410,8 @@ /* Ran off end. */ D1(printk(KERN_DEBUG "Empty flash ends normally at 0x%08x\n", ofs)); - if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) && - !jeb->first_node->next_in_ino && !jeb->dirty_size) + if (buf_ofs == jeb->offset && jeb->used_size == PAD(c->cleanmarker_size) && + c->cleanmarker_size && !jeb->first_node->next_in_ino && !jeb->dirty_size) return BLK_STATE_CLEANMARKER; wasempty = 1; continue; @@ -430,7 +430,7 @@ continue; } if (je16_to_cpu(node->magic) == JFFS2_DIRTY_BITMASK) { - D1(printk(KERN_DEBUG "Empty bitmask at 0x%08x\n", ofs)); + D1(printk(KERN_DEBUG "Dirty bitmask at 0x%08x\n", ofs)); DIRTY_SPACE(4); ofs += 4; continue; @@ -492,7 +492,7 @@ case JFFS2_NODETYPE_INODE: if (buf_ofs + buf_len < ofs + sizeof(struct jffs2_raw_inode)) { buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs); - D1(printk(KERN_DEBUG "Fewer than %d bytes (inode node) left to end of buf. Reading 0x%x at 0x%08x\n", + D1(printk(KERN_DEBUG "Fewer than %zd bytes (inode node) left to end of buf. Reading 0x%x at 0x%08x\n", sizeof(struct jffs2_raw_inode), buf_len, ofs)); err = jffs2_fill_scan_buf(c, buf, ofs, buf_len); if (err) @@ -585,8 +585,8 @@ } - D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, used 0x%08x\n", jeb->offset, - jeb->free_size, jeb->dirty_size, jeb->used_size)); + D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, unchecked 0x%08x, used 0x%08x\n", jeb->offset, + jeb->free_size, jeb->dirty_size, jeb->unchecked_size, jeb->used_size)); /* mark_node_obsolete can add to wasted !! */ if (jeb->wasted_size) { @@ -596,9 +596,10 @@ jeb->wasted_size = 0; } - if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && - !jeb->first_node->next_in_ino && !jeb->dirty_size) + if ((jeb->used_size + jeb->unchecked_size) == PAD(c->cleanmarker_size) && !jeb->dirty_size + && (!jeb->first_node || jeb->first_node->next_in_ino) ) return BLK_STATE_CLEANMARKER; + /* move blocks with max 4 byte dirty space to cleanlist */ else if (!ISDIRTY(c->sector_size - (jeb->used_size + jeb->unchecked_size))) { c->dirty_size -= jeb->dirty_size; diff -Nru a/fs/jffs2/super.c b/fs/jffs2/super.c --- a/fs/jffs2/super.c Mon Jun 9 23:16:09 2003 +++ b/fs/jffs2/super.c Mon Jun 9 23:16:09 2003 @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: super.c,v 1.74 2002/11/12 09:37:39 dwmw2 Exp $ + * $Id: super.c,v 1.79 2003/05/27 22:35:42 dwmw2 Exp $ * */ @@ -23,7 +23,6 @@ #include <linux/jffs2.h> #include <linux/pagemap.h> #include <linux/mtd/mtd.h> -#include <linux/interrupt.h> #include <linux/ctype.h> #include <linux/namei.h> #include "nodelist.h" @@ -53,7 +52,7 @@ if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == SLAB_CTOR_CONSTRUCTOR) { - init_MUTEX(&ei->sem); + init_MUTEX_LOCKED(&ei->sem); inode_init_once(&ei->vfs_inode); } } @@ -101,9 +100,9 @@ return 0; } -static struct super_block * -jffs2_get_sb_mtd(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data, struct mtd_info *mtd) +static struct super_block *jffs2_get_sb_mtd(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data, struct mtd_info *mtd) { struct super_block *sb; struct jffs2_sb_info *c; @@ -153,9 +152,9 @@ return sb; } -static struct super_block * -jffs2_get_sb_mtdnr(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data, int mtdnr) +static struct super_block *jffs2_get_sb_mtdnr(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data, int mtdnr) { struct mtd_info *mtd; @@ -168,9 +167,9 @@ return jffs2_get_sb_mtd(fs_type, flags, dev_name, data, mtd); } -static struct super_block * -jffs2_get_sb(struct file_system_type *fs_type, int flags, - const char *dev_name, void *data) +static struct super_block *jffs2_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, + void *data) { int err; struct nameidata nd; diff -Nru a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c --- a/fs/jffs2/wbuf.c Mon Jun 9 23:16:08 2003 +++ b/fs/jffs2/wbuf.c Mon Jun 9 23:16:08 2003 @@ -7,39 +7,40 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: wbuf.c,v 1.20 2002/11/12 11:33:02 dwmw2 Exp $ - * + some of the dependencies on later MTD NAND code temporarily reverted. + * $Id: wbuf.c,v 1.30 2003/02/19 17:48:49 gleixner Exp $ * */ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/mtd/mtd.h> -#include <linux/interrupt.h> #include <linux/crc32.h> #include <linux/mtd/nand.h> #include "nodelist.h" -/* FIXME duplicated defines in wbuf.c and nand.c - * Constants for out of band layout - */ -#ifndef NAND_BADBLOCK_POS -#define NAND_BADBLOCK_POS 5 -#endif -#ifndef NAND_JFFS2_OOB_BADBPOS -#define NAND_JFFS2_OOB_BADBPOS 5 -#define NAND_JFFS2_OOB8_FSDAPOS 6 -#define NAND_JFFS2_OOB16_FSDAPOS 8 -#define NAND_JFFS2_OOB8_FSDALEN 2 -#define NAND_JFFS2_OOB16_FSDALEN 8 -#endif - /* max. erase failures before we mark a block bad */ #define MAX_ERASE_FAILURES 5 /* two seconds timeout for timed wbuf-flushing */ #define WBUF_FLUSH_TIMEOUT 2 * HZ +#define JFFS2_OOB_ECCPOS0 0 +#define JFFS2_OOB_ECCPOS1 1 +#define JFFS2_OOB_ECCPOS2 2 +#define JFFS2_OOB_ECCPOS3 3 +#define JFFS2_OOB_ECCPOS4 6 +#define JFFS2_OOB_ECCPOS5 7 + +#define NAND_JFFS2_OOB8_FSDAPOS 6 +#define NAND_JFFS2_OOB16_FSDAPOS 8 +#define NAND_JFFS2_OOB8_FSDALEN 2 +#define NAND_JFFS2_OOB16_FSDALEN 8 + +struct nand_oobinfo jffs2_oobinfo = { + useecc: 1, + eccpos: {JFFS2_OOB_ECCPOS0, JFFS2_OOB_ECCPOS1, JFFS2_OOB_ECCPOS2, JFFS2_OOB_ECCPOS3, JFFS2_OOB_ECCPOS4, JFFS2_OOB_ECCPOS5} +}; + static inline void jffs2_refile_wbuf_blocks(struct jffs2_sb_info *c) { struct list_head *this, *next; @@ -178,13 +179,14 @@ /* else jffs2_flash_writev has actually filled in the rest of the buffer for us, and will deal with the node refs etc. later. */ - ret = c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf); + ret = c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf, NULL, &jffs2_oobinfo); if (ret || retlen != c->wbuf_pagesize) { if (ret) printk(KERN_CRIT "jffs2_flush_wbuf(): Write failed with %d\n",ret); else - printk(KERN_CRIT "jffs2_flush_wbuf(): Write was short %d instead of %d\n",retlen,c->wbuf_pagesize); + printk(KERN_CRIT "jffs2_flush_wbuf(): Write was short: %zd instead of %d\n", + retlen, c->wbuf_pagesize); ret = -EIO; /* CHECKME NAND @@ -205,7 +207,7 @@ /* Adjusting free size of next block only, if it's called from fsync ! */ if (pad == 2) { D1(printk(KERN_DEBUG "jffs2_flush_wbuf() adjusting free_size of c->nextblock\n")); - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); if (!c->nextblock) BUG(); /* wbuf_pagesize - wbuf_len is the amount of space that's to be @@ -222,13 +224,13 @@ c->free_size -= (c->wbuf_pagesize - c->wbuf_len); c->nextblock->wasted_size += (c->wbuf_pagesize - c->wbuf_len); c->wasted_size += (c->wbuf_pagesize - c->wbuf_len); - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); } /* Stick any now-obsoleted blocks on the erase_pending_list */ - spin_lock_bh(&c->erase_completion_lock); + spin_lock(&c->erase_completion_lock); jffs2_refile_wbuf_blocks(c); - spin_unlock_bh(&c->erase_completion_lock); + spin_unlock(&c->erase_completion_lock); memset(c->wbuf,0xff,c->wbuf_pagesize); /* adjust write buffer offset, else we get a non contigous write bug */ @@ -394,7 +396,7 @@ outvecs[splitvec].iov_len = split_ofs; /* We did cross a page boundary, so we write some now */ - ret = jffs2_flash_direct_writev(c, outvecs, splitvec+1, outvec_to, &wbuf_retlen); + ret = c->mtd->writev_ecc(c->mtd, outvecs, splitvec+1, outvec_to, &wbuf_retlen, NULL, &jffs2_oobinfo); if (ret < 0 || wbuf_retlen != PAGE_DIV(totlen)) { /* At this point we have no problem, c->wbuf is empty. @@ -442,11 +444,19 @@ } /* - This is the entry for NOR-Flash. We use it also for NAND to flush wbuf + * This is the entry for flash write. + * Check, if we work on NAND FLASH, if so build an iovec and write it via vritev */ int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, const u_char *buf) { - return c->mtd->write(c->mtd, ofs, len, retlen, buf); + struct iovec vecs[1]; + + if (jffs2_can_mark_obsolete(c)) + return c->mtd->write(c->mtd, ofs, len, retlen, buf); + + vecs[0].iov_base = (unsigned char *) buf; + vecs[0].iov_len = len; + return jffs2_flash_writev(c, vecs, 1, ofs, retlen); } /* @@ -459,10 +469,11 @@ /* Read flash */ if (!jffs2_can_mark_obsolete(c)) { - ret = c->mtd->read(c->mtd, ofs, len, retlen, buf); + ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, &jffs2_oobinfo); if ( (ret == -EIO) && (*retlen == len) ) { - printk(KERN_WARNING "mtd->read(0x%x bytes from 0x%llx) returned ECC error\n", len, ofs); + printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx) returned ECC error\n", + len, ofs); /* * We have the raw data without ECC correction in the buffer, maybe * we are lucky and all data or parts are correct. We check the node. @@ -549,7 +560,7 @@ if (retlen < len) { D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB return short read " - "(%d bytes not %d) for block at %08x\n", retlen, len, jeb->offset)); + "(%zd bytes not %d) for block at %08x\n", retlen, len, jeb->offset)); ret = -EIO; goto out; } @@ -593,69 +604,83 @@ return ret; } -int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) +/* +* Scan for a valid cleanmarker and for bad blocks +* For virtual blocks (concatenated physical blocks) check the cleanmarker +* only in the first page of the first physical block, but scan for bad blocks in all +* physical blocks +*/ +int jffs2_check_nand_cleanmarker (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) { struct jffs2_unknown_node n; unsigned char buf[32]; unsigned char *p; - int ret,i; - size_t retlen; - int fsdata_pos,fsdata_len, oob_size, badblock_pos; + int ret, i, cnt, retval = 0; + size_t retlen, offset; + int fsdata_pos, fsdata_len, oob_size, badblock_pos; + offset = jeb->offset; oob_size = c->mtd->oobsize; - switch(c->mtd->ecctype) { - case MTD_ECC_SW: + switch (c->mtd->ecctype) { + case MTD_ECC_SW: fsdata_pos = (c->wbuf_pagesize == 256) ? NAND_JFFS2_OOB8_FSDAPOS : NAND_JFFS2_OOB16_FSDAPOS; fsdata_len = (c->wbuf_pagesize == 256) ? NAND_JFFS2_OOB8_FSDALEN : NAND_JFFS2_OOB16_FSDALEN; badblock_pos = NAND_BADBLOCK_POS; break; default: - D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Invalid ECC type\n")); + D1 (printk (KERN_WARNING "jffs2_write_nand_cleanmarker(): Invalid ECC type\n")); return -EINVAL; - } - - /* - * We read oob data from page 0 and 1 of the block. - * page 0 contains cleanmarker and badblock info - * page 2 contains failure count of this block - */ - ret = c->mtd->read_oob(c->mtd, jeb->offset, oob_size << 1 , &retlen, buf); - - if (ret) { - D1(printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): Read OOB failed %d for block at %08x\n", ret, jeb->offset)); - return ret; - } - if (retlen < (oob_size << 1) ) { - D1(printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): Read OOB return short read (%d bytes not %d) for block at %08x\n", retlen, oob_size << 1 , jeb->offset)); - return -EIO; } - /* Check for bad block marker */ - if (buf[badblock_pos] != 0xff) { - D1(printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): Bad block at %08x\n",jeb->offset)); - return 2; - } - /* Check for failure counter in the second page */ - if (buf[badblock_pos+oob_size] != 0xff) { - D1(printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): Block marked as failed at %08x, fail count:%d\n",jeb->offset,buf[badblock_pos+oob_size])); - return 3; - } + /* Loop through the physical blocks */ + for (cnt = 0; cnt < (c->sector_size / c->mtd->erasesize); cnt++) { + /* + * We read oob data from page 0 and 1 of the block. + * page 0 contains cleanmarker and badblock info + * page 1 contains failure count of this block + */ + ret = c->mtd->read_oob (c->mtd, offset, oob_size << 1, &retlen, buf); - n.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); - n.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER); - n.totlen = cpu_to_je32(8); - p = (unsigned char *) &n; - - for (i = 0; i < fsdata_len; i++) { - if (buf[fsdata_pos+i] != p[i]) { - D2(printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): Cleanmarker node not detected in block at %08x\n", jeb->offset)); - return 1; + if (ret) { + D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Read OOB failed %d for block at %08x\n", ret, jeb->offset)); + return ret; } + if (retlen < (oob_size << 1)) { + D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Read OOB return short read (%zd bytes not %d) for block at %08x\n", retlen, oob_size << 1, jeb->offset)); + return -EIO; + } + + /* Check for bad block marker */ + if (buf[badblock_pos] != 0xff) { + D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Bad block at %08x\n", jeb->offset)); + return 2; + } + + /* Check for failure counter in the second page */ + if (buf[badblock_pos + oob_size] != 0xff) { + D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Block marked as failed at %08x, fail count:%d\n", jeb->offset, buf[badblock_pos + oob_size])); + return 3; + } + + /* Check cleanmarker only on the first physical block */ + if (!cnt) { + n.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK); + n.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER); + n.totlen = cpu_to_je32 (8); + p = (unsigned char *) &n; + + for (i = 0; i < fsdata_len; i++) { + if (buf[fsdata_pos + i] != p[i]) { + D2 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Cleanmarker node not detected in block at %08x\n", jeb->offset)); + retval = 1; + } + } + } + offset += c->mtd->erasesize; } - - return 0; + return retval; } int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb) @@ -686,7 +711,7 @@ return ret; } if (retlen != fsdata_len) { - D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Short write for block at %08x: %d not %d\n", jeb->offset, retlen, fsdata_len)); + D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Short write for block at %08x: %zd not %d\n", jeb->offset, retlen, fsdata_len)); return ret; } return 0; @@ -721,7 +746,7 @@ } if (retlen < oob_size) { - D1(printk(KERN_WARNING "jffs2_nand_read_failcnt(): Read OOB return short read (%d bytes not %d) for block at %08x\n", retlen, oob_size, jeb->offset)); + D1(printk(KERN_WARNING "jffs2_nand_read_failcnt(): Read OOB return short read (%zd bytes not %d) for block at %08x\n", retlen, oob_size, jeb->offset)); return -EIO; } @@ -767,9 +792,8 @@ return ret; } if (retlen != 1) { - D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Short write for block at %08x: %d not 1\n", jeb->offset, retlen)); + D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Short write for block at %08x: %zd not 1\n", jeb->offset, retlen)); return ret; } return 0; } - diff -Nru a/fs/jffs2/write.c b/fs/jffs2/write.c --- a/fs/jffs2/write.c Mon Jun 9 23:16:11 2003 +++ b/fs/jffs2/write.c Mon Jun 9 23:16:11 2003 @@ -7,7 +7,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: write.c,v 1.60 2002/09/09 16:29:08 dwmw2 Exp $ + * $Id: write.c,v 1.65 2003/01/21 18:11:29 dwmw2 Exp $ * */ @@ -47,7 +47,7 @@ ri->nodetype = cpu_to_je16(JFFS2_NODETYPE_INODE); ri->totlen = cpu_to_je32(PAD(sizeof(*ri))); ri->hdr_crc = cpu_to_je32(crc32(0, ri, sizeof(struct jffs2_unknown_node)-4)); - ri->mode = cpu_to_je32(mode); + ri->mode = cpu_to_jemode(mode); f->highest_version = 1; ri->version = cpu_to_je32(f->highest_version); @@ -55,6 +55,7 @@ return 0; } +#if CONFIG_JFFS2_FS_DEBUG > 0 static void writecheck(struct jffs2_sb_info *c, uint32_t ofs) { unsigned char buf[16]; @@ -63,7 +64,7 @@ ret = jffs2_flash_read(c, ofs, 16, &retlen, buf); if (ret || (retlen != 16)) { - D1(printk(KERN_DEBUG "read failed or short in writecheck(). ret %d, retlen %d\n", ret, retlen)); + D1(printk(KERN_DEBUG "read failed or short in writecheck(). ret %d, retlen %zd\n", ret, retlen)); return; } ret = 0; @@ -79,7 +80,7 @@ buf[8], buf[9], buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]); } } - +#endif /* jffs2_write_dnode - given a raw_inode, allocate a full_dnode for it, @@ -105,10 +106,10 @@ vecs[1].iov_base = (unsigned char *)data; vecs[1].iov_len = datalen; - writecheck(c, flash_ofs); + D1(writecheck(c, flash_ofs)); if (je32_to_cpu(ri->totlen) != sizeof(*ri) + datalen) { - printk(KERN_WARNING "jffs2_write_dnode: ri->totlen (0x%08x) != sizeof(*ri) (0x%08x) + datalen (0x%08x)\n", je32_to_cpu(ri->totlen), sizeof(*ri), datalen); + printk(KERN_WARNING "jffs2_write_dnode: ri->totlen (0x%08x) != sizeof(*ri) (0x%08zx) + datalen (0x%08x)\n", je32_to_cpu(ri->totlen), sizeof(*ri), datalen); } raw = jffs2_alloc_raw_node_ref(); if (!raw) @@ -135,7 +136,7 @@ ret = jffs2_flash_writev(c, vecs, cnt, flash_ofs, &retlen); if (ret || (retlen != sizeof(*ri) + datalen)) { - printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %d\n", + printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n", sizeof(*ri)+datalen, flash_ofs, ret, retlen); /* Mark the space as dirtied */ if (retlen) { @@ -162,20 +163,27 @@ return ERR_PTR(ret?ret:-EIO); } /* Mark the space used */ - if (datalen == PAGE_CACHE_SIZE) + /* If node covers at least a whole page, or if it starts at the + beginning of a page and runs to the end of the file, or if + it's a hole node, mark it REF_PRISTINE, else REF_NORMAL. + */ + if ((je32_to_cpu(ri->dsize) >= PAGE_CACHE_SIZE) || + ( ((je32_to_cpu(ri->offset)&(PAGE_CACHE_SIZE-1))==0) && + (je32_to_cpu(ri->dsize)+je32_to_cpu(ri->offset) == je32_to_cpu(ri->isize)))) { raw->flash_offset |= REF_PRISTINE; - else + } else { raw->flash_offset |= REF_NORMAL; + } jffs2_add_physical_node_ref(c, raw); /* Link into per-inode list */ raw->next_in_ino = f->inocache->nodes; f->inocache->nodes = raw; - D1(printk(KERN_DEBUG "jffs2_write_dnode wrote node at 0x%08x with dsize 0x%x, csize 0x%x, node_crc 0x%08x, data_crc 0x%08x, totlen 0x%08x\n", - flash_ofs, je32_to_cpu(ri->dsize), je32_to_cpu(ri->csize), - je32_to_cpu(ri->node_crc), je32_to_cpu(ri->data_crc), - je32_to_cpu(ri->totlen))); + D1(printk(KERN_DEBUG "jffs2_write_dnode wrote node at 0x%08x(%d) with dsize 0x%x, csize 0x%x, node_crc 0x%08x, data_crc 0x%08x, totlen 0x%08x\n", + flash_ofs, ref_flags(raw), je32_to_cpu(ri->dsize), + je32_to_cpu(ri->csize), je32_to_cpu(ri->node_crc), + je32_to_cpu(ri->data_crc), je32_to_cpu(ri->totlen))); if (writelen) *writelen = retlen; @@ -194,7 +202,7 @@ D1(printk(KERN_DEBUG "jffs2_write_dirent(ino #%u, name at *0x%p \"%s\"->ino #%u, name_crc 0x%08x)\n", je32_to_cpu(rd->pino), name, name, je32_to_cpu(rd->ino), je32_to_cpu(rd->name_crc))); - writecheck(c, flash_ofs); + D1(writecheck(c, flash_ofs)); D1(if(je32_to_cpu(rd->hdr_crc) != crc32(0, rd, sizeof(struct jffs2_unknown_node)-4)) { printk(KERN_CRIT "Eep. CRC not correct in jffs2_write_dirent()\n"); @@ -233,7 +241,7 @@ ret = jffs2_flash_writev(c, vecs, 2, flash_ofs, &retlen); if (ret || (retlen != sizeof(*rd) + namelen)) { - printk(KERN_NOTICE "Write of %d bytes at 0x%08x failed. returned %d, retlen %d\n", + printk(KERN_NOTICE "Write of %zd bytes at 0x%08x failed. returned %d, retlen %zd\n", sizeof(*rd)+namelen, flash_ofs, ret, retlen); /* Mark the space as dirtied */ if (retlen) { @@ -290,7 +298,7 @@ } down(&f->sem); datalen = writelen; - cdatalen = min(alloclen - sizeof(*ri), writelen); + cdatalen = min_t(uint32_t, alloclen - sizeof(*ri), writelen); comprbuf = kmalloc(cdatalen, GFP_KERNEL); if (comprbuf) { @@ -392,7 +400,7 @@ fn = jffs2_write_dnode(c, f, ri, NULL, 0, phys_ofs, &writtenlen); D1(printk(KERN_DEBUG "jffs2_do_create created file with mode 0x%x\n", - je32_to_cpu(ri->mode))); + jemode_to_cpu(ri->mode))); if (IS_ERR(fn)) { D1(printk(KERN_DEBUG "jffs2_write_dnode() failed\n")); diff -Nru a/fs/jfs/resize.c b/fs/jfs/resize.c --- a/fs/jfs/resize.c Mon Jun 9 23:16:15 2003 +++ b/fs/jfs/resize.c Mon Jun 9 23:16:15 2003 @@ -1,5 +1,5 @@ /* - * Copyright (c) International Business Machines Corp., 2000-2002 + * Copyright (c) International Business Machines Corp., 2000-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 @@ -348,7 +348,7 @@ /* need to grow map file ? */ if (nPages == newNpages) - goto updateImap; + goto finalizeBmap; /* * grow bmap file for the new map pages required: @@ -414,6 +414,7 @@ if (XSize) goto extendBmap; + finalizeBmap: /* finalize bmap */ dbFinalizeBmap(ipbmap); @@ -427,7 +428,6 @@ * (computation of ag number from agstart based on agsize * will correctly identify the new ag); */ - updateImap: /* if new AG size the same as old AG size, done! */ if (bmp->db_agsize != old_agsize) { if ((rc = diExtendFS(ipimap, ipbmap))) @@ -485,8 +485,8 @@ /* mark extendfs() completion */ j_sb->s_state &= cpu_to_le32(~FM_EXTENDFS); - j_sb->s_size = cpu_to_le64(bmp->db_mapsize) << - le16_to_cpu(j_sb->s_l2bfactor); + j_sb->s_size = cpu_to_le64(bmp->db_mapsize << + le16_to_cpu(j_sb->s_l2bfactor)); j_sb->s_agsize = cpu_to_le32(bmp->db_agsize); /* update inline log space descriptor */ diff -Nru a/fs/jfs/super.c b/fs/jfs/super.c --- a/fs/jfs/super.c Mon Jun 9 23:16:11 2003 +++ b/fs/jfs/super.c Mon Jun 9 23:16:11 2003 @@ -105,10 +105,14 @@ } #ifdef CONFIG_JFS_POSIX_ACL - if (ji->i_acl && (ji->i_acl != JFS_ACL_NOT_CACHED)) + if (ji->i_acl != JFS_ACL_NOT_CACHED) { posix_acl_release(ji->i_acl); - if (ji->i_default_acl && (ji->i_default_acl != JFS_ACL_NOT_CACHED)) + ji->i_acl = JFS_ACL_NOT_CACHED; + } + if (ji->i_default_acl != JFS_ACL_NOT_CACHED) { posix_acl_release(ji->i_default_acl); + ji->i_default_acl = JFS_ACL_NOT_CACHED; + } #endif kmem_cache_free(jfs_inode_cachep, ji); diff -Nru a/fs/libfs.c b/fs/libfs.c --- a/fs/libfs.c Mon Jun 9 23:16:05 2003 +++ b/fs/libfs.c Mon Jun 9 23:16:05 2003 @@ -336,7 +336,7 @@ int simple_fill_super(struct super_block *s, int magic, struct tree_descr *files) { - static struct super_operations s_ops = {statfs:simple_statfs}; + static struct super_operations s_ops = {.statfs = simple_statfs}; struct inode *inode; struct dentry *root; struct dentry *dentry; diff -Nru a/fs/msdos/namei.c b/fs/msdos/namei.c --- a/fs/msdos/namei.c Mon Jun 9 23:16:20 2003 +++ b/fs/msdos/namei.c Mon Jun 9 23:16:20 2003 @@ -112,8 +112,9 @@ } /***** Locates a directory entry. Uses unformatted name. */ -static int msdos_find(struct inode *dir,const char *name,int len, - struct buffer_head **bh,struct msdos_dir_entry **de,int *ino) +static int msdos_find(struct inode *dir, const char *name, int len, + struct buffer_head **bh, struct msdos_dir_entry **de, + loff_t *i_pos) { int res; char dotsOK; @@ -123,7 +124,7 @@ res = msdos_format_name(name,len, msdos_name,&MSDOS_SB(dir->i_sb)->options); if (res < 0) return -ENOENT; - res = fat_scan(dir,msdos_name,bh,de,ino); + res = fat_scan(dir, msdos_name, bh, de, i_pos); if (!res && dotsOK) { if (name[0]=='.') { if (!((*de)->attr & ATTR_HIDDEN)) @@ -134,7 +135,6 @@ } } return res; - } /* @@ -199,19 +199,19 @@ struct inode *inode = NULL; struct msdos_dir_entry *de; struct buffer_head *bh = NULL; - int ino,res; + loff_t i_pos; + int res; dentry->d_op = &msdos_dentry_operations; lock_kernel(); res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &bh, - &de, &ino); - + &de, &i_pos); if (res == -ENOENT) goto add; if (res < 0) goto out; - inode = fat_build_inode(sb, de, ino, &res); + inode = fat_build_inode(sb, de, i_pos, &res); if (res) goto out; add: @@ -231,12 +231,11 @@ static int msdos_add_entry(struct inode *dir, const char *name, struct buffer_head **bh, struct msdos_dir_entry **de, - int *ino, - int is_dir, int is_hid) + loff_t *i_pos, int is_dir, int is_hid) { int res; - res = fat_add_entries(dir, 1, bh, de, ino); + res = fat_add_entries(dir, 1, bh, de, i_pos); if (res < 0) return res; @@ -268,7 +267,8 @@ struct buffer_head *bh; struct msdos_dir_entry *de; struct inode *inode; - int ino,res,is_hid; + loff_t i_pos; + int res, is_hid; char msdos_name[MSDOS_NAME]; lock_kernel(); @@ -280,18 +280,18 @@ } is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.'); /* Have to do it due to foo vs. .foo conflicts */ - if (fat_scan(dir,msdos_name,&bh,&de,&ino) >= 0) { + if (fat_scan(dir, msdos_name, &bh, &de, &i_pos) >= 0) { brelse(bh); unlock_kernel(); return -EINVAL; } inode = NULL; - res = msdos_add_entry(dir, msdos_name, &bh, &de, &ino, 0, is_hid); + res = msdos_add_entry(dir, msdos_name, &bh, &de, &i_pos, 0, is_hid); if (res) { unlock_kernel(); return res; } - inode = fat_build_inode(dir->i_sb, de, ino, &res); + inode = fat_build_inode(dir->i_sb, de, i_pos, &res); brelse(bh); if (!inode) { unlock_kernel(); @@ -308,14 +308,15 @@ int msdos_rmdir(struct inode *dir, struct dentry *dentry) { struct inode *inode = dentry->d_inode; - int res,ino; + loff_t i_pos; + int res; struct buffer_head *bh; struct msdos_dir_entry *de; bh = NULL; lock_kernel(); res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, - &bh, &de, &ino); + &bh, &de, &i_pos); if (res < 0) goto rmdir_done; /* @@ -351,7 +352,7 @@ struct inode *inode; int res,is_hid; char msdos_name[MSDOS_NAME]; - int ino; + loff_t i_pos; lock_kernel(); res = msdos_format_name(dentry->d_name.name,dentry->d_name.len, @@ -362,13 +363,13 @@ } is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.'); /* foo vs .foo situation */ - if (fat_scan(dir,msdos_name,&bh,&de,&ino) >= 0) + if (fat_scan(dir, msdos_name, &bh, &de, &i_pos) >= 0) goto out_exist; - res = msdos_add_entry(dir, msdos_name, &bh, &de, &ino, 1, is_hid); + res = msdos_add_entry(dir, msdos_name, &bh, &de, &i_pos, 1, is_hid); if (res) goto out_unlock; - inode = fat_build_inode(dir->i_sb, de, ino, &res); + inode = fat_build_inode(dir->i_sb, de, i_pos, &res); if (!inode) { brelse(bh); goto out_unlock; @@ -414,14 +415,15 @@ int msdos_unlink( struct inode *dir, struct dentry *dentry) { struct inode *inode = dentry->d_inode; - int res,ino; + loff_t i_pos; + int res; struct buffer_head *bh; struct msdos_dir_entry *de; bh = NULL; lock_kernel(); res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, - &bh, &de, &ino); + &bh, &de, &i_pos); if (res < 0) goto unlink_done; @@ -443,12 +445,12 @@ struct dentry *old_dentry, struct inode *new_dir,char *new_name, struct dentry *new_dentry, struct buffer_head *old_bh, - struct msdos_dir_entry *old_de, int old_ino, int is_hid) + struct msdos_dir_entry *old_de, loff_t old_i_pos, int is_hid) { struct buffer_head *new_bh=NULL,*dotdot_bh=NULL; struct msdos_dir_entry *new_de,*dotdot_de; struct inode *old_inode,*new_inode; - int new_ino,dotdot_ino; + loff_t new_i_pos, dotdot_i_pos; int error; int is_dir; @@ -456,7 +458,8 @@ new_inode = new_dentry->d_inode; is_dir = S_ISDIR(old_inode->i_mode); - if (fat_scan(new_dir,new_name,&new_bh,&new_de,&new_ino)>=0 &&!new_inode) + if (fat_scan(new_dir, new_name, &new_bh, &new_de, &new_i_pos) >= 0 + && !new_inode) goto degenerate_case; if (is_dir) { if (new_inode) { @@ -465,7 +468,7 @@ goto out; } error = fat_scan(old_inode, MSDOS_DOTDOT, &dotdot_bh, - &dotdot_de, &dotdot_ino); + &dotdot_de, &dotdot_i_pos); if (error < 0) { printk(KERN_WARNING "MSDOS: %s/%s, get dotdot failed, ret=%d\n", @@ -476,7 +479,7 @@ } if (!new_bh) { error = msdos_add_entry(new_dir, new_name, &new_bh, &new_de, - &new_ino, is_dir, is_hid); + &new_i_pos, is_dir, is_hid); if (error) goto out; } @@ -489,7 +492,7 @@ old_de->name[0] = DELETED_FLAG; mark_buffer_dirty(old_bh); fat_detach(old_inode); - fat_attach(old_inode, new_ino); + fat_attach(old_inode, new_i_pos); if (is_hid) MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN; else @@ -544,8 +547,8 @@ { struct buffer_head *old_bh; struct msdos_dir_entry *old_de; - int old_ino, error; - int is_hid,old_hid; /* if new file and old file are hidden */ + loff_t old_i_pos; + int error, is_hid, old_hid; /* if new file and old file are hidden */ char old_msdos_name[MSDOS_NAME], new_msdos_name[MSDOS_NAME]; lock_kernel(); @@ -562,13 +565,13 @@ is_hid = (new_dentry->d_name.name[0]=='.') && (new_msdos_name[0]!='.'); old_hid = (old_dentry->d_name.name[0]=='.') && (old_msdos_name[0]!='.'); - error = fat_scan(old_dir, old_msdos_name, &old_bh, &old_de, &old_ino); + error = fat_scan(old_dir, old_msdos_name, &old_bh, &old_de, &old_i_pos); if (error < 0) goto rename_done; error = do_msdos_rename(old_dir, old_msdos_name, old_dentry, new_dir, new_msdos_name, new_dentry, - old_bh, old_de, (ino_t)old_ino, is_hid); + old_bh, old_de, old_i_pos, is_hid); brelse(old_bh); rename_done: diff -Nru a/fs/namei.c b/fs/namei.c --- a/fs/namei.c Mon Jun 9 23:16:09 2003 +++ b/fs/namei.c Mon Jun 9 23:16:09 2003 @@ -1631,7 +1631,9 @@ error = dir->i_op->unlink(dir, dentry); } up(&dentry->d_inode->i_sem); - if (!error) { + + /* We don't d_delete() NFS sillyrenamed files--they still exist. */ + if (!error && !(dentry->d_flags & DCACHE_NFSFS_RENAMED)) { d_delete(dentry); inode_dir_notify(dir, DN_DELETE); } @@ -1671,7 +1673,7 @@ goto slashes; inode = dentry->d_inode; if (inode) - inode = igrab(inode); + atomic_inc(&inode->i_count); error = vfs_unlink(nd.dentry->d_inode, dentry); exit2: dput(dentry); diff -Nru a/fs/namespace.c b/fs/namespace.c --- a/fs/namespace.c Mon Jun 9 23:16:15 2003 +++ b/fs/namespace.c Mon Jun 9 23:16:15 2003 @@ -24,7 +24,7 @@ #include <asm/uaccess.h> extern int __init init_rootfs(void); -extern int __init fs_subsys_init(void); +extern int __init sysfs_init(void); static struct list_head *mount_hashtable; static int hash_mask, hash_bits; @@ -1144,7 +1144,7 @@ d++; i--; } while (i); - fs_subsys_init(); + sysfs_init(); init_rootfs(); init_mount_tree(); } diff -Nru a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c --- a/fs/ncpfs/inode.c Mon Jun 9 23:16:12 2003 +++ b/fs/ncpfs/inode.c Mon Jun 9 23:16:12 2003 @@ -295,9 +295,9 @@ static void ncp_stop_tasks(struct ncp_server *server) { struct sock* sk = server->ncp_sock->sk; - sk->error_report = server->error_report; - sk->data_ready = server->data_ready; - sk->write_space = server->write_space; + sk->sk_error_report = server->error_report; + sk->sk_data_ready = server->data_ready; + sk->sk_write_space = server->write_space; del_timer_sync(&server->timeout_tm); flush_scheduled_work(); } @@ -550,12 +550,12 @@ INIT_LIST_HEAD(&server->tx.requests); init_MUTEX(&server->rcv.creq_sem); - server->tx.creq = NULL; - server->rcv.creq = NULL; - server->data_ready = sock->sk->data_ready; - server->write_space = sock->sk->write_space; - server->error_report = sock->sk->error_report; - sock->sk->user_data = server; + server->tx.creq = NULL; + server->rcv.creq = NULL; + server->data_ready = sock->sk->sk_data_ready; + server->write_space = sock->sk->sk_write_space; + server->error_report = sock->sk->sk_error_report; + sock->sk->sk_user_data = server; init_timer(&server->timeout_tm); #undef NCP_PACKET_SIZE @@ -566,15 +566,15 @@ if (server->packet == NULL) goto out_nls; - sock->sk->data_ready = ncp_tcp_data_ready; - sock->sk->error_report = ncp_tcp_error_report; + sock->sk->sk_data_ready = ncp_tcp_data_ready; + sock->sk->sk_error_report = ncp_tcp_error_report; if (sock->type == SOCK_STREAM) { server->rcv.ptr = (unsigned char*)&server->rcv.buf; server->rcv.len = 10; server->rcv.state = 0; INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc, server); INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc, server); - sock->sk->write_space = ncp_tcp_write_space; + sock->sk->sk_write_space = ncp_tcp_write_space; } else { INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc, server); INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc, server); diff -Nru a/fs/ncpfs/sock.c b/fs/ncpfs/sock.c --- a/fs/ncpfs/sock.c Mon Jun 9 23:16:10 2003 +++ b/fs/ncpfs/sock.c Mon Jun 9 23:16:10 2003 @@ -83,21 +83,21 @@ }; void ncp_tcp_data_ready(struct sock *sk, int len) { - struct ncp_server *server = sk->user_data; + struct ncp_server *server = sk->sk_user_data; server->data_ready(sk, len); schedule_work(&server->rcv.tq); } void ncp_tcp_error_report(struct sock *sk) { - struct ncp_server *server = sk->user_data; + struct ncp_server *server = sk->sk_user_data; server->error_report(sk); schedule_work(&server->rcv.tq); } void ncp_tcp_write_space(struct sock *sk) { - struct ncp_server *server = sk->user_data; + struct ncp_server *server = sk->sk_user_data; /* We do not need any locking: we first set tx.creq, and then we do sendmsg, not vice versa... */ @@ -427,7 +427,7 @@ unsigned int hdrl; result -= 8; - hdrl = sock->sk->family == AF_INET ? 8 : 6; + hdrl = sock->sk->sk_family == AF_INET ? 8 : 6; if (sign_verify_reply(server, ((char*)req->reply_buf) + hdrl, result - hdrl, cpu_to_le32(result), ((char*)req->reply_buf) + result)) { printk(KERN_INFO "ncpfs: Signature violation\n"); result = -EIO; diff -Nru a/fs/nfs/unlink.c b/fs/nfs/unlink.c --- a/fs/nfs/unlink.c Mon Jun 9 23:16:19 2003 +++ b/fs/nfs/unlink.c Mon Jun 9 23:16:19 2003 @@ -150,8 +150,7 @@ /** * nfs_async_unlink - asynchronous unlinking of a file - * @dir: directory in which the file resides. - * @name: name of the file to unlink. + * @dentry: dentry to unlink */ int nfs_async_unlink(struct dentry *dentry) @@ -190,7 +189,7 @@ } /** - * nfs_complete_remove - Initialize completion of the sillydelete + * nfs_complete_unlink - Initialize completion of the sillydelete * @dentry: dentry to delete * * Since we're most likely to be called by dentry_iput(), we diff -Nru a/fs/partitions/mac.c b/fs/partitions/mac.c --- a/fs/partitions/mac.c Mon Jun 9 23:16:08 2003 +++ b/fs/partitions/mac.c Mon Jun 9 23:16:08 2003 @@ -11,7 +11,7 @@ #include "check.h" #include "mac.h" -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC extern void note_bootable_part(dev_t dev, int part, int goodness); #endif @@ -34,7 +34,7 @@ unsigned char *data; int blk, blocks_in_map; unsigned secsize; -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC int found_root = 0; int found_root_goodness = 0; #endif @@ -74,7 +74,7 @@ be32_to_cpu(part->start_block) * (secsize/512), be32_to_cpu(part->block_count) * (secsize/512)); -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC /* * If this is the first bootable partition, tell the * setup code, in case it wants to make this the root. @@ -115,11 +115,11 @@ found_root_goodness = goodness; } } -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_PMAC */ ++slot; } -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC if (found_root_goodness) note_bootable_part(bdev->bd_dev, found_root, found_root_goodness); #endif diff -Nru a/fs/proc/base.c b/fs/proc/base.c --- a/fs/proc/base.c Mon Jun 9 23:16:14 2003 +++ b/fs/proc/base.c Mon Jun 9 23:16:14 2003 @@ -557,7 +557,24 @@ } #endif +static loff_t mem_lseek(struct file * file, loff_t offset, int orig) +{ + switch (orig) { + case 0: + file->f_pos = offset; + break; + case 1: + file->f_pos += offset; + break; + default: + return -EINVAL; + } + force_successful_syscall_return(); + return file->f_pos; +} + static struct file_operations proc_mem_operations = { + .llseek = mem_lseek, .read = mem_read, .write = mem_write, .open = mem_open, diff -Nru a/fs/proc/inode.c b/fs/proc/inode.c --- a/fs/proc/inode.c Mon Jun 9 23:16:18 2003 +++ b/fs/proc/inode.c Mon Jun 9 23:16:18 2003 @@ -61,8 +61,6 @@ struct proc_dir_entry *de; struct task_struct *tsk; - inode->i_state = I_CLEAR; - /* Let go of any associated process */ tsk = PROC_I(inode)->task; if (tsk) @@ -75,6 +73,7 @@ module_put(de->owner); de_put(de); } + clear_inode(inode); } struct vfsmount *proc_mnt; diff -Nru a/fs/proc/kcore.c b/fs/proc/kcore.c --- a/fs/proc/kcore.c Mon Jun 9 23:16:13 2003 +++ b/fs/proc/kcore.c Mon Jun 9 23:16:13 2003 @@ -99,7 +99,12 @@ } #else /* CONFIG_KCORE_AOUT */ -#define KCORE_BASE PAGE_OFFSET +#ifndef kc_vaddr_to_offset +#define kc_vaddr_to_offset(v) ((v) - PAGE_OFFSET) +#endif +#ifndef kc_offset_to_vaddr +#define kc_offset_to_vaddr(o) ((o) + PAGE_OFFSET) +#endif #define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) @@ -112,29 +117,60 @@ void *data; }; +static struct kcore_list *kclist; +static rwlock_t kclist_lock = RW_LOCK_UNLOCKED; + +void +kclist_add(struct kcore_list *new, void *addr, size_t size) +{ + new->addr = (unsigned long)addr; + new->size = size; + + write_lock(&kclist_lock); + new->next = kclist; + kclist = new; + write_unlock(&kclist_lock); +} + +struct kcore_list * +kclist_del(void *addr) +{ + struct kcore_list *m, **p = &kclist; + + write_lock(&kclist_lock); + for (m = *p; m; p = &m->next) { + if (m->addr == (unsigned long)addr) { + *p = m->next; + write_unlock(&kclist_lock); + return m; + } + } + write_unlock(&kclist_lock); + return 0; +} + extern char saved_command_line[]; -static size_t get_kcore_size(int *num_vma, size_t *elf_buflen) +static size_t get_kcore_size(int *nphdr, size_t *elf_buflen) { size_t try, size; - struct vm_struct *m; + struct kcore_list *m; - *num_vma = 0; - size = ((size_t)high_memory - KCORE_BASE + PAGE_SIZE); - if (!vmlist) { - *elf_buflen = PAGE_SIZE; - return (size); - } + *nphdr = 1; /* PT_NOTE */ + size = 0; - for (m=vmlist; m; m=m->next) { - try = (size_t)m->addr + m->size; - if (try > KCORE_BASE + size) - size = try - KCORE_BASE; - *num_vma = *num_vma + 1; + for (m=kclist; m; m=m->next) { + try = kc_vaddr_to_offset((size_t)m->addr + m->size); + if (try > size) + size = try; + *nphdr = *nphdr + 1; } *elf_buflen = sizeof(struct elfhdr) + - (*num_vma + 2)*sizeof(struct elf_phdr) + - 3 * sizeof(struct memelfnote); + (*nphdr + 2)*sizeof(struct elf_phdr) + + 3 * sizeof(struct memelfnote) + + sizeof(struct elf_prstatus) + + sizeof(struct elf_prpsinfo) + + sizeof(struct task_struct); *elf_buflen = PAGE_ALIGN(*elf_buflen); return size + *elf_buflen; } @@ -184,9 +220,9 @@ /* * store an ELF coredump header in the supplied buffer - * num_vma is the number of elements in vmlist + * nphdr is the number of elf_phdr to insert */ -static void elf_kcore_store_hdr(char *bufp, int num_vma, int dataoff) +static void elf_kcore_store_hdr(char *bufp, int nphdr, int dataoff) { struct elf_prstatus prstatus; /* NT_PRSTATUS */ struct elf_prpsinfo prpsinfo; /* NT_PRPSINFO */ @@ -194,7 +230,7 @@ struct elfhdr *elf; struct memelfnote notes[3]; off_t offset = 0; - struct vm_struct *m; + struct kcore_list *m; /* setup ELF header */ elf = (struct elfhdr *) bufp; @@ -214,7 +250,7 @@ elf->e_flags = 0; elf->e_ehsize = sizeof(struct elfhdr); elf->e_phentsize= sizeof(struct elf_phdr); - elf->e_phnum = 2 + num_vma; + elf->e_phnum = nphdr; elf->e_shentsize= 0; elf->e_shnum = 0; elf->e_shstrndx = 0; @@ -232,33 +268,17 @@ nhdr->p_flags = 0; nhdr->p_align = 0; - /* setup ELF PT_LOAD program header for the - * virtual range 0xc0000000 -> high_memory */ - phdr = (struct elf_phdr *) bufp; - bufp += sizeof(struct elf_phdr); - offset += sizeof(struct elf_phdr); - phdr->p_type = PT_LOAD; - phdr->p_flags = PF_R|PF_W|PF_X; - phdr->p_offset = PAGE_OFFSET - KCORE_BASE + dataoff; - phdr->p_vaddr = PAGE_OFFSET; - phdr->p_paddr = __pa(PAGE_OFFSET); - phdr->p_filesz = phdr->p_memsz = ((unsigned long)high_memory - PAGE_OFFSET); - phdr->p_align = PAGE_SIZE; - - /* setup ELF PT_LOAD program header for every vmalloc'd area */ - for (m=vmlist; m; m=m->next) { - if (m->flags & VM_IOREMAP) /* don't dump ioremap'd stuff! (TA) */ - continue; - + /* setup ELF PT_LOAD program header for every area */ + for (m=kclist; m; m=m->next) { phdr = (struct elf_phdr *) bufp; bufp += sizeof(struct elf_phdr); offset += sizeof(struct elf_phdr); phdr->p_type = PT_LOAD; phdr->p_flags = PF_R|PF_W|PF_X; - phdr->p_offset = (size_t)m->addr - KCORE_BASE + dataoff; + phdr->p_offset = kc_vaddr_to_offset(m->addr) + dataoff; phdr->p_vaddr = (size_t)m->addr; - phdr->p_paddr = __pa(m->addr); + phdr->p_paddr = 0; phdr->p_filesz = phdr->p_memsz = m->size; phdr->p_align = PAGE_SIZE; } @@ -294,7 +314,7 @@ strcpy(prpsinfo.pr_fname, "vmlinux"); strncpy(prpsinfo.pr_psargs, saved_command_line, ELF_PRARGSZ); - nhdr->p_filesz = notesize(¬es[1]); + nhdr->p_filesz += notesize(¬es[1]); bufp = storenote(¬es[1], bufp); /* set up the task structure */ @@ -303,7 +323,7 @@ notes[2].datasz = sizeof(struct task_struct); notes[2].data = current; - nhdr->p_filesz = notesize(¬es[2]); + nhdr->p_filesz += notesize(¬es[2]); bufp = storenote(¬es[2], bufp); } /* end elf_kcore_store_hdr() */ @@ -317,13 +337,14 @@ ssize_t acc = 0; size_t size, tsz; size_t elf_buflen; - int num_vma; + int nphdr; unsigned long start; - read_lock(&vmlist_lock); - proc_root_kcore->size = size = get_kcore_size(&num_vma, &elf_buflen); + read_lock(&kclist_lock); + tsz = get_kcore_size(&nphdr, &elf_buflen); + proc_root_kcore->size = size = tsz + elf_buflen; if (buflen == 0 || *fpos >= size) { - read_unlock(&vmlist_lock); + read_unlock(&kclist_lock); return 0; } @@ -340,12 +361,12 @@ tsz = buflen; elf_buf = kmalloc(elf_buflen, GFP_ATOMIC); if (!elf_buf) { - read_unlock(&vmlist_lock); + read_unlock(&kclist_lock); return -ENOMEM; } memset(elf_buf, 0, elf_buflen); - elf_kcore_store_hdr(elf_buf, num_vma, elf_buflen); - read_unlock(&vmlist_lock); + elf_kcore_store_hdr(elf_buf, nphdr, elf_buflen); + read_unlock(&kclist_lock); if (copy_to_user(buffer, elf_buf + *fpos, tsz)) { kfree(elf_buf); return -EFAULT; @@ -360,41 +381,30 @@ if (buflen == 0) return acc; } else - read_unlock(&vmlist_lock); - - /* where page 0 not mapped, write zeros into buffer */ -#if defined (__i386__) || defined (__mc68000__) || defined(__x86_64__) - if (*fpos < PAGE_SIZE + elf_buflen) { - /* work out how much to clear */ - tsz = PAGE_SIZE + elf_buflen - *fpos; - if (buflen < tsz) - tsz = buflen; - - /* write zeros to buffer */ - if (clear_user(buffer, tsz)) - return -EFAULT; - buflen -= tsz; - *fpos += tsz; - buffer += tsz; - acc += tsz; + read_unlock(&kclist_lock); - /* leave now if filled buffer already */ - if (buflen == 0) - return tsz; - } -#endif - /* - * Fill the remainder of the buffer from kernel VM space. - * We said in the ELF header that the data which starts - * at 'elf_buflen' is virtual address KCORE_BASE. --rmk + * Check to see if our file offset matches with any of + * the addresses in the elf_phdr on our list. */ - start = KCORE_BASE + (*fpos - elf_buflen); + start = kc_offset_to_vaddr(*fpos - elf_buflen); if ((tsz = (PAGE_SIZE - (start & ~PAGE_MASK))) > buflen) tsz = buflen; while (buflen) { - if ((start >= VMALLOC_START) && (start < VMALLOC_END)) { + struct kcore_list *m; + + read_lock(&kclist_lock); + for (m=kclist; m; m=m->next) { + if (start >= m->addr && start < (m->addr+m->size)) + break; + } + read_unlock(&kclist_lock); + + if (m == NULL) { + if (clear_user(buffer, tsz)) + return -EFAULT; + } else if ((start >= VMALLOC_START) && (start < VMALLOC_END)) { char * elf_buf; struct vm_struct *m; unsigned long curstart = start; @@ -439,8 +449,7 @@ return -EFAULT; } kfree(elf_buf); - } else if ((start > PAGE_OFFSET) && (start < - (unsigned long)high_memory)) { + } else { if (kern_addr_valid(start)) { if (copy_to_user(buffer, (char *)start, tsz)) return -EFAULT; @@ -448,9 +457,6 @@ if (clear_user(buffer, tsz)) return -EFAULT; } - } else { - if (clear_user(buffer, tsz)) - return -EFAULT; } buflen -= tsz; *fpos += tsz; diff -Nru a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c --- a/fs/proc/proc_misc.c Mon Jun 9 23:16:07 2003 +++ b/fs/proc/proc_misc.c Mon Jun 9 23:16:07 2003 @@ -378,8 +378,23 @@ { int i, len; extern unsigned long total_forks; - u64 jif = get_jiffies_64() - INITIAL_JIFFIES; + u64 jif; unsigned int sum = 0, user = 0, nice = 0, system = 0, idle = 0, iowait = 0; + struct timeval now; + unsigned long seq; + + /* Atomically read jiffies and time of day */ + do { + seq = read_seqbegin(&xtime_lock); + + jif = get_jiffies_64(); + do_gettimeofday(&now); + } while (read_seqretry(&xtime_lock, seq)); + + /* calc # of seconds since boot time */ + jif -= INITIAL_JIFFIES; + jif = ((u64)now.tv_sec * HZ) + (now.tv_usec/(1000000/HZ)) - jif; + do_div(jif, HZ); for (i = 0 ; i < NR_CPUS; i++) { int j; @@ -419,7 +434,6 @@ len += sprintf(page + len, " %u", kstat_irqs(i)); #endif - do_div(jif, HZ); len += sprintf(page + len, "\nctxt %lu\n" "btime %lu\n" @@ -427,7 +441,7 @@ "procs_running %lu\n" "procs_blocked %lu\n", nr_context_switches(), - xtime.tv_sec - (unsigned long) jif, + (unsigned long)jif, total_forks, nr_running(), nr_iowait()); diff -Nru a/fs/proc/proc_tty.c b/fs/proc/proc_tty.c --- a/fs/proc/proc_tty.c Mon Jun 9 23:16:10 2003 +++ b/fs/proc/proc_tty.c Mon Jun 9 23:16:10 2003 @@ -57,8 +57,6 @@ break; case TTY_DRIVER_TYPE_SERIAL: seq_printf(m, "serial"); - if (p->subtype == 2) - seq_printf(m, ":callout"); break; case TTY_DRIVER_TYPE_PTY: if (p->subtype == PTY_TYPE_MASTER) diff -Nru a/fs/reiserfs/file.c b/fs/reiserfs/file.c --- a/fs/reiserfs/file.c Mon Jun 9 23:16:05 2003 +++ b/fs/reiserfs/file.c Mon Jun 9 23:16:05 2003 @@ -736,6 +736,7 @@ struct buffer_head *itembuf=NULL; // Buffer head that contains items that we are going to deal with INITIALIZE_PATH(path); // path to item, that we are going to deal with. __u32 * item=0; // pointer to item we are going to deal with + int item_pos=-1; /* Position in indirect item */ if ( num_pages < 1 ) { @@ -807,7 +808,6 @@ reiserfs_write_lock(inode->i_sb); // We need that for at least search_by_key() for ( i = 0; i < num_pages ; i++ ) { - int item_pos=-1; /* Position in indirect item */ head = page_buffers(prepared_pages[i]); /* For each buffer in the page */ diff -Nru a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c --- a/fs/reiserfs/inode.c Mon Jun 9 23:16:09 2003 +++ b/fs/reiserfs/inode.c Mon Jun 9 23:16:09 2003 @@ -2109,11 +2109,13 @@ * someone else could have locked them and sent them down the * pipe without locking the page */ + bh = head ; do { if (!buffer_uptodate(bh)) { partial = 1; break; } + bh = bh->b_this_page; } while(bh != head); if (!partial) SetPageUptodate(page); diff -Nru a/fs/reiserfs/journal.c b/fs/reiserfs/journal.c --- a/fs/reiserfs/journal.c Mon Jun 9 23:16:14 2003 +++ b/fs/reiserfs/journal.c Mon Jun 9 23:16:14 2003 @@ -1368,10 +1368,10 @@ /* compares description block with commit block. returns 1 if they differ, 0 if they are the same */ static int journal_compare_desc_commit(struct super_block *p_s_sb, struct reiserfs_journal_desc *desc, struct reiserfs_journal_commit *commit) { - if (le32_to_cpu(commit->j_trans_id) != le32_to_cpu(desc->j_trans_id) || - le32_to_cpu(commit->j_len) != le32_to_cpu(desc->j_len) || - le32_to_cpu(commit->j_len) > SB_JOURNAL_TRANS_MAX(p_s_sb) || - le32_to_cpu(commit->j_len) <= 0 + if (get_commit_trans_id (commit) != get_desc_trans_id (desc) || + get_commit_trans_len (commit) != get_desc_trans_len (desc) || + get_commit_trans_len (commit) > SB_JOURNAL_TRANS_MAX(p_s_sb) || + get_commit_trans_len (commit) <= 0 ) { return 1 ; } @@ -1391,18 +1391,18 @@ return 0 ; desc = (struct reiserfs_journal_desc *)d_bh->b_data ; - if (le32_to_cpu(desc->j_len) > 0 && !memcmp(desc->j_magic, JOURNAL_DESC_MAGIC, 8)) { - if (oldest_invalid_trans_id && *oldest_invalid_trans_id && le32_to_cpu(desc->j_trans_id) > *oldest_invalid_trans_id) { + if (get_desc_trans_len(desc) > 0 && !memcmp(get_journal_desc_magic (d_bh), JOURNAL_DESC_MAGIC, 8)) { + if (oldest_invalid_trans_id && *oldest_invalid_trans_id && get_desc_trans_id(desc) > *oldest_invalid_trans_id) { reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-986: transaction " "is valid returning because trans_id %d is greater than " - "oldest_invalid %lu\n", le32_to_cpu(desc->j_trans_id), + "oldest_invalid %lu\n", get_desc_trans_id(desc), *oldest_invalid_trans_id); return 0 ; } - if (newest_mount_id && *newest_mount_id > le32_to_cpu(desc->j_mount_id)) { + if (newest_mount_id && *newest_mount_id > get_desc_mount_id (desc)) { reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1087: transaction " "is valid returning because mount_id %d is less than " - "newest_mount_id %lu\n", desc->j_mount_id, + "newest_mount_id %lu\n", get_desc_mount_id (desc), *newest_mount_id) ; return -1 ; } @@ -1410,7 +1410,7 @@ /* ok, we have a journal description block, lets see if the transaction was valid */ c_bh = journal_bread(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + - ((offset + le32_to_cpu(desc->j_len) + 1) % SB_ONDISK_JOURNAL_SIZE(p_s_sb))) ; + ((offset + get_desc_trans_len(desc) + 1) % SB_ONDISK_JOURNAL_SIZE(p_s_sb))) ; if (!c_bh) return 0 ; commit = (struct reiserfs_journal_commit *)c_bh->b_data ; @@ -1419,21 +1419,21 @@ "journal_transaction_is_valid, commit offset %ld had bad " "time %d or length %d\n", c_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb), - le32_to_cpu(commit->j_trans_id), - le32_to_cpu(commit->j_len)); + get_commit_trans_id (commit), + get_commit_trans_len(commit)); brelse(c_bh) ; if (oldest_invalid_trans_id) - *oldest_invalid_trans_id = le32_to_cpu(desc->j_trans_id) ; + *oldest_invalid_trans_id = get_desc_trans_id(desc) ; reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1004: " "transaction_is_valid setting oldest invalid trans_id " - "to %d\n", le32_to_cpu(desc->j_trans_id)) ; + "to %d\n", get_desc_trans_id(desc)) ; return -1; } brelse(c_bh) ; reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1006: found valid " "transaction start offset %lu, len %d id %d\n", d_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb), - le32_to_cpu(desc->j_len), le32_to_cpu(desc->j_trans_id)) ; + get_desc_trans_len(desc), get_desc_trans_id(desc)) ; return 1 ; } else { return 0 ; @@ -1463,6 +1463,7 @@ struct buffer_head **real_blocks = NULL ; unsigned long trans_offset ; int i; + int trans_half; d_bh = journal_bread(p_s_sb, cur_dblock) ; if (!d_bh) @@ -1472,24 +1473,24 @@ reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1037: " "journal_read_transaction, offset %lu, len %d mount_id %d\n", d_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb), - le32_to_cpu(desc->j_len), le32_to_cpu(desc->j_mount_id)) ; - if (le32_to_cpu(desc->j_trans_id) < oldest_trans_id) { + get_desc_trans_len(desc), get_desc_mount_id(desc)) ; + if (get_desc_trans_id(desc) < oldest_trans_id) { reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1039: " "journal_read_trans skipping because %lu is too old\n", cur_dblock - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb)) ; brelse(d_bh) ; return 1 ; } - if (le32_to_cpu(desc->j_mount_id) != newest_mount_id) { + if (get_desc_mount_id(desc) != newest_mount_id) { reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1146: " "journal_read_trans skipping because %d is != " - "newest_mount_id %lu\n", le32_to_cpu(desc->j_mount_id), + "newest_mount_id %lu\n", get_desc_mount_id(desc), newest_mount_id) ; brelse(d_bh) ; return 1 ; } c_bh = journal_bread(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + - ((trans_offset + le32_to_cpu(desc->j_len) + 1) % + ((trans_offset + get_desc_trans_len(desc) + 1) % SB_ONDISK_JOURNAL_SIZE(p_s_sb))) ; if (!c_bh) { brelse(d_bh) ; @@ -1500,30 +1501,31 @@ reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal_read_transaction, " "commit offset %ld had bad time %d or length %d\n", c_bh->b_blocknr - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb), - le32_to_cpu(commit->j_trans_id), le32_to_cpu(commit->j_len)); + get_commit_trans_id(commit), get_commit_trans_len(commit)); brelse(c_bh) ; brelse(d_bh) ; return 1; } - trans_id = le32_to_cpu(desc->j_trans_id) ; + trans_id = get_desc_trans_id(desc) ; /* now we know we've got a good transaction, and it was inside the valid time ranges */ - log_blocks = reiserfs_kmalloc(le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), GFP_NOFS, p_s_sb) ; - real_blocks = reiserfs_kmalloc(le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), GFP_NOFS, p_s_sb) ; + log_blocks = reiserfs_kmalloc(get_desc_trans_len(desc) * sizeof(struct buffer_head *), GFP_NOFS, p_s_sb) ; + real_blocks = reiserfs_kmalloc(get_desc_trans_len(desc) * sizeof(struct buffer_head *), GFP_NOFS, p_s_sb) ; if (!log_blocks || !real_blocks) { brelse(c_bh) ; brelse(d_bh) ; - reiserfs_kfree(log_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ; - reiserfs_kfree(real_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ; + reiserfs_kfree(log_blocks, get_desc_trans_len(desc) * sizeof(struct buffer_head *), p_s_sb) ; + reiserfs_kfree(real_blocks, get_desc_trans_len(desc) * sizeof(struct buffer_head *), p_s_sb) ; reiserfs_warning("journal-1169: kmalloc failed, unable to mount FS\n") ; return -1 ; } /* get all the buffer heads */ - for(i = 0 ; i < le32_to_cpu(desc->j_len) ; i++) { + trans_half = journal_trans_half (p_s_sb->s_blocksize) ; + for(i = 0 ; i < get_desc_trans_len(desc) ; i++) { log_blocks[i] = journal_getblk(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + (trans_offset + 1 + i) % SB_ONDISK_JOURNAL_SIZE(p_s_sb)); - if (i < JOURNAL_TRANS_HALF) { + if (i < trans_half) { real_blocks[i] = sb_getblk(p_s_sb, le32_to_cpu(desc->j_realblock[i])) ; } else { - real_blocks[i] = sb_getblk(p_s_sb, le32_to_cpu(commit->j_realblock[i - JOURNAL_TRANS_HALF])) ; + real_blocks[i] = sb_getblk(p_s_sb, le32_to_cpu(commit->j_realblock[i - trans_half])) ; } /* make sure we don't try to replay onto log or reserved area */ if (is_block_in_log_or_reserved_area(p_s_sb, real_blocks[i]->b_blocknr)) { @@ -1532,23 +1534,23 @@ brelse_array(real_blocks, i) ; brelse(c_bh) ; brelse(d_bh) ; - reiserfs_kfree(log_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ; - reiserfs_kfree(real_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ; + reiserfs_kfree(log_blocks, get_desc_trans_len(desc) * sizeof(struct buffer_head *), p_s_sb) ; + reiserfs_kfree(real_blocks, get_desc_trans_len(desc) * sizeof(struct buffer_head *), p_s_sb) ; return -1 ; } } /* read in the log blocks, memcpy to the corresponding real block */ - ll_rw_block(READ, le32_to_cpu(desc->j_len), log_blocks) ; - for (i = 0 ; i < le32_to_cpu(desc->j_len) ; i++) { + ll_rw_block(READ, get_desc_trans_len(desc), log_blocks) ; + for (i = 0 ; i < get_desc_trans_len(desc) ; i++) { wait_on_buffer(log_blocks[i]) ; if (!buffer_uptodate(log_blocks[i])) { reiserfs_warning("journal-1212: REPLAY FAILURE fsck required! buffer write failed\n") ; - brelse_array(log_blocks + i, le32_to_cpu(desc->j_len) - i) ; - brelse_array(real_blocks, le32_to_cpu(desc->j_len)) ; + brelse_array(log_blocks + i, get_desc_trans_len(desc) - i) ; + brelse_array(real_blocks, get_desc_trans_len(desc)) ; brelse(c_bh) ; brelse(d_bh) ; - reiserfs_kfree(log_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ; - reiserfs_kfree(real_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ; + reiserfs_kfree(log_blocks, get_desc_trans_len(desc) * sizeof(struct buffer_head *), p_s_sb) ; + reiserfs_kfree(real_blocks, get_desc_trans_len(desc) * sizeof(struct buffer_head *), p_s_sb) ; return -1 ; } memcpy(real_blocks[i]->b_data, log_blocks[i]->b_data, real_blocks[i]->b_size) ; @@ -1556,24 +1558,24 @@ brelse(log_blocks[i]) ; } /* flush out the real blocks */ - for (i = 0 ; i < le32_to_cpu(desc->j_len) ; i++) { + for (i = 0 ; i < get_desc_trans_len(desc) ; i++) { set_buffer_dirty(real_blocks[i]) ; ll_rw_block(WRITE, 1, real_blocks + i) ; } - for (i = 0 ; i < le32_to_cpu(desc->j_len) ; i++) { + for (i = 0 ; i < get_desc_trans_len(desc) ; i++) { wait_on_buffer(real_blocks[i]) ; if (!buffer_uptodate(real_blocks[i])) { reiserfs_warning("journal-1226: REPLAY FAILURE, fsck required! buffer write failed\n") ; - brelse_array(real_blocks + i, le32_to_cpu(desc->j_len) - i) ; + brelse_array(real_blocks + i, get_desc_trans_len(desc) - i) ; brelse(c_bh) ; brelse(d_bh) ; - reiserfs_kfree(log_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ; - reiserfs_kfree(real_blocks, le32_to_cpu(desc->j_len) * sizeof(struct buffer_head *), p_s_sb) ; + reiserfs_kfree(log_blocks, get_desc_trans_len(desc) * sizeof(struct buffer_head *), p_s_sb) ; + reiserfs_kfree(real_blocks, get_desc_trans_len(desc) * sizeof(struct buffer_head *), p_s_sb) ; return -1 ; } brelse(real_blocks[i]) ; } - cur_dblock = SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + ((trans_offset + le32_to_cpu(desc->j_len) + 2) % SB_ONDISK_JOURNAL_SIZE(p_s_sb)) ; + cur_dblock = SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + ((trans_offset + get_desc_trans_len(desc) + 2) % SB_ONDISK_JOURNAL_SIZE(p_s_sb)) ; reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1095: setting journal " "start to offset %ld\n", cur_dblock - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb)) ; @@ -1716,28 +1718,28 @@ if (ret == 1) { desc = (struct reiserfs_journal_desc *)d_bh->b_data ; if (oldest_start == 0) { /* init all oldest_ values */ - oldest_trans_id = le32_to_cpu(desc->j_trans_id) ; + oldest_trans_id = get_desc_trans_id(desc) ; oldest_start = d_bh->b_blocknr ; - newest_mount_id = le32_to_cpu(desc->j_mount_id) ; + newest_mount_id = get_desc_mount_id(desc) ; reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1179: Setting " "oldest_start to offset %lu, trans_id %lu\n", oldest_start - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb), oldest_trans_id) ; - } else if (oldest_trans_id > le32_to_cpu(desc->j_trans_id)) { + } else if (oldest_trans_id > get_desc_trans_id(desc)) { /* one we just read was older */ - oldest_trans_id = le32_to_cpu(desc->j_trans_id) ; + oldest_trans_id = get_desc_trans_id(desc) ; oldest_start = d_bh->b_blocknr ; reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1180: Resetting " "oldest_start to offset %lu, trans_id %lu\n", oldest_start - SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb), oldest_trans_id) ; } - if (newest_mount_id < le32_to_cpu(desc->j_mount_id)) { - newest_mount_id = le32_to_cpu(desc->j_mount_id) ; + if (newest_mount_id < get_desc_mount_id(desc)) { + newest_mount_id = get_desc_mount_id(desc) ; reiserfs_debug(p_s_sb, REISERFS_DEBUG_CODE, "journal-1299: Setting " - "newest_mount_id to %d\n", le32_to_cpu(desc->j_mount_id)); + "newest_mount_id to %d\n", get_desc_mount_id(desc)); } - cur_dblock += le32_to_cpu(desc->j_len) + 2 ; + cur_dblock += get_desc_trans_len(desc) + 2 ; } else { cur_dblock++ ; } @@ -1964,13 +1966,6 @@ struct reiserfs_journal *journal; char b[BDEVNAME_SIZE]; - if (sizeof(struct reiserfs_journal_commit) != 4096 || - sizeof(struct reiserfs_journal_desc) != 4096) { - printk("journal-1249: commit or desc struct not 4096 %Zd %Zd\n", sizeof(struct reiserfs_journal_commit), - sizeof(struct reiserfs_journal_desc)) ; - return 1 ; - } - journal = SB_JOURNAL(p_s_sb) = vmalloc(sizeof (struct reiserfs_journal)) ; if (!journal) { printk("journal-1256: unable to get memory for journal structure\n") ; @@ -1989,6 +1984,16 @@ SB_BMAP_NR(p_s_sb) + 1 : REISERFS_DISK_OFFSET_IN_BYTES / p_s_sb->s_blocksize + 2); + /* Sanity check to see is the standard journal fitting withing first bitmap + (actual for small blocksizes) */ + if ( !SB_ONDISK_JOURNAL_DEVICE( p_s_sb ) && + (SB_JOURNAL_1st_RESERVED_BLOCK(p_s_sb) + SB_ONDISK_JOURNAL_SIZE(p_s_sb) > p_s_sb->s_blocksize * 8) ) { + printk("journal-1393: journal does not fit for area addressed by first of bitmap blocks. " + "It starts at %u and its size is %u. Block size %ld\n", + SB_JOURNAL_1st_RESERVED_BLOCK(p_s_sb), SB_ONDISK_JOURNAL_SIZE(p_s_sb), p_s_sb->s_blocksize) ; + goto free_and_return; + } + if( journal_init_dev( p_s_sb, journal, j_dev_name ) != 0 ) { printk( "sh-462: unable to initialize jornal device\n"); goto free_and_return; @@ -2105,6 +2110,7 @@ SB_JOURNAL(p_s_sb)->j_cnode_free = SB_JOURNAL(p_s_sb)->j_cnode_free_list ? num_cnodes : 0 ; SB_JOURNAL(p_s_sb)->j_cnode_used = 0 ; SB_JOURNAL(p_s_sb)->j_must_wait = 0 ; + init_journal_hash(p_s_sb) ; SB_JOURNAL_LIST(p_s_sb)[0].j_list_bitmap = get_list_bitmap(p_s_sb, SB_JOURNAL_LIST(p_s_sb)) ; if (!(SB_JOURNAL_LIST(p_s_sb)[0].j_list_bitmap)) { @@ -2882,6 +2888,7 @@ int commit_now = flags & COMMIT_NOW ; int wait_on_commit = flags & WAIT ; struct reiserfs_super_block *rs ; + int trans_half ; if (reiserfs_dont_log(th->t_super)) { return 0 ; @@ -2929,16 +2936,16 @@ d_bh = journal_getblk(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + SB_JOURNAL(p_s_sb)->j_start) ; set_buffer_uptodate(d_bh) ; desc = (struct reiserfs_journal_desc *)(d_bh)->b_data ; - memset(desc, 0, sizeof(struct reiserfs_journal_desc)) ; - memcpy(desc->j_magic, JOURNAL_DESC_MAGIC, 8) ; - desc->j_trans_id = cpu_to_le32(SB_JOURNAL(p_s_sb)->j_trans_id) ; + memset(d_bh->b_data, 0, d_bh->b_size) ; + memcpy(get_journal_desc_magic (d_bh), JOURNAL_DESC_MAGIC, 8) ; + set_desc_trans_id(desc, SB_JOURNAL(p_s_sb)->j_trans_id) ; /* setup commit block. Don't write (keep it clean too) this one until after everyone else is written */ c_bh = journal_getblk(p_s_sb, SB_ONDISK_JOURNAL_1st_BLOCK(p_s_sb) + ((SB_JOURNAL(p_s_sb)->j_start + SB_JOURNAL(p_s_sb)->j_len + 1) % SB_ONDISK_JOURNAL_SIZE(p_s_sb))) ; commit = (struct reiserfs_journal_commit *)c_bh->b_data ; - memset(commit, 0, sizeof(struct reiserfs_journal_commit)) ; - commit->j_trans_id = cpu_to_le32(SB_JOURNAL(p_s_sb)->j_trans_id) ; + memset(c_bh->b_data, 0, c_bh->b_size) ; + set_commit_trans_id(commit, SB_JOURNAL(p_s_sb)->j_trans_id) ; set_buffer_uptodate(c_bh) ; /* init this journal list */ @@ -2963,6 +2970,7 @@ /* for each real block, add it to the journal list hash, ** copy into real block index array in the commit or desc block */ + trans_half = journal_trans_half(p_s_sb->s_blocksize) ; for (i = 0, cn = SB_JOURNAL(p_s_sb)->j_first ; cn ; cn = cn->next, i++) { if (test_bit(BH_JDirty, &cn->bh->b_state) ) { jl_cn = get_cnode(p_s_sb) ; @@ -2990,27 +2998,27 @@ jl_cn->bh = cn->bh ; jl_cn->jlist = SB_JOURNAL_LIST(p_s_sb) + SB_JOURNAL_LIST_INDEX(p_s_sb) ; insert_journal_hash(SB_JOURNAL(p_s_sb)->j_list_hash_table, jl_cn) ; - if (i < JOURNAL_TRANS_HALF) { + if (i < trans_half) { desc->j_realblock[i] = cpu_to_le32(cn->bh->b_blocknr) ; } else { - commit->j_realblock[i - JOURNAL_TRANS_HALF] = cpu_to_le32(cn->bh->b_blocknr) ; + commit->j_realblock[i - trans_half] = cpu_to_le32(cn->bh->b_blocknr) ; } } else { i-- ; } } - - desc->j_len = cpu_to_le32(SB_JOURNAL(p_s_sb)->j_len) ; - desc->j_mount_id = cpu_to_le32(SB_JOURNAL(p_s_sb)->j_mount_id) ; - desc->j_trans_id = cpu_to_le32(SB_JOURNAL(p_s_sb)->j_trans_id) ; - commit->j_len = cpu_to_le32(SB_JOURNAL(p_s_sb)->j_len) ; + + set_desc_trans_len(desc, SB_JOURNAL(p_s_sb)->j_len) ; + set_desc_mount_id(desc, SB_JOURNAL(p_s_sb)->j_mount_id) ; + set_desc_trans_id(desc, SB_JOURNAL(p_s_sb)->j_trans_id) ; + set_commit_trans_len(commit, SB_JOURNAL(p_s_sb)->j_len); /* special check in case all buffers in the journal were marked for not logging */ if (SB_JOURNAL(p_s_sb)->j_len == 0) { brelse(d_bh) ; brelse(c_bh) ; unlock_journal(p_s_sb) ; -printk("journal-2020: do_journal_end: BAD desc->j_len is ZERO\n") ; + printk("journal-2020: do_journal_end: BAD desc->j_len is ZERO\n") ; atomic_set(&(SB_JOURNAL(p_s_sb)->j_jlock), 0) ; wake_up(&(SB_JOURNAL(p_s_sb)->j_join_wait)) ; return 0 ; diff -Nru a/fs/reiserfs/prints.c b/fs/reiserfs/prints.c --- a/fs/reiserfs/prints.c Mon Jun 9 23:16:14 2003 +++ b/fs/reiserfs/prints.c Mon Jun 9 23:16:14 2003 @@ -546,12 +546,13 @@ { struct reiserfs_journal_desc * desc; - desc = (struct reiserfs_journal_desc *)(bh->b_data); - if (memcmp(desc->j_magic, JOURNAL_DESC_MAGIC, 8)) + if (memcmp(get_journal_desc_magic (bh), JOURNAL_DESC_MAGIC, 8)) return 1; + desc = (struct reiserfs_journal_desc *)(bh->b_data); printk ("Desc block %llu (j_trans_id %d, j_mount_id %d, j_len %d)", - (unsigned long long)bh->b_blocknr, desc->j_trans_id, desc->j_mount_id, desc->j_len); + (unsigned long long)bh->b_blocknr, get_desc_trans_id (desc), get_desc_mount_id (desc), + get_desc_trans_len (desc)); return 0; } diff -Nru a/fs/reiserfs/super.c b/fs/reiserfs/super.c --- a/fs/reiserfs/super.c Mon Jun 9 23:16:11 2003 +++ b/fs/reiserfs/super.c Mon Jun 9 23:16:11 2003 @@ -23,9 +23,6 @@ #include <linux/buffer_head.h> #include <linux/vfs.h> -#define REISERFS_OLD_BLOCKSIZE 4096 -#define REISERFS_SUPER_MAGIC_STRING_OFFSET_NJ 20 - static struct file_system_type reiserfs_fs_type; const char reiserfs_3_5_magic_string[] = REISERFS_SUPER_MAGIC_STRING; @@ -500,8 +497,11 @@ mount options that have values rather than being toggles. */ typedef struct { char * value; - int bitmask; /* bit which is to be set in mount_options bitmask when this - value is found, 0 is no bits are to be set */ + int setmask; /* bitmask which is to set on mount_options bitmask when this + value is found, 0 is no bits are to be changed. */ + int clrmask; /* bitmask which is to clear on mount_options bitmask when this + value is found, 0 is no bits are to be changed. This is + applied BEFORE setmask */ } arg_desc_t; @@ -511,25 +511,30 @@ char * option_name; int arg_required; /* 0 if argument is not required, not 0 otherwise */ const arg_desc_t * values; /* list of values accepted by an option */ - int bitmask; /* bit which is to be set in mount_options bitmask when this - option is selected, 0 is not bits are to be set */ + int setmask; /* bitmask which is to set on mount_options bitmask when this + value is found, 0 is no bits are to be changed. */ + int clrmask; /* bitmask which is to clear on mount_options bitmask when this + value is found, 0 is no bits are to be changed. This is + applied BEFORE setmask */ } opt_desc_t; /* possible values for "-o block-allocator=" and bits which are to be set in s_mount_opt of reiserfs specific part of in-core super block */ static const arg_desc_t balloc[] = { - {"noborder", REISERFS_NO_BORDER}, - {"no_unhashed_relocation", REISERFS_NO_UNHASHED_RELOCATION}, - {"hashed_relocation", REISERFS_HASHED_RELOCATION}, - {"test4", REISERFS_TEST4}, - {NULL, -1} + {"noborder", 1<<REISERFS_NO_BORDER, 0}, + {"border", 0, 1<<REISERFS_NO_BORDER}, + {"no_unhashed_relocation", 1<<REISERFS_NO_UNHASHED_RELOCATION, 0}, + {"hashed_relocation", 1<<REISERFS_HASHED_RELOCATION, 0}, + {"test4", 1<<REISERFS_TEST4, 0}, + {"notest4", 0, 1<<REISERFS_TEST4}, + {NULL, 0, 0} }; static const arg_desc_t tails[] = { - {"on", REISERFS_LARGETAIL}, - {"off", -1}, - {"small", REISERFS_SMALLTAIL}, - {NULL, 0} + {"on", 1<<REISERFS_LARGETAIL, 1<<REISERFS_SMALLTAIL}, + {"off", 0, (1<<REISERFS_LARGETAIL)|(1<<REISERFS_SMALLTAIL)}, + {"small", 1<<REISERFS_SMALLTAIL, 1<<REISERFS_LARGETAIL}, + {NULL, 0, 0} }; int reiserfs_default_io_size = 128 * 1024; /* Default recommended I/O size is 128k. @@ -571,16 +576,21 @@ /* Ugly special case, probably we should redo options parser so that it can understand several arguments for some options, also so that it can fill several bitfields with option values. */ - reiserfs_parse_alloc_options( s, p + 6); - return 0; + if ( reiserfs_parse_alloc_options( s, p + 6) ) { + return -1; + } else { + return 0; + } } /* for every option in the list */ for (opt = opts; opt->option_name; opt ++) { if (!strncmp (p, opt->option_name, strlen (opt->option_name))) { - if (bit_flags && opt->bitmask != -1) - set_bit (opt->bitmask, bit_flags); + if (bit_flags) { + *bit_flags &= ~opt->clrmask; + *bit_flags |= opt->setmask; + } break; } } @@ -620,7 +630,7 @@ } if (!opt->values) { - /* *opt_arg contains pointer to argument */ + /* *=NULLopt_arg contains pointer to argument */ *opt_arg = p; return opt->arg_required; } @@ -628,8 +638,10 @@ /* values possible for this option are listed in opt->values */ for (arg = opt->values; arg->value; arg ++) { if (!strcmp (p, arg->value)) { - if (bit_flags && arg->bitmask != -1 ) - set_bit (arg->bitmask, bit_flags); + if (bit_flags) { + *bit_flags &= ~arg->clrmask; + *bit_flags |= arg->setmask; + } return opt->arg_required; } } @@ -638,7 +650,6 @@ return -1; } - /* returns 0 if something is wrong in option string, 1 - otherwise */ static int reiserfs_parse_options (struct super_block * s, char * options, /* string given via mount's -o */ unsigned long * mount_options, @@ -652,18 +663,18 @@ char * arg = NULL; char * pos; opt_desc_t opts[] = { - {"tails", 't', tails, -1}, - {"notail", 0, 0, -1}, /* Compatibility stuff, so that -o notail -for old setups still work */ - {"conv", 0, 0, REISERFS_CONVERT}, - {"attrs", 0, 0, REISERFS_ATTRS}, - {"nolog", 0, 0, -1}, - {"replayonly", 0, 0, REPLAYONLY}, - {"block-allocator", 'a', balloc, -1}, - {"resize", 'r', 0, -1}, - {"jdev", 'j', 0, -1}, - {"nolargeio", 'w', 0, -1}, - {NULL, 0, 0, -1} + {"tails", 't', tails, 0, 0}, /* Compatibility stuff, so that -o notail for old setups still work */ + {"notail", 0, 0, 0, (1<<REISERFS_LARGETAIL)|(1<<REISERFS_SMALLTAIL)}, + {"conv", 0, 0, 1<<REISERFS_CONVERT, 0}, + {"attrs", 0, 0, 1<<REISERFS_ATTRS, 0}, + {"noattrs", 0, 0, 0, 1<<REISERFS_ATTRS}, + {"nolog", 0, 0, 0, 0}, /* This is unsupported */ + {"replayonly", 0, 0, 1<<REPLAYONLY, 0}, + {"block-allocator", 'a', balloc, 0, 0}, + {"resize", 'r', 0, 0, 0}, + {"jdev", 'j', 0, 0, 0}, + {"nolargeio", 'w', 0, 0, 0}, + {NULL, 0, 0, 0, 0} }; *blocks = 0; @@ -671,9 +682,6 @@ /* use default configuration: create tails, journaling on, no conversion to newest format */ return 1; - else - /* Drop defaults to zeroes */ - *mount_options = 0; for (pos = options; pos; ) { c = reiserfs_getopt (s, &pos, opts, &arg, mount_options); @@ -695,11 +703,25 @@ } if ( c == 'w' ) { - reiserfs_default_io_size = PAGE_SIZE; + char *p=0; + int val = simple_strtoul (arg, &p, 0); + + if ( *p != '\0') { + printk ("reiserfs_parse_options: non-numeric value %s for nolargeio option\n", arg); + return 0; + } + if ( val ) + reiserfs_default_io_size = PAGE_SIZE; + else + reiserfs_default_io_size = 128 * 1024; } if (c == 'j') { if (arg && *arg && jdev_name) { + if ( *jdev_name ) { //Hm, already assigned? + printk("reiserfs_parse_options: journal device was already specified to be %s\n", *jdev_name); + return 0; + } *jdev_name = arg; } } @@ -731,14 +753,28 @@ struct reiserfs_super_block * rs; struct reiserfs_transaction_handle th ; unsigned long blocks; - unsigned long mount_options; + unsigned long mount_options = REISERFS_SB(s)->s_mount_opt; + unsigned long safe_mask = 0; rs = SB_DISK_SUPER_BLOCK (s); if (!reiserfs_parse_options(s, arg, &mount_options, &blocks, NULL)) return -EINVAL; - handle_attrs( s ); + handle_attrs(s); + + /* Add options that are safe here */ + safe_mask |= 1 << REISERFS_SMALLTAIL; + safe_mask |= 1 << REISERFS_LARGETAIL; + safe_mask |= 1 << REISERFS_NO_BORDER; + safe_mask |= 1 << REISERFS_NO_UNHASHED_RELOCATION; + safe_mask |= 1 << REISERFS_HASHED_RELOCATION; + safe_mask |= 1 << REISERFS_TEST4; + safe_mask |= 1 << REISERFS_ATTRS; + + /* Update the bitmask, taking care to keep + * the bits we're not allowed to change here */ + REISERFS_SB(s)->s_mount_opt = (REISERFS_SB(s)->s_mount_opt & ~safe_mask) | (mount_options & safe_mask); if(blocks) { int rc = reiserfs_resize(s, blocks); diff -Nru a/fs/smbfs/proc.c b/fs/smbfs/proc.c --- a/fs/smbfs/proc.c Mon Jun 9 23:16:07 2003 +++ b/fs/smbfs/proc.c Mon Jun 9 23:16:07 2003 @@ -900,10 +900,10 @@ * Store the server in sock user_data (Only used by sunrpc) */ sk = SOCKET_I(filp->f_dentry->d_inode)->sk; - sk->user_data = server; + sk->sk_user_data = server; /* chain into the data_ready callback */ - server->data_ready = xchg(&sk->data_ready, smb_data_ready); + server->data_ready = xchg(&sk->sk_data_ready, smb_data_ready); /* check if we have an old smbmount that uses seconds for the serverzone */ diff -Nru a/fs/smbfs/sock.c b/fs/smbfs/sock.c --- a/fs/smbfs/sock.c Mon Jun 9 23:16:10 2003 +++ b/fs/smbfs/sock.c Mon Jun 9 23:16:10 2003 @@ -68,7 +68,7 @@ static struct smb_sb_info * server_from_socket(struct socket *socket) { - return socket->sk->user_data; + return socket->sk->sk_user_data; } /* @@ -77,7 +77,7 @@ void smb_data_ready(struct sock *sk, int len) { - struct smb_sb_info *server = server_from_socket(sk->socket); + struct smb_sb_info *server = server_from_socket(sk->sk_socket); void (*data_ready)(struct sock *, int) = server->data_ready; data_ready(sk, len); @@ -117,7 +117,7 @@ struct socket *sock = server_sock(server); VERBOSE("closing socket %p\n", sock); - sock->sk->data_ready = server->data_ready; + sock->sk->sk_data_ready = server->data_ready; server->sock_file = NULL; fput(file); } @@ -226,7 +226,7 @@ sock = server_sock(server); if (!sock) goto out; - if (sock->sk->state != TCP_ESTABLISHED) + if (sock->sk->sk_state != TCP_ESTABLISHED) goto out; if (!server->smb_read) { @@ -290,7 +290,7 @@ sock = server_sock(server); if (!sock) goto out; - if (sock->sk->state != TCP_ESTABLISHED) + if (sock->sk->sk_state != TCP_ESTABLISHED) goto out; fs = get_fs(); @@ -345,7 +345,7 @@ sock = server_sock(server); if (!sock) goto out; - if (sock->sk->state != TCP_ESTABLISHED) + if (sock->sk->sk_state != TCP_ESTABLISHED) goto out; fs = get_fs(); @@ -400,7 +400,7 @@ sock = server_sock(server); if (!sock) goto out; - if (sock->sk->state != TCP_ESTABLISHED) + if (sock->sk->sk_state != TCP_ESTABLISHED) goto out; msg.msg_name = NULL; diff -Nru a/fs/sysfs/bin.c b/fs/sysfs/bin.c --- a/fs/sysfs/bin.c Mon Jun 9 23:16:12 2003 +++ b/fs/sysfs/bin.c Mon Jun 9 23:16:12 2003 @@ -30,10 +30,15 @@ loff_t offs = *off; int ret; - if (offs > size) - return 0; - if (offs + count > size) - count = size - offs; + if (count > PAGE_SIZE) + count = PAGE_SIZE; + + if (size) { + if (offs > size) + return 0; + if (offs + count > size) + count = size - offs; + } ret = fill_read(dentry, buffer, offs, count); if (ret < 0) @@ -41,7 +46,7 @@ count = ret; ret = -EFAULT; - if (copy_to_user(userbuf, buffer + offs, count) != 0) + if (copy_to_user(userbuf, buffer, count) != 0) goto Done; *off = offs + count; @@ -69,19 +74,23 @@ loff_t offs = *off; int ret; - if (offs > size) - return 0; - if (offs + count > size) - count = size - offs; + if (count > PAGE_SIZE) + count = PAGE_SIZE; + if (size) { + if (offs > size) + return 0; + if (offs + count > size) + count = size - offs; + } ret = -EFAULT; - if (copy_from_user(buffer + offs, userbuf, count)) + if (copy_from_user(buffer, userbuf, count)) goto Done; count = flush_write(dentry, buffer, offs, count); if (count > 0) *off = offs + count; - ret = 0; + ret = count; Done: return ret; } @@ -102,7 +111,7 @@ goto Done; error = -ENOMEM; - file->private_data = kmalloc(attr->size, GFP_KERNEL); + file->private_data = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!file->private_data) goto Done; diff -Nru a/fs/sysfs/inode.c b/fs/sysfs/inode.c --- a/fs/sysfs/inode.c Mon Jun 9 23:16:17 2003 +++ b/fs/sysfs/inode.c Mon Jun 9 23:16:17 2003 @@ -60,9 +60,10 @@ Proceed: if (init) error = init(inode); - if (!error) + if (!error) { d_instantiate(dentry, inode); - else + dget(dentry); /* Extra count - pin the dentry in core */ + } else iput(inode); Done: return error; diff -Nru a/fs/vfat/namei.c b/fs/vfat/namei.c --- a/fs/vfat/namei.c Mon Jun 9 23:16:15 2003 +++ b/fs/vfat/namei.c Mon Jun 9 23:16:15 2003 @@ -317,9 +317,10 @@ { struct msdos_dir_entry *de; struct buffer_head *bh = NULL; - int ino,res; + loff_t i_pos; + int res; - res = fat_scan(dir,name,&bh,&de,&ino); + res = fat_scan(dir, name, &bh, &de, &i_pos); brelse(bh); if (res < 0) return -ENOENT; @@ -781,7 +782,7 @@ int res, len; struct msdos_dir_entry *dummy_de; struct buffer_head *dummy_bh; - int dummy_ino; + loff_t dummy_i_pos; dir_slots = (struct msdos_dir_slot *) kmalloc(sizeof(struct msdos_dir_slot) * MSDOS_SLOTS, GFP_KERNEL); @@ -797,7 +798,7 @@ goto cleanup; /* build the empty directory entry of number of slots */ - offset = fat_add_entries(dir, slots, &dummy_bh, &dummy_de, &dummy_ino); + offset = fat_add_entries(dir, slots, &dummy_bh, &dummy_de, &dummy_i_pos); if (offset < 0) { res = offset; goto cleanup; @@ -807,7 +808,7 @@ /* Now create the new entry */ *bh = NULL; for (slot = 0; slot < slots; slot++) { - if (fat_get_entry(dir, &offset, bh, de, &sinfo_out->ino) < 0) { + if (fat_get_entry(dir, &offset, bh, de, &sinfo_out->i_pos) < 0) { res = -EIO; goto cleanup; } @@ -852,7 +853,7 @@ &offset,&sinfo->longname_offset); if (res>0) { sinfo->long_slots = res-1; - if (fat_get_entry(dir,&offset,last_bh,last_de,&sinfo->ino)>=0) + if (fat_get_entry(dir,&offset,last_bh,last_de,&sinfo->i_pos)>=0) return 0; res = -EIO; } @@ -882,7 +883,7 @@ table++; goto error; } - inode = fat_build_inode(dir->i_sb, de, sinfo.ino, &res); + inode = fat_build_inode(dir->i_sb, de, sinfo.i_pos, &res); brelse(bh); if (res) { unlock_kernel(); @@ -926,7 +927,7 @@ unlock_kernel(); return res; } - inode = fat_build_inode(sb, de, sinfo.ino, &res); + inode = fat_build_inode(sb, de, sinfo.i_pos, &res); brelse(bh); if (!inode) { unlock_kernel(); @@ -945,8 +946,8 @@ static void vfat_remove_entry(struct inode *dir,struct vfat_slot_info *sinfo, struct buffer_head *bh, struct msdos_dir_entry *de) { - loff_t offset; - int i,ino; + loff_t offset, i_pos; + int i; /* remove the shortname */ dir->i_mtime = CURRENT_TIME; @@ -958,7 +959,7 @@ /* remove the longname */ offset = sinfo->longname_offset; de = NULL; for (i = sinfo->long_slots; i > 0; --i) { - if (fat_get_entry(dir, &offset, &bh, &de, &ino) < 0) + if (fat_get_entry(dir, &offset, &bh, &de, &i_pos) < 0) continue; de->name[0] = DELETED_FLAG; de->attr = ATTR_NONE; @@ -1040,7 +1041,7 @@ unlock_kernel(); return res; } - inode = fat_build_inode(sb, de, sinfo.ino, &res); + inode = fat_build_inode(sb, de, sinfo.i_pos, &res); if (!inode) goto out; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; @@ -1078,7 +1079,7 @@ { struct buffer_head *old_bh,*new_bh,*dotdot_bh; struct msdos_dir_entry *old_de,*new_de,*dotdot_de; - int dotdot_ino; + loff_t dotdot_i_pos; struct inode *old_inode, *new_inode; int res, is_dir; struct vfat_slot_info old_sinfo,sinfo; @@ -1094,13 +1095,13 @@ is_dir = S_ISDIR(old_inode->i_mode); if (is_dir && (res = fat_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh, - &dotdot_de,&dotdot_ino)) < 0) + &dotdot_de,&dotdot_i_pos)) < 0) goto rename_done; if (new_dentry->d_inode) { res = vfat_find(new_dir,&new_dentry->d_name,&sinfo,&new_bh, &new_de); - if (res < 0 || MSDOS_I(new_inode)->i_location != sinfo.ino) { + if (res < 0 || MSDOS_I(new_inode)->i_pos != sinfo.i_pos) { /* WTF??? Cry and fail. */ printk(KERN_WARNING "vfat_rename: fs corrupted\n"); goto rename_done; @@ -1124,7 +1125,7 @@ vfat_remove_entry(old_dir,&old_sinfo,old_bh,old_de); old_bh=NULL; fat_detach(old_inode); - fat_attach(old_inode, sinfo.ino); + fat_attach(old_inode, sinfo.i_pos); mark_inode_dirty(old_inode); old_dir->i_version++; diff -Nru a/include/asm-alpha/agp_backend.h b/include/asm-alpha/agp_backend.h --- a/include/asm-alpha/agp_backend.h Mon Jun 9 23:16:05 2003 +++ b/include/asm-alpha/agp_backend.h Mon Jun 9 23:16:05 2003 @@ -33,8 +33,8 @@ int (*setup)(alpha_agp_info *); void (*cleanup)(alpha_agp_info *); int (*configure)(alpha_agp_info *); - int (*bind)(alpha_agp_info *, off_t, agp_memory *); - int (*unbind)(alpha_agp_info *, off_t, agp_memory *); + int (*bind)(alpha_agp_info *, off_t, struct agp_memory *); + int (*unbind)(alpha_agp_info *, off_t, struct agp_memory *); unsigned long (*translate)(alpha_agp_info *, dma_addr_t); }; diff -Nru a/include/asm-alpha/bitops.h b/include/asm-alpha/bitops.h --- a/include/asm-alpha/bitops.h Mon Jun 9 23:16:12 2003 +++ b/include/asm-alpha/bitops.h Mon Jun 9 23:16:12 2003 @@ -233,7 +233,7 @@ } static inline int -test_bit(int nr, volatile void * addr) +test_bit(int nr, const volatile void * addr) { return (1UL & (((const int *) addr)[nr >> 5] >> (nr & 31))) != 0UL; } diff -Nru a/include/asm-alpha/bug.h b/include/asm-alpha/bug.h --- a/include/asm-alpha/bug.h Mon Jun 9 23:16:17 2003 +++ b/include/asm-alpha/bug.h Mon Jun 9 23:16:17 2003 @@ -9,6 +9,15 @@ __asm__ __volatile__("call_pal %0 # bugchk\n\t"".long %1\n\t.8byte %2" \ : : "i" (PAL_bugchk), "i"(__LINE__), "i"(__FILE__)) +#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0) + #define PAGE_BUG(page) BUG() + +#define WARN_ON(condition) do { \ + if (unlikely((condition)!=0)) { \ + printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \ + dump_stack(); \ + } \ +} while (0) #endif diff -Nru a/include/asm-alpha/ptrace.h b/include/asm-alpha/ptrace.h --- a/include/asm-alpha/ptrace.h Mon Jun 9 23:16:08 2003 +++ b/include/asm-alpha/ptrace.h Mon Jun 9 23:16:08 2003 @@ -70,6 +70,12 @@ #define user_mode(regs) (((regs)->ps & 8) != 0) #define instruction_pointer(regs) ((regs)->pc) extern void show_regs(struct pt_regs *); + +#define alpha_task_regs(task) \ + ((struct pt_regs *) ((long) (task)->thread_info + 2*PAGE_SIZE) - 1) + +#define force_successful_syscall_return() (alpha_task_regs(current)->r0 = 0) + #endif #endif diff -Nru a/include/asm-alpha/string.h b/include/asm-alpha/string.h --- a/include/asm-alpha/string.h Mon Jun 9 23:16:10 2003 +++ b/include/asm-alpha/string.h Mon Jun 9 23:16:10 2003 @@ -13,6 +13,7 @@ #define __HAVE_ARCH_MEMCPY extern void * memcpy(void *, const void *, size_t); #define __HAVE_ARCH_MEMMOVE +#define __HAVE_ARCH_BCOPY extern void * memmove(void *, const void *, size_t); /* For backward compatibility with modules. Unused otherwise. */ diff -Nru a/include/asm-alpha/thread_info.h b/include/asm-alpha/thread_info.h --- a/include/asm-alpha/thread_info.h Mon Jun 9 23:16:18 2003 +++ b/include/asm-alpha/thread_info.h Mon Jun 9 23:16:18 2003 @@ -51,7 +51,7 @@ /* Thread information allocation. */ #define THREAD_SIZE (2*PAGE_SIZE) -#define alloc_thread_info() \ +#define alloc_thread_info(tsk) \ ((struct thread_info *) __get_free_pages(GFP_KERNEL,1)) #define free_thread_info(ti) free_pages((unsigned long) (ti), 1) #define get_thread_info(ti) get_task_struct((ti)->task) diff -Nru a/include/asm-alpha/uaccess.h b/include/asm-alpha/uaccess.h --- a/include/asm-alpha/uaccess.h Mon Jun 9 23:16:16 2003 +++ b/include/asm-alpha/uaccess.h Mon Jun 9 23:16:16 2003 @@ -340,25 +340,31 @@ * Complex access routines */ +/* This little bit of silliness is to get the GP loaded for a function + that ordinarily wouldn't. Otherwise we could have it done by the macro + directly, which can be optimized the linker. */ +#ifdef MODULE +#define __module_address(sym) "r"(sym), +#define __module_call(ra, arg, sym) "jsr $" #ra ",(%" #arg ")," #sym +#else +#define __module_address(sym) +#define __module_call(ra, arg, sym) "bsr $" #ra "," #sym " !samegp" +#endif + extern void __copy_user(void); extern inline long __copy_tofrom_user_nocheck(void *to, const void *from, long len) { - /* This little bit of silliness is to get the GP loaded for - a function that ordinarily wouldn't. Otherwise we could - have it done by the macro directly, which can be optimized - the linker. */ - register void * pv __asm__("$27") = __copy_user; - register void * __cu_to __asm__("$6") = to; register const void * __cu_from __asm__("$7") = from; register long __cu_len __asm__("$0") = len; __asm__ __volatile__( - "jsr $28,(%3),__copy_user" - : "=r" (__cu_len), "=r" (__cu_from), "=r" (__cu_to), "=r"(pv) - : "0" (__cu_len), "1" (__cu_from), "2" (__cu_to), "3"(pv) + __module_call(28, 3, __copy_user) + : "=r" (__cu_len), "=r" (__cu_from), "=r" (__cu_to) + : __module_address(__copy_user) + "0" (__cu_len), "1" (__cu_from), "2" (__cu_to) : "$1","$2","$3","$4","$5","$28","memory"); return __cu_len; @@ -367,20 +373,8 @@ extern inline long __copy_tofrom_user(void *to, const void *from, long len, const void *validate) { - if (__access_ok((long)validate, len, get_fs())) { - register void * pv __asm__("$27") = __copy_user; - register void * __cu_to __asm__("$6") = to; - register const void * __cu_from __asm__("$7") = from; - register long __cu_len __asm__("$0") = len; - __asm__ __volatile__( - "jsr $28,(%3),__copy_user" - : "=r"(__cu_len), "=r"(__cu_from), "=r"(__cu_to), - "=r" (pv) - : "0" (__cu_len), "1" (__cu_from), "2" (__cu_to), - "3" (pv) - : "$1","$2","$3","$4","$5","$28","memory"); - len = __cu_len; - } + if (__access_ok((long)validate, len, get_fs())) + len = __copy_tofrom_user_nocheck(to, from, len); return len; } @@ -404,18 +398,13 @@ extern inline long __clear_user(void *to, long len) { - /* This little bit of silliness is to get the GP loaded for - a function that ordinarily wouldn't. Otherwise we could - have it done by the macro directly, which can be optimized - the linker. */ - register void * pv __asm__("$27") = __do_clear_user; - register void * __cl_to __asm__("$6") = to; register long __cl_len __asm__("$0") = len; __asm__ __volatile__( - "jsr $28,(%2),__do_clear_user" - : "=r"(__cl_len), "=r"(__cl_to), "=r"(pv) - : "0"(__cl_len), "1"(__cl_to), "2"(pv) + __module_call(28, 2, __do_clear_user) + : "=r"(__cl_len), "=r"(__cl_to) + : __module_address(__do_clear_user) + "0"(__cl_len), "1"(__cl_to) : "$1","$2","$3","$4","$5","$28","memory"); return __cl_len; } @@ -423,19 +412,13 @@ extern inline long clear_user(void *to, long len) { - if (__access_ok((long)to, len, get_fs())) { - register void * pv __asm__("$27") = __do_clear_user; - register void * __cl_to __asm__("$6") = to; - register long __cl_len __asm__("$0") = len; - __asm__ __volatile__( - "jsr $28,(%2),__do_clear_user" - : "=r"(__cl_len), "=r"(__cl_to), "=r"(pv) - : "0"(__cl_len), "1"(__cl_to), "2"(pv) - : "$1","$2","$3","$4","$5","$28","memory"); - len = __cl_len; - } + if (__access_ok((long)to, len, get_fs())) + len = __clear_user(to, len); return len; } + +#undef __module_address +#undef __module_call /* Returns: -EFAULT if exception before terminator, N if the entire buffer filled, else strlen. */ diff -Nru a/include/asm-alpha/unaligned.h b/include/asm-alpha/unaligned.h --- a/include/asm-alpha/unaligned.h Mon Jun 9 23:16:10 2003 +++ b/include/asm-alpha/unaligned.h Mon Jun 9 23:16:10 2003 @@ -14,7 +14,7 @@ * the get/put functions are indeed always optimized, * and that we use the correct sizes. */ -extern void bad_unaligned_access_length(void); +extern void bad_unaligned_access_length(void) __attribute__((noreturn)); /* * EGCS 1.1 knows about arbitrary unaligned loads. Define some diff -Nru a/include/asm-alpha/unistd.h b/include/asm-alpha/unistd.h --- a/include/asm-alpha/unistd.h Mon Jun 9 23:16:10 2003 +++ b/include/asm-alpha/unistd.h Mon Jun 9 23:16:10 2003 @@ -349,7 +349,17 @@ #define __NR_set_tid_address 411 #define __NR_restart_syscall 412 #define __NR_fadvise64 413 -#define NR_SYSCALLS 414 +#define __NR_timer_create 414 +#define __NR_timer_settime 415 +#define __NR_timer_gettime 416 +#define __NR_timer_getoverrun 417 +#define __NR_timer_delete 418 +#define __NR_clock_settime 419 +#define __NR_clock_gettime 420 +#define __NR_clock_getres 421 +#define __NR_clock_nanosleep 422 +#define __NR_semtimedop 423 +#define NR_SYSCALLS 424 #if defined(__GNUC__) diff -Nru a/include/asm-arm/bug.h b/include/asm-arm/bug.h --- a/include/asm-arm/bug.h Mon Jun 9 23:16:05 2003 +++ b/include/asm-arm/bug.h Mon Jun 9 23:16:05 2003 @@ -18,4 +18,13 @@ #endif +#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0) + +#define WARN_ON(condition) do { \ + if (unlikely((condition)!=0)) { \ + printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \ + dump_stack(); \ + } \ +} while (0) + #endif diff -Nru a/include/asm-arm/dma-mapping.h b/include/asm-arm/dma-mapping.h --- a/include/asm-arm/dma-mapping.h Mon Jun 9 23:16:05 2003 +++ b/include/asm-arm/dma-mapping.h Mon Jun 9 23:16:05 2003 @@ -42,12 +42,12 @@ /* * Return whether the given device DMA address mask can be supported * properly. For example, if your device can only drive the low 24-bits - * during PCI bus mastering, then you would pass 0x00ffffff as the mask + * during bus mastering, then you would pass 0x00ffffff as the mask * to this function. */ static inline int dma_supported(struct device *dev, u64 mask) { - return 1; + return dev->dma_mask && *dev->dma_mask != 0; } static inline int dma_set_mask(struct device *dev, u64 dma_mask) @@ -81,14 +81,8 @@ * return the CPU-viewed address, and sets @handle to be the * device-viewed address. */ -static inline void * -dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, int gfp) -{ - if (dev == NULL || dmadev_is_sa1111(dev) || *dev->dma_mask != 0xffffffff) - gfp |= GFP_DMA; - - return consistent_alloc(gfp, size, handle, 0); -} +extern void * +dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, int gfp); /** * dma_free_coherent - free memory allocated by dma_alloc_coherent diff -Nru a/include/asm-arm/hardware.h b/include/asm-arm/hardware.h --- a/include/asm-arm/hardware.h Mon Jun 9 23:16:06 2003 +++ b/include/asm-arm/hardware.h Mon Jun 9 23:16:06 2003 @@ -15,4 +15,13 @@ #include <asm/arch/hardware.h> +#ifndef __ASSEMBLY__ + +struct platform_device; + +extern int platform_add_devices(struct platform_device *, int); +extern int platform_add_device(struct platform_device *); + +#endif + #endif diff -Nru a/include/asm-arm/thread_info.h b/include/asm-arm/thread_info.h --- a/include/asm-arm/thread_info.h Mon Jun 9 23:16:11 2003 +++ b/include/asm-arm/thread_info.h Mon Jun 9 23:16:11 2003 @@ -84,7 +84,7 @@ #define THREAD_SIZE (8192) -extern struct thread_info *alloc_thread_info(void); +extern struct thread_info *alloc_thread_info(struct task_struct *task); extern void free_thread_info(struct thread_info *); #define get_thread_info(ti) get_task_struct((ti)->task) diff -Nru a/include/asm-arm/uaccess.h b/include/asm-arm/uaccess.h --- a/include/asm-arm/uaccess.h Mon Jun 9 23:16:15 2003 +++ b/include/asm-arm/uaccess.h Mon Jun 9 23:16:15 2003 @@ -144,13 +144,13 @@ register int __e asm("r0"); \ switch (sizeof(*(__p))) { \ case 1: \ - __put_user_x(__r1, __p, __e, 1, "r2", "lr"); \ + __put_user_x(__r1, __p, __e, 1, "ip", "lr"); \ break; \ case 2: \ - __put_user_x(__r1, __p, __e, 2, "r2", "lr"); \ + __put_user_x(__r1, __p, __e, 2, "ip", "lr"); \ break; \ case 4: \ - __put_user_x(__r1, __p, __e, 4, "r2", "lr"); \ + __put_user_x(__r1, __p, __e, 4, "ip", "lr"); \ break; \ case 8: \ __put_user_x(__r1, __p, __e, 8, "ip", "lr"); \ diff -Nru a/include/asm-arm26/a.out.h b/include/asm-arm26/a.out.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/a.out.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,38 @@ +#ifndef __ARM_A_OUT_H__ +#define __ARM_A_OUT_H__ + +#include <linux/personality.h> +#include <asm/types.h> + +struct exec +{ + __u32 a_info; /* Use macros N_MAGIC, etc for access */ + __u32 a_text; /* length of text, in bytes */ + __u32 a_data; /* length of data, in bytes */ + __u32 a_bss; /* length of uninitialized data area for file, in bytes */ + __u32 a_syms; /* length of symbol table data in file, in bytes */ + __u32 a_entry; /* start address */ + __u32 a_trsize; /* length of relocation info for text, in bytes */ + __u32 a_drsize; /* length of relocation info for data, in bytes */ +}; + +/* + * This is always the same + */ +#define N_TXTADDR(a) (0x00008000) + +#define N_TRSIZE(a) ((a).a_trsize) +#define N_DRSIZE(a) ((a).a_drsize) +#define N_SYMSIZE(a) ((a).a_syms) + +#define M_ARM 103 + +#ifdef __KERNEL__ +#define STACK_TOP TASK_SIZE +#endif + +#ifndef LIBRARY_START_TEXT +#define LIBRARY_START_TEXT (0x00c00000) +#endif + +#endif /* __A_OUT_GNU_H__ */ diff -Nru a/include/asm-arm26/arch.h b/include/asm-arm26/arch.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/arch.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,62 @@ +/* + * linux/include/asm-arm/mach/arch.h + * + * Copyright (C) 2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * The size of struct machine_desc + * (for assembler code) + * FIXME - I count 45... or is this padding? + */ +#define SIZEOF_MACHINE_DESC 48 + +#ifndef __ASSEMBLY__ + +struct tag; + +struct machine_desc { + int nr; /* arch no FIXME - get rid */ + const char *name; /* architecture name */ + unsigned int param_offset; /* parameter page */ + + unsigned int video_start; /* start of video RAM */ + unsigned int video_end; /* end of video RAM */ + + unsigned int reserve_lp0 :1; /* never has lp0 */ + unsigned int reserve_lp1 :1; /* never has lp1 */ + unsigned int reserve_lp2 :1; /* never has lp2 */ + unsigned int soft_reboot :1; /* soft reboot */ + void (*fixup)(struct machine_desc *, + struct tag *, char **, + struct meminfo *); + void (*map_io)(void);/* IO mapping function */ + void (*init_irq)(void); +}; + +/* + * Set of macros to define architecture features. This is built into + * a table by the linker. + */ +#define MACHINE_START(_type,_name) \ +const struct machine_desc __mach_desc_##_type \ + __attribute__((__section__(".arch.info"))) = { \ + nr: MACH_TYPE_##_type, \ + name: _name, + +#define MAINTAINER(n) + +#define BOOT_PARAMS(_params) \ + param_offset: _params, + +#define INITIRQ(_func) \ + init_irq: _func, + +#define MACHINE_END \ +}; + +#endif diff -Nru a/include/asm-arm26/assembler.h b/include/asm-arm26/assembler.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/assembler.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,106 @@ +/* + * linux/asm/assembler.h + * + * This file contains arm architecture specific defines + * for the different processors. + * + * Do not include any C declarations in this file - it is included by + * assembler source. + */ +#ifndef __ASSEMBLY__ +#error "Only include this from assembly code" +#endif + +/* + * Endian independent macros for shifting bytes within registers. + */ +#define pull lsr +#define push lsl +#define byte(x) (x*8) + +#ifdef __STDC__ +#define LOADREGS(cond, base, reglist...)\ + ldm##cond base,reglist^ + +#define RETINSTR(instr, regs...)\ + instr##s regs +#else +#define LOADREGS(cond, base, reglist...)\ + ldm/**/cond base,reglist^ + +#define RETINSTR(instr, regs...)\ + instr/**/s regs +#endif + +#define MODENOP\ + mov r0, r0 + +#define MODE(savereg,tmpreg,mode) \ + mov savereg, pc; \ + bic tmpreg, savereg, $0x0c000003; \ + orr tmpreg, tmpreg, $mode; \ + teqp tmpreg, $0 + +#define RESTOREMODE(savereg) \ + teqp savereg, $0 + +#define SAVEIRQS(tmpreg) + +#define RESTOREIRQS(tmpreg) + +#define DISABLEIRQS(tmpreg)\ + teqp pc, $0x08000003 + +#define ENABLEIRQS(tmpreg)\ + teqp pc, $0x00000003 + +#define USERMODE(tmpreg)\ + teqp pc, $0x00000000;\ + mov r0, r0 + +#define SVCMODE(tmpreg)\ + teqp pc, $0x00000003;\ + mov r0, r0 + + +/* + * Save the current IRQ state and disable IRQs + * Note that this macro assumes FIQs are enabled, and + * that the processor is in SVC mode. + */ + .macro save_and_disable_irqs, oldcpsr, temp + mov \oldcpsr, pc + orr \temp, \oldcpsr, #0x08000000 + teqp \temp, #0 + .endm + +/* + * Restore interrupt state previously stored in + * a register + * ** Actually do nothing on Arc - hope that the caller uses a MOVS PC soon + * after! + */ + .macro restore_irqs, oldcpsr + @ This be restore_irqs + .endm + +/* + * These two are used to save LR/restore PC over a user-based access. + * The old 26-bit architecture requires that we save lr (R14) + */ + .macro save_lr + str lr, [sp, #-4]! + .endm + + .macro restore_pc + ldmfd sp!, {pc}^ + .endm + +#define USER(x...) \ +9999: x; \ + .section __ex_table,"a"; \ + .align 3; \ + .long 9999b,9001f; \ + .previous + + diff -Nru a/include/asm-arm26/atomic.h b/include/asm-arm26/atomic.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/atomic.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,115 @@ +/* + * linux/include/asm-arm26/atomic.h + * + * Copyright (c) 1996 Russell King. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Changelog: + * 27-06-1996 RMK Created + * 13-04-1997 RMK Made functions atomic! + * 07-12-1997 RMK Upgraded for v2.1. + * 26-08-1998 PJB Added #ifdef __KERNEL__ + * + * FIXME - its probably worth seeing what these compile into... + */ +#ifndef __ASM_ARM_ATOMIC_H +#define __ASM_ARM_ATOMIC_H + +#include <linux/config.h> + +#ifdef CONFIG_SMP +#error SMP is NOT supported +#endif + +typedef struct { volatile int counter; } atomic_t; + +#define ATOMIC_INIT(i) { (i) } + +#ifdef __KERNEL__ +#include <asm/system.h> + +#define atomic_read(v) ((v)->counter) +#define atomic_set(v,i) (((v)->counter) = (i)) + +static inline void atomic_add(int i, volatile atomic_t *v) +{ + unsigned long flags; + + local_irq_save(flags); + v->counter += i; + local_irq_restore(flags); +} + +static inline void atomic_sub(int i, volatile atomic_t *v) +{ + unsigned long flags; + + local_irq_save(flags); + v->counter -= i; + local_irq_restore(flags); +} + +static inline void atomic_inc(volatile atomic_t *v) +{ + unsigned long flags; + + local_irq_save(flags); + v->counter += 1; + local_irq_restore(flags); +} + +static inline void atomic_dec(volatile atomic_t *v) +{ + unsigned long flags; + + local_irq_save(flags); + v->counter -= 1; + local_irq_restore(flags); +} + +static inline int atomic_dec_and_test(volatile atomic_t *v) +{ + unsigned long flags; + int val; + + local_irq_save(flags); + val = v->counter; + v->counter = val -= 1; + local_irq_restore(flags); + + return val == 0; +} + +static inline int atomic_add_negative(int i, volatile atomic_t *v) +{ + unsigned long flags; + int val; + + local_irq_save(flags); + val = v->counter; + v->counter = val += i; + local_irq_restore(flags); + + return val < 0; +} + +static inline void atomic_clear_mask(unsigned long mask, unsigned long *addr) +{ + unsigned long flags; + + local_irq_save(flags); + *addr &= ~mask; + local_irq_restore(flags); +} + +/* Atomic operations are already serializing on ARM */ +#define smp_mb__before_atomic_dec() barrier() +#define smp_mb__after_atomic_dec() barrier() +#define smp_mb__before_atomic_inc() barrier() +#define smp_mb__after_atomic_inc() barrier() + +#endif +#endif diff -Nru a/include/asm-arm26/bitops.h b/include/asm-arm26/bitops.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/bitops.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,349 @@ +/* + * Copyright 1995, Russell King. + * Various bits and pieces copyrights include: + * Linus Torvalds (test_bit). + * Big endian support: Copyright 2001, Nicolas Pitre + * reworked by rmk. + * + * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1). + * + * Please note that the code in this file should never be included + * from user space. Many of these are not implemented in assembler + * since they would be too costly. Also, they require priviledged + * instructions (which are not available from user mode) to ensure + * that they are atomic. + */ + +#ifndef __ASM_ARM_BITOPS_H +#define __ASM_ARM_BITOPS_H + +#ifdef __KERNEL__ + +#include <asm/system.h> + +#define smp_mb__before_clear_bit() do { } while (0) +#define smp_mb__after_clear_bit() do { } while (0) + +/* + * These functions are the basis of our bit ops. + * First, the atomic bitops. + * + * The endian issue for these functions is handled by the macros below. + */ +static inline void +____atomic_set_bit(unsigned int bit, volatile unsigned long *p) +{ + unsigned long flags; + unsigned long mask = 1UL << (bit & 31); + + p += bit >> 5; + + local_irq_save(flags); + *p |= mask; + local_irq_restore(flags); +} + +static inline void +____atomic_clear_bit(unsigned int bit, volatile unsigned long *p) +{ + unsigned long flags; + unsigned long mask = 1UL << (bit & 31); + + p += bit >> 5; + + local_irq_save(flags); + *p &= ~mask; + local_irq_restore(flags); +} + +static inline void +____atomic_change_bit(unsigned int bit, volatile unsigned long *p) +{ + unsigned long flags; + unsigned long mask = 1UL << (bit & 31); + + p += bit >> 5; + + local_irq_save(flags); + *p ^= mask; + local_irq_restore(flags); +} + +static inline int +____atomic_test_and_set_bit(unsigned int bit, volatile unsigned long *p) +{ + unsigned long flags; + unsigned int res; + unsigned long mask = 1UL << (bit & 31); + + p += bit >> 5; + + local_irq_save(flags); + res = *p; + *p = res | mask; + local_irq_restore(flags); + + return res & mask; +} + +static inline int +____atomic_test_and_clear_bit(unsigned int bit, volatile unsigned long *p) +{ + unsigned long flags; + unsigned int res; + unsigned long mask = 1UL << (bit & 31); + + p += bit >> 5; + + local_irq_save(flags); + res = *p; + *p = res & ~mask; + local_irq_restore(flags); + + return res & mask; +} + +static inline int +____atomic_test_and_change_bit_mask(unsigned int bit, volatile unsigned long *p) +{ + unsigned long flags; + unsigned int res; + unsigned long mask = 1UL << (bit & 31); + + p += bit >> 5; + + local_irq_save(flags); + res = *p; + *p = res ^ mask; + local_irq_restore(flags); + + return res & mask; +} + +/* + * Now the non-atomic variants. We let the compiler handle all + * optimisations for these. These are all _native_ endian. + */ +static inline void __set_bit(int nr, volatile unsigned long *p) +{ + p[nr >> 5] |= (1UL << (nr & 31)); +} + +static inline void __clear_bit(int nr, volatile unsigned long *p) +{ + p[nr >> 5] &= ~(1UL << (nr & 31)); +} + +static inline void __change_bit(int nr, volatile unsigned long *p) +{ + p[nr >> 5] ^= (1UL << (nr & 31)); +} + +static inline int __test_and_set_bit(int nr, volatile unsigned long *p) +{ + unsigned long oldval, mask = 1UL << (nr & 31); + + p += nr >> 5; + + oldval = *p; + *p = oldval | mask; + return oldval & mask; +} + +static inline int __test_and_clear_bit(int nr, volatile unsigned long *p) +{ + unsigned long oldval, mask = 1UL << (nr & 31); + + p += nr >> 5; + + oldval = *p; + *p = oldval & ~mask; + + return oldval & mask; +} + +static inline int __test_and_change_bit(int nr, volatile unsigned long *p) +{ + unsigned long oldval, mask = 1UL << (nr & 31); + + p += nr >> 5; + + oldval = *p; + *p = oldval ^ mask; + + return oldval & mask; +} + +/* + * This routine doesn't need to be atomic. + */ +static inline int __test_bit(int nr, const unsigned long * p) +{ + return p[nr >> 5] & (1UL << (nr & 31)); +} + +/* + * A note about Endian-ness. + * ------------------------- + * + * ------------ physical data bus bits ----------- + * D31 ... D24 D23 ... D16 D15 ... D8 D7 ... D0 + * byte 3 byte 2 byte 1 byte 0 + * + * Note that bit 0 is defined to be 32-bit word bit 0, not byte 0 bit 0. + */ + +/* + * Little endian assembly bitops. nr = 0 -> byte 0 bit 0. + */ +extern void _set_bit_le(int nr, volatile unsigned long * p); +extern void _clear_bit_le(int nr, volatile unsigned long * p); +extern void _change_bit_le(int nr, volatile unsigned long * p); +extern int _test_and_set_bit_le(int nr, volatile unsigned long * p); +extern int _test_and_clear_bit_le(int nr, volatile unsigned long * p); +extern int _test_and_change_bit_le(int nr, volatile unsigned long * p); +extern int _find_first_zero_bit_le(void * p, unsigned size); +extern int _find_next_zero_bit_le(void * p, int size, int offset); + +/* + * The __* form of bitops are non-atomic and may be reordered. + */ +#define ATOMIC_BITOP_LE(name,nr,p) \ + (__builtin_constant_p(nr) ? \ + ____atomic_##name(nr, p) : \ + _##name##_le(nr,p)) + +#define ATOMIC_BITOP_BE(name,nr,p) \ + (__builtin_constant_p(nr) ? \ + ____atomic_##name(nr, p) : \ + _##name##_be(nr,p)) + +#define NONATOMIC_BITOP(name,nr,p) \ + (____nonatomic_##name(nr, p)) + +/* + * These are the little endian, atomic definitions. + */ +#define set_bit(nr,p) ATOMIC_BITOP_LE(set_bit,nr,p) +#define clear_bit(nr,p) ATOMIC_BITOP_LE(clear_bit,nr,p) +#define change_bit(nr,p) ATOMIC_BITOP_LE(change_bit,nr,p) +#define test_and_set_bit(nr,p) ATOMIC_BITOP_LE(test_and_set_bit,nr,p) +#define test_and_clear_bit(nr,p) ATOMIC_BITOP_LE(test_and_clear_bit,nr,p) +#define test_and_change_bit(nr,p) ATOMIC_BITOP_LE(test_and_change_bit,nr,p) +#define test_bit(nr,p) __test_bit(nr,p) +#define find_first_zero_bit(p,sz) _find_first_zero_bit_le(p,sz) +#define find_next_zero_bit(p,sz,off) _find_next_zero_bit_le(p,sz,off) + +#define WORD_BITOFF_TO_LE(x) ((x)) + +/* + * ffz = Find First Zero in word. Undefined if no zero exists, + * so code should check against ~0UL first.. + */ +static inline unsigned long ffz(unsigned long word) +{ + int k; + + word = ~word; + k = 31; + if (word & 0x0000ffff) { k -= 16; word <<= 16; } + if (word & 0x00ff0000) { k -= 8; word <<= 8; } + if (word & 0x0f000000) { k -= 4; word <<= 4; } + if (word & 0x30000000) { k -= 2; word <<= 2; } + if (word & 0x40000000) { k -= 1; } + return k; +} + +/* + * ffz = Find First Zero in word. Undefined if no zero exists, + * so code should check against ~0UL first.. + */ +static inline unsigned long __ffs(unsigned long word) +{ + int k; + + k = 31; + if (word & 0x0000ffff) { k -= 16; word <<= 16; } + if (word & 0x00ff0000) { k -= 8; word <<= 8; } + if (word & 0x0f000000) { k -= 4; word <<= 4; } + if (word & 0x30000000) { k -= 2; word <<= 2; } + if (word & 0x40000000) { k -= 1; } + return k; +} + +/* + * fls: find last bit set. + */ + +#define fls(x) generic_fls(x) + +/* + * ffs: find first bit set. This is defined the same way as + * the libc and compiler builtin ffs routines, therefore + * differs in spirit from the above ffz (man ffs). + */ + +#define ffs(x) generic_ffs(x) + +/* + * Find first bit set in a 168-bit bitmap, where the first + * 128 bits are unlikely to be set. + */ +static inline int sched_find_first_bit(unsigned long *b) +{ + unsigned long v; + unsigned int off; + + for (off = 0; v = b[off], off < 4; off++) { + if (unlikely(v)) + break; + } + return __ffs(v) + off * 32; +} + +/* + * hweightN: returns the hamming weight (i.e. the number + * of bits set) of a N-bit word + */ + +#define hweight32(x) generic_hweight32(x) +#define hweight16(x) generic_hweight16(x) +#define hweight8(x) generic_hweight8(x) + +/* + * Ext2 is defined to use little-endian byte ordering. + * These do not need to be atomic. + */ +#define ext2_set_bit(nr,p) \ + __test_and_set_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)p) +#define ext2_set_bit_atomic(lock,nr,p) \ + test_and_set_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p)) +#define ext2_clear_bit(nr,p) \ + __test_and_clear_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)p) +#define ext2_clear_bit_atomic(lock,nr,p) \ + test_and_clear_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)(p)) +#define ext2_test_bit(nr,p) \ + __test_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)p) +#define ext2_find_first_zero_bit(p,sz) \ + _find_first_zero_bit_le(p,sz) +#define ext2_find_next_zero_bit(p,sz,off) \ + _find_next_zero_bit_le(p,sz,off) + +/* + * Minix is defined to use little-endian byte ordering. + * These do not need to be atomic. + */ +#define minix_set_bit(nr,p) \ + __set_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)p) +#define minix_test_bit(nr,p) \ + __test_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)p) +#define minix_test_and_set_bit(nr,p) \ + __test_and_set_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)p) +#define minix_test_and_clear_bit(nr,p) \ + __test_and_clear_bit(WORD_BITOFF_TO_LE(nr), (unsigned long *)p) +#define minix_find_first_zero_bit(p,sz) \ + _find_first_zero_bit_le(p,sz) + +#endif /* __KERNEL__ */ + +#endif /* _ARM_BITOPS_H */ diff -Nru a/include/asm-arm26/bug.h b/include/asm-arm26/bug.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/bug.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,21 @@ +#ifndef _ASMARM_BUG_H +#define _ASMARM_BUG_H + +#include <linux/config.h> + +#ifdef CONFIG_DEBUG_BUGVERBOSE +extern void __bug(const char *file, int line, void *data); + +/* give file/line information */ +#define BUG() __bug(__FILE__, __LINE__, NULL) +#define PAGE_BUG(page) __bug(__FILE__, __LINE__, page) + +#else + +/* these just cause an oops */ +#define BUG() (*(int *)0 = 0) +#define PAGE_BUG(page) (*(int *)0 = 0) + +#endif + +#endif diff -Nru a/include/asm-arm26/bugs.h b/include/asm-arm26/bugs.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/bugs.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,15 @@ +/* + * linux/include/asm-arm/bugs.h + * + * Copyright (C) 1995 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_BUGS_H +#define __ASM_BUGS_H + +#define check_bugs() cpu_check_bugs() + +#endif diff -Nru a/include/asm-arm26/byteorder.h b/include/asm-arm26/byteorder.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/byteorder.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,24 @@ +/* + * linux/include/asm-arm/byteorder.h + * + * ARM Endian-ness. In little endian mode, the data bus is connected such + * that byte accesses appear as: + * 0 = d0...d7, 1 = d8...d15, 2 = d16...d23, 3 = d24...d31 + * and word accesses (data or instruction) appear as: + * d0...d31 + * + */ +#ifndef __ASM_ARM_BYTEORDER_H +#define __ASM_ARM_BYTEORDER_H + +#include <asm/types.h> + +#if !defined(__STRICT_ANSI__) || defined(__KERNEL__) +# define __BYTEORDER_HAS_U64__ +# define __SWAB_64_THRU_32__ +#endif + +#include <linux/byteorder/little_endian.h> + +#endif + diff -Nru a/include/asm-arm26/cache.h b/include/asm-arm26/cache.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/cache.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,19 @@ +/* + * linux/include/asm-arm26/cache.h + */ +#ifndef __ASMARM_CACHE_H +#define __ASMARM_CACHE_H + +#define L1_CACHE_BYTES 32 +#define L1_CACHE_ALIGN(x) (((x)+(L1_CACHE_BYTES-1))&~(L1_CACHE_BYTES-1)) +#define SMP_CACHE_BYTES L1_CACHE_BYTES + +#ifdef MODULE +#define __cacheline_aligned __attribute__((__aligned__(L1_CACHE_BYTES))) +#else +#define __cacheline_aligned \ + __attribute__((__aligned__(L1_CACHE_BYTES), \ + __section__(".data.cacheline_aligned"))) +#endif + +#endif diff -Nru a/include/asm-arm26/cacheflush.h b/include/asm-arm26/cacheflush.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/cacheflush.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,44 @@ +/* + * linux/include/asm-arm/cacheflush.h + * + * Copyright (C) 2000-2002 Russell King + * Copyright (C) 2003 Ian Molton + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * ARM26 cache 'functions' + * + */ + +#ifndef _ASMARM_CACHEFLUSH_H +#define _ASMARM_CACHEFLUSH_H + +#if 1 //FIXME - BAD INCLUDES!!! +#include <linux/sched.h> +#include <linux/mm.h> +#endif + +#define flush_cache_all() do { } while (0) +#define flush_cache_mm(mm) do { } while (0) +#define flush_cache_range(vma,start,end) do { } while (0) +#define flush_cache_page(vma,vmaddr) do { } while (0) +#define flush_page_to_ram(page) do { } while (0) + +#define invalidate_dcache_range(start,end) do { } while (0) +#define clean_dcache_range(start,end) do { } while (0) +#define flush_dcache_range(start,end) do { } while (0) +#define flush_dcache_page(page) do { } while (0) +#define clean_dcache_entry(_s) do { } while (0) +#define clean_cache_entry(_start) do { } while (0) + +#define flush_icache_user_range(start,end, bob, fred) do { } while (0) +#define flush_icache_range(start,end) do { } while (0) +#define flush_icache_page(vma,page) do { } while (0) + +/* DAG: ARM3 will flush cache on MEMC updates anyway? so don't bother */ +/* IM : Yes, it will, but only if setup to do so (we do this). */ +#define clean_cache_area(_start,_size) do { } while (0) + +#endif diff -Nru a/include/asm-arm26/calls.h b/include/asm-arm26/calls.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/calls.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,262 @@ +/* + * linux/arch/arm26/lib/calls.h + * + * Copyright (C) 2003 Ian Molton + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * FIXME + * This file is included twice in entry-common.S which may not be necessary + */ +#ifndef NR_syscalls +#define NR_syscalls 256 +#else + +__syscall_start: +/* 0 */ .long sys_ni_syscall + .long sys_exit + .long sys_fork_wrapper + .long sys_read + .long sys_write +/* 5 */ .long sys_open + .long sys_close + .long sys_ni_syscall /* was sys_waitpid */ + .long sys_creat + .long sys_link +/* 10 */ .long sys_unlink + .long sys_execve_wrapper + .long sys_chdir + .long sys_time /* used by libc4 */ + .long sys_mknod +/* 15 */ .long sys_chmod + .long sys_lchown16 + .long sys_ni_syscall /* was sys_break */ + .long sys_ni_syscall /* was sys_stat */ + .long sys_lseek +/* 20 */ .long sys_getpid + .long sys_mount + .long sys_oldumount /* used by libc4 */ + .long sys_setuid16 + .long sys_getuid16 +/* 25 */ .long sys_stime + .long sys_ptrace + .long sys_alarm /* used by libc4 */ + .long sys_ni_syscall /* was sys_fstat */ + .long sys_pause +/* 30 */ .long sys_utime /* used by libc4 */ + .long sys_ni_syscall /* was sys_stty */ + .long sys_ni_syscall /* was sys_getty */ + .long sys_access + .long sys_nice +/* 35 */ .long sys_ni_syscall /* was sys_ftime */ + .long sys_sync + .long sys_kill + .long sys_rename + .long sys_mkdir +/* 40 */ .long sys_rmdir + .long sys_dup + .long sys_pipe + .long sys_times + .long sys_ni_syscall /* was sys_prof */ +/* 45 */ .long sys_brk + .long sys_setgid16 + .long sys_getgid16 + .long sys_ni_syscall /* was sys_signal */ + .long sys_geteuid16 +/* 50 */ .long sys_getegid16 + .long sys_acct + .long sys_umount + .long sys_ni_syscall /* was sys_lock */ + .long sys_ioctl +/* 55 */ .long sys_fcntl + .long sys_ni_syscall /* was sys_mpx */ + .long sys_setpgid + .long sys_ni_syscall /* was sys_ulimit */ + .long sys_ni_syscall /* was sys_olduname */ +/* 60 */ .long sys_umask + .long sys_chroot + .long sys_ustat + .long sys_dup2 + .long sys_getppid +/* 65 */ .long sys_getpgrp + .long sys_setsid + .long sys_sigaction + .long sys_ni_syscall /* was sys_sgetmask */ + .long sys_ni_syscall /* was sys_ssetmask */ +/* 70 */ .long sys_setreuid16 + .long sys_setregid16 + .long sys_sigsuspend_wrapper + .long sys_sigpending + .long sys_sethostname +/* 75 */ .long sys_setrlimit + .long sys_old_getrlimit /* used by libc4 */ + .long sys_getrusage + .long sys_gettimeofday + .long sys_settimeofday +/* 80 */ .long sys_getgroups16 + .long sys_setgroups16 + .long old_select /* used by libc4 */ + .long sys_symlink + .long sys_ni_syscall /* was sys_lstat */ +/* 85 */ .long sys_readlink + .long sys_uselib + .long sys_swapon + .long sys_reboot + .long old_readdir /* used by libc4 */ +/* 90 */ .long old_mmap /* used by libc4 */ + .long sys_munmap + .long sys_truncate + .long sys_ftruncate + .long sys_fchmod +/* 95 */ .long sys_fchown16 + .long sys_getpriority + .long sys_setpriority + .long sys_ni_syscall /* was sys_profil */ + .long sys_statfs +/* 100 */ .long sys_fstatfs + .long sys_ni_syscall + .long sys_socketcall + .long sys_syslog + .long sys_setitimer +/* 105 */ .long sys_getitimer + .long sys_newstat + .long sys_newlstat + .long sys_newfstat + .long sys_ni_syscall /* was sys_uname */ +/* 110 */ .long sys_ni_syscall /* was sys_iopl */ + .long sys_vhangup + .long sys_ni_syscall + .long sys_syscall /* call a syscall */ + .long sys_wait4 +/* 115 */ .long sys_swapoff + .long sys_sysinfo + .long sys_ipc + .long sys_fsync + .long sys_sigreturn_wrapper +/* 120 */ .long sys_clone_wapper + .long sys_setdomainname + .long sys_newuname + .long sys_ni_syscall + .long sys_adjtimex +/* 125 */ .long sys_mprotect + .long sys_sigprocmask + .long sys_ni_syscall /* WAS: sys_create_module */ + .long sys_init_module + .long sys_delete_module +/* 130 */ .long sys_ni_syscall /* WAS: sys_get_kernel_syms */ + .long sys_quotactl + .long sys_getpgid + .long sys_fchdir + .long sys_bdflush +/* 135 */ .long sys_sysfs + .long sys_personality + .long sys_ni_syscall /* .long _sys_afs_syscall */ + .long sys_setfsuid16 + .long sys_setfsgid16 +/* 140 */ .long sys_llseek + .long sys_getdents + .long sys_select + .long sys_flock + .long sys_msync +/* 145 */ .long sys_readv + .long sys_writev + .long sys_getsid + .long sys_fdatasync + .long sys_sysctl +/* 150 */ .long sys_mlock + .long sys_munlock + .long sys_mlockall + .long sys_munlockall + .long sys_sched_setparam +/* 155 */ .long sys_sched_getparam + .long sys_sched_setscheduler + .long sys_sched_getscheduler + .long sys_sched_yield + .long sys_sched_get_priority_max +/* 160 */ .long sys_sched_get_priority_min + .long sys_sched_rr_get_interval + .long sys_nanosleep + .long sys_arm_mremap + .long sys_setresuid16 +/* 165 */ .long sys_getresuid16 + .long sys_ni_syscall + .long sys_ni_syscall /* WAS: sys_query_module */ + .long sys_poll + .long sys_nfsservctl +/* 170 */ .long sys_setresgid16 + .long sys_getresgid16 + .long sys_prctl + .long sys_rt_sigreturn_wrapper + .long sys_rt_sigaction +/* 175 */ .long sys_rt_sigprocmask + .long sys_rt_sigpending + .long sys_rt_sigtimedwait + .long sys_rt_sigqueueinfo + .long sys_rt_sigsuspend_wrapper +/* 180 */ .long sys_pread64 + .long sys_pwrite64 + .long sys_chown16 + .long sys_getcwd + .long sys_capget +/* 185 */ .long sys_capset + .long sys_sigaltstack_wrapper + .long sys_sendfile + .long sys_ni_syscall + .long sys_ni_syscall +/* 190 */ .long sys_vfork_wrapper + .long sys_getrlimit + .long sys_mmap2 + .long sys_truncate64 + .long sys_ftruncate64 +/* 195 */ .long sys_stat64 + .long sys_lstat64 + .long sys_fstat64 + .long sys_lchown + .long sys_getuid +/* 200 */ .long sys_getgid + .long sys_geteuid + .long sys_getegid + .long sys_setreuid + .long sys_setregid +/* 205 */ .long sys_getgroups + .long sys_setgroups + .long sys_fchown + .long sys_setresuid + .long sys_getresuid +/* 210 */ .long sys_setresgid + .long sys_getresgid + .long sys_chown + .long sys_setuid + .long sys_setgid +/* 215 */ .long sys_setfsuid + .long sys_setfsgid + .long sys_getdents64 + .long sys_pivot_root + .long sys_mincore +/* 220 */ .long sys_madvise + .long sys_fcntl64 + .long sys_ni_syscall /* TUX */ + .long sys_ni_syscall /* WAS: sys_security */ + .long sys_gettid +/* 225 */ .long sys_readahead + .long sys_setxattr + .long sys_lsetxattr + .long sys_fsetxattr + .long sys_getxattr +/* 230 */ .long sys_lgetxattr + .long sys_fgetxattr + .long sys_listxattr + .long sys_llistxattr + .long sys_flistxattr +/* 235 */ .long sys_removexattr + .long sys_lremovexattr + .long sys_fremovexattr + .long sys_tkill +__syscall_end: + + .rept NR_syscalls - (__syscall_end - __syscall_start) / 4 + .long sys_ni_syscall + .endr +#endif diff -Nru a/include/asm-arm26/checksum.h b/include/asm-arm26/checksum.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/checksum.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,158 @@ +/* + * linux/include/asm-arm/checksum.h + * + * IP checksum routines + * + * Copyright (C) Original authors of ../asm-i386/checksum.h + * Copyright (C) 1996-1999 Russell King + */ +#ifndef __ASM_ARM_CHECKSUM_H +#define __ASM_ARM_CHECKSUM_H + +/* + * computes the checksum of a memory block at buff, length len, + * and adds in "sum" (32-bit) + * + * returns a 32-bit number suitable for feeding into itself + * or csum_tcpudp_magic + * + * this function must be called with even lengths, except + * for the last fragment, which may be odd + * + * it's best to have buff aligned on a 32-bit boundary + */ +unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum); + +/* + * the same as csum_partial, but copies from src while it + * checksums, and handles user-space pointer exceptions correctly, when needed. + * + * here even more important to align src and dst on a 32-bit (or even + * better 64-bit) boundary + */ + +unsigned int +csum_partial_copy_nocheck(const char *src, char *dst, int len, int sum); + +unsigned int +csum_partial_copy_from_user(const char *src, char *dst, int len, int sum, int *err_ptr); + +/* + * These are the old (and unsafe) way of doing checksums, a warning message will be + * printed if they are used and an exception occurs. + * + * these functions should go away after some time. + */ +#define csum_partial_copy(src,dst,len,sum) csum_partial_copy_nocheck(src,dst,len,sum) + +/* + * This is a version of ip_compute_csum() optimized for IP headers, + * which always checksum on 4 octet boundaries. + */ +static inline unsigned short +ip_fast_csum(unsigned char * iph, unsigned int ihl) +{ + unsigned int sum, tmp1; + + __asm__ __volatile__( + "ldr %0, [%1], #4 @ ip_fast_csum \n\ + ldr %3, [%1], #4 \n\ + sub %2, %2, #5 \n\ + adds %0, %0, %3 \n\ + ldr %3, [%1], #4 \n\ + adcs %0, %0, %3 \n\ + ldr %3, [%1], #4 \n\ +1: adcs %0, %0, %3 \n\ + ldr %3, [%1], #4 \n\ + tst %2, #15 @ do this carefully \n\ + subne %2, %2, #1 @ without destroying \n\ + bne 1b @ the carry flag \n\ + adcs %0, %0, %3 \n\ + adc %0, %0, #0 \n\ + adds %0, %0, %0, lsl #16 \n\ + addcs %0, %0, #0x10000 \n\ + mvn %0, %0 \n\ + mov %0, %0, lsr #16" + : "=r" (sum), "=r" (iph), "=r" (ihl), "=r" (tmp1) + : "1" (iph), "2" (ihl) + : "cc"); + return sum; +} + +/* + * Fold a partial checksum without adding pseudo headers + */ +static inline unsigned int +csum_fold(unsigned int sum) +{ + __asm__( + "adds %0, %1, %1, lsl #16 @ csum_fold \n\ + addcs %0, %0, #0x10000" + : "=r" (sum) + : "r" (sum) + : "cc"); + return (~sum) >> 16; +} + +static inline unsigned int +csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr, unsigned short len, + unsigned int proto, unsigned int sum) +{ + __asm__( + "adds %0, %1, %2 @ csum_tcpudp_nofold \n\ + adcs %0, %0, %3 \n\ + adcs %0, %0, %4 \n\ + adcs %0, %0, %5 \n\ + adc %0, %0, #0" + : "=&r"(sum) + : "r" (sum), "r" (daddr), "r" (saddr), "r" (ntohs(len) << 16), "Ir" (proto << 8) + : "cc"); + return sum; +} +/* + * computes the checksum of the TCP/UDP pseudo-header + * returns a 16-bit checksum, already complemented + */ +static inline unsigned short int +csum_tcpudp_magic(unsigned long saddr, unsigned long daddr, unsigned short len, + unsigned int proto, unsigned int sum) +{ + __asm__( + "adds %0, %1, %2 @ csum_tcpudp_magic \n\ + adcs %0, %0, %3 \n\ + adcs %0, %0, %4 \n\ + adcs %0, %0, %5 \n\ + adc %0, %0, #0 \n\ + adds %0, %0, %0, lsl #16 \n\ + addcs %0, %0, #0x10000 \n\ + mvn %0, %0" + : "=&r"(sum) + : "r" (sum), "r" (daddr), "r" (saddr), "r" (ntohs(len)), "Ir" (proto << 8) + : "cc"); + return sum >> 16; +} + + +/* + * this routine is used for miscellaneous IP-like checksums, mainly + * in icmp.c + */ +static inline unsigned short +ip_compute_csum(unsigned char * buff, int len) +{ + return csum_fold(csum_partial(buff, len, 0)); +} + +#define _HAVE_ARCH_IPV6_CSUM +extern unsigned long +__csum_ipv6_magic(struct in6_addr *saddr, struct in6_addr *daddr, __u32 len, + __u32 proto, unsigned int sum); + +static inline unsigned short int +csum_ipv6_magic(struct in6_addr *saddr, struct in6_addr *daddr, __u32 len, + unsigned short proto, unsigned int sum) +{ + return csum_fold(__csum_ipv6_magic(saddr, daddr, htonl(len), + htonl(proto), sum)); +} +#endif diff -Nru a/include/asm-arm26/constants.h b/include/asm-arm26/constants.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/constants.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,29 @@ +#ifndef __ASM_OFFSETS_H__ +#define __ASM_OFFSETS_H__ +/* + * DO NOT MODIFY. + * + * This file was generated by arch/arm26/Makefile + * + */ + +#define TSK_USED_MATH 788 /* offsetof(struct task_struct, used_math) */ +#define TSK_ACTIVE_MM 96 /* offsetof(struct task_struct, active_mm) */ + +#define VMA_VM_MM 0 /* offsetof(struct vm_area_struct, vm_mm) */ +#define VMA_VM_FLAGS 20 /* offsetof(struct vm_area_struct, vm_flags) */ + +#define VM_EXEC 4 /* VM_EXEC */ + + +#define PAGE_PRESENT 1 /* L_PTE_PRESENT */ +#define PAGE_READONLY 95 /* PAGE_READONLY */ +#define PAGE_NOT_USER 3 /* PAGE_NONE */ +#define PAGE_OLD 3 /* PAGE_NONE */ +#define PAGE_CLEAN 128 /* L_PTE_DIRTY */ + +#define PAGE_SZ 32768 /* PAGE_SIZE */ + +#define SYS_ERROR0 10420224 /* 0x9f0000 */ + +#endif diff -Nru a/include/asm-arm26/current.h b/include/asm-arm26/current.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/current.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,15 @@ +#ifndef _ASMARM_CURRENT_H +#define _ASMARM_CURRENT_H + +#include <linux/thread_info.h> + +static inline struct task_struct *get_current(void) __attribute__ (( __const__ )); + +static inline struct task_struct *get_current(void) +{ + return current_thread_info()->task; +} + +#define current (get_current()) + +#endif /* _ASMARM_CURRENT_H */ diff -Nru a/include/asm-arm26/delay.h b/include/asm-arm26/delay.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/delay.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,34 @@ +#ifndef __ASM_ARM_DELAY_H +#define __ASM_ARM_DELAY_H + +/* + * Copyright (C) 1995 Russell King + * + * Delay routines, using a pre-computed "loops_per_second" value. + */ + +extern void __delay(int loops); + +/* + * division by multiplication: you don't have to worry about + * loss of precision. + * + * Use only for very small delays ( < 1 msec). Should probably use a + * lookup table, really, as the multiplications take much too long with + * short delays. This is a "reasonable" implementation, though (and the + * first constant multiplications gets optimized away if the delay is + * a constant) + * + * FIXME - lets improve it then... + */ +extern void udelay(unsigned long usecs); + +static inline unsigned long muldiv(unsigned long a, unsigned long b, unsigned long c) +{ + return a * b / c; +} + + + +#endif /* defined(_ARM_DELAY_H) */ + diff -Nru a/include/asm-arm26/div64.h b/include/asm-arm26/div64.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/div64.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,14 @@ +#ifndef __ASM_ARM_DIV64 +#define __ASM_ARM_DIV64 + +/* We're not 64-bit, but... */ +#define do_div(n,base) \ +({ \ + int __res; \ + __res = ((unsigned long)n) % (unsigned int)base; \ + n = ((unsigned long)n) / (unsigned int)base; \ + __res; \ +}) + +#endif + diff -Nru a/include/asm-arm26/dma.h b/include/asm-arm26/dma.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/dma.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,184 @@ +#ifndef __ASM_ARM_DMA_H +#define __ASM_ARM_DMA_H + +typedef unsigned int dmach_t; + +#include <linux/config.h> +#include <linux/spinlock.h> +#include <asm/system.h> +#include <asm/memory.h> +#include <asm/scatterlist.h> + +// FIXME - do we really need this? arm26 cant do 'proper' DMA + +typedef struct dma_struct dma_t; +typedef unsigned int dmamode_t; + +struct dma_ops { + int (*request)(dmach_t, dma_t *); /* optional */ + void (*free)(dmach_t, dma_t *); /* optional */ + void (*enable)(dmach_t, dma_t *); /* mandatory */ + void (*disable)(dmach_t, dma_t *); /* mandatory */ + int (*residue)(dmach_t, dma_t *); /* optional */ + int (*setspeed)(dmach_t, dma_t *, int); /* optional */ + char *type; +}; + +struct dma_struct { + struct scatterlist buf; /* single DMA */ + int sgcount; /* number of DMA SG */ + struct scatterlist *sg; /* DMA Scatter-Gather List */ + + unsigned int active:1; /* Transfer active */ + unsigned int invalid:1; /* Address/Count changed */ + unsigned int using_sg:1; /* using scatter list? */ + dmamode_t dma_mode; /* DMA mode */ + int speed; /* DMA speed */ + + unsigned int lock; /* Device is allocated */ + const char *device_id; /* Device name */ + + unsigned int dma_base; /* Controller base address */ + int dma_irq; /* Controller IRQ */ + int state; /* Controller state */ + struct scatterlist cur_sg; /* Current controller buffer */ + + struct dma_ops *d_ops; +}; + +/* Prototype: void arch_dma_init(dma) + * Purpose : Initialise architecture specific DMA + * Params : dma - pointer to array of DMA structures + */ +extern void arch_dma_init(dma_t *dma); + +extern void isa_init_dma(dma_t *dma); + + +#define MAX_DMA_ADDRESS 0x03000000 +#define MAX_DMA_CHANNELS 3 + +/* ARC */ +#define DMA_VIRTUAL_FLOPPY0 0 +#define DMA_VIRTUAL_FLOPPY1 1 +#define DMA_VIRTUAL_SOUND 2 + +/* A5K */ +#define DMA_FLOPPY 0 + +/* + * DMA modes + */ +#define DMA_MODE_MASK 3 + +#define DMA_MODE_READ 0 +#define DMA_MODE_WRITE 1 +#define DMA_MODE_CASCADE 2 +#define DMA_AUTOINIT 4 + +extern spinlock_t dma_spin_lock; + +static inline unsigned long claim_dma_lock(void) +{ + unsigned long flags; + spin_lock_irqsave(&dma_spin_lock, flags); + return flags; +} + +static inline void release_dma_lock(unsigned long flags) +{ + spin_unlock_irqrestore(&dma_spin_lock, flags); +} + +/* Clear the 'DMA Pointer Flip Flop'. + * Write 0 for LSB/MSB, 1 for MSB/LSB access. + */ +#define clear_dma_ff(channel) + +/* Set only the page register bits of the transfer address. + * + * NOTE: This is an architecture specific function, and should + * be hidden from the drivers + */ +extern void set_dma_page(dmach_t channel, char pagenr); + +/* Request a DMA channel + * + * Some architectures may need to do allocate an interrupt + */ +extern int request_dma(dmach_t channel, const char * device_id); + +/* Free a DMA channel + * + * Some architectures may need to do free an interrupt + */ +extern void free_dma(dmach_t channel); + +/* Enable DMA for this channel + * + * On some architectures, this may have other side effects like + * enabling an interrupt and setting the DMA registers. + */ +extern void enable_dma(dmach_t channel); + +/* Disable DMA for this channel + * + * On some architectures, this may have other side effects like + * disabling an interrupt or whatever. + */ +extern void disable_dma(dmach_t channel); + +/* Test whether the specified channel has an active DMA transfer + */ +extern int dma_channel_active(dmach_t channel); + +/* Set the DMA scatter gather list for this channel + * + * This should not be called if a DMA channel is enabled, + * especially since some DMA architectures don't update the + * DMA address immediately, but defer it to the enable_dma(). + */ +extern void set_dma_sg(dmach_t channel, struct scatterlist *sg, int nr_sg); + +/* Set the DMA address for this channel + * + * This should not be called if a DMA channel is enabled, + * especially since some DMA architectures don't update the + * DMA address immediately, but defer it to the enable_dma(). + */ +extern void set_dma_addr(dmach_t channel, unsigned long physaddr); + +/* Set the DMA byte count for this channel + * + * This should not be called if a DMA channel is enabled, + * especially since some DMA architectures don't update the + * DMA count immediately, but defer it to the enable_dma(). + */ +extern void set_dma_count(dmach_t channel, unsigned long count); + +/* Set the transfer direction for this channel + * + * This should not be called if a DMA channel is enabled, + * especially since some DMA architectures don't update the + * DMA transfer direction immediately, but defer it to the + * enable_dma(). + */ +extern void set_dma_mode(dmach_t channel, dmamode_t mode); + +/* Set the transfer speed for this channel + */ +extern void set_dma_speed(dmach_t channel, int cycle_ns); + +/* Get DMA residue count. After a DMA transfer, this + * should return zero. Reading this while a DMA transfer is + * still in progress will return unpredictable results. + * If called before the channel has been used, it may return 1. + * Otherwise, it returns the number of _bytes_ left to transfer. + */ +extern int get_dma_residue(dmach_t channel); + +#ifndef NO_DMA +#define NO_DMA 255 +#endif + +#endif /* _ARM_DMA_H */ diff -Nru a/include/asm-arm26/ecard.h b/include/asm-arm26/ecard.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/ecard.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,291 @@ +/* + * linux/include/asm-arm26/ecard.h + * + * definitions for expansion cards + * + * This is a new system as from Linux 1.2.3 + * + * Changelog: + * 11-12-1996 RMK Further minor improvements + * 12-09-1997 RMK Added interrupt enable/disable for card level + * 18-05-2003 IM Adjusted for ARM26 + * + * Reference: Acorns Risc OS 3 Programmers Reference Manuals. + */ + +#ifndef __ASM_ECARD_H +#define __ASM_ECARD_H + +/* + * Currently understood cards (but not necessarily + * supported): + * Manufacturer Product ID + */ +#define MANU_ACORN 0x0000 +#define PROD_ACORN_SCSI 0x0002 +#define PROD_ACORN_ETHER1 0x0003 +#define PROD_ACORN_MFM 0x000b + +#define MANU_ANT2 0x0011 +#define PROD_ANT_ETHER3 0x00a4 + +#define MANU_ATOMWIDE 0x0017 +#define PROD_ATOMWIDE_3PSERIAL 0x0090 + +#define MANU_IRLAM_INSTRUMENTS 0x001f +#define MANU_IRLAM_INSTRUMENTS_ETHERN 0x5678 + +#define MANU_OAK 0x0021 +#define PROD_OAK_SCSI 0x0058 + +#define MANU_MORLEY 0x002b +#define PROD_MORLEY_SCSI_UNCACHED 0x0067 + +#define MANU_CUMANA 0x003a +#define PROD_CUMANA_SCSI_2 0x003a +#define PROD_CUMANA_SCSI_1 0x00a0 + +#define MANU_ICS 0x003c +#define PROD_ICS_IDE 0x00ae + +#define MANU_ICS2 0x003d +#define PROD_ICS2_IDE 0x00ae + +#define MANU_SERPORT 0x003f +#define PROD_SERPORT_DSPORT 0x00b9 + +#define MANU_ARXE 0x0041 +#define PROD_ARXE_SCSI 0x00be + +#define MANU_I3 0x0046 +#define PROD_I3_ETHERLAN500 0x00d4 +#define PROD_I3_ETHERLAN600 0x00ec +#define PROD_I3_ETHERLAN600A 0x011e + +#define MANU_ANT 0x0053 +#define PROD_ANT_ETHERM 0x00d8 +#define PROD_ANT_ETHERB 0x00e4 + +#define MANU_ALSYSTEMS 0x005b +#define PROD_ALSYS_SCSIATAPI 0x0107 + +#define MANU_MCS 0x0063 +#define PROD_MCS_CONNECT32 0x0125 + +#define MANU_EESOX 0x0064 +#define PROD_EESOX_SCSI2 0x008c + +#define MANU_YELLOWSTONE 0x0096 +#define PROD_YELLOWSTONE_RAPIDE32 0x0120 + +#define MANU_SIMTEC 0x005f +#define PROD_SIMTEC_IDE8 0x0130 +#define PROD_SIMTEC_IDE16 0x0131 + + +#ifdef ECARD_C +#define CONST +#else +#define CONST const +#endif + +#define MAX_ECARDS 4 + +typedef enum { /* Cards address space */ + ECARD_IOC, + ECARD_MEMC, + ECARD_EASI +} card_type_t; + +typedef enum { /* Speed for ECARD_IOC space */ + ECARD_SLOW = 0, + ECARD_MEDIUM = 1, + ECARD_FAST = 2, + ECARD_SYNC = 3 +} card_speed_t; + +struct ecard_id { /* Card ID structure */ + unsigned short manufacturer; + unsigned short product; + void *data; +}; + +struct in_ecid { /* Packed card ID information */ + unsigned short product; /* Product code */ + unsigned short manufacturer; /* Manufacturer code */ + unsigned char id:4; /* Simple ID */ + unsigned char cd:1; /* Chunk dir present */ + unsigned char is:1; /* Interrupt status pointers */ + unsigned char w:2; /* Width */ + unsigned char country; /* Country */ + unsigned char irqmask; /* IRQ mask */ + unsigned char fiqmask; /* FIQ mask */ + unsigned long irqoff; /* IRQ offset */ + unsigned long fiqoff; /* FIQ offset */ +}; + +typedef struct expansion_card ecard_t; +typedef unsigned long *loader_t; + +typedef struct { /* Card handler routines */ + void (*irqenable)(ecard_t *ec, int irqnr); + void (*irqdisable)(ecard_t *ec, int irqnr); + int (*irqpending)(ecard_t *ec); + void (*fiqenable)(ecard_t *ec, int fiqnr); + void (*fiqdisable)(ecard_t *ec, int fiqnr); + int (*fiqpending)(ecard_t *ec); +} expansioncard_ops_t; + +#define ECARD_NUM_RESOURCES (6) + +#define ECARD_RES_IOCSLOW (0) +#define ECARD_RES_IOCMEDIUM (1) +#define ECARD_RES_IOCFAST (2) +#define ECARD_RES_IOCSYNC (3) +#define ECARD_RES_MEMC (4) +#define ECARD_RES_EASI (5) + +#define ecard_resource_start(ec,nr) ((ec)->resource[nr].start) +#define ecard_resource_end(ec,nr) ((ec)->resource[nr].end) +#define ecard_resource_len(ec,nr) ((ec)->resource[nr].end - \ + (ec)->resource[nr].start + 1) + +/* + * This contains all the info needed on an expansion card + */ +struct expansion_card { + struct expansion_card *next; + + struct device dev; + struct resource resource[ECARD_NUM_RESOURCES]; + + /* Public data */ + volatile unsigned char *irqaddr; /* address of IRQ register */ + volatile unsigned char *fiqaddr; /* address of FIQ register */ + unsigned char irqmask; /* IRQ mask */ + unsigned char fiqmask; /* FIQ mask */ + unsigned char claimed; /* Card claimed? */ + + void *irq_data; /* Data for use for IRQ by card */ + void *fiq_data; /* Data for use for FIQ by card */ + const expansioncard_ops_t *ops; /* Enable/Disable Ops for card */ + + CONST unsigned int slot_no; /* Slot number */ + CONST unsigned int dma; /* DMA number (for request_dma) */ + CONST unsigned int irq; /* IRQ number (for request_irq) */ + CONST unsigned int fiq; /* FIQ number (for request_irq) */ + CONST card_type_t type; /* Type of card */ + CONST struct in_ecid cid; /* Card Identification */ + + /* Private internal data */ + const char *card_desc; /* Card description */ + CONST unsigned int podaddr; /* Base Linux address for card */ + CONST loader_t loader; /* loader program */ + u64 dma_mask; +}; + +struct in_chunk_dir { + unsigned int start_offset; + union { + unsigned char string[256]; + unsigned char data[1]; + } d; +}; + +/* + * ecard_claim: claim an expansion card entry + * FIXME - are these atomic / called with interrupts off ? + */ +#define ecard_claim(ec) ((ec)->claimed = 1) + +/* + * ecard_release: release an expansion card entry + */ +#define ecard_release(ec) ((ec)->claimed = 0) + +/* + * Read a chunk from an expansion card + * cd : where to put read data + * ec : expansion card info struct + * id : id number to find + * num: (n+1)'th id to find. + */ +extern int ecard_readchunk (struct in_chunk_dir *cd, struct expansion_card *ec, int id, int num); + +/* + * Obtain the address of a card + */ +extern unsigned int ecard_address (struct expansion_card *ec, card_type_t card_type, card_speed_t speed); + +#ifdef ECARD_C +/* Definitions internal to ecard.c - for it's use only!! + * + * External expansion card header as read from the card + */ +struct ex_ecid { + unsigned char r_irq:1; + unsigned char r_zero:1; + unsigned char r_fiq:1; + unsigned char r_id:4; + unsigned char r_a:1; + + unsigned char r_cd:1; + unsigned char r_is:1; + unsigned char r_w:2; + unsigned char r_r1:4; + + unsigned char r_r2:8; + + unsigned char r_prod[2]; + + unsigned char r_manu[2]; + + unsigned char r_country; + + unsigned char r_irqmask; + unsigned char r_irqoff[3]; + + unsigned char r_fiqmask; + unsigned char r_fiqoff[3]; +}; + +/* + * Chunk directory entry as read from the card + */ +struct ex_chunk_dir { + unsigned char r_id; + unsigned char r_len[3]; + unsigned long r_start; + union { + char string[256]; + char data[1]; + } d; +#define c_id(x) ((x)->r_id) +#define c_len(x) ((x)->r_len[0]|((x)->r_len[1]<<8)|((x)->r_len[2]<<16)) +#define c_start(x) ((x)->r_start) +}; + +#endif + +extern struct bus_type ecard_bus_type; + +#define ECARD_DEV(_d) container_of((_d), struct expansion_card, dev) + +struct ecard_driver { + int (*probe)(struct expansion_card *, const struct ecard_id *id); + void (*remove)(struct expansion_card *); + void (*shutdown)(struct expansion_card *); + const struct ecard_id *id_table; + unsigned int id; + struct device_driver drv; +}; + +#define ECARD_DRV(_d) container_of((_d), struct ecard_driver, drv) + +#define ecard_set_drvdata(ec,data) dev_set_drvdata(&(ec)->dev, (data)) +#define ecard_get_drvdata(ec) dev_get_drvdata(&(ec)->dev) + +int ecard_register_driver(struct ecard_driver *); +void ecard_remove_driver(struct ecard_driver *); + +#endif diff -Nru a/include/asm-arm26/elf.h b/include/asm-arm26/elf.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/elf.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,77 @@ +#ifndef __ASMARM_ELF_H +#define __ASMARM_ELF_H + +/* + * ELF register definitions.. + */ + +#include <asm/ptrace.h> +#include <asm/procinfo.h> + +//FIXME - is it always 32K ? + +#define ELF_EXEC_PAGESIZE 32768 +#define SET_PERSONALITY(ex,ibcs2) set_personality(PER_LINUX) + +typedef unsigned long elf_greg_t; +typedef unsigned long elf_freg_t[3]; + +#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t)) +typedef elf_greg_t elf_gregset_t[ELF_NGREG]; + +typedef struct { void *null; } elf_fpregset_t; + +/* + * This is used to ensure we don't load something for the wrong architecture. + * We can only execute 26-bit code. + */ + +#define EM_ARM 40 +#define EF_ARM_APCS26 0x08 + +//#define elf_check_arch(x) ( ((x)->e_machine == EM_ARM) && ((x)->e_flags & EF_ARM_APCS26) ) FIXME!!!!! - this looks OK, but the flags seem to be wrong. +#define elf_check_arch(x) (1) + +/* + * These are used to set parameters in the core dumps. + */ +#define ELF_CLASS ELFCLASS32 +#define ELF_DATA ELFDATA2LSB; +#define ELF_ARCH EM_ARM + +#define USE_ELF_CORE_DUMP + +/* This is the location that an ET_DYN program is loaded if exec'ed. Typical + use of this is to invoke "./ld.so someprog" to test out a new version of + the loader. We need to make sure that it is out of the way of the program + that it will "exec", and that there is sufficient room for the brk. */ + +#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3) + +/* When the program starts, a1 contains a pointer to a function to be + registered with atexit, as per the SVR4 ABI. A value of 0 means we + have no such handler. */ +#define ELF_PLAT_INIT(_r, load_addr) (_r)->ARM_r0 = 0 + +/* This yields a mask that user programs can use to figure out what + instruction set this cpu supports. */ + +extern unsigned int elf_hwcap; +#define ELF_HWCAP (elf_hwcap) + +/* This yields a string that ld.so will use to load implementation + specific libraries for optimization. This is more specific in + intent than poking at uname or /proc/cpuinfo. */ + +/* For now we just provide a fairly general string that describes the + processor family. This could be made more specific later if someone + implemented optimisations that require it. 26-bit CPUs give you + "v1l" for ARM2 (no SWP) and "v2l" for anything else (ARM1 isn't + supported). + */ + +#define ELF_PLATFORM_SIZE 8 +extern char elf_platform[]; +#define ELF_PLATFORM (elf_platform) + +#endif diff -Nru a/include/asm-arm26/errno.h b/include/asm-arm26/errno.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/errno.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,6 @@ +#ifndef _ARM_ERRNO_H +#define _ARM_ERRNO_H + +#include <asm-generic/errno.h> + +#endif diff -Nru a/include/asm-arm26/fcntl.h b/include/asm-arm26/fcntl.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/fcntl.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,86 @@ +#ifndef _ARM_FCNTL_H +#define _ARM_FCNTL_H + +/* open/fcntl - O_SYNC is only implemented on blocks devices and on files + located on an ext2 file system */ +#define O_ACCMODE 0003 +#define O_RDONLY 00 +#define O_WRONLY 01 +#define O_RDWR 02 +#define O_CREAT 0100 /* not fcntl */ +#define O_EXCL 0200 /* not fcntl */ +#define O_NOCTTY 0400 /* not fcntl */ +#define O_TRUNC 01000 /* not fcntl */ +#define O_APPEND 02000 +#define O_NONBLOCK 04000 +#define O_NDELAY O_NONBLOCK +#define O_SYNC 010000 +#define FASYNC 020000 /* fcntl, for BSD compatibility */ +#define O_DIRECTORY 040000 /* must be a directory */ +#define O_NOFOLLOW 0100000 /* don't follow links */ +#define O_DIRECT 0200000 /* direct disk access hint - currently ignored */ +#define O_LARGEFILE 0400000 + +#define F_DUPFD 0 /* dup */ +#define F_GETFD 1 /* get close_on_exec */ +#define F_SETFD 2 /* set/clear close_on_exec */ +#define F_GETFL 3 /* get file->f_flags */ +#define F_SETFL 4 /* set file->f_flags */ +#define F_GETLK 5 +#define F_SETLK 6 +#define F_SETLKW 7 + +#define F_SETOWN 8 /* for sockets. */ +#define F_GETOWN 9 /* for sockets. */ +#define F_SETSIG 10 /* for sockets. */ +#define F_GETSIG 11 /* for sockets. */ + +#define F_GETLK64 12 /* using 'struct flock64' */ +#define F_SETLK64 13 +#define F_SETLKW64 14 + +/* for F_[GET|SET]FL */ +#define FD_CLOEXEC 1 /* actually anything with low bit set goes */ + +/* for posix fcntl() and lockf() */ +#define F_RDLCK 0 +#define F_WRLCK 1 +#define F_UNLCK 2 + +/* for old implementation of bsd flock () */ +#define F_EXLCK 4 /* or 3 */ +#define F_SHLCK 8 /* or 4 */ + +/* for leases */ +#define F_INPROGRESS 16 + +/* operations for bsd flock(), also used by the kernel implementation */ +#define LOCK_SH 1 /* shared lock */ +#define LOCK_EX 2 /* exclusive lock */ +#define LOCK_NB 4 /* or'd with one of the above to prevent + blocking */ +#define LOCK_UN 8 /* remove lock */ + +#define LOCK_MAND 32 /* This is a mandatory flock */ +#define LOCK_READ 64 /* ... Which allows concurrent read operations */ +#define LOCK_WRITE 128 /* ... Which allows concurrent write operations */ +#define LOCK_RW 192 /* ... Which allows concurrent read & write ops */ + +struct flock { + short l_type; + short l_whence; + off_t l_start; + off_t l_len; + pid_t l_pid; +}; + +struct flock64 { + short l_type; + short l_whence; + loff_t l_start; + loff_t l_len; + pid_t l_pid; +}; + +#define F_LINUX_SPECIFIC_BASE 1024 +#endif diff -Nru a/include/asm-arm26/fiq.h b/include/asm-arm26/fiq.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/fiq.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,37 @@ +/* + * linux/include/asm-arm/fiq.h + * + * Support for FIQ on ARM architectures. + * Written by Philip Blundell <philb@gnu.org>, 1998 + * Re-written by Russell King + */ + +#ifndef __ASM_FIQ_H +#define __ASM_FIQ_H + +#include <asm/ptrace.h> + +struct fiq_handler { + struct fiq_handler *next; + /* Name + */ + const char *name; + /* Called to ask driver to relinquish/ + * reacquire FIQ + * return zero to accept, or -<errno> + */ + int (*fiq_op)(void *, int relinquish); + /* data for the relinquish/reacquire functions + */ + void *dev_id; +}; + +extern int claim_fiq(struct fiq_handler *f); +extern void release_fiq(struct fiq_handler *f); +extern void set_fiq_handler(void *start, unsigned int length); +extern void set_fiq_regs(struct pt_regs *regs); +extern void get_fiq_regs(struct pt_regs *regs); +extern void enable_fiq(int fiq); +extern void disable_fiq(int fiq); + +#endif diff -Nru a/include/asm-arm26/floppy.h b/include/asm-arm26/floppy.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/floppy.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,141 @@ +/* + * linux/include/asm-arm/floppy.h + * + * Copyright (C) 1996-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Note that we don't touch FLOPPY_DMA nor FLOPPY_IRQ here + */ +#ifndef __ASM_ARM_FLOPPY_H +#define __ASM_ARM_FLOPPY_H + +#define fd_outb(val,port) \ + do { \ + if ((port) == FD_DOR) \ + fd_setdor((val)); \ + else \ + outb((val),(port)); \ + } while(0) + +#define fd_inb(port) inb((port)) +#define fd_request_irq() request_irq(IRQ_FLOPPYDISK,floppy_interrupt,\ + SA_INTERRUPT|SA_SAMPLE_RANDOM,"floppy",NULL) +#define fd_free_irq() free_irq(IRQ_FLOPPYDISK,NULL) +#define fd_disable_irq() disable_irq(IRQ_FLOPPYDISK) +#define fd_enable_irq() enable_irq(IRQ_FLOPPYDISK) + +#define fd_request_dma() request_dma(DMA_FLOPPY,"floppy") +#define fd_free_dma() free_dma(DMA_FLOPPY) +#define fd_disable_dma() disable_dma(DMA_FLOPPY) +#define fd_enable_dma() enable_dma(DMA_FLOPPY) +#define fd_clear_dma_ff() clear_dma_ff(DMA_FLOPPY) +#define fd_set_dma_mode(mode) set_dma_mode(DMA_FLOPPY, (mode)) +#define fd_set_dma_addr(addr) set_dma_addr(DMA_FLOPPY, virt_to_bus((addr))) +#define fd_set_dma_count(len) set_dma_count(DMA_FLOPPY, (len)) +#define fd_cacheflush(addr,sz) + +/* need to clean up dma.h */ +#define DMA_FLOPPYDISK DMA_FLOPPY + +/* Floppy_selects is the list of DOR's to select drive fd + * + * On initialisation, the floppy list is scanned, and the drives allocated + * in the order that they are found. This is done by seeking the drive + * to a non-zero track, and then restoring it to track 0. If an error occurs, + * then there is no floppy drive present. [to be put back in again] + */ +static unsigned char floppy_selects[2][4] = +{ + { 0x10, 0x21, 0x23, 0x33 }, + { 0x10, 0x21, 0x23, 0x33 } +}; + +#define fd_setdor(dor) \ +do { \ + int new_dor = (dor); \ + if (new_dor & 0xf0) \ + new_dor = (new_dor & 0x0c) | floppy_selects[fdc][new_dor & 3]; \ + else \ + new_dor &= 0x0c; \ + outb(new_dor, FD_DOR); \ +} while (0) + +/* + * Someday, we'll automatically detect which drives are present... + */ +static inline void fd_scandrives (void) +{ +#if 0 + int floppy, drive_count; + + fd_disable_irq(); + raw_cmd = &default_raw_cmd; + raw_cmd->flags = FD_RAW_SPIN | FD_RAW_NEED_SEEK; + raw_cmd->track = 0; + raw_cmd->rate = ?; + drive_count = 0; + for (floppy = 0; floppy < 4; floppy ++) { + current_drive = drive_count; + /* + * Turn on floppy motor + */ + if (start_motor(redo_fd_request)) + continue; + /* + * Set up FDC + */ + fdc_specify(); + /* + * Tell FDC to recalibrate + */ + output_byte(FD_RECALIBRATE); + LAST_OUT(UNIT(floppy)); + /* wait for command to complete */ + if (!successful) { + int i; + for (i = drive_count; i < 3; i--) + floppy_selects[fdc][i] = floppy_selects[fdc][i + 1]; + floppy_selects[fdc][3] = 0; + floppy -= 1; + } else + drive_count++; + } +#else + floppy_selects[0][0] = 0x10; + floppy_selects[0][1] = 0x21; + floppy_selects[0][2] = 0x23; + floppy_selects[0][3] = 0x33; +#endif +} + +#define FDC1 (0x3f0) + +#define FLOPPY0_TYPE 4 +#define FLOPPY1_TYPE 4 + +#define N_FDC 1 +#define N_DRIVE 4 + +#define FLOPPY_MOTOR_MASK 0xf0 + +#define CROSS_64KB(a,s) (0) + +/* + * This allows people to reverse the order of + * fd0 and fd1, in case their hardware is + * strangely connected (as some RiscPCs + * and A5000s seem to be). + */ +static void driveswap(int *ints, int dummy, int dummy2) +{ + floppy_selects[0][0] ^= floppy_selects[0][1]; + floppy_selects[0][1] ^= floppy_selects[0][0]; + floppy_selects[0][0] ^= floppy_selects[0][1]; +} + +#define EXTRA_FLOPPY_PARAMS ,{ "driveswap", &driveswap, NULL, 0, 0 } + +#endif diff -Nru a/include/asm-arm26/fpstate.h b/include/asm-arm26/fpstate.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/fpstate.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,29 @@ +/* + * linux/include/asm-arm/fpstate.h + * + * Copyright (C) 1995 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __ASM_ARM_FPSTATE_H +#define __ASM_ARM_FPSTATE_H + +#define FP_SIZE 35 + +struct fp_hard_struct { + unsigned int save[FP_SIZE]; /* as yet undefined */ +}; + +struct fp_soft_struct { + unsigned int save[FP_SIZE]; /* undefined information */ +}; + +union fp_state { + struct fp_hard_struct hard; + struct fp_soft_struct soft; +}; + +#endif diff -Nru a/include/asm-arm26/hardirq.h b/include/asm-arm26/hardirq.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/hardirq.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,93 @@ +#ifndef __ASM_HARDIRQ_H +#define __ASM_HARDIRQ_H + +#include <linux/config.h> +#include <linux/cache.h> +#include <linux/threads.h> + +/* softirq.h is sensitive to the offsets of these fields */ +typedef struct { + unsigned int __softirq_pending; + unsigned int __local_irq_count; + unsigned int __local_bh_count; + unsigned int __syscall_count; + struct task_struct * __ksoftirqd_task; /* waitqueue is too large */ +} ____cacheline_aligned irq_cpustat_t; + +#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */ + +/* + * We put the hardirq and softirq counter into the preemption + * counter. The bitmask has the following meaning: + * + * - bits 0-7 are the preemption count (max depth: 256) + * - bits 8-15 are the softirq count (max # of softirqs: 256) + * - bits 16-23 are the hardirq count (max # of hardirqs: 256) + * - bit 26 is the PREEMPT_ACTIVE flag + */ +#define PREEMPT_BITS 8 +#define SOFTIRQ_BITS 8 +#define HARDIRQ_BITS 8 + +#define PREEMPT_SHIFT 0 +#define SOFTIRQ_SHIFT (PREEMPT_SHIFT + PREEMPT_BITS) +#define HARDIRQ_SHIFT (SOFTIRQ_SHIFT + SOFTIRQ_BITS) + +#define __MASK(x) ((1UL << (x))-1) + +#define PREEMPT_MASK (__MASK(PREEMPT_BITS) << PREEMPT_SHIFT) +#define HARDIRQ_MASK (__MASK(HARDIRQ_BITS) << HARDIRQ_SHIFT) +#define SOFTIRQ_MASK (__MASK(SOFTIRQ_BITS) << SOFTIRQ_SHIFT) + +#define hardirq_count() (preempt_count() & HARDIRQ_MASK) +#define softirq_count() (preempt_count() & SOFTIRQ_MASK) +#define irq_count() (preempt_count() & (HARDIRQ_MASK|SOFTIRQ_MASK)) + +#define PREEMPT_OFFSET (1UL << PREEMPT_SHIFT) +#define SOFTIRQ_OFFSET (1UL << SOFTIRQ_SHIFT) +#define HARDIRQ_OFFSET (1UL << HARDIRQ_SHIFT) + +/* + * The hardirq mask has to be large enough to have space + * for potentially all IRQ sources in the system nesting + * on a single CPU: + */ +#if (1 << HARDIRQ_BITS) < NR_IRQS +# error HARDIRQ_BITS is too low! +#endif + +/* + * Are we doing bottom half or hardware interrupt processing? + * Are we in a softirq context? Interrupt context? + */ +#define in_irq() (hardirq_count()) +#define in_softirq() (softirq_count()) +#define in_interrupt() (irq_count()) + +#define hardirq_trylock() (!in_interrupt()) +#define hardirq_endlock() do { } while (0) + +#define irq_enter() (preempt_count() += HARDIRQ_OFFSET) + +#ifdef CONFIG_PREEMPT +# define in_atomic() ((preempt_count() & ~PREEMPT_ACTIVE) != kernel_locked())# define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1) +#else +# define in_atomic() (preempt_count() != 0) +# define IRQ_EXIT_OFFSET HARDIRQ_OFFSET +#endif + +#ifndef CONFIG_SMP +#define irq_exit() \ + do { \ + preempt_count() -= HARDIRQ_OFFSET; \ + if (!in_interrupt() && softirq_pending(smp_processor_id())) \ + __asm__("bl%? __do_softirq": : : "lr");/* out of line */\ + preempt_enable_no_resched(); \ + } while (0) + +#define synchronize_irq(irq) barrier() +#else +#error SMP not supported +#endif + +#endif /* __ASM_HARDIRQ_H */ diff -Nru a/include/asm-arm26/hardware.h b/include/asm-arm26/hardware.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/hardware.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,109 @@ +/* + * linux/include/asm-arm/arch-arc/hardware.h + * + * Copyright (C) 1996-1999 Russell King. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This file contains the hardware definitions of the + * Acorn Archimedes/A5000 machines. + * + * Modifications: + * 04-04-1998 PJB/RMK Merged arc and a5k versions + */ +#ifndef __ASM_HARDWARE_H +#define __ASM_HARDWARE_H + +#include <linux/config.h> + + +/* + * What hardware must be present - these can be tested by the kernel + * source. + */ +#define HAS_IOC +#define HAS_MEMC +#define HAS_VIDC + +#define VDMA_ALIGNMENT PAGE_SIZE +#define VDMA_XFERSIZE 16 +#define VDMA_INIT 0 +#define VDMA_START 1 +#define VDMA_END 2 + +#ifndef __ASSEMBLY__ +extern void memc_write(unsigned int reg, unsigned long val); + +#define video_set_dma(start,end,offset) \ +do { \ + memc_write (VDMA_START, (start >> 2)); \ + memc_write (VDMA_END, (end - VDMA_XFERSIZE) >> 2); \ + memc_write (VDMA_INIT, (offset >> 2)); \ +} while (0) +#endif + + +/* Hardware addresses of major areas. + * *_START is the physical address + * *_SIZE is the size of the region + * *_BASE is the virtual address + */ +#define IO_START 0x03000000 +#define IO_SIZE 0x01000000 +#define IO_BASE 0x03000000 + +/* + * Screen mapping information + */ +#define SCREEN_START 0x02000000 +#define SCREEN_END 0x02078000 +#define SCREEN_SIZE 0x00078000 +#define SCREEN_BASE 0x02000000 + + +#define EXPMASK_BASE 0x03360000 +#define IOEB_BASE 0x03350000 +#define VIDC_BASE 0x03400000 +#define LATCHA_BASE 0x03250040 +#define LATCHB_BASE 0x03250018 +#define IOC_BASE 0x03200000 +#define FLOPPYDMA_BASE 0x0302a000 +#define PCIO_BASE 0x03010000 + +// FIXME - are the below correct? +#define PODSLOT_IOC0_BASE 0x03240000 +#define PODSLOT_IOC_SIZE (1 << 14) +#define PODSLOT_MEMC_BASE 0x03000000 +#define PODSLOT_MEMC_SIZE (1 << 14) + +#define vidc_writel(val) __raw_writel(val, VIDC_BASE) + +#ifndef __ASSEMBLY__ + +/* + * for use with inb/outb + */ +#define IOEB_VID_CTL (IOEB_BASE + 0x48) +#define IOEB_PRESENT (IOEB_BASE + 0x50) +#define IOEB_PSCLR (IOEB_BASE + 0x58) +#define IOEB_MONTYPE (IOEB_BASE + 0x70) + +#define IO_EC_IOC_BASE 0x80090000 +#define IO_EC_MEMC_BASE 0x80000000 + +#ifdef CONFIG_ARCH_ARC +/* A680 hardware */ +#define WD1973_BASE 0x03290000 +#define WD1973_LATCH 0x03350000 +#define Z8530_BASE 0x032b0008 +#define SCSI_BASE 0x03100000 +#endif + +#endif + +#define EXPMASK_STATUS (EXPMASK_BASE + 0x00) +#define EXPMASK_ENABLE (EXPMASK_BASE + 0x04) + +#endif diff -Nru a/include/asm-arm26/hdreg.h b/include/asm-arm26/hdreg.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/hdreg.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,15 @@ +/* + * linux/include/asm-arm26/hdreg.h + * + * Used by include/linux/ide.h + * + * Copyright (C) 1994-1996 Linus Torvalds & authors + */ + +#ifndef __ASMARM_HDREG_H +#define __ASMARM_HDREG_H + +typedef unsigned int ide_ioreg_t; + +#endif /* __ASMARM_HDREG_H */ + diff -Nru a/include/asm-arm26/ian_char.h b/include/asm-arm26/ian_char.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/ian_char.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,79 @@ +#ifndef _ian_char_h_included +#define _ian_char_h_included +static int charset[256*8] = {0x777700, 0x7700770, 0x7700770, 0x7777770, 0x7700770, 0x7700770, 0x7700770, 0x0, 0x777770, 0x7700770, 0x7700770, 0x777770, 0x7700770, 0x7700770, 0x777770, 0x0, 0x777700, 0x7700770, 0x770, 0x770, 0x770, 0x7700770, 0x777700, 0x0, 0x77770, 0x770770, 0x7700770, 0x7700770, 0x7700770, 0x770770, 0x77770, 0x0, 0x7777770, 0x770, 0x770, 0x777770, 0x770, 0x770, 0x7777770, 0x0, 0x7777770, 0x770, 0x770, 0x777770, 0x770, 0x770, 0x770, 0x0, 0x777700, 0x7700770, 0x770, 0x7770770, 0x7700770, 0x7700770, 0x777700, 0x0, 0x7700770, 0x7700770, 0x7700770, 0x7777770, 0x7700770, 0x7700770, 0x7700770, 0x0, 0x7777770, 0x77000, 0x77000, 0x77000, 0x77000, 0x77000, 0x7777770, 0x0, 0x7777700, 0x770000, 0x770000, 0x770000, 0x770000, 0x770770, 0x77700, 0x0, 0x7700770, 0x770770, 0x77770, 0x7770, 0x77770, 0x770770, 0x7700770, 0x0, 0x770, 0x770, 0x770, 0x770, 0x770, 0x770, 0x7777770, 0x0, 0x77000770, 0x77707770, 0x77777770, 0x77070770, 0x77070770, 0x77000770, 0x77000770, 0x0, 0x7700770, 0x7700770, 0x7707770, 0x7777770, 0x7770770, 0x7700770, 0x7700770, 0x0, 0x777700, 0x7700770, 0x7700770, 0x7700770, 0x7700770, 0x7700770, 0x777700, 0x0, 0x777770, 0x7700770, 0x7700770, 0x777770, 0x770, 0x770, 0x770, 0x0, 0x777700, 0x7700770, 0x7700770, 0x7700770, 0x7070770, 0x770770, 0x7707700, 0x0, 0x777770, 0x7700770, 0x7700770, 0x777770, 0x770770, 0x7700770, 0x7700770, 0x0, 0x777700, 0x7700770, 0x770, 0x777700, 0x7700000, 0x7700770, 0x777700, 0x0, 0x7777770, 0x77000, 0x77000, 0x77000, 0x77000, 0x77000, 0x77000, 0x0, 0x7700770, 0x7700770, 0x7700770, 0x7700770, 0x7700770, 0x7700770, 0x777700, 0x0, 0x7700770, 0x7700770, 0x7700770, 0x7700770, 0x7700770, 0x777700, 0x77000, 0x0, 0x77000770, 0x77000770, 0x77070770, 0x77070770, 0x77777770, 0x77707770, 0x77000770, 0x0, 0x7700770, 0x7700770, 0x777700, 0x77000, 0x777700, 0x7700770, 0x7700770, 0x0, 0x7700770, 0x7700770, 0x7700770, 0x777700, 0x77000, 0x77000, 0x77000, 0x0, 0x7777770, 0x7700000, 0x770000, 0x77000, 0x7700, 0x770, 0x7777770, 0x0, 0x777770, 0x770, 0x770, 0x770, 0x770, 0x770, 0x777770, 0x0, 0x0, 0x770, 0x7700, 0x77000, 0x770000, 0x7700000, 0x0, 0x0, 0x7777700, 0x7700000, 0x7700000, 0x7700000, 0x7700000, 0x7700000, 0x7777700, 0x0, 0x777700, 0x7700770, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x77777777, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x77000, 0x77000, 0x77000, 0x77000, 0x77000, 0x0, 0x77000, 0x0, 0x770770, 0x770770, 0x770770, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7707700, 0x7707700, 0x77777770, 0x7707700, 0x77777770, 0x7707700, 0x7707700, 0x0, 0x770000, 0x77777700, 0x70770, 0x7777700, 0x77070000, 0x7777770, 0x77000, 0x0, 0x770, 0x7700770, 0x770000, 0x77000, 0x7700, 0x7700770, 0x7700000, 0x0, 0x77700, 0x770770, 0x770770, 0x77700, 0x70770770, 0x7700770, 0x77077700, 0x0, 0x77000, 0x77000, 0x77000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x770000, 0x77000, 0x7700, 0x7700, 0x7700, 0x77000, 0x770000, 0x0, 0x7700, 0x77000, 0x770000, 0x770000, 0x770000, 0x77000, 0x7700, 0x0, 0x0, 0x77000, 0x7777770, 0x777700, 0x7777770, 0x77000, 0x0, 0x0, 0x0, 0x77000, 0x77000, 0x7777770, 0x77000, 0x77000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x77000, 0x77000, 0x7700, 0x0, 0x0, 0x0, 0x7777770, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x77000, 0x77000, 0x0, 0x0, 0x7700000, 0x770000, 0x77000, 0x7700, 0x770, 0x0, 0x0, 0x777700, 0x7700770, 0x7770770, 0x7777770, 0x7707770, 0x7700770, 0x777700, 0x0, 0x77000, 0x77700, 0x77000, 0x77000, 0x77000, 0x77000, 0x7777770, 0x0, 0x777700, 0x7700770, 0x7700000, 0x770000, 0x77000, 0x7700, 0x7777770, 0x0, 0x777700, 0x7700770, 0x7700000, 0x777000, 0x7700000, 0x7700770, 0x777700, 0x0, 0x770000, 0x777000, 0x777700, 0x770770, 0x7777770, 0x770000, 0x770000, 0x0, 0x7777770, 0x770, 0x777770, 0x7700000, 0x7700000, 0x7700770, 0x777700, 0x0, 0x777000, 0x7700, 0x770, 0x777770, 0x7700770, 0x7700770, 0x777700, 0x0, 0x7777770, 0x7700000, 0x770000, 0x77000, 0x7700, 0x7700, 0x7700, 0x0, 0x777700, 0x7700770, 0x7700770, 0x777700, 0x7700770, 0x7700770, 0x777700, 0x0, 0x777700, 0x7700770, 0x7700770, 0x7777700, 0x7700000, 0x770000, 0x77700, 0x0, 0x0, 0x0, 0x77000, 0x77000, 0x0, 0x77000, 0x77000, 0x0, 0x0, 0x0, 0x77000, 0x77000, 0x0, 0x77000, 0x77000, 0x7700, 0x770000, 0x77000, 0x7700, 0x770, 0x7700, 0x77000, 0x770000, 0x0, 0x0, 0x0, 0x7777770, 0x0, 0x7777770, 0x0, 0x0, 0x0, 0x7700, 0x77000, 0x770000, 0x7700000, 0x770000, 0x77000, 0x7700, 0x0, 0x777700, 0x7700770, 0x770000, 0x77000, 0x77000, 0x0, 0x77000, 0x0, 0x777700, 0x7700770, 0x7770770, 0x7070770, 0x7770770, 0x770, 0x777700, 0x0, 0x777700, 0x7700770, 0x7700770, 0x7777770, 0x7700770, 0x7700770, 0x7700770, 0x0, 0x777770, 0x7700770, 0x7700770, 0x777770, 0x7700770, 0x7700770, 0x777770, 0x0, 0x777700, 0x7700770, 0x770, 0x770, 0x770, 0x7700770, 0x777700, 0x0, 0x77770, 0x770770, 0x7700770, 0x7700770, 0x7700770, 0x770770, 0x77770, 0x0, 0x7777770, 0x770, 0x770, 0x777770, 0x770, 0x770, 0x7777770, 0x0, 0x7777770, 0x770, 0x770, 0x777770, 0x770, 0x770, 0x770, 0x0, 0x777700, 0x7700770, 0x770, 0x7770770, 0x7700770, 0x7700770, 0x777700, 0x0, 0x7700770, 0x7700770, 0x7700770, 0x7777770, 0x7700770, 0x7700770, 0x7700770, 0x0, 0x7777770, 0x77000, 0x77000, 0x77000, 0x77000, 0x77000, 0x7777770, 0x0, 0x7777700, 0x770000, 0x770000, 0x770000, 0x770000, 0x770770, 0x77700, 0x0, 0x7700770, 0x770770, 0x77770, 0x7770, 0x77770, 0x770770, 0x7700770, 0x0, 0x770, 0x770, 0x770, 0x770, 0x770, 0x770, 0x7777770, 0x0, 0x77000770, 0x77707770, 0x77777770, 0x77070770, 0x77070770, 0x77000770, 0x77000770, 0x0, 0x7700770, 0x7700770, 0x7707770, 0x7777770, 0x7770770, 0x7700770, 0x7700770, 0x0, 0x777700, 0x7700770, 0x7700770, 0x7700770, 0x7700770, 0x7700770, 0x777700, 0x0, 0x777770, 0x7700770, 0x7700770, 0x777770, 0x770, 0x770, 0x770, 0x0, 0x777700, 0x7700770, 0x7700770, 0x7700770, 0x7070770, 0x770770, 0x7707700, 0x0, 0x777770, 0x7700770, 0x7700770, 0x777770, 0x770770, 0x7700770, 0x7700770, 0x0, 0x777700, 0x7700770, 0x770, 0x777700, 0x7700000, 0x7700770, 0x777700, 0x0, 0x7777770, 0x77000, 0x77000, 0x77000, 0x77000, 0x77000, 0x77000, 0x0, 0x7700770, 0x7700770, 0x7700770, 0x7700770, 0x7700770, 0x7700770, 0x777700, 0x0, 0x7700770, 0x7700770, 0x7700770, 0x7700770, 0x7700770, 0x777700, 0x77000, 0x0, 0x77000770, 0x77000770, 0x77070770, 0x77070770, 0x77777770, 0x77707770, 0x77000770, 0x0, 0x7700770, 0x7700770, 0x777700, 0x77000, 0x777700, 0x7700770, 0x7700770, 0x0, 0x7700770, 0x7700770, 0x7700770, 0x777700, 0x77000, 0x77000, 0x77000, 0x0, 0x7777770, 0x7700000, 0x770000, 0x77000, 0x7700, 0x770, 0x7777770, 0x0, 0x777770, 0x770, 0x770, 0x770, 0x770, 0x770, 0x777770, 0x0, 0x0, 0x770, 0x7700, 0x77000, 0x770000, 0x7700000, 0x0, 0x0, 0x7777700, 0x7700000, 0x7700000, 0x7700000, 0x7700000, 0x7700000, 0x7777700, 0x0, 0x777700, 0x7700770, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x77777777, 0x7700, 0x77000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x777700, 0x7700000, 0x7777700, 0x7700770, 0x7777700, 0x0, 0x770, 0x770, 0x777770, 0x7700770, 0x7700770, 0x7700770, 0x777770, 0x0, 0x0, 0x0, 0x777700, 0x7700770, 0x770, 0x7700770, 0x777700, 0x0, 0x7700000, 0x7700000, 0x7777700, 0x7700770, 0x7700770, 0x7700770, 0x7777700, 0x0, 0x0, 0x0, 0x777700, 0x7700770, 0x7777770, 0x770, 0x777700, 0x0, 0x777000, 0x7700, 0x7700, 0x777770, 0x7700, 0x7700, 0x7700, 0x0, 0x0, 0x0, 0x7777700, 0x7700770, 0x7700770, 0x7777700, 0x7700000, 0x777700, 0x770, 0x770, 0x777770, 0x7700770, 0x7700770, 0x7700770, 0x7700770, 0x0, 0x77000, 0x0, 0x77700, 0x77000, 0x77000, 0x77000, 0x777700, 0x0, 0x77000, 0x0, 0x77700, 0x77000, 0x77000, 0x77000, 0x77000, 0x7770, 0x770, 0x770, 0x7700770, 0x770770, 0x77770, 0x770770, 0x7700770, 0x0, 0x77700, 0x77000, 0x77000, 0x77000, 0x77000, 0x77000, 0x777700, 0x0, 0x0, 0x0, 0x7707700, 0x77777770, 0x77070770, 0x77070770, 0x77000770, 0x0, 0x0, 0x0, 0x777770, 0x7700770, 0x7700770, 0x7700770, 0x7700770, 0x0, 0x0, 0x0, 0x777700, 0x7700770, 0x7700770, 0x7700770, 0x777700, 0x0, 0x0, 0x0, 0x777770, 0x7700770, 0x7700770, 0x777770, 0x770, 0x770, 0x0, 0x0, 0x7777700, 0x7700770, 0x7700770, 0x7777700, 0x7700000, 0x77700000, 0x0, 0x0, 0x770770, 0x7707770, 0x770, 0x770, 0x770, 0x0, 0x0, 0x0, 0x7777700, 0x770, 0x777700, 0x7700000, 0x777770, 0x0, 0x7700, 0x7700, 0x777770, 0x7700, 0x7700, 0x7700, 0x777000, 0x0, 0x0, 0x0, 0x7700770, 0x7700770, 0x7700770, 0x7700770, 0x7777700, 0x0, 0x0, 0x0, 0x7700770, 0x7700770, 0x7700770, 0x777700, 0x77000, 0x0, 0x0, 0x0, 0x77000770, 0x77070770, 0x77070770, 0x77777770, 0x7707700, 0x0, 0x0, 0x0, 0x7700770, 0x777700, 0x77000, 0x777700, 0x7700770, 0x0, 0x0, 0x0, 0x7700770, 0x7700770, 0x7700770, 0x7777700, 0x7700000, 0x777700, 0x0, 0x0, 0x7777770, 0x770000, 0x77000, 0x7700, 0x7777770, 0x0, 0x770000, 0x77000, 0x77000, 0x7770, 0x77000, 0x77000, 0x770000, 0x0, 0x77000, 0x77000, 0x77000, 0x77000, 0x77000, 0x77000, 0x77000, 0x0, 0x7700, 0x77000, 0x77000, 0x7770000, 0x77000, 0x77000, 0x7700, 0x0, 0x70007700, 0x77070770, 0x7700070, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x77000000, 0x77000000, 0x7700000, 0x7700000, 0x7707770, 0x777000, 0x770000, 0x0, 0x777000, 0x77000770, 0x77070770, 0x77070770, 0x77777770, 0x77707770, 0x77000770, 0x0, 0x777000, 0x7707700, 0x0, 0x77070770, 0x77070770, 0x77777770, 0x7707700, 0x0, 0x7777777, 0x7007007, 0x7007007, 0x7007777, 0x7000007, 0x7000007, 0x7777777, 0x0, 0x7700770, 0x70077007, 0x70000007, 0x7000070, 0x70000007, 0x70077007, 0x7700770, 0x0, 0x77000, 0x7700770, 0x7000070, 0x7700770, 0x777700, 0x77000, 0x77000, 0x0, 0x77000, 0x7700770, 0x0, 0x7700770, 0x7700770, 0x7777700, 0x7700000, 0x777700, 0x77700000, 0x70000000, 0x7000000, 0x700770, 0x707007, 0x770, 0x7007, 0x770, 0x77000, 0x70700, 0x77770070, 0x70000007, 0x77770070, 0x70700, 0x77000, 0x0, 0x77000, 0x707000, 0x7007777, 0x70000007, 0x7007777, 0x707000, 0x77000, 0x0, 0x777700, 0x700700, 0x700700, 0x77700777, 0x7000070, 0x700700, 0x77000, 0x0, 0x77000, 0x700700, 0x7000070, 0x77700777, 0x700700, 0x700700, 0x777700, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x77077077, 0x77077077, 0x0, 0x70007777, 0x77077070, 0x70707070, 0x70007070, 0x0, 0x0, 0x0, 0x0, 0x77, 0x770077, 0x77000, 0x7700, 0x770, 0x77077077, 0x77077000, 0x0, 0x0, 0x0, 0x777700, 0x7777770, 0x7777770, 0x777700, 0x0, 0x0, 0x770000, 0x77000, 0x77000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x770000, 0x770000, 0x77000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x770000, 0x77000, 0x7700, 0x7700, 0x77000, 0x770000, 0x0, 0x0, 0x7700, 0x77000, 0x770000, 0x770000, 0x77000, 0x7700, 0x0, 0x77077000, 0x7707700, 0x7707700, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7707700, 0x7707700, 0x770770, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7707700, 0x7707700, 0x770770, 0x0, 0x0, 0x0, 0x777700, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x77777777, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7777770, 0x0, 0x0, 0x0, 0x0, 0x77707770, 0x770077, 0x770077, 0x77770077, 0x770077, 0x770077, 0x77707770, 0x0, 0x0, 0x0, 0x7770770, 0x77077077, 0x77777077, 0x77077, 0x7770770, 0x0, 0x77000, 0x77000, 0x7777770, 0x77000, 0x77000, 0x77000, 0x77000, 0x77000, 0x77000, 0x77000, 0x7777770, 0x77000, 0x7777770, 0x77000, 0x77000, 0x77000, 0x777700, 0x7700770, 0x770, 0x7707777, 0x7700770, 0x7700770, 0x7700770, 0x0, 0x7777700, 0x7700770, 0x7700770, 0x7707777, 0x7700770, 0x7700770, 0x7700770, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x77000, 0x0, 0x77000, 0x77000, 0x77000, 0x77000, 0x77000, 0x0, 0x70000, 0x7777700, 0x77070770, 0x70770, 0x77070770, 0x7777700, 0x70000, 0x0, 0x777000, 0x7707700, 0x7700, 0x777770, 0x7700, 0x7700, 0x7777770, 0x0, 0x0, 0x7700770, 0x777700, 0x7700770, 0x7700770, 0x777700, 0x7700770, 0x0, 0x7700770, 0x777700, 0x77000, 0x77000, 0x7777770, 0x77000, 0x77000, 0x0, 0x77000, 0x77000, 0x77000, 0x0, 0x77000, 0x77000, 0x77000, 0x0, 0x777700, 0x770, 0x777700, 0x7700770, 0x777700, 0x7700000, 0x777700, 0x0, 0x7700770, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x777700, 0x7000070, 0x70077007, 0x70000707, 0x70000707, 0x70077007, 0x7000070, 0x777700, 0x777000, 0x7700000, 0x7777000, 0x7707700, 0x7777000, 0x0, 0x7777700, 0x0, 0x0, 0x77007700, 0x7700770, 0x770077, 0x770077, 0x7700770, 0x77007700, 0x0, 0x7777770, 0x7700000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7777770, 0x0, 0x0, 0x0, 0x0, 0x777700, 0x7000070, 0x70077707, 0x70700707, 0x70077707, 0x70700707, 0x7000070, 0x777700, 0x7777770, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x777700, 0x7700770, 0x777700, 0x0, 0x0, 0x0, 0x0, 0x0, 0x77000, 0x77000, 0x7777770, 0x77000, 0x77000, 0x0, 0x7777770, 0x0, 0x77700, 0x700000, 0x77000, 0x700, 0x777700, 0x0, 0x0, 0x0, 0x77700, 0x700000, 0x77000, 0x700000, 0x77700, 0x0, 0x0, 0x0, 0x770000, 0x77000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x77007700, 0x77007700, 0x77007700, 0x77007700, 0x7777700, 0x770, 0x77000000, 0x7777700, 0x7707770, 0x7707770, 0x7707700, 0x7707700, 0x7777700, 0x0, 0x0, 0x0, 0x0, 0x77000, 0x77000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x77000, 0x7700, 0x7000, 0x7700, 0x7000, 0x7000, 0x77700, 0x0, 0x0, 0x0, 0x777000, 0x7707700, 0x7707700, 0x7707700, 0x777000, 0x0, 0x7777700, 0x0, 0x0, 0x770077, 0x7700770, 0x77007700, 0x77007700, 0x7700770, 0x770077, 0x0, 0x70, 0x77, 0x70, 0x70070, 0x70070, 0x7070000, 0x77770000, 0x7000000, 0x70, 0x77, 0x70, 0x77770070, 0x70000070, 0x77770000, 0x70000, 0x77770000, 0x777, 0x700, 0x777, 0x70700, 0x70777, 0x7070000, 0x77770000, 0x7000000, 0x77000, 0x0, 0x77000, 0x77000, 0x7700, 0x7700770, 0x777700, 0x0, 0x7700, 0x77000, 0x0, 0x777700, 0x7700770, 0x7777770, 0x7700770, 0x0, 0x770000, 0x77000, 0x0, 0x777700, 0x7700770, 0x7777770, 0x7700770, 0x0, 0x77000, 0x7700770, 0x0, 0x777700, 0x7700770, 0x7777770, 0x7700770, 0x0, 0x7707700, 0x770770, 0x0, 0x777700, 0x7700770, 0x7777770, 0x7700770, 0x0, 0x7700770, 0x7700770, 0x0, 0x777700, 0x7700770, 0x7777770, 0x7700770, 0x0, 0x777700, 0x7700770, 0x777700, 0x777700, 0x7700770, 0x7777770, 0x7700770, 0x0, 0x77777700, 0x7700770, 0x7700770, 0x77777770, 0x7700770, 0x7700770, 0x77700770, 0x0, 0x777700, 0x7700770, 0x770, 0x770, 0x7700770, 0x777700, 0x7700, 0x770, 0x7700, 0x77000, 0x7777770, 0x770, 0x777770, 0x770, 0x7777770, 0x0, 0x770000, 0x77000, 0x7777770, 0x770, 0x777770, 0x770, 0x7777770, 0x0, 0x777700, 0x7700770, 0x7777770, 0x770, 0x777770, 0x770, 0x7777770, 0x0, 0x7700770, 0x0, 0x7777770, 0x770, 0x777770, 0x770, 0x7777770, 0x0, 0x7700, 0x77000, 0x0, 0x7777770, 0x77000, 0x77000, 0x7777770, 0x0, 0x770000, 0x77000, 0x0, 0x7777770, 0x77000, 0x77000, 0x7777770, 0x0, 0x777700, 0x7700770, 0x0, 0x7777770, 0x77000, 0x77000, 0x7777770, 0x0, 0x7700770, 0x7700770, 0x0, 0x7777770, 0x77000, 0x77000, 0x7777770, 0x0, 0x77770, 0x770770, 0x7700770, 0x7707777, 0x7700770, 0x770770, 0x77770, 0x0, 0x7707700, 0x770770, 0x0, 0x7700770, 0x7707770, 0x7770770, 0x7700770, 0x0, 0x7700, 0x77000, 0x777700, 0x7700770, 0x7700770, 0x7700770, 0x777700, 0x0, 0x770000, 0x77000, 0x777700, 0x7700770, 0x7700770, 0x7700770, 0x777700, 0x0, 0x777700, 0x7700770, 0x777700, 0x7700770, 0x7700770, 0x7700770, 0x777700, 0x0, 0x7707700, 0x770770, 0x777700, 0x7700770, 0x7700770, 0x7700770, 0x777700, 0x0, 0x7700770, 0x0, 0x777700, 0x7700770, 0x7700770, 0x7700770, 0x777700, 0x0, 0x0, 0x77000770, 0x7707700, 0x777000, 0x777000, 0x7707700, 0x77000770, 0x0, 0x70777700, 0x7700770, 0x7770770, 0x7777770, 0x7707770, 0x7700770, 0x777707, 0x0, 0x7700, 0x77000, 0x7700770, 0x7700770, 0x7700770, 0x7700770, 0x777700, 0x0, 0x770000, 0x77000, 0x7700770, 0x7700770, 0x7700770, 0x7700770, 0x777700, 0x0, 0x777700, 0x7700770, 0x0, 0x7700770, 0x7700770, 0x7700770, 0x777700, 0x0, 0x7700770, 0x0, 0x7700770, 0x7700770, 0x7700770, 0x7700770, 0x777700, 0x0, 0x770000, 0x77000, 0x7700770, 0x7700770, 0x777700, 0x77000, 0x77000, 0x0, 0x7777, 0x770, 0x777770, 0x7700770, 0x777770, 0x770, 0x7777, 0x0, 0x777700, 0x7700770, 0x7700770, 0x770770, 0x7700770, 0x7700770, 0x770770, 0x77, 0x7700, 0x77000, 0x777700, 0x7700000, 0x7777700, 0x7700770, 0x7777700, 0x0, 0x770000, 0x77000, 0x777700, 0x7700000, 0x7777700, 0x7700770, 0x7777700, 0x0, 0x77000, 0x7700770, 0x777700, 0x7700000, 0x7777700, 0x7700770, 0x7777700, 0x0, 0x7707700, 0x770770, 0x777700, 0x7700000, 0x7777700, 0x7700770, 0x7777700, 0x0, 0x7700770, 0x0, 0x777700, 0x7700000, 0x7777700, 0x7700770, 0x7777700, 0x0, 0x777700, 0x7700770, 0x777700, 0x7700000, 0x7777700, 0x7700770, 0x7777700, 0x0, 0x0, 0x0, 0x77777700, 0x70770000, 0x77777700, 0x770770, 0x77777700, 0x0, 0x0, 0x0, 0x777700, 0x7700770, 0x770, 0x7700770, 0x777700, 0x770, 0x7700, 0x77000, 0x777700, 0x7700770, 0x7777770, 0x770, 0x777700, 0x0, 0x770000, 0x77000, 0x777700, 0x7700770, 0x7777770, 0x770, 0x777700, 0x0, 0x777700, 0x7700770, 0x777700, 0x7700770, 0x7777770, 0x770, 0x777700, 0x0, 0x7700770, 0x0, 0x777700, 0x7700770, 0x7777770, 0x770, 0x777700, 0x0, 0x7700, 0x77000, 0x0, 0x77700, 0x77000, 0x77000, 0x777700, 0x0, 0x770000, 0x77000, 0x0, 0x77700, 0x77000, 0x77000, 0x777700, 0x0, 0x777700, 0x7700770, 0x0, 0x77700, 0x77000, 0x77000, 0x777700, 0x0, 0x7700770, 0x0, 0x0, 0x77700, 0x77000, 0x77000, 0x777700, 0x0, 0x77000, 0x7777700, 0x770000, 0x7700000, 0x7777700, 0x7700770, 0x7777700, 0x0, 0x7707700, 0x770770, 0x0, 0x777770, 0x7700770, 0x7700770, 0x7700770, 0x0, 0x7700, 0x77000, 0x0, 0x777700, 0x7700770, 0x7700770, 0x777700, 0x0, 0x770000, 0x77000, 0x0, 0x777700, 0x7700770, 0x7700770, 0x777700, 0x0, 0x777700, 0x7700770, 0x0, 0x777700, 0x7700770, 0x7700770, 0x777700, 0x0, 0x7707700, 0x770770, 0x0, 0x777700, 0x7700770, 0x7700770, 0x777700, 0x0, 0x7700770, 0x0, 0x0, 0x777700, 0x7700770, 0x7700770, 0x777700, 0x0, 0x0, 0x77000, 0x0, 0x77777777, 0x0, 0x77000, 0x0, 0x0, 0x0, 0x7000000, 0x777700, 0x7770770, 0x7707770, 0x7700770, 0x777707, 0x0, 0x7700, 0x77000, 0x0, 0x7700770, 0x7700770, 0x7700770, 0x7777700, 0x0, 0x770000, 0x77000, 0x0, 0x7700770, 0x7700770, 0x7700770, 0x7777700, 0x0, 0x777700, 0x7700770, 0x0, 0x7700770, 0x7700770, 0x7700770, 0x7777700, 0x0, 0x7700770, 0x0, 0x0, 0x7700770, 0x7700770, 0x7700770, 0x7777700, 0x0, 0x770000, 0x77000, 0x7700770, 0x7700770, 0x7700770, 0x7777700, 0x7700000, 0x777700, 0x770, 0x770, 0x777770, 0x7700770, 0x777770, 0x770, 0x770, 0x0, 0x7700770, 0x0, 0x7700770, 0x7700770, 0x7700770, 0x7777700, 0x7700000, 0x777700}; + + +static void ian_scroll_screen(void){ + int i; + char *j; + char *screen_base = (char*)0x2000000;//1F88000; + for(i = 8; i < 480 ; i++) + for(j = screen_base + i*(640/2) ; j < screen_base + (i+1)*(640/2) ; j++) + *(j-(8*(640/2))) = *j; + for(i = 479 ; i >= 472 ; i--) + for(j = screen_base + i*(640/2) ; j < screen_base + (i+1)*(640/2) ; j++) + *j = 0; + +} + +static void ian_print(char *string){ + char *screen_base = (char*)0x2000000; + static int x, y, first, page; + int *temp; + int i; + + if(first == 0){ + first = 1; + for(i = 0 ; i < (640/2)*480 ; i++) screen_base[i] = 0; + } + + while(*string){ + if(*string==10){ + y++; + x = 0; + if(y > 59){ + y = 59; + ian_scroll_screen(); + } + } + else if(*string == 8){ + if(x) + x--; + } + else{ + if(x > 79){ + y++; + x = 0; + if(y > 59){ + y = 59; + ian_scroll_screen(); + } + } + + temp = (int *)(screen_base + ((640/2)*8*y) + (x * 4)); + for(i = 0 ; i < 8 ; i++){ + *temp = charset[i + (*string * 8)]; + temp += 640/8; + } + x++; + } + string++; + } +} + +static void ian_print_num(unsigned long value){ + int i; + char out[9]; + + for(i = 7; i >= 0 ; i--){ + out[i] = value & 0x0F; + out[i] = out[i]<10?out[i]+'0':out[i]+'A'-10; + value = value >> 4; + } + out[8] = 0; + + ian_print(out); + +} + +#endif diff -Nru a/include/asm-arm26/ide.h b/include/asm-arm26/ide.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/ide.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,75 @@ +/* + * linux/include/asm-arm/ide.h + * + * Copyright (C) 1994-1996 Linus Torvalds & authors + */ + +/* + * This file contains the i386 architecture specific IDE code. + */ + +#ifndef __ASMARM_IDE_H +#define __ASMARM_IDE_H + +#ifdef __KERNEL__ + +#ifndef MAX_HWIFS +#define MAX_HWIFS 4 +#endif + +#include <asm/irq.h> +#include <asm/mach-types.h> + +/* JMA 18.05.03 these will never be needed, but the kernel needs them to compile */ +#define __ide_mm_insw(port,addr,len) readsw(port,addr,len) +#define __ide_mm_insl(port,addr,len) readsl(port,addr,len) +#define __ide_mm_outsw(port,addr,len) writesw(port,addr,len) +#define __ide_mm_outsl(port,addr,len) writesl(port,addr,len) + +/* + * Set up a hw structure for a specified data port, control port and IRQ. + * This should follow whatever the default interface uses. + */ +static __inline__ void +ide_init_hwif_ports(hw_regs_t *hw, int data_port, int ctrl_port, int *irq) +{ + ide_ioreg_t reg = (ide_ioreg_t) data_port; + int i; + + for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) { + hw->io_ports[i] = reg; + reg += 1; + } + hw->io_ports[IDE_CONTROL_OFFSET] = (ide_ioreg_t) ctrl_port; + if (irq) + *irq = 0; +} + +/* + * This registers the standard ports for this architecture with the IDE + * driver. + */ +static __inline__ void ide_init_default_hwifs(void) +{ + if (machine_is_a5k()) { + hw_regs_t hw; + + memset(&hw, 0, sizeof(hw)); + + ide_init_hwif_ports(&hw, 0x1f0, 0x3f6, NULL); + hw.irq = IRQ_HARDDISK; + ide_register_hw(&hw,NULL); + } +} + + +/* + * We always use the new IDE port registering, + * so these are fixed here. + */ +#define ide_default_io_base(i) ((ide_ioreg_t)0) +#define ide_default_irq(b) (0) + +#endif /* __KERNEL__ */ + +#endif /* __ASMARM_IDE_H */ diff -Nru a/include/asm-arm26/io.h b/include/asm-arm26/io.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/io.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,419 @@ +/* + * linux/include/asm-arm/io.h + * + * Copyright (C) 1996-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Modifications: + * 16-Sep-1996 RMK Inlined the inx/outx functions & optimised for both + * constant addresses and variable addresses. + * 04-Dec-1997 RMK Moved a lot of this stuff to the new architecture + * specific IO header files. + * 27-Mar-1999 PJB Second parameter of memcpy_toio is const.. + * 04-Apr-1999 PJB Added check_signature. + * 12-Dec-1999 RMK More cleanups + * 18-Jun-2000 RMK Removed virt_to_* and friends definitions + */ +#ifndef __ASM_ARM_IO_H +#define __ASM_ARM_IO_H + +#ifdef __KERNEL__ + +#include <linux/config.h> +#include <linux/types.h> +#include <asm/byteorder.h> +#include <asm/memory.h> +#include <asm/hardware.h> + +/* + * Generic IO read/write. These perform native-endian accesses. Note + * that some architectures will want to re-define __raw_{read,write}w. + */ +extern void __raw_writesb(unsigned int addr, const void *data, int bytelen); +extern void __raw_writesw(unsigned int addr, const void *data, int wordlen); +extern void __raw_writesl(unsigned int addr, const void *data, int longlen); + +extern void __raw_readsb(unsigned int addr, void *data, int bytelen); +extern void __raw_readsw(unsigned int addr, void *data, int wordlen); +extern void __raw_readsl(unsigned int addr, void *data, int longlen); + +#define __raw_writeb(v,a) (*(volatile unsigned char *)(a) = (v)) +#define __raw_writew(v,a) (*(volatile unsigned short *)(a) = (v)) +#define __raw_writel(v,a) (*(volatile unsigned int *)(a) = (v)) + +#define __raw_readb(a) (*(volatile unsigned char *)(a)) +#define __raw_readw(a) (*(volatile unsigned short *)(a)) +#define __raw_readl(a) (*(volatile unsigned int *)(a)) + + +/* + * Bad read/write accesses... + */ +extern void __readwrite_bug(const char *fn); + +/* + * Now, pick up the machine-defined IO definitions + */ + +#define IO_SPACE_LIMIT 0xffffffff + +/* + * GCC is totally crap at loading/storing data. We try to persuade it + * to do the right thing by using these whereever possible instead of + * the above. + */ +#define __arch_base_getb(b,o) \ + ({ \ + unsigned int v, r = (b); \ + __asm__ __volatile__( \ + "ldrb %0, [%1, %2]" \ + : "=r" (v) \ + : "r" (r), "Ir" (o)); \ + v; \ + }) + +#define __arch_base_getl(b,o) \ + ({ \ + unsigned int v, r = (b); \ + __asm__ __volatile__( \ + "ldr %0, [%1, %2]" \ + : "=r" (v) \ + : "r" (r), "Ir" (o)); \ + v; \ + }) + +#define __arch_base_putb(v,b,o) \ + ({ \ + unsigned int r = (b); \ + __asm__ __volatile__( \ + "strb %0, [%1, %2]" \ + : \ + : "r" (v), "r" (r), "Ir" (o)); \ + }) + +#define __arch_base_putl(v,b,o) \ + ({ \ + unsigned int r = (b); \ + __asm__ __volatile__( \ + "str %0, [%1, %2]" \ + : \ + : "r" (v), "r" (r), "Ir" (o)); \ + }) + +/* + * We use two different types of addressing - PC style addresses, and ARM + * addresses. PC style accesses the PC hardware with the normal PC IO + * addresses, eg 0x3f8 for serial#1. ARM addresses are 0x80000000+ + * and are translated to the start of IO. Note that all addresses are + * shifted left! + */ +#define __PORT_PCIO(x) (!((x) & 0x80000000)) + +/* + * Dynamic IO functions - let the compiler + * optimize the expressions + */ +static inline void __outb (unsigned int value, unsigned int port) +{ + unsigned long temp; + __asm__ __volatile__( + "tst %2, #0x80000000\n\t" + "mov %0, %4\n\t" + "addeq %0, %0, %3\n\t" + "strb %1, [%0, %2, lsl #2] @ outb" + : "=&r" (temp) + : "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE) + : "cc"); +} + +static inline void __outw (unsigned int value, unsigned int port) +{ + unsigned long temp; + __asm__ __volatile__( + "tst %2, #0x80000000\n\t" + "mov %0, %4\n\t" + "addeq %0, %0, %3\n\t" + "str %1, [%0, %2, lsl #2] @ outw" + : "=&r" (temp) + : "r" (value|value<<16), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE) + : "cc"); +} + +static inline void __outl (unsigned int value, unsigned int port) +{ + unsigned long temp; + __asm__ __volatile__( + "tst %2, #0x80000000\n\t" + "mov %0, %4\n\t" + "addeq %0, %0, %3\n\t" + "str %1, [%0, %2, lsl #2] @ outl" + : "=&r" (temp) + : "r" (value), "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE) + : "cc"); +} + +#define DECLARE_DYN_IN(sz,fnsuffix,instr) \ +static inline unsigned sz __in##fnsuffix (unsigned int port) \ +{ \ + unsigned long temp, value; \ + __asm__ __volatile__( \ + "tst %2, #0x80000000\n\t" \ + "mov %0, %4\n\t" \ + "addeq %0, %0, %3\n\t" \ + "ldr" instr " %1, [%0, %2, lsl #2] @ in" #fnsuffix \ + : "=&r" (temp), "=r" (value) \ + : "r" (port), "Ir" (PCIO_BASE - IO_BASE), "Ir" (IO_BASE) \ + : "cc"); \ + return (unsigned sz)value; \ +} + +static inline unsigned int __ioaddr (unsigned int port) \ +{ \ + if (__PORT_PCIO(port)) \ + return (unsigned int)(PCIO_BASE + (port << 2)); \ + else \ + return (unsigned int)(IO_BASE + (port << 2)); \ +} + +#define DECLARE_IO(sz,fnsuffix,instr) \ + DECLARE_DYN_IN(sz,fnsuffix,instr) + +DECLARE_IO(char,b,"b") +DECLARE_IO(short,w,"") +DECLARE_IO(int,l,"") + +#undef DECLARE_IO +#undef DECLARE_DYN_IN + +/* + * Constant address IO functions + * + * These have to be macros for the 'J' constraint to work - + * +/-4096 immediate operand. + */ +#define __outbc(value,port) \ +({ \ + if (__PORT_PCIO((port))) \ + __asm__ __volatile__( \ + "strb %0, [%1, %2] @ outbc" \ + : : "r" (value), "r" (PCIO_BASE), "Jr" ((port) << 2)); \ + else \ + __asm__ __volatile__( \ + "strb %0, [%1, %2] @ outbc" \ + : : "r" (value), "r" (IO_BASE), "r" ((port) << 2)); \ +}) + +#define __inbc(port) \ +({ \ + unsigned char result; \ + if (__PORT_PCIO((port))) \ + __asm__ __volatile__( \ + "ldrb %0, [%1, %2] @ inbc" \ + : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2)); \ + else \ + __asm__ __volatile__( \ + "ldrb %0, [%1, %2] @ inbc" \ + : "=r" (result) : "r" (IO_BASE), "r" ((port) << 2)); \ + result; \ +}) + +#define __outwc(value,port) \ +({ \ + unsigned long v = value; \ + if (__PORT_PCIO((port))) \ + __asm__ __volatile__( \ + "str %0, [%1, %2] @ outwc" \ + : : "r" (v|v<<16), "r" (PCIO_BASE), "Jr" ((port) << 2)); \ + else \ + __asm__ __volatile__( \ + "str %0, [%1, %2] @ outwc" \ + : : "r" (v|v<<16), "r" (IO_BASE), "r" ((port) << 2)); \ +}) + +#define __inwc(port) \ +({ \ + unsigned short result; \ + if (__PORT_PCIO((port))) \ + __asm__ __volatile__( \ + "ldr %0, [%1, %2] @ inwc" \ + : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2)); \ + else \ + __asm__ __volatile__( \ + "ldr %0, [%1, %2] @ inwc" \ + : "=r" (result) : "r" (IO_BASE), "r" ((port) << 2)); \ + result & 0xffff; \ +}) + +#define __outlc(value,port) \ +({ \ + unsigned long v = value; \ + if (__PORT_PCIO((port))) \ + __asm__ __volatile__( \ + "str %0, [%1, %2] @ outlc" \ + : : "r" (v), "r" (PCIO_BASE), "Jr" ((port) << 2)); \ + else \ + __asm__ __volatile__( \ + "str %0, [%1, %2] @ outlc" \ + : : "r" (v), "r" (IO_BASE), "r" ((port) << 2)); \ +}) + +#define __inlc(port) \ +({ \ + unsigned long result; \ + if (__PORT_PCIO((port))) \ + __asm__ __volatile__( \ + "ldr %0, [%1, %2] @ inlc" \ + : "=r" (result) : "r" (PCIO_BASE), "Jr" ((port) << 2)); \ + else \ + __asm__ __volatile__( \ + "ldr %0, [%1, %2] @ inlc" \ + : "=r" (result) : "r" (IO_BASE), "r" ((port) << 2)); \ + result; \ +}) + +#define __ioaddrc(port) \ +({ \ + unsigned long addr; \ + if (__PORT_PCIO((port))) \ + addr = PCIO_BASE + ((port) << 2); \ + else \ + addr = IO_BASE + ((port) << 2); \ + addr; \ +}) + +#define inb(p) (__builtin_constant_p((p)) ? __inbc(p) : __inb(p)) +#define inw(p) (__builtin_constant_p((p)) ? __inwc(p) : __inw(p)) +#define inl(p) (__builtin_constant_p((p)) ? __inlc(p) : __inl(p)) +#define outb(v,p) (__builtin_constant_p((p)) ? __outbc(v,p) : __outb(v,p)) +#define outw(v,p) (__builtin_constant_p((p)) ? __outwc(v,p) : __outw(v,p)) +#define outl(v,p) (__builtin_constant_p((p)) ? __outlc(v,p) : __outl(v,p)) +#define __ioaddr(p) (__builtin_constant_p((p)) ? __ioaddr(p) : __ioaddrc(p)) + +/* JMA 18.02.03 added sb,sl from arm/io.h, changing io to ioaddr */ + +#define outsb(p,d,l) __raw_writesb(__ioaddr(p),d,l) +#define outsw(p,d,l) __raw_writesw(__ioaddr(p),d,l) +#define outsl(p,d,l) __raw_writesl(__ioaddr(p),d,l) + +#define insb(p,d,l) __raw_readsb(__ioaddr(p),d,l) +#define insw(p,d,l) __raw_readsw(__ioaddr(p),d,l) +#define insl(p,d,l) __raw_readsl(__ioaddr(p),d,l) + +#define insw(p,d,l) __raw_readsw(__ioaddr(p),d,l) +#define outsw(p,d,l) __raw_writesw(__ioaddr(p),d,l) + +#define readb(c) (__readwrite_bug("readb"),0) +#define readw(c) (__readwrite_bug("readw"),0) +#define readl(c) (__readwrite_bug("readl"),0) +#define writeb(v,c) __readwrite_bug("writeb") +#define writew(v,c) __readwrite_bug("writew") +#define writel(v,c) __readwrite_bug("writel") + +#define readsw(p,d,l) (__readwrite_bug("readsw"),0) +#define readsl(p,d,l) (__readwrite_bug("readsl"),0) +#define writesw(p,d,l) __readwrite_bug("writesw") +#define writesl(p,d,l) __readwrite_bug("writesl") + +/* the following macro is depreciated */ +#define ioaddr(port) __ioaddr((port)) + +/* + * No ioremap support here. + */ +#define __arch_ioremap(c,s,f,a) ((void *)(c)) +#define __arch_iounmap(c) do { } while (0) + + +#if defined(__arch_putb) || defined(__arch_putw) || defined(__arch_putl) || \ + defined(__arch_getb) || defined(__arch_getw) || defined(__arch_getl) +#warning machine class uses old __arch_putw or __arch_getw +#endif + +/* + * IO port access primitives + * ------------------------- + * + * The ARM doesn't have special IO access instructions; all IO is memory + * mapped. Note that these are defined to perform little endian accesses + * only. Their primary purpose is to access PCI and ISA peripherals. + * + * Note that for a big endian machine, this implies that the following + * big endian mode connectivity is in place, as described by numerious + * ARM documents: + * + * PCI: D0-D7 D8-D15 D16-D23 D24-D31 + * ARM: D24-D31 D16-D23 D8-D15 D0-D7 + * + * The machine specific io.h include defines __io to translate an "IO" + * address to a memory address. + * + * Note that we prevent GCC re-ordering or caching values in expressions + * by introducing sequence points into the in*() definitions. Note that + * __raw_* do not guarantee this behaviour. + */ +/* +#define outsb(p,d,l) __raw_writesb(__io(p),d,l) +#define outsw(p,d,l) __raw_writesw(__io(p),d,l) + +#define insb(p,d,l) __raw_readsb(__io(p),d,l) +#define insw(p,d,l) __raw_readsw(__io(p),d,l) +*/ +#define outb_p(val,port) outb((val),(port)) +#define outw_p(val,port) outw((val),(port)) +#define inb_p(port) inb((port)) +#define inw_p(port) inw((port)) +#define inl_p(port) inl((port)) + +#define outsb_p(port,from,len) outsb(port,from,len) +#define outsw_p(port,from,len) outsw(port,from,len) +#define insb_p(port,to,len) insb(port,to,len) +#define insw_p(port,to,len) insw(port,to,len) + +/* + * String version of IO memory access ops: + */ +extern void _memcpy_fromio(void *, unsigned long, size_t); +extern void _memcpy_toio(unsigned long, const void *, size_t); +extern void _memset_io(unsigned long, int, size_t); + +/* + * ioremap and friends. + * + * ioremap takes a PCI memory address, as specified in + * linux/Documentation/IO-mapping.txt. + */ +extern void * __ioremap(unsigned long, size_t, unsigned long, unsigned long); +extern void __iounmap(void *addr); + +#ifndef __arch_ioremap +#define ioremap(cookie,size) __ioremap(cookie,size,0,1) +#define ioremap_nocache(cookie,size) __ioremap(cookie,size,0,1) +#define iounmap(cookie) __iounmap(cookie) +#else +#define ioremap(cookie,size) __arch_ioremap((cookie),(size),0,1) +#define ioremap_nocache(cookie,size) __arch_ioremap((cookie),(size),0,1) +#define iounmap(cookie) __arch_iounmap(cookie) +#endif + +/* + * DMA-consistent mapping functions. These allocate/free a region of + * uncached, unwrite-buffered mapped memory space for use with DMA + * devices. This is the "generic" version. The PCI specific version + * is in pci.h + */ +extern void *consistent_alloc(int gfp, size_t size, dma_addr_t *handle); +extern void consistent_free(void *vaddr, size_t size, dma_addr_t handle); +extern void consistent_sync(void *vaddr, size_t size, int rw); + +/* + * can the hardware map this into one segment or not, given no other + * constraints. + */ +#define BIOVEC_MERGEABLE(vec1, vec2) \ + ((bvec_to_phys((vec1)) + (vec1)->bv_len) == bvec_to_phys((vec2))) + +#endif /* __KERNEL__ */ +#endif /* __ASM_ARM_IO_H */ diff -Nru a/include/asm-arm26/ioc.h b/include/asm-arm26/ioc.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/ioc.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,72 @@ +/* + * linux/include/asm-arm/hardware/ioc.h + * + * Copyright (C) Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Use these macros to read/write the IOC. All it does is perform the actual + * read/write. + */ +#ifndef __ASMARM_HARDWARE_IOC_H +#define __ASMARM_HARDWARE_IOC_H + +#ifndef __ASSEMBLY__ + +/* + * We use __raw_base variants here so that we give the compiler the + * chance to keep IOC_BASE in a register. + */ +#define ioc_readb(off) __raw_readb(IOC_BASE + (off)) +#define ioc_writeb(val,off) __raw_writeb(val, IOC_BASE + (off)) + +#endif + +#define IOC_CONTROL (0x00) +#define IOC_KARTTX (0x04) +#define IOC_KARTRX (0x04) + +#define IOC_IRQSTATA (0x10) +#define IOC_IRQREQA (0x14) +#define IOC_IRQCLRA (0x14) +#define IOC_IRQMASKA (0x18) + +#define IOC_IRQSTATB (0x20) +#define IOC_IRQREQB (0x24) +#define IOC_IRQMASKB (0x28) + +#define IOC_FIQSTAT (0x30) +#define IOC_FIQREQ (0x34) +#define IOC_FIQMASK (0x38) + +#define IOC_T0CNTL (0x40) +#define IOC_T0LTCHL (0x40) +#define IOC_T0CNTH (0x44) +#define IOC_T0LTCHH (0x44) +#define IOC_T0GO (0x48) +#define IOC_T0LATCH (0x4c) + +#define IOC_T1CNTL (0x50) +#define IOC_T1LTCHL (0x50) +#define IOC_T1CNTH (0x54) +#define IOC_T1LTCHH (0x54) +#define IOC_T1GO (0x58) +#define IOC_T1LATCH (0x5c) + +#define IOC_T2CNTL (0x60) +#define IOC_T2LTCHL (0x60) +#define IOC_T2CNTH (0x64) +#define IOC_T2LTCHH (0x64) +#define IOC_T2GO (0x68) +#define IOC_T2LATCH (0x6c) + +#define IOC_T3CNTL (0x70) +#define IOC_T3LTCHL (0x70) +#define IOC_T3CNTH (0x74) +#define IOC_T3LTCHH (0x74) +#define IOC_T3GO (0x78) +#define IOC_T3LATCH (0x7c) + +#endif diff -Nru a/include/asm-arm26/ioctl.h b/include/asm-arm26/ioctl.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/ioctl.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,74 @@ +/* + * linux/ioctl.h for Linux by H.H. Bergman. + */ + +#ifndef _ASMARM_IOCTL_H +#define _ASMARM_IOCTL_H + +/* ioctl command encoding: 32 bits total, command in lower 16 bits, + * size of the parameter structure in the lower 14 bits of the + * upper 16 bits. + * Encoding the size of the parameter structure in the ioctl request + * is useful for catching programs compiled with old versions + * and to avoid overwriting user space outside the user buffer area. + * The highest 2 bits are reserved for indicating the ``access mode''. + * NOTE: This limits the max parameter size to 16kB -1 ! + */ + +/* + * The following is for compatibility across the various Linux + * platforms. The i386 ioctl numbering scheme doesn't really enforce + * a type field. De facto, however, the top 8 bits of the lower 16 + * bits are indeed used as a type field, so we might just as well make + * this explicit here. Please be sure to use the decoding macros + * below from now on. + */ +#define _IOC_NRBITS 8 +#define _IOC_TYPEBITS 8 +#define _IOC_SIZEBITS 14 +#define _IOC_DIRBITS 2 + +#define _IOC_NRMASK ((1 << _IOC_NRBITS)-1) +#define _IOC_TYPEMASK ((1 << _IOC_TYPEBITS)-1) +#define _IOC_SIZEMASK ((1 << _IOC_SIZEBITS)-1) +#define _IOC_DIRMASK ((1 << _IOC_DIRBITS)-1) + +#define _IOC_NRSHIFT 0 +#define _IOC_TYPESHIFT (_IOC_NRSHIFT+_IOC_NRBITS) +#define _IOC_SIZESHIFT (_IOC_TYPESHIFT+_IOC_TYPEBITS) +#define _IOC_DIRSHIFT (_IOC_SIZESHIFT+_IOC_SIZEBITS) + +/* + * Direction bits. + */ +#define _IOC_NONE 0U +#define _IOC_WRITE 1U +#define _IOC_READ 2U + +#define _IOC(dir,type,nr,size) \ + (((dir) << _IOC_DIRSHIFT) | \ + ((type) << _IOC_TYPESHIFT) | \ + ((nr) << _IOC_NRSHIFT) | \ + ((size) << _IOC_SIZESHIFT)) + +/* used to create numbers */ +#define _IO(type,nr) _IOC(_IOC_NONE,(type),(nr),0) +#define _IOR(type,nr,size) _IOC(_IOC_READ,(type),(nr),sizeof(size)) +#define _IOW(type,nr,size) _IOC(_IOC_WRITE,(type),(nr),sizeof(size)) +#define _IOWR(type,nr,size) _IOC(_IOC_READ|_IOC_WRITE,(type),(nr),sizeof(size)) + +/* used to decode ioctl numbers.. */ +#define _IOC_DIR(nr) (((nr) >> _IOC_DIRSHIFT) & _IOC_DIRMASK) +#define _IOC_TYPE(nr) (((nr) >> _IOC_TYPESHIFT) & _IOC_TYPEMASK) +#define _IOC_NR(nr) (((nr) >> _IOC_NRSHIFT) & _IOC_NRMASK) +#define _IOC_SIZE(nr) (((nr) >> _IOC_SIZESHIFT) & _IOC_SIZEMASK) + +/* ...and for the drivers/sound files... */ + +#define IOC_IN (_IOC_WRITE << _IOC_DIRSHIFT) +#define IOC_OUT (_IOC_READ << _IOC_DIRSHIFT) +#define IOC_INOUT ((_IOC_WRITE|_IOC_READ) << _IOC_DIRSHIFT) +#define IOCSIZE_MASK (_IOC_SIZEMASK << _IOC_SIZESHIFT) +#define IOCSIZE_SHIFT (_IOC_SIZESHIFT) + +#endif /* _ASMARM_IOCTL_H */ diff -Nru a/include/asm-arm26/ioctls.h b/include/asm-arm26/ioctls.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/ioctls.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,81 @@ +#ifndef __ASM_ARM_IOCTLS_H +#define __ASM_ARM_IOCTLS_H + +#include <asm/ioctl.h> + +/* 0x54 is just a magic number to make these relatively unique ('T') */ + +#define TCGETS 0x5401 +#define TCSETS 0x5402 +#define TCSETSW 0x5403 +#define TCSETSF 0x5404 +#define TCGETA 0x5405 +#define TCSETA 0x5406 +#define TCSETAW 0x5407 +#define TCSETAF 0x5408 +#define TCSBRK 0x5409 +#define TCXONC 0x540A +#define TCFLSH 0x540B +#define TIOCEXCL 0x540C +#define TIOCNXCL 0x540D +#define TIOCSCTTY 0x540E +#define TIOCGPGRP 0x540F +#define TIOCSPGRP 0x5410 +#define TIOCOUTQ 0x5411 +#define TIOCSTI 0x5412 +#define TIOCGWINSZ 0x5413 +#define TIOCSWINSZ 0x5414 +#define TIOCMGET 0x5415 +#define TIOCMBIS 0x5416 +#define TIOCMBIC 0x5417 +#define TIOCMSET 0x5418 +#define TIOCGSOFTCAR 0x5419 +#define TIOCSSOFTCAR 0x541A +#define FIONREAD 0x541B +#define TIOCINQ FIONREAD +#define TIOCLINUX 0x541C +#define TIOCCONS 0x541D +#define TIOCGSERIAL 0x541E +#define TIOCSSERIAL 0x541F +#define TIOCPKT 0x5420 +#define FIONBIO 0x5421 +#define TIOCNOTTY 0x5422 +#define TIOCSETD 0x5423 +#define TIOCGETD 0x5424 +#define TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ +#define TIOCTTYGSTRUCT 0x5426 /* For debugging only */ +#define TIOCSBRK 0x5427 /* BSD compatibility */ +#define TIOCCBRK 0x5428 /* BSD compatibility */ +#define TIOCGSID 0x5429 /* Return the session ID of FD */ +#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ +#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ + +#define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ +#define FIOCLEX 0x5451 +#define FIOASYNC 0x5452 +#define TIOCSERCONFIG 0x5453 +#define TIOCSERGWILD 0x5454 +#define TIOCSERSWILD 0x5455 +#define TIOCGLCKTRMIOS 0x5456 +#define TIOCSLCKTRMIOS 0x5457 +#define TIOCSERGSTRUCT 0x5458 /* For debugging only */ +#define TIOCSERGETLSR 0x5459 /* Get line status register */ +#define TIOCSERGETMULTI 0x545A /* Get multiport config */ +#define TIOCSERSETMULTI 0x545B /* Set multiport config */ + +#define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ +#define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ +#define FIOQSIZE 0x545E + +/* Used for packet mode */ +#define TIOCPKT_DATA 0 +#define TIOCPKT_FLUSHREAD 1 +#define TIOCPKT_FLUSHWRITE 2 +#define TIOCPKT_STOP 4 +#define TIOCPKT_START 8 +#define TIOCPKT_NOSTOP 16 +#define TIOCPKT_DOSTOP 32 + +#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ + +#endif diff -Nru a/include/asm-arm26/ipc.h b/include/asm-arm26/ipc.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/ipc.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,28 @@ +#ifndef __ASMARM_IPC_H +#define __ASMARM_IPC_H + +/* + * These are used to wrap system calls on ARM. + * + * See arch/arm/kernel/sys-arm.c for ugly details.. + */ +struct ipc_kludge { + struct msgbuf *msgp; + long msgtyp; +}; + +#define SEMOP 1 +#define SEMGET 2 +#define SEMCTL 3 +#define MSGSND 11 +#define MSGRCV 12 +#define MSGGET 13 +#define MSGCTL 14 +#define SHMAT 21 +#define SHMDT 22 +#define SHMGET 23 +#define SHMCTL 24 + +#define IPCCALL(version,op) ((version)<<16 | (op)) + +#endif diff -Nru a/include/asm-arm26/ipcbuf.h b/include/asm-arm26/ipcbuf.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/ipcbuf.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,29 @@ +#ifndef __ASMARM_IPCBUF_H +#define __ASMARM_IPCBUF_H + +/* + * The ipc64_perm structure for arm architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 32-bit mode_t and seq + * - 2 miscellaneous 32-bit values + */ + +struct ipc64_perm +{ + __kernel_key_t key; + __kernel_uid32_t uid; + __kernel_gid32_t gid; + __kernel_uid32_t cuid; + __kernel_gid32_t cgid; + __kernel_mode_t mode; + unsigned short __pad1; + unsigned short seq; + unsigned short __pad2; + unsigned long __unused1; + unsigned long __unused2; +}; + +#endif /* __ASMARM_IPCBUF_H */ diff -Nru a/include/asm-arm26/irq.h b/include/asm-arm26/irq.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/irq.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,50 @@ +#ifndef __ASM_ARM_IRQ_H +#define __ASM_ARM_IRQ_H + +#include <asm/sysirq.h> + +#ifndef NR_IRQS +#define NR_IRQS 128 +#endif + + +/* JMA 18.05.02 Copied off arch/arm/irq.h */ +#ifndef irq_canonicalize +#define irq_canonicalize(i) (i) +#endif + + +/* + * Use this value to indicate lack of interrupt + * capability + */ +#ifndef NO_IRQ +#define NO_IRQ ((unsigned int)(-1)) +#endif + +struct irqaction; + +#define disable_irq_nosync(i) disable_irq(i) + +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + +#define __IRQT_FALEDGE (1 << 0) +#define __IRQT_RISEDGE (1 << 1) +#define __IRQT_LOWLVL (1 << 2) +#define __IRQT_HIGHLVL (1 << 3) + +#define IRQT_NOEDGE (0) +#define IRQT_RISING (__IRQT_RISEDGE) +#define IRQT_FALLING (__IRQT_FALEDGE) +#define IRQT_BOTHEDGE (__IRQT_RISEDGE|__IRQT_FALEDGE) +#define IRQT_LOW (__IRQT_LOWLVL) +#define IRQT_HIGH (__IRQT_HIGHLVL) +#define IRQT_PROBE (1 << 4) + +int set_irq_type(unsigned int irq, unsigned int type); + +int setup_irq(unsigned int, struct irqaction *); + +#endif + diff -Nru a/include/asm-arm26/irqchip.h b/include/asm-arm26/irqchip.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/irqchip.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,118 @@ +/* + * linux/include/asm-arm/mach/irq.h + * + * Copyright (C) 1995-2000 Russell King. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_ARM_MACH_IRQ_H +#define __ASM_ARM_MACH_IRQ_H + +struct irqdesc; +struct pt_regs; +struct seq_file; + +typedef void (*irq_handler_t)(unsigned int, struct irqdesc *, struct pt_regs *); +typedef void (*irq_control_t)(unsigned int); + +struct irqchip { + /* + * Acknowledge the IRQ. + * If this is a level-based IRQ, then it is expected to mask the IRQ + * as well. + */ + void (*ack)(unsigned int); + /* + * Mask the IRQ in hardware. + */ + void (*mask)(unsigned int); + /* + * Unmask the IRQ in hardware. + */ + void (*unmask)(unsigned int); + /* + * Re-run the IRQ + */ + void (*rerun)(unsigned int); + /* + * Set the type of the IRQ. + */ + int (*type)(unsigned int, unsigned int); +}; + +struct irqdesc { + irq_handler_t handle; + struct irqchip *chip; + struct irqaction *action; + + unsigned int enabled : 1; /* IRQ is currently enabled */ + unsigned int triggered: 1; /* IRQ has occurred */ + unsigned int running : 1; /* IRQ is running */ + unsigned int pending : 1; /* IRQ is pending */ + unsigned int probing : 1; /* IRQ in use for a probe */ + unsigned int probe_ok : 1; /* IRQ can be used for probe */ + unsigned int valid : 1; /* IRQ claimable */ + unsigned int noautoenable : 1; /* don't automatically enable IRQ */ + unsigned int unused :23; + unsigned int depth; /* disable depth */ + + /* + * IRQ lock detection + */ + unsigned int lck_cnt; + unsigned int lck_pc; + unsigned int lck_jif; +}; + +extern struct irqdesc irq_desc[]; + +/* + * This is internal. Do not use it. + */ +extern void (*init_arch_irq)(void); +extern void init_FIQ(void); +extern int show_fiq_list(struct seq_file *, void *); +void __set_irq_handler(unsigned int irq, irq_handler_t, int); + +/* + * External stuff. + */ +#define set_irq_handler(irq,handler) __set_irq_handler(irq,handler,0) +#define set_irq_chained_handler(irq,handler) __set_irq_handler(irq,handler,1) + +void set_irq_chip(unsigned int irq, struct irqchip *); +void set_irq_flags(unsigned int irq, unsigned int flags); + +#ifdef not_yet +/* + * This is to be used by the top-level machine IRQ decoder only. + */ +static inline void call_irq(struct pt_regs *regs, unsigned int irq) +{ + struct irqdesc *desc = irq_desc + irq; + + spin_lock(&irq_controller_lock); + desc->handle(irq, desc, regs); + spin_unlock(&irq_controller_lock); + + if (softirq_pending(smp_processor_id())) + do_softirq(); +} +#endif + +#define IRQF_VALID (1 << 0) +#define IRQF_PROBE (1 << 1) +#define IRQF_NOAUTOEN (1 << 2) + +/* + * Built-in IRQ handlers. + */ +void do_level_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs); +void do_edge_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs); +void do_simple_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs); +void do_bad_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs); +void dummy_mask_unmask_irq(unsigned int irq); + +#endif diff -Nru a/include/asm-arm26/keyboard.h.old b/include/asm-arm26/keyboard.h.old --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/keyboard.h.old Mon Jun 9 23:16:20 2003 @@ -0,0 +1,78 @@ +/* + * linux/include/asm-arm/keyboard.h + * + * Copyright (C) 1998 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Keyboard driver definitions for ARM + */ +#ifndef __ASM_ARM_KEYBOARD_H +#define __ASM_ARM_KEYBOARD_H + +#include <linux/kd.h> +#include <linux/pm.h> + +/* + * We provide a unified keyboard interface when in VC_MEDIUMRAW + * mode. This means that all keycodes must be common between + * all supported keyboards. This unfortunately puts us at odds + * with the PC keyboard interface chip... but we can't do anything + * about that now. + */ +#ifdef __KERNEL__ + +extern int (*k_setkeycode)(unsigned int, unsigned int); +extern int (*k_getkeycode)(unsigned int); +extern int (*k_translate)(unsigned char, unsigned char *, char); +extern char (*k_unexpected_up)(unsigned char); +extern void (*k_leds)(unsigned char); + + +static inline int kbd_setkeycode(unsigned int sc, unsigned int kc) +{ + int ret = -EINVAL; + + if (k_setkeycode) + ret = k_setkeycode(sc, kc); + + return ret; +} + +static inline int kbd_getkeycode(unsigned int sc) +{ + int ret = -EINVAL; + + if (k_getkeycode) + ret = k_getkeycode(sc); + + return ret; +} + +static inline void kbd_leds(unsigned char leds) +{ + if (k_leds) + k_leds(leds); +} + +extern int k_sysrq_key; +extern unsigned char *k_sysrq_xlate; + +#define SYSRQ_KEY k_sysrq_key +#define kbd_sysrq_xlate k_sysrq_xlate +#define kbd_translate k_translate +#define kbd_unexpected_up k_unexpected_up + +#define NR_SCANCODES 128 + +extern int a5kkbd_init_hw(void); + +#define kbd_disable_irq() disable_irq(IRQ_KEYBOARDRX) +#define kbd_enable_irq() enable_irq(IRQ_KEYBOARDRX) +#define kbd_init_hw() a5kkbd_init_hw() + +#endif /* __KERNEL__ */ + +#endif /* __ASM_ARM_KEYBOARD_H */ diff -Nru a/include/asm-arm26/kmap_types.h b/include/asm-arm26/kmap_types.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/kmap_types.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,12 @@ +#ifndef __ARM_KMAP_TYPES_H +#define __ARM_KMAP_TYPES_H + +/* + * This is the "bare minimum". AIO seems to require this. + */ +enum km_type { + KM_IRQ0, + KM_USER1 +}; + +#endif diff -Nru a/include/asm-arm26/leds.h b/include/asm-arm26/leds.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/leds.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,51 @@ +/* + * linux/include/asm-arm/leds.h + * + * Copyright (C) 1998 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Event-driven interface for LEDs on machines + * Added led_start and led_stop- Alex Holden, 28th Dec 1998. + */ +#ifndef ASM_ARM_LEDS_H +#define ASM_ARM_LEDS_H + +#include <linux/config.h> + +typedef enum { + led_idle_start, + led_idle_end, + led_timer, + led_start, + led_stop, + led_claim, /* override idle & timer leds */ + led_release, /* restore idle & timer leds */ + led_start_timer_mode, + led_stop_timer_mode, + led_green_on, + led_green_off, + led_amber_on, + led_amber_off, + led_red_on, + led_red_off, + led_blue_on, + led_blue_off, + /* + * I want this between led_timer and led_start, but + * someone has decided to export this to user space + */ + led_halted +} led_event_t; + +/* Use this routine to handle LEDs */ + +#ifdef CONFIG_LEDS +extern void (*leds_event)(led_event_t); +#else +#define leds_event(e) +#endif + +#endif diff -Nru a/include/asm-arm26/limits.h b/include/asm-arm26/limits.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/limits.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,11 @@ +#ifndef __ASM_PIPE_H +#define __ASM_PIPE_H + +#ifndef PAGE_SIZE +#include <asm/page.h> +#endif + +#define PIPE_BUF PAGE_SIZE + +#endif + diff -Nru a/include/asm-arm26/linkage.h b/include/asm-arm26/linkage.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/linkage.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,7 @@ +#ifndef __ASM_LINKAGE_H +#define __ASM_LINKAGE_H + +#define __ALIGN .align 0 +#define __ALIGN_STR ".align 0" + +#endif diff -Nru a/include/asm-arm26/linux_logo.h b/include/asm-arm26/linux_logo.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/linux_logo.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,19 @@ +/* + * linux/include/asm-arm/linux_logo.h + * + * Copyright (C) 1998 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Linux console driver logo definitions for ARM + */ + +#include <linux/init.h> +#include <linux/version.h> + +#define linux_logo_banner "ARM Linux version " UTS_RELEASE + +#include <linux/linux_logo.h> + diff -Nru a/include/asm-arm26/locks.h b/include/asm-arm26/locks.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/locks.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,161 @@ +/* + * linux/include/asm-arm/proc-armo/locks.h + * + * Copyright (C) 2000 Russell King + * Fixes for 26 bit machines, (C) 2000 Dave Gilbert + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Interrupt safe locking assembler. + */ +#ifndef __ASM_PROC_LOCKS_H +#define __ASM_PROC_LOCKS_H + +/* Decrements by 1, fails if value < 0 */ +#define __down_op(ptr,fail) \ + ({ \ + __asm__ __volatile__ ( \ + "@ atomic down operation\n" \ +" mov ip, pc\n" \ +" orr lr, ip, #0x08000000\n" \ +" teqp lr, #0\n" \ +" ldr lr, [%0]\n" \ +" and ip, ip, #0x0c000003\n" \ +" subs lr, lr, #1\n" \ +" str lr, [%0]\n" \ +" orrmi ip, ip, #0x80000000 @ set N\n" \ +" teqp ip, #0\n" \ +" movmi ip, %0\n" \ +" blmi " #fail \ + : \ + : "r" (ptr) \ + : "ip", "lr", "cc"); \ + }) + +#define __down_op_ret(ptr,fail) \ + ({ \ + unsigned int result; \ + __asm__ __volatile__ ( \ +" @ down_op_ret\n" \ +" mov ip, pc\n" \ +" orr lr, ip, #0x08000000\n" \ +" teqp lr, #0\n" \ +" ldr lr, [%1]\n" \ +" and ip, ip, #0x0c000003\n" \ +" subs lr, lr, #1\n" \ +" str lr, [%1]\n" \ +" orrmi ip, ip, #0x80000000 @ set N\n" \ +" teqp ip, #0\n" \ +" movmi ip, %1\n" \ +" movpl ip, #0\n" \ +" blmi " #fail "\n" \ +" mov %0, ip" \ + : "=&r" (result) \ + : "r" (ptr) \ + : "ip", "lr", "cc"); \ + result; \ + }) + +#define __up_op(ptr,wake) \ + ({ \ + __asm__ __volatile__ ( \ + "@ up_op\n" \ +" mov ip, pc\n" \ +" orr lr, ip, #0x08000000\n" \ +" teqp lr, #0\n" \ +" ldr lr, [%0]\n" \ +" and ip, ip, #0x0c000003\n" \ +" adds lr, lr, #1\n" \ +" str lr, [%0]\n" \ +" orrle ip, ip, #0x80000000 @ set N - should this be mi ??? DAG ! \n" \ +" teqp ip, #0\n" \ +" movmi ip, %0\n" \ +" blmi " #wake \ + : \ + : "r" (ptr) \ + : "ip", "lr", "cc"); \ + }) + +/* + * The value 0x01000000 supports up to 128 processors and + * lots of processes. BIAS must be chosen such that sub'ing + * BIAS once per CPU will result in the long remaining + * negative. + */ +#define RW_LOCK_BIAS 0x01000000 +#define RW_LOCK_BIAS_STR "0x01000000" + +/* Decrements by RW_LOCK_BIAS rather than 1, fails if value != 0 */ +#define __down_op_write(ptr,fail) \ + ({ \ + __asm__ __volatile__( \ + "@ down_op_write\n" \ +" mov ip, pc\n" \ +" orr lr, ip, #0x08000000\n" \ +" teqp lr, #0\n" \ +" and ip, ip, #0x0c000003\n" \ +\ +" ldr lr, [%0]\n" \ +" subs lr, lr, %1\n" \ +" str lr, [%0]\n" \ +\ +" orreq ip, ip, #0x40000000 @ set Z \n"\ +" teqp ip, #0\n" \ +" movne ip, %0\n" \ +" blne " #fail \ + : \ + : "r" (ptr), "I" (RW_LOCK_BIAS) \ + : "ip", "lr", "cc"); \ + }) + +/* Increments by RW_LOCK_BIAS, wakes if value >= 0 */ +#define __up_op_write(ptr,wake) \ + ({ \ + __asm__ __volatile__( \ + "@ up_op_read\n" \ +" mov ip, pc\n" \ +" orr lr, ip, #0x08000000\n" \ +" teqp lr, #0\n" \ +\ +" ldr lr, [%0]\n" \ +" and ip, ip, #0x0c000003\n" \ +" adds lr, lr, %1\n" \ +" str lr, [%0]\n" \ +\ +" orrcs ip, ip, #0x20000000 @ set C\n" \ +" teqp ip, #0\n" \ +" movcs ip, %0\n" \ +" blcs " #wake \ + : \ + : "r" (ptr), "I" (RW_LOCK_BIAS) \ + : "ip", "lr", "cc"); \ + }) + +#define __down_op_read(ptr,fail) \ + __down_op(ptr, fail) + +#define __up_op_read(ptr,wake) \ + ({ \ + __asm__ __volatile__( \ + "@ up_op_read\n" \ +" mov ip, pc\n" \ +" orr lr, ip, #0x08000000\n" \ +" teqp lr, #0\n" \ +\ +" ldr lr, [%0]\n" \ +" and ip, ip, #0x0c000003\n" \ +" adds lr, lr, %1\n" \ +" str lr, [%0]\n" \ +\ +" orreq ip, ip, #0x40000000 @ Set Z \n" \ +" teqp ip, #0\n" \ +" moveq ip, %0\n" \ +" bleq " #wake \ + : \ + : "r" (ptr), "I" (1) \ + : "ip", "lr", "cc"); \ + }) + +#endif diff -Nru a/include/asm-arm26/mach-types.h b/include/asm-arm26/mach-types.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/mach-types.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,36 @@ +/* + * Unlike ARM32 this is NOT automatically generated. DONT delete it + */ + +#ifndef __ASM_ARM_MACH_TYPE_H +#define __ASM_ARM_MACH_TYPE_H + +#include <linux/config.h> + +#ifndef __ASSEMBLY__ +extern unsigned int __machine_arch_type; +#endif + +#define MACH_TYPE_ARCHIMEDES 10 +#define MACH_TYPE_A5K 11 + +#ifdef CONFIG_ARCH_ARC +# define machine_arch_type MACH_TYPE_ARCHIMEDES +# define machine_is_archimedes() (machine_arch_type == MACH_TYPE_ARCHIMEDES) +#else +# define machine_is_archimedes() (0) +#endif + +#ifdef CONFIG_ARCH_A5K +# define machine_arch_type MACH_TYPE_A5K +# define machine_is_a5k() (machine_arch_type == MACH_TYPE_A5K) +#else +# define machine_is_a5k() (0) +#endif + +#ifndef machine_arch_type +#error Unknown machine type +#define machine_arch_type __machine_arch_type +#endif + +#endif diff -Nru a/include/asm-arm26/map.h b/include/asm-arm26/map.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/map.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,24 @@ +/* + * linux/include/asm-arm/map.h + * + * Copyright (C) 1999-2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Page table mapping constructs and function prototypes + */ +struct map_desc { + unsigned long virtual; + unsigned long physical; + unsigned long length; + unsigned int type; +}; + +struct meminfo; + +extern void create_memmap_holes(struct meminfo *); +extern void memtable_init(struct meminfo *); +extern void iotable_init(struct map_desc *); +extern void setup_io_desc(void); diff -Nru a/include/asm-arm26/mc146818rtc.h b/include/asm-arm26/mc146818rtc.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/mc146818rtc.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,28 @@ +/* + * Machine dependent access functions for RTC registers. + */ +#ifndef _ASM_MC146818RTC_H +#define _ASM_MC146818RTC_H + +#include <asm/irq.h> +#include <asm/io.h> + +#ifndef RTC_PORT +#define RTC_PORT(x) (0x70 + (x)) +#define RTC_ALWAYS_BCD 1 /* RTC operates in binary mode */ +#endif + +/* + * The yet supported machines all access the RTC index register via + * an ISA port access but the way to access the date register differs ... + */ +#define CMOS_READ(addr) ({ \ +outb_p((addr),RTC_PORT(0)); \ +inb_p(RTC_PORT(1)); \ +}) +#define CMOS_WRITE(val, addr) ({ \ +outb_p((addr),RTC_PORT(0)); \ +outb_p((val),RTC_PORT(1)); \ +}) + +#endif /* _ASM_MC146818RTC_H */ diff -Nru a/include/asm-arm26/memory.h b/include/asm-arm26/memory.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/memory.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,101 @@ +/* + * linux/include/asm-arm26/memory.h + * + * Copyright (C) 2000-2002 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Note: this file should not be included by non-asm/.h files + */ +#ifndef __ASM_ARM_MEMORY_H +#define __ASM_ARM_MEMORY_H + +/* + * User space: 26MB + */ +#define TASK_SIZE (0x01a00000UL) + +/* + * This decides where the kernel will search for a free chunk of vm + * space during mmap's. + */ +#define TASK_UNMAPPED_BASE (TASK_SIZE / 3) + +/* + * Page offset: 32MB + */ +#define PAGE_OFFSET (0x02000000UL) +#define PHYS_OFFSET (0x02000000UL) + +#define PHYS_TO_NID(addr) (0) + +/* + * PFNs are used to describe any physical page; this means + * PFN 0 == physical address 0. + * + * This is the PFN of the first RAM page in the kernel + * direct-mapped view. We assume this is the first page + * of RAM in the mem_map as well. + */ +#define PHYS_PFN_OFFSET (PHYS_OFFSET >> PAGE_SHIFT) + +/* + * These are *only* valid on the kernel direct mapped RAM memory. + */ +static inline unsigned long virt_to_phys(void *x) +{ + return (unsigned long)x; +} + +static inline void *phys_to_virt(unsigned long x) +{ + return (void *)((unsigned long)x); +} + +#define __pa(x) (unsigned long)(x) +#define __va(x) ((void *)(unsigned long)(x)) + +/* + * Virtual <-> DMA view memory address translations + * Again, these are *only* valid on the kernel direct mapped RAM + * memory. Use of these is *depreciated*. + */ +#define virt_to_bus(x) ((unsigned long)(x)) +#define bus_to_virt(x) ((void *)((unsigned long)(x))) + +/* + * Conversion between a struct page and a physical address. + * + * Note: when converting an unknown physical address to a + * struct page, the resulting pointer must be validated + * using VALID_PAGE(). It must return an invalid struct page + * for any physical address not corresponding to a system + * RAM address. + * + * page_to_pfn(page) convert a struct page * to a PFN number + * pfn_to_page(pfn) convert a _valid_ PFN number to struct page * + * pfn_valid(pfn) indicates whether a PFN number is valid + * + * virt_to_page(k) convert a _valid_ virtual address to struct page * + * virt_addr_valid(k) indicates whether a virtual address is valid + */ +#define page_to_pfn(page) (((page) - mem_map) + PHYS_PFN_OFFSET) +#define pfn_to_page(pfn) ((mem_map + (pfn)) - PHYS_PFN_OFFSET) +#define pfn_valid(pfn) ((pfn) >= PHYS_PFN_OFFSET && (pfn) < (PHYS_PFN_OFFSET + max_mapnr)) + +#define virt_to_page(kaddr) (pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)) +#define virt_addr_valid(kaddr) ((int)(kaddr) >= PAGE_OFFSET && (int)(kaddr) < (unsigned long)high_memory) + +/* + * For BIO. "will die". Kill me when bio_to_phys() and bvec_to_phys() die. + */ +#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) + +/* + * We should really eliminate virt_to_bus() here - it's depreciated. + */ +#define page_to_bus(page) (page_address(page)) + +#endif diff -Nru a/include/asm-arm26/mman.h b/include/asm-arm26/mman.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/mman.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,41 @@ +#ifndef __ARM_MMAN_H__ +#define __ARM_MMAN_H__ + +#define PROT_READ 0x1 /* page can be read */ +#define PROT_WRITE 0x2 /* page can be written */ +#define PROT_EXEC 0x4 /* page can be executed */ +#define PROT_SEM 0x8 /* page may be used for atomic ops */ +#define PROT_NONE 0x0 /* page can not be accessed */ + +#define MAP_SHARED 0x01 /* Share changes */ +#define MAP_PRIVATE 0x02 /* Changes are private */ +#define MAP_TYPE 0x0f /* Mask for type of mapping */ +#define MAP_FIXED 0x10 /* Interpret addr exactly */ +#define MAP_ANONYMOUS 0x20 /* don't use a file */ + +#define MAP_GROWSDOWN 0x0100 /* stack-like segment */ +#define MAP_DENYWRITE 0x0800 /* ETXTBSY */ +#define MAP_EXECUTABLE 0x1000 /* mark it as an executable */ +#define MAP_LOCKED 0x2000 /* pages are locked */ +#define MAP_NORESERVE 0x4000 /* don't check for reservations */ +#define MAP_POPULATE 0x8000 /* populate (prefault) page tables */ +#define MAP_NONBLOCK 0x10000 /* do not block on IO */ + +#define MS_ASYNC 1 /* sync memory asynchronously */ +#define MS_INVALIDATE 2 /* invalidate the caches */ +#define MS_SYNC 4 /* synchronous memory sync */ + +#define MCL_CURRENT 1 /* lock all current mappings */ +#define MCL_FUTURE 2 /* lock all future mappings */ + +#define MADV_NORMAL 0x0 /* default page-in behavior */ +#define MADV_RANDOM 0x1 /* page-in minimum required */ +#define MADV_SEQUENTIAL 0x2 /* read-ahead aggressively */ +#define MADV_WILLNEED 0x3 /* pre-fault pages */ +#define MADV_DONTNEED 0x4 /* discard these pages */ + +/* compatibility flags */ +#define MAP_ANON MAP_ANONYMOUS +#define MAP_FILE 0 + +#endif /* __ARM_MMAN_H__ */ diff -Nru a/include/asm-arm26/mmu.h b/include/asm-arm26/mmu.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/mmu.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,9 @@ +#ifndef __ARM_MMU_H +#define __ARM_MMU_H + +/* + * The ARM doesn't have a mmu context + */ +typedef struct { } mm_context_t; + +#endif diff -Nru a/include/asm-arm26/mmu_context.h b/include/asm-arm26/mmu_context.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/mmu_context.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,51 @@ +/* + * linux/include/asm-arm/mmu_context.h + * + * Copyright (C) 1996 Russell King. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Changelog: + * 27-06-1996 RMK Created + */ +#ifndef __ASM_ARM_MMU_CONTEXT_H +#define __ASM_ARM_MMU_CONTEXT_H + +#define init_new_context(tsk,mm) 0 +#define destroy_context(mm) do { } while(0) + +/* + * This is called when "tsk" is about to enter lazy TLB mode. + * + * mm: describes the currently active mm context + * tsk: task which is entering lazy tlb + * cpu: cpu number which is entering lazy tlb + * + * tsk->mm will be NULL + */ +static inline void +enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk, unsigned cpu) +{ +} + +/* + * This is the actual mm switch as far as the scheduler + * is concerned. No registers are touched. + */ +static inline void +switch_mm(struct mm_struct *prev, struct mm_struct *next, + struct task_struct *tsk, unsigned int cpu) +{ + cpu_switch_mm(next->pgd, next); +} + +#define deactivate_mm(tsk,mm) do { } while (0) + +static inline void activate_mm(struct mm_struct *prev, struct mm_struct *next) +{ + cpu_switch_mm(next->pgd, next); +} + +#endif diff -Nru a/include/asm-arm26/module.h b/include/asm-arm26/module.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/module.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,12 @@ +#ifndef _ASM_ARM_MODULE_H +#define _ASM_ARM_MODULE_H +/* + * This file contains the arm architecture specific module code. + */ + +#define module_map(x) vmalloc(x) +#define module_unmap(x) vfree(x) +#define module_arch_init(x) (0) +#define arch_init_modules(x) do { } while (0) + +#endif /* _ASM_ARM_MODULE_H */ diff -Nru a/include/asm-arm26/msgbuf.h b/include/asm-arm26/msgbuf.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/msgbuf.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,31 @@ +#ifndef _ASMARM_MSGBUF_H +#define _ASMARM_MSGBUF_H + +/* + * The msqid64_ds structure for arm architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 64-bit time_t to solve y2038 problem + * - 2 miscellaneous 32-bit values + */ + +struct msqid64_ds { + struct ipc64_perm msg_perm; + __kernel_time_t msg_stime; /* last msgsnd time */ + unsigned long __unused1; + __kernel_time_t msg_rtime; /* last msgrcv time */ + unsigned long __unused2; + __kernel_time_t msg_ctime; /* last change time */ + unsigned long __unused3; + unsigned long msg_cbytes; /* current number of bytes on queue */ + unsigned long msg_qnum; /* number of messages in queue */ + unsigned long msg_qbytes; /* max number of bytes on queue */ + __kernel_pid_t msg_lspid; /* pid of last msgsnd */ + __kernel_pid_t msg_lrpid; /* last receive pid */ + unsigned long __unused4; + unsigned long __unused5; +}; + +#endif /* _ASMARM_MSGBUF_H */ diff -Nru a/include/asm-arm26/namei.h b/include/asm-arm26/namei.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/namei.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,25 @@ +/* + * linux/include/asm-arm/namei.h + * + * Routines to handle famous /usr/gnemul + * Derived from the Sparc version of this file + * + * Included from linux/fs/namei.c + */ + +#ifndef __ASMARM_NAMEI_H +#define __ASMARM_NAMEI_H + +#define ARM_BSD_EMUL "usr/gnemul/bsd/" + +static inline char *__emul_prefix(void) +{ + switch (current->personality) { + case PER_BSD: + return ARM_BSD_EMUL; + default: + return NULL; + } +} + +#endif /* __ASMARM_NAMEI_H */ diff -Nru a/include/asm-arm26/oldlatches.h b/include/asm-arm26/oldlatches.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/oldlatches.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,37 @@ +/* + * linux/include/asm-arm/arch-arc/oldlatches.h + * + * Copyright (C) 1996 Russell King, Dave Gilbert + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Modifications: + * 04-04-1998 PJB/RMK Merged arc and a5k versions + */ +#ifndef _ASM_ARCH_OLDLATCH_H +#define _ASM_ARCH_OLDLATCH_H + +#define LATCHA_FDSEL0 (1<<0) +#define LATCHA_FDSEL1 (1<<1) +#define LATCHA_FDSEL2 (1<<2) +#define LATCHA_FDSEL3 (1<<3) +#define LATCHA_FDSELALL (0xf) +#define LATCHA_SIDESEL (1<<4) +#define LATCHA_MOTOR (1<<5) +#define LATCHA_INUSE (1<<6) +#define LATCHA_CHANGERST (1<<7) + +#define LATCHB_FDCDENSITY (1<<1) +#define LATCHB_FDCRESET (1<<3) +#define LATCHB_PRINTSTROBE (1<<4) + +/* newval=(oldval & mask)|newdata */ +void oldlatch_bupdate(unsigned char mask,unsigned char newdata); + +/* newval=(oldval & mask)|newdata */ +void oldlatch_aupdate(unsigned char mask,unsigned char newdata); + +#endif + diff -Nru a/include/asm-arm26/page.h b/include/asm-arm26/page.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/page.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,115 @@ +#ifndef _ASMARM_PAGE_H +#define _ASMARM_PAGE_H + +#include <linux/config.h> + +#ifdef __KERNEL__ +#ifndef __ASSEMBLY__ + +extern void __clear_user_page(void *p, unsigned long user); +extern void __copy_user_page(void *to, const void *from, unsigned long user); +extern void copy_page(void *to, const void *from); + +//FIXME these may be wrong on ARM26 +#define clear_user_page(addr,vaddr,pg) \ + do { \ + preempt_disable(); \ + __clear_user_page(addr, vaddr); \ + preempt_enable(); \ + } while (0) + +#define copy_user_page(to,from,vaddr,pg) \ + do { \ + preempt_disable(); \ + __copy_user_page(to, from, vaddr); \ + preempt_enable(); \ + } while (0) + +#define clear_page(page) memzero((void *)(page), PAGE_SIZE) +#define copy_page(to, from) __copy_user_page(to, from, 0); + +#undef STRICT_MM_TYPECHECKS + +#ifdef STRICT_MM_TYPECHECKS +/* + * These are used to make use of C type-checking.. + */ +typedef struct { unsigned long pgd; } pgd_t; +typedef struct { unsigned long pte; } pte_t; +typedef struct { unsigned long pmd; } pmd_t; +typedef struct { unsigned long pgprot; } pgprot_t; + +#define pgd_val(x) ((x).pgd) +#define pte_val(x) ((x).pte) +#define pmd_val(x) ((x).pmd) +#define pgprot_val(x) ((x).pgprot) + +#define __pte(x) ((pte_t) { (x) } ) +#define __pmd(x) ((pmd_t) { (x) } ) +#define __pgprot(x) ((pgprot_t) { (x) } ) + +#else +/* + * .. while these make it easier on the compiler + */ +typedef unsigned long pgd_t; +typedef unsigned long pte_t; +typedef unsigned long pmd_t; +typedef unsigned long pgprot_t; + +//FIXME - should these cast to unsigned long? +#define pgd_val(x) (x) +#define pte_val(x) (x) +#define pmd_val(x) (x) +#define pgprot_val(x) (x) + +#define __pte(x) (x) +#define __pmd(x) (x) +#define __pgprot(x) (x) + +#endif /* STRICT_MM_TYPECHECKS */ +#endif /* !__ASSEMBLY__ */ +#endif /* __KERNEL__ */ + +/* PAGE_SHIFT determines the page size. This is configurable. */ +#if defined(CONFIG_PAGESIZE_16) +#define PAGE_SHIFT 14 /* 16K */ +#else /* default */ +#define PAGE_SHIFT 15 /* 32K */ +#endif + +#define EXEC_PAGESIZE 32768 + +#define PAGE_SIZE (1UL << PAGE_SHIFT) +#define PAGE_MASK (~(PAGE_SIZE-1)) + +/* to align the pointer to the (next) page boundary */ +#define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) + +#ifdef __KERNEL__ +#ifndef __ASSEMBLY__ + +/* 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; +} + +#include <asm/memory.h> + +#endif /* !__ASSEMBLY__ */ + +#define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ + VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) + +#endif /* __KERNEL__ */ + +#endif diff -Nru a/include/asm-arm26/param.h b/include/asm-arm26/param.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/param.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,37 @@ +/* + * linux/include/asm-arm/param.h + * + * Copyright (C) 1995-1999 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_PARAM_H +#define __ASM_PARAM_H + +#ifndef __KERNEL_HZ +#define __KERNEL_HZ 100 +#endif + +#ifdef __KERNEL__ +# define HZ __KERNEL_HZ /* Internal kernel timer frequency */ +# define USER_HZ 100 /* User interfaces are in "ticks" */ +# define CLOCKS_PER_SEC (USER_HZ) /* like times() */ +#else +# define HZ 100 +#endif + +#ifndef NGROUPS +#define NGROUPS 32 +#endif + +#ifndef NOGROUP +#define NOGROUP (-1) +#endif + +/* max length of hostname */ +#define MAXHOSTNAMELEN 64 + +#endif + diff -Nru a/include/asm-arm26/parport.h b/include/asm-arm26/parport.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/parport.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,18 @@ +/* + * linux/include/asm-arm/parport.h: ARM-specific parport initialisation + * + * Copyright (C) 1999, 2000 Tim Waugh <tim@cyberelk.demon.co.uk> + * + * This file should only be included by drivers/parport/parport_pc.c. + */ + +#ifndef __ASMARM_PARPORT_H +#define __ASMARM_PARPORT_H + +static int __devinit parport_pc_find_isa_ports (int autoirq, int autodma); +static int __devinit parport_pc_find_nonpci_ports (int autoirq, int autodma) +{ + return parport_pc_find_isa_ports (autoirq, autodma); +} + +#endif /* !(_ASMARM_PARPORT_H) */ diff -Nru a/include/asm-arm26/pci.h b/include/asm-arm26/pci.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/pci.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,5 @@ +/* Should not be needed. IDE stupidity */ +/* JMA 18.05.03 - is kinda needed, if only to tell it we don't have a PCI bus */ + +#define PCI_DMA_BUS_IS_PHYS 0 + diff -Nru a/include/asm-arm26/percpu.h b/include/asm-arm26/percpu.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/percpu.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,6 @@ +#ifndef __ARM_PERCPU +#define __ARM_PERCPU + +#include <asm-generic/percpu.h> + +#endif diff -Nru a/include/asm-arm26/pgalloc.h b/include/asm-arm26/pgalloc.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/pgalloc.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,70 @@ +/* + * linux/include/asm-arm/pgalloc.h + * + * Copyright (C) 2000-2001 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef _ASMARM_PGALLOC_H +#define _ASMARM_PGALLOC_H + +#include <asm/processor.h> +#include <asm/cacheflush.h> +#include <asm/tlbflush.h> +#include <linux/slab.h> + +extern kmem_cache_t *pte_cache; + +static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr){ + return kmem_cache_alloc(pte_cache, GFP_KERNEL); +} + +static inline void pte_free_kernel(pte_t *pte){ + if (pte) + kmem_cache_free(pte_cache, pte); +} + +/* + * Populate the pmdp entry with a pointer to the pte. This pmd is part + * of the mm address space. + * + * If 'mm' is the init tasks mm, then we are doing a vmalloc, and we + * need to set stuff up correctly for it. + */ +static inline void +pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *ptep) +{ +//FIXME - is this doing the right thing? + set_pmd(pmdp, (unsigned long)ptep | 1/*FIXME _PMD_PRESENT*/); +} + +/* + * FIXME - We use the old 2.5.5-rmk1 hack for this. + * This is not truly correct, but should be functional. + */ +#define pte_alloc_one(mm,addr) ((struct page *)pte_alloc_one_kernel(mm,addr)) +#define pte_free(pte) pte_free_kernel((pte_t *)pte) +#define pmd_populate(mm,pmdp,ptep) pmd_populate_kernel(mm,pmdp,(pte_t *)ptep) + +/* + * Since we have only two-level page tables, these are trivial + * + * trick __pmd_alloc into optimising away. The actual value is irrelevant though as it + * is thrown away. It just cant be zero. -IM + */ + +#define pmd_alloc_one(mm,addr) ((pmd_t *)2); BUG() +#define pmd_free(pmd) do { } while (0) +#define pgd_populate(mm,pmd,pte) (0) + +extern pgd_t *get_pgd_slow(struct mm_struct *mm); +extern void free_pgd_slow(pgd_t *pgd); + +#define pgd_alloc(mm) get_pgd_slow(mm) +#define pgd_free(pgd) free_pgd_slow(pgd) + +#define check_pgt_cache() do { } while (0) + +#endif diff -Nru a/include/asm-arm26/pgtable.h b/include/asm-arm26/pgtable.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/pgtable.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,298 @@ +/* + * linux/include/asm-arm26/pgtable.h + * + * Copyright (C) 2000-2002 Russell King + * Copyright (C) 2003 Ian Molton + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef _ASMARM_PGTABLE_H +#define _ASMARM_PGTABLE_H + +#include <linux/config.h> +#include <asm/memory.h> + +/* + * The table below defines the page protection levels that we insert into our + * Linux page table version. These get translated into the best that the + * architecture can perform. Note that on most ARM hardware: + * 1) We cannot do execute protection + * 2) If we could do execute protection, then read is implied + * 3) write implies read permissions + */ +#define __P000 PAGE_NONE +#define __P001 PAGE_READONLY +#define __P010 PAGE_COPY +#define __P011 PAGE_COPY +#define __P100 PAGE_READONLY +#define __P101 PAGE_READONLY +#define __P110 PAGE_COPY +#define __P111 PAGE_COPY + +#define __S000 PAGE_NONE +#define __S001 PAGE_READONLY +#define __S010 PAGE_SHARED +#define __S011 PAGE_SHARED +#define __S100 PAGE_READONLY +#define __S101 PAGE_READONLY +#define __S110 PAGE_SHARED +#define __S111 PAGE_SHARED + +/* + * PMD_SHIFT determines the size of the area a second-level page table can map + * PGDIR_SHIFT determines what a third-level page table entry can map + */ +#define PGD_SHIFT 25 +#define PMD_SHIFT 20 + +#define PGD_SIZE (1UL << PGD_SHIFT) +#define PGD_MASK (~(PGD_SIZE-1)) +#define PMD_SIZE (1UL << PMD_SHIFT) +#define PMD_MASK (~(PMD_SIZE-1)) + +/* The kernel likes to use these names for the above (ick) */ +#define PGDIR_SIZE PGD_SIZE +#define PGDIR_MASK PGD_MASK + +#define PTRS_PER_PGD 32 +#define PTRS_PER_PMD 1 +#define PTRS_PER_PTE 32 + +#define FIRST_USER_PGD_NR 1 +#define USER_PTRS_PER_PGD ((TASK_SIZE/PGD_SIZE) - FIRST_USER_PGD_NR) + +// FIXME - WTF? +#define LIBRARY_TEXT_START 0x0c000000 + + + +#ifndef __ASSEMBLY__ +extern void __pte_error(const char *file, int line, unsigned long val); +extern void __pmd_error(const char *file, int line, unsigned long val); +extern void __pgd_error(const char *file, int line, unsigned long val); + +#define pte_ERROR(pte) __pte_error(__FILE__, __LINE__, pte_val(pte)) +#define pmd_ERROR(pmd) __pmd_error(__FILE__, __LINE__, pmd_val(pmd)) +#define pgd_ERROR(pgd) __pgd_error(__FILE__, __LINE__, pgd_val(pgd)) + +/* + * ZERO_PAGE is a global shared page that is always zero: used + * for zero-mapped memory areas etc.. + */ +extern struct page *empty_zero_page; +#define ZERO_PAGE(vaddr) (empty_zero_page) + +#define pte_pfn(pte) (pte_val(pte) >> PAGE_SHIFT) +#define pte_page(pte) (pfn_to_page(pte_pfn(pte))) +#define pfn_pte(pfn,prot) (__pte(((pfn) << PAGE_SHIFT) | pgprot_val(prot))) +#define pages_to_mb(x) ((x) >> (20 - PAGE_SHIFT)) +#define mk_pte(page,prot) pfn_pte(page_to_pfn(page),prot) +#define page_pte_prot(page,prot) mk_pte(page, prot) +#define page_pte(page) mk_pte(page, __pgprot(0)) + +/* + * Terminology: PGD = Page Directory, PMD = Page Middle Directory, + * PTE = Page Table Entry + * + * on arm26 we have no 2nd level page table. we simulate this by removing the + * PMD. + * + * pgd_none is 0 to prevernt pmd_alloc() calling __pmd_alloc(). This causes it + * to return pmd_offset(pgd,addr) which is a pointer to the pgd (IOW, a no-op). + * + * however, to work this way, whilst we are allocating 32 pgds, containing 32 + * PTEs, the actual work is done on the PMDs, thus: + * + * instead of mm->pgd->pmd->pte + * we have mm->pgdpmd->pte + * + * IOW, think of PGD operations and PMD ones as being the same thing, just + * that PGD stuff deals with the mm_struct side of things, wheras PMD stuff + * deals with the pte side of things. + * + * additionally, we store some bits in the PGD and PTE pointers: + * PGDs: + * o The lowest (1) bit of the PGD is to determine if it is present or swap. + * o The 2nd bit of the PGD is unused and must be zero. + * o The top 6 bits of the PGD must be zero. + * PTEs: + * o The lower 5 bits of a pte are flags. bit 1 is the 'present' flag. The + * others determine the pages attributes. + * + * the pgd_val, pmd_val, and pte_val macros seem to be private to our code. + * They get the RAW value of the PGD/PMD/PTE entry, including our flags + * encoded into the pointers. + * + * The pgd_offset, pmd_offset, and pte_offset macros are used by the kernel, + * so they shouldnt have our flags attached. + * + * If you understood that, feel free to explain it to me... + * + */ + +#define _PMD_PRESENT (0x01) + +/* These definitions allow us to optimise out stuff like pmd_alloc() */ +#define pgd_none(pgd) (0) +#define pgd_bad(pgd) (0) +#define pgd_present(pgd) (1) +#define pgd_clear(pgdp) do { } while (0) + +/* Whilst these handle our actual 'page directory' (the agglomeration of pgd and pmd) + */ +#define pmd_none(pmd) (!pmd_val(pmd)) +#define pmd_bad(pmd) ((pmd_val(pmd) & 0xfc000002)) +#define pmd_present(pmd) (pmd_val(pmd) & _PMD_PRESENT) +#define set_pmd(pmd_ptr, pmd) ((*(pmd_ptr)) = (pmd)) +#define pmd_clear(pmdp) set_pmd(pmdp, __pmd(0)) + +/* and these handle our pte tables */ +#define pte_none(pte) (!pte_val(pte)) +#define pte_present(pte) (pte_val(pte) & _PAGE_PRESENT) +#define set_pte(pte_ptr, pte) ((*(pte_ptr)) = (pte)) +#define pte_clear(ptep) set_pte((ptep), __pte(0)) + +/* macros to ease the getting of pointers to stuff... */ +#define pgd_offset(mm, addr) ((pgd_t *)(mm)->pgd + __pgd_index(addr)) +#define pmd_offset(pgd, addr) ((pmd_t *)(pgd)) +#define pte_offset(pmd, addr) ((pte_t *)pmd_page(*(pmd)) + __pte_index(addr)) + +/* there is no __pmd_index as we dont use pmds */ +#define __pgd_index(addr) ((addr) >> PGD_SHIFT) +#define __pte_index(addr) (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)) + + +/* Keep the kernel happy */ +#define pgd_index(addr) __pgd_index(addr) +#define pgd_offset_k(addr) (pgd_offset(&init_mm, addr)) + +/* + * The vmalloc() routines leaves a hole of 4kB between each vmalloced + * area for the same reason. ;) FIXME: surely 1 page not 4k ? + */ +#define VMALLOC_START 0x01a00000 +#define VMALLOC_VMADDR(x) ((unsigned long)(x)) +#define VMALLOC_END 0x01c00000 + +/* Is pmd_page supposed to return a pointer to a page in some arches? ours seems to + * return a pointer to memory (no special alignment) + */ +#define pmd_page(pmd) ((unsigned long)(pmd_val((pmd)) & ~_PMD_PRESENT)) +#define pmd_page_kernel(pmd) ((pte_t *)(pmd_val((pmd)) & ~_PMD_PRESENT)) + +#define pte_offset_kernel(dir,addr) (pmd_page_kernel(*(dir)) + __pte_index(addr)) + +#define pte_offset_map(dir,addr) (pmd_page_kernel(*(dir)) + __pte_index(addr)) +#define pte_offset_map_nested(dir,addr) (pmd_page_kernel(*(dir)) + __pte_index(addr)) +#define pte_unmap(pte) do { } while (0) +#define pte_unmap_nested(pte) do { } while (0) + + +#define _PAGE_PRESENT 0x01 +#define _PAGE_READONLY 0x02 +#define _PAGE_NOT_USER 0x04 +#define _PAGE_OLD 0x08 +#define _PAGE_CLEAN 0x10 + +// an old page has never been read. +// a clean page has never been written. + +/* -- present -- -- !dirty -- --- !write --- ---- !user --- */ +#define PAGE_NONE __pgprot(_PAGE_PRESENT | _PAGE_CLEAN | _PAGE_READONLY | _PAGE_NOT_USER) +#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_CLEAN ) +#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_CLEAN | _PAGE_READONLY ) +#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_CLEAN | _PAGE_READONLY ) +#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_NOT_USER) + +#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_OLD | _PAGE_CLEAN) + +/* + * The following only work if pte_present() is true. + * Undefined behaviour if not.. + */ +#define pte_read(pte) (!(pte_val(pte) & _PAGE_NOT_USER)) +#define pte_write(pte) (!(pte_val(pte) & _PAGE_READONLY)) +#define pte_exec(pte) (!(pte_val(pte) & _PAGE_NOT_USER)) +#define pte_dirty(pte) (!(pte_val(pte) & _PAGE_CLEAN)) +#define pte_young(pte) (!(pte_val(pte) & _PAGE_OLD)) +//ONLY when !pte_present() I think. nicked from arm32 (FIXME!) +#define pte_file(pte) (!(pte_val(pte) & _PAGE_OLD)) + +#define PTE_BIT_FUNC(fn,op) \ +static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; } + +PTE_BIT_FUNC(wrprotect, |= _PAGE_READONLY); +PTE_BIT_FUNC(mkwrite, &= ~_PAGE_READONLY); +PTE_BIT_FUNC(exprotect, |= _PAGE_NOT_USER); +PTE_BIT_FUNC(mkexec, &= ~_PAGE_NOT_USER); +PTE_BIT_FUNC(mkclean, |= _PAGE_CLEAN); +PTE_BIT_FUNC(mkdirty, &= ~_PAGE_CLEAN); +PTE_BIT_FUNC(mkold, |= _PAGE_OLD); +PTE_BIT_FUNC(mkyoung, &= ~_PAGE_OLD); + +/* + * We don't store cache state bits in the page table here. FIXME - or do we? + */ +#define pgprot_noncached(prot) (prot) +#define pgprot_writecombine(prot) (prot) //FIXME - is a no-op? + +extern void pgtable_cache_init(void); + +//FIXME - nicked from arm32 and brutally hacked. probably wrong. +#define pte_to_pgoff(x) (pte_val(x) >> 2) +#define pgoff_to_pte(x) __pte(((x) << 2) & ~_PAGE_OLD) + +//FIXME - next line borrowed from arm32. is it right? +#define PTE_FILE_MAX_BITS 30 + + +static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) +{ + pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); + return pte; +} + +extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; + +/* Encode and decode a swap entry. + * + * We support up to 32GB of swap on 4k machines + */ +#define __swp_type(x) (((x).val >> 2) & 0x7f) +#define __swp_offset(x) ((x).val >> 9) +#define __swp_entry(type,offset) ((swp_entry_t) { ((type) << 2) | ((offset) << 9) }) +#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) +#define __swp_entry_to_pte(swp) ((pte_t) { (swp).val }) + +/* Needs to be defined here and not in linux/mm.h, as it is arch dependent */ +/* FIXME: this is not correct */ +#define kern_addr_valid(addr) (1) + +/* + * Conversion functions: convert a page and protection to a page entry, + * and a page entry and page directory to the page they refer to. + */ +static inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot) +{ + pte_t pte; + pte_val(pte) = physpage | pgprot_val(pgprot); + return pte; +} + + +#include <asm-generic/pgtable.h> + +/* + * remap a physical address `phys' of size `size' with page protection `prot' + * into virtual address `from' + */ +#define io_remap_page_range(vma,from,phys,size,prot) \ + remap_page_range(vma,from,phys,size,prot) + +typedef pte_t *pte_addr_t; + +#endif /* !__ASSEMBLY__ */ + +#endif /* _ASMARM_PGTABLE_H */ diff -Nru a/include/asm-arm26/poll.h b/include/asm-arm26/poll.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/poll.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,25 @@ +#ifndef __ASMARM_POLL_H +#define __ASMARM_POLL_H + +/* These are specified by iBCS2 */ +#define POLLIN 0x0001 +#define POLLPRI 0x0002 +#define POLLOUT 0x0004 +#define POLLERR 0x0008 +#define POLLHUP 0x0010 +#define POLLNVAL 0x0020 + +/* The rest seem to be more-or-less nonstandard. Check them! */ +#define POLLRDNORM 0x0040 +#define POLLRDBAND 0x0080 +#define POLLWRNORM 0x0100 +#define POLLWRBAND 0x0200 +#define POLLMSG 0x0400 + +struct pollfd { + int fd; + short events; + short revents; +}; + +#endif diff -Nru a/include/asm-arm26/posix_types.h b/include/asm-arm26/posix_types.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/posix_types.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,81 @@ +/* + * linux/include/asm-arm/posix_types.h + * + * Copyright (C) 1996-1998 Russell King. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Changelog: + * 27-06-1996 RMK Created + */ +#ifndef __ARCH_ARM_POSIX_TYPES_H +#define __ARCH_ARM_POSIX_TYPES_H + +/* + * This file is generally used by user-level software, so you need to + * be a little careful about namespace pollution etc. Also, we cannot + * assume GCC is being used. + */ + +typedef unsigned short __kernel_dev_t; +typedef unsigned long __kernel_ino_t; +typedef unsigned short __kernel_mode_t; +typedef unsigned short __kernel_nlink_t; +typedef long __kernel_off_t; +typedef int __kernel_pid_t; +typedef unsigned short __kernel_ipc_pid_t; +typedef unsigned short __kernel_uid_t; +typedef unsigned short __kernel_gid_t; +typedef unsigned int __kernel_size_t; +typedef int __kernel_ssize_t; +typedef int __kernel_ptrdiff_t; +typedef long __kernel_time_t; +typedef long __kernel_suseconds_t; +typedef long __kernel_clock_t; +typedef int __kernel_timer_t; +typedef int __kernel_clockid_t; +typedef int __kernel_daddr_t; +typedef char * __kernel_caddr_t; +typedef unsigned short __kernel_uid16_t; +typedef unsigned short __kernel_gid16_t; +typedef unsigned int __kernel_uid32_t; +typedef unsigned int __kernel_gid32_t; + +typedef unsigned short __kernel_old_uid_t; +typedef unsigned short __kernel_old_gid_t; + +#ifdef __GNUC__ +typedef long long __kernel_loff_t; +#endif + +typedef struct { +#if defined(__KERNEL__) || defined(__USE_ALL) + int val[2]; +#else /* !defined(__KERNEL__) && !defined(__USE_ALL) */ + int __val[2]; +#endif /* !defined(__KERNEL__) && !defined(__USE_ALL) */ +} __kernel_fsid_t; + +#if defined(__KERNEL__) || !defined(__GLIBC__) || (__GLIBC__ < 2) + +#undef __FD_SET +#define __FD_SET(fd, fdsetp) \ + (((fd_set *)fdsetp)->fds_bits[fd >> 5] |= (1<<(fd & 31))) + +#undef __FD_CLR +#define __FD_CLR(fd, fdsetp) \ + (((fd_set *)fdsetp)->fds_bits[fd >> 5] &= ~(1<<(fd & 31))) + +#undef __FD_ISSET +#define __FD_ISSET(fd, fdsetp) \ + ((((fd_set *)fdsetp)->fds_bits[fd >> 5] & (1<<(fd & 31))) != 0) + +#undef __FD_ZERO +#define __FD_ZERO(fdsetp) \ + (memset (fdsetp, 0, sizeof (*(fd_set *)fdsetp))) + +#endif + +#endif diff -Nru a/include/asm-arm26/proc-fns.h b/include/asm-arm26/proc-fns.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/proc-fns.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,49 @@ +/* + * linux/include/asm-arm26/proc-fns.h + * + * Copyright (C) 2000 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASSEMBLY__ + +#include <asm/page.h> + +/* + * Don't change this structure - ASM code + * relies on it. + */ +extern struct processor { + /* check for any bugs */ + void (*_check_bugs)(void); + /* Set up any processor specifics */ + void (*_proc_init)(void); + /* Disable any processor specifics */ + void (*_proc_fin)(void); + /* set the MEMC hardware mappings */ + void (*_set_pgd)(pgd_t *pgd); + /* XCHG */ + unsigned long (*_xchg_1)(unsigned long x, volatile void *ptr); + unsigned long (*_xchg_4)(unsigned long x, volatile void *ptr); +} processor; + +extern const struct processor arm2_processor_functions; +extern const struct processor arm250_processor_functions; +extern const struct processor arm3_processor_functions; + +#define cpu_check_bugs() processor._check_bugs() +#define cpu_proc_init() processor._proc_init() +#define cpu_proc_fin() processor._proc_fin() +#define cpu_do_idle() do { } while (0) +#define cpu_switch_mm(pgd,mm) processor._set_pgd(pgd) +#define cpu_xchg_1(x,ptr) processor._xchg_1(x,ptr) +#define cpu_xchg_4(x,ptr) processor._xchg_4(x,ptr) + + +//FIXME - these shouldnt be in proc-fn.h +extern void cpu_memc_update_all(pgd_t *pgd); +extern void cpu_memc_update_entry(pgd_t *pgd, unsigned long phys_pte, unsigned long log_addr); + +#endif diff -Nru a/include/asm-arm26/processor.h b/include/asm-arm26/processor.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/processor.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,121 @@ +/* + * linux/include/asm-arm26/processor.h + * + * Copyright (C) 1995 Russell King + * Copyright (C) 2003 Ian Molton + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef __ASM_ARM_PROCESSOR_H +#define __ASM_ARM_PROCESSOR_H + +/* + * Default implementation of macro that returns current + * instruction pointer ("program counter"). + */ +#define current_text_addr() ({ __label__ _l; _l: &&_l;}) + +#ifdef __KERNEL__ + +#define EISA_bus 0 +#define MCA_bus 0 +#define MCA_bus__is_a_macro + +#include <asm/atomic.h> +#include <asm/ptrace.h> +#include <linux/string.h> + +#define KERNEL_STACK_SIZE 4096 + +typedef struct { + void (*put_byte)(void); /* Special calling convention */ + void (*get_byte)(void); /* Special calling convention */ + void (*put_half)(void); /* Special calling convention */ + void (*get_half)(void); /* Special calling convention */ + void (*put_word)(void); /* Special calling convention */ + void (*get_word)(void); /* Special calling convention */ + void (*put_dword)(void); /* Special calling convention */ + unsigned long (*copy_from_user)(void *to, const void *from, unsigned long sz); + unsigned long (*copy_to_user)(void *to, const void *from, unsigned long sz); + unsigned long (*clear_user)(void *addr, unsigned long sz); + unsigned long (*strncpy_from_user)(char *to, const char *from, unsigned long sz); + unsigned long (*strnlen_user)(const char *s, long n); +} uaccess_t; + +extern uaccess_t uaccess_user, uaccess_kernel; + +#define EXTRA_THREAD_STRUCT \ + uaccess_t *uaccess; /* User access functions*/ + +#define EXTRA_THREAD_STRUCT_INIT \ + uaccess: &uaccess_kernel, + +// FIXME?!! + +#define start_thread(regs,pc,sp) \ +({ \ + unsigned long *stack = (unsigned long *)sp; \ + set_fs(USER_DS); \ + memzero(regs->uregs, sizeof (regs->uregs)); \ + regs->ARM_pc = pc | ~0xfc000003; /* pc */ \ + regs->ARM_sp = sp; /* sp */ \ + regs->ARM_r2 = stack[2]; /* r2 (envp) */ \ + regs->ARM_r1 = stack[1]; /* r1 (argv) */ \ + regs->ARM_r0 = stack[0]; /* r0 (argc) */ \ +}) + +#define KSTK_EIP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1020]) +#define KSTK_ESP(tsk) (((unsigned long *)(4096+(unsigned long)(tsk)))[1018]) + +struct debug_entry { + u32 address; + u32 insn; +}; + +struct debug_info { + int nsaved; + struct debug_entry bp[2]; +}; + +struct thread_struct { + /* fault info */ + unsigned long address; + unsigned long trap_no; + unsigned long error_code; + /* debugging */ + struct debug_info debug; + EXTRA_THREAD_STRUCT +}; + +#define INIT_THREAD { \ +EXTRA_THREAD_STRUCT_INIT \ +} + +/* Forward declaration, a strange C thing */ +struct task_struct; + +/* Free all resources held by a thread. */ +extern void release_thread(struct task_struct *); + +/* Copy and release all segment info associated with a VM */ +#define copy_segments(tsk, mm) do { } while (0) +#define release_segments(mm) do { } while (0) + +unsigned long get_wchan(struct task_struct *p); + +#define cpu_relax() barrier() + +/* Prepare to copy thread state - unlazy all lazy status */ +#define prepare_to_copy(tsk) do { } while (0) + +/* + * Create a new kernel thread + */ +extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags); + +#endif + +#endif /* __ASM_ARM_PROCESSOR_H */ diff -Nru a/include/asm-arm26/procinfo.h b/include/asm-arm26/procinfo.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/procinfo.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,56 @@ +/* + * linux/include/asm-arm/procinfo.h + * + * Copyright (C) 1996-1999 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_PROCINFO_H +#define __ASM_PROCINFO_H + +#ifndef __ASSEMBLY__ + +//struct processor; +//struct cpu_user_fns; + +struct proc_info_item { + const char *manufacturer; + const char *cpu_name; +}; + +/* + * Note! struct processor is always defined if we're + * using MULTI_CPU, otherwise this entry is unused, + * but still exists. + * + * NOTE! The following structure is defined by assembly + * language, NOT C code. For more information, check: + * arch/arm/mm/proc-*.S and arch/arm/kernel/head-armv.S + */ +struct proc_info_list { + unsigned int cpu_val; + unsigned int cpu_mask; + const char *arch_name; + const char *elf_name; + unsigned int elf_hwcap; + struct proc_info_item *info; + struct processor *proc; +}; + +#endif /* __ASSEMBLY__ */ + +#define PROC_INFO_SZ 48 + +#define HWCAP_SWP 1 +#define HWCAP_HALF 2 +#define HWCAP_THUMB 4 +#define HWCAP_26BIT 8 /* Play it safe */ +#define HWCAP_FAST_MULT 16 +#define HWCAP_FPA 32 +#define HWCAP_VFP 64 +#define HWCAP_EDSP 128 +#define HWCAP_JAVA 256 + +#endif diff -Nru a/include/asm-arm26/ptrace.h b/include/asm-arm26/ptrace.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/ptrace.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,103 @@ +#ifndef __ASM_ARM_PTRACE_H +#define __ASM_ARM_PTRACE_H + +#define PTRACE_GETREGS 12 +#define PTRACE_SETREGS 13 +#define PTRACE_GETFPREGS 14 +#define PTRACE_SETFPREGS 15 +#define PTRACE_OLDSETOPTIONS 21 + +/* options set using PTRACE_SETOPTIONS */ +#define PTRACE_O_TRACESYSGOOD 0x00000001 + +#define MODE_USR26 0x00000000 +#define MODE_FIQ26 0x00000001 +#define MODE_IRQ26 0x00000002 +#define MODE_SVC26 0x00000003 +#define MODE_MASK 0x00000003 + +#define PSR_F_BIT 0x04000000 +#define PSR_I_BIT 0x08000000 +#define PSR_V_BIT 0x10000000 +#define PSR_C_BIT 0x20000000 +#define PSR_Z_BIT 0x40000000 +#define PSR_N_BIT 0x80000000 + +#define PCMASK 0xfc000003 + + +#ifndef __ASSEMBLY__ + +#define pc_pointer(v) ((v) & ~PCMASK) /* convert v to pc type address */ +#define instruction_pointer(regs) (pc_pointer((regs)->ARM_pc)) /* get pc */ + +/* this struct defines the way the registers are stored on the + stack during a system call. */ + +struct pt_regs { + long uregs[17]; +}; + +#define ARM_pc uregs[15] +#define ARM_lr uregs[14] +#define ARM_sp uregs[13] +#define ARM_ip uregs[12] +#define ARM_fp uregs[11] +#define ARM_r10 uregs[10] +#define ARM_r9 uregs[9] +#define ARM_r8 uregs[8] +#define ARM_r7 uregs[7] +#define ARM_r6 uregs[6] +#define ARM_r5 uregs[5] +#define ARM_r4 uregs[4] +#define ARM_r3 uregs[3] +#define ARM_r2 uregs[2] +#define ARM_r1 uregs[1] +#define ARM_r0 uregs[0] +#define ARM_ORIG_r0 uregs[16] + +#ifdef __KERNEL__ + +#define processor_mode(regs) \ + ((regs)->ARM_pc & MODE_MASK) + +#define user_mode(regs) \ + (processor_mode(regs) == MODE_USR26) + +#define interrupts_enabled(regs) \ + (!((regs)->ARM_pc & PSR_I_BIT)) + +#define fast_interrupts_enabled(regs) \ + (!((regs)->ARM_pc & PSR_F_BIT)) + +#define condition_codes(regs) \ + ((regs)->ARM_pc & (PSR_V_BIT|PSR_C_BIT|PSR_Z_BIT|PSR_N_BIT)) + +/* Are the current registers suitable for user mode? + * (used to maintain security in signal handlers) + */ +static inline int valid_user_regs(struct pt_regs *regs) +{ + if (user_mode(regs) && + (regs->ARM_pc & (PSR_F_BIT | PSR_I_BIT)) == 0) + return 1; + + /* + * force it to be something sensible + */ + regs->ARM_pc &= ~(MODE_MASK | PSR_F_BIT | PSR_I_BIT); + + return 0; +} + +extern void show_regs(struct pt_regs *); + +#define predicate(x) (x & 0xf0000000) +#define PREDICATE_ALWAYS 0xe0000000 + +#endif /* __KERNEL__ */ + +#endif /* __ASSEMBLY__ */ + +#endif + diff -Nru a/include/asm-arm26/resource.h b/include/asm-arm26/resource.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/resource.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,47 @@ +#ifndef _ARM_RESOURCE_H +#define _ARM_RESOURCE_H + +/* + * Resource limits + */ + +#define RLIMIT_CPU 0 /* CPU time in ms */ +#define RLIMIT_FSIZE 1 /* Maximum filesize */ +#define RLIMIT_DATA 2 /* max data size */ +#define RLIMIT_STACK 3 /* max stack size */ +#define RLIMIT_CORE 4 /* max core file size */ +#define RLIMIT_RSS 5 /* max resident set size */ +#define RLIMIT_NPROC 6 /* max number of processes */ +#define RLIMIT_NOFILE 7 /* max number of open files */ +#define RLIMIT_MEMLOCK 8 /* max locked-in-memory address space */ +#define RLIMIT_AS 9 /* address space limit */ +#define RLIMIT_LOCKS 10 /* maximum file locks held */ + +#define RLIM_NLIMITS 11 + +#ifdef __KERNEL__ + +/* + * SuS says limits have to be unsigned. + * Which makes a ton more sense anyway. + */ +#define RLIM_INFINITY (~0UL) + +#define INIT_RLIMITS \ +{ \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { _STK_LIM, RLIM_INFINITY }, \ + { 0, RLIM_INFINITY }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { 0, 0 }, \ + { INR_OPEN, INR_OPEN }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ +} + +#endif /* __KERNEL__ */ + +#endif diff -Nru a/include/asm-arm26/rmap.h b/include/asm-arm26/rmap.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/rmap.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,66 @@ +#ifndef _ARM_RMAP_H +#define _ARM_RMAP_H + +/* + * linux/include/asm-arm26/proc-armv/rmap.h + * + * Architecture dependant parts of the reverse mapping code, + * + * ARM is different since hardware page tables are smaller than + * the page size and Linux uses a "duplicate" one with extra info. + * For rmap this means that the first 2 kB of a page are the hardware + * page tables and the last 2 kB are the software page tables. + */ + +static inline void pgtable_add_rmap(struct page *page, struct mm_struct * mm, unsigned long address) +{ + page->mapping = (void *)mm; + page->index = address & ~((PTRS_PER_PTE * PAGE_SIZE) - 1); + inc_page_state(nr_page_table_pages); +} + +static inline void pgtable_remove_rmap(struct page *page) +{ + page->mapping = NULL; + page->index = 0; + dec_page_state(nr_page_table_pages); +} + +static inline struct mm_struct * ptep_to_mm(pte_t * ptep) +{ + struct page * page = virt_to_page(ptep); + return (struct mm_struct *)page->mapping; +} + +/* The page table takes half of the page */ +#define PTE_MASK ((PAGE_SIZE / 2) - 1) + +static inline unsigned long ptep_to_address(pte_t * ptep) +{ + struct page * page = virt_to_page(ptep); + unsigned long low_bits; + + low_bits = ((unsigned long)ptep & PTE_MASK) * PTRS_PER_PTE; + return page->index + low_bits; +} + +//FIXME!!! IS these correct? +static inline pte_addr_t ptep_to_paddr(pte_t *ptep) +{ + return (pte_addr_t)ptep; +} + +static inline pte_t *rmap_ptep_map(pte_addr_t pte_paddr) +{ + return (pte_t *)pte_paddr; +} + +static inline void rmap_ptep_unmap(pte_t *pte) +{ + return; +} + + +//#include <asm-generic/rmap.h> + +#endif /* _ARM_RMAP_H */ diff -Nru a/include/asm-arm26/scatterlist.h b/include/asm-arm26/scatterlist.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/scatterlist.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,26 @@ +#ifndef _ASMARM_SCATTERLIST_H +#define _ASMARM_SCATTERLIST_H + +#include <asm/types.h> + +struct scatterlist { + struct page *page; /* buffer page */ + unsigned int offset; /* buffer offset */ + dma_addr_t dma_address; /* dma address */ + unsigned int length; /* length */ + char *__address; /* for set_dma_addr */ +}; + +/* + * These macros should be used after a pci_map_sg call has been done + * to get bus addresses of each of the SG entries and their lengths. + * You should only work with the number of sg entries pci_map_sg + * returns, or alternatively stop on the first sg_dma_len(sg) which + * is 0. + */ +#define sg_dma_address(sg) ((sg)->dma_address) +#define sg_dma_len(sg) ((sg)->length) + +#define ISA_DMA_THRESHOLD (0xffffffff) + +#endif /* _ASMARM_SCATTERLIST_H */ diff -Nru a/include/asm-arm26/segment.h b/include/asm-arm26/segment.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/segment.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,11 @@ +#ifndef __ASM_ARM_SEGMENT_H +#define __ASM_ARM_SEGMENT_H + +#define __KERNEL_CS 0x0 +#define __KERNEL_DS 0x0 + +#define __USER_CS 0x1 +#define __USER_DS 0x1 + +#endif /* __ASM_ARM_SEGMENT_H */ + diff -Nru a/include/asm-arm26/semaphore-helper.h b/include/asm-arm26/semaphore-helper.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/semaphore-helper.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,84 @@ +#ifndef ASMARM_SEMAPHORE_HELPER_H +#define ASMARM_SEMAPHORE_HELPER_H + +/* + * These two _must_ execute atomically wrt each other. + */ +static inline void wake_one_more(struct semaphore * sem) +{ + unsigned long flags; + + spin_lock_irqsave(&semaphore_wake_lock, flags); + if (atomic_read(&sem->count) <= 0) + sem->waking++; + spin_unlock_irqrestore(&semaphore_wake_lock, flags); +} + +static inline int waking_non_zero(struct semaphore *sem) +{ + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&semaphore_wake_lock, flags); + if (sem->waking > 0) { + sem->waking--; + ret = 1; + } + spin_unlock_irqrestore(&semaphore_wake_lock, flags); + return ret; +} + +/* + * waking non zero interruptible + * 1 got the lock + * 0 go to sleep + * -EINTR interrupted + * + * We must undo the sem->count down_interruptible() increment while we are + * protected by the spinlock in order to make this atomic_inc() with the + * atomic_read() in wake_one_more(), otherwise we can race. -arca + */ +static inline int waking_non_zero_interruptible(struct semaphore *sem, + struct task_struct *tsk) +{ + unsigned long flags; + int ret = 0; + + spin_lock_irqsave(&semaphore_wake_lock, flags); + if (sem->waking > 0) { + sem->waking--; + ret = 1; + } else if (signal_pending(tsk)) { + atomic_inc(&sem->count); + ret = -EINTR; + } + spin_unlock_irqrestore(&semaphore_wake_lock, flags); + return ret; +} + +/* + * waking_non_zero_try_lock: + * 1 failed to lock + * 0 got the lock + * + * We must undo the sem->count down_interruptible() increment while we are + * protected by the spinlock in order to make this atomic_inc() with the + * atomic_read() in wake_one_more(), otherwise we can race. -arca + */ +static inline int waking_non_zero_trylock(struct semaphore *sem) +{ + unsigned long flags; + int ret = 1; + + spin_lock_irqsave(&semaphore_wake_lock, flags); + if (sem->waking <= 0) + atomic_inc(&sem->count); + else { + sem->waking--; + ret = 0; + } + spin_unlock_irqrestore(&semaphore_wake_lock, flags); + return ret; +} + +#endif diff -Nru a/include/asm-arm26/semaphore.h b/include/asm-arm26/semaphore.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/semaphore.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,128 @@ +/* + * linux/include/asm-arm/semaphore.h + */ +#ifndef __ASM_ARM_SEMAPHORE_H +#define __ASM_ARM_SEMAPHORE_H + +#include <linux/linkage.h> +#include <linux/spinlock.h> +#include <linux/wait.h> +#include <linux/rwsem.h> + +#include <asm/atomic.h> +#include <asm/locks.h> + +struct semaphore { + atomic_t count; + int sleepers; + wait_queue_head_t wait; +#if WAITQUEUE_DEBUG + long __magic; +#endif +}; + +#if WAITQUEUE_DEBUG +# define __SEM_DEBUG_INIT(name) \ + , (long)&(name).__magic +#else +# define __SEM_DEBUG_INIT(name) +#endif + +#define __SEMAPHORE_INIT(name,count) \ + { ATOMIC_INIT(count), 0, \ + __WAIT_QUEUE_HEAD_INITIALIZER((name).wait) \ + __SEM_DEBUG_INIT(name) } + +#define __MUTEX_INITIALIZER(name) \ + __SEMAPHORE_INIT(name,1) + +#define __DECLARE_SEMAPHORE_GENERIC(name,count) \ + struct semaphore name = __SEMAPHORE_INIT(name,count) + +#define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) +#define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0) + +static inline void sema_init(struct semaphore *sem, int val) +{ + atomic_set(&sem->count, val); + sem->sleepers = 0; + init_waitqueue_head(&sem->wait); +#if WAITQUEUE_DEBUG + sem->__magic = (long)&sem->__magic; +#endif +} + +static inline void init_MUTEX(struct semaphore *sem) +{ + sema_init(sem, 1); +} + +static inline void init_MUTEX_LOCKED(struct semaphore *sem) +{ + sema_init(sem, 0); +} + +/* + * special register calling convention + */ +asmlinkage void __down_failed(void); +asmlinkage int __down_interruptible_failed(void); +asmlinkage int __down_trylock_failed(void); +asmlinkage void __up_wakeup(void); + +extern void __down(struct semaphore * sem); +extern int __down_interruptible(struct semaphore * sem); +extern int __down_trylock(struct semaphore * sem); +extern void __up(struct semaphore * sem); + +/* + * This is ugly, but we want the default case to fall through. + * "__down" is the actual routine that waits... + */ +static inline void down(struct semaphore * sem) +{ +#if WAITQUEUE_DEBUG + CHECK_MAGIC(sem->__magic); +#endif + + __down_op(sem, __down_failed); +} + +/* + * This is ugly, but we want the default case to fall through. + * "__down_interruptible" is the actual routine that waits... + */ +static inline int down_interruptible (struct semaphore * sem) +{ +#if WAITQUEUE_DEBUG + CHECK_MAGIC(sem->__magic); +#endif + + return __down_op_ret(sem, __down_interruptible_failed); +} + +static inline int down_trylock(struct semaphore *sem) +{ +#if WAITQUEUE_DEBUG + CHECK_MAGIC(sem->__magic); +#endif + + return __down_op_ret(sem, __down_trylock_failed); +} + +/* + * Note! This is subtle. We jump to wake people up only if + * the semaphore was negative (== somebody was waiting on it). + * The default case (no contention) will result in NO + * jumps for both down() and up(). + */ +static inline void up(struct semaphore * sem) +{ +#if WAITQUEUE_DEBUG + CHECK_MAGIC(sem->__magic); +#endif + + __up_op(sem, __up_wakeup); +} + +#endif diff -Nru a/include/asm-arm26/sembuf.h b/include/asm-arm26/sembuf.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/sembuf.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,25 @@ +#ifndef _ASMARM_SEMBUF_H +#define _ASMARM_SEMBUF_H + +/* + * The semid64_ds structure for arm architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 64-bit time_t to solve y2038 problem + * - 2 miscellaneous 32-bit values + */ + +struct semid64_ds { + struct ipc64_perm sem_perm; /* permissions .. see ipc.h */ + __kernel_time_t sem_otime; /* last semop time */ + unsigned long __unused1; + __kernel_time_t sem_ctime; /* last change time */ + unsigned long __unused2; + unsigned long sem_nsems; /* no. of semaphores in array */ + unsigned long __unused3; + unsigned long __unused4; +}; + +#endif /* _ASMARM_SEMBUF_H */ diff -Nru a/include/asm-arm26/serial.h b/include/asm-arm26/serial.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/serial.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,65 @@ +/* + * linux/include/asm-arm/serial.h + * + * Copyright (C) 1996 Russell King. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Changelog: + * 15-10-1996 RMK Created + */ + +#ifndef __ASM_SERIAL_H +#define __ASM_SERIAL_H + +#include <linux/config.h> + +/* + * This assumes you have a 1.8432 MHz clock for your UART. + * + * It'd be nice if someone built a serial card with a 24.576 MHz + * clock, since the 16550A is capable of handling a top speed of 1.5 + * megabits/second; but this requires the faster clock. + */ +#define BASE_BAUD (1843200 / 16) + +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST) + +#define RS_TABLE_SIZE 16 + +#if defined(CONFIG_ARCH_A5K) + /* UART CLK PORT IRQ FLAGS */ + +#define STD_SERIAL_PORT_DEFNS \ + { 0, BASE_BAUD, 0x3F8, 10, STD_COM_FLAGS }, /* ttyS0 */ \ + { 0, BASE_BAUD, 0x2F8, 10, STD_COM_FLAGS }, /* ttyS1 */ + +#else + +#define STD_SERIAL_PORT_DEFNS \ + { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS0 */ \ + { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS1 */ + +#endif + +#define EXTRA_SERIAL_PORT_DEFNS \ + { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS2 */ \ + { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS3 */ \ + { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS4 */ \ + { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS5 */ \ + { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS6 */ \ + { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS7 */ \ + { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS8 */ \ + { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS9 */ \ + { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS10 */ \ + { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS11 */ \ + { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS12 */ \ + { 0, BASE_BAUD, 0 , 0, STD_COM_FLAGS }, /* ttyS13 */ + +#define SERIAL_PORT_DFNS \ + STD_SERIAL_PORT_DEFNS \ + EXTRA_SERIAL_PORT_DEFNS + +#endif diff -Nru a/include/asm-arm26/setup.h b/include/asm-arm26/setup.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/setup.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,205 @@ +/* + * linux/include/asm/setup.h + * + * Copyright (C) 1997-1999 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Structure passed to kernel to tell it about the + * hardware it's running on. See linux/Documentation/arm/Setup + * for more info. + */ +#ifndef __ASMARM_SETUP_H +#define __ASMARM_SETUP_H + +#define COMMAND_LINE_SIZE 1024 + +/* The list ends with an ATAG_NONE node. */ +#define ATAG_NONE 0x00000000 + +struct tag_header { + u32 size; + u32 tag; +}; + +/* The list must start with an ATAG_CORE node */ +#define ATAG_CORE 0x54410001 + +struct tag_core { + u32 flags; /* bit 0 = read-only */ + u32 pagesize; + u32 rootdev; +}; + +/* it is allowed to have multiple ATAG_MEM nodes */ +#define ATAG_MEM 0x54410002 + +struct tag_mem32 { + u32 size; + u32 start; /* physical start address */ +}; + +/* VGA text type displays */ +#define ATAG_VIDEOTEXT 0x54410003 + +struct tag_videotext { + u8 x; + u8 y; + u16 video_page; + u8 video_mode; + u8 video_cols; + u16 video_ega_bx; + u8 video_lines; + u8 video_isvga; + u16 video_points; +}; + +/* describes how the ramdisk will be used in kernel */ +#define ATAG_RAMDISK 0x54410004 + +struct tag_ramdisk { + u32 flags; /* bit 0 = load, bit 1 = prompt */ + u32 size; /* decompressed ramdisk size in _kilo_ bytes */ + u32 start; /* starting block of floppy-based RAM disk image */ +}; + +/* describes where the compressed ramdisk image lives */ +/* + * this one accidentally used virtual addresses - as such, + * its depreciated. + */ +#define ATAG_INITRD 0x54410005 + +/* describes where the compressed ramdisk image lives */ +#define ATAG_INITRD2 0x54420005 + +struct tag_initrd { + u32 start; /* physical start address */ + u32 size; /* size of compressed ramdisk image in bytes */ +}; + +/* board serial number. "64 bits should be enough for everybody" */ +#define ATAG_SERIAL 0x54410006 + +struct tag_serialnr { + u32 low; + u32 high; +}; + +/* board revision */ +#define ATAG_REVISION 0x54410007 + +struct tag_revision { + u32 rev; +}; + +/* initial values for vesafb-type framebuffers. see struct screen_info + * in include/linux/tty.h + */ +#define ATAG_VIDEOLFB 0x54410008 + +struct tag_videolfb { + u16 lfb_width; + u16 lfb_height; + u16 lfb_depth; + u16 lfb_linelength; + u32 lfb_base; + u32 lfb_size; + u8 red_size; + u8 red_pos; + u8 green_size; + u8 green_pos; + u8 blue_size; + u8 blue_pos; + u8 rsvd_size; + u8 rsvd_pos; +}; + +/* command line: \0 terminated string */ +#define ATAG_CMDLINE 0x54410009 + +struct tag_cmdline { + char cmdline[1]; /* this is the minimum size */ +}; + +/* acorn RiscPC specific information */ +#define ATAG_ACORN 0x41000101 + +struct tag_acorn { + u32 memc_control_reg; + u32 vram_pages; + u8 sounddefault; + u8 adfsdrives; +}; + +/* footbridge memory clock, see arch/arm/mach-footbridge/arch.c */ +#define ATAG_MEMCLK 0x41000402 + +struct tag_memclk { + u32 fmemclk; +}; + +struct tag { + struct tag_header hdr; + union { + struct tag_core core; + struct tag_mem32 mem; + struct tag_videotext videotext; + struct tag_ramdisk ramdisk; + struct tag_initrd initrd; + struct tag_serialnr serialnr; + struct tag_revision revision; + struct tag_videolfb videolfb; + struct tag_cmdline cmdline; + + /* + * Acorn specific + */ + struct tag_acorn acorn; + + /* + * DC21285 specific + */ + struct tag_memclk memclk; + } u; +}; + +struct tagtable { + u32 tag; + int (*parse)(const struct tag *); +}; + +#define __tag __attribute__((unused, __section__(".taglist"))) +#define __tagtable(tag, fn) \ +static struct tagtable __tagtable_##fn __tag = { tag, fn } + +#define tag_member_present(tag,member) \ + ((unsigned long)(&((struct tag *)0L)->member + 1) \ + <= (tag)->hdr.size * 4) + +#define tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size)) +#define tag_size(type) ((sizeof(struct tag_header) + sizeof(struct type)) >> 2) + +#define for_each_tag(t,base) \ + for (t = base; t->hdr.size; t = tag_next(t)) + +/* + * Memory map description + */ +#define NR_BANKS 8 + +struct meminfo { + int nr_banks; + unsigned long end; + struct { + unsigned long start; + unsigned long size; + int node; + } bank[NR_BANKS]; +}; + +extern struct meminfo meminfo; + +#endif diff -Nru a/include/asm-arm26/shmbuf.h b/include/asm-arm26/shmbuf.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/shmbuf.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,42 @@ +#ifndef _ASMARM_SHMBUF_H +#define _ASMARM_SHMBUF_H + +/* + * The shmid64_ds structure for arm architecture. + * Note extra padding because this structure is passed back and forth + * between kernel and user space. + * + * Pad space is left for: + * - 64-bit time_t to solve y2038 problem + * - 2 miscellaneous 32-bit values + */ + +struct shmid64_ds { + struct ipc64_perm shm_perm; /* operation perms */ + size_t shm_segsz; /* size of segment (bytes) */ + __kernel_time_t shm_atime; /* last attach time */ + unsigned long __unused1; + __kernel_time_t shm_dtime; /* last detach time */ + unsigned long __unused2; + __kernel_time_t shm_ctime; /* last change time */ + unsigned long __unused3; + __kernel_pid_t shm_cpid; /* pid of creator */ + __kernel_pid_t shm_lpid; /* pid of last operator */ + unsigned long shm_nattch; /* no. of current attaches */ + unsigned long __unused4; + unsigned long __unused5; +}; + +struct shminfo64 { + unsigned long shmmax; + unsigned long shmmin; + unsigned long shmmni; + unsigned long shmseg; + unsigned long shmall; + unsigned long __unused1; + unsigned long __unused2; + unsigned long __unused3; + unsigned long __unused4; +}; + +#endif /* _ASMARM_SHMBUF_H */ diff -Nru a/include/asm-arm26/shmparam.h b/include/asm-arm26/shmparam.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/shmparam.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,15 @@ +#ifndef _ASMARM_SHMPARAM_H +#define _ASMARM_SHMPARAM_H + +#ifndef SHMMAX +#define SHMMAX 0x003fa000 +#endif + +/* + * This should be the size of the virtually indexed cache/ways, + * or page size, whichever is greater since the cache aliases + * every size/ways bytes. + */ +#define SHMLBA PAGE_SIZE /* attach addr a multiple of this */ + +#endif /* _ASMARM_SHMPARAM_H */ diff -Nru a/include/asm-arm26/sigcontext.h b/include/asm-arm26/sigcontext.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/sigcontext.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,33 @@ +#ifndef _ASMARM_SIGCONTEXT_H +#define _ASMARM_SIGCONTEXT_H + +/* + * Signal context structure - contains all info to do with the state + * before the signal handler was invoked. Note: only add new entries + * to the end of the structure. + */ +struct sigcontext { + unsigned long trap_no; + unsigned long error_code; + unsigned long oldmask; + unsigned long arm_r0; + unsigned long arm_r1; + unsigned long arm_r2; + unsigned long arm_r3; + unsigned long arm_r4; + unsigned long arm_r5; + unsigned long arm_r6; + unsigned long arm_r7; + unsigned long arm_r8; + unsigned long arm_r9; + unsigned long arm_r10; + unsigned long arm_fp; + unsigned long arm_ip; + unsigned long arm_sp; + unsigned long arm_lr; + unsigned long arm_pc; + unsigned long fault_address; +}; + + +#endif diff -Nru a/include/asm-arm26/siginfo.h b/include/asm-arm26/siginfo.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/siginfo.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,6 @@ +#ifndef _ASMARM_SIGINFO_H +#define _ASMARM_SIGINFO_H + +#include <asm-generic/siginfo.h> + +#endif diff -Nru a/include/asm-arm26/signal.h b/include/asm-arm26/signal.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/signal.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,201 @@ +#ifndef _ASMARM_SIGNAL_H +#define _ASMARM_SIGNAL_H + +#include <linux/types.h> + +/* Avoid too many header ordering problems. */ +struct siginfo; + +#ifdef __KERNEL__ +/* Most things should be clean enough to redefine this at will, if care + is taken to make libc match. */ + +#define _NSIG 64 +#define _NSIG_BPW 32 +#define _NSIG_WORDS (_NSIG / _NSIG_BPW) + +typedef unsigned long old_sigset_t; /* at least 32 bits */ + +typedef struct { + unsigned long sig[_NSIG_WORDS]; +} sigset_t; + +#else +/* Here we must cater to libcs that poke about in kernel headers. */ + +#define NSIG 32 +typedef unsigned long sigset_t; + +#endif /* __KERNEL__ */ + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGIOT 6 +#define SIGBUS 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGURG 23 +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGPROF 27 +#define SIGWINCH 28 +#define SIGIO 29 +#define SIGPOLL SIGIO +/* +#define SIGLOST 29 +*/ +#define SIGPWR 30 +#define SIGSYS 31 +#define SIGUNUSED 31 + +/* These should not be considered constants from userland. */ +#define SIGRTMIN 32 +#define SIGRTMAX (_NSIG-1) + +#define SIGSWI 32 + +/* + * SA_FLAGS values: + * + * SA_NOCLDSTOP flag to turn off SIGCHLD when children stop. + * SA_NOCLDWAIT flag on SIGCHLD to inhibit zombies. + * SA_SIGINFO deliver the signal with SIGINFO structs + * SA_THIRTYTWO delivers the signal in 32-bit mode, even if the task + * is running in 26-bit. + * SA_ONSTACK allows alternate signal stacks (see sigaltstack(2)). + * SA_RESTART flag to get restarting signals (which were the default long ago) + * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the + * SA_NODEFER prevents the current signal from being masked in the handler. + * SA_RESETHAND clears the handler when the signal is delivered. + * + * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single + * Unix names RESETHAND and NODEFER respectively. + */ +#define SA_NOCLDSTOP 0x00000001 +#define SA_NOCLDWAIT 0x00000002 /* not supported yet */ +#define SA_SIGINFO 0x00000004 +#define SA_THIRTYTWO 0x02000000 +#define SA_RESTORER 0x04000000 +#define SA_ONSTACK 0x08000000 +#define SA_RESTART 0x10000000 +#define SA_NODEFER 0x40000000 +#define SA_RESETHAND 0x80000000 + +#define SA_NOMASK SA_NODEFER +#define SA_ONESHOT SA_RESETHAND +#define SA_INTERRUPT 0x20000000 /* dummy -- ignored */ + + +/* + * sigaltstack controls + */ +#define SS_ONSTACK 1 +#define SS_DISABLE 2 + +#define MINSIGSTKSZ 2048 +#define SIGSTKSZ 8192 + +#ifdef __KERNEL__ + +/* + * These values of sa_flags are used only by the kernel as part of the + * irq handling routines. + * + * SA_INTERRUPT is also used by the irq handling routines. + * SA_SHIRQ is for shared interrupt support on PCI and EISA. + */ +#define SA_PROBE 0x80000000 +#define SA_SAMPLE_RANDOM 0x10000000 +#define SA_IRQNOMASK 0x08000000 +#define SA_SHIRQ 0x04000000 +#endif + +#define SIG_BLOCK 0 /* for blocking signals */ +#define SIG_UNBLOCK 1 /* for unblocking signals */ +#define SIG_SETMASK 2 /* for setting the signal mask */ + +/* Type of a signal handler. */ +typedef void (*__sighandler_t)(int); + +#define SIG_DFL ((__sighandler_t)0) /* default signal handling */ +#define SIG_IGN ((__sighandler_t)1) /* ignore signal */ +#define SIG_ERR ((__sighandler_t)-1) /* error return from signal */ + +#ifdef __KERNEL__ +struct old_sigaction { + __sighandler_t sa_handler; + old_sigset_t sa_mask; + unsigned long sa_flags; + void (*sa_restorer)(void); +}; + +struct sigaction { + __sighandler_t sa_handler; + unsigned long sa_flags; + void (*sa_restorer)(void); + sigset_t sa_mask; /* mask last for extensibility */ +}; + +struct k_sigaction { + struct sigaction sa; +}; + +#else +/* Here we must cater to libcs that poke about in kernel headers. */ + +struct sigaction { + union { + __sighandler_t _sa_handler; + void (*_sa_sigaction)(int, struct siginfo *, void *); + } _u; + sigset_t sa_mask; + unsigned long sa_flags; + void (*sa_restorer)(void); +}; + +#define sa_handler _u._sa_handler +#define sa_sigaction _u._sa_sigaction + +#endif /* __KERNEL__ */ + +typedef struct sigaltstack { + void *ss_sp; + int ss_flags; + size_t ss_size; +} stack_t; + +#ifdef __KERNEL__ +#include <asm/sigcontext.h> + +#define sigmask(sig) (1UL << ((sig) - 1)) +//FIXME!!! +//#define HAVE_ARCH_GET_SIGNAL_TO_DELIVER + +#endif + + +#ifdef __KERNEL__ +#include <asm/sigcontext.h> +#define ptrace_signal_deliver(regs, cookie) do { } while (0) +#endif + + +#endif diff -Nru a/include/asm-arm26/sizes.h b/include/asm-arm26/sizes.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/sizes.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,52 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the 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 + */ +/* DO NOT EDIT!! - this file automatically generated + * from .s file by awk -f s2h.awk + */ +/* Size defintions + * Copyright (C) ARM Limited 1998. All rights reserved. + */ + +#ifndef __sizes_h +#define __sizes_h 1 + +/* handy sizes */ +#define SZ_1K 0x00000400 +#define SZ_4K 0x00001000 +#define SZ_8K 0x00002000 +#define SZ_16K 0x00004000 +#define SZ_64K 0x00010000 +#define SZ_128K 0x00020000 +#define SZ_256K 0x00040000 +#define SZ_512K 0x00080000 + +#define SZ_1M 0x00100000 +#define SZ_2M 0x00200000 +#define SZ_4M 0x00400000 +#define SZ_8M 0x00800000 +#define SZ_16M 0x01000000 +#define SZ_32M 0x02000000 +#define SZ_64M 0x04000000 +#define SZ_128M 0x08000000 +#define SZ_256M 0x10000000 +#define SZ_512M 0x20000000 + +#define SZ_1G 0x40000000 +#define SZ_2G 0x80000000 + +#endif + +/* END */ diff -Nru a/include/asm-arm26/smp.h b/include/asm-arm26/smp.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/smp.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,10 @@ +#ifndef __ASM_SMP_H +#define __ASM_SMP_H + +#include <linux/config.h> + +#ifdef CONFIG_SMP +#error SMP not supported +#endif + +#endif diff -Nru a/include/asm-arm26/socket.h b/include/asm-arm26/socket.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/socket.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,64 @@ +#ifndef _ASMARM_SOCKET_H +#define _ASMARM_SOCKET_H + +#include <asm/sockios.h> + +/* For setsockopt(2) */ +#define SOL_SOCKET 1 + +#define SO_DEBUG 1 +#define SO_REUSEADDR 2 +#define SO_TYPE 3 +#define SO_ERROR 4 +#define SO_DONTROUTE 5 +#define SO_BROADCAST 6 +#define SO_SNDBUF 7 +#define SO_RCVBUF 8 +#define SO_KEEPALIVE 9 +#define SO_OOBINLINE 10 +#define SO_NO_CHECK 11 +#define SO_PRIORITY 12 +#define SO_LINGER 13 +#define SO_BSDCOMPAT 14 +/* To add :#define SO_REUSEPORT 15 */ +#define SO_PASSCRED 16 +#define SO_PEERCRED 17 +#define SO_RCVLOWAT 18 +#define SO_SNDLOWAT 19 +#define SO_RCVTIMEO 20 +#define SO_SNDTIMEO 21 + +/* Security levels - as per NRL IPv6 - don't actually do anything */ +#define SO_SECURITY_AUTHENTICATION 22 +#define SO_SECURITY_ENCRYPTION_TRANSPORT 23 +#define SO_SECURITY_ENCRYPTION_NETWORK 24 + +#define SO_BINDTODEVICE 25 + +/* Socket filtering */ +#define SO_ATTACH_FILTER 26 +#define SO_DETACH_FILTER 27 + +#define SO_PEERNAME 28 +#define SO_TIMESTAMP 29 +#define SCM_TIMESTAMP SO_TIMESTAMP + +#define SO_ACCEPTCONN 30 + +/* Nast libc5 fixup - bletch */ +#if defined(__KERNEL__) +/* Socket types. */ +#define SOCK_STREAM 1 /* stream (connection) socket */ +#define SOCK_DGRAM 2 /* datagram (conn.less) socket */ +#define SOCK_RAW 3 /* raw socket */ +#define SOCK_RDM 4 /* reliably-delivered message */ +#define SOCK_SEQPACKET 5 /* sequential packet socket */ +#define SOCK_PACKET 10 /* linux specific way of */ + /* getting packets at the dev */ + /* level. For writing rarp and */ + /* other similar things on the */ + /* user level. */ +#define SOCK_MAX (SOCK_PACKET+1) +#endif + +#endif /* _ASM_SOCKET_H */ diff -Nru a/include/asm-arm26/sockios.h b/include/asm-arm26/sockios.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/sockios.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,12 @@ +#ifndef __ARCH_ARM_SOCKIOS_H +#define __ARCH_ARM_SOCKIOS_H + +/* Socket-level I/O control calls. */ +#define FIOSETOWN 0x8901 +#define SIOCSPGRP 0x8902 +#define FIOGETOWN 0x8903 +#define SIOCGPGRP 0x8904 +#define SIOCATMARK 0x8905 +#define SIOCGSTAMP 0x8906 /* Get stamp */ + +#endif diff -Nru a/include/asm-arm26/softirq.h b/include/asm-arm26/softirq.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/softirq.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,20 @@ +#ifndef __ASM_SOFTIRQ_H +#define __ASM_SOFTIRQ_H + +#include <linux/preempt.h> +#include <asm/hardirq.h> + +#define local_bh_disable() \ + do { preempt_count() += SOFTIRQ_OFFSET; barrier(); } while (0) +#define __local_bh_enable() \ + do { barrier(); preempt_count() -= SOFTIRQ_OFFSET; } while (0) + +#define local_bh_enable() \ +do { \ + __local_bh_enable(); \ + if (unlikely(!in_interrupt() && softirq_pending(smp_processor_id()))) \ + __asm__("bl%? __do_softirq": : : "lr");/* out of line */\ + preempt_check_resched(); \ +} while (0) + +#endif /* __ASM_SOFTIRQ_H */ diff -Nru a/include/asm-arm26/spinlock.h b/include/asm-arm26/spinlock.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/spinlock.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,6 @@ +#ifndef __ASM_SPINLOCK_H +#define __ASM_SPINLOCK_H + +#error ARM architecture does not support SMP spin locks + +#endif /* __ASM_SPINLOCK_H */ diff -Nru a/include/asm-arm26/stat.h b/include/asm-arm26/stat.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/stat.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,79 @@ +#ifndef _ASMARM_STAT_H +#define _ASMARM_STAT_H + +struct __old_kernel_stat { + unsigned short st_dev; + unsigned short st_ino; + unsigned short st_mode; + unsigned short st_nlink; + unsigned short st_uid; + unsigned short st_gid; + unsigned short st_rdev; + unsigned long st_size; + unsigned long st_atime; + unsigned long st_mtime; + unsigned long st_ctime; +}; + +struct stat { + unsigned short st_dev; + unsigned short __pad1; + unsigned long st_ino; + unsigned short st_mode; + unsigned short st_nlink; + unsigned short st_uid; + unsigned short st_gid; + unsigned short st_rdev; + unsigned short __pad2; + unsigned long st_size; + unsigned long st_blksize; + unsigned long st_blocks; + unsigned long st_atime; + unsigned long st_atime_nsec; + unsigned long st_mtime; + unsigned long st_mtime_nsec; + unsigned long st_ctime; + unsigned long st_ctime_nsec; + unsigned long __unused4; + unsigned long __unused5; +}; + +/* This matches struct stat64 in glibc2.1, hence the absolutely + * insane amounts of padding around dev_t's. + */ +struct stat64 { + unsigned short st_dev; + unsigned char __pad0b[6]; + unsigned char __pad0[4]; + +#define STAT64_HAS_BROKEN_ST_INO 1 + unsigned long __st_ino; + unsigned int st_mode; + unsigned int st_nlink; + + unsigned long st_uid; + unsigned long st_gid; + + unsigned short st_rdev; + unsigned char __pad3b[6]; + unsigned char __pad3[4]; + + long long st_size; + unsigned long st_blksize; + + unsigned long st_blocks; /* Number 512-byte blocks allocated. */ + unsigned long __pad4; /* Future possible st_blocks hi bits */ + + unsigned long st_atime; + unsigned long st_atime_nsec; + + unsigned long st_mtime; + unsigned long st_mtime_nsec; + + unsigned long st_ctime; + unsigned long st_ctime_nsec; + + unsigned long long st_ino; +}; + +#endif diff -Nru a/include/asm-arm26/statfs.h b/include/asm-arm26/statfs.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/statfs.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,25 @@ +#ifndef _ASMARM_STATFS_H +#define _ASMARM_STATFS_H + +#ifndef __KERNEL_STRICT_NAMES + +#include <linux/types.h> + +typedef __kernel_fsid_t fsid_t; + +#endif + +struct statfs { + long f_type; + long f_bsize; + long f_blocks; + long f_bfree; + long f_bavail; + long f_files; + long f_ffree; + __kernel_fsid_t f_fsid; + long f_namelen; + long f_spare[6]; +}; + +#endif diff -Nru a/include/asm-arm26/string.h b/include/asm-arm26/string.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/string.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,43 @@ +#ifndef __ASM_ARM_STRING_H +#define __ASM_ARM_STRING_H + +/* + * We don't do inline string functions, since the + * optimised inline asm versions are not small. + */ + +#define __HAVE_ARCH_STRRCHR +extern char * strrchr(const char * s, int c); + +#define __HAVE_ARCH_STRCHR +extern char * strchr(const char * s, int c); + +#define __HAVE_ARCH_MEMCPY +extern void * memcpy(void *, const void *, __kernel_size_t); + +#define __HAVE_ARCH_MEMMOVE +extern void * memmove(void *, const void *, __kernel_size_t); + +#define __HAVE_ARCH_MEMCHR +extern void * memchr(const void *, int, __kernel_size_t); + +#define __HAVE_ARCH_MEMZERO +#define __HAVE_ARCH_MEMSET +extern void * memset(void *, int, __kernel_size_t); + +extern void __memzero(void *ptr, __kernel_size_t n); + +#define memset(p,v,n) \ + ({ \ + if ((n) != 0) { \ + if (__builtin_constant_p((v)) && (v) == 0) \ + __memzero((p),(n)); \ + else \ + memset((p),(v),(n)); \ + } \ + (p); \ + }) + +#define memzero(p,n) ({ if ((n) != 0) __memzero((p),(n)); (p); }) + +#endif diff -Nru a/include/asm-arm26/suspend.h b/include/asm-arm26/suspend.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/suspend.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,4 @@ +#ifdef _ASMARM_SUSPEND_H +#define _ASMARM_SUSPEND_H + +#endif diff -Nru a/include/asm-arm26/sysirq.h b/include/asm-arm26/sysirq.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/sysirq.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,61 @@ +/* + * linux/include/asm-arm/arch-arc/irqs.h + * + * Copyright (C) 1996 Russell King, Dave Gilbert + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Modifications: + * 04-04-1998 PJB Merged arc and a5k versions + */ + +#include <linux/config.h> + +#if defined(CONFIG_ARCH_A5K) +#define IRQ_PRINTER 0 +#define IRQ_BATLOW 1 +#define IRQ_FLOPPYINDEX 2 +#define IRQ_FLOPPYDISK 12 +#elif defined(CONFIG_ARCH_ARC) +#define IRQ_PRINTERBUSY 0 +#define IRQ_SERIALRING 1 +#define IRQ_PRINTERACK 2 +#define IRQ_FLOPPYCHANGED 12 +#endif + +#define IRQ_VSYNCPULSE 3 +#define IRQ_POWERON 4 +#define IRQ_TIMER0 5 +#define IRQ_TIMER1 6 +#define IRQ_IMMEDIATE 7 +#define IRQ_EXPCARDFIQ 8 +#define IRQ_SOUNDCHANGE 9 +#define IRQ_SERIALPORT 10 +#define IRQ_HARDDISK 11 +#define IRQ_EXPANSIONCARD 13 +#define IRQ_KEYBOARDTX 14 +#define IRQ_KEYBOARDRX 15 + +#if defined(CONFIG_ARCH_A5K) +#define FIQ_SERIALPORT 4 +#elif defined(CONFIG_ARCH_ARC) +#define FIQ_FLOPPYIRQ 1 +#define FIQ_FD1772 FIQ_FLOPPYIRQ +#endif + +#define FIQ_FLOPPYDATA 0 +#define FIQ_ECONET 2 +#define FIQ_EXPANSIONCARD 6 +#define FIQ_FORCE 7 + +#define IRQ_TIMER IRQ_TIMER0 + +/* + * This is the offset of the FIQ "IRQ" numbers + */ +#define FIQ_START 64 + +#define irq_cannonicalize(i) (i) + diff -Nru a/include/asm-arm26/system.h b/include/asm-arm26/system.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/system.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,204 @@ +#ifndef __ASM_ARM_SYSTEM_H +#define __ASM_ARM_SYSTEM_H + +#ifdef __KERNEL__ + +#include <linux/config.h> +#include <linux/kernel.h> +#include <asm/proc-fns.h> + +#define vectors_base() (0) + +static inline unsigned long __xchg(unsigned long x, volatile void *ptr, int size) +{ + extern void __bad_xchg(volatile void *, int); + + switch (size) { + case 1: return cpu_xchg_1(x, ptr); + case 4: return cpu_xchg_4(x, ptr); + default: __bad_xchg(ptr, size); + } + return 0; +} + +/* + * We need to turn the caches off before calling the reset vector - RiscOS + * messes up if we don't + */ +#define proc_hard_reset() cpu_proc_fin() + +/* + * A couple of speedups for the ARM + */ + +/* + * Enable IRQs (sti) + */ +#define local_irq_enable() \ + do { \ + unsigned long temp; \ + __asm__ __volatile__( \ +" mov %0, pc @ sti\n" \ +" bic %0, %0, #0x08000000\n" \ +" teqp %0, #0\n" \ + : "=r" (temp) \ + : \ + : "memory"); \ + } while(0) + +/* + * Disable IRQs (cli) + */ +#define local_irq_disable() \ + do { \ + unsigned long temp; \ + __asm__ __volatile__( \ +" mov %0, pc @ cli\n" \ +" orr %0, %0, #0x08000000\n" \ +" teqp %0, #0\n" \ + : "=r" (temp) \ + : \ + : "memory"); \ + } while(0) + +/* Disable FIQs (clf) */ + +#define __clf() do { \ + unsigned long temp; \ + __asm__ __volatile__( \ +" mov %0, pc @ clf\n" \ +" orr %0, %0, #0x04000000\n" \ +" teqp %0, #0\n" \ + : "=r" (temp)); \ + } while(0) + +/* Enable FIQs (stf) */ + +#define __stf() do { \ + unsigned long temp; \ + __asm__ __volatile__( \ +" mov %0, pc @ stf\n" \ +" bic %0, %0, #0x04000000\n" \ +" teqp %0, #0\n" \ + : "=r" (temp)); \ + } while(0) + +/* + * save current IRQ & FIQ state + */ +#define local_save_flags(x) \ + do { \ + __asm__ __volatile__( \ +" mov %0, pc @ save_flags\n" \ +" and %0, %0, #0x0c000000\n" \ + : "=r" (x)); \ + } while (0) + +/* + * Save the current interrupt enable state & disable IRQs + */ +#define local_irq_save(x) \ + do { \ + unsigned long temp; \ + __asm__ __volatile__( \ +" mov %0, pc @ save_flags_cli\n" \ +" orr %1, %0, #0x08000000\n" \ +" and %0, %0, #0x0c000000\n" \ +" teqp %1, #0\n" \ + : "=r" (x), "=r" (temp) \ + : \ + : "memory"); \ + } while (0) + +/* + * restore saved IRQ & FIQ state + */ +#define local_irq_restore(x) \ + do { \ + unsigned long temp; \ + __asm__ __volatile__( \ +" mov %0, pc @ restore_flags\n" \ +" bic %0, %0, #0x0c000000\n" \ +" orr %0, %0, %1\n" \ +" teqp %0, #0\n" \ + : "=&r" (temp) \ + : "r" (x) \ + : "memory"); \ + } while (0) + + +struct thread_info; + +/* information about the system we're running on */ +extern unsigned int system_rev; +extern unsigned int system_serial_low; +extern unsigned int system_serial_high; + +struct pt_regs; + +void die(const char *msg, struct pt_regs *regs, int err) + __attribute__((noreturn)); + +void die_if_kernel(const char *str, struct pt_regs *regs, int err); + +void hook_fault_code(int nr, int (*fn)(unsigned long, unsigned int, + struct pt_regs *), + int sig, const char *name); + +#define xchg(ptr,x) \ + ((__typeof__(*(ptr)))__xchg((unsigned long)(x),(ptr),sizeof(*(ptr)))) + +#define tas(ptr) (xchg((ptr),1)) + +extern asmlinkage void __backtrace(void); + +/* + * Include processor dependent parts + */ + +#define mb() __asm__ __volatile__ ("" : : : "memory") +#define rmb() mb() +#define wmb() mb() +#define nop() __asm__ __volatile__("mov\tr0,r0\t@ nop\n\t"); + +#define prepare_to_switch() do { } while(0) + +/* + * switch_to(prev, next) should switch from task `prev' to `next' + * `prev' will never be the same as `next'. + * The `mb' is to tell GCC not to cache `current' across this call. + */ +struct thread_info; + +extern struct task_struct *__switch_to(struct thread_info *, struct thread_info *); + +#define switch_to(prev,next,last) \ + do { \ + __switch_to(prev->thread_info,next->thread_info); \ + mb(); \ + } while (0) + + +#ifdef CONFIG_SMP +#error SMP not supported +#endif /* CONFIG_SMP */ + +#define irqs_disabled() \ +({ \ + unsigned long flags; \ + local_save_flags(flags); \ + flags & PSR_I_BIT; \ +}) + +#define set_mb(var, value) do { var = value; mb(); } while (0) +#define smp_mb() barrier() +#define smp_rmb() barrier() +#define smp_wmb() barrier() +#define smp_read_barrier_depends() do { } while(0) + +#define clf() __clf() +#define stf() __stf() + +#endif /* __KERNEL__ */ + +#endif diff -Nru a/include/asm-arm26/termbits.h b/include/asm-arm26/termbits.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/termbits.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,170 @@ +#ifndef __ASM_ARM_TERMBITS_H +#define __ASM_ARM_TERMBITS_H + +typedef unsigned char cc_t; +typedef unsigned int speed_t; +typedef unsigned int tcflag_t; + +#define NCCS 19 +struct termios { + tcflag_t c_iflag; /* input mode flags */ + tcflag_t c_oflag; /* output mode flags */ + tcflag_t c_cflag; /* control mode flags */ + tcflag_t c_lflag; /* local mode flags */ + cc_t c_line; /* line discipline */ + cc_t c_cc[NCCS]; /* control characters */ +}; + +/* c_cc characters */ +#define VINTR 0 +#define VQUIT 1 +#define VERASE 2 +#define VKILL 3 +#define VEOF 4 +#define VTIME 5 +#define VMIN 6 +#define VSWTC 7 +#define VSTART 8 +#define VSTOP 9 +#define VSUSP 10 +#define VEOL 11 +#define VREPRINT 12 +#define VDISCARD 13 +#define VWERASE 14 +#define VLNEXT 15 +#define VEOL2 16 + +/* c_iflag bits */ +#define IGNBRK 0000001 +#define BRKINT 0000002 +#define IGNPAR 0000004 +#define PARMRK 0000010 +#define INPCK 0000020 +#define ISTRIP 0000040 +#define INLCR 0000100 +#define IGNCR 0000200 +#define ICRNL 0000400 +#define IUCLC 0001000 +#define IXON 0002000 +#define IXANY 0004000 +#define IXOFF 0010000 +#define IMAXBEL 0020000 + +/* c_oflag bits */ +#define OPOST 0000001 +#define OLCUC 0000002 +#define ONLCR 0000004 +#define OCRNL 0000010 +#define ONOCR 0000020 +#define ONLRET 0000040 +#define OFILL 0000100 +#define OFDEL 0000200 +#define NLDLY 0000400 +#define NL0 0000000 +#define NL1 0000400 +#define CRDLY 0003000 +#define CR0 0000000 +#define CR1 0001000 +#define CR2 0002000 +#define CR3 0003000 +#define TABDLY 0014000 +#define TAB0 0000000 +#define TAB1 0004000 +#define TAB2 0010000 +#define TAB3 0014000 +#define XTABS 0014000 +#define BSDLY 0020000 +#define BS0 0000000 +#define BS1 0020000 +#define VTDLY 0040000 +#define VT0 0000000 +#define VT1 0040000 +#define FFDLY 0100000 +#define FF0 0000000 +#define FF1 0100000 + +/* c_cflag bit meaning */ +#define CBAUD 0010017 +#define B0 0000000 /* hang up */ +#define B50 0000001 +#define B75 0000002 +#define B110 0000003 +#define B134 0000004 +#define B150 0000005 +#define B200 0000006 +#define B300 0000007 +#define B600 0000010 +#define B1200 0000011 +#define B1800 0000012 +#define B2400 0000013 +#define B4800 0000014 +#define B9600 0000015 +#define B19200 0000016 +#define B38400 0000017 +#define EXTA B19200 +#define EXTB B38400 +#define CSIZE 0000060 +#define CS5 0000000 +#define CS6 0000020 +#define CS7 0000040 +#define CS8 0000060 +#define CSTOPB 0000100 +#define CREAD 0000200 +#define PARENB 0000400 +#define PARODD 0001000 +#define HUPCL 0002000 +#define CLOCAL 0004000 +#define CBAUDEX 0010000 +#define B57600 0010001 +#define B115200 0010002 +#define B230400 0010003 +#define B460800 0010004 +#define B500000 0010005 +#define B576000 0010006 +#define B921600 0010007 +#define B1000000 0010010 +#define B1152000 0010011 +#define B1500000 0010012 +#define B2000000 0010013 +#define B2500000 0010014 +#define B3000000 0010015 +#define B3500000 0010016 +#define B4000000 0010017 +#define CIBAUD 002003600000 /* input baud rate (not used) */ +#define CMSPAR 010000000000 /* mark or space (stick) parity */ +#define CRTSCTS 020000000000 /* flow control */ + +/* c_lflag bits */ +#define ISIG 0000001 +#define ICANON 0000002 +#define XCASE 0000004 +#define ECHO 0000010 +#define ECHOE 0000020 +#define ECHOK 0000040 +#define ECHONL 0000100 +#define NOFLSH 0000200 +#define TOSTOP 0000400 +#define ECHOCTL 0001000 +#define ECHOPRT 0002000 +#define ECHOKE 0004000 +#define FLUSHO 0010000 +#define PENDIN 0040000 +#define IEXTEN 0100000 + +/* tcflow() and TCXONC use these */ +#define TCOOFF 0 +#define TCOON 1 +#define TCIOFF 2 +#define TCION 3 + +/* tcflush() and TCFLSH use these */ +#define TCIFLUSH 0 +#define TCOFLUSH 1 +#define TCIOFLUSH 2 + +/* tcsetattr uses these */ +#define TCSANOW 0 +#define TCSADRAIN 1 +#define TCSAFLUSH 2 + +#endif /* __ASM_ARM_TERMBITS_H */ diff -Nru a/include/asm-arm26/termios.h b/include/asm-arm26/termios.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/termios.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,108 @@ +#ifndef __ASM_ARM_TERMIOS_H +#define __ASM_ARM_TERMIOS_H + +#include <asm/termbits.h> +#include <asm/ioctls.h> + +struct winsize { + unsigned short ws_row; + unsigned short ws_col; + unsigned short ws_xpixel; + unsigned short ws_ypixel; +}; + +#define NCC 8 +struct termio { + unsigned short c_iflag; /* input mode flags */ + unsigned short c_oflag; /* output mode flags */ + unsigned short c_cflag; /* control mode flags */ + unsigned short c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[NCC]; /* control characters */ +}; + +#ifdef __KERNEL__ +/* intr=^C quit=^| erase=del kill=^U + eof=^D vtime=\0 vmin=\1 sxtc=\0 + start=^Q stop=^S susp=^Z eol=\0 + reprint=^R discard=^U werase=^W lnext=^V + eol2=\0 +*/ +#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0" +#endif + +/* modem lines */ +#define TIOCM_LE 0x001 +#define TIOCM_DTR 0x002 +#define TIOCM_RTS 0x004 +#define TIOCM_ST 0x008 +#define TIOCM_SR 0x010 +#define TIOCM_CTS 0x020 +#define TIOCM_CAR 0x040 +#define TIOCM_RNG 0x080 +#define TIOCM_DSR 0x100 +#define TIOCM_CD TIOCM_CAR +#define TIOCM_RI TIOCM_RNG +#define TIOCM_OUT1 0x2000 +#define TIOCM_OUT2 0x4000 +#define TIOCM_LOOP 0x8000 + +/* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */ + +/* line disciplines */ +#define N_TTY 0 +#define N_SLIP 1 +#define N_MOUSE 2 +#define N_PPP 3 +#define N_STRIP 4 +#define N_AX25 5 +#define N_X25 6 /* X.25 async */ +#define N_6PACK 7 +#define N_MASC 8 /* Reserved for Mobitex module <kaz@cafe.net> */ +#define N_R3964 9 /* Reserved for Simatic R3964 module */ +#define N_PROFIBUS_FDL 10 /* Reserved for Profibus <Dave@mvhi.com> */ +#define N_IRDA 11 /* Linux IrDa - http://irda.sourceforge.net/ */ +#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */ +#define N_HDLC 13 /* synchronous HDLC */ +#define N_SYNC_PPP 14 +#define N_HCI 15 /* Bluetooth HCI UART */ + +#ifdef __KERNEL__ + +/* + * Translate a "termio" structure into a "termios". Ugh. + */ +#define SET_LOW_TERMIOS_BITS(termios, termio, x) { \ + unsigned short __tmp; \ + get_user(__tmp,&(termio)->x); \ + *(unsigned short *) &(termios)->x = __tmp; \ +} + +#define user_termio_to_kernel_termios(termios, termio) \ +({ \ + SET_LOW_TERMIOS_BITS(termios, termio, c_iflag); \ + SET_LOW_TERMIOS_BITS(termios, termio, c_oflag); \ + SET_LOW_TERMIOS_BITS(termios, termio, c_cflag); \ + SET_LOW_TERMIOS_BITS(termios, termio, c_lflag); \ + copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \ +}) + +/* + * Translate a "termios" structure into a "termio". Ugh. + */ +#define kernel_termios_to_user_termio(termio, termios) \ +({ \ + put_user((termios)->c_iflag, &(termio)->c_iflag); \ + put_user((termios)->c_oflag, &(termio)->c_oflag); \ + put_user((termios)->c_cflag, &(termio)->c_cflag); \ + put_user((termios)->c_lflag, &(termio)->c_lflag); \ + put_user((termios)->c_line, &(termio)->c_line); \ + copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \ +}) + +#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios)) +#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios)) + +#endif /* __KERNEL__ */ + +#endif /* __ASM_ARM_TERMIOS_H */ diff -Nru a/include/asm-arm26/thread_info.h b/include/asm-arm26/thread_info.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/thread_info.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,144 @@ +/* + * linux/include/asm-arm26/thread_info.h + * + * Copyright (C) 2002 Russell King. + * Copyright (C) 2003 Ian Molton. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#ifndef __ASM_ARM_THREAD_INFO_H +#define __ASM_ARM_THREAD_INFO_H + +#ifdef __KERNEL__ + +#ifndef __ASSEMBLY__ + +struct task_struct; +struct exec_domain; + +#include <asm/fpstate.h> +#include <asm/ptrace.h> +#include <asm/types.h> + +typedef unsigned long mm_segment_t; + +struct cpu_context_save { + __u32 r4; + __u32 r5; + __u32 r6; + __u32 r7; + __u32 r8; + __u32 r9; + __u32 sl; + __u32 fp; + __u32 sp; + __u32 pc; +}; + +/* + * low level task data that entry.S needs immediate access to. + * We assume cpu_context follows immedately after cpu_domain. + */ +struct thread_info { + unsigned long flags; /* low level flags */ + __s32 preempt_count; /* 0 => preemptable, <0 => bug */ + mm_segment_t addr_limit; /* address limit */ + struct task_struct *task; /* main task structure */ + struct exec_domain *exec_domain; /* execution domain */ + __u32 cpu; /* cpu */ + struct cpu_context_save cpu_context; /* cpu context */ + struct restart_block restart_block; + union fp_state fpstate; +}; + +#define INIT_THREAD_INFO(tsk) \ +{ \ + .task &tsk, \ + .exec_domain &default_exec_domain, \ + .flags 0, \ + .preempt_count 0, \ + .addr_limit KERNEL_DS, \ + .restart_block = { \ + .fn = do_no_restart_syscall, \ + }, \ +} + +#define init_thread_info (init_thread_union.thread_info) +#define init_stack (init_thread_union.stack) + +/* + * how to get the thread information struct from C + */ +static inline struct thread_info *current_thread_info(void) __attribute__ (( __const__ )); + +static inline struct thread_info *current_thread_info(void) +{ + register unsigned long sp asm ("sp"); + return (struct thread_info *)(sp & ~0x1fff); +} + +/* FIXME - PAGE_SIZE < 32K */ +#define THREAD_SIZE (8192) +/*FIXME INIT_THREAD_SIZE - how big? */ +//#define INIT_THREAD_SIZE (65536) +#define __get_user_regs(x) (((struct pt_regs *)((unsigned long)(x) + THREAD_SIZE - 8)) - 1) + +extern struct thread_info *alloc_thread_info(void); +extern void free_thread_info(struct thread_info *); + +#define get_thread_info(ti) get_task_struct((ti)->task) +#define put_thread_info(ti) put_task_struct((ti)->task) + +#define thread_saved_pc(tsk) \ + ((unsigned long)(pc_pointer((tsk)->thread_info->cpu_context.pc))) +#define thread_saved_fp(tsk) \ + ((unsigned long)((tsk)->thread_info->cpu_context.fp)) + +#else /* !__ASSEMBLY__ */ + +#define TI_FLAGS 0 +#define TI_PREEMPT 4 +#define TI_ADDR_LIMIT 8 +#define TI_TASK 12 +#define TI_EXEC_DOMAIN 16 +#define TI_CPU 20 +#define TI_CPU_SAVE 24 +#define TI_RESTART_BLOCK 28 +#define TI_FPSTATE 68 + +#endif + +#define PREEMPT_ACTIVE 0x04000000 + +/* + * thread information flags: + * TIF_SYSCALL_TRACE - syscall trace active + * TIF_NOTIFY_RESUME - resumption notification requested + * TIF_SIGPENDING - signal pending + * TIF_NEED_RESCHED - rescheduling necessary + * TIF_USEDFPU - FPU was used by this task this quantum (SMP) + * TIF_POLLING_NRFLAG - true if poll_idle() is polling TIF_NEED_RESCHED + */ +#define TIF_NOTIFY_RESUME 0 +#define TIF_SIGPENDING 1 +#define TIF_NEED_RESCHED 2 +#define TIF_SYSCALL_TRACE 8 +#define TIF_USED_FPU 16 +#define TIF_POLLING_NRFLAG 17 + +#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME) +#define _TIF_SIGPENDING (1 << TIF_SIGPENDING) +#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED) +#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE) +#define _TIF_USED_FPU (1 << TIF_USED_FPU) +#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG) + +/* + * Change these and you break ASM code in entry-common.S + */ +#define _TIF_WORK_MASK 0x000000ff + +#endif /* __KERNEL__ */ +#endif /* __ASM_ARM_THREAD_INFO_H */ diff -Nru a/include/asm-arm26/timex.h b/include/asm-arm26/timex.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/timex.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,31 @@ +/* + * linux/include/asm-arm/timex.h + * + * Copyright (C) 1997,1998 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Architecture Specific TIME specifications + */ +#ifndef _ASMARM_TIMEX_H +#define _ASMARM_TIMEX_H + +/* + * On the RiscPC, the clock ticks at 2MHz. + */ +#define CLOCK_TICK_RATE 2000000 + +/* IS THAT RIGHT ON A5000? FIXME */ + +typedef unsigned long cycles_t; + +extern cycles_t cacheflush_time; + +static inline cycles_t get_cycles (void) +{ + return 0; +} + +#endif diff -Nru a/include/asm-arm26/tlb.h b/include/asm-arm26/tlb.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/tlb.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,62 @@ +#ifndef __ASMARM_TLB_H +#define __ASMARM_TLB_H + +#include <asm/tlbflush.h> + +/* + * TLB handling. This allows us to remove pages from the page + * tables, and efficiently handle the TLB issues. + */ +struct mmu_gather { + struct mm_struct *mm; + unsigned int freed; + + unsigned int flushes; + unsigned int avoided_flushes; +}; + +extern struct mmu_gather mmu_gathers[NR_CPUS]; + +static inline struct mmu_gather * +tlb_gather_mmu(struct mm_struct *mm, unsigned int full_mm_flush) +{ + int cpu = smp_processor_id(); + struct mmu_gather *tlb = &mmu_gathers[cpu]; + + tlb->mm = mm; + tlb->freed = 0; + + return tlb; +} + +static inline void +tlb_finish_mmu(struct mmu_gather *tlb, unsigned long start, unsigned long end) +{ + struct mm_struct *mm = tlb->mm; + unsigned long freed = tlb->freed; + int rss = mm->rss; + + if (rss < freed) + freed = rss; + mm->rss = rss - freed; + + if (freed) { + flush_tlb_mm(mm); + tlb->flushes++; + } else { + tlb->avoided_flushes++; + } + + /* keep the page table cache within bounds */ + check_pgt_cache(); +} + +#define tlb_remove_tlb_entry(tlb,ptep,address) do { } while (0) +#define tlb_start_vma(tlb,vma) do { } while (0) +#define tlb_end_vma(tlb,vma) do { } while (0) + +#define tlb_remove_page(tlb,page) free_page_and_swap_cache(page) +#define pte_free_tlb(tlb,ptep) pte_free(ptep) +#define pmd_free_tlb(tlb,pmdp) pmd_free(pmdp) + +#endif diff -Nru a/include/asm-arm26/tlbflush.h b/include/asm-arm26/tlbflush.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/tlbflush.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,70 @@ +#ifndef __ASMARM_TLBFLUSH_H +#define __ASMARM_TLBFLUSH_H + +/* + * TLB flushing: + * + * - flush_tlb_all() flushes all processes TLBs + * - flush_tlb_mm(mm) flushes the specified mm context TLB's + * - flush_tlb_page(vma, vmaddr) flushes one page + * - flush_tlb_range(vma, start, end) flushes a range of pages + */ + +#define flush_tlb_all() memc_update_all() +#define flush_tlb_mm(mm) memc_update_mm(mm) +#define flush_tlb_page(vma, vmaddr) do { printk("flush_tlb_page\n");} while (0) // IS THIS RIGHT? +#define flush_tlb_range(vma,start,end) \ + do { memc_update_mm(vma->vm_mm); (void)(start); (void)(end); } while (0) +#define flush_tlb_pgtables(mm,start,end) do { printk("flush_tlb_pgtables\n");} while (0) +#define flush_tlb_kernel_range(s,e) do { printk("flush_tlb_range\n");} while (0) + +/* + * The following handle the weird MEMC chip + */ +static inline void memc_update_all(void) +{ + struct task_struct *p; + cpu_memc_update_all(init_mm.pgd); + for_each_process(p) { + if (!p->mm) + continue; + cpu_memc_update_all(p->mm->pgd); + } + processor._set_pgd(current->active_mm->pgd); +} + +static inline void memc_update_mm(struct mm_struct *mm) +{ + cpu_memc_update_all(mm->pgd); + + if (mm == current->active_mm) + processor._set_pgd(mm->pgd); +} + +static inline void +memc_clear(struct mm_struct *mm, struct page *page) +{ + cpu_memc_update_entry(mm->pgd, (unsigned long) page_address(page), 0); + + if (mm == current->active_mm) + processor._set_pgd(mm->pgd); +} + +static inline void +memc_update_addr(struct mm_struct *mm, pte_t pte, unsigned long vaddr) +{ + cpu_memc_update_entry(mm->pgd, pte_val(pte), vaddr); + + if (mm == current->active_mm) + processor._set_pgd(mm->pgd); +} + +static inline void +update_mmu_cache(struct vm_area_struct *vma, unsigned long addr, pte_t pte) +{ + struct mm_struct *mm = vma->vm_mm; +printk("update_mmu_cache\n"); + memc_update_addr(mm, pte, addr); +} + +#endif diff -Nru a/include/asm-arm26/topology.h b/include/asm-arm26/topology.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/topology.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,6 @@ +#ifndef _ASM_ARM_TOPOLOGY_H +#define _ASM_ARM_TOPOLOGY_H + +#include <asm-generic/topology.h> + +#endif /* _ASM_ARM_TOPOLOGY_H */ diff -Nru a/include/asm-arm26/types.h b/include/asm-arm26/types.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/types.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,59 @@ +#ifndef __ASM_ARM_TYPES_H +#define __ASM_ARM_TYPES_H + +#ifndef __ASSEMBLY__ + +typedef unsigned short umode_t; + +/* + * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the + * header files exported to user space + */ + +typedef __signed__ char __s8; +typedef unsigned char __u8; + +typedef __signed__ short __s16; +typedef unsigned short __u16; + +typedef __signed__ int __s32; +typedef unsigned int __u32; + +#if defined(__GNUC__) && !defined(__STRICT_ANSI__) +typedef __signed__ long long __s64; +typedef unsigned long long __u64; +#endif + +#endif /* __ASSEMBLY__ */ + +/* + * These aren't exported outside the kernel to avoid name space clashes + */ +#ifdef __KERNEL__ + +#define BITS_PER_LONG 32 + +#ifndef __ASSEMBLY__ + +typedef signed char s8; +typedef unsigned char u8; + +typedef signed short s16; +typedef unsigned short u16; + +typedef signed int s32; +typedef unsigned int u32; + +typedef signed long long s64; +typedef unsigned long long u64; + +/* Dma addresses are 32-bits wide. */ + +typedef u32 dma_addr_t; +typedef u32 dma64_addr_t; + +#endif /* __ASSEMBLY__ */ + +#endif /* __KERNEL__ */ + +#endif diff -Nru a/include/asm-arm26/uaccess-asm.h b/include/asm-arm26/uaccess-asm.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/uaccess-asm.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,151 @@ +/* + * linux/include/asm-arm/proc-armo/uaccess.h + * + * Copyright (C) 1996 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * The fs functions are implemented on the ARM2 and ARM3 architectures + * manually. + * Use *_user functions to access user memory with faulting behaving + * as though the user is accessing the memory. + * Use set_fs(get_ds()) and then the *_user functions to allow them to + * access kernel memory. + */ + +/* + * These are the values used to represent the user `fs' and the kernel `ds' + */ +#define KERNEL_DS 0x03000000 +#define USER_DS 0x02000000 + +extern uaccess_t uaccess_user, uaccess_kernel; + +static inline void set_fs (mm_segment_t fs) +{ + current_thread_info()->addr_limit = fs; + current->thread.uaccess = fs == USER_DS ? &uaccess_user : &uaccess_kernel; +} + +#define __range_ok(addr,size) ({ \ + unsigned long flag, sum; \ + __asm__ __volatile__("subs %1, %0, %3; cmpcs %1, %2; movcs %0, #0" \ + : "=&r" (flag), "=&r" (sum) \ + : "r" (addr), "Ir" (size), "0" (current_thread_info()->addr_limit) \ + : "cc"); \ + flag; }) + +#define __addr_ok(addr) ({ \ + unsigned long flag; \ + __asm__ __volatile__("cmp %2, %0; movlo %0, #0" \ + : "=&r" (flag) \ + : "0" (current_thread_info()->addr_limit), "r" (addr) \ + : "cc"); \ + (flag == 0); }) + +#define __put_user_asm_byte(x,addr,err) \ + __asm__ __volatile__( \ + " mov r0, %1\n" \ + " mov r1, %2\n" \ + " mov r2, %0\n" \ + " mov lr, pc\n" \ + " mov pc, %3\n" \ + " mov %0, r2\n" \ + : "=r" (err) \ + : "r" (x), "r" (addr), "r" (current->thread.uaccess->put_byte), \ + "0" (err) \ + : "r0", "r1", "r2", "lr") + +#define __put_user_asm_half(x,addr,err) \ + __asm__ __volatile__( \ + " mov r0, %1\n" \ + " mov r1, %2\n" \ + " mov r2, %0\n" \ + " mov lr, pc\n" \ + " mov pc, %3\n" \ + " mov %0, r2\n" \ + : "=r" (err) \ + : "r" (x), "r" (addr), "r" (current->thread.uaccess->put_half), \ + "0" (err) \ + : "r0", "r1", "r2", "lr") + +#define __put_user_asm_word(x,addr,err) \ + __asm__ __volatile__( \ + " mov r0, %1\n" \ + " mov r1, %2\n" \ + " mov r2, %0\n" \ + " mov lr, pc\n" \ + " mov pc, %3\n" \ + " mov %0, r2\n" \ + : "=r" (err) \ + : "r" (x), "r" (addr), "r" (current->thread.uaccess->put_word), \ + "0" (err) \ + : "r0", "r1", "r2", "lr") + +#define __put_user_asm_dword(x,addr,err) \ + __asm__ __volatile__( \ + " mov r0, %1\n" \ + " mov r1, %2\n" \ + " mov r2, %0\n" \ + " mov lr, pc\n" \ + " mov pc, %3\n" \ + " mov %0, r2\n" \ + : "=r" (err) \ + : "r" (x), "r" (addr), "r" (current->thread.uaccess->put_dword), \ + "0" (err) \ + : "r0", "r1", "r2", "lr") + +#define __get_user_asm_byte(x,addr,err) \ + __asm__ __volatile__( \ + " mov r0, %2\n" \ + " mov r1, %0\n" \ + " mov lr, pc\n" \ + " mov pc, %3\n" \ + " mov %0, r1\n" \ + " mov %1, r0\n" \ + : "=r" (err), "=r" (x) \ + : "r" (addr), "r" (current->thread.uaccess->get_byte), "0" (err) \ + : "r0", "r1", "r2", "lr") + +#define __get_user_asm_half(x,addr,err) \ + __asm__ __volatile__( \ + " mov r0, %2\n" \ + " mov r1, %0\n" \ + " mov lr, pc\n" \ + " mov pc, %3\n" \ + " mov %0, r1\n" \ + " mov %1, r0\n" \ + : "=r" (err), "=r" (x) \ + : "r" (addr), "r" (current->thread.uaccess->get_half), "0" (err) \ + : "r0", "r1", "r2", "lr") + +#define __get_user_asm_word(x,addr,err) \ + __asm__ __volatile__( \ + " mov r0, %2\n" \ + " mov r1, %0\n" \ + " mov lr, pc\n" \ + " mov pc, %3\n" \ + " mov %0, r1\n" \ + " mov %1, r0\n" \ + : "=r" (err), "=r" (x) \ + : "r" (addr), "r" (current->thread.uaccess->get_word), "0" (err) \ + : "r0", "r1", "r2", "lr") + +#define __do_copy_from_user(to,from,n) \ + (n) = current->thread.uaccess->copy_from_user((to),(from),(n)) + +#define __do_copy_to_user(to,from,n) \ + (n) = current->thread.uaccess->copy_to_user((to),(from),(n)) + +#define __do_clear_user(addr,sz) \ + (sz) = current->thread.uaccess->clear_user((addr),(sz)) + +#define __do_strncpy_from_user(dst,src,count,res) \ + (res) = current->thread.uaccess->strncpy_from_user(dst,src,count) + +#define __do_strnlen_user(s,n,res) \ + (res) = current->thread.uaccess->strnlen_user(s,n) diff -Nru a/include/asm-arm26/uaccess.h b/include/asm-arm26/uaccess.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/uaccess.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,260 @@ +#ifndef _ASMARM_UACCESS_H +#define _ASMARM_UACCESS_H + +/* + * User space memory access functions + */ +#include <linux/sched.h> +#include <asm/errno.h> + +#define VERIFY_READ 0 +#define VERIFY_WRITE 1 + +/* + * The exception table consists of pairs of addresses: the first is the + * address of an instruction that is allowed to fault, and the second is + * the address at which the program should continue. No registers are + * modified, so it is entirely up to the continuation code to figure out + * what to do. + * + * All the routines below use bits of fixup code that are out of line + * with the main instruction path. This means when everything is well, + * we don't even have to jump over them. Further, they do not intrude + * on our cache or tlb entries. + */ + +struct exception_table_entry +{ + unsigned long insn, fixup; +}; + +/* Returns 0 if exception not found and fixup otherwise. */ +extern unsigned long search_exception_table(unsigned long); +extern int fixup_exception(struct pt_regs *regs); + +#define get_ds() (KERNEL_DS) +#define get_fs() (current_thread_info()->addr_limit) +#define segment_eq(a,b) ((a) == (b)) + +#include <asm/uaccess-asm.h> + +#define access_ok(type,addr,size) (__range_ok(addr,size) == 0) + +static inline int verify_area(int type, const void * addr, unsigned long size) +{ + return access_ok(type, addr, size) ? 0 : -EFAULT; +} + +/* + * Single-value transfer routines. They automatically use the right + * size if we just have the right pointer type. Note that the functions + * which read from user space (*get_*) need to take care not to leak + * kernel data even if the calling code is buggy and fails to check + * the return value. This means zeroing out the destination variable + * or buffer on error. Normally this is done out of line by the + * fixup code, but there are a few places where it intrudes on the + * main code path. When we only write to user space, there is no + * problem. + * + * The "__xxx" versions of the user access functions do not verify the + * address space - it must have been done previously with a separate + * "access_ok()" call. + * + * The "xxx_error" versions set the third argument to EFAULT if an + * error occurs, and leave it unchanged on success. Note that these + * versions are void (ie, don't return a value as such). + */ + +extern int __get_user_1(void *); +extern int __get_user_2(void *); +extern int __get_user_4(void *); +extern int __get_user_8(void *); +extern int __get_user_bad(void); + +#define __get_user_x(__r1,__p,__e,__s,__i...) \ + __asm__ __volatile__ ("bl __get_user_" #__s \ + : "=&r" (__e), "=r" (__r1) \ + : "0" (__p) \ + : __i) + +#define get_user(x,p) \ + ({ \ + const register typeof(*(p)) *__p asm("r0") = (p); \ + register typeof(*(p)) __r1 asm("r1"); \ + register int __e asm("r0"); \ + switch (sizeof(*(p))) { \ + case 1: \ + __get_user_x(__r1, __p, __e, 1, "lr"); \ + break; \ + case 2: \ + __get_user_x(__r1, __p, __e, 2, "r2", "lr"); \ + break; \ + case 4: \ + __get_user_x(__r1, __p, __e, 4, "lr"); \ + break; \ + case 8: \ + __get_user_x(__r1, __p, __e, 8, "lr"); \ + break; \ + default: __e = __get_user_bad(); break; \ + } \ + x = __r1; \ + __e; \ + }) + + +#define __get_user(x,ptr) \ +({ \ + long __gu_err = 0; \ + __get_user_err((x),(ptr),__gu_err); \ + __gu_err; \ +}) + +#define __get_user_error(x,ptr,err) \ +({ \ + __get_user_err((x),(ptr),err); \ + (void) 0; \ +}) + +#define __get_user_err(x,ptr,err) \ +do { \ + unsigned long __gu_addr = (unsigned long)(ptr); \ + unsigned long __gu_val; \ + switch (sizeof(*(ptr))) { \ + case 1: __get_user_asm_byte(__gu_val,__gu_addr,err); break; \ + case 2: __get_user_asm_half(__gu_val,__gu_addr,err); break; \ + case 4: __get_user_asm_word(__gu_val,__gu_addr,err); break; \ + default: (__gu_val) = __get_user_bad(); \ + } \ + (x) = (__typeof__(*(ptr)))__gu_val; \ +} while (0) + +extern int __put_user_1(void *, unsigned int); +extern int __put_user_2(void *, unsigned int); +extern int __put_user_4(void *, unsigned int); +extern int __put_user_8(void *, unsigned long long); +extern int __put_user_bad(void); + +#define __put_user_x(__r1,__p,__e,__s,__i...) \ + __asm__ __volatile__ ("bl __put_user_" #__s \ + : "=&r" (__e) \ + : "0" (__p), "r" (__r1) \ + : __i) + +#define put_user(x,p) \ + ({ \ + const register typeof(*(p)) __r1 asm("r1") = (x); \ + const register typeof(*(p)) *__p asm("r0") = (p); \ + register int __e asm("r0"); \ + switch (sizeof(*(p))) { \ + case 1: \ + __put_user_x(__r1, __p, __e, 1, "r2", "lr"); \ + break; \ + case 2: \ + __put_user_x(__r1, __p, __e, 2, "r2", "lr"); \ + break; \ + case 4: \ + __put_user_x(__r1, __p, __e, 4, "r2", "lr"); \ + break; \ + case 8: \ + __put_user_x(__r1, __p, __e, 8, "ip", "lr"); \ + break; \ + default: __e = __put_user_bad(); break; \ + } \ + __e; \ + }) + +#define __put_user(x,ptr) \ +({ \ + long __pu_err = 0; \ + __put_user_err((x),(ptr),__pu_err); \ + __pu_err; \ +}) + +#define __put_user_error(x,ptr,err) \ +({ \ + __put_user_err((x),(ptr),err); \ + (void) 0; \ +}) + +#define __put_user_err(x,ptr,err) \ +do { \ + unsigned long __pu_addr = (unsigned long)(ptr); \ + __typeof__(*(ptr)) __pu_val = (x); \ + switch (sizeof(*(ptr))) { \ + case 1: __put_user_asm_byte(__pu_val,__pu_addr,err); break; \ + case 2: __put_user_asm_half(__pu_val,__pu_addr,err); break; \ + case 4: __put_user_asm_word(__pu_val,__pu_addr,err); break; \ + case 8: __put_user_asm_dword(__pu_val,__pu_addr,err); break; \ + default: __put_user_bad(); \ + } \ +} while (0) + +static __inline__ unsigned long copy_from_user(void *to, const void *from, unsigned long n) +{ + if (access_ok(VERIFY_READ, from, n)) + __do_copy_from_user(to, from, n); + else /* security hole - plug it */ + memzero(to, n); + return n; +} + +static __inline__ unsigned long __copy_from_user(void *to, const void *from, unsigned long n) +{ + __do_copy_from_user(to, from, n); + return n; +} + +static __inline__ unsigned long copy_to_user(void *to, const void *from, unsigned long n) +{ + if (access_ok(VERIFY_WRITE, to, n)) + __do_copy_to_user(to, from, n); + return n; +} + +static __inline__ unsigned long __copy_to_user(void *to, const void *from, unsigned long n) +{ + __do_copy_to_user(to, from, n); + return n; +} + +static __inline__ unsigned long clear_user (void *to, unsigned long n) +{ + if (access_ok(VERIFY_WRITE, to, n)) + __do_clear_user(to, n); + return n; +} + +static __inline__ unsigned long __clear_user (void *to, unsigned long n) +{ + __do_clear_user(to, n); + return n; +} + +static __inline__ long strncpy_from_user (char *dst, const char *src, long count) +{ + long res = -EFAULT; + if (access_ok(VERIFY_READ, src, 1)) + __do_strncpy_from_user(dst, src, count, res); + return res; +} + +static __inline__ long __strncpy_from_user (char *dst, const char *src, long count) +{ + long res; + __do_strncpy_from_user(dst, src, count, res); + return res; +} + +#define strlen_user(s) strnlen_user(s, ~0UL >> 1) + +static inline long strnlen_user(const char *s, long n) +{ + unsigned long res = 0; + + if (__addr_ok(s)) + __do_strnlen_user(s, n, res); + + return res; +} + +#endif /* _ASMARM_UACCESS_H */ diff -Nru a/include/asm-arm26/ucontext.h b/include/asm-arm26/ucontext.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/ucontext.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,12 @@ +#ifndef _ASMARM_UCONTEXT_H +#define _ASMARM_UCONTEXT_H + +struct ucontext { + unsigned long uc_flags; + struct ucontext *uc_link; + stack_t uc_stack; + struct sigcontext uc_mcontext; + sigset_t uc_sigmask; /* mask last for extensibility */ +}; + +#endif /* !_ASMARM_UCONTEXT_H */ diff -Nru a/include/asm-arm26/unaligned.h b/include/asm-arm26/unaligned.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/unaligned.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,118 @@ +#ifndef __ASM_ARM_UNALIGNED_H +#define __ASM_ARM_UNALIGNED_H + +#include <asm/types.h> + +extern int __bug_unaligned_x(void *ptr); + +/* + * What is the most efficient way of loading/storing an unaligned value? + * + * That is the subject of this file. Efficiency here is defined as + * minimum code size with minimum register usage for the common cases. + * It is currently not believed that long longs are common, so we + * trade efficiency for the chars, shorts and longs against the long + * longs. + * + * Current stats with gcc 2.7.2.2 for these functions: + * + * ptrsize get: code regs put: code regs + * 1 1 1 1 2 + * 2 3 2 3 2 + * 4 7 3 7 3 + * 8 20 6 16 6 + * + * gcc 2.95.1 seems to code differently: + * + * ptrsize get: code regs put: code regs + * 1 1 1 1 2 + * 2 3 2 3 2 + * 4 7 4 7 4 + * 8 19 8 15 6 + * + * which may or may not be more efficient (depending upon whether + * you can afford the extra registers). Hopefully the gcc 2.95 + * is inteligent enough to decide if it is better to use the + * extra register, but evidence so far seems to suggest otherwise. + * + * Unfortunately, gcc is not able to optimise the high word + * out of long long >> 32, or the low word from long long << 32 + */ + +#define __get_unaligned_2_le(__p) \ + (__p[0] | __p[1] << 8) + +#define __get_unaligned_4_le(__p) \ + (__p[0] | __p[1] << 8 | __p[2] << 16 | __p[3] << 24) + +#define __get_unaligned_le(ptr) \ + ({ \ + __typeof__(*(ptr)) __v; \ + __u8 *__p = (__u8 *)(ptr); \ + switch (sizeof(*(ptr))) { \ + case 1: __v = *(ptr); break; \ + case 2: __v = __get_unaligned_2_le(__p); break; \ + case 4: __v = __get_unaligned_4_le(__p); break; \ + case 8: { \ + unsigned int __v1, __v2; \ + __v2 = __get_unaligned_4_le((__p+4)); \ + __v1 = __get_unaligned_4_le(__p); \ + __v = ((unsigned long long)__v2 << 32 | __v1); \ + } \ + break; \ + default: __v = __bug_unaligned_x(__p); break; \ + } \ + __v; \ + }) + +static inline void __put_unaligned_2_le(__u32 __v, register __u8 *__p) +{ + *__p++ = __v; + *__p++ = __v >> 8; +} + +static inline void __put_unaligned_4_le(__u32 __v, register __u8 *__p) +{ + __put_unaligned_2_le(__v >> 16, __p + 2); + __put_unaligned_2_le(__v, __p); +} + +static inline void __put_unaligned_8_le(const unsigned long long __v, register __u8 *__p) +{ + /* + * tradeoff: 8 bytes of stack for all unaligned puts (2 + * instructions), or an extra register in the long long + * case - go for the extra register. + */ + __put_unaligned_4_le(__v >> 32, __p+4); + __put_unaligned_4_le(__v, __p); +} + +/* + * Try to store an unaligned value as efficiently as possible. + */ +#define __put_unaligned_le(val,ptr) \ + ({ \ + switch (sizeof(*(ptr))) { \ + case 1: \ + *(ptr) = (val); \ + break; \ + case 2: __put_unaligned_2_le((val),(__u8 *)(ptr)); \ + break; \ + case 4: __put_unaligned_4_le((val),(__u8 *)(ptr)); \ + break; \ + case 8: __put_unaligned_8_le((val),(__u8 *)(ptr)); \ + break; \ + default: __bug_unaligned_x(ptr); \ + break; \ + } \ + (void) 0; \ + }) + +/* + * Select endianness + */ +#define get_unaligned __get_unaligned_le +#define put_unaligned __put_unaligned_le + +#endif diff -Nru a/include/asm-arm26/uncompress.h b/include/asm-arm26/uncompress.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/uncompress.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,111 @@ +/* + * linux/include/asm-arm/arch-arc/uncompress.h + * + * Copyright (C) 1996 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#define VIDMEM ((char *)0x02000000) + +int video_num_columns, video_num_lines, video_size_row; +int white, bytes_per_char_h; +extern unsigned long con_charconvtable[256]; + +struct param_struct { + unsigned long page_size; + unsigned long nr_pages; + unsigned long ramdisk_size; + unsigned long mountrootrdonly; + unsigned long rootdev; + unsigned long video_num_cols; + unsigned long video_num_rows; + unsigned long video_x; + unsigned long video_y; + unsigned long memc_control_reg; + unsigned char sounddefault; + unsigned char adfsdrives; + unsigned char bytes_per_char_h; + unsigned char bytes_per_char_v; + unsigned long unused[256/4-11]; +}; + +static struct param_struct *params = (struct param_struct *)0x0207c000; + +/* + * This does not append a newline + */ +static void puts(const char *s) +{ + extern void ll_write_char(char *, unsigned long); + int x,y; + unsigned char c; + char *ptr; + + x = params->video_x; + y = params->video_y; + + while ( ( c = *(unsigned char *)s++ ) != '\0' ) { + if ( c == '\n' ) { + x = 0; + if ( ++y >= video_num_lines ) { + y--; + } + } else { + ptr = VIDMEM + ((y*video_num_columns*params->bytes_per_char_v+x)*bytes_per_char_h); + ll_write_char(ptr, c|(white<<16)); + if ( ++x >= video_num_columns ) { + x = 0; + if ( ++y >= video_num_lines ) { + y--; + } + } + } + } + + params->video_x = x; + params->video_y = y; +} + +static void error(char *x); + +/* + * Setup for decompression + */ +static void arch_decomp_setup(void) +{ + int i; + + video_num_lines = params->video_num_rows; + video_num_columns = params->video_num_cols; + bytes_per_char_h = params->bytes_per_char_h; + video_size_row = video_num_columns * bytes_per_char_h; + if (bytes_per_char_h == 4) + for (i = 0; i < 256; i++) + con_charconvtable[i] = + (i & 128 ? 1 << 0 : 0) | + (i & 64 ? 1 << 4 : 0) | + (i & 32 ? 1 << 8 : 0) | + (i & 16 ? 1 << 12 : 0) | + (i & 8 ? 1 << 16 : 0) | + (i & 4 ? 1 << 20 : 0) | + (i & 2 ? 1 << 24 : 0) | + (i & 1 ? 1 << 28 : 0); + else + for (i = 0; i < 16; i++) + con_charconvtable[i] = + (i & 8 ? 1 << 0 : 0) | + (i & 4 ? 1 << 8 : 0) | + (i & 2 ? 1 << 16 : 0) | + (i & 1 ? 1 << 24 : 0); + + white = bytes_per_char_h == 8 ? 0xfc : 7; + + if (params->nr_pages * params->page_size < 4096*1024) error("<4M of mem\n"); +} + +/* + * nothing to do + */ +#define arch_decomp_wdog() diff -Nru a/include/asm-arm26/unistd.h b/include/asm-arm26/unistd.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/unistd.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,481 @@ +/* + * linux/include/asm-arm/unistd.h + * + * Copyright (C) 2001 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Please forward _all_ changes to this file to rmk@arm.linux.org.uk, + * no matter what the change is. Thanks! + */ +#ifndef __ASM_ARM_UNISTD_H +#define __ASM_ARM_UNISTD_H + +#include <linux/linkage.h> + +#define __NR_SYSCALL_BASE 0x900000 + +/* + * This file contains the system call numbers. + */ + +#define __NR_restart_syscall (__NR_SYSCALL_BASE+ 0) +#define __NR_exit (__NR_SYSCALL_BASE+ 1) +#define __NR_fork (__NR_SYSCALL_BASE+ 2) +#define __NR_read (__NR_SYSCALL_BASE+ 3) +#define __NR_write (__NR_SYSCALL_BASE+ 4) +#define __NR_open (__NR_SYSCALL_BASE+ 5) +#define __NR_close (__NR_SYSCALL_BASE+ 6) +#define __NR_waitpid (__NR_SYSCALL_BASE+ 7) +#define __NR_creat (__NR_SYSCALL_BASE+ 8) +#define __NR_link (__NR_SYSCALL_BASE+ 9) +#define __NR_unlink (__NR_SYSCALL_BASE+ 10) +#define __NR_execve (__NR_SYSCALL_BASE+ 11) +#define __NR_chdir (__NR_SYSCALL_BASE+ 12) +#define __NR_time (__NR_SYSCALL_BASE+ 13) +#define __NR_mknod (__NR_SYSCALL_BASE+ 14) +#define __NR_chmod (__NR_SYSCALL_BASE+ 15) +#define __NR_lchown (__NR_SYSCALL_BASE+ 16) +#define __NR_break (__NR_SYSCALL_BASE+ 17) + +#define __NR_lseek (__NR_SYSCALL_BASE+ 19) +#define __NR_getpid (__NR_SYSCALL_BASE+ 20) +#define __NR_mount (__NR_SYSCALL_BASE+ 21) +#define __NR_umount (__NR_SYSCALL_BASE+ 22) +#define __NR_setuid (__NR_SYSCALL_BASE+ 23) +#define __NR_getuid (__NR_SYSCALL_BASE+ 24) +#define __NR_stime (__NR_SYSCALL_BASE+ 25) +#define __NR_ptrace (__NR_SYSCALL_BASE+ 26) +#define __NR_alarm (__NR_SYSCALL_BASE+ 27) + +#define __NR_pause (__NR_SYSCALL_BASE+ 29) +#define __NR_utime (__NR_SYSCALL_BASE+ 30) +#define __NR_stty (__NR_SYSCALL_BASE+ 31) +#define __NR_gtty (__NR_SYSCALL_BASE+ 32) +#define __NR_access (__NR_SYSCALL_BASE+ 33) +#define __NR_nice (__NR_SYSCALL_BASE+ 34) +#define __NR_ftime (__NR_SYSCALL_BASE+ 35) +#define __NR_sync (__NR_SYSCALL_BASE+ 36) +#define __NR_kill (__NR_SYSCALL_BASE+ 37) +#define __NR_rename (__NR_SYSCALL_BASE+ 38) +#define __NR_mkdir (__NR_SYSCALL_BASE+ 39) +#define __NR_rmdir (__NR_SYSCALL_BASE+ 40) +#define __NR_dup (__NR_SYSCALL_BASE+ 41) +#define __NR_pipe (__NR_SYSCALL_BASE+ 42) +#define __NR_times (__NR_SYSCALL_BASE+ 43) +#define __NR_prof (__NR_SYSCALL_BASE+ 44) +#define __NR_brk (__NR_SYSCALL_BASE+ 45) +#define __NR_setgid (__NR_SYSCALL_BASE+ 46) +#define __NR_getgid (__NR_SYSCALL_BASE+ 47) +#define __NR_signal (__NR_SYSCALL_BASE+ 48) +#define __NR_geteuid (__NR_SYSCALL_BASE+ 49) +#define __NR_getegid (__NR_SYSCALL_BASE+ 50) +#define __NR_acct (__NR_SYSCALL_BASE+ 51) +#define __NR_umount2 (__NR_SYSCALL_BASE+ 52) +#define __NR_lock (__NR_SYSCALL_BASE+ 53) +#define __NR_ioctl (__NR_SYSCALL_BASE+ 54) +#define __NR_fcntl (__NR_SYSCALL_BASE+ 55) +#define __NR_mpx (__NR_SYSCALL_BASE+ 56) +#define __NR_setpgid (__NR_SYSCALL_BASE+ 57) +#define __NR_ulimit (__NR_SYSCALL_BASE+ 58) + +#define __NR_umask (__NR_SYSCALL_BASE+ 60) +#define __NR_chroot (__NR_SYSCALL_BASE+ 61) +#define __NR_ustat (__NR_SYSCALL_BASE+ 62) +#define __NR_dup2 (__NR_SYSCALL_BASE+ 63) +#define __NR_getppid (__NR_SYSCALL_BASE+ 64) +#define __NR_getpgrp (__NR_SYSCALL_BASE+ 65) +#define __NR_setsid (__NR_SYSCALL_BASE+ 66) +#define __NR_sigaction (__NR_SYSCALL_BASE+ 67) +#define __NR_sgetmask (__NR_SYSCALL_BASE+ 68) +#define __NR_ssetmask (__NR_SYSCALL_BASE+ 69) +#define __NR_setreuid (__NR_SYSCALL_BASE+ 70) +#define __NR_setregid (__NR_SYSCALL_BASE+ 71) +#define __NR_sigsuspend (__NR_SYSCALL_BASE+ 72) +#define __NR_sigpending (__NR_SYSCALL_BASE+ 73) +#define __NR_sethostname (__NR_SYSCALL_BASE+ 74) +#define __NR_setrlimit (__NR_SYSCALL_BASE+ 75) +#define __NR_getrlimit (__NR_SYSCALL_BASE+ 76) /* Back compat 2GB limited rlimit */ +#define __NR_getrusage (__NR_SYSCALL_BASE+ 77) +#define __NR_gettimeofday (__NR_SYSCALL_BASE+ 78) +#define __NR_settimeofday (__NR_SYSCALL_BASE+ 79) +#define __NR_getgroups (__NR_SYSCALL_BASE+ 80) +#define __NR_setgroups (__NR_SYSCALL_BASE+ 81) +#define __NR_select (__NR_SYSCALL_BASE+ 82) +#define __NR_symlink (__NR_SYSCALL_BASE+ 83) + +#define __NR_readlink (__NR_SYSCALL_BASE+ 85) +#define __NR_uselib (__NR_SYSCALL_BASE+ 86) +#define __NR_swapon (__NR_SYSCALL_BASE+ 87) +#define __NR_reboot (__NR_SYSCALL_BASE+ 88) +#define __NR_readdir (__NR_SYSCALL_BASE+ 89) +#define __NR_mmap (__NR_SYSCALL_BASE+ 90) +#define __NR_munmap (__NR_SYSCALL_BASE+ 91) +#define __NR_truncate (__NR_SYSCALL_BASE+ 92) +#define __NR_ftruncate (__NR_SYSCALL_BASE+ 93) +#define __NR_fchmod (__NR_SYSCALL_BASE+ 94) +#define __NR_fchown (__NR_SYSCALL_BASE+ 95) +#define __NR_getpriority (__NR_SYSCALL_BASE+ 96) +#define __NR_setpriority (__NR_SYSCALL_BASE+ 97) +#define __NR_profil (__NR_SYSCALL_BASE+ 98) +#define __NR_statfs (__NR_SYSCALL_BASE+ 99) +#define __NR_fstatfs (__NR_SYSCALL_BASE+100) +#define __NR_ioperm (__NR_SYSCALL_BASE+101) +#define __NR_socketcall (__NR_SYSCALL_BASE+102) +#define __NR_syslog (__NR_SYSCALL_BASE+103) +#define __NR_setitimer (__NR_SYSCALL_BASE+104) +#define __NR_getitimer (__NR_SYSCALL_BASE+105) +#define __NR_stat (__NR_SYSCALL_BASE+106) +#define __NR_lstat (__NR_SYSCALL_BASE+107) +#define __NR_fstat (__NR_SYSCALL_BASE+108) + + +#define __NR_vhangup (__NR_SYSCALL_BASE+111) +#define __NR_idle (__NR_SYSCALL_BASE+112) +#define __NR_syscall (__NR_SYSCALL_BASE+113) /* syscall to call a syscall! */ +#define __NR_wait4 (__NR_SYSCALL_BASE+114) +#define __NR_swapoff (__NR_SYSCALL_BASE+115) +#define __NR_sysinfo (__NR_SYSCALL_BASE+116) +#define __NR_ipc (__NR_SYSCALL_BASE+117) +#define __NR_fsync (__NR_SYSCALL_BASE+118) +#define __NR_sigreturn (__NR_SYSCALL_BASE+119) +#define __NR_clone (__NR_SYSCALL_BASE+120) +#define __NR_setdomainname (__NR_SYSCALL_BASE+121) +#define __NR_uname (__NR_SYSCALL_BASE+122) +#define __NR_modify_ldt (__NR_SYSCALL_BASE+123) +#define __NR_adjtimex (__NR_SYSCALL_BASE+124) +#define __NR_mprotect (__NR_SYSCALL_BASE+125) +#define __NR_sigprocmask (__NR_SYSCALL_BASE+126) +#define __NR_create_module (__NR_SYSCALL_BASE+127) +#define __NR_init_module (__NR_SYSCALL_BASE+128) +#define __NR_delete_module (__NR_SYSCALL_BASE+129) +#define __NR_get_kernel_syms (__NR_SYSCALL_BASE+130) +#define __NR_quotactl (__NR_SYSCALL_BASE+131) +#define __NR_getpgid (__NR_SYSCALL_BASE+132) +#define __NR_fchdir (__NR_SYSCALL_BASE+133) +#define __NR_bdflush (__NR_SYSCALL_BASE+134) +#define __NR_sysfs (__NR_SYSCALL_BASE+135) +#define __NR_personality (__NR_SYSCALL_BASE+136) +#define __NR_afs_syscall (__NR_SYSCALL_BASE+137) /* Syscall for Andrew File System */ +#define __NR_setfsuid (__NR_SYSCALL_BASE+138) +#define __NR_setfsgid (__NR_SYSCALL_BASE+139) +#define __NR__llseek (__NR_SYSCALL_BASE+140) +#define __NR_getdents (__NR_SYSCALL_BASE+141) +#define __NR__newselect (__NR_SYSCALL_BASE+142) +#define __NR_flock (__NR_SYSCALL_BASE+143) +#define __NR_msync (__NR_SYSCALL_BASE+144) +#define __NR_readv (__NR_SYSCALL_BASE+145) +#define __NR_writev (__NR_SYSCALL_BASE+146) +#define __NR_getsid (__NR_SYSCALL_BASE+147) +#define __NR_fdatasync (__NR_SYSCALL_BASE+148) +#define __NR__sysctl (__NR_SYSCALL_BASE+149) +#define __NR_mlock (__NR_SYSCALL_BASE+150) +#define __NR_munlock (__NR_SYSCALL_BASE+151) +#define __NR_mlockall (__NR_SYSCALL_BASE+152) +#define __NR_munlockall (__NR_SYSCALL_BASE+153) +#define __NR_sched_setparam (__NR_SYSCALL_BASE+154) +#define __NR_sched_getparam (__NR_SYSCALL_BASE+155) +#define __NR_sched_setscheduler (__NR_SYSCALL_BASE+156) +#define __NR_sched_getscheduler (__NR_SYSCALL_BASE+157) +#define __NR_sched_yield (__NR_SYSCALL_BASE+158) +#define __NR_sched_get_priority_max (__NR_SYSCALL_BASE+159) +#define __NR_sched_get_priority_min (__NR_SYSCALL_BASE+160) +#define __NR_sched_rr_get_interval (__NR_SYSCALL_BASE+161) +#define __NR_nanosleep (__NR_SYSCALL_BASE+162) +#define __NR_mremap (__NR_SYSCALL_BASE+163) +#define __NR_setresuid (__NR_SYSCALL_BASE+164) +#define __NR_getresuid (__NR_SYSCALL_BASE+165) +#define __NR_vm86 (__NR_SYSCALL_BASE+166) +#define __NR_query_module (__NR_SYSCALL_BASE+167) +#define __NR_poll (__NR_SYSCALL_BASE+168) +#define __NR_nfsservctl (__NR_SYSCALL_BASE+169) +#define __NR_setresgid (__NR_SYSCALL_BASE+170) +#define __NR_getresgid (__NR_SYSCALL_BASE+171) +#define __NR_prctl (__NR_SYSCALL_BASE+172) +#define __NR_rt_sigreturn (__NR_SYSCALL_BASE+173) +#define __NR_rt_sigaction (__NR_SYSCALL_BASE+174) +#define __NR_rt_sigprocmask (__NR_SYSCALL_BASE+175) +#define __NR_rt_sigpending (__NR_SYSCALL_BASE+176) +#define __NR_rt_sigtimedwait (__NR_SYSCALL_BASE+177) +#define __NR_rt_sigqueueinfo (__NR_SYSCALL_BASE+178) +#define __NR_rt_sigsuspend (__NR_SYSCALL_BASE+179) +#define __NR_pread64 (__NR_SYSCALL_BASE+180) +#define __NR_pwrite64 (__NR_SYSCALL_BASE+181) +#define __NR_chown (__NR_SYSCALL_BASE+182) +#define __NR_getcwd (__NR_SYSCALL_BASE+183) +#define __NR_capget (__NR_SYSCALL_BASE+184) +#define __NR_capset (__NR_SYSCALL_BASE+185) +#define __NR_sigaltstack (__NR_SYSCALL_BASE+186) +#define __NR_sendfile (__NR_SYSCALL_BASE+187) + /* 188 reserved */ + /* 189 reserved */ +#define __NR_vfork (__NR_SYSCALL_BASE+190) +#define __NR_ugetrlimit (__NR_SYSCALL_BASE+191) /* SuS compliant getrlimit */ +#define __NR_mmap2 (__NR_SYSCALL_BASE+192) +#define __NR_truncate64 (__NR_SYSCALL_BASE+193) +#define __NR_ftruncate64 (__NR_SYSCALL_BASE+194) +#define __NR_stat64 (__NR_SYSCALL_BASE+195) +#define __NR_lstat64 (__NR_SYSCALL_BASE+196) +#define __NR_fstat64 (__NR_SYSCALL_BASE+197) +#define __NR_lchown32 (__NR_SYSCALL_BASE+198) +#define __NR_getuid32 (__NR_SYSCALL_BASE+199) +#define __NR_getgid32 (__NR_SYSCALL_BASE+200) +#define __NR_geteuid32 (__NR_SYSCALL_BASE+201) +#define __NR_getegid32 (__NR_SYSCALL_BASE+202) +#define __NR_setreuid32 (__NR_SYSCALL_BASE+203) +#define __NR_setregid32 (__NR_SYSCALL_BASE+204) +#define __NR_getgroups32 (__NR_SYSCALL_BASE+205) +#define __NR_setgroups32 (__NR_SYSCALL_BASE+206) +#define __NR_fchown32 (__NR_SYSCALL_BASE+207) +#define __NR_setresuid32 (__NR_SYSCALL_BASE+208) +#define __NR_getresuid32 (__NR_SYSCALL_BASE+209) +#define __NR_setresgid32 (__NR_SYSCALL_BASE+210) +#define __NR_getresgid32 (__NR_SYSCALL_BASE+211) +#define __NR_chown32 (__NR_SYSCALL_BASE+212) +#define __NR_setuid32 (__NR_SYSCALL_BASE+213) +#define __NR_setgid32 (__NR_SYSCALL_BASE+214) +#define __NR_setfsuid32 (__NR_SYSCALL_BASE+215) +#define __NR_setfsgid32 (__NR_SYSCALL_BASE+216) +#define __NR_getdents64 (__NR_SYSCALL_BASE+217) +#define __NR_pivot_root (__NR_SYSCALL_BASE+218) +#define __NR_mincore (__NR_SYSCALL_BASE+219) +#define __NR_madvise (__NR_SYSCALL_BASE+220) +#define __NR_fcntl64 (__NR_SYSCALL_BASE+221) + /* 222 for tux */ +#define __NR_security (__NR_SYSCALL_BASE+223) +#define __NR_gettid (__NR_SYSCALL_BASE+224) +#define __NR_readahead (__NR_SYSCALL_BASE+225) +#define __NR_setxattr (__NR_SYSCALL_BASE+226) +#define __NR_lsetxattr (__NR_SYSCALL_BASE+227) +#define __NR_fsetxattr (__NR_SYSCALL_BASE+228) +#define __NR_getxattr (__NR_SYSCALL_BASE+229) +#define __NR_lgetxattr (__NR_SYSCALL_BASE+230) +#define __NR_fgetxattr (__NR_SYSCALL_BASE+231) +#define __NR_listxattr (__NR_SYSCALL_BASE+232) +#define __NR_llistxattr (__NR_SYSCALL_BASE+233) +#define __NR_flistxattr (__NR_SYSCALL_BASE+234) +#define __NR_removexattr (__NR_SYSCALL_BASE+235) +#define __NR_lremovexattr (__NR_SYSCALL_BASE+236) +#define __NR_fremovexattr (__NR_SYSCALL_BASE+237) +#define __NR_tkill (__NR_SYSCALL_BASE+238) + +/* + * The following SWIs are ARM private. + */ +#define __ARM_NR_BASE (__NR_SYSCALL_BASE+0x0f0000) +#define __ARM_NR_breakpoint (__ARM_NR_BASE+1) +#define __ARM_NR_cacheflush (__ARM_NR_BASE+2) +#define __ARM_NR_usr26 (__ARM_NR_BASE+3) +#define __ARM_NR_usr32 (__ARM_NR_BASE+4) + +#define __sys2(x) #x +#define __sys1(x) __sys2(x) + +#ifndef __syscall +#define __syscall(name) "swi\t" __sys1(__NR_##name) "\n\t" +#endif + +#define __syscall_return(type, res) \ +do { \ + if ((unsigned long)(res) >= (unsigned long)(-125)) { \ + errno = -(res); \ + res = -1; \ + } \ + return (type) (res); \ +} while (0) + +#define _syscall0(type,name) \ +type name(void) { \ + long __res; \ + __asm__ __volatile__ ( \ + __syscall(name) \ + "mov %0,r0" \ + :"=r" (__res) : : "r0","lr"); \ + __syscall_return(type,__res); \ +} + +#define _syscall1(type,name,type1,arg1) \ +type name(type1 arg1) { \ + long __res; \ + __asm__ __volatile__ ( \ + "mov\tr0,%1\n\t" \ + __syscall(name) \ + "mov %0,r0" \ + : "=r" (__res) \ + : "r" ((long)(arg1)) \ + : "r0","lr"); \ + __syscall_return(type,__res); \ +} + +#define _syscall2(type,name,type1,arg1,type2,arg2) \ +type name(type1 arg1,type2 arg2) { \ + long __res; \ + __asm__ __volatile__ ( \ + "mov\tr0,%1\n\t" \ + "mov\tr1,%2\n\t" \ + __syscall(name) \ + "mov\t%0,r0" \ + : "=r" (__res) \ + : "r" ((long)(arg1)),"r" ((long)(arg2)) \ + : "r0","r1","lr"); \ + __syscall_return(type,__res); \ +} + + +#define _syscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \ +type name(type1 arg1,type2 arg2,type3 arg3) { \ + long __res; \ + __asm__ __volatile__ ( \ + "mov\tr0,%1\n\t" \ + "mov\tr1,%2\n\t" \ + "mov\tr2,%3\n\t" \ + __syscall(name) \ + "mov\t%0,r0" \ + : "=r" (__res) \ + : "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3)) \ + : "r0","r1","r2","lr"); \ + __syscall_return(type,__res); \ +} + + +#define _syscall4(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4) \ +type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) { \ + long __res; \ + __asm__ __volatile__ ( \ + "mov\tr0,%1\n\t" \ + "mov\tr1,%2\n\t" \ + "mov\tr2,%3\n\t" \ + "mov\tr3,%4\n\t" \ + __syscall(name) \ + "mov\t%0,r0" \ + : "=r" (__res) \ + : "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3)),"r" ((long)(arg4)) \ + : "r0","r1","r2","r3","lr"); \ + __syscall_return(type,__res); \ +} + + +#define _syscall5(type,name,type1,arg1,type2,arg2,type3,arg3,type4,arg4,type5,arg5) \ +type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, type5 arg5) { \ + long __res; \ + __asm__ __volatile__ ( \ + "mov\tr0,%1\n\t" \ + "mov\tr1,%2\n\t" \ + "mov\tr2,%3\n\t" \ + "mov\tr3,%4\n\t" \ + "mov\tr4,%5\n\t" \ + __syscall(name) \ + "mov\t%0,r0" \ + : "=r" (__res) \ + : "r" ((long)(arg1)),"r" ((long)(arg2)),"r" ((long)(arg3)),"r" ((long)(arg4)), \ + "r" ((long)(arg5)) \ + : "r0","r1","r2","r3","r4","lr"); \ + __syscall_return(type,__res); \ +} + +#ifdef __KERNEL_SYSCALLS__ + +struct rusage; +asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru); + +static inline long idle(void) +{ + extern long sys_idle(void); + return sys_idle(); +} + +static inline long pause(void) +{ + extern long sys_pause(void); + return sys_pause(); +} + +static inline long sync(void) +{ + extern long sys_sync(void); + return sys_sync(); +} + +static inline pid_t setsid(void) +{ + extern long sys_setsid(void); + return sys_setsid(); +} + +static inline long write(int fd, const char *buf, off_t count) +{ + extern long sys_write(int, const char *, int); + return sys_write(fd, buf, count); +} + +static inline long read(int fd, char *buf, off_t count) +{ + extern long sys_read(int, char *, int); + return sys_read(fd, buf, count); +} + +static inline off_t lseek(int fd, off_t offset, int count) +{ + extern off_t sys_lseek(int, off_t, int); + return sys_lseek(fd, offset, count); +} + +static inline long dup(int fd) +{ + extern long sys_dup(int); + return sys_dup(fd); +} + +static inline long open(const char *file, int flag, int mode) +{ + extern long sys_open(const char *, int, int); + return sys_open(file, flag, mode); +} + +static inline long close(int fd) +{ + extern long sys_close(unsigned int); + return sys_close(fd); +} + +static inline long _exit(int exitcode) +{ + extern long sys_exit(int) __attribute__((noreturn)); + return sys_exit(exitcode); +} + +static inline pid_t waitpid(pid_t pid, int *wait_stat, int options) +{ + return sys_wait4((int)pid, wait_stat, options, NULL); +} + +static inline long delete_module(const char *name) +{ + extern long sys_delete_module(const char *name); + return sys_delete_module(name); +} + +static inline pid_t wait(int * wait_stat) +{ + return sys_wait4(-1, wait_stat, 0, NULL); +} + +/* + * The following two can't be eliminated yet - they rely on + * specific conditions. + */ +static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp); + +#endif + +/* + * "Conditional" syscalls + * + * What we want is __attribute__((weak,alias("sys_ni_syscall"))), + * but it doesn't work on all toolchains, so we just do it by hand + */ +#define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall"); + +#endif /* __ASM_ARM_UNISTD_H */ diff -Nru a/include/asm-arm26/user.h b/include/asm-arm26/user.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/user.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,84 @@ +#ifndef _ARM_USER_H +#define _ARM_USER_H + +#include <asm/page.h> +#include <asm/ptrace.h> +/* Core file format: The core file is written in such a way that gdb + can understand it and provide useful information to the user (under + linux we use the 'trad-core' bfd). There are quite a number of + obstacles to being able to view the contents of the floating point + registers, and until these are solved you will not be able to view the + contents of them. Actually, you can read in the core file and look at + the contents of the user struct to find out what the floating point + registers contain. + The actual file contents are as follows: + UPAGE: 1 page consisting of a user struct that tells gdb what is present + in the file. Directly after this is a copy of the task_struct, which + is currently not used by gdb, but it may come in useful at some point. + All of the registers are stored as part of the upage. The upage should + always be only one page. + DATA: The data area is stored. We use current->end_text to + current->brk to pick up all of the user variables, plus any memory + that may have been malloced. No attempt is made to determine if a page + is demand-zero or if a page is totally unused, we just cover the entire + range. All of the addresses are rounded in such a way that an integral + number of pages is written. + STACK: We need the stack information in order to get a meaningful + backtrace. We need to write the data from (esp) to + current->start_stack, so we round each of these off in order to be able + to write an integer number of pages. + The minimum core file size is 3 pages, or 12288 bytes. +*/ + +struct user_fp { + struct fp_reg { + unsigned int sign1:1; + unsigned int unused:15; + unsigned int sign2:1; + unsigned int exponent:14; + unsigned int j:1; + unsigned int mantissa1:31; + unsigned int mantissa0:32; + } fpregs[8]; + unsigned int fpsr:32; + unsigned int fpcr:32; + unsigned char ftype[8]; + unsigned int init_flag; +}; + +/* When the kernel dumps core, it starts by dumping the user struct - + this will be used by gdb to figure out where the data and stack segments + are within the file, and what virtual addresses to use. */ +struct user{ +/* We start with the registers, to mimic the way that "memory" is returned + from the ptrace(3,...) function. */ + struct pt_regs regs; /* Where the registers are actually stored */ +/* ptrace does not yet supply these. Someday.... */ + int u_fpvalid; /* True if math co-processor being used. */ + /* for this mess. Not yet used. */ +/* The rest of this junk is to help gdb figure out what goes where */ + unsigned long int u_tsize; /* Text segment size (pages). */ + unsigned long int u_dsize; /* Data segment size (pages). */ + unsigned long int u_ssize; /* Stack segment size (pages). */ + unsigned long start_code; /* Starting virtual address of text. */ + unsigned long start_stack; /* Starting virtual address of stack area. + This is actually the bottom of the stack, + the top of the stack is always found in the + esp register. */ + long int signal; /* Signal that caused the core dump. */ + int reserved; /* No longer used */ + struct pt_regs * u_ar0; /* Used by gdb to help find the values for */ + /* the registers. */ + unsigned long magic; /* To uniquely identify a core file */ + char u_comm[32]; /* User command that was responsible */ + int u_debugreg[8]; + struct user_fp u_fp; /* FP state */ + struct user_fp_struct * u_fp0;/* Used by gdb to help find the values for */ + /* the FP registers. */ +}; +#define NBPG PAGE_SIZE +#define UPAGES 1 +#define HOST_TEXT_START_ADDR (u.start_code) +#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG) + +#endif /* _ARM_USER_H */ diff -Nru a/include/asm-arm26/xor.h b/include/asm-arm26/xor.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-arm26/xor.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,141 @@ +/* + * linux/include/asm-arm/xor.h + * + * Copyright (C) 2001 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include <asm-generic/xor.h> + +#define __XOR(a1, a2) a1 ^= a2 + +#define GET_BLOCK_2(dst) \ + __asm__("ldmia %0, {%1, %2}" \ + : "=r" (dst), "=r" (a1), "=r" (a2) \ + : "0" (dst)) + +#define GET_BLOCK_4(dst) \ + __asm__("ldmia %0, {%1, %2, %3, %4}" \ + : "=r" (dst), "=r" (a1), "=r" (a2), "=r" (a3), "=r" (a4) \ + : "0" (dst)) + +#define XOR_BLOCK_2(src) \ + __asm__("ldmia %0!, {%1, %2}" \ + : "=r" (src), "=r" (b1), "=r" (b2) \ + : "0" (src)); \ + __XOR(a1, b1); __XOR(a2, b2); + +#define XOR_BLOCK_4(src) \ + __asm__("ldmia %0!, {%1, %2, %3, %4}" \ + : "=r" (src), "=r" (b1), "=r" (b2), "=r" (b3), "=r" (b4) \ + : "0" (src)); \ + __XOR(a1, b1); __XOR(a2, b2); __XOR(a3, b3); __XOR(a4, b4) + +#define PUT_BLOCK_2(dst) \ + __asm__ __volatile__("stmia %0!, {%2, %3}" \ + : "=r" (dst) \ + : "0" (dst), "r" (a1), "r" (a2)) + +#define PUT_BLOCK_4(dst) \ + __asm__ __volatile__("stmia %0!, {%2, %3, %4, %5}" \ + : "=r" (dst) \ + : "0" (dst), "r" (a1), "r" (a2), "r" (a3), "r" (a4)) + +static void +xor_arm4regs_2(unsigned long bytes, unsigned long *p1, unsigned long *p2) +{ + unsigned int lines = bytes / sizeof(unsigned long) / 4; + register unsigned int a1 __asm__("r4"); + register unsigned int a2 __asm__("r5"); + register unsigned int a3 __asm__("r6"); + register unsigned int a4 __asm__("r7"); + register unsigned int b1 __asm__("r8"); + register unsigned int b2 __asm__("r9"); + register unsigned int b3 __asm__("ip"); + register unsigned int b4 __asm__("lr"); + + do { + GET_BLOCK_4(p1); + XOR_BLOCK_4(p2); + PUT_BLOCK_4(p1); + } while (--lines); +} + +static void +xor_arm4regs_3(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3) +{ + unsigned int lines = bytes / sizeof(unsigned long) / 4; + register unsigned int a1 __asm__("r4"); + register unsigned int a2 __asm__("r5"); + register unsigned int a3 __asm__("r6"); + register unsigned int a4 __asm__("r7"); + register unsigned int b1 __asm__("r8"); + register unsigned int b2 __asm__("r9"); + register unsigned int b3 __asm__("ip"); + register unsigned int b4 __asm__("lr"); + + do { + GET_BLOCK_4(p1); + XOR_BLOCK_4(p2); + XOR_BLOCK_4(p3); + PUT_BLOCK_4(p1); + } while (--lines); +} + +static void +xor_arm4regs_4(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3, unsigned long *p4) +{ + unsigned int lines = bytes / sizeof(unsigned long) / 2; + register unsigned int a1 __asm__("r8"); + register unsigned int a2 __asm__("r9"); + register unsigned int b1 __asm__("ip"); + register unsigned int b2 __asm__("lr"); + + do { + GET_BLOCK_2(p1); + XOR_BLOCK_2(p2); + XOR_BLOCK_2(p3); + XOR_BLOCK_2(p4); + PUT_BLOCK_2(p1); + } while (--lines); +} + +static void +xor_arm4regs_5(unsigned long bytes, unsigned long *p1, unsigned long *p2, + unsigned long *p3, unsigned long *p4, unsigned long *p5) +{ + unsigned int lines = bytes / sizeof(unsigned long) / 2; + register unsigned int a1 __asm__("r8"); + register unsigned int a2 __asm__("r9"); + register unsigned int b1 __asm__("ip"); + register unsigned int b2 __asm__("lr"); + + do { + GET_BLOCK_2(p1); + XOR_BLOCK_2(p2); + XOR_BLOCK_2(p3); + XOR_BLOCK_2(p4); + XOR_BLOCK_2(p5); + PUT_BLOCK_2(p1); + } while (--lines); +} + +static struct xor_block_template xor_block_arm4regs = { + name: "arm4regs", + do_2: xor_arm4regs_2, + do_3: xor_arm4regs_3, + do_4: xor_arm4regs_4, + do_5: xor_arm4regs_5, +}; + +#undef XOR_TRY_TEMPLATES +#define XOR_TRY_TEMPLATES \ + do { \ + xor_speed(&xor_block_arm4regs); \ + xor_speed(&xor_block_8regs); \ + xor_speed(&xor_block_32regs); \ + } while (0) diff -Nru a/include/asm-cris/bug.h b/include/asm-cris/bug.h --- a/include/asm-cris/bug.h Mon Jun 9 23:16:19 2003 +++ b/include/asm-cris/bug.h Mon Jun 9 23:16:19 2003 @@ -9,4 +9,13 @@ BUG(); \ } while (0) +#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0) + +#define WARN_ON(condition) do { \ + if (unlikely((condition)!=0)) { \ + printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \ + dump_stack(); \ + } \ +} while (0) + #endif diff -Nru a/include/asm-generic/percpu.h b/include/asm-generic/percpu.h --- a/include/asm-generic/percpu.h Mon Jun 9 23:16:08 2003 +++ b/include/asm-generic/percpu.h Mon Jun 9 23:16:08 2003 @@ -8,22 +8,25 @@ extern unsigned long __per_cpu_offset[NR_CPUS]; /* Separate out the type, so (int[3], foo) works. */ -#ifndef MODULE #define DEFINE_PER_CPU(type, name) \ __attribute__((__section__(".data.percpu"))) __typeof__(type) name##__per_cpu -#endif /* var is in discarded region: offset to particular copy we want */ #define per_cpu(var, cpu) (*RELOC_HIDE(&var##__per_cpu, __per_cpu_offset[cpu])) #define __get_cpu_var(var) per_cpu(var, smp_processor_id()) +static inline void percpu_modcopy(void *pcpudst, const void *src, + unsigned long size) +{ + unsigned int i; + for (i = 0; i < NR_CPUS; i++) + if (cpu_possible(i)) + memcpy(pcpudst + __per_cpu_offset[i], src, size); +} #else /* ! SMP */ -/* Can't define per-cpu variables in modules. Sorry --RR */ -#ifndef MODULE #define DEFINE_PER_CPU(type, name) \ __typeof__(type) name##__per_cpu -#endif #define per_cpu(var, cpu) ((void)cpu, var##__per_cpu) #define __get_cpu_var(var) var##__per_cpu diff -Nru a/include/asm-h8300/bug.h b/include/asm-h8300/bug.h --- a/include/asm-h8300/bug.h Mon Jun 9 23:16:05 2003 +++ b/include/asm-h8300/bug.h Mon Jun 9 23:16:05 2003 @@ -9,4 +9,13 @@ BUG(); \ } while (0) +#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0) + +#define WARN_ON(condition) do { \ + if (unlikely((condition)!=0)) { \ + printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \ + dump_stack(); \ + } \ +} while (0) + #endif diff -Nru a/include/asm-h8300/thread_info.h b/include/asm-h8300/thread_info.h --- a/include/asm-h8300/thread_info.h Mon Jun 9 23:16:09 2003 +++ b/include/asm-h8300/thread_info.h Mon Jun 9 23:16:09 2003 @@ -65,7 +65,7 @@ } /* thread information allocation */ -#define alloc_thread_info() ((struct thread_info *) \ +#define alloc_thread_info(tsk) ((struct thread_info *) \ __get_free_pages(GFP_KERNEL, 1)) #define free_thread_info(ti) free_pages((unsigned long) (ti), 1) #define get_thread_info(ti) get_task_struct((ti)->task) diff -Nru a/include/asm-i386/bug.h b/include/asm-i386/bug.h --- a/include/asm-i386/bug.h Mon Jun 9 23:16:07 2003 +++ b/include/asm-i386/bug.h Mon Jun 9 23:16:07 2003 @@ -19,8 +19,17 @@ #define BUG() __asm__ __volatile__("ud2\n") #endif +#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0) + #define PAGE_BUG(page) do { \ BUG(); \ +} while (0) + +#define WARN_ON(condition) do { \ + if (unlikely((condition)!=0)) { \ + printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \ + dump_stack(); \ + } \ } while (0) #endif diff -Nru a/include/asm-i386/cpu.h b/include/asm-i386/cpu.h --- a/include/asm-i386/cpu.h Mon Jun 9 23:16:15 2003 +++ b/include/asm-i386/cpu.h Mon Jun 9 23:16:15 2003 @@ -3,8 +3,8 @@ #include <linux/device.h> #include <linux/cpu.h> +#include <linux/topology.h> -#include <asm/topology.h> #include <asm/node.h> struct i386_cpu { diff -Nru a/include/asm-i386/mach-generic/mach_apic.h b/include/asm-i386/mach-generic/mach_apic.h --- a/include/asm-i386/mach-generic/mach_apic.h Mon Jun 9 23:16:10 2003 +++ b/include/asm-i386/mach-generic/mach_apic.h Mon Jun 9 23:16:10 2003 @@ -24,8 +24,6 @@ #define check_apicid_present (genapic->check_apicid_present) #define check_phys_apicid_present (genapic->check_phys_apicid_present) #define check_apicid_used (genapic->check_apicid_used) -#define GET_APIC_ID (genapic->get_apic_id) -#define APIC_ID_MASK (genapic->apic_id_mask) #define cpu_mask_to_apicid (genapic->cpu_mask_to_apicid) #endif /* __ASM_MACH_APIC_H */ diff -Nru a/include/asm-i386/mach-generic/mach_apicdef.h b/include/asm-i386/mach-generic/mach_apicdef.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/asm-i386/mach-generic/mach_apicdef.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,11 @@ +#ifndef _GENAPIC_MACH_APICDEF_H +#define _GENAPIC_MACH_APICDEF_H 1 + +#ifndef APIC_DEFINITION +#include <asm/genapic.h> + +#define GET_APIC_ID (genapic->get_apic_id) +#define APIC_ID_MASK (genapic->apic_id_mask) +#endif + +#endif diff -Nru a/include/asm-i386/mach-numaq/mach_apic.h b/include/asm-i386/mach-numaq/mach_apic.h --- a/include/asm-i386/mach-numaq/mach_apic.h Mon Jun 9 23:16:10 2003 +++ b/include/asm-i386/mach-numaq/mach_apic.h Mon Jun 9 23:16:10 2003 @@ -107,37 +107,13 @@ return (1); } +/* + * We use physical apicids here, not logical, so just return the default + * physical broadcast to stop people from breaking us + */ static inline unsigned int cpu_mask_to_apicid (unsigned long cpumask) { - int num_bits_set; - int cpus_found = 0; - int cpu; - int apicid; - - num_bits_set = hweight32(cpumask); - /* Return id to all */ - if (num_bits_set == 32) - return (int) 0xFF; - /* - * The cpus in the mask must all be on the apic cluster. If are not - * on the same apicid cluster return default value of TARGET_CPUS. - */ - cpu = ffs(cpumask)-1; - apicid = cpu_to_logical_apicid(cpu); - while (cpus_found < num_bits_set) { - if (cpumask & (1 << cpu)) { - int new_apicid = cpu_to_logical_apicid(cpu); - if (apicid_cluster(apicid) != - apicid_cluster(new_apicid)){ - printk ("%s: Not a valid mask!\n",__FUNCTION__); - return TARGET_CPUS; - } - apicid = apicid | new_apicid; - cpus_found++; - } - cpu++; - } - return apicid; + return (int) 0xF; } #endif /* __ASM_MACH_APIC_H */ diff -Nru a/include/asm-i386/mach-summit/mach_apic.h b/include/asm-i386/mach-summit/mach_apic.h --- a/include/asm-i386/mach-summit/mach_apic.h Mon Jun 9 23:16:15 2003 +++ b/include/asm-i386/mach-summit/mach_apic.h Mon Jun 9 23:16:15 2003 @@ -4,13 +4,7 @@ #include <linux/config.h> #include <asm/smp.h> -#ifdef CONFIG_X86_GENERICARCH -#define x86_summit 1 /* must be an constant expressiona for generic arch */ -#else -extern int x86_summit; -#endif - -#define esr_disable (x86_summit ? 1 : 0) +#define esr_disable (1) #define NO_BALANCE_IRQ (0) #define XAPIC_DEST_CPUS_MASK 0x0Fu @@ -22,27 +16,27 @@ ((phys_apic) & XAPIC_DEST_CLUSTER_MASK) ); } -#define APIC_DFR_VALUE (x86_summit ? APIC_DFR_CLUSTER : APIC_DFR_FLAT) +#define APIC_DFR_VALUE (APIC_DFR_CLUSTER) static inline unsigned long target_cpus(void) { - return (x86_summit ? XAPIC_DEST_CPUS_MASK : cpu_online_map); + return XAPIC_DEST_CPUS_MASK; } #define TARGET_CPUS (target_cpus()) -#define INT_DELIVERY_MODE (x86_summit ? dest_Fixed : dest_LowestPrio) +#define INT_DELIVERY_MODE (dest_Fixed) #define INT_DEST_MODE 1 /* logical delivery broadcast to all procs */ #define APIC_BROADCAST_ID (0x0F) static inline unsigned long check_apicid_used(unsigned long bitmap, int apicid) { - return (x86_summit ? 0 : (bitmap & (1 << apicid))); + return 0; } /* we don't use the phys_cpu_present_map to indicate apicid presence */ static inline unsigned long check_apicid_present(int bit) { - return (x86_summit ? 1 : (phys_cpu_present_map & (1 << bit))); + return 1; } #define apicid_cluster(apicid) (apicid & 0xF0) @@ -53,10 +47,7 @@ { unsigned long val, id; - if (x86_summit) - id = xapic_phys_to_log_apicid(hard_smp_processor_id()); - else - id = 1UL << smp_processor_id(); + id = xapic_phys_to_log_apicid(hard_smp_processor_id()); apic_write_around(APIC_DFR, APIC_DFR_VALUE); val = apic_read(APIC_LDR) & ~APIC_LDR_MASK; val |= SET_APIC_LOGICAL_ID(id); @@ -75,8 +66,8 @@ static inline void clustered_apic_check(void) { - printk("Enabling APIC mode: %s. Using %d I/O APICs\n", - (x86_summit ? "Summit" : "Flat"), nr_ioapics); + printk("Enabling APIC mode: Summit. Using %d I/O APICs\n", + nr_ioapics); } static inline int apicid_to_node(int logical_apicid) @@ -93,24 +84,18 @@ static inline int cpu_present_to_apicid(int mps_cpu) { - if (x86_summit) - return (int) bios_cpu_apicid[mps_cpu]; - else - return mps_cpu; + return (int) bios_cpu_apicid[mps_cpu]; } static inline ulong ioapic_phys_id_map(ulong phys_map) { /* For clustered we don't have a good way to do this yet - hack */ - return (x86_summit ? 0x0F : phys_map); + return 0x0F; } static inline unsigned long apicid_to_cpu_present(int apicid) { - if (x86_summit) - return 1; - else - return (1ul << apicid); + return 1; } static inline int mpc_apic_id(struct mpc_config_processor *m, @@ -130,10 +115,7 @@ static inline int check_phys_apicid_present(int boot_cpu_physical_apicid) { - if (x86_summit) - return (1); - else - return test_bit(boot_cpu_physical_apicid, &phys_cpu_present_map); + return 1; } static inline unsigned int cpu_mask_to_apicid (unsigned long cpumask) diff -Nru a/include/asm-i386/mach-summit/mach_mpparse.h b/include/asm-i386/mach-summit/mach_mpparse.h --- a/include/asm-i386/mach-summit/mach_mpparse.h Mon Jun 9 23:16:10 2003 +++ b/include/asm-i386/mach-summit/mach_mpparse.h Mon Jun 9 23:16:10 2003 @@ -1,6 +1,8 @@ #ifndef __ASM_MACH_MPPARSE_H #define __ASM_MACH_MPPARSE_H +#include <mach_apic.h> + extern int use_cyclone; static inline void mpc_oem_bus_info(struct mpc_config_bus *m, char *name, @@ -21,9 +23,6 @@ (!strncmp(productid, "VIGIL SMP", 9) || !strncmp(productid, "EXA", 3) || !strncmp(productid, "RUTHLESS SMP", 12))){ -#ifndef CONFIG_X86_GENERICARCH - x86_summit = 1; -#endif use_cyclone = 1; /*enable cyclone-timer*/ return 1; } @@ -36,12 +35,76 @@ if (!strncmp(oem_id, "IBM", 3) && (!strncmp(oem_table_id, "SERVIGIL", 8) || !strncmp(oem_table_id, "EXA", 3))){ -#ifndef CONFIG_X86_GENERICARCH - x86_summit = 1; -#endif use_cyclone = 1; /*enable cyclone-timer*/ return 1; } return 0; } + +struct rio_table_hdr { + unsigned char version; /* Version number of this data structure */ + /* Version 3 adds chassis_num & WP_index */ + unsigned char num_scal_dev; /* # of Scalability devices (Twisters for Vigil) */ + unsigned char num_rio_dev; /* # of RIO I/O devices (Cyclones and Winnipegs) */ +} __attribute__((packed)); + +struct scal_detail { + unsigned char node_id; /* Scalability Node ID */ + unsigned long CBAR; /* Address of 1MB register space */ + unsigned char port0node; /* Node ID port connected to: 0xFF=None */ + unsigned char port0port; /* Port num port connected to: 0,1,2, or 0xFF=None */ + unsigned char port1node; /* Node ID port connected to: 0xFF = None */ + unsigned char port1port; /* Port num port connected to: 0,1,2, or 0xFF=None */ + unsigned char port2node; /* Node ID port connected to: 0xFF = None */ + unsigned char port2port; /* Port num port connected to: 0,1,2, or 0xFF=None */ + unsigned char chassis_num; /* 1 based Chassis number (1 = boot node) */ +} __attribute__((packed)); + +struct rio_detail { + unsigned char node_id; /* RIO Node ID */ + unsigned long BBAR; /* Address of 1MB register space */ + unsigned char type; /* Type of device */ + unsigned char owner_id; /* For WPEG: Node ID of Cyclone that owns this WPEG*/ + /* For CYC: Node ID of Twister that owns this CYC */ + unsigned char port0node; /* Node ID port connected to: 0xFF=None */ + unsigned char port0port; /* Port num port connected to: 0,1,2, or 0xFF=None */ + unsigned char port1node; /* Node ID port connected to: 0xFF=None */ + unsigned char port1port; /* Port num port connected to: 0,1,2, or 0xFF=None */ + unsigned char first_slot; /* For WPEG: Lowest slot number below this WPEG */ + /* For CYC: 0 */ + unsigned char status; /* For WPEG: Bit 0 = 1 : the XAPIC is used */ + /* = 0 : the XAPIC is not used, ie:*/ + /* ints fwded to another XAPIC */ + /* Bits1:7 Reserved */ + /* For CYC: Bits0:7 Reserved */ + unsigned char WP_index; /* For WPEG: WPEG instance index - lower ones have */ + /* lower slot numbers/PCI bus numbers */ + /* For CYC: No meaning */ + unsigned char chassis_num; /* 1 based Chassis number */ + /* For LookOut WPEGs this field indicates the */ + /* Expansion Chassis #, enumerated from Boot */ + /* Node WPEG external port, then Boot Node CYC */ + /* external port, then Next Vigil chassis WPEG */ + /* external port, etc. */ + /* Shared Lookouts have only 1 chassis number (the */ + /* first one assigned) */ +} __attribute__((packed)); + + +typedef enum { + CompatTwister = 0, /* Compatibility Twister */ + AltTwister = 1, /* Alternate Twister of internal 8-way */ + CompatCyclone = 2, /* Compatibility Cyclone */ + AltCyclone = 3, /* Alternate Cyclone of internal 8-way */ + CompatWPEG = 4, /* Compatibility WPEG */ + AltWPEG = 5, /* Second Planar WPEG */ + LookOutAWPEG = 6, /* LookOut WPEG */ + LookOutBWPEG = 7, /* LookOut WPEG */ +} node_type; + +static inline int is_WPEG(node_type type){ + return (type == CompatWPEG || type == AltWPEG || + type == LookOutAWPEG || type == LookOutBWPEG); +} + #endif /* __ASM_MACH_MPPARSE_H */ diff -Nru a/include/asm-i386/memblk.h b/include/asm-i386/memblk.h --- a/include/asm-i386/memblk.h Mon Jun 9 23:16:13 2003 +++ b/include/asm-i386/memblk.h Mon Jun 9 23:16:13 2003 @@ -4,8 +4,8 @@ #include <linux/device.h> #include <linux/mmzone.h> #include <linux/memblk.h> +#include <linux/topology.h> -#include <asm/topology.h> #include <asm/node.h> struct i386_memblk { diff -Nru a/include/asm-i386/mpspec.h b/include/asm-i386/mpspec.h --- a/include/asm-i386/mpspec.h Mon Jun 9 23:16:05 2003 +++ b/include/asm-i386/mpspec.h Mon Jun 9 23:16:05 2003 @@ -222,6 +222,10 @@ extern int pic_mode; extern int using_apic_timer; +#ifdef CONFIG_X86_SUMMIT +extern void setup_summit (void); +#endif + #ifdef CONFIG_ACPI_BOOT extern void mp_register_lapic (u8 id, u8 enabled); extern void mp_register_lapic_address (u64 address); diff -Nru a/include/asm-i386/node.h b/include/asm-i386/node.h --- a/include/asm-i386/node.h Mon Jun 9 23:16:09 2003 +++ b/include/asm-i386/node.h Mon Jun 9 23:16:09 2003 @@ -4,8 +4,7 @@ #include <linux/device.h> #include <linux/mmzone.h> #include <linux/node.h> - -#include <asm/topology.h> +#include <linux/topology.h> struct i386_node { struct node node; diff -Nru a/include/asm-i386/smp.h b/include/asm-i386/smp.h --- a/include/asm-i386/smp.h Mon Jun 9 23:16:14 2003 +++ b/include/asm-i386/smp.h Mon Jun 9 23:16:14 2003 @@ -41,7 +41,6 @@ extern void smp_flush_tlb(void); extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs); extern void smp_send_reschedule(int cpu); -extern void smp_send_reschedule_all(void); extern void smp_invalidate_rcv(void); /* Process an NMI */ extern void (*mtrr_hook) (void); extern void zap_low_mappings (void); diff -Nru a/include/asm-i386/stat.h b/include/asm-i386/stat.h --- a/include/asm-i386/stat.h Mon Jun 9 23:16:07 2003 +++ b/include/asm-i386/stat.h Mon Jun 9 23:16:07 2003 @@ -73,4 +73,6 @@ unsigned long long st_ino; }; +#define STAT_HAVE_NSEC 1 + #endif diff -Nru a/include/asm-i386/thread_info.h b/include/asm-i386/thread_info.h --- a/include/asm-i386/thread_info.h Mon Jun 9 23:16:07 2003 +++ b/include/asm-i386/thread_info.h Mon Jun 9 23:16:07 2003 @@ -87,7 +87,7 @@ /* thread information allocation */ #define THREAD_SIZE (2*PAGE_SIZE) -#define alloc_thread_info() ((struct thread_info *) __get_free_pages(GFP_KERNEL,1)) +#define alloc_thread_info(tsk) ((struct thread_info *) __get_free_pages(GFP_KERNEL,1)) #define free_thread_info(ti) free_pages((unsigned long) (ti), 1) #define get_thread_info(ti) get_task_struct((ti)->task) #define put_thread_info(ti) put_task_struct((ti)->task) diff -Nru a/include/asm-ia64/bug.h b/include/asm-ia64/bug.h --- a/include/asm-ia64/bug.h Mon Jun 9 23:16:05 2003 +++ b/include/asm-ia64/bug.h Mon Jun 9 23:16:05 2003 @@ -7,6 +7,16 @@ # define ia64_abort() (*(volatile int *) 0 = 0) #endif #define BUG() do { printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); ia64_abort(); } while (0) + +#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0) + #define PAGE_BUG(page) do { BUG(); } while (0) + +#define WARN_ON(condition) do { \ + if (unlikely((condition)!=0)) { \ + printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \ + dump_stack(); \ + } \ +} while (0) #endif diff -Nru a/include/asm-ia64/percpu.h b/include/asm-ia64/percpu.h --- a/include/asm-ia64/percpu.h Mon Jun 9 23:16:16 2003 +++ b/include/asm-ia64/percpu.h Mon Jun 9 23:16:16 2003 @@ -8,6 +8,7 @@ * Copyright (C) 2002-2003 Hewlett-Packard Co * David Mosberger-Tang <davidm@hpl.hp.com> */ +#define PERCPU_ENOUGH_ROOM PERCPU_PAGE_SIZE #ifdef __ASSEMBLY__ @@ -19,15 +20,15 @@ extern unsigned long __per_cpu_offset[NR_CPUS]; -#ifndef MODULE #define DEFINE_PER_CPU(type, name) \ __attribute__((__section__(".data.percpu"))) __typeof__(type) name##__per_cpu -#endif #define DECLARE_PER_CPU(type, name) extern __typeof__(type) name##__per_cpu #define __get_cpu_var(var) (var##__per_cpu) #ifdef CONFIG_SMP # define per_cpu(var, cpu) (*RELOC_HIDE(&var##__per_cpu, __per_cpu_offset[cpu])) + +extern void percpu_modcopy(void *pcpudst, const void *src, unsigned long size); #else # define per_cpu(var, cpu) ((void)cpu, __get_cpu_var(var)) #endif diff -Nru a/include/asm-ia64/pgtable.h b/include/asm-ia64/pgtable.h --- a/include/asm-ia64/pgtable.h Mon Jun 9 23:16:09 2003 +++ b/include/asm-ia64/pgtable.h Mon Jun 9 23:16:09 2003 @@ -209,6 +209,10 @@ #define VMALLOC_VMADDR(x) ((unsigned long)(x)) #define VMALLOC_END (0xa000000000000000 + (1UL << (4*PAGE_SHIFT - 9))) +/* fs/proc/kcore.c */ +#define kc_vaddr_to_offset(v) ((v) - 0xA000000000000000) +#define kc_offset_to_vaddr(o) ((o) + 0xA000000000000000) + /* * Conversion functions: convert page frame number (pfn) and a protection value to a page * table entry (pte). diff -Nru a/include/asm-ia64/ptrace.h b/include/asm-ia64/ptrace.h --- a/include/asm-ia64/ptrace.h Mon Jun 9 23:16:15 2003 +++ b/include/asm-ia64/ptrace.h Mon Jun 9 23:16:15 2003 @@ -250,11 +250,10 @@ extern void ia64_increment_ip (struct pt_regs *pt); extern void ia64_decrement_ip (struct pt_regs *pt); -static inline void -force_successful_syscall_return (void) -{ - ia64_task_regs(current)->r8 = 0; -} +#define force_successful_syscall_return() \ + do { \ + ia64_task_regs(current)->r8 = 0; \ + } while (0) #endif /* !__KERNEL__ */ diff -Nru a/include/asm-ia64/smp.h b/include/asm-ia64/smp.h --- a/include/asm-ia64/smp.h Mon Jun 9 23:16:12 2003 +++ b/include/asm-ia64/smp.h Mon Jun 9 23:16:12 2003 @@ -136,8 +136,6 @@ extern int smp_call_function_single (int cpuid, void (*func) (void *info), void *info, int retry, int wait); extern void smp_send_reschedule (int cpu); -extern void smp_send_reschedule_all (void); - #endif /* CONFIG_SMP */ #endif /* _ASM_IA64_SMP_H */ diff -Nru a/include/asm-m68k/bug.h b/include/asm-m68k/bug.h --- a/include/asm-m68k/bug.h Mon Jun 9 23:16:16 2003 +++ b/include/asm-m68k/bug.h Mon Jun 9 23:16:16 2003 @@ -21,8 +21,20 @@ } while (0) #endif +#define BUG_ON(condition) do { \ + if (unlikely((condition)!=0)) \ + BUG(); \ +} while(0) + #define PAGE_BUG(page) do { \ BUG(); \ +} while (0) + +#define WARN_ON(condition) do { \ + if (unlikely((condition)!=0)) { \ + printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \ + dump_stack(); \ + } \ } while (0) #endif diff -Nru a/include/asm-m68k/thread_info.h b/include/asm-m68k/thread_info.h --- a/include/asm-m68k/thread_info.h Mon Jun 9 23:16:15 2003 +++ b/include/asm-m68k/thread_info.h Mon Jun 9 23:16:15 2003 @@ -28,10 +28,10 @@ /* THREAD_SIZE should be 8k, so handle differently for 4k and 8k machines */ #if PAGE_SHIFT == 13 /* 8k machines */ -#define alloc_thread_info() ((struct thread_info *)__get_free_pages(GFP_KERNEL,0)) +#define alloc_thread_info(tsk) ((struct thread_info *)__get_free_pages(GFP_KERNEL,0)) #define free_thread_info(ti) free_pages((unsigned long)(ti),0) #else /* otherwise assume 4k pages */ -#define alloc_thread_info() ((struct thread_info *)__get_free_pages(GFP_KERNEL,1)) +#define alloc_thread_info(tsk) ((struct thread_info *)__get_free_pages(GFP_KERNEL,1)) #define free_thread_info(ti) free_pages((unsigned long)(ti),1) #endif /* PAGE_SHIFT == 13 */ diff -Nru a/include/asm-m68knommu/bug.h b/include/asm-m68knommu/bug.h --- a/include/asm-m68knommu/bug.h Mon Jun 9 23:16:08 2003 +++ b/include/asm-m68knommu/bug.h Mon Jun 9 23:16:08 2003 @@ -5,8 +5,20 @@ printk("%s(%d): kernel BUG!\n", __FILE__, __LINE__); \ } while (0) +#define BUG_ON(condition) do { \ + if (unlikely((condition)!=0)) \ + BUG(); \ +} while(0) + #define PAGE_BUG(page) do { \ BUG(); \ +} while (0) + +#define WARN_ON(condition) do { \ + if (unlikely((condition)!=0)) { \ + printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \ + dump_stack(); \ + } \ } while (0) #endif diff -Nru a/include/asm-m68knommu/thread_info.h b/include/asm-m68knommu/thread_info.h --- a/include/asm-m68knommu/thread_info.h Mon Jun 9 23:16:10 2003 +++ b/include/asm-m68knommu/thread_info.h Mon Jun 9 23:16:10 2003 @@ -65,7 +65,7 @@ } /* thread information allocation */ -#define alloc_thread_info() ((struct thread_info *) \ +#define alloc_thread_info(tsk) ((struct thread_info *) \ __get_free_pages(GFP_KERNEL, 1)) #define free_thread_info(ti) free_pages((unsigned long) (ti), 1) #define get_thread_info(ti) get_task_struct((ti)->task) diff -Nru a/include/asm-mips/bug.h b/include/asm-mips/bug.h --- a/include/asm-mips/bug.h Mon Jun 9 23:16:15 2003 +++ b/include/asm-mips/bug.h Mon Jun 9 23:16:15 2003 @@ -3,6 +3,14 @@ #define __ASM_BUG_H #define BUG() do { printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); *(int *)0=0; } while (0) +#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0) #define PAGE_BUG(page) do { BUG(); } while (0) + +#define WARN_ON(condition) do { \ + if (unlikely((condition)!=0)) { \ + printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \ + dump_stack(); \ + } \ +} while (0) #endif diff -Nru a/include/asm-mips64/bug.h b/include/asm-mips64/bug.h --- a/include/asm-mips64/bug.h Mon Jun 9 23:16:19 2003 +++ b/include/asm-mips64/bug.h Mon Jun 9 23:16:19 2003 @@ -2,6 +2,14 @@ #define _ASM_BUG_H #define BUG() do { printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); *(int *)0=0; } while (0) +#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0) #define PAGE_BUG(page) do { BUG(); } while (0) + +#define WARN_ON(condition) do { \ + if (unlikely((condition)!=0)) { \ + printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \ + dump_stack(); \ + } \ +} while (0) #endif diff -Nru a/include/asm-parisc/bug.h b/include/asm-parisc/bug.h --- a/include/asm-parisc/bug.h Mon Jun 9 23:16:16 2003 +++ b/include/asm-parisc/bug.h Mon Jun 9 23:16:16 2003 @@ -10,8 +10,20 @@ dump_stack(); \ } while (0) +#define BUG_ON(condition) do { \ + if (unlikely((condition)!=0)) \ + BUG(); \ +} while(0) + #define PAGE_BUG(page) do { \ BUG(); \ +} while (0) + +#define WARN_ON(condition) do { \ + if (unlikely((condition)!=0)) { \ + printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \ + dump_stack(); \ + } \ } while (0) #endif diff -Nru a/include/asm-parisc/thread_info.h b/include/asm-parisc/thread_info.h --- a/include/asm-parisc/thread_info.h Mon Jun 9 23:16:09 2003 +++ b/include/asm-parisc/thread_info.h Mon Jun 9 23:16:09 2003 @@ -37,7 +37,7 @@ #define THREAD_SIZE (PAGE_SIZE << THREAD_ORDER) #define THREAD_SHIFT (PAGE_SHIFT + THREAD_ORDER) -#define alloc_thread_info() ((struct thread_info *) \ +#define alloc_thread_info(tsk) ((struct thread_info *) \ __get_free_pages(GFP_KERNEL, THREAD_ORDER)) #define free_thread_info(ti) free_pages((unsigned long) (ti), THREAD_ORDER) #define get_thread_info(ti) get_task_struct((ti)->task) diff -Nru a/include/asm-ppc/bug.h b/include/asm-ppc/bug.h --- a/include/asm-ppc/bug.h Mon Jun 9 23:16:16 2003 +++ b/include/asm-ppc/bug.h Mon Jun 9 23:16:16 2003 @@ -1,21 +1,48 @@ #ifndef _PPC_BUG_H #define _PPC_BUG_H -#include <linux/config.h> -#include <asm/xmon.h> +struct bug_entry { + unsigned long bug_addr; + int line; + const char *file; + const char *function; +}; -#ifdef CONFIG_XMON -extern void xmon(struct pt_regs *); -#define BUG() do { \ - printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ - xmon(0); \ +/* + * If this bit is set in the line number it means that the trap + * is for WARN_ON rather than BUG or BUG_ON. + */ +#define BUG_WARNING_TRAP 0x1000000 + +#define BUG() do { \ + __asm__ __volatile__( \ + "1: twi 31,0,0\n" \ + ".section __bug_table,\"a\"\n\t" \ + " .long 1b,%0,%1,%2\n" \ + ".previous" \ + : : "i" (__LINE__), "i" (__FILE__), "i" (__FUNCTION__)); \ } while (0) -#else -#define BUG() do { \ - printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ - __asm__ __volatile__(".long 0x0"); \ + +#define BUG_ON(x) do { \ + __asm__ __volatile__( \ + "1: twnei %0,0\n" \ + ".section __bug_table,\"a\"\n\t" \ + " .long 1b,%1,%2,%3\n" \ + ".previous" \ + : : "r" (x), "i" (__LINE__), "i" (__FILE__), \ + "i" (__FUNCTION__)); \ } while (0) -#endif + #define PAGE_BUG(page) do { BUG(); } while (0) + +#define WARN_ON(x) do { \ + __asm__ __volatile__( \ + "1: twnei %0,0\n" \ + ".section __bug_table,\"a\"\n\t" \ + " .long 1b,%1,%2,%3\n" \ + ".previous" \ + : : "r" (x), "i" (__LINE__ + BUG_WARNING_TRAP), \ + "i" (__FILE__), "i" (__FUNCTION__)); \ +} while (0) #endif diff -Nru a/include/asm-ppc/dma.h b/include/asm-ppc/dma.h --- a/include/asm-ppc/dma.h Mon Jun 9 23:16:18 2003 +++ b/include/asm-ppc/dma.h Mon Jun 9 23:16:18 2003 @@ -99,7 +99,7 @@ */ /* see prep_setup_arch() for detailed informations */ -#if defined(CONFIG_SOUND_CS4232) && defined(CONFIG_ALL_PPC) +#if defined(CONFIG_SOUND_CS4232) && defined(CONFIG_PPC_PREP) extern long ppc_cs4232_dma, ppc_cs4232_dma2; #define SND_DMA1 ppc_cs4232_dma #define SND_DMA2 ppc_cs4232_dma2 diff -Nru a/include/asm-ppc/hardirq.h b/include/asm-ppc/hardirq.h --- a/include/asm-ppc/hardirq.h Mon Jun 9 23:16:05 2003 +++ b/include/asm-ppc/hardirq.h Mon Jun 9 23:16:05 2003 @@ -5,6 +5,7 @@ #include <linux/config.h> #include <linux/cache.h> #include <linux/smp_lock.h> +#include <asm/irq.h> /* The __last_jiffy_stamp field is needed to ensure that no decrementer * interrupt is lost on SMP machines. Since on most CPUs it is in the same diff -Nru a/include/asm-ppc/io.h b/include/asm-ppc/io.h --- a/include/asm-ppc/io.h Mon Jun 9 23:16:17 2003 +++ b/include/asm-ppc/io.h Mon Jun 9 23:16:17 2003 @@ -77,7 +77,7 @@ #define insl(port, buf, nl) _insl_ns((u32 *)((port)+_IO_BASE), (buf), (nl)) #define outsl(port, buf, nl) _outsl_ns((u32 *)((port)+_IO_BASE), (buf), (nl)) -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_PMAC /* * On powermacs, we will get a machine check exception if we * try to read data from a non-existent I/O port. Because the @@ -149,7 +149,7 @@ #define inl(port) in_be32((u32 *)((port)+_IO_BASE)) #define outl(val, port) out_be32((u32 *)((port)+_IO_BASE), (val)) -#else /* not APUS or ALL_PPC */ +#else /* not APUS or PMAC */ #define inb(port) in_8((u8 *)((port)+_IO_BASE)) #define outb(val, port) out_8((u8 *)((port)+_IO_BASE), (val)) #define inw(port) in_le16((u16 *)((port)+_IO_BASE)) diff -Nru a/include/asm-ppc/ipc.h b/include/asm-ppc/ipc.h --- a/include/asm-ppc/ipc.h Mon Jun 9 23:16:20 2003 +++ b/include/asm-ppc/ipc.h Mon Jun 9 23:16:20 2003 @@ -7,7 +7,7 @@ * See arch/ppc/kernel/syscalls.c for ugly details.. */ struct ipc_kludge { - struct msgbuf *msgp; + struct msgbuf __user *msgp; long msgtyp; }; diff -Nru a/include/asm-ppc/mmu_context.h b/include/asm-ppc/mmu_context.h --- a/include/asm-ppc/mmu_context.h Mon Jun 9 23:16:13 2003 +++ b/include/asm-ppc/mmu_context.h Mon Jun 9 23:16:13 2003 @@ -57,7 +57,7 @@ #define LAST_CONTEXT 15 #define FIRST_CONTEXT 0 -#elif CONFIG_4xx +#elif defined(CONFIG_4xx) #define NO_CONTEXT 256 #define LAST_CONTEXT 255 #define FIRST_CONTEXT 1 diff -Nru a/include/asm-ppc/module.h b/include/asm-ppc/module.h --- a/include/asm-ppc/module.h Mon Jun 9 23:16:09 2003 +++ b/include/asm-ppc/module.h Mon Jun 9 23:16:09 2003 @@ -2,6 +2,9 @@ #define _ASM_PPC_MODULE_H /* Module stuff for PPC. (C) 2001 Rusty Russell */ +#include <linux/list.h> +#include <asm/bug.h> + /* Thanks to Paul M for explaining this. PPC can only do rel jumps += 32MB, and often the kernel and other @@ -20,7 +23,14 @@ { /* Indices of PLT sections within module. */ unsigned int core_plt_section, init_plt_section; + + /* List of BUG addresses, source line numbers and filenames */ + struct list_head bug_list; + struct bug_entry *bug_table; + unsigned int num_bugs; }; + +extern struct bug_entry *module_find_bug(unsigned long bugaddr); #define Elf_Shdr Elf32_Shdr #define Elf_Sym Elf32_Sym diff -Nru a/include/asm-ppc/ocp.h b/include/asm-ppc/ocp.h --- a/include/asm-ppc/ocp.h Mon Jun 9 23:16:08 2003 +++ b/include/asm-ppc/ocp.h Mon Jun 9 23:16:08 2003 @@ -36,6 +36,7 @@ #include <linux/list.h> #include <linux/config.h> #include <linux/device.h> +#include <linux/errno.h> #include <asm/ocp_ids.h> #include <asm/mmu.h> /* For phys_addr_t */ diff -Nru a/include/asm-ppc/prep_nvram.h b/include/asm-ppc/prep_nvram.h --- a/include/asm-ppc/prep_nvram.h Mon Jun 9 23:16:15 2003 +++ b/include/asm-ppc/prep_nvram.h Mon Jun 9 23:16:15 2003 @@ -89,7 +89,7 @@ typedef enum _PM_MODE { Suspend = 0x80, /* Part of state is in memory */ Normal = 0x00 /* No power management in effect */ -} PMMode; +} PMMODE; typedef struct _HEADER { unsigned short Size; /* NVRAM size in K(1024) */ diff -Nru a/include/asm-ppc/processor.h b/include/asm-ppc/processor.h --- a/include/asm-ppc/processor.h Mon Jun 9 23:16:05 2003 +++ b/include/asm-ppc/processor.h Mon Jun 9 23:16:05 2003 @@ -559,7 +559,7 @@ /* We only need to define a new _MACH_xxx for machines which are part of * a configuration which supports more than one type of different machine. - * This is currently limited to CONFIG_ALL_PPC and CHRP/PReP/PMac. -- Tom + * This is currently limited to CONFIG_PPC_MULTIPLATFORM and CHRP/PReP/PMac. -- Tom */ #define _MACH_prep 0x00000001 #define _MACH_Pmac 0x00000002 /* pmac or pmac clone (non-chrp) */ @@ -620,7 +620,7 @@ #define SR15 15 #ifndef __ASSEMBLY__ -#if defined(CONFIG_ALL_PPC) +#ifdef CONFIG_PPC_MULTIPLATFORM extern int _machine; /* what kind of prep workstation we are */ @@ -635,7 +635,7 @@ extern unsigned char ucBoardRevMaj, ucBoardRevMin; #else #define _machine 0 -#endif /* CONFIG_ALL_PPC */ +#endif /* CONFIG_PPC_MULTIPLATFORM */ struct task_struct; void start_thread(struct pt_regs *regs, unsigned long nip, unsigned long sp); @@ -691,8 +691,10 @@ unsigned long fpscr_pad; /* fpr ... fpscr must be contiguous */ unsigned long fpscr; /* Floating point status */ #ifdef CONFIG_ALTIVEC - vector128 vr[32]; /* Complete AltiVec set */ - vector128 vscr; /* AltiVec status */ + /* Complete AltiVec register set */ + vector128 vr[32] __attribute((aligned(16))); + /* AltiVec status */ + vector128 vscr __attribute((aligned(16))); unsigned long vrsave; #endif /* CONFIG_ALTIVEC */ }; diff -Nru a/include/asm-ppc/ptrace.h b/include/asm-ppc/ptrace.h --- a/include/asm-ppc/ptrace.h Mon Jun 9 23:16:13 2003 +++ b/include/asm-ppc/ptrace.h Mon Jun 9 23:16:13 2003 @@ -33,7 +33,7 @@ /* N.B. for critical exceptions on 4xx, the dar and dsisr fields are overloaded to hold srr0 and srr1. */ unsigned long dar; /* Fault registers */ - unsigned long dsisr; + unsigned long dsisr; /* on 4xx/Book-E used for ESR */ unsigned long result; /* Result of a system call */ }; diff -Nru a/include/asm-ppc/semaphore.h b/include/asm-ppc/semaphore.h --- a/include/asm-ppc/semaphore.h Mon Jun 9 23:16:13 2003 +++ b/include/asm-ppc/semaphore.h Mon Jun 9 23:16:13 2003 @@ -29,12 +29,12 @@ */ atomic_t count; wait_queue_head_t wait; -#if WAITQUEUE_DEBUG +#ifdef WAITQUEUE_DEBUG long __magic; #endif }; -#if WAITQUEUE_DEBUG +#ifdef WAITQUEUE_DEBUG # define __SEM_DEBUG_INIT(name) \ , (long)&(name).__magic #else @@ -59,7 +59,7 @@ { atomic_set(&sem->count, val); init_waitqueue_head(&sem->wait); -#if WAITQUEUE_DEBUG +#ifdef WAITQUEUE_DEBUG sem->__magic = (long)&sem->__magic; #endif } @@ -80,7 +80,7 @@ extern inline void down(struct semaphore * sem) { -#if WAITQUEUE_DEBUG +#ifdef WAITQUEUE_DEBUG CHECK_MAGIC(sem->__magic); #endif might_sleep(); @@ -97,7 +97,7 @@ { int ret = 0; -#if WAITQUEUE_DEBUG +#ifdef WAITQUEUE_DEBUG CHECK_MAGIC(sem->__magic); #endif might_sleep(); @@ -112,7 +112,7 @@ { int ret; -#if WAITQUEUE_DEBUG +#ifdef WAITQUEUE_DEBUG CHECK_MAGIC(sem->__magic); #endif @@ -123,7 +123,7 @@ extern inline void up(struct semaphore * sem) { -#if WAITQUEUE_DEBUG +#ifdef WAITQUEUE_DEBUG CHECK_MAGIC(sem->__magic); #endif diff -Nru a/include/asm-ppc/system.h b/include/asm-ppc/system.h --- a/include/asm-ppc/system.h Mon Jun 9 23:16:10 2003 +++ b/include/asm-ppc/system.h Mon Jun 9 23:16:10 2003 @@ -5,7 +5,7 @@ #define __PPC_SYSTEM_H #include <linux/config.h> -#include <linux/kdev_t.h> +#include <linux/kernel.h> #include <asm/processor.h> #include <asm/atomic.h> @@ -43,9 +43,9 @@ #define smp_wmb() wmb() #define smp_read_barrier_depends() read_barrier_depends() #else -#define smp_mb() __asm__ __volatile__("": : :"memory") -#define smp_rmb() __asm__ __volatile__("": : :"memory") -#define smp_wmb() __asm__ __volatile__("": : :"memory") +#define smp_mb() barrier() +#define smp_rmb() barrier() +#define smp_wmb() barrier() #define smp_read_barrier_depends() do { } while(0) #endif /* CONFIG_SMP */ diff -Nru a/include/asm-ppc/thread_info.h b/include/asm-ppc/thread_info.h --- a/include/asm-ppc/thread_info.h Mon Jun 9 23:16:08 2003 +++ b/include/asm-ppc/thread_info.h Mon Jun 9 23:16:08 2003 @@ -54,7 +54,7 @@ } /* thread information allocation */ -#define alloc_thread_info() ((struct thread_info *) \ +#define alloc_thread_info(tsk) ((struct thread_info *) \ __get_free_pages(GFP_KERNEL, 1)) #define free_thread_info(ti) free_pages((unsigned long) (ti), 1) #define get_thread_info(ti) get_task_struct((ti)->task) diff -Nru a/include/asm-ppc/types.h b/include/asm-ppc/types.h --- a/include/asm-ppc/types.h Mon Jun 9 23:16:18 2003 +++ b/include/asm-ppc/types.h Mon Jun 9 23:16:18 2003 @@ -19,7 +19,7 @@ typedef struct { __u32 u[4]; -} __attribute((aligned(16))) __vector128; +} __vector128; /* * XXX allowed outside of __KERNEL__ for now, until glibc gets diff -Nru a/include/asm-ppc/uaccess.h b/include/asm-ppc/uaccess.h --- a/include/asm-ppc/uaccess.h Mon Jun 9 23:16:05 2003 +++ b/include/asm-ppc/uaccess.h Mon Jun 9 23:16:05 2003 @@ -32,7 +32,7 @@ #define __access_ok(addr,size) (__kernel_ok || __user_ok((addr),(size))) #define access_ok(type,addr,size) __access_ok((unsigned long)(addr),(size)) -extern inline int verify_area(int type, const void * addr, unsigned long size) +extern inline int verify_area(int type, const void __user * addr, unsigned long size) { return access_ok(type,addr,size) ? 0 : -EFAULT; } @@ -225,45 +225,46 @@ /* more complex routines */ -extern int __copy_tofrom_user(void *to, const void *from, unsigned long size); +extern int __copy_tofrom_user(void __user *to, const void __user *from, + unsigned long size); extern inline unsigned long -copy_from_user(void *to, const void *from, unsigned long n) +copy_from_user(void *to, const void __user *from, unsigned long n) { unsigned long over; if (access_ok(VERIFY_READ, from, n)) - return __copy_tofrom_user(to, from, n); + return __copy_tofrom_user((void __user *)to, from, n); if ((unsigned long)from < TASK_SIZE) { over = (unsigned long)from + n - TASK_SIZE; - return __copy_tofrom_user(to, from, n - over) + over; + return __copy_tofrom_user((void __user *)to, from, n - over) + over; } return n; } extern inline unsigned long -copy_to_user(void *to, const void *from, unsigned long n) +copy_to_user(void __user *to, const void *from, unsigned long n) { unsigned long over; if (access_ok(VERIFY_WRITE, to, n)) - return __copy_tofrom_user(to, from, n); + return __copy_tofrom_user(to, (void __user *) from, n); if ((unsigned long)to < TASK_SIZE) { over = (unsigned long)to + n - TASK_SIZE; - return __copy_tofrom_user(to, from, n - over) + over; + return __copy_tofrom_user(to, (void __user *) from, n - over) + over; } return n; } #define __copy_from_user(to, from, size) \ - __copy_tofrom_user((to), (from), (size)) + __copy_tofrom_user((void __user *)(to), (from), (size)) #define __copy_to_user(to, from, size) \ - __copy_tofrom_user((to), (from), (size)) + __copy_tofrom_user((to), (void __user *)(from), (size)) -extern unsigned long __clear_user(void *addr, unsigned long size); +extern unsigned long __clear_user(void __user *addr, unsigned long size); extern inline unsigned long -clear_user(void *addr, unsigned long size) +clear_user(void __user *addr, unsigned long size) { if (access_ok(VERIFY_WRITE, addr, size)) return __clear_user(addr, size); @@ -274,10 +275,10 @@ return size; } -extern int __strncpy_from_user(char *dst, const char *src, long count); +extern int __strncpy_from_user(char *dst, const char __user *src, long count); extern inline long -strncpy_from_user(char *dst, const char *src, long count) +strncpy_from_user(char *dst, const char __user *src, long count) { if (access_ok(VERIFY_READ, src, 1)) return __strncpy_from_user(dst, src, count); @@ -290,7 +291,7 @@ * Return 0 for error */ -extern int __strnlen_user(const char *str, long len, unsigned long top); +extern int __strnlen_user(const char __user *str, long len, unsigned long top); /* * Returns the length of the string at str (including the null byte), @@ -300,7 +301,7 @@ * The `top' parameter to __strnlen_user is to make sure that * we can never overflow from the user area into kernel space. */ -extern __inline__ int strnlen_user(const char *str, long len) +extern __inline__ int strnlen_user(const char __user *str, long len) { unsigned long top = __kernel_ok? ~0UL: TASK_SIZE - 1; diff -Nru a/include/asm-ppc64/bug.h b/include/asm-ppc64/bug.h --- a/include/asm-ppc64/bug.h Mon Jun 9 23:16:07 2003 +++ b/include/asm-ppc64/bug.h Mon Jun 9 23:16:07 2003 @@ -27,7 +27,16 @@ } while (0) #endif +#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0) + #define PAGE_BUG(page) do { BUG(); } while (0) + +#define WARN_ON(condition) do { \ + if (unlikely((condition)!=0)) { \ + printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \ + dump_stack(); \ + } \ +} while (0) #endif #endif diff -Nru a/include/asm-ppc64/elf.h b/include/asm-ppc64/elf.h --- a/include/asm-ppc64/elf.h Mon Jun 9 23:16:16 2003 +++ b/include/asm-ppc64/elf.h Mon Jun 9 23:16:16 2003 @@ -97,18 +97,43 @@ #define ELF_ET_DYN_BASE (0x08000000) +#ifdef __KERNEL__ + /* Common routine for both 32-bit and 64-bit processes */ -#define ELF_CORE_COPY_REGS(gregs, regs) ppc64_elf_core_copy_regs(gregs, regs); -static inline void -ppc64_elf_core_copy_regs(elf_gregset_t dstRegs, struct pt_regs* srcRegs) +static inline void ppc64_elf_core_copy_regs(elf_gregset_t elf_regs, + struct pt_regs *regs) { int i; + int gprs = sizeof(struct pt_regs)/sizeof(elf_greg_t64); + + if (gprs > ELF_NGREG) + gprs = ELF_NGREG; + + for (i=0; i < gprs; i++) + elf_regs[i] = (elf_greg_t)((elf_greg_t64 *)regs)[i]; +} +#define ELF_CORE_COPY_REGS(gregs, regs) ppc64_elf_core_copy_regs(gregs, regs); - int numGPRS = ((sizeof(struct pt_regs)/sizeof(elf_greg_t64)) < ELF_NGREG) ? (sizeof(struct pt_regs)/sizeof(elf_greg_t64)) : ELF_NGREG; +static inline int dump_task_regs(struct task_struct *tsk, + elf_gregset_t *elf_regs) +{ + struct pt_regs *regs = tsk->thread.regs; + if (regs) + ppc64_elf_core_copy_regs(*elf_regs, regs); - for (i=0; i < numGPRS; i++) - dstRegs[i] = (elf_greg_t)((elf_greg_t64 *)srcRegs)[i]; + return 1; } +#define ELF_CORE_COPY_TASK_REGS(tsk, elf_regs) dump_task_regs(tsk, elf_regs) + +extern int dump_task_fpu(struct task_struct *, elf_fpregset_t *); +#define ELF_CORE_COPY_FPREGS(tsk, elf_fpregs) dump_task_fpu(tsk, elf_fpregs) + +#ifdef CONFIG_SMP +extern void dump_smp_unlazy_fpu(void); +#define ELF_CORE_SYNC dump_smp_unlazy_fpu +#endif + +#endif /* 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 -Nru a/include/asm-ppc64/mmzone.h b/include/asm-ppc64/mmzone.h --- a/include/asm-ppc64/mmzone.h Mon Jun 9 23:16:19 2003 +++ b/include/asm-ppc64/mmzone.h Mon Jun 9 23:16:19 2003 @@ -21,6 +21,7 @@ extern int numa_cpu_lookup_table[]; extern int numa_memory_lookup_table[]; extern unsigned long numa_cpumask_lookup_table[]; +extern int nr_cpus_in_node[]; #define MAX_MEMORY (1UL << 41) /* 256MB regions */ diff -Nru a/include/asm-ppc64/paca.h b/include/asm-ppc64/paca.h --- a/include/asm-ppc64/paca.h Mon Jun 9 23:16:10 2003 +++ b/include/asm-ppc64/paca.h Mon Jun 9 23:16:10 2003 @@ -33,17 +33,6 @@ #include <asm/mmu.h> #include <asm/processor.h> -/* A paca entry is required for each logical processor. On systems - * that support hardware multi-threading, this is equal to twice the - * number of physical processors. On LPAR systems, we are required - * to have space for the maximum number of logical processors we - * could ever possibly have. Currently, we are limited to allocating - * 24 processors to a partition which gives 48 logical processors on - * an HMT box. Therefore, we reserve this many paca entries. - */ -#define MAX_PROCESSORS 24 -#define MAX_PACAS MAX_PROCESSORS * 2 - extern struct paca_struct paca[]; register struct paca_struct *local_paca asm("r13"); #define get_paca() local_paca diff -Nru a/include/asm-ppc64/pci-bridge.h b/include/asm-ppc64/pci-bridge.h --- a/include/asm-ppc64/pci-bridge.h Mon Jun 9 23:16:07 2003 +++ b/include/asm-ppc64/pci-bridge.h Mon Jun 9 23:16:07 2003 @@ -77,7 +77,7 @@ static inline struct device_node *pci_device_to_OF_node(struct pci_dev *dev) { struct device_node *dn = (struct device_node *)(dev->sysdata); - if (dn->devfn == dev->devfn && dn->busno == dev->bus->number) + if (dn->devfn == dev->devfn && dn->busno == (dev->bus->number&0xff)) return dn; /* fast path. sysdata is good */ else return fetch_dev_dn(dev); diff -Nru a/include/asm-ppc64/signal.h b/include/asm-ppc64/signal.h --- a/include/asm-ppc64/signal.h Mon Jun 9 23:16:10 2003 +++ b/include/asm-ppc64/signal.h Mon Jun 9 23:16:10 2003 @@ -2,6 +2,7 @@ #define _ASMPPC64_SIGNAL_H #include <linux/types.h> +#include <asm/siginfo.h> /* Avoid too many header ordering problems. */ struct siginfo; @@ -72,19 +73,19 @@ * SA_ONESHOT and SA_NOMASK are the historical Linux names for the Single * Unix names RESETHAND and NODEFER respectively. */ -#define SA_NOCLDSTOP 0x00000001 -#define SA_NOCLDWAIT 0x00000002 -#define SA_SIGINFO 0x00000004 -#define SA_ONSTACK 0x08000000 -#define SA_RESTART 0x10000000 -#define SA_NODEFER 0x40000000 -#define SA_RESETHAND 0x80000000 +#define SA_NOCLDSTOP 0x00000001u +#define SA_NOCLDWAIT 0x00000002u +#define SA_SIGINFO 0x00000004u +#define SA_ONSTACK 0x08000000u +#define SA_RESTART 0x10000000u +#define SA_NODEFER 0x40000000u +#define SA_RESETHAND 0x80000000u #define SA_NOMASK SA_NODEFER #define SA_ONESHOT SA_RESETHAND -#define SA_INTERRUPT 0x20000000 /* dummy -- ignored */ +#define SA_INTERRUPT 0x20000000u /* dummy -- ignored */ -#define SA_RESTORER 0x04000000 +#define SA_RESTORER 0x04000000u /* * sigaltstack controls @@ -143,6 +144,16 @@ size_t ss_size; } stack_t; +struct pt_regs; +struct timespec; +extern int do_signal(sigset_t *oldset, struct pt_regs *regs); +extern int do_signal32(sigset_t *oldset, struct pt_regs *regs); +extern long sys_rt_sigprocmask(int how, sigset_t *set, sigset_t *oset, + size_t sigsetsize); +extern long sys_rt_sigpending(sigset_t *set, size_t sigsetsize); +extern long sys_rt_sigtimedwait(const sigset_t *uthese, siginfo_t *uinfo, + const struct timespec *uts, size_t sigsetsize); +extern long sys_rt_sigqueueinfo(int pid, int sig, siginfo_t *uinfo); #define ptrace_signal_deliver(regs, cookie) do { } while (0) struct pt_regs; diff -Nru a/include/asm-ppc64/smp.h b/include/asm-ppc64/smp.h --- a/include/asm-ppc64/smp.h Mon Jun 9 23:16:05 2003 +++ b/include/asm-ppc64/smp.h Mon Jun 9 23:16:05 2003 @@ -34,7 +34,6 @@ extern void smp_send_xmon_break(int cpu); struct pt_regs; extern void smp_message_recv(int, struct pt_regs *); -extern void smp_send_reschedule_all(void); #define NO_PROC_ID 0xFF /* No processor magic marker */ diff -Nru a/include/asm-ppc64/system.h b/include/asm-ppc64/system.h --- a/include/asm-ppc64/system.h Mon Jun 9 23:16:19 2003 +++ b/include/asm-ppc64/system.h Mon Jun 9 23:16:19 2003 @@ -83,6 +83,7 @@ extern void flush_instruction_cache(void); extern int _get_PVR(void); extern void giveup_fpu(struct task_struct *); +extern void disable_kernel_fp(void); extern void enable_kernel_fp(void); extern void cvt_fd(float *from, double *to, unsigned long *fpscr); extern void cvt_df(double *from, float *to, unsigned long *fpscr); diff -Nru a/include/asm-ppc64/thread_info.h b/include/asm-ppc64/thread_info.h --- a/include/asm-ppc64/thread_info.h Mon Jun 9 23:16:07 2003 +++ b/include/asm-ppc64/thread_info.h Mon Jun 9 23:16:07 2003 @@ -52,7 +52,7 @@ #define THREAD_SIZE (PAGE_SIZE << THREAD_ORDER) #define THREAD_SHIFT (PAGE_SHIFT + THREAD_ORDER) -#define alloc_thread_info() ((struct thread_info *) \ +#define alloc_thread_info(tsk) ((struct thread_info *) \ __get_free_pages(GFP_KERNEL, THREAD_ORDER)) #define free_thread_info(ti) free_pages((unsigned long) (ti), THREAD_ORDER) #define get_thread_info(ti) get_task_struct((ti)->task) diff -Nru a/include/asm-ppc64/topology.h b/include/asm-ppc64/topology.h --- a/include/asm-ppc64/topology.h Mon Jun 9 23:16:19 2003 +++ b/include/asm-ppc64/topology.h Mon Jun 9 23:16:19 2003 @@ -38,6 +38,8 @@ #define pcibus_to_cpumask(bus) (cpu_online_map) +#define nr_cpus_node(node) (nr_cpus_in_node[node]) + /* Cross-node load balancing interval. */ #define NODE_BALANCE_RATE 10 diff -Nru a/include/asm-ppc64/uaccess.h b/include/asm-ppc64/uaccess.h --- a/include/asm-ppc64/uaccess.h Mon Jun 9 23:16:13 2003 +++ b/include/asm-ppc64/uaccess.h Mon Jun 9 23:16:13 2003 @@ -206,6 +206,7 @@ return __copy_tofrom_user(to, from, n); if ((unsigned long)from < TASK_SIZE) { over = (unsigned long)from + n - TASK_SIZE; + memset(to + over, 0, over); return __copy_tofrom_user(to, from, n - over) + over; } return n; diff -Nru a/include/asm-s390/bug.h b/include/asm-s390/bug.h --- a/include/asm-s390/bug.h Mon Jun 9 23:16:16 2003 +++ b/include/asm-s390/bug.h Mon Jun 9 23:16:16 2003 @@ -6,8 +6,20 @@ __asm__ __volatile__(".long 0"); \ } while (0) +#define BUG_ON(condition) do { \ + if (unlikely((condition)!=0)) \ + BUG(); \ +} while(0) + #define PAGE_BUG(page) do { \ BUG(); \ } while (0) + +#define WARN_ON(condition) do { \ + if (unlikely((condition)!=0)) { \ + printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \ + dump_stack(); \ + } \ +} while (0) #endif diff -Nru a/include/asm-s390/thread_info.h b/include/asm-s390/thread_info.h --- a/include/asm-s390/thread_info.h Mon Jun 9 23:16:15 2003 +++ b/include/asm-s390/thread_info.h Mon Jun 9 23:16:15 2003 @@ -68,7 +68,7 @@ } /* thread information allocation */ -#define alloc_thread_info() ((struct thread_info *) \ +#define alloc_thread_info(tsk) ((struct thread_info *) \ __get_free_pages(GFP_KERNEL,THREAD_ORDER)) #define free_thread_info(ti) free_pages((unsigned long) (ti),THREAD_ORDER) #define get_thread_info(ti) get_task_struct((ti)->task) diff -Nru a/include/asm-sh/bug.h b/include/asm-sh/bug.h --- a/include/asm-sh/bug.h Mon Jun 9 23:16:18 2003 +++ b/include/asm-sh/bug.h Mon Jun 9 23:16:18 2003 @@ -9,8 +9,20 @@ asm volatile("nop"); \ } while (0) +#define BUG_ON(condition) do { \ + if (unlikely((condition)!=0)) \ + BUG(); \ +} while(0) + #define PAGE_BUG(page) do { \ BUG(); \ +} while (0) + +#define WARN_ON(condition) do { \ + if (unlikely((condition)!=0)) { \ + printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \ + dump_stack(); \ + } \ } while (0) #endif diff -Nru a/include/asm-sparc/bug.h b/include/asm-sparc/bug.h --- a/include/asm-sparc/bug.h Mon Jun 9 23:16:20 2003 +++ b/include/asm-sparc/bug.h Mon Jun 9 23:16:20 2003 @@ -12,8 +12,20 @@ #define BUG() __builtin_trap() #endif +#define BUG_ON(condition) do { \ + if (unlikely((condition)!=0)) \ + BUG(); \ +} while(0) + #define PAGE_BUG(page) do { \ BUG(); \ +} while (0) + +#define WARN_ON(condition) do { \ + if (unlikely((condition)!=0)) { \ + printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \ + dump_stack(); \ + } \ } while (0) #endif diff -Nru a/include/asm-sparc/thread_info.h b/include/asm-sparc/thread_info.h --- a/include/asm-sparc/thread_info.h Mon Jun 9 23:16:19 2003 +++ b/include/asm-sparc/thread_info.h Mon Jun 9 23:16:19 2003 @@ -78,7 +78,7 @@ #endif BTFIXUPDEF_CALL(struct thread_info *, alloc_thread_info, void) -#define alloc_thread_info() BTFIXUP_CALL(alloc_thread_info)() +#define alloc_thread_info(tsk) BTFIXUP_CALL(alloc_thread_info)() BTFIXUPDEF_CALL(void, free_thread_info, struct thread_info *) #define free_thread_info(ti) BTFIXUP_CALL(free_thread_info)(ti) diff -Nru a/include/asm-sparc64/bug.h b/include/asm-sparc64/bug.h --- a/include/asm-sparc64/bug.h Mon Jun 9 23:16:14 2003 +++ b/include/asm-sparc64/bug.h Mon Jun 9 23:16:14 2003 @@ -13,8 +13,20 @@ #define BUG() __builtin_trap() #endif +#define BUG_ON(condition) do { \ + if (unlikely((condition)!=0)) \ + BUG(); \ +} while(0) + #define PAGE_BUG(page) do { \ BUG(); \ +} while (0) + +#define WARN_ON(condition) do { \ + if (unlikely((condition)!=0)) { \ + printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \ + dump_stack(); \ + } \ } while (0) #endif diff -Nru a/include/asm-sparc64/thread_info.h b/include/asm-sparc64/thread_info.h --- a/include/asm-sparc64/thread_info.h Mon Jun 9 23:16:15 2003 +++ b/include/asm-sparc64/thread_info.h Mon Jun 9 23:16:15 2003 @@ -142,10 +142,10 @@ /* thread information allocation */ #if PAGE_SHIFT == 13 -#define alloc_thread_info() ((struct thread_info *)__get_free_pages(GFP_KERNEL, 1)) +#define alloc_thread_info(tsk)((struct thread_info *)__get_free_pages(GFP_KERNEL, 1)) #define free_thread_info(ti) free_pages((unsigned long)(ti),1) #else /* PAGE_SHIFT == 13 */ -#define alloc_thread_info() ((struct thread_info *)__get_free_pages(GFP_KERNEL, 0)) +#define alloc_thread_info(tsk)((struct thread_info *)__get_free_pages(GFP_KERNEL, 0)) #define free_thread_info(ti) free_pages((unsigned long)(ti),0) #endif /* PAGE_SHIFT == 13 */ diff -Nru a/include/asm-um/bug.h b/include/asm-um/bug.h --- a/include/asm-um/bug.h Mon Jun 9 23:16:12 2003 +++ b/include/asm-um/bug.h Mon Jun 9 23:16:12 2003 @@ -7,8 +7,20 @@ panic("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ } while (0) +#define BUG_ON(condition) do { \ + if (unlikely((condition)!=0)) \ + BUG(); \ +} while(0) + #define PAGE_BUG(page) do { \ BUG(); \ +} while (0) + +#define WARN_ON(condition) do { \ + if (unlikely((condition)!=0)) { \ + printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \ + dump_stack(); \ + } \ } while (0) extern int foo; diff -Nru a/include/asm-um/processor-ppc.h b/include/asm-um/processor-ppc.h --- a/include/asm-um/processor-ppc.h Mon Jun 9 23:16:08 2003 +++ b/include/asm-um/processor-ppc.h Mon Jun 9 23:16:08 2003 @@ -3,7 +3,7 @@ #if defined(__ASSEMBLY__) -#define CONFIG_ALL_PPC +#define CONFIG_PPC_MULTIPLATFORM #include "arch/processor.h" #else diff -Nru a/include/asm-um/thread_info.h b/include/asm-um/thread_info.h --- a/include/asm-um/thread_info.h Mon Jun 9 23:16:09 2003 +++ b/include/asm-um/thread_info.h Mon Jun 9 23:16:09 2003 @@ -49,7 +49,7 @@ /* thread information allocation */ #define THREAD_SIZE (4*PAGE_SIZE) -#define alloc_thread_info() ((struct thread_info *) \ +#define alloc_thread_info(tsk) ((struct thread_info *) \ __get_free_pages(GFP_KERNEL,2)) #define free_thread_info(ti) free_pages((unsigned long) (ti), 2) #define get_thread_info(ti) get_task_struct((ti)->task) diff -Nru a/include/asm-v850/bitops.h b/include/asm-v850/bitops.h --- a/include/asm-v850/bitops.h Mon Jun 9 23:16:13 2003 +++ b/include/asm-v850/bitops.h Mon Jun 9 23:16:13 2003 @@ -1,8 +1,8 @@ /* * include/asm-v850/bitops.h -- Bit operations * - * Copyright (C) 2001,02 NEC Corporation - * Copyright (C) 2001,02 Miles Bader <miles@gnu.org> + * Copyright (C) 2001,02,03 NEC Electronics Corporation + * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org> * Copyright (C) 1992 Linus Torvalds. * * This file is subject to the terms and conditions of the GNU General @@ -133,7 +133,7 @@ "m" (*((const char *)(addr) + ((nr) >> 3)))); \ __test_bit_res; \ }) -extern __inline__ int __test_bit (int nr, void *addr) +extern __inline__ int __test_bit (int nr, const void *addr) { int res; __asm__ ("tst1 %1, [%2]; setf nz, %0" diff -Nru a/include/asm-v850/bug.h b/include/asm-v850/bug.h --- a/include/asm-v850/bug.h Mon Jun 9 23:16:08 2003 +++ b/include/asm-v850/bug.h Mon Jun 9 23:16:08 2003 @@ -18,4 +18,13 @@ #define BUG() __bug() #define PAGE_BUG(page) __bug() +#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0) + +#define WARN_ON(condition) do { \ + if (unlikely((condition)!=0)) { \ + printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \ + dump_stack(); \ + } \ +} while (0) + #endif /* __V850_BUG_H__ */ diff -Nru a/include/asm-v850/nb85e_cache.h b/include/asm-v850/nb85e_cache.h --- a/include/asm-v850/nb85e_cache.h Mon Jun 9 23:16:12 2003 +++ b/include/asm-v850/nb85e_cache.h Mon Jun 9 23:16:12 2003 @@ -35,7 +35,7 @@ #define L1_CACHE_BYTES NB85E_CACHE_LINE_SIZE -#ifndef __ASSEMBLY__ +#if defined(__KERNEL__) && !defined(__ASSEMBLY__) /* Set caching params via the BHC and DCC registers. */ void nb85e_cache_enable (u16 bhc, u16 dcc); @@ -73,6 +73,6 @@ #define flush_icache_user_range nb85e_cache_flush_icache_user_range #define flush_cache_sigtramp nb85e_cache_flush_sigtramp -#endif /* !__ASSEMBLY__ */ +#endif /* __KERNEL__ && !__ASSEMBLY__ */ #endif /* __V850_NB85E_CACHE_H__ */ diff -Nru a/include/asm-v850/sim.h b/include/asm-v850/sim.h --- a/include/asm-v850/sim.h Mon Jun 9 23:16:08 2003 +++ b/include/asm-v850/sim.h Mon Jun 9 23:16:08 2003 @@ -1,8 +1,8 @@ /* * include/asm-v850/sim.h -- Machine-dependent defs for GDB v850e simulator * - * Copyright (C) 2001,02 NEC Corporation - * Copyright (C) 2001,02 Miles Bader <miles@gnu.org> + * Copyright (C) 2001,02,03 NEC Electronics Corporation + * Copyright (C) 2001,02,03 Miles Bader <miles@gnu.org> * * 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 diff -Nru a/include/asm-v850/thread_info.h b/include/asm-v850/thread_info.h --- a/include/asm-v850/thread_info.h Mon Jun 9 23:16:10 2003 +++ b/include/asm-v850/thread_info.h Mon Jun 9 23:16:10 2003 @@ -54,7 +54,7 @@ */ /* thread information allocation */ -#define alloc_thread_info() ((struct thread_info *) \ +#define alloc_thread_info(tsk) ((struct thread_info *) \ __get_free_pages(GFP_KERNEL, 1)) #define free_thread_info(ti) free_pages((unsigned long) (ti), 1) #define get_thread_info(ti) get_task_struct((ti)->task) diff -Nru a/include/asm-x86_64/apic.h b/include/asm-x86_64/apic.h --- a/include/asm-x86_64/apic.h Mon Jun 9 23:16:18 2003 +++ b/include/asm-x86_64/apic.h Mon Jun 9 23:16:18 2003 @@ -75,13 +75,16 @@ extern void setup_boot_APIC_clock (void); extern void setup_secondary_APIC_clock (void); extern void setup_apic_nmi_watchdog (void); -extern void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason); +extern void disable_lapic_nmi_watchdog(void); +extern void enable_lapic_nmi_watchdog(void); +extern inline void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason); extern int APIC_init_uniprocessor (void); extern void disable_APIC_timer(void); extern void enable_APIC_timer(void); -extern struct pm_dev *apic_pm_register(pm_dev_t, unsigned long, pm_callback); -extern void apic_pm_unregister(struct pm_dev*); +#ifdef CONFIG_PM +extern struct sys_device device_lapic; +#endif extern int check_nmi_watchdog (void); diff -Nru a/include/asm-x86_64/apicdef.h b/include/asm-x86_64/apicdef.h --- a/include/asm-x86_64/apicdef.h Mon Jun 9 23:16:08 2003 +++ b/include/asm-x86_64/apicdef.h Mon Jun 9 23:16:08 2003 @@ -108,7 +108,7 @@ #define APIC_BASE (fix_to_virt(FIX_APIC_BASE)) -#define MAX_IO_APICS 8 +#define MAX_IO_APICS 16 /* * the local APIC register structure, memory mapped. Not terribly well diff -Nru a/include/asm-x86_64/bootsetup.h b/include/asm-x86_64/bootsetup.h --- a/include/asm-x86_64/bootsetup.h Mon Jun 9 23:16:16 2003 +++ b/include/asm-x86_64/bootsetup.h Mon Jun 9 23:16:16 2003 @@ -25,6 +25,7 @@ #define KERNEL_START (*(unsigned int *) (PARAM+0x214)) #define INITRD_START (*(unsigned int *) (PARAM+0x218)) #define INITRD_SIZE (*(unsigned int *) (PARAM+0x21c)) +#define EDID_INFO (*(struct edid_info *) (PARAM+0x440)) #define COMMAND_LINE saved_command_line #define COMMAND_LINE_SIZE 256 diff -Nru a/include/asm-x86_64/bug.h b/include/asm-x86_64/bug.h --- a/include/asm-x86_64/bug.h Mon Jun 9 23:16:19 2003 +++ b/include/asm-x86_64/bug.h Mon Jun 9 23:16:19 2003 @@ -18,7 +18,15 @@ #define BUG() \ asm volatile("ud2 ; .quad %c1 ; .short %c0" :: \ "i"(__LINE__), "i" (__stringify(KBUILD_BASENAME))) +#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0) #define PAGE_BUG(page) BUG() void out_of_line_bug(void); + +#define WARN_ON(condition) do { \ + if (unlikely((condition)!=0)) { \ + printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \ + dump_stack(); \ + } \ +} while (0) #endif diff -Nru a/include/asm-x86_64/cpufeature.h b/include/asm-x86_64/cpufeature.h --- a/include/asm-x86_64/cpufeature.h Mon Jun 9 23:16:13 2003 +++ b/include/asm-x86_64/cpufeature.h Mon Jun 9 23:16:13 2003 @@ -70,7 +70,7 @@ #define cpu_has_tsc 1 #define cpu_has_pae ___BUG___ #define cpu_has_pge 1 -#define cpu_has_apic 1 +#define cpu_has_apic boot_cpu_has(X86_FEATURE_APIC) #define cpu_has_mtrr 1 #define cpu_has_mmx 1 #define cpu_has_fxsr 1 diff -Nru a/include/asm-x86_64/proto.h b/include/asm-x86_64/proto.h --- a/include/asm-x86_64/proto.h Mon Jun 9 23:16:18 2003 +++ b/include/asm-x86_64/proto.h Mon Jun 9 23:16:18 2003 @@ -51,6 +51,10 @@ extern void swap_low_mappings(void); +extern void oops_begin(void); +extern void die(const char *,struct pt_regs *,long); +extern void __die(const char * str, struct pt_regs * regs, long err); + extern int map_syscall32(struct mm_struct *mm, unsigned long address); extern char *syscall32_page; diff -Nru a/include/asm-x86_64/smp.h b/include/asm-x86_64/smp.h --- a/include/asm-x86_64/smp.h Mon Jun 9 23:16:05 2003 +++ b/include/asm-x86_64/smp.h Mon Jun 9 23:16:05 2003 @@ -42,10 +42,11 @@ extern void smp_flush_tlb(void); extern void smp_message_irq(int cpl, void *dev_id, struct pt_regs *regs); extern void smp_send_reschedule(int cpu); -extern void smp_send_reschedule_all(void); extern void smp_invalidate_rcv(void); /* Process an NMI */ extern void (*mtrr_hook) (void); extern void zap_low_mappings(void); +void smp_stop_cpu(void); + #define SMP_TRAMPOLINE_BASE 0x6000 diff -Nru a/include/asm-x86_64/suspend.h b/include/asm-x86_64/suspend.h --- a/include/asm-x86_64/suspend.h Mon Jun 9 23:16:13 2003 +++ b/include/asm-x86_64/suspend.h Mon Jun 9 23:16:13 2003 @@ -41,7 +41,7 @@ #define loaddebug(thread,register) \ __asm__("movq %0,%%db" #register \ : /* no output */ \ - :"r" ((thread)->debugreg[register])) + :"r" ((thread)->debugreg##register)) extern void fix_processor_context(void); extern void do_magic(int resume); diff -Nru a/include/asm-x86_64/thread_info.h b/include/asm-x86_64/thread_info.h --- a/include/asm-x86_64/thread_info.h Mon Jun 9 23:16:15 2003 +++ b/include/asm-x86_64/thread_info.h Mon Jun 9 23:16:15 2003 @@ -73,7 +73,7 @@ } /* thread information allocation */ -#define alloc_thread_info() \ +#define alloc_thread_info(tsk) \ ((struct thread_info *) __get_free_pages(GFP_KERNEL,THREAD_ORDER)) #define free_thread_info(ti) free_pages((unsigned long) (ti), THREAD_ORDER) #define get_thread_info(ti) get_task_struct((ti)->task) diff -Nru a/include/asm-x86_64/uaccess.h b/include/asm-x86_64/uaccess.h --- a/include/asm-x86_64/uaccess.h Mon Jun 9 23:16:08 2003 +++ b/include/asm-x86_64/uaccess.h Mon Jun 9 23:16:08 2003 @@ -237,6 +237,7 @@ extern unsigned long copy_to_user(void *to, const void *from, unsigned len); extern unsigned long copy_from_user(void *to, const void *from, unsigned len); +extern unsigned long copy_in_user(void *to, const void *from, unsigned len); static inline int __copy_from_user(void *dst, const void *src, unsigned size) { @@ -293,6 +294,47 @@ asm("":::"memory"); __put_user_asm(1[(u64*)src],1+(u64*)dst,ret,"q","","ir",8); return ret; + default: + return copy_user_generic(dst,src,size); + } +} + + +static inline int __copy_in_user(void *dst, const void *src, unsigned size) +{ + if (!__builtin_constant_p(size)) + return copy_user_generic(dst,src,size); + int ret = 0; + switch (size) { + case 1: { + u8 tmp; + __get_user_asm(tmp,(u8 *)src,ret,"b","b","=q",1); + if (!ret) + __put_user_asm(tmp,(u8 *)dst,ret,"b","b","iq",1); + return ret; + } + case 2: { + u16 tmp; + __get_user_asm(tmp,(u16 *)src,ret,"w","w","=r",2); + if (!ret) + __put_user_asm(tmp,(u16 *)dst,ret,"w","w","ir",2); + return ret; + } + + case 4: { + u32 tmp; + __get_user_asm(tmp,(u32 *)src,ret,"l","k","=r",4); + if (!ret) + __put_user_asm(tmp,(u32 *)dst,ret,"l","k","ir",4); + return ret; + } + case 8: { + u64 tmp; + __get_user_asm(tmp,(u64 *)src,ret,"q","","=r",8); + if (!ret) + __put_user_asm(tmp,(u64 *)dst,ret,"q","","ir",8); + return ret; + } default: return copy_user_generic(dst,src,size); } diff -Nru a/include/linux/aio.h b/include/linux/aio.h --- a/include/linux/aio.h Mon Jun 9 23:16:05 2003 +++ b/include/linux/aio.h Mon Jun 9 23:16:05 2003 @@ -41,9 +41,9 @@ #define kiocbClearKicked(iocb) clear_bit(KIF_KICKED, &(iocb)->ki_flags) #define kiocbClearCancelled(iocb) clear_bit(KIF_CANCELLED, &(iocb)->ki_flags) -#define kiocbIsLocked(iocb) test_bit(0, &(iocb)->ki_flags) -#define kiocbIsKicked(iocb) test_bit(1, &(iocb)->ki_flags) -#define kiocbIsCancelled(iocb) test_bit(2, &(iocb)->ki_flags) +#define kiocbIsLocked(iocb) test_bit(KIF_LOCKED, &(iocb)->ki_flags) +#define kiocbIsKicked(iocb) test_bit(KIF_KICKED, &(iocb)->ki_flags) +#define kiocbIsCancelled(iocb) test_bit(KIF_CANCELLED, &(iocb)->ki_flags) struct kiocb { struct list_head ki_run_list; diff -Nru a/include/linux/atalk.h b/include/linux/atalk.h --- a/include/linux/atalk.h Mon Jun 9 23:16:17 2003 +++ b/include/linux/atalk.h Mon Jun 9 23:16:17 2003 @@ -196,7 +196,7 @@ extern void aarp_cleanup_module(void); #endif /* MODULE */ -#define at_sk(__sk) ((struct atalk_sock *)(__sk)->protinfo) +#define at_sk(__sk) ((struct atalk_sock *)(__sk)->sk_protinfo) extern struct sock *atalk_sockets; extern rwlock_t atalk_sockets_lock; diff -Nru a/include/linux/atmdev.h b/include/linux/atmdev.h --- a/include/linux/atmdev.h Mon Jun 9 23:16:17 2003 +++ b/include/linux/atmdev.h Mon Jun 9 23:16:17 2003 @@ -30,7 +30,7 @@ #define ATM_DS3_PCR (8000*12) /* DS3: 12 cells in a 125 usec time slot */ -#define atm_sk(__sk) ((struct atm_vcc *)(__sk)->protinfo) +#define atm_sk(__sk) ((struct atm_vcc *)(__sk)->sk_protinfo) #define ATM_SD(s) (atm_sk((s)->sk)) @@ -413,19 +413,20 @@ static inline void atm_force_charge(struct atm_vcc *vcc,int truesize) { - atomic_add(truesize, &vcc->sk->rmem_alloc); + atomic_add(truesize, &vcc->sk->sk_rmem_alloc); } static inline void atm_return(struct atm_vcc *vcc,int truesize) { - atomic_sub(truesize, &vcc->sk->rmem_alloc); + atomic_sub(truesize, &vcc->sk->sk_rmem_alloc); } static inline int atm_may_send(struct atm_vcc *vcc,unsigned int size) { - return (size + atomic_read(&vcc->sk->wmem_alloc)) < vcc->sk->sndbuf; + return (size + atomic_read(&vcc->sk->sk_wmem_alloc)) < + vcc->sk->sk_sndbuf; } diff -Nru a/include/linux/bio.h b/include/linux/bio.h --- a/include/linux/bio.h Mon Jun 9 23:16:16 2003 +++ b/include/linux/bio.h Mon Jun 9 23:16:16 2003 @@ -222,6 +222,7 @@ }; extern struct bio_pair *bio_split(struct bio *bi, mempool_t *pool, int first_sectors); +extern mempool_t *bio_split_pool; extern void bio_pair_release(struct bio_pair *dbio); extern struct bio *bio_alloc(int, int); diff -Nru a/include/linux/bitops.h b/include/linux/bitops.h --- a/include/linux/bitops.h Mon Jun 9 23:16:19 2003 +++ b/include/linux/bitops.h Mon Jun 9 23:16:19 2003 @@ -1,5 +1,6 @@ #ifndef _LINUX_BITOPS_H #define _LINUX_BITOPS_H +#include <asm/types.h> #include <asm/bitops.h> /* @@ -107,7 +108,25 @@ return (res & 0x0F) + ((res >> 4) & 0x0F); } -#include <asm/bitops.h> +static inline unsigned long generic_hweight64(u64 w) +{ +#if BITS_PER_LONG < 64 + return generic_hweight32((unsigned int)(w >> 32)) + + generic_hweight32((unsigned int)w); +#else + u64 res; + res = (w & 0x5555555555555555) + ((w >> 1) & 0x5555555555555555); + res = (res & 0x3333333333333333) + ((res >> 2) & 0x3333333333333333); + res = (res & 0x0F0F0F0F0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F0F0F0F0F); + res = (res & 0x00FF00FF00FF00FF) + ((res >> 8) & 0x00FF00FF00FF00FF); + res = (res & 0x0000FFFF0000FFFF) + ((res >> 16) & 0x0000FFFF0000FFFF); + return (res & 0x00000000FFFFFFFF) + ((res >> 32) & 0x00000000FFFFFFFF); +#endif +} +static inline unsigned long hweight_long(unsigned long w) +{ + return sizeof(w) == 4 ? generic_hweight32(w) : generic_hweight64(w); +} #endif diff -Nru a/include/linux/blkdev.h b/include/linux/blkdev.h --- a/include/linux/blkdev.h Mon Jun 9 23:16:08 2003 +++ b/include/linux/blkdev.h Mon Jun 9 23:16:08 2003 @@ -179,7 +179,8 @@ unsigned long *tag_map; /* bit map of free/busy tags */ struct list_head busy_list; /* fifo list of busy tags */ int busy; /* current depth */ - int max_depth; + int max_depth; /* what we will send to device */ + int real_max_depth; /* what the array can hold */ }; struct request_queue @@ -430,7 +431,6 @@ extern void blk_queue_max_segment_size(request_queue_t *, unsigned int); extern void blk_queue_hardsect_size(request_queue_t *, unsigned short); extern void blk_queue_segment_boundary(request_queue_t *, unsigned long); -extern void blk_queue_assign_lock(request_queue_t *, spinlock_t *); extern void blk_queue_prep_rq(request_queue_t *, prep_rq_fn *pfn); extern void blk_queue_merge_bvec(request_queue_t *, merge_bvec_fn *); extern void blk_queue_dma_alignment(request_queue_t *, int); @@ -452,10 +452,12 @@ extern void blk_queue_end_tag(request_queue_t *, struct request *); extern int blk_queue_init_tags(request_queue_t *, int); extern void blk_queue_free_tags(request_queue_t *); +extern int blk_queue_resize_tags(request_queue_t *, int); extern void blk_queue_invalidate_tags(request_queue_t *); extern void blk_congestion_wait(int rw, long timeout); extern void blk_rq_bio_prep(request_queue_t *, struct request *, struct bio *); +extern void blk_rq_prep_restart(struct request *); #define MAX_PHYS_SEGMENTS 128 #define MAX_HW_SEGMENTS 128 diff -Nru a/include/linux/compat_ioctl.h b/include/linux/compat_ioctl.h --- a/include/linux/compat_ioctl.h Mon Jun 9 23:16:19 2003 +++ b/include/linux/compat_ioctl.h Mon Jun 9 23:16:19 2003 @@ -1,5 +1,6 @@ /* List here explicitly which ioctl's are known to have - * compatible types passed or none at all... + * compatible types passed or none at all... Please include + * only stuff that is compatible on *all architectures*. */ /* Big T */ COMPATIBLE_IOCTL(TCGETA) @@ -354,6 +355,15 @@ COMPATIBLE_IOCTL(CDROM_LOCKDOOR) COMPATIBLE_IOCTL(CDROM_DEBUG) COMPATIBLE_IOCTL(CDROM_GET_CAPABILITY) +/* Ignore cdrom.h about these next 5 ioctls, they absolutely do + * not take a struct cdrom_read, instead they take a struct cdrom_msf + * which is compatible. + */ +COMPATIBLE_IOCTL(CDROMREADMODE2) +COMPATIBLE_IOCTL(CDROMREADMODE1) +COMPATIBLE_IOCTL(CDROMREADRAW) +COMPATIBLE_IOCTL(CDROMREADCOOKED) +COMPATIBLE_IOCTL(CDROMREADALL) /* DVD ioctls */ COMPATIBLE_IOCTL(DVD_READ_STRUCT) COMPATIBLE_IOCTL(DVD_WRITE_STRUCT) diff -Nru a/include/linux/cpu.h b/include/linux/cpu.h --- a/include/linux/cpu.h Mon Jun 9 23:16:08 2003 +++ b/include/linux/cpu.h Mon Jun 9 23:16:08 2003 @@ -31,6 +31,24 @@ extern int register_cpu(struct cpu *, int, struct node *); extern struct class cpu_class; +struct notifier_block; + +#ifdef CONFIG_SMP +/* Need to know about CPUs going up/down? */ +extern int register_cpu_notifier(struct notifier_block *nb); +extern void unregister_cpu_notifier(struct notifier_block *nb); + +int cpu_up(unsigned int cpu); +#else +static inline int register_cpu_notifier(struct notifier_block *nb) +{ + return 0; +} +static inline void unregister_cpu_notifier(struct notifier_block *nb) +{ +} +#endif /* CONFIG_SMP */ + /* Stop CPUs going up and down. */ extern struct semaphore cpucontrol; #endif /* _LINUX_CPU_H_ */ diff -Nru a/include/linux/cyclades.h b/include/linux/cyclades.h --- a/include/linux/cyclades.h Mon Jun 9 23:16:20 2003 +++ b/include/linux/cyclades.h Mon Jun 9 23:16:20 2003 @@ -588,8 +588,6 @@ int breakon; int breakoff; int blocked_open; /* # of blocked opens */ - long session; /* Session of opening process */ - long pgrp; /* pgrp of opening process */ unsigned char *xmit_buf; int xmit_head; int xmit_tail; @@ -599,7 +597,6 @@ unsigned long jiffies[3]; unsigned long rflush_count; struct termios normal_termios; - struct termios callout_termios; struct cyclades_monitor mon; struct cyclades_idle_stats idle_stats; struct cyclades_icount icount; diff -Nru a/include/linux/device-mapper.h b/include/linux/device-mapper.h --- a/include/linux/device-mapper.h Mon Jun 9 23:16:15 2003 +++ b/include/linux/device-mapper.h Mon Jun 9 23:16:15 2003 @@ -17,7 +17,8 @@ * In the constructor the target parameter will already have the * table, type, begin and len fields filled in. */ -typedef int (*dm_ctr_fn) (struct dm_target *target, int argc, char **argv); +typedef int (*dm_ctr_fn) (struct dm_target *target, + unsigned int argc, char **argv); /* * The destructor doesn't need to free the dm_target, just @@ -32,8 +33,12 @@ * > 0: simple remap complete */ typedef int (*dm_map_fn) (struct dm_target *ti, struct bio *bio); + +typedef void (*dm_suspend_fn) (struct dm_target *ti); +typedef void (*dm_resume_fn) (struct dm_target *ti); + typedef int (*dm_status_fn) (struct dm_target *ti, status_type_t status_type, - char *result, int maxlen); + char *result, unsigned int maxlen); void dm_error(const char *message); @@ -55,6 +60,8 @@ dm_ctr_fn ctr; dm_dtr_fn dtr; dm_map_fn map; + dm_suspend_fn suspend; + dm_resume_fn resume; dm_status_fn status; }; diff -Nru a/include/linux/device.h b/include/linux/device.h --- a/include/linux/device.h Mon Jun 9 23:16:18 2003 +++ b/include/linux/device.h Mon Jun 9 23:16:18 2003 @@ -3,21 +3,9 @@ * * Copyright (c) 2001-2003 Patrick Mochel <mochel@osdl.org> * - * This is a relatively simple centralized driver model. - * The data structures were mainly lifted directly from the PCI - * driver model. These are thought to be the common fields that - * are relevant to all device buses. + * This file is released under the GPLv2 * - * All the devices are arranged in a tree. All devices should - * have some sort of parent bus of whom they are children of. - * Devices should not be direct children of the system root. - * - * Device drivers should not directly call the device_* routines - * or access the contents of struct device directly. Instead, - * abstract that from the drivers and write bus-specific wrappers - * that do it for you. - * - * See Documentation/driver-model.txt for more information. + * See Documentation/driver-model/ for more information. */ #ifndef _DEVICE_H_ @@ -169,6 +157,8 @@ int (*hotplug)(struct class_device *dev, char **envp, int num_envp, char *buffer, int buffer_size); + + void (*release)(struct class_device *dev); }; extern int class_register(struct class *); @@ -312,6 +302,8 @@ extern void device_initialize(struct device * dev); extern int device_add(struct device * dev); extern void device_del(struct device * dev); +extern int device_for_each_child(struct device *, void *, + int (*fn)(struct device *, void *)); /* * Manual binding of a device to driver. See drivers/base/bus.c @@ -393,6 +385,8 @@ u32 num_resources; struct resource * resource; }; + +#define to_platform_device(x) container_of((x), struct platform_device, dev) extern int platform_device_register(struct platform_device *); extern void platform_device_unregister(struct platform_device *); diff -Nru a/include/linux/ethtool.h b/include/linux/ethtool.h --- a/include/linux/ethtool.h Mon Jun 9 23:16:08 2003 +++ b/include/linux/ethtool.h Mon Jun 9 23:16:08 2003 @@ -252,23 +252,23 @@ /* CMDs currently supported */ #define ETHTOOL_GSET 0x00000001 /* Get settings. */ -#define ETHTOOL_SSET 0x00000002 /* Set settings, privileged. */ +#define ETHTOOL_SSET 0x00000002 /* Set settings. */ #define ETHTOOL_GDRVINFO 0x00000003 /* Get driver info. */ -#define ETHTOOL_GREGS 0x00000004 /* Get NIC registers, privileged. */ +#define ETHTOOL_GREGS 0x00000004 /* Get NIC registers. */ #define ETHTOOL_GWOL 0x00000005 /* Get wake-on-lan options. */ -#define ETHTOOL_SWOL 0x00000006 /* Set wake-on-lan options, priv. */ +#define ETHTOOL_SWOL 0x00000006 /* Set wake-on-lan options. */ #define ETHTOOL_GMSGLVL 0x00000007 /* Get driver message level */ -#define ETHTOOL_SMSGLVL 0x00000008 /* Set driver msg level, priv. */ -#define ETHTOOL_NWAY_RST 0x00000009 /* Restart autonegotiation, priv. */ +#define ETHTOOL_SMSGLVL 0x00000008 /* Set driver msg level. */ +#define ETHTOOL_NWAY_RST 0x00000009 /* Restart autonegotiation. */ #define ETHTOOL_GLINK 0x0000000a /* Get link status (ethtool_value) */ #define ETHTOOL_GEEPROM 0x0000000b /* Get EEPROM data */ -#define ETHTOOL_SEEPROM 0x0000000c /* Set EEPROM data, priv. */ +#define ETHTOOL_SEEPROM 0x0000000c /* Set EEPROM data. */ #define ETHTOOL_GCOALESCE 0x0000000e /* Get coalesce config */ -#define ETHTOOL_SCOALESCE 0x0000000f /* Set coalesce config, priv. */ +#define ETHTOOL_SCOALESCE 0x0000000f /* Set coalesce config. */ #define ETHTOOL_GRINGPARAM 0x00000010 /* Get ring parameters */ -#define ETHTOOL_SRINGPARAM 0x00000011 /* Set ring parameters, priv. */ +#define ETHTOOL_SRINGPARAM 0x00000011 /* Set ring parameters. */ #define ETHTOOL_GPAUSEPARAM 0x00000012 /* Get pause parameters */ -#define ETHTOOL_SPAUSEPARAM 0x00000013 /* Set pause parameters, priv. */ +#define ETHTOOL_SPAUSEPARAM 0x00000013 /* Set pause parameters. */ #define ETHTOOL_GRXCSUM 0x00000014 /* Get RX hw csum enable (ethtool_value) */ #define ETHTOOL_SRXCSUM 0x00000015 /* Set RX hw csum enable (ethtool_value) */ #define ETHTOOL_GTXCSUM 0x00000016 /* Get TX hw csum enable (ethtool_value) */ @@ -276,8 +276,8 @@ #define ETHTOOL_GSG 0x00000018 /* Get scatter-gather enable * (ethtool_value) */ #define ETHTOOL_SSG 0x00000019 /* Set scatter-gather enable - * (ethtool_value), priv. */ -#define ETHTOOL_TEST 0x0000001a /* execute NIC self-test, priv. */ + * (ethtool_value). */ +#define ETHTOOL_TEST 0x0000001a /* execute NIC self-test. */ #define ETHTOOL_GSTRINGS 0x0000001b /* get specified string set */ #define ETHTOOL_PHYS_ID 0x0000001c /* identify the NIC */ #define ETHTOOL_GSTATS 0x0000001d /* get NIC-specific statistics */ @@ -299,6 +299,7 @@ #define SUPPORTED_MII (1 << 9) #define SUPPORTED_FIBRE (1 << 10) #define SUPPORTED_BNC (1 << 11) +#define SUPPORTED_10000baseT_Full (1 << 12) /* Indicates what features are advertised by the interface. */ #define ADVERTISED_10baseT_Half (1 << 0) @@ -313,6 +314,7 @@ #define ADVERTISED_MII (1 << 9) #define ADVERTISED_FIBRE (1 << 10) #define ADVERTISED_BNC (1 << 11) +#define ADVERTISED_10000baseT_Full (1 << 12) /* The following are all involved in forcing a particular link * mode for the device for setting things. When getting the @@ -320,10 +322,11 @@ * it was foced up into this mode or autonegotiated. */ -/* The forced speed, 10Mb, 100Mb, gigabit. */ +/* The forced speed, 10Mb, 100Mb, gigabit, 10GbE. */ #define SPEED_10 10 #define SPEED_100 100 #define SPEED_1000 1000 +#define SPEED_10000 10000 /* Duplex, half or full. */ #define DUPLEX_HALF 0x00 diff -Nru a/include/linux/fcdevice.h b/include/linux/fcdevice.h --- a/include/linux/fcdevice.h Mon Jun 9 23:16:09 2003 +++ b/include/linux/fcdevice.h Mon Jun 9 23:16:09 2003 @@ -33,11 +33,7 @@ extern int fc_rebuild_header(struct sk_buff *skb); extern unsigned short fc_type_trans(struct sk_buff *skb, struct net_device *dev); -extern struct net_device *init_fcdev(struct net_device *dev, int sizeof_priv); extern struct net_device *alloc_fcdev(int sizeof_priv); -extern int register_fcdev(struct net_device *dev); -extern void unregister_fcdev(struct net_device *dev); - #endif #endif /* _LINUX_FCDEVICE_H */ diff -Nru a/include/linux/fddidevice.h b/include/linux/fddidevice.h --- a/include/linux/fddidevice.h Mon Jun 9 23:16:10 2003 +++ b/include/linux/fddidevice.h Mon Jun 9 23:16:10 2003 @@ -34,7 +34,6 @@ extern int fddi_rebuild_header(struct sk_buff *skb); extern unsigned short fddi_type_trans(struct sk_buff *skb, struct net_device *dev); -extern struct net_device *init_fddidev(struct net_device *dev, int sizeof_priv); extern struct net_device *alloc_fddidev(int sizeof_priv); #endif diff -Nru a/include/linux/fs.h b/include/linux/fs.h --- a/include/linux/fs.h Mon Jun 9 23:16:08 2003 +++ b/include/linux/fs.h Mon Jun 9 23:16:08 2003 @@ -917,7 +917,6 @@ struct file_system_type { const char *name; - struct subsystem subsys; int fs_flags; struct super_block *(*get_sb) (struct file_system_type *, int, const char *, void *); @@ -1059,7 +1058,7 @@ extern void blk_run_queues(void); /* fs/char_dev.c */ -extern int alloc_chrdev_region(dev_t *, unsigned, char *); +extern int alloc_chrdev_region(dev_t *, unsigned, unsigned, char *); extern int register_chrdev_region(dev_t, unsigned, char *); extern int register_chrdev(unsigned int, const char *, struct file_operations *); diff -Nru a/include/linux/generic_serial.h b/include/linux/generic_serial.h --- a/include/linux/generic_serial.h Mon Jun 9 23:16:17 2003 +++ b/include/linux/generic_serial.h Mon Jun 9 23:16:17 2003 @@ -37,11 +37,8 @@ /* struct semaphore port_write_sem; */ int flags; struct termios normal_termios; - struct termios callout_termios; wait_queue_head_t open_wait; wait_queue_head_t close_wait; - long session; - long pgrp; int count; int blocked_open; struct tty_struct *tty; @@ -67,8 +64,6 @@ #define GS_TYPE_NORMAL 1 -#define GS_TYPE_CALLOUT 2 - #define GS_DEBUG_FLUSH 0x00000001 #define GS_DEBUG_BTR 0x00000002 diff -Nru a/include/linux/genhd.h b/include/linux/genhd.h --- a/include/linux/genhd.h Mon Jun 9 23:16:07 2003 +++ b/include/linux/genhd.h Mon Jun 9 23:16:07 2003 @@ -83,8 +83,6 @@ int major; /* major number of driver */ int first_minor; int minors; - int minor_shift; /* number of times minor is shifted to - get real minor */ char disk_name[16]; /* name of major driver */ struct hd_struct **part; /* [indexed by minor] */ struct block_device_operations *fops; @@ -160,16 +158,15 @@ #ifdef CONFIG_SMP static inline int init_disk_stats(struct gendisk *disk) { - disk->dkstats = kmalloc_percpu(sizeof (struct disk_stats), GFP_KERNEL); + disk->dkstats = alloc_percpu(struct disk_stats); if (!disk->dkstats) return 0; - disk_stat_set_all(disk, 0); return 1; } static inline void free_disk_stats(struct gendisk *disk) { - kfree_percpu(disk->dkstats); + free_percpu(disk->dkstats); } #else /* CONFIG_SMP */ static inline int init_disk_stats(struct gendisk *disk) diff -Nru a/include/linux/hayesesp.h b/include/linux/hayesesp.h --- a/include/linux/hayesesp.h Mon Jun 9 23:16:16 2003 +++ b/include/linux/hayesesp.h Mon Jun 9 23:16:16 2003 @@ -96,8 +96,6 @@ 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 */ unsigned char *xmit_buf; int xmit_head; int xmit_tail; @@ -105,7 +103,6 @@ struct work_struct tqueue; struct work_struct tqueue_hangup; struct termios normal_termios; - struct termios callout_termios; wait_queue_head_t open_wait; wait_queue_head_t close_wait; wait_queue_head_t delta_msr_wait; diff -Nru a/include/linux/hippidevice.h b/include/linux/hippidevice.h --- a/include/linux/hippidevice.h Mon Jun 9 23:16:19 2003 +++ b/include/linux/hippidevice.h Mon Jun 9 23:16:19 2003 @@ -49,12 +49,8 @@ extern int hippi_header_parse(struct sk_buff *skb, unsigned char *haddr); extern void hippi_net_init(void); -void hippi_setup(struct net_device *dev); -extern struct net_device *init_hippi_dev(struct net_device *dev, int sizeof_priv); extern struct net_device *alloc_hippi_dev(int sizeof_priv); -extern int register_hipdev(struct net_device *dev); -extern void unregister_hipdev(struct net_device *dev); #endif #endif /* _LINUX_HIPPIDEVICE_H */ diff -Nru a/include/linux/hugetlb.h b/include/linux/hugetlb.h --- a/include/linux/hugetlb.h Mon Jun 9 23:16:12 2003 +++ b/include/linux/hugetlb.h Mon Jun 9 23:16:12 2003 @@ -72,6 +72,12 @@ #endif /* !CONFIG_HUGETLB_PAGE */ #ifdef CONFIG_HUGETLBFS +struct hugetlbfs_config { + uid_t uid; + gid_t gid; + umode_t mode; +}; + extern struct file_operations hugetlbfs_file_operations; extern struct vm_operations_struct hugetlb_vm_ops; struct file *hugetlb_zero_setup(size_t); diff -Nru a/include/linux/i2c-id.h b/include/linux/i2c-id.h --- a/include/linux/i2c-id.h Mon Jun 9 23:16:06 2003 +++ b/include/linux/i2c-id.h Mon Jun 9 23:16:06 2003 @@ -98,6 +98,7 @@ #define I2C_DRIVERID_ZR36120 50 /* Zoran 36120 video encoder */ #define I2C_DRIVERID_24LC32A 51 /* Microchip 24LC32A 32k EEPROM */ #define I2C_DRIVERID_STM41T00 52 /* real time clock */ +#define I2C_DRIVERID_UDA1342 53 /* UDA1342 audio codec */ @@ -178,6 +179,7 @@ #define I2C_ALGO_MPC8XX 0x110000 /* MPC8xx PowerPC I2C algorithm */ #define I2C_ALGO_OCP 0x120000 /* IBM or otherwise On-chip I2C algorithm */ #define I2C_ALGO_BITHS 0x130000 /* enhanced bit style adapters */ +#define I2C_ALGO_OCP_IOP3XX 0x140000 /* XSCALE IOP3XX On-chip I2C alg */ #define I2C_ALGO_EXP 0x800000 /* experimental */ @@ -213,6 +215,9 @@ #define I2C_HW_B_FRODO 0x13 /* 2d3D, Inc. SA-1110 Development Board */ #define I2C_HW_B_OMAHA 0x14 /* Omaha I2C interface (ARM) */ #define I2C_HW_B_GUIDE 0x15 /* Guide bit-basher */ +#define I2C_HW_B_IXP2000 0x16 /* GPIO on IXP2000 systems */ +#define I2C_HW_B_IXP425 0x17 /* GPIO on IXP425 systems */ +#define I2C_HW_B_S3VIA 0x18 /* S3Via ProSavage adapter */ /* --- PCF 8584 based algorithms */ #define I2C_HW_P_LP 0x00 /* Parallel port interface */ @@ -234,6 +239,8 @@ /* --- PowerPC on-chip adapters */ #define I2C_HW_OCP 0x00 /* IBM on-chip I2C adapter */ +/* --- XSCALE on-chip adapters */ +#define I2C_HW_IOP321 0x00 /* --- SMBus only adapters */ #define I2C_HW_SMBUS_PIIX4 0x00 diff -Nru a/include/linux/ide.h b/include/linux/ide.h --- a/include/linux/ide.h Mon Jun 9 23:16:10 2003 +++ b/include/linux/ide.h Mon Jun 9 23:16:10 2003 @@ -720,7 +720,7 @@ unsigned doorlocking : 1; /* for removable only: door lock/unlock works */ unsigned autotune : 3; /* 1=autotune, 2=noautotune, 3=biostimings, 0=default */ - unsigned remap_0_to_1 : 2; /* 0=remap if ezdrive, 1=remap, 2=noremap */ + unsigned remap_0_to_1 : 1; /* 0=noremap, 1=remap 0->1 (for EZDrive) */ unsigned ata_flash : 1; /* 1=present, 0=default */ unsigned blocked : 1; /* 1=powermanagment told us not to do anything, so sleep nicely */ unsigned vdma : 1; /* 1=doing PIO over DMA 0=doing normal DMA */ @@ -817,33 +817,25 @@ * * temporarily mapping a (possible) highmem bio for PIO transfer */ -#define ide_rq_offset(rq) \ - (((rq)->hard_cur_sectors - (rq)->current_nr_sectors) << 9) -/* - * taskfiles really should use hard_cur_sectors as well! - */ -#define task_rq_offset(rq) \ - (((rq)->nr_sectors - (rq)->current_nr_sectors) * SECTOR_SIZE) - -static inline void *ide_map_buffer(struct request *rq, unsigned long *flags) +static inline void *task_map_rq(struct request *rq, unsigned long *flags) { /* * fs request */ - if (rq->bio) - return bio_kmap_irq(rq->bio, flags) + ide_rq_offset(rq); + if (rq->cbio) + return rq_map_buffer(rq, flags); /* * task request */ - return rq->buffer + task_rq_offset(rq); + return rq->buffer + blk_rq_offset(rq); } -static inline void ide_unmap_buffer(struct request *rq, char *buffer, unsigned long *flags) +static inline void task_unmap_rq(struct request *rq, char *buffer, unsigned long *flags) { - if (rq->bio) - bio_kunmap_irq(buffer, flags); + if (rq->cbio) + rq_unmap_buffer(buffer, flags); } #define IDE_CHIPSET_PCI_MASK \ @@ -1115,7 +1107,6 @@ #ifdef CONFIG_PROC_FS extern void proc_ide_create(void); extern void proc_ide_destroy(void); -extern void recreate_proc_ide_device(ide_hwif_t *, ide_drive_t *); extern void destroy_proc_ide_device(ide_hwif_t *, ide_drive_t *); extern void destroy_proc_ide_drives(ide_hwif_t *); extern void create_proc_ide_interfaces(void); @@ -1418,6 +1409,31 @@ extern void atapi_output_bytes(ide_drive_t *, void *, u32); extern void taskfile_input_data(ide_drive_t *, void *, u32); extern void taskfile_output_data(ide_drive_t *, void *, u32); + +#define IDE_PIO_IN 0 +#define IDE_PIO_OUT 1 + +static inline void task_sectors(ide_drive_t *drive, struct request *rq, + unsigned nsect, int rw) +{ + unsigned long flags; + char *buf; + + buf = task_map_rq(rq, &flags); + + /* + * IRQ can happen instantly after reading/writing + * last sector of the datablock. + */ + process_that_request_first(rq, nsect); + + if (rw == IDE_PIO_OUT) + taskfile_output_data(drive, buf, nsect * SECTOR_WORDS); + else + taskfile_input_data(drive, buf, nsect * SECTOR_WORDS); + + task_unmap_rq(rq, buf, &flags); +} extern int drive_is_ready(ide_drive_t *); extern int wait_for_ready(ide_drive_t *, int /* timeout */); diff -Nru a/include/linux/if_arp.h b/include/linux/if_arp.h --- a/include/linux/if_arp.h Mon Jun 9 23:16:17 2003 +++ b/include/linux/if_arp.h Mon Jun 9 23:16:17 2003 @@ -60,7 +60,7 @@ #define ARPHRD_RAWHDLC 518 /* Raw HDLC */ #define ARPHRD_TUNNEL 768 /* IPIP tunnel */ -#define ARPHRD_TUNNEL6 769 /* IPIP6 tunnel */ +#define ARPHRD_TUNNEL6 769 /* IP6IP6 tunnel */ #define ARPHRD_FRAD 770 /* Frame Relay Access Device */ #define ARPHRD_SKIP 771 /* SKIP vif */ #define ARPHRD_LOOPBACK 772 /* Loopback device */ diff -Nru a/include/linux/if_ec.h b/include/linux/if_ec.h --- a/include/linux/if_ec.h Mon Jun 9 23:16:07 2003 +++ b/include/linux/if_ec.h Mon Jun 9 23:16:07 2003 @@ -56,7 +56,7 @@ unsigned short num; }; -#define ec_sk(__sk) ((struct econet_opt *)(__sk)->protinfo) +#define ec_sk(__sk) ((struct econet_opt *)(__sk)->sk_protinfo) struct ec_device { diff -Nru a/include/linux/if_pppox.h b/include/linux/if_pppox.h --- a/include/linux/if_pppox.h Mon Jun 9 23:16:08 2003 +++ b/include/linux/if_pppox.h Mon Jun 9 23:16:08 2003 @@ -132,7 +132,7 @@ #define pppoe_pa proto.pppoe.pa #define pppoe_relay proto.pppoe.relay -#define pppox_sk(__sk) ((struct pppox_opt *)(__sk)->protinfo) +#define pppox_sk(__sk) ((struct pppox_opt *)(__sk)->sk_protinfo) struct module; diff -Nru a/include/linux/if_wanpipe.h b/include/linux/if_wanpipe.h --- a/include/linux/if_wanpipe.h Mon Jun 9 23:16:19 2003 +++ b/include/linux/if_wanpipe.h Mon Jun 9 23:16:19 2003 @@ -34,7 +34,7 @@ typedef struct { unsigned char free; - unsigned char sk_state; + unsigned char state_sk; int rcvbuf; int sndbuf; int rmem; @@ -117,7 +117,7 @@ unsigned short num; }; -#define wp_sk(__sk) ((struct wanpipe_opt *)(__sk)->protinfo) +#define wp_sk(__sk) ((struct wanpipe_opt *)(__sk)->sk_protinfo) #endif diff -Nru a/include/linux/init_task.h b/include/linux/init_task.h --- a/include/linux/init_task.h Mon Jun 9 23:16:07 2003 +++ b/include/linux/init_task.h Mon Jun 9 23:16:07 2003 @@ -45,7 +45,9 @@ #define INIT_SIGNALS(sig) { \ .count = ATOMIC_INIT(1), \ - .shared_pending = { NULL, &sig.shared_pending.head, {{0}}}, \ + .shared_pending = { \ + .list = LIST_HEAD_INIT(sig.shared_pending.list), \ + .signal = {{0}}}, \ } #define INIT_SIGHAND(sighand) { \ @@ -97,9 +99,11 @@ .files = &init_files, \ .signal = &init_signals, \ .sighand = &init_sighand, \ - .pending = { NULL, &tsk.pending.head, {{0}}}, \ + .pending = { \ + .list = LIST_HEAD_INIT(tsk.pending.list), \ + .signal = {{0}}}, \ .blocked = {{0}}, \ - .posix_timers = LIST_HEAD_INIT(tsk.posix_timers), \ + .posix_timers = LIST_HEAD_INIT(tsk.posix_timers), \ .alloc_lock = SPIN_LOCK_UNLOCKED, \ .proc_lock = SPIN_LOCK_UNLOCKED, \ .switch_lock = SPIN_LOCK_UNLOCKED, \ diff -Nru a/include/linux/ip6_tunnel.h b/include/linux/ip6_tunnel.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/ip6_tunnel.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,32 @@ +/* + * $Id$ + */ + +#ifndef _IP6_TUNNEL_H +#define _IP6_TUNNEL_H + +#define IPV6_TLV_TNL_ENCAP_LIMIT 4 +#define IPV6_DEFAULT_TNL_ENCAP_LIMIT 4 + +/* don't add encapsulation limit if one isn't present in inner packet */ +#define IP6_TNL_F_IGN_ENCAP_LIMIT 0x1 +/* copy the traffic class field from the inner packet */ +#define IP6_TNL_F_USE_ORIG_TCLASS 0x2 +/* copy the flowlabel from the inner packet */ +#define IP6_TNL_F_USE_ORIG_FLOWLABEL 0x4 +/* being used for Mobile IPv6 */ +#define IP6_TNL_F_MIP6_DEV 0x8 + +struct ip6_tnl_parm { + char name[IFNAMSIZ]; /* name of tunnel device */ + int link; /* ifindex of underlying L2 interface */ + __u8 proto; /* tunnel protocol */ + __u8 encap_limit; /* encapsulation limit for tunnel */ + __u8 hop_limit; /* hop limit for tunnel */ + __u32 flowinfo; /* traffic class and flowlabel for tunnel */ + __u32 flags; /* tunnel flags */ + struct in6_addr laddr; /* local tunnel end-point address */ + struct in6_addr raddr; /* remote tunnel end-point address */ +}; + +#endif diff -Nru a/include/linux/ipv6.h b/include/linux/ipv6.h --- a/include/linux/ipv6.h Mon Jun 9 23:16:15 2003 +++ b/include/linux/ipv6.h Mon Jun 9 23:16:15 2003 @@ -229,7 +229,7 @@ #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) #define __ipv6_only_sock(sk) (inet6_sk(sk)->ipv6only) -#define ipv6_only_sock(sk) ((sk)->family == PF_INET6 && __ipv6_only_sock(sk)) +#define ipv6_only_sock(sk) ((sk)->sk_family == PF_INET6 && __ipv6_only_sock(sk)) #else #define __ipv6_only_sock(sk) 0 #define ipv6_only_sock(sk) 0 diff -Nru a/include/linux/irq.h b/include/linux/irq.h --- a/include/linux/irq.h Mon Jun 9 23:16:10 2003 +++ b/include/linux/irq.h Mon Jun 9 23:16:10 2003 @@ -61,6 +61,8 @@ hw_irq_controller *handler; struct irqaction *action; /* IRQ action list */ unsigned int depth; /* nested irq disables */ + unsigned int irq_count; /* For detecting broken interrupts */ + unsigned int irqs_unhandled; spinlock_t lock; } ____cacheline_aligned irq_desc_t; diff -Nru a/include/linux/isdn.h b/include/linux/isdn.h --- a/include/linux/isdn.h Mon Jun 9 23:16:19 2003 +++ b/include/linux/isdn.h Mon Jun 9 23:16:19 2003 @@ -250,8 +250,6 @@ #define ISDN_ASYNC_SPLIT_TERMIOS 0x0008 /* Sep. termios for dialin/out */ #define ISDN_SERIAL_XMIT_SIZE 1024 /* Default bufsize for write */ #define ISDN_SERIAL_XMIT_MAX 4000 /* Maximum bufsize for write */ -#define ISDN_SERIAL_TYPE_NORMAL 1 -#define ISDN_SERIAL_TYPE_CALLOUT 2 #ifdef CONFIG_ISDN_AUDIO /* For using sk_buffs with audio we need some private variables @@ -301,8 +299,6 @@ 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 online; /* 1 = B-Channel is up, drop data */ /* 2 = B-Channel is up, deliver d.*/ int dialing; /* Dial in progress or ATA */ @@ -348,7 +344,6 @@ struct timer_list connect_timer; /* waiting for CONNECT */ struct timer_list read_timer; /* read incoming data */ struct termios normal_termios; /* For saving termios structs */ - struct termios callout_termios; wait_queue_head_t open_wait, close_wait; struct semaphore write_sem; } modem_info; diff -Nru a/include/linux/isicom.h b/include/linux/isicom.h --- a/include/linux/isicom.h Mon Jun 9 23:16:10 2003 +++ b/include/linux/isicom.h Mon Jun 9 23:16:10 2003 @@ -148,8 +148,6 @@ unsigned short channel; unsigned short status; unsigned short closing_wait; - long session; - long pgrp; struct isi_board * card; struct tty_struct * tty; wait_queue_head_t close_wait; @@ -161,7 +159,6 @@ int xmit_tail; int xmit_cnt; struct termios normal_termios; - struct termios callout_termios; }; diff -Nru a/include/linux/istallion.h b/include/linux/istallion.h --- a/include/linux/istallion.h Mon Jun 9 23:16:08 2003 +++ b/include/linux/istallion.h Mon Jun 9 23:16:08 2003 @@ -66,8 +66,6 @@ int rc; int argsize; void *argp; - long session; - long pgrp; unsigned int rxmarkmsk; struct tty_struct *tty; #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) @@ -81,7 +79,6 @@ #endif struct work_struct tqhangup; struct termios normaltermios; - struct termios callouttermios; asysigs_t asig; unsigned long addr; unsigned long rxoffset; diff -Nru a/include/linux/jffs2.h b/include/linux/jffs2.h --- a/include/linux/jffs2.h Mon Jun 9 23:16:17 2003 +++ b/include/linux/jffs2.h Mon Jun 9 23:16:17 2003 @@ -8,19 +8,23 @@ * For licensing information, see the file 'LICENCE' in the * jffs2 directory. * - * $Id: jffs2.h,v 1.25 2002/08/20 21:37:27 dwmw2 Exp $ + * $Id: jffs2.h,v 1.30 2003/02/15 00:15:22 dwmw2 Exp $ * */ #ifndef __LINUX_JFFS2_H__ #define __LINUX_JFFS2_H__ +/* You must include something which defines the C99 uintXX_t types. + We don't do it from here because this file is used in too many + different environments. */ + #define JFFS2_SUPER_MAGIC 0x72b6 /* Values we may expect to find in the 'magic' field */ #define JFFS2_OLD_MAGIC_BITMASK 0x1984 #define JFFS2_MAGIC_BITMASK 0x1985 -#define KSAMTIB_CIGAM_2SFFJ 0x5981 /* For detecting wrong-endian fs */ +#define KSAMTIB_CIGAM_2SFFJ 0x8519 /* For detecting wrong-endian fs */ #define JFFS2_EMPTY_BITMASK 0xffff #define JFFS2_DIRTY_BITMASK 0x0000 @@ -76,29 +80,42 @@ } __attribute__((packed)) jint32_t; typedef struct { + uint32_t m; +} __attribute__((packed)) jmode_t; + +typedef struct { uint16_t v16; } __attribute__((packed)) jint16_t; #define JFFS2_NATIVE_ENDIAN +/* Note we handle mode bits conversion from JFFS2 (i.e. Linux) to/from + whatever OS we're actually running on here too. */ + #if defined(JFFS2_NATIVE_ENDIAN) #define cpu_to_je16(x) ((jint16_t){x}) #define cpu_to_je32(x) ((jint32_t){x}) +#define cpu_to_jemode(x) ((jmode_t){os_to_jffs2_mode(x)}) #define je16_to_cpu(x) ((x).v16) #define je32_to_cpu(x) ((x).v32) +#define jemode_to_cpu(x) (jffs2_to_os_mode((x).m)) #elif defined(JFFS2_BIG_ENDIAN) #define cpu_to_je16(x) ((jint16_t){cpu_to_be16(x)}) #define cpu_to_je32(x) ((jint32_t){cpu_to_be32(x)}) +#define cpu_to_jemode(x) ((jmode_t){cpu_to_be32(os_to_jffs2_mode(x))}) #define je16_to_cpu(x) (be16_to_cpu(x.v16)) #define je32_to_cpu(x) (be32_to_cpu(x.v32)) +#define jemode_to_cpu(x) (be32_to_cpu(jffs2_to_os_mode((x).m))) #elif defined(JFFS2_LITTLE_ENDIAN) #define cpu_to_je16(x) ((jint16_t){cpu_to_le16(x)}) #define cpu_to_je32(x) ((jint32_t){cpu_to_le32(x)}) +#define cpu_to_jemode(x) ((jmode_t){cpu_to_le32(os_to_jffs2_mode(x))}) #define je16_to_cpu(x) (le16_to_cpu(x.v16)) #define je32_to_cpu(x) (le32_to_cpu(x.v32)) +#define jemode_to_cpu(x) (le32_to_cpu(jffs2_to_os_mode((x).m))) #else #error wibble #endif @@ -144,7 +161,7 @@ jint32_t hdr_crc; jint32_t ino; /* Inode number. */ jint32_t version; /* Version number. */ - jint32_t mode; /* The file's type or mode. */ + jmode_t mode; /* The file's type or mode. */ jint16_t uid; /* The file's owner. */ jint16_t gid; /* The file's group. */ jint32_t isize; /* Total resultant size of this inode (used for truncations) */ @@ -159,7 +176,7 @@ jint16_t flags; /* See JFFS2_INO_FLAG_* */ jint32_t data_crc; /* CRC for the (compressed) data. */ jint32_t node_crc; /* CRC for the raw inode (excluding data) */ -// uint8_t data[dsize]; + uint8_t data[0]; } __attribute__((packed)); union jffs2_node_union { diff -Nru a/include/linux/jffs2_fs_sb.h b/include/linux/jffs2_fs_sb.h --- a/include/linux/jffs2_fs_sb.h Mon Jun 9 23:16:05 2003 +++ b/include/linux/jffs2_fs_sb.h Mon Jun 9 23:16:05 2003 @@ -1,4 +1,4 @@ -/* $Id: jffs2_fs_sb.h,v 1.35 2002/11/12 09:42:18 dwmw2 Exp $ */ +/* $Id: jffs2_fs_sb.h,v 1.37 2003/01/17 16:04:44 dwmw2 Exp $ */ #ifndef _JFFS2_FS_SB #define _JFFS2_FS_SB @@ -8,6 +8,8 @@ #include <linux/workqueue.h> #include <linux/completion.h> #include <asm/semaphore.h> +#include <linux/timer.h> +#include <linux/wait.h> #include <linux/list.h> #define JFFS2_SB_FLAG_RO 1 @@ -73,6 +75,7 @@ against erase completion handler */ wait_queue_head_t erase_wait; /* For waiting for erases to complete */ + wait_queue_head_t inocache_wq; struct jffs2_inode_cache **inocache_list; spinlock_t inocache_lock; diff -Nru a/include/linux/kernel.h b/include/linux/kernel.h --- a/include/linux/kernel.h Mon Jun 9 23:16:05 2003 +++ b/include/linux/kernel.h Mon Jun 9 23:16:05 2003 @@ -228,14 +228,6 @@ char _f[20-2*sizeof(long)-sizeof(int)]; /* Padding: libc5 uses this.. */ }; -#define BUG_ON(condition) do { if (unlikely((condition)!=0)) BUG(); } while(0) -#define WARN_ON(condition) do { \ - if (unlikely((condition)!=0)) { \ - printk("Badness in %s at %s:%d\n", __FUNCTION__, __FILE__, __LINE__); \ - dump_stack(); \ - } \ -} while (0) - extern void BUILD_BUG(void); #define BUILD_BUG_ON(condition) do { if (condition) BUILD_BUG(); } while(0) diff -Nru a/include/linux/kobject.h b/include/linux/kobject.h --- a/include/linux/kobject.h Mon Jun 9 23:16:05 2003 +++ b/include/linux/kobject.h Mon Jun 9 23:16:05 2003 @@ -1,6 +1,15 @@ /* * kobject.h - generic kernel object infrastructure. * + * Copyright (c) 2002-2003 Patrick Mochel + * Copyright (c) 2002-2003 Open Source Development Labs + * + * This file is released under the GPLv2. + * + * + * Please read Documentation/kobject.txt before using the kobject + * interface, ESPECIALLY the parts about reference counts and object + * destructors. */ #if defined(__KERNEL__) && !defined(_KOBJECT_H_) diff -Nru a/include/linux/list.h b/include/linux/list.h --- a/include/linux/list.h Mon Jun 9 23:16:13 2003 +++ b/include/linux/list.h Mon Jun 9 23:16:13 2003 @@ -443,17 +443,50 @@ *(n->pprev) = n; } +static __inline__ void hlist_add_after(struct hlist_node *n, + struct hlist_node *next) +{ + next->next = n->next; + *(next->pprev) = n; + n->next = next; +} + #define hlist_entry(ptr, type, member) container_of(ptr,type,member) /* Cannot easily do prefetch unfortunately */ #define hlist_for_each(pos, head) \ - for (pos = (head)->first; pos; \ + for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \ pos = pos->next) #define hlist_for_each_safe(pos, n, head) \ for (pos = (head)->first; n = pos ? pos->next : 0, pos; \ pos = n) +/** + * hlist_for_each_entry - iterate over list of given type + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry(tpos, pos, head, member) \ + for (pos = (head)->first; \ + pos && ({ prefetch(pos->next); 1;}) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) +/** + * hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry + * @tpos: the type * to use as a loop counter. + * @pos: the &struct hlist_node to use as a loop counter. + * @n: another &struct hlist_node to use as temporary storage + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + */ +#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ + for (pos = (head)->first; \ + pos && ({ n = pos->next; 1; }) && \ + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \ + pos = n) #else #warning "don't include kernel headers in userspace" #endif /* __KERNEL__ */ diff -Nru a/include/linux/matroxfb.h b/include/linux/matroxfb.h --- a/include/linux/matroxfb.h Mon Jun 9 23:16:06 2003 +++ b/include/linux/matroxfb.h Mon Jun 9 23:16:06 2003 @@ -3,6 +3,7 @@ #include <asm/ioctl.h> #include <asm/types.h> +#include <linux/videodev2.h> struct matroxioc_output_mode { __u32 output; /* which output */ @@ -29,6 +30,14 @@ #define MATROXFB_GET_AVAILABLE_OUTPUTS _IOR('n',0xF9,sizeof(__u32)) /* which outputs exist on this framebuffer */ #define MATROXFB_GET_ALL_OUTPUTS _IOR('n',0xFB,sizeof(__u32)) + +enum matroxfb_ctrl_id { + MATROXFB_CID_TESTOUT = V4L2_CID_PRIVATE_BASE, + MATROXFB_CID_DEFLICKER, + MATROXFB_CID_LAST +}; + +#define FBIO_WAITFORVSYNC _IOW('F', 0x20, u_int32_t) #endif diff -Nru a/include/linux/mmzone.h b/include/linux/mmzone.h --- a/include/linux/mmzone.h Mon Jun 9 23:16:13 2003 +++ b/include/linux/mmzone.h Mon Jun 9 23:16:13 2003 @@ -249,13 +249,32 @@ #define for_each_zone(zone) \ for (zone = pgdat_list->node_zones; zone; zone = next_zone(zone)) +/** + * is_highmem - helper function to quickly check if a struct zone is a + * highmem zone or not. This is an attempt to keep references + * to ZONE_{DMA/NORMAL/HIGHMEM/etc} in general code to a minimum. + * @zone - pointer to struct zone variable + */ +static inline int is_highmem(struct zone *zone) +{ + return (zone - zone->zone_pgdat->node_zones == ZONE_HIGHMEM); +} + +/* These two functions are used to setup the per zone pages min values */ +struct ctl_table; +struct file; +int min_free_kbytes_sysctl_handler(struct ctl_table *, int, struct file *, + void *, size_t *); +extern void setup_per_zone_pages_min(void); + + #ifdef CONFIG_NUMA #define MAX_NR_MEMBLKS BITS_PER_LONG /* Max number of Memory Blocks */ #else /* !CONFIG_NUMA */ #define MAX_NR_MEMBLKS 1 #endif /* CONFIG_NUMA */ -#include <asm/topology.h> +#include <linux/topology.h> /* Returns the number of the current Node. */ #define numa_node_id() (cpu_to_node(smp_processor_id())) diff -Nru a/include/linux/module.h b/include/linux/module.h --- a/include/linux/module.h Mon Jun 9 23:16:16 2003 +++ b/include/linux/module.h Mon Jun 9 23:16:16 2003 @@ -247,6 +247,9 @@ char *strtab; #endif + /* Per-cpu data. */ + void *percpu; + /* The command line arguments (may be mangled). People like keeping pointers to this stuff */ char *args; @@ -263,6 +266,13 @@ /* Is this address in a module? */ struct module *module_text_address(unsigned long addr); +/* Returns module and fills in value, defined and namebuf, or NULL if + symnum out of range. */ +struct module *module_get_kallsym(unsigned int symnum, + unsigned long *value, + char *type, + char namebuf[128]); +int is_exported(const char *name, const struct module *mod); #ifdef CONFIG_MODULE_UNLOAD unsigned int module_refcount(struct module *mod); @@ -406,6 +416,19 @@ char **modname) { return NULL; +} + +static inline struct module *module_get_kallsym(unsigned int symnum, + unsigned long *value, + char *type, + char namebuf[128]) +{ + return NULL; +} + +static inline int is_exported(const char *name, const struct module *mod) +{ + return 0; } static inline int register_module_notifier(struct notifier_block * nb) diff -Nru a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h --- a/include/linux/msdos_fs.h Mon Jun 9 23:16:16 2003 +++ b/include/linux/msdos_fs.h Mon Jun 9 23:16:16 2003 @@ -27,8 +27,6 @@ #define MSDOS_SUPER_MAGIC 0x4d44 /* MD */ -#define FAT_CACHE 8 /* FAT cache size */ - #define ATTR_NONE 0 /* no attribute bits */ #define ATTR_RO 1 /* read-only */ #define ATTR_HIDDEN 2 /* hidden */ @@ -178,7 +176,7 @@ struct vfat_slot_info { int long_slots; /* number of long slots in filename */ loff_t longname_offset; /* dir offset for longname start */ - int ino; /* ino for the file */ + loff_t i_pos; /* on-disk position of directory entry */ }; /* Convert attribute bits and a mask to the UNIX mode. */ @@ -204,14 +202,6 @@ return container_of(inode, struct msdos_inode_info, vfs_inode); } -struct fat_cache { - struct super_block *sb; /* fs in question. NULL means unused */ - int start_cluster; /* first cluster of the chain. */ - int file_cluster; /* cluster number in the file. */ - int disk_cluster; /* cluster number on disk. */ - struct fat_cache *next; /* next cache entry */ -}; - static inline void fat16_towchar(wchar_t *dst, const __u8 *src, size_t len) { #ifdef __BIG_ENDIAN @@ -241,13 +231,12 @@ /* fat/cache.c */ extern int fat_access(struct super_block *sb, int nr, int new_value); extern int __fat_access(struct super_block *sb, int nr, int new_value); -extern int fat_bmap(struct inode *inode, int sector); -extern void fat_cache_init(void); +extern int fat_bmap(struct inode *inode, sector_t sector, sector_t *phys); +extern void fat_cache_init(struct super_block *sb); extern void fat_cache_lookup(struct inode *inode, int cluster, int *f_clu, int *d_clu); extern void fat_cache_add(struct inode *inode, int f_clu, int d_clu); extern void fat_cache_inval_inode(struct inode *inode); -extern void fat_cache_inval_dev(struct super_block *sb); extern int fat_free(struct inode *inode, int skip); /* fat/dir.c */ @@ -259,7 +248,7 @@ unsigned int cmd, unsigned long arg); extern int fat_dir_empty(struct inode *dir); extern int fat_add_entries(struct inode *dir, int slots, struct buffer_head **bh, - struct msdos_dir_entry **de, int *ino); + struct msdos_dir_entry **de, loff_t *i_pos); extern int fat_new_dir(struct inode *dir, struct inode *parent, int is_vfat); /* fat/file.c */ @@ -271,11 +260,11 @@ /* fat/inode.c */ extern void fat_hash_init(void); -extern void fat_attach(struct inode *inode, int i_pos); +extern void fat_attach(struct inode *inode, loff_t i_pos); extern void fat_detach(struct inode *inode); -extern struct inode *fat_iget(struct super_block *sb, int i_pos); +extern struct inode *fat_iget(struct super_block *sb, loff_t i_pos); extern struct inode *fat_build_inode(struct super_block *sb, - struct msdos_dir_entry *de, int ino, int *res); + struct msdos_dir_entry *de, loff_t i_pos, int *res); extern void fat_delete_inode(struct inode *inode); extern void fat_clear_inode(struct inode *inode); extern void fat_put_super(struct super_block *sb); @@ -295,26 +284,27 @@ extern int date_dos2unix(unsigned short time, unsigned short date); extern void fat_date_unix2dos(int unix_date, unsigned short *time, unsigned short *date); -extern int fat__get_entry(struct inode *dir, loff_t *pos, struct buffer_head **bh, - struct msdos_dir_entry **de, int *ino); +extern int fat__get_entry(struct inode *dir, loff_t *pos, + struct buffer_head **bh, + struct msdos_dir_entry **de, loff_t *i_pos); static __inline__ int fat_get_entry(struct inode *dir, loff_t *pos, struct buffer_head **bh, - struct msdos_dir_entry **de, int *ino) + struct msdos_dir_entry **de, loff_t *i_pos) { /* Fast stuff first */ if (*bh && *de && (*de - (struct msdos_dir_entry *)(*bh)->b_data) < MSDOS_SB(dir->i_sb)->dir_per_block - 1) { *pos += sizeof(struct msdos_dir_entry); (*de)++; - (*ino)++; + (*i_pos)++; return 0; } - return fat__get_entry(dir,pos,bh,de,ino); + return fat__get_entry(dir, pos, bh, de, i_pos); } extern int fat_subdirs(struct inode *dir); extern int fat_scan(struct inode *dir, const char *name, struct buffer_head **res_bh, - struct msdos_dir_entry **res_de, int *ino); + struct msdos_dir_entry **res_de, loff_t *i_pos); /* msdos/namei.c - these are for Umsdos */ extern struct dentry *msdos_lookup(struct inode *dir, struct dentry *); diff -Nru a/include/linux/msdos_fs_i.h b/include/linux/msdos_fs_i.h --- a/include/linux/msdos_fs_i.h Mon Jun 9 23:16:19 2003 +++ b/include/linux/msdos_fs_i.h Mon Jun 9 23:16:19 2003 @@ -8,12 +8,16 @@ */ struct msdos_inode_info { + /* cache of lastest accessed cluster */ + int file_cluster; /* cluster number in the file. */ + int disk_cluster; /* cluster number on disk. */ + loff_t mmu_private; int i_start; /* first cluster or 0 */ int i_logstart; /* logical first cluster */ int i_attrs; /* unused attribute bits */ int i_ctime_ms; /* unused change time in milliseconds */ - int i_location; /* on-disk position of directory entry or 0 */ + loff_t i_pos; /* on-disk position of directory entry or 0 */ struct list_head i_fat_hash; /* hash by i_location */ struct inode vfs_inode; }; diff -Nru a/include/linux/msdos_fs_sb.h b/include/linux/msdos_fs_sb.h --- a/include/linux/msdos_fs_sb.h Mon Jun 9 23:16:12 2003 +++ b/include/linux/msdos_fs_sb.h Mon Jun 9 23:16:12 2003 @@ -26,6 +26,15 @@ nocase:1; /* Does this need case conversion? 0=need case conversion*/ }; +#define FAT_CACHE_NR 8 /* number of FAT cache */ + +struct fat_cache { + int start_cluster; /* first cluster of the chain. */ + int file_cluster; /* cluster number in the file. */ + int disk_cluster; /* cluster number on disk. */ + struct fat_cache *next; /* next cache entry */ +}; + struct msdos_sb_info { unsigned short cluster_size; /* sectors/cluster */ unsigned short cluster_bits; /* sectors/cluster */ @@ -47,6 +56,9 @@ void *dir_ops; /* Opaque; default directory operations */ int dir_per_block; /* dir entries per block */ int dir_per_block_bits; /* log2(dir_per_block) */ + + spinlock_t cache_lock; + struct fat_cache cache_array[FAT_CACHE_NR], *cache; }; #endif diff -Nru a/include/linux/mtd/blktrans.h b/include/linux/mtd/blktrans.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/mtd/blktrans.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,75 @@ +/* + * $Id: blktrans.h,v 1.4 2003/05/21 01:01:32 dwmw2 Exp $ + * + * (C) 2003 David Woodhouse <dwmw2@infradead.org> + * + * Interface to Linux block layer for MTD 'translation layers'. + * + */ + +#ifndef __MTD_TRANS_H__ +#define __MTD_TRANS_H__ + +#include <asm/semaphore.h> + +struct mtd_info; +struct mtd_blktrans_ops; +struct file; +struct inode; + +struct mtd_blktrans_dev { + struct mtd_blktrans_ops *tr; + struct list_head list; + struct mtd_info *mtd; + struct semaphore sem; + int devnum; + int blksize; + unsigned long size; + int readonly; + void *blkcore_priv; /* gendisk in 2.5, devfs_handle in 2.4 */ +}; + +struct blkcore_priv; /* Differs for 2.4 and 2.5 kernels; private */ + +struct mtd_blktrans_ops { + char *name; + int major; + int part_bits; + + /* Access functions */ + int (*readsect)(struct mtd_blktrans_dev *dev, + unsigned long block, char *buffer); + int (*writesect)(struct mtd_blktrans_dev *dev, + unsigned long block, char *buffer); + + /* HDIO_GETGEO and HDIO_GETGEO_BIG are the only non-private + ioctls which are expected to be passed through */ + int (*ioctl)(struct mtd_blktrans_dev *dev, + struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg); + + /* Called with mtd_table_mutex held; no race with add/remove */ + int (*open)(struct mtd_blktrans_dev *dev, + struct inode *i, struct file *f); + int (*release)(struct mtd_blktrans_dev *dev, + struct inode *i, struct file *f); + + /* Called on {de,}registration and on subsequent addition/removal + of devices, with mtd_table_mutex held. */ + void (*add_mtd)(struct mtd_blktrans_ops *tr, struct mtd_info *mtd); + void (*remove_dev)(struct mtd_blktrans_dev *dev); + + struct list_head devs; + struct list_head list; + struct module *owner; + + struct mtd_blkcore_priv *blkcore_priv; +}; + +extern int register_mtd_blktrans(struct mtd_blktrans_ops *tr); +extern int deregister_mtd_blktrans(struct mtd_blktrans_ops *tr); +extern int add_mtd_blktrans_dev(struct mtd_blktrans_dev *dev); +extern int del_mtd_blktrans_dev(struct mtd_blktrans_dev *dev); + + +#endif /* __MTD_TRANS_H__ */ diff -Nru a/include/linux/mtd/cfi.h b/include/linux/mtd/cfi.h --- a/include/linux/mtd/cfi.h Mon Jun 9 23:16:10 2003 +++ b/include/linux/mtd/cfi.h Mon Jun 9 23:16:10 2003 @@ -1,13 +1,14 @@ /* Common Flash Interface structures * See http://support.intel.com/design/flash/technote/index.htm - * $Id: cfi.h,v 1.25 2001/09/04 07:06:21 dwmw2 Exp $ + * $Id: cfi.h,v 1.35 2003/05/28 15:37:32 dwmw2 Exp $ */ #ifndef __MTD_CFI_H__ #define __MTD_CFI_H__ #include <linux/config.h> +#include <linux/version.h> #include <linux/delay.h> #include <linux/types.h> #include <linux/interrupt.h> @@ -18,13 +19,16 @@ * You can optimize the code size and performance by defining only * the geometry(ies) available on your hardware. * CFIDEV_INTERLEAVE_n, where represents the interleave (number of chips to fill the bus width) - * CFIDEV_BUSWIDTH_n, where n is the bus width in bytes (1, 2 or 4 bytes) + * CFIDEV_BUSWIDTH_n, where n is the bus width in bytes (1, 2, 4 or 8 bytes) * * By default, all (known) geometries are supported. */ #ifndef CONFIG_MTD_CFI_GEOMETRY +/* The default case - support all but 64-bit, which has + a performance penalty */ + #define CFIDEV_INTERLEAVE_1 (1) #define CFIDEV_INTERLEAVE_2 (2) #define CFIDEV_INTERLEAVE_4 (4) @@ -33,8 +37,12 @@ #define CFIDEV_BUSWIDTH_2 (2) #define CFIDEV_BUSWIDTH_4 (4) +typedef __u32 cfi_word; + #else +/* Explicitly configured buswidth/interleave support */ + #ifdef CONFIG_MTD_CFI_I1 #define CFIDEV_INTERLEAVE_1 (1) #endif @@ -44,6 +52,9 @@ #ifdef CONFIG_MTD_CFI_I4 #define CFIDEV_INTERLEAVE_4 (4) #endif +#ifdef CONFIG_MTD_CFI_I8 +#define CFIDEV_INTERLEAVE_8 (8) +#endif #ifdef CONFIG_MTD_CFI_B1 #define CFIDEV_BUSWIDTH_1 (1) @@ -54,6 +65,27 @@ #ifdef CONFIG_MTD_CFI_B4 #define CFIDEV_BUSWIDTH_4 (4) #endif +#ifdef CONFIG_MTD_CFI_B8 +#define CFIDEV_BUSWIDTH_8 (8) +#endif + +/* pick the largest necessary */ +#ifdef CONFIG_MTD_CFI_B8 +typedef __u64 cfi_word; + +/* This only works if asm/io.h is included first */ +#ifndef __raw_readll +#define __raw_readll(addr) (*(volatile __u64 *)(addr)) +#endif +#ifndef __raw_writell +#define __raw_writell(v, addr) (*(volatile __u64 *)(addr) = (v)) +#endif +#define CFI_WORD_64 +#else /* CONFIG_MTD_CFI_B8 */ +/* All others can use 32-bits. It's probably more efficient than + the smaller types anyway */ +typedef __u32 cfi_word; +#endif /* CONFIG_MTD_CFI_B8 */ #endif @@ -61,12 +93,15 @@ * The following macros are used to select the code to execute: * cfi_buswidth_is_*() * cfi_interleave_is_*() - * [where * is either 1, 2 or 4] + * [where * is either 1, 2, 4, or 8] * Those macros should be used with 'if' statements. If only one of few * geometry arrangements are selected, they expand to constants thus allowing * the compiler (most of them being 0) to optimize away all the unneeded code, * while still validating the syntax (which is not possible with embedded * #if ... #endif constructs). + * The exception to this is the 64-bit versions, which need an extension + * to the cfi_word type, and cause compiler warnings about shifts being + * out of range. */ #ifdef CFIDEV_INTERLEAVE_1 @@ -105,6 +140,18 @@ # define cfi_interleave_is_4() (0) #endif +#ifdef CFIDEV_INTERLEAVE_8 +# ifdef CFIDEV_INTERLEAVE +# undef CFIDEV_INTERLEAVE +# define CFIDEV_INTERLEAVE (cfi->interleave) +# else +# define CFIDEV_INTERLEAVE CFIDEV_INTERLEAVE_8 +# endif +# define cfi_interleave_is_8() (CFIDEV_INTERLEAVE == CFIDEV_INTERLEAVE_8) +#else +# define cfi_interleave_is_8() (0) +#endif + #ifndef CFIDEV_INTERLEAVE #error You must define at least one interleave to support! #endif @@ -145,6 +192,18 @@ # define cfi_buswidth_is_4() (0) #endif +#ifdef CFIDEV_BUSWIDTH_8 +# ifdef CFIDEV_BUSWIDTH +# undef CFIDEV_BUSWIDTH +# define CFIDEV_BUSWIDTH (map->buswidth) +# else +# define CFIDEV_BUSWIDTH CFIDEV_BUSWIDTH_8 +# endif +# define cfi_buswidth_is_8() (CFIDEV_BUSWIDTH == CFIDEV_BUSWIDTH_8) +#else +# define cfi_buswidth_is_8() (0) +#endif + #ifndef CFIDEV_BUSWIDTH #error You must define at least one bus width to support! #endif @@ -156,6 +215,7 @@ #define CFI_DEVICETYPE_X8 (8 / 8) #define CFI_DEVICETYPE_X16 (16 / 8) #define CFI_DEVICETYPE_X32 (32 / 8) +#define CFI_DEVICETYPE_X64 (64 / 8) /* NB: We keep these structures in memory in HOST byteorder, except * where individually noted. @@ -206,6 +266,10 @@ __u16 BlkStatusRegMask; __u8 VccOptimal; __u8 VppOptimal; + __u8 NumProtectionFields; + __u16 ProtRegAddr; + __u8 FactProtRegSize; + __u8 UserProtRegSize; } __attribute__((packed)); struct cfi_pri_query { @@ -229,8 +293,8 @@ #define P_ID_RESERVED 65535 -#define CFI_MODE_CFI 0 -#define CFI_MODE_JEDEC 1 +#define CFI_MODE_CFI 1 +#define CFI_MODE_JEDEC 0 struct cfi_private { __u16 cmdset; @@ -264,9 +328,9 @@ /* * Transforms the CFI command for the given geometry (bus width & interleave. */ -static inline __u32 cfi_build_cmd(u_char cmd, struct map_info *map, struct cfi_private *cfi) +static inline cfi_word cfi_build_cmd(u_char cmd, struct map_info *map, struct cfi_private *cfi) { - __u32 val = 0; + cfi_word val = 0; if (cfi_buswidth_is_1()) { /* 1 x8 device */ @@ -291,6 +355,27 @@ val = (cmd << 16) | cmd; val = cpu_to_cfi32((val << 8) | val); } +#ifdef CFI_WORD_64 + } else if (cfi_buswidth_is_8()) { + if (cfi_interleave_is_1()) { + /* 1 x64 device in x64 mode */ + val = cpu_to_cfi64(cmd); + } else if (cfi_interleave_is_2()) { + /* 2 x32 device in x32 mode */ + val = cmd; + val = cpu_to_cfi64((val << 32) | val); + } else if (cfi_interleave_is_4()) { + /* 4 (x16, x32 or x64) devices in x16 mode */ + val = (cmd << 16) | cmd; + val = cpu_to_cfi64((val << 32) | val); + } else if (cfi_interleave_is_8()) { + /* 8 (x8, x16 or x32) devices in x8 mode */ + val = (cmd << 8) | cmd; + val = (val << 16) | val; + val = (val << 32) | val; + val = cpu_to_cfi64(val); + } +#endif /* CFI_WORD_64 */ } return val; } @@ -300,14 +385,16 @@ * Read a value according to the bus width. */ -static inline __u32 cfi_read(struct map_info *map, __u32 addr) +static inline cfi_word cfi_read(struct map_info *map, __u32 addr) { if (cfi_buswidth_is_1()) { - return map->read8(map, addr); + return map_read8(map, addr); } else if (cfi_buswidth_is_2()) { - return map->read16(map, addr); + return map_read16(map, addr); } else if (cfi_buswidth_is_4()) { - return map->read32(map, addr); + return map_read32(map, addr); + } else if (cfi_buswidth_is_8()) { + return map_read64(map, addr); } else { return 0; } @@ -317,14 +404,16 @@ * Write a value according to the bus width. */ -static inline void cfi_write(struct map_info *map, __u32 val, __u32 addr) +static inline void cfi_write(struct map_info *map, cfi_word val, __u32 addr) { if (cfi_buswidth_is_1()) { - map->write8(map, val, addr); + map_write8(map, val, addr); } else if (cfi_buswidth_is_2()) { - map->write16(map, val, addr); + map_write16(map, val, addr); } else if (cfi_buswidth_is_4()) { - map->write32(map, val, addr); + map_write32(map, val, addr); + } else if (cfi_buswidth_is_8()) { + map_write64(map, val, addr); } } @@ -337,9 +426,9 @@ */ static inline __u32 cfi_send_gen_cmd(u_char cmd, __u32 cmd_addr, __u32 base, struct map_info *map, struct cfi_private *cfi, - int type, __u32 *prev_val) + int type, cfi_word *prev_val) { - __u32 val; + cfi_word val; __u32 addr = base + cfi_build_cmd_addr(cmd_addr, CFIDEV_INTERLEAVE, type); val = cfi_build_cmd(cmd, map, cfi); @@ -355,11 +444,13 @@ static inline __u8 cfi_read_query(struct map_info *map, __u32 addr) { if (cfi_buswidth_is_1()) { - return map->read8(map, addr); + return map_read8(map, addr); } else if (cfi_buswidth_is_2()) { - return cfi16_to_cpu(map->read16(map, addr)); + return cfi16_to_cpu(map_read16(map, addr)); } else if (cfi_buswidth_is_4()) { - return cfi32_to_cpu(map->read32(map, addr)); + return cfi32_to_cpu(map_read32(map, addr)); + } else if (cfi_buswidth_is_8()) { + return cfi64_to_cpu(map_read64(map, addr)); } else { return 0; } @@ -368,17 +459,17 @@ static inline void cfi_udelay(int us) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0) - if (need_resched()) { - unsigned long t = us * HZ / 1000000; - if (t < 1) - t = 1; + unsigned long t = us * HZ / 1000000; + if (t) { set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(t); + return; } - else #endif - udelay(us); + udelay(us); + cond_resched(); } + static inline void cfi_spin_lock(spinlock_t *mutex) { spin_lock_bh(mutex); @@ -388,6 +479,5 @@ { spin_unlock_bh(mutex); } - #endif /* __MTD_CFI_H__ */ diff -Nru a/include/linux/mtd/cfi_endian.h b/include/linux/mtd/cfi_endian.h --- a/include/linux/mtd/cfi_endian.h Mon Jun 9 23:16:05 2003 +++ b/include/linux/mtd/cfi_endian.h Mon Jun 9 23:16:05 2003 @@ -1,5 +1,5 @@ /* - * $Id: cfi_endian.h,v 1.10 2001/06/18 11:00:46 abz Exp $ + * $Id: cfi_endian.h,v 1.11 2002/01/30 23:20:48 awozniak Exp $ * */ @@ -30,22 +30,28 @@ #define cfi8_to_cpu(x) (x) #define cpu_to_cfi16(x) cpu_to_le16(x) #define cpu_to_cfi32(x) cpu_to_le32(x) +#define cpu_to_cfi64(x) cpu_to_le64(x) #define cfi16_to_cpu(x) le16_to_cpu(x) #define cfi32_to_cpu(x) le32_to_cpu(x) +#define cfi64_to_cpu(x) le64_to_cpu(x) #elif defined (CFI_BIG_ENDIAN) #define cpu_to_cfi8(x) (x) #define cfi8_to_cpu(x) (x) #define cpu_to_cfi16(x) cpu_to_be16(x) #define cpu_to_cfi32(x) cpu_to_be32(x) +#define cpu_to_cfi64(x) cpu_to_be64(x) #define cfi16_to_cpu(x) be16_to_cpu(x) #define cfi32_to_cpu(x) be32_to_cpu(x) +#define cfi64_to_cpu(x) be64_to_cpu(x) #elif defined (CFI_HOST_ENDIAN) #define cpu_to_cfi8(x) (x) #define cfi8_to_cpu(x) (x) #define cpu_to_cfi16(x) (x) #define cpu_to_cfi32(x) (x) +#define cpu_to_cfi64(x) (x) #define cfi16_to_cpu(x) (x) #define cfi32_to_cpu(x) (x) +#define cfi64_to_cpu(x) (x) #else #error No CFI endianness defined #endif diff -Nru a/include/linux/mtd/compatmac.h b/include/linux/mtd/compatmac.h --- a/include/linux/mtd/compatmac.h Mon Jun 9 23:16:17 2003 +++ b/include/linux/mtd/compatmac.h Mon Jun 9 23:16:17 2003 @@ -1,201 +1,10 @@ -/* - * mtd/include/compatmac.h - * - * $Id: compatmac.h,v 1.4 2000/07/03 10:01:38 dwmw2 Exp $ - * - * Extensions and omissions from the normal 'linux/compatmac.h' - * files. hopefully this will end up empty as the 'real' one - * becomes fully-featured. - */ - - -/* First, include the parts which the kernel is good enough to provide - * to us - */ - #ifndef __LINUX_MTD_COMPATMAC_H__ #define __LINUX_MTD_COMPATMAC_H__ -#include <linux/types.h> /* used later in this header */ -#include <linux/module.h> -#ifndef LINUX_VERSION_CODE -#include <linux/version.h> -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) -#include <linux/vmalloc.h> -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,0,0) -# error "This kernel is too old: not supported by this file" -#endif - -/* Modularization issues */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,18) -# define __USE_OLD_SYMTAB__ -# define EXPORT_NO_SYMBOLS register_symtab(NULL); -# define REGISTER_SYMTAB(tab) register_symtab(tab) -#else -# define REGISTER_SYMTAB(tab) /* nothing */ -#endif - -#ifdef __USE_OLD_SYMTAB__ -# define __MODULE_STRING(s) /* nothing */ -# define MODULE_PARM(v,t) /* nothing */ -# define MODULE_PARM_DESC(v,t) /* nothing */ -# define MODULE_AUTHOR(n) /* nothing */ -# define MODULE_DESCRIPTION(d) /* nothing */ -# define MODULE_SUPPORTED_DEVICE(n) /* nothing */ -#endif - -/* - * "select" changed in 2.1.23. The implementation is twin, but this - * header is new - */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,22) -# include <linux/poll.h> -#else -# define __USE_OLD_SELECT__ -#endif - -/* Other change in the fops are solved using pseudo-types */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) -# define lseek_t long long -# define lseek_off_t long long -#else -# define lseek_t int -# define lseek_off_t off_t -#endif - -/* changed the prototype of read/write */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0) || defined(__alpha__) -# define count_t unsigned long -# define read_write_t long -#else -# define count_t int -# define read_write_t int -#endif - - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,31) -# define release_t void -# define release_return(x) return -#else -# define release_t int -# define release_return(x) return (x) -#endif - -#if LINUX_VERSION_CODE < 0x20300 -#define __exit -#endif -#if LINUX_VERSION_CODE < 0x20200 -#define __init -#else -#include <linux/init.h> -#endif - -#if LINUX_VERSION_CODE < 0x20300 -#define init_MUTEX(x) do {*(x) = MUTEX;} while (0) -#define RQFUNC_ARG void -#define blkdev_dequeue_request(req) do {CURRENT = req->next;} while (0) -#else -#define RQFUNC_ARG request_queue_t *q -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0) -#define __MOD_INC_USE_COUNT(mod) \ - (atomic_inc(&(mod)->uc.usecount), (mod)->flags |= MOD_VISITED|MOD_USED_ONCE) -#define __MOD_DEC_USE_COUNT(mod) \ - (atomic_dec(&(mod)->uc.usecount), (mod)->flags |= MOD_VISITED) -#endif - - - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) - -#define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x = NULL -#define init_waitqueue_head init_waitqueue - -static inline int try_inc_mod_count(struct module *mod) -{ - if (mod) - __MOD_INC_USE_COUNT(mod); - return 1; -} -#endif - - -/* Yes, I'm aware that it's a fairly ugly hack. - Until the __constant_* macros appear in Linus' own kernels, this is - the way it has to be done. - DW 19/1/00 - */ - -#include <asm/byteorder.h> - -#ifndef __constant_cpu_to_le16 - -#ifdef __BIG_ENDIAN -#define __constant_cpu_to_le64(x) ___swab64((x)) -#define __constant_le64_to_cpu(x) ___swab64((x)) -#define __constant_cpu_to_le32(x) ___swab32((x)) -#define __constant_le32_to_cpu(x) ___swab32((x)) -#define __constant_cpu_to_le16(x) ___swab16((x)) -#define __constant_le16_to_cpu(x) ___swab16((x)) -#define __constant_cpu_to_be64(x) ((__u64)(x)) -#define __constant_be64_to_cpu(x) ((__u64)(x)) -#define __constant_cpu_to_be32(x) ((__u32)(x)) -#define __constant_be32_to_cpu(x) ((__u32)(x)) -#define __constant_cpu_to_be16(x) ((__u16)(x)) -#define __constant_be16_to_cpu(x) ((__u16)(x)) -#else -#ifdef __LITTLE_ENDIAN -#define __constant_cpu_to_le64(x) ((__u64)(x)) -#define __constant_le64_to_cpu(x) ((__u64)(x)) -#define __constant_cpu_to_le32(x) ((__u32)(x)) -#define __constant_le32_to_cpu(x) ((__u32)(x)) -#define __constant_cpu_to_le16(x) ((__u16)(x)) -#define __constant_le16_to_cpu(x) ((__u16)(x)) -#define __constant_cpu_to_be64(x) ___swab64((x)) -#define __constant_be64_to_cpu(x) ___swab64((x)) -#define __constant_cpu_to_be32(x) ___swab32((x)) -#define __constant_be32_to_cpu(x) ___swab32((x)) -#define __constant_cpu_to_be16(x) ___swab16((x)) -#define __constant_be16_to_cpu(x) ___swab16((x)) -#else -#error No (recognised) endianness defined (unless it,s PDP) -#endif /* __LITTLE_ENDIAN */ -#endif /* __BIG_ENDIAN */ - -#endif /* ifndef __constant_cpu_to_le16 */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) - #define mod_init_t int __init - #define mod_exit_t void -#else - #define mod_init_t static int __init - #define mod_exit_t static void __exit -#endif - -#ifndef THIS_MODULE -#ifdef MODULE -#define THIS_MODULE (&__this_module) -#else -#define THIS_MODULE (NULL) -#endif -#endif - -#if LINUX_VERSION_CODE < 0x20300 -#include <linux/interrupt.h> -#define spin_lock_bh(lock) do {start_bh_atomic();spin_lock(lock);} while(0) -#define spin_unlock_bh(lock) do {spin_unlock(lock);end_bh_atomic();} while(0) -#else -#include <linux/interrupt.h> -#include <linux/spinlock.h> -#endif +/* Nothing to see here. We write 2.5-compatible code and this + file makes it all OK in older kernels, but it's empty in _current_ + kernels. Include guard just to make GCC ignore it in future inclusions + anyway... */ #endif /* __LINUX_MTD_COMPATMAC_H__ */ - - diff -Nru a/include/linux/mtd/doc2000.h b/include/linux/mtd/doc2000.h --- a/include/linux/mtd/doc2000.h Mon Jun 9 23:16:13 2003 +++ b/include/linux/mtd/doc2000.h Mon Jun 9 23:16:13 2003 @@ -2,7 +2,7 @@ /* Linux driver for Disk-On-Chip 2000 */ /* (c) 1999 Machine Vision Holdings, Inc. */ /* Author: David Woodhouse <dwmw2@mvhi.com> */ -/* $Id: doc2000.h,v 1.15 2001/09/19 00:22:15 dwmw2 Exp $ */ +/* $Id: doc2000.h,v 1.16 2003/05/23 11:29:33 dwmw2 Exp $ */ #ifndef __MTD_DOC2000_H__ #define __MTD_DOC2000_H__ @@ -38,6 +38,35 @@ #define DoC_Mil_CDSN_IO 0x0800 #define DoC_2k_CDSN_IO 0x1800 +#define DoC_Mplus_NOP 0x1002 +#define DoC_Mplus_AliasResolution 0x1004 +#define DoC_Mplus_DOCControl 0x1006 +#define DoC_Mplus_AccessStatus 0x1008 +#define DoC_Mplus_DeviceSelect 0x1008 +#define DoC_Mplus_Configuration 0x100a +#define DoC_Mplus_OutputControl 0x1002 +#define DoC_Mplus_FlashControl 0x1020 +#define DoC_Mplus_FlashSelect 0x1022 +#define DoC_Mplus_FlashCmd 0x1024 +#define DoC_Mplus_FlashAddress 0x1026 +#define DoC_Mplus_FlashData0 0x1028 +#define DoC_Mplus_FlashData1 0x1029 +#define DoC_Mplus_ReadPipeInit 0x102a +#define DoC_Mplus_LastDataRead 0x102c +#define DoC_Mplus_LastDataRead1 0x102d +#define DoC_Mplus_WritePipeTerm 0x102e +#define DoC_Mplus_ECCSyndrome0 0x1040 +#define DoC_Mplus_ECCSyndrome1 0x1041 +#define DoC_Mplus_ECCSyndrome2 0x1042 +#define DoC_Mplus_ECCSyndrome3 0x1043 +#define DoC_Mplus_ECCSyndrome4 0x1044 +#define DoC_Mplus_ECCSyndrome5 0x1045 +#define DoC_Mplus_ECCConf 0x1046 +#define DoC_Mplus_Toggle 0x1046 +#define DoC_Mplus_DownloadStatus 0x1074 +#define DoC_Mplus_CtrlConfirm 0x1076 +#define DoC_Mplus_Power 0x1fff + /* How to access the device? * On ARM, it'll be mmap'd directly with 32-bit wide accesses. * On PPC, it's mmap'd and 16-bit wide. @@ -71,13 +100,20 @@ #define DOC_MODE_RESERVED1 2 #define DOC_MODE_RESERVED2 3 -#define DOC_MODE_MDWREN 4 #define DOC_MODE_CLR_ERR 0x80 +#define DOC_MODE_RST_LAT 0x10 +#define DOC_MODE_BDECT 0x08 +#define DOC_MODE_MDWREN 0x04 #define DOC_ChipID_Doc2k 0x20 #define DOC_ChipID_DocMil 0x30 +#define DOC_ChipID_DocMilPlus32 0x40 +#define DOC_ChipID_DocMilPlus16 0x41 #define CDSN_CTRL_FR_B 0x80 +#define CDSN_CTRL_FR_B0 0x40 +#define CDSN_CTRL_FR_B1 0x80 + #define CDSN_CTRL_ECC_IO 0x20 #define CDSN_CTRL_FLASH_IO 0x10 #define CDSN_CTRL_WP 0x08 @@ -93,6 +129,10 @@ #define DOC_ECC_RESV 0x02 #define DOC_ECC_IGNORE 0x01 +#define DOC_FLASH_CE 0x80 +#define DOC_FLASH_WP 0x40 +#define DOC_FLASH_BANK 0x02 + /* We have to also set the reserved bit 1 for enable */ #define DOC_ECC_EN (DOC_ECC__EN | DOC_ECC_RESV) #define DOC_ECC_DIS (DOC_ECC_RESV) @@ -110,6 +150,9 @@ #define MAX_FLOORS_MIL 4 #define MAX_CHIPS_MIL 1 +#define MAX_FLOORS_MPLUS 1 +#define MAX_CHIPS_MPLUS 1 + #define ADDR_COLUMN 1 #define ADDR_PAGE 2 #define ADDR_COLUMN_PAGE 3 @@ -126,6 +169,7 @@ int chipshift; char page256; char pageadrlen; + char interleave; /* Internal interleaving - Millennium Plus style */ unsigned long erasesize; int curfloor; diff -Nru a/include/linux/mtd/flashchip.h b/include/linux/mtd/flashchip.h --- a/include/linux/mtd/flashchip.h Mon Jun 9 23:16:18 2003 +++ b/include/linux/mtd/flashchip.h Mon Jun 9 23:16:18 2003 @@ -6,7 +6,7 @@ * * (C) 2000 Red Hat. GPLd. * - * $Id: flashchip.h,v 1.7 2001/01/18 03:52:36 nico Exp $ + * $Id: flashchip.h,v 1.9 2003/04/30 11:15:22 dwmw2 Exp $ * */ @@ -36,6 +36,7 @@ FL_UNLOADING, FL_LOCKING, FL_UNLOCKING, + FL_POINT, FL_UNKNOWN } flstate_t; @@ -54,8 +55,13 @@ a given offset, and we'll want to add the per-chip length field back in. */ + int ref_point_counter; flstate_t state; flstate_t oldstate; + + int write_suspended:1; + int erase_suspended:1; + spinlock_t *mutex; spinlock_t _spinlock; /* We do it like this because sometimes they'll be shared. */ wait_queue_head_t wq; /* Wait on here when we're waiting for the chip diff -Nru a/include/linux/mtd/inftl.h b/include/linux/mtd/inftl.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/mtd/inftl.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,129 @@ +/* + * inftl.h -- defines to support the Inverse NAND Flash Translation Layer + * + * (C) Copyright 2002, Greg Ungerer (gerg@snapgear.com) + * + * $Id: inftl.h,v 1.3 2003/05/23 11:35:34 dwmw2 Exp $ + */ + +#ifndef __MTD_INFTL_H__ +#define __MTD_INFTL_H__ + +#include <linux/mtd/blktrans.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nftl.h> + +#define OSAK_VERSION 0x5120 +#define PERCENTUSED 98 + +#define SECTORSIZE 512 + +#ifndef INFTL_MAJOR +#define INFTL_MAJOR 93 /* FIXME */ +#endif +#define INFTL_PARTN_BITS 4 + +/* Block Control Information */ + +struct inftl_bci { + __u8 ECCsig[6]; + __u8 Status; + __u8 Status1; +} __attribute__((packed)); + +struct inftl_unithead1 { + __u16 virtualUnitNo; + __u16 prevUnitNo; + __u8 ANAC; + __u8 NACs; + __u8 parityPerField; + __u8 discarded; +} __attribute__((packed)); + +struct inftl_unithead2 { + __u8 parityPerField; + __u8 ANAC; + __u16 prevUnitNo; + __u16 virtualUnitNo; + __u8 NACs; + __u8 discarded; +} __attribute__((packed)); + +struct inftl_unittail { + __u8 Reserved[4]; + __u16 EraseMark; + __u16 EraseMark1; +} __attribute__((packed)); + +union inftl_uci { + struct inftl_unithead1 a; + struct inftl_unithead2 b; + struct inftl_unittail c; +}; + +struct inftl_oob { + struct inftl_bci b; + union inftl_uci u; +}; + + +/* INFTL Media Header */ + +struct INFTLPartition { + __u32 virtualUnits; + __u32 firstUnit; + __u32 lastUnit; + __u32 flags; + __u32 spareUnits; + __u32 Reserved0; + __u32 Reserved1; +} __attribute__((packed)); + +struct INFTLMediaHeader { + char bootRecordID[8]; + __u32 NoOfBootImageBlocks; + __u32 NoOfBinaryPartitions; + __u32 NoOfBDTLPartitions; + __u32 BlockMultiplierBits; + __u32 FormatFlags; + __u32 OsakVersion; + __u32 PercentUsed; + struct INFTLPartition Partitions[4]; +} __attribute__((packed)); + +/* Partition flag types */ +#define INFTL_BINARY 0x20000000 +#define INFTL_BDTL 0x40000000 +#define INFTL_LAST 0x80000000 + + +#ifdef __KERNEL__ + +struct INFTLrecord { + struct mtd_blktrans_dev mbd; + __u16 MediaUnit, SpareMediaUnit; + __u32 EraseSize; + struct INFTLMediaHeader MediaHdr; + int usecount; + unsigned char heads; + unsigned char sectors; + unsigned short cylinders; + __u16 numvunits; + __u16 firstEUN; + __u16 lastEUN; + __u16 numfreeEUNs; + __u16 LastFreeEUN; /* To speed up finding a free EUN */ + int head,sect,cyl; + __u16 *PUtable; /* Physical Unit Table */ + __u16 *VUtable; /* Virtual Unit Table */ + unsigned int nb_blocks; /* number of physical blocks */ + unsigned int nb_boot_blocks; /* number of blocks used by the bios */ + struct erase_info instr; +}; + +int INFTL_mount(struct INFTLrecord *s); +int INFTL_formatblock(struct INFTLrecord *s, int block); + +#endif /* __KERNEL__ */ + +#endif /* __MTD_INFTL_H__ */ diff -Nru a/include/linux/mtd/jedec.h b/include/linux/mtd/jedec.h --- a/include/linux/mtd/jedec.h Mon Jun 9 23:16:19 2003 +++ b/include/linux/mtd/jedec.h Mon Jun 9 23:16:19 2003 @@ -7,14 +7,13 @@ * * See the AMD flash databook for information on how to operate the interface. * - * $Id: jedec.h,v 1.2 2001/11/06 14:37:36 dwmw2 Exp $ + * $Id: jedec.h,v 1.3 2003/05/21 11:51:01 dwmw2 Exp $ */ #ifndef __LINUX_MTD_JEDEC_H__ #define __LINUX_MTD_JEDEC_H__ #include <linux/types.h> -#include <linux/mtd/map.h> #define MAX_JEDEC_CHIPS 16 diff -Nru a/include/linux/mtd/map.h b/include/linux/mtd/map.h --- a/include/linux/mtd/map.h Mon Jun 9 23:16:10 2003 +++ b/include/linux/mtd/map.h Mon Jun 9 23:16:10 2003 @@ -1,14 +1,15 @@ /* Overhauled routines for dealing with different mmap regions of flash */ -/* $Id: map.h,v 1.25 2001/09/09 15:04:17 dwmw2 Exp $ */ +/* $Id: map.h,v 1.34 2003/05/28 12:42:22 dwmw2 Exp $ */ #ifndef __LINUX_MTD_MAP_H__ #define __LINUX_MTD_MAP_H__ #include <linux/config.h> #include <linux/types.h> -#include <linux/mtd/mtd.h> -#include <linux/slab.h> +#include <linux/list.h> +#include <asm/system.h> +#include <asm/io.h> /* The map stuff is very simple. You fill in your struct map_info with a handful of routines for accessing the device, making sure they handle @@ -29,34 +30,44 @@ struct map_info { char *name; unsigned long size; + unsigned long phys; +#define NO_XIP (-1UL) + + unsigned long virt; + void *cached; + int buswidth; /* in octets */ - __u8 (*read8)(struct map_info *, unsigned long); - __u16 (*read16)(struct map_info *, unsigned long); - __u32 (*read32)(struct map_info *, unsigned long); + +#ifdef CONFIG_MTD_COMPLEX_MAPPINGS + u8 (*read8)(struct map_info *, unsigned long); + u16 (*read16)(struct map_info *, unsigned long); + u32 (*read32)(struct map_info *, unsigned long); + u64 (*read64)(struct map_info *, unsigned long); /* If it returned a 'long' I'd call it readl. * It doesn't. * I won't. * dwmw2 */ void (*copy_from)(struct map_info *, void *, unsigned long, ssize_t); - void (*write8)(struct map_info *, __u8, unsigned long); - void (*write16)(struct map_info *, __u16, unsigned long); - void (*write32)(struct map_info *, __u32, unsigned long); + void (*write8)(struct map_info *, u8, unsigned long); + void (*write16)(struct map_info *, u16, unsigned long); + void (*write32)(struct map_info *, u32, unsigned long); + void (*write64)(struct map_info *, u64, unsigned long); void (*copy_to)(struct map_info *, unsigned long, const void *, ssize_t); + /* We can perhaps put in 'point' and 'unpoint' methods, if we really + want to enable XIP for non-linear mappings. Not yet though. */ +#endif + /* set_vpp() must handle being reentered -- enable, enable, disable + must leave it enabled. */ void (*set_vpp)(struct map_info *, int); - /* We put these two here rather than a single void *map_priv, - because we want mappers to be able to have quickly-accessible - cache for the 'currently-mapped page' without the _extra_ - redirection that would be necessary. If you need more than - two longs, turn the second into a pointer. dwmw2 */ + unsigned long map_priv_1; unsigned long map_priv_2; void *fldrv_priv; struct mtd_chip_driver *fldrv; }; - struct mtd_chip_driver { struct mtd_info *(*probe)(struct map_info *map); void (*destroy)(struct mtd_info *); @@ -68,24 +79,94 @@ void register_mtd_chip_driver(struct mtd_chip_driver *); void unregister_mtd_chip_driver(struct mtd_chip_driver *); -struct mtd_info *do_map_probe(char *name, struct map_info *map); +struct mtd_info *do_map_probe(const char *name, struct map_info *map); +void map_destroy(struct mtd_info *mtd); +#define ENABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 1); } while(0) +#define DISABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 0); } while(0) + +#ifdef CONFIG_MTD_COMPLEX_MAPPINGS +#define map_read8(map, ofs) (map)->read8(map, ofs) +#define map_read16(map, ofs) (map)->read16(map, ofs) +#define map_read32(map, ofs) (map)->read32(map, ofs) +#define map_read64(map, ofs) (map)->read64(map, ofs) +#define map_copy_from(map, to, from, len) (map)->copy_from(map, to, from, len) +#define map_write8(map, datum, ofs) (map)->write8(map, datum, ofs) +#define map_write16(map, datum, ofs) (map)->write16(map, datum, ofs) +#define map_write32(map, datum, ofs) (map)->write32(map, datum, ofs) +#define map_write64(map, datum, ofs) (map)->write64(map, datum, ofs) +#define map_copy_to(map, to, from, len) (map)->copy_to(map, to, from, len) -/* - * Destroy an MTD device which was created for a map device. - * Make sure the MTD device is already unregistered before calling this - */ -static inline void map_destroy(struct mtd_info *mtd) +extern void simple_map_init(struct map_info *); +#define map_is_linear(map) (map->phys != NO_XIP) + +#else +static inline u8 map_read8(struct map_info *map, unsigned long ofs) { - struct map_info *map = mtd->priv; + return __raw_readb(map->virt + ofs); +} - if (map->fldrv->destroy) - map->fldrv->destroy(mtd); - module_put(map->fldrv->module); - kfree(mtd); +static inline u16 map_read16(struct map_info *map, unsigned long ofs) +{ + return __raw_readw(map->virt + ofs); } -#define ENABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 1); } while(0) -#define DISABLE_VPP(map) do { if(map->set_vpp) map->set_vpp(map, 0); } while(0) +static inline u32 map_read32(struct map_info *map, unsigned long ofs) +{ + return __raw_readl(map->virt + ofs); +} + +static inline u64 map_read64(struct map_info *map, unsigned long ofs) +{ +#ifndef CONFIG_MTD_CFI_B8 /* 64-bit mappings */ + BUG(); + return 0; +#else + return __raw_readll(map->virt + ofs); +#endif +} + +static inline void map_write8(struct map_info *map, u8 datum, unsigned long ofs) +{ + __raw_writeb(datum, map->virt + ofs); + mb(); +} + +static inline void map_write16(struct map_info *map, u16 datum, unsigned long ofs) +{ + __raw_writew(datum, map->virt + ofs); + mb(); +} + +static inline void map_write32(struct map_info *map, u32 datum, unsigned long ofs) +{ + __raw_writel(datum, map->virt + ofs); + mb(); +} + +static inline void map_write64(struct map_info *map, u64 datum, unsigned long ofs) +{ +#ifndef CONFIG_MTD_CFI_B8 /* 64-bit mappings */ + BUG(); +#else + __raw_writell(datum, map->virt + ofs); + mb(); +#endif /* CFI_B8 */ +} + +static inline void map_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy_fromio(to, map->virt + from, len); +} + +static inline void map_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + memcpy_toio(map->virt + to, from, len); +} + +#define simple_map_init(map) do { } while (0) +#define map_is_linear(map) (1) + +#endif /* !CONFIG_MTD_COMPLEX_MAPPINGS */ #endif /* __LINUX_MTD_MAP_H__ */ diff -Nru a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h --- a/include/linux/mtd/mtd.h Mon Jun 9 23:16:05 2003 +++ b/include/linux/mtd/mtd.h Mon Jun 9 23:16:05 2003 @@ -1,5 +1,5 @@ -/* $Id: mtd.h,v 1.33 2001/06/09 00:08:59 dwmw2 Exp $ */ +/* $Id: mtd.h,v 1.45 2003/05/20 21:56:40 dwmw2 Exp $ */ #ifndef __MTD_MTD_H__ #define __MTD_MTD_H__ @@ -9,7 +9,6 @@ #include <linux/config.h> #include <linux/version.h> #include <linux/types.h> -#include <linux/mtd/compatmac.h> #include <linux/module.h> #include <linux/uio.h> @@ -26,7 +25,6 @@ unsigned char *ptr; }; - #define MTD_CHAR_MAJOR 90 #define MTD_BLOCK_MAJOR 31 #define MAX_MTD_DEVICES 16 @@ -93,16 +91,23 @@ #define MEMUNLOCK _IOW('M', 6, struct erase_info_user) #define MEMGETREGIONCOUNT _IOR('M', 7, int) #define MEMGETREGIONINFO _IOWR('M', 8, struct region_info_user) +#define MEMSETOOBSEL _IOW('M', 9, struct nand_oobinfo) + +struct nand_oobinfo { + int useecc; + int eccpos[6]; +}; + #ifndef __KERNEL__ typedef struct mtd_info_user mtd_info_t; typedef struct erase_info_user erase_info_t; typedef struct region_info_user region_info_t; +typedef struct nand_oobinfo nand_oobinfo_t; /* User-space ioctl definitions */ - #else /* __KERNEL__ */ @@ -147,11 +152,15 @@ u_int32_t oobsize; // Amount of OOB data per block (e.g. 16) u_int32_t ecctype; u_int32_t eccsize; + // Kernel-only stuff starts here. char *name; int index; + // oobinfo is a nand_oobinfo structure, which can be set by iotcl (MEMSETOOBINFO) + struct nand_oobinfo oobinfo; + /* Data for variable erase regions. If numeraseregions is zero, * it means that the whole device has erasesize as given above. */ @@ -161,32 +170,47 @@ /* This really shouldn't be here. It can go away in 2.5 */ u_int32_t bank_size; - struct module *module; int (*erase) (struct mtd_info *mtd, struct erase_info *instr); /* This stuff for eXecute-In-Place */ int (*point) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf); /* We probably shouldn't allow XIP if the unpoint isn't a NULL */ - void (*unpoint) (struct mtd_info *mtd, u_char * addr); + void (*unpoint) (struct mtd_info *mtd, u_char * addr, loff_t from, size_t len); int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); - int (*read_ecc) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf); - int (*write_ecc) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf); + int (*read_ecc) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); + int (*write_ecc) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf, struct nand_oobinfo *oobsel); int (*read_oob) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); int (*write_oob) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf); + /* + * Methods to access the protection register area, present in some + * flash devices. The user data is one time programmable but the + * factory data is read only. + */ + int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); + + int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); + + /* This function is not yet implemented */ + int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf); + /* iovec-based read/write methods. We need these especially for NAND flash, with its limited number of write cycles per erase. NB: The 'count' parameter is the number of _vectors_, each of which contains an (ofs, len) tuple. */ int (*readv) (struct mtd_info *mtd, struct iovec *vecs, unsigned long count, loff_t from, size_t *retlen); + int (*readv_ecc) (struct mtd_info *mtd, struct iovec *vecs, unsigned long count, loff_t from, + size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel); int (*writev) (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen); + int (*writev_ecc) (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, + size_t *retlen, u_char *eccbuf, struct nand_oobinfo *oobsel); /* Sync */ void (*sync) (struct mtd_info *mtd); @@ -200,6 +224,9 @@ void (*resume) (struct mtd_info *mtd); void *priv; + + struct module *owner; + int usecount; }; @@ -208,35 +235,27 @@ extern int add_mtd_device(struct mtd_info *mtd); extern int del_mtd_device (struct mtd_info *mtd); -extern struct mtd_info *__get_mtd_device(struct mtd_info *mtd, int num); +extern struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num); + +extern void put_mtd_device(struct mtd_info *mtd); -static inline struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num) -{ - struct mtd_info *ret; - - ret = __get_mtd_device(mtd, num); - if (ret && !try_module_get(ret->module)) - return NULL; - return ret; -} - -static inline void put_mtd_device(struct mtd_info *mtd) -{ - module_put(mtd->module); -} struct mtd_notifier { void (*add)(struct mtd_info *mtd); void (*remove)(struct mtd_info *mtd); - struct mtd_notifier *next; + struct list_head list; }; extern void register_mtd_user (struct mtd_notifier *new); extern int unregister_mtd_user (struct mtd_notifier *old); +int default_mtd_writev(struct mtd_info *mtd, const struct iovec *vecs, + unsigned long count, loff_t to, size_t *retlen); + +int default_mtd_readv(struct mtd_info *mtd, struct iovec *vecs, + unsigned long count, loff_t from, size_t *retlen); -#ifndef MTDC #define MTD_ERASE(mtd, args...) (*(mtd->erase))(mtd, args) #define MTD_POINT(mtd, a,b,c,d) (*(mtd->point))(mtd, a,b,c, (u_char **)(d)) #define MTD_UNPOINT(mtd, arg) (*(mtd->unpoint))(mtd, (u_char *)arg) @@ -249,7 +268,6 @@ #define MTD_READOOB(mtd, args...) (*(mtd->read_oob))(mtd, args) #define MTD_WRITEOOB(mtd, args...) (*(mtd->write_oob))(mtd, args) #define MTD_SYNC(mtd) do { if (mtd->sync) (*(mtd->sync))(mtd); } while (0) -#endif /* MTDC */ /* * Debugging macro and defines @@ -266,7 +284,8 @@ printk(KERN_INFO args); \ } while(0) #else /* CONFIG_MTD_DEBUG */ -#define DEBUG(n, args...) +#define DEBUG(n, args...) do { } while(0) + #endif /* CONFIG_MTD_DEBUG */ #endif /* __KERNEL__ */ diff -Nru a/include/linux/mtd/nand.h b/include/linux/mtd/nand.h --- a/include/linux/mtd/nand.h Mon Jun 9 23:16:18 2003 +++ b/include/linux/mtd/nand.h Mon Jun 9 23:16:18 2003 @@ -2,9 +2,10 @@ * linux/include/linux/mtd/nand.h * * Copyright (c) 2000 David Woodhouse <dwmw2@mvhi.com> - * Steven J. Hill <sjhill@cotw.com> + * Steven J. Hill <sjhill@realitydiluted.com> + * Thomas Gleixner <tglx@linutronix.de> * - * $Id: nand.h,v 1.8 2000/10/30 17:16:17 sjhill Exp $ + * $Id: nand.h,v 1.25 2003/05/21 15:15:02 dwmw2 Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -23,19 +24,51 @@ * bat later if I did something naughty. * 10-11-2000 SJH Added private NAND flash structure for driver * 10-24-2000 SJH Added prototype for 'nand_scan' function + * 10-29-2001 TG changed nand_chip structure to support + * hardwarespecific function for accessing control lines + * 02-21-2002 TG added support for different read/write adress and + * ready/busy line access function + * 02-26-2002 TG added chip_delay to nand_chip structure to optimize + * command delay times for different chips + * 04-28-2002 TG OOB config defines moved from nand.c to avoid duplicate + * defines in jffs2/wbuf.c + * 08-07-2002 TG forced bad block location to byte 5 of OOB, even if + * CONFIG_MTD_NAND_ECC_JFFS2 is not set + * 08-10-2002 TG extensions to nand_chip structure to support HW-ECC + * + * 08-29-2002 tglx nand_chip structure: data_poi for selecting + * internal / fs-driver buffer + * support for 6byte/512byte hardware ECC + * read_ecc, write_ecc extended for different oob-layout + * oob layout selections: NAND_NONE_OOB, NAND_JFFS2_OOB, + * NAND_YAFFS_OOB + * 11-25-2002 tglx Added Manufacturer code FUJITSU, NATIONAL + * Split manufacturer and device ID structures */ #ifndef __LINUX_MTD_NAND_H #define __LINUX_MTD_NAND_H #include <linux/config.h> -#include <linux/sched.h> +#include <linux/wait.h> +#include <linux/spinlock.h> +struct mtd_info; /* * Searches for a NAND device */ extern int nand_scan (struct mtd_info *mtd); /* + * Constants for hardware specific CLE/ALE/NCE function +*/ +#define NAND_CTL_SETNCE 1 +#define NAND_CTL_CLRNCE 2 +#define NAND_CTL_SETCLE 3 +#define NAND_CTL_CLRCLE 4 +#define NAND_CTL_SETALE 5 +#define NAND_CTL_CLRALE 6 + +/* * Standard NAND flash commands */ #define NAND_CMD_READ0 0 @@ -49,6 +82,29 @@ #define NAND_CMD_ERASE2 0xd0 #define NAND_CMD_RESET 0xff +/* + * Constants for ECC_MODES + * + * NONE: No ECC + * SOFT: Software ECC 3 byte ECC per 256 Byte data + * HW3_256: Hardware ECC 3 byte ECC per 256 Byte data + * HW3_512: Hardware ECC 3 byte ECC per 512 Byte data + * + * +*/ +#define NAND_ECC_NONE 0 +#define NAND_ECC_SOFT 1 +#define NAND_ECC_HW3_256 2 +#define NAND_ECC_HW3_512 3 +#define NAND_ECC_HW6_512 4 +#define NAND_ECC_DISKONCHIP 5 + +/* + * Constants for Hardware ECC +*/ +#define NAND_ECC_READ 0 +#define NAND_ECC_WRITE 1 + /* * Enumeration for NAND flash chip state */ @@ -60,20 +116,33 @@ FL_SYNCING } nand_state_t; + /* * NAND Private Flash Chip Data * * Structure overview: * - * IO_ADDR - address to access the 8 I/O lines to the flash device + * IO_ADDR_R - address to read the 8 I/O lines of the flash device + * + * IO_ADDR_W - address to write the 8 I/O lines of the flash device + * + * hwcontrol - hardwarespecific function for accesing control-lines * - * CTRL_ADDR - address where ALE, CLE and CE control bits are accessed + * dev_ready - hardwarespecific function for accesing device ready/busy line * - * CLE - location in control word for Command Latch Enable bit + * waitfunc - hardwarespecific function for wait on ready * - * ALE - location in control word for Address Latch Enable bit + * calculate_ecc - function for ecc calculation or readback from ecc hardware * - * NCE - location in control word for nChip Enable bit + * correct_data - function for ecc correction, matching to ecc generator (sw/hw) + * + * enable_hwecc - function to enable (reset) hardware ecc generator + * + * eccmod - mode of ecc: see constants + * + * eccsize - databytes used per ecc-calculation + * + * chip_delay - chip dependent delay for transfering data from array to read regs (tR) * * chip_lock - spinlock used to protect access to this structure * @@ -85,27 +154,30 @@ * * data_buf - data buffer passed to/from MTD user modules * - * ecc_code_buf - used only for holding calculated or read ECCs for - * a page read or written when ECC is in use + * data_cache - data cache for redundant page access and shadow for + * ECC failure * - * reserved - padding to make structure fall on word boundary if - * when ECC is in use + * cache_page - number of last valid page in page_cache */ struct nand_chip { - unsigned long IO_ADDR; - unsigned long CTRL_ADDR; - unsigned int CLE; - unsigned int ALE; - unsigned int NCE; - spinlock_t chip_lock; + unsigned long IO_ADDR_R; + unsigned long IO_ADDR_W; + void (*hwcontrol)(int cmd); + int (*dev_ready)(void); + void (*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr); + int (*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state); + void (*calculate_ecc)(const u_char *dat, u_char *ecc_code); + int (*correct_data)(u_char *dat, u_char *read_ecc, u_char *calc_ecc); + void (*enable_hwecc)(int mode); + int eccmode; + int eccsize; + int chip_delay; + spinlock_t chip_lock; wait_queue_head_t wq; - nand_state_t state; - int page_shift; - u_char *data_buf; -#ifdef CONFIG_MTD_NAND_ECC - u_char ecc_code_buf[6]; - u_char reserved[2]; -#endif + nand_state_t state; + int page_shift; + u_char *data_buf; + u_char *data_poi; }; /* @@ -113,17 +185,17 @@ */ #define NAND_MFR_TOSHIBA 0x98 #define NAND_MFR_SAMSUNG 0xec +#define NAND_MFR_FUJITSU 0x04 +#define NAND_MFR_NATIONAL 0x8f /* * NAND Flash Device ID Structure * * Structure overview: * - * name - Complete name of device - * - * manufacture_id - manufacturer ID code of device. + * name - Identify the device type * - * model_id - model ID code of device. + * id - device ID code * * chipshift - total number of address bits for the device which * is used to calculate address offsets and the total @@ -143,12 +215,30 @@ */ struct nand_flash_dev { char * name; - int manufacture_id; - int model_id; + int id; int chipshift; - char page256; - char pageadrlen; unsigned long erasesize; + char page256; }; + +/* + * NAND Flash Manufacturer ID Structure + * + * name - Manufacturer name + * + * id - manufacturer ID code of device. +*/ +struct nand_manufacturers { + int id; + char * name; +}; + +extern struct nand_flash_dev nand_flash_ids[]; +extern struct nand_manufacturers nand_manuf_ids[]; + +/* +* Constants for oob configuration +*/ +#define NAND_BADBLOCK_POS 5 #endif /* __LINUX_MTD_NAND_H */ diff -Nru a/include/linux/mtd/nand_ecc.h b/include/linux/mtd/nand_ecc.h --- a/include/linux/mtd/nand_ecc.h Mon Jun 9 23:16:13 2003 +++ b/include/linux/mtd/nand_ecc.h Mon Jun 9 23:16:13 2003 @@ -1,9 +1,9 @@ /* * drivers/mtd/nand_ecc.h * - * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) + * Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com) * - * $Id: nand_ecc.h,v 1.1 2000/10/12 00:57:15 sjhill Exp $ + * $Id: nand_ecc.h,v 1.2 2003/02/20 13:34:20 sjhill Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff -Nru a/include/linux/mtd/nand_ids.h b/include/linux/mtd/nand_ids.h --- a/include/linux/mtd/nand_ids.h Mon Jun 9 23:16:07 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,52 +0,0 @@ -/* - * linux/include/linux/mtd/nand_ids.h - * - * Copyright (c) 2000 David Woodhouse <dwmw2@mvhi.com> - * Steven J. Hill <sjhill@cotw.com> - * - * $Id: nand_ids.h,v 1.1 2000/10/13 16:16:26 mdeans Exp $ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * Info: - * Contains standard defines and IDs for NAND flash devices - * - * Changelog: - * 01-31-2000 DMW Created - * 09-18-2000 SJH Moved structure out of the Disk-On-Chip drivers - * so it can be used by other NAND flash device - * drivers. I also changed the copyright since none - * of the original contents of this file are specific - * to DoC devices. David can whack me with a baseball - * bat later if I did something naughty. - * 10-11-2000 SJH Added private NAND flash structure for driver - * 2000-10-13 BE Moved out of 'nand.h' - avoids duplication. - */ - -#ifndef __LINUX_MTD_NAND_IDS_H -#define __LINUX_MTD_NAND_IDS_H - -static struct nand_flash_dev nand_flash_ids[] = { - {"Toshiba TC5816BDC", NAND_MFR_TOSHIBA, 0x64, 21, 1, 2, 0x1000}, - {"Toshiba TC5832DC", NAND_MFR_TOSHIBA, 0x6b, 22, 0, 2, 0x2000}, - {"Toshiba TH58V128DC", NAND_MFR_TOSHIBA, 0x73, 24, 0, 2, 0x4000}, - {"Toshiba TC58256FT/DC", NAND_MFR_TOSHIBA, 0x75, 25, 0, 2, 0x4000}, - {"Toshiba TH58512FT", NAND_MFR_TOSHIBA, 0x76, 26, 0, 3, 0x4000}, - {"Toshiba TC58V32DC", NAND_MFR_TOSHIBA, 0xe5, 22, 0, 2, 0x2000}, - {"Toshiba TC58V64AFT/DC", NAND_MFR_TOSHIBA, 0xe6, 23, 0, 2, 0x2000}, - {"Toshiba TC58V16BDC", NAND_MFR_TOSHIBA, 0xea, 21, 1, 2, 0x1000}, - {"Samsung KM29N16000", NAND_MFR_SAMSUNG, 0x64, 21, 1, 2, 0x1000}, - {"Samsung unknown 4Mb", NAND_MFR_SAMSUNG, 0x6b, 22, 0, 2, 0x2000}, - {"Samsung KM29U128T", NAND_MFR_SAMSUNG, 0x73, 24, 0, 2, 0x4000}, - {"Samsung KM29U256T", NAND_MFR_SAMSUNG, 0x75, 25, 0, 2, 0x4000}, - {"Samsung unknown 64Mb", NAND_MFR_SAMSUNG, 0x76, 26, 0, 3, 0x4000}, - {"Samsung KM29W32000", NAND_MFR_SAMSUNG, 0xe3, 22, 0, 2, 0x2000}, - {"Samsung unknown 4Mb", NAND_MFR_SAMSUNG, 0xe5, 22, 0, 2, 0x2000}, - {"Samsung KM29U64000", NAND_MFR_SAMSUNG, 0xe6, 23, 0, 2, 0x2000}, - {"Samsung KM29W16000", NAND_MFR_SAMSUNG, 0xea, 21, 1, 2, 0x1000}, - {NULL,} -}; - -#endif /* __LINUX_MTD_NAND_IDS_H */ diff -Nru a/include/linux/mtd/nftl.h b/include/linux/mtd/nftl.h --- a/include/linux/mtd/nftl.h Mon Jun 9 23:16:17 2003 +++ b/include/linux/mtd/nftl.h Mon Jun 9 23:16:17 2003 @@ -1,15 +1,14 @@ - -/* Defines for NAND Flash Translation Layer */ -/* (c) 1999 Machine Vision Holdings, Inc. */ -/* Author: David Woodhouse <dwmw2@mvhi.com> */ -/* $Id: nftl.h,v 1.10 2000/12/29 00:25:38 dwmw2 Exp $ */ +/* + * $Id: nftl.h,v 1.13 2003/05/23 11:25:02 dwmw2 Exp $ + * + * (C) 1999-2003 David Woodhouse <dwmw2@infradead.org> + */ #ifndef __MTD_NFTL_H__ #define __MTD_NFTL_H__ -#ifndef __BOOT__ #include <linux/mtd/mtd.h> -#endif +#include <linux/mtd/blktrans.h> /* Block Control Information */ @@ -84,8 +83,7 @@ #define BLOCK_RESERVED 0xfffc /* bios block or bad block */ struct NFTLrecord { - struct mtd_info *mtd; - struct semaphore mutex; + struct mtd_blktrans_dev mbd; __u16 MediaUnit, SpareMediaUnit; __u32 EraseSize; struct NFTLMediaHeader MediaHdr; @@ -97,14 +95,12 @@ __u16 lastEUN; /* should be suppressed */ __u16 numfreeEUNs; __u16 LastFreeEUN; /* To speed up finding a free EUN */ - __u32 long nr_sects; int head,sect,cyl; __u16 *EUNtable; /* [numvunits]: First EUN for each virtual unit */ __u16 *ReplUnitTable; /* [numEUNs]: ReplUnitNumber for each */ unsigned int nb_blocks; /* number of physical blocks */ unsigned int nb_boot_blocks; /* number of blocks used by the bios */ struct erase_info instr; - struct gendisk *disk; }; int NFTL_mount(struct NFTLrecord *s); @@ -115,7 +111,7 @@ #endif #define MAX_NFTLS 16 -#define MAX_SECTORS_PER_UNIT 32 +#define MAX_SECTORS_PER_UNIT 64 #define NFTL_PARTN_BITS 4 #endif /* __KERNEL__ */ diff -Nru a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h --- a/include/linux/mtd/partitions.h Mon Jun 9 23:16:18 2003 +++ b/include/linux/mtd/partitions.h Mon Jun 9 23:16:18 2003 @@ -5,7 +5,7 @@ * * This code is GPL * - * $Id: partitions.h,v 1.6 2001/03/17 17:10:21 dwmw2 Exp $ + * $Id: partitions.h,v 1.14 2003/05/20 21:56:29 dwmw2 Exp $ */ #ifndef MTD_PARTITIONS_H @@ -26,29 +26,51 @@ * will extend to the end of the master MTD device. * offset: absolute starting position within the master MTD device; if * defined as MTDPART_OFS_APPEND, the partition will start where the - * previous one ended. + * previous one ended; if MTDPART_OFS_NXTBLK, at the next erase block. * mask_flags: contains flags that have to be masked (removed) from the * master MTD flag set for the corresponding MTD partition. * For example, to force a read-only partition, simply adding * MTD_WRITEABLE to the mask_flags will do the trick. * * Note: writeable partitions require their size and offset be - * erasesize aligned. + * erasesize aligned (e.g. use MTDPART_OFS_NEXTBLK). */ struct mtd_partition { - char *name; /* identifier string */ - u_int32_t size; /* partition size */ + char *name; /* identifier string */ + u_int32_t size; /* partition size */ u_int32_t offset; /* offset within the master MTD space */ - u_int32_t mask_flags; /* master MTD flags to mask out for this partition */ + u_int32_t mask_flags; /* master MTD flags to mask out for this partition */ + struct nand_oobinfo *oobsel; /* out of band layout for this partition (NAND only)*/ + struct mtd_info **mtdp; /* pointer to store the MTD object */ }; +#define MTDPART_OFS_NXTBLK (-2) #define MTDPART_OFS_APPEND (-1) #define MTDPART_SIZ_FULL (0) int add_mtd_partitions(struct mtd_info *, struct mtd_partition *, int); int del_mtd_partitions(struct mtd_info *); + +/* + * Functions dealing with the various ways of partitioning the space + */ + +struct mtd_part_parser { + struct list_head list; + struct module *owner; + const char *name; + int (*parse_fn)(struct mtd_info *, struct mtd_partition **, unsigned long); +}; + +extern struct mtd_part_parser *get_partition_parser(const char *name); +extern int register_mtd_parser(struct mtd_part_parser *parser); +extern int deregister_mtd_parser(struct mtd_part_parser *parser); +extern int parse_mtd_partitions(struct mtd_info *master, const char **types, + struct mtd_partition **pparts, unsigned long origin); + +#define put_partition_parser(p) do { module_put((p)->owner); } while(0) #endif diff -Nru a/include/linux/mtd/pmc551.h b/include/linux/mtd/pmc551.h --- a/include/linux/mtd/pmc551.h Mon Jun 9 23:16:06 2003 +++ b/include/linux/mtd/pmc551.h Mon Jun 9 23:16:06 2003 @@ -1,5 +1,5 @@ /* - * $Id: pmc551.h,v 1.4 2001/06/12 16:19:38 major Exp $ + * $Id: pmc551.h,v 1.5 2003/01/24 16:49:53 dwmw2 Exp $ * * PMC551 PCI Mezzanine Ram Device * @@ -17,7 +17,7 @@ #include <linux/mtd/mtd.h> -#define PMC551_VERSION "$Id: pmc551.h,v 1.4 2001/06/12 16:19:38 major Exp $\n"\ +#define PMC551_VERSION "$Id: pmc551.h,v 1.5 2003/01/24 16:49:53 dwmw2 Exp $\n"\ "Ramix PMC551 PCI Mezzanine Ram Driver. (C) 1999,2000 Nortel Networks.\n" /* @@ -36,7 +36,7 @@ * Function Prototypes */ static int pmc551_erase(struct mtd_info *, struct erase_info *); -static void pmc551_unpoint(struct mtd_info *, u_char *); +static void pmc551_unpoint(struct mtd_info *, u_char *, loff_t, size_t); static int pmc551_point (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf); static int pmc551_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *); static int pmc551_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *); diff -Nru a/include/linux/netdevice.h b/include/linux/netdevice.h --- a/include/linux/netdevice.h Mon Jun 9 23:16:19 2003 +++ b/include/linux/netdevice.h Mon Jun 9 23:16:19 2003 @@ -147,8 +147,6 @@ #ifdef __KERNEL__ -extern const char *if_port_text[]; - #include <linux/cache.h> #include <linux/skbuff.h> @@ -335,6 +333,7 @@ void *dn_ptr; /* DECnet specific data */ void *ip6_ptr; /* IPv6 specific data */ void *ec_ptr; /* Econet specific data */ + void *ax25_ptr; /* AX.25 specific data */ struct list_head poll_list; /* Link to poll list */ int quota; diff -Nru a/include/linux/pci.h b/include/linux/pci.h --- a/include/linux/pci.h Mon Jun 9 23:16:11 2003 +++ b/include/linux/pci.h Mon Jun 9 23:16:11 2003 @@ -390,6 +390,11 @@ or supports 64-bit transfers. */ struct list_head pools; /* pci_pools tied to this device */ + u64 consistent_dma_mask;/* Like dma_mask, but for + pci_alloc_consistent mappings as + not all hardware supports + 64 bit addresses for consistent + allocations such descriptors. */ u32 current_state; /* Current operating state. In ACPI-speak, this is D0-D3, D0 being fully functional, and D3 being off. */ @@ -463,10 +468,6 @@ #define pci_bus_b(n) list_entry(n, struct pci_bus, node) -extern struct list_head pci_root_buses; /* list of all known PCI buses */ -extern struct list_head pci_devices; /* list of all devices */ -extern struct bus_type pci_bus_type; - /* * Error values that may be returned by PCI functions. */ @@ -517,18 +518,17 @@ /* these external functions are only available when PCI support is enabled */ #ifdef CONFIG_PCI -static inline int pci_present(void) -{ - return !list_empty(&pci_devices); -} +extern struct bus_type pci_bus_type; + +/* Do NOT directly access these two variables, unless you are arch specific pci + * code, or pci core code. */ +extern struct list_head pci_root_buses; /* list of all known PCI buses */ +extern struct list_head pci_devices; /* list of all devices */ -#define pci_for_each_dev(dev) \ - for(dev = pci_dev_g(pci_devices.next); dev != pci_dev_g(&pci_devices); dev = pci_dev_g(dev->global_list.next)) -#define pci_for_each_dev_reverse(dev) \ - for(dev = pci_dev_g(pci_devices.prev); dev != pci_dev_g(&pci_devices); dev = pci_dev_g(dev->global_list.prev)) #define pci_for_each_bus(bus) \ for(bus = pci_bus_b(pci_root_buses.next); bus != pci_bus_b(&pci_root_buses); bus = pci_bus_b(bus->node.next)) +int pci_present(void); void pcibios_fixup_bus(struct pci_bus *); int pcibios_enable_device(struct pci_dev *, int mask); char *pcibios_setup (char *str); @@ -546,39 +546,28 @@ { return pci_scan_bus_parented(NULL, bus, ops, sysdata); } -struct pci_bus *pci_alloc_primary_bus_parented(struct device * parent, int bus); -static inline struct pci_bus *pci_alloc_primary_bus(int bus) -{ - return pci_alloc_primary_bus_parented(NULL, bus); -} int pci_scan_slot(struct pci_bus *bus, int devfn); void pci_bus_add_devices(struct pci_bus *bus); -int pci_proc_attach_device(struct pci_dev *dev); -int pci_proc_detach_device(struct pci_dev *dev); -int pci_proc_attach_bus(struct pci_bus *bus); -int pci_proc_detach_bus(struct pci_bus *bus); void pci_name_device(struct pci_dev *dev); char *pci_class_name(u32 class); void pci_read_bridge_bases(struct pci_bus *child); struct resource *pci_find_parent_resource(const struct pci_dev *dev, struct resource *res); -int pci_setup_device(struct pci_dev *dev); int pci_get_interrupt_pin(struct pci_dev *dev, struct pci_dev **bridge); extern struct pci_dev *pci_get_dev(struct pci_dev *dev); extern void pci_put_dev(struct pci_dev *dev); +extern void pci_remove_bus_device(struct pci_dev *dev); + /* Generic PCI functions exported to card drivers */ struct pci_dev *pci_find_device (unsigned int vendor, unsigned int device, const struct pci_dev *from); +struct pci_dev *pci_find_device_reverse (unsigned int vendor, unsigned int device, const struct pci_dev *from); struct pci_dev *pci_find_subsys (unsigned int vendor, unsigned int device, unsigned int ss_vendor, unsigned int ss_device, const struct pci_dev *from); struct pci_dev *pci_find_class (unsigned int class, const struct pci_dev *from); -struct pci_bus *pci_find_bus(unsigned char busnr); struct pci_dev *pci_find_slot (unsigned int bus, unsigned int devfn); -unsigned char pci_bus_max_busnr(struct pci_bus* bus); -unsigned char pci_max_busnr(void); int pci_find_capability (struct pci_dev *dev, int cap); -int pci_bus_find_capability (struct pci_bus *bus, unsigned int devfn, int cap); int pci_bus_read_config_byte (struct pci_bus *bus, unsigned int devfn, int where, u8 *val); int pci_bus_read_config_word (struct pci_bus *bus, unsigned int devfn, int where, u16 *val); @@ -612,8 +601,6 @@ return pci_bus_write_config_dword (dev->bus, dev->devfn, where, val); } -extern spinlock_t pci_lock; - int pci_enable_device(struct pci_dev *dev); int pci_enable_device_bars(struct pci_dev *dev, int mask); void pci_disable_device(struct pci_dev *dev); @@ -623,6 +610,7 @@ void pci_clear_mwi(struct pci_dev *dev); int pci_set_dma_mask(struct pci_dev *dev, u64 mask); int pci_dac_set_dma_mask(struct pci_dev *dev, u64 mask); +int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask); int pci_assign_resource(struct pci_dev *dev, int i); /* Power management related routines */ @@ -632,7 +620,6 @@ int pci_enable_wake(struct pci_dev *dev, u32 state, int enable); /* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */ - void pci_bus_assign_resources(struct pci_bus *bus); void pci_bus_size_bridges(struct pci_bus *bus); int pci_claim_resource(struct pci_dev *, int); @@ -648,24 +635,14 @@ void pci_release_region(struct pci_dev *, int); /* drivers/pci/bus.c */ - -int pci_bus_alloc_resource(struct pci_bus *bus, struct resource *res, - unsigned long size, unsigned long align, - unsigned long min, unsigned int type_mask, - void (*alignf)(void *, struct resource *, - unsigned long, unsigned long), - void *alignf_data); void pci_enable_bridges(struct pci_bus *bus); /* New-style probing supporting hot-pluggable devices */ int pci_register_driver(struct pci_driver *); void pci_unregister_driver(struct pci_driver *); -void pci_remove_bus_device(struct pci_dev *); void pci_remove_behind_bridge(struct pci_dev *); struct pci_driver *pci_dev_driver(const struct pci_dev *); const struct pci_device_id *pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev); -unsigned int pci_do_scan_bus(struct pci_bus *bus); -struct pci_bus * pci_add_new_bus(struct pci_bus *parent, struct pci_dev *dev, int busnr); int pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max, int pass); /* kmem_cache style wrapper around pci_alloc_consistent() */ @@ -680,42 +657,6 @@ extern struct pci_dev *isa_bridge; #endif -/* Some worker functions that PCI Hotplug drivers find useful */ -struct pci_dev_wrapped { - struct pci_dev *dev; - void *data; -}; - -struct pci_bus_wrapped { - struct pci_bus *bus; - void *data; -}; - -struct pci_visit { - int (* pre_visit_pci_bus) (struct pci_bus_wrapped *, - struct pci_dev_wrapped *); - int (* post_visit_pci_bus) (struct pci_bus_wrapped *, - struct pci_dev_wrapped *); - - int (* pre_visit_pci_dev) (struct pci_dev_wrapped *, - struct pci_bus_wrapped *); - int (* visit_pci_dev) (struct pci_dev_wrapped *, - struct pci_bus_wrapped *); - int (* post_visit_pci_dev) (struct pci_dev_wrapped *, - struct pci_bus_wrapped *); -}; - -extern int pci_visit_dev(struct pci_visit *fn, - struct pci_dev_wrapped *wrapped_dev, - struct pci_bus_wrapped *wrapped_parent); -extern int pci_remove_device_safe(struct pci_dev *dev); - -static inline void -pci_dynids_set_use_driver_data(struct pci_driver *pdrv, int val) -{ - pdrv->dynids.use_driver_data = val; -} - #endif /* CONFIG_PCI */ /* Include architecture-dependent settings and functions */ @@ -764,16 +705,12 @@ static inline int scsi_to_pci_dma_dir(unsigned char scsi_dir) { return scsi_dir; } static inline int pci_find_capability (struct pci_dev *dev, int cap) {return 0; } static inline const struct pci_device_id *pci_match_device(const struct pci_device_id *ids, const struct pci_dev *dev) { return NULL; } -static inline void pci_dynids_set_use_driver_data(struct pci_driver *pdrv, int val) { } /* Power management related routines */ static inline int pci_save_state(struct pci_dev *dev, u32 *buffer) { return 0; } static inline int pci_restore_state(struct pci_dev *dev, u32 *buffer) { return 0; } static inline int pci_set_power_state(struct pci_dev *dev, int state) { return 0; } static inline int pci_enable_wake(struct pci_dev *dev, u32 state, int enable) { return 0; } - -#define pci_for_each_dev(dev) \ - for(dev = NULL; 0; ) #define isa_bridge ((struct pci_dev *)NULL) diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h --- a/include/linux/pci_ids.h Mon Jun 9 23:16:10 2003 +++ b/include/linux/pci_ids.h Mon Jun 9 23:16:10 2003 @@ -1398,9 +1398,20 @@ #define PCI_DEVICE_ID_RP4QUAD 0x0004 #define PCI_DEVICE_ID_RP8OCTA 0x0005 #define PCI_DEVICE_ID_RP8J 0x0006 +#define PCI_DEVICE_ID_RP4J 0x0007 #define PCI_DEVICE_ID_RPP4 0x000A #define PCI_DEVICE_ID_RPP8 0x000B #define PCI_DEVICE_ID_RP8M 0x000C +#define PCI_DEVICE_ID_RP4M 0x000D +#define PCI_DEVICE_ID_RP2_232 0x000E +#define PCI_DEVICE_ID_RP2_422 0x000F +#define PCI_DEVICE_ID_URP32INTF 0x0801 +#define PCI_DEVICE_ID_URP8INTF 0x0802 +#define PCI_DEVICE_ID_URP16INTF 0x0803 +#define PCI_DEVICE_ID_URP8OCTA 0x0805 +#define PCI_DEVICE_ID_UPCI_RM3_8PORT 0x080C +#define PCI_DEVICE_ID_UPCI_RM3_4PORT 0x080D +#define PCI_DEVICE_ID_CRP16INTF 0x0903 #define PCI_VENDOR_ID_CYCLADES 0x120e #define PCI_DEVICE_ID_CYCLOM_Y_Lo 0x0100 diff -Nru a/include/linux/percpu.h b/include/linux/percpu.h --- a/include/linux/percpu.h Mon Jun 9 23:16:18 2003 +++ b/include/linux/percpu.h Mon Jun 9 23:16:18 2003 @@ -1,9 +1,16 @@ #ifndef __LINUX_PERCPU_H #define __LINUX_PERCPU_H #include <linux/spinlock.h> /* For preempt_disable() */ -#include <linux/slab.h> /* For kmalloc_percpu() */ +#include <linux/slab.h> /* For kmalloc() */ +#include <linux/smp.h> +#include <linux/string.h> /* For memset() */ #include <asm/percpu.h> +/* Enough to cover all DEFINE_PER_CPUs in kernel, including modules. */ +#ifndef PERCPU_ENOUGH_ROOM +#define PERCPU_ENOUGH_ROOM 32768 +#endif + /* Must be an lvalue. */ #define get_cpu_var(var) (*({ preempt_disable(); &__get_cpu_var(var); })) #define put_cpu_var(var) preempt_enable() @@ -17,7 +24,7 @@ /* * Use this to get to a cpu's version of the per-cpu object allocated using - * kmalloc_percpu. If you want to get "this cpu's version", maybe you want + * alloc_percpu. If you want to get "this cpu's version", maybe you want * to use get_cpu_ptr... */ #define per_cpu_ptr(ptr, cpu) \ @@ -26,19 +33,22 @@ (__typeof__(ptr))__p->ptrs[(cpu)]; \ }) -extern void *kmalloc_percpu(size_t size, int flags); -extern void kfree_percpu(const void *); +extern void *__alloc_percpu(size_t size, size_t align); +extern void free_percpu(const void *); extern void kmalloc_percpu_init(void); #else /* CONFIG_SMP */ #define per_cpu_ptr(ptr, cpu) (ptr) -static inline void *kmalloc_percpu(size_t size, int flags) +static inline void *__alloc_percpu(size_t size, size_t align) { - return(kmalloc(size, flags)); + void *ret = kmalloc(size, GFP_KERNEL); + if (ret) + memset(ret, 0, size); + return ret; } -static inline void kfree_percpu(const void *ptr) +static inline void free_percpu(const void *ptr) { kfree(ptr); } @@ -46,9 +56,13 @@ #endif /* CONFIG_SMP */ +/* Simple wrapper for the common case: zeros memory. */ +#define alloc_percpu(type) \ + ((type *)(__alloc_percpu(sizeof(type), __alignof__(type)))) + /* - * Use these with kmalloc_percpu. If - * 1. You want to operate on memory allocated by kmalloc_percpu (dereference + * Use these with alloc_percpu. If + * 1. You want to operate on memory allocated by alloc_percpu (dereference * and read/modify/write) AND * 2. You want "this cpu's version" of the object AND * 3. You want to do this safely since: diff -Nru a/include/linux/proc_fs.h b/include/linux/proc_fs.h --- a/include/linux/proc_fs.h Mon Jun 9 23:16:05 2003 +++ b/include/linux/proc_fs.h Mon Jun 9 23:16:05 2003 @@ -74,6 +74,12 @@ kdev_t rdev; }; +struct kcore_list { + struct kcore_list *next; + unsigned long addr; + size_t size; +}; + #ifdef CONFIG_PROC_FS extern struct proc_dir_entry proc_root; @@ -179,6 +185,12 @@ remove_proc_entry(name,proc_net); } +/* + * fs/proc/kcore.c + */ +extern void kclist_add(struct kcore_list *, void *, size_t); +extern struct kcore_list *kclist_del(void *); + #else #define proc_root_driver NULL @@ -187,10 +199,14 @@ get_info_t *get_info) {return NULL;} static inline void proc_net_remove(const char *name) {} +static inline struct dentry *proc_pid_unhash(struct task_struct *p) { return NULL; } +static inline void proc_pid_flush(struct dentry *proc_dentry) { } + static inline struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, struct proc_dir_entry *parent) { return NULL; } -static inline void remove_proc_entry(const char *name, struct proc_dir_entry *parent) {}; +#define remove_proc_entry(name, parent) do {} while (0) + static inline struct proc_dir_entry *proc_symlink(const char *name, struct proc_dir_entry *parent,char *dest) {return NULL;} static inline struct proc_dir_entry *proc_mknod(const char *name,mode_t mode, @@ -211,6 +227,14 @@ static inline void proc_tty_unregister_driver(struct tty_driver *driver) {}; extern struct proc_dir_entry proc_root; + +static inline void kclist_add(struct kcore_list *new, void *addr, size_t size) +{ +} +static inline struct kcore_list * kclist_del(void *addr) +{ + return NULL; +} #endif /* CONFIG_PROC_FS */ diff -Nru a/include/linux/ptrace.h b/include/linux/ptrace.h --- a/include/linux/ptrace.h Mon Jun 9 23:16:07 2003 +++ b/include/linux/ptrace.h Mon Jun 9 23:16:07 2003 @@ -92,6 +92,23 @@ if (unlikely(child->ptrace)) __ptrace_unlink(child); } + + +#ifndef force_successful_syscall_return +/* + * System call handlers that, upon successful completion, need to return a + * negative value should call force_successful_syscall_return() right before + * returning. On architectures where the syscall convention provides for a + * separate error flag (e.g., alpha, ia64, ppc{,64}, sparc{,64}, possibly + * others), this macro can be used to ensure that the error flag will not get + * set. On architectures which do not support a separate error flag, the macro + * is a no-op and the spurious error condition needs to be filtered out by some + * other means (e.g., in user-level, by passing an extra argument to the + * syscall handler, or something along those lines). + */ +#define force_successful_syscall_return() do { } while (0) +#endif + #endif #endif diff -Nru a/include/linux/raid/linear.h b/include/linux/raid/linear.h --- a/include/linux/raid/linear.h Mon Jun 9 23:16:19 2003 +++ b/include/linux/raid/linear.h Mon Jun 9 23:16:19 2003 @@ -19,9 +19,9 @@ struct linear_private_data { struct linear_hash *hash_table; - dev_info_t disks[MD_SB_DISKS]; dev_info_t *smallest; int nr_zones; + dev_info_t disks[0]; }; diff -Nru a/include/linux/raid/md.h b/include/linux/raid/md.h --- a/include/linux/raid/md.h Mon Jun 9 23:16:06 2003 +++ b/include/linux/raid/md.h Mon Jun 9 23:16:06 2003 @@ -40,6 +40,7 @@ #include <linux/reboot.h> #include <linux/vmalloc.h> #include <linux/blkpg.h> +#include <linux/bio.h> /* * 'md_p.h' holds the 'physical' layout of RAID devices @@ -61,21 +62,6 @@ #define MD_MINOR_VERSION 90 #define MD_PATCHLEVEL_VERSION 0 -/* - * XXX(hch): This function is broken. Someone who understands the md - * code needs to go through all callers, check whether bdev could - * be NULL and replace it with direct calls to bdevmame. - * - * This would also fix the returns buffer on stack issue nicely :) - */ -static inline const char *bdev_partition_name (struct block_device *bdev) -{ - char b[BDEVNAME_SIZE]; - - if (!bdev) - return __bdevname(0, b); - return bdevname(bdev, b); -} extern int register_md_personality (int p_num, mdk_personality_t *p); extern int unregister_md_personality (int p_num); extern mdk_thread_t * md_register_thread (void (*run) (mddev_t *mddev), diff -Nru a/include/linux/raid/multipath.h b/include/linux/raid/multipath.h --- a/include/linux/raid/multipath.h Mon Jun 9 23:16:16 2003 +++ b/include/linux/raid/multipath.h Mon Jun 9 23:16:16 2003 @@ -2,7 +2,6 @@ #define _MULTIPATH_H #include <linux/raid/md.h> -#include <linux/bio.h> struct multipath_info { mdk_rdev_t *rdev; @@ -10,7 +9,7 @@ struct multipath_private_data { mddev_t *mddev; - struct multipath_info multipaths[MD_SB_DISKS]; + struct multipath_info *multipaths; int raid_disks; int working_disks; spinlock_t device_lock; diff -Nru a/include/linux/raid/raid0.h b/include/linux/raid/raid0.h --- a/include/linux/raid/raid0.h Mon Jun 9 23:16:19 2003 +++ b/include/linux/raid/raid0.h Mon Jun 9 23:16:19 2003 @@ -8,22 +8,19 @@ sector_t zone_offset; /* Zone offset in md_dev */ sector_t dev_offset; /* Zone offset in real dev */ sector_t size; /* Zone size */ - int nb_dev; /* # of devices attached to the zone */ - mdk_rdev_t *dev[MD_SB_DISKS]; /* Devices attached to the zone */ -}; - -struct raid0_hash -{ - struct strip_zone *zone0, *zone1; + int nb_dev; /* # of devices attached to the zone */ + mdk_rdev_t **dev; /* Devices attached to the zone */ }; struct raid0_private_data { - struct raid0_hash *hash_table; /* Dynamically allocated */ - struct strip_zone *strip_zone; /* This one too */ + struct strip_zone **hash_table; /* Table of indexes into strip_zone */ + struct strip_zone *strip_zone; + mdk_rdev_t **devlist; /* lists of rdevs, pointed to by strip_zone->dev */ int nr_strip_zones; - struct strip_zone *smallest; - int nr_zones; + + sector_t hash_spacing; + int preshift; /* shift this before divide by hash_spacing */ }; typedef struct raid0_private_data raid0_conf_t; diff -Nru a/include/linux/raid/raid1.h b/include/linux/raid/raid1.h --- a/include/linux/raid/raid1.h Mon Jun 9 23:16:14 2003 +++ b/include/linux/raid/raid1.h Mon Jun 9 23:16:14 2003 @@ -14,7 +14,7 @@ struct r1_private_data_s { mddev_t *mddev; - mirror_info_t mirrors[MD_SB_DISKS]; + mirror_info_t *mirrors; int raid_disks; int working_disks; int last_used; @@ -67,13 +67,14 @@ */ struct bio *read_bio; int read_disk; - /* - * if the IO is in WRITE direction, then multiple bios are used: - */ - struct bio *write_bios[MD_SB_DISKS]; r1bio_t *next_r1; /* next for retry or in free list */ struct list_head retry_list; + /* + * if the IO is in WRITE direction, then multiple bios are used. + * We choose the number when they are allocated. + */ + struct bio *write_bios[0]; }; /* bits for r1bio.state */ diff -Nru a/include/linux/raid/raid5.h b/include/linux/raid/raid5.h --- a/include/linux/raid/raid5.h Mon Jun 9 23:16:17 2003 +++ b/include/linux/raid/raid5.h Mon Jun 9 23:16:17 2003 @@ -3,7 +3,6 @@ #include <linux/raid/md.h> #include <linux/raid/xor.h> -#include <linux/bio.h> /* * @@ -203,7 +202,6 @@ struct raid5_private_data { struct stripe_head **stripe_hashtbl; mddev_t *mddev; - struct disk_info disks[MD_SB_DISKS]; struct disk_info *spare; int chunk_size, level, algorithm; int raid_disks, working_disks, failed_disks; @@ -225,6 +223,7 @@ * waiting for 25% to be free */ spinlock_t device_lock; + struct disk_info disks[0]; }; typedef struct raid5_private_data raid5_conf_t; diff -Nru a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h --- a/include/linux/reiserfs_fs.h Mon Jun 9 23:16:18 2003 +++ b/include/linux/reiserfs_fs.h Mon Jun 9 23:16:18 2003 @@ -1631,28 +1631,42 @@ /***************************************************************************/ /*#ifdef __KERNEL__*/ +#define get_journal_desc_magic(bh) (bh->b_data + bh->b_size - 12) -/* journal.c see journal.c for all the comments here */ - -#define JOURNAL_TRANS_HALF 1018 /* must be correct to keep the desc and commit structs at 4k */ +#define journal_trans_half(blocksize) \ + ((blocksize - sizeof (struct reiserfs_journal_desc) + sizeof (__u32) - 12) / sizeof (__u32)) +/* journal.c see journal.c for all the comments here */ /* first block written in a commit. */ struct reiserfs_journal_desc { __u32 j_trans_id ; /* id of commit */ __u32 j_len ; /* length of commit. len +1 is the commit block */ __u32 j_mount_id ; /* mount id of this trans*/ - __u32 j_realblock[JOURNAL_TRANS_HALF] ; /* real locations for each block */ - char j_magic[12] ; + __u32 j_realblock[1] ; /* real locations for each block */ } ; +#define get_desc_trans_id(d) le32_to_cpu((d)->j_trans_id) +#define get_desc_trans_len(d) le32_to_cpu((d)->j_len) +#define get_desc_mount_id(d) le32_to_cpu((d)->j_mount_id) + +#define set_desc_trans_id(d,val) do { (d)->j_trans_id = cpu_to_le32 (val); } while (0) +#define set_desc_trans_len(d,val) do { (d)->j_len = cpu_to_le32 (val); } while (0) +#define set_desc_mount_id(d,val) do { (d)->j_mount_id = cpu_to_le32 (val); } while (0) + /* last block written in a commit */ struct reiserfs_journal_commit { __u32 j_trans_id ; /* must match j_trans_id from the desc block */ __u32 j_len ; /* ditto */ - __u32 j_realblock[JOURNAL_TRANS_HALF] ; /* real locations for each block */ - char j_digest[16] ; /* md5 sum of all the blocks involved, including desc and commit. not used, kill it */ + __u32 j_realblock[1] ; /* real locations for each block */ } ; + +#define get_commit_trans_id(c) le32_to_cpu((c)->j_trans_id) +#define get_commit_trans_len(c) le32_to_cpu((c)->j_len) +#define get_commit_mount_id(c) le32_to_cpu((c)->j_mount_id) + +#define set_commit_trans_id(c,val) do { (c)->j_trans_id = cpu_to_le32 (val); } while (0) +#define set_commit_trans_len(c,val) do { (c)->j_len = cpu_to_le32 (val); } while (0) /* this header block gets written whenever a transaction is considered fully flushed, and is more recent than the ** last fully flushed transaction. fully flushed means all the log blocks and all the real blocks are on disk, diff -Nru a/include/linux/reiserfs_fs_sb.h b/include/linux/reiserfs_fs_sb.h --- a/include/linux/reiserfs_fs_sb.h Mon Jun 9 23:16:13 2003 +++ b/include/linux/reiserfs_fs_sb.h Mon Jun 9 23:16:13 2003 @@ -253,6 +253,8 @@ struct reiserfs_journal_cnode *j_list_hash_table[JOURNAL_HASH_SIZE] ; /* hash table for all the real buffer heads in all the transactions */ struct list_head j_prealloc_list; /* list of inodes which have preallocated blocks */ + unsigned long j_max_trans_size ; + unsigned long j_max_batch_size ; }; #define JOURNAL_DESC_MAGIC "ReIsErLB" /* ick. magic string to find desc blocks in the journal */ diff -Nru a/include/linux/rocket.h b/include/linux/rocket.h --- a/include/linux/rocket.h Mon Jun 9 23:16:05 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,55 +0,0 @@ -/* - * This file contains the exported interface of the rocket driver to - * its configuration program. - */ - -struct rocket_config { - int line; - int flags; - int closing_wait; - int close_delay; - int port; - int reserved[32]; -}; - -struct rocket_ports { - int tty_major; - int callout_major; - int port_bitmap[4]; - int reserved[32]; -}; - -/* - * Rocketport flags - */ -#define ROCKET_CALLOUT_NOHUP 0x00000001 -#define ROCKET_FORCE_CD 0x00000002 -#define ROCKET_HUP_NOTIFY 0x00000004 -#define ROCKET_SPLIT_TERMIOS 0x00000008 -#define ROCKET_SPD_MASK 0x00000070 -#define ROCKET_SPD_HI 0x00000010 /* Use 56000 instead of 38400 bps */ -#define ROCKET_SPD_VHI 0x00000020 /* Use 115200 instead of 38400 bps*/ -#define ROCKET_SPD_SHI 0x00000030 /* Use 230400 instead of 38400 bps*/ -#define ROCKET_SPD_WARP 0x00000040 /* Use 460800 instead of 38400 bps*/ -#define ROCKET_SAK 0x00000080 -#define ROCKET_SESSION_LOCKOUT 0x00000100 -#define ROCKET_PGRP_LOCKOUT 0x00000200 - -#define ROCKET_FLAGS 0x000003FF - -#define ROCKET_USR_MASK 0x0071 /* Legal flags that non-privileged - * users can set or reset */ - -/* - * For closing_wait and closing_wait2 - */ -#define ROCKET_CLOSING_WAIT_NONE 65535 -#define ROCKET_CLOSING_WAIT_INF 0 - -/* - * Rocketport ioctls -- "RP" - */ -#define RCKP_GET_STRUCT 0x00525001 -#define RCKP_GET_CONFIG 0x00525002 -#define RCKP_SET_CONFIG 0x00525003 -#define RCKP_GET_PORTS 0x00525004 diff -Nru a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h --- a/include/linux/rtnetlink.h Mon Jun 9 23:16:16 2003 +++ b/include/linux/rtnetlink.h Mon Jun 9 23:16:16 2003 @@ -50,7 +50,7 @@ #define RTM_MAX (RTM_BASE+31) /* - Generic structure for encapsulation optional route information. + Generic structure for encapsulation of optional route information. It is reminiscent of sockaddr, but with sa_family replaced with attribute type. */ @@ -603,8 +603,8 @@ #define rtnl_shlock_nowait() down_trylock(&rtnl_sem) #define rtnl_shunlock() do { up(&rtnl_sem); \ - if (rtnl && rtnl->receive_queue.qlen) \ - rtnl->data_ready(rtnl, 0); \ + if (rtnl && rtnl->sk_receive_queue.qlen) \ + rtnl->sk_data_ready(rtnl, 0); \ } while(0) extern void rtnl_lock(void); diff -Nru a/include/linux/sched.h b/include/linux/sched.h --- a/include/linux/sched.h Mon Jun 9 23:16:07 2003 +++ b/include/linux/sched.h Mon Jun 9 23:16:07 2003 @@ -288,11 +288,6 @@ uid_t uid; }; -#define get_current_user() ({ \ - struct user_struct *__user = current->user; \ - atomic_inc(&__user->__count); \ - __user; }) - extern struct user_struct *find_user(uid_t); extern struct user_struct root_user; @@ -317,6 +312,7 @@ unsigned long it_incr; /* interval specified in jiffies */ struct task_struct *it_process; /* process to send signal to */ struct timer_list it_timer; + struct sigqueue *sigq; /* signal queue entry. */ }; @@ -571,6 +567,10 @@ extern int kill_pg(pid_t, int, int); extern int kill_sl(pid_t, int, int); extern int kill_proc(pid_t, int, int); +extern struct sigqueue *sigqueue_alloc(void); +extern void sigqueue_free(struct sigqueue *); +extern int send_sigqueue(int, struct sigqueue *, struct task_struct *); +extern int send_group_sigqueue(int, struct sigqueue *, struct task_struct *); extern int do_sigaction(int, const struct k_sigaction *, struct k_sigaction *); extern int do_sigaltstack(const stack_t __user *, stack_t __user *, unsigned long); diff -Nru a/include/linux/serial167.h b/include/linux/serial167.h --- a/include/linux/serial167.h Mon Jun 9 23:16:09 2003 +++ b/include/linux/serial167.h Mon Jun 9 23:16:09 2003 @@ -43,8 +43,6 @@ int x_char; /* to be pushed out ASAP */ int x_break; int blocked_open; /* # of blocked opens */ - long session; /* Session of opening process */ - long pgrp; /* pgrp of opening process */ unsigned char *xmit_buf; int xmit_head; int xmit_tail; @@ -53,7 +51,6 @@ int default_timeout; struct work_struct tqueue; struct termios normal_termios; - struct termios callout_termios; wait_queue_head_t open_wait; wait_queue_head_t close_wait; struct cyclades_monitor mon; diff -Nru a/include/linux/serialP.h b/include/linux/serialP.h --- a/include/linux/serialP.h Mon Jun 9 23:16:07 2003 +++ b/include/linux/serialP.h Mon Jun 9 23:16:07 2003 @@ -50,7 +50,6 @@ unsigned short closing_wait; /* time to wait before closing */ struct async_icount icount; struct termios normal_termios; - struct termios callout_termios; int io_type; struct async_struct *info; struct pci_dev *dev; @@ -80,8 +79,6 @@ unsigned long last_active; int line; int blocked_open; /* # of blocked opens */ - long session; /* Session of opening process */ - long pgrp; /* pgrp of opening process */ struct circ_buf xmit; spinlock_t xmit_lock; u8 *iomem_base; diff -Nru a/include/linux/serial_core.h b/include/linux/serial_core.h --- a/include/linux/serial_core.h Mon Jun 9 23:16:07 2003 +++ b/include/linux/serial_core.h Mon Jun 9 23:16:07 2003 @@ -266,6 +266,7 @@ struct module *owner; const char *driver_name; const char *dev_name; + const char *devfs_name; int major; int minor; int nr; diff -Nru a/include/linux/signal.h b/include/linux/signal.h --- a/include/linux/signal.h Mon Jun 9 23:16:08 2003 +++ b/include/linux/signal.h Mon Jun 9 23:16:08 2003 @@ -1,6 +1,8 @@ #ifndef _LINUX_SIGNAL_H #define _LINUX_SIGNAL_H +#include <linux/list.h> +#include <linux/spinlock.h> #include <asm/signal.h> #include <asm/siginfo.h> @@ -10,12 +12,17 @@ */ struct sigqueue { - struct sigqueue *next; + struct list_head list; + spinlock_t *lock; + int flags; siginfo_t info; }; +/* flags values. */ +#define SIGQUEUE_PREALLOC 1 + struct sigpending { - struct sigqueue *head, **tail; + struct list_head list; sigset_t signal; }; @@ -197,8 +204,7 @@ static inline void init_sigpending(struct sigpending *sig) { sigemptyset(&sig->signal); - sig->head = NULL; - sig->tail = &sig->head; + INIT_LIST_HEAD(&sig->list); } extern long do_sigpending(void __user *, unsigned long); diff -Nru a/include/linux/smp.h b/include/linux/smp.h --- a/include/linux/smp.h Mon Jun 9 23:16:13 2003 +++ b/include/linux/smp.h Mon Jun 9 23:16:13 2003 @@ -84,14 +84,6 @@ #define MSG_RESCHEDULE 0x0003 /* Reschedule request from master CPU*/ #define MSG_CALL_FUNCTION 0x0004 /* Call function on all other CPUs */ -struct notifier_block; - -/* Need to know about CPUs going up/down? */ -extern int register_cpu_notifier(struct notifier_block *nb); -extern void unregister_cpu_notifier(struct notifier_block *nb); - -int cpu_up(unsigned int cpu); - /* * Mark the boot cpu "online" so that it can call console drivers in * printk() and can access its per-cpu storage. @@ -110,7 +102,6 @@ #define smp_call_function(func,info,retry,wait) ({ 0; }) #define on_each_cpu(func,info,retry,wait) ({ func(info); 0; }) static inline void smp_send_reschedule(int cpu) { } -static inline void smp_send_reschedule_all(void) { } #define cpu_online_map 1 #define cpu_online(cpu) ({ BUG_ON((cpu) != 0); 1; }) #define num_online_cpus() 1 @@ -118,16 +109,6 @@ #define cpu_possible(cpu) ({ BUG_ON((cpu) != 0); 1; }) #define smp_prepare_boot_cpu() do {} while (0) -struct notifier_block; - -/* Need to know about CPUs going up/down? */ -static inline int register_cpu_notifier(struct notifier_block *nb) -{ - return 0; -} -static inline void unregister_cpu_notifier(struct notifier_block *nb) -{ -} #endif /* !SMP */ #define get_cpu() ({ preempt_disable(); smp_processor_id(); }) diff -Nru a/include/linux/spinlock.h b/include/linux/spinlock.h --- a/include/linux/spinlock.h Mon Jun 9 23:16:12 2003 +++ b/include/linux/spinlock.h Mon Jun 9 23:16:12 2003 @@ -13,6 +13,7 @@ #include <linux/kernel.h> #include <linux/stringify.h> +#include <asm/processor.h> /* for cpu relax */ #include <asm/system.h> /* diff -Nru a/include/linux/stallion.h b/include/linux/stallion.h --- a/include/linux/stallion.h Mon Jun 9 23:16:18 2003 +++ b/include/linux/stallion.h Mon Jun 9 23:16:18 2003 @@ -84,8 +84,6 @@ int refcount; int openwaitcnt; int brklen; - long session; - long pgrp; unsigned int sigs; unsigned int rxignoremsk; unsigned int rxmarkmsk; @@ -103,7 +101,6 @@ wait_queue_head_t close_wait; #endif struct termios normaltermios; - struct termios callouttermios; struct work_struct tqueue; comstats_t stats; stlrq_t tx; diff -Nru a/include/linux/sysctl.h b/include/linux/sysctl.h --- a/include/linux/sysctl.h Mon Jun 9 23:16:13 2003 +++ b/include/linux/sysctl.h Mon Jun 9 23:16:13 2003 @@ -156,6 +156,7 @@ VM_HUGETLB_PAGES=18, /* int: Number of available Huge Pages */ VM_SWAPPINESS=19, /* Tendency to steal mapped memory */ VM_LOWER_ZONE_PROTECTION=20,/* Amount of protection of lower zones */ + VM_MIN_FREE_KBYTES=21, /* Minimum free kilobytes to maintain */ }; @@ -307,7 +308,8 @@ NET_IPV4_ICMP_RATEMASK=90, NET_TCP_TW_REUSE=91, NET_TCP_FRTO=92, - NET_TCP_LOW_LATENCY=93 + NET_TCP_LOW_LATENCY=93, + NET_IPV4_IPFRAG_SECRET_INTERVAL=94, }; enum { @@ -365,7 +367,11 @@ NET_IPV6_NEIGH=17, NET_IPV6_ROUTE=18, NET_IPV6_ICMP=19, - NET_IPV6_BINDV6ONLY=20 + NET_IPV6_BINDV6ONLY=20, + NET_IPV6_IP6FRAG_HIGH_THRESH=21, + NET_IPV6_IP6FRAG_LOW_THRESH=22, + NET_IPV6_IP6FRAG_TIME=23, + NET_IPV6_IP6FRAG_SECRET_INTERVAL=24 }; enum { diff -Nru a/include/linux/sysfs.h b/include/linux/sysfs.h --- a/include/linux/sysfs.h Mon Jun 9 23:16:10 2003 +++ b/include/linux/sysfs.h Mon Jun 9 23:16:10 2003 @@ -23,6 +23,9 @@ ssize_t (*write)(struct kobject *, char *, loff_t, size_t); }; +int sysfs_create_bin_file(struct kobject * kobj, struct bin_attribute * attr); +int sysfs_remove_bin_file(struct kobject * kobj, struct bin_attribute * attr); + struct sysfs_ops { ssize_t (*show)(struct kobject *, struct attribute *,char *); ssize_t (*store)(struct kobject *,struct attribute *,const char *, size_t); diff -Nru a/include/linux/tcp.h b/include/linux/tcp.h --- a/include/linux/tcp.h Mon Jun 9 23:16:11 2003 +++ b/include/linux/tcp.h Mon Jun 9 23:16:11 2003 @@ -17,11 +17,8 @@ #ifndef _LINUX_TCP_H #define _LINUX_TCP_H -#include <linux/config.h> -#include <linux/skbuff.h> +#include <linux/types.h> #include <asm/byteorder.h> -#include <net/sock.h> -#include <linux/ip.h> struct tcphdr { __u16 source; @@ -188,6 +185,13 @@ __u32 tcpi_reordering; }; +#ifdef __KERNEL__ + +#include <linux/config.h> +#include <linux/skbuff.h> +#include <linux/ip.h> +#include <net/sock.h> + /* This defines a selective acknowledgement block. */ struct tcp_sack_block { __u32 start_seq; @@ -383,5 +387,7 @@ }; #define tcp_sk(__sk) (&((struct tcp_sock *)__sk)->tcp) + +#endif #endif /* _LINUX_TCP_H */ diff -Nru a/include/linux/timex.h b/include/linux/timex.h --- a/include/linux/timex.h Mon Jun 9 23:16:06 2003 +++ b/include/linux/timex.h Mon Jun 9 23:16:06 2003 @@ -51,6 +51,9 @@ #ifndef _LINUX_TIMEX_H #define _LINUX_TIMEX_H +#include <linux/config.h> +#include <linux/compiler.h> + #include <asm/param.h> /* @@ -309,6 +312,105 @@ extern long pps_calcnt; /* calibration intervals */ extern long pps_errcnt; /* calibration errors */ extern long pps_stbcnt; /* stability limit exceeded */ + +#ifdef CONFIG_TIME_INTERPOLATION + +struct time_interpolator { + /* cache-hot stuff first: */ + unsigned long (*get_offset) (void); + void (*update) (long); + void (*reset) (void); + + /* cache-cold stuff follows here: */ + struct time_interpolator *next; + unsigned long frequency; /* frequency in counts/second */ + long drift; /* drift in parts-per-million (or -1) */ +}; + +extern volatile unsigned long last_nsec_offset; +#ifndef __HAVE_ARCH_CMPXCHG +extern spin_lock_t last_nsec_offset_lock; +#endif +extern struct time_interpolator *time_interpolator; + +extern void register_time_interpolator(struct time_interpolator *); +extern void unregister_time_interpolator(struct time_interpolator *); + +/* Called with xtime WRITE-lock acquired. */ +static inline void +time_interpolator_update(long delta_nsec) +{ + struct time_interpolator *ti = time_interpolator; + + if (last_nsec_offset > 0) { +#ifdef __HAVE_ARCH_CMPXCHG + unsigned long new, old; + + do { + old = last_nsec_offset; + if (old > delta_nsec) + new = old - delta_nsec; + else + new = 0; + } while (cmpxchg(&last_nsec_offset, old, new) != old); +#else + /* + * This really hurts, because it serializes gettimeofday(), but without an + * atomic single-word compare-and-exchange, there isn't all that much else + * we can do. + */ + spin_lock(&last_nsec_offset_lock); + { + last_nsec_offset -= min(last_nsec_offset, delta_nsec); + } + spin_unlock(&last_nsec_offset_lock); +#endif + } + + if (ti) + (*ti->update)(delta_nsec); +} + +/* Called with xtime WRITE-lock acquired. */ +static inline void +time_interpolator_reset(void) +{ + struct time_interpolator *ti = time_interpolator; + + last_nsec_offset = 0; + if (ti) + (*ti->reset)(); +} + +/* Called with xtime READ-lock acquired. */ +static inline unsigned long +time_interpolator_get_offset(void) +{ + struct time_interpolator *ti = time_interpolator; + if (ti) + return (*ti->get_offset)(); + return last_nsec_offset; +} + +#else /* !CONFIG_TIME_INTERPOLATION */ + +static inline void +time_interpolator_update(long delta_nsec) +{ +} + +static inline void +time_interpolator_reset(void) +{ +} + +static inline unsigned long +time_interpolator_get_offset(void) +{ + return 0; +} + +#endif /* !CONFIG_TIME_INTERPOLATION */ #endif /* KERNEL */ diff -Nru a/include/linux/topology.h b/include/linux/topology.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/linux/topology.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,51 @@ +/* + * include/linux/topology.h + * + * Written by: Matthew Dobson, IBM Corporation + * + * Copyright (C) 2002, IBM Corp. + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, 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, GOOD TITLE or + * NON INFRINGEMENT. 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. + * + * Send feedback to <colpatch@us.ibm.com> + */ +#ifndef _LINUX_TOPOLOGY_H +#define _LINUX_TOPOLOGY_H + +#include <linux/bitops.h> +#include <linux/mmzone.h> +#include <linux/smp.h> + +#include <asm/topology.h> + +#ifndef nr_cpus_node +#define nr_cpus_node(node) (hweight_long(node_to_cpumask(node))) +#endif + +static inline int __next_node_with_cpus(int node) +{ + do + ++node; + while (node < numnodes && !nr_cpus_node(node)); + return node; +} + +#define for_each_node_with_cpus(node) \ + for (node = 0; node < numnodes; node = __next_node_with_cpus(node)) + +#endif /* _LINUX_TOPOLOGY_H */ diff -Nru a/include/linux/trdevice.h b/include/linux/trdevice.h --- a/include/linux/trdevice.h Mon Jun 9 23:16:08 2003 +++ b/include/linux/trdevice.h Mon Jun 9 23:16:08 2003 @@ -34,10 +34,7 @@ extern int tr_rebuild_header(struct sk_buff *skb); extern unsigned short tr_type_trans(struct sk_buff *skb, struct net_device *dev); extern void tr_source_route(struct sk_buff *skb, struct trh_hdr *trh, struct net_device *dev); -extern struct net_device *init_trdev(struct net_device *dev, int sizeof_priv); extern struct net_device *alloc_trdev(int sizeof_priv); -extern int register_trdev(struct net_device *dev); -extern void unregister_trdev(struct net_device *dev); #endif diff -Nru a/include/linux/tty_driver.h b/include/linux/tty_driver.h --- a/include/linux/tty_driver.h Mon Jun 9 23:16:14 2003 +++ b/include/linux/tty_driver.h Mon Jun 9 23:16:14 2003 @@ -124,6 +124,7 @@ struct cdev cdev; struct module *owner; const char *driver_name; + const char *devfs_name; const char *name; int name_base; /* offset of printed name */ short major; /* major device number */ diff -Nru a/include/linux/udp.h b/include/linux/udp.h --- a/include/linux/udp.h Mon Jun 9 23:16:08 2003 +++ b/include/linux/udp.h Mon Jun 9 23:16:08 2003 @@ -17,10 +17,7 @@ #ifndef _LINUX_UDP_H #define _LINUX_UDP_H -#include <linux/config.h> -#include <asm/byteorder.h> -#include <net/sock.h> -#include <linux/ip.h> +#include <linux/types.h> struct udphdr { __u16 source; @@ -36,6 +33,12 @@ /* UDP encapsulation types */ #define UDP_ENCAP_ESPINUDP 2 /* draft-ietf-ipsec-udp-encaps-06 */ +#ifdef __KERNEL__ + +#include <linux/config.h> +#include <net/sock.h> +#include <linux/ip.h> + struct udp_opt { int pending; /* Any pending frames ? */ unsigned int corkflag; /* Cork is required */ @@ -62,5 +65,7 @@ }; #define udp_sk(__sk) (&((struct udp_sock *)__sk)->udp) + +#endif #endif /* _LINUX_UDP_H */ diff -Nru a/include/linux/usb.h b/include/linux/usb.h --- a/include/linux/usb.h Mon Jun 9 23:16:10 2003 +++ b/include/linux/usb.h Mon Jun 9 23:16:10 2003 @@ -278,6 +278,8 @@ /* mostly for devices emulating SCSI over USB */ extern int usb_reset_device(struct usb_device *dev); +extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id); + /* for drivers using iso endpoints */ extern int usb_get_current_frame_number (struct usb_device *usb_dev); diff -Nru a/include/linux/wanrouter.h b/include/linux/wanrouter.h --- a/include/linux/wanrouter.h Mon Jun 9 23:16:09 2003 +++ b/include/linux/wanrouter.h Mon Jun 9 23:16:09 2003 @@ -534,7 +534,8 @@ /* Public Data */ -extern struct wan_device *router_devlist; /* list of registered devices */ +/* list of registered devices */ +extern struct wan_device *wanrouter_router_devlist; #endif /* __KERNEL__ */ #endif /* _ROUTER_H */ diff -Nru a/include/linux/writeback.h b/include/linux/writeback.h --- a/include/linux/writeback.h Mon Jun 9 23:16:07 2003 +++ b/include/linux/writeback.h Mon Jun 9 23:16:07 2003 @@ -78,6 +78,10 @@ extern int dirty_writeback_centisecs; extern int dirty_expire_centisecs; +struct ctl_table; +struct file; +int dirty_writeback_centisecs_handler(struct ctl_table *, int, struct file *, + void *, size_t *); void page_writeback_init(void); void balance_dirty_pages(struct address_space *mapping); diff -Nru a/include/linux/xfrm.h b/include/linux/xfrm.h --- a/include/linux/xfrm.h Mon Jun 9 23:16:08 2003 +++ b/include/linux/xfrm.h Mon Jun 9 23:16:08 2003 @@ -44,7 +44,7 @@ uid_t user; }; -#define XFRM_INF (~(u64)0) +#define XFRM_INF (~(__u64)0) struct xfrm_lifetime_cfg { @@ -164,7 +164,7 @@ }; struct xfrm_usersa_id { - xfrm_address_t saddr; + xfrm_address_t daddr; __u32 spi; __u16 family; __u8 proto; diff -Nru a/include/linux/zconf.h b/include/linux/zconf.h --- a/include/linux/zconf.h Mon Jun 9 23:16:16 2003 +++ b/include/linux/zconf.h Mon Jun 9 23:16:16 2003 @@ -8,18 +8,6 @@ #ifndef _ZCONF_H #define _ZCONF_H -#if defined(__GNUC__) || defined(__386__) || defined(i386) -# ifndef __32BIT__ -# define __32BIT__ -# endif -#endif - -#if defined(__STDC__) || defined(__cplusplus) -# ifndef STDC -# define STDC -# endif -#endif - /* The memory requirements for deflate are (in bytes): (1 << (windowBits+2)) + (1 << (memLevel+9)) that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) @@ -35,7 +23,7 @@ /* Maximum value for memLevel in deflateInit2 */ #ifndef MAX_MEM_LEVEL -# define MAX_MEM_LEVEL 9 +# define MAX_MEM_LEVEL 8 #endif /* Maximum value for windowBits in deflateInit2 and inflateInit2. @@ -49,42 +37,9 @@ /* Type declarations */ -#ifndef OF /* function prototypes */ -# ifdef STDC -# define OF(args) args -# else -# define OF(args) () -# endif -#endif - -#ifndef ZEXPORT -# define ZEXPORT -#endif -#ifndef ZEXPORTVA -# define ZEXPORTVA -#endif -#ifndef ZEXTERN -# define ZEXTERN extern -#endif -#ifndef FAR -# define FAR -#endif - typedef unsigned char Byte; /* 8 bits */ typedef unsigned int uInt; /* 16 bits or more */ typedef unsigned long uLong; /* 32 bits or more */ - -typedef Byte FAR Bytef; -typedef char FAR charf; -typedef int FAR intf; -typedef uInt FAR uIntf; -typedef uLong FAR uLongf; - -typedef void FAR *voidpf; typedef void *voidp; - -#include <linux/types.h> /* for off_t */ -#include <linux/unistd.h> /* for SEEK_* and off_t */ -#define z_off_t off_t #endif /* _ZCONF_H */ diff -Nru a/include/linux/zlib.h b/include/linux/zlib.h --- a/include/linux/zlib.h Mon Jun 9 23:16:13 2003 +++ b/include/linux/zlib.h Mon Jun 9 23:16:13 2003 @@ -33,10 +33,6 @@ #include <linux/zconf.h> -#ifdef __cplusplus -extern "C" { -#endif - #define ZLIB_VERSION "1.1.3" /* @@ -60,22 +56,19 @@ crash even in case of corrupted input. */ -typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); -typedef void (*free_func) OF((voidpf opaque, voidpf address)); - struct internal_state; typedef struct z_stream_s { - Bytef *next_in; /* next input byte */ + Byte *next_in; /* next input byte */ uInt avail_in; /* number of bytes available at next_in */ uLong total_in; /* total nb of input bytes read so far */ - Bytef *next_out; /* next output byte should be put there */ + Byte *next_out; /* next output byte should be put there */ uInt avail_out; /* remaining free space at next_out */ uLong total_out; /* total nb of bytes output so far */ char *msg; /* last error message, NULL if no error */ - struct internal_state FAR *state; /* not visible by applications */ + struct internal_state *state; /* not visible by applications */ void *workspace; /* memory allocated for this stream */ @@ -84,7 +77,7 @@ uLong reserved; /* reserved for future use */ } z_stream; -typedef z_stream FAR *z_streamp; +typedef z_stream *z_streamp; /* The application must update next_in and avail_in when avail_in has @@ -98,7 +91,7 @@ memory management. The compression library attaches no meaning to the opaque value. - zalloc must return Z_NULL if there is not enough memory for the object. + zalloc must return NULL if there is not enough memory for the object. If zlib is used in a multi-threaded application, zalloc and zfree must be thread safe. @@ -160,18 +153,16 @@ #define Z_DEFLATED 8 /* The deflate compression method (the only one supported in this version) */ -#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ - /* basic functions */ -ZEXTERN const char * ZEXPORT zlib_zlibVersion OF((void)); +extern const char * zlib_zlibVersion (void); /* The application can compare zlibVersion and ZLIB_VERSION for consistency. If the first character differs, the library code actually used is not compatible with the zlib.h header file used by the application. This check is automatically made by deflateInit and inflateInit. */ -ZEXTERN int ZEXPORT zlib_deflate_workspacesize OF((void)); +extern int zlib_deflate_workspacesize (void); /* Returns the number of bytes that needs to be allocated for a per- stream workspace. A pointer to this number of bytes should be @@ -179,11 +170,11 @@ */ /* -ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); +extern int deflateInit (z_streamp strm, int level); Initializes the internal stream state for compression. The fields zalloc, zfree and opaque must be initialized before by the caller. - If zalloc and zfree are set to Z_NULL, deflateInit updates them to + If zalloc and zfree are set to NULL, deflateInit updates them to use default allocation functions. The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: @@ -201,7 +192,7 @@ */ -ZEXTERN int ZEXPORT zlib_deflate OF((z_streamp strm, int flush)); +extern int zlib_deflate (z_streamp strm, int flush); /* deflate compresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may introduce some @@ -279,7 +270,7 @@ */ -ZEXTERN int ZEXPORT zlib_deflateEnd OF((z_streamp strm)); +extern int zlib_deflateEnd (z_streamp strm); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any @@ -293,7 +284,7 @@ */ -ZEXTERN int ZEXPORT zlib_inflate_workspacesize OF((void)); +extern int zlib_inflate_workspacesize (void); /* Returns the number of bytes that needs to be allocated for a per- stream workspace. A pointer to this number of bytes should be @@ -301,15 +292,15 @@ */ /* -ZEXTERN int ZEXPORT zlib_inflateInit OF((z_streamp strm)); +extern int zlib_inflateInit (z_streamp strm); Initializes the internal stream state for decompression. The fields next_in, avail_in, and workspace must be initialized before by - the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + the caller. If next_in is not NULL and avail_in is large enough (the exact value depends on the compression method), inflateInit determines the compression method from the zlib header and allocates all data structures accordingly; otherwise the allocation will be deferred to the first call of - inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + inflate. If zalloc and zfree are set to NULL, inflateInit updates them to use default allocation functions. inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough @@ -321,7 +312,7 @@ */ -ZEXTERN int ZEXPORT zlib_inflate OF((z_streamp strm, int flush)); +extern int zlib_inflate (z_streamp strm, int flush); /* inflate decompresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may some @@ -390,7 +381,7 @@ */ -ZEXTERN int ZEXPORT zlib_inflateEnd OF((z_streamp strm)); +extern int zlib_inflateEnd (z_streamp strm); /* All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any @@ -408,12 +399,12 @@ */ /* -ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, +extern int deflateInit2 (z_streamp strm, int level, int method, int windowBits, int memLevel, - int strategy)); + int strategy); This is another version of deflateInit with more compression options. The fields next_in, zalloc, zfree and opaque must be initialized before by @@ -451,9 +442,9 @@ not perform any compression: this will be done by deflate(). */ -ZEXTERN int ZEXPORT zlib_deflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); +extern int zlib_deflateSetDictionary (z_streamp strm, + const Byte *dictionary, + uInt dictLength); /* Initializes the compression dictionary from the given byte sequence without producing any compressed output. This function must be called @@ -487,8 +478,7 @@ perform any compression: this will be done by deflate(). */ -ZEXTERN int ZEXPORT zlib_deflateCopy OF((z_streamp dest, - z_streamp source)); +extern int zlib_deflateCopy (z_streamp dest, z_streamp source); /* Sets the destination stream as a complete copy of the source stream. @@ -505,7 +495,7 @@ destination. */ -ZEXTERN int ZEXPORT zlib_deflateReset OF((z_streamp strm)); +extern int zlib_deflateReset (z_streamp strm); /* This function is equivalent to deflateEnd followed by deflateInit, but does not free and reallocate all the internal compression state. @@ -516,9 +506,7 @@ stream state was inconsistent (such as zalloc or state being NULL). */ -ZEXTERN int ZEXPORT zlib_deflateParams OF((z_streamp strm, - int level, - int strategy)); +extern int zlib_deflateParams (z_streamp strm, int level, int strategy); /* Dynamically update the compression level and compression strategy. The interpretation of level and strategy is as in deflateInit2. This can be @@ -538,8 +526,7 @@ */ /* -ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, - int windowBits)); +extern int inflateInit2 (z_streamp strm, int windowBits); This is another version of inflateInit with an extra parameter. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized @@ -560,9 +547,9 @@ modified, but next_out and avail_out are unchanged.) */ -ZEXTERN int ZEXPORT zlib_inflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); +extern int zlib_inflateSetDictionary (z_streamp strm, + const Byte *dictionary, + uInt dictLength); /* Initializes the decompression dictionary from the given uncompressed byte sequence. This function must be called immediately after a call of inflate @@ -579,7 +566,7 @@ inflate(). */ -ZEXTERN int ZEXPORT zlib_inflateSync OF((z_streamp strm)); +extern int zlib_inflateSync (z_streamp strm); /* Skips invalid compressed data until a full flush point (see above the description of deflate with Z_FULL_FLUSH) can be found, or until all @@ -594,7 +581,7 @@ until success or end of the input data. */ -ZEXTERN int ZEXPORT zlib_inflateReset OF((z_streamp strm)); +extern int zlib_inflateReset (z_streamp strm); /* This function is equivalent to inflateEnd followed by inflateInit, but does not free and reallocate all the internal decompression state. @@ -604,7 +591,7 @@ stream state was inconsistent (such as zalloc or state being NULL). */ -extern int ZEXPORT zlib_inflateIncomp OF((z_stream *strm)); +extern int zlib_inflateIncomp (z_stream *strm); /* This function adds the data at next_in (avail_in bytes) to the output history without performing any output. There must be no pending output, @@ -618,16 +605,16 @@ /* deflateInit and inflateInit are macros to allow checking the zlib version * and the compiler's view of z_stream: */ -ZEXTERN int ZEXPORT zlib_deflateInit_ OF((z_streamp strm, int level, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT zlib_inflateInit_ OF((z_streamp strm, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT zlib_deflateInit2_ OF((z_streamp strm, int level, int method, +extern int zlib_deflateInit_ (z_streamp strm, int level, + const char *version, int stream_size); +extern int zlib_inflateInit_ (z_streamp strm, + const char *version, int stream_size); +extern int zlib_deflateInit2_ (z_streamp strm, int level, int method, int windowBits, int memLevel, int strategy, const char *version, - int stream_size)); -ZEXTERN int ZEXPORT zlib_inflateInit2_ OF((z_streamp strm, int windowBits, - const char *version, int stream_size)); + int stream_size); +extern int zlib_inflateInit2_ (z_streamp strm, int windowBits, + const char *version, int stream_size); #define zlib_deflateInit(strm, level) \ zlib_deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) #define zlib_inflateInit(strm) \ @@ -643,12 +630,8 @@ struct internal_state {int dummy;}; /* hack for buggy compilers */ #endif -ZEXTERN const char * ZEXPORT zlib_zError OF((int err)); -ZEXTERN int ZEXPORT zlib_inflateSyncPoint OF((z_streamp z)); -ZEXTERN const uLongf * ZEXPORT zlib_get_crc_table OF((void)); - -#ifdef __cplusplus -} -#endif +extern const char * zlib_zError (int err); +extern int zlib_inflateSyncPoint (z_streamp z); +extern const uLong * zlib_get_crc_table (void); #endif /* _ZLIB_H */ diff -Nru a/include/linux/zutil.h b/include/linux/zutil.h --- a/include/linux/zutil.h Mon Jun 9 23:16:14 2003 +++ b/include/linux/zutil.h Mon Jun 9 23:16:14 2003 @@ -18,15 +18,8 @@ #include <linux/errno.h> #include <linux/kernel.h> -#ifndef local -# define local static -#endif -/* compile with -Dlocal if your debugger can't find static symbols */ - typedef unsigned char uch; -typedef uch FAR uchf; typedef unsigned short ush; -typedef ush FAR ushf; typedef unsigned long ulg; /* common constants */ @@ -64,8 +57,8 @@ /* functions */ -typedef uLong (ZEXPORT *check_func) OF((uLong check, const Bytef *buf, - uInt len)); +typedef uLong (*check_func) (uLong check, const Byte *buf, + uInt len); /* checksum functions */ @@ -88,7 +81,7 @@ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed much faster. Usage example: - uLong adler = adler32(0L, Z_NULL, 0); + uLong adler = adler32(0L, NULL, 0); while (read_buffer(buffer, length) != EOF) { adler = adler32(adler, buffer, length); @@ -96,14 +89,14 @@ if (adler != original_adler) error(); */ static inline uLong zlib_adler32(uLong adler, - const Bytef *buf, + const Byte *buf, uInt len) { unsigned long s1 = adler & 0xffff; unsigned long s2 = (adler >> 16) & 0xffff; int k; - if (buf == Z_NULL) return 1L; + if (buf == NULL) return 1L; while (len > 0) { k = len < NMAX ? len : NMAX; diff -Nru a/include/net/af_unix.h b/include/net/af_unix.h --- a/include/net/af_unix.h Mon Jun 9 23:16:16 2003 +++ b/include/net/af_unix.h Mon Jun 9 23:16:16 2003 @@ -24,8 +24,8 @@ static inline unix_socket *next_unix_socket(int *i, unix_socket *s) { /* More in this chain? */ - if (s->next) - return s->next; + if (s->sk_next) + return s->sk_next; /* Look for next non-empty chain. */ for ((*i)++; *i <= UNIX_HASH_SIZE; (*i)++) { if (unix_socket_table[*i]) diff -Nru a/include/net/ax25.h b/include/net/ax25.h --- a/include/net/ax25.h Mon Jun 9 23:16:15 2003 +++ b/include/net/ax25.h Mon Jun 9 23:16:15 2003 @@ -201,7 +201,7 @@ struct sock *sk; /* Backlink to socket */ } ax25_cb; -#define ax25_sk(__sk) ((ax25_cb *)(__sk)->protinfo) +#define ax25_sk(__sk) ((ax25_cb *)(__sk)->sk_protinfo) /* af_ax25.c */ extern ax25_cb *ax25_list; @@ -233,7 +233,12 @@ /* ax25_dev.c */ extern ax25_dev *ax25_dev_list; extern spinlock_t ax25_dev_lock; -extern ax25_dev *ax25_dev_ax25dev(struct net_device *); + +static inline ax25_dev *ax25_dev_ax25dev(struct net_device *dev) +{ + return dev->ax25_ptr; +} + extern ax25_dev *ax25_addr_ax25dev(ax25_address *); extern void ax25_dev_device_up(struct net_device *); extern void ax25_dev_device_down(struct net_device *); diff -Nru a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h --- a/include/net/bluetooth/hci_core.h Mon Jun 9 23:16:13 2003 +++ b/include/net/bluetooth/hci_core.h Mon Jun 9 23:16:13 2003 @@ -485,7 +485,7 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb); /* HCI info for socket */ -#define hci_pi(sk) ((struct hci_pinfo *) sk->protinfo) +#define hci_pi(sk) ((struct hci_pinfo *)sk->sk_protinfo) struct hci_pinfo { struct hci_dev *hdev; struct hci_filter filter; diff -Nru a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h --- a/include/net/bluetooth/l2cap.h Mon Jun 9 23:16:08 2003 +++ b/include/net/bluetooth/l2cap.h Mon Jun 9 23:16:08 2003 @@ -206,7 +206,7 @@ }; /* ----- L2CAP channel and socket info ----- */ -#define l2cap_pi(sk) ((struct l2cap_pinfo *) sk->protinfo) +#define l2cap_pi(sk) ((struct l2cap_pinfo *)sk->sk_protinfo) struct l2cap_pinfo { __u16 psm; diff -Nru a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h --- a/include/net/bluetooth/rfcomm.h Mon Jun 9 23:16:16 2003 +++ b/include/net/bluetooth/rfcomm.h Mon Jun 9 23:16:16 2003 @@ -302,7 +302,7 @@ u8 rc_channel; }; -#define rfcomm_pi(sk) ((struct rfcomm_pinfo *) sk->protinfo) +#define rfcomm_pi(sk) ((struct rfcomm_pinfo *)sk->sk_protinfo) struct rfcomm_pinfo { struct rfcomm_dlc *dlc; diff -Nru a/include/net/bluetooth/sco.h b/include/net/bluetooth/sco.h --- a/include/net/bluetooth/sco.h Mon Jun 9 23:16:08 2003 +++ b/include/net/bluetooth/sco.h Mon Jun 9 23:16:08 2003 @@ -71,7 +71,7 @@ #define sco_conn_unlock(c) spin_unlock(&c->lock); /* ----- SCO socket info ----- */ -#define sco_pi(sk) ((struct sco_pinfo *) sk->protinfo) +#define sco_pi(sk) ((struct sco_pinfo *)sk->sk_protinfo) struct sco_pinfo { __u32 flags; diff -Nru a/include/net/dn.h b/include/net/dn.h --- a/include/net/dn.h Mon Jun 9 23:16:15 2003 +++ b/include/net/dn.h Mon Jun 9 23:16:15 2003 @@ -133,7 +133,7 @@ }; -#define DN_SK(__sk) ((struct dn_scp *)(__sk)->protinfo) +#define DN_SK(__sk) ((struct dn_scp *)(__sk)->sk_protinfo) /* * src,dst : Source and Destination DECnet addresses diff -Nru a/include/net/dn_fib.h b/include/net/dn_fib.h --- a/include/net/dn_fib.h Mon Jun 9 23:16:12 2003 +++ b/include/net/dn_fib.h Mon Jun 9 23:16:12 2003 @@ -184,8 +184,8 @@ #else /* Endnode */ -#define dn_fib_init() (0) -#define dn_fib_cleanup() (0) +#define dn_fib_init() do { } while(0) +#define dn_fib_cleanup() do { } while(0) #define dn_fib_lookup(fl, res) (-ESRCH) #define dn_fib_info_put(fi) do { } while(0) diff -Nru a/include/net/dn_nsp.h b/include/net/dn_nsp.h --- a/include/net/dn_nsp.h Mon Jun 9 23:16:16 2003 +++ b/include/net/dn_nsp.h Mon Jun 9 23:16:16 2003 @@ -201,7 +201,7 @@ */ static __inline__ int dn_congested(struct sock *sk) { - return atomic_read(&sk->rmem_alloc) > (sk->rcvbuf >> 1); + return atomic_read(&sk->sk_rmem_alloc) > (sk->sk_rcvbuf >> 1); } #define DN_MAX_NSP_DATA_HEADER (11) diff -Nru a/include/net/flow.h b/include/net/flow.h --- a/include/net/flow.h Mon Jun 9 23:16:18 2003 +++ b/include/net/flow.h Mon Jun 9 23:16:18 2003 @@ -87,6 +87,7 @@ extern void *flow_cache_lookup(struct flowi *key, u16 family, u8 dir, flow_resolve_t resolver); +extern void flow_cache_flush(void *object); extern atomic_t flow_cache_genid; #endif diff -Nru a/include/net/ip.h b/include/net/ip.h --- a/include/net/ip.h Mon Jun 9 23:16:15 2003 +++ b/include/net/ip.h Mon Jun 9 23:16:15 2003 @@ -238,7 +238,7 @@ { inet_sk(sk)->rcv_saddr = inet_sk(sk)->saddr = 0; #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - if (sk->family == PF_INET6) { + if (sk->sk_family == PF_INET6) { struct ipv6_pinfo *np = inet6_sk(sk); memset(&np->saddr, 0, sizeof(np->saddr)); diff -Nru a/include/net/ip6_fib.h b/include/net/ip6_fib.h --- a/include/net/ip6_fib.h Mon Jun 9 23:16:16 2003 +++ b/include/net/ip6_fib.h Mon Jun 9 23:16:16 2003 @@ -111,9 +111,10 @@ struct rt6_statistics { __u32 fib_nodes; __u32 fib_route_nodes; - __u32 fib_rt_alloc; /* permanet routes */ + __u32 fib_rt_alloc; /* permanent routes */ __u32 fib_rt_entries; /* rt entries in table */ __u32 fib_rt_cache; /* cache routes */ + __u32 fib_discarded_routes; }; #define RTN_TL_ROOT 0x0001 diff -Nru a/include/net/ip6_route.h b/include/net/ip6_route.h --- a/include/net/ip6_route.h Mon Jun 9 23:16:08 2003 +++ b/include/net/ip6_route.h Mon Jun 9 23:16:08 2003 @@ -107,11 +107,11 @@ struct ipv6_pinfo *np = inet6_sk(sk); struct rt6_info *rt = (struct rt6_info *) dst; - write_lock(&sk->dst_lock); + write_lock(&sk->sk_dst_lock); __sk_dst_set(sk, dst); np->daddr_cache = daddr; np->dst_cookie = rt->rt6i_node ? rt->rt6i_node->fn_sernum : 0; - write_unlock(&sk->dst_lock); + write_unlock(&sk->sk_dst_lock); } #endif diff -Nru a/include/net/ip6_tunnel.h b/include/net/ip6_tunnel.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/net/ip6_tunnel.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,44 @@ +/* + * $Id$ + */ + +#ifndef _NET_IP6_TUNNEL_H +#define _NET_IP6_TUNNEL_H + +#include <linux/ipv6.h> +#include <linux/netdevice.h> +#include <linux/ip6_tunnel.h> + +/* capable of sending packets */ +#define IP6_TNL_F_CAP_XMIT 0x10000 +/* capable of receiving packets */ +#define IP6_TNL_F_CAP_RCV 0x20000 + +#define IP6_TNL_MAX 128 + +/* IPv6 tunnel */ + +struct ip6_tnl { + struct ip6_tnl *next; /* next tunnel in list */ + struct net_device *dev; /* virtual device associated with tunnel */ + struct net_device_stats stat; /* statistics for tunnel device */ + int recursion; /* depth of hard_start_xmit recursion */ + struct ip6_tnl_parm parms; /* tunnel configuration paramters */ + struct flowi fl; /* flowi template for xmit */ +}; + +/* Tunnel encapsulation limit destination sub-option */ + +struct ipv6_tlv_tnl_enc_lim { + __u8 type; /* type-code for option */ + __u8 length; /* option length */ + __u8 encap_limit; /* tunnel encapsulation limit */ +} __attribute__ ((packed)); + +#ifdef __KERNEL__ +#ifdef CONFIG_IPV6_TUNNEL +extern int __init ip6_tunnel_init(void); +extern void ip6_tunnel_cleanup(void); +#endif +#endif +#endif diff -Nru a/include/net/ipv6.h b/include/net/ipv6.h --- a/include/net/ipv6.h Mon Jun 9 23:16:17 2003 +++ b/include/net/ipv6.h Mon Jun 9 23:16:17 2003 @@ -145,7 +145,7 @@ int snmp6_register_dev(struct inet6_dev *idev); int snmp6_unregister_dev(struct inet6_dev *idev); -int snmp6_mib_init(void *ptr[2], size_t mibsize); +int snmp6_mib_init(void *ptr[2], size_t mibsize, size_t mibalign); void snmp6_mib_free(void *ptr[2]); struct ip6_ra_chain @@ -263,6 +263,21 @@ memcpy((void *) a1, (const void *) a2, sizeof(struct in6_addr)); } +static inline void ipv6_addr_prefix(struct in6_addr *pfx, + const struct in6_addr *addr, + int plen) +{ + /* caller must guarantee 0 <= plen <= 128 */ + int o = plen >> 3, + b = plen & 0x7; + + memcpy(pfx->s6_addr, addr, o); + if (b != 0) + pfx->s6_addr[o] = addr->s6_addr[o] & (0xff00 >> b); + if (o < 16) + memset(pfx->s6_addr + o, 0, 16 - o); +} + #ifndef __HAVE_ARCH_ADDR_SET static inline void ipv6_addr_set(struct in6_addr *addr, __u32 w1, __u32 w2, @@ -299,7 +314,8 @@ extern int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, - struct ipv6_txoptions *opt); + struct ipv6_txoptions *opt, + int ipfragok); extern int ip6_nd_hdr(struct sock *sk, struct sk_buff *skb, @@ -315,7 +331,7 @@ unsigned length, struct ipv6_txoptions *opt, int hlimit, int flags); -extern int ip6_found_nexthdr(struct sk_buff *skb, u8 **nexthdr); +extern int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr); extern int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb), @@ -405,6 +421,14 @@ int *uaddr_len, int peer); extern int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); + +/* + * reassembly.c + */ +extern int sysctl_ip6frag_high_thresh; +extern int sysctl_ip6frag_low_thresh; +extern int sysctl_ip6frag_time; +extern int sysctl_ip6frag_secret_interval; #endif /* __KERNEL__ */ #endif /* _NET_IPV6_H */ diff -Nru a/include/net/ipx.h b/include/net/ipx.h --- a/include/net/ipx.h Mon Jun 9 23:16:07 2003 +++ b/include/net/ipx.h Mon Jun 9 23:16:07 2003 @@ -105,7 +105,7 @@ unsigned short ipx_ncp_conn; }; -#define ipx_sk(__sk) ((struct ipx_opt *)(__sk)->protinfo) +#define ipx_sk(__sk) ((struct ipx_opt *)(__sk)->sk_protinfo) #define IPX_SKB_CB(__skb) ((struct ipx_cb *)&((__skb)->cb[0])) #endif #define IPX_MIN_EPHEMERAL_SOCKET 0x4000 diff -Nru a/include/net/irda/af_irda.h b/include/net/irda/af_irda.h --- a/include/net/irda/af_irda.h Mon Jun 9 23:16:18 2003 +++ b/include/net/irda/af_irda.h Mon Jun 9 23:16:18 2003 @@ -77,6 +77,6 @@ LOCAL_FLOW rx_flow; }; -#define irda_sk(__sk) ((struct irda_sock *)(__sk)->protinfo) +#define irda_sk(__sk) ((struct irda_sock *)(__sk)->sk_protinfo) #endif /* AF_IRDA_H */ diff -Nru a/include/net/irda/ircomm_tty.h b/include/net/irda/ircomm_tty.h --- a/include/net/irda/ircomm_tty.h Mon Jun 9 23:16:10 2003 +++ b/include/net/irda/ircomm_tty.h Mon Jun 9 23:16:10 2003 @@ -93,7 +93,6 @@ void *ckey; struct termios normal_termios; - struct termios callout_termios; wait_queue_head_t open_wait; wait_queue_head_t close_wait; @@ -103,8 +102,6 @@ unsigned short close_delay; unsigned short closing_wait; /* time to wait before closing */ - long session; /* Session of opening process */ - long pgrp; /* pgrp of opening process */ int open_count; int blocked_open; /* # of blocked opens */ diff -Nru a/include/net/llc_c_ev.h b/include/net/llc_c_ev.h --- a/include/net/llc_c_ev.h Mon Jun 9 23:16:07 2003 +++ b/include/net/llc_c_ev.h Mon Jun 9 23:16:07 2003 @@ -275,7 +275,7 @@ static __inline__ int llc_conn_space(struct sock *sk, struct sk_buff *skb) { - return atomic_read(&sk->rmem_alloc) + skb->truesize < - (unsigned)sk->rcvbuf; + return atomic_read(&sk->sk_rmem_alloc) + skb->truesize < + (unsigned)sk->sk_rcvbuf; } #endif /* LLC_C_EV_H */ diff -Nru a/include/net/llc_conn.h b/include/net/llc_conn.h --- a/include/net/llc_conn.h Mon Jun 9 23:16:18 2003 +++ b/include/net/llc_conn.h Mon Jun 9 23:16:18 2003 @@ -67,7 +67,7 @@ Used for resending FRMR */ }; -#define llc_sk(__sk) ((struct llc_opt *)(__sk)->protinfo) +#define llc_sk(__sk) ((struct llc_opt *)(__sk)->sk_protinfo) extern struct sock *llc_sk_alloc(int family, int priority); extern void llc_sk_free(struct sock *sk); diff -Nru a/include/net/netrom.h b/include/net/netrom.h --- a/include/net/netrom.h Mon Jun 9 23:16:13 2003 +++ b/include/net/netrom.h Mon Jun 9 23:16:13 2003 @@ -74,7 +74,7 @@ struct sock *sk; /* Backlink to socket */ } nr_cb; -#define nr_sk(__sk) ((nr_cb *)(__sk)->protinfo) +#define nr_sk(__sk) ((nr_cb *)(__sk)->sk_protinfo) struct nr_neigh { struct nr_neigh *next; diff -Nru a/include/net/rose.h b/include/net/rose.h --- a/include/net/rose.h Mon Jun 9 23:16:07 2003 +++ b/include/net/rose.h Mon Jun 9 23:16:07 2003 @@ -138,7 +138,7 @@ struct sock *sk; /* Backlink to socket */ } rose_cb; -#define rose_sk(__sk) ((rose_cb *)(__sk)->protinfo) +#define rose_sk(__sk) ((rose_cb *)(__sk)->sk_protinfo) /* af_rose.c */ extern ax25_address rose_callsign; diff -Nru a/include/net/route.h b/include/net/route.h --- a/include/net/route.h Mon Jun 9 23:16:05 2003 +++ b/include/net/route.h Mon Jun 9 23:16:05 2003 @@ -44,7 +44,7 @@ /* RTO_CONN is not used (being alias for 0), but preserved not to break * some modules referring to it. */ -#define RT_CONN_FLAGS(sk) (RT_TOS(inet_sk(sk)->tos) | sk->localroute) +#define RT_CONN_FLAGS(sk) (RT_TOS(inet_sk(sk)->tos) | sk->sk_localroute) struct inet_peer; struct rtable diff -Nru a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h --- a/include/net/sctp/sctp.h Mon Jun 9 23:16:09 2003 +++ b/include/net/sctp/sctp.h Mon Jun 9 23:16:09 2003 @@ -597,7 +597,7 @@ #define sctp_sstate(sk, state) __sctp_sstate((sk), (SCTP_SS_##state)) int static inline __sctp_sstate(const struct sock *sk, sctp_sock_state_t state) { - return sk->state == state; + return sk->sk_state == state; } #endif /* __net_sctp_h__ */ diff -Nru a/include/net/snmp.h b/include/net/snmp.h --- a/include/net/snmp.h Mon Jun 9 23:16:10 2003 +++ b/include/net/snmp.h Mon Jun 9 23:16:10 2003 @@ -42,6 +42,11 @@ */ +/* + * RFC 1213: MIB-II + * RFC 2011 (updates 1213): SNMPv2-MIB-IP + * RFC 2863: Interfaces Group MIB + */ struct ip_mib { unsigned long IpInReceives; @@ -64,6 +69,9 @@ unsigned long __pad[0]; }; +/* + * RFC 2465: IPv6 MIB: General Group + */ struct ipv6_mib { unsigned long Ip6InReceives; @@ -91,6 +99,10 @@ unsigned long __pad[0]; }; +/* + * RFC 1213: MIB-II ICMP Group + * RFC 2011 (updates 1213): SNMPv2 MIB for IP: ICMP group + */ struct icmp_mib { unsigned long IcmpInMsgs; @@ -123,6 +135,9 @@ unsigned long __pad[0]; }; +/* + * RFC 2466: ICMPv6-MIB + */ struct icmpv6_mib { unsigned long Icmp6InMsgs; @@ -161,6 +176,10 @@ unsigned long __pad[0]; }; +/* + * RFC 1213: MIB-II TCP group + * RFC 2012 (updates 1213): SNMPv2-MIB-TCP + */ struct tcp_mib { unsigned long TcpRtoAlgorithm; @@ -180,6 +199,10 @@ unsigned long __pad[0]; }; +/* + * RFC 1213: MIB-II UDP group + * RFC 2013 (updates 1213): SNMPv2-MIB-UDP + */ struct udp_mib { unsigned long UdpInDatagrams; diff -Nru a/include/net/sock.h b/include/net/sock.h --- a/include/net/sock.h Mon Jun 9 23:16:16 2003 +++ b/include/net/sock.h Mon Jun 9 23:16:16 2003 @@ -59,21 +59,11 @@ * the other protocols. */ -/* Sock flags */ -enum { - SOCK_DEAD, - SOCK_DONE, - SOCK_URGINLINE, - SOCK_KEEPOPEN, - SOCK_LINGER, - SOCK_DESTROY, - SOCK_BROADCAST, -}; - -/* Define this to get the sk->debug debugging facility. */ +/* Define this to get the sk->sk_debug debugging facility. */ #define SOCK_DEBUGGING #ifdef SOCK_DEBUGGING -#define SOCK_DEBUG(sk, msg...) do { if((sk) && ((sk)->debug)) printk(KERN_DEBUG msg); } while (0) +#define SOCK_DEBUG(sk, msg...) do { if ((sk) && ((sk)->sk_debug)) \ + printk(KERN_DEBUG msg); } while (0) #else #define SOCK_DEBUG(sk, msg...) do { } while (0) #endif @@ -90,123 +80,147 @@ } socket_lock_t; #define sock_lock_init(__sk) \ -do { spin_lock_init(&((__sk)->lock.slock)); \ - (__sk)->lock.owner = NULL; \ - init_waitqueue_head(&((__sk)->lock.wq)); \ +do { spin_lock_init(&((__sk)->sk_lock.slock)); \ + (__sk)->sk_lock.owner = NULL; \ + init_waitqueue_head(&((__sk)->sk_lock.wq)); \ } while(0) +struct sock; + +/** + * struct sock_common - minimal network layer representation of sockets + * @skc_family - network address family + * @skc_state - Connection state + * @skc_reuse - %SO_REUSEADDR setting + * @skc_bound_dev_if - bound device index if != 0 + * @skc_next - main hash linkage for various protocol lookup tables + * @skc_pprev - main hash linkage for various protocol lookup tables + * @skc_bind_next - main hash linkage for various protocol lookup tables + * @skc_bind_pprev - main hash linkage for various protocol lookup tables + * @skc_refcnt - reference count + * + * This is the minimal network layer representation of sockets, the header + * for struct sock and struct tcp_tw_bucket. + */ +struct sock_common { + unsigned short skc_family; + volatile unsigned char skc_state; + unsigned char skc_reuse; + int skc_bound_dev_if; + struct sock *skc_next; + struct sock **skc_pprev; + struct sock *skc_bind_next; + struct sock **skc_bind_pprev; + atomic_t skc_refcnt; +}; + /** * struct sock - network layer representation of sockets - * @state - Connection state - * @zapped - ax25 & ipx means !linked - * @reuse - %SO_REUSEADDR setting - * @shutdown - mask of %SEND_SHUTDOWN and/or %RCV_SHUTDOWN - * @bound_dev_if - bound device index if != 0 - * @next - main hash linkage for various protocol lookup tables - * @pprev - main hash linkage for various protocol lookup tables - * @bind_next - main hash linkage for various protocol lookup tables - * @bind_pprev - main hash linkage for various protocol lookup tables - * @refcnt - reference count - * @family - network address family - * @use_write_queue - wheter to call sk->write_space(sk) in sock_wfree - * @userlocks - %SO_SNDBUF and %SO_RCVBUF settings - * @lock - synchronizer - * @rcvbuf - size of receive buffer in bytes - * @sleep - sock wait queue - * @dst_cache - destination cache - * @dst_lock - destination cache lock - * @policy - flow policy - * @rmem_alloc - receive queue bytes committed - * @receive_queue - incoming packets - * @wmem_alloc - transmit queue bytes committed - * @write_queue - Packet sending queue - * @omem_alloc - "o" is "option" or "other" - * @wmem_queued - persistent queue size - * @forward_alloc - space allocated forward - * @allocation - allocation mode - * @sndbuf - size of send buffer in bytes - * @prev - pointer to previous sock in the list this sock is in - * @flags - %SO_LINGER (l_onoff), %SO_BROADCAST, %SO_KEEPALIVE, %SO_OOBINLINE settings - * @no_check - %SO_NO_CHECK setting, wether or not checkup packets - * @debug - %SO_DEBUG setting - * @rcvtstamp - %SO_TIMESTAMP setting - * @no_largesend - whether to sent large segments or not - * @route_caps - route capabilities (e.g. %NETIF_F_TSO) - * @lingertime - %SO_LINGER l_linger setting - * @hashent - hash entry in several tables (e.g. tcp_ehash) - * @pair - socket pair (e.g. AF_UNIX/unix_peer) - * @backlog - always used with the per-socket spinlock held - * @callback_lock - used with the callbacks in the end of this struct - * @error_queue - rarely used - * @prot - protocol handlers inside a network family - * @err - last error - * @err_soft - errors that don't cause failure but are the cause of a persistent failure not just 'timed out' - * @ack_backlog - current listen backlog - * @max_ack_backlog - listen backlog set in listen() - * @priority - %SO_PRIORITY setting - * @type - socket type (%SOCK_STREAM, etc) - * @localroute - route locally only, %SO_DONTROUTE setting - * @protocol - which protocol this socket belongs in this network family - * @peercred - %SO_PEERCRED setting - * @rcvlowat - %SO_RCVLOWAT setting - * @rcvtimeo - %SO_RCVTIMEO setting - * @sndtimeo - %SO_SNDTIMEO setting - * @filter - socket filtering instructions - * @protinfo - private area, net family specific, when not using slab - * @slab - the slabcache this instance was allocated from - * @timer - sock cleanup timer - * @stamp - time stamp of last packet received - * @socket - Identd and reporting IO signals - * @user_data - RPC layer private data - * @owner - module that owns this socket - * @state_change - callback to indicate change in the state of the sock - * @data_ready - callback to indicate there is data to be processed - * @write_space - callback to indicate there is bf sending space available - * @error_report - callback to indicate errors (e.g. %MSG_ERRQUEUE) - * @backlog_rcv - callback to process the backlog - * @destruct - called at sock freeing time, i.e. when all refcnt == 0 + * @__sk_common - shared layout with tcp_tw_bucket + * @sk_zapped - ax25 & ipx means !linked + * @sk_shutdown - mask of %SEND_SHUTDOWN and/or %RCV_SHUTDOWN + * @sk_use_write_queue - wheter to call sk->sk_write_space in sock_wfree + * @sk_userlocks - %SO_SNDBUF and %SO_RCVBUF settings + * @sk_lock - synchronizer + * @sk_rcvbuf - size of receive buffer in bytes + * @sk_sleep - sock wait queue + * @sk_dst_cache - destination cache + * @sk_dst_lock - destination cache lock + * @sk_policy - flow policy + * @sk_rmem_alloc - receive queue bytes committed + * @sk_receive_queue - incoming packets + * @sk_wmem_alloc - transmit queue bytes committed + * @sk_write_queue - Packet sending queue + * @sk_omem_alloc - "o" is "option" or "other" + * @sk_wmem_queued - persistent queue size + * @sk_forward_alloc - space allocated forward + * @sk_allocation - allocation mode + * @sk_sndbuf - size of send buffer in bytes + * @sk_prev - pointer to previous sock in the list this sock is in + * @sk_flags - %SO_LINGER (l_onoff), %SO_BROADCAST, %SO_KEEPALIVE, %SO_OOBINLINE settings + * @sk_no_check - %SO_NO_CHECK setting, wether or not checkup packets + * @sk_debug - %SO_DEBUG setting + * @sk_rcvtstamp - %SO_TIMESTAMP setting + * @sk_no_largesend - whether to sent large segments or not + * @sk_route_caps - route capabilities (e.g. %NETIF_F_TSO) + * @sk_lingertime - %SO_LINGER l_linger setting + * @sk_hashent - hash entry in several tables (e.g. tcp_ehash) + * @sk_pair - socket pair (e.g. AF_UNIX/unix_peer) + * @sk_backlog - always used with the per-socket spinlock held + * @sk_callback_lock - used with the callbacks in the end of this struct + * @sk_error_queue - rarely used + * @sk_prot - protocol handlers inside a network family + * @sk_err - last error + * @sk_err_soft - errors that don't cause failure but are the cause of a persistent failure not just 'timed out' + * @sk_ack_backlog - current listen backlog + * @sk_max_ack_backlog - listen backlog set in listen() + * @sk_priority - %SO_PRIORITY setting + * @sk_type - socket type (%SOCK_STREAM, etc) + * @sk_localroute - route locally only, %SO_DONTROUTE setting + * @sk_protocol - which protocol this socket belongs in this network family + * @sk_peercred - %SO_PEERCRED setting + * @sk_rcvlowat - %SO_RCVLOWAT setting + * @sk_rcvtimeo - %SO_RCVTIMEO setting + * @sk_sndtimeo - %SO_SNDTIMEO setting + * @sk_filter - socket filtering instructions + * @sk_protinfo - private area, net family specific, when not using slab + * @sk_slab - the slabcache this instance was allocated from + * @sk_timer - sock cleanup timer + * @sk_stamp - time stamp of last packet received + * @sk_socket - Identd and reporting IO signals + * @sk_user_data - RPC layer private data + * @sk_owner - module that owns this socket + * @sk_state_change - callback to indicate change in the state of the sock + * @sk_data_ready - callback to indicate there is data to be processed + * @sk_write_space - callback to indicate there is bf sending space available + * @sk_error_report - callback to indicate errors (e.g. %MSG_ERRQUEUE) + * @sk_backlog_rcv - callback to process the backlog + * @sk_destruct - called at sock freeing time, i.e. when all refcnt == 0 */ struct sock { - /* Begin of struct sock/struct tcp_tw_bucket shared layout */ - volatile unsigned char state, - zapped; - unsigned char reuse; - unsigned char shutdown; - int bound_dev_if; - struct sock *next; - struct sock **pprev; - struct sock *bind_next; - struct sock **bind_pprev; - atomic_t refcnt; - unsigned short family; - /* End of struct sock/struct tcp_tw_bucket shared layout */ - unsigned char use_write_queue; - unsigned char userlocks; - socket_lock_t lock; - int rcvbuf; - wait_queue_head_t *sleep; - struct dst_entry *dst_cache; - rwlock_t dst_lock; - struct xfrm_policy *policy[2]; - atomic_t rmem_alloc; - struct sk_buff_head receive_queue; - atomic_t wmem_alloc; - struct sk_buff_head write_queue; - atomic_t omem_alloc; - int wmem_queued; - int forward_alloc; - unsigned int allocation; - int sndbuf; - struct sock *prev; - unsigned long flags; - char no_check; - unsigned char debug; - unsigned char rcvtstamp; - unsigned char no_largesend; - int route_caps; - unsigned long lingertime; - int hashent; - struct sock *pair; + /* + * Now struct tcp_tw_bucket also uses sock_common, so please just + * don't add nothing before this first member (__sk_common) --acme + */ + struct sock_common __sk_common; +#define sk_family __sk_common.skc_family +#define sk_state __sk_common.skc_state +#define sk_reuse __sk_common.skc_reuse +#define sk_bound_dev_if __sk_common.skc_bound_dev_if +#define sk_next __sk_common.skc_next +#define sk_pprev __sk_common.skc_pprev +#define sk_bind_next __sk_common.skc_bind_next +#define sk_bind_pprev __sk_common.skc_bind_pprev +#define sk_refcnt __sk_common.skc_refcnt + volatile unsigned char sk_zapped; + unsigned char sk_shutdown; + unsigned char sk_use_write_queue; + unsigned char sk_userlocks; + socket_lock_t sk_lock; + int sk_rcvbuf; + wait_queue_head_t *sk_sleep; + struct dst_entry *sk_dst_cache; + rwlock_t sk_dst_lock; + struct xfrm_policy *sk_policy[2]; + atomic_t sk_rmem_alloc; + struct sk_buff_head sk_receive_queue; + atomic_t sk_wmem_alloc; + struct sk_buff_head sk_write_queue; + atomic_t sk_omem_alloc; + int sk_wmem_queued; + int sk_forward_alloc; + unsigned int sk_allocation; + int sk_sndbuf; + struct sock *sk_prev; + unsigned long sk_flags; + char sk_no_check; + unsigned char sk_debug; + unsigned char sk_rcvtstamp; + unsigned char sk_no_largesend; + int sk_route_caps; + unsigned long sk_lingertime; + int sk_hashent; + struct sock *sk_pair; /* * The backlog queue is special, it is always used with * the per-socket spinlock held and requires low latency @@ -215,49 +229,75 @@ struct { struct sk_buff *head; struct sk_buff *tail; - } backlog; - rwlock_t callback_lock; - struct sk_buff_head error_queue; - struct proto *prot; - int err, - err_soft; - unsigned short ack_backlog; - unsigned short max_ack_backlog; - __u32 priority; - unsigned short type; - unsigned char localroute; - unsigned char protocol; - struct ucred peercred; - int rcvlowat; - long rcvtimeo; - long sndtimeo; - struct sk_filter *filter; - void *protinfo; - kmem_cache_t *slab; - struct timer_list timer; - struct timeval stamp; - struct socket *socket; - void *user_data; - struct module *owner; - void (*state_change)(struct sock *sk); - void (*data_ready)(struct sock *sk, int bytes); - void (*write_space)(struct sock *sk); - void (*error_report)(struct sock *sk); - int (*backlog_rcv) (struct sock *sk, - struct sk_buff *skb); - void (*destruct)(struct sock *sk); + } sk_backlog; + rwlock_t sk_callback_lock; + struct sk_buff_head sk_error_queue; + struct proto *sk_prot; + int sk_err, + sk_err_soft; + unsigned short sk_ack_backlog; + unsigned short sk_max_ack_backlog; + __u32 sk_priority; + unsigned short sk_type; + unsigned char sk_localroute; + unsigned char sk_protocol; + struct ucred sk_peercred; + int sk_rcvlowat; + long sk_rcvtimeo; + long sk_sndtimeo; + struct sk_filter *sk_filter; + void *sk_protinfo; + kmem_cache_t *sk_slab; + struct timer_list sk_timer; + struct timeval sk_stamp; + struct socket *sk_socket; + void *sk_user_data; + struct module *sk_owner; + void (*sk_state_change)(struct sock *sk); + void (*sk_data_ready)(struct sock *sk, int bytes); + void (*sk_write_space)(struct sock *sk); + void (*sk_error_report)(struct sock *sk); + int (*sk_backlog_rcv)(struct sock *sk, + struct sk_buff *skb); + void (*sk_destruct)(struct sock *sk); }; +/* Sock flags */ +enum sock_flags { + SOCK_DEAD, + SOCK_DONE, + SOCK_URGINLINE, + SOCK_KEEPOPEN, + SOCK_LINGER, + SOCK_DESTROY, + SOCK_BROADCAST, +}; + +static inline void sock_set_flag(struct sock *sk, enum sock_flags flag) +{ + __set_bit(flag, &sk->sk_flags); +} + +static inline void sock_reset_flag(struct sock *sk, enum sock_flags flag) +{ + __clear_bit(flag, &sk->sk_flags); +} + +static inline int sock_flag(struct sock *sk, enum sock_flags flag) +{ + return test_bit(flag, &sk->sk_flags); +} + /* The per-socket spinlock must be held here. */ -#define sk_add_backlog(__sk, __skb) \ -do { if((__sk)->backlog.tail == NULL) { \ - (__sk)->backlog.head = \ - (__sk)->backlog.tail = (__skb); \ - } else { \ - ((__sk)->backlog.tail)->next = (__skb); \ - (__sk)->backlog.tail = (__skb); \ - } \ - (__skb)->next = NULL; \ +#define sk_add_backlog(__sk, __skb) \ +do { if (!(__sk)->sk_backlog.tail) { \ + (__sk)->sk_backlog.head = \ + (__sk)->sk_backlog.tail = (__skb); \ + } else { \ + ((__sk)->sk_backlog.tail)->next = (__skb); \ + (__sk)->sk_backlog.tail = (__skb); \ + } \ + (__skb)->next = NULL; \ } while(0) /* IP protocol blocks we attach to sockets. @@ -322,9 +362,9 @@ * change the ownership of this struct sock, with one not needed * transient sk_set_owner call. */ - if (unlikely(sk->owner != NULL)) + if (unlikely(sk->sk_owner != NULL)) BUG(); - sk->owner = owner; + sk->sk_owner = owner; __module_get(owner); } @@ -408,28 +448,29 @@ */ extern void __lock_sock(struct sock *sk); extern void __release_sock(struct sock *sk); -#define sock_owned_by_user(sk) (NULL != (sk)->lock.owner) +#define sock_owned_by_user(sk) ((sk)->sk_lock.owner) #define lock_sock(__sk) \ do { might_sleep(); \ - spin_lock_bh(&((__sk)->lock.slock)); \ - if ((__sk)->lock.owner != NULL) \ + spin_lock_bh(&((__sk)->sk_lock.slock)); \ + if ((__sk)->sk_lock.owner) \ __lock_sock(__sk); \ - (__sk)->lock.owner = (void *)1; \ - spin_unlock_bh(&((__sk)->lock.slock)); \ + (__sk)->sk_lock.owner = (void *)1; \ + spin_unlock_bh(&((__sk)->sk_lock.slock)); \ } while(0) #define release_sock(__sk) \ -do { spin_lock_bh(&((__sk)->lock.slock)); \ - if ((__sk)->backlog.tail != NULL) \ +do { spin_lock_bh(&((__sk)->sk_lock.slock)); \ + if ((__sk)->sk_backlog.tail) \ __release_sock(__sk); \ - (__sk)->lock.owner = NULL; \ - if (waitqueue_active(&((__sk)->lock.wq))) wake_up(&((__sk)->lock.wq)); \ - spin_unlock_bh(&((__sk)->lock.slock)); \ + (__sk)->sk_lock.owner = NULL; \ + if (waitqueue_active(&((__sk)->sk_lock.wq))) \ + wake_up(&((__sk)->sk_lock.wq)); \ + spin_unlock_bh(&((__sk)->sk_lock.slock)); \ } while(0) /* BH context may only use the following locking interface. */ -#define bh_lock_sock(__sk) spin_lock(&((__sk)->lock.slock)) -#define bh_unlock_sock(__sk) spin_unlock(&((__sk)->lock.slock)) +#define bh_lock_sock(__sk) spin_lock(&((__sk)->sk_lock.slock)) +#define bh_unlock_sock(__sk) spin_unlock(&((__sk)->sk_lock.slock)) extern struct sock * sk_alloc(int family, int priority, int zero_it, kmem_cache_t *slab); @@ -532,13 +573,13 @@ if (err) return err; - if (sk->filter) { + if (sk->sk_filter) { struct sk_filter *filter; if (needlock) bh_lock_sock(sk); - filter = sk->filter; + filter = sk->sk_filter; if (filter) { int pkt_len = sk_run_filter(skb, filter->insns, filter->len); @@ -566,7 +607,7 @@ { unsigned int size = sk_filter_len(fp); - atomic_sub(size, &sk->omem_alloc); + atomic_sub(size, &sk->sk_omem_alloc); if (atomic_dec_and_test(&fp->refcnt)) kfree(fp); @@ -575,7 +616,7 @@ static inline void sk_filter_charge(struct sock *sk, struct sk_filter *fp) { atomic_inc(&fp->refcnt); - atomic_add(sk_filter_len(fp), &sk->omem_alloc); + atomic_add(sk_filter_len(fp), &sk->sk_omem_alloc); } /* @@ -611,7 +652,7 @@ static inline void sock_hold(struct sock *sk) { - atomic_inc(&sk->refcnt); + atomic_inc(&sk->sk_refcnt); } /* Ungrab socket in the context, which assumes that socket refcnt @@ -619,13 +660,13 @@ */ static inline void __sock_put(struct sock *sk) { - atomic_dec(&sk->refcnt); + atomic_dec(&sk->sk_refcnt); } /* Ungrab socket and destroy it, if it was the last reference. */ static inline void sock_put(struct sock *sk) { - if (atomic_dec_and_test(&sk->refcnt)) + if (atomic_dec_and_test(&sk->sk_refcnt)) sk_free(sk); } @@ -638,29 +679,29 @@ */ static inline void sock_orphan(struct sock *sk) { - write_lock_bh(&sk->callback_lock); - __set_bit(SOCK_DEAD, &sk->flags); - sk->socket = NULL; - sk->sleep = NULL; - write_unlock_bh(&sk->callback_lock); + write_lock_bh(&sk->sk_callback_lock); + sock_set_flag(sk, SOCK_DEAD); + sk->sk_socket = NULL; + sk->sk_sleep = NULL; + write_unlock_bh(&sk->sk_callback_lock); } static inline void sock_graft(struct sock *sk, struct socket *parent) { - write_lock_bh(&sk->callback_lock); - sk->sleep = &parent->wait; + write_lock_bh(&sk->sk_callback_lock); + sk->sk_sleep = &parent->wait; parent->sk = sk; - sk->socket = parent; - write_unlock_bh(&sk->callback_lock); + sk->sk_socket = parent; + write_unlock_bh(&sk->sk_callback_lock); } static inline int sock_i_uid(struct sock *sk) { int uid; - read_lock(&sk->callback_lock); - uid = sk->socket ? SOCK_INODE(sk->socket)->i_uid : 0; - read_unlock(&sk->callback_lock); + read_lock(&sk->sk_callback_lock); + uid = sk->sk_socket ? SOCK_INODE(sk->sk_socket)->i_uid : 0; + read_unlock(&sk->sk_callback_lock); return uid; } @@ -668,16 +709,16 @@ { unsigned long ino; - read_lock(&sk->callback_lock); - ino = sk->socket ? SOCK_INODE(sk->socket)->i_ino : 0; - read_unlock(&sk->callback_lock); + read_lock(&sk->sk_callback_lock); + ino = sk->sk_socket ? SOCK_INODE(sk->sk_socket)->i_ino : 0; + read_unlock(&sk->sk_callback_lock); return ino; } static inline struct dst_entry * __sk_dst_get(struct sock *sk) { - return sk->dst_cache; + return sk->sk_dst_cache; } static inline struct dst_entry * @@ -685,11 +726,11 @@ { struct dst_entry *dst; - read_lock(&sk->dst_lock); - dst = sk->dst_cache; + read_lock(&sk->sk_dst_lock); + dst = sk->sk_dst_cache; if (dst) dst_hold(dst); - read_unlock(&sk->dst_lock); + read_unlock(&sk->sk_dst_lock); return dst; } @@ -698,17 +739,17 @@ { struct dst_entry *old_dst; - old_dst = sk->dst_cache; - sk->dst_cache = dst; + old_dst = sk->sk_dst_cache; + sk->sk_dst_cache = dst; dst_release(old_dst); } static inline void sk_dst_set(struct sock *sk, struct dst_entry *dst) { - write_lock(&sk->dst_lock); + write_lock(&sk->sk_dst_lock); __sk_dst_set(sk, dst); - write_unlock(&sk->dst_lock); + write_unlock(&sk->sk_dst_lock); } static inline void @@ -716,26 +757,26 @@ { struct dst_entry *old_dst; - old_dst = sk->dst_cache; - sk->dst_cache = NULL; + old_dst = sk->sk_dst_cache; + sk->sk_dst_cache = NULL; dst_release(old_dst); } static inline void sk_dst_reset(struct sock *sk) { - write_lock(&sk->dst_lock); + write_lock(&sk->sk_dst_lock); __sk_dst_reset(sk); - write_unlock(&sk->dst_lock); + write_unlock(&sk->sk_dst_lock); } static inline struct dst_entry * __sk_dst_check(struct sock *sk, u32 cookie) { - struct dst_entry *dst = sk->dst_cache; + struct dst_entry *dst = sk->sk_dst_cache; if (dst && dst->obsolete && dst->ops->check(dst, cookie) == NULL) { - sk->dst_cache = NULL; + sk->sk_dst_cache = NULL; return NULL; } @@ -770,14 +811,14 @@ sock_hold(sk); skb->sk = sk; skb->destructor = sock_wfree; - atomic_add(skb->truesize, &sk->wmem_alloc); + atomic_add(skb->truesize, &sk->sk_wmem_alloc); } static inline void skb_set_owner_r(struct sk_buff *skb, struct sock *sk) { skb->sk = sk; skb->destructor = sock_rfree; - atomic_add(skb->truesize, &sk->rmem_alloc); + atomic_add(skb->truesize, &sk->sk_rmem_alloc); } static inline int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) @@ -787,7 +828,8 @@ /* Cast skb->rcvbuf to unsigned... It's pointless, but reduces number of warnings when compiling with -W --ANK */ - if (atomic_read(&sk->rmem_alloc) + skb->truesize >= (unsigned)sk->rcvbuf) { + if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >= + (unsigned)sk->sk_rcvbuf) { err = -ENOMEM; goto out; } @@ -802,9 +844,9 @@ skb->dev = NULL; skb_set_owner_r(skb, sk); - skb_queue_tail(&sk->receive_queue, skb); - if (!test_bit(SOCK_DEAD, &sk->flags)) - sk->data_ready(sk,skb->len); + skb_queue_tail(&sk->sk_receive_queue, skb); + if (!sock_flag(sk, SOCK_DEAD)) + sk->sk_data_ready(sk, skb->len); out: return err; } @@ -814,12 +856,13 @@ /* Cast skb->rcvbuf to unsigned... It's pointless, but reduces number of warnings when compiling with -W --ANK */ - if (atomic_read(&sk->rmem_alloc) + skb->truesize >= (unsigned)sk->rcvbuf) + if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >= + (unsigned)sk->sk_rcvbuf) return -ENOMEM; skb_set_owner_r(skb, sk); - skb_queue_tail(&sk->error_queue,skb); - if (!test_bit(SOCK_DEAD, &sk->flags)) - sk->data_ready(sk,skb->len); + skb_queue_tail(&sk->sk_error_queue, skb); + if (!sock_flag(sk, SOCK_DEAD)) + sk->sk_data_ready(sk, skb->len); return 0; } @@ -829,7 +872,7 @@ static inline int sock_error(struct sock *sk) { - int err=xchg(&sk->err,0); + int err = xchg(&sk->sk_err, 0); return -err; } @@ -837,8 +880,8 @@ { int amt = 0; - if (!(sk->shutdown & SEND_SHUTDOWN)) { - amt = sk->sndbuf - atomic_read(&sk->wmem_alloc); + if (!(sk->sk_shutdown & SEND_SHUTDOWN)) { + amt = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); if (amt < 0) amt = 0; } @@ -847,8 +890,8 @@ static inline void sk_wake_async(struct sock *sk, int how, int band) { - if (sk->socket && sk->socket->fasync_list) - sock_wake_async(sk->socket, how, band); + if (sk->sk_socket && sk->sk_socket->fasync_list) + sock_wake_async(sk->sk_socket, how, band); } #define SOCK_MIN_SNDBUF 2048 @@ -859,7 +902,7 @@ */ static inline int sock_writeable(struct sock *sk) { - return atomic_read(&sk->wmem_alloc) < (sk->sndbuf / 2); + return atomic_read(&sk->sk_wmem_alloc) < (sk->sk_sndbuf / 2); } static inline int gfp_any(void) @@ -869,17 +912,17 @@ static inline long sock_rcvtimeo(struct sock *sk, int noblock) { - return noblock ? 0 : sk->rcvtimeo; + return noblock ? 0 : sk->sk_rcvtimeo; } static inline long sock_sndtimeo(struct sock *sk, int noblock) { - return noblock ? 0 : sk->sndtimeo; + return noblock ? 0 : sk->sk_sndtimeo; } static inline int sock_rcvlowat(struct sock *sk, int waitall, int len) { - return (waitall ? len : min_t(int, sk->rcvlowat, len)) ? : 1; + return (waitall ? len : min_t(int, sk->sk_rcvlowat, len)) ? : 1; } /* Alas, with timeout socket operations are not restartable. @@ -893,10 +936,10 @@ static __inline__ void sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb) { - if (sk->rcvtstamp) + if (sk->sk_rcvtstamp) put_cmsg(msg, SOL_SOCKET, SO_TIMESTAMP, sizeof(skb->stamp), &skb->stamp); else - sk->stamp = skb->stamp; + sk->sk_stamp = skb->stamp; } /* @@ -925,20 +968,20 @@ #define SOCK_SLEEP_PRE(sk) { struct task_struct *tsk = current; \ DECLARE_WAITQUEUE(wait, tsk); \ tsk->state = TASK_INTERRUPTIBLE; \ - add_wait_queue((sk)->sleep, &wait); \ + add_wait_queue((sk)->sk_sleep, &wait); \ release_sock(sk); #define SOCK_SLEEP_POST(sk) tsk->state = TASK_RUNNING; \ - remove_wait_queue((sk)->sleep, &wait); \ + remove_wait_queue((sk)->sk_sleep, &wait); \ lock_sock(sk); \ } static inline void sock_valbool_flag(struct sock *sk, int bit, int valbool) { if (valbool) - __set_bit(bit, &sk->flags); + sock_set_flag(sk, bit); else - __clear_bit(bit, &sk->flags); + sock_reset_flag(sk, bit); } extern __u32 sysctl_wmem_max; diff -Nru a/include/net/tcp.h b/include/net/tcp.h --- a/include/net/tcp.h Mon Jun 9 23:16:07 2003 +++ b/include/net/tcp.h Mon Jun 9 23:16:07 2003 @@ -54,7 +54,7 @@ * * 1) Sockets bound to different interfaces may share a local port. * Failing that, goto test 2. - * 2) If all sockets have sk->reuse set, and none of them are in + * 2) If all sockets have sk->sk_reuse set, and none of them are in * TCP_LISTEN state, the port may be shared. * Failing that, goto test 3. * 3) If all sockets are bound to a specific inet_sk(sk)->rcv_saddr local @@ -65,12 +65,12 @@ * The interesting point, is test #2. This is what an FTP server does * all day. To optimize this case we use a specific flag bit defined * below. As we add sockets to a bind bucket list, we perform a - * check of: (newsk->reuse && (newsk->state != TCP_LISTEN)) + * check of: (newsk->sk_reuse && (newsk->sk_state != TCP_LISTEN)) * As long as all sockets added to a bind bucket pass this test, * the flag bit will be set. * The resulting situation is that tcp_v[46]_verify_bind() can just check * for this flag bit, if it is set and the socket trying to bind has - * sk->reuse set, we don't even have to walk the owners list at all, + * sk->sk_reuse set, we don't even have to walk the owners list at all, * we return that it is ok to bind this socket to the requested local port. * * Sounds like a lot of work, but it is worth it. In a more naive @@ -97,7 +97,7 @@ /* This is for sockets with full identity only. Sockets here will * always be without wildcards and will have the following invariant: * - * TCP_ESTABLISHED <= sk->state < TCP_CLOSE + * TCP_ESTABLISHED <= sk->sk_state < TCP_CLOSE * * First half of the table is for sockets not in TIME_WAIT, second half * is for TIME_WAIT sockets only. @@ -165,54 +165,55 @@ * without violating the protocol specification. */ struct tcp_tw_bucket { - /* These _must_ match the beginning of struct sock precisely. - * XXX Yes I know this is gross, but I'd have to edit every single - * XXX networking file if I created a "struct sock_header". -DaveM + /* + * Now struct sock also uses sock_common, so please just + * don't add nothing before this first member (__tw_common) --acme */ - volatile unsigned char state, /* Connection state */ - substate; /* "zapped" -> "substate" */ - unsigned char reuse; /* SO_REUSEADDR setting */ - unsigned char rcv_wscale; /* also TW bucket specific */ - int bound_dev_if; - /* Main hash linkage for various protocol lookup tables. */ - struct sock *next; - struct sock **pprev; - struct sock *bind_next; - struct sock **bind_pprev; - atomic_t refcnt; - unsigned short family; - /* End of struct sock/struct tcp_tw_bucket shared layout */ - __u16 sport; + struct sock_common __tw_common; +#define tw_family __tw_common.skc_family +#define tw_state __tw_common.skc_state +#define tw_reuse __tw_common.skc_reuse +#define tw_bound_dev_if __tw_common.skc_bound_dev_if +#define tw_next __tw_common.skc_next +#define tw_pprev __tw_common.skc_pprev +#define tw_bind_next __tw_common.skc_bind_next +#define tw_bind_pprev __tw_common.skc_bind_pprev +#define tw_refcnt __tw_common.skc_refcnt + volatile unsigned char tw_substate; + unsigned char tw_rcv_wscale; + __u16 tw_sport; /* Socket demultiplex comparisons on incoming packets. */ /* these five are in inet_opt */ - __u32 daddr; - __u32 rcv_saddr; - __u16 dport; - __u16 num; + __u32 tw_daddr; + __u32 tw_rcv_saddr; + __u16 tw_dport; + __u16 tw_num; /* And these are ours. */ - int hashent; - int timeout; - __u32 rcv_nxt; - __u32 snd_nxt; - __u32 rcv_wnd; - __u32 ts_recent; - long ts_recent_stamp; - unsigned long ttd; - struct tcp_bind_bucket *tb; - struct tcp_tw_bucket *next_death; - struct tcp_tw_bucket **pprev_death; + int tw_hashent; + int tw_timeout; + __u32 tw_rcv_nxt; + __u32 tw_snd_nxt; + __u32 tw_rcv_wnd; + __u32 tw_ts_recent; + long tw_ts_recent_stamp; + unsigned long tw_ttd; + struct tcp_bind_bucket *tw_tb; + struct tcp_tw_bucket *tw_next_death; + struct tcp_tw_bucket **tw_pprev_death; #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - struct in6_addr v6_daddr; - struct in6_addr v6_rcv_saddr; + struct in6_addr tw_v6_daddr; + struct in6_addr tw_v6_rcv_saddr; #endif }; +#define tcptw_sk(__sk) ((struct tcp_tw_bucket *)(__sk)) + extern kmem_cache_t *tcp_timewait_cachep; static inline void tcp_tw_put(struct tcp_tw_bucket *tw) { - if (atomic_dec_and_test(&tw->refcnt)) { + if (atomic_dec_and_test(&tw->tw_refcnt)) { #ifdef INET_REFCNT_DEBUG printk(KERN_DEBUG "tw_bucket %p released\n", tw); #endif @@ -246,23 +247,32 @@ #endif /* __BIG_ENDIAN */ #define TCP_IPV4_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif)\ (((*((__u64 *)&(inet_sk(__sk)->daddr)))== (__cookie)) && \ - ((*((__u32 *)&(inet_sk(__sk)->dport)))== (__ports)) && \ - (!((__sk)->bound_dev_if) || ((__sk)->bound_dev_if == (__dif)))) + ((*((__u32 *)&(inet_sk(__sk)->dport)))== (__ports)) && \ + (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) +#define TCP_IPV4_TW_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif)\ + (((*((__u64 *)&(tcptw_sk(__sk)->tw_daddr))) == (__cookie)) && \ + ((*((__u32 *)&(tcptw_sk(__sk)->tw_dport))) == (__ports)) && \ + (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) #else /* 32-bit arch */ #define TCP_V4_ADDR_COOKIE(__name, __saddr, __daddr) #define TCP_IPV4_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif)\ ((inet_sk(__sk)->daddr == (__saddr)) && \ (inet_sk(__sk)->rcv_saddr == (__daddr)) && \ ((*((__u32 *)&(inet_sk(__sk)->dport)))== (__ports)) && \ - (!((__sk)->bound_dev_if) || ((__sk)->bound_dev_if == (__dif)))) + (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) +#define TCP_IPV4_TW_MATCH(__sk, __cookie, __saddr, __daddr, __ports, __dif)\ + ((tcptw_sk(__sk)->tw_daddr == (__saddr)) && \ + (tcptw_sk(__sk)->tw_rcv_saddr == (__daddr)) && \ + ((*((__u32 *)&(tcptw_sk(__sk)->tw_dport))) == (__ports)) && \ + (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) #endif /* 64-bit arch */ #define TCP_IPV6_MATCH(__sk, __saddr, __daddr, __ports, __dif) \ (((*((__u32 *)&(inet_sk(__sk)->dport)))== (__ports)) && \ - ((__sk)->family == AF_INET6) && \ + ((__sk)->sk_family == AF_INET6) && \ !ipv6_addr_cmp(&inet6_sk(__sk)->daddr, (__saddr)) && \ !ipv6_addr_cmp(&inet6_sk(__sk)->rcv_saddr, (__daddr)) && \ - (!((__sk)->bound_dev_if) || ((__sk)->bound_dev_if == (__dif)))) + (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) /* These can have wildcards, don't try too hard. */ static __inline__ int tcp_lhashfn(unsigned short num) @@ -439,6 +449,11 @@ #define TCP_TIME_PROBE0 3 /* Zero window probe timer */ #define TCP_TIME_KEEPOPEN 4 /* Keepalive timer */ +/* Flags in tp->nonagle */ +#define TCP_NAGLE_OFF 1 /* Nagle's algo is disabled */ +#define TCP_NAGLE_CORK 2 /* Socket is corked */ +#define TCP_NAGLE_PUSH 4 /* Cork is overriden for already queued data */ + /* sysctl variables for tcp */ extern int sysctl_max_syn_backlog; extern int sysctl_tcp_timestamps; @@ -921,7 +936,8 @@ { struct tcp_opt *tp = tcp_sk(sk); struct dst_entry *dst = __sk_dst_get(sk); - int mss_now = large && (sk->route_caps&NETIF_F_TSO) && !tp->urg_mode ? + int mss_now = large && (sk->sk_route_caps & NETIF_F_TSO) && + !tp->urg_mode ? tp->mss_cache : tp->mss_cache_std; if (dst) { @@ -972,7 +988,7 @@ { if (skb_queue_len(&tp->out_of_order_queue) == 0 && tp->rcv_wnd && - atomic_read(&sk->rmem_alloc) < sk->rcvbuf && + atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf && !tp->urg_data) tcp_fast_path_on(tp); } @@ -1055,9 +1071,9 @@ #define TCP_SKB_CB(__skb) ((struct tcp_skb_cb *)&((__skb)->cb[0])) #define for_retrans_queue(skb, sk, tp) \ - for (skb = (sk)->write_queue.next; \ + for (skb = (sk)->sk_write_queue.next; \ (skb != (tp)->send_head) && \ - (skb != (struct sk_buff *)&(sk)->write_queue); \ + (skb != (struct sk_buff *)&(sk)->sk_write_queue); \ skb=skb->next) @@ -1069,12 +1085,12 @@ */ static inline int tcp_min_write_space(struct sock *sk) { - return sk->wmem_queued/2; + return sk->sk_wmem_queued / 2; } static inline int tcp_wspace(struct sock *sk) { - return sk->sndbuf - sk->wmem_queued; + return sk->sk_sndbuf - sk->sk_wmem_queued; } @@ -1205,7 +1221,7 @@ { return (skb->len < mss_now && !(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN) && - (nonagle == 2 || + ((nonagle&TCP_NAGLE_CORK) || (!nonagle && tp->packets_out && tcp_minshall_check(tp)))); @@ -1241,7 +1257,7 @@ /* Don't be strict about the congestion window for the * final FIN frame. -DaveM */ - return ((nonagle==1 || tp->urg_mode + return (((nonagle&TCP_NAGLE_PUSH) || tp->urg_mode || !tcp_nagle_check(tp, skb, cur_mss, nonagle)) && ((tcp_packets_in_flight(tp) < tp->snd_cwnd) || (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_FIN)) && @@ -1256,7 +1272,7 @@ static __inline__ int tcp_skb_is_last(struct sock *sk, struct sk_buff *skb) { - return (skb->next == (struct sk_buff*)&sk->write_queue); + return skb->next == (struct sk_buff *)&sk->sk_write_queue; } /* Push out any pending frames which were held back due to @@ -1272,7 +1288,7 @@ if (skb) { if (!tcp_skb_is_last(sk, skb)) - nonagle = 1; + nonagle = TCP_NAGLE_PUSH; if (!tcp_snd_test(tp, skb, cur_mss, nonagle) || tcp_write_xmit(sk, nonagle)) tcp_check_probe_timer(sk, tp); @@ -1292,7 +1308,7 @@ return (skb && tcp_snd_test(tp, skb, tcp_current_mss(sk, 1), - tcp_skb_is_last(sk, skb) ? 1 : tp->nonagle)); + tcp_skb_is_last(sk, skb) ? TCP_NAGLE_PUSH : tp->nonagle)); } static __inline__ void tcp_init_wl(struct tcp_opt *tp, u32 ack, u32 seq) @@ -1354,19 +1370,19 @@ if (!sysctl_tcp_low_latency && tp->ucopy.task) { __skb_queue_tail(&tp->ucopy.prequeue, skb); tp->ucopy.memory += skb->truesize; - if (tp->ucopy.memory > sk->rcvbuf) { + if (tp->ucopy.memory > sk->sk_rcvbuf) { struct sk_buff *skb1; if (sock_owned_by_user(sk)) BUG(); while ((skb1 = __skb_dequeue(&tp->ucopy.prequeue)) != NULL) { - sk->backlog_rcv(sk, skb1); + sk->sk_backlog_rcv(sk, skb1); NET_INC_STATS_BH(TCPPrequeueDropped); } tp->ucopy.memory = 0; } else if (skb_queue_len(&tp->ucopy.prequeue) == 1) { - wake_up_interruptible(sk->sleep); + wake_up_interruptible(sk->sk_sleep); if (!tcp_ack_scheduled(tp)) tcp_reset_xmit_timer(sk, TCP_TIME_DACK, (3*TCP_RTO_MIN)/4); } @@ -1388,7 +1404,7 @@ static __inline__ void tcp_set_state(struct sock *sk, int state) { - int oldstate = sk->state; + int oldstate = sk->sk_state; switch (state) { case TCP_ESTABLISHED: @@ -1400,8 +1416,8 @@ if (oldstate == TCP_CLOSE_WAIT || oldstate == TCP_ESTABLISHED) TCP_INC_STATS(TcpEstabResets); - sk->prot->unhash(sk); - if (sk->prev && !(sk->userlocks&SOCK_BINDPORT_LOCK)) + sk->sk_prot->unhash(sk); + if (sk->sk_prev && !(sk->sk_userlocks & SOCK_BINDPORT_LOCK)) tcp_put_port(sk); /* fall through */ default: @@ -1412,7 +1428,7 @@ /* Change state AFTER socket is unhashed to avoid closed * socket sitting in hash tables. */ - sk->state = state; + sk->sk_state = state; #ifdef STATE_TRACE SOCK_DEBUG(sk, "TCP sk=%p, State %s -> %s\n",sk, statename[oldstate],statename[state]); @@ -1424,10 +1440,10 @@ tcp_set_state(sk, TCP_CLOSE); tcp_clear_xmit_timers(sk); - sk->shutdown = SHUTDOWN_MASK; + sk->sk_shutdown = SHUTDOWN_MASK; - if (!test_bit(SOCK_DEAD, &sk->flags)) - sk->state_change(sk); + if (!sock_flag(sk, SOCK_DEAD)) + sk->sk_state_change(sk); else tcp_destroy_sock(sk); } @@ -1577,27 +1593,28 @@ /* Note: caller must be prepared to deal with negative returns */ static inline int tcp_space(struct sock *sk) { - return tcp_win_from_space(sk->rcvbuf - atomic_read(&sk->rmem_alloc)); + return tcp_win_from_space(sk->sk_rcvbuf - + atomic_read(&sk->sk_rmem_alloc)); } static inline int tcp_full_space( struct sock *sk) { - return tcp_win_from_space(sk->rcvbuf); + return tcp_win_from_space(sk->sk_rcvbuf); } static inline void tcp_acceptq_removed(struct sock *sk) { - sk->ack_backlog--; + sk->sk_ack_backlog--; } static inline void tcp_acceptq_added(struct sock *sk) { - sk->ack_backlog++; + sk->sk_ack_backlog++; } static inline int tcp_acceptq_is_full(struct sock *sk) { - return sk->ack_backlog > sk->max_ack_backlog; + return sk->sk_ack_backlog > sk->sk_max_ack_backlog; } static inline void tcp_acceptq_queue(struct sock *sk, struct open_request *req, @@ -1700,15 +1717,15 @@ static inline void tcp_free_skb(struct sock *sk, struct sk_buff *skb) { tcp_sk(sk)->queue_shrunk = 1; - sk->wmem_queued -= skb->truesize; - sk->forward_alloc += skb->truesize; + sk->sk_wmem_queued -= skb->truesize; + sk->sk_forward_alloc += skb->truesize; __kfree_skb(skb); } static inline void tcp_charge_skb(struct sock *sk, struct sk_buff *skb) { - sk->wmem_queued += skb->truesize; - sk->forward_alloc -= skb->truesize; + sk->sk_wmem_queued += skb->truesize; + sk->sk_forward_alloc -= skb->truesize; } extern void __tcp_mem_reclaim(struct sock *sk); @@ -1716,7 +1733,7 @@ static inline void tcp_mem_reclaim(struct sock *sk) { - if (sk->forward_alloc >= TCP_MEM_QUANTUM) + if (sk->sk_forward_alloc >= TCP_MEM_QUANTUM) __tcp_mem_reclaim(sk); } @@ -1730,9 +1747,9 @@ static inline void tcp_moderate_sndbuf(struct sock *sk) { - if (!(sk->userlocks&SOCK_SNDBUF_LOCK)) { - sk->sndbuf = min(sk->sndbuf, sk->wmem_queued/2); - sk->sndbuf = max(sk->sndbuf, SOCK_MIN_SNDBUF); + if (!(sk->sk_userlocks & SOCK_SNDBUF_LOCK)) { + sk->sk_sndbuf = min(sk->sk_sndbuf, sk->sk_wmem_queued / 2); + sk->sk_sndbuf = max(sk->sk_sndbuf, SOCK_MIN_SNDBUF); } } @@ -1742,7 +1759,7 @@ if (skb) { skb->truesize += mem; - if (sk->forward_alloc >= (int)skb->truesize || + if (sk->sk_forward_alloc >= (int)skb->truesize || tcp_mem_schedule(sk, skb->truesize, 0)) { skb_reserve(skb, MAX_TCP_HEADER); return skb; @@ -1762,9 +1779,9 @@ static inline struct page * tcp_alloc_page(struct sock *sk) { - if (sk->forward_alloc >= (int)PAGE_SIZE || + if (sk->sk_forward_alloc >= (int)PAGE_SIZE || tcp_mem_schedule(sk, PAGE_SIZE, 0)) { - struct page *page = alloc_pages(sk->allocation, 0); + struct page *page = alloc_pages(sk->sk_allocation, 0); if (page) return page; } @@ -1777,7 +1794,7 @@ { struct sk_buff *skb; - while ((skb = __skb_dequeue(&sk->write_queue)) != NULL) + while ((skb = __skb_dequeue(&sk->sk_write_queue)) != NULL) tcp_free_skb(sk, skb); tcp_mem_reclaim(sk); } @@ -1788,8 +1805,8 @@ { skb->sk = sk; skb->destructor = tcp_rfree; - atomic_add(skb->truesize, &sk->rmem_alloc); - sk->forward_alloc -= skb->truesize; + atomic_add(skb->truesize, &sk->sk_rmem_alloc); + sk->sk_forward_alloc -= skb->truesize; } extern void tcp_listen_wlock(void); @@ -1859,10 +1876,10 @@ static inline void tcp_v4_setup_caps(struct sock *sk, struct dst_entry *dst) { - sk->route_caps = dst->dev->features; - if (sk->route_caps & NETIF_F_TSO) { - if (sk->no_largesend || dst->header_len) - sk->route_caps &= ~NETIF_F_TSO; + sk->sk_route_caps = dst->dev->features; + if (sk->sk_route_caps & NETIF_F_TSO) { + if (sk->sk_no_largesend || dst->header_len) + sk->sk_route_caps &= ~NETIF_F_TSO; } } diff -Nru a/include/net/tcp_ecn.h b/include/net/tcp_ecn.h --- a/include/net/tcp_ecn.h Mon Jun 9 23:16:15 2003 +++ b/include/net/tcp_ecn.h Mon Jun 9 23:16:15 2003 @@ -31,10 +31,10 @@ TCP_ECN_send_syn(struct sock *sk, struct tcp_opt *tp, struct sk_buff *skb) { tp->ecn_flags = 0; - if (sysctl_tcp_ecn && !(sk->route_caps&NETIF_F_TSO)) { + if (sysctl_tcp_ecn && !(sk->sk_route_caps & NETIF_F_TSO)) { TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_ECE|TCPCB_FLAG_CWR; tp->ecn_flags = TCP_ECN_OK; - sk->no_largesend = 1; + sk->sk_no_largesend = 1; } } diff -Nru a/include/net/udp.h b/include/net/udp.h --- a/include/net/udp.h Mon Jun 9 23:16:16 2003 +++ b/include/net/udp.h Mon Jun 9 23:16:16 2003 @@ -43,10 +43,9 @@ { struct sock *sk = udp_hash[num & (UDP_HTABLE_SIZE - 1)]; - for(; sk != NULL; sk = sk->next) { + for (; sk; sk = sk->sk_next) if (inet_sk(sk)->num == num) return 1; - } return 0; } diff -Nru a/include/net/x25.h b/include/net/x25.h --- a/include/net/x25.h Mon Jun 9 23:16:14 2003 +++ b/include/net/x25.h Mon Jun 9 23:16:14 2003 @@ -149,7 +149,7 @@ unsigned long vc_facil_mask; /* inc_call facilities mask */ }; -#define x25_sk(__sk) ((struct x25_opt *)(__sk)->protinfo) +#define x25_sk(__sk) ((struct x25_opt *)(__sk)->sk_protinfo) /* af_x25.c */ extern int sysctl_x25_restart_request_timeout; diff -Nru a/include/net/xfrm.h b/include/net/xfrm.h --- a/include/net/xfrm.h Mon Jun 9 23:16:17 2003 +++ b/include/net/xfrm.h Mon Jun 9 23:16:17 2003 @@ -9,6 +9,7 @@ #include <linux/crypto.h> #include <linux/pfkeyv2.h> #include <linux/in6.h> +#include <linux/slab.h> #include <net/sock.h> #include <net/dst.h> @@ -78,7 +79,7 @@ We add genid to each dst plus pointer to genid of raw IP route, pmtu disc will update pmtu on raw IP route and increase its genid. dst_check() will see this for top level and trigger resyncing - metrics. Plus, it will be made via sk->dst_cache. Solved. + metrics. Plus, it will be made via sk->sk_dst_cache. Solved. */ /* Full description of state of transformer. */ @@ -265,6 +266,7 @@ struct xfrm_policy { struct xfrm_policy *next; + struct list_head list; /* This lock only affects elements except for entry. */ rwlock_t lock; @@ -586,7 +588,7 @@ static inline int xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, unsigned short family) { - if (sk && sk->policy[XFRM_POLICY_IN]) + if (sk && sk->sk_policy[XFRM_POLICY_IN]) return __xfrm_policy_check(sk, dir, skb, family); return !xfrm_policy_list[dir] || @@ -628,7 +630,7 @@ static inline int xfrm_sk_clone_policy(struct sock *sk) { - if (unlikely(sk->policy[0] || sk->policy[1])) + if (unlikely(sk->sk_policy[0] || sk->sk_policy[1])) return __xfrm_sk_clone_policy(sk); return 0; } @@ -637,13 +639,13 @@ static inline void xfrm_sk_free_policy(struct sock *sk) { - if (unlikely(sk->policy[0] != NULL)) { - __xfrm_sk_free_policy(sk->policy[0], 0); - sk->policy[0] = NULL; - } - if (unlikely(sk->policy[1] != NULL)) { - __xfrm_sk_free_policy(sk->policy[1], 1); - sk->policy[1] = NULL; + if (unlikely(sk->sk_policy[0] != NULL)) { + __xfrm_sk_free_policy(sk->sk_policy[0], 0); + sk->sk_policy[0] = NULL; + } + if (unlikely(sk->sk_policy[1] != NULL)) { + __xfrm_sk_free_policy(sk->sk_policy[1], 1); + sk->sk_policy[1] = NULL; } } @@ -789,7 +791,8 @@ struct xfrm_policy *xfrm_policy_alloc(int gfp); extern int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*), void *); int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl); -struct xfrm_policy *xfrm_policy_delete(int dir, struct xfrm_selector *sel); +struct xfrm_policy *xfrm_policy_bysel(int dir, struct xfrm_selector *sel, + int delete); struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete); void xfrm_policy_flush(void); u32 xfrm_get_acqseq(void); diff -Nru a/include/pcmcia/ds.h b/include/pcmcia/ds.h --- a/include/pcmcia/ds.h Mon Jun 9 23:16:05 2003 +++ b/include/pcmcia/ds.h Mon Jun 9 23:16:05 2003 @@ -156,12 +156,6 @@ int pcmcia_register_driver(struct pcmcia_driver *driver); void pcmcia_unregister_driver(struct pcmcia_driver *driver); -/* legacy driver registration interface. don't use in new code */ -int register_pccard_driver(dev_info_t *dev_info, - dev_link_t *(*attach)(void), - void (*detach)(dev_link_t *)); -int unregister_pccard_driver(dev_info_t *dev_info); - /* error reporting */ void cs_error(client_handle_t handle, int func, int ret); diff -Nru a/include/scsi/sg.h b/include/scsi/sg.h --- a/include/scsi/sg.h Mon Jun 9 23:16:10 2003 +++ b/include/scsi/sg.h Mon Jun 9 23:16:10 2003 @@ -9,11 +9,18 @@ Original driver (sg.h): * Copyright (C) 1992 Lawrence Foard Version 2 and 3 extensions to driver: -* Copyright (C) 1998 - 2002 Douglas Gilbert +* Copyright (C) 1998 - 2003 Douglas Gilbert - Version: 3.5.27 (20020812) + Version: 3.5.29 (20030529) This version is for 2.5 series kernels. + Changes since 3.5.28 (20030308) + - fix bug introduced in version 3.1.24 (last segment of sgat list) + Changes since 3.5.27 (20020812) + - remove procfs entries: hosts, host_hdr + host_strs (now in sysfs) + - add sysfs sg driver params: def_reserved_size, allow_dio, version + - new boot option: "sg_allow_dio" and module parameter: "allow_dio" + - multiple internal changes due to scsi subsystem rework Changes since 3.5.26 (20020708) - re-add direct IO using Kai Makisara's work - re-tab to 8, start using C99-isms @@ -237,7 +244,7 @@ read/written by a single scsi command. The user can find the value of PAGE_SIZE by calling getpagesize() defined in unistd.h . */ -#define SG_DEFAULT_RETRIES 1 +#define SG_DEFAULT_RETRIES 0 /* Defaults, commented if they differ from original sg driver */ #define SG_DEF_FORCE_LOW_DMA 0 /* was 1 -> memory below 16MB on i386 */ diff -Nru a/include/sound/ac97_codec.h b/include/sound/ac97_codec.h --- a/include/sound/ac97_codec.h Mon Jun 9 23:16:13 2003 +++ b/include/sound/ac97_codec.h Mon Jun 9 23:16:13 2003 @@ -293,6 +293,7 @@ unsigned short codec_cfg[3]; // CODEC_CFG bits struct semaphore mutex; } ad18xx; + unsigned int dev_flags; /* device specific */ } spec; }; @@ -329,7 +330,7 @@ void snd_ac97_resume(ac97_t *ac97); #endif -enum { AC97_TUNE_HP_ONLY, AC97_TUNE_SWAP_HP }; +enum { AC97_TUNE_HP_ONLY, AC97_TUNE_SWAP_HP, AC97_TUNE_SWAP_SURROUND }; struct ac97_quirk { unsigned short vendor; diff -Nru a/include/sound/ak4xxx-adda.h b/include/sound/ak4xxx-adda.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/sound/ak4xxx-adda.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,68 @@ +#ifndef __SOUND_AK4XXX_ADDA_H +#define __SOUND_AK4XXX_ADDA_H + +/* + * ALSA driver for AK4524 / AK4528 / AK4529 / AK4355 / AK4381 + * AD and DA converters + * + * Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the 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 AK4XXX_MAX_CHIPS +#define AK4XXX_MAX_CHIPS 4 +#endif + +typedef struct snd_akm4xxx akm4xxx_t; + +struct snd_ak4xxx_ops { + void (*lock)(akm4xxx_t *ak, int chip); + void (*unlock)(akm4xxx_t *ak, int chip); + void (*write)(akm4xxx_t *ak, int chip, unsigned char reg, unsigned char val); + // unsigned char (*read)(akm4xxx_t *ak, int chip, unsigned char reg); + void (*set_rate_val)(akm4xxx_t *ak, unsigned int rate); +}; + +#define AK4XXX_IMAGE_SIZE (AK4XXX_MAX_CHIPS * 16) /* 64 bytes */ + +struct snd_akm4xxx { + snd_card_t *card; + unsigned int num_adcs; /* AK4524 or AK4528 ADCs */ + unsigned int num_dacs; /* AK4524 or AK4528 DACs */ + unsigned char images[AK4XXX_IMAGE_SIZE]; /* saved register image */ + unsigned char ipga_gain[AK4XXX_MAX_CHIPS][2]; /* saved register image for IPGA (AK4528) */ + unsigned long private_value[AK4XXX_MAX_CHIPS]; /* helper for driver */ + void *private_data[AK4XXX_MAX_CHIPS]; /* helper for driver */ + /* template should fill the following fields */ + unsigned int idx_offset; /* control index offset */ + enum { + SND_AK4524, SND_AK4528, SND_AK4529, SND_AK4355, SND_AK4381 + } type; + struct snd_ak4xxx_ops ops; +}; + +void snd_akm4xxx_write(akm4xxx_t *ak, int chip, unsigned char reg, unsigned char val); +void snd_akm4xxx_reset(akm4xxx_t *ak, int state); +void snd_akm4xxx_init(akm4xxx_t *ak); +int snd_akm4xxx_build_controls(akm4xxx_t *ak); + +#define snd_akm4xxx_get(ak,chip,reg) (ak)->images[(chip) * 16 + (reg)] +#define snd_akm4xxx_set(ak,chip,reg,val) ((ak)->images[(chip) * 16 + (reg)] = (val)) +#define snd_akm4xxx_get_ipga(ak,chip,reg) (ak)->ipga_gain[chip][(reg)-4] +#define snd_akm4xxx_set_ipga(ak,chip,reg,val) ((ak)->ipga_gain[chip][(reg)-4] = (val)) + +#endif /* __SOUND_AK4XXX_ADDA_H */ diff -Nru a/include/sound/asequencer.h b/include/sound/asequencer.h --- a/include/sound/asequencer.h Mon Jun 9 23:16:14 2003 +++ b/include/sound/asequencer.h Mon Jun 9 23:16:14 2003 @@ -596,7 +596,7 @@ #define SNDRV_SEQ_PORT_TYPE_MIDI_MT32 (1<<5) /* MT-32 compatible device */ /* other standards...*/ -#define SNDRV_SEQ_PORT_TYPE_SYNTH (1<<10) /* Synth device */ +#define SNDRV_SEQ_PORT_TYPE_SYNTH (1<<10) /* Synth device (no MIDI compatible - direct wavetable) */ #define SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE (1<<11) /* Sampling device (support sample download) */ #define SNDRV_SEQ_PORT_TYPE_SAMPLE (1<<12) /* Sampling device (sample can be downloaded at any time) */ /*...*/ diff -Nru a/include/sound/core.h b/include/sound/core.h --- a/include/sound/core.h Mon Jun 9 23:16:19 2003 +++ b/include/sound/core.h Mon Jun 9 23:16:19 2003 @@ -25,6 +25,7 @@ #include <linux/sched.h> /* wake_up() */ #include <asm/semaphore.h> /* struct semaphore */ #include <linux/rwsem.h> /* struct rw_semaphore */ +#include <linux/workqueue.h> /* struct workqueue_struct */ /* Typedef's */ typedef struct timespec snd_timestamp_t; @@ -158,6 +159,7 @@ spinlock_t files_lock; /* lock the files for this card */ int shutdown; /* this card is going down */ wait_queue_head_t shutdown_sleep; + struct work_struct free_workq; /* for free in workqueue */ #ifdef CONFIG_PM int (*set_power_state) (snd_card_t *card, unsigned int state); @@ -184,7 +186,7 @@ up(&card->power_lock); } -void snd_power_wait(snd_card_t *card); +int snd_power_wait(snd_card_t *card, unsigned int power_state, struct file *file); static inline unsigned int snd_power_get_state(snd_card_t *card) { @@ -199,7 +201,7 @@ #else #define snd_power_lock(card) do { (void)(card); } while (0) #define snd_power_unlock(card) do { (void)(card); } while (0) -#define snd_power_wait(card) do { (void)(card); } while (0) +static inline int snd_power_wait(snd_card_t *card, unsigned int state, struct file *file) { return 0; } #define snd_power_get_state(card) SNDRV_CTL_POWER_D0 #define snd_power_change_state(card, state) do { (void)(card); } while (0) #endif @@ -211,8 +213,8 @@ int number; /* minor number */ int device; /* device number */ const char *comment; /* for /proc/asound/devices */ - snd_info_entry_t *dev; /* for /proc/asound/dev */ struct file_operations *f_ops; /* file operations */ + char name[0]; /* device name (keep at the end of structure) */ }; typedef struct _snd_minor snd_minor_t; @@ -240,12 +242,13 @@ /* sound_oss.c */ #ifdef CONFIG_SND_OSSEMUL - int snd_minor_info_oss_init(void); int snd_minor_info_oss_done(void); - int snd_oss_init_module(void); - +#else +#define snd_minor_info_oss_init() /*NOP*/ +#define snd_minor_info_oss_done() /*NOP*/ +#define snd_oss_init_module() /*NOP*/ #endif /* memory.c */ @@ -268,6 +271,10 @@ #define kfree_nocheck(obj) snd_wrapper_kfree(obj) #define vfree_nocheck(obj) snd_wrapper_vfree(obj) #else +#define snd_memory_init() /*NOP*/ +#define snd_memory_done() /*NOP*/ +#define snd_memory_info_init() /*NOP*/ +#define snd_memory_info_done() /*NOP*/ #define kmalloc_nocheck(size, flags) kmalloc(size, flags) #define vmalloc_nocheck(size) vmalloc(size) #define kfree_nocheck(obj) kfree(obj) diff -Nru a/include/sound/cs8427.h b/include/sound/cs8427.h --- a/include/sound/cs8427.h Mon Jun 9 23:16:14 2003 +++ b/include/sound/cs8427.h Mon Jun 9 23:16:14 2003 @@ -48,7 +48,7 @@ #define CS8427_REG_UDATABUF 0x13 #define CS8427_REG_QSUBCODE 0x14 /* 0x14-0x1d (10 bytes) */ #define CS8427_REG_OMCKRMCKRATIO 0x1e -#define CS8427_REG_CORU_DATABUF 0x20 +#define CS8427_REG_CORU_DATABUF 0x20 /* 24 byte buffer area */ #define CS8427_REG_ID_AND_VER 0x7f /* CS8427_REG_CONTROL1 bits */ @@ -188,6 +188,7 @@ int snd_cs8427_detect(snd_i2c_bus_t *bus, unsigned char addr); int snd_cs8427_create(snd_i2c_bus_t *bus, unsigned char addr, snd_i2c_device_t **r_cs8427); +void snd_cs8427_reset(snd_i2c_device_t *cs8427); int snd_cs8427_iec958_build(snd_i2c_device_t *cs8427, snd_pcm_substream_t *playback_substream, snd_pcm_substream_t *capture_substream); int snd_cs8427_iec958_active(snd_i2c_device_t *cs8427, int active); int snd_cs8427_iec958_pcm(snd_i2c_device_t *cs8427, unsigned int rate); diff -Nru a/include/sound/info.h b/include/sound/info.h --- a/include/sound/info.h Mon Jun 9 23:16:16 2003 +++ b/include/sound/info.h Mon Jun 9 23:16:16 2003 @@ -69,20 +69,15 @@ struct vm_area_struct * vma); }; -struct snd_info_entry_device { - unsigned short major; - unsigned short minor; -}; - struct snd_info_entry { const char *name; mode_t mode; long size; unsigned short content; + unsigned short disconnected: 1; union { struct snd_info_entry_text text; struct snd_info_entry_ops *ops; - struct snd_info_entry_device device; } c; snd_info_entry_t *parent; snd_card_t *card; diff -Nru a/include/sound/initval.h b/include/sound/initval.h --- a/include/sound/initval.h Mon Jun 9 23:16:05 2003 +++ b/include/sound/initval.h Mon Jun 9 23:16:05 2003 @@ -53,7 +53,7 @@ #define SNDRV_DEFAULT_STR { [0 ... (SNDRV_CARDS-1)] = NULL } #define SNDRV_DEFAULT_ENABLE { 1, [1 ... (SNDRV_CARDS-1)] = 0 } #define SNDRV_DEFAULT_ENABLE_PNP { [0 ... (SNDRV_CARDS-1)] = 1 } -#ifdef __ISAPNP__ +#ifdef CONFIG_PNP #define SNDRV_DEFAULT_ENABLE_ISAPNP SNDRV_DEFAULT_ENABLE_PNP #else #define SNDRV_DEFAULT_ENABLE_ISAPNP SNDRV_DEFAULT_ENABLE diff -Nru a/include/sound/mpu401.h b/include/sound/mpu401.h --- a/include/sound/mpu401.h Mon Jun 9 23:16:18 2003 +++ b/include/sound/mpu401.h Mon Jun 9 23:16:18 2003 @@ -22,7 +22,6 @@ * */ -#include <linux/interrupt.h> #include "rawmidi.h" #include <linux/interrupt.h> @@ -50,8 +49,6 @@ #define MPU401_MODE_BIT_OUTPUT 1 #define MPU401_MODE_BIT_INPUT_TRIGGER 2 #define MPU401_MODE_BIT_OUTPUT_TRIGGER 3 -#define MPU401_MODE_BIT_RX_LOOP 4 -#define MPU401_MODE_BIT_TX_LOOP 5 #define MPU401_MODE_INPUT (1<<MPU401_MODE_BIT_INPUT) #define MPU401_MODE_OUTPUT (1<<MPU401_MODE_BIT_OUTPUT) @@ -88,6 +85,9 @@ spinlock_t input_lock; spinlock_t output_lock; spinlock_t timer_lock; + + atomic_t rx_loop; + atomic_t tx_loop; struct timer_list timer; diff -Nru a/include/sound/opl4.h b/include/sound/opl4.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/sound/opl4.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,32 @@ +#ifndef __SOUND_OPL4_H +#define __SOUND_OPL4_H + +/* + * Global definitions for the OPL4 driver + * Copyright (c) 2003 by Clemens Ladisch <clemens@ladisch.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <sound/opl3.h> + +typedef struct opl4 opl4_t; + +extern int snd_opl4_create(snd_card_t *card, + unsigned long fm_port, unsigned long pcm_port, + int seq_device, + opl3_t **opl3, opl4_t **opl4); + +#endif /* __SOUND_OPL4_H */ diff -Nru a/include/sound/pcm.h b/include/sound/pcm.h --- a/include/sound/pcm.h Mon Jun 9 23:16:12 2003 +++ b/include/sound/pcm.h Mon Jun 9 23:16:12 2003 @@ -317,8 +317,8 @@ snd_pcm_uframes_t silence_size; /* Silence filling size */ snd_pcm_uframes_t boundary; /* pointers wrap point */ - snd_pcm_uframes_t silenced_start; - snd_pcm_uframes_t silenced_size; + snd_pcm_uframes_t silence_start; /* starting pointer to silence area */ + snd_pcm_uframes_t silence_filled; /* size filled with silence */ snd_pcm_sync_id_t sync; /* hardware synchronization ID */ @@ -328,7 +328,6 @@ atomic_t mmap_count; /* -- locking / scheduling -- */ - spinlock_t lock; wait_queue_head_t sleep; struct timer_list tick_timer; struct fasync_struct *fasync; @@ -360,6 +359,11 @@ #endif }; +typedef struct _snd_pcm_group { /* keep linked substreams */ + spinlock_t lock; + struct list_head substreams; +} snd_pcm_group_t; + struct _snd_pcm_substream { snd_pcm_t *pcm; snd_pcm_str_t *pstr; @@ -383,8 +387,10 @@ /* -- next substream -- */ snd_pcm_substream_t *next; /* -- linked substreams -- */ - snd_pcm_substream_t *link_next; - snd_pcm_substream_t *link_prev; + struct list_head link_list; /* linked list member */ + snd_pcm_group_t self_group; /* fake group for non linked substream (with substream lock inside) */ + snd_pcm_group_t *group; /* pointer to current group */ + /* -- assigned files -- */ snd_pcm_file_t *file; struct file *ffile; #if defined(CONFIG_SND_PCM_OSS) || defined(CONFIG_SND_PCM_OSS_MODULE) @@ -468,6 +474,8 @@ * Native I/O */ +extern rwlock_t snd_pcm_link_rwlock; + int snd_pcm_info(snd_pcm_substream_t * substream, snd_pcm_info_t *info); int snd_pcm_info_user(snd_pcm_substream_t * substream, snd_pcm_info_t *info); int snd_pcm_status(snd_pcm_substream_t * substream, snd_pcm_status_t *status); @@ -567,6 +575,53 @@ /* * PCM library */ + +static inline int snd_pcm_stream_linked(snd_pcm_substream_t *substream) +{ + return substream->group != &substream->self_group; +} + +static inline void snd_pcm_stream_lock(snd_pcm_substream_t *substream) +{ + read_lock(&snd_pcm_link_rwlock); + spin_lock(&substream->self_group.lock); +} + +static inline void snd_pcm_stream_unlock(snd_pcm_substream_t *substream) +{ + spin_unlock(&substream->self_group.lock); + read_unlock(&snd_pcm_link_rwlock); +} + +static inline void snd_pcm_stream_lock_irq(snd_pcm_substream_t *substream) +{ + read_lock_irq(&snd_pcm_link_rwlock); + spin_lock(&substream->self_group.lock); +} + +static inline void snd_pcm_stream_unlock_irq(snd_pcm_substream_t *substream) +{ + spin_unlock(&substream->self_group.lock); + read_unlock_irq(&snd_pcm_link_rwlock); +} + +#define snd_pcm_stream_lock_irqsave(substream, flags) \ +do { \ + read_lock_irqsave(&snd_pcm_link_rwlock, (flags)); \ + spin_lock(&substream->self_group.lock); \ +} while (0) + +#define snd_pcm_stream_unlock_irqrestore(substream, flags) \ +do { \ + spin_unlock(&substream->self_group.lock); \ + read_unlock_irqrestore(&snd_pcm_link_rwlock, (flags)); \ +} while (0) + +#define snd_pcm_group_for_each(pos, substream) \ + list_for_each(pos, &substream->group->substreams) + +#define snd_pcm_group_substream_entry(pos) \ + list_entry(pos, snd_pcm_substream_t, link_list) static inline int snd_pcm_running(snd_pcm_substream_t *substream) { diff -Nru a/include/sound/sb.h b/include/sound/sb.h --- a/include/sound/sb.h Mon Jun 9 23:16:11 2003 +++ b/include/sound/sb.h Mon Jun 9 23:16:11 2003 @@ -40,10 +40,11 @@ SB_HW_DT019X, /* Diamond Tech. DT-019X / Avance Logic ALS-007 */ }; -#define SB_OPEN_PCM 0x01 -#define SB_OPEN_MIDI_INPUT 0x02 -#define SB_OPEN_MIDI_OUTPUT 0x04 -#define SB_OPEN_MIDI_TRIGGER 0x08 +#define SB_OPEN_PCM 0x01 +#define SB_OPEN_MIDI_INPUT 0x02 +#define SB_OPEN_MIDI_OUTPUT 0x04 +#define SB_OPEN_MIDI_INPUT_TRIGGER 0x08 +#define SB_OPEN_MIDI_OUTPUT_TRIGGER 0x10 #define SB_MODE_HALT 0x00 #define SB_MODE_PLAYBACK_8 0x01 @@ -157,6 +158,7 @@ #define SB_DSP_STEREO_16BIT 0xac #define SB_DSP_MIDI_INPUT_IRQ 0x31 +#define SB_DSP_MIDI_UART_IRQ 0x35 #define SB_DSP_MIDI_OUTPUT 0x38 #define SB_DSP4_OUT8_AI 0xc6 @@ -295,13 +297,13 @@ /* sb8_init.c */ int snd_sb8dsp_pcm(sb_t *chip, int device, snd_pcm_t ** rpcm); /* sb8.c */ -void snd_sb8dsp_interrupt(sb_t *chip); +irqreturn_t snd_sb8dsp_interrupt(sb_t *chip); int snd_sb8_playback_open(snd_pcm_substream_t *substream); int snd_sb8_capture_open(snd_pcm_substream_t *substream); int snd_sb8_playback_close(snd_pcm_substream_t *substream); int snd_sb8_capture_close(snd_pcm_substream_t *substream); /* midi8.c */ -void snd_sb8dsp_midi_interrupt(sb_t *chip); +irqreturn_t snd_sb8dsp_midi_interrupt(sb_t *chip); int snd_sb8dsp_midi(sb_t *chip, int device, snd_rawmidi_t ** rrawmidi); /* sb16_init.c */ diff -Nru a/include/sound/sndmagic.h b/include/sound/sndmagic.h --- a/include/sound/sndmagic.h Mon Jun 9 23:16:09 2003 +++ b/include/sound/sndmagic.h Mon Jun 9 23:16:09 2003 @@ -193,6 +193,9 @@ #define snd_usb_midi_in_endpoint_t_magic 0xa15a3f03 #define ak4117_t_magic 0xa15a4000 #define psic_t_magic 0xa15a4100 +#define opl4_t_magic 0xa15a2602 +#define vx_core_t_magic 0xa15a4110 +#define vx_pipe_t_magic 0xa15a4112 #else diff -Nru a/include/sound/uda1341.h b/include/sound/uda1341.h --- a/include/sound/uda1341.h Mon Jun 9 23:16:15 2003 +++ b/include/sound/uda1341.h Mon Jun 9 23:16:15 2003 @@ -15,7 +15,7 @@ * features support */ -/* $Id: uda1341.h,v 1.4 2003/02/25 12:48:16 perex Exp $ */ +/* $Id: uda1341.h,v 1.5 2003/04/19 13:34:32 perex Exp $ */ #define UDA1341_ALSA_NAME "snd-uda1341" @@ -210,6 +210,10 @@ CMD_IG, CMD_AGC_TIME, CMD_AGC_LEVEL, +#ifdef CONFIG_PM + CMD_SUSPEND, + CMD_RESUME, +#endif CMD_LAST, }; @@ -221,19 +225,6 @@ }; int __init snd_chip_uda1341_mixer_new(snd_card_t *card, struct l3_client **clnt); -void __init snd_chip_uda1341_mixer_del(snd_card_t *card); - -#ifdef DEBUG_MODE -#define DEBUG(format, args...) do{printk(format, ##args);}while(0) -#else -#define DEBUG(format, args...) /* nothing */ -#endif - -#ifdef DEBUG_FUNCTION_NAMES -#define DEBUG_NAME(format, args...) do{printk(format, ##args);}while(0) -#else -#define DEBUG_NAME(format, args...) /* nothing */ -#endif /* * Local variables: diff -Nru a/include/sound/version.h b/include/sound/version.h --- a/include/sound/version.h Mon Jun 9 23:16:10 2003 +++ b/include/sound/version.h Mon Jun 9 23:16:10 2003 @@ -1,3 +1,3 @@ /* include/version.h. Generated by configure. */ -#define CONFIG_SND_VERSION "0.9.2" -#define CONFIG_SND_DATE " (Thu Mar 20 13:31:57 2003 UTC)" +#define CONFIG_SND_VERSION "0.9.4" +#define CONFIG_SND_DATE " (Fri Jun 06 09:23:03 2003 UTC)" diff -Nru a/include/sound/vx_core.h b/include/sound/vx_core.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/include/sound/vx_core.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,550 @@ +/* + * Driver for Digigram VX soundcards + * + * Hardware core part + * + * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __SOUND_VX_COMMON_H +#define __SOUND_VX_COMMON_H + +#include <sound/pcm.h> +#include <sound/hwdep.h> +#include <linux/interrupt.h> + +typedef struct snd_vx_core vx_core_t; +typedef struct vx_pipe vx_pipe_t; + +#define VX_DRIVER_VERSION 0x010000 /* 1.0.0 */ + +/* + */ +#define SIZE_MAX_CMD 0x10 +#define SIZE_MAX_STATUS 0x10 + +struct vx_rmh { + u16 LgCmd; /* length of the command to send (WORDs) */ + u16 LgStat; /* length of the status received (WORDs) */ + u32 Cmd[SIZE_MAX_CMD]; + u32 Stat[SIZE_MAX_STATUS]; + u16 DspStat; /* status type, RMP_SSIZE_XXX */ +}; + +typedef u64 pcx_time_t; + +#define VX_MAX_PIPES 16 +#define VX_MAX_PERIODS 32 +#define VX_MAX_CODECS 2 + +struct vx_ibl_info { + int size; /* the current IBL size (0 = query) in bytes */ + int max_size; /* max. IBL size in bytes */ + int min_size; /* min. IBL size in bytes */ + int granularity; /* granularity */ +}; + +struct vx_pipe { + int number; + unsigned int is_capture: 1; + unsigned int data_mode: 1; + unsigned int running: 1; + unsigned int prepared: 1; + int channels; + unsigned int differed_type; + pcx_time_t pcx_time; + snd_pcm_substream_t *substream; + + int hbuf_size; /* H-buffer size in bytes */ + int buffer_bytes; /* the ALSA pcm buffer size in bytes */ + int period_bytes; /* the ALSA pcm period size in bytes */ + int hw_ptr; /* the current hardware pointer in bytes */ + int position; /* the current position in frames (playback only) */ + int transferred; /* the transferred size (per period) in frames */ + int align; /* size of alignment */ + u64 cur_count; /* current sample position (for playback) */ + + unsigned int references; /* an output pipe may be used for monitoring and/or playback */ + vx_pipe_t *monitoring_pipe; /* pointer to the monitoring pipe (capture pipe only)*/ + + struct tasklet_struct start_tq; +}; + +struct snd_vx_ops { + /* low-level i/o */ + unsigned char (*in8)(vx_core_t *chip, int reg); + unsigned int (*in32)(vx_core_t *chip, int reg); + void (*out8)(vx_core_t *chip, int reg, unsigned char val); + void (*out32)(vx_core_t *chip, int reg, unsigned int val); + /* irq */ + int (*test_and_ack)(vx_core_t *chip); + void (*validate_irq)(vx_core_t *chip, int enable); + /* codec */ + void (*write_codec)(vx_core_t *chip, int codec, unsigned int data); + void (*akm_write)(vx_core_t *chip, int reg, unsigned int data); + void (*reset_codec)(vx_core_t *chip); + void (*change_audio_source)(vx_core_t *chip, int src); + void (*set_clock_source)(vx_core_t *chp, int src); + /* chip init */ + int (*load_dsp)(vx_core_t *chip, const snd_hwdep_dsp_image_t *dsp); + void (*reset_dsp)(vx_core_t *chip); + void (*reset_board)(vx_core_t *chip, int cold_reset); + int (*add_controls)(vx_core_t *chip); + /* pcm */ + void (*dma_write)(vx_core_t *chip, snd_pcm_runtime_t *runtime, + vx_pipe_t *pipe, int count); + void (*dma_read)(vx_core_t *chip, snd_pcm_runtime_t *runtime, + vx_pipe_t *pipe, int count); +}; + +struct snd_vx_hardware { + const char *name; + int type; /* VX_TYPE_XXX */ + + /* hardware specs */ + unsigned int num_codecs; + unsigned int num_ins; + unsigned int num_outs; + unsigned int output_level_max; +}; + +/* hwdep id string */ +#define SND_VX_HWDEP_ID "VX Loader" + +/* hardware type */ +enum { + /* VX222 PCI */ + VX_TYPE_BOARD, /* old VX222 PCI */ + VX_TYPE_V2, /* VX222 V2 PCI */ + VX_TYPE_MIC, /* VX222 Mic PCI */ + /* VX-pocket */ + VX_TYPE_VXPOCKET, /* VXpocket V2 */ + VX_TYPE_VXP440, /* VXpocket 440 */ + VX_TYPE_NUMS +}; + +/* chip status */ +enum { + VX_STAT_XILINX_LOADED = (1 << 0), /* devices are registered */ + VX_STAT_DEVICE_INIT = (1 << 1), /* devices are registered */ + VX_STAT_CHIP_INIT = (1 << 2), /* all operational */ + VX_STAT_IN_SUSPEND = (1 << 10), /* in suspend phase */ + VX_STAT_IS_STALE = (1 << 15) /* device is stale */ +}; + +/* min/max values for analog output for old codecs */ +#define VX_ANALOG_OUT_LEVEL_MAX 0xe3 + +struct snd_vx_core { + /* ALSA stuff */ + snd_card_t *card; + snd_pcm_t *pcm[VX_MAX_CODECS]; + int type; /* VX_TYPE_XXX */ + + int irq; + /* ports are defined externally */ + + /* low-level functions */ + struct snd_vx_hardware *hw; + struct snd_vx_ops *ops; + + spinlock_t lock; + spinlock_t irq_lock; + struct tasklet_struct tq; + + unsigned int chip_status; + unsigned int pcm_running; + + snd_hwdep_t *hwdep; + + struct vx_rmh irq_rmh; /* RMH used in interrupts */ + + unsigned int audio_info; /* see VX_AUDIO_INFO */ + unsigned int audio_ins; + unsigned int audio_outs; + struct vx_pipe **playback_pipes; + struct vx_pipe **capture_pipes; + + /* clock and audio sources */ + unsigned int audio_source; /* current audio input source */ + unsigned int audio_source_target; + unsigned int clock_source; /* current clock source (INTERNAL_QUARTZ or UER_SYNC) */ + unsigned int freq; /* current frequency */ + unsigned int freq_detected; /* detected frequency from digital in */ + unsigned int uer_detected; /* VX_UER_MODE_XXX */ + unsigned int uer_bits; /* IEC958 status bits */ + struct vx_ibl_info ibl; /* IBL information */ + + /* mixer setting */ + int output_level[VX_MAX_CODECS][2]; /* analog output level */ + int audio_gain[2][4]; /* digital audio level (playback/capture) */ + unsigned char audio_active[4]; /* mute/unmute on digital playback */ + int audio_monitor[4]; /* playback hw-monitor level */ + unsigned char audio_monitor_active[4]; /* playback hw-monitor mute/unmute */ + + struct semaphore mixer_mutex; +}; + + +/* + * constructor + */ +vx_core_t *snd_vx_create(snd_card_t *card, struct snd_vx_hardware *hw, + struct snd_vx_ops *ops, int extra_size); +int snd_vx_hwdep_new(vx_core_t *chip); +int snd_vx_load_boot_image(vx_core_t *chip, const snd_hwdep_dsp_image_t *boot); +int snd_vx_dsp_boot(vx_core_t *chip, const snd_hwdep_dsp_image_t *boot); +int snd_vx_dsp_load(vx_core_t *chip, const snd_hwdep_dsp_image_t *dsp); + +/* + * interrupt handler; exported for pcmcia + */ +irqreturn_t snd_vx_irq_handler(int irq, void *dev, struct pt_regs *regs); + +/* + * power-management routines + */ +#ifdef CONFIG_PM +void snd_vx_suspend(vx_core_t *chip); +void snd_vx_resume(vx_core_t *chip); +#endif + + +/* + * lowlevel functions + */ +inline static int vx_test_and_ack(vx_core_t *chip) +{ + snd_assert(chip->ops->test_and_ack, return -ENXIO); + return chip->ops->test_and_ack(chip); +} + +inline static void vx_validate_irq(vx_core_t *chip, int enable) +{ + snd_assert(chip->ops->validate_irq, return); + chip->ops->validate_irq(chip, enable); +} + +inline static unsigned char snd_vx_inb(vx_core_t *chip, int reg) +{ + snd_assert(chip->ops->in8, return 0); + return chip->ops->in8(chip, reg); +} + +inline static unsigned int snd_vx_inl(vx_core_t *chip, int reg) +{ + snd_assert(chip->ops->in32, return 0); + return chip->ops->in32(chip, reg); +} + +inline static void snd_vx_outb(vx_core_t *chip, int reg, unsigned char val) +{ + snd_assert(chip->ops->out8, return); + return chip->ops->out8(chip, reg, val); +} + +inline static void snd_vx_outl(vx_core_t *chip, int reg, unsigned int val) +{ + snd_assert(chip->ops->out32, return); + return chip->ops->out32(chip, reg, val); +} + +#define vx_inb(chip,reg) snd_vx_inb(chip, VX_##reg) +#define vx_outb(chip,reg,val) snd_vx_outb(chip, VX_##reg,val) +#define vx_inl(chip,reg) snd_vx_inl(chip, VX_##reg) +#define vx_outl(chip,reg,val) snd_vx_outl(chip, VX_##reg,val) + +void snd_vx_delay(vx_core_t *chip, int msec); + +static inline void vx_reset_dsp(vx_core_t *chip) +{ + snd_assert(chip->ops->reset_dsp, return); + chip->ops->reset_dsp(chip); +} + +int vx_send_msg(vx_core_t *chip, struct vx_rmh *rmh); +int vx_send_msg_nolock(vx_core_t *chip, struct vx_rmh *rmh); +int vx_send_rih(vx_core_t *chip, int cmd); +int vx_send_rih_nolock(vx_core_t *chip, int cmd); + +void vx_reset_codec(vx_core_t *chip, int cold_reset); + +/* + * check the bit on the specified register + * returns zero if a bit matches, or a negative error code. + * exported for vxpocket driver + */ +int snd_vx_check_reg_bit(vx_core_t *chip, int reg, int mask, int bit, int time); +#define vx_check_isr(chip,mask,bit,time) snd_vx_check_reg_bit(chip, VX_ISR, mask, bit, time) +#define vx_wait_isr_bit(chip,bit) vx_check_isr(chip, bit, bit, 200) +#define vx_wait_for_rx_full(chip) vx_wait_isr_bit(chip, ISR_RX_FULL) + + +/* + * pseudo-DMA transfer + */ +inline static void vx_pseudo_dma_write(vx_core_t *chip, snd_pcm_runtime_t *runtime, + vx_pipe_t *pipe, int count) +{ + snd_assert(chip->ops->dma_write, return); + chip->ops->dma_write(chip, runtime, pipe, count); +} + +inline static void vx_pseudo_dma_read(vx_core_t *chip, snd_pcm_runtime_t *runtime, + vx_pipe_t *pipe, int count) +{ + snd_assert(chip->ops->dma_read, return); + chip->ops->dma_read(chip, runtime, pipe, count); +} + + + +/* error with hardware code, + * the return value is -(VX_ERR_MASK | actual-hw-error-code) + */ +#define VX_ERR_MASK 0x1000000 +#define vx_get_error(err) (-(err) & ~VX_ERR_MASK) + + +/* + * pcm stuff + */ +int snd_vx_pcm_new(vx_core_t *chip); +void vx_pcm_update_intr(vx_core_t *chip, unsigned int events); + +/* + * mixer stuff + */ +int snd_vx_mixer_new(vx_core_t *chip); +void vx_toggle_dac_mute(vx_core_t *chip, int mute); +int vx_sync_audio_source(vx_core_t *chip); +int vx_set_monitor_level(vx_core_t *chip, int audio, int level, int active); + +/* + * IEC958 & clock stuff + */ +void vx_set_iec958_status(vx_core_t *chip, unsigned int bits); +int vx_set_clock(vx_core_t *chip, unsigned int freq); +void vx_change_clock_source(vx_core_t *chip, int source); +void vx_set_internal_clock(vx_core_t *chip, unsigned int freq); +int vx_change_frequency(vx_core_t *chip); + + +/* + * hardware constants + */ + +#define vx_has_new_dsp(chip) ((chip)->type != VX_TYPE_BOARD) +#define vx_is_pcmcia(chip) ((chip)->type >= VX_TYPE_VXPOCKET) + +/* audio input source */ +enum { + VX_AUDIO_SRC_DIGITAL, + VX_AUDIO_SRC_LINE, + VX_AUDIO_SRC_MIC +}; + +/* clock source */ +enum { + INTERNAL_QUARTZ, + UER_SYNC +}; + +/* SPDIF/UER type */ +enum { + VX_UER_MODE_CONSUMER, + VX_UER_MODE_PROFESSIONAL, + VX_UER_MODE_NOT_PRESENT, +}; + +/* register indices */ +enum { + VX_ICR, + VX_CVR, + VX_ISR, + VX_IVR, + VX_RXH, + VX_TXH = VX_RXH, + VX_RXM, + VX_TXM = VX_RXM, + VX_RXL, + VX_TXL = VX_RXL, + VX_DMA, + VX_CDSP, + VX_RFREQ, + VX_RUER_V2, + VX_GAIN, + VX_DATA = VX_GAIN, + VX_MEMIRQ, + VX_ACQ, + VX_BIT0, + VX_BIT1, + VX_MIC0, + VX_MIC1, + VX_MIC2, + VX_MIC3, + VX_PLX0, + VX_PLX1, + VX_PLX2, + + VX_LOFREQ, // V2: ACQ, VP: RFREQ + VX_HIFREQ, // V2: BIT0, VP: RUER_V2 + VX_CSUER, // V2: BIT1, VP: BIT0 + VX_RUER, // V2: RUER_V2, VP: BIT1 + + VX_REG_MAX, + + /* aliases for VX board */ + VX_RESET_DMA = VX_ISR, + VX_CFG = VX_RFREQ, + VX_STATUS = VX_MEMIRQ, + VX_SELMIC = VX_MIC0, + VX_COMPOT = VX_MIC1, + VX_SCOMPR = VX_MIC2, + VX_GLIMIT = VX_MIC3, + VX_INTCSR = VX_PLX0, + VX_CNTRL = VX_PLX1, + VX_GPIOC = VX_PLX2, + + /* aliases for VXPOCKET board */ + VX_MICRO = VX_MEMIRQ, + VX_CODEC2 = VX_MEMIRQ, + VX_DIALOG = VX_ACQ, + +}; + +/* RMH status type */ +enum { + RMH_SSIZE_FIXED = 0, /* status size given by the driver (in LgStat) */ + RMH_SSIZE_ARG = 1, /* status size given in the LSB byte */ + RMH_SSIZE_MASK = 2, /* status size given in bitmask */ +}; + + +/* bits for ICR register */ +#define ICR_HF1 0x10 +#define ICR_HF0 0x08 +#define ICR_TREQ 0x02 /* Interrupt mode + HREQ set on for transfer (->DSP) request */ +#define ICR_RREQ 0x01 /* Interrupt mode + RREQ set on for transfer (->PC) request */ + +/* bits for CVR register */ +#define CVR_HC 0x80 + +/* bits for ISR register */ +#define ISR_HF3 0x10 +#define ISR_HF2 0x08 +#define ISR_CHK 0x10 +#define ISR_ERR 0x08 +#define ISR_TX_READY 0x04 +#define ISR_TX_EMPTY 0x02 +#define ISR_RX_FULL 0x01 + +/* Constants used to access the DATA register */ +#define VX_DATA_CODEC_MASK 0x80 +#define VX_DATA_XICOR_MASK 0x80 + +/* Constants used to access the CSUER register (both for VX2 and VXP) */ +#define VX_SUER_FREQ_MASK 0x0c +#define VX_SUER_FREQ_32KHz_MASK 0x0c +#define VX_SUER_FREQ_44KHz_MASK 0x00 +#define VX_SUER_FREQ_48KHz_MASK 0x04 +#define VX_SUER_DATA_PRESENT_MASK 0x02 +#define VX_SUER_CLOCK_PRESENT_MASK 0x01 + +#define VX_CUER_HH_BITC_SEL_MASK 0x08 +#define VX_CUER_MH_BITC_SEL_MASK 0x04 +#define VX_CUER_ML_BITC_SEL_MASK 0x02 +#define VX_CUER_LL_BITC_SEL_MASK 0x01 + +#define XX_UER_CBITS_OFFSET_MASK 0x1f + + +/* bits for audio_info */ +#define VX_AUDIO_INFO_REAL_TIME (1<<0) /* real-time processing available */ +#define VX_AUDIO_INFO_OFFLINE (1<<1) /* offline processing available */ +#define VX_AUDIO_INFO_MPEG1 (1<<5) +#define VX_AUDIO_INFO_MPEG2 (1<<6) +#define VX_AUDIO_INFO_LINEAR_8 (1<<7) +#define VX_AUDIO_INFO_LINEAR_16 (1<<8) +#define VX_AUDIO_INFO_LINEAR_24 (1<<9) + +/* DSP Interrupt Request values */ +#define VXP_IRQ_OFFSET 0x40 /* add 0x40 offset for vxpocket and vx222/v2 */ +/* call with vx_send_irq_dsp() */ +#define IRQ_MESS_WRITE_END 0x30 +#define IRQ_MESS_WRITE_NEXT 0x32 +#define IRQ_MESS_READ_NEXT 0x34 +#define IRQ_MESS_READ_END 0x36 +#define IRQ_MESSAGE 0x38 +#define IRQ_RESET_CHK 0x3A +#define IRQ_CONNECT_STREAM_NEXT 0x26 +#define IRQ_CONNECT_STREAM_END 0x28 +#define IRQ_PAUSE_START_CONNECT 0x2A +#define IRQ_END_CONNECTION 0x2C + +/* Is there async. events pending ( IT Source Test ) */ +#define ASYNC_EVENTS_PENDING 0x008000 +#define HBUFFER_EVENTS_PENDING 0x004000 // Not always accurate +#define NOTIF_EVENTS_PENDING 0x002000 +#define TIME_CODE_EVENT_PENDING 0x001000 +#define FREQUENCY_CHANGE_EVENT_PENDING 0x000800 +#define END_OF_BUFFER_EVENTS_PENDING 0x000400 +#define FATAL_DSP_ERROR 0xff0000 + +/* Stream Format Header Defines */ +#define HEADER_FMT_BASE 0xFED00000 +#define HEADER_FMT_MONO 0x000000C0 +#define HEADER_FMT_INTEL 0x00008000 +#define HEADER_FMT_16BITS 0x00002000 +#define HEADER_FMT_24BITS 0x00004000 +#define HEADER_FMT_UPTO11 0x00000200 /* frequency is less or equ. to 11k.*/ +#define HEADER_FMT_UPTO32 0x00000100 /* frequency is over 11k and less then 32k.*/ + +/* Constants used to access the Codec */ +#define XX_CODEC_SELECTOR 0x20 +/* codec commands */ +#define XX_CODEC_ADC_CONTROL_REGISTER 0x01 +#define XX_CODEC_DAC_CONTROL_REGISTER 0x02 +#define XX_CODEC_LEVEL_LEFT_REGISTER 0x03 +#define XX_CODEC_LEVEL_RIGHT_REGISTER 0x04 +#define XX_CODEC_PORT_MODE_REGISTER 0x05 +#define XX_CODEC_STATUS_REPORT_REGISTER 0x06 +#define XX_CODEC_CLOCK_CONTROL_REGISTER 0x07 + +/* + * Audio-level control values + */ +#define CVAL_M110DB 0x000 /* -110dB */ +#define CVAL_M99DB 0x02C +#define CVAL_M21DB 0x163 +#define CVAL_M18DB 0x16F +#define CVAL_M10DB 0x18F +#define CVAL_0DB 0x1B7 +#define CVAL_18DB 0x1FF /* +18dB */ +#define CVAL_MAX 0x1FF + +#define AUDIO_IO_HAS_MUTE_LEVEL 0x400000 +#define AUDIO_IO_HAS_MUTE_MONITORING_1 0x200000 +#define AUDIO_IO_HAS_MUTE_MONITORING_2 0x100000 +#define VALID_AUDIO_IO_DIGITAL_LEVEL 0x01 +#define VALID_AUDIO_IO_MONITORING_LEVEL 0x02 +#define VALID_AUDIO_IO_MUTE_LEVEL 0x04 +#define VALID_AUDIO_IO_MUTE_MONITORING_1 0x08 +#define VALID_AUDIO_IO_MUTE_MONITORING_2 0x10 + + +#endif /* __SOUND_VX_COMMON_H */ diff -Nru a/include/video/edid.h b/include/video/edid.h --- a/include/video/edid.h Mon Jun 9 23:16:08 2003 +++ b/include/video/edid.h Mon Jun 9 23:16:08 2003 @@ -4,7 +4,7 @@ #ifdef __KERNEL__ #include <linux/config.h> -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_OF #include <linux/pci.h> #endif @@ -18,7 +18,7 @@ #endif /* CONFIG_X86 */ -#ifdef CONFIG_ALL_PPC +#ifdef CONFIG_PPC_OF extern char *get_EDID_from_OF(struct pci_dev *pdev); #endif diff -Nru a/init/main.c b/init/main.c --- a/init/main.c Mon Jun 9 23:16:08 2003 +++ b/init/main.c Mon Jun 9 23:16:08 2003 @@ -37,6 +37,7 @@ #include <linux/rcupdate.h> #include <linux/moduleparam.h> #include <linux/writeback.h> +#include <linux/cpu.h> #include <asm/io.h> #include <asm/bugs.h> @@ -318,14 +319,16 @@ /* Copy section for each CPU (we discard the original) */ size = ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES); - if (!size) - return; +#ifdef CONFIG_MODULES + if (size < PERCPU_ENOUGH_ROOM) + size = PERCPU_ENOUGH_ROOM; +#endif ptr = alloc_bootmem(size * NR_CPUS); for (i = 0; i < NR_CPUS; i++, ptr += size) { __per_cpu_offset[i] = ptr - __per_cpu_start; - memcpy(ptr, __per_cpu_start, size); + memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start); } } #endif /* !__GENERIC_PER_CPU */ @@ -388,6 +391,7 @@ lock_kernel(); printk(linux_banner); setup_arch(&command_line); + setup_per_zone_pages_min(); setup_per_cpu_areas(); /* diff -Nru a/ipc/sem.c b/ipc/sem.c --- a/ipc/sem.c Mon Jun 9 23:16:10 2003 +++ b/ipc/sem.c Mon Jun 9 23:16:10 2003 @@ -268,39 +268,39 @@ for (sop = sops; sop < sops + nsops; sop++) { curr = sma->sem_base + sop->sem_num; sem_op = sop->sem_op; - - if (!sem_op && curr->semval) + result = curr->semval; + + if (!sem_op && result) goto would_block; - curr->sempid = (curr->sempid << 16) | pid; - curr->semval += sem_op; - if (sop->sem_flg & SEM_UNDO) - { + result += sem_op; + if (result < 0) + goto would_block; + if (result > SEMVMX) + goto out_of_range; + if (sop->sem_flg & SEM_UNDO) { int undo = un->semadj[sop->sem_num] - sem_op; /* * Exceeding the undo range is an error. */ if (undo < (-SEMAEM - 1) || undo > SEMAEM) - { - /* Don't undo the undo */ - sop->sem_flg &= ~SEM_UNDO; goto out_of_range; - } - un->semadj[sop->sem_num] = undo; } - if (curr->semval < 0) - goto would_block; - if (curr->semval > SEMVMX) - goto out_of_range; + curr->semval = result; } - if (do_undo) - { - sop--; + if (do_undo) { result = 0; goto undo; } - + sop--; + while (sop >= sops) { + sma->sem_base[sop->sem_num].sempid = pid; + if (sop->sem_flg & SEM_UNDO) + un->semadj[sop->sem_num] -= sop->sem_op; + sop--; + } + sma->sem_otime = get_seconds(); return 0; @@ -315,13 +315,9 @@ result = 1; undo: + sop--; while (sop >= sops) { - curr = sma->sem_base + sop->sem_num; - curr->semval -= sop->sem_op; - curr->sempid >>= 16; - - if (sop->sem_flg & SEM_UNDO) - un->semadj[sop->sem_num] += sop->sem_op; + sma->sem_base[sop->sem_num].semval -= sop->sem_op; sop--; } @@ -659,7 +655,7 @@ err = curr->semval; goto out_unlock; case GETPID: - err = curr->sempid & 0xffff; + err = curr->sempid; goto out_unlock; case GETNCNT: err = count_semncnt(sma,semnum); diff -Nru a/kernel/compat.c b/kernel/compat.c --- a/kernel/compat.c Mon Jun 9 23:16:12 2003 +++ b/kernel/compat.c Mon Jun 9 23:16:12 2003 @@ -368,8 +368,7 @@ ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r); set_fs (old_fs); - if (!ret) - { + if (ret > 0) { if (put_compat_rusage(ru, &r)) return -EFAULT; if (stat_addr && put_user(status, stat_addr)) diff -Nru a/kernel/cpu.c b/kernel/cpu.c --- a/kernel/cpu.c Mon Jun 9 23:16:18 2003 +++ b/kernel/cpu.c Mon Jun 9 23:16:18 2003 @@ -8,6 +8,7 @@ #include <linux/notifier.h> #include <linux/sched.h> #include <linux/unistd.h> +#include <linux/cpu.h> #include <asm/semaphore.h> /* This protects CPUs going up and down... */ diff -Nru a/kernel/cpufreq.c b/kernel/cpufreq.c --- a/kernel/cpufreq.c Mon Jun 9 23:16:08 2003 +++ b/kernel/cpufreq.c Mon Jun 9 23:16:08 2003 @@ -29,12 +29,9 @@ * level driver of CPUFreq support, and its locking mutex. * cpu_max_freq is in kHz. */ -struct cpufreq_driver *cpufreq_driver; +static struct cpufreq_driver *cpufreq_driver; static DECLARE_MUTEX (cpufreq_driver_sem); -/* required for the proc interface, remove when that goes away */ -EXPORT_SYMBOL_GPL(cpufreq_driver); - /** * Two notifier lists: the "policy" list is involved in the * validation process for a new CPU frequency policy; the @@ -54,10 +51,14 @@ static struct class_interface cpufreq_interface; -static int cpufreq_cpu_get(unsigned int cpu) { +static int cpufreq_cpu_get(unsigned int cpu) +{ if (cpu >= NR_CPUS) return 0; + if (!cpufreq_driver) + return 0; + if (!try_module_get(cpufreq_driver->owner)) return 0; @@ -69,7 +70,8 @@ return 1; } -static void cpufreq_cpu_put(unsigned int cpu) { +static void cpufreq_cpu_put(unsigned int cpu) +{ kobject_put(&cpufreq_driver->policy[cpu].kobj); module_put(cpufreq_driver->owner); } @@ -81,7 +83,8 @@ /** * cpufreq_parse_governor - parse a governor string */ -int cpufreq_parse_governor (char *str_governor, unsigned int *policy, struct cpufreq_governor **governor) +int cpufreq_parse_governor (char *str_governor, unsigned int *policy, + struct cpufreq_governor **governor) { if (!strnicmp(str_governor, "performance", CPUFREQ_NAME_LEN)) { *policy = CPUFREQ_POLICY_PERFORMANCE; @@ -230,7 +233,8 @@ /** * show_scaling_available_governors - show the available CPUfreq governors */ -static ssize_t show_scaling_available_governors(struct cpufreq_policy * policy, char *buf) +static ssize_t show_scaling_available_governors (struct cpufreq_policy * policy, + char *buf) { ssize_t i = 0; struct cpufreq_governor *t; diff -Nru a/kernel/exec_domain.c b/kernel/exec_domain.c --- a/kernel/exec_domain.c Mon Jun 9 23:16:14 2003 +++ b/kernel/exec_domain.c Mon Jun 9 23:16:14 2003 @@ -32,11 +32,12 @@ }; struct exec_domain default_exec_domain = { - "Linux", /* name */ - default_handler, /* lcall7 causes a seg fault. */ - 0, 0, /* PER_LINUX personality. */ - ident_map, /* Identity map signals. */ - ident_map, /* - both ways. */ + .name = "Linux", /* name */ + .handler = default_handler, /* lcall7 causes a seg fault. */ + .pers_low = 0, /* PER_LINUX personality. */ + .pers_high = 0, /* PER_LINUX personality. */ + .signal_map = ident_map, /* Identity map signals. */ + .signal_invmap = ident_map, /* - both ways. */ }; @@ -247,24 +248,65 @@ int abi_fake_utsname; static struct ctl_table abi_table[] = { - {ABI_DEFHANDLER_COFF, "defhandler_coff", &abi_defhandler_coff, - sizeof(int), 0644, NULL, &proc_doulongvec_minmax}, - {ABI_DEFHANDLER_ELF, "defhandler_elf", &abi_defhandler_elf, - sizeof(int), 0644, NULL, &proc_doulongvec_minmax}, - {ABI_DEFHANDLER_LCALL7, "defhandler_lcall7", &abi_defhandler_lcall7, - sizeof(int), 0644, NULL, &proc_doulongvec_minmax}, - {ABI_DEFHANDLER_LIBCSO, "defhandler_libcso", &abi_defhandler_libcso, - sizeof(int), 0644, NULL, &proc_doulongvec_minmax}, - {ABI_TRACE, "trace", &abi_traceflg, - sizeof(u_int), 0644, NULL, &proc_dointvec}, - {ABI_FAKE_UTSNAME, "fake_utsname", &abi_fake_utsname, - sizeof(int), 0644, NULL, &proc_dointvec}, - {0} + { + .ctl_name = ABI_DEFHANDLER_COFF, + .procname = "defhandler_coff", + .data = &abi_defhandler_coff, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_doulongvec_minmax, + }, + { + .ctl_name = ABI_DEFHANDLER_ELF, + .procname = "defhandler_elf", + .data = &abi_defhandler_elf, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_doulongvec_minmax, + }, + { + .ctl_name = ABI_DEFHANDLER_LCALL7, + .procname = "defhandler_lcall7", + .data = &abi_defhandler_lcall7, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_doulongvec_minmax, + }, + { + .ctl_name = ABI_DEFHANDLER_LIBCSO, + .procname = "defhandler_libcso", + .data = &abi_defhandler_libcso, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_doulongvec_minmax, + }, + { + .ctl_name = ABI_TRACE, + .procname = "trace", + .data = &abi_traceflg, + .maxlen = sizeof(u_int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = ABI_FAKE_UTSNAME, + .procname = "fake_utsname", + .data = &abi_fake_utsname, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { .ctl_name = 0 } }; static struct ctl_table abi_root_table[] = { - {CTL_ABI, "abi", NULL, 0, 0555, abi_table}, - {0} + { + .ctl_name = CTL_ABI, + .procname = "abi", + .mode = 0555, + .child = abi_table, + }, + { .ctl_name = 0 } }; static int __init diff -Nru a/kernel/fork.c b/kernel/fork.c --- a/kernel/fork.c Mon Jun 9 23:16:07 2003 +++ b/kernel/fork.c Mon Jun 9 23:16:07 2003 @@ -38,8 +38,6 @@ #include <asm/cacheflush.h> #include <asm/tlbflush.h> -static kmem_cache_t *task_struct_cachep; - extern int copy_semundo(unsigned long clone_flags, struct task_struct *tsk); extern void exit_semundo(struct task_struct *tsk); @@ -74,7 +72,13 @@ return total; } -static void free_task_struct(struct task_struct *tsk) +#ifndef __HAVE_ARCH_TASK_STRUCT_ALLOCATOR +# define alloc_task_struct() kmem_cache_alloc(task_struct_cachep, GFP_KERNEL) +# define free_task_struct(tsk) kmem_cache_free(task_struct_cachep, (tsk)) +static kmem_cache_t *task_struct_cachep; +#endif + +static void free_task(struct task_struct *tsk) { /* * The task cache is effectively disabled right now. @@ -84,14 +88,14 @@ */ if (tsk != current) { free_thread_info(tsk->thread_info); - kmem_cache_free(task_struct_cachep,tsk); + free_task_struct(tsk); } else { int cpu = get_cpu(); tsk = task_cache[cpu]; if (tsk) { free_thread_info(tsk->thread_info); - kmem_cache_free(task_struct_cachep,tsk); + free_task_struct(tsk); } task_cache[cpu] = current; put_cpu(); @@ -106,7 +110,7 @@ security_task_free(tsk); free_uid(tsk->user); - free_task_struct(tsk); + free_task(tsk); } void add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait) @@ -186,6 +190,7 @@ void __init fork_init(unsigned long mempages) { +#ifndef __HAVE_ARCH_TASK_STRUCT_ALLOCATOR /* create a slab on which task_structs can be allocated */ task_struct_cachep = kmem_cache_create("task_struct", @@ -193,6 +198,7 @@ SLAB_MUST_HWCACHE_ALIGN, NULL, NULL); if (!task_struct_cachep) panic("fork_init(): cannot create task_struct SLAB cache"); +#endif /* * The default maximum number of threads is set to a safe @@ -222,13 +228,13 @@ task_cache[cpu] = NULL; put_cpu(); if (!tsk) { - ti = alloc_thread_info(); - if (!ti) + tsk = alloc_task_struct(); + if (!tsk) return NULL; - tsk = kmem_cache_alloc(task_struct_cachep, GFP_KERNEL); - if (!tsk) { - free_thread_info(ti); + ti = alloc_thread_info(tsk); + if (!ti) { + free_task_struct(tsk); return NULL; } } else @@ -1041,7 +1047,7 @@ atomic_dec(&p->user->processes); free_uid(p->user); bad_fork_free: - free_task_struct(p); + free_task(p); goto fork_out; } diff -Nru a/kernel/kallsyms.c b/kernel/kallsyms.c --- a/kernel/kallsyms.c Mon Jun 9 23:16:19 2003 +++ b/kernel/kallsyms.c Mon Jun 9 23:16:19 2003 @@ -8,6 +8,11 @@ */ #include <linux/kallsyms.h> #include <linux/module.h> +#include <linux/init.h> +#include <linux/seq_file.h> +#include <linux/fs.h> +#include <linux/err.h> +#include <linux/proc_fs.h> /* These will be re-linked against their real values during the second link stage */ extern unsigned long kallsyms_addresses[] __attribute__((weak)); @@ -116,6 +121,171 @@ printk(fmt, buffer); } } + +/* To avoid O(n^2) iteration, we carry prefix along. */ +struct kallsym_iter +{ + loff_t pos; + struct module *owner; + unsigned long value; + unsigned int nameoff; /* If iterating in core kernel symbols */ + char type; + char name[128]; +}; + +/* Only label it "global" if it is exported. */ +static void upcase_if_global(struct kallsym_iter *iter) +{ + if (is_exported(iter->name, iter->owner)) + iter->type += 'A' - 'a'; +} + +static int get_ksymbol_mod(struct kallsym_iter *iter) +{ + iter->owner = module_get_kallsym(iter->pos - kallsyms_num_syms, + &iter->value, + &iter->type, iter->name); + if (iter->owner == NULL) + return 0; + + upcase_if_global(iter); + return 1; +} + +static void get_ksymbol_core(struct kallsym_iter *iter) +{ + unsigned stemlen; + + /* First char of each symbol name indicates prefix length + shared with previous name (stem compresion). */ + stemlen = kallsyms_names[iter->nameoff++]; + + strlcpy(iter->name+stemlen, kallsyms_names+iter->nameoff, 128-stemlen); + iter->nameoff += strlen(kallsyms_names + iter->nameoff) + 1; + iter->owner = NULL; + iter->value = kallsyms_addresses[iter->pos]; + iter->type = 't'; + + upcase_if_global(iter); +} + +static void reset_iter(struct kallsym_iter *iter) +{ + iter->name[0] = '\0'; + iter->nameoff = 0; + iter->pos = 0; +} + +/* Returns false if pos at or past end of file. */ +static int update_iter(struct kallsym_iter *iter, loff_t pos) +{ + /* Module symbols can be accessed randomly. */ + if (pos >= kallsyms_num_syms) { + iter->pos = pos; + return get_ksymbol_mod(iter); + } + + /* If we're past the desired position, reset to start. */ + if (pos < iter->pos) + reset_iter(iter); + + /* We need to iterate through the previous symbols. */ + for (; iter->pos <= pos; iter->pos++) + get_ksymbol_core(iter); + return 1; +} + +static void *s_next(struct seq_file *m, void *p, loff_t *pos) +{ + (*pos)++; + + if (!update_iter(m->private, *pos)) + return NULL; + return p; +} + +static void *s_start(struct seq_file *m, loff_t *pos) +{ + if (!update_iter(m->private, *pos)) + return NULL; + return m->private; +} + +static void s_stop(struct seq_file *m, void *p) +{ +} + +static int s_show(struct seq_file *m, void *p) +{ + struct kallsym_iter *iter = m->private; + + /* Some debugging symbols have no name. Ignore them. */ + if (!iter->name[0]) + return 0; + + if (iter->owner) + seq_printf(m, "%0*lx %c %s\t[%s]\n", + (int)(2*sizeof(void*)), + iter->value, iter->type, iter->name, + module_name(iter->owner)); + else + seq_printf(m, "%0*lx %c %s\n", + (int)(2*sizeof(void*)), + iter->value, iter->type, iter->name); + return 0; +} + +struct seq_operations kallsyms_op = { + .start = s_start, + .next = s_next, + .stop = s_stop, + .show = s_show +}; + +static int kallsyms_open(struct inode *inode, struct file *file) +{ + /* We keep iterator in m->private, since normal case is to + * s_start from where we left off, so we avoid O(N^2). */ + struct kallsym_iter *iter; + int ret; + + iter = kmalloc(sizeof(*iter), GFP_KERNEL); + if (!iter) + return -ENOMEM; + + ret = seq_open(file, &kallsyms_op); + if (ret == 0) + ((struct seq_file *)file->private_data)->private = iter; + else + kfree(iter); + return ret; +} + +static int kallsyms_release(struct inode *inode, struct file *file) +{ + struct seq_file *m = (struct seq_file *)file->private_data; + kfree(m->private); + return seq_release(inode, file); +} + +static struct file_operations kallsyms_operations = { + .open = kallsyms_open, + .read = seq_read, + .llseek = seq_lseek, + .release = kallsyms_release, +}; + +int __init kallsyms_init(void) +{ + struct proc_dir_entry *entry; + + /* root-only: could chew up lots of cpu by read, seek back, read... */ + entry = create_proc_entry("kallsyms", 0400, NULL); + if (entry) + entry->proc_fops = &kallsyms_operations; + return 0; +} +__initcall(kallsyms_init); EXPORT_SYMBOL(kallsyms_lookup); EXPORT_SYMBOL(__print_symbol); diff -Nru a/kernel/kmod.c b/kernel/kmod.c --- a/kernel/kmod.c Mon Jun 9 23:16:09 2003 +++ b/kernel/kmod.c Mon Jun 9 23:16:09 2003 @@ -58,9 +58,9 @@ * If module auto-loading support is disabled then this function * becomes a no-operation. */ -#define MODULENAME_SIZE 32 int request_module(const char *fmt, ...) { +#define MODULENAME_SIZE 32 va_list args; char module_name[MODULENAME_SIZE]; unsigned int max_modprobes; diff -Nru a/kernel/ksyms.c b/kernel/ksyms.c --- a/kernel/ksyms.c Mon Jun 9 23:16:05 2003 +++ b/kernel/ksyms.c Mon Jun 9 23:16:05 2003 @@ -98,8 +98,8 @@ EXPORT_SYMBOL(kmalloc); EXPORT_SYMBOL(kfree); #ifdef CONFIG_SMP -EXPORT_SYMBOL(kmalloc_percpu); -EXPORT_SYMBOL(kfree_percpu); +EXPORT_SYMBOL(__alloc_percpu); +EXPORT_SYMBOL(free_percpu); EXPORT_SYMBOL(percpu_counter_mod); #endif EXPORT_SYMBOL(vfree); diff -Nru a/kernel/module.c b/kernel/module.c --- a/kernel/module.c Mon Jun 9 23:16:15 2003 +++ b/kernel/module.c Mon Jun 9 23:16:15 2003 @@ -205,6 +205,167 @@ return NULL; } +#ifdef CONFIG_SMP +/* Number of blocks used and allocated. */ +static unsigned int pcpu_num_used, pcpu_num_allocated; +/* Size of each block. -ve means used. */ +static int *pcpu_size; + +static int split_block(unsigned int i, unsigned short size) +{ + /* Reallocation required? */ + if (pcpu_num_used + 1 > pcpu_num_allocated) { + int *new = kmalloc(sizeof(new[0]) * pcpu_num_allocated*2, + GFP_KERNEL); + if (!new) + return 0; + + memcpy(new, pcpu_size, sizeof(new[0])*pcpu_num_allocated); + pcpu_num_allocated *= 2; + kfree(pcpu_size); + pcpu_size = new; + } + + /* Insert a new subblock */ + memmove(&pcpu_size[i+1], &pcpu_size[i], + sizeof(pcpu_size[0]) * (pcpu_num_used - i)); + pcpu_num_used++; + + pcpu_size[i+1] -= size; + pcpu_size[i] = size; + return 1; +} + +static inline unsigned int block_size(int val) +{ + if (val < 0) + return -val; + return val; +} + +/* Created by linker magic */ +extern char __per_cpu_start[], __per_cpu_end[]; + +static void *percpu_modalloc(unsigned long size, unsigned long align) +{ + unsigned long extra; + unsigned int i; + void *ptr; + + BUG_ON(align > SMP_CACHE_BYTES); + + ptr = __per_cpu_start; + for (i = 0; i < pcpu_num_used; ptr += block_size(pcpu_size[i]), i++) { + /* Extra for alignment requirement. */ + extra = ALIGN((unsigned long)ptr, align) - (unsigned long)ptr; + BUG_ON(i == 0 && extra != 0); + + if (pcpu_size[i] < 0 || pcpu_size[i] < extra + size) + continue; + + /* Transfer extra to previous block. */ + if (pcpu_size[i-1] < 0) + pcpu_size[i-1] -= extra; + else + pcpu_size[i-1] += extra; + pcpu_size[i] -= extra; + ptr += extra; + + /* Split block if warranted */ + if (pcpu_size[i] - size > sizeof(unsigned long)) + if (!split_block(i, size)) + return NULL; + + /* Mark allocated */ + pcpu_size[i] = -pcpu_size[i]; + return ptr; + } + + printk(KERN_WARNING "Could not allocate %lu bytes percpu data\n", + size); + return NULL; +} + +static void percpu_modfree(void *freeme) +{ + unsigned int i; + void *ptr = __per_cpu_start + block_size(pcpu_size[0]); + + /* First entry is core kernel percpu data. */ + for (i = 1; i < pcpu_num_used; ptr += block_size(pcpu_size[i]), i++) { + if (ptr == freeme) { + pcpu_size[i] = -pcpu_size[i]; + goto free; + } + } + BUG(); + + free: + /* Merge with previous? */ + if (pcpu_size[i-1] >= 0) { + pcpu_size[i-1] += pcpu_size[i]; + pcpu_num_used--; + memmove(&pcpu_size[i], &pcpu_size[i+1], + (pcpu_num_used - i) * sizeof(pcpu_size[0])); + i--; + } + /* Merge with next? */ + if (i+1 < pcpu_num_used && pcpu_size[i+1] >= 0) { + pcpu_size[i] += pcpu_size[i+1]; + pcpu_num_used--; + memmove(&pcpu_size[i+1], &pcpu_size[i+2], + (pcpu_num_used - (i+1)) * sizeof(pcpu_size[0])); + } +} + +static unsigned int find_pcpusec(Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + const char *secstrings) +{ + return find_sec(hdr, sechdrs, secstrings, ".data.percpu"); +} + +static int percpu_modinit(void) +{ + pcpu_num_used = 2; + pcpu_num_allocated = 2; + pcpu_size = kmalloc(sizeof(pcpu_size[0]) * pcpu_num_allocated, + GFP_KERNEL); + /* Static in-kernel percpu data (used). */ + pcpu_size[0] = -ALIGN(__per_cpu_end-__per_cpu_start, SMP_CACHE_BYTES); + /* Free room. */ + pcpu_size[1] = PERCPU_ENOUGH_ROOM + pcpu_size[0]; + if (pcpu_size[1] < 0) { + printk(KERN_ERR "No per-cpu room for modules.\n"); + pcpu_num_used = 1; + } + + return 0; +} +__initcall(percpu_modinit); +#else /* ... !CONFIG_SMP */ +static inline void *percpu_modalloc(unsigned long size, unsigned long align) +{ + return NULL; +} +static inline void percpu_modfree(void *pcpuptr) +{ + BUG(); +} +static inline unsigned int find_pcpusec(Elf_Ehdr *hdr, + Elf_Shdr *sechdrs, + const char *secstrings) +{ + return 0; +} +static inline void percpu_modcopy(void *pcpudst, const void *src, + unsigned long size) +{ + /* pcpusec should be 0, and size of that section should be 0. */ + BUG_ON(size != 0); +} +#endif /* CONFIG_SMP */ + #ifdef CONFIG_MODULE_UNLOAD /* Init the unload section of the module. */ static void module_unload_init(struct module *mod) @@ -913,6 +1074,8 @@ /* This may be NULL, but that's OK */ module_free(mod, mod->module_init); kfree(mod->args); + if (mod->percpu) + percpu_modfree(mod->percpu); /* Finally, free the core (containing the module structure) */ module_free(mod, mod->module_core); @@ -939,10 +1102,11 @@ unsigned int symindex, const char *strtab, unsigned int versindex, + unsigned int pcpuindex, struct module *mod) { Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr; - + unsigned long secbase; unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym); int ret = 0; @@ -979,10 +1143,12 @@ break; default: - sym[i].st_value - = (unsigned long) - (sechdrs[sym[i].st_shndx].sh_addr - + sym[i].st_value); + /* Divert to percpu allocation if a percpu var. */ + if (sym[i].st_shndx == pcpuindex) + secbase = (unsigned long)mod->percpu; + else + secbase = sechdrs[sym[i].st_shndx].sh_addr; + sym[i].st_value += secbase; break; } } @@ -1108,6 +1274,83 @@ return NULL; } +#ifdef CONFIG_KALLSYMS +int is_exported(const char *name, const struct module *mod) +{ + unsigned int i; + + if (!mod) { + for (i = 0; __start___ksymtab+i < __stop___ksymtab; i++) + if (strcmp(__start___ksymtab[i].name, name) == 0) + return 1; + return 0; + } + for (i = 0; i < mod->num_syms; i++) + if (strcmp(mod->syms[i].name, name) == 0) + return 1; + return 0; +} + +/* As per nm */ +static char elf_type(const Elf_Sym *sym, + Elf_Shdr *sechdrs, + const char *secstrings, + struct module *mod) +{ + if (ELF_ST_BIND(sym->st_info) == STB_WEAK) { + if (ELF_ST_TYPE(sym->st_info) == STT_OBJECT) + return 'v'; + else + return 'w'; + } + if (sym->st_shndx == SHN_UNDEF) + return 'U'; + if (sym->st_shndx == SHN_ABS) + return 'a'; + if (sym->st_shndx >= SHN_LORESERVE) + return '?'; + if (sechdrs[sym->st_shndx].sh_flags & SHF_EXECINSTR) + return 't'; + if (sechdrs[sym->st_shndx].sh_flags & SHF_ALLOC + && sechdrs[sym->st_shndx].sh_type != SHT_NOBITS) { + if (!(sechdrs[sym->st_shndx].sh_flags & SHF_WRITE)) + return 'r'; + else if (sechdrs[sym->st_shndx].sh_flags & ARCH_SHF_SMALL) + return 'g'; + else + return 'd'; + } + if (sechdrs[sym->st_shndx].sh_type == SHT_NOBITS) { + if (sechdrs[sym->st_shndx].sh_flags & ARCH_SHF_SMALL) + return 's'; + else + return 'b'; + } + if (strncmp(secstrings + sechdrs[sym->st_shndx].sh_name, + ".debug", strlen(".debug")) == 0) + return 'n'; + return '?'; +} + +static void add_kallsyms(struct module *mod, + Elf_Shdr *sechdrs, + unsigned int symindex, + unsigned int strindex, + const char *secstrings) +{ + unsigned int i; + + mod->symtab = (void *)sechdrs[symindex].sh_addr; + mod->num_symtab = sechdrs[symindex].sh_size / sizeof(Elf_Sym); + mod->strtab = (void *)sechdrs[strindex].sh_addr; + + /* Set types up while we still have access to sections. */ + for (i = 0; i < mod->num_symtab; i++) + mod->symtab[i].st_info + = elf_type(&mod->symtab[i], sechdrs, secstrings, mod); +} +#endif + /* Allocate and load the module: note that size of section 0 is always zero, and we rely on this for optional sections. */ static struct module *load_module(void __user *umod, @@ -1119,7 +1362,7 @@ char *secstrings, *args, *modmagic, *strtab = NULL; unsigned int i, symindex = 0, strindex = 0, setupindex, exindex, exportindex, modindex, obsparmindex, infoindex, gplindex, - crcindex, gplcrcindex, versindex; + crcindex, gplcrcindex, versindex, pcpuindex; long arglen; struct module *mod; long err = 0; @@ -1194,6 +1437,7 @@ obsparmindex = find_sec(hdr, sechdrs, secstrings, "__obsparm"); versindex = find_sec(hdr, sechdrs, secstrings, "__versions"); infoindex = find_sec(hdr, sechdrs, secstrings, ".modinfo"); + pcpuindex = find_pcpusec(hdr, sechdrs, secstrings); /* Don't keep modinfo section */ sechdrs[infoindex].sh_flags &= ~(unsigned long)SHF_ALLOC; @@ -1250,6 +1494,17 @@ if (err < 0) goto free_mod; + if (pcpuindex) { + /* We have a special allocation for this section. */ + mod->percpu = percpu_modalloc(sechdrs[pcpuindex].sh_size, + sechdrs[pcpuindex].sh_addralign); + if (!mod->percpu) { + err = -ENOMEM; + goto free_mod; + } + sechdrs[pcpuindex].sh_flags &= ~(unsigned long)SHF_ALLOC; + } + /* Determine total sizes, and put offsets in sh_entsize. For now this is done generically; there doesn't appear to be any special cases for the architectures. */ @@ -1259,7 +1514,7 @@ ptr = module_alloc(mod->core_size); if (!ptr) { err = -ENOMEM; - goto free_mod; + goto free_percpu; } memset(ptr, 0, mod->core_size); mod->module_core = ptr; @@ -1303,7 +1558,8 @@ set_license(mod, get_modinfo(sechdrs, infoindex, "license")); /* Fix up syms, so that st_value is a pointer to location. */ - err = simplify_symbols(sechdrs, symindex, strtab, versindex, mod); + err = simplify_symbols(sechdrs, symindex, strtab, versindex, pcpuindex, + mod); if (err < 0) goto cleanup; @@ -1342,15 +1598,18 @@ goto cleanup; } -#ifdef CONFIG_KALLSYMS - mod->symtab = (void *)sechdrs[symindex].sh_addr; - mod->num_symtab = sechdrs[symindex].sh_size / sizeof(Elf_Sym); - mod->strtab = (void *)sechdrs[strindex].sh_addr; -#endif + /* Finally, copy percpu area over. */ + percpu_modcopy(mod->percpu, (void *)sechdrs[pcpuindex].sh_addr, + sechdrs[pcpuindex].sh_size); + err = module_finalize(hdr, sechdrs, mod); if (err < 0) goto cleanup; +#ifdef CONFIG_KALLSYMS + add_kallsyms(mod, sechdrs, symindex, strindex, secstrings); +#endif + mod->args = args; if (obsparmindex) { err = obsolete_params(mod->name, mod->args, @@ -1383,6 +1642,9 @@ module_free(mod, mod->module_init); free_core: module_free(mod, mod->module_core); + free_percpu: + if (mod->percpu) + percpu_modfree(mod->percpu); free_mod: kfree(args); free_hdr: @@ -1527,6 +1789,30 @@ return get_ksymbol(mod, addr, size, offset); } } + return NULL; +} + +struct module *module_get_kallsym(unsigned int symnum, + unsigned long *value, + char *type, + char namebuf[128]) +{ + struct module *mod; + + down(&module_mutex); + list_for_each_entry(mod, &modules, list) { + if (symnum < mod->num_symtab) { + *value = mod->symtab[symnum].st_value; + *type = mod->symtab[symnum].st_info; + strncpy(namebuf, + mod->strtab + mod->symtab[symnum].st_name, + 127); + up(&module_mutex); + return mod; + } + symnum -= mod->num_symtab; + } + up(&module_mutex); return NULL; } #endif /* CONFIG_KALLSYMS */ diff -Nru a/kernel/posix-timers.c b/kernel/posix-timers.c --- a/kernel/posix-timers.c Mon Jun 9 23:16:13 2003 +++ b/kernel/posix-timers.c Mon Jun 9 23:16:13 2003 @@ -288,46 +288,32 @@ static void timer_notify_task(struct k_itimer *timr) { - struct siginfo info; int ret; - memset(&info, 0, sizeof (info)); + memset(&timr->sigq->info, 0, sizeof(siginfo_t)); /* Send signal to the process that owns this timer. */ - info.si_signo = timr->it_sigev_signo; - info.si_errno = 0; - info.si_code = SI_TIMER; - info.si_tid = timr->it_id; - info.si_value = timr->it_sigev_value; + timr->sigq->info.si_signo = timr->it_sigev_signo; + timr->sigq->info.si_errno = 0; + timr->sigq->info.si_code = SI_TIMER; + timr->sigq->info.si_tid = timr->it_id; + timr->sigq->info.si_value = timr->it_sigev_value; if (timr->it_incr) - info.si_sys_private = ++timr->it_requeue_pending; + timr->sigq->info.si_sys_private = ++timr->it_requeue_pending; if (timr->it_sigev_notify & SIGEV_THREAD_ID & MIPS_SIGEV) - ret = send_sig_info(info.si_signo, &info, timr->it_process); + ret = send_sigqueue(timr->it_sigev_signo, timr->sigq, + timr->it_process); else - ret = send_group_sig_info(info.si_signo, &info, - timr->it_process); - switch (ret) { - - default: - /* - * Signal was not sent. May or may not need to - * restart the timer. - */ - printk(KERN_WARNING "sending signal failed: %d\n", ret); - case 1: + ret = send_group_sigqueue(timr->it_sigev_signo, timr->sigq, + timr->it_process); + if (ret) { /* - * signal was not sent because of sig_ignor or, - * possibly no queue memory OR will be sent but, + * signal was not sent because of sig_ignor * we will not get a call back to restart it AND * it should be restarted. */ schedule_next_timer(timr); - case 0: - /* - * all's well new signal queued - */ - break; } } @@ -379,7 +365,11 @@ struct k_itimer *tmr; tmr = kmem_cache_alloc(posix_timers_cache, GFP_KERNEL); memset(tmr, 0, sizeof (struct k_itimer)); - + tmr->it_id = (timer_t)-1; + if (unlikely(!(tmr->sigq = sigqueue_alloc()))) { + kmem_cache_free(posix_timers_cache, tmr); + tmr = 0; + } return tmr; } @@ -390,6 +380,7 @@ idr_remove(&posix_timers_id, tmr->it_id); spin_unlock_irq(&idr_lock); } + sigqueue_free(tmr->sigq); kmem_cache_free(posix_timers_cache, tmr); } diff -Nru a/kernel/rcupdate.c b/kernel/rcupdate.c --- a/kernel/rcupdate.c Mon Jun 9 23:16:05 2003 +++ b/kernel/rcupdate.c Mon Jun 9 23:16:05 2003 @@ -43,6 +43,7 @@ #include <linux/percpu.h> #include <linux/notifier.h> #include <linux/rcupdate.h> +#include <linux/cpu.h> /* Definition for rcupdate control block. */ struct rcu_ctrlblk rcu_ctrlblk = diff -Nru a/kernel/resource.c b/kernel/resource.c --- a/kernel/resource.c Mon Jun 9 23:16:15 2003 +++ b/kernel/resource.c Mon Jun 9 23:16:15 2003 @@ -20,8 +20,19 @@ #include <asm/io.h> -struct resource ioport_resource = { "PCI IO", 0x0000, IO_SPACE_LIMIT, IORESOURCE_IO }; -struct resource iomem_resource = { "PCI mem", 0UL, ~0UL, IORESOURCE_MEM }; +struct resource ioport_resource = { + .name = "PCI IO", + .start = 0x0000, + .end = IO_SPACE_LIMIT, + .flags = IORESOURCE_IO, +}; + +struct resource iomem_resource = { + .name = "PCI mem", + .start = 0UL, + .end = ~0UL, + .flags = IORESOURCE_MEM, +}; static rwlock_t resource_lock = RW_LOCK_UNLOCKED; diff -Nru a/kernel/sched.c b/kernel/sched.c --- a/kernel/sched.c Mon Jun 9 23:16:16 2003 +++ b/kernel/sched.c Mon Jun 9 23:16:17 2003 @@ -32,6 +32,7 @@ #include <linux/delay.h> #include <linux/timer.h> #include <linux/rcupdate.h> +#include <linux/cpu.h> #ifdef CONFIG_NUMA #define cpu_to_node_mask(cpu) node_to_cpumask(cpu_to_node(cpu)) @@ -501,7 +502,7 @@ } success = 1; } -#if CONFIG_SMP +#ifdef CONFIG_SMP else if (unlikely(kick) && task_running(rq, p) && (p->thread_info->cpu != smp_processor_id())) smp_send_reschedule(p->thread_info->cpu); @@ -779,7 +780,7 @@ return best_cpu; minload = 10000000; - for (i = 0; i < numnodes; i++) { + for_each_node_with_cpus(i) { load = atomic_read(&node_nr_running[i]); if (load < minload) { minload = load; diff -Nru a/kernel/signal.c b/kernel/signal.c --- a/kernel/signal.c Mon Jun 9 23:16:10 2003 +++ b/kernel/signal.c Mon Jun 9 23:16:10 2003 @@ -4,6 +4,10 @@ * Copyright (C) 1991, 1992 Linus Torvalds * * 1997-11-02 Modified for POSIX.1b signals by Richard Henderson + * + * 2003-06-02 Jim Houston - Concurrent Computer Corp. + * Changes to use preallocated sigqueue structures + * to allow signals to be sent reliably. */ #define __KERNEL_SYSCALLS__ @@ -258,20 +262,38 @@ return sig; } +struct sigqueue *__sigqueue_alloc(void) +{ + struct sigqueue *q = 0; + + if (atomic_read(&nr_queued_signals) < max_queued_signals) + q = kmem_cache_alloc(sigqueue_cachep, GFP_ATOMIC); + if (q) { + atomic_inc(&nr_queued_signals); + INIT_LIST_HEAD(&q->list); + q->flags = 0; + q->lock = 0; + } + return(q); +} + +static inline void __sigqueue_free(struct sigqueue *q) +{ + if (q->flags & SIGQUEUE_PREALLOC) + return; + kmem_cache_free(sigqueue_cachep, q); + atomic_dec(&nr_queued_signals); +} + static void flush_sigqueue(struct sigpending *queue) { - struct sigqueue *q, *n; + struct sigqueue *q; sigemptyset(&queue->signal); - q = queue->head; - queue->head = NULL; - queue->tail = &queue->head; - - while (q) { - n = q->next; - kmem_cache_free(sigqueue_cachep, q); - atomic_dec(&nr_queued_signals); - q = n; + while (!list_empty(&queue->list)) { + q = list_entry(queue->list.next, struct sigqueue , list); + list_del_init(&q->list); + __sigqueue_free(q); } } @@ -411,15 +433,32 @@ static inline int collect_signal(int sig, struct sigpending *list, siginfo_t *info) { - if (sigismember(&list->signal, sig)) { - /* Collect the siginfo appropriate to this signal. */ - struct sigqueue *q, **pp; - pp = &list->head; - while ((q = *pp) != NULL) { - if (q->info.si_signo == sig) - goto found_it; - pp = &q->next; + struct sigqueue *q, *first = 0; + int still_pending = 0; + + if (unlikely(!sigismember(&list->signal, sig))) + return 0; + + /* + * Collect the siginfo appropriate to this signal. Check if + * there is another siginfo for the same signal. + */ + list_for_each_entry(q, &list->list, list) { + if (q->info.si_signo == sig) { + if (first) { + still_pending = 1; + break; + } + first = q; } + } + if (first) { + list_del_init(&first->list); + copy_siginfo(info, &first->info); + __sigqueue_free(first); + if (!still_pending) + sigdelset(&list->signal, sig); + } else { /* Ok, it wasn't in the queue. This must be a fast-pathed signal or we must have been @@ -431,31 +470,8 @@ info->si_code = 0; info->si_pid = 0; info->si_uid = 0; - return 1; - -found_it: - if ((*pp = q->next) == NULL) - list->tail = pp; - - /* Copy the sigqueue information and free the queue entry */ - copy_siginfo(info, &q->info); - kmem_cache_free(sigqueue_cachep,q); - atomic_dec(&nr_queued_signals); - - /* Non-RT signals can exist multiple times.. */ - if (sig >= SIGRTMIN) { - while ((q = *pp) != NULL) { - if (q->info.si_signo == sig) - goto found_another; - pp = &q->next; - } - } - - sigdelset(&list->signal, sig); -found_another: - return 1; } - return 0; + return 1; } static int __dequeue_signal(struct sigpending *pending, sigset_t *mask, @@ -544,25 +560,18 @@ */ static int rm_from_queue(unsigned long mask, struct sigpending *s) { - struct sigqueue *q, **pp; + struct sigqueue *q, *n; if (!sigtestsetmask(&s->signal, mask)) return 0; sigdelsetmask(&s->signal, mask); - - pp = &s->head; - - while ((q = *pp) != NULL) { + list_for_each_entry_safe(q, n, &s->list, list) { if (q->info.si_signo < SIGRTMIN && - (mask & sigmask (q->info.si_signo))) { - if ((*pp = q->next) == NULL) - s->tail = pp; - kmem_cache_free(sigqueue_cachep,q); - atomic_dec(&nr_queued_signals); - continue; + (mask & sigmask(q->info.si_signo))) { + list_del_init(&q->list); + __sigqueue_free(q); } - pp = &q->next; } return 1; } @@ -695,9 +704,8 @@ if (q) { atomic_inc(&nr_queued_signals); - q->next = NULL; - *signals->tail = q; - signals->tail = &q->next; + q->flags = 0; + list_add_tail(&q->list, &signals->list); switch ((unsigned long) info) { case 0: q->info.si_signo = sig; @@ -827,49 +835,11 @@ && !((p)->flags & PF_EXITING) \ && (task_curr(p) || !signal_pending(p))) -static inline int -__group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p) + +static inline void +__group_complete_signal(int sig, struct task_struct *p, unsigned int mask) { struct task_struct *t; - unsigned int mask; - int ret = 0; - -#ifdef CONFIG_SMP - if (!spin_is_locked(&p->sighand->siglock)) - BUG(); -#endif - handle_stop_signal(sig, p); - - if (((unsigned long)info > 2) && (info->si_code == SI_TIMER)) - /* - * Set up a return to indicate that we dropped the signal. - */ - ret = info->si_sys_private; - - /* Short-circuit ignored signals. */ - if (sig_ignored(p, sig)) - return ret; - - if (LEGACY_QUEUE(&p->signal->shared_pending, sig)) - /* This is a non-RT signal and we already have one queued. */ - return ret; - - /* - * Don't bother zombies and stopped tasks (but - * SIGKILL will punch through stopped state) - */ - mask = TASK_DEAD | TASK_ZOMBIE; - if (sig != SIGKILL) - mask |= TASK_STOPPED; - - /* - * Put this signal on the shared-pending queue, or fail with EAGAIN. - * We always use the shared queue for process-wide signals, - * to avoid several races. - */ - ret = send_signal(sig, info, &p->signal->shared_pending); - if (unlikely(ret)) - return ret; /* * Now find a thread we can wake up to take the signal off the queue. @@ -884,7 +854,7 @@ * There is just one thread and it does not need to be woken. * It will dequeue unblocked signals before it runs again. */ - return 0; + return; else { /* * Otherwise try to find a suitable thread. @@ -903,7 +873,7 @@ * Any eligible threads will see * the signal in the queue soon. */ - return 0; + return; } p->signal->curr_target = t; } @@ -934,7 +904,7 @@ signal_wake_up(t, 1); t = next_thread(t); } while (t != p); - return 0; + return; } /* @@ -958,7 +928,7 @@ t = next_thread(t); } while (t != p); wake_up_process(p->signal->group_exit_task); - return 0; + return; } /* @@ -966,6 +936,53 @@ * Tell the chosen thread to wake up and dequeue it. */ signal_wake_up(t, sig == SIGKILL); + return; +} + +static inline int +__group_send_sig_info(int sig, struct siginfo *info, struct task_struct *p) +{ + unsigned int mask; + int ret = 0; + +#ifdef CONFIG_SMP + if (!spin_is_locked(&p->sighand->siglock)) + BUG(); +#endif + handle_stop_signal(sig, p); + + if (((unsigned long)info > 2) && (info->si_code == SI_TIMER)) + /* + * Set up a return to indicate that we dropped the signal. + */ + ret = info->si_sys_private; + + /* Short-circuit ignored signals. */ + if (sig_ignored(p, sig)) + return ret; + + if (LEGACY_QUEUE(&p->signal->shared_pending, sig)) + /* This is a non-RT signal and we already have one queued. */ + return ret; + + /* + * Don't bother zombies and stopped tasks (but + * SIGKILL will punch through stopped state) + */ + mask = TASK_DEAD | TASK_ZOMBIE; + if (sig != SIGKILL) + mask |= TASK_STOPPED; + + /* + * Put this signal on the shared-pending queue, or fail with EAGAIN. + * We always use the shared queue for process-wide signals, + * to avoid several races. + */ + ret = send_signal(sig, info, &p->signal->shared_pending); + if (unlikely(ret)) + return ret; + + __group_complete_signal(sig, p, mask); return 0; } @@ -1195,6 +1212,142 @@ } /* + * These functions support sending signals using preallocated sigqueue + * structures. This is needed "because realtime applications cannot + * afford to lose notifications of asynchronous events, like timer + * expirations or I/O completions". In the case of Posix Timers + * we allocate the sigqueue structure from the timer_create. If this + * allocation fails we are able to report the failure to the application + * with an EAGAIN error. + */ + +struct sigqueue *sigqueue_alloc(void) +{ + struct sigqueue *q; + + if ((q = __sigqueue_alloc())) + q->flags |= SIGQUEUE_PREALLOC; + return(q); +} + +void sigqueue_free(struct sigqueue *q) +{ + unsigned long flags; + BUG_ON(!(q->flags & SIGQUEUE_PREALLOC)); + /* + * If the signal is still pending remove it from the + * pending queue. + */ + if (unlikely(!list_empty(&q->list))) { + read_lock(&tasklist_lock); + spin_lock_irqsave(q->lock, flags); + if (!list_empty(&q->list)) + list_del_init(&q->list); + spin_unlock_irqrestore(q->lock, flags); + read_unlock(&tasklist_lock); + } + q->flags &= ~SIGQUEUE_PREALLOC; + __sigqueue_free(q); +} + +int +send_sigqueue(int sig, struct sigqueue *q, struct task_struct *p) +{ + unsigned long flags; + int ret = 0; + + /* + * We need the tasklist lock even for the specific + * thread case (when we don't need to follow the group + * lists) in order to avoid races with "p->sighand" + * going away or changing from under us. + */ + BUG_ON(!(q->flags & SIGQUEUE_PREALLOC)); + read_lock(&tasklist_lock); + spin_lock_irqsave(&p->sighand->siglock, flags); + + if (unlikely(!list_empty(&q->list))) { + /* + * If an SI_TIMER entry is already queue just increment + * the overrun count. + */ + if (q->info.si_code != SI_TIMER) + BUG(); + q->info.si_overrun++; + goto out; + } + /* Short-circuit ignored signals. */ + if (sig_ignored(p, sig)) { + ret = 1; + goto out; + } + + q->lock = &p->sighand->siglock; + list_add_tail(&q->list, &p->pending.list); + sigaddset(&p->pending.signal, sig); + if (!sigismember(&p->blocked, sig)) + signal_wake_up(p, sig == SIGKILL); + +out: + spin_unlock_irqrestore(&p->sighand->siglock, flags); + read_unlock(&tasklist_lock); + return(ret); +} + +int +send_group_sigqueue(int sig, struct sigqueue *q, struct task_struct *p) +{ + unsigned long flags; + unsigned int mask; + int ret = 0; + + BUG_ON(!(q->flags & SIGQUEUE_PREALLOC)); + read_lock(&tasklist_lock); + spin_lock_irqsave(&p->sighand->siglock, flags); + handle_stop_signal(sig, p); + + /* Short-circuit ignored signals. */ + if (sig_ignored(p, sig)) { + ret = 1; + goto out; + } + + if (unlikely(!list_empty(&q->list))) { + /* + * If an SI_TIMER entry is already queue just increment + * the overrun count. Other uses should not try to + * send the signal multiple times. + */ + if (q->info.si_code != SI_TIMER) + BUG(); + q->info.si_overrun++; + goto out; + } + /* + * Don't bother zombies and stopped tasks (but + * SIGKILL will punch through stopped state) + */ + mask = TASK_DEAD | TASK_ZOMBIE; + if (sig != SIGKILL) + mask |= TASK_STOPPED; + + /* + * Put this signal on the shared-pending queue. + * We always use the shared queue for process-wide signals, + * to avoid several races. + */ + q->lock = &p->sighand->siglock; + list_add_tail(&q->list, &p->signal->shared_pending.list); + sigaddset(&p->signal->shared_pending.signal, sig); + + __group_complete_signal(sig, p, mask); +out: + spin_unlock_irqrestore(&p->sighand->siglock, flags); + read_unlock(&tasklist_lock); + return(ret); +} + +/* * Joy. Or not. Pthread wants us to wake up every thread * in our parent group. */ @@ -1646,6 +1799,10 @@ EXPORT_SYMBOL(send_sig); EXPORT_SYMBOL(send_sig_info); EXPORT_SYMBOL(send_group_sig_info); +EXPORT_SYMBOL(sigqueue_alloc); +EXPORT_SYMBOL(sigqueue_free); +EXPORT_SYMBOL(send_sigqueue); +EXPORT_SYMBOL(send_group_sigqueue); EXPORT_SYMBOL(sigprocmask); EXPORT_SYMBOL(block_all_signals); EXPORT_SYMBOL(unblock_all_signals); diff -Nru a/kernel/softirq.c b/kernel/softirq.c --- a/kernel/softirq.c Mon Jun 9 23:16:08 2003 +++ b/kernel/softirq.c Mon Jun 9 23:16:08 2003 @@ -14,6 +14,7 @@ #include <linux/init.h> #include <linux/mm.h> #include <linux/notifier.h> +#include <linux/cpu.h> /* - No shared variables, all the data are CPU local. diff -Nru a/kernel/sysctl.c b/kernel/sysctl.c --- a/kernel/sysctl.c Mon Jun 9 23:16:07 2003 +++ b/kernel/sysctl.c Mon Jun 9 23:16:07 2003 @@ -57,6 +57,7 @@ extern int cad_pid; extern int pid_max; extern int sysctl_lower_zone_protection; +extern int min_free_kbytes; /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */ static int maxolduid = 65535; @@ -149,219 +150,631 @@ /* The default sysctl tables: */ static ctl_table root_table[] = { - {CTL_KERN, "kernel", NULL, 0, 0555, kern_table}, - {CTL_VM, "vm", NULL, 0, 0555, vm_table}, + { + .ctl_name = CTL_KERN, + .procname = "kernel", + .mode = 0555, + .child = kern_table, + }, + { + .ctl_name = CTL_VM, + .procname = "vm", + .mode = 0555, + .child = vm_table, + }, #ifdef CONFIG_NET - {CTL_NET, "net", NULL, 0, 0555, net_table}, -#endif - {CTL_PROC, "proc", NULL, 0, 0555, proc_table}, - {CTL_FS, "fs", NULL, 0, 0555, fs_table}, - {CTL_DEBUG, "debug", NULL, 0, 0555, debug_table}, - {CTL_DEV, "dev", NULL, 0, 0555, dev_table}, - {0} + { + .ctl_name = CTL_NET, + .procname = "net", + .mode = 0555, + .child = net_table, + }, +#endif + { + .ctl_name = CTL_PROC, + .procname = "proc", + .mode = 0555, + .child = proc_table, + }, + { + .ctl_name = CTL_FS, + .procname = "fs", + .mode = 0555, + .child = fs_table, + }, + { + .ctl_name = CTL_DEBUG, + .procname = "debug", + .mode = 0555, + .child = debug_table, + }, + { + .ctl_name = CTL_DEV, + .procname = "dev", + .mode = 0555, + .child = dev_table, + }, + { .ctl_name = 0 } }; static ctl_table kern_table[] = { - {KERN_OSTYPE, "ostype", system_utsname.sysname, 64, - 0444, NULL, &proc_doutsstring, &sysctl_string}, - {KERN_OSRELEASE, "osrelease", system_utsname.release, 64, - 0444, NULL, &proc_doutsstring, &sysctl_string}, - {KERN_VERSION, "version", system_utsname.version, 64, - 0444, NULL, &proc_doutsstring, &sysctl_string}, - {KERN_NODENAME, "hostname", system_utsname.nodename, 64, - 0644, NULL, &proc_doutsstring, &sysctl_string}, - {KERN_DOMAINNAME, "domainname", system_utsname.domainname, 64, - 0644, NULL, &proc_doutsstring, &sysctl_string}, - {KERN_PANIC, "panic", &panic_timeout, sizeof(int), - 0644, NULL, &proc_dointvec}, - {KERN_CORE_USES_PID, "core_uses_pid", &core_uses_pid, sizeof(int), - 0644, NULL, &proc_dointvec}, - {KERN_CORE_PATTERN, "core_pattern", core_pattern, 64, - 0644, NULL, &proc_dostring, &sysctl_string}, - {KERN_TAINTED, "tainted", &tainted, sizeof(int), - 0644, NULL, &proc_dointvec}, - {KERN_CAP_BSET, "cap-bound", &cap_bset, sizeof(kernel_cap_t), - 0600, NULL, &proc_dointvec_bset}, + { + .ctl_name = KERN_OSTYPE, + .procname = "ostype", + .data = system_utsname.sysname, + .maxlen = 64, + .mode = 0444, + .proc_handler = &proc_doutsstring, + .strategy = &sysctl_string, + }, + { + .ctl_name = KERN_OSRELEASE, + .procname = "osrelease", + .data = system_utsname.release, + .maxlen = 64, + .mode = 0444, + .proc_handler = &proc_doutsstring, + .strategy = &sysctl_string, + }, + { + .ctl_name = KERN_VERSION, + .procname = "version", + .data = system_utsname.version, + .maxlen = 64, + .mode = 0444, + .proc_handler = &proc_doutsstring, + .strategy = &sysctl_string, + }, + { + .ctl_name = KERN_NODENAME, + .procname = "hostname", + .data = system_utsname.nodename, + .maxlen = 64, + .mode = 0644, + .proc_handler = &proc_doutsstring, + .strategy = &sysctl_string, + }, + { + .ctl_name = KERN_DOMAINNAME, + .procname = "domainname", + .data = system_utsname.domainname, + .maxlen = 64, + .mode = 0644, + .proc_handler = &proc_doutsstring, + .strategy = &sysctl_string, + }, + { + .ctl_name = KERN_PANIC, + .procname = "panic", + .data = &panic_timeout, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = KERN_CORE_USES_PID, + .procname = "core_uses_pid", + .data = &core_uses_pid, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = KERN_CORE_PATTERN, + .procname = "core_pattern", + .data = core_pattern, + .maxlen = 64, + .mode = 0644, + .proc_handler = &proc_dostring, + .strategy = &sysctl_string, + }, + { + .ctl_name = KERN_TAINTED, + .procname = "tainted", + .data = &tainted, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = KERN_CAP_BSET, + .procname = "cap-bound", + .data = &cap_bset, + .maxlen = sizeof(kernel_cap_t), + .mode = 0600, + .proc_handler = &proc_dointvec_bset, + }, #ifdef CONFIG_BLK_DEV_INITRD - {KERN_REALROOTDEV, "real-root-dev", &real_root_dev, sizeof(int), - 0644, NULL, &proc_dointvec}, + { + .ctl_name = KERN_REALROOTDEV, + .procname = "real-root-dev", + .data = &real_root_dev, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, #endif #ifdef __sparc__ - {KERN_SPARC_REBOOT, "reboot-cmd", reboot_command, - 256, 0644, NULL, &proc_dostring, &sysctl_string }, - {KERN_SPARC_STOP_A, "stop-a", &stop_a_enabled, sizeof (int), - 0644, NULL, &proc_dointvec}, + { + .ctl_name = KERN_SPARC_REBOOT, + .procname = "reboot-cmd", + .data = reboot_command, + .maxlen = 256, + .mode = 0644, + .proc_handler = &proc_dostring, + .strategy = &sysctl_string, + }, + { + .ctl_name = KERN_SPARC_STOP_A, + .procname = "stop-a", + .data = &stop_a_enabled, + .maxlen = sizeof (int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, #endif #if defined(CONFIG_PPC32) && defined(CONFIG_6xx) - {KERN_PPC_POWERSAVE_NAP, "powersave-nap", &powersave_nap, sizeof(int), - 0644, NULL, &proc_dointvec}, - {KERN_PPC_L2CR, "l2cr", NULL, 0, - 0644, NULL, &proc_dol2crvec}, -#endif - {KERN_CTLALTDEL, "ctrl-alt-del", &C_A_D, sizeof(int), - 0644, NULL, &proc_dointvec}, - {KERN_PRINTK, "printk", &console_loglevel, 4*sizeof(int), - 0644, NULL, &proc_dointvec}, + { + .ctl_name = KERN_PPC_POWERSAVE_NAP, + .procname = "powersave-nap", + .data = &powersave_nap, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = KERN_PPC_L2CR, + .procname = "l2cr", + .mode = 0644, + .proc_handler = &proc_dol2crvec, + }, +#endif + { + .ctl_name = KERN_CTLALTDEL, + .procname = "ctrl-alt-del", + .data = &C_A_D, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = KERN_PRINTK, + .procname = "printk", + .data = &console_loglevel, + .maxlen = 4*sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, #ifdef CONFIG_KMOD - {KERN_MODPROBE, "modprobe", &modprobe_path, 256, - 0644, NULL, &proc_dostring, &sysctl_string }, + { + .ctl_name = KERN_MODPROBE, + .procname = "modprobe", + .data = &modprobe_path, + .maxlen = 256, + .mode = 0644, + .proc_handler = &proc_dostring, + .strategy = &sysctl_string, + }, #endif #ifdef CONFIG_HOTPLUG - {KERN_HOTPLUG, "hotplug", &hotplug_path, 256, - 0644, NULL, &proc_dostring, &sysctl_string }, + { + .ctl_name = KERN_HOTPLUG, + .procname = "hotplug", + .data = &hotplug_path, + .maxlen = 256, + .mode = 0644, + .proc_handler = &proc_dostring, + .strategy = &sysctl_string, + }, #endif #ifdef CONFIG_CHR_DEV_SG - {KERN_SG_BIG_BUFF, "sg-big-buff", &sg_big_buff, sizeof (int), - 0444, NULL, &proc_dointvec}, + { + .ctl_name = KERN_SG_BIG_BUFF, + .procname = "sg-big-buff", + .data = &sg_big_buff, + .maxlen = sizeof (int), + .mode = 0444, + .proc_handler = &proc_dointvec, + }, #endif #ifdef CONFIG_BSD_PROCESS_ACCT - {KERN_ACCT, "acct", &acct_parm, 3*sizeof(int), - 0644, NULL, &proc_dointvec}, -#endif - {KERN_RTSIGNR, "rtsig-nr", &nr_queued_signals, sizeof(int), - 0444, NULL, &proc_dointvec}, - {KERN_RTSIGMAX, "rtsig-max", &max_queued_signals, sizeof(int), - 0644, NULL, &proc_dointvec}, + { + .ctl_name = KERN_ACCT, + .procname = "acct", + .data = &acct_parm, + .maxlen = 3*sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, +#endif + { + .ctl_name = KERN_RTSIGNR, + .procname = "rtsig-nr", + .data = &nr_queued_signals, + .maxlen = sizeof(int), + .mode = 0444, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = KERN_RTSIGMAX, + .procname = "rtsig-max", + .data = &max_queued_signals, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, #ifdef CONFIG_SYSVIPC - {KERN_SHMMAX, "shmmax", &shm_ctlmax, sizeof (size_t), - 0644, NULL, &proc_doulongvec_minmax}, - {KERN_SHMALL, "shmall", &shm_ctlall, sizeof (size_t), - 0644, NULL, &proc_doulongvec_minmax}, - {KERN_SHMMNI, "shmmni", &shm_ctlmni, sizeof (int), - 0644, NULL, &proc_dointvec}, - {KERN_MSGMAX, "msgmax", &msg_ctlmax, sizeof (int), - 0644, NULL, &proc_dointvec}, - {KERN_MSGMNI, "msgmni", &msg_ctlmni, sizeof (int), - 0644, NULL, &proc_dointvec}, - {KERN_MSGMNB, "msgmnb", &msg_ctlmnb, sizeof (int), - 0644, NULL, &proc_dointvec}, - {KERN_SEM, "sem", &sem_ctls, 4*sizeof (int), - 0644, NULL, &proc_dointvec}, + { + .ctl_name = KERN_SHMMAX, + .procname = "shmmax", + .data = &shm_ctlmax, + .maxlen = sizeof (size_t), + .mode = 0644, + .proc_handler = &proc_doulongvec_minmax, + }, + { + .ctl_name = KERN_SHMALL, + .procname = "shmall", + .data = &shm_ctlall, + .maxlen = sizeof (size_t), + .mode = 0644, + .proc_handler = &proc_doulongvec_minmax, + }, + { + .ctl_name = KERN_SHMMNI, + .procname = "shmmni", + .data = &shm_ctlmni, + .maxlen = sizeof (int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = KERN_MSGMAX, + .procname = "msgmax", + .data = &msg_ctlmax, + .maxlen = sizeof (int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = KERN_MSGMNI, + .procname = "msgmni", + .data = &msg_ctlmni, + .maxlen = sizeof (int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = KERN_MSGMNB, + .procname = "msgmnb", + .data = &msg_ctlmnb, + .maxlen = sizeof (int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = KERN_SEM, + .procname = "sem", + .data = &sem_ctls, + .maxlen = 4*sizeof (int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, #endif #ifdef CONFIG_MAGIC_SYSRQ - {KERN_SYSRQ, "sysrq", &sysrq_enabled, sizeof (int), - 0644, NULL, &proc_dointvec}, -#endif - {KERN_CADPID, "cad_pid", &cad_pid, sizeof (int), - 0600, NULL, &proc_dointvec}, - {KERN_MAX_THREADS, "threads-max", &max_threads, sizeof(int), - 0644, NULL, &proc_dointvec}, - {KERN_RANDOM, "random", NULL, 0, 0555, random_table}, - {KERN_OVERFLOWUID, "overflowuid", &overflowuid, sizeof(int), 0644, NULL, - &proc_dointvec_minmax, &sysctl_intvec, NULL, - &minolduid, &maxolduid}, - {KERN_OVERFLOWGID, "overflowgid", &overflowgid, sizeof(int), 0644, NULL, - &proc_dointvec_minmax, &sysctl_intvec, NULL, - &minolduid, &maxolduid}, + { + .ctl_name = KERN_SYSRQ, + .procname = "sysrq", + .data = &sysrq_enabled, + .maxlen = sizeof (int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, +#endif + { + .ctl_name = KERN_CADPID, + .procname = "cad_pid", + .data = &cad_pid, + .maxlen = sizeof (int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = KERN_MAX_THREADS, + .procname = "threads-max", + .data = &max_threads, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = KERN_RANDOM, + .procname = "random", + .mode = 0555, + .child = random_table, + }, + { + .ctl_name = KERN_OVERFLOWUID, + .procname = "overflowuid", + .data = &overflowuid, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &minolduid, + .extra2 = &maxolduid, + }, + { + .ctl_name = KERN_OVERFLOWGID, + .procname = "overflowgid", + .data = &overflowgid, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &minolduid, + .extra2 = &maxolduid, + }, #ifdef CONFIG_ARCH_S390 #ifdef CONFIG_MATHEMU - {KERN_IEEE_EMULATION_WARNINGS,"ieee_emulation_warnings", - &sysctl_ieee_emulation_warnings,sizeof(int),0644,NULL,&proc_dointvec}, -#endif - {KERN_S390_USER_DEBUG_LOGGING,"userprocess_debug", - &sysctl_userprocess_debug,sizeof(int),0644,NULL,&proc_dointvec}, -#endif - {KERN_PIDMAX, "pid_max", &pid_max, sizeof (int), - 0600, NULL, &proc_dointvec}, - {KERN_PANIC_ON_OOPS,"panic_on_oops", - &panic_on_oops,sizeof(int),0644,NULL,&proc_dointvec}, - {0} + { + .ctl_name = KERN_IEEE_EMULATION_WARNINGS, + .procname = "ieee_emulation_warnings", + .data = &sysctl_ieee_emulation_warnings, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, +#endif + { + .ctl_name = KERN_S390_USER_DEBUG_LOGGING, + .procname = "userprocess_debug", + .data = &sysctl_userprocess_debug, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, +#endif + { + .ctl_name = KERN_PIDMAX, + .procname = "pid_max", + .data = &pid_max, + .maxlen = sizeof (int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = KERN_PANIC_ON_OOPS, + .procname = "panic_on_oops", + .data = &panic_on_oops, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { .ctl_name = 0 } }; /* Constants for minimum and maximum testing in vm_table. We use these as one-element integer vectors. */ static int zero = 0; -static int one = 1; static int one_hundred = 100; static ctl_table vm_table[] = { - {VM_OVERCOMMIT_MEMORY, "overcommit_memory", &sysctl_overcommit_memory, - sizeof(sysctl_overcommit_memory), 0644, NULL, &proc_dointvec}, - {VM_OVERCOMMIT_RATIO, "overcommit_ratio", - &sysctl_overcommit_ratio, sizeof(sysctl_overcommit_ratio), 0644, - NULL, &proc_dointvec}, - {VM_PAGE_CLUSTER, "page-cluster", - &page_cluster, sizeof(int), 0644, NULL, &proc_dointvec}, - {VM_DIRTY_BACKGROUND, "dirty_background_ratio", - &dirty_background_ratio, sizeof(dirty_background_ratio), - 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL, - &zero, &one_hundred }, - {VM_DIRTY_RATIO, "dirty_ratio", &vm_dirty_ratio, - sizeof(vm_dirty_ratio), 0644, NULL, &proc_dointvec_minmax, - &sysctl_intvec, NULL, &zero, &one_hundred }, - {VM_DIRTY_WB_CS, "dirty_writeback_centisecs", - &dirty_writeback_centisecs, sizeof(dirty_writeback_centisecs), 0644, - NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL, - /* Here, we define the range of possible values for - dirty_writeback_centisecs. - - The default value is 5 seconds (500 centisec). We will use 1 - centisec, the smallest possible value that could make any sort of - sense. If we allowed the user to set the interval to 0 seconds - (which would presumably mean to chew up all of the CPU looking for - dirty pages and writing them out, without taking a break), the - interval would effectively become 1 second (100 centisecs), due to - some nicely documented throttling code in wb_kupdate(). - - There is no maximum legal value for dirty_writeback. */ - &one , NULL}, - {VM_DIRTY_EXPIRE_CS, "dirty_expire_centisecs", - &dirty_expire_centisecs, sizeof(dirty_expire_centisecs), 0644, - NULL, &proc_dointvec}, - { VM_NR_PDFLUSH_THREADS, "nr_pdflush_threads", - &nr_pdflush_threads, sizeof nr_pdflush_threads, - 0444 /* read-only*/, NULL, &proc_dointvec}, - {VM_SWAPPINESS, "swappiness", &vm_swappiness, sizeof(vm_swappiness), - 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL, &zero, - &one_hundred }, + { + .ctl_name = VM_OVERCOMMIT_MEMORY, + .procname = "overcommit_memory", + .data = &sysctl_overcommit_memory, + .maxlen = sizeof(sysctl_overcommit_memory), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = VM_OVERCOMMIT_RATIO, + .procname = "overcommit_ratio", + .data = &sysctl_overcommit_ratio, + .maxlen = sizeof(sysctl_overcommit_ratio), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = VM_PAGE_CLUSTER, + .procname = "page-cluster", + .data = &page_cluster, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = VM_DIRTY_BACKGROUND, + .procname = "dirty_background_ratio", + .data = &dirty_background_ratio, + .maxlen = sizeof(dirty_background_ratio), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &zero, + .extra2 = &one_hundred, + }, + { + .ctl_name = VM_DIRTY_RATIO, + .procname = "dirty_ratio", + .data = &vm_dirty_ratio, + .maxlen = sizeof(vm_dirty_ratio), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &zero, + .extra2 = &one_hundred, + }, + { + .ctl_name = VM_DIRTY_WB_CS, + .procname = "dirty_writeback_centisecs", + .data = &dirty_writeback_centisecs, + .maxlen = sizeof(dirty_writeback_centisecs), + .mode = 0644, + .proc_handler = dirty_writeback_centisecs_handler, + }, + { + .ctl_name = VM_DIRTY_EXPIRE_CS, + .procname = "dirty_expire_centisecs", + .data = &dirty_expire_centisecs, + .maxlen = sizeof(dirty_expire_centisecs), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = VM_NR_PDFLUSH_THREADS, + .procname = "nr_pdflush_threads", + .data = &nr_pdflush_threads, + .maxlen = sizeof nr_pdflush_threads, + .mode = 0444 /* read-only*/, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = VM_SWAPPINESS, + .procname = "swappiness", + .data = &vm_swappiness, + .maxlen = sizeof(vm_swappiness), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &zero, + .extra2 = &one_hundred, + }, #ifdef CONFIG_HUGETLB_PAGE - {VM_HUGETLB_PAGES, "nr_hugepages", &htlbpage_max, sizeof(int), 0644, - NULL, &hugetlb_sysctl_handler}, -#endif - {VM_LOWER_ZONE_PROTECTION, "lower_zone_protection", - &sysctl_lower_zone_protection, sizeof(sysctl_lower_zone_protection), - 0644, NULL, &proc_dointvec_minmax, &sysctl_intvec, NULL, &zero, - NULL, }, - {0} + { + .ctl_name = VM_HUGETLB_PAGES, + .procname = "nr_hugepages", + .data = &htlbpage_max, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &hugetlb_sysctl_handler, + }, +#endif + { + .ctl_name = VM_LOWER_ZONE_PROTECTION, + .procname = "lower_zone_protection", + .data = &sysctl_lower_zone_protection, + .maxlen = sizeof(sysctl_lower_zone_protection), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &zero, + }, + { + .ctl_name = VM_MIN_FREE_KBYTES, + .procname = "min_free_kbytes", + .data = &min_free_kbytes, + .maxlen = sizeof(min_free_kbytes), + .mode = 0644, + .proc_handler = &min_free_kbytes_sysctl_handler, + .strategy = &sysctl_intvec, + .extra1 = &zero, + }, + { .ctl_name = 0 } }; static ctl_table proc_table[] = { - {0} + { .ctl_name = 0 } }; static ctl_table fs_table[] = { - {FS_NRINODE, "inode-nr", &inodes_stat, 2*sizeof(int), - 0444, NULL, &proc_dointvec}, - {FS_STATINODE, "inode-state", &inodes_stat, 7*sizeof(int), - 0444, NULL, &proc_dointvec}, - {FS_NRFILE, "file-nr", &files_stat, 3*sizeof(int), - 0444, NULL, &proc_dointvec}, - {FS_MAXFILE, "file-max", &files_stat.max_files, sizeof(int), - 0644, NULL, &proc_dointvec}, - {FS_DENTRY, "dentry-state", &dentry_stat, 6*sizeof(int), - 0444, NULL, &proc_dointvec}, - {FS_OVERFLOWUID, "overflowuid", &fs_overflowuid, sizeof(int), 0644, NULL, - &proc_dointvec_minmax, &sysctl_intvec, NULL, - &minolduid, &maxolduid}, - {FS_OVERFLOWGID, "overflowgid", &fs_overflowgid, sizeof(int), 0644, NULL, - &proc_dointvec_minmax, &sysctl_intvec, NULL, - &minolduid, &maxolduid}, - {FS_LEASES, "leases-enable", &leases_enable, sizeof(int), - 0644, NULL, &proc_dointvec}, - {FS_DIR_NOTIFY, "dir-notify-enable", &dir_notify_enable, - sizeof(int), 0644, NULL, &proc_dointvec}, - {FS_LEASE_TIME, "lease-break-time", &lease_break_time, sizeof(int), - 0644, NULL, &proc_dointvec}, - {0} + { + .ctl_name = FS_NRINODE, + .procname = "inode-nr", + .data = &inodes_stat, + .maxlen = 2*sizeof(int), + .mode = 0444, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = FS_STATINODE, + .procname = "inode-state", + .data = &inodes_stat, + .maxlen = 7*sizeof(int), + .mode = 0444, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = FS_NRFILE, + .procname = "file-nr", + .data = &files_stat, + .maxlen = 3*sizeof(int), + .mode = 0444, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = FS_MAXFILE, + .procname = "file-max", + .data = &files_stat.max_files, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = FS_DENTRY, + .procname = "dentry-state", + .data = &dentry_stat, + .maxlen = 6*sizeof(int), + .mode = 0444, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = FS_OVERFLOWUID, + .procname = "overflowuid", + .data = &fs_overflowuid, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &minolduid, + .extra2 = &maxolduid, + }, + { + .ctl_name = FS_OVERFLOWGID, + .procname = "overflowgid", + .data = &fs_overflowgid, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &minolduid, + .extra2 = &maxolduid, + }, + { + .ctl_name = FS_LEASES, + .procname = "leases-enable", + .data = &leases_enable, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = FS_DIR_NOTIFY, + .procname = "dir-notify-enable", + .data = &dir_notify_enable, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = FS_LEASE_TIME, + .procname = "lease-break-time", + .data = &lease_break_time, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, + { .ctl_name = 0 } }; static ctl_table debug_table[] = { - {0} + { .ctl_name = 0 } }; static ctl_table dev_table[] = { - {0} + { .ctl_name = 0 } }; extern void init_irq_proc (void); diff -Nru a/kernel/time.c b/kernel/time.c --- a/kernel/time.c Mon Jun 9 23:16:08 2003 +++ b/kernel/time.c Mon Jun 9 23:16:08 2003 @@ -35,8 +35,6 @@ */ struct timezone sys_tz; -extern unsigned long last_time_offset; - #if !defined(__alpha__) && !defined(__ia64__) /* @@ -77,9 +75,10 @@ if (get_user(value, tptr)) return -EFAULT; write_seqlock_irq(&xtime_lock); + + time_interpolator_reset(); xtime.tv_sec = value; xtime.tv_nsec = 0; - last_time_offset = 0; time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; time_maxerror = NTP_PHASE_LIMIT; @@ -125,7 +124,7 @@ { write_seqlock_irq(&xtime_lock); xtime.tv_sec += sys_tz.tz_minuteswest * 60; - last_time_offset = 0; + time_interpolator_update(sys_tz.tz_minuteswest * 60 * NSEC_PER_SEC); write_sequnlock_irq(&xtime_lock); } @@ -381,7 +380,6 @@ txc->calcnt = pps_calcnt; txc->errcnt = pps_errcnt; txc->stbcnt = pps_stbcnt; - last_time_offset = 0; write_sequnlock_irq(&xtime_lock); do_gettimeofday(&txc->time); return(result); diff -Nru a/kernel/timer.c b/kernel/timer.c --- a/kernel/timer.c Mon Jun 9 23:16:17 2003 +++ b/kernel/timer.c Mon Jun 9 23:16:17 2003 @@ -29,6 +29,7 @@ #include <linux/thread_info.h> #include <linux/time.h> #include <linux/jiffies.h> +#include <linux/cpu.h> #include <asm/uaccess.h> #include <asm/div64.h> @@ -517,6 +518,7 @@ if (xtime.tv_sec % 86400 == 0) { xtime.tv_sec--; wall_to_monotonic.tv_sec++; + time_interpolator_update(-NSEC_PER_SEC); time_state = TIME_OOP; clock_was_set(); printk(KERN_NOTICE "Clock: inserting leap second 23:59:60 UTC\n"); @@ -527,6 +529,7 @@ if ((xtime.tv_sec + 1) % 86400 == 0) { xtime.tv_sec++; wall_to_monotonic.tv_sec--; + time_interpolator_update(NSEC_PER_SEC); time_state = TIME_WAIT; clock_was_set(); printk(KERN_NOTICE "Clock: deleting leap second 23:59:59 UTC\n"); @@ -605,7 +608,7 @@ /* in the NTP reference this is called "hardclock()" */ static void update_wall_time_one_tick(void) { - long time_adjust_step; + long time_adjust_step, delta_nsec; if ( (time_adjust_step = time_adjust) != 0 ) { /* We are doing an adjtime thing. @@ -621,11 +624,11 @@ time_adjust_step = tickadj; else if (time_adjust < -tickadj) time_adjust_step = -tickadj; - + /* Reduce by this step the amount of time left */ time_adjust -= time_adjust_step; } - xtime.tv_nsec += tick_nsec + time_adjust_step * 1000; + delta_nsec = tick_nsec + time_adjust_step * 1000; /* * Advance the phase, once it gets to one microsecond, then * advance the tick more. @@ -634,13 +637,15 @@ if (time_phase <= -FINEUSEC) { long ltemp = -time_phase >> (SHIFT_SCALE - 10); time_phase += ltemp << (SHIFT_SCALE - 10); - xtime.tv_nsec -= ltemp; + delta_nsec -= ltemp; } else if (time_phase >= FINEUSEC) { long ltemp = time_phase >> (SHIFT_SCALE - 10); time_phase -= ltemp << (SHIFT_SCALE - 10); - xtime.tv_nsec += ltemp; + delta_nsec += ltemp; } + xtime.tv_nsec += delta_nsec; + time_interpolator_update(delta_nsec); } /* @@ -660,6 +665,7 @@ if (xtime.tv_nsec >= 1000000000) { xtime.tv_nsec -= 1000000000; xtime.tv_sec++; + time_interpolator_update(NSEC_PER_SEC); second_overflow(); } } @@ -777,7 +783,6 @@ #ifndef ARCH_HAVE_XTIME_LOCK seqlock_t xtime_lock __cacheline_aligned_in_smp = SEQLOCK_UNLOCKED; #endif -unsigned long last_time_offset; /* * This function runs timers and the timer-tq in bottom half context. @@ -811,7 +816,6 @@ wall_jiffies += ticks; update_wall_time(ticks); } - last_time_offset = 0; calc_load(ticks); } @@ -1221,3 +1225,65 @@ register_cpu_notifier(&timers_nb); open_softirq(TIMER_SOFTIRQ, run_timer_softirq, NULL); } + +#ifdef CONFIG_TIME_INTERPOLATION +volatile unsigned long last_nsec_offset; +#ifndef __HAVE_ARCH_CMPXCHG +spinlock_t last_nsec_offset_lock = SPIN_LOCK_UNLOCKED; +#endif + +struct time_interpolator *time_interpolator; +static struct time_interpolator *time_interpolator_list; +static spinlock_t time_interpolator_lock = SPIN_LOCK_UNLOCKED; + +static inline int +is_better_time_interpolator(struct time_interpolator *new) +{ + if (!time_interpolator) + return 1; + return new->frequency > 2*time_interpolator->frequency || + (unsigned long)new->drift < (unsigned long)time_interpolator->drift; +} + +void +register_time_interpolator(struct time_interpolator *ti) +{ + spin_lock(&time_interpolator_lock); + write_seqlock_irq(&xtime_lock); + if (is_better_time_interpolator(ti)) + time_interpolator = ti; + write_sequnlock_irq(&xtime_lock); + + ti->next = time_interpolator_list; + time_interpolator_list = ti; + spin_unlock(&time_interpolator_lock); +} + +void +unregister_time_interpolator(struct time_interpolator *ti) +{ + struct time_interpolator *curr, **prev; + + spin_lock(&time_interpolator_lock); + prev = &time_interpolator_list; + for (curr = *prev; curr; curr = curr->next) { + if (curr == ti) { + *prev = curr->next; + break; + } + prev = &curr->next; + } + + write_seqlock_irq(&xtime_lock); + if (ti == time_interpolator) { + /* we lost the best time-interpolator: */ + time_interpolator = NULL; + /* find the next-best interpolator */ + for (curr = time_interpolator_list; curr; curr = curr->next) + if (is_better_time_interpolator(curr)) + time_interpolator = curr; + } + write_sequnlock_irq(&xtime_lock); + spin_unlock(&time_interpolator_lock); +} +#endif /* CONFIG_TIME_INTERPOLATION */ diff -Nru a/lib/Makefile b/lib/Makefile --- a/lib/Makefile Mon Jun 9 23:16:06 2003 +++ b/lib/Makefile Mon Jun 9 23:16:06 2003 @@ -6,18 +6,17 @@ # unless it's something special (ie not a .c file). # -L_TARGET := lib.a -obj-y := errno.o ctype.o string.o vsprintf.o cmdline.o \ +lib-y := errno.o ctype.o string.o vsprintf.o cmdline.o \ bust_spinlocks.o rbtree.o radix-tree.o dump_stack.o \ kobject.o idr.o -obj-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o -obj-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o -obj-$(CONFIG_SMP) += percpu_counter.o +lib-$(CONFIG_RWSEM_GENERIC_SPINLOCK) += rwsem-spinlock.o +lib-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += rwsem.o +lib-$(CONFIG_SMP) += percpu_counter.o ifneq ($(CONFIG_HAVE_DEC_LOCK),y) - obj-y += dec_and_lock.o + lib-y += dec_and_lock.o endif obj-$(CONFIG_CRC32) += crc32.o diff -Nru a/lib/kobject.c b/lib/kobject.c --- a/lib/kobject.c Mon Jun 9 23:16:18 2003 +++ b/lib/kobject.c Mon Jun 9 23:16:18 2003 @@ -3,6 +3,11 @@ * * Copyright (c) 2002-2003 Patrick Mochel <mochel@osdl.org> * + * This file is released under the GPLv2. + * + * + * Please see the file Documentation/kobject.txt for critical information + * about using the kobject interface. */ #undef DEBUG @@ -12,10 +17,6 @@ #include <linux/module.h> #include <linux/stat.h> -/* This lock can be removed entirely when the sysfs_init() code is cleaned up - * to not try to reference itself before it is initialized. */ -static spinlock_t kobj_lock = SPIN_LOCK_UNLOCKED; - /** * populate_dir - populate directory with attributes. * @kobj: object we're working on. @@ -345,14 +346,12 @@ struct kobject * kobject_get(struct kobject * kobj) { struct kobject * ret = kobj; - unsigned long flags; - spin_lock_irqsave(&kobj_lock, flags); - if (kobj && atomic_read(&kobj->refcount) > 0) + if (kobj) { + WARN_ON(!atomic_read(&kobj->refcount)); atomic_inc(&kobj->refcount); - else + } else ret = NULL; - spin_unlock_irqrestore(&kobj_lock, flags); return ret; } @@ -382,15 +381,8 @@ void kobject_put(struct kobject * kobj) { - unsigned long flags; - - local_irq_save(flags); - if (atomic_dec_and_lock(&kobj->refcount, &kobj_lock)) { - spin_unlock_irqrestore(&kobj_lock, flags); + if (atomic_dec_and_test(&kobj->refcount)) kobject_cleanup(kobj); - } else { - local_irq_restore(flags); - } } diff -Nru a/lib/zlib_deflate/deflate.c b/lib/zlib_deflate/deflate.c --- a/lib/zlib_deflate/deflate.c Mon Jun 9 23:16:07 2003 +++ b/lib/zlib_deflate/deflate.c Mon Jun 9 23:16:07 2003 @@ -63,22 +63,22 @@ finish_done /* finish done, accept no more input or output */ } block_state; -typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +typedef block_state (*compress_func) (deflate_state *s, int flush); /* Compression function. Returns the block state after the call. */ -local void fill_window OF((deflate_state *s)); -local block_state deflate_stored OF((deflate_state *s, int flush)); -local block_state deflate_fast OF((deflate_state *s, int flush)); -local block_state deflate_slow OF((deflate_state *s, int flush)); -local void lm_init OF((deflate_state *s)); -local void putShortMSB OF((deflate_state *s, uInt b)); -local void flush_pending OF((z_streamp strm)); -local int read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); -local uInt longest_match OF((deflate_state *s, IPos cur_match)); +static void fill_window (deflate_state *s); +static block_state deflate_stored (deflate_state *s, int flush); +static block_state deflate_fast (deflate_state *s, int flush); +static block_state deflate_slow (deflate_state *s, int flush); +static void lm_init (deflate_state *s); +static void putShortMSB (deflate_state *s, uInt b); +static void flush_pending (z_streamp strm); +static int read_buf (z_streamp strm, Byte *buf, unsigned size); +static uInt longest_match (deflate_state *s, IPos cur_match); #ifdef DEBUG_ZLIB -local void check_match OF((deflate_state *s, IPos start, IPos match, - int length)); +static void check_match (deflate_state *s, IPos start, IPos match, + int length); #endif /* =========================================================================== @@ -111,7 +111,7 @@ compress_func func; } config; -local const config configuration_table[10] = { +static const config configuration_table[10] = { /* good lazy nice chain */ /* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ /* 1 */ {4, 4, 8, 4, deflate_fast}, /* maximum speed, no lazy matches */ @@ -161,14 +161,15 @@ */ #define CLEAR_HASH(s) \ s->head[s->hash_size-1] = NIL; \ - memset((charf *)s->head, 0, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + memset((char *)s->head, 0, (unsigned)(s->hash_size-1)*sizeof(*s->head)); /* ========================================================================= */ -int zlib_deflateInit_(strm, level, version, stream_size) - z_streamp strm; - int level; - const char *version; - int stream_size; +int zlib_deflateInit_( + z_streamp strm, + int level, + const char *version, + int stream_size +) { return zlib_deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, @@ -177,34 +178,34 @@ } /* ========================================================================= */ -int zlib_deflateInit2_(strm, level, method, windowBits, memLevel, strategy, - version, stream_size) - z_streamp strm; - int level; - int method; - int windowBits; - int memLevel; - int strategy; - const char *version; - int stream_size; +int zlib_deflateInit2_( + z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy, + const char *version, + int stream_size +) { deflate_state *s; int noheader = 0; static char* my_version = ZLIB_VERSION; deflate_workspace *mem; - ushf *overlay; + ush *overlay; /* We overlay pending_buf and d_buf+l_buf. This works since the average * output size for (length,distance) codes is <= 24 bits. */ - if (version == Z_NULL || version[0] != my_version[0] || + if (version == NULL || version[0] != my_version[0] || stream_size != sizeof(z_stream)) { return Z_VERSION_ERROR; } - if (strm == Z_NULL) return Z_STREAM_ERROR; + if (strm == NULL) return Z_STREAM_ERROR; - strm->msg = Z_NULL; + strm->msg = NULL; if (level == Z_DEFAULT_COMPRESSION) level = 6; @@ -215,12 +216,12 @@ windowBits = -windowBits; } if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || - windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + windowBits < 9 || windowBits > 15 || level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) { return Z_STREAM_ERROR; } s = (deflate_state *) &(mem->deflate_memory); - strm->state = (struct internal_state FAR *)s; + strm->state = (struct internal_state *)s; s->strm = strm; s->noheader = noheader; @@ -233,14 +234,14 @@ s->hash_mask = s->hash_size - 1; s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); - s->window = (Bytef *) mem->window_memory; - s->prev = (Posf *) mem->prev_memory; - s->head = (Posf *) mem->head_memory; + s->window = (Byte *) mem->window_memory; + s->prev = (Pos *) mem->prev_memory; + s->head = (Pos *) mem->head_memory; s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ - overlay = (ushf *) mem->overlay_memory; - s->pending_buf = (uchf *) overlay; + overlay = (ush *) mem->overlay_memory; + s->pending_buf = (uch *) overlay; s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); s->d_buf = overlay + s->lit_bufsize/sizeof(ush); @@ -254,17 +255,18 @@ } /* ========================================================================= */ -int zlib_deflateSetDictionary (strm, dictionary, dictLength) - z_streamp strm; - const Bytef *dictionary; - uInt dictLength; +int zlib_deflateSetDictionary( + z_streamp strm, + const Byte *dictionary, + uInt dictLength +) { deflate_state *s; uInt length = dictLength; uInt n; IPos hash_head = 0; - if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL) + if (strm == NULL || strm->state == NULL || dictionary == NULL) return Z_STREAM_ERROR; s = (deflate_state *) strm->state; @@ -279,7 +281,7 @@ dictionary += dictLength - length; /* use the tail of the dictionary */ #endif } - memcpy((charf *)s->window, dictionary, length); + memcpy((char *)s->window, dictionary, length); s->strstart = length; s->block_start = (long)length; @@ -297,16 +299,17 @@ } /* ========================================================================= */ -int zlib_deflateReset (strm) - z_streamp strm; +int zlib_deflateReset( + z_streamp strm +) { deflate_state *s; - if (strm == Z_NULL || strm->state == Z_NULL) + if (strm == NULL || strm->state == NULL) return Z_STREAM_ERROR; strm->total_in = strm->total_out = 0; - strm->msg = Z_NULL; + strm->msg = NULL; strm->data_type = Z_UNKNOWN; s = (deflate_state *)strm->state; @@ -327,16 +330,17 @@ } /* ========================================================================= */ -int zlib_deflateParams(strm, level, strategy) - z_streamp strm; - int level; - int strategy; +int zlib_deflateParams( + z_streamp strm, + int level, + int strategy +) { deflate_state *s; compress_func func; int err = Z_OK; - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (strm == NULL || strm->state == NULL) return Z_STREAM_ERROR; s = (deflate_state *) strm->state; if (level == Z_DEFAULT_COMPRESSION) { @@ -367,9 +371,10 @@ * IN assertion: the stream state is correct and there is enough room in * pending_buf. */ -local void putShortMSB (s, b) - deflate_state *s; - uInt b; +static void putShortMSB( + deflate_state *s, + uInt b +) { put_byte(s, (Byte)(b >> 8)); put_byte(s, (Byte)(b & 0xff)); @@ -381,8 +386,9 @@ * to avoid allocating a large strm->next_out buffer and copying into it. * (See also read_buf()). */ -local void flush_pending(strm) - z_streamp strm; +static void flush_pending( + z_streamp strm +) { deflate_state *s = (deflate_state *) strm->state; unsigned len = s->pending; @@ -390,7 +396,7 @@ if (len > strm->avail_out) len = strm->avail_out; if (len == 0) return; - if (strm->next_out != Z_NULL) { + if (strm->next_out != NULL) { memcpy(strm->next_out, s->pending_out, len); strm->next_out += len; } @@ -404,20 +410,21 @@ } /* ========================================================================= */ -int zlib_deflate (strm, flush) - z_streamp strm; - int flush; +int zlib_deflate( + z_streamp strm, + int flush +) { int old_flush; /* value of flush param for previous deflate call */ deflate_state *s; - if (strm == Z_NULL || strm->state == Z_NULL || + if (strm == NULL || strm->state == NULL || flush > Z_FINISH || flush < 0) { return Z_STREAM_ERROR; } s = (deflate_state *) strm->state; - if ((strm->next_in == Z_NULL && strm->avail_in != 0) || + if ((strm->next_in == NULL && strm->avail_in != 0) || (s->status == FINISH_STATE && flush != Z_FINISH)) { return Z_STREAM_ERROR; } @@ -541,13 +548,14 @@ } /* ========================================================================= */ -int zlib_deflateEnd (strm) - z_streamp strm; +int zlib_deflateEnd( + z_streamp strm +) { int status; deflate_state *s; - if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + if (strm == NULL || strm->state == NULL) return Z_STREAM_ERROR; s = (deflate_state *) strm->state; status = s->status; @@ -556,7 +564,7 @@ return Z_STREAM_ERROR; } - strm->state = Z_NULL; + strm->state = NULL; return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; } @@ -564,20 +572,21 @@ /* ========================================================================= * Copy the source state to the destination state. */ -int zlib_deflateCopy (dest, source) - z_streamp dest; - z_streamp source; +int zlib_deflateCopy ( + z_streamp dest, + z_streamp source +) { #ifdef MAXSEG_64K return Z_STREAM_ERROR; #else deflate_state *ds; deflate_state *ss; - ushf *overlay; + ush *overlay; deflate_workspace *mem; - if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + if (source == NULL || dest == NULL || source->state == NULL) { return Z_STREAM_ERROR; } @@ -589,15 +598,15 @@ ds = &(mem->deflate_memory); - dest->state = (struct internal_state FAR *) ds; + dest->state = (struct internal_state *) ds; *ds = *ss; ds->strm = dest; - ds->window = (Bytef *) mem->window_memory; - ds->prev = (Posf *) mem->prev_memory; - ds->head = (Posf *) mem->head_memory; - overlay = (ushf *) mem->overlay_memory; - ds->pending_buf = (uchf *) overlay; + ds->window = (Byte *) mem->window_memory; + ds->prev = (Pos *) mem->prev_memory; + ds->head = (Pos *) mem->head_memory; + overlay = (ush *) mem->overlay_memory; + ds->pending_buf = (uch *) overlay; memcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); memcpy(ds->prev, ss->prev, ds->w_size * sizeof(Pos)); @@ -623,10 +632,11 @@ * allocating a large strm->next_in buffer and copying from it. * (See also flush_pending()). */ -local int read_buf(strm, buf, size) - z_streamp strm; - Bytef *buf; - unsigned size; +static int read_buf( + z_streamp strm, + Byte *buf, + unsigned size +) { unsigned len = strm->avail_in; @@ -648,8 +658,9 @@ /* =========================================================================== * Initialize the "longest match" routines for a new zlib stream */ -local void lm_init (s) - deflate_state *s; +static void lm_init( + deflate_state *s +) { s->window_size = (ulg)2L*s->w_size; @@ -682,13 +693,14 @@ /* For 80x86 and 680x0, an optimized version will be provided in match.asm or * match.S. The code will be functionally equivalent. */ -local uInt longest_match(s, cur_match) - deflate_state *s; - IPos cur_match; /* current match */ +static uInt longest_match( + deflate_state *s, + IPos cur_match /* current match */ +) { unsigned chain_length = s->max_chain_length;/* max hash chain length */ - register Bytef *scan = s->window + s->strstart; /* current string */ - register Bytef *match; /* matched string */ + register Byte *scan = s->window + s->strstart; /* current string */ + register Byte *match; /* matched string */ register int len; /* length of current match */ int best_len = s->prev_length; /* best match length so far */ int nice_match = s->nice_match; /* stop if match long enough */ @@ -697,18 +709,18 @@ /* Stop when cur_match becomes <= limit. To simplify the code, * we prevent matches with the string of window index 0. */ - Posf *prev = s->prev; + Pos *prev = s->prev; uInt wmask = s->w_mask; #ifdef UNALIGNED_OK /* Compare two bytes at a time. Note: this is not always beneficial. * Try with and without -DUNALIGNED_OK to check. */ - register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; - register ush scan_start = *(ushf*)scan; - register ush scan_end = *(ushf*)(scan+best_len-1); + register Byte *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ush*)scan; + register ush scan_end = *(ush*)(scan+best_len-1); #else - register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte *strend = s->window + s->strstart + MAX_MATCH; register Byte scan_end1 = scan[best_len-1]; register Byte scan_end = scan[best_len]; #endif @@ -740,8 +752,8 @@ /* This code assumes sizeof(unsigned short) == 2. Do not use * UNALIGNED_OK if your compiler uses a different size. */ - if (*(ushf*)(match+best_len-1) != scan_end || - *(ushf*)match != scan_start) continue; + if (*(ush*)(match+best_len-1) != scan_end || + *(ush*)match != scan_start) continue; /* It is not necessary to compare scan[2] and match[2] since they are * always equal when the other bytes match, given that the hash keys @@ -755,10 +767,10 @@ Assert(scan[2] == match[2], "scan[2]?"); scan++, match++; do { - } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + } while (*(ush*)(scan+=2) == *(ush*)(match+=2) && + *(ush*)(scan+=2) == *(ush*)(match+=2) && + *(ush*)(scan+=2) == *(ush*)(match+=2) && + *(ush*)(scan+=2) == *(ush*)(match+=2) && scan < strend); /* The funny "do {}" generates better code on most compilers */ @@ -807,7 +819,7 @@ best_len = len; if (len >= nice_match) break; #ifdef UNALIGNED_OK - scan_end = *(ushf*)(scan+best_len-1); + scan_end = *(ush*)(scan+best_len-1); #else scan_end1 = scan[best_len-1]; scan_end = scan[best_len]; @@ -824,14 +836,16 @@ /* =========================================================================== * Check that the match at match_start is indeed a match. */ -local void check_match(s, start, match, length) - deflate_state *s; - IPos start, match; - int length; +static void check_match( + deflate_state *s, + IPos start, + IPos match, + int length +) { /* check that the match is indeed a match */ - if (memcmp((charf *)s->window + match, - (charf *)s->window + start, length) != EQUAL) { + if (memcmp((char *)s->window + match, + (char *)s->window + start, length) != EQUAL) { fprintf(stderr, " start %u, match %u, length %d\n", start, match, length); do { @@ -858,11 +872,12 @@ * performed for at least two bytes (required for the zip translate_eol * option -- not supported here). */ -local void fill_window(s) - deflate_state *s; +static void fill_window( + deflate_state *s +) { register unsigned n, m; - register Posf *p; + register Pos *p; unsigned more; /* Amount of free space at the end of the window. */ uInt wsize = s->w_size; @@ -884,7 +899,7 @@ */ } else if (s->strstart >= wsize+MAX_DIST(s)) { - memcpy((charf *)s->window, (charf *)s->window+wsize, + memcpy((char *)s->window, (char *)s->window+wsize, (unsigned)wsize); s->match_start -= wsize; s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ @@ -953,8 +968,8 @@ */ #define FLUSH_BLOCK_ONLY(s, eof) { \ zlib_tr_flush_block(s, (s->block_start >= 0L ? \ - (charf *)&s->window[(unsigned)s->block_start] : \ - (charf *)Z_NULL), \ + (char *)&s->window[(unsigned)s->block_start] : \ + NULL), \ (ulg)((long)s->strstart - s->block_start), \ (eof)); \ s->block_start = s->strstart; \ @@ -977,9 +992,10 @@ * NOTE: this function should be optimized to avoid extra copying from * window to pending_buf. */ -local block_state deflate_stored(s, flush) - deflate_state *s; - int flush; +static block_state deflate_stored( + deflate_state *s, + int flush +) { /* Stored blocks are limited to 0xffff bytes, pending_buf is limited * to pending_buf_size, and each stored block has a 5 byte header: @@ -1035,9 +1051,10 @@ * new strings in the dictionary only for unmatched strings or for short * matches. It is used only for the fast compression options. */ -local block_state deflate_fast(s, flush) - deflate_state *s; - int flush; +static block_state deflate_fast( + deflate_state *s, + int flush +) { IPos hash_head = NIL; /* head of the hash chain */ int bflush; /* set if current block must be flushed */ @@ -1128,9 +1145,10 @@ * evaluation for matches: a match is finally adopted only if there is * no better match at the next window position. */ -local block_state deflate_slow(s, flush) - deflate_state *s; - int flush; +static block_state deflate_slow( + deflate_state *s, + int flush +) { IPos hash_head = NIL; /* head of hash chain */ int bflush; /* set if current block must be flushed */ @@ -1244,7 +1262,7 @@ return flush == Z_FINISH ? finish_done : block_done; } -ZEXTERN int ZEXPORT zlib_deflate_workspacesize () +extern int zlib_deflate_workspacesize(void) { return sizeof(deflate_workspace); } diff -Nru a/lib/zlib_deflate/deftree.c b/lib/zlib_deflate/deftree.c --- a/lib/zlib_deflate/deftree.c Mon Jun 9 23:16:08 2003 +++ b/lib/zlib_deflate/deftree.c Mon Jun 9 23:16:08 2003 @@ -60,16 +60,16 @@ #define REPZ_11_138 18 /* repeat a zero length 11-138 times (7 bits of repeat count) */ -local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ +static const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; -local const int extra_dbits[D_CODES] /* extra bits for each distance code */ +static const int extra_dbits[D_CODES] /* extra bits for each distance code */ = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; -local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ +static const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; -local const uch bl_order[BL_CODES] +static const uch bl_order[BL_CODES] = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; /* The lengths of the bit length codes are sent in order of decreasing * probability, to avoid transmitting the lengths for unused bit length codes. @@ -84,73 +84,73 @@ * Local data. These are initialized only once. */ -local ct_data static_ltree[L_CODES+2]; +static ct_data static_ltree[L_CODES+2]; /* The static literal tree. Since the bit lengths are imposed, there is no * need for the L_CODES extra codes used during heap construction. However * The codes 286 and 287 are needed to build a canonical tree (see zlib_tr_init * below). */ -local ct_data static_dtree[D_CODES]; +static ct_data static_dtree[D_CODES]; /* The static distance tree. (Actually a trivial tree since all codes use * 5 bits.) */ -local uch dist_code[512]; +static uch dist_code[512]; /* distance codes. The first 256 values correspond to the distances * 3 .. 258, the last 256 values correspond to the top 8 bits of * the 15 bit distances. */ -local uch length_code[MAX_MATCH-MIN_MATCH+1]; +static uch length_code[MAX_MATCH-MIN_MATCH+1]; /* length code for each normalized match length (0 == MIN_MATCH) */ -local int base_length[LENGTH_CODES]; +static int base_length[LENGTH_CODES]; /* First normalized length for each code (0 = MIN_MATCH) */ -local int base_dist[D_CODES]; +static int base_dist[D_CODES]; /* First normalized distance for each code (0 = distance of 1) */ struct static_tree_desc_s { const ct_data *static_tree; /* static tree or NULL */ - const intf *extra_bits; /* extra bits for each code or NULL */ + const int *extra_bits; /* extra bits for each code or NULL */ int extra_base; /* base index for extra_bits */ int elems; /* max number of elements in the tree */ int max_length; /* max bit length for the codes */ }; -local static_tree_desc static_l_desc = +static static_tree_desc static_l_desc = {static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; -local static_tree_desc static_d_desc = +static static_tree_desc static_d_desc = {static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; -local static_tree_desc static_bl_desc = +static static_tree_desc static_bl_desc = {(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; /* =========================================================================== * Local (static) routines in this file. */ -local void tr_static_init OF((void)); -local void init_block OF((deflate_state *s)); -local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); -local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); -local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); -local void build_tree OF((deflate_state *s, tree_desc *desc)); -local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); -local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); -local int build_bl_tree OF((deflate_state *s)); -local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, - int blcodes)); -local void compress_block OF((deflate_state *s, ct_data *ltree, - ct_data *dtree)); -local void set_data_type OF((deflate_state *s)); -local unsigned bi_reverse OF((unsigned value, int length)); -local void bi_windup OF((deflate_state *s)); -local void bi_flush OF((deflate_state *s)); -local void copy_block OF((deflate_state *s, charf *buf, unsigned len, - int header)); +static void tr_static_init (void); +static void init_block (deflate_state *s); +static void pqdownheap (deflate_state *s, ct_data *tree, int k); +static void gen_bitlen (deflate_state *s, tree_desc *desc); +static void gen_codes (ct_data *tree, int max_code, ush *bl_count); +static void build_tree (deflate_state *s, tree_desc *desc); +static void scan_tree (deflate_state *s, ct_data *tree, int max_code); +static void send_tree (deflate_state *s, ct_data *tree, int max_code); +static int build_bl_tree (deflate_state *s); +static void send_all_trees (deflate_state *s, int lcodes, int dcodes, + int blcodes); +static void compress_block (deflate_state *s, ct_data *ltree, + ct_data *dtree); +static void set_data_type (deflate_state *s); +static unsigned bi_reverse (unsigned value, int length); +static void bi_windup (deflate_state *s); +static void bi_flush (deflate_state *s); +static void copy_block (deflate_state *s, char *buf, unsigned len, + int header); #ifndef DEBUG_ZLIB # define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) @@ -174,12 +174,13 @@ * IN assertion: length <= 16 and value fits in length bits. */ #ifdef DEBUG_ZLIB -local void send_bits OF((deflate_state *s, int value, int length)); +static void send_bits (deflate_state *s, int value, int length); -local void send_bits(s, value, length) - deflate_state *s; - int value; /* value to send */ - int length; /* number of bits */ +static void send_bits( + deflate_state *s, + int value, /* value to send */ + int length /* number of bits */ +) { Tracevv((stderr," l %2d v %4x ", length, value)); Assert(length > 0 && length <= 15, "invalid length"); @@ -225,7 +226,7 @@ * this function may be called by two threads concurrently, but this is * harmless since both invocations do exactly the same thing. */ -local void tr_static_init() +static void tr_static_init(void) { static int static_init_done = 0; int n; /* iterates over tree elements */ @@ -295,8 +296,9 @@ /* =========================================================================== * Initialize the tree data structures for a new zlib stream. */ -void zlib_tr_init(s) - deflate_state *s; +void zlib_tr_init( + deflate_state *s +) { tr_static_init(); @@ -325,8 +327,9 @@ /* =========================================================================== * Initialize a new block. */ -local void init_block(s) - deflate_state *s; +static void init_block( + deflate_state *s +) { int n; /* iterates over tree elements */ @@ -369,10 +372,11 @@ * when the heap property is re-established (each father smaller than its * two sons). */ -local void pqdownheap(s, tree, k) - deflate_state *s; - ct_data *tree; /* the tree to restore */ - int k; /* node to move down */ +static void pqdownheap( + deflate_state *s, + ct_data *tree, /* the tree to restore */ + int k /* node to move down */ +) { int v = s->heap[k]; int j = k << 1; /* left son of k */ @@ -404,14 +408,15 @@ * The length opt_len is updated; static_len is also updated if stree is * not null. */ -local void gen_bitlen(s, desc) - deflate_state *s; - tree_desc *desc; /* the tree descriptor */ +static void gen_bitlen( + deflate_state *s, + tree_desc *desc /* the tree descriptor */ +) { ct_data *tree = desc->dyn_tree; int max_code = desc->max_code; const ct_data *stree = desc->stat_desc->static_tree; - const intf *extra = desc->stat_desc->extra_bits; + const int *extra = desc->stat_desc->extra_bits; int base = desc->stat_desc->extra_base; int max_length = desc->stat_desc->max_length; int h; /* heap index */ @@ -491,10 +496,11 @@ * OUT assertion: the field code is set for all tree elements of non * zero code length. */ -local void gen_codes (tree, max_code, bl_count) - ct_data *tree; /* the tree to decorate */ - int max_code; /* largest code with non zero frequency */ - ushf *bl_count; /* number of codes at each bit length */ +static void gen_codes( + ct_data *tree, /* the tree to decorate */ + int max_code, /* largest code with non zero frequency */ + ush *bl_count /* number of codes at each bit length */ +) { ush next_code[MAX_BITS+1]; /* next code value for each bit length */ ush code = 0; /* running code value */ @@ -533,9 +539,10 @@ * and corresponding code. The length opt_len is updated; static_len is * also updated if stree is not null. The field max_code is set. */ -local void build_tree(s, desc) - deflate_state *s; - tree_desc *desc; /* the tree descriptor */ +static void build_tree( + deflate_state *s, + tree_desc *desc /* the tree descriptor */ +) { ct_data *tree = desc->dyn_tree; const ct_data *stree = desc->stat_desc->static_tree; @@ -620,10 +627,11 @@ * Scan a literal or distance tree to determine the frequencies of the codes * in the bit length tree. */ -local void scan_tree (s, tree, max_code) - deflate_state *s; - ct_data *tree; /* the tree to be scanned */ - int max_code; /* and its largest code of non zero frequency */ +static void scan_tree( + deflate_state *s, + ct_data *tree, /* the tree to be scanned */ + int max_code /* and its largest code of non zero frequency */ +) { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ @@ -665,10 +673,11 @@ * Send a literal or distance tree in compressed form, using the codes in * bl_tree. */ -local void send_tree (s, tree, max_code) - deflate_state *s; - ct_data *tree; /* the tree to be scanned */ - int max_code; /* and its largest code of non zero frequency */ +static void send_tree( + deflate_state *s, + ct_data *tree, /* the tree to be scanned */ + int max_code /* and its largest code of non zero frequency */ +) { int n; /* iterates over all tree elements */ int prevlen = -1; /* last emitted length */ @@ -716,8 +725,9 @@ * Construct the Huffman tree for the bit lengths and return the index in * bl_order of the last bit length code to send. */ -local int build_bl_tree(s) - deflate_state *s; +static int build_bl_tree( + deflate_state *s +) { int max_blindex; /* index of last bit length code of non zero freq */ @@ -751,9 +761,12 @@ * lengths of the bit length codes, the literal tree and the distance tree. * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. */ -local void send_all_trees(s, lcodes, dcodes, blcodes) - deflate_state *s; - int lcodes, dcodes, blcodes; /* number of codes for each tree */ +static void send_all_trees( + deflate_state *s, + int lcodes, /* number of codes for each tree */ + int dcodes, /* number of codes for each tree */ + int blcodes /* number of codes for each tree */ +) { int rank; /* index in bl_order */ @@ -780,11 +793,12 @@ /* =========================================================================== * Send a stored block */ -void zlib_tr_stored_block(s, buf, stored_len, eof) - deflate_state *s; - charf *buf; /* input block */ - ulg stored_len; /* length of input block */ - int eof; /* true if this is the last block for a file */ +void zlib_tr_stored_block( + deflate_state *s, + char *buf, /* input block */ + ulg stored_len, /* length of input block */ + int eof /* true if this is the last block for a file */ +) { send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; @@ -795,8 +809,9 @@ /* Send just the `stored block' type code without any length bytes or data. */ -void zlib_tr_stored_type_only(s) - deflate_state *s; +void zlib_tr_stored_type_only( + deflate_state *s +) { send_bits(s, (STORED_BLOCK << 1), 3); bi_windup(s); @@ -815,8 +830,9 @@ * To simplify the code, we assume the worst case of last real code encoded * on one bit only. */ -void zlib_tr_align(s) - deflate_state *s; +void zlib_tr_align( + deflate_state *s +) { send_bits(s, STATIC_TREES<<1, 3); send_code(s, END_BLOCK, static_ltree); @@ -841,11 +857,12 @@ * trees or store, and output the encoded block to the zip file. This function * returns the total compressed length for the file so far. */ -ulg zlib_tr_flush_block(s, buf, stored_len, eof) - deflate_state *s; - charf *buf; /* input block, or NULL if too old */ - ulg stored_len; /* length of input block */ - int eof; /* true if this is the last block for a file */ +ulg zlib_tr_flush_block( + deflate_state *s, + char *buf, /* input block, or NULL if too old */ + ulg stored_len, /* length of input block */ + int eof /* true if this is the last block for a file */ +) { ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ int max_blindex = 0; /* index of last bit length code of non zero freq */ @@ -899,7 +916,7 @@ if (stored_len <= opt_lenb && eof && s->compressed_len==0L && seekable()) { # endif /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */ - if (buf == (charf*)0) error ("block vanished"); + if (buf == (char*)0) error ("block vanished"); copy_block(s, buf, (unsigned)stored_len, 0); /* without header */ s->compressed_len = stored_len << 3; @@ -953,10 +970,11 @@ * Save the match info and tally the frequency counts. Return true if * the current block must be flushed. */ -int zlib_tr_tally (s, dist, lc) - deflate_state *s; - unsigned dist; /* distance of matched string */ - unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +int zlib_tr_tally( + deflate_state *s, + unsigned dist, /* distance of matched string */ + unsigned lc /* match length-MIN_MATCH or unmatched char (if dist==0) */ +) { s->d_buf[s->last_lit] = (ush)dist; s->l_buf[s->last_lit++] = (uch)lc; @@ -1001,10 +1019,11 @@ /* =========================================================================== * Send the block data compressed using the given Huffman trees */ -local void compress_block(s, ltree, dtree) - deflate_state *s; - ct_data *ltree; /* literal tree */ - ct_data *dtree; /* distance tree */ +static void compress_block( + deflate_state *s, + ct_data *ltree, /* literal tree */ + ct_data *dtree /* distance tree */ +) { unsigned dist; /* distance of matched string */ int lc; /* match length or unmatched char (if dist == 0) */ @@ -1054,8 +1073,9 @@ * IN assertion: the fields freq of dyn_ltree are set and the total of all * frequencies does not exceed 64K (to fit in an int on 16 bit machines). */ -local void set_data_type(s) - deflate_state *s; +static void set_data_type( + deflate_state *s +) { int n = 0; unsigned ascii_freq = 0; @@ -1070,11 +1090,12 @@ * Copy a stored block, storing first the length and its * one's complement if requested. */ -local void copy_block(s, buf, len, header) - deflate_state *s; - charf *buf; /* the input data */ - unsigned len; /* its length */ - int header; /* true if block header must be written */ +static void copy_block( + deflate_state *s, + char *buf, /* the input data */ + unsigned len, /* its length */ + int header /* true if block header must be written */ +) { bi_windup(s); /* align on byte boundary */ s->last_eob_len = 8; /* enough lookahead for inflate */ diff -Nru a/lib/zlib_deflate/defutil.h b/lib/zlib_deflate/defutil.h --- a/lib/zlib_deflate/defutil.h Mon Jun 9 23:16:08 2003 +++ b/lib/zlib_deflate/defutil.h Mon Jun 9 23:16:08 2003 @@ -46,7 +46,7 @@ ush dad; /* father node in Huffman tree */ ush len; /* length of bit string */ } dl; -} FAR ct_data; +} ct_data; #define Freq fc.freq #define Code fc.code @@ -59,10 +59,9 @@ ct_data *dyn_tree; /* the dynamic tree */ int max_code; /* largest code with non zero frequency */ static_tree_desc *stat_desc; /* the corresponding static tree */ -} FAR tree_desc; +} tree_desc; typedef ush Pos; -typedef Pos FAR Posf; typedef unsigned IPos; /* A Pos is an index in the character window. We use short instead of int to @@ -72,9 +71,9 @@ typedef struct deflate_state { z_streamp strm; /* pointer back to this zlib stream */ int status; /* as the name implies */ - Bytef *pending_buf; /* output still pending */ + Byte *pending_buf; /* output still pending */ ulg pending_buf_size; /* size of pending_buf */ - Bytef *pending_out; /* next pending byte to output to the stream */ + Byte *pending_out; /* next pending byte to output to the stream */ int pending; /* nb of bytes in the pending buffer */ int noheader; /* suppress zlib header and adler32 */ Byte data_type; /* UNKNOWN, BINARY or ASCII */ @@ -87,7 +86,7 @@ uInt w_bits; /* log2(w_size) (8..16) */ uInt w_mask; /* w_size - 1 */ - Bytef *window; + Byte *window; /* Sliding window. Input bytes are read into the second half of the window, * and move to the first half later to keep a dictionary of at least wSize * bytes. With this organization, matches are limited to a distance of @@ -102,13 +101,13 @@ * is directly used as sliding window. */ - Posf *prev; + Pos *prev; /* Link to older string with same hash index. To limit the size of this * array to 64K, this link is maintained only for the last 32K strings. * An index in this array is thus a window index modulo 32K. */ - Posf *head; /* Heads of the hash chains or NIL. */ + Pos *head; /* Heads of the hash chains or NIL. */ uInt ins_h; /* hash index of string to be inserted */ uInt hash_size; /* number of elements in hash table */ @@ -188,7 +187,7 @@ /* Depth of each subtree used as tie breaker for trees of equal frequency */ - uchf *l_buf; /* buffer for literals or lengths */ + uch *l_buf; /* buffer for literals or lengths */ uInt lit_bufsize; /* Size of match buffer for literals/lengths. There are 4 reasons for @@ -212,7 +211,7 @@ uInt last_lit; /* running index in l_buf */ - ushf *d_buf; + ush *d_buf; /* Buffer for distances. To simplify the code, d_buf and l_buf have * the same number of elements. To use different lengths, an extra flag * array would be necessary. @@ -237,7 +236,7 @@ * are always zero. */ -} FAR deflate_state; +} deflate_state; typedef struct deflate_workspace { /* State memory for the deflator */ @@ -265,14 +264,14 @@ */ /* in trees.c */ -void zlib_tr_init OF((deflate_state *s)); -int zlib_tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); -ulg zlib_tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, - int eof)); -void zlib_tr_align OF((deflate_state *s)); -void zlib_tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, - int eof)); -void zlib_tr_stored_type_only OF((deflate_state *)); +void zlib_tr_init (deflate_state *s); +int zlib_tr_tally (deflate_state *s, unsigned dist, unsigned lc); +ulg zlib_tr_flush_block (deflate_state *s, char *buf, ulg stored_len, + int eof); +void zlib_tr_align (deflate_state *s); +void zlib_tr_stored_block (deflate_state *s, char *buf, ulg stored_len, + int eof); +void zlib_tr_stored_type_only (deflate_state *); /* =========================================================================== diff -Nru a/lib/zlib_inflate/infblock.c b/lib/zlib_inflate/infblock.c --- a/lib/zlib_inflate/infblock.c Mon Jun 9 23:16:16 2003 +++ b/lib/zlib_inflate/infblock.c Mon Jun 9 23:16:16 2003 @@ -16,7 +16,7 @@ #define bits word.what.Bits /* Table for deflate from PKZIP's appnote.txt. */ -local const uInt border[] = { /* Order of the bit length code lengths */ +static const uInt border[] = { /* Order of the bit length code lengths */ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; /* @@ -65,12 +65,13 @@ */ -void zlib_inflate_blocks_reset(s, z, c) -inflate_blocks_statef *s; -z_streamp z; -uLongf *c; +void zlib_inflate_blocks_reset( + inflate_blocks_statef *s, + z_streamp z, + uLong *c +) { - if (c != Z_NULL) + if (c != NULL) *c = s->check; if (s->mode == CODES) zlib_inflate_codes_free(s->sub.decode.codes, z); @@ -78,14 +79,15 @@ s->bitk = 0; s->bitb = 0; s->read = s->write = s->window; - if (s->checkfn != Z_NULL) - z->adler = s->check = (*s->checkfn)(0L, (const Bytef *)Z_NULL, 0); + if (s->checkfn != NULL) + z->adler = s->check = (*s->checkfn)(0L, NULL, 0); } -inflate_blocks_statef *zlib_inflate_blocks_new(z, c, w) -z_streamp z; -check_func c; -uInt w; +inflate_blocks_statef *zlib_inflate_blocks_new( + z_streamp z, + check_func c, + uInt w +) { inflate_blocks_statef *s; @@ -95,22 +97,23 @@ s->end = s->window + w; s->checkfn = c; s->mode = TYPE; - zlib_inflate_blocks_reset(s, z, Z_NULL); + zlib_inflate_blocks_reset(s, z, NULL); return s; } -int zlib_inflate_blocks(s, z, r) -inflate_blocks_statef *s; -z_streamp z; -int r; +int zlib_inflate_blocks( + inflate_blocks_statef *s, + z_streamp z, + int r +) { uInt t; /* temporary storage */ uLong b; /* bit buffer */ uInt k; /* bits in bit buffer */ - Bytef *p; /* input data pointer */ + Byte *p; /* input data pointer */ uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ + Byte *q; /* output window write pointer */ uInt m; /* bytes to end of window or read pointer */ /* copy input/output information to locals (UPDATE macro restores) */ @@ -138,7 +141,7 @@ zlib_inflate_trees_fixed(&bl, &bd, &tl, &td, z); s->sub.decode.codes = zlib_inflate_codes_new(bl, bd, tl, td, z); - if (s->sub.decode.codes == Z_NULL) + if (s->sub.decode.codes == NULL) { r = Z_MEM_ERROR; LEAVE @@ -267,7 +270,7 @@ s->sub.trees.index = i; } } - s->sub.trees.tb = Z_NULL; + s->sub.trees.tb = NULL; { uInt bl, bd; inflate_huft *tl, *td; @@ -286,7 +289,7 @@ r = t; LEAVE } - if ((c = zlib_inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) + if ((c = zlib_inflate_codes_new(bl, bd, tl, td, z)) == NULL) { r = Z_MEM_ERROR; LEAVE @@ -325,19 +328,21 @@ } -int zlib_inflate_blocks_free(s, z) -inflate_blocks_statef *s; -z_streamp z; +int zlib_inflate_blocks_free( + inflate_blocks_statef *s, + z_streamp z +) { - zlib_inflate_blocks_reset(s, z, Z_NULL); + zlib_inflate_blocks_reset(s, z, NULL); return Z_OK; } -void zlib_inflate_set_dictionary(s, d, n) -inflate_blocks_statef *s; -const Bytef *d; -uInt n; +void zlib_inflate_set_dictionary( + inflate_blocks_statef *s, + const Byte *d, + uInt n +) { memcpy(s->window, d, n); s->read = s->write = s->window + n; @@ -346,10 +351,11 @@ /* Returns true if inflate is currently at the end of a block generated * by Z_SYNC_FLUSH or Z_FULL_FLUSH. - * IN assertion: s != Z_NULL + * IN assertion: s != NULL */ -int zlib_inflate_blocks_sync_point(s) -inflate_blocks_statef *s; +int zlib_inflate_blocks_sync_point( + inflate_blocks_statef *s +) { return s->mode == LENS; } diff -Nru a/lib/zlib_inflate/infblock.h b/lib/zlib_inflate/infblock.h --- a/lib/zlib_inflate/infblock.h Mon Jun 9 23:16:14 2003 +++ b/lib/zlib_inflate/infblock.h Mon Jun 9 23:16:14 2003 @@ -12,33 +12,33 @@ #define _INFBLOCK_H struct inflate_blocks_state; -typedef struct inflate_blocks_state FAR inflate_blocks_statef; +typedef struct inflate_blocks_state inflate_blocks_statef; -extern inflate_blocks_statef * zlib_inflate_blocks_new OF(( +extern inflate_blocks_statef * zlib_inflate_blocks_new ( z_streamp z, - check_func c, /* check function */ - uInt w)); /* window size */ + check_func c, /* check function */ + uInt w); /* window size */ -extern int zlib_inflate_blocks OF(( +extern int zlib_inflate_blocks ( inflate_blocks_statef *, z_streamp , - int)); /* initial return code */ + int); /* initial return code */ -extern void zlib_inflate_blocks_reset OF(( +extern void zlib_inflate_blocks_reset ( inflate_blocks_statef *, z_streamp , - uLongf *)); /* check value on output */ + uLong *); /* check value on output */ -extern int zlib_inflate_blocks_free OF(( +extern int zlib_inflate_blocks_free ( inflate_blocks_statef *, - z_streamp)); + z_streamp); -extern void zlib_inflate_set_dictionary OF(( +extern void zlib_inflate_set_dictionary ( inflate_blocks_statef *s, - const Bytef *d, /* dictionary */ - uInt n)); /* dictionary length */ + const Byte *d, /* dictionary */ + uInt n); /* dictionary length */ -extern int zlib_inflate_blocks_sync_point OF(( - inflate_blocks_statef *s)); +extern int zlib_inflate_blocks_sync_point ( + inflate_blocks_statef *s); #endif /* _INFBLOCK_H */ diff -Nru a/lib/zlib_inflate/infcodes.c b/lib/zlib_inflate/infcodes.c --- a/lib/zlib_inflate/infcodes.c Mon Jun 9 23:16:10 2003 +++ b/lib/zlib_inflate/infcodes.c Mon Jun 9 23:16:10 2003 @@ -14,11 +14,13 @@ #define exop word.what.Exop #define bits word.what.Bits -inflate_codes_statef *zlib_inflate_codes_new(bl, bd, tl, td, z) -uInt bl, bd; -inflate_huft *tl; -inflate_huft *td; /* need separate declaration for Borland C++ */ -z_streamp z; +inflate_codes_statef *zlib_inflate_codes_new( + uInt bl, + uInt bd, + inflate_huft *tl, + inflate_huft *td, /* need separate declaration for Borland C++ */ + z_streamp z +) { inflate_codes_statef *c; @@ -34,21 +36,22 @@ } -int zlib_inflate_codes(s, z, r) -inflate_blocks_statef *s; -z_streamp z; -int r; +int zlib_inflate_codes( + inflate_blocks_statef *s, + z_streamp z, + int r +) { uInt j; /* temporary storage */ inflate_huft *t; /* temporary pointer */ uInt e; /* extra bits or operation */ uLong b; /* bit buffer */ uInt k; /* bits in bit buffer */ - Bytef *p; /* input data pointer */ + Byte *p; /* input data pointer */ uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ + Byte *q; /* output window write pointer */ uInt m; /* bytes to end of window or read pointer */ - Bytef *f; /* pointer to copy strings from */ + Byte *f; /* pointer to copy strings from */ inflate_codes_statef *c = s->sub.decode.codes; /* codes state */ /* copy input/output information to locals (UPDATE macro restores) */ @@ -146,15 +149,9 @@ DUMPBITS(j) c->mode = COPY; case COPY: /* o: copying bytes in window, waiting for space */ -#ifndef __TURBOC__ /* Turbo C bug for following expression */ - f = (uInt)(q - s->window) < c->sub.copy.dist ? - s->end - (c->sub.copy.dist - (q - s->window)) : - q - c->sub.copy.dist; -#else f = q - c->sub.copy.dist; - if ((uInt)(q - s->window) < c->sub.copy.dist) - f = s->end - (c->sub.copy.dist - (uInt)(q - s->window)); -#endif + while (f < s->window) /* modulo window size-"while" instead */ + f += s->end - s->window; /* of "if" handles invalid distances */ while (c->len) { NEEDOUT @@ -197,8 +194,9 @@ } -void zlib_inflate_codes_free(c, z) -inflate_codes_statef *c; -z_streamp z; +void zlib_inflate_codes_free( + inflate_codes_statef *c, + z_streamp z +) { } diff -Nru a/lib/zlib_inflate/infcodes.h b/lib/zlib_inflate/infcodes.h --- a/lib/zlib_inflate/infcodes.h Mon Jun 9 23:16:09 2003 +++ b/lib/zlib_inflate/infcodes.h Mon Jun 9 23:16:09 2003 @@ -14,20 +14,20 @@ #include "infblock.h" struct inflate_codes_state; -typedef struct inflate_codes_state FAR inflate_codes_statef; +typedef struct inflate_codes_state inflate_codes_statef; -extern inflate_codes_statef *zlib_inflate_codes_new OF(( +extern inflate_codes_statef *zlib_inflate_codes_new ( uInt, uInt, inflate_huft *, inflate_huft *, - z_streamp )); + z_streamp ); -extern int zlib_inflate_codes OF(( +extern int zlib_inflate_codes ( inflate_blocks_statef *, z_streamp , - int)); + int); -extern void zlib_inflate_codes_free OF(( +extern void zlib_inflate_codes_free ( inflate_codes_statef *, - z_streamp )); + z_streamp ); #endif /* _INFCODES_H */ diff -Nru a/lib/zlib_inflate/inffast.c b/lib/zlib_inflate/inffast.c --- a/lib/zlib_inflate/inffast.c Mon Jun 9 23:16:19 2003 +++ b/lib/zlib_inflate/inffast.c Mon Jun 9 23:16:19 2003 @@ -25,26 +25,28 @@ at least ten. The ten bytes are six bytes for the longest length/ distance pair plus four bytes for overloading the bit buffer. */ -int zlib_inflate_fast(bl, bd, tl, td, s, z) -uInt bl, bd; -inflate_huft *tl; -inflate_huft *td; /* need separate declaration for Borland C++ */ -inflate_blocks_statef *s; -z_streamp z; +int zlib_inflate_fast( + uInt bl, + uInt bd, + inflate_huft *tl, + inflate_huft *td, /* need separate declaration for Borland C++ */ + inflate_blocks_statef *s, + z_streamp z +) { inflate_huft *t; /* temporary pointer */ uInt e; /* extra bits or operation */ uLong b; /* bit buffer */ uInt k; /* bits in bit buffer */ - Bytef *p; /* input data pointer */ + Byte *p; /* input data pointer */ uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ + Byte *q; /* output window write pointer */ uInt m; /* bytes to end of window or read pointer */ uInt ml; /* mask for literal/length tree */ uInt md; /* mask for distance tree */ uInt c; /* bytes to copy */ uInt d; /* distance back to copy from */ - Bytef *r; /* copy source pointer */ + Byte *r; /* copy source pointer */ /* load input, output, bit values */ LOAD @@ -88,28 +90,41 @@ /* do the copy */ m -= c; - if ((uInt)(q - s->window) >= d) /* offset before dest */ - { /* just copy */ - r = q - d; - *q++ = *r++; c--; /* minimum count is three, */ - *q++ = *r++; c--; /* so unroll loop a little */ - } - else /* else offset after destination */ + r = q - d; + if (r < s->window) /* wrap if needed */ { - e = d - (uInt)(q - s->window); /* bytes from offset to end */ - r = s->end - e; /* pointer to offset */ - if (c > e) /* if source crosses, */ + do { + r += s->end - s->window; /* force pointer in window */ + } while (r < s->window); /* covers invalid distances */ + e = s->end - r; + if (c > e) { - c -= e; /* copy to end of window */ + c -= e; /* wrapped copy */ do { - *q++ = *r++; + *q++ = *r++; } while (--e); - r = s->window; /* copy rest from start of window */ + r = s->window; + do { + *q++ = *r++; + } while (--c); } + else /* normal copy */ + { + *q++ = *r++; c--; + *q++ = *r++; c--; + do { + *q++ = *r++; + } while (--c); + } + } + else /* normal copy */ + { + *q++ = *r++; c--; + *q++ = *r++; c--; + do { + *q++ = *r++; + } while (--c); } - do { /* copy all or what's left */ - *q++ = *r++; - } while (--c); break; } else if ((e & 64) == 0) diff -Nru a/lib/zlib_inflate/inffast.h b/lib/zlib_inflate/inffast.h --- a/lib/zlib_inflate/inffast.h Mon Jun 9 23:16:07 2003 +++ b/lib/zlib_inflate/inffast.h Mon Jun 9 23:16:07 2003 @@ -8,10 +8,10 @@ subject to change. Applications should only use zlib.h. */ -extern int zlib_inflate_fast OF(( +extern int zlib_inflate_fast ( uInt, uInt, inflate_huft *, inflate_huft *, inflate_blocks_statef *, - z_streamp )); + z_streamp ); diff -Nru a/lib/zlib_inflate/inffixed.h b/lib/zlib_inflate/inffixed.h --- a/lib/zlib_inflate/inffixed.h Mon Jun 9 23:16:08 2003 +++ b/lib/zlib_inflate/inffixed.h Mon Jun 9 23:16:08 2003 @@ -7,9 +7,9 @@ subject to change. Applications should only use zlib.h. */ -local uInt fixed_bl = 9; -local uInt fixed_bd = 5; -local inflate_huft fixed_tl[] = { +static uInt fixed_bl = 9; +static uInt fixed_bd = 5; +static inflate_huft fixed_tl[] = { {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192}, {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160}, @@ -139,7 +139,7 @@ {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191}, {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255} }; -local inflate_huft fixed_td[] = { +static inflate_huft fixed_td[] = { {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097}, {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385}, {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193}, diff -Nru a/lib/zlib_inflate/inflate.c b/lib/zlib_inflate/inflate.c --- a/lib/zlib_inflate/inflate.c Mon Jun 9 23:16:13 2003 +++ b/lib/zlib_inflate/inflate.c Mon Jun 9 23:16:13 2003 @@ -8,53 +8,56 @@ #include "infblock.h" #include "infutil.h" -int ZEXPORT zlib_inflate_workspacesize(void) +int zlib_inflate_workspacesize(void) { return sizeof(struct inflate_workspace); } -int ZEXPORT zlib_inflateReset(z) -z_streamp z; +int zlib_inflateReset( + z_streamp z +) { - if (z == Z_NULL || z->state == Z_NULL || z->workspace == Z_NULL) + if (z == NULL || z->state == NULL || z->workspace == NULL) return Z_STREAM_ERROR; z->total_in = z->total_out = 0; - z->msg = Z_NULL; + z->msg = NULL; z->state->mode = z->state->nowrap ? BLOCKS : METHOD; - zlib_inflate_blocks_reset(z->state->blocks, z, Z_NULL); + zlib_inflate_blocks_reset(z->state->blocks, z, NULL); return Z_OK; } -int ZEXPORT zlib_inflateEnd(z) -z_streamp z; +int zlib_inflateEnd( + z_streamp z +) { - if (z == Z_NULL || z->state == Z_NULL || z->workspace == Z_NULL) + if (z == NULL || z->state == NULL || z->workspace == NULL) return Z_STREAM_ERROR; - if (z->state->blocks != Z_NULL) + if (z->state->blocks != NULL) zlib_inflate_blocks_free(z->state->blocks, z); - z->state = Z_NULL; + z->state = NULL; return Z_OK; } -int ZEXPORT zlib_inflateInit2_(z, w, version, stream_size) -z_streamp z; -int w; -const char *version; -int stream_size; +int zlib_inflateInit2_( + z_streamp z, + int w, + const char *version, + int stream_size +) { - if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || - stream_size != sizeof(z_stream) || z->workspace == Z_NULL) + if (version == NULL || version[0] != ZLIB_VERSION[0] || + stream_size != sizeof(z_stream) || z->workspace == NULL) return Z_VERSION_ERROR; /* initialize state */ - if (z == Z_NULL) + if (z == NULL) return Z_STREAM_ERROR; - z->msg = Z_NULL; + z->msg = NULL; z->state = &WS(z)->internal_state; - z->state->blocks = Z_NULL; + z->state->blocks = NULL; /* handle undocumented nowrap option (no zlib header or check) */ z->state->nowrap = 0; @@ -74,8 +77,8 @@ /* create inflate_blocks state */ if ((z->state->blocks = - zlib_inflate_blocks_new(z, z->state->nowrap ? Z_NULL : zlib_adler32, (uInt)1 << w)) - == Z_NULL) + zlib_inflate_blocks_new(z, z->state->nowrap ? NULL : zlib_adler32, (uInt)1 << w)) + == NULL) { zlib_inflateEnd(z); return Z_MEM_ERROR; @@ -100,10 +103,11 @@ } -int ZEXPORT zlib_inflateInit_(z, version, stream_size) -z_streamp z; -const char *version; -int stream_size; +int zlib_inflateInit_( + z_streamp z, + const char *version, + int stream_size +) { return zlib_inflateInit2_(z, DEF_WBITS, version, stream_size); } @@ -113,14 +117,15 @@ #define NEEDBYTE {if(z->avail_in==0)goto empty;r=trv;} #define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) -int ZEXPORT zlib_inflate(z, f) -z_streamp z; -int f; +int zlib_inflate( + z_streamp z, + int f +) { int r, trv; uInt b; - if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL) + if (z == NULL || z->state == NULL || z->next_in == NULL) return Z_STREAM_ERROR; trv = f == Z_FINISH ? Z_BUF_ERROR : Z_OK; r = Z_BUF_ERROR; @@ -245,16 +250,17 @@ } -int ZEXPORT zlib_inflateSync(z) -z_streamp z; +int zlib_inflateSync( + z_streamp z +) { uInt n; /* number of bytes to look at */ - Bytef *p; /* pointer to bytes */ + Byte *p; /* pointer to bytes */ uInt m; /* number of marker bytes found in a row */ uLong r, w; /* temporaries to save total_in and total_out */ /* set up */ - if (z == Z_NULL || z->state == Z_NULL) + if (z == NULL || z->state == NULL) return Z_STREAM_ERROR; if (z->state->mode != I_BAD) { @@ -303,10 +309,11 @@ * decompressing, PPP checks that at the end of input packet, inflate is * waiting for these length bytes. */ -int ZEXPORT zlib_inflateSyncPoint(z) -z_streamp z; +int zlib_inflateSyncPoint( + z_streamp z +) { - if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL) + if (z == NULL || z->state == NULL || z->state->blocks == NULL) return Z_STREAM_ERROR; return zlib_inflate_blocks_sync_point(z->state->blocks); } @@ -325,9 +332,9 @@ uLong b; /* bit buffer */ /* NOT USED HERE */ uInt k; /* bits in bit buffer */ /* NOT USED HERE */ uInt t; /* temporary storage */ - Bytef *p; /* input data pointer */ + Byte *p; /* input data pointer */ uInt n; /* bytes available there */ - Bytef *q; /* output window write pointer */ + Byte *q; /* output window write pointer */ uInt m; /* bytes to end of window or read pointer */ if (s->read != s->write) @@ -345,7 +352,7 @@ /* is there room until end of buffer? */ if (t > m) t = m; /* update check information */ - if (s->checkfn != Z_NULL) + if (s->checkfn != NULL) s->check = (*s->checkfn)(s->check, q, t); memcpy(q, p, t); q += t; @@ -373,8 +380,10 @@ * will have been updated if need be. */ -int ZEXPORT zlib_inflateIncomp(z) -z_stream *z; +int zlib_inflateIncomp( + z_stream *z + +) { if (z->state->mode != BLOCKS) return Z_DATA_ERROR; diff -Nru a/lib/zlib_inflate/inftrees.c b/lib/zlib_inflate/inftrees.c --- a/lib/zlib_inflate/inftrees.c Mon Jun 9 23:16:18 2003 +++ b/lib/zlib_inflate/inftrees.c Mon Jun 9 23:16:18 2003 @@ -22,31 +22,31 @@ #define bits word.what.Bits -local int huft_build OF(( - uIntf *, /* code lengths in bits */ +static int huft_build ( + uInt *, /* code lengths in bits */ uInt, /* number of codes */ uInt, /* number of "simple" codes */ - const uIntf *, /* list of base values for non-simple codes */ - const uIntf *, /* list of extra bits for non-simple codes */ - inflate_huft * FAR*,/* result: starting table */ - uIntf *, /* maximum lookup bits (returns actual) */ + const uInt *, /* list of base values for non-simple codes */ + const uInt *, /* list of extra bits for non-simple codes */ + inflate_huft **, /* result: starting table */ + uInt *, /* maximum lookup bits (returns actual) */ inflate_huft *, /* space for trees */ uInt *, /* hufts used in space */ - uIntf * )); /* space for values */ + uInt * ); /* space for values */ /* Tables for deflate from PKZIP's appnote.txt. */ -local const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */ +static const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; /* see note #13 above about 258 */ -local const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */ +static const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */ -local const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */ +static const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577}; -local const uInt cpdext[30] = { /* Extra bits for distance codes */ +static const uInt cpdext[30] = { /* Extra bits for distance codes */ 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13}; @@ -87,17 +87,18 @@ /* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ #define BMAX 15 /* maximum bit length of any code */ -local int huft_build(b, n, s, d, e, t, m, hp, hn, v) -uIntf *b; /* code lengths in bits (all assumed <= BMAX) */ -uInt n; /* number of codes (assumed <= 288) */ -uInt s; /* number of simple-valued codes (0..s-1) */ -const uIntf *d; /* list of base values for non-simple codes */ -const uIntf *e; /* list of extra bits for non-simple codes */ -inflate_huft * FAR *t; /* result: starting table */ -uIntf *m; /* maximum lookup bits, returns actual */ -inflate_huft *hp; /* space for trees */ -uInt *hn; /* hufts used in space */ -uIntf *v; /* working area: values in order of bit length */ +static int huft_build( + uInt *b, /* code lengths in bits (all assumed <= BMAX) */ + uInt n, /* number of codes (assumed <= 288) */ + uInt s, /* number of simple-valued codes (0..s-1) */ + const uInt *d, /* list of base values for non-simple codes */ + const uInt *e, /* list of extra bits for non-simple codes */ + inflate_huft **t, /* result: starting table */ + uInt *m, /* maximum lookup bits, returns actual */ + inflate_huft *hp, /* space for trees */ + uInt *hn, /* hufts used in space */ + uInt *v /* working area: values in order of bit length */ +) /* Given a list of code lengths and a maximum table size, make a set of tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR if the given code set is incomplete (the tables are still built in this @@ -115,13 +116,13 @@ register int k; /* number of bits in current code */ int l; /* bits per table (returned in m) */ uInt mask; /* (1 << w) - 1, to avoid cc -O bug on HP */ - register uIntf *p; /* pointer into c[], b[], or v[] */ + register uInt *p; /* pointer into c[], b[], or v[] */ inflate_huft *q; /* points to current table */ struct inflate_huft_s r; /* table entry for structure assignment */ inflate_huft *u[BMAX]; /* table stack */ register int w; /* bits before this table == (l * h) */ uInt x[BMAX+1]; /* bit offsets, then code stack */ - uIntf *xp; /* pointer into x */ + uInt *xp; /* pointer into x */ int y; /* number of dummy codes added */ uInt z; /* number of entries in current table */ @@ -138,7 +139,7 @@ } while (--i); if (c[0] == n) /* null input--all zero length codes */ { - *t = (inflate_huft *)Z_NULL; + *t = NULL; *m = 0; return Z_OK; } @@ -192,8 +193,8 @@ p = v; /* grab values in bit order */ h = -1; /* no tables yet--level -1 */ w = -l; /* bits decoded == (l * h) */ - u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */ - q = (inflate_huft *)Z_NULL; /* ditto */ + u[0] = NULL; /* just to keep compilers happy */ + q = NULL; /* ditto */ z = 0; /* ditto */ /* go through the bit lengths (k already is bits in shortest code) */ @@ -228,7 +229,7 @@ /* allocate new table */ if (*hn + z > MANY) /* (note: doesn't matter for fixed) */ - return Z_MEM_ERROR; /* not enough memory */ + return Z_DATA_ERROR; /* overflow of MANY */ u[h] = q = hp + *hn; *hn += z; @@ -288,20 +289,20 @@ } -int zlib_inflate_trees_bits(c, bb, tb, hp, z) -uIntf *c; /* 19 code lengths */ -uIntf *bb; /* bits tree desired/actual depth */ -inflate_huft * FAR *tb; /* bits tree result */ -inflate_huft *hp; /* space for trees */ -z_streamp z; /* for messages */ +int zlib_inflate_trees_bits( + uInt *c, /* 19 code lengths */ + uInt *bb, /* bits tree desired/actual depth */ + inflate_huft **tb, /* bits tree result */ + inflate_huft *hp, /* space for trees */ + z_streamp z /* for messages */ +) { int r; uInt hn = 0; /* hufts used in space */ - uIntf *v; /* work area for huft_build */ + uInt *v; /* work area for huft_build */ v = WS(z)->tree_work_area_1; - r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, - tb, bb, hp, &hn, v); + r = huft_build(c, 19, 19, NULL, NULL, tb, bb, hp, &hn, v); if (r == Z_DATA_ERROR) z->msg = (char*)"oversubscribed dynamic bit lengths tree"; else if (r == Z_BUF_ERROR || *bb == 0) @@ -312,20 +313,21 @@ return r; } -int zlib_inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, hp, z) -uInt nl; /* number of literal/length codes */ -uInt nd; /* number of distance codes */ -uIntf *c; /* that many (total) code lengths */ -uIntf *bl; /* literal desired/actual bit depth */ -uIntf *bd; /* distance desired/actual bit depth */ -inflate_huft * FAR *tl; /* literal/length tree result */ -inflate_huft * FAR *td; /* distance tree result */ -inflate_huft *hp; /* space for trees */ -z_streamp z; /* for messages */ +int zlib_inflate_trees_dynamic( + uInt nl, /* number of literal/length codes */ + uInt nd, /* number of distance codes */ + uInt *c, /* that many (total) code lengths */ + uInt *bl, /* literal desired/actual bit depth */ + uInt *bd, /* distance desired/actual bit depth */ + inflate_huft **tl, /* literal/length tree result */ + inflate_huft **td, /* distance tree result */ + inflate_huft *hp, /* space for trees */ + z_streamp z /* for messages */ +) { int r; uInt hn = 0; /* hufts used in space */ - uIntf *v; /* work area for huft_build */ + uInt *v; /* work area for huft_build */ /* allocate work area */ v = WS(z)->tree_work_area_2; @@ -376,12 +378,13 @@ #include "inffixed.h" -int zlib_inflate_trees_fixed(bl, bd, tl, td, z) -uIntf *bl; /* literal desired/actual bit depth */ -uIntf *bd; /* distance desired/actual bit depth */ -inflate_huft * FAR *tl; /* literal/length tree result */ -inflate_huft * FAR *td; /* distance tree result */ -z_streamp z; /* for memory allocation */ +int zlib_inflate_trees_fixed( + uInt *bl, /* literal desired/actual bit depth */ + uInt *bd, /* distance desired/actual bit depth */ + inflate_huft **tl, /* literal/length tree result */ + inflate_huft **td, /* distance tree result */ + z_streamp z /* for memory allocation */ +) { *bl = fixed_bl; *bd = fixed_bd; diff -Nru a/lib/zlib_inflate/inftrees.h b/lib/zlib_inflate/inftrees.h --- a/lib/zlib_inflate/inftrees.h Mon Jun 9 23:16:20 2003 +++ b/lib/zlib_inflate/inftrees.h Mon Jun 9 23:16:20 2003 @@ -14,7 +14,7 @@ #ifndef _INFTREES_H #define _INFTREES_H -typedef struct inflate_huft_s FAR inflate_huft; +typedef struct inflate_huft_s inflate_huft; struct inflate_huft_s { union { @@ -35,29 +35,29 @@ value below is more than safe. */ #define MANY 1440 -extern int zlib_inflate_trees_bits OF(( - uIntf *, /* 19 code lengths */ - uIntf *, /* bits tree desired/actual depth */ - inflate_huft * FAR *, /* bits tree result */ +extern int zlib_inflate_trees_bits ( + uInt *, /* 19 code lengths */ + uInt *, /* bits tree desired/actual depth */ + inflate_huft **, /* bits tree result */ inflate_huft *, /* space for trees */ - z_streamp)); /* for messages */ + z_streamp); /* for messages */ -extern int zlib_inflate_trees_dynamic OF(( +extern int zlib_inflate_trees_dynamic ( uInt, /* number of literal/length codes */ uInt, /* number of distance codes */ - uIntf *, /* that many (total) code lengths */ - uIntf *, /* literal desired/actual bit depth */ - uIntf *, /* distance desired/actual bit depth */ - inflate_huft * FAR *, /* literal/length tree result */ - inflate_huft * FAR *, /* distance tree result */ + uInt *, /* that many (total) code lengths */ + uInt *, /* literal desired/actual bit depth */ + uInt *, /* distance desired/actual bit depth */ + inflate_huft **, /* literal/length tree result */ + inflate_huft **, /* distance tree result */ inflate_huft *, /* space for trees */ - z_streamp)); /* for messages */ + z_streamp); /* for messages */ -extern int zlib_inflate_trees_fixed OF(( - uIntf *, /* literal desired/actual bit depth */ - uIntf *, /* distance desired/actual bit depth */ - inflate_huft * FAR *, /* literal/length tree result */ - inflate_huft * FAR *, /* distance tree result */ - z_streamp)); /* for memory allocation */ +extern int zlib_inflate_trees_fixed ( + uInt *, /* literal desired/actual bit depth */ + uInt *, /* distance desired/actual bit depth */ + inflate_huft **, /* literal/length tree result */ + inflate_huft **, /* distance tree result */ + z_streamp); /* for memory allocation */ #endif /* _INFTREES_H */ diff -Nru a/lib/zlib_inflate/infutil.c b/lib/zlib_inflate/infutil.c --- a/lib/zlib_inflate/infutil.c Mon Jun 9 23:16:17 2003 +++ b/lib/zlib_inflate/infutil.c Mon Jun 9 23:16:17 2003 @@ -20,14 +20,15 @@ /* copy as much as possible from the sliding window to the output area */ -int zlib_inflate_flush(s, z, r) -inflate_blocks_statef *s; -z_streamp z; -int r; +int zlib_inflate_flush( + inflate_blocks_statef *s, + z_streamp z, + int r +) { uInt n; - Bytef *p; - Bytef *q; + Byte *p; + Byte *q; /* local copies of source and destination pointers */ p = z->next_out; @@ -43,7 +44,7 @@ z->total_out += n; /* update check information */ - if (s->checkfn != Z_NULL) + if (s->checkfn != NULL) z->adler = s->check = (*s->checkfn)(s->check, q, n); /* copy as far as end of window */ @@ -69,7 +70,7 @@ z->total_out += n; /* update check information */ - if (s->checkfn != Z_NULL) + if (s->checkfn != NULL) z->adler = s->check = (*s->checkfn)(s->check, q, n); /* copy */ diff -Nru a/lib/zlib_inflate/infutil.h b/lib/zlib_inflate/infutil.h --- a/lib/zlib_inflate/infutil.h Mon Jun 9 23:16:16 2003 +++ b/lib/zlib_inflate/infutil.h Mon Jun 9 23:16:16 2003 @@ -40,7 +40,7 @@ struct { uInt table; /* table lengths (14 bits) */ uInt index; /* index into blens (or border) */ - uIntf *blens; /* bit lengths of codes */ + uInt *blens; /* bit lengths of codes */ uInt bb; /* bit length tree depth */ inflate_huft *tb; /* bit length decoding tree */ } trees; /* if DTREE, decoding info for trees */ @@ -55,10 +55,10 @@ uInt bitk; /* bits in bit buffer */ uLong bitb; /* bit buffer */ inflate_huft *hufts; /* single malloc for tree space */ - Bytef *window; /* sliding window */ - Bytef *end; /* one byte after sliding window */ - Bytef *read; /* window read pointer */ - Bytef *write; /* window write pointer */ + Byte *window; /* sliding window */ + Byte *end; /* one byte after sliding window */ + Byte *read; /* window read pointer */ + Byte *write; /* window write pointer */ check_func checkfn; /* check function */ uLong check; /* check on output */ @@ -92,10 +92,10 @@ extern uInt zlib_inflate_mask[17]; /* copy as much as possible from the sliding window to the output area */ -extern int zlib_inflate_flush OF(( +extern int zlib_inflate_flush ( inflate_blocks_statef *, z_streamp , - int)); + int); /* inflate private state */ typedef enum { diff -Nru a/mm/bootmem.c b/mm/bootmem.c --- a/mm/bootmem.c Mon Jun 9 23:16:09 2003 +++ b/mm/bootmem.c Mon Jun 9 23:16:09 2003 @@ -151,7 +151,11 @@ unsigned long i, start = 0, incr, eidx; void *ret; - BUG_ON(!size); + if(!size) { + printk("__alloc_bootmem_core(): zero-sized request\n"); + dump_stack(); + BUG(); + } BUG_ON(align & (align-1)); eidx = bdata->node_low_pfn - (bdata->node_boot_start >> PAGE_SHIFT); diff -Nru a/mm/filemap.c b/mm/filemap.c --- a/mm/filemap.c Mon Jun 9 23:16:09 2003 +++ b/mm/filemap.c Mon Jun 9 23:16:09 2003 @@ -81,8 +81,6 @@ { struct address_space *mapping = page->mapping; - BUG_ON(PageDirty(page) && !PageSwapCache(page)); - radix_tree_delete(&mapping->page_tree, page->index); list_del(&page->list); page->mapping = NULL; @@ -1410,7 +1408,12 @@ } } -static inline int +/* + * Copy as much as we can into the page and return the number of bytes which + * were sucessfully copied. If a fault is encountered then clear the page + * out to (offset+bytes) and return the number of bytes which were copied. + */ +static inline size_t filemap_copy_from_user(struct page *page, unsigned long offset, const char __user *buf, unsigned bytes) { @@ -1427,44 +1430,60 @@ left = __copy_from_user(kaddr + offset, buf, bytes); kunmap(page); } - return left; + return bytes - left; } -static int +static size_t __filemap_copy_from_user_iovec(char *vaddr, const struct iovec *iov, size_t base, size_t bytes) { - int left = 0; + size_t copied = 0, left = 0; while (bytes) { char __user *buf = iov->iov_base + base; int copy = min(bytes, iov->iov_len - base); + base = 0; - if ((left = __copy_from_user(vaddr, buf, copy))) - break; + left = __copy_from_user(vaddr, buf, copy); + copied += copy; bytes -= copy; vaddr += copy; iov++; + + if (unlikely(left)) { + /* zero the rest of the target like __copy_from_user */ + if (bytes) + memset(vaddr, 0, bytes); + break; + } } - return left; + return copied - left; } -static inline int +/* + * This has the same sideeffects and return value as filemap_copy_from_user(). + * The difference is that on a fault we need to memset the remainder of the + * page (out to offset+bytes), to emulate filemap_copy_from_user()'s + * single-segment behaviour. + */ +static inline size_t filemap_copy_from_user_iovec(struct page *page, unsigned long offset, const struct iovec *iov, size_t base, size_t bytes) { char *kaddr; - int left; + size_t copied; kaddr = kmap_atomic(page, KM_USER0); - left = __filemap_copy_from_user_iovec(kaddr + offset, iov, base, bytes); + copied = __filemap_copy_from_user_iovec(kaddr + offset, iov, + base, bytes); kunmap_atomic(kaddr, KM_USER0); - if (left != 0) { + if (copied != bytes) { kaddr = kmap(page); - left = __filemap_copy_from_user_iovec(kaddr + offset, iov, base, bytes); + copied = __filemap_copy_from_user_iovec(kaddr + offset, iov, + base, bytes); kunmap(page); } - return left; + return copied; } static inline void @@ -1475,6 +1494,7 @@ while (bytes) { int copy = min(bytes, iov->iov_len - base); + bytes -= copy; base += copy; if (iov->iov_len == base) { @@ -1672,7 +1692,7 @@ do { unsigned long index; unsigned long offset; - long page_fault; + size_t copied; offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */ index = pos >> PAGE_CACHE_SHIFT; @@ -1707,18 +1727,16 @@ break; } if (likely(nr_segs == 1)) - page_fault = filemap_copy_from_user(page, offset, + copied = filemap_copy_from_user(page, offset, buf, bytes); else - page_fault = filemap_copy_from_user_iovec(page, offset, + copied = filemap_copy_from_user_iovec(page, offset, cur_iov, iov_base, bytes); flush_dcache_page(page); status = a_ops->commit_write(file, page, offset, offset+bytes); - if (unlikely(page_fault)) { - status = -EFAULT; - } else { + if (likely(copied > 0)) { if (!status) - status = bytes; + status = copied; if (status >= 0) { written += status; @@ -1730,6 +1748,10 @@ &iov_base, status); } } + if (unlikely(copied != bytes)) + if (status >= 0) + status = -EFAULT; + if (!PageReferenced(page)) SetPageReferenced(page); unlock_page(page); diff -Nru a/mm/mmap.c b/mm/mmap.c --- a/mm/mmap.c Mon Jun 9 23:16:14 2003 +++ b/mm/mmap.c Mon Jun 9 23:16:14 2003 @@ -677,6 +677,7 @@ vma->vm_pgoff = pgoff; vma->vm_file = NULL; vma->vm_private_data = NULL; + vma->vm_next = NULL; INIT_LIST_HEAD(&vma->shared); if (file) { diff -Nru a/mm/page-writeback.c b/mm/page-writeback.c --- a/mm/page-writeback.c Mon Jun 9 23:16:15 2003 +++ b/mm/page-writeback.c Mon Jun 9 23:16:15 2003 @@ -26,6 +26,8 @@ #include <linux/percpu.h> #include <linux/notifier.h> #include <linux/smp.h> +#include <linux/sysctl.h> +#include <linux/cpu.h> /* * The maximum number of pages to writeout in a single bdflush/kupdate @@ -219,7 +221,6 @@ } put_cpu(); } -EXPORT_SYMBOL_GPL(balance_dirty_pages_ratelimited); /* * writeback at least _min_pages, and keep writing until the amount of dirty @@ -329,7 +330,24 @@ } if (time_before(next_jif, jiffies + HZ)) next_jif = jiffies + HZ; - mod_timer(&wb_timer, next_jif); + if (dirty_writeback_centisecs) + mod_timer(&wb_timer, next_jif); +} + +/* + * sysctl handler for /proc/sys/vm/dirty_writeback_centisecs + */ +int dirty_writeback_centisecs_handler(ctl_table *table, int write, + struct file *file, void *buffer, size_t *length) +{ + proc_dointvec(table, write, file, buffer, length); + if (dirty_writeback_centisecs) { + mod_timer(&wb_timer, + jiffies + (dirty_writeback_centisecs * HZ) / 100); + } else { + del_timer(&wb_timer); + } + return 0; } static void wb_timer_fn(unsigned long unused) @@ -430,11 +448,12 @@ int ret = 0; struct writeback_control wbc = { .sync_mode = WB_SYNC_ALL, + .nr_to_write = 1, }; BUG_ON(!PageLocked(page)); - if (wait && PageWriteback(page)) + if (wait) wait_on_page_writeback(page); spin_lock(&mapping->page_lock); diff -Nru a/mm/page_alloc.c b/mm/page_alloc.c --- a/mm/page_alloc.c Mon Jun 9 23:16:07 2003 +++ b/mm/page_alloc.c Mon Jun 9 23:16:07 2003 @@ -28,8 +28,9 @@ #include <linux/blkdev.h> #include <linux/slab.h> #include <linux/notifier.h> - -#include <asm/topology.h> +#include <linux/topology.h> +#include <linux/sysctl.h> +#include <linux/cpu.h> DECLARE_BITMAP(node_online_map, MAX_NUMNODES); DECLARE_BITMAP(memblk_online_map, MAX_NR_MEMBLKS); @@ -48,9 +49,7 @@ EXPORT_SYMBOL(zone_table); static char *zone_names[MAX_NR_ZONES] = { "DMA", "Normal", "HighMem" }; -static int zone_balance_ratio[MAX_NR_ZONES] __initdata = { 128, 128, 128, }; -static int zone_balance_min[MAX_NR_ZONES] __initdata = { 20 , 20, 20, }; -static int zone_balance_max[MAX_NR_ZONES] __initdata = { 255 , 255, 255, }; +int min_free_kbytes = 1024; /* * Temporary debugging check for pages not lying within a given zone. @@ -1206,7 +1205,6 @@ for (j = 0; j < MAX_NR_ZONES; j++) { struct zone *zone = pgdat->node_zones + j; - unsigned long mask; unsigned long size, realsize; unsigned long batch; @@ -1280,15 +1278,6 @@ pgdat->nr_zones = j+1; - mask = (realsize / zone_balance_ratio[j]); - if (mask < zone_balance_min[j]) - mask = zone_balance_min[j]; - else if (mask > zone_balance_max[j]) - mask = zone_balance_max[j]; - zone->pages_min = mask; - zone->pages_low = mask*2; - zone->pages_high = mask*3; - zone->zone_mem_map = lmem_map; zone->zone_start_pfn = zone_start_pfn; @@ -1373,19 +1362,6 @@ } #endif -static int __init setup_mem_frac(char *str) -{ - int j = 0; - - while (get_option(&str, &zone_balance_ratio[j++]) == 2); - printk("setup_mem_frac: "); - for (j = 0; j < MAX_NR_ZONES; j++) printk("%d ", zone_balance_ratio[j]); - printk("\n"); - return 1; -} - -__setup("memfrac=", setup_mem_frac); - #ifdef CONFIG_PROC_FS #include <linux/seq_file.h> @@ -1561,4 +1537,65 @@ { init_page_alloc_cpu(smp_processor_id()); register_cpu_notifier(&page_alloc_nb); +} + +/* + * setup_per_zone_pages_min - called when min_free_kbytes changes. Ensures + * that the pages_{min,low,high} values for each zone are set correctly + * with respect to min_free_kbytes. + */ +void setup_per_zone_pages_min(void) +{ + unsigned long pages_min = min_free_kbytes >> (PAGE_SHIFT - 10); + unsigned long lowmem_pages = 0; + struct zone *zone; + unsigned long flags; + + /* Calculate total number of !ZONE_HIGHMEM pages */ + for_each_zone(zone) + if (!is_highmem(zone)) + lowmem_pages += zone->present_pages; + + for_each_zone(zone) { + spin_lock_irqsave(&zone->lru_lock, flags); + if (is_highmem(zone)) { + /* + * Often, highmem doesn't need to reserve any pages. + * But the pages_min/low/high values are also used for + * batching up page reclaim activity so we need a + * decent value here. + */ + int min_pages; + + min_pages = zone->present_pages / 1024; + if (min_pages < SWAP_CLUSTER_MAX) + min_pages = SWAP_CLUSTER_MAX; + if (min_pages > 128) + min_pages = 128; + zone->pages_min = min_pages; + } else { + /* if it's a lowmem zone, reserve a number of pages + * proportionate to the zone's size. + */ + zone->pages_min = (pages_min * zone->present_pages) / + lowmem_pages; + } + + zone->pages_low = zone->pages_min * 2; + zone->pages_high = zone->pages_min * 3; + spin_unlock_irqrestore(&zone->lru_lock, flags); + } +} + +/* + * min_free_kbytes_sysctl_handler - just a wrapper around proc_dointvec() so + * that we can call setup_per_zone_pages_min() whenever min_free_kbytes + * changes. + */ +int min_free_kbytes_sysctl_handler(ctl_table *table, int write, + struct file *file, void *buffer, size_t *length) +{ + proc_dointvec(table, write, file, buffer, length); + setup_per_zone_pages_min(); + return 0; } diff -Nru a/mm/slab.c b/mm/slab.c --- a/mm/slab.c Mon Jun 9 23:16:16 2003 +++ b/mm/slab.c Mon Jun 9 23:16:16 2003 @@ -25,6 +25,10 @@ * page long) and always contiguous), and each slab contains multiple * initialized objects. * + * This means, that your constructor is used only for newly allocated + * slabs and you must pass objects with the same intializations to + * kmem_cache_free. + * * Each cache can only support one memory type (GFP_DMA, GFP_HIGHMEM, * normal). If you need a special memory type, then must create a new * cache for that memory type. @@ -84,6 +88,7 @@ #include <linux/seq_file.h> #include <linux/notifier.h> #include <linux/kallsyms.h> +#include <linux/cpu.h> #include <asm/uaccess.h> /* @@ -210,6 +215,7 @@ unsigned long free_objects; int free_touched; unsigned long next_reap; + struct array_cache *shared; }; #define LIST3_INIT(parent) \ @@ -781,7 +787,7 @@ *(unsigned char *)(addr+size-1) = POISON_END; } -static void *fprob(unsigned char* addr, unsigned int size) +static void *scan_poisoned_obj(unsigned char* addr, unsigned int size) { unsigned char *end; @@ -807,7 +813,7 @@ if (cachep->flags & SLAB_STORE_USER) { size -= BYTES_PER_WORD; } - end = fprob(addr, size); + end = scan_poisoned_obj(addr, size); if (end) { int s; printk(KERN_ERR "Slab corruption: start=%p, expend=%p, " @@ -1209,6 +1215,7 @@ } static void free_block (kmem_cache_t* cachep, void** objpp, int len); +static void drain_array_locked(kmem_cache_t* cachep, struct array_cache *ac); static void do_drain(void *arg) { @@ -1217,13 +1224,20 @@ check_irq_off(); ac = ac_data(cachep); + spin_lock(&cachep->spinlock); free_block(cachep, &ac_entry(ac)[0], ac->avail); + spin_unlock(&cachep->spinlock); ac->avail = 0; } static void drain_cpu_caches(kmem_cache_t *cachep) { smp_call_function_all_cpus(do_drain, cachep); + check_irq_on(); + spin_lock_irq(&cachep->spinlock); + if (cachep->lists.shared) + drain_array_locked(cachep, cachep->lists.shared); + spin_unlock_irq(&cachep->spinlock); } @@ -1321,6 +1335,8 @@ for (i = 0; i < NR_CPUS; i++) kfree(cachep->array[i]); /* NUMA: free the list3 structures */ + kfree(cachep->lists.shared); + cachep->lists.shared = NULL; } kmem_cache_free(&cache_cache, cachep); @@ -1663,6 +1679,19 @@ BUG_ON(ac->avail > 0); spin_lock(&cachep->spinlock); + if (l3->shared) { + struct array_cache *shared_array = l3->shared; + if (shared_array->avail) { + if (batchcount > shared_array->avail) + batchcount = shared_array->avail; + shared_array->avail -= batchcount; + ac->avail = batchcount; + memcpy(ac_entry(ac), &ac_entry(shared_array)[shared_array->avail], + sizeof(void*)*batchcount); + shared_array->touched = 1; + goto alloc_done; + } + } while (batchcount > 0) { struct list_head *entry; struct slab *slabp; @@ -1686,6 +1715,7 @@ must_grow: l3->free_objects -= ac->avail; +alloc_done: spin_unlock(&cachep->spinlock); if (unlikely(!ac->avail)) { @@ -1784,13 +1814,11 @@ * the l3 structure */ -static inline void -__free_block(kmem_cache_t *cachep, void **objpp, int nr_objects) +static void free_block(kmem_cache_t *cachep, void **objpp, int nr_objects) { int i; - check_irq_off(); - spin_lock(&cachep->spinlock); + check_spinlock_acquired(cachep); /* NUMA: move add into loop */ cachep->lists.free_objects += nr_objects; @@ -1828,12 +1856,6 @@ &list3_data_ptr(cachep, objp)->slabs_partial); } } - spin_unlock(&cachep->spinlock); -} - -static void free_block(kmem_cache_t* cachep, void** objpp, int len) -{ - __free_block(cachep, objpp, len); } static void cache_flusharray (kmem_cache_t* cachep, struct array_cache *ac) @@ -1845,14 +1867,28 @@ BUG_ON(!batchcount || batchcount > ac->avail); #endif check_irq_off(); - __free_block(cachep, &ac_entry(ac)[0], batchcount); + spin_lock(&cachep->spinlock); + if (cachep->lists.shared) { + struct array_cache *shared_array = cachep->lists.shared; + int max = shared_array->limit-shared_array->avail; + if (max) { + if (batchcount > max) + batchcount = max; + memcpy(&ac_entry(shared_array)[shared_array->avail], + &ac_entry(ac)[0], + sizeof(void*)*batchcount); + shared_array->avail += batchcount; + goto free_done; + } + } + free_block(cachep, &ac_entry(ac)[0], batchcount); +free_done: #if STATS { int i = 0; struct list_head *p; - spin_lock(&cachep->spinlock); p = list3_data(cachep)->slabs_free.next; while (p != &(list3_data(cachep)->slabs_free)) { struct slab *slabp; @@ -1864,9 +1900,9 @@ p = p->next; } STATS_SET_FREEABLE(cachep, i); - spin_unlock(&cachep->spinlock); } #endif + spin_unlock(&cachep->spinlock); ac->avail -= batchcount; memmove(&ac_entry(ac)[0], &ac_entry(ac)[batchcount], sizeof(void*)*ac->avail); @@ -1953,26 +1989,18 @@ #ifdef CONFIG_SMP /** - * kmalloc_percpu - allocate one copy of the object for every present - * cpu in the system. + * __alloc_percpu - allocate one copy of the object for every present + * cpu in the system, zeroing them. * Objects should be dereferenced using per_cpu_ptr/get_cpu_ptr * macros only. * * @size: how many bytes of memory are required. - * @flags: the type of memory to allocate. - * The @flags argument may be one of: - * - * %GFP_USER - Allocate memory on behalf of user. May sleep. - * - * %GFP_KERNEL - Allocate normal kernel ram. May sleep. - * - * %GFP_ATOMIC - Allocation will not sleep. Use inside interrupt handlers. + * @align: the alignment, which can't be greater than SMP_CACHE_BYTES. */ -void * -kmalloc_percpu(size_t size, int flags) +void *__alloc_percpu(size_t size, size_t align) { int i; - struct percpu_data *pdata = kmalloc(sizeof (*pdata), flags); + struct percpu_data *pdata = kmalloc(sizeof (*pdata), GFP_KERNEL); if (!pdata) return NULL; @@ -1980,9 +2008,10 @@ for (i = 0; i < NR_CPUS; i++) { if (!cpu_possible(i)) continue; - pdata->ptrs[i] = kmalloc(size, flags); + pdata->ptrs[i] = kmalloc(size, GFP_KERNEL); if (!pdata->ptrs[i]) goto unwind_oom; + memset(pdata->ptrs[i], 0, size); } /* Catch derefs w/o wrappers */ @@ -2039,14 +2068,14 @@ #ifdef CONFIG_SMP /** - * kfree_percpu - free previously allocated percpu memory - * @objp: pointer returned by kmalloc_percpu. + * free_percpu - free previously allocated percpu memory + * @objp: pointer returned by alloc_percpu. * - * Don't free memory not originally allocated by kmalloc_percpu() + * Don't free memory not originally allocated by alloc_percpu() * The complemented objp is to check for that. */ void -kfree_percpu(const void *objp) +free_percpu(const void *objp) { int i; struct percpu_data *p = (struct percpu_data *) (~(unsigned long) objp); @@ -2107,9 +2136,10 @@ } -static int do_tune_cpucache (kmem_cache_t* cachep, int limit, int batchcount) +static int do_tune_cpucache (kmem_cache_t* cachep, int limit, int batchcount, int shared) { struct ccupdate_struct new; + struct array_cache *new_shared; int i; memset(&new.new,0,sizeof(new.new)); @@ -2143,11 +2173,29 @@ struct array_cache *ccold = new.new[i]; if (!ccold) continue; - local_irq_disable(); + spin_lock_irq(&cachep->spinlock); free_block(cachep, ac_entry(ccold), ccold->avail); - local_irq_enable(); + spin_unlock_irq(&cachep->spinlock); kfree(ccold); } + new_shared = kmalloc(sizeof(void*)*batchcount*shared+ + sizeof(struct array_cache), GFP_KERNEL); + if (new_shared) { + struct array_cache *old; + new_shared->avail = 0; + new_shared->limit = batchcount*shared; + new_shared->batchcount = 0xbaadf00d; + new_shared->touched = 0; + + spin_lock_irq(&cachep->spinlock); + old = cachep->lists.shared; + cachep->lists.shared = new_shared; + if (old) + free_block(cachep, ac_entry(old), old->avail); + spin_unlock_irq(&cachep->spinlock); + kfree(old); + } + return 0; } @@ -2155,7 +2203,7 @@ static void enable_cpucache (kmem_cache_t *cachep) { int err; - int limit; + int limit, shared; /* The head array serves three purposes: * - create a LIFO ordering, i.e. return objects that are cache-warm @@ -2170,11 +2218,25 @@ else if (cachep->objsize > PAGE_SIZE) limit = 8; else if (cachep->objsize > 1024) - limit = 54; + limit = 24; else if (cachep->objsize > 256) - limit = 120; + limit = 54; else - limit = 248; + limit = 120; + + /* Cpu bound tasks (e.g. network routing) can exhibit cpu bound + * allocation behaviour: Most allocs on one cpu, most free operations + * on another cpu. For these cases, an efficient object passing between + * cpus is necessary. This is provided by a shared array. The array + * replaces Bonwick's magazine layer. + * On uniprocessor, it's functionally equivalent (but less efficient) + * to a larger limit. Thus disabled by default. + */ + shared = 0; +#ifdef CONFIG_SMP + if (cachep->objsize <= PAGE_SIZE) + shared = 8; +#endif #if DEBUG /* With debugging enabled, large batchcount lead to excessively @@ -2184,12 +2246,53 @@ if (limit > 32) limit = 32; #endif - err = do_tune_cpucache(cachep, limit, (limit+1)/2); + err = do_tune_cpucache(cachep, limit, (limit+1)/2, shared); if (err) printk(KERN_ERR "enable_cpucache failed for %s, error %d.\n", cachep->name, -err); } +static void drain_array(kmem_cache_t *cachep, struct array_cache *ac) +{ + int tofree; + + check_irq_off(); + if (ac->touched) { + ac->touched = 0; + } else if (ac->avail) { + tofree = (ac->limit+4)/5; + if (tofree > ac->avail) { + tofree = (ac->avail+1)/2; + } + spin_lock(&cachep->spinlock); + free_block(cachep, ac_entry(ac), tofree); + spin_unlock(&cachep->spinlock); + ac->avail -= tofree; + memmove(&ac_entry(ac)[0], &ac_entry(ac)[tofree], + sizeof(void*)*ac->avail); + } +} + +static void drain_array_locked(kmem_cache_t *cachep, struct array_cache *ac) +{ + int tofree; + + check_spinlock_acquired(cachep); + if (ac->touched) { + ac->touched = 0; + } else if (ac->avail) { + tofree = (ac->limit+4)/5; + if (tofree > ac->avail) { + tofree = (ac->avail+1)/2; + } + free_block(cachep, ac_entry(ac), tofree); + ac->avail -= tofree; + memmove(&ac_entry(ac)[0], &ac_entry(ac)[tofree], + sizeof(void*)*ac->avail); + } +} + + /** * cache_reap - Reclaim memory from caches. * @@ -2216,7 +2319,6 @@ kmem_cache_t *searchp; struct list_head* p; int tofree; - struct array_cache *ac; struct slab *slabp; searchp = list_entry(walk, kmem_cache_t, next); @@ -2226,19 +2328,8 @@ check_irq_on(); local_irq_disable(); - ac = ac_data(searchp); - if (ac->touched) { - ac->touched = 0; - } else if (ac->avail) { - tofree = (ac->limit+4)/5; - if (tofree > ac->avail) { - tofree = (ac->avail+1)/2; - } - free_block(searchp, ac_entry(ac), tofree); - ac->avail -= tofree; - memmove(&ac_entry(ac)[0], &ac_entry(ac)[tofree], - sizeof(void*)*ac->avail); - } + drain_array(searchp, ac_data(searchp)); + if(time_after(searchp->lists.next_reap, jiffies)) goto next_irqon; @@ -2247,6 +2338,10 @@ goto next_unlock; } searchp->lists.next_reap = jiffies + REAPTIMEOUT_LIST3; + + if (searchp->lists.shared) + drain_array_locked(searchp, searchp->lists.shared); + if (searchp->lists.free_touched) { searchp->lists.free_touched = 0; goto next_unlock; @@ -2311,11 +2406,19 @@ * Output format version, so at least we can change it * without _too_ many complaints. */ - seq_puts(m, "slabinfo - version: 1.2" #if STATS - " (statistics)" + seq_puts(m, "slabinfo - version: 2.0 (statistics)\n"); +#else + seq_puts(m, "slabinfo - version: 2.0\n"); +#endif + seq_puts(m, "# name <active_objs> <num_objs> <objsize> <objperslab> <pagesperslab>"); + seq_puts(m, " : tunables <batchcount> <limit <sharedfactor>"); + seq_puts(m, " : slabdata <active_slabs> <num_slabs> <sharedavail>"); +#if STATS + seq_puts(m, " : globalstat <listallocs> <maxobjs> <grown> <reaped> <error> <maxfreeable> <freelimit>"); + seq_puts(m, " : cpustat <allochit <allocmiss <freehit <freemiss>"); #endif - "\n"); + seq_putc(m, '\n'); } p = cache_chain.next; while (n--) { @@ -2399,13 +2502,16 @@ if (error) printk(KERN_ERR "slab: cache %s error: %s\n", name, error); - seq_printf(m, "%-17s %6lu %6lu %6u %4lu %4lu %4u", + seq_printf(m, "%-17s %6lu %6lu %6u %4u %4d", name, active_objs, num_objs, cachep->objsize, - active_slabs, num_slabs, (1<<cachep->gfporder)); - - seq_printf(m, " : %4u %4u", cachep->limit, cachep->batchcount); + cachep->num, (1<<cachep->gfporder)); + seq_printf(m, " : tunables %4u %4u %4u", + cachep->limit, cachep->batchcount, + cachep->lists.shared->limit/cachep->batchcount); + seq_printf(m, " : slabdata %6lu %6lu %6u", + active_slabs, num_slabs, cachep->lists.shared->avail); #if STATS - { // list3 stats + { /* list3 stats */ unsigned long high = cachep->high_mark; unsigned long allocs = cachep->num_allocations; unsigned long grown = cachep->grown; @@ -2414,22 +2520,23 @@ unsigned long max_freeable = cachep->max_freeable; unsigned long free_limit = cachep->free_limit; - seq_printf(m, " : %6lu %7lu %5lu %4lu %4lu %4lu %4lu", - high, allocs, grown, reaped, errors, + seq_printf(m, " : globalstat %7lu %6lu %5lu %4lu %4lu %4lu %4lu", + allocs, high, grown, reaped, errors, max_freeable, free_limit); } - { // cpucache stats + /* cpu stats */ + { unsigned long allochit = atomic_read(&cachep->allochit); unsigned long allocmiss = atomic_read(&cachep->allocmiss); unsigned long freehit = atomic_read(&cachep->freehit); unsigned long freemiss = atomic_read(&cachep->freemiss); - seq_printf(m, " : %6lu %6lu %6lu %6lu", - allochit, allocmiss, freehit, freemiss); + seq_printf(m, " : cpustat %6lu %6lu %6lu %6lu", + allochit, allocmiss, freehit, freemiss); } #endif - spin_unlock_irq(&cachep->spinlock); seq_putc(m, '\n'); + spin_unlock_irq(&cachep->spinlock); return 0; } @@ -2456,7 +2563,7 @@ #define MAX_SLABINFO_WRITE 128 /** - * slabinfo_write - SMP tuning for the slab allocator + * slabinfo_write - Tuning for the slab allocator * @file: unused * @buffer: user buffer * @count: data len @@ -2466,7 +2573,7 @@ size_t count, loff_t *ppos) { char kbuf[MAX_SLABINFO_WRITE+1], *tmp; - int limit, batchcount, res; + int limit, batchcount, shared, res; struct list_head *p; if (count > MAX_SLABINFO_WRITE) @@ -2480,10 +2587,8 @@ return -EINVAL; *tmp = '\0'; tmp++; - limit = simple_strtol(tmp, &tmp, 10); - while (*tmp == ' ') - tmp++; - batchcount = simple_strtol(tmp, &tmp, 10); + if (sscanf(tmp, " %d %d %d", &limit, &batchcount, &shared) != 3) + return -EINVAL; /* Find the cache in the chain of caches. */ down(&cache_chain_sem); @@ -2494,10 +2599,11 @@ if (!strcmp(cachep->name, kbuf)) { if (limit < 1 || batchcount < 1 || - batchcount > limit) { + batchcount > limit || + shared < 0) { res = -EINVAL; } else { - res = do_tune_cpucache(cachep, limit, batchcount); + res = do_tune_cpucache(cachep, limit, batchcount, shared); } break; } diff -Nru a/mm/vmscan.c b/mm/vmscan.c --- a/mm/vmscan.c Mon Jun 9 23:16:07 2003 +++ b/mm/vmscan.c Mon Jun 9 23:16:07 2003 @@ -28,10 +28,10 @@ #include <linux/pagevec.h> #include <linux/backing-dev.h> #include <linux/rmap-locking.h> +#include <linux/topology.h> #include <asm/pgalloc.h> #include <asm/tlbflush.h> -#include <asm/topology.h> #include <asm/div64.h> #include <linux/swapops.h> diff -Nru a/net/appletalk/aarp.c b/net/appletalk/aarp.c --- a/net/appletalk/aarp.c Mon Jun 9 23:16:19 2003 +++ b/net/appletalk/aarp.c Mon Jun 9 23:16:19 2003 @@ -630,7 +630,7 @@ sendit: if (skb->sk) - skb->priority = skb->sk->priority; + skb->priority = skb->sk->sk_priority; dev_queue_xmit(skb); sent: return 1; diff -Nru a/net/appletalk/atalk_proc.c b/net/appletalk/atalk_proc.c --- a/net/appletalk/atalk_proc.c Mon Jun 9 23:16:18 2003 +++ b/net/appletalk/atalk_proc.c Mon Jun 9 23:16:18 2003 @@ -144,7 +144,7 @@ { struct sock *s; - for (s = atalk_sockets; pos && s; s = s->next) + for (s = atalk_sockets; pos && s; s = s->sk_next) --pos; return s; @@ -170,7 +170,7 @@ goto out; } i = v; - i = i->next; + i = i->sk_next; out: return i; } @@ -196,10 +196,11 @@ seq_printf(seq, "%02X %04X:%02X:%02X %04X:%02X:%02X %08X:%08X " "%02X %d\n", - s->type, ntohs(at->src_net), at->src_node, at->src_port, + s->sk_type, ntohs(at->src_net), at->src_node, at->src_port, ntohs(at->dest_net), at->dest_node, at->dest_port, - atomic_read(&s->wmem_alloc), atomic_read(&s->rmem_alloc), - s->state, SOCK_INODE(s->socket)->i_uid); + atomic_read(&s->sk_wmem_alloc), + atomic_read(&s->sk_rmem_alloc), + s->sk_state, SOCK_INODE(s->sk_socket)->i_uid); out: return 0; } diff -Nru a/net/appletalk/ddp.c b/net/appletalk/ddp.c --- a/net/appletalk/ddp.c Mon Jun 9 23:16:19 2003 +++ b/net/appletalk/ddp.c Mon Jun 9 23:16:19 2003 @@ -92,11 +92,11 @@ static inline void atalk_insert_socket(struct sock *sk) { write_lock_bh(&atalk_sockets_lock); - sk->next = atalk_sockets; - if (sk->next) - atalk_sockets->pprev = &sk->next; + sk->sk_next = atalk_sockets; + if (sk->sk_next) + atalk_sockets->sk_pprev = &sk->sk_next; atalk_sockets = sk; - sk->pprev = &atalk_sockets; + sk->sk_pprev = &atalk_sockets; write_unlock_bh(&atalk_sockets_lock); } #endif @@ -104,11 +104,11 @@ static inline void atalk_remove_socket(struct sock *sk) { write_lock_bh(&atalk_sockets_lock); - if (sk->pprev) { - if (sk->next) - sk->next->pprev = sk->pprev; - *sk->pprev = sk->next; - sk->pprev = NULL; + if (sk->sk_pprev) { + if (sk->sk_next) + sk->sk_next->sk_pprev = sk->sk_pprev; + *sk->sk_pprev = sk->sk_next; + sk->sk_pprev = NULL; } write_unlock_bh(&atalk_sockets_lock); } @@ -119,7 +119,7 @@ struct sock *s; read_lock_bh(&atalk_sockets_lock); - for (s = atalk_sockets; s; s = s->next) { + for (s = atalk_sockets; s; s = s->sk_next) { struct atalk_sock *at = at_sk(s); if (to->sat_port != at->src_port) @@ -165,7 +165,7 @@ struct sock *s; write_lock_bh(&atalk_sockets_lock); - for (s = atalk_sockets; s; s = s->next) { + for (s = atalk_sockets; s; s = s->sk_next) { struct atalk_sock *at = at_sk(s); if (at->src_net == sat->sat_addr.s_net && @@ -176,11 +176,11 @@ if (!s) { /* Wheee, it's free, assign and insert. */ - sk->next = atalk_sockets; - if (sk->next) - atalk_sockets->pprev = &sk->next; + sk->sk_next = atalk_sockets; + if (sk->sk_next) + atalk_sockets->sk_pprev = &sk->sk_next; atalk_sockets = sk; - sk->pprev = &atalk_sockets; + sk->sk_pprev = &atalk_sockets; } write_unlock_bh(&atalk_sockets_lock); @@ -191,29 +191,29 @@ { struct sock *sk = (struct sock *)data; - if (!atomic_read(&sk->wmem_alloc) && - !atomic_read(&sk->rmem_alloc) && test_bit(SOCK_DEAD, &sk->flags)) + if (!atomic_read(&sk->sk_wmem_alloc) && + !atomic_read(&sk->sk_rmem_alloc) && sock_flag(sk, SOCK_DEAD)) sock_put(sk); else { - sk->timer.expires = jiffies + SOCK_DESTROY_TIME; - add_timer(&sk->timer); + sk->sk_timer.expires = jiffies + SOCK_DESTROY_TIME; + add_timer(&sk->sk_timer); } } static inline void atalk_destroy_socket(struct sock *sk) { atalk_remove_socket(sk); - skb_queue_purge(&sk->receive_queue); + skb_queue_purge(&sk->sk_receive_queue); - if (!atomic_read(&sk->wmem_alloc) && - !atomic_read(&sk->rmem_alloc) && test_bit(SOCK_DEAD, &sk->flags)) + if (!atomic_read(&sk->sk_wmem_alloc) && + !atomic_read(&sk->sk_rmem_alloc) && sock_flag(sk, SOCK_DEAD)) sock_put(sk); else { - init_timer(&sk->timer); - sk->timer.expires = jiffies + SOCK_DESTROY_TIME; - sk->timer.function = atalk_destroy_timer; - sk->timer.data = (unsigned long) sk; - add_timer(&sk->timer); + init_timer(&sk->sk_timer); + sk->sk_timer.expires = jiffies + SOCK_DESTROY_TIME; + sk->sk_timer.function = atalk_destroy_timer; + sk->sk_timer.data = (unsigned long)sk; + add_timer(&sk->sk_timer); } } @@ -992,7 +992,7 @@ sock->ops = &atalk_dgram_ops; sock_init_data(sock, sk); /* Checksums on by default */ - sk->zapped = 1; + sk->sk_zapped = 1; out: return rc; outsk: @@ -1006,9 +1006,10 @@ struct sock *sk = sock->sk; if (sk) { - if (!test_bit(SOCK_DEAD, &sk->flags)) - sk->state_change(sk); - __set_bit(SOCK_DEAD, &sk->flags); + if (!sock_flag(sk, SOCK_DEAD)) { + sk->sk_state_change(sk); + sock_set_flag(sk, SOCK_DEAD); + } sock->sk = NULL; atalk_destroy_socket(sk); } @@ -1035,7 +1036,7 @@ for (sat->sat_port = ATPORT_RESERVED; sat->sat_port < ATPORT_LAST; sat->sat_port++) { - for (s = atalk_sockets; s; s = s->next) { + for (s = atalk_sockets; s; s = s->sk_next) { struct atalk_sock *at = at_sk(s); if (at->src_net == sat->sat_addr.s_net && @@ -1045,11 +1046,11 @@ } /* Wheee, it's free, assign and insert. */ - sk->next = atalk_sockets; - if (sk->next) - atalk_sockets->pprev = &sk->next; + sk->sk_next = atalk_sockets; + if (sk->sk_next) + atalk_sockets->sk_pprev = &sk->sk_next; atalk_sockets = sk; - sk->pprev = &atalk_sockets; + sk->sk_pprev = &atalk_sockets; at_sk(sk)->src_port = sat->sat_port; retval = 0; goto out; @@ -1078,7 +1079,7 @@ n = atalk_pick_and_bind_port(sk, &sat); if (!n) - sk->zapped = 0; + sk->sk_zapped = 0; out: return n; } @@ -1090,7 +1091,7 @@ struct sock *sk = sock->sk; struct atalk_sock *at = at_sk(sk); - if (!sk->zapped || addr_len != sizeof(struct sockaddr_at)) + if (!sk->sk_zapped || addr_len != sizeof(struct sockaddr_at)) return -EINVAL; if (addr->sat_family != AF_APPLETALK) @@ -1125,7 +1126,7 @@ return -EADDRINUSE; } - sk->zapped = 0; + sk->sk_zapped = 0; return 0; } @@ -1137,7 +1138,7 @@ struct atalk_sock *at = at_sk(sk); struct sockaddr_at *addr; - sk->state = TCP_CLOSE; + sk->sk_state = TCP_CLOSE; sock->state = SS_UNCONNECTED; if (addr_len != sizeof(*addr)) @@ -1149,7 +1150,7 @@ return -EAFNOSUPPORT; if (addr->sat_addr.s_node == ATADDR_BCAST && - !test_bit(SOCK_BROADCAST, &sk->flags)) { + !sock_flag(sk, SOCK_BROADCAST)) { #if 1 printk(KERN_WARNING "%s is broken and did not set " "SO_BROADCAST. It will break when 2.2 is " @@ -1160,7 +1161,7 @@ #endif } - if (sk->zapped) + if (sk->sk_zapped) if (atalk_autobind(sk) < 0) return -EBUSY; @@ -1171,8 +1172,8 @@ at->dest_net = addr->sat_addr.s_net; at->dest_node = addr->sat_addr.s_node; - sock->state = SS_CONNECTED; - sk->state = TCP_ESTABLISHED; + sock->state = SS_CONNECTED; + sk->sk_state = TCP_ESTABLISHED; return 0; } @@ -1187,14 +1188,14 @@ struct sock *sk = sock->sk; struct atalk_sock *at = at_sk(sk); - if (sk->zapped) + if (sk->sk_zapped) if (atalk_autobind(sk) < 0) return -ENOBUFS; *uaddr_len = sizeof(struct sockaddr_at); if (peer) { - if (sk->state != TCP_ESTABLISHED) + if (sk->sk_state != TCP_ESTABLISHED) return -ENOTCONN; sat.sat_addr.s_net = at->dest_net; @@ -1505,7 +1506,7 @@ return -EMSGSIZE; if (usat) { - if (sk->zapped) + if (sk->sk_zapped) if (atalk_autobind(sk) < 0) return -EBUSY; @@ -1515,7 +1516,7 @@ /* netatalk doesn't implement this check */ if (usat->sat_addr.s_node == ATADDR_BCAST && - !test_bit(SOCK_BROADCAST, &sk->flags)) { + !sock_flag(sk, SOCK_BROADCAST)) { printk(KERN_INFO "SO_BROADCAST: Fix your netatalk as " "it will break before 2.2\n"); #if 0 @@ -1523,7 +1524,7 @@ #endif } } else { - if (sk->state != TCP_ESTABLISHED) + if (sk->sk_state != TCP_ESTABLISHED) return -ENOTCONN; usat = &local_satalk; usat->sat_family = AF_APPLETALK; @@ -1598,7 +1599,7 @@ return -EFAULT; } - if (sk->no_check == 1) + if (sk->sk_no_check == 1) ddp->deh_sum = 0; else ddp->deh_sum = atalk_checksum(ddp, len + sizeof(*ddp)); @@ -1660,7 +1661,7 @@ ddp = ddp_hdr(skb); *((__u16 *)&ddphv) = ntohs(*((__u16 *)ddp)); - if (sk->type == SOCK_RAW) { + if (sk->sk_type == SOCK_RAW) { copied = ddphv.deh_len; if (copied > size) { copied = size; @@ -1704,7 +1705,8 @@ switch (cmd) { /* Protocol layer */ case TIOCOUTQ: { - long amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); + long amount = sk->sk_sndbuf - + atomic_read(&sk->sk_wmem_alloc); if (amount < 0) amount = 0; @@ -1716,7 +1718,7 @@ * These two are safe on a single CPU system as only * user tasks fiddle here */ - struct sk_buff *skb = skb_peek(&sk->receive_queue); + struct sk_buff *skb = skb_peek(&sk->sk_receive_queue); long amount = 0; if (skb) @@ -1728,9 +1730,9 @@ if (!sk) break; rc = -ENOENT; - if (!sk->stamp.tv_sec) + if (!sk->sk_stamp.tv_sec) break; - rc = copy_to_user((void *)arg, &sk->stamp, + rc = copy_to_user((void *)arg, &sk->sk_stamp, sizeof(struct timeval)) ? -EFAULT : 0; break; /* Routing */ diff -Nru a/net/atm/atm_misc.c b/net/atm/atm_misc.c --- a/net/atm/atm_misc.c Mon Jun 9 23:16:08 2003 +++ b/net/atm/atm_misc.c Mon Jun 9 23:16:08 2003 @@ -16,7 +16,8 @@ int atm_charge(struct atm_vcc *vcc,int truesize) { atm_force_charge(vcc,truesize); - if (atomic_read(&vcc->sk->rmem_alloc) <= vcc->sk->rcvbuf) return 1; + if (atomic_read(&vcc->sk->sk_rmem_alloc) <= vcc->sk->sk_rcvbuf) + return 1; atm_return(vcc,truesize); atomic_inc(&vcc->stats->rx_drop); return 0; @@ -29,11 +30,12 @@ int guess = atm_guess_pdu2truesize(pdu_size); atm_force_charge(vcc,guess); - if (atomic_read(&vcc->sk->rmem_alloc) <= vcc->sk->rcvbuf) { + if (atomic_read(&vcc->sk->sk_rmem_alloc) <= vcc->sk->sk_rcvbuf) { struct sk_buff *skb = alloc_skb(pdu_size,gfp_flags); if (skb) { - atomic_add(skb->truesize-guess,&vcc->sk->rmem_alloc); + atomic_add(skb->truesize-guess, + &vcc->sk->sk_rmem_alloc); return skb; } } diff -Nru a/net/atm/br2684.c b/net/atm/br2684.c --- a/net/atm/br2684.c Mon Jun 9 23:16:10 2003 +++ b/net/atm/br2684.c Mon Jun 9 23:16:10 2003 @@ -188,7 +188,7 @@ dev_kfree_skb(skb); return 0; } - atomic_add(skb->truesize, &atmvcc->sk->wmem_alloc); + atomic_add(skb->truesize, &atmvcc->sk->sk_wmem_alloc); ATM_SKB(skb)->atm_options = atmvcc->atm_options; brdev->stats.tx_packets++; brdev->stats.tx_bytes += skb->len; @@ -551,7 +551,7 @@ barrier(); atmvcc->push = br2684_push; skb_queue_head_init(©); - skb_migrate(&atmvcc->sk->receive_queue, ©); + skb_migrate(&atmvcc->sk->sk_receive_queue, ©); while ((skb = skb_dequeue(©))) { BRPRIV(skb->dev)->stats.rx_bytes -= skb->len; BRPRIV(skb->dev)->stats.rx_packets--; diff -Nru a/net/atm/clip.c b/net/atm/clip.c --- a/net/atm/clip.c Mon Jun 9 23:16:19 2003 +++ b/net/atm/clip.c Mon Jun 9 23:16:19 2003 @@ -66,7 +66,7 @@ ctrl->itf_num = itf; ctrl->ip = ip; atm_force_charge(atmarpd,skb->truesize); - skb_queue_tail(&atmarpd->sk->receive_queue,skb); + skb_queue_tail(&atmarpd->sk->sk_receive_queue, skb); wake_up(&atmarpd->sleep); return 0; } @@ -435,7 +435,7 @@ memcpy(here,llc_oui,sizeof(llc_oui)); ((u16 *) here)[3] = skb->protocol; } - atomic_add(skb->truesize,&vcc->sk->wmem_alloc); + atomic_add(skb->truesize, &vcc->sk->sk_wmem_alloc); ATM_SKB(skb)->atm_options = vcc->atm_options; entry->vccs->last_use = jiffies; DPRINTK("atm_skb(%p)->vcc(%p)->dev(%p)\n",skb,vcc,vcc->dev); @@ -493,7 +493,7 @@ vcc->push = clip_push; vcc->pop = clip_pop; skb_queue_head_init(©); - skb_migrate(&vcc->sk->receive_queue,©); + skb_migrate(&vcc->sk->sk_receive_queue, ©); /* re-process everything received between connection setup and MKIP */ while ((skb = skb_dequeue(©))) if (!clip_devs) { @@ -699,10 +699,10 @@ barrier(); unregister_inetaddr_notifier(&clip_inet_notifier); unregister_netdevice_notifier(&clip_dev_notifier); - if (skb_peek(&vcc->sk->receive_queue)) + if (skb_peek(&vcc->sk->sk_receive_queue)) printk(KERN_ERR "atmarpd_close: closing with requests " "pending\n"); - skb_queue_purge(&vcc->sk->receive_queue); + skb_queue_purge(&vcc->sk->sk_receive_queue); DPRINTK("(done)\n"); module_put(THIS_MODULE); } diff -Nru a/net/atm/common.c b/net/atm/common.c --- a/net/atm/common.c Mon Jun 9 23:16:20 2003 +++ b/net/atm/common.c Mon Jun 9 23:16:20 2003 @@ -32,21 +32,61 @@ #include <linux/atmlec.h> #include "lec.h" #include "lec_arpc.h" -struct atm_lane_ops atm_lane_ops; -#endif -#ifdef CONFIG_ATM_LANE_MODULE +struct atm_lane_ops *atm_lane_ops; +static DECLARE_MUTEX(atm_lane_ops_mutex); + +void atm_lane_ops_set(struct atm_lane_ops *hook) +{ + down(&atm_lane_ops_mutex); + atm_lane_ops = hook; + up(&atm_lane_ops_mutex); +} + +int try_atm_lane_ops(void) +{ + down(&atm_lane_ops_mutex); + if (atm_lane_ops && try_module_get(atm_lane_ops->owner)) { + up(&atm_lane_ops_mutex); + return 1; + } + up(&atm_lane_ops_mutex); + return 0; +} + +#if defined(CONFIG_ATM_LANE_MODULE) || defined(CONFIG_ATM_MPOA_MODULE) EXPORT_SYMBOL(atm_lane_ops); +EXPORT_SYMBOL(try_atm_lane_ops); +EXPORT_SYMBOL(atm_lane_ops_set); +#endif #endif #if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE) #include <linux/atmmpc.h> #include "mpc.h" -struct atm_mpoa_ops atm_mpoa_ops; -#endif +struct atm_mpoa_ops *atm_mpoa_ops; +static DECLARE_MUTEX(atm_mpoa_ops_mutex); + +void atm_mpoa_ops_set(struct atm_mpoa_ops *hook) +{ + down(&atm_mpoa_ops_mutex); + atm_mpoa_ops = hook; + up(&atm_mpoa_ops_mutex); +} + +int try_atm_mpoa_ops(void) +{ + down(&atm_mpoa_ops_mutex); + if (atm_mpoa_ops && try_module_get(atm_mpoa_ops->owner)) { + up(&atm_mpoa_ops_mutex); + return 1; + } + up(&atm_mpoa_ops_mutex); + return 0; +} #ifdef CONFIG_ATM_MPOA_MODULE EXPORT_SYMBOL(atm_mpoa_ops); -#ifndef CONFIG_ATM_LANE_MODULE -EXPORT_SYMBOL(atm_lane_ops); +EXPORT_SYMBOL(try_atm_mpoa_ops); +EXPORT_SYMBOL(atm_mpoa_ops_set); #endif #endif @@ -121,14 +161,16 @@ { struct sk_buff *skb; - if (atomic_read(&vcc->sk->wmem_alloc) && !atm_may_send(vcc,size)) { + if (atomic_read(&vcc->sk->sk_wmem_alloc) && !atm_may_send(vcc, size)) { DPRINTK("Sorry: wmem_alloc = %d, size = %d, sndbuf = %d\n", - atomic_read(&vcc->sk->wmem_alloc),size,vcc->sk->sndbuf); + atomic_read(&vcc->sk->sk_wmem_alloc), size, + vcc->sk->sk_sndbuf); return NULL; } while (!(skb = alloc_skb(size,GFP_KERNEL))) schedule(); - DPRINTK("AlTx %d += %d\n",atomic_read(&vcc->sk->wmem_alloc),skb->truesize); - atomic_add(skb->truesize, &vcc->sk->wmem_alloc); + DPRINTK("AlTx %d += %d\n", atomic_read(&vcc->sk->sk_wmem_alloc), + skb->truesize); + atomic_add(skb->truesize, &vcc->sk->sk_wmem_alloc); return skb; } @@ -148,15 +190,15 @@ memset(&vcc->local,0,sizeof(struct sockaddr_atmsvc)); memset(&vcc->remote,0,sizeof(struct sockaddr_atmsvc)); vcc->qos.txtp.max_sdu = 1 << 16; /* for meta VCs */ - atomic_set(&vcc->sk->wmem_alloc,0); - atomic_set(&vcc->sk->rmem_alloc,0); + atomic_set(&vcc->sk->sk_wmem_alloc, 0); + atomic_set(&vcc->sk->sk_rmem_alloc, 0); vcc->push = NULL; vcc->pop = NULL; vcc->push_oam = NULL; vcc->vpi = vcc->vci = 0; /* no VCI/VPI yet */ vcc->atm_options = vcc->aal_options = 0; init_waitqueue_head(&vcc->sleep); - sk->sleep = &vcc->sleep; + sk->sk_sleep = &vcc->sleep; sock->sk = sk; return 0; } @@ -171,17 +213,17 @@ if (vcc->dev) { if (vcc->dev->ops->close) vcc->dev->ops->close(vcc); if (vcc->push) vcc->push(vcc,NULL); /* atmarpd has no push */ - while ((skb = skb_dequeue(&vcc->sk->receive_queue))) { + while ((skb = skb_dequeue(&vcc->sk->sk_receive_queue))) { atm_return(vcc,skb->truesize); kfree_skb(skb); } module_put(vcc->dev->ops->owner); atm_dev_release(vcc->dev); - if (atomic_read(&vcc->sk->rmem_alloc)) + if (atomic_read(&vcc->sk->sk_rmem_alloc)) printk(KERN_WARNING "atm_release_vcc: strange ... " "rmem_alloc == %d after closing\n", - atomic_read(&vcc->sk->rmem_alloc)); + atomic_read(&vcc->sk->sk_rmem_alloc)); bind_vcc(vcc,NULL); } @@ -391,7 +433,7 @@ add_wait_queue(&vcc->sleep,&wait); set_current_state(TASK_INTERRUPTIBLE); error = 1; /* <= 0 is error */ - while (!(skb = skb_dequeue(&vcc->sk->receive_queue))) { + while (!(skb = skb_dequeue(&vcc->sk->sk_receive_queue))) { if (test_bit(ATM_VF_RELEASED,&vcc->flags) || test_bit(ATM_VF_CLOSE,&vcc->flags)) { error = vcc->reply; @@ -422,7 +464,8 @@ if (vcc->dev->ops->feedback) vcc->dev->ops->feedback(vcc,skb,(unsigned long) skb->data, (unsigned long) buff,eff_len); - DPRINTK("RcvM %d -= %d\n",atomic_read(&vcc->sk->rmem_alloc),skb->truesize); + DPRINTK("RcvM %d -= %d\n", atomic_read(&vcc->sk->sk_rmem_alloc), + skb->truesize); atm_return(vcc,skb->truesize); error = copy_to_user(buff,skb->data,eff_len) ? -EFAULT : 0; kfree_skb(skb); @@ -501,14 +544,15 @@ vcc = ATM_SD(sock); poll_wait(file,&vcc->sleep,wait); mask = 0; - if (skb_peek(&vcc->sk->receive_queue)) + if (skb_peek(&vcc->sk->sk_receive_queue)) mask |= POLLIN | POLLRDNORM; if (test_bit(ATM_VF_RELEASED,&vcc->flags) || test_bit(ATM_VF_CLOSE,&vcc->flags)) mask |= POLLHUP; if (sock->state != SS_CONNECTING) { if (vcc->qos.txtp.traffic_class != ATM_NONE && - vcc->qos.txtp.max_sdu+atomic_read(&vcc->sk->wmem_alloc) <= vcc->sk->sndbuf) + vcc->qos.txtp.max_sdu + + atomic_read(&vcc->sk->sk_wmem_alloc) <= vcc->sk->sk_sndbuf) mask |= POLLOUT | POLLWRNORM; } else if (vcc->reply != WAITING) { @@ -573,8 +617,8 @@ ret_val = -EINVAL; goto done; } - ret_val = put_user(vcc->sk->sndbuf- - atomic_read(&vcc->sk->wmem_alloc), + ret_val = put_user(vcc->sk->sk_sndbuf - + atomic_read(&vcc->sk->sk_wmem_alloc), (int *) arg) ? -EFAULT : 0; goto done; case SIOCINQ: @@ -585,7 +629,7 @@ ret_val = -EINVAL; goto done; } - skb = skb_peek(&vcc->sk->receive_queue); + skb = skb_peek(&vcc->sk->sk_receive_queue); ret_val = put_user(skb ? skb->len : 0,(int *) arg) ? -EFAULT : 0; goto done; @@ -628,11 +672,11 @@ kfree(tmp_buf); goto done; case SIOCGSTAMP: /* borrowed from IP */ - if (!vcc->sk->stamp.tv_sec) { + if (!vcc->sk->sk_stamp.tv_sec) { ret_val = -ENOENT; goto done; } - ret_val = copy_to_user((void *) arg, &vcc->sk->stamp, + ret_val = copy_to_user((void *)arg, &vcc->sk->sk_stamp, sizeof(struct timeval)) ? -EFAULT : 0; goto done; case ATM_SETSC: @@ -728,27 +772,40 @@ ret_val = -EPERM; goto done; } - if (atm_lane_ops.lecd_attach == NULL) - atm_lane_init(); - if (atm_lane_ops.lecd_attach == NULL) { /* try again */ +#if defined(CONFIG_ATM_LANE_MODULE) + if (!atm_lane_ops) + request_module("lec"); +#endif + if (try_atm_lane_ops()) { + error = atm_lane_ops->lecd_attach(vcc, (int) arg); + module_put(atm_lane_ops->owner); + if (error >= 0) + sock->state = SS_CONNECTED; + ret_val = error; + } else ret_val = -ENOSYS; - goto done; - } - error = atm_lane_ops.lecd_attach(vcc, (int)arg); - if (error >= 0) sock->state = SS_CONNECTED; - ret_val = error; goto done; case ATMLEC_MCAST: - if (!capable(CAP_NET_ADMIN)) + if (!capable(CAP_NET_ADMIN)) { ret_val = -EPERM; - else - ret_val = atm_lane_ops.mcast_attach(vcc, (int)arg); + goto done; + } + if (try_atm_lane_ops()) { + ret_val = atm_lane_ops->mcast_attach(vcc, (int) arg); + module_put(atm_lane_ops->owner); + } else + ret_val = -ENOSYS; goto done; case ATMLEC_DATA: - if (!capable(CAP_NET_ADMIN)) + if (!capable(CAP_NET_ADMIN)) { ret_val = -EPERM; - else - ret_val = atm_lane_ops.vcc_attach(vcc, (void*)arg); + goto done; + } + if (try_atm_lane_ops()) { + ret_val = atm_lane_ops->vcc_attach(vcc, (void *) arg); + module_put(atm_lane_ops->owner); + } else + ret_val = -ENOSYS; goto done; #endif #if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE) @@ -757,21 +814,29 @@ ret_val = -EPERM; goto done; } - if (atm_mpoa_ops.mpoad_attach == NULL) - atm_mpoa_init(); - if (atm_mpoa_ops.mpoad_attach == NULL) { /* try again */ +#if defined(CONFIG_ATM_MPOA_MODULE) + if (!atm_mpoa_ops) + request_module("mpoa"); +#endif + if (try_atm_mpoa_ops()) { + error = atm_mpoa_ops->mpoad_attach(vcc, (int) arg); + module_put(atm_mpoa_ops->owner); + if (error >= 0) + sock->state = SS_CONNECTED; + ret_val = error; + } else ret_val = -ENOSYS; - goto done; - } - error = atm_mpoa_ops.mpoad_attach(vcc, (int)arg); - if (error >= 0) sock->state = SS_CONNECTED; - ret_val = error; goto done; case ATMMPC_DATA: - if (!capable(CAP_NET_ADMIN)) + if (!capable(CAP_NET_ADMIN)) { ret_val = -EPERM; - else - ret_val = atm_mpoa_ops.vcc_attach(vcc, arg); + goto done; + } + if (try_atm_mpoa_ops()) { + ret_val = atm_mpoa_ops->vcc_attach(vcc, arg); + module_put(atm_mpoa_ops->owner); + } else + ret_val = -ENOSYS; goto done; #endif #if defined(CONFIG_ATM_TCP) || defined(CONFIG_ATM_TCP_MODULE) @@ -1017,7 +1082,7 @@ if (!error) error = adjust_tp(&qos->rxtp,qos->aal); if (error) return error; if (!vcc->dev->ops->change_qos) return -EOPNOTSUPP; - if (vcc->sk->family == AF_ATMPVC) + if (vcc->sk->sk_family == AF_ATMPVC) return vcc->dev->ops->change_qos(vcc,qos,ATM_MF_SET); return svc_change_qos(vcc,qos); } @@ -1155,40 +1220,6 @@ } -/* - * lane_mpoa_init.c: A couple of helper functions - * to make modular LANE and MPOA client easier to implement - */ - -/* - * This is how it goes: - * - * if xxxx is not compiled as module, call atm_xxxx_init_ops() - * from here - * else call atm_mpoa_init_ops() from init_module() within - * the kernel when xxxx module is loaded - * - * In either case function pointers in struct atm_xxxx_ops - * are initialized to their correct values. Either they - * point to functions in the module or in the kernel - */ - -extern struct atm_mpoa_ops atm_mpoa_ops; /* in common.c */ -extern struct atm_lane_ops atm_lane_ops; /* in common.c */ - -#if defined(CONFIG_ATM_MPOA) || defined(CONFIG_ATM_MPOA_MODULE) -void atm_mpoa_init(void) -{ -#ifndef CONFIG_ATM_MPOA_MODULE /* not module */ - atm_mpoa_init_ops(&atm_mpoa_ops); -#else - request_module("mpoa"); -#endif - - return; -} -#endif - #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br, @@ -1199,18 +1230,8 @@ EXPORT_SYMBOL(br_fdb_put_hook); #endif /* defined(CONFIG_ATM_LANE_MODULE) || defined(CONFIG_BRIDGE_MODULE) */ #endif /* defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) */ +#endif /* defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) */ -void atm_lane_init(void) -{ -#ifndef CONFIG_ATM_LANE_MODULE /* not module */ - atm_lane_init_ops(&atm_lane_ops); -#else - request_module("lec"); -#endif - - return; -} -#endif static int __init atm_init(void) { diff -Nru a/net/atm/lec.c b/net/atm/lec.c --- a/net/atm/lec.c Mon Jun 9 23:16:14 2003 +++ b/net/atm/lec.c Mon Jun 9 23:16:14 2003 @@ -56,8 +56,6 @@ #define DPRINTK(format,args...) #endif -static spinlock_t lec_arp_spinlock = SPIN_LOCK_UNLOCKED; - #define DUMP_PACKETS 0 /* 0 = None, * 1 = 30 first bytes * 2 = Whole packet @@ -71,9 +69,9 @@ static int lec_close(struct net_device *dev); static struct net_device_stats *lec_get_stats(struct net_device *dev); static void lec_init(struct net_device *dev); -static __inline__ struct lec_arp_table* lec_arp_find(struct lec_priv *priv, +static inline struct lec_arp_table* lec_arp_find(struct lec_priv *priv, unsigned char *mac_addr); -static __inline__ int lec_arp_remove(struct lec_arp_table **lec_arp_tables, +static inline int lec_arp_remove(struct lec_priv *priv, struct lec_arp_table *to_remove); /* LANE2 functions */ static void lane2_associate_ind (struct net_device *dev, u8 *mac_address, @@ -95,8 +93,18 @@ static struct net_device *dev_lec[MAX_LEC_ITF]; /* This will be called from proc.c via function pointer */ -struct net_device **get_dev_lec (void) { - return &dev_lec[0]; +struct net_device *get_dev_lec(int itf) +{ + struct net_device *dev; + + if (itf >= MAX_LEC_ITF) + return NULL; + rtnl_lock(); + dev = dev_lec[itf]; + if (dev) + dev_hold(dev); + rtnl_unlock(); + return dev; } #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) @@ -125,7 +133,7 @@ priv = (struct lec_priv *)dev->priv; atm_force_charge(priv->lecd, skb2->truesize); - skb_queue_tail(&priv->lecd->sk->receive_queue, skb2); + skb_queue_tail(&priv->lecd->sk->sk_receive_queue, skb2); wake_up(&priv->lecd->sleep); } @@ -202,7 +210,7 @@ lec_send(struct atm_vcc *vcc, struct sk_buff *skb, struct lec_priv *priv) { if (atm_may_send(vcc, skb->len)) { - atomic_add(skb->truesize, &vcc->sk->wmem_alloc); + atomic_add(skb->truesize, &vcc->sk->sk_wmem_alloc); ATM_SKB(skb)->vcc = vcc; ATM_SKB(skb)->atm_options = vcc->atm_options; priv->stats.tx_packets++; @@ -398,7 +406,7 @@ int i; char *tmp; /* FIXME */ - atomic_sub(skb->truesize, &vcc->sk->wmem_alloc); + atomic_sub(skb->truesize, &vcc->sk->sk_wmem_alloc); mesg = (struct atmlec_msg *)skb->data; tmp = skb->data; tmp += sizeof(struct atmlec_msg); @@ -426,7 +434,7 @@ break; case l_narp_req: /* LANE2: see 7.1.35 in the lane2 spec */ entry = lec_arp_find(priv, mesg->content.normal.mac_addr); - lec_arp_remove(priv->lec_arp_tables, entry); + lec_arp_remove(priv, entry); if (mesg->content.normal.no_source_le_narp) break; @@ -504,7 +512,7 @@ skb2->len = sizeof(struct atmlec_msg); memcpy(skb2->data, mesg, sizeof(struct atmlec_msg)); atm_force_charge(priv->lecd, skb2->truesize); - skb_queue_tail(&priv->lecd->sk->receive_queue, skb2); + skb_queue_tail(&priv->lecd->sk->sk_receive_queue, skb2); wake_up(&priv->lecd->sleep); } if (f != NULL) br_fdb_put_hook(f); @@ -533,16 +541,16 @@ netif_stop_queue(dev); lec_arp_destroy(priv); - if (skb_peek(&vcc->sk->receive_queue)) + if (skb_peek(&vcc->sk->sk_receive_queue)) printk("%s lec_atm_close: closing with messages pending\n", dev->name); - while ((skb = skb_dequeue(&vcc->sk->receive_queue))) { + while ((skb = skb_dequeue(&vcc->sk->sk_receive_queue))) { atm_return(vcc, skb->truesize); dev_kfree_skb(skb); } printk("%s: Shut down!\n", dev->name); - MOD_DEC_USE_COUNT; + module_put(THIS_MODULE); } static struct atmdev_ops lecdev_ops = { @@ -589,13 +597,13 @@ memcpy(&mesg->content.normal.atm_addr, atm_addr, ATM_ESA_LEN); atm_force_charge(priv->lecd, skb->truesize); - skb_queue_tail(&priv->lecd->sk->receive_queue, skb); + skb_queue_tail(&priv->lecd->sk->sk_receive_queue, skb); wake_up(&priv->lecd->sleep); if (data != NULL) { DPRINTK("lec: about to send %d bytes of data\n", data->len); atm_force_charge(priv->lecd, data->truesize); - skb_queue_tail(&priv->lecd->sk->receive_queue, data); + skb_queue_tail(&priv->lecd->sk->sk_receive_queue, data); wake_up(&priv->lecd->sleep); } @@ -677,7 +685,7 @@ #endif /* DUMP_PACKETS > 0 */ if (memcmp(skb->data, lec_ctrl_magic, 4) ==0) { /* Control frame, to daemon*/ DPRINTK("%s: To daemon\n",dev->name); - skb_queue_tail(&vcc->sk->receive_queue, skb); + skb_queue_tail(&vcc->sk->sk_receive_queue, skb); wake_up(&vcc->sleep); } else { /* Data frame, queue to protocol handlers */ unsigned char *dst; @@ -823,51 +831,37 @@ if (dev_lec[i]->flags & IFF_UP) { netif_start_queue(dev_lec[i]); } - MOD_INC_USE_COUNT; + __module_get(THIS_MODULE); return i; } -void atm_lane_init_ops(struct atm_lane_ops *ops) +static struct atm_lane_ops __atm_lane_ops = { - ops->lecd_attach = lecd_attach; - ops->mcast_attach = lec_mcast_attach; - ops->vcc_attach = lec_vcc_attach; - ops->get_lecs = get_dev_lec; - - printk("lec.c: " __DATE__ " " __TIME__ " initialized\n"); - - return; -} + .lecd_attach = lecd_attach, + .mcast_attach = lec_mcast_attach, + .vcc_attach = lec_vcc_attach, + .get_lec = get_dev_lec, + .owner = THIS_MODULE +}; static int __init lane_module_init(void) { - extern struct atm_lane_ops atm_lane_ops; - - atm_lane_init_ops(&atm_lane_ops); - + atm_lane_ops_set(&__atm_lane_ops); + printk("lec.c: " __DATE__ " " __TIME__ " initialized\n"); return 0; } static void __exit lane_module_cleanup(void) { int i; - extern struct atm_lane_ops atm_lane_ops; struct lec_priv *priv; - atm_lane_ops.lecd_attach = NULL; - atm_lane_ops.mcast_attach = NULL; - atm_lane_ops.vcc_attach = NULL; - atm_lane_ops.get_lecs = NULL; + atm_lane_ops_set(NULL); for (i = 0; i < MAX_LEC_ITF; i++) { if (dev_lec[i] != NULL) { priv = (struct lec_priv *)dev_lec[i]->priv; -#if defined(CONFIG_TR) - if (priv->is_trdev) - unregister_trdev(dev_lec[i]); - else -#endif - unregister_netdev(dev_lec[i]); + unregister_netdev(dev_lec[i]); kfree(dev_lec[i]); dev_lec[i] = NULL; } @@ -1067,6 +1061,7 @@ for (i=0;i<LEC_ARP_TABLE_SIZE;i++) { priv->lec_arp_tables[i] = NULL; } + spin_lock_init(&priv->lec_arp_lock); init_timer(&priv->lec_arp_timer); priv->lec_arp_timer.expires = jiffies+LEC_ARP_REFRESH_INTERVAL; priv->lec_arp_timer.data = (unsigned long)priv; @@ -1103,21 +1098,20 @@ * Insert entry to lec_arp_table * LANE2: Add to the end of the list to satisfy 8.1.13 */ -static __inline__ void -lec_arp_add(struct lec_arp_table **lec_arp_tables, - struct lec_arp_table *to_add) +static inline void +lec_arp_add(struct lec_priv *priv, struct lec_arp_table *to_add) { unsigned long flags; unsigned short place; struct lec_arp_table *tmp; - spin_lock_irqsave(&lec_arp_spinlock, flags); + spin_lock_irqsave(&priv->lec_arp_lock, flags); place = HASH(to_add->mac_addr[ETH_ALEN-1]); - tmp = lec_arp_tables[place]; + tmp = priv->lec_arp_tables[place]; to_add->next = NULL; if (tmp == NULL) - lec_arp_tables[place] = to_add; + priv->lec_arp_tables[place] = to_add; else { /* add to the end */ while (tmp->next) @@ -1125,7 +1119,7 @@ tmp->next = to_add; } - spin_unlock_irqrestore(&lec_arp_spinlock, flags); + spin_unlock_irqrestore(&priv->lec_arp_lock, flags); DPRINTK("LEC_ARP: Added entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", 0xff&to_add->mac_addr[0], 0xff&to_add->mac_addr[1], @@ -1136,8 +1130,8 @@ /* * Remove entry from lec_arp_table */ -static __inline__ int -lec_arp_remove(struct lec_arp_table **lec_arp_tables, +static inline int +lec_arp_remove(struct lec_priv *priv, struct lec_arp_table *to_remove) { unsigned long flags; @@ -1145,22 +1139,22 @@ struct lec_arp_table *tmp; int remove_vcc=1; - spin_lock_irqsave(&lec_arp_spinlock, flags); + spin_lock_irqsave(&priv->lec_arp_lock, flags); if (!to_remove) { - spin_unlock_irqrestore(&lec_arp_spinlock, flags); + spin_unlock_irqrestore(&priv->lec_arp_lock, flags); return -1; } place = HASH(to_remove->mac_addr[ETH_ALEN-1]); - tmp = lec_arp_tables[place]; + tmp = priv->lec_arp_tables[place]; if (tmp == to_remove) { - lec_arp_tables[place] = tmp->next; + priv->lec_arp_tables[place] = tmp->next; } else { while(tmp && tmp->next != to_remove) { tmp = tmp->next; } if (!tmp) {/* Entry was not found */ - spin_unlock_irqrestore(&lec_arp_spinlock, flags); + spin_unlock_irqrestore(&priv->lec_arp_lock, flags); return -1; } } @@ -1174,7 +1168,7 @@ * ESI_FLUSH_PENDING, ESI_FORWARD_DIRECT */ for(place=0;place<LEC_ARP_TABLE_SIZE;place++) { - for(tmp=lec_arp_tables[place];tmp!=NULL;tmp=tmp->next){ + for(tmp = priv->lec_arp_tables[place]; tmp != NULL; tmp = tmp->next) { if (memcmp(tmp->atm_addr, to_remove->atm_addr, ATM_ESA_LEN)==0) { remove_vcc=0; @@ -1187,7 +1181,7 @@ } skb_queue_purge(&to_remove->tx_wait); /* FIXME: good place for this? */ - spin_unlock_irqrestore(&lec_arp_spinlock, flags); + spin_unlock_irqrestore(&priv->lec_arp_lock, flags); DPRINTK("LEC_ARP: Removed entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", 0xff&to_remove->mac_addr[0], 0xff&to_remove->mac_addr[1], @@ -1383,7 +1377,7 @@ for (i=0;i<LEC_ARP_TABLE_SIZE;i++) { for(entry =priv->lec_arp_tables[i];entry != NULL; entry=next) { next = entry->next; - lec_arp_remove(priv->lec_arp_tables, entry); + lec_arp_remove(priv, entry); kfree(entry); } } @@ -1423,7 +1417,7 @@ /* * Find entry by mac_address */ -static __inline__ struct lec_arp_table* +static inline struct lec_arp_table* lec_arp_find(struct lec_priv *priv, unsigned char *mac_addr) { @@ -1561,8 +1555,6 @@ lec_arp_check_expire(unsigned long data) { struct lec_priv *priv = (struct lec_priv *)data; - struct lec_arp_table **lec_arp_tables = - (struct lec_arp_table **)priv->lec_arp_tables; struct lec_arp_table *entry, *next; unsigned long now; unsigned long time_to_check; @@ -1578,7 +1570,7 @@ lec_arp_get(priv); now = jiffies; for(i=0;i<LEC_ARP_TABLE_SIZE;i++) { - for(entry = lec_arp_tables[i];entry != NULL;) { + for(entry = priv->lec_arp_tables[i]; entry != NULL; ) { if ((entry->flags) & LEC_REMOTE_FLAG && priv->topology_change) time_to_check=priv->forward_delay_time; @@ -1594,7 +1586,7 @@ /* Remove entry */ DPRINTK("LEC:Entry timed out\n"); next = entry->next; - lec_arp_remove(lec_arp_tables, entry); + lec_arp_remove(priv, entry); kfree(entry); entry = next; } else { @@ -1687,7 +1679,7 @@ if (!entry) { return priv->mcast_vcc; } - lec_arp_add(priv->lec_arp_tables, entry); + lec_arp_add(priv, entry); /* We want arp-request(s) to be sent */ entry->packets_flooded =1; entry->status = ESI_ARP_PENDING; @@ -1720,7 +1712,7 @@ if (!memcmp(atm_addr, entry->atm_addr, ATM_ESA_LEN) && (permanent || !(entry->flags & LEC_PERMANENT_FLAG))) { - lec_arp_remove(priv->lec_arp_tables, entry); + lec_arp_remove(priv, entry); kfree(entry); } lec_arp_put(priv); @@ -1786,7 +1778,7 @@ entry->status = ESI_FORWARD_DIRECT; memcpy(entry->mac_addr, mac_addr, ETH_ALEN); entry->last_used = jiffies; - lec_arp_add(priv->lec_arp_tables, entry); + lec_arp_add(priv, entry); } if (remoteflag) entry->flags|=LEC_REMOTE_FLAG; @@ -1806,7 +1798,7 @@ return; } entry->status = ESI_UNKNOWN; - lec_arp_add(priv->lec_arp_tables, entry); + lec_arp_add(priv, entry); /* Temporary, changes before end of function */ } memcpy(entry->atm_addr, atm_addr, ATM_ESA_LEN); @@ -2057,7 +2049,7 @@ to_add->old_push = vcc->push; vcc->push = lec_push; priv->mcast_vcc = vcc; - lec_arp_add(priv->lec_arp_tables, to_add); + lec_arp_add(priv, to_add); lec_arp_put(priv); return 0; } @@ -2075,7 +2067,7 @@ for(entry = priv->lec_arp_tables[i];entry; entry=next) { next = entry->next; if (vcc == entry->vcc) { - lec_arp_remove(priv->lec_arp_tables,entry); + lec_arp_remove(priv, entry); kfree(entry); if (priv->mcast_vcc == vcc) { priv->mcast_vcc = NULL; @@ -2155,23 +2147,23 @@ lec_arp_get(priv); entry = priv->lec_arp_empty_ones; if (vcc == entry->vcc) { - spin_lock_irqsave(&lec_arp_spinlock, flags); + spin_lock_irqsave(&priv->lec_arp_lock, flags); del_timer(&entry->timer); memcpy(entry->mac_addr, src, ETH_ALEN); entry->status = ESI_FORWARD_DIRECT; entry->last_used = jiffies; priv->lec_arp_empty_ones = entry->next; - spin_unlock_irqrestore(&lec_arp_spinlock, flags); + spin_unlock_irqrestore(&priv->lec_arp_lock, flags); /* We might have got an entry */ if ((prev=lec_arp_find(priv,src))) { - lec_arp_remove(priv->lec_arp_tables, prev); + lec_arp_remove(priv, prev); kfree(prev); } - lec_arp_add(priv->lec_arp_tables, entry); + lec_arp_add(priv, entry); lec_arp_put(priv); return; } - spin_lock_irqsave(&lec_arp_spinlock, flags); + spin_lock_irqsave(&priv->lec_arp_lock, flags); prev = entry; entry = entry->next; while (entry && entry->vcc != vcc) { @@ -2181,7 +2173,7 @@ if (!entry) { DPRINTK("LEC_ARP: Arp_check_empties: entry not found!\n"); lec_arp_put(priv); - spin_unlock_irqrestore(&lec_arp_spinlock, flags); + spin_unlock_irqrestore(&priv->lec_arp_lock, flags); return; } del_timer(&entry->timer); @@ -2189,12 +2181,12 @@ entry->status = ESI_FORWARD_DIRECT; entry->last_used = jiffies; prev->next = entry->next; - spin_unlock_irqrestore(&lec_arp_spinlock, flags); + spin_unlock_irqrestore(&priv->lec_arp_lock, flags); if ((prev = lec_arp_find(priv, src))) { - lec_arp_remove(priv->lec_arp_tables,prev); + lec_arp_remove(priv, prev); kfree(prev); } - lec_arp_add(priv->lec_arp_tables,entry); + lec_arp_add(priv, entry); lec_arp_put(priv); } MODULE_LICENSE("GPL"); diff -Nru a/net/atm/lec.h b/net/atm/lec.h --- a/net/atm/lec.h Mon Jun 9 23:16:09 2003 +++ b/net/atm/lec.h Mon Jun 9 23:16:09 2003 @@ -64,7 +64,8 @@ int (*lecd_attach)(struct atm_vcc *vcc, int arg); int (*mcast_attach)(struct atm_vcc *vcc, int arg); int (*vcc_attach)(struct atm_vcc *vcc, void *arg); - struct net_device **(*get_lecs)(void); + struct net_device * (*get_lec)(int itf); + struct module *owner; }; /* @@ -102,6 +103,7 @@ collects all those VCCs. LANEv1 client has only one item in this list. These entries are not aged out. */ atomic_t lec_arp_users; + spinlock_t lec_arp_lock; struct atm_vcc *mcast_vcc; /* Default Multicast Send VCC */ struct atm_vcc *lecd; struct timer_list lec_arp_timer; @@ -148,14 +150,16 @@ int lecd_attach(struct atm_vcc *vcc, int arg); int lec_vcc_attach(struct atm_vcc *vcc, void *arg); int lec_mcast_attach(struct atm_vcc *vcc, int arg); -struct net_device **get_dev_lec(void); +struct net_device *get_dev_lec(int itf); int make_lec(struct atm_vcc *vcc); int send_to_lecd(struct lec_priv *priv, atmlec_msg_type type, unsigned char *mac_addr, unsigned char *atm_addr, struct sk_buff *data); void lec_push(struct atm_vcc *vcc, struct sk_buff *skb); -void atm_lane_init(void); -void atm_lane_init_ops(struct atm_lane_ops *ops); +extern struct atm_lane_ops *atm_lane_ops; +void atm_lane_ops_set(struct atm_lane_ops *hook); +int try_atm_lane_ops(void); + #endif /* _LEC_H_ */ diff -Nru a/net/atm/mpc.c b/net/atm/mpc.c --- a/net/atm/mpc.c Mon Jun 9 23:16:17 2003 +++ b/net/atm/mpc.c Mon Jun 9 23:16:17 2003 @@ -251,12 +251,13 @@ static struct net_device *find_lec_by_itfnum(int itf) { - extern struct atm_lane_ops atm_lane_ops; /* in common.c */ - - if (atm_lane_ops.get_lecs == NULL) + struct net_device *dev; + if (!try_atm_lane_ops()) return NULL; - return atm_lane_ops.get_lecs()[itf]; /* FIXME: something better */ + dev = atm_lane_ops->get_lec(itf); + module_put(atm_lane_ops->owner); + return dev; } static struct mpoa_client *alloc_mpc(void) @@ -522,7 +523,7 @@ memcpy(skb->data, &llc_snap_mpoa_data, sizeof(struct llc_snap_hdr)); } - atomic_add(skb->truesize, &entry->shortcut->sk->wmem_alloc); + atomic_add(skb->truesize, &entry->shortcut->sk->sk_wmem_alloc); ATM_SKB(skb)->atm_options = entry->shortcut->atm_options; entry->shortcut->send(entry->shortcut, skb); entry->packets_fwded++; @@ -666,7 +667,8 @@ skb->dev = dev; if (memcmp(skb->data, &llc_snap_mpoa_ctrl, sizeof(struct llc_snap_hdr)) == 0) { dprintk("mpoa: (%s) mpc_push: control packet arrived\n", dev->name); - skb_queue_tail(&vcc->sk->receive_queue, skb); /* Pass control packets to daemon */ + /* Pass control packets to daemon */ + skb_queue_tail(&vcc->sk->sk_receive_queue, skb); wake_up(&vcc->sleep); return; } @@ -779,9 +781,10 @@ if (mpc->dev) { /* check if the lec is LANE2 capable */ priv = (struct lec_priv *)mpc->dev->priv; - if (priv->lane_version < 2) + if (priv->lane_version < 2) { + dev_put(mpc->dev); mpc->dev = NULL; - else + } else priv->lane2_ops->associate_indicator = lane2_assoc_ind; } @@ -802,7 +805,7 @@ send_set_mps_ctrl_addr(mpc->mps_ctrl_addr, mpc); } - MOD_INC_USE_COUNT; + __module_get(THIS_MODULE); return arg; } @@ -839,19 +842,20 @@ struct lec_priv *priv = (struct lec_priv *)mpc->dev->priv; priv->lane2_ops->associate_indicator = NULL; stop_mpc(mpc); + dev_put(mpc->dev); } mpc->in_ops->destroy_cache(mpc); mpc->eg_ops->destroy_cache(mpc); - while ( (skb = skb_dequeue(&vcc->sk->receive_queue)) ){ + while ((skb = skb_dequeue(&vcc->sk->sk_receive_queue))) { atm_return(vcc, skb->truesize); kfree_skb(skb); } printk("mpoa: (%s) going down\n", (mpc->dev) ? mpc->dev->name : "<unknown>"); - MOD_DEC_USE_COUNT; + module_put(THIS_MODULE); return; } @@ -864,7 +868,7 @@ struct mpoa_client *mpc = find_mpc_by_vcc(vcc); struct k_message *mesg = (struct k_message*)skb->data; - atomic_sub(skb->truesize, &vcc->sk->wmem_alloc); + atomic_sub(skb->truesize, &vcc->sk->sk_wmem_alloc); if (mpc == NULL) { printk("mpoa: msg_from_mpoad: no mpc found\n"); @@ -941,7 +945,7 @@ skb_put(skb, sizeof(struct k_message)); memcpy(skb->data, mesg, sizeof(struct k_message)); atm_force_charge(mpc->mpoad_vcc, skb->truesize); - skb_queue_tail(&mpc->mpoad_vcc->sk->receive_queue, skb); + skb_queue_tail(&mpc->mpoad_vcc->sk->sk_receive_queue, skb); wake_up(&mpc->mpoad_vcc->sleep); return 0; @@ -975,6 +979,7 @@ } mpc->dev_num = priv->itfnum; mpc->dev = dev; + dev_hold(dev); dprintk("mpoa: (%s) was initialized\n", dev->name); break; case NETDEV_UNREGISTER: @@ -984,6 +989,7 @@ break; dprintk("mpoa: device (%s) was deallocated\n", dev->name); stop_mpc(mpc); + dev_put(mpc->dev); mpc->dev = NULL; break; case NETDEV_UP: @@ -1218,7 +1224,7 @@ purge_msg->content.eg_info = entry->ctrl_info; atm_force_charge(vcc, skb->truesize); - skb_queue_tail(&vcc->sk->receive_queue, skb); + skb_queue_tail(&vcc->sk->sk_receive_queue, skb); wake_up(&vcc->sleep); dprintk("mpoa: purge_egress_shortcut: exiting:\n"); @@ -1393,13 +1399,18 @@ return; } -void atm_mpoa_init_ops(struct atm_mpoa_ops *ops) +static struct atm_mpoa_ops __atm_mpoa_ops = { + .mpoad_attach = atm_mpoa_mpoad_attach, + .vcc_attach = atm_mpoa_vcc_attach, + .owner = THIS_MODULE +}; + +static __init int atm_mpoa_init(void) { - ops->mpoad_attach = atm_mpoa_mpoad_attach; - ops->vcc_attach = atm_mpoa_vcc_attach; + atm_mpoa_ops_set(&__atm_mpoa_ops); #ifdef CONFIG_PROC_FS - if(mpc_proc_init() != 0) + if (mpc_proc_init() != 0) printk(KERN_INFO "mpoa: failed to initialize /proc/mpoa\n"); else printk(KERN_INFO "mpoa: /proc/mpoa initialized\n"); @@ -1407,22 +1418,11 @@ printk("mpc.c: " __DATE__ " " __TIME__ " initialized\n"); - return; -} - -#ifdef MODULE -int init_module(void) -{ - extern struct atm_mpoa_ops atm_mpoa_ops; - - atm_mpoa_init_ops(&atm_mpoa_ops); - return 0; } -void cleanup_module(void) +void __exit atm_mpoa_cleanup(void) { - extern struct atm_mpoa_ops atm_mpoa_ops; struct mpoa_client *mpc, *tmp; struct atm_mpoa_qos *qos, *nextqos; struct lec_priv *priv; @@ -1433,8 +1433,7 @@ del_timer(&mpc_timer); unregister_netdevice_notifier(&mpoa_notifier); - atm_mpoa_ops.mpoad_attach = NULL; - atm_mpoa_ops.vcc_attach = NULL; + atm_mpoa_ops_set(NULL); mpc = mpcs; mpcs = NULL; @@ -1469,5 +1468,8 @@ return; } -#endif /* MODULE */ + +module_init(atm_mpoa_init); +module_exit(atm_mpoa_cleanup); + MODULE_LICENSE("GPL"); diff -Nru a/net/atm/mpc.h b/net/atm/mpc.h --- a/net/atm/mpc.h Mon Jun 9 23:16:07 2003 +++ b/net/atm/mpc.h Mon Jun 9 23:16:07 2003 @@ -48,11 +48,13 @@ struct atm_mpoa_ops { int (*mpoad_attach)(struct atm_vcc *vcc, int arg); /* attach mpoa daemon */ int (*vcc_attach)(struct atm_vcc *vcc, long arg); /* attach shortcut vcc */ + struct module *owner; }; /* Boot/module initialization function */ -void atm_mpoa_init(void); -void atm_mpoa_init_ops(struct atm_mpoa_ops *ops); +extern struct atm_mpoa_ops *atm_mpoa_ops; +int try_atm_mpoa_ops(void); +void atm_mpoa_ops_set(struct atm_mpoa_ops *hook); /* MPOA QoS operations */ struct atm_mpoa_qos *atm_mpoa_add_qos(uint32_t dst_ip, struct atm_qos *qos); diff -Nru a/net/atm/pppoatm.c b/net/atm/pppoatm.c --- a/net/atm/pppoatm.c Mon Jun 9 23:16:15 2003 +++ b/net/atm/pppoatm.c Mon Jun 9 23:16:15 2003 @@ -231,7 +231,7 @@ kfree_skb(skb); return 1; } - atomic_add(skb->truesize, &ATM_SKB(skb)->vcc->sk->wmem_alloc); + atomic_add(skb->truesize, &ATM_SKB(skb)->vcc->sk->sk_wmem_alloc); ATM_SKB(skb)->atm_options = ATM_SKB(skb)->vcc->atm_options; DPRINTK("(unit %d): atm_skb(%p)->vcc(%p)->dev(%p)\n", pvcc->chan.unit, skb, ATM_SKB(skb)->vcc, diff -Nru a/net/atm/proc.c b/net/atm/proc.c --- a/net/atm/proc.c Mon Jun 9 23:16:09 2003 +++ b/net/atm/proc.c Mon Jun 9 23:16:09 2003 @@ -47,7 +47,6 @@ #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) #include "lec.h" #include "lec_arpc.h" -extern struct atm_lane_ops atm_lane_ops; /* in common.c */ #endif static ssize_t proc_dev_atm_read(struct file *file,char *buf,size_t count, @@ -137,7 +136,7 @@ unsigned char *ip; int svc,off,ip_len; - svc = !clip_vcc || clip_vcc->vcc->sk->family == AF_ATMSVC; + svc = !clip_vcc || clip_vcc->vcc->sk->sk_family == AF_ATMSVC; off = sprintf(buf,"%-6s%-4s%-4s%5ld ",dev->name,svc ? "SVC" : "PVC", !clip_vcc || clip_vcc->encap ? "LLC" : "NULL", (jiffies-(clip_vcc ? clip_vcc->last_use : entry->neigh->used))/ @@ -214,7 +213,7 @@ if (!vcc->dev) here += sprintf(here,"Unassigned "); else here += sprintf(here,"%3d %3d %5d ",vcc->dev->number,vcc->vpi, vcc->vci); - switch (vcc->sk->family) { + switch (vcc->sk->sk_family) { case AF_ATMPVC: here += sprintf(here,"PVC"); break; @@ -222,12 +221,12 @@ here += sprintf(here,"SVC"); break; default: - here += sprintf(here,"%3d",vcc->sk->family); + here += sprintf(here, "%3d", vcc->sk->sk_family); } here += sprintf(here," %04lx %5d %7d/%7d %7d/%7d\n",vcc->flags, vcc->reply, - atomic_read(&vcc->sk->wmem_alloc),vcc->sk->sndbuf, - atomic_read(&vcc->sk->rmem_alloc),vcc->sk->rcvbuf); + atomic_read(&vcc->sk->sk_wmem_alloc), vcc->sk->sk_sndbuf, + atomic_read(&vcc->sk->sk_rmem_alloc), vcc->sk->sk_rcvbuf); } @@ -355,7 +354,8 @@ dev = list_entry(p, struct atm_dev, dev_list); spin_lock_irqsave(&dev->lock, flags); for (vcc = dev->vccs; vcc; vcc = vcc->next) - if (vcc->sk->family == PF_ATMPVC && vcc->dev && !left--) { + if (vcc->sk->sk_family == PF_ATMPVC && + vcc->dev && !left--) { pvc_info(vcc,buf,clip_info); spin_unlock_irqrestore(&dev->lock, flags); spin_unlock(&atm_dev_lock); @@ -424,7 +424,7 @@ dev = list_entry(p, struct atm_dev, dev_list); spin_lock_irqsave(&dev->lock, flags); for (vcc = dev->vccs; vcc; vcc = vcc->next) - if (vcc->sk->family == PF_ATMSVC && !left--) { + if (vcc->sk->sk_family == PF_ATMSVC && !left--) { svc_info(vcc,buf); spin_unlock_irqrestore(&dev->lock, flags); spin_unlock(&atm_dev_lock); @@ -481,57 +481,72 @@ #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE) static int atm_lec_info(loff_t pos,char *buf) { + unsigned long flags; struct lec_priv *priv; struct lec_arp_table *entry; int i, count, d, e; - struct net_device **dev_lec; + struct net_device *dev; if (!pos) { return sprintf(buf,"Itf MAC ATM destination" " Status Flags " "VPI/VCI Recv VPI/VCI\n"); } - if (atm_lane_ops.get_lecs == NULL) + if (!try_atm_lane_ops()) return 0; /* the lane module is not there yet */ - else - dev_lec = atm_lane_ops.get_lecs(); count = pos; - for(d=0;d<MAX_LEC_ITF;d++) { - if (!dev_lec[d] || !(priv = - (struct lec_priv *) dev_lec[d]->priv)) continue; - for(i=0;i<LEC_ARP_TABLE_SIZE;i++) { - entry = priv->lec_arp_tables[i]; - for(;entry;entry=entry->next) { - if (--count) continue; - e=sprintf(buf,"%s ", - dev_lec[d]->name); - lec_info(entry,buf+e); + for(d = 0; d < MAX_LEC_ITF; d++) { + dev = atm_lane_ops->get_lec(d); + if (!dev || !(priv = (struct lec_priv *) dev->priv)) + continue; + spin_lock_irqsave(&priv->lec_arp_lock, flags); + for(i = 0; i < LEC_ARP_TABLE_SIZE; i++) { + for(entry = priv->lec_arp_tables[i]; entry; entry = entry->next) { + if (--count) + continue; + e = sprintf(buf,"%s ", dev->name); + lec_info(entry, buf+e); + spin_unlock_irqrestore(&priv->lec_arp_lock, flags); + dev_put(dev); + module_put(atm_lane_ops->owner); return strlen(buf); } } - for(entry=priv->lec_arp_empty_ones; entry; - entry=entry->next) { - if (--count) continue; - e=sprintf(buf,"%s ",dev_lec[d]->name); + for(entry = priv->lec_arp_empty_ones; entry; entry = entry->next) { + if (--count) + continue; + e = sprintf(buf,"%s ", dev->name); lec_info(entry, buf+e); + spin_unlock_irqrestore(&priv->lec_arp_lock, flags); + dev_put(dev); + module_put(atm_lane_ops->owner); return strlen(buf); } - for(entry=priv->lec_no_forward; entry; - entry=entry->next) { - if (--count) continue; - e=sprintf(buf,"%s ",dev_lec[d]->name); + for(entry = priv->lec_no_forward; entry; entry=entry->next) { + if (--count) + continue; + e = sprintf(buf,"%s ", dev->name); lec_info(entry, buf+e); + spin_unlock_irqrestore(&priv->lec_arp_lock, flags); + dev_put(dev); + module_put(atm_lane_ops->owner); return strlen(buf); } - for(entry=priv->mcast_fwds; entry; - entry=entry->next) { - if (--count) continue; - e=sprintf(buf,"%s ",dev_lec[d]->name); + for(entry = priv->mcast_fwds; entry; entry = entry->next) { + if (--count) + continue; + e = sprintf(buf,"%s ", dev->name); lec_info(entry, buf+e); + spin_unlock_irqrestore(&priv->lec_arp_lock, flags); + dev_put(dev); + module_put(atm_lane_ops->owner); return strlen(buf); } + spin_unlock_irqrestore(&priv->lec_arp_lock, flags); + dev_put(dev); } + module_put(atm_lane_ops->owner); return 0; } #endif diff -Nru a/net/atm/raw.c b/net/atm/raw.c --- a/net/atm/raw.c Mon Jun 9 23:16:18 2003 +++ b/net/atm/raw.c Mon Jun 9 23:16:18 2003 @@ -28,7 +28,7 @@ void atm_push_raw(struct atm_vcc *vcc,struct sk_buff *skb) { if (skb) { - skb_queue_tail(&vcc->sk->receive_queue,skb); + skb_queue_tail(&vcc->sk->sk_receive_queue, skb); wake_up(&vcc->sleep); } } @@ -36,8 +36,9 @@ static void atm_pop_raw(struct atm_vcc *vcc,struct sk_buff *skb) { - DPRINTK("APopR (%d) %d -= %d\n",vcc->vci,vcc->sk->wmem_alloc,skb->truesize); - atomic_sub(skb->truesize, &vcc->sk->wmem_alloc); + DPRINTK("APopR (%d) %d -= %d\n", vcc->vci, vcc->sk->sk_wmem_alloc, + skb->truesize); + atomic_sub(skb->truesize, &vcc->sk->sk_wmem_alloc); dev_kfree_skb_any(skb); wake_up(&vcc->sleep); } diff -Nru a/net/atm/signaling.c b/net/atm/signaling.c --- a/net/atm/signaling.c Mon Jun 9 23:16:16 2003 +++ b/net/atm/signaling.c Mon Jun 9 23:16:16 2003 @@ -60,7 +60,7 @@ } #endif atm_force_charge(sigd,skb->truesize); - skb_queue_tail(&sigd->sk->receive_queue,skb); + skb_queue_tail(&sigd->sk->sk_receive_queue,skb); wake_up(&sigd->sleep); } @@ -97,7 +97,7 @@ struct atm_vcc *session_vcc; msg = (struct atmsvc_msg *) skb->data; - atomic_sub(skb->truesize, &vcc->sk->wmem_alloc); + atomic_sub(skb->truesize, &vcc->sk->sk_wmem_alloc); DPRINTK("sigd_send %d (0x%lx)\n",(int) msg->type, (unsigned long) msg->vcc); vcc = *(struct atm_vcc **) &msg->vcc; @@ -128,12 +128,13 @@ case as_indicate: vcc = *(struct atm_vcc **) &msg->listen_vcc; DPRINTK("as_indicate!!!\n"); - if (vcc->sk->ack_backlog == vcc->sk->max_ack_backlog) { + if (vcc->sk->sk_ack_backlog == + vcc->sk->sk_max_ack_backlog) { sigd_enq(0,as_reject,vcc,NULL,NULL); return 0; } - vcc->sk->ack_backlog++; - skb_queue_tail(&vcc->sk->receive_queue,skb); + vcc->sk->sk_ack_backlog++; + skb_queue_tail(&vcc->sk->sk_receive_queue, skb); if (vcc->callback) { DPRINTK("waking vcc->sleep 0x%p\n", &vcc->sleep); @@ -197,7 +198,7 @@ static void purge_vccs(struct atm_vcc *vcc) { while (vcc) { - if (vcc->sk->family == PF_ATMSVC && + if (vcc->sk->sk_family == PF_ATMSVC && !test_bit(ATM_VF_META,&vcc->flags)) { set_bit(ATM_VF_RELEASED,&vcc->flags); vcc->reply = -EUNATCH; @@ -216,9 +217,9 @@ DPRINTK("sigd_close\n"); sigd = NULL; - if (skb_peek(&vcc->sk->receive_queue)) + if (skb_peek(&vcc->sk->sk_receive_queue)) printk(KERN_ERR "sigd_close: closing with requests pending\n"); - skb_queue_purge(&vcc->sk->receive_queue); + skb_queue_purge(&vcc->sk->sk_receive_queue); spin_lock(&atm_dev_lock); list_for_each(p, &atm_devs) { diff -Nru a/net/atm/svc.c b/net/atm/svc.c --- a/net/atm/svc.c Mon Jun 9 23:16:15 2003 +++ b/net/atm/svc.c Mon Jun 9 23:16:15 2003 @@ -74,7 +74,7 @@ } /* beware - socket is still in use by atmsigd until the last as_indicate has been answered */ - while ((skb = skb_dequeue(&vcc->sk->receive_queue))) { + while ((skb = skb_dequeue(&vcc->sk->sk_receive_queue))) { DPRINTK("LISTEN REL\n"); sigd_enq2(NULL,as_reject,vcc,NULL,NULL,&vcc->qos,0); dev_kfree_skb(skb); @@ -253,7 +253,8 @@ remove_wait_queue(&vcc->sleep,&wait); if (!sigd) return -EUNATCH; set_bit(ATM_VF_LISTEN,&vcc->flags); - vcc->sk->max_ack_backlog = backlog > 0 ? backlog : ATM_BACKLOG_DEFAULT; + vcc->sk->sk_max_ack_backlog = backlog > 0 ? backlog : + ATM_BACKLOG_DEFAULT; return vcc->reply; } @@ -277,7 +278,8 @@ DECLARE_WAITQUEUE(wait,current); add_wait_queue(&old_vcc->sleep,&wait); - while (!(skb = skb_dequeue(&old_vcc->sk->receive_queue)) && sigd) { + while (!(skb = skb_dequeue(&old_vcc->sk->sk_receive_queue)) && + sigd) { if (test_bit(ATM_VF_RELEASED,&old_vcc->flags)) break; if (test_bit(ATM_VF_CLOSE,&old_vcc->flags)) { error = old_vcc->reply; @@ -306,7 +308,7 @@ error = atm_connect(newsock,msg->pvc.sap_addr.itf, msg->pvc.sap_addr.vpi,msg->pvc.sap_addr.vci); dev_kfree_skb(skb); - old_vcc->sk->ack_backlog--; + old_vcc->sk->sk_ack_backlog--; if (error) { sigd_enq2(NULL,as_reject,old_vcc,NULL,NULL, &old_vcc->qos,error); diff -Nru a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c --- a/net/ax25/af_ax25.c Mon Jun 9 23:16:18 2003 +++ b/net/ax25/af_ax25.c Mon Jun 9 23:16:18 2003 @@ -174,7 +174,8 @@ for (s = ax25_list; s != NULL; s = s->next) { if ((s->iamdigi && !digi) || (!s->iamdigi && digi)) continue; - if (s->sk != NULL && ax25cmp(&s->source_addr, addr) == 0 && s->sk->type == type && s->sk->state == TCP_LISTEN) { + if (s->sk && !ax25cmp(&s->source_addr, addr) && + s->sk->sk_type == type && s->sk->sk_state == TCP_LISTEN) { /* If device is null we match any device */ if (s->ax25_dev == NULL || s->ax25_dev->dev == dev) { spin_unlock_bh(&ax25_list_lock); @@ -199,7 +200,9 @@ spin_lock_bh(&ax25_list_lock); for (s = ax25_list; s != NULL; s = s->next) { - if (s->sk != NULL && ax25cmp(&s->source_addr, my_addr) == 0 && ax25cmp(&s->dest_addr, dest_addr) == 0 && s->sk->type == type) { + if (s->sk && !ax25cmp(&s->source_addr, my_addr) && + !ax25cmp(&s->dest_addr, dest_addr) && + s->sk->sk_type == type) { sk = s->sk; /* XXX Sleeps with spinlock held, use refcounts instead. XXX */ lock_sock(sk); @@ -223,7 +226,7 @@ spin_lock_bh(&ax25_list_lock); for (s = ax25_list; s != NULL; s = s->next) { - if (s->sk != NULL && s->sk->type != SOCK_SEQPACKET) + if (s->sk && s->sk->sk_type != SOCK_SEQPACKET) continue; if (s->ax25_dev == NULL) continue; @@ -258,7 +261,7 @@ spin_lock_bh(&ax25_list_lock); for (s = ax25_list; s != NULL; s = s->next) { if (s->sk != NULL && ax25cmp(&s->source_addr, addr) == 0 && - s->sk->type == SOCK_RAW) { + s->sk->sk_type == SOCK_RAW) { sk = s->sk; lock_sock(sk); break; @@ -274,9 +277,9 @@ struct sk_buff *copy; while (sk != NULL) { - if (sk->type == SOCK_RAW && - sk->protocol == proto && - atomic_read(&sk->rmem_alloc) <= sk->rcvbuf) { + if (sk->sk_type == SOCK_RAW && + sk->sk_protocol == proto && + atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) { if ((copy = skb_clone(skb, GFP_ATOMIC)) == NULL) return; @@ -284,7 +287,7 @@ kfree_skb(copy); } - sk = sk->next; + sk = sk->sk_next; } } @@ -322,13 +325,13 @@ ax25_clear_queues(ax25); /* Flush the queues */ if (ax25->sk != NULL) { - while ((skb = skb_dequeue(&ax25->sk->receive_queue)) != NULL) { + while ((skb = skb_dequeue(&ax25->sk->sk_receive_queue)) != NULL) { if (skb->sk != ax25->sk) { /* A pending connection */ ax25_cb *sax25 = ax25_sk(skb->sk); /* Queue the unaccepted socket for death */ - __set_bit(SOCK_DEAD, &skb->sk->flags); + sock_set_flag(skb->sk, SOCK_DEAD); ax25_start_heartbeat(sax25); sax25->state = AX25_STATE_0; @@ -339,8 +342,8 @@ } if (ax25->sk != NULL) { - if (atomic_read(&ax25->sk->wmem_alloc) != 0 || - atomic_read(&ax25->sk->rmem_alloc) != 0) { + if (atomic_read(&ax25->sk->sk_wmem_alloc) || + atomic_read(&ax25->sk->sk_rmem_alloc)) { /* Defer: outstanding buffers */ init_timer(&ax25->timer); ax25->timer.expires = jiffies + 10 * HZ; @@ -650,8 +653,9 @@ break; } - if (sk->type == SOCK_SEQPACKET && - (sock->state != SS_UNCONNECTED || sk->state == TCP_LISTEN)) { + if (sk->sk_type == SOCK_SEQPACKET && + (sock->state != SS_UNCONNECTED || + sk->sk_state == TCP_LISTEN)) { res = -EADDRNOTAVAIL; break; } @@ -771,9 +775,9 @@ int res = 0; lock_sock(sk); - if (sk->type == SOCK_SEQPACKET && sk->state != TCP_LISTEN) { - sk->max_ack_backlog = backlog; - sk->state = TCP_LISTEN; + if (sk->sk_type == SOCK_SEQPACKET && sk->sk_state != TCP_LISTEN) { + sk->sk_max_ack_backlog = backlog; + sk->sk_state = TCP_LISTEN; goto out; } res = -EOPNOTSUPP; @@ -846,9 +850,9 @@ sock_init_data(sock, sk); sk_set_owner(sk, THIS_MODULE); - sk->destruct = ax25_free_sock; + sk->sk_destruct = ax25_free_sock; sock->ops = &ax25_proto_ops; - sk->protocol = protocol; + sk->sk_protocol = protocol; ax25->sk = sk; @@ -868,7 +872,7 @@ return NULL; } - switch (osk->type) { + switch (osk->sk_type) { case SOCK_DGRAM: break; case SOCK_SEQPACKET: @@ -882,17 +886,17 @@ sock_init_data(NULL, sk); sk_set_owner(sk, THIS_MODULE); - sk->destruct = ax25_free_sock; - sk->type = osk->type; - sk->socket = osk->socket; - sk->priority = osk->priority; - sk->protocol = osk->protocol; - sk->rcvbuf = osk->rcvbuf; - sk->sndbuf = osk->sndbuf; - sk->debug = osk->debug; - sk->state = TCP_ESTABLISHED; - sk->sleep = osk->sleep; - sk->zapped = osk->zapped; + sk->sk_destruct = ax25_free_sock; + sk->sk_type = osk->sk_type; + sk->sk_socket = osk->sk_socket; + sk->sk_priority = osk->sk_priority; + sk->sk_protocol = osk->sk_protocol; + sk->sk_rcvbuf = osk->sk_rcvbuf; + sk->sk_sndbuf = osk->sk_sndbuf; + sk->sk_debug = osk->sk_debug; + sk->sk_state = TCP_ESTABLISHED; + sk->sk_sleep = osk->sk_sleep; + sk->sk_zapped = osk->sk_zapped; oax25 = ax25_sk(osk); @@ -938,7 +942,7 @@ lock_sock(sk); ax25 = ax25_sk(sk); - if (sk->type == SOCK_SEQPACKET) { + if (sk->sk_type == SOCK_SEQPACKET) { switch (ax25->state) { case AX25_STATE_0: ax25_disconnect(ax25, 0); @@ -978,26 +982,26 @@ ax25_calculate_t1(ax25); ax25_start_t1timer(ax25); ax25->state = AX25_STATE_2; - sk->state = TCP_CLOSE; - sk->shutdown |= SEND_SHUTDOWN; - sk->state_change(sk); - __set_bit(SOCK_DEAD, &sk->flags); - __set_bit(SOCK_DESTROY, &sk->flags); + sk->sk_state = TCP_CLOSE; + sk->sk_shutdown |= SEND_SHUTDOWN; + sk->sk_state_change(sk); + sock_set_flag(sk, SOCK_DEAD); + sock_set_flag(sk, SOCK_DESTROY); break; default: break; } } else { - sk->state = TCP_CLOSE; - sk->shutdown |= SEND_SHUTDOWN; - sk->state_change(sk); - __set_bit(SOCK_DEAD, &sk->flags); + sk->sk_state = TCP_CLOSE; + sk->sk_shutdown |= SEND_SHUTDOWN; + sk->sk_state_change(sk); + sock_set_flag(sk, SOCK_DEAD); ax25_destroy_socket(ax25); } sock->sk = NULL; - sk->socket = NULL; /* Not used, but we should do this */ + sk->sk_socket = NULL; /* Not used, but we should do this */ release_sock(sk); return 0; @@ -1041,7 +1045,7 @@ lock_sock(sk); ax25 = ax25_sk(sk); - if (sk->zapped == 0) { + if (!sk->sk_zapped) { err = -EINVAL; goto out; } @@ -1075,7 +1079,7 @@ done: ax25_insert_socket(ax25); - sk->zapped = 0; + sk->sk_zapped = 0; out: release_sock(sk); @@ -1122,7 +1126,7 @@ /* deal with restarts */ if (sock->state == SS_CONNECTING) { - switch (sk->state) { + switch (sk->sk_state) { case TCP_SYN_SENT: /* still trying */ err = -EINPROGRESS; goto out; @@ -1138,12 +1142,12 @@ } } - if (sk->state == TCP_ESTABLISHED && sk->type == SOCK_SEQPACKET) { + if (sk->sk_state == TCP_ESTABLISHED && sk->sk_type == SOCK_SEQPACKET) { err = -EISCONN; /* No reconnect on a seqpacket socket */ goto out; } - sk->state = TCP_CLOSE; + sk->sk_state = TCP_CLOSE; sock->state = SS_UNCONNECTED; if (ax25->digipeat != NULL) { @@ -1188,7 +1192,7 @@ * the socket is already bound, check to see if the device has * been filled in, error if it hasn't. */ - if (sk->zapped) { + if (sk->sk_zapped) { /* check if we can remove this feature. It is broken. */ printk(KERN_WARNING "ax25_connect(): %s uses autobind, please contact jreuter@yaina.de\n", current->comm); @@ -1204,7 +1208,7 @@ } } - if (sk->type == SOCK_SEQPACKET && + if (sk->sk_type == SOCK_SEQPACKET && ax25_find_cb(&ax25->source_addr, &fsa->fsa_ax25.sax25_call, digi, ax25->ax25_dev->dev)) { if (digi != NULL) @@ -1217,15 +1221,15 @@ ax25->digipeat = digi; /* First the easy one */ - if (sk->type != SOCK_SEQPACKET) { + if (sk->sk_type != SOCK_SEQPACKET) { sock->state = SS_CONNECTED; - sk->state = TCP_ESTABLISHED; + sk->sk_state = TCP_ESTABLISHED; goto out; } /* Move to connecting socket, ax.25 lapb WAIT_UA.. */ sock->state = SS_CONNECTING; - sk->state = TCP_SYN_SENT; + sk->sk_state = TCP_SYN_SENT; switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) { case AX25_PROTO_STD_SIMPLEX: @@ -1250,18 +1254,18 @@ ax25_start_heartbeat(ax25); /* Now the loop */ - if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) { + if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) { err = -EINPROGRESS; goto out; } - if (sk->state == TCP_SYN_SENT) { + if (sk->sk_state == TCP_SYN_SENT) { struct task_struct *tsk = current; DECLARE_WAITQUEUE(wait, tsk); - add_wait_queue(sk->sleep, &wait); + add_wait_queue(sk->sk_sleep, &wait); for (;;) { - if (sk->state != TCP_SYN_SENT) + if (sk->sk_state != TCP_SYN_SENT) break; set_current_state(TASK_INTERRUPTIBLE); release_sock(sk); @@ -1273,10 +1277,10 @@ return -ERESTARTSYS; } current->state = TASK_RUNNING; - remove_wait_queue(sk->sleep, &wait); + remove_wait_queue(sk->sk_sleep, &wait); } - if (sk->state != TCP_ESTABLISHED) { + if (sk->sk_state != TCP_ESTABLISHED) { /* Not in ABM, not in WAIT_UA -> failed */ sock->state = SS_UNCONNECTED; err = sock_error(sk); /* Always set at this point */ @@ -1308,12 +1312,12 @@ return -EINVAL; lock_sock(sk); - if (sk->type != SOCK_SEQPACKET) { + if (sk->sk_type != SOCK_SEQPACKET) { err = -EOPNOTSUPP; goto out; } - if (sk->state != TCP_LISTEN) { + if (sk->sk_state != TCP_LISTEN) { err = -EINVAL; goto out; } @@ -1322,9 +1326,9 @@ * The read queue this time is holding sockets ready to use * hooked into the SABM we saved */ - add_wait_queue(sk->sleep, &wait); + add_wait_queue(sk->sk_sleep, &wait); for (;;) { - skb = skb_dequeue(&sk->receive_queue); + skb = skb_dequeue(&sk->sk_receive_queue); if (skb) break; @@ -1340,16 +1344,16 @@ return -ERESTARTSYS; } current->state = TASK_RUNNING; - remove_wait_queue(sk->sleep, &wait); + remove_wait_queue(sk->sk_sleep, &wait); - newsk = skb->sk; - newsk->pair = NULL; - newsk->socket = newsock; - newsk->sleep = &newsock->wait; + newsk = skb->sk; + newsk->sk_pair = NULL; + newsk->sk_socket = newsock; + newsk->sk_sleep = &newsock->wait; /* Now attach up the new socket */ kfree_skb(skb); - sk->ack_backlog--; + sk->sk_ack_backlog--; newsock->sk = newsk; newsock->state = SS_CONNECTED; @@ -1372,7 +1376,7 @@ ax25 = ax25_sk(sk); if (peer != 0) { - if (sk->state != TCP_ESTABLISHED) { + if (sk->sk_state != TCP_ESTABLISHED) { err = -ENOTCONN; goto out; } @@ -1426,12 +1430,12 @@ lock_sock(sk); ax25 = ax25_sk(sk); - if (sk->zapped) { + if (sk->sk_zapped) { err = -EADDRNOTAVAIL; goto out; } - if (sk->shutdown & SEND_SHUTDOWN) { + if (sk->sk_shutdown & SEND_SHUTDOWN) { send_sig(SIGPIPE, current, 0); err = -EPIPE; goto out; @@ -1486,7 +1490,8 @@ } sax = *usax; - if (sk->type == SOCK_SEQPACKET && ax25cmp(&ax25->dest_addr, &sax.sax25_call) != 0) { + if (sk->sk_type == SOCK_SEQPACKET && + ax25cmp(&ax25->dest_addr, &sax.sax25_call)) { err = -EISCONN; goto out; } @@ -1500,7 +1505,7 @@ * it has become closed (not started closed) and is VC * we ought to SIGPIPE, EPIPE */ - if (sk->state != TCP_ESTABLISHED) { + if (sk->sk_state != TCP_ESTABLISHED) { err = -ENOTCONN; goto out; } @@ -1532,14 +1537,14 @@ /* Add the PID if one is not supplied by the user in the skb */ if (!ax25->pidincl) { asmptr = skb_push(skb, 1); - *asmptr = sk->protocol; + *asmptr = sk->sk_protocol; } SOCK_DEBUG(sk, "AX.25: Transmitting buffer\n"); - if (sk->type == SOCK_SEQPACKET) { + if (sk->sk_type == SOCK_SEQPACKET) { /* Connected mode sockets go via the LAPB machine */ - if (sk->state != TCP_ESTABLISHED) { + if (sk->sk_state != TCP_ESTABLISHED) { kfree_skb(skb); err = -ENOTCONN; goto out; @@ -1598,7 +1603,7 @@ * This works for seqpacket too. The receiver has ordered the * queue for us! We do one quick check first though */ - if (sk->type == SOCK_SEQPACKET && sk->state != TCP_ESTABLISHED) { + if (sk->sk_type == SOCK_SEQPACKET && sk->sk_state != TCP_ESTABLISHED) { err = -ENOTCONN; goto out; } @@ -1670,7 +1675,7 @@ switch (cmd) { case TIOCOUTQ: { long amount; - amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); + amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); if (amount < 0) amount = 0; res = put_user(amount, (int *)arg); @@ -1681,7 +1686,7 @@ struct sk_buff *skb; long amount = 0L; /* These two are safe on a single CPU system as only user tasks fiddle here */ - if ((skb = skb_peek(&sk->receive_queue)) != NULL) + if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) amount = skb->len; res = put_user(amount, (int *)arg); break; @@ -1689,11 +1694,12 @@ case SIOCGSTAMP: if (sk != NULL) { - if (sk->stamp.tv_sec == 0) { + if (!sk->sk_stamp.tv_sec) { res = -ENOENT; break; } - res = copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0; + res = copy_to_user((void *)arg, &sk->sk_stamp, + sizeof(struct timeval)) ? -EFAULT : 0; break; } res = -EINVAL; @@ -1764,8 +1770,8 @@ ax25_info.idletimer = ax25_display_timer(&ax25->idletimer) / (60 * HZ); ax25_info.n2count = ax25->n2count; ax25_info.state = ax25->state; - ax25_info.rcv_q = atomic_read(&sk->rmem_alloc); - ax25_info.snd_q = atomic_read(&sk->wmem_alloc); + ax25_info.rcv_q = atomic_read(&sk->sk_rmem_alloc); + ax25_info.snd_q = atomic_read(&sk->sk_wmem_alloc); ax25_info.vs = ax25->vs; ax25_info.vr = ax25->vr; ax25_info.va = ax25->va; @@ -1878,9 +1884,9 @@ if (ax25->sk != NULL) { len += sprintf(buffer + len, " %d %d %ld\n", - atomic_read(&ax25->sk->wmem_alloc), - atomic_read(&ax25->sk->rmem_alloc), - ax25->sk->socket != NULL ? SOCK_INODE(ax25->sk->socket)->i_ino : 0L); + atomic_read(&ax25->sk->sk_wmem_alloc), + atomic_read(&ax25->sk->sk_rmem_alloc), + ax25->sk->sk_socket != NULL ? SOCK_INODE(ax25->sk->sk_socket)->i_ino : 0L); } else { len += sprintf(buffer + len, " * * *\n"); } diff -Nru a/net/ax25/ax25_dev.c b/net/ax25/ax25_dev.c --- a/net/ax25/ax25_dev.c Mon Jun 9 23:16:07 2003 +++ b/net/ax25/ax25_dev.c Mon Jun 9 23:16:07 2003 @@ -34,21 +34,6 @@ ax25_dev *ax25_dev_list; spinlock_t ax25_dev_lock = SPIN_LOCK_UNLOCKED; -ax25_dev *ax25_dev_ax25dev(struct net_device *dev) -{ - ax25_dev *ax25_dev, *res = NULL; - - spin_lock_bh(&ax25_dev_lock); - for (ax25_dev = ax25_dev_list; ax25_dev != NULL; ax25_dev = ax25_dev->next) - if (ax25_dev->dev == dev) { - res = ax25_dev; - break; - } - spin_unlock_bh(&ax25_dev_lock); - - return res; -} - ax25_dev *ax25_addr_ax25dev(ax25_address *addr) { ax25_dev *ax25_dev, *res = NULL; @@ -80,6 +65,7 @@ memset(ax25_dev, 0x00, sizeof(*ax25_dev)); + dev->ax25_ptr = ax25_dev; ax25_dev->dev = dev; ax25_dev->forward = NULL; @@ -152,6 +138,7 @@ s = s->next; } spin_unlock_bh(&ax25_dev_lock); + dev->ax25_ptr = NULL; ax25_register_sysctl(); } diff -Nru a/net/ax25/ax25_ds_in.c b/net/ax25/ax25_ds_in.c --- a/net/ax25/ax25_ds_in.c Mon Jun 9 23:16:15 2003 +++ b/net/ax25/ax25_ds_in.c Mon Jun 9 23:16:15 2003 @@ -65,10 +65,13 @@ ax25->state = AX25_STATE_3; ax25->n2count = 0; if (ax25->sk != NULL) { - ax25->sk->state = TCP_ESTABLISHED; - /* For WAIT_SABM connections we will produce an accept ready socket here */ - if (!test_bit(SOCK_DEAD, &ax25->sk->flags)) - ax25->sk->state_change(ax25->sk); + ax25->sk->sk_state = TCP_ESTABLISHED; + /* + * For WAIT_SABM connections we will produce an accept + * ready socket here + */ + if (!sock_flag(ax25->sk, SOCK_DEAD)) + ax25->sk->sk_state_change(ax25->sk); } ax25_dama_on(ax25); diff -Nru a/net/ax25/ax25_ds_timer.c b/net/ax25/ax25_ds_timer.c --- a/net/ax25/ax25_ds_timer.c Mon Jun 9 23:16:18 2003 +++ b/net/ax25/ax25_ds_timer.c Mon Jun 9 23:16:18 2003 @@ -103,7 +103,9 @@ case AX25_STATE_0: /* Magic here: If we listen() and a new link dies before it is accepted() it isn't 'dead' so doesn't get removed. */ - if (ax25->sk == NULL || test_bit(SOCK_DESTROY, &ax25->sk->flags) || (ax25->sk->state == TCP_LISTEN && test_bit(SOCK_DEAD, &ax25->sk->flags))) { + if (!ax25->sk || sock_flag(ax25->sk, SOCK_DESTROY) || + (ax25->sk->sk_state == TCP_LISTEN && + sock_flag(ax25->sk, SOCK_DEAD))) { ax25_destroy_socket(ax25); return; } @@ -114,7 +116,8 @@ * Check the state of the receive buffer. */ if (ax25->sk != NULL) { - if (atomic_read(&ax25->sk->rmem_alloc) < (ax25->sk->rcvbuf / 2) && + if (atomic_read(&ax25->sk->sk_rmem_alloc) < + (ax25->sk->sk_rcvbuf / 2) && (ax25->condition & AX25_COND_OWN_RX_BUSY)) { ax25->condition &= ~AX25_COND_OWN_RX_BUSY; ax25->condition &= ~AX25_COND_ACK_PENDING; @@ -154,12 +157,13 @@ ax25_stop_t3timer(ax25); if (ax25->sk != NULL) { - ax25->sk->state = TCP_CLOSE; - ax25->sk->err = 0; - ax25->sk->shutdown |= SEND_SHUTDOWN; - if (!test_bit(SOCK_DEAD, &ax25->sk->flags)) - ax25->sk->state_change(ax25->sk); - __set_bit(SOCK_DEAD, &ax25->sk->flags); + ax25->sk->sk_state = TCP_CLOSE; + ax25->sk->sk_err = 0; + ax25->sk->sk_shutdown |= SEND_SHUTDOWN; + if (!sock_flag(ax25->sk, SOCK_DEAD)) { + ax25->sk->sk_state_change(ax25->sk); + sock_set_flag(ax25->sk, SOCK_DEAD); + } } } diff -Nru a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c --- a/net/ax25/ax25_in.c Mon Jun 9 23:16:08 2003 +++ b/net/ax25/ax25_in.c Mon Jun 9 23:16:08 2003 @@ -147,7 +147,8 @@ } if (ax25->sk != NULL && ax25->ax25_dev->values[AX25_VALUES_CONMODE] == 2) { - if ((!ax25->pidincl && ax25->sk->protocol == pid) || ax25->pidincl) { + if ((!ax25->pidincl && ax25->sk->sk_protocol == pid) || + ax25->pidincl) { if (sock_queue_rcv_skb(ax25->sk, skb) == 0) queued = 1; else @@ -277,7 +278,8 @@ /* Now find a suitable dgram socket */ sk = ax25_get_socket(&dest, &src, SOCK_DGRAM); if (sk != NULL) { - if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf) { + if (atomic_read(&sk->sk_rmem_alloc) >= + sk->sk_rcvbuf) { kfree_skb(skb); } else { /* @@ -355,7 +357,7 @@ sk = ax25_find_listener(next_digi, 1, dev, SOCK_SEQPACKET); if (sk != NULL) { - if (sk->ack_backlog == sk->max_ack_backlog || + if (sk->sk_ack_backlog == sk->sk_max_ack_backlog || (make = ax25_make_new(sk, ax25_dev)) == NULL) { if (mine) ax25_return_dm(dev, &src, &dest, &dp); @@ -366,12 +368,12 @@ ax25 = ax25_sk(make); skb_set_owner_r(skb, make); - skb_queue_head(&sk->receive_queue, skb); + skb_queue_head(&sk->sk_receive_queue, skb); - make->state = TCP_ESTABLISHED; - make->pair = sk; + make->sk_state = TCP_ESTABLISHED; + make->sk_pair = sk; - sk->ack_backlog++; + sk->sk_ack_backlog++; } else { if (!mine) { kfree_skb(skb); @@ -433,12 +435,11 @@ ax25_start_t3timer(ax25); ax25_start_idletimer(ax25); - if (sk != NULL) { - if (!test_bit(SOCK_DEAD, &sk->flags)) - sk->data_ready(sk, skb->len); - } else { + if (sk) { + if (!sock_flag(sk, SOCK_DEAD)) + sk->sk_data_ready(sk, skb->len); + } else kfree_skb(skb); - } return 0; } diff -Nru a/net/ax25/ax25_ip.c b/net/ax25/ax25_ip.c --- a/net/ax25/ax25_ip.c Mon Jun 9 23:16:10 2003 +++ b/net/ax25/ax25_ip.c Mon Jun 9 23:16:10 2003 @@ -154,9 +154,15 @@ skb_set_owner_w(ourskb, skb->sk); kfree_skb(skb); - - src_c = *src; - dst_c = *dst; + /* dl9sau: bugfix + * after kfree_skb(), dst and src which were pointer + * to bp which is part of skb->data would not be valid + * anymore hope that after skb_pull(ourskb, ..) our + * dsc_c and src_c will not become invalid + */ + bp = ourskb->data; + dst_c = *(ax25_address *)(bp + 1); + src_c = *(ax25_address *)(bp + 8); skb_pull(ourskb, AX25_HEADER_LEN - 1); /* Keep PID */ ourskb->nh.raw = ourskb->data; diff -Nru a/net/ax25/ax25_route.c b/net/ax25/ax25_route.c --- a/net/ax25/ax25_route.c Mon Jun 9 23:16:15 2003 +++ b/net/ax25/ax25_route.c Mon Jun 9 23:16:15 2003 @@ -435,7 +435,7 @@ } if (ax25->sk != NULL) - ax25->sk->zapped = 0; + ax25->sk->sk_zapped = 0; put: ax25_put_route(ax25_rt); diff -Nru a/net/ax25/ax25_std_in.c b/net/ax25/ax25_std_in.c --- a/net/ax25/ax25_std_in.c Mon Jun 9 23:16:16 2003 +++ b/net/ax25/ax25_std_in.c Mon Jun 9 23:16:16 2003 @@ -73,10 +73,10 @@ ax25->state = AX25_STATE_3; ax25->n2count = 0; if (ax25->sk != NULL) { - ax25->sk->state = TCP_ESTABLISHED; + ax25->sk->sk_state = TCP_ESTABLISHED; /* For WAIT_SABM connections we will produce an accept ready socket here */ - if (!test_bit(SOCK_DEAD, &ax25->sk->flags)) - ax25->sk->state_change(ax25->sk); + if (!sock_flag(ax25->sk, SOCK_DEAD)) + ax25->sk->sk_state_change(ax25->sk); } } break; diff -Nru a/net/ax25/ax25_std_timer.c b/net/ax25/ax25_std_timer.c --- a/net/ax25/ax25_std_timer.c Mon Jun 9 23:16:08 2003 +++ b/net/ax25/ax25_std_timer.c Mon Jun 9 23:16:08 2003 @@ -37,7 +37,9 @@ case AX25_STATE_0: /* Magic here: If we listen() and a new link dies before it is accepted() it isn't 'dead' so doesn't get removed. */ - if (ax25->sk == NULL || test_bit(SOCK_DESTROY, &ax25->sk->flags) || (ax25->sk->state == TCP_LISTEN && test_bit(SOCK_DEAD, &ax25->sk->flags))) { + if (!ax25->sk || sock_flag(ax25->sk, SOCK_DESTROY) || + (ax25->sk->sk_state == TCP_LISTEN && + sock_flag(ax25->sk, SOCK_DEAD))) { ax25_destroy_socket(ax25); return; } @@ -49,7 +51,8 @@ * Check the state of the receive buffer. */ if (ax25->sk != NULL) { - if (atomic_read(&ax25->sk->rmem_alloc) < (ax25->sk->rcvbuf / 2) && + if (atomic_read(&ax25->sk->sk_rmem_alloc) < + (ax25->sk->sk_rcvbuf / 2) && (ax25->condition & AX25_COND_OWN_RX_BUSY)) { ax25->condition &= ~AX25_COND_OWN_RX_BUSY; ax25->condition &= ~AX25_COND_ACK_PENDING; @@ -91,12 +94,13 @@ ax25_stop_t3timer(ax25); if (ax25->sk != NULL) { - ax25->sk->state = TCP_CLOSE; - ax25->sk->err = 0; - ax25->sk->shutdown |= SEND_SHUTDOWN; - if (!test_bit(SOCK_DEAD, &ax25->sk->flags)) - ax25->sk->state_change(ax25->sk); - __set_bit(SOCK_DEAD, &ax25->sk->flags); + ax25->sk->sk_state = TCP_CLOSE; + ax25->sk->sk_err = 0; + ax25->sk->sk_shutdown |= SEND_SHUTDOWN; + if (!sock_flag(ax25->sk, SOCK_DEAD)) { + ax25->sk->sk_state_change(ax25->sk); + sock_set_flag(ax25->sk, SOCK_DEAD); + } } } diff -Nru a/net/ax25/ax25_subr.c b/net/ax25/ax25_subr.c --- a/net/ax25/ax25_subr.c Mon Jun 9 23:16:18 2003 +++ b/net/ax25/ax25_subr.c Mon Jun 9 23:16:18 2003 @@ -282,11 +282,12 @@ ax25_link_failed(ax25, reason); if (ax25->sk != NULL) { - ax25->sk->state = TCP_CLOSE; - ax25->sk->err = reason; - ax25->sk->shutdown |= SEND_SHUTDOWN; - if (!test_bit(SOCK_DEAD, &ax25->sk->flags)) - ax25->sk->state_change(ax25->sk); - __set_bit(SOCK_DEAD, &ax25->sk->flags); + ax25->sk->sk_state = TCP_CLOSE; + ax25->sk->sk_err = reason; + ax25->sk->sk_shutdown |= SEND_SHUTDOWN; + if (!sock_flag(ax25->sk, SOCK_DEAD)) { + ax25->sk->sk_state_change(ax25->sk); + sock_set_flag(ax25->sk, SOCK_DEAD); + } } } diff -Nru a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c --- a/net/bluetooth/af_bluetooth.c Mon Jun 9 23:16:08 2003 +++ b/net/bluetooth/af_bluetooth.c Mon Jun 9 23:16:08 2003 @@ -126,15 +126,15 @@ return NULL; } memset(pi, 0, pi_size); - sk->protinfo = pi; + sk->sk_protinfo = pi; } sock_init_data(sock, sk); INIT_LIST_HEAD(&bt_sk(sk)->accept_q); - sk->zapped = 0; - sk->protocol = proto; - sk->state = BT_OPEN; + sk->sk_zapped = 0; + sk->sk_protocol = proto; + sk->sk_state = BT_OPEN; return sk; } @@ -142,7 +142,7 @@ void bt_sock_link(struct bt_sock_list *l, struct sock *sk) { write_lock_bh(&l->lock); - sk->next = l->head; + sk->sk_next = l->head; l->head = sk; sock_hold(sk); write_unlock_bh(&l->lock); @@ -153,9 +153,9 @@ struct sock **skp; write_lock_bh(&l->lock); - for (skp = &l->head; *skp; skp = &((*skp)->next)) { + for (skp = &l->head; *skp; skp = &((*skp)->sk_next)) { if (*skp == sk) { - *skp = sk->next; + *skp = sk->sk_next; __sock_put(sk); break; } @@ -170,15 +170,15 @@ sock_hold(sk); list_add_tail(&bt_sk(sk)->accept_q, &bt_sk(parent)->accept_q); bt_sk(sk)->parent = parent; - parent->ack_backlog++; + parent->sk_ack_backlog++; } static void bt_accept_unlink(struct sock *sk) { - BT_DBG("sk %p state %d", sk, sk->state); + BT_DBG("sk %p state %d", sk, sk->sk_state); list_del_init(&bt_sk(sk)->accept_q); - bt_sk(sk)->parent->ack_backlog--; + bt_sk(sk)->parent->sk_ack_backlog--; bt_sk(sk)->parent = NULL; sock_put(sk); } @@ -194,13 +194,13 @@ sk = (struct sock *) list_entry(p, struct bt_sock, accept_q); lock_sock(sk); - if (sk->state == BT_CLOSED) { + if (sk->sk_state == BT_CLOSED) { release_sock(sk); bt_accept_unlink(sk); continue; } - if (sk->state == BT_CONNECTED || !newsock) { + if (sk->sk_state == BT_CONNECTED || !newsock) { bt_accept_unlink(sk); if (newsock) sock_graft(sk, newsock); @@ -226,7 +226,7 @@ return -EOPNOTSUPP; if (!(skb = skb_recv_datagram(sk, flags, noblock, &err))) { - if (sk->shutdown & RCV_SHUTDOWN) + if (sk->sk_shutdown & RCV_SHUTDOWN) return 0; return err; } @@ -254,30 +254,30 @@ BT_DBG("sock %p, sk %p", sock, sk); - poll_wait(file, sk->sleep, wait); + poll_wait(file, sk->sk_sleep, wait); mask = 0; - if (sk->err || !skb_queue_empty(&sk->error_queue)) + if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) mask |= POLLERR; - if (sk->shutdown == SHUTDOWN_MASK) + if (sk->sk_shutdown == SHUTDOWN_MASK) mask |= POLLHUP; - if (!skb_queue_empty(&sk->receive_queue) || + if (!skb_queue_empty(&sk->sk_receive_queue) || !list_empty(&bt_sk(sk)->accept_q) || - (sk->shutdown & RCV_SHUTDOWN)) + (sk->sk_shutdown & RCV_SHUTDOWN)) mask |= POLLIN | POLLRDNORM; - if (sk->state == BT_CLOSED) + if (sk->sk_state == BT_CLOSED) mask |= POLLHUP; - if (sk->state == BT_CONNECT || sk->state == BT_CONNECT2) + if (sk->sk_state == BT_CONNECT || sk->sk_state == BT_CONNECT2) return mask; if (sock_writeable(sk)) mask |= POLLOUT | POLLWRNORM | POLLWRBAND; else - set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); + set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); return mask; } @@ -290,8 +290,8 @@ BT_DBG("sk %p", sk); - add_wait_queue(sk->sleep, &wait); - while (sk->state != BT_CONNECTED) { + add_wait_queue(sk->sk_sleep, &wait); + while (sk->sk_state != BT_CONNECTED) { set_current_state(TASK_INTERRUPTIBLE); if (!timeo) { err = -EAGAIN; @@ -303,10 +303,10 @@ lock_sock(sk); err = 0; - if (sk->state == BT_CONNECTED) + if (sk->sk_state == BT_CONNECTED) break; - if (sk->err) { + if (sk->sk_err) { err = sock_error(sk); break; } @@ -317,7 +317,7 @@ } } set_current_state(TASK_RUNNING); - remove_wait_queue(sk->sleep, &wait); + remove_wait_queue(sk->sk_sleep, &wait); return err; } diff -Nru a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c --- a/net/bluetooth/bnep/core.c Mon Jun 9 23:16:15 2003 +++ b/net/bluetooth/bnep/core.c Mon Jun 9 23:16:15 2003 @@ -465,21 +465,21 @@ set_fs(KERNEL_DS); init_waitqueue_entry(&wait, current); - add_wait_queue(sk->sleep, &wait); + add_wait_queue(sk->sk_sleep, &wait); while (!atomic_read(&s->killed)) { set_current_state(TASK_INTERRUPTIBLE); // RX - while ((skb = skb_dequeue(&sk->receive_queue))) { + while ((skb = skb_dequeue(&sk->sk_receive_queue))) { skb_orphan(skb); bnep_rx_frame(s, skb); } - if (sk->state != BT_CONNECTED) + if (sk->sk_state != BT_CONNECTED) break; // TX - while ((skb = skb_dequeue(&sk->write_queue))) + while ((skb = skb_dequeue(&sk->sk_write_queue))) if (bnep_tx_frame(s, skb)) break; netif_wake_queue(dev); @@ -487,7 +487,7 @@ schedule(); } set_current_state(TASK_RUNNING); - remove_wait_queue(sk->sleep, &wait); + remove_wait_queue(sk->sk_sleep, &wait); /* Cleanup session */ down_write(&bnep_session_sem); @@ -609,11 +609,11 @@ if (s) { /* Wakeup user-space which is polling for socket errors. * This is temporary hack untill we have shutdown in L2CAP */ - s->sock->sk->err = EUNATCH; + s->sock->sk->sk_err = EUNATCH; /* Kill session thread */ atomic_inc(&s->killed); - wake_up_interruptible(s->sock->sk->sleep); + wake_up_interruptible(s->sock->sk->sk_sleep); } else err = -ENOENT; diff -Nru a/net/bluetooth/bnep/netdev.c b/net/bluetooth/bnep/netdev.c --- a/net/bluetooth/bnep/netdev.c Mon Jun 9 23:16:16 2003 +++ b/net/bluetooth/bnep/netdev.c Mon Jun 9 23:16:16 2003 @@ -121,8 +121,8 @@ r->len = htons(skb->len - len); } - skb_queue_tail(&sk->write_queue, skb); - wake_up_interruptible(sk->sleep); + skb_queue_tail(&sk->sk_write_queue, skb); + wake_up_interruptible(sk->sk_sleep); #endif } @@ -209,13 +209,13 @@ /* * We cannot send L2CAP packets from here as we are potentially in a bh. * So we have to queue them and wake up session thread which is sleeping - * on the sk->sleep. + * on the sk->sk_sleep. */ dev->trans_start = jiffies; - skb_queue_tail(&sk->write_queue, skb); - wake_up_interruptible(sk->sleep); + skb_queue_tail(&sk->sk_write_queue, skb); + wake_up_interruptible(sk->sk_sleep); - if (skb_queue_len(&sk->write_queue) >= BNEP_TX_QUEUE_LEN) { + if (skb_queue_len(&sk->sk_write_queue) >= BNEP_TX_QUEUE_LEN) { BT_DBG("tx queue is full"); /* Stop queuing. diff -Nru a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c --- a/net/bluetooth/bnep/sock.c Mon Jun 9 23:16:20 2003 +++ b/net/bluetooth/bnep/sock.c Mon Jun 9 23:16:20 2003 @@ -93,7 +93,7 @@ if (!nsock) return err; - if (nsock->sk->state != BT_CONNECTED) + if (nsock->sk->sk_state != BT_CONNECTED) return -EBADFD; err = bnep_add_connection(&ca, nsock); @@ -179,8 +179,8 @@ sock->state = SS_UNCONNECTED; - sk->destruct = NULL; - sk->protocol = protocol; + sk->sk_destruct = NULL; + sk->sk_protocol = protocol; return 0; } diff -Nru a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c --- a/net/bluetooth/hci_sock.c Mon Jun 9 23:16:13 2003 +++ b/net/bluetooth/hci_sock.c Mon Jun 9 23:16:13 2003 @@ -95,11 +95,11 @@ BT_DBG("hdev %p len %d", hdev, skb->len); read_lock(&hci_sk_list.lock); - for (sk = hci_sk_list.head; sk; sk = sk->next) { + for (sk = hci_sk_list.head; sk; sk = sk->sk_next) { struct hci_filter *flt; struct sk_buff *nskb; - if (sk->state != BT_BOUND || hci_pi(sk)->hdev != hdev) + if (sk->sk_state != BT_BOUND || hci_pi(sk)->hdev != hdev) continue; /* Don't send frame to the socket it came from */ @@ -157,8 +157,8 @@ sock_orphan(sk); - skb_queue_purge(&sk->receive_queue); - skb_queue_purge(&sk->write_queue); + skb_queue_purge(&sk->sk_receive_queue); + skb_queue_purge(&sk->sk_write_queue); sock_put(sk); return 0; @@ -283,7 +283,7 @@ } hci_pi(sk)->hdev = hdev; - sk->state = BT_BOUND; + sk->sk_state = BT_BOUND; done: release_sock(sk); @@ -330,7 +330,7 @@ if (flags & (MSG_OOB)) return -EOPNOTSUPP; - if (sk->state == BT_CLOSED) + if (sk->sk_state == BT_CLOSED) return 0; if (!(skb = skb_recv_datagram(sk, flags, noblock, &err))) @@ -587,7 +587,7 @@ return -ENOMEM; sock->state = SS_UNCONNECTED; - sk->state = BT_OPEN; + sk->sk_state = BT_OPEN; bt_sock_link(&hci_sk_list, sk); return 0; @@ -610,13 +610,13 @@ /* Detach sockets from device */ read_lock(&hci_sk_list.lock); - for (sk = hci_sk_list.head; sk; sk = sk->next) { + for (sk = hci_sk_list.head; sk; sk = sk->sk_next) { bh_lock_sock(sk); if (hci_pi(sk)->hdev == hdev) { hci_pi(sk)->hdev = NULL; - sk->err = EPIPE; - sk->state = BT_OPEN; - sk->state_change(sk); + sk->sk_err = EPIPE; + sk->sk_state = BT_OPEN; + sk->sk_state_change(sk); hci_dev_put(hdev); } diff -Nru a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c --- a/net/bluetooth/l2cap.c Mon Jun 9 23:16:15 2003 +++ b/net/bluetooth/l2cap.c Mon Jun 9 23:16:15 2003 @@ -86,7 +86,7 @@ { struct sock *sk = (struct sock *) arg; - BT_DBG("sock %p state %d", sk, sk->state); + BT_DBG("sock %p state %d", sk, sk->sk_state); bh_lock_sock(sk); __l2cap_sock_close(sk, ETIMEDOUT); @@ -98,25 +98,25 @@ static void l2cap_sock_set_timer(struct sock *sk, long timeout) { - BT_DBG("sk %p state %d timeout %ld", sk, sk->state, timeout); + BT_DBG("sk %p state %d timeout %ld", sk, sk->sk_state, timeout); - if (!mod_timer(&sk->timer, jiffies + timeout)) + if (!mod_timer(&sk->sk_timer, jiffies + timeout)) sock_hold(sk); } static void l2cap_sock_clear_timer(struct sock *sk) { - BT_DBG("sock %p state %d", sk, sk->state); + BT_DBG("sock %p state %d", sk, sk->sk_state); - if (timer_pending(&sk->timer) && del_timer(&sk->timer)) + if (timer_pending(&sk->sk_timer) && del_timer(&sk->sk_timer)) __sock_put(sk); } static void l2cap_sock_init_timer(struct sock *sk) { - init_timer(&sk->timer); - sk->timer.function = l2cap_sock_timeout; - sk->timer.data = (unsigned long)sk; + init_timer(&sk->sk_timer); + sk->sk_timer.function = l2cap_sock_timeout; + sk->sk_timer.data = (unsigned long)sk; } /* ---- L2CAP connections ---- */ @@ -186,7 +186,7 @@ static struct sock *__l2cap_get_sock_by_addr(u16 psm, bdaddr_t *src) { struct sock *sk; - for (sk = l2cap_sk_list.head; sk; sk = sk->next) { + for (sk = l2cap_sk_list.head; sk; sk = sk->sk_next) { if (l2cap_pi(sk)->sport == psm && !bacmp(&bt_sk(sk)->src, src)) break; } @@ -200,8 +200,8 @@ { struct sock *sk, *sk1 = NULL; - for (sk = l2cap_sk_list.head; sk; sk = sk->next) { - if (state && sk->state != state) + for (sk = l2cap_sk_list.head; sk; sk = sk->sk_next) { + if (state && sk->sk_state != state) continue; if (l2cap_pi(sk)->psm == psm) { @@ -233,11 +233,11 @@ { BT_DBG("sk %p", sk); - skb_queue_purge(&sk->receive_queue); - skb_queue_purge(&sk->write_queue); + skb_queue_purge(&sk->sk_receive_queue); + skb_queue_purge(&sk->sk_write_queue); - if (sk->protinfo) - kfree(sk->protinfo); + if (sk->sk_protinfo) + kfree(sk->sk_protinfo); } static void l2cap_sock_cleanup_listen(struct sock *parent) @@ -250,8 +250,8 @@ while ((sk = bt_accept_dequeue(parent, NULL))) l2cap_sock_close(sk); - parent->state = BT_CLOSED; - parent->zapped = 1; + parent->sk_state = BT_CLOSED; + parent->sk_zapped = 1; } /* Kill socket (only if zapped and orphan) @@ -259,22 +259,22 @@ */ static void l2cap_sock_kill(struct sock *sk) { - if (!sk->zapped || sk->socket) + if (!sk->sk_zapped || sk->sk_socket) return; - BT_DBG("sk %p state %d", sk, sk->state); + BT_DBG("sk %p state %d", sk, sk->sk_state); /* Kill poor orphan */ bt_sock_unlink(&l2cap_sk_list, sk); - __set_bit(SOCK_DEAD, &sk->flags); + sock_set_flag(sk, SOCK_DEAD); sock_put(sk); } static void __l2cap_sock_close(struct sock *sk, int reason) { - BT_DBG("sk %p state %d socket %p", sk, sk->state, sk->socket); + BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket); - switch (sk->state) { + switch (sk->sk_state) { case BT_LISTEN: l2cap_sock_cleanup_listen(sk); break; @@ -282,11 +282,11 @@ case BT_CONNECTED: case BT_CONFIG: case BT_CONNECT2: - if (sk->type == SOCK_SEQPACKET) { + if (sk->sk_type == SOCK_SEQPACKET) { struct l2cap_conn *conn = l2cap_pi(sk)->conn; struct l2cap_disconn_req req; - sk->state = BT_DISCONN; + sk->sk_state = BT_DISCONN; l2cap_sock_set_timer(sk, HZ * 5); req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid); @@ -303,7 +303,7 @@ break; default: - sk->zapped = 1; + sk->sk_zapped = 1; break; } } @@ -327,7 +327,7 @@ BT_DBG("sk %p", sk); if (parent) { - sk->type = parent->type; + sk->sk_type = parent->sk_type; pi->imtu = l2cap_pi(parent)->imtu; pi->omtu = l2cap_pi(parent)->omtu; pi->link_mode = l2cap_pi(parent)->link_mode; @@ -352,11 +352,11 @@ sk_set_owner(sk, THIS_MODULE); - sk->destruct = l2cap_sock_destruct; - sk->sndtimeo = L2CAP_CONN_TIMEOUT; + sk->sk_destruct = l2cap_sock_destruct; + sk->sk_sndtimeo = L2CAP_CONN_TIMEOUT; - sk->protocol = proto; - sk->state = BT_OPEN; + sk->sk_protocol = proto; + sk->sk_state = BT_OPEN; l2cap_sock_init_timer(sk); @@ -401,7 +401,7 @@ lock_sock(sk); - if (sk->state != BT_OPEN) { + if (sk->sk_state != BT_OPEN) { err = -EBADFD; goto done; } @@ -414,7 +414,7 @@ bacpy(&bt_sk(sk)->src, &la->l2_bdaddr); l2cap_pi(sk)->psm = la->l2_psm; l2cap_pi(sk)->sport = la->l2_psm; - sk->state = BT_BOUND; + sk->sk_state = BT_BOUND; } write_unlock_bh(&l2cap_sk_list.lock); @@ -458,18 +458,18 @@ l2cap_chan_add(conn, sk, NULL); - sk->state = BT_CONNECT; - l2cap_sock_set_timer(sk, sk->sndtimeo); + sk->sk_state = BT_CONNECT; + l2cap_sock_set_timer(sk, sk->sk_sndtimeo); if (hcon->state == BT_CONNECTED) { - if (sk->type == SOCK_SEQPACKET) { + if (sk->sk_type == SOCK_SEQPACKET) { struct l2cap_conn_req req; req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); req.psm = l2cap_pi(sk)->psm; l2cap_send_req(conn, L2CAP_CONN_REQ, sizeof(req), &req); } else { l2cap_sock_clear_timer(sk); - sk->state = BT_CONNECTED; + sk->sk_state = BT_CONNECTED; } } @@ -494,12 +494,12 @@ goto done; } - if (sk->type == SOCK_SEQPACKET && !la->l2_psm) { + if (sk->sk_type == SOCK_SEQPACKET && !la->l2_psm) { err = -EINVAL; goto done; } - switch(sk->state) { + switch(sk->sk_state) { case BT_CONNECT: case BT_CONNECT2: case BT_CONFIG: @@ -544,7 +544,7 @@ lock_sock(sk); - if (sk->state != BT_BOUND || sock->type != SOCK_SEQPACKET) { + if (sk->sk_state != BT_BOUND || sock->type != SOCK_SEQPACKET) { err = -EBADFD; goto done; } @@ -554,9 +554,9 @@ goto done; } - sk->max_ack_backlog = backlog; - sk->ack_backlog = 0; - sk->state = BT_LISTEN; + sk->sk_max_ack_backlog = backlog; + sk->sk_ack_backlog = 0; + sk->sk_state = BT_LISTEN; done: release_sock(sk); @@ -572,7 +572,7 @@ lock_sock(sk); - if (sk->state != BT_LISTEN) { + if (sk->sk_state != BT_LISTEN) { err = -EBADFD; goto done; } @@ -582,7 +582,7 @@ BT_DBG("sk %p timeo %ld", sk, timeo); /* Wait for an incoming connection. (wake-one). */ - add_wait_queue_exclusive(sk->sleep, &wait); + add_wait_queue_exclusive(sk->sk_sleep, &wait); while (!(nsk = bt_accept_dequeue(sk, newsock))) { set_current_state(TASK_INTERRUPTIBLE); if (!timeo) { @@ -594,7 +594,7 @@ timeo = schedule_timeout(timeo); lock_sock(sk); - if (sk->state != BT_LISTEN) { + if (sk->sk_state != BT_LISTEN) { err = -EBADFD; break; } @@ -605,7 +605,7 @@ } } set_current_state(TASK_RUNNING); - remove_wait_queue(sk->sleep, &wait); + remove_wait_queue(sk->sk_sleep, &wait); if (err) goto done; @@ -648,7 +648,7 @@ BT_DBG("sk %p len %d", sk, len); /* First fragment (with L2CAP header) */ - if (sk->type == SOCK_DGRAM) + if (sk->sk_type == SOCK_DGRAM) hlen = L2CAP_HDR_SIZE + 2; else hlen = L2CAP_HDR_SIZE; @@ -665,7 +665,7 @@ lh->cid = __cpu_to_le16(l2cap_pi(sk)->dcid); lh->len = __cpu_to_le16(len + (hlen - L2CAP_HDR_SIZE)); - if (sk->type == SOCK_DGRAM) + if (sk->sk_type == SOCK_DGRAM) put_unaligned(l2cap_pi(sk)->psm, (u16 *) skb_put(skb, 2)); if (memcpy_fromiovec(skb_put(skb, count), msg->msg_iov, count)) { @@ -713,7 +713,7 @@ BT_DBG("sock %p, sk %p", sock, sk); - if (sk->err) + if (sk->sk_err) return sock_error(sk); if (msg->msg_flags & MSG_OOB) @@ -725,7 +725,7 @@ lock_sock(sk); - if (sk->state == BT_CONNECTED) + if (sk->sk_state == BT_CONNECTED) err = l2cap_do_send(sk, msg, len); else err = -ENOTCONN; @@ -804,7 +804,7 @@ break; case L2CAP_CONNINFO: - if (sk->state != BT_CONNECTED) { + if (sk->sk_state != BT_CONNECTED) { err = -ENOTCONN; break; } @@ -837,7 +837,7 @@ l2cap_sock_clear_timer(sk); lock_sock(sk); - sk->shutdown = SHUTDOWN_MASK; + sk->sk_shutdown = SHUTDOWN_MASK; __l2cap_sock_close(sk, ECONNRESET); release_sock(sk); @@ -939,10 +939,10 @@ l2cap_pi(sk)->conn = conn; - if (sk->type == SOCK_SEQPACKET) { + if (sk->sk_type == SOCK_SEQPACKET) { /* Alloc CID for connection-oriented socket */ l2cap_pi(sk)->scid = l2cap_alloc_cid(l); - } else if (sk->type == SOCK_DGRAM) { + } else if (sk->sk_type == SOCK_DGRAM) { /* Connectionless socket */ l2cap_pi(sk)->scid = 0x0002; l2cap_pi(sk)->dcid = 0x0002; @@ -978,14 +978,14 @@ hci_conn_put(conn->hcon); } - sk->state = BT_CLOSED; - sk->err = err; - sk->zapped = 1; + sk->sk_state = BT_CLOSED; + sk->sk_err = err; + sk->sk_zapped = 1; if (parent) - parent->data_ready(parent, 0); + parent->sk_data_ready(parent, 0); else - sk->state_change(sk); + sk->sk_state_change(sk); } static void l2cap_conn_ready(struct l2cap_conn *conn) @@ -1000,11 +1000,11 @@ for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { bh_lock_sock(sk); - if (sk->type != SOCK_SEQPACKET) { + if (sk->sk_type != SOCK_SEQPACKET) { l2cap_sock_clear_timer(sk); - sk->state = BT_CONNECTED; - sk->state_change(sk); - } else if (sk->state == BT_CONNECT) { + sk->sk_state = BT_CONNECTED; + sk->sk_state_change(sk); + } else if (sk->sk_state == BT_CONNECT) { struct l2cap_conn_req req; req.scid = __cpu_to_le16(l2cap_pi(sk)->scid); req.psm = l2cap_pi(sk)->psm; @@ -1030,13 +1030,13 @@ /* Outgoing channel. * Wake up socket sleeping on connect. */ - sk->state = BT_CONNECTED; - sk->state_change(sk); + sk->sk_state = BT_CONNECTED; + sk->sk_state_change(sk); } else { /* Incoming channel. * Wake up socket sleeping on accept. */ - parent->data_ready(parent, 0); + parent->sk_data_ready(parent, 0); } } @@ -1051,7 +1051,7 @@ read_lock(&l->lock); for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { - if (sk->type != SOCK_RAW) + if (sk->sk_type != SOCK_RAW) continue; /* Don't send frame to the socket it came from */ @@ -1352,8 +1352,8 @@ result = L2CAP_CR_NO_MEM; /* Check for backlog size */ - if (parent->ack_backlog > parent->max_ack_backlog) { - BT_DBG("backlog full %d", parent->ack_backlog); + if (parent->sk_ack_backlog > parent->sk_max_ack_backlog) { + BT_DBG("backlog full %d", parent->sk_ack_backlog); goto response; } @@ -1366,7 +1366,7 @@ /* Check if we already have channel with that dcid */ if (__l2cap_get_chan_by_dcid(list, scid)) { write_unlock(&list->lock); - sk->zapped = 1; + sk->sk_zapped = 1; l2cap_sock_kill(sk); goto response; } @@ -1382,12 +1382,12 @@ __l2cap_chan_add(conn, sk, parent); dcid = l2cap_pi(sk)->scid; - l2cap_sock_set_timer(sk, sk->sndtimeo); + l2cap_sock_set_timer(sk, sk->sk_sndtimeo); /* Service level security */ result = L2CAP_CR_PEND; status = L2CAP_CS_AUTHEN_PEND; - sk->state = BT_CONNECT2; + sk->sk_state = BT_CONNECT2; l2cap_pi(sk)->ident = cmd->ident; if (l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT) { @@ -1398,7 +1398,7 @@ goto done; } - sk->state = BT_CONFIG; + sk->sk_state = BT_CONFIG; result = status = 0; done: @@ -1435,7 +1435,7 @@ switch (result) { case L2CAP_CR_SUCCESS: - sk->state = BT_CONFIG; + sk->sk_state = BT_CONFIG; l2cap_pi(sk)->dcid = dcid; l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT; @@ -1488,7 +1488,7 @@ l2cap_pi(sk)->conf_state |= L2CAP_CONF_OUTPUT_DONE; if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) { - sk->state = BT_CONNECTED; + sk->sk_state = BT_CONNECTED; l2cap_chan_ready(sk); } else if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) { u8 req[64]; @@ -1522,7 +1522,7 @@ /* They didn't like our options. Well... we do not negotiate. * Close channel. */ - sk->state = BT_DISCONN; + sk->sk_state = BT_DISCONN; l2cap_sock_set_timer(sk, HZ * 5); req.dcid = __cpu_to_le16(l2cap_pi(sk)->dcid); @@ -1538,7 +1538,7 @@ l2cap_pi(sk)->conf_state |= L2CAP_CONF_INPUT_DONE; if (l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE) { - sk->state = BT_CONNECTED; + sk->sk_state = BT_CONNECTED; l2cap_chan_ready(sk); } @@ -1566,7 +1566,7 @@ rsp.scid = __cpu_to_le16(l2cap_pi(sk)->dcid); l2cap_send_rsp(conn, cmd->ident, L2CAP_DISCONN_RSP, sizeof(rsp), &rsp); - sk->shutdown = SHUTDOWN_MASK; + sk->sk_shutdown = SHUTDOWN_MASK; l2cap_chan_del(sk, ECONNRESET); bh_unlock_sock(sk); @@ -1690,7 +1690,7 @@ BT_DBG("sk %p, len %d", sk, skb->len); - if (sk->state != BT_CONNECTED) + if (sk->sk_state != BT_CONNECTED) goto drop; if (l2cap_pi(sk)->imtu < skb->len) @@ -1722,7 +1722,7 @@ BT_DBG("sk %p, len %d", sk, skb->len); - if (sk->state != BT_BOUND && sk->state != BT_CONNECTED) + if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED) goto drop; if (l2cap_pi(sk)->imtu < skb->len) @@ -1781,8 +1781,8 @@ /* Find listening sockets and check their link_mode */ read_lock(&l2cap_sk_list.lock); - for (sk = l2cap_sk_list.head; sk; sk = sk->next) { - if (sk->state != BT_LISTEN) + for (sk = l2cap_sk_list.head; sk; sk = sk->sk_next) { + if (sk->sk_state != BT_LISTEN) continue; if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) { @@ -1845,17 +1845,17 @@ for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { bh_lock_sock(sk); - if (sk->state != BT_CONNECT2 || + if (sk->sk_state != BT_CONNECT2 || (l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT)) { bh_unlock_sock(sk); continue; } if (!status) { - sk->state = BT_CONFIG; + sk->sk_state = BT_CONFIG; result = 0; } else { - sk->state = BT_DISCONN; + sk->sk_state = BT_DISCONN; l2cap_sock_set_timer(sk, HZ/10); result = L2CAP_CR_SEC_BLOCK; } @@ -1892,16 +1892,16 @@ for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) { bh_lock_sock(sk); - if (sk->state != BT_CONNECT2) { + if (sk->sk_state != BT_CONNECT2) { bh_unlock_sock(sk); continue; } if (!status) { - sk->state = BT_CONFIG; + sk->sk_state = BT_CONFIG; result = 0; } else { - sk->state = BT_DISCONN; + sk->sk_state = BT_DISCONN; l2cap_sock_set_timer(sk, HZ/10); result = L2CAP_CR_SEC_BLOCK; } @@ -2008,7 +2008,7 @@ read_lock_bh(&l2cap_sk_list.lock); - for (sk = l2cap_sk_list.head; sk; sk = sk->next) + for (sk = l2cap_sk_list.head; sk; sk = sk->sk_next) if (!l--) return sk; return NULL; @@ -2018,7 +2018,7 @@ { struct sock *sk = e; (*pos)++; - return sk->next; + return sk->sk_next; } static void l2cap_seq_stop(struct seq_file *seq, void *e) @@ -2033,8 +2033,8 @@ seq_printf(seq, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d 0x%x\n", batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), - sk->state, pi->psm, pi->scid, pi->dcid, pi->imtu, pi->omtu, - pi->link_mode); + sk->sk_state, pi->psm, pi->scid, pi->dcid, pi->imtu, + pi->omtu, pi->link_mode); return 0; } diff -Nru a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c --- a/net/bluetooth/rfcomm/core.c Mon Jun 9 23:16:05 2003 +++ b/net/bluetooth/rfcomm/core.c Mon Jun 9 23:16:05 2003 @@ -144,7 +144,7 @@ /* ---- L2CAP callbacks ---- */ static void rfcomm_l2state_change(struct sock *sk) { - BT_DBG("%p state %d", sk, sk->state); + BT_DBG("%p state %d", sk, sk->sk_state); rfcomm_schedule(RFCOMM_SCHED_STATE); } @@ -163,8 +163,8 @@ err = sock_create(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP, sock); if (!err) { struct sock *sk = (*sock)->sk; - sk->data_ready = rfcomm_l2data_ready; - sk->state_change = rfcomm_l2state_change; + sk->sk_data_ready = rfcomm_l2data_ready; + sk->sk_state_change = rfcomm_l2state_change; } return err; } @@ -1545,19 +1545,19 @@ struct sock *sk = sock->sk; struct sk_buff *skb; - BT_DBG("session %p state %ld qlen %d", s, s->state, skb_queue_len(&sk->receive_queue)); + BT_DBG("session %p state %ld qlen %d", s, s->state, skb_queue_len(&sk->sk_receive_queue)); /* Get data directly from socket receive queue without copying it. */ - while ((skb = skb_dequeue(&sk->receive_queue))) { + while ((skb = skb_dequeue(&sk->sk_receive_queue))) { skb_orphan(skb); rfcomm_recv_frame(s, skb); } - if (sk->state == BT_CLOSED) { + if (sk->sk_state == BT_CLOSED) { if (!s->initiator) rfcomm_session_put(s); - rfcomm_session_close(s, sk->err); + rfcomm_session_close(s, sk->sk_err); } } @@ -1587,8 +1587,8 @@ } /* Set our callbacks */ - nsock->sk->data_ready = rfcomm_l2data_ready; - nsock->sk->state_change = rfcomm_l2state_change; + nsock->sk->sk_data_ready = rfcomm_l2data_ready; + nsock->sk->sk_state_change = rfcomm_l2state_change; s = rfcomm_session_add(nsock, BT_OPEN); if (s) @@ -1603,7 +1603,7 @@ BT_DBG("%p state %ld", s, s->state); - switch(sk->state) { + switch(sk->sk_state) { case BT_CONNECTED: s->state = BT_CONNECT; @@ -1616,7 +1616,7 @@ case BT_CLOSED: s->state = BT_CLOSED; - rfcomm_session_close(s, sk->err); + rfcomm_session_close(s, sk->sk_err); break; } } diff -Nru a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c --- a/net/bluetooth/rfcomm/sock.c Mon Jun 9 23:16:15 2003 +++ b/net/bluetooth/rfcomm/sock.c Mon Jun 9 23:16:15 2003 @@ -78,11 +78,11 @@ if (!sk) return; - atomic_add(skb->len, &sk->rmem_alloc); - skb_queue_tail(&sk->receive_queue, skb); - sk->data_ready(sk, skb->len); + atomic_add(skb->len, &sk->sk_rmem_alloc); + skb_queue_tail(&sk->sk_receive_queue, skb); + sk->sk_data_ready(sk, skb->len); - if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf) + if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf) rfcomm_dlc_throttle(d); } @@ -97,16 +97,16 @@ bh_lock_sock(sk); if (err) - sk->err = err; - sk->state = d->state; + sk->sk_err = err; + sk->sk_state = d->state; parent = bt_sk(sk)->parent; if (!parent) { if (d->state == BT_CONNECTED) rfcomm_session_getaddr(d->session, &bt_sk(sk)->src, NULL); - sk->state_change(sk); + sk->sk_state_change(sk); } else - parent->data_ready(parent, 0); + parent->sk_data_ready(parent, 0); bh_unlock_sock(sk); } @@ -116,7 +116,7 @@ { struct sock *sk; - for (sk = rfcomm_sk_list.head; sk; sk = sk->next) { + for (sk = rfcomm_sk_list.head; sk; sk = sk->sk_next) { if (rfcomm_pi(sk)->channel == channel && !bacmp(&bt_sk(sk)->src, src)) break; @@ -132,8 +132,8 @@ { struct sock *sk, *sk1 = NULL; - for (sk = rfcomm_sk_list.head; sk; sk = sk->next) { - if (state && sk->state != state) + for (sk = rfcomm_sk_list.head; sk; sk = sk->sk_next) { + if (state && sk->sk_state != state) continue; if (rfcomm_pi(sk)->channel == channel) { @@ -167,8 +167,8 @@ BT_DBG("sk %p dlc %p", sk, d); - skb_queue_purge(&sk->receive_queue); - skb_queue_purge(&sk->write_queue); + skb_queue_purge(&sk->sk_receive_queue); + skb_queue_purge(&sk->sk_write_queue); rfcomm_dlc_lock(d); rfcomm_pi(sk)->dlc = NULL; @@ -180,8 +180,8 @@ rfcomm_dlc_put(d); - if (sk->protinfo) - kfree(sk->protinfo); + if (sk->sk_protinfo) + kfree(sk->sk_protinfo); } static void rfcomm_sock_cleanup_listen(struct sock *parent) @@ -194,8 +194,8 @@ while ((sk = bt_accept_dequeue(parent, NULL))) rfcomm_sock_close(sk); - parent->state = BT_CLOSED; - parent->zapped = 1; + parent->sk_state = BT_CLOSED; + parent->sk_zapped = 1; } /* Kill socket (only if zapped and orphan) @@ -203,14 +203,14 @@ */ static void rfcomm_sock_kill(struct sock *sk) { - if (!sk->zapped || sk->socket) + if (!sk->sk_zapped || sk->sk_socket) return; - BT_DBG("sk %p state %d refcnt %d", sk, sk->state, atomic_read(&sk->refcnt)); + BT_DBG("sk %p state %d refcnt %d", sk, sk->sk_state, atomic_read(&sk->sk_refcnt)); /* Kill poor orphan */ bt_sock_unlink(&rfcomm_sk_list, sk); - __set_bit(SOCK_DEAD, &sk->flags); + sock_set_flag(sk, SOCK_DEAD); sock_put(sk); } @@ -223,9 +223,9 @@ lock_sock(sk); - BT_DBG("sk %p state %d socket %p", sk, sk->state, sk->socket); + BT_DBG("sk %p state %d socket %p", sk, sk->sk_state, sk->sk_socket); - switch (sk->state) { + switch (sk->sk_state) { case BT_LISTEN: rfcomm_sock_cleanup_listen(sk); break; @@ -237,7 +237,7 @@ rfcomm_dlc_close(d, 0); default: - sk->zapped = 1; + sk->sk_zapped = 1; break; }; @@ -251,7 +251,7 @@ BT_DBG("sk %p", sk); if (parent) - sk->type = parent->type; + sk->sk_type = parent->sk_type; } static struct sock *rfcomm_sock_alloc(struct socket *sock, int proto, int prio) @@ -276,14 +276,14 @@ rfcomm_pi(sk)->dlc = d; d->owner = sk; - sk->destruct = rfcomm_sock_destruct; - sk->sndtimeo = RFCOMM_CONN_TIMEOUT; + sk->sk_destruct = rfcomm_sock_destruct; + sk->sk_sndtimeo = RFCOMM_CONN_TIMEOUT; - sk->sndbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10; - sk->rcvbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10; + sk->sk_sndbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10; + sk->sk_rcvbuf = RFCOMM_MAX_CREDITS * RFCOMM_DEFAULT_MTU * 10; - sk->protocol = proto; - sk->state = BT_OPEN; + sk->sk_protocol = proto; + sk->sk_state = BT_OPEN; bt_sock_link(&rfcomm_sk_list, sk); @@ -324,7 +324,7 @@ lock_sock(sk); - if (sk->state != BT_OPEN) { + if (sk->sk_state != BT_OPEN) { err = -EBADFD; goto done; } @@ -337,7 +337,7 @@ /* Save source address */ bacpy(&bt_sk(sk)->src, &sa->rc_bdaddr); rfcomm_pi(sk)->channel = sa->rc_channel; - sk->state = BT_BOUND; + sk->sk_state = BT_BOUND; } write_unlock_bh(&rfcomm_sk_list.lock); @@ -359,15 +359,15 @@ if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_rc)) return -EINVAL; - if (sk->state != BT_OPEN && sk->state != BT_BOUND) + if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) return -EBADFD; - if (sk->type != SOCK_STREAM) + if (sk->sk_type != SOCK_STREAM) return -EINVAL; lock_sock(sk); - sk->state = BT_CONNECT; + sk->sk_state = BT_CONNECT; bacpy(&bt_sk(sk)->dst, &sa->rc_bdaddr); rfcomm_pi(sk)->channel = sa->rc_channel; @@ -388,14 +388,14 @@ lock_sock(sk); - if (sk->state != BT_BOUND) { + if (sk->sk_state != BT_BOUND) { err = -EBADFD; goto done; } - sk->max_ack_backlog = backlog; - sk->ack_backlog = 0; - sk->state = BT_LISTEN; + sk->sk_max_ack_backlog = backlog; + sk->sk_ack_backlog = 0; + sk->sk_state = BT_LISTEN; done: release_sock(sk); @@ -411,7 +411,7 @@ lock_sock(sk); - if (sk->state != BT_LISTEN) { + if (sk->sk_state != BT_LISTEN) { err = -EBADFD; goto done; } @@ -421,7 +421,7 @@ BT_DBG("sk %p timeo %ld", sk, timeo); /* Wait for an incoming connection. (wake-one). */ - add_wait_queue_exclusive(sk->sleep, &wait); + add_wait_queue_exclusive(sk->sk_sleep, &wait); while (!(nsk = bt_accept_dequeue(sk, newsock))) { set_current_state(TASK_INTERRUPTIBLE); if (!timeo) { @@ -433,7 +433,7 @@ timeo = schedule_timeout(timeo); lock_sock(sk); - if (sk->state != BT_LISTEN) { + if (sk->sk_state != BT_LISTEN) { err = -EBADFD; break; } @@ -444,7 +444,7 @@ } } set_current_state(TASK_RUNNING); - remove_wait_queue(sk->sleep, &wait); + remove_wait_queue(sk->sk_sleep, &wait); if (err) goto done; @@ -488,7 +488,7 @@ if (msg->msg_flags & MSG_OOB) return -EOPNOTSUPP; - if (sk->shutdown & SEND_SHUTDOWN) + if (sk->sk_shutdown & SEND_SHUTDOWN) return -EPIPE; BT_DBG("sock %p, sk %p", sock, sk); @@ -530,23 +530,23 @@ { DECLARE_WAITQUEUE(wait, current); - add_wait_queue(sk->sleep, &wait); + add_wait_queue(sk->sk_sleep, &wait); for (;;) { set_current_state(TASK_INTERRUPTIBLE); - if (skb_queue_len(&sk->receive_queue) || sk->err || (sk->shutdown & RCV_SHUTDOWN) || + if (skb_queue_len(&sk->sk_receive_queue) || sk->sk_err || (sk->sk_shutdown & RCV_SHUTDOWN) || signal_pending(current) || !timeo) break; - set_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags); + set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); release_sock(sk); timeo = schedule_timeout(timeo); lock_sock(sk); - clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags); + clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); } __set_current_state(TASK_RUNNING); - remove_wait_queue(sk->sleep, &wait); + remove_wait_queue(sk->sk_sleep, &wait); return timeo; } @@ -557,7 +557,7 @@ int target, err = 0, copied = 0; long timeo; - if (sk->state != BT_CONNECTED) + if (sk->sk_state != BT_CONNECTED) return -EINVAL; if (flags & MSG_OOB) @@ -576,14 +576,14 @@ struct sk_buff *skb; int chunk; - skb = skb_dequeue(&sk->receive_queue); + skb = skb_dequeue(&sk->sk_receive_queue); if (!skb) { if (copied >= target) break; if ((err = sock_error(sk)) != 0) break; - if (sk->shutdown & RCV_SHUTDOWN) + if (sk->sk_shutdown & RCV_SHUTDOWN) break; err = -EAGAIN; @@ -601,7 +601,7 @@ chunk = min_t(unsigned int, skb->len, size); if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) { - skb_queue_head(&sk->receive_queue, skb); + skb_queue_head(&sk->sk_receive_queue, skb); if (!copied) copied = -EFAULT; break; @@ -610,24 +610,24 @@ size -= chunk; if (!(flags & MSG_PEEK)) { - atomic_sub(chunk, &sk->rmem_alloc); + atomic_sub(chunk, &sk->sk_rmem_alloc); skb_pull(skb, chunk); if (skb->len) { - skb_queue_head(&sk->receive_queue, skb); + skb_queue_head(&sk->sk_receive_queue, skb); break; } kfree_skb(skb); } else { /* put message back and return */ - skb_queue_head(&sk->receive_queue, skb); + skb_queue_head(&sk->sk_receive_queue, skb); break; } } while (size); out: - if (atomic_read(&sk->rmem_alloc) <= (sk->rcvbuf >> 2)) + if (atomic_read(&sk->sk_rmem_alloc) <= (sk->sk_rcvbuf >> 2)) rfcomm_dlc_unthrottle(rfcomm_pi(sk)->dlc); release_sock(sk); @@ -643,8 +643,8 @@ if (!sk) return 0; lock_sock(sk); - sk->shutdown = SHUTDOWN_MASK; - if (sk->state == BT_CONNECTED) + sk->sk_shutdown = SHUTDOWN_MASK; + if (sk->sk_state == BT_CONNECTED) rfcomm_dlc_close(rfcomm_pi(sk)->dlc, 0); release_sock(sk); @@ -744,8 +744,8 @@ return 0; /* Check for backlog size */ - if (parent->ack_backlog > parent->max_ack_backlog) { - BT_DBG("backlog full %d", parent->ack_backlog); + if (parent->sk_ack_backlog > parent->sk_max_ack_backlog) { + BT_DBG("backlog full %d", parent->sk_ack_backlog); goto done; } @@ -758,7 +758,7 @@ bacpy(&bt_sk(sk)->dst, &dst); rfcomm_pi(sk)->channel = channel; - sk->state = BT_CONFIG; + sk->sk_state = BT_CONFIG; bt_accept_enqueue(parent, sk); /* Accept connection and return socket DLC */ @@ -779,7 +779,7 @@ read_lock_bh(&rfcomm_sk_list.lock); - for (sk = rfcomm_sk_list.head; sk; sk = sk->next) + for (sk = rfcomm_sk_list.head; sk; sk = sk->sk_next) if (!l--) return sk; return NULL; @@ -789,7 +789,7 @@ { struct sock *sk = e; (*pos)++; - return sk->next; + return sk->sk_next; } static void rfcomm_seq_stop(struct seq_file *seq, void *e) @@ -802,7 +802,7 @@ struct sock *sk = e; seq_printf(seq, "%s %s %d %d\n", batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), - sk->state, rfcomm_pi(sk)->channel); + sk->sk_state, rfcomm_pi(sk)->channel); return 0; } diff -Nru a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c --- a/net/bluetooth/rfcomm/tty.c Mon Jun 9 23:16:13 2003 +++ b/net/bluetooth/rfcomm/tty.c Mon Jun 9 23:16:13 2003 @@ -294,7 +294,7 @@ if (req.flags & (1 << RFCOMM_REUSE_DLC)) { /* Socket must be connected */ - if (sk->state != BT_CONNECTED) + if (sk->sk_state != BT_CONNECTED) return -EBADFD; dlc = rfcomm_pi(sk)->dlc; @@ -314,7 +314,7 @@ if (req.flags & (1 << RFCOMM_REUSE_DLC)) { /* DLC is now used by device. * Socket must be disconnected */ - sk->state = BT_CLOSED; + sk->sk_state = BT_CLOSED; } return id; @@ -863,11 +863,8 @@ .magic = TTY_DRIVER_MAGIC, .driver_name = "rfcomm", -#ifdef CONFIG_DEVFS_FS - .name = "bluetooth/rfcomm/", -#else + .devfs_name = "bluetooth/rfcomm/", .name = "rfcomm", -#endif .major = RFCOMM_TTY_MAJOR, .minor_start = RFCOMM_TTY_MINOR, .num = RFCOMM_TTY_PORTS, diff -Nru a/net/bluetooth/sco.c b/net/bluetooth/sco.c --- a/net/bluetooth/sco.c Mon Jun 9 23:16:08 2003 +++ b/net/bluetooth/sco.c Mon Jun 9 23:16:08 2003 @@ -81,11 +81,11 @@ { struct sock *sk = (struct sock *) arg; - BT_DBG("sock %p state %d", sk, sk->state); + BT_DBG("sock %p state %d", sk, sk->sk_state); bh_lock_sock(sk); - sk->err = ETIMEDOUT; - sk->state_change(sk); + sk->sk_err = ETIMEDOUT; + sk->sk_state_change(sk); bh_unlock_sock(sk); sco_sock_kill(sk); @@ -94,25 +94,25 @@ static void sco_sock_set_timer(struct sock *sk, long timeout) { - BT_DBG("sock %p state %d timeout %ld", sk, sk->state, timeout); + BT_DBG("sock %p state %d timeout %ld", sk, sk->sk_state, timeout); - if (!mod_timer(&sk->timer, jiffies + timeout)) + if (!mod_timer(&sk->sk_timer, jiffies + timeout)) sock_hold(sk); } static void sco_sock_clear_timer(struct sock *sk) { - BT_DBG("sock %p state %d", sk, sk->state); + BT_DBG("sock %p state %d", sk, sk->sk_state); - if (timer_pending(&sk->timer) && del_timer(&sk->timer)) + if (timer_pending(&sk->sk_timer) && del_timer(&sk->sk_timer)) __sock_put(sk); } static void sco_sock_init_timer(struct sock *sk) { - init_timer(&sk->timer); - sk->timer.function = sco_sock_timeout; - sk->timer.data = (unsigned long)sk; + init_timer(&sk->sk_timer); + sk->sk_timer.function = sco_sock_timeout; + sk->sk_timer.data = (unsigned long)sk; } /* ---- SCO connections ---- */ @@ -232,10 +232,10 @@ if (hcon->state == BT_CONNECTED) { sco_sock_clear_timer(sk); - sk->state = BT_CONNECTED; + sk->sk_state = BT_CONNECTED; } else { - sk->state = BT_CONNECT; - sco_sock_set_timer(sk, sk->sndtimeo); + sk->sk_state = BT_CONNECT; + sco_sock_set_timer(sk, sk->sk_sndtimeo); } done: hci_dev_unlock_bh(hdev); @@ -283,7 +283,7 @@ BT_DBG("sk %p len %d", sk, skb->len); - if (sk->state != BT_CONNECTED) + if (sk->sk_state != BT_CONNECTED) goto drop; if (!sock_queue_rcv_skb(sk, skb)) @@ -299,7 +299,7 @@ { struct sock *sk; - for (sk = sco_sk_list.head; sk; sk = sk->next) { + for (sk = sco_sk_list.head; sk; sk = sk->sk_next) { if (!bacmp(&bt_sk(sk)->src, ba)) break; } @@ -316,8 +316,8 @@ read_lock(&sco_sk_list.lock); - for (sk = sco_sk_list.head; sk; sk = sk->next) { - if (sk->state != BT_LISTEN) + for (sk = sco_sk_list.head; sk; sk = sk->sk_next) { + if (sk->sk_state != BT_LISTEN) continue; /* Exact match. */ @@ -338,11 +338,11 @@ { BT_DBG("sk %p", sk); - skb_queue_purge(&sk->receive_queue); - skb_queue_purge(&sk->write_queue); + skb_queue_purge(&sk->sk_receive_queue); + skb_queue_purge(&sk->sk_write_queue); - if (sk->protinfo) - kfree(sk->protinfo); + if (sk->sk_protinfo) + kfree(sk->sk_protinfo); } static void sco_sock_cleanup_listen(struct sock *parent) @@ -355,8 +355,8 @@ while ((sk = bt_accept_dequeue(parent, NULL))) sco_sock_close(sk); - parent->state = BT_CLOSED; - parent->zapped = 1; + parent->sk_state = BT_CLOSED; + parent->sk_zapped = 1; } /* Kill socket (only if zapped and orphan) @@ -364,14 +364,14 @@ */ static void sco_sock_kill(struct sock *sk) { - if (!sk->zapped || sk->socket) + if (!sk->sk_zapped || sk->sk_socket) return; - BT_DBG("sk %p state %d", sk, sk->state); + BT_DBG("sk %p state %d", sk, sk->sk_state); /* Kill poor orphan */ bt_sock_unlink(&sco_sk_list, sk); - __set_bit(SOCK_DEAD, &sk->flags); + sock_set_flag(sk, SOCK_DEAD); sock_put(sk); } @@ -388,9 +388,9 @@ conn = sco_pi(sk)->conn; - BT_DBG("sk %p state %d conn %p socket %p", sk, sk->state, conn, sk->socket); + BT_DBG("sk %p state %d conn %p socket %p", sk, sk->sk_state, conn, sk->sk_socket); - switch (sk->state) { + switch (sk->sk_state) { case BT_LISTEN: sco_sock_cleanup_listen(sk); break; @@ -403,7 +403,7 @@ break; default: - sk->zapped = 1; + sk->sk_zapped = 1; break; }; @@ -417,7 +417,7 @@ BT_DBG("sk %p", sk); if (parent) - sk->type = parent->type; + sk->sk_type = parent->sk_type; } static struct sock *sco_sock_alloc(struct socket *sock, int proto, int prio) @@ -430,9 +430,9 @@ sk_set_owner(sk, THIS_MODULE); - sk->destruct = sco_sock_destruct; - sk->sndtimeo = SCO_CONN_TIMEOUT; - sk->state = BT_OPEN; + sk->sk_destruct = sco_sock_destruct; + sk->sk_sndtimeo = SCO_CONN_TIMEOUT; + sk->sk_state = BT_OPEN; sco_sock_init_timer(sk); @@ -474,7 +474,7 @@ lock_sock(sk); - if (sk->state != BT_OPEN) { + if (sk->sk_state != BT_OPEN) { err = -EBADFD; goto done; } @@ -486,7 +486,7 @@ } else { /* Save source address */ bacpy(&bt_sk(sk)->src, &sa->sco_bdaddr); - sk->state = BT_BOUND; + sk->sk_state = BT_BOUND; } write_unlock_bh(&sco_sk_list.lock); @@ -508,10 +508,10 @@ if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_sco)) return -EINVAL; - if (sk->state != BT_OPEN && sk->state != BT_BOUND) + if (sk->sk_state != BT_OPEN && sk->sk_state != BT_BOUND) return -EBADFD; - if (sk->type != SOCK_SEQPACKET) + if (sk->sk_type != SOCK_SEQPACKET) return -EINVAL; lock_sock(sk); @@ -538,14 +538,14 @@ lock_sock(sk); - if (sk->state != BT_BOUND || sock->type != SOCK_SEQPACKET) { + if (sk->sk_state != BT_BOUND || sock->type != SOCK_SEQPACKET) { err = -EBADFD; goto done; } - sk->max_ack_backlog = backlog; - sk->ack_backlog = 0; - sk->state = BT_LISTEN; + sk->sk_max_ack_backlog = backlog; + sk->sk_ack_backlog = 0; + sk->sk_state = BT_LISTEN; done: release_sock(sk); @@ -561,7 +561,7 @@ lock_sock(sk); - if (sk->state != BT_LISTEN) { + if (sk->sk_state != BT_LISTEN) { err = -EBADFD; goto done; } @@ -571,7 +571,7 @@ BT_DBG("sk %p timeo %ld", sk, timeo); /* Wait for an incoming connection. (wake-one). */ - add_wait_queue_exclusive(sk->sleep, &wait); + add_wait_queue_exclusive(sk->sk_sleep, &wait); while (!(ch = bt_accept_dequeue(sk, newsock))) { set_current_state(TASK_INTERRUPTIBLE); if (!timeo) { @@ -583,7 +583,7 @@ timeo = schedule_timeout(timeo); lock_sock(sk); - if (sk->state != BT_LISTEN) { + if (sk->sk_state != BT_LISTEN) { err = -EBADFD; break; } @@ -594,7 +594,7 @@ } } set_current_state(TASK_RUNNING); - remove_wait_queue(sk->sleep, &wait); + remove_wait_queue(sk->sk_sleep, &wait); if (err) goto done; @@ -633,7 +633,7 @@ BT_DBG("sock %p, sk %p", sock, sk); - if (sk->err) + if (sk->sk_err) return sock_error(sk); if (msg->msg_flags & MSG_OOB) @@ -641,7 +641,7 @@ lock_sock(sk); - if (sk->state == BT_CONNECTED) + if (sk->sk_state == BT_CONNECTED) err = sco_send_frame(sk, msg, len); else err = -ENOTCONN; @@ -685,7 +685,7 @@ switch (optname) { case SCO_OPTIONS: - if (sk->state != BT_CONNECTED) { + if (sk->sk_state != BT_CONNECTED) { err = -ENOTCONN; break; } @@ -701,7 +701,7 @@ break; case SCO_CONNINFO: - if (sk->state != BT_CONNECTED) { + if (sk->sk_state != BT_CONNECTED) { err = -ENOTCONN; break; } @@ -767,11 +767,11 @@ hci_conn_put(conn->hcon); } - sk->state = BT_CLOSED; - sk->err = err; - sk->state_change(sk); + sk->sk_state = BT_CLOSED; + sk->sk_err = err; + sk->sk_state_change(sk); - sk->zapped = 1; + sk->sk_zapped = 1; } static void sco_conn_ready(struct sco_conn *conn) @@ -785,8 +785,8 @@ if ((sk = conn->sk)) { sco_sock_clear_timer(sk); bh_lock_sock(sk); - sk->state = BT_CONNECTED; - sk->state_change(sk); + sk->sk_state = BT_CONNECTED; + sk->sk_state_change(sk); bh_unlock_sock(sk); } else { parent = sco_get_sock_listen(conn->src); @@ -809,10 +809,10 @@ hci_conn_hold(conn->hcon); __sco_chan_add(conn, sk, parent); - sk->state = BT_CONNECTED; + sk->sk_state = BT_CONNECTED; /* Wake up parent */ - parent->data_ready(parent, 1); + parent->sk_data_ready(parent, 1); bh_unlock_sock(parent); } @@ -888,7 +888,7 @@ read_lock_bh(&sco_sk_list.lock); - for (sk = sco_sk_list.head; sk; sk = sk->next) + for (sk = sco_sk_list.head; sk; sk = sk->sk_next) if (!l--) return sk; return NULL; @@ -898,7 +898,7 @@ { struct sock *sk = e; (*pos)++; - return sk->next; + return sk->sk_next; } static void sco_seq_stop(struct seq_file *seq, void *e) @@ -910,7 +910,7 @@ { struct sock *sk = e; seq_printf(seq, "%s %s %d\n", - batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), sk->state); + batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst), sk->sk_state); return 0; } diff -Nru a/net/bridge/br_if.c b/net/bridge/br_if.c --- a/net/bridge/br_if.c Mon Jun 9 23:16:19 2003 +++ b/net/bridge/br_if.c Mon Jun 9 23:16:19 2003 @@ -170,11 +170,12 @@ struct net_device *dev; int ret = 0; - dev = dev_get_by_name(name); + rtnl_lock(); + dev = __dev_get_by_name(name); if (dev == NULL) - return -ENXIO; /* Could not find device */ + ret = -ENXIO; /* Could not find device */ - if (!(dev->priv_flags & IFF_EBRIDGE)) { + else if (!(dev->priv_flags & IFF_EBRIDGE)) { /* Attempt to delete non bridge device! */ ret = -EPERM; } @@ -186,11 +187,10 @@ else { del_ifs((struct net_bridge *) dev->priv); - - unregister_netdev(dev); + unregister_netdevice(dev); } - dev_put(dev); + rtnl_unlock(); return ret; } diff -Nru a/net/bridge/br_input.c b/net/bridge/br_input.c --- a/net/bridge/br_input.c Mon Jun 9 23:16:08 2003 +++ b/net/bridge/br_input.c Mon Jun 9 23:16:08 2003 @@ -41,9 +41,6 @@ indev = skb->dev; skb->dev = &br->dev; - skb->pkt_type = PACKET_HOST; - skb_push(skb, ETH_HLEN); - skb->protocol = eth_type_trans(skb, &br->dev); NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL, br_pass_frame_up_finish); diff -Nru a/net/core/datagram.c b/net/core/datagram.c --- a/net/core/datagram.c Mon Jun 9 23:16:14 2003 +++ b/net/core/datagram.c Mon Jun 9 23:16:14 2003 @@ -59,7 +59,7 @@ */ static inline int connection_based(struct sock *sk) { - return sk->type == SOCK_SEQPACKET || sk->type == SOCK_STREAM; + return sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM; } /* @@ -70,26 +70,26 @@ int error; DEFINE_WAIT(wait); - prepare_to_wait_exclusive(sk->sleep, &wait, TASK_INTERRUPTIBLE); + prepare_to_wait_exclusive(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); /* Socket errors? */ error = sock_error(sk); if (error) goto out_err; - if (!skb_queue_empty(&sk->receive_queue)) + if (!skb_queue_empty(&sk->sk_receive_queue)) goto out; /* Socket shut down? */ - if (sk->shutdown & RCV_SHUTDOWN) + if (sk->sk_shutdown & RCV_SHUTDOWN) goto out_noerr; /* Sequenced packets can come disconnected. * If so we report the problem */ error = -ENOTCONN; - if (connection_based(sk) && !(sk->state == TCP_ESTABLISHED || - sk->state == TCP_LISTEN)) + if (connection_based(sk) && + !(sk->sk_state == TCP_ESTABLISHED || sk->sk_state == TCP_LISTEN)) goto out_err; /* handle signals */ @@ -99,7 +99,7 @@ error = 0; *timeo_p = schedule_timeout(*timeo_p); out: - finish_wait(sk->sleep, &wait); + finish_wait(sk->sk_sleep, &wait); return error; interrupted: error = sock_intr_errno(*timeo_p); @@ -146,7 +146,9 @@ { struct sk_buff *skb; long timeo; - /* Caller is allowed not to check sk->err before skb_recv_datagram() */ + /* + * Caller is allowed not to check sk->sk_err before skb_recv_datagram() + */ int error = sock_error(sk); if (error) @@ -164,14 +166,15 @@ if (flags & MSG_PEEK) { unsigned long cpu_flags; - spin_lock_irqsave(&sk->receive_queue.lock, cpu_flags); - skb = skb_peek(&sk->receive_queue); + spin_lock_irqsave(&sk->sk_receive_queue.lock, + cpu_flags); + skb = skb_peek(&sk->sk_receive_queue); if (skb) atomic_inc(&skb->users); - spin_unlock_irqrestore(&sk->receive_queue.lock, + spin_unlock_irqrestore(&sk->sk_receive_queue.lock, cpu_flags); } else - skb = skb_dequeue(&sk->receive_queue); + skb = skb_dequeue(&sk->sk_receive_queue); if (skb) return skb; @@ -451,26 +454,26 @@ struct sock *sk = sock->sk; unsigned int mask; - poll_wait(file, sk->sleep, wait); + poll_wait(file, sk->sk_sleep, wait); mask = 0; /* exceptional events? */ - if (sk->err || !skb_queue_empty(&sk->error_queue)) + if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) mask |= POLLERR; - if (sk->shutdown == SHUTDOWN_MASK) + if (sk->sk_shutdown == SHUTDOWN_MASK) mask |= POLLHUP; /* readable? */ - if (!skb_queue_empty(&sk->receive_queue) || - (sk->shutdown & RCV_SHUTDOWN)) + if (!skb_queue_empty(&sk->sk_receive_queue) || + (sk->sk_shutdown & RCV_SHUTDOWN)) mask |= POLLIN | POLLRDNORM; /* Connection-based need to check for termination and startup */ if (connection_based(sk)) { - if (sk->state == TCP_CLOSE) + if (sk->sk_state == TCP_CLOSE) mask |= POLLHUP; /* connection hasn't started yet? */ - if (sk->state == TCP_SYN_SENT) + if (sk->sk_state == TCP_SYN_SENT) return mask; } @@ -478,7 +481,7 @@ if (sock_writeable(sk)) mask |= POLLOUT | POLLWRNORM | POLLWRBAND; else - set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); + set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); return mask; } diff -Nru a/net/core/dev.c b/net/core/dev.c --- a/net/core/dev.c Mon Jun 9 23:16:12 2003 +++ b/net/core/dev.c Mon Jun 9 23:16:12 2003 @@ -2863,10 +2863,6 @@ * */ -extern void net_device_init(void); -extern void ip_auto_config(void); - - /* * This is called single threaded during boot, so no need * to take the rtnl semaphore. @@ -2999,11 +2995,6 @@ #ifdef CONFIG_NET_SCHED pktsched_init(); #endif - /* - * Initialise network devices - */ - - net_device_init(); rc = 0; out: return rc; diff -Nru a/net/core/dst.c b/net/core/dst.c --- a/net/core/dst.c Mon Jun 9 23:16:14 2003 +++ b/net/core/dst.c Mon Jun 9 23:16:14 2003 @@ -1,7 +1,7 @@ /* - * net/dst.c Protocol independent destination cache. + * net/core/dst.c Protocol independent destination cache. * - * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> + * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> * */ diff -Nru a/net/core/dv.c b/net/core/dv.c --- a/net/core/dv.c Mon Jun 9 23:16:11 2003 +++ b/net/core/dv.c Mon Jun 9 23:16:11 2003 @@ -5,8 +5,6 @@ * * Generic frame diversion * - * Version: @(#)eth.c 0.41 09/09/2000 - * * Authors: * Benoit LOCHER: initial integration within the kernel with support for ethernet * Dave Miller: improvement on the code (correctness, performance and source files) diff -Nru a/net/core/filter.c b/net/core/filter.c --- a/net/core/filter.c Mon Jun 9 23:16:09 2003 +++ b/net/core/filter.c Mon Jun 9 23:16:09 2003 @@ -36,14 +36,13 @@ #include <linux/filter.h> /* No hurry in this branch */ - static u8 *load_pointer(struct sk_buff *skb, int k) { u8 *ptr = NULL; - if (k>=SKF_NET_OFF) + if (k >= SKF_NET_OFF) ptr = skb->nh.raw + k - SKF_NET_OFF; - else if (k>=SKF_LL_OFF) + else if (k >= SKF_LL_OFF) ptr = skb->mac.raw + k - SKF_LL_OFF; if (ptr >= skb->head && ptr < skb->tail) @@ -80,268 +79,224 @@ /* * Process array of filter instructions. */ - - for(pc = 0; pc < flen; pc++) - { + for (pc = 0; pc < flen; pc++) { fentry = &filter[pc]; - switch(fentry->code) - { - case BPF_ALU|BPF_ADD|BPF_X: - A += X; - continue; - - case BPF_ALU|BPF_ADD|BPF_K: - A += fentry->k; - continue; - - case BPF_ALU|BPF_SUB|BPF_X: - A -= X; - continue; - - case BPF_ALU|BPF_SUB|BPF_K: - A -= fentry->k; - continue; - - case BPF_ALU|BPF_MUL|BPF_X: - A *= X; - continue; - - case BPF_ALU|BPF_MUL|BPF_K: - A *= fentry->k; - continue; - - case BPF_ALU|BPF_DIV|BPF_X: - if(X == 0) - return (0); - A /= X; - continue; - - case BPF_ALU|BPF_DIV|BPF_K: - if(fentry->k == 0) - return (0); - A /= fentry->k; - continue; - - case BPF_ALU|BPF_AND|BPF_X: - A &= X; - continue; - - case BPF_ALU|BPF_AND|BPF_K: - A &= fentry->k; - continue; - - case BPF_ALU|BPF_OR|BPF_X: - A |= X; - continue; - - case BPF_ALU|BPF_OR|BPF_K: - A |= fentry->k; - continue; - - case BPF_ALU|BPF_LSH|BPF_X: - A <<= X; - continue; - - case BPF_ALU|BPF_LSH|BPF_K: - A <<= fentry->k; - continue; - - case BPF_ALU|BPF_RSH|BPF_X: - A >>= X; - continue; - - case BPF_ALU|BPF_RSH|BPF_K: - A >>= fentry->k; - continue; - - case BPF_ALU|BPF_NEG: - A = -A; - continue; - - case BPF_JMP|BPF_JA: - pc += fentry->k; - continue; - - case BPF_JMP|BPF_JGT|BPF_K: - pc += (A > fentry->k) ? fentry->jt : fentry->jf; - continue; - - case BPF_JMP|BPF_JGE|BPF_K: - pc += (A >= fentry->k) ? fentry->jt : fentry->jf; - continue; - - case BPF_JMP|BPF_JEQ|BPF_K: - pc += (A == fentry->k) ? fentry->jt : fentry->jf; - continue; - - case BPF_JMP|BPF_JSET|BPF_K: - pc += (A & fentry->k) ? fentry->jt : fentry->jf; - continue; - - case BPF_JMP|BPF_JGT|BPF_X: - pc += (A > X) ? fentry->jt : fentry->jf; - continue; - - case BPF_JMP|BPF_JGE|BPF_X: - pc += (A >= X) ? fentry->jt : fentry->jf; - continue; - - case BPF_JMP|BPF_JEQ|BPF_X: - pc += (A == X) ? fentry->jt : fentry->jf; - continue; - - case BPF_JMP|BPF_JSET|BPF_X: - pc += (A & X) ? fentry->jt : fentry->jf; + switch (fentry->code) { + case BPF_ALU|BPF_ADD|BPF_X: + A += X; + continue; + case BPF_ALU|BPF_ADD|BPF_K: + A += fentry->k; + continue; + case BPF_ALU|BPF_SUB|BPF_X: + A -= X; + continue; + case BPF_ALU|BPF_SUB|BPF_K: + A -= fentry->k; + continue; + case BPF_ALU|BPF_MUL|BPF_X: + A *= X; + continue; + case BPF_ALU|BPF_MUL|BPF_K: + A *= fentry->k; + continue; + case BPF_ALU|BPF_DIV|BPF_X: + if (X == 0) + return 0; + A /= X; + continue; + case BPF_ALU|BPF_DIV|BPF_K: + if (fentry->k == 0) + return 0; + A /= fentry->k; + continue; + case BPF_ALU|BPF_AND|BPF_X: + A &= X; + continue; + case BPF_ALU|BPF_AND|BPF_K: + A &= fentry->k; + continue; + case BPF_ALU|BPF_OR|BPF_X: + A |= X; + continue; + case BPF_ALU|BPF_OR|BPF_K: + A |= fentry->k; + continue; + case BPF_ALU|BPF_LSH|BPF_X: + A <<= X; + continue; + case BPF_ALU|BPF_LSH|BPF_K: + A <<= fentry->k; + continue; + case BPF_ALU|BPF_RSH|BPF_X: + A >>= X; + continue; + case BPF_ALU|BPF_RSH|BPF_K: + A >>= fentry->k; + continue; + case BPF_ALU|BPF_NEG: + A = -A; + continue; + case BPF_JMP|BPF_JA: + pc += fentry->k; + continue; + case BPF_JMP|BPF_JGT|BPF_K: + pc += (A > fentry->k) ? fentry->jt : fentry->jf; + continue; + case BPF_JMP|BPF_JGE|BPF_K: + pc += (A >= fentry->k) ? fentry->jt : fentry->jf; + continue; + case BPF_JMP|BPF_JEQ|BPF_K: + pc += (A == fentry->k) ? fentry->jt : fentry->jf; + continue; + case BPF_JMP|BPF_JSET|BPF_K: + pc += (A & fentry->k) ? fentry->jt : fentry->jf; + continue; + case BPF_JMP|BPF_JGT|BPF_X: + pc += (A > X) ? fentry->jt : fentry->jf; + continue; + case BPF_JMP|BPF_JGE|BPF_X: + pc += (A >= X) ? fentry->jt : fentry->jf; + continue; + case BPF_JMP|BPF_JEQ|BPF_X: + pc += (A == X) ? fentry->jt : fentry->jf; + continue; + case BPF_JMP|BPF_JSET|BPF_X: + pc += (A & X) ? fentry->jt : fentry->jf; + continue; + case BPF_LD|BPF_W|BPF_ABS: + k = fentry->k; + load_w: + if (k >= 0 && (unsigned int)(k+sizeof(u32)) <= len) { + A = ntohl(*(u32*)&data[k]); continue; + } + if (k < 0) { + u8 *ptr; - case BPF_LD|BPF_W|BPF_ABS: - k = fentry->k; -load_w: - if(k >= 0 && (unsigned int)(k+sizeof(u32)) <= len) { - A = ntohl(*(u32*)&data[k]); + if (k >= SKF_AD_OFF) + break; + ptr = load_pointer(skb, k); + if (ptr) { + A = ntohl(*(u32*)ptr); continue; } - if (k<0) { - u8 *ptr; - - if (k>=SKF_AD_OFF) - break; - if ((ptr = load_pointer(skb, k)) != NULL) { - A = ntohl(*(u32*)ptr); - continue; - } - } else { - u32 tmp; - if (!skb_copy_bits(skb, k, &tmp, 4)) { - A = ntohl(tmp); - continue; - } + } else { + u32 tmp; + if (!skb_copy_bits(skb, k, &tmp, 4)) { + A = ntohl(tmp); + continue; } - return 0; + } + return 0; + case BPF_LD|BPF_H|BPF_ABS: + k = fentry->k; + load_h: + if (k >= 0 && (unsigned int)(k + sizeof(u16)) <= len) { + A = ntohs(*(u16*)&data[k]); + continue; + } + if (k < 0) { + u8 *ptr; - case BPF_LD|BPF_H|BPF_ABS: - k = fentry->k; -load_h: - if(k >= 0 && (unsigned int) (k + sizeof(u16)) <= len) { - A = ntohs(*(u16*)&data[k]); + if (k >= SKF_AD_OFF) + break; + ptr = load_pointer(skb, k); + if (ptr) { + A = ntohs(*(u16*)ptr); continue; } - if (k<0) { - u8 *ptr; - - if (k>=SKF_AD_OFF) - break; - if ((ptr = load_pointer(skb, k)) != NULL) { - A = ntohs(*(u16*)ptr); - continue; - } - } else { - u16 tmp; - if (!skb_copy_bits(skb, k, &tmp, 2)) { - A = ntohs(tmp); - continue; - } + } else { + u16 tmp; + if (!skb_copy_bits(skb, k, &tmp, 2)) { + A = ntohs(tmp); + continue; } - return 0; - - case BPF_LD|BPF_B|BPF_ABS: - k = fentry->k; + } + return 0; + case BPF_LD|BPF_B|BPF_ABS: + k = fentry->k; load_b: - if(k >= 0 && (unsigned int)k < len) { - A = data[k]; + if (k >= 0 && (unsigned int)k < len) { + A = data[k]; + continue; + } + if (k < 0) { + u8 *ptr; + + if (k >= SKF_AD_OFF) + break; + ptr = load_pointer(skb, k); + if (ptr) { + A = *ptr; continue; } - if (k<0) { - u8 *ptr; - - if (k>=SKF_AD_OFF) - break; - if ((ptr = load_pointer(skb, k)) != NULL) { - A = *ptr; - continue; - } - } else { - u8 tmp; - if (!skb_copy_bits(skb, k, &tmp, 1)) { - A = tmp; - continue; - } + } else { + u8 tmp; + if (!skb_copy_bits(skb, k, &tmp, 1)) { + A = tmp; + continue; } + } + return 0; + case BPF_LD|BPF_W|BPF_LEN: + A = len; + continue; + case BPF_LDX|BPF_W|BPF_LEN: + X = len; + continue; + case BPF_LD|BPF_W|BPF_IND: + k = X + fentry->k; + goto load_w; + case BPF_LD|BPF_H|BPF_IND: + k = X + fentry->k; + goto load_h; + case BPF_LD|BPF_B|BPF_IND: + k = X + fentry->k; + goto load_b; + case BPF_LDX|BPF_B|BPF_MSH: + k = fentry->k; + if (k >= 0 && (unsigned int)k >= len) return 0; - - case BPF_LD|BPF_W|BPF_LEN: - A = len; - continue; - - case BPF_LDX|BPF_W|BPF_LEN: - X = len; - continue; - - case BPF_LD|BPF_W|BPF_IND: - k = X + fentry->k; - goto load_w; - - case BPF_LD|BPF_H|BPF_IND: - k = X + fentry->k; - goto load_h; - - case BPF_LD|BPF_B|BPF_IND: - k = X + fentry->k; - goto load_b; - - case BPF_LDX|BPF_B|BPF_MSH: - k = fentry->k; - if(k >= 0 && (unsigned int)k >= len) - return (0); - X = (data[k] & 0xf) << 2; - continue; - - case BPF_LD|BPF_IMM: - A = fentry->k; - continue; - - case BPF_LDX|BPF_IMM: - X = fentry->k; - continue; - - case BPF_LD|BPF_MEM: - A = mem[fentry->k]; - continue; - - case BPF_LDX|BPF_MEM: - X = mem[fentry->k]; - continue; - - case BPF_MISC|BPF_TAX: - X = A; - continue; - - case BPF_MISC|BPF_TXA: - A = X; - continue; - - case BPF_RET|BPF_K: - return ((unsigned int)fentry->k); - - case BPF_RET|BPF_A: - return ((unsigned int)A); - - case BPF_ST: - mem[fentry->k] = A; - continue; - - case BPF_STX: - mem[fentry->k] = X; - continue; - - default: - /* Invalid instruction counts as RET */ - return (0); + X = (data[k] & 0xf) << 2; + continue; + case BPF_LD|BPF_IMM: + A = fentry->k; + continue; + case BPF_LDX|BPF_IMM: + X = fentry->k; + continue; + case BPF_LD|BPF_MEM: + A = mem[fentry->k]; + continue; + case BPF_LDX|BPF_MEM: + X = mem[fentry->k]; + continue; + case BPF_MISC|BPF_TAX: + X = A; + continue; + case BPF_MISC|BPF_TXA: + A = X; + continue; + case BPF_RET|BPF_K: + return ((unsigned int)fentry->k); + case BPF_RET|BPF_A: + return ((unsigned int)A); + case BPF_ST: + mem[fentry->k] = A; + continue; + case BPF_STX: + mem[fentry->k] = X; + continue; + default: + /* Invalid instruction counts as RET */ + return 0; } - /* Handle ancillary data, which are impossible - (or very difficult) to get parsing packet contents. + /* + * Handle ancillary data, which are impossible + * (or very difficult) to get parsing packet contents. */ switch (k-SKF_AD_OFF) { case SKF_AD_PROTOCOL: @@ -358,7 +313,7 @@ } } - return (0); + return 0; } /** @@ -373,75 +328,55 @@ * * Returns 0 if the rule set is legal or a negative errno code if not. */ - int sk_chk_filter(struct sock_filter *filter, int flen) { struct sock_filter *ftest; - int pc; + int pc; - if ((unsigned int) flen >= (~0U / sizeof(struct sock_filter))) + if ((unsigned int)flen >= (~0U / sizeof(struct sock_filter))) return -EINVAL; - /* - * Check the filter code now. - */ - for(pc = 0; pc < flen; pc++) - { - /* - * All jumps are forward as they are not signed - */ - - ftest = &filter[pc]; - if(BPF_CLASS(ftest->code) == BPF_JMP) - { - /* - * But they mustn't jump off the end. - */ - if(BPF_OP(ftest->code) == BPF_JA) - { - /* Note, the large ftest->k might cause - loops. Compare this with conditional - jumps below, where offsets are limited. --ANK (981016) + /* check the filter code now */ + for (pc = 0; pc < flen; pc++) { + /* all jumps are forward as they are not signed */ + ftest = &filter[pc]; + if (BPF_CLASS(ftest->code) == BPF_JMP) { + /* but they mustn't jump off the end */ + if (BPF_OP(ftest->code) == BPF_JA) { + /* + * Note, the large ftest->k might cause loops. + * Compare this with conditional jumps below, + * where offsets are limited. --ANK (981016) */ if (ftest->k >= (unsigned)(flen-pc-1)) return -EINVAL; - } - else - { - /* - * For conditionals both must be safe - */ - if(pc + ftest->jt +1 >= flen || pc + ftest->jf +1 >= flen) + } else { + /* for conditionals both must be safe */ + if (pc + ftest->jt +1 >= flen || + pc + ftest->jf +1 >= flen) return -EINVAL; } - } + } - /* - * Check that memory operations use valid addresses. - */ - - if (ftest->k >= BPF_MEMWORDS) - { - /* - * But it might not be a memory operation... - */ + /* check that memory operations use valid addresses. */ + if (ftest->k >= BPF_MEMWORDS) { + /* but it might not be a memory operation... */ switch (ftest->code) { case BPF_ST: case BPF_STX: case BPF_LD|BPF_MEM: case BPF_LDX|BPF_MEM: - return -EINVAL; + return -EINVAL; } } - } + } /* - * The program must end with a return. We don't care where they - * jumped within the script (its always forwards) but in the - * end they _will_ hit this. + * The program must end with a return. We don't care where they + * jumped within the script (its always forwards) but in the end + * they _will_ hit this. */ - - return (BPF_CLASS(filter[flen - 1].code) == BPF_RET)?0:-EINVAL; + return (BPF_CLASS(filter[flen - 1].code) == BPF_RET) ? 0 : -EINVAL; } /** @@ -454,7 +389,6 @@ * occurs or there is insufficient memory for the filter a negative * errno code is returned. On success the return is zero. */ - int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk) { struct sk_filter *fp; @@ -463,12 +397,11 @@ /* Make sure new filter is there and in the right amounts. */ if (fprog->filter == NULL || fprog->len > BPF_MAXINSNS) - return (-EINVAL); - - fp = (struct sk_filter *)sock_kmalloc(sk, fsize+sizeof(*fp), GFP_KERNEL); - if(fp == NULL) - return (-ENOMEM); + return -EINVAL; + fp = sock_kmalloc(sk, fsize+sizeof(*fp), GFP_KERNEL); + if (!fp) + return -ENOMEM; if (copy_from_user(fp->insns, fprog->filter, fsize)) { sock_kfree_s(sk, fp, fsize+sizeof(*fp)); return -EFAULT; @@ -477,18 +410,18 @@ atomic_set(&fp->refcnt, 1); fp->len = fprog->len; - if ((err = sk_chk_filter(fp->insns, fp->len))==0) { + err = sk_chk_filter(fp->insns, fp->len); + if (!err) { struct sk_filter *old_fp; - spin_lock_bh(&sk->lock.slock); - old_fp = sk->filter; - sk->filter = fp; - spin_unlock_bh(&sk->lock.slock); + spin_lock_bh(&sk->sk_lock.slock); + old_fp = sk->sk_filter; + sk->sk_filter = fp; + spin_unlock_bh(&sk->sk_lock.slock); fp = old_fp; } if (fp) sk_filter_release(sk, fp); - - return (err); + return err; } diff -Nru a/net/core/flow.c b/net/core/flow.c --- a/net/core/flow.c Mon Jun 9 23:16:06 2003 +++ b/net/core/flow.c Mon Jun 9 23:16:06 2003 @@ -11,8 +11,13 @@ #include <linux/mm.h> #include <linux/random.h> #include <linux/init.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/smp.h> +#include <linux/completion.h> #include <net/flow.h> #include <asm/atomic.h> +#include <asm/semaphore.h> struct flow_cache_entry { struct flow_cache_entry *next; @@ -48,6 +53,14 @@ #define FLOW_HASH_RND_PERIOD (10 * 60 * HZ) +struct flow_flush_info { + void *object; + atomic_t cpuleft; + struct completion completion; +}; +static struct tasklet_struct flow_flush_tasklets[NR_CPUS]; +static DECLARE_MUTEX(flow_flush_sem); + static void flow_cache_new_hashrnd(unsigned long arg) { int i; @@ -169,6 +182,22 @@ } } + if (!fle) { + if (flow_count(cpu) > flow_hwm) + flow_cache_shrink(cpu); + + fle = kmem_cache_alloc(flow_cachep, SLAB_ATOMIC); + if (fle) { + fle->next = *head; + *head = fle; + fle->family = family; + fle->dir = dir; + memcpy(&fle->key, key, sizeof(*key)); + fle->object = NULL; + flow_count(cpu)++; + } + } + { void *obj; atomic_t *obj_ref; @@ -185,28 +214,67 @@ fle->object_ref = obj_ref; if (obj) atomic_inc(fle->object_ref); - } else { - if (flow_count(cpu) > flow_hwm) - flow_cache_shrink(cpu); - - fle = kmem_cache_alloc(flow_cachep, SLAB_ATOMIC); - if (fle) { - fle->next = *head; - *head = fle; - fle->family = family; - fle->dir = dir; - memcpy(&fle->key, key, sizeof(*key)); - fle->genid = atomic_read(&flow_cache_genid); - fle->object = obj; - fle->object_ref = obj_ref; - - flow_count(cpu)++; - } } local_bh_enable(); return obj; } +} + +static void flow_cache_flush_tasklet(unsigned long data) +{ + struct flow_flush_info *info = (void *)data; + void *object = info->object; + int i; + int cpu; + + cpu = smp_processor_id(); + for (i = 0; i < flow_hash_size; i++) { + struct flow_cache_entry *fle, **flp; + + flp = &flow_table[(cpu << flow_hash_shift) + i]; + for (; (fle = *flp) != NULL; flp = &fle->next) { + if (fle->object != object) + continue; + fle->object = NULL; + atomic_dec(fle->object_ref); + } + } + + if (atomic_dec_and_test(&info->cpuleft)) + complete(&info->completion); +} + +static void flow_cache_flush_per_cpu(void *data) +{ + struct flow_flush_info *info = data; + int cpu; + struct tasklet_struct *tasklet; + + cpu = smp_processor_id(); + tasklet = &flow_flush_tasklets[cpu]; + tasklet_init(tasklet, flow_cache_flush_tasklet, (unsigned long)info); + tasklet_schedule(tasklet); +} + +void flow_cache_flush(void *object) +{ + struct flow_flush_info info; + + info.object = object; + atomic_set(&info.cpuleft, num_online_cpus()); + init_completion(&info.completion); + + down(&flow_flush_sem); + + smp_call_function(flow_cache_flush_per_cpu, &info, 1, 0); + local_bh_disable(); + flow_cache_flush_per_cpu(&info); + local_bh_enable(); + + wait_for_completion(&info.completion); + + up(&flow_flush_sem); } static int __init flow_cache_init(void) diff -Nru a/net/core/iovec.c b/net/core/iovec.c --- a/net/core/iovec.c Mon Jun 9 23:16:20 2003 +++ b/net/core/iovec.c Mon Jun 9 23:16:20 2003 @@ -41,35 +41,36 @@ { int size, err, ct; - if(m->msg_namelen) - { - if(mode==VERIFY_READ) - { - err=move_addr_to_kernel(m->msg_name, m->msg_namelen, address); - if(err<0) - goto out; + if (m->msg_namelen) { + if (mode == VERIFY_READ) { + err = move_addr_to_kernel(m->msg_name, m->msg_namelen, + address); + if (err < 0) + return err; } - m->msg_name = address; - } else + } else { m->msg_name = NULL; + } - err = -EFAULT; size = m->msg_iovlen * sizeof(struct iovec); if (copy_from_user(iov, m->msg_iov, size)) - goto out; - m->msg_iov=iov; + return -EFAULT; + + m->msg_iov = iov; + err = 0; - for (err = 0, ct = 0; ct < m->msg_iovlen; ct++) { + for (ct = 0; ct < m->msg_iovlen; ct++) { err += iov[ct].iov_len; - /* Goal is not to verify user data, but to prevent returning - negative value, which is interpreted as errno. - Overflow is still possible, but it is harmless. + /* + * Goal is not to verify user data, but to prevent returning + * negative value, which is interpreted as errno. + * Overflow is still possible, but it is harmless. */ if (err < 0) return -EMSGSIZE; } -out: + return err; } @@ -81,25 +82,20 @@ int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len) { - int err = -EFAULT; - - while(len>0) - { - if(iov->iov_len) - { + while (len > 0) { + if (iov->iov_len) { int copy = min_t(unsigned int, iov->iov_len, len); if (copy_to_user(iov->iov_base, kdata, copy)) - goto out; - kdata+=copy; - len-=copy; - iov->iov_len-=copy; - iov->iov_base+=copy; + return -EFAULT; + kdata += copy; + len -= copy; + iov->iov_len -= copy; + iov->iov_base += copy; } iov++; } - err = 0; -out: - return err; + + return 0; } /* @@ -110,16 +106,14 @@ void memcpy_tokerneliovec(struct iovec *iov, unsigned char *kdata, int len) { - while(len>0) - { - if(iov->iov_len) - { + while (len > 0) { + if (iov->iov_len) { int copy = min_t(unsigned int, iov->iov_len, len); memcpy(iov->iov_base, kdata, copy); - kdata+=copy; - len-=copy; - iov->iov_len-=copy; - iov->iov_base+=copy; + kdata += copy; + len -= copy; + iov->iov_len -= copy; + iov->iov_base += copy; } iov++; } @@ -134,59 +128,47 @@ int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len) { - int err = -EFAULT; - - while(len>0) - { - if(iov->iov_len) - { + while (len > 0) { + if (iov->iov_len) { int copy = min_t(unsigned int, len, iov->iov_len); if (copy_from_user(kdata, iov->iov_base, copy)) - goto out; - len-=copy; - kdata+=copy; - iov->iov_base+=copy; - iov->iov_len-=copy; + return -EFAULT; + len -= copy; + kdata += copy; + iov->iov_base += copy; + iov->iov_len -= copy; } iov++; } - err = 0; -out: - return err; -} + return 0; +} /* * For use with ip_build_xmit */ - int memcpy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset, int len) { - int err = -EFAULT; - /* Skip over the finished iovecs */ - while(offset >= iov->iov_len) - { + while (offset >= iov->iov_len) { offset -= iov->iov_len; iov++; } - while (len > 0) - { + while (len > 0) { u8 *base = iov->iov_base + offset; int copy = min_t(unsigned int, len, iov->iov_len - offset); offset = 0; if (copy_from_user(kdata, base, copy)) - goto out; - len -= copy; + return -EFAULT; + len -= copy; kdata += copy; iov++; } - err = 0; -out: - return err; + + return 0; } /* @@ -197,7 +179,6 @@ * ip_build_xmit must ensure that when fragmenting only the last * call to this function will be unaligned also. */ - int csum_partial_copy_fromiovecend(unsigned char *kdata, struct iovec *iov, int offset, unsigned int len, int *csump) { @@ -205,21 +186,19 @@ int partial_cnt = 0, err = 0; /* Skip over the finished iovecs */ - while (offset >= iov->iov_len) - { + while (offset >= iov->iov_len) { offset -= iov->iov_len; iov++; } - while (len > 0) - { + while (len > 0) { u8 *base = iov->iov_base + offset; int copy = min_t(unsigned int, len, iov->iov_len - offset); offset = 0; + /* There is a remnant from previous iov. */ - if (partial_cnt) - { + if (partial_cnt) { int par_len = 4 - partial_cnt; /* iov component is too short ... */ @@ -227,9 +206,9 @@ if (copy_from_user(kdata, base, copy)) goto out_fault; kdata += copy; - base += copy; + base += copy; partial_cnt += copy; - len -= copy; + len -= copy; iov++; if (len) continue; @@ -247,11 +226,9 @@ partial_cnt = 0; } - if (len > copy) - { + if (len > copy) { partial_cnt = copy % 4; - if (partial_cnt) - { + if (partial_cnt) { copy -= partial_cnt; if (copy_from_user(kdata + copy, base + copy, partial_cnt)) diff -Nru a/net/core/net-sysfs.c b/net/core/net-sysfs.c --- a/net/core/net-sysfs.c Mon Jun 9 23:16:18 2003 +++ b/net/core/net-sysfs.c Mon Jun 9 23:16:18 2003 @@ -16,16 +16,6 @@ #include <net/sock.h> #include <linux/rtnetlink.h> -const char *if_port_text[] = { - [IF_PORT_UNKNOWN] = "unknown", - [IF_PORT_10BASE2] = "BNC", - [IF_PORT_10BASET] = "10baseT", - [IF_PORT_AUI] = "AUI", - [IF_PORT_100BASET] = "100baseT", - [IF_PORT_100BASETX] = "100baseTX", - [IF_PORT_100BASEFX] = "100baseFX" -}; - #define to_net_dev(class) container_of((class), struct net_device, class_dev) /* generate a show function for simple field */ @@ -66,20 +56,6 @@ NETDEVICE_ATTR(features, "%#x\n"); NETDEVICE_ATTR(type, "%d\n"); -/* TODO: only a few devices set this now should fix others. */ -static ssize_t show_port(struct class_device *dev, char *buf) -{ - unsigned char port = to_net_dev(dev)->if_port; - char *cp = buf; - - cp += sprintf(cp, "%d", port); - if (port < ARRAY_SIZE(if_port_text)) - cp += sprintf(cp, " (%s)", if_port_text[port]); - *cp++ ='\n'; - return cp - buf; -} -static CLASS_DEVICE_ATTR(if_port, S_IRUGO, show_port, NULL); - static ssize_t format_addr(char *buf, const unsigned char *addr, int len) { int i; @@ -175,7 +151,6 @@ &class_device_attr_features, &class_device_attr_mtu, &class_device_attr_flags, - &class_device_attr_if_port, &class_device_attr_type, &class_device_attr_address, &class_device_attr_broadcast, @@ -294,7 +269,7 @@ class_dev->class = &net_class; class_dev->class_data = net; - snprintf(class_dev->class_id, BUS_ID_SIZE, net->name); + strlcpy(class_dev->class_id, net->name, BUS_ID_SIZE); if ((ret = class_device_register(class_dev))) goto out; @@ -303,17 +278,18 @@ goto out_unreg; } + + net->stats_kobj.parent = NULL; if (net->get_stats) { struct kobject *k = &net->stats_kobj; - memset(k, 0, sizeof(*k)); k->parent = kobject_get(&class_dev->kobj); if (!k->parent) { ret = -EBUSY; goto out_unreg; } - snprintf(k->name, KOBJ_NAME_LEN, "%s", "statistics"); + strlcpy(k->name, "statistics", KOBJ_NAME_LEN); k->ktype = &netstat_ktype; if((ret = kobject_register(k))) @@ -331,8 +307,9 @@ void netdev_unregister_sysfs(struct net_device *net) { - if (net->get_stats) - kobject_del(&net->stats_kobj); + if (net->stats_kobj.parent) + kobject_unregister(&net->stats_kobj); + class_device_unregister(&net->class_dev); } diff -Nru a/net/core/netfilter.c b/net/core/netfilter.c --- a/net/core/netfilter.c Mon Jun 9 23:16:11 2003 +++ b/net/core/netfilter.c Mon Jun 9 23:16:11 2003 @@ -633,7 +633,7 @@ .fwmark = (*pskb)->nfmark #endif } }, - .oif = (*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0, + .oif = (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0, }; struct net_device *dev_src = NULL; int err; @@ -648,7 +648,7 @@ if ((err=ip_route_output_key(&rt, &fl)) != 0) { printk("route_me_harder: ip_route_output_key(dst=%u.%u.%u.%u, src=%u.%u.%u.%u, oif=%d, tos=0x%x, fwmark=0x%lx) error %d\n", NIPQUAD(iph->daddr), NIPQUAD(iph->saddr), - (*pskb)->sk ? (*pskb)->sk->bound_dev_if : 0, + (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0, RT_TOS(iph->tos)|RTO_CONN, #ifdef CONFIG_IP_ROUTE_FWMARK (*pskb)->nfmark, diff -Nru a/net/core/rtnetlink.c b/net/core/rtnetlink.c --- a/net/core/rtnetlink.c Mon Jun 9 23:16:20 2003 +++ b/net/core/rtnetlink.c Mon Jun 9 23:16:20 2003 @@ -490,10 +490,11 @@ if (rtnl_shlock_nowait()) return; - while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) { + while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { if (rtnetlink_rcv_skb(skb)) { if (skb->len) - skb_queue_head(&sk->receive_queue, skb); + skb_queue_head(&sk->sk_receive_queue, + skb); else kfree_skb(skb); break; @@ -504,7 +505,7 @@ up(&rtnl_sem); netdev_run_todo(); - } while (rtnl && rtnl->receive_queue.qlen); + } while (rtnl && rtnl->sk_receive_queue.qlen); } static struct rtnetlink_link link_rtnetlink_table[RTM_MAX-RTM_BASE+1] = diff -Nru a/net/core/sock.c b/net/core/sock.c --- a/net/core/sock.c Mon Jun 9 23:16:16 2003 +++ b/net/core/sock.c Mon Jun 9 23:16:16 2003 @@ -177,10 +177,9 @@ */ #ifdef SO_DONTLINGER /* Compatibility item... */ - switch(optname) - { + switch (optname) { case SO_DONTLINGER: - __clear_bit(SOCK_LINGER, &sk->flags); + sock_reset_flag(sk, SOCK_LINGER); return 0; } #endif @@ -203,17 +202,17 @@ ret = -EACCES; } else - sk->debug=valbool; + sk->sk_debug = valbool; break; case SO_REUSEADDR: - sk->reuse = valbool; + sk->sk_reuse = valbool; break; case SO_TYPE: case SO_ERROR: ret = -ENOPROTOOPT; break; case SO_DONTROUTE: - sk->localroute=valbool; + sk->sk_localroute = valbool; break; case SO_BROADCAST: sock_valbool_flag(sk, SOCK_BROADCAST, valbool); @@ -227,17 +226,17 @@ if (val > sysctl_wmem_max) val = sysctl_wmem_max; - sk->userlocks |= SOCK_SNDBUF_LOCK; + sk->sk_userlocks |= SOCK_SNDBUF_LOCK; if ((val * 2) < SOCK_MIN_SNDBUF) - sk->sndbuf = SOCK_MIN_SNDBUF; + sk->sk_sndbuf = SOCK_MIN_SNDBUF; else - sk->sndbuf = (val * 2); + sk->sk_sndbuf = val * 2; /* * Wake up sending tasks if we * upped the value. */ - sk->write_space(sk); + sk->sk_write_space(sk); break; case SO_RCVBUF: @@ -249,20 +248,18 @@ if (val > sysctl_rmem_max) val = sysctl_rmem_max; - sk->userlocks |= SOCK_RCVBUF_LOCK; + sk->sk_userlocks |= SOCK_RCVBUF_LOCK; /* FIXME: is this lower bound the right one? */ if ((val * 2) < SOCK_MIN_RCVBUF) - sk->rcvbuf = SOCK_MIN_RCVBUF; + sk->sk_rcvbuf = SOCK_MIN_RCVBUF; else - sk->rcvbuf = (val * 2); + sk->sk_rcvbuf = val * 2; break; case SO_KEEPALIVE: #ifdef CONFIG_INET - if (sk->protocol == IPPROTO_TCP) - { + if (sk->sk_protocol == IPPROTO_TCP) tcp_set_keepalive(sk, valbool); - } #endif sock_valbool_flag(sk, SOCK_KEEPOPEN, valbool); break; @@ -272,12 +269,12 @@ break; case SO_NO_CHECK: - sk->no_check = valbool; + sk->sk_no_check = valbool; break; case SO_PRIORITY: if ((val >= 0 && val <= 6) || capable(CAP_NET_ADMIN)) - sk->priority = val; + sk->sk_priority = val; else ret = -EPERM; break; @@ -291,16 +288,16 @@ ret = -EFAULT; break; } - if(ling.l_onoff==0) { - __clear_bit(SOCK_LINGER, &sk->flags); - } else { + if (!ling.l_onoff) + sock_reset_flag(sk, SOCK_LINGER); + else { #if (BITS_PER_LONG == 32) if (ling.l_linger >= MAX_SCHEDULE_TIMEOUT/HZ) - sk->lingertime=MAX_SCHEDULE_TIMEOUT; + sk->sk_lingertime = MAX_SCHEDULE_TIMEOUT; else #endif - sk->lingertime=ling.l_linger*HZ; - __set_bit(SOCK_LINGER, &sk->flags); + sk->sk_lingertime = ling.l_linger * HZ; + sock_set_flag(sk, SOCK_LINGER); } break; @@ -313,21 +310,21 @@ break; case SO_TIMESTAMP: - sk->rcvtstamp = valbool; + sk->sk_rcvtstamp = valbool; break; case SO_RCVLOWAT: if (val < 0) val = INT_MAX; - sk->rcvlowat = val ? : 1; + sk->sk_rcvlowat = val ? : 1; break; case SO_RCVTIMEO: - ret = sock_set_timeout(&sk->rcvtimeo, optval, optlen); + ret = sock_set_timeout(&sk->sk_rcvtimeo, optval, optlen); break; case SO_SNDTIMEO: - ret = sock_set_timeout(&sk->sndtimeo, optval, optlen); + ret = sock_set_timeout(&sk->sk_sndtimeo, optval, optlen); break; #ifdef CONFIG_NETDEVICES @@ -348,7 +345,7 @@ */ if (!valbool) { - sk->bound_dev_if = 0; + sk->sk_bound_dev_if = 0; } else { if (optlen > IFNAMSIZ) optlen = IFNAMSIZ; @@ -361,14 +358,14 @@ sk_dst_reset(sk); if (devname[0] == '\0') { - sk->bound_dev_if = 0; + sk->sk_bound_dev_if = 0; } else { struct net_device *dev = dev_get_by_name(devname); if (!dev) { ret = -ENODEV; break; } - sk->bound_dev_if = dev->ifindex; + sk->sk_bound_dev_if = dev->ifindex; dev_put(dev); } } @@ -391,15 +388,15 @@ break; case SO_DETACH_FILTER: - spin_lock_bh(&sk->lock.slock); - filter = sk->filter; + spin_lock_bh(&sk->sk_lock.slock); + filter = sk->sk_filter; if (filter) { - sk->filter = NULL; - spin_unlock_bh(&sk->lock.slock); + sk->sk_filter = NULL; + spin_unlock_bh(&sk->sk_lock.slock); sk_filter_release(sk, filter); break; } - spin_unlock_bh(&sk->lock.slock); + spin_unlock_bh(&sk->sk_lock.slock); ret = -ENONET; break; @@ -436,59 +433,59 @@ switch(optname) { case SO_DEBUG: - v.val = sk->debug; + v.val = sk->sk_debug; break; case SO_DONTROUTE: - v.val = sk->localroute; + v.val = sk->sk_localroute; break; case SO_BROADCAST: - v.val= test_bit(SOCK_BROADCAST, &sk->flags); + v.val = !!sock_flag(sk, SOCK_BROADCAST); break; case SO_SNDBUF: - v.val=sk->sndbuf; + v.val = sk->sk_sndbuf; break; case SO_RCVBUF: - v.val =sk->rcvbuf; + v.val = sk->sk_rcvbuf; break; case SO_REUSEADDR: - v.val = sk->reuse; + v.val = sk->sk_reuse; break; case SO_KEEPALIVE: - v.val = test_bit(SOCK_KEEPOPEN, &sk->flags); + v.val = !!sock_flag(sk, SOCK_KEEPOPEN); break; case SO_TYPE: - v.val = sk->type; + v.val = sk->sk_type; break; case SO_ERROR: v.val = -sock_error(sk); if(v.val==0) - v.val=xchg(&sk->err_soft,0); + v.val = xchg(&sk->sk_err_soft, 0); break; case SO_OOBINLINE: - v.val = test_bit(SOCK_URGINLINE, &sk->flags); + v.val = !!sock_flag(sk, SOCK_URGINLINE); break; case SO_NO_CHECK: - v.val = sk->no_check; + v.val = sk->sk_no_check; break; case SO_PRIORITY: - v.val = sk->priority; + v.val = sk->sk_priority; break; case SO_LINGER: - lv=sizeof(v.ling); - v.ling.l_onoff = test_bit(SOCK_LINGER, &sk->flags); - v.ling.l_linger=sk->lingertime/HZ; + lv = sizeof(v.ling); + v.ling.l_onoff = !!sock_flag(sk, SOCK_LINGER); + v.ling.l_linger = sk->sk_lingertime / HZ; break; case SO_BSDCOMPAT: @@ -496,33 +493,33 @@ break; case SO_TIMESTAMP: - v.val = sk->rcvtstamp; + v.val = sk->sk_rcvtstamp; break; case SO_RCVTIMEO: lv=sizeof(struct timeval); - if (sk->rcvtimeo == MAX_SCHEDULE_TIMEOUT) { + if (sk->sk_rcvtimeo == MAX_SCHEDULE_TIMEOUT) { v.tm.tv_sec = 0; v.tm.tv_usec = 0; } else { - v.tm.tv_sec = sk->rcvtimeo/HZ; - v.tm.tv_usec = ((sk->rcvtimeo%HZ)*1000)/HZ; + v.tm.tv_sec = sk->sk_rcvtimeo / HZ; + v.tm.tv_usec = ((sk->sk_rcvtimeo % HZ) * 1000) / HZ; } break; case SO_SNDTIMEO: lv=sizeof(struct timeval); - if (sk->sndtimeo == MAX_SCHEDULE_TIMEOUT) { + if (sk->sk_sndtimeo == MAX_SCHEDULE_TIMEOUT) { v.tm.tv_sec = 0; v.tm.tv_usec = 0; } else { - v.tm.tv_sec = sk->sndtimeo/HZ; - v.tm.tv_usec = ((sk->sndtimeo%HZ)*1000)/HZ; + v.tm.tv_sec = sk->sk_sndtimeo / HZ; + v.tm.tv_usec = ((sk->sk_sndtimeo % HZ) * 1000) / HZ; } break; case SO_RCVLOWAT: - v.val = sk->rcvlowat; + v.val = sk->sk_rcvlowat; break; case SO_SNDLOWAT: @@ -534,9 +531,9 @@ break; case SO_PEERCRED: - if (len > sizeof(sk->peercred)) - len = sizeof(sk->peercred); - if (copy_to_user(optval, &sk->peercred, len)) + if (len > sizeof(sk->sk_peercred)) + len = sizeof(sk->sk_peercred); + if (copy_to_user(optval, &sk->sk_peercred, len)) return -EFAULT; goto lenout; @@ -557,7 +554,7 @@ * the UNIX standard wants it for whatever reason... -DaveM */ case SO_ACCEPTCONN: - v.val = (sk->state == TCP_LISTEN); + v.val = sk->sk_state == TCP_LISTEN; break; default: @@ -598,10 +595,10 @@ if (zero_it) { memset(sk, 0, zero_it == 1 ? sizeof(struct sock) : zero_it); - sk->family = family; + sk->sk_family = family; sock_lock_init(sk); } - sk->slab = slab; + sk->sk_slab = slab; } return sk; } @@ -609,21 +606,22 @@ void sk_free(struct sock *sk) { struct sk_filter *filter; - struct module *owner = sk->owner; + struct module *owner = sk->sk_owner; - if (sk->destruct) - sk->destruct(sk); + if (sk->sk_destruct) + sk->sk_destruct(sk); - filter = sk->filter; + filter = sk->sk_filter; if (filter) { sk_filter_release(sk, filter); - sk->filter = NULL; + sk->sk_filter = NULL; } - if (atomic_read(&sk->omem_alloc)) - printk(KERN_DEBUG "sk_free: optmem leakage (%d bytes) detected.\n", atomic_read(&sk->omem_alloc)); + if (atomic_read(&sk->sk_omem_alloc)) + printk(KERN_DEBUG "%s: optmem leakage (%d bytes) detected.\n", + __FUNCTION__, atomic_read(&sk->sk_omem_alloc)); - kmem_cache_free(sk->slab, sk); + kmem_cache_free(sk->sk_slab, sk); module_put(owner); } @@ -658,9 +656,9 @@ struct sock *sk = skb->sk; /* In case it might be waiting for more memory. */ - atomic_sub(skb->truesize, &sk->wmem_alloc); - if (!sk->use_write_queue) - sk->write_space(sk); + atomic_sub(skb->truesize, &sk->sk_wmem_alloc); + if (!sk->sk_use_write_queue) + sk->sk_write_space(sk); sock_put(sk); } @@ -671,7 +669,7 @@ { struct sock *sk = skb->sk; - atomic_sub(skb->truesize, &sk->rmem_alloc); + atomic_sub(skb->truesize, &sk->sk_rmem_alloc); } /* @@ -679,7 +677,7 @@ */ struct sk_buff *sock_wmalloc(struct sock *sk, unsigned long size, int force, int priority) { - if (force || atomic_read(&sk->wmem_alloc) < sk->sndbuf) { + if (force || atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf) { struct sk_buff * skb = alloc_skb(size, priority); if (skb) { skb_set_owner_w(skb, sk); @@ -694,7 +692,7 @@ */ struct sk_buff *sock_rmalloc(struct sock *sk, unsigned long size, int force, int priority) { - if (force || atomic_read(&sk->rmem_alloc) < sk->rcvbuf) { + if (force || atomic_read(&sk->sk_rmem_alloc) < sk->sk_rcvbuf) { struct sk_buff *skb = alloc_skb(size, priority); if (skb) { skb_set_owner_r(skb, sk); @@ -710,16 +708,16 @@ void *sock_kmalloc(struct sock *sk, int size, int priority) { if ((unsigned)size <= sysctl_optmem_max && - atomic_read(&sk->omem_alloc)+size < sysctl_optmem_max) { + atomic_read(&sk->sk_omem_alloc) + size < sysctl_optmem_max) { void *mem; /* First do the add, to avoid the race if kmalloc * might sleep. */ - atomic_add(size, &sk->omem_alloc); + atomic_add(size, &sk->sk_omem_alloc); mem = kmalloc(size, priority); if (mem) return mem; - atomic_sub(size, &sk->omem_alloc); + atomic_sub(size, &sk->sk_omem_alloc); } return NULL; } @@ -730,7 +728,7 @@ void sock_kfree_s(struct sock *sk, void *mem, int size) { kfree(mem); - atomic_sub(size, &sk->omem_alloc); + atomic_sub(size, &sk->sk_omem_alloc); } /* It is almost wait_for_tcp_memory minus release_sock/lock_sock. @@ -740,23 +738,23 @@ { DEFINE_WAIT(wait); - clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); + clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); for (;;) { if (!timeo) break; if (signal_pending(current)) break; - set_bit(SOCK_NOSPACE, &sk->socket->flags); - prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE); - if (atomic_read(&sk->wmem_alloc) < sk->sndbuf) + set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); + prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); + if (atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf) break; - if (sk->shutdown & SEND_SHUTDOWN) + if (sk->sk_shutdown & SEND_SHUTDOWN) break; - if (sk->err) + if (sk->sk_err) break; timeo = schedule_timeout(timeo); } - finish_wait(sk->sleep, &wait); + finish_wait(sk->sk_sleep, &wait); return timeo; } @@ -773,7 +771,7 @@ long timeo; int err; - gfp_mask = sk->allocation; + gfp_mask = sk->sk_allocation; if (gfp_mask & __GFP_WAIT) gfp_mask |= __GFP_REPEAT; @@ -784,11 +782,11 @@ goto failure; err = -EPIPE; - if (sk->shutdown & SEND_SHUTDOWN) + if (sk->sk_shutdown & SEND_SHUTDOWN) goto failure; - if (atomic_read(&sk->wmem_alloc) < sk->sndbuf) { - skb = alloc_skb(header_len, sk->allocation); + if (atomic_read(&sk->sk_wmem_alloc) < sk->sk_sndbuf) { + skb = alloc_skb(header_len, sk->sk_allocation); if (skb) { int npages; int i; @@ -804,7 +802,7 @@ struct page *page; skb_frag_t *frag; - page = alloc_pages(sk->allocation, 0); + page = alloc_pages(sk->sk_allocation, 0); if (!page) { err = -ENOBUFS; skb_shinfo(skb)->nr_frags = i; @@ -827,8 +825,8 @@ err = -ENOBUFS; goto failure; } - set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); - set_bit(SOCK_NOSPACE, &sk->socket->flags); + set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); + set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); err = -EAGAIN; if (!timeo) goto failure; @@ -858,35 +856,35 @@ DEFINE_WAIT(wait); for(;;) { - prepare_to_wait_exclusive(&sk->lock.wq, &wait, + prepare_to_wait_exclusive(&sk->sk_lock.wq, &wait, TASK_UNINTERRUPTIBLE); - spin_unlock_bh(&sk->lock.slock); + spin_unlock_bh(&sk->sk_lock.slock); schedule(); - spin_lock_bh(&sk->lock.slock); + spin_lock_bh(&sk->sk_lock.slock); if(!sock_owned_by_user(sk)) break; } - finish_wait(&sk->lock.wq, &wait); + finish_wait(&sk->sk_lock.wq, &wait); } void __release_sock(struct sock *sk) { - struct sk_buff *skb = sk->backlog.head; + struct sk_buff *skb = sk->sk_backlog.head; do { - sk->backlog.head = sk->backlog.tail = NULL; + sk->sk_backlog.head = sk->sk_backlog.tail = NULL; bh_unlock_sock(sk); do { struct sk_buff *next = skb->next; skb->next = NULL; - sk->backlog_rcv(sk, skb); + sk->sk_backlog_rcv(sk, skb); skb = next; } while (skb != NULL); bh_lock_sock(sk); - } while((skb = sk->backlog.head) != NULL); + } while((skb = sk->sk_backlog.head) != NULL); } /* @@ -1015,101 +1013,101 @@ void sock_def_wakeup(struct sock *sk) { - read_lock(&sk->callback_lock); - if (sk->sleep && waitqueue_active(sk->sleep)) - wake_up_interruptible_all(sk->sleep); - read_unlock(&sk->callback_lock); + read_lock(&sk->sk_callback_lock); + if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) + wake_up_interruptible_all(sk->sk_sleep); + read_unlock(&sk->sk_callback_lock); } void sock_def_error_report(struct sock *sk) { - read_lock(&sk->callback_lock); - if (sk->sleep && waitqueue_active(sk->sleep)) - wake_up_interruptible(sk->sleep); + read_lock(&sk->sk_callback_lock); + if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) + wake_up_interruptible(sk->sk_sleep); sk_wake_async(sk,0,POLL_ERR); - read_unlock(&sk->callback_lock); + read_unlock(&sk->sk_callback_lock); } void sock_def_readable(struct sock *sk, int len) { - read_lock(&sk->callback_lock); - if (sk->sleep && waitqueue_active(sk->sleep)) - wake_up_interruptible(sk->sleep); + read_lock(&sk->sk_callback_lock); + if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) + wake_up_interruptible(sk->sk_sleep); sk_wake_async(sk,1,POLL_IN); - read_unlock(&sk->callback_lock); + read_unlock(&sk->sk_callback_lock); } void sock_def_write_space(struct sock *sk) { - read_lock(&sk->callback_lock); + read_lock(&sk->sk_callback_lock); /* Do not wake up a writer until he can make "significant" * progress. --DaveM */ - if((atomic_read(&sk->wmem_alloc) << 1) <= sk->sndbuf) { - if (sk->sleep && waitqueue_active(sk->sleep)) - wake_up_interruptible(sk->sleep); + if((atomic_read(&sk->sk_wmem_alloc) << 1) <= sk->sk_sndbuf) { + if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) + wake_up_interruptible(sk->sk_sleep); /* Should agree with poll, otherwise some programs break */ if (sock_writeable(sk)) sk_wake_async(sk, 2, POLL_OUT); } - read_unlock(&sk->callback_lock); + read_unlock(&sk->sk_callback_lock); } void sock_def_destruct(struct sock *sk) { - if (sk->protinfo) - kfree(sk->protinfo); + if (sk->sk_protinfo) + kfree(sk->sk_protinfo); } void sk_send_sigurg(struct sock *sk) { - if (sk->socket && sk->socket->file) - if (send_sigurg(&sk->socket->file->f_owner)) + if (sk->sk_socket && sk->sk_socket->file) + if (send_sigurg(&sk->sk_socket->file->f_owner)) sk_wake_async(sk, 3, POLL_PRI); } void sock_init_data(struct socket *sock, struct sock *sk) { - skb_queue_head_init(&sk->receive_queue); - skb_queue_head_init(&sk->write_queue); - skb_queue_head_init(&sk->error_queue); + skb_queue_head_init(&sk->sk_receive_queue); + skb_queue_head_init(&sk->sk_write_queue); + skb_queue_head_init(&sk->sk_error_queue); - init_timer(&sk->timer); + init_timer(&sk->sk_timer); - sk->allocation = GFP_KERNEL; - sk->rcvbuf = sysctl_rmem_default; - sk->sndbuf = sysctl_wmem_default; - sk->state = TCP_CLOSE; - sk->zapped = 1; - sk->socket = sock; + sk->sk_allocation = GFP_KERNEL; + sk->sk_rcvbuf = sysctl_rmem_default; + sk->sk_sndbuf = sysctl_wmem_default; + sk->sk_state = TCP_CLOSE; + sk->sk_zapped = 1; + sk->sk_socket = sock; if(sock) { - sk->type = sock->type; - sk->sleep = &sock->wait; + sk->sk_type = sock->type; + sk->sk_sleep = &sock->wait; sock->sk = sk; } else - sk->sleep = NULL; + sk->sk_sleep = NULL; - sk->dst_lock = RW_LOCK_UNLOCKED; - sk->callback_lock = RW_LOCK_UNLOCKED; + sk->sk_dst_lock = RW_LOCK_UNLOCKED; + sk->sk_callback_lock = RW_LOCK_UNLOCKED; - sk->state_change = sock_def_wakeup; - sk->data_ready = sock_def_readable; - sk->write_space = sock_def_write_space; - sk->error_report = sock_def_error_report; - sk->destruct = sock_def_destruct; - - sk->peercred.pid = 0; - sk->peercred.uid = -1; - sk->peercred.gid = -1; - sk->rcvlowat = 1; - sk->rcvtimeo = MAX_SCHEDULE_TIMEOUT; - sk->sndtimeo = MAX_SCHEDULE_TIMEOUT; - sk->owner = NULL; + sk->sk_state_change = sock_def_wakeup; + sk->sk_data_ready = sock_def_readable; + sk->sk_write_space = sock_def_write_space; + sk->sk_error_report = sock_def_error_report; + sk->sk_destruct = sock_def_destruct; + + sk->sk_peercred.pid = 0; + sk->sk_peercred.uid = -1; + sk->sk_peercred.gid = -1; + sk->sk_rcvlowat = 1; + sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT; + sk->sk_sndtimeo = MAX_SCHEDULE_TIMEOUT; + sk->sk_owner = NULL; - atomic_set(&sk->refcnt, 1); + atomic_set(&sk->sk_refcnt, 1); } diff -Nru a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c --- a/net/decnet/af_decnet.c Mon Jun 9 23:16:13 2003 +++ b/net/decnet/af_decnet.c Mon Jun 9 23:16:13 2003 @@ -180,7 +180,7 @@ struct dn_scp *scp = DN_SK(sk); if (scp->addrloc == port) return -1; - sk = sk->next; + sk = sk->sk_next; } return 0; } @@ -212,9 +212,9 @@ struct sock **skp; int rv = -EUSERS; - if (sk->next) + if (sk->sk_next) BUG(); - if (sk->pprev) + if (sk->sk_pprev) BUG(); write_lock_bh(&dn_hash_lock); @@ -226,8 +226,8 @@ if ((skp = dn_find_list(sk)) == NULL) goto out; - sk->next = *skp; - sk->pprev = skp; + sk->sk_next = *skp; + sk->sk_pprev = skp; *skp = sk; rv = 0; out: @@ -237,36 +237,36 @@ static void dn_unhash_sock(struct sock *sk) { - struct sock **skp = sk->pprev; + struct sock **skp = sk->sk_pprev; if (skp == NULL) return; write_lock(&dn_hash_lock); while(*skp != sk) - skp = &((*skp)->next); - *skp = sk->next; + skp = &((*skp)->sk_next); + *skp = sk->sk_next; write_unlock(&dn_hash_lock); - sk->next = NULL; - sk->pprev = NULL; + sk->sk_next = NULL; + sk->sk_pprev = NULL; } static void dn_unhash_sock_bh(struct sock *sk) { - struct sock **skp = sk->pprev; + struct sock **skp = sk->sk_pprev; if (skp == NULL) return; write_lock_bh(&dn_hash_lock); while(*skp != sk) - skp = &((*skp)->next); - *skp = sk->next; + skp = &((*skp)->sk_next); + *skp = sk->sk_next; write_unlock_bh(&dn_hash_lock); - sk->next = NULL; - sk->pprev = NULL; + sk->sk_next = NULL; + sk->sk_pprev = NULL; } struct sock **listen_hash(struct sockaddr_dn *addr) @@ -292,7 +292,7 @@ */ static void dn_rehash_sock(struct sock *sk) { - struct sock **skp = sk->pprev; + struct sock **skp = sk->sk_pprev; struct dn_scp *scp = DN_SK(sk); if (scp->addr.sdn_flags & SDF_WILD) @@ -300,14 +300,14 @@ write_lock_bh(&dn_hash_lock); while(*skp != sk) - skp = &((*skp)->next); - *skp = sk->next; + skp = &((*skp)->sk_next); + *skp = sk->sk_next; DN_SK(sk)->addrloc = 0; skp = listen_hash(&DN_SK(sk)->addr); - sk->next = *skp; - sk->pprev = skp; + sk->sk_next = *skp; + sk->sk_pprev = skp; *skp = sk; write_unlock_bh(&dn_hash_lock); } @@ -405,9 +405,9 @@ struct sock *sk; read_lock(&dn_hash_lock); - for(sk = *skp; sk != NULL; sk = sk->next) { + for(sk = *skp; sk; sk = sk->sk_next) { struct dn_scp *scp = DN_SK(sk); - if (sk->state != TCP_LISTEN) + if (sk->sk_state != TCP_LISTEN) continue; if (scp->addr.sdn_objnum) { if (scp->addr.sdn_objnum != addr->sdn_objnum) @@ -425,7 +425,7 @@ return sk; } - if (dn_wild_sk && (dn_wild_sk->state == TCP_LISTEN)) + if (dn_wild_sk && (dn_wild_sk->sk_state == TCP_LISTEN)) sock_hold((sk = dn_wild_sk)); read_unlock(&dn_hash_lock); @@ -440,7 +440,7 @@ read_lock(&dn_hash_lock); sk = dn_sk_hash[cb->dst_port & DN_SK_HASH_MASK]; - for (; sk != NULL; sk = sk->next) { + for (; sk; sk = sk->sk_next) { scp = DN_SK(sk); if (cb->src != dn_saddr2dn(&scp->peer)) continue; @@ -469,7 +469,7 @@ skb_queue_purge(&scp->other_xmit_queue); skb_queue_purge(&scp->other_receive_queue); - dst_release(xchg(&sk->dst_cache, NULL)); + dst_release(xchg(&sk->sk_dst_cache, NULL)); } struct sock *dn_alloc_sock(struct socket *sock, int gfp) @@ -488,12 +488,12 @@ sock_init_data(sock, sk); sk_set_owner(sk, THIS_MODULE); - sk->backlog_rcv = dn_nsp_backlog_rcv; - sk->destruct = dn_destruct; - sk->no_check = 1; - sk->family = PF_DECnet; - sk->protocol = 0; - sk->allocation = gfp; + sk->sk_backlog_rcv = dn_nsp_backlog_rcv; + sk->sk_destruct = dn_destruct; + sk->sk_no_check = 1; + sk->sk_family = PF_DECnet; + sk->sk_protocol = 0; + sk->sk_allocation = gfp; /* Initialization of DECnet Session Control Port */ scp->state = DN_O; /* Open */ @@ -600,7 +600,7 @@ scp->persist = (HZ * decnet_time_wait); - if (sk->socket) + if (sk->sk_socket) return 0; dn_stop_fast_timer(sk); /* unlikely, but possible that this is runninng */ @@ -619,16 +619,17 @@ scp->nsp_rxtshift = 0; /* reset back off */ - if (sk->socket) { - if (sk->socket->state != SS_UNCONNECTED) - sk->socket->state = SS_DISCONNECTING; + if (sk->sk_socket) { + if (sk->sk_socket->state != SS_UNCONNECTED) + sk->sk_socket->state = SS_DISCONNECTING; } - sk->state = TCP_CLOSE; + sk->sk_state = TCP_CLOSE; switch(scp->state) { case DN_DN: - dn_nsp_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC, sk->allocation); + dn_nsp_send_disc(sk, NSP_DISCCONF, NSP_REASON_DC, + sk->sk_allocation); scp->persist_fxn = dn_destroy_timer; scp->persist = dn_nsp_persist(sk); break; @@ -640,7 +641,7 @@ case DN_DI: case DN_DR: disc_reject: - dn_nsp_send_disc(sk, NSP_DISCINIT, 0, sk->allocation); + dn_nsp_send_disc(sk, NSP_DISCINIT, 0, sk->sk_allocation); case DN_NC: case DN_NR: case DN_RJ: @@ -697,7 +698,7 @@ if ((sk = dn_alloc_sock(sock, GFP_KERNEL)) == NULL) return -ENOBUFS; - sk->protocol = protocol; + sk->sk_protocol = protocol; return 0; } @@ -777,13 +778,13 @@ rv = -EINVAL; lock_sock(sk); - if (sk->zapped != 0) { + if (sk->sk_zapped) { memcpy(&scp->addr, saddr, addr_len); - sk->zapped = 0; + sk->sk_zapped = 0; rv = dn_hash_sock(sk); if (rv) { - sk->zapped = 1; + sk->sk_zapped = 1; } } release_sock(sk); @@ -798,7 +799,7 @@ struct dn_scp *scp = DN_SK(sk); int rv; - sk->zapped = 0; + sk->sk_zapped = 0; scp->addr.sdn_flags = 0; scp->addr.sdn_objnum = 0; @@ -823,7 +824,7 @@ if (rv == 0) { rv = dn_hash_sock(sk); if (rv) { - sk->zapped = 1; + sk->sk_zapped = 1; } } @@ -843,7 +844,7 @@ scp->segsize_loc = dst_path_metric(__sk_dst_get(sk), RTAX_ADVMSS); dn_send_conn_conf(sk, allocation); - prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE); + prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); for(;;) { release_sock(sk); if (scp->state == DN_CC) @@ -861,13 +862,13 @@ err = -EAGAIN; if (!*timeo) break; - prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE); + prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); } - finish_wait(sk->sleep, &wait); + finish_wait(sk->sk_sleep, &wait); if (err == 0) { - sk->socket->state = SS_CONNECTED; + sk->sk_socket->state = SS_CONNECTED; } else if (scp->state != DN_CC) { - sk->socket->state = SS_UNCONNECTED; + sk->sk_socket->state = SS_UNCONNECTED; } return err; } @@ -884,7 +885,7 @@ if (!*timeo) return -EALREADY; - prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE); + prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); for(;;) { release_sock(sk); if (scp->state == DN_CI || scp->state == DN_CC) @@ -902,21 +903,21 @@ err = -ETIMEDOUT; if (!*timeo) break; - prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE); + prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); } - finish_wait(sk->sleep, &wait); + finish_wait(sk->sk_sleep, &wait); out: if (err == 0) { - sk->socket->state = SS_CONNECTED; + sk->sk_socket->state = SS_CONNECTED; } else if (scp->state != DN_CI && scp->state != DN_CC) { - sk->socket->state = SS_UNCONNECTED; + sk->sk_socket->state = SS_UNCONNECTED; } return err; } static int __dn_connect(struct sock *sk, struct sockaddr_dn *addr, int addrlen, long *timeo, int flags) { - struct socket *sock = sk->socket; + struct socket *sock = sk->sk_socket; struct dn_scp *scp = DN_SK(sk); int err = -EISCONN; struct flowi fl; @@ -949,8 +950,8 @@ if (addr->sdn_flags & SDF_WILD) goto out; - if (sk->zapped) { - err = dn_auto_bind(sk->socket); + if (sk->sk_zapped) { + err = dn_auto_bind(sk->sk_socket); if (err) goto out; } @@ -959,17 +960,17 @@ err = -EHOSTUNREACH; memset(&fl, 0, sizeof(fl)); - fl.oif = sk->bound_dev_if; + fl.oif = sk->sk_bound_dev_if; fl.fld_dst = dn_saddr2dn(&scp->peer); fl.fld_src = dn_saddr2dn(&scp->addr); dn_sk_ports_copy(&fl, scp); fl.proto = DNPROTO_NSP; - if (dn_route_output_sock(&sk->dst_cache, &fl, sk, flags) < 0) + if (dn_route_output_sock(&sk->sk_dst_cache, &fl, sk, flags) < 0) goto out; - sk->route_caps = sk->dst_cache->dev->features; + sk->sk_route_caps = sk->sk_dst_cache->dev->features; sock->state = SS_CONNECTING; scp->state = DN_CI; - scp->segsize_loc = dst_path_metric(sk->dst_cache, RTAX_ADVMSS); + scp->segsize_loc = dst_path_metric(sk->sk_dst_cache, RTAX_ADVMSS); dn_nsp_send_conninit(sk, NSP_CI); err = -EINPROGRESS; @@ -1002,7 +1003,7 @@ case DN_RUN: return 0; case DN_CR: - return dn_confirm_accept(sk, timeo, sk->allocation); + return dn_confirm_accept(sk, timeo, sk->sk_allocation); case DN_CI: case DN_CC: return dn_wait_run(sk, timeo); @@ -1050,19 +1051,19 @@ struct sk_buff *skb = NULL; int err = 0; - prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE); + prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); for(;;) { release_sock(sk); - skb = skb_dequeue(&sk->receive_queue); + skb = skb_dequeue(&sk->sk_receive_queue); if (skb == NULL) { *timeo = schedule_timeout(*timeo); - skb = skb_dequeue(&sk->receive_queue); + skb = skb_dequeue(&sk->sk_receive_queue); } lock_sock(sk); if (skb != NULL) break; err = -EINVAL; - if (sk->state != TCP_LISTEN) + if (sk->sk_state != TCP_LISTEN) break; err = sock_intr_errno(*timeo); if (signal_pending(current)) @@ -1070,9 +1071,9 @@ err = -EAGAIN; if (!*timeo) break; - prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE); + prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); } - finish_wait(sk->sleep, &wait); + finish_wait(sk->sk_sleep, &wait); return skb == NULL ? ERR_PTR(err) : skb; } @@ -1089,12 +1090,12 @@ lock_sock(sk); - if (sk->state != TCP_LISTEN || DN_SK(sk)->state != DN_O) { + if (sk->sk_state != TCP_LISTEN || DN_SK(sk)->state != DN_O) { release_sock(sk); return -EINVAL; } - skb = skb_dequeue(&sk->receive_queue); + skb = skb_dequeue(&sk->sk_receive_queue); if (skb == NULL) { skb = dn_wait_for_connect(sk, &timeo); if (IS_ERR(skb)) { @@ -1104,8 +1105,8 @@ } cb = DN_SKB_CB(skb); - sk->ack_backlog--; - newsk = dn_alloc_sock(newsock, sk->allocation); + sk->sk_ack_backlog--; + newsk = dn_alloc_sock(newsock, sk->sk_allocation); if (newsk == NULL) { release_sock(sk); kfree_skb(skb); @@ -1113,7 +1114,7 @@ } release_sock(sk); - dst_release(xchg(&newsk->dst_cache, skb->dst)); + dst_release(xchg(&newsk->sk_dst_cache, skb->dst)); skb->dst = NULL; DN_SK(newsk)->state = DN_CR; @@ -1129,7 +1130,7 @@ if ((DN_SK(newsk)->services_rem & NSP_FC_MASK) == NSP_FC_NONE) DN_SK(newsk)->max_window = decnet_no_fc_max_cwnd; - newsk->state = TCP_LISTEN; + newsk->sk_state = TCP_LISTEN; memcpy(&(DN_SK(newsk)->addr), &(DN_SK(sk)->addr), sizeof(struct sockaddr_dn)); /* @@ -1168,15 +1169,16 @@ lock_sock(newsk); err = dn_hash_sock(newsk); if (err == 0) { - newsk->zapped = 0; + newsk->sk_zapped = 0; dn_send_conn_ack(newsk); /* - * Here we use sk->allocation since although the conn conf is + * Here we use sk->sk_allocation since although the conn conf is * for the newsk, the context is the old socket. */ if (DN_SK(newsk)->accept_mode == ACC_IMMED) - err = dn_confirm_accept(newsk, &timeo, sk->allocation); + err = dn_confirm_accept(newsk, &timeo, + sk->sk_allocation); } release_sock(newsk); return err; @@ -1246,7 +1248,7 @@ return val; case TIOCOUTQ: - amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); + amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); if (amount < 0) amount = 0; err = put_user(amount, (int *)arg); @@ -1257,9 +1259,10 @@ if ((skb = skb_peek(&scp->other_receive_queue)) != NULL) { amount = skb->len; } else { - struct sk_buff *skb = sk->receive_queue.next; + struct sk_buff *skb = sk->sk_receive_queue.next; for(;;) { - if (skb == (struct sk_buff *)&sk->receive_queue) + if (skb == + (struct sk_buff *)&sk->sk_receive_queue) break; amount += skb->len; skb = skb->next; @@ -1284,15 +1287,15 @@ lock_sock(sk); - if (sk->zapped) + if (sk->sk_zapped) goto out; - if ((DN_SK(sk)->state != DN_O) || (sk->state == TCP_LISTEN)) + if ((DN_SK(sk)->state != DN_O) || (sk->sk_state == TCP_LISTEN)) goto out; - sk->max_ack_backlog = backlog; - sk->ack_backlog = 0; - sk->state = TCP_LISTEN; + sk->sk_max_ack_backlog = backlog; + sk->sk_ack_backlog = 0; + sk->sk_state = TCP_LISTEN; err = 0; dn_rehash_sock(sk); @@ -1325,7 +1328,7 @@ if (how != SHUTDOWN_MASK) goto out; - sk->shutdown = how; + sk->sk_shutdown = how; dn_destroy_sock(sk); err = 0; @@ -1438,7 +1441,7 @@ if (scp->state != DN_CR) return -EINVAL; timeo = sock_rcvtimeo(sk, 0); - err = dn_confirm_accept(sk, &timeo, sk->allocation); + err = dn_confirm_accept(sk, &timeo, sk->sk_allocation); return err; case DSO_CONREJECT: @@ -1447,8 +1450,8 @@ return -EINVAL; scp->state = DN_DR; - sk->shutdown = SHUTDOWN_MASK; - dn_nsp_send_disc(sk, 0x38, 0, sk->allocation); + sk->sk_shutdown = SHUTDOWN_MASK; + dn_nsp_send_disc(sk, 0x38, 0, sk->sk_allocation); break; default: @@ -1662,7 +1665,7 @@ if (cb->nsp_flags & 0x40) { /* SOCK_SEQPACKET reads to EOM */ - if (sk->type == SOCK_SEQPACKET) + if (sk->sk_type == SOCK_SEQPACKET) return 1; /* so does SOCK_STREAM unless WAITALL is specified */ if (!(flags & MSG_WAITALL)) @@ -1685,7 +1688,7 @@ { struct sock *sk = sock->sk; struct dn_scp *scp = DN_SK(sk); - struct sk_buff_head *queue = &sk->receive_queue; + struct sk_buff_head *queue = &sk->sk_receive_queue; int target = size > 1 ? 1 : 0; int copied = 0; int rv = 0; @@ -1696,7 +1699,7 @@ lock_sock(sk); - if (sk->zapped) { + if (sk->sk_zapped) { rv = -EADDRNOTAVAIL; goto out; } @@ -1705,7 +1708,7 @@ if (rv) goto out; - if (sk->shutdown & RCV_SHUTDOWN) { + if (sk->sk_shutdown & RCV_SHUTDOWN) { if (!(flags & MSG_NOSIGNAL)) send_sig(SIGPIPE, current, 0); rv = -EPIPE; @@ -1728,7 +1731,7 @@ * See if there is data ready to read, sleep if there isn't */ for(;;) { - if (sk->err) + if (sk->sk_err) goto out; if (skb_queue_len(&scp->other_receive_queue)) { @@ -1800,7 +1803,7 @@ } if (eor) { - if (sk->type == SOCK_SEQPACKET) + if (sk->sk_type == SOCK_SEQPACKET) break; if (!(flags & MSG_WAITALL)) break; @@ -1816,12 +1819,12 @@ rv = copied; - if (eor && (sk->type == SOCK_SEQPACKET)) + if (eor && (sk->sk_type == SOCK_SEQPACKET)) msg->msg_flags |= MSG_EOR; out: if (rv == 0) - rv = (flags & MSG_PEEK) ? -sk->err : sock_error(sk); + rv = (flags & MSG_PEEK) ? -sk->sk_err : sock_error(sk); if ((rv >= 0) && msg->msg_name) { memcpy(msg->msg_name, &scp->peer, sizeof(struct sockaddr_dn)); @@ -1950,13 +1953,13 @@ if (err) goto out_err; - if (sk->shutdown & SEND_SHUTDOWN) { + if (sk->sk_shutdown & SEND_SHUTDOWN) { err = -EPIPE; goto out_err; } - if ((flags & MSG_TRYHARD) && sk->dst_cache) - dst_negative_advice(&sk->dst_cache); + if ((flags & MSG_TRYHARD) && sk->sk_dst_cache) + dst_negative_advice(&sk->sk_dst_cache); mss = scp->segsize_rem; fctype = scp->services_rem & NSP_FC_MASK; @@ -2053,7 +2056,7 @@ } sent += len; - dn_nsp_queue_xmit(sk, skb, sk->allocation, flags & MSG_OOB); + dn_nsp_queue_xmit(sk, skb, sk->sk_allocation, flags & MSG_OOB); skb = NULL; scp->persist = dn_nsp_persist(sk); @@ -2132,7 +2135,7 @@ { struct dn_iter_state *state = seq->private; - n = n->next; + n = n->sk_next; try_again: if (n) goto out; diff -Nru a/net/decnet/dn_nsp_in.c b/net/decnet/dn_nsp_in.c --- a/net/decnet/dn_nsp_in.c Mon Jun 9 23:16:09 2003 +++ b/net/decnet/dn_nsp_in.c Mon Jun 9 23:16:09 2003 @@ -119,8 +119,8 @@ break; } - if (wakeup && !test_bit(SOCK_DEAD, &sk->flags)) - sk->state_change(sk); + if (wakeup && !sock_flag(sk, SOCK_DEAD)) + sk->sk_state_change(sk); } /* @@ -324,14 +324,14 @@ static void dn_nsp_conn_init(struct sock *sk, struct sk_buff *skb) { - if (sk->ack_backlog >= sk->max_ack_backlog) { + if (sk->sk_ack_backlog >= sk->sk_max_ack_backlog) { kfree_skb(skb); return; } - sk->ack_backlog++; - skb_queue_tail(&sk->receive_queue, skb); - sk->state_change(sk); + sk->sk_ack_backlog++; + skb_queue_tail(&sk->sk_receive_queue, skb); + sk->sk_state_change(sk); } static void dn_nsp_conn_conf(struct sock *sk, struct sk_buff *skb) @@ -351,7 +351,7 @@ if ((scp->state == DN_CI) || (scp->state == DN_CD)) { scp->persist = 0; scp->addrrem = cb->src_port; - sk->state = TCP_ESTABLISHED; + sk->sk_state = TCP_ESTABLISHED; scp->state = DN_RUN; scp->services_rem = cb->services; scp->info_rem = cb->info; @@ -368,8 +368,8 @@ } } dn_nsp_send_link(sk, DN_NOCHANGE, 0); - if (!test_bit(SOCK_DEAD, &sk->flags)) - sk->state_change(sk); + if (!sock_flag(sk, SOCK_DEAD)) + sk->sk_state_change(sk); } out: @@ -413,7 +413,7 @@ } scp->addrrem = cb->src_port; - sk->state = TCP_CLOSE; + sk->sk_state = TCP_CLOSE; switch(scp->state) { case DN_CI: @@ -421,7 +421,7 @@ scp->state = DN_RJ; break; case DN_RUN: - sk->shutdown |= SHUTDOWN_MASK; + sk->sk_shutdown |= SHUTDOWN_MASK; scp->state = DN_DN; break; case DN_DI: @@ -429,10 +429,10 @@ break; } - if (!test_bit(SOCK_DEAD, &sk->flags)) { - if (sk->socket->state != SS_UNCONNECTED) - sk->socket->state = SS_DISCONNECTING; - sk->state_change(sk); + if (!sock_flag(sk, SOCK_DEAD)) { + if (sk->sk_socket->state != SS_UNCONNECTED) + sk->sk_socket->state = SS_DISCONNECTING; + sk->sk_state_change(sk); } /* @@ -465,7 +465,7 @@ reason = dn_ntohs(*(__u16 *)skb->data); - sk->state = TCP_CLOSE; + sk->sk_state = TCP_CLOSE; switch(scp->state) { case DN_CI: @@ -481,15 +481,15 @@ scp->state = DN_DIC; break; case DN_RUN: - sk->shutdown |= SHUTDOWN_MASK; + sk->sk_shutdown |= SHUTDOWN_MASK; case DN_CC: scp->state = DN_CN; } - if (!test_bit(SOCK_DEAD, &sk->flags)) { - if (sk->socket->state != SS_UNCONNECTED) - sk->socket->state = SS_DISCONNECTING; - sk->state_change(sk); + if (!sock_flag(sk, SOCK_DEAD)) { + if (sk->sk_socket->state != SS_UNCONNECTED) + sk->sk_socket->state = SS_DISCONNECTING; + sk->sk_state_change(sk); } scp->persist_fxn = dn_destroy_timer; @@ -558,8 +558,8 @@ } break; } - if (wake_up && !test_bit(SOCK_DEAD, &sk->flags)) - sk->state_change(sk); + if (wake_up && !sock_flag(sk, SOCK_DEAD)) + sk->sk_state_change(sk); } dn_nsp_send_oth_ack(sk); @@ -580,7 +580,8 @@ /* Cast skb->rcvbuf to unsigned... It's pointless, but reduces number of warnings when compiling with -W --ANK */ - if (atomic_read(&sk->rmem_alloc) + skb->truesize >= (unsigned)sk->rcvbuf) { + if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >= + (unsigned)sk->sk_rcvbuf) { err = -ENOMEM; goto out; } @@ -595,16 +596,16 @@ /* This code only runs from BH or BH protected context. * Therefore the plain read_lock is ok here. -DaveM */ - read_lock(&sk->callback_lock); - if (!test_bit(SOCK_DEAD, &sk->flags)) { - struct socket *sock = sk->socket; - wake_up_interruptible(sk->sleep); + read_lock(&sk->sk_callback_lock); + if (!sock_flag(sk, SOCK_DEAD)) { + struct socket *sock = sk->sk_socket; + wake_up_interruptible(sk->sk_sleep); if (sock && sock->fasync_list && !test_bit(SOCK_ASYNC_WAITDATA, &sock->flags)) __kill_fasync(sock->fasync_list, sig, (sig == SIGURG) ? POLL_PRI : POLL_IN); } - read_unlock(&sk->callback_lock); + read_unlock(&sk->sk_callback_lock); out: return err; } @@ -651,7 +652,7 @@ skb_pull(skb, 2); if (seq_next(scp->numdat_rcv, segnum)) { - if (dn_queue_skb(sk, skb, SIGIO, &sk->receive_queue) == 0) { + if (dn_queue_skb(sk, skb, SIGIO, &sk->sk_receive_queue) == 0) { seq_add(&scp->numdat_rcv, 1); queued = 1; } @@ -679,9 +680,9 @@ if (scp->state == DN_CI) { scp->state = DN_NC; - sk->state = TCP_CLOSE; - if (!test_bit(SOCK_DEAD, &sk->flags)) - sk->state_change(sk); + sk->sk_state = TCP_CLOSE; + if (!sock_flag(sk, SOCK_DEAD)) + sk->sk_state_change(sk); } kfree_skb(skb); @@ -882,10 +883,10 @@ int other = 1; /* both data and ack frames can kick a CC socket into RUN */ - if ((scp->state == DN_CC) && !test_bit(SOCK_DEAD, &sk->flags)) { + if ((scp->state == DN_CC) && !sock_flag(sk, SOCK_DEAD)) { scp->state = DN_RUN; - sk->state = TCP_ESTABLISHED; - sk->state_change(sk); + sk->sk_state = TCP_ESTABLISHED; + sk->sk_state_change(sk); } if ((cb->nsp_flags & 0x1c) == 0) diff -Nru a/net/decnet/dn_nsp_out.c b/net/decnet/dn_nsp_out.c --- a/net/decnet/dn_nsp_out.c Mon Jun 9 23:16:19 2003 +++ b/net/decnet/dn_nsp_out.c Mon Jun 9 23:16:19 2003 @@ -92,20 +92,20 @@ } memset(&fl, 0, sizeof(fl)); - fl.oif = sk->bound_dev_if; + fl.oif = sk->sk_bound_dev_if; fl.fld_src = dn_saddr2dn(&scp->addr); fl.fld_dst = dn_saddr2dn(&scp->peer); dn_sk_ports_copy(&fl, scp); fl.proto = DNPROTO_NSP; - if (dn_route_output_sock(&sk->dst_cache, &fl, sk, 0) == 0) { + if (dn_route_output_sock(&sk->sk_dst_cache, &fl, sk, 0) == 0) { dst = sk_dst_get(sk); - sk->route_caps = dst->dev->features; + sk->sk_route_caps = dst->dev->features; goto try_again; } - sk->err = EHOSTUNREACH; - if (!test_bit(SOCK_DEAD, &sk->flags)) - sk->state_change(sk); + sk->sk_err = EHOSTUNREACH; + if (!sock_flag(sk, SOCK_DEAD)) + sk->sk_state_change(sk); } @@ -155,40 +155,42 @@ break; } - if (sk->shutdown & SEND_SHUTDOWN) { + if (sk->sk_shutdown & SEND_SHUTDOWN) { *err = EINVAL; break; } - if (sk->err) + if (sk->sk_err) break; len = *size + 11; - space = sk->sndbuf - atomic_read(&sk->wmem_alloc); + space = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); if (space < len) { - if ((sk->socket->type == SOCK_STREAM) && (space >= (16 + 11))) + if ((sk->sk_socket->type == SOCK_STREAM) && + (space >= (16 + 11))) len = space; } if (space < len) { - set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); + set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); if (noblock) { *err = EWOULDBLOCK; break; } - clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags); + clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); SOCK_SLEEP_PRE(sk) - if ((sk->sndbuf - atomic_read(&sk->wmem_alloc)) < len) + if ((sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc)) < + len) schedule(); SOCK_SLEEP_POST(sk) continue; } - if ((skb = dn_alloc_skb(sk, len, sk->allocation)) == NULL) + if ((skb = dn_alloc_skb(sk, len, sk->sk_allocation)) == NULL) continue; *size = len - 11; @@ -546,7 +548,7 @@ struct sk_buff *skb = NULL; struct nsp_conn_ack_msg *msg; - if ((skb = dn_alloc_skb(sk, 3, sk->allocation)) == NULL) + if ((skb = dn_alloc_skb(sk, 3, sk->sk_allocation)) == NULL) return; msg = (struct nsp_conn_ack_msg *)skb_put(skb, 3); @@ -662,7 +664,7 @@ if (reason == 0) reason = scp->discdata_out.opt_status; - dn_nsp_do_disc(sk, msgflg, reason, gfp, sk->dst_cache, ddl, + dn_nsp_do_disc(sk, msgflg, reason, gfp, sk->sk_dst_cache, ddl, scp->discdata_out.opt_data, scp->addrrem, scp->addrloc); } @@ -714,14 +716,15 @@ void dn_nsp_send_conninit(struct sock *sk, unsigned char msgflg) { struct dn_scp *scp = DN_SK(sk); - struct sk_buff *skb = NULL; struct nsp_conn_init_msg *msg; unsigned char aux; unsigned char menuver; struct dn_skb_cb *cb; unsigned char type = 1; + int allocation = (msgflg == NSP_CI) ? sk->sk_allocation : GFP_ATOMIC; + struct sk_buff *skb = dn_alloc_skb(sk, 200, allocation); - if ((skb = dn_alloc_skb(sk, 200, (msgflg == NSP_CI) ? sk->allocation : GFP_ATOMIC)) == NULL) + if (!skb) return; cb = DN_SKB_CB(skb); diff -Nru a/net/decnet/dn_timer.c b/net/decnet/dn_timer.c --- a/net/decnet/dn_timer.c Mon Jun 9 23:16:14 2003 +++ b/net/decnet/dn_timer.c Mon Jun 9 23:16:14 2003 @@ -38,16 +38,16 @@ void dn_start_slow_timer(struct sock *sk) { - sk->timer.expires = jiffies + SLOW_INTERVAL; - sk->timer.function = dn_slow_timer; - sk->timer.data = (unsigned long)sk; + sk->sk_timer.expires = jiffies + SLOW_INTERVAL; + sk->sk_timer.function = dn_slow_timer; + sk->sk_timer.data = (unsigned long)sk; - add_timer(&sk->timer); + add_timer(&sk->sk_timer); } void dn_stop_slow_timer(struct sock *sk) { - del_timer(&sk->timer); + del_timer(&sk->sk_timer); } static void dn_slow_timer(unsigned long arg) @@ -59,8 +59,8 @@ bh_lock_sock(sk); if (sock_owned_by_user(sk)) { - sk->timer.expires = jiffies + HZ / 10; - add_timer(&sk->timer); + sk->sk_timer.expires = jiffies + HZ / 10; + add_timer(&sk->sk_timer); goto out; } @@ -102,9 +102,9 @@ scp->keepalive_fxn(sk); } - sk->timer.expires = jiffies + SLOW_INTERVAL; + sk->sk_timer.expires = jiffies + SLOW_INTERVAL; - add_timer(&sk->timer); + add_timer(&sk->sk_timer); out: bh_unlock_sock(sk); sock_put(sk); diff -Nru a/net/decnet/netfilter/dn_rtmsg.c b/net/decnet/netfilter/dn_rtmsg.c --- a/net/decnet/netfilter/dn_rtmsg.c Mon Jun 9 23:16:12 2003 +++ b/net/decnet/netfilter/dn_rtmsg.c Mon Jun 9 23:16:12 2003 @@ -120,7 +120,7 @@ { struct sk_buff *skb; - while((skb = skb_dequeue(&sk->receive_queue)) != NULL) { + while((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { dnrmg_receive_user_skb(skb); kfree_skb(skb); } @@ -145,7 +145,7 @@ rv = nf_register_hook(&dnrmg_ops); if (rv) { - sock_release(dnrmg->socket); + sock_release(dnrmg->sk_socket); } return rv; @@ -154,7 +154,7 @@ static void __exit fini(void) { nf_unregister_hook(&dnrmg_ops); - sock_release(dnrmg->socket); + sock_release(dnrmg->sk_socket); } diff -Nru a/net/econet/af_econet.c b/net/econet/af_econet.c --- a/net/econet/af_econet.c Mon Jun 9 23:16:12 2003 +++ b/net/econet/af_econet.c Mon Jun 9 23:16:12 2003 @@ -101,10 +101,10 @@ while ((s = *list) != NULL) { if (s == sk) { - *list = s->next; + *list = s->sk_next; break; } - list = &s->next; + list = &s->sk_next; } write_unlock_bh(&econet_lock); @@ -115,7 +115,7 @@ static void econet_insert_socket(struct sock **list, struct sock *sk) { write_lock_bh(&econet_lock); - sk->next = *list; + sk->sk_next = *list; sock_hold(sk); write_unlock_bh(&econet_lock); } @@ -170,7 +170,7 @@ err = memcpy_toiovec(msg->msg_iov, skb->data, copied); if (err) goto out_free; - sk->stamp=skb->stamp; + sk->sk_stamp = skb->stamp; if (msg->msg_name) memcpy(msg->msg_name, skb->cb, msg->msg_namelen); @@ -364,7 +364,7 @@ err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len); skb->protocol = proto; skb->dev = dev; - skb->priority = sk->priority; + skb->priority = sk->sk_priority; if (err) goto out_free; @@ -500,13 +500,14 @@ { struct sock *sk=(struct sock *)data; - if (!atomic_read(&sk->wmem_alloc) && !atomic_read(&sk->rmem_alloc)) { + if (!atomic_read(&sk->sk_wmem_alloc) && + !atomic_read(&sk->sk_rmem_alloc)) { sk_free(sk); return; } - sk->timer.expires=jiffies+10*HZ; - add_timer(&sk->timer); + sk->sk_timer.expires = jiffies + 10 * HZ; + add_timer(&sk->sk_timer); printk(KERN_DEBUG "econet socket destroy delayed\n"); } @@ -527,21 +528,22 @@ * Now the socket is dead. No more input will appear. */ - sk->state_change(sk); /* It is useless. Just for sanity. */ + sk->sk_state_change(sk); /* It is useless. Just for sanity. */ sock->sk = NULL; - sk->socket = NULL; - __set_bit(SOCK_DEAD, &sk->flags); + sk->sk_socket = NULL; + sock_set_flag(sk, SOCK_DEAD); /* Purge queues */ - skb_queue_purge(&sk->receive_queue); + skb_queue_purge(&sk->sk_receive_queue); - if (atomic_read(&sk->rmem_alloc) || atomic_read(&sk->wmem_alloc)) { - sk->timer.data=(unsigned long)sk; - sk->timer.expires=jiffies+HZ; - sk->timer.function=econet_destroy_timer; - add_timer(&sk->timer); + if (atomic_read(&sk->sk_rmem_alloc) || + atomic_read(&sk->sk_wmem_alloc)) { + sk->sk_timer.data = (unsigned long)sk; + sk->sk_timer.expires = jiffies + HZ; + sk->sk_timer.function = econet_destroy_timer; + add_timer(&sk->sk_timer); return 0; } @@ -570,7 +572,7 @@ if (sk == NULL) goto out; - sk->reuse = 1; + sk->sk_reuse = 1; sock->ops = &econet_ops; sock_init_data(sock,sk); @@ -578,8 +580,8 @@ if (!eo) goto out_free; memset(eo, 0, sizeof(*eo)); - sk->zapped=0; - sk->family = PF_ECONET; + sk->sk_zapped = 0; + sk->sk_family = PF_ECONET; eo->num = protocol; econet_insert_socket(&econet_sklist, sk); @@ -671,9 +673,10 @@ switch(cmd) { case SIOCGSTAMP: - if(sk->stamp.tv_sec==0) + if (!sk->sk_stamp.tv_sec) return -ENOENT; - return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0; + return copy_to_user((void *)arg, &sk->sk_stamp, + sizeof(struct timeval)) ? -EFAULT : 0; case SIOCSIFADDR: case SIOCGIFADDR: return ec_dev_ioctl(sock, cmd, (void *)arg); @@ -733,7 +736,7 @@ (opt->net == net || opt->net == 0)) return sk; - sk = sk->next; + sk = sk->sk_next; } return NULL; @@ -990,9 +993,9 @@ return error; } - udpsock->sk->reuse = 1; - udpsock->sk->allocation = GFP_ATOMIC; /* we're going to call it - from interrupts */ + udpsock->sk->sk_reuse = 1; + udpsock->sk->sk_allocation = GFP_ATOMIC; /* we're going to call it + from interrupts */ error = udpsock->ops->bind(udpsock, (struct sockaddr *)&sin, sizeof(sin)); @@ -1002,7 +1005,7 @@ goto release; } - udpsock->sk->data_ready = aun_data_available; + udpsock->sk->sk_data_ready = aun_data_available; return 0; diff -Nru a/net/ipv4/Kconfig b/net/ipv4/Kconfig --- a/net/ipv4/Kconfig Mon Jun 9 23:16:16 2003 +++ b/net/ipv4/Kconfig Mon Jun 9 23:16:16 2003 @@ -343,6 +343,10 @@ config INET_AH tristate "IP: AH transformation" + select CRYPTO + select CRYPTO_HMAC + select CRYPTO_MD5 + select CRYPTO_SHA1 ---help--- Support for IPsec AH. @@ -350,6 +354,11 @@ config INET_ESP tristate "IP: ESP transformation" + select CRYPTO + select CRYPTO_HMAC + select CRYPTO_MD5 + select CRYPTO_SHA1 + select CRYPTO_DES ---help--- Support for IPsec ESP. @@ -357,6 +366,8 @@ config INET_IPCOMP tristate "IP: IPComp transformation" + select CRYPTO + select CRYPTO_DEFLATE ---help--- Support for IP Paylod Compression (RFC3173), typically needed for IPsec. diff -Nru a/net/ipv4/Makefile b/net/ipv4/Makefile --- a/net/ipv4/Makefile Mon Jun 9 23:16:08 2003 +++ b/net/ipv4/Makefile Mon Jun 9 23:16:08 2003 @@ -16,8 +16,8 @@ obj-$(CONFIG_NET_IPIP) += ipip.o obj-$(CONFIG_NET_IPGRE) += ip_gre.o obj-$(CONFIG_SYN_COOKIES) += syncookies.o -obj-$(CONFIG_INET_AH) += ah.o -obj-$(CONFIG_INET_ESP) += esp.o +obj-$(CONFIG_INET_AH) += ah4.o +obj-$(CONFIG_INET_ESP) += esp4.o obj-$(CONFIG_INET_IPCOMP) += ipcomp.o obj-$(CONFIG_IP_PNP) += ipconfig.o obj-$(CONFIG_NETFILTER) += netfilter/ diff -Nru a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c --- a/net/ipv4/af_inet.c Mon Jun 9 23:16:07 2003 +++ b/net/ipv4/af_inet.c Mon Jun 9 23:16:07 2003 @@ -137,28 +137,27 @@ { struct inet_opt *inet = inet_sk(sk); - __skb_queue_purge(&sk->receive_queue); - __skb_queue_purge(&sk->error_queue); + __skb_queue_purge(&sk->sk_receive_queue); + __skb_queue_purge(&sk->sk_error_queue); - if (sk->type == SOCK_STREAM && sk->state != TCP_CLOSE) { + if (sk->sk_type == SOCK_STREAM && sk->sk_state != TCP_CLOSE) { printk("Attempt to release TCP socket in state %d %p\n", - sk->state, - sk); + sk->sk_state, sk); return; } - if (!test_bit(SOCK_DEAD, &sk->flags)) { + if (!sock_flag(sk, SOCK_DEAD)) { printk("Attempt to release alive inet socket %p\n", sk); return; } - BUG_TRAP(!atomic_read(&sk->rmem_alloc)); - BUG_TRAP(!atomic_read(&sk->wmem_alloc)); - BUG_TRAP(!sk->wmem_queued); - BUG_TRAP(!sk->forward_alloc); + BUG_TRAP(!atomic_read(&sk->sk_rmem_alloc)); + BUG_TRAP(!atomic_read(&sk->sk_wmem_alloc)); + BUG_TRAP(!sk->sk_wmem_queued); + BUG_TRAP(!sk->sk_forward_alloc); if (inet->opt) kfree(inet->opt); - dst_release(sk->dst_cache); + dst_release(sk->sk_dst_cache); #ifdef INET_REFCNT_DEBUG atomic_dec(&inet_sock_nr); printk(KERN_DEBUG "INET socket %p released, %d are still alive\n", @@ -168,8 +167,8 @@ void inet_sock_release(struct sock *sk) { - if (sk->prot->destroy) - sk->prot->destroy(sk); + if (sk->sk_prot->destroy) + sk->sk_prot->destroy(sk); /* Observation: when inet_sock_release is called, processes have * no access to socket. But net still has. @@ -178,7 +177,7 @@ * A. Remove from hash tables. */ - sk->prot->unhash(sk); + sk->sk_prot->unhash(sk); /* In this point socket cannot receive new packets, * but it is possible that some packets are in flight @@ -198,9 +197,9 @@ xfrm_sk_free_policy(sk); #ifdef INET_REFCNT_DEBUG - if (atomic_read(&sk->refcnt) != 1) + if (atomic_read(&sk->sk_refcnt) != 1) printk(KERN_DEBUG "Destruction inet %p delayed, c=%d\n", - sk, atomic_read(&sk->refcnt)); + sk, atomic_read(&sk->sk_refcnt)); #endif sock_put(sk); } @@ -220,7 +219,7 @@ { struct sock *sk = sock->sk; - return sk->prot->setsockopt(sk, level, optname, optval, optlen); + return sk->sk_prot->setsockopt(sk, level, optname, optval, optlen); } /* @@ -236,7 +235,7 @@ { struct sock *sk = sock->sk; - return sk->prot->getsockopt(sk, level, optname, optval, optlen); + return sk->sk_prot->getsockopt(sk, level, optname, optval, optlen); } /* @@ -250,7 +249,7 @@ lock_sock(sk); inet = inet_sk(sk); if (!inet->num) { - if (sk->prot->get_port(sk, 0)) { + if (sk->sk_prot->get_port(sk, 0)) { release_sock(sk); return -EAGAIN; } @@ -275,7 +274,7 @@ if (sock->state != SS_UNCONNECTED || sock->type != SOCK_STREAM) goto out; - old_state = sk->state; + old_state = sk->sk_state; if (!((1 << old_state) & (TCPF_CLOSE | TCPF_LISTEN))) goto out; @@ -287,7 +286,7 @@ if (err) goto out; } - sk->max_ack_backlog = backlog; + sk->sk_max_ack_backlog = backlog; err = 0; out: @@ -368,10 +367,10 @@ goto out_sk_free; err = 0; sock->ops = answer->ops; - sk->prot = answer->prot; - sk->no_check = answer->no_check; + sk->sk_prot = answer->prot; + sk->sk_no_check = answer->no_check; if (INET_PROTOSW_REUSE & answer->flags) - sk->reuse = 1; + sk->sk_reuse = 1; rcu_read_unlock(); inet = inet_sk(sk); @@ -392,11 +391,11 @@ sock_init_data(sock, sk); sk_set_owner(sk, THIS_MODULE); - sk->destruct = inet_sock_destruct; - sk->zapped = 0; - sk->family = PF_INET; - sk->protocol = protocol; - sk->backlog_rcv = sk->prot->backlog_rcv; + sk->sk_destruct = inet_sock_destruct; + sk->sk_zapped = 0; + sk->sk_family = PF_INET; + sk->sk_protocol = protocol; + sk->sk_backlog_rcv = sk->sk_prot->backlog_rcv; inet->uc_ttl = -1; inet->mc_loop = 1; @@ -416,11 +415,11 @@ */ inet->sport = htons(inet->num); /* Add to protocol hash chains. */ - sk->prot->hash(sk); + sk->sk_prot->hash(sk); } - if (sk->prot->init) { - err = sk->prot->init(sk); + if (sk->sk_prot->init) { + err = sk->sk_prot->init(sk); if (err) inet_sock_release(sk); } @@ -456,11 +455,11 @@ * linger.. */ timeout = 0; - if (test_bit(SOCK_LINGER, &sk->flags) && - !(current->flags & PF_EXITING)) - timeout = sk->lingertime; + if (sock_flag(sk, SOCK_LINGER) && + !(current->flags & PF_EXITING)) + timeout = sk->sk_lingertime; sock->sk = NULL; - sk->prot->close(sk, timeout); + sk->sk_prot->close(sk, timeout); } return 0; } @@ -478,8 +477,8 @@ int err; /* If the socket has its own bind function then use it. (RAW) */ - if (sk->prot->bind) { - err = sk->prot->bind(sk, uaddr, addr_len); + if (sk->sk_prot->bind) { + err = sk->sk_prot->bind(sk, uaddr, addr_len); goto out; } err = -EINVAL; @@ -520,7 +519,7 @@ /* Check these errors (active socket, double bind). */ err = -EINVAL; - if (sk->state != TCP_CLOSE || inet->num) + if (sk->sk_state != TCP_CLOSE || inet->num) goto out_release_sock; inet->rcv_saddr = inet->saddr = addr->sin_addr.s_addr; @@ -528,16 +527,16 @@ inet->saddr = 0; /* Use device */ /* Make sure we are allowed to bind here. */ - if (sk->prot->get_port(sk, snum)) { + if (sk->sk_prot->get_port(sk, snum)) { inet->saddr = inet->rcv_saddr = 0; err = -EADDRINUSE; goto out_release_sock; } if (inet->rcv_saddr) - sk->userlocks |= SOCK_BINDADDR_LOCK; + sk->sk_userlocks |= SOCK_BINDADDR_LOCK; if (snum) - sk->userlocks |= SOCK_BINDPORT_LOCK; + sk->sk_userlocks |= SOCK_BINDPORT_LOCK; inet->sport = htons(inet->num); inet->daddr = 0; inet->dport = 0; @@ -555,33 +554,33 @@ struct sock *sk = sock->sk; if (uaddr->sa_family == AF_UNSPEC) - return sk->prot->disconnect(sk, flags); + return sk->sk_prot->disconnect(sk, flags); if (!inet_sk(sk)->num && inet_autobind(sk)) return -EAGAIN; - return sk->prot->connect(sk, (struct sockaddr *)uaddr, addr_len); + return sk->sk_prot->connect(sk, (struct sockaddr *)uaddr, addr_len); } static long inet_wait_for_connect(struct sock *sk, long timeo) { DEFINE_WAIT(wait); - prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE); + prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); - /* Basic assumption: if someone sets sk->err, he _must_ + /* Basic assumption: if someone sets sk->sk_err, he _must_ * change state of the socket from TCP_SYN_*. * Connect() does not allow to get error notifications * without closing the socket. */ - while ((1 << sk->state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) { + while ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) { release_sock(sk); timeo = schedule_timeout(timeo); lock_sock(sk); if (signal_pending(current) || !timeo) break; - prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE); + prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); } - finish_wait(sk->sleep, &wait); + finish_wait(sk->sk_sleep, &wait); return timeo; } @@ -599,7 +598,7 @@ lock_sock(sk); if (uaddr->sa_family == AF_UNSPEC) { - err = sk->prot->disconnect(sk, flags); + err = sk->sk_prot->disconnect(sk, flags); sock->state = err ? SS_DISCONNECTING : SS_UNCONNECTED; goto out; } @@ -617,10 +616,10 @@ break; case SS_UNCONNECTED: err = -EISCONN; - if (sk->state != TCP_CLOSE) + if (sk->sk_state != TCP_CLOSE) goto out; - err = sk->prot->connect(sk, uaddr, addr_len); + err = sk->sk_prot->connect(sk, uaddr, addr_len); if (err < 0) goto out; @@ -636,7 +635,7 @@ timeo = sock_sndtimeo(sk, flags & O_NONBLOCK); - if ((1 << sk->state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) { + if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) { /* Error code is set above */ if (!timeo || !inet_wait_for_connect(sk, timeo)) goto out; @@ -649,10 +648,10 @@ /* Connection was closed by RST, timeout, ICMP error * or another process disconnected us. */ - if (sk->state == TCP_CLOSE) + if (sk->sk_state == TCP_CLOSE) goto sock_error; - /* sk->err may be not zero now, if RECVERR was ordered by user + /* sk->sk_err may be not zero now, if RECVERR was ordered by user * and error was received after socket entered established state. * Hence, it is handled normally after connect() return successfully. */ @@ -666,7 +665,7 @@ sock_error: err = sock_error(sk) ? : -ECONNABORTED; sock->state = SS_UNCONNECTED; - if (sk->prot->disconnect(sk, flags)) + if (sk->sk_prot->disconnect(sk, flags)) sock->state = SS_DISCONNECTING; goto out; } @@ -679,14 +678,14 @@ { struct sock *sk1 = sock->sk; int err = -EINVAL; - struct sock *sk2 = sk1->prot->accept(sk1, flags, &err); + struct sock *sk2 = sk1->sk_prot->accept(sk1, flags, &err); if (!sk2) goto do_err; lock_sock(sk2); - BUG_TRAP((1 << sk2->state) & + BUG_TRAP((1 << sk2->sk_state) & (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT | TCPF_CLOSE)); sock_graft(sk2, newsock); @@ -712,7 +711,7 @@ sin->sin_family = AF_INET; if (peer) { if (!inet->dport || - (((1 << sk->state) & (TCPF_CLOSE | TCPF_SYN_SENT)) && + (((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_SYN_SENT)) && peer == 1)) return -ENOTCONN; sin->sin_port = inet->dport; @@ -737,8 +736,8 @@ int addr_len = 0; int err; - err = sk->prot->recvmsg(iocb, sk, msg, size, flags & MSG_DONTWAIT, - flags & ~MSG_DONTWAIT, &addr_len); + err = sk->sk_prot->recvmsg(iocb, sk, msg, size, flags & MSG_DONTWAIT, + flags & ~MSG_DONTWAIT, &addr_len); if (err >= 0) msg->msg_namelen = addr_len; return err; @@ -754,7 +753,7 @@ if (!inet_sk(sk)->num && inet_autobind(sk)) return -EAGAIN; - return sk->prot->sendmsg(iocb, sk, msg, size); + return sk->sk_prot->sendmsg(iocb, sk, msg, size); } @@ -766,8 +765,8 @@ if (!inet_sk(sk)->num && inet_autobind(sk)) return -EAGAIN; - if (sk->prot->sendpage) - return sk->prot->sendpage(sk, page, offset, size, flags); + if (sk->sk_prot->sendpage) + return sk->sk_prot->sendpage(sk, page, offset, size, flags); return sock_no_sendpage(sock, page, offset, size, flags); } @@ -788,22 +787,22 @@ lock_sock(sk); if (sock->state == SS_CONNECTING) { - if ((1 << sk->state) & + if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV | TCPF_CLOSE)) sock->state = SS_DISCONNECTING; else sock->state = SS_CONNECTED; } - switch (sk->state) { + switch (sk->sk_state) { case TCP_CLOSE: err = -ENOTCONN; /* Hack to wake up other listeners, who can poll for POLLHUP, even on eg. unconnected UDP sockets -- RR */ default: - sk->shutdown |= how; - if (sk->prot->shutdown) - sk->prot->shutdown(sk, how); + sk->sk_shutdown |= how; + if (sk->sk_prot->shutdown) + sk->sk_prot->shutdown(sk, how); break; /* Remaining two branches are temporary solution for missing @@ -815,13 +814,13 @@ break; /* Fall through */ case TCP_SYN_SENT: - err = sk->prot->disconnect(sk, O_NONBLOCK); + err = sk->sk_prot->disconnect(sk, O_NONBLOCK); sock->state = err ? SS_DISCONNECTING : SS_UNCONNECTED; break; } /* Wake up anyone sleeping in poll. */ - sk->state_change(sk); + sk->sk_state_change(sk); release_sock(sk); return err; } @@ -843,9 +842,9 @@ switch (cmd) { case SIOCGSTAMP: - if (!sk->stamp.tv_sec) + if (!sk->sk_stamp.tv_sec) err = -ENOENT; - else if (copy_to_user((void *)arg, &sk->stamp, + else if (copy_to_user((void *)arg, &sk->sk_stamp, sizeof(struct timeval))) err = -EFAULT; break; @@ -873,8 +872,8 @@ err = devinet_ioctl(cmd, (void *)arg); break; default: - if (!sk->prot->ioctl || - (err = sk->prot->ioctl(sk, cmd, arg)) == + if (!sk->sk_prot->ioctl || + (err = sk->sk_prot->ioctl(sk, cmd, arg)) == -ENOIOCTLCMD) err = dev_ioctl(cmd, (void *)arg); break; @@ -1068,60 +1067,29 @@ static int __init init_ipv4_mibs(void) { - int i; - - net_statistics[0] = - kmalloc_percpu(sizeof (struct linux_mib), GFP_KERNEL); - net_statistics[1] = - kmalloc_percpu(sizeof (struct linux_mib), GFP_KERNEL); - ip_statistics[0] = kmalloc_percpu(sizeof (struct ip_mib), GFP_KERNEL); - ip_statistics[1] = kmalloc_percpu(sizeof (struct ip_mib), GFP_KERNEL); - icmp_statistics[0] = - kmalloc_percpu(sizeof (struct icmp_mib), GFP_KERNEL); - icmp_statistics[1] = - kmalloc_percpu(sizeof (struct icmp_mib), GFP_KERNEL); - tcp_statistics[0] = kmalloc_percpu(sizeof (struct tcp_mib), GFP_KERNEL); - tcp_statistics[1] = kmalloc_percpu(sizeof (struct tcp_mib), GFP_KERNEL); - udp_statistics[0] = kmalloc_percpu(sizeof (struct udp_mib), GFP_KERNEL); - udp_statistics[1] = kmalloc_percpu(sizeof (struct udp_mib), GFP_KERNEL); + net_statistics[0] = alloc_percpu(struct linux_mib); + net_statistics[1] = alloc_percpu(struct linux_mib); + ip_statistics[0] = alloc_percpu(struct ip_mib); + ip_statistics[1] = alloc_percpu(struct ip_mib); + icmp_statistics[0] = alloc_percpu(struct icmp_mib); + icmp_statistics[1] = alloc_percpu(struct icmp_mib); + tcp_statistics[0] = alloc_percpu(struct tcp_mib); + tcp_statistics[1] = alloc_percpu(struct tcp_mib); + udp_statistics[0] = alloc_percpu(struct udp_mib); + udp_statistics[1] = alloc_percpu(struct udp_mib); if (! (net_statistics[0] && net_statistics[1] && ip_statistics[0] && ip_statistics[1] && tcp_statistics[0] && tcp_statistics[1] && udp_statistics[0] && udp_statistics[1])) return -ENOMEM; - /* Set all the per cpu copies of the mibs to zero */ - for (i = 0; i < NR_CPUS; i++) { - if (cpu_possible(i)) { - memset(per_cpu_ptr(net_statistics[0], i), 0, - sizeof (struct linux_mib)); - memset(per_cpu_ptr(net_statistics[1], i), 0, - sizeof (struct linux_mib)); - memset(per_cpu_ptr(ip_statistics[0], i), 0, - sizeof (struct ip_mib)); - memset(per_cpu_ptr(ip_statistics[1], i), 0, - sizeof (struct ip_mib)); - memset(per_cpu_ptr(icmp_statistics[0], i), 0, - sizeof (struct icmp_mib)); - memset(per_cpu_ptr(icmp_statistics[1], i), 0, - sizeof (struct icmp_mib)); - memset(per_cpu_ptr(tcp_statistics[0], i), 0, - sizeof (struct tcp_mib)); - memset(per_cpu_ptr(tcp_statistics[1], i), 0, - sizeof (struct tcp_mib)); - memset(per_cpu_ptr(udp_statistics[0], i), 0, - sizeof (struct udp_mib)); - memset(per_cpu_ptr(udp_statistics[1], i), 0, - sizeof (struct udp_mib)); - } - } - (void) tcp_mib_init(); return 0; } int ipv4_proc_init(void); +extern void ipfrag_init(void); static int __init inet_init(void) { @@ -1224,6 +1192,9 @@ printk(KERN_CRIT "inet_init: Cannot init ipv4 mibs\n"); ; ipv4_proc_init(); + + ipfrag_init(); + return 0; } diff -Nru a/net/ipv4/ah.c b/net/ipv4/ah.c --- a/net/ipv4/ah.c Mon Jun 9 23:16:18 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,361 +0,0 @@ -#include <linux/config.h> -#include <linux/module.h> -#include <net/ip.h> -#include <net/xfrm.h> -#include <net/ah.h> -#include <linux/crypto.h> -#include <linux/pfkeyv2.h> -#include <net/icmp.h> -#include <asm/scatterlist.h> - - -/* Clear mutable options and find final destination to substitute - * into IP header for icv calculation. Options are already checked - * for validity, so paranoia is not required. */ - -static int ip_clear_mutable_options(struct iphdr *iph, u32 *daddr) -{ - unsigned char * optptr = (unsigned char*)(iph+1); - int l = iph->ihl*4 - sizeof(struct iphdr); - int optlen; - - while (l > 0) { - switch (*optptr) { - case IPOPT_END: - return 0; - case IPOPT_NOOP: - l--; - optptr++; - continue; - } - optlen = optptr[1]; - if (optlen<2 || optlen>l) - return -EINVAL; - switch (*optptr) { - case IPOPT_SEC: - case 0x85: /* Some "Extended Security" crap. */ - case 0x86: /* Another "Commercial Security" crap. */ - case IPOPT_RA: - case 0x80|21: /* RFC1770 */ - break; - case IPOPT_LSRR: - case IPOPT_SSRR: - if (optlen < 6) - return -EINVAL; - memcpy(daddr, optptr+optlen-4, 4); - /* Fall through */ - default: - memset(optptr+2, 0, optlen-2); - } - l -= optlen; - optptr += optlen; - } - return 0; -} - -static int ah_output(struct sk_buff *skb) -{ - int err; - struct dst_entry *dst = skb->dst; - struct xfrm_state *x = dst->xfrm; - struct iphdr *iph, *top_iph; - struct ip_auth_hdr *ah; - struct ah_data *ahp; - union { - struct iphdr iph; - char buf[60]; - } tmp_iph; - - if (skb->ip_summed == CHECKSUM_HW && skb_checksum_help(skb) == NULL) { - err = -EINVAL; - goto error_nolock; - } - - spin_lock_bh(&x->lock); - err = xfrm_check_output(x, skb, AF_INET); - if (err) - goto error; - - iph = skb->nh.iph; - if (x->props.mode) { - top_iph = (struct iphdr*)skb_push(skb, x->props.header_len); - top_iph->ihl = 5; - top_iph->version = 4; - top_iph->tos = 0; - top_iph->tot_len = htons(skb->len); - top_iph->frag_off = 0; - if (!(iph->frag_off&htons(IP_DF))) - __ip_select_ident(top_iph, dst, 0); - top_iph->ttl = 0; - top_iph->protocol = IPPROTO_AH; - top_iph->check = 0; - top_iph->saddr = x->props.saddr.a4; - top_iph->daddr = x->id.daddr.a4; - ah = (struct ip_auth_hdr*)(top_iph+1); - ah->nexthdr = IPPROTO_IPIP; - } else { - memcpy(&tmp_iph, skb->data, iph->ihl*4); - top_iph = (struct iphdr*)skb_push(skb, x->props.header_len); - memcpy(top_iph, &tmp_iph, iph->ihl*4); - iph = &tmp_iph.iph; - top_iph->tos = 0; - top_iph->tot_len = htons(skb->len); - top_iph->frag_off = 0; - top_iph->ttl = 0; - top_iph->protocol = IPPROTO_AH; - top_iph->check = 0; - if (top_iph->ihl != 5) { - err = ip_clear_mutable_options(top_iph, &top_iph->daddr); - if (err) - goto error; - } - ah = (struct ip_auth_hdr*)((char*)top_iph+iph->ihl*4); - ah->nexthdr = iph->protocol; - } - ahp = x->data; - ah->hdrlen = (XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + - ahp->icv_trunc_len) >> 2) - 2; - - ah->reserved = 0; - ah->spi = x->id.spi; - ah->seq_no = htonl(++x->replay.oseq); - ahp->icv(ahp, skb, ah->auth_data); - top_iph->tos = iph->tos; - top_iph->ttl = iph->ttl; - if (x->props.mode) { - top_iph->frag_off = iph->frag_off&~htons(IP_MF|IP_OFFSET); - memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); - } else { - top_iph->frag_off = iph->frag_off; - top_iph->daddr = iph->daddr; - if (iph->ihl != 5) - memcpy(top_iph+1, iph+1, iph->ihl*4 - sizeof(struct iphdr)); - } - ip_send_check(top_iph); - - skb->nh.raw = skb->data; - - x->curlft.bytes += skb->len; - x->curlft.packets++; - spin_unlock_bh(&x->lock); - if ((skb->dst = dst_pop(dst)) == NULL) { - err = -EHOSTUNREACH; - goto error_nolock; - } - return NET_XMIT_BYPASS; - -error: - spin_unlock_bh(&x->lock); -error_nolock: - kfree_skb(skb); - return err; -} - -int ah_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb) -{ - int ah_hlen; - struct iphdr *iph; - struct ip_auth_hdr *ah; - struct ah_data *ahp; - char work_buf[60]; - - if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr))) - goto out; - - ah = (struct ip_auth_hdr*)skb->data; - ahp = x->data; - ah_hlen = (ah->hdrlen + 2) << 2; - - if (ah_hlen != XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_full_len) && - ah_hlen != XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_trunc_len)) - goto out; - - if (!pskb_may_pull(skb, ah_hlen)) - goto out; - - /* We are going to _remove_ AH header to keep sockets happy, - * so... Later this can change. */ - if (skb_cloned(skb) && - pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) - goto out; - - skb->ip_summed = CHECKSUM_NONE; - - ah = (struct ip_auth_hdr*)skb->data; - iph = skb->nh.iph; - - memcpy(work_buf, iph, iph->ihl*4); - - iph->ttl = 0; - iph->tos = 0; - iph->frag_off = 0; - iph->check = 0; - if (iph->ihl != 5) { - u32 dummy; - if (ip_clear_mutable_options(iph, &dummy)) - goto out; - } - { - u8 auth_data[ahp->icv_trunc_len]; - - memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len); - skb_push(skb, skb->data - skb->nh.raw); - ahp->icv(ahp, skb, ah->auth_data); - if (memcmp(ah->auth_data, auth_data, ahp->icv_trunc_len)) { - x->stats.integrity_failed++; - goto out; - } - } - ((struct iphdr*)work_buf)->protocol = ah->nexthdr; - skb->nh.raw = skb_pull(skb, ah_hlen); - memcpy(skb->nh.raw, work_buf, iph->ihl*4); - skb->nh.iph->tot_len = htons(skb->len); - skb_pull(skb, skb->nh.iph->ihl*4); - skb->h.raw = skb->data; - - return 0; - -out: - return -EINVAL; -} - -void ah4_err(struct sk_buff *skb, u32 info) -{ - struct iphdr *iph = (struct iphdr*)skb->data; - struct ip_auth_hdr *ah = (struct ip_auth_hdr*)(skb->data+(iph->ihl<<2)); - struct xfrm_state *x; - - if (skb->h.icmph->type != ICMP_DEST_UNREACH || - skb->h.icmph->code != ICMP_FRAG_NEEDED) - return; - - x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET); - if (!x) - return; - printk(KERN_DEBUG "pmtu discvovery on SA AH/%08x/%08x\n", - ntohl(ah->spi), ntohl(iph->daddr)); - xfrm_state_put(x); -} - -static int ah_init_state(struct xfrm_state *x, void *args) -{ - struct ah_data *ahp = NULL; - struct xfrm_algo_desc *aalg_desc; - - /* null auth can use a zero length key */ - if (x->aalg->alg_key_len > 512) - goto error; - - ahp = kmalloc(sizeof(*ahp), GFP_KERNEL); - if (ahp == NULL) - return -ENOMEM; - - memset(ahp, 0, sizeof(*ahp)); - - ahp->key = x->aalg->alg_key; - ahp->key_len = (x->aalg->alg_key_len+7)/8; - ahp->tfm = crypto_alloc_tfm(x->aalg->alg_name, 0); - if (!ahp->tfm) - goto error; - ahp->icv = ah_hmac_digest; - - /* - * Lookup the algorithm description maintained by xfrm_algo, - * verify crypto transform properties, and store information - * we need for AH processing. This lookup cannot fail here - * after a successful crypto_alloc_tfm(). - */ - aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name); - BUG_ON(!aalg_desc); - - if (aalg_desc->uinfo.auth.icv_fullbits/8 != - crypto_tfm_alg_digestsize(ahp->tfm)) { - printk(KERN_INFO "AH: %s digestsize %u != %hu\n", - x->aalg->alg_name, crypto_tfm_alg_digestsize(ahp->tfm), - aalg_desc->uinfo.auth.icv_fullbits/8); - goto error; - } - - ahp->icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8; - ahp->icv_trunc_len = aalg_desc->uinfo.auth.icv_truncbits/8; - - ahp->work_icv = kmalloc(ahp->icv_full_len, GFP_KERNEL); - if (!ahp->work_icv) - goto error; - - x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_trunc_len); - if (x->props.mode) - x->props.header_len += sizeof(struct iphdr); - x->data = ahp; - - return 0; - -error: - if (ahp) { - if (ahp->work_icv) - kfree(ahp->work_icv); - if (ahp->tfm) - crypto_free_tfm(ahp->tfm); - kfree(ahp); - } - return -EINVAL; -} - -static void ah_destroy(struct xfrm_state *x) -{ - struct ah_data *ahp = x->data; - - if (ahp->work_icv) { - kfree(ahp->work_icv); - ahp->work_icv = NULL; - } - if (ahp->tfm) { - crypto_free_tfm(ahp->tfm); - ahp->tfm = NULL; - } - kfree(ahp); -} - - -static struct xfrm_type ah_type = -{ - .description = "AH4", - .owner = THIS_MODULE, - .proto = IPPROTO_AH, - .init_state = ah_init_state, - .destructor = ah_destroy, - .input = ah_input, - .output = ah_output -}; - -static struct inet_protocol ah4_protocol = { - .handler = xfrm4_rcv, - .err_handler = ah4_err, - .no_policy = 1, -}; - -static int __init ah4_init(void) -{ - if (xfrm_register_type(&ah_type, AF_INET) < 0) { - printk(KERN_INFO "ip ah init: can't add xfrm type\n"); - return -EAGAIN; - } - if (inet_add_protocol(&ah4_protocol, IPPROTO_AH) < 0) { - printk(KERN_INFO "ip ah init: can't add protocol\n"); - xfrm_unregister_type(&ah_type, AF_INET); - return -EAGAIN; - } - return 0; -} - -static void __exit ah4_fini(void) -{ - if (inet_del_protocol(&ah4_protocol, IPPROTO_AH) < 0) - printk(KERN_INFO "ip ah close: can't remove protocol\n"); - if (xfrm_unregister_type(&ah_type, AF_INET) < 0) - printk(KERN_INFO "ip ah close: can't remove xfrm type\n"); -} - -module_init(ah4_init); -module_exit(ah4_fini); -MODULE_LICENSE("GPL"); diff -Nru a/net/ipv4/ah4.c b/net/ipv4/ah4.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/ipv4/ah4.c Mon Jun 9 23:16:18 2003 @@ -0,0 +1,361 @@ +#include <linux/config.h> +#include <linux/module.h> +#include <net/ip.h> +#include <net/xfrm.h> +#include <net/ah.h> +#include <linux/crypto.h> +#include <linux/pfkeyv2.h> +#include <net/icmp.h> +#include <asm/scatterlist.h> + + +/* Clear mutable options and find final destination to substitute + * into IP header for icv calculation. Options are already checked + * for validity, so paranoia is not required. */ + +static int ip_clear_mutable_options(struct iphdr *iph, u32 *daddr) +{ + unsigned char * optptr = (unsigned char*)(iph+1); + int l = iph->ihl*4 - sizeof(struct iphdr); + int optlen; + + while (l > 0) { + switch (*optptr) { + case IPOPT_END: + return 0; + case IPOPT_NOOP: + l--; + optptr++; + continue; + } + optlen = optptr[1]; + if (optlen<2 || optlen>l) + return -EINVAL; + switch (*optptr) { + case IPOPT_SEC: + case 0x85: /* Some "Extended Security" crap. */ + case 0x86: /* Another "Commercial Security" crap. */ + case IPOPT_RA: + case 0x80|21: /* RFC1770 */ + break; + case IPOPT_LSRR: + case IPOPT_SSRR: + if (optlen < 6) + return -EINVAL; + memcpy(daddr, optptr+optlen-4, 4); + /* Fall through */ + default: + memset(optptr+2, 0, optlen-2); + } + l -= optlen; + optptr += optlen; + } + return 0; +} + +static int ah_output(struct sk_buff *skb) +{ + int err; + struct dst_entry *dst = skb->dst; + struct xfrm_state *x = dst->xfrm; + struct iphdr *iph, *top_iph; + struct ip_auth_hdr *ah; + struct ah_data *ahp; + union { + struct iphdr iph; + char buf[60]; + } tmp_iph; + + if (skb->ip_summed == CHECKSUM_HW && skb_checksum_help(skb) == NULL) { + err = -EINVAL; + goto error_nolock; + } + + spin_lock_bh(&x->lock); + err = xfrm_check_output(x, skb, AF_INET); + if (err) + goto error; + + iph = skb->nh.iph; + if (x->props.mode) { + top_iph = (struct iphdr*)skb_push(skb, x->props.header_len); + top_iph->ihl = 5; + top_iph->version = 4; + top_iph->tos = 0; + top_iph->tot_len = htons(skb->len); + top_iph->frag_off = 0; + if (!(iph->frag_off&htons(IP_DF))) + __ip_select_ident(top_iph, dst, 0); + top_iph->ttl = 0; + top_iph->protocol = IPPROTO_AH; + top_iph->check = 0; + top_iph->saddr = x->props.saddr.a4; + top_iph->daddr = x->id.daddr.a4; + ah = (struct ip_auth_hdr*)(top_iph+1); + ah->nexthdr = IPPROTO_IPIP; + } else { + memcpy(&tmp_iph, skb->data, iph->ihl*4); + top_iph = (struct iphdr*)skb_push(skb, x->props.header_len); + memcpy(top_iph, &tmp_iph, iph->ihl*4); + iph = &tmp_iph.iph; + top_iph->tos = 0; + top_iph->tot_len = htons(skb->len); + top_iph->frag_off = 0; + top_iph->ttl = 0; + top_iph->protocol = IPPROTO_AH; + top_iph->check = 0; + if (top_iph->ihl != 5) { + err = ip_clear_mutable_options(top_iph, &top_iph->daddr); + if (err) + goto error; + } + ah = (struct ip_auth_hdr*)((char*)top_iph+iph->ihl*4); + ah->nexthdr = iph->protocol; + } + ahp = x->data; + ah->hdrlen = (XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + + ahp->icv_trunc_len) >> 2) - 2; + + ah->reserved = 0; + ah->spi = x->id.spi; + ah->seq_no = htonl(++x->replay.oseq); + ahp->icv(ahp, skb, ah->auth_data); + top_iph->tos = iph->tos; + top_iph->ttl = iph->ttl; + if (x->props.mode) { + top_iph->frag_off = iph->frag_off&~htons(IP_MF|IP_OFFSET); + memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); + } else { + top_iph->frag_off = iph->frag_off; + top_iph->daddr = iph->daddr; + if (iph->ihl != 5) + memcpy(top_iph+1, iph+1, iph->ihl*4 - sizeof(struct iphdr)); + } + ip_send_check(top_iph); + + skb->nh.raw = skb->data; + + x->curlft.bytes += skb->len; + x->curlft.packets++; + spin_unlock_bh(&x->lock); + if ((skb->dst = dst_pop(dst)) == NULL) { + err = -EHOSTUNREACH; + goto error_nolock; + } + return NET_XMIT_BYPASS; + +error: + spin_unlock_bh(&x->lock); +error_nolock: + kfree_skb(skb); + return err; +} + +int ah_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb) +{ + int ah_hlen; + struct iphdr *iph; + struct ip_auth_hdr *ah; + struct ah_data *ahp; + char work_buf[60]; + + if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr))) + goto out; + + ah = (struct ip_auth_hdr*)skb->data; + ahp = x->data; + ah_hlen = (ah->hdrlen + 2) << 2; + + if (ah_hlen != XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_full_len) && + ah_hlen != XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_trunc_len)) + goto out; + + if (!pskb_may_pull(skb, ah_hlen)) + goto out; + + /* We are going to _remove_ AH header to keep sockets happy, + * so... Later this can change. */ + if (skb_cloned(skb) && + pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) + goto out; + + skb->ip_summed = CHECKSUM_NONE; + + ah = (struct ip_auth_hdr*)skb->data; + iph = skb->nh.iph; + + memcpy(work_buf, iph, iph->ihl*4); + + iph->ttl = 0; + iph->tos = 0; + iph->frag_off = 0; + iph->check = 0; + if (iph->ihl != 5) { + u32 dummy; + if (ip_clear_mutable_options(iph, &dummy)) + goto out; + } + { + u8 auth_data[ahp->icv_trunc_len]; + + memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len); + skb_push(skb, skb->data - skb->nh.raw); + ahp->icv(ahp, skb, ah->auth_data); + if (memcmp(ah->auth_data, auth_data, ahp->icv_trunc_len)) { + x->stats.integrity_failed++; + goto out; + } + } + ((struct iphdr*)work_buf)->protocol = ah->nexthdr; + skb->nh.raw = skb_pull(skb, ah_hlen); + memcpy(skb->nh.raw, work_buf, iph->ihl*4); + skb->nh.iph->tot_len = htons(skb->len); + skb_pull(skb, skb->nh.iph->ihl*4); + skb->h.raw = skb->data; + + return 0; + +out: + return -EINVAL; +} + +void ah4_err(struct sk_buff *skb, u32 info) +{ + struct iphdr *iph = (struct iphdr*)skb->data; + struct ip_auth_hdr *ah = (struct ip_auth_hdr*)(skb->data+(iph->ihl<<2)); + struct xfrm_state *x; + + if (skb->h.icmph->type != ICMP_DEST_UNREACH || + skb->h.icmph->code != ICMP_FRAG_NEEDED) + return; + + x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET); + if (!x) + return; + printk(KERN_DEBUG "pmtu discvovery on SA AH/%08x/%08x\n", + ntohl(ah->spi), ntohl(iph->daddr)); + xfrm_state_put(x); +} + +static int ah_init_state(struct xfrm_state *x, void *args) +{ + struct ah_data *ahp = NULL; + struct xfrm_algo_desc *aalg_desc; + + /* null auth can use a zero length key */ + if (x->aalg->alg_key_len > 512) + goto error; + + ahp = kmalloc(sizeof(*ahp), GFP_KERNEL); + if (ahp == NULL) + return -ENOMEM; + + memset(ahp, 0, sizeof(*ahp)); + + ahp->key = x->aalg->alg_key; + ahp->key_len = (x->aalg->alg_key_len+7)/8; + ahp->tfm = crypto_alloc_tfm(x->aalg->alg_name, 0); + if (!ahp->tfm) + goto error; + ahp->icv = ah_hmac_digest; + + /* + * Lookup the algorithm description maintained by xfrm_algo, + * verify crypto transform properties, and store information + * we need for AH processing. This lookup cannot fail here + * after a successful crypto_alloc_tfm(). + */ + aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name); + BUG_ON(!aalg_desc); + + if (aalg_desc->uinfo.auth.icv_fullbits/8 != + crypto_tfm_alg_digestsize(ahp->tfm)) { + printk(KERN_INFO "AH: %s digestsize %u != %hu\n", + x->aalg->alg_name, crypto_tfm_alg_digestsize(ahp->tfm), + aalg_desc->uinfo.auth.icv_fullbits/8); + goto error; + } + + ahp->icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8; + ahp->icv_trunc_len = aalg_desc->uinfo.auth.icv_truncbits/8; + + ahp->work_icv = kmalloc(ahp->icv_full_len, GFP_KERNEL); + if (!ahp->work_icv) + goto error; + + x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) + ahp->icv_trunc_len); + if (x->props.mode) + x->props.header_len += sizeof(struct iphdr); + x->data = ahp; + + return 0; + +error: + if (ahp) { + if (ahp->work_icv) + kfree(ahp->work_icv); + if (ahp->tfm) + crypto_free_tfm(ahp->tfm); + kfree(ahp); + } + return -EINVAL; +} + +static void ah_destroy(struct xfrm_state *x) +{ + struct ah_data *ahp = x->data; + + if (ahp->work_icv) { + kfree(ahp->work_icv); + ahp->work_icv = NULL; + } + if (ahp->tfm) { + crypto_free_tfm(ahp->tfm); + ahp->tfm = NULL; + } + kfree(ahp); +} + + +static struct xfrm_type ah_type = +{ + .description = "AH4", + .owner = THIS_MODULE, + .proto = IPPROTO_AH, + .init_state = ah_init_state, + .destructor = ah_destroy, + .input = ah_input, + .output = ah_output +}; + +static struct inet_protocol ah4_protocol = { + .handler = xfrm4_rcv, + .err_handler = ah4_err, + .no_policy = 1, +}; + +static int __init ah4_init(void) +{ + if (xfrm_register_type(&ah_type, AF_INET) < 0) { + printk(KERN_INFO "ip ah init: can't add xfrm type\n"); + return -EAGAIN; + } + if (inet_add_protocol(&ah4_protocol, IPPROTO_AH) < 0) { + printk(KERN_INFO "ip ah init: can't add protocol\n"); + xfrm_unregister_type(&ah_type, AF_INET); + return -EAGAIN; + } + return 0; +} + +static void __exit ah4_fini(void) +{ + if (inet_del_protocol(&ah4_protocol, IPPROTO_AH) < 0) + printk(KERN_INFO "ip ah close: can't remove protocol\n"); + if (xfrm_unregister_type(&ah_type, AF_INET) < 0) + printk(KERN_INFO "ip ah close: can't remove xfrm type\n"); +} + +module_init(ah4_init); +module_exit(ah4_fini); +MODULE_LICENSE("GPL"); diff -Nru a/net/ipv4/esp.c b/net/ipv4/esp.c --- a/net/ipv4/esp.c Mon Jun 9 23:16:14 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,604 +0,0 @@ -#include <linux/config.h> -#include <linux/module.h> -#include <net/ip.h> -#include <net/xfrm.h> -#include <net/esp.h> -#include <asm/scatterlist.h> -#include <linux/crypto.h> -#include <linux/pfkeyv2.h> -#include <linux/random.h> -#include <net/icmp.h> -#include <net/udp.h> - -#define MAX_SG_ONSTACK 4 - -/* decapsulation data for use when post-processing */ -struct esp_decap_data { - xfrm_address_t saddr; - __u16 sport; - __u8 proto; -}; - -int esp_output(struct sk_buff *skb) -{ - int err; - struct dst_entry *dst = skb->dst; - struct xfrm_state *x = dst->xfrm; - struct iphdr *iph, *top_iph; - struct ip_esp_hdr *esph; - struct crypto_tfm *tfm; - struct esp_data *esp; - struct sk_buff *trailer; - struct udphdr *uh = NULL; - struct xfrm_encap_tmpl *encap = NULL; - int blksize; - int clen; - int alen; - int nfrags; - union { - struct iphdr iph; - char buf[60]; - } tmp_iph; - - /* First, if the skb is not checksummed, complete checksum. */ - if (skb->ip_summed == CHECKSUM_HW && skb_checksum_help(skb) == NULL) { - err = -EINVAL; - goto error_nolock; - } - - spin_lock_bh(&x->lock); - err = xfrm_check_output(x, skb, AF_INET); - if (err) - goto error; - err = -ENOMEM; - - /* Strip IP header in transport mode. Save it. */ - if (!x->props.mode) { - iph = skb->nh.iph; - memcpy(&tmp_iph, iph, iph->ihl*4); - __skb_pull(skb, iph->ihl*4); - } - /* Now skb is pure payload to encrypt */ - - /* Round to block size */ - clen = skb->len; - - esp = x->data; - alen = esp->auth.icv_trunc_len; - tfm = esp->conf.tfm; - blksize = (crypto_tfm_alg_blocksize(tfm) + 3) & ~3; - clen = (clen + 2 + blksize-1)&~(blksize-1); - if (esp->conf.padlen) - clen = (clen + esp->conf.padlen-1)&~(esp->conf.padlen-1); - - if ((nfrags = skb_cow_data(skb, clen-skb->len+alen, &trailer)) < 0) - goto error; - - /* Fill padding... */ - do { - int i; - for (i=0; i<clen-skb->len - 2; i++) - *(u8*)(trailer->tail + i) = i+1; - } while (0); - *(u8*)(trailer->tail + clen-skb->len - 2) = (clen - skb->len)-2; - pskb_put(skb, trailer, clen - skb->len); - - encap = x->encap; - - iph = skb->nh.iph; - if (x->props.mode) { - top_iph = (struct iphdr*)skb_push(skb, x->props.header_len); - esph = (struct ip_esp_hdr*)(top_iph+1); - if (encap && encap->encap_type) { - switch (encap->encap_type) { - case UDP_ENCAP_ESPINUDP: - uh = (struct udphdr*) esph; - esph = (struct ip_esp_hdr*)(uh+1); - top_iph->protocol = IPPROTO_UDP; - break; - default: - printk(KERN_INFO - "esp_output(): Unhandled encap: %u\n", - encap->encap_type); - top_iph->protocol = IPPROTO_ESP; - break; - } - } else - top_iph->protocol = IPPROTO_ESP; - *(u8*)(trailer->tail - 1) = IPPROTO_IPIP; - top_iph->ihl = 5; - top_iph->version = 4; - top_iph->tos = iph->tos; /* DS disclosed */ - top_iph->tot_len = htons(skb->len + alen); - top_iph->frag_off = iph->frag_off&htons(IP_DF); - if (!(top_iph->frag_off)) - ip_select_ident(top_iph, dst, 0); - top_iph->ttl = iph->ttl; /* TTL disclosed */ - top_iph->check = 0; - top_iph->saddr = x->props.saddr.a4; - top_iph->daddr = x->id.daddr.a4; - memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); - } else { - esph = (struct ip_esp_hdr*)skb_push(skb, x->props.header_len); - top_iph = (struct iphdr*)skb_push(skb, iph->ihl*4); - memcpy(top_iph, &tmp_iph, iph->ihl*4); - if (encap && encap->encap_type) { - switch (encap->encap_type) { - case UDP_ENCAP_ESPINUDP: - uh = (struct udphdr*) esph; - esph = (struct ip_esp_hdr*)(uh+1); - top_iph->protocol = IPPROTO_UDP; - break; - default: - printk(KERN_INFO - "esp_output(): Unhandled encap: %u\n", - encap->encap_type); - top_iph->protocol = IPPROTO_ESP; - break; - } - } else - top_iph->protocol = IPPROTO_ESP; - iph = &tmp_iph.iph; - top_iph->tot_len = htons(skb->len + alen); - top_iph->check = 0; - top_iph->frag_off = iph->frag_off; - *(u8*)(trailer->tail - 1) = iph->protocol; - } - - /* this is non-NULL only with UDP Encapsulation */ - if (encap && uh) { - uh->source = encap->encap_sport; - uh->dest = encap->encap_dport; - uh->len = htons(skb->len + alen - sizeof(struct iphdr)); - uh->check = 0; - } - - esph->spi = x->id.spi; - esph->seq_no = htonl(++x->replay.oseq); - - if (esp->conf.ivlen) - crypto_cipher_set_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm)); - - do { - struct scatterlist sgbuf[nfrags>MAX_SG_ONSTACK ? 0 : nfrags]; - struct scatterlist *sg = sgbuf; - - if (unlikely(nfrags > MAX_SG_ONSTACK)) { - sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); - if (!sg) - goto error; - } - skb_to_sgvec(skb, sg, esph->enc_data+esp->conf.ivlen-skb->data, clen); - crypto_cipher_encrypt(tfm, sg, sg, clen); - if (unlikely(sg != sgbuf)) - kfree(sg); - } while (0); - - if (esp->conf.ivlen) { - memcpy(esph->enc_data, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm)); - crypto_cipher_get_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm)); - } - - if (esp->auth.icv_full_len) { - esp->auth.icv(esp, skb, (u8*)esph-skb->data, - sizeof(struct ip_esp_hdr) + esp->conf.ivlen+clen, trailer->tail); - pskb_put(skb, trailer, alen); - } - - ip_send_check(top_iph); - - skb->nh.raw = skb->data; - - x->curlft.bytes += skb->len; - x->curlft.packets++; - spin_unlock_bh(&x->lock); - if ((skb->dst = dst_pop(dst)) == NULL) { - err = -EHOSTUNREACH; - goto error_nolock; - } - return NET_XMIT_BYPASS; - -error: - spin_unlock_bh(&x->lock); -error_nolock: - kfree_skb(skb); - return err; -} - -/* - * Note: detecting truncated vs. non-truncated authentication data is very - * expensive, so we only support truncated data, which is the recommended - * and common case. - */ -int esp_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb) -{ - struct iphdr *iph; - struct ip_esp_hdr *esph; - struct esp_data *esp = x->data; - struct sk_buff *trailer; - int blksize = crypto_tfm_alg_blocksize(esp->conf.tfm); - int alen = esp->auth.icv_trunc_len; - int elen = skb->len - sizeof(struct ip_esp_hdr) - esp->conf.ivlen - alen; - int nfrags; - int encap_len = 0; - - if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr))) - goto out; - - if (elen <= 0 || (elen & (blksize-1))) - goto out; - - /* If integrity check is required, do this. */ - if (esp->auth.icv_full_len) { - u8 sum[esp->auth.icv_full_len]; - u8 sum1[alen]; - - esp->auth.icv(esp, skb, 0, skb->len-alen, sum); - - if (skb_copy_bits(skb, skb->len-alen, sum1, alen)) - BUG(); - - if (unlikely(memcmp(sum, sum1, alen))) { - x->stats.integrity_failed++; - goto out; - } - } - - if ((nfrags = skb_cow_data(skb, 0, &trailer)) < 0) - goto out; - - skb->ip_summed = CHECKSUM_NONE; - - esph = (struct ip_esp_hdr*)skb->data; - iph = skb->nh.iph; - - /* Get ivec. This can be wrong, check against another impls. */ - if (esp->conf.ivlen) - crypto_cipher_set_iv(esp->conf.tfm, esph->enc_data, crypto_tfm_alg_ivsize(esp->conf.tfm)); - - { - u8 nexthdr[2]; - struct scatterlist sgbuf[nfrags>MAX_SG_ONSTACK ? 0 : nfrags]; - struct scatterlist *sg = sgbuf; - u8 workbuf[60]; - int padlen; - - if (unlikely(nfrags > MAX_SG_ONSTACK)) { - sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); - if (!sg) - goto out; - } - skb_to_sgvec(skb, sg, sizeof(struct ip_esp_hdr) + esp->conf.ivlen, elen); - crypto_cipher_decrypt(esp->conf.tfm, sg, sg, elen); - if (unlikely(sg != sgbuf)) - kfree(sg); - - if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2)) - BUG(); - - padlen = nexthdr[0]; - if (padlen+2 >= elen) - goto out; - - /* ... check padding bits here. Silly. :-) */ - - if (x->encap && decap && decap->decap_type) { - struct esp_decap_data *encap_data; - struct udphdr *uh = (struct udphdr *) (iph+1); - - encap_data = (struct esp_decap_data *) (decap->decap_data); - encap_data->proto = 0; - - switch (decap->decap_type) { - case UDP_ENCAP_ESPINUDP: - - if ((void*)uh == (void*)esph) { - printk(KERN_DEBUG - "esp_input(): Got ESP; expecting ESPinUDP\n"); - break; - } - - encap_data->proto = AF_INET; - encap_data->saddr.a4 = iph->saddr; - encap_data->sport = uh->source; - encap_len = (void*)esph - (void*)uh; - if (encap_len != sizeof(*uh)) - printk(KERN_DEBUG - "esp_input(): UDP -> ESP: too much room: %d\n", - encap_len); - break; - - default: - printk(KERN_INFO - "esp_input(): processing unknown encap type: %u\n", - decap->decap_type); - break; - } - } - - iph->protocol = nexthdr[1]; - pskb_trim(skb, skb->len - alen - padlen - 2); - memcpy(workbuf, skb->nh.raw, iph->ihl*4); - skb->h.raw = skb_pull(skb, sizeof(struct ip_esp_hdr) + esp->conf.ivlen); - skb->nh.raw += encap_len + sizeof(struct ip_esp_hdr) + esp->conf.ivlen; - memcpy(skb->nh.raw, workbuf, iph->ihl*4); - skb->nh.iph->tot_len = htons(skb->len); - } - - return 0; - -out: - return -EINVAL; -} - -int esp_post_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb) -{ - - if (x->encap) { - struct xfrm_encap_tmpl *encap; - struct esp_decap_data *decap_data; - - encap = x->encap; - decap_data = (struct esp_decap_data *)(decap->decap_data); - - /* first, make sure that the decap type == the encap type */ - if (encap->encap_type != decap->decap_type) - return -EINVAL; - - /* Next, if we don't have an encap type, then ignore it */ - if (!encap->encap_type) - return 0; - - switch (encap->encap_type) { - case UDP_ENCAP_ESPINUDP: - /* - * 1) if the NAT-T peer's IP or port changed then - * advertize the change to the keying daemon. - * This is an inbound SA, so just compare - * SRC ports. - */ - if (decap_data->proto == AF_INET && - (decap_data->saddr.a4 != x->props.saddr.a4 || - decap_data->sport != encap->encap_sport)) { - xfrm_address_t ipaddr; - - ipaddr.a4 = decap_data->saddr.a4; - km_new_mapping(x, &ipaddr, decap_data->sport); - - /* XXX: perhaps add an extra - * policy check here, to see - * if we should allow or - * reject a packet from a - * different source - * address/port. - */ - } - - /* - * 2) ignore UDP/TCP checksums in case - * of NAT-T in Transport Mode, or - * perform other post-processing fixes - * as per * draft-ietf-ipsec-udp-encaps-06, - * section 3.1.2 - */ - if (!x->props.mode) - skb->ip_summed = CHECKSUM_UNNECESSARY; - - break; - default: - printk(KERN_INFO - "esp4_post_input(): Unhandled encap type: %u\n", - encap->encap_type); - break; - } - } - return 0; -} - -static u32 esp4_get_max_size(struct xfrm_state *x, int mtu) -{ - struct esp_data *esp = x->data; - u32 blksize = crypto_tfm_alg_blocksize(esp->conf.tfm); - - if (x->props.mode) { - mtu = (mtu + 2 + blksize-1)&~(blksize-1); - } else { - /* The worst case. */ - mtu += 2 + blksize; - } - if (esp->conf.padlen) - mtu = (mtu + esp->conf.padlen-1)&~(esp->conf.padlen-1); - - return mtu + x->props.header_len + esp->auth.icv_trunc_len; -} - -void esp4_err(struct sk_buff *skb, u32 info) -{ - struct iphdr *iph = (struct iphdr*)skb->data; - struct ip_esp_hdr *esph = (struct ip_esp_hdr*)(skb->data+(iph->ihl<<2)); - struct xfrm_state *x; - - if (skb->h.icmph->type != ICMP_DEST_UNREACH || - skb->h.icmph->code != ICMP_FRAG_NEEDED) - return; - - x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET); - if (!x) - return; - printk(KERN_DEBUG "pmtu discvovery on SA ESP/%08x/%08x\n", - ntohl(esph->spi), ntohl(iph->daddr)); - xfrm_state_put(x); -} - -void esp_destroy(struct xfrm_state *x) -{ - struct esp_data *esp = x->data; - - if (esp->conf.tfm) { - crypto_free_tfm(esp->conf.tfm); - esp->conf.tfm = NULL; - } - if (esp->conf.ivec) { - kfree(esp->conf.ivec); - esp->conf.ivec = NULL; - } - if (esp->auth.tfm) { - crypto_free_tfm(esp->auth.tfm); - esp->auth.tfm = NULL; - } - if (esp->auth.work_icv) { - kfree(esp->auth.work_icv); - esp->auth.work_icv = NULL; - } - kfree(esp); -} - -int esp_init_state(struct xfrm_state *x, void *args) -{ - struct esp_data *esp = NULL; - - /* null auth and encryption can have zero length keys */ - if (x->aalg) { - if (x->aalg->alg_key_len > 512) - goto error; - } - if (x->ealg == NULL) - goto error; - - esp = kmalloc(sizeof(*esp), GFP_KERNEL); - if (esp == NULL) - return -ENOMEM; - - memset(esp, 0, sizeof(*esp)); - - if (x->aalg) { - struct xfrm_algo_desc *aalg_desc; - - esp->auth.key = x->aalg->alg_key; - esp->auth.key_len = (x->aalg->alg_key_len+7)/8; - esp->auth.tfm = crypto_alloc_tfm(x->aalg->alg_name, 0); - if (esp->auth.tfm == NULL) - goto error; - esp->auth.icv = esp_hmac_digest; - - aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name); - BUG_ON(!aalg_desc); - - if (aalg_desc->uinfo.auth.icv_fullbits/8 != - crypto_tfm_alg_digestsize(esp->auth.tfm)) { - printk(KERN_INFO "ESP: %s digestsize %u != %hu\n", - x->aalg->alg_name, - crypto_tfm_alg_digestsize(esp->auth.tfm), - aalg_desc->uinfo.auth.icv_fullbits/8); - goto error; - } - - esp->auth.icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8; - esp->auth.icv_trunc_len = aalg_desc->uinfo.auth.icv_truncbits/8; - - esp->auth.work_icv = kmalloc(esp->auth.icv_full_len, GFP_KERNEL); - if (!esp->auth.work_icv) - goto error; - } - esp->conf.key = x->ealg->alg_key; - esp->conf.key_len = (x->ealg->alg_key_len+7)/8; - esp->conf.tfm = crypto_alloc_tfm(x->ealg->alg_name, CRYPTO_TFM_MODE_CBC); - if (esp->conf.tfm == NULL) - goto error; - esp->conf.ivlen = crypto_tfm_alg_ivsize(esp->conf.tfm); - esp->conf.padlen = 0; - if (esp->conf.ivlen) { - esp->conf.ivec = kmalloc(esp->conf.ivlen, GFP_KERNEL); - get_random_bytes(esp->conf.ivec, esp->conf.ivlen); - } - crypto_cipher_setkey(esp->conf.tfm, esp->conf.key, esp->conf.key_len); - x->props.header_len = sizeof(struct ip_esp_hdr) + esp->conf.ivlen; - if (x->props.mode) - x->props.header_len += sizeof(struct iphdr); - if (x->encap) { - struct xfrm_encap_tmpl *encap = x->encap; - - if (encap->encap_type) { - switch (encap->encap_type) { - case UDP_ENCAP_ESPINUDP: - x->props.header_len += sizeof(struct udphdr); - break; - default: - printk (KERN_INFO - "esp_init_state(): Unhandled encap type: %u\n", - encap->encap_type); - break; - } - } - } - x->data = esp; - x->props.trailer_len = esp4_get_max_size(x, 0) - x->props.header_len; - return 0; - -error: - if (esp) { - if (esp->auth.tfm) - crypto_free_tfm(esp->auth.tfm); - if (esp->auth.work_icv) - kfree(esp->auth.work_icv); - if (esp->conf.tfm) - crypto_free_tfm(esp->conf.tfm); - kfree(esp); - } - return -EINVAL; -} - -static struct xfrm_type esp_type = -{ - .description = "ESP4", - .owner = THIS_MODULE, - .proto = IPPROTO_ESP, - .init_state = esp_init_state, - .destructor = esp_destroy, - .get_max_size = esp4_get_max_size, - .input = esp_input, - .post_input = esp_post_input, - .output = esp_output -}; - -static struct inet_protocol esp4_protocol = { - .handler = xfrm4_rcv, - .err_handler = esp4_err, - .no_policy = 1, -}; - -int __init esp4_init(void) -{ - struct xfrm_decap_state decap; - - if (sizeof(struct esp_decap_data) < - sizeof(decap.decap_data)) { - extern void decap_data_too_small(void); - - decap_data_too_small(); - } - - esp_type.owner = THIS_MODULE; - if (xfrm_register_type(&esp_type, AF_INET) < 0) { - printk(KERN_INFO "ip esp init: can't add xfrm type\n"); - return -EAGAIN; - } - if (inet_add_protocol(&esp4_protocol, IPPROTO_ESP) < 0) { - printk(KERN_INFO "ip esp init: can't add protocol\n"); - xfrm_unregister_type(&esp_type, AF_INET); - return -EAGAIN; - } - return 0; -} - -static void __exit esp4_fini(void) -{ - if (inet_del_protocol(&esp4_protocol, IPPROTO_ESP) < 0) - printk(KERN_INFO "ip esp close: can't remove protocol\n"); - if (xfrm_unregister_type(&esp_type, AF_INET) < 0) - printk(KERN_INFO "ip esp close: can't remove xfrm type\n"); -} - -module_init(esp4_init); -module_exit(esp4_fini); -MODULE_LICENSE("GPL"); diff -Nru a/net/ipv4/esp4.c b/net/ipv4/esp4.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/ipv4/esp4.c Mon Jun 9 23:16:14 2003 @@ -0,0 +1,603 @@ +#include <linux/config.h> +#include <linux/module.h> +#include <net/ip.h> +#include <net/xfrm.h> +#include <net/esp.h> +#include <asm/scatterlist.h> +#include <linux/crypto.h> +#include <linux/pfkeyv2.h> +#include <linux/random.h> +#include <net/icmp.h> +#include <net/udp.h> + +#define MAX_SG_ONSTACK 4 + +/* decapsulation data for use when post-processing */ +struct esp_decap_data { + xfrm_address_t saddr; + __u16 sport; + __u8 proto; +}; + +int esp_output(struct sk_buff *skb) +{ + int err; + struct dst_entry *dst = skb->dst; + struct xfrm_state *x = dst->xfrm; + struct iphdr *iph, *top_iph; + struct ip_esp_hdr *esph; + struct crypto_tfm *tfm; + struct esp_data *esp; + struct sk_buff *trailer; + struct udphdr *uh = NULL; + struct xfrm_encap_tmpl *encap = NULL; + int blksize; + int clen; + int alen; + int nfrags; + union { + struct iphdr iph; + char buf[60]; + } tmp_iph; + + /* First, if the skb is not checksummed, complete checksum. */ + if (skb->ip_summed == CHECKSUM_HW && skb_checksum_help(skb) == NULL) { + err = -EINVAL; + goto error_nolock; + } + + spin_lock_bh(&x->lock); + err = xfrm_check_output(x, skb, AF_INET); + if (err) + goto error; + err = -ENOMEM; + + /* Strip IP header in transport mode. Save it. */ + if (!x->props.mode) { + iph = skb->nh.iph; + memcpy(&tmp_iph, iph, iph->ihl*4); + __skb_pull(skb, iph->ihl*4); + } + /* Now skb is pure payload to encrypt */ + + /* Round to block size */ + clen = skb->len; + + esp = x->data; + alen = esp->auth.icv_trunc_len; + tfm = esp->conf.tfm; + blksize = (crypto_tfm_alg_blocksize(tfm) + 3) & ~3; + clen = (clen + 2 + blksize-1)&~(blksize-1); + if (esp->conf.padlen) + clen = (clen + esp->conf.padlen-1)&~(esp->conf.padlen-1); + + if ((nfrags = skb_cow_data(skb, clen-skb->len+alen, &trailer)) < 0) + goto error; + + /* Fill padding... */ + do { + int i; + for (i=0; i<clen-skb->len - 2; i++) + *(u8*)(trailer->tail + i) = i+1; + } while (0); + *(u8*)(trailer->tail + clen-skb->len - 2) = (clen - skb->len)-2; + pskb_put(skb, trailer, clen - skb->len); + + encap = x->encap; + + iph = skb->nh.iph; + if (x->props.mode) { + top_iph = (struct iphdr*)skb_push(skb, x->props.header_len); + esph = (struct ip_esp_hdr*)(top_iph+1); + if (encap && encap->encap_type) { + switch (encap->encap_type) { + case UDP_ENCAP_ESPINUDP: + uh = (struct udphdr*) esph; + esph = (struct ip_esp_hdr*)(uh+1); + top_iph->protocol = IPPROTO_UDP; + break; + default: + printk(KERN_INFO + "esp_output(): Unhandled encap: %u\n", + encap->encap_type); + top_iph->protocol = IPPROTO_ESP; + break; + } + } else + top_iph->protocol = IPPROTO_ESP; + *(u8*)(trailer->tail - 1) = IPPROTO_IPIP; + top_iph->ihl = 5; + top_iph->version = 4; + top_iph->tos = iph->tos; /* DS disclosed */ + top_iph->tot_len = htons(skb->len + alen); + top_iph->frag_off = iph->frag_off&htons(IP_DF); + if (!(top_iph->frag_off)) + ip_select_ident(top_iph, dst, 0); + top_iph->ttl = iph->ttl; /* TTL disclosed */ + top_iph->check = 0; + top_iph->saddr = x->props.saddr.a4; + top_iph->daddr = x->id.daddr.a4; + memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options)); + } else { + esph = (struct ip_esp_hdr*)skb_push(skb, x->props.header_len); + top_iph = (struct iphdr*)skb_push(skb, iph->ihl*4); + memcpy(top_iph, &tmp_iph, iph->ihl*4); + if (encap && encap->encap_type) { + switch (encap->encap_type) { + case UDP_ENCAP_ESPINUDP: + uh = (struct udphdr*) esph; + esph = (struct ip_esp_hdr*)(uh+1); + top_iph->protocol = IPPROTO_UDP; + break; + default: + printk(KERN_INFO + "esp_output(): Unhandled encap: %u\n", + encap->encap_type); + top_iph->protocol = IPPROTO_ESP; + break; + } + } else + top_iph->protocol = IPPROTO_ESP; + iph = &tmp_iph.iph; + top_iph->tot_len = htons(skb->len + alen); + top_iph->check = 0; + top_iph->frag_off = iph->frag_off; + *(u8*)(trailer->tail - 1) = iph->protocol; + } + + /* this is non-NULL only with UDP Encapsulation */ + if (encap && uh) { + uh->source = encap->encap_sport; + uh->dest = encap->encap_dport; + uh->len = htons(skb->len + alen - sizeof(struct iphdr)); + uh->check = 0; + } + + esph->spi = x->id.spi; + esph->seq_no = htonl(++x->replay.oseq); + + if (esp->conf.ivlen) + crypto_cipher_set_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm)); + + do { + struct scatterlist sgbuf[nfrags>MAX_SG_ONSTACK ? 0 : nfrags]; + struct scatterlist *sg = sgbuf; + + if (unlikely(nfrags > MAX_SG_ONSTACK)) { + sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); + if (!sg) + goto error; + } + skb_to_sgvec(skb, sg, esph->enc_data+esp->conf.ivlen-skb->data, clen); + crypto_cipher_encrypt(tfm, sg, sg, clen); + if (unlikely(sg != sgbuf)) + kfree(sg); + } while (0); + + if (esp->conf.ivlen) { + memcpy(esph->enc_data, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm)); + crypto_cipher_get_iv(tfm, esp->conf.ivec, crypto_tfm_alg_ivsize(tfm)); + } + + if (esp->auth.icv_full_len) { + esp->auth.icv(esp, skb, (u8*)esph-skb->data, + sizeof(struct ip_esp_hdr) + esp->conf.ivlen+clen, trailer->tail); + pskb_put(skb, trailer, alen); + } + + ip_send_check(top_iph); + + skb->nh.raw = skb->data; + + x->curlft.bytes += skb->len; + x->curlft.packets++; + spin_unlock_bh(&x->lock); + if ((skb->dst = dst_pop(dst)) == NULL) { + err = -EHOSTUNREACH; + goto error_nolock; + } + return NET_XMIT_BYPASS; + +error: + spin_unlock_bh(&x->lock); +error_nolock: + kfree_skb(skb); + return err; +} + +/* + * Note: detecting truncated vs. non-truncated authentication data is very + * expensive, so we only support truncated data, which is the recommended + * and common case. + */ +int esp_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb) +{ + struct iphdr *iph; + struct ip_esp_hdr *esph; + struct esp_data *esp = x->data; + struct sk_buff *trailer; + int blksize = crypto_tfm_alg_blocksize(esp->conf.tfm); + int alen = esp->auth.icv_trunc_len; + int elen = skb->len - sizeof(struct ip_esp_hdr) - esp->conf.ivlen - alen; + int nfrags; + int encap_len = 0; + + if (!pskb_may_pull(skb, sizeof(struct ip_esp_hdr))) + goto out; + + if (elen <= 0 || (elen & (blksize-1))) + goto out; + + /* If integrity check is required, do this. */ + if (esp->auth.icv_full_len) { + u8 sum[esp->auth.icv_full_len]; + u8 sum1[alen]; + + esp->auth.icv(esp, skb, 0, skb->len-alen, sum); + + if (skb_copy_bits(skb, skb->len-alen, sum1, alen)) + BUG(); + + if (unlikely(memcmp(sum, sum1, alen))) { + x->stats.integrity_failed++; + goto out; + } + } + + if ((nfrags = skb_cow_data(skb, 0, &trailer)) < 0) + goto out; + + skb->ip_summed = CHECKSUM_NONE; + + esph = (struct ip_esp_hdr*)skb->data; + iph = skb->nh.iph; + + /* Get ivec. This can be wrong, check against another impls. */ + if (esp->conf.ivlen) + crypto_cipher_set_iv(esp->conf.tfm, esph->enc_data, crypto_tfm_alg_ivsize(esp->conf.tfm)); + + { + u8 nexthdr[2]; + struct scatterlist sgbuf[nfrags>MAX_SG_ONSTACK ? 0 : nfrags]; + struct scatterlist *sg = sgbuf; + u8 workbuf[60]; + int padlen; + + if (unlikely(nfrags > MAX_SG_ONSTACK)) { + sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); + if (!sg) + goto out; + } + skb_to_sgvec(skb, sg, sizeof(struct ip_esp_hdr) + esp->conf.ivlen, elen); + crypto_cipher_decrypt(esp->conf.tfm, sg, sg, elen); + if (unlikely(sg != sgbuf)) + kfree(sg); + + if (skb_copy_bits(skb, skb->len-alen-2, nexthdr, 2)) + BUG(); + + padlen = nexthdr[0]; + if (padlen+2 >= elen) + goto out; + + /* ... check padding bits here. Silly. :-) */ + + if (x->encap && decap && decap->decap_type) { + struct esp_decap_data *encap_data; + struct udphdr *uh = (struct udphdr *) (iph+1); + + encap_data = (struct esp_decap_data *) (decap->decap_data); + encap_data->proto = 0; + + switch (decap->decap_type) { + case UDP_ENCAP_ESPINUDP: + + if ((void*)uh == (void*)esph) { + printk(KERN_DEBUG + "esp_input(): Got ESP; expecting ESPinUDP\n"); + break; + } + + encap_data->proto = AF_INET; + encap_data->saddr.a4 = iph->saddr; + encap_data->sport = uh->source; + encap_len = (void*)esph - (void*)uh; + if (encap_len != sizeof(*uh)) + printk(KERN_DEBUG + "esp_input(): UDP -> ESP: too much room: %d\n", + encap_len); + break; + + default: + printk(KERN_INFO + "esp_input(): processing unknown encap type: %u\n", + decap->decap_type); + break; + } + } + + iph->protocol = nexthdr[1]; + pskb_trim(skb, skb->len - alen - padlen - 2); + memcpy(workbuf, skb->nh.raw, iph->ihl*4); + skb->h.raw = skb_pull(skb, sizeof(struct ip_esp_hdr) + esp->conf.ivlen); + skb->nh.raw += encap_len + sizeof(struct ip_esp_hdr) + esp->conf.ivlen; + memcpy(skb->nh.raw, workbuf, iph->ihl*4); + skb->nh.iph->tot_len = htons(skb->len); + } + + return 0; + +out: + return -EINVAL; +} + +int esp_post_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb) +{ + + if (x->encap) { + struct xfrm_encap_tmpl *encap; + struct esp_decap_data *decap_data; + + encap = x->encap; + decap_data = (struct esp_decap_data *)(decap->decap_data); + + /* first, make sure that the decap type == the encap type */ + if (encap->encap_type != decap->decap_type) + return -EINVAL; + + /* Next, if we don't have an encap type, then ignore it */ + if (!encap->encap_type) + return 0; + + switch (encap->encap_type) { + case UDP_ENCAP_ESPINUDP: + /* + * 1) if the NAT-T peer's IP or port changed then + * advertize the change to the keying daemon. + * This is an inbound SA, so just compare + * SRC ports. + */ + if (decap_data->proto == AF_INET && + (decap_data->saddr.a4 != x->props.saddr.a4 || + decap_data->sport != encap->encap_sport)) { + xfrm_address_t ipaddr; + + ipaddr.a4 = decap_data->saddr.a4; + km_new_mapping(x, &ipaddr, decap_data->sport); + + /* XXX: perhaps add an extra + * policy check here, to see + * if we should allow or + * reject a packet from a + * different source + * address/port. + */ + } + + /* + * 2) ignore UDP/TCP checksums in case + * of NAT-T in Transport Mode, or + * perform other post-processing fixes + * as per * draft-ietf-ipsec-udp-encaps-06, + * section 3.1.2 + */ + if (!x->props.mode) + skb->ip_summed = CHECKSUM_UNNECESSARY; + + break; + default: + printk(KERN_INFO + "esp4_post_input(): Unhandled encap type: %u\n", + encap->encap_type); + break; + } + } + return 0; +} + +static u32 esp4_get_max_size(struct xfrm_state *x, int mtu) +{ + struct esp_data *esp = x->data; + u32 blksize = crypto_tfm_alg_blocksize(esp->conf.tfm); + + if (x->props.mode) { + mtu = (mtu + 2 + blksize-1)&~(blksize-1); + } else { + /* The worst case. */ + mtu += 2 + blksize; + } + if (esp->conf.padlen) + mtu = (mtu + esp->conf.padlen-1)&~(esp->conf.padlen-1); + + return mtu + x->props.header_len + esp->auth.icv_trunc_len; +} + +void esp4_err(struct sk_buff *skb, u32 info) +{ + struct iphdr *iph = (struct iphdr*)skb->data; + struct ip_esp_hdr *esph = (struct ip_esp_hdr*)(skb->data+(iph->ihl<<2)); + struct xfrm_state *x; + + if (skb->h.icmph->type != ICMP_DEST_UNREACH || + skb->h.icmph->code != ICMP_FRAG_NEEDED) + return; + + x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET); + if (!x) + return; + printk(KERN_DEBUG "pmtu discvovery on SA ESP/%08x/%08x\n", + ntohl(esph->spi), ntohl(iph->daddr)); + xfrm_state_put(x); +} + +void esp_destroy(struct xfrm_state *x) +{ + struct esp_data *esp = x->data; + + if (esp->conf.tfm) { + crypto_free_tfm(esp->conf.tfm); + esp->conf.tfm = NULL; + } + if (esp->conf.ivec) { + kfree(esp->conf.ivec); + esp->conf.ivec = NULL; + } + if (esp->auth.tfm) { + crypto_free_tfm(esp->auth.tfm); + esp->auth.tfm = NULL; + } + if (esp->auth.work_icv) { + kfree(esp->auth.work_icv); + esp->auth.work_icv = NULL; + } + kfree(esp); +} + +int esp_init_state(struct xfrm_state *x, void *args) +{ + struct esp_data *esp = NULL; + + /* null auth and encryption can have zero length keys */ + if (x->aalg) { + if (x->aalg->alg_key_len > 512) + goto error; + } + if (x->ealg == NULL) + goto error; + + esp = kmalloc(sizeof(*esp), GFP_KERNEL); + if (esp == NULL) + return -ENOMEM; + + memset(esp, 0, sizeof(*esp)); + + if (x->aalg) { + struct xfrm_algo_desc *aalg_desc; + + esp->auth.key = x->aalg->alg_key; + esp->auth.key_len = (x->aalg->alg_key_len+7)/8; + esp->auth.tfm = crypto_alloc_tfm(x->aalg->alg_name, 0); + if (esp->auth.tfm == NULL) + goto error; + esp->auth.icv = esp_hmac_digest; + + aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name); + BUG_ON(!aalg_desc); + + if (aalg_desc->uinfo.auth.icv_fullbits/8 != + crypto_tfm_alg_digestsize(esp->auth.tfm)) { + printk(KERN_INFO "ESP: %s digestsize %u != %hu\n", + x->aalg->alg_name, + crypto_tfm_alg_digestsize(esp->auth.tfm), + aalg_desc->uinfo.auth.icv_fullbits/8); + goto error; + } + + esp->auth.icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8; + esp->auth.icv_trunc_len = aalg_desc->uinfo.auth.icv_truncbits/8; + + esp->auth.work_icv = kmalloc(esp->auth.icv_full_len, GFP_KERNEL); + if (!esp->auth.work_icv) + goto error; + } + esp->conf.key = x->ealg->alg_key; + esp->conf.key_len = (x->ealg->alg_key_len+7)/8; + esp->conf.tfm = crypto_alloc_tfm(x->ealg->alg_name, CRYPTO_TFM_MODE_CBC); + if (esp->conf.tfm == NULL) + goto error; + esp->conf.ivlen = crypto_tfm_alg_ivsize(esp->conf.tfm); + esp->conf.padlen = 0; + if (esp->conf.ivlen) { + esp->conf.ivec = kmalloc(esp->conf.ivlen, GFP_KERNEL); + get_random_bytes(esp->conf.ivec, esp->conf.ivlen); + } + crypto_cipher_setkey(esp->conf.tfm, esp->conf.key, esp->conf.key_len); + x->props.header_len = sizeof(struct ip_esp_hdr) + esp->conf.ivlen; + if (x->props.mode) + x->props.header_len += sizeof(struct iphdr); + if (x->encap) { + struct xfrm_encap_tmpl *encap = x->encap; + + if (encap->encap_type) { + switch (encap->encap_type) { + case UDP_ENCAP_ESPINUDP: + x->props.header_len += sizeof(struct udphdr); + break; + default: + printk (KERN_INFO + "esp_init_state(): Unhandled encap type: %u\n", + encap->encap_type); + break; + } + } + } + x->data = esp; + x->props.trailer_len = esp4_get_max_size(x, 0) - x->props.header_len; + return 0; + +error: + if (esp) { + if (esp->auth.tfm) + crypto_free_tfm(esp->auth.tfm); + if (esp->auth.work_icv) + kfree(esp->auth.work_icv); + if (esp->conf.tfm) + crypto_free_tfm(esp->conf.tfm); + kfree(esp); + } + return -EINVAL; +} + +static struct xfrm_type esp_type = +{ + .description = "ESP4", + .owner = THIS_MODULE, + .proto = IPPROTO_ESP, + .init_state = esp_init_state, + .destructor = esp_destroy, + .get_max_size = esp4_get_max_size, + .input = esp_input, + .post_input = esp_post_input, + .output = esp_output +}; + +static struct inet_protocol esp4_protocol = { + .handler = xfrm4_rcv, + .err_handler = esp4_err, + .no_policy = 1, +}; + +static int __init esp4_init(void) +{ + struct xfrm_decap_state decap; + + if (sizeof(struct esp_decap_data) < + sizeof(decap.decap_data)) { + extern void decap_data_too_small(void); + + decap_data_too_small(); + } + + if (xfrm_register_type(&esp_type, AF_INET) < 0) { + printk(KERN_INFO "ip esp init: can't add xfrm type\n"); + return -EAGAIN; + } + if (inet_add_protocol(&esp4_protocol, IPPROTO_ESP) < 0) { + printk(KERN_INFO "ip esp init: can't add protocol\n"); + xfrm_unregister_type(&esp_type, AF_INET); + return -EAGAIN; + } + return 0; +} + +static void __exit esp4_fini(void) +{ + if (inet_del_protocol(&esp4_protocol, IPPROTO_ESP) < 0) + printk(KERN_INFO "ip esp close: can't remove protocol\n"); + if (xfrm_unregister_type(&esp_type, AF_INET) < 0) + printk(KERN_INFO "ip esp close: can't remove xfrm type\n"); +} + +module_init(esp4_init); +module_exit(esp4_fini); +MODULE_LICENSE("GPL"); diff -Nru a/net/ipv4/icmp.c b/net/ipv4/icmp.c --- a/net/ipv4/icmp.c Mon Jun 9 23:16:18 2003 +++ b/net/ipv4/icmp.c Mon Jun 9 23:16:18 2003 @@ -234,13 +234,13 @@ { local_bh_disable(); - if (unlikely(!spin_trylock(&icmp_socket->sk->lock.slock))) + if (unlikely(!spin_trylock(&icmp_socket->sk->sk_lock.slock))) BUG(); } static void icmp_xmit_unlock(void) { - spin_unlock_bh(&icmp_socket->sk->lock.slock); + spin_unlock_bh(&icmp_socket->sk->sk_lock.slock); } /* @@ -344,12 +344,12 @@ icmp_param->head_len, ipc, rt, MSG_DONTWAIT); - if ((skb = skb_peek(&icmp_socket->sk->write_queue)) != NULL) { + if ((skb = skb_peek(&icmp_socket->sk->sk_write_queue)) != NULL) { struct icmphdr *icmph = skb->h.icmph; unsigned int csum = 0; struct sk_buff *skb1; - skb_queue_walk(&icmp_socket->sk->write_queue, skb1) { + skb_queue_walk(&icmp_socket->sk->sk_write_queue, skb1) { csum = csum_add(csum, skb1->csum); } csum = csum_partial_copy_nocheck((void *)&icmp_param->data, @@ -685,7 +685,7 @@ iph->saddr, skb->dev->ifindex)) != NULL) { raw_err(raw_sk, skb, info); - raw_sk = raw_sk->next; + raw_sk = raw_sk->sk_next; iph = (struct iphdr *)skb->data; } } @@ -1101,8 +1101,8 @@ if (err < 0) panic("Failed to create the ICMP control socket.\n"); - per_cpu(__icmp_socket, i)->sk->allocation = GFP_ATOMIC; - per_cpu(__icmp_socket, i)->sk->sndbuf = SK_WMEM_MAX * 2; + per_cpu(__icmp_socket, i)->sk->sk_allocation = GFP_ATOMIC; + per_cpu(__icmp_socket, i)->sk->sk_sndbuf = SK_WMEM_MAX * 2; inet = inet_sk(per_cpu(__icmp_socket, i)->sk); inet->uc_ttl = -1; inet->pmtudisc = IP_PMTUDISC_DONT; @@ -1111,6 +1111,6 @@ * see it, we do not wish this socket to see incoming * packets. */ - per_cpu(__icmp_socket, i)->sk->prot->unhash(per_cpu(__icmp_socket, i)->sk); + per_cpu(__icmp_socket, i)->sk->sk_prot->unhash(per_cpu(__icmp_socket, i)->sk); } } diff -Nru a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c --- a/net/ipv4/ip_fragment.c Mon Jun 9 23:16:09 2003 +++ b/net/ipv4/ip_fragment.c Mon Jun 9 23:16:09 2003 @@ -31,6 +31,8 @@ #include <linux/ip.h> #include <linux/icmp.h> #include <linux/netdevice.h> +#include <linux/jhash.h> +#include <linux/random.h> #include <net/sock.h> #include <net/ip.h> #include <net/icmp.h> @@ -97,6 +99,7 @@ /* Per-bucket lock is easy to add now. */ static struct ipq *ipq_hash[IPQ_HASHSZ]; static rwlock_t ipfrag_lock = RW_LOCK_UNLOCKED; +static u32 ipfrag_hash_rnd; static LIST_HEAD(ipq_lru_list); int ip_frag_nqueues = 0; @@ -116,21 +119,51 @@ write_unlock(&ipfrag_lock); } -/* - * Was: ((((id) >> 1) ^ (saddr) ^ (daddr) ^ (prot)) & (IPQ_HASHSZ - 1)) - * - * I see, I see evil hand of bigendian mafia. On Intel all the packets hit - * one hash bucket with this hash function. 8) - */ -static __inline__ unsigned int ipqhashfn(u16 id, u32 saddr, u32 daddr, u8 prot) +static unsigned int ipqhashfn(u16 id, u32 saddr, u32 daddr, u8 prot) { - unsigned int h = saddr ^ daddr; - - h ^= (h>>16)^id; - h ^= (h>>8)^prot; - return h & (IPQ_HASHSZ - 1); + return jhash_3words((u32)id << 16 | prot, saddr, daddr, + ipfrag_hash_rnd) & (IPQ_HASHSZ - 1); } +static struct timer_list ipfrag_secret_timer; +int sysctl_ipfrag_secret_interval = 10 * 60 * HZ; + +static void ipfrag_secret_rebuild(unsigned long dummy) +{ + unsigned long now = jiffies; + int i; + + write_lock(&ipfrag_lock); + get_random_bytes(&ipfrag_hash_rnd, sizeof(u32)); + for (i = 0; i < IPQ_HASHSZ; i++) { + struct ipq *q; + + q = ipq_hash[i]; + while (q) { + struct ipq *next = q->next; + unsigned int hval = ipqhashfn(q->id, q->saddr, + q->daddr, q->protocol); + + if (hval != i) { + /* Unlink. */ + if (q->next) + q->next->pprev = q->pprev; + *q->pprev = q->next; + + /* Relink to new hash chain. */ + if ((q->next = ipq_hash[hval]) != NULL) + q->next->pprev = &q->next; + ipq_hash[hval] = q; + q->pprev = &ipq_hash[hval]; + } + + q = next; + } + } + write_unlock(&ipfrag_lock); + + mod_timer(&ipfrag_secret_timer, now + sysctl_ipfrag_secret_interval); +} atomic_t ip_frag_mem = ATOMIC_INIT(0); /* Memory used for fragments */ @@ -630,4 +663,15 @@ IP_INC_STATS_BH(IpReasmFails); kfree_skb(skb); return NULL; +} + +void ipfrag_init(void) +{ + ipfrag_hash_rnd = (u32) ((num_physpages ^ (num_physpages>>7)) ^ + (jiffies ^ (jiffies >> 6))); + + init_timer(&ipfrag_secret_timer); + ipfrag_secret_timer.function = ipfrag_secret_rebuild; + ipfrag_secret_timer.expires = jiffies + sysctl_ipfrag_secret_interval; + add_timer(&ipfrag_secret_timer); } diff -Nru a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c --- a/net/ipv4/ip_input.c Mon Jun 9 23:16:06 2003 +++ b/net/ipv4/ip_input.c Mon Jun 9 23:16:06 2003 @@ -167,9 +167,9 @@ /* If socket is bound to an interface, only report * the packet if it came from that interface. */ - if (sk && inet_sk(sk)->num == protocol - && ((sk->bound_dev_if == 0) - || (sk->bound_dev_if == skb->dev->ifindex))) { + if (sk && inet_sk(sk)->num == protocol && + (!sk->sk_bound_dev_if || + sk->sk_bound_dev_if == skb->dev->ifindex)) { if (skb->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) { skb = ip_defrag(skb); if (skb == NULL) { diff -Nru a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c --- a/net/ipv4/ip_output.c Mon Jun 9 23:16:19 2003 +++ b/net/ipv4/ip_output.c Mon Jun 9 23:16:19 2003 @@ -148,7 +148,7 @@ iph->ttl = ip_select_ttl(inet, &rt->u.dst); iph->daddr = rt->rt_dst; iph->saddr = rt->rt_src; - iph->protocol = sk->protocol; + iph->protocol = sk->sk_protocol; iph->tot_len = htons(skb->len); ip_select_ident(iph, &rt->u.dst, sk); skb->nh.iph = iph; @@ -159,7 +159,7 @@ } ip_send_check(iph); - skb->priority = sk->priority; + skb->priority = sk->sk_priority; /* Send it out. */ return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev, @@ -316,12 +316,12 @@ daddr = opt->faddr; { - struct flowi fl = { .oif = sk->bound_dev_if, + struct flowi fl = { .oif = sk->sk_bound_dev_if, .nl_u = { .ip4_u = { .daddr = daddr, .saddr = inet->saddr, .tos = RT_CONN_FLAGS(sk) } }, - .proto = sk->protocol, + .proto = sk->sk_protocol, .uli_u = { .ports = { .sport = inet->sport, .dport = inet->dport } } }; @@ -351,7 +351,7 @@ else iph->frag_off = 0; iph->ttl = ip_select_ttl(inet, &rt->u.dst); - iph->protocol = sk->protocol; + iph->protocol = sk->sk_protocol; iph->saddr = rt->rt_src; iph->daddr = rt->rt_dst; skb->nh.iph = iph; @@ -363,7 +363,7 @@ } mtu = dst_pmtu(&rt->u.dst); - if (skb->len > mtu && (sk->route_caps&NETIF_F_TSO)) { + if (skb->len > mtu && (sk->sk_route_caps & NETIF_F_TSO)) { unsigned int hlen; /* Hack zone: all this must be done by TCP. */ @@ -379,7 +379,7 @@ /* Add an IP checksum. */ ip_send_check(iph); - skb->priority = sk->priority; + skb->priority = sk->sk_priority; return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev, dst_output); @@ -739,14 +739,14 @@ if (flags&MSG_PROBE) return 0; - if (skb_queue_empty(&sk->write_queue)) { + if (skb_queue_empty(&sk->sk_write_queue)) { /* * setup for corking. */ opt = ipc->opt; if (opt) { if (inet->cork.opt == NULL) - inet->cork.opt = kmalloc(sizeof(struct ip_options)+40, sk->allocation); + inet->cork.opt = kmalloc(sizeof(struct ip_options) + 40, sk->sk_allocation); memcpy(inet->cork.opt, opt, sizeof(struct ip_options)+opt->optlen); inet->cork.flags |= IPCORK_OPT; inet->cork.addr = ipc->addr; @@ -805,7 +805,7 @@ * it is not necessary. Not a big bug, but needs a fix. */ - if ((skb = skb_peek_tail(&sk->write_queue)) == NULL) + if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL) goto alloc_new_skb; while (length > 0) { @@ -842,10 +842,11 @@ (flags & MSG_DONTWAIT), &err); } else { skb = NULL; - if (atomic_read(&sk->wmem_alloc) <= 2*sk->sndbuf) + if (atomic_read(&sk->sk_wmem_alloc) <= + 2 * sk->sk_sndbuf) skb = sock_wmalloc(sk, alloclen + hh_len + 15, 1, - sk->allocation); + sk->sk_allocation); if (unlikely(skb == NULL)) err = -ENOBUFS; } @@ -883,7 +884,7 @@ /* * Put the packet on the pending queue. */ - __skb_queue_tail(&sk->write_queue, skb); + __skb_queue_tail(&sk->sk_write_queue, skb); continue; } @@ -922,7 +923,7 @@ } else if (i < MAX_SKB_FRAGS) { if (copy > PAGE_SIZE) copy = PAGE_SIZE; - page = alloc_pages(sk->allocation, 0); + page = alloc_pages(sk->sk_allocation, 0); if (page == NULL) { err = -ENOMEM; goto error; @@ -933,7 +934,7 @@ skb_fill_page_desc(skb, i, page, 0, 0); frag = &skb_shinfo(skb)->frags[i]; skb->truesize += PAGE_SIZE; - atomic_add(PAGE_SIZE, &sk->wmem_alloc); + atomic_add(PAGE_SIZE, &sk->sk_wmem_alloc); } else { err = -EMSGSIZE; goto error; @@ -978,7 +979,7 @@ if (flags&MSG_PROBE) return 0; - if (skb_queue_empty(&sk->write_queue)) + if (skb_queue_empty(&sk->sk_write_queue)) return -EINVAL; rt = inet->cork.rt; @@ -999,7 +1000,7 @@ return -EMSGSIZE; } - if ((skb = skb_peek_tail(&sk->write_queue)) == NULL) + if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL) return -EINVAL; inet->cork.length += size; @@ -1012,7 +1013,7 @@ BUG_TRAP(len == 0); skb = sock_wmalloc(sk, fragheaderlen + hh_len + 15, 1, - sk->allocation); + sk->sk_allocation); if (unlikely(!skb)) { err = -ENOBUFS; goto error; @@ -1036,7 +1037,7 @@ /* * Put the packet on the pending queue. */ - __skb_queue_tail(&sk->write_queue, skb); + __skb_queue_tail(&sk->sk_write_queue, skb); continue; } @@ -1088,14 +1089,14 @@ __u8 ttl; int err = 0; - if ((skb = __skb_dequeue(&sk->write_queue)) == NULL) + if ((skb = __skb_dequeue(&sk->sk_write_queue)) == NULL) goto out; tail_skb = &(skb_shinfo(skb)->frag_list); /* move skb->data to ip header from ext header */ if (skb->data < skb->nh.raw) __skb_pull(skb, skb->nh.raw - skb->data); - while ((tmp_skb = __skb_dequeue(&sk->write_queue)) != NULL) { + while ((tmp_skb = __skb_dequeue(&sk->sk_write_queue)) != NULL) { __skb_pull(tmp_skb, skb->h.raw - skb->nh.raw); *tail_skb = tmp_skb; tail_skb = &(tmp_skb->next); @@ -1147,12 +1148,12 @@ iph->id = htons(inet->id++); } iph->ttl = ttl; - iph->protocol = sk->protocol; + iph->protocol = sk->sk_protocol; iph->saddr = rt->rt_src; iph->daddr = rt->rt_dst; ip_send_check(iph); - skb->priority = sk->priority; + skb->priority = sk->sk_priority; skb->dst = dst_clone(&rt->u.dst); /* Netfilter gets whole the not fragmented skb. */ @@ -1186,7 +1187,7 @@ struct inet_opt *inet = inet_sk(sk); struct sk_buff *skb; - while ((skb = __skb_dequeue_tail(&sk->write_queue)) != NULL) + while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) kfree_skb(skb); inet->cork.flags &= ~IPCORK_OPT; @@ -1257,7 +1258,7 @@ .uli_u = { .ports = { .sport = skb->h.th->dest, .dport = skb->h.th->source } }, - .proto = sk->protocol }; + .proto = sk->sk_protocol }; if (ip_route_output_key(&rt, &fl)) return; } @@ -1270,11 +1271,11 @@ */ bh_lock_sock(sk); inet->tos = skb->nh.iph->tos; - sk->priority = skb->priority; - sk->protocol = skb->nh.iph->protocol; + sk->sk_priority = skb->priority; + sk->sk_protocol = skb->nh.iph->protocol; ip_append_data(sk, ip_reply_glue_bits, arg->iov->iov_base, len, 0, &ipc, rt, MSG_DONTWAIT); - if ((skb = skb_peek(&sk->write_queue)) != NULL) { + if ((skb = skb_peek(&sk->sk_write_queue)) != NULL) { if (arg->csumoffset >= 0) *((u16 *)skb->h.raw + arg->csumoffset) = csum_fold(csum_add(skb->csum, arg->csum)); skb->ip_summed = CHECKSUM_NONE; diff -Nru a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c --- a/net/ipv4/ip_sockglue.c Mon Jun 9 23:16:09 2003 +++ b/net/ipv4/ip_sockglue.c Mon Jun 9 23:16:09 2003 @@ -194,7 +194,7 @@ { struct ip_ra_chain *ra, *new_ra, **rap; - if (sk->type != SOCK_RAW || inet_sk(sk)->num == IPPROTO_RAW) + if (sk->sk_type != SOCK_RAW || inet_sk(sk)->num == IPPROTO_RAW) return -EINVAL; new_ra = on ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL; @@ -315,7 +315,7 @@ int copied; err = -EAGAIN; - skb = skb_dequeue(&sk->error_queue); + skb = skb_dequeue(&sk->sk_error_queue); if (skb == NULL) goto out; @@ -362,15 +362,14 @@ err = copied; /* Reset and regenerate socket error */ - spin_lock_irq(&sk->error_queue.lock); - sk->err = 0; - if ((skb2 = skb_peek(&sk->error_queue)) != NULL) { - sk->err = SKB_EXT_ERR(skb2)->ee.ee_errno; - spin_unlock_irq(&sk->error_queue.lock); - sk->error_report(sk); - } else { - spin_unlock_irq(&sk->error_queue.lock); - } + spin_lock_irq(&sk->sk_error_queue.lock); + sk->sk_err = 0; + if ((skb2 = skb_peek(&sk->sk_error_queue)) != NULL) { + sk->sk_err = SKB_EXT_ERR(skb2)->ee.ee_errno; + spin_unlock_irq(&sk->sk_error_queue.lock); + sk->sk_error_report(sk); + } else + spin_unlock_irq(&sk->sk_error_queue.lock); out_free_skb: kfree_skb(skb); @@ -431,12 +430,13 @@ err = ip_options_get(&opt, optval, optlen, 1); if (err) break; - if (sk->type == SOCK_STREAM) { + if (sk->sk_type == SOCK_STREAM) { struct tcp_opt *tp = tcp_sk(sk); #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - if (sk->family == PF_INET || - (!((1<<sk->state)&(TCPF_LISTEN|TCPF_CLOSE)) - && inet->daddr != LOOPBACK4_IPV6)) { + if (sk->sk_family == PF_INET || + (!((1 << sk->sk_state) & + (TCPF_LISTEN | TCPF_CLOSE)) && + inet->daddr != LOOPBACK4_IPV6)) { #endif if (inet->opt) tp->ext_header_len -= inet->opt->optlen; @@ -483,7 +483,7 @@ inet->cmsg_flags &= ~IP_CMSG_RETOPTS; break; case IP_TOS: /* This sets both TOS and Precedence */ - if (sk->type == SOCK_STREAM) { + if (sk->sk_type == SOCK_STREAM) { val &= ~3; val |= inet->tos & 3; } @@ -494,7 +494,7 @@ } if (inet->tos != val) { inet->tos = val; - sk->priority = rt_tos2priority(val); + sk->sk_priority = rt_tos2priority(val); sk_dst_reset(sk); } break; @@ -506,7 +506,7 @@ inet->uc_ttl = val; break; case IP_HDRINCL: - if(sk->type!=SOCK_RAW) { + if (sk->sk_type != SOCK_RAW) { err = -ENOPROTOOPT; break; } @@ -520,10 +520,10 @@ case IP_RECVERR: inet->recverr = !!val; if (!val) - skb_queue_purge(&sk->error_queue); + skb_queue_purge(&sk->sk_error_queue); break; case IP_MULTICAST_TTL: - if (sk->type == SOCK_STREAM) + if (sk->sk_type == SOCK_STREAM) goto e_inval; if (optlen<1) goto e_inval; @@ -543,7 +543,7 @@ struct ip_mreqn mreq; struct net_device *dev = NULL; - if (sk->type == SOCK_STREAM) + if (sk->sk_type == SOCK_STREAM) goto e_inval; /* * Check the arguments are allowable @@ -581,7 +581,8 @@ break; err = -EINVAL; - if (sk->bound_dev_if && mreq.imr_ifindex != sk->bound_dev_if) + if (sk->sk_bound_dev_if && + mreq.imr_ifindex != sk->sk_bound_dev_if) break; inet->mc_index = mreq.imr_ifindex; @@ -998,7 +999,7 @@ release_sock(sk); - if (sk->type != SOCK_STREAM) + if (sk->sk_type != SOCK_STREAM) return -ENOPROTOOPT; msg.msg_control = optval; diff -Nru a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c --- a/net/ipv4/ipcomp.c Mon Jun 9 23:16:17 2003 +++ b/net/ipv4/ipcomp.c Mon Jun 9 23:16:17 2003 @@ -382,9 +382,9 @@ goto out; } -static struct xfrm_type ipcomp_type = -{ +static struct xfrm_type ipcomp_type = { .description = "IPCOMP4", + .owner = THIS_MODULE, .proto = IPPROTO_COMP, .init_state = ipcomp_init_state, .destructor = ipcomp_destroy, @@ -400,7 +400,6 @@ static int __init ipcomp4_init(void) { - ipcomp_type.owner = THIS_MODULE; if (xfrm_register_type(&ipcomp_type, AF_INET) < 0) { printk(KERN_INFO "ipcomp init: can't add xfrm type\n"); return -EAGAIN; diff -Nru a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c --- a/net/ipv4/ipmr.c Mon Jun 9 23:16:12 2003 +++ b/net/ipv4/ipmr.c Mon Jun 9 23:16:12 2003 @@ -860,7 +860,8 @@ switch(optname) { case MRT_INIT: - if(sk->type!=SOCK_RAW || inet_sk(sk)->num!=IPPROTO_IGMP) + if (sk->sk_type != SOCK_RAW || + inet_sk(sk)->num != IPPROTO_IGMP) return -EOPNOTSUPP; if(optlen!=sizeof(int)) return -ENOPROTOOPT; diff -Nru a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c --- a/net/ipv4/netfilter/ip_conntrack_core.c Mon Jun 9 23:16:05 2003 +++ b/net/ipv4/netfilter/ip_conntrack_core.c Mon Jun 9 23:16:05 2003 @@ -1288,7 +1288,7 @@ IPPROTO_TCP } }; /* We only do TCP at the moment: is there a better way? */ - if (strcmp(sk->prot->name, "TCP") != 0) { + if (strcmp(sk->sk_prot->name, "TCP")) { DEBUGP("SO_ORIGINAL_DST: Not a TCP socket\n"); return -ENOPROTOOPT; } diff -Nru a/net/ipv4/netfilter/ip_queue.c b/net/ipv4/netfilter/ip_queue.c --- a/net/ipv4/netfilter/ip_queue.c Mon Jun 9 23:16:20 2003 +++ b/net/ipv4/netfilter/ip_queue.c Mon Jun 9 23:16:20 2003 @@ -535,14 +535,14 @@ if (down_trylock(&ipqnl_sem)) return; - while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) { + while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { ipq_rcv_skb(skb); kfree_skb(skb); } up(&ipqnl_sem); - } while (ipqnl && ipqnl->receive_queue.qlen); + } while (ipqnl && ipqnl->sk_receive_queue.qlen); } static int @@ -691,7 +691,7 @@ proc_net_remove(IPQ_PROC_FS_NAME); cleanup_ipqnl: - sock_release(ipqnl->socket); + sock_release(ipqnl->sk_socket); down(&ipqnl_sem); up(&ipqnl_sem); diff -Nru a/net/ipv4/netfilter/ipchains_core.c b/net/ipv4/netfilter/ipchains_core.c --- a/net/ipv4/netfilter/ipchains_core.c Mon Jun 9 23:16:17 2003 +++ b/net/ipv4/netfilter/ipchains_core.c Mon Jun 9 23:16:17 2003 @@ -1836,7 +1836,7 @@ cleanup_netlink: #if defined(CONFIG_NETLINK_DEV) || defined(CONFIG_NETLINK_DEV_MODULE) - sock_release(ipfwsk->socket); + sock_release(ipfwsk->sk_socket); cleanup_nothing: #endif diff -Nru a/net/ipv4/netfilter/ipfwadm_core.c b/net/ipv4/netfilter/ipfwadm_core.c --- a/net/ipv4/netfilter/ipfwadm_core.c Mon Jun 9 23:16:10 2003 +++ b/net/ipv4/netfilter/ipfwadm_core.c Mon Jun 9 23:16:10 2003 @@ -1435,7 +1435,7 @@ cleanup: #ifdef CONFIG_IP_FIREWALL_NETLINK - sock_release(ipfwsk->socket); + sock_release(ipfwsk->sk_socket); #endif unregister_netdevice_notifier(&ipfw_dev_notifier); diff -Nru a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c --- a/net/ipv4/netfilter/ipt_ULOG.c Mon Jun 9 23:16:09 2003 +++ b/net/ipv4/netfilter/ipt_ULOG.c Mon Jun 9 23:16:09 2003 @@ -336,7 +336,7 @@ return -ENOMEM; if (ipt_register_target(&ipt_ulog_reg) != 0) { - sock_release(nflognl->socket); + sock_release(nflognl->sk_socket); return -EINVAL; } @@ -351,7 +351,7 @@ DEBUGP("ipt_ULOG: cleanup_module\n"); ipt_unregister_target(&ipt_ulog_reg); - sock_release(nflognl->socket); + sock_release(nflognl->sk_socket); /* remove pending timers and free allocated skb's */ for (i = 0; i < ULOG_MAXNLGROUPS; i++) { diff -Nru a/net/ipv4/netfilter/ipt_owner.c b/net/ipv4/netfilter/ipt_owner.c --- a/net/ipv4/netfilter/ipt_owner.c Mon Jun 9 23:16:18 2003 +++ b/net/ipv4/netfilter/ipt_owner.c Mon Jun 9 23:16:18 2003 @@ -28,7 +28,8 @@ if(files) { spin_lock(&files->file_lock); for (i=0; i < files->max_fds; i++) { - if (fcheck_files(files, i) == skb->sk->socket->file) { + if (fcheck_files(files, i) == + skb->sk->sk_socket->file) { spin_unlock(&files->file_lock); task_unlock(p); read_unlock(&tasklist_lock); @@ -59,7 +60,8 @@ if(files) { spin_lock(&files->file_lock); for (i=0; i < files->max_fds; i++) { - if (fcheck_files(files, i) == skb->sk->socket->file) { + if (fcheck_files(files, i) == + skb->sk->sk_socket->file) { spin_unlock(&files->file_lock); task_unlock(p); read_unlock(&tasklist_lock); @@ -78,7 +80,7 @@ match_sid(const struct sk_buff *skb, pid_t sid) { struct task_struct *g, *p; - struct file *file = skb->sk->socket->file; + struct file *file = skb->sk->sk_socket->file; int i, found=0; read_lock(&tasklist_lock); @@ -119,17 +121,17 @@ { const struct ipt_owner_info *info = matchinfo; - if (!skb->sk || !skb->sk->socket || !skb->sk->socket->file) + if (!skb->sk || !skb->sk->sk_socket || !skb->sk->sk_socket->file) return 0; if(info->match & IPT_OWNER_UID) { - if((skb->sk->socket->file->f_uid != info->uid) ^ + if ((skb->sk->sk_socket->file->f_uid != info->uid) ^ !!(info->invert & IPT_OWNER_UID)) return 0; } if(info->match & IPT_OWNER_GID) { - if((skb->sk->socket->file->f_gid != info->gid) ^ + if ((skb->sk->sk_socket->file->f_gid != info->gid) ^ !!(info->invert & IPT_OWNER_GID)) return 0; } diff -Nru a/net/ipv4/raw.c b/net/ipv4/raw.c --- a/net/ipv4/raw.c Mon Jun 9 23:16:13 2003 +++ b/net/ipv4/raw.c Mon Jun 9 23:16:13 2003 @@ -89,11 +89,11 @@ (RAWV4_HTABLE_SIZE - 1)]; write_lock_bh(&raw_v4_lock); - if ((sk->next = *skp) != NULL) - (*skp)->pprev = &sk->next; + if ((sk->sk_next = *skp) != NULL) + (*skp)->sk_pprev = &sk->sk_next; *skp = sk; - sk->pprev = skp; - sock_prot_inc_use(sk->prot); + sk->sk_pprev = skp; + sock_prot_inc_use(sk->sk_prot); sock_hold(sk); write_unlock_bh(&raw_v4_lock); } @@ -101,12 +101,12 @@ static void raw_v4_unhash(struct sock *sk) { write_lock_bh(&raw_v4_lock); - if (sk->pprev) { - if (sk->next) - sk->next->pprev = sk->pprev; - *sk->pprev = sk->next; - sk->pprev = NULL; - sock_prot_dec_use(sk->prot); + if (sk->sk_pprev) { + if (sk->sk_next) + sk->sk_next->sk_pprev = sk->sk_pprev; + *sk->sk_pprev = sk->sk_next; + sk->sk_pprev = NULL; + sock_prot_dec_use(sk->sk_prot); __sock_put(sk); } write_unlock_bh(&raw_v4_lock); @@ -118,13 +118,13 @@ { struct sock *s = sk; - for (s = sk; s; s = s->next) { + for (; s; s = s->sk_next) { struct inet_opt *inet = inet_sk(s); if (inet->num == num && !(inet->daddr && inet->daddr != raddr) && !(inet->rcv_saddr && inet->rcv_saddr != laddr) && - !(s->bound_dev_if && s->bound_dev_if != dif)) + !(s->sk_bound_dev_if && s->sk_bound_dev_if != dif)) break; /* gotcha */ } return s; @@ -174,7 +174,7 @@ if (clone) raw_rcv(sk, clone); } - sk = __raw_v4_lookup(sk->next, iph->protocol, + sk = __raw_v4_lookup(sk->sk_next, iph->protocol, iph->saddr, iph->daddr, skb->dev->ifindex); } @@ -195,7 +195,7 @@ 2. Socket is connected (otherwise the error indication is useless without ip_recverr and error is hard. */ - if (!inet->recverr && sk->state != TCP_ESTABLISHED) + if (!inet->recverr && sk->sk_state != TCP_ESTABLISHED) return; switch (type) { @@ -231,8 +231,8 @@ } if (inet->recverr || harderr) { - sk->err = err; - sk->error_report(sk); + sk->sk_err = err; + sk->sk_error_report(sk); } } @@ -288,7 +288,7 @@ goto error; skb_reserve(skb, hh_len); - skb->priority = sk->priority; + skb->priority = sk->sk_priority; skb->dst = dst_clone(&rt->u.dst); skb->nh.iph = iph = (struct iphdr *)skb_put(skb, length); @@ -390,14 +390,14 @@ */ } else { err = -EINVAL; - if (sk->state != TCP_ESTABLISHED) + if (sk->sk_state != TCP_ESTABLISHED) goto out; daddr = inet->daddr; } ipc.addr = inet->saddr; ipc.opt = NULL; - ipc.oif = sk->bound_dev_if; + ipc.oif = sk->sk_bound_dev_if; if (msg->msg_controllen) { err = ip_cmsg_send(msg, &ipc); @@ -426,7 +426,7 @@ daddr = ipc.opt->faddr; } } - tos = RT_TOS(inet->tos) | sk->localroute; + tos = RT_TOS(inet->tos) | sk->sk_localroute; if (msg->msg_flags & MSG_DONTROUTE) tos |= RTO_ONLINK; @@ -443,15 +443,16 @@ { .daddr = daddr, .saddr = saddr, .tos = tos } }, - .proto = inet->hdrincl ? IPPROTO_RAW : sk->protocol }; + .proto = inet->hdrincl ? IPPROTO_RAW : + sk->sk_protocol, + }; err = ip_route_output_flow(&rt, &fl, sk, !(msg->msg_flags&MSG_DONTWAIT)); } if (err) goto done; err = -EACCES; - if (rt->rt_flags & RTCF_BROADCAST && - !test_bit(SOCK_BROADCAST, &sk->flags)) + if (rt->rt_flags & RTCF_BROADCAST && !sock_flag(sk, SOCK_BROADCAST)) goto done; if (msg->msg_flags & MSG_CONFIRM) @@ -507,7 +508,7 @@ int ret = -EINVAL; int chk_addr_ret; - if (sk->state != TCP_CLOSE || addr_len < sizeof(struct sockaddr_in)) + if (sk->sk_state != TCP_CLOSE || addr_len < sizeof(struct sockaddr_in)) goto out; chk_addr_ret = inet_addr_type(addr->sin_addr.s_addr); ret = -EADDRNOTAVAIL; @@ -646,18 +647,18 @@ { switch (cmd) { case SIOCOUTQ: { - int amount = atomic_read(&sk->wmem_alloc); + int amount = atomic_read(&sk->sk_wmem_alloc); return put_user(amount, (int *)arg); } case SIOCINQ: { struct sk_buff *skb; int amount = 0; - spin_lock_irq(&sk->receive_queue.lock); - skb = skb_peek(&sk->receive_queue); + spin_lock_irq(&sk->sk_receive_queue.lock); + skb = skb_peek(&sk->sk_receive_queue); if (skb != NULL) amount = skb->len; - spin_unlock_irq(&sk->receive_queue.lock); + spin_unlock_irq(&sk->sk_receive_queue.lock); return put_user(amount, (int *)arg); } @@ -701,8 +702,8 @@ for (state->bucket = 0; state->bucket < RAWV4_HTABLE_SIZE; ++state->bucket) { sk = raw_v4_htable[state->bucket]; - while (sk && sk->family != PF_INET) - sk = sk->next; + while (sk && sk->sk_family != PF_INET) + sk = sk->sk_next; if (sk) break; } @@ -714,10 +715,10 @@ struct raw_iter_state* state = raw_seq_private(seq); do { - sk = sk->next; + sk = sk->sk_next; try_again: ; - } while (sk && sk->family != PF_INET); + } while (sk && sk->sk_family != PF_INET); if (!sk && ++state->bucket < RAWV4_HTABLE_SIZE) { sk = raw_v4_htable[state->bucket]; @@ -769,10 +770,11 @@ sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X" " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p", - i, src, srcp, dest, destp, sp->state, - atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc), + i, src, srcp, dest, destp, sp->sk_state, + atomic_read(&sp->sk_wmem_alloc), + atomic_read(&sp->sk_rmem_alloc), 0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp), - atomic_read(&sp->refcnt), sp); + atomic_read(&sp->sk_refcnt), sp); return tmpbuf; } diff -Nru a/net/ipv4/route.c b/net/ipv4/route.c --- a/net/ipv4/route.c Mon Jun 9 23:16:19 2003 +++ b/net/ipv4/route.c Mon Jun 9 23:16:19 2003 @@ -2694,16 +2694,9 @@ ipv4_dst_ops.gc_thresh = (rt_hash_mask + 1); ip_rt_max_size = (rt_hash_mask + 1) * 16; - rt_cache_stat = kmalloc_percpu(sizeof (struct rt_cache_stat), - GFP_KERNEL); + rt_cache_stat = alloc_percpu(struct rt_cache_stat); if (!rt_cache_stat) goto out_enomem1; - for (i = 0; i < NR_CPUS; i++) { - if (cpu_possible(i)) { - memset(per_cpu_ptr(rt_cache_stat, i), 0, - sizeof (struct rt_cache_stat)); - } - } devinet_init(); ip_fib_init(); @@ -2739,7 +2732,7 @@ out: return rc; out_enomem: - kfree_percpu(rt_cache_stat); + free_percpu(rt_cache_stat); out_enomem1: rc = -ENOMEM; goto out; diff -Nru a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c --- a/net/ipv4/syncookies.c Mon Jun 9 23:16:05 2003 +++ b/net/ipv4/syncookies.c Mon Jun 9 23:16:05 2003 @@ -103,7 +103,7 @@ child = tp->af_specific->syn_recv_sock(sk, skb, req, dst); if (child) { - sk_set_owner(child, sk->owner); + sk_set_owner(child, sk->sk_owner); tcp_acceptq_queue(sk, req, child); } else tcp_openreq_free(req); diff -Nru a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c --- a/net/ipv4/sysctl_net_ipv4.c Mon Jun 9 23:16:16 2003 +++ b/net/ipv4/sysctl_net_ipv4.c Mon Jun 9 23:16:16 2003 @@ -27,6 +27,7 @@ extern int sysctl_ipfrag_low_thresh; extern int sysctl_ipfrag_high_thresh; extern int sysctl_ipfrag_time; +extern int sysctl_ipfrag_secret_interval; /* From ip_output.c */ extern int sysctl_ip_dynaddr; @@ -571,6 +572,15 @@ .maxlen = sizeof(int), .mode = 0644, .proc_handler = &proc_dointvec + }, + { + .ctl_name = NET_IPV4_IPFRAG_SECRET_INTERVAL, + .procname = "ipfrag_secret_interval", + .data = &sysctl_ipfrag_secret_interval, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_jiffies, + .strategy = &sysctl_jiffies }, { .ctl_name = 0 } }; diff -Nru a/net/ipv4/tcp.c b/net/ipv4/tcp.c --- a/net/ipv4/tcp.c Mon Jun 9 23:16:09 2003 +++ b/net/ipv4/tcp.c Mon Jun 9 23:16:09 2003 @@ -294,7 +294,7 @@ { int amt = TCP_PAGES(size); - sk->forward_alloc += amt * TCP_MEM_QUANTUM; + sk->sk_forward_alloc += amt * TCP_MEM_QUANTUM; atomic_add(amt, &tcp_memory_allocated); /* Under limit. */ @@ -315,18 +315,16 @@ tcp_enter_memory_pressure(); if (kind) { - if (atomic_read(&sk->rmem_alloc) < sysctl_tcp_rmem[0]) + if (atomic_read(&sk->sk_rmem_alloc) < sysctl_tcp_rmem[0]) return 1; - } else { - if (sk->wmem_queued < sysctl_tcp_wmem[0]) - return 1; - } + } else if (sk->sk_wmem_queued < sysctl_tcp_wmem[0]) + return 1; if (!tcp_memory_pressure || sysctl_tcp_mem[2] > atomic_read(&tcp_sockets_allocated) * - TCP_PAGES(sk->wmem_queued + - atomic_read(&sk->rmem_alloc) + - sk->forward_alloc)) + TCP_PAGES(sk->sk_wmem_queued + + atomic_read(&sk->sk_rmem_alloc) + + sk->sk_forward_alloc)) return 1; suppress_allocation: @@ -337,22 +335,22 @@ /* Fail only if socket is _under_ its sndbuf. * In this case we cannot block, so that we have to fail. */ - if (sk->wmem_queued + size >= sk->sndbuf) + if (sk->sk_wmem_queued + size >= sk->sk_sndbuf) return 1; } /* Alas. Undo changes. */ - sk->forward_alloc -= amt * TCP_MEM_QUANTUM; + sk->sk_forward_alloc -= amt * TCP_MEM_QUANTUM; atomic_sub(amt, &tcp_memory_allocated); return 0; } void __tcp_mem_reclaim(struct sock *sk) { - if (sk->forward_alloc >= TCP_MEM_QUANTUM) { - atomic_sub(sk->forward_alloc / TCP_MEM_QUANTUM, + if (sk->sk_forward_alloc >= TCP_MEM_QUANTUM) { + atomic_sub(sk->sk_forward_alloc / TCP_MEM_QUANTUM, &tcp_memory_allocated); - sk->forward_alloc &= TCP_MEM_QUANTUM - 1; + sk->sk_forward_alloc &= TCP_MEM_QUANTUM - 1; if (tcp_memory_pressure && atomic_read(&tcp_memory_allocated) < sysctl_tcp_mem[0]) tcp_memory_pressure = 0; @@ -363,8 +361,8 @@ { struct sock *sk = skb->sk; - atomic_sub(skb->truesize, &sk->rmem_alloc); - sk->forward_alloc += skb->truesize; + atomic_sub(skb->truesize, &sk->sk_rmem_alloc); + sk->sk_forward_alloc += skb->truesize; } /* @@ -389,8 +387,8 @@ struct sock *sk = sock->sk; struct tcp_opt *tp = tcp_sk(sk); - poll_wait(file, sk->sleep, wait); - if (sk->state == TCP_LISTEN) + poll_wait(file, sk->sk_sleep, wait); + if (sk->sk_state == TCP_LISTEN) return tcp_listen_poll(sk, wait); /* Socket is not locked. We are protected from async events @@ -399,7 +397,7 @@ */ mask = 0; - if (sk->err) + if (sk->sk_err) mask = POLLERR; /* @@ -429,28 +427,29 @@ * NOTE. Check for TCP_CLOSE is added. The goal is to prevent * blocking on fresh not-connected or disconnected socket. --ANK */ - if (sk->shutdown == SHUTDOWN_MASK || sk->state == TCP_CLOSE) + if (sk->sk_shutdown == SHUTDOWN_MASK || sk->sk_state == TCP_CLOSE) mask |= POLLHUP; - if (sk->shutdown & RCV_SHUTDOWN) + if (sk->sk_shutdown & RCV_SHUTDOWN) mask |= POLLIN | POLLRDNORM; /* Connected? */ - if ((1 << sk->state) & ~(TCPF_SYN_SENT | TCPF_SYN_RECV)) { + if ((1 << sk->sk_state) & ~(TCPF_SYN_SENT | TCPF_SYN_RECV)) { /* Potential race condition. If read of tp below will - * escape above sk->state, we can be illegally awaken + * escape above sk->sk_state, we can be illegally awaken * in SYN_* states. */ if ((tp->rcv_nxt != tp->copied_seq) && (tp->urg_seq != tp->copied_seq || tp->rcv_nxt != tp->copied_seq + 1 || - test_bit(SOCK_URGINLINE, &sk->flags) || !tp->urg_data)) + sock_flag(sk, SOCK_URGINLINE) || !tp->urg_data)) mask |= POLLIN | POLLRDNORM; - if (!(sk->shutdown & SEND_SHUTDOWN)) { + if (!(sk->sk_shutdown & SEND_SHUTDOWN)) { if (tcp_wspace(sk) >= tcp_min_write_space(sk)) { mask |= POLLOUT | POLLWRNORM; } else { /* send SIGIO later */ - set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); - set_bit(SOCK_NOSPACE, &sk->socket->flags); + set_bit(SOCK_ASYNC_NOSPACE, + &sk->sk_socket->flags); + set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); /* Race breaker. If space is freed after * wspace test but before the flags are set, @@ -472,15 +471,15 @@ */ void tcp_write_space(struct sock *sk) { - struct socket *sock = sk->socket; + struct socket *sock = sk->sk_socket; if (tcp_wspace(sk) >= tcp_min_write_space(sk) && sock) { clear_bit(SOCK_NOSPACE, &sock->flags); - if (sk->sleep && waitqueue_active(sk->sleep)) - wake_up_interruptible(sk->sleep); + if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) + wake_up_interruptible(sk->sk_sleep); - if (sock->fasync_list && !(sk->shutdown & SEND_SHUTDOWN)) + if (sock->fasync_list && !(sk->sk_shutdown & SEND_SHUTDOWN)) sock_wake_async(sock, 2, POLL_OUT); } } @@ -492,22 +491,22 @@ switch (cmd) { case SIOCINQ: - if (sk->state == TCP_LISTEN) + if (sk->sk_state == TCP_LISTEN) return -EINVAL; lock_sock(sk); - if ((1 << sk->state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) + if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) answ = 0; - else if (test_bit(SOCK_URGINLINE, &sk->flags) || + else if (sock_flag(sk, SOCK_URGINLINE) || !tp->urg_data || before(tp->urg_seq, tp->copied_seq) || !before(tp->urg_seq, tp->rcv_nxt)) { answ = tp->rcv_nxt - tp->copied_seq; /* Subtract 1, if FIN is in queue. */ - if (answ && !skb_queue_empty(&sk->receive_queue)) + if (answ && !skb_queue_empty(&sk->sk_receive_queue)) answ -= - ((struct sk_buff*)sk->receive_queue.prev)->h.th->fin; + ((struct sk_buff *)sk->sk_receive_queue.prev)->h.th->fin; } else answ = tp->urg_seq - tp->copied_seq; release_sock(sk); @@ -516,10 +515,10 @@ answ = tp->urg_data && tp->urg_seq == tp->copied_seq; break; case SIOCOUTQ: - if (sk->state == TCP_LISTEN) + if (sk->sk_state == TCP_LISTEN) return -EINVAL; - if ((1 << sk->state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) + if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) answ = 0; else answ = tp->write_seq - tp->snd_una; @@ -538,8 +537,8 @@ struct tcp_opt *tp = tcp_sk(sk); struct tcp_listen_opt *lopt; - sk->max_ack_backlog = 0; - sk->ack_backlog = 0; + sk->sk_max_ack_backlog = 0; + sk->sk_ack_backlog = 0; tp->accept_queue = tp->accept_queue_tail = NULL; tp->syn_wait_lock = RW_LOCK_UNLOCKED; tcp_delack_init(tp); @@ -563,17 +562,17 @@ * It is OK, because this socket enters to hash table only * after validation is complete. */ - sk->state = TCP_LISTEN; - if (!sk->prot->get_port(sk, inet->num)) { + sk->sk_state = TCP_LISTEN; + if (!sk->sk_prot->get_port(sk, inet->num)) { inet->sport = htons(inet->num); sk_dst_reset(sk); - sk->prot->hash(sk); + sk->sk_prot->hash(sk); return 0; } - sk->state = TCP_CLOSE; + sk->sk_state = TCP_CLOSE; write_lock_bh(&tp->syn_wait_lock); tp->listen_opt = NULL; write_unlock_bh(&tp->syn_wait_lock); @@ -649,7 +648,7 @@ tcp_acceptq_removed(sk); tcp_openreq_fastfree(req); } - BUG_TRAP(!sk->ack_backlog); + BUG_TRAP(!sk->sk_ack_backlog); } /* @@ -663,24 +662,24 @@ struct task_struct *tsk = current; DEFINE_WAIT(wait); - while ((1 << sk->state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) { - if (sk->err) + while ((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) { + if (sk->sk_err) return sock_error(sk); - if ((1 << sk->state) & ~(TCPF_SYN_SENT | TCPF_SYN_RECV)) + if ((1 << sk->sk_state) & ~(TCPF_SYN_SENT | TCPF_SYN_RECV)) return -EPIPE; if (!*timeo_p) return -EAGAIN; if (signal_pending(tsk)) return sock_intr_errno(*timeo_p); - prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE); + prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); tp->write_pending++; release_sock(sk); *timeo_p = schedule_timeout(*timeo_p); lock_sock(sk); - finish_wait(sk->sleep, &wait); + finish_wait(sk->sk_sleep, &wait); tp->write_pending--; } return 0; @@ -688,7 +687,7 @@ static inline int tcp_memory_free(struct sock *sk) { - return sk->wmem_queued < sk->sndbuf; + return sk->sk_wmem_queued < sk->sk_sndbuf; } /* @@ -706,21 +705,21 @@ current_timeo = vm_wait = (net_random() % (HZ / 5)) + 2; for (;;) { - set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); + set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); - prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE); + prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); - if (sk->err || (sk->shutdown & SEND_SHUTDOWN)) + if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN)) goto do_error; if (!*timeo) goto do_nonblock; if (signal_pending(current)) goto do_interrupted; - clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); + clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); if (tcp_memory_free(sk) && !vm_wait) break; - set_bit(SOCK_NOSPACE, &sk->socket->flags); + set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); tp->write_pending++; release_sock(sk); if (!tcp_memory_free(sk) || vm_wait) @@ -739,7 +738,7 @@ *timeo = current_timeo; } out: - finish_wait(sk->sleep, &wait); + finish_wait(sk->sk_sleep, &wait); return err; do_error: @@ -796,10 +795,12 @@ TCP_SKB_CB(skb)->end_seq = tp->write_seq; TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK; TCP_SKB_CB(skb)->sacked = 0; - __skb_queue_tail(&sk->write_queue, skb); + __skb_queue_tail(&sk->sk_write_queue, skb); tcp_charge_skb(sk, skb); if (!tp->send_head) tp->send_head = skb; + else if (tp->nonagle&TCP_NAGLE_PUSH) + tp->nonagle &= ~TCP_NAGLE_PUSH; } static inline void tcp_mark_urg(struct tcp_opt *tp, int flags, @@ -816,12 +817,12 @@ int mss_now, int nonagle) { if (tp->send_head) { - struct sk_buff *skb = sk->write_queue.prev; + struct sk_buff *skb = sk->sk_write_queue.prev; if (!(flags & MSG_MORE) || forced_push(tp)) tcp_mark_push(tp, skb); tcp_mark_urg(tp, flags, skb); __tcp_push_pending_frames(sk, tp, mss_now, - (flags & MSG_MORE) ? 2 : nonagle); + (flags & MSG_MORE) ? TCP_NAGLE_CORK : nonagle); } } @@ -844,21 +845,21 @@ long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); /* Wait for a connection to finish. */ - if ((1 << sk->state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) + if ((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) if ((err = wait_for_tcp_connect(sk, 0, &timeo)) != 0) goto out_err; - clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); + clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); mss_now = tcp_current_mss(sk, !(flags&MSG_OOB)); copied = 0; err = -EPIPE; - if (sk->err || (sk->shutdown & SEND_SHUTDOWN)) + if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN)) goto do_error; while (psize > 0) { - struct sk_buff *skb = sk->write_queue.prev; + struct sk_buff *skb = sk->sk_write_queue.prev; struct page *page = pages[poffset / PAGE_SIZE]; int copy, i; int offset = poffset % PAGE_SIZE; @@ -870,7 +871,7 @@ goto wait_for_sndbuf; skb = tcp_alloc_pskb(sk, 0, tp->mss_cache, - sk->allocation); + sk->sk_allocation); if (!skb) goto wait_for_memory; @@ -911,16 +912,16 @@ if (forced_push(tp)) { tcp_mark_push(tp, skb); - __tcp_push_pending_frames(sk, tp, mss_now, 1); + __tcp_push_pending_frames(sk, tp, mss_now, TCP_NAGLE_PUSH); } else if (skb == tp->send_head) tcp_push_one(sk, mss_now); continue; wait_for_sndbuf: - set_bit(SOCK_NOSPACE, &sk->socket->flags); + set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); wait_for_memory: if (copied) - tcp_push(sk, tp, flags & ~MSG_MORE, mss_now, 1); + tcp_push(sk, tp, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH); if ((err = wait_for_tcp_memory(sk, &timeo)) != 0) goto do_error; @@ -948,8 +949,8 @@ #define TCP_ZC_CSUM_FLAGS (NETIF_F_IP_CSUM | NETIF_F_NO_CSUM | NETIF_F_HW_CSUM) - if (!(sk->route_caps & NETIF_F_SG) || - !(sk->route_caps & TCP_ZC_CSUM_FLAGS)) + if (!(sk->sk_route_caps & NETIF_F_SG) || + !(sk->sk_route_caps & TCP_ZC_CSUM_FLAGS)) return sock_no_sendpage(sock, page, offset, size, flags); #undef TCP_ZC_CSUM_FLAGS @@ -985,8 +986,8 @@ skb->len += copy; skb->data_len += copy; skb->truesize += copy; - sk->wmem_queued += copy; - sk->forward_alloc -= copy; + sk->sk_wmem_queued += copy; + sk->sk_forward_alloc -= copy; return 0; } @@ -1016,7 +1017,7 @@ { int tmp = tp->mss_cache_std; - if (sk->route_caps & NETIF_F_SG) { + if (sk->sk_route_caps & NETIF_F_SG) { int pgbreak = SKB_MAX_HEAD(MAX_TCP_HEADER); if (tmp >= pgbreak && @@ -1044,12 +1045,12 @@ timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT); /* Wait for a connection to finish. */ - if ((1 << sk->state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) + if ((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) if ((err = wait_for_tcp_connect(sk, flags, &timeo)) != 0) goto out_err; /* This should be in poll */ - clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); + clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); mss_now = tcp_current_mss(sk, !(flags&MSG_OOB)); @@ -1059,7 +1060,7 @@ copied = 0; err = -EPIPE; - if (sk->err || (sk->shutdown & SEND_SHUTDOWN)) + if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN)) goto do_error; while (--iovlen >= 0) { @@ -1071,7 +1072,7 @@ while (seglen > 0) { int copy; - skb = sk->write_queue.prev; + skb = sk->sk_write_queue.prev; if (!tp->send_head || (copy = mss_now - skb->len) <= 0) { @@ -1084,14 +1085,16 @@ goto wait_for_sndbuf; skb = tcp_alloc_pskb(sk, select_size(sk, tp), - 0, sk->allocation); + 0, sk->sk_allocation); if (!skb) goto wait_for_memory; /* * Check whether we can use HW checksum. */ - if (sk->route_caps & (NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM)) + if (sk->sk_route_caps & + (NETIF_F_IP_CSUM | NETIF_F_NO_CSUM | + NETIF_F_HW_CSUM)) skb->ip_summed = CHECKSUM_HW; skb_entail(sk, tp, skb); @@ -1122,7 +1125,7 @@ merge = 1; } else if (i == MAX_SKB_FRAGS || (!i && - !(sk->route_caps & NETIF_F_SG))) { + !(sk->sk_route_caps & NETIF_F_SG))) { /* Need to add new fragment and cannot * do this because interface is non-SG, * or because all the page slots are @@ -1199,16 +1202,16 @@ if (forced_push(tp)) { tcp_mark_push(tp, skb); - __tcp_push_pending_frames(sk, tp, mss_now, 1); + __tcp_push_pending_frames(sk, tp, mss_now, TCP_NAGLE_PUSH); } else if (skb == tp->send_head) tcp_push_one(sk, mss_now); continue; wait_for_sndbuf: - set_bit(SOCK_NOSPACE, &sk->socket->flags); + set_bit(SOCK_NOSPACE, &sk->sk_socket->flags); wait_for_memory: if (copied) - tcp_push(sk, tp, flags & ~MSG_MORE, mss_now, 1); + tcp_push(sk, tp, flags & ~MSG_MORE, mss_now, TCP_NAGLE_PUSH); if ((err = wait_for_tcp_memory(sk, &timeo)) != 0) goto do_error; @@ -1254,11 +1257,11 @@ struct tcp_opt *tp = tcp_sk(sk); /* No URG data to read. */ - if (test_bit(SOCK_URGINLINE, &sk->flags) || !tp->urg_data || - tp->urg_data == TCP_URG_READ) + if (sock_flag(sk, SOCK_URGINLINE) || !tp->urg_data || + tp->urg_data == TCP_URG_READ) return -EINVAL; /* Yes this is right ! */ - if (sk->state == TCP_CLOSE && !test_bit(SOCK_DONE, &sk->flags)) + if (sk->sk_state == TCP_CLOSE && !sock_flag(sk, SOCK_DONE)) return -ENOTCONN; if (tp->urg_data & TCP_URG_VALID) { @@ -1281,7 +1284,7 @@ return err ? -EFAULT : len; } - if (sk->state == TCP_CLOSE || (sk->shutdown & RCV_SHUTDOWN)) + if (sk->sk_state == TCP_CLOSE || (sk->sk_shutdown & RCV_SHUTDOWN)) return 0; /* Fixed the recv(..., MSG_OOB) behaviour. BSD docs and @@ -1301,7 +1304,7 @@ static inline void tcp_eat_skb(struct sock *sk, struct sk_buff *skb) { - __skb_unlink(skb, &sk->receive_queue); + __skb_unlink(skb, &sk->sk_receive_queue); __kfree_skb(skb); } @@ -1317,7 +1320,7 @@ int time_to_ack = 0; #if TCP_DEBUG - struct sk_buff *skb = skb_peek(&sk->receive_queue); + struct sk_buff *skb = skb_peek(&sk->sk_receive_queue); BUG_TRAP(!skb || before(tp->copied_seq, TCP_SKB_CB(skb)->end_seq)); #endif @@ -1335,7 +1338,7 @@ * in queue. */ (copied > 0 && (tp->ack.pending & TCP_ACK_PUSHED) && - !tp->ack.pingpong && !atomic_read(&sk->rmem_alloc))) + !tp->ack.pingpong && !atomic_read(&sk->sk_rmem_alloc))) time_to_ack = 1; } @@ -1345,7 +1348,7 @@ * Even if window raised up to infinity, do not send window open ACK * in states, where we will not receive more. It is useless. */ - if (copied > 0 && !time_to_ack && !(sk->shutdown & RCV_SHUTDOWN)) { + if (copied > 0 && !time_to_ack && !(sk->sk_shutdown & RCV_SHUTDOWN)) { __u32 rcv_window_now = tcp_receive_window(tp); /* Optimize, __tcp_select_window() is not cheap. */ @@ -1365,7 +1368,7 @@ tcp_send_ack(sk); } -/* Now socket state including sk->err is changed only under lock, +/* Now socket state including sk->sk_err is changed only under lock, * hence we may omit checks after joining wait queue. * We check receive queue before schedule() only as optimization; * it is very likely that release_sock() added new data. @@ -1375,18 +1378,18 @@ { DEFINE_WAIT(wait); - prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE); + prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); - set_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags); + set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); release_sock(sk); - if (skb_queue_empty(&sk->receive_queue)) + if (skb_queue_empty(&sk->sk_receive_queue)) timeo = schedule_timeout(timeo); lock_sock(sk); - clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags); + clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); - finish_wait(sk->sleep, &wait); + finish_wait(sk->sk_sleep, &wait); return timeo; } @@ -1401,7 +1404,7 @@ * necessary */ local_bh_disable(); while ((skb = __skb_dequeue(&tp->ucopy.prequeue)) != NULL) - sk->backlog_rcv(sk, skb); + sk->sk_backlog_rcv(sk, skb); local_bh_enable(); /* Clear memory counter. */ @@ -1413,7 +1416,7 @@ struct sk_buff *skb; u32 offset; - skb_queue_walk(&sk->receive_queue, skb) { + skb_queue_walk(&sk->sk_receive_queue, skb) { offset = seq - TCP_SKB_CB(skb)->seq; if (skb->h.th->syn) offset--; @@ -1445,7 +1448,7 @@ u32 offset; int copied = 0; - if (sk->state == TCP_LISTEN) + if (sk->sk_state == TCP_LISTEN) return -ENOTCONN; while ((skb = tcp_recv_skb(sk, seq, &offset)) != NULL) { if (offset < skb->len) { @@ -1511,7 +1514,7 @@ TCP_CHECK_TIMER(sk); err = -ENOTCONN; - if (sk->state == TCP_LISTEN) + if (sk->sk_state == TCP_LISTEN) goto out; timeo = sock_rcvtimeo(sk, nonblock); @@ -1549,7 +1552,7 @@ /* Next get a buffer. */ - skb = skb_peek(&sk->receive_queue); + skb = skb_peek(&sk->sk_receive_queue); do { if (!skb) break; @@ -1571,34 +1574,34 @@ goto found_fin_ok; BUG_TRAP(flags & MSG_PEEK); skb = skb->next; - } while (skb != (struct sk_buff *)&sk->receive_queue); + } while (skb != (struct sk_buff *)&sk->sk_receive_queue); /* Well, if we have backlog, try to process it now yet. */ - if (copied >= target && !sk->backlog.tail) + if (copied >= target && !sk->sk_backlog.tail) break; if (copied) { - if (sk->err || - sk->state == TCP_CLOSE || - (sk->shutdown & RCV_SHUTDOWN) || + if (sk->sk_err || + sk->sk_state == TCP_CLOSE || + (sk->sk_shutdown & RCV_SHUTDOWN) || !timeo || (flags & MSG_PEEK)) break; } else { - if (test_bit(SOCK_DONE, &sk->flags)) + if (sock_flag(sk, SOCK_DONE)) break; - if (sk->err) { + if (sk->sk_err) { copied = sock_error(sk); break; } - if (sk->shutdown & RCV_SHUTDOWN) + if (sk->sk_shutdown & RCV_SHUTDOWN) break; - if (sk->state == TCP_CLOSE) { - if (!test_bit(SOCK_DONE, &sk->flags)) { + if (sk->sk_state == TCP_CLOSE) { + if (!sock_flag(sk, SOCK_DONE)) { /* This occurs when user tries to read * from never connected socket. */ @@ -1711,8 +1714,7 @@ u32 urg_offset = tp->urg_seq - *seq; if (urg_offset < used) { if (!urg_offset) { - if (!test_bit(SOCK_URGINLINE, - &sk->flags)) { + if (!sock_flag(sk, SOCK_URGINLINE)) { ++*seq; offset++; used--; @@ -1826,7 +1828,7 @@ static int tcp_close_state(struct sock *sk) { - int next = (int)new_state[sk->state]; + int next = (int)new_state[sk->sk_state]; int ns = next & TCP_STATE_MASK; tcp_set_state(sk, ns); @@ -1836,7 +1838,7 @@ /* * Shutdown the sending side of a connection. Much like close except - * that we don't receive shut down or set SOCK_DEAD in sk->flags. + * that we don't receive shut down or set_sock_flag(sk, SOCK_DEAD). */ void tcp_shutdown(struct sock *sk, int how) @@ -1849,7 +1851,7 @@ return; /* If we've already sent a FIN, or it's a closed state, skip this. */ - if ((1 << sk->state) & + if ((1 << sk->sk_state) & (TCPF_ESTABLISHED | TCPF_SYN_SENT | TCPF_SYN_RECV | TCPF_CLOSE_WAIT)) { /* Clear out any half completed packets. FIN if needed. */ @@ -1865,26 +1867,26 @@ static inline int closing(struct sock *sk) { - return (1 << sk->state) & + return (1 << sk->sk_state) & (TCPF_FIN_WAIT1 | TCPF_CLOSING | TCPF_LAST_ACK); } static __inline__ void tcp_kill_sk_queues(struct sock *sk) { /* First the read buffer. */ - __skb_queue_purge(&sk->receive_queue); + __skb_queue_purge(&sk->sk_receive_queue); /* Next, the error queue. */ - __skb_queue_purge(&sk->error_queue); + __skb_queue_purge(&sk->sk_error_queue); /* Next, the write queue. */ - BUG_TRAP(skb_queue_empty(&sk->write_queue)); + BUG_TRAP(skb_queue_empty(&sk->sk_write_queue)); /* Account for returned memory. */ tcp_mem_reclaim(sk); - BUG_TRAP(!sk->wmem_queued); - BUG_TRAP(!sk->forward_alloc); + BUG_TRAP(!sk->sk_wmem_queued); + BUG_TRAP(!sk->sk_forward_alloc); /* It is _impossible_ for the backlog to contain anything * when we get here. All user references to this socket @@ -1900,33 +1902,33 @@ */ void tcp_destroy_sock(struct sock *sk) { - BUG_TRAP(sk->state == TCP_CLOSE); - BUG_TRAP(test_bit(SOCK_DEAD, &sk->flags)); + BUG_TRAP(sk->sk_state == TCP_CLOSE); + BUG_TRAP(sock_flag(sk, SOCK_DEAD)); /* It cannot be in hash table! */ - BUG_TRAP(!sk->pprev); + BUG_TRAP(!sk->sk_pprev); /* If it has not 0 inet_sk(sk)->num, it must be bound */ - BUG_TRAP(!inet_sk(sk)->num || sk->prev); + BUG_TRAP(!inet_sk(sk)->num || sk->sk_prev); #ifdef TCP_DEBUG - if (sk->zapped) { + if (sk->sk_zapped) { printk(KERN_DEBUG "TCP: double destroy sk=%p\n", sk); sock_hold(sk); } - sk->zapped = 1; + sk->sk_zapped = 1; #endif - sk->prot->destroy(sk); + sk->sk_prot->destroy(sk); tcp_kill_sk_queues(sk); xfrm_sk_free_policy(sk); #ifdef INET_REFCNT_DEBUG - if (atomic_read(&sk->refcnt) != 1) { + if (atomic_read(&sk->sk_refcnt) != 1) { printk(KERN_DEBUG "Destruction TCP %p delayed, c=%d\n", - sk, atomic_read(&sk->refcnt)); + sk, atomic_read(&sk->sk_refcnt)); } #endif @@ -1940,9 +1942,9 @@ int data_was_unread = 0; lock_sock(sk); - sk->shutdown = SHUTDOWN_MASK; + sk->sk_shutdown = SHUTDOWN_MASK; - if (sk->state == TCP_LISTEN) { + if (sk->sk_state == TCP_LISTEN) { tcp_set_state(sk, TCP_CLOSE); /* Special case. */ @@ -1955,7 +1957,7 @@ * descriptor close, not protocol-sourced closes, because the * reader process may not have drained the data yet! */ - while ((skb = __skb_dequeue(&sk->receive_queue)) != NULL) { + while ((skb = __skb_dequeue(&sk->sk_receive_queue)) != NULL) { u32 len = TCP_SKB_CB(skb)->end_seq - TCP_SKB_CB(skb)->seq - skb->h.th->fin; data_was_unread += len; @@ -1978,9 +1980,9 @@ NET_INC_STATS_USER(TCPAbortOnClose); tcp_set_state(sk, TCP_CLOSE); tcp_send_active_reset(sk, GFP_KERNEL); - } else if (test_bit(SOCK_LINGER, &sk->flags) && !sk->lingertime) { + } else if (sock_flag(sk, SOCK_LINGER) && !sk->sk_lingertime) { /* Check zero linger _after_ checking for unread data. */ - sk->prot->disconnect(sk, 0); + sk->sk_prot->disconnect(sk, 0); NET_INC_STATS_USER(TCPAbortOnData); } else if (tcp_close_state(sk)) { /* We FIN if the application ate all the data before @@ -2016,7 +2018,8 @@ DEFINE_WAIT(wait); do { - prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE); + prepare_to_wait(sk->sk_sleep, &wait, + TASK_INTERRUPTIBLE); if (!closing(sk)) break; release_sock(sk); @@ -2024,7 +2027,7 @@ lock_sock(sk); } while (!signal_pending(tsk) && timeout); - finish_wait(sk->sleep, &wait); + finish_wait(sk->sk_sleep, &wait); } adjudge_to_death: @@ -2056,7 +2059,7 @@ * linger2 option. --ANK */ - if (sk->state == TCP_FIN_WAIT2) { + if (sk->sk_state == TCP_FIN_WAIT2) { struct tcp_opt *tp = tcp_sk(sk); if (tp->linger2 < 0) { tcp_set_state(sk, TCP_CLOSE); @@ -2074,10 +2077,10 @@ } } } - if (sk->state != TCP_CLOSE) { + if (sk->sk_state != TCP_CLOSE) { tcp_mem_reclaim(sk); if (atomic_read(&tcp_orphan_count) > sysctl_tcp_max_orphans || - (sk->wmem_queued > SOCK_MIN_SNDBUF && + (sk->sk_wmem_queued > SOCK_MIN_SNDBUF && atomic_read(&tcp_memory_allocated) > sysctl_tcp_mem[2])) { if (net_ratelimit()) printk(KERN_INFO "TCP: too many of orphaned " @@ -2089,7 +2092,7 @@ } atomic_inc(&tcp_orphan_count); - if (sk->state == TCP_CLOSE) + if (sk->sk_state == TCP_CLOSE) tcp_destroy_sock(sk); /* Otherwise, socket is reprieved until protocol close. */ @@ -2112,10 +2115,9 @@ { struct inet_opt *inet = inet_sk(sk); struct tcp_opt *tp = tcp_sk(sk); - int old_state; int err = 0; + int old_state = sk->sk_state; - old_state = sk->state; if (old_state != TCP_CLOSE) tcp_set_state(sk, TCP_CLOSE); @@ -2129,22 +2131,22 @@ * states */ tcp_send_active_reset(sk, gfp_any()); - sk->err = ECONNRESET; + sk->sk_err = ECONNRESET; } else if (old_state == TCP_SYN_SENT) - sk->err = ECONNRESET; + sk->sk_err = ECONNRESET; tcp_clear_xmit_timers(sk); - __skb_queue_purge(&sk->receive_queue); + __skb_queue_purge(&sk->sk_receive_queue); tcp_writequeue_purge(sk); __skb_queue_purge(&tp->out_of_order_queue); inet->dport = 0; - if (!(sk->userlocks & SOCK_BINDADDR_LOCK)) + if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK)) inet_reset_saddr(sk); - sk->shutdown = 0; - __clear_bit(SOCK_DONE, &sk->flags); + sk->sk_shutdown = 0; + sock_reset_flag(sk, SOCK_DONE); tp->srtt = 0; if ((tp->write_seq += tp->max_window + 2) == 0) tp->write_seq = 1; @@ -2162,9 +2164,9 @@ tcp_sack_reset(tp); __sk_dst_reset(sk); - BUG_TRAP(!inet->num || sk->prev); + BUG_TRAP(!inet->num || sk->sk_prev); - sk->error_report(sk); + sk->sk_error_report(sk); return err; } @@ -2193,7 +2195,8 @@ * having to remove and re-insert us on the wait queue. */ for (;;) { - prepare_to_wait_exclusive(sk->sleep, &wait, TASK_INTERRUPTIBLE); + prepare_to_wait_exclusive(sk->sk_sleep, &wait, + TASK_INTERRUPTIBLE); release_sock(sk); if (!tp->accept_queue) timeo = schedule_timeout(timeo); @@ -2202,7 +2205,7 @@ if (tp->accept_queue) break; err = -EINVAL; - if (sk->state != TCP_LISTEN) + if (sk->sk_state != TCP_LISTEN) break; err = sock_intr_errno(timeo); if (signal_pending(current)) @@ -2211,7 +2214,7 @@ if (!timeo) break; } - finish_wait(sk->sleep, &wait); + finish_wait(sk->sk_sleep, &wait); return err; } @@ -2232,7 +2235,7 @@ * and that it has something pending. */ error = -EINVAL; - if (sk->state != TCP_LISTEN) + if (sk->sk_state != TCP_LISTEN) goto out; /* Find already established connection */ @@ -2256,7 +2259,7 @@ newsk = req->sk; tcp_acceptq_removed(sk); tcp_openreq_fastfree(req); - BUG_TRAP(newsk->state != TCP_SYN_RECV); + BUG_TRAP(newsk->sk_state != TCP_SYN_RECV); release_sock(sk); return newsk; @@ -2301,16 +2304,20 @@ break; case TCP_NODELAY: - /* You cannot try to use this and TCP_CORK in - * tandem, so let the user know. - */ - if (tp->nonagle == 2) { - err = -EINVAL; - break; - } - tp->nonagle = !val ? 0 : 1; - if (val) + if (val) { + /* TCP_NODELAY is weaker than TCP_CORK, so that + * this option on corked socket is remembered, but + * it is not activated until cork is cleared. + * + * However, when TCP_NODELAY is set we make + * an explicit push, which overrides even TCP_CORK + * for currently queued segments. + */ + tp->nonagle |= TCP_NAGLE_OFF|TCP_NAGLE_PUSH; tcp_push_pending_frames(sk, tp); + } else { + tp->nonagle &= ~TCP_NAGLE_OFF; + } break; case TCP_CORK: @@ -2322,18 +2329,15 @@ * out headers with a write() call first and then use * sendfile to send out the data parts. * - * You cannot try to use TCP_NODELAY and this mechanism - * at the same time, so let the user know. + * TCP_CORK can be set together with TCP_NODELAY and it is + * stronger than TCP_NODELAY. */ - if (tp->nonagle == 1) { - err = -EINVAL; - break; - } - if (val != 0) { - tp->nonagle = 2; + if (val) { + tp->nonagle |= TCP_NAGLE_CORK; } else { - tp->nonagle = 0; - + tp->nonagle &= ~TCP_NAGLE_CORK; + if (tp->nonagle&TCP_NAGLE_OFF) + tp->nonagle |= TCP_NAGLE_PUSH; tcp_push_pending_frames(sk, tp); } break; @@ -2343,8 +2347,9 @@ err = -EINVAL; else { tp->keepalive_time = val * HZ; - if (test_bit(SOCK_KEEPOPEN, &sk->flags) && - !((1 << sk->state) & (TCPF_CLOSE | TCPF_LISTEN))) { + if (sock_flag(sk, SOCK_KEEPOPEN) && + !((1 << sk->sk_state) & + (TCPF_CLOSE | TCPF_LISTEN))) { __u32 elapsed = tcp_time_stamp - tp->rcv_tstamp; if (tp->keepalive_time > elapsed) elapsed = tp->keepalive_time - elapsed; @@ -2397,7 +2402,7 @@ case TCP_WINDOW_CLAMP: if (!val) { - if (sk->state != TCP_CLOSE) { + if (sk->sk_state != TCP_CLOSE) { err = -EINVAL; break; } @@ -2412,7 +2417,7 @@ tp->ack.pingpong = 1; } else { tp->ack.pingpong = 0; - if ((1 << sk->state) & + if ((1 << sk->sk_state) & (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT) && tcp_ack_scheduled(tp)) { tp->ack.pending |= TCP_ACK_PUSHED; @@ -2452,14 +2457,14 @@ switch (optname) { case TCP_MAXSEG: val = tp->mss_cache_std; - if (!val && ((1 << sk->state) & (TCPF_CLOSE | TCPF_LISTEN))) + if (!val && ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))) val = tp->user_mss; break; case TCP_NODELAY: - val = (tp->nonagle == 1); + val = !!(tp->nonagle&TCP_NAGLE_OFF); break; case TCP_CORK: - val = (tp->nonagle == 2); + val = !!(tp->nonagle&TCP_NAGLE_CORK); break; case TCP_KEEPIDLE: val = (tp->keepalive_time ? : sysctl_tcp_keepalive_time) / HZ; @@ -2491,7 +2496,7 @@ if (get_user(len, optlen)) return -EFAULT; - info.tcpi_state = sk->state; + info.tcpi_state = sk->sk_state; info.tcpi_ca_state = tp->ca_state; info.tcpi_retransmits = tp->retransmits; info.tcpi_probes = tp->probes_out; diff -Nru a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c --- a/net/ipv4/tcp_diag.c Mon Jun 9 23:16:05 2003 +++ b/net/ipv4/tcp_diag.c Mon Jun 9 23:16:05 2003 @@ -54,32 +54,32 @@ nlh = NLMSG_PUT(skb, pid, seq, TCPDIAG_GETSOCK, sizeof(*r)); r = NLMSG_DATA(nlh); - if (sk->state != TCP_TIME_WAIT) { + if (sk->sk_state != TCP_TIME_WAIT) { if (ext & (1<<(TCPDIAG_MEMINFO-1))) minfo = TCPDIAG_PUT(skb, TCPDIAG_MEMINFO, sizeof(*minfo)); if (ext & (1<<(TCPDIAG_INFO-1))) info = TCPDIAG_PUT(skb, TCPDIAG_INFO, sizeof(*info)); } - r->tcpdiag_family = sk->family; - r->tcpdiag_state = sk->state; + r->tcpdiag_family = sk->sk_family; + r->tcpdiag_state = sk->sk_state; r->tcpdiag_timer = 0; r->tcpdiag_retrans = 0; - r->id.tcpdiag_if = sk->bound_dev_if; + r->id.tcpdiag_if = sk->sk_bound_dev_if; r->id.tcpdiag_cookie[0] = (u32)(unsigned long)sk; r->id.tcpdiag_cookie[1] = (u32)(((unsigned long)sk >> 31) >> 1); if (r->tcpdiag_state == TCP_TIME_WAIT) { struct tcp_tw_bucket *tw = (struct tcp_tw_bucket*)sk; - long tmo = tw->ttd - jiffies; + long tmo = tw->tw_ttd - jiffies; if (tmo < 0) tmo = 0; - r->id.tcpdiag_sport = tw->sport; - r->id.tcpdiag_dport = tw->dport; - r->id.tcpdiag_src[0] = tw->rcv_saddr; - r->id.tcpdiag_dst[0] = tw->daddr; - r->tcpdiag_state = tw->substate; + r->id.tcpdiag_sport = tw->tw_sport; + r->id.tcpdiag_dport = tw->tw_dport; + r->id.tcpdiag_src[0] = tw->tw_rcv_saddr; + r->id.tcpdiag_dst[0] = tw->tw_daddr; + r->tcpdiag_state = tw->tw_substate; r->tcpdiag_timer = 3; r->tcpdiag_expires = (tmo*1000+HZ-1)/HZ; r->tcpdiag_rqueue = 0; @@ -89,9 +89,9 @@ #ifdef CONFIG_IPV6 if (r->tcpdiag_family == AF_INET6) { ipv6_addr_copy((struct in6_addr *)r->id.tcpdiag_src, - &tw->v6_rcv_saddr); + &tw->tw_v6_rcv_saddr); ipv6_addr_copy((struct in6_addr *)r->id.tcpdiag_dst, - &tw->v6_daddr); + &tw->tw_v6_daddr); } #endif nlh->nlmsg_len = skb->tail - b; @@ -124,10 +124,10 @@ r->tcpdiag_timer = 4; r->tcpdiag_retrans = tp->probes_out; r->tcpdiag_expires = EXPIRES_IN_MS(tp->timeout); - } else if (timer_pending(&sk->timer)) { + } else if (timer_pending(&sk->sk_timer)) { r->tcpdiag_timer = 2; r->tcpdiag_retrans = tp->probes_out; - r->tcpdiag_expires = EXPIRES_IN_MS(sk->timer.expires); + r->tcpdiag_expires = EXPIRES_IN_MS(sk->sk_timer.expires); } else { r->tcpdiag_timer = 0; r->tcpdiag_expires = 0; @@ -140,16 +140,16 @@ r->tcpdiag_inode = sock_i_ino(sk); if (minfo) { - minfo->tcpdiag_rmem = atomic_read(&sk->rmem_alloc); - minfo->tcpdiag_wmem = sk->wmem_queued; - minfo->tcpdiag_fmem = sk->forward_alloc; - minfo->tcpdiag_tmem = atomic_read(&sk->wmem_alloc); + minfo->tcpdiag_rmem = atomic_read(&sk->sk_rmem_alloc); + minfo->tcpdiag_wmem = sk->sk_wmem_queued; + minfo->tcpdiag_fmem = sk->sk_forward_alloc; + minfo->tcpdiag_tmem = atomic_read(&sk->sk_wmem_alloc); } if (info) { u32 now = tcp_time_stamp; - info->tcpi_state = sk->state; + info->tcpi_state = sk->sk_state; info->tcpi_ca_state = tp->ca_state; info->tcpi_retransmits = tp->retransmits; info->tcpi_probes = tp->probes_out; @@ -264,7 +264,7 @@ out: if (sk) { - if (sk->state == TCP_TIME_WAIT) + if (sk->sk_state == TCP_TIME_WAIT) tcp_tw_put((struct tcp_tw_bucket*)sk); else sock_put(sk); @@ -325,7 +325,7 @@ yes = ntohs(inet->dport) <= op[1].no; break; case TCPDIAG_BC_AUTO: - yes = !(sk->userlocks&SOCK_BINDPORT_LOCK); + yes = !(sk->sk_userlocks & SOCK_BINDPORT_LOCK); break; case TCPDIAG_BC_S_COND: case TCPDIAG_BC_D_COND: @@ -344,7 +344,7 @@ break; #ifdef CONFIG_IPV6 - if (sk->family == AF_INET6) { + if (sk->sk_family == AF_INET6) { struct ipv6_pinfo *np = inet6_sk(sk); if (op->code == TCPDIAG_BC_S_COND) @@ -362,7 +362,8 @@ if (bitstring_match(addr, cond->addr, cond->prefix_len)) break; - if (sk->family == AF_INET6 && cond->family == AF_INET) { + if (sk->sk_family == AF_INET6 && + cond->family == AF_INET) { if (addr[0] == 0 && addr[1] == 0 && addr[2] == htonl(0xffff) && bitstring_match(addr+3, cond->addr, cond->prefix_len)) @@ -466,7 +467,7 @@ for (sk = tcp_listening_hash[i], num = 0; sk != NULL; - sk = sk->next, num++) { + sk = sk->sk_next, num++) { struct inet_opt *inet = inet_sk(sk); if (num < s_num) continue; @@ -506,12 +507,12 @@ for (sk = head->chain, num = 0; sk != NULL; - sk = sk->next, num++) { + sk = sk->sk_next, num++) { struct inet_opt *inet = inet_sk(sk); if (num < s_num) continue; - if (!(r->tcpdiag_states&(1<<sk->state))) + if (!(r->tcpdiag_states & (1 << sk->sk_state))) continue; if (r->id.tcpdiag_sport != inet->sport && r->id.tcpdiag_sport) @@ -531,12 +532,12 @@ if (r->tcpdiag_states&TCPF_TIME_WAIT) { for (sk = tcp_ehash[i+tcp_ehash_size].chain; sk != NULL; - sk = sk->next, num++) { + sk = sk->sk_next, num++) { struct inet_opt *inet = inet_sk(sk); if (num < s_num) continue; - if (!(r->tcpdiag_states&(1<<sk->zapped))) + if (!(r->tcpdiag_states & (1 << sk->sk_zapped))) continue; if (r->id.tcpdiag_sport != inet->sport && r->id.tcpdiag_sport) @@ -622,7 +623,7 @@ { struct sk_buff *skb; - while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) { + while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { tcpdiag_rcv_skb(skb); kfree_skb(skb); } diff -Nru a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c --- a/net/ipv4/tcp_input.c Mon Jun 9 23:16:16 2003 +++ b/net/ipv4/tcp_input.c Mon Jun 9 23:16:16 2003 @@ -184,7 +184,7 @@ /* Buffer size and advertised window tuning. * - * 1. Tuning sk->sndbuf, when connection enters established state. + * 1. Tuning sk->sk_sndbuf, when connection enters established state. */ static void tcp_fixup_sndbuf(struct sock *sk) @@ -192,8 +192,8 @@ int sndmem = tcp_sk(sk)->mss_clamp + MAX_TCP_HEADER + 16 + sizeof(struct sk_buff); - if (sk->sndbuf < 3*sndmem) - sk->sndbuf = min(3*sndmem, sysctl_tcp_wmem[2]); + if (sk->sk_sndbuf < 3 * sndmem) + sk->sk_sndbuf = min(3 * sndmem, sysctl_tcp_wmem[2]); } /* 2. Tuning advertised window (window_clamp, rcv_ssthresh) @@ -276,8 +276,8 @@ */ while (tcp_win_from_space(rcvmem) < tp->advmss) rcvmem += 128; - if (sk->rcvbuf < 4*rcvmem) - sk->rcvbuf = min(4*rcvmem, sysctl_tcp_rmem[2]); + if (sk->sk_rcvbuf < 4 * rcvmem) + sk->sk_rcvbuf = min(4 * rcvmem, sysctl_tcp_rmem[2]); } /* 4. Try to fixup all. It is made iimediately after connection enters @@ -288,9 +288,9 @@ struct tcp_opt *tp = tcp_sk(sk); int maxwin; - if (!(sk->userlocks&SOCK_RCVBUF_LOCK)) + if (!(sk->sk_userlocks & SOCK_RCVBUF_LOCK)) tcp_fixup_rcvbuf(sk); - if (!(sk->userlocks&SOCK_SNDBUF_LOCK)) + if (!(sk->sk_userlocks & SOCK_SNDBUF_LOCK)) tcp_fixup_sndbuf(sk); maxwin = tcp_full_space(sk); @@ -331,15 +331,16 @@ * do not clamp window. Try to expand rcvbuf instead. */ if (ofo_win) { - if (sk->rcvbuf < sysctl_tcp_rmem[2] && - !(sk->userlocks&SOCK_RCVBUF_LOCK) && + if (sk->sk_rcvbuf < sysctl_tcp_rmem[2] && + !(sk->sk_userlocks & SOCK_RCVBUF_LOCK) && !tcp_memory_pressure && atomic_read(&tcp_memory_allocated) < sysctl_tcp_mem[0]) - sk->rcvbuf = min(atomic_read(&sk->rmem_alloc), sysctl_tcp_rmem[2]); + sk->sk_rcvbuf = min(atomic_read(&sk->sk_rmem_alloc), + sysctl_tcp_rmem[2]); } - if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf) { + if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf) { app_win += ofo_win; - if (atomic_read(&sk->rmem_alloc) >= 2*sk->rcvbuf) + if (atomic_read(&sk->sk_rmem_alloc) >= 2 * sk->sk_rcvbuf) app_win >>= 1; if (app_win > tp->ack.rcv_mss) app_win -= tp->ack.rcv_mss; @@ -556,8 +557,8 @@ if (m >= dst_metric(dst, RTAX_RTTVAR)) dst->metrics[RTAX_RTTVAR-1] = m; else - dst->metrics[RTAX_RTT-1] -= - (dst->metrics[RTAX_RTT-1] - m)>>2; + dst->metrics[RTAX_RTTVAR-1] -= + (dst->metrics[RTAX_RTTVAR-1] - m)>>2; } if (tp->snd_ssthresh >= 0xFFFF) { @@ -778,9 +779,9 @@ /* So, SACKs for already sent large segments will be lost. * Not good, but alternative is to resegment the queue. */ - if (sk->route_caps&NETIF_F_TSO) { - sk->route_caps &= ~NETIF_F_TSO; - sk->no_largesend = 1; + if (sk->sk_route_caps & NETIF_F_TSO) { + sk->sk_route_caps &= ~NETIF_F_TSO; + sk->sk_no_largesend = 1; tp->mss_cache = tp->mss_cache_std; } @@ -1128,13 +1129,13 @@ * receiver _host_ is heavily congested (or buggy). * Do processing similar to RTO timeout. */ - if ((skb = skb_peek(&sk->write_queue)) != NULL && + if ((skb = skb_peek(&sk->sk_write_queue)) != NULL && (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED)) { NET_INC_STATS_BH(TCPSACKReneging); tcp_enter_loss(sk, 1); tp->retransmits++; - tcp_retransmit_skb(sk, skb_peek(&sk->write_queue)); + tcp_retransmit_skb(sk, skb_peek(&sk->sk_write_queue)); tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto); return 1; } @@ -1153,7 +1154,8 @@ static inline int tcp_head_timedout(struct sock *sk, struct tcp_opt *tp) { - return tp->packets_out && tcp_skb_timedout(tp, skb_peek(&sk->write_queue)); + return tp->packets_out && + tcp_skb_timedout(tp, skb_peek(&sk->sk_write_queue)); } /* Linux NewReno/SACK/FACK/ECN state machine. @@ -1840,7 +1842,7 @@ int acked = 0; __s32 seq_rtt = -1; - while((skb = skb_peek(&sk->write_queue)) && (skb != tp->send_head)) { + while ((skb = skb_peek(&sk->sk_write_queue)) && skb != tp->send_head) { struct tcp_skb_cb *scb = TCP_SKB_CB(skb); __u8 sacked = scb->sacked; @@ -2080,7 +2082,7 @@ /* We passed data and got it acked, remove any soft error * log. Something worked... */ - sk->err_soft = 0; + sk->sk_err_soft = 0; tp->rcv_tstamp = tcp_time_stamp; prior_packets = tp->packets_out; if (!prior_packets) @@ -2107,7 +2109,7 @@ } if ((flag & FLAG_FORWARD_PROGRESS) || !(flag&FLAG_NOT_DUP)) - dst_confirm(sk->dst_cache); + dst_confirm(sk->sk_dst_cache); return 1; @@ -2339,21 +2341,21 @@ static void tcp_reset(struct sock *sk) { /* We want the right error as BSD sees it (and indeed as we do). */ - switch (sk->state) { + switch (sk->sk_state) { case TCP_SYN_SENT: - sk->err = ECONNREFUSED; + sk->sk_err = ECONNREFUSED; break; case TCP_CLOSE_WAIT: - sk->err = EPIPE; + sk->sk_err = EPIPE; break; case TCP_CLOSE: return; default: - sk->err = ECONNRESET; + sk->sk_err = ECONNRESET; } - if (!test_bit(SOCK_DEAD, &sk->flags)) - sk->error_report(sk); + if (!sock_flag(sk, SOCK_DEAD)) + sk->sk_error_report(sk); tcp_done(sk); } @@ -2378,10 +2380,10 @@ tcp_schedule_ack(tp); - sk->shutdown |= RCV_SHUTDOWN; - __clear_bit(SOCK_DONE, &sk->flags); + sk->sk_shutdown |= RCV_SHUTDOWN; + sock_reset_flag(sk, SOCK_DONE); - switch(sk->state) { + switch (sk->sk_state) { case TCP_SYN_RECV: case TCP_ESTABLISHED: /* Move to CLOSE_WAIT */ @@ -2416,7 +2418,8 @@ /* Only TCP_LISTEN and TCP_CLOSE are left, in these * cases we should never reach this piece of code. */ - printk("tcp_fin: Impossible, sk->state=%d\n", sk->state); + printk(KERN_ERR "%s: Impossible, sk->sk_state=%d\n", + __FUNCTION__, sk->sk_state); break; }; @@ -2428,11 +2431,12 @@ tcp_sack_reset(tp); tcp_mem_reclaim(sk); - if (!test_bit(SOCK_DEAD, &sk->flags)) { - sk->state_change(sk); + if (!sock_flag(sk, SOCK_DEAD)) { + sk->sk_state_change(sk); /* Do not send POLL_HUP for half duplex close. */ - if (sk->shutdown == SHUTDOWN_MASK || sk->state == TCP_CLOSE) + if (sk->sk_shutdown == SHUTDOWN_MASK || + sk->sk_state == TCP_CLOSE) sk_wake_async(sk, 1, POLL_HUP); else sk_wake_async(sk, 1, POLL_IN); @@ -2650,7 +2654,7 @@ TCP_SKB_CB(skb)->end_seq); __skb_unlink(skb, skb->list); - __skb_queue_tail(&sk->receive_queue, skb); + __skb_queue_tail(&sk->sk_receive_queue, skb); tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; if(skb->h.th->fin) tcp_fin(skb, sk, skb->h.th); @@ -2659,7 +2663,7 @@ static inline int tcp_rmem_schedule(struct sock *sk, struct sk_buff *skb) { - return (int)skb->truesize <= sk->forward_alloc || + return (int)skb->truesize <= sk->sk_forward_alloc || tcp_mem_schedule(sk, skb->truesize, 1); } @@ -2714,13 +2718,13 @@ if (eaten <= 0) { queue_and_out: if (eaten < 0 && - (atomic_read(&sk->rmem_alloc) > sk->rcvbuf || + (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf || !tcp_rmem_schedule(sk, skb))) { if (tcp_prune_queue(sk) < 0 || !tcp_rmem_schedule(sk, skb)) goto drop; } tcp_set_owner_r(skb, sk); - __skb_queue_tail(&sk->receive_queue, skb); + __skb_queue_tail(&sk->sk_receive_queue, skb); } tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; if(skb->len) @@ -2743,10 +2747,10 @@ tcp_fast_path_check(sk, tp); - if (eaten > 0) { + if (eaten > 0) __kfree_skb(skb); - } else if (!test_bit(SOCK_DEAD, &sk->flags)) - sk->data_ready(sk, 0); + else if (!sock_flag(sk, SOCK_DEAD)) + sk->sk_data_ready(sk, 0); return; } @@ -2787,7 +2791,7 @@ TCP_ECN_check_ce(tp, skb); - if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf || + if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf || !tcp_rmem_schedule(sk, skb)) { if (tcp_prune_queue(sk) < 0 || !tcp_rmem_schedule(sk, skb)) goto drop; @@ -3024,18 +3028,18 @@ NET_INC_STATS_BH(PruneCalled); - if (atomic_read(&sk->rmem_alloc) >= sk->rcvbuf) + if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf) tcp_clamp_window(sk, tp); else if (tcp_memory_pressure) tp->rcv_ssthresh = min(tp->rcv_ssthresh, 4U * tp->advmss); tcp_collapse_ofo_queue(sk); - tcp_collapse(sk, sk->receive_queue.next, - (struct sk_buff*)&sk->receive_queue, + tcp_collapse(sk, sk->sk_receive_queue.next, + (struct sk_buff*)&sk->sk_receive_queue, tp->copied_seq, tp->rcv_nxt); tcp_mem_reclaim(sk); - if (atomic_read(&sk->rmem_alloc) <= sk->rcvbuf) + if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) return 0; /* Collapsing did not help, destructive actions follow. @@ -3057,7 +3061,7 @@ tcp_mem_reclaim(sk); } - if(atomic_read(&sk->rmem_alloc) <= sk->rcvbuf) + if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) return 0; /* If we are really being abused, tell the caller to silently @@ -3081,7 +3085,7 @@ struct tcp_opt *tp = tcp_sk(sk); if (tp->ca_state == TCP_CA_Open && - sk->socket && !test_bit(SOCK_NOSPACE, &sk->socket->flags)) { + sk->sk_socket && !test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) { /* Limited by application or receiver window. */ u32 win_used = max(tp->snd_cwnd_used, 2U); if (win_used < tp->snd_cwnd) { @@ -3105,7 +3109,7 @@ struct tcp_opt *tp = tcp_sk(sk); if (tp->packets_out < tp->snd_cwnd && - !(sk->userlocks&SOCK_SNDBUF_LOCK) && + !(sk->sk_userlocks & SOCK_SNDBUF_LOCK) && !tcp_memory_pressure && atomic_read(&tcp_memory_allocated) < sysctl_tcp_mem[0]) { int sndmem = max_t(u32, tp->mss_clamp, tp->mss_cache) + @@ -3113,12 +3117,12 @@ demanded = max_t(unsigned int, tp->snd_cwnd, tp->reordering + 1); sndmem *= 2*demanded; - if (sndmem > sk->sndbuf) - sk->sndbuf = min(sndmem, sysctl_tcp_wmem[2]); + if (sndmem > sk->sk_sndbuf) + sk->sk_sndbuf = min(sndmem, sysctl_tcp_wmem[2]); tp->snd_cwnd_stamp = tcp_time_stamp; } - sk->write_space(sk); + sk->sk_write_space(sk); } static inline void tcp_check_space(struct sock *sk) @@ -3127,7 +3131,8 @@ if (tp->queue_shrunk) { tp->queue_shrunk = 0; - if (sk->socket && test_bit(SOCK_NOSPACE, &sk->socket->flags)) + if (sk->sk_socket && + test_bit(SOCK_NOSPACE, &sk->sk_socket->flags)) tcp_new_space(sk); } } @@ -3247,9 +3252,9 @@ * buggy users. */ if (tp->urg_seq == tp->copied_seq && tp->urg_data && - !test_bit(SOCK_URGINLINE, &sk->flags) && + !sock_flag(sk, SOCK_URGINLINE) && tp->copied_seq != tp->rcv_nxt) { - struct sk_buff *skb = skb_peek(&sk->receive_queue); + struct sk_buff *skb = skb_peek(&sk->sk_receive_queue); tp->copied_seq++; if (skb && !before(tp->copied_seq, TCP_SKB_CB(skb)->end_seq)) { __skb_unlink(skb, skb->list); @@ -3284,8 +3289,8 @@ if (skb_copy_bits(skb, ptr, &tmp, 1)) BUG(); tp->urg_data = TCP_URG_VALID | tmp; - if (!test_bit(SOCK_DEAD, &sk->flags)) - sk->data_ready(sk,0); + if (!sock_flag(sk, SOCK_DEAD)) + sk->sk_data_ready(sk, 0); } } } @@ -3483,14 +3488,14 @@ tp->rcv_nxt == tp->rcv_wup) tcp_store_ts_recent(tp); - if ((int)skb->truesize > sk->forward_alloc) + if ((int)skb->truesize > sk->sk_forward_alloc) goto step5; NET_INC_STATS_BH(TCPHPHits); /* Bulk data transfer: receiver */ __skb_pull(skb,tcp_header_len); - __skb_queue_tail(&sk->receive_queue, skb); + __skb_queue_tail(&sk->sk_receive_queue, skb); tcp_set_owner_r(skb, sk); tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; } @@ -3519,7 +3524,7 @@ if (eaten) __kfree_skb(skb); else - sk->data_ready(sk, 0); + sk->sk_data_ready(sk, 0); return 0; } } @@ -3659,7 +3664,7 @@ TCP_ECN_rcv_synack(tp, th); if (tp->ecn_flags&TCP_ECN_OK) - sk->no_largesend = 1; + sk->sk_no_largesend = 1; tp->snd_wl1 = TCP_SKB_CB(skb)->seq; tcp_ack(sk, skb, FLAG_SLOWPATH); @@ -3699,7 +3704,7 @@ tcp_init_metrics(sk); tcp_init_buffer_space(sk); - if (test_bit(SOCK_KEEPOPEN, &sk->flags)) + if (sock_flag(sk, SOCK_KEEPOPEN)) tcp_reset_keepalive_timer(sk, keepalive_time_when(tp)); if (!tp->snd_wscale) @@ -3714,8 +3719,8 @@ mb(); tcp_set_state(sk, TCP_ESTABLISHED); - if(!test_bit(SOCK_DEAD, &sk->flags)) { - sk->state_change(sk); + if (!sock_flag(sk, SOCK_DEAD)) { + sk->sk_state_change(sk); sk_wake_async(sk, 0, POLL_OUT); } @@ -3787,7 +3792,7 @@ TCP_ECN_rcv_syn(tp, th); if (tp->ecn_flags&TCP_ECN_OK) - sk->no_largesend = 1; + sk->sk_no_largesend = 1; tcp_sync_mss(sk, tp->pmtu_cookie); tcp_initialize_rcv_mss(sk); @@ -3840,7 +3845,7 @@ tp->saw_tstamp = 0; - switch (sk->state) { + switch (sk->sk_state) { case TCP_CLOSE: goto discard; @@ -3928,20 +3933,20 @@ if (th->ack) { int acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH); - switch(sk->state) { + switch(sk->sk_state) { case TCP_SYN_RECV: if (acceptable) { tp->copied_seq = tp->rcv_nxt; mb(); tcp_set_state(sk, TCP_ESTABLISHED); - sk->state_change(sk); + sk->sk_state_change(sk); /* Note, that this wakeup is only for marginal * crossed SYN case. Passively open sockets - * are not waked up, because sk->sleep == NULL - * and sk->socket == NULL. + * are not waked up, because sk->sk_sleep == + * NULL and sk->sk_socket == NULL. */ - if (sk->socket) { + if (sk->sk_socket) { sk_wake_async(sk,0,POLL_OUT); } @@ -3974,13 +3979,13 @@ case TCP_FIN_WAIT1: if (tp->snd_una == tp->write_seq) { tcp_set_state(sk, TCP_FIN_WAIT2); - sk->shutdown |= SEND_SHUTDOWN; - dst_confirm(sk->dst_cache); + sk->sk_shutdown |= SEND_SHUTDOWN; + dst_confirm(sk->sk_dst_cache); - if (!test_bit(SOCK_DEAD, &sk->flags)) { + if (!sock_flag(sk, SOCK_DEAD)) /* Wake up lingering close() */ - sk->state_change(sk); - } else { + sk->sk_state_change(sk); + else { int tmo; if (tp->linger2 < 0 || @@ -4032,7 +4037,7 @@ tcp_urg(sk, skb, th); /* step 7: process the segment text */ - switch (sk->state) { + switch (sk->sk_state) { case TCP_CLOSE_WAIT: case TCP_CLOSING: case TCP_LAST_ACK: @@ -4044,7 +4049,7 @@ * RFC 1122 says we MUST send a reset. * BSD 4.4 also does reset. */ - if (sk->shutdown & RCV_SHUTDOWN) { + if (sk->sk_shutdown & RCV_SHUTDOWN) { if (TCP_SKB_CB(skb)->end_seq != TCP_SKB_CB(skb)->seq && after(TCP_SKB_CB(skb)->end_seq - th->fin, tp->rcv_nxt)) { NET_INC_STATS_BH(TCPAbortOnData); @@ -4060,7 +4065,7 @@ } /* tcp_data could move socket to TIME-WAIT */ - if (sk->state != TCP_CLOSE) { + if (sk->sk_state != TCP_CLOSE) { tcp_data_snd_check(sk); tcp_ack_snd_check(sk); } diff -Nru a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c --- a/net/ipv4/tcp_ipv4.c Mon Jun 9 23:16:09 2003 +++ b/net/ipv4/tcp_ipv4.c Mon Jun 9 23:16:09 2003 @@ -161,12 +161,12 @@ struct tcp_bind_bucket *tb; spin_lock(&head->lock); - tb = (struct tcp_bind_bucket *)sk->prev; - if ((child->bind_next = tb->owners) != NULL) - tb->owners->bind_pprev = &child->bind_next; + tb = (struct tcp_bind_bucket *)sk->sk_prev; + if ((child->sk_bind_next = tb->owners) != NULL) + tb->owners->sk_bind_pprev = &child->sk_bind_next; tb->owners = child; - child->bind_pprev = &tb->owners; - child->prev = (struct sock *)tb; + child->sk_bind_pprev = &tb->owners; + child->sk_prev = (struct sock *)tb; spin_unlock(&head->lock); } @@ -181,25 +181,25 @@ unsigned short snum) { inet_sk(sk)->num = snum; - if ((sk->bind_next = tb->owners) != NULL) - tb->owners->bind_pprev = &sk->bind_next; + if ((sk->sk_bind_next = tb->owners) != NULL) + tb->owners->sk_bind_pprev = &sk->sk_bind_next; tb->owners = sk; - sk->bind_pprev = &tb->owners; - sk->prev = (struct sock *)tb; + sk->sk_bind_pprev = &tb->owners; + sk->sk_prev = (struct sock *)tb; } static inline int tcp_bind_conflict(struct sock *sk, struct tcp_bind_bucket *tb) { struct inet_opt *inet = inet_sk(sk); struct sock *sk2 = tb->owners; - int sk_reuse = sk->reuse; + int reuse = sk->sk_reuse; - for ( ; sk2; sk2 = sk2->bind_next) { + for (; sk2; sk2 = sk2->sk_bind_next) { if (sk != sk2 && !ipv6_only_sock(sk2) && - sk->bound_dev_if == sk2->bound_dev_if) { - if (!sk_reuse || !sk2->reuse || - sk2->state == TCP_LISTEN) { + sk->sk_bound_dev_if == sk2->sk_bound_dev_if) { + if (!reuse || !sk2->sk_reuse || + sk2->sk_state == TCP_LISTEN) { struct inet_opt *inet2 = inet_sk(sk2); if (!inet2->rcv_saddr || !inet->rcv_saddr || inet2->rcv_saddr == inet->rcv_saddr) @@ -262,9 +262,10 @@ break; } if (tb && tb->owners) { - if (sk->reuse > 1) + if (sk->sk_reuse > 1) goto success; - if (tb->fastreuse > 0 && sk->reuse && sk->state != TCP_LISTEN) { + if (tb->fastreuse > 0 && + sk->sk_reuse && sk->sk_state != TCP_LISTEN) { goto success; } else { ret = 1; @@ -276,16 +277,17 @@ if (!tb && (tb = tcp_bucket_create(head, snum)) == NULL) goto fail_unlock; if (!tb->owners) { - if (sk->reuse && sk->state != TCP_LISTEN) + if (sk->sk_reuse && sk->sk_state != TCP_LISTEN) tb->fastreuse = 1; else tb->fastreuse = 0; - } else if (tb->fastreuse && (!sk->reuse || sk->state == TCP_LISTEN)) + } else if (tb->fastreuse && + (!sk->sk_reuse || sk->sk_state == TCP_LISTEN)) tb->fastreuse = 0; success: - if (!sk->prev) + if (!sk->sk_prev) tcp_bind_hash(sk, tb, snum); - BUG_TRAP(sk->prev == (struct sock *)tb); + BUG_TRAP(sk->sk_prev == (struct sock *)tb); ret = 0; fail_unlock: @@ -305,11 +307,11 @@ struct tcp_bind_bucket *tb; spin_lock(&head->lock); - tb = (struct tcp_bind_bucket *) sk->prev; - if (sk->bind_next) - sk->bind_next->bind_pprev = sk->bind_pprev; - *(sk->bind_pprev) = sk->bind_next; - sk->prev = NULL; + tb = (struct tcp_bind_bucket *)sk->sk_prev; + if (sk->sk_bind_next) + sk->sk_bind_next->sk_bind_pprev = sk->sk_bind_pprev; + *(sk->sk_bind_pprev) = sk->sk_bind_next; + sk->sk_prev = NULL; inet->num = 0; tcp_bucket_destroy(tb); spin_unlock(&head->lock); @@ -355,29 +357,29 @@ struct sock **skp; rwlock_t *lock; - BUG_TRAP(!sk->pprev); - if (listen_possible && sk->state == TCP_LISTEN) { + BUG_TRAP(!sk->sk_pprev); + if (listen_possible && sk->sk_state == TCP_LISTEN) { skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)]; lock = &tcp_lhash_lock; tcp_listen_wlock(); } else { - skp = &tcp_ehash[(sk->hashent = tcp_sk_hashfn(sk))].chain; - lock = &tcp_ehash[sk->hashent].lock; + skp = &tcp_ehash[(sk->sk_hashent = tcp_sk_hashfn(sk))].chain; + lock = &tcp_ehash[sk->sk_hashent].lock; write_lock(lock); } - if ((sk->next = *skp) != NULL) - (*skp)->pprev = &sk->next; + if ((sk->sk_next = *skp) != NULL) + (*skp)->sk_pprev = &sk->sk_next; *skp = sk; - sk->pprev = skp; - sock_prot_inc_use(sk->prot); + sk->sk_pprev = skp; + sock_prot_inc_use(sk->sk_prot); write_unlock(lock); - if (listen_possible && sk->state == TCP_LISTEN) + if (listen_possible && sk->sk_state == TCP_LISTEN) wake_up(&tcp_lhash_wait); } static void tcp_v4_hash(struct sock *sk) { - if (sk->state != TCP_CLOSE) { + if (sk->sk_state != TCP_CLOSE) { local_bh_disable(); __tcp_v4_hash(sk, 1); local_bh_enable(); @@ -388,30 +390,30 @@ { rwlock_t *lock; - if (!sk->pprev) + if (!sk->sk_pprev) goto ende; - if (sk->state == TCP_LISTEN) { + if (sk->sk_state == TCP_LISTEN) { local_bh_disable(); tcp_listen_wlock(); lock = &tcp_lhash_lock; } else { - struct tcp_ehash_bucket *head = &tcp_ehash[sk->hashent]; + struct tcp_ehash_bucket *head = &tcp_ehash[sk->sk_hashent]; lock = &head->lock; write_lock_bh(&head->lock); } - if (sk->pprev) { - if (sk->next) - sk->next->pprev = sk->pprev; - *sk->pprev = sk->next; - sk->pprev = NULL; - sock_prot_dec_use(sk->prot); + if (sk->sk_pprev) { + if (sk->sk_next) + sk->sk_next->sk_pprev = sk->sk_pprev; + *sk->sk_pprev = sk->sk_next; + sk->sk_pprev = NULL; + sock_prot_dec_use(sk->sk_prot); } write_unlock_bh(lock); ende: - if (sk->state == TCP_LISTEN) + if (sk->sk_state == TCP_LISTEN) wake_up(&tcp_lhash_wait); } @@ -428,20 +430,20 @@ int score, hiscore; hiscore=-1; - for (; sk; sk = sk->next) { + for (; sk; sk = sk->sk_next) { struct inet_opt *inet = inet_sk(sk); if (inet->num == hnum && !ipv6_only_sock(sk)) { __u32 rcv_saddr = inet->rcv_saddr; - score = (sk->family == PF_INET ? 1 : 0); + score = (sk->sk_family == PF_INET ? 1 : 0); if (rcv_saddr) { if (rcv_saddr != daddr) continue; score+=2; } - if (sk->bound_dev_if) { - if (sk->bound_dev_if != dif) + if (sk->sk_bound_dev_if) { + if (sk->sk_bound_dev_if != dif) continue; score+=2; } @@ -467,10 +469,10 @@ if (sk) { struct inet_opt *inet = inet_sk(sk); - if (inet->num == hnum && !sk->next && + if (inet->num == hnum && !sk->sk_next && (!inet->rcv_saddr || inet->rcv_saddr == daddr) && - (sk->family == PF_INET || !ipv6_only_sock(sk)) && - !sk->bound_dev_if) + (sk->sk_family == PF_INET || !ipv6_only_sock(sk)) && + !sk->sk_bound_dev_if) goto sherry_cache; sk = __tcp_v4_lookup_listener(sk, daddr, hnum, dif); } @@ -502,14 +504,14 @@ int hash = tcp_hashfn(daddr, hnum, saddr, sport); head = &tcp_ehash[hash]; read_lock(&head->lock); - for (sk = head->chain; sk; sk = sk->next) { + for (sk = head->chain; sk; sk = sk->sk_next) { if (TCP_IPV4_MATCH(sk, acookie, saddr, daddr, ports, dif)) goto hit; /* You sunk my battleship! */ } /* Must check for a TIME_WAIT'er before going to listener hash. */ - for (sk = (head + tcp_ehash_size)->chain; sk; sk = sk->next) - if (TCP_IPV4_MATCH(sk, acookie, saddr, daddr, ports, dif)) + for (sk = (head + tcp_ehash_size)->chain; sk; sk = sk->sk_next) + if (TCP_IPV4_TW_MATCH(sk, acookie, saddr, daddr, ports, dif)) goto hit; out: read_unlock(&head->lock); @@ -555,7 +557,7 @@ struct inet_opt *inet = inet_sk(sk); u32 daddr = inet->rcv_saddr; u32 saddr = inet->daddr; - int dif = sk->bound_dev_if; + int dif = sk->sk_bound_dev_if; TCP_V4_ADDR_COOKIE(acookie, saddr, daddr) __u32 ports = TCP_COMBINED_PORTS(inet->dport, lport); int hash = tcp_hashfn(daddr, lport, saddr, inet->dport); @@ -567,10 +569,10 @@ /* Check TIME-WAIT sockets first. */ for (skp = &(head + tcp_ehash_size)->chain; (sk2 = *skp) != NULL; - skp = &sk2->next) { + skp = &sk2->sk_next) { tw = (struct tcp_tw_bucket *)sk2; - if (TCP_IPV4_MATCH(sk2, acookie, saddr, daddr, ports, dif)) { + if (TCP_IPV4_TW_MATCH(sk2, acookie, saddr, daddr, ports, dif)) { struct tcp_opt *tp = tcp_sk(sk); /* With PAWS, it is safe from the viewpoint @@ -587,15 +589,15 @@ fall back to VJ's scheme and use initial timestamp retrieved from peer table. */ - if (tw->ts_recent_stamp && + if (tw->tw_ts_recent_stamp && (!twp || (sysctl_tcp_tw_reuse && xtime.tv_sec - - tw->ts_recent_stamp > 1))) { + tw->tw_ts_recent_stamp > 1))) { if ((tp->write_seq = - tw->snd_nxt + 65535 + 2) == 0) + tw->tw_snd_nxt + 65535 + 2) == 0) tp->write_seq = 1; - tp->ts_recent = tw->ts_recent; - tp->ts_recent_stamp = tw->ts_recent_stamp; + tp->ts_recent = tw->tw_ts_recent; + tp->ts_recent_stamp = tw->tw_ts_recent_stamp; sock_hold(sk2); skp = &head->chain; goto unique; @@ -606,7 +608,7 @@ tw = NULL; /* And established part... */ - for (skp = &head->chain; (sk2 = *skp) != NULL; skp = &sk2->next) { + for (skp = &head->chain; (sk2 = *skp) != NULL; skp = &sk2->sk_next) { if (TCP_IPV4_MATCH(sk2, acookie, saddr, daddr, ports, dif)) goto not_unique; } @@ -616,14 +618,14 @@ * in hash table socket with a funny identity. */ inet->num = lport; inet->sport = htons(lport); - BUG_TRAP(!sk->pprev); - if ((sk->next = *skp) != NULL) - (*skp)->pprev = &sk->next; + BUG_TRAP(!sk->sk_pprev); + if ((sk->sk_next = *skp) != NULL) + (*skp)->sk_pprev = &sk->sk_next; *skp = sk; - sk->pprev = skp; - sk->hashent = hash; - sock_prot_inc_use(sk->prot); + sk->sk_pprev = skp; + sk->sk_hashent = hash; + sock_prot_inc_use(sk->sk_prot); write_unlock(&head->lock); if (twp) { @@ -727,7 +729,7 @@ spin_unlock(&tcp_portalloc_lock); tcp_bind_hash(sk, tb, rover); - if (!sk->pprev) { + if (!sk->sk_pprev) { inet_sk(sk)->sport = htons(rover); __tcp_v4_hash(sk, 0); } @@ -743,9 +745,9 @@ } head = &tcp_bhash[tcp_bhashfn(snum)]; - tb = (struct tcp_bind_bucket *)sk->prev; + tb = (struct tcp_bind_bucket *)sk->sk_prev; spin_lock_bh(&head->lock); - if (tb->owners == sk && !sk->bind_next) { + if (tb->owners == sk && !sk->sk_bind_next) { __tcp_v4_hash(sk, 0); spin_unlock_bh(&head->lock); return 0; @@ -784,7 +786,7 @@ } tmp = ip_route_connect(&rt, nexthop, inet->saddr, - RT_CONN_FLAGS(sk), sk->bound_dev_if, + RT_CONN_FLAGS(sk), sk->sk_bound_dev_if, IPPROTO_TCP, inet->sport, usin->sin_port, sk); if (tmp < 0) @@ -871,7 +873,7 @@ /* This unhashes the socket and releases the local port, if necessary. */ tcp_set_state(sk, TCP_CLOSE); ip_rt_put(rt); - sk->route_caps = 0; + sk->sk_route_caps = 0; inet->dport = 0; return err; } @@ -943,7 +945,7 @@ * send out by Linux are always <576bytes so they should go through * unfragmented). */ - if (sk->state == TCP_LISTEN) + if (sk->sk_state == TCP_LISTEN) return; /* We don't check in the destentry if pmtu discovery is forbidden @@ -961,7 +963,7 @@ * for the case, if this connection will not able to recover. */ if (mtu < dst_pmtu(dst) && ip_dont_fragment(sk, dst)) - sk->err_soft = EMSGSIZE; + sk->sk_err_soft = EMSGSIZE; mtu = dst_pmtu(dst); @@ -1017,7 +1019,7 @@ ICMP_INC_STATS_BH(IcmpInErrors); return; } - if (sk->state == TCP_TIME_WAIT) { + if (sk->sk_state == TCP_TIME_WAIT) { tcp_tw_put((struct tcp_tw_bucket *)sk); return; } @@ -1029,12 +1031,12 @@ if (sock_owned_by_user(sk)) NET_INC_STATS_BH(LockDroppedIcmps); - if (sk->state == TCP_CLOSE) + if (sk->sk_state == TCP_CLOSE) goto out; tp = tcp_sk(sk); seq = ntohl(th->seq); - if (sk->state != TCP_LISTEN && + if (sk->sk_state != TCP_LISTEN && !between(seq, tp->snd_una, tp->snd_nxt)) { NET_INC_STATS(OutOfWindowIcmps); goto out; @@ -1070,7 +1072,7 @@ goto out; } - switch (sk->state) { + switch (sk->sk_state) { struct open_request *req, **prev; case TCP_LISTEN: if (sock_owned_by_user(sk)) @@ -1106,13 +1108,13 @@ */ if (!sock_owned_by_user(sk)) { TCP_INC_STATS_BH(TcpAttemptFails); - sk->err = err; + sk->sk_err = err; - sk->error_report(sk); + sk->sk_error_report(sk); tcp_done(sk); } else { - sk->err_soft = err; + sk->sk_err_soft = err; } goto out; } @@ -1135,10 +1137,10 @@ inet = inet_sk(sk); if (!sock_owned_by_user(sk) && inet->recverr) { - sk->err = err; - sk->error_report(sk); + sk->sk_err = err; + sk->sk_error_report(sk); } else { /* Only an error on timeout */ - sk->err_soft = err; + sk->sk_err_soft = err; } out: @@ -1269,8 +1271,8 @@ { struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)sk; - tcp_v4_send_ack(skb, tw->snd_nxt, tw->rcv_nxt, - tw->rcv_wnd >> tw->rcv_wscale, tw->ts_recent); + tcp_v4_send_ack(skb, tw->tw_snd_nxt, tw->tw_rcv_nxt, + tw->tw_rcv_wnd >> tw->tw_rcv_wscale, tw->tw_ts_recent); tcp_tw_put(tw); } @@ -1286,7 +1288,7 @@ { struct rtable *rt; struct ip_options *opt = req->af.v4_req.opt; - struct flowi fl = { .oif = sk->bound_dev_if, + struct flowi fl = { .oif = sk->sk_bound_dev_if, .nl_u = { .ip4_u = { .daddr = ((opt && opt->srr) ? opt->faddr : @@ -1586,7 +1588,7 @@ if (!newsk) goto exit; - newsk->dst_cache = dst; + newsk->sk_dst_cache = dst; tcp_v4_setup_caps(newsk, dst); newtp = tcp_sk(newsk); @@ -1641,7 +1643,7 @@ tcp_v4_iif(skb)); if (nsk) { - if (nsk->state != TCP_TIME_WAIT) { + if (nsk->sk_state != TCP_TIME_WAIT) { bh_lock_sock(nsk); return nsk; } @@ -1693,7 +1695,7 @@ */ int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb) { - if (sk->state == TCP_ESTABLISHED) { /* Fast path */ + if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */ TCP_CHECK_TIMER(sk); if (tcp_rcv_established(sk, skb, skb->h.th, skb->len)) goto reset; @@ -1704,7 +1706,7 @@ if (skb->len < (skb->h.th->doff << 2) || tcp_checksum_complete(skb)) goto csum_err; - if (sk->state == TCP_LISTEN) { + if (sk->sk_state == TCP_LISTEN) { struct sock *nsk = tcp_v4_hnd_req(sk, skb); if (!nsk) goto discard; @@ -1789,7 +1791,7 @@ goto no_tcp_socket; process: - if (sk->state == TCP_TIME_WAIT) + if (sk->sk_state == TCP_TIME_WAIT) goto do_time_wait; if (!xfrm4_policy_check(sk, XFRM_POLICY_IN, skb)) @@ -1870,8 +1872,8 @@ */ static void __tcp_v4_rehash(struct sock *sk) { - sk->prot->unhash(sk); - sk->prot->hash(sk); + sk->sk_prot->unhash(sk); + sk->sk_prot->hash(sk); } static int tcp_v4_reselect_saddr(struct sock *sk) @@ -1888,8 +1890,8 @@ /* Query new route. */ err = ip_route_connect(&rt, daddr, 0, - RT_TOS(inet->tos) | sk->localroute, - sk->bound_dev_if, + RT_TOS(inet->tos) | sk->sk_localroute, + sk->sk_bound_dev_if, IPPROTO_TCP, inet->sport, inet->dport, sk); if (err) @@ -1941,7 +1943,7 @@ daddr = inet->opt->faddr; { - struct flowi fl = { .oif = sk->bound_dev_if, + struct flowi fl = { .oif = sk->sk_bound_dev_if, .nl_u = { .ip4_u = { .daddr = daddr, .saddr = inet->saddr, @@ -1960,13 +1962,13 @@ } /* Routing failed... */ - sk->route_caps = 0; + sk->sk_route_caps = 0; if (!sysctl_ip_dynaddr || - sk->state != TCP_SYN_SENT || - (sk->userlocks & SOCK_BINDADDR_LOCK) || + sk->sk_state != TCP_SYN_SENT || + (sk->sk_userlocks & SOCK_BINDADDR_LOCK) || (err = tcp_v4_reselect_saddr(sk)) != 0) - sk->err_soft=-err; + sk->sk_err_soft = -err; return err; } @@ -2023,14 +2025,14 @@ { struct inet_peer *peer = NULL; - peer = inet_getpeer(tw->daddr, 1); + peer = inet_getpeer(tw->tw_daddr, 1); if (peer) { - if ((s32)(peer->tcp_ts - tw->ts_recent) <= 0 || + if ((s32)(peer->tcp_ts - tw->tw_ts_recent) <= 0 || (peer->tcp_ts_stamp + TCP_PAWS_MSL < xtime.tv_sec && - peer->tcp_ts_stamp <= tw->ts_recent_stamp)) { - peer->tcp_ts_stamp = tw->ts_recent_stamp; - peer->tcp_ts = tw->ts_recent; + peer->tcp_ts_stamp <= tw->tw_ts_recent_stamp)) { + peer->tcp_ts_stamp = tw->tw_ts_recent_stamp; + peer->tcp_ts = tw->tw_ts_recent; } inet_putpeer(peer); return 1; @@ -2083,15 +2085,15 @@ tp->reordering = sysctl_tcp_reordering; - sk->state = TCP_CLOSE; + sk->sk_state = TCP_CLOSE; - sk->write_space = tcp_write_space; - sk->use_write_queue = 1; + sk->sk_write_space = tcp_write_space; + sk->sk_use_write_queue = 1; tp->af_specific = &ipv4_specific; - sk->sndbuf = sysctl_tcp_wmem[1]; - sk->rcvbuf = sysctl_tcp_rmem[1]; + sk->sk_sndbuf = sysctl_tcp_wmem[1]; + sk->sk_rcvbuf = sysctl_tcp_rmem[1]; atomic_inc(&tcp_sockets_allocated); @@ -2114,7 +2116,7 @@ __skb_queue_purge(&tp->ucopy.prequeue); /* Clean up a referenced TCP bind bucket. */ - if (sk->prev) + if (sk->sk_prev) tcp_put_port(sk); /* If sendmsg cached page exists, toss it. */ @@ -2142,7 +2144,7 @@ if (!sk) continue; ++st->num; - if (sk->family == st->family) { + if (sk->sk_family == st->family) { rc = sk; goto out; } @@ -2195,14 +2197,14 @@ get_req: req = tp->listen_opt->syn_table[st->sbucket]; } - sk = st->syn_wait_sk->next; + sk = st->syn_wait_sk->sk_next; st->state = TCP_SEQ_STATE_LISTENING; read_unlock_bh(&tp->syn_wait_lock); } else - sk = sk->next; + sk = sk->sk_next; get_sk: while (sk) { - if (sk->family == st->family) { + if (sk->sk_family == st->family) { cur = sk; goto out; } @@ -2216,7 +2218,7 @@ goto get_req; } read_unlock_bh(&tp->syn_wait_lock); - sk = sk->next; + sk = sk->sk_next; } if (++st->bucket < TCP_LHTABLE_SIZE) { sk = tcp_listening_hash[st->bucket]; @@ -2248,8 +2250,8 @@ read_lock(&tcp_ehash[st->bucket].lock); for (sk = tcp_ehash[st->bucket].chain; sk; - sk = sk->next, ++st->num) { - if (sk->family != st->family) + sk = sk->sk_next, ++st->num) { + if (sk->sk_family != st->family) continue; rc = sk; goto out; @@ -2257,8 +2259,8 @@ st->state = TCP_SEQ_STATE_TIME_WAIT; for (tw = (struct tcp_tw_bucket *) tcp_ehash[st->bucket + tcp_ehash_size].chain; - tw; tw = (struct tcp_tw_bucket *)tw->next, ++st->num) { - if (tw->family != st->family) + tw; tw = (struct tcp_tw_bucket *)tw->tw_next, ++st->num) { + if (tw->tw_family != st->family) continue; rc = tw; goto out; @@ -2278,11 +2280,11 @@ if (st->state == TCP_SEQ_STATE_TIME_WAIT) { tw = cur; - tw = (struct tcp_tw_bucket *)tw->next; + tw = (struct tcp_tw_bucket *)tw->tw_next; get_tw: - while (tw && tw->family != st->family) { + while (tw && tw->tw_family != st->family) { ++st->num; - tw = (struct tcp_tw_bucket *)tw->next; + tw = (struct tcp_tw_bucket *)tw->tw_next; } if (tw) { cur = tw; @@ -2298,11 +2300,11 @@ goto out; } } else - sk = sk->next; + sk = sk->sk_next; - while (sk && sk->family != st->family) { + while (sk && sk->sk_family != st->family) { ++st->num; - sk = sk->next; + sk = sk->sk_next; } if (!sk) { st->state = TCP_SEQ_STATE_TIME_WAIT; @@ -2482,7 +2484,7 @@ uid, 0, /* non standard timer */ 0, /* open_requests have no inode */ - atomic_read(&sk->refcnt), + atomic_read(&sk->sk_refcnt), req); } @@ -2503,9 +2505,9 @@ } else if (tp->pending == TCP_TIME_PROBE0) { timer_active = 4; timer_expires = tp->timeout; - } else if (timer_pending(&sp->timer)) { + } else if (timer_pending(&sp->sk_timer)) { timer_active = 2; - timer_expires = sp->timer.expires; + timer_expires = sp->sk_timer.expires; } else { timer_active = 0; timer_expires = jiffies; @@ -2513,14 +2515,14 @@ sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX " "%08X %5d %8d %lu %d %p %u %u %u %u %d", - i, src, srcp, dest, destp, sp->state, + i, src, srcp, dest, destp, sp->sk_state, tp->write_seq - tp->snd_una, tp->rcv_nxt - tp->copied_seq, timer_active, timer_expires - jiffies, tp->retransmits, sock_i_uid(sp), tp->probes_out, sock_i_ino(sp), - atomic_read(&sp->refcnt), sp, + atomic_read(&sp->sk_refcnt), sp, tp->rto, tp->ack.ato, (tp->ack.quick << 1) | tp->ack.pingpong, tp->snd_cwnd, tp->snd_ssthresh >= 0xFFFF ? -1 : tp->snd_ssthresh); @@ -2530,21 +2532,21 @@ { unsigned int dest, src; __u16 destp, srcp; - int ttd = tw->ttd - jiffies; + int ttd = tw->tw_ttd - jiffies; if (ttd < 0) ttd = 0; - dest = tw->daddr; - src = tw->rcv_saddr; - destp = ntohs(tw->dport); - srcp = ntohs(tw->sport); + dest = tw->tw_daddr; + src = tw->tw_rcv_saddr; + destp = ntohs(tw->tw_dport); + srcp = ntohs(tw->tw_sport); sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X" " %02X %08X:%08X %02X:%08X %08X %5d %8d %d %d %p", - i, src, srcp, dest, destp, tw->substate, 0, 0, + i, src, srcp, dest, destp, tw->tw_substate, 0, 0, 3, ttd, 0, 0, 0, 0, - atomic_read(&tw->refcnt), tw); + atomic_read(&tw->tw_refcnt), tw); } #define TMPSZ 150 @@ -2627,12 +2629,12 @@ int err = sock_create(PF_INET, SOCK_RAW, IPPROTO_TCP, &tcp_socket); if (err < 0) panic("Failed to create the TCP control socket.\n"); - tcp_socket->sk->allocation = GFP_ATOMIC; + tcp_socket->sk->sk_allocation = GFP_ATOMIC; inet_sk(tcp_socket->sk)->uc_ttl = -1; /* Unhash it so that IP input processing does not even * see it, we do not wish this socket to see incoming * packets. */ - tcp_socket->sk->prot->unhash(tcp_socket->sk); + tcp_socket->sk->sk_prot->unhash(tcp_socket->sk); } diff -Nru a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c --- a/net/ipv4/tcp_minisocks.c Mon Jun 9 23:16:16 2003 +++ b/net/ipv4/tcp_minisocks.c Mon Jun 9 23:16:16 2003 @@ -61,32 +61,33 @@ struct tcp_bind_bucket *tb; /* Unlink from established hashes. */ - ehead = &tcp_ehash[tw->hashent]; + ehead = &tcp_ehash[tw->tw_hashent]; write_lock(&ehead->lock); - if (!tw->pprev) { + if (!tw->tw_pprev) { write_unlock(&ehead->lock); return; } - if(tw->next) - tw->next->pprev = tw->pprev; - *(tw->pprev) = tw->next; - tw->pprev = NULL; + if (tw->tw_next) + tw->tw_next->sk_pprev = tw->tw_pprev; + *(tw->tw_pprev) = tw->tw_next; + tw->tw_pprev = NULL; write_unlock(&ehead->lock); /* Disassociate with bind bucket. */ - bhead = &tcp_bhash[tcp_bhashfn(tw->num)]; + bhead = &tcp_bhash[tcp_bhashfn(tw->tw_num)]; spin_lock(&bhead->lock); - tb = tw->tb; - if(tw->bind_next) - tw->bind_next->bind_pprev = tw->bind_pprev; - *(tw->bind_pprev) = tw->bind_next; - tw->tb = NULL; + tb = tw->tw_tb; + if (tw->tw_bind_next) + tw->tw_bind_next->sk_bind_pprev = tw->tw_bind_pprev; + *(tw->tw_bind_pprev) = tw->tw_bind_next; + tw->tw_tb = NULL; tcp_bucket_destroy(tb); spin_unlock(&bhead->lock); #ifdef INET_REFCNT_DEBUG - if (atomic_read(&tw->refcnt) != 1) { - printk(KERN_DEBUG "tw_bucket %p refcnt=%d\n", tw, atomic_read(&tw->refcnt)); + if (atomic_read(&tw->tw_refcnt) != 1) { + printk(KERN_DEBUG "tw_bucket %p refcnt=%d\n", tw, + atomic_read(&tw->tw_refcnt)); } #endif tcp_tw_put(tw); @@ -128,33 +129,34 @@ int paws_reject = 0; tp.saw_tstamp = 0; - if (th->doff > (sizeof(struct tcphdr)>>2) && tw->ts_recent_stamp) { + if (th->doff > (sizeof(struct tcphdr) >> 2) && tw->tw_ts_recent_stamp) { tcp_parse_options(skb, &tp, 0); if (tp.saw_tstamp) { - tp.ts_recent = tw->ts_recent; - tp.ts_recent_stamp = tw->ts_recent_stamp; + tp.ts_recent = tw->tw_ts_recent; + tp.ts_recent_stamp = tw->tw_ts_recent_stamp; paws_reject = tcp_paws_check(&tp, th->rst); } } - if (tw->substate == TCP_FIN_WAIT2) { + if (tw->tw_substate == TCP_FIN_WAIT2) { /* Just repeat all the checks of tcp_rcv_state_process() */ /* Out of window, send ACK */ if (paws_reject || !tcp_in_window(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq, - tw->rcv_nxt, tw->rcv_nxt + tw->rcv_wnd)) + tw->tw_rcv_nxt, + tw->tw_rcv_nxt + tw->tw_rcv_wnd)) return TCP_TW_ACK; if (th->rst) goto kill; - if (th->syn && !before(TCP_SKB_CB(skb)->seq, tw->rcv_nxt)) + if (th->syn && !before(TCP_SKB_CB(skb)->seq, tw->tw_rcv_nxt)) goto kill_with_rst; /* Dup ACK? */ - if (!after(TCP_SKB_CB(skb)->end_seq, tw->rcv_nxt) || + if (!after(TCP_SKB_CB(skb)->end_seq, tw->tw_rcv_nxt) || TCP_SKB_CB(skb)->end_seq == TCP_SKB_CB(skb)->seq) { tcp_tw_put(tw); return TCP_TW_SUCCESS; @@ -163,7 +165,8 @@ /* New data or FIN. If new data arrive after half-duplex close, * reset. */ - if (!th->fin || TCP_SKB_CB(skb)->end_seq != tw->rcv_nxt+1) { + if (!th->fin || + TCP_SKB_CB(skb)->end_seq != tw->tw_rcv_nxt + 1) { kill_with_rst: tcp_tw_deschedule(tw); tcp_tw_put(tw); @@ -171,11 +174,11 @@ } /* FIN arrived, enter true time-wait state. */ - tw->substate = TCP_TIME_WAIT; - tw->rcv_nxt = TCP_SKB_CB(skb)->end_seq; + tw->tw_substate = TCP_TIME_WAIT; + tw->tw_rcv_nxt = TCP_SKB_CB(skb)->end_seq; if (tp.saw_tstamp) { - tw->ts_recent_stamp = xtime.tv_sec; - tw->ts_recent = tp.rcv_tsval; + tw->tw_ts_recent_stamp = xtime.tv_sec; + tw->tw_ts_recent = tp.rcv_tsval; } /* I am shamed, but failed to make it more elegant. @@ -183,10 +186,10 @@ * to generalize to IPv6. Taking into account that IPv6 * do not undertsnad recycling in any case, it not * a big problem in practice. --ANK */ - if (tw->family == AF_INET && - sysctl_tcp_tw_recycle && tw->ts_recent_stamp && + if (tw->tw_family == AF_INET && + sysctl_tcp_tw_recycle && tw->tw_ts_recent_stamp && tcp_v4_tw_remember_stamp(tw)) - tcp_tw_schedule(tw, tw->timeout); + tcp_tw_schedule(tw, tw->tw_timeout); else tcp_tw_schedule(tw, TCP_TIMEWAIT_LEN); return TCP_TW_ACK; @@ -210,7 +213,7 @@ */ if (!paws_reject && - (TCP_SKB_CB(skb)->seq == tw->rcv_nxt && + (TCP_SKB_CB(skb)->seq == tw->tw_rcv_nxt && (TCP_SKB_CB(skb)->seq == TCP_SKB_CB(skb)->end_seq || th->rst))) { /* In window segment, it may be only reset or bare ack. */ @@ -229,8 +232,8 @@ tcp_tw_schedule(tw, TCP_TIMEWAIT_LEN); if (tp.saw_tstamp) { - tw->ts_recent = tp.rcv_tsval; - tw->ts_recent_stamp = xtime.tv_sec; + tw->tw_ts_recent = tp.rcv_tsval; + tw->tw_ts_recent_stamp = xtime.tv_sec; } tcp_tw_put(tw); @@ -255,9 +258,9 @@ */ if (th->syn && !th->rst && !th->ack && !paws_reject && - (after(TCP_SKB_CB(skb)->seq, tw->rcv_nxt) || - (tp.saw_tstamp && (s32)(tw->ts_recent - tp.rcv_tsval) < 0))) { - u32 isn = tw->snd_nxt+65535+2; + (after(TCP_SKB_CB(skb)->seq, tw->tw_rcv_nxt) || + (tp.saw_tstamp && (s32)(tw->tw_ts_recent - tp.rcv_tsval) < 0))) { + u32 isn = tw->tw_snd_nxt + 65535 + 2; if (isn == 0) isn++; TCP_SKB_CB(skb)->when = isn; @@ -293,7 +296,7 @@ */ static void __tcp_tw_hashdance(struct sock *sk, struct tcp_tw_bucket *tw) { - struct tcp_ehash_bucket *ehead = &tcp_ehash[sk->hashent]; + struct tcp_ehash_bucket *ehead = &tcp_ehash[sk->sk_hashent]; struct tcp_bind_hashbucket *bhead; struct sock **head, *sktw; @@ -303,33 +306,33 @@ */ bhead = &tcp_bhash[tcp_bhashfn(inet_sk(sk)->num)]; spin_lock(&bhead->lock); - tw->tb = (struct tcp_bind_bucket *)sk->prev; - BUG_TRAP(sk->prev!=NULL); - if ((tw->bind_next = tw->tb->owners) != NULL) - tw->tb->owners->bind_pprev = &tw->bind_next; - tw->tb->owners = (struct sock*)tw; - tw->bind_pprev = &tw->tb->owners; + tw->tw_tb = (struct tcp_bind_bucket *)sk->sk_prev; + BUG_TRAP(sk->sk_prev); + if ((tw->tw_bind_next = tw->tw_tb->owners) != NULL) + tw->tw_tb->owners->sk_bind_pprev = &tw->tw_bind_next; + tw->tw_tb->owners = (struct sock *)tw; + tw->tw_bind_pprev = &tw->tw_tb->owners; spin_unlock(&bhead->lock); write_lock(&ehead->lock); /* Step 2: Remove SK from established hash. */ - if (sk->pprev) { - if(sk->next) - sk->next->pprev = sk->pprev; - *sk->pprev = sk->next; - sk->pprev = NULL; - sock_prot_dec_use(sk->prot); + if (sk->sk_pprev) { + if (sk->sk_next) + sk->sk_next->sk_pprev = sk->sk_pprev; + *sk->sk_pprev = sk->sk_next; + sk->sk_pprev = NULL; + sock_prot_dec_use(sk->sk_prot); } /* Step 3: Hash TW into TIMEWAIT half of established hash table. */ head = &(ehead + tcp_ehash_size)->chain; sktw = (struct sock *)tw; - if((sktw->next = *head) != NULL) - (*head)->pprev = &sktw->next; + if ((sktw->sk_next = *head) != NULL) + (*head)->sk_pprev = &sktw->sk_next; *head = sktw; - sktw->pprev = head; - atomic_inc(&tw->refcnt); + sktw->sk_pprev = head; + atomic_inc(&tw->tw_refcnt); write_unlock(&ehead->lock); } @@ -354,33 +357,33 @@ int rto = (tp->rto<<2) - (tp->rto>>1); /* Give us an identity. */ - tw->daddr = inet->daddr; - tw->rcv_saddr = inet->rcv_saddr; - tw->bound_dev_if= sk->bound_dev_if; - tw->num = inet->num; - tw->state = TCP_TIME_WAIT; - tw->substate = state; - tw->sport = inet->sport; - tw->dport = inet->dport; - tw->family = sk->family; - tw->reuse = sk->reuse; - tw->rcv_wscale = tp->rcv_wscale; - atomic_set(&tw->refcnt, 1); - - tw->hashent = sk->hashent; - tw->rcv_nxt = tp->rcv_nxt; - tw->snd_nxt = tp->snd_nxt; - tw->rcv_wnd = tcp_receive_window(tp); - tw->ts_recent = tp->ts_recent; - tw->ts_recent_stamp= tp->ts_recent_stamp; - tw->pprev_death = NULL; + tw->tw_daddr = inet->daddr; + tw->tw_rcv_saddr = inet->rcv_saddr; + tw->tw_bound_dev_if = sk->sk_bound_dev_if; + tw->tw_num = inet->num; + tw->tw_state = TCP_TIME_WAIT; + tw->tw_substate = state; + tw->tw_sport = inet->sport; + tw->tw_dport = inet->dport; + tw->tw_family = sk->sk_family; + tw->tw_reuse = sk->sk_reuse; + tw->tw_rcv_wscale = tp->rcv_wscale; + atomic_set(&tw->tw_refcnt, 1); + + tw->tw_hashent = sk->sk_hashent; + tw->tw_rcv_nxt = tp->rcv_nxt; + tw->tw_snd_nxt = tp->snd_nxt; + tw->tw_rcv_wnd = tcp_receive_window(tp); + tw->tw_ts_recent = tp->ts_recent; + tw->tw_ts_recent_stamp = tp->ts_recent_stamp; + tw->tw_pprev_death = NULL; #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) - if(tw->family == PF_INET6) { + if (tw->tw_family == PF_INET6) { struct ipv6_pinfo *np = inet6_sk(sk); - ipv6_addr_copy(&tw->v6_daddr, &np->daddr); - ipv6_addr_copy(&tw->v6_rcv_saddr, &np->rcv_saddr); + ipv6_addr_copy(&tw->tw_v6_daddr, &np->daddr); + ipv6_addr_copy(&tw->tw_v6_rcv_saddr, &np->rcv_saddr); } #endif /* Linkage updates. */ @@ -391,9 +394,9 @@ timeo = rto; if (recycle_ok) { - tw->timeout = rto; + tw->tw_timeout = rto; } else { - tw->timeout = TCP_TIMEWAIT_LEN; + tw->tw_timeout = TCP_TIMEWAIT_LEN; if (state == TCP_TIME_WAIT) timeo = TCP_TIMEWAIT_LEN; } @@ -443,10 +446,10 @@ goto out; while((tw = tcp_tw_death_row[tcp_tw_death_row_slot]) != NULL) { - tcp_tw_death_row[tcp_tw_death_row_slot] = tw->next_death; - if (tw->next_death) - tw->next_death->pprev_death = tw->pprev_death; - tw->pprev_death = NULL; + tcp_tw_death_row[tcp_tw_death_row_slot] = tw->tw_next_death; + if (tw->tw_next_death) + tw->tw_next_death->tw_pprev_death = tw->tw_pprev_death; + tw->tw_pprev_death = NULL; spin_unlock(&tw_death_lock); tcp_timewait_kill(tw); @@ -474,11 +477,11 @@ void tcp_tw_deschedule(struct tcp_tw_bucket *tw) { spin_lock(&tw_death_lock); - if (tw->pprev_death) { - if(tw->next_death) - tw->next_death->pprev_death = tw->pprev_death; - *tw->pprev_death = tw->next_death; - tw->pprev_death = NULL; + if (tw->tw_pprev_death) { + if (tw->tw_next_death) + tw->tw_next_death->tw_pprev_death = tw->tw_pprev_death; + *tw->tw_pprev_death = tw->tw_next_death; + tw->tw_pprev_death = NULL; tcp_tw_put(tw); if (--tcp_tw_count == 0) del_timer(&tcp_tw_timer); @@ -530,14 +533,14 @@ spin_lock(&tw_death_lock); /* Unlink it, if it was scheduled */ - if (tw->pprev_death) { - if(tw->next_death) - tw->next_death->pprev_death = tw->pprev_death; - *tw->pprev_death = tw->next_death; - tw->pprev_death = NULL; + if (tw->tw_pprev_death) { + if (tw->tw_next_death) + tw->tw_next_death->tw_pprev_death = tw->tw_pprev_death; + *tw->tw_pprev_death = tw->tw_next_death; + tw->tw_pprev_death = NULL; tcp_tw_count--; } else - atomic_inc(&tw->refcnt); + atomic_inc(&tw->tw_refcnt); if (slot >= TCP_TW_RECYCLE_SLOTS) { /* Schedule to slow timer */ @@ -548,11 +551,11 @@ if (slot >= TCP_TWKILL_SLOTS) slot = TCP_TWKILL_SLOTS-1; } - tw->ttd = jiffies + timeo; + tw->tw_ttd = jiffies + timeo; slot = (tcp_tw_death_row_slot + slot) & (TCP_TWKILL_SLOTS - 1); tpp = &tcp_tw_death_row[slot]; } else { - tw->ttd = jiffies + (slot<<TCP_TW_RECYCLE_TICK); + tw->tw_ttd = jiffies + (slot << TCP_TW_RECYCLE_TICK); if (tcp_twcal_hand < 0) { tcp_twcal_hand = 0; @@ -567,10 +570,10 @@ tpp = &tcp_twcal_row[slot]; } - if((tw->next_death = *tpp) != NULL) - (*tpp)->pprev_death = &tw->next_death; + if ((tw->tw_next_death = *tpp) != NULL) + (*tpp)->tw_pprev_death = &tw->tw_next_death; *tpp = tw; - tw->pprev_death = tpp; + tw->tw_pprev_death = tpp; if (tcp_tw_count++ == 0) mod_timer(&tcp_tw_timer, jiffies+TCP_TWKILL_PERIOD); @@ -597,8 +600,8 @@ struct tcp_tw_bucket *tw; while((tw = tcp_twcal_row[slot]) != NULL) { - tcp_twcal_row[slot] = tw->next_death; - tw->pprev_death = NULL; + tcp_twcal_row[slot] = tw->tw_next_death; + tw->tw_pprev_death = NULL; tcp_timewait_kill(tw); tcp_tw_put(tw); @@ -639,18 +642,18 @@ /* allocate the newsk from the same slab of the master sock, * if not, at sk_free time we'll try to free it from the wrong * slabcache (i.e. is it TCPv4 or v6?) -acme */ - struct sock *newsk = sk_alloc(PF_INET, GFP_ATOMIC, 0, sk->slab); + struct sock *newsk = sk_alloc(PF_INET, GFP_ATOMIC, 0, sk->sk_slab); if(newsk != NULL) { struct tcp_opt *newtp; struct sk_filter *filter; memcpy(newsk, sk, sizeof(struct tcp_sock)); - newsk->state = TCP_SYN_RECV; + newsk->sk_state = TCP_SYN_RECV; /* SANITY */ - newsk->pprev = NULL; - newsk->prev = NULL; + newsk->sk_pprev = NULL; + newsk->sk_prev = NULL; /* Clone the TCP header template */ inet_sk(newsk)->dport = req->rmt_port; @@ -658,29 +661,29 @@ sock_lock_init(newsk); bh_lock_sock(newsk); - newsk->dst_lock = RW_LOCK_UNLOCKED; - atomic_set(&newsk->rmem_alloc, 0); - skb_queue_head_init(&newsk->receive_queue); - atomic_set(&newsk->wmem_alloc, 0); - skb_queue_head_init(&newsk->write_queue); - atomic_set(&newsk->omem_alloc, 0); - newsk->wmem_queued = 0; - newsk->forward_alloc = 0; - - __clear_bit(SOCK_DONE, &newsk->flags); - newsk->userlocks = sk->userlocks & ~SOCK_BINDPORT_LOCK; - newsk->backlog.head = newsk->backlog.tail = NULL; - newsk->callback_lock = RW_LOCK_UNLOCKED; - skb_queue_head_init(&newsk->error_queue); - newsk->write_space = tcp_write_space; + newsk->sk_dst_lock = RW_LOCK_UNLOCKED; + atomic_set(&newsk->sk_rmem_alloc, 0); + skb_queue_head_init(&newsk->sk_receive_queue); + atomic_set(&newsk->sk_wmem_alloc, 0); + skb_queue_head_init(&newsk->sk_write_queue); + atomic_set(&newsk->sk_omem_alloc, 0); + newsk->sk_wmem_queued = 0; + newsk->sk_forward_alloc = 0; + + sock_reset_flag(newsk, SOCK_DONE); + newsk->sk_userlocks = sk->sk_userlocks & ~SOCK_BINDPORT_LOCK; + newsk->sk_backlog.head = newsk->sk_backlog.tail = NULL; + newsk->sk_callback_lock = RW_LOCK_UNLOCKED; + skb_queue_head_init(&newsk->sk_error_queue); + newsk->sk_write_space = tcp_write_space; - if ((filter = newsk->filter) != NULL) + if ((filter = newsk->sk_filter) != NULL) sk_filter_charge(newsk, filter); if (unlikely(xfrm_sk_clone_policy(newsk))) { /* It is still raw copy of parent, so invalidate * destructor and make plain sk_free() */ - newsk->destruct = NULL; + newsk->sk_destruct = NULL; sk_free(newsk); return NULL; } @@ -744,19 +747,20 @@ memset(&newtp->syn_wait_lock, 0, sizeof(newtp->syn_wait_lock)); /* Back to base struct sock members. */ - newsk->err = 0; - newsk->priority = 0; - atomic_set(&newsk->refcnt, 2); + newsk->sk_err = 0; + newsk->sk_priority = 0; + atomic_set(&newsk->sk_refcnt, 2); #ifdef INET_REFCNT_DEBUG atomic_inc(&inet_sock_nr); #endif atomic_inc(&tcp_sockets_allocated); - if (test_bit(SOCK_KEEPOPEN, &newsk->flags)) - tcp_reset_keepalive_timer(newsk, keepalive_time_when(newtp)); - newsk->socket = NULL; - newsk->sleep = NULL; - newsk->owner = NULL; + if (sock_flag(newsk, SOCK_KEEPOPEN)) + tcp_reset_keepalive_timer(newsk, + keepalive_time_when(newtp)); + newsk->sk_socket = NULL; + newsk->sk_sleep = NULL; + newsk->sk_owner = NULL; newtp->tstamp_ok = req->tstamp_ok; if((newtp->sack_ok = req->sack_ok) != 0) { @@ -790,7 +794,7 @@ newtp->mss_clamp = req->mss; TCP_ECN_openreq_child(newtp, req); if (newtp->ecn_flags&TCP_ECN_OK) - newsk->no_largesend = 1; + newsk->sk_no_largesend = 1; TCP_INC_STATS_BH(TcpPassiveOpens); } @@ -966,7 +970,7 @@ if (child == NULL) goto listen_overflow; - sk_set_owner(child, sk->owner); + sk_set_owner(child, sk->sk_owner); tcp_synq_unlink(tp, req, prev); tcp_synq_removed(sk, req); @@ -998,14 +1002,14 @@ struct sk_buff *skb) { int ret = 0; - int state = child->state; + int state = child->sk_state; if (!sock_owned_by_user(child)) { ret = tcp_rcv_state_process(child, skb, skb->h.th, skb->len); /* Wakeup parent, send SIGIO */ - if (state == TCP_SYN_RECV && child->state != state) - parent->data_ready(parent, 0); + if (state == TCP_SYN_RECV && child->sk_state != state) + parent->sk_data_ready(parent, 0); } else { /* Alas, it is possible again, because we do lookup * in main socket hash table and lock on listening diff -Nru a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c --- a/net/ipv4/tcp_output.c Mon Jun 9 23:16:15 2003 +++ b/net/ipv4/tcp_output.c Mon Jun 9 23:16:15 2003 @@ -48,7 +48,7 @@ void update_send_head(struct sock *sk, struct tcp_opt *tp, struct sk_buff *skb) { tp->send_head = skb->next; - if (tp->send_head == (struct sk_buff *) &sk->write_queue) + if (tp->send_head == (struct sk_buff *)&sk->sk_write_queue) tp->send_head = NULL; tp->snd_nxt = TCP_SKB_CB(skb)->end_seq; if (tp->packets_out++ == 0) @@ -309,13 +309,13 @@ /* Advance write_seq and place onto the write_queue. */ tp->write_seq = TCP_SKB_CB(skb)->end_seq; - __skb_queue_tail(&sk->write_queue, skb); + __skb_queue_tail(&sk->sk_write_queue, skb); tcp_charge_skb(sk, skb); if (!force_queue && tp->send_head == NULL && tcp_snd_test(tp, skb, cur_mss, tp->nonagle)) { /* Send it out now. */ TCP_SKB_CB(skb)->when = tcp_time_stamp; - if (tcp_transmit_skb(sk, skb_clone(skb, sk->allocation)) == 0) { + if (!tcp_transmit_skb(sk, skb_clone(skb, sk->sk_allocation))) { tp->snd_nxt = TCP_SKB_CB(skb)->end_seq; tcp_minshall_update(tp, cur_mss, skb); if (tp->packets_out++ == 0) @@ -336,10 +336,10 @@ struct tcp_opt *tp = tcp_sk(sk); struct sk_buff *skb = tp->send_head; - if (tcp_snd_test(tp, skb, cur_mss, 1)) { + if (tcp_snd_test(tp, skb, cur_mss, TCP_NAGLE_PUSH)) { /* Send it out now. */ TCP_SKB_CB(skb)->when = tcp_time_stamp; - if (tcp_transmit_skb(sk, skb_clone(skb, sk->allocation)) == 0) { + if (!tcp_transmit_skb(sk, skb_clone(skb, sk->sk_allocation))) { tp->send_head = NULL; tp->snd_nxt = TCP_SKB_CB(skb)->end_seq; if (tp->packets_out++ == 0) @@ -587,7 +587,7 @@ tp->pmtu_cookie = pmtu; tp->mss_cache = tp->mss_cache_std = mss_now; - if (sk->route_caps&NETIF_F_TSO) { + if (sk->sk_route_caps & NETIF_F_TSO) { int large_mss; large_mss = 65535 - tp->af_specific->net_header_len - @@ -620,7 +620,7 @@ * In time closedown will finish, we empty the write queue and all * will be happy. */ - if(sk->state != TCP_CLOSE) { + if (sk->sk_state != TCP_CLOSE) { struct sk_buff *skb; int sent_pkts = 0; @@ -632,7 +632,7 @@ mss_now = tcp_current_mss(sk, 1); while((skb = tp->send_head) && - tcp_snd_test(tp, skb, mss_now, tcp_skb_is_last(sk, skb) ? nonagle : 1)) { + tcp_snd_test(tp, skb, mss_now, tcp_skb_is_last(sk, skb) ? nonagle : TCP_NAGLE_PUSH)) { if (skb->len > mss_now) { if (tcp_fragment(sk, skb, mss_now)) break; @@ -886,16 +886,17 @@ /* Do not sent more than we queued. 1/4 is reserved for possible * copying overhead: frgagmentation, tunneling, mangling etc. */ - if (atomic_read(&sk->wmem_alloc) > min(sk->wmem_queued+(sk->wmem_queued>>2),sk->sndbuf)) + if (atomic_read(&sk->sk_wmem_alloc) > + min(sk->sk_wmem_queued + (sk->sk_wmem_queued >> 2), sk->sk_sndbuf)) return -EAGAIN; if (before(TCP_SKB_CB(skb)->seq, tp->snd_una)) { if (before(TCP_SKB_CB(skb)->end_seq, tp->snd_una)) BUG(); - if (sk->route_caps&NETIF_F_TSO) { - sk->route_caps &= ~NETIF_F_TSO; - sk->no_largesend = 1; + if (sk->sk_route_caps & NETIF_F_TSO) { + sk->sk_route_caps &= ~NETIF_F_TSO; + sk->sk_no_largesend = 1; tp->mss_cache = tp->mss_cache_std; } @@ -924,7 +925,7 @@ if(!(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_SYN) && (skb->len < (cur_mss >> 1)) && (skb->next != tp->send_head) && - (skb->next != (struct sk_buff *)&sk->write_queue) && + (skb->next != (struct sk_buff *)&sk->sk_write_queue) && (skb_shinfo(skb)->nr_frags == 0 && skb_shinfo(skb->next)->nr_frags == 0) && (sysctl_tcp_retrans_collapse != 0)) tcp_retrans_try_collapse(sk, skb, cur_mss); @@ -1013,7 +1014,8 @@ else NET_INC_STATS_BH(TCPSlowStartRetrans); - if (skb == skb_peek(&sk->write_queue)) + if (skb == + skb_peek(&sk->sk_write_queue)) tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto); } @@ -1059,7 +1061,7 @@ if(tcp_retransmit_skb(sk, skb)) break; - if (skb == skb_peek(&sk->write_queue)) + if (skb == skb_peek(&sk->sk_write_queue)) tcp_reset_xmit_timer(sk, TCP_TIME_RETRANS, tp->rto); NET_INC_STATS_BH(TCPForwardRetrans); @@ -1073,7 +1075,7 @@ void tcp_send_fin(struct sock *sk) { struct tcp_opt *tp = tcp_sk(sk); - struct sk_buff *skb = skb_peek_tail(&sk->write_queue); + struct sk_buff *skb = skb_peek_tail(&sk->sk_write_queue); unsigned int mss_now; /* Optimization, tack on the FIN if we have a queue of @@ -1106,7 +1108,7 @@ TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(skb)->seq + 1; tcp_send_skb(sk, skb, 1, mss_now); } - __tcp_push_pending_frames(sk, tp, mss_now, 1); + __tcp_push_pending_frames(sk, tp, mss_now, TCP_NAGLE_OFF); } /* We get here when a process closes a file descriptor (either due to @@ -1149,7 +1151,7 @@ { struct sk_buff* skb; - skb = skb_peek(&sk->write_queue); + skb = skb_peek(&sk->sk_write_queue); if (skb == NULL || !(TCP_SKB_CB(skb)->flags&TCPCB_FLAG_SYN)) { printk(KERN_DEBUG "tcp_send_synack: wrong queue state\n"); return -EFAULT; @@ -1159,8 +1161,8 @@ struct sk_buff *nskb = skb_copy(skb, GFP_ATOMIC); if (nskb == NULL) return -ENOMEM; - __skb_unlink(skb, &sk->write_queue); - __skb_queue_head(&sk->write_queue, nskb); + __skb_unlink(skb, &sk->sk_write_queue); + __skb_queue_head(&sk->sk_write_queue, nskb); tcp_free_skb(sk, skb); tcp_charge_skb(sk, nskb); skb = nskb; @@ -1275,8 +1277,8 @@ tp->rcv_ssthresh = tp->rcv_wnd; - sk->err = 0; - __clear_bit(SOCK_DONE, &sk->flags); + sk->sk_err = 0; + sock_reset_flag(sk, SOCK_DONE); tp->snd_wnd = 0; tcp_init_wl(tp, tp->write_seq, 0); tp->snd_una = tp->write_seq; @@ -1300,7 +1302,7 @@ tcp_connect_init(sk); - buff = alloc_skb(MAX_TCP_HEADER + 15, sk->allocation); + buff = alloc_skb(MAX_TCP_HEADER + 15, sk->sk_allocation); if (unlikely(buff == NULL)) return -ENOBUFS; @@ -1319,7 +1321,7 @@ /* Send it off. */ TCP_SKB_CB(buff)->when = tcp_time_stamp; tp->retrans_stamp = TCP_SKB_CB(buff)->when; - __skb_queue_tail(&sk->write_queue, buff); + __skb_queue_tail(&sk->sk_write_queue, buff); tcp_charge_skb(sk, buff); tp->packets_out++; tcp_transmit_skb(sk, skb_clone(buff, GFP_KERNEL)); @@ -1388,7 +1390,7 @@ void tcp_send_ack(struct sock *sk) { /* If we have been reset, we may not send again. */ - if(sk->state != TCP_CLOSE) { + if (sk->sk_state != TCP_CLOSE) { struct tcp_opt *tp = tcp_sk(sk); struct sk_buff *buff; @@ -1456,7 +1458,7 @@ int tcp_write_wakeup(struct sock *sk) { - if (sk->state != TCP_CLOSE) { + if (sk->sk_state != TCP_CLOSE) { struct tcp_opt *tp = tcp_sk(sk); struct sk_buff *skb; @@ -1481,9 +1483,9 @@ return -1; /* SWS override triggered forced fragmentation. * Disable TSO, the connection is too sick. */ - if (sk->route_caps&NETIF_F_TSO) { - sk->no_largesend = 1; - sk->route_caps &= ~NETIF_F_TSO; + if (sk->sk_route_caps & NETIF_F_TSO) { + sk->sk_no_largesend = 1; + sk->sk_route_caps &= ~NETIF_F_TSO; tp->mss_cache = tp->mss_cache_std; } } diff -Nru a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c --- a/net/ipv4/tcp_timer.c Mon Jun 9 23:16:18 2003 +++ b/net/ipv4/tcp_timer.c Mon Jun 9 23:16:18 2003 @@ -57,9 +57,9 @@ tp->delack_timer.data = (unsigned long) sk; tp->ack.pending = 0; - init_timer(&sk->timer); - sk->timer.function=&tcp_keepalive_timer; - sk->timer.data = (unsigned long) sk; + init_timer(&sk->sk_timer); + sk->sk_timer.function = &tcp_keepalive_timer; + sk->sk_timer.data = (unsigned long)sk; } void tcp_clear_xmit_timers(struct sock *sk) @@ -77,14 +77,14 @@ del_timer(&tp->delack_timer)) __sock_put(sk); - if(timer_pending(&sk->timer) && del_timer(&sk->timer)) + if (timer_pending(&sk->sk_timer) && del_timer(&sk->sk_timer)) __sock_put(sk); } static void tcp_write_err(struct sock *sk) { - sk->err = sk->err_soft ? : ETIMEDOUT; - sk->error_report(sk); + sk->sk_err = sk->sk_err_soft ? : ETIMEDOUT; + sk->sk_error_report(sk); tcp_done(sk); NET_INC_STATS_BH(TCPAbortOnTimeout); @@ -112,11 +112,11 @@ orphans <<= 1; /* If some dubious ICMP arrived, penalize even more. */ - if (sk->err_soft) + if (sk->sk_err_soft) orphans <<= 1; if (orphans >= sysctl_tcp_max_orphans || - (sk->wmem_queued > SOCK_MIN_SNDBUF && + (sk->sk_wmem_queued > SOCK_MIN_SNDBUF && atomic_read(&tcp_memory_allocated) > sysctl_tcp_mem[2])) { if (net_ratelimit()) printk(KERN_INFO "Out of socket memory\n"); @@ -142,7 +142,7 @@ int retries = sysctl_tcp_orphan_retries; /* May be zero. */ /* We know from an ICMP that something is wrong. */ - if (sk->err_soft && !alive) + if (sk->sk_err_soft && !alive) retries = 0; /* However, if socket sent something recently, select some safe @@ -159,9 +159,9 @@ struct tcp_opt *tp = tcp_sk(sk); int retry_until; - if ((1<<sk->state)&(TCPF_SYN_SENT|TCPF_SYN_RECV)) { + if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV)) { if (tp->retransmits) - dst_negative_advice(&sk->dst_cache); + dst_negative_advice(&sk->sk_dst_cache); retry_until = tp->syn_retries ? : sysctl_tcp_syn_retries; } else { if (tp->retransmits >= sysctl_tcp_retries1) { @@ -185,11 +185,11 @@ Golden words :-). */ - dst_negative_advice(&sk->dst_cache); + dst_negative_advice(&sk->sk_dst_cache); } retry_until = sysctl_tcp_retries2; - if (test_bit(SOCK_DEAD, &sk->flags)) { + if (sock_flag(sk, SOCK_DEAD)) { int alive = (tp->rto < TCP_RTO_MAX); retry_until = tcp_orphan_retries(sk, alive); @@ -224,7 +224,7 @@ tcp_mem_reclaim(sk); - if (sk->state == TCP_CLOSE || !(tp->ack.pending&TCP_ACK_TIMER)) + if (sk->sk_state == TCP_CLOSE || !(tp->ack.pending & TCP_ACK_TIMER)) goto out; if ((long)(tp->ack.timeout - jiffies) > 0) { @@ -241,7 +241,7 @@ skb_queue_len(&tp->ucopy.prequeue)); while ((skb = __skb_dequeue(&tp->ucopy.prequeue)) != NULL) - sk->backlog_rcv(sk, skb); + sk->sk_backlog_rcv(sk, skb); tp->ucopy.memory = 0; } @@ -297,7 +297,7 @@ */ max_probes = sysctl_tcp_retries2; - if (test_bit(SOCK_DEAD, &sk->flags)) { + if (sock_flag(sk, SOCK_DEAD)) { int alive = ((tp->rto<<tp->backoff) < TCP_RTO_MAX); max_probes = tcp_orphan_retries(sk, alive); @@ -325,10 +325,10 @@ if (tp->packets_out == 0) goto out; - BUG_TRAP(!skb_queue_empty(&sk->write_queue)); + BUG_TRAP(!skb_queue_empty(&sk->sk_write_queue)); - if (tp->snd_wnd == 0 && !test_bit(SOCK_DEAD, &sk->flags) && - !((1<<sk->state)&(TCPF_SYN_SENT|TCPF_SYN_RECV))) { + if (!tp->snd_wnd && !sock_flag(sk, SOCK_DEAD) && + !((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV))) { /* Receiver dastardly shrinks window. Our retransmits * become zero probes, but we should not timeout this * connection. If the socket is an orphan, time it out, @@ -347,7 +347,7 @@ goto out; } tcp_enter_loss(sk, 0); - tcp_retransmit_skb(sk, skb_peek(&sk->write_queue)); + tcp_retransmit_skb(sk, skb_peek(&sk->sk_write_queue)); __sk_dst_reset(sk); goto out_reset_timer; } @@ -381,7 +381,7 @@ tcp_enter_loss(sk, 0); } - if (tcp_retransmit_skb(sk, skb_peek(&sk->write_queue)) > 0) { + if (tcp_retransmit_skb(sk, skb_peek(&sk->sk_write_queue)) > 0) { /* Retransmission failed because of local congestion, * do not backoff. */ @@ -433,7 +433,7 @@ goto out_unlock; } - if (sk->state == TCP_CLOSE || !tp->pending) + if (sk->sk_state == TCP_CLOSE || !tp->pending) goto out; if ((long)(tp->timeout - jiffies) > 0) { @@ -556,22 +556,22 @@ void tcp_delete_keepalive_timer (struct sock *sk) { - if (timer_pending(&sk->timer) && del_timer (&sk->timer)) + if (timer_pending(&sk->sk_timer) && del_timer (&sk->sk_timer)) __sock_put(sk); } void tcp_reset_keepalive_timer (struct sock *sk, unsigned long len) { - if (!mod_timer(&sk->timer, jiffies+len)) + if (!mod_timer(&sk->sk_timer, jiffies + len)) sock_hold(sk); } void tcp_set_keepalive(struct sock *sk, int val) { - if ((1<<sk->state)&(TCPF_CLOSE|TCPF_LISTEN)) + if ((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN)) return; - if (val && !test_bit(SOCK_KEEPOPEN, &sk->flags)) + if (val && !sock_flag(sk, SOCK_KEEPOPEN)) tcp_reset_keepalive_timer(sk, keepalive_time_when(tcp_sk(sk))); else if (!val) tcp_delete_keepalive_timer(sk); @@ -592,12 +592,12 @@ goto out; } - if (sk->state == TCP_LISTEN) { + if (sk->sk_state == TCP_LISTEN) { tcp_synack_timer(sk); goto out; } - if (sk->state == TCP_FIN_WAIT2 && test_bit(SOCK_DEAD, &sk->flags)) { + if (sk->sk_state == TCP_FIN_WAIT2 && sock_flag(sk, SOCK_DEAD)) { if (tp->linger2 >= 0) { int tmo = tcp_fin_time(tp) - TCP_TIMEWAIT_LEN; @@ -610,7 +610,7 @@ goto death; } - if (!test_bit(SOCK_KEEPOPEN, &sk->flags) || sk->state == TCP_CLOSE) + if (!sock_flag(sk, SOCK_KEEPOPEN) || sk->sk_state == TCP_CLOSE) goto out; elapsed = keepalive_time_when(tp); diff -Nru a/net/ipv4/udp.c b/net/ipv4/udp.c --- a/net/ipv4/udp.c Mon Jun 9 23:16:08 2003 +++ b/net/ipv4/udp.c Mon Jun 9 23:16:08 2003 @@ -148,7 +148,7 @@ do { if (++size >= best_size_so_far) goto next; - } while ((sk2 = sk2->next) != NULL); + } while ((sk2 = sk2->sk_next) != NULL); best_size_so_far = size; best = result; next:; @@ -171,28 +171,28 @@ for (sk2 = udp_hash[snum & (UDP_HTABLE_SIZE - 1)]; sk2 != NULL; - sk2 = sk2->next) { + sk2 = sk2->sk_next) { struct inet_opt *inet2 = inet_sk(sk2); if (inet2->num == snum && sk2 != sk && !ipv6_only_sock(sk2) && - sk2->bound_dev_if == sk->bound_dev_if && + sk2->sk_bound_dev_if == sk->sk_bound_dev_if && (!inet2->rcv_saddr || !inet->rcv_saddr || inet2->rcv_saddr == inet->rcv_saddr) && - (!sk2->reuse || !sk->reuse)) + (!sk2->sk_reuse || !sk->sk_reuse)) goto fail; } } inet->num = snum; - if (sk->pprev == NULL) { + if (!sk->sk_pprev) { struct sock **skp = &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]; - if ((sk->next = *skp) != NULL) - (*skp)->pprev = &sk->next; + if ((sk->sk_next = *skp) != NULL) + (*skp)->sk_pprev = &sk->sk_next; *skp = sk; - sk->pprev = skp; - sock_prot_inc_use(sk->prot); + sk->sk_pprev = skp; + sock_prot_inc_use(sk->sk_prot); sock_hold(sk); } write_unlock_bh(&udp_hash_lock); @@ -211,13 +211,13 @@ static void udp_v4_unhash(struct sock *sk) { write_lock_bh(&udp_hash_lock); - if (sk->pprev) { - if (sk->next) - sk->next->pprev = sk->pprev; - *sk->pprev = sk->next; - sk->pprev = NULL; + if (sk->sk_pprev) { + if (sk->sk_next) + sk->sk_next->sk_pprev = sk->sk_pprev; + *sk->sk_pprev = sk->sk_next; + sk->sk_pprev = NULL; inet_sk(sk)->num = 0; - sock_prot_dec_use(sk->prot); + sock_prot_dec_use(sk->sk_prot); __sock_put(sk); } write_unlock_bh(&udp_hash_lock); @@ -232,11 +232,12 @@ unsigned short hnum = ntohs(dport); int badness = -1; - for(sk = udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]; sk != NULL; sk = sk->next) { + for (sk = udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]; sk; + sk = sk->sk_next) { struct inet_opt *inet = inet_sk(sk); if (inet->num == hnum && !ipv6_only_sock(sk)) { - int score = (sk->family == PF_INET ? 1 : 0); + int score = (sk->sk_family == PF_INET ? 1 : 0); if (inet->rcv_saddr) { if (inet->rcv_saddr != daddr) continue; @@ -252,8 +253,8 @@ continue; score+=2; } - if(sk->bound_dev_if) { - if(sk->bound_dev_if != dif) + if (sk->sk_bound_dev_if) { + if (sk->sk_bound_dev_if != dif) continue; score+=2; } @@ -288,7 +289,8 @@ { struct sock *s = sk; unsigned short hnum = ntohs(loc_port); - for(; s; s = s->next) { + + for (; s; s = s->sk_next) { struct inet_opt *inet = inet_sk(s); if (inet->num != hnum || @@ -296,7 +298,7 @@ (inet->dport != rmt_port && inet->dport) || (inet->rcv_saddr && inet->rcv_saddr != loc_addr) || ipv6_only_sock(s) || - (s->bound_dev_if && s->bound_dev_if != dif)) + (s->sk_bound_dev_if && s->sk_bound_dev_if != dif)) continue; if (!ip_mc_sf_allow(sk, loc_addr, rmt_addr, dif)) continue; @@ -370,13 +372,13 @@ * 4.1.3.3. */ if (!inet->recverr) { - if (!harderr || sk->state != TCP_ESTABLISHED) + if (!harderr || sk->sk_state != TCP_ESTABLISHED) goto out; } else { ip_icmp_error(sk, skb, err, uh->dest, info, (u8*)(uh+1)); } - sk->err = err; - sk->error_report(sk); + sk->sk_err = err; + sk->sk_error_report(sk); out: sock_put(sk); } @@ -404,7 +406,7 @@ int err = 0; /* Grab the skbuff where UDP header space exists. */ - if ((skb = skb_peek(&sk->write_queue)) == NULL) + if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) goto out; /* @@ -416,12 +418,12 @@ uh->len = htons(up->len); uh->check = 0; - if (sk->no_check == UDP_CSUM_NOXMIT) { + if (sk->sk_no_check == UDP_CSUM_NOXMIT) { skb->ip_summed = CHECKSUM_NONE; goto send; } - if (skb_queue_len(&sk->write_queue) == 1) { + if (skb_queue_len(&sk->sk_write_queue) == 1) { /* * Only one fragment on the socket. */ @@ -454,7 +456,7 @@ sizeof(struct udphdr), skb->csum); } - skb_queue_walk(&sk->write_queue, skb) { + skb_queue_walk(&sk->sk_write_queue, skb) { csum = csum_add(csum, skb->csum); } uh->check = csum_tcpudp_magic(up->saddr, up->daddr, @@ -544,7 +546,7 @@ if (dport == 0) return -EINVAL; } else { - if (sk->state != TCP_ESTABLISHED) + if (sk->sk_state != TCP_ESTABLISHED) return -ENOTCONN; daddr = inet->daddr; dport = inet->dport; @@ -555,7 +557,7 @@ } ipc.addr = inet->saddr; - ipc.oif = sk->bound_dev_if; + ipc.oif = sk->sk_bound_dev_if; if (msg->msg_controllen) { err = ip_cmsg_send(msg, &ipc); if (err) @@ -577,7 +579,7 @@ connected = 0; } tos = RT_TOS(inet->tos); - if (sk->localroute || (msg->msg_flags&MSG_DONTROUTE) || + if (sk->sk_localroute || (msg->msg_flags & MSG_DONTROUTE) || (ipc.opt && ipc.opt->is_strictroute)) { tos |= RTO_ONLINK; connected = 0; @@ -609,8 +611,8 @@ goto out; err = -EACCES; - if (rt->rt_flags&RTCF_BROADCAST && - !test_bit(SOCK_BROADCAST, &sk->flags)) + if ((rt->rt_flags & RTCF_BROADCAST) && + !sock_flag(sk, SOCK_BROADCAST)) goto out; if (connected) sk_dst_set(sk, dst_clone(&rt->u.dst)); @@ -701,7 +703,8 @@ ret = ip_append_page(sk, page, offset, size, flags); if (ret == -EOPNOTSUPP) { release_sock(sk); - return sock_no_sendpage(sk->socket, page, offset, size, flags); + return sock_no_sendpage(sk->sk_socket, page, offset, + size, flags); } if (ret < 0) { udp_flush_pending_frames(sk); @@ -728,7 +731,7 @@ { case SIOCOUTQ: { - int amount = atomic_read(&sk->wmem_alloc); + int amount = atomic_read(&sk->sk_wmem_alloc); return put_user(amount, (int *)arg); } @@ -738,8 +741,8 @@ unsigned long amount; amount = 0; - spin_lock_irq(&sk->receive_queue.lock); - skb = skb_peek(&sk->receive_queue); + spin_lock_irq(&sk->sk_receive_queue.lock); + skb = skb_peek(&sk->sk_receive_queue); if (skb != NULL) { /* * We will only return the amount @@ -748,7 +751,7 @@ */ amount = skb->len - sizeof(struct udphdr); } - spin_unlock_irq(&sk->receive_queue.lock); + spin_unlock_irq(&sk->sk_receive_queue.lock); return put_user(amount, (int *)arg); } @@ -844,12 +847,12 @@ /* Clear queue. */ if (flags&MSG_PEEK) { int clear = 0; - spin_lock_irq(&sk->receive_queue.lock); - if (skb == skb_peek(&sk->receive_queue)) { - __skb_unlink(skb, &sk->receive_queue); + spin_lock_irq(&sk->sk_receive_queue.lock); + if (skb == skb_peek(&sk->sk_receive_queue)) { + __skb_unlink(skb, &sk->sk_receive_queue); clear = 1; } - spin_unlock_irq(&sk->receive_queue.lock); + spin_unlock_irq(&sk->sk_receive_queue.lock); if (clear) kfree_skb(skb); } @@ -877,7 +880,7 @@ sk_dst_reset(sk); - oif = sk->bound_dev_if; + oif = sk->sk_bound_dev_if; saddr = inet->saddr; if (MULTICAST(usin->sin_addr.s_addr)) { if (!oif) @@ -891,8 +894,7 @@ inet->sport, usin->sin_port, sk); if (err) return err; - if ((rt->rt_flags&RTCF_BROADCAST) && - !test_bit(SOCK_BROADCAST, &sk->flags)) { + if ((rt->rt_flags & RTCF_BROADCAST) && !sock_flag(sk, SOCK_BROADCAST)) { ip_rt_put(rt); return -EACCES; } @@ -902,7 +904,7 @@ inet->rcv_saddr = rt->rt_src; inet->daddr = rt->rt_dst; inet->dport = usin->sin_port; - sk->state = TCP_ESTABLISHED; + sk->sk_state = TCP_ESTABLISHED; inet->id = jiffies; sk_dst_set(sk, &rt->u.dst); @@ -916,15 +918,15 @@ * 1003.1g - break association. */ - sk->state = TCP_CLOSE; + sk->sk_state = TCP_CLOSE; inet->daddr = 0; inet->dport = 0; - sk->bound_dev_if = 0; - if (!(sk->userlocks & SOCK_BINDADDR_LOCK)) + sk->sk_bound_dev_if = 0; + if (!(sk->sk_userlocks & SOCK_BINDADDR_LOCK)) inet_reset_saddr(sk); - if (!(sk->userlocks&SOCK_BINDPORT_LOCK)) { - sk->prot->unhash(sk); + if (!(sk->sk_userlocks & SOCK_BINDPORT_LOCK)) { + sk->sk_prot->unhash(sk); inet->sport = 0; } sk_dst_reset(sk); @@ -1055,7 +1057,7 @@ /* FALLTHROUGH -- it's a UDP Packet */ } - if (sk->filter && skb->ip_summed != CHECKSUM_UNNECESSARY) { + if (sk->sk_filter && skb->ip_summed != CHECKSUM_UNNECESSARY) { if (__udp_checksum_complete(skb)) { UDP_INC_STATS_BH(UdpInErrors); kfree_skb(skb); @@ -1095,7 +1097,7 @@ do { struct sk_buff *skb1 = skb; - sknext = udp_v4_mcast_next(sk->next, uh->dest, daddr, + sknext = udp_v4_mcast_next(sk->sk_next, uh->dest, daddr, uh->source, saddr, dif); if(sknext) skb1 = skb_clone(skb, GFP_ATOMIC); @@ -1357,8 +1359,9 @@ struct udp_iter_state *state = seq->private; for (; state->bucket < UDP_HTABLE_SIZE; ++state->bucket) - for (i = 0, sk = udp_hash[state->bucket]; sk; ++i, sk = sk->next) { - if (sk->family != state->family) + for (i = 0, sk = udp_hash[state->bucket]; sk; + ++i, sk = sk->sk_next) { + if (sk->sk_family != state->family) continue; if (l--) continue; @@ -1388,12 +1391,11 @@ state = seq->private; sk = v; - sk = sk->next; + sk = sk->sk_next; - for (; sk; sk = sk->next) { - if (sk->family == state->family) + for (; sk; sk = sk->sk_next) + if (sk->sk_family == state->family) goto out; - } if (++state->bucket >= UDP_HTABLE_SIZE) goto out; @@ -1481,10 +1483,11 @@ sprintf(tmpbuf, "%4d: %08X:%04X %08X:%04X" " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p", - bucket, src, srcp, dest, destp, sp->state, - atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc), + bucket, src, srcp, dest, destp, sp->sk_state, + atomic_read(&sp->sk_wmem_alloc), + atomic_read(&sp->sk_rmem_alloc), 0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp), - atomic_read(&sp->refcnt), sp); + atomic_read(&sp->sk_refcnt), sp); } static int udp4_seq_show(struct seq_file *seq, void *v) diff -Nru a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c --- a/net/ipv4/xfrm4_input.c Mon Jun 9 23:16:07 2003 +++ b/net/ipv4/xfrm4_input.c Mon Jun 9 23:16:07 2003 @@ -9,6 +9,7 @@ * */ +#include <linux/slab.h> #include <net/ip.h> #include <net/xfrm.h> diff -Nru a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c --- a/net/ipv4/xfrm4_tunnel.c Mon Jun 9 23:16:07 2003 +++ b/net/ipv4/xfrm4_tunnel.c Mon Jun 9 23:16:07 2003 @@ -215,6 +215,7 @@ static struct xfrm_type ipip_type = { .description = "IPIP", + .owner = THIS_MODULE, .proto = IPPROTO_IPIP, .init_state = ipip_init_state, .destructor = ipip_destroy, @@ -229,7 +230,6 @@ static int __init ipip_init(void) { - ipip_type.owner = THIS_MODULE; if (xfrm_register_type(&ipip_type, AF_INET) < 0) { printk(KERN_INFO "ipip init: can't add xfrm type\n"); return -EAGAIN; diff -Nru a/net/ipv6/Kconfig b/net/ipv6/Kconfig --- a/net/ipv6/Kconfig Mon Jun 9 23:16:12 2003 +++ b/net/ipv6/Kconfig Mon Jun 9 23:16:12 2003 @@ -4,6 +4,8 @@ config IPV6_PRIVACY bool "IPv6: Privacy Extensions (RFC 3041) support" depends on IPV6 + select CRYPTO + select CRYPTO_MD5 ---help--- Privacy Extensions for Stateless Address Autoconfiguration in IPv6 support. With this option, additional periodically-alter @@ -20,6 +22,10 @@ config INET6_AH tristate "IPv6: AH transformation" depends on IPV6 + select CRYPTO + select CRYPTO_HMAC + select CRYPTO_MD5 + select CRYPTO_SHA1 ---help--- Support for IPsec AH. @@ -28,6 +34,11 @@ config INET6_ESP tristate "IPv6: ESP transformation" depends on IPV6 + select CRYPTO + select CRYPTO_HMAC + select CRYPTO_MD5 + select CRYPTO_SHA1 + select CRYPTO_DES ---help--- Support for IPsec ESP. @@ -36,10 +47,20 @@ config INET6_IPCOMP tristate "IPv6: IPComp transformation" depends on IPV6 + select CRYPTO + select CRYPTO_DEFLATE ---help--- Support for IP Paylod Compression (RFC3173), typically needed for IPsec. If unsure, say Y. + +config IPV6_TUNNEL + tristate "IPv6: IPv6-in-IPv6 tunnel" + depends on IPV6 + ---help--- + Support for IPv6-in-IPv6 tunnels described in RFC 2473. + + If unsure, say N. source "net/ipv6/netfilter/Kconfig" diff -Nru a/net/ipv6/Makefile b/net/ipv6/Makefile --- a/net/ipv6/Makefile Mon Jun 9 23:16:16 2003 +++ b/net/ipv6/Makefile Mon Jun 9 23:16:16 2003 @@ -15,3 +15,5 @@ obj-$(CONFIG_INET6_ESP) += esp6.o obj-$(CONFIG_INET6_IPCOMP) += ipcomp6.o obj-$(CONFIG_NETFILTER) += netfilter/ + +obj-$(CONFIG_IPV6_TUNNEL) += ip6_tunnel.o diff -Nru a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c --- a/net/ipv6/addrconf.c Mon Jun 9 23:16:18 2003 +++ b/net/ipv6/addrconf.c Mon Jun 9 23:16:18 2003 @@ -19,7 +19,7 @@ * * Janos Farkas : delete timer on ifdown * <chexum@bankinf.banki.hu> - * Andi Kleen : kill doube kfree on module + * Andi Kleen : kill double kfree on module * unload. * Maciej W. Rozycki : FDDI support * sekiya@USAGI : Don't send too many RS @@ -33,6 +33,8 @@ * Yuji SEKIYA @USAGI : Don't assign a same IPv6 * address on a same interface. * YOSHIFUJI Hideaki @USAGI : ARCnet support + * YOSHIFUJI Hideaki @USAGI : convert /proc/net/if_inet6 to + * seq_file. */ #include <linux/config.h> @@ -76,6 +78,9 @@ #include <asm/uaccess.h> +#include <linux/proc_fs.h> +#include <linux/seq_file.h> + #define IPV6_MAX_ADDRESSES 16 /* Set to 3 to get tracing... */ @@ -338,10 +343,16 @@ "%s(): cannot create /proc/net/dev_snmp6/%s\n", __FUNCTION__, dev->name)); neigh_parms_release(&nd_tbl, ndev->nd_parms); + ndev->dead = 1; in6_dev_finish_destroy(ndev); return NULL; } + /* One reference from device. We must do this before + * we invoke __ipv6_regen_rndid(). + */ + in6_dev_hold(ndev); + #ifdef CONFIG_IPV6_PRIVACY get_random_bytes(ndev->rndid, sizeof(ndev->rndid)); get_random_bytes(ndev->entropy, sizeof(ndev->entropy)); @@ -362,8 +373,6 @@ write_lock_bh(&addrconf_lock); dev->ip6_ptr = ndev; - /* One reference from device */ - in6_dev_hold(ndev); write_unlock_bh(&addrconf_lock); ipv6_mc_init_dev(ndev); @@ -391,38 +400,6 @@ return idev; } -void ipv6_addr_prefix(struct in6_addr *prefix, - struct in6_addr *addr, int prefix_len) -{ - unsigned long mask; - int ncopy, nbits; - - memset(prefix, 0, sizeof(*prefix)); - - if (prefix_len <= 0) - return; - if (prefix_len > 128) - prefix_len = 128; - - ncopy = prefix_len / 32; - switch (ncopy) { - case 4: prefix->s6_addr32[3] = addr->s6_addr32[3]; - case 3: prefix->s6_addr32[2] = addr->s6_addr32[2]; - case 2: prefix->s6_addr32[1] = addr->s6_addr32[1]; - case 1: prefix->s6_addr32[0] = addr->s6_addr32[0]; - case 0: break; - } - nbits = prefix_len % 32; - if (nbits == 0) - return; - - mask = ~((1 << (32 - nbits)) - 1); - mask = htonl(mask); - - prefix->s6_addr32[ncopy] = addr->s6_addr32[ncopy] & mask; -} - - static void dev_forward_change(struct inet6_dev *idev) { struct net_device *dev; @@ -1248,7 +1225,7 @@ rtmsg.rtmsg_type = RTMSG_NEWROUTE; rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF; - /* prefix length - 96 bytes "::d.d.d.d" */ + /* prefix length - 96 bits "::d.d.d.d" */ rtmsg.rtmsg_dst_len = 96; rtmsg.rtmsg_flags = RTF_UP|RTF_NONEXTHOP; rtmsg.rtmsg_ifindex = dev->ifindex; @@ -2090,57 +2067,141 @@ } #ifdef CONFIG_PROC_FS -static int iface_proc_info(char *buffer, char **start, off_t offset, - int length) +struct if6_iter_state { + int bucket; +}; + +static inline struct inet6_ifaddr *if6_get_bucket(struct seq_file *seq, loff_t *pos) { - struct inet6_ifaddr *ifp; int i; - int len = 0; - off_t pos=0; - off_t begin=0; + struct inet6_ifaddr *ifa = NULL; + loff_t l = *pos; + struct if6_iter_state *state = seq->private; + + for (; state->bucket < IN6_ADDR_HSIZE; ++state->bucket) + for (i = 0, ifa = inet6_addr_lst[state->bucket]; ifa; ++i, ifa=ifa->lst_next) { + if (l--) + continue; + *pos = i; + goto out; + } +out: + return ifa; +} - for (i=0; i < IN6_ADDR_HSIZE; i++) { - read_lock_bh(&addrconf_hash_lock); - for (ifp=inet6_addr_lst[i]; ifp; ifp=ifp->lst_next) { - int j; +static void *if6_seq_start(struct seq_file *seq, loff_t *pos) +{ + read_lock_bh(&addrconf_hash_lock); + return *pos ? if6_get_bucket(seq, pos) : (void *)1; +} - for (j=0; j<16; j++) { - sprintf(buffer + len, "%02x", - ifp->addr.s6_addr[j]); - len += 2; - } +static void *if6_seq_next(struct seq_file *seq, void *v, loff_t *pos) +{ + struct inet6_ifaddr *ifa; + struct if6_iter_state *state; - len += sprintf(buffer + len, - " %02x %02x %02x %02x %8s\n", - ifp->idev->dev->ifindex, - ifp->prefix_len, - ifp->scope, - ifp->flags, - ifp->idev->dev->name); - pos=begin+len; - if(pos<offset) { - len=0; - begin=pos; - } - if(pos>offset+length) { - read_unlock_bh(&addrconf_hash_lock); - goto done; - } - } - read_unlock_bh(&addrconf_hash_lock); + if (v == (void *)1) { + ifa = if6_get_bucket(seq, pos); + goto out; } -done: + state = seq->private; + + ifa = v; + ifa = ifa->lst_next; + if (ifa) + goto out; - *start=buffer+(offset-begin); - len-=(offset-begin); - if(len>length) - len=length; - if(len<0) - len=0; - return len; + if (++state->bucket >= IN6_ADDR_HSIZE) + goto out; + + *pos = 0; + ifa = if6_get_bucket(seq, pos); +out: + ++*pos; + return ifa; } +static inline void if6_iface_seq_show(struct seq_file *seq, struct inet6_ifaddr *ifp) +{ + seq_printf(seq, + "%04x%04x%04x%04x%04x%04x%04x%04x %02x %02x %02x %02x %8s\n", + NIP6(ifp->addr), + ifp->idev->dev->ifindex, + ifp->prefix_len, + ifp->scope, + ifp->flags, + ifp->idev->dev->name); +} + +static int if6_seq_show(struct seq_file *seq, void *v) +{ + if (v == (void *)1) + return 0; + else + if6_iface_seq_show(seq, v); + return 0; +} + +static void if6_seq_stop(struct seq_file *seq, void *v) +{ + read_unlock_bh(&addrconf_hash_lock); +} + +static struct seq_operations if6_seq_ops = { + .start = if6_seq_start, + .next = if6_seq_next, + .show = if6_seq_show, + .stop = if6_seq_stop, +}; + +static int if6_seq_open(struct inode *inode, struct file *file) +{ + struct seq_file *seq; + int rc = -ENOMEM; + struct if6_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL); + + if (!s) + goto out; + memset(s, 0, sizeof(*s)); + + rc = seq_open(file, &if6_seq_ops); + if (rc) + goto out_kfree; + + seq = file->private_data; + seq->private = s; +out: + return rc; +out_kfree: + kfree(s); + goto out; +} + +static struct file_operations if6_fops = { + .owner = THIS_MODULE, + .open = if6_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_private, +}; + +int __init if6_proc_init(void) +{ + struct proc_dir_entry *p; + int rc = 0; + + p = create_proc_entry("if_inet6", S_IRUGO, proc_net); + if (p) + p->proc_fops = &if6_fops; + else + rc = -ENOMEM; + return rc; +} +void if6_proc_exit(void) +{ + proc_net_remove("if_inet6"); +} #endif /* CONFIG_PROC_FS */ /* @@ -2727,10 +2788,6 @@ rtnl_unlock(); #endif -#ifdef CONFIG_PROC_FS - proc_net_create("if_inet6", 0, iface_proc_info); -#endif - addrconf_verify(0); rtnetlink_links[PF_INET6] = inet6_rtnetlink_table; #ifdef CONFIG_SYSCTL diff -Nru a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c --- a/net/ipv6/af_inet6.c Mon Jun 9 23:16:13 2003 +++ b/net/ipv6/af_inet6.c Mon Jun 9 23:16:13 2003 @@ -57,6 +57,9 @@ #include <net/transp_v6.h> #include <net/ip6_route.h> #include <net/addrconf.h> +#if CONFIG_IPV6_TUNNEL +#include <net/ip6_tunnel.h> +#endif #include <asm/uaccess.h> #include <asm/system.h> @@ -75,18 +78,16 @@ #ifdef CONFIG_PROC_FS extern int raw6_proc_init(void); -extern int raw6_proc_exit(void); - +extern void raw6_proc_exit(void); extern int tcp6_proc_init(void); extern void tcp6_proc_exit(void); - extern int udp6_proc_init(void); extern void udp6_proc_exit(void); - extern int ipv6_misc_proc_init(void); -extern int ipv6_misc_proc_exit(void); - +extern void ipv6_misc_proc_exit(void); extern int anycast6_get_info(char *, char **, off_t, int); +extern int if6_proc_init(void); +extern void if6_proc_exit(void); #endif #ifdef CONFIG_SYSCTL @@ -146,9 +147,9 @@ { struct ipv6_pinfo *rc = (&((struct tcp6_sock *)sk)->inet6); - if (sk->protocol == IPPROTO_UDP) + if (sk->sk_protocol == IPPROTO_UDP) rc = (&((struct udp6_sock *)sk)->inet6); - else if (sk->protocol == IPPROTO_RAW) + else if (sk->sk_protocol == IPPROTO_RAW) rc = (&((struct raw6_sock *)sk)->inet6); return rc; } @@ -200,10 +201,10 @@ sock_init_data(sock, sk); sk_set_owner(sk, THIS_MODULE); - sk->prot = answer->prot; - sk->no_check = answer->no_check; + sk->sk_prot = answer->prot; + sk->sk_no_check = answer->no_check; if (INET_PROTOSW_REUSE & answer->flags) - sk->reuse = 1; + sk->sk_reuse = 1; rcu_read_unlock(); inet = inet_sk(sk); @@ -214,12 +215,12 @@ inet->hdrincl = 1; } - sk->destruct = inet6_sock_destruct; - sk->zapped = 0; - sk->family = PF_INET6; - sk->protocol = protocol; + sk->sk_destruct = inet6_sock_destruct; + sk->sk_zapped = 0; + sk->sk_family = PF_INET6; + sk->sk_protocol = protocol; - sk->backlog_rcv = answer->prot->backlog_rcv; + sk->sk_backlog_rcv = answer->prot->backlog_rcv; tcp6sk = (struct tcp6_sock *)sk; tcp6sk->pinet6 = np = inet6_sk_generic(sk); @@ -255,10 +256,10 @@ * creation time automatically shares. */ inet->sport = ntohs(inet->num); - sk->prot->hash(sk); + sk->sk_prot->hash(sk); } - if (sk->prot->init) { - int err = sk->prot->init(sk); + if (sk->sk_prot->init) { + int err = sk->sk_prot->init(sk); if (err != 0) { inet_sock_release(sk); return err; @@ -295,8 +296,8 @@ int addr_type = 0; /* If the socket has its own bind function then use it. */ - if(sk->prot->bind) - return sk->prot->bind(sk, uaddr, addr_len); + if (sk->sk_prot->bind) + return sk->sk_prot->bind(sk, uaddr, addr_len); if (addr_len < SIN6_LEN_RFC2133) return -EINVAL; @@ -312,7 +313,7 @@ } else { if (addr_type != IPV6_ADDR_ANY) { /* ipv4 addr of the socket is invalid. Only the - * unpecified and mapped address have a v4 equivalent. + * unspecified and mapped address have a v4 equivalent. */ v4addr = LOOPBACK4_IPV6; if (!(addr_type & IPV6_ADDR_MULTICAST)) { @@ -329,7 +330,7 @@ lock_sock(sk); /* Check these errors (active socket, double bind). */ - if (sk->state != TCP_CLOSE || inet->num) { + if (sk->sk_state != TCP_CLOSE || inet->num) { release_sock(sk); return -EINVAL; } @@ -340,11 +341,11 @@ /* Override any existing binding, if another one * is supplied by user. */ - sk->bound_dev_if = addr->sin6_scope_id; + sk->sk_bound_dev_if = addr->sin6_scope_id; } /* Binding to link-local address requires an interface */ - if (sk->bound_dev_if == 0) { + if (!sk->sk_bound_dev_if) { release_sock(sk); return -EINVAL; } @@ -359,16 +360,16 @@ ipv6_addr_copy(&np->saddr, &addr->sin6_addr); /* Make sure we are allowed to bind here. */ - if (sk->prot->get_port(sk, snum) != 0) { + if (sk->sk_prot->get_port(sk, snum)) { inet_reset_saddr(sk); release_sock(sk); return -EADDRINUSE; } if (addr_type != IPV6_ADDR_ANY) - sk->userlocks |= SOCK_BINDADDR_LOCK; + sk->sk_userlocks |= SOCK_BINDADDR_LOCK; if (snum) - sk->userlocks |= SOCK_BINDPORT_LOCK; + sk->sk_userlocks |= SOCK_BINDPORT_LOCK; inet->sport = ntohs(inet->num); inet->dport = 0; inet->daddr = 0; @@ -439,7 +440,8 @@ if (peer) { if (!inet->dport) return -ENOTCONN; - if (((1<<sk->state)&(TCPF_CLOSE|TCPF_SYN_SENT)) && peer == 1) + if (((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_SYN_SENT)) && + peer == 1) return -ENOTCONN; sin->sin6_port = inet->dport; ipv6_addr_copy(&sin->sin6_addr, &np->daddr); @@ -454,7 +456,7 @@ sin->sin6_port = inet->sport; } if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL) - sin->sin6_scope_id = sk->bound_dev_if; + sin->sin6_scope_id = sk->sk_bound_dev_if; *uaddr_len = sizeof(*sin); return(0); } @@ -467,9 +469,9 @@ switch(cmd) { case SIOCGSTAMP: - if(sk->stamp.tv_sec==0) + if (!sk->sk_stamp.tv_sec) return -ENOENT; - err = copy_to_user((void *)arg, &sk->stamp, + err = copy_to_user((void *)arg, &sk->sk_stamp, sizeof(struct timeval)); if (err) return -EFAULT; @@ -487,7 +489,8 @@ case SIOCSIFDSTADDR: return addrconf_set_dstaddr((void *) arg); default: - if(sk->prot->ioctl==0 || (err=sk->prot->ioctl(sk, cmd, arg))==-ENOIOCTLCMD) + if (!sk->sk_prot->ioctl || + (err = sk->sk_prot->ioctl(sk, cmd, arg)) == -ENOIOCTLCMD) return(dev_ioctl(cmd,(void *) arg)); return err; } @@ -642,32 +645,23 @@ } int -snmp6_mib_init(void *ptr[2], size_t mibsize) +snmp6_mib_init(void *ptr[2], size_t mibsize, size_t mibalign) { - int i; - if (ptr == NULL) return -EINVAL; - ptr[0] = kmalloc_percpu(mibsize, GFP_KERNEL); + ptr[0] = __alloc_percpu(mibsize, mibalign); if (!ptr[0]) goto err0; - ptr[1] = kmalloc_percpu(mibsize, GFP_KERNEL); + ptr[1] = __alloc_percpu(mibsize, mibalign); if (!ptr[1]) goto err1; - /* Zero percpu version of the mibs */ - for (i = 0; i < NR_CPUS; i++) { - if (cpu_possible(i)) { - memset(per_cpu_ptr(ptr[0], i), 0, mibsize); - memset(per_cpu_ptr(ptr[1], i), 0, mibsize); - } - } return 0; err1: - kfree_percpu(ptr[0]); + free_percpu(ptr[0]); ptr[0] = NULL; err0: return -ENOMEM; @@ -678,18 +672,21 @@ { if (ptr == NULL) return; - kfree_percpu(ptr[0]); - kfree_percpu(ptr[1]); + free_percpu(ptr[0]); + free_percpu(ptr[1]); ptr[0] = ptr[1] = NULL; } static int __init init_ipv6_mibs(void) { - if (snmp6_mib_init((void **)ipv6_statistics, sizeof (struct ipv6_mib)) < 0) + if (snmp6_mib_init((void **)ipv6_statistics, sizeof (struct ipv6_mib), + __alignof__(struct ipv6_mib)) < 0) goto err_ip_mib; - if (snmp6_mib_init((void **)icmpv6_statistics, sizeof (struct icmpv6_mib)) < 0) + if (snmp6_mib_init((void **)icmpv6_statistics, sizeof (struct icmpv6_mib), + __alignof__(struct ipv6_mib)) < 0) goto err_icmp_mib; - if (snmp6_mib_init((void **)udp_stats_in6, sizeof (struct udp_mib)) < 0) + if (snmp6_mib_init((void **)udp_stats_in6, sizeof (struct udp_mib), + __alignof__(struct ipv6_mib)) < 0) goto err_udp_mib; return 0; @@ -782,6 +779,11 @@ err = ndisc_init(&inet6_family_ops); if (err) goto ndisc_fail; +#ifdef CONFIG_IPV6_TUNNEL + err = ip6_tunnel_init(); + if (err) + goto ip6_tunnel_fail; +#endif err = igmp6_init(&inet6_family_ops); if (err) goto igmp_fail; @@ -799,6 +801,8 @@ if (!proc_net_create("anycast6", 0, anycast6_get_info)) goto proc_anycast6_fail; + if (if6_proc_init()) + goto proc_if6_fail; #endif ipv6_netdev_notif_init(); ipv6_packet_init(); @@ -820,6 +824,8 @@ return 0; #ifdef CONFIG_PROC_FS +proc_if6_fail: + proc_net_remove("anycast6"); proc_anycast6_fail: ipv6_misc_proc_exit(); proc_misc6_fail: @@ -832,6 +838,10 @@ igmp6_cleanup(); #endif igmp_fail: +#ifdef CONFIG_IPV6_TUNNEL + ip6_tunnel_cleanup(); +ip6_tunnel_fail: +#endif ndisc_cleanup(); ndisc_fail: icmpv6_cleanup(); @@ -852,11 +862,12 @@ /* First of all disallow new sockets creation. */ sock_unregister(PF_INET6); #ifdef CONFIG_PROC_FS - raw6_proc_exit(); - proc_net_remove("tcp6"); - proc_net_remove("udp6"); - ipv6_misc_proc_exit(); - proc_net_remove("anycast6"); + if6_proc_exit(); + proc_net_remove("anycast6"); + ipv6_misc_proc_exit(); + udp6_proc_exit(); + tcp6_proc_exit(); + raw6_proc_exit(); #endif /* Cleanup code parts. */ sit_cleanup(); @@ -866,6 +877,9 @@ ip6_route_cleanup(); ipv6_packet_cleanup(); igmp6_cleanup(); +#ifdef CONFIG_IPV6_TUNNEL + ip6_tunnel_cleanup(); +#endif ndisc_cleanup(); icmpv6_cleanup(); #ifdef CONFIG_SYSCTL diff -Nru a/net/ipv6/datagram.c b/net/ipv6/datagram.c --- a/net/ipv6/datagram.c Mon Jun 9 23:16:07 2003 +++ b/net/ipv6/datagram.c Mon Jun 9 23:16:07 2003 @@ -117,7 +117,7 @@ int copied; err = -EAGAIN; - skb = skb_dequeue(&sk->error_queue); + skb = skb_dequeue(&sk->sk_error_queue); if (skb == NULL) goto out; @@ -190,14 +190,14 @@ err = copied; /* Reset and regenerate socket error */ - spin_lock_irq(&sk->error_queue.lock); - sk->err = 0; - if ((skb2 = skb_peek(&sk->error_queue)) != NULL) { - sk->err = SKB_EXT_ERR(skb2)->ee.ee_errno; - spin_unlock_irq(&sk->error_queue.lock); - sk->error_report(sk); + spin_lock_irq(&sk->sk_error_queue.lock); + sk->sk_err = 0; + if ((skb2 = skb_peek(&sk->sk_error_queue)) != NULL) { + sk->sk_err = SKB_EXT_ERR(skb2)->ee.ee_errno; + spin_unlock_irq(&sk->sk_error_queue.lock); + sk->sk_error_report(sk); } else { - spin_unlock_irq(&sk->error_queue.lock); + spin_unlock_irq(&sk->sk_error_queue.lock); } out_free_skb: diff -Nru a/net/ipv6/esp6.c b/net/ipv6/esp6.c --- a/net/ipv6/esp6.c Mon Jun 9 23:16:14 2003 +++ b/net/ipv6/esp6.c Mon Jun 9 23:16:14 2003 @@ -39,57 +39,6 @@ #define MAX_SG_ONSTACK 4 -/* BUGS: - * - we assume replay seqno is always present. - */ - -/* Move to common area: it is shared with AH. */ -/* Common with AH after some work on arguments. */ - -static int get_offset(u8 *packet, u32 packet_len, u8 *nexthdr, struct ipv6_opt_hdr **prevhdr) -{ - u16 offset = sizeof(struct ipv6hdr); - struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr*)(packet + offset); - u8 nextnexthdr; - - *nexthdr = ((struct ipv6hdr*)packet)->nexthdr; - - while (offset + 1 < packet_len) { - - switch (*nexthdr) { - - case NEXTHDR_HOP: - case NEXTHDR_ROUTING: - offset += ipv6_optlen(exthdr); - *nexthdr = exthdr->nexthdr; - *prevhdr = exthdr; - exthdr = (struct ipv6_opt_hdr*)(packet + offset); - break; - - case NEXTHDR_DEST: - nextnexthdr = - ((struct ipv6_opt_hdr*)(packet + offset + ipv6_optlen(exthdr)))->nexthdr; - /* XXX We know the option is inner dest opt - with next next header check. */ - if (nextnexthdr != NEXTHDR_HOP && - nextnexthdr != NEXTHDR_ROUTING && - nextnexthdr != NEXTHDR_DEST) { - return offset; - } - offset += ipv6_optlen(exthdr); - *nexthdr = exthdr->nexthdr; - *prevhdr = exthdr; - exthdr = (struct ipv6_opt_hdr*)(packet + offset); - break; - - default : - return offset; - } - } - - return offset; -} - int esp6_output(struct sk_buff *skb) { int err; @@ -101,12 +50,12 @@ struct crypto_tfm *tfm; struct esp_data *esp; struct sk_buff *trailer; - struct ipv6_opt_hdr *prevhdr = NULL; int blksize; int clen; int alen; int nfrags; - u8 nexthdr; + u8 *prevhdr; + u8 nexthdr = 0; /* First, if the skb is not checksummed, complete checksum. */ if (skb->ip_summed == CHECKSUM_HW && skb_checksum_help(skb) == NULL) { @@ -123,7 +72,9 @@ /* Strip IP header in transport mode. Save it. */ if (!x->props.mode) { - hdr_len = get_offset(skb->nh.raw, skb->len, &nexthdr, &prevhdr); + hdr_len = ip6_find_1stfragopt(skb, &prevhdr); + nexthdr = *prevhdr; + *prevhdr = IPPROTO_ESP; iph = kmalloc(hdr_len, GFP_ATOMIC); if (!iph) { err = -ENOMEM; @@ -178,18 +129,12 @@ ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr); } else { - /* XXX exthdr */ esph = (struct ipv6_esp_hdr*)skb_push(skb, x->props.header_len); skb->h.raw = (unsigned char*)esph; top_iph = (struct ipv6hdr*)skb_push(skb, hdr_len); memcpy(top_iph, iph, hdr_len); kfree(iph); top_iph->payload_len = htons(skb->len + alen - sizeof(struct ipv6hdr)); - if (prevhdr) { - prevhdr->nexthdr = IPPROTO_ESP; - } else { - top_iph->nexthdr = IPPROTO_ESP; - } *(u8*)(trailer->tail - 1) = nexthdr; } @@ -302,6 +247,7 @@ struct scatterlist sgbuf[nfrags>MAX_SG_ONSTACK ? 0 : nfrags]; struct scatterlist *sg = sgbuf; u8 padlen; + u8 *prevhdr; if (unlikely(nfrags > MAX_SG_ONSTACK)) { sg = kmalloc(sizeof(struct scatterlist)*nfrags, GFP_ATOMIC); @@ -325,11 +271,13 @@ } /* ... check padding bits here. Silly. :-) */ - ret_nexthdr = ((struct ipv6hdr*)tmp_hdr)->nexthdr = nexthdr[1]; pskb_trim(skb, skb->len - alen - padlen - 2); skb->h.raw = skb_pull(skb, sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen); skb->nh.raw += sizeof(struct ipv6_esp_hdr) + esp->conf.ivlen; memcpy(skb->nh.raw, tmp_hdr, hdr_len); + skb->nh.ipv6h->payload_len = htons(skb->len - sizeof(struct ipv6hdr)); + ip6_find_1stfragopt(skb, &prevhdr); + ret_nexthdr = *prevhdr = nexthdr[1]; } kfree(tmp_hdr); return ret_nexthdr; diff -Nru a/net/ipv6/icmp.c b/net/ipv6/icmp.c --- a/net/ipv6/icmp.c Mon Jun 9 23:16:09 2003 +++ b/net/ipv6/icmp.c Mon Jun 9 23:16:09 2003 @@ -96,13 +96,13 @@ static __inline__ void icmpv6_xmit_lock(void) { local_bh_disable(); - if (unlikely(!spin_trylock(&icmpv6_socket->sk->lock.slock))) + if (unlikely(!spin_trylock(&icmpv6_socket->sk->sk_lock.slock))) BUG(); } static __inline__ void icmpv6_xmit_unlock(void) { - spin_unlock_bh(&icmpv6_socket->sk->lock.slock); + spin_unlock_bh(&icmpv6_socket->sk->sk_lock.slock); } /* @@ -213,14 +213,14 @@ struct icmp6hdr *icmp6h; int err = 0; - if ((skb = skb_peek(&sk->write_queue)) == NULL) + if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) goto out; icmp6h = (struct icmp6hdr*) skb->h.raw; memcpy(icmp6h, thdr, sizeof(struct icmp6hdr)); icmp6h->icmp6_cksum = 0; - if (skb_queue_len(&sk->write_queue) == 1) { + if (skb_queue_len(&sk->sk_write_queue) == 1) { skb->csum = csum_partial((char *)icmp6h, sizeof(struct icmp6hdr), skb->csum); icmp6h->icmp6_cksum = csum_ipv6_magic(&fl->fl6_src, @@ -230,7 +230,7 @@ } else { u32 tmp_csum = 0; - skb_queue_walk(&sk->write_queue, skb) { + skb_queue_walk(&sk->sk_write_queue, skb) { tmp_csum = csum_add(tmp_csum, skb->csum); } @@ -263,7 +263,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, struct net_device *dev) { - struct inet6_dev *idev; + struct inet6_dev *idev = NULL; struct ipv6hdr *hdr = skb->nh.ipv6h; struct sock *sk = icmpv6_socket->sk; struct ipv6_pinfo *np = inet6_sk(sk); @@ -384,7 +384,7 @@ hlimit, NULL, &fl, (struct rt6_info*)dst, MSG_DONTWAIT); if (err) { ip6_flush_pending_frames(sk); - goto out; + goto out_put; } err = icmpv6_push_pending_frames(sk, &fl, &tmp_hdr, len + sizeof(struct icmp6hdr)); __skb_push(skb, plen); @@ -393,6 +393,7 @@ ICMP6_INC_STATS_OFFSET_BH(idev, Icmp6OutDestUnreachs, type - ICMPV6_DEST_UNREACH); ICMP6_INC_STATS_BH(idev, Icmp6OutMsgs); +out_put: if (likely(idev != NULL)) in6_dev_put(idev); out: @@ -455,13 +456,14 @@ if (err) { ip6_flush_pending_frames(sk); - goto out; + goto out_put; } err = icmpv6_push_pending_frames(sk, &fl, &tmp_hdr, skb->len + sizeof(struct icmp6hdr)); ICMP6_INC_STATS_BH(idev, Icmp6OutEchoReplies); ICMP6_INC_STATS_BH(idev, Icmp6OutMsgs); +out_put: if (likely(idev != NULL)) in6_dev_put(idev); out: @@ -517,7 +519,7 @@ if ((sk = raw_v6_htable[hash]) != NULL) { while((sk = __raw_v6_lookup(sk, nexthdr, daddr, saddr))) { rawv6_err(sk, skb, NULL, type, code, inner_offset, info); - sk = sk->next; + sk = sk->sk_next; } } read_unlock(&raw_v6_lock); @@ -685,9 +687,9 @@ } sk = __icmpv6_socket[i]->sk; - sk->allocation = GFP_ATOMIC; - sk->sndbuf = SK_WMEM_MAX*2; - sk->prot->unhash(sk); + sk->sk_allocation = GFP_ATOMIC; + sk->sk_sndbuf = SK_WMEM_MAX * 2; + sk->sk_prot->unhash(sk); } diff -Nru a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c --- a/net/ipv6/ip6_fib.c Mon Jun 9 23:16:17 2003 +++ b/net/ipv6/ip6_fib.c Mon Jun 9 23:16:17 2003 @@ -40,7 +40,6 @@ #include <net/ip6_route.h> #define RT6_DEBUG 2 -#undef CONFIG_IPV6_SUBTREES #if RT6_DEBUG >= 3 #define RT6_TRACE(x...) printk(KERN_DEBUG x) @@ -594,8 +593,8 @@ is orphan. If it is, shoot it. */ st_failure: - if (fn && !(fn->fn_flags&RTN_RTINFO|RTN_ROOT)) - fib_repair_tree(fn); + if (fn && !(fn->fn_flags & (RTN_RTINFO|RTN_ROOT))) + fib6_repair_tree(fn); dst_free(&rt->u.dst); return err; #endif @@ -896,6 +895,7 @@ *rtp = rt->u.next; rt->rt6i_node = NULL; rt6_stats.fib_rt_entries--; + rt6_stats.fib_discarded_routes++; /* Adjust walkers */ read_lock(&fib6_walker_lock); diff -Nru a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c --- a/net/ipv6/ip6_input.c Mon Jun 9 23:16:16 2003 +++ b/net/ipv6/ip6_input.c Mon Jun 9 23:16:16 2003 @@ -145,7 +145,7 @@ nexthdr = skb->nh.ipv6h->nexthdr; nhoff = offsetof(struct ipv6hdr, nexthdr); - /* Skip hop-by-hop options, they are already parsed. */ + /* Skip hop-by-hop options, they are already parsed. */ if (nexthdr == NEXTHDR_HOP) { nhoff = sizeof(struct ipv6hdr); nexthdr = skb->h.raw[0]; diff -Nru a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c --- a/net/ipv6/ip6_output.c Mon Jun 9 23:16:06 2003 +++ b/net/ipv6/ip6_output.c Mon Jun 9 23:16:06 2003 @@ -153,7 +153,7 @@ struct ipv6hdr *iph = skb->nh.ipv6h; struct dst_entry *dst; struct flowi fl = { - .oif = skb->sk ? skb->sk->bound_dev_if : 0, + .oif = skb->sk ? skb->sk->sk_bound_dev_if : 0, .nl_u = { .ip6_u = { .daddr = iph->daddr, @@ -196,7 +196,7 @@ */ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl, - struct ipv6_txoptions *opt) + struct ipv6_txoptions *opt, int ipfragok) { struct ipv6_pinfo *np = sk ? inet6_sk(sk) : NULL; struct in6_addr *first_hop = &fl->fl6_dst; @@ -258,13 +258,14 @@ ipv6_addr_copy(&hdr->daddr, first_hop); mtu = dst_pmtu(dst); - if (skb->len <= mtu) { + if ((skb->len <= mtu) || ipfragok) { IP6_INC_STATS(Ip6OutRequests); return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_maybe_reroute); } if (net_ratelimit()) printk(KERN_DEBUG "IPv6: sending pkt_too_big to self\n"); + skb->dev = dst->dev; icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, skb->dev); kfree_skb(skb); return -EMSGSIZE; @@ -381,7 +382,7 @@ /* * Length of fragmented part on every packet but * the last must be an: - * "integer multiple of 8 octects". + * "integer multiple of 8 octets". */ frag_len = (mtu - unfrag_len) & ~0x7; @@ -457,7 +458,7 @@ struct frag_hdr *fhdr2; - skb = skb_copy(last_skb, sk->allocation); + skb = skb_copy(last_skb, sk->sk_allocation); if (skb == NULL) { IP6_INC_STATS(Ip6FragFails); @@ -587,7 +588,7 @@ if (err) { #if IP6_DEBUG >= 2 printk(KERN_DEBUG "ip6_build_xmit: " - "no availiable source address\n"); + "no available source address\n"); #endif goto out; } @@ -887,7 +888,7 @@ #endif } -int ip6_found_nexthdr(struct sk_buff *skb, u8 **nexthdr) +int ip6_find_1stfragopt(struct sk_buff *skb, u8 **nexthdr) { u16 offset = sizeof(struct ipv6hdr); struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr*)(skb->nh.ipv6h + 1); @@ -929,7 +930,7 @@ u8 *prevhdr, nexthdr = 0; dev = rt->u.dst.dev; - hlen = ip6_found_nexthdr(skb, &prevhdr); + hlen = ip6_find_1stfragopt(skb, &prevhdr); nexthdr = *prevhdr; mtu = dst_pmtu(&rt->u.dst) - hlen - sizeof(struct frag_hdr); @@ -1187,7 +1188,7 @@ if (err) { #if IP6_DEBUG >= 2 printk(KERN_DEBUG "ip6_build_xmit: " - "no availiable source address\n"); + "no available source address\n"); #endif return err; } @@ -1222,13 +1223,14 @@ if (flags&MSG_PROBE) return 0; - if (skb_queue_empty(&sk->write_queue)) { + if (skb_queue_empty(&sk->sk_write_queue)) { /* * setup for corking */ if (opt) { if (np->cork.opt == NULL) - np->cork.opt = kmalloc(opt->tot_len, sk->allocation); + np->cork.opt = kmalloc(opt->tot_len, + sk->sk_allocation); memcpy(np->cork.opt, opt, opt->tot_len); inet->cork.flags |= IPCORK_OPT; /* need source address above miyazawa*/ @@ -1268,7 +1270,7 @@ inet->cork.length += length; - if ((skb = skb_peek_tail(&sk->write_queue)) == NULL) + if ((skb = skb_peek_tail(&sk->sk_write_queue)) == NULL) goto alloc_new_skb; while (length > 0) { @@ -1295,10 +1297,11 @@ (flags & MSG_DONTWAIT), &err); } else { skb = NULL; - if (atomic_read(&sk->wmem_alloc) <= 2*sk->sndbuf) + if (atomic_read(&sk->sk_wmem_alloc) <= + 2 * sk->sk_sndbuf) skb = sock_wmalloc(sk, alloclen + hh_len + 15, 1, - sk->allocation); + sk->sk_allocation); if (unlikely(skb == NULL)) err = -ENOBUFS; } @@ -1335,7 +1338,7 @@ /* * Put the packet on the pending queue */ - __skb_queue_tail(&sk->write_queue, skb); + __skb_queue_tail(&sk->sk_write_queue, skb); continue; } @@ -1374,7 +1377,7 @@ } else if(i < MAX_SKB_FRAGS) { if (copy > PAGE_SIZE) copy = PAGE_SIZE; - page = alloc_pages(sk->allocation, 0); + page = alloc_pages(sk->sk_allocation, 0); if (page == NULL) { err = -ENOMEM; goto error; @@ -1385,7 +1388,7 @@ skb_fill_page_desc(skb, i, page, 0, 0); frag = &skb_shinfo(skb)->frags[i]; skb->truesize += PAGE_SIZE; - atomic_add(PAGE_SIZE, &sk->wmem_alloc); + atomic_add(PAGE_SIZE, &sk->sk_wmem_alloc); } else { err = -EMSGSIZE; goto error; @@ -1423,14 +1426,14 @@ unsigned char proto = fl->proto; int err = 0; - if ((skb = __skb_dequeue(&sk->write_queue)) == NULL) + if ((skb = __skb_dequeue(&sk->sk_write_queue)) == NULL) goto out; tail_skb = &(skb_shinfo(skb)->frag_list); /* move skb->data to ip header from ext header */ if (skb->data < skb->nh.raw) __skb_pull(skb, skb->nh.raw - skb->data); - while ((tmp_skb = __skb_dequeue(&sk->write_queue)) != NULL) { + while ((tmp_skb = __skb_dequeue(&sk->sk_write_queue)) != NULL) { __skb_pull(tmp_skb, skb->h.raw - skb->nh.raw); *tail_skb = tmp_skb; tail_skb = &(tmp_skb->next); @@ -1496,7 +1499,7 @@ struct ipv6_pinfo *np = inet6_sk(sk); struct sk_buff *skb; - while ((skb = __skb_dequeue_tail(&sk->write_queue)) != NULL) + while ((skb = __skb_dequeue_tail(&sk->sk_write_queue)) != NULL) kfree_skb(skb); inet->cork.flags &= ~IPCORK_OPT; diff -Nru a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/net/ipv6/ip6_tunnel.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,1261 @@ +/* + * IPv6 over IPv6 tunnel device + * Linux INET6 implementation + * + * Authors: + * Ville Nuorvala <vnuorval@tcs.hut.fi> + * + * $Id$ + * + * Based on: + * linux/net/ipv6/sit.c + * + * RFC 2473 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#include <linux/config.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/types.h> +#include <linux/socket.h> +#include <linux/sockios.h> +#include <linux/if.h> +#include <linux/in.h> +#include <linux/ip.h> +#include <linux/if_tunnel.h> +#include <linux/net.h> +#include <linux/in6.h> +#include <linux/netdevice.h> +#include <linux/if_arp.h> +#include <linux/icmpv6.h> +#include <linux/init.h> +#include <linux/route.h> +#include <linux/rtnetlink.h> + +#include <asm/uaccess.h> +#include <asm/atomic.h> + +#include <net/ip.h> +#include <net/sock.h> +#include <net/ipv6.h> +#include <net/protocol.h> +#include <net/ip6_route.h> +#include <net/addrconf.h> +#include <net/ip6_tunnel.h> + +MODULE_AUTHOR("Ville Nuorvala"); +MODULE_DESCRIPTION("IPv6-in-IPv6 tunnel"); +MODULE_LICENSE("GPL"); + +#define IPV6_TLV_TEL_DST_SIZE 8 + +#ifdef IP6_TNL_DEBUG +#define IP6_TNL_TRACE(x...) printk(KERN_DEBUG "%s:" x "\n", __FUNCTION__) +#else +#define IP6_TNL_TRACE(x...) do {;} while(0) +#endif + +#define IPV6_TCLASS_MASK (IPV6_FLOWINFO_MASK & ~IPV6_FLOWLABEL_MASK) + +/* socket(s) used by ip6ip6_tnl_xmit() for resending packets */ +static struct socket *__ip6_socket[NR_CPUS]; +#define ip6_socket __ip6_socket[smp_processor_id()] + +static void ip6_xmit_lock(void) +{ + local_bh_disable(); + if (unlikely(!spin_trylock(&ip6_socket->sk->sk_lock.slock))) + BUG(); +} + +static void ip6_xmit_unlock(void) +{ + spin_unlock_bh(&ip6_socket->sk->sk_lock.slock); +} + +#define HASH_SIZE 32 + +#define HASH(addr) (((addr)->s6_addr32[0] ^ (addr)->s6_addr32[1] ^ \ + (addr)->s6_addr32[2] ^ (addr)->s6_addr32[3]) & \ + (HASH_SIZE - 1)) + +static int ip6ip6_fb_tnl_dev_init(struct net_device *dev); +static int ip6ip6_tnl_dev_init(struct net_device *dev); + +/* the IPv6 tunnel fallback device */ +static struct net_device ip6ip6_fb_tnl_dev = { + .name = "ip6tnl0", + .init = ip6ip6_fb_tnl_dev_init +}; + +/* the IPv6 fallback tunnel */ +static struct ip6_tnl ip6ip6_fb_tnl = { + .dev = &ip6ip6_fb_tnl_dev, + .parms ={.name = "ip6tnl0", .proto = IPPROTO_IPV6} +}; + +/* lists for storing tunnels in use */ +static struct ip6_tnl *tnls_r_l[HASH_SIZE]; +static struct ip6_tnl *tnls_wc[1]; +static struct ip6_tnl **tnls[2] = { tnls_wc, tnls_r_l }; + +/* lock for the tunnel lists */ +static rwlock_t ip6ip6_lock = RW_LOCK_UNLOCKED; + +/** + * ip6ip6_tnl_lookup - fetch tunnel matching the end-point addresses + * @remote: the address of the tunnel exit-point + * @local: the address of the tunnel entry-point + * + * Return: + * tunnel matching given end-points if found, + * else fallback tunnel if its device is up, + * else %NULL + **/ + +struct ip6_tnl * +ip6ip6_tnl_lookup(struct in6_addr *remote, struct in6_addr *local) +{ + unsigned h0 = HASH(remote); + unsigned h1 = HASH(local); + struct ip6_tnl *t; + + for (t = tnls_r_l[h0 ^ h1]; t; t = t->next) { + if (!ipv6_addr_cmp(local, &t->parms.laddr) && + !ipv6_addr_cmp(remote, &t->parms.raddr) && + (t->dev->flags & IFF_UP)) + return t; + } + if ((t = tnls_wc[0]) != NULL && (t->dev->flags & IFF_UP)) + return t; + + return NULL; +} + +/** + * ip6ip6_bucket - get head of list matching given tunnel parameters + * @p: parameters containing tunnel end-points + * + * Description: + * ip6ip6_bucket() returns the head of the list matching the + * &struct in6_addr entries laddr and raddr in @p. + * + * Return: head of IPv6 tunnel list + **/ + +static struct ip6_tnl ** +ip6ip6_bucket(struct ip6_tnl_parm *p) +{ + struct in6_addr *remote = &p->raddr; + struct in6_addr *local = &p->laddr; + unsigned h = 0; + int prio = 0; + + if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) { + prio = 1; + h = HASH(remote) ^ HASH(local); + } + return &tnls[prio][h]; +} + +/** + * ip6ip6_tnl_link - add tunnel to hash table + * @t: tunnel to be added + **/ + +static void +ip6ip6_tnl_link(struct ip6_tnl *t) +{ + struct ip6_tnl **tp = ip6ip6_bucket(&t->parms); + + write_lock_bh(&ip6ip6_lock); + t->next = *tp; + write_unlock_bh(&ip6ip6_lock); + *tp = t; +} + +/** + * ip6ip6_tnl_unlink - remove tunnel from hash table + * @t: tunnel to be removed + **/ + +static void +ip6ip6_tnl_unlink(struct ip6_tnl *t) +{ + struct ip6_tnl **tp; + + for (tp = ip6ip6_bucket(&t->parms); *tp; tp = &(*tp)->next) { + if (t == *tp) { + write_lock_bh(&ip6ip6_lock); + *tp = t->next; + write_unlock_bh(&ip6ip6_lock); + break; + } + } +} + +/** + * ip6_tnl_create() - create a new tunnel + * @p: tunnel parameters + * @pt: pointer to new tunnel + * + * Description: + * Create tunnel matching given parameters. + * + * Return: + * 0 on success + **/ + +static int +ip6_tnl_create(struct ip6_tnl_parm *p, struct ip6_tnl **pt) +{ + struct net_device *dev; + int err = -ENOBUFS; + struct ip6_tnl *t; + + dev = kmalloc(sizeof (*dev) + sizeof (*t), GFP_KERNEL); + if (!dev) + return err; + + memset(dev, 0, sizeof (*dev) + sizeof (*t)); + dev->priv = (void *) (dev + 1); + t = (struct ip6_tnl *) dev->priv; + t->dev = dev; + dev->init = ip6ip6_tnl_dev_init; + memcpy(&t->parms, p, sizeof (*p)); + t->parms.name[IFNAMSIZ - 1] = '\0'; + if (t->parms.hop_limit > 255) + t->parms.hop_limit = -1; + strcpy(dev->name, t->parms.name); + if (!dev->name[0]) { + int i = 0; + int exists = 0; + + do { + sprintf(dev->name, "ip6tnl%d", ++i); + exists = (__dev_get_by_name(dev->name) != NULL); + } while (i < IP6_TNL_MAX && exists); + + if (i == IP6_TNL_MAX) { + goto failed; + } + memcpy(t->parms.name, dev->name, IFNAMSIZ); + } + SET_MODULE_OWNER(dev); + if ((err = register_netdevice(dev)) < 0) { + goto failed; + } + ip6ip6_tnl_link(t); + *pt = t; + return 0; +failed: + kfree(dev); + return err; +} + +/** + * ip6_tnl_destroy() - destroy old tunnel + * @t: tunnel to be destroyed + * + * Return: + * whatever unregister_netdevice() returns + **/ + +static inline int +ip6_tnl_destroy(struct ip6_tnl *t) +{ + return unregister_netdevice(t->dev); +} + +/** + * ip6ip6_tnl_locate - find or create tunnel matching given parameters + * @p: tunnel parameters + * @create: != 0 if allowed to create new tunnel if no match found + * + * Description: + * ip6ip6_tnl_locate() first tries to locate an existing tunnel + * based on @parms. If this is unsuccessful, but @create is set a new + * tunnel device is created and registered for use. + * + * Return: + * 0 if tunnel located or created, + * -EINVAL if parameters incorrect, + * -ENODEV if no matching tunnel available + **/ + +static int +ip6ip6_tnl_locate(struct ip6_tnl_parm *p, struct ip6_tnl **pt, int create) +{ + struct in6_addr *remote = &p->raddr; + struct in6_addr *local = &p->laddr; + struct ip6_tnl *t; + + if (p->proto != IPPROTO_IPV6) + return -EINVAL; + + for (t = *ip6ip6_bucket(p); t; t = t->next) { + if (!ipv6_addr_cmp(local, &t->parms.laddr) && + !ipv6_addr_cmp(remote, &t->parms.raddr)) { + *pt = t; + return (create ? -EEXIST : 0); + } + } + if (!create) { + return -ENODEV; + } + return ip6_tnl_create(p, pt); +} + +/** + * ip6ip6_tnl_dev_destructor - tunnel device destructor + * @dev: the device to be destroyed + **/ + +static void +ip6ip6_tnl_dev_destructor(struct net_device *dev) +{ + kfree(dev); +} + +/** + * ip6ip6_tnl_dev_uninit - tunnel device uninitializer + * @dev: the device to be destroyed + * + * Description: + * ip6ip6_tnl_dev_uninit() removes tunnel from its list + **/ + +static void +ip6ip6_tnl_dev_uninit(struct net_device *dev) +{ + if (dev == &ip6ip6_fb_tnl_dev) { + write_lock_bh(&ip6ip6_lock); + tnls_wc[0] = NULL; + write_unlock_bh(&ip6ip6_lock); + } else { + struct ip6_tnl *t = (struct ip6_tnl *) dev->priv; + ip6ip6_tnl_unlink(t); + } +} + +/** + * parse_tvl_tnl_enc_lim - handle encapsulation limit option + * @skb: received socket buffer + * + * Return: + * 0 if none was found, + * else index to encapsulation limit + **/ + +static __u16 +parse_tlv_tnl_enc_lim(struct sk_buff *skb, __u8 * raw) +{ + struct ipv6hdr *ipv6h = (struct ipv6hdr *) raw; + __u8 nexthdr = ipv6h->nexthdr; + __u16 off = sizeof (*ipv6h); + + while (ipv6_ext_hdr(nexthdr) && nexthdr != NEXTHDR_NONE) { + __u16 optlen = 0; + struct ipv6_opt_hdr *hdr; + if (raw + off + sizeof (*hdr) > skb->data && + !pskb_may_pull(skb, raw - skb->data + off + sizeof (*hdr))) + break; + + hdr = (struct ipv6_opt_hdr *) (raw + off); + if (nexthdr == NEXTHDR_FRAGMENT) { + struct frag_hdr *frag_hdr = (struct frag_hdr *) hdr; + if (frag_hdr->frag_off) + break; + optlen = 8; + } else if (nexthdr == NEXTHDR_AUTH) { + optlen = (hdr->hdrlen + 2) << 2; + } else { + optlen = ipv6_optlen(hdr); + } + if (nexthdr == NEXTHDR_DEST) { + __u16 i = off + 2; + while (1) { + struct ipv6_tlv_tnl_enc_lim *tel; + + /* No more room for encapsulation limit */ + if (i + sizeof (*tel) > off + optlen) + break; + + tel = (struct ipv6_tlv_tnl_enc_lim *) &raw[i]; + /* return index of option if found and valid */ + if (tel->type == IPV6_TLV_TNL_ENCAP_LIMIT && + tel->length == 1) + return i; + /* else jump to next option */ + if (tel->type) + i += tel->length + 2; + else + i++; + } + } + nexthdr = hdr->nexthdr; + off += optlen; + } + return 0; +} + +/** + * ip6ip6_err - tunnel error handler + * + * Description: + * ip6ip6_err() should handle errors in the tunnel according + * to the specifications in RFC 2473. + **/ + +void ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, + int type, int code, int offset, __u32 info) +{ + struct ipv6hdr *ipv6h = (struct ipv6hdr *) skb->data; + struct ip6_tnl *t; + int rel_msg = 0; + int rel_type = ICMPV6_DEST_UNREACH; + int rel_code = ICMPV6_ADDR_UNREACH; + __u32 rel_info = 0; + __u16 len; + + /* If the packet doesn't contain the original IPv6 header we are + in trouble since we might need the source address for furter + processing of the error. */ + + read_lock(&ip6ip6_lock); + if ((t = ip6ip6_tnl_lookup(&ipv6h->daddr, &ipv6h->saddr)) == NULL) + goto out; + + switch (type) { + __u32 teli; + struct ipv6_tlv_tnl_enc_lim *tel; + __u32 mtu; + case ICMPV6_DEST_UNREACH: + if (net_ratelimit()) + printk(KERN_WARNING + "%s: Path to destination invalid " + "or inactive!\n", t->parms.name); + rel_msg = 1; + break; + case ICMPV6_TIME_EXCEED: + if (code == ICMPV6_EXC_HOPLIMIT) { + if (net_ratelimit()) + printk(KERN_WARNING + "%s: Too small hop limit or " + "routing loop in tunnel!\n", + t->parms.name); + rel_msg = 1; + } + break; + case ICMPV6_PARAMPROB: + /* ignore if parameter problem not caused by a tunnel + encapsulation limit sub-option */ + if (code != ICMPV6_HDR_FIELD) { + break; + } + teli = parse_tlv_tnl_enc_lim(skb, skb->data); + + if (teli && teli == info - 2) { + tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->data[teli]; + if (tel->encap_limit <= 1) { + if (net_ratelimit()) + printk(KERN_WARNING + "%s: Too small encapsulation " + "limit or routing loop in " + "tunnel!\n", t->parms.name); + rel_msg = 1; + } + } + break; + case ICMPV6_PKT_TOOBIG: + mtu = info - offset; + if (mtu <= IPV6_MIN_MTU) { + mtu = IPV6_MIN_MTU; + } + t->dev->mtu = mtu; + + if ((len = sizeof (*ipv6h) + ipv6h->payload_len) > mtu) { + rel_type = ICMPV6_PKT_TOOBIG; + rel_code = 0; + rel_info = mtu; + rel_msg = 1; + } + break; + } + if (rel_msg && pskb_may_pull(skb, offset + sizeof (*ipv6h))) { + struct rt6_info *rt; + struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); + if (!skb2) + goto out; + + dst_release(skb2->dst); + skb2->dst = NULL; + skb_pull(skb2, offset); + skb2->nh.raw = skb2->data; + + /* Try to guess incoming interface */ + rt = rt6_lookup(&skb2->nh.ipv6h->saddr, NULL, 0, 0); + + if (rt && rt->rt6i_dev) + skb2->dev = rt->rt6i_dev; + + icmpv6_send(skb2, rel_type, rel_code, rel_info, skb2->dev); + + if (rt) + dst_free(&rt->u.dst); + + kfree_skb(skb2); + } +out: + read_unlock(&ip6ip6_lock); +} + +/** + * ip6ip6_rcv - decapsulate IPv6 packet and retransmit it locally + * @skb: received socket buffer + * + * Return: 0 + **/ + +int ip6ip6_rcv(struct sk_buff **pskb, unsigned int *nhoffp) +{ + struct sk_buff *skb = *pskb; + struct ipv6hdr *ipv6h; + struct ip6_tnl *t; + + if (!pskb_may_pull(skb, sizeof (*ipv6h))) + goto discard; + + ipv6h = skb->nh.ipv6h; + + read_lock(&ip6ip6_lock); + + if ((t = ip6ip6_tnl_lookup(&ipv6h->saddr, &ipv6h->daddr)) != NULL) { + if (!(t->parms.flags & IP6_TNL_F_CAP_RCV)) { + t->stat.rx_dropped++; + read_unlock(&ip6ip6_lock); + goto discard; + } + skb->mac.raw = skb->nh.raw; + skb->nh.raw = skb->data; + skb->protocol = htons(ETH_P_IPV6); + skb->pkt_type = PACKET_HOST; + memset(skb->cb, 0, sizeof(struct inet6_skb_parm)); + skb->dev = t->dev; + dst_release(skb->dst); + skb->dst = NULL; + t->stat.rx_packets++; + t->stat.rx_bytes += skb->len; + netif_rx(skb); + read_unlock(&ip6ip6_lock); + return 0; + } + read_unlock(&ip6ip6_lock); + icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, skb->dev); +discard: + kfree_skb(skb); + return 0; +} + +/** + * txopt_len - get necessary size for new &struct ipv6_txoptions + * @orig_opt: old options + * + * Return: + * Size of old one plus size of tunnel encapsulation limit option + **/ + +static inline int +txopt_len(struct ipv6_txoptions *orig_opt) +{ + int len = sizeof (*orig_opt) + 8; + + if (orig_opt && orig_opt->dst0opt) + len += ipv6_optlen(orig_opt->dst0opt); + return len; +} + +/** + * merge_options - add encapsulation limit to original options + * @encap_limit: number of allowed encapsulation limits + * @orig_opt: original options + * + * Return: + * Pointer to new &struct ipv6_txoptions containing the tunnel + * encapsulation limit + **/ + +static struct ipv6_txoptions * +merge_options(struct sock *sk, __u8 encap_limit, + struct ipv6_txoptions *orig_opt) +{ + struct ipv6_tlv_tnl_enc_lim *tel; + struct ipv6_txoptions *opt; + __u8 *raw; + __u8 pad_to = 8; + int opt_len = txopt_len(orig_opt); + + if (!(opt = sock_kmalloc(sk, opt_len, GFP_ATOMIC))) { + return NULL; + } + + memset(opt, 0, opt_len); + opt->tot_len = opt_len; + opt->dst0opt = (struct ipv6_opt_hdr *) (opt + 1); + opt->opt_nflen = 8; + + raw = (__u8 *) opt->dst0opt; + + tel = (struct ipv6_tlv_tnl_enc_lim *) (opt->dst0opt + 1); + tel->type = IPV6_TLV_TNL_ENCAP_LIMIT; + tel->length = 1; + tel->encap_limit = encap_limit; + + if (orig_opt) { + __u8 *orig_raw; + + opt->hopopt = orig_opt->hopopt; + + /* Keep the original destination options properly + aligned and merge possible old paddings to the + new padding option */ + if ((orig_raw = (__u8 *) orig_opt->dst0opt) != NULL) { + __u8 type; + int i = sizeof (struct ipv6_opt_hdr); + pad_to += sizeof (struct ipv6_opt_hdr); + while (i < ipv6_optlen(orig_opt->dst0opt)) { + type = orig_raw[i++]; + if (type == IPV6_TLV_PAD0) + pad_to++; + else if (type == IPV6_TLV_PADN) { + int len = orig_raw[i++]; + i += len; + pad_to += len + 2; + } else { + break; + } + } + opt->dst0opt->hdrlen = orig_opt->dst0opt->hdrlen + 1; + memcpy(raw + pad_to, orig_raw + pad_to - 8, + opt_len - sizeof (*opt) - pad_to); + } + opt->srcrt = orig_opt->srcrt; + opt->opt_nflen += orig_opt->opt_nflen; + + opt->dst1opt = orig_opt->dst1opt; + opt->auth = orig_opt->auth; + opt->opt_flen = orig_opt->opt_flen; + } + raw[5] = IPV6_TLV_PADN; + + /* subtract lengths of destination suboption header, + tunnel encapsulation limit and pad N header */ + raw[6] = pad_to - 7; + + return opt; +} + +/** + * ip6ip6_tnl_addr_conflict - compare packet addresses to tunnel's own + * @t: the outgoing tunnel device + * @hdr: IPv6 header from the incoming packet + * + * Description: + * Avoid trivial tunneling loop by checking that tunnel exit-point + * doesn't match source of incoming packet. + * + * Return: + * 1 if conflict, + * 0 else + **/ + +static inline int +ip6ip6_tnl_addr_conflict(struct ip6_tnl *t, struct ipv6hdr *hdr) +{ + return !ipv6_addr_cmp(&t->parms.raddr, &hdr->saddr); +} + +/** + * ip6ip6_tnl_xmit - encapsulate packet and send + * @skb: the outgoing socket buffer + * @dev: the outgoing tunnel device + * + * Description: + * Build new header and do some sanity checks on the packet before sending + * it to ip6_build_xmit(). + * + * Return: + * 0 + **/ + +int ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct ip6_tnl *t = (struct ip6_tnl *) dev->priv; + struct net_device_stats *stats = &t->stat; + struct ipv6hdr *ipv6h = skb->nh.ipv6h; + struct ipv6_txoptions *orig_opt = NULL; + struct ipv6_txoptions *opt = NULL; + __u8 encap_limit = 0; + __u16 offset; + struct flowi fl; + struct ip6_flowlabel *fl_lbl = NULL; + int err = 0; + struct dst_entry *dst; + int link_failure = 0; + struct sock *sk = ip6_socket->sk; + struct ipv6_pinfo *np = inet6_sk(sk); + int mtu; + + if (t->recursion++) { + stats->collisions++; + goto tx_err; + } + if (skb->protocol != htons(ETH_P_IPV6) || + !(t->parms.flags & IP6_TNL_F_CAP_XMIT) || + ip6ip6_tnl_addr_conflict(t, ipv6h)) { + goto tx_err; + } + if ((offset = parse_tlv_tnl_enc_lim(skb, skb->nh.raw)) > 0) { + struct ipv6_tlv_tnl_enc_lim *tel; + tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->nh.raw[offset]; + if (tel->encap_limit <= 1) { + icmpv6_send(skb, ICMPV6_PARAMPROB, + ICMPV6_HDR_FIELD, offset + 2, skb->dev); + goto tx_err; + } + encap_limit = tel->encap_limit - 1; + } else if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) { + encap_limit = t->parms.encap_limit; + } + ip6_xmit_lock(); + + memcpy(&fl, &t->fl, sizeof (fl)); + + if ((t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS)) + fl.fl6_flowlabel |= (*(__u32 *) ipv6h & IPV6_TCLASS_MASK); + if ((t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL)) + fl.fl6_flowlabel |= (*(__u32 *) ipv6h & IPV6_FLOWLABEL_MASK); + + if (fl.fl6_flowlabel) { + fl_lbl = fl6_sock_lookup(sk, fl.fl6_flowlabel); + if (fl_lbl) + orig_opt = fl_lbl->opt; + } + if (encap_limit > 0) { + if (!(opt = merge_options(sk, encap_limit, orig_opt))) { + goto tx_err_free_fl_lbl; + } + } else { + opt = orig_opt; + } + dst = __sk_dst_check(sk, np->dst_cookie); + + if (dst) { + if (np->daddr_cache == NULL || + ipv6_addr_cmp(&fl.fl6_dst, np->daddr_cache) || + (fl.oif && fl.oif != dst->dev->ifindex)) { + dst = NULL; + } + } + if (dst == NULL) { + dst = ip6_route_output(sk, &fl); + if (dst->error) { + stats->tx_carrier_errors++; + link_failure = 1; + goto tx_err_dst_release; + } + /* local routing loop */ + if (dst->dev == dev) { + stats->collisions++; + if (net_ratelimit()) + printk(KERN_WARNING + "%s: Local routing loop detected!\n", + t->parms.name); + goto tx_err_dst_release; + } + ipv6_addr_copy(&np->daddr, &fl.fl6_dst); + ipv6_addr_copy(&np->saddr, &fl.fl6_src); + } + mtu = dst_pmtu(dst) - sizeof (*ipv6h); + if (opt) { + mtu -= (opt->opt_nflen + opt->opt_flen); + } + if (mtu < IPV6_MIN_MTU) + mtu = IPV6_MIN_MTU; + if (skb->dst && mtu < dst_pmtu(skb->dst)) { + struct rt6_info *rt = (struct rt6_info *) skb->dst; + rt->rt6i_flags |= RTF_MODIFIED; + rt->u.dst.metrics[RTAX_MTU-1] = mtu; + } + if (skb->len > mtu) { + icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev); + goto tx_err_opt_release; + } + err = ip6_append_data(sk, ip_generic_getfrag, skb->nh.raw, skb->len, 0, + t->parms.hop_limit, opt, &fl, + (struct rt6_info *)dst, MSG_DONTWAIT); + + if (err) { + ip6_flush_pending_frames(sk); + } else { + err = ip6_push_pending_frames(sk); + err = (err < 0 ? err : 0); + } + if (!err) { + stats->tx_bytes += skb->len; + stats->tx_packets++; + } else { + stats->tx_errors++; + stats->tx_aborted_errors++; + } + if (opt && opt != orig_opt) + sock_kfree_s(sk, opt, opt->tot_len); + + fl6_sock_release(fl_lbl); + ip6_dst_store(sk, dst, &np->daddr); + ip6_xmit_unlock(); + kfree_skb(skb); + t->recursion--; + return 0; +tx_err_dst_release: + dst_release(dst); +tx_err_opt_release: + if (opt && opt != orig_opt) + sock_kfree_s(sk, opt, opt->tot_len); +tx_err_free_fl_lbl: + fl6_sock_release(fl_lbl); + ip6_xmit_unlock(); + if (link_failure) + dst_link_failure(skb); +tx_err: + stats->tx_errors++; + stats->tx_dropped++; + kfree_skb(skb); + t->recursion--; + return 0; +} + +static void ip6_tnl_set_cap(struct ip6_tnl *t) +{ + struct ip6_tnl_parm *p = &t->parms; + struct in6_addr *laddr = &p->laddr; + struct in6_addr *raddr = &p->raddr; + int ltype = ipv6_addr_type(laddr); + int rtype = ipv6_addr_type(raddr); + + p->flags &= ~(IP6_TNL_F_CAP_XMIT|IP6_TNL_F_CAP_RCV); + + if (ltype != IPV6_ADDR_ANY && rtype != IPV6_ADDR_ANY && + ((ltype|rtype) & + (IPV6_ADDR_UNICAST| + IPV6_ADDR_LOOPBACK|IPV6_ADDR_LINKLOCAL| + IPV6_ADDR_MAPPED|IPV6_ADDR_RESERVED)) == IPV6_ADDR_UNICAST) { + struct net_device *ldev = NULL; + int l_ok = 1; + int r_ok = 1; + + if (p->link) + ldev = dev_get_by_index(p->link); + + if ((ltype&IPV6_ADDR_UNICAST) && !ipv6_chk_addr(laddr, ldev)) + l_ok = 0; + + if ((rtype&IPV6_ADDR_UNICAST) && ipv6_chk_addr(raddr, NULL)) + r_ok = 0; + + if (l_ok && r_ok) { + if (ltype&IPV6_ADDR_UNICAST) + p->flags |= IP6_TNL_F_CAP_XMIT; + if (rtype&IPV6_ADDR_UNICAST) + p->flags |= IP6_TNL_F_CAP_RCV; + } + if (ldev) + dev_put(ldev); + } +} + + +static void ip6ip6_tnl_link_config(struct ip6_tnl *t) +{ + struct net_device *dev = t->dev; + struct ip6_tnl_parm *p = &t->parms; + struct flowi *fl; + /* Set up flowi template */ + fl = &t->fl; + ipv6_addr_copy(&fl->fl6_src, &p->laddr); + ipv6_addr_copy(&fl->fl6_dst, &p->raddr); + fl->oif = p->link; + fl->fl6_flowlabel = 0; + + if (!(p->flags&IP6_TNL_F_USE_ORIG_TCLASS)) + fl->fl6_flowlabel |= IPV6_TCLASS_MASK & htonl(p->flowinfo); + if (!(p->flags&IP6_TNL_F_USE_ORIG_FLOWLABEL)) + fl->fl6_flowlabel |= IPV6_FLOWLABEL_MASK & htonl(p->flowinfo); + + ip6_tnl_set_cap(t); + + if (p->flags&IP6_TNL_F_CAP_XMIT && p->flags&IP6_TNL_F_CAP_RCV) + dev->flags |= IFF_POINTOPOINT; + else + dev->flags &= ~IFF_POINTOPOINT; + + if (p->flags & IP6_TNL_F_CAP_XMIT) { + struct rt6_info *rt = rt6_lookup(&p->raddr, &p->laddr, + p->link, 0); + if (rt) { + struct net_device *rtdev; + if (!(rtdev = rt->rt6i_dev) || + rtdev->type == ARPHRD_TUNNEL6) { + /* as long as tunnels use the same socket + for transmission, locally nested tunnels + won't work */ + dst_release(&rt->u.dst); + goto no_link; + } else { + dev->iflink = rtdev->ifindex; + dev->hard_header_len = rtdev->hard_header_len + + sizeof (struct ipv6hdr); + dev->mtu = rtdev->mtu - sizeof (struct ipv6hdr); + if (dev->mtu < IPV6_MIN_MTU) + dev->mtu = IPV6_MIN_MTU; + + dst_release(&rt->u.dst); + } + } + } else { + no_link: + dev->iflink = 0; + dev->hard_header_len = LL_MAX_HEADER + sizeof (struct ipv6hdr); + dev->mtu = ETH_DATA_LEN - sizeof (struct ipv6hdr); + } +} + +/** + * ip6ip6_tnl_change - update the tunnel parameters + * @t: tunnel to be changed + * @p: tunnel configuration parameters + * @active: != 0 if tunnel is ready for use + * + * Description: + * ip6ip6_tnl_change() updates the tunnel parameters + **/ + +static int +ip6ip6_tnl_change(struct ip6_tnl *t, struct ip6_tnl_parm *p) +{ + ipv6_addr_copy(&t->parms.laddr, &p->laddr); + ipv6_addr_copy(&t->parms.raddr, &p->raddr); + t->parms.flags = p->flags; + t->parms.hop_limit = (p->hop_limit <= 255 ? p->hop_limit : -1); + t->parms.encap_limit = p->encap_limit; + t->parms.flowinfo = p->flowinfo; + ip6ip6_tnl_link_config(t); + return 0; +} + +/** + * ip6ip6_tnl_ioctl - configure ipv6 tunnels from userspace + * @dev: virtual device associated with tunnel + * @ifr: parameters passed from userspace + * @cmd: command to be performed + * + * Description: + * ip6ip6_tnl_ioctl() is used for managing IPv6 tunnels + * from userspace. + * + * The possible commands are the following: + * %SIOCGETTUNNEL: get tunnel parameters for device + * %SIOCADDTUNNEL: add tunnel matching given tunnel parameters + * %SIOCCHGTUNNEL: change tunnel parameters to those given + * %SIOCDELTUNNEL: delete tunnel + * + * The fallback device "ip6tnl0", created during module + * initialization, can be used for creating other tunnel devices. + * + * Return: + * 0 on success, + * %-EFAULT if unable to copy data to or from userspace, + * %-EPERM if current process hasn't %CAP_NET_ADMIN set + * %-EINVAL if passed tunnel parameters are invalid, + * %-EEXIST if changing a tunnel's parameters would cause a conflict + * %-ENODEV if attempting to change or delete a nonexisting device + **/ + +static int +ip6ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + int err = 0; + int create; + struct ip6_tnl_parm p; + struct ip6_tnl *t = NULL; + + switch (cmd) { + case SIOCGETTUNNEL: + if (dev == &ip6ip6_fb_tnl_dev) { + if (copy_from_user(&p, + ifr->ifr_ifru.ifru_data, + sizeof (p))) { + err = -EFAULT; + break; + } + if ((err = ip6ip6_tnl_locate(&p, &t, 0)) == -ENODEV) + t = (struct ip6_tnl *) dev->priv; + else if (err) + break; + } else + t = (struct ip6_tnl *) dev->priv; + + memcpy(&p, &t->parms, sizeof (p)); + if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof (p))) { + err = -EFAULT; + } + break; + case SIOCADDTUNNEL: + case SIOCCHGTUNNEL: + err = -EPERM; + create = (cmd == SIOCADDTUNNEL); + if (!capable(CAP_NET_ADMIN)) + break; + if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof (p))) { + err = -EFAULT; + break; + } + if (!create && dev != &ip6ip6_fb_tnl_dev) { + t = (struct ip6_tnl *) dev->priv; + } + if (!t && (err = ip6ip6_tnl_locate(&p, &t, create))) { + break; + } + if (cmd == SIOCCHGTUNNEL) { + if (t->dev != dev) { + err = -EEXIST; + break; + } + ip6ip6_tnl_unlink(t); + err = ip6ip6_tnl_change(t, &p); + ip6ip6_tnl_link(t); + netdev_state_change(dev); + } + if (copy_to_user(ifr->ifr_ifru.ifru_data, + &t->parms, sizeof (p))) { + err = -EFAULT; + } else { + err = 0; + } + break; + case SIOCDELTUNNEL: + err = -EPERM; + if (!capable(CAP_NET_ADMIN)) + break; + + if (dev == &ip6ip6_fb_tnl_dev) { + if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, + sizeof (p))) { + err = -EFAULT; + break; + } + err = ip6ip6_tnl_locate(&p, &t, 0); + if (err) + break; + if (t == &ip6ip6_fb_tnl) { + err = -EPERM; + break; + } + } else { + t = (struct ip6_tnl *) dev->priv; + } + err = ip6_tnl_destroy(t); + break; + default: + err = -EINVAL; + } + return err; +} + +/** + * ip6ip6_tnl_get_stats - return the stats for tunnel device + * @dev: virtual device associated with tunnel + * + * Return: stats for device + **/ + +static struct net_device_stats * +ip6ip6_tnl_get_stats(struct net_device *dev) +{ + return &(((struct ip6_tnl *) dev->priv)->stat); +} + +/** + * ip6ip6_tnl_change_mtu - change mtu manually for tunnel device + * @dev: virtual device associated with tunnel + * @new_mtu: the new mtu + * + * Return: + * 0 on success, + * %-EINVAL if mtu too small + **/ + +static int +ip6ip6_tnl_change_mtu(struct net_device *dev, int new_mtu) +{ + if (new_mtu < IPV6_MIN_MTU) { + return -EINVAL; + } + dev->mtu = new_mtu; + return 0; +} + +/** + * ip6ip6_tnl_dev_init_gen - general initializer for all tunnel devices + * @dev: virtual device associated with tunnel + * + * Description: + * Set function pointers and initialize the &struct flowi template used + * by the tunnel. + **/ + +static void +ip6ip6_tnl_dev_init_gen(struct net_device *dev) +{ + struct ip6_tnl *t = (struct ip6_tnl *) dev->priv; + struct flowi *fl = &t->fl; + + memset(fl, 0, sizeof (*fl)); + fl->proto = IPPROTO_IPV6; + + dev->destructor = ip6ip6_tnl_dev_destructor; + dev->uninit = ip6ip6_tnl_dev_uninit; + dev->hard_start_xmit = ip6ip6_tnl_xmit; + dev->get_stats = ip6ip6_tnl_get_stats; + dev->do_ioctl = ip6ip6_tnl_ioctl; + dev->change_mtu = ip6ip6_tnl_change_mtu; + dev->type = ARPHRD_TUNNEL6; + dev->flags |= IFF_NOARP; + if (ipv6_addr_type(&t->parms.raddr) & IPV6_ADDR_UNICAST && + ipv6_addr_type(&t->parms.laddr) & IPV6_ADDR_UNICAST) + dev->flags |= IFF_POINTOPOINT; + /* Hmm... MAX_ADDR_LEN is 8, so the ipv6 addresses can't be + copied to dev->dev_addr and dev->broadcast, like the ipv4 + addresses were in ipip.c, ip_gre.c and sit.c. */ + dev->addr_len = 0; +} + +/** + * ip6ip6_tnl_dev_init - initializer for all non fallback tunnel devices + * @dev: virtual device associated with tunnel + **/ + +static int +ip6ip6_tnl_dev_init(struct net_device *dev) +{ + struct ip6_tnl *t = (struct ip6_tnl *) dev->priv; + ip6ip6_tnl_dev_init_gen(dev); + ip6ip6_tnl_link_config(t); + return 0; +} + +/** + * ip6ip6_fb_tnl_dev_init - initializer for fallback tunnel device + * @dev: fallback device + * + * Return: 0 + **/ + +int ip6ip6_fb_tnl_dev_init(struct net_device *dev) +{ + ip6ip6_tnl_dev_init_gen(dev); + tnls_wc[0] = &ip6ip6_fb_tnl; + return 0; +} + +static struct inet6_protocol ip6ip6_protocol = { + .handler = ip6ip6_rcv, + .err_handler = ip6ip6_err, + .flags = INET6_PROTO_FINAL +}; + +/** + * ip6_tunnel_init - register protocol and reserve needed resources + * + * Return: 0 on success + **/ + +int __init ip6_tunnel_init(void) +{ + int i, j, err; + struct sock *sk; + struct ipv6_pinfo *np; + + ip6ip6_fb_tnl_dev.priv = (void *) &ip6ip6_fb_tnl; + + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_possible(i)) + continue; + + err = sock_create(PF_INET6, SOCK_RAW, IPPROTO_IPV6, + &__ip6_socket[i]); + if (err < 0) { + printk(KERN_ERR + "Failed to create the IPv6 tunnel socket " + "(err %d).\n", + err); + goto fail; + } + sk = __ip6_socket[i]->sk; + sk->sk_allocation = GFP_ATOMIC; + + np = inet6_sk(sk); + np->hop_limit = 255; + np->mc_loop = 0; + + sk->sk_prot->unhash(sk); + } + if ((err = inet6_add_protocol(&ip6ip6_protocol, IPPROTO_IPV6)) < 0) { + printk(KERN_ERR "Failed to register IPv6 protocol\n"); + goto fail; + } + + SET_MODULE_OWNER(&ip6ip6_fb_tnl_dev); + register_netdev(&ip6ip6_fb_tnl_dev); + + return 0; +fail: + for (j = 0; j < i; j++) { + if (!cpu_possible(j)) + continue; + sock_release(__ip6_socket[j]); + __ip6_socket[j] = NULL; + } + return err; +} + +/** + * ip6_tunnel_cleanup - free resources and unregister protocol + **/ + +void ip6_tunnel_cleanup(void) +{ + int i; + + unregister_netdev(&ip6ip6_fb_tnl_dev); + + inet6_del_protocol(&ip6ip6_protocol, IPPROTO_IPV6); + + for (i = 0; i < NR_CPUS; i++) { + if (!cpu_possible(i)) + continue; + sock_release(__ip6_socket[i]); + __ip6_socket[i] = NULL; + } +} + +#ifdef MODULE +module_init(ip6_tunnel_init); +module_exit(ip6_tunnel_cleanup); +#endif diff -Nru a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c --- a/net/ipv6/ipcomp6.c Mon Jun 9 23:16:12 2003 +++ b/net/ipv6/ipcomp6.c Mon Jun 9 23:16:12 2003 @@ -105,7 +105,7 @@ iph = skb->nh.ipv6h; iph->payload_len = htons(skb->len); - ip6_found_nexthdr(skb, &prevhdr); + ip6_find_1stfragopt(skb, &prevhdr); *prevhdr = nexthdr; out: if (tmp_hdr) @@ -160,7 +160,7 @@ skb->nh.raw = skb->data; /* == top_iph */ skb->h.raw = skb->nh.raw + hdr_len; } else { - hdr_len = ip6_found_nexthdr(skb, &prevhdr); + hdr_len = ip6_find_1stfragopt(skb, &prevhdr); nexthdr = *prevhdr; } @@ -203,7 +203,7 @@ top_iph->payload_len = htons(skb->len - sizeof(struct ipv6hdr)); skb->nh.raw = skb->data; /* top_iph */ - ip6_found_nexthdr(skb, &prevhdr); + ip6_find_1stfragopt(skb, &prevhdr); *prevhdr = IPPROTO_COMP; ipch = (struct ipv6_comp_hdr *)((unsigned char *)top_iph + hdr_len); diff -Nru a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c --- a/net/ipv6/ipv6_sockglue.c Mon Jun 9 23:16:07 2003 +++ b/net/ipv6/ipv6_sockglue.c Mon Jun 9 23:16:07 2003 @@ -81,7 +81,7 @@ struct ip6_ra_chain *ra, *new_ra, **rap; /* RA packet may be delivered ONLY to IPPROTO_RAW socket */ - if (sk->type != SOCK_RAW || inet_sk(sk)->num != IPPROTO_RAW) + if (sk->sk_type != SOCK_RAW || inet_sk(sk)->num != IPPROTO_RAW) return -EINVAL; new_ra = (sel>=0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL; @@ -134,7 +134,7 @@ int val, valbool; int retv = -ENOPROTOOPT; - if(level==SOL_IP && sk->type != SOCK_RAW) + if (level == SOL_IP && sk->sk_type != SOCK_RAW) return udp_prot.setsockopt(sk, level, optname, optval, optlen); if(level!=SOL_IPV6) @@ -156,11 +156,11 @@ struct ipv6_txoptions *opt; struct sk_buff *pktopt; - if (sk->protocol != IPPROTO_UDP && - sk->protocol != IPPROTO_TCP) + if (sk->sk_protocol != IPPROTO_UDP && + sk->sk_protocol != IPPROTO_TCP) break; - if (sk->state != TCP_ESTABLISHED) { + if (sk->sk_state != TCP_ESTABLISHED) { retv = -ENOTCONN; break; } @@ -174,26 +174,26 @@ fl6_free_socklist(sk); ipv6_sock_mc_close(sk); - if (sk->protocol == IPPROTO_TCP) { + if (sk->sk_protocol == IPPROTO_TCP) { struct tcp_opt *tp = tcp_sk(sk); local_bh_disable(); - sock_prot_dec_use(sk->prot); + sock_prot_dec_use(sk->sk_prot); sock_prot_inc_use(&tcp_prot); local_bh_enable(); - sk->prot = &tcp_prot; + sk->sk_prot = &tcp_prot; tp->af_specific = &ipv4_specific; - sk->socket->ops = &inet_stream_ops; - sk->family = PF_INET; + sk->sk_socket->ops = &inet_stream_ops; + sk->sk_family = PF_INET; tcp_sync_mss(sk, tp->pmtu_cookie); } else { local_bh_disable(); - sock_prot_dec_use(sk->prot); + sock_prot_dec_use(sk->sk_prot); sock_prot_inc_use(&udp_prot); local_bh_enable(); - sk->prot = &udp_prot; - sk->socket->ops = &inet_dgram_ops; - sk->family = PF_INET; + sk->sk_prot = &udp_prot; + sk->sk_socket->ops = &inet_dgram_ops; + sk->sk_family = PF_INET; } opt = xchg(&np->opt, NULL); if (opt) @@ -202,7 +202,7 @@ if (pktopt) kfree_skb(pktopt); - sk->destruct = inet_sock_destruct; + sk->sk_destruct = inet_sock_destruct; #ifdef INET_REFCNT_DEBUG atomic_dec(&inet6_sock_nr); #endif @@ -264,7 +264,7 @@ int junk; fl.fl6_flowlabel = 0; - fl.oif = sk->bound_dev_if; + fl.oif = sk->sk_bound_dev_if; if (optlen == 0) goto update; @@ -295,10 +295,11 @@ goto done; update: retv = 0; - if (sk->type == SOCK_STREAM) { + if (sk->sk_type == SOCK_STREAM) { if (opt) { struct tcp_opt *tp = tcp_sk(sk); - if (!((1<<sk->state)&(TCPF_LISTEN|TCPF_CLOSE)) + if (!((1 << sk->sk_state) & + (TCPF_LISTEN | TCPF_CLOSE)) && inet_sk(sk)->daddr != LOOPBACK4_IPV6) { tp->ext_header_len = opt->opt_flen + opt->opt_nflen; tcp_sync_mss(sk, tp->pmtu_cookie); @@ -307,9 +308,9 @@ opt = xchg(&np->opt, opt); sk_dst_reset(sk); } else { - write_lock(&sk->dst_lock); + write_lock(&sk->sk_dst_lock); opt = xchg(&np->opt, opt); - write_unlock(&sk->dst_lock); + write_unlock(&sk->sk_dst_lock); sk_dst_reset(sk); } @@ -326,7 +327,7 @@ break; case IPV6_MULTICAST_HOPS: - if (sk->type == SOCK_STREAM) + if (sk->sk_type == SOCK_STREAM) goto e_inval; if (val > 255 || val < -1) goto e_inval; @@ -340,9 +341,9 @@ break; case IPV6_MULTICAST_IF: - if (sk->type == SOCK_STREAM) + if (sk->sk_type == SOCK_STREAM) goto e_inval; - if (sk->bound_dev_if && sk->bound_dev_if != val) + if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != val) goto e_inval; if (__dev_get_by_index(val) == NULL) { @@ -488,7 +489,7 @@ case IPV6_RECVERR: np->recverr = valbool; if (!val) - skb_queue_purge(&sk->error_queue); + skb_queue_purge(&sk->sk_error_queue); retv = 0; break; case IPV6_FLOWINFO_SEND: @@ -528,7 +529,7 @@ int len; int val; - if(level==SOL_IP && sk->type != SOCK_RAW) + if (level == SOL_IP && sk->sk_type != SOCK_RAW) return udp_prot.getsockopt(sk, level, optname, optval, optlen); if(level!=SOL_IPV6) return -ENOPROTOOPT; @@ -536,12 +537,12 @@ return -EFAULT; switch (optname) { case IPV6_ADDRFORM: - if (sk->protocol != IPPROTO_UDP && - sk->protocol != IPPROTO_TCP) + if (sk->sk_protocol != IPPROTO_UDP && + sk->sk_protocol != IPPROTO_TCP) return -EINVAL; - if (sk->state != TCP_ESTABLISHED) + if (sk->sk_state != TCP_ESTABLISHED) return -ENOTCONN; - val = sk->family; + val = sk->sk_family; break; case MCAST_MSFILTER: { @@ -564,7 +565,7 @@ struct msghdr msg; struct sk_buff *skb; - if (sk->type != SOCK_STREAM) + if (sk->sk_type != SOCK_STREAM) return -ENOPROTOOPT; msg.msg_control = optval; diff -Nru a/net/ipv6/ipv6_syms.c b/net/ipv6/ipv6_syms.c --- a/net/ipv6/ipv6_syms.c Mon Jun 9 23:16:15 2003 +++ b/net/ipv6/ipv6_syms.c Mon Jun 9 23:16:15 2003 @@ -35,6 +35,12 @@ EXPORT_SYMBOL(in6addr_any); EXPORT_SYMBOL(in6addr_loopback); EXPORT_SYMBOL(in6_dev_finish_destroy); -EXPORT_SYMBOL(ip6_found_nexthdr); +EXPORT_SYMBOL(ip6_find_1stfragopt); EXPORT_SYMBOL(xfrm6_rcv); EXPORT_SYMBOL(xfrm6_clear_mutable_options); +EXPORT_SYMBOL(rt6_lookup); +EXPORT_SYMBOL(fl6_sock_lookup); +EXPORT_SYMBOL(ipv6_ext_hdr); +EXPORT_SYMBOL(ip6_append_data); +EXPORT_SYMBOL(ip6_flush_pending_frames); +EXPORT_SYMBOL(ip6_push_pending_frames); diff -Nru a/net/ipv6/mcast.c b/net/ipv6/mcast.c --- a/net/ipv6/mcast.c Mon Jun 9 23:16:17 2003 +++ b/net/ipv6/mcast.c Mon Jun 9 23:16:17 2003 @@ -2176,8 +2176,8 @@ } sk = igmp6_socket->sk; - sk->allocation = GFP_ATOMIC; - sk->prot->unhash(sk); + sk->sk_allocation = GFP_ATOMIC; + sk->sk_prot->unhash(sk); np = inet6_sk(sk); np->hop_limit = 1; diff -Nru a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c --- a/net/ipv6/ndisc.c Mon Jun 9 23:16:14 2003 +++ b/net/ipv6/ndisc.c Mon Jun 9 23:16:14 2003 @@ -389,9 +389,14 @@ return -EINVAL; } -static inline void ndisc_rt_init(struct rt6_info *rt, struct net_device *dev, - struct neighbour *neigh) +static inline struct dst_entry *ndisc_dst_alloc(struct net_device *dev, + struct neighbour *neigh) { + struct rt6_info *rt = ip6_dst_alloc(); + + if (unlikely(rt == NULL)) + goto out; + rt->rt6i_dev = dev; rt->rt6i_nexthop = neigh; rt->rt6i_expires = 0; @@ -399,6 +404,8 @@ rt->rt6i_metric = 0; rt->u.dst.metrics[RTAX_HOPLIMIT-1] = 255; rt->u.dst.output = ndisc_output; +out: + return (struct dst_entry *)rt; } static inline void ndisc_flow_init(struct flowi *fl, u8 type, @@ -420,7 +427,6 @@ struct inet6_ifaddr *ifp; struct inet6_dev *idev; struct flowi fl; - struct rt6_info *rt = NULL; struct dst_entry* dst; struct sock *sk = ndisc_socket->sk; struct in6_addr *src_addr; @@ -431,27 +437,22 @@ len = sizeof(struct icmp6hdr) + sizeof(struct in6_addr); - rt = ip6_dst_alloc(); - if (!rt) - return; - /* for anycast or proxy, solicited_addr != src_addr */ ifp = ipv6_get_ifaddr(solicited_addr, dev); if (ifp) { src_addr = solicited_addr; in6_ifa_put(ifp); } else { - if (ipv6_dev_get_saddr(dev, daddr, &tmpaddr, 0)) { - dst_free(dst); + if (ipv6_dev_get_saddr(dev, daddr, &tmpaddr, 0)) return; - } src_addr = &tmpaddr; } ndisc_flow_init(&fl, NDISC_NEIGHBOUR_ADVERTISEMENT, src_addr, daddr); - ndisc_rt_init(rt, dev, neigh); - dst = (struct dst_entry*)rt; + dst = ndisc_dst_alloc(dev, neigh); + if (!dst) + return; err = xfrm_lookup(&dst, &fl, NULL, 0); if (err < 0) { @@ -518,7 +519,6 @@ struct in6_addr *daddr, struct in6_addr *saddr) { struct flowi fl; - struct rt6_info *rt = NULL; struct dst_entry* dst; struct inet6_dev *idev; struct sock *sk = ndisc_socket->sk; @@ -535,14 +535,11 @@ saddr = &addr_buf; } - rt = ip6_dst_alloc(); - if (!rt) - return; - ndisc_flow_init(&fl, NDISC_NEIGHBOUR_SOLICITATION, saddr, daddr); - ndisc_rt_init(rt, dev, neigh); - dst = (struct dst_entry*)rt; + dst = ndisc_dst_alloc(dev, neigh); + if (!dst) + return; dst_clone(dst); err = xfrm_lookup(&dst, &fl, NULL, 0); @@ -601,7 +598,6 @@ struct in6_addr *daddr) { struct flowi fl; - struct rt6_info *rt = NULL; struct dst_entry* dst; struct inet6_dev *idev; struct sock *sk = ndisc_socket->sk; @@ -611,14 +607,11 @@ int len; int err; - rt = ip6_dst_alloc(); - if (!rt) - return; - ndisc_flow_init(&fl, NDISC_ROUTER_SOLICITATION, saddr, daddr); - ndisc_rt_init(rt, dev, NULL); - dst = (struct dst_entry*)rt; + dst = ndisc_dst_alloc(dev, NULL); + if (!dst) + return; dst_clone(dst); err = xfrm_lookup(&dst, &fl, NULL, 0); @@ -1299,12 +1292,6 @@ int hlen; dev = skb->dev; - rt = rt6_lookup(&skb->nh.ipv6h->saddr, NULL, dev->ifindex, 1); - - if (rt == NULL) - return; - - dst = (struct dst_entry*)rt; if (ipv6_get_lladdr(dev, &saddr_buf)) { ND_PRINTK1("redirect: no link_local addr for dev\n"); @@ -1313,7 +1300,12 @@ ndisc_flow_init(&fl, NDISC_REDIRECT, &saddr_buf, &skb->nh.ipv6h->saddr); + rt = rt6_lookup(&skb->nh.ipv6h->saddr, NULL, dev->ifindex, 1); + if (rt == NULL) + return; + dst = &rt->u.dst; dst_clone(dst); + err = xfrm_lookup(&dst, &fl, NULL, 0); if (err) { dst_release(dst); @@ -1474,11 +1466,11 @@ sk = ndisc_socket->sk; np = inet6_sk(sk); - sk->allocation = GFP_ATOMIC; + sk->sk_allocation = GFP_ATOMIC; np->hop_limit = 255; /* Do not loopback ndisc messages */ np->mc_loop = 0; - sk->prot->unhash(sk); + sk->sk_prot->unhash(sk); /* * Initialize the neighbour table diff -Nru a/net/ipv6/netfilter/ip6_queue.c b/net/ipv6/netfilter/ip6_queue.c --- a/net/ipv6/netfilter/ip6_queue.c Mon Jun 9 23:16:09 2003 +++ b/net/ipv6/netfilter/ip6_queue.c Mon Jun 9 23:16:09 2003 @@ -538,14 +538,14 @@ if (down_trylock(&ipqnl_sem)) return; - while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) { + while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { ipq_rcv_skb(skb); kfree_skb(skb); } up(&ipqnl_sem); - } while (ipqnl && ipqnl->receive_queue.qlen); + } while (ipqnl && ipqnl->sk_receive_queue.qlen); } static int @@ -694,7 +694,7 @@ proc_net_remove(IPQ_PROC_FS_NAME); cleanup_ipqnl: - sock_release(ipqnl->socket); + sock_release(ipqnl->sk_socket); down(&ipqnl_sem); up(&ipqnl_sem); diff -Nru a/net/ipv6/netfilter/ip6t_owner.c b/net/ipv6/netfilter/ip6t_owner.c --- a/net/ipv6/netfilter/ip6t_owner.c Mon Jun 9 23:16:17 2003 +++ b/net/ipv6/netfilter/ip6t_owner.c Mon Jun 9 23:16:17 2003 @@ -31,7 +31,7 @@ if(files) { spin_lock(&files->file_lock); for (i=0; i < files->max_fds; i++) { - if (fcheck_files(files, i) == skb->sk->socket->file) { + if (fcheck_files(files, i) == skb->sk->sk_socket->file) { spin_unlock(&files->file_lock); task_unlock(p); read_unlock(&tasklist_lock); @@ -50,7 +50,7 @@ match_sid(const struct sk_buff *skb, pid_t sid) { struct task_struct *g, *p; - struct file *file = skb->sk->socket->file; + struct file *file = skb->sk->sk_socket->file; int i, found=0; read_lock(&tasklist_lock); @@ -93,17 +93,17 @@ { const struct ip6t_owner_info *info = matchinfo; - if (!skb->sk || !skb->sk->socket || !skb->sk->socket->file) + if (!skb->sk || !skb->sk->sk_socket || !skb->sk->sk_socket->file) return 0; if(info->match & IP6T_OWNER_UID) { - if((skb->sk->socket->file->f_uid != info->uid) ^ + if((skb->sk->sk_socket->file->f_uid != info->uid) ^ !!(info->invert & IP6T_OWNER_UID)) return 0; } if(info->match & IP6T_OWNER_GID) { - if((skb->sk->socket->file->f_gid != info->gid) ^ + if((skb->sk->sk_socket->file->f_gid != info->gid) ^ !!(info->invert & IP6T_OWNER_GID)) return 0; } diff -Nru a/net/ipv6/proc.c b/net/ipv6/proc.c --- a/net/ipv6/proc.c Mon Jun 9 23:16:10 2003 +++ b/net/ipv6/proc.c Mon Jun 9 23:16:10 2003 @@ -228,7 +228,8 @@ if (!idev || !idev->dev) return -EINVAL; - if (snmp6_mib_init((void **)idev->stats.icmpv6, sizeof(struct icmpv6_mib)) < 0) + if (snmp6_mib_init((void **)idev->stats.icmpv6, sizeof(struct icmpv6_mib), + __alignof__(struct ipv6_mib)) < 0) goto err_icmp; #ifdef CONFIG_PROC_FS @@ -299,11 +300,10 @@ goto out; } -int ipv6_misc_proc_exit(void) +void ipv6_misc_proc_exit(void) { proc_net_remove("sockstat6"); proc_net_remove("dev_snmp6"); proc_net_remove("snmp6"); - return 0; } diff -Nru a/net/ipv6/raw.c b/net/ipv6/raw.c --- a/net/ipv6/raw.c Mon Jun 9 23:16:10 2003 +++ b/net/ipv6/raw.c Mon Jun 9 23:16:10 2003 @@ -62,11 +62,11 @@ (RAWV6_HTABLE_SIZE - 1)]; write_lock_bh(&raw_v6_lock); - if ((sk->next = *skp) != NULL) - (*skp)->pprev = &sk->next; + if ((sk->sk_next = *skp) != NULL) + (*skp)->sk_pprev = &sk->sk_next; *skp = sk; - sk->pprev = skp; - sock_prot_inc_use(sk->prot); + sk->sk_pprev = skp; + sock_prot_inc_use(sk->sk_prot); sock_hold(sk); write_unlock_bh(&raw_v6_lock); } @@ -74,12 +74,12 @@ static void raw_v6_unhash(struct sock *sk) { write_lock_bh(&raw_v6_lock); - if (sk->pprev) { - if (sk->next) - sk->next->pprev = sk->pprev; - *sk->pprev = sk->next; - sk->pprev = NULL; - sock_prot_dec_use(sk->prot); + if (sk->sk_pprev) { + if (sk->sk_next) + sk->sk_next->sk_pprev = sk->sk_pprev; + *sk->sk_pprev = sk->sk_next; + sk->sk_pprev = NULL; + sock_prot_dec_use(sk->sk_prot); __sock_put(sk); } write_unlock_bh(&raw_v6_lock); @@ -93,7 +93,7 @@ struct sock *s = sk; int addr_type = ipv6_addr_type(loc_addr); - for(s = sk; s; s = s->next) { + for (s = sk; s; s = s->sk_next) { if (inet_sk(s)->num == num) { struct ipv6_pinfo *np = inet6_sk(s); @@ -176,7 +176,7 @@ if (clone) rawv6_rcv(sk, clone); } - sk = __raw_v6_lookup(sk->next, nexthdr, daddr, saddr); + sk = __raw_v6_lookup(sk->sk_next, nexthdr, daddr, saddr); } out: read_unlock(&raw_v6_lock); @@ -203,7 +203,7 @@ lock_sock(sk); err = -EINVAL; - if (sk->state != TCP_CLOSE) + if (sk->sk_state != TCP_CLOSE) goto out; if (addr_type & IPV6_ADDR_LINKLOCAL) { @@ -212,11 +212,11 @@ /* Override any existing binding, if another one * is supplied by user. */ - sk->bound_dev_if = addr->sin6_scope_id; + sk->sk_bound_dev_if = addr->sin6_scope_id; } /* Binding to link-local address requires an interface */ - if (sk->bound_dev_if == 0) + if (!sk->sk_bound_dev_if) goto out; } @@ -257,7 +257,7 @@ 2. Socket is connected (otherwise the error indication is useless without recverr and error is hard. */ - if (!np->recverr && sk->state != TCP_ESTABLISHED) + if (!np->recverr && sk->sk_state != TCP_ESTABLISHED) return; harderr = icmpv6_err_convert(type, code, &err); @@ -272,14 +272,14 @@ } if (np->recverr || harderr) { - sk->err = err; - sk->error_report(sk); + sk->sk_err = err; + sk->sk_error_report(sk); } } static inline int rawv6_rcv_skb(struct sock * sk, struct sk_buff * skb) { - if (sk->filter && skb->ip_summed != CHECKSUM_UNNECESSARY) { + if (sk->sk_filter && skb->ip_summed != CHECKSUM_UNNECESSARY) { if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) { /* FIXME: increment a raw6 drops counter here */ kfree_skb(skb); @@ -422,12 +422,12 @@ /* Clear queue. */ if (flags&MSG_PEEK) { int clear = 0; - spin_lock_irq(&sk->receive_queue.lock); - if (skb == skb_peek(&sk->receive_queue)) { - __skb_unlink(skb, &sk->receive_queue); + spin_lock_irq(&sk->sk_receive_queue.lock); + if (skb == skb_peek(&sk->sk_receive_queue)) { + __skb_unlink(skb, &sk->sk_receive_queue); clear = 1; } - spin_unlock_irq(&sk->receive_queue.lock); + spin_unlock_irq(&sk->sk_receive_queue.lock); if (clear) kfree_skb(skb); } @@ -446,7 +446,7 @@ int err = 0; u16 *csum; - if ((skb = skb_peek(&sk->write_queue)) == NULL) + if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) goto out; if (opt->offset + 1 < len) @@ -456,7 +456,7 @@ goto out; } - if (skb_queue_len(&sk->write_queue) == 1) { + if (skb_queue_len(&sk->sk_write_queue) == 1) { /* * Only one fragment on the socket. */ @@ -467,7 +467,7 @@ } else { u32 tmp_csum = 0; - skb_queue_walk(&sk->write_queue, skb) { + skb_queue_walk(&sk->sk_write_queue, skb) { tmp_csum = csum_add(tmp_csum, skb->csum); } @@ -508,7 +508,7 @@ goto error; skb_reserve(skb, hh_len); - skb->priority = sk->priority; + skb->priority = sk->sk_priority; skb->dst = dst_clone(&rt->u.dst); skb->nh.ipv6h = iph = (struct ipv6hdr *)skb_put(skb, length); @@ -597,8 +597,11 @@ } } - /* Otherwise it will be difficult to maintain sk->dst_cache. */ - if (sk->state == TCP_ESTABLISHED && + /* + * Otherwise it will be difficult to maintain + * sk->sk_dst_cache. + */ + if (sk->sk_state == TCP_ESTABLISHED && !ipv6_addr_cmp(daddr, &np->daddr)) daddr = &np->daddr; @@ -607,7 +610,7 @@ ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL) fl.oif = sin6->sin6_scope_id; } else { - if (sk->state != TCP_ESTABLISHED) + if (sk->sk_state != TCP_ESTABLISHED) return(-EINVAL); proto = inet->num; @@ -625,7 +628,7 @@ } if (fl.oif == 0) - fl.oif = sk->bound_dev_if; + fl.oif = sk->sk_bound_dev_if; if (msg->msg_controllen) { opt = &opt_space; @@ -857,7 +860,7 @@ switch(cmd) { case SIOCOUTQ: { - int amount = atomic_read(&sk->wmem_alloc); + int amount = atomic_read(&sk->sk_wmem_alloc); return put_user(amount, (int *)arg); } case SIOCINQ: @@ -865,11 +868,11 @@ struct sk_buff *skb; int amount = 0; - spin_lock_irq(&sk->receive_queue.lock); - skb = skb_peek(&sk->receive_queue); + spin_lock_irq(&sk->sk_receive_queue.lock); + skb = skb_peek(&sk->sk_receive_queue); if (skb != NULL) amount = skb->tail - skb->h.raw; - spin_unlock_irq(&sk->receive_queue.lock); + spin_unlock_irq(&sk->sk_receive_queue.lock); return put_user(amount, (int *)arg); } @@ -928,8 +931,8 @@ for (state->bucket = 0; state->bucket < RAWV6_HTABLE_SIZE; ++state->bucket) { sk = raw_v6_htable[state->bucket]; - while (sk && sk->family != PF_INET6) - sk = sk->next; + while (sk && sk->sk_family != PF_INET6) + sk = sk->sk_next; if (sk) break; } @@ -941,10 +944,10 @@ struct raw6_iter_state* state = raw6_seq_private(seq); do { - sk = sk->next; + sk = sk->sk_next; try_again: ; - } while (sk && sk->family != PF_INET6); + } while (sk && sk->sk_family != PF_INET6); if (!sk && ++state->bucket < RAWV6_HTABLE_SIZE) { sk = raw_v6_htable[state->bucket]; @@ -1003,12 +1006,13 @@ src->s6_addr32[2], src->s6_addr32[3], srcp, dest->s6_addr32[0], dest->s6_addr32[1], dest->s6_addr32[2], dest->s6_addr32[3], destp, - sp->state, - atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc), + sp->sk_state, + atomic_read(&sp->sk_wmem_alloc), + atomic_read(&sp->sk_rmem_alloc), 0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp), - atomic_read(&sp->refcnt), sp); + atomic_read(&sp->sk_refcnt), sp); } static int raw6_seq_show(struct seq_file *seq, void *v) diff -Nru a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c --- a/net/ipv6/reassembly.c Mon Jun 9 23:16:09 2003 +++ b/net/ipv6/reassembly.c Mon Jun 9 23:16:09 2003 @@ -24,6 +24,9 @@ * Alexey Kuznetsov SMP races, threading, cleanup. * Patrick McHardy LRU queue of frag heads for evictor. * Mitsuru KANDA @USAGI Register inet6_protocol{}. + * David Stevens and + * YOSHIFUJI,H. @USAGI Always remove fragment header to + * calculate ICV correctly. */ #include <linux/config.h> #include <linux/errno.h> @@ -38,6 +41,8 @@ #include <linux/in6.h> #include <linux/ipv6.h> #include <linux/icmpv6.h> +#include <linux/random.h> +#include <linux/jhash.h> #include <net/sock.h> #include <net/snmp.h> @@ -49,10 +54,10 @@ #include <net/ndisc.h> #include <net/addrconf.h> -static int sysctl_ip6frag_high_thresh = 256*1024; -static int sysctl_ip6frag_low_thresh = 192*1024; +int sysctl_ip6frag_high_thresh = 256*1024; +int sysctl_ip6frag_low_thresh = 192*1024; -static int sysctl_ip6frag_time = IPV6_FRAG_TIMEOUT; +int sysctl_ip6frag_time = IPV6_FRAG_TIMEOUT; struct ip6frag_skb_cb { @@ -99,6 +104,7 @@ static struct frag_queue *ip6_frag_hash[IP6Q_HASHSZ]; static rwlock_t ip6_frag_lock = RW_LOCK_UNLOCKED; +static u32 ip6_frag_hash_rnd; static LIST_HEAD(ip6_frag_lru_list); int ip6_frag_nqueues = 0; @@ -118,16 +124,73 @@ write_unlock(&ip6_frag_lock); } -static __inline__ unsigned int ip6qhashfn(u32 id, struct in6_addr *saddr, - struct in6_addr *daddr) +static unsigned int ip6qhashfn(u32 id, struct in6_addr *saddr, + struct in6_addr *daddr) { - unsigned int h = saddr->s6_addr32[3] ^ daddr->s6_addr32[3] ^ id; + u32 a, b, c; - h ^= (h>>16); - h ^= (h>>8); - return h & (IP6Q_HASHSZ - 1); + a = saddr->s6_addr32[0]; + b = saddr->s6_addr32[1]; + c = saddr->s6_addr32[2]; + + a += JHASH_GOLDEN_RATIO; + b += JHASH_GOLDEN_RATIO; + c += ip6_frag_hash_rnd; + __jhash_mix(a, b, c); + + a += saddr->s6_addr32[3]; + b += daddr->s6_addr32[0]; + c += daddr->s6_addr32[1]; + __jhash_mix(a, b, c); + + a += daddr->s6_addr32[2]; + b += daddr->s6_addr32[3]; + c += id; + __jhash_mix(a, b, c); + + return c & (IP6Q_HASHSZ - 1); } +static struct timer_list ip6_frag_secret_timer; +int sysctl_ip6frag_secret_interval = 10 * 60 * HZ; + +static void ip6_frag_secret_rebuild(unsigned long dummy) +{ + unsigned long now = jiffies; + int i; + + write_lock(&ip6_frag_lock); + get_random_bytes(&ip6_frag_hash_rnd, sizeof(u32)); + for (i = 0; i < IP6Q_HASHSZ; i++) { + struct frag_queue *q; + + q = ip6_frag_hash[i]; + while (q) { + struct frag_queue *next = q->next; + unsigned int hval = ip6qhashfn(q->id, + &q->saddr, + &q->daddr); + + if (hval != i) { + /* Unlink. */ + if (q->next) + q->next->pprev = q->pprev; + *q->pprev = q->next; + + /* Relink to new hash chain. */ + if ((q->next = ip6_frag_hash[hval]) != NULL) + q->next->pprev = &q->next; + ip6_frag_hash[hval] = q; + q->pprev = &ip6_frag_hash[hval]; + } + + q = next; + } + } + write_unlock(&ip6_frag_lock); + + mod_timer(&ip6_frag_secret_timer, now + sysctl_ip6frag_secret_interval); +} atomic_t ip6_frag_mem = ATOMIC_INIT(0); @@ -524,7 +587,6 @@ struct net_device *dev) { struct sk_buff *fp, *head = fq->fragments; - int remove_fraghdr = 0; int payload_len; unsigned int nhoff; @@ -537,12 +599,8 @@ payload_len = (head->data - head->nh.raw) - sizeof(struct ipv6hdr) + fq->len; nhoff = head->h.raw - head->nh.raw; - if (payload_len > 65535) { - payload_len -= 8; - if (payload_len > 65535) - goto out_oversize; - remove_fraghdr = 1; - } + if (payload_len > 65535 + 8) + goto out_oversize; /* Head of list must not be cloned. */ if (skb_cloned(head) && pskb_expand_head(head, 0, 0, GFP_ATOMIC)) @@ -571,18 +629,13 @@ atomic_add(clone->truesize, &ip6_frag_mem); } - /* Normally we do not remove frag header from datagram, but - * we have to do this and to relocate header, when payload - * is > 65535-8. */ - if (remove_fraghdr) { - nhoff = fq->nhoffset; - head->nh.raw[nhoff] = head->h.raw[0]; - memmove(head->head+8, head->head, (head->data-head->head)-8); - head->mac.raw += 8; - head->nh.raw += 8; - } else { - ((struct frag_hdr*)head->h.raw)->frag_off = 0; - } + /* We have to remove fragment header from datagram and to relocate + * header in order to calculate ICV correctly. */ + nhoff = fq->nhoffset; + head->nh.raw[nhoff] = head->h.raw[0]; + memmove(head->head+8, head->head, (head->data-head->head)-8); + head->mac.raw += 8; + head->nh.raw += 8; skb_shinfo(head)->frag_list = head->next; head->h.raw = head->data; @@ -696,4 +749,12 @@ { if (inet6_add_protocol(&frag_protocol, IPPROTO_FRAGMENT) < 0) printk(KERN_ERR "ipv6_frag_init: Could not register protocol\n"); + + ip6_frag_hash_rnd = (u32) ((num_physpages ^ (num_physpages>>7)) ^ + (jiffies ^ (jiffies >> 6))); + + init_timer(&ip6_frag_secret_timer); + ip6_frag_secret_timer.function = ip6_frag_secret_rebuild; + ip6_frag_secret_timer.expires = jiffies + sysctl_ip6frag_secret_interval; + add_timer(&ip6_frag_secret_timer); } diff -Nru a/net/ipv6/route.c b/net/ipv6/route.c --- a/net/ipv6/route.c Mon Jun 9 23:16:16 2003 +++ b/net/ipv6/route.c Mon Jun 9 23:16:16 2003 @@ -253,13 +253,15 @@ } } for (sprt = rt; - !match && sprt && sprt != rt6_dflt_pointer; + !match && sprt; sprt = sprt->u.next) { if (sprt->u.dst.obsolete <= 0 && sprt->u.dst.error == 0) { match = sprt; break; } + if (sprt == rt6_dflt_pointer) + break; } } } @@ -334,7 +336,7 @@ return err; } -/* No rt6_lock! If COW faild, the function returns dead route entry +/* No rt6_lock! If COW failed, the function returns dead route entry with dst->error set to errno value. */ @@ -585,19 +587,6 @@ Remove it only when all the things will work! */ -static void ipv6_addr_prefix(struct in6_addr *pfx, - const struct in6_addr *addr, int plen) -{ - int b = plen&0x7; - int o = plen>>3; - - memcpy(pfx->s6_addr, addr, o); - if (o < 16) - memset(pfx->s6_addr + o, 0, 16 - o); - if (b != 0) - pfx->s6_addr[o] = addr->s6_addr[o]&(0xff00 >> b); -} - static int ipv6_get_mtu(struct net_device *dev) { int mtu = IPV6_MIN_MTU; @@ -1218,10 +1207,12 @@ if (rt == NULL) return -ENOMEM; + dev_hold(&loopback_dev); + rt->u.dst.flags = DST_HOST; rt->u.dst.input = ip6_input; rt->u.dst.output = ip6_output; - rt->rt6i_dev = dev_get_by_name("lo"); + rt->rt6i_dev = &loopback_dev; rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev); rt->u.dst.metrics[RTAX_ADVMSS-1] = max_t(unsigned int, dst_pmtu(&rt->u.dst) - 60, ip6_rt_min_advmss); if (rt->u.dst.metrics[RTAX_ADVMSS-1] > 65535-20) @@ -1784,11 +1775,12 @@ static int rt6_stats_seq_show(struct seq_file *seq, void *v) { - seq_printf(seq, "%04x %04x %04x %04x %04x %04x\n", + seq_printf(seq, "%04x %04x %04x %04x %04x %04x %04x\n", rt6_stats.fib_nodes, rt6_stats.fib_route_nodes, rt6_stats.fib_rt_alloc, rt6_stats.fib_rt_entries, rt6_stats.fib_rt_cache, - atomic_read(&ip6_dst_ops.entries)); + atomic_read(&ip6_dst_ops.entries), + rt6_stats.fib_discarded_routes); return 0; } diff -Nru a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c --- a/net/ipv6/sysctl_net_ipv6.c Mon Jun 9 23:16:07 2003 +++ b/net/ipv6/sysctl_net_ipv6.c Mon Jun 9 23:16:07 2003 @@ -42,6 +42,40 @@ .mode = 0644, .proc_handler = &proc_dointvec }, + { + .ctl_name = NET_IPV6_IP6FRAG_HIGH_THRESH, + .procname = "ip6frag_high_thresh", + .data = &sysctl_ip6frag_high_thresh, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec + }, + { + .ctl_name = NET_IPV6_IP6FRAG_LOW_THRESH, + .procname = "ip6frag_low_thresh", + .data = &sysctl_ip6frag_low_thresh, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec + }, + { + .ctl_name = NET_IPV6_IP6FRAG_TIME, + .procname = "ip6frag_time", + .data = &sysctl_ip6frag_time, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_jiffies, + .strategy = &sysctl_jiffies, + }, + { + .ctl_name = NET_IPV6_IP6FRAG_SECRET_INTERVAL, + .procname = "ip6frag_secret_interval", + .data = &sysctl_ip6frag_secret_interval, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_jiffies, + .strategy = &sysctl_jiffies + }, { .ctl_name = 0 } }; diff -Nru a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c --- a/net/ipv6/tcp_ipv6.c Mon Jun 9 23:16:13 2003 +++ b/net/ipv6/tcp_ipv6.c Mon Jun 9 23:16:13 2003 @@ -101,22 +101,23 @@ if (!inet_sk(sk2)->rcv_saddr && !ipv6_only_sock(sk)) return 1; - if (sk2->family == AF_INET6 && + if (sk2->sk_family == AF_INET6 && ipv6_addr_any(&inet6_sk(sk2)->rcv_saddr) && !(ipv6_only_sock(sk2) && addr_type == IPV6_ADDR_MAPPED)) return 1; if (addr_type == IPV6_ADDR_ANY && (!ipv6_only_sock(sk) || - !(sk2->family == AF_INET6 ? - ipv6_addr_type(&inet6_sk(sk2)->rcv_saddr) == IPV6_ADDR_MAPPED : 1))) + !(sk2->sk_family == AF_INET6 ? + (ipv6_addr_type(&inet6_sk(sk2)->rcv_saddr) == IPV6_ADDR_MAPPED) : + 1))) return 1; - if (sk2->family == AF_INET6 && + if (sk2->sk_family == AF_INET6 && !ipv6_addr_cmp(&np->rcv_saddr, - (sk2->state != TCP_TIME_WAIT ? + (sk2->sk_state != TCP_TIME_WAIT ? &inet6_sk(sk2)->rcv_saddr : - &((struct tcp_tw_bucket *)sk)->v6_rcv_saddr))) + &((struct tcp_tw_bucket *)sk)->tw_v6_rcv_saddr))) return 1; if (addr_type == IPV6_ADDR_MAPPED && @@ -135,10 +136,10 @@ struct sock *sk2 = tb->owners; /* We must walk the whole port owner list in this case. -DaveM */ - for (; sk2; sk2 = sk2->bind_next) - if (sk != sk2 && sk->bound_dev_if == sk2->bound_dev_if && - (!sk->reuse || !sk2->reuse || - sk2->state == TCP_LISTEN) && + for (; sk2; sk2 = sk2->sk_bind_next) + if (sk != sk2 && sk->sk_bound_dev_if == sk2->sk_bound_dev_if && + (!sk->sk_reuse || !sk2->sk_reuse || + sk2->sk_state == TCP_LISTEN) && ipv6_rcv_saddr_equal(sk, sk2)) break; @@ -196,7 +197,8 @@ break; } if (tb != NULL && tb->owners != NULL) { - if (tb->fastreuse > 0 && sk->reuse != 0 && sk->state != TCP_LISTEN) { + if (tb->fastreuse > 0 && sk->sk_reuse && + sk->sk_state != TCP_LISTEN) { goto success; } else { ret = 1; @@ -209,18 +211,18 @@ (tb = tcp_bucket_create(head, snum)) == NULL) goto fail_unlock; if (tb->owners == NULL) { - if (sk->reuse && sk->state != TCP_LISTEN) + if (sk->sk_reuse && sk->sk_state != TCP_LISTEN) tb->fastreuse = 1; else tb->fastreuse = 0; } else if (tb->fastreuse && - ((sk->reuse == 0) || (sk->state == TCP_LISTEN))) + (!sk->sk_reuse || sk->sk_state == TCP_LISTEN)) tb->fastreuse = 0; success: - if (!sk->prev) + if (!sk->sk_prev) tcp_bind_hash(sk, tb, snum); - BUG_TRAP(sk->prev == (struct sock *)tb); + BUG_TRAP(sk->sk_prev == (struct sock *)tb); ret = 0; fail_unlock: @@ -235,30 +237,30 @@ struct sock **skp; rwlock_t *lock; - BUG_TRAP(sk->pprev==NULL); + BUG_TRAP(!sk->sk_pprev); - if(sk->state == TCP_LISTEN) { + if (sk->sk_state == TCP_LISTEN) { skp = &tcp_listening_hash[tcp_sk_listen_hashfn(sk)]; lock = &tcp_lhash_lock; tcp_listen_wlock(); } else { - skp = &tcp_ehash[(sk->hashent = tcp_v6_sk_hashfn(sk))].chain; - lock = &tcp_ehash[sk->hashent].lock; + skp = &tcp_ehash[(sk->sk_hashent = tcp_v6_sk_hashfn(sk))].chain; + lock = &tcp_ehash[sk->sk_hashent].lock; write_lock(lock); } - if((sk->next = *skp) != NULL) - (*skp)->pprev = &sk->next; + if ((sk->sk_next = *skp) != NULL) + (*skp)->sk_pprev = &sk->sk_next; *skp = sk; - sk->pprev = skp; - sock_prot_inc_use(sk->prot); + sk->sk_pprev = skp; + sock_prot_inc_use(sk->sk_prot); write_unlock(lock); } static void tcp_v6_hash(struct sock *sk) { - if(sk->state != TCP_CLOSE) { + if (sk->sk_state != TCP_CLOSE) { struct tcp_opt *tp = tcp_sk(sk); if (tp->af_specific == &ipv6_mapped) { @@ -280,8 +282,8 @@ hiscore=0; read_lock(&tcp_lhash_lock); sk = tcp_listening_hash[tcp_lhashfn(hnum)]; - for(; sk; sk = sk->next) { - if (inet_sk(sk)->num == hnum && sk->family == PF_INET6) { + for (; sk; sk = sk->sk_next) { + if (inet_sk(sk)->num == hnum && sk->sk_family == PF_INET6) { struct ipv6_pinfo *np = inet6_sk(sk); score = 1; @@ -290,8 +292,8 @@ continue; score++; } - if (sk->bound_dev_if) { - if (sk->bound_dev_if != dif) + if (sk->sk_bound_dev_if) { + if (sk->sk_bound_dev_if != dif) continue; score++; } @@ -332,21 +334,21 @@ hash = tcp_v6_hashfn(daddr, hnum, saddr, sport); head = &tcp_ehash[hash]; read_lock(&head->lock); - for(sk = head->chain; sk; sk = sk->next) { + for (sk = head->chain; sk; sk = sk->sk_next) { /* For IPV6 do the cheaper port and family tests first. */ if(TCP_IPV6_MATCH(sk, saddr, daddr, ports, dif)) goto hit; /* You sunk my battleship! */ } /* Must check for a TIME_WAIT'er before going to listener hash. */ - for(sk = (head + tcp_ehash_size)->chain; sk; sk = sk->next) { + for (sk = (head + tcp_ehash_size)->chain; sk; sk = sk->sk_next) { /* FIXME: acme: check this... */ struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)sk; - if(*((__u32 *)&(tw->dport)) == ports && - sk->family == PF_INET6) { - if(!ipv6_addr_cmp(&tw->v6_daddr, saddr) && - !ipv6_addr_cmp(&tw->v6_rcv_saddr, daddr) && - (!sk->bound_dev_if || sk->bound_dev_if == dif)) + if(*((__u32 *)&(tw->tw_dport)) == ports && + sk->sk_family == PF_INET6) { + if(!ipv6_addr_cmp(&tw->tw_v6_daddr, saddr) && + !ipv6_addr_cmp(&tw->tw_v6_rcv_saddr, daddr) && + (!sk->sk_bound_dev_if || sk->sk_bound_dev_if == dif)) goto hit; } } @@ -394,9 +396,22 @@ static u32 tcp_v6_synq_hash(struct in6_addr *raddr, u16 rport, u32 rnd) { - return (jhash_3words(raddr->s6_addr32[0] ^ raddr->s6_addr32[1], - raddr->s6_addr32[2] ^ raddr->s6_addr32[3], - (u32) rport, rnd) & (TCP_SYNQ_HSIZE - 1)); + u32 a, b, c; + + a = raddr->s6_addr32[0]; + b = raddr->s6_addr32[1]; + c = raddr->s6_addr32[2]; + + a += JHASH_GOLDEN_RATIO; + b += JHASH_GOLDEN_RATIO; + c += rnd; + __jhash_mix(a, b, c); + + a += raddr->s6_addr32[3]; + b += (u32) rport; + __jhash_mix(a, b, c); + + return c & (TCP_SYNQ_HSIZE - 1); } static struct open_request *tcp_v6_search_req(struct tcp_opt *tp, @@ -455,7 +470,7 @@ struct ipv6_pinfo *np = inet6_sk(sk); struct in6_addr *daddr = &np->rcv_saddr; struct in6_addr *saddr = &np->daddr; - int dif = sk->bound_dev_if; + int dif = sk->sk_bound_dev_if; u32 ports = TCP_COMBINED_PORTS(inet->dport, inet->num); int hash = tcp_v6_hashfn(daddr, inet->num, saddr, inet->dport); struct tcp_ehash_bucket *head = &tcp_ehash[hash]; @@ -464,22 +479,24 @@ write_lock_bh(&head->lock); - for(skp = &(head + tcp_ehash_size)->chain; (sk2=*skp)!=NULL; skp = &sk2->next) { + for (skp = &(head + tcp_ehash_size)->chain; (sk2 = *skp) != NULL; + skp = &sk2->sk_next) { tw = (struct tcp_tw_bucket*)sk2; - if(*((__u32 *)&(tw->dport)) == ports && - sk2->family == PF_INET6 && - !ipv6_addr_cmp(&tw->v6_daddr, saddr) && - !ipv6_addr_cmp(&tw->v6_rcv_saddr, daddr) && - sk2->bound_dev_if == sk->bound_dev_if) { + if(*((__u32 *)&(tw->tw_dport)) == ports && + sk2->sk_family == PF_INET6 && + !ipv6_addr_cmp(&tw->tw_v6_daddr, saddr) && + !ipv6_addr_cmp(&tw->tw_v6_rcv_saddr, daddr) && + sk2->sk_bound_dev_if == sk->sk_bound_dev_if) { struct tcp_opt *tp = tcp_sk(sk); - if (tw->ts_recent_stamp) { + if (tw->tw_ts_recent_stamp) { /* See comment in tcp_ipv4.c */ - if ((tp->write_seq = tw->snd_nxt+65535+2) == 0) + tp->write_seq = tw->tw_snd_nxt + 65535 + 2; + if (!tp->write_seq) tp->write_seq = 1; - tp->ts_recent = tw->ts_recent; - tp->ts_recent_stamp = tw->ts_recent_stamp; + tp->ts_recent = tw->tw_ts_recent; + tp->ts_recent_stamp = tw->tw_ts_recent_stamp; sock_hold(sk2); skp = &head->chain; goto unique; @@ -489,20 +506,20 @@ } tw = NULL; - for(skp = &head->chain; (sk2=*skp)!=NULL; skp = &sk2->next) { + for (skp = &head->chain; (sk2 = *skp) != NULL; skp = &sk2->sk_next) { if(TCP_IPV6_MATCH(sk, saddr, daddr, ports, dif)) goto not_unique; } unique: - BUG_TRAP(sk->pprev==NULL); - if ((sk->next = *skp) != NULL) - (*skp)->pprev = &sk->next; + BUG_TRAP(!sk->sk_pprev); + if ((sk->sk_next = *skp) != NULL) + (*skp)->sk_pprev = &sk->sk_next; *skp = sk; - sk->pprev = skp; - sk->hashent = hash; - sock_prot_inc_use(sk->prot); + sk->sk_pprev = skp; + sk->sk_hashent = hash; + sock_prot_inc_use(sk->sk_prot); write_unlock_bh(&head->lock); if (tw) { @@ -539,7 +556,7 @@ spin_lock_bh(&head->lock); - if (tb->owners == sk && sk->bind_next == NULL) { + if (tb->owners == sk && !sk->sk_bind_next) { __tcp_v6_hash(sk); spin_unlock_bh(&head->lock); return 0; @@ -608,15 +625,15 @@ /* If interface is set while binding, indices * must coincide. */ - if (sk->bound_dev_if && - sk->bound_dev_if != usin->sin6_scope_id) + if (sk->sk_bound_dev_if && + sk->sk_bound_dev_if != usin->sin6_scope_id) return -EINVAL; - sk->bound_dev_if = usin->sin6_scope_id; + sk->sk_bound_dev_if = usin->sin6_scope_id; } /* Connect to link-local address requires an interface */ - if (sk->bound_dev_if == 0) + if (!sk->sk_bound_dev_if) return -EINVAL; } @@ -648,14 +665,14 @@ sin.sin_addr.s_addr = usin->sin6_addr.s6_addr32[3]; tp->af_specific = &ipv6_mapped; - sk->backlog_rcv = tcp_v4_do_rcv; + sk->sk_backlog_rcv = tcp_v4_do_rcv; err = tcp_v4_connect(sk, (struct sockaddr *)&sin, sizeof(sin)); if (err) { tp->ext_header_len = exthdrlen; tp->af_specific = &ipv6_specific; - sk->backlog_rcv = tcp_v6_do_rcv; + sk->sk_backlog_rcv = tcp_v6_do_rcv; goto failure; } else { ipv6_addr_set(&np->saddr, 0, 0, htonl(0x0000FFFF), @@ -674,7 +691,7 @@ ipv6_addr_copy(&fl.fl6_dst, &np->daddr); ipv6_addr_copy(&fl.fl6_src, (saddr ? saddr : &np->saddr)); - fl.oif = sk->bound_dev_if; + fl.oif = sk->sk_bound_dev_if; fl.fl_ip_dport = usin->sin6_port; fl.fl_ip_sport = inet->sport; @@ -691,7 +708,8 @@ } ip6_dst_store(sk, dst, NULL); - sk->route_caps = dst->dev->features&~(NETIF_F_IP_CSUM|NETIF_F_TSO); + sk->sk_route_caps = dst->dev->features & + ~(NETIF_F_IP_CSUM | NETIF_F_TSO); if (saddr == NULL) { err = ipv6_get_saddr(dst, &np->daddr, &saddr_buf); @@ -735,7 +753,7 @@ failure: __sk_dst_reset(sk); inet->dport = 0; - sk->route_caps = 0; + sk->sk_route_caps = 0; return err; } @@ -757,7 +775,7 @@ return; } - if (sk->state == TCP_TIME_WAIT) { + if (sk->sk_state == TCP_TIME_WAIT) { tcp_tw_put((struct tcp_tw_bucket*)sk); return; } @@ -766,12 +784,13 @@ if (sock_owned_by_user(sk)) NET_INC_STATS_BH(LockDroppedIcmps); - if (sk->state == TCP_CLOSE) + if (sk->sk_state == TCP_CLOSE) goto out; tp = tcp_sk(sk); seq = ntohl(th->seq); - if (sk->state != TCP_LISTEN && !between(seq, tp->snd_una, tp->snd_nxt)) { + if (sk->sk_state != TCP_LISTEN && + !between(seq, tp->snd_una, tp->snd_nxt)) { NET_INC_STATS_BH(OutOfWindowIcmps); goto out; } @@ -783,7 +802,7 @@ if (sock_owned_by_user(sk)) goto out; - if ((1<<sk->state)&(TCPF_LISTEN|TCPF_CLOSE)) + if ((1 << sk->sk_state) & (TCPF_LISTEN | TCPF_CLOSE)) goto out; /* icmp should have updated the destination cache entry */ @@ -801,7 +820,7 @@ fl.proto = IPPROTO_TCP; ipv6_addr_copy(&fl.fl6_dst, &np->daddr); ipv6_addr_copy(&fl.fl6_src, &np->saddr); - fl.oif = sk->bound_dev_if; + fl.oif = sk->sk_bound_dev_if; fl.fl_ip_dport = inet->dport; fl.fl_ip_sport = inet->sport; @@ -810,7 +829,7 @@ dst_hold(dst); if (dst->error) { - sk->err_soft = -dst->error; + sk->sk_err_soft = -dst->error; } else if (tp->pmtu_cookie > dst_pmtu(dst)) { tcp_sync_mss(sk, dst_pmtu(dst)); tcp_simple_retransmit(sk); @@ -822,7 +841,7 @@ icmpv6_err_convert(type, code, &err); /* Might be for an open_request */ - switch (sk->state) { + switch (sk->sk_state) { struct open_request *req, **prev; case TCP_LISTEN: if (sock_owned_by_user(sk)) @@ -851,22 +870,20 @@ It can, it SYNs are crossed. --ANK */ if (!sock_owned_by_user(sk)) { TCP_INC_STATS_BH(TcpAttemptFails); - sk->err = err; - sk->error_report(sk); /* Wake people up to see the error (see connect in sock.c) */ + sk->sk_err = err; + sk->sk_error_report(sk); /* Wake people up to see the error (see connect in sock.c) */ tcp_done(sk); - } else { - sk->err_soft = err; - } + } else + sk->sk_err_soft = err; goto out; } if (!sock_owned_by_user(sk) && np->recverr) { - sk->err = err; - sk->error_report(sk); - } else { - sk->err_soft = err; - } + sk->sk_err = err; + sk->sk_error_report(sk); + } else + sk->sk_err_soft = err; out: bh_unlock_sock(sk); @@ -922,7 +939,7 @@ csum_partial((char *)th, skb->len, skb->csum)); ipv6_addr_copy(&fl.fl6_dst, &req->af.v6_req.rmt_addr); - err = ip6_xmit(sk, skb, &fl, opt); + err = ip6_xmit(sk, skb, &fl, opt, 0); if (err == NET_XMIT_CN) err = 0; } @@ -1040,7 +1057,7 @@ buff->dst = ip6_route_output(NULL, &fl); if (buff->dst->error == 0) { - ip6_xmit(NULL, buff, &fl, NULL); + ip6_xmit(NULL, buff, &fl, NULL, 0); TCP_INC_STATS_BH(TcpOutSegs); TCP_INC_STATS_BH(TcpOutRsts); return; @@ -1103,7 +1120,7 @@ buff->dst = ip6_route_output(NULL, &fl); if (buff->dst->error == 0) { - ip6_xmit(NULL, buff, &fl, NULL); + ip6_xmit(NULL, buff, &fl, NULL, 0); TCP_INC_STATS_BH(TcpOutSegs); return; } @@ -1115,8 +1132,8 @@ { struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)sk; - tcp_v6_send_ack(skb, tw->snd_nxt, tw->rcv_nxt, - tw->rcv_wnd>>tw->rcv_wscale, tw->ts_recent); + tcp_v6_send_ack(skb, tw->tw_snd_nxt, tw->tw_rcv_nxt, + tw->tw_rcv_wnd >> tw->tw_rcv_wscale, tw->tw_ts_recent); tcp_tw_put(tw); } @@ -1147,7 +1164,7 @@ tcp_v6_iif(skb)); if (nsk) { - if (nsk->state != TCP_TIME_WAIT) { + if (nsk->sk_state != TCP_TIME_WAIT) { bh_lock_sock(nsk); return nsk; } @@ -1234,10 +1251,11 @@ atomic_inc(&skb->users); req->af.v6_req.pktopts = skb; } - req->af.v6_req.iif = sk->bound_dev_if; + req->af.v6_req.iif = sk->sk_bound_dev_if; /* So that link locals have meaning */ - if (!sk->bound_dev_if && ipv6_addr_type(&req->af.v6_req.rmt_addr)&IPV6_ADDR_LINKLOCAL) + if (!sk->sk_bound_dev_if && + ipv6_addr_type(&req->af.v6_req.rmt_addr) & IPV6_ADDR_LINKLOCAL) req->af.v6_req.iif = tcp_v6_iif(skb); if (isn == 0) @@ -1299,7 +1317,7 @@ ipv6_addr_copy(&newnp->rcv_saddr, &newnp->saddr); newtp->af_specific = &ipv6_mapped; - newsk->backlog_rcv = tcp_v4_do_rcv; + newsk->sk_backlog_rcv = tcp_v4_do_rcv; newnp->pktoptions = NULL; newnp->opt = NULL; newnp->mcast_oif = tcp_v6_iif(skb); @@ -1344,7 +1362,7 @@ ipv6_addr_copy(&fl.fl6_dst, rt0->addr); } ipv6_addr_copy(&fl.fl6_src, &req->af.v6_req.loc_addr); - fl.oif = sk->bound_dev_if; + fl.oif = sk->sk_bound_dev_if; fl.fl_ip_dport = req->rmt_port; fl.fl_ip_sport = inet_sk(sk)->sport; @@ -1364,7 +1382,8 @@ #endif ip6_dst_store(newsk, dst, NULL); - sk->route_caps = dst->dev->features&~(NETIF_F_IP_CSUM|NETIF_F_TSO); + sk->sk_route_caps = dst->dev->features & + ~(NETIF_F_IP_CSUM | NETIF_F_TSO); newtcp6sk = (struct tcp6_sock *)newsk; newtcp6sk->pinet6 = &newtcp6sk->inet6; @@ -1378,7 +1397,7 @@ ipv6_addr_copy(&newnp->daddr, &req->af.v6_req.rmt_addr); ipv6_addr_copy(&newnp->saddr, &req->af.v6_req.loc_addr); ipv6_addr_copy(&newnp->rcv_saddr, &req->af.v6_req.loc_addr); - newsk->bound_dev_if = req->af.v6_req.iif; + newsk->sk_bound_dev_if = req->af.v6_req.iif; /* Now IPv6 options... @@ -1511,7 +1530,7 @@ if (np->rxopt.all) opt_skb = skb_clone(skb, GFP_ATOMIC); - if (sk->state == TCP_ESTABLISHED) { /* Fast path */ + if (sk->sk_state == TCP_ESTABLISHED) { /* Fast path */ TCP_CHECK_TIMER(sk); if (tcp_rcv_established(sk, skb, skb->h.th, skb->len)) goto reset; @@ -1524,7 +1543,7 @@ if (skb->len < (skb->h.th->doff<<2) || tcp_checksum_complete(skb)) goto csum_err; - if (sk->state == TCP_LISTEN) { + if (sk->sk_state == TCP_LISTEN) { struct sock *nsk = tcp_v6_hnd_req(sk, skb); if (!nsk) goto discard; @@ -1573,7 +1592,7 @@ */ tp = tcp_sk(sk); if (TCP_SKB_CB(opt_skb)->end_seq == tp->rcv_nxt && - !((1<<sk->state)&(TCPF_CLOSE|TCPF_LISTEN))) { + !((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_LISTEN))) { if (np->rxopt.bits.rxinfo) np->mcast_oif = tcp_v6_iif(opt_skb); if (np->rxopt.bits.rxhlim) @@ -1637,7 +1656,7 @@ goto no_tcp_socket; process: - if(sk->state == TCP_TIME_WAIT) + if (sk->sk_state == TCP_TIME_WAIT) goto do_time_wait; if (!xfrm6_policy_check(sk, XFRM_POLICY_IN, skb)) @@ -1736,7 +1755,7 @@ ipv6_addr_copy(&fl.fl6_dst, &np->daddr); ipv6_addr_copy(&fl.fl6_src, &np->saddr); fl.fl6_flowlabel = np->flow_label; - fl.oif = sk->bound_dev_if; + fl.oif = sk->sk_bound_dev_if; fl.fl_ip_dport = inet->dport; fl.fl_ip_sport = inet->sport; @@ -1750,12 +1769,13 @@ if (dst->error) { err = dst->error; dst_release(dst); - sk->route_caps = 0; + sk->sk_route_caps = 0; return err; } ip6_dst_store(sk, dst, NULL); - sk->route_caps = dst->dev->features&~(NETIF_F_IP_CSUM|NETIF_F_TSO); + sk->sk_route_caps = dst->dev->features & + ~(NETIF_F_IP_CSUM | NETIF_F_TSO); } return 0; @@ -1775,7 +1795,7 @@ ipv6_addr_copy(&fl.fl6_src, &np->saddr); fl.fl6_flowlabel = np->flow_label; IP6_ECN_flow_xmit(sk, fl.fl6_flowlabel); - fl.oif = sk->bound_dev_if; + fl.oif = sk->sk_bound_dev_if; fl.fl_ip_sport = inet->sport; fl.fl_ip_dport = inet->dport; @@ -1790,9 +1810,9 @@ dst = ip6_route_output(sk, &fl); if (dst->error) { - sk->err_soft = -dst->error; + sk->sk_err_soft = -dst->error; dst_release(dst); - return -sk->err_soft; + return -sk->sk_err_soft; } ip6_dst_store(sk, dst, NULL); @@ -1803,7 +1823,7 @@ /* Restore final destination back after routing done */ ipv6_addr_copy(&fl.fl6_dst, &np->daddr); - return ip6_xmit(sk, skb, &fl, np->opt); + return ip6_xmit(sk, skb, &fl, np->opt, 0); } static void v6_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr) @@ -1817,8 +1837,9 @@ /* We do not store received flowlabel for TCP */ sin6->sin6_flowinfo = 0; sin6->sin6_scope_id = 0; - if (sk->bound_dev_if && ipv6_addr_type(&sin6->sin6_addr)&IPV6_ADDR_LINKLOCAL) - sin6->sin6_scope_id = sk->bound_dev_if; + if (sk->sk_bound_dev_if && + ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) + sin6->sin6_scope_id = sk->sk_bound_dev_if; } static int tcp_v6_remember_stamp(struct sock *sk) @@ -1893,15 +1914,15 @@ tp->reordering = sysctl_tcp_reordering; - sk->state = TCP_CLOSE; + sk->sk_state = TCP_CLOSE; tp->af_specific = &ipv6_specific; - sk->write_space = tcp_write_space; - sk->use_write_queue = 1; + sk->sk_write_space = tcp_write_space; + sk->sk_use_write_queue = 1; - sk->sndbuf = sysctl_tcp_wmem[1]; - sk->rcvbuf = sysctl_tcp_rmem[1]; + sk->sk_sndbuf = sysctl_tcp_wmem[1]; + sk->sk_rcvbuf = sysctl_tcp_rmem[1]; atomic_inc(&tcp_sockets_allocated); @@ -1925,7 +1946,7 @@ __skb_queue_purge(&tp->ucopy.prequeue); /* Clean up a referenced TCP bind bucket. */ - if(sk->prev != NULL) + if (sk->sk_prev) tcp_put_port(sk); /* If sendmsg cached page exists, toss it. */ @@ -1990,9 +2011,9 @@ } else if (tp->pending == TCP_TIME_PROBE0) { timer_active = 4; timer_expires = tp->timeout; - } else if (timer_pending(&sp->timer)) { + } else if (timer_pending(&sp->sk_timer)) { timer_active = 2; - timer_expires = sp->timer.expires; + timer_expires = sp->sk_timer.expires; } else { timer_active = 0; timer_expires = jiffies; @@ -2006,14 +2027,14 @@ src->s6_addr32[2], src->s6_addr32[3], srcp, dest->s6_addr32[0], dest->s6_addr32[1], dest->s6_addr32[2], dest->s6_addr32[3], destp, - sp->state, + sp->sk_state, tp->write_seq-tp->snd_una, tp->rcv_nxt-tp->copied_seq, timer_active, timer_expires-jiffies, tp->retransmits, sock_i_uid(sp), tp->probes_out, sock_i_ino(sp), - atomic_read(&sp->refcnt), sp, + atomic_read(&sp->sk_refcnt), sp, tp->rto, tp->ack.ato, (tp->ack.quick<<1)|tp->ack.pingpong, tp->snd_cwnd, tp->snd_ssthresh>=0xFFFF?-1:tp->snd_ssthresh ); @@ -2024,15 +2045,15 @@ { struct in6_addr *dest, *src; __u16 destp, srcp; - int ttd = tw->ttd - jiffies; + int ttd = tw->tw_ttd - jiffies; if (ttd < 0) ttd = 0; - dest = &tw->v6_daddr; - src = &tw->v6_rcv_saddr; - destp = ntohs(tw->dport); - srcp = ntohs(tw->sport); + dest = &tw->tw_v6_daddr; + src = &tw->tw_v6_rcv_saddr; + destp = ntohs(tw->tw_dport); + srcp = ntohs(tw->tw_sport); seq_printf(seq, "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X " @@ -2042,9 +2063,9 @@ src->s6_addr32[2], src->s6_addr32[3], srcp, dest->s6_addr32[0], dest->s6_addr32[1], dest->s6_addr32[2], dest->s6_addr32[3], destp, - tw->substate, 0, 0, + tw->tw_substate, 0, 0, 3, ttd, 0, 0, 0, 0, - atomic_read(&tw->refcnt), tw); + atomic_read(&tw->tw_refcnt), tw); } static int tcp6_seq_show(struct seq_file *seq, void *v) diff -Nru a/net/ipv6/udp.c b/net/ipv6/udp.c --- a/net/ipv6/udp.c Mon Jun 9 23:16:17 2003 +++ b/net/ipv6/udp.c Mon Jun 9 23:16:17 2003 @@ -70,18 +70,18 @@ if (!inet_sk(sk2)->rcv_saddr && !ipv6_only_sock(sk)) return 1; - if (sk2->family == AF_INET6 && + if (sk2->sk_family == AF_INET6 && ipv6_addr_any(&inet6_sk(sk2)->rcv_saddr) && !(ipv6_only_sock(sk2) && addr_type == IPV6_ADDR_MAPPED)) return 1; if (addr_type == IPV6_ADDR_ANY && (!ipv6_only_sock(sk) || - !(sk2->family == AF_INET6 ? + !(sk2->sk_family == AF_INET6 ? (ipv6_addr_type(&inet6_sk(sk2)->rcv_saddr) == IPV6_ADDR_MAPPED) : 1))) return 1; - if (sk2->family == AF_INET6 && + if (sk2->sk_family == AF_INET6 && !ipv6_addr_cmp(&inet6_sk(sk)->rcv_saddr, &inet6_sk(sk2)->rcv_saddr)) return 1; @@ -126,7 +126,7 @@ do { if (++size >= best_size_so_far) goto next; - } while ((sk2 = sk2->next) != NULL); + } while ((sk2 = sk2->sk_next) != NULL); best_size_so_far = size; best = result; next:; @@ -147,24 +147,24 @@ for (sk2 = udp_hash[snum & (UDP_HTABLE_SIZE - 1)]; sk2 != NULL; - sk2 = sk2->next) { + sk2 = sk2->sk_next) { if (inet_sk(sk2)->num == snum && sk2 != sk && - sk2->bound_dev_if == sk->bound_dev_if && - (!sk2->reuse || !sk->reuse) && + sk2->sk_bound_dev_if == sk->sk_bound_dev_if && + (!sk2->sk_reuse || !sk->sk_reuse) && udv6_rcv_saddr_equal(sk, sk2)) goto fail; } } inet_sk(sk)->num = snum; - if (sk->pprev == NULL) { + if (!sk->sk_pprev) { struct sock **skp = &udp_hash[snum & (UDP_HTABLE_SIZE - 1)]; - if ((sk->next = *skp) != NULL) - (*skp)->pprev = &sk->next; + if ((sk->sk_next = *skp) != NULL) + (*skp)->sk_pprev = &sk->sk_next; *skp = sk; - sk->pprev = skp; - sock_prot_inc_use(sk->prot); + sk->sk_pprev = skp; + sock_prot_inc_use(sk->sk_prot); sock_hold(sk); } write_unlock_bh(&udp_hash_lock); @@ -183,13 +183,13 @@ static void udp_v6_unhash(struct sock *sk) { write_lock_bh(&udp_hash_lock); - if (sk->pprev) { - if (sk->next) - sk->next->pprev = sk->pprev; - *sk->pprev = sk->next; - sk->pprev = NULL; + if (sk->sk_pprev) { + if (sk->sk_next) + sk->sk_next->sk_pprev = sk->sk_pprev; + *sk->sk_pprev = sk->sk_next; + sk->sk_pprev = NULL; inet_sk(sk)->num = 0; - sock_prot_dec_use(sk->prot); + sock_prot_dec_use(sk->sk_prot); __sock_put(sk); } write_unlock_bh(&udp_hash_lock); @@ -203,10 +203,11 @@ int badness = -1; read_lock(&udp_hash_lock); - for(sk = udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]; sk != NULL; sk = sk->next) { + for (sk = udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]; sk; + sk = sk->sk_next) { struct inet_opt *inet = inet_sk(sk); - if (inet->num == hnum && sk->family == PF_INET6) { + if (inet->num == hnum && sk->sk_family == PF_INET6) { struct ipv6_pinfo *np = inet6_sk(sk); int score = 0; if (inet->dport) { @@ -224,8 +225,8 @@ continue; score++; } - if(sk->bound_dev_if) { - if(sk->bound_dev_if != dif) + if (sk->sk_bound_dev_if) { + if (sk->sk_bound_dev_if != dif) continue; score++; } @@ -254,7 +255,6 @@ struct inet_opt *inet = inet_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk); struct in6_addr *daddr; - struct in6_addr saddr; struct dst_entry *dst; struct flowi fl; struct ip6_flowlabel *flowlabel = NULL; @@ -329,17 +329,19 @@ if (addr_type&IPV6_ADDR_LINKLOCAL) { if (addr_len >= sizeof(struct sockaddr_in6) && usin->sin6_scope_id) { - if (sk->bound_dev_if && sk->bound_dev_if != usin->sin6_scope_id) { + if (sk->sk_bound_dev_if && + sk->sk_bound_dev_if != usin->sin6_scope_id) { fl6_sock_release(flowlabel); return -EINVAL; } - sk->bound_dev_if = usin->sin6_scope_id; - if (!sk->bound_dev_if && (addr_type&IPV6_ADDR_MULTICAST)) + sk->sk_bound_dev_if = usin->sin6_scope_id; + if (!sk->sk_bound_dev_if && + (addr_type & IPV6_ADDR_MULTICAST)) fl.oif = np->mcast_oif; } /* Connect to link-local address requires an interface */ - if (sk->bound_dev_if == 0) + if (!sk->sk_bound_dev_if) return -EINVAL; } @@ -355,8 +357,8 @@ fl.proto = IPPROTO_UDP; ipv6_addr_copy(&fl.fl6_dst, &np->daddr); - ipv6_addr_copy(&fl.fl6_src, &saddr); - fl.oif = sk->bound_dev_if; + ipv6_addr_copy(&fl.fl6_src, &np->saddr); + fl.oif = sk->sk_bound_dev_if; fl.fl_ip_dport = inet->dport; fl.fl_ip_sport = inet->sport; @@ -381,21 +383,24 @@ return err; } - ip6_dst_store(sk, dst, &fl.fl6_dst); - /* get the source address used in the appropriate device */ - err = ipv6_get_saddr(dst, daddr, &saddr); + err = ipv6_get_saddr(dst, daddr, &fl.fl6_src); if (err == 0) { if (ipv6_addr_any(&np->saddr)) - ipv6_addr_copy(&np->saddr, &saddr); + ipv6_addr_copy(&np->saddr, &fl.fl6_src); if (ipv6_addr_any(&np->rcv_saddr)) { - ipv6_addr_copy(&np->rcv_saddr, &saddr); + ipv6_addr_copy(&np->rcv_saddr, &fl.fl6_src); inet->rcv_saddr = LOOPBACK4_IPV6; } - sk->state = TCP_ESTABLISHED; + + ip6_dst_store(sk, dst, + !ipv6_addr_cmp(&fl.fl6_dst, &np->daddr) ? + &np->daddr : NULL); + + sk->sk_state = TCP_ESTABLISHED; } fl6_sock_release(flowlabel); @@ -492,12 +497,12 @@ /* Clear queue. */ if (flags&MSG_PEEK) { int clear = 0; - spin_lock_irq(&sk->receive_queue.lock); - if (skb == skb_peek(&sk->receive_queue)) { - __skb_unlink(skb, &sk->receive_queue); + spin_lock_irq(&sk->sk_receive_queue.lock); + if (skb == skb_peek(&sk->sk_receive_queue)) { + __skb_unlink(skb, &sk->sk_receive_queue); clear = 1; } - spin_unlock_irq(&sk->receive_queue.lock); + spin_unlock_irq(&sk->sk_receive_queue.lock); if (clear) kfree_skb(skb); } @@ -532,14 +537,14 @@ if (!icmpv6_err_convert(type, code, &err) && !np->recverr) goto out; - if (sk->state != TCP_ESTABLISHED && !np->recverr) + if (sk->sk_state != TCP_ESTABLISHED && !np->recverr) goto out; if (np->recverr) ipv6_icmp_error(sk, skb, err, uh->dest, ntohl(info), (u8 *)(uh+1)); - sk->err = err; - sk->error_report(sk); + sk->sk_err = err; + sk->sk_error_report(sk); out: sock_put(sk); } @@ -551,7 +556,7 @@ return -1; } - if (sk->filter && skb->ip_summed != CHECKSUM_UNNECESSARY) { + if (sk->sk_filter && skb->ip_summed != CHECKSUM_UNNECESSARY) { if ((unsigned short)csum_fold(skb_checksum(skb, 0, skb->len, skb->csum))) { UDP6_INC_STATS_BH(UdpInErrors); kfree_skb(skb); @@ -576,10 +581,10 @@ { struct sock *s = sk; unsigned short num = ntohs(loc_port); - for(; s; s = s->next) { + for (; s; s = s->sk_next) { struct inet_opt *inet = inet_sk(s); - if (inet->num == num && sk->family == PF_INET6) { + if (inet->num == num && sk->sk_family == PF_INET6) { struct ipv6_pinfo *np = inet6_sk(s); if (inet->dport) { if (inet->dport != rmt_port) @@ -589,7 +594,7 @@ ipv6_addr_cmp(&np->daddr, rmt_addr)) continue; - if (s->bound_dev_if && s->bound_dev_if != dif) + if (s->sk_bound_dev_if && s->sk_bound_dev_if != dif) continue; if (!ipv6_addr_any(&np->rcv_saddr)) { @@ -625,8 +630,8 @@ buff = NULL; sk2 = sk; - while((sk2 = udp_v6_mcast_next(sk2->next, uh->dest, daddr, - uh->source, saddr, dif))) { + while ((sk2 = udp_v6_mcast_next(sk2->sk_next, uh->dest, daddr, + uh->source, saddr, dif))) { if (!buff) { buff = skb_clone(skb, GFP_ATOMIC); if (!buff) @@ -768,7 +773,7 @@ int err = 0; /* Grab the skbuff where UDP header space exists. */ - if ((skb = skb_peek(&sk->write_queue)) == NULL) + if ((skb = skb_peek(&sk->sk_write_queue)) == NULL) goto out; /* @@ -780,12 +785,12 @@ uh->len = htons(up->len); uh->check = 0; - if (sk->no_check == UDP_CSUM_NOXMIT) { + if (sk->sk_no_check == UDP_CSUM_NOXMIT) { skb->ip_summed = CHECKSUM_NONE; goto send; } - if (skb_queue_len(&sk->write_queue) == 1) { + if (skb_queue_len(&sk->sk_write_queue) == 1) { skb->csum = csum_partial((char *)uh, sizeof(struct udphdr), skb->csum); uh->check = csum_ipv6_magic(&fl->fl6_src, @@ -794,7 +799,7 @@ } else { u32 tmp_csum = 0; - skb_queue_walk(&sk->write_queue, skb) { + skb_queue_walk(&sk->sk_write_queue, skb) { tmp_csum = csum_add(tmp_csum, skb->csum); } tmp_csum = csum_partial((char *)uh, @@ -884,8 +889,11 @@ } } - /* Otherwise it will be difficult to maintain sk->dst_cache. */ - if (sk->state == TCP_ESTABLISHED && + /* + * Otherwise it will be difficult to maintain + * sk->sk_dst_cache. + */ + if (sk->sk_state == TCP_ESTABLISHED && !ipv6_addr_cmp(daddr, &np->daddr)) daddr = &np->daddr; @@ -894,7 +902,7 @@ ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL) fl.oif = sin6->sin6_scope_id; } else { - if (sk->state != TCP_ESTABLISHED) + if (sk->sk_state != TCP_ESTABLISHED) return -ENOTCONN; up->dport = inet->dport; @@ -921,7 +929,7 @@ } if (!fl.oif) - fl.oif = sk->bound_dev_if; + fl.oif = sk->sk_bound_dev_if; if (msg->msg_controllen) { opt = &opt_space; @@ -1142,12 +1150,13 @@ src->s6_addr32[2], src->s6_addr32[3], srcp, dest->s6_addr32[0], dest->s6_addr32[1], dest->s6_addr32[2], dest->s6_addr32[3], destp, - sp->state, - atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc), + sp->sk_state, + atomic_read(&sp->sk_wmem_alloc), + atomic_read(&sp->sk_rmem_alloc), 0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp), - atomic_read(&sp->refcnt), sp); + atomic_read(&sp->sk_refcnt), sp); } static int udp6_seq_show(struct seq_file *seq, void *v) diff -Nru a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c --- a/net/ipv6/xfrm6_policy.c Mon Jun 9 23:16:08 2003 +++ b/net/ipv6/xfrm6_policy.c Mon Jun 9 23:16:08 2003 @@ -146,7 +146,7 @@ memcpy(&dst_prev->metrics, &rt->u.dst.metrics, sizeof(dst_prev->metrics)); dst_prev->path = &rt->u.dst; - /* Copy neighbout for reachability confirmation */ + /* Copy neighbour for reachability confirmation */ dst_prev->neighbour = neigh_clone(rt->u.dst.neighbour); dst_prev->input = rt->u.dst.input; dst_prev->output = dst_prev->xfrm->type->output; diff -Nru a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c --- a/net/ipx/af_ipx.c Mon Jun 9 23:16:08 2003 +++ b/net/ipx/af_ipx.c Mon Jun 9 23:16:08 2003 @@ -143,16 +143,16 @@ spin_lock_bh(&intrfc->if_sklist_lock); s = intrfc->if_sklist; if (s == sk) { - intrfc->if_sklist = s->next; + intrfc->if_sklist = s->sk_next; goto out_unlock; } - while (s && s->next) { - if (s->next == sk) { - s->next = sk->next; + while (s && s->sk_next) { + if (s->sk_next == sk) { + s->sk_next = sk->sk_next; goto out_unlock; } - s = s->next; + s = s->sk_next; } out_unlock: spin_unlock_bh(&intrfc->if_sklist_lock); @@ -165,14 +165,14 @@ static void ipx_destroy_socket(struct sock *sk) { ipx_remove_socket(sk); - skb_queue_purge(&sk->receive_queue); + skb_queue_purge(&sk->sk_receive_queue); #ifdef IPX_REFCNT_DEBUG atomic_dec(&ipx_sock_nr); printk(KERN_DEBUG "IPX socket %p released, %d are still alive\n", sk, atomic_read(&ipx_sock_nr)); - if (atomic_read(&sk->refcnt) != 1) + if (atomic_read(&sk->sk_refcnt) != 1) printk(KERN_DEBUG "Destruction sock ipx %p delayed, cnt=%d\n", - sk, atomic_read(&sk->refcnt)); + sk, atomic_read(&sk->sk_refcnt)); #endif sock_put(sk); } @@ -246,14 +246,14 @@ sock_hold(sk); spin_lock_bh(&intrfc->if_sklist_lock); ipx_sk(sk)->intrfc = intrfc; - sk->next = NULL; + sk->sk_next = NULL; if (!intrfc->if_sklist) intrfc->if_sklist = sk; else { struct sock *s = intrfc->if_sklist; - while (s->next) - s = s->next; - s->next = sk; + while (s->sk_next) + s = s->sk_next; + s->sk_next = sk; } spin_unlock_bh(&intrfc->if_sklist_lock); ipxitf_put(intrfc); @@ -266,7 +266,7 @@ struct sock *s = intrfc->if_sklist; while (s && ipx_sk(s)->port != port) - s = s->next; + s = s->sk_next; return s; } @@ -303,7 +303,7 @@ if (ipxs->port == port && !memcmp(node, ipxs->node, IPX_NODE_LEN)) break; - s = s->next; + s = s->sk_next; } spin_unlock_bh(&intrfc->if_sklist_lock); ipxitf_put(intrfc); @@ -324,14 +324,14 @@ for (s = intrfc->if_sklist; s;) { struct ipx_opt *ipxs = ipx_sk(s); - s->err = ENOLINK; - s->error_report(s); + s->sk_err = ENOLINK; + s->sk_error_report(s); ipxs->intrfc = NULL; ipxs->port = 0; - s->zapped = 1; /* Indicates it is no longer bound */ + s->sk_zapped = 1; /* Indicates it is no longer bound */ t = s; - s = s->next; - t->next = NULL; + s = s->sk_next; + t->sk_next = NULL; } intrfc->if_sklist = NULL; spin_unlock_bh(&intrfc->if_sklist_lock); @@ -429,7 +429,7 @@ if (intrfc != ipx_internal_net) break; } - s = s->next; + s = s->sk_next; } /* skb was solely for us, and we did not make a copy, so free it. */ @@ -468,7 +468,7 @@ spin_lock_bh(&intrfc->if_sklist_lock); for (sk = intrfc->if_sklist; sk && ipx_sk(sk)->ipx_ncp_conn != connection; - sk = sk->next); + sk = sk->sk_next); if (sk) sock_hold(sk); spin_unlock_bh(&intrfc->if_sklist_lock); @@ -1385,7 +1385,7 @@ atomic_read(&ipx_sock_nr)); #endif sock_init_data(sock, sk); - sk->no_check = 1; /* Checksum off by default */ + sk->sk_no_check = 1; /* Checksum off by default */ rc = 0; out: return rc; @@ -1401,10 +1401,10 @@ if (!sk) goto out; - if (!test_bit(SOCK_DEAD, &sk->flags)) - sk->state_change(sk); + if (!sock_flag(sk, SOCK_DEAD)) + sk->sk_state_change(sk); - __set_bit(SOCK_DEAD, &sk->flags); + sock_set_flag(sk, SOCK_DEAD); sock->sk = NULL; ipx_destroy_socket(sk); out: @@ -1442,7 +1442,7 @@ struct sockaddr_ipx *addr = (struct sockaddr_ipx *)uaddr; int rc = -EINVAL; - if (!sk->zapped || addr_len != sizeof(struct sockaddr_ipx)) + if (!sk->sk_zapped || addr_len != sizeof(struct sockaddr_ipx)) goto out; intrfc = ipxitf_find_using_net(addr->sipx_network); @@ -1520,7 +1520,7 @@ #endif /* CONFIG_IPX_INTERN */ ipxitf_insert_socket(intrfc, sk); - sk->zapped = 0; + sk->sk_zapped = 0; rc = 0; out_put: @@ -1538,7 +1538,7 @@ int rc = -EINVAL; struct ipx_route *rt; - sk->state = TCP_CLOSE; + sk->sk_state = TCP_CLOSE; sock->state = SS_UNCONNECTED; if (addr_len != sizeof(*addr)) @@ -1580,7 +1580,7 @@ if (sock->type == SOCK_DGRAM) { sock->state = SS_CONNECTED; - sk->state = TCP_ESTABLISHED; + sk->sk_state = TCP_ESTABLISHED; } if (rt) @@ -1604,7 +1604,7 @@ if (peer) { rc = -ENOTCONN; - if (sk->state != TCP_ESTABLISHED) + if (sk->sk_state != TCP_ESTABLISHED) goto out; addr = &ipxs->dest_addr; @@ -1703,7 +1703,7 @@ int flags = msg->msg_flags; /* Socket gets bound below anyway */ -/* if (sk->zapped) +/* if (sk->sk_zapped) return -EIO; */ /* Socket not bound */ if (flags & ~MSG_DONTWAIT) goto out; @@ -1733,7 +1733,7 @@ goto out; } else { rc = -ENOTCONN; - if (sk->state != TCP_ESTABLISHED) + if (sk->sk_state != TCP_ESTABLISHED) goto out; usipx = &local_sipx; @@ -1784,7 +1784,7 @@ } rc = -ENOTCONN; - if (sk->zapped) + if (sk->sk_zapped) goto out; skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, @@ -1803,7 +1803,7 @@ copied); if (rc) goto out_free; - sk->stamp = skb->stamp; + sk->sk_stamp = skb->stamp; msg->msg_namelen = sizeof(*sipx); @@ -1831,13 +1831,13 @@ switch (cmd) { case TIOCOUTQ: - amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); + amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); if (amount < 0) amount = 0; rc = put_user(amount, (int *)arg); break; case TIOCINQ: { - struct sk_buff *skb = skb_peek(&sk->receive_queue); + struct sk_buff *skb = skb_peek(&sk->sk_receive_queue); /* These two are safe on a single CPU system as only * user tasks fiddle here */ if (skb) @@ -1878,10 +1878,10 @@ rc = -EINVAL; if (sk) { rc = -ENOENT; - if (!sk->stamp.tv_sec) + if (!sk->sk_stamp.tv_sec) break; rc = -EFAULT; - if (!copy_to_user((void *)arg, &sk->stamp, + if (!copy_to_user((void *)arg, &sk->sk_stamp, sizeof(struct timeval))) rc = 0; } diff -Nru a/net/ipx/ipx_proc.c b/net/ipx/ipx_proc.c --- a/net/ipx/ipx_proc.c Mon Jun 9 23:16:05 2003 +++ b/net/ipx/ipx_proc.c Mon Jun 9 23:16:05 2003 @@ -174,7 +174,7 @@ if (!pos) break; spin_lock_bh(&i->if_sklist_lock); - for (s = i->if_sklist; pos && s; s = s->next) + for (s = i->if_sklist; pos && s; s = s->sk_next) --pos; if (!pos) { if (!s) @@ -213,8 +213,8 @@ goto out; } sk = v; - if (sk->next) { - sk = sk->next; + if (sk->sk_next) { + sk = sk->sk_next; goto out; } ipxs = ipx_sk(sk); @@ -264,7 +264,7 @@ seq_printf(seq, "%08lX:%04X ", (unsigned long) htonl(ipxs->intrfc->if_netnum), htons(ipxs->port)); #endif /* CONFIG_IPX_INTERN */ - if (s->state != TCP_ESTABLISHED) + if (s->sk_state != TCP_ESTABLISHED) seq_printf(seq, "%-28s", "Not_Connected"); else { seq_printf(seq, "%08lX:%02X%02X%02X%02X%02X%02X:%04X ", @@ -276,8 +276,9 @@ } seq_printf(seq, "%08X %08X %02X %03d\n", - atomic_read(&s->wmem_alloc), atomic_read(&s->rmem_alloc), - s->state, SOCK_INODE(s->socket)->i_uid); + atomic_read(&s->sk_wmem_alloc), + atomic_read(&s->sk_rmem_alloc), + s->sk_state, SOCK_INODE(s->sk_socket)->i_uid); out: return 0; } diff -Nru a/net/ipx/ipx_route.c b/net/ipx/ipx_route.c --- a/net/ipx/ipx_route.c Mon Jun 9 23:16:12 2003 +++ b/net/ipx/ipx_route.c Mon Jun 9 23:16:12 2003 @@ -238,7 +238,7 @@ } /* Apply checksum. Not allowed on 802.3 links. */ - if (sk->no_check || intrfc->if_dlink_type == IPX_FRAME_8023) + if (sk->sk_no_check || intrfc->if_dlink_type == IPX_FRAME_8023) ipx->ipx_checksum = 0xFFFF; else ipx->ipx_checksum = ipx_cksum(ipx, len + sizeof(struct ipxhdr)); diff -Nru a/net/irda/af_irda.c b/net/irda/af_irda.c --- a/net/irda/af_irda.c Mon Jun 9 23:16:09 2003 +++ b/net/irda/af_irda.c Mon Jun 9 23:16:09 2003 @@ -133,13 +133,14 @@ } /* Prevent race conditions with irda_release() and irda_shutdown() */ - if ((!test_bit(SOCK_DEAD, &sk->flags)) && (sk->state != TCP_CLOSE)) { - sk->state = TCP_CLOSE; - sk->err = ECONNRESET; - sk->shutdown |= SEND_SHUTDOWN; - - sk->state_change(sk); - __set_bit(SOCK_DEAD, &sk->flags); /* Uh-oh... Should use sock_orphan ? */ + if (!sock_flag(sk, SOCK_DEAD) && sk->sk_state != TCP_CLOSE) { + sk->sk_state = TCP_CLOSE; + sk->sk_err = ECONNRESET; + sk->sk_shutdown |= SEND_SHUTDOWN; + + sk->sk_state_change(sk); + /* Uh-oh... Should use sock_orphan ? */ + sock_set_flag(sk, SOCK_DEAD); /* Close our TSAP. * If we leave it open, IrLMP put it back into the list of @@ -150,7 +151,7 @@ * requests. Some apps forget to close sockets, or hang to it * a bit too long, so we may stay in this dead state long * enough to be noticed... - * Note : all socket function do check sk->state, so we are + * Note : all socket function do check sk->sk_state, so we are * safe... * Jean II */ @@ -162,8 +163,8 @@ /* Note : once we are there, there is not much you want to do * with the socket anymore, apart from closing it. - * For example, bind() and connect() won't reset sk->err, - * sk->shutdown and sk->flags to valid values... + * For example, bind() and connect() won't reset sk->sk_err, + * sk->sk_shutdown and sk->sk_flags to valid values... * Jean II */ } @@ -191,7 +192,7 @@ return; dev_kfree_skb(skb); - // Should be ??? skb_queue_tail(&sk->receive_queue, skb); + // Should be ??? skb_queue_tail(&sk->sk_receive_queue, skb); /* How much header space do we need to reserve */ self->max_header_size = max_header_size; @@ -200,7 +201,7 @@ self->max_sdu_size_tx = max_sdu_size; /* Find out what the largest chunk of data that we can transmit is */ - switch (sk->type) { + switch (sk->sk_type) { case SOCK_STREAM: if (max_sdu_size != 0) { ERROR("%s: max_sdu_size must be 0\n", __FUNCTION__); @@ -225,8 +226,8 @@ memcpy(&self->qos_tx, qos, sizeof(struct qos_info)); /* We are now connected! */ - sk->state = TCP_ESTABLISHED; - sk->state_change(sk); + sk->sk_state = TCP_ESTABLISHED; + sk->sk_state_change(sk); } /* @@ -257,7 +258,7 @@ self->max_sdu_size_tx = max_sdu_size; /* Find out what the largest chunk of data that we can transmit is */ - switch (sk->type) { + switch (sk->sk_type) { case SOCK_STREAM: if (max_sdu_size != 0) { ERROR("%s: max_sdu_size must be 0\n", __FUNCTION__); @@ -283,8 +284,8 @@ memcpy(&self->qos_tx, qos, sizeof(struct qos_info)); - skb_queue_tail(&sk->receive_queue, skb); - sk->state_change(sk); + skb_queue_tail(&sk->sk_receive_queue, skb); + sk->sk_state_change(sk); } /* @@ -343,7 +344,7 @@ self->tx_flow = flow; IRDA_DEBUG(1, "%s(), IrTTP wants us to start again\n", __FUNCTION__); - wake_up_interruptible(sk->sleep); + wake_up_interruptible(sk->sk_sleep); break; default: IRDA_DEBUG(0, "%s(), Unknown flow command!\n", __FUNCTION__); @@ -716,7 +717,7 @@ struct irda_sock *self = irda_sk(sk); if (peer) { - if (sk->state != TCP_ESTABLISHED) + if (sk->sk_state != TCP_ESTABLISHED) return -ENOTCONN; saddr.sir_family = AF_IRDA; @@ -750,13 +751,13 @@ IRDA_DEBUG(2, "%s()\n", __FUNCTION__); - if ((sk->type != SOCK_STREAM) && (sk->type != SOCK_SEQPACKET) && - (sk->type != SOCK_DGRAM)) + if ((sk->sk_type != SOCK_STREAM) && (sk->sk_type != SOCK_SEQPACKET) && + (sk->sk_type != SOCK_DGRAM)) return -EOPNOTSUPP; - if (sk->state != TCP_LISTEN) { - sk->max_ack_backlog = backlog; - sk->state = TCP_LISTEN; + if (sk->sk_state != TCP_LISTEN) { + sk->sk_max_ack_backlog = backlog; + sk->sk_state = TCP_LISTEN; return 0; } @@ -786,7 +787,8 @@ #ifdef CONFIG_IRDA_ULTRA /* Special care for Ultra sockets */ - if ((sk->type == SOCK_DGRAM) && (sk->protocol == IRDAPROTO_ULTRA)) { + if ((sk->sk_type == SOCK_DGRAM) && + (sk->sk_protocol == IRDAPROTO_ULTRA)) { self->pid = addr->sir_lsap_sel; if (self->pid & 0x80) { IRDA_DEBUG(0, "%s(), extension in PID not supp!\n", __FUNCTION__); @@ -801,7 +803,7 @@ /* Pretend we are connected */ sock->state = SS_CONNECTED; - sk->state = TCP_ESTABLISHED; + sk->sk_state = TCP_ESTABLISHED; return 0; } @@ -838,7 +840,7 @@ ASSERT(self != NULL, return -1;); - err = irda_create(newsock, sk->protocol); + err = irda_create(newsock, sk->sk_protocol); if (err) return err; @@ -848,11 +850,11 @@ if ((sk = sock->sk) == NULL) return -EINVAL; - if ((sk->type != SOCK_STREAM) && (sk->type != SOCK_SEQPACKET) && - (sk->type != SOCK_DGRAM)) + if ((sk->sk_type != SOCK_STREAM) && (sk->sk_type != SOCK_SEQPACKET) && + (sk->sk_type != SOCK_DGRAM)) return -EOPNOTSUPP; - if (sk->state != TCP_LISTEN) + if (sk->sk_state != TCP_LISTEN) return -EINVAL; /* @@ -868,7 +870,7 @@ * calling us, the data is waiting for us ;-) * Jean II */ - skb = skb_dequeue(&sk->receive_queue); + skb = skb_dequeue(&sk->sk_receive_queue); if (skb == NULL) { int ret = 0; DECLARE_WAITQUEUE(waitq, current); @@ -882,10 +884,10 @@ * We don't us the macro because the condition has * side effects : we want to make sure that only one * skb get dequeued - Jean II */ - add_wait_queue(sk->sleep, &waitq); + add_wait_queue(sk->sk_sleep, &waitq); for (;;) { set_current_state(TASK_INTERRUPTIBLE); - skb = skb_dequeue(&sk->receive_queue); + skb = skb_dequeue(&sk->sk_receive_queue); if (skb != NULL) break; if (!signal_pending(current)) { @@ -896,13 +898,13 @@ break; } current->state = TASK_RUNNING; - remove_wait_queue(sk->sleep, &waitq); + remove_wait_queue(sk->sk_sleep, &waitq); if(ret) return -ERESTARTSYS; } newsk = newsock->sk; - newsk->state = TCP_ESTABLISHED; + newsk->sk_state = TCP_ESTABLISHED; new = irda_sk(newsk); ASSERT(new != NULL, return -1;); @@ -934,7 +936,7 @@ skb->sk = NULL; skb->destructor = NULL; kfree_skb(skb); - sk->ack_backlog--; + sk->sk_ack_backlog--; newsock->state = SS_CONNECTED; @@ -974,23 +976,23 @@ IRDA_DEBUG(2, "%s(%p)\n", __FUNCTION__, self); /* Don't allow connect for Ultra sockets */ - if ((sk->type == SOCK_DGRAM) && (sk->protocol == IRDAPROTO_ULTRA)) + if ((sk->sk_type == SOCK_DGRAM) && (sk->sk_protocol == IRDAPROTO_ULTRA)) return -ESOCKTNOSUPPORT; - if (sk->state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) { + if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) { sock->state = SS_CONNECTED; return 0; /* Connect completed during a ERESTARTSYS event */ } - if (sk->state == TCP_CLOSE && sock->state == SS_CONNECTING) { + if (sk->sk_state == TCP_CLOSE && sock->state == SS_CONNECTING) { sock->state = SS_UNCONNECTED; return -ECONNREFUSED; } - if (sk->state == TCP_ESTABLISHED) + if (sk->sk_state == TCP_ESTABLISHED) return -EISCONN; /* No reconnect on a seqpacket socket */ - sk->state = TCP_CLOSE; + sk->sk_state = TCP_CLOSE; sock->state = SS_UNCONNECTED; if (addr_len != sizeof(struct sockaddr_irda)) @@ -1023,7 +1025,7 @@ /* Move to connecting socket, start sending Connect Requests */ sock->state = SS_CONNECTING; - sk->state = TCP_SYN_SENT; + sk->sk_state = TCP_SYN_SENT; /* Connect to remote device */ err = irttp_connect_request(self->tsap, self->dtsap_sel, @@ -1035,13 +1037,14 @@ } /* Now the loop */ - if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) + if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) return -EINPROGRESS; - if (wait_event_interruptible(*(sk->sleep), (sk->state!=TCP_SYN_SENT))) + if (wait_event_interruptible(*(sk->sk_sleep), + (sk->sk_state != TCP_SYN_SENT))) return -ERESTARTSYS; - if (sk->state != TCP_ESTABLISHED) { + if (sk->sk_state != TCP_ESTABLISHED) { sock->state = SS_UNCONNECTED; return sock_error(sk); /* Always set at this point */ } @@ -1094,9 +1097,9 @@ init_waitqueue_head(&self->query_wait); /* Initialise networking socket struct */ - sock_init_data(sock, sk); /* Note : set sk->refcnt to 1 */ - sk->family = PF_IRDA; - sk->protocol = protocol; + sock_init_data(sock, sk); /* Note : set sk->sk_refcnt to 1 */ + sk->sk_family = PF_IRDA; + sk->sk_protocol = protocol; /* Link networking socket and IrDA socket structs together */ self->sk = sk; @@ -1193,9 +1196,9 @@ if (sk == NULL) return 0; - sk->state = TCP_CLOSE; - sk->shutdown |= SEND_SHUTDOWN; - sk->state_change(sk); + sk->sk_state = TCP_CLOSE; + sk->sk_shutdown |= SEND_SHUTDOWN; + sk->sk_state_change(sk); /* Destroy IrDA socket */ irda_destroy_socket(irda_sk(sk)); @@ -1206,10 +1209,10 @@ sock->sk = NULL; /* Purge queues (see sock_init_data()) */ - skb_queue_purge(&sk->receive_queue); + skb_queue_purge(&sk->sk_receive_queue); /* Destroy networking socket if we are the last reference on it, - * i.e. if(sk->refcnt == 0) -> sk_free(sk) */ + * i.e. if(sk->sk_refcnt == 0) -> sk_free(sk) */ sock_put(sk); /* Notes on socket locking and deallocation... - Jean II @@ -1263,12 +1266,12 @@ if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_EOR)) return -EINVAL; - if (sk->shutdown & SEND_SHUTDOWN) { + if (sk->sk_shutdown & SEND_SHUTDOWN) { send_sig(SIGPIPE, current, 0); return -EPIPE; } - if (sk->state != TCP_ESTABLISHED) + if (sk->sk_state != TCP_ESTABLISHED) return -ENOTCONN; self = irda_sk(sk); @@ -1276,12 +1279,12 @@ /* Check if IrTTP is wants us to slow down */ - if (wait_event_interruptible(*(sk->sleep), - (self->tx_flow != FLOW_STOP || sk->state != TCP_ESTABLISHED))) + if (wait_event_interruptible(*(sk->sk_sleep), + (self->tx_flow != FLOW_STOP || sk->sk_state != TCP_ESTABLISHED))) return -ERESTARTSYS; /* Check if we are still connected */ - if (sk->state != TCP_ESTABLISHED) + if (sk->sk_state != TCP_ESTABLISHED) return -ENOTCONN; /* Check that we don't send out to big frames */ @@ -1357,7 +1360,7 @@ * empty */ if (self->rx_flow == FLOW_STOP) { - if ((atomic_read(&sk->rmem_alloc) << 2) <= sk->rcvbuf) { + if ((atomic_read(&sk->sk_rmem_alloc) << 2) <= sk->sk_rcvbuf) { IRDA_DEBUG(2, "%s(), Starting IrTTP\n", __FUNCTION__); self->rx_flow = FLOW_START; irttp_flow_request(self->tsap, FLOW_START); @@ -1397,9 +1400,8 @@ do { int chunk; - struct sk_buff *skb; + struct sk_buff *skb = skb_dequeue(&sk->sk_receive_queue); - skb=skb_dequeue(&sk->receive_queue); if (skb==NULL) { int ret = 0; @@ -1410,32 +1412,32 @@ * wait_event_interruptible() macro. * We don't us the macro because the test condition * is messy. - Jean II */ - set_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags); - add_wait_queue(sk->sleep, &waitq); + set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); + add_wait_queue(sk->sk_sleep, &waitq); set_current_state(TASK_INTERRUPTIBLE); /* * POSIX 1003.1g mandates this order. */ - if (sk->err) + if (sk->sk_err) ret = sock_error(sk); - else if (sk->shutdown & RCV_SHUTDOWN) + else if (sk->sk_shutdown & RCV_SHUTDOWN) ; else if (noblock) ret = -EAGAIN; else if (signal_pending(current)) ret = -ERESTARTSYS; - else if (skb_peek(&sk->receive_queue) == NULL) + else if (skb_peek(&sk->sk_receive_queue) == NULL) /* Wait process until data arrives */ schedule(); current->state = TASK_RUNNING; - remove_wait_queue(sk->sleep, &waitq); - clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags); + remove_wait_queue(sk->sk_sleep, &waitq); + clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); if(ret) return(ret); - if (sk->shutdown & RCV_SHUTDOWN) + if (sk->sk_shutdown & RCV_SHUTDOWN) break; continue; @@ -1443,7 +1445,7 @@ chunk = min_t(unsigned int, skb->len, size); if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) { - skb_queue_head(&sk->receive_queue, skb); + skb_queue_head(&sk->sk_receive_queue, skb); if (copied == 0) copied = -EFAULT; break; @@ -1459,7 +1461,7 @@ if (skb->len) { IRDA_DEBUG(1, "%s(), back on q!\n", __FUNCTION__); - skb_queue_head(&sk->receive_queue, skb); + skb_queue_head(&sk->sk_receive_queue, skb); break; } @@ -1468,7 +1470,7 @@ IRDA_DEBUG(0, "%s() questionable!?\n", __FUNCTION__); /* put message back and return */ - skb_queue_head(&sk->receive_queue, skb); + skb_queue_head(&sk->sk_receive_queue, skb); break; } } while (size); @@ -1480,7 +1482,7 @@ * empty */ if (self->rx_flow == FLOW_STOP) { - if ((atomic_read(&sk->rmem_alloc) << 2) <= sk->rcvbuf) { + if ((atomic_read(&sk->sk_rmem_alloc) << 2) <= sk->sk_rcvbuf) { IRDA_DEBUG(2, "%s(), Starting IrTTP\n", __FUNCTION__); self->rx_flow = FLOW_START; irttp_flow_request(self->tsap, FLOW_START); @@ -1511,12 +1513,12 @@ if (msg->msg_flags & ~MSG_DONTWAIT) return -EINVAL; - if (sk->shutdown & SEND_SHUTDOWN) { + if (sk->sk_shutdown & SEND_SHUTDOWN) { send_sig(SIGPIPE, current, 0); return -EPIPE; } - if (sk->state != TCP_ESTABLISHED) + if (sk->sk_state != TCP_ESTABLISHED) return -ENOTCONN; self = irda_sk(sk); @@ -1577,7 +1579,7 @@ if (msg->msg_flags & ~MSG_DONTWAIT) return -EINVAL; - if (sk->shutdown & SEND_SHUTDOWN) { + if (sk->sk_shutdown & SEND_SHUTDOWN) { send_sig(SIGPIPE, current, 0); return -EPIPE; } @@ -1628,9 +1630,9 @@ IRDA_DEBUG(1, "%s(%p)\n", __FUNCTION__, self); - sk->state = TCP_CLOSE; - sk->shutdown |= SEND_SHUTDOWN; - sk->state_change(sk); + sk->sk_state = TCP_CLOSE; + sk->sk_shutdown |= SEND_SHUTDOWN; + sk->sk_state_change(sk); if (self->iriap) { iriap_close(self->iriap); @@ -1663,32 +1665,32 @@ IRDA_DEBUG(4, "%s()\n", __FUNCTION__); - poll_wait(file, sk->sleep, wait); + poll_wait(file, sk->sk_sleep, wait); mask = 0; /* Exceptional events? */ - if (sk->err) + if (sk->sk_err) mask |= POLLERR; - if (sk->shutdown & RCV_SHUTDOWN) { + if (sk->sk_shutdown & RCV_SHUTDOWN) { IRDA_DEBUG(0, "%s(), POLLHUP\n", __FUNCTION__); mask |= POLLHUP; } /* Readable? */ - if (!skb_queue_empty(&sk->receive_queue)) { + if (!skb_queue_empty(&sk->sk_receive_queue)) { IRDA_DEBUG(4, "Socket is readable\n"); mask |= POLLIN | POLLRDNORM; } /* Connection-based need to check for termination and startup */ - switch (sk->type) { + switch (sk->sk_type) { case SOCK_STREAM: - if (sk->state == TCP_CLOSE) { + if (sk->sk_state == TCP_CLOSE) { IRDA_DEBUG(0, "%s(), POLLHUP\n", __FUNCTION__); mask |= POLLHUP; } - if (sk->state == TCP_ESTABLISHED) { + if (sk->sk_state == TCP_ESTABLISHED) { if ((self->tx_flow == FLOW_START) && sock_writeable(sk)) { @@ -1725,7 +1727,7 @@ switch (cmd) { case TIOCOUTQ: { long amount; - amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); + amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); if (amount < 0) amount = 0; if (put_user(amount, (unsigned int *)arg)) @@ -1737,7 +1739,7 @@ struct sk_buff *skb; long amount = 0L; /* These two are safe on a single CPU system as only user tasks fiddle here */ - if ((skb = skb_peek(&sk->receive_queue)) != NULL) + if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) amount = skb->len; if (put_user(amount, (unsigned int *)arg)) return -EFAULT; @@ -1746,9 +1748,9 @@ case SIOCGSTAMP: if (sk != NULL) { - if (sk->stamp.tv_sec == 0) + if (!sk->sk_stamp.tv_sec) return -ENOENT; - if (copy_to_user((void *)arg, &sk->stamp, + if (copy_to_user((void *)arg, &sk->sk_stamp, sizeof(struct timeval))) return -EFAULT; return 0; @@ -1972,7 +1974,7 @@ return -EFAULT; /* Only possible for a seqpacket service (TTP with SAR) */ - if (sk->type != SOCK_SEQPACKET) { + if (sk->sk_type != SOCK_SEQPACKET) { IRDA_DEBUG(2, "%s(), setting max_sdu_size = %d\n", __FUNCTION__, opt); self->max_sdu_size_rx = opt; diff -Nru a/net/irda/ircomm/ircomm_tty.c b/net/irda/ircomm/ircomm_tty.c --- a/net/irda/ircomm/ircomm_tty.c Mon Jun 9 23:16:09 2003 +++ b/net/irda/ircomm/ircomm_tty.c Mon Jun 9 23:16:09 2003 @@ -248,48 +248,20 @@ tty = self->tty; - if (tty->driver->subtype == SERIAL_TYPE_CALLOUT) { - /* this is a callout device */ - /* just verify that normal device is not in use */ - if (self->flags & ASYNC_NORMAL_ACTIVE) - return -EBUSY; - if ((self->flags & ASYNC_CALLOUT_ACTIVE) && - (self->flags & ASYNC_SESSION_LOCKOUT) && - (self->session != current->session)) - return -EBUSY; - if ((self->flags & ASYNC_CALLOUT_ACTIVE) && - (self->flags & ASYNC_PGRP_LOCKOUT) && - (self->pgrp != current->pgrp)) - return -EBUSY; - self->flags |= ASYNC_CALLOUT_ACTIVE; - return 0; - } - /* * If non-blocking mode is set, or the port is not enabled, * then make the check up front and then exit. */ if (filp->f_flags & O_NONBLOCK || tty->flags & (1 << TTY_IO_ERROR)){ /* nonblock mode is set or port is not enabled */ - /* just verify that callout device is not active */ - if (self->flags & ASYNC_CALLOUT_ACTIVE) - return -EBUSY; self->flags |= ASYNC_NORMAL_ACTIVE; - IRDA_DEBUG(1, "%s(), O_NONBLOCK requested!\n", __FUNCTION__ ); return 0; } - if (self->flags & ASYNC_CALLOUT_ACTIVE) { - if (self->normal_termios.c_cflag & CLOCAL) { - IRDA_DEBUG(1, "%s(), doing CLOCAL!\n", __FUNCTION__ ); - do_clocal = 1; - } - } else { - if (tty->termios->c_cflag & CLOCAL) { - IRDA_DEBUG(1, "%s(), doing CLOCAL!\n", __FUNCTION__ ); - do_clocal = 1; - } + if (tty->termios->c_cflag & CLOCAL) { + IRDA_DEBUG(1, "%s(), doing CLOCAL!\n", __FUNCTION__ ); + do_clocal = 1; } /* Wait for carrier detect and the line to become @@ -315,8 +287,7 @@ self->blocked_open++; while (1) { - if (!(self->flags & ASYNC_CALLOUT_ACTIVE) && - (tty->termios->c_cflag & CBAUD)) { + if (tty->termios->c_cflag & CBAUD) { /* Here, we use to lock those two guys, but * as ircomm_param_request() does it itself, * I don't see the point (and I see the deadlock). @@ -339,8 +310,7 @@ * specified, we cannot return before the IrCOMM link is * ready */ - if (!(self->flags & ASYNC_CALLOUT_ACTIVE) && - !(self->flags & ASYNC_CLOSING) && + if (!(self->flags & ASYNC_CLOSING) && (do_clocal || (self->settings.dce & IRCOMM_CD)) && self->state == IRCOMM_TTY_READY) { @@ -509,10 +479,6 @@ return ret; } - - self->session = current->session; - self->pgrp = current->pgrp; - return 0; } @@ -605,8 +571,7 @@ wake_up_interruptible(&self->open_wait); } - self->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| - ASYNC_CLOSING); + self->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&self->close_wait); MOD_DEC_USE_COUNT; @@ -1054,7 +1019,7 @@ /* I guess we need to lock here - Jean II */ spin_lock_irqsave(&self->spinlock, flags); - self->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + self->flags &= ~ASYNC_NORMAL_ACTIVE; self->tty = 0; self->open_count = 0; spin_unlock_irqrestore(&self->spinlock, flags); @@ -1133,9 +1098,7 @@ if (status & IRCOMM_CD) { wake_up_interruptible(&self->open_wait); - } else if (!((self->flags & ASYNC_CALLOUT_ACTIVE) && - (self->flags & ASYNC_CALLOUT_NOHUP))) - { + } else { IRDA_DEBUG(2, "%s(), Doing serial hangup..\n", __FUNCTION__ ); if (tty) @@ -1364,8 +1327,6 @@ ret += sprintf(buf+ret, "ASYNC_CLOSING|"); if (self->flags & ASYNC_NORMAL_ACTIVE) ret += sprintf(buf+ret, "ASYNC_NORMAL_ACTIVE|"); - if (self->flags & ASYNC_CALLOUT_ACTIVE) - ret += sprintf(buf+ret, "ASYNC_CALLOUT_ACTIVE|"); if (self->flags) ret--; /* remove the last | */ ret += sprintf(buf+ret, "\n"); diff -Nru a/net/key/af_key.c b/net/key/af_key.c --- a/net/key/af_key.c Mon Jun 9 23:16:08 2003 +++ b/net/key/af_key.c Mon Jun 9 23:16:08 2003 @@ -46,19 +46,19 @@ int registered; int promisc; }; -#define pfkey_sk(__sk) ((struct pfkey_opt *)(__sk)->protinfo) +#define pfkey_sk(__sk) ((struct pfkey_opt *)(__sk)->sk_protinfo) static void pfkey_sock_destruct(struct sock *sk) { - skb_queue_purge(&sk->receive_queue); + skb_queue_purge(&sk->sk_receive_queue); - if (!test_bit(SOCK_DEAD, &sk->flags)) { + if (!sock_flag(sk, SOCK_DEAD)) { printk("Attempt to release alive pfkey socket: %p\n", sk); return; } - BUG_TRAP(atomic_read(&sk->rmem_alloc)==0); - BUG_TRAP(atomic_read(&sk->wmem_alloc)==0); + BUG_TRAP(!atomic_read(&sk->sk_rmem_alloc)); + BUG_TRAP(!atomic_read(&sk->sk_wmem_alloc)); kfree(pfkey_sk(sk)); @@ -114,7 +114,7 @@ static void pfkey_insert(struct sock *sk) { pfkey_table_grab(); - sk->next = pfkey_table; + sk->sk_next = pfkey_table; pfkey_table = sk; sock_hold(sk); pfkey_table_ungrab(); @@ -125,9 +125,9 @@ struct sock **skp; pfkey_table_grab(); - for (skp = &pfkey_table; *skp; skp = &((*skp)->next)) { + for (skp = &pfkey_table; *skp; skp = &((*skp)->sk_next)) { if (*skp == sk) { - *skp = sk->next; + *skp = sk->sk_next; __sock_put(sk); break; } @@ -165,8 +165,8 @@ } memset(pfk, 0, sizeof(*pfk)); - sk->family = PF_KEY; - sk->destruct = pfkey_sock_destruct; + sk->sk_family = PF_KEY; + sk->sk_destruct = pfkey_sock_destruct; atomic_inc(&pfkey_socks_nr); @@ -188,7 +188,7 @@ sock_orphan(sk); sock->sk = NULL; - skb_queue_purge(&sk->write_queue); + skb_queue_purge(&sk->sk_write_queue); sock_put(sk); return 0; @@ -209,11 +209,11 @@ } } if (*skb2 != NULL) { - if (atomic_read(&sk->rmem_alloc) <= sk->rcvbuf) { + if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) { skb_orphan(*skb2); skb_set_owner_r(*skb2, sk); - skb_queue_tail(&sk->receive_queue, *skb2); - sk->data_ready(sk, (*skb2)->len); + skb_queue_tail(&sk->sk_receive_queue, *skb2); + sk->sk_data_ready(sk, (*skb2)->len); *skb2 = NULL; err = 0; } @@ -241,7 +241,7 @@ return -ENOMEM; pfkey_lock_table(); - for (sk = pfkey_table; sk; sk = sk->next) { + for (sk = pfkey_table; sk; sk = sk->sk_next) { struct pfkey_opt *pfk = pfkey_sk(sk); int err2; @@ -1990,7 +1990,7 @@ if (sel.dport) sel.dport_mask = ~0; - xp = xfrm_policy_delete(pol->sadb_x_policy_dir-1, &sel); + xp = xfrm_policy_bysel(pol->sadb_x_policy_dir-1, &sel, 1); if (xp == NULL) return -ENOENT; @@ -2016,7 +2016,6 @@ out: if (xp) { xfrm_policy_kill(xp); - xfrm_pol_put(xp); } return err; } @@ -2060,7 +2059,8 @@ if (xp) { if (hdr->sadb_msg_type == SADB_X_SPDDELETE2) xfrm_policy_kill(xp); - xfrm_pol_put(xp); + else + xfrm_pol_put(xp); } return err; } @@ -2694,7 +2694,7 @@ goto out; err = -EMSGSIZE; - if ((unsigned)len > sk->sndbuf-32) + if ((unsigned)len > sk->sk_sndbuf - 32) goto out; err = -ENOBUFS; @@ -2804,12 +2804,12 @@ read_lock(&pfkey_table_lock); - for (s = pfkey_table; s; s = s->next) { + for (s = pfkey_table; s; s = s->sk_next) { len += sprintf(buffer+len,"%p %-6d %-6u %-6u %-6u %-6lu", s, - atomic_read(&s->refcnt), - atomic_read(&s->rmem_alloc), - atomic_read(&s->wmem_alloc), + atomic_read(&s->sk_refcnt), + atomic_read(&s->sk_rmem_alloc), + atomic_read(&s->sk_wmem_alloc), sock_i_uid(s), sock_i_ino(s) ); diff -Nru a/net/llc/af_llc.c b/net/llc/af_llc.c --- a/net/llc/af_llc.c Mon Jun 9 23:16:05 2003 +++ b/net/llc/af_llc.c Mon Jun 9 23:16:05 2003 @@ -97,7 +97,7 @@ if (addr->sllc_test || addr->sllc_xid) rc = LLC_PDU_LEN_U; - else if (sk->type == SOCK_STREAM) + else if (sk->sk_type == SOCK_STREAM) rc = LLC_PDU_LEN_I; return rc; } @@ -129,11 +129,11 @@ static void llc_ui_sk_init(struct socket *sock, struct sock *sk) { - sk->type = sock->type; - sk->sleep = &sock->wait; - sk->socket = sock; - sock->sk = sk; - sock->ops = &llc_ui_ops; + sk->sk_type = sock->type; + sk->sk_sleep = &sock->wait; + sk->sk_socket = sock; + sock->sk = sk; + sock->ops = &llc_ui_ops; } /** @@ -180,8 +180,8 @@ dprintk("%s: closing local(%02X) remote(%02X)\n", __FUNCTION__, llc->laddr.lsap, llc->daddr.lsap); if (!llc_send_disc(sk)) - llc_ui_wait_for_disc(sk, sk->rcvtimeo); - if (!sk->zapped) + llc_ui_wait_for_disc(sk, sk->sk_rcvtimeo); + if (!sk->sk_zapped) llc_sap_unassign_sock(llc->sap, sk); release_sock(sk); if (llc->sap && !llc->sap->sk_list.list) @@ -246,7 +246,7 @@ struct net_device *dev = NULL; int rc = -EINVAL; - if (!sk->zapped) + if (!sk->sk_zapped) goto out; /* bind to a specific mac, optional. */ if (!llc_mac_null(addr->sllc_smac)) { @@ -281,7 +281,7 @@ memset(&laddr, 0, sizeof(laddr)); memset(&daddr, 0, sizeof(daddr)); if (!llc_mac_null(addr->sllc_mmac)) { - if (sk->type != SOCK_DGRAM) { + if (sk->sk_type != SOCK_DGRAM) { rc = -EOPNOTSUPP; goto out; } @@ -304,7 +304,7 @@ memcpy(&llc->addr, addr, sizeof(llc->addr)); /* assign new connection to its SAP */ llc_sap_assign_sock(sap, sk); - rc = sk->zapped = 0; + rc = sk->sk_zapped = 0; out: return rc; } @@ -334,7 +334,7 @@ int rc = -EINVAL; dprintk("%s: binding %02X\n", __FUNCTION__, addr->sllc_ssap); - if (!sk->zapped || addrlen != sizeof(*addr)) + if (!sk->sk_zapped || addrlen != sizeof(*addr)) goto out; rc = -EAFNOSUPPORT; if (addr->sllc_family != AF_LLC) @@ -362,16 +362,16 @@ int rc = -ENOTCONN; lock_sock(sk); - if (sk->state != TCP_ESTABLISHED) + if (sk->sk_state != TCP_ESTABLISHED) goto out; rc = -EINVAL; if (how != 2) goto out; rc = llc_send_disc(sk); if (!rc) - rc = llc_ui_wait_for_disc(sk, sk->rcvtimeo); + rc = llc_ui_wait_for_disc(sk, sk->sk_rcvtimeo); /* Wake up anyone sleeping in poll */ - sk->state_change(sk); + sk->sk_state_change(sk); out: release_sock(sk); return rc; @@ -407,7 +407,7 @@ if (addr->sllc_family != AF_LLC) goto out; /* bind connection to sap if user hasn't done it. */ - if (sk->zapped) { + if (sk->sk_zapped) { /* bind to sap with null dev, exclusive */ rc = llc_ui_autobind(sock, addr); if (rc) @@ -422,23 +422,23 @@ llc->dev = dev; } else dev = llc->dev; - if (sk->type != SOCK_STREAM) + if (sk->sk_type != SOCK_STREAM) goto out; rc = -EALREADY; if (sock->state == SS_CONNECTING) goto out; sock->state = SS_CONNECTING; - sk->state = TCP_SYN_SENT; + sk->sk_state = TCP_SYN_SENT; llc->link = llc_ui_next_link_no(llc->sap->laddr.lsap); rc = llc_establish_connection(sk, dev->dev_addr, addr->sllc_dmac, addr->sllc_dsap); if (rc) { dprintk("%s: llc_ui_send_conn failed :-(\n", __FUNCTION__); - sock->state = SS_UNCONNECTED; - sk->state = TCP_CLOSE; + sock->state = SS_UNCONNECTED; + sk->sk_state = TCP_CLOSE; goto out; } - rc = llc_ui_wait_for_conn(sk, sk->rcvtimeo); + rc = llc_ui_wait_for_conn(sk, sk->sk_rcvtimeo); if (rc) dprintk("%s: llc_ui_wait_for_conn failed=%d\n", __FUNCTION__, rc); out: @@ -463,20 +463,20 @@ if (sock->state != SS_UNCONNECTED) goto out; rc = -EOPNOTSUPP; - if (sk->type != SOCK_STREAM) + if (sk->sk_type != SOCK_STREAM) goto out; rc = -EAGAIN; - if (sk->zapped) + if (sk->sk_zapped) goto out; rc = 0; if (!(unsigned)backlog) /* BSDism */ backlog = 1; - sk->max_ack_backlog = backlog; - if (sk->state != TCP_LISTEN) { - sk->ack_backlog = 0; - sk->state = TCP_LISTEN; + sk->sk_max_ack_backlog = backlog; + if (sk->sk_state != TCP_LISTEN) { + sk->sk_ack_backlog = 0; + sk->sk_state = TCP_LISTEN; } - sk->socket->flags |= __SO_ACCEPTCON; + sk->sk_socket->flags |= __SO_ACCEPTCON; out: release_sock(sk); return rc; @@ -487,7 +487,7 @@ DECLARE_WAITQUEUE(wait, current); int rc; - add_wait_queue_exclusive(sk->sleep, &wait); + add_wait_queue_exclusive(sk->sk_sleep, &wait); for (;;) { __set_current_state(TASK_INTERRUPTIBLE); rc = -ERESTARTSYS; @@ -497,7 +497,7 @@ if (!timeout) break; rc = 0; - if (sk->state != TCP_CLOSE) { + if (sk->sk_state != TCP_CLOSE) { release_sock(sk); timeout = schedule_timeout(timeout); lock_sock(sk); @@ -505,7 +505,7 @@ break; } __set_current_state(TASK_RUNNING); - remove_wait_queue(sk->sleep, &wait); + remove_wait_queue(sk->sk_sleep, &wait); return rc; } @@ -514,11 +514,11 @@ DECLARE_WAITQUEUE(wait, current); int rc; - add_wait_queue_exclusive(sk->sleep, &wait); + add_wait_queue_exclusive(sk->sk_sleep, &wait); for (;;) { __set_current_state(TASK_INTERRUPTIBLE); rc = -EAGAIN; - if (sk->state == TCP_CLOSE) + if (sk->sk_state == TCP_CLOSE) break; rc = -ERESTARTSYS; if (signal_pending(current)) @@ -527,7 +527,7 @@ if (!timeout) break; rc = 0; - if (sk->state != TCP_ESTABLISHED) { + if (sk->sk_state != TCP_ESTABLISHED) { release_sock(sk); timeout = schedule_timeout(timeout); lock_sock(sk); @@ -535,7 +535,7 @@ break; } __set_current_state(TASK_RUNNING); - remove_wait_queue(sk->sleep, &wait); + remove_wait_queue(sk->sk_sleep, &wait); return rc; } @@ -544,10 +544,10 @@ DECLARE_WAITQUEUE(wait, current); int rc = 0; - add_wait_queue_exclusive(sk->sleep, &wait); + add_wait_queue_exclusive(sk->sk_sleep, &wait); for (;;) { __set_current_state(TASK_INTERRUPTIBLE); - if (sk->shutdown & RCV_SHUTDOWN) + if (sk->sk_shutdown & RCV_SHUTDOWN) break; rc = -ERESTARTSYS; if (signal_pending(current)) @@ -558,12 +558,12 @@ /* * Well, if we have backlog, try to process it now. */ - if (sk->backlog.tail) { + if (sk->sk_backlog.tail) { release_sock(sk); lock_sock(sk); } rc = 0; - if (skb_queue_empty(&sk->receive_queue)) { + if (skb_queue_empty(&sk->sk_receive_queue)) { release_sock(sk); timeout = schedule_timeout(timeout); lock_sock(sk); @@ -571,7 +571,7 @@ break; } __set_current_state(TASK_RUNNING); - remove_wait_queue(sk->sleep, &wait); + remove_wait_queue(sk->sk_sleep, &wait); return rc; } @@ -581,12 +581,12 @@ struct llc_opt *llc = llc_sk(sk); int rc; - add_wait_queue_exclusive(sk->sleep, &wait); + add_wait_queue_exclusive(sk->sk_sleep, &wait); for (;;) { dprintk("%s: looping...\n", __FUNCTION__); __set_current_state(TASK_INTERRUPTIBLE); rc = -ENOTCONN; - if (sk->shutdown & RCV_SHUTDOWN) + if (sk->sk_shutdown & RCV_SHUTDOWN) break; rc = -ERESTARTSYS; if (signal_pending(current)) @@ -603,7 +603,7 @@ break; } __set_current_state(TASK_RUNNING); - remove_wait_queue(sk->sleep, &wait); + remove_wait_queue(sk->sk_sleep, &wait); return rc; } @@ -626,18 +626,18 @@ dprintk("%s: accepting on %02X\n", __FUNCTION__, llc_sk(sk)->addr.sllc_ssap); lock_sock(sk); - if (sk->type != SOCK_STREAM) + if (sk->sk_type != SOCK_STREAM) goto out; rc = -EINVAL; - if (sock->state != SS_UNCONNECTED || sk->state != TCP_LISTEN) + if (sock->state != SS_UNCONNECTED || sk->sk_state != TCP_LISTEN) goto out; /* wait for a connection to arrive. */ - rc = llc_ui_wait_for_data(sk, sk->rcvtimeo); + rc = llc_ui_wait_for_data(sk, sk->sk_rcvtimeo); if (rc) goto out; dprintk("%s: got a new connection on %02X\n", __FUNCTION__, llc_sk(sk)->addr.sllc_ssap); - skb = skb_dequeue(&sk->receive_queue); + skb = skb_dequeue(&sk->sk_receive_queue); rc = -EINVAL; if (!skb->sk) goto frees; @@ -645,9 +645,9 @@ newsk = skb->sk; /* attach connection to a new socket. */ llc_ui_sk_init(newsock, newsk); - newsk->pair = NULL; - newsk->zapped = 0; - newsk->state = TCP_ESTABLISHED; + newsk->sk_pair = NULL; + newsk->sk_zapped = 0; + newsk->sk_state = TCP_ESTABLISHED; newsock->state = SS_CONNECTED; llc = llc_sk(sk); newllc = llc_sk(newsk); @@ -657,8 +657,8 @@ newllc->link = llc_ui_next_link_no(newllc->laddr.lsap); /* put original socket back into a clean listen state. */ - sk->state = TCP_LISTEN; - sk->ack_backlog--; + sk->sk_state = TCP_LISTEN; + sk->sk_ack_backlog--; skb->sk = NULL; dprintk("%s: ok success on %02X, client on %02X\n", __FUNCTION__, llc_sk(sk)->addr.sllc_ssap, newllc->addr.sllc_dsap); @@ -699,7 +699,7 @@ llc_sk(sk)->laddr.lsap, llc_sk(sk)->daddr.lsap); goto out; } - skb = skb_dequeue(&sk->receive_queue); + skb = skb_dequeue(&sk->sk_receive_queue); if (!skb) /* shutdown */ goto out; copied = skb->len; @@ -710,7 +710,7 @@ goto dgram_free; if (skb->len > copied) { skb_pull(skb, copied); - skb_queue_head(&sk->receive_queue, skb); + skb_queue_head(&sk->sk_receive_queue, skb); } if (uaddr) memcpy(uaddr, llc_ui_skb_cb(skb), sizeof(*uaddr)); @@ -757,7 +757,7 @@ addr = &llc->addr; } /* must bind connection to sap if user hasn't done it. */ - if (sk->zapped) { + if (sk->sk_zapped) { /* bind to sap with null dev, exclusive. */ rc = llc_ui_autobind(sock, addr); if (rc) @@ -789,7 +789,7 @@ rc = memcpy_fromiovec(skb_put(skb, copied), msg->msg_iov, copied); if (rc) goto out; - if (sk->type == SOCK_DGRAM || addr->sllc_ua) { + if (sk->sk_type == SOCK_DGRAM || addr->sllc_ua) { llc_build_and_send_ui_pkt(llc->sap, skb, addr->sllc_dmac, addr->sllc_dsap); goto out; @@ -805,7 +805,7 @@ goto out; } rc = -ENOPROTOOPT; - if (!(sk->type == SOCK_STREAM && !addr->sllc_ua)) + if (!(sk->sk_type == SOCK_STREAM && !addr->sllc_ua)) goto out; rc = llc_ui_send_data(sk, skb, noblock); if (rc) @@ -839,13 +839,13 @@ int rc = 0; lock_sock(sk); - if (sk->zapped) + if (sk->sk_zapped) goto out; *uaddrlen = sizeof(sllc); memset(uaddr, 0, *uaddrlen); if (peer) { rc = -ENOTCONN; - if (sk->state != TCP_ESTABLISHED) + if (sk->sk_state != TCP_ESTABLISHED) goto out; if(llc->dev) sllc.sllc_arphrd = llc->dev->type; diff -Nru a/net/llc/llc_c_ac.c b/net/llc/llc_c_ac.c --- a/net/llc/llc_c_ac.c Mon Jun 9 23:16:19 2003 +++ b/net/llc/llc_c_ac.c Mon Jun 9 23:16:19 2003 @@ -783,7 +783,7 @@ llc_sk(sk)->p_flag = value; if (state_changed) - sk->state_change(sk); + sk->sk_state_change(sk); } int llc_conn_ac_send_sabme_cmd_p_set_x(struct sock *sk, struct sk_buff *skb) diff -Nru a/net/llc/llc_conn.c b/net/llc/llc_conn.c --- a/net/llc/llc_conn.c Mon Jun 9 23:16:06 2003 +++ b/net/llc/llc_conn.c Mon Jun 9 23:16:06 2003 @@ -44,7 +44,7 @@ struct sockaddr_llc *addr = llc_ui_skb_cb(skb); /* save primitive for use by the user. */ - addr->sllc_family = skb->sk->family; + addr->sllc_family = skb->sk->sk_family; addr->sllc_arphrd = skb->dev->type; addr->sllc_test = prim == LLC_TEST_PRIM; addr->sllc_xid = prim == LLC_XID_PRIM; @@ -110,19 +110,20 @@ struct sock *parent = skb->sk; skb->sk = sk; - skb_queue_tail(&parent->receive_queue, skb); - sk->state_change(parent); + skb_queue_tail(&parent->sk_receive_queue, skb); + sk->sk_state_change(parent); } break; case LLC_DISC_PRIM: sock_hold(sk); - if (sk->type == SOCK_STREAM && sk->state == TCP_ESTABLISHED) { - sk->shutdown = SHUTDOWN_MASK; - sk->socket->state = SS_UNCONNECTED; - sk->state = TCP_CLOSE; - if (!test_bit(SOCK_DEAD, &sk->flags)) { - sk->state_change(sk); - __set_bit(SOCK_DEAD, &sk->flags); + if (sk->sk_type == SOCK_STREAM && + sk->sk_state == TCP_ESTABLISHED) { + sk->sk_shutdown = SHUTDOWN_MASK; + sk->sk_socket->state = SS_UNCONNECTED; + sk->sk_state = TCP_CLOSE; + if (!sock_flag(sk, SOCK_DEAD)) { + sk->sk_state_change(sk); + sock_set_flag(sk, SOCK_DEAD); } } kfree_skb(skb); @@ -149,28 +150,29 @@ switch (ev->cfm_prim) { case LLC_DATA_PRIM: if (!llc_data_accept_state(llc->state)) - sk->write_space(sk); + sk->sk_write_space(sk); else rc = llc->failed_data_req = 1; break; case LLC_CONN_PRIM: - if (sk->type == SOCK_STREAM && sk->state == TCP_SYN_SENT) { + if (sk->sk_type == SOCK_STREAM && + sk->sk_state == TCP_SYN_SENT) { if (ev->status) { - sk->socket->state = SS_UNCONNECTED; - sk->state = TCP_CLOSE; + sk->sk_socket->state = SS_UNCONNECTED; + sk->sk_state = TCP_CLOSE; } else { - sk->socket->state = SS_CONNECTED; - sk->state = TCP_ESTABLISHED; + sk->sk_socket->state = SS_CONNECTED; + sk->sk_state = TCP_ESTABLISHED; } - sk->state_change(sk); + sk->sk_state_change(sk); } break; case LLC_DISC_PRIM: sock_hold(sk); - if (sk->type == SOCK_STREAM && sk->state == TCP_CLOSING) { - sk->socket->state = SS_UNCONNECTED; - sk->state = TCP_CLOSE; - sk->state_change(sk); + if (sk->sk_type == SOCK_STREAM && sk->sk_state == TCP_CLOSING) { + sk->sk_socket->state = SS_UNCONNECTED; + sk->sk_state = TCP_CLOSE; + sk->sk_state_change(sk); } sock_put(sk); break; @@ -199,7 +201,7 @@ void llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb) { /* queue PDU to send to MAC layer */ - skb_queue_tail(&sk->write_queue, skb); + skb_queue_tail(&sk->sk_write_queue, skb); llc_conn_send_pdus(sk); } @@ -250,7 +252,7 @@ pdu = llc_pdu_sn_hdr(skb); llc_pdu_set_cmd_rsp(skb, LLC_PDU_CMD); llc_pdu_set_pf_bit(skb, first_p_bit); - skb_queue_tail(&sk->write_queue, skb); + skb_queue_tail(&sk->sk_write_queue, skb); first_p_bit = 0; llc->vS = LLC_I_GET_NS(pdu); howmany_resend++; @@ -291,7 +293,7 @@ llc_pdu_set_cmd_rsp(skb, LLC_PDU_RSP); llc_pdu_set_pf_bit(skb, first_f_bit); - skb_queue_tail(&sk->write_queue, skb); + skb_queue_tail(&sk->sk_write_queue, skb); first_f_bit = 0; llc->vS = LLC_I_GET_NS(pdu); howmany_resend++; @@ -351,7 +353,7 @@ { struct sk_buff *skb; - while ((skb = skb_dequeue(&sk->write_queue)) != NULL) { + while ((skb = skb_dequeue(&sk->sk_write_queue)) != NULL) { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); if (!LLC_PDU_TYPE_IS_I(pdu) && @@ -391,7 +393,7 @@ if (!rc && trans->next_state != NO_STATE_CHANGE) { llc->state = trans->next_state; if (!llc_data_accept_state(llc->state)) - sk->state_change(sk); + sk->sk_state_change(sk); } } out: @@ -489,7 +491,7 @@ struct sock *rc; read_lock_bh(&sap->sk_list.lock); - for (rc = sap->sk_list.list; rc; rc = rc->next) { + for (rc = sap->sk_list.list; rc; rc = rc->sk_next) { struct llc_opt *llc = llc_sk(rc); if (llc->laddr.lsap == laddr->lsap && @@ -518,10 +520,10 @@ struct sock *rc; read_lock_bh(&sap->sk_list.lock); - for (rc = sap->sk_list.list; rc; rc = rc->next) { + for (rc = sap->sk_list.list; rc; rc = rc->sk_next) { struct llc_opt *llc = llc_sk(rc); - if (rc->type == SOCK_STREAM && rc->state == TCP_LISTEN && + if (rc->sk_type == SOCK_STREAM && rc->sk_state == TCP_LISTEN && llc->laddr.lsap == laddr->lsap && llc_mac_match(llc->laddr.mac, laddr->mac)) break; @@ -545,10 +547,10 @@ struct sock *rc; read_lock_bh(&sap->sk_list.lock); - for (rc = sap->sk_list.list; rc; rc = rc->next) { + for (rc = sap->sk_list.list; rc; rc = rc->sk_next) { struct llc_opt *llc = llc_sk(rc); - if (rc->type == SOCK_DGRAM && + if (rc->sk_type == SOCK_DGRAM && llc->laddr.lsap == laddr->lsap && llc_mac_match(llc->laddr.mac, laddr->mac)) break; diff -Nru a/net/llc/llc_if.c b/net/llc/llc_if.c --- a/net/llc/llc_if.c Mon Jun 9 23:16:12 2003 +++ b/net/llc/llc_if.c Mon Jun 9 23:16:12 2003 @@ -223,7 +223,7 @@ memcpy(laddr.mac, lmac, sizeof(laddr.mac)); existing = llc_lookup_established(llc->sap, &daddr, &laddr); if (existing) { - if (existing->state == TCP_ESTABLISHED) { + if (existing->sk_state == TCP_ESTABLISHED) { sk = existing; goto out_put; } else @@ -261,7 +261,7 @@ struct sk_buff *skb; sock_hold(sk); - if (sk->type != SOCK_STREAM || sk->state != TCP_ESTABLISHED || + if (sk->sk_type != SOCK_STREAM || sk->sk_state != TCP_ESTABLISHED || llc_sk(sk)->state == LLC_CONN_STATE_ADM || llc_sk(sk)->state == LLC_CONN_OUT_OF_SVC) goto out; @@ -272,7 +272,7 @@ skb = alloc_skb(0, GFP_ATOMIC); if (!skb) goto out; - sk->state = TCP_CLOSING; + sk->sk_state = TCP_CLOSING; ev = llc_conn_ev(skb); ev->type = LLC_CONN_EV_TYPE_PRIM; ev->prim = LLC_DISC_PRIM; diff -Nru a/net/llc/llc_mac.c b/net/llc/llc_mac.c --- a/net/llc/llc_mac.c Mon Jun 9 23:16:17 2003 +++ b/net/llc/llc_mac.c Mon Jun 9 23:16:17 2003 @@ -126,7 +126,7 @@ goto drop; } - sk = llc_sk_alloc(parent->family, GFP_ATOMIC); + sk = llc_sk_alloc(parent->sk_family, GFP_ATOMIC); if (!sk) { sock_put(parent); goto drop; diff -Nru a/net/llc/llc_main.c b/net/llc/llc_main.c --- a/net/llc/llc_main.c Mon Jun 9 23:16:10 2003 +++ b/net/llc/llc_main.c Mon Jun 9 23:16:10 2003 @@ -206,7 +206,7 @@ llc->rw = 128; /* rx win size (opt and equal to * tx_win of remote LLC) */ skb_queue_head_init(&llc->pdu_unack_q); - sk->backlog_rcv = llc_backlog_rcv; + sk->sk_backlog_rcv = llc_backlog_rcv; llc_sk(sk) = llc; out: return rc; @@ -258,15 +258,15 @@ #ifdef DEBUG_LLC_CONN_ALLOC printk(KERN_INFO "%s: unackq=%d, txq=%d\n", __FUNCTION__, skb_queue_len(&llc->pdu_unack_q), - skb_queue_len(&sk->write_queue)); + skb_queue_len(&sk->sk_write_queue)); #endif - skb_queue_purge(&sk->receive_queue); - skb_queue_purge(&sk->write_queue); + skb_queue_purge(&sk->sk_receive_queue); + skb_queue_purge(&sk->sk_write_queue); skb_queue_purge(&llc->pdu_unack_q); #ifdef LLC_REFCNT_DEBUG - if (atomic_read(&sk->refcnt) != 1) { + if (atomic_read(&sk->sk_refcnt) != 1) { printk(KERN_DEBUG "Destruction of LLC sock %p delayed in %s, cnt=%d\n", - sk, __FUNCTION__, atomic_read(&sk->refcnt)); + sk, __FUNCTION__, atomic_read(&sk->sk_refcnt)); printk(KERN_DEBUG "%d LLC sockets are still alive\n", atomic_read(&llc_sock_nr)); } else { @@ -290,7 +290,7 @@ struct llc_opt *llc = llc_sk(sk); llc_conn_ac_stop_all_timers(sk, NULL); - skb_queue_purge(&sk->write_queue); + skb_queue_purge(&sk->sk_write_queue); skb_queue_purge(&llc->pdu_unack_q); llc->remote_busy_flag = 0; llc->cause_flag = 0; @@ -323,7 +323,7 @@ write_lock_bh(&sap->sk_list.lock); - for (sk = sap->sk_list.list; sk; sk = sk->next) { + for (sk = sap->sk_list.list; sk; sk = sk->sk_next) { llc_sk(sk)->state = LLC_CONN_STATE_TEMP; if (llc_send_disc(sk)) diff -Nru a/net/llc/llc_proc.c b/net/llc/llc_proc.c --- a/net/llc/llc_proc.c Mon Jun 9 23:16:07 2003 +++ b/net/llc/llc_proc.c Mon Jun 9 23:16:07 2003 @@ -44,7 +44,7 @@ sap = list_entry(sap_entry, struct llc_sap, node); read_lock_bh(&sap->sk_list.lock); - for (sk = sap->sk_list.list; sk; sk = sk->next) + for (sk = sap->sk_list.list; sk; sk = sk->sk_next) if (!pos--) { if (!sk) read_unlock_bh(&sap->sk_list.lock); @@ -76,8 +76,8 @@ goto out; } sk = v; - if (sk->next) { - sk = sk->next; + if (sk->sk_next) { + sk = sk->sk_next; goto out; } llc = llc_sk(sk); @@ -124,7 +124,7 @@ sk = v; llc = llc_sk(sk); - seq_printf(seq, "%2X %2X ", sk->type, + seq_printf(seq, "%2X %2X ", sk->sk_type, !llc_mac_null(llc->addr.sllc_mmac)); if (llc->dev && llc_mac_null(llc->addr.sllc_mmac)) @@ -136,8 +136,10 @@ seq_printf(seq, "@%02X ", llc->sap->laddr.lsap); llc_ui_format_mac(seq, llc->addr.sllc_dmac); seq_printf(seq, "@%02X %8d %8d %2d %3d %4d\n", llc->addr.sllc_dsap, - atomic_read(&sk->wmem_alloc), atomic_read(&sk->rmem_alloc), - sk->state, sk->socket ? SOCK_INODE(sk->socket)->i_uid : -1, + atomic_read(&sk->sk_wmem_alloc), + atomic_read(&sk->sk_rmem_alloc), + sk->sk_state, + sk->sk_socket ? SOCK_INODE(sk->sk_socket)->i_uid : -1, llc->link); out: return 0; @@ -181,7 +183,7 @@ timer_pending(&llc->pf_cycle_timer.timer), timer_pending(&llc->rej_sent_timer.timer), timer_pending(&llc->busy_state_timer.timer), - !!sk->backlog.tail, sock_owned_by_user(sk)); + !!sk->sk_backlog.tail, sock_owned_by_user(sk)); out: return 0; } diff -Nru a/net/llc/llc_sap.c b/net/llc/llc_sap.c --- a/net/llc/llc_sap.c Mon Jun 9 23:16:16 2003 +++ b/net/llc/llc_sap.c Mon Jun 9 23:16:16 2003 @@ -34,11 +34,11 @@ { write_lock_bh(&sap->sk_list.lock); llc_sk(sk)->sap = sap; - sk->next = sap->sk_list.list; - if (sk->next) - sap->sk_list.list->pprev = &sk->next; + sk->sk_next = sap->sk_list.list; + if (sk->sk_next) + sap->sk_list.list->sk_pprev = &sk->sk_next; sap->sk_list.list = sk; - sk->pprev = &sap->sk_list.list; + sk->sk_pprev = &sap->sk_list.list; sock_hold(sk); write_unlock_bh(&sap->sk_list.lock); } @@ -53,14 +53,14 @@ void llc_sap_unassign_sock(struct llc_sap *sap, struct sock *sk) { write_lock_bh(&sap->sk_list.lock); - if (sk->pprev) { - if (sk->next) - sk->next->pprev = sk->pprev; - *sk->pprev = sk->next; - sk->pprev = NULL; + if (sk->sk_pprev) { + if (sk->sk_next) + sk->sk_next->sk_pprev = sk->sk_pprev; + *sk->sk_pprev = sk->sk_next; + sk->sk_pprev = NULL; /* * This only makes sense if the socket was inserted on the - * list, if sk->pprev is NULL it wasn't + * list, if sk->sk_pprev is NULL it wasn't */ sock_put(sk); } @@ -195,7 +195,7 @@ ev->ind_cfm_flag = 0; llc_sap_next_state(sap, skb); if (ev->ind_cfm_flag == LLC_IND) { - if (skb->sk->state == TCP_LISTEN) + if (skb->sk->sk_state == TCP_LISTEN) kfree_skb(skb); else { llc_save_primitive(skb, ev->prim); diff -Nru a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c --- a/net/netlink/af_netlink.c Mon Jun 9 23:16:12 2003 +++ b/net/netlink/af_netlink.c Mon Jun 9 23:16:12 2003 @@ -66,7 +66,7 @@ void (*data_ready)(struct sock *sk, int bytes); }; -#define nlk_sk(__sk) ((struct netlink_opt *)(__sk)->protinfo) +#define nlk_sk(__sk) ((struct netlink_opt *)(__sk)->sk_protinfo) static struct sock *nl_table[MAX_LINKS]; static DECLARE_WAIT_QUEUE_HEAD(nl_table_wait); @@ -88,14 +88,14 @@ static void netlink_sock_destruct(struct sock *sk) { - skb_queue_purge(&sk->receive_queue); + skb_queue_purge(&sk->sk_receive_queue); - if (!test_bit(SOCK_DEAD, &sk->flags)) { + if (!sock_flag(sk, SOCK_DEAD)) { printk("Freeing alive netlink socket %p\n", sk); return; } - BUG_TRAP(atomic_read(&sk->rmem_alloc)==0); - BUG_TRAP(atomic_read(&sk->wmem_alloc)==0); + BUG_TRAP(!atomic_read(&sk->sk_rmem_alloc)); + BUG_TRAP(!atomic_read(&sk->sk_wmem_alloc)); BUG_TRAP(!nlk_sk(sk)->cb); kfree(nlk_sk(sk)); @@ -162,7 +162,7 @@ struct sock *sk; read_lock(&nl_table_lock); - for (sk=nl_table[protocol]; sk; sk=sk->next) { + for (sk = nl_table[protocol]; sk; sk = sk->sk_next) { if (nlk_sk(sk)->pid == pid) { sock_hold(sk); read_unlock(&nl_table_lock); @@ -182,7 +182,7 @@ struct sock *osk; netlink_table_grab(); - for (osk=nl_table[sk->protocol]; osk; osk=osk->next) { + for (osk = nl_table[sk->sk_protocol]; osk; osk = osk->sk_next) { if (nlk_sk(osk)->pid == pid) break; } @@ -190,8 +190,8 @@ err = -EBUSY; if (nlk_sk(sk)->pid == 0) { nlk_sk(sk)->pid = pid; - sk->next = nl_table[sk->protocol]; - nl_table[sk->protocol] = sk; + sk->sk_next = nl_table[sk->sk_protocol]; + nl_table[sk->sk_protocol] = sk; sock_hold(sk); err = 0; } @@ -205,9 +205,9 @@ struct sock **skp; netlink_table_grab(); - for (skp = &nl_table[sk->protocol]; *skp; skp = &((*skp)->next)) { + for (skp = &nl_table[sk->sk_protocol]; *skp; skp = &((*skp)->sk_next)) { if (*skp == sk) { - *skp = sk->next; + *skp = sk->sk_next; __sock_put(sk); break; } @@ -246,10 +246,10 @@ spin_lock_init(&nlk->cb_lock); init_waitqueue_head(&nlk->wait); - sk->destruct = netlink_sock_destruct; + sk->sk_destruct = netlink_sock_destruct; atomic_inc(&netlink_sock_nr); - sk->protocol=protocol; + sk->sk_protocol = protocol; return 0; } @@ -280,11 +280,13 @@ sock->sk = NULL; wake_up_interruptible_all(&nlk->wait); - skb_queue_purge(&sk->write_queue); + skb_queue_purge(&sk->sk_write_queue); if (nlk->pid && !nlk->groups) { - struct netlink_notify n = { .protocol = sk->protocol, - .pid = nlk->pid }; + struct netlink_notify n = { + .protocol = sk->sk_protocol, + .pid = nlk->pid, + }; notifier_call_chain(&netlink_chain, NETLINK_URELEASE, &n); } @@ -301,7 +303,7 @@ retry: netlink_table_grab(); - for (osk=nl_table[sk->protocol]; osk; osk=osk->next) { + for (osk = nl_table[sk->sk_protocol]; osk; osk = osk->sk_next) { if (nlk_sk(osk)->pid == pid) { /* Bind collision, search negative pid values. */ if (pid > 0) @@ -322,7 +324,8 @@ static inline int netlink_capable(struct socket *sock, unsigned flag) { - return (nl_nonroot[sock->sk->protocol] & flag) || capable(CAP_NET_ADMIN); + return (nl_nonroot[sock->sk->sk_protocol] & flag) || + capable(CAP_NET_ADMIN); } static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len) @@ -412,8 +415,8 @@ static void netlink_overrun(struct sock *sk) { if (!test_and_set_bit(0, &nlk_sk(sk)->state)) { - sk->err = ENOBUFS; - sk->error_report(sk); + sk->sk_err = ENOBUFS; + sk->sk_error_report(sk); } } @@ -422,7 +425,7 @@ struct sock *sk; struct netlink_opt *nlk; int len = skb->len; - int protocol = ssk->protocol; + int protocol = ssk->sk_protocol; long timeo; DECLARE_WAITQUEUE(wait, current); @@ -443,7 +446,7 @@ } #endif - if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf || + if (atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf || test_bit(0, &nlk->state)) { if (!timeo) { if (!nlk->pid) @@ -456,9 +459,9 @@ __set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&nlk->wait, &wait); - if ((atomic_read(&sk->rmem_alloc) > sk->rcvbuf || - test_bit(0, &nlk->state)) && - !test_bit(SOCK_DEAD, &sk->flags)) + if ((atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf || + test_bit(0, &nlk->state)) && + !sock_flag(sk, SOCK_DEAD)) timeo = schedule_timeout(timeo); __set_current_state(TASK_RUNNING); @@ -474,8 +477,8 @@ skb_orphan(skb); skb_set_owner_r(skb, sk); - skb_queue_tail(&sk->receive_queue, skb); - sk->data_ready(sk, len); + skb_queue_tail(&sk->sk_receive_queue, skb); + sk->sk_data_ready(sk, len); sock_put(sk); return len; @@ -490,16 +493,16 @@ #ifdef NL_EMULATE_DEV if (nlk->handler) { skb_orphan(skb); - nlk->handler(sk->protocol, skb); + nlk->handler(sk->sk_protocol, skb); return 0; } else #endif - if (atomic_read(&sk->rmem_alloc) <= sk->rcvbuf && + if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf && !test_bit(0, &nlk->state)) { skb_orphan(skb); skb_set_owner_r(skb, sk); - skb_queue_tail(&sk->receive_queue, skb); - sk->data_ready(sk, skb->len); + skb_queue_tail(&sk->sk_receive_queue, skb); + sk->sk_data_ready(sk, skb->len); return 0; } return -1; @@ -510,14 +513,14 @@ { struct sock *sk; struct sk_buff *skb2 = NULL; - int protocol = ssk->protocol; + int protocol = ssk->sk_protocol; int failure = 0, delivered = 0; /* While we sleep in clone, do not allow to change socket list */ netlink_lock_table(); - for (sk = nl_table[protocol]; sk; sk = sk->next) { + for (sk = nl_table[protocol]; sk; sk = sk->sk_next) { struct netlink_opt *nlk = nlk_sk(sk); if (ssk == sk) @@ -569,10 +572,10 @@ void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code) { struct sock *sk; - int protocol = ssk->protocol; + int protocol = ssk->sk_protocol; read_lock(&nl_table_lock); - for (sk = nl_table[protocol]; sk; sk = sk->next) { + for (sk = nl_table[protocol]; sk; sk = sk->sk_next) { struct netlink_opt *nlk = nlk_sk(sk); if (ssk == sk) continue; @@ -580,8 +583,8 @@ if (nlk->pid == pid || !(nlk->groups & group)) continue; - sk->err = code; - sk->error_report(sk); + sk->sk_err = code; + sk->sk_error_report(sk); } read_unlock(&nl_table_lock); } @@ -590,7 +593,7 @@ { struct netlink_opt *nlk = nlk_sk(sk); - if (skb_queue_len(&sk->receive_queue) == 0) + if (!skb_queue_len(&sk->sk_receive_queue)) clear_bit(0, &nlk->state); if (!test_bit(0, &nlk->state)) wake_up_interruptible(&nlk->wait); @@ -637,7 +640,7 @@ } err = -EMSGSIZE; - if ((unsigned)len > sk->sndbuf-32) + if ((unsigned)len > sk->sk_sndbuf - 32) goto out; err = -ENOBUFS; skb = alloc_skb(len, GFP_KERNEL); @@ -726,7 +729,7 @@ siocb->scm->creds = *NETLINK_CREDS(skb); skb_free_datagram(sk, skb); - if (nlk->cb && atomic_read(&sk->rmem_alloc) <= sk->rcvbuf / 2) + if (nlk->cb && atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2) netlink_dump(sk); scm_recv(sock, msg, siocb->scm, flags); @@ -770,7 +773,7 @@ return NULL; } sk = sock->sk; - sk->data_ready = netlink_data_ready; + sk->sk_data_ready = netlink_data_ready; if (input) nlk_sk(sk)->data_ready = input; @@ -821,16 +824,16 @@ if (len > 0) { spin_unlock(&nlk->cb_lock); - skb_queue_tail(&sk->receive_queue, skb); - sk->data_ready(sk, len); + skb_queue_tail(&sk->sk_receive_queue, skb); + sk->sk_data_ready(sk, len); return 0; } nlh = __nlmsg_put(skb, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, NLMSG_DONE, sizeof(int)); nlh->nlmsg_flags |= NLM_F_MULTI; memcpy(NLMSG_DATA(nlh), &len, sizeof(len)); - skb_queue_tail(&sk->receive_queue, skb); - sk->data_ready(sk, skb->len); + skb_queue_tail(&sk->sk_receive_queue, skb); + sk->sk_data_ready(sk, skb->len); cb->done(cb); nlk->cb = NULL; @@ -861,7 +864,7 @@ atomic_inc(&skb->users); cb->skb = skb; - sk = netlink_lookup(ssk->protocol, NETLINK_CB(skb).pid); + sk = netlink_lookup(ssk->sk_protocol, NETLINK_CB(skb).pid); if (sk == NULL) { netlink_destroy_callback(cb); return -ECONNREFUSED; @@ -922,7 +925,7 @@ return -ENOBUFS; nlk_sk(sk)->handler = function; write_lock_bh(&nl_emu_lock); - netlink_kernel[unit] = sk->socket; + netlink_kernel[unit] = sk->sk_socket; write_unlock_bh(&nl_emu_lock); return 0; } @@ -978,18 +981,18 @@ for (i=0; i<MAX_LINKS; i++) { read_lock(&nl_table_lock); - for (s = nl_table[i]; s; s = s->next) { + for (s = nl_table[i]; s; s = s->sk_next) { struct netlink_opt *nlk = nlk_sk(s); len+=sprintf(buffer+len,"%p %-3d %-6d %08x %-8d %-8d %p %d", s, - s->protocol, + s->sk_protocol, nlk->pid, nlk->groups, - atomic_read(&s->rmem_alloc), - atomic_read(&s->wmem_alloc), + atomic_read(&s->sk_rmem_alloc), + atomic_read(&s->sk_wmem_alloc), nlk->cb, - atomic_read(&s->refcnt) + atomic_read(&s->sk_refcnt) ); buffer[len++]='\n'; diff -Nru a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c --- a/net/netrom/af_netrom.c Mon Jun 9 23:16:12 2003 +++ b/net/netrom/af_netrom.c Mon Jun 9 23:16:12 2003 @@ -94,19 +94,19 @@ spin_lock_bh(&nr_list_lock); if ((s = nr_list) == sk) { - nr_list = s->next; + nr_list = s->sk_next; spin_unlock_bh(&nr_list_lock); return; } - while (s != NULL && s->next != NULL) { - if (s->next == sk) { - s->next = sk->next; + while (s && s->sk_next) { + if (s->sk_next == sk) { + s->sk_next = sk->sk_next; spin_unlock_bh(&nr_list_lock); return; } - s = s->next; + s = s->sk_next; } spin_unlock_bh(&nr_list_lock); @@ -120,7 +120,7 @@ struct sock *s; spin_lock_bh(&nr_list_lock); - for (s = nr_list; s != NULL; s = s->next) { + for (s = nr_list; s; s = s->sk_next) { if (nr_sk(s)->device == dev) nr_disconnect(s, ENETUNREACH); } @@ -149,7 +149,7 @@ static void nr_insert_socket(struct sock *sk) { spin_lock_bh(&nr_list_lock); - sk->next = nr_list; + sk->sk_next = nr_list; nr_list = sk; spin_unlock_bh(&nr_list_lock); } @@ -163,9 +163,9 @@ struct sock *s; spin_lock_bh(&nr_list_lock); - for (s = nr_list; s != NULL; s = s->next) { + for (s = nr_list; s; s = s->sk_next) { if (!ax25cmp(&nr_sk(s)->source_addr, addr) && - s->state == TCP_LISTEN) { + s->sk_state == TCP_LISTEN) { spin_unlock_bh(&nr_list_lock); return s; } @@ -183,7 +183,7 @@ struct sock *s; spin_lock_bh(&nr_list_lock); - for (s = nr_list; s != NULL; s = s->next) { + for (s = nr_list; s; s = s->sk_next) { nr_cb *nr = nr_sk(s); if (nr->my_index == index && nr->my_id == id) { @@ -205,7 +205,7 @@ struct sock *s; spin_lock_bh(&nr_list_lock); - for (s = nr_list; s != NULL; s = s->next) { + for (s = nr_list; s; s = s->sk_next) { nr_cb *nr = nr_sk(s); if (nr->your_index == index && nr->your_id == id && @@ -274,9 +274,10 @@ nr_clear_queues(sk); /* Flush the queues */ - while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) { - if (skb->sk != sk) { /* A pending connection */ - __set_bit(SOCK_DEAD, &skb->sk->flags); /* Queue the unaccepted socket for death */ + while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { + if (skb->sk != sk) { /* A pending connection */ + /* Queue the unaccepted socket for death */ + sock_set_flag(skb->sk, SOCK_DEAD); nr_start_heartbeat(skb->sk); nr_sk(skb->sk)->state = NR_STATE_0; } @@ -284,13 +285,14 @@ kfree_skb(skb); } - if (atomic_read(&sk->wmem_alloc) != 0 || atomic_read(&sk->rmem_alloc) != 0) { + if (atomic_read(&sk->sk_wmem_alloc) || + atomic_read(&sk->sk_rmem_alloc)) { /* Defer: outstanding buffers */ - init_timer(&sk->timer); - sk->timer.expires = jiffies + 10 * HZ; - sk->timer.function = nr_destroy_timer; - sk->timer.data = (unsigned long)sk; - add_timer(&sk->timer); + init_timer(&sk->sk_timer); + sk->sk_timer.expires = jiffies + 10 * HZ; + sk->sk_timer.function = nr_destroy_timer; + sk->sk_timer.data = (unsigned long)sk; + add_timer(&sk->sk_timer); } else sk_free(sk); } @@ -406,10 +408,10 @@ { struct sock *sk = sock->sk; - if (sk->state != TCP_LISTEN) { + if (sk->sk_state != TCP_LISTEN) { memset(&nr_sk(sk)->user_addr, 0, AX25_ADDR_LEN); - sk->max_ack_backlog = backlog; - sk->state = TCP_LISTEN; + sk->sk_max_ack_backlog = backlog; + sk->sk_state = TCP_LISTEN; return 0; } @@ -432,7 +434,7 @@ sock_init_data(sock, sk); sock->ops = &nr_proto_ops; - sk->protocol = protocol; + sk->sk_protocol = protocol; skb_queue_head_init(&nr->ack_queue); skb_queue_head_init(&nr->reseq_queue); @@ -461,7 +463,7 @@ struct sock *sk; nr_cb *nr, *onr; - if (osk->type != SOCK_SEQPACKET) + if (osk->sk_type != SOCK_SEQPACKET) return NULL; if ((sk = nr_alloc_sock()) == NULL) @@ -471,16 +473,16 @@ sock_init_data(NULL, sk); - sk->type = osk->type; - sk->socket = osk->socket; - sk->priority = osk->priority; - sk->protocol = osk->protocol; - sk->rcvbuf = osk->rcvbuf; - sk->sndbuf = osk->sndbuf; - sk->debug = osk->debug; - sk->state = TCP_ESTABLISHED; - sk->sleep = osk->sleep; - sk->zapped = osk->zapped; + sk->sk_type = osk->sk_type; + sk->sk_socket = osk->sk_socket; + sk->sk_priority = osk->sk_priority; + sk->sk_protocol = osk->sk_protocol; + sk->sk_rcvbuf = osk->sk_rcvbuf; + sk->sk_sndbuf = osk->sk_sndbuf; + sk->sk_debug = osk->sk_debug; + sk->sk_state = TCP_ESTABLISHED; + sk->sk_sleep = osk->sk_sleep; + sk->sk_zapped = osk->sk_zapped; skb_queue_head_init(&nr->ack_queue); skb_queue_head_init(&nr->reseq_queue); @@ -532,16 +534,16 @@ nr_stop_t4timer(sk); nr_stop_idletimer(sk); nr->state = NR_STATE_2; - sk->state = TCP_CLOSE; - sk->shutdown |= SEND_SHUTDOWN; - sk->state_change(sk); - __set_bit(SOCK_DEAD, &sk->flags); - __set_bit(SOCK_DESTROY, &sk->flags); - sk->socket = NULL; + sk->sk_state = TCP_CLOSE; + sk->sk_shutdown |= SEND_SHUTDOWN; + sk->sk_state_change(sk); + sock_set_flag(sk, SOCK_DEAD); + sock_set_flag(sk, SOCK_DESTROY); + sk->sk_socket = NULL; break; default: - sk->socket = NULL; + sk->sk_socket = NULL; break; } @@ -558,7 +560,7 @@ struct net_device *dev; ax25_address *user, *source; - if (sk->zapped == 0) + if (!sk->sk_zapped) return -EINVAL; if (addr_len < sizeof(struct sockaddr_ax25) || addr_len > sizeof(struct @@ -600,7 +602,7 @@ nr->device = dev; nr_insert_socket(sk); - sk->zapped = 0; + sk->sk_zapped = 0; SOCK_DEBUG(sk, "NET/ROM: socket is bound\n"); return 0; } @@ -614,20 +616,20 @@ ax25_address *user, *source = NULL; struct net_device *dev; - if (sk->state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) { + if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) { sock->state = SS_CONNECTED; return 0; /* Connect completed during a ERESTARTSYS event */ } - if (sk->state == TCP_CLOSE && sock->state == SS_CONNECTING) { + if (sk->sk_state == TCP_CLOSE && sock->state == SS_CONNECTING) { sock->state = SS_UNCONNECTED; return -ECONNREFUSED; } - if (sk->state == TCP_ESTABLISHED) + if (sk->sk_state == TCP_ESTABLISHED) return -EISCONN; /* No reconnect on a seqpacket socket */ - sk->state = TCP_CLOSE; + sk->sk_state = TCP_CLOSE; sock->state = SS_UNCONNECTED; if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25)) @@ -636,8 +638,8 @@ if (addr->sax25_family != AF_NETROM) return -EINVAL; - if (sk->zapped) { /* Must bind first - autobinding in this may or may not work */ - sk->zapped = 0; + if (sk->sk_zapped) { /* Must bind first - autobinding in this may or may not work */ + sk->sk_zapped = 0; if ((dev = nr_dev_first()) == NULL) return -ENETUNREACH; @@ -667,8 +669,8 @@ circuit++; /* Move to connecting socket, start sending Connect Requests */ - sock->state = SS_CONNECTING; - sk->state = TCP_SYN_SENT; + sock->state = SS_CONNECTING; + sk->sk_state = TCP_SYN_SENT; nr_establish_data_link(sk); @@ -677,21 +679,21 @@ nr_start_heartbeat(sk); /* Now the loop */ - if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) + if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) return -EINPROGRESS; /* * A Connect Ack with Choke or timeout or failed routing will go to * closed. */ - if (sk->state == TCP_SYN_SENT) { + if (sk->sk_state == TCP_SYN_SENT) { struct task_struct *tsk = current; DECLARE_WAITQUEUE(wait, tsk); - add_wait_queue(sk->sleep, &wait); + add_wait_queue(sk->sk_sleep, &wait); for (;;) { set_current_state(TASK_INTERRUPTIBLE); - if (sk->state != TCP_SYN_SENT) + if (sk->sk_state != TCP_SYN_SENT) break; if (!signal_pending(tsk)) { schedule(); @@ -700,10 +702,10 @@ return -ERESTARTSYS; } current->state = TASK_RUNNING; - remove_wait_queue(sk->sleep, &wait); + remove_wait_queue(sk->sk_sleep, &wait); } - if (sk->state != TCP_ESTABLISHED) { + if (sk->sk_state != TCP_ESTABLISHED) { sock->state = SS_UNCONNECTED; return sock_error(sk); /* Always set at this point */ } @@ -726,12 +728,12 @@ return -EINVAL; lock_sock(sk); - if (sk->type != SOCK_SEQPACKET) { + if (sk->sk_type != SOCK_SEQPACKET) { err = -EOPNOTSUPP; goto out; } - if (sk->state != TCP_LISTEN) { + if (sk->sk_state != TCP_LISTEN) { err = -EINVAL; goto out; } @@ -740,9 +742,9 @@ * The write queue this time is holding sockets ready to use * hooked into the SABM we saved */ - add_wait_queue(sk->sleep, &wait); + add_wait_queue(sk->sk_sleep, &wait); for (;;) { - skb = skb_dequeue(&sk->receive_queue); + skb = skb_dequeue(&sk->sk_receive_queue); if (skb) break; @@ -758,16 +760,16 @@ return -ERESTARTSYS; } current->state = TASK_RUNNING; - remove_wait_queue(sk->sleep, &wait); + remove_wait_queue(sk->sk_sleep, &wait); newsk = skb->sk; - newsk->pair = NULL; - newsk->socket = newsock; - newsk->sleep = &newsock->wait; + newsk->sk_pair = NULL; + newsk->sk_socket = newsock; + newsk->sk_sleep = &newsock->wait; /* Now attach up the new socket */ kfree_skb(skb); - sk->ack_backlog--; + sk->sk_ack_backlog--; newsock->sk = newsk; out: @@ -782,7 +784,7 @@ nr_cb *nr = nr_sk(sk); if (peer != 0) { - if (sk->state != TCP_ESTABLISHED) + if (sk->sk_state != TCP_ESTABLISHED) return -ENOTCONN; sax->fsa_ax25.sax25_family = AF_NETROM; sax->fsa_ax25.sax25_ndigis = 1; @@ -892,7 +894,8 @@ user = (ax25_address *)(skb->data + 21); - if (sk == NULL || sk->ack_backlog == sk->max_ack_backlog || (make = nr_make_new(sk)) == NULL) { + if (!sk || sk->sk_ack_backlog == sk->sk_max_ack_backlog || + (make = nr_make_new(sk)) == NULL) { nr_transmit_refusal(skb, 0); return 0; } @@ -900,7 +903,7 @@ window = skb->data[20]; skb->sk = make; - make->state = TCP_ESTABLISHED; + make->sk_state = TCP_ESTABLISHED; /* Fill in his circuit details */ nr_make = nr_sk(make); @@ -940,18 +943,18 @@ nr_make->vr = 0; nr_make->vl = 0; nr_make->state = NR_STATE_3; - sk->ack_backlog++; - make->pair = sk; + sk->sk_ack_backlog++; + make->sk_pair = sk; nr_insert_socket(make); - skb_queue_head(&sk->receive_queue, skb); + skb_queue_head(&sk->sk_receive_queue, skb); nr_start_heartbeat(make); nr_start_idletimer(make); - if (!test_bit(SOCK_DEAD, &sk->flags)) - sk->data_ready(sk, skb->len); + if (!sock_flag(sk, SOCK_DEAD)) + sk->sk_data_ready(sk, skb->len); return 1; } @@ -971,10 +974,10 @@ if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR)) return -EINVAL; - if (sk->zapped) + if (sk->sk_zapped) return -EADDRNOTAVAIL; - if (sk->shutdown & SEND_SHUTDOWN) { + if (sk->sk_shutdown & SEND_SHUTDOWN) { send_sig(SIGPIPE, current, 0); return -EPIPE; } @@ -991,7 +994,7 @@ if (sax.sax25_family != AF_NETROM) return -EINVAL; } else { - if (sk->state != TCP_ESTABLISHED) + if (sk->sk_state != TCP_ESTABLISHED) return -ENOTCONN; sax.sax25_family = AF_NETROM; sax.sax25_call = nr->dest_addr; @@ -1037,7 +1040,7 @@ memcpy_fromiovec(asmptr, msg->msg_iov, len); SOCK_DEBUG(sk, "NET/ROM: Transmitting buffer\n"); - if (sk->state != TCP_ESTABLISHED) { + if (sk->sk_state != TCP_ESTABLISHED) { kfree_skb(skb); return -ENOTCONN; } @@ -1061,7 +1064,7 @@ * us! We do one quick check first though */ - if (sk->state != TCP_ESTABLISHED) + if (sk->sk_state != TCP_ESTABLISHED) return -ENOTCONN; /* Now we can treat all alike */ @@ -1098,7 +1101,7 @@ switch (cmd) { case TIOCOUTQ: { long amount; - amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); + amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); if (amount < 0) amount = 0; return put_user(amount, (int *)arg); @@ -1108,16 +1111,16 @@ struct sk_buff *skb; long amount = 0L; /* These two are safe on a single CPU system as only user tasks fiddle here */ - if ((skb = skb_peek(&sk->receive_queue)) != NULL) + if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) amount = skb->len; return put_user(amount, (int *)arg); } case SIOCGSTAMP: if (sk != NULL) { - if (sk->stamp.tv_sec == 0) + if (!sk->sk_stamp.tv_sec) return -ENOENT; - return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0; + return copy_to_user((void *)arg, &sk->sk_stamp, sizeof(struct timeval)) ? -EFAULT : 0; } return -EINVAL; @@ -1159,7 +1162,7 @@ len += sprintf(buffer, "user_addr dest_node src_node dev my your st vs vr va t1 t2 t4 idle n2 wnd Snd-Q Rcv-Q inode\n"); - for (s = nr_list; s != NULL; s = s->next) { + for (s = nr_list; s; s = s->sk_next) { nr_cb *nr = nr_sk(s); if ((dev = nr->device) == NULL) @@ -1193,9 +1196,9 @@ nr->n2count, nr->n2, nr->window, - atomic_read(&s->wmem_alloc), - atomic_read(&s->rmem_alloc), - s->socket != NULL ? SOCK_INODE(s->socket)->i_ino : 0L); + atomic_read(&s->sk_wmem_alloc), + atomic_read(&s->sk_rmem_alloc), + s->sk_socket ? SOCK_INODE(s->sk_socket)->i_ino : 0L); pos = begin + len; diff -Nru a/net/netrom/nr_in.c b/net/netrom/nr_in.c --- a/net/netrom/nr_in.c Mon Jun 9 23:16:10 2003 +++ b/net/netrom/nr_in.c Mon Jun 9 23:16:10 2003 @@ -89,9 +89,9 @@ nr->state = NR_STATE_3; nr->n2count = 0; nr->window = skb->data[20]; - sk->state = TCP_ESTABLISHED; - if (!test_bit(SOCK_DEAD, &sk->flags)) - sk->state_change(sk); + sk->sk_state = TCP_ESTABLISHED; + if (!sock_flag(sk, SOCK_DEAD)) + sk->sk_state_change(sk); break; } diff -Nru a/net/netrom/nr_out.c b/net/netrom/nr_out.c --- a/net/netrom/nr_out.c Mon Jun 9 23:16:12 2003 +++ b/net/netrom/nr_out.c Mon Jun 9 23:16:12 2003 @@ -65,12 +65,12 @@ if (skb->len > 0) skbn->data[4] |= NR_MORE_FLAG; - skb_queue_tail(&sk->write_queue, skbn); /* Throw it on the queue */ + skb_queue_tail(&sk->sk_write_queue, skbn); /* Throw it on the queue */ } kfree_skb(skb); } else { - skb_queue_tail(&sk->write_queue, skb); /* Throw it on the queue */ + skb_queue_tail(&sk->sk_write_queue, skb); /* Throw it on the queue */ } nr_kick(sk); @@ -135,7 +135,7 @@ if (nr->condition & NR_COND_PEER_RX_BUSY) return; - if (skb_peek(&sk->write_queue) == NULL) + if (!skb_peek(&sk->sk_write_queue)) return; start = (skb_peek(&nr->ack_queue) == NULL) ? nr->va : nr->vs; @@ -154,11 +154,11 @@ /* * Dequeue the frame and copy it. */ - skb = skb_dequeue(&sk->write_queue); + skb = skb_dequeue(&sk->sk_write_queue); do { if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) { - skb_queue_head(&sk->write_queue, skb); + skb_queue_head(&sk->sk_write_queue, skb); break; } @@ -176,7 +176,8 @@ */ skb_queue_tail(&nr->ack_queue, skb); - } while (nr->vs != end && (skb = skb_dequeue(&sk->write_queue)) != NULL); + } while (nr->vs != end && + (skb = skb_dequeue(&sk->sk_write_queue)) != NULL); nr->vl = nr->vr; nr->condition &= ~NR_COND_ACK_PENDING; diff -Nru a/net/netrom/nr_subr.c b/net/netrom/nr_subr.c --- a/net/netrom/nr_subr.c Mon Jun 9 23:16:20 2003 +++ b/net/netrom/nr_subr.c Mon Jun 9 23:16:20 2003 @@ -36,7 +36,7 @@ { nr_cb *nr = nr_sk(sk); - skb_queue_purge(&sk->write_queue); + skb_queue_purge(&sk->sk_write_queue); skb_queue_purge(&nr->ack_queue); skb_queue_purge(&nr->reseq_queue); skb_queue_purge(&nr->frag_queue); @@ -75,7 +75,7 @@ while ((skb = skb_dequeue(&nr_sk(sk)->ack_queue)) != NULL) { if (skb_prev == NULL) - skb_queue_head(&sk->write_queue, skb); + skb_queue_head(&sk->sk_write_queue, skb); else skb_append(skb_prev, skb); skb_prev = skb; @@ -272,12 +272,12 @@ nr_sk(sk)->state = NR_STATE_0; - sk->state = TCP_CLOSE; - sk->err = reason; - sk->shutdown |= SEND_SHUTDOWN; - - if (!test_bit(SOCK_DEAD, &sk->flags)) - sk->state_change(sk); - - __set_bit(SOCK_DEAD, &sk->flags); + sk->sk_state = TCP_CLOSE; + sk->sk_err = reason; + sk->sk_shutdown |= SEND_SHUTDOWN; + + if (!sock_flag(sk, SOCK_DEAD)) { + sk->sk_state_change(sk); + sock_set_flag(sk, SOCK_DEAD); + } } diff -Nru a/net/netrom/nr_timer.c b/net/netrom/nr_timer.c --- a/net/netrom/nr_timer.c Mon Jun 9 23:16:16 2003 +++ b/net/netrom/nr_timer.c Mon Jun 9 23:16:16 2003 @@ -92,13 +92,13 @@ void nr_start_heartbeat(struct sock *sk) { - del_timer(&sk->timer); + del_timer(&sk->sk_timer); - sk->timer.data = (unsigned long)sk; - sk->timer.function = &nr_heartbeat_expiry; - sk->timer.expires = jiffies + 5 * HZ; + sk->sk_timer.data = (unsigned long)sk; + sk->sk_timer.function = &nr_heartbeat_expiry; + sk->sk_timer.expires = jiffies + 5 * HZ; - add_timer(&sk->timer); + add_timer(&sk->sk_timer); } void nr_stop_t1timer(struct sock *sk) @@ -123,7 +123,7 @@ void nr_stop_heartbeat(struct sock *sk) { - del_timer(&sk->timer); + del_timer(&sk->sk_timer); } int nr_t1timer_running(struct sock *sk) @@ -141,9 +141,8 @@ case NR_STATE_0: /* Magic here: If we listen() and a new link dies before it is accepted() it isn't 'dead' so doesn't get removed. */ - if (test_bit(SOCK_DESTROY, &sk->flags) || - (sk->state == TCP_LISTEN && - test_bit(SOCK_DEAD, &sk->flags))) { + if (sock_flag(sk, SOCK_DESTROY) || + (sk->sk_state == TCP_LISTEN && sock_flag(sk, SOCK_DEAD))) { nr_destroy_socket(sk); return; } @@ -153,7 +152,7 @@ /* * Check for the state of the receive buffer. */ - if (atomic_read(&sk->rmem_alloc) < (sk->rcvbuf / 2) && + if (atomic_read(&sk->sk_rmem_alloc) < (sk->sk_rcvbuf / 2) && (nr->condition & NR_COND_OWN_RX_BUSY)) { nr->condition &= ~NR_COND_OWN_RX_BUSY; nr->condition &= ~NR_COND_ACK_PENDING; @@ -207,14 +206,14 @@ nr_stop_t2timer(sk); nr_stop_t4timer(sk); - sk->state = TCP_CLOSE; - sk->err = 0; - sk->shutdown |= SEND_SHUTDOWN; - - if (!test_bit(SOCK_DEAD, &sk->flags)) - sk->state_change(sk); - - __set_bit(SOCK_DEAD, &sk->flags); + sk->sk_state = TCP_CLOSE; + sk->sk_err = 0; + sk->sk_shutdown |= SEND_SHUTDOWN; + + if (!sock_flag(sk, SOCK_DEAD)) { + sk->sk_state_change(sk); + sock_set_flag(sk, SOCK_DEAD); + } bh_unlock_sock(sk); } diff -Nru a/net/netsyms.c b/net/netsyms.c --- a/net/netsyms.c Mon Jun 9 23:16:10 2003 +++ b/net/netsyms.c Mon Jun 9 23:16:10 2003 @@ -337,7 +337,7 @@ EXPORT_SYMBOL(xfrm_alloc_spi); EXPORT_SYMBOL(xfrm_state_flush); EXPORT_SYMBOL(xfrm_policy_kill); -EXPORT_SYMBOL(xfrm_policy_delete); +EXPORT_SYMBOL(xfrm_policy_bysel); EXPORT_SYMBOL(xfrm_policy_insert); EXPORT_SYMBOL(xfrm_policy_walk); EXPORT_SYMBOL(xfrm_policy_flush); @@ -477,8 +477,10 @@ EXPORT_SYMBOL(sysctl_max_syn_backlog); #endif -EXPORT_SYMBOL(ip_generic_getfrag); +#endif +#if defined (CONFIG_IPV6_MODULE) || defined (CONFIG_IP_SCTP_MODULE) || defined (CONFIG_IPV6_TUNNEL_MODULE) +EXPORT_SYMBOL(ip_generic_getfrag); #endif EXPORT_SYMBOL(tcp_read_sock); @@ -608,8 +610,6 @@ EXPORT_SYMBOL(dev_mc_delete); EXPORT_SYMBOL(dev_mc_upload); EXPORT_SYMBOL(__kill_fasync); - -EXPORT_SYMBOL(if_port_text); #ifdef CONFIG_HIPPI EXPORT_SYMBOL(hippi_type_trans); diff -Nru a/net/packet/af_packet.c b/net/packet/af_packet.c --- a/net/packet/af_packet.c Mon Jun 9 23:16:15 2003 +++ b/net/packet/af_packet.c Mon Jun 9 23:16:15 2003 @@ -191,14 +191,14 @@ #endif }; -#define pkt_sk(__sk) ((struct packet_opt *)(__sk)->protinfo) +#define pkt_sk(__sk) ((struct packet_opt *)(__sk)->sk_protinfo) void packet_sock_destruct(struct sock *sk) { - BUG_TRAP(atomic_read(&sk->rmem_alloc)==0); - BUG_TRAP(atomic_read(&sk->wmem_alloc)==0); + BUG_TRAP(!atomic_read(&sk->sk_rmem_alloc)); + BUG_TRAP(!atomic_read(&sk->sk_wmem_alloc)); - if (!test_bit(SOCK_DEAD, &sk->flags)) { + if (!sock_flag(sk, SOCK_DEAD)) { printk("Attempt to release alive packet socket: %p\n", sk); return; } @@ -356,7 +356,7 @@ err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len); skb->protocol = proto; skb->dev = dev; - skb->priority = sk->priority; + skb->priority = sk->sk_priority; if (err) goto out_free; @@ -418,7 +418,7 @@ structure, so that corresponding packet head never delivered to user. */ - if (sk->type != SOCK_DGRAM) + if (sk->sk_type != SOCK_DGRAM) skb_push(skb, skb->data - skb->mac.raw); else if (skb->pkt_type == PACKET_OUTGOING) { /* Special case: outgoing packets have ll header at head */ @@ -428,13 +428,14 @@ snaplen = skb->len; - if (sk->filter) { + if (sk->sk_filter) { unsigned res = snaplen; struct sk_filter *filter; bh_lock_sock(sk); - if ((filter = sk->filter) != NULL) - res = sk_run_filter(skb, sk->filter->insns, sk->filter->len); + if ((filter = sk->sk_filter) != NULL) + res = sk_run_filter(skb, sk->sk_filter->insns, + sk->sk_filter->len); bh_unlock_sock(sk); if (res == 0) @@ -443,7 +444,8 @@ snaplen = res; } - if (atomic_read(&sk->rmem_alloc) + skb->truesize >= (unsigned)sk->rcvbuf) + if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >= + (unsigned)sk->sk_rcvbuf) goto drop_n_acct; if (skb_shared(skb)) { @@ -475,17 +477,17 @@ skb_set_owner_r(skb, sk); skb->dev = NULL; - spin_lock(&sk->receive_queue.lock); + spin_lock(&sk->sk_receive_queue.lock); po->stats.tp_packets++; - __skb_queue_tail(&sk->receive_queue, skb); - spin_unlock(&sk->receive_queue.lock); - sk->data_ready(sk,skb->len); + __skb_queue_tail(&sk->sk_receive_queue, skb); + spin_unlock(&sk->sk_receive_queue.lock); + sk->sk_data_ready(sk, skb->len); return 0; drop_n_acct: - spin_lock(&sk->receive_queue.lock); + spin_lock(&sk->sk_receive_queue.lock); po->stats.tp_drops++; - spin_unlock(&sk->receive_queue.lock); + spin_unlock(&sk->sk_receive_queue.lock); drop_n_restore: if (skb_head != skb->data && skb_shared(skb)) { @@ -518,7 +520,7 @@ po = pkt_sk(sk); if (dev->hard_header) { - if (sk->type != SOCK_DGRAM) + if (sk->sk_type != SOCK_DGRAM) skb_push(skb, skb->data - skb->mac.raw); else if (skb->pkt_type == PACKET_OUTGOING) { /* Special case: outgoing packets have ll header at head */ @@ -530,13 +532,14 @@ snaplen = skb->len; - if (sk->filter) { + if (sk->sk_filter) { unsigned res = snaplen; struct sk_filter *filter; bh_lock_sock(sk); - if ((filter = sk->filter) != NULL) - res = sk_run_filter(skb, sk->filter->insns, sk->filter->len); + if ((filter = sk->sk_filter) != NULL) + res = sk_run_filter(skb, sk->sk_filter->insns, + sk->sk_filter->len); bh_unlock_sock(sk); if (res == 0) @@ -545,7 +548,7 @@ snaplen = res; } - if (sk->type == SOCK_DGRAM) { + if (sk->sk_type == SOCK_DGRAM) { macoff = netoff = TPACKET_ALIGN(TPACKET_HDRLEN) + 16; } else { unsigned maclen = skb->nh.raw - skb->data; @@ -555,7 +558,8 @@ if (macoff + snaplen > po->frame_size) { if (po->copy_thresh && - atomic_read(&sk->rmem_alloc) + skb->truesize < (unsigned)sk->rcvbuf) { + atomic_read(&sk->sk_rmem_alloc) + skb->truesize < + (unsigned)sk->sk_rcvbuf) { if (skb_shared(skb)) { copy_skb = skb_clone(skb, GFP_ATOMIC); } else { @@ -572,7 +576,7 @@ if (snaplen > skb->len-skb->data_len) snaplen = skb->len-skb->data_len; - spin_lock(&sk->receive_queue.lock); + spin_lock(&sk->sk_receive_queue.lock); h = po->iovec[po->head]; if (h->tp_status) @@ -581,11 +585,11 @@ po->stats.tp_packets++; if (copy_skb) { status |= TP_STATUS_COPY; - __skb_queue_tail(&sk->receive_queue, copy_skb); + __skb_queue_tail(&sk->sk_receive_queue, copy_skb); } if (!po->stats.tp_drops) status &= ~TP_STATUS_LOSING; - spin_unlock(&sk->receive_queue.lock); + spin_unlock(&sk->sk_receive_queue.lock); memcpy((u8*)h + macoff, skb->data, snaplen); @@ -621,7 +625,7 @@ } } - sk->data_ready(sk, 0); + sk->sk_data_ready(sk, 0); drop_n_restore: if (skb_head != skb->data && skb_shared(skb)) { @@ -634,9 +638,9 @@ ring_is_full: po->stats.tp_drops++; - spin_unlock(&sk->receive_queue.lock); + spin_unlock(&sk->sk_receive_queue.lock); - sk->data_ready(sk, 0); + sk->sk_data_ready(sk, 0); if (copy_skb) kfree_skb(copy_skb); goto drop_n_restore; @@ -713,7 +717,7 @@ skb->protocol = proto; skb->dev = dev; - skb->priority = sk->priority; + skb->priority = sk->sk_priority; err = -ENETDOWN; if (!(dev->flags & IFF_UP)) @@ -755,9 +759,9 @@ return 0; write_lock_bh(&packet_sklist_lock); - for (skp = &packet_sklist; *skp; skp = &(*skp)->next) { + for (skp = &packet_sklist; *skp; skp = &(*skp)->sk_next) { if (*skp == sk) { - *skp = sk->next; + *skp = sk->sk_next; __sock_put(sk); break; } @@ -799,7 +803,7 @@ /* Purge queues */ - skb_queue_purge(&sk->receive_queue); + skb_queue_purge(&sk->sk_receive_queue); sock_put(sk); return 0; @@ -843,9 +847,9 @@ sock_hold(sk); po->running = 1; } else { - sk->err = ENETDOWN; - if (!test_bit(SOCK_DEAD, &sk->flags)) - sk->error_report(sk); + sk->sk_err = ENETDOWN; + if (!sock_flag(sk, SOCK_DEAD)) + sk->sk_error_report(sk); } } else { dev_add_pack(&po->prot_hook); @@ -959,10 +963,10 @@ if (!po) goto out_free; memset(po, 0, sizeof(*po)); - sk->family = PF_PACKET; + sk->sk_family = PF_PACKET; po->num = protocol; - sk->destruct = packet_sock_destruct; + sk->sk_destruct = packet_sock_destruct; atomic_inc(&packet_socks_nr); /* @@ -985,7 +989,7 @@ } write_lock_bh(&packet_sklist_lock); - sk->next = packet_sklist; + sk->sk_next = packet_sklist; packet_sklist = sk; sock_hold(sk); write_unlock_bh(&packet_sklist_lock); @@ -1342,10 +1346,10 @@ if (len > sizeof(struct tpacket_stats)) len = sizeof(struct tpacket_stats); - spin_lock_bh(&sk->receive_queue.lock); + spin_lock_bh(&sk->sk_receive_queue.lock); st = po->stats; memset(&po->stats, 0, sizeof(st)); - spin_unlock_bh(&sk->receive_queue.lock); + spin_unlock_bh(&sk->sk_receive_queue.lock); st.tp_packets += st.tp_drops; if (copy_to_user(optval, &st, len)) @@ -1368,7 +1372,7 @@ struct net_device *dev = (struct net_device*)data; read_lock(&packet_sklist_lock); - for (sk = packet_sklist; sk; sk = sk->next) { + for (sk = packet_sklist; sk; sk = sk->sk_next) { struct packet_opt *po = pkt_sk(sk); switch (msg) { @@ -1380,9 +1384,9 @@ __dev_remove_pack(&po->prot_hook); __sock_put(sk); po->running = 0; - sk->err = ENETDOWN; - if (!test_bit(SOCK_DEAD, &sk->flags)) - sk->error_report(sk); + sk->sk_err = ENETDOWN; + if (!sock_flag(sk, SOCK_DEAD)) + sk->sk_error_report(sk); } if (msg == NETDEV_UNREGISTER) { po->ifindex = -1; @@ -1424,7 +1428,7 @@ switch(cmd) { case SIOCOUTQ: { - int amount = atomic_read(&sk->wmem_alloc); + int amount = atomic_read(&sk->sk_wmem_alloc); return put_user(amount, (int *)arg); } case SIOCINQ: @@ -1432,17 +1436,17 @@ struct sk_buff *skb; int amount = 0; - spin_lock_bh(&sk->receive_queue.lock); - skb = skb_peek(&sk->receive_queue); + spin_lock_bh(&sk->sk_receive_queue.lock); + skb = skb_peek(&sk->sk_receive_queue); if (skb) amount = skb->len; - spin_unlock_bh(&sk->receive_queue.lock); + spin_unlock_bh(&sk->sk_receive_queue.lock); return put_user(amount, (int *)arg); } case SIOCGSTAMP: - if (sk->stamp.tv_sec==0) + if (!sk->sk_stamp.tv_sec) return -ENOENT; - if (copy_to_user((void *)arg, &sk->stamp, + if (copy_to_user((void *)arg, &sk->sk_stamp, sizeof(struct timeval))) return -EFAULT; break; @@ -1482,14 +1486,14 @@ struct packet_opt *po = pkt_sk(sk); unsigned int mask = datagram_poll(file, sock, wait); - spin_lock_bh(&sk->receive_queue.lock); + spin_lock_bh(&sk->sk_receive_queue.lock); if (po->iovec) { unsigned last = po->head ? po->head-1 : po->iovmax; if (po->iovec[last]->tp_status) mask |= POLLIN | POLLRDNORM; } - spin_unlock_bh(&sk->receive_queue.lock); + spin_unlock_bh(&sk->sk_receive_queue.lock); return mask; } @@ -1635,20 +1639,20 @@ err = 0; #define XC(a, b) ({ __typeof__ ((a)) __t; __t = (a); (a) = (b); __t; }) - spin_lock_bh(&sk->receive_queue.lock); + spin_lock_bh(&sk->sk_receive_queue.lock); pg_vec = XC(po->pg_vec, pg_vec); io_vec = XC(po->iovec, io_vec); po->iovmax = req->tp_frame_nr-1; po->head = 0; po->frame_size = req->tp_frame_size; - spin_unlock_bh(&sk->receive_queue.lock); + spin_unlock_bh(&sk->sk_receive_queue.lock); order = XC(po->pg_vec_order, order); req->tp_block_nr = XC(po->pg_vec_len, req->tp_block_nr); po->pg_vec_pages = req->tp_block_size/PAGE_SIZE; po->prot_hook.func = po->iovec ? tpacket_rcv : packet_rcv; - skb_queue_purge(&sk->receive_queue); + skb_queue_purge(&sk->sk_receive_queue); #undef XC if (atomic_read(&po->mapped)) printk(KERN_DEBUG "packet_mmap: vma is busy: %d\n", atomic_read(&po->mapped)); @@ -1778,17 +1782,17 @@ read_lock(&packet_sklist_lock); - for (s = packet_sklist; s; s = s->next) { + for (s = packet_sklist; s; s = s->sk_next) { struct packet_opt *po = pkt_sk(s); len+=sprintf(buffer+len,"%p %-6d %-4d %04x %-5d %1d %-6u %-6u %-6lu", s, - atomic_read(&s->refcnt), - s->type, + atomic_read(&s->sk_refcnt), + s->sk_type, ntohs(po->num), po->ifindex, po->running, - atomic_read(&s->rmem_alloc), + atomic_read(&s->sk_rmem_alloc), sock_i_uid(s), sock_i_ino(s) ); diff -Nru a/net/rose/af_rose.c b/net/rose/af_rose.c --- a/net/rose/af_rose.c Mon Jun 9 23:16:12 2003 +++ b/net/rose/af_rose.c Mon Jun 9 23:16:12 2003 @@ -155,19 +155,19 @@ spin_lock_bh(&rose_list_lock); if ((s = rose_list) == sk) { - rose_list = s->next; + rose_list = s->sk_next; spin_unlock_bh(&rose_list_lock); return; } - while (s != NULL && s->next != NULL) { - if (s->next == sk) { - s->next = sk->next; + while (s && s->sk_next) { + if (s->sk_next == sk) { + s->sk_next = sk->sk_next; spin_unlock_bh(&rose_list_lock); return; } - s = s->next; + s = s->sk_next; } spin_unlock_bh(&rose_list_lock); } @@ -181,7 +181,7 @@ struct sock *s; spin_lock_bh(&rose_list_lock); - for (s = rose_list; s != NULL; s = s->next) { + for (s = rose_list; s; s = s->sk_next) { rose_cb *rose = rose_sk(s); if (rose->neighbour == neigh) { @@ -201,7 +201,7 @@ struct sock *s; spin_lock_bh(&rose_list_lock); - for (s = rose_list; s != NULL; s = s->next) { + for (s = rose_list; s; s = s->sk_next) { rose_cb *rose = rose_sk(s); if (rose->device == dev) { @@ -244,7 +244,7 @@ { spin_lock_bh(&rose_list_lock); - sk->next = rose_list; + sk->sk_next = rose_list; rose_list = sk; spin_unlock_bh(&rose_list_lock); } @@ -258,23 +258,23 @@ struct sock *s; spin_lock_bh(&rose_list_lock); - for (s = rose_list; s != NULL; s = s->next) { + for (s = rose_list; s; s = s->sk_next) { rose_cb *rose = rose_sk(s); if (!rosecmp(&rose->source_addr, addr) && !ax25cmp(&rose->source_call, call) && - !rose->source_ndigis && s->state == TCP_LISTEN) { + !rose->source_ndigis && s->sk_state == TCP_LISTEN) { spin_unlock_bh(&rose_list_lock); return s; } } - for (s = rose_list; s != NULL; s = s->next) { + for (s = rose_list; s; s = s->sk_next) { rose_cb *rose = rose_sk(s); if (!rosecmp(&rose->source_addr, addr) && !ax25cmp(&rose->source_call, &null_ax25_address) && - s->state == TCP_LISTEN) { + s->sk_state == TCP_LISTEN) { spin_unlock_bh(&rose_list_lock); return s; } @@ -292,7 +292,7 @@ struct sock *s; spin_lock_bh(&rose_list_lock); - for (s = rose_list; s != NULL; s = s->next) { + for (s = rose_list; s; s = s->sk_next) { rose_cb *rose = rose_sk(s); if (rose->lci == lci && rose->neighbour == neigh) { @@ -355,9 +355,10 @@ rose_clear_queues(sk); /* Flush the queues */ - while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) { - if (skb->sk != sk) { /* A pending connection */ - __set_bit(SOCK_DEAD, &skb->sk->flags); /* Queue the unaccepted socket for death */ + while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { + if (skb->sk != sk) { /* A pending connection */ + /* Queue the unaccepted socket for death */ + sock_set_flag(skb->sk, SOCK_DEAD); rose_start_heartbeat(skb->sk); rose_sk(skb->sk)->state = ROSE_STATE_0; } @@ -365,13 +366,14 @@ kfree_skb(skb); } - if (atomic_read(&sk->wmem_alloc) != 0 || atomic_read(&sk->rmem_alloc) != 0) { + if (atomic_read(&sk->sk_wmem_alloc) || + atomic_read(&sk->sk_rmem_alloc)) { /* Defer: outstanding buffers */ - init_timer(&sk->timer); - sk->timer.expires = jiffies + 10 * HZ; - sk->timer.function = rose_destroy_timer; - sk->timer.data = (unsigned long)sk; - add_timer(&sk->timer); + init_timer(&sk->sk_timer); + sk->sk_timer.expires = jiffies + 10 * HZ; + sk->sk_timer.function = rose_destroy_timer; + sk->sk_timer.data = (unsigned long)sk; + add_timer(&sk->sk_timer); } else sk_free(sk); } @@ -503,15 +505,15 @@ { struct sock *sk = sock->sk; - if (sk->state != TCP_LISTEN) { + if (sk->sk_state != TCP_LISTEN) { rose_cb *rose = rose_sk(sk); rose->dest_ndigis = 0; memset(&rose->dest_addr, 0, ROSE_ADDR_LEN); memset(&rose->dest_call, 0, AX25_ADDR_LEN); memset(rose->dest_digis, 0, AX25_ADDR_LEN * ROSE_MAX_DIGIS); - sk->max_ack_backlog = backlog; - sk->state = TCP_LISTEN; + sk->sk_max_ack_backlog = backlog; + sk->sk_state = TCP_LISTEN; return 0; } @@ -540,7 +542,7 @@ #endif sock->ops = &rose_proto_ops; - sk->protocol = protocol; + sk->sk_protocol = protocol; init_timer(&rose->timer); init_timer(&rose->idletimer); @@ -561,7 +563,7 @@ struct sock *sk; rose_cb *rose, *orose; - if (osk->type != SOCK_SEQPACKET) + if (osk->sk_type != SOCK_SEQPACKET) return NULL; if ((sk = rose_alloc_sock()) == NULL) @@ -577,16 +579,16 @@ rose->fraglen = 0; #endif - sk->type = osk->type; - sk->socket = osk->socket; - sk->priority = osk->priority; - sk->protocol = osk->protocol; - sk->rcvbuf = osk->rcvbuf; - sk->sndbuf = osk->sndbuf; - sk->debug = osk->debug; - sk->state = TCP_ESTABLISHED; - sk->sleep = osk->sleep; - sk->zapped = osk->zapped; + sk->sk_type = osk->sk_type; + sk->sk_socket = osk->sk_socket; + sk->sk_priority = osk->sk_priority; + sk->sk_protocol = osk->sk_protocol; + sk->sk_rcvbuf = osk->sk_rcvbuf; + sk->sk_sndbuf = osk->sk_sndbuf; + sk->sk_debug = osk->sk_debug; + sk->sk_state = TCP_ESTABLISHED; + sk->sk_sleep = osk->sk_sleep; + sk->sk_zapped = osk->sk_zapped; init_timer(&rose->timer); init_timer(&rose->idletimer); @@ -634,11 +636,11 @@ rose_write_internal(sk, ROSE_CLEAR_REQUEST); rose_start_t3timer(sk); rose->state = ROSE_STATE_2; - sk->state = TCP_CLOSE; - sk->shutdown |= SEND_SHUTDOWN; - sk->state_change(sk); - __set_bit(SOCK_DEAD, &sk->flags); - __set_bit(SOCK_DESTROY, &sk->flags); + sk->sk_state = TCP_CLOSE; + sk->sk_shutdown |= SEND_SHUTDOWN; + sk->sk_state_change(sk); + sock_set_flag(sk, SOCK_DEAD); + sock_set_flag(sk, SOCK_DESTROY); break; default: @@ -646,7 +648,7 @@ } sock->sk = NULL; - sk->socket = NULL; /* Not used, but we should do this. **/ + sk->sk_socket = NULL; /* Not used, but we should do this. **/ return 0; } @@ -660,7 +662,7 @@ ax25_address *user, *source; int n; - if (sk->zapped == 0) + if (!sk->sk_zapped) return -EINVAL; if (addr_len != sizeof(struct sockaddr_rose) && addr_len != sizeof(struct full_sockaddr_rose)) @@ -705,7 +707,7 @@ rose_insert_socket(sk); - sk->zapped = 0; + sk->sk_zapped = 0; SOCK_DEBUG(sk, "ROSE: socket is bound\n"); return 0; } @@ -720,20 +722,20 @@ struct net_device *dev; int n; - if (sk->state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) { + if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) { sock->state = SS_CONNECTED; return 0; /* Connect completed during a ERESTARTSYS event */ } - if (sk->state == TCP_CLOSE && sock->state == SS_CONNECTING) { + if (sk->sk_state == TCP_CLOSE && sock->state == SS_CONNECTING) { sock->state = SS_UNCONNECTED; return -ECONNREFUSED; } - if (sk->state == TCP_ESTABLISHED) + if (sk->sk_state == TCP_ESTABLISHED) return -EISCONN; /* No reconnect on a seqpacket socket */ - sk->state = TCP_CLOSE; + sk->sk_state = TCP_CLOSE; sock->state = SS_UNCONNECTED; if (addr_len != sizeof(struct sockaddr_rose) && addr_len != sizeof(struct full_sockaddr_rose)) @@ -761,8 +763,8 @@ if (!rose->lci) return -ENETUNREACH; - if (sk->zapped) { /* Must bind first - autobinding in this may or may not work */ - sk->zapped = 0; + if (sk->sk_zapped) { /* Must bind first - autobinding in this may or may not work */ + sk->sk_zapped = 0; if ((dev = rose_dev_first()) == NULL) return -ENETUNREACH; @@ -794,7 +796,7 @@ /* Move to connecting socket, start sending Connect Requests */ sock->state = SS_CONNECTING; - sk->state = TCP_SYN_SENT; + sk->sk_state = TCP_SYN_SENT; rose->state = ROSE_STATE_1; @@ -805,21 +807,21 @@ rose_start_t1timer(sk); /* Now the loop */ - if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) + if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) return -EINPROGRESS; /* * A Connect Ack with Choke or timeout or failed routing will go to * closed. */ - if (sk->state == TCP_SYN_SENT) { + if (sk->sk_state == TCP_SYN_SENT) { struct task_struct *tsk = current; DECLARE_WAITQUEUE(wait, tsk); - add_wait_queue(sk->sleep, &wait); + add_wait_queue(sk->sk_sleep, &wait); for (;;) { set_current_state(TASK_INTERRUPTIBLE); - if (sk->state != TCP_SYN_SENT) + if (sk->sk_state != TCP_SYN_SENT) break; if (!signal_pending(tsk)) { schedule(); @@ -828,10 +830,10 @@ return -ERESTARTSYS; } current->state = TASK_RUNNING; - remove_wait_queue(sk->sleep, &wait); + remove_wait_queue(sk->sk_sleep, &wait); } - if (sk->state != TCP_ESTABLISHED) { + if (sk->sk_state != TCP_ESTABLISHED) { sock->state = SS_UNCONNECTED; return sock_error(sk); /* Always set at this point */ } @@ -854,12 +856,12 @@ return -EINVAL; lock_sock(sk); - if (sk->type != SOCK_SEQPACKET) { + if (sk->sk_type != SOCK_SEQPACKET) { err = -EOPNOTSUPP; goto out; } - if (sk->state != TCP_LISTEN) { + if (sk->sk_state != TCP_LISTEN) { err = -EINVAL; goto out; } @@ -868,9 +870,9 @@ * The write queue this time is holding sockets ready to use * hooked into the SABM we saved */ - add_wait_queue(sk->sleep, &wait); + add_wait_queue(sk->sk_sleep, &wait); for (;;) { - skb = skb_dequeue(&sk->receive_queue); + skb = skb_dequeue(&sk->sk_receive_queue); if (skb) break; @@ -886,17 +888,17 @@ return -ERESTARTSYS; } current->state = TASK_RUNNING; - remove_wait_queue(sk->sleep, &wait); + remove_wait_queue(sk->sk_sleep, &wait); newsk = skb->sk; - newsk->pair = NULL; - newsk->socket = newsock; - newsk->sleep = &newsock->wait; + newsk->sk_pair = NULL; + newsk->sk_socket = newsock; + newsk->sk_sleep = &newsock->wait; /* Now attach up the new socket */ skb->sk = NULL; kfree_skb(skb); - sk->ack_backlog--; + sk->sk_ack_backlog--; newsock->sk = newsk; out: @@ -914,7 +916,7 @@ int n; if (peer != 0) { - if (sk->state != TCP_ESTABLISHED) + if (sk->sk_state != TCP_ESTABLISHED) return -ENOTCONN; srose->srose_family = AF_ROSE; srose->srose_addr = rose->dest_addr; @@ -962,13 +964,14 @@ /* * We can't accept the Call Request. */ - if (sk == NULL || sk->ack_backlog == sk->max_ack_backlog || (make = rose_make_new(sk)) == NULL) { + if (!sk || sk->sk_ack_backlog == sk->sk_max_ack_backlog || + (make = rose_make_new(sk)) == NULL) { rose_transmit_clear_request(neigh, lci, ROSE_NETWORK_CONGESTION, 120); return 0; } skb->sk = make; - make->state = TCP_ESTABLISHED; + make->sk_state = TCP_ESTABLISHED; make_rose = rose_sk(make); make_rose->lci = lci; @@ -1001,17 +1004,17 @@ make_rose->va = 0; make_rose->vr = 0; make_rose->vl = 0; - sk->ack_backlog++; - make->pair = sk; + sk->sk_ack_backlog++; + make->sk_pair = sk; rose_insert_socket(make); - skb_queue_head(&sk->receive_queue, skb); + skb_queue_head(&sk->sk_receive_queue, skb); rose_start_heartbeat(make); - if (!test_bit(SOCK_DEAD, &sk->flags)) - sk->data_ready(sk, skb->len); + if (!sock_flag(sk, SOCK_DEAD)) + sk->sk_data_ready(sk, skb->len); return 1; } @@ -1031,10 +1034,10 @@ if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR)) return -EINVAL; - if (sk->zapped) + if (sk->sk_zapped) return -EADDRNOTAVAIL; - if (sk->shutdown & SEND_SHUTDOWN) { + if (sk->sk_shutdown & SEND_SHUTDOWN) { send_sig(SIGPIPE, current, 0); return -EPIPE; } @@ -1061,7 +1064,7 @@ if (srose.srose_family != AF_ROSE) return -EINVAL; } else { - if (sk->state != TCP_ESTABLISHED) + if (sk->sk_state != TCP_ESTABLISHED) return -ENOTCONN; srose.srose_family = AF_ROSE; @@ -1120,7 +1123,7 @@ SOCK_DEBUG(sk, "ROSE: Transmitting buffer\n"); - if (sk->state != TCP_ESTABLISHED) { + if (sk->sk_state != TCP_ESTABLISHED) { kfree_skb(skb); return -ENOTCONN; } @@ -1162,16 +1165,16 @@ if (skb->len > 0) skbn->data[2] |= M_BIT; - skb_queue_tail(&sk->write_queue, skbn); /* Throw it on the queue */ + skb_queue_tail(&sk->sk_write_queue, skbn); /* Throw it on the queue */ } skb->free = 1; kfree_skb(skb, FREE_WRITE); } else { - skb_queue_tail(&sk->write_queue, skb); /* Throw it on the queue */ + skb_queue_tail(&sk->sk_write_queue, skb); /* Throw it on the queue */ } #else - skb_queue_tail(&sk->write_queue, skb); /* Shove it onto the queue */ + skb_queue_tail(&sk->sk_write_queue, skb); /* Shove it onto the queue */ #endif rose_kick(sk); @@ -1195,7 +1198,7 @@ * This works for seqpacket too. The receiver has ordered the queue for * us! We do one quick check first though */ - if (sk->state != TCP_ESTABLISHED) + if (sk->sk_state != TCP_ESTABLISHED) return -ENOTCONN; /* Now we can treat all alike */ @@ -1254,7 +1257,7 @@ switch (cmd) { case TIOCOUTQ: { long amount; - amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); + amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc); if (amount < 0) amount = 0; return put_user(amount, (unsigned int *)arg); @@ -1264,16 +1267,17 @@ struct sk_buff *skb; long amount = 0L; /* These two are safe on a single CPU system as only user tasks fiddle here */ - if ((skb = skb_peek(&sk->receive_queue)) != NULL) + if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) amount = skb->len; return put_user(amount, (unsigned int *)arg); } case SIOCGSTAMP: if (sk != NULL) { - if (sk->stamp.tv_sec == 0) + if (!sk->sk_stamp.tv_sec) return -ENOENT; - return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0; + return copy_to_user((void *)arg, &sk->sk_stamp, + sizeof(struct timeval)) ? -EFAULT : 0; } return -EINVAL; @@ -1358,7 +1362,7 @@ len += sprintf(buffer, "dest_addr dest_call src_addr src_call dev lci neigh st vs vr va t t1 t2 t3 hb idle Snd-Q Rcv-Q inode\n"); - for (s = rose_list; s != NULL; s = s->next) { + for (s = rose_list; s; s = s->sk_next) { rose_cb *rose = rose_sk(s); if ((dev = rose->device) == NULL) @@ -1392,9 +1396,9 @@ rose->hb / HZ, ax25_display_timer(&rose->idletimer) / (60 * HZ), rose->idle / (60 * HZ), - atomic_read(&s->wmem_alloc), - atomic_read(&s->rmem_alloc), - s->socket != NULL ? SOCK_INODE(s->socket)->i_ino : 0L); + atomic_read(&s->sk_wmem_alloc), + atomic_read(&s->sk_rmem_alloc), + s->sk_socket ? SOCK_INODE(s->sk_socket)->i_ino : 0L); pos = begin + len; @@ -1535,7 +1539,6 @@ dev_rose[i].priv = NULL; unregister_netdev(&dev_rose[i]); } - kfree(dev_rose[i].name); } kfree(dev_rose); diff -Nru a/net/rose/rose_in.c b/net/rose/rose_in.c --- a/net/rose/rose_in.c Mon Jun 9 23:16:14 2003 +++ b/net/rose/rose_in.c Mon Jun 9 23:16:14 2003 @@ -53,9 +53,9 @@ rose->vr = 0; rose->vl = 0; rose->state = ROSE_STATE_3; - sk->state = TCP_ESTABLISHED; - if (!test_bit(SOCK_DEAD, &sk->flags)) - sk->state_change(sk); + sk->sk_state = TCP_ESTABLISHED; + if (!sock_flag(sk, SOCK_DEAD)) + sk->sk_state_change(sk); break; case ROSE_CLEAR_REQUEST: @@ -183,7 +183,8 @@ rose_stop_idletimer(sk); break; } - if (atomic_read(&sk->rmem_alloc) > (sk->rcvbuf / 2)) + if (atomic_read(&sk->sk_rmem_alloc) > + (sk->sk_rcvbuf / 2)) rose->condition |= ROSE_COND_OWN_RX_BUSY; } /* diff -Nru a/net/rose/rose_out.c b/net/rose/rose_out.c --- a/net/rose/rose_out.c Mon Jun 9 23:16:20 2003 +++ b/net/rose/rose_out.c Mon Jun 9 23:16:20 2003 @@ -58,7 +58,7 @@ if (rose->condition & ROSE_COND_PEER_RX_BUSY) return; - if (skb_peek(&sk->write_queue) == NULL) + if (!skb_peek(&sk->sk_write_queue)) return; start = (skb_peek(&rose->ack_queue) == NULL) ? rose->va : rose->vs; @@ -74,11 +74,11 @@ * the window is full. */ - skb = skb_dequeue(&sk->write_queue); + skb = skb_dequeue(&sk->sk_write_queue); do { if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) { - skb_queue_head(&sk->write_queue, skb); + skb_queue_head(&sk->sk_write_queue, skb); break; } @@ -96,7 +96,8 @@ */ skb_queue_tail(&rose->ack_queue, skb); - } while (rose->vs != end && (skb = skb_dequeue(&sk->write_queue)) != NULL); + } while (rose->vs != end && + (skb = skb_dequeue(&sk->sk_write_queue)) != NULL); rose->vl = rose->vr; rose->condition &= ~ROSE_COND_ACK_PENDING; diff -Nru a/net/rose/rose_route.c b/net/rose/rose_route.c --- a/net/rose/rose_route.c Mon Jun 9 23:16:19 2003 +++ b/net/rose/rose_route.c Mon Jun 9 23:16:19 2003 @@ -907,12 +907,13 @@ rose->neighbour = NULL; rose->lci = 0; rose->state = ROSE_STATE_0; - sk->state = TCP_CLOSE; - sk->err = 0; - sk->shutdown |= SEND_SHUTDOWN; - if (!test_bit(SOCK_DEAD, &sk->flags)) - sk->state_change(sk); - __set_bit(SOCK_DEAD, &sk->flags); + sk->sk_state = TCP_CLOSE; + sk->sk_err = 0; + sk->sk_shutdown |= SEND_SHUTDOWN; + if (!sock_flag(sk, SOCK_DEAD)) { + sk->sk_state_change(sk); + sock_set_flag(sk, SOCK_DEAD); + } } else { skb->h.raw = skb->data; diff -Nru a/net/rose/rose_subr.c b/net/rose/rose_subr.c --- a/net/rose/rose_subr.c Mon Jun 9 23:16:19 2003 +++ b/net/rose/rose_subr.c Mon Jun 9 23:16:19 2003 @@ -33,7 +33,7 @@ */ void rose_clear_queues(struct sock *sk) { - skb_queue_purge(&sk->write_queue); + skb_queue_purge(&sk->sk_write_queue); skb_queue_purge(&rose_sk(sk)->ack_queue); } @@ -70,7 +70,7 @@ */ while ((skb = skb_dequeue(&rose_sk(sk)->ack_queue)) != NULL) { if (skb_prev == NULL) - skb_queue_head(&sk->write_queue, skb); + skb_queue_head(&sk->sk_write_queue, skb); else skb_append(skb_prev, skb); skb_prev = skb; @@ -506,12 +506,12 @@ if (diagnostic != -1) rose->diagnostic = diagnostic; - sk->state = TCP_CLOSE; - sk->err = reason; - sk->shutdown |= SEND_SHUTDOWN; - - if (!test_bit(SOCK_DEAD, &sk->flags)) - sk->state_change(sk); - - __set_bit(SOCK_DEAD, &sk->flags); + sk->sk_state = TCP_CLOSE; + sk->sk_err = reason; + sk->sk_shutdown |= SEND_SHUTDOWN; + + if (!sock_flag(sk, SOCK_DEAD)) { + sk->sk_state_change(sk); + sock_set_flag(sk, SOCK_DEAD); + } } diff -Nru a/net/rose/rose_timer.c b/net/rose/rose_timer.c --- a/net/rose/rose_timer.c Mon Jun 9 23:16:15 2003 +++ b/net/rose/rose_timer.c Mon Jun 9 23:16:15 2003 @@ -35,13 +35,13 @@ void rose_start_heartbeat(struct sock *sk) { - del_timer(&sk->timer); + del_timer(&sk->sk_timer); - sk->timer.data = (unsigned long)sk; - sk->timer.function = &rose_heartbeat_expiry; - sk->timer.expires = jiffies + 5 * HZ; + sk->sk_timer.data = (unsigned long)sk; + sk->sk_timer.function = &rose_heartbeat_expiry; + sk->sk_timer.expires = jiffies + 5 * HZ; - add_timer(&sk->timer); + add_timer(&sk->sk_timer); } void rose_start_t1timer(struct sock *sk) @@ -113,7 +113,7 @@ void rose_stop_heartbeat(struct sock *sk) { - del_timer(&sk->timer); + del_timer(&sk->sk_timer); } void rose_stop_timer(struct sock *sk) @@ -136,9 +136,8 @@ case ROSE_STATE_0: /* Magic here: If we listen() and a new link dies before it is accepted() it isn't 'dead' so doesn't get removed. */ - if (test_bit(SOCK_DESTROY, &sk->flags) || - (sk->state == TCP_LISTEN && - test_bit(SOCK_DEAD, &sk->flags))) { + if (sock_flag(sk, SOCK_DESTROY) || + (sk->sk_state == TCP_LISTEN && sock_flag(sk, SOCK_DEAD))) { rose_destroy_socket(sk); return; } @@ -148,7 +147,7 @@ /* * Check for the state of the receive buffer. */ - if (atomic_read(&sk->rmem_alloc) < (sk->rcvbuf / 2) && + if (atomic_read(&sk->sk_rmem_alloc) < (sk->sk_rcvbuf / 2) && (rose->condition & ROSE_COND_OWN_RX_BUSY)) { rose->condition &= ~ROSE_COND_OWN_RX_BUSY; rose->condition &= ~ROSE_COND_ACK_PENDING; @@ -205,13 +204,13 @@ rose_start_t3timer(sk); - sk->state = TCP_CLOSE; - sk->err = 0; - sk->shutdown |= SEND_SHUTDOWN; - - if (!test_bit(SOCK_DEAD, &sk->flags)) - sk->state_change(sk); - - __set_bit(SOCK_DEAD, &sk->flags); + sk->sk_state = TCP_CLOSE; + sk->sk_err = 0; + sk->sk_shutdown |= SEND_SHUTDOWN; + + if (!sock_flag(sk, SOCK_DEAD)) { + sk->sk_state_change(sk); + sock_set_flag(sk, SOCK_DEAD); + } bh_unlock_sock(sk); } diff -Nru a/net/rxrpc/transport.c b/net/rxrpc/transport.c --- a/net/rxrpc/transport.c Mon Jun 9 23:16:16 2003 +++ b/net/rxrpc/transport.c Mon Jun 9 23:16:16 2003 @@ -112,9 +112,9 @@ /* set the socket up */ sock = trans->socket->sk; - sock->user_data = trans; - sock->data_ready = rxrpc_data_ready; - sock->error_report = rxrpc_error_report; + sock->sk_user_data = trans; + sock->sk_data_ready = rxrpc_data_ready; + sock->sk_error_report = rxrpc_error_report; down_write(&rxrpc_proc_transports_sem); list_add_tail(&trans->proc_link,&rxrpc_proc_transports); @@ -184,7 +184,7 @@ /* close the socket */ if (trans->socket) { - trans->socket->sk->user_data = NULL; + trans->socket->sk->sk_user_data = NULL; sock_release(trans->socket); trans->socket = NULL; } @@ -255,16 +255,16 @@ { struct rxrpc_transport *trans; - _enter("%p{t=%p},%d",sk,sk->user_data,count); + _enter("%p{t=%p},%d",sk,sk->sk_user_data,count); /* queue the transport for attention by krxiod */ - trans = (struct rxrpc_transport *) sk->user_data; + trans = (struct rxrpc_transport *) sk->sk_user_data; if (trans) rxrpc_krxiod_queue_transport(trans); /* wake up anyone waiting on the socket */ - if (sk->sleep && waitqueue_active(sk->sleep)) - wake_up_interruptible(sk->sleep); + if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) + wake_up_interruptible(sk->sk_sleep); _leave(""); @@ -279,18 +279,18 @@ { struct rxrpc_transport *trans; - _enter("%p{t=%p}",sk,sk->user_data); + _enter("%p{t=%p}",sk,sk->sk_user_data); /* queue the transport for attention by krxiod */ - trans = (struct rxrpc_transport *) sk->user_data; + trans = (struct rxrpc_transport *) sk->sk_user_data; if (trans) { trans->error_rcvd = 1; rxrpc_krxiod_queue_transport(trans); } /* wake up anyone waiting on the socket */ - if (sk->sleep && waitqueue_active(sk->sleep)) - wake_up_interruptible(sk->sleep); + if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) + wake_up_interruptible(sk->sk_sleep); _leave(""); diff -Nru a/net/sched/sch_atm.c b/net/sched/sch_atm.c --- a/net/sched/sch_atm.c Mon Jun 9 23:16:11 2003 +++ b/net/sched/sch_atm.c Mon Jun 9 23:16:11 2003 @@ -508,7 +508,8 @@ ATM_SKB(skb)->vcc = flow->vcc; memcpy(skb_push(skb,flow->hdr_len),flow->hdr, flow->hdr_len); - atomic_add(skb->truesize,&flow->vcc->sk->wmem_alloc); + atomic_add(skb->truesize, + &flow->vcc->sk->sk_wmem_alloc); /* atm.atm_options are already set by atm_tc_enqueue */ (void) flow->vcc->send(flow->vcc,skb); } diff -Nru a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c --- a/net/sched/sch_ingress.c Mon Jun 9 23:16:16 2003 +++ b/net/sched/sch_ingress.c Mon Jun 9 23:16:16 2003 @@ -15,10 +15,10 @@ #include <linux/rtnetlink.h> #include <linux/netfilter_ipv4.h> #include <linux/netfilter.h> +#include <linux/smp.h> #include <net/pkt_sched.h> #include <asm/byteorder.h> #include <asm/uaccess.h> -#include <asm/smp.h> #include <linux/kmod.h> #include <linux/stat.h> #include <linux/interrupt.h> diff -Nru a/net/sctp/associola.c b/net/sctp/associola.c --- a/net/sctp/associola.c Mon Jun 9 23:16:06 2003 +++ b/net/sctp/associola.c Mon Jun 9 23:16:06 2003 @@ -177,10 +177,10 @@ * RFC 6 - A SCTP receiver MUST be able to receive a minimum of * 1500 bytes in one SCTP packet. */ - if (sk->rcvbuf < SCTP_DEFAULT_MINWINDOW) + if (sk->sk_rcvbuf < SCTP_DEFAULT_MINWINDOW) asoc->rwnd = SCTP_DEFAULT_MINWINDOW; else - asoc->rwnd = sk->rcvbuf; + asoc->rwnd = sk->sk_rcvbuf; asoc->a_rwnd = asoc->rwnd; @@ -299,7 +299,7 @@ /* Decrement the backlog value for a TCP-style listening socket. */ if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) - sk->ack_backlog--; + sk->sk_ack_backlog--; /* Mark as dead, so other users can know this structure is * going away. @@ -857,7 +857,7 @@ /* Decrement the backlog value for a TCP-style socket. */ if (sctp_style(oldsk, TCP)) - oldsk->ack_backlog--; + oldsk->sk_ack_backlog--; /* Release references to the old endpoint and the sock. */ sctp_endpoint_put(assoc->ep); @@ -1026,7 +1026,7 @@ case SCTP_STATE_SHUTDOWN_RECEIVED: if ((asoc->rwnd > asoc->a_rwnd) && ((asoc->rwnd - asoc->a_rwnd) >= - min_t(__u32, (asoc->base.sk->rcvbuf >> 1), asoc->pmtu))) + min_t(__u32, (asoc->base.sk->sk_rcvbuf >> 1), asoc->pmtu))) return 1; break; default: @@ -1109,7 +1109,7 @@ * the endpoint. */ scope = sctp_scope(&asoc->peer.active_path->ipaddr); - flags = (PF_INET6 == asoc->base.sk->family) ? SCTP_ADDR6_ALLOWED : 0; + flags = (PF_INET6 == asoc->base.sk->sk_family) ? SCTP_ADDR6_ALLOWED : 0; if (asoc->peer.ipv4_address) flags |= SCTP_ADDR4_PEERSUPP; if (asoc->peer.ipv6_address) diff -Nru a/net/sctp/endpointola.c b/net/sctp/endpointola.c --- a/net/sctp/endpointola.c Mon Jun 9 23:16:07 2003 +++ b/net/sctp/endpointola.c Mon Jun 9 23:16:07 2003 @@ -151,12 +151,12 @@ /* FIXME - Should the min and max window size be configurable * sysctl parameters as opposed to be constants? */ - sk->rcvbuf = SCTP_DEFAULT_MAXWINDOW; - sk->sndbuf = SCTP_DEFAULT_MAXWINDOW * 2; + sk->sk_rcvbuf = SCTP_DEFAULT_MAXWINDOW; + sk->sk_sndbuf = SCTP_DEFAULT_MAXWINDOW * 2; /* Use SCTP specific send buffer space queues. */ - sk->write_space = sctp_write_space; - sk->use_write_queue = 1; + sk->sk_write_space = sctp_write_space; + sk->sk_use_write_queue = 1; /* Initialize the secret key used with cookie. */ get_random_bytes(&ep->secret_key[0], SCTP_SECRET_SIZE); @@ -178,7 +178,7 @@ /* Increment the backlog value for a TCP-style listening socket. */ if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) - sk->ack_backlog++; + sk->sk_ack_backlog++; } /* Free the endpoint structure. Delay cleanup until @@ -195,7 +195,7 @@ { SCTP_ASSERT(ep->base.dead, "Endpoint is not dead", return); - ep->base.sk->state = SCTP_SS_CLOSED; + ep->base.sk->sk_state = SCTP_SS_CLOSED; /* Unlink this endpoint, so we can't find it again! */ sctp_unhash_endpoint(ep); @@ -209,7 +209,7 @@ sctp_bind_addr_free(&ep->base.bind_addr); /* Remove and free the port */ - if (ep->base.sk->prev != NULL) + if (ep->base.sk->sk_prev) sctp_put_port(ep->base.sk); /* Give up our hold on the sock. */ diff -Nru a/net/sctp/input.c b/net/sctp/input.c --- a/net/sctp/input.c Mon Jun 9 23:16:06 2003 +++ b/net/sctp/input.c Mon Jun 9 23:16:06 2003 @@ -447,10 +447,10 @@ inet = inet_sk(sk); if (!sock_owned_by_user(sk) && inet->recverr) { - sk->err = err; - sk->error_report(sk); + sk->sk_err = err; + sk->sk_error_report(sk); } else { /* Only an error on timeout */ - sk->err_soft = err; + sk->sk_err_soft = err; } out_unlock: diff -Nru a/net/sctp/ipv6.c b/net/sctp/ipv6.c --- a/net/sctp/ipv6.c Mon Jun 9 23:16:14 2003 +++ b/net/sctp/ipv6.c Mon Jun 9 23:16:14 2003 @@ -123,10 +123,10 @@ np = inet6_sk(sk); icmpv6_err_convert(type, code, &err); if (!sock_owned_by_user(sk) && np->recverr) { - sk->err = err; - sk->error_report(sk); + sk->sk_err = err; + sk->sk_error_report(sk); } else { /* Only an error on timeout */ - sk->err_soft = err; + sk->sk_err_soft = err; } out_unlock: @@ -146,7 +146,7 @@ memset(&fl, 0, sizeof(fl)); - fl.proto = sk->protocol; + fl.proto = sk->sk_protocol; /* Fill in the dest address from the route entry passed with the skb * and the source address from the transport. @@ -159,7 +159,7 @@ if (ipv6_addr_type(&fl.fl6_src) & IPV6_ADDR_LINKLOCAL) fl.oif = transport->saddr.v6.sin6_scope_id; else - fl.oif = sk->bound_dev_if; + fl.oif = sk->sk_bound_dev_if; fl.fl_ip_sport = inet_sk(sk)->sport; fl.fl_ip_dport = transport->ipaddr.v6.sin6_port; @@ -176,7 +176,7 @@ SCTP_INC_STATS(SctpOutSCTPPacks); - return ip6_xmit(sk, skb, &fl, np->opt); + return ip6_xmit(sk, skb, &fl, np->opt, ipfragok); } /* Returns the dst cache entry for the given source and destination ip @@ -366,13 +366,13 @@ addr->v6.sin6_addr = inet6_sk(sk)->rcv_saddr; } -/* Initialize sk->rcv_saddr from sctp_addr. */ +/* Initialize sk->sk_rcv_saddr from sctp_addr. */ static void sctp_v6_to_sk_saddr(union sctp_addr *addr, struct sock *sk) { inet6_sk(sk)->rcv_saddr = addr->v6.sin6_addr; } -/* Initialize sk->daddr from sctp_addr. */ +/* Initialize sk->sk_daddr from sctp_addr. */ static void sctp_v6_to_sk_daddr(union sctp_addr *addr, struct sock *sk) { inet6_sk(sk)->daddr = addr->v6.sin6_addr; @@ -500,25 +500,25 @@ struct sctp6_sock *newsctp6sk; newsk = sk_alloc(PF_INET6, GFP_KERNEL, sizeof(struct sctp6_sock), - sk->slab); + sk->sk_slab); if (!newsk) goto out; sock_init_data(NULL, newsk); sk_set_owner(newsk, THIS_MODULE); - newsk->type = SOCK_STREAM; + newsk->sk_type = SOCK_STREAM; - newsk->prot = sk->prot; - newsk->no_check = sk->no_check; - newsk->reuse = sk->reuse; - - newsk->destruct = inet_sock_destruct; - newsk->zapped = 0; - newsk->family = PF_INET6; - newsk->protocol = IPPROTO_SCTP; - newsk->backlog_rcv = sk->prot->backlog_rcv; - newsk->shutdown = sk->shutdown; + newsk->sk_prot = sk->sk_prot; + newsk->sk_no_check = sk->sk_no_check; + newsk->sk_reuse = sk->sk_reuse; + + newsk->sk_destruct = inet_sock_destruct; + newsk->sk_zapped = 0; + newsk->sk_family = PF_INET6; + newsk->sk_protocol = IPPROTO_SCTP; + newsk->sk_backlog_rcv = sk->sk_prot->backlog_rcv; + newsk->sk_shutdown = sk->sk_shutdown; newsctp6sk = (struct sctp6_sock *)newsk; newsctp6sk->pinet6 = &newsctp6sk->inet6; @@ -556,7 +556,7 @@ atomic_inc(&inet_sock_nr); #endif - if (0 != newsk->prot->init(newsk)) { + if (newsk->sk_prot->init(newsk)) { inet_sock_release(newsk); newsk = NULL; } @@ -716,8 +716,8 @@ */ if (addr->v6.sin6_scope_id) - sk->bound_dev_if = addr->v6.sin6_scope_id; - if (!sk->bound_dev_if) + sk->sk_bound_dev_if = addr->v6.sin6_scope_id; + if (!sk->sk_bound_dev_if) return 0; } af = opt->pf->af; @@ -746,8 +746,8 @@ */ if (addr->v6.sin6_scope_id) - sk->bound_dev_if = addr->v6.sin6_scope_id; - if (!sk->bound_dev_if) + sk->sk_bound_dev_if = addr->v6.sin6_scope_id; + if (!sk->sk_bound_dev_if) return 0; } af = opt->pf->af; diff -Nru a/net/sctp/output.c b/net/sctp/output.c --- a/net/sctp/output.c Mon Jun 9 23:16:08 2003 +++ b/net/sctp/output.c Mon Jun 9 23:16:08 2003 @@ -138,7 +138,7 @@ if (!packet->has_cookie_echo) { error = sctp_packet_transmit(packet); if (error < 0) - chunk->skb->sk->err = -error; + chunk->skb->sk->sk_err = -error; /* If we have an empty packet, then we can NOT ever * return PMTU_FULL. @@ -429,7 +429,7 @@ /* Set up the IP options. */ /* BUG: not implemented - * For v4 this all lives somewhere in sk->opt... + * For v4 this all lives somewhere in sk->sk_opt... */ /* Dump that on IP! */ diff -Nru a/net/sctp/outqueue.c b/net/sctp/outqueue.c --- a/net/sctp/outqueue.c Mon Jun 9 23:16:09 2003 +++ b/net/sctp/outqueue.c Mon Jun 9 23:16:09 2003 @@ -492,7 +492,7 @@ error = sctp_outq_flush(q, /* rtx_timeout */ 1); if (error) - q->asoc->base.sk->err = -error; + q->asoc->base.sk->sk_err = -error; } /* diff -Nru a/net/sctp/protocol.c b/net/sctp/protocol.c --- a/net/sctp/protocol.c Mon Jun 9 23:16:14 2003 +++ b/net/sctp/protocol.c Mon Jun 9 23:16:14 2003 @@ -267,13 +267,13 @@ addr->v4.sin_addr.s_addr = inet_sk(sk)->rcv_saddr; } -/* Initialize sk->rcv_saddr from sctp_addr. */ +/* Initialize sk->sk_rcv_saddr from sctp_addr. */ static void sctp_v4_to_sk_saddr(union sctp_addr *addr, struct sock *sk) { inet_sk(sk)->rcv_saddr = addr->v4.sin_addr.s_addr; } -/* Initialize sk->daddr from sctp_addr. */ +/* Initialize sk->sk_daddr from sctp_addr. */ static void sctp_v4_to_sk_daddr(union sctp_addr *addr, struct sock *sk) { inet_sk(sk)->daddr = addr->v4.sin_addr.s_addr; @@ -512,25 +512,25 @@ struct inet_opt *newinet; newsk = sk_alloc(PF_INET, GFP_KERNEL, sizeof(struct sctp_sock), - sk->slab); + sk->sk_slab); if (!newsk) goto out; sock_init_data(NULL, newsk); sk_set_owner(newsk, THIS_MODULE); - newsk->type = SOCK_STREAM; + newsk->sk_type = SOCK_STREAM; - newsk->prot = sk->prot; - newsk->no_check = sk->no_check; - newsk->reuse = sk->reuse; - newsk->shutdown = sk->shutdown; - - newsk->destruct = inet_sock_destruct; - newsk->zapped = 0; - newsk->family = PF_INET; - newsk->protocol = IPPROTO_SCTP; - newsk->backlog_rcv = sk->prot->backlog_rcv; + newsk->sk_prot = sk->sk_prot; + newsk->sk_no_check = sk->sk_no_check; + newsk->sk_reuse = sk->sk_reuse; + newsk->sk_shutdown = sk->sk_shutdown; + + newsk->sk_destruct = inet_sock_destruct; + newsk->sk_zapped = 0; + newsk->sk_family = PF_INET; + newsk->sk_protocol = IPPROTO_SCTP; + newsk->sk_backlog_rcv = sk->sk_prot->backlog_rcv; newinet = inet_sk(newsk); @@ -555,7 +555,7 @@ atomic_inc(&inet_sock_nr); #endif - if (0 != newsk->prot->init(newsk)) { + if (newsk->sk_prot->init(newsk)) { inet_sock_release(newsk); newsk = NULL; } @@ -601,7 +601,7 @@ "SCTP: Failed to create the SCTP control socket.\n"); return err; } - sctp_ctl_socket->sk->allocation = GFP_ATOMIC; + sctp_ctl_socket->sk->sk_allocation = GFP_ATOMIC; inet_sk(sctp_ctl_socket->sk)->uc_ttl = -1; return 0; @@ -878,36 +878,22 @@ static int __init init_sctp_mibs(void) { - int i; - - sctp_statistics[0] = kmalloc_percpu(sizeof (struct sctp_mib), - GFP_KERNEL); + sctp_statistics[0] = alloc_percpu(struct sctp_mib); if (!sctp_statistics[0]) return -ENOMEM; - sctp_statistics[1] = kmalloc_percpu(sizeof (struct sctp_mib), - GFP_KERNEL); + sctp_statistics[1] = alloc_percpu(struct sctp_mib); if (!sctp_statistics[1]) { - kfree_percpu(sctp_statistics[0]); + free_percpu(sctp_statistics[0]); return -ENOMEM; } - - /* Zero all percpu versions of the mibs */ - for (i = 0; i < NR_CPUS; i++) { - if (cpu_possible(i)) { - memset(per_cpu_ptr(sctp_statistics[0], i), 0, - sizeof (struct sctp_mib)); - memset(per_cpu_ptr(sctp_statistics[1], i), 0, - sizeof (struct sctp_mib)); - } - } return 0; } static void cleanup_sctp_mibs(void) { - kfree_percpu(sctp_statistics[0]); - kfree_percpu(sctp_statistics[1]); + free_percpu(sctp_statistics[0]); + free_percpu(sctp_statistics[1]); } /* Initialize the universe into something sensible. */ diff -Nru a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c --- a/net/sctp/sm_make_chunk.c Mon Jun 9 23:16:07 2003 +++ b/net/sctp/sm_make_chunk.c Mon Jun 9 23:16:07 2003 @@ -1895,7 +1895,7 @@ */ switch (param.p->type) { case SCTP_PARAM_IPV6_ADDRESS: - if( PF_INET6 != asoc->base.sk->family) + if (PF_INET6 != asoc->base.sk->sk_family) break; /* Fall through. */ case SCTP_PARAM_IPV4_ADDRESS: diff -Nru a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c --- a/net/sctp/sm_sideeffect.c Mon Jun 9 23:16:15 2003 +++ b/net/sctp/sm_sideeffect.c Mon Jun 9 23:16:15 2003 @@ -229,7 +229,7 @@ transport, GFP_ATOMIC); if (error) - asoc->base.sk->err = -error; + asoc->base.sk->sk_err = -error; out_unlock: sctp_bh_unlock_sock(asoc->base.sk); @@ -269,7 +269,7 @@ (void *)timeout_type, GFP_ATOMIC); if (error) - asoc->base.sk->err = -error; + asoc->base.sk->sk_err = -error; out_unlock: sctp_bh_unlock_sock(asoc->base.sk); @@ -339,7 +339,7 @@ transport, GFP_ATOMIC); if (error) - asoc->base.sk->err = -error; + asoc->base.sk->sk_err = -error; out_unlock: sctp_bh_unlock_sock(asoc->base.sk); @@ -616,16 +616,16 @@ asoc->state_timestamp = jiffies; if (sctp_style(sk, TCP)) { - /* Change the sk->state of a TCP-style socket that has + /* Change the sk->sk_state of a TCP-style socket that has * sucessfully completed a connect() call. */ if (sctp_state(asoc, ESTABLISHED) && sctp_sstate(sk, CLOSED)) - sk->state = SCTP_SS_ESTABLISHED; + sk->sk_state = SCTP_SS_ESTABLISHED; /* Set the RCV_SHUTDOWN flag when a SHUTDOWN is received. */ if (sctp_state(asoc, SHUTDOWN_RECEIVED) && sctp_sstate(sk, ESTABLISHED)) - sk->shutdown |= RCV_SHUTDOWN; + sk->sk_shutdown |= RCV_SHUTDOWN; } if (sctp_state(asoc, ESTABLISHED) || @@ -644,7 +644,7 @@ * notifications. */ if (!sctp_style(sk, UDP)) - sk->state_change(sk); + sk->sk_state_change(sk); } } diff -Nru a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c --- a/net/sctp/sm_statefuns.c Mon Jun 9 23:16:06 2003 +++ b/net/sctp/sm_statefuns.c Mon Jun 9 23:16:06 2003 @@ -213,7 +213,8 @@ * ABORT. */ if (!sctp_sstate(sk, LISTENING) || - (sctp_style(sk, TCP) && (sk->ack_backlog >= sk->max_ack_backlog))) + (sctp_style(sk, TCP) && + (sk->sk_ack_backlog >= sk->sk_max_ack_backlog))) return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands); /* Verify the INIT chunk before processing it. */ diff -Nru a/net/sctp/socket.c b/net/sctp/socket.c --- a/net/sctp/socket.c Mon Jun 9 23:16:20 2003 +++ b/net/sctp/socket.c Mon Jun 9 23:16:20 2003 @@ -327,7 +327,7 @@ * added. */ -/* Unprotected by locks. Call only with socket lock sk->lock held! See +/* Unprotected by locks. Call only with socket lock sk->sk_lock held! See * sctp_bindx() for a lock-protected call. */ @@ -537,8 +537,8 @@ goto err_bindx_rem; }; - /* FIXME - There is probably a need to check if sk->saddr and - * sk->rcv_addr are currently set to one of the addresses to + /* FIXME - There is probably a need to check if sk->sk_saddr and + * sk->sk_rcv_addr are currently set to one of the addresses to * be removed. This is something which needs to be looked into * when we are fixing the outstanding issues with multi-homing * socket routing and failover schemes. Refer to comments in @@ -713,7 +713,7 @@ printk("sctp_close(sk: 0x%p, timeout:%ld)\n", sk, timeout); sctp_lock_sock(sk); - sk->shutdown = SHUTDOWN_MASK; + sk->sk_shutdown = SHUTDOWN_MASK; ep = sctp_sk(sk)->ep; @@ -731,8 +731,8 @@ sctp_unhash_established(asoc); sctp_association_free(asoc); - } else if (test_bit(SOCK_LINGER, &sk->flags) && - !sk->lingertime) + } else if (sock_flag(sk, SOCK_LINGER) && + !sk->sk_lingertime) sctp_primitive_ABORT(asoc, NULL); else sctp_primitive_SHUTDOWN(asoc, NULL); @@ -741,7 +741,7 @@ } /* Clean up any skbs sitting on the receive queue. */ - skb_queue_purge(&sk->receive_queue); + skb_queue_purge(&sk->sk_receive_queue); skb_queue_purge(&sctp_sk(sk)->pd_lobby); /* On a TCP-style socket, block for at most linger_time if set. */ @@ -1073,7 +1073,7 @@ /* API 7.1.7, the sndbuf size per association bounds the * maximum size of data that can be sent in a single send call. */ - if (msg_len > sk->sndbuf) { + if (msg_len > sk->sk_sndbuf) { err = -EMSGSIZE; goto out_free; } @@ -1296,7 +1296,7 @@ sctp_ulpevent_read_sndrcvinfo(event, msg); #if 0 /* FIXME: we should be calling IP/IPv6 layers. */ - if (sk->protinfo.af_inet.cmsg_flags) + if (sk->sk_protinfo.af_inet.cmsg_flags) ip_cmsg_recv(msg, skb); #endif @@ -1311,7 +1311,7 @@ if (flags & MSG_PEEK) goto out_free; sctp_skb_pull(skb, copied); - skb_queue_head(&sk->receive_queue, skb); + skb_queue_head(&sk->sk_receive_queue, skb); /* When only partial message is copied to the user, increase * rwnd by that amount. If all the data in the skb is read, @@ -1819,7 +1819,7 @@ af = sctp_get_af_specific(to.sa.sa_family); af->to_sk_daddr(&to, sk); - timeo = sock_sndtimeo(sk, sk->socket->file->f_flags & O_NONBLOCK); + timeo = sock_sndtimeo(sk, sk->sk_socket->file->f_flags & O_NONBLOCK); err = sctp_wait_for_connect(asoc, &timeo); out_unlock: @@ -1865,7 +1865,7 @@ goto out; } - timeo = sock_rcvtimeo(sk, sk->socket->file->f_flags & O_NONBLOCK); + timeo = sock_rcvtimeo(sk, sk->sk_socket->file->f_flags & O_NONBLOCK); error = sctp_wait_for_accept(sk, timeo); if (error) @@ -1916,7 +1916,7 @@ sp = sctp_sk(sk); /* Initialize the SCTP per socket area. */ - switch (sk->type) { + switch (sk->sk_type) { case SOCK_SEQPACKET: sp->type = SCTP_SOCKET_UDP; break; @@ -1988,7 +1988,7 @@ /* User specified fragmentation limit. */ sp->user_frag = 0; - sp->pf = sctp_get_pf_specific(sk->family); + sp->pf = sctp_get_pf_specific(sk->sk_family); /* Control variables for partial data delivery. */ sp->pd_mode = 0; @@ -2184,7 +2184,7 @@ return -EINVAL; /* Create a new socket. */ - err = sock_create(sk->family, SOCK_SEQPACKET, IPPROTO_SCTP, &sock); + err = sock_create(sk->sk_family, SOCK_SEQPACKET, IPPROTO_SCTP, &sock); if (err < 0) return err; @@ -2814,12 +2814,12 @@ * used by other socket (pp->sk != NULL); that other * socket is going to be sk2. */ - int sk_reuse = sk->reuse; + int reuse = sk->sk_reuse; struct sock *sk2 = pp->sk; SCTP_DEBUG_PRINTK("sctp_get_port() found a " "possible match\n"); - if (pp->fastreuse != 0 && sk->reuse != 0) + if (pp->fastreuse && sk->sk_reuse) goto success; /* Run through the list of sockets bound to the port @@ -2832,11 +2832,11 @@ * that this port/socket (sk) combination are already * in an endpoint. */ - for ( ; sk2 != NULL; sk2 = sk2->bind_next) { + for (; sk2; sk2 = sk2->sk_bind_next) { struct sctp_endpoint *ep2; ep2 = sctp_sk(sk2)->ep; - if (sk_reuse && sk2->reuse) + if (reuse && sk2->sk_reuse) continue; if (sctp_bind_addr_match(&ep2->base.bind_addr, addr, @@ -2860,12 +2860,12 @@ goto fail_unlock; /* In either case (hit or miss), make sure fastreuse is 1 only - * if sk->reuse is too (that is, if the caller requested + * if sk->sk_reuse is too (that is, if the caller requested * SO_REUSEADDR on this socket -sk-). */ if (!pp->sk) - pp->fastreuse = sk->reuse ? 1 : 0; - else if (pp->fastreuse && sk->reuse == 0) + pp->fastreuse = sk->sk_reuse ? 1 : 0; + else if (pp->fastreuse && !sk->sk_reuse) pp->fastreuse = 0; /* We are set, so fill up all the data in the hash table @@ -2874,12 +2874,12 @@ */ success: inet_sk(sk)->num = snum; - if (sk->prev == NULL) { - if ((sk->bind_next = pp->sk) != NULL) - pp->sk->bind_pprev = &sk->bind_next; + if (!sk->sk_prev) { + if ((sk->sk_bind_next = pp->sk) != NULL) + pp->sk->sk_bind_pprev = &sk->sk_bind_next; pp->sk = sk; - sk->bind_pprev = &pp->sk; - sk->prev = (struct sock *) pp; + sk->sk_bind_pprev = &pp->sk; + sk->sk_prev = (struct sock *) pp; } ret = 0; @@ -2907,7 +2907,7 @@ af->from_sk(&addr, sk); addr.v4.sin_port = htons(snum); - /* Note: sk->num gets filled in if ephemeral port request. */ + /* Note: sk->sk_num gets filled in if ephemeral port request. */ ret = sctp_get_port_local(sk, &addr); return (ret ? 1 : 0); @@ -2948,7 +2948,7 @@ if (sctp_autobind(sk)) return -EAGAIN; } - sk->state = SCTP_SS_LISTENING; + sk->sk_state = SCTP_SS_LISTENING; sctp_hash_endpoint(ep); return 0; } @@ -2981,8 +2981,8 @@ if (sctp_autobind(sk)) return -EAGAIN; } - sk->state = SCTP_SS_LISTENING; - sk->max_ack_backlog = backlog; + sk->sk_state = SCTP_SS_LISTENING; + sk->sk_max_ack_backlog = backlog; sctp_hash_endpoint(ep); return 0; } @@ -3056,7 +3056,7 @@ struct sctp_opt *sp = sctp_sk(sk); unsigned int mask; - poll_wait(file, sk->sleep, wait); + poll_wait(file, sk->sk_sleep, wait); /* A TCP-style listening socket becomes readable when the accept queue * is not empty. @@ -3068,14 +3068,14 @@ mask = 0; /* Is there any exceptional events? */ - if (sk->err || !skb_queue_empty(&sk->error_queue)) + if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) mask |= POLLERR; - if (sk->shutdown == SHUTDOWN_MASK) + if (sk->sk_shutdown == SHUTDOWN_MASK) mask |= POLLHUP; /* Is it readable? Reconsider this code with TCP-style support. */ - if (!skb_queue_empty(&sk->receive_queue) || - (sk->shutdown & RCV_SHUTDOWN)) + if (!skb_queue_empty(&sk->sk_receive_queue) || + (sk->sk_shutdown & RCV_SHUTDOWN)) mask |= POLLIN | POLLRDNORM; /* The association is either gone or not ready. */ @@ -3086,7 +3086,7 @@ if (sctp_writeable(sk)) { mask |= POLLOUT | POLLWRNORM; } else { - set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); + set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); /* * Since the socket is not locked, the buffer * might be made available after the writeable check and @@ -3133,11 +3133,11 @@ sctp_bind_bucket_t *pp; sctp_spin_lock(&head->lock); - pp = (sctp_bind_bucket_t *) sk->prev; - if (sk->bind_next) - sk->bind_next->bind_pprev = sk->bind_pprev; - *(sk->bind_pprev) = sk->bind_next; - sk->prev = NULL; + pp = (sctp_bind_bucket_t *)sk->sk_prev; + if (sk->sk_bind_next) + sk->sk_bind_next->sk_bind_pprev = sk->sk_bind_pprev; + *(sk->sk_bind_pprev) = sk->sk_bind_next; + sk->sk_prev = NULL; inet_sk(sk)->num = 0; if (pp->sk) { if (pp->next) @@ -3299,18 +3299,18 @@ int error; DEFINE_WAIT(wait); - prepare_to_wait_exclusive(sk->sleep, &wait, TASK_INTERRUPTIBLE); + prepare_to_wait_exclusive(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); /* Socket errors? */ error = sock_error(sk); if (error) goto out; - if (!skb_queue_empty(&sk->receive_queue)) + if (!skb_queue_empty(&sk->sk_receive_queue)) goto ready; /* Socket shut down? */ - if (sk->shutdown & RCV_SHUTDOWN) + if (sk->sk_shutdown & RCV_SHUTDOWN) goto out; /* Sequenced packets can come disconnected. If so we report the @@ -3336,14 +3336,14 @@ sctp_lock_sock(sk); ready: - finish_wait(sk->sleep, &wait); + finish_wait(sk->sk_sleep, &wait); return 0; interrupted: error = sock_intr_errno(*timeo_p); out: - finish_wait(sk->sleep, &wait); + finish_wait(sk->sk_sleep, &wait); *err = error; return error; } @@ -3359,7 +3359,7 @@ struct sk_buff *skb; long timeo; - /* Caller is allowed not to check sk->err before calling. */ + /* Caller is allowed not to check sk->sk_err before calling. */ error = sock_error(sk); if (error) goto no_packet; @@ -3380,21 +3380,21 @@ if (flags & MSG_PEEK) { unsigned long cpu_flags; - sctp_spin_lock_irqsave(&sk->receive_queue.lock, + sctp_spin_lock_irqsave(&sk->sk_receive_queue.lock, cpu_flags); - skb = skb_peek(&sk->receive_queue); + skb = skb_peek(&sk->sk_receive_queue); if (skb) atomic_inc(&skb->users); - sctp_spin_unlock_irqrestore(&sk->receive_queue.lock, + sctp_spin_unlock_irqrestore(&sk->sk_receive_queue.lock, cpu_flags); } else { - skb = skb_dequeue(&sk->receive_queue); + skb = skb_dequeue(&sk->sk_receive_queue); } if (skb) return skb; - if (sk->shutdown & RCV_SHUTDOWN) + if (sk->sk_shutdown & RCV_SHUTDOWN) break; /* User doesn't want to wait. */ @@ -3437,7 +3437,7 @@ struct sock *sk = asoc->base.sk; int amt = 0; - amt = sk->sndbuf - asoc->sndbuf_used; + amt = sk->sk_sndbuf - asoc->sndbuf_used; if (amt < 0) amt = 0; return amt; @@ -3465,29 +3465,29 @@ *((struct sctp_chunk **)(chunk->skb->cb)) = chunk; asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk); - sk->wmem_queued += SCTP_DATA_SNDSIZE(chunk); + sk->sk_wmem_queued += SCTP_DATA_SNDSIZE(chunk); } /* If sndbuf has changed, wake up per association sndbuf waiters. */ static void __sctp_write_space(struct sctp_association *asoc) { struct sock *sk = asoc->base.sk; - struct socket *sock = sk->socket; + struct socket *sock = sk->sk_socket; if ((sctp_wspace(asoc) > 0) && sock) { if (waitqueue_active(&asoc->wait)) wake_up_interruptible(&asoc->wait); if (sctp_writeable(sk)) { - if (sk->sleep && waitqueue_active(sk->sleep)) - wake_up_interruptible(sk->sleep); + if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) + wake_up_interruptible(sk->sk_sleep); /* Note that we try to include the Async I/O support * here by modeling from the current TCP/UDP code. * We have not tested with it yet. */ if (sock->fasync_list && - !(sk->shutdown & SEND_SHUTDOWN)) + !(sk->sk_shutdown & SEND_SHUTDOWN)) sock_wake_async(sock, 2, POLL_OUT); } } @@ -3508,7 +3508,7 @@ asoc = chunk->asoc; sk = asoc->base.sk; asoc->sndbuf_used -= SCTP_DATA_SNDSIZE(chunk); - sk->wmem_queued -= SCTP_DATA_SNDSIZE(chunk); + sk->sk_wmem_queued -= SCTP_DATA_SNDSIZE(chunk); __sctp_write_space(asoc); sctp_association_put(asoc); @@ -3535,7 +3535,7 @@ TASK_INTERRUPTIBLE); if (!*timeo_p) goto do_nonblock; - if (sk->err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING || + if (sk->sk_err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING || asoc->base.dead) goto do_error; if (signal_pending(current)) @@ -3602,7 +3602,7 @@ { int amt = 0; - amt = sk->sndbuf - sk->wmem_queued; + amt = sk->sk_sndbuf - sk->sk_wmem_queued; if (amt < 0) amt = 0; return amt; @@ -3629,9 +3629,9 @@ TASK_INTERRUPTIBLE); if (!*timeo_p) goto do_nonblock; - if (sk->shutdown & RCV_SHUTDOWN) + if (sk->sk_shutdown & RCV_SHUTDOWN) break; - if (sk->err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING || + if (sk->sk_err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING || asoc->base.dead) goto do_error; if (signal_pending(current)) @@ -3681,7 +3681,8 @@ for (;;) { - prepare_to_wait_exclusive(sk->sleep, &wait, TASK_INTERRUPTIBLE); + prepare_to_wait_exclusive(sk->sk_sleep, &wait, + TASK_INTERRUPTIBLE); if (list_empty(&ep->asocs)) { sctp_release_sock(sk); @@ -3706,7 +3707,7 @@ break; } - finish_wait(sk->sleep, &wait); + finish_wait(sk->sk_sleep, &wait); return err; } @@ -3716,7 +3717,7 @@ DEFINE_WAIT(wait); do { - prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE); + prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); if (list_empty(&sctp_sk(sk)->ep->asocs)) break; sctp_release_sock(sk); @@ -3724,7 +3725,7 @@ sctp_lock_sock(sk); } while (!signal_pending(current) && timeout); - finish_wait(sk->sleep, &wait); + finish_wait(sk->sk_sleep, &wait); } /* Populate the fields of the newsk from the oldsk and migrate the assoc @@ -3743,8 +3744,8 @@ /* Migrate socket buffer sizes and all the socket level options to the * new socket. */ - newsk->sndbuf = oldsk->sndbuf; - newsk->rcvbuf = oldsk->rcvbuf; + newsk->sk_sndbuf = oldsk->sk_sndbuf; + newsk->sk_rcvbuf = oldsk->sk_rcvbuf; *newsp = *oldsp; /* Restore the ep value that was overwritten with the above structure @@ -3756,11 +3757,11 @@ /* Move any messages in the old socket's receive queue that are for the * peeled off association to the new socket's receive queue. */ - sctp_skb_for_each(skb, &oldsk->receive_queue, tmp) { + sctp_skb_for_each(skb, &oldsk->sk_receive_queue, tmp) { event = sctp_skb2event(skb); if (event->asoc == assoc) { __skb_unlink(skb, skb->list); - __skb_queue_tail(&newsk->receive_queue, skb); + __skb_queue_tail(&newsk->sk_receive_queue, skb); } } @@ -3780,7 +3781,7 @@ if (assoc->ulpq.pd_mode) { queue = &newsp->pd_lobby; } else - queue = &newsk->receive_queue; + queue = &newsk->sk_receive_queue; /* Walk through the pd_lobby, looking for skbs that * need moved to the new socket. @@ -3814,9 +3815,9 @@ * is called, set RCV_SHUTDOWN flag. */ if (sctp_state(assoc, CLOSED) && sctp_style(newsk, TCP)) - newsk->shutdown |= RCV_SHUTDOWN; + newsk->sk_shutdown |= RCV_SHUTDOWN; - newsk->state = SCTP_SS_ESTABLISHED; + newsk->sk_state = SCTP_SS_ESTABLISHED; } /* This proto struct describes the ULP interface for SCTP. */ diff -Nru a/net/sctp/transport.c b/net/sctp/transport.c --- a/net/sctp/transport.c Mon Jun 9 23:16:08 2003 +++ b/net/sctp/transport.c Mon Jun 9 23:16:08 2003 @@ -245,7 +245,7 @@ if (dst) { transport->pmtu = dst_pmtu(dst); - /* Initialize sk->rcv_saddr, if the transport is the + /* Initialize sk->sk_rcv_saddr, if the transport is the * association's active path for getsockname(). */ if (asoc && (transport == asoc->peer.active_path)) diff -Nru a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c --- a/net/sctp/ulpqueue.c Mon Jun 9 23:16:19 2003 +++ b/net/sctp/ulpqueue.c Mon Jun 9 23:16:19 2003 @@ -163,7 +163,7 @@ sp->pd_mode = 0; if (!skb_queue_empty(&sp->pd_lobby)) { struct list_head *list; - sctp_skb_list_tail(&sp->pd_lobby, &sk->receive_queue); + sctp_skb_list_tail(&sp->pd_lobby, &sk->sk_receive_queue); list = (struct list_head *)&sctp_sk(sk)->pd_lobby; INIT_LIST_HEAD(list); return 1; @@ -189,7 +189,7 @@ /* If the socket is just going to throw this away, do not * even try to deliver it. */ - if (test_bit(SOCK_DEAD, &sk->flags) || (sk->shutdown & RCV_SHUTDOWN)) + if (sock_flag(sk, SOCK_DEAD) || (sk->sk_shutdown & RCV_SHUTDOWN)) goto out_free; /* Check if the user wishes to receive this event. */ @@ -202,13 +202,13 @@ */ if (!sctp_sk(sk)->pd_mode) { - queue = &sk->receive_queue; + queue = &sk->sk_receive_queue; } else if (ulpq->pd_mode) { if (event->msg_flags & MSG_NOTIFICATION) queue = &sctp_sk(sk)->pd_lobby; else { clear_pd = event->msg_flags & MSG_EOR; - queue = &sk->receive_queue; + queue = &sk->sk_receive_queue; } } else queue = &sctp_sk(sk)->pd_lobby; @@ -229,8 +229,8 @@ if (clear_pd) sctp_ulpq_clear_pd(ulpq); - if (queue == &sk->receive_queue) - sk->data_ready(sk, 0); + if (queue == &sk->sk_receive_queue) + sk->sk_data_ready(sk, 0); return 1; out_free: @@ -773,7 +773,7 @@ freed = 0; - if (skb_queue_empty(&asoc->base.sk->receive_queue)) { + if (skb_queue_empty(&asoc->base.sk->sk_receive_queue)) { freed = sctp_ulpq_renege_order(ulpq, needed); if (freed < needed) { freed += sctp_ulpq_renege_frags(ulpq, needed - freed); @@ -812,9 +812,9 @@ SCTP_PARTIAL_DELIVERY_ABORTED, gfp); if (ev) - __skb_queue_tail(&sk->receive_queue, sctp_event2skb(ev)); + __skb_queue_tail(&sk->sk_receive_queue, sctp_event2skb(ev)); /* If there is data waiting, send it up the socket now. */ if (sctp_ulpq_clear_pd(ulpq) || ev) - sk->data_ready(sk, 0); + sk->sk_data_ready(sk, 0); } diff -Nru a/net/socket.c b/net/socket.c --- a/net/socket.c Mon Jun 9 23:16:10 2003 +++ b/net/socket.c Mon Jun 9 23:16:10 2003 @@ -889,11 +889,11 @@ * * 1. fasync_list is modified only under process context socket lock * i.e. under semaphore. - * 2. fasync_list is used under read_lock(&sk->callback_lock) + * 2. fasync_list is used under read_lock(&sk->sk_callback_lock) * or under socket lock. * 3. fasync_list can be used from softirq context, so that * modification under socket lock have to be enhanced with - * write_lock_bh(&sk->callback_lock). + * write_lock_bh(&sk->sk_callback_lock). * --ANK (990710) */ @@ -930,9 +930,9 @@ { if(fa!=NULL) { - write_lock_bh(&sk->callback_lock); + write_lock_bh(&sk->sk_callback_lock); fa->fa_fd=fd; - write_unlock_bh(&sk->callback_lock); + write_unlock_bh(&sk->sk_callback_lock); kfree(fna); goto out; @@ -941,17 +941,17 @@ fna->fa_fd=fd; fna->magic=FASYNC_MAGIC; fna->fa_next=sock->fasync_list; - write_lock_bh(&sk->callback_lock); + write_lock_bh(&sk->sk_callback_lock); sock->fasync_list=fna; - write_unlock_bh(&sk->callback_lock); + write_unlock_bh(&sk->sk_callback_lock); } else { if (fa!=NULL) { - write_lock_bh(&sk->callback_lock); + write_lock_bh(&sk->sk_callback_lock); *prev=fa->fa_next; - write_unlock_bh(&sk->callback_lock); + write_unlock_bh(&sk->sk_callback_lock); kfree(fa); } } diff -Nru a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c --- a/net/sunrpc/svcsock.c Mon Jun 9 23:16:07 2003 +++ b/net/sunrpc/svcsock.c Mon Jun 9 23:16:07 2003 @@ -496,9 +496,9 @@ * DaveM said I could! */ lock_sock(sock->sk); - sock->sk->sndbuf = snd * 2; - sock->sk->rcvbuf = rcv * 2; - sock->sk->userlocks |= SOCK_SNDBUF_LOCK|SOCK_RCVBUF_LOCK; + sock->sk->sk_sndbuf = snd * 2; + sock->sk->sk_rcvbuf = rcv * 2; + sock->sk->sk_userlocks |= SOCK_SNDBUF_LOCK|SOCK_RCVBUF_LOCK; release_sock(sock->sk); #endif } @@ -508,7 +508,7 @@ static void svc_udp_data_ready(struct sock *sk, int count) { - struct svc_sock *svsk = (struct svc_sock *)(sk->user_data); + struct svc_sock *svsk = (struct svc_sock *)(sk->sk_user_data); if (!svsk) goto out; @@ -517,8 +517,8 @@ set_bit(SK_DATA, &svsk->sk_flags); svc_sock_enqueue(svsk); out: - if (sk->sleep && waitqueue_active(sk->sleep)) - wake_up_interruptible(sk->sleep); + if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) + wake_up_interruptible(sk->sk_sleep); } /* @@ -527,7 +527,7 @@ static void svc_write_space(struct sock *sk) { - struct svc_sock *svsk = (struct svc_sock *)(sk->user_data); + struct svc_sock *svsk = (struct svc_sock *)(sk->sk_user_data); if (svsk) { dprintk("svc: socket %p(inet %p), write_space busy=%d\n", @@ -535,10 +535,10 @@ svc_sock_enqueue(svsk); } - if (sk->sleep && waitqueue_active(sk->sleep)) { + if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) { printk(KERN_WARNING "RPC svc_write_space: some sleeping on %p\n", svsk); - wake_up_interruptible(sk->sleep); + wake_up_interruptible(sk->sk_sleep); } } @@ -589,6 +589,8 @@ rqstp->rq_addr.sin_port = skb->h.uh->source; rqstp->rq_addr.sin_addr.s_addr = skb->nh.iph->saddr; + svsk->sk_sk->sk_stamp = skb->stamp; + if (skb_is_nonlinear(skb)) { /* we have to copy */ local_bh_disable(); @@ -629,7 +631,6 @@ serv->sv_stats->netudpcnt++; /* One down, maybe more to go... */ - svsk->sk_sk->stamp = skb->stamp; svc_sock_received(svsk); return len; @@ -651,8 +652,8 @@ static void svc_udp_init(struct svc_sock *svsk) { - svsk->sk_sk->data_ready = svc_udp_data_ready; - svsk->sk_sk->write_space = svc_write_space; + svsk->sk_sk->sk_data_ready = svc_udp_data_ready; + svsk->sk_sk->sk_write_space = svc_write_space; svsk->sk_recvfrom = svc_udp_recvfrom; svsk->sk_sendto = svc_udp_sendto; @@ -678,21 +679,21 @@ struct svc_sock *svsk; dprintk("svc: socket %p TCP (listen) state change %d\n", - sk, sk->state); + sk, sk->sk_state); - if (sk->state != TCP_ESTABLISHED) { + if (sk->sk_state != TCP_ESTABLISHED) { /* Aborted connection, SYN_RECV or whatever... */ goto out; } - if (!(svsk = (struct svc_sock *) sk->user_data)) { + if (!(svsk = (struct svc_sock *) sk->sk_user_data)) { printk("svc: socket %p: no user data\n", sk); goto out; } set_bit(SK_CONN, &svsk->sk_flags); svc_sock_enqueue(svsk); out: - if (sk->sleep && waitqueue_active(sk->sleep)) - wake_up_interruptible_all(sk->sleep); + if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) + wake_up_interruptible_all(sk->sk_sleep); } /* @@ -704,17 +705,17 @@ struct svc_sock *svsk; dprintk("svc: socket %p TCP (connected) state change %d (svsk %p)\n", - sk, sk->state, sk->user_data); + sk, sk->sk_state, sk->sk_user_data); - if (!(svsk = (struct svc_sock *) sk->user_data)) { + if (!(svsk = (struct svc_sock *) sk->sk_user_data)) { printk("svc: socket %p: no user data\n", sk); goto out; } set_bit(SK_CLOSE, &svsk->sk_flags); svc_sock_enqueue(svsk); out: - if (sk->sleep && waitqueue_active(sk->sleep)) - wake_up_interruptible_all(sk->sleep); + if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) + wake_up_interruptible_all(sk->sk_sleep); } static void @@ -723,14 +724,14 @@ struct svc_sock * svsk; dprintk("svc: socket %p TCP data ready (svsk %p)\n", - sk, sk->user_data); - if (!(svsk = (struct svc_sock *)(sk->user_data))) + sk, sk->sk_user_data); + if (!(svsk = (struct svc_sock *)(sk->sk_user_data))) goto out; set_bit(SK_DATA, &svsk->sk_flags); svc_sock_enqueue(svsk); out: - if (sk->sleep && waitqueue_active(sk->sleep)) - wake_up_interruptible(sk->sleep); + if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) + wake_up_interruptible(sk->sk_sleep); } /* @@ -796,7 +797,7 @@ /* make sure that a write doesn't block forever when * low on memory */ - newsock->sk->sndtimeo = HZ*30; + newsock->sk->sk_sndtimeo = HZ*30; if (!(newsvsk = svc_setup_socket(serv, newsock, &err, 0))) goto failed; @@ -1034,15 +1035,15 @@ svsk->sk_recvfrom = svc_tcp_recvfrom; svsk->sk_sendto = svc_tcp_sendto; - if (sk->state == TCP_LISTEN) { + if (sk->sk_state == TCP_LISTEN) { dprintk("setting up TCP socket for listening\n"); - sk->data_ready = svc_tcp_listen_data_ready; + sk->sk_data_ready = svc_tcp_listen_data_ready; set_bit(SK_CONN, &svsk->sk_flags); } else { dprintk("setting up TCP socket for reading\n"); - sk->state_change = svc_tcp_state_change; - sk->data_ready = svc_tcp_data_ready; - sk->write_space = svc_write_space; + sk->sk_state_change = svc_tcp_state_change; + sk->sk_data_ready = svc_tcp_data_ready; + sk->sk_write_space = svc_write_space; svsk->sk_reclen = 0; svsk->sk_tcplen = 0; @@ -1289,7 +1290,7 @@ /* Register socket with portmapper */ if (*errp >= 0 && pmap_register) - *errp = svc_register(serv, inet->protocol, + *errp = svc_register(serv, inet->sk_protocol, ntohs(inet_sk(inet)->sport)); if (*errp < 0) { @@ -1298,12 +1299,12 @@ } set_bit(SK_BUSY, &svsk->sk_flags); - inet->user_data = svsk; + inet->sk_user_data = svsk; svsk->sk_sock = sock; svsk->sk_sk = inet; - svsk->sk_ostate = inet->state_change; - svsk->sk_odata = inet->data_ready; - svsk->sk_owspace = inet->write_space; + svsk->sk_ostate = inet->sk_state_change; + svsk->sk_odata = inet->sk_data_ready; + svsk->sk_owspace = inet->sk_write_space; svsk->sk_server = serv; svsk->sk_lastrecv = get_seconds(); INIT_LIST_HEAD(&svsk->sk_deferred); @@ -1362,7 +1363,7 @@ return error; if (sin != NULL) { - sock->sk->reuse = 1; /* allow address reuse */ + sock->sk->sk_reuse = 1; /* allow address reuse */ error = sock->ops->bind(sock, (struct sockaddr *) sin, sizeof(*sin)); if (error < 0) @@ -1397,9 +1398,9 @@ serv = svsk->sk_server; sk = svsk->sk_sk; - sk->state_change = svsk->sk_ostate; - sk->data_ready = svsk->sk_odata; - sk->write_space = svsk->sk_owspace; + sk->sk_state_change = svsk->sk_ostate; + sk->sk_data_ready = svsk->sk_odata; + sk->sk_write_space = svsk->sk_owspace; spin_lock_bh(&serv->sv_lock); diff -Nru a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c --- a/net/sunrpc/xprt.c Mon Jun 9 23:16:15 2003 +++ b/net/sunrpc/xprt.c Mon Jun 9 23:16:15 2003 @@ -129,7 +129,7 @@ static inline struct rpc_xprt * xprt_from_sock(struct sock *sk) { - return (struct rpc_xprt *) sk->user_data; + return (struct rpc_xprt *) sk->sk_user_data; } /* @@ -367,18 +367,18 @@ if (!sk) return; - write_lock_bh(&sk->callback_lock); + write_lock_bh(&sk->sk_callback_lock); xprt->inet = NULL; xprt->sock = NULL; - sk->user_data = NULL; - sk->data_ready = xprt->old_data_ready; - sk->state_change = xprt->old_state_change; - sk->write_space = xprt->old_write_space; - write_unlock_bh(&sk->callback_lock); + sk->sk_user_data = NULL; + sk->sk_data_ready = xprt->old_data_ready; + sk->sk_state_change = xprt->old_state_change; + sk->sk_write_space = xprt->old_write_space; + write_unlock_bh(&sk->sk_callback_lock); xprt_disconnect(xprt); - sk->no_check = 0; + sk->sk_no_check = 0; sock_release(sock); } @@ -448,7 +448,7 @@ status = sock->ops->connect(sock, (struct sockaddr *) &xprt->addr, sizeof(xprt->addr), O_NONBLOCK); dprintk("RPC: %4d connect status %d connected %d sock state %d\n", - task->tk_pid, -status, xprt_connected(xprt), inet->state); + task->tk_pid, -status, xprt_connected(xprt), inet->sk_state); if (status >= 0) return; @@ -458,12 +458,13 @@ case -EALREADY: /* Protect against TCP socket state changes */ lock_sock(inet); - if (inet->state != TCP_ESTABLISHED) { + if (inet->sk_state != TCP_ESTABLISHED) { dprintk("RPC: %4d waiting for connection\n", task->tk_pid); task->tk_timeout = RPC_CONNECT_TIMEOUT; /* if the socket is already closing, delay briefly */ - if ((1 << inet->state) & ~(TCPF_SYN_SENT|TCPF_SYN_RECV)) + if ((1 << inet->sk_state) & + ~(TCPF_SYN_SENT | TCPF_SYN_RECV)) task->tk_timeout = RPC_REESTABLISH_TIMEOUT; rpc_sleep_on(&xprt->pending, task, xprt_connect_status, NULL); @@ -679,7 +680,7 @@ struct sk_buff *skb; int err, repsize, copied; - read_lock(&sk->callback_lock); + read_lock(&sk->sk_callback_lock); dprintk("RPC: udp_data_ready...\n"); if (!(xprt = xprt_from_sock(sk))) { printk("RPC: udp_data_ready request not found!\n"); @@ -728,9 +729,9 @@ dropit: skb_free_datagram(sk, skb); out: - if (sk->sleep && waitqueue_active(sk->sleep)) - wake_up_interruptible(sk->sleep); - read_unlock(&sk->callback_lock); + if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) + wake_up_interruptible(sk->sk_sleep); + read_unlock(&sk->sk_callback_lock); } /* @@ -935,7 +936,7 @@ struct rpc_xprt *xprt; read_descriptor_t rd_desc; - read_lock(&sk->callback_lock); + read_lock(&sk->sk_callback_lock); dprintk("RPC: tcp_data_ready...\n"); if (!(xprt = xprt_from_sock(sk))) { printk("RPC: tcp_data_ready socket info not found!\n"); @@ -949,7 +950,7 @@ rd_desc.count = 65536; tcp_read_sock(sk, &rd_desc, tcp_data_recv); out: - read_unlock(&sk->callback_lock); + read_unlock(&sk->sk_callback_lock); } static void @@ -957,15 +958,15 @@ { struct rpc_xprt *xprt; - read_lock(&sk->callback_lock); + read_lock(&sk->sk_callback_lock); if (!(xprt = xprt_from_sock(sk))) goto out; dprintk("RPC: tcp_state_change client %p...\n", xprt); dprintk("RPC: state %x conn %d dead %d zapped %d\n", - sk->state, xprt_connected(xprt), - test_bit(SOCK_DEAD, &sk->flags), sk->zapped); + sk->sk_state, xprt_connected(xprt), + sock_flag(sk, SOCK_DEAD), sk->sk_zapped); - switch (sk->state) { + switch (sk->sk_state) { case TCP_ESTABLISHED: spin_lock_bh(&xprt->sock_lock); if (!xprt_test_and_set_connected(xprt)) { @@ -989,9 +990,9 @@ break; } out: - if (sk->sleep && waitqueue_active(sk->sleep)) - wake_up_interruptible_all(sk->sleep); - read_unlock(&sk->callback_lock); + if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) + wake_up_interruptible_all(sk->sk_sleep); + read_unlock(&sk->sk_callback_lock); } /* @@ -1006,8 +1007,8 @@ struct rpc_xprt *xprt; struct socket *sock; - read_lock(&sk->callback_lock); - if (!(xprt = xprt_from_sock(sk)) || !(sock = sk->socket)) + read_lock(&sk->sk_callback_lock); + if (!(xprt = xprt_from_sock(sk)) || !(sock = sk->sk_socket)) goto out; if (xprt->shutdown) goto out; @@ -1030,10 +1031,10 @@ if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->pending) rpc_wake_up_task(xprt->snd_task); spin_unlock_bh(&xprt->sock_lock); - if (sk->sleep && waitqueue_active(sk->sleep)) - wake_up_interruptible(sk->sleep); + if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) + wake_up_interruptible(sk->sk_sleep); out: - read_unlock(&sk->callback_lock); + read_unlock(&sk->sk_callback_lock); } /* @@ -1465,28 +1466,28 @@ if (xprt->inet) return; - write_lock_bh(&sk->callback_lock); - sk->user_data = xprt; - xprt->old_data_ready = sk->data_ready; - xprt->old_state_change = sk->state_change; - xprt->old_write_space = sk->write_space; + write_lock_bh(&sk->sk_callback_lock); + sk->sk_user_data = xprt; + xprt->old_data_ready = sk->sk_data_ready; + xprt->old_state_change = sk->sk_state_change; + xprt->old_write_space = sk->sk_write_space; if (xprt->prot == IPPROTO_UDP) { - sk->data_ready = udp_data_ready; - sk->no_check = UDP_CSUM_NORCV; + sk->sk_data_ready = udp_data_ready; + sk->sk_no_check = UDP_CSUM_NORCV; xprt_set_connected(xprt); } else { struct tcp_opt *tp = tcp_sk(sk); tp->nonagle = 1; /* disable Nagle's algorithm */ - sk->data_ready = tcp_data_ready; - sk->state_change = tcp_state_change; + sk->sk_data_ready = tcp_data_ready; + sk->sk_state_change = tcp_state_change; xprt_clear_connected(xprt); } - sk->write_space = xprt_write_space; + sk->sk_write_space = xprt_write_space; /* Reset to new socket */ xprt->sock = sock; xprt->inet = sk; - write_unlock_bh(&sk->callback_lock); + write_unlock_bh(&sk->sk_callback_lock); return; } @@ -1502,13 +1503,13 @@ if (xprt->stream) return; if (xprt->rcvsize) { - sk->userlocks |= SOCK_RCVBUF_LOCK; - sk->rcvbuf = xprt->rcvsize * RPC_MAXCONG * 2; + sk->sk_userlocks |= SOCK_RCVBUF_LOCK; + sk->sk_rcvbuf = xprt->rcvsize * RPC_MAXCONG * 2; } if (xprt->sndsize) { - sk->userlocks |= SOCK_SNDBUF_LOCK; - sk->sndbuf = xprt->sndsize * RPC_MAXCONG * 2; - sk->write_space(sk); + sk->sk_userlocks |= SOCK_SNDBUF_LOCK; + sk->sk_sndbuf = xprt->sndsize * RPC_MAXCONG * 2; + sk->sk_write_space(sk); } } diff -Nru a/net/unix/af_unix.c b/net/unix/af_unix.c --- a/net/unix/af_unix.c Mon Jun 9 23:16:14 2003 +++ b/net/unix/af_unix.c Mon Jun 9 23:16:14 2003 @@ -145,7 +145,7 @@ return hash&(UNIX_HASH_SIZE-1); } -#define unix_peer(sk) ((sk)->pair) +#define unix_peer(sk) ((sk)->sk_pair) static inline int unix_our_peer(unix_socket *sk, unix_socket *osk) { @@ -215,15 +215,15 @@ unix_socket **list = u->list; if (list) { - if (sk->next) - sk->next->prev = sk->prev; - if (sk->prev) - sk->prev->next = sk->next; + if (sk->sk_next) + sk->sk_next->sk_prev = sk->sk_prev; + if (sk->sk_prev) + sk->sk_prev->sk_next = sk->sk_next; if (*list == sk) - *list = sk->next; + *list = sk->sk_next; u->list = NULL; - sk->prev = NULL; - sk->next = NULL; + sk->sk_prev = NULL; + sk->sk_next = NULL; __sock_put(sk); } } @@ -234,10 +234,10 @@ BUG_TRAP(!u->list); u->list = list; - sk->prev = NULL; - sk->next = *list; + sk->sk_prev = NULL; + sk->sk_next = *list; if (*list) - (*list)->prev = sk; + (*list)->sk_prev = sk; *list=sk; sock_hold(sk); } @@ -261,7 +261,7 @@ { unix_socket *s; - for (s=unix_socket_table[hash^type]; s; s=s->next) { + for (s = unix_socket_table[hash ^ type]; s; s = s->sk_next) { struct unix_sock *u = unix_sk(s); if (u->addr->len == len && @@ -290,8 +290,8 @@ unix_socket *s; read_lock(&unix_table_lock); - for (s=unix_socket_table[i->i_ino & (UNIX_HASH_SIZE-1)]; s; s=s->next) - { + for (s = unix_socket_table[i->i_ino & (UNIX_HASH_SIZE - 1)]; s; + s = s->sk_next) { struct dentry *dentry = unix_sk(s)->dentry; if(dentry && dentry->d_inode == i) @@ -306,18 +306,18 @@ static inline int unix_writable(struct sock *sk) { - return ((atomic_read(&sk->wmem_alloc)<<2) <= sk->sndbuf); + return (atomic_read(&sk->sk_wmem_alloc) << 2) <= sk->sk_sndbuf; } static void unix_write_space(struct sock *sk) { - read_lock(&sk->callback_lock); + read_lock(&sk->sk_callback_lock); if (unix_writable(sk)) { - if (sk->sleep && waitqueue_active(sk->sleep)) - wake_up_interruptible(sk->sleep); + if (sk->sk_sleep && waitqueue_active(sk->sk_sleep)) + wake_up_interruptible(sk->sk_sleep); sk_wake_async(sk, 2, POLL_OUT); } - read_unlock(&sk->callback_lock); + read_unlock(&sk->sk_callback_lock); } /* When dgram socket disconnects (or changes its peer), we clear its receive @@ -326,18 +326,17 @@ * may receive messages only from that peer. */ static void unix_dgram_disconnected(struct sock *sk, struct sock *other) { - if (skb_queue_len(&sk->receive_queue)) { - skb_queue_purge(&sk->receive_queue); + if (skb_queue_len(&sk->sk_receive_queue)) { + skb_queue_purge(&sk->sk_receive_queue); wake_up_interruptible_all(&unix_sk(sk)->peer_wait); /* If one link of bidirectional dgram pipe is disconnected, * we signal error. Messages are lost. Do not make this, * when peer was not connected to us. */ - if (!test_bit(SOCK_DEAD, &other->flags) && - unix_peer(other) == sk) { - other->err = ECONNRESET; - other->error_report(other); + if (!sock_flag(other, SOCK_DEAD) && unix_peer(other) == sk) { + other->sk_err = ECONNRESET; + other->sk_error_report(other); } } } @@ -346,12 +345,12 @@ { struct unix_sock *u = unix_sk(sk); - skb_queue_purge(&sk->receive_queue); + skb_queue_purge(&sk->sk_receive_queue); - BUG_TRAP(atomic_read(&sk->wmem_alloc) == 0); + BUG_TRAP(!atomic_read(&sk->sk_wmem_alloc)); BUG_TRAP(!u->list); - BUG_TRAP(sk->socket==NULL); - if (!test_bit(SOCK_DEAD, &sk->flags)) { + BUG_TRAP(!sk->sk_socket); + if (!sock_flag(sk, SOCK_DEAD)) { printk("Attempt to release alive unix socket: %p\n", sk); return; } @@ -379,13 +378,13 @@ /* Clear state */ unix_state_wlock(sk); sock_orphan(sk); - sk->shutdown = SHUTDOWN_MASK; + sk->sk_shutdown = SHUTDOWN_MASK; dentry = u->dentry; u->dentry = NULL; mnt = u->mnt; u->mnt = NULL; - state = sk->state; - sk->state = TCP_CLOSE; + state = sk->sk_state; + sk->sk_state = TCP_CLOSE; unix_state_wunlock(sk); wake_up_interruptible_all(&u->peer_wait); @@ -393,16 +392,17 @@ skpair=unix_peer(sk); if (skpair!=NULL) { - if (sk->type==SOCK_STREAM) { + if (sk->sk_type == SOCK_STREAM) { unix_state_wlock(skpair); - skpair->shutdown=SHUTDOWN_MASK; /* No more writes*/ - if (!skb_queue_empty(&sk->receive_queue) || embrion) - skpair->err = ECONNRESET; + /* No more writes */ + skpair->sk_shutdown = SHUTDOWN_MASK; + if (!skb_queue_empty(&sk->sk_receive_queue) || embrion) + skpair->sk_err = ECONNRESET; unix_state_wunlock(skpair); - skpair->state_change(skpair); - read_lock(&skpair->callback_lock); + skpair->sk_state_change(skpair); + read_lock(&skpair->sk_callback_lock); sk_wake_async(skpair,1,POLL_HUP); - read_unlock(&skpair->callback_lock); + read_unlock(&skpair->sk_callback_lock); } sock_put(skpair); /* It may now die */ unix_peer(sk) = NULL; @@ -410,8 +410,7 @@ /* Try to flush out this socket. Throw out buffers at least */ - while((skb=skb_dequeue(&sk->receive_queue))!=NULL) - { + while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { if (state==TCP_LISTEN) unix_release_sock(skb->sk, 1); /* passed fds are erased in the kfree_skb hook */ @@ -457,16 +456,16 @@ if (!u->addr) goto out; /* No listens on an unbound socket */ unix_state_wlock(sk); - if (sk->state != TCP_CLOSE && sk->state != TCP_LISTEN) + if (sk->sk_state != TCP_CLOSE && sk->sk_state != TCP_LISTEN) goto out_unlock; - if (backlog > sk->max_ack_backlog) + if (backlog > sk->sk_max_ack_backlog) wake_up_interruptible_all(&u->peer_wait); - sk->max_ack_backlog=backlog; - sk->state=TCP_LISTEN; + sk->sk_max_ack_backlog = backlog; + sk->sk_state = TCP_LISTEN; /* set credentials so connect can copy them */ - sk->peercred.pid = current->pid; - sk->peercred.uid = current->euid; - sk->peercred.gid = current->egid; + sk->sk_peercred.pid = current->pid; + sk->sk_peercred.uid = current->euid; + sk->sk_peercred.gid = current->egid; err = 0; out_unlock: @@ -496,10 +495,9 @@ sock_init_data(sock,sk); sk_set_owner(sk, THIS_MODULE); - sk->write_space = unix_write_space; - - sk->max_ack_backlog = sysctl_unix_max_dgram_qlen; - sk->destruct = unix_sock_destructor; + sk->sk_write_space = unix_write_space; + sk->sk_max_ack_backlog = sysctl_unix_max_dgram_qlen; + sk->sk_destruct = unix_sock_destructor; u = unix_sk(sk); u->dentry = NULL; u->mnt = NULL; @@ -590,7 +588,7 @@ yield(); goto retry; } - addr->hash ^= sk->type; + addr->hash ^= sk->sk_type; __unix_remove_socket(sk); u->addr = addr; @@ -624,13 +622,13 @@ if (!u) goto put_fail; - if (u->type == type) + if (u->sk_type == type) update_atime(nd.dentry->d_inode); path_release(&nd); err=-EPROTOTYPE; - if (u->type != type) { + if (u->sk_type != type) { sock_put(u); goto fail; } @@ -694,7 +692,7 @@ memcpy(addr->name, sunaddr, addr_len); addr->len = addr_len; - addr->hash = hash^sk->type; + addr->hash = hash ^ sk->sk_type; atomic_set(&addr->refcnt, 1); if (sunaddr->sun_path[0]) { @@ -737,7 +735,8 @@ /* * All right, let's create it. */ - mode = S_IFSOCK | (SOCK_INODE(sock)->i_mode & ~current->fs->umask); + mode = S_IFSOCK | + (SOCK_INODE(sock)->i_mode & ~current->fs->umask); err = vfs_mknod(nd.dentry->d_inode, dentry, mode, 0); if (err) goto out_mknod_dput; @@ -753,7 +752,7 @@ if (!sunaddr->sun_path[0]) { err = -EADDRINUSE; if (__unix_find_socket_byname(sunaddr, addr_len, - sk->type, hash)) { + sk->sk_type, hash)) { unix_release_addr(addr); goto out_unlock; } @@ -819,7 +818,7 @@ if (!unix_may_send(sk, other)) goto out_unlock; - err = security_unix_may_send(sk->socket, other->socket); + err = security_unix_may_send(sk->sk_socket, other->sk_socket); if (err) goto out_unlock; @@ -863,9 +862,10 @@ prepare_to_wait_exclusive(&u->peer_wait, &wait, TASK_INTERRUPTIBLE); - sched = (!test_bit(SOCK_DEAD, &other->flags) && - !(other->shutdown&RCV_SHUTDOWN) && - skb_queue_len(&other->receive_queue) > other->max_ack_backlog); + sched = !sock_flag(other, SOCK_DEAD) && + !(other->sk_shutdown & RCV_SHUTDOWN) && + (skb_queue_len(&other->sk_receive_queue) > + other->sk_max_ack_backlog); unix_state_runlock(other); @@ -919,7 +919,7 @@ restart: /* Find listening sock. */ - other=unix_find_other(sunaddr, addr_len, sk->type, hash, &err); + other = unix_find_other(sunaddr, addr_len, sk->sk_type, hash, &err); if (!other) goto out; @@ -927,17 +927,18 @@ unix_state_rlock(other); /* Apparently VFS overslept socket death. Retry. */ - if (test_bit(SOCK_DEAD, &other->flags)) { + if (sock_flag(other, SOCK_DEAD)) { unix_state_runlock(other); sock_put(other); goto restart; } err = -ECONNREFUSED; - if (other->state != TCP_LISTEN) + if (other->sk_state != TCP_LISTEN) goto out_unlock; - if (skb_queue_len(&other->receive_queue) > other->max_ack_backlog) { + if (skb_queue_len(&other->sk_receive_queue) > + other->sk_max_ack_backlog) { err = -EAGAIN; if (!timeo) goto out_unlock; @@ -962,7 +963,7 @@ Well, and we have to recheck the state after socket locked. */ - st = sk->state; + st = sk->sk_state; switch (st) { case TCP_CLOSE: @@ -979,14 +980,14 @@ unix_state_wlock(sk); - if (sk->state != st) { + if (sk->sk_state != st) { unix_state_wunlock(sk); unix_state_runlock(other); sock_put(other); goto restart; } - err = security_unix_stream_connect(sock, other->socket, newsk); + err = security_unix_stream_connect(sock, other->sk_socket, newsk); if (err) { unix_state_wunlock(sk); goto out_unlock; @@ -995,14 +996,14 @@ /* The way is open! Fastly set all the necessary fields... */ sock_hold(sk); - unix_peer(newsk)=sk; - newsk->state=TCP_ESTABLISHED; - newsk->type=SOCK_STREAM; - newsk->peercred.pid = current->pid; - newsk->peercred.uid = current->euid; - newsk->peercred.gid = current->egid; + unix_peer(newsk) = sk; + newsk->sk_state = TCP_ESTABLISHED; + newsk->sk_type = SOCK_STREAM; + newsk->sk_peercred.pid = current->pid; + newsk->sk_peercred.uid = current->euid; + newsk->sk_peercred.gid = current->egid; newu = unix_sk(newsk); - newsk->sleep = &newu->peer_wait; + newsk->sk_sleep = &newu->peer_wait; otheru = unix_sk(other); /* copy address information from listening to new sock*/ @@ -1016,24 +1017,24 @@ } /* Set credentials */ - sk->peercred = other->peercred; + sk->sk_peercred = other->sk_peercred; sock_hold(newsk); - unix_peer(sk)=newsk; - sock->state=SS_CONNECTED; - sk->state=TCP_ESTABLISHED; + unix_peer(sk) = newsk; + sock->state = SS_CONNECTED; + sk->sk_state = TCP_ESTABLISHED; unix_state_wunlock(sk); /* take ten and and send info to listening sock */ - spin_lock(&other->receive_queue.lock); - __skb_queue_tail(&other->receive_queue,skb); + spin_lock(&other->sk_receive_queue.lock); + __skb_queue_tail(&other->sk_receive_queue, skb); /* Undo artificially decreased inflight after embrion * is installed to listening socket. */ atomic_inc(&newu->inflight); - spin_unlock(&other->receive_queue.lock); + spin_unlock(&other->sk_receive_queue.lock); unix_state_runlock(other); - other->data_ready(other, 0); + other->sk_data_ready(other, 0); sock_put(other); return 0; @@ -1060,16 +1061,15 @@ sock_hold(skb); unix_peer(ska)=skb; unix_peer(skb)=ska; - ska->peercred.pid = skb->peercred.pid = current->pid; - ska->peercred.uid = skb->peercred.uid = current->euid; - ska->peercred.gid = skb->peercred.gid = current->egid; - - if (ska->type != SOCK_DGRAM) - { - ska->state=TCP_ESTABLISHED; - skb->state=TCP_ESTABLISHED; - socka->state=SS_CONNECTED; - sockb->state=SS_CONNECTED; + ska->sk_peercred.pid = skb->sk_peercred.pid = current->pid; + ska->sk_peercred.uid = skb->sk_peercred.uid = current->euid; + ska->sk_peercred.gid = skb->sk_peercred.gid = current->egid; + + if (ska->sk_type != SOCK_DGRAM) { + ska->sk_state = TCP_ESTABLISHED; + skb->sk_state = TCP_ESTABLISHED; + socka->state = SS_CONNECTED; + sockb->state = SS_CONNECTED; } return 0; } @@ -1086,7 +1086,7 @@ goto out; err = -EINVAL; - if (sk->state!=TCP_LISTEN) + if (sk->sk_state != TCP_LISTEN) goto out; /* If socket state is TCP_LISTEN it cannot change (for now...), @@ -1233,7 +1233,7 @@ goto out; err = -EMSGSIZE; - if ((unsigned)len > sk->sndbuf - 32) + if ((unsigned)len > sk->sk_sndbuf - 32) goto out; skb = sock_alloc_send_skb(sk, len, msg->msg_flags&MSG_DONTWAIT, &err); @@ -1257,7 +1257,8 @@ if (sunaddr == NULL) goto out_free; - other = unix_find_other(sunaddr, namelen, sk->type, hash, &err); + other = unix_find_other(sunaddr, namelen, sk->sk_type, + hash, &err); if (other==NULL) goto out_free; } @@ -1267,7 +1268,7 @@ if (!unix_may_send(sk, other)) goto out_unlock; - if (test_bit(SOCK_DEAD, &other->flags)) { + if (sock_flag(other, SOCK_DEAD)) { /* * Check with 1003.1g - what should * datagram error @@ -1295,15 +1296,16 @@ } err = -EPIPE; - if (other->shutdown&RCV_SHUTDOWN) + if (other->sk_shutdown & RCV_SHUTDOWN) goto out_unlock; - err = security_unix_may_send(sk->socket, other->socket); + err = security_unix_may_send(sk->sk_socket, other->sk_socket); if (err) goto out_unlock; if (unix_peer(other) != sk && - skb_queue_len(&other->receive_queue) > other->max_ack_backlog) { + (skb_queue_len(&other->sk_receive_queue) > + other->sk_max_ack_backlog)) { if (!timeo) { err = -EAGAIN; goto out_unlock; @@ -1318,9 +1320,9 @@ goto restart; } - skb_queue_tail(&other->receive_queue, skb); + skb_queue_tail(&other->sk_receive_queue, skb); unix_state_runlock(other); - other->data_ready(other, len); + other->sk_data_ready(other, len); sock_put(other); scm_destroy(siocb->scm); return len; @@ -1360,7 +1362,7 @@ goto out_err; if (msg->msg_namelen) { - err = (sk->state==TCP_ESTABLISHED ? -EISCONN : -EOPNOTSUPP); + err = sk->sk_state == TCP_ESTABLISHED ? -EISCONN : -EOPNOTSUPP; goto out_err; } else { sunaddr = NULL; @@ -1370,7 +1372,7 @@ goto out_err; } - if (sk->shutdown&SEND_SHUTDOWN) + if (sk->sk_shutdown & SEND_SHUTDOWN) goto pipe_err; while(sent < len) @@ -1383,8 +1385,8 @@ size=len-sent; /* Keep two messages in the pipe so it schedules better */ - if (size > sk->sndbuf/2 - 64) - size = sk->sndbuf/2 - 64; + if (size > sk->sk_sndbuf / 2 - 64) + size = sk->sk_sndbuf / 2 - 64; if (size > SKB_MAX_ALLOC) size = SKB_MAX_ALLOC; @@ -1418,13 +1420,13 @@ unix_state_rlock(other); - if (test_bit(SOCK_DEAD, &other->flags) || - (other->shutdown & RCV_SHUTDOWN)) + if (sock_flag(other, SOCK_DEAD) || + (other->sk_shutdown & RCV_SHUTDOWN)) goto pipe_err_free; - skb_queue_tail(&other->receive_queue, skb); + skb_queue_tail(&other->sk_receive_queue, skb); unix_state_runlock(other); - other->data_ready(other, size); + other->sk_data_ready(other, size); sent+=size; } sock_put(other); @@ -1545,23 +1547,23 @@ unix_state_rlock(sk); for (;;) { - prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE); + prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE); - if (skb_queue_len(&sk->receive_queue) || - sk->err || - (sk->shutdown & RCV_SHUTDOWN) || + if (skb_queue_len(&sk->sk_receive_queue) || + sk->sk_err || + (sk->sk_shutdown & RCV_SHUTDOWN) || signal_pending(current) || !timeo) break; - set_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags); + set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); unix_state_runlock(sk); timeo = schedule_timeout(timeo); unix_state_rlock(sk); - clear_bit(SOCK_ASYNC_WAITDATA, &sk->socket->flags); + clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); } - finish_wait(sk->sleep, &wait); + finish_wait(sk->sk_sleep, &wait); unix_state_runlock(sk); return timeo; } @@ -1584,7 +1586,7 @@ long timeo; err = -EINVAL; - if (sk->state != TCP_ESTABLISHED) + if (sk->sk_state != TCP_ESTABLISHED) goto out; err = -EOPNOTSUPP; @@ -1612,7 +1614,7 @@ int chunk; struct sk_buff *skb; - skb=skb_dequeue(&sk->receive_queue); + skb = skb_dequeue(&sk->sk_receive_queue); if (skb==NULL) { if (copied >= target) @@ -1624,7 +1626,7 @@ if ((err = sock_error(sk)) != 0) break; - if (sk->shutdown & RCV_SHUTDOWN) + if (sk->sk_shutdown & RCV_SHUTDOWN) break; err = -EAGAIN; if (!timeo) @@ -1644,7 +1646,7 @@ if (check_creds) { /* Never glue messages from different writers */ if (memcmp(UNIXCREDS(skb), &siocb->scm->creds, sizeof(siocb->scm->creds)) != 0) { - skb_queue_head(&sk->receive_queue, skb); + skb_queue_head(&sk->sk_receive_queue, skb); break; } } else { @@ -1662,7 +1664,7 @@ chunk = min_t(unsigned int, skb->len, size); if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) { - skb_queue_head(&sk->receive_queue, skb); + skb_queue_head(&sk->sk_receive_queue, skb); if (copied == 0) copied = -EFAULT; break; @@ -1681,7 +1683,7 @@ /* put the skb back if we didn't use it up.. */ if (skb->len) { - skb_queue_head(&sk->receive_queue, skb); + skb_queue_head(&sk->sk_receive_queue, skb); break; } @@ -1698,7 +1700,7 @@ siocb->scm->fp = scm_fp_dup(UNIXCB(skb).fp); /* put message back and return */ - skb_queue_head(&sk->receive_queue, skb); + skb_queue_head(&sk->sk_receive_queue, skb); break; } } while (size); @@ -1718,14 +1720,14 @@ if (mode) { unix_state_wlock(sk); - sk->shutdown |= mode; + sk->sk_shutdown |= mode; other=unix_peer(sk); if (other) sock_hold(other); unix_state_wunlock(sk); - sk->state_change(sk); + sk->sk_state_change(sk); - if (other && sk->type == SOCK_STREAM) { + if (other && sk->sk_type == SOCK_STREAM) { int peer_mode = 0; if (mode&RCV_SHUTDOWN) @@ -1733,15 +1735,15 @@ if (mode&SEND_SHUTDOWN) peer_mode |= RCV_SHUTDOWN; unix_state_wlock(other); - other->shutdown |= peer_mode; + other->sk_shutdown |= peer_mode; unix_state_wunlock(other); - other->state_change(other); - read_lock(&other->callback_lock); + other->sk_state_change(other); + read_lock(&other->sk_callback_lock); if (peer_mode == SHUTDOWN_MASK) sk_wake_async(other,1,POLL_HUP); else if (peer_mode & RCV_SHUTDOWN) sk_wake_async(other,1,POLL_IN); - read_unlock(&other->callback_lock); + read_unlock(&other->sk_callback_lock); } if (other) sock_put(other); @@ -1758,21 +1760,22 @@ switch(cmd) { case SIOCOUTQ: - amount = atomic_read(&sk->wmem_alloc); + amount = atomic_read(&sk->sk_wmem_alloc); err = put_user(amount, (int *)arg); break; case SIOCINQ: { struct sk_buff *skb; - if (sk->state==TCP_LISTEN) { + if (sk->sk_state == TCP_LISTEN) { err = -EINVAL; break; } - spin_lock(&sk->receive_queue.lock); - if((skb=skb_peek(&sk->receive_queue))!=NULL) + spin_lock(&sk->sk_receive_queue.lock); + skb = skb_peek(&sk->sk_receive_queue); + if (skb) amount=skb->len; - spin_unlock(&sk->receive_queue.lock); + spin_unlock(&sk->sk_receive_queue.lock); err = put_user(amount, (int *)arg); break; } @@ -1789,21 +1792,22 @@ struct sock *sk = sock->sk; unsigned int mask; - poll_wait(file, sk->sleep, wait); + poll_wait(file, sk->sk_sleep, wait); mask = 0; /* exceptional events? */ - if (sk->err) + if (sk->sk_err) mask |= POLLERR; - if (sk->shutdown == SHUTDOWN_MASK) + if (sk->sk_shutdown == SHUTDOWN_MASK) mask |= POLLHUP; /* readable? */ - if (!skb_queue_empty(&sk->receive_queue) || (sk->shutdown&RCV_SHUTDOWN)) + if (!skb_queue_empty(&sk->sk_receive_queue) || + (sk->sk_shutdown & RCV_SHUTDOWN)) mask |= POLLIN | POLLRDNORM; /* Connection-based need to check for termination and startup */ - if (sk->type == SOCK_STREAM && sk->state==TCP_CLOSE) + if (sk->sk_type == SOCK_STREAM && sk->sk_state == TCP_CLOSE) mask |= POLLHUP; /* @@ -1838,13 +1842,13 @@ len+=sprintf(buffer+len,"%p: %08X %08X %08X %04X %02X %5lu", s, - atomic_read(&s->refcnt), + atomic_read(&s->sk_refcnt), 0, - s->state == TCP_LISTEN ? __SO_ACCEPTCON : 0, - s->type, - s->socket ? - (s->state == TCP_ESTABLISHED ? SS_CONNECTED : SS_UNCONNECTED) : - (s->state == TCP_ESTABLISHED ? SS_CONNECTING : SS_DISCONNECTING), + s->sk_state == TCP_LISTEN ? __SO_ACCEPTCON : 0, + s->sk_type, + s->sk_socket ? + (s->sk_state == TCP_ESTABLISHED ? SS_CONNECTED : SS_UNCONNECTED) : + (s->sk_state == TCP_ESTABLISHED ? SS_CONNECTING : SS_DISCONNECTING), sock_i_ino(s)); if (u->addr) { diff -Nru a/net/unix/garbage.c b/net/unix/garbage.c --- a/net/unix/garbage.c Mon Jun 9 23:16:09 2003 +++ b/net/unix/garbage.c Mon Jun 9 23:16:09 2003 @@ -219,8 +219,8 @@ * negative inflight counter to close race window. * It is trick of course and dirty one. */ - if(s->socket && s->socket->file) - open_count = file_count(s->socket->file); + if (s->sk_socket && s->sk_socket->file) + open_count = file_count(s->sk_socket->file); if (open_count > atomic_read(&unix_sk(s)->inflight)) maybe_unmark_and_push(s); } @@ -234,15 +234,14 @@ unix_socket *x = pop_stack(); unix_socket *sk; - spin_lock(&x->receive_queue.lock); - skb=skb_peek(&x->receive_queue); + spin_lock(&x->sk_receive_queue.lock); + skb = skb_peek(&x->sk_receive_queue); /* * Loop through all but first born */ - while(skb && skb != (struct sk_buff *)&x->receive_queue) - { + while (skb && skb != (struct sk_buff *)&x->sk_receive_queue) { /* * Do we have file descriptors ? */ @@ -266,12 +265,11 @@ } } /* We have to scan not-yet-accepted ones too */ - if (x->state == TCP_LISTEN) { + if (x->sk_state == TCP_LISTEN) maybe_unmark_and_push(skb->sk); - } skb=skb->next; } - spin_unlock(&x->receive_queue.lock); + spin_unlock(&x->sk_receive_queue.lock); sock_put(x); } @@ -283,10 +281,11 @@ if (u->gc_tree == GC_ORPHAN) { struct sk_buff *nextsk; - spin_lock(&s->receive_queue.lock); - skb=skb_peek(&s->receive_queue); - while(skb && skb != (struct sk_buff *)&s->receive_queue) - { + + spin_lock(&s->sk_receive_queue.lock); + skb = skb_peek(&s->sk_receive_queue); + while (skb && + skb != (struct sk_buff *)&s->sk_receive_queue) { nextsk=skb->next; /* * Do we have file descriptors ? @@ -298,7 +297,7 @@ } skb=nextsk; } - spin_unlock(&s->receive_queue.lock); + spin_unlock(&s->sk_receive_queue.lock); } u->gc_tree = GC_ORPHAN; } diff -Nru a/net/wanrouter/af_wanpipe.c b/net/wanrouter/af_wanpipe.c --- a/net/wanrouter/af_wanpipe.c Mon Jun 9 23:16:19 2003 +++ b/net/wanrouter/af_wanpipe.c Mon Jun 9 23:16:19 2003 @@ -84,12 +84,12 @@ * When the user sends a packet via send() system call * the wanpipe_sendmsg() function is executed. * - * Each packet is enqueud into sk->write_queue transmit + * Each packet is enqueud into sk->sk_write_queue transmit * queue. When the packet is enqueued, a delayed transmit * timer is triggerd which acts as a Bottom Half hander. * * wanpipe_delay_transmit() function (BH), dequeues packets - * from the sk->write_queue transmit queue and sends it + * from the sk->sk_write_queue transmit queue and sends it * to the deriver via dev->hard_start_xmit(skb, dev) function. * Note, this function is actual a function pointer of if_send() * routine in the wanpipe driver. @@ -99,7 +99,7 @@ * In order to provide 100% guaranteed packet delivery, * an atomic 'packet_sent' counter is implemented. Counter * is incremented for each packet enqueued - * into sk->write_queue. Counter is decremented each + * into sk->sk_write_queue. Counter is decremented each * time wanpipe_delayed_transmit() function successfuly * passes the packet to the driver. Before each send(), a poll * routine checks the sock resources The maximum value of @@ -263,16 +263,16 @@ } break; case WAN_PACKET_CMD: - sk->state = chan->state; + sk->sk_state = chan->state; /* Bug fix: update Mar6. * Do not set the sock lcn number here, since * cmd is not guaranteed to be executed on the * board, thus Lcn could be wrong */ - sk->data_ready(sk,skb->len); + sk->sk_data_ready(sk, skb->len); kfree_skb(skb); break; case WAN_PACKET_ERR: - sk->state = chan->state; + sk->sk_state = chan->state; if (sock_queue_err_skb(sk,skb)<0){ return -ENOMEM; } @@ -284,11 +284,11 @@ } //?????????????????????? -// if (sk->state == WANSOCK_DISCONNECTED){ -// if (sk->zapped){ +// if (sk->sk_state == WANSOCK_DISCONNECTED){ +// if (sk->sk_zapped) { // //printk(KERN_INFO "wansock: Disconnected, killing early\n"); // wanpipe_unlink_driver(sk); -// sk->bound_dev_if = 0; +// sk->sk_bound_dev_if = 0; // } // } @@ -359,7 +359,7 @@ /* Initialize the new sock structure */ - newsk->bound_dev_if = dev->ifindex; + newsk->sk_bound_dev_if = dev->ifindex; newwp = wp_sk(newsk); newwp->card = wp->card; @@ -395,7 +395,7 @@ chan->lcn = mbox_ptr->cmd.lcn; card->u.x.svc_to_dev_map[(chan->lcn%MAX_X25_LCN)] = dev; - newsk->zapped=0; + newsk->sk_zapped = 0; newwp->num = htons(X25_PROT); if (wanpipe_do_bind(newsk, dev, newwp->num)) { @@ -403,7 +403,7 @@ release_device(dev); return -EINVAL; } - newsk->state = WANSOCK_CONNECTING; + newsk->sk_state = WANSOCK_CONNECTING; /* Fill in the standard sock address info */ @@ -416,23 +416,23 @@ sll->sll_halen = 0; skb->dev = dev; - sk->ack_backlog++; + sk->sk_ack_backlog++; /* We must do this manually, since the sock_queue_rcv_skb() * function sets the skb->dev to NULL. However, we use * the dev field in the accept function.*/ - if (atomic_read(&sk->rmem_alloc) + skb->truesize >= - (unsigned)sk->rcvbuf){ + if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >= + (unsigned)sk->sk_rcvbuf) { wanpipe_unlink_driver(newsk); wanpipe_kill_sock_irq (newsk); - --sk->ack_backlog; + --sk->sk_ack_backlog; return -ENOMEM; } skb_set_owner_r(skb, sk); - skb_queue_tail(&sk->receive_queue, skb); - sk->data_ready(sk,skb->len); + skb_queue_tail(&sk->sk_receive_queue, skb); + sk->sk_data_ready(sk, skb->len); return 0; } @@ -456,22 +456,22 @@ { struct sock *sk; - if (osk->type != SOCK_RAW) + if (osk->sk_type != SOCK_RAW) return NULL; if ((sk = wanpipe_alloc_socket()) == NULL) return NULL; - sk->type = osk->type; - sk->socket = osk->socket; - sk->priority = osk->priority; - sk->protocol = osk->protocol; + sk->sk_type = osk->sk_type; + sk->sk_socket = osk->sk_socket; + sk->sk_priority = osk->sk_priority; + sk->sk_protocol = osk->sk_protocol; wp_sk(sk)->num = wp_sk(osk)->num; - sk->rcvbuf = osk->rcvbuf; - sk->sndbuf = osk->sndbuf; - sk->debug = osk->debug; - sk->state = WANSOCK_CONNECTING; - sk->sleep = osk->sleep; + sk->sk_rcvbuf = osk->sk_rcvbuf; + sk->sk_sndbuf = osk->sk_sndbuf; + sk->sk_debug = osk->sk_debug; + sk->sk_state = WANSOCK_CONNECTING; + sk->sk_sleep = osk->sk_sleep; return sk; } @@ -521,17 +521,17 @@ * * This function implements a sendto() system call, * for AF_WANPIPE socket family. - * During socket bind() sk->bound_dev_if is initialized + * During socket bind() sk->sk_bound_dev_if is initialized * to a correct network device. This number is used * to find a network device to which the packet should * be passed to. * - * Each packet is queued into sk->write_queue and + * Each packet is queued into sk->sk_write_queue and * delayed transmit bottom half handler is marked for * execution. * * A socket must be in WANSOCK_CONNECTED state before - * a packet is queued into sk->write_queue. + * a packet is queued into sk->sk_write_queue. *===========================================================*/ static int wanpipe_sendmsg(struct kiocb *iocb, struct socket *sock, @@ -547,10 +547,10 @@ int ifindex, err, reserve = 0; - if (!sk->zapped) + if (!sk->sk_zapped) return -ENETDOWN; - if (sk->state != WANSOCK_CONNECTED) + if (sk->sk_state != WANSOCK_CONNECTED) return -ENOTCONN; if (msg->msg_flags&~MSG_DONTWAIT) @@ -564,7 +564,7 @@ wp = wp_sk(sk); if (saddr == NULL) { - ifindex = sk->bound_dev_if; + ifindex = sk->sk_bound_dev_if; proto = wp->num; addr = NULL; @@ -573,7 +573,7 @@ return -EINVAL; } - ifindex = sk->bound_dev_if; + ifindex = sk->sk_bound_dev_if; proto = saddr->sll_protocol; addr = saddr->sll_addr; } @@ -619,19 +619,20 @@ skb->protocol = proto; skb->dev = dev; - skb->priority = sk->priority; + skb->priority = sk->sk_priority; skb->pkt_type = WAN_PACKET_DATA; err = -ENETDOWN; if (!(dev->flags & IFF_UP)) goto out_free; - if (atomic_read(&sk->wmem_alloc) + skb->truesize > (unsigned int)sk->sndbuf){ + if (atomic_read(&sk->sk_wmem_alloc) + skb->truesize > + (unsigned int)sk->sk_sndbuf){ kfree_skb(skb); return -ENOBUFS; } - skb_queue_tail(&sk->write_queue,skb); + skb_queue_tail(&sk->sk_write_queue,skb); atomic_inc(&wp->packet_sent); if (!(test_and_set_bit(0, &wp->timer))){ @@ -652,7 +653,7 @@ * wanpipe_delayed_tarnsmit * * Transmit bottom half handler. It dequeues packets - * from sk->write_queue and passes them to the + * from sk->sk_write_queue and passes them to the * driver. If the driver is busy, the packet is * re-enqueued. * @@ -675,7 +676,7 @@ return; } - if (sk->state != WANSOCK_CONNECTED || !sk->zapped){ + if (sk->sk_state != WANSOCK_CONNECTED || !sk->sk_zapped) { clear_bit(0, &wp->timer); DBG_PRINTK(KERN_INFO "wansock: Tx Timer, State not CONNECTED\n"); return; @@ -701,13 +702,13 @@ } /* Check for a packet in the fifo and send */ - if ((skb=skb_dequeue(&sk->write_queue)) != NULL){ + if ((skb = skb_dequeue(&sk->sk_write_queue)) != NULL){ if (dev->hard_start_xmit(skb, dev) != 0){ /* Driver failed to transmit, re-enqueue * the packet and retry again later */ - skb_queue_head(&sk->write_queue,skb); + skb_queue_head(&sk->sk_write_queue,skb); clear_bit(0,&wanpipe_tx_critical); return; }else{ @@ -718,11 +719,11 @@ */ atomic_dec(&wp->packet_sent); - if (skb_peek(&sk->write_queue) == NULL){ + if (skb_peek(&sk->sk_write_queue) == NULL) { /* If there is nothing to send, kick * the poll routine, which will trigger * the application to send more data */ - sk->data_ready(sk,0); + sk->sk_data_ready(sk, 0); clear_bit(0, &wp->timer); }else{ /* Reschedule as fast as possible */ @@ -763,10 +764,10 @@ int err=0; DECLARE_WAITQUEUE(wait, current); - dev = dev_get_by_index(sk->bound_dev_if); + dev = dev_get_by_index(sk->sk_bound_dev_if); if (dev == NULL){ printk(KERN_INFO "wansock: Exec failed no dev %i\n", - sk->bound_dev_if); + sk->sk_bound_dev_if); return -ENODEV; } dev_put(dev); @@ -799,7 +800,7 @@ atomic_set(&chan->command, cmd); } - add_wait_queue(sk->sleep,&wait); + add_wait_queue(sk->sk_sleep,&wait); current->state = TASK_INTERRUPTIBLE; for (;;){ if (((mbox_cmd_t*)wp->mbox)->cmd.result != 0x7F) { @@ -813,7 +814,7 @@ schedule(); } current->state = TASK_RUNNING; - remove_wait_queue(sk->sleep,&wait); + remove_wait_queue(sk->sk_sleep,&wait); return err; } @@ -830,27 +831,29 @@ struct sock *sk=(struct sock *)data; wanpipe_opt *wp = wp_sk(sk); - if ((!atomic_read(&sk->wmem_alloc) && !atomic_read(&sk->rmem_alloc)) || + if ((!atomic_read(&sk->sk_wmem_alloc) && + !atomic_read(&sk->sk_rmem_alloc)) || (++wp->force == 5)) { - if (atomic_read(&sk->wmem_alloc) || atomic_read(&sk->rmem_alloc)) + if (atomic_read(&sk->sk_wmem_alloc) || + atomic_read(&sk->sk_rmem_alloc)) printk(KERN_INFO "wansock: Warning, Packet Discarded due to sock shutdown!\n"); kfree(wp); wp_sk(sk) = NULL; - if (atomic_read(&sk->refcnt) != 1){ - atomic_set(&sk->refcnt,1); + if (atomic_read(&sk->sk_refcnt) != 1) { + atomic_set(&sk->sk_refcnt, 1); DBG_PRINTK(KERN_INFO "wansock: Error, wrong reference count: %i ! :delay.\n", - atomic_read(&sk->refcnt)); + atomic_read(&sk->sk_refcnt)); } sock_put(sk); atomic_dec(&wanpipe_socks_nr); return; } - sk->timer.expires=jiffies+5*HZ; - add_timer(&sk->timer); + sk->sk_timer.expires = jiffies + 5 * HZ; + add_timer(&sk->sk_timer); printk(KERN_INFO "wansock: packet sk destroy delayed\n"); } @@ -866,11 +869,11 @@ struct net_device *dev; wanpipe_common_t *chan=NULL; - sk->zapped=0; - sk->state = WANSOCK_DISCONNECTED; + sk->sk_zapped = 0; + sk->sk_state = WANSOCK_DISCONNECTED; wp_sk(sk)->dev = NULL; - dev = dev_get_by_index(sk->bound_dev_if); + dev = dev_get_by_index(sk->sk_bound_dev_if); if (!dev){ printk(KERN_INFO "wansock: No dev on release\n"); return; @@ -915,7 +918,7 @@ chan->mbox = wp->mbox; chan->tx_timer = &wp->tx_timer; wp->dev = dev; - sk->zapped = 1; + sk->sk_zapped = 1; clear_bit(0,&chan->common_critical); } @@ -966,23 +969,23 @@ */ if (wp->num == htons(X25_PROT) && - sk->state != WANSOCK_DISCONNECTED && sk->zapped) { - struct net_device *dev = dev_get_by_index(sk->bound_dev_if); + sk->sk_state != WANSOCK_DISCONNECTED && sk->sk_zapped) { + struct net_device *dev = dev_get_by_index(sk->sk_bound_dev_if); wanpipe_common_t *chan; if (dev){ chan=dev->priv; atomic_set(&chan->disconnect,1); DBG_PRINTK(KERN_INFO "wansock: Sending Clear Indication %i\n", - sk->state); + sk->sk_state); dev_put(dev); } } set_bit(1,&wanpipe_tx_critical); write_lock(&wanpipe_sklist_lock); - for (skp = &wanpipe_sklist; *skp; skp = &(*skp)->next) { + for (skp = &wanpipe_sklist; *skp; skp = &(*skp)->sk_next) { if (*skp == sk) { - *skp = sk->next; + *skp = sk->sk_next; __sock_put(sk); break; } @@ -999,35 +1002,37 @@ * Now the socket is dead. No more input will appear. */ - sk->state_change(sk); /* It is useless. Just for sanity. */ + sk->sk_state_change(sk); /* It is useless. Just for sanity. */ sock->sk = NULL; - sk->socket = NULL; - __set_bit(SOCK_DEAD, &sk->flags); + sk->sk_socket = NULL; + sock_set_flag(sk, SOCK_DEAD); /* Purge queues */ - skb_queue_purge(&sk->receive_queue); - skb_queue_purge(&sk->write_queue); - skb_queue_purge(&sk->error_queue); - - if (atomic_read(&sk->rmem_alloc) || atomic_read(&sk->wmem_alloc)) { - del_timer(&sk->timer); + skb_queue_purge(&sk->sk_receive_queue); + skb_queue_purge(&sk->sk_write_queue); + skb_queue_purge(&sk->sk_error_queue); + + if (atomic_read(&sk->sk_rmem_alloc) || + atomic_read(&sk->sk_wmem_alloc)) { + del_timer(&sk->sk_timer); printk(KERN_INFO "wansock: Killing in Timer R %i , W %i\n", - atomic_read(&sk->rmem_alloc),atomic_read(&sk->wmem_alloc)); - sk->timer.data=(unsigned long)sk; - sk->timer.expires=jiffies+HZ; - sk->timer.function=wanpipe_destroy_timer; - add_timer(&sk->timer); + atomic_read(&sk->sk_rmem_alloc), + atomic_read(&sk->sk_wmem_alloc)); + sk->sk_timer.data = (unsigned long)sk; + sk->sk_timer.expires = jiffies + HZ; + sk->sk_timer.function = wanpipe_destroy_timer; + add_timer(&sk->sk_timer); return 0; } kfree(wp); wp_sk(sk) = NULL; - if (atomic_read(&sk->refcnt) != 1){ + if (atomic_read(&sk->sk_refcnt) != 1) { DBG_PRINTK(KERN_INFO "wansock: Error, wrong reference count: %i !:release.\n", - atomic_read(&sk->refcnt)); - atomic_set(&sk->refcnt,1); + atomic_read(&sk->sk_refcnt)); + atomic_set(&sk->sk_refcnt, 1); } sock_put(sk); atomic_dec(&wanpipe_socks_nr); @@ -1046,10 +1051,10 @@ static void check_write_queue(struct sock *sk) { - if (sk->state != WANSOCK_CONNECTED) + if (sk->sk_state != WANSOCK_CONNECTED) return; - if (!atomic_read(&sk->wmem_alloc)) + if (!atomic_read(&sk->sk_wmem_alloc)) return; printk(KERN_INFO "wansock: MAJOR ERROR, Data lost on sock release !!!\n"); @@ -1071,24 +1076,25 @@ struct sk_buff *skb=NULL; struct sock *deadsk=NULL; - if (sk->state == WANSOCK_LISTEN || sk->state == WANSOCK_BIND_LISTEN){ - while ((skb=skb_dequeue(&sk->receive_queue))!=NULL){ + if (sk->sk_state == WANSOCK_LISTEN || + sk->sk_state == WANSOCK_BIND_LISTEN) { + while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { if ((deadsk = get_newsk_from_skb(skb))){ DBG_PRINTK (KERN_INFO "wansock: RELEASE: FOUND DEAD SOCK\n"); - __set_bit(SOCK_DEAD, &deadsk->flags); + sock_set_flag(deadsk, SOCK_DEAD); start_cleanup_timer(deadsk); } kfree_skb(skb); } - if (sk->zapped) + if (sk->sk_zapped) wanpipe_unlink_card(sk); }else{ - if (sk->zapped) + if (sk->sk_zapped) wanpipe_unlink_driver(sk); } - sk->state = WANSOCK_DISCONNECTED; - sk->bound_dev_if = 0; - sk->zapped=0; + sk->sk_state = WANSOCK_DISCONNECTED; + sk->sk_bound_dev_if = 0; + sk->sk_zapped = 0; wp = wp_sk(sk); if (wp && wp->mbox) { @@ -1108,11 +1114,11 @@ static void start_cleanup_timer (struct sock *sk) { - del_timer(&sk->timer); - sk->timer.data = (unsigned long)sk; - sk->timer.expires = jiffies + HZ; - sk->timer.function = wanpipe_kill_sock_timer; - add_timer(&sk->timer); + del_timer(&sk->sk_timer); + sk->sk_timer.data = (unsigned long)sk; + sk->sk_timer.expires = jiffies + HZ; + sk->sk_timer.function = wanpipe_kill_sock_timer; + add_timer(&sk->sk_timer); } @@ -1137,15 +1143,15 @@ * appropriate locks */ if (test_bit(1,&wanpipe_tx_critical)){ - sk->timer.expires=jiffies+10; - add_timer(&sk->timer); + sk->sk_timer.expires = jiffies + 10; + add_timer(&sk->sk_timer); return; } write_lock(&wanpipe_sklist_lock); - for (skp = &wanpipe_sklist; *skp; skp = &(*skp)->next) { + for (skp = &wanpipe_sklist; *skp; skp = &(*skp)->sk_next) { if (*skp == sk) { - *skp = sk->next; + *skp = sk->sk_next; __sock_put(sk); break; } @@ -1154,8 +1160,8 @@ if (wp_sk(sk)->num == htons(X25_PROT) && - sk->state != WANSOCK_DISCONNECTED){ - struct net_device *dev = dev_get_by_index(sk->bound_dev_if); + sk->sk_state != WANSOCK_DISCONNECTED) { + struct net_device *dev = dev_get_by_index(sk->sk_bound_dev_if); wanpipe_common_t *chan; if (dev){ chan=dev->priv; @@ -1166,20 +1172,21 @@ release_driver(sk); - sk->socket = NULL; + sk->sk_socket = NULL; /* Purge queues */ - skb_queue_purge(&sk->receive_queue); - skb_queue_purge(&sk->write_queue); - skb_queue_purge(&sk->error_queue); - - if (atomic_read(&sk->rmem_alloc) || atomic_read(&sk->wmem_alloc)) { - del_timer(&sk->timer); + skb_queue_purge(&sk->sk_receive_queue); + skb_queue_purge(&sk->sk_write_queue); + skb_queue_purge(&sk->sk_error_queue); + + if (atomic_read(&sk->sk_rmem_alloc) || + atomic_read(&sk->sk_wmem_alloc)) { + del_timer(&sk->sk_timer); printk(KERN_INFO "wansock: Killing SOCK in Timer\n"); - sk->timer.data=(unsigned long)sk; - sk->timer.expires=jiffies+HZ; - sk->timer.function=wanpipe_destroy_timer; - add_timer(&sk->timer); + sk->sk_timer.data = (unsigned long)sk; + sk->sk_timer.expires = jiffies + HZ; + sk->sk_timer.function = wanpipe_destroy_timer; + add_timer(&sk->sk_timer); return; } @@ -1188,10 +1195,10 @@ wp_sk(sk) = NULL; } - if (atomic_read(&sk->refcnt) != 1){ - atomic_set(&sk->refcnt,1); + if (atomic_read(&sk->sk_refcnt) != 1) { + atomic_set(&sk->sk_refcnt, 1); DBG_PRINTK(KERN_INFO "wansock: Error, wrong reference count: %i ! :timer.\n", - atomic_read(&sk->refcnt)); + atomic_read(&sk->sk_refcnt)); } sock_put(sk); atomic_dec(&wanpipe_socks_nr); @@ -1210,16 +1217,16 @@ * appropriate locks */ write_lock(&wanpipe_sklist_lock); - for (skp = &wanpipe_sklist; *skp; skp = &(*skp)->next) { + for (skp = &wanpipe_sklist; *skp; skp = &(*skp)->sk_next) { if (*skp == sk) { - *skp = sk->next; + *skp = sk->sk_next; __sock_put(sk); break; } } write_unlock(&wanpipe_sklist_lock); - sk->socket = NULL; + sk->sk_socket = NULL; if (wp_sk(sk)) { @@ -1227,10 +1234,10 @@ wp_sk(sk) = NULL; } - if (atomic_read(&sk->refcnt) != 1){ - atomic_set(&sk->refcnt,1); + if (atomic_read(&sk->sk_refcnt) != 1) { + atomic_set(&sk->sk_refcnt, 1); DBG_PRINTK(KERN_INFO "wansock: Error, wrong reference count: %i ! :timer.\n", - atomic_read(&sk->refcnt)); + atomic_read(&sk->sk_refcnt)); } sock_put(sk); atomic_dec(&wanpipe_socks_nr); @@ -1244,17 +1251,17 @@ if (!sk) return; - sk->socket = NULL; + sk->sk_socket = NULL; if (wp_sk(sk)) { kfree(wp_sk(sk)); wp_sk(sk) = NULL; } - if (atomic_read(&sk->refcnt) != 1){ - atomic_set(&sk->refcnt,1); + if (atomic_read(&sk->sk_refcnt) != 1) { + atomic_set(&sk->sk_refcnt, 1); DBG_PRINTK(KERN_INFO "wansock: Error, wrong reference count: %i !:listen.\n", - atomic_read(&sk->refcnt)); + atomic_read(&sk->sk_refcnt)); } sock_put(sk); atomic_dec(&wanpipe_socks_nr); @@ -1277,7 +1284,7 @@ wanpipe_common_t *chan=NULL; int err=0; - if (sk->zapped){ + if (sk->sk_zapped) { err = -EALREADY; goto bind_unlock_exit; } @@ -1293,29 +1300,29 @@ if (dev) { if (dev->flags&IFF_UP) { chan=dev->priv; - sk->state = chan->state; + sk->sk_state = chan->state; if (wp->num == htons(X25_PROT) && - sk->state != WANSOCK_DISCONNECTED && - sk->state != WANSOCK_CONNECTING){ + sk->sk_state != WANSOCK_DISCONNECTED && + sk->sk_state != WANSOCK_CONNECTING) { DBG_PRINTK(KERN_INFO "wansock: Binding to Device not DISCONNECTED %i\n", - sk->state); + sk->sk_state); release_device(dev); err = -EAGAIN; goto bind_unlock_exit; } wanpipe_link_driver(dev,sk); - sk->bound_dev_if = dev->ifindex; + sk->sk_bound_dev_if = dev->ifindex; /* X25 Specific option */ if (wp->num == htons(X25_PROT)) wp_sk(sk)->svc = chan->svc; } else { - sk->err = ENETDOWN; - sk->error_report(sk); + sk->sk_err = ENETDOWN; + sk->sk_error_report(sk); release_device(dev); err = -EINVAL; } @@ -1386,7 +1393,7 @@ if (sll->sll_protocol) wp->num = sll->sll_protocol; - sk->state = WANSOCK_BIND_LISTEN; + sk->sk_state = WANSOCK_BIND_LISTEN; return 0; }else if (!strcmp(sll->sll_device,"svc_connect")){ @@ -1527,16 +1534,16 @@ if ((sk = wanpipe_alloc_socket()) == NULL) return -ENOBUFS; - sk->reuse = 1; + sk->sk_reuse = 1; sock->ops = &wanpipe_ops; sock_init_data(sock,sk); - sk->zapped=0; - sk->family = PF_WANPIPE; - wp_sk(sk)->num = protocol; - sk->state = WANSOCK_DISCONNECTED; - sk->ack_backlog = 0; - sk->bound_dev_if=0; + sk->sk_zapped = 0; + sk->sk_family = PF_WANPIPE; + wp_sk(sk)->num = protocol; + sk->sk_state = WANSOCK_DISCONNECTED; + sk->sk_ack_backlog = 0; + sk->sk_bound_dev_if = 0; atomic_inc(&wanpipe_socks_nr); @@ -1544,7 +1551,7 @@ * can also change the list */ set_bit(1,&wanpipe_tx_critical); write_lock(&wanpipe_sklist_lock); - sk->next = wanpipe_sklist; + sk->sk_next = wanpipe_sklist; wanpipe_sklist = sk; sock_hold(sk); write_unlock(&wanpipe_sklist_lock); @@ -1586,7 +1593,7 @@ */ if (flags & MSG_OOB){ - skb=skb_dequeue(&sk->error_queue); + skb = skb_dequeue(&sk->sk_error_queue); }else{ skb=skb_recv_datagram(sk,flags,1,&err); } @@ -1653,7 +1660,7 @@ struct net_device *dev = NULL; wanpipe_common_t *chan=NULL; - dev = dev_get_by_index(sk->bound_dev_if); + dev = dev_get_by_index(sk->sk_bound_dev_if); if (!dev) return; @@ -1663,7 +1670,8 @@ return; if (atomic_read(&chan->receive_block)){ - if (atomic_read(&sk->rmem_alloc) < ((unsigned)sk->rcvbuf*0.9) ){ + if (atomic_read(&sk->sk_rmem_alloc) < + ((unsigned)sk->sk_rcvbuf * 0.9)) { printk(KERN_INFO "wansock: Queuing task for wanpipe\n"); atomic_set(&chan->receive_block,0); wanpipe_queue_tq(&chan->wanpipe_task); @@ -1689,9 +1697,9 @@ struct wan_sockaddr_ll *sll = (struct wan_sockaddr_ll*)uaddr; sll->sll_family = AF_WANPIPE; - sll->sll_ifindex = sk->bound_dev_if; + sll->sll_ifindex = sk->sk_bound_dev_if; sll->sll_protocol = wp_sk(sk)->num; - dev = dev_get_by_index(sk->bound_dev_if); + dev = dev_get_by_index(sk->sk_bound_dev_if); if (dev) { sll->sll_hatype = dev->type; sll->sll_halen = dev->addr_len; @@ -1725,7 +1733,7 @@ struct net_device *dev = (struct net_device *)data; struct wanpipe_opt *po; - for (sk = wanpipe_sklist; sk; sk = sk->next) { + for (sk = wanpipe_sklist; sk; sk = sk->sk_next) { if ((po = wp_sk(sk)) == NULL) continue; @@ -1735,25 +1743,25 @@ switch (msg) { case NETDEV_DOWN: case NETDEV_UNREGISTER: - if (dev->ifindex == sk->bound_dev_if) { + if (dev->ifindex == sk->sk_bound_dev_if) { printk(KERN_INFO "wansock: Device down %s\n",dev->name); - if (sk->zapped){ + if (sk->sk_zapped) { wanpipe_unlink_driver(sk); - sk->err = ENETDOWN; - sk->error_report(sk); + sk->sk_err = ENETDOWN; + sk->sk_error_report(sk); } if (msg == NETDEV_UNREGISTER) { printk(KERN_INFO "wansock: Unregistering Device: %s\n", dev->name); wanpipe_unlink_driver(sk); - sk->bound_dev_if = 0; + sk->sk_bound_dev_if = 0; } } break; case NETDEV_UP: - if (dev->ifindex == sk->bound_dev_if && - po->num && !sk->zapped) { + if (dev->ifindex == sk->sk_bound_dev_if && + po->num && !sk->sk_zapped) { printk(KERN_INFO "wansock: Registering Device: %s\n", dev->name); wanpipe_link_driver(dev,sk); @@ -1781,20 +1789,21 @@ switch(cmd) { case SIOCGSTAMP: - if(sk->stamp.tv_sec==0) + if (!sk->sk_stamp.tv_sec) return -ENOENT; err = -EFAULT; - if (!copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval))) + if (!copy_to_user((void *)arg, &sk->sk_stamp, + sizeof(struct timeval))) err = 0; return err; case SIOC_WANPIPE_CHECK_TX: - return atomic_read(&sk->wmem_alloc); + return atomic_read(&sk->sk_wmem_alloc); case SIOC_WANPIPE_SOCK_STATE: - if (sk->state == WANSOCK_CONNECTED) + if (sk->sk_state == WANSOCK_CONNECTED) return 0; return 1; @@ -1825,7 +1834,7 @@ case SIOC_WANPIPE_SET_NONBLOCK: - if (sk->state != WANSOCK_DISCONNECTED) + if (sk->sk_state != WANSOCK_DISCONNECTED) return -EINVAL; sock->file->f_flags |= O_NONBLOCK; @@ -1876,7 +1885,7 @@ int cnt=0, err=0; wan_debug_t *dbg_data = (wan_debug_t *)arg; - for (sk = wanpipe_sklist; sk; sk = sk->next){ + for (sk = wanpipe_sklist; sk; sk = sk->sk_next) { wanpipe_opt *wp = wp_sk(sk); if (sk == origsk){ @@ -1885,25 +1894,31 @@ if ((err=put_user(1, &dbg_data->debug[cnt].free))) return err; - if ((err=put_user(sk->state, &dbg_data->debug[cnt].sk_state))) + if ((err = put_user(sk->sk_state, + &dbg_data->debug[cnt].state_sk))) return err; - if ((err=put_user(sk->rcvbuf, &dbg_data->debug[cnt].rcvbuf))) + if ((err = put_user(sk->sk_rcvbuf, + &dbg_data->debug[cnt].rcvbuf))) return err; - if ((err=put_user(atomic_read(&sk->rmem_alloc), &dbg_data->debug[cnt].rmem))) + if ((err = put_user(atomic_read(&sk->sk_rmem_alloc), + &dbg_data->debug[cnt].rmem))) return err; - if ((err=put_user(atomic_read(&sk->wmem_alloc), &dbg_data->debug[cnt].wmem))) + if ((err = put_user(atomic_read(&sk->sk_wmem_alloc), + &dbg_data->debug[cnt].wmem))) return err; - if ((err=put_user(sk->sndbuf, &dbg_data->debug[cnt].sndbuf))) + if ((err = put_user(sk->sk_sndbuf, + &dbg_data->debug[cnt].sndbuf))) return err; if ((err=put_user(sk_count, &dbg_data->debug[cnt].sk_count))) return err; if ((err=put_user(wp->poll_cnt, &dbg_data->debug[cnt].poll_cnt))) return err; - if ((err=put_user(sk->bound_dev_if, &dbg_data->debug[cnt].bound))) + if ((err = put_user(sk->sk_bound_dev_if, + &dbg_data->debug[cnt].bound))) return err; - if (sk->bound_dev_if){ - dev = dev_get_by_index(sk->bound_dev_if); + if (sk->sk_bound_dev_if) { + dev = dev_get_by_index(sk->sk_bound_dev_if); if (!dev) continue; @@ -2014,7 +2029,7 @@ if (!wp_sk(sk)->mbox) { void *mbox_ptr; - struct net_device *dev = dev_get_by_index(sk->bound_dev_if); + struct net_device *dev = dev_get_by_index(sk->sk_bound_dev_if); if (!dev) return -ENODEV; @@ -2078,28 +2093,28 @@ ++wp_sk(sk)->poll_cnt; - poll_wait(file, sk->sleep, wait); + poll_wait(file, sk->sk_sleep, wait); mask = 0; /* exceptional events? */ - if (sk->err || !skb_queue_empty(&sk->error_queue)){ + if (sk->sk_err || !skb_queue_empty(&sk->sk_error_queue)) { mask |= POLLPRI; return mask; } - if (sk->shutdown & RCV_SHUTDOWN) + if (sk->sk_shutdown & RCV_SHUTDOWN) mask |= POLLHUP; /* readable? */ - if (!skb_queue_empty(&sk->receive_queue)){ + if (!skb_queue_empty(&sk->sk_receive_queue)) { mask |= POLLIN | POLLRDNORM; } /* connection hasn't started yet */ - if (sk->state == WANSOCK_CONNECTING){ + if (sk->sk_state == WANSOCK_CONNECTING) { return mask; } - if (sk->state == WANSOCK_DISCONNECTED){ + if (sk->sk_state == WANSOCK_DISCONNECTED) { mask = POLLPRI; return mask; } @@ -2120,7 +2135,7 @@ if (sock_writeable(sk)){ mask |= POLLOUT | POLLWRNORM | POLLWRBAND; }else{ - set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); + set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); } return mask; @@ -2142,10 +2157,10 @@ if (wp_sk(sk)->num != htons(X25_PROT)) return -EINVAL; - if (sk->state == WANSOCK_BIND_LISTEN) { + if (sk->sk_state == WANSOCK_BIND_LISTEN) { - sk->max_ack_backlog = backlog; - sk->state = WANSOCK_LISTEN; + sk->sk_max_ack_backlog = backlog; + sk->sk_state = WANSOCK_LISTEN; return 0; }else{ printk(KERN_INFO "wansock: Listening sock was not binded\n"); @@ -2174,7 +2189,7 @@ card->sk=sk; card->func=wanpipe_listen_rcv; - sk->zapped=1; + sk->sk_zapped = 1; return 0; } @@ -2225,7 +2240,7 @@ case SIOC_WANPIPE_ACCEPT_CALL: - if (sk->state != WANSOCK_CONNECTING){ + if (sk->sk_state != WANSOCK_CONNECTING) { err = -EHOSTDOWN; break; } @@ -2238,7 +2253,7 @@ * Do not set the sock lcn number here, since * it is done in wanpipe_listen_rcv(). */ - if (sk->state == WANSOCK_CONNECTED){ + if (sk->sk_state == WANSOCK_CONNECTED) { wp->lcn = ((mbox_cmd_t*)wp->mbox)->cmd.lcn; DBG_PRINTK(KERN_INFO "\nwansock: Accept OK %i\n", wp->lcn); @@ -2254,7 +2269,7 @@ case SIOC_WANPIPE_CLEAR_CALL: - if (sk->state == WANSOCK_DISCONNECTED){ + if (sk->sk_state == WANSOCK_DISCONNECTED) { err = -EINVAL; break; } @@ -2264,7 +2279,8 @@ * if so, check whether user wants to wait until data * is transmitted, or clear a call and drop packets */ - if (atomic_read(&sk->wmem_alloc) || check_driver_busy(sk)){ + if (atomic_read(&sk->sk_wmem_alloc) || + check_driver_busy(sk)) { mbox_cmd_t *mbox = wp->mbox; if (mbox->cmd.qdm & 0x80){ mbox->cmd.result = 0x35; @@ -2273,14 +2289,14 @@ } } - sk->state = WANSOCK_DISCONNECTING; + sk->sk_state = WANSOCK_DISCONNECTING; err = execute_command(sk,X25_CLEAR_CALL,0); if (err < 0) break; err = -ECONNREFUSED; - if (sk->state == WANSOCK_DISCONNECTED){ + if (sk->sk_state == WANSOCK_DISCONNECTED) { DBG_PRINTK(KERN_INFO "\nwansock: CLEAR OK %i\n", wp->lcn); wp->lcn = 0; @@ -2290,7 +2306,7 @@ case SIOC_WANPIPE_RESET_CALL: - if (sk->state != WANSOCK_CONNECTED){ + if (sk->sk_state != WANSOCK_CONNECTED) { err = -EINVAL; break; } @@ -2300,7 +2316,8 @@ * if so, check whether user wants to wait until data * is transmitted, or reset a call and drop packets */ - if (atomic_read(&sk->wmem_alloc) || check_driver_busy(sk)){ + if (atomic_read(&sk->sk_wmem_alloc) || + check_driver_busy(sk)) { mbox_cmd_t *mbox = wp->mbox; if (mbox->cmd.qdm & 0x80){ mbox->cmd.result = 0x35; @@ -2324,7 +2341,7 @@ if (err < 0) break; - if (sk->state == WANSOCK_CONNECTED){ + if (sk->sk_state == WANSOCK_CONNECTED) { wp->lcn = ((mbox_cmd_t*)wp->mbox)->cmd.lcn; @@ -2332,7 +2349,8 @@ wp->lcn); err = 0; - }else if (sk->state == WANSOCK_CONNECTING && (flags & O_NONBLOCK)){ + } else if (sk->sk_state == WANSOCK_CONNECTING && + (flags & O_NONBLOCK)) { wp->lcn = ((mbox_cmd_t*)wp->mbox)->cmd.lcn; DBG_PRINTK(KERN_INFO "\nwansock: Place Call OK: Waiting %i\n", wp->lcn); @@ -2355,7 +2373,7 @@ static int check_driver_busy (struct sock *sk) { - struct net_device *dev = dev_get_by_index(sk->bound_dev_if); + struct net_device *dev = dev_get_by_index(sk->sk_bound_dev_if); wanpipe_common_t *chan; if (!dev) @@ -2394,19 +2412,19 @@ if ((sk = sock->sk) == NULL) return -EINVAL; - if (sk->type != SOCK_RAW) + if (sk->sk_type != SOCK_RAW) return -EOPNOTSUPP; - if (sk->state != WANSOCK_LISTEN) + if (sk->sk_state != WANSOCK_LISTEN) return -EINVAL; if (wp_sk(sk)->num != htons(X25_PROT)) return -EINVAL; - add_wait_queue(sk->sleep,&wait); + add_wait_queue(sk->sk_sleep,&wait); current->state = TASK_INTERRUPTIBLE; for (;;){ - skb = skb_dequeue(&sk->receive_queue); + skb = skb_dequeue(&sk->sk_receive_queue); if (skb){ err=0; break; @@ -2418,7 +2436,7 @@ schedule(); } current->state = TASK_RUNNING; - remove_wait_queue(sk->sleep,&wait); + remove_wait_queue(sk->sk_sleep,&wait); if (err != 0) return err; @@ -2430,18 +2448,18 @@ set_bit(1,&wanpipe_tx_critical); write_lock(&wanpipe_sklist_lock); - newsk->next = wanpipe_sklist; + newsk->sk_next = wanpipe_sklist; wanpipe_sklist = newsk; sock_hold(sk); write_unlock(&wanpipe_sklist_lock); clear_bit(1,&wanpipe_tx_critical); - newsk->pair = NULL; - newsk->socket = newsock; - newsk->sleep = &newsock->wait; + newsk->sk_pair = NULL; + newsk->sk_socket = newsock; + newsk->sk_sleep = &newsock->wait; /* Now attach up the new socket */ - sk->ack_backlog--; + sk->sk_ack_backlog--; newsock->sk = newsk; kfree_skb(skb); @@ -2496,16 +2514,16 @@ if (wp_sk(sk)->num != htons(X25_PROT)) return -EINVAL; - if (sk->state == WANSOCK_CONNECTED) + if (sk->sk_state == WANSOCK_CONNECTED) return -EISCONN; /* No reconnect on a seqpacket socket */ - if (sk->state != WAN_DISCONNECTED){ + if (sk->sk_state != WAN_DISCONNECTED) { printk(KERN_INFO "wansock: Trying to connect on channel NON DISCONNECT\n"); return -ECONNREFUSED; } - sk->state = WANSOCK_DISCONNECTED; - sock->state = SS_UNCONNECTED; + sk->sk_state = WANSOCK_DISCONNECTED; + sock->state = SS_UNCONNECTED; if (addr_len != sizeof(struct wan_sockaddr_ll)) return -EINVAL; @@ -2513,16 +2531,16 @@ if (addr->sll_family != AF_WANPIPE) return -EINVAL; - if ((dev = dev_get_by_index(sk->bound_dev_if)) == NULL) + if ((dev = dev_get_by_index(sk->sk_bound_dev_if)) == NULL) return -ENETUNREACH; dev_put(dev); - if (!sk->zapped) /* Must bind first - autobinding does not work */ + if (!sk->sk_zapped) /* Must bind first - autobinding does not work */ return -EINVAL; sock->state = SS_CONNECTING; - sk->state = WANSOCK_CONNECTING; + sk->sk_state = WANSOCK_CONNECTING; if (!wp_sk(sk)->mbox) { if (wp_sk (sk)->svc) @@ -2536,15 +2554,15 @@ if ((err=wanpipe_exec_cmd(sk, X25_PLACE_CALL,flags)) != 0){ sock->state = SS_UNCONNECTED; - sk->state = WANSOCK_CONNECTED; + sk->sk_state = WANSOCK_CONNECTED; return err; } - if (sk->state != WANSOCK_CONNECTED && (flags & O_NONBLOCK)){ + if (sk->sk_state != WANSOCK_CONNECTED && (flags & O_NONBLOCK)) { return 0; } - if (sk->state != WANSOCK_CONNECTED) { + if (sk->sk_state != WANSOCK_CONNECTED) { sock->state = SS_UNCONNECTED; return -ECONNREFUSED; } diff -Nru a/net/wanrouter/wanproc.c b/net/wanrouter/wanproc.c --- a/net/wanrouter/wanproc.c Mon Jun 9 23:16:11 2003 +++ b/net/wanrouter/wanproc.c Mon Jun 9 23:16:11 2003 @@ -87,7 +87,8 @@ lock_kernel(); if (!l--) return (void *)1; - for (wandev = router_devlist; l-- && wandev; wandev = wandev->next) + for (wandev = wanrouter_router_devlist; l-- && wandev; + wandev = wandev->next) ; return wandev; } @@ -96,7 +97,7 @@ { struct wan_device *wandev = v; (*pos)++; - return (v == (void *)1) ? router_devlist : wandev->next; + return (v == (void *)1) ? wanrouter_router_devlist : wandev->next; } static void r_stop(struct seq_file *m, void *v) diff -Nru a/net/x25/af_x25.c b/net/x25/af_x25.c --- a/net/x25/af_x25.c Mon Jun 9 23:16:19 2003 +++ b/net/x25/af_x25.c Mon Jun 9 23:16:19 2003 @@ -158,15 +158,15 @@ write_lock_bh(&x25_list_lock); if ((s = x25_list) == sk) - x25_list = s->next; - else while (s && s->next) { - if (s->next == sk) { - s->next = sk->next; + x25_list = s->sk_next; + else while (s && s->sk_next) { + if (s->sk_next == sk) { + s->sk_next = sk->sk_next; sock_put(sk); break; } - s = s->next; + s = s->sk_next; } write_unlock_bh(&x25_list_lock); @@ -181,7 +181,7 @@ write_lock_bh(&x25_list_lock); - for (s = x25_list; s; s = s->next) + for (s = x25_list; s; s = s->sk_next) if (x25_sk(s)->neighbour && x25_sk(s)->neighbour->dev == dev) x25_disconnect(s, ENETUNREACH, 0, 0); @@ -230,7 +230,7 @@ static void x25_insert_socket(struct sock *sk) { write_lock_bh(&x25_list_lock); - sk->next = x25_list; + sk->sk_next = x25_list; x25_list = sk; sock_hold(sk); write_unlock_bh(&x25_list_lock); @@ -246,12 +246,12 @@ read_lock_bh(&x25_list_lock); - for (s = x25_list; s; s = s->next) + for (s = x25_list; s; s = s->sk_next) if ((!strcmp(addr->x25_addr, x25_sk(s)->source_addr.x25_addr) || !strcmp(addr->x25_addr, null_x25_address.x25_addr)) && - s->state == TCP_LISTEN) + s->sk_state == TCP_LISTEN) break; if (s) @@ -267,7 +267,7 @@ { struct sock *s; - for (s = x25_list; s; s = s->next) + for (s = x25_list; s; s = s->sk_next) if (x25_sk(s)->lci == lci && x25_sk(s)->neighbour == nb) break; if (s) @@ -339,12 +339,12 @@ x25_remove_socket(sk); x25_clear_queues(sk); /* Flush the queues */ - while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) { + while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { if (skb->sk != sk) { /* A pending connection */ /* * Queue the unaccepted socket for death */ - __set_bit(SOCK_DEAD, &skb->sk->flags); + sock_set_flag(skb->sk, SOCK_DEAD); x25_start_heartbeat(skb->sk); x25_sk(skb->sk)->state = X25_STATE_0; } @@ -352,13 +352,14 @@ kfree_skb(skb); } - if (atomic_read(&sk->wmem_alloc) || atomic_read(&sk->rmem_alloc)) { + if (atomic_read(&sk->sk_wmem_alloc) || + atomic_read(&sk->sk_rmem_alloc)) { /* Defer: outstanding buffers */ - init_timer(&sk->timer); - sk->timer.expires = jiffies + 10 * HZ; - sk->timer.function = x25_destroy_timer; - sk->timer.data = (unsigned long)sk; - add_timer(&sk->timer); + init_timer(&sk->sk_timer); + sk->sk_timer.expires = jiffies + 10 * HZ; + sk->sk_timer.function = x25_destroy_timer; + sk->sk_timer.data = (unsigned long)sk; + add_timer(&sk->sk_timer); } else sk_free(sk); release_sock(sk); @@ -428,10 +429,10 @@ struct sock *sk = sock->sk; int rc = -EOPNOTSUPP; - if (sk->state != TCP_LISTEN) { + if (sk->sk_state != TCP_LISTEN) { memset(&x25_sk(sk)->dest_addr, 0, X25_ADDR_LEN); - sk->max_ack_backlog = backlog; - sk->state = TCP_LISTEN; + sk->sk_max_ack_backlog = backlog; + sk->sk_state = TCP_LISTEN; rc = 0; } @@ -488,8 +489,8 @@ init_timer(&x25->timer); sock->ops = &x25_proto_ops; - sk->protocol = protocol; - sk->backlog_rcv = x25_backlog_rcv; + sk->sk_protocol = protocol; + sk->sk_backlog_rcv = x25_backlog_rcv; x25->t21 = sysctl_x25_call_request_timeout; x25->t22 = sysctl_x25_reset_request_timeout; @@ -513,7 +514,7 @@ struct sock *sk = NULL; struct x25_opt *x25, *ox25; - if (osk->type != SOCK_SEQPACKET) + if (osk->sk_type != SOCK_SEQPACKET) goto out; if ((sk = x25_alloc_socket()) == NULL) @@ -521,17 +522,17 @@ x25 = x25_sk(sk); - sk->type = osk->type; - sk->socket = osk->socket; - sk->priority = osk->priority; - sk->protocol = osk->protocol; - sk->rcvbuf = osk->rcvbuf; - sk->sndbuf = osk->sndbuf; - sk->debug = osk->debug; - sk->state = TCP_ESTABLISHED; - sk->sleep = osk->sleep; - sk->zapped = osk->zapped; - sk->backlog_rcv = osk->backlog_rcv; + sk->sk_type = osk->sk_type; + sk->sk_socket = osk->sk_socket; + sk->sk_priority = osk->sk_priority; + sk->sk_protocol = osk->sk_protocol; + sk->sk_rcvbuf = osk->sk_rcvbuf; + sk->sk_sndbuf = osk->sk_sndbuf; + sk->sk_debug = osk->sk_debug; + sk->sk_state = TCP_ESTABLISHED; + sk->sk_sleep = osk->sk_sleep; + sk->sk_zapped = osk->sk_zapped; + sk->sk_backlog_rcv = osk->sk_backlog_rcv; ox25 = x25_sk(osk); x25->t21 = ox25->t21; @@ -571,16 +572,16 @@ x25_write_internal(sk, X25_CLEAR_REQUEST); x25_start_t23timer(sk); x25->state = X25_STATE_2; - sk->state = TCP_CLOSE; - sk->shutdown |= SEND_SHUTDOWN; - sk->state_change(sk); - __set_bit(SOCK_DEAD, &sk->flags); - __set_bit(SOCK_DESTROY, &sk->flags); + sk->sk_state = TCP_CLOSE; + sk->sk_shutdown |= SEND_SHUTDOWN; + sk->sk_state_change(sk); + sock_set_flag(sk, SOCK_DEAD); + sock_set_flag(sk, SOCK_DESTROY); break; } - sock->sk = NULL; - sk->socket = NULL; /* Not used, but we should do this */ + sock->sk = NULL; + sk->sk_socket = NULL; /* Not used, but we should do this */ out: return 0; } @@ -590,14 +591,14 @@ struct sock *sk = sock->sk; struct sockaddr_x25 *addr = (struct sockaddr_x25 *)uaddr; - if (!sk->zapped || + if (!sk->sk_zapped || addr_len != sizeof(struct sockaddr_x25) || addr->sx25_family != AF_X25) return -EINVAL; x25_sk(sk)->source_addr = addr->sx25_addr; x25_insert_socket(sk); - sk->zapped = 0; + sk->sk_zapped = 0; SOCK_DEBUG(sk, "x25_bind: socket is bound\n"); return 0; @@ -608,7 +609,7 @@ DECLARE_WAITQUEUE(wait, current); int rc; - add_wait_queue_exclusive(sk->sleep, &wait); + add_wait_queue_exclusive(sk->sk_sleep, &wait); for (;;) { __set_current_state(TASK_INTERRUPTIBLE); rc = -ERESTARTSYS; @@ -616,11 +617,11 @@ break; rc = sock_error(sk); if (rc) { - sk->socket->state = SS_UNCONNECTED; + sk->sk_socket->state = SS_UNCONNECTED; break; } rc = 0; - if (sk->state != TCP_ESTABLISHED) { + if (sk->sk_state != TCP_ESTABLISHED) { release_sock(sk); schedule(); lock_sock(sk); @@ -628,7 +629,7 @@ break; } __set_current_state(TASK_RUNNING); - remove_wait_queue(sk->sleep, &wait); + remove_wait_queue(sk->sk_sleep, &wait); return rc; } @@ -642,22 +643,22 @@ int rc = 0; lock_sock(sk); - if (sk->state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) { + if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) { sock->state = SS_CONNECTED; goto out; /* Connect completed during a ERESTARTSYS event */ } rc = -ECONNREFUSED; - if (sk->state == TCP_CLOSE && sock->state == SS_CONNECTING) { + if (sk->sk_state == TCP_CLOSE && sock->state == SS_CONNECTING) { sock->state = SS_UNCONNECTED; goto out; } rc = -EISCONN; /* No reconnect on a seqpacket socket */ - if (sk->state == TCP_ESTABLISHED) + if (sk->sk_state == TCP_ESTABLISHED) goto out; - sk->state = TCP_CLOSE; + sk->sk_state = TCP_CLOSE; sock->state = SS_UNCONNECTED; rc = -EINVAL; @@ -681,7 +682,7 @@ goto out_put_neigh; rc = -EINVAL; - if (sk->zapped) /* Must bind first - autobinding does not work */ + if (sk->sk_zapped) /* Must bind first - autobinding does not work */ goto out_put_neigh; if (!strcmp(x25->source_addr.x25_addr, null_x25_address.x25_addr)) @@ -691,7 +692,7 @@ /* Move to connecting socket, start sending Connect Requests */ sock->state = SS_CONNECTING; - sk->state = TCP_SYN_SENT; + sk->sk_state = TCP_SYN_SENT; x25->state = X25_STATE_1; @@ -702,7 +703,7 @@ /* Now the loop */ rc = -EINPROGRESS; - if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) + if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) goto out_put_neigh; rc = x25_wait_for_connection_establishment(sk); @@ -726,10 +727,10 @@ DECLARE_WAITQUEUE(wait, current); int rc = 0; - add_wait_queue_exclusive(sk->sleep, &wait); + add_wait_queue_exclusive(sk->sk_sleep, &wait); for (;;) { __set_current_state(TASK_INTERRUPTIBLE); - if (sk->shutdown & RCV_SHUTDOWN) + if (sk->sk_shutdown & RCV_SHUTDOWN) break; rc = -ERESTARTSYS; if (signal_pending(current)) @@ -738,7 +739,7 @@ if (!timeout) break; rc = 0; - if (skb_queue_empty(&sk->receive_queue)) { + if (skb_queue_empty(&sk->sk_receive_queue)) { release_sock(sk); timeout = schedule_timeout(timeout); lock_sock(sk); @@ -746,7 +747,7 @@ break; } __set_current_state(TASK_RUNNING); - remove_wait_queue(sk->sleep, &wait); + remove_wait_queue(sk->sk_sleep, &wait); return rc; } @@ -757,29 +758,29 @@ struct sk_buff *skb; int rc = -EINVAL; - if (!sk || sk->state != TCP_LISTEN) + if (!sk || sk->sk_state != TCP_LISTEN) goto out; rc = -EOPNOTSUPP; - if (sk->type != SOCK_SEQPACKET) + if (sk->sk_type != SOCK_SEQPACKET) goto out; - rc = x25_wait_for_data(sk, sk->rcvtimeo); + rc = x25_wait_for_data(sk, sk->sk_rcvtimeo); if (rc) goto out; - skb = skb_dequeue(&sk->receive_queue); + skb = skb_dequeue(&sk->sk_receive_queue); rc = -EINVAL; if (!skb->sk) goto out; - newsk = skb->sk; - newsk->pair = NULL; - newsk->socket = newsock; - newsk->sleep = &newsock->wait; + newsk = skb->sk; + newsk->sk_pair = NULL; + newsk->sk_socket = newsock; + newsk->sk_sleep = &newsock->wait; /* Now attach up the new socket */ skb->sk = NULL; kfree_skb(skb); - sk->ack_backlog--; + sk->sk_ack_backlog--; newsock->sk = newsk; newsock->state = SS_CONNECTED; rc = 0; @@ -795,7 +796,7 @@ struct x25_opt *x25 = x25_sk(sk); if (peer) { - if (sk->state != TCP_ESTABLISHED) + if (sk->sk_state != TCP_ESTABLISHED) return -ENOTCONN; sx25->sx25_addr = x25->dest_addr; } else @@ -836,7 +837,7 @@ /* * We can't accept the Call Request. */ - if (!sk || sk->ack_backlog == sk->max_ack_backlog) + if (!sk || sk->sk_ack_backlog == sk->sk_max_ack_backlog) goto out_clear_request; /* @@ -865,7 +866,7 @@ skb_pull(skb, len); skb->sk = make; - make->state = TCP_ESTABLISHED; + make->sk_state = TCP_ESTABLISHED; makex25 = x25_sk(make); makex25->lci = lci; @@ -887,17 +888,17 @@ makex25->state = X25_STATE_3; - sk->ack_backlog++; - make->pair = sk; + sk->sk_ack_backlog++; + make->sk_pair = sk; x25_insert_socket(make); - skb_queue_head(&sk->receive_queue, skb); + skb_queue_head(&sk->sk_receive_queue, skb); x25_start_heartbeat(make); - if (!test_bit(SOCK_DEAD, &sk->flags)) - sk->data_ready(sk, skb->len); + if (!sock_flag(sk, SOCK_DEAD)) + sk->sk_data_ready(sk, skb->len); rc = 1; sock_put(sk); out: @@ -930,11 +931,11 @@ goto out; rc = -EADDRNOTAVAIL; - if (sk->zapped) + if (sk->sk_zapped) goto out; rc = -EPIPE; - if (sk->shutdown & SEND_SHUTDOWN) { + if (sk->sk_shutdown & SEND_SHUTDOWN) { send_sig(SIGPIPE, current, 0); goto out; } @@ -961,7 +962,7 @@ * to SIGPIPE, EPIPE; */ rc = -ENOTCONN; - if (sk->state != TCP_ESTABLISHED) + if (sk->sk_state != TCP_ESTABLISHED) goto out; sx25.sx25_family = AF_X25; @@ -1046,7 +1047,7 @@ SOCK_DEBUG(sk, "x25_sendmsg: Transmitting buffer\n"); rc = -ENOTCONN; - if (sk->state != TCP_ESTABLISHED) + if (sk->sk_state != TCP_ESTABLISHED) goto out_kfree_skb; if (msg->msg_flags & MSG_OOB) @@ -1101,13 +1102,13 @@ * This works for seqpacket too. The receiver has ordered the queue for * us! We do one quick check first though */ - if (sk->state != TCP_ESTABLISHED) + if (sk->sk_state != TCP_ESTABLISHED) goto out; if (flags & MSG_OOB) { rc = -EINVAL; - if (test_bit(SOCK_URGINLINE, &sk->flags) || - !skb_peek(&x25->interrupt_in_queue)) + if (sock_flag(sk, SOCK_URGINLINE) || + !skb_peek(&x25->interrupt_in_queue)) goto out; skb = skb_dequeue(&x25->interrupt_in_queue); @@ -1183,8 +1184,8 @@ switch (cmd) { case TIOCOUTQ: { - int amount; - amount = sk->sndbuf - atomic_read(&sk->wmem_alloc); + int amount = sk->sk_sndbuf - + atomic_read(&sk->sk_wmem_alloc); if (amount < 0) amount = 0; rc = put_user(amount, (unsigned int *)arg); @@ -1198,7 +1199,7 @@ * These two are safe on a single CPU system as * only user tasks fiddle here */ - if ((skb = skb_peek(&sk->receive_queue)) != NULL) + if ((skb = skb_peek(&sk->sk_receive_queue)) != NULL) amount = skb->len; rc = put_user(amount, (unsigned int *)arg); break; @@ -1207,9 +1208,9 @@ case SIOCGSTAMP: if (sk) { rc = -ENOENT; - if (!sk->stamp.tv_sec) + if (!sk->sk_stamp.tv_sec) break; - rc = copy_to_user((void *)arg, &sk->stamp, + rc = copy_to_user((void *)arg, &sk->sk_stamp, sizeof(struct timeval)) ? -EFAULT : 0; } rc = -EINVAL; @@ -1256,7 +1257,8 @@ sizeof(facilities))) break; rc = -EINVAL; - if (sk->state != TCP_LISTEN && sk->state != TCP_CLOSE) + if (sk->sk_state != TCP_LISTEN && + sk->sk_state != TCP_CLOSE) break; if (facilities.pacsize_in < X25_PS16 || facilities.pacsize_in > X25_PS4096) @@ -1360,7 +1362,7 @@ write_lock_bh(&x25_list_lock); - for (s = x25_list; s; s = s->next) + for (s = x25_list; s; s = s->sk_next) if (x25_sk(s)->neighbour == nb) x25_disconnect(s, ENETUNREACH, 0, 0); diff -Nru a/net/x25/x25_in.c b/net/x25/x25_in.c --- a/net/x25/x25_in.c Mon Jun 9 23:16:19 2003 +++ b/net/x25/x25_in.c Mon Jun 9 23:16:19 2003 @@ -85,9 +85,9 @@ } skb_set_owner_r(skbn, sk); - skb_queue_tail(&sk->receive_queue, skbn); - if (!test_bit(SOCK_DEAD, &sk->flags)) - sk->data_ready(sk, skbn->len); + skb_queue_tail(&sk->sk_receive_queue, skbn); + if (!sock_flag(sk, SOCK_DEAD)) + sk->sk_data_ready(sk, skbn->len); return 0; } @@ -112,7 +112,7 @@ x25->vr = 0; x25->vl = 0; x25->state = X25_STATE_3; - sk->state = TCP_ESTABLISHED; + sk->sk_state = TCP_ESTABLISHED; /* * Parse the data in the frame. */ @@ -129,8 +129,8 @@ skb->len); x25->calluserdata.cudlength = skb->len; } - if (!test_bit(SOCK_DEAD, &sk->flags)) - sk->state_change(sk); + if (!sock_flag(sk, SOCK_DEAD)) + sk->sk_state_change(sk); break; } case X25_CLEAR_REQUEST: @@ -255,7 +255,8 @@ x25->state = X25_STATE_4; break; } - if (atomic_read(&sk->rmem_alloc) > (sk->rcvbuf / 2)) + if (atomic_read(&sk->sk_rmem_alloc) > + (sk->sk_rcvbuf / 2)) x25->condition |= X25_COND_OWN_RX_BUSY; } /* @@ -277,9 +278,9 @@ break; case X25_INTERRUPT: - if (test_bit(SOCK_URGINLINE, &sk->flags)) { - queued = (sock_queue_rcv_skb(sk, skb) == 0); - } else { + if (sock_flag(sk, SOCK_URGINLINE)) + queued = !sock_queue_rcv_skb(sk, skb); + else { skb_set_owner_r(skb, sk); skb_queue_tail(&x25->interrupt_in_queue, skb); queued = 1; diff -Nru a/net/x25/x25_out.c b/net/x25/x25_out.c --- a/net/x25/x25_out.c Mon Jun 9 23:16:07 2003 +++ b/net/x25/x25_out.c Mon Jun 9 23:16:07 2003 @@ -111,13 +111,13 @@ skbn->data[2] |= X25_STD_M_BIT; } - skb_queue_tail(&sk->write_queue, skbn); + skb_queue_tail(&sk->sk_write_queue, skbn); sent += len; } kfree_skb(skb); } else { - skb_queue_tail(&sk->write_queue, skb); + skb_queue_tail(&sk->sk_write_queue, skb); sent = skb->len - header_len; } return sent; @@ -169,7 +169,7 @@ if (x25->condition & X25_COND_PEER_RX_BUSY) return; - if (skb_peek(&sk->write_queue) == NULL) + if (!skb_peek(&sk->sk_write_queue)) return; modulus = x25->neighbour->extended ? X25_EMODULUS : X25_SMODULUS; @@ -187,11 +187,11 @@ * the window is full. */ - skb = skb_dequeue(&sk->write_queue); + skb = skb_dequeue(&sk->sk_write_queue); do { if ((skbn = skb_clone(skb, GFP_ATOMIC)) == NULL) { - skb_queue_head(&sk->write_queue, skb); + skb_queue_head(&sk->sk_write_queue, skb); break; } @@ -209,7 +209,8 @@ */ skb_queue_tail(&x25->ack_queue, skb); - } while (x25->vs != end && (skb = skb_dequeue(&sk->write_queue)) != NULL); + } while (x25->vs != end && + (skb = skb_dequeue(&sk->sk_write_queue)) != NULL); x25->vl = x25->vr; x25->condition &= ~X25_COND_ACK_PENDING; diff -Nru a/net/x25/x25_proc.c b/net/x25/x25_proc.c --- a/net/x25/x25_proc.c Mon Jun 9 23:16:08 2003 +++ b/net/x25/x25_proc.c Mon Jun 9 23:16:08 2003 @@ -94,7 +94,7 @@ { struct sock *s; - for (s = x25_list; pos && s; s = s->next) + for (s = x25_list; pos && s; s = s->sk_next) --pos; return s; @@ -120,7 +120,7 @@ goto out; } s = v; - s = s->next; + s = s->sk_next; out: return s; } @@ -158,8 +158,9 @@ devname, x25->lci & 0x0FFF, x25->state, x25->vs, x25->vr, x25->va, x25_display_timer(s) / HZ, x25->t2 / HZ, x25->t21 / HZ, x25->t22 / HZ, x25->t23 / HZ, - atomic_read(&s->wmem_alloc), atomic_read(&s->rmem_alloc), - s->socket ? SOCK_INODE(s->socket)->i_ino : 0L); + atomic_read(&s->sk_wmem_alloc), + atomic_read(&s->sk_rmem_alloc), + s->sk_socket ? SOCK_INODE(s->sk_socket)->i_ino : 0L); out: return 0; } diff -Nru a/net/x25/x25_subr.c b/net/x25/x25_subr.c --- a/net/x25/x25_subr.c Mon Jun 9 23:16:08 2003 +++ b/net/x25/x25_subr.c Mon Jun 9 23:16:08 2003 @@ -49,7 +49,7 @@ { struct x25_opt *x25 = x25_sk(sk); - skb_queue_purge(&sk->write_queue); + skb_queue_purge(&sk->sk_write_queue); skb_queue_purge(&x25->ack_queue); skb_queue_purge(&x25->interrupt_in_queue); skb_queue_purge(&x25->interrupt_out_queue); @@ -90,7 +90,7 @@ */ while ((skb = skb_dequeue(&x25_sk(sk)->ack_queue)) != NULL) { if (!skb_prev) - skb_queue_head(&sk->write_queue, skb); + skb_queue_head(&sk->sk_write_queue, skb); else skb_append(skb_prev, skb); skb_prev = skb; @@ -340,14 +340,14 @@ x25->causediag.cause = cause; x25->causediag.diagnostic = diagnostic; - sk->state = TCP_CLOSE; - sk->err = reason; - sk->shutdown |= SEND_SHUTDOWN; - - if (!test_bit(SOCK_DEAD, &sk->flags)) - sk->state_change(sk); - - __set_bit(SOCK_DEAD, &sk->flags); + sk->sk_state = TCP_CLOSE; + sk->sk_err = reason; + sk->sk_shutdown |= SEND_SHUTDOWN; + + if (!sock_flag(sk, SOCK_DEAD)) { + sk->sk_state_change(sk); + sock_set_flag(sk, SOCK_DEAD); + } } /* @@ -358,7 +358,7 @@ { struct x25_opt *x25 = x25_sk(sk); - if (atomic_read(&sk->rmem_alloc) < (sk->rcvbuf / 2) && + if (atomic_read(&sk->sk_rmem_alloc) < (sk->sk_rcvbuf / 2) && (x25->condition & X25_COND_OWN_RX_BUSY)) { x25->condition &= ~X25_COND_OWN_RX_BUSY; x25->condition &= ~X25_COND_ACK_PENDING; diff -Nru a/net/x25/x25_timer.c b/net/x25/x25_timer.c --- a/net/x25/x25_timer.c Mon Jun 9 23:16:07 2003 +++ b/net/x25/x25_timer.c Mon Jun 9 23:16:07 2003 @@ -45,18 +45,18 @@ void x25_start_heartbeat(struct sock *sk) { - del_timer(&sk->timer); + del_timer(&sk->sk_timer); - sk->timer.data = (unsigned long)sk; - sk->timer.function = &x25_heartbeat_expiry; - sk->timer.expires = jiffies + 5 * HZ; + sk->sk_timer.data = (unsigned long)sk; + sk->sk_timer.function = &x25_heartbeat_expiry; + sk->sk_timer.expires = jiffies + 5 * HZ; - add_timer(&sk->timer); + add_timer(&sk->sk_timer); } void x25_stop_heartbeat(struct sock *sk) { - del_timer(&sk->timer); + del_timer(&sk->sk_timer); } void x25_start_t2timer(struct sock *sk) @@ -137,9 +137,14 @@ switch (x25_sk(sk)->state) { case X25_STATE_0: - /* Magic here: If we listen() and a new link dies before it - is accepted() it isn't 'dead' so doesn't get removed. */ - if (test_bit(SOCK_DESTROY, &sk->flags) || (sk->state == TCP_LISTEN && test_bit(SOCK_DEAD, &sk->flags))) { + /* + * Magic here: If we listen() and a new link dies + * before it is accepted() it isn't 'dead' so doesn't + * get removed. + */ + if (sock_flag(sk, SOCK_DESTROY) || + (sk->sk_state == TCP_LISTEN && + sock_flag(sk, SOCK_DEAD))) { x25_destroy_socket(sk); goto unlock; } diff -Nru a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c --- a/net/xfrm/xfrm_policy.c Mon Jun 9 23:16:12 2003 +++ b/net/xfrm/xfrm_policy.c Mon Jun 9 23:16:12 2003 @@ -14,6 +14,11 @@ */ #include <linux/config.h> +#include <linux/slab.h> +#include <linux/kmod.h> +#include <linux/list.h> +#include <linux/spinlock.h> +#include <linux/workqueue.h> #include <net/xfrm.h> #include <net/ip.h> @@ -28,6 +33,11 @@ kmem_cache_t *xfrm_dst_cache; +static struct work_struct xfrm_policy_gc_work; +static struct list_head xfrm_policy_gc_list = + LIST_HEAD_INIT(xfrm_policy_gc_list); +static spinlock_t xfrm_policy_gc_lock = SPIN_LOCK_UNLOCKED; + int xfrm_register_type(struct xfrm_type *type, unsigned short family) { struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); @@ -73,16 +83,25 @@ struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); struct xfrm_type_map *typemap; struct xfrm_type *type; + int modload_attempted = 0; if (unlikely(afinfo == NULL)) return NULL; typemap = afinfo->type_map; +retry: read_lock(&typemap->lock); type = typemap->map[proto]; if (unlikely(type && !try_module_get(type->owner))) type = NULL; read_unlock(&typemap->lock); + if (!type && !modload_attempted) { + request_module("xfrm-type-%d-%d", + (int) family, (int) proto); + modload_attempted = 1; + goto retry; + } + xfrm_policy_put_afinfo(afinfo); return type; } @@ -151,7 +170,6 @@ xp = xfrm_policy_byid(0, index, 1); if (xp) { xfrm_policy_kill(xp); - xfrm_pol_put(xp); } } @@ -193,27 +211,56 @@ kfree(policy); } +static void xfrm_policy_gc_kill(struct xfrm_policy *policy) +{ + struct dst_entry *dst; + + while ((dst = policy->bundles) != NULL) { + policy->bundles = dst->next; + dst_free(dst); + } + + if (del_timer(&policy->timer)) + atomic_dec(&policy->refcnt); + + if (atomic_read(&policy->refcnt) > 1) + flow_cache_flush(policy); + + xfrm_pol_put(policy); +} + +static void xfrm_policy_gc_task(void *data) +{ + struct xfrm_policy *policy; + struct list_head *entry, *tmp; + struct list_head gc_list = LIST_HEAD_INIT(gc_list); + + spin_lock_bh(&xfrm_policy_gc_lock); + list_splice_init(&xfrm_policy_gc_list, &gc_list); + spin_unlock_bh(&xfrm_policy_gc_lock); + + list_for_each_safe(entry, tmp, &gc_list) { + policy = list_entry(entry, struct xfrm_policy, list); + xfrm_policy_gc_kill(policy); + } +} + /* Rule must be locked. Release descentant resources, announce * entry dead. The rule must be unlinked from lists to the moment. */ void xfrm_policy_kill(struct xfrm_policy *policy) { - struct dst_entry *dst; - write_lock_bh(&policy->lock); if (policy->dead) goto out; policy->dead = 1; - while ((dst = policy->bundles) != NULL) { - policy->bundles = dst->next; - dst_free(dst); - } - - if (del_timer(&policy->timer)) - atomic_dec(&policy->refcnt); + spin_lock(&xfrm_policy_gc_lock); + list_add(&policy->list, &xfrm_policy_gc_list); + spin_unlock(&xfrm_policy_gc_lock); + schedule_work(&xfrm_policy_gc_work); out: write_unlock_bh(&policy->lock); @@ -244,22 +291,34 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) { struct xfrm_policy *pol, **p; + struct xfrm_policy *delpol = NULL; + struct xfrm_policy **newpos = NULL; write_lock_bh(&xfrm_policy_lock); for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL; p = &pol->next) { - if (memcmp(&policy->selector, &pol->selector, sizeof(pol->selector)) == 0) { + if (!delpol && memcmp(&policy->selector, &pol->selector, sizeof(pol->selector)) == 0) { if (excl) { write_unlock_bh(&xfrm_policy_lock); return -EEXIST; } + *p = pol->next; + delpol = pol; + if (policy->priority > pol->priority) + continue; + } else if (policy->priority >= pol->priority) + continue; + if (!newpos) + newpos = p; + if (delpol) break; - } } + if (newpos) + p = newpos; xfrm_pol_hold(policy); - policy->next = pol ? pol->next : NULL; + policy->next = *p; *p = policy; atomic_inc(&flow_cache_genid); - policy->index = pol ? pol->index : xfrm_gen_index(dir); + policy->index = delpol ? delpol->index : xfrm_gen_index(dir); policy->curlft.add_time = (unsigned long)xtime.tv_sec; policy->curlft.use_time = 0; if (policy->lft.hard_add_expires_seconds && @@ -267,27 +326,31 @@ xfrm_pol_hold(policy); write_unlock_bh(&xfrm_policy_lock); - if (pol) { - atomic_dec(&pol->refcnt); - xfrm_policy_kill(pol); - xfrm_pol_put(pol); + if (delpol) { + xfrm_policy_kill(delpol); } return 0; } -struct xfrm_policy *xfrm_policy_delete(int dir, struct xfrm_selector *sel) +struct xfrm_policy *xfrm_policy_bysel(int dir, struct xfrm_selector *sel, + int delete) { struct xfrm_policy *pol, **p; write_lock_bh(&xfrm_policy_lock); for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL; p = &pol->next) { if (memcmp(sel, &pol->selector, sizeof(*sel)) == 0) { - *p = pol->next; + if (delete) + *p = pol->next; break; } } - if (pol) - atomic_inc(&flow_cache_genid); + if (pol) { + if (delete) + atomic_inc(&flow_cache_genid); + else + xfrm_pol_hold(pol); + } write_unlock_bh(&xfrm_policy_lock); return pol; } @@ -326,7 +389,6 @@ write_unlock_bh(&xfrm_policy_lock); xfrm_policy_kill(xp); - xfrm_pol_put(xp); write_lock_bh(&xfrm_policy_lock); } @@ -370,8 +432,8 @@ /* Find policy to apply to this flow. */ -void xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir, - void **objp, atomic_t **obj_refp) +static void xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir, + void **objp, atomic_t **obj_refp) { struct xfrm_policy *pol; @@ -399,10 +461,9 @@ struct xfrm_policy *pol; read_lock_bh(&xfrm_policy_lock); - if ((pol = sk->policy[dir]) != NULL) { - int match; - - match = xfrm_selector_match(&pol->selector, fl, sk->family); + if ((pol = sk->sk_policy[dir]) != NULL) { + int match = xfrm_selector_match(&pol->selector, fl, + sk->sk_family); if (match) xfrm_pol_hold(pol); else @@ -438,8 +499,8 @@ struct xfrm_policy *old_pol; write_lock_bh(&xfrm_policy_lock); - old_pol = sk->policy[dir]; - sk->policy[dir] = pol; + old_pol = sk->sk_policy[dir]; + sk->sk_policy[dir] = pol; if (pol) { pol->curlft.add_time = (unsigned long)xtime.tv_sec; pol->index = xfrm_gen_index(XFRM_POLICY_MAX+dir); @@ -451,7 +512,6 @@ if (old_pol) { xfrm_policy_kill(old_pol); - xfrm_pol_put(old_pol); } return 0; } @@ -479,14 +539,13 @@ int __xfrm_sk_clone_policy(struct sock *sk) { - struct xfrm_policy *p0, *p1; - p0 = sk->policy[0]; - p1 = sk->policy[1]; - sk->policy[0] = NULL; - sk->policy[1] = NULL; - if (p0 && (sk->policy[0] = clone_policy(p0, 0)) == NULL) + struct xfrm_policy *p0 = sk->sk_policy[0], + *p1 = sk->sk_policy[1]; + + sk->sk_policy[0] = sk->sk_policy[1] = NULL; + if (p0 && (sk->sk_policy[0] = clone_policy(p0, 0)) == NULL) return -ENOMEM; - if (p1 && (sk->policy[1] = clone_policy(p1, 1)) == NULL) + if (p1 && (sk->sk_policy[1] = clone_policy(p1, 1)) == NULL) return -ENOMEM; return 0; } @@ -498,7 +557,6 @@ write_unlock_bh(&xfrm_policy_lock); xfrm_policy_kill(pol); - xfrm_pol_put(pol); } /* Resolve list of templates for the flow, given policy. */ @@ -632,7 +690,7 @@ restart: genid = atomic_read(&flow_cache_genid); policy = NULL; - if (sk && sk->policy[1]) + if (sk && sk->sk_policy[1]) policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl); if (!policy) { @@ -820,7 +878,7 @@ } pol = NULL; - if (sk && sk->policy[dir]) + if (sk && sk->sk_policy[dir]) pol = xfrm_sk_policy_lookup(sk, dir, &fl); if (!pol) @@ -1117,6 +1175,8 @@ NULL, NULL); if (!xfrm_dst_cache) panic("XFRM: failed to allocate xfrm_dst_cache\n"); + + INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task, NULL); } void __init xfrm_init(void) diff -Nru a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c --- a/net/xfrm/xfrm_state.c Mon Jun 9 23:16:15 2003 +++ b/net/xfrm/xfrm_state.c Mon Jun 9 23:16:15 2003 @@ -112,9 +112,9 @@ if (tmo < next) next = tmo; } - if (x->lft.hard_use_expires_seconds && x->curlft.use_time) { + if (x->lft.hard_use_expires_seconds) { long tmo = x->lft.hard_use_expires_seconds + - x->curlft.use_time - now; + (x->curlft.use_time ? : now) - now; if (tmo <= 0) goto expired; if (tmo < next) @@ -130,9 +130,9 @@ else if (tmo < next) next = tmo; } - if (x->lft.soft_use_expires_seconds && x->curlft.use_time) { + if (x->lft.soft_use_expires_seconds) { long tmo = x->lft.soft_use_expires_seconds + - x->curlft.use_time - now; + (x->curlft.use_time ? : now) - now; if (tmo <= 0) warn = 1; else if (tmo < next) @@ -701,7 +701,8 @@ err = -EINVAL; read_lock(&xfrm_km_lock); list_for_each_entry(km, &xfrm_km_list, list) { - pol = km->compile_policy(sk->family, optname, data, optlen, &err); + pol = km->compile_policy(sk->sk_family, optname, data, + optlen, &err); if (err >= 0) break; } diff -Nru a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c --- a/net/xfrm/xfrm_user.c Mon Jun 9 23:16:14 2003 +++ b/net/xfrm/xfrm_user.c Mon Jun 9 23:16:14 2003 @@ -260,7 +260,7 @@ if (!x) return err; - x1 = xfrm_state_lookup(&x->props.saddr, x->id.spi, x->id.proto, x->props.family); + x1 = xfrm_state_lookup(&x->id.daddr, x->id.spi, x->id.proto, x->props.family); if (x1) { xfrm_state_put(x); xfrm_state_put(x1); @@ -277,7 +277,7 @@ struct xfrm_state *x; struct xfrm_usersa_id *p = NLMSG_DATA(nlh); - x = xfrm_state_lookup(&p->saddr, p->spi, p->proto, p->family); + x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family); if (x == NULL) return -ESRCH; @@ -403,7 +403,7 @@ struct sk_buff *resp_skb; int err; - x = xfrm_state_lookup(&p->saddr, p->spi, p->proto, p->family); + x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family); err = -ESRCH; if (x == NULL) goto out_noput; @@ -656,26 +656,6 @@ return 0; } -static int xfrm_del_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma) -{ - struct xfrm_policy *xp; - struct xfrm_userpolicy_id *p; - int err; - - p = NLMSG_DATA(nlh); - - err = verify_policy_dir(p->dir); - if (err) - return err; - - xp = xfrm_policy_delete(p->dir, &p->sel); - if (xp == NULL) - return -ENOENT; - xfrm_policy_kill(xp); - xfrm_pol_put(xp); - return 0; -} - static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr) { struct xfrm_dump_info *sp = ptr; @@ -774,24 +754,39 @@ { struct xfrm_policy *xp; struct xfrm_userpolicy_id *p; - struct sk_buff *resp_skb; int err; + int delete; p = NLMSG_DATA(nlh); - xp = xfrm_policy_byid(p->dir, p->index, 0); + delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY; + + err = verify_policy_dir(p->dir); + if (err) + return err; + + if (p->index) + xp = xfrm_policy_byid(p->dir, p->index, delete); + else + xp = xfrm_policy_bysel(p->dir, &p->sel, delete); if (xp == NULL) return -ENOENT; - resp_skb = xfrm_policy_netlink(skb, xp, p->dir, nlh->nlmsg_seq); - if (IS_ERR(resp_skb)) { - err = PTR_ERR(resp_skb); - } else { - err = netlink_unicast(xfrm_nl, resp_skb, - NETLINK_CB(skb).pid, MSG_DONTWAIT); + if (delete) + xfrm_policy_kill(xp); + else { + struct sk_buff *resp_skb; + + resp_skb = xfrm_policy_netlink(skb, xp, p->dir, nlh->nlmsg_seq); + if (IS_ERR(resp_skb)) { + err = PTR_ERR(resp_skb); + } else { + err = netlink_unicast(xfrm_nl, resp_skb, + NETLINK_CB(skb).pid, + MSG_DONTWAIT); + } + xfrm_pol_put(xp); } - xfrm_pol_put(xp); - return err; } @@ -819,7 +814,7 @@ .dump = xfrm_dump_sa, }, { .doit = xfrm_add_policy }, - { .doit = xfrm_del_policy }, + { .doit = xfrm_get_policy }, { .doit = xfrm_get_policy, .dump = xfrm_dump_policy, @@ -946,10 +941,11 @@ down(&xfrm_cfg_sem); - while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) { + while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { if (xfrm_user_rcv_skb(skb)) { if (skb->len) - skb_queue_head(&sk->receive_queue, skb); + skb_queue_head(&sk->sk_receive_queue, + skb); else kfree_skb(skb); break; @@ -959,7 +955,7 @@ up(&xfrm_cfg_sem); - } while (xfrm_nl && xfrm_nl->receive_queue.qlen); + } while (xfrm_nl && xfrm_nl->sk_receive_queue.qlen); } static int build_expire(struct sk_buff *skb, struct xfrm_state *x, int hard) @@ -1126,7 +1122,7 @@ static void __exit xfrm_user_exit(void) { xfrm_unregister_km(&netlink_mgr); - sock_release(xfrm_nl->socket); + sock_release(xfrm_nl->sk_socket); } module_init(xfrm_user_init); diff -Nru a/scripts/Makefile.build b/scripts/Makefile.build --- a/scripts/Makefile.build Mon Jun 9 23:16:17 2003 +++ b/scripts/Makefile.build Mon Jun 9 23:16:17 2003 @@ -32,9 +32,7 @@ endif ifdef L_TARGET -ifneq ($(L_TARGET),lib.a) -$(warning kbuild: $(obj)/Makefile - L_TARGET := $(L_TARGET) target shall be renamed to lib.a. Please fix!) -endif +$(error kbuild: $(obj)/Makefile - Use of L_TARGET is replaced by lib-y in 2.5. Please fix!) endif ifdef list-multi @@ -47,21 +45,19 @@ # =========================================================================== -# If a Makefile does not define a L_TARGET, link an object called "built-in.o" - -ifdef L_TARGET -L_TARGET := $(obj)/$(L_TARGET) -else -ifneq ($(strip $(obj-y) $(obj-m) $(obj-n) $(obj-)),) -O_TARGET := $(obj)/built-in.o +ifneq ($(strip $(lib-y) $(lib-m) $(lib-n) $(lib-)),) +lib-target := $(obj)/lib.a endif + +ifneq ($(strip $(obj-y) $(obj-m) $(obj-n) $(obj-) $(lib-target)),) +builtin-target := $(obj)/built-in.o endif # We keep a list of all modules in $(MODVERDIR) touch-module = @echo $(@:.o=.ko) > $(MODVERDIR)/$(@F:.o=.mod) -__build: $(if $(KBUILD_BUILTIN),$(O_TARGET) $(L_TARGET) $(extra-y)) \ +__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \ $(if $(KBUILD_MODULES),$(obj-m)) \ $(subdir-ym) $(always) @: @@ -71,55 +67,7 @@ quiet_cmd_checksrc = CHECK $< cmd_checksrc = $(CHECK) $(c_flags) $< ; endif - -# Module versioning -# --------------------------------------------------------------------------- - -ifdef CONFIG_MODVERSIONS - -# $(call if_changed_rule,vcc_o_c) does essentially the same as the -# normal $(call if_changed_dep,cc_o_c), i.e. compile an object file -# from a C file, keeping track of the command line and dependencies. -# -# However, actually it does: -# o compile a .tmp_<file>.o from <file>.c -# o if .tmp_<file>.o doesn't contain a __ksymtab version, i.e. does -# not export symbols, we just rename .tmp_<file>.o to <file>.o and -# are done. -# o otherwise, we calculate symbol versions using the good old -# genksyms on the preprocessed source and postprocess them in a way -# that they are usable as a linker script -# o generate <file>.o from .tmp_<file>.o using the linker to -# replace the unresolved symbols __crc_exported_symbol with -# the actual value of the checksum generated by genksyms - -quiet_cmd_vcc_o_c = CC $(quiet_modtag) $@ -cmd_vcc_o_c = $(CC) $(c_flags) -c -o $(@D)/.tmp_$(@F) $< - -define rule_vcc_o_c - $(if $($(quiet)cmd_checksrc),echo ' $($(quiet)cmd_checksrc)';) \ - $(cmd_checksrc) \ - $(if $($(quiet)cmd_vcc_o_c),echo ' $($(quiet)cmd_vcc_o_c)';) \ - $(cmd_vcc_o_c); \ - \ - if ! $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then \ - mv $(@D)/.tmp_$(@F) $@; \ - else \ - $(CPP) -D__GENKSYMS__ $(c_flags) $< \ - | $(GENKSYMS) \ - > $(@D)/.tmp_$(@F:.o=.ver); \ - \ - $(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) \ - -T $(@D)/.tmp_$(@F:.o=.ver); \ - rm -f $(@D)/.tmp_$(@F) $(@D)/.tmp_$(@F:.o=.ver); \ - fi; - \ - scripts/fixdep $(depfile) $@ '$(cmd_vcc_o_c)' > $(@D)/.$(@F).tmp; \ - rm -f $(depfile); \ - mv -f $(@D)/.$(@F).tmp $(@D)/.$(@F).cmd -endef -endif # Compile C sources (.c) # --------------------------------------------------------------------------- @@ -164,35 +112,63 @@ %.i: %.c FORCE $(call if_changed_dep,cc_i_c) +# C (.c) files +# The C file is compiled and updated dependency information is generated. +# (See cmd_cc_o_c + relevant part of rule_cc_o_c) + quiet_cmd_cc_o_c = CC $(quiet_modtag) $@ -cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< + +ifndef CONFIG_MODVERSIONS +cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< + +else +# When module versioning is enabled the following steps are executed: +# o compile a .tmp_<file>.o from <file>.c +# o if .tmp_<file>.o doesn't contain a __ksymtab version, i.e. does +# not export symbols, we just rename .tmp_<file>.o to <file>.o and +# are done. +# o otherwise, we calculate symbol versions using the good old +# genksyms on the preprocessed source and postprocess them in a way +# that they are usable as a linker script +# o generate <file>.o from .tmp_<file>.o using the linker to +# replace the unresolved symbols __crc_exported_symbol with +# the actual value of the checksum generated by genksyms + +cmd_cc_o_c = $(CC) $(c_flags) -c -o $(@D)/.tmp_$(@F) $< +cmd_modversions = \ + if ! $(OBJDUMP) -h $(@D)/.tmp_$(@F) | grep -q __ksymtab; then \ + mv $(@D)/.tmp_$(@F) $@; \ + else \ + $(CPP) -D__GENKSYMS__ $(c_flags) $< \ + | $(GENKSYMS) \ + > $(@D)/.tmp_$(@F:.o=.ver); \ + \ + $(LD) $(LDFLAGS) -r -o $@ $(@D)/.tmp_$(@F) \ + -T $(@D)/.tmp_$(@F:.o=.ver); \ + rm -f $(@D)/.tmp_$(@F) $(@D)/.tmp_$(@F:.o=.ver); \ + fi; +endif + define rule_cc_o_c - $(if $($(quiet)cmd_checksrc),echo ' $($(quiet)cmd_checksrc)';) \ - $(cmd_checksrc) \ - $(if $($(quiet)cmd_cc_o_c),echo ' $($(quiet)cmd_cc_o_c)';) \ - $(cmd_cc_o_c); \ - scripts/fixdep $(depfile) $@ '$(cmd_cc_o_c)' > $(@D)/.$(@F).tmp; \ - rm -f $(depfile); \ + $(if $($(quiet)cmd_checksrc),echo ' $($(quiet)cmd_checksrc)';) \ + $(cmd_checksrc) \ + $(if $($(quiet)cmd_cc_o_c),echo ' $($(quiet)cmd_cc_o_c)';) \ + $(cmd_cc_o_c); \ + $(cmd_modversions) \ + scripts/fixdep $(depfile) $@ '$(cmd_cc_o_c)' > $(@D)/.$(@F).tmp; \ + rm -f $(depfile); \ mv -f $(@D)/.$(@F).tmp $(@D)/.$(@F).cmd endef # Built-in and composite module parts %.o: %.c FORCE -ifdef CONFIG_MODVERSIONS - $(call if_changed_rule,vcc_o_c) -else $(call if_changed_rule,cc_o_c) -endif # Single-part modules are special since we need to mark them in $(MODVERDIR) $(single-used-m): %.o: %.c FORCE -ifdef CONFIG_MODVERSIONS - $(call if_changed_rule,vcc_o_c) -else $(call if_changed_rule,cc_o_c) -endif $(touch-module) quiet_cmd_cc_lst_c = MKLST $@ @@ -223,7 +199,8 @@ %.o: %.S FORCE $(call if_changed_dep,as_o_S) -targets += $(real-objs-y) $(real-objs-m) $(extra-y) $(MAKECMDGOALS) $(always) +targets += $(real-objs-y) $(real-objs-m) $(lib-y) +targets += $(extra-y) $(MAKECMDGOALS) $(always) # Build the compiled-in targets # --------------------------------------------------------------------------- @@ -234,30 +211,30 @@ # # Rule to compile a set of .o files into one .o file # -ifdef O_TARGET +ifdef builtin-target quiet_cmd_link_o_target = LD $@ -# If the list of objects to link is empty, just create an empty O_TARGET +# If the list of objects to link is empty, just create an empty built-in.o cmd_link_o_target = $(if $(strip $(obj-y)),\ $(LD) $(ld_flags) -r -o $@ $(filter $(obj-y), $^),\ rm -f $@; $(AR) rcs $@) -$(O_TARGET): $(obj-y) FORCE +$(builtin-target): $(obj-y) FORCE $(call if_changed,link_o_target) -targets += $(O_TARGET) -endif # O_TARGET +targets += $(builtin-target) +endif # builtin-target # # Rule to compile a set of .o files into one .a file # -ifdef L_TARGET +ifdef lib-target quiet_cmd_link_l_target = AR $@ -cmd_link_l_target = rm -f $@; $(AR) $(EXTRA_ARFLAGS) rcs $@ $(obj-y) +cmd_link_l_target = rm -f $@; $(AR) $(EXTRA_ARFLAGS) rcs $@ $(lib-y) -$(L_TARGET): $(obj-y) FORCE +$(lib-target): $(lib-y) FORCE $(call if_changed,link_l_target) -targets += $(L_TARGET) +targets += $(lib-target) endif # diff -Nru a/scripts/Makefile.lib b/scripts/Makefile.lib --- a/scripts/Makefile.lib Mon Jun 9 23:16:12 2003 +++ b/scripts/Makefile.lib Mon Jun 9 23:16:12 2003 @@ -18,6 +18,12 @@ obj-m := $(filter-out $(obj-y),$(obj-m)) +# Libraries are always collected in one lib file. +# Filter out objects already built-in + +lib-y := $(filter-out $(obj-y), $(sort $(lib-y) $(lib-m))) + + # Handle objects in subdirs # --------------------------------------------------------------------------- # o if we encounter foo/ in $(obj-y), replace it by foo/built-in.o @@ -91,6 +97,7 @@ targets := $(addprefix $(obj)/,$(targets)) obj-y := $(addprefix $(obj)/,$(obj-y)) obj-m := $(addprefix $(obj)/,$(obj-m)) +lib-y := $(addprefix $(obj)/,$(lib-y)) subdir-obj-y := $(addprefix $(obj)/,$(subdir-obj-y)) real-objs-y := $(addprefix $(obj)/,$(real-objs-y)) real-objs-m := $(addprefix $(obj)/,$(real-objs-m)) diff -Nru a/scripts/docproc.c b/scripts/docproc.c --- a/scripts/docproc.c Mon Jun 9 23:16:07 2003 +++ b/scripts/docproc.c Mon Jun 9 23:16:07 2003 @@ -93,7 +93,7 @@ waitpid(pid, &ret ,0); } if (WIFEXITED(ret)) - exitstatus = WEXITSTATUS(ret); + exitstatus |= WEXITSTATUS(ret); else exitstatus = 0xff; } diff -Nru a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c --- a/scripts/kconfig/conf.c Mon Jun 9 23:16:18 2003 +++ b/scripts/kconfig/conf.c Mon Jun 9 23:16:18 2003 @@ -35,44 +35,6 @@ static char nohelp_text[] = "Sorry, no help available for this option yet.\n"; -#if 0 -static void printc(int ch) -{ - static int sep = 0; - - if (!sep) { - putchar('['); - sep = 1; - } else if (ch) - putchar('/'); - if (!ch) { - putchar(']'); - putchar(' '); - sep = 0; - } else - putchar(ch); -} -#endif - -static void printo(const char *o) -{ - static int sep = 0; - - if (!sep) { - putchar('('); - sep = 1; - } else if (o) { - putchar(','); - putchar(' '); - } - if (!o) { - putchar(')'); - putchar(' '); - sep = 0; - } else - printf("%s", o); -} - static void strip(char *str) { char *p = str; @@ -90,6 +52,16 @@ *p-- = 0; } +static void check_stdin(void) +{ + if (!valid_stdin && input_mode == ask_silent) { + printf("aborted!\n\n"); + printf("Console input/output is redirected. "); + printf("Run 'make oldconfig' to update configuration.\n\n"); + exit(1); + } +} + static void conf_askvalue(struct symbol *sym, const char *def) { enum symbol_type type = sym_get_type(sym); @@ -101,6 +73,13 @@ line[0] = '\n'; line[1] = 0; + if (!sym_is_changable(sym)) { + printf("%s\n", def); + line[0] = '\n'; + line[1] = 0; + return; + } + switch (input_mode) { case ask_new: case ask_silent: @@ -108,12 +87,7 @@ printf("%s\n", def); return; } - if (!valid_stdin && input_mode == ask_silent) { - printf("aborted!\n\n"); - printf("Console input/output is redirected. "); - printf("Run 'make oldconfig' to update configuration.\n\n"); - exit(1); - } + check_stdin(); case ask_all: fflush(stdout); fgets(line, 128, stdin); @@ -294,9 +268,8 @@ static int conf_choice(struct menu *menu) { struct symbol *sym, *def_sym; - struct menu *cmenu, *def_menu; - const char *help; - int type, len; + struct menu *child; + int type; bool is_new; sym = menu->sym; @@ -314,74 +287,111 @@ break; } } else { - sym->def = sym->curr; - if (S_TRI(sym->curr) == mod) { + switch (sym_get_tristate_value(sym)) { + case no: + return 1; + case mod: printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu)); return 0; + case yes: + break; } } while (1) { - printf("%*s%s ", indent - 1, "", menu_get_prompt(menu)); + int cnt, def; + + printf("%*s%s\n", indent - 1, "", menu_get_prompt(menu)); def_sym = sym_get_choice_value(sym); - def_menu = NULL; - for (cmenu = menu->list; cmenu; cmenu = cmenu->next) { - if (!menu_is_visible(cmenu)) + cnt = def = 0; + line[0] = '0'; + line[1] = 0; + for (child = menu->list; child; child = child->next) { + if (!menu_is_visible(child)) + continue; + if (!child->sym) { + printf("%*c %s\n", indent, '*', menu_get_prompt(child)); continue; - printo(menu_get_prompt(cmenu)); - if (cmenu->sym == def_sym) - def_menu = cmenu; - } - printo(NULL); - if (def_menu) - printf("[%s] ", menu_get_prompt(def_menu)); - else { + } + cnt++; + if (child->sym == def_sym) { + def = cnt; + printf("%*c", indent, '>'); + } else + printf("%*c", indent, ' '); + printf(" %d. %s", cnt, menu_get_prompt(child)); + if (child->sym->name) + printf(" (%s)", child->sym->name); + if (!sym_has_value(child->sym)) + printf(" (NEW)"); printf("\n"); - return 1; } + printf("%*schoice", indent - 1, ""); + if (cnt == 1) { + printf("[1]: 1\n"); + goto conf_childs; + } + printf("[1-%d", cnt); + if (sym->help) + printf("?"); + printf("]: "); switch (input_mode) { case ask_new: case ask_silent: + if (!is_new) { + cnt = def; + printf("%d\n", cnt); + break; + } + check_stdin(); case ask_all: - if (is_new) - sym->flags |= SYMBOL_NEW; - conf_askvalue(sym, menu_get_prompt(def_menu)); + fflush(stdout); + fgets(line, 128, stdin); strip(line); + if (line[0] == '?') { + printf("\n%s\n", menu->sym->help ? + menu->sym->help : nohelp_text); + continue; + } + if (!line[0]) + cnt = def; + else if (isdigit(line[0])) + cnt = atoi(line); + else + continue; + break; + case set_random: + def = (random() % cnt) + 1; + case set_default: + case set_yes: + case set_mod: + case set_no: + cnt = def; + printf("%d\n", cnt); break; - default: - line[0] = 0; - printf("\n"); } - if (line[0] == '?' && !line[1]) { - help = nohelp_text; - if (menu->sym->help) - help = menu->sym->help; - printf("\n%s\n", help); - continue; + + conf_childs: + for (child = menu->list; child; child = child->next) { + if (!child->sym || !menu_is_visible(child)) + continue; + if (!--cnt) + break; } - if (line[0]) { - len = strlen(line); - line[len] = 0; - - def_menu = NULL; - for (cmenu = menu->list; cmenu; cmenu = cmenu->next) { - if (!cmenu->sym || !menu_is_visible(cmenu)) - continue; - if (!strncasecmp(line, menu_get_prompt(cmenu), len)) { - def_menu = cmenu; - break; - } - } + if (!child) + continue; + if (line[strlen(line) - 1] == '?') { + printf("\n%s\n", child->sym->help ? + child->sym->help : nohelp_text); + continue; } - if (def_menu) { - sym_set_choice_value(sym, def_menu->sym); - if (def_menu->list) { - indent += 2; - conf(def_menu->list); - indent -= 2; - } - return 1; + sym_set_choice_value(sym, child->sym); + if (child->list) { + indent += 2; + conf(child->list); + indent -= 2; } + return 1; } } @@ -422,7 +432,7 @@ if (sym_is_choice(sym)) { conf_choice(menu); - if (S_TRI(sym->curr) != mod) + if (sym->curr.tri != mod) return; goto conf_childs; } diff -Nru a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c --- a/scripts/kconfig/confdata.c Mon Jun 9 23:16:19 2003 +++ b/scripts/kconfig/confdata.c Mon Jun 9 23:16:19 2003 @@ -105,11 +105,11 @@ case S_INT: case S_HEX: case S_STRING: - if (S_VAL(sym->def)) - free(S_VAL(sym->def)); + if (sym->user.val) + free(sym->user.val); default: - S_VAL(sym->def) = NULL; - S_TRI(sym->def) = no; + sym->user.val = NULL; + sym->user.tri = no; } } @@ -129,7 +129,7 @@ switch (sym->type) { case S_BOOLEAN: case S_TRISTATE: - sym->def = symbol_no.curr; + sym->user = symbol_no.curr; sym->flags &= ~SYMBOL_NEW; break; default: @@ -154,18 +154,18 @@ switch (sym->type) { case S_TRISTATE: if (p[0] == 'm') { - S_TRI(sym->def) = mod; + sym->user.tri = mod; sym->flags &= ~SYMBOL_NEW; break; } case S_BOOLEAN: if (p[0] == 'y') { - S_TRI(sym->def) = yes; + sym->user.tri = yes; sym->flags &= ~SYMBOL_NEW; break; } if (p[0] == 'n') { - S_TRI(sym->def) = no; + sym->user.tri = no; sym->flags &= ~SYMBOL_NEW; break; } @@ -187,7 +187,7 @@ case S_INT: case S_HEX: if (sym_string_valid(sym, p)) { - S_VAL(sym->def) = strdup(p); + sym->user.val = strdup(p); sym->flags &= ~SYMBOL_NEW; } else { fprintf(stderr, "%s:%d: symbol value '%s' invalid for %s\n", name, lineno, p, sym->name); @@ -198,21 +198,21 @@ ; } if (sym_is_choice_value(sym)) { - prop = sym_get_choice_prop(sym); - switch (S_TRI(sym->def)) { + struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); + switch (sym->user.tri) { case mod: - if (S_TRI(prop->def->def) == yes) + if (cs->user.tri == yes) /* warn? */; break; case yes: - if (S_TRI(prop->def->def) != no) + if (cs->user.tri != no) /* warn? */; - S_VAL(prop->def->def) = sym; + cs->user.val = sym; break; case no: break; } - S_TRI(prop->def->def) = S_TRI(sym->def); + cs->user.tri = sym->user.tri; } break; case '\n': @@ -224,12 +224,27 @@ fclose(in); for_all_symbols(i, sym) { + sym_calc_value(sym); + if (sym_has_value(sym)) { + if (sym->visible == no) + sym->flags |= SYMBOL_NEW; + switch (sym->type) { + case S_STRING: + case S_INT: + case S_HEX: + if (!sym_string_within_range(sym, sym->user.val)) + sym->flags |= SYMBOL_NEW; + default: + break; + } + } if (!sym_is_choice(sym)) continue; prop = sym_get_choice_prop(sym); sym->flags &= ~SYMBOL_NEW; - for (e = prop->dep; e; e = e->left.expr) - sym->flags |= e->right.sym->flags & SYMBOL_NEW; + for (e = prop->expr; e; e = e->left.expr) + if (e->right.sym->visible != no) + sym->flags |= e->right.sym->flags & SYMBOL_NEW; } sym_change_count = 1; @@ -242,23 +257,45 @@ FILE *out, *out_h; struct symbol *sym; struct menu *menu; - char oldname[128]; + const char *basename; + char dirname[128], tmpname[128], newname[128]; int type, l; const char *str; - out = fopen(".tmpconfig", "w"); + dirname[0] = 0; + if (name && name[0]) { + char *slash = strrchr(name, '/'); + if (slash) { + int size = slash - name + 1; + memcpy(dirname, name, size); + dirname[size] = 0; + if (slash[1]) + basename = slash + 1; + else + basename = conf_def_filename; + } else + basename = name; + } else + basename = conf_def_filename; + + sprintf(newname, "%s.tmpconfig.%d", dirname, getpid()); + out = fopen(newname, "w"); if (!out) return 1; - out_h = fopen(".tmpconfig.h", "w"); - if (!out_h) - return 1; + out_h = NULL; + if (!name) { + out_h = fopen(".tmpconfig.h", "w"); + if (!out_h) + return 1; + } fprintf(out, "#\n" "# Automatically generated make config: don't edit\n" "#\n"); - fprintf(out_h, "/*\n" - " * Automatically generated C config: don't edit\n" - " */\n" - "#define AUTOCONF_INCLUDED\n"); + if (out_h) + fprintf(out_h, "/*\n" + " * Automatically generated C config: don't edit\n" + " */\n" + "#define AUTOCONF_INCLUDED\n"); if (!sym_change_count) sym_clear_all_valid(); @@ -274,10 +311,11 @@ "#\n" "# %s\n" "#\n", str); - fprintf(out_h, "\n" - "/*\n" - " * %s\n" - " */\n", str); + if (out_h) + fprintf(out_h, "\n" + "/*\n" + " * %s\n" + " */\n", str); } else if (!(sym->flags & SYMBOL_CHOICE)) { sym_calc_value(sym); if (!(sym->flags & SYMBOL_WRITE)) @@ -286,7 +324,7 @@ type = sym->type; if (type == S_TRISTATE) { sym_calc_value(modules_sym); - if (S_TRI(modules_sym->curr) == no) + if (modules_sym->curr.tri == no) type = S_BOOLEAN; } switch (type) { @@ -295,15 +333,18 @@ switch (sym_get_tristate_value(sym)) { case no: fprintf(out, "# CONFIG_%s is not set\n", sym->name); - fprintf(out_h, "#undef CONFIG_%s\n", sym->name); + if (out_h) + fprintf(out_h, "#undef CONFIG_%s\n", sym->name); break; case mod: fprintf(out, "CONFIG_%s=m\n", sym->name); - fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name); + if (out_h) + fprintf(out_h, "#define CONFIG_%s_MODULE 1\n", sym->name); break; case yes: fprintf(out, "CONFIG_%s=y\n", sym->name); - fprintf(out_h, "#define CONFIG_%s 1\n", sym->name); + if (out_h) + fprintf(out_h, "#define CONFIG_%s 1\n", sym->name); break; } break; @@ -311,34 +352,40 @@ // fix me str = sym_get_string_value(sym); fprintf(out, "CONFIG_%s=\"", sym->name); - fprintf(out_h, "#define CONFIG_%s \"", sym->name); + if (out_h) + fprintf(out_h, "#define CONFIG_%s \"", sym->name); do { l = strcspn(str, "\"\\"); if (l) { fwrite(str, l, 1, out); - fwrite(str, l, 1, out_h); + if (out_h) + fwrite(str, l, 1, out_h); } str += l; while (*str == '\\' || *str == '"') { fprintf(out, "\\%c", *str); - fprintf(out_h, "\\%c", *str); + if (out_h) + fprintf(out_h, "\\%c", *str); str++; } } while (*str); fputs("\"\n", out); - fputs("\"\n", out_h); + if (out_h) + fputs("\"\n", out_h); break; case S_HEX: str = sym_get_string_value(sym); if (str[0] != '0' || (str[1] != 'x' && str[1] != 'X')) { fprintf(out, "CONFIG_%s=%s\n", sym->name, str); - fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str); + if (out_h) + fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str); break; } case S_INT: str = sym_get_string_value(sym); fprintf(out, "CONFIG_%s=%s\n", sym->name, str); - fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str); + if (out_h) + fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str); break; } } @@ -358,18 +405,18 @@ } } fclose(out); - fclose(out_h); - - if (!name) { + if (out_h) { + fclose(out_h); rename(".tmpconfig.h", "include/linux/autoconf.h"); - name = conf_def_filename; - file_write_dep(NULL); - } else - unlink(".tmpconfig.h"); - - sprintf(oldname, "%s.old", name); - rename(name, oldname); - if (rename(".tmpconfig", name)) + } + if (!name || basename != conf_def_filename) { + if (!name) + name = conf_def_filename; + sprintf(tmpname, "%s.old", name); + rename(name, tmpname); + } + sprintf(tmpname, "%s%s", dirname, basename); + if (rename(newname, tmpname)) return 1; sym_change_count = 0; diff -Nru a/scripts/kconfig/expr.c b/scripts/kconfig/expr.c --- a/scripts/kconfig/expr.c Mon Jun 9 23:16:10 2003 +++ b/scripts/kconfig/expr.c Mon Jun 9 23:16:10 2003 @@ -55,6 +55,13 @@ return e2 ? expr_alloc_two(E_AND, e1, e2) : e1; } +struct expr *expr_alloc_or(struct expr *e1, struct expr *e2) +{ + if (!e1) + return e2; + return e2 ? expr_alloc_two(E_OR, e1, e2) : e1; +} + struct expr *expr_copy(struct expr *org) { struct expr *e; @@ -158,9 +165,22 @@ void expr_eliminate_eq(struct expr **ep1, struct expr **ep2) { - if (!e1 || !e2 || e1->type != e2->type) + if (!e1 || !e2) return; - __expr_eliminate_eq(e1->type, ep1, ep2); + switch (e1->type) { + case E_OR: + case E_AND: + __expr_eliminate_eq(e1->type, ep1, ep2); + default: + ; + } + if (e1->type != e2->type) switch (e2->type) { + case E_OR: + case E_AND: + __expr_eliminate_eq(e2->type, ep1, ep2); + default: + ; + } e1 = expr_eliminate_yn(e1); e2 = expr_eliminate_yn(e2); } @@ -195,6 +215,7 @@ trans_count = old_count; return res; case E_CHOICE: + case E_RANGE: case E_NONE: /* panic */; } @@ -897,6 +918,7 @@ case E_SYMBOL: return expr_alloc_comp(type, e->left.sym, sym); case E_CHOICE: + case E_RANGE: case E_NONE: /* panic */; } @@ -914,7 +936,7 @@ switch (e->type) { case E_SYMBOL: sym_calc_value(e->left.sym); - return S_TRI(e->left.sym->curr); + return e->left.sym->curr.tri; case E_AND: val1 = expr_calc_value(e->left.expr); val2 = expr_calc_value(e->right.expr); @@ -1017,11 +1039,18 @@ expr_print(e->right.expr, fn, data, E_AND); break; case E_CHOICE: + fn(data, e->right.sym->name); if (e->left.expr) { - expr_print(e->left.expr, fn, data, E_CHOICE); fn(data, " ^ "); + expr_print(e->left.expr, fn, data, E_CHOICE); } + break; + case E_RANGE: + fn(data, "["); + fn(data, e->left.sym->name); + fn(data, " "); fn(data, e->right.sym->name); + fn(data, "]"); break; default: { diff -Nru a/scripts/kconfig/expr.h b/scripts/kconfig/expr.h --- a/scripts/kconfig/expr.h Mon Jun 9 23:16:14 2003 +++ b/scripts/kconfig/expr.h Mon Jun 9 23:16:14 2003 @@ -18,10 +18,6 @@ struct file { struct file *next; struct file *parent; -#ifdef CML1 - struct statement *stmt; - struct statement *last_stmt; -#endif char *name; int lineno; int flags; @@ -36,7 +32,7 @@ } tristate; enum expr_type { - E_NONE, E_OR, E_AND, E_NOT, E_EQUAL, E_UNEQUAL, E_CHOICE, E_SYMBOL + E_NONE, E_OR, E_AND, E_NOT, E_EQUAL, E_UNEQUAL, E_CHOICE, E_SYMBOL, E_RANGE }; union expr_data { @@ -45,18 +41,10 @@ }; struct expr { -#ifdef CML1 - int token; -#else enum expr_type type; -#endif union expr_data left, right; }; -#define E_TRI(ev) ((ev).tri) -#define E_EXPR(ev) ((ev).expr) -#define E_CALC(ev) (E_TRI(ev) = expr_calc_value(E_EXPR(ev))) - #define E_OR(dep1, dep2) (((dep1)>(dep2))?(dep1):(dep2)) #define E_AND(dep1, dep2) (((dep1)<(dep2))?(dep1):(dep2)) #define E_NOT(dep) (2-(dep)) @@ -66,12 +54,8 @@ tristate tri; }; -#define S_VAL(sv) ((sv).value) -#define S_TRI(sv) ((sv).tri) -#define S_EQ(sv1, sv2) (S_VAL(sv1) == S_VAL(sv2) || !strcmp(S_VAL(sv1), S_VAL(sv2))) - struct symbol_value { - void *value; + void *val; tristate tri; }; @@ -83,31 +67,17 @@ struct symbol *next; char *name; char *help; -#ifdef CML1 - int type; -#else enum symbol_type type; -#endif - struct symbol_value curr, def; + struct symbol_value curr, user; tristate visible; int flags; struct property *prop; struct expr *dep, *dep2; - struct menu *menu; + struct expr_value rev_dep; }; #define for_all_symbols(i, sym) for (i = 0; i < 257; i++) for (sym = symbol_hash[i]; sym; sym = sym->next) if (sym->type != S_OTHER) -#ifdef CML1 -#define SYMBOL_UNKNOWN S_UNKNOWN -#define SYMBOL_BOOLEAN S_BOOLEAN -#define SYMBOL_TRISTATE S_TRISTATE -#define SYMBOL_INT S_INT -#define SYMBOL_HEX S_HEX -#define SYMBOL_STRING S_STRING -#define SYMBOL_OTHER S_OTHER -#endif - #define SYMBOL_YES 0x0001 #define SYMBOL_MOD 0x0002 #define SYMBOL_NO 0x0004 @@ -122,34 +92,28 @@ #define SYMBOL_CHANGED 0x0400 #define SYMBOL_NEW 0x0800 #define SYMBOL_AUTO 0x1000 +#define SYMBOL_CHECKED 0x2000 +#define SYMBOL_CHECK_DONE 0x4000 +#define SYMBOL_WARNED 0x8000 #define SYMBOL_MAXLENGTH 256 #define SYMBOL_HASHSIZE 257 #define SYMBOL_HASHMASK 0xff enum prop_type { - P_UNKNOWN, P_PROMPT, P_COMMENT, P_MENU, P_ROOTMENU, P_DEFAULT, P_CHOICE + P_UNKNOWN, P_PROMPT, P_COMMENT, P_MENU, P_DEFAULT, P_CHOICE, P_SELECT, P_RANGE }; struct property { struct property *next; struct symbol *sym; -#ifdef CML1 - int token; -#else enum prop_type type; -#endif const char *text; - struct symbol *def; struct expr_value visible; - struct expr *dep; - struct expr *dep2; + struct expr *expr; struct menu *menu; struct file *file; int lineno; -#ifdef CML1 - struct property *next_pos; -#endif }; #define for_all_properties(sym, st, tok) \ @@ -176,6 +140,7 @@ }; #define MENU_CHANGED 0x0001 +#define MENU_ROOT 0x0002 #ifndef SWIG @@ -186,18 +151,12 @@ extern struct symbol symbol_yes, symbol_no, symbol_mod; extern struct symbol *modules_sym; extern int cdebug; -extern int print_type; struct expr *expr_alloc_symbol(struct symbol *sym); -#ifdef CML1 -struct expr *expr_alloc_one(int token, struct expr *ce); -struct expr *expr_alloc_two(int token, struct expr *e1, struct expr *e2); -struct expr *expr_alloc_comp(int token, struct symbol *s1, struct symbol *s2); -#else struct expr *expr_alloc_one(enum expr_type type, struct expr *ce); struct expr *expr_alloc_two(enum expr_type type, struct expr *e1, struct expr *e2); struct expr *expr_alloc_comp(enum expr_type type, struct symbol *s1, struct symbol *s2); -#endif struct expr *expr_alloc_and(struct expr *e1, struct expr *e2); +struct expr *expr_alloc_or(struct expr *e1, struct expr *e2); struct expr *expr_copy(struct expr *org); void expr_free(struct expr *e); int expr_eq(struct expr *e1, struct expr *e2); @@ -217,17 +176,6 @@ void expr_fprint(struct expr *e, FILE *out); void print_expr(int mask, struct expr *e, int prevtoken); -#ifdef CML1 -static inline int expr_is_yes(struct expr *e) -{ - return !e || (e->token == WORD && e->left.sym == &symbol_yes); -} - -static inline int expr_is_no(struct expr *e) -{ - return e && (e->token == WORD && e->left.sym == &symbol_no); -} -#else static inline int expr_is_yes(struct expr *e) { return !e || (e->type == E_SYMBOL && e->left.sym == &symbol_yes); @@ -237,7 +185,6 @@ { return e && (e->type == E_SYMBOL && e->left.sym == &symbol_no); } -#endif #endif #ifdef __cplusplus diff -Nru a/scripts/kconfig/gconf.c b/scripts/kconfig/gconf.c --- a/scripts/kconfig/gconf.c Mon Jun 9 23:16:19 2003 +++ b/scripts/kconfig/gconf.c Mon Jun 9 23:16:19 2003 @@ -164,8 +164,6 @@ strcpy(buf, "comment"); if (val == P_MENU) strcpy(buf, "menu"); - if (val == P_ROOTMENU) - strcpy(buf, "rootmenu"); if (val == P_DEFAULT) strcpy(buf, "default"); if (val == P_CHOICE) @@ -798,7 +796,7 @@ current = current->parent; ptype = current->prompt ? current->prompt->type : P_UNKNOWN; - if ((ptype != P_ROOTMENU) && (ptype != P_MENU)) + if (ptype != P_MENU) current = current->parent; display_tree_part(); @@ -836,6 +834,8 @@ gtk_widget_show(tree1_w); gtk_window_get_default_size(GTK_WINDOW(main_wnd), &w, &h); gtk_paned_set_position(GTK_PANED(hpaned), w / 2); + if (tree2) + gtk_tree_store_clear(tree2); display_list(); } @@ -922,8 +922,10 @@ config_changed = TRUE; if (view_mode == FULL_VIEW) update_tree(&rootmenu, NULL); - else if (view_mode == SPLIT_VIEW) + else if (view_mode == SPLIT_VIEW) { update_tree(current, NULL); + display_list(); + } else if (view_mode == SINGLE_VIEW) display_tree_part(); //fixme: keep exp/coll break; @@ -949,8 +951,10 @@ sym_set_tristate_value(menu->sym, newval); if (view_mode == FULL_VIEW) update_tree(&rootmenu, NULL); - else if (view_mode == SPLIT_VIEW) + else if (view_mode == SPLIT_VIEW) { update_tree(current, NULL); + display_list(); + } else if (view_mode == SINGLE_VIEW) display_tree_part(); //fixme: keep exp/coll } @@ -1035,8 +1039,7 @@ enum prop_type ptype; ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; - if (((ptype == P_MENU) || (ptype == P_ROOTMENU)) && - (view_mode == SINGLE_VIEW) && (col == COL_OPTION)) { + if (ptype == P_MENU && view_mode != FULL_VIEW && col == COL_OPTION) { // goes down into menu current = menu; display_tree_part(); @@ -1192,7 +1195,6 @@ ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; switch (ptype) { case P_MENU: - case P_ROOTMENU: row[COL_PIXBUF] = (gchar *) xpm_menu; if (view_mode != FULL_VIEW) row[COL_PIXVIS] = GINT_TO_POINTER(TRUE); @@ -1477,11 +1479,11 @@ if (sym) sym->flags &= ~SYMBOL_CHANGED; - if ((view_mode == SPLIT_VIEW) && (ptype != P_ROOTMENU) && + if ((view_mode == SPLIT_VIEW) && !(child->flags & MENU_ROOT) && (tree == tree1)) continue; - if ((view_mode == SPLIT_VIEW) && (ptype == P_ROOTMENU) && + if ((view_mode == SPLIT_VIEW) && (child->flags & MENU_ROOT) && (tree == tree2)) continue; @@ -1503,7 +1505,7 @@ && (tree == tree2)) continue; - if (((menu != &rootmenu) && (ptype != P_ROOTMENU)) || + if (((menu != &rootmenu) && !(menu->flags & MENU_ROOT)) || (view_mode == FULL_VIEW) || (view_mode == SPLIT_VIEW)) { indent++; @@ -1525,8 +1527,6 @@ /* Display the list in the left frame (split view) */ static void display_list(void) { - if (tree2) - gtk_tree_store_clear(tree2); if (tree1) gtk_tree_store_clear(tree1); @@ -1542,7 +1542,7 @@ if (!menu->prompt || menu->prompt->type != P_MENU) return; - menu->prompt->type = P_ROOTMENU; + menu->flags |= MENU_ROOT; for (child = menu->list; child; child = child->next) fixup_rootmenu(child); } diff -Nru a/scripts/kconfig/lex.zconf.c_shipped b/scripts/kconfig/lex.zconf.c_shipped --- a/scripts/kconfig/lex.zconf.c_shipped Mon Jun 9 23:16:18 2003 +++ b/scripts/kconfig/lex.zconf.c_shipped Mon Jun 9 23:16:18 2003 @@ -1,50 +1,84 @@ -#define yy_create_buffer zconf_create_buffer -#define yy_delete_buffer zconf_delete_buffer -#define yy_scan_buffer zconf_scan_buffer -#define yy_scan_string zconf_scan_string -#define yy_scan_bytes zconf_scan_bytes -#define yy_flex_debug zconf_flex_debug -#define yy_init_buffer zconf_init_buffer -#define yy_flush_buffer zconf_flush_buffer -#define yy_load_buffer_state zconf_load_buffer_state -#define yy_switch_to_buffer zconf_switch_to_buffer -#define yyin zconfin -#define yyleng zconfleng -#define yylex zconflex -#define yyout zconfout -#define yyrestart zconfrestart -#define yytext zconftext -/* A lexical scanner generated by flex */ +#line 3 "lex.zconf.c" -/* Scanner skeleton version: - * $Header: /home/daffy/u0/vern/flex/RCS/flex.skl,v 2.91 96/09/10 16:58:48 vern Exp $ - */ +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 31 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ #include <stdio.h> +#include <string.h> #include <errno.h> +#include <stdlib.h> -/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ -#ifdef c_plusplus -#ifndef __cplusplus -#define __cplusplus -#endif -#endif +/* end standard C headers. */ +/* flex integer type definitions */ -#ifdef __cplusplus +#ifndef FLEXINT_H +#define FLEXINT_H -#include <stdlib.h> -#ifndef _WIN32 -#include <unistd.h> +/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ + +#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L +#include <inttypes.h> +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; +#endif /* ! C99 */ + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) #endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! FLEXINT_H */ -/* Use prototypes in function declarations. */ -#define YY_USE_PROTOS +#ifdef __cplusplus /* The "const" storage-class-modifier is valid. */ #define YY_USE_CONST @@ -53,34 +87,17 @@ #if __STDC__ -#define YY_USE_PROTOS #define YY_USE_CONST #endif /* __STDC__ */ #endif /* ! __cplusplus */ -#ifdef __TURBOC__ - #pragma warn -rch - #pragma warn -use -#include <io.h> -#include <stdlib.h> -#define YY_USE_CONST -#define YY_USE_PROTOS -#endif - #ifdef YY_USE_CONST #define yyconst const #else #define yyconst #endif - -#ifdef YY_USE_PROTOS -#define YY_PROTO(proto) proto -#else -#define YY_PROTO(proto) () -#endif - /* Returned upon end-of-file. */ #define YY_NULL 0 @@ -95,71 +112,71 @@ * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ -#define BEGIN yy_start = 1 + 2 * +#define BEGIN (yy_start) = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ -#define YY_START ((yy_start - 1) / 2) +#define YY_START (((yy_start) - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ -#define YY_NEW_FILE yyrestart( yyin ) +#define YY_NEW_FILE zconfrestart(zconfin ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ +#ifndef YY_BUF_SIZE #define YY_BUF_SIZE 16384 +#endif +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +extern int zconfleng; -extern int yyleng; -extern FILE *yyin, *yyout; +extern FILE *zconfin, *zconfout; #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 -/* The funky do-while in the following #define is used to turn the definition - * int a single C statement (which needs a semi-colon terminator). This - * avoids problems with code like: - * - * if ( condition_holds ) - * yyless( 5 ); - * else - * do_something_else(); - * - * Prior to using the do-while the compiler would get upset at the - * "else" because it interpreted the "if" statement as being all - * done when it reached the ';' after the yyless() call. - */ - -/* Return all but the first 'n' matched characters back to the input stream. */ - + #define YY_LESS_LINENO(n) + +/* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ do \ { \ - /* Undo effects of setting up yytext. */ \ - *yy_cp = yy_hold_char; \ + /* Undo effects of setting up zconftext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = (yy_hold_char); \ YY_RESTORE_YY_MORE_OFFSET \ - yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \ - YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up zconftext again */ \ } \ while ( 0 ) -#define unput(c) yyunput( c, yytext_ptr ) +#define unput(c) yyunput( c, (yytext_ptr) ) /* The following is because we cannot portably get our hands on size_t * (without autoconf's help, which isn't available because we want * flex-generated scanners to compile on their own). */ -typedef unsigned int yy_size_t; +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef unsigned int yy_size_t; +#endif +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state { FILE *yy_input_file; @@ -196,12 +213,16 @@ */ int yy_at_bol; + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; + #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process @@ -211,97 +232,126 @@ * possible backing-up. * * When we actually see the EOF, we change the status to "new" - * (via yyrestart()), so that the user can continue scanning by - * just pointing yyin at a new input file. + * (via zconfrestart()), so that the user can continue scanning by + * just pointing zconfin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ -static YY_BUFFER_STATE yy_current_buffer = 0; +/* Stack of input buffers. */ +static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ +static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ +static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". + * + * Returns the top of the stack, or NULL. */ -#define YY_CURRENT_BUFFER yy_current_buffer +#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ + ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ + : NULL) +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] -/* yy_hold_char holds the character lost when yytext is formed. */ +/* yy_hold_char holds the character lost when zconftext is formed. */ static char yy_hold_char; - static int yy_n_chars; /* number of characters read into yy_ch_buf */ - - -int yyleng; +int zconfleng; /* Points to current character in buffer. */ static char *yy_c_buf_p = (char *) 0; static int yy_init = 1; /* whether we need to initialize */ static int yy_start = 0; /* start state number */ -/* Flag which is used to allow yywrap()'s to do buffer switches - * instead of setting up a fresh yyin. A bit of a hack ... +/* Flag which is used to allow zconfwrap()'s to do buffer switches + * instead of setting up a fresh zconfin. A bit of a hack ... */ static int yy_did_buffer_switch_on_eof; -void yyrestart YY_PROTO(( FILE *input_file )); - -void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer )); -void yy_load_buffer_state YY_PROTO(( void )); -YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size )); -void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b )); -void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file )); -void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b )); -#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer ) - -YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size )); -YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str )); -YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len )); - -static void *yy_flex_alloc YY_PROTO(( yy_size_t )); -static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t )); -static void yy_flex_free YY_PROTO(( void * )); +void zconfrestart (FILE *input_file ); +void zconf_switch_to_buffer (YY_BUFFER_STATE new_buffer ); +YY_BUFFER_STATE zconf_create_buffer (FILE *file,int size ); +void zconf_delete_buffer (YY_BUFFER_STATE b ); +void zconf_flush_buffer (YY_BUFFER_STATE b ); +void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer ); +void zconfpop_buffer_state (void ); + +static void zconfensure_buffer_stack (void ); +static void zconf_load_buffer_state (void ); +static void zconf_init_buffer (YY_BUFFER_STATE b,FILE *file ); + +#define YY_FLUSH_BUFFER zconf_flush_buffer(YY_CURRENT_BUFFER ) + +YY_BUFFER_STATE zconf_scan_buffer (char *base,yy_size_t size ); +YY_BUFFER_STATE zconf_scan_string (yyconst char *yy_str ); +YY_BUFFER_STATE zconf_scan_bytes (yyconst char *bytes,int len ); + +void *zconfalloc (yy_size_t ); +void *zconfrealloc (void *,yy_size_t ); +void zconffree (void * ); -#define yy_new_buffer yy_create_buffer +#define yy_new_buffer zconf_create_buffer #define yy_set_interactive(is_interactive) \ { \ - if ( ! yy_current_buffer ) \ - yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ - yy_current_buffer->yy_is_interactive = is_interactive; \ + if ( ! YY_CURRENT_BUFFER ){ \ + zconfensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + zconf_create_buffer(zconfin,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ - if ( ! yy_current_buffer ) \ - yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ - yy_current_buffer->yy_at_bol = at_bol; \ + if ( ! YY_CURRENT_BUFFER ){\ + zconfensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + zconf_create_buffer(zconfin,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } -#define YY_AT_BOL() (yy_current_buffer->yy_at_bol) +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) +/* Begin user sect3 */ -#define yywrap() 1 +#define zconfwrap(n) 1 #define YY_SKIP_YYWRAP + typedef unsigned char YY_CHAR; -FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; + +FILE *zconfin = (FILE *) 0, *zconfout = (FILE *) 0; + typedef int yy_state_type; -extern char *yytext; -#define yytext_ptr yytext -static yyconst short yy_nxt[][37] = + +extern int zconflineno; + +int zconflineno = 1; + +extern char *zconftext; +#define yytext_ptr zconftext +static yyconst flex_int16_t yy_nxt[][38] = { { 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 }, { 11, 12, 13, 14, 12, 12, 15, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12 + 12, 12, 12, 12, 12, 12, 12, 12 }, { @@ -309,21 +359,21 @@ 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12 + 12, 12, 12, 12, 12, 12, 12, 12 }, { 11, 16, 16, 17, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 18, 16, 16, 18, 19, 20, 21, - 22, 18, 18, 23, 24, 18, 25, 18, 26, 27, - 18, 28, 29, 30, 18, 18, 16 + 16, 16, 16, 18, 16, 16, 18, 18, 19, 20, + 21, 22, 18, 18, 23, 24, 18, 25, 18, 26, + 27, 18, 28, 29, 30, 18, 18, 16 }, { 11, 16, 16, 17, 16, 16, 16, 16, 16, 16, - 16, 16, 16, 18, 16, 16, 18, 19, 20, 21, - 22, 18, 18, 23, 24, 18, 25, 18, 26, 27, - 18, 28, 29, 30, 18, 18, 16 + 16, 16, 16, 18, 16, 16, 18, 18, 19, 20, + 21, 22, 18, 18, 23, 24, 18, 25, 18, 26, + 27, 18, 28, 29, 30, 18, 18, 16 }, @@ -331,14 +381,14 @@ 11, 31, 32, 33, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31 + 31, 31, 31, 31, 31, 31, 31, 31 }, { 11, 31, 32, 33, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, 31, - 31, 31, 31, 31, 31, 31, 31 + 31, 31, 31, 31, 31, 31, 31, 31 }, { @@ -346,36 +396,36 @@ 34, 34, 34, 34, 34, 37, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34 + 34, 34, 34, 34, 34, 34, 34, 34 }, { 11, 34, 34, 35, 34, 36, 34, 34, 36, 34, 34, 34, 34, 34, 34, 37, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, - 34, 34, 34, 34, 34, 34, 34 + 34, 34, 34, 34, 34, 34, 34, 34 }, { 11, 38, 38, 39, 40, 41, 42, 43, 41, 44, 45, 46, 47, 47, 48, 49, 47, 47, 47, 47, - 47, 47, 47, 47, 50, 47, 47, 47, 51, 47, - 47, 47, 47, 47, 47, 47, 52 + 47, 47, 47, 47, 47, 50, 47, 47, 47, 51, + 47, 47, 47, 47, 47, 47, 47, 52 }, { 11, 38, 38, 39, 40, 41, 42, 43, 41, 44, 45, 46, 47, 47, 48, 49, 47, 47, 47, 47, - 47, 47, 47, 47, 50, 47, 47, 47, 51, 47, - 47, 47, 47, 47, 47, 47, 52 + 47, 47, 47, 47, 47, 50, 47, 47, 47, 51, + 47, 47, 47, 47, 47, 47, 47, 52 }, { -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, - -11, -11, -11, -11, -11, -11, -11 + -11, -11, -11, -11, -11, -11, -11, -11 }, { @@ -383,21 +433,21 @@ -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, -12, - -12, -12, -12, -12, -12, -12, -12 + -12, -12, -12, -12, -12, -12, -12, -12 }, { 11, -13, 53, 54, -13, -13, 55, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, -13, - -13, -13, -13, -13, -13, -13, -13 + -13, -13, -13, -13, -13, -13, -13, -13 }, { 11, -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, -14, - -14, -14, -14, -14, -14, -14, -14 + -14, -14, -14, -14, -14, -14, -14, -14 }, @@ -405,14 +455,14 @@ 11, 56, 56, 57, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, - 56, 56, 56, 56, 56, 56, 56 + 56, 56, 56, 56, 56, 56, 56, 56 }, { 11, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, -16, - -16, -16, -16, -16, -16, -16, -16 + -16, -16, -16, -16, -16, -16, -16, -16 }, { @@ -420,73 +470,73 @@ -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, -17, - -17, -17, -17, -17, -17, -17, -17 + -17, -17, -17, -17, -17, -17, -17, -17 }, { 11, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, 58, -18, -18, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -18 + 58, 58, 58, 58, 58, 58, 58, -18 }, { 11, -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, -19, 58, -19, -19, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 59, 58, - 58, 58, 58, 58, 58, 58, -19 + 58, 58, 58, 58, 58, 58, 58, 58, 58, 59, + 58, 58, 58, 58, 58, 58, 58, -19 }, { 11, -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, -20, 58, -20, -20, 58, 58, 58, 58, - 58, 58, 58, 60, 58, 58, 58, 58, 61, 58, - 58, 58, 58, 58, 58, 58, -20 + 58, 58, 58, 58, 60, 58, 58, 58, 58, 61, + 58, 58, 58, 58, 58, 58, 58, -20 }, { 11, -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, -21, 58, -21, -21, 58, 58, 58, 58, - 62, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -21 + 58, 62, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -21 }, { 11, -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, -22, 58, -22, -22, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 63, 58, 58, - 58, 58, 58, 58, 58, 58, -22 + 58, 58, 58, 58, 58, 58, 58, 58, 63, 58, + 58, 58, 58, 58, 58, 58, 58, -22 }, { 11, -23, -23, -23, -23, -23, -23, -23, -23, -23, -23, -23, -23, 58, -23, -23, 58, 58, 58, 58, - 64, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -23 + 58, 64, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -23 }, { 11, -24, -24, -24, -24, -24, -24, -24, -24, -24, -24, -24, -24, 58, -24, -24, 58, 58, 58, 58, - 58, 65, 58, 58, 58, 58, 58, 66, 58, 58, - 58, 58, 58, 58, 58, 58, -24 + 58, 58, 65, 58, 58, 58, 58, 58, 66, 58, + 58, 58, 58, 58, 58, 58, 58, -24 }, { 11, -25, -25, -25, -25, -25, -25, -25, -25, -25, - -25, -25, -25, 58, -25, -25, 67, 58, 58, 58, - 68, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -25 + -25, -25, -25, 58, -25, -25, 58, 67, 58, 58, + 58, 68, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -25 }, { 11, -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, -26, 58, -26, -26, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 58, 69, - 58, 58, 58, 58, 58, 58, -26 + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 69, 58, 58, 58, 58, 58, 58, -26 }, { @@ -494,21 +544,21 @@ -27, -27, -27, 58, -27, -27, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 70, 58, 58, 58, 58, -27 + 58, 58, 70, 58, 58, 58, 58, -27 }, { 11, -28, -28, -28, -28, -28, -28, -28, -28, -28, - -28, -28, -28, 58, -28, -28, 58, 58, 58, 58, - 71, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -28 + -28, -28, -28, 58, -28, -28, 58, 71, 58, 58, + 58, 72, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -28 }, { 11, -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, -29, 58, -29, -29, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 72, 58, - 58, 58, 58, 73, 58, 58, -29 + 58, 73, 58, 58, 58, 58, 58, 58, 58, 74, + 58, 58, 58, 58, 75, 58, 58, -29 }, @@ -516,36 +566,36 @@ 11, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, -30, 58, -30, -30, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 74, 58, 58, 58, 58, -30 + 58, 58, 76, 58, 58, 58, 58, -30 }, { - 11, 75, 75, -31, 75, 75, 75, 75, 75, 75, - 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, - 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, - 75, 75, 75, 75, 75, 75, 75 + 11, 77, 77, -31, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77 }, { - 11, -32, 76, 77, -32, -32, -32, -32, -32, -32, + 11, -32, 78, 79, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, -32, - -32, -32, -32, -32, -32, -32, -32 + -32, -32, -32, -32, -32, -32, -32, -32 }, { - 11, 78, -33, -33, 78, 78, 78, 78, 78, 78, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, - 78, 78, 78, 78, 78, 78, 78 + 11, 80, -33, -33, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80 }, { - 11, 79, 79, 80, 79, -34, 79, 79, -34, 79, - 79, 79, 79, 79, 79, -34, 79, 79, 79, 79, - 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, - 79, 79, 79, 79, 79, 79, 79 + 11, 81, 81, 82, 81, -34, 81, 81, -34, 81, + 81, 81, 81, 81, 81, -34, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81 }, @@ -553,73 +603,73 @@ 11, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, -35, - -35, -35, -35, -35, -35, -35, -35 + -35, -35, -35, -35, -35, -35, -35, -35 }, { 11, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, -36, - -36, -36, -36, -36, -36, -36, -36 + -36, -36, -36, -36, -36, -36, -36, -36 }, { - 11, 81, 81, 82, 81, 81, 81, 81, 81, 81, - 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 11, 83, 83, 84, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, - 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, - 81, 81, 81, 81, 81, 81, 81 + 83, 83, 83, 83, 83, 83, 83, 83, 83, 83, + 83, 83, 83, 83, 83, 83, 83, 83 }, { 11, -38, -38, -38, -38, -38, -38, -38, -38, -38, -38, -38, -38, -38, -38, -38, -38, -38, -38, -38, -38, -38, -38, -38, -38, -38, -38, -38, -38, -38, - -38, -38, -38, -38, -38, -38, -38 + -38, -38, -38, -38, -38, -38, -38, -38 }, { 11, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, -39, - -39, -39, -39, -39, -39, -39, -39 + -39, -39, -39, -39, -39, -39, -39, -39 }, { 11, -40, -40, -40, -40, -40, -40, -40, -40, -40, - -40, -40, -40, -40, 83, -40, -40, -40, -40, -40, + -40, -40, -40, -40, 85, -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, -40, - -40, -40, -40, -40, -40, -40, -40 + -40, -40, -40, -40, -40, -40, -40, -40 }, { 11, -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, -41, - -41, -41, -41, -41, -41, -41, -41 + -41, -41, -41, -41, -41, -41, -41, -41 }, { - 11, 84, 84, -42, 84, 84, 84, 84, 84, 84, - 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, + 11, 86, 86, -42, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, - 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, - 84, 84, 84, 84, 84, 84, 84 + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86 }, { - 11, -43, -43, -43, -43, -43, -43, 85, -43, -43, + 11, -43, -43, -43, -43, -43, -43, 87, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, -43, - -43, -43, -43, -43, -43, -43, -43 + -43, -43, -43, -43, -43, -43, -43, -43 }, { 11, -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, -44, - -44, -44, -44, -44, -44, -44, -44 + -44, -44, -44, -44, -44, -44, -44, -44 }, @@ -627,51 +677,51 @@ 11, -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, -45, - -45, -45, -45, -45, -45, -45, -45 + -45, -45, -45, -45, -45, -45, -45, -45 }, { 11, -46, -46, -46, -46, -46, -46, -46, -46, -46, - -46, 86, 87, 87, -46, -46, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87, -46 + -46, 88, 89, 89, -46, -46, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, -46 }, { 11, -47, -47, -47, -47, -47, -47, -47, -47, -47, - -47, 87, 87, 87, -47, -47, 87, 87, 87, 87, + -47, 89, 89, 89, -47, -47, 89, 89, 89, 89, - 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87, -47 + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, -47 }, { 11, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, -48, - -48, -48, -48, -48, -48, -48, -48 + -48, -48, -48, -48, -48, -48, -48, -48 }, { - 11, -49, -49, 88, -49, -49, -49, -49, -49, -49, + 11, -49, -49, 90, -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, -49, - -49, -49, -49, -49, -49, -49, -49 + -49, -49, -49, -49, -49, -49, -49, -49 }, { 11, -50, -50, -50, -50, -50, -50, -50, -50, -50, - -50, 87, 87, 87, -50, -50, 87, 87, 87, 87, - 87, 89, 87, 87, 87, 87, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87, -50 + -50, 89, 89, 89, -50, -50, 89, 89, 89, 89, + 89, 89, 91, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, -50 }, { 11, -51, -51, -51, -51, -51, -51, -51, -51, -51, - -51, 87, 87, 87, -51, -51, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87, 87, 90, 87, 87, - 87, 87, 87, 87, 87, 87, -51 + -51, 89, 89, 89, -51, -51, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 92, 89, + 89, 89, 89, 89, 89, 89, 89, -51 }, { @@ -679,21 +729,21 @@ -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, - -52, -52, -52, -52, -52, -52, 91 + -52, -52, -52, -52, -52, -52, -52, 93 }, { 11, -53, 53, 54, -53, -53, 55, -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, -53, - -53, -53, -53, -53, -53, -53, -53 + -53, -53, -53, -53, -53, -53, -53, -53 }, { 11, -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, -54, - -54, -54, -54, -54, -54, -54, -54 + -54, -54, -54, -54, -54, -54, -54, -54 }, @@ -701,14 +751,14 @@ 11, 56, 56, 57, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, - 56, 56, 56, 56, 56, 56, 56 + 56, 56, 56, 56, 56, 56, 56, 56 }, { 11, 56, 56, 57, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, - 56, 56, 56, 56, 56, 56, 56 + 56, 56, 56, 56, 56, 56, 56, 56 }, { @@ -716,58 +766,58 @@ -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, -57, - -57, -57, -57, -57, -57, -57, -57 + -57, -57, -57, -57, -57, -57, -57, -57 }, { 11, -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, -58, 58, -58, -58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -58 + 58, 58, 58, 58, 58, 58, 58, -58 }, { 11, -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, -59, 58, -59, -59, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 92, 58, - 58, 58, 58, 58, 58, 58, -59 + 58, 58, 58, 58, 58, 58, 58, 58, 58, 94, + 58, 58, 58, 58, 58, 58, 58, -59 }, { 11, -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, -60, 58, -60, -60, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 93, 58, - 58, 58, 58, 58, 58, 58, -60 + 58, 58, 58, 58, 58, 58, 58, 58, 58, 95, + 58, 58, 58, 58, 58, 58, 58, -60 }, { 11, -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, -61, 58, -61, -61, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 94, 95, 58, 58, - 58, 58, 58, 58, 58, 58, -61 + 58, 58, 58, 58, 58, 58, 58, 96, 97, 58, + 58, 58, 58, 58, 58, 58, 58, -61 }, { 11, -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, -62, 58, -62, -62, 58, 58, 58, 58, - 58, 96, 58, 58, 58, 58, 58, 58, 58, 97, - 58, 58, 58, 58, 58, 58, -62 + 58, 58, 98, 58, 58, 58, 58, 58, 58, 58, + 99, 58, 58, 58, 58, 58, 58, -62 }, { 11, -63, -63, -63, -63, -63, -63, -63, -63, -63, - -63, -63, -63, 58, -63, -63, 58, 58, 58, 98, - 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -63 + -63, -63, -63, 58, -63, -63, 58, 100, 58, 58, + 101, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -63 }, { 11, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, -64, 58, -64, -64, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 99, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 100, -64 + 58, 58, 58, 58, 58, 58, 102, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 103, -64 }, @@ -775,51 +825,51 @@ 11, -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, -65, 58, -65, -65, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -65 + 58, 58, 58, 58, 58, 58, 58, -65 }, { 11, -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, -66, 58, -66, -66, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 101, 58, 58, -66 + 58, 58, 58, 58, 104, 58, 58, -66 }, { 11, -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, -67, 58, -67, -67, 58, 58, 58, 58, - 58, 58, 58, 58, 102, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -67 + 58, 58, 58, 58, 58, 105, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -67 }, { 11, -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, -68, 58, -68, -68, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 103, 58, 58, - 58, 58, 58, 58, 58, 58, -68 + 58, 58, 58, 58, 58, 58, 58, 58, 106, 58, + 58, 58, 58, 58, 58, 58, 58, -68 }, { 11, -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, -69, 58, -69, -69, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 104, 58, 58, -69 + 58, 58, 58, 58, 107, 58, 58, -69 }, { 11, -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, -70, 58, -70, -70, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 105, 58, - 58, 58, 58, 58, 58, 58, -70 + 58, 58, 58, 58, 58, 58, 58, 58, 58, 108, + 58, 58, 58, 58, 58, 58, 58, -70 }, { 11, -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, -71, 58, -71, -71, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 106, 58, 58, 58, 58, 58, -71 + 58, 58, 58, 58, 58, 58, 58, 58, 109, 58, + 58, 58, 58, 58, 58, 58, 58, -71 }, { @@ -827,58 +877,58 @@ -72, -72, -72, 58, -72, -72, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 107, 58, -72 + 58, 110, 58, 58, 58, 58, 58, -72 }, { 11, -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, -73, 58, -73, -73, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 108, 58, 58, 58, 58, -73 + 58, 58, 58, 58, 58, 58, 111, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -73 }, { 11, -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, -74, 58, -74, -74, 58, 58, 58, 58, - 58, 58, 58, 58, 109, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -74 + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 112, 58, -74 }, { - 11, 75, 75, -75, 75, 75, 75, 75, 75, 75, - 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, - 75, 75, 75, 75, 75, 75, 75, 75, 75, 75, - 75, 75, 75, 75, 75, 75, 75 + 11, -75, -75, -75, -75, -75, -75, -75, -75, -75, + -75, -75, -75, 58, -75, -75, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 113, 58, 58, 58, 58, -75 }, { - 11, -76, 76, 77, -76, -76, -76, -76, -76, -76, - -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, - -76, -76, -76, -76, -76, -76, -76, -76, -76, -76, - -76, -76, -76, -76, -76, -76, -76 + 11, -76, -76, -76, -76, -76, -76, -76, -76, -76, + -76, -76, -76, 58, -76, -76, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 114, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -76 }, { - 11, 78, -77, -77, 78, 78, 78, 78, 78, 78, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, + 11, 77, 77, -77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, - 78, 78, 78, 78, 78, 78, 78, 78, 78, 78, - 78, 78, 78, 78, 78, 78, 78 + 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, + 77, 77, 77, 77, 77, 77, 77, 77 }, { - 11, -78, -78, -78, -78, -78, -78, -78, -78, -78, + 11, -78, 78, 79, -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, -78, - -78, -78, -78, -78, -78, -78, -78 + -78, -78, -78, -78, -78, -78, -78, -78 }, { - 11, 79, 79, 80, 79, -79, 79, 79, -79, 79, - 79, 79, 79, 79, 79, -79, 79, 79, 79, 79, - 79, 79, 79, 79, 79, 79, 79, 79, 79, 79, - 79, 79, 79, 79, 79, 79, 79 + 11, 80, -79, -79, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80 }, @@ -886,14 +936,14 @@ 11, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, -80, - -80, -80, -80, -80, -80, -80, -80 + -80, -80, -80, -80, -80, -80, -80, -80 }, { - 11, -81, -81, 82, -81, -81, -81, -81, -81, -81, - -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, - -81, -81, -81, -81, -81, -81, -81, -81, -81, -81, - -81, -81, -81, -81, -81, -81, -81 + 11, 81, 81, 82, 81, -81, 81, 81, -81, 81, + 81, 81, 81, 81, 81, -81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81, 81, 81, + 81, 81, 81, 81, 81, 81, 81, 81 }, { @@ -901,21 +951,21 @@ -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, -82, - -82, -82, -82, -82, -82, -82, -82 + -82, -82, -82, -82, -82, -82, -82, -82 }, { - 11, -83, -83, -83, -83, -83, -83, -83, -83, -83, + 11, -83, -83, 84, -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, -83, - -83, -83, -83, -83, -83, -83, -83 + -83, -83, -83, -83, -83, -83, -83, -83 }, { - 11, 84, 84, -84, 84, 84, 84, 84, 84, 84, - 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, - 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, - 84, 84, 84, 84, 84, 84, 84 + 11, -84, -84, -84, -84, -84, -84, -84, -84, -84, + -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, + -84, -84, -84, -84, -84, -84, -84, -84, -84, -84, + -84, -84, -84, -84, -84, -84, -84, -84 }, @@ -923,569 +973,569 @@ 11, -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, -85, - -85, -85, -85, -85, -85, -85, -85 + -85, -85, -85, -85, -85, -85, -85, -85 }, { - 11, -86, -86, -86, -86, -86, -86, -86, -86, -86, - -86, 110, 87, 87, -86, -86, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87, -86 + 11, 86, 86, -86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86, 86, 86, + 86, 86, 86, 86, 86, 86, 86, 86 }, { 11, -87, -87, -87, -87, -87, -87, -87, -87, -87, - -87, 87, 87, 87, -87, -87, 87, 87, 87, 87, + -87, -87, -87, -87, -87, -87, -87, -87, -87, -87, - 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87, -87 + -87, -87, -87, -87, -87, -87, -87, -87, -87, -87, + -87, -87, -87, -87, -87, -87, -87, -87 }, { 11, -88, -88, -88, -88, -88, -88, -88, -88, -88, - -88, -88, -88, -88, -88, -88, -88, -88, -88, -88, - -88, -88, -88, -88, -88, -88, -88, -88, -88, -88, - -88, -88, -88, -88, -88, -88, -88 + -88, 115, 89, 89, -88, -88, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, -88 }, { 11, -89, -89, -89, -89, -89, -89, -89, -89, -89, - -89, 87, 87, 87, -89, -89, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87, -89 + -89, 89, 89, 89, -89, -89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, -89 }, { 11, -90, -90, -90, -90, -90, -90, -90, -90, -90, - -90, 87, 87, 87, -90, -90, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87, -90 + -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, + -90, -90, -90, -90, -90, -90, -90, -90, -90, -90, + -90, -90, -90, -90, -90, -90, -90, -90 }, { 11, -91, -91, -91, -91, -91, -91, -91, -91, -91, - -91, -91, -91, -91, -91, -91, -91, -91, -91, -91, - -91, -91, -91, -91, -91, -91, -91, -91, -91, -91, - -91, -91, -91, -91, -91, -91, -91 + -91, 89, 89, 89, -91, -91, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, -91 }, { 11, -92, -92, -92, -92, -92, -92, -92, -92, -92, - -92, -92, -92, 58, -92, -92, 58, 58, 58, 58, + -92, 89, 89, 89, -92, -92, 89, 89, 89, 89, - 58, 58, 58, 58, 58, 111, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -92 + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, -92 }, { 11, -93, -93, -93, -93, -93, -93, -93, -93, -93, - -93, -93, -93, 58, -93, -93, 58, 58, 58, 58, - 58, 58, 58, 58, 112, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -93 + -93, -93, -93, -93, -93, -93, -93, -93, -93, -93, + -93, -93, -93, -93, -93, -93, -93, -93, -93, -93, + -93, -93, -93, -93, -93, -93, -93, -93 }, { 11, -94, -94, -94, -94, -94, -94, -94, -94, -94, -94, -94, -94, 58, -94, -94, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 113, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -94 + 58, 58, 58, 58, 58, 58, 116, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -94 }, { 11, -95, -95, -95, -95, -95, -95, -95, -95, -95, -95, -95, -95, 58, -95, -95, 58, 58, 58, 58, - 58, 114, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -95 + 58, 58, 58, 58, 58, 117, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -95 }, { 11, -96, -96, -96, -96, -96, -96, -96, -96, -96, - -96, -96, -96, 58, -96, -96, 115, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -96 + -96, -96, -96, 58, -96, -96, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 118, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -96 }, { 11, -97, -97, -97, -97, -97, -97, -97, -97, -97, -97, -97, -97, 58, -97, -97, 58, 58, 58, 58, - 116, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -97 + 58, 58, 119, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -97 }, { 11, -98, -98, -98, -98, -98, -98, -98, -98, -98, - -98, -98, -98, 58, -98, -98, 58, 58, 117, 58, - 58, 58, 58, 58, 118, 58, 119, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -98 + -98, -98, -98, 58, -98, -98, 120, 121, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -98 }, { 11, -99, -99, -99, -99, -99, -99, -99, -99, -99, -99, -99, -99, 58, -99, -99, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 58, 120, - 58, 58, 58, 58, 58, 58, -99 + 58, 122, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -99 }, { 11, -100, -100, -100, -100, -100, -100, -100, -100, -100, - -100, -100, -100, 58, -100, -100, 58, 58, 58, 58, + -100, -100, -100, 58, -100, -100, 58, 58, 123, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -100 + 58, 58, 58, 58, 58, 58, 58, -100 }, { 11, -101, -101, -101, -101, -101, -101, -101, -101, -101, - -101, -101, -101, 58, -101, -101, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -101 + -101, -101, -101, 58, -101, -101, 58, 58, 58, 124, + 58, 58, 58, 58, 58, 125, 58, 126, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -101 }, { 11, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, -102, 58, -102, -102, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 121, 58, 58, - 58, 58, 58, 58, 58, 58, -102 + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 127, 58, 58, 58, 58, 58, 58, -102 }, { 11, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, -103, 58, -103, -103, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 122, 58, -103 + 58, 58, 58, 58, 58, 58, 58, -103 }, { 11, -104, -104, -104, -104, -104, -104, -104, -104, -104, -104, -104, -104, 58, -104, -104, 58, 58, 58, 58, - 58, 58, 58, 58, 123, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -104 + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -104 }, { 11, -105, -105, -105, -105, -105, -105, -105, -105, -105, -105, -105, -105, 58, -105, -105, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 124, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -105 + 58, 58, 58, 58, 58, 58, 58, 58, 128, 58, + 58, 58, 58, 58, 58, 58, 58, -105 }, { 11, -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, -106, 58, -106, -106, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 125, 58, -106 + 58, 58, 58, 58, 58, 129, 58, -106 }, { 11, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, -107, 58, -107, -107, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 126, 58, 58, 58, 58, -107 + 58, 58, 58, 58, 58, 130, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -107 }, { 11, -108, -108, -108, -108, -108, -108, -108, -108, -108, -108, -108, -108, 58, -108, -108, 58, 58, 58, 58, - 58, 58, 58, 58, 127, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -108 + 58, 58, 58, 58, 58, 58, 58, 131, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -108 }, { 11, -109, -109, -109, -109, -109, -109, -109, -109, -109, -109, -109, -109, 58, -109, -109, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 128, 58, 58, 58, -109 + 58, 58, 58, 132, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -109 }, { 11, -110, -110, -110, -110, -110, -110, -110, -110, -110, - -110, 87, 87, 87, -110, -110, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, - 87, 87, 87, 87, 87, 87, -110 + -110, -110, -110, 58, -110, -110, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 133, 58, -110 }, { 11, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, -111, 58, -111, -111, 58, 58, 58, 58, - 129, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -111 + 58, 134, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -111 }, { 11, -112, -112, -112, -112, -112, -112, -112, -112, -112, - -112, -112, -112, 58, -112, -112, 58, 58, 130, 58, + -112, -112, -112, 58, -112, -112, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -112 + 58, 58, 135, 58, 58, 58, 58, -112 }, { 11, -113, -113, -113, -113, -113, -113, -113, -113, -113, -113, -113, -113, 58, -113, -113, 58, 58, 58, 58, - 131, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -113 + 58, 58, 58, 58, 58, 136, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -113 }, { 11, -114, -114, -114, -114, -114, -114, -114, -114, -114, -114, -114, -114, 58, -114, -114, 58, 58, 58, 58, - 58, 58, 58, 58, 132, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -114 + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 137, 58, 58, 58, -114 }, { 11, -115, -115, -115, -115, -115, -115, -115, -115, -115, - -115, -115, -115, 58, -115, -115, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 133, 58, -115 + -115, 89, 89, 89, -115, -115, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, 89, 89, 89, + 89, 89, 89, 89, 89, 89, 89, -115 }, { 11, -116, -116, -116, -116, -116, -116, -116, -116, -116, -116, -116, -116, 58, -116, -116, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 134, 58, 58, - 58, 58, 58, 58, 58, 58, -116 + 58, 138, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -116 }, { 11, -117, -117, -117, -117, -117, -117, -117, -117, -117, - -117, -117, -117, 58, -117, -117, 58, 58, 58, 58, + -117, -117, -117, 58, -117, -117, 58, 58, 58, 139, - 58, 58, 58, 135, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -117 + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -117 }, { 11, -118, -118, -118, -118, -118, -118, -118, -118, -118, -118, -118, -118, 58, -118, -118, 58, 58, 58, 58, - 58, 136, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -118 + 58, 140, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -118 }, { 11, -119, -119, -119, -119, -119, -119, -119, -119, -119, -119, -119, -119, 58, -119, -119, 58, 58, 58, 58, - 137, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -119 + 58, 58, 58, 58, 58, 141, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -119 }, { 11, -120, -120, -120, -120, -120, -120, -120, -120, -120, - -120, -120, -120, 58, -120, -120, 58, 58, 58, 58, + -120, -120, -120, 58, -120, -120, 58, 58, 142, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -120 + 58, 58, 58, 58, 143, 58, 58, -120 }, { 11, -121, -121, -121, -121, -121, -121, -121, -121, -121, -121, -121, -121, 58, -121, -121, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 138, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -121 + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 144, 58, -121 }, { 11, -122, -122, -122, -122, -122, -122, -122, -122, -122, - -122, -122, -122, 58, -122, -122, 58, 58, 139, 58, + -122, -122, -122, 58, -122, -122, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -122 + 58, 58, 58, 58, 58, 58, 58, 58, 145, 58, + 58, 58, 58, 58, 58, 58, 58, -122 }, { 11, -123, -123, -123, -123, -123, -123, -123, -123, -123, -123, -123, -123, 58, -123, -123, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 140, 58, - 58, 58, 58, 58, 58, 58, -123 + 58, 58, 58, 58, 58, 58, 146, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -123 }, { 11, -124, -124, -124, -124, -124, -124, -124, -124, -124, -124, -124, -124, 58, -124, -124, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 58, 141, - 58, 58, 58, 58, 58, 58, -124 + 58, 58, 58, 58, 147, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -124 }, { 11, -125, -125, -125, -125, -125, -125, -125, -125, -125, -125, -125, -125, 58, -125, -125, 58, 58, 58, 58, - 58, 58, 58, 58, 142, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -125 + 58, 58, 148, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -125 }, { 11, -126, -126, -126, -126, -126, -126, -126, -126, -126, - -126, -126, -126, 58, -126, -126, 58, 58, 143, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -126 + -126, -126, -126, 58, -126, -126, 58, 58, 58, 58, + 58, 149, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -126 }, { 11, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, -127, 58, -127, -127, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 144, 58, 58, - 58, 58, 58, 58, 58, 58, -127 + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -127 }, { 11, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, -128, 58, -128, -128, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 145, 58, 58, -128 + 58, 58, 58, 58, 58, 58, 58, 150, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -128 }, { 11, -129, -129, -129, -129, -129, -129, -129, -129, -129, - -129, -129, -129, 58, -129, -129, 146, 58, 58, 58, + -129, -129, -129, 58, -129, -129, 58, 58, 58, 151, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -129 + 58, 58, 58, 58, 58, 58, 58, -129 }, { 11, -130, -130, -130, -130, -130, -130, -130, -130, -130, -130, -130, -130, 58, -130, -130, 58, 58, 58, 58, - 147, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -130 + 58, 58, 58, 58, 58, 58, 58, 58, 58, 152, + 58, 58, 58, 58, 58, 58, 58, -130 }, { 11, -131, -131, -131, -131, -131, -131, -131, -131, -131, -131, -131, -131, 58, -131, -131, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 148, 58, 58, - 58, 58, 58, 58, 58, 58, -131 + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 153, 58, 58, 58, 58, 58, 58, -131 }, { 11, -132, -132, -132, -132, -132, -132, -132, -132, -132, -132, -132, -132, 58, -132, -132, 58, 58, 58, 58, - 58, 58, 149, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -132 + 58, 154, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -132 }, { 11, -133, -133, -133, -133, -133, -133, -133, -133, -133, -133, -133, -133, 58, -133, -133, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 150, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -133 + 58, 58, 58, 58, 58, 155, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -133 }, { 11, -134, -134, -134, -134, -134, -134, -134, -134, -134, - -134, -134, -134, 58, -134, -134, 58, 58, 58, 151, + -134, -134, -134, 58, -134, -134, 58, 58, 58, 156, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -134 + 58, 58, 58, 58, 58, 58, 58, -134 }, { 11, -135, -135, -135, -135, -135, -135, -135, -135, -135, - -135, -135, -135, 58, -135, -135, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 152, 58, - 58, 58, 58, 58, 58, 58, -135 + -135, -135, -135, 58, -135, -135, 58, 58, 58, 157, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -135 }, { 11, -136, -136, -136, -136, -136, -136, -136, -136, -136, -136, -136, -136, 58, -136, -136, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -136 + 58, 58, 58, 58, 58, 58, 58, 58, 158, 58, + 58, 58, 58, 58, 58, 58, 58, -136 }, { 11, -137, -137, -137, -137, -137, -137, -137, -137, -137, -137, -137, -137, 58, -137, -137, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 153, 58, 58, - 58, 58, 58, 58, 58, 58, -137 + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 159, 58, 58, -137 }, { 11, -138, -138, -138, -138, -138, -138, -138, -138, -138, - -138, -138, -138, 58, -138, -138, 58, 58, 58, 58, - 154, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -138 + -138, -138, -138, 58, -138, -138, 58, 160, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -138 }, { 11, -139, -139, -139, -139, -139, -139, -139, -139, -139, -139, -139, -139, 58, -139, -139, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 155, 58, - 58, 58, 58, 58, 58, 58, -139 + 58, 161, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -139 }, { 11, -140, -140, -140, -140, -140, -140, -140, -140, -140, -140, -140, -140, 58, -140, -140, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 156, 58, 58, - 58, 58, 58, 58, 58, 58, -140 + 58, 58, 58, 58, 58, 58, 58, 58, 162, 58, + 58, 58, 58, 58, 58, 58, 58, -140 }, { 11, -141, -141, -141, -141, -141, -141, -141, -141, -141, -141, -141, -141, 58, -141, -141, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 157, 58, 58, -141 + 58, 58, 58, 163, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -141 }, { 11, -142, -142, -142, -142, -142, -142, -142, -142, -142, -142, -142, -142, 58, -142, -142, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 158, 58, 58, 58, 58, -142 + 58, 58, 58, 58, 58, 58, 58, 58, 58, 164, + 58, 58, 58, 58, 58, 58, 58, -142 }, { 11, -143, -143, -143, -143, -143, -143, -143, -143, -143, -143, -143, -143, 58, -143, -143, 58, 58, 58, 58, - 159, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -143 + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 165, 58, 58, 58, 58, -143 }, { 11, -144, -144, -144, -144, -144, -144, -144, -144, -144, -144, -144, -144, 58, -144, -144, 58, 58, 58, 58, - 58, 58, 160, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -144 + 58, 58, 58, 58, 58, 58, 166, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -144 }, { 11, -145, -145, -145, -145, -145, -145, -145, -145, -145, - -145, -145, -145, 58, -145, -145, 161, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -145 + -145, -145, -145, 58, -145, -145, 58, 58, 58, 58, + 167, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -145 }, { 11, -146, -146, -146, -146, -146, -146, -146, -146, -146, -146, -146, -146, 58, -146, -146, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 162, 58, 58, - 58, 58, 58, 58, 58, 58, -146 + 58, 168, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -146 }, { 11, -147, -147, -147, -147, -147, -147, -147, -147, -147, -147, -147, -147, 58, -147, -147, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -147 + 58, 58, 58, 58, 58, 58, 58, 58, 58, 169, + 58, 58, 58, 58, 58, 58, 58, -147 }, { 11, -148, -148, -148, -148, -148, -148, -148, -148, -148, -148, -148, -148, 58, -148, -148, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 163, 58, 58, -148 + 58, 58, 58, 58, 58, 58, 58, -148 }, { 11, -149, -149, -149, -149, -149, -149, -149, -149, -149, -149, -149, -149, 58, -149, -149, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -149 + 58, 58, 58, 58, 58, 58, 58, 58, 170, 58, + 58, 58, 58, 58, 58, 58, 58, -149 }, { 11, -150, -150, -150, -150, -150, -150, -150, -150, -150, -150, -150, -150, 58, -150, -150, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 164, 58, 58, -150 + 58, 171, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -150 }, { 11, -151, -151, -151, -151, -151, -151, -151, -151, -151, -151, -151, -151, 58, -151, -151, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 165, 58, 58, 58, -151 + 58, 58, 58, 58, 58, 58, 58, 58, 58, 172, + 58, 58, 58, 58, 58, 58, 58, -151 }, { 11, -152, -152, -152, -152, -152, -152, -152, -152, -152, -152, -152, -152, 58, -152, -152, 58, 58, 58, 58, - 58, 58, 58, 58, 166, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -152 + 58, 58, 58, 58, 58, 58, 58, 58, 173, 58, + 58, 58, 58, 58, 58, 58, 58, -152 }, { 11, -153, -153, -153, -153, -153, -153, -153, -153, -153, -153, -153, -153, 58, -153, -153, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 167, 58, -153 + 58, 58, 58, 58, 174, 58, 58, -153 }, { 11, -154, -154, -154, -154, -154, -154, -154, -154, -154, -154, -154, -154, 58, -154, -154, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 168, 58, 58, - 58, 58, 58, 58, 58, 58, -154 + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -154 }, { 11, -155, -155, -155, -155, -155, -155, -155, -155, -155, -155, -155, -155, 58, -155, -155, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 169, 58, 58, - 58, 58, 58, 58, 58, 58, -155 + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 175, 58, 58, 58, 58, -155 }, { 11, -156, -156, -156, -156, -156, -156, -156, -156, -156, - -156, -156, -156, 58, -156, -156, 170, 58, 58, 58, + -156, -156, -156, 58, -156, -156, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -156 + 58, 58, 58, 58, 176, 58, 58, -156 }, { 11, -157, -157, -157, -157, -157, -157, -157, -157, -157, -157, -157, -157, 58, -157, -157, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -157 + 58, 177, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -157 }, { 11, -158, -158, -158, -158, -158, -158, -158, -158, -158, -158, -158, -158, 58, -158, -158, 58, 58, 58, 58, - 171, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -158 + 58, 58, 58, 178, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -158 }, { 11, -159, -159, -159, -159, -159, -159, -159, -159, -159, - -159, -159, -159, 58, -159, -159, 58, 58, 58, 58, + -159, -159, -159, 58, -159, -159, 58, 179, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -159 + 58, 58, 58, 58, 58, 58, 58, -159 }, { 11, -160, -160, -160, -160, -160, -160, -160, -160, -160, -160, -160, -160, 58, -160, -160, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -160 + 58, 58, 58, 58, 58, 58, 58, 58, 180, 58, + 58, 58, 58, 58, 58, 58, 58, -160 }, { 11, -161, -161, -161, -161, -161, -161, -161, -161, -161, -161, -161, -161, 58, -161, -161, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 172, 58, 58, -161 + 58, 58, 58, 58, 58, 58, 58, -161 }, { @@ -1493,36 +1543,36 @@ -162, -162, -162, 58, -162, -162, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -162 + 58, 58, 58, 58, 181, 58, 58, -162 }, { 11, -163, -163, -163, -163, -163, -163, -163, -163, -163, -163, -163, -163, 58, -163, -163, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -163 + 58, 58, 58, 58, 58, 58, 58, -163 }, { 11, -164, -164, -164, -164, -164, -164, -164, -164, -164, -164, -164, -164, 58, -164, -164, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -164 + 58, 58, 58, 58, 58, 58, 58, 58, 58, 182, + 58, 58, 58, 58, 58, 58, 58, -164 }, { 11, -165, -165, -165, -165, -165, -165, -165, -165, -165, -165, -165, -165, 58, -165, -165, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -165 + 58, 58, 58, 58, 58, 183, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -165 }, { 11, -166, -166, -166, -166, -166, -166, -166, -166, -166, - -166, -166, -166, 58, -166, -166, 58, 58, 173, 58, + -166, -166, -166, 58, -166, -166, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -166 + 58, 58, 58, 58, 184, 58, 58, -166 }, { @@ -1530,73 +1580,73 @@ -167, -167, -167, 58, -167, -167, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -167 + 58, 58, 58, 185, 58, 58, 58, -167 }, { 11, -168, -168, -168, -168, -168, -168, -168, -168, -168, -168, -168, -168, 58, -168, -168, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 174, 58, -168 + 58, 58, 58, 58, 58, 58, 58, -168 }, { 11, -169, -169, -169, -169, -169, -169, -169, -169, -169, -169, -169, -169, 58, -169, -169, 58, 58, 58, 58, - 58, 175, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -169 + 58, 58, 58, 58, 58, 186, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -169 }, { 11, -170, -170, -170, -170, -170, -170, -170, -170, -170, -170, -170, -170, 58, -170, -170, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 176, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -170 + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 187, 58, -170 }, { 11, -171, -171, -171, -171, -171, -171, -171, -171, -171, -171, -171, -171, 58, -171, -171, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 177, 58, 58, 58, -171 + 58, 58, 58, 58, 58, 58, 58, 58, 188, 58, + 58, 58, 58, 58, 58, 58, 58, -171 }, { 11, -172, -172, -172, -172, -172, -172, -172, -172, -172, -172, -172, -172, 58, -172, -172, 58, 58, 58, 58, - 178, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -172 + 58, 58, 58, 58, 58, 58, 58, 58, 189, 58, + 58, 58, 58, 58, 58, 58, 58, -172 }, { 11, -173, -173, -173, -173, -173, -173, -173, -173, -173, - -173, -173, -173, 58, -173, -173, 58, 58, 58, 58, - 179, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -173 + -173, -173, -173, 58, -173, -173, 58, 190, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -173 }, { 11, -174, -174, -174, -174, -174, -174, -174, -174, -174, -174, -174, -174, 58, -174, -174, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -174 + 58, 58, 58, 58, 58, 58, 58, -174 }, { 11, -175, -175, -175, -175, -175, -175, -175, -175, -175, -175, -175, -175, 58, -175, -175, 58, 58, 58, 58, - 58, 58, 58, 58, 180, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -175 + 58, 191, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -175 }, { 11, -176, -176, -176, -176, -176, -176, -176, -176, -176, -176, -176, -176, 58, -176, -176, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -176 + 58, 58, 58, 58, 58, 58, 58, -176 }, { @@ -1604,83 +1654,307 @@ -177, -177, -177, 58, -177, -177, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -177 + 58, 58, 58, 58, 58, 58, 58, -177 }, { 11, -178, -178, -178, -178, -178, -178, -178, -178, -178, -178, -178, -178, 58, -178, -178, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -178 + 58, 58, 58, 58, 58, 58, 58, -178 }, { 11, -179, -179, -179, -179, -179, -179, -179, -179, -179, -179, -179, -179, 58, -179, -179, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -179 + 58, 58, 58, 58, 192, 58, 58, -179 }, { 11, -180, -180, -180, -180, -180, -180, -180, -180, -180, -180, -180, -180, 58, -180, -180, 58, 58, 58, 58, - 58, 58, 181, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -180 + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -180 }, { 11, -181, -181, -181, -181, -181, -181, -181, -181, -181, -181, -181, -181, 58, -181, -181, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, - 58, 58, 58, 58, 58, 58, -181 + 58, 58, 58, 58, 58, 58, 58, -181 }, - } ; + { + 11, -182, -182, -182, -182, -182, -182, -182, -182, -182, + -182, -182, -182, 58, -182, -182, 58, 58, 58, 58, + + 58, 58, 58, 58, 58, 58, 193, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -182 + }, + + { + 11, -183, -183, -183, -183, -183, -183, -183, -183, -183, + -183, -183, -183, 58, -183, -183, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 194, 58, 58, 58, -183 + }, + + { + 11, -184, -184, -184, -184, -184, -184, -184, -184, -184, + -184, -184, -184, 58, -184, -184, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -184 + + }, + + { + 11, -185, -185, -185, -185, -185, -185, -185, -185, -185, + -185, -185, -185, 58, -185, -185, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -185 + }, + + { + 11, -186, -186, -186, -186, -186, -186, -186, -186, -186, + -186, -186, -186, 58, -186, -186, 58, 58, 58, 195, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -186 + }, + + { + 11, -187, -187, -187, -187, -187, -187, -187, -187, -187, + -187, -187, -187, 58, -187, -187, 58, 58, 58, 58, + + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -187 + }, + + { + 11, -188, -188, -188, -188, -188, -188, -188, -188, -188, + -188, -188, -188, 58, -188, -188, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 196, 58, -188 + }, + + { + 11, -189, -189, -189, -189, -189, -189, -189, -189, -189, + -189, -189, -189, 58, -189, -189, 58, 58, 58, 58, + 58, 58, 197, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -189 + }, + + { + 11, -190, -190, -190, -190, -190, -190, -190, -190, -190, + -190, -190, -190, 58, -190, -190, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 198, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -190 + }, + + { + 11, -191, -191, -191, -191, -191, -191, -191, -191, -191, + -191, -191, -191, 58, -191, -191, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 199, 58, 58, 58, -191 + }, + + { + 11, -192, -192, -192, -192, -192, -192, -192, -192, -192, + -192, -192, -192, 58, -192, -192, 58, 58, 58, 58, -static yy_state_type yy_get_previous_state YY_PROTO(( void )); -static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state )); -static int yy_get_next_buffer YY_PROTO(( void )); -static void yy_fatal_error YY_PROTO(( yyconst char msg[] )); + 58, 200, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -192 + }, + + { + 11, -193, -193, -193, -193, -193, -193, -193, -193, -193, + -193, -193, -193, 58, -193, -193, 58, 58, 58, 58, + 58, 201, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -193 + }, + + { + 11, -194, -194, -194, -194, -194, -194, -194, -194, -194, + -194, -194, -194, 58, -194, -194, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 202, 58, 58, -194 + + }, + + { + 11, -195, -195, -195, -195, -195, -195, -195, -195, -195, + -195, -195, -195, 58, -195, -195, 58, 58, 58, 58, + 58, 203, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -195 + }, + + { + 11, -196, -196, -196, -196, -196, -196, -196, -196, -196, + -196, -196, -196, 58, -196, -196, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -196 + }, + + { + 11, -197, -197, -197, -197, -197, -197, -197, -197, -197, + -197, -197, -197, 58, -197, -197, 58, 58, 58, 58, + + 58, 58, 58, 58, 58, 204, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -197 + }, + + { + 11, -198, -198, -198, -198, -198, -198, -198, -198, -198, + -198, -198, -198, 58, -198, -198, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -198 + }, + + { + 11, -199, -199, -199, -199, -199, -199, -199, -199, -199, + -199, -199, -199, 58, -199, -199, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -199 + + }, + + { + 11, -200, -200, -200, -200, -200, -200, -200, -200, -200, + -200, -200, -200, 58, -200, -200, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -200 + }, + + { + 11, -201, -201, -201, -201, -201, -201, -201, -201, -201, + -201, -201, -201, 58, -201, -201, 58, 205, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -201 + }, + + { + 11, -202, -202, -202, -202, -202, -202, -202, -202, -202, + -202, -202, -202, 58, -202, -202, 58, 206, 58, 58, + + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -202 + }, + + { + 11, -203, -203, -203, -203, -203, -203, -203, -203, -203, + -203, -203, -203, 58, -203, -203, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -203 + }, + + { + 11, -204, -204, -204, -204, -204, -204, -204, -204, -204, + -204, -204, -204, 58, -204, -204, 58, 58, 58, 58, + 58, 58, 58, 207, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -204 + + }, + + { + 11, -205, -205, -205, -205, -205, -205, -205, -205, -205, + -205, -205, -205, 58, -205, -205, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 208, 58, + 58, 58, 58, 58, 58, 58, 58, -205 + }, + + { + 11, -206, -206, -206, -206, -206, -206, -206, -206, -206, + -206, -206, -206, 58, -206, -206, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 209, 58, 58, -206 + }, + + { + 11, -207, -207, -207, -207, -207, -207, -207, -207, -207, + -207, -207, -207, 58, -207, -207, 58, 58, 58, 58, + + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -207 + }, + + { + 11, -208, -208, -208, -208, -208, -208, -208, -208, -208, + -208, -208, -208, 58, -208, -208, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -208 + }, + + { + 11, -209, -209, -209, -209, -209, -209, -209, -209, -209, + -209, -209, -209, 58, -209, -209, 58, 58, 58, 58, + 58, 210, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -209 + + }, + + { + 11, -210, -210, -210, -210, -210, -210, -210, -210, -210, + -210, -210, -210, 58, -210, -210, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + 58, 58, 58, 58, 58, 58, 58, -210 + }, + + } ; + +static yy_state_type yy_get_previous_state (void ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); +static int yy_get_next_buffer (void ); +static void yy_fatal_error (yyconst char msg[] ); /* Done after the current pattern has been matched and before the - * corresponding action - sets up yytext. + * corresponding action - sets up zconftext. */ #define YY_DO_BEFORE_ACTION \ - yytext_ptr = yy_bp; \ - yyleng = (int) (yy_cp - yy_bp); \ - yy_hold_char = *yy_cp; \ + (yytext_ptr) = yy_bp; \ + zconfleng = (size_t) (yy_cp - yy_bp); \ + (yy_hold_char) = *yy_cp; \ *yy_cp = '\0'; \ - yy_c_buf_p = yy_cp; + (yy_c_buf_p) = yy_cp; -#define YY_NUM_RULES 58 -#define YY_END_OF_BUFFER 59 -static yyconst short int yy_accept[182] = +#define YY_NUM_RULES 64 +#define YY_END_OF_BUFFER 65 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static yyconst flex_int16_t yy_accept[211] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 59, 5, 4, 3, 2, 30, 31, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, - 57, 54, 56, 49, 53, 52, 51, 47, 42, 36, - 41, 45, 47, 34, 35, 44, 44, 37, 47, 44, - 44, 47, 4, 3, 2, 2, 1, 29, 29, 29, - 29, 29, 29, 29, 16, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 57, 54, 56, 55, 49, 48, - 51, 50, 38, 45, 32, 44, 44, 46, 39, 40, - 33, 29, 29, 29, 29, 29, 29, 29, 29, 27, - - 26, 29, 29, 29, 29, 29, 29, 29, 29, 43, - 24, 29, 29, 29, 29, 29, 29, 29, 29, 15, - 29, 7, 29, 29, 29, 29, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 17, 29, 29, 29, 29, - 29, 29, 29, 29, 29, 29, 10, 29, 13, 29, - 29, 29, 29, 29, 29, 29, 22, 29, 9, 28, - 29, 25, 12, 21, 18, 29, 8, 29, 29, 29, - 29, 29, 29, 6, 29, 20, 19, 23, 11, 29, - 14 + 65, 5, 4, 3, 2, 36, 37, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 63, 60, 62, 55, 59, 58, 57, 53, 48, 42, + 47, 51, 53, 40, 41, 50, 50, 43, 53, 50, + 50, 53, 4, 3, 2, 2, 1, 35, 35, 35, + 35, 35, 35, 35, 16, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 63, 60, 62, 61, + 55, 54, 57, 56, 44, 51, 38, 50, 50, 52, + 45, 46, 39, 35, 35, 35, 35, 35, 35, 35, + + 35, 35, 30, 29, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 49, 25, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 15, 35, 7, 35, + 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 35, 35, 35, 17, 35, 35, + 35, 35, 35, 34, 35, 35, 35, 35, 35, 35, + 10, 35, 13, 35, 35, 35, 35, 33, 35, 35, + 35, 35, 35, 22, 35, 32, 9, 31, 35, 26, + 12, 35, 35, 21, 18, 35, 8, 35, 35, 35, + 35, 35, 27, 35, 35, 6, 35, 20, 19, 23, + + 35, 35, 11, 35, 35, 35, 14, 28, 35, 24 } ; -static yyconst int yy_ec[256] = +static yyconst flex_int32_t yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -1691,11 +1965,11 @@ 14, 1, 1, 1, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, - 1, 15, 1, 1, 13, 1, 16, 17, 18, 19, + 1, 15, 1, 1, 16, 1, 17, 18, 19, 20, - 20, 21, 22, 23, 24, 13, 13, 25, 26, 27, - 28, 29, 30, 31, 32, 33, 34, 13, 13, 35, - 13, 13, 1, 36, 1, 1, 1, 1, 1, 1, + 21, 22, 23, 24, 25, 13, 13, 26, 27, 28, + 29, 30, 31, 32, 33, 34, 35, 13, 13, 36, + 13, 13, 1, 37, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -1712,6 +1986,9 @@ 1, 1, 1, 1, 1 } ; +extern int zconf_flex_debug; +int zconf_flex_debug = 0; + /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ @@ -1719,13 +1996,7 @@ #define yymore() yymore_used_but_not_detected #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET -char *yytext; -#define INITIAL 0 -#define YY_NEVER_INTERACTIVE 1 -#define COMMAND 1 -#define HELP 2 -#define STRING 3 -#define PARAM 4 +char *zconftext; /* * Copyright (C) 2002 Roman Zippel <zippel@linux-m68k.org> @@ -1789,71 +2060,52 @@ text[size] = 0; } +#define INITIAL 0 +#define COMMAND 1 +#define HELP 2 +#define STRING 3 +#define PARAM 4 + +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include <unistd.h> + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus -extern "C" int yywrap YY_PROTO(( void )); +extern "C" int zconfwrap (void ); #else -extern int yywrap YY_PROTO(( void )); +extern int zconfwrap (void ); #endif #endif -#ifndef YY_NO_UNPUT -static void yyunput YY_PROTO(( int c, char *buf_ptr )); -#endif - + static void yyunput (int c,char *buf_ptr ); + #ifndef yytext_ptr -static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int )); +static void yy_flex_strncpy (char *,yyconst char *,int ); #endif #ifdef YY_NEED_STRLEN -static int yy_flex_strlen YY_PROTO(( yyconst char * )); +static int yy_flex_strlen (yyconst char * ); #endif #ifndef YY_NO_INPUT -#ifdef __cplusplus -static int yyinput YY_PROTO(( void )); -#else -static int input YY_PROTO(( void )); -#endif -#endif - -#if YY_STACK_USED -static int yy_start_stack_ptr = 0; -static int yy_start_stack_depth = 0; -static int *yy_start_stack = 0; -#ifndef YY_NO_PUSH_STATE -static void yy_push_state YY_PROTO(( int new_state )); -#endif -#ifndef YY_NO_POP_STATE -static void yy_pop_state YY_PROTO(( void )); -#endif -#ifndef YY_NO_TOP_STATE -static int yy_top_state YY_PROTO(( void )); -#endif +#ifdef __cplusplus +static int yyinput (void ); #else -#define YY_NO_PUSH_STATE 1 -#define YY_NO_POP_STATE 1 -#define YY_NO_TOP_STATE 1 +static int input (void ); #endif -#ifdef YY_MALLOC_DECL -YY_MALLOC_DECL -#else -#if __STDC__ -#ifndef __cplusplus -#include <stdlib.h> -#endif -#else -/* Just try to get by without declaring the routines. This will fail - * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int) - * or sizeof(void*) != sizeof(int). - */ -#endif #endif /* Amount of stuff to slurp up with each read. */ @@ -1862,12 +2114,11 @@ #endif /* Copy whatever the last rule matched to the standard output. */ - #ifndef ECHO /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ -#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) +#define ECHO (void) fwrite( zconftext, zconfleng, 1, zconfout ) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, @@ -1876,7 +2127,7 @@ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ errno=0; \ - while ( (result = read( fileno(yyin), (char *) buf, max_size )) < 0 ) \ + while ( (result = read( fileno(zconfin), (char *) buf, max_size )) < 0 ) \ { \ if( errno != EINTR) \ { \ @@ -1884,8 +2135,10 @@ break; \ } \ errno=0; \ - clearerr(yyin); \ - } + clearerr(zconfin); \ + }\ +\ + #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - @@ -1906,14 +2159,20 @@ #define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) #endif +/* end tables serialization structures and prototypes */ + /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL -#define YY_DECL int yylex YY_PROTO(( void )) -#endif +#define YY_DECL_IS_OURS 1 -/* Code executed at the beginning of each rule, after yytext and yyleng +extern int zconflex (void); + +#define YY_DECL int zconflex (void) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after zconftext and zconfleng * have been set up. */ #ifndef YY_USER_ACTION @@ -1928,56 +2187,58 @@ #define YY_RULE_SETUP \ YY_USER_ACTION +/** The main scanner function which does all the work. + */ YY_DECL - { +{ register yy_state_type yy_current_state; register char *yy_cp, *yy_bp; register int yy_act; - - + int str = 0; int ts, i; - - if ( yy_init ) + if ( (yy_init) ) { - yy_init = 0; + (yy_init) = 0; #ifdef YY_USER_INIT YY_USER_INIT; #endif - if ( ! yy_start ) - yy_start = 1; /* first start state */ + if ( ! (yy_start) ) + (yy_start) = 1; /* first start state */ - if ( ! yyin ) - yyin = stdin; + if ( ! zconfin ) + zconfin = stdin; - if ( ! yyout ) - yyout = stdout; + if ( ! zconfout ) + zconfout = stdout; - if ( ! yy_current_buffer ) - yy_current_buffer = - yy_create_buffer( yyin, YY_BUF_SIZE ); + if ( ! YY_CURRENT_BUFFER ) { + zconfensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + zconf_create_buffer(zconfin,YY_BUF_SIZE ); + } - yy_load_buffer_state(); + zconf_load_buffer_state( ); } while ( 1 ) /* loops until end-of-file is reached */ { - yy_cp = yy_c_buf_p; + yy_cp = (yy_c_buf_p); - /* Support of yytext. */ - *yy_cp = yy_hold_char; + /* Support of zconftext. */ + *yy_cp = (yy_hold_char); /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; - yy_current_state = yy_start; + yy_current_state = (yy_start); yy_match: - while ( (yy_current_state = yy_nxt[yy_current_state][yy_ec[YY_SC_TO_UI(*yy_cp)]]) > 0 ) + while ( (yy_current_state = yy_nxt[yy_current_state][ yy_ec[YY_SC_TO_UI(*yy_cp)] ]) > 0 ) ++yy_cp; yy_current_state = -yy_current_state; @@ -1987,13 +2248,12 @@ YY_DO_BEFORE_ACTION; - do_action: /* This label is used only to access EOF actions. */ - switch ( yy_act ) { /* beginning of action switch */ case 1: +/* rule 1 can match eol */ YY_RULE_SETUP current_file->lineno++; YY_BREAK @@ -2002,6 +2262,7 @@ YY_BREAK case 3: +/* rule 3 can match eol */ YY_RULE_SETUP current_file->lineno++; return T_EOL; YY_BREAK @@ -2014,7 +2275,7 @@ case 5: YY_RULE_SETUP { - unput(yytext[0]); + unput(zconftext[0]); BEGIN(COMMAND); } YY_BREAK @@ -2093,7 +2354,7 @@ YY_BREAK case 24: YY_RULE_SETUP -BEGIN(PARAM); return T_BOOLEAN; +BEGIN(PARAM); return T_DEF_TRISTATE; YY_BREAK case 25: YY_RULE_SETUP @@ -2101,103 +2362,129 @@ YY_BREAK case 26: YY_RULE_SETUP -BEGIN(PARAM); return T_INT; +BEGIN(PARAM); return T_BOOLEAN; YY_BREAK case 27: YY_RULE_SETUP -BEGIN(PARAM); return T_HEX; +BEGIN(PARAM); return T_DEF_BOOLEAN; YY_BREAK case 28: YY_RULE_SETUP -BEGIN(PARAM); return T_STRING; +BEGIN(PARAM); return T_DEF_BOOLEAN; YY_BREAK case 29: YY_RULE_SETUP +BEGIN(PARAM); return T_INT; + YY_BREAK +case 30: +YY_RULE_SETUP +BEGIN(PARAM); return T_HEX; + YY_BREAK +case 31: +YY_RULE_SETUP +BEGIN(PARAM); return T_STRING; + YY_BREAK +case 32: +YY_RULE_SETUP +BEGIN(PARAM); return T_SELECT; + YY_BREAK +case 33: +YY_RULE_SETUP +BEGIN(PARAM); return T_SELECT; + YY_BREAK +case 34: +YY_RULE_SETUP +BEGIN(PARAM); return T_RANGE; + YY_BREAK +case 35: +YY_RULE_SETUP { - alloc_string(yytext, yyleng); + alloc_string(zconftext, zconfleng); zconflval.string = text; return T_WORD; } YY_BREAK -case 30: +case 36: YY_RULE_SETUP YY_BREAK -case 31: +case 37: +/* rule 37 can match eol */ YY_RULE_SETUP current_file->lineno++; BEGIN(INITIAL); YY_BREAK - -case 32: +case 38: YY_RULE_SETUP return T_AND; YY_BREAK -case 33: +case 39: YY_RULE_SETUP return T_OR; YY_BREAK -case 34: +case 40: YY_RULE_SETUP return T_OPEN_PAREN; YY_BREAK -case 35: +case 41: YY_RULE_SETUP return T_CLOSE_PAREN; YY_BREAK -case 36: +case 42: YY_RULE_SETUP return T_NOT; YY_BREAK -case 37: +case 43: YY_RULE_SETUP return T_EQUAL; YY_BREAK -case 38: +case 44: YY_RULE_SETUP return T_UNEQUAL; YY_BREAK -case 39: +case 45: YY_RULE_SETUP return T_IF; YY_BREAK -case 40: +case 46: YY_RULE_SETUP return T_ON; YY_BREAK -case 41: +case 47: YY_RULE_SETUP { - str = yytext[0]; + str = zconftext[0]; new_string(); BEGIN(STRING); } YY_BREAK -case 42: +case 48: +/* rule 48 can match eol */ YY_RULE_SETUP BEGIN(INITIAL); current_file->lineno++; return T_EOL; YY_BREAK -case 43: +case 49: YY_RULE_SETUP /* ignore */ YY_BREAK -case 44: +case 50: YY_RULE_SETUP { - alloc_string(yytext, yyleng); + alloc_string(zconftext, zconfleng); zconflval.string = text; return T_WORD; } YY_BREAK -case 45: +case 51: YY_RULE_SETUP /* comment */ YY_BREAK -case 46: +case 52: +/* rule 52 can match eol */ YY_RULE_SETUP current_file->lineno++; YY_BREAK -case 47: +case 53: YY_RULE_SETUP YY_BREAK @@ -2207,53 +2494,55 @@ } YY_BREAK - -case 48: -*yy_cp = yy_hold_char; /* undo effects of setting up yytext */ -yy_c_buf_p = yy_cp -= 1; -YY_DO_BEFORE_ACTION; /* set up yytext again */ +case 54: +/* rule 54 can match eol */ +*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */ +(yy_c_buf_p) = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up zconftext again */ YY_RULE_SETUP { - append_string(yytext, yyleng); + append_string(zconftext, zconfleng); zconflval.string = text; return T_WORD_QUOTE; } YY_BREAK -case 49: +case 55: YY_RULE_SETUP { - append_string(yytext, yyleng); + append_string(zconftext, zconfleng); } YY_BREAK -case 50: -*yy_cp = yy_hold_char; /* undo effects of setting up yytext */ -yy_c_buf_p = yy_cp -= 1; -YY_DO_BEFORE_ACTION; /* set up yytext again */ +case 56: +/* rule 56 can match eol */ +*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */ +(yy_c_buf_p) = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up zconftext again */ YY_RULE_SETUP { - append_string(yytext + 1, yyleng - 1); + append_string(zconftext + 1, zconfleng - 1); zconflval.string = text; return T_WORD_QUOTE; } YY_BREAK -case 51: +case 57: YY_RULE_SETUP { - append_string(yytext + 1, yyleng - 1); + append_string(zconftext + 1, zconfleng - 1); } YY_BREAK -case 52: +case 58: YY_RULE_SETUP { - if (str == yytext[0]) { + if (str == zconftext[0]) { BEGIN(PARAM); zconflval.string = text; return T_WORD_QUOTE; } else - append_string(yytext, 1); + append_string(zconftext, 1); } YY_BREAK -case 53: +case 59: +/* rule 59 can match eol */ YY_RULE_SETUP { printf("%s:%d:warning: multi-line strings not supported\n", zconf_curname(), zconf_lineno()); @@ -2268,13 +2557,12 @@ } YY_BREAK - -case 54: +case 60: YY_RULE_SETUP { ts = 0; - for (i = 0; i < yyleng; i++) { - if (yytext[i] == '\t') + for (i = 0; i < zconfleng; i++) { + if (zconftext[i] == '\t') ts = (ts & ~7) + 8; else ts++; @@ -2292,13 +2580,13 @@ } append_string(" ", ts); } - } YY_BREAK -case 55: -*yy_cp = yy_hold_char; /* undo effects of setting up yytext */ -yy_c_buf_p = yy_cp -= 1; -YY_DO_BEFORE_ACTION; /* set up yytext again */ +case 61: +/* rule 61 can match eol */ +*yy_cp = (yy_hold_char); /* undo effects of setting up zconftext */ +(yy_c_buf_p) = yy_cp -= 1; +YY_DO_BEFORE_ACTION; /* set up zconftext again */ YY_RULE_SETUP { current_file->lineno++; @@ -2306,17 +2594,18 @@ return T_HELPTEXT; } YY_BREAK -case 56: +case 62: +/* rule 62 can match eol */ YY_RULE_SETUP { current_file->lineno++; append_string("\n", 1); } YY_BREAK -case 57: +case 63: YY_RULE_SETUP { - append_string(yytext, yyleng); + append_string(zconftext, zconfleng); if (!first_ts) first_ts = last_ts; } @@ -2335,11 +2624,11 @@ zconf_endfile(); return T_EOF; } - fclose(yyin); + fclose(zconfin); yyterminate(); } YY_BREAK -case 58: +case 64: YY_RULE_SETUP YY_FATAL_ERROR( "flex scanner jammed" ); YY_BREAK @@ -2347,26 +2636,26 @@ case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ - int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1; + int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ - *yy_cp = yy_hold_char; + *yy_cp = (yy_hold_char); YY_RESTORE_YY_MORE_OFFSET - if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW ) + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user - * just pointed yyin at a new source and called - * yylex(). If so, then we have to assure - * consistency between yy_current_buffer and our + * just pointed zconfin at a new source and called + * zconflex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ - yy_n_chars = yy_current_buffer->yy_n_chars; - yy_current_buffer->yy_input_file = yyin; - yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL; + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = zconfin; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position @@ -2376,13 +2665,13 @@ * end-of-buffer state). Contrast this with the test * in input(). */ - if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) { /* This was really a NUL. */ yy_state_type yy_next_state; - yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text; + (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; - yy_current_state = yy_get_previous_state(); + yy_current_state = yy_get_previous_state( ); /* Okay, we're now positioned to make the NUL * transition. We couldn't have @@ -2395,41 +2684,41 @@ yy_next_state = yy_try_NUL_trans( yy_current_state ); - yy_bp = yytext_ptr + YY_MORE_ADJ; + yy_bp = (yytext_ptr) + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ - yy_cp = ++yy_c_buf_p; + yy_cp = ++(yy_c_buf_p); yy_current_state = yy_next_state; goto yy_match; } else { - yy_cp = yy_c_buf_p; + yy_cp = (yy_c_buf_p); goto yy_find_action; } } - else switch ( yy_get_next_buffer() ) + else switch ( yy_get_next_buffer( ) ) { case EOB_ACT_END_OF_FILE: { - yy_did_buffer_switch_on_eof = 0; + (yy_did_buffer_switch_on_eof) = 0; - if ( yywrap() ) + if ( zconfwrap( ) ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up - * yytext, we can now set up + * zconftext, we can now set up * yy_c_buf_p so that if some total * hoser (like flex itself) wants to * call the scanner after we return the * YY_NULL, it'll still work - another * YY_NULL will get returned. */ - yy_c_buf_p = yytext_ptr + YY_MORE_ADJ; + (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; @@ -2437,30 +2726,30 @@ else { - if ( ! yy_did_buffer_switch_on_eof ) + if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: - yy_c_buf_p = - yytext_ptr + yy_amount_of_matched_text; + (yy_c_buf_p) = + (yytext_ptr) + yy_amount_of_matched_text; - yy_current_state = yy_get_previous_state(); + yy_current_state = yy_get_previous_state( ); - yy_cp = yy_c_buf_p; - yy_bp = yytext_ptr + YY_MORE_ADJ; + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: - yy_c_buf_p = - &yy_current_buffer->yy_ch_buf[yy_n_chars]; + (yy_c_buf_p) = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; - yy_current_state = yy_get_previous_state(); + yy_current_state = yy_get_previous_state( ); - yy_cp = yy_c_buf_p; - yy_bp = yytext_ptr + YY_MORE_ADJ; + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_find_action; } break; @@ -2471,8 +2760,7 @@ "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ - } /* end of yylex */ - +} /* end of zconflex */ /* yy_get_next_buffer - try to read in a new buffer * @@ -2481,21 +2769,20 @@ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ - -static int yy_get_next_buffer() - { - register char *dest = yy_current_buffer->yy_ch_buf; - register char *source = yytext_ptr; +static int yy_get_next_buffer (void) +{ + register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + register char *source = (yytext_ptr); register int number_to_move, i; int ret_val; - if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] ) + if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) YY_FATAL_ERROR( "fatal flex scanner internal error--end of buffer missed" ); - if ( yy_current_buffer->yy_fill_buffer == 0 ) + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) { /* Don't try to fill the buffer, so this is an EOF. */ - if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 ) + if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) { /* We matched a single character, the EOB, so * treat this as a final EOF. @@ -2515,34 +2802,30 @@ /* Try to read more data. */ /* First move last chars to start of buffer. */ - number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1; + number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); - if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ - yy_current_buffer->yy_n_chars = yy_n_chars = 0; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; else { - int num_to_read = - yy_current_buffer->yy_buf_size - number_to_move - 1; + size_t num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ -#ifdef YY_USES_REJECT - YY_FATAL_ERROR( -"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); -#else /* just a shorter name for the current buffer */ - YY_BUFFER_STATE b = yy_current_buffer; + YY_BUFFER_STATE b = YY_CURRENT_BUFFER; int yy_c_buf_p_offset = - (int) (yy_c_buf_p - b->yy_ch_buf); + (int) ((yy_c_buf_p) - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { @@ -2555,8 +2838,7 @@ b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ - yy_flex_realloc( (void *) b->yy_ch_buf, - b->yy_buf_size + 2 ); + zconfrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); } else /* Can't grow it, we don't own it. */ @@ -2566,35 +2848,35 @@ YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); - yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; - num_to_read = yy_current_buffer->yy_buf_size - + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; -#endif + } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ - YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), - yy_n_chars, num_to_read ); + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + (yy_n_chars), num_to_read ); - yy_current_buffer->yy_n_chars = yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } - if ( yy_n_chars == 0 ) + if ( (yy_n_chars) == 0 ) { if ( number_to_move == YY_MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; - yyrestart( yyin ); + zconfrestart(zconfin ); } else { ret_val = EOB_ACT_LAST_MATCH; - yy_current_buffer->yy_buffer_status = + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } @@ -2602,127 +2884,112 @@ else ret_val = EOB_ACT_CONTINUE_SCAN; - yy_n_chars += number_to_move; - yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR; - yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + (yy_n_chars) += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; - yytext_ptr = &yy_current_buffer->yy_ch_buf[0]; + (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; return ret_val; - } - +} /* yy_get_previous_state - get the state just before the EOB char was reached */ -static yy_state_type yy_get_previous_state() - { + static yy_state_type yy_get_previous_state (void) +{ register yy_state_type yy_current_state; register char *yy_cp; + + yy_current_state = (yy_start); - yy_current_state = yy_start; - - for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp ) + for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) { yy_current_state = yy_nxt[yy_current_state][(*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1)]; } return yy_current_state; - } - +} /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ - -#ifdef YY_USE_PROTOS -static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state ) -#else -static yy_state_type yy_try_NUL_trans( yy_current_state ) -yy_state_type yy_current_state; -#endif - { + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) +{ register int yy_is_jam; - + yy_current_state = yy_nxt[yy_current_state][1]; yy_is_jam = (yy_current_state <= 0); return yy_is_jam ? 0 : yy_current_state; - } - +} -#ifndef YY_NO_UNPUT -#ifdef YY_USE_PROTOS -static void yyunput( int c, register char *yy_bp ) -#else -static void yyunput( c, yy_bp ) -int c; -register char *yy_bp; -#endif - { - register char *yy_cp = yy_c_buf_p; + static void yyunput (int c, register char * yy_bp ) +{ + register char *yy_cp; + + yy_cp = (yy_c_buf_p); - /* undo effects of setting up yytext */ - *yy_cp = yy_hold_char; + /* undo effects of setting up zconftext */ + *yy_cp = (yy_hold_char); - if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) { /* need to shift things up to make room */ /* +2 for EOB chars. */ - register int number_to_move = yy_n_chars + 2; - register char *dest = &yy_current_buffer->yy_ch_buf[ - yy_current_buffer->yy_buf_size + 2]; + register int number_to_move = (yy_n_chars) + 2; + register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ + YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; register char *source = - &yy_current_buffer->yy_ch_buf[number_to_move]; + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; - while ( source > yy_current_buffer->yy_ch_buf ) + while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) *--dest = *--source; yy_cp += (int) (dest - source); yy_bp += (int) (dest - source); - yy_current_buffer->yy_n_chars = - yy_n_chars = yy_current_buffer->yy_buf_size; + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; - if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) YY_FATAL_ERROR( "flex scanner push-back overflow" ); } *--yy_cp = (char) c; + (yytext_ptr) = yy_bp; + (yy_hold_char) = *yy_cp; + (yy_c_buf_p) = yy_cp; +} - yytext_ptr = yy_bp; - yy_hold_char = *yy_cp; - yy_c_buf_p = yy_cp; - } -#endif /* ifndef YY_NO_UNPUT */ - - +#ifndef YY_NO_INPUT #ifdef __cplusplus -static int yyinput() + static int yyinput (void) #else -static int input() + static int input (void) #endif - { - int c; - *yy_c_buf_p = yy_hold_char; +{ + int c; + + *(yy_c_buf_p) = (yy_hold_char); - if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ - if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) /* This was really a NUL. */ - *yy_c_buf_p = '\0'; + *(yy_c_buf_p) = '\0'; else { /* need more input */ - int offset = yy_c_buf_p - yytext_ptr; - ++yy_c_buf_p; + int offset = (yy_c_buf_p) - (yytext_ptr); + ++(yy_c_buf_p); - switch ( yy_get_next_buffer() ) + switch ( yy_get_next_buffer( ) ) { case EOB_ACT_LAST_MATCH: /* This happens because yy_g_n_b() @@ -2736,16 +3003,16 @@ */ /* Reset buffer status. */ - yyrestart( yyin ); + zconfrestart(zconfin ); - /* fall through */ + /*FALLTHROUGH*/ case EOB_ACT_END_OF_FILE: { - if ( yywrap() ) + if ( zconfwrap( ) ) return EOF; - if ( ! yy_did_buffer_switch_on_eof ) + if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; #ifdef __cplusplus return yyinput(); @@ -2755,176 +3022,165 @@ } case EOB_ACT_CONTINUE_SCAN: - yy_c_buf_p = yytext_ptr + offset; + (yy_c_buf_p) = (yytext_ptr) + offset; break; } } } - c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */ - *yy_c_buf_p = '\0'; /* preserve yytext */ - yy_hold_char = *++yy_c_buf_p; - + c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ + *(yy_c_buf_p) = '\0'; /* preserve zconftext */ + (yy_hold_char) = *++(yy_c_buf_p); return c; - } - - -#ifdef YY_USE_PROTOS -void yyrestart( FILE *input_file ) -#else -void yyrestart( input_file ) -FILE *input_file; -#endif - { - if ( ! yy_current_buffer ) - yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); +} +#endif /* ifndef YY_NO_INPUT */ - yy_init_buffer( yy_current_buffer, input_file ); - yy_load_buffer_state(); +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * + * @note This function does not reset the start condition to @c INITIAL . + */ + void zconfrestart (FILE * input_file ) +{ + + if ( ! YY_CURRENT_BUFFER ){ + zconfensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + zconf_create_buffer(zconfin,YY_BUF_SIZE ); } + zconf_init_buffer(YY_CURRENT_BUFFER,input_file ); + zconf_load_buffer_state( ); +} -#ifdef YY_USE_PROTOS -void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) -#else -void yy_switch_to_buffer( new_buffer ) -YY_BUFFER_STATE new_buffer; -#endif - { - if ( yy_current_buffer == new_buffer ) +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * + */ + void zconf_switch_to_buffer (YY_BUFFER_STATE new_buffer ) +{ + + /* TODO. We should be able to replace this entire function body + * with + * zconfpop_buffer_state(); + * zconfpush_buffer_state(new_buffer); + */ + zconfensure_buffer_stack (); + if ( YY_CURRENT_BUFFER == new_buffer ) return; - if ( yy_current_buffer ) + if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ - *yy_c_buf_p = yy_hold_char; - yy_current_buffer->yy_buf_pos = yy_c_buf_p; - yy_current_buffer->yy_n_chars = yy_n_chars; + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } - yy_current_buffer = new_buffer; - yy_load_buffer_state(); + YY_CURRENT_BUFFER_LVALUE = new_buffer; + zconf_load_buffer_state( ); /* We don't actually know whether we did this switch during - * EOF (yywrap()) processing, but the only time this flag - * is looked at is after yywrap() is called, so it's safe + * EOF (zconfwrap()) processing, but the only time this flag + * is looked at is after zconfwrap() is called, so it's safe * to go ahead and always set it. */ - yy_did_buffer_switch_on_eof = 1; - } - - -#ifdef YY_USE_PROTOS -void yy_load_buffer_state( void ) -#else -void yy_load_buffer_state() -#endif - { - yy_n_chars = yy_current_buffer->yy_n_chars; - yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos; - yyin = yy_current_buffer->yy_input_file; - yy_hold_char = *yy_c_buf_p; - } + (yy_did_buffer_switch_on_eof) = 1; +} +static void zconf_load_buffer_state (void) +{ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + zconfin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + (yy_hold_char) = *(yy_c_buf_p); +} -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_create_buffer( FILE *file, int size ) -#else -YY_BUFFER_STATE yy_create_buffer( file, size ) -FILE *file; -int size; -#endif - { +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * + * @return the allocated buffer state. + */ + YY_BUFFER_STATE zconf_create_buffer (FILE * file, int size ) +{ YY_BUFFER_STATE b; - - b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + + b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) - YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" ); b->yy_buf_size = size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ - b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 ); + b->yy_ch_buf = (char *) zconfalloc(b->yy_buf_size + 2 ); if ( ! b->yy_ch_buf ) - YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + YY_FATAL_ERROR( "out of dynamic memory in zconf_create_buffer()" ); b->yy_is_our_buffer = 1; - yy_init_buffer( b, file ); + zconf_init_buffer(b,file ); return b; - } - +} -#ifdef YY_USE_PROTOS -void yy_delete_buffer( YY_BUFFER_STATE b ) -#else -void yy_delete_buffer( b ) -YY_BUFFER_STATE b; -#endif - { +/** Destroy the buffer. + * @param b a buffer created with zconf_create_buffer() + * + */ + void zconf_delete_buffer (YY_BUFFER_STATE b ) +{ + if ( ! b ) return; - if ( b == yy_current_buffer ) - yy_current_buffer = (YY_BUFFER_STATE) 0; + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) - yy_flex_free( (void *) b->yy_ch_buf ); - - yy_flex_free( (void *) b ); - } - - -#ifndef _WIN32 -#include <unistd.h> -#else -#ifndef YY_ALWAYS_INTERACTIVE -#ifndef YY_NEVER_INTERACTIVE -extern int isatty YY_PROTO(( int )); -#endif -#endif -#endif + zconffree((void *) b->yy_ch_buf ); -#ifdef YY_USE_PROTOS -void yy_init_buffer( YY_BUFFER_STATE b, FILE *file ) -#else -void yy_init_buffer( b, file ) -YY_BUFFER_STATE b; -FILE *file; -#endif + zconffree((void *) b ); +} +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a zconfrestart() or at EOF. + */ + static void zconf_init_buffer (YY_BUFFER_STATE b, FILE * file ) - { - yy_flush_buffer( b ); +{ + int oerrno = errno; + + zconf_flush_buffer(b ); b->yy_input_file = file; b->yy_fill_buffer = 1; -#if YY_ALWAYS_INTERACTIVE - b->yy_is_interactive = 1; -#else -#if YY_NEVER_INTERACTIVE - b->yy_is_interactive = 0; -#else - b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; -#endif -#endif - } - - -#ifdef YY_USE_PROTOS -void yy_flush_buffer( YY_BUFFER_STATE b ) -#else -void yy_flush_buffer( b ) -YY_BUFFER_STATE b; -#endif + /* If b is the current buffer, then zconf_init_buffer was _probably_ + * called from zconfrestart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = 0; + + errno = oerrno; +} - { - if ( ! b ) +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * + */ + void zconf_flush_buffer (YY_BUFFER_STATE b ) +{ + if ( ! b ) return; b->yy_n_chars = 0; @@ -2941,31 +3197,123 @@ b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; - if ( b == yy_current_buffer ) - yy_load_buffer_state(); + if ( b == YY_CURRENT_BUFFER ) + zconf_load_buffer_state( ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * + */ +void zconfpush_buffer_state (YY_BUFFER_STATE new_buffer ) +{ + if (new_buffer == NULL) + return; + + zconfensure_buffer_stack(); + + /* This block is copied from zconf_switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + (yy_buffer_stack_top)++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from zconf_switch_to_buffer. */ + zconf_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * + */ +void zconfpop_buffer_state (void) +{ + if (!YY_CURRENT_BUFFER) + return; + + zconf_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + if ((yy_buffer_stack_top) > 0) + --(yy_buffer_stack_top); + + if (YY_CURRENT_BUFFER) { + zconf_load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void zconfensure_buffer_stack (void) +{ + int num_to_alloc; + + if (!(yy_buffer_stack)) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; + (yy_buffer_stack) = (struct yy_buffer_state**)zconfalloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + ); + + memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + (yy_buffer_stack_max) = num_to_alloc; + (yy_buffer_stack_top) = 0; + return; } + if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ -#ifndef YY_NO_SCAN_BUFFER -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size ) -#else -YY_BUFFER_STATE yy_scan_buffer( base, size ) -char *base; -yy_size_t size; -#endif - { - YY_BUFFER_STATE b; + /* Increase the buffer to prepare for a possible push. */ + int grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = (yy_buffer_stack_max) + grow_size; + (yy_buffer_stack) = (struct yy_buffer_state**)zconfrealloc + ((yy_buffer_stack), + num_to_alloc * sizeof(struct yy_buffer_state*) + ); + + /* zero only the new slots.*/ + memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); + (yy_buffer_stack_max) = num_to_alloc; + } +} +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE zconf_scan_buffer (char * base, yy_size_t size ) +{ + YY_BUFFER_STATE b; + if ( size < 2 || base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ return 0; - b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + b = (YY_BUFFER_STATE) zconfalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) - YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_buffer()" ); b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; @@ -2977,58 +3325,53 @@ b->yy_fill_buffer = 0; b->yy_buffer_status = YY_BUFFER_NEW; - yy_switch_to_buffer( b ); + zconf_switch_to_buffer(b ); return b; - } -#endif - - -#ifndef YY_NO_SCAN_STRING -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str ) -#else -YY_BUFFER_STATE yy_scan_string( yy_str ) -yyconst char *yy_str; -#endif - { - int len; - for ( len = 0; yy_str[len]; ++len ) - ; - - return yy_scan_bytes( yy_str, len ); - } -#endif +} +/** Setup the input buffer state to scan a string. The next call to zconflex() will + * scan from a @e copy of @a str. + * @param str a NUL-terminated string to scan + * + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * zconf_scan_bytes() instead. + */ +YY_BUFFER_STATE zconf_scan_string (yyconst char * str ) +{ + + return zconf_scan_bytes(str,strlen(str) ); +} -#ifndef YY_NO_SCAN_BYTES -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len ) -#else -YY_BUFFER_STATE yy_scan_bytes( bytes, len ) -yyconst char *bytes; -int len; -#endif - { +/** Setup the input buffer state to scan the given bytes. The next call to zconflex() will + * scan from a @e copy of @a bytes. + * @param bytes the byte buffer to scan + * @param len the number of bytes in the buffer pointed to by @a bytes. + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE zconf_scan_bytes (yyconst char * bytes, int len ) +{ YY_BUFFER_STATE b; char *buf; yy_size_t n; int i; - + /* Get memory for full buffer, including space for trailing EOB's. */ n = len + 2; - buf = (char *) yy_flex_alloc( n ); + buf = (char *) zconfalloc(n ); if ( ! buf ) - YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + YY_FATAL_ERROR( "out of dynamic memory in zconf_scan_bytes()" ); for ( i = 0; i < len; ++i ) buf[i] = bytes[i]; buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; - b = yy_scan_buffer( buf, n ); + b = zconf_scan_buffer(buf,n ); if ( ! b ) - YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + YY_FATAL_ERROR( "bad buffer in zconf_scan_bytes()" ); /* It's okay to grow etc. this buffer, and we should throw it * away when we're done. @@ -3036,148 +3379,164 @@ b->yy_is_our_buffer = 1; return b; - } -#endif - +} -#ifndef YY_NO_PUSH_STATE -#ifdef YY_USE_PROTOS -static void yy_push_state( int new_state ) -#else -static void yy_push_state( new_state ) -int new_state; +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 #endif - { - if ( yy_start_stack_ptr >= yy_start_stack_depth ) - { - yy_size_t new_size; - yy_start_stack_depth += YY_START_STACK_INCR; - new_size = yy_start_stack_depth * sizeof( int ); - - if ( ! yy_start_stack ) - yy_start_stack = (int *) yy_flex_alloc( new_size ); +static void yy_fatal_error (yyconst char* msg ) +{ + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} - else - yy_start_stack = (int *) yy_flex_realloc( - (void *) yy_start_stack, new_size ); +/* Redefine yyless() so it works in section 3 code. */ - if ( ! yy_start_stack ) - YY_FATAL_ERROR( - "out of memory expanding start-condition stack" ); - } +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up zconftext. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + zconftext[zconfleng] = (yy_hold_char); \ + (yy_c_buf_p) = zconftext + yyless_macro_arg; \ + (yy_hold_char) = *(yy_c_buf_p); \ + *(yy_c_buf_p) = '\0'; \ + zconfleng = yyless_macro_arg; \ + } \ + while ( 0 ) - yy_start_stack[yy_start_stack_ptr++] = YY_START; +/* Accessor methods (get/set functions) to struct members. */ - BEGIN(new_state); - } -#endif +/** Get the current line number. + * + */ +int zconfget_lineno (void) +{ + + return zconflineno; +} +/** Get the input stream. + * + */ +FILE *zconfget_in (void) +{ + return zconfin; +} -#ifndef YY_NO_POP_STATE -static void yy_pop_state() - { - if ( --yy_start_stack_ptr < 0 ) - YY_FATAL_ERROR( "start-condition stack underflow" ); +/** Get the output stream. + * + */ +FILE *zconfget_out (void) +{ + return zconfout; +} - BEGIN(yy_start_stack[yy_start_stack_ptr]); - } -#endif +/** Get the length of the current token. + * + */ +int zconfget_leng (void) +{ + return zconfleng; +} +/** Get the current token. + * + */ -#ifndef YY_NO_TOP_STATE -static int yy_top_state() - { - return yy_start_stack[yy_start_stack_ptr - 1]; - } -#endif +char *zconfget_text (void) +{ + return zconftext; +} -#ifndef YY_EXIT_FAILURE -#define YY_EXIT_FAILURE 2 -#endif +/** Set the current line number. + * @param line_number + * + */ +void zconfset_lineno (int line_number ) +{ + + zconflineno = line_number; +} -#ifdef YY_USE_PROTOS -static void yy_fatal_error( yyconst char msg[] ) -#else -static void yy_fatal_error( msg ) -char msg[]; -#endif - { - (void) fprintf( stderr, "%s\n", msg ); - exit( YY_EXIT_FAILURE ); - } +/** Set the input stream. This does not discard the current + * input buffer. + * @param in_str A readable stream. + * + * @see zconf_switch_to_buffer + */ +void zconfset_in (FILE * in_str ) +{ + zconfin = in_str ; +} +void zconfset_out (FILE * out_str ) +{ + zconfout = out_str ; +} +int zconfget_debug (void) +{ + return zconf_flex_debug; +} -/* Redefine yyless() so it works in section 3 code. */ +void zconfset_debug (int bdebug ) +{ + zconf_flex_debug = bdebug ; +} -#undef yyless -#define yyless(n) \ - do \ - { \ - /* Undo effects of setting up yytext. */ \ - yytext[yyleng] = yy_hold_char; \ - yy_c_buf_p = yytext + n; \ - yy_hold_char = *yy_c_buf_p; \ - *yy_c_buf_p = '\0'; \ - yyleng = n; \ - } \ - while ( 0 ) +/* zconflex_destroy is for both reentrant and non-reentrant scanners. */ +int zconflex_destroy (void) +{ + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + zconf_delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + zconfpop_buffer_state(); + } + + /* Destroy the stack itself. */ + zconffree((yy_buffer_stack) ); + (yy_buffer_stack) = NULL; + return 0; +} -/* Internal utility routines. */ +/* + * Internal utility routines. + */ #ifndef yytext_ptr -#ifdef YY_USE_PROTOS -static void yy_flex_strncpy( char *s1, yyconst char *s2, int n ) -#else -static void yy_flex_strncpy( s1, s2, n ) -char *s1; -yyconst char *s2; -int n; -#endif - { +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) +{ register int i; - for ( i = 0; i < n; ++i ) + for ( i = 0; i < n; ++i ) s1[i] = s2[i]; - } +} #endif #ifdef YY_NEED_STRLEN -#ifdef YY_USE_PROTOS -static int yy_flex_strlen( yyconst char *s ) -#else -static int yy_flex_strlen( s ) -yyconst char *s; -#endif - { +static int yy_flex_strlen (yyconst char * s ) +{ register int n; - for ( n = 0; s[n]; ++n ) + for ( n = 0; s[n]; ++n ) ; return n; - } +} #endif - -#ifdef YY_USE_PROTOS -static void *yy_flex_alloc( yy_size_t size ) -#else -static void *yy_flex_alloc( size ) -yy_size_t size; -#endif - { +void *zconfalloc (yy_size_t size ) +{ return (void *) malloc( size ); - } +} -#ifdef YY_USE_PROTOS -static void *yy_flex_realloc( void *ptr, yy_size_t size ) -#else -static void *yy_flex_realloc( ptr, size ) -void *ptr; -yy_size_t size; -#endif - { +void *zconfrealloc (void * ptr, yy_size_t size ) +{ /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter @@ -3186,24 +3545,26 @@ * as though doing an assignment. */ return (void *) realloc( (char *) ptr, size ); - } +} -#ifdef YY_USE_PROTOS -static void yy_flex_free( void *ptr ) -#else -static void yy_flex_free( ptr ) -void *ptr; -#endif - { - free( ptr ); - } +void zconffree (void * ptr ) +{ + free( (char *) ptr ); /* see zconfrealloc() for (char *) cast */ +} -#if YY_MAIN -int main() - { - yylex(); - return 0; - } +#define YYTABLES_NAME "yytables" + +#undef YY_NEW_FILE +#undef YY_FLUSH_BUFFER +#undef yy_set_bol +#undef yy_new_buffer +#undef yy_set_interactive +#undef yytext_ptr +#undef YY_DO_BEFORE_ACTION + +#ifdef YY_DECL_IS_OURS +#undef YY_DECL_IS_OURS +#undef YY_DECL #endif void zconf_starthelp(void) @@ -3216,11 +3577,10 @@ static void zconf_endhelp(void) { zconflval.string = text; - BEGIN(INITIAL); + BEGIN(INITIAL); } - -/* +/* * Try to open specified file with following names: * ./name * $(srctree)/name @@ -3246,8 +3606,8 @@ void zconf_initscan(const char *name) { - yyin = zconf_fopen(name); - if (!yyin) { + zconfin = zconf_fopen(name); + if (!zconfin) { printf("can't find file %s\n", name); exit(1); } @@ -3267,12 +3627,12 @@ memset(buf, 0, sizeof(*buf)); current_buf->state = YY_CURRENT_BUFFER; - yyin = zconf_fopen(name); - if (!yyin) { + zconfin = zconf_fopen(name); + if (!zconfin) { printf("%s:%d: can't open file \"%s\"\n", zconf_curname(), zconf_lineno(), name); exit(1); } - yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); + zconf_switch_to_buffer(zconf_create_buffer(zconfin,YY_BUF_SIZE)); buf->parent = current_buf; current_buf = buf; @@ -3300,9 +3660,9 @@ parent = current_buf->parent; if (parent) { - fclose(yyin); - yy_delete_buffer(YY_CURRENT_BUFFER); - yy_switch_to_buffer(parent->state); + fclose(zconfin); + zconf_delete_buffer(YY_CURRENT_BUFFER); + zconf_switch_to_buffer(parent->state); } free(current_buf); current_buf = parent; @@ -3313,7 +3673,7 @@ int zconf_lineno(void) { if (current_buf) - return current_file->lineno; + return current_file->lineno - 1; else return 0; } @@ -3325,3 +3685,4 @@ else return "<none>"; } + diff -Nru a/scripts/kconfig/lkc.h b/scripts/kconfig/lkc.h --- a/scripts/kconfig/lkc.h Mon Jun 9 23:16:05 2003 +++ b/scripts/kconfig/lkc.h Mon Jun 9 23:16:05 2003 @@ -49,9 +49,11 @@ void menu_end_menu(void); void menu_add_entry(struct symbol *sym); void menu_end_entry(void); -struct property *create_prop(enum prop_type type); void menu_add_dep(struct expr *dep); -struct property *menu_add_prop(int token, char *prompt, struct symbol *def, struct expr *dep); +struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep); +void menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep); +void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep); +void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep); void menu_finalize(struct menu *parent); void menu_set_type(int type); struct file *file_lookup(const char *name); @@ -64,16 +66,19 @@ void sym_init(void); void sym_clear_all_valid(void); void sym_set_changed(struct symbol *sym); +struct symbol *sym_check_deps(struct symbol *sym); +struct property *prop_alloc(enum prop_type type, struct symbol *sym); +struct symbol *prop_get_symbol(struct property *prop); static inline tristate sym_get_tristate_value(struct symbol *sym) { - return S_TRI(sym->curr); + return sym->curr.tri; } static inline struct symbol *sym_get_choice_value(struct symbol *sym) { - return (struct symbol *)S_VAL(sym->curr); + return (struct symbol *)sym->curr.val; } static inline bool sym_set_choice_value(struct symbol *ch, struct symbol *chval) @@ -98,7 +103,6 @@ static inline bool sym_has_value(struct symbol *sym) { - //return S_VAL(sym->def) != NULL; return sym->flags & SYMBOL_NEW ? false : true; } diff -Nru a/scripts/kconfig/lkc_proto.h b/scripts/kconfig/lkc_proto.h --- a/scripts/kconfig/lkc_proto.h Mon Jun 9 23:16:09 2003 +++ b/scripts/kconfig/lkc_proto.h Mon Jun 9 23:16:09 2003 @@ -18,13 +18,14 @@ P(sym_lookup,struct symbol *,(const char *name, int isconst)); P(sym_find,struct symbol *,(const char *name)); -P(sym_type_name,const char *,(int type)); +P(sym_type_name,const char *,(enum symbol_type type)); P(sym_calc_value,void,(struct symbol *sym)); -P(sym_get_type,int,(struct symbol *sym)); +P(sym_get_type,enum symbol_type,(struct symbol *sym)); P(sym_tristate_within_range,bool,(struct symbol *sym,tristate tri)); P(sym_set_tristate_value,bool,(struct symbol *sym,tristate tri)); P(sym_toggle_tristate_value,tristate,(struct symbol *sym)); P(sym_string_valid,bool,(struct symbol *sym, const char *newval)); +P(sym_string_within_range,bool,(struct symbol *sym, const char *str)); P(sym_set_string_value,bool,(struct symbol *sym, const char *newval)); P(sym_is_changable,bool,(struct symbol *sym)); P(sym_get_choice_prop,struct property *,(struct symbol *sym)); diff -Nru a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c --- a/scripts/kconfig/mconf.c Mon Jun 9 23:16:08 2003 +++ b/scripts/kconfig/mconf.c Mon Jun 9 23:16:08 2003 @@ -384,7 +384,10 @@ switch (type) { case S_BOOLEAN: cprint("t%p", menu); - cprint1("[%c]", val == no ? ' ' : '*'); + if (sym_is_changable(sym)) + cprint1("[%c]", val == no ? ' ' : '*'); + else + cprint1("---"); break; case S_TRISTATE: cprint("t%p", menu); @@ -393,7 +396,10 @@ case mod: ch = 'M'; break; default: ch = ' '; break; } - cprint1("<%c>", ch); + if (sym_is_changable(sym)) + cprint1("<%c>", ch); + else + cprint1("---"); break; default: cprint("s%p", menu); @@ -402,13 +408,15 @@ if (tmp < 0) tmp = 0; cprint1("%*c%s%s", tmp, ' ', menu_get_prompt(menu), - sym_has_value(sym) ? "" : " (NEW)"); + (sym_has_value(sym) || !sym_is_changable(sym)) ? + "" : " (NEW)"); cprint_done(); goto conf_childs; } } cprint1("%*c%s%s", indent + 1, ' ', menu_get_prompt(menu), - sym_has_value(sym) ? "" : " (NEW)"); + (sym_has_value(sym) || !sym_is_changable(sym)) ? + "" : " (NEW)"); if (menu->prompt->type == P_MENU) { cprint1(" --->"); cprint_done(); @@ -780,10 +788,12 @@ conf_write(NULL); printf("\n\n" "*** End of Linux kernel configuration.\n" - "*** Check the top-level Makefile for additional configuration.\n" - "*** Next, you may run 'make bzImage', 'make bzdisk', or 'make install'.\n\n"); + "*** Execute 'make' to build the kernel or try 'make help'." + "\n\n"); } else - printf("\n\nYour kernel configuration changes were NOT saved.\n\n"); + printf("\n\n" + "Your kernel configuration changes were NOT saved." + "\n\n"); return 0; } diff -Nru a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c --- a/scripts/kconfig/menu.c Mon Jun 9 23:16:18 2003 +++ b/scripts/kconfig/menu.c Mon Jun 9 23:16:18 2003 @@ -94,56 +94,43 @@ sym->type = type; return; } - fprintf(stderr, "%s:%d: type of '%s' redefined from '%s' to '%s'\n", + fprintf(stderr, "%s:%d:warning: type of '%s' redefined from '%s' to '%s'\n", current_entry->file->name, current_entry->lineno, sym->name ? sym->name : "<choice>", sym_type_name(sym->type), sym_type_name(type)); } -struct property *create_prop(enum prop_type type) +struct property *menu_add_prop(enum prop_type type, char *prompt, struct expr *expr, struct expr *dep) { - struct property *prop; - - prop = malloc(sizeof(*prop)); - memset(prop, 0, sizeof(*prop)); - prop->type = type; - prop->file = current_file; - prop->lineno = zconf_lineno(); - - return prop; -} - -struct property *menu_add_prop(int token, char *prompt, struct symbol *def, struct expr *dep) -{ - struct property *prop = create_prop(token); - struct property **propp; + struct property *prop = prop_alloc(type, current_entry->sym); - prop->sym = current_entry->sym; prop->menu = current_entry; prop->text = prompt; - prop->def = def; - E_EXPR(prop->visible) = menu_check_dep(dep); + prop->expr = expr; + prop->visible.expr = menu_check_dep(dep); - if (prompt) + if (prompt) { + if (current_entry->prompt) + fprintf(stderr, "%s:%d: prompt redefined\n", + current_entry->file->name, current_entry->lineno); current_entry->prompt = prop; - - /* append property to the prop list of symbol */ - if (prop->sym) { - for (propp = &prop->sym->prop; *propp; propp = &(*propp)->next) - ; - *propp = prop; } return prop; } -void menu_add_prompt(int token, char *prompt, struct expr *dep) +void menu_add_prompt(enum prop_type type, char *prompt, struct expr *dep) +{ + menu_add_prop(type, prompt, NULL, dep); +} + +void menu_add_expr(enum prop_type type, struct expr *expr, struct expr *dep) { - current_entry->prompt = menu_add_prop(token, prompt, NULL, dep); + menu_add_prop(type, NULL, expr, dep); } -void menu_add_default(int token, struct symbol *def, struct expr *dep) +void menu_add_symbol(enum prop_type type, struct symbol *sym, struct expr *dep) { - current_entry->prompt = menu_add_prop(token, NULL, def, dep); + menu_add_prop(type, NULL, expr_alloc_symbol(sym), dep); } void menu_finalize(struct menu *parent) @@ -151,7 +138,7 @@ struct menu *menu, *last_menu; struct symbol *sym; struct property *prop; - struct expr *parentdep, *basedep, *dep, *dep2; + struct expr *parentdep, *basedep, *dep, *dep2, **ep; sym = parent->sym; if (parent->list) { @@ -168,7 +155,7 @@ } parentdep = expr_alloc_symbol(sym); } else if (parent->prompt) - parentdep = E_EXPR(parent->prompt->visible); + parentdep = parent->prompt->visible.expr; else parentdep = parent->dep; @@ -184,23 +171,28 @@ for (; prop; prop = prop->next) { if (prop->menu != menu) continue; - dep = expr_transform(E_EXPR(prop->visible)); + dep = expr_transform(prop->visible.expr); dep = expr_alloc_and(expr_copy(basedep), dep); dep = expr_eliminate_dups(dep); if (menu->sym && menu->sym->type != S_TRISTATE) dep = expr_trans_bool(dep); - E_EXPR(prop->visible) = dep; + prop->visible.expr = dep; + if (prop->type == P_SELECT) { + struct symbol *es = prop_get_symbol(prop); + es->rev_dep.expr = expr_alloc_or(es->rev_dep.expr, + expr_alloc_and(expr_alloc_symbol(menu->sym), expr_copy(dep))); + } } } for (menu = parent->list; menu; menu = menu->next) menu_finalize(menu); } else if (sym) { - basedep = parent->prompt ? E_EXPR(parent->prompt->visible) : NULL; + basedep = parent->prompt ? parent->prompt->visible.expr : NULL; basedep = expr_trans_compare(basedep, E_UNEQUAL, &symbol_no); basedep = expr_eliminate_dups(expr_transform(basedep)); last_menu = NULL; for (menu = parent->next; menu; menu = menu->next) { - dep = menu->prompt ? E_EXPR(menu->prompt->visible) : menu->dep; + dep = menu->prompt ? menu->prompt->visible.expr : menu->dep; if (!expr_contains_symbol(dep, sym)) break; if (expr_depends_symbol(dep, sym)) @@ -229,14 +221,27 @@ for (menu = parent->list; menu; menu = menu->next) { if (sym && sym_is_choice(sym) && menu->sym) { menu->sym->flags |= SYMBOL_CHOICEVAL; + if (!menu->prompt) + fprintf(stderr, "%s:%d:warning: choice value must have a prompt\n", + menu->file->name, menu->lineno); + for (prop = menu->sym->prop; prop; prop = prop->next) { + if (prop->type == P_PROMPT && prop->menu != menu) { + fprintf(stderr, "%s:%d:warning: choice values currently only support a single prompt\n", + prop->file->name, prop->lineno); + + } + if (prop->type == P_DEFAULT) + fprintf(stderr, "%s:%d:warning: defaults for choice values not supported\n", + prop->file->name, prop->lineno); + } current_entry = menu; menu_set_type(sym->type); - menu_add_prop(P_CHOICE, NULL, parent->sym, NULL); - prop = sym_get_choice_prop(parent->sym); - //dep = expr_alloc_one(E_CHOICE, dep); - //dep->right.sym = menu->sym; - prop->dep = expr_alloc_one(E_CHOICE, prop->dep); - prop->dep->right.sym = menu->sym; + menu_add_symbol(P_CHOICE, sym, NULL); + prop = sym_get_choice_prop(sym); + for (ep = &prop->expr; *ep; ep = &(*ep)->left.expr) + ; + *ep = expr_alloc_one(E_CHOICE, NULL); + (*ep)->right.sym = menu->sym; } if (menu->list && (!menu->prompt || !menu->prompt->text)) { for (last_menu = menu->list; ; last_menu = last_menu->next) { @@ -249,20 +254,79 @@ menu->list = NULL; } } + + if (sym && !(sym->flags & SYMBOL_WARNED)) { + struct symbol *sym2; + if (sym->type == S_UNKNOWN) + fprintf(stderr, "%s:%d:warning: config symbol defined without type\n", + parent->file->name, parent->lineno); + + if (sym_is_choice(sym) && !parent->prompt) + fprintf(stderr, "%s:%d:warning: choice must have a prompt\n", + parent->file->name, parent->lineno); + + for (prop = sym->prop; prop; prop = prop->next) { + switch (prop->type) { + case P_DEFAULT: + if ((sym->type == S_STRING || sym->type == S_INT || sym->type == S_HEX) && + prop->expr->type != E_SYMBOL) + fprintf(stderr, "%s:%d:warning: default must be a single symbol\n", + prop->file->name, prop->lineno); + break; + case P_SELECT: + sym2 = prop_get_symbol(prop); + if ((sym->type != S_BOOLEAN && sym->type != S_TRISTATE) || + (sym2->type != S_BOOLEAN && sym2->type != S_TRISTATE)) + fprintf(stderr, "%s:%d:warning: enable is only allowed with boolean and tristate symbols\n", + prop->file->name, prop->lineno); + break; + case P_RANGE: + if (sym->type != S_INT && sym->type != S_HEX) + fprintf(stderr, "%s:%d:warning: range is only allowed for int or hex symbols\n", + prop->file->name, prop->lineno); + if (!sym_string_valid(sym, prop->expr->left.sym->name) || + !sym_string_valid(sym, prop->expr->right.sym->name)) + fprintf(stderr, "%s:%d:warning: range is invalid\n", + prop->file->name, prop->lineno); + break; + default: + ; + } + } + sym->flags |= SYMBOL_WARNED; + } + + if (sym && !sym_is_optional(sym) && parent->prompt) { + sym->rev_dep.expr = expr_alloc_or(sym->rev_dep.expr, + expr_alloc_and(parent->prompt->visible.expr, + expr_alloc_symbol(&symbol_mod))); + } } bool menu_is_visible(struct menu *menu) { + struct menu *child; + struct symbol *sym; tristate visible; if (!menu->prompt) return false; - if (menu->sym) { - sym_calc_value(menu->sym); - visible = E_TRI(menu->prompt->visible); + sym = menu->sym; + if (sym) { + sym_calc_value(sym); + visible = menu->prompt->visible.tri; } else - visible = E_CALC(menu->prompt->visible); - return visible != no; + visible = menu->prompt->visible.tri = expr_calc_value(menu->prompt->visible.expr); + + if (visible != no) + return true; + if (!sym || sym_get_tristate_value(menu->sym) == no) + return false; + + for (child = menu->list; child; child = child->next) + if (menu_is_visible(child)) + return true; + return false; } const char *menu_get_prompt(struct menu *menu) @@ -285,7 +349,7 @@ for (; menu != &rootmenu; menu = menu->parent) { type = menu->prompt ? menu->prompt->type : 0; - if (type == P_MENU || type == P_ROOTMENU) + if (type == P_MENU) break; } return menu; diff -Nru a/scripts/kconfig/qconf.cc b/scripts/kconfig/qconf.cc --- a/scripts/kconfig/qconf.cc Mon Jun 9 23:16:06 2003 +++ b/scripts/kconfig/qconf.cc Mon Jun 9 23:16:06 2003 @@ -65,11 +65,11 @@ switch (mode) { case menuMode: - if (type != P_ROOTMENU) + if (!(child->flags & MENU_ROOT)) goto hide; break; case symbolMode: - if (type == P_ROOTMENU) + if (child->flags & MENU_ROOT) goto hide; break; default: @@ -83,8 +83,7 @@ else item->testUpdateMenu(visible); - if (mode == fullMode || mode == menuMode || - (type != P_MENU && type != P_ROOTMENU)) + if (mode == fullMode || mode == menuMode || type != P_MENU) updateMenuList(item, child); else updateMenuList(item, 0); @@ -140,7 +139,6 @@ if (prop) switch (prop->type) { case P_MENU: - case P_ROOTMENU: if (list->mode == singleMode || list->mode == symbolMode) { /* a menuconfig entry is displayed differently * depending whether it's at the view root or a child. @@ -172,6 +170,7 @@ char ch; if (!sym_is_changable(sym) && !list->showAll) { + setPixmap(promptColIdx, 0); setText(noColIdx, 0); setText(modColIdx, 0); setText(yesColIdx, 0); @@ -288,7 +287,7 @@ ConfigItem::~ConfigItem(void) { if (menu) { - ConfigItem** ip = &(ConfigItem*)menu->data; + ConfigItem** ip = (ConfigItem**)&menu->data; for (; *ip; ip = &(*ip)->nextItem) { if (*ip == this) { *ip = nextItem; @@ -333,7 +332,7 @@ updateAll(false), symbolYesPix(xpm_symbol_yes), symbolModPix(xpm_symbol_mod), symbolNoPix(xpm_symbol_no), choiceYesPix(xpm_choice_yes), choiceNoPix(xpm_choice_no), - menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), + menuPix(xpm_menu), menuInvPix(xpm_menu_inv), menuBackPix(xpm_menuback), voidPix(xpm_void), showAll(false), showName(false), showRange(false), showData(false), rootEntry(0) { @@ -392,7 +391,7 @@ if (!menu) return; type = menu->prompt ? menu->prompt->type : P_UNKNOWN; - if (mode == menuMode && (type == P_MENU || type == P_ROOTMENU)) + if (mode == menuMode && type == P_MENU) emit menuSelected(menu); } @@ -403,7 +402,8 @@ if (!rootEntry) goto update; - if ((mode == singleMode || mode == symbolMode) && rootEntry != &rootmenu) { + if (rootEntry != &rootmenu && (mode == singleMode || + (mode == symbolMode && rootEntry->parent != &rootmenu))) { item = firstChild(); if (!item) item = new ConfigItem(this, 0, true); @@ -507,7 +507,7 @@ if (rootEntry == menu) return; type = menu && menu->prompt ? menu->prompt->type : P_UNKNOWN; - if (type != P_MENU && type != P_ROOTMENU) + if (type != P_MENU) return; updateMenuList(this, 0); rootEntry = menu; @@ -518,13 +518,12 @@ void ConfigList::setParentMenu(void) { ConfigItem* item; - struct menu *oldroot, *newroot; + struct menu *oldroot; oldroot = rootEntry; - newroot = menu_get_parent_menu(oldroot); - if (newroot == oldroot) + if (rootEntry == &rootmenu) return; - setRootMenu(newroot); + setRootMenu(menu_get_parent_menu(rootEntry->parent)); QListViewItemIterator it(this); for (; (item = (ConfigItem*)it.current()); it++) { @@ -566,7 +565,8 @@ if (!menu) break; type = menu->prompt ? menu->prompt->type : P_UNKNOWN; - if ((type == P_MENU || type == P_ROOTMENU) && mode != fullMode) { + if (type == P_MENU && rootEntry != menu && + mode != fullMode && mode != menuMode) { emit menuSelected(menu); break; } @@ -601,6 +601,7 @@ QPoint p(contentsToViewport(e->pos())); ConfigItem* item = (ConfigItem*)itemAt(p); struct menu *menu; + enum prop_type ptype; const QPixmap* pm; int idx, x; @@ -617,14 +618,17 @@ int off = header()->sectionPos(0) + itemMargin() + treeStepSize() * (item->depth() + (rootIsDecorated() ? 1 : 0)); if (x >= off && x < off + pm->width()) { - if (item->goParent) + if (item->goParent) { emit parentSelected(); - else if (!menu) break; - else if (menu->sym) - changeValue(item); - else + } else if (!menu) + break; + ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; + if (ptype == P_MENU && rootEntry != menu && + mode != fullMode && mode != menuMode) emit menuSelected(menu); + else + changeValue(item); } } break; @@ -671,8 +675,7 @@ if (!menu) goto skip; ptype = menu->prompt ? menu->prompt->type : P_UNKNOWN; - if ((ptype == P_ROOTMENU || ptype == P_MENU) && - (mode == singleMode || mode == symbolMode)) + if (ptype == P_MENU && (mode == singleMode || mode == symbolMode)) emit menuSelected(menu); else if (menu->sym) changeValue(item); @@ -880,7 +883,6 @@ connect(menuList, SIGNAL(gotFocus(void)), SLOT(listFocusChanged(void))); - //showFullView(); showSplitView(); } @@ -959,36 +961,54 @@ if (showDebug) { debug += "type: "; debug += print_filter(sym_type_name(sym->type)); + if (sym_is_choice(sym)) + debug += " (choice)"; debug += "<br>"; + if (sym->rev_dep.expr) { + debug += "reverse dep: "; + expr_print(sym->rev_dep.expr, expr_print_help, &debug, E_NONE); + debug += "<br>"; + } for (struct property *prop = sym->prop; prop; prop = prop->next) { switch (prop->type) { case P_PROMPT: + case P_MENU: debug += "prompt: "; debug += print_filter(prop->text); debug += "<br>"; - if (prop->visible.expr) { - debug += " dep: "; - expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE); - debug += "<br>"; - } break; case P_DEFAULT: debug += "default: "; - debug += print_filter(prop->def->name); + expr_print(prop->expr, expr_print_help, &debug, E_NONE); debug += "<br>"; - if (prop->visible.expr) { - debug += " dep: "; - expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE); + break; + case P_CHOICE: + if (sym_is_choice(sym)) { + debug += "choice: "; + expr_print(prop->expr, expr_print_help, &debug, E_NONE); debug += "<br>"; } break; - case P_CHOICE: + case P_SELECT: + debug += "select: "; + expr_print(prop->expr, expr_print_help, &debug, E_NONE); + debug += "<br>"; + break; + case P_RANGE: + debug += "range: "; + expr_print(prop->expr, expr_print_help, &debug, E_NONE); + debug += "<br>"; break; default: debug += "unknown property: "; debug += prop_get_type_name(prop->type); debug += "<br>"; } + if (prop->visible.expr) { + debug += " dep: "; + expr_print(prop->visible.expr, expr_print_help, &debug, E_NONE); + debug += "<br>"; + } } debug += "<br>"; } @@ -1002,10 +1022,12 @@ if (menu->prompt->visible.expr) { debug += " dep: "; expr_print(menu->prompt->visible.expr, expr_print_help, &debug, E_NONE); - debug += "<br>"; + debug += "<br><br>"; } } } + if (showDebug) + debug += QString().sprintf("defined at %s:%d<br><br>", menu->file->name, menu->lineno); helpText->setText(head + debug + help); } @@ -1133,6 +1155,8 @@ return; configList->showName = b; configList->reinit(); + menuList->showName = b; + menuList->reinit(); } void ConfigMainWindow::setShowRange(bool b) @@ -1141,6 +1165,8 @@ return; configList->showRange = b; configList->reinit(); + menuList->showRange = b; + menuList->reinit(); } void ConfigMainWindow::setShowData(bool b) @@ -1149,6 +1175,8 @@ return; configList->showData = b; configList->reinit(); + menuList->showData = b; + menuList->reinit(); } /* @@ -1206,12 +1234,25 @@ void fixup_rootmenu(struct menu *menu) { struct menu *child; + static int menu_cnt = 0; - if (!menu->prompt || menu->prompt->type != P_MENU) - return; - menu->prompt->type = P_ROOTMENU; - for (child = menu->list; child; child = child->next) - fixup_rootmenu(child); + menu->flags |= MENU_ROOT; + for (child = menu->list; child; child = child->next) { + if (child->prompt && child->prompt->type == P_MENU) { + menu_cnt++; + fixup_rootmenu(child); + menu_cnt--; + } else if (!menu_cnt) + fixup_rootmenu(child); + } +} + +static const char *progname; + +static void usage(void) +{ + printf("%s <config>\n", progname); + exit(0); } int main(int ac, char** av) @@ -1223,23 +1264,23 @@ kconfig_load(); #endif + progname = av[0]; configApp = new QApplication(ac, av); #if QT_VERSION >= 300 configSettings = new QSettings; #endif if (ac > 1 && av[1][0] == '-') { switch (av[1][1]) { - case 'a': - //showAll = 1; - break; case 'h': case '?': - printf("%s <config>\n", av[0]); - exit(0); + usage(); } name = av[2]; } else name = av[1]; + if (!name) + usage(); + conf_parse(name); fixup_rootmenu(&rootmenu); conf_read(NULL); diff -Nru a/scripts/kconfig/qconf.h b/scripts/kconfig/qconf.h --- a/scripts/kconfig/qconf.h Mon Jun 9 23:16:10 2003 +++ b/scripts/kconfig/qconf.h Mon Jun 9 23:16:10 2003 @@ -108,7 +108,7 @@ QPixmap symbolYesPix, symbolModPix, symbolNoPix; QPixmap choiceYesPix, choiceNoPix; - QPixmap menuPix, menuInvPix, menuBackPix; + QPixmap menuPix, menuInvPix, menuBackPix, voidPix; bool showAll, showName, showRange, showData; enum listMode mode; diff -Nru a/scripts/kconfig/symbol.c b/scripts/kconfig/symbol.c --- a/scripts/kconfig/symbol.c Mon Jun 9 23:16:08 2003 +++ b/scripts/kconfig/symbol.c Mon Jun 9 23:16:08 2003 @@ -34,18 +34,9 @@ void sym_add_default(struct symbol *sym, const char *def) { - struct property *prop = create_prop(P_DEFAULT); - struct property **propp; - - prop->sym = sym; - prop->def = sym_lookup(def, 1); + struct property *prop = prop_alloc(P_DEFAULT, sym); - /* append property to the prop list of symbol */ - if (prop->sym) { - for (propp = &prop->sym->prop; *propp; propp = &(*propp)->next) - ; - *propp = prop; - } + prop->expr = expr_alloc_symbol(sym_lookup(def, 1)); } void sym_init(void) @@ -81,22 +72,23 @@ sym_add_default(sym, uts.release); } -int sym_get_type(struct symbol *sym) +enum symbol_type sym_get_type(struct symbol *sym) { - int type = sym->type; + enum symbol_type type = sym->type; + if (type == S_TRISTATE) { if (sym_is_choice_value(sym) && sym->visible == yes) type = S_BOOLEAN; else { sym_calc_value(modules_sym); - if (S_TRI(modules_sym->curr) == no) + if (modules_sym->curr.tri == no) type = S_BOOLEAN; } } return type; } -const char *sym_type_name(int type) +const char *sym_type_name(enum symbol_type type) { switch (type) { case S_BOOLEAN: @@ -111,6 +103,8 @@ return "string"; case S_UNKNOWN: return "unknown"; + case S_OTHER: + break; } return "???"; } @@ -127,37 +121,96 @@ struct property *sym_get_default_prop(struct symbol *sym) { struct property *prop; - tristate visible; for_all_defaults(sym, prop) { - visible = E_CALC(prop->visible); - if (visible != no) + prop->visible.tri = expr_calc_value(prop->visible.expr); + if (prop->visible.tri != no) + return prop; + } + return NULL; +} + +struct property *sym_get_range_prop(struct symbol *sym) +{ + struct property *prop; + + for_all_properties(sym, prop, P_RANGE) { + prop->visible.tri = expr_calc_value(prop->visible.expr); + if (prop->visible.tri != no) return prop; } return NULL; } -void sym_calc_visibility(struct symbol *sym) +static void sym_calc_visibility(struct symbol *sym) { struct property *prop; - tristate visible, oldvisible; + tristate tri; /* any prompt visible? */ - oldvisible = sym->visible; - visible = no; - for_all_prompts(sym, prop) - visible = E_OR(visible, E_CALC(prop->visible)); - if (oldvisible != visible) { - sym->visible = visible; + tri = no; + for_all_prompts(sym, prop) { + prop->visible.tri = expr_calc_value(prop->visible.expr); + tri = E_OR(tri, prop->visible.tri); + } + if (sym->visible != tri) { + sym->visible = tri; + sym_set_changed(sym); + } + if (sym_is_choice_value(sym)) + return; + tri = no; + if (sym->rev_dep.expr) + tri = expr_calc_value(sym->rev_dep.expr); + if (sym->rev_dep.tri != tri) { + sym->rev_dep.tri = tri; sym_set_changed(sym); } } +static struct symbol *sym_calc_choice(struct symbol *sym) +{ + struct symbol *def_sym; + struct property *prop; + struct expr *e; + + /* is the user choice visible? */ + def_sym = sym->user.val; + if (def_sym) { + sym_calc_visibility(def_sym); + if (def_sym->visible != no) + return def_sym; + } + + /* any of the defaults visible? */ + for_all_defaults(sym, prop) { + prop->visible.tri = expr_calc_value(prop->visible.expr); + if (prop->visible.tri == no) + continue; + def_sym = prop_get_symbol(prop); + sym_calc_visibility(def_sym); + if (def_sym->visible != no) + return def_sym; + } + + /* just get the first visible value */ + prop = sym_get_choice_prop(sym); + for (e = prop->expr; e; e = e->left.expr) { + def_sym = e->right.sym; + sym_calc_visibility(def_sym); + if (def_sym->visible != no) + return def_sym; + } + + /* no choice? reset tristate value */ + sym->curr.tri = no; + return NULL; +} + void sym_calc_value(struct symbol *sym) { struct symbol_value newval, oldval; - struct property *prop, *def_prop; - struct symbol *def_sym; + struct property *prop; struct expr *e; if (!sym) @@ -165,6 +218,7 @@ if (sym->flags & SYMBOL_VALID) return; + sym->flags |= SYMBOL_VALID; oldval = sym->curr; @@ -179,17 +233,10 @@ newval = symbol_no.curr; break; default: - S_VAL(newval) = sym->name; - S_TRI(newval) = no; - if (sym->flags & SYMBOL_CONST) { - goto out; - } - //newval = symbol_empty.curr; - // generate warning somewhere here later - //S_TRI(newval) = yes; - goto out; + sym->curr.val = sym->name; + sym->curr.tri = no; + return; } - sym->flags |= SYMBOL_VALID; if (!sym_is_choice_value(sym)) sym->flags &= ~SYMBOL_WRITE; @@ -198,95 +245,73 @@ /* set default if recursively called */ sym->curr = newval; - if (sym->visible != no) { - sym->flags |= SYMBOL_WRITE; - if (!sym_has_value(sym)) { - if (!sym_is_choice(sym)) { - prop = sym_get_default_prop(sym); - if (prop) { - sym_calc_value(prop->def); - newval = prop->def->curr; - } - } else - S_TRI(newval) = S_TRI(sym->def); - } else - newval = sym->def; - - S_TRI(newval) = E_AND(S_TRI(newval), sym->visible); - /* if the symbol is visible and not optionial, - * possibly ignore old user choice. */ - if (!sym_is_optional(sym) && S_TRI(newval) == no) - S_TRI(newval) = sym->visible; + switch (sym_get_type(sym)) { + case S_BOOLEAN: + case S_TRISTATE: if (sym_is_choice_value(sym) && sym->visible == yes) { prop = sym_get_choice_prop(sym); - S_TRI(newval) = (S_VAL(prop->def->curr) == sym) ? yes : no; - } - } else { - prop = sym_get_default_prop(sym); - if (prop) { + newval.tri = (prop_get_symbol(prop)->curr.val == sym) ? yes : no; + } else if (E_OR(sym->visible, sym->rev_dep.tri) != no) { sym->flags |= SYMBOL_WRITE; - sym_calc_value(prop->def); - newval = prop->def->curr; + if (sym_has_value(sym)) + newval.tri = sym->user.tri; + else if (!sym_is_choice(sym)) { + prop = sym_get_default_prop(sym); + if (prop) + newval.tri = expr_calc_value(prop->expr); + } + newval.tri = E_OR(E_AND(newval.tri, sym->visible), sym->rev_dep.tri); + } else if (!sym_is_choice(sym)) { + prop = sym_get_default_prop(sym); + if (prop) { + sym->flags |= SYMBOL_WRITE; + newval.tri = expr_calc_value(prop->expr); + } + } + if (sym_get_type(sym) == S_BOOLEAN) { + if (newval.tri == mod) + newval.tri = yes; + if (sym->visible == mod) + sym->visible = yes; + if (sym->rev_dep.tri == mod) + sym->rev_dep.tri = yes; } - } - - switch (sym_get_type(sym)) { - case S_TRISTATE: - if (S_TRI(newval) != mod) - break; - sym_calc_value(modules_sym); - if (S_TRI(modules_sym->curr) == no) - S_TRI(newval) = yes; break; - case S_BOOLEAN: - if (S_TRI(newval) == mod) - S_TRI(newval) = yes; - } - -out: - sym->curr = newval; - - if (sym_is_choice(sym) && S_TRI(newval) == yes) { - def_sym = S_VAL(sym->def); - if (def_sym) { - sym_calc_visibility(def_sym); - if (def_sym->visible == no) - def_sym = NULL; - } - if (!def_sym) { - for_all_defaults(sym, def_prop) { - if (E_CALC(def_prop->visible) == no) - continue; - sym_calc_visibility(def_prop->def); - if (def_prop->def->visible != no) { - def_sym = def_prop->def; - break; - } + case S_STRING: + case S_HEX: + case S_INT: + if (sym->visible != no) { + sym->flags |= SYMBOL_WRITE; + if (sym_has_value(sym)) { + newval.val = sym->user.val; + break; } } - - if (!def_sym) { - prop = sym_get_choice_prop(sym); - for (e = prop->dep; e; e = e->left.expr) { - sym_calc_visibility(e->right.sym); - if (e->right.sym->visible != no) { - def_sym = e->right.sym; - break; - } + prop = sym_get_default_prop(sym); + if (prop) { + struct symbol *ds = prop_get_symbol(prop); + if (ds) { + sym->flags |= SYMBOL_WRITE; + sym_calc_value(ds); + newval.val = ds->curr.val; } } - - S_VAL(newval) = def_sym; + break; + default: + ; } - if (memcmp(&oldval, &newval, sizeof(newval))) - sym_set_changed(sym); sym->curr = newval; + if (sym_is_choice(sym) && newval.tri == yes) + sym->curr.val = sym_calc_choice(sym); + + if (memcmp(&oldval, &sym->curr, sizeof(oldval))) + sym_set_changed(sym); if (sym_is_choice(sym)) { int flags = sym->flags & (SYMBOL_CHANGED | SYMBOL_WRITE); prop = sym_get_choice_prop(sym); - for (e = prop->dep; e; e = e->left.expr) { + for (e = prop->expr; e; e = e->left.expr) { e->right.sym->flags |= flags; if (flags & SYMBOL_CHANGED) sym_set_changed(e->right.sym); @@ -334,19 +359,13 @@ if (type != S_BOOLEAN && type != S_TRISTATE) return false; - switch (val) { - case no: - if (sym_is_choice_value(sym) && sym->visible == yes) - return false; - return sym_is_optional(sym); - case mod: - if (sym_is_choice_value(sym) && sym->visible == yes) - return false; - return type == S_TRISTATE; - case yes: - return type == S_BOOLEAN || sym->visible == yes; - } - return false; + if (type == S_BOOLEAN && val == mod) + return false; + if (sym->visible <= sym->rev_dep.tri) + return false; + if (sym_is_choice_value(sym) && sym->visible == yes) + return val == yes; + return val >= sym->rev_dep.tri && val <= sym->visible; } bool sym_set_tristate_value(struct symbol *sym, tristate val) @@ -361,13 +380,13 @@ sym_set_changed(sym); } if (sym_is_choice_value(sym) && val == yes) { - struct property *prop = sym_get_choice_prop(sym); + struct symbol *cs = prop_get_symbol(sym_get_choice_prop(sym)); - S_VAL(prop->def->def) = sym; - prop->def->flags &= ~SYMBOL_NEW; + cs->user.val = sym; + cs->flags &= ~SYMBOL_NEW; } - S_TRI(sym->def) = val; + sym->user.tri = val; if (oldval != val) { sym_clear_all_valid(); if (sym == modules_sym) @@ -432,14 +451,51 @@ case S_BOOLEAN: case S_TRISTATE: switch (str[0]) { - case 'y': - case 'Y': + case 'y': case 'Y': + case 'm': case 'M': + case 'n': case 'N': + return true; + } + return false; + default: + return false; + } +} + +bool sym_string_within_range(struct symbol *sym, const char *str) +{ + struct property *prop; + int val; + + switch (sym->type) { + case S_STRING: + return sym_string_valid(sym, str); + case S_INT: + if (!sym_string_valid(sym, str)) + return false; + prop = sym_get_range_prop(sym); + if (!prop) + return true; + val = strtol(str, NULL, 10); + return val >= strtol(prop->expr->left.sym->name, NULL, 10) && + val <= strtol(prop->expr->right.sym->name, NULL, 10); + case S_HEX: + if (!sym_string_valid(sym, str)) + return false; + prop = sym_get_range_prop(sym); + if (!prop) + return true; + val = strtol(str, NULL, 16); + return val >= strtol(prop->expr->left.sym->name, NULL, 16) && + val <= strtol(prop->expr->right.sym->name, NULL, 16); + case S_BOOLEAN: + case S_TRISTATE: + switch (str[0]) { + case 'y': case 'Y': return sym_tristate_within_range(sym, yes); - case 'm': - case 'M': + case 'm': case 'M': return sym_tristate_within_range(sym, mod); - case 'n': - case 'N': + case 'n': case 'N': return sym_tristate_within_range(sym, no); } return false; @@ -458,14 +514,11 @@ case S_BOOLEAN: case S_TRISTATE: switch (newval[0]) { - case 'y': - case 'Y': + case 'y': case 'Y': return sym_set_tristate_value(sym, yes); - case 'm': - case 'M': + case 'm': case 'M': return sym_set_tristate_value(sym, mod); - case 'n': - case 'N': + case 'n': case 'N': return sym_set_tristate_value(sym, no); } return false; @@ -473,7 +526,7 @@ ; } - if (!sym_string_valid(sym, newval)) + if (!sym_string_within_range(sym, newval)) return false; if (sym->flags & SYMBOL_NEW) { @@ -481,15 +534,15 @@ sym_set_changed(sym); } - oldval = S_VAL(sym->def); + oldval = sym->user.val; size = strlen(newval) + 1; if (sym->type == S_HEX && (newval[0] != '0' || (newval[1] != 'x' && newval[1] != 'X'))) { size += 2; - S_VAL(sym->def) = val = malloc(size); + sym->user.val = val = malloc(size); *val++ = '0'; *val++ = 'x'; } else if (!oldval || strcmp(oldval, newval)) - S_VAL(sym->def) = val = malloc(size); + sym->user.val = val = malloc(size); else return true; @@ -520,20 +573,12 @@ default: ; } - return (const char *)S_VAL(sym->curr); + return (const char *)sym->curr.val; } bool sym_is_changable(struct symbol *sym) { - if (sym->visible == no) - return false; - /* at least 'n' and 'y'/'m' is selectable */ - if (sym_is_optional(sym)) - return true; - /* no 'n', so 'y' and 'm' must be selectable */ - if (sym_get_type(sym) == S_TRISTATE && sym->visible == yes) - return true; - return false; + return sym->visible > sym->rev_dep.tri; } struct symbol *sym_lookup(const char *name, int isconst) @@ -611,6 +656,104 @@ return symbol; } +struct symbol *sym_check_deps(struct symbol *sym); + +static struct symbol *sym_check_expr_deps(struct expr *e) +{ + struct symbol *sym; + + if (!e) + return NULL; + switch (e->type) { + case E_OR: + case E_AND: + sym = sym_check_expr_deps(e->left.expr); + if (sym) + return sym; + return sym_check_expr_deps(e->right.expr); + case E_NOT: + return sym_check_expr_deps(e->left.expr); + case E_EQUAL: + case E_UNEQUAL: + sym = sym_check_deps(e->left.sym); + if (sym) + return sym; + return sym_check_deps(e->right.sym); + case E_SYMBOL: + return sym_check_deps(e->left.sym); + default: + break; + } + printf("Oops! How to check %d?\n", e->type); + return NULL; +} + +struct symbol *sym_check_deps(struct symbol *sym) +{ + struct symbol *sym2; + struct property *prop; + + if (sym->flags & SYMBOL_CHECK_DONE) + return NULL; + if (sym->flags & SYMBOL_CHECK) { + printf("Warning! Found recursive dependency: %s", sym->name); + return sym; + } + + sym->flags |= (SYMBOL_CHECK | SYMBOL_CHECKED); + sym2 = sym_check_expr_deps(sym->rev_dep.expr); + if (sym2) + goto out; + + for (prop = sym->prop; prop; prop = prop->next) { + if (prop->type == P_CHOICE) + continue; + sym2 = sym_check_expr_deps(prop->visible.expr); + if (sym2) + goto out; + if (prop->type != P_DEFAULT || sym_is_choice(sym)) + continue; + sym2 = sym_check_expr_deps(prop->expr); + if (sym2) + goto out; + } +out: + if (sym2) + printf(" %s", sym->name); + sym->flags &= ~SYMBOL_CHECK; + return sym2; +} + +struct property *prop_alloc(enum prop_type type, struct symbol *sym) +{ + struct property *prop; + struct property **propp; + + prop = malloc(sizeof(*prop)); + memset(prop, 0, sizeof(*prop)); + prop->type = type; + prop->sym = sym; + prop->file = current_file; + prop->lineno = zconf_lineno(); + + /* append property to the prop list of symbol */ + if (sym) { + for (propp = &sym->prop; *propp; propp = &(*propp)->next) + ; + *propp = prop; + } + + return prop; +} + +struct symbol *prop_get_symbol(struct property *prop) +{ + if (prop->expr && (prop->expr->type == E_SYMBOL || + prop->expr->type == E_CHOICE)) + return prop->expr->left.sym; + return NULL; +} + const char *prop_get_type_name(enum prop_type type) { switch (type) { @@ -620,13 +763,16 @@ return "comment"; case P_MENU: return "menu"; - case P_ROOTMENU: - return "rootmenu"; case P_DEFAULT: return "default"; case P_CHOICE: return "choice"; - default: - return "unknown"; + case P_SELECT: + return "select"; + case P_RANGE: + return "range"; + case P_UNKNOWN: + break; } + return "unknown"; } diff -Nru a/scripts/kconfig/zconf.l b/scripts/kconfig/zconf.l --- a/scripts/kconfig/zconf.l Mon Jun 9 23:16:16 2003 +++ b/scripts/kconfig/zconf.l Mon Jun 9 23:16:16 2003 @@ -106,11 +106,17 @@ "default" BEGIN(PARAM); return T_DEFAULT; "prompt" BEGIN(PARAM); return T_PROMPT; "tristate" BEGIN(PARAM); return T_TRISTATE; + "def_tristate" BEGIN(PARAM); return T_DEF_TRISTATE; "bool" BEGIN(PARAM); return T_BOOLEAN; "boolean" BEGIN(PARAM); return T_BOOLEAN; + "def_bool" BEGIN(PARAM); return T_DEF_BOOLEAN; + "def_boolean" BEGIN(PARAM); return T_DEF_BOOLEAN; "int" BEGIN(PARAM); return T_INT; "hex" BEGIN(PARAM); return T_HEX; "string" BEGIN(PARAM); return T_STRING; + "select" BEGIN(PARAM); return T_SELECT; + "enable" BEGIN(PARAM); return T_SELECT; + "range" BEGIN(PARAM); return T_RANGE; {n}+ { alloc_string(yytext, yyleng); zconflval.string = text; @@ -208,7 +214,6 @@ } append_string(" ", ts); } - } [ \t]*\n/[^ \t\n] { current_file->lineno++; @@ -250,11 +255,11 @@ static void zconf_endhelp(void) { zconflval.string = text; - BEGIN(INITIAL); + BEGIN(INITIAL); } -/* +/* * Try to open specified file with following names: * ./name * $(srctree)/name @@ -347,7 +352,7 @@ int zconf_lineno(void) { if (current_buf) - return current_file->lineno; + return current_file->lineno - 1; else return 0; } diff -Nru a/scripts/kconfig/zconf.tab.c_shipped b/scripts/kconfig/zconf.tab.c_shipped --- a/scripts/kconfig/zconf.tab.c_shipped Mon Jun 9 23:16:17 2003 +++ b/scripts/kconfig/zconf.tab.c_shipped Mon Jun 9 23:16:17 2003 @@ -81,22 +81,26 @@ T_PROMPT = 274, T_DEFAULT = 275, T_TRISTATE = 276, - T_BOOLEAN = 277, - T_STRING = 278, - T_INT = 279, - T_HEX = 280, - T_WORD = 281, - T_WORD_QUOTE = 282, - T_UNEQUAL = 283, - T_EOF = 284, - T_EOL = 285, - T_CLOSE_PAREN = 286, - T_OPEN_PAREN = 287, - T_ON = 288, - T_OR = 289, - T_AND = 290, - T_EQUAL = 291, - T_NOT = 292 + T_DEF_TRISTATE = 277, + T_BOOLEAN = 278, + T_DEF_BOOLEAN = 279, + T_STRING = 280, + T_INT = 281, + T_HEX = 282, + T_WORD = 283, + T_WORD_QUOTE = 284, + T_UNEQUAL = 285, + T_EOF = 286, + T_EOL = 287, + T_CLOSE_PAREN = 288, + T_OPEN_PAREN = 289, + T_ON = 290, + T_SELECT = 291, + T_RANGE = 292, + T_OR = 293, + T_AND = 294, + T_EQUAL = 295, + T_NOT = 296 }; #endif #define T_MAINMENU 258 @@ -118,22 +122,26 @@ #define T_PROMPT 274 #define T_DEFAULT 275 #define T_TRISTATE 276 -#define T_BOOLEAN 277 -#define T_STRING 278 -#define T_INT 279 -#define T_HEX 280 -#define T_WORD 281 -#define T_WORD_QUOTE 282 -#define T_UNEQUAL 283 -#define T_EOF 284 -#define T_EOL 285 -#define T_CLOSE_PAREN 286 -#define T_OPEN_PAREN 287 -#define T_ON 288 -#define T_OR 289 -#define T_AND 290 -#define T_EQUAL 291 -#define T_NOT 292 +#define T_DEF_TRISTATE 277 +#define T_BOOLEAN 278 +#define T_DEF_BOOLEAN 279 +#define T_STRING 280 +#define T_INT 281 +#define T_HEX 282 +#define T_WORD 283 +#define T_WORD_QUOTE 284 +#define T_UNEQUAL 285 +#define T_EOF 286 +#define T_EOL 287 +#define T_CLOSE_PAREN 288 +#define T_OPEN_PAREN 289 +#define T_ON 290 +#define T_SELECT 291 +#define T_RANGE 292 +#define T_OR 293 +#define T_AND 294 +#define T_EQUAL 295 +#define T_NOT 296 @@ -172,7 +180,7 @@ /* Enabling traces. */ #ifndef YYDEBUG -# define YYDEBUG 1 +# define YYDEBUG 0 #endif /* Enabling verbose error messages. */ @@ -308,20 +316,20 @@ /* YYFINAL -- State number of the termination state. */ #define YYFINAL 2 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 160 +#define YYLAST 201 /* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 38 +#define YYNTOKENS 42 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 41 /* YYNRULES -- Number of rules. */ -#define YYNRULES 99 +#define YYNRULES 104 /* YYNRULES -- Number of states. */ -#define YYNSTATES 152 +#define YYNSTATES 182 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 -#define YYMAXUTOK 292 +#define YYMAXUTOK 296 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) @@ -358,7 +366,7 @@ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, - 35, 36, 37 + 35, 36, 37, 38, 39, 40, 41 }; #if YYDEBUG @@ -367,64 +375,69 @@ static const unsigned short yyprhs[] = { 0, 0, 3, 4, 7, 9, 11, 13, 17, 19, - 21, 23, 26, 28, 30, 32, 34, 36, 38, 41, - 45, 48, 52, 53, 57, 61, 64, 67, 70, 73, - 76, 79, 82, 86, 90, 92, 96, 98, 103, 106, - 107, 111, 115, 118, 121, 125, 127, 131, 132, 135, - 138, 140, 146, 150, 151, 154, 157, 160, 163, 167, - 169, 174, 177, 178, 181, 184, 187, 191, 194, 197, - 200, 204, 207, 210, 211, 215, 218, 222, 225, 228, - 229, 231, 235, 237, 239, 241, 243, 245, 247, 249, - 250, 253, 255, 259, 263, 267, 270, 274, 278, 280 + 21, 23, 26, 28, 30, 32, 34, 36, 38, 42, + 45, 49, 52, 53, 56, 59, 62, 65, 69, 74, + 78, 83, 87, 91, 95, 100, 105, 110, 116, 119, + 122, 124, 128, 131, 132, 135, 138, 141, 144, 149, + 153, 157, 160, 165, 166, 169, 173, 175, 179, 182, + 183, 186, 189, 192, 196, 199, 201, 205, 208, 209, + 212, 215, 218, 222, 226, 228, 232, 235, 238, 241, + 242, 245, 248, 253, 257, 261, 262, 265, 267, 269, + 272, 275, 278, 280, 282, 283, 286, 288, 292, 296, + 300, 303, 307, 311, 313 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const yysigned_char yyrhs[] = { - 39, 0, -1, -1, 39, 40, -1, 41, -1, 51, - -1, 62, -1, 3, 73, 75, -1, 5, -1, 15, - -1, 8, -1, 1, 75, -1, 57, -1, 67, -1, - 43, -1, 45, -1, 65, -1, 75, -1, 10, 26, - -1, 42, 30, 46, -1, 11, 26, -1, 44, 30, - 46, -1, -1, 46, 47, 30, -1, 46, 71, 30, - -1, 46, 69, -1, 46, 30, -1, 21, 72, -1, - 22, 72, -1, 24, 72, -1, 25, 72, -1, 23, - 72, -1, 19, 73, 76, -1, 20, 78, 76, -1, - 7, -1, 48, 30, 52, -1, 74, -1, 49, 54, - 50, 30, -1, 49, 54, -1, -1, 52, 53, 30, - -1, 52, 71, 30, -1, 52, 69, -1, 52, 30, - -1, 19, 73, 76, -1, 18, -1, 20, 78, 76, - -1, -1, 54, 41, -1, 14, 77, -1, 74, -1, - 55, 30, 58, 56, 30, -1, 55, 30, 58, -1, - -1, 58, 41, -1, 58, 62, -1, 58, 51, -1, - 4, 73, -1, 59, 30, 70, -1, 74, -1, 60, - 63, 61, 30, -1, 60, 63, -1, -1, 63, 41, - -1, 63, 62, -1, 63, 51, -1, 63, 1, 30, - -1, 6, 73, -1, 64, 30, -1, 9, 73, -1, - 66, 30, 70, -1, 12, 30, -1, 68, 13, -1, - -1, 70, 71, 30, -1, 70, 30, -1, 16, 33, - 77, -1, 16, 77, -1, 17, 77, -1, -1, 73, - -1, 73, 14, 77, -1, 26, -1, 27, -1, 5, - -1, 8, -1, 15, -1, 30, -1, 29, -1, -1, - 14, 77, -1, 78, -1, 78, 36, 78, -1, 78, - 28, 78, -1, 32, 77, 31, -1, 37, 77, -1, - 77, 34, 77, -1, 77, 35, 77, -1, 26, -1, - 27, -1 + 43, 0, -1, -1, 43, 44, -1, 45, -1, 55, + -1, 66, -1, 3, 77, 79, -1, 5, -1, 15, + -1, 8, -1, 1, 79, -1, 61, -1, 71, -1, + 47, -1, 49, -1, 69, -1, 79, -1, 10, 28, + 32, -1, 46, 50, -1, 11, 28, 32, -1, 48, + 50, -1, -1, 50, 51, -1, 50, 75, -1, 50, + 73, -1, 50, 32, -1, 21, 76, 32, -1, 22, + 81, 80, 32, -1, 23, 76, 32, -1, 24, 81, + 80, 32, -1, 26, 76, 32, -1, 27, 76, 32, + -1, 25, 76, 32, -1, 19, 77, 80, 32, -1, + 20, 81, 80, 32, -1, 36, 28, 80, 32, -1, + 37, 82, 82, 80, 32, -1, 7, 32, -1, 52, + 56, -1, 78, -1, 53, 58, 54, -1, 53, 58, + -1, -1, 56, 57, -1, 56, 75, -1, 56, 73, + -1, 56, 32, -1, 19, 77, 80, 32, -1, 21, + 76, 32, -1, 23, 76, 32, -1, 18, 32, -1, + 20, 28, 80, 32, -1, -1, 58, 45, -1, 14, + 81, 32, -1, 78, -1, 59, 62, 60, -1, 59, + 62, -1, -1, 62, 45, -1, 62, 66, -1, 62, + 55, -1, 4, 77, 32, -1, 63, 74, -1, 78, + -1, 64, 67, 65, -1, 64, 67, -1, -1, 67, + 45, -1, 67, 66, -1, 67, 55, -1, 67, 1, + 32, -1, 6, 77, 32, -1, 68, -1, 9, 77, + 32, -1, 70, 74, -1, 12, 32, -1, 72, 13, + -1, -1, 74, 75, -1, 74, 32, -1, 16, 35, + 81, 32, -1, 16, 81, 32, -1, 17, 81, 32, + -1, -1, 77, 80, -1, 28, -1, 29, -1, 5, + 79, -1, 8, 79, -1, 15, 79, -1, 32, -1, + 31, -1, -1, 14, 81, -1, 82, -1, 82, 40, + 82, -1, 82, 30, 82, -1, 34, 81, 33, -1, + 41, 81, -1, 81, 38, 81, -1, 81, 39, 81, + -1, 28, -1, 29, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const unsigned short yyrline[] = { - 0, 90, 90, 91, 94, 95, 96, 97, 98, 99, - 100, 101, 105, 106, 107, 108, 109, 110, 116, 124, - 130, 138, 148, 150, 151, 152, 153, 156, 162, 168, - 174, 180, 186, 192, 200, 209, 215, 224, 225, 231, - 233, 234, 235, 236, 239, 245, 251, 257, 259, 264, - 273, 282, 283, 289, 291, 292, 293, 298, 305, 311, - 320, 321, 327, 329, 330, 331, 332, 335, 341, 348, - 355, 362, 368, 375, 376, 377, 380, 385, 390, 398, - 400, 404, 409, 410, 413, 414, 415, 419, 419, 421, - 422, 425, 426, 427, 428, 429, 430, 431, 434, 435 + 0, 94, 94, 95, 98, 99, 100, 101, 102, 103, + 104, 105, 109, 110, 111, 112, 113, 114, 120, 128, + 134, 142, 152, 154, 155, 156, 157, 160, 166, 173, + 179, 186, 192, 198, 204, 210, 216, 222, 230, 239, + 245, 254, 255, 261, 263, 264, 265, 266, 269, 275, + 281, 287, 293, 299, 301, 306, 315, 324, 325, 331, + 333, 334, 335, 340, 347, 353, 362, 363, 369, 371, + 372, 373, 374, 377, 383, 390, 397, 404, 410, 417, + 418, 419, 422, 427, 432, 440, 442, 447, 448, 451, + 452, 453, 457, 457, 459, 460, 463, 464, 465, 466, + 467, 468, 469, 472, 473 }; #endif @@ -437,9 +450,10 @@ "T_SOURCE", "T_CHOICE", "T_ENDCHOICE", "T_COMMENT", "T_CONFIG", "T_MENUCONFIG", "T_HELP", "T_HELPTEXT", "T_IF", "T_ENDIF", "T_DEPENDS", "T_REQUIRES", "T_OPTIONAL", "T_PROMPT", "T_DEFAULT", "T_TRISTATE", - "T_BOOLEAN", "T_STRING", "T_INT", "T_HEX", "T_WORD", "T_WORD_QUOTE", - "T_UNEQUAL", "T_EOF", "T_EOL", "T_CLOSE_PAREN", "T_OPEN_PAREN", "T_ON", - "T_OR", "T_AND", "T_EQUAL", "T_NOT", "$accept", "input", "block", + "T_DEF_TRISTATE", "T_BOOLEAN", "T_DEF_BOOLEAN", "T_STRING", "T_INT", + "T_HEX", "T_WORD", "T_WORD_QUOTE", "T_UNEQUAL", "T_EOF", "T_EOL", + "T_CLOSE_PAREN", "T_OPEN_PAREN", "T_ON", "T_SELECT", "T_RANGE", "T_OR", + "T_AND", "T_EQUAL", "T_NOT", "$accept", "input", "block", "common_block", "config_entry_start", "config_stmt", "menuconfig_entry_start", "menuconfig_stmt", "config_option_list", "config_option", "choice", "choice_entry", "choice_end", "choice_stmt", @@ -459,38 +473,41 @@ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, - 285, 286, 287, 288, 289, 290, 291, 292 + 285, 286, 287, 288, 289, 290, 291, 292, 293, 294, + 295, 296 }; # endif /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const unsigned char yyr1[] = { - 0, 38, 39, 39, 40, 40, 40, 40, 40, 40, - 40, 40, 41, 41, 41, 41, 41, 41, 42, 43, - 44, 45, 46, 46, 46, 46, 46, 47, 47, 47, - 47, 47, 47, 47, 48, 49, 50, 51, 51, 52, - 52, 52, 52, 52, 53, 53, 53, 54, 54, 55, - 56, 57, 57, 58, 58, 58, 58, 59, 60, 61, - 62, 62, 63, 63, 63, 63, 63, 64, 65, 66, - 67, 68, 69, 70, 70, 70, 71, 71, 71, 72, - 72, 72, 73, 73, 74, 74, 74, 75, 75, 76, - 76, 77, 77, 77, 77, 77, 77, 77, 78, 78 + 0, 42, 43, 43, 44, 44, 44, 44, 44, 44, + 44, 44, 45, 45, 45, 45, 45, 45, 46, 47, + 48, 49, 50, 50, 50, 50, 50, 51, 51, 51, + 51, 51, 51, 51, 51, 51, 51, 51, 52, 53, + 54, 55, 55, 56, 56, 56, 56, 56, 57, 57, + 57, 57, 57, 58, 58, 59, 60, 61, 61, 62, + 62, 62, 62, 63, 64, 65, 66, 66, 67, 67, + 67, 67, 67, 68, 69, 70, 71, 72, 73, 74, + 74, 74, 75, 75, 75, 76, 76, 77, 77, 78, + 78, 78, 79, 79, 80, 80, 81, 81, 81, 81, + 81, 81, 81, 82, 82 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ static const unsigned char yyr2[] = { 0, 2, 0, 2, 1, 1, 1, 3, 1, 1, - 1, 2, 1, 1, 1, 1, 1, 1, 2, 3, - 2, 3, 0, 3, 3, 2, 2, 2, 2, 2, - 2, 2, 3, 3, 1, 3, 1, 4, 2, 0, - 3, 3, 2, 2, 3, 1, 3, 0, 2, 2, - 1, 5, 3, 0, 2, 2, 2, 2, 3, 1, - 4, 2, 0, 2, 2, 2, 3, 2, 2, 2, - 3, 2, 2, 0, 3, 2, 3, 2, 2, 0, - 1, 3, 1, 1, 1, 1, 1, 1, 1, 0, - 2, 1, 3, 3, 3, 2, 3, 3, 1, 1 + 1, 2, 1, 1, 1, 1, 1, 1, 3, 2, + 3, 2, 0, 2, 2, 2, 2, 3, 4, 3, + 4, 3, 3, 3, 4, 4, 4, 5, 2, 2, + 1, 3, 2, 0, 2, 2, 2, 2, 4, 3, + 3, 2, 4, 0, 2, 3, 1, 3, 2, 0, + 2, 2, 2, 3, 2, 1, 3, 2, 0, 2, + 2, 2, 3, 3, 1, 3, 2, 2, 2, 0, + 2, 2, 4, 3, 3, 0, 2, 1, 1, 2, + 2, 2, 1, 1, 0, 2, 1, 3, 3, 3, + 2, 3, 3, 1, 1 }; /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state @@ -498,134 +515,151 @@ means the default is an error. */ static const unsigned char yydefact[] = { - 2, 0, 1, 0, 0, 0, 8, 0, 34, 10, - 0, 0, 0, 0, 9, 88, 87, 3, 4, 0, - 14, 0, 15, 0, 47, 5, 0, 12, 0, 62, - 6, 0, 16, 0, 13, 17, 11, 82, 83, 0, - 57, 67, 69, 18, 20, 98, 99, 0, 0, 49, - 91, 22, 22, 39, 38, 53, 73, 0, 68, 73, - 7, 0, 95, 0, 0, 0, 0, 19, 21, 35, - 84, 85, 86, 48, 0, 36, 52, 58, 0, 63, - 65, 0, 64, 59, 70, 94, 96, 97, 93, 92, - 0, 0, 0, 0, 0, 79, 79, 79, 79, 79, - 26, 0, 0, 25, 0, 45, 0, 0, 43, 0, - 42, 0, 37, 54, 56, 0, 55, 50, 75, 0, - 66, 60, 71, 0, 77, 78, 89, 89, 27, 80, - 28, 31, 29, 30, 23, 72, 24, 89, 89, 40, - 41, 51, 74, 76, 0, 32, 33, 0, 44, 46, - 90, 81 + 2, 0, 1, 0, 0, 0, 8, 0, 0, 10, + 0, 0, 0, 0, 9, 93, 92, 3, 4, 22, + 14, 22, 15, 43, 53, 5, 59, 12, 79, 68, + 6, 74, 16, 79, 13, 17, 11, 87, 88, 0, + 0, 0, 38, 0, 0, 0, 103, 104, 0, 0, + 0, 96, 19, 21, 39, 42, 58, 64, 0, 76, + 7, 63, 73, 75, 18, 20, 0, 100, 55, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 85, 0, + 85, 0, 85, 85, 85, 26, 0, 0, 23, 0, + 25, 24, 0, 0, 0, 85, 85, 47, 44, 46, + 45, 0, 0, 0, 54, 41, 40, 60, 62, 57, + 61, 56, 81, 80, 0, 69, 71, 66, 70, 65, + 99, 101, 102, 98, 97, 77, 0, 0, 0, 94, + 94, 0, 94, 94, 0, 94, 0, 0, 0, 94, + 0, 78, 51, 94, 94, 0, 0, 89, 90, 91, + 72, 0, 83, 84, 0, 0, 0, 27, 86, 0, + 29, 0, 33, 31, 32, 0, 94, 0, 0, 49, + 50, 82, 95, 34, 35, 28, 30, 36, 0, 48, + 52, 37 }; /* YYDEFGOTO[NTERM-NUM]. */ static const short yydefgoto[] = { - -1, 1, 17, 18, 19, 20, 21, 22, 67, 101, - 23, 24, 74, 25, 69, 109, 54, 26, 115, 27, - 76, 28, 29, 81, 30, 57, 31, 32, 33, 34, - 102, 103, 77, 104, 128, 129, 75, 35, 145, 49, - 50 + -1, 1, 17, 18, 19, 20, 21, 22, 52, 88, + 23, 24, 105, 25, 54, 98, 55, 26, 109, 27, + 56, 28, 29, 117, 30, 58, 31, 32, 33, 34, + 89, 90, 57, 91, 131, 132, 106, 35, 155, 50, + 51 }; /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ -#define YYPACT_NINF -121 +#define YYPACT_NINF -99 static const short yypact[] = { - -121, 25, -121, -18, -11, -11, -121, -11, -121, -121, - -11, 21, 27, 112, -121, -121, -121, -121, -121, 51, - -121, 54, -121, 57, -121, -121, 58, -121, 62, -121, - -121, 80, -121, 96, -121, -121, -121, -121, -121, -18, - -121, -121, -121, -121, -121, -121, -121, 112, 112, 17, - 77, -121, -121, -121, 85, -121, -121, 56, -121, -121, - -121, -21, -121, 112, 112, 42, 42, 100, 100, 115, - -121, -121, -121, -121, 98, -121, 68, 28, 99, -121, - -121, 111, -121, -121, 28, -121, 105, -121, -121, -121, - 116, 110, 112, -11, 42, -11, -11, -11, -11, -11, - -121, 118, 137, -121, 121, -121, -11, 42, -121, 122, - -121, 123, -121, -121, -121, 124, -121, -121, -121, 125, - -121, -121, -121, 112, 17, 17, 142, 142, -121, 143, - -121, -121, -121, -121, -121, -121, -121, 142, 142, -121, - -121, -121, -121, 17, 112, -121, -121, 112, -121, -121, - 17, 17 + -99, 48, -99, 38, 46, 46, -99, 46, -29, -99, + 46, -17, -3, -11, -99, -99, -99, -99, -99, -99, + -99, -99, -99, -99, -99, -99, -99, -99, -99, -99, + -99, -99, -99, -99, -99, -99, -99, -99, -99, 38, + 12, 15, -99, 18, 51, 62, -99, -99, -11, -11, + 4, -24, 138, 138, 160, 121, 110, -4, 81, -4, + -99, -99, -99, -99, -99, -99, -19, -99, -99, -11, + -11, 70, 70, 73, 32, -11, 46, -11, 46, -11, + 46, -11, 46, 46, 46, -99, 36, 70, -99, 95, + -99, -99, 96, 46, 106, 46, 46, -99, -99, -99, + -99, 38, 38, 38, -99, -99, -99, -99, -99, -99, + -99, -99, -99, -99, 112, -99, -99, -99, -99, -99, + -99, 117, -99, -99, -99, -99, -11, 33, 65, 131, + 1, 119, 131, 1, 136, 1, 153, 154, 155, 131, + 70, -99, -99, 131, 131, 156, 157, -99, -99, -99, + -99, 101, -99, -99, -11, 158, 159, -99, -99, 161, + -99, 162, -99, -99, -99, 163, 131, 164, 165, -99, + -99, -99, 99, -99, -99, -99, -99, -99, 166, -99, + -99, -99 }; /* YYPGOTO[NTERM-NUM]. */ -static const yysigned_char yypgoto[] = +static const short yypgoto[] = { - -121, -121, -121, -35, -121, -121, -121, -121, 106, -121, - -121, -121, -121, -34, -121, -121, -121, -121, -121, -121, - -121, -121, -121, -121, -33, -121, -121, -121, -121, -121, - -121, 90, 101, 34, 10, -4, -30, -1, -120, -43, - -57 + -99, -99, -99, 111, -99, -99, -99, -99, 178, -99, + -99, -99, -99, 91, -99, -99, -99, -99, -99, -99, + -99, -99, -99, -99, 115, -99, -99, -99, -99, -99, + -99, 146, 168, 89, 27, 0, 126, -1, -98, -48, + -63 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which number is the opposite. If zero, do what YYDEFACT says. If YYTABLE_NINF, syntax error. */ -#define YYTABLE_NINF -62 +#define YYTABLE_NINF -68 static const short yytable[] = { - 39, 40, 36, 41, 61, 62, 42, 146, 88, 89, - 85, 15, 16, 63, 64, 37, 38, 148, 149, 73, - 86, 87, 79, 80, 82, 2, 3, 83, 4, 5, - 6, 7, 8, 9, 10, 11, 12, 127, 60, 13, - 14, 113, 114, 116, 91, 92, 117, 43, 124, 125, - 138, 63, 64, 44, 15, 16, -61, 78, 118, -61, - 5, 70, 7, 8, 71, 10, 11, 12, 45, 46, - 13, 72, 5, 70, 7, 8, 71, 10, 11, 12, - 143, 51, 13, 72, 52, 15, 16, 53, 55, 126, - 70, 7, 56, 71, 10, 11, 12, 15, 16, 13, - 72, 150, 137, 111, 151, 65, 130, 131, 132, 133, - 58, 119, 90, 66, 15, 16, 91, 92, 119, 93, - 94, 95, 96, 97, 98, 99, 59, 90, 112, 120, - 100, 91, 92, 105, 106, 107, 45, 46, 45, 46, - 64, 121, 47, 123, 47, 108, 122, 48, 134, 48, - 135, 136, 139, 140, 141, 142, 144, 147, 68, 110, - 84 + 66, 67, 36, 42, 39, 40, 71, 41, 123, 124, + 43, 44, 74, 75, 120, 154, 72, 46, 47, 69, + 70, 121, 122, 48, 140, 45, 127, 128, 112, 130, + 49, 133, 156, 135, 158, 159, 68, 161, 60, 69, + 70, 165, 69, 70, 61, 167, 168, 62, 2, 3, + 63, 4, 5, 6, 7, 8, 9, 10, 11, 12, + 46, 47, 13, 14, 139, 152, 48, 126, 178, 15, + 16, 69, 70, 49, 37, 38, 129, 166, 151, 15, + 16, -67, 114, 64, -67, 5, 101, 7, 8, 102, + 10, 11, 12, 143, 65, 13, 103, 153, 46, 47, + 147, 148, 149, 69, 70, 125, 172, 134, 141, 136, + 137, 138, 15, 16, 5, 101, 7, 8, 102, 10, + 11, 12, 145, 146, 13, 103, 101, 7, 142, 102, + 10, 11, 12, 171, 144, 13, 103, 69, 70, 69, + 70, 15, 16, 100, 150, 154, 113, 108, 113, 116, + 73, 157, 15, 16, 74, 75, 70, 76, 77, 78, + 79, 80, 81, 82, 83, 84, 104, 107, 160, 115, + 85, 110, 73, 118, 86, 87, 74, 75, 92, 93, + 94, 95, 111, 96, 119, 162, 163, 164, 169, 170, + 173, 174, 97, 175, 176, 177, 179, 180, 181, 53, + 99, 59 }; static const unsigned char yycheck[] = { - 4, 5, 3, 7, 47, 48, 10, 127, 65, 66, - 31, 29, 30, 34, 35, 26, 27, 137, 138, 54, - 63, 64, 57, 57, 57, 0, 1, 57, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 94, 39, 14, - 15, 76, 76, 76, 16, 17, 76, 26, 91, 92, - 107, 34, 35, 26, 29, 30, 0, 1, 30, 3, - 4, 5, 6, 7, 8, 9, 10, 11, 26, 27, - 14, 15, 4, 5, 6, 7, 8, 9, 10, 11, - 123, 30, 14, 15, 30, 29, 30, 30, 30, 93, - 5, 6, 30, 8, 9, 10, 11, 29, 30, 14, - 15, 144, 106, 69, 147, 28, 96, 97, 98, 99, - 30, 77, 12, 36, 29, 30, 16, 17, 84, 19, - 20, 21, 22, 23, 24, 25, 30, 12, 30, 30, - 30, 16, 17, 18, 19, 20, 26, 27, 26, 27, - 35, 30, 32, 33, 32, 30, 30, 37, 30, 37, - 13, 30, 30, 30, 30, 30, 14, 14, 52, 69, - 59 + 48, 49, 3, 32, 4, 5, 30, 7, 71, 72, + 10, 28, 16, 17, 33, 14, 40, 28, 29, 38, + 39, 69, 70, 34, 87, 28, 74, 75, 32, 77, + 41, 79, 130, 81, 132, 133, 32, 135, 39, 38, + 39, 139, 38, 39, 32, 143, 144, 32, 0, 1, + 32, 3, 4, 5, 6, 7, 8, 9, 10, 11, + 28, 29, 14, 15, 28, 32, 34, 35, 166, 31, + 32, 38, 39, 41, 28, 29, 76, 140, 126, 31, + 32, 0, 1, 32, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 93, 32, 14, 15, 32, 28, 29, + 101, 102, 103, 38, 39, 32, 154, 80, 13, 82, + 83, 84, 31, 32, 4, 5, 6, 7, 8, 9, + 10, 11, 95, 96, 14, 15, 5, 6, 32, 8, + 9, 10, 11, 32, 28, 14, 15, 38, 39, 38, + 39, 31, 32, 54, 32, 14, 57, 56, 59, 58, + 12, 32, 31, 32, 16, 17, 39, 19, 20, 21, + 22, 23, 24, 25, 26, 27, 55, 56, 32, 58, + 32, 56, 12, 58, 36, 37, 16, 17, 18, 19, + 20, 21, 56, 23, 58, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 21, + 54, 33 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const unsigned char yystos[] = { - 0, 39, 0, 1, 3, 4, 5, 6, 7, 8, - 9, 10, 11, 14, 15, 29, 30, 40, 41, 42, - 43, 44, 45, 48, 49, 51, 55, 57, 59, 60, - 62, 64, 65, 66, 67, 75, 75, 26, 27, 73, - 73, 73, 73, 26, 26, 26, 27, 32, 37, 77, - 78, 30, 30, 30, 54, 30, 30, 63, 30, 30, - 75, 77, 77, 34, 35, 28, 36, 46, 46, 52, - 5, 8, 15, 41, 50, 74, 58, 70, 1, 41, - 51, 61, 62, 74, 70, 31, 77, 77, 78, 78, - 12, 16, 17, 19, 20, 21, 22, 23, 24, 25, - 30, 47, 68, 69, 71, 18, 19, 20, 30, 53, - 69, 71, 30, 41, 51, 56, 62, 74, 30, 71, - 30, 30, 30, 33, 77, 77, 73, 78, 72, 73, - 72, 72, 72, 72, 30, 13, 30, 73, 78, 30, - 30, 30, 30, 77, 14, 76, 76, 14, 76, 76, - 77, 77 + 0, 43, 0, 1, 3, 4, 5, 6, 7, 8, + 9, 10, 11, 14, 15, 31, 32, 44, 45, 46, + 47, 48, 49, 52, 53, 55, 59, 61, 63, 64, + 66, 68, 69, 70, 71, 79, 79, 28, 29, 77, + 77, 77, 32, 77, 28, 28, 28, 29, 34, 41, + 81, 82, 50, 50, 56, 58, 62, 74, 67, 74, + 79, 32, 32, 32, 32, 32, 81, 81, 32, 38, + 39, 30, 40, 12, 16, 17, 19, 20, 21, 22, + 23, 24, 25, 26, 27, 32, 36, 37, 51, 72, + 73, 75, 18, 19, 20, 21, 23, 32, 57, 73, + 75, 5, 8, 15, 45, 54, 78, 45, 55, 60, + 66, 78, 32, 75, 1, 45, 55, 65, 66, 78, + 33, 81, 81, 82, 82, 32, 35, 81, 81, 77, + 81, 76, 77, 81, 76, 81, 76, 76, 76, 28, + 82, 13, 32, 77, 28, 76, 76, 79, 79, 79, + 32, 81, 32, 32, 14, 80, 80, 32, 80, 80, + 32, 80, 32, 32, 32, 80, 82, 80, 80, 32, + 32, 32, 81, 32, 32, 32, 32, 32, 80, 32, + 32, 32 }; #if ! defined (YYSIZE_T) && defined (__SIZE_TYPE__) @@ -1258,10 +1292,10 @@ case 18: { - struct symbol *sym = sym_lookup(yyvsp[0].string, 0); + struct symbol *sym = sym_lookup(yyvsp[-1].string, 0); sym->flags |= SYMBOL_OPTIONAL; menu_add_entry(sym); - printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), yyvsp[0].string); + printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), yyvsp[-1].string); ;} break; @@ -1276,10 +1310,10 @@ case 20: { - struct symbol *sym = sym_lookup(yyvsp[0].string, 0); + struct symbol *sym = sym_lookup(yyvsp[-1].string, 0); sym->flags |= SYMBOL_OPTIONAL; menu_add_entry(sym); - printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), yyvsp[0].string); + printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), yyvsp[-1].string); ;} break; @@ -1295,11 +1329,6 @@ ;} break; - case 26: - - { ;} - break; - case 27: { @@ -1311,12 +1340,30 @@ case 28: { + menu_add_expr(P_DEFAULT, yyvsp[-2].expr, yyvsp[-1].expr); + menu_set_type(S_TRISTATE); + printd(DEBUG_PARSE, "%s:%d:def_boolean\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 29: + + { menu_set_type(S_BOOLEAN); printd(DEBUG_PARSE, "%s:%d:boolean\n", zconf_curname(), zconf_lineno()); ;} break; - case 29: + case 30: + + { + menu_add_expr(P_DEFAULT, yyvsp[-2].expr, yyvsp[-1].expr); + menu_set_type(S_BOOLEAN); + printd(DEBUG_PARSE, "%s:%d:def_boolean\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 31: { menu_set_type(S_INT); @@ -1324,7 +1371,7 @@ ;} break; - case 30: + case 32: { menu_set_type(S_HEX); @@ -1332,7 +1379,7 @@ ;} break; - case 31: + case 33: { menu_set_type(S_STRING); @@ -1340,34 +1387,50 @@ ;} break; - case 32: + case 34: { - menu_add_prop(P_PROMPT, yyvsp[-1].string, NULL, yyvsp[0].expr); + menu_add_prompt(P_PROMPT, yyvsp[-2].string, yyvsp[-1].expr); printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); ;} break; - case 33: + case 35: { - menu_add_prop(P_DEFAULT, NULL, yyvsp[-1].symbol, yyvsp[0].expr); + menu_add_expr(P_DEFAULT, yyvsp[-2].expr, yyvsp[-1].expr); printd(DEBUG_PARSE, "%s:%d:default\n", zconf_curname(), zconf_lineno()); ;} break; - case 34: + case 36: + + { + menu_add_symbol(P_SELECT, sym_lookup(yyvsp[-2].string, 0), yyvsp[-1].expr); + printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 37: + + { + menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,yyvsp[-3].symbol, yyvsp[-2].symbol), yyvsp[-1].expr); + printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 38: { struct symbol *sym = sym_lookup(NULL, 0); sym->flags |= SYMBOL_CHOICE; menu_add_entry(sym); - menu_add_prop(P_CHOICE, NULL, NULL, NULL); + menu_add_expr(P_CHOICE, NULL, NULL); printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno()); ;} break; - case 35: + case 39: { menu_end_entry(); @@ -1375,7 +1438,7 @@ ;} break; - case 36: + case 40: { if (zconf_endtoken(yyvsp[0].token, T_CHOICE, T_ENDCHOICE)) { @@ -1385,7 +1448,7 @@ ;} break; - case 38: + case 42: { printf("%s:%d: missing 'endchoice' for this 'choice' statement\n", current_menu->file->name, current_menu->lineno); @@ -1393,15 +1456,31 @@ ;} break; - case 44: + case 48: { - menu_add_prop(P_PROMPT, yyvsp[-1].string, NULL, yyvsp[0].expr); + menu_add_prompt(P_PROMPT, yyvsp[-2].string, yyvsp[-1].expr); printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); ;} break; - case 45: + case 49: + + { + menu_set_type(S_TRISTATE); + printd(DEBUG_PARSE, "%s:%d:tristate\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 50: + + { + menu_set_type(S_BOOLEAN); + printd(DEBUG_PARSE, "%s:%d:boolean\n", zconf_curname(), zconf_lineno()); +;} + break; + + case 51: { current_entry->sym->flags |= SYMBOL_OPTIONAL; @@ -1409,26 +1488,26 @@ ;} break; - case 46: + case 52: { - menu_add_prop(P_DEFAULT, NULL, yyvsp[-1].symbol, yyvsp[0].expr); + menu_add_symbol(P_DEFAULT, sym_lookup(yyvsp[-2].string, 0), yyvsp[-1].expr); printd(DEBUG_PARSE, "%s:%d:default\n", zconf_curname(), zconf_lineno()); ;} break; - case 49: + case 55: { printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno()); menu_add_entry(NULL); - menu_add_dep(yyvsp[0].expr); + menu_add_dep(yyvsp[-1].expr); menu_end_entry(); menu_add_menu(); ;} break; - case 50: + case 56: { if (zconf_endtoken(yyvsp[0].token, T_IF, T_ENDIF)) { @@ -1438,7 +1517,7 @@ ;} break; - case 52: + case 58: { printf("%s:%d: missing 'endif' for this 'if' statement\n", current_menu->file->name, current_menu->lineno); @@ -1446,16 +1525,16 @@ ;} break; - case 57: + case 63: { menu_add_entry(NULL); - menu_add_prop(P_MENU, yyvsp[0].string, NULL, NULL); + menu_add_prop(P_MENU, yyvsp[-1].string, NULL, NULL); printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno()); ;} break; - case 58: + case 64: { menu_end_entry(); @@ -1463,7 +1542,7 @@ ;} break; - case 59: + case 65: { if (zconf_endtoken(yyvsp[0].token, T_MENU, T_ENDMENU)) { @@ -1473,7 +1552,7 @@ ;} break; - case 61: + case 67: { printf("%s:%d: missing 'endmenu' for this 'menu' statement\n", current_menu->file->name, current_menu->lineno); @@ -1481,43 +1560,43 @@ ;} break; - case 66: + case 72: { zconfprint("invalid menu option"); yyerrok; ;} break; - case 67: + case 73: { - yyval.string = yyvsp[0].string; - printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), yyvsp[0].string); + yyval.string = yyvsp[-1].string; + printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), yyvsp[-1].string); ;} break; - case 68: + case 74: { - zconf_nextfile(yyvsp[-1].string); + zconf_nextfile(yyvsp[0].string); ;} break; - case 69: + case 75: { menu_add_entry(NULL); - menu_add_prop(P_COMMENT, yyvsp[0].string, NULL, NULL); + menu_add_prop(P_COMMENT, yyvsp[-1].string, NULL, NULL); printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno()); ;} break; - case 70: + case 76: { menu_end_entry(); ;} break; - case 71: + case 77: { printd(DEBUG_PARSE, "%s:%d:help\n", zconf_curname(), zconf_lineno()); @@ -1525,122 +1604,110 @@ ;} break; - case 72: + case 78: { current_entry->sym->help = yyvsp[0].string; ;} break; - case 75: - - { ;} - break; - - case 76: + case 82: { - menu_add_dep(yyvsp[0].expr); + menu_add_dep(yyvsp[-1].expr); printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno()); ;} break; - case 77: + case 83: { - menu_add_dep(yyvsp[0].expr); + menu_add_dep(yyvsp[-1].expr); printd(DEBUG_PARSE, "%s:%d:depends\n", zconf_curname(), zconf_lineno()); ;} break; - case 78: + case 84: { - menu_add_dep(yyvsp[0].expr); + menu_add_dep(yyvsp[-1].expr); printd(DEBUG_PARSE, "%s:%d:requires\n", zconf_curname(), zconf_lineno()); ;} break; - case 80: - - { - menu_add_prop(P_PROMPT, yyvsp[0].string, NULL, NULL); -;} - break; - - case 81: + case 86: { - menu_add_prop(P_PROMPT, yyvsp[-2].string, NULL, yyvsp[0].expr); + menu_add_prop(P_PROMPT, yyvsp[-1].string, NULL, yyvsp[0].expr); ;} break; - case 84: + case 89: { yyval.token = T_ENDMENU; ;} break; - case 85: + case 90: { yyval.token = T_ENDCHOICE; ;} break; - case 86: + case 91: { yyval.token = T_ENDIF; ;} break; - case 89: + case 94: { yyval.expr = NULL; ;} break; - case 90: + case 95: { yyval.expr = yyvsp[0].expr; ;} break; - case 91: + case 96: { yyval.expr = expr_alloc_symbol(yyvsp[0].symbol); ;} break; - case 92: + case 97: { yyval.expr = expr_alloc_comp(E_EQUAL, yyvsp[-2].symbol, yyvsp[0].symbol); ;} break; - case 93: + case 98: { yyval.expr = expr_alloc_comp(E_UNEQUAL, yyvsp[-2].symbol, yyvsp[0].symbol); ;} break; - case 94: + case 99: { yyval.expr = yyvsp[-1].expr; ;} break; - case 95: + case 100: { yyval.expr = expr_alloc_one(E_NOT, yyvsp[0].expr); ;} break; - case 96: + case 101: { yyval.expr = expr_alloc_two(E_OR, yyvsp[-2].expr, yyvsp[0].expr); ;} break; - case 97: + case 102: { yyval.expr = expr_alloc_two(E_AND, yyvsp[-2].expr, yyvsp[0].expr); ;} break; - case 98: + case 103: { yyval.symbol = sym_lookup(yyvsp[0].string, 0); free(yyvsp[0].string); ;} break; - case 99: + case 104: { yyval.symbol = sym_lookup(yyvsp[0].string, 1); free(yyvsp[0].string); ;} break; @@ -1848,6 +1915,9 @@ void conf_parse(const char *name) { + struct symbol *sym; + int i; + zconf_initscan(name); sym_init(); @@ -1860,6 +1930,12 @@ if (zconfnerrs) exit(1); menu_finalize(&rootmenu); + for_all_symbols(i, sym) { + if (!(sym->flags & SYMBOL_CHECKED) && sym_check_deps(sym)) + printf("\n"); + else + sym->flags |= SYMBOL_CHECK_DONE; + } sym_change_count = 1; } @@ -1875,7 +1951,7 @@ case T_ENDIF: return "endif"; } return "<token>"; -} +} static bool zconf_endtoken(int token, int starttoken, int endtoken) { @@ -1897,7 +1973,7 @@ { va_list ap; - fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); + fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno() + 1); va_start(ap, err); vfprintf(stderr, err, ap); va_end(ap); @@ -1906,7 +1982,7 @@ static void zconferror(const char *err) { - fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno(), err); + fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err); } void print_quoted_string(FILE *out, const char *str) @@ -1931,8 +2007,6 @@ struct symbol *sym = menu->sym; struct property *prop; - //sym->flags |= SYMBOL_PRINTED; - if (sym_is_choice(sym)) fprintf(out, "choice\n"); else @@ -1957,13 +2031,6 @@ fputs(" ???\n", out); break; } -#if 0 - if (!expr_is_yes(sym->dep)) { - fputs(" depends ", out); - expr_fprint(sym->dep, out); - fputc('\n', out); - } -#endif for (prop = sym->prop; prop; prop = prop->next) { if (prop->menu != menu) continue; @@ -1971,25 +2038,18 @@ case P_PROMPT: fputs(" prompt ", out); print_quoted_string(out, prop->text); - if (prop->def) { - fputc(' ', out); - if (prop->def->flags & SYMBOL_CONST) - print_quoted_string(out, prop->def->name); - else - fputs(prop->def->name, out); - } - if (!expr_is_yes(E_EXPR(prop->visible))) { + if (!expr_is_yes(prop->visible.expr)) { fputs(" if ", out); - expr_fprint(E_EXPR(prop->visible), out); + expr_fprint(prop->visible.expr, out); } fputc('\n', out); break; case P_DEFAULT: fputs( " default ", out); - print_quoted_string(out, prop->def->name); - if (!expr_is_yes(E_EXPR(prop->visible))) { + expr_fprint(prop->expr, out); + if (!expr_is_yes(prop->visible.expr)) { fputs(" if ", out); - expr_fprint(E_EXPR(prop->visible), out); + expr_fprint(prop->visible.expr, out); } fputc('\n', out); break; @@ -2012,7 +2072,6 @@ void zconfdump(FILE *out) { - //struct file *file; struct property *prop; struct symbol *sym; struct menu *menu; @@ -2023,11 +2082,6 @@ print_symbol(out, menu); else if ((prop = menu->prompt)) { switch (prop->type) { - //case T_MAINMENU: - // fputs("\nmainmenu ", out); - // print_quoted_string(out, prop->text); - // fputs("\n", out); - // break; case P_COMMENT: fputs("\ncomment ", out); print_quoted_string(out, prop->text); @@ -2038,19 +2092,12 @@ print_quoted_string(out, prop->text); fputs("\n", out); break; - //case T_SOURCE: - // fputs("\nsource ", out); - // print_quoted_string(out, prop->text); - // fputs("\n", out); - // break; - //case T_IF: - // fputs("\nif\n", out); default: ; } - if (!expr_is_yes(E_EXPR(prop->visible))) { + if (!expr_is_yes(prop->visible.expr)) { fputs(" depends ", out); - expr_fprint(E_EXPR(prop->visible), out); + expr_fprint(prop->visible.expr, out); fputc('\n', out); } fputs("\n", out); diff -Nru a/scripts/kconfig/zconf.y b/scripts/kconfig/zconf.y --- a/scripts/kconfig/zconf.y Mon Jun 9 23:16:18 2003 +++ b/scripts/kconfig/zconf.y Mon Jun 9 23:16:18 2003 @@ -57,7 +57,9 @@ %token T_PROMPT %token T_DEFAULT %token T_TRISTATE +%token T_DEF_TRISTATE %token T_BOOLEAN +%token T_DEF_BOOLEAN %token T_STRING %token T_INT %token T_HEX @@ -69,6 +71,8 @@ %token T_CLOSE_PAREN %token T_OPEN_PAREN %token T_ON +%token T_SELECT +%token T_RANGE %left T_OR %left T_AND @@ -113,7 +117,7 @@ /* config/menuconfig entry */ -config_entry_start: T_CONFIG T_WORD +config_entry_start: T_CONFIG T_WORD T_EOL { struct symbol *sym = sym_lookup($2, 0); sym->flags |= SYMBOL_OPTIONAL; @@ -121,13 +125,13 @@ printd(DEBUG_PARSE, "%s:%d:config %s\n", zconf_curname(), zconf_lineno(), $2); }; -config_stmt: config_entry_start T_EOL config_option_list +config_stmt: config_entry_start config_option_list { menu_end_entry(); printd(DEBUG_PARSE, "%s:%d:endconfig\n", zconf_curname(), zconf_lineno()); }; -menuconfig_entry_start: T_MENUCONFIG T_WORD +menuconfig_entry_start: T_MENUCONFIG T_WORD T_EOL { struct symbol *sym = sym_lookup($2, 0); sym->flags |= SYMBOL_OPTIONAL; @@ -135,7 +139,7 @@ printd(DEBUG_PARSE, "%s:%d:menuconfig %s\n", zconf_curname(), zconf_lineno(), $2); }; -menuconfig_stmt: menuconfig_entry_start T_EOL config_option_list +menuconfig_stmt: menuconfig_entry_start config_option_list { if (current_entry->prompt) current_entry->prompt->type = P_MENU; @@ -147,66 +151,92 @@ config_option_list: /* empty */ - | config_option_list config_option T_EOL - | config_option_list depends T_EOL + | config_option_list config_option + | config_option_list depends | config_option_list help | config_option_list T_EOL -{ }; +; -config_option: T_TRISTATE prompt_stmt_opt +config_option: T_TRISTATE prompt_stmt_opt T_EOL { menu_set_type(S_TRISTATE); printd(DEBUG_PARSE, "%s:%d:tristate\n", zconf_curname(), zconf_lineno()); }; -config_option: T_BOOLEAN prompt_stmt_opt +config_option: T_DEF_TRISTATE expr if_expr T_EOL +{ + menu_add_expr(P_DEFAULT, $2, $3); + menu_set_type(S_TRISTATE); + printd(DEBUG_PARSE, "%s:%d:def_boolean\n", zconf_curname(), zconf_lineno()); +}; + +config_option: T_BOOLEAN prompt_stmt_opt T_EOL { menu_set_type(S_BOOLEAN); printd(DEBUG_PARSE, "%s:%d:boolean\n", zconf_curname(), zconf_lineno()); }; -config_option: T_INT prompt_stmt_opt +config_option: T_DEF_BOOLEAN expr if_expr T_EOL +{ + menu_add_expr(P_DEFAULT, $2, $3); + menu_set_type(S_BOOLEAN); + printd(DEBUG_PARSE, "%s:%d:def_boolean\n", zconf_curname(), zconf_lineno()); +}; + +config_option: T_INT prompt_stmt_opt T_EOL { menu_set_type(S_INT); printd(DEBUG_PARSE, "%s:%d:int\n", zconf_curname(), zconf_lineno()); }; -config_option: T_HEX prompt_stmt_opt +config_option: T_HEX prompt_stmt_opt T_EOL { menu_set_type(S_HEX); printd(DEBUG_PARSE, "%s:%d:hex\n", zconf_curname(), zconf_lineno()); }; -config_option: T_STRING prompt_stmt_opt +config_option: T_STRING prompt_stmt_opt T_EOL { menu_set_type(S_STRING); printd(DEBUG_PARSE, "%s:%d:string\n", zconf_curname(), zconf_lineno()); }; -config_option: T_PROMPT prompt if_expr +config_option: T_PROMPT prompt if_expr T_EOL { - menu_add_prop(P_PROMPT, $2, NULL, $3); + menu_add_prompt(P_PROMPT, $2, $3); printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); }; -config_option: T_DEFAULT symbol if_expr +config_option: T_DEFAULT expr if_expr T_EOL { - menu_add_prop(P_DEFAULT, NULL, $2, $3); + menu_add_expr(P_DEFAULT, $2, $3); printd(DEBUG_PARSE, "%s:%d:default\n", zconf_curname(), zconf_lineno()); }; +config_option: T_SELECT T_WORD if_expr T_EOL +{ + menu_add_symbol(P_SELECT, sym_lookup($2, 0), $3); + printd(DEBUG_PARSE, "%s:%d:select\n", zconf_curname(), zconf_lineno()); +}; + +config_option: T_RANGE symbol symbol if_expr T_EOL +{ + menu_add_expr(P_RANGE, expr_alloc_comp(E_RANGE,$2, $3), $4); + printd(DEBUG_PARSE, "%s:%d:range\n", zconf_curname(), zconf_lineno()); +}; + /* choice entry */ -choice: T_CHOICE +choice: T_CHOICE T_EOL { struct symbol *sym = sym_lookup(NULL, 0); sym->flags |= SYMBOL_CHOICE; menu_add_entry(sym); - menu_add_prop(P_CHOICE, NULL, NULL, NULL); + menu_add_expr(P_CHOICE, NULL, NULL); printd(DEBUG_PARSE, "%s:%d:choice\n", zconf_curname(), zconf_lineno()); }; -choice_entry: choice T_EOL choice_option_list +choice_entry: choice choice_option_list { menu_end_entry(); menu_add_menu(); @@ -221,7 +251,7 @@ }; choice_stmt: - choice_entry choice_block choice_end T_EOL + choice_entry choice_block choice_end | choice_entry choice_block { printf("%s:%d: missing 'endchoice' for this 'choice' statement\n", current_menu->file->name, current_menu->lineno); @@ -230,27 +260,39 @@ choice_option_list: /* empty */ - | choice_option_list choice_option T_EOL - | choice_option_list depends T_EOL + | choice_option_list choice_option + | choice_option_list depends | choice_option_list help | choice_option_list T_EOL ; -choice_option: T_PROMPT prompt if_expr +choice_option: T_PROMPT prompt if_expr T_EOL { - menu_add_prop(P_PROMPT, $2, NULL, $3); + menu_add_prompt(P_PROMPT, $2, $3); printd(DEBUG_PARSE, "%s:%d:prompt\n", zconf_curname(), zconf_lineno()); }; -choice_option: T_OPTIONAL +choice_option: T_TRISTATE prompt_stmt_opt T_EOL +{ + menu_set_type(S_TRISTATE); + printd(DEBUG_PARSE, "%s:%d:tristate\n", zconf_curname(), zconf_lineno()); +}; + +choice_option: T_BOOLEAN prompt_stmt_opt T_EOL +{ + menu_set_type(S_BOOLEAN); + printd(DEBUG_PARSE, "%s:%d:boolean\n", zconf_curname(), zconf_lineno()); +}; + +choice_option: T_OPTIONAL T_EOL { current_entry->sym->flags |= SYMBOL_OPTIONAL; printd(DEBUG_PARSE, "%s:%d:optional\n", zconf_curname(), zconf_lineno()); }; -choice_option: T_DEFAULT symbol if_expr +choice_option: T_DEFAULT T_WORD if_expr T_EOL { - menu_add_prop(P_DEFAULT, NULL, $2, $3); + menu_add_symbol(P_DEFAULT, sym_lookup($2, 0), $3); printd(DEBUG_PARSE, "%s:%d:default\n", zconf_curname(), zconf_lineno()); }; @@ -261,7 +303,7 @@ /* if entry */ -if: T_IF expr +if: T_IF expr T_EOL { printd(DEBUG_PARSE, "%s:%d:if\n", zconf_curname(), zconf_lineno()); menu_add_entry(NULL); @@ -279,8 +321,8 @@ }; if_stmt: - if T_EOL if_block if_end T_EOL - | if T_EOL if_block + if if_block if_end + | if if_block { printf("%s:%d: missing 'endif' for this 'if' statement\n", current_menu->file->name, current_menu->lineno); zconfnerrs++; @@ -295,14 +337,14 @@ /* menu entry */ -menu: T_MENU prompt +menu: T_MENU prompt T_EOL { menu_add_entry(NULL); menu_add_prop(P_MENU, $2, NULL, NULL); printd(DEBUG_PARSE, "%s:%d:menu\n", zconf_curname(), zconf_lineno()); }; -menu_entry: menu T_EOL depends_list +menu_entry: menu depends_list { menu_end_entry(); menu_add_menu(); @@ -317,7 +359,7 @@ }; menu_stmt: - menu_entry menu_block menu_end T_EOL + menu_entry menu_block menu_end | menu_entry menu_block { printf("%s:%d: missing 'endmenu' for this 'menu' statement\n", current_menu->file->name, current_menu->lineno); @@ -332,27 +374,27 @@ | menu_block error T_EOL { zconfprint("invalid menu option"); yyerrok; } ; -source: T_SOURCE prompt +source: T_SOURCE prompt T_EOL { $$ = $2; printd(DEBUG_PARSE, "%s:%d:source %s\n", zconf_curname(), zconf_lineno(), $2); }; -source_stmt: source T_EOL +source_stmt: source { zconf_nextfile($1); }; /* comment entry */ -comment: T_COMMENT prompt +comment: T_COMMENT prompt T_EOL { menu_add_entry(NULL); menu_add_prop(P_COMMENT, $2, NULL, NULL); printd(DEBUG_PARSE, "%s:%d:comment\n", zconf_curname(), zconf_lineno()); }; -comment_stmt: comment T_EOL depends_list +comment_stmt: comment depends_list { menu_end_entry(); }; @@ -373,21 +415,21 @@ /* depends option */ depends_list: /* empty */ - | depends_list depends T_EOL + | depends_list depends | depends_list T_EOL -{ }; +; -depends: T_DEPENDS T_ON expr +depends: T_DEPENDS T_ON expr T_EOL { menu_add_dep($3); printd(DEBUG_PARSE, "%s:%d:depends on\n", zconf_curname(), zconf_lineno()); } - | T_DEPENDS expr + | T_DEPENDS expr T_EOL { menu_add_dep($2); printd(DEBUG_PARSE, "%s:%d:depends\n", zconf_curname(), zconf_lineno()); } - | T_REQUIRES expr + | T_REQUIRES expr T_EOL { menu_add_dep($2); printd(DEBUG_PARSE, "%s:%d:requires\n", zconf_curname(), zconf_lineno()); @@ -397,22 +439,18 @@ prompt_stmt_opt: /* empty */ - | prompt + | prompt if_expr { - menu_add_prop(P_PROMPT, $1, NULL, NULL); -} - | prompt T_IF expr -{ - menu_add_prop(P_PROMPT, $1, NULL, $3); + menu_add_prop(P_PROMPT, $1, NULL, $2); }; prompt: T_WORD | T_WORD_QUOTE ; -end: T_ENDMENU { $$ = T_ENDMENU; } - | T_ENDCHOICE { $$ = T_ENDCHOICE; } - | T_ENDIF { $$ = T_ENDIF; } +end: T_ENDMENU nl_or_eof { $$ = T_ENDMENU; } + | T_ENDCHOICE nl_or_eof { $$ = T_ENDCHOICE; } + | T_ENDIF nl_or_eof { $$ = T_ENDIF; } ; nl_or_eof: @@ -439,6 +477,9 @@ void conf_parse(const char *name) { + struct symbol *sym; + int i; + zconf_initscan(name); sym_init(); @@ -451,6 +492,12 @@ if (zconfnerrs) exit(1); menu_finalize(&rootmenu); + for_all_symbols(i, sym) { + if (!(sym->flags & SYMBOL_CHECKED) && sym_check_deps(sym)) + printf("\n"); + else + sym->flags |= SYMBOL_CHECK_DONE; + } sym_change_count = 1; } @@ -466,7 +513,7 @@ case T_ENDIF: return "endif"; } return "<token>"; -} +} static bool zconf_endtoken(int token, int starttoken, int endtoken) { @@ -488,7 +535,7 @@ { va_list ap; - fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno()); + fprintf(stderr, "%s:%d: ", zconf_curname(), zconf_lineno() + 1); va_start(ap, err); vfprintf(stderr, err, ap); va_end(ap); @@ -497,7 +544,7 @@ static void zconferror(const char *err) { - fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno(), err); + fprintf(stderr, "%s:%d: %s\n", zconf_curname(), zconf_lineno() + 1, err); } void print_quoted_string(FILE *out, const char *str) @@ -522,8 +569,6 @@ struct symbol *sym = menu->sym; struct property *prop; - //sym->flags |= SYMBOL_PRINTED; - if (sym_is_choice(sym)) fprintf(out, "choice\n"); else @@ -548,13 +593,6 @@ fputs(" ???\n", out); break; } -#if 0 - if (!expr_is_yes(sym->dep)) { - fputs(" depends ", out); - expr_fprint(sym->dep, out); - fputc('\n', out); - } -#endif for (prop = sym->prop; prop; prop = prop->next) { if (prop->menu != menu) continue; @@ -562,25 +600,18 @@ case P_PROMPT: fputs(" prompt ", out); print_quoted_string(out, prop->text); - if (prop->def) { - fputc(' ', out); - if (prop->def->flags & SYMBOL_CONST) - print_quoted_string(out, prop->def->name); - else - fputs(prop->def->name, out); - } - if (!expr_is_yes(E_EXPR(prop->visible))) { + if (!expr_is_yes(prop->visible.expr)) { fputs(" if ", out); - expr_fprint(E_EXPR(prop->visible), out); + expr_fprint(prop->visible.expr, out); } fputc('\n', out); break; case P_DEFAULT: fputs( " default ", out); - print_quoted_string(out, prop->def->name); - if (!expr_is_yes(E_EXPR(prop->visible))) { + expr_fprint(prop->expr, out); + if (!expr_is_yes(prop->visible.expr)) { fputs(" if ", out); - expr_fprint(E_EXPR(prop->visible), out); + expr_fprint(prop->visible.expr, out); } fputc('\n', out); break; @@ -603,7 +634,6 @@ void zconfdump(FILE *out) { - //struct file *file; struct property *prop; struct symbol *sym; struct menu *menu; @@ -614,11 +644,6 @@ print_symbol(out, menu); else if ((prop = menu->prompt)) { switch (prop->type) { - //case T_MAINMENU: - // fputs("\nmainmenu ", out); - // print_quoted_string(out, prop->text); - // fputs("\n", out); - // break; case P_COMMENT: fputs("\ncomment ", out); print_quoted_string(out, prop->text); @@ -629,19 +654,12 @@ print_quoted_string(out, prop->text); fputs("\n", out); break; - //case T_SOURCE: - // fputs("\nsource ", out); - // print_quoted_string(out, prop->text); - // fputs("\n", out); - // break; - //case T_IF: - // fputs("\nif\n", out); default: ; } - if (!expr_is_yes(E_EXPR(prop->visible))) { + if (!expr_is_yes(prop->visible.expr)) { fputs(" depends ", out); - expr_fprint(E_EXPR(prop->visible), out); + expr_fprint(prop->visible.expr, out); fputc('\n', out); } fputs("\n", out); diff -Nru a/scripts/kernel-doc b/scripts/kernel-doc --- a/scripts/kernel-doc Mon Jun 9 23:16:11 2003 +++ b/scripts/kernel-doc Mon Jun 9 23:16:11 2003 @@ -154,6 +154,7 @@ # '%CONST' - name of a constant. my $errors = 0; +my $warnings = 0; # match expressions used to find embedded type information my $type_constant = '\%([-_\w]+)'; @@ -1352,7 +1353,9 @@ "or member '$param' not " . "described in '$declaration_name'\n"; } - ++$errors; + print STDERR "Warning(${file}:$.):". + " No description found for parameter '$param'\n"; + ++$warnings; } push @parameterlist, $param; @@ -1456,6 +1459,12 @@ chomp; process_file($_); } +if ($verbose && $errors) { + print STDERR "$errors errors\n"; +} +if ($verbose && $warnings) { + print STDERR "$warnings warnings\n"; +} exit($errors); @@ -1580,7 +1589,7 @@ } else { print STDERR "Warning(${file}:$.): Cannot understand $_ on line $.", " - I thought it was a doc line\n"; - ++$errors; + ++$warnings; $state = 0; } } elsif ($state == 2) { # look for head: lines, and include content @@ -1633,7 +1642,7 @@ } else { # i dont know - bad line? ignore. print STDERR "Warning(${file}:$.): bad line: $_"; - ++$errors; + ++$warnings; } } elsif ($state == 3) { # scanning for function { (end of prototype) if ($decl_type eq 'function') { diff -Nru a/security/Kconfig b/security/Kconfig --- a/security/Kconfig Mon Jun 9 23:16:15 2003 +++ b/security/Kconfig Mon Jun 9 23:16:15 2003 @@ -33,7 +33,7 @@ config SECURITY_ROOTPLUG tristate "Root Plug Support" - depends on SECURITY!=n + depends on USB && SECURITY!=n help This is a sample LSM module that should only be used as such. It prevents any programs running with egid == 0 if a specific diff -Nru a/security/root_plug.c b/security/root_plug.c --- a/security/root_plug.c Mon Jun 9 23:16:19 2003 +++ b/security/root_plug.c Mon Jun 9 23:16:19 2003 @@ -54,7 +54,7 @@ #define MY_NAME "root_plug" #endif -#define dbg(fmt, arg...) \ +#define root_dbg(fmt, arg...) \ do { \ if (debug) \ printk(KERN_DEBUG "%s: %s: " fmt , \ @@ -62,70 +62,21 @@ ## arg); \ } while (0) -extern struct list_head usb_bus_list; -extern struct semaphore usb_bus_list_lock; - -static int match_device (struct usb_device *dev) -{ - int retval = -ENODEV; - int child; - - dbg ("looking at vendor %d, product %d\n", - dev->descriptor.idVendor, - dev->descriptor.idProduct); - - /* see if this device matches */ - if ((dev->descriptor.idVendor == vendor_id) && - (dev->descriptor.idProduct == product_id)) { - dbg ("found the device!\n"); - retval = 0; - goto exit; - } - - /* look through all of the children of this device */ - for (child = 0; child < dev->maxchild; ++child) { - if (dev->children[child]) { - retval = match_device (dev->children[child]); - if (retval == 0) - goto exit; - } - } -exit: - return retval; -} - -static int find_usb_device (void) -{ - struct list_head *buslist; - struct usb_bus *bus; - int retval = -ENODEV; - - down (&usb_bus_list_lock); - for (buslist = usb_bus_list.next; - buslist != &usb_bus_list; - buslist = buslist->next) { - bus = container_of (buslist, struct usb_bus, bus_list); - retval = match_device(bus->root_hub); - if (retval == 0) - goto exit; - } -exit: - up (&usb_bus_list_lock); - return retval; -} - - static int rootplug_bprm_check_security (struct linux_binprm *bprm) { - dbg ("file %s, e_uid = %d, e_gid = %d\n", - bprm->filename, bprm->e_uid, bprm->e_gid); + struct usb_device *dev; + + root_dbg("file %s, e_uid = %d, e_gid = %d\n", + bprm->filename, bprm->e_uid, bprm->e_gid); if (bprm->e_gid == 0) { - if (find_usb_device() != 0) { - dbg ("e_gid = 0, and device not found, " - "task not allowed to run...\n"); + dev = usb_find_device(vendor_id, product_id); + if (!dev) { + root_dbg("e_gid = 0, and device not found, " + "task not allowed to run...\n"); return -EPERM; } + usb_put_dev(dev); } return 0; diff -Nru a/sound/Kconfig b/sound/Kconfig --- a/sound/Kconfig Mon Jun 9 23:16:18 2003 +++ b/sound/Kconfig Mon Jun 9 23:16:18 2003 @@ -24,7 +24,13 @@ # here assuming USB is defined before ALSA source "sound/usb/Kconfig" +# the following will depenend on the order of config. +# here assuming PCMCIA is defined before ALSA +source "sound/pcmcia/Kconfig" + source "sound/sparc/Kconfig" + +source "sound/parisc/Kconfig" endmenu diff -Nru a/sound/Makefile b/sound/Makefile --- a/sound/Makefile Mon Jun 9 23:16:09 2003 +++ b/sound/Makefile Mon Jun 9 23:16:09 2003 @@ -3,8 +3,7 @@ obj-$(CONFIG_SOUND) += soundcore.o obj-$(CONFIG_SOUND_PRIME) += oss/ -obj-$(CONFIG_DMASOUND) += oss/ -obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ +obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ synth/ usb/ sparc/ parisc/ pcmcia/ ifeq ($(CONFIG_SND),y) obj-y += last.o diff -Nru a/sound/arm/sa11xx-uda1341.c b/sound/arm/sa11xx-uda1341.c --- a/sound/arm/sa11xx-uda1341.c Mon Jun 9 23:16:06 2003 +++ b/sound/arm/sa11xx-uda1341.c Mon Jun 9 23:16:06 2003 @@ -15,9 +15,13 @@ * 2002-04-04 Tomas Kasparek better rates handling (allow non-standard rates) * 2003-02-14 Brian Avery fixed full duplex mode, other updates * 2003-02-20 Tomas Kasparek merged updates by Brian (except HAL) + * 2003-04-19 Jaroslav Kysela recoded DMA stuff to follow 2.4.18rmk3-hh24 kernel + * working suspend and resume + * 2003-04-28 Tomas Kasparek updated work by Jaroslav to compile it under 2.5.x again + * merged HAL layer (patches from Brian) */ -/* $Id: sa11xx-uda1341.c,v 1.8 2003/02/25 12:48:15 perex Exp $ */ +/* $Id: sa11xx-uda1341.c,v 1.11 2003/04/30 14:53:11 perex Exp $ */ /*************************************************************************************************** * @@ -55,7 +59,7 @@ * ***************************************************************************************************/ - +#include <linux/config.h> #include <sound/driver.h> #include <linux/module.h> #include <linux/init.h> @@ -64,9 +68,21 @@ #include <linux/delay.h> #include <linux/slab.h> +#ifdef CONFIG_PM +#include <linux/pm.h> +#endif + #include <asm/hardware.h> +#include <asm/arch/h3600.h> +#include <asm/mach-types.h> #include <asm/dma.h> +#ifdef CONFIG_H3600_HAL +#include <asm/semaphore.h> +#include <asm/uaccess.h> +#include <asm/arch/h3600_hal.h> +#endif + #include <sound/core.h> #include <sound/pcm.h> #include <sound/initval.h> @@ -77,6 +93,15 @@ #undef DEBUG_FUNCTION_NAMES #include <sound/uda1341.h> +/* + * FIXME: Is this enough as autodetection of 2.4.X-rmkY-hhZ kernels? + * We use DMA stuff from 2.4.18-rmk3-hh24 here to be able to compile this + * module for Familiar 0.6.1 + */ +#ifdef CONFIG_H3600_HAL +#define HH_VERSION 1 +#endif + /* {{{ Type definitions */ MODULE_AUTHOR("Tomas Kasparek <tomas.kasparek@seznam.cz>"); @@ -92,26 +117,21 @@ #define chip_t sa11xx_uda1341_t -typedef enum stream_id_t{ - PLAYBACK=0, - CAPTURE, - MAX_STREAMS, -}stream_id_t; - typedef struct audio_stream { - char *id; /* identification string */ - int stream_id; /* numeric identification */ + char *id; /* identification string */ + int stream_id; /* numeric identification */ dma_device_t dma_dev; /* device identifier for DMA */ +#ifdef HH_VERSION + dmach_t dmach; /* dma channel identification */ +#else dma_regs_t *dma_regs; /* points to our DMA registers */ - - int active:1; /* we are using this stream for transfer now */ - - int sent_periods; /* # of sent periods from actual DMA buffer */ - int sent_total; /* # of sent periods total (just for info & debug) */ - - int sync; /* are we recoding - flag used to do DMA trans. for sync */ +#endif + int active:1; /* we are using this stream for transfer now */ + int period; /* current transfer period */ + int periods; /* current count of periods registerd in the DMA engine */ + int tx_spin; /* are we recoding - flag used to do DMA trans. for sync */ + unsigned int old_offset; spinlock_t dma_lock; /* for locking in DMA operations (see dma-sa1100.c in the kernel) */ - snd_pcm_substream_t *stream; }audio_stream_t; @@ -119,10 +139,10 @@ struct pm_dev *pm_dev; snd_card_t *card; struct l3_client *uda1341; - + snd_pcm_t *pcm; long samplerate; - audio_stream_t *s[MAX_STREAMS]; -}sa11xx_uda1341_t; + audio_stream_t s[2]; /* playback & capture */ +} sa11xx_uda1341_t; static struct snd_card_sa11xx_uda1341 *sa11xx_uda1341 = NULL; @@ -185,8 +205,6 @@ int clk_div = 0; int clk=0; - DEBUG(KERN_DEBUG "set_samplerate rate: %ld\n", rate); - /* We don't want to mess with clocks when frames are in flight */ Ser4SSCR0 &= ~SSCR0_SSE; /* wait for any frame to complete */ @@ -224,7 +242,11 @@ rate = 8000; /* Set the external clock generator */ +#ifdef CONFIG_H3600_HAL + h3600_audio_clock(rate); +#else sa11xx_uda1341_set_audio_clock(rate); +#endif /* Select the clock divisor */ switch (rate) { @@ -256,7 +278,6 @@ l3_command(sa11xx_uda1341->uda1341, CMD_FS, (void *)clk); Ser4SSCR0 = (Ser4SSCR0 & ~0xff00) + clk_div + SSCR0_SSE; - DEBUG(KERN_DEBUG "set_samplerate done (new rate: %ld)\n", rate); sa11xx_uda1341->samplerate = rate; } @@ -268,20 +289,14 @@ { unsigned long flags; - DEBUG_NAME(KERN_DEBUG "audio_init\n"); - /* Setup DMA stuff */ - if (sa11xx_uda1341->s[PLAYBACK]) { - sa11xx_uda1341->s[PLAYBACK]->id = "UDA1341 out"; - sa11xx_uda1341->s[PLAYBACK]->stream_id = PLAYBACK; - sa11xx_uda1341->s[PLAYBACK]->dma_dev = DMA_Ser4SSPWr; - } - - if (sa11xx_uda1341->s[CAPTURE]) { - sa11xx_uda1341->s[CAPTURE]->id = "UDA1341 in"; - sa11xx_uda1341->s[CAPTURE]->stream_id = CAPTURE; - sa11xx_uda1341->s[CAPTURE]->dma_dev = DMA_Ser4SSPRd; - } + sa11xx_uda1341->s[SNDRV_PCM_STREAM_PLAYBACK].id = "UDA1341 out"; + sa11xx_uda1341->s[SNDRV_PCM_STREAM_PLAYBACK].stream_id = SNDRV_PCM_STREAM_PLAYBACK; + sa11xx_uda1341->s[SNDRV_PCM_STREAM_PLAYBACK].dma_dev = DMA_Ser4SSPWr; + + sa11xx_uda1341->s[SNDRV_PCM_STREAM_CAPTURE].id = "UDA1341 in"; + sa11xx_uda1341->s[SNDRV_PCM_STREAM_CAPTURE].stream_id = SNDRV_PCM_STREAM_CAPTURE; + sa11xx_uda1341->s[SNDRV_PCM_STREAM_CAPTURE].dma_dev = DMA_Ser4SSPRd; /* Initialize the UDA1341 internal state */ @@ -296,41 +311,60 @@ local_irq_restore(flags); /* Enable the audio power */ +#ifdef CONFIG_H3600_HAL + h3600_audio_power(AUDIO_RATE_DEFAULT); +#else clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_CODEC_NRESET); set_sa11xx_uda1341_egpio(IPAQ_EGPIO_AUDIO_ON); set_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE); - +#endif + + /* Wait for the UDA1341 to wake up */ + mdelay(1); //FIXME - was removed by Perex - Why? + /* Initialize the UDA1341 internal state */ l3_open(sa11xx_uda1341->uda1341); - /* external clock configuration (after l3_open - regs must be - * initialized */ - sa11xx_uda1341_set_samplerate(sa11xx_uda1341, AUDIO_RATE_DEFAULT); + /* external clock configuration (after l3_open - regs must be initialized */ + sa11xx_uda1341_set_samplerate(sa11xx_uda1341, sa11xx_uda1341->samplerate); /* Wait for the UDA1341 to wake up */ set_sa11xx_uda1341_egpio(IPAQ_EGPIO_CODEC_NRESET); - mdelay(1); - + mdelay(1); - /* make the left and right channels unswapped (flip the WS latch ) */ + /* make the left and right channels unswapped (flip the WS latch) */ Ser4SSDR = 0; - + +#ifdef CONFIG_H3600_HAL + h3600_audio_mute(0); +#else clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE); +#endif } static void sa11xx_uda1341_audio_shutdown(sa11xx_uda1341_t *sa11xx_uda1341) { /* mute on */ +#ifdef CONFIG_H3600_HAL + h3600_audio_mute(1); +#else set_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE); +#endif /* disable the audio power and all signals leading to the audio chip */ l3_close(sa11xx_uda1341->uda1341); Ser4SSCR0 = 0; clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_CODEC_NRESET); - /* power off */ + + /* power off and mute off */ + /* FIXME - is muting off necesary??? */ +#ifdef CONFIG_H3600_HAL + h3600_audio_power(0); + h3600_audio_mute(0); +#else clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_AUDIO_ON); - /* mute off */ clr_sa11xx_uda1341_egpio(IPAQ_EGPIO_QMUTE); +#endif } /* }}} */ @@ -344,16 +378,40 @@ #define FORCE_CLOCK_ADDR (dma_addr_t)FLUSH_BASE_PHYS #define FORCE_CLOCK_SIZE 4096 // was 2048 -static void audio_dma_request(audio_stream_t *s, void (*callback)(void *)) +// FIXME Why this value exactly - wrote comment +#define DMA_BUF_SIZE 8176 /* <= MAX_DMA_SIZE from asm/arch-sa1100/dma.h */ + +#ifdef HH_VERSION + +static int audio_dma_request(audio_stream_t *s, void (*callback)(void *, int)) { int ret; - DEBUG_NAME(KERN_DEBUG "audio_dma_request"); + ret = sa1100_request_dma(&s->dmach, s->id, s->dma_dev); + if (ret < 0) { + printk(KERN_ERR "unable to grab audio dma 0x%x\n", s->dma_dev); + return ret; + } + sa1100_dma_set_callback(s->dmach, callback); + return 0; +} - DEBUG("\t request id <%s>\n", s->id); - DEBUG("\t request dma_dev = 0x%x \n", s->dma_dev); - ret = sa1100_request_dma((s)->dma_dev, (s)->id, callback, s, &((s)->dma_regs)); - DEBUG("\t request ret = %d\n", ret); +static inline void audio_dma_free(audio_stream_t *s) +{ + sa1100_free_dma(s->dmach); + s->dmach = -1; +} + +#else + +static int audio_dma_request(audio_stream_t *s, void (*callback)(void *)) +{ + int ret; + + ret = sa1100_request_dma(s->dma_dev, s->id, callback, s, &s->dma_regs); + if (ret < 0) + printk(KERN_ERR "unable to grab audio dma 0x%x\n", s->dma_dev); + return ret; } static void audio_dma_free(audio_stream_t *s) @@ -362,33 +420,30 @@ (s)->dma_regs = 0; } +#endif + static u_int audio_get_dma_pos(audio_stream_t *s) { snd_pcm_substream_t * substream = s->stream; snd_pcm_runtime_t *runtime = substream->runtime; unsigned int offset; unsigned long flags; + dma_addr_t addr; - DEBUG_NAME(KERN_DEBUG "get_dma_pos"); - // this must be called w/ interrupts locked out see dma-sa1100.c in the kernel spin_lock_irqsave(&s->dma_lock, flags); - offset = sa1100_get_dma_pos((s)->dma_regs) - runtime->dma_addr; +#ifdef HH_VERSION + sa1100_dma_get_current(s->dmach, NULL, &addr); +#else + addr = sa1100_get_dma_pos((s)->dma_regs); +#endif + offset = addr - runtime->dma_addr; spin_unlock_irqrestore(&s->dma_lock, flags); - DEBUG(" %d ->", offset); offset = bytes_to_frames(runtime,offset); - DEBUG(" %d [fr]\n", offset); - - if (offset >= runtime->buffer_size){ - offset = runtime->buffer_size; - } + if (offset >= runtime->buffer_size) + offset = 0; - DEBUG(KERN_DEBUG " hw_ptr_interrupt: %lX\n", - (unsigned long)runtime->hw_ptr_interrupt); - DEBUG(KERN_DEBUG " updated pos [fr]: %ld\n", - offset - (offset % runtime->min_align)); - return offset; } @@ -397,143 +452,100 @@ */ static void audio_stop_dma(audio_stream_t *s) { - long flags; - - DEBUG_NAME(KERN_DEBUG "stop_dma\n"); - - /* - * zero filling streams (sync=1) don;t have alsa streams attached - * but the 0 fill dma xfer still needs to be stopped - */ - if (!(s->stream || s->sync)) - return; + unsigned long flags; - spin_lock_irqsave(&(s->dma_lock), flags); + spin_lock_irqsave(&s->dma_lock, flags); s->active = 0; - s->sent_periods = 0; - s->sent_total = 0; - s->sync = 0; - + s->period = 0; /* this stops the dma channel and clears the buffer ptrs */ - sa1100_clear_dma((s)->dma_regs); - spin_unlock_irqrestore(&(s->dma_lock), flags); -} - -static void audio_reset(audio_stream_t *s) -{ - DEBUG_NAME(KERN_DEBUG "dma_reset\n"); - - if (s->stream) { - audio_stop_dma(s); - } - s->active = 0; +#ifdef HH_VERSION + sa1100_dma_flush_all(s->dmach); +#else + sa1100_clear_dma(s->dma_regs); +#endif + spin_unlock_irqrestore(&s->dma_lock, flags); } - static void audio_process_dma(audio_stream_t *s) { - snd_pcm_substream_t * substream = s->stream; + snd_pcm_substream_t *substream = s->stream; snd_pcm_runtime_t *runtime; + unsigned int dma_size; + unsigned int offset; int ret; - DEBUG_NAME(KERN_DEBUG "process_dma\n"); - /* we are requested to process synchronization DMA transfer */ - if(!s->active && s->sync){ - snd_assert(s->stream_id == PLAYBACK,return); + if (s->tx_spin) { + snd_assert(s->stream_id == SNDRV_PCM_STREAM_PLAYBACK, return); /* fill the xmit dma buffers and return */ +#ifdef HH_VERSION + sa1100_dma_set_spin(s->dmach, FORCE_CLOCK_ADDR, FORCE_CLOCK_SIZE); +#else while (1) { - DEBUG(KERN_DEBUG "sent zero dma period (dma_size[B]: %d)\n", FORCE_CLOCK_SIZE); - ret = sa1100_start_dma((s)->dma_regs, FORCE_CLOCK_ADDR, FORCE_CLOCK_SIZE); + ret = sa1100_start_dma(s->dma_regs, FORCE_CLOCK_ADDR, FORCE_CLOCK_SIZE); if (ret) return; } +#endif + return; } /* must be set here - only valid for running streams, not for forced_clock dma fills */ runtime = substream->runtime; - - DEBUG("audio_process_dma hw_ptr_base = 0x%x w_ptr_interrupt = 0x%x " - "period_size = %d periods = %d buffer_size = %d sync=0x%x dma_area = 0x%x\n", - runtime->hw_ptr_base, - runtime->hw_ptr_interrupt, - runtime->period_size, - runtime->periods, - runtime->buffer_size, - runtime->sync, - runtime->dma_area); - - DEBUG("audio_process_dma sent_total = %d sent_period = %d\n", - s->sent_total, - s->sent_periods); - - while(s->active) { - unsigned int dma_size; - unsigned int offset ; - - dma_size = frames_to_bytes(runtime,runtime->period_size) ; - offset = dma_size * s->sent_periods; - if (dma_size > MAX_DMA_SIZE){ - /* this should not happen! */ - printk(KERN_ERR "---> cut dma_size: %d -> ", dma_size); - dma_size = CUT_DMA_SIZE; - printk("%d <---\n", dma_size); + while (s->active && s->periods < runtime->periods) { + dma_size = frames_to_bytes(runtime, runtime->period_size); + if (s->old_offset) { + /* a little trick, we need resume from old position */ + offset = frames_to_bytes(runtime, s->old_offset - 1); + s->old_offset = 0; + s->periods = 0; + s->period = offset / dma_size; + offset %= dma_size; + dma_size = dma_size - offset; + if (!dma_size) + continue; /* special case */ + } else { + offset = dma_size * s->period; + snd_assert(dma_size <= DMA_BUF_SIZE, ); } - - /* - * the first time this while loop will run 3 times, i.e. it'll fill the 2 dma - * buffers then get a -EBUSY, every other time it'll refill the completed buffer - * and then get the -EBUSY so it'll just run twice - */ - ret = sa1100_start_dma((s)->dma_regs, runtime->dma_addr + offset, dma_size); +#ifdef HH_VERSION + ret = sa1100_dma_queue_buffer(s->dmach, s, runtime->dma_addr + offset, dma_size); if (ret) + return; //FIXME +#else + ret = sa1100_start_dma((s)->dma_regs, runtime->dma_addr + offset, dma_size); + if (ret) { + printk(KERN_ERR "audio_process_dma: cannot queue DMA buffer (%i)\n", ret); return; - - DEBUG(KERN_DEBUG "sent period %d (%d total)(dma_size[B]: %d" - "offset[B]: %06d)\n", - s->sent_periods, s->sent_total, dma_size, offset); - -#ifdef DEBUG_MODE - printk(KERN_DEBUG " dma_area:"); - for (i=0; i < 32; i++) { - printk(" %02x", *(char *)(runtime->dma_addr+offset+i)); } - printk("\n"); -#endif - s->sent_total++; - s->sent_periods++; - s->sent_periods %= runtime->periods; +#endif + + s->period++; + s->period %= runtime->periods; + s->periods++; } } +#ifdef HH_VERSION +static void audio_dma_callback(void *data, int size) +#else static void audio_dma_callback(void *data) +#endif { audio_stream_t *s = data; - char *buf; - int i; - - DEBUG_NAME(KERN_DEBUG "dma_callback\n"); - - DEBUG(KERN_DEBUG "----> period done <----\n"); - -#ifdef DEBUG_MODE - printk(KERN_DEBUG " dma_area:"); - buf = (char *)s->stream->runtime->dma_addr + ((s->sent_periods - 1 ) * - frames_to_bytes( s->stream->runtime, s->stream->runtime->period_size)); - for (i=0; i < 32; i++) { - printk(" %02x", *(char *)(buf + i)); - } - printk("\n"); -#endif - /* - * If we are getting a callback for an active stream then we inform - * the PCM middle layer we've finished a period - */ + /* + * If we are getting a callback for an active stream then we inform + * the PCM middle layer we've finished a period + */ if (s->active) snd_pcm_period_elapsed(s->stream); + spin_lock(&s->dma_lock); + if (!s->tx_spin && s->periods > 0) + s->periods--; audio_process_dma(s); + spin_unlock(&s->dma_lock); } /* }}} */ @@ -542,96 +554,172 @@ /* {{{ trigger & timer */ -static int snd_card_sa11xx_uda1341_pcm_trigger(stream_id_t stream_id, - snd_pcm_substream_t * substream, int cmd) +static int snd_sa11xx_uda1341_trigger(snd_pcm_substream_t * substream, int cmd) { sa11xx_uda1341_t *chip = snd_pcm_substream_chip(substream); - snd_pcm_runtime_t *runtime = substream->runtime; - int i; - - DEBUG_NAME(KERN_DEBUG "pcm_trigger id: %d cmd: %d\n", stream_id, cmd); + int stream_id = substream->pstr->stream; + audio_stream_t *s = &chip->s[stream_id]; + audio_stream_t *s1 = &chip->s[stream_id ^ 1]; + int err = 0; - DEBUG(KERN_DEBUG " sound: %d x %d [Hz]\n", runtime->channels, runtime->rate); - DEBUG(KERN_DEBUG " periods: %ld x %ld [fr]\n", (unsigned long)runtime->periods, - (unsigned long) runtime->period_size); - DEBUG(KERN_DEBUG " buffer_size: %ld [fr]\n", (unsigned long)runtime->buffer_size); - DEBUG(KERN_DEBUG " dma_addr %p\n", (char *)runtime->dma_addr); - -#ifdef DEBUG_MODE - printk(KERN_DEBUG " dma_area:"); - for (i=0; i < 32; i++) { - printk(" %02x", *(char *)(runtime->dma_addr+i)); - } - printk("\n"); -#endif - + /* note local interrupts are already disabled in the midlevel code */ + spin_lock(&s->dma_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* now we need to make sure a record only stream has a clock */ - if (stream_id == CAPTURE && !chip->s[PLAYBACK]->active) { - /* we need to force fill the xmit DMA with zeros */ - DEBUG(KERN_DEBUG "starting zero fill DMA transfer\n"); - chip->s[PLAYBACK]->sync = 1; - audio_process_dma(chip->s[PLAYBACK]); + if (stream_id == SNDRV_PCM_STREAM_CAPTURE && !s1->active) { + /* we need to force fill the xmit DMA with zeros */ + s1->tx_spin = 1; + audio_process_dma(s1); } /* this case is when you were recording then you turn on a - * playback stream so we - * stop (also clears it) the dma first, clear the sync flag - * and then we let it get turned on + * playback stream so we stop (also clears it) the dma first, + * clear the sync flag and then we let it turned on */ - else if (stream_id == PLAYBACK && chip->s[PLAYBACK]->sync) { - chip->s[PLAYBACK]->sync = 0; - audio_stop_dma(chip->s[PLAYBACK]); - } + else { + s->tx_spin = 0; + } /* requested stream startup */ - chip->s[stream_id]->active = 1; - audio_process_dma(chip->s[stream_id]); + s->active = 1; + audio_process_dma(s); break; case SNDRV_PCM_TRIGGER_STOP: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* requested stream shutdown */ - chip->s[stream_id]->active = 0; - audio_stop_dma(chip->s[stream_id]); + audio_stop_dma(s); /* * now we need to make sure a record only stream has a clock * so if we're stopping a playback with an active capture * we need to turn the 0 fill dma on for the xmit side */ - if (stream_id == PLAYBACK && chip->s[CAPTURE]->active) { - /* we need to force fill the xmit DMA with zeros */ - DEBUG(KERN_DEBUG "starting zero fill DMA transfer\n"); - chip->s[PLAYBACK]->sync = 1; - chip->s[PLAYBACK]->active = 0; - audio_process_dma(chip->s[PLAYBACK]); + if (stream_id == SNDRV_PCM_STREAM_PLAYBACK && s1->active) { + /* we need to force fill the xmit DMA with zeros */ + s->tx_spin = 1; + audio_process_dma(s); } /* * we killed a capture only stream, so we should also kill * the zero fill transmit */ - else if (stream_id == CAPTURE && chip->s[PLAYBACK]->sync) { - audio_stop_dma(chip->s[PLAYBACK]); + else { + if (s1->tx_spin) { + s1->tx_spin = 0; + audio_stop_dma(s1); + } } break; + case SNDRV_PCM_TRIGGER_SUSPEND: + s->active = 0; +#ifdef HH_VERSION + sa1100_dma_stop(s->dmach); +#else + //FIXME - DMA API +#endif + s->old_offset = audio_get_dma_pos(s) + 1; +#ifdef HH_VERSION + sa1100_dma_flush_all(s->dmach); +#else + //FIXME - DMA API +#endif + s->periods = 0; + break; + case SNDRV_PCM_TRIGGER_RESUME: + s->active = 1; + s->tx_spin = 0; + audio_process_dma(s); + if (stream_id == SNDRV_PCM_STREAM_CAPTURE && !s1->active) { + s1->tx_spin = 1; + audio_process_dma(s1); + } + break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: +#ifdef HH_VERSION + sa1100_dma_stop(s->dmach); +#else + //FIXME - DMA API +#endif + s->active = 0; + if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) { + if (s1->active) { + s->tx_spin = 1; + s->old_offset = audio_get_dma_pos(s) + 1; +#ifdef HH_VERSION + sa1100_dma_flush_all(s->dmach); +#else + //FIXME - DMA API +#endif + audio_process_dma(s); + } + } else { + if (s1->tx_spin) { + s1->tx_spin = 0; +#ifdef HH_VERSION + sa1100_dma_flush_all(s1->dmach); +#else + //FIXME - DMA API +#endif + } + } + break; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + s->active = 1; + if (s->old_offset) { + s->tx_spin = 0; + audio_process_dma(s); + break; + } + if (stream_id == SNDRV_PCM_STREAM_CAPTURE && !s1->active) { + s1->tx_spin = 1; + audio_process_dma(s1); + } +#ifdef HH_VERSION + sa1100_dma_resume(s->dmach); +#else + //FIXME - DMA API +#endif + break; default: - return -EINVAL; + err = -EINVAL; break; } + spin_unlock(&s->dma_lock); + return err; +} + +static int snd_sa11xx_uda1341_prepare(snd_pcm_substream_t * substream) +{ + sa11xx_uda1341_t *chip = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + audio_stream_t *s = &chip->s[substream->pstr->stream]; + + /* set requested samplerate */ + sa11xx_uda1341_set_samplerate(chip, runtime->rate); + + /* set requestd format when available */ + /* set FMT here !!! FIXME */ + + s->period = 0; + s->periods = 0; + return 0; } +static snd_pcm_uframes_t snd_sa11xx_uda1341_pointer(snd_pcm_substream_t * substream) +{ + sa11xx_uda1341_t *chip = snd_pcm_substream_chip(substream); + return audio_get_dma_pos(&chip->s[substream->pstr->stream]); +} + /* }}} */ static snd_pcm_hardware_t snd_sa11xx_uda1341_capture = { .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID), + SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), .formats = SNDRV_PCM_FMTBIT_S16_LE, .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |\ @@ -641,9 +729,9 @@ .rate_max = 48000, .channels_min = 2, .channels_max = 2, - .buffer_bytes_max = 16380, + .buffer_bytes_max = 64*1024, .period_bytes_min = 64, - .period_bytes_max = 8190, /* <= MAX_DMA_SIZE from ams/arch-sa1100/dma.h */ + .period_bytes_max = DMA_BUF_SIZE, .periods_min = 2, .periods_max = 255, .fifo_size = 0, @@ -653,7 +741,8 @@ { .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID), + SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME), .formats = SNDRV_PCM_FMTBIT_S16_LE, .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |\ @@ -663,218 +752,87 @@ .rate_max = 48000, .channels_min = 2, .channels_max = 2, - .buffer_bytes_max = 16380, + .buffer_bytes_max = 64*1024, .period_bytes_min = 64, - .period_bytes_max = 8190, /* <= MAX_DMA_SIZE from ams/arch-sa1100/dma.h */ + .period_bytes_max = DMA_BUF_SIZE, .periods_min = 2, .periods_max = 255, .fifo_size = 0, }; -/* {{{ snd_card_sa11xx_uda1341_playback functions */ - -static int snd_card_sa11xx_uda1341_playback_open(snd_pcm_substream_t * substream) +static int snd_card_sa11xx_uda1341_open(snd_pcm_substream_t * substream) { sa11xx_uda1341_t *chip = snd_pcm_substream_chip(substream); snd_pcm_runtime_t *runtime = substream->runtime; + int stream_id = substream->pstr->stream; int err; - - DEBUG_NAME(KERN_DEBUG "playback_open\n"); - - chip->s[PLAYBACK]->stream = substream; - chip->s[PLAYBACK]->sent_periods = 0; - chip->s[PLAYBACK]->sent_total = 0; - - /* no reset here since we may be zero filling the DMA - * if we are, the dma stream will get reset in the pcm_trigger - * i.e. when it actually starts to play - */ - /* audio_reset(chip->s[PLAYBACK]); */ - - runtime->hw = snd_sa11xx_uda1341_playback; - if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) - return err; - if ((err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - &hw_constraints_rates)) < 0) - return err; - - return 0; -} -static int snd_card_sa11xx_uda1341_playback_close(snd_pcm_substream_t * substream) -{ - sa11xx_uda1341_t *chip = snd_pcm_substream_chip(substream); + chip->s[stream_id].stream = substream; - DEBUG_NAME(KERN_DEBUG "playback_close\n"); - - chip->s[PLAYBACK]->stream = NULL; - - return 0; -} - -static int snd_card_sa11xx_uda1341_playback_ioctl(snd_pcm_substream_t * substream, - unsigned int cmd, void *arg) -{ - DEBUG_NAME(KERN_DEBUG "playback_ioctl cmd: %d\n", cmd); - return snd_pcm_lib_ioctl(substream, cmd, arg); -} - -static int snd_card_sa11xx_uda1341_playback_prepare(snd_pcm_substream_t * substream) -{ - sa11xx_uda1341_t *chip = snd_pcm_substream_chip(substream); - snd_pcm_runtime_t *runtime = substream->runtime; - - DEBUG_NAME(KERN_DEBUG "playback_prepare\n"); - - /* set requested samplerate */ - sa11xx_uda1341_set_samplerate(chip, runtime->rate); - - return 0; -} - -static int snd_card_sa11xx_uda1341_playback_trigger(snd_pcm_substream_t * substream, int cmd) -{ - DEBUG_NAME(KERN_DEBUG "playback_trigger\n"); - return snd_card_sa11xx_uda1341_pcm_trigger(PLAYBACK, substream, cmd); -} - -static snd_pcm_uframes_t snd_card_sa11xx_uda1341_playback_pointer(snd_pcm_substream_t * substream) -{ - snd_pcm_uframes_t pos; - sa11xx_uda1341_t *chip = snd_pcm_substream_chip(substream); - - DEBUG_NAME(KERN_DEBUG "playback_pointer\n"); - - pos = audio_get_dma_pos(chip->s[PLAYBACK]); - return pos; -} - -/* }}} */ - -/* {{{ snd_card_sa11xx_uda1341_record functions */ - -static int snd_card_sa11xx_uda1341_capture_open(snd_pcm_substream_t * substream) -{ - sa11xx_uda1341_t *chip = snd_pcm_substream_chip(substream); - snd_pcm_runtime_t *runtime = substream->runtime; - int err; - - DEBUG_NAME(KERN_DEBUG "record_open\n"); - - chip->s[CAPTURE]->stream = substream; - chip->s[CAPTURE]->sent_periods = 0; - chip->s[CAPTURE]->sent_total = 0; - - audio_reset(chip->s[CAPTURE]); - - runtime->hw = snd_sa11xx_uda1341_capture; + if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) + runtime->hw = snd_sa11xx_uda1341_playback; + else + runtime->hw = snd_sa11xx_uda1341_capture; if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) return err; - if ((err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - &hw_constraints_rates)) < 0) + if ((err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates)) < 0) return err; return 0; } -static int snd_card_sa11xx_uda1341_capture_close(snd_pcm_substream_t * substream) -{ - sa11xx_uda1341_t *chip = snd_pcm_substream_chip(substream); - - DEBUG_NAME(KERN_DEBUG "record_close\n"); - - chip->s[CAPTURE]->stream = NULL; - - return 0; -} - -static int snd_card_sa11xx_uda1341_capture_ioctl(snd_pcm_substream_t * substream, - unsigned int cmd, void *arg) -{ - DEBUG_NAME(KERN_DEBUG "record_ioctl cmd: %d\n", cmd); - return snd_pcm_lib_ioctl(substream, cmd, arg); -} - -static int snd_card_sa11xx_uda1341_capture_prepare(snd_pcm_substream_t * substream) +static int snd_card_sa11xx_uda1341_close(snd_pcm_substream_t * substream) { sa11xx_uda1341_t *chip = snd_pcm_substream_chip(substream); - snd_pcm_runtime_t *runtime = substream->runtime; - - DEBUG_NAME(KERN_DEBUG "record_prepare\n"); - /* set requested samplerate */ - sa11xx_uda1341_set_samplerate(chip, runtime->rate); - + chip->s[substream->pstr->stream].stream = NULL; return 0; } -static int snd_card_sa11xx_uda1341_capture_trigger(snd_pcm_substream_t * substream, int cmd) -{ - DEBUG_NAME(KERN_DEBUG "record_trigger\n"); - return snd_card_sa11xx_uda1341_pcm_trigger(CAPTURE, substream, cmd); -} - -static snd_pcm_uframes_t snd_card_sa11xx_uda1341_capture_pointer(snd_pcm_substream_t * substream) -{ - snd_pcm_uframes_t pos; - sa11xx_uda1341_t *chip = snd_pcm_substream_chip(substream); - - DEBUG_NAME(KERN_DEBUG "record_pointer\n"); - pos = audio_get_dma_pos(chip->s[CAPTURE]); - return pos; -} - -/* }}} */ - /* {{{ HW params & free */ static int snd_sa11xx_uda1341_hw_params(snd_pcm_substream_t * substream, - snd_pcm_hw_params_t * hw_params) + snd_pcm_hw_params_t * hw_params) { - DEBUG_NAME(KERN_DEBUG "hw_params\n"); return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); } static int snd_sa11xx_uda1341_hw_free(snd_pcm_substream_t * substream) { - DEBUG_NAME(KERN_DEBUG "hw_free\n"); return snd_pcm_lib_free_pages(substream); } /* }}} */ static snd_pcm_ops_t snd_card_sa11xx_uda1341_playback_ops = { - .open = snd_card_sa11xx_uda1341_playback_open, - .close = snd_card_sa11xx_uda1341_playback_close, - .ioctl = snd_card_sa11xx_uda1341_playback_ioctl, + .open = snd_card_sa11xx_uda1341_open, + .close = snd_card_sa11xx_uda1341_close, + .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_sa11xx_uda1341_hw_params, .hw_free = snd_sa11xx_uda1341_hw_free, - .prepare = snd_card_sa11xx_uda1341_playback_prepare, - .trigger = snd_card_sa11xx_uda1341_playback_trigger, - .pointer = snd_card_sa11xx_uda1341_playback_pointer, + .prepare = snd_sa11xx_uda1341_prepare, + .trigger = snd_sa11xx_uda1341_trigger, + .pointer = snd_sa11xx_uda1341_pointer, }; static snd_pcm_ops_t snd_card_sa11xx_uda1341_capture_ops = { - .open = snd_card_sa11xx_uda1341_capture_open, - .close = snd_card_sa11xx_uda1341_capture_close, - .ioctl = snd_card_sa11xx_uda1341_capture_ioctl, + .open = snd_card_sa11xx_uda1341_open, + .close = snd_card_sa11xx_uda1341_close, + .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_sa11xx_uda1341_hw_params, .hw_free = snd_sa11xx_uda1341_hw_free, - .prepare = snd_card_sa11xx_uda1341_capture_prepare, - .trigger = snd_card_sa11xx_uda1341_capture_trigger, - .pointer = snd_card_sa11xx_uda1341_capture_pointer, + .prepare = snd_sa11xx_uda1341_prepare, + .trigger = snd_sa11xx_uda1341_trigger, + .pointer = snd_sa11xx_uda1341_pointer, }; -static int __init snd_card_sa11xx_uda1341_pcm(sa11xx_uda1341_t *sa11xx_uda1341, int device, int substreams) +static int __init snd_card_sa11xx_uda1341_pcm(sa11xx_uda1341_t *sa11xx_uda1341, int device) { snd_pcm_t *pcm; int err; - DEBUG_NAME(KERN_DEBUG "sa11xx_uda1341_pcm\n"); - - if ((err = snd_pcm_new(sa11xx_uda1341->card, "UDA1341 PCM", device, - substreams, substreams, &pcm)) < 0) + if ((err = snd_pcm_new(sa11xx_uda1341->card, "UDA1341 PCM", device, 1, 1, &pcm)) < 0) return err; /* @@ -890,14 +848,13 @@ pcm->info_flags = 0; strcpy(pcm->name, "UDA1341 PCM"); - sa11xx_uda1341->s[PLAYBACK] = snd_kcalloc(sizeof(audio_stream_t), GFP_KERNEL); - sa11xx_uda1341->s[CAPTURE] = snd_kcalloc(sizeof(audio_stream_t), GFP_KERNEL); - sa11xx_uda1341_audio_init(sa11xx_uda1341); /* setup DMA controller */ - audio_dma_request(sa11xx_uda1341->s[PLAYBACK], audio_dma_callback); - audio_dma_request(sa11xx_uda1341->s[CAPTURE], audio_dma_callback); + audio_dma_request(&sa11xx_uda1341->s[SNDRV_PCM_STREAM_PLAYBACK], audio_dma_callback); + audio_dma_request(&sa11xx_uda1341->s[SNDRV_PCM_STREAM_CAPTURE], audio_dma_callback); + + sa11xx_uda1341->pcm = pcm; return 0; } @@ -908,73 +865,88 @@ #ifdef CONFIG_PM -static int sa11xx_uda1341_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) +static void snd_sa11xx_uda1341_suspend(sa11xx_uda1341_t *chip) { - sa11xx_uda1341_t *sa11xx_uda1341 = pm_dev->data; - audio_stream_t *is, *os; - int stopstate; - - DEBUG_NAME(KERN_DEBUG "pm_callback\n"); - - /* pause resume is broken see note */ - printk("Pause/Resume support currently broken... \n"); - return -1; + snd_card_t *card = chip->card; + + if (card->power_state == SNDRV_CTL_POWER_D3hot) + return; + snd_pcm_suspend_all(chip->pcm); +#ifdef HH_VERSION + sa1100_dma_sleep(chip->s[SNDRV_PCM_STREAM_PLAYBACK].dmach); + sa1100_dma_sleep(chip->s[SNDRV_PCM_STREAM_CAPTURE].dmach); +#else + //FIXME +#endif + l3_command(chip->uda1341, CMD_SUSPEND, NULL); + sa11xx_uda1341_audio_shutdown(chip); + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); +} - is = sa11xx_uda1341->s[PLAYBACK]; - os = sa11xx_uda1341->s[CAPTURE]; +static void snd_sa11xx_uda1341_resume(sa11xx_uda1341_t *chip) +{ + snd_card_t *card = chip->card; + + if (card->power_state == SNDRV_CTL_POWER_D0) + return; + sa11xx_uda1341_audio_init(chip); + l3_command(chip->uda1341, CMD_RESUME, NULL); +#ifdef HH_VERSION + sa1100_dma_wakeup(chip->s[SNDRV_PCM_STREAM_PLAYBACK].dmach); + sa1100_dma_wakeup(chip->s[SNDRV_PCM_STREAM_CAPTURE].dmach); +#else + //FIXME +#endif + snd_power_change_state(card, SNDRV_CTL_POWER_D0); +} + +static int sa11xx_uda1341_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) +{ + sa11xx_uda1341_t *chip = pm_dev->data; switch (req) { case PM_SUSPEND: /* enter D1-D3 */ - if (is && is->dma_regs) { - stopstate = is->active; - audio_stop_dma(is); - DMA_CLEAR(is); - is->active = stopstate; - } - if (os && os->dma_regs) { - stopstate = os->active; - audio_stop_dma(os); - DMA_CLEAR(os); - os->active = stopstate; - } - if (is->stream || os->stream) - sa11xx_uda1341_audio_shutdown(sa11xx_uda1341); + snd_sa11xx_uda1341_suspend(chip); break; case PM_RESUME: /* enter D0 */ - if (is->stream || os->stream) - sa11xx_uda1341_audio_init(sa11xx_uda1341); - if (os && os->dma_regs) { - DMA_RESET(os); - audio_process_dma(os); - } - if (is && is->dma_regs) { - DMA_RESET(is); - audio_process_dma(is); - } + snd_sa11xx_uda1341_resume(chip); break; } return 0; } -#endif - -void snd_sa11xx_uda1341_free(snd_card_t *card) +static int sa11xx_uda1341_set_power_state(snd_card_t *card, unsigned int power_state) { - sa11xx_uda1341_t *chip = snd_magic_cast(sa11xx_uda1341_t, card->private_data, return); - - DEBUG_NAME(KERN_DEBUG "snd_sa11xx_uda1341_free\n"); + sa11xx_uda1341_t *chip = snd_magic_cast(sa11xx_uda1341_t, card->power_state_private_data, return); - audio_dma_free(chip->s[PLAYBACK]); - audio_dma_free(chip->s[CAPTURE]); + switch (power_state) { + case SNDRV_CTL_POWER_D0: + case SNDRV_CTL_POWER_D1: + case SNDRV_CTL_POWER_D2: + snd_sa11xx_uda1341_resume(chip); + break; + case SNDRV_CTL_POWER_D3hot: + case SNDRV_CTL_POWER_D3cold: + snd_sa11xx_uda1341_suspend(chip); + break; + default: + return -EINVAL; + } + return 0; +} - kfree(chip->s[PLAYBACK]); - kfree(chip->s[CAPTURE]); +#endif /* COMFIG_PM */ - chip->s[PLAYBACK] = NULL; - chip->s[CAPTURE] = NULL; +void snd_sa11xx_uda1341_free(snd_card_t *card) +{ + sa11xx_uda1341_t *chip = snd_magic_cast(sa11xx_uda1341_t, card->private_data, return); - snd_magic_kfree(chip); + pm_unregister(chip->pm_dev); + audio_dma_free(&chip->s[SNDRV_PCM_STREAM_PLAYBACK]); + audio_dma_free(&chip->s[SNDRV_PCM_STREAM_CAPTURE]); + sa11xx_uda1341 = NULL; card->private_data = NULL; + kfree(chip); } static int __init sa11xx_uda1341_init(void) @@ -982,34 +954,36 @@ int err; snd_card_t *card; - DEBUG_NAME(KERN_DEBUG "sa11xx_uda1341_uda1341_init\n"); - if (!machine_is_h3xxx()) return -ENODEV; /* register the soundcard */ - card = snd_card_new(-1, id, THIS_MODULE, 0); + card = snd_card_new(-1, id, THIS_MODULE, sizeof(sa11xx_uda1341_t)); if (card == NULL) return -ENOMEM; + sa11xx_uda1341 = snd_magic_kcalloc(sa11xx_uda1341_t, 0, GFP_KERNEL); if (sa11xx_uda1341 == NULL) - return -ENOMEM; + return -ENOMEM; card->private_data = (void *)sa11xx_uda1341; card->private_free = snd_sa11xx_uda1341_free; - + sa11xx_uda1341->card = card; + sa11xx_uda1341->samplerate = AUDIO_RATE_DEFAULT; // mixer if ((err = snd_chip_uda1341_mixer_new(sa11xx_uda1341->card, &sa11xx_uda1341->uda1341))) goto nodev; // PCM - if ((err = snd_card_sa11xx_uda1341_pcm(sa11xx_uda1341, 0, 2)) < 0) + if ((err = snd_card_sa11xx_uda1341_pcm(sa11xx_uda1341, 0)) < 0) goto nodev; #ifdef CONFIG_PM + card->power_state_private_data = sa11xx_uda1341; + card->set_power_state = sa11xx_uda1341_set_power_state; sa11xx_uda1341->pm_dev = pm_register(PM_SYS_DEV, 0, sa11xx_uda1341_pm_callback); if (sa11xx_uda1341->pm_dev) sa11xx_uda1341->pm_dev->data = sa11xx_uda1341; @@ -1031,9 +1005,7 @@ static void __exit sa11xx_uda1341_exit(void) { - snd_chip_uda1341_mixer_del(sa11xx_uda1341->card); snd_card_free(sa11xx_uda1341->card); - sa11xx_uda1341 = NULL; } module_init(sa11xx_uda1341_init); diff -Nru a/sound/core/Makefile b/sound/core/Makefile --- a/sound/core/Makefile Mon Jun 9 23:16:15 2003 +++ b/sound/core/Makefile Mon Jun 9 23:16:15 2003 @@ -45,6 +45,7 @@ obj-$(CONFIG_SND_MPU401) += snd-rawmidi.o snd.o snd-timer.o obj-$(CONFIG_SND_ALS100) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o obj-$(CONFIG_SND_AZT2320) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o +obj-$(CONFIG_SND_AZT3328) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o obj-$(CONFIG_SND_CMI8330) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o obj-$(CONFIG_SND_DT019X) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o obj-$(CONFIG_SND_ES18XX) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o @@ -69,6 +70,7 @@ obj-$(CONFIG_SND_SBAWE) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o obj-$(CONFIG_SND_ES968) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o obj-$(CONFIG_SND_WAVEFRONT) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o +obj-$(CONFIG_SND_SSCAPE) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o obj-$(CONFIG_SND_ALS4000) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o obj-$(CONFIG_SND_CMIPCI) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o obj-$(CONFIG_SND_CS4281) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o @@ -78,6 +80,7 @@ obj-$(CONFIG_SND_ES1968) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o obj-$(CONFIG_SND_FM801) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o obj-$(CONFIG_SND_ICE1712) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o +obj-$(CONFIG_SND_ICE1724) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o obj-$(CONFIG_SND_INTEL8X0) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o obj-$(CONFIG_SND_MAESTRO3) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o obj-$(CONFIG_SND_RME32) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o @@ -90,7 +93,7 @@ obj-$(CONFIG_SND_KORG1212) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o obj-$(CONFIG_SND_NM256) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o obj-$(CONFIG_SND_RME9652) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o -obj-$(CONFIG_SND_HDSP) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o +obj-$(CONFIG_SND_HDSP) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o obj-$(CONFIG_SND_TRIDENT) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o obj-$(CONFIG_SND_YMFPCI) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o snd-hwdep.o obj-$(CONFIG_SND_POWERMAC) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o @@ -101,5 +104,11 @@ obj-$(CONFIG_SND_SBAWE) += snd-hwdep.o endif obj-$(CONFIG_SND_USB_AUDIO) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-rawmidi.o +obj-$(CONFIG_SND_SUN_AMD7930) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o +obj-$(CONFIG_SND_SUN_CS4231) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o +obj-$(CONFIG_SND_HARMONY) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o +obj-$(CONFIG_SND_VXPOCKET) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-hwdep.o +obj-$(CONFIG_SND_VXP440) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-hwdep.o +obj-$(CONFIG_SND_VX222) += snd-pcm.o snd-timer.o snd-page-alloc.o snd.o snd-hwdep.o obj-m := $(sort $(obj-m)) diff -Nru a/sound/core/control.c b/sound/core/control.c --- a/sound/core/control.c Mon Jun 9 23:16:08 2003 +++ b/sound/core/control.c Mon Jun 9 23:16:08 2003 @@ -396,10 +396,6 @@ continue; if (kctl->id.index + kctl->count <= id->index) continue; - if (kctl->id.index != id->index) { - printk("BOOOR: %i, %i, %i\n", kctl->id.index, kctl->count, id->index); - continue; - } return kctl; } return NULL; @@ -772,9 +768,9 @@ return -EPERM; #ifdef CONFIG_PM if (card->set_power_state) { - snd_power_lock(card); - err = card->set_power_state(card, err); - snd_power_unlock(card); + snd_power_lock(card); + err = card->set_power_state(card, err); + snd_power_unlock(card); } else #endif err = -ENOPROTOOPT; @@ -931,9 +927,7 @@ static struct file_operations snd_ctl_f_ops = { -#ifndef LINUX_2_2 .owner = THIS_MODULE, -#endif .read = snd_ctl_read, .open = snd_ctl_open, .release = snd_ctl_release, diff -Nru a/sound/core/hwdep.c b/sound/core/hwdep.c --- a/sound/core/hwdep.c Mon Jun 9 23:16:06 2003 +++ b/sound/core/hwdep.c Mon Jun 9 23:16:06 2003 @@ -292,9 +292,7 @@ static struct file_operations snd_hwdep_f_ops = { -#ifndef LINUX_2_2 .owner = THIS_MODULE, -#endif .llseek = snd_hwdep_llseek, .read = snd_hwdep_read, .write = snd_hwdep_write, diff -Nru a/sound/core/info.c b/sound/core/info.c --- a/sound/core/info.c Mon Jun 9 23:16:19 2003 +++ b/sound/core/info.c Mon Jun 9 23:16:19 2003 @@ -41,7 +41,6 @@ { static char *reserved[] = { - "dev", "version", "meminfo", "memdebug", @@ -69,9 +68,6 @@ #ifdef CONFIG_PROC_FS -extern int major; -extern struct file_operations snd_fops; - static DECLARE_MUTEX(info_mutex); typedef struct _snd_info_private_data { @@ -120,33 +116,11 @@ */ struct proc_dir_entry *snd_proc_root = NULL; -struct proc_dir_entry *snd_proc_dev = NULL; snd_info_entry_t *snd_seq_root = NULL; #ifdef CONFIG_SND_OSSEMUL snd_info_entry_t *snd_oss_root = NULL; #endif -#ifdef LINUX_2_2 -static void snd_info_fill_inode(struct inode *inode, int fill) -{ - if (fill) - MOD_INC_USE_COUNT; - else - MOD_DEC_USE_COUNT; -} - -static inline void snd_info_entry_prepare(struct proc_dir_entry *de) -{ - de->fill_inode = snd_info_fill_inode; -} - -void snd_remove_proc_entry(struct proc_dir_entry *parent, - struct proc_dir_entry *de) -{ - if (parent && de) - proc_unregister(parent, de->low_ino); -} -#else static inline void snd_info_entry_prepare(struct proc_dir_entry *de) { de->owner = THIS_MODULE; @@ -158,7 +132,6 @@ if (de) remove_proc_entry(de->name, parent); } -#endif static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig) { @@ -168,9 +141,7 @@ data = snd_magic_cast(snd_info_private_data_t, file->private_data, return -ENXIO); entry = data->entry; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 3) lock_kernel(); -#endif switch (entry->content) { case SNDRV_INFO_CONTENT_TEXT: switch (orig) { @@ -199,9 +170,7 @@ } ret = -ENXIO; out: -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 3) unlock_kernel(); -#endif return ret; } @@ -296,7 +265,7 @@ down(&info_mutex); p = PDE(inode); entry = p == NULL ? NULL : (snd_info_entry_t *)p->data; - if (entry == NULL) { + if (entry == NULL || entry->disconnected) { up(&info_mutex); return -ENODEV; } @@ -520,9 +489,7 @@ static struct file_operations snd_info_entry_operations = { -#ifndef LINUX_2_2 .owner = THIS_MODULE, -#endif .llseek = snd_info_entry_llseek, .read = snd_info_entry_read, .write = snd_info_entry_write, @@ -533,71 +500,6 @@ .release = snd_info_entry_release, }; -#ifdef LINUX_2_2 -static struct inode_operations snd_info_entry_inode_operations = -{ - &snd_info_entry_operations, /* default sound info directory file-ops */ -}; - -static struct inode_operations snd_info_device_inode_operations = -{ - &snd_fops, /* default sound info directory file-ops */ -}; -#endif /* LINUX_2_2 */ - -static int snd_info_card_readlink(struct dentry *dentry, - char *buffer, int buflen) -{ - char *s = PDE(dentry->d_inode)->data; -#ifndef LINUX_2_2 - return vfs_readlink(dentry, buffer, buflen, s); -#else - int len; - - if (s == NULL) - return -EIO; - len = strlen(s); - if (len > buflen) - len = buflen; - if (copy_to_user(buffer, s, len)) - return -EFAULT; - return len; -#endif -} - -#ifndef LINUX_2_2 -static int snd_info_card_followlink(struct dentry *dentry, - struct nameidata *nd) -{ - char *s = PDE(dentry->d_inode)->data; - return vfs_follow_link(nd, s); -} -#else -static struct dentry *snd_info_card_followlink(struct dentry *dentry, - struct dentry *base, - unsigned int follow) -{ - char *s = PDE(dentry->d_inode)->data; - return lookup_dentry(s, base, follow); -} -#endif - -#ifdef LINUX_2_2 -static struct file_operations snd_info_card_link_operations = -{ - NULL -}; -#endif - -struct inode_operations snd_info_card_link_inode_operations = -{ -#ifdef LINUX_2_2 - .default_file_ops = &snd_info_card_link_operations, -#endif - .readlink = snd_info_card_readlink, - .follow_link = snd_info_card_followlink, -}; - /** * snd_create_proc_entry - create a procfs entry * @name: the name of the proc file @@ -627,10 +529,6 @@ if (p == NULL) return -ENOMEM; snd_proc_root = p; - p = snd_create_proc_entry("dev", S_IFDIR | S_IRUGO | S_IXUGO, snd_proc_root); - if (p == NULL) - return -ENOMEM; - snd_proc_dev = p; #ifdef CONFIG_SND_OSSEMUL { snd_info_entry_t *entry; @@ -658,13 +556,9 @@ } #endif snd_info_version_init(); -#ifdef CONFIG_SND_DEBUG_MEMORY snd_memory_info_init(); -#endif snd_minor_info_init(); -#ifdef CONFIG_SND_OSSEMUL snd_minor_info_oss_init(); -#endif snd_card_info_init(); return 0; } @@ -672,13 +566,9 @@ int __exit snd_info_done(void) { snd_card_info_done(); -#ifdef CONFIG_SND_OSSEMUL snd_minor_info_oss_done(); -#endif snd_minor_info_done(); -#ifdef CONFIG_SND_DEBUG_MEMORY snd_memory_info_done(); -#endif snd_info_version_done(); if (snd_proc_root) { #if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE) @@ -689,7 +579,6 @@ if (snd_oss_root) snd_info_unregister(snd_oss_root); #endif - snd_remove_proc_entry(snd_proc_root, snd_proc_dev); snd_remove_proc_entry(&proc_root, snd_proc_root); } return 0; @@ -729,7 +618,6 @@ */ int snd_info_card_register(snd_card_t * card) { - char *s; struct proc_dir_entry *p; snd_assert(card != NULL, return -ENXIO); @@ -737,19 +625,9 @@ if (!strcmp(card->id, card->proc_root->name)) return 0; - s = snd_kmalloc_strdup(card->proc_root->name, GFP_KERNEL); - if (s == NULL) - return -ENOMEM; - p = snd_create_proc_entry(card->id, S_IFLNK | S_IRUGO | S_IWUGO | S_IXUGO, snd_proc_root); + p = proc_symlink(card->id, snd_proc_root, card->proc_root->name); if (p == NULL) return -ENOMEM; - p->data = s; -#ifndef LINUX_2_2 - p->owner = card->module; - p->proc_iops = &snd_info_card_link_inode_operations; -#else - p->ops = &snd_info_card_link_inode_operations; -#endif card->proc_root_link = p; return 0; } @@ -760,13 +638,8 @@ */ int snd_info_card_free(snd_card_t * card) { - void *data; - snd_assert(card != NULL, return -ENXIO); if (card->proc_root_link) { - data = card->proc_root_link->data; - card->proc_root_link->data = NULL; - kfree(data); snd_remove_proc_entry(snd_proc_root, card->proc_root_link); card->proc_root_link = NULL; } @@ -941,6 +814,13 @@ return snd_info_register(entry); } +static int snd_info_dev_disconnect_entry(snd_device_t *device) +{ + snd_info_entry_t *entry = snd_magic_cast(snd_info_entry_t, device->device_data, return -ENXIO); + entry->disconnected = 1; + return 0; +} + static int snd_info_dev_unregister_entry(snd_device_t *device) { snd_info_entry_t *entry = snd_magic_cast(snd_info_entry_t, device->device_data, return -ENXIO); @@ -973,7 +853,7 @@ static snd_device_ops_t ops = { .dev_free = snd_info_dev_free_entry, .dev_register = snd_info_dev_register_entry, - // .dev_disconnect = snd_info_dev_disconnect_entry, + .dev_disconnect = snd_info_dev_disconnect_entry, .dev_unregister = snd_info_dev_unregister_entry }; snd_info_entry_t *entry; @@ -1008,97 +888,6 @@ snd_magic_kfree(entry); } -#ifdef LINUX_2_2 -static void snd_info_device_fill_inode(struct inode *inode, int fill) -{ - struct proc_dir_entry *de; - snd_info_entry_t *entry; - - if (!fill) { - MOD_DEC_USE_COUNT; - return; - } - MOD_INC_USE_COUNT; - de = PDE(inode); - if (de == NULL) - return; - entry = (snd_info_entry_t *) de->data; - if (entry == NULL) - return; - inode->i_gid = device_gid; - inode->i_uid = device_uid; - inode->i_rdev = MKDEV(entry->c.device.major, entry->c.device.minor); -} - -static inline void snd_info_device_entry_prepare(struct proc_dir_entry *de, snd_info_entry_t *entry) -{ - de->fill_inode = snd_info_device_fill_inode; - de->ops = &snd_info_device_inode_operations; -} -#else -static inline void snd_info_device_entry_prepare(struct proc_dir_entry *de, snd_info_entry_t *entry) -{ - de->rdev = mk_kdev(entry->c.device.major, entry->c.device.minor); - de->owner = THIS_MODULE; -} -#endif /* LINUX_2_2 */ - -/* - * create a procfs device file - */ -snd_info_entry_t *snd_info_create_device(const char *name, unsigned int number, unsigned int mode) -{ - unsigned short _major = number >> 16; - unsigned short minor = (unsigned short) number; - snd_info_entry_t *entry; - struct proc_dir_entry *p = NULL; - - if (!_major) - _major = major; - if (!mode) - mode = S_IFCHR | S_IRUGO | S_IWUGO; - mode &= (device_mode & (S_IRUGO | S_IWUGO)) | S_IFCHR | S_IFBLK; - entry = snd_info_create_module_entry(THIS_MODULE, name, NULL); - if (entry == NULL) - return NULL; - entry->content = SNDRV_INFO_CONTENT_DEVICE; - entry->mode = mode; - entry->c.device.major = _major; - entry->c.device.minor = minor; - down(&info_mutex); - p = create_proc_entry(entry->name, entry->mode, snd_proc_dev); - if (p) { - snd_info_device_entry_prepare(p, entry); - } else { - up(&info_mutex); - snd_info_free_entry(entry); - return NULL; - } - p->gid = device_gid; - p->uid = device_uid; - p->data = (void *) entry; - entry->p = p; - up(&info_mutex); - - if (strncmp(name, "controlC", 8) != 0) /* created in sound.c */ - devfs_mk_cdev(MKDEV(_major, minor), mode, "snd/%s", name); - return entry; -} - -/* - * release a procfs device file - */ -void snd_info_free_device(snd_info_entry_t * entry) -{ - snd_runtime_check(entry, return); - down(&info_mutex); - snd_remove_proc_entry(snd_proc_dev, entry->p); - up(&info_mutex); - if (entry->p && strncmp(entry->name, "controlC", 8)) - devfs_remove("snd/%s", entry->name); - snd_info_free_entry(entry); -} - /** * snd_info_register - register the info entry * @entry: the info entry @@ -1119,16 +908,9 @@ up(&info_mutex); return -ENOMEM; } -#ifndef LINUX_2_2 p->owner = entry->module; -#endif - if (!S_ISDIR(entry->mode)) { -#ifndef LINUX_2_2 + if (!S_ISDIR(entry->mode)) p->proc_fops = &snd_info_entry_operations; -#else - p->ops = &snd_info_entry_inode_operations; -#endif - } p->size = entry->size; p->data = entry; entry->p = p; diff -Nru a/sound/core/init.c b/sound/core/init.c --- a/sound/core/init.c Mon Jun 9 23:16:08 2003 +++ b/sound/core/init.c Mon Jun 9 23:16:08 2003 @@ -26,7 +26,6 @@ #include <linux/slab.h> #include <linux/time.h> #include <linux/ctype.h> -#include <linux/workqueue.h> #include <sound/core.h> #include <sound/control.h> #include <sound/info.h> @@ -50,6 +49,8 @@ snd_iprintf(buffer, "%s\n", entry->card->id); } +static void snd_card_free_thread(void * __card); + /** * snd_card_new - create and initialize a soundcard structure * @idx: card index (address) [0 ... (SNDRV_CARDS-1)] @@ -115,6 +116,7 @@ INIT_LIST_HEAD(&card->ctl_files); spin_lock_init(&card->files_lock); init_waitqueue_head(&card->shutdown_sleep); + INIT_WORK(&card->free_workq, snd_card_free_thread, card); #ifdef CONFIG_PM init_MUTEX(&card->power_lock); init_waitqueue_head(&card->power_sleep); @@ -193,9 +195,7 @@ f_ops = &s_f_ops->f_ops; memset(f_ops, 0, sizeof(*f_ops)); -#ifndef LINUX_2_2 f_ops->owner = file->f_op->owner; -#endif f_ops->release = file->f_op->release; f_ops->poll = snd_disconnect_poll; @@ -252,6 +252,10 @@ snd_cards_count--; write_unlock(&snd_card_rwlock); +#ifdef CONFIG_PM + wake_up(&card->power_sleep); +#endif + /* wait, until all devices are ready for the free operation */ wait_event(card->shutdown_sleep, card->files == NULL); @@ -325,16 +329,15 @@ */ int snd_card_free_in_thread(snd_card_t * card) { - DECLARE_WORK(works, snd_card_free_thread, card); - if (card->files == NULL) { snd_card_free(card); return 0; } - if (schedule_work(&works)) + + if (schedule_work(&card->free_workq)) return 0; - snd_printk(KERN_ERR "kernel_thread failed in snd_card_free_in_thread for card %i\n", card->number); + snd_printk(KERN_ERR "schedule_work() failed in snd_card_free_in_thread for card %i\n", card->number); /* try to free the structure immediately */ snd_card_free(card); return -EFAULT; @@ -352,6 +355,10 @@ id++; } id = card->id; + while (*spos != '\0' && !isalnum(*spos)) + spos++; + if (isdigit(*spos)) + *id++ = isalpha(card->shortname[0]) ? card->shortname[0] : 'D'; while (*spos != '\0' && (size_t)(id - card->id) < sizeof(card->id) - 1) { if (isalnum(*spos)) *id++ = *spos; @@ -360,6 +367,9 @@ *id = '\0'; id = card->id; + + if (*id == '\0') + strcpy(id, "default"); while (1) { if (loops-- == 0) { @@ -419,7 +429,7 @@ write_unlock(&snd_card_rwlock); return 0; } - if (!card->id[0]) + if (card->id[0] == '\0') choose_default_id(card); snd_cards[card->number] = card; snd_cards_count++; @@ -662,21 +672,35 @@ /** * snd_power_wait - wait until the power-state is changed. * @card: soundcard structure + * @power_state: expected power state + * @file: file structure for the O_NONBLOCK check (optional) * * Waits until the power-state is changed. * * Note: the power lock must be active before call. */ -void snd_power_wait(snd_card_t *card) +int snd_power_wait(snd_card_t *card, unsigned int power_state, struct file *file) { wait_queue_t wait; + /* fastpath */ + if (snd_power_get_state(card) == power_state) + return 0; init_waitqueue_entry(&wait, current); add_wait_queue(&card->power_sleep, &wait); - snd_power_unlock(card); - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(30 * HZ); - remove_wait_queue(&card->power_sleep, &wait); - snd_power_lock(card); + while (1) { + if (card->shutdown) + return -ENODEV; + if (snd_power_get_state(card) == power_state) { + remove_wait_queue(&card->power_sleep, &wait); + return 0; + } + if (file && (file->f_flags & O_NONBLOCK)) + return -EAGAIN; + snd_power_unlock(card); + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(30 * HZ); + snd_power_lock(card); + } } #endif /* CONFIG_PM */ diff -Nru a/sound/core/memalloc.c b/sound/core/memalloc.c --- a/sound/core/memalloc.c Mon Jun 9 23:16:19 2003 +++ b/sound/core/memalloc.c Mon Jun 9 23:16:19 2003 @@ -80,7 +80,6 @@ #define snd_assert(expr, args...) /**/ #endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) #ifdef CONFIG_PCI #if defined(__i386__) || defined(__ppc__) || defined(__x86_64__) #define HACK_PCI_ALLOC_CONSISTENT @@ -98,7 +97,7 @@ * again. */ -void *snd_pci_hack_alloc_consistent(struct pci_dev *hwdev, size_t size, +static void *snd_pci_hack_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle) { void *ret; @@ -133,7 +132,6 @@ #endif /* arch */ #endif /* CONFIG_PCI */ -#endif /* LINUX >= 2.4.0 */ /* @@ -261,14 +259,16 @@ /* * search for the device */ -static struct snd_mem_list *mem_list_find(const struct snd_dma_device *dev, int allow_unused) +static struct snd_mem_list *mem_list_find(const struct snd_dma_device *dev, int search_empty) { struct list_head *p; struct snd_mem_list *mem; list_for_each(p, &mem_list_head) { mem = list_entry(p, struct snd_mem_list, list); - if (compare_device(&mem->dev, dev, allow_unused)) + if (mem->used && search_empty) + continue; + if (compare_device(&mem->dev, dev, search_empty)) return mem; } return NULL; @@ -623,7 +623,7 @@ } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0) && defined(__i386__) +#if defined(__i386__) /* * on ix86, we allocate a page with GFP_KERNEL to assure the * allocation. the code is almost same with kernel/i386/pci-dma.c but @@ -823,12 +823,12 @@ static void __init preallocate_cards(void) { - struct pci_dev *pci; + struct pci_dev *pci = NULL; int card; card = 0; - pci_for_each_dev(pci) { + while ((pci = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci)) != NULL) { struct prealloc_dev *dev; if (card >= SNDRV_CARDS) break; diff -Nru a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c --- a/sound/core/oss/mixer_oss.c Mon Jun 9 23:16:15 2003 +++ b/sound/core/oss/mixer_oss.c Mon Jun 9 23:16:15 2003 @@ -376,9 +376,7 @@ static struct file_operations snd_mixer_oss_f_ops = { -#ifndef LINUX_2_2 .owner = THIS_MODULE, -#endif .open = snd_mixer_oss_open, .release = snd_mixer_oss_release, .ioctl = snd_mixer_oss_ioctl, diff -Nru a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c --- a/sound/core/oss/pcm_oss.c Mon Jun 9 23:16:18 2003 +++ b/sound/core/oss/pcm_oss.c Mon Jun 9 23:16:18 2003 @@ -1477,10 +1477,10 @@ continue; runtime = substream->runtime; - spin_lock_irq(&runtime->lock); + snd_pcm_stream_lock_irq(substream); if (snd_pcm_running(substream)) snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); - spin_unlock_irq(&runtime->lock); + snd_pcm_stream_unlock_irq(substream); if (substream->open_flag) { if (substream->ops->hw_free != NULL) substream->ops->hw_free(substream); @@ -1918,21 +1918,21 @@ if (psubstream != NULL) { snd_pcm_runtime_t *runtime = psubstream->runtime; poll_wait(file, &runtime->sleep, wait); - spin_lock_irq(&runtime->lock); + snd_pcm_stream_lock_irq(psubstream); if (runtime->status->state != SNDRV_PCM_STATE_DRAINING && (runtime->status->state != SNDRV_PCM_STATE_RUNNING || snd_pcm_oss_playback_ready(psubstream))) mask |= POLLOUT | POLLWRNORM; - spin_unlock_irq(&runtime->lock); + snd_pcm_stream_unlock_irq(psubstream); } if (csubstream != NULL) { snd_pcm_runtime_t *runtime = csubstream->runtime; poll_wait(file, &runtime->sleep, wait); - spin_lock_irq(&runtime->lock); + snd_pcm_stream_lock_irq(csubstream); if (runtime->status->state != SNDRV_PCM_STATE_RUNNING || snd_pcm_oss_capture_ready(csubstream)) mask |= POLLIN | POLLRDNORM; - spin_unlock_irq(&runtime->lock); + snd_pcm_stream_unlock_irq(csubstream); } return mask; @@ -1981,11 +1981,7 @@ if (runtime->oss.plugin_first != NULL) return -EIO; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 25) if (area->vm_pgoff != 0) -#else - if (area->vm_offset != 0) -#endif return -EINVAL; err = snd_pcm_mmap_data(substream, file, area); @@ -2148,9 +2144,7 @@ static struct file_operations snd_pcm_oss_f_reg = { -#ifndef LINUX_2_2 .owner = THIS_MODULE, -#endif .read = snd_pcm_oss_read, .write = snd_pcm_oss_write, .open = snd_pcm_oss_open, diff -Nru a/sound/core/pcm.c b/sound/core/pcm.c --- a/sound/core/pcm.c Mon Jun 9 23:16:20 2003 +++ b/sound/core/pcm.c Mon Jun 9 23:16:20 2003 @@ -317,10 +317,10 @@ snd_iprintf(buffer, "closed\n"); return; } - spin_lock_irq(&runtime->lock); + snd_pcm_stream_lock_irq(substream); if (runtime->status->state == SNDRV_PCM_STATE_OPEN) { snd_iprintf(buffer, "no setup\n"); - spin_unlock_irq(&runtime->lock); + snd_pcm_stream_unlock_irq(substream); return; } snd_iprintf(buffer, "access: %s\n", snd_pcm_access_name(runtime->access)); @@ -340,7 +340,7 @@ snd_iprintf(buffer, "OSS periods: %u\n", runtime->oss.periods); } #endif - spin_unlock_irq(&runtime->lock); + snd_pcm_stream_unlock_irq(substream); } static void snd_pcm_substream_proc_sw_params_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer) @@ -351,10 +351,10 @@ snd_iprintf(buffer, "closed\n"); return; } - spin_lock_irq(&runtime->lock); + snd_pcm_stream_lock_irq(substream); if (runtime->status->state == SNDRV_PCM_STATE_OPEN) { snd_iprintf(buffer, "no setup\n"); - spin_unlock_irq(&runtime->lock); + snd_pcm_stream_unlock_irq(substream); return; } snd_iprintf(buffer, "tstamp_mode: %s\n", snd_pcm_tstamp_mode_name(runtime->tstamp_mode)); @@ -367,7 +367,7 @@ snd_iprintf(buffer, "silence_threshold: %lu\n", runtime->silence_threshold); snd_iprintf(buffer, "silence_size: %lu\n", runtime->silence_size); snd_iprintf(buffer, "boundary: %lu\n", runtime->boundary); - spin_unlock_irq(&runtime->lock); + snd_pcm_stream_unlock_irq(substream); } static void snd_pcm_substream_proc_status_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer) @@ -588,13 +588,15 @@ pstr->substream = substream; else prev->next = substream; - substream->link_next = substream; - substream->link_prev = substream; err = snd_pcm_substream_proc_init(substream); if (err < 0) { snd_magic_kfree(substream); return err; } + substream->group = &substream->self_group; + spin_lock_init(&substream->self_group.lock); + INIT_LIST_HEAD(&substream->self_group.substreams); + list_add_tail(&substream->link_list, &substream->self_group.substreams); spin_lock_init(&substream->timer_lock); prev = substream; } @@ -793,7 +795,6 @@ memset((void*)runtime->control, 0, size); init_waitqueue_head(&runtime->sleep); - spin_lock_init(&runtime->lock); atomic_set(&runtime->mmap_count, 0); init_timer(&runtime->tick_timer); runtime->tick_timer.function = snd_pcm_tick_timer_func; @@ -1022,6 +1023,7 @@ EXPORT_SYMBOL(snd_pcm_format_name); EXPORT_SYMBOL(snd_pcm_subformat_name); /* pcm_native.c */ +EXPORT_SYMBOL(snd_pcm_link_rwlock); EXPORT_SYMBOL(snd_pcm_start); #ifdef CONFIG_PM EXPORT_SYMBOL(snd_pcm_suspend); diff -Nru a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c --- a/sound/core/pcm_lib.c Mon Jun 9 23:16:10 2003 +++ b/sound/core/pcm_lib.c Mon Jun 9 23:16:10 2003 @@ -32,8 +32,8 @@ /* * fill ring buffer with silence - * runtime->silenced_start: starting pointer to silence area - * runtime->silenced_size: size filled with silence + * runtime->silence_start: starting pointer to silence area + * runtime->silence_filled: size filled with silence * runtime->silence_threshold: threshold from application * runtime->silence_size: maximal size from application * @@ -46,20 +46,20 @@ if (runtime->silence_size < runtime->boundary) { snd_pcm_sframes_t noise_dist, n; - if (runtime->silenced_start != runtime->control->appl_ptr) { - n = runtime->control->appl_ptr - runtime->silenced_start; + if (runtime->silence_start != runtime->control->appl_ptr) { + n = runtime->control->appl_ptr - runtime->silence_start; if (n < 0) n += runtime->boundary; - if ((snd_pcm_uframes_t)n < runtime->silenced_size) - runtime->silenced_size -= n; + if ((snd_pcm_uframes_t)n < runtime->silence_filled) + runtime->silence_filled -= n; else - runtime->silenced_size = 0; - runtime->silenced_start = runtime->control->appl_ptr; + runtime->silence_filled = 0; + runtime->silence_start = runtime->control->appl_ptr; } - if (runtime->silenced_size == runtime->buffer_size) + if (runtime->silence_filled == runtime->buffer_size) return; - snd_assert(runtime->silenced_size <= runtime->buffer_size, return); - noise_dist = snd_pcm_playback_hw_avail(runtime) + runtime->silenced_size; + snd_assert(runtime->silence_filled <= runtime->buffer_size, return); + noise_dist = snd_pcm_playback_hw_avail(runtime) + runtime->silence_filled; if (noise_dist > (snd_pcm_sframes_t) runtime->silence_threshold) return; frames = runtime->silence_threshold - noise_dist; @@ -67,30 +67,30 @@ frames = runtime->silence_size; } else { if (new_hw_ptr == ULONG_MAX) { /* initialization */ - runtime->silenced_size = 0; - runtime->silenced_start = runtime->control->appl_ptr; + runtime->silence_filled = 0; + runtime->silence_start = runtime->control->appl_ptr; } else { ofs = runtime->status->hw_ptr; frames = new_hw_ptr - ofs; if ((snd_pcm_sframes_t)frames < 0) frames += runtime->boundary; - runtime->silenced_size -= frames; - if ((snd_pcm_sframes_t)runtime->silenced_size < 0) { - runtime->silenced_size = 0; - runtime->silenced_start = (ofs + frames) - runtime->buffer_size; + runtime->silence_filled -= frames; + if ((snd_pcm_sframes_t)runtime->silence_filled < 0) { + runtime->silence_filled = 0; + runtime->silence_start = (ofs + frames) - runtime->buffer_size; } else { - runtime->silenced_start = ofs - runtime->silenced_size; + runtime->silence_start = ofs - runtime->silence_filled; } - if ((snd_pcm_sframes_t)runtime->silenced_start < 0) - runtime->silenced_start += runtime->boundary; + if ((snd_pcm_sframes_t)runtime->silence_start < 0) + runtime->silence_start += runtime->boundary; } frames = runtime->buffer_size; } - snd_assert(frames >= runtime->silenced_size, return); - frames -= runtime->silenced_size; + snd_assert(frames >= runtime->silence_filled, return); + frames -= runtime->silence_filled; if (frames == 0) return; - ofs = (runtime->silenced_start + runtime->silenced_size) % runtime->buffer_size; + ofs = (runtime->silence_start + runtime->silence_filled) % runtime->buffer_size; while (frames > 0) { transfer = ofs + frames > runtime->buffer_size ? runtime->buffer_size - ofs : frames; if (runtime->access == SNDRV_PCM_ACCESS_RW_INTERLEAVED || @@ -120,13 +120,13 @@ } } } - runtime->silenced_size += transfer; + runtime->silence_filled += transfer; frames -= transfer; ofs = 0; } } -int snd_pcm_update_hw_ptr_interrupt(snd_pcm_substream_t *substream) +static inline int snd_pcm_update_hw_ptr_interrupt(snd_pcm_substream_t *substream) { snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_uframes_t pos; @@ -1932,9 +1932,9 @@ if (runtime->silence_size >= runtime->boundary) { frames = 1; } else if (runtime->silence_size > 0 && - runtime->silenced_size < runtime->buffer_size) { + runtime->silence_filled < runtime->buffer_size) { snd_pcm_sframes_t noise_dist; - noise_dist = snd_pcm_playback_hw_avail(runtime) + runtime->silenced_size; + noise_dist = snd_pcm_playback_hw_avail(runtime) + runtime->silence_filled; snd_assert(noise_dist <= (snd_pcm_sframes_t)runtime->silence_threshold, ); frames = noise_dist - runtime->silence_threshold; } @@ -1976,18 +1976,20 @@ void snd_pcm_tick_elapsed(snd_pcm_substream_t *substream) { snd_pcm_runtime_t *runtime; + unsigned long flags; + snd_assert(substream != NULL, return); runtime = substream->runtime; snd_assert(runtime != NULL, return); - spin_lock_irq(&runtime->lock); + snd_pcm_stream_lock_irqsave(substream, flags); if (!snd_pcm_running(substream) || snd_pcm_update_hw_ptr(substream) < 0) goto _end; if (runtime->sleep_min) snd_pcm_tick_prepare(substream); _end: - spin_unlock_irq(&runtime->lock); + snd_pcm_stream_unlock_irqrestore(substream, flags); } /** @@ -2004,6 +2006,8 @@ void snd_pcm_period_elapsed(snd_pcm_substream_t *substream) { snd_pcm_runtime_t *runtime; + unsigned long flags; + snd_assert(substream != NULL, return); runtime = substream->runtime; snd_assert(runtime != NULL, return); @@ -2011,7 +2015,7 @@ if (runtime->transfer_ack_begin) runtime->transfer_ack_begin(substream); - spin_lock(&runtime->lock); + snd_pcm_stream_lock_irqsave(substream, flags); if (!snd_pcm_running(substream) || snd_pcm_update_hw_ptr_interrupt(substream) < 0) goto _end; @@ -2021,7 +2025,7 @@ if (runtime->sleep_min) snd_pcm_tick_prepare(substream); _end: - spin_unlock(&runtime->lock); + snd_pcm_stream_unlock_irqrestore(substream, flags); if (runtime->transfer_ack_end) runtime->transfer_ack_end(substream); kill_fasync(&runtime->fasync, SIGIO, POLL_IN); @@ -2065,7 +2069,7 @@ if (size > runtime->xfer_align) size -= size % runtime->xfer_align; - spin_lock_irq(&runtime->lock); + snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_PREPARED: case SNDRV_PCM_STATE_RUNNING: @@ -2093,6 +2097,7 @@ (size >= runtime->xfer_align && avail < runtime->xfer_align))) { wait_queue_t wait; enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED } state; + long tout; if (nonblock) { err = -EAGAIN; @@ -2107,16 +2112,16 @@ state = SIGNALED; break; } - spin_unlock_irq(&runtime->lock); - if (schedule_timeout(10 * HZ) == 0) { - spin_lock_irq(&runtime->lock); + snd_pcm_stream_unlock_irq(substream); + tout = schedule_timeout(10 * HZ); + snd_pcm_stream_lock_irq(substream); + if (tout == 0) { if (runtime->status->state != SNDRV_PCM_STATE_PREPARED && runtime->status->state != SNDRV_PCM_STATE_PAUSED) { state = runtime->status->state == SNDRV_PCM_STATE_SUSPENDED ? SUSPENDED : EXPIRED; break; } } - spin_lock_irq(&runtime->lock); switch (runtime->status->state) { case SNDRV_PCM_STATE_XRUN: case SNDRV_PCM_STATE_DRAINING: @@ -2162,15 +2167,13 @@ cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size; if (frames > cont) frames = cont; - snd_assert(frames != 0, - spin_unlock_irq(&runtime->lock); - return -EINVAL); + snd_assert(frames != 0, snd_pcm_stream_unlock_irq(substream); return -EINVAL); appl_ptr = runtime->control->appl_ptr; appl_ofs = appl_ptr % runtime->buffer_size; - spin_unlock_irq(&runtime->lock); + snd_pcm_stream_unlock_irq(substream); if ((err = transfer(substream, appl_ofs, (void *)data, offset, frames)) < 0) goto _end; - spin_lock_irq(&runtime->lock); + snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_XRUN: err = -EPIPE; @@ -2204,7 +2207,7 @@ snd_pcm_tick_prepare(substream); } _end_unlock: - spin_unlock_irq(&runtime->lock); + snd_pcm_stream_unlock_irq(substream); _end: return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; } @@ -2348,7 +2351,7 @@ if (size > runtime->xfer_align) size -= size % runtime->xfer_align; - spin_lock_irq(&runtime->lock); + snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_PREPARED: if (size >= runtime->start_threshold) { @@ -2389,6 +2392,7 @@ (size >= runtime->xfer_align && avail < runtime->xfer_align)) { wait_queue_t wait; enum { READY, SIGNALED, ERROR, SUSPENDED, EXPIRED } state; + long tout; if (nonblock) { err = -EAGAIN; @@ -2403,16 +2407,16 @@ state = SIGNALED; break; } - spin_unlock_irq(&runtime->lock); - if (schedule_timeout(10 * HZ) == 0) { - spin_lock_irq(&runtime->lock); + snd_pcm_stream_unlock_irq(substream); + tout = schedule_timeout(10 * HZ); + snd_pcm_stream_lock_irq(substream); + if (tout == 0) { if (runtime->status->state != SNDRV_PCM_STATE_PREPARED && runtime->status->state != SNDRV_PCM_STATE_PAUSED) { state = runtime->status->state == SNDRV_PCM_STATE_SUSPENDED ? SUSPENDED : EXPIRED; break; } } - spin_lock_irq(&runtime->lock); switch (runtime->status->state) { case SNDRV_PCM_STATE_XRUN: state = ERROR; @@ -2459,15 +2463,13 @@ cont = runtime->buffer_size - runtime->control->appl_ptr % runtime->buffer_size; if (frames > cont) frames = cont; - snd_assert(frames != 0, - spin_unlock_irq(&runtime->lock); - return -EINVAL); + snd_assert(frames != 0, snd_pcm_stream_unlock_irq(substream); return -EINVAL); appl_ptr = runtime->control->appl_ptr; appl_ofs = appl_ptr % runtime->buffer_size; - spin_unlock_irq(&runtime->lock); + snd_pcm_stream_unlock_irq(substream); if ((err = transfer(substream, appl_ofs, (void *)data, offset, frames)) < 0) goto _end; - spin_lock_irq(&runtime->lock); + snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_XRUN: err = -EPIPE; @@ -2495,7 +2497,7 @@ snd_pcm_tick_prepare(substream); } _end_unlock: - spin_unlock_irq(&runtime->lock); + snd_pcm_stream_unlock_irq(substream); _end: return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; } diff -Nru a/sound/core/pcm_native.c b/sound/core/pcm_native.c --- a/sound/core/pcm_native.c Mon Jun 9 23:16:09 2003 +++ b/sound/core/pcm_native.c Mon Jun 9 23:16:09 2003 @@ -64,7 +64,8 @@ * */ -static rwlock_t pcm_link_lock = RW_LOCK_UNLOCKED; +rwlock_t snd_pcm_link_rwlock = RW_LOCK_UNLOCKED; + static inline mm_segment_t snd_enter_user(void) { @@ -463,7 +464,7 @@ if ((params->silence_threshold != 0 || params->silence_size < runtime->boundary) && (params->silence_threshold + params->silence_size > runtime->buffer_size)) return -EINVAL; - spin_lock_irq(&runtime->lock); + snd_pcm_stream_lock_irq(substream); runtime->tstamp_mode = params->tstamp_mode; runtime->sleep_min = params->sleep_min; runtime->period_step = params->period_step; @@ -484,7 +485,7 @@ snd_pcm_playback_silence(substream, ULONG_MAX); wake_up(&runtime->sleep); } - spin_unlock_irq(&runtime->lock); + snd_pcm_stream_unlock_irq(substream); return 0; } @@ -505,7 +506,7 @@ { snd_pcm_runtime_t *runtime = substream->runtime; - spin_lock_irq(&runtime->lock); + snd_pcm_stream_lock_irq(substream); status->state = runtime->status->state; status->suspended_state = runtime->status->suspended_state; if (status->state == SNDRV_PCM_STATE_OPEN) @@ -540,7 +541,7 @@ runtime->avail_max = 0; runtime->overrange = 0; _end: - spin_unlock_irq(&runtime->lock); + snd_pcm_stream_unlock_irq(substream); return 0; } @@ -601,56 +602,128 @@ runtime->trigger_master = NULL; } -#define _SND_PCM_ACTION(aname, substream, state, res, check_master) { \ - snd_pcm_substream_t *s; \ - res = 0; \ - read_lock(&pcm_link_lock); \ - s = substream; \ - do { \ - if (s != substream) \ - spin_lock(&s->runtime->lock); \ - res = snd_pcm_pre_##aname(s, state); \ - if (res < 0) \ - break; \ - s = s->link_next; \ - } while (s != substream); \ - if (res < 0) { \ - /* Clean all spin_lock */ \ - while (s != substream) { \ - spin_unlock(&s->runtime->lock); \ - s = s->link_prev; \ - } \ - goto _end; \ - } \ - s = substream; \ - do { \ - snd_pcm_runtime_t *runtime = s->runtime; \ - int err; \ - if (check_master && runtime->trigger_master != s) \ - goto _done; \ - err = snd_pcm_do_##aname(s, state); \ - if (err < 0) { \ - if (res == 0) \ - res = err; \ - } else { \ - _done: \ - snd_pcm_post_##aname(s, state); \ - } \ - if (s != substream) \ - spin_unlock(&runtime->lock); \ - s = s->link_next; \ - } while (s != substream); \ - _end: \ - read_unlock(&pcm_link_lock); \ -} - -#define SND_PCM_ACTION(aname, substream, state) { \ - int res; \ - _SND_PCM_ACTION(aname, substream, state, res, 1); \ - return res; \ +struct action_ops { + int (*pre_action)(snd_pcm_substream_t *substream, int state); + int (*do_action)(snd_pcm_substream_t *substream, int state); + void (*post_action)(snd_pcm_substream_t *substream, int state); +}; + +/* + * this functions is core for handling of linked stream + * Note: the stream state might be changed also on failure + * Note2: call with calling stream lock + link lock + */ +static int snd_pcm_action_group(struct action_ops *ops, + snd_pcm_substream_t *substream, + int state) +{ + struct list_head *pos; + snd_pcm_substream_t *s = NULL; + int err, res = 0; + + snd_pcm_group_for_each(pos, substream) { + s = snd_pcm_group_substream_entry(pos); + if (s != substream) + spin_lock(&s->self_group.lock); + res = ops->pre_action(s, state); + if (res < 0) + break; + } + if (res >= 0) { + snd_pcm_group_for_each(pos, substream) { + s = snd_pcm_group_substream_entry(pos); + err = ops->do_action(s, state); + if (err < 0) { + if (res == 0) + res = err; + } else { + ops->post_action(s, state); + } + if (s != substream) + spin_unlock(&s->self_group.lock); + } + } else { + snd_pcm_substream_t *s1; + /* unlock all streams */ + snd_pcm_group_for_each(pos, substream) { + s1 = snd_pcm_group_substream_entry(pos); + if (s1 != substream) + spin_unlock(&s1->self_group.lock); + if (s1 == s) /* end */ + break; + } + } + return res; +} + +/* + * Note: call with stream lock + */ +static int snd_pcm_action_single(struct action_ops *ops, + snd_pcm_substream_t *substream, + int state) +{ + int res; + + res = ops->pre_action(substream, state); + if (res < 0) + return res; + res = ops->do_action(substream, state); + if (res == 0) { + ops->post_action(substream, state); + } + return res; +} + +/* + * Note: call with stream lock + */ +static int snd_pcm_action(struct action_ops *ops, + snd_pcm_substream_t *substream, + int state) +{ + int res; + + if (snd_pcm_stream_linked(substream)) { + if (!spin_trylock(&substream->group->lock)) { + spin_unlock(&substream->self_group.lock); + spin_lock(&substream->group->lock); + spin_lock(&substream->self_group.lock); + } + res = snd_pcm_action_group(ops, substream, state); + spin_unlock(&substream->group->lock); + } else { + res = snd_pcm_action_single(ops, substream, state); + } + return res; +} + +/* + * Note: don't use any locks before + */ +static int snd_pcm_action_lock_irq(struct action_ops *ops, + snd_pcm_substream_t *substream, + int state) +{ + int res; + + read_lock_irq(&snd_pcm_link_rwlock); + if (snd_pcm_stream_linked(substream)) { + spin_lock(&substream->group->lock); + spin_lock(&substream->self_group.lock); + res = snd_pcm_action_group(ops, substream, state); + spin_unlock(&substream->self_group.lock); + spin_unlock(&substream->group->lock); + } else { + spin_lock(&substream->self_group.lock); + res = snd_pcm_action_single(ops, substream, state); + spin_unlock(&substream->self_group.lock); + } + read_unlock_irq(&snd_pcm_link_rwlock); + return res; } -static inline int snd_pcm_pre_start(snd_pcm_substream_t *substream, int state) +static int snd_pcm_pre_start(snd_pcm_substream_t *substream, int state) { snd_pcm_runtime_t *runtime = substream->runtime; if (runtime->status->state != SNDRV_PCM_STATE_PREPARED) @@ -662,12 +735,14 @@ return 0; } -static inline int snd_pcm_do_start(snd_pcm_substream_t *substream, int state) +static int snd_pcm_do_start(snd_pcm_substream_t *substream, int state) { + if (substream->runtime->trigger_master != substream) + return 0; return substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_START); } -static inline void snd_pcm_post_start(snd_pcm_substream_t *substream, int state) +static void snd_pcm_post_start(snd_pcm_substream_t *substream, int state) { snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_trigger_tstamp(substream); @@ -681,15 +756,21 @@ snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTART, &runtime->trigger_tstamp); } +static struct action_ops snd_pcm_action_start = { + .pre_action = snd_pcm_pre_start, + .do_action = snd_pcm_do_start, + .post_action = snd_pcm_post_start +}; + /** - * snd_pcm_sart + * snd_pcm_start */ int snd_pcm_start(snd_pcm_substream_t *substream) { - SND_PCM_ACTION(start, substream, 0); + return snd_pcm_action(&snd_pcm_action_start, substream, 0); } -static inline int snd_pcm_pre_stop(snd_pcm_substream_t *substream, int state) +static int snd_pcm_pre_stop(snd_pcm_substream_t *substream, int state) { snd_pcm_runtime_t *runtime = substream->runtime; if (substream->runtime->status->state != SNDRV_PCM_STATE_RUNNING && @@ -699,12 +780,14 @@ return 0; } -static inline int snd_pcm_do_stop(snd_pcm_substream_t *substream, int state) +static int snd_pcm_do_stop(snd_pcm_substream_t *substream, int state) { + if (substream->runtime->trigger_master != substream) + return 0; return substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_STOP); } -static inline void snd_pcm_post_stop(snd_pcm_substream_t *substream, int state) +static void snd_pcm_post_stop(snd_pcm_substream_t *substream, int state) { snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_trigger_tstamp(substream); @@ -715,15 +798,21 @@ wake_up(&runtime->sleep); } +static struct action_ops snd_pcm_action_stop = { + .pre_action = snd_pcm_pre_stop, + .do_action = snd_pcm_do_stop, + .post_action = snd_pcm_post_stop +}; + /** * snd_pcm_stop */ int snd_pcm_stop(snd_pcm_substream_t *substream, int state) { - SND_PCM_ACTION(stop, substream, state); + return snd_pcm_action(&snd_pcm_action_stop, substream, state); } -static inline int snd_pcm_pre_pause(snd_pcm_substream_t *substream, int push) +static int snd_pcm_pre_pause(snd_pcm_substream_t *substream, int push) { snd_pcm_runtime_t *runtime = substream->runtime; if (!(runtime->info & SNDRV_PCM_INFO_PAUSE)) @@ -737,14 +826,16 @@ return 0; } -static inline int snd_pcm_do_pause(snd_pcm_substream_t *substream, int push) +static int snd_pcm_do_pause(snd_pcm_substream_t *substream, int push) { + if (substream->runtime->trigger_master != substream) + return 0; return substream->ops->trigger(substream, push ? SNDRV_PCM_TRIGGER_PAUSE_PUSH : SNDRV_PCM_TRIGGER_PAUSE_RELEASE); } -static inline void snd_pcm_post_pause(snd_pcm_substream_t *substream, int push) +static void snd_pcm_post_pause(snd_pcm_substream_t *substream, int push) { snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_trigger_tstamp(substream); @@ -763,15 +854,21 @@ } } +static struct action_ops snd_pcm_action_pause = { + .pre_action = snd_pcm_pre_pause, + .do_action = snd_pcm_do_pause, + .post_action = snd_pcm_post_pause +}; + static int snd_pcm_pause(snd_pcm_substream_t *substream, int push) { - SND_PCM_ACTION(pause, substream, push); + return snd_pcm_action(&snd_pcm_action_pause, substream, push); } #ifdef CONFIG_PM /* suspend */ -static inline int snd_pcm_pre_suspend(snd_pcm_substream_t *substream, int state) +static int snd_pcm_pre_suspend(snd_pcm_substream_t *substream, int state) { snd_pcm_runtime_t *runtime = substream->runtime; if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) @@ -781,15 +878,17 @@ return 0; } -static inline int snd_pcm_do_suspend(snd_pcm_substream_t *substream, int state) +static int snd_pcm_do_suspend(snd_pcm_substream_t *substream, int state) { snd_pcm_runtime_t *runtime = substream->runtime; + if (runtime->trigger_master != substream) + return 0; if (runtime->status->suspended_state != SNDRV_PCM_STATE_RUNNING) return 0; return substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_SUSPEND); } -static inline void snd_pcm_post_suspend(snd_pcm_substream_t *substream, int state) +static void snd_pcm_post_suspend(snd_pcm_substream_t *substream, int state) { snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_trigger_tstamp(substream); @@ -800,12 +899,18 @@ wake_up(&runtime->sleep); } +static struct action_ops snd_pcm_action_suspend = { + .pre_action = snd_pcm_pre_suspend, + .do_action = snd_pcm_do_suspend, + .post_action = snd_pcm_post_suspend +}; + /** * snd_pcm_suspend */ int snd_pcm_suspend(snd_pcm_substream_t *substream) { - SND_PCM_ACTION(suspend, substream, 0); + return snd_pcm_action(&snd_pcm_action_suspend, substream, 0); } /** @@ -814,24 +919,23 @@ int snd_pcm_suspend_all(snd_pcm_t *pcm) { snd_pcm_substream_t *substream; - snd_pcm_runtime_t *runtime; int stream, err; for (stream = 0; stream < 2; stream++) { for (substream = pcm->streams[stream].substream; substream; substream = substream->next) { /* FIXME: the open/close code should lock this as well */ - if ((runtime = substream->runtime) == NULL) + if (substream->runtime == NULL) continue; - spin_lock(&runtime->lock); - if (runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { - spin_unlock(&runtime->lock); + snd_pcm_stream_lock(substream); + if (substream->runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) { + snd_pcm_stream_unlock(substream); continue; } if ((err = snd_pcm_suspend(substream)) < 0) { - spin_unlock(&runtime->lock); + snd_pcm_stream_unlock(substream); return err; } - spin_unlock(&runtime->lock); + snd_pcm_stream_unlock(substream); } } return 0; @@ -839,7 +943,7 @@ /* resume */ -static inline int snd_pcm_pre_resume(snd_pcm_substream_t *substream, int state) +static int snd_pcm_pre_resume(snd_pcm_substream_t *substream, int state) { snd_pcm_runtime_t *runtime = substream->runtime; if (!(runtime->info & SNDRV_PCM_INFO_RESUME)) @@ -848,15 +952,17 @@ return 0; } -static inline int snd_pcm_do_resume(snd_pcm_substream_t *substream, int state) +static int snd_pcm_do_resume(snd_pcm_substream_t *substream, int state) { snd_pcm_runtime_t *runtime = substream->runtime; + if (runtime->trigger_master != substream) + return 0; if (runtime->status->suspended_state != SNDRV_PCM_STATE_RUNNING) return 0; return substream->ops->trigger(substream, SNDRV_PCM_TRIGGER_RESUME); } -static inline void snd_pcm_post_resume(snd_pcm_substream_t *substream, int state) +static void snd_pcm_post_resume(snd_pcm_substream_t *substream, int state) { snd_pcm_runtime_t *runtime = substream->runtime; snd_pcm_trigger_tstamp(substream); @@ -867,23 +973,20 @@ snd_pcm_tick_prepare(substream); } +static struct action_ops snd_pcm_action_resume = { + .pre_action = snd_pcm_pre_resume, + .do_action = snd_pcm_do_resume, + .post_action = snd_pcm_post_resume +}; + static int snd_pcm_resume(snd_pcm_substream_t *substream) { snd_card_t *card = substream->pcm->card; int res; snd_power_lock(card); - while (snd_power_get_state(card) != SNDRV_CTL_POWER_D0) { - if (substream->ffile->f_flags & O_NONBLOCK) { - res = -EAGAIN; - goto _power_unlock; - } - snd_power_wait(card); - } - - _SND_PCM_ACTION(resume, substream, 0, res, 1); - - _power_unlock: + if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile)) >= 0) + return snd_pcm_action_lock_irq(&snd_pcm_action_resume, substream, 0); snd_power_unlock(card); return res; } @@ -904,7 +1007,7 @@ int result; snd_power_lock(card); - spin_lock_irq(&runtime->lock); + snd_pcm_stream_lock_irq(substream); _xrun_recovery: switch (runtime->status->state) { case SNDRV_PCM_STATE_XRUN: @@ -914,26 +1017,21 @@ result = snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); break; case SNDRV_PCM_STATE_SUSPENDED: - while (snd_power_get_state(card) != SNDRV_CTL_POWER_D0) { - if (substream->ffile->f_flags & O_NONBLOCK) { - result = -EAGAIN; - goto _end; - } - spin_unlock_irq(&runtime->lock); - snd_power_wait(card); - spin_lock_irq(&runtime->lock); - } - goto _xrun_recovery; + snd_pcm_stream_unlock_irq(substream); + result = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile); + snd_pcm_stream_lock_irq(substream); + if (result >= 0) + goto _xrun_recovery; + break; default: result = -EBADFD; } - _end: - spin_unlock_irq(&runtime->lock); + snd_pcm_stream_unlock_irq(substream); snd_power_unlock(card); return result; } -static inline int snd_pcm_pre_reset(snd_pcm_substream_t * substream, int state) +static int snd_pcm_pre_reset(snd_pcm_substream_t * substream, int state) { snd_pcm_runtime_t *runtime = substream->runtime; switch (runtime->status->state) { @@ -947,7 +1045,7 @@ } } -static inline int snd_pcm_do_reset(snd_pcm_substream_t * substream, int state) +static int snd_pcm_do_reset(snd_pcm_substream_t * substream, int state) { snd_pcm_runtime_t *runtime = substream->runtime; int err = substream->ops->ioctl(substream, SNDRV_PCM_IOCTL1_RESET, 0); @@ -956,12 +1054,12 @@ // snd_assert(runtime->status->hw_ptr < runtime->buffer_size, ); runtime->hw_ptr_base = 0; runtime->hw_ptr_interrupt = runtime->status->hw_ptr - runtime->status->hw_ptr % runtime->period_size; - runtime->silenced_start = runtime->status->hw_ptr; - runtime->silenced_size = 0; + runtime->silence_start = runtime->status->hw_ptr; + runtime->silence_filled = 0; return 0; } -static inline void snd_pcm_post_reset(snd_pcm_substream_t * substream, int state) +static void snd_pcm_post_reset(snd_pcm_substream_t * substream, int state) { snd_pcm_runtime_t *runtime = substream->runtime; runtime->control->appl_ptr = runtime->status->hw_ptr; @@ -970,17 +1068,18 @@ snd_pcm_playback_silence(substream, ULONG_MAX); } +static struct action_ops snd_pcm_action_reset = { + .pre_action = snd_pcm_pre_reset, + .do_action = snd_pcm_do_reset, + .post_action = snd_pcm_post_reset +}; + static int snd_pcm_reset(snd_pcm_substream_t *substream) { - int res; - - spin_lock_irq(&substream->runtime->lock); - _SND_PCM_ACTION(reset, substream, 0, res, 0); - spin_unlock_irq(&substream->runtime->lock); - return res; + return snd_pcm_action_lock_irq(&snd_pcm_action_reset, substream, 0); } -static inline int snd_pcm_pre_prepare(snd_pcm_substream_t * substream, int state) +static int snd_pcm_pre_prepare(snd_pcm_substream_t * substream, int state) { snd_pcm_runtime_t *runtime = substream->runtime; switch (runtime->status->state) { @@ -993,7 +1092,7 @@ } } -static inline int snd_pcm_do_prepare(snd_pcm_substream_t * substream, int state) +static int snd_pcm_do_prepare(snd_pcm_substream_t * substream, int state) { int err; err = substream->ops->prepare(substream); @@ -1002,13 +1101,19 @@ return snd_pcm_do_reset(substream, 0); } -static inline void snd_pcm_post_prepare(snd_pcm_substream_t * substream, int state) +static void snd_pcm_post_prepare(snd_pcm_substream_t * substream, int state) { snd_pcm_runtime_t *runtime = substream->runtime; runtime->control->appl_ptr = runtime->status->hw_ptr; runtime->status->state = SNDRV_PCM_STATE_PREPARED; } +static struct action_ops snd_pcm_action_prepare = { + .pre_action = snd_pcm_pre_prepare, + .do_action = snd_pcm_do_prepare, + .post_action = snd_pcm_post_prepare +}; + /** * snd_pcm_prepare */ @@ -1018,41 +1123,35 @@ snd_card_t *card = substream->pcm->card; snd_power_lock(card); - while (snd_power_get_state(card) != SNDRV_CTL_POWER_D0) { - if (substream->ffile->f_flags & O_NONBLOCK) { - res = -EAGAIN; - goto _power_unlock; - } - snd_power_wait(card); - } - - spin_lock_irq(&substream->runtime->lock); - _SND_PCM_ACTION(prepare, substream, 0, res, 0); - spin_unlock_irq(&substream->runtime->lock); - - _power_unlock: + if ((res = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile)) >= 0) + res = snd_pcm_action_lock_irq(&snd_pcm_action_prepare, substream, 0); snd_power_unlock(card); return res; } static void snd_pcm_change_state(snd_pcm_substream_t *substream, int state) { + struct list_head *pos; snd_pcm_substream_t *s; - read_lock(&pcm_link_lock); - s = substream->link_next; - while (s != substream) { - spin_lock(&s->runtime->lock); - s = s->link_next; + + if (snd_pcm_stream_linked(substream)) { + if (!spin_trylock(&substream->group->lock)) { + spin_unlock(&substream->self_group.lock); + spin_lock(&substream->group->lock); + spin_lock(&substream->self_group.lock); + } + snd_pcm_group_for_each(pos, substream) { + s = snd_pcm_group_substream_entry(pos); + if (s != substream) + spin_lock(&s->self_group.lock); + s->runtime->status->state = state; + if (s != substream) + spin_unlock(&s->self_group.lock); + } + spin_unlock(&substream->group->lock); + } else { + substream->runtime->status->state = state; } - s = substream; - do { - snd_pcm_runtime_t *runtime = s->runtime; - runtime->status->state = state; - if (s != substream) - spin_unlock(&runtime->lock); - s = s->link_next; - } while (s != substream); - read_unlock(&pcm_link_lock); } static int snd_pcm_playback_drop(snd_pcm_substream_t *substream); @@ -1072,7 +1171,7 @@ card = substream->pcm->card; snd_power_lock(card); - spin_lock_irq(&runtime->lock); + snd_pcm_stream_lock_irq(substream); /* stop_threshold fixup to avoid endless loop when */ /* stop_threshold > buffer_size */ @@ -1088,16 +1187,12 @@ case SNDRV_PCM_STATE_DRAINING: break; case SNDRV_PCM_STATE_SUSPENDED: - while (snd_power_get_state(card) != SNDRV_CTL_POWER_D0) { - if (substream->ffile->f_flags & O_NONBLOCK) { - result = -EAGAIN; - goto _end; - } - spin_unlock_irq(&runtime->lock); - snd_power_wait(card); - spin_lock_irq(&runtime->lock); - } - goto _xrun_recovery; + snd_pcm_stream_unlock_irq(substream); + result = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile); + snd_pcm_stream_lock_irq(substream); + if (result >= 0) + snd_pcm_change_state(substream, SNDRV_PCM_STATE_SETUP); + goto _end; case SNDRV_PCM_STATE_OPEN: result = -EBADFD; goto _end; @@ -1112,7 +1207,6 @@ } /* Fall through */ case SNDRV_PCM_STATE_XRUN: - _xrun_recovery: snd_pcm_change_state(substream, SNDRV_PCM_STATE_SETUP); /* Fall through */ case SNDRV_PCM_STATE_SETUP: @@ -1137,18 +1231,19 @@ init_waitqueue_entry(&wait, current); add_wait_queue(&runtime->sleep, &wait); while (1) { + long tout; set_current_state(TASK_INTERRUPTIBLE); if (signal_pending(current)) { state = SIGNALED; break; } - spin_unlock_irq(&runtime->lock); - if (schedule_timeout(10 * HZ) == 0) { - spin_lock_irq(&runtime->lock); + snd_pcm_stream_unlock_irq(substream); + tout = schedule_timeout(10 * HZ); + snd_pcm_stream_lock_irq(substream); + if (tout == 0) { state = runtime->status->state == SNDRV_PCM_STATE_SUSPENDED ? SUSPENDED : EXPIRED; break; } - spin_lock_irq(&runtime->lock); if (runtime->status->state != SNDRV_PCM_STATE_DRAINING) { state = READY; break; @@ -1174,7 +1269,7 @@ _end: runtime->stop_threshold = stop_threshold; - spin_unlock_irq(&runtime->lock); + snd_pcm_stream_unlock_irq(substream); snd_power_unlock(card); if (state == EXPIRED) snd_pcm_playback_drop(substream); @@ -1187,8 +1282,9 @@ snd_pcm_runtime_t *runtime = substream->runtime; snd_card_t *card = substream->pcm->card; int res = 0; + snd_power_lock(card); - spin_lock_irq(&runtime->lock); + snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_OPEN: res = -EBADFD; @@ -1207,26 +1303,20 @@ /* Fall through */ case SNDRV_PCM_STATE_PREPARED: case SNDRV_PCM_STATE_XRUN: - _xrun_recovery: snd_pcm_change_state(substream, SNDRV_PCM_STATE_SETUP); break; case SNDRV_PCM_STATE_SUSPENDED: - while (snd_power_get_state(card) != SNDRV_CTL_POWER_D0) { - if (substream->ffile->f_flags & O_NONBLOCK) { - res = -EAGAIN; - goto _end; - } - spin_unlock_irq(&runtime->lock); - snd_power_wait(card); - spin_lock_irq(&runtime->lock); - } - goto _xrun_recovery; + snd_pcm_stream_unlock_irq(substream); + res = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile); + snd_pcm_stream_lock_irq(substream); + if (res >= 0) + snd_pcm_change_state(substream, SNDRV_PCM_STATE_SETUP); + break; default: break; } runtime->control->appl_ptr = runtime->status->hw_ptr; - _end: - spin_unlock_irq(&runtime->lock); + snd_pcm_stream_unlock_irq(substream); snd_power_unlock(card); return res; } @@ -1236,8 +1326,9 @@ snd_pcm_runtime_t *runtime = substream->runtime; snd_card_t *card = substream->pcm->card; int res = 0; + snd_power_lock(card); - spin_lock_irq(&runtime->lock); + snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_OPEN: res = -EBADFD; @@ -1266,21 +1357,16 @@ SNDRV_PCM_STATE_DRAINING : SNDRV_PCM_STATE_SETUP); break; case SNDRV_PCM_STATE_SUSPENDED: - while (snd_power_get_state(card) != SNDRV_CTL_POWER_D0) { - if (substream->ffile->f_flags & O_NONBLOCK) { - res = -EAGAIN; - goto _end; - } - spin_unlock_irq(&runtime->lock); - snd_power_wait(card); - spin_lock_irq(&runtime->lock); - } - goto _xrun_recovery; + snd_pcm_stream_unlock_irq(substream); + res = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile); + snd_pcm_stream_lock_irq(substream); + if (res >= 0) + goto _xrun_recovery; + break; default: break; } - _end: - spin_unlock_irq(&runtime->lock); + snd_pcm_stream_unlock_irq(substream); snd_power_unlock(card); return res; } @@ -1290,8 +1376,9 @@ snd_pcm_runtime_t *runtime = substream->runtime; snd_card_t *card = substream->pcm->card; int res = 0; + snd_power_lock(card); - spin_lock_irq(&runtime->lock); + snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_OPEN: res = -EBADFD; @@ -1305,15 +1392,11 @@ snd_pcm_stop(substream, SNDRV_PCM_STATE_SETUP); break; case SNDRV_PCM_STATE_SUSPENDED: - while (snd_power_get_state(card) != SNDRV_CTL_POWER_D0) { - if (substream->ffile->f_flags & O_NONBLOCK) { - res = -EAGAIN; - goto _end; - } - spin_unlock_irq(&runtime->lock); - snd_power_wait(card); - spin_lock_irq(&runtime->lock); - } + snd_pcm_stream_unlock_irq(substream); + res = snd_power_wait(card, SNDRV_CTL_POWER_D0, substream->ffile); + snd_pcm_stream_lock_irq(substream); + if (res < 0) + goto _end; /* Fall through */ case SNDRV_PCM_STATE_PREPARED: case SNDRV_PCM_STATE_DRAINING: @@ -1324,13 +1407,14 @@ break; } runtime->control->appl_ptr = runtime->status->hw_ptr; - _end: - spin_unlock_irq(&runtime->lock); + _end: + snd_pcm_stream_unlock_irq(substream); snd_power_unlock(card); return res; } /* WARNING: Don't forget to fput back the file */ +extern int snd_major; static struct file *snd_pcm_file_fd(int fd) { struct file *file; @@ -1341,7 +1425,7 @@ return 0; inode = file->f_dentry->d_inode; if (!S_ISCHR(inode->i_mode) || - major(inode->i_rdev) != CONFIG_SND_MAJOR) { + major(inode->i_rdev) != snd_major) { fput(file); return 0; } @@ -1359,7 +1443,8 @@ int res = 0; struct file *file; snd_pcm_file_t *pcm_file; - snd_pcm_substream_t *s, *substream1; + snd_pcm_substream_t *substream1; + if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) return -EBADFD; file = snd_pcm_file_fd(fd); @@ -1367,40 +1452,67 @@ return -EBADFD; pcm_file = snd_magic_cast(snd_pcm_file_t, file->private_data, return -ENXIO); substream1 = pcm_file->substream; - write_lock_irq(&pcm_link_lock); + write_lock_irq(&snd_pcm_link_rwlock); if (substream->runtime->status->state != substream1->runtime->status->state) { res = -EBADFD; goto _end; } - s = substream; - do { - if (s == substream1) { - res = -EALREADY; + if (snd_pcm_stream_linked(substream1)) { + res = -EALREADY; + goto _end; + } + if (!snd_pcm_stream_linked(substream)) { + substream->group = kmalloc(sizeof(snd_pcm_group_t), GFP_ATOMIC); + if (substream->group == NULL) { + res = -ENOMEM; goto _end; } - s = s->link_next; - } while (s != substream); - substream1->link_prev->link_next = substream->link_next; - substream->link_next->link_prev = substream1->link_prev; - substream->link_next = substream1; - substream1->link_prev = substream; + spin_lock_init(&substream->group->lock); + INIT_LIST_HEAD(&substream->group->substreams); + list_add_tail(&substream->link_list, &substream->group->substreams); + } + list_add_tail(&substream1->link_list, &substream->group->substreams); + substream1->group = substream->group; _end: - write_unlock_irq(&pcm_link_lock); + write_unlock_irq(&snd_pcm_link_rwlock); fput(file); return res; } -static int snd_pcm_unlink(snd_pcm_substream_t *substream) +static void relink_to_local(snd_pcm_substream_t *substream) { - write_lock_irq(&pcm_link_lock); - substream->link_prev->link_next = substream->link_next; - substream->link_next->link_prev = substream->link_prev; - substream->link_prev = substream; - substream->link_next = substream; - write_unlock_irq(&pcm_link_lock); - return 0; + substream->group = &substream->self_group; + INIT_LIST_HEAD(&substream->self_group.substreams); + list_add_tail(&substream->link_list, &substream->self_group.substreams); } +static int snd_pcm_unlink(snd_pcm_substream_t *substream) +{ + struct list_head *pos; + int res = 0, count = 0; + + write_lock_irq(&snd_pcm_link_rwlock); + if (!snd_pcm_stream_linked(substream)) { + res = -EINVAL; + goto _end; + } + list_del(&substream->link_list); + snd_pcm_group_for_each(pos, substream) { + if (++count > 1) + break; + } + if (count == 1) { /* detach the last stream, too */ + snd_pcm_group_for_each(pos, substream) { + relink_to_local(snd_pcm_group_substream_entry(pos)); + break; + } + kfree(substream->group); + } + relink_to_local(substream); + _end: + write_unlock_irq(&snd_pcm_link_rwlock); + return res; +} static int snd_pcm_hw_rule_mul(snd_pcm_hw_params_t *params, snd_pcm_hw_rule_t *rule) @@ -1453,7 +1565,8 @@ if (! snd_mask_test(mask, k)) continue; bits = snd_pcm_format_physical_width(k); - snd_assert(bits > 0, continue); + if (bits <= 0) + continue; /* ignore invalid formats */ if ((unsigned)bits < i->min || (unsigned)bits > i->max) snd_mask_reset(&m, k); } @@ -1474,7 +1587,8 @@ if (! snd_mask_test(hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT), k)) continue; bits = snd_pcm_format_physical_width(k); - snd_assert(bits > 0, continue); + if (bits <= 0) + continue; /* ignore invalid formats */ if (t.min > (unsigned)bits) t.min = bits; if (t.max < (unsigned)bits) @@ -1912,7 +2026,7 @@ if (frames == 0) return 0; - spin_lock_irq(&runtime->lock); + snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_PREPARED: break; @@ -1947,7 +2061,7 @@ snd_pcm_tick_prepare(substream); ret = frames; __end: - spin_unlock_irq(&runtime->lock); + snd_pcm_stream_unlock_irq(substream); return ret; } @@ -1961,7 +2075,7 @@ if (frames == 0) return 0; - spin_lock_irq(&runtime->lock); + snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_PREPARED: case SNDRV_PCM_STATE_DRAINING: @@ -1996,7 +2110,7 @@ snd_pcm_tick_prepare(substream); ret = frames; __end: - spin_unlock_irq(&runtime->lock); + snd_pcm_stream_unlock_irq(substream); return ret; } @@ -2010,7 +2124,7 @@ if (frames == 0) return 0; - spin_lock_irq(&runtime->lock); + snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_PREPARED: case SNDRV_PCM_STATE_PAUSED: @@ -2046,7 +2160,7 @@ snd_pcm_tick_prepare(substream); ret = frames; __end: - spin_unlock_irq(&runtime->lock); + snd_pcm_stream_unlock_irq(substream); return ret; } @@ -2060,7 +2174,7 @@ if (frames == 0) return 0; - spin_lock_irq(&runtime->lock); + snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_PREPARED: case SNDRV_PCM_STATE_DRAINING: @@ -2096,7 +2210,7 @@ snd_pcm_tick_prepare(substream); ret = frames; __end: - spin_unlock_irq(&runtime->lock); + snd_pcm_stream_unlock_irq(substream); return ret; } @@ -2105,7 +2219,7 @@ snd_pcm_runtime_t *runtime = substream->runtime; int err; - spin_lock_irq(&runtime->lock); + snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_DRAINING: if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) @@ -2126,7 +2240,7 @@ err = -EBADFD; break; } - spin_unlock_irq(&runtime->lock); + snd_pcm_stream_unlock_irq(substream); return err; } @@ -2136,7 +2250,7 @@ int err; snd_pcm_sframes_t n = 0; - spin_lock_irq(&runtime->lock); + snd_pcm_stream_lock_irq(substream); switch (runtime->status->state) { case SNDRV_PCM_STATE_DRAINING: if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) @@ -2161,7 +2275,7 @@ err = -EBADFD; break; } - spin_unlock_irq(&runtime->lock); + snd_pcm_stream_unlock_irq(substream); if (!err) if (put_user(n, res)) err = -EFAULT; @@ -2208,13 +2322,7 @@ case SNDRV_PCM_IOCTL_RESET: return snd_pcm_reset(substream); case SNDRV_PCM_IOCTL_START: - { - int res; - spin_lock_irq(&substream->runtime->lock); - res = snd_pcm_start(substream); - spin_unlock_irq(&substream->runtime->lock); - return res; - } + return snd_pcm_action(&snd_pcm_action_start, substream, 0); case SNDRV_PCM_IOCTL_LINK: return snd_pcm_link(substream, (long) arg); case SNDRV_PCM_IOCTL_UNLINK: @@ -2310,9 +2418,9 @@ case SNDRV_PCM_IOCTL_PAUSE: { int res; - spin_lock_irq(&substream->runtime->lock); + snd_pcm_stream_lock_irq(substream); res = snd_pcm_pause(substream, (long) arg); - spin_unlock_irq(&substream->runtime->lock); + snd_pcm_stream_unlock_irq(substream); return res; } case SNDRV_PCM_IOCTL_DRAIN: @@ -2494,9 +2602,6 @@ snd_pcm_runtime_t *runtime; snd_pcm_sframes_t result; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0) - up(&file->f_dentry->d_inode->i_sem); -#endif pcm_file = snd_magic_cast(snd_pcm_file_t, file->private_data, result = -ENXIO; goto end); substream = pcm_file->substream; snd_assert(substream != NULL, result = -ENXIO; goto end); @@ -2514,13 +2619,9 @@ if (result > 0) result = frames_to_bytes(runtime, result); end: -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0) - down(&file->f_dentry->d_inode->i_sem); -#endif return result; } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 44) static ssize_t snd_pcm_readv(struct file *file, const struct iovec *_vector, unsigned long count, loff_t * offset) @@ -2567,9 +2668,6 @@ void **bufs; snd_pcm_uframes_t frames; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0) - up(&file->f_dentry->d_inode->i_sem); -#endif pcm_file = snd_magic_cast(snd_pcm_file_t, file->private_data, result = -ENXIO; goto end); substream = pcm_file->substream; snd_assert(substream != NULL, result = -ENXIO; goto end); @@ -2594,12 +2692,8 @@ result = frames_to_bytes(runtime, result); kfree(bufs); end: -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 3, 0) - down(&file->f_dentry->d_inode->i_sem); -#endif return result; } -#endif unsigned int snd_pcm_playback_poll(struct file *file, poll_table * wait) { @@ -2617,7 +2711,7 @@ poll_wait(file, &runtime->sleep, wait); - spin_lock_irq(&runtime->lock); + snd_pcm_stream_lock_irq(substream); avail = snd_pcm_playback_avail(runtime); switch (runtime->status->state) { case SNDRV_PCM_STATE_RUNNING: @@ -2635,7 +2729,7 @@ mask = POLLOUT | POLLWRNORM | POLLERR; break; } - spin_unlock_irq(&runtime->lock); + snd_pcm_stream_unlock_irq(substream); return mask; } @@ -2655,7 +2749,7 @@ poll_wait(file, &runtime->sleep, wait); - spin_lock_irq(&runtime->lock); + snd_pcm_stream_lock_irq(substream); avail = snd_pcm_capture_avail(runtime); switch (runtime->status->state) { case SNDRV_PCM_STATE_RUNNING: @@ -2677,26 +2771,11 @@ mask = POLLIN | POLLRDNORM | POLLERR; break; } - spin_unlock_irq(&runtime->lock); + snd_pcm_stream_unlock_irq(substream); return mask; } -#ifndef VM_RESERVED -#ifndef LINUX_2_2 -static int snd_pcm_mmap_swapout(struct page * page, struct file * file) -#else -static int snd_pcm_mmap_swapout(struct vm_area_struct * area, struct page * page) -#endif -{ - return 0; -} -#endif - -#ifndef LINUX_2_2 static struct page * snd_pcm_mmap_status_nopage(struct vm_area_struct *area, unsigned long address, int no_share) -#else -static unsigned long snd_pcm_mmap_status_nopage(struct vm_area_struct *area, unsigned long address, int no_share) -#endif { snd_pcm_substream_t *substream = (snd_pcm_substream_t *)area->vm_private_data; snd_pcm_runtime_t *runtime; @@ -2707,19 +2786,12 @@ runtime = substream->runtime; page = virt_to_page(runtime->status); get_page(page); -#ifndef LINUX_2_2 return page; -#else - return page_address(page); -#endif } static struct vm_operations_struct snd_pcm_vm_ops_status = { .nopage = snd_pcm_mmap_status_nopage, -#ifndef VM_RESERVED - .swapout = snd_pcm_mmap_swapout, -#endif }; int snd_pcm_mmap_status(snd_pcm_substream_t *substream, struct file *file, @@ -2735,22 +2807,12 @@ if (size != PAGE_ALIGN(sizeof(snd_pcm_mmap_status_t))) return -EINVAL; area->vm_ops = &snd_pcm_vm_ops_status; -#ifndef LINUX_2_2 area->vm_private_data = substream; -#else - area->vm_private_data = (long)substream; -#endif -#ifdef VM_RESERVED area->vm_flags |= VM_RESERVED; -#endif return 0; } -#ifndef LINUX_2_2 static struct page * snd_pcm_mmap_control_nopage(struct vm_area_struct *area, unsigned long address, int no_share) -#else -static unsigned long snd_pcm_mmap_control_nopage(struct vm_area_struct *area, unsigned long address, int no_share) -#endif { snd_pcm_substream_t *substream = (snd_pcm_substream_t *)area->vm_private_data; snd_pcm_runtime_t *runtime; @@ -2761,19 +2823,12 @@ runtime = substream->runtime; page = virt_to_page(runtime->control); get_page(page); -#ifndef LINUX_2_2 return page; -#else - return page_address(page); -#endif } static struct vm_operations_struct snd_pcm_vm_ops_control = { .nopage = snd_pcm_mmap_control_nopage, -#ifndef VM_RESERVED - .swapout = snd_pcm_mmap_swapout, -#endif }; static int snd_pcm_mmap_control(snd_pcm_substream_t *substream, struct file *file, @@ -2789,14 +2844,8 @@ if (size != PAGE_ALIGN(sizeof(snd_pcm_mmap_control_t))) return -EINVAL; area->vm_ops = &snd_pcm_vm_ops_control; -#ifndef LINUX_2_2 area->vm_private_data = substream; -#else - area->vm_private_data = (long)substream; -#endif -#ifdef VM_RESERVED area->vm_flags |= VM_RESERVED; -#endif return 0; } @@ -2812,11 +2861,7 @@ atomic_dec(&substream->runtime->mmap_count); } -#ifndef LINUX_2_2 static struct page * snd_pcm_mmap_data_nopage(struct vm_area_struct *area, unsigned long address, int no_share) -#else -static unsigned long snd_pcm_mmap_data_nopage(struct vm_area_struct *area, unsigned long address, int no_share) -#endif { snd_pcm_substream_t *substream = (snd_pcm_substream_t *)area->vm_private_data; snd_pcm_runtime_t *runtime; @@ -2828,11 +2873,7 @@ if (substream == NULL) return NOPAGE_OOM; runtime = substream->runtime; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 25) offset = area->vm_pgoff << PAGE_SHIFT; -#else - offset = area->vm_offset; -#endif offset += address - area->vm_start; snd_assert((offset % PAGE_SIZE) == 0, return NOPAGE_OOM); dma_bytes = PAGE_ALIGN(runtime->dma_bytes); @@ -2847,11 +2888,7 @@ page = virt_to_page(vaddr); } get_page(page); -#ifndef LINUX_2_2 return page; -#else - return page_address(page); -#endif } static struct vm_operations_struct snd_pcm_vm_ops_data = @@ -2859,9 +2896,6 @@ .open = snd_pcm_mmap_data_open, .close = snd_pcm_mmap_data_close, .nopage = snd_pcm_mmap_data_nopage, -#ifndef VM_RESERVED - .swapout = snd_pcm_mmap_swapout, -#endif }; int snd_pcm_mmap_data(snd_pcm_substream_t *substream, struct file *file, @@ -2889,11 +2923,7 @@ runtime->access == SNDRV_PCM_ACCESS_RW_NONINTERLEAVED) return -EINVAL; size = area->vm_end - area->vm_start; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 25) offset = area->vm_pgoff << PAGE_SHIFT; -#else - offset = area->vm_offset; -#endif dma_bytes = PAGE_ALIGN(runtime->dma_bytes); if ((size_t)size > dma_bytes) return -EINVAL; @@ -2901,14 +2931,8 @@ return -EINVAL; area->vm_ops = &snd_pcm_vm_ops_data; -#ifndef LINUX_2_2 area->vm_private_data = substream; -#else - area->vm_private_data = (long)substream; -#endif -#ifdef VM_RESERVED area->vm_flags |= VM_RESERVED; -#endif atomic_inc(&runtime->mmap_count); return 0; } @@ -2923,11 +2947,7 @@ substream = pcm_file->substream; snd_assert(substream != NULL, return -ENXIO); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 25) offset = area->vm_pgoff << PAGE_SHIFT; -#else - offset = area->vm_offset; -#endif switch (offset) { case SNDRV_PCM_MMAP_OFFSET_STATUS: return snd_pcm_mmap_status(substream, file, area); @@ -3035,13 +3055,9 @@ */ static struct file_operations snd_pcm_f_ops_playback = { -#ifndef LINUX_2_2 .owner = THIS_MODULE, -#endif .write = snd_pcm_write, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 44) .writev = snd_pcm_writev, -#endif .open = snd_pcm_open, .release = snd_pcm_release, .poll = snd_pcm_playback_poll, @@ -3051,13 +3067,9 @@ }; static struct file_operations snd_pcm_f_ops_capture = { -#ifndef LINUX_2_2 .owner = THIS_MODULE, -#endif .read = snd_pcm_read, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 44) .readv = snd_pcm_readv, -#endif .open = snd_pcm_open, .release = snd_pcm_release, .poll = snd_pcm_capture_poll, diff -Nru a/sound/core/rawmidi.c b/sound/core/rawmidi.c --- a/sound/core/rawmidi.c Mon Jun 9 23:16:07 2003 +++ b/sound/core/rawmidi.c Mon Jun 9 23:16:07 2003 @@ -1316,9 +1316,7 @@ static struct file_operations snd_rawmidi_f_ops = { -#ifndef LINUX_2_2 .owner = THIS_MODULE, -#endif .read = snd_rawmidi_read, .write = snd_rawmidi_write, .open = snd_rawmidi_open, diff -Nru a/sound/core/seq/Makefile b/sound/core/seq/Makefile --- a/sound/core/seq/Makefile Mon Jun 9 23:16:18 2003 +++ b/sound/core/seq/Makefile Mon Jun 9 23:16:18 2003 @@ -43,6 +43,7 @@ obj-$(call sequencer,$(CONFIG_SND_MPU401)) += $(RAWMIDI_OBJS) obj-$(call sequencer,$(CONFIG_SND_ALS100)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) obj-$(call sequencer,$(CONFIG_SND_AZT2320)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) +obj-$(call sequencer,$(CONFIG_SND_AZT3328)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) obj-$(call sequencer,$(CONFIG_SND_DT019X)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) obj-$(call sequencer,$(CONFIG_SND_ES18XX)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) obj-$(call sequencer,$(CONFIG_SND_OPL3SA2)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) @@ -65,6 +66,7 @@ obj-$(call sequencer,$(CONFIG_SND_SBAWE)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) snd-seq-virmidi.o obj-$(call sequencer,$(CONFIG_SND_ES968)) += $(RAWMIDI_OBJS) obj-$(call sequencer,$(CONFIG_SND_WAVEFRONT)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) +obj-$(call sequencer,$(CONFIG_SND_SSCAPE)) += $(RAWMIDI_OBJS) obj-$(call sequencer,$(CONFIG_SND_ALS4000)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) obj-$(call sequencer,$(CONFIG_SND_CMIPCI)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) obj-$(call sequencer,$(CONFIG_SND_CS4281)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) @@ -74,6 +76,7 @@ obj-$(call sequencer,$(CONFIG_SND_ES1968)) += $(RAWMIDI_OBJS) obj-$(call sequencer,$(CONFIG_SND_FM801)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) obj-$(call sequencer,$(CONFIG_SND_ICE1712)) += $(RAWMIDI_OBJS) +obj-$(call sequencer,$(CONFIG_SND_ICE1724)) += $(RAWMIDI_OBJS) obj-$(call sequencer,$(CONFIG_SND_INTEL8X0)) += $(RAWMIDI_OBJS) obj-$(call sequencer,$(CONFIG_SND_SONICVIBES)) += $(RAWMIDI_OBJS) $(OPL3_OBJS) obj-$(call sequencer,$(CONFIG_SND_VIA82XX)) += $(RAWMIDI_OBJS) diff -Nru a/sound/core/seq/instr/Makefile b/sound/core/seq/instr/Makefile --- a/sound/core/seq/instr/Makefile Mon Jun 9 23:16:17 2003 +++ b/sound/core/seq/instr/Makefile Mon Jun 9 23:16:17 2003 @@ -19,6 +19,7 @@ # Toplevel Module Dependency obj-$(call sequencer,$(CONFIG_SND_ALS100)) += snd-ainstr-fm.o obj-$(call sequencer,$(CONFIG_SND_AZT2320)) += snd-ainstr-fm.o +obj-$(call sequencer,$(CONFIG_SND_AZT3328)) += snd-ainstr-fm.o obj-$(call sequencer,$(CONFIG_SND_DT019X)) += snd-ainstr-fm.o obj-$(call sequencer,$(CONFIG_SND_ES18XX)) += snd-ainstr-fm.o obj-$(call sequencer,$(CONFIG_SND_OPL3SA2)) += snd-ainstr-fm.o diff -Nru a/sound/core/seq/oss/seq_oss.c b/sound/core/seq/oss/seq_oss.c --- a/sound/core/seq/oss/seq_oss.c Mon Jun 9 23:16:16 2003 +++ b/sound/core/seq/oss/seq_oss.c Mon Jun 9 23:16:16 2003 @@ -194,9 +194,7 @@ static struct file_operations seq_oss_f_ops = { -#ifndef LINUX_2_2 .owner = THIS_MODULE, -#endif .read = odev_read, .write = odev_write, .open = odev_open, diff -Nru a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c --- a/sound/core/seq/seq_clientmgr.c Mon Jun 9 23:16:07 2003 +++ b/sound/core/seq/seq_clientmgr.c Mon Jun 9 23:16:07 2003 @@ -2454,9 +2454,7 @@ static struct file_operations snd_seq_f_ops = { -#ifndef LINUX_2_2 .owner = THIS_MODULE, -#endif .read = snd_seq_read, .write = snd_seq_write, .open = snd_seq_open, diff -Nru a/sound/core/seq/seq_memory.c b/sound/core/seq/seq_memory.c --- a/sound/core/seq/seq_memory.c Mon Jun 9 23:16:07 2003 +++ b/sound/core/seq/seq_memory.c Mon Jun 9 23:16:07 2003 @@ -235,18 +235,7 @@ while (pool->free == NULL && ! nonblock && ! pool->closing) { spin_unlock(&pool->lock); -#ifdef LINUX_2_2 - /* change semaphore to allow other clients - to access device file */ - if (file) - up(&semaphore_of(file)); -#endif interruptible_sleep_on(&pool->output_sleep); -#ifdef LINUX_2_2 - /* restore semaphore again */ - if (file) - down(&semaphore_of(file)); -#endif spin_lock(&pool->lock); /* interrupted? */ if (signal_pending(current)) { diff -Nru a/sound/core/sgbuf.c b/sound/core/sgbuf.c --- a/sound/core/sgbuf.c Mon Jun 9 23:16:15 2003 +++ b/sound/core/sgbuf.c Mon Jun 9 23:16:15 2003 @@ -20,7 +20,6 @@ */ #include <linux/config.h> -#include <linux/version.h> #include <linux/pci.h> #include <linux/slab.h> #include <linux/mm.h> diff -Nru a/sound/core/sound.c b/sound/core/sound.c --- a/sound/core/sound.c Mon Jun 9 23:16:15 2003 +++ b/sound/core/sound.c Mon Jun 9 23:16:15 2003 @@ -35,11 +35,12 @@ #define SNDRV_OS_MINORS 256 -int major = CONFIG_SND_MAJOR; +static int major = CONFIG_SND_MAJOR; +int snd_major; static int cards_limit = SNDRV_CARDS; -int device_mode = S_IFCHR | S_IRUGO | S_IWUGO; -int device_gid = 0; -int device_uid = 0; +#ifdef CONFIG_DEVFS_FS +static int device_mode = S_IFCHR | S_IRUGO | S_IWUGO; +#endif MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); MODULE_DESCRIPTION("Advanced Linux Sound Architecture driver for soundcards."); @@ -52,15 +53,11 @@ MODULE_PARM(cards_limit, "i"); MODULE_PARM_DESC(cards_limit, "Count of soundcards installed in the system."); MODULE_PARM_SYNTAX(cards_limit, "default:8,skill:advanced"); +#ifdef CONFIG_DEVFS_FS MODULE_PARM(device_mode, "i"); -MODULE_PARM_DESC(device_mode, "Device file permission mask for sound dynamic device filesystem."); +MODULE_PARM_DESC(device_mode, "Device file permission mask for devfs."); MODULE_PARM_SYNTAX(device_mode, "default:0666,base:8"); -MODULE_PARM(device_gid, "i"); -MODULE_PARM_DESC(device_gid, "Device file GID for sound dynamic device filesystem."); -MODULE_PARM_SYNTAX(device_gid, "default:0"); -MODULE_PARM(device_uid, "i"); -MODULE_PARM_DESC(device_uid, "Device file UID for sound dynamic device filesystem."); -MODULE_PARM_SYNTAX(device_uid, "default:0"); +#endif int snd_ecards_limit; @@ -157,9 +154,7 @@ struct file_operations snd_fops = { -#ifndef LINUX_2_2 .owner = THIS_MODULE, -#endif .open = snd_open }; @@ -210,22 +205,25 @@ if (minor < 0) return minor; - preg = (snd_minor_t *)kmalloc(sizeof(snd_minor_t), GFP_KERNEL); + snd_assert(name, return -EINVAL); + preg = (snd_minor_t *)kmalloc(sizeof(snd_minor_t) + strlen(name) + 1, GFP_KERNEL); if (preg == NULL) return -ENOMEM; *preg = *reg; preg->number = minor; preg->device = dev; - preg->dev = NULL; + strcpy(preg->name, name); down(&sound_mutex); if (snd_minor_search(minor)) { up(&sound_mutex); kfree(preg); return -EBUSY; } - if (name) - preg->dev = snd_info_create_device(name, minor, 0); list_add_tail(&preg->list, &snd_minors_hash[SNDRV_MINOR_CARD(minor)]); +#ifdef CONFIG_DEVFS_FS + if (strncmp(name, "controlC", 8)) /* created in sound.c */ + devfs_mk_cdev(MKDEV(major, minor), S_IFCHR | device_mode, "snd/%s", name); +#endif up(&sound_mutex); return 0; } @@ -253,8 +251,10 @@ up(&sound_mutex); return -EINVAL; } - if (mptr->dev) - snd_info_free_device(mptr->dev); +#ifdef CONFIG_DEVFS_FS + if (strncmp(mptr->name, "controlC", 8)) /* created in sound.c */ + devfs_remove("snd/%s", mptr->name); +#endif list_del(&mptr->list); up(&sound_mutex); kfree(mptr); @@ -321,10 +321,15 @@ static int __init alsa_sound_init(void) { +#ifdef CONFIG_DEVFS_FS short controlnum; - int err = 0; +#endif +#ifdef CONFIG_SND_OSSEMUL + int err; +#endif int card; + snd_major = major; snd_ecards_limit = cards_limit; for (card = 0; card < SNDRV_CARDS; card++) INIT_LIST_HEAD(&snd_minors_hash[card]); @@ -335,6 +340,7 @@ devfs_mk_dir("snd"); if (register_chrdev(major, "alsa", &snd_fops)) { snd_printk(KERN_ERR "unable to register native major device number %d\n", major); + devfs_remove("snd"); return -EIO; } #ifdef CONFIG_SND_DEBUG_MEMORY @@ -344,24 +350,21 @@ #ifdef CONFIG_SND_DEBUG_MEMORY snd_memory_done(); #endif + unregister_chrdev(major, "alsa"); + devfs_remove("snd"); return -ENOMEM; } #ifdef CONFIG_SND_OSSEMUL snd_info_minor_register(); #endif - - for (controlnum = 0; controlnum < cards_limit; controlnum++) { - devfs_mk_cdev(MKDEV(major, controlnum<<5), - device_mode | S_IFCHR, "snd/controlC%d", controlnum); - } - +#ifdef CONFIG_DEVFS_FS + for (controlnum = 0; controlnum < cards_limit; controlnum++) + devfs_mk_cdev(MKDEV(major, controlnum<<5), S_IFCHR | device_mode, "snd/controlC%d", controlnum); +#endif #ifndef MODULE printk(KERN_INFO "Advanced Linux Sound Architecture Driver Version " CONFIG_SND_VERSION CONFIG_SND_DATE ".\n"); #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) && defined(CONFIG_APM) - pm_init(); -#endif - return err; + return 0; } static void __exit alsa_sound_exit(void) @@ -375,9 +378,6 @@ snd_info_minor_unregister(); #endif snd_info_done(); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) && defined(CONFIG_APM) - pm_done(); -#endif #ifdef CONFIG_SND_DEBUG_MEMORY snd_memory_done(); #endif @@ -390,6 +390,7 @@ module_exit(alsa_sound_exit) /* sound.c */ +EXPORT_SYMBOL(snd_major); EXPORT_SYMBOL(snd_ecards_limit); #if defined(CONFIG_KMOD) EXPORT_SYMBOL(snd_request_card); @@ -453,8 +454,6 @@ EXPORT_SYMBOL(snd_info_create_module_entry); EXPORT_SYMBOL(snd_info_create_card_entry); EXPORT_SYMBOL(snd_info_free_entry); -EXPORT_SYMBOL(snd_info_create_device); -EXPORT_SYMBOL(snd_info_free_device); EXPORT_SYMBOL(snd_info_register); EXPORT_SYMBOL(snd_info_unregister); EXPORT_SYMBOL(snd_card_proc_new); diff -Nru a/sound/core/sound_oss.c b/sound/core/sound_oss.c --- a/sound/core/sound_oss.c Mon Jun 9 23:16:19 2003 +++ b/sound/core/sound_oss.c Mon Jun 9 23:16:19 2003 @@ -107,7 +107,6 @@ *preg = *reg; preg->number = minor; preg->device = dev; - preg->dev = NULL; down(&sound_oss_mutex); list_add_tail(&preg->list, &snd_oss_minors_hash[cidx]); minor_unit = SNDRV_MINOR_OSS_DEVICE(minor); diff -Nru a/sound/core/timer.c b/sound/core/timer.c --- a/sound/core/timer.c Mon Jun 9 23:16:14 2003 +++ b/sound/core/timer.c Mon Jun 9 23:16:14 2003 @@ -1733,9 +1733,7 @@ static struct file_operations snd_timer_f_ops = { -#ifndef LINUX_2_2 .owner = THIS_MODULE, -#endif .read = snd_timer_user_read, .open = snd_timer_user_open, .release = snd_timer_user_release, diff -Nru a/sound/drivers/Makefile b/sound/drivers/Makefile --- a/sound/drivers/Makefile Mon Jun 9 23:16:15 2003 +++ b/sound/drivers/Makefile Mon Jun 9 23:16:15 2003 @@ -14,4 +14,4 @@ obj-$(CONFIG_SND_SERIAL_U16550) += snd-serial-u16550.o obj-$(CONFIG_SND_MTPAV) += snd-mtpav.o -obj-$(CONFIG_SND) += opl3/ mpu401/ +obj-$(CONFIG_SND) += opl3/ opl4/ mpu401/ vx/ diff -Nru a/sound/drivers/dummy.c b/sound/drivers/dummy.c --- a/sound/drivers/dummy.c Mon Jun 9 23:16:18 2003 +++ b/sound/drivers/dummy.c Mon Jun 9 23:16:18 2003 @@ -21,11 +21,7 @@ #include <sound/driver.h> #include <linux/version.h> #include <linux/init.h> -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) #include <linux/jiffies.h> -#else -#include <linux/sched.h> -#endif #include <linux/slab.h> #include <linux/time.h> #include <linux/wait.h> @@ -58,8 +54,8 @@ #if 0 /* ICE1712 emulation */ #define MAX_BUFFER_SIZE (256 * 1024) #define USE_FORMATS SNDRV_PCM_FMTBIT_S32_LE -#define USE_CHANNELS_MIN 12 -#define USE_CHANNELS_MAX 12 +#define USE_CHANNELS_MIN 10 +#define USE_CHANNELS_MAX 10 #define USE_PERIODS_MIN 1 #define USE_PERIODS_MAX 1024 #endif @@ -247,8 +243,8 @@ dpcm->pcm_irq_pos += dpcm->pcm_jiffie; dpcm->pcm_buf_pos += dpcm->pcm_jiffie; dpcm->pcm_buf_pos %= dpcm->pcm_size; - while (dpcm->pcm_irq_pos >= dpcm->pcm_count) { - dpcm->pcm_irq_pos -= dpcm->pcm_count; + if (dpcm->pcm_irq_pos >= dpcm->pcm_count) { + dpcm->pcm_irq_pos %= dpcm->pcm_count; snd_pcm_period_elapsed(dpcm->substream); } spin_unlock_irq(&dpcm->lock); @@ -430,7 +426,7 @@ { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 2; - uinfo->value.integer.min = 0; + uinfo->value.integer.min = -50; uinfo->value.integer.max = 100; return 0; } @@ -455,8 +451,16 @@ int change, addr = kcontrol->private_value; int left, right; - left = ucontrol->value.integer.value[0] % 101; - right = ucontrol->value.integer.value[1] % 101; + left = ucontrol->value.integer.value[0]; + if (left < -50) + left = -50; + if (left > 100) + left = 100; + right = ucontrol->value.integer.value[1]; + if (right < -50) + right = -50; + if (right > 100) + right = 100; spin_lock_irqsave(&dummy->mixer_lock, flags); change = dummy->mixer_volume[addr][0] != left || dummy->mixer_volume[addr][1] != right; diff -Nru a/sound/drivers/mpu401/Makefile b/sound/drivers/mpu401/Makefile --- a/sound/drivers/mpu401/Makefile Mon Jun 9 23:16:20 2003 +++ b/sound/drivers/mpu401/Makefile Mon Jun 9 23:16:20 2003 @@ -10,6 +10,7 @@ obj-$(CONFIG_SND_MPU401) += snd-mpu401.o snd-mpu401-uart.o obj-$(CONFIG_SND_ALS100) += snd-mpu401-uart.o obj-$(CONFIG_SND_AZT2320) += snd-mpu401-uart.o +obj-$(CONFIG_SND_AZT3328) += snd-mpu401-uart.o obj-$(CONFIG_SND_DT019X) += snd-mpu401-uart.o obj-$(CONFIG_SND_ES18XX) += snd-mpu401-uart.o obj-$(CONFIG_SND_OPL3SA2) += snd-mpu401-uart.o @@ -31,6 +32,7 @@ obj-$(CONFIG_SND_ES1968) += snd-mpu401-uart.o obj-$(CONFIG_SND_FM801) += snd-mpu401-uart.o obj-$(CONFIG_SND_ICE1712) += snd-mpu401-uart.o +obj-$(CONFIG_SND_ICE1724) += snd-mpu401-uart.o obj-$(CONFIG_SND_INTEL8X0) += snd-mpu401-uart.o obj-$(CONFIG_SND_SONICVIBES) += snd-mpu401-uart.o obj-$(CONFIG_SND_VIA82XX) += snd-mpu401-uart.o @@ -38,5 +40,6 @@ obj-$(CONFIG_SND_TRIDENT) += snd-mpu401-uart.o obj-$(CONFIG_SND_YMFPCI) += snd-mpu401-uart.o obj-$(CONFIG_SND_PC98_CS4232) += snd-mpu401-uart.o +obj-$(CONFIG_SND_SSCAPE) += snd-mpu401-uart.o obj-m := $(sort $(obj-m)) diff -Nru a/sound/drivers/mpu401/mpu401_uart.c b/sound/drivers/mpu401/mpu401_uart.c --- a/sound/drivers/mpu401/mpu401_uart.c Mon Jun 9 23:16:10 2003 +++ b/sound/drivers/mpu401/mpu401_uart.c Mon Jun 9 23:16:10 2003 @@ -90,27 +90,27 @@ #endif } -static irqreturn_t _snd_mpu401_uart_interrupt(mpu401_t *mpu) +static void _snd_mpu401_uart_interrupt(mpu401_t *mpu) { + spin_lock(&mpu->input_lock); if (test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode)) { - if (! test_and_set_bit(MPU401_MODE_BIT_RX_LOOP, &mpu->mode)) { - spin_lock(&mpu->input_lock); - snd_mpu401_uart_input_read(mpu); - spin_unlock(&mpu->input_lock); - clear_bit(MPU401_MODE_BIT_RX_LOOP, &mpu->mode); - } - } else + atomic_dec(&mpu->rx_loop); + snd_mpu401_uart_input_read(mpu); + atomic_inc(&mpu->rx_loop); + } else { snd_mpu401_uart_clear_rx(mpu); + } + spin_unlock(&mpu->input_lock); /* ok. for better Tx performance try do some output when input is done */ if (test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode) && test_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode)) { - spin_lock(&mpu->output_lock); - snd_mpu401_uart_output_write(mpu); - spin_unlock(&mpu->output_lock); + if (spin_trylock(&mpu->output_lock)) { + atomic_dec(&mpu->tx_loop); + snd_mpu401_uart_output_write(mpu); + atomic_inc(&mpu->tx_loop); + spin_unlock(&mpu->output_lock); + } } - - /* FIXME! This should really check whether the irq was for us */ - return IRQ_HANDLED; } /** @@ -127,7 +127,8 @@ if (mpu == NULL) return IRQ_NONE; - return _snd_mpu401_uart_interrupt(mpu); + _snd_mpu401_uart_interrupt(mpu); + return IRQ_HANDLED; } /* @@ -242,6 +243,7 @@ snd_mpu401_uart_cmd(mpu, MPU401_ENTER_UART, 1); } mpu->substream_input = substream; + atomic_set(&mpu->rx_loop, 1); set_bit(MPU401_MODE_BIT_INPUT, &mpu->mode); return 0; } @@ -259,6 +261,7 @@ snd_mpu401_uart_cmd(mpu, MPU401_ENTER_UART, 1); } mpu->substream_output = substream; + atomic_set(&mpu->tx_loop, 1); set_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode); return 0; } @@ -312,12 +315,15 @@ /* read data in advance */ /* prevent double enter via rawmidi->event callback */ - if (! test_and_set_bit(MPU401_MODE_BIT_RX_LOOP, &mpu->mode)) { - spin_lock_irqsave(&mpu->input_lock, flags); - snd_mpu401_uart_input_read(mpu); - spin_unlock_irqrestore(&mpu->input_lock, flags); - clear_bit(MPU401_MODE_BIT_RX_LOOP, &mpu->mode); + if (atomic_dec_and_test(&mpu->rx_loop)) { + local_irq_save(flags); + if (spin_trylock(&mpu->input_lock)) { + snd_mpu401_uart_input_read(mpu); + spin_unlock(&mpu->input_lock); + } + local_irq_restore(flags); } + atomic_inc(&mpu->rx_loop); } else { if (mpu->irq < 0) snd_mpu401_uart_remove_timer(mpu, 1); @@ -371,9 +377,11 @@ break; } } + if (timeout == 0) + break; /* Tx FIFO full - try again later */ } else { snd_mpu401_uart_remove_timer (mpu, 0); - max = 1; /* no other data - leave the tx loop */ + break; /* no other data - leave the tx loop */ } } while (--max > 0); } @@ -389,6 +397,7 @@ mpu = snd_magic_cast(mpu401_t, substream->rmidi->private_data, return); if (up) { set_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode); + /* try to add the timer at each output trigger, * since the output timer might have been removed in * snd_mpu401_uart_output_write(). @@ -397,12 +406,15 @@ /* output pending data */ /* prevent double enter via rawmidi->event callback */ - if (! test_and_set_bit(MPU401_MODE_BIT_TX_LOOP, &mpu->mode)) { - spin_lock_irqsave(&mpu->output_lock, flags); - snd_mpu401_uart_output_write(mpu); - spin_unlock_irqrestore(&mpu->output_lock, flags); - clear_bit(MPU401_MODE_BIT_TX_LOOP, &mpu->mode); + if (atomic_dec_and_test(&mpu->tx_loop)) { + local_irq_save(flags); + if (spin_trylock(&mpu->output_lock)) { + snd_mpu401_uart_output_write(mpu); + spin_unlock(&mpu->output_lock); + } + local_irq_restore(flags); } + atomic_inc(&mpu->tx_loop); } else { snd_mpu401_uart_remove_timer(mpu, 0); clear_bit(MPU401_MODE_BIT_OUTPUT_TRIGGER, &mpu->mode); diff -Nru a/sound/drivers/opl3/Makefile b/sound/drivers/opl3/Makefile --- a/sound/drivers/opl3/Makefile Mon Jun 9 23:16:05 2003 +++ b/sound/drivers/opl3/Makefile Mon Jun 9 23:16:05 2003 @@ -4,12 +4,10 @@ # snd-opl3-lib-objs := opl3_lib.o opl3_synth.o -ifeq ($(subst m,y,$(CONFIG_SND_SEQUENCER)),y) snd-opl3-synth-objs := opl3_seq.o opl3_midi.o opl3_drums.o ifeq ($(CONFIG_SND_SEQUENCER_OSS),y) snd-opl3-synth-objs += opl3_oss.o endif -endif OPL3_OBJS = snd-opl3-lib.o ifeq ($(subst m,y,$(CONFIG_SND_SEQUENCER)),y) @@ -19,6 +17,7 @@ # Toplevel Module Dependency obj-$(CONFIG_SND_ALS100) += $(OPL3_OBJS) obj-$(CONFIG_SND_AZT2320) += $(OPL3_OBJS) +obj-$(CONFIG_SND_AZT3328) += $(OPL3_OBJS) obj-$(CONFIG_SND_DT019X) += $(OPL3_OBJS) obj-$(CONFIG_SND_ES18XX) += $(OPL3_OBJS) obj-$(CONFIG_SND_OPL3SA2) += $(OPL3_OBJS) diff -Nru a/sound/drivers/opl3/opl3_lib.c b/sound/drivers/opl3/opl3_lib.c --- a/sound/drivers/opl3/opl3_lib.c Mon Jun 9 23:16:08 2003 +++ b/sound/drivers/opl3/opl3_lib.c Mon Jun 9 23:16:08 2003 @@ -160,17 +160,11 @@ opl3->hardware = OPL3_HW_OPL2; } else { /* - * Detect availability of OPL4. Unfortunately, the OPL4 - * port of the chip may not be connected to the PC bus. + * If we had an OPL4 chip, opl3->hardware would have been set + * by the OPL4 driver; so we can assume OPL3 here. */ snd_assert(opl3->r_port != 0, return -ENODEV); - opl3->command(opl3, OPL3_RIGHT | OPL3_REG_MODE, OPL3_OPL3_ENABLE | OPL3_OPL4_ENABLE); - /* All OPL4 registers are readable. */ - if (inb(opl3->r_port + 1) == (OPL3_OPL3_ENABLE | OPL3_OPL4_ENABLE)) { - opl3->hardware = OPL3_HW_OPL4; - } else { - opl3->hardware = OPL3_HW_OPL3; - } + opl3->hardware = OPL3_HW_OPL3; } return 0; } diff -Nru a/sound/drivers/opl4/Makefile b/sound/drivers/opl4/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/drivers/opl4/Makefile Mon Jun 9 23:16:20 2003 @@ -0,0 +1,15 @@ +# +# Makefile for ALSA +# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz> +# + +snd-opl4-lib-objs := opl4_lib.o opl4_mixer.o opl4_proc.o +snd-opl4-synth-objs := opl4_seq.o opl4_synth.o yrw801.o + +OPL4_OBJS := snd-opl4-lib.o +ifeq ($(subst m,y,$(CONFIG_SND_SEQUENCER)),y) + OPL4_OBJS += snd-opl4-synth.o +endif + +obj-$(CONFIG_SND_OPTI92X_AD1848) += $(OPL4_OBJS) +obj-$(CONFIG_SND_OPTI92X_CS4231) += $(OPL4_OBJS) diff -Nru a/sound/drivers/opl4/opl4_lib.c b/sound/drivers/opl4/opl4_lib.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/drivers/opl4/opl4_lib.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,275 @@ +/* + * Functions for accessing OPL4 devices + * Copyright (c) 2003 by Clemens Ladisch <clemens@ladisch.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "opl4_local.h" +#include <sound/initval.h> +#include <linux/ioport.h> +#include <asm/io.h> + +MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); +MODULE_DESCRIPTION("OPL4 driver"); +MODULE_LICENSE("GPL"); +MODULE_CLASSES("{sound}"); + +static void inline snd_opl4_wait(opl4_t *opl4) +{ + int timeout = 10; + while ((inb(opl4->fm_port) & OPL4_STATUS_BUSY) && --timeout > 0) + ; +} + +void snd_opl4_write(opl4_t *opl4, u8 reg, u8 value) +{ + unsigned long flags; + + spin_lock_irqsave(&opl4->reg_lock, flags); + + snd_opl4_wait(opl4); + outb(reg, opl4->pcm_port); + + snd_opl4_wait(opl4); + outb(value, opl4->pcm_port + 1); + + spin_unlock_irqrestore(&opl4->reg_lock, flags); +} + +u8 snd_opl4_read(opl4_t *opl4, u8 reg) +{ + unsigned long flags; + u8 value; + + spin_lock_irqsave(&opl4->reg_lock, flags); + + snd_opl4_wait(opl4); + outb(reg, opl4->pcm_port); + + snd_opl4_wait(opl4); + value = inb(opl4->pcm_port + 1); + + spin_unlock_irqrestore(&opl4->reg_lock, flags); + return value; +} + +void snd_opl4_read_memory(opl4_t *opl4, char *buf, int offset, int size) +{ + u8 memcfg = snd_opl4_read(opl4, OPL4_REG_MEMORY_CONFIGURATION); + snd_opl4_write(opl4, OPL4_REG_MEMORY_CONFIGURATION, memcfg | OPL4_MODE_BIT); + + snd_opl4_write(opl4, OPL4_REG_MEMORY_ADDRESS_HIGH, offset >> 16); + snd_opl4_write(opl4, OPL4_REG_MEMORY_ADDRESS_MID, offset >> 8); + snd_opl4_write(opl4, OPL4_REG_MEMORY_ADDRESS_LOW, offset); + for (; size > 0; size--) + *buf++ = snd_opl4_read(opl4, OPL4_REG_MEMORY_DATA); + + snd_opl4_write(opl4, OPL4_REG_MEMORY_CONFIGURATION, memcfg); +} + +void snd_opl4_write_memory(opl4_t *opl4, const char *buf, int offset, int size) +{ + u8 memcfg = snd_opl4_read(opl4, OPL4_REG_MEMORY_CONFIGURATION); + snd_opl4_write(opl4, OPL4_REG_MEMORY_CONFIGURATION, memcfg | OPL4_MODE_BIT); + + snd_opl4_write(opl4, OPL4_REG_MEMORY_ADDRESS_HIGH, offset >> 16); + snd_opl4_write(opl4, OPL4_REG_MEMORY_ADDRESS_MID, offset >> 8); + snd_opl4_write(opl4, OPL4_REG_MEMORY_ADDRESS_LOW, offset); + for (; size > 0; size--) + snd_opl4_write(opl4, OPL4_REG_MEMORY_DATA, *buf++); + + snd_opl4_write(opl4, OPL4_REG_MEMORY_CONFIGURATION, memcfg); +} + +static void snd_opl4_enable_opl4(opl4_t *opl4) +{ + outb(OPL3_REG_MODE, opl4->fm_port + 2); + inb(opl4->fm_port); + inb(opl4->fm_port); + outb(OPL3_OPL3_ENABLE | OPL3_OPL4_ENABLE, opl4->fm_port + 3); + inb(opl4->fm_port); + inb(opl4->fm_port); +} + +static int snd_opl4_detect(opl4_t *opl4) +{ + u8 id1, id2; + + snd_opl4_enable_opl4(opl4); + + id1 = snd_opl4_read(opl4, OPL4_REG_MEMORY_CONFIGURATION); + snd_printdd("OPL4[02]=%02x\n", id1); + switch (id1 & OPL4_DEVICE_ID_MASK) { + case 0x20: + opl4->hardware = OPL3_HW_OPL4; + break; + case 0x40: + opl4->hardware = OPL3_HW_OPL4_ML; + break; + default: + return -ENODEV; + } + + snd_opl4_write(opl4, OPL4_REG_MIX_CONTROL_FM, 0x00); + snd_opl4_write(opl4, OPL4_REG_MIX_CONTROL_PCM, 0xff); + id1 = snd_opl4_read(opl4, OPL4_REG_MIX_CONTROL_FM); + id2 = snd_opl4_read(opl4, OPL4_REG_MIX_CONTROL_PCM); + snd_printdd("OPL4 id1=%02x id2=%02x\n", id1, id2); + if (id1 != 0x00 || id2 != 0xff) + return -ENODEV; + + snd_opl4_write(opl4, OPL4_REG_MIX_CONTROL_FM, 0x3f); + snd_opl4_write(opl4, OPL4_REG_MIX_CONTROL_PCM, 0x3f); + snd_opl4_write(opl4, OPL4_REG_MEMORY_CONFIGURATION, 0x00); + return 0; +} + +#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE) +static void snd_opl4_seq_dev_free(snd_seq_device_t *seq_dev) +{ + opl4_t *opl4 = snd_magic_cast(opl4_t, seq_dev->private_data, return); + opl4->seq_dev = NULL; +} + +static int snd_opl4_create_seq_dev(opl4_t *opl4, int seq_device) +{ + opl4->seq_dev_num = seq_device; + if (snd_seq_device_new(opl4->card, seq_device, SNDRV_SEQ_DEV_ID_OPL4, + sizeof(opl4_t *), &opl4->seq_dev) >= 0) { + strcpy(opl4->seq_dev->name, "OPL4 Wavetable"); + *(opl4_t **)SNDRV_SEQ_DEVICE_ARGPTR(opl4->seq_dev) = opl4; + opl4->seq_dev->private_data = opl4; + opl4->seq_dev->private_free = snd_opl4_seq_dev_free; + } + return 0; +} +#endif + +static void snd_opl4_free(opl4_t *opl4) +{ +#ifdef CONFIG_PROC_FS + snd_opl4_free_proc(opl4); +#endif + if (opl4->res_fm_port) { + release_resource(opl4->res_fm_port); + kfree_nocheck(opl4->res_fm_port); + } + if (opl4->res_pcm_port) { + release_resource(opl4->res_pcm_port); + kfree_nocheck(opl4->res_pcm_port); + } + snd_magic_kfree(opl4); +} + +static int snd_opl4_dev_free(snd_device_t *device) +{ + opl4_t *opl4 = snd_magic_cast(opl4_t, device->device_data, return -ENXIO); + snd_opl4_free(opl4); + return 0; +} + +int snd_opl4_create(snd_card_t *card, + unsigned long fm_port, unsigned long pcm_port, + int seq_device, + opl3_t **ropl3, opl4_t **ropl4) +{ + opl4_t *opl4; + opl3_t *opl3; + int err; + static snd_device_ops_t ops = { + .dev_free = snd_opl4_dev_free + }; + + if (ropl3) + *ropl3 = NULL; + if (ropl4) + *ropl4 = NULL; + + opl4 = snd_magic_kcalloc(opl4_t, 0, GFP_KERNEL); + if (!opl4) + return -ENOMEM; + + opl4->res_fm_port = request_region(fm_port, 8, "OPL4 FM"); + opl4->res_pcm_port = request_region(pcm_port, 8, "OPL4 PCM/MIX"); + if (!opl4->res_fm_port || !opl4->res_pcm_port) { + snd_opl4_free(opl4); + return -EBUSY; + } + + opl4->card = card; + opl4->fm_port = fm_port; + opl4->pcm_port = pcm_port; + spin_lock_init(&opl4->reg_lock); + init_MUTEX(&opl4->access_mutex); + + err = snd_opl4_detect(opl4); + if (err < 0) { + snd_opl4_free(opl4); + snd_printd("OPL4 chip not detected at %#lx/%#lx\n", fm_port, pcm_port); + return err; + } + + err = snd_opl3_create(card, fm_port, fm_port + 2, opl4->hardware, 1, &opl3); + if (err < 0) { + snd_opl4_free(opl4); + return err; + } + + /* opl3 initialization disabled opl4, so reenable */ + snd_opl4_enable_opl4(opl4); + + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, opl4, &ops); + if (err < 0) { + snd_device_free(card, opl3); + snd_opl4_free(opl4); + return err; + } + + snd_opl4_create_mixer(opl4); +#ifdef CONFIG_PROC_FS + snd_opl4_create_proc(opl4); +#endif + +#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE) + opl4->seq_client = -1; + if (opl4->hardware < OPL3_HW_OPL4_ML) + snd_opl4_create_seq_dev(opl4, seq_device); +#endif + + if (ropl3) + *ropl3 = opl3; + if (ropl4) + *ropl4 = opl4; + return 0; +} + +EXPORT_SYMBOL(snd_opl4_write); +EXPORT_SYMBOL(snd_opl4_read); +EXPORT_SYMBOL(snd_opl4_write_memory); +EXPORT_SYMBOL(snd_opl4_read_memory); +EXPORT_SYMBOL(snd_opl4_create); + +static int __init alsa_opl4_init(void) +{ + return 0; +} + +static void __exit alsa_opl4_exit(void) +{ +} + +module_init(alsa_opl4_init) +module_exit(alsa_opl4_exit) diff -Nru a/sound/drivers/opl4/opl4_local.h b/sound/drivers/opl4/opl4_local.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/drivers/opl4/opl4_local.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,231 @@ +/* + * Local definitions for the OPL4 driver + * + * Copyright (c) 2003 by Clemens Ladisch <clemens@ladisch.de> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed and/or modified under the + * terms of the 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 BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + */ + +#ifndef __OPL4_LOCAL_H +#define __OPL4_LOCAL_H + +#include <sound/opl4.h> + +/* + * Register numbers + */ + +#define OPL4_REG_TEST0 0x00 +#define OPL4_REG_TEST1 0x01 + +#define OPL4_REG_MEMORY_CONFIGURATION 0x02 +#define OPL4_MODE_BIT 0x01 +#define OPL4_MTYPE_BIT 0x02 +#define OPL4_TONE_HEADER_MASK 0x1c +#define OPL4_DEVICE_ID_MASK 0xe0 + +#define OPL4_REG_MEMORY_ADDRESS_HIGH 0x03 +#define OPL4_REG_MEMORY_ADDRESS_MID 0x04 +#define OPL4_REG_MEMORY_ADDRESS_LOW 0x05 +#define OPL4_REG_MEMORY_DATA 0x06 + +/* + * Offsets to the register banks for voices. To get the + * register number just add the voice number to the bank offset. + * + * Wave Table Number low bits (0x08 to 0x1F) + */ +#define OPL4_REG_TONE_NUMBER 0x08 + +/* Wave Table Number high bit, F-Number low bits (0x20 to 0x37) */ +#define OPL4_REG_F_NUMBER 0x20 +#define OPL4_TONE_NUMBER_BIT8 0x01 +#define OPL4_F_NUMBER_LOW_MASK 0xfe + +/* F-Number high bits, Octave, Pseudo-Reverb (0x38 to 0x4F) */ +#define OPL4_REG_OCTAVE 0x38 +#define OPL4_F_NUMBER_HIGH_MASK 0x07 +#define OPL4_BLOCK_MASK 0xf0 +#define OPL4_PSEUDO_REVERB_BIT 0x08 + +/* Total Level, Level Direct (0x50 to 0x67) */ +#define OPL4_REG_LEVEL 0x50 +#define OPL4_TOTAL_LEVEL_MASK 0xfe +#define OPL4_LEVEL_DIRECT_BIT 0x01 + +/* Key On, Damp, LFO RST, CH, Panpot (0x68 to 0x7F) */ +#define OPL4_REG_MISC 0x68 +#define OPL4_KEY_ON_BIT 0x80 +#define OPL4_DAMP_BIT 0x40 +#define OPL4_LFO_RESET_BIT 0x20 +#define OPL4_OUTPUT_CHANNEL_BIT 0x10 +#define OPL4_PAN_POT_MASK 0x0f + +/* LFO, VIB (0x80 to 0x97) */ +#define OPL4_REG_LFO_VIBRATO 0x80 +#define OPL4_LFO_FREQUENCY_MASK 0x38 +#define OPL4_VIBRATO_DEPTH_MASK 0x07 +#define OPL4_CHORUS_SEND_MASK 0xc0 /* ML only */ + +/* Attack / Decay 1 rate (0x98 to 0xAF) */ +#define OPL4_REG_ATTACK_DECAY1 0x98 +#define OPL4_ATTACK_RATE_MASK 0xf0 +#define OPL4_DECAY1_RATE_MASK 0x0f + +/* Decay level / 2 rate (0xB0 to 0xC7) */ +#define OPL4_REG_LEVEL_DECAY2 0xb0 +#define OPL4_DECAY_LEVEL_MASK 0xf0 +#define OPL4_DECAY2_RATE_MASK 0x0f + +/* Release rate / Rate correction (0xC8 to 0xDF) */ +#define OPL4_REG_RELEASE_CORRECTION 0xc8 +#define OPL4_RELEASE_RATE_MASK 0x0f +#define OPL4_RATE_INTERPOLATION_MASK 0xf0 + +/* AM (0xE0 to 0xF7) */ +#define OPL4_REG_TREMOLO 0xe0 +#define OPL4_TREMOLO_DEPTH_MASK 0x07 +#define OPL4_REVERB_SEND_MASK 0xe0 /* ML only */ + +/* Mixer */ +#define OPL4_REG_MIX_CONTROL_FM 0xf8 +#define OPL4_REG_MIX_CONTROL_PCM 0xf9 +#define OPL4_MIX_LEFT_MASK 0x07 +#define OPL4_MIX_RIGHT_MASK 0x38 + +#define OPL4_REG_ATC 0xfa +#define OPL4_ATC_BIT 0x01 /* ???, ML only */ + +/* bits in the OPL3 Status register */ +#define OPL4_STATUS_BUSY 0x01 +#define OPL4_STATUS_LOAD 0x02 + + +#define OPL4_MAX_VOICES 24 + +#define SNDRV_SEQ_DEV_ID_OPL4 "opl4-synth" + + +typedef struct opl4_sound { + u16 tone; + s16 pitch_offset; + u8 key_scaling; + s8 panpot; + u8 vibrato; + u8 tone_attenuate; + u8 volume_factor; + u8 reg_lfo_vibrato; + u8 reg_attack_decay1; + u8 reg_level_decay2; + u8 reg_release_correction; + u8 reg_tremolo; +} opl4_sound_t; + +typedef struct opl4_region { + u8 key_min, key_max; + opl4_sound_t sound; +} opl4_region_t; + +typedef struct opl4_region_ptr { + int count; + const opl4_region_t *regions; +} opl4_region_ptr_t; + +typedef struct opl4_voice { + struct list_head list; + int number; + snd_midi_channel_t *chan; + int note; + int velocity; + const opl4_sound_t *sound; + u8 reg_f_number; + u8 reg_misc; +} opl4_voice_t; + +struct opl4 { + unsigned long fm_port; + unsigned long pcm_port; + struct resource *res_fm_port; + struct resource *res_pcm_port; + unsigned short hardware; + spinlock_t reg_lock; + snd_card_t *card; + +#ifdef CONFIG_PROC_FS + snd_info_entry_t *proc_entry; + int memory_access; +#endif + struct semaphore access_mutex; + +#if defined(CONFIG_SND_SEQUENCER) || defined(CONFIG_SND_SEQUENCER_MODULE) + int used; + + int seq_dev_num; + int seq_client; + snd_seq_device_t *seq_dev; + + snd_midi_channel_set_t *chset; + opl4_voice_t voices[OPL4_MAX_VOICES]; + struct list_head off_voices; + struct list_head on_voices; + spinlock_t voices_lock; +#endif +}; + +/* opl4_lib.c */ +void snd_opl4_write(opl4_t *opl4, u8 reg, u8 value); +u8 snd_opl4_read(opl4_t *opl4, u8 reg); +void snd_opl4_read_memory(opl4_t *opl4, char *buf, int offset, int size); +void snd_opl4_write_memory(opl4_t *opl4, const char *buf, int offset, int size); + +/* opl4_mixer.c */ +int snd_opl4_create_mixer(opl4_t *opl4); + +#ifdef CONFIG_PROC_FS +/* opl4_proc.c */ +int snd_opl4_create_proc(opl4_t *opl4); +void snd_opl4_free_proc(opl4_t *opl4); +#endif + +/* opl4_seq.c */ +extern int volume_boost; + +/* opl4_synth.c */ +void snd_opl4_synth_reset(opl4_t *opl4); +void snd_opl4_synth_shutdown(opl4_t *opl4); +void snd_opl4_note_on(void *p, int note, int vel, snd_midi_channel_t *chan); +void snd_opl4_note_off(void *p, int note, int vel, snd_midi_channel_t *chan); +void snd_opl4_terminate_note(void *p, int note, snd_midi_channel_t *chan); +void snd_opl4_control(void *p, int type, snd_midi_channel_t *chan); +void snd_opl4_sysex(void *p, unsigned char *buf, int len, int parsed, snd_midi_channel_set_t *chset); + +/* yrw801.c */ +int snd_yrw801_detect(opl4_t *opl4); +extern const opl4_region_ptr_t snd_yrw801_regions[]; + +#endif /* __OPL4_LOCAL_H */ diff -Nru a/sound/drivers/opl4/opl4_mixer.c b/sound/drivers/opl4/opl4_mixer.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/drivers/opl4/opl4_mixer.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,93 @@ +/* + * OPL4 mixer functions + * Copyright (c) 2003 by Clemens Ladisch <clemens@ladisch.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "opl4_local.h" +#include <sound/control.h> + +#define chip_t opl4_t + +static int snd_opl4_ctl_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 7; + return 0; +} + +static int snd_opl4_ctl_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + opl4_t *opl4 = snd_kcontrol_chip(kcontrol); + u8 reg = kcontrol->private_value; + u8 value; + + value = snd_opl4_read(opl4, reg); + ucontrol->value.integer.value[0] = 7 - (value & 7); + ucontrol->value.integer.value[1] = 7 - ((value >> 3) & 7); + return 0; +} + +static int snd_opl4_ctl_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + opl4_t *opl4 = snd_kcontrol_chip(kcontrol); + u8 reg = kcontrol->private_value; + u8 value, old_value; + + value = (7 - (ucontrol->value.integer.value[0] & 7)) | + ((7 - (ucontrol->value.integer.value[1] & 7)) << 3); + old_value = snd_opl4_read(opl4, reg); + snd_opl4_write(opl4, reg, value); + return value != old_value; +} + +static snd_kcontrol_new_t snd_opl4_controls[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "FM Playback Volume", + .info = snd_opl4_ctl_info, + .get = snd_opl4_ctl_get, + .put = snd_opl4_ctl_put, + .private_value = OPL4_REG_MIX_CONTROL_FM + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Wavetable Playback Volume", + .info = snd_opl4_ctl_info, + .get = snd_opl4_ctl_get, + .put = snd_opl4_ctl_put, + .private_value = OPL4_REG_MIX_CONTROL_PCM + } +}; + +int snd_opl4_create_mixer(opl4_t *opl4) +{ + snd_card_t *card = opl4->card; + int i, err; + +#if 0 /* already set by the codec driver */ + strcpy(card->mixername, "OPL4 Mixer"); +#endif + + for (i = 0; i < 2; ++i) { + err = snd_ctl_add(card, snd_ctl_new1(&snd_opl4_controls[i], opl4)); + if (err < 0) + return err; + } + return 0; +} diff -Nru a/sound/drivers/opl4/opl4_proc.c b/sound/drivers/opl4/opl4_proc.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/drivers/opl4/opl4_proc.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,165 @@ +/* + * Functions for the OPL4 proc file + * Copyright (c) 2003 by Clemens Ladisch <clemens@ladisch.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "opl4_local.h" +#include <sound/info.h> + +#ifdef CONFIG_PROC_FS + +static int snd_opl4_mem_proc_open(snd_info_entry_t *entry, + unsigned short mode, void **file_private_data) +{ + opl4_t *opl4 = snd_magic_cast(opl4_t, entry->private_data, return -ENXIO); + + down(&opl4->access_mutex); + if (opl4->memory_access) { + up(&opl4->access_mutex); + return -EBUSY; + } + opl4->memory_access++; + up(&opl4->access_mutex); + return 0; +} + +static int snd_opl4_mem_proc_release(snd_info_entry_t *entry, + unsigned short mode, void *file_private_data) +{ + opl4_t *opl4 = snd_magic_cast(opl4_t, entry->private_data, return -ENXIO); + + down(&opl4->access_mutex); + opl4->memory_access--; + up(&opl4->access_mutex); + return 0; +} + +static long snd_opl4_mem_proc_read(snd_info_entry_t *entry, void *file_private_data, + struct file *file, char *_buf, long count) +{ + opl4_t *opl4 = snd_magic_cast(opl4_t, entry->private_data, return -ENXIO); + long size; + char* buf; + + size = count; + if (file->f_pos + size > entry->size) + size = entry->size - file->f_pos; + if (size > 0) { + buf = kmalloc(size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + snd_opl4_read_memory(opl4, buf, file->f_pos, size); + if (copy_to_user(_buf, buf, size)) { + kfree(buf); + return -EFAULT; + } + kfree(buf); + file->f_pos += size; + return size; + } + return 0; +} + +static long snd_opl4_mem_proc_write(snd_info_entry_t *entry, void *file_private_data, + struct file *file, const char *_buf, long count) +{ + opl4_t *opl4 = snd_magic_cast(opl4_t, entry->private_data, return -ENXIO); + long size; + char *buf; + + size = count; + if (file->f_pos + size > entry->size) + size = entry->size - file->f_pos; + if (size > 0) { + buf = kmalloc(size, GFP_KERNEL); + if (!buf) + return -ENOMEM; + if (copy_from_user(buf, _buf, size)) { + kfree(buf); + return -EFAULT; + } + snd_opl4_write_memory(opl4, buf, file->f_pos, size); + kfree(buf); + file->f_pos += size; + return size; + } + return 0; +} + +static long long snd_opl4_mem_proc_llseek(snd_info_entry_t *entry, void *file_private_data, + struct file *file, long long offset, int orig) +{ + switch (orig) { + case 0: /* SEEK_SET */ + file->f_pos = offset; + break; + case 1: /* SEEK_CUR */ + file->f_pos += offset; + break; + case 2: /* SEEK_END, offset is negative */ + file->f_pos = entry->size + offset; + break; + default: + return -EINVAL; + } + if (file->f_pos > entry->size) + file->f_pos = entry->size; + return file->f_pos; +} + +static struct snd_info_entry_ops snd_opl4_mem_proc_ops = { + .open = snd_opl4_mem_proc_open, + .release = snd_opl4_mem_proc_release, + .read = snd_opl4_mem_proc_read, + .write = snd_opl4_mem_proc_write, + .llseek = snd_opl4_mem_proc_llseek, +}; + +int snd_opl4_create_proc(opl4_t *opl4) +{ + snd_info_entry_t *entry; + + entry = snd_info_create_card_entry(opl4->card, "opl4-mem", opl4->card->proc_root); + if (entry) { + if (opl4->hardware < OPL3_HW_OPL4_ML) { + /* OPL4 can access 4 MB external ROM/SRAM */ + entry->mode |= S_IWUSR; + entry->size = 4 * 1024 * 1024; + } else { + /* OPL4-ML has 1 MB internal ROM */ + entry->size = 1 * 1024 * 1024; + } + entry->content = SNDRV_INFO_CONTENT_DATA; + entry->c.ops = &snd_opl4_mem_proc_ops; + entry->module = THIS_MODULE; + entry->private_data = opl4; + if (snd_info_register(entry) < 0) { + snd_info_free_entry(entry); + entry = NULL; + } + } + opl4->proc_entry = entry; + return 0; +} + +void snd_opl4_free_proc(opl4_t *opl4) +{ + if (opl4->proc_entry) + snd_info_unregister(opl4->proc_entry); +} + +#endif /* CONFIG_PROC_FS */ diff -Nru a/sound/drivers/opl4/opl4_seq.c b/sound/drivers/opl4/opl4_seq.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/drivers/opl4/opl4_seq.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,224 @@ +/* + * OPL4 sequencer functions + * + * Copyright (c) 2003 by Clemens Ladisch <clemens@ladisch.de> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed and/or modified under the + * terms of the 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 BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + */ + +#include "opl4_local.h" +#include <linux/init.h> +#include <sound/initval.h> + +MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); +MODULE_DESCRIPTION("OPL4 wavetable synth driver"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_CLASSES("{sound}"); + +int volume_boost = 8; + +MODULE_PARM(volume_boost, "i"); +MODULE_PARM_DESC(volume_boost, "Additional volume for OPL4 wavetable sounds."); +MODULE_PARM_SYNTAX(volume_boost, "default:8"); + +static int snd_opl4_seq_use_inc(opl4_t *opl4) +{ + if (!try_module_get(opl4->card->module)) + return -EFAULT; + return 0; +} + +static void snd_opl4_seq_use_dec(opl4_t *opl4) +{ + module_put(opl4->card->module); +} + +static int snd_opl4_seq_use(void *private_data, snd_seq_port_subscribe_t *info) +{ + opl4_t *opl4 = snd_magic_cast(opl4_t, private_data, return -ENXIO); + int err; + + down(&opl4->access_mutex); + + if (opl4->used) { + up(&opl4->access_mutex); + return -EBUSY; + } + opl4->used++; + + if (info->sender.client != SNDRV_SEQ_CLIENT_SYSTEM) { + err = snd_opl4_seq_use_inc(opl4); + if (err < 0) { + up(&opl4->access_mutex); + return err; + } + } + + up(&opl4->access_mutex); + + snd_opl4_synth_reset(opl4); + return 0; +} + +static int snd_opl4_seq_unuse(void *private_data, snd_seq_port_subscribe_t *info) +{ + opl4_t *opl4 = snd_magic_cast(opl4_t, private_data, return -ENXIO); + + snd_opl4_synth_shutdown(opl4); + + down(&opl4->access_mutex); + opl4->used--; + up(&opl4->access_mutex); + + if (info->sender.client != SNDRV_SEQ_CLIENT_SYSTEM) + snd_opl4_seq_use_dec(opl4); + return 0; +} + +static snd_midi_op_t opl4_ops = { + .note_on = snd_opl4_note_on, + .note_off = snd_opl4_note_off, + .note_terminate = snd_opl4_terminate_note, + .control = snd_opl4_control, + .sysex = snd_opl4_sysex, +}; + +static int snd_opl4_seq_event_input(snd_seq_event_t *ev, int direct, + void *private_data, int atomic, int hop) +{ + opl4_t *opl4 = snd_magic_cast(opl4_t, private_data, return -ENXIO); + + snd_midi_process_event(&opl4_ops, ev, opl4->chset); + return 0; +} + +static void snd_opl4_seq_free_port(void *private_data) +{ + opl4_t *opl4 = snd_magic_cast(opl4_t, private_data, return); + + snd_midi_channel_free_set(opl4->chset); +} + +static int snd_opl4_seq_new_device(snd_seq_device_t *dev) +{ + opl4_t *opl4; + int client; + snd_seq_client_callback_t callbacks; + snd_seq_client_info_t cinfo; + snd_seq_port_callback_t pcallbacks; + + opl4 = *(opl4_t **)SNDRV_SEQ_DEVICE_ARGPTR(dev); + if (!opl4) + return -EINVAL; + + if (snd_yrw801_detect(opl4) < 0) + return -ENODEV; + + opl4->chset = snd_midi_channel_alloc_set(16); + if (!opl4->chset) + return -ENOMEM; + opl4->chset->private_data = opl4; + + /* allocate new client */ + memset(&callbacks, 0, sizeof(callbacks)); + callbacks.private_data = opl4; + callbacks.allow_output = callbacks.allow_input = 1; + client = snd_seq_create_kernel_client(opl4->card, opl4->seq_dev_num, &callbacks); + if (client < 0) { + snd_midi_channel_free_set(opl4->chset); + return client; + } + opl4->seq_client = client; + opl4->chset->client = client; + + /* change name of client */ + memset(&cinfo, 0, sizeof(cinfo)); + cinfo.client = client; + cinfo.type = KERNEL_CLIENT; + strcpy(cinfo.name, "OPL4 Wavetable"); + snd_seq_kernel_client_ctl(client, SNDRV_SEQ_IOCTL_SET_CLIENT_INFO, &cinfo); + + /* create new port */ + memset(&pcallbacks, 0, sizeof(pcallbacks)); + pcallbacks.owner = THIS_MODULE; + pcallbacks.use = snd_opl4_seq_use; + pcallbacks.unuse = snd_opl4_seq_unuse; + pcallbacks.event_input = snd_opl4_seq_event_input; + pcallbacks.private_free = snd_opl4_seq_free_port; + pcallbacks.private_data = opl4; + + opl4->chset->port = snd_seq_event_port_attach(client, &pcallbacks, + SNDRV_SEQ_PORT_CAP_WRITE | + SNDRV_SEQ_PORT_CAP_SUBS_WRITE, + SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | + SNDRV_SEQ_PORT_TYPE_MIDI_GM, + 16, 24, + "OPL4 Wavetable Port"); + if (opl4->chset->port < 0) { + int err = opl4->chset->port; + snd_midi_channel_free_set(opl4->chset); + snd_seq_delete_kernel_client(client); + opl4->seq_client = -1; + return err; + } + return 0; +} + +static int snd_opl4_seq_delete_device(snd_seq_device_t *dev) +{ + opl4_t *opl4; + + opl4 = *(opl4_t **)SNDRV_SEQ_DEVICE_ARGPTR(dev); + if (!opl4) + return -EINVAL; + + if (opl4->seq_client >= 0) { + snd_seq_delete_kernel_client(opl4->seq_client); + opl4->seq_client = -1; + } + return 0; +} + +static int __init alsa_opl4_synth_init(void) +{ + static snd_seq_dev_ops_t ops = { + snd_opl4_seq_new_device, + snd_opl4_seq_delete_device + }; + + return snd_seq_device_register_driver(SNDRV_SEQ_DEV_ID_OPL4, &ops, + sizeof(opl4_t*)); +} + +static void __exit alsa_opl4_synth_exit(void) +{ + snd_seq_device_unregister_driver(SNDRV_SEQ_DEV_ID_OPL4); +} + +module_init(alsa_opl4_synth_init) +module_exit(alsa_opl4_synth_exit) diff -Nru a/sound/drivers/opl4/opl4_synth.c b/sound/drivers/opl4/opl4_synth.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/drivers/opl4/opl4_synth.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,623 @@ +/* + * OPL4 MIDI synthesizer functions + * + * Copyright (c) 2003 by Clemens Ladisch <clemens@ladisch.de> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed and/or modified under the + * terms of the 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 BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + */ + +#include "opl4_local.h" +#include <linux/delay.h> +#include <asm/io.h> +#include <sound/asoundef.h> + +/* GM2 controllers */ +#ifndef MIDI_CTL_RELEASE_TIME +#define MIDI_CTL_RELEASE_TIME 0x48 +#define MIDI_CTL_ATTACK_TIME 0x49 +#define MIDI_CTL_DECAY_TIME 0x4b +#define MIDI_CTL_VIBRATO_RATE 0x4c +#define MIDI_CTL_VIBRATO_DEPTH 0x4d +#define MIDI_CTL_VIBRATO_DELAY 0x4e +#endif + +/* + * This table maps 100/128 cents to F_NUMBER. + */ +static const s16 snd_opl4_pitch_map[0x600] = { + 0x000,0x000,0x001,0x001,0x002,0x002,0x003,0x003, + 0x004,0x004,0x005,0x005,0x006,0x006,0x006,0x007, + 0x007,0x008,0x008,0x009,0x009,0x00a,0x00a,0x00b, + 0x00b,0x00c,0x00c,0x00d,0x00d,0x00d,0x00e,0x00e, + 0x00f,0x00f,0x010,0x010,0x011,0x011,0x012,0x012, + 0x013,0x013,0x014,0x014,0x015,0x015,0x015,0x016, + 0x016,0x017,0x017,0x018,0x018,0x019,0x019,0x01a, + 0x01a,0x01b,0x01b,0x01c,0x01c,0x01d,0x01d,0x01e, + 0x01e,0x01e,0x01f,0x01f,0x020,0x020,0x021,0x021, + 0x022,0x022,0x023,0x023,0x024,0x024,0x025,0x025, + 0x026,0x026,0x027,0x027,0x028,0x028,0x029,0x029, + 0x029,0x02a,0x02a,0x02b,0x02b,0x02c,0x02c,0x02d, + 0x02d,0x02e,0x02e,0x02f,0x02f,0x030,0x030,0x031, + 0x031,0x032,0x032,0x033,0x033,0x034,0x034,0x035, + 0x035,0x036,0x036,0x037,0x037,0x038,0x038,0x038, + 0x039,0x039,0x03a,0x03a,0x03b,0x03b,0x03c,0x03c, + 0x03d,0x03d,0x03e,0x03e,0x03f,0x03f,0x040,0x040, + 0x041,0x041,0x042,0x042,0x043,0x043,0x044,0x044, + 0x045,0x045,0x046,0x046,0x047,0x047,0x048,0x048, + 0x049,0x049,0x04a,0x04a,0x04b,0x04b,0x04c,0x04c, + 0x04d,0x04d,0x04e,0x04e,0x04f,0x04f,0x050,0x050, + 0x051,0x051,0x052,0x052,0x053,0x053,0x054,0x054, + 0x055,0x055,0x056,0x056,0x057,0x057,0x058,0x058, + 0x059,0x059,0x05a,0x05a,0x05b,0x05b,0x05c,0x05c, + 0x05d,0x05d,0x05e,0x05e,0x05f,0x05f,0x060,0x060, + 0x061,0x061,0x062,0x062,0x063,0x063,0x064,0x064, + 0x065,0x065,0x066,0x066,0x067,0x067,0x068,0x068, + 0x069,0x069,0x06a,0x06a,0x06b,0x06b,0x06c,0x06c, + 0x06d,0x06d,0x06e,0x06e,0x06f,0x06f,0x070,0x071, + 0x071,0x072,0x072,0x073,0x073,0x074,0x074,0x075, + 0x075,0x076,0x076,0x077,0x077,0x078,0x078,0x079, + 0x079,0x07a,0x07a,0x07b,0x07b,0x07c,0x07c,0x07d, + 0x07d,0x07e,0x07e,0x07f,0x07f,0x080,0x081,0x081, + 0x082,0x082,0x083,0x083,0x084,0x084,0x085,0x085, + 0x086,0x086,0x087,0x087,0x088,0x088,0x089,0x089, + 0x08a,0x08a,0x08b,0x08b,0x08c,0x08d,0x08d,0x08e, + 0x08e,0x08f,0x08f,0x090,0x090,0x091,0x091,0x092, + 0x092,0x093,0x093,0x094,0x094,0x095,0x096,0x096, + 0x097,0x097,0x098,0x098,0x099,0x099,0x09a,0x09a, + 0x09b,0x09b,0x09c,0x09c,0x09d,0x09d,0x09e,0x09f, + 0x09f,0x0a0,0x0a0,0x0a1,0x0a1,0x0a2,0x0a2,0x0a3, + 0x0a3,0x0a4,0x0a4,0x0a5,0x0a6,0x0a6,0x0a7,0x0a7, + 0x0a8,0x0a8,0x0a9,0x0a9,0x0aa,0x0aa,0x0ab,0x0ab, + 0x0ac,0x0ad,0x0ad,0x0ae,0x0ae,0x0af,0x0af,0x0b0, + 0x0b0,0x0b1,0x0b1,0x0b2,0x0b2,0x0b3,0x0b4,0x0b4, + 0x0b5,0x0b5,0x0b6,0x0b6,0x0b7,0x0b7,0x0b8,0x0b8, + 0x0b9,0x0ba,0x0ba,0x0bb,0x0bb,0x0bc,0x0bc,0x0bd, + 0x0bd,0x0be,0x0be,0x0bf,0x0c0,0x0c0,0x0c1,0x0c1, + 0x0c2,0x0c2,0x0c3,0x0c3,0x0c4,0x0c4,0x0c5,0x0c6, + 0x0c6,0x0c7,0x0c7,0x0c8,0x0c8,0x0c9,0x0c9,0x0ca, + 0x0cb,0x0cb,0x0cc,0x0cc,0x0cd,0x0cd,0x0ce,0x0ce, + 0x0cf,0x0d0,0x0d0,0x0d1,0x0d1,0x0d2,0x0d2,0x0d3, + 0x0d3,0x0d4,0x0d5,0x0d5,0x0d6,0x0d6,0x0d7,0x0d7, + 0x0d8,0x0d8,0x0d9,0x0da,0x0da,0x0db,0x0db,0x0dc, + 0x0dc,0x0dd,0x0de,0x0de,0x0df,0x0df,0x0e0,0x0e0, + 0x0e1,0x0e1,0x0e2,0x0e3,0x0e3,0x0e4,0x0e4,0x0e5, + 0x0e5,0x0e6,0x0e7,0x0e7,0x0e8,0x0e8,0x0e9,0x0e9, + 0x0ea,0x0eb,0x0eb,0x0ec,0x0ec,0x0ed,0x0ed,0x0ee, + 0x0ef,0x0ef,0x0f0,0x0f0,0x0f1,0x0f1,0x0f2,0x0f3, + 0x0f3,0x0f4,0x0f4,0x0f5,0x0f5,0x0f6,0x0f7,0x0f7, + 0x0f8,0x0f8,0x0f9,0x0f9,0x0fa,0x0fb,0x0fb,0x0fc, + 0x0fc,0x0fd,0x0fd,0x0fe,0x0ff,0x0ff,0x100,0x100, + 0x101,0x101,0x102,0x103,0x103,0x104,0x104,0x105, + 0x106,0x106,0x107,0x107,0x108,0x108,0x109,0x10a, + 0x10a,0x10b,0x10b,0x10c,0x10c,0x10d,0x10e,0x10e, + 0x10f,0x10f,0x110,0x111,0x111,0x112,0x112,0x113, + 0x114,0x114,0x115,0x115,0x116,0x116,0x117,0x118, + 0x118,0x119,0x119,0x11a,0x11b,0x11b,0x11c,0x11c, + 0x11d,0x11e,0x11e,0x11f,0x11f,0x120,0x120,0x121, + 0x122,0x122,0x123,0x123,0x124,0x125,0x125,0x126, + 0x126,0x127,0x128,0x128,0x129,0x129,0x12a,0x12b, + 0x12b,0x12c,0x12c,0x12d,0x12e,0x12e,0x12f,0x12f, + 0x130,0x131,0x131,0x132,0x132,0x133,0x134,0x134, + 0x135,0x135,0x136,0x137,0x137,0x138,0x138,0x139, + 0x13a,0x13a,0x13b,0x13b,0x13c,0x13d,0x13d,0x13e, + 0x13e,0x13f,0x140,0x140,0x141,0x141,0x142,0x143, + 0x143,0x144,0x144,0x145,0x146,0x146,0x147,0x148, + 0x148,0x149,0x149,0x14a,0x14b,0x14b,0x14c,0x14c, + 0x14d,0x14e,0x14e,0x14f,0x14f,0x150,0x151,0x151, + 0x152,0x153,0x153,0x154,0x154,0x155,0x156,0x156, + 0x157,0x157,0x158,0x159,0x159,0x15a,0x15b,0x15b, + 0x15c,0x15c,0x15d,0x15e,0x15e,0x15f,0x160,0x160, + 0x161,0x161,0x162,0x163,0x163,0x164,0x165,0x165, + 0x166,0x166,0x167,0x168,0x168,0x169,0x16a,0x16a, + 0x16b,0x16b,0x16c,0x16d,0x16d,0x16e,0x16f,0x16f, + 0x170,0x170,0x171,0x172,0x172,0x173,0x174,0x174, + 0x175,0x175,0x176,0x177,0x177,0x178,0x179,0x179, + 0x17a,0x17a,0x17b,0x17c,0x17c,0x17d,0x17e,0x17e, + 0x17f,0x180,0x180,0x181,0x181,0x182,0x183,0x183, + 0x184,0x185,0x185,0x186,0x187,0x187,0x188,0x188, + 0x189,0x18a,0x18a,0x18b,0x18c,0x18c,0x18d,0x18e, + 0x18e,0x18f,0x190,0x190,0x191,0x191,0x192,0x193, + 0x193,0x194,0x195,0x195,0x196,0x197,0x197,0x198, + 0x199,0x199,0x19a,0x19a,0x19b,0x19c,0x19c,0x19d, + 0x19e,0x19e,0x19f,0x1a0,0x1a0,0x1a1,0x1a2,0x1a2, + 0x1a3,0x1a4,0x1a4,0x1a5,0x1a6,0x1a6,0x1a7,0x1a8, + 0x1a8,0x1a9,0x1a9,0x1aa,0x1ab,0x1ab,0x1ac,0x1ad, + 0x1ad,0x1ae,0x1af,0x1af,0x1b0,0x1b1,0x1b1,0x1b2, + 0x1b3,0x1b3,0x1b4,0x1b5,0x1b5,0x1b6,0x1b7,0x1b7, + 0x1b8,0x1b9,0x1b9,0x1ba,0x1bb,0x1bb,0x1bc,0x1bd, + 0x1bd,0x1be,0x1bf,0x1bf,0x1c0,0x1c1,0x1c1,0x1c2, + 0x1c3,0x1c3,0x1c4,0x1c5,0x1c5,0x1c6,0x1c7,0x1c7, + 0x1c8,0x1c9,0x1c9,0x1ca,0x1cb,0x1cb,0x1cc,0x1cd, + 0x1cd,0x1ce,0x1cf,0x1cf,0x1d0,0x1d1,0x1d1,0x1d2, + 0x1d3,0x1d3,0x1d4,0x1d5,0x1d5,0x1d6,0x1d7,0x1d7, + 0x1d8,0x1d9,0x1d9,0x1da,0x1db,0x1db,0x1dc,0x1dd, + 0x1dd,0x1de,0x1df,0x1df,0x1e0,0x1e1,0x1e1,0x1e2, + 0x1e3,0x1e4,0x1e4,0x1e5,0x1e6,0x1e6,0x1e7,0x1e8, + 0x1e8,0x1e9,0x1ea,0x1ea,0x1eb,0x1ec,0x1ec,0x1ed, + 0x1ee,0x1ee,0x1ef,0x1f0,0x1f0,0x1f1,0x1f2,0x1f3, + 0x1f3,0x1f4,0x1f5,0x1f5,0x1f6,0x1f7,0x1f7,0x1f8, + 0x1f9,0x1f9,0x1fa,0x1fb,0x1fb,0x1fc,0x1fd,0x1fe, + 0x1fe,0x1ff,0x200,0x200,0x201,0x202,0x202,0x203, + 0x204,0x205,0x205,0x206,0x207,0x207,0x208,0x209, + 0x209,0x20a,0x20b,0x20b,0x20c,0x20d,0x20e,0x20e, + 0x20f,0x210,0x210,0x211,0x212,0x212,0x213,0x214, + 0x215,0x215,0x216,0x217,0x217,0x218,0x219,0x21a, + 0x21a,0x21b,0x21c,0x21c,0x21d,0x21e,0x21e,0x21f, + 0x220,0x221,0x221,0x222,0x223,0x223,0x224,0x225, + 0x226,0x226,0x227,0x228,0x228,0x229,0x22a,0x22b, + 0x22b,0x22c,0x22d,0x22d,0x22e,0x22f,0x230,0x230, + 0x231,0x232,0x232,0x233,0x234,0x235,0x235,0x236, + 0x237,0x237,0x238,0x239,0x23a,0x23a,0x23b,0x23c, + 0x23c,0x23d,0x23e,0x23f,0x23f,0x240,0x241,0x241, + 0x242,0x243,0x244,0x244,0x245,0x246,0x247,0x247, + 0x248,0x249,0x249,0x24a,0x24b,0x24c,0x24c,0x24d, + 0x24e,0x24f,0x24f,0x250,0x251,0x251,0x252,0x253, + 0x254,0x254,0x255,0x256,0x257,0x257,0x258,0x259, + 0x259,0x25a,0x25b,0x25c,0x25c,0x25d,0x25e,0x25f, + 0x25f,0x260,0x261,0x262,0x262,0x263,0x264,0x265, + 0x265,0x266,0x267,0x267,0x268,0x269,0x26a,0x26a, + 0x26b,0x26c,0x26d,0x26d,0x26e,0x26f,0x270,0x270, + 0x271,0x272,0x273,0x273,0x274,0x275,0x276,0x276, + 0x277,0x278,0x279,0x279,0x27a,0x27b,0x27c,0x27c, + 0x27d,0x27e,0x27f,0x27f,0x280,0x281,0x282,0x282, + 0x283,0x284,0x285,0x285,0x286,0x287,0x288,0x288, + 0x289,0x28a,0x28b,0x28b,0x28c,0x28d,0x28e,0x28e, + 0x28f,0x290,0x291,0x291,0x292,0x293,0x294,0x294, + 0x295,0x296,0x297,0x298,0x298,0x299,0x29a,0x29b, + 0x29b,0x29c,0x29d,0x29e,0x29e,0x29f,0x2a0,0x2a1, + 0x2a1,0x2a2,0x2a3,0x2a4,0x2a5,0x2a5,0x2a6,0x2a7, + 0x2a8,0x2a8,0x2a9,0x2aa,0x2ab,0x2ab,0x2ac,0x2ad, + 0x2ae,0x2af,0x2af,0x2b0,0x2b1,0x2b2,0x2b2,0x2b3, + 0x2b4,0x2b5,0x2b5,0x2b6,0x2b7,0x2b8,0x2b9,0x2b9, + 0x2ba,0x2bb,0x2bc,0x2bc,0x2bd,0x2be,0x2bf,0x2c0, + 0x2c0,0x2c1,0x2c2,0x2c3,0x2c4,0x2c4,0x2c5,0x2c6, + 0x2c7,0x2c7,0x2c8,0x2c9,0x2ca,0x2cb,0x2cb,0x2cc, + 0x2cd,0x2ce,0x2ce,0x2cf,0x2d0,0x2d1,0x2d2,0x2d2, + 0x2d3,0x2d4,0x2d5,0x2d6,0x2d6,0x2d7,0x2d8,0x2d9, + 0x2da,0x2da,0x2db,0x2dc,0x2dd,0x2dd,0x2de,0x2df, + 0x2e0,0x2e1,0x2e1,0x2e2,0x2e3,0x2e4,0x2e5,0x2e5, + 0x2e6,0x2e7,0x2e8,0x2e9,0x2e9,0x2ea,0x2eb,0x2ec, + 0x2ed,0x2ed,0x2ee,0x2ef,0x2f0,0x2f1,0x2f1,0x2f2, + 0x2f3,0x2f4,0x2f5,0x2f5,0x2f6,0x2f7,0x2f8,0x2f9, + 0x2f9,0x2fa,0x2fb,0x2fc,0x2fd,0x2fd,0x2fe,0x2ff, + 0x300,0x301,0x302,0x302,0x303,0x304,0x305,0x306, + 0x306,0x307,0x308,0x309,0x30a,0x30a,0x30b,0x30c, + 0x30d,0x30e,0x30f,0x30f,0x310,0x311,0x312,0x313, + 0x313,0x314,0x315,0x316,0x317,0x318,0x318,0x319, + 0x31a,0x31b,0x31c,0x31c,0x31d,0x31e,0x31f,0x320, + 0x321,0x321,0x322,0x323,0x324,0x325,0x326,0x326, + 0x327,0x328,0x329,0x32a,0x32a,0x32b,0x32c,0x32d, + 0x32e,0x32f,0x32f,0x330,0x331,0x332,0x333,0x334, + 0x334,0x335,0x336,0x337,0x338,0x339,0x339,0x33a, + 0x33b,0x33c,0x33d,0x33e,0x33e,0x33f,0x340,0x341, + 0x342,0x343,0x343,0x344,0x345,0x346,0x347,0x348, + 0x349,0x349,0x34a,0x34b,0x34c,0x34d,0x34e,0x34e, + 0x34f,0x350,0x351,0x352,0x353,0x353,0x354,0x355, + 0x356,0x357,0x358,0x359,0x359,0x35a,0x35b,0x35c, + 0x35d,0x35e,0x35f,0x35f,0x360,0x361,0x362,0x363, + 0x364,0x364,0x365,0x366,0x367,0x368,0x369,0x36a, + 0x36a,0x36b,0x36c,0x36d,0x36e,0x36f,0x370,0x370, + 0x371,0x372,0x373,0x374,0x375,0x376,0x377,0x377, + 0x378,0x379,0x37a,0x37b,0x37c,0x37d,0x37d,0x37e, + 0x37f,0x380,0x381,0x382,0x383,0x383,0x384,0x385, + 0x386,0x387,0x388,0x389,0x38a,0x38a,0x38b,0x38c, + 0x38d,0x38e,0x38f,0x390,0x391,0x391,0x392,0x393, + 0x394,0x395,0x396,0x397,0x398,0x398,0x399,0x39a, + 0x39b,0x39c,0x39d,0x39e,0x39f,0x39f,0x3a0,0x3a1, + 0x3a2,0x3a3,0x3a4,0x3a5,0x3a6,0x3a7,0x3a7,0x3a8, + 0x3a9,0x3aa,0x3ab,0x3ac,0x3ad,0x3ae,0x3ae,0x3af, + 0x3b0,0x3b1,0x3b2,0x3b3,0x3b4,0x3b5,0x3b6,0x3b6, + 0x3b7,0x3b8,0x3b9,0x3ba,0x3bb,0x3bc,0x3bd,0x3be, + 0x3bf,0x3bf,0x3c0,0x3c1,0x3c2,0x3c3,0x3c4,0x3c5, + 0x3c6,0x3c7,0x3c7,0x3c8,0x3c9,0x3ca,0x3cb,0x3cc, + 0x3cd,0x3ce,0x3cf,0x3d0,0x3d1,0x3d1,0x3d2,0x3d3, + 0x3d4,0x3d5,0x3d6,0x3d7,0x3d8,0x3d9,0x3da,0x3da, + 0x3db,0x3dc,0x3dd,0x3de,0x3df,0x3e0,0x3e1,0x3e2, + 0x3e3,0x3e4,0x3e4,0x3e5,0x3e6,0x3e7,0x3e8,0x3e9, + 0x3ea,0x3eb,0x3ec,0x3ed,0x3ee,0x3ef,0x3ef,0x3f0, + 0x3f1,0x3f2,0x3f3,0x3f4,0x3f5,0x3f6,0x3f7,0x3f8, + 0x3f9,0x3fa,0x3fa,0x3fb,0x3fc,0x3fd,0x3fe,0x3ff +}; + +/* + * Attenuation according to GM recommendations, in -0.375 dB units. + * table[v] = 40 * log(v / 127) / -0.375 + */ +static unsigned char snd_opl4_volume_table[128] = { + 255,224,192,173,160,150,141,134, + 128,122,117,113,109,105,102, 99, + 96, 93, 90, 88, 85, 83, 81, 79, + 77, 75, 73, 71, 70, 68, 67, 65, + 64, 62, 61, 59, 58, 57, 56, 54, + 53, 52, 51, 50, 49, 48, 47, 46, + 45, 44, 43, 42, 41, 40, 39, 39, + 38, 37, 36, 35, 34, 34, 33, 32, + 31, 31, 30, 29, 29, 28, 27, 27, + 26, 25, 25, 24, 24, 23, 22, 22, + 21, 21, 20, 19, 19, 18, 18, 17, + 17, 16, 16, 15, 15, 14, 14, 13, + 13, 12, 12, 11, 11, 10, 10, 9, + 9, 9, 8, 8, 7, 7, 6, 6, + 6, 5, 5, 4, 4, 4, 3, 3, + 2, 2, 2, 1, 1, 0, 0, 0 +}; + +static void snd_opl4_write_mask(opl4_t *opl4, u8 reg, u8 mask, u8 value) +{ + snd_opl4_write(opl4, reg, ((snd_opl4_read(opl4, reg)) & ~mask) | (value & mask)); +} + +/* + * Initializes all voices. + */ +void snd_opl4_synth_reset(opl4_t *opl4) +{ + int i; + + for (i = 0; i < OPL4_MAX_VOICES; i++) + snd_opl4_write(opl4, OPL4_REG_MISC + i, OPL4_DAMP_BIT); + + spin_lock_init(&opl4->voices_lock); + INIT_LIST_HEAD(&opl4->off_voices); + INIT_LIST_HEAD(&opl4->on_voices); + memset(opl4->voices, 0, sizeof(opl4->voices)); + for (i = 0; i < OPL4_MAX_VOICES; i++) { + opl4->voices[i].number = i; + list_add_tail(&opl4->voices[i].list, &opl4->off_voices); + } + + snd_midi_channel_set_clear(opl4->chset); +} + +/* + * Shuts down all voices. + */ +void snd_opl4_synth_shutdown(opl4_t *opl4) +{ + int i; + + for (i = 0; i < OPL4_MAX_VOICES; i++) + snd_opl4_write_mask(opl4, OPL4_REG_MISC + i, OPL4_KEY_ON_BIT, 0); +} + +/* + * Executes the callback for all voices playing the specified note. + */ +static void snd_opl4_do_for_note(opl4_t *opl4, int note, snd_midi_channel_t *chan, + void (*func)(opl4_t *opl4, opl4_voice_t *voice)) +{ + int i; + unsigned long flags; + opl4_voice_t *voice; + + spin_lock_irqsave(&opl4->voices_lock, flags); + for (i = 0; i < OPL4_MAX_VOICES; i++) { + voice = &opl4->voices[i]; + if (voice->chan == chan && voice->note == note) { + func(opl4, voice); + } + } + spin_unlock_irqrestore(&opl4->voices_lock, flags); +} + +/* + * Executes the callback for all voices of to the specified channel. + */ +static void snd_opl4_do_for_channel(opl4_t *opl4, snd_midi_channel_t *chan, + void (*func)(opl4_t *opl4, opl4_voice_t *voice)) +{ + int i; + unsigned long flags; + opl4_voice_t *voice; + + spin_lock_irqsave(&opl4->voices_lock, flags); + for (i = 0; i < OPL4_MAX_VOICES; i++) { + voice = &opl4->voices[i]; + if (voice->chan == chan) { + func(opl4, voice); + } + } + spin_unlock_irqrestore(&opl4->voices_lock, flags); +} + +/* + * Executes the callback for all active voices. + */ +static void snd_opl4_do_for_all(opl4_t *opl4, + void (*func)(opl4_t *opl4, opl4_voice_t *voice)) +{ + int i; + unsigned long flags; + opl4_voice_t *voice; + + spin_lock_irqsave(&opl4->voices_lock, flags); + for (i = 0; i < OPL4_MAX_VOICES; i++) { + voice = &opl4->voices[i]; + if (voice->chan) + func(opl4, voice); + } + spin_unlock_irqrestore(&opl4->voices_lock, flags); +} + +static void snd_opl4_update_volume(opl4_t *opl4, opl4_voice_t *voice) +{ + int att; + + att = voice->sound->tone_attenuate; + att += snd_opl4_volume_table[opl4->chset->gs_master_volume & 0x7f]; + att += snd_opl4_volume_table[voice->chan->gm_volume & 0x7f]; + att += snd_opl4_volume_table[voice->chan->gm_expression & 0x7f]; + att += snd_opl4_volume_table[voice->velocity]; + att = 0x7f - (0x7f - att) * (voice->sound->volume_factor) / 0xfe - volume_boost; + if (att < 0) + att = 0; + else if (att > 0x7e) + att = 0x7e; + snd_opl4_write(opl4, OPL4_REG_LEVEL + voice->number, att << 1); +} + +static void snd_opl4_update_pan(opl4_t *opl4, opl4_voice_t *voice) +{ + int pan = voice->sound->panpot; + + if (!voice->chan->drum_channel) + pan += (voice->chan->control[MIDI_CTL_MSB_PAN] - 0x40) >> 3; + if (pan < -7) + pan = -7; + else if (pan > 7) + pan = 7; + voice->reg_misc = (voice->reg_misc & ~OPL4_PAN_POT_MASK) + | (pan & OPL4_PAN_POT_MASK); + snd_opl4_write(opl4, OPL4_REG_MISC + voice->number, voice->reg_misc); +} + +static void snd_opl4_update_vibrato_depth(opl4_t *opl4, opl4_voice_t *voice) +{ + int depth; + + if (voice->chan->drum_channel) + return; + depth = (7 - voice->sound->vibrato) + * (voice->chan->control[MIDI_CTL_VIBRATO_DEPTH] & 0x7f); + depth = (depth >> 7) + voice->sound->vibrato; + snd_opl4_write_mask(opl4, OPL4_REG_LFO_VIBRATO + voice->number, + OPL4_VIBRATO_DEPTH_MASK, depth); +} + +static void snd_opl4_update_pitch(opl4_t *opl4, opl4_voice_t *voice) +{ + snd_midi_channel_t *chan = voice->chan; + int note, pitch, octave; + + note = chan->drum_channel ? 60 : voice->note; + /* + * pitch is in 100/128 cents, so 0x80 is one semitone and + * 0x600 is one octave. + */ + pitch = ((note - 60) << 7) * voice->sound->key_scaling / 100 + (60 << 7); + pitch += voice->sound->pitch_offset; + if (!chan->drum_channel) + pitch += chan->gm_rpn_coarse_tuning; + pitch += chan->gm_rpn_fine_tuning >> 7; + pitch += chan->midi_pitchbend * chan->gm_rpn_pitch_bend_range / 0x2000; + if (pitch < 0) + pitch = 0; + else if (pitch >= 0x6000) + pitch = 0x5fff; + octave = pitch / 0x600 - 8; + pitch = snd_opl4_pitch_map[pitch % 0x600]; + + snd_opl4_write(opl4, OPL4_REG_OCTAVE + voice->number, + (octave << 4) | ((pitch >> 7) & OPL4_F_NUMBER_HIGH_MASK)); + voice->reg_f_number = (voice->reg_f_number & OPL4_TONE_NUMBER_BIT8) + | ((pitch << 1) & OPL4_F_NUMBER_LOW_MASK); + snd_opl4_write(opl4, OPL4_REG_F_NUMBER + voice->number, voice->reg_f_number); +} + +static void snd_opl4_update_tone_parameters(opl4_t *opl4, opl4_voice_t *voice) +{ + snd_opl4_write(opl4, OPL4_REG_LFO_VIBRATO + voice->number, + voice->sound->reg_lfo_vibrato); + snd_opl4_write(opl4, OPL4_REG_ATTACK_DECAY1 + voice->number, + voice->sound->reg_attack_decay1); + snd_opl4_write(opl4, OPL4_REG_LEVEL_DECAY2 + voice->number, + voice->sound->reg_level_decay2); + snd_opl4_write(opl4, OPL4_REG_RELEASE_CORRECTION + voice->number, + voice->sound->reg_release_correction); + snd_opl4_write(opl4, OPL4_REG_TREMOLO + voice->number, + voice->sound->reg_tremolo); +} + +/* allocate one voice */ +static opl4_voice_t *snd_opl4_get_voice(opl4_t *opl4) +{ + /* first, try to get the oldest key-off voice */ + if (!list_empty(&opl4->off_voices)) + return list_entry(opl4->off_voices.next, opl4_voice_t, list); + /* then get the oldest key-on voice */ + snd_assert(!list_empty(&opl4->on_voices), ); + return list_entry(opl4->on_voices.next, opl4_voice_t, list); +} + +static void snd_opl4_wait_for_wave_headers(opl4_t *opl4) +{ + int timeout = 200; + + while ((inb(opl4->fm_port) & OPL4_STATUS_LOAD) && --timeout > 0) + udelay(10); +} + +void snd_opl4_note_on(void *private_data, int note, int vel, snd_midi_channel_t *chan) +{ + opl4_t *opl4 = snd_magic_cast(opl4_t, private_data, return); + const opl4_region_ptr_t *regions; + opl4_voice_t *voice[2]; + const opl4_sound_t *sound[2]; + int voices = 0, i; + unsigned long flags; + + /* determine the number of voices and voice parameters */ + i = chan->drum_channel ? 0x80 : (chan->midi_program & 0x7f); + regions = &snd_yrw801_regions[i]; + for (i = 0; i < regions->count; i++) { + if (note >= regions->regions[i].key_min && + note <= regions->regions[i].key_max) { + sound[voices] = ®ions->regions[i].sound; + if (++voices >= 2) + break; + } + } + + /* allocate and initialize the needed voices */ + spin_lock_irqsave(&opl4->voices_lock, flags); + for (i = 0; i < voices; i++) { + voice[i] = snd_opl4_get_voice(opl4); + list_del(&voice[i]->list); + list_add_tail(&voice[i]->list, &opl4->on_voices); + voice[i]->chan = chan; + voice[i]->note = note; + voice[i]->velocity = vel & 0x7f; + voice[i]->sound = sound[i]; + } + spin_unlock_irqrestore(&opl4->voices_lock, flags); + + /* set tone number (triggers header loading) */ + for (i = 0; i < voices; i++) { + voice[i]->reg_f_number = + (sound[i]->tone >> 8) & OPL4_TONE_NUMBER_BIT8; + snd_opl4_write(opl4, OPL4_REG_F_NUMBER + voice[i]->number, + voice[i]->reg_f_number); + snd_opl4_write(opl4, OPL4_REG_TONE_NUMBER + voice[i]->number, + sound[i]->tone & 0xff); + } + + /* set parameters which can be set while loading */ + for (i = 0; i < voices; i++) { + voice[i]->reg_misc = OPL4_LFO_RESET_BIT; + snd_opl4_update_pan(opl4, voice[i]); + snd_opl4_update_pitch(opl4, voice[i]); + snd_opl4_update_volume(opl4, voice[i]); + } + + /* wait for completion of loading */ + snd_opl4_wait_for_wave_headers(opl4); + + /* set remaining parameters */ + for (i = 0; i < voices; i++) { + snd_opl4_update_tone_parameters(opl4, voice[i]); + snd_opl4_update_vibrato_depth(opl4, voice[i]); + } + + /* finally, switch on all voices */ + for (i = 0; i < voices; i++) { + voice[i]->reg_misc = + (voice[i]->reg_misc & 0x1f) | OPL4_KEY_ON_BIT; + snd_opl4_write(opl4, OPL4_REG_MISC + voice[i]->number, + voice[i]->reg_misc); + } +} + +static void snd_opl4_voice_off(opl4_t *opl4, opl4_voice_t *voice) +{ + list_del(&voice->list); + list_add_tail(&voice->list, &opl4->off_voices); + + voice->reg_misc &= ~OPL4_KEY_ON_BIT; + snd_opl4_write(opl4, OPL4_REG_MISC + voice->number, voice->reg_misc); +} + +void snd_opl4_note_off(void *private_data, int note, int vel, snd_midi_channel_t *chan) +{ + opl4_t *opl4 = snd_magic_cast(opl4_t, private_data, return); + + snd_opl4_do_for_note(opl4, note, chan, snd_opl4_voice_off); +} + +static void snd_opl4_terminate_voice(opl4_t *opl4, opl4_voice_t *voice) +{ + list_del(&voice->list); + list_add_tail(&voice->list, &opl4->off_voices); + + voice->reg_misc = (voice->reg_misc & ~OPL4_KEY_ON_BIT) | OPL4_DAMP_BIT; + snd_opl4_write(opl4, OPL4_REG_MISC + voice->number, voice->reg_misc); +} + +void snd_opl4_terminate_note(void *private_data, int note, snd_midi_channel_t *chan) +{ + opl4_t *opl4 = snd_magic_cast(opl4_t, private_data, return); + + snd_opl4_do_for_note(opl4, note, chan, snd_opl4_terminate_voice); +} + +void snd_opl4_control(void *private_data, int type, snd_midi_channel_t *chan) +{ + opl4_t *opl4 = snd_magic_cast(opl4_t, private_data, return); + + switch (type) { + case MIDI_CTL_MSB_MODWHEEL: + chan->control[MIDI_CTL_VIBRATO_DEPTH] = chan->control[MIDI_CTL_MSB_MODWHEEL]; + snd_opl4_do_for_channel(opl4, chan, snd_opl4_update_vibrato_depth); + break; + case MIDI_CTL_MSB_MAIN_VOLUME: + snd_opl4_do_for_channel(opl4, chan, snd_opl4_update_volume); + break; + case MIDI_CTL_MSB_PAN: + snd_opl4_do_for_channel(opl4, chan, snd_opl4_update_pan); + break; + case MIDI_CTL_MSB_EXPRESSION: + snd_opl4_do_for_channel(opl4, chan, snd_opl4_update_volume); + break; + case MIDI_CTL_VIBRATO_RATE: + /* not yet supported */ + break; + case MIDI_CTL_VIBRATO_DEPTH: + snd_opl4_do_for_channel(opl4, chan, snd_opl4_update_vibrato_depth); + break; + case MIDI_CTL_VIBRATO_DELAY: + /* not yet supported */ + break; + case MIDI_CTL_E1_REVERB_DEPTH: + /* + * Each OPL4 voice has a bit called "Pseudo-Reverb", but + * IMHO _not_ using it enhances the listening experience. + */ + break; + case MIDI_CTL_PITCHBEND: + snd_opl4_do_for_channel(opl4, chan, snd_opl4_update_pitch); + break; + } +} + +void snd_opl4_sysex(void *private_data, unsigned char *buf, int len, + int parsed, snd_midi_channel_set_t *chset) +{ + opl4_t *opl4 = snd_magic_cast(opl4_t, private_data, return); + + if (parsed == SNDRV_MIDI_SYSEX_GS_MASTER_VOLUME) + snd_opl4_do_for_all(opl4, snd_opl4_update_volume); +} diff -Nru a/sound/drivers/opl4/yrw801.c b/sound/drivers/opl4/yrw801.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/drivers/opl4/yrw801.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,961 @@ +/* + * Information about the Yamaha YRW801 wavetable ROM chip + * + * Copyright (c) 2003 by Clemens Ladisch <clemens@ladisch.de> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions, and the following disclaimer, + * without modification. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * Alternatively, this software may be distributed and/or modified under the + * terms of the 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 BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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. + */ + +#include "opl4_local.h" + +int snd_yrw801_detect(opl4_t *opl4) +{ + char buf[15]; + + snd_opl4_read_memory(opl4, buf, 0x001200, 15); + if (memcmp(buf, "CopyrightYAMAHA", 15)) + return -ENODEV; + snd_opl4_read_memory(opl4, buf, 0x1ffffe, 2); + if (buf[0] != 0x01) + return -ENODEV; + snd_printdd("YRW801 ROM version %02x.%02x\n", buf[0], buf[1]); + return 0; +} + +/* + * The instrument definitions are stored statically because, in practice, the + * OPL4 is always coupled with a YRW801. Dynamic instrument loading would be + * required if downloading sample data to external SRAM was actually supported + * by this driver. + */ + +static const opl4_region_t regions_00[] = { /* Acoustic Grand Piano */ + {0x14, 0x27, {0x12c,7474,100, 0,0,0x00,0xc8,0x20,0xf2,0x13,0x08,0x0}}, + {0x28, 0x2d, {0x12d,6816,100, 0,0,0x00,0xc8,0x20,0xf2,0x14,0x08,0x0}}, + {0x2e, 0x33, {0x12e,5899,100, 0,0,0x00,0xc8,0x20,0xf2,0x14,0x08,0x0}}, + {0x34, 0x39, {0x12f,5290,100, 0,0,0x00,0xc8,0x20,0xf2,0x14,0x08,0x0}}, + {0x3a, 0x3f, {0x130,4260,100, 0,0,0x0a,0xc8,0x20,0xf2,0x14,0x08,0x0}}, + {0x40, 0x45, {0x131,3625,100, 0,0,0x0a,0xc8,0x20,0xf2,0x14,0x08,0x0}}, + {0x46, 0x4b, {0x132,3116,100, 0,0,0x04,0xc8,0x20,0xf2,0x14,0x08,0x0}}, + {0x4c, 0x52, {0x133,2081,100, 0,0,0x03,0xc8,0x20,0xf2,0x14,0x18,0x0}}, + {0x53, 0x58, {0x134,1444,100, 0,0,0x07,0xc8,0x20,0xf3,0x14,0x18,0x0}}, + {0x59, 0x6d, {0x135,1915,100, 0,0,0x00,0xc8,0x20,0xf4,0x15,0x08,0x0}} +}; +static const opl4_region_t regions_01[] = { /* Bright Acoustic Piano */ + {0x14, 0x2d, {0x12c,7474,100, 0,0,0x00,0xc8,0x20,0xf2,0x13,0x08,0x0}}, + {0x2e, 0x33, {0x12d,6816,100, 0,0,0x00,0xc8,0x20,0xf2,0x14,0x08,0x0}}, + {0x34, 0x39, {0x12e,5899,100, 0,0,0x00,0xc8,0x20,0xf2,0x14,0x08,0x0}}, + {0x3a, 0x3f, {0x12f,5290,100, 0,0,0x00,0xc8,0x20,0xf2,0x14,0x08,0x0}}, + {0x40, 0x45, {0x130,4260,100, 0,0,0x0a,0xc8,0x20,0xf2,0x14,0x08,0x0}}, + {0x46, 0x4b, {0x131,3625,100, 0,0,0x0a,0xc8,0x20,0xf2,0x14,0x08,0x0}}, + {0x4c, 0x52, {0x132,3116,100, 0,0,0x04,0xc8,0x20,0xf2,0x14,0x08,0x0}}, + {0x53, 0x58, {0x133,2081,100, 0,0,0x07,0xc8,0x20,0xf2,0x14,0x18,0x0}}, + {0x59, 0x5e, {0x134,1444,100, 0,0,0x0a,0xc8,0x20,0xf3,0x14,0x18,0x0}}, + {0x5f, 0x6d, {0x135,1915,100, 0,0,0x00,0xc8,0x20,0xf4,0x15,0x08,0x0}} +}; +static const opl4_region_t regions_02[] = { /* Electric Grand Piano */ + {0x14, 0x2d, {0x12c,7476,100, 1,0,0x00,0xae,0x20,0xf2,0x13,0x07,0x0}}, + {0x2e, 0x33, {0x12d,6818,100, 1,0,0x00,0xae,0x20,0xf2,0x14,0x07,0x0}}, + {0x34, 0x39, {0x12e,5901,100, 1,0,0x00,0xae,0x20,0xf2,0x14,0x07,0x0}}, + {0x3a, 0x3f, {0x12f,5292,100, 1,0,0x00,0xae,0x20,0xf2,0x14,0x07,0x0}}, + {0x40, 0x45, {0x130,4262,100, 1,0,0x00,0xae,0x20,0xf2,0x14,0x07,0x0}}, + {0x46, 0x4b, {0x131,3627,100, 1,0,0x00,0xae,0x20,0xf2,0x14,0x07,0x0}}, + {0x4c, 0x52, {0x132,3118,100, 1,0,0x00,0xae,0x20,0xf2,0x14,0x07,0x0}}, + {0x53, 0x58, {0x133,2083,100, 1,0,0x00,0xae,0x20,0xf2,0x14,0x17,0x0}}, + {0x59, 0x5e, {0x134,1446,100, 1,0,0x00,0xae,0x20,0xf3,0x14,0x17,0x0}}, + {0x5f, 0x6d, {0x135,1917,100, 1,0,0x00,0xae,0x20,0xf4,0x15,0x07,0x0}}, + {0x00, 0x7f, {0x06c,6375,100,-1,0,0x00,0xc2,0x28,0xf4,0x23,0x18,0x0}} +}; +static const opl4_region_t regions_03[] = { /* Honky-Tonk Piano */ + {0x14, 0x27, {0x12c,7474,100, 0,0,0x00,0xb4,0x20,0xf2,0x13,0x08,0x0}}, + {0x28, 0x2d, {0x12d,6816,100, 0,0,0x00,0xb4,0x20,0xf2,0x14,0x08,0x0}}, + {0x2e, 0x33, {0x12e,5899,100, 0,0,0x00,0xb4,0x20,0xf2,0x14,0x08,0x0}}, + {0x34, 0x39, {0x12f,5290,100, 0,0,0x00,0xb4,0x20,0xf2,0x14,0x08,0x0}}, + {0x3a, 0x3f, {0x130,4260,100, 0,0,0x0a,0xb4,0x20,0xf2,0x14,0x08,0x0}}, + {0x40, 0x45, {0x131,3625,100, 0,0,0x0a,0xb4,0x20,0xf2,0x14,0x08,0x0}}, + {0x46, 0x4b, {0x132,3116,100, 0,0,0x04,0xb4,0x20,0xf2,0x14,0x08,0x0}}, + {0x4c, 0x52, {0x133,2081,100, 0,0,0x03,0xb4,0x20,0xf2,0x14,0x18,0x0}}, + {0x53, 0x58, {0x134,1444,100, 0,0,0x07,0xb4,0x20,0xf3,0x14,0x18,0x0}}, + {0x59, 0x6d, {0x135,1915,100, 0,0,0x00,0xb4,0x20,0xf4,0x15,0x08,0x0}}, + {0x14, 0x27, {0x12c,7486,100, 0,0,0x00,0xb4,0x20,0xf2,0x13,0x08,0x0}}, + {0x28, 0x2d, {0x12d,6803,100, 0,0,0x00,0xb4,0x20,0xf2,0x14,0x08,0x0}}, + {0x2e, 0x33, {0x12e,5912,100, 0,0,0x00,0xb4,0x20,0xf2,0x14,0x08,0x0}}, + {0x34, 0x39, {0x12f,5275,100, 0,0,0x00,0xb4,0x20,0xf2,0x14,0x08,0x0}}, + {0x3a, 0x3f, {0x130,4274,100, 0,0,0x0a,0xb4,0x20,0xf2,0x14,0x08,0x0}}, + {0x40, 0x45, {0x131,3611,100, 0,0,0x0a,0xb4,0x20,0xf2,0x14,0x08,0x0}}, + {0x46, 0x4b, {0x132,3129,100, 0,0,0x04,0xb4,0x20,0xf2,0x14,0x08,0x0}}, + {0x4c, 0x52, {0x133,2074,100, 0,0,0x07,0xb4,0x20,0xf2,0x14,0x18,0x0}}, + {0x53, 0x58, {0x134,1457,100, 0,0,0x01,0xb4,0x20,0xf3,0x14,0x18,0x0}}, + {0x59, 0x6d, {0x135,1903,100, 0,0,0x00,0xb4,0x20,0xf4,0x15,0x08,0x0}} +}; +static const opl4_region_t regions_04[] = { /* Electric Piano 1 */ + {0x15, 0x6c, {0x00b,6570,100, 0,0,0x00,0x28,0x38,0xf0,0x00,0x0c,0x0}}, + {0x00, 0x7f, {0x06c,6375,100, 0,2,0x00,0xb0,0x22,0xf4,0x23,0x19,0x0}} +}; +static const opl4_region_t regions_05[] = { /* Electric Piano 2 */ + {0x14, 0x27, {0x12c,7476,100, 0,3,0x00,0xa2,0x1b,0xf2,0x13,0x08,0x0}}, + {0x28, 0x2d, {0x12d,6818,100, 0,3,0x00,0xa2,0x1b,0xf2,0x14,0x08,0x0}}, + {0x2e, 0x33, {0x12e,5901,100, 0,3,0x00,0xa2,0x1b,0xf2,0x14,0x08,0x0}}, + {0x34, 0x39, {0x12f,5292,100, 0,3,0x00,0xa2,0x1b,0xf2,0x14,0x08,0x0}}, + {0x3a, 0x3f, {0x130,4262,100, 0,3,0x0a,0xa2,0x1b,0xf2,0x14,0x08,0x0}}, + {0x40, 0x45, {0x131,3627,100, 0,3,0x0a,0xa2,0x1b,0xf2,0x14,0x08,0x0}}, + {0x46, 0x4b, {0x132,3118,100, 0,3,0x04,0xa2,0x1b,0xf2,0x14,0x08,0x0}}, + {0x4c, 0x52, {0x133,2083,100, 0,3,0x03,0xa2,0x1b,0xf2,0x14,0x18,0x0}}, + {0x53, 0x58, {0x134,1446,100, 0,3,0x07,0xa2,0x1b,0xf3,0x14,0x18,0x0}}, + {0x59, 0x6d, {0x135,1917,100, 0,3,0x00,0xa2,0x1b,0xf4,0x15,0x08,0x0}}, + {0x14, 0x2d, {0x12c,7472,100, 0,0,0x00,0xa2,0x18,0xf2,0x13,0x08,0x0}}, + {0x2e, 0x33, {0x12d,6814,100, 0,0,0x00,0xa2,0x18,0xf2,0x14,0x08,0x0}}, + {0x34, 0x39, {0x12e,5897,100, 0,0,0x00,0xa2,0x18,0xf2,0x14,0x08,0x0}}, + {0x3a, 0x3f, {0x12f,5288,100, 0,0,0x00,0xa2,0x18,0xf2,0x14,0x08,0x0}}, + {0x40, 0x45, {0x130,4258,100, 0,0,0x0a,0xa2,0x18,0xf2,0x14,0x08,0x0}}, + {0x46, 0x4b, {0x131,3623,100, 0,0,0x0a,0xa2,0x18,0xf2,0x14,0x08,0x0}}, + {0x4c, 0x52, {0x132,3114,100, 0,0,0x04,0xa2,0x18,0xf2,0x14,0x08,0x0}}, + {0x53, 0x58, {0x133,2079,100, 0,0,0x07,0xa2,0x18,0xf2,0x14,0x18,0x0}}, + {0x59, 0x5e, {0x134,1442,100, 0,0,0x0a,0xa2,0x18,0xf3,0x14,0x18,0x0}}, + {0x5f, 0x6d, {0x135,1913,100, 0,0,0x00,0xa2,0x18,0xf4,0x15,0x08,0x0}} +}; +static const opl4_region_t regions_06[] = { /* Harpsichord */ + {0x15, 0x39, {0x080,5158,100, 0,0,0x00,0xb2,0x20,0xf5,0x24,0x19,0x0}}, + {0x3a, 0x3f, {0x081,4408,100, 0,0,0x00,0xb2,0x20,0xf5,0x25,0x09,0x0}}, + {0x40, 0x45, {0x082,3622,100, 0,0,0x00,0xb2,0x20,0xf5,0x25,0x09,0x0}}, + {0x46, 0x4d, {0x083,2843,100, 0,0,0x00,0xb2,0x20,0xf5,0x25,0x19,0x0}}, + {0x4e, 0x6c, {0x084,1307,100, 0,0,0x00,0xb2,0x20,0xf5,0x25,0x29,0x0}} +}; +static const opl4_region_t regions_07[] = { /* Clavinet */ + {0x15, 0x51, {0x027,5009,100, 0,0,0x00,0xd2,0x28,0xf5,0x13,0x2b,0x0}}, + {0x52, 0x6c, {0x028,3495,100, 0,0,0x00,0xd2,0x28,0xf5,0x13,0x3b,0x0}} +}; +static const opl4_region_t regions_08[] = { /* Celesta */ + {0x15, 0x6c, {0x02b,3267,100, 0,0,0x00,0xdc,0x20,0xf4,0x15,0x07,0x3}} +}; +static const opl4_region_t regions_09[] = { /* Glockenspiel */ + {0x15, 0x78, {0x0f3, 285,100, 0,0,0x00,0xc2,0x28,0xf6,0x25,0x25,0x0}} +}; +static const opl4_region_t regions_0a[] = { /* Music Box */ + {0x15, 0x6c, {0x0f3,3362,100, 0,0,0x00,0xb6,0x20,0xa6,0x25,0x25,0x0}}, + {0x15, 0x6c, {0x101,4773,100, 0,0,0x00,0xaa,0x20,0xd4,0x14,0x16,0x0}} +}; +static const opl4_region_t regions_0b[] = { /* Vibraphone */ + {0x15, 0x6c, {0x101,4778,100, 0,0,0x00,0xc0,0x28,0xf4,0x14,0x16,0x4}} +}; +static const opl4_region_t regions_0c[] = { /* Marimba */ + {0x15, 0x3f, {0x0f4,4778,100, 0,0,0x00,0xc4,0x38,0xf7,0x47,0x08,0x0}}, + {0x40, 0x4c, {0x0f5,3217,100, 0,0,0x00,0xc4,0x38,0xf7,0x47,0x08,0x0}}, + {0x4d, 0x5a, {0x0f5,3217,100, 0,0,0x00,0xc4,0x38,0xf7,0x48,0x08,0x0}}, + {0x5b, 0x7f, {0x0f5,3218,100, 0,0,0x00,0xc4,0x38,0xf7,0x48,0x18,0x0}} +}; +static const opl4_region_t regions_0d[] = { /* Xylophone */ + {0x00, 0x7f, {0x136,1729,100, 0,0,0x00,0xd2,0x38,0xf0,0x06,0x36,0x0}} +}; +static const opl4_region_t regions_0e[] = { /* Tubular Bell */ + {0x01, 0x7f, {0x0ff,3999,100, 0,1,0x00,0x90,0x21,0xf4,0xa3,0x25,0x1}} +}; +static const opl4_region_t regions_0f[] = { /* Dulcimer */ + {0x00, 0x7f, {0x03f,4236,100, 0,1,0x00,0xbc,0x29,0xf5,0x16,0x07,0x0}}, + {0x00, 0x7f, {0x040,4236,100, 0,2,0x0e,0x94,0x2a,0xf5,0x16,0x07,0x0}} +}; +static const opl4_region_t regions_10[] = { /* Drawbar Organ */ + {0x01, 0x7f, {0x08e,4394,100, 0,2,0x14,0xc2,0x3a,0xf0,0x00,0x0a,0x0}} +}; +static const opl4_region_t regions_11[] = { /* Percussive Organ */ + {0x15, 0x3b, {0x08c,6062,100, 0,3,0x00,0xbe,0x3b,0xf0,0x00,0x09,0x0}}, + {0x3c, 0x6c, {0x08d,2984,100, 0,3,0x00,0xbe,0x3b,0xf0,0x00,0x09,0x0}} +}; +static const opl4_region_t regions_12[] = { /* Rock Organ */ + {0x15, 0x30, {0x128,6574,100, 0,1,0x00,0xcc,0x39,0xf0,0x00,0x0a,0x0}}, + {0x31, 0x3c, {0x129,5040,100, 0,1,0x00,0xcc,0x39,0xf0,0x00,0x0a,0x0}}, + {0x3d, 0x48, {0x12a,3498,100, 0,1,0x00,0xcc,0x39,0xf0,0x00,0x0a,0x0}}, + {0x49, 0x54, {0x12b,1957,100, 0,1,0x00,0xcc,0x39,0xf0,0x00,0x0a,0x0}}, + {0x55, 0x6c, {0x127, 423,100, 0,1,0x00,0xcc,0x39,0xf0,0x00,0x0a,0x0}} +}; +static const opl4_region_t regions_13[] = { /* Church Organ */ + {0x15, 0x29, {0x087,7466,100, 0,1,0x00,0xc4,0x11,0xf0,0x00,0x09,0x0}}, + {0x2a, 0x30, {0x088,6456,100, 0,1,0x00,0xc4,0x11,0xf0,0x00,0x09,0x0}}, + {0x31, 0x38, {0x089,5428,100, 0,1,0x00,0xc4,0x11,0xf0,0x00,0x09,0x0}}, + {0x39, 0x41, {0x08a,4408,100, 0,1,0x00,0xc4,0x11,0xf0,0x00,0x09,0x0}}, + {0x42, 0x6c, {0x08b,3406,100, 0,1,0x00,0xc4,0x11,0xf0,0x00,0x09,0x0}} +}; +static const opl4_region_t regions_14[] = { /* Reed Organ */ + {0x00, 0x53, {0x0ac,5570,100, 0,0,0x06,0xc0,0x38,0xf0,0x00,0x09,0x1}}, + {0x54, 0x7f, {0x0ad,2497,100, 0,0,0x00,0xc0,0x38,0xf0,0x00,0x09,0x1}} +}; +static const opl4_region_t regions_15[] = { /* Accordion */ + {0x15, 0x4c, {0x006,4261,100, 0,2,0x00,0xa4,0x22,0x90,0x00,0x09,0x0}}, + {0x4d, 0x6c, {0x007,1530,100, 0,2,0x00,0xa4,0x22,0x90,0x00,0x09,0x0}}, + {0x15, 0x6c, {0x070,4391,100, 0,3,0x00,0x8a,0x23,0xa0,0x00,0x09,0x0}} +}; +static const opl4_region_t regions_16[] = { /* Harmonica */ + {0x15, 0x6c, {0x070,4408,100, 0,0,0x00,0xae,0x30,0xa0,0x00,0x09,0x2}} +}; +static const opl4_region_t regions_17[] = { /* Tango Accordion */ + {0x00, 0x53, {0x0ac,5573,100, 0,0,0x00,0xae,0x38,0xf0,0x00,0x09,0x0}}, + {0x54, 0x7f, {0x0ad,2500,100, 0,0,0x00,0xae,0x38,0xf0,0x00,0x09,0x0}}, + {0x15, 0x6c, {0x041,8479,100, 0,2,0x00,0x6a,0x3a,0x75,0x20,0x0a,0x0}} +}; +static const opl4_region_t regions_18[] = { /* Nylon Guitar */ + {0x15, 0x2f, {0x0b3,6964,100, 0,0,0x05,0xca,0x28,0xf5,0x34,0x09,0x0}}, + {0x30, 0x36, {0x0b7,5567,100, 0,0,0x0c,0xca,0x28,0xf5,0x34,0x09,0x0}}, + {0x37, 0x3c, {0x0b5,4653,100, 0,0,0x00,0xca,0x28,0xf6,0x34,0x09,0x0}}, + {0x3d, 0x43, {0x0b4,3892,100, 0,0,0x00,0xca,0x28,0xf6,0x35,0x09,0x0}}, + {0x44, 0x60, {0x0b6,2723,100, 0,0,0x00,0xca,0x28,0xf6,0x35,0x19,0x0}} +}; +static const opl4_region_t regions_19[] = { /* Steel Guitar */ + {0x15, 0x31, {0x00c,6937,100, 0,0,0x00,0xbc,0x28,0xf0,0x04,0x19,0x0}}, + {0x32, 0x38, {0x00d,5410,100, 0,0,0x00,0xbc,0x28,0xf0,0x05,0x09,0x0}}, + {0x39, 0x47, {0x00e,4379,100, 0,0,0x00,0xbc,0x28,0xf5,0x94,0x09,0x0}}, + {0x48, 0x6c, {0x00f,2843,100, 0,0,0x00,0xbc,0x28,0xf6,0x95,0x09,0x0}} +}; +static const opl4_region_t regions_1a[] = { /* Jazz Guitar */ + {0x15, 0x31, {0x05a,6832,100, 0,0,0x00,0xca,0x28,0xf6,0x34,0x09,0x0}}, + {0x32, 0x3f, {0x05b,4897,100, 0,0,0x00,0xca,0x28,0xf6,0x34,0x09,0x0}}, + {0x40, 0x6c, {0x05c,3218,100, 0,0,0x00,0xca,0x28,0xf6,0x34,0x09,0x0}} +}; +static const opl4_region_t regions_1b[] = { /* Clean Guitar */ + {0x15, 0x2c, {0x061,7053,100, 0,1,0x00,0xb4,0x29,0xf5,0x54,0x0a,0x0}}, + {0x2d, 0x31, {0x060,6434,100, 0,1,0x00,0xb4,0x29,0xf5,0x54,0x0a,0x0}}, + {0x32, 0x38, {0x063,5764,100, 0,1,0x00,0xbe,0x29,0xf5,0x55,0x0a,0x0}}, + {0x39, 0x3f, {0x062,4627,100, 0,1,0x00,0xb4,0x29,0xf5,0x55,0x0a,0x0}}, + {0x40, 0x44, {0x065,3963,100, 0,1,0x00,0xb4,0x29,0xf5,0x55,0x1a,0x0}}, + {0x45, 0x4b, {0x064,3313,100, 0,1,0x00,0xb4,0x29,0xf5,0x55,0x1a,0x0}}, + {0x4c, 0x54, {0x066,2462,100, 0,1,0x00,0xb4,0x29,0xf5,0x55,0x2a,0x0}}, + {0x55, 0x6c, {0x067,1307,100, 0,1,0x00,0xb4,0x29,0xf6,0x56,0x0a,0x0}} +}; +static const opl4_region_t regions_1c[] = { /* Muted Guitar */ + {0x01, 0x7f, {0x068,4408,100, 0,0,0x00,0xcc,0x28,0xf6,0x15,0x09,0x0}} +}; +static const opl4_region_t regions_1d[] = { /* Overdriven Guitar */ + {0x00, 0x40, {0x0a5,6589,100, 0,1,0x00,0xc0,0x29,0xf2,0x11,0x09,0x0}}, + {0x41, 0x7f, {0x0a6,5428,100, 0,1,0x00,0xc0,0x29,0xf2,0x11,0x09,0x0}} +}; +static const opl4_region_t regions_1e[] = { /* Distortion Guitar */ + {0x15, 0x2a, {0x051,6928,100, 0,1,0x00,0xbc,0x21,0xa2,0x12,0x0a,0x0}}, + {0x2b, 0x2e, {0x052,6433,100, 0,1,0x00,0xbc,0x21,0xa2,0x12,0x0a,0x0}}, + {0x2f, 0x32, {0x053,5944,100, 0,1,0x00,0xbc,0x21,0xa2,0x12,0x0a,0x0}}, + {0x33, 0x36, {0x054,5391,100, 0,1,0x00,0xbc,0x21,0xa2,0x12,0x0a,0x0}}, + {0x37, 0x3a, {0x055,4897,100, 0,1,0x00,0xbc,0x21,0xa2,0x12,0x0a,0x0}}, + {0x3b, 0x3e, {0x056,4408,100, 0,1,0x00,0xbc,0x21,0xa2,0x12,0x0a,0x0}}, + {0x3f, 0x42, {0x057,3892,100, 0,1,0x00,0xbc,0x21,0xa2,0x12,0x0a,0x0}}, + {0x43, 0x46, {0x058,3361,100, 0,1,0x00,0xbc,0x21,0xa2,0x12,0x0a,0x0}}, + {0x47, 0x6c, {0x059,2784,100, 0,1,0x00,0xbc,0x21,0xa2,0x12,0x0a,0x0}} +}; +static const opl4_region_t regions_1f[] = { /* Guitar Harmonics */ + {0x15, 0x44, {0x05e,5499,100, 0,0,0x00,0xce,0x28,0xf4,0x24,0x09,0x0}}, + {0x45, 0x49, {0x05d,4850,100, 0,0,0x00,0xe2,0x28,0xf4,0x24,0x09,0x0}}, + {0x4a, 0x6c, {0x05f,4259,100, 0,0,0x00,0xce,0x28,0xf4,0x24,0x09,0x0}} +}; +static const opl4_region_t regions_20[] = { /* Acoustic Bass */ + {0x15, 0x30, {0x004,8053,100, 0,0,0x00,0xe2,0x18,0xf5,0x15,0x09,0x0}}, + {0x31, 0x6c, {0x005,4754,100, 0,0,0x00,0xe2,0x18,0xf5,0x15,0x09,0x0}} +}; +static const opl4_region_t regions_21[] = { /* Fingered Bass */ + {0x01, 0x20, {0x04a,8762,100, 0,0,0x00,0xde,0x18,0xf6,0x14,0x09,0x0}}, + {0x21, 0x25, {0x04b,8114,100, 0,0,0x00,0xde,0x18,0xf6,0x14,0x09,0x0}}, + {0x26, 0x2a, {0x04c,7475,100, 0,0,0x00,0xde,0x18,0xf6,0x14,0x09,0x0}}, + {0x2b, 0x7f, {0x04d,6841,100, 0,0,0x00,0xde,0x18,0xf6,0x14,0x09,0x0}} +}; +static const opl4_region_t regions_22[] = { /* Picked Bass */ + {0x15, 0x23, {0x04f,7954,100, 0,0,0x00,0xcc,0x18,0xf3,0x90,0x0a,0x0}}, + {0x24, 0x2a, {0x050,7318,100, 0,0,0x05,0xcc,0x18,0xf3,0x90,0x1a,0x0}}, + {0x2b, 0x2f, {0x06b,6654,100, 0,0,0x00,0xcc,0x18,0xf3,0x90,0x2a,0x0}}, + {0x30, 0x47, {0x069,6031,100, 0,0,0x00,0xcc,0x18,0xf5,0xb0,0x0a,0x0}}, + {0x48, 0x6c, {0x06a,5393,100, 0,0,0x00,0xcc,0x18,0xf5,0xb0,0x0a,0x0}} +}; +static const opl4_region_t regions_23[] = { /* Fretless Bass */ + {0x01, 0x7f, {0x04e,5297,100, 0,0,0x00,0xd2,0x10,0xf3,0x63,0x19,0x0}} +}; +static const opl4_region_t regions_24[] = { /* Slap Bass 1 */ + {0x15, 0x6c, {0x0a3,7606,100, 0,1,0x00,0xde,0x19,0xf5,0x32,0x1a,0x0}} +}; +static const opl4_region_t regions_25[] = { /* Slap Bass 2 */ + {0x01, 0x7f, {0x0a2,6694,100, 0,0,0x00,0xda,0x20,0xb0,0x02,0x09,0x0}} +}; +static const opl4_region_t regions_26[] = { /* Synth Bass 1 */ + {0x15, 0x6c, {0x0be,7466,100, 0,1,0x00,0xb8,0x39,0xf4,0x14,0x09,0x0}} +}; +static const opl4_region_t regions_27[] = { /* Synth Bass 2 */ + {0x00, 0x7f, {0x117,8103,100, 0,1,0x00,0xca,0x39,0xf3,0x50,0x08,0x0}} +}; +static const opl4_region_t regions_28[] = { /* Violin */ + {0x15, 0x3a, {0x105,5158,100, 0,3,0x00,0xcc,0x3b,0xf3,0x20,0x09,0x0}}, + {0x3b, 0x3f, {0x102,4754,100, 0,3,0x00,0xcc,0x3b,0xf3,0x20,0x09,0x0}}, + {0x40, 0x41, {0x106,4132,100, 0,3,0x00,0xcc,0x3b,0xf3,0x20,0x09,0x0}}, + {0x42, 0x44, {0x107,4033,100, 0,3,0x00,0xcc,0x3b,0xf3,0x20,0x09,0x0}}, + {0x45, 0x47, {0x108,3580,100, 0,3,0x00,0xcc,0x3b,0xf3,0x20,0x09,0x0}}, + {0x48, 0x4a, {0x10a,2957,100, 0,3,0x00,0xcc,0x3b,0xf3,0x20,0x09,0x0}}, + {0x4b, 0x4c, {0x10b,2724,100, 0,3,0x00,0xcc,0x3b,0xf3,0x20,0x09,0x0}}, + {0x4d, 0x4e, {0x10c,2530,100, 0,3,0x00,0xcc,0x3b,0xf3,0x20,0x09,0x0}}, + {0x4f, 0x51, {0x10d,2166,100, 0,3,0x00,0xcc,0x3b,0xf3,0x20,0x09,0x0}}, + {0x52, 0x6c, {0x109,1825,100, 0,3,0x00,0xcc,0x3b,0xf3,0x20,0x09,0x0}} +}; +static const opl4_region_t regions_29[] = { /* Viola */ + {0x15, 0x32, {0x103,5780,100, 0,3,0x00,0xc4,0x3b,0xa3,0x20,0x09,0x0}}, + {0x33, 0x35, {0x104,5534,100, 0,3,0x00,0xc4,0x3b,0xa3,0x20,0x09,0x0}}, + {0x36, 0x38, {0x105,5158,100, 0,3,0x00,0xc4,0x3b,0xa3,0x20,0x09,0x0}}, + {0x39, 0x3d, {0x102,4754,100, 0,3,0x00,0xca,0x3b,0xa3,0x20,0x09,0x0}}, + {0x3e, 0x3f, {0x106,4132,100, 0,3,0x00,0xc4,0x3b,0xa3,0x20,0x09,0x0}}, + {0x40, 0x42, {0x107,4033,100, 0,3,0x00,0xc4,0x3b,0xa3,0x20,0x09,0x0}}, + {0x43, 0x45, {0x108,3580,100, 0,3,0x00,0xd0,0x3b,0xa3,0x20,0x09,0x0}}, + {0x46, 0x48, {0x10a,2957,100, 0,3,0x00,0xca,0x3b,0xa3,0x20,0x09,0x0}}, + {0x49, 0x4a, {0x10b,2724,100, 0,3,0x00,0xd0,0x3b,0xa3,0x20,0x09,0x0}}, + {0x4b, 0x4c, {0x10c,2530,100, 0,3,0x00,0xca,0x3b,0xa3,0x20,0x09,0x0}}, + {0x4d, 0x4f, {0x10d,2166,100, 0,3,0x00,0xd0,0x3b,0xa3,0x20,0x09,0x0}}, + {0x50, 0x6c, {0x109,1825,100, 0,3,0x00,0xd0,0x3b,0xa3,0x20,0x09,0x0}} +}; +static const opl4_region_t regions_2a[] = { /* Cello */ + {0x15, 0x2d, {0x112,6545,100, 0,3,0x00,0xc0,0x33,0xa0,0x00,0x08,0x0}}, + {0x2e, 0x37, {0x113,5764,100, 0,3,0x00,0xc0,0x33,0xa0,0x00,0x08,0x0}}, + {0x38, 0x3e, {0x115,4378,100, 0,3,0x00,0xc0,0x33,0xa0,0x00,0x18,0x0}}, + {0x3f, 0x44, {0x116,3998,100, 0,3,0x00,0xc0,0x33,0xa0,0x00,0x18,0x0}}, + {0x45, 0x6c, {0x114,3218,100, 0,3,0x00,0xc0,0x33,0xa0,0x00,0x18,0x0}} +}; +static const opl4_region_t regions_2b[] = { /* Contrabass */ + {0x15, 0x29, {0x110,7713,100, 0,1,0x00,0xc2,0x19,0x90,0x00,0x09,0x0}}, + {0x2a, 0x6c, {0x111,6162,100, 0,1,0x00,0xc2,0x19,0x90,0x00,0x09,0x0}} +}; +static const opl4_region_t regions_2c[] = { /* Tremolo Strings */ + {0x15, 0x3b, {0x0b0,4810,100, 0,0,0x0a,0xde,0x38,0xf0,0x00,0x07,0x6}}, + {0x3c, 0x41, {0x035,4035,100, 0,0,0x05,0xde,0x38,0xf0,0x00,0x07,0x6}}, + {0x42, 0x47, {0x033,3129,100, 0,0,0x05,0xde,0x38,0xf0,0x00,0x07,0x6}}, + {0x48, 0x52, {0x034,2625,100, 0,0,0x05,0xde,0x38,0xf0,0x00,0x07,0x6}}, + {0x53, 0x6c, {0x0af, 936,100, 0,0,0x00,0xde,0x38,0xf0,0x00,0x07,0x6}} +}; +static const opl4_region_t regions_2d[] = { /* Pizzicato Strings */ + {0x15, 0x32, {0x0b8,6186,100, 0,0,0x00,0xbc,0x28,0xf0,0x00,0x05,0x0}}, + {0x33, 0x3b, {0x0b9,5031,100, 0,0,0x00,0xbc,0x28,0xf0,0x00,0x05,0x0}}, + {0x3c, 0x42, {0x0bb,4146,100, 0,0,0x00,0xbc,0x28,0xf0,0x00,0x05,0x0}}, + {0x43, 0x48, {0x0ba,3245,100, 0,0,0x00,0xc2,0x28,0xf0,0x00,0x05,0x0}}, + {0x49, 0x6c, {0x0bc,2352,100, 0,0,0x00,0xbc,0x28,0xf0,0x00,0x05,0x0}} +}; +static const opl4_region_t regions_2e[] = { /* Harp */ + {0x15, 0x46, {0x07e,3740,100, 0,1,0x00,0xd2,0x29,0xf5,0x25,0x07,0x0}}, + {0x47, 0x6c, {0x07f,2319,100, 0,1,0x00,0xd2,0x29,0xf5,0x25,0x07,0x0}} +}; +static const opl4_region_t regions_2f[] = { /* Timpani */ + {0x15, 0x6c, {0x100,6570,100, 0,0,0x00,0xf8,0x28,0xf0,0x05,0x16,0x0}} +}; +static const opl4_region_t regions_30[] = { /* Strings */ + {0x15, 0x3b, {0x13c,4806,100, 0,0,0x00,0xc8,0x20,0x80,0x00,0x07,0x0}}, + {0x3c, 0x41, {0x13e,4035,100, 0,0,0x00,0xc8,0x20,0x80,0x00,0x07,0x0}}, + {0x42, 0x47, {0x13d,3122,100, 0,0,0x00,0xc8,0x20,0x80,0x00,0x07,0x0}}, + {0x48, 0x52, {0x13f,2629,100, 0,0,0x00,0xbe,0x20,0x80,0x00,0x07,0x0}}, + {0x53, 0x6c, {0x140, 950,100, 0,0,0x00,0xbe,0x20,0x80,0x00,0x07,0x0}} +}; +static const opl4_region_t regions_31[] = { /* Slow Strings */ + {0x15, 0x3b, {0x0b0,4810,100, 0,1,0x0a,0xbe,0x19,0xf0,0x00,0x07,0x0}}, + {0x3c, 0x41, {0x035,4035,100, 0,1,0x05,0xbe,0x19,0xf0,0x00,0x07,0x0}}, + {0x42, 0x47, {0x033,3129,100, 0,1,0x05,0xbe,0x19,0xf0,0x00,0x07,0x0}}, + {0x48, 0x52, {0x034,2625,100, 0,1,0x05,0xbe,0x19,0xf0,0x00,0x07,0x0}}, + {0x53, 0x6c, {0x0af, 936,100, 0,1,0x00,0xbe,0x19,0xf0,0x00,0x07,0x0}} +}; +static const opl4_region_t regions_32[] = { /* Synth Strings 1 */ + {0x05, 0x71, {0x002,6045,100,-2,0,0x00,0xa6,0x20,0x93,0x22,0x06,0x0}}, + {0x15, 0x6c, {0x0ae,3261,100, 2,0,0x00,0xc6,0x20,0x70,0x01,0x06,0x0}} +}; +static const opl4_region_t regions_33[] = { /* Synth Strings 2 */ + {0x15, 0x6c, {0x002,4513,100, 5,1,0x00,0xb4,0x19,0x70,0x00,0x06,0x0}}, + {0x15, 0x6c, {0x002,4501,100,-5,1,0x00,0xb4,0x19,0x70,0x00,0x06,0x0}} +}; +static const opl4_region_t regions_34[] = { /* Choir Aahs */ + {0x15, 0x3a, {0x018,5010,100, 0,2,0x00,0xc2,0x1a,0x70,0x00,0x08,0x0}}, + {0x3b, 0x40, {0x019,4370,100, 0,2,0x00,0xc2,0x1a,0x70,0x00,0x08,0x0}}, + {0x41, 0x47, {0x01a,3478,100, 0,2,0x00,0xc2,0x1a,0x70,0x00,0x08,0x0}}, + {0x48, 0x6c, {0x01b,2197,100, 0,2,0x00,0xc2,0x1a,0x70,0x00,0x08,0x0}} +}; +static const opl4_region_t regions_35[] = { /* Voice Oohs */ + {0x15, 0x6c, {0x029,3596,100, 0,0,0x00,0xe6,0x20,0xf7,0x20,0x08,0x0}} +}; +static const opl4_region_t regions_36[] = { /* Synth Voice */ + {0x15, 0x6c, {0x02a,3482,100, 0,1,0x00,0xc2,0x19,0x85,0x21,0x07,0x0}} +}; +static const opl4_region_t regions_37[] = { /* Orchestra Hit */ + {0x15, 0x6c, {0x049,4394,100, 0,0,0x00,0xfe,0x30,0x80,0x05,0x05,0x0}} +}; +static const opl4_region_t regions_38[] = { /* Trumpet */ + {0x15, 0x3c, {0x0f6,4706,100, 0,2,0x00,0xd6,0x32,0xf3,0x20,0x0a,0x0}}, + {0x3d, 0x43, {0x0f8,3894,100, 0,2,0x00,0xd6,0x32,0xf3,0x20,0x0a,0x0}}, + {0x44, 0x48, {0x0f7,3118,100, 0,2,0x00,0xd6,0x32,0xf3,0x20,0x0a,0x0}}, + {0x49, 0x4e, {0x0fa,2322,100, 0,2,0x00,0xd6,0x32,0xf3,0x20,0x0a,0x0}}, + {0x4f, 0x55, {0x0f9,1634,100, 0,2,0x00,0xd6,0x32,0xf3,0x20,0x0a,0x0}}, + {0x56, 0x6c, {0x0fb, 786,100, 0,2,0x00,0xd6,0x32,0xf3,0x20,0x0a,0x0}} +}; +static const opl4_region_t regions_39[] = { /* Trombone */ + {0x15, 0x3a, {0x0f0,5053,100, 0,1,0x00,0xd6,0x21,0xf0,0x00,0x09,0x0}}, + {0x3b, 0x3f, {0x0f1,4290,100, 0,1,0x00,0xd6,0x21,0xf0,0x00,0x09,0x0}}, + {0x40, 0x6c, {0x0f2,3580,100, 0,1,0x00,0xd6,0x21,0xf0,0x00,0x09,0x0}} +}; +static const opl4_region_t regions_3a[] = { /* Tuba */ + {0x15, 0x2d, {0x085,7096,100, 0,1,0x00,0xde,0x21,0xf5,0x10,0x09,0x0}}, + {0x2e, 0x6c, {0x086,6014,100, 0,1,0x00,0xde,0x21,0xf5,0x10,0x09,0x0}} +}; +static const opl4_region_t regions_3b[] = { /* Muted Trumpet */ + {0x15, 0x45, {0x0b1,4135,100, 0,0,0x00,0xcc,0x28,0xf3,0x10,0x0a,0x1}}, + {0x46, 0x6c, {0x0b2,2599,100, 0,0,0x00,0xcc,0x28,0x83,0x10,0x0a,0x1}} +}; +static const opl4_region_t regions_3c[] = { /* French Horns */ + {0x15, 0x49, {0x07c,3624,100, 0,2,0x00,0xd0,0x1a,0xf0,0x00,0x09,0x0}}, + {0x4a, 0x6c, {0x07d,2664,100, 0,2,0x00,0xd0,0x1a,0xf0,0x00,0x09,0x0}} +}; +static const opl4_region_t regions_3d[] = { /* Brass Section */ + {0x15, 0x42, {0x0fc,4375,100, 0,0,0x00,0xd6,0x28,0xf0,0x00,0x0a,0x0}}, + {0x43, 0x6c, {0x0fd,2854,100, 0,0,0x00,0xd6,0x28,0xf0,0x00,0x0a,0x0}} +}; +static const opl4_region_t regions_3e[] = { /* Synth Brass 1 */ + {0x01, 0x27, {0x0d3,9094,100,-1,0,0x00,0xbe,0x18,0xa5,0x11,0x08,0x0}}, + {0x28, 0x2d, {0x0da,8335,100,-1,0,0x00,0xbe,0x18,0xa5,0x11,0x08,0x0}}, + {0x2e, 0x33, {0x0d4,7558,100,-1,0,0x00,0xbe,0x18,0xa5,0x11,0x08,0x0}}, + {0x34, 0x39, {0x0db,6785,100,-1,0,0x00,0xbe,0x18,0xa5,0x11,0x08,0x0}}, + {0x3a, 0x3f, {0x0d5,6042,100,-1,0,0x00,0xbe,0x18,0xa5,0x11,0x08,0x0}}, + {0x40, 0x45, {0x0dc,5257,100,-1,0,0x00,0xbe,0x18,0xa5,0x11,0x08,0x0}}, + {0x46, 0x4b, {0x0d6,4493,100,-1,0,0x00,0xbe,0x18,0xa5,0x11,0x08,0x0}}, + {0x4c, 0x51, {0x0dd,3741,100,-1,0,0x00,0xbe,0x18,0xa5,0x11,0x08,0x0}}, + {0x52, 0x57, {0x0d7,3012,100,-1,0,0x00,0xbe,0x18,0xa5,0x11,0x08,0x0}}, + {0x58, 0x5d, {0x0de,2167,100,-1,0,0x00,0xbe,0x18,0xa5,0x11,0x08,0x0}}, + {0x5e, 0x63, {0x0d8,1421,100,-1,0,0x00,0xbe,0x18,0xa5,0x11,0x08,0x0}}, + {0x64, 0x7f, {0x0d9,-115,100,-1,0,0x00,0xbe,0x18,0xa5,0x11,0x08,0x0}}, + {0x01, 0x27, {0x118,9103,100, 1,1,0x00,0xbe,0x19,0x85,0x23,0x08,0x0}}, + {0x28, 0x2d, {0x119,8340,100, 1,1,0x00,0xbe,0x19,0x85,0x23,0x08,0x0}}, + {0x2e, 0x33, {0x11a,7565,100, 1,1,0x00,0xbe,0x19,0x85,0x23,0x08,0x0}}, + {0x34, 0x39, {0x11b,6804,100, 1,1,0x00,0xbe,0x19,0x85,0x23,0x08,0x0}}, + {0x3a, 0x3f, {0x11c,6042,100, 1,1,0x00,0xbe,0x19,0x85,0x23,0x08,0x0}}, + {0x40, 0x45, {0x11d,5277,100, 1,1,0x00,0xbe,0x19,0x85,0x23,0x08,0x0}}, + {0x46, 0x4b, {0x11e,4520,100, 1,1,0x00,0xbe,0x19,0x85,0x23,0x08,0x0}}, + {0x4c, 0x51, {0x11f,3741,100, 1,1,0x00,0xbe,0x19,0x85,0x23,0x08,0x0}}, + {0x52, 0x57, {0x120,3012,100, 1,1,0x00,0xbe,0x19,0x85,0x23,0x08,0x0}}, + {0x58, 0x5d, {0x121,2166,100, 1,1,0x00,0xbe,0x19,0x85,0x23,0x08,0x0}}, + {0x5e, 0x64, {0x122,1421,100, 1,1,0x00,0xbe,0x19,0x85,0x23,0x08,0x0}}, + {0x65, 0x7f, {0x123,-115,100, 1,1,0x00,0xbe,0x19,0x85,0x23,0x08,0x0}} +}; +static const opl4_region_t regions_3f[] = { /* Synth Brass 2 */ + {0x01, 0x27, {0x118,9113,100, 3,6,0x00,0xae,0x26,0x85,0x23,0x08,0x0}}, + {0x28, 0x2d, {0x119,8350,100, 3,6,0x00,0xae,0x26,0x85,0x23,0x08,0x0}}, + {0x2e, 0x33, {0x11a,7575,100, 3,6,0x00,0xae,0x26,0x85,0x23,0x08,0x0}}, + {0x34, 0x39, {0x11b,6814,100, 3,6,0x00,0xae,0x26,0x85,0x23,0x08,0x0}}, + {0x3a, 0x3f, {0x11c,6052,100, 3,6,0x00,0xae,0x26,0x85,0x23,0x08,0x0}}, + {0x40, 0x45, {0x11d,5287,100, 3,6,0x00,0xae,0x26,0x85,0x23,0x08,0x0}}, + {0x46, 0x4b, {0x11e,4530,100, 3,6,0x00,0xae,0x26,0x85,0x23,0x08,0x0}}, + {0x4c, 0x51, {0x11f,3751,100, 3,6,0x00,0xae,0x26,0x85,0x23,0x08,0x0}}, + {0x52, 0x57, {0x120,3022,100, 3,6,0x00,0xae,0x26,0x85,0x23,0x08,0x0}}, + {0x58, 0x5d, {0x121,2176,100, 3,6,0x00,0xae,0x26,0x85,0x23,0x08,0x0}}, + {0x5e, 0x64, {0x122,1431,100, 3,6,0x00,0xae,0x26,0x85,0x23,0x08,0x0}}, + {0x65, 0x7f, {0x123,-105,100, 3,6,0x00,0xae,0x26,0x85,0x23,0x08,0x0}}, + {0x00, 0x7f, {0x124,4034,100,-3,2,0x00,0xea,0x22,0x85,0x23,0x08,0x0}} +}; +static const opl4_region_t regions_40[] = { /* Soprano Sax */ + {0x15, 0x3f, {0x0e3,4228,100, 0,1,0x00,0xc8,0x21,0xf5,0x20,0x0a,0x0}}, + {0x40, 0x45, {0x0e4,3495,100, 0,1,0x00,0xc8,0x21,0xf5,0x20,0x0a,0x0}}, + {0x46, 0x4b, {0x0e5,2660,100, 0,1,0x00,0xd6,0x21,0xf5,0x20,0x0a,0x0}}, + {0x4c, 0x51, {0x0e6,2002,100, 0,1,0x00,0xd6,0x21,0xf5,0x20,0x0a,0x0}}, + {0x52, 0x59, {0x0e7,1186,100, 0,1,0x00,0xd6,0x21,0xf5,0x20,0x0a,0x0}}, + {0x59, 0x6c, {0x0e8,1730,100, 0,1,0x00,0xc8,0x21,0xf5,0x20,0x0a,0x0}} +}; +static const opl4_region_t regions_41[] = { /* Alto Sax */ + {0x15, 0x32, {0x092,6204,100, 0,1,0x00,0xbe,0x19,0xf5,0x20,0x0b,0x0}}, + {0x33, 0x35, {0x096,5812,100, 0,1,0x00,0xbe,0x19,0xf5,0x20,0x0b,0x0}}, + {0x36, 0x3a, {0x099,5318,100, 0,1,0x00,0xbe,0x19,0xf5,0x20,0x0b,0x0}}, + {0x3b, 0x3b, {0x08f,5076,100, 0,1,0x00,0xbe,0x19,0xf5,0x20,0x0b,0x0}}, + {0x3c, 0x3e, {0x093,4706,100, 0,1,0x00,0xbe,0x19,0xf5,0x20,0x0b,0x0}}, + {0x3f, 0x41, {0x097,4321,100, 0,1,0x00,0xbe,0x19,0xf5,0x20,0x0b,0x0}}, + {0x42, 0x44, {0x09a,3893,100, 0,1,0x00,0xbe,0x19,0xf5,0x20,0x0b,0x0}}, + {0x45, 0x47, {0x090,3497,100, 0,1,0x00,0xbe,0x19,0xf5,0x20,0x0b,0x0}}, + {0x48, 0x4a, {0x094,3119,100, 0,1,0x00,0xbe,0x19,0xf5,0x20,0x0b,0x0}}, + {0x4b, 0x4d, {0x098,2726,100, 0,1,0x00,0xbe,0x19,0xf5,0x20,0x0b,0x0}}, + {0x4e, 0x50, {0x09b,2393,100, 0,1,0x00,0xbe,0x19,0xf5,0x20,0x0b,0x0}}, + {0x51, 0x53, {0x091,2088,100, 0,1,0x00,0xbe,0x19,0xf5,0x20,0x0b,0x0}}, + {0x54, 0x6c, {0x095,1732,100, 0,1,0x00,0xbe,0x19,0xf5,0x20,0x0b,0x0}} +}; +static const opl4_region_t regions_42[] = { /* Tenor Sax */ + {0x24, 0x30, {0x0e9,6301,100, 0,1,0x00,0xbc,0x19,0xf4,0x10,0x0b,0x0}}, + {0x31, 0x34, {0x0ea,5781,100, 0,1,0x00,0xbc,0x19,0xf4,0x10,0x0b,0x0}}, + {0x35, 0x3a, {0x0eb,5053,100, 0,1,0x00,0xbc,0x19,0xf4,0x10,0x0b,0x0}}, + {0x3b, 0x41, {0x0ed,4165,100, 0,1,0x00,0xbc,0x19,0xf4,0x10,0x0b,0x0}}, + {0x42, 0x47, {0x0ec,3218,100, 0,1,0x00,0xbc,0x19,0xf4,0x10,0x0b,0x0}}, + {0x48, 0x51, {0x0ee,2462,100, 0,1,0x00,0xbc,0x19,0xf4,0x10,0x0b,0x0}}, + {0x52, 0x6c, {0x0ef,1421,100, 0,1,0x00,0xbc,0x19,0xf4,0x10,0x0b,0x0}} +}; +static const opl4_region_t regions_43[] = { /* Baritone Sax */ + {0x15, 0x2d, {0x0df,6714,100, 0,1,0x00,0xce,0x19,0xf0,0x00,0x0a,0x0}}, + {0x2e, 0x34, {0x0e1,5552,100, 0,1,0x00,0xce,0x19,0xf0,0x00,0x0a,0x0}}, + {0x35, 0x39, {0x0e2,5178,100, 0,1,0x00,0xce,0x19,0xf0,0x00,0x0a,0x0}}, + {0x3a, 0x6c, {0x0e0,4437,100, 0,1,0x00,0xce,0x19,0xf0,0x00,0x0a,0x0}} +}; +static const opl4_region_t regions_44[] = { /* Oboe */ + {0x15, 0x3c, {0x042,4493,100, 0,1,0x00,0xe6,0x39,0xf4,0x10,0x0a,0x0}}, + {0x3d, 0x43, {0x044,3702,100, 0,1,0x00,0xdc,0x39,0xf4,0x10,0x0a,0x0}}, + {0x44, 0x49, {0x043,2956,100, 0,1,0x00,0xdc,0x39,0xf4,0x10,0x0a,0x0}}, + {0x4a, 0x4f, {0x046,2166,100, 0,1,0x00,0xdc,0x39,0xf4,0x10,0x0a,0x0}}, + {0x50, 0x55, {0x045,1420,100, 0,1,0x00,0xdc,0x39,0xf4,0x10,0x0a,0x0}}, + {0x56, 0x6c, {0x047, 630,100, 0,1,0x00,0xe6,0x39,0xf4,0x10,0x0a,0x0}} +}; +static const opl4_region_t regions_45[] = { /* English Horn */ + {0x15, 0x38, {0x03c,5098,100, 0,1,0x00,0xc4,0x31,0xf0,0x00,0x09,0x0}}, + {0x39, 0x3e, {0x03b,4291,100, 0,1,0x00,0xc4,0x31,0xf0,0x00,0x09,0x0}}, + {0x3f, 0x6c, {0x03d,3540,100, 0,1,0x00,0xc4,0x31,0xf0,0x00,0x09,0x0}} +}; +static const opl4_region_t regions_46[] = { /* Bassoon */ + {0x15, 0x22, {0x038,7833,100, 0,1,0x00,0xc6,0x31,0xf0,0x00,0x0b,0x0}}, + {0x23, 0x2e, {0x03a,7070,100, 0,1,0x00,0xc6,0x31,0xf0,0x00,0x0b,0x0}}, + {0x2f, 0x6c, {0x039,6302,100, 0,1,0x00,0xc6,0x31,0xf0,0x00,0x0b,0x0}} +}; +static const opl4_region_t regions_47[] = { /* Clarinet */ + {0x15, 0x3b, {0x09e,5900,100, 0,1,0x00,0xc8,0x29,0xf3,0x20,0x0a,0x0}}, + {0x3c, 0x41, {0x0a0,5158,100, 0,1,0x00,0xc8,0x29,0xf3,0x20,0x0a,0x0}}, + {0x42, 0x4a, {0x09f,4260,100, 0,1,0x00,0xc8,0x29,0xf3,0x20,0x0a,0x0}}, + {0x4b, 0x6c, {0x0a1,2957,100, 0,1,0x00,0xc8,0x29,0xf3,0x20,0x0a,0x0}} +}; +static const opl4_region_t regions_48[] = { /* Piccolo */ + {0x15, 0x40, {0x071,4803,100, 0,0,0x00,0xe6,0x38,0xf0,0x00,0x0a,0x2}}, + {0x41, 0x4d, {0x072,3314,100, 0,0,0x00,0xe6,0x38,0xf0,0x00,0x0a,0x2}}, + {0x4e, 0x53, {0x073,1731,100, 0,0,0x00,0xe6,0x38,0xf0,0x00,0x0a,0x2}}, + {0x54, 0x5f, {0x074,2085,100, 0,0,0x00,0xe6,0x38,0xf0,0x00,0x0a,0x2}}, + {0x60, 0x6c, {0x075,1421,100, 0,0,0x00,0xe6,0x38,0xf0,0x00,0x0a,0x2}} +}; +static const opl4_region_t regions_49[] = { /* Flute */ + {0x15, 0x40, {0x071,4803,100, 0,0,0x00,0xdc,0x38,0xf0,0x00,0x0a,0x2}}, + {0x41, 0x4d, {0x072,3314,100, 0,0,0x00,0xdc,0x38,0xf0,0x00,0x0a,0x2}}, + {0x4e, 0x6c, {0x073,1731,100, 0,0,0x00,0xe6,0x38,0xf0,0x00,0x0a,0x2}} +}; +static const opl4_region_t regions_4a[] = { /* Recorder */ + {0x15, 0x6f, {0x0bd,4897,100, 0,0,0x00,0xec,0x30,0x70,0x00,0x09,0x1}} +}; +static const opl4_region_t regions_4b[] = { /* Pan Flute */ + {0x15, 0x6c, {0x077,2359,100, 0,0,0x00,0xde,0x38,0xf0,0x00,0x09,0x3}} +}; +static const opl4_region_t regions_4c[] = { /* Bottle Blow */ + {0x15, 0x6c, {0x077,2359,100, 0,0,0x00,0xc8,0x38,0xf0,0x00,0x09,0x1}}, + {0x01, 0x7f, {0x125,7372,100, 0,0,0x1e,0x80,0x00,0xf0,0x00,0x09,0x0}} +}; +static const opl4_region_t regions_4d[] = { /* Shakuhachi */ + {0x00, 0x7f, {0x0ab,4548,100, 0,0,0x00,0xd6,0x30,0xf0,0x00,0x0a,0x3}}, + {0x15, 0x6c, {0x076,3716,100, 0,0,0x00,0xa2,0x28,0x70,0x00,0x09,0x2}} +}; +static const opl4_region_t regions_4e[] = { /* Whistle */ + {0x00, 0x7f, {0x0aa,1731,100, 0,4,0x00,0xd2,0x2c,0x70,0x00,0x0a,0x0}} +}; +static const opl4_region_t regions_4f[] = { /* Ocarina */ + {0x00, 0x7f, {0x0aa,1731,100, 0,1,0x00,0xce,0x29,0x90,0x00,0x0a,0x1}} +}; +static const opl4_region_t regions_50[] = { /* Square Lead */ + {0x01, 0x2a, {0x0cc,9853,100, 3,0,0x00,0xac,0x38,0xc6,0x21,0x09,0x0}}, + {0x2b, 0x36, {0x0cd,6785,100, 3,0,0x00,0xac,0x38,0xc6,0x21,0x09,0x0}}, + {0x37, 0x42, {0x0ca,5248,100, 3,0,0x00,0xac,0x38,0xc6,0x21,0x09,0x0}}, + {0x43, 0x4e, {0x0cf,3713,100, 3,0,0x00,0xac,0x38,0xc6,0x21,0x09,0x0}}, + {0x4f, 0x5a, {0x0ce,2176,100, 3,0,0x00,0xac,0x38,0xc6,0x21,0x09,0x0}}, + {0x5b, 0x7f, {0x0cb, 640,100, 3,0,0x00,0xac,0x38,0xc6,0x21,0x09,0x0}}, + {0x01, 0x2a, {0x0cc,9844,100,-3,0,0x00,0xac,0x08,0xc6,0x21,0x09,0x0}}, + {0x2b, 0x36, {0x0cd,6776,100,-3,0,0x00,0xac,0x08,0xc6,0x21,0x09,0x0}}, + {0x37, 0x42, {0x0ca,5239,100,-3,0,0x00,0xac,0x08,0xc6,0x21,0x09,0x0}}, + {0x43, 0x4e, {0x0cf,3704,100,-3,0,0x00,0xac,0x08,0xc6,0x21,0x09,0x0}}, + {0x4f, 0x5a, {0x0ce,2167,100,-3,0,0x00,0xac,0x08,0xc6,0x21,0x09,0x0}}, + {0x5b, 0x7f, {0x0cb, 631,100,-3,0,0x00,0xac,0x08,0xc6,0x21,0x09,0x0}} +}; +static const opl4_region_t regions_51[] = { /* Sawtooth Lead */ + {0x01, 0x27, {0x118,9108,100, 0,0,0x00,0xc8,0x30,0xf2,0x22,0x0a,0x0}}, + {0x28, 0x2d, {0x119,8345,100, 0,0,0x00,0xc8,0x30,0xf2,0x22,0x0a,0x0}}, + {0x2e, 0x33, {0x11a,7570,100, 0,0,0x00,0xc8,0x30,0xf2,0x22,0x0a,0x0}}, + {0x34, 0x39, {0x11b,6809,100, 0,0,0x00,0xc8,0x30,0xf2,0x22,0x0a,0x0}}, + {0x3a, 0x3f, {0x11c,6047,100, 0,0,0x00,0xc8,0x30,0xf2,0x22,0x0a,0x0}}, + {0x40, 0x45, {0x11d,5282,100, 0,0,0x00,0xc8,0x30,0xf2,0x22,0x0a,0x0}}, + {0x46, 0x4b, {0x11e,4525,100, 0,0,0x00,0xc8,0x30,0xf2,0x22,0x0a,0x0}}, + {0x4c, 0x51, {0x11f,3746,100, 0,0,0x00,0xc8,0x30,0xf2,0x22,0x0a,0x0}}, + {0x52, 0x57, {0x120,3017,100, 0,0,0x00,0xc8,0x30,0xf2,0x22,0x0a,0x0}}, + {0x58, 0x5d, {0x121,2171,100, 0,0,0x00,0xc8,0x30,0xf2,0x22,0x0a,0x0}}, + {0x5e, 0x66, {0x122,1426,100, 0,0,0x00,0xc8,0x30,0xf2,0x22,0x0a,0x0}}, + {0x67, 0x7f, {0x123,-110,100, 0,0,0x00,0xc8,0x30,0xf2,0x22,0x0a,0x0}}, + {0x01, 0x27, {0x118,9098,100, 0,0,0x00,0xc8,0x30,0xf2,0x22,0x0a,0x0}}, + {0x28, 0x2d, {0x119,8335,100, 0,0,0x00,0xc8,0x30,0xf2,0x22,0x0a,0x0}}, + {0x2e, 0x33, {0x11a,7560,100, 0,0,0x00,0xc8,0x30,0xf2,0x22,0x0a,0x0}}, + {0x34, 0x39, {0x11b,6799,100, 0,0,0x00,0xc8,0x30,0xf2,0x22,0x0a,0x0}}, + {0x3a, 0x3f, {0x11c,6037,100, 0,0,0x00,0xc8,0x30,0xf2,0x22,0x0a,0x0}}, + {0x40, 0x45, {0x11d,5272,100, 0,0,0x00,0xc8,0x30,0xf2,0x22,0x0a,0x0}}, + {0x46, 0x4b, {0x11e,4515,100, 0,0,0x00,0xc8,0x30,0xf2,0x22,0x0a,0x0}}, + {0x4c, 0x51, {0x11f,3736,100, 0,0,0x00,0xc8,0x30,0xf2,0x22,0x0a,0x0}}, + {0x52, 0x57, {0x120,3007,100, 0,0,0x00,0xc8,0x30,0xf2,0x22,0x0a,0x0}}, + {0x58, 0x5d, {0x121,2161,100, 0,0,0x00,0xc8,0x30,0xf2,0x22,0x0a,0x0}}, + {0x5e, 0x66, {0x122,1416,100, 0,0,0x00,0xc8,0x30,0xf2,0x22,0x0a,0x0}}, + {0x67, 0x7f, {0x123,-120,100, 0,0,0x00,0xc8,0x30,0xf2,0x22,0x0a,0x0}} +}; +static const opl4_region_t regions_52[] = { /* Calliope Lead */ + {0x00, 0x7f, {0x0aa,1731,100, 0,0,0x00,0xc2,0x28,0x90,0x00,0x0a,0x2}}, + {0x15, 0x6c, {0x076,3716,100, 0,0,0x00,0xb6,0x28,0xb0,0x00,0x09,0x2}} +}; +static const opl4_region_t regions_53[] = { /* Chiffer Lead */ + {0x00, 0x7f, {0x13a,3665,100, 0,2,0x00,0xcc,0x2a,0xf0,0x10,0x09,0x1}}, + {0x01, 0x7f, {0x0fe,3660,100, 0,0,0x00,0xbe,0x28,0xf3,0x10,0x17,0x0}} +}; +static const opl4_region_t regions_54[] = { /* Charang Lead */ + {0x00, 0x40, {0x0a5,6594,100, 0,3,0x00,0xba,0x33,0xf2,0x11,0x09,0x0}}, + {0x41, 0x7f, {0x0a6,5433,100, 0,3,0x00,0xba,0x33,0xf2,0x11,0x09,0x0}}, + {0x01, 0x27, {0x118,9098,100, 0,2,0x00,0xa4,0x2a,0xf2,0x22,0x0e,0x0}}, + {0x28, 0x2d, {0x119,8335,100, 0,2,0x00,0xa4,0x2a,0xf2,0x22,0x0e,0x0}}, + {0x2e, 0x33, {0x11a,7560,100, 0,2,0x00,0xa4,0x2a,0xf2,0x22,0x0e,0x0}}, + {0x34, 0x39, {0x11b,6799,100, 0,2,0x00,0xa4,0x2a,0xf2,0x22,0x0e,0x0}}, + {0x3a, 0x3f, {0x11c,6037,100, 0,2,0x00,0xa4,0x2a,0xf2,0x22,0x0e,0x0}}, + {0x40, 0x45, {0x11d,5272,100, 0,2,0x00,0xa4,0x2a,0xf2,0x22,0x0e,0x0}}, + {0x46, 0x4b, {0x11e,4515,100, 0,2,0x00,0xa4,0x2a,0xf2,0x22,0x0e,0x0}}, + {0x4c, 0x51, {0x11f,3736,100, 0,2,0x00,0xa4,0x2a,0xf2,0x22,0x0e,0x0}}, + {0x52, 0x57, {0x120,3007,100, 0,2,0x00,0xa4,0x2a,0xf2,0x22,0x0e,0x0}}, + {0x58, 0x5d, {0x121,2161,100, 0,2,0x00,0xa4,0x2a,0xf2,0x22,0x0e,0x0}}, + {0x5e, 0x66, {0x122,1416,100, 0,2,0x00,0xa4,0x2a,0xf2,0x22,0x0e,0x0}}, + {0x67, 0x7f, {0x123,-120,100, 0,2,0x00,0xa4,0x2a,0xf2,0x22,0x0e,0x0}} +}; +static const opl4_region_t regions_55[] = { /* Voice Lead */ + {0x00, 0x7f, {0x0aa,1739,100, 0,6,0x00,0x8c,0x2e,0x90,0x00,0x0a,0x0}}, + {0x15, 0x6c, {0x02a,3474,100, 0,1,0x00,0xd8,0x29,0xf0,0x05,0x0a,0x0}} +}; +static const opl4_region_t regions_56[] = { /* 5ths Lead */ + {0x01, 0x27, {0x118,8468,100, 0,2,0x00,0xd0,0x32,0xf5,0x20,0x08,0x0}}, + {0x28, 0x2d, {0x119,7705,100, 0,2,0x00,0xd0,0x32,0xf5,0x20,0x08,0x0}}, + {0x2e, 0x33, {0x11a,6930,100, 0,2,0x00,0xd0,0x32,0xf5,0x20,0x08,0x0}}, + {0x34, 0x39, {0x11b,6169,100, 0,2,0x00,0xd0,0x32,0xf5,0x20,0x08,0x0}}, + {0x3a, 0x3f, {0x11c,5407,100, 0,2,0x00,0xd0,0x32,0xf5,0x20,0x08,0x0}}, + {0x40, 0x45, {0x11d,4642,100, 0,2,0x00,0xd0,0x32,0xf5,0x20,0x08,0x0}}, + {0x46, 0x4b, {0x11e,3885,100, 0,2,0x00,0xd0,0x32,0xf5,0x20,0x08,0x0}}, + {0x4c, 0x51, {0x11f,3106,100, 0,2,0x00,0xd0,0x32,0xf5,0x20,0x08,0x0}}, + {0x52, 0x57, {0x120,2377,100, 0,2,0x00,0xd0,0x32,0xf5,0x20,0x08,0x0}}, + {0x58, 0x5d, {0x121,1531,100, 0,2,0x00,0xd0,0x32,0xf5,0x20,0x08,0x0}}, + {0x5e, 0x64, {0x122, 786,100, 0,2,0x00,0xd0,0x32,0xf5,0x20,0x08,0x0}}, + {0x65, 0x7f, {0x123,-750,100, 0,2,0x00,0xd0,0x32,0xf5,0x20,0x08,0x0}}, + {0x05, 0x71, {0x002,4503,100, 0,1,0x00,0xb8,0x31,0xb3,0x20,0x0b,0x0}} +}; +static const opl4_region_t regions_57[] = { /* Bass & Lead */ + {0x00, 0x7f, {0x117,8109,100, 0,1,0x00,0xbc,0x29,0xf3,0x50,0x08,0x0}}, + {0x01, 0x27, {0x118,9097,100, 0,2,0x00,0xbc,0x2a,0xf2,0x20,0x0a,0x0}}, + {0x28, 0x2d, {0x119,8334,100, 0,2,0x00,0xbc,0x2a,0xf2,0x20,0x0a,0x0}}, + {0x2e, 0x33, {0x11a,7559,100, 0,2,0x00,0xbc,0x2a,0xf2,0x20,0x0a,0x0}}, + {0x34, 0x39, {0x11b,6798,100, 0,2,0x00,0xbc,0x2a,0xf2,0x20,0x0a,0x0}}, + {0x3a, 0x3f, {0x11c,6036,100, 0,2,0x00,0xbc,0x2a,0xf2,0x20,0x0a,0x0}}, + {0x40, 0x45, {0x11d,5271,100, 0,2,0x00,0xbc,0x2a,0xf2,0x20,0x0a,0x0}}, + {0x46, 0x4b, {0x11e,4514,100, 0,2,0x00,0xbc,0x2a,0xf2,0x20,0x0a,0x0}}, + {0x4c, 0x51, {0x11f,3735,100, 0,2,0x00,0xbc,0x2a,0xf2,0x20,0x0a,0x0}}, + {0x52, 0x57, {0x120,3006,100, 0,2,0x00,0xbc,0x2a,0xf2,0x20,0x0a,0x0}}, + {0x58, 0x5d, {0x121,2160,100, 0,2,0x00,0xbc,0x2a,0xf2,0x20,0x0a,0x0}}, + {0x5e, 0x66, {0x122,1415,100, 0,2,0x00,0xbc,0x2a,0xf2,0x20,0x0a,0x0}}, + {0x67, 0x7f, {0x123,-121,100, 0,2,0x00,0xbc,0x2a,0xf2,0x20,0x0a,0x0}} +}; +static const opl4_region_t regions_58[] = { /* New Age Pad */ + {0x15, 0x6c, {0x002,4501,100, 0,4,0x00,0xa4,0x24,0x80,0x01,0x05,0x0}}, + {0x15, 0x6c, {0x0f3,4253,100, 0,3,0x00,0x8c,0x23,0xa2,0x14,0x06,0x1}} +}; +static const opl4_region_t regions_59[] = { /* Warm Pad */ + {0x15, 0x6c, {0x04e,5306,100, 2,2,0x00,0x92,0x2a,0x34,0x23,0x05,0x2}}, + {0x15, 0x6c, {0x029,3575,100,-2,2,0x00,0xbe,0x22,0x31,0x23,0x06,0x0}} +}; +static const opl4_region_t regions_5a[] = { /* Polysynth Pad */ + {0x01, 0x27, {0x118,9111,100, 0,3,0x00,0xae,0x23,0xf2,0x20,0x07,0x1}}, + {0x28, 0x2d, {0x119,8348,100, 0,3,0x00,0xae,0x23,0xf2,0x20,0x07,0x1}}, + {0x2e, 0x33, {0x11a,7573,100, 0,3,0x00,0xae,0x23,0xf2,0x20,0x07,0x1}}, + {0x34, 0x39, {0x11b,6812,100, 0,3,0x00,0xae,0x23,0xf2,0x20,0x07,0x1}}, + {0x3a, 0x3f, {0x11c,6050,100, 0,3,0x00,0xae,0x23,0xf2,0x20,0x07,0x1}}, + {0x40, 0x45, {0x11d,5285,100, 0,3,0x00,0xae,0x23,0xf2,0x20,0x07,0x1}}, + {0x46, 0x4b, {0x11e,4528,100, 0,3,0x00,0xae,0x23,0xf2,0x20,0x07,0x1}}, + {0x4c, 0x51, {0x11f,3749,100, 0,3,0x00,0xae,0x23,0xf2,0x20,0x07,0x1}}, + {0x52, 0x57, {0x120,3020,100, 0,3,0x00,0xae,0x23,0xf2,0x20,0x07,0x1}}, + {0x58, 0x5d, {0x121,2174,100, 0,3,0x00,0xae,0x23,0xf2,0x20,0x07,0x1}}, + {0x5e, 0x66, {0x122,1429,100, 0,3,0x00,0xae,0x23,0xf2,0x20,0x07,0x1}}, + {0x67, 0x7f, {0x123,-107,100, 0,3,0x00,0xae,0x23,0xf2,0x20,0x07,0x1}}, + {0x00, 0x7f, {0x124,4024,100, 0,2,0x00,0xae,0x22,0xe5,0x20,0x08,0x0}} +}; +static const opl4_region_t regions_5b[] = { /* Choir Pad */ + {0x15, 0x3a, {0x018,5010,100, 0,5,0x00,0xb0,0x25,0x70,0x00,0x06,0x0}}, + {0x3b, 0x40, {0x019,4370,100, 0,5,0x00,0xb0,0x25,0x70,0x00,0x06,0x0}}, + {0x41, 0x47, {0x01a,3478,100, 0,5,0x00,0xb0,0x25,0x70,0x00,0x06,0x0}}, + {0x48, 0x6c, {0x01b,2197,100, 0,5,0x00,0xb0,0x25,0x70,0x00,0x06,0x0}}, + {0x15, 0x6c, {0x02a,3482,100, 0,4,0x00,0x98,0x24,0x65,0x21,0x06,0x0}} +}; +static const opl4_region_t regions_5c[] = { /* Bowed Pad */ + {0x15, 0x6c, {0x101,4790,100,-1,1,0x00,0xbe,0x19,0x44,0x14,0x16,0x0}}, + {0x00, 0x7f, {0x0aa,1720,100, 1,1,0x00,0x94,0x19,0x40,0x00,0x06,0x0}} +}; +static const opl4_region_t regions_5d[] = { /* Metallic Pad */ + {0x15, 0x31, {0x00c,6943,100, 0,2,0x00,0xa0,0x0a,0x60,0x03,0x06,0x0}}, + {0x32, 0x38, {0x00d,5416,100, 0,2,0x00,0xa0,0x0a,0x60,0x03,0x06,0x0}}, + {0x39, 0x47, {0x00e,4385,100, 0,2,0x00,0xa0,0x0a,0x60,0x03,0x06,0x0}}, + {0x48, 0x6c, {0x00f,2849,100, 0,2,0x00,0xa0,0x0a,0x60,0x03,0x06,0x0}}, + {0x00, 0x7f, {0x03f,4224,100, 0,1,0x00,0x9c,0x31,0x65,0x16,0x07,0x0}} +}; +static const opl4_region_t regions_5e[] = { /* Halo Pad */ + {0x00, 0x7f, {0x124,4038,100, 0,2,0x00,0xa6,0x1a,0x85,0x23,0x08,0x0}}, + {0x15, 0x6c, {0x02a,3471,100, 0,3,0x00,0xc0,0x1b,0xc0,0x05,0x06,0x0}} +}; +static const opl4_region_t regions_5f[] = { /* Sweep Pad */ + {0x01, 0x27, {0x0d3,9100,100, 0,1,0x00,0xce,0x19,0x13,0x11,0x06,0x0}}, + {0x28, 0x2d, {0x0da,8341,100, 0,1,0x00,0xce,0x19,0x13,0x11,0x06,0x0}}, + {0x2e, 0x33, {0x0d4,7564,100, 0,1,0x00,0xce,0x19,0x13,0x11,0x06,0x0}}, + {0x34, 0x39, {0x0db,6791,100, 0,1,0x00,0xce,0x19,0x13,0x11,0x06,0x0}}, + {0x3a, 0x3f, {0x0d5,6048,100, 0,1,0x00,0xce,0x19,0x13,0x11,0x06,0x0}}, + {0x40, 0x45, {0x0dc,5263,100, 0,1,0x00,0xce,0x19,0x13,0x11,0x06,0x0}}, + {0x46, 0x4b, {0x0d6,4499,100, 0,1,0x00,0xce,0x19,0x13,0x11,0x06,0x0}}, + {0x4c, 0x51, {0x0dd,3747,100, 0,1,0x00,0xce,0x19,0x13,0x11,0x06,0x0}}, + {0x52, 0x57, {0x0d7,3018,100, 0,1,0x00,0xce,0x19,0x13,0x11,0x06,0x0}}, + {0x58, 0x5d, {0x0de,2173,100, 0,1,0x00,0xce,0x19,0x13,0x11,0x06,0x0}}, + {0x5e, 0x63, {0x0d8,1427,100, 0,1,0x00,0xce,0x19,0x13,0x11,0x06,0x0}}, + {0x64, 0x7f, {0x0d9,-109,100, 0,1,0x00,0xce,0x19,0x13,0x11,0x06,0x0}}, + {0x01, 0x27, {0x0d3,9088,100, 0,0,0x00,0xce,0x18,0x13,0x11,0x06,0x0}}, + {0x28, 0x2d, {0x0da,8329,100, 0,0,0x00,0xce,0x18,0x13,0x11,0x06,0x0}}, + {0x2e, 0x33, {0x0d4,7552,100, 0,0,0x00,0xce,0x18,0x13,0x11,0x06,0x0}}, + {0x34, 0x39, {0x0db,6779,100, 0,0,0x00,0xce,0x18,0x13,0x11,0x06,0x0}}, + {0x3a, 0x3f, {0x0d5,6036,100, 0,0,0x00,0xce,0x18,0x13,0x11,0x06,0x0}}, + {0x40, 0x45, {0x0dc,5251,100, 0,0,0x00,0xce,0x18,0x13,0x11,0x06,0x0}}, + {0x46, 0x4b, {0x0d6,4487,100, 0,0,0x00,0xce,0x18,0x13,0x11,0x06,0x0}}, + {0x4c, 0x51, {0x0dd,3735,100, 0,0,0x00,0xce,0x18,0x13,0x11,0x06,0x0}}, + {0x52, 0x57, {0x0d7,3006,100, 0,0,0x00,0xce,0x18,0x13,0x11,0x06,0x0}}, + {0x58, 0x5d, {0x0de,2161,100, 0,0,0x00,0xce,0x18,0x13,0x11,0x06,0x0}}, + {0x5e, 0x63, {0x0d8,1415,100, 0,0,0x00,0xce,0x18,0x13,0x11,0x06,0x0}}, + {0x64, 0x7f, {0x0d9,-121,100, 0,0,0x00,0xce,0x18,0x13,0x11,0x06,0x0}} +}; +static const opl4_region_t regions_60[] = { /* Ice Rain */ + {0x01, 0x7f, {0x04e,9345,100, 0,2,0x00,0xcc,0x22,0xa3,0x63,0x17,0x0}}, + {0x00, 0x7f, {0x143,5586, 20, 0,2,0x00,0x6e,0x2a,0xf0,0x05,0x05,0x0}} +}; +static const opl4_region_t regions_61[] = { /* Soundtrack */ + {0x15, 0x6c, {0x002,4501,100, 0,2,0x00,0xb6,0x2a,0x60,0x01,0x05,0x0}}, + {0x15, 0x6c, {0x0f3,1160,100, 0,5,0x00,0xa8,0x2d,0x52,0x14,0x06,0x2}} +}; +static const opl4_region_t regions_62[] = { /* Crystal */ + {0x15, 0x6c, {0x0f3,1826,100, 0,3,0x00,0xb8,0x33,0xf6,0x25,0x25,0x0}}, + {0x15, 0x2c, {0x06d,7454,100, 0,3,0x00,0xac,0x3b,0x85,0x24,0x06,0x0}}, + {0x2d, 0x36, {0x06e,5925,100, 0,3,0x00,0xac,0x3b,0x85,0x24,0x06,0x0}}, + {0x37, 0x6c, {0x06f,4403,100, 0,3,0x09,0xac,0x3b,0x85,0x24,0x06,0x0}} +}; +static const opl4_region_t regions_63[] = { /* Atmosphere */ + {0x05, 0x71, {0x002,4509,100, 0,2,0x00,0xc8,0x32,0x73,0x22,0x06,0x1}}, + {0x15, 0x2f, {0x0b3,6964,100, 0,2,0x05,0xc2,0x32,0xf5,0x34,0x07,0x2}}, + {0x30, 0x36, {0x0b7,5567,100, 0,2,0x0c,0xc2,0x32,0xf5,0x34,0x07,0x2}}, + {0x37, 0x3c, {0x0b5,4653,100, 0,2,0x00,0xc2,0x32,0xf6,0x34,0x07,0x2}}, + {0x3d, 0x43, {0x0b4,3892,100, 0,2,0x00,0xc2,0x32,0xf6,0x35,0x07,0x2}}, + {0x44, 0x60, {0x0b6,2723,100, 0,2,0x00,0xc2,0x32,0xf6,0x35,0x17,0x2}} +}; +static const opl4_region_t regions_64[] = { /* Brightness */ + {0x00, 0x7f, {0x137,5285,100, 0,2,0x00,0xbe,0x2a,0xa5,0x18,0x08,0x0}}, + {0x15, 0x6c, {0x02a,3481,100, 0,1,0x00,0xc8,0x29,0x80,0x05,0x05,0x0}} +}; +static const opl4_region_t regions_65[] = { /* Goblins */ + {0x15, 0x6c, {0x002,4501,100,-1,2,0x00,0xca,0x2a,0x40,0x01,0x05,0x0}}, + {0x15, 0x6c, {0x009,9679, 20, 1,4,0x00,0x3c,0x0c,0x22,0x11,0x06,0x0}} +}; +static const opl4_region_t regions_66[] = { /* Echoes */ + {0x15, 0x6c, {0x02a,3487,100, 0,3,0x00,0xae,0x2b,0xf5,0x21,0x06,0x0}}, + {0x00, 0x7f, {0x124,4027,100, 0,3,0x00,0xae,0x2b,0x85,0x23,0x07,0x0}} +}; +static const opl4_region_t regions_67[] = { /* Sci-Fi */ + {0x15, 0x31, {0x00c,6940,100, 0,3,0x00,0xc8,0x2b,0x90,0x05,0x06,0x3}}, + {0x32, 0x38, {0x00d,5413,100, 0,3,0x00,0xc8,0x2b,0x90,0x05,0x06,0x3}}, + {0x39, 0x47, {0x00e,4382,100, 0,3,0x00,0xc8,0x2b,0x90,0x05,0x06,0x3}}, + {0x48, 0x6c, {0x00f,2846,100, 0,3,0x00,0xc8,0x2b,0x90,0x05,0x06,0x3}}, + {0x15, 0x6c, {0x002,4498,100, 0,2,0x00,0xd4,0x22,0x80,0x01,0x05,0x0}} +}; +static const opl4_region_t regions_68[] = { /* Sitar */ + {0x00, 0x7f, {0x10f,4408,100, 0,2,0x00,0xc4,0x32,0xf4,0x15,0x16,0x1}} +}; +static const opl4_region_t regions_69[] = { /* Banjo */ + {0x15, 0x34, {0x013,5685,100, 0,0,0x00,0xdc,0x38,0xf6,0x15,0x09,0x0}}, + {0x35, 0x38, {0x014,5009,100, 0,0,0x00,0xdc,0x38,0xf6,0x15,0x09,0x0}}, + {0x39, 0x3c, {0x012,4520,100, 0,0,0x00,0xdc,0x38,0xf6,0x15,0x09,0x0}}, + {0x3d, 0x44, {0x015,3622,100, 0,0,0x00,0xdc,0x38,0xf6,0x15,0x09,0x0}}, + {0x45, 0x4c, {0x017,2661,100, 0,0,0x00,0xdc,0x38,0xf6,0x15,0x09,0x0}}, + {0x4d, 0x6d, {0x016,1632,100, 0,0,0x00,0xdc,0x38,0xf6,0x15,0x09,0x0}} +}; +static const opl4_region_t regions_6a[] = { /* Shamisen */ + {0x15, 0x6c, {0x10e,3273,100, 0,0,0x00,0xc0,0x28,0xf7,0x76,0x08,0x0}} +}; +static const opl4_region_t regions_6b[] = { /* Koto */ + {0x00, 0x7f, {0x0a9,4033,100, 0,0,0x00,0xc6,0x20,0xf0,0x06,0x07,0x0}} +}; +static const opl4_region_t regions_6c[] = { /* Kalimba */ + {0x00, 0x7f, {0x137,3749,100, 0,0,0x00,0xce,0x38,0xf5,0x18,0x08,0x0}} +}; +static const opl4_region_t regions_6d[] = { /* Bagpipe */ + {0x15, 0x39, {0x0a4,7683,100, 0,4,0x00,0xc0,0x1c,0xf0,0x00,0x09,0x0}}, + {0x15, 0x39, {0x0a7,7680,100, 0,1,0x00,0xaa,0x19,0xf0,0x00,0x09,0x0}}, + {0x3a, 0x6c, {0x0a8,3697,100, 0,1,0x00,0xaa,0x19,0xf0,0x00,0x09,0x0}} +}; +static const opl4_region_t regions_6e[] = { /* Fiddle */ + {0x15, 0x3a, {0x105,5158,100, 0,1,0x00,0xca,0x31,0xf3,0x20,0x09,0x0}}, + {0x3b, 0x3f, {0x102,4754,100, 0,1,0x00,0xca,0x31,0xf3,0x20,0x09,0x0}}, + {0x40, 0x41, {0x106,4132,100, 0,1,0x00,0xca,0x31,0xf3,0x20,0x09,0x0}}, + {0x42, 0x44, {0x107,4033,100, 0,1,0x00,0xca,0x31,0xf3,0x20,0x09,0x0}}, + {0x45, 0x47, {0x108,3580,100, 0,1,0x00,0xca,0x31,0xf3,0x20,0x09,0x0}}, + {0x48, 0x4a, {0x10a,2957,100, 0,1,0x00,0xca,0x31,0xf3,0x20,0x09,0x0}}, + {0x4b, 0x4c, {0x10b,2724,100, 0,1,0x00,0xca,0x31,0xf3,0x20,0x09,0x0}}, + {0x4d, 0x4e, {0x10c,2530,100, 0,1,0x00,0xca,0x31,0xf3,0x20,0x09,0x0}}, + {0x4f, 0x51, {0x10d,2166,100, 0,1,0x00,0xca,0x31,0xf3,0x20,0x09,0x0}}, + {0x52, 0x6c, {0x109,1825,100, 0,1,0x00,0xca,0x31,0xf3,0x20,0x09,0x0}} +}; +static const opl4_region_t regions_6f[] = { /* Shanai */ + {0x15, 0x6c, {0x041,6946,100, 0,1,0x00,0xc4,0x31,0x95,0x20,0x09,0x0}} +}; +static const opl4_region_t regions_70[] = { /* Tinkle Bell */ + {0x15, 0x73, {0x0f3,1821,100, 0,3,0x00,0xc8,0x3b,0xd6,0x25,0x25,0x0}}, + {0x00, 0x7f, {0x137,5669,100, 0,3,0x00,0x66,0x3b,0xf5,0x18,0x08,0x0}} +}; +static const opl4_region_t regions_71[] = { /* Agogo */ + {0x15, 0x74, {0x00b,2474,100, 0,0,0x00,0xd2,0x38,0xf0,0x00,0x09,0x0}} +}; +static const opl4_region_t regions_72[] = { /* Steel Drums */ + {0x01, 0x7f, {0x0fe,3670,100, 0,0,0x00,0xca,0x38,0xf3,0x06,0x17,0x1}}, + {0x15, 0x6c, {0x100,9602,100, 0,0,0x00,0x54,0x38,0xb0,0x05,0x16,0x1}} +}; +static const opl4_region_t regions_73[] = { /* Woodblock */ + {0x15, 0x6c, {0x02c,2963, 50, 0,0,0x07,0xd4,0x00,0xf0,0x00,0x09,0x0}} +}; +static const opl4_region_t regions_74[] = { /* Taiko Drum */ + {0x13, 0x6c, {0x03e,1194, 50, 0,0,0x00,0xaa,0x38,0xf0,0x04,0x04,0x0}} +}; +static const opl4_region_t regions_75[] = { /* Melodic Tom */ + {0x15, 0x6c, {0x0c7,6418, 50, 0,0,0x00,0xe4,0x38,0xf0,0x05,0x01,0x0}} +}; +static const opl4_region_t regions_76[] = { /* Synth Drum */ + {0x15, 0x6c, {0x026,3898, 50, 0,0,0x00,0xd0,0x38,0xf0,0x04,0x04,0x0}} +}; +static const opl4_region_t regions_77[] = { /* Reverse Cymbal */ + {0x15, 0x6c, {0x031,4138, 50, 0,0,0x00,0xfe,0x38,0x3a,0xf0,0x09,0x0}} +}; +static const opl4_region_t regions_78[] = { /* Guitar Fret Noise */ + {0x15, 0x6c, {0x138,5266,100, 0,0,0x00,0xa0,0x38,0xf0,0x00,0x09,0x0}} +}; +static const opl4_region_t regions_79[] = { /* Breath Noise */ + {0x01, 0x7f, {0x125,4269,100, 0,0,0x1e,0xd0,0x38,0xf0,0x00,0x09,0x0}} +}; +static const opl4_region_t regions_7a[] = { /* Seashore */ + {0x15, 0x6c, {0x008,2965, 20,-2,0,0x00,0xfe,0x00,0x20,0x03,0x04,0x0}}, + {0x01, 0x7f, {0x037,4394, 20, 2,0,0x14,0xfe,0x00,0x20,0x04,0x05,0x0}} +}; +static const opl4_region_t regions_7b[] = { /* Bird Tweet */ + {0x15, 0x6c, {0x009,8078, 5,-4,7,0x00,0xc2,0x0f,0x22,0x12,0x07,0x0}}, + {0x15, 0x6c, {0x009,3583, 5, 4,5,0x00,0xae,0x15,0x72,0x12,0x07,0x0}} +}; +static const opl4_region_t regions_7c[] = { /* Telephone Ring */ + {0x15, 0x6c, {0x003,3602, 10, 0,0,0x00,0xce,0x00,0xf0,0x00,0x0f,0x0}} +}; +static const opl4_region_t regions_7d[] = { /* Helicopter */ + {0x0c, 0x7f, {0x001,2965, 10,-2,0,0x00,0xe0,0x08,0x30,0x01,0x07,0x0}}, + {0x01, 0x7f, {0x037,4394, 10, 2,0,0x44,0x76,0x00,0x30,0x01,0x07,0x0}} +}; +static const opl4_region_t regions_7e[] = { /* Applause */ + {0x15, 0x6c, {0x036,8273, 20,-6,7,0x00,0xc4,0x0f,0x70,0x01,0x05,0x0}}, + {0x15, 0x6c, {0x036,8115, 5, 6,7,0x00,0xc6,0x07,0x70,0x01,0x05,0x0}} +}; +static const opl4_region_t regions_7f[] = { /* Gun Shot */ + {0x15, 0x6c, {0x139,2858, 20, 0,0,0x00,0xbe,0x38,0xf0,0x03,0x00,0x0}} +}; +static const opl4_region_t regions_drums[] = { + {0x18, 0x18, {0x0cb,6397,100, 3,0,0x00,0xf4,0x38,0xc9,0x1c,0x0c,0x0}}, + {0x19, 0x19, {0x0c4,3714,100, 0,0,0x00,0xe0,0x00,0x97,0x19,0x09,0x0}}, + {0x1a, 0x1a, {0x0c4,3519,100, 0,0,0x00,0xea,0x00,0x61,0x01,0x07,0x0}}, + {0x1b, 0x1b, {0x0c4,3586,100, 0,0,0x00,0xea,0x00,0xf7,0x19,0x09,0x0}}, + {0x1c, 0x1c, {0x0c4,3586,100, 0,0,0x00,0xea,0x00,0x81,0x01,0x07,0x0}}, + {0x1e, 0x1e, {0x0c3,4783,100, 0,0,0x00,0xea,0x00,0xf0,0x00,0x09,0x0}}, + {0x1f, 0x1f, {0x0d1,4042,100, 0,0,0x00,0xd6,0x00,0xf0,0x05,0x05,0x0}}, + {0x20, 0x20, {0x0d2,5943,100, 0,0,0x00,0xcc,0x00,0xf0,0x00,0x09,0x0}}, + {0x21, 0x21, {0x011,3842,100, 0,0,0x00,0xea,0x00,0xf0,0x16,0x06,0x0}}, + {0x23, 0x23, {0x011,4098,100, 0,0,0x00,0xea,0x00,0xf0,0x16,0x06,0x0}}, + {0x24, 0x24, {0x011,4370,100, 0,0,0x00,0xea,0x00,0xf0,0x00,0x06,0x0}}, + {0x25, 0x25, {0x0d2,4404,100, 0,0,0x00,0xd6,0x00,0xf0,0x00,0x06,0x0}}, + {0x26, 0x26, {0x0d1,4298,100, 0,0,0x00,0xd6,0x00,0xf0,0x05,0x05,0x0}}, + {0x27, 0x27, {0x00a,4403,100,-1,0,0x00,0xd6,0x00,0xf0,0x00,0x09,0x0}}, + {0x28, 0x28, {0x0d1,4554,100, 0,0,0x00,0xdc,0x00,0xf0,0x07,0x07,0x0}}, + {0x29, 0x29, {0x0c8,4242,100,-4,0,0x00,0xd6,0x00,0xf6,0x16,0x06,0x0}}, + {0x2a, 0x2a, {0x079,6160,100, 2,0,0x00,0xe0,0x00,0xf5,0x19,0x09,0x0}}, + {0x2b, 0x2b, {0x0c8,4626,100,-3,0,0x00,0xd6,0x00,0xf6,0x16,0x06,0x0}}, + {0x2c, 0x2c, {0x07b,6039,100, 2,0,0x00,0xd6,0x00,0xf0,0x00,0x09,0x0}}, + {0x2d, 0x2d, {0x0c8,5394,100,-2,0,0x00,0xd6,0x00,0xf6,0x16,0x06,0x0}}, + {0x2e, 0x2e, {0x07a,5690,100, 2,0,0x00,0xd6,0x00,0xf0,0x00,0x05,0x0}}, + {0x2f, 0x2f, {0x0c7,5185,100, 2,0,0x00,0xe0,0x00,0xf6,0x17,0x07,0x0}}, + {0x30, 0x30, {0x0c7,5650,100, 3,0,0x00,0xe0,0x00,0xf6,0x17,0x07,0x0}}, + {0x31, 0x31, {0x031,4395,100, 2,0,0x00,0xea,0x00,0xf0,0x05,0x05,0x0}}, + {0x32, 0x32, {0x0c7,6162,100, 4,0,0x00,0xe0,0x00,0xf6,0x17,0x07,0x0}}, + {0x33, 0x33, {0x02e,4391,100,-2,0,0x00,0xea,0x00,0xf0,0x05,0x05,0x0}}, + {0x34, 0x34, {0x07a,3009,100,-2,0,0x00,0xea,0x00,0xf2,0x15,0x05,0x0}}, + {0x35, 0x35, {0x021,4522,100,-3,0,0x00,0xd6,0x00,0xf0,0x05,0x05,0x0}}, + {0x36, 0x36, {0x025,5163,100, 1,0,0x00,0xe0,0x00,0xf0,0x00,0x09,0x0}}, + {0x37, 0x37, {0x031,5287,100,-1,0,0x00,0xea,0x00,0xf5,0x16,0x06,0x0}}, + {0x38, 0x38, {0x01d,4395,100, 2,0,0x00,0xe0,0x00,0xf0,0x00,0x09,0x0}}, + {0x39, 0x39, {0x031,4647,100,-2,0,0x00,0xea,0x00,0xf4,0x16,0x06,0x0}}, + {0x3a, 0x3a, {0x09d,4426,100,-4,0,0x00,0xe0,0x00,0xf4,0x17,0x07,0x0}}, + {0x3b, 0x3b, {0x02e,4659,100,-2,0,0x00,0xea,0x00,0xf0,0x06,0x06,0x0}}, + {0x3c, 0x3c, {0x01c,4769,100, 4,0,0x00,0xea,0x00,0xf0,0x00,0x09,0x0}}, + {0x3d, 0x3d, {0x01c,4611,100, 4,0,0x00,0xea,0x00,0xf0,0x00,0x09,0x0}}, + {0x3e, 0x3e, {0x01e,4402,100,-3,0,0x00,0xea,0x00,0xf0,0x00,0x09,0x0}}, + {0x3f, 0x3f, {0x01f,4387,100,-3,0,0x00,0xea,0x00,0xf0,0x00,0x09,0x0}}, + {0x40, 0x40, {0x01f,3983,100,-2,0,0x00,0xea,0x00,0xf0,0x00,0x09,0x0}}, + {0x41, 0x41, {0x09c,4526,100, 2,0,0x00,0xea,0x00,0xf0,0x00,0x09,0x0}}, + {0x42, 0x42, {0x09c,4016,100, 2,0,0x00,0xea,0x00,0xf0,0x00,0x09,0x0}}, + {0x43, 0x43, {0x00b,4739,100,-4,0,0x00,0xea,0x00,0xf0,0x00,0x09,0x0}}, + {0x44, 0x44, {0x00b,4179,100,-4,0,0x00,0xea,0x00,0xf0,0x00,0x09,0x0}}, + {0x45, 0x45, {0x02f,4787,100,-4,0,0x00,0xd6,0x00,0xf0,0x00,0x09,0x0}}, + {0x46, 0x46, {0x030,4665,100,-4,0,0x00,0xd6,0x00,0xf0,0x00,0x09,0x0}}, + {0x47, 0x47, {0x144,4519,100, 4,0,0x00,0xea,0x00,0xf0,0x00,0x0b,0x0}}, + {0x48, 0x48, {0x144,4111,100, 4,0,0x00,0xea,0x00,0xf0,0x00,0x0b,0x0}}, + {0x49, 0x49, {0x024,6408,100, 3,0,0x00,0xe0,0x00,0xf0,0x00,0x09,0x0}}, + {0x4a, 0x4a, {0x024,4144,100, 3,0,0x00,0xcc,0x00,0xf0,0x00,0x09,0x0}}, + {0x4b, 0x4b, {0x020,4001,100, 2,0,0x00,0xe0,0x00,0xf0,0x00,0x09,0x0}}, + {0x4c, 0x4c, {0x02c,4402,100, 4,0,0x00,0xea,0x00,0xf0,0x00,0x09,0x0}}, + {0x4d, 0x4d, {0x02c,3612,100, 4,0,0x00,0xea,0x00,0xf0,0x00,0x09,0x0}}, + {0x4e, 0x4e, {0x022,4129,100,-2,0,0x00,0xea,0x00,0xf0,0x00,0x09,0x0}}, + {0x4f, 0x4f, {0x023,4147,100,-2,0,0x00,0xea,0x00,0xf0,0x00,0x09,0x0}}, + {0x50, 0x50, {0x032,4412,100,-4,0,0x00,0xd6,0x00,0xf0,0x08,0x09,0x0}}, + {0x51, 0x51, {0x032,4385,100,-4,0,0x00,0xd6,0x00,0xf0,0x00,0x09,0x0}}, + {0x52, 0x52, {0x02f,5935,100,-1,0,0x00,0xd6,0x00,0xf0,0x00,0x09,0x0}} +}; + +#define REGION(num) { ARRAY_SIZE(regions ## num), regions ## num } +const opl4_region_ptr_t snd_yrw801_regions[0x81] = { + REGION(_00), REGION(_01), REGION(_02), REGION(_03), + REGION(_04), REGION(_05), REGION(_06), REGION(_07), + REGION(_08), REGION(_09), REGION(_0a), REGION(_0b), + REGION(_0c), REGION(_0d), REGION(_0e), REGION(_0f), + REGION(_10), REGION(_11), REGION(_12), REGION(_13), + REGION(_14), REGION(_15), REGION(_16), REGION(_17), + REGION(_18), REGION(_19), REGION(_1a), REGION(_1b), + REGION(_1c), REGION(_1d), REGION(_1e), REGION(_1f), + REGION(_20), REGION(_21), REGION(_22), REGION(_23), + REGION(_24), REGION(_25), REGION(_26), REGION(_27), + REGION(_28), REGION(_29), REGION(_2a), REGION(_2b), + REGION(_2c), REGION(_2d), REGION(_2e), REGION(_2f), + REGION(_30), REGION(_31), REGION(_32), REGION(_33), + REGION(_34), REGION(_35), REGION(_36), REGION(_37), + REGION(_38), REGION(_39), REGION(_3a), REGION(_3b), + REGION(_3c), REGION(_3d), REGION(_3e), REGION(_3f), + REGION(_40), REGION(_41), REGION(_42), REGION(_43), + REGION(_44), REGION(_45), REGION(_46), REGION(_47), + REGION(_48), REGION(_49), REGION(_4a), REGION(_4b), + REGION(_4c), REGION(_4d), REGION(_4e), REGION(_4f), + REGION(_50), REGION(_51), REGION(_52), REGION(_53), + REGION(_54), REGION(_55), REGION(_56), REGION(_57), + REGION(_58), REGION(_59), REGION(_5a), REGION(_5b), + REGION(_5c), REGION(_5d), REGION(_5e), REGION(_5f), + REGION(_60), REGION(_61), REGION(_62), REGION(_63), + REGION(_64), REGION(_65), REGION(_66), REGION(_67), + REGION(_68), REGION(_69), REGION(_6a), REGION(_6b), + REGION(_6c), REGION(_6d), REGION(_6e), REGION(_6f), + REGION(_70), REGION(_71), REGION(_72), REGION(_73), + REGION(_74), REGION(_75), REGION(_76), REGION(_77), + REGION(_78), REGION(_79), REGION(_7a), REGION(_7b), + REGION(_7c), REGION(_7d), REGION(_7e), REGION(_7f), + REGION(_drums) +}; diff -Nru a/sound/drivers/vx/Makefile b/sound/drivers/vx/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/drivers/vx/Makefile Mon Jun 9 23:16:20 2003 @@ -0,0 +1,11 @@ +# +# Makefile for ALSA +# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz> +# + +snd-vx-lib-objs := vx_core.o vx_hwdep.o vx_pcm.o vx_mixer.o vx_cmd.o vx_uer.o + +obj-$(CONFIG_SND_VXPOCKET) += snd-vx-lib.o +obj-$(CONFIG_SND_VXP440) += snd-vx-lib.o +obj-$(CONFIG_SND_VX222) += snd-vx-lib.o + diff -Nru a/sound/drivers/vx/vx_cmd.c b/sound/drivers/vx/vx_cmd.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/drivers/vx/vx_cmd.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,109 @@ +/* + * Driver for Digigram VX soundcards + * + * DSP commands + * + * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <sound/driver.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/vx_core.h> +#include "vx_cmd.h" + +/* + * Array of DSP commands + */ +struct vx_cmd_info vx_dsp_cmds[] = { +[CMD_VERSION] = { 0x010000, 2, RMH_SSIZE_FIXED, 1 }, +[CMD_SUPPORTED] = { 0x020000, 1, RMH_SSIZE_FIXED, 2 }, +[CMD_TEST_IT] = { 0x040000, 1, RMH_SSIZE_FIXED, 1 }, +[CMD_SEND_IRQA] = { 0x070001, 1, RMH_SSIZE_FIXED, 0 }, +[CMD_IBL] = { 0x080000, 1, RMH_SSIZE_FIXED, 4 }, +[CMD_ASYNC] = { 0x0A0000, 1, RMH_SSIZE_ARG, 0 }, +[CMD_RES_PIPE] = { 0x400000, 1, RMH_SSIZE_FIXED, 0 }, +[CMD_FREE_PIPE] = { 0x410000, 1, RMH_SSIZE_FIXED, 0 }, +[CMD_CONF_PIPE] = { 0x42A101, 2, RMH_SSIZE_FIXED, 0 }, +[CMD_ABORT_CONF_PIPE] = { 0x42A100, 2, RMH_SSIZE_FIXED, 0 }, +[CMD_PARAM_OUTPUT_PIPE] = { 0x43A000, 2, RMH_SSIZE_FIXED, 0 }, +[CMD_STOP_PIPE] = { 0x470004, 1, RMH_SSIZE_FIXED, 0 }, +[CMD_PIPE_STATE] = { 0x480000, 1, RMH_SSIZE_FIXED, 1 }, +[CMD_PIPE_SPL_COUNT] = { 0x49A000, 2, RMH_SSIZE_FIXED, 2 }, +[CMD_CAN_START_PIPE] = { 0x4b0000, 1, RMH_SSIZE_FIXED, 1 }, +[CMD_SIZE_HBUFFER] = { 0x4C0000, 1, RMH_SSIZE_FIXED, 1 }, +[CMD_START_STREAM] = { 0x80A000, 2, RMH_SSIZE_FIXED, 0 }, +[CMD_START_ONE_STREAM] = { 0x800000, 1, RMH_SSIZE_FIXED, 0 }, +[CMD_PAUSE_STREAM] = { 0x81A000, 2, RMH_SSIZE_FIXED, 0 }, +[CMD_PAUSE_ONE_STREAM] = { 0x810000, 1, RMH_SSIZE_FIXED, 0 }, +[CMD_STREAM_OUT_LEVEL_ADJUST] = { 0x828000, 2, RMH_SSIZE_FIXED, 0 }, +[CMD_STOP_STREAM] = { 0x830000, 1, RMH_SSIZE_FIXED, 0 }, +[CMD_FORMAT_STREAM_OUT] = { 0x868000, 1, RMH_SSIZE_FIXED, 0 }, +[CMD_FORMAT_STREAM_IN] = { 0x878800, 1, RMH_SSIZE_FIXED, 0 }, +[CMD_GET_STREAM_STATE] = { 0x890001, 2, RMH_SSIZE_FIXED, 1 }, +[CMD_DROP_BYTES_AWAY] = { 0x8A8000, 2, RMH_SSIZE_FIXED, 0 }, +[CMD_GET_REMAINING_BYTES] = { 0x8D0800, 1, RMH_SSIZE_FIXED, 2 }, +[CMD_CONNECT_AUDIO] = { 0xC10000, 1, RMH_SSIZE_FIXED, 0 }, +[CMD_AUDIO_LEVEL_ADJUST] = { 0xC2A000, 3, RMH_SSIZE_FIXED, 0 }, +[CMD_AUDIO_VU_PIC_METER] = { 0xC3A003, 2, RMH_SSIZE_FIXED, 1 }, +[CMD_GET_AUDIO_LEVELS] = { 0xC4A000, 2, RMH_SSIZE_FIXED, 0 }, +[CMD_GET_NOTIFY_EVENT] = { 0x4D0000, 1, RMH_SSIZE_ARG, 0 }, +[CMD_INFO_NOTIFIED] = { 0x0B0000, 1, RMH_SSIZE_FIXED, 2 }, +[CMD_ACCESS_IO_FCT] = { 0x098000, 1, RMH_SSIZE_ARG, 0 }, +[CMD_STATUS_R_BUFFERS] = { 0x440000, 1, RMH_SSIZE_ARG, 0 }, +[CMD_UPDATE_R_BUFFERS] = { 0x848000, 4, RMH_SSIZE_FIXED, 0 }, +[CMD_LOAD_EFFECT_CONTEXT] = { 0x0c8000, 3, RMH_SSIZE_FIXED, 1 }, +[CMD_EFFECT_ONE_PIPE] = { 0x458000, 0, RMH_SSIZE_FIXED, 0 }, +[CMD_MODIFY_CLOCK] = { 0x0d0000, 1, RMH_SSIZE_FIXED, 0 }, +[CMD_STREAM1_OUT_SET_N_LEVELS] ={ 0x858000, 3, RMH_SSIZE_FIXED, 0 }, +[CMD_PURGE_STREAM_DCMDS] = { 0x8b8000, 3, RMH_SSIZE_FIXED, 0 }, +[CMD_NOTIFY_PIPE_TIME] = { 0x4e0000, 1, RMH_SSIZE_FIXED, 0 }, +[CMD_LOAD_EFFECT_CONTEXT_PACKET] = { 0x0c8000, 1, RMH_SSIZE_FIXED, 0 }, +[CMD_RELIC_R_BUFFER] = { 0x8e0800, 1, RMH_SSIZE_FIXED, 1 }, +[CMD_RESYNC_AUDIO_INPUTS] = { 0x0e0000, 1, RMH_SSIZE_FIXED, 0 }, +[CMD_NOTIFY_STREAM_TIME] = { 0x8f0000, 1, RMH_SSIZE_FIXED, 0 }, +[CMD_STREAM_SAMPLE_COUNT] = { 0x900000, 1, RMH_SSIZE_FIXED, 2 }, +[CMD_CONFIG_TIME_CODE] = { 0x050000, 2, RMH_SSIZE_FIXED, 0 }, +[CMD_GET_TIME_CODE] = { 0x060000, 1, RMH_SSIZE_FIXED, 5 }, +[CMD_MANAGE_SIGNAL] = { 0x0f0000, 1, RMH_SSIZE_FIXED, 0 }, +[CMD_PARAMETER_STREAM_OUT] = { 0x91A000, 3, RMH_SSIZE_FIXED, 0 }, +[CMD_READ_BOARD_FREQ] = { 0x030000, 1, RMH_SSIZE_FIXED, 2 }, +[CMD_GET_STREAM_LEVELS] = { 0x8c0000, 1, RMH_SSIZE_FIXED, 3 }, +[CMD_PURGE_PIPE_DCMDS] = { 0x4f8000, 3, RMH_SSIZE_FIXED, 0 }, +// [CMD_SET_STREAM_OUT_EFFECTS] = { 0x888000, 34, RMH_SSIZE_FIXED, 0 }, +// [CMD_GET_STREAM_OUT_EFFECTS] = { 0x928000, 2, RMH_SSIZE_FIXED, 32 }, +[CMD_CONNECT_MONITORING] = { 0xC00000, 1, RMH_SSIZE_FIXED, 0 }, +[CMD_STREAM2_OUT_SET_N_LEVELS] = { 0x938000, 3, RMH_SSIZE_FIXED, 0 }, +[CMD_CANCEL_R_BUFFERS] = { 0x948000, 4, RMH_SSIZE_FIXED, 0 }, +[CMD_NOTIFY_END_OF_BUFFER] = { 0x950000, 1, RMH_SSIZE_FIXED, 0 }, +[CMD_GET_STREAM_VU_METER] = { 0x95A000, 2, RMH_SSIZE_ARG, 0 }, +}; + +/** + * vx_init_rmh - initialize the RMH instance + * @rmh: the rmh pointer to be initialized + * @cmd: the rmh command to be set + */ +void vx_init_rmh(struct vx_rmh *rmh, unsigned int cmd) +{ + snd_assert(cmd < CMD_LAST_INDEX, return); + rmh->LgCmd = vx_dsp_cmds[cmd].length; + rmh->LgStat = vx_dsp_cmds[cmd].st_length; + rmh->DspStat = vx_dsp_cmds[cmd].st_type; + rmh->Cmd[0] = vx_dsp_cmds[cmd].opcode; +} + diff -Nru a/sound/drivers/vx/vx_cmd.h b/sound/drivers/vx/vx_cmd.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/drivers/vx/vx_cmd.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,248 @@ +/* + * Driver for Digigram VX soundcards + * + * Definitions of DSP commands + * + * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __VX_CMD_H +#define __VX_CMD_H + +enum { + CMD_VERSION, + CMD_SUPPORTED, + CMD_TEST_IT, + CMD_SEND_IRQA, + CMD_IBL, + CMD_ASYNC, + CMD_RES_PIPE, + CMD_FREE_PIPE, + CMD_CONF_PIPE, + CMD_ABORT_CONF_PIPE, + CMD_PARAM_OUTPUT_PIPE, + CMD_STOP_PIPE, + CMD_PIPE_STATE, + CMD_PIPE_SPL_COUNT, + CMD_CAN_START_PIPE, + CMD_SIZE_HBUFFER, + CMD_START_STREAM, + CMD_START_ONE_STREAM, + CMD_PAUSE_STREAM, + CMD_PAUSE_ONE_STREAM, + CMD_STREAM_OUT_LEVEL_ADJUST, + CMD_STOP_STREAM, + CMD_FORMAT_STREAM_OUT, + CMD_FORMAT_STREAM_IN, + CMD_GET_STREAM_STATE, + CMD_DROP_BYTES_AWAY, + CMD_GET_REMAINING_BYTES, + CMD_CONNECT_AUDIO, + CMD_AUDIO_LEVEL_ADJUST, + CMD_AUDIO_VU_PIC_METER, + CMD_GET_AUDIO_LEVELS, + CMD_GET_NOTIFY_EVENT, + CMD_INFO_NOTIFIED, + CMD_ACCESS_IO_FCT, + CMD_STATUS_R_BUFFERS, + CMD_UPDATE_R_BUFFERS, + CMD_LOAD_EFFECT_CONTEXT, + CMD_EFFECT_ONE_PIPE, + CMD_MODIFY_CLOCK, + CMD_STREAM1_OUT_SET_N_LEVELS, + CMD_PURGE_STREAM_DCMDS, + CMD_NOTIFY_PIPE_TIME, + CMD_LOAD_EFFECT_CONTEXT_PACKET, + CMD_RELIC_R_BUFFER, + CMD_RESYNC_AUDIO_INPUTS, + CMD_NOTIFY_STREAM_TIME, + CMD_STREAM_SAMPLE_COUNT, + CMD_CONFIG_TIME_CODE, + CMD_GET_TIME_CODE, + CMD_MANAGE_SIGNAL, + CMD_PARAMETER_STREAM_OUT, + CMD_READ_BOARD_FREQ, + CMD_GET_STREAM_LEVELS, + CMD_PURGE_PIPE_DCMDS, + // CMD_SET_STREAM_OUT_EFFECTS, + // CMD_GET_STREAM_OUT_EFFECTS, + CMD_CONNECT_MONITORING, + CMD_STREAM2_OUT_SET_N_LEVELS, + CMD_CANCEL_R_BUFFERS, + CMD_NOTIFY_END_OF_BUFFER, + CMD_GET_STREAM_VU_METER, + CMD_LAST_INDEX +}; + +struct vx_cmd_info { + unsigned int opcode; /* command word */ + int length; /* command length (in words) */ + int st_type; /* status type (RMH_SSIZE_XXX) */ + int st_length; /* fixed length */ +}; + +/* Family and code op of some DSP requests. */ +#define CODE_OP_PIPE_TIME 0x004e0000 +#define CODE_OP_START_STREAM 0x00800000 +#define CODE_OP_PAUSE_STREAM 0x00810000 +#define CODE_OP_OUT_STREAM_LEVEL 0x00820000 +#define CODE_OP_UPDATE_R_BUFFERS 0x00840000 +#define CODE_OP_OUT_STREAM1_LEVEL_CURVE 0x00850000 +#define CODE_OP_OUT_STREAM2_LEVEL_CURVE 0x00930000 +#define CODE_OP_OUT_STREAM_FORMAT 0x00860000 +#define CODE_OP_STREAM_TIME 0x008f0000 +#define CODE_OP_OUT_STREAM_EXTRAPARAMETER 0x00910000 +#define CODE_OP_OUT_AUDIO_LEVEL 0x00c20000 + +#define NOTIFY_LAST_COMMAND 0x00400000 + +/* Values for a user delay */ +#define DC_DIFFERED_DELAY (1<<BIT_DIFFERED_COMMAND) +#define DC_NOTIFY_DELAY (1<<BIT_NOTIFIED_COMMAND) +#define DC_HBUFFER_DELAY (1<<BIT_TIME_RELATIVE_TO_BUFFER) +#define DC_MULTIPLE_DELAY (1<<BIT_RESERVED) +#define DC_STREAM_TIME_DELAY (1<<BIT_STREAM_TIME) +#define DC_CANCELLED_DELAY (1<<BIT_CANCELLED_COMMAND) + +/* Values for tiDelayed field in TIME_INFO structure, + * and for pbPause field in PLAY_BUFFER_INFO structure + */ +#define BIT_DIFFERED_COMMAND 0 +#define BIT_NOTIFIED_COMMAND 1 +#define BIT_TIME_RELATIVE_TO_BUFFER 2 +#define BIT_RESERVED 3 +#define BIT_STREAM_TIME 4 +#define BIT_CANCELLED_COMMAND 5 + +/* Access to the "Size" field of the response of the CMD_GET_NOTIFY_EVENT request. */ +#define GET_NOTIFY_EVENT_SIZE_FIELD_MASK 0x000000ff + +/* DSP commands general masks */ +#define OPCODE_MASK 0x00ff0000 +#define DSP_DIFFERED_COMMAND_MASK 0x0000C000 + +/* Notifications (NOTIFY_INFO) */ +#define ALL_CMDS_NOTIFIED 0x0000 // reserved +#define START_STREAM_NOTIFIED 0x0001 +#define PAUSE_STREAM_NOTIFIED 0x0002 +#define OUT_STREAM_LEVEL_NOTIFIED 0x0003 +#define OUT_STREAM_PARAMETER_NOTIFIED 0x0004 // left for backward compatibility +#define OUT_STREAM_FORMAT_NOTIFIED 0x0004 +#define PIPE_TIME_NOTIFIED 0x0005 +#define OUT_AUDIO_LEVEL_NOTIFIED 0x0006 +#define OUT_STREAM_LEVEL_CURVE_NOTIFIED 0x0007 +#define STREAM_TIME_NOTIFIED 0x0008 +#define OUT_STREAM_EXTRAPARAMETER_NOTIFIED 0x0009 +#define UNKNOWN_COMMAND_NOTIFIED 0xffff + +/* Output pipe parameters setting */ +#define MASK_VALID_PIPE_MPEG_PARAM 0x000040 +#define MASK_VALID_PIPE_BACKWARD_PARAM 0x000020 +#define MASK_SET_PIPE_MPEG_PARAM 0x000002 +#define MASK_SET_PIPE_BACKWARD_PARAM 0x000001 + +#define MASK_DSP_WORD 0x00FFFFFF +#define MASK_ALL_STREAM 0x00FFFFFF +#define MASK_DSP_WORD_LEVEL 0x000001FF +#define MASK_FIRST_FIELD 0x0000001F +#define FIELD_SIZE 5 + +#define COMMAND_RECORD_MASK 0x000800 + +/* PipeManagement definition bits (PIPE_DECL_INFO) */ +#define P_UNDERRUN_SKIP_SOUND_MASK 0x01 +#define P_PREPARE_FOR_MPEG3_MASK 0x02 +#define P_DO_NOT_RESET_ANALOG_LEVELS 0x04 +#define P_ALLOW_UNDER_ALLOCATION_MASK 0x08 +#define P_DATA_MODE_MASK 0x10 +#define P_ASIO_BUFFER_MANAGEMENT_MASK 0x20 + +#define BIT_SKIP_SOUND 0x08 // bit 3 +#define BIT_DATA_MODE 0x10 // bit 4 + +/* Bits in the CMD_MODIFY_CLOCK request. */ +#define CMD_MODIFY_CLOCK_FD_BIT 0x00000001 +#define CMD_MODIFY_CLOCK_T_BIT 0x00000002 +#define CMD_MODIFY_CLOCK_S_BIT 0x00000004 + +/* Access to the results of the CMD_GET_TIME_CODE RMH. */ +#define TIME_CODE_V_MASK 0x00800000 +#define TIME_CODE_N_MASK 0x00400000 +#define TIME_CODE_B_MASK 0x00200000 +#define TIME_CODE_W_MASK 0x00100000 + +/* Values for the CMD_MANAGE_SIGNAL RMH. */ +#define MANAGE_SIGNAL_TIME_CODE 0x01 +#define MANAGE_SIGNAL_MIDI 0x02 + +/* Values for the CMD_CONFIG_TIME_CODE RMH. */ +#define CONFIG_TIME_CODE_CANCEL 0x00001000 + +/* Mask to get only the effective time from the + * high word out of the 2 returned by the DSP + */ +#define PCX_TIME_HI_MASK 0x000fffff + +/* Values for setting a H-Buffer time */ +#define HBUFFER_TIME_HIGH 0x00200000 +#define HBUFFER_TIME_LOW 0x00000000 + +#define NOTIFY_MASK_TIME_HIGH 0x00400000 +#define MULTIPLE_MASK_TIME_HIGH 0x00100000 +#define STREAM_MASK_TIME_HIGH 0x00800000 + + +/* + * + */ +extern struct vx_cmd_info vx_dsp_cmds[]; + +void vx_init_rmh(struct vx_rmh *rmh, unsigned int cmd); + +/** + * vx_send_pipe_cmd_params - fill first command word for pipe commands + * @rmh: the rmh to be modified + * @is_capture: 0 = playback, 1 = capture operation + * @param1: first pipe-parameter + * @param2: second pipe-parameter + */ +static inline void vx_set_pipe_cmd_params(struct vx_rmh *rmh, int is_capture, + int param1, int param2) +{ + if (is_capture) + rmh->Cmd[0] |= COMMAND_RECORD_MASK; + rmh->Cmd[0] |= (((u32)param1 & MASK_FIRST_FIELD) << FIELD_SIZE) & MASK_DSP_WORD; + + if (param2) + rmh->Cmd[0] |= ((u32)param2 & MASK_FIRST_FIELD) & MASK_DSP_WORD; + +} + +/** + * vx_set_stream_cmd_params - fill first command word for stream commands + * @rmh: the rmh to be modified + * @is_capture: 0 = playback, 1 = capture operation + * @pipe: the pipe index (zero-based) + */ +static inline void vx_set_stream_cmd_params(struct vx_rmh *rmh, int is_capture, int pipe) +{ + if (is_capture) + rmh->Cmd[0] |= COMMAND_RECORD_MASK; + rmh->Cmd[0] |= (((u32)pipe & MASK_FIRST_FIELD) << FIELD_SIZE) & MASK_DSP_WORD; +} + +#endif /* __VX_CMD_H */ diff -Nru a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/drivers/vx/vx_core.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,809 @@ +/* + * Driver for Digigram VX soundcards + * + * Hardware core part + * + * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <sound/driver.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <sound/core.h> +#include <sound/pcm.h> +#include <sound/asoundef.h> +#include <sound/info.h> +#include <asm/io.h> +#include <sound/vx_core.h> +#include "vx_cmd.h" + +MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); +MODULE_DESCRIPTION("Common routines for Digigram VX drivers"); +MODULE_LICENSE("GPL"); + + +/* + * snd_vx_delay - delay for the specified time + * @xmsec: the time to delay in msec + */ +void snd_vx_delay(vx_core_t *chip, int xmsec) +{ + if (! (chip->chip_status & VX_STAT_IN_SUSPEND) && ! in_interrupt() && + xmsec >= 1000 / HZ) { + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout((xmsec * HZ + 999) / 1000); + } else { + mdelay(xmsec); + } +} + +/* + * vx_check_reg_bit - wait for the specified bit is set/reset on a register + * @reg: register to check + * @mask: bit mask + * @bit: resultant bit to be checked + * @time: time-out of loop in msec + * + * returns zero if a bit matches, or a negative error code. + */ +int snd_vx_check_reg_bit(vx_core_t *chip, int reg, int mask, int bit, int time) +{ + unsigned long end_time = jiffies + (time * HZ + 999) / 1000; +#ifdef CONFIG_SND_DEBUG + static char *reg_names[VX_REG_MAX] = { + "ICR", "CVR", "ISR", "IVR", "RXH", "RXM", "RXL", + "DMA", "CDSP", "RFREQ", "RUER/V2", "DATA", "MEMIRQ", + "ACQ", "BIT0", "BIT1", "MIC0", "MIC1", "MIC2", + "MIC3", "INTCSR", "CNTRL", "GPIOC", + "LOFREQ", "HIFREQ", "CSUER", "RUER" + }; +#endif + do { + if ((snd_vx_inb(chip, reg) & mask) == bit) + return 0; + //snd_vx_delay(chip, 10); + } while (time_after_eq(end_time, jiffies)); + snd_printd(KERN_DEBUG "vx_check_reg_bit: timeout, reg=%s, mask=0x%x, val=0x%x\n", reg_names[reg], mask, snd_vx_inb(chip, reg)); + return -EIO; +} + +/* + * vx_send_irq_dsp - set command irq bit + * @num: the requested IRQ type, IRQ_XXX + * + * this triggers the specified IRQ request + * returns 0 if successful, or a negative error code. + * + */ +static int vx_send_irq_dsp(vx_core_t *chip, int num) +{ + int nirq; + + /* wait for Hc = 0 */ + if (snd_vx_check_reg_bit(chip, VX_CVR, CVR_HC, 0, 200) < 0) + return -EIO; + + nirq = num; + if (vx_has_new_dsp(chip)) + nirq += VXP_IRQ_OFFSET; + vx_outb(chip, CVR, (nirq >> 1) | CVR_HC); + return 0; +} + + +/* + * vx_reset_chk - reset CHK bit on ISR + * + * returns 0 if successful, or a negative error code. + */ +static int vx_reset_chk(vx_core_t *chip) +{ + /* Reset irq CHK */ + if (vx_send_irq_dsp(chip, IRQ_RESET_CHK) < 0) + return -EIO; + /* Wait until CHK = 0 */ + if (vx_check_isr(chip, ISR_CHK, 0, 200) < 0) + return -EIO; + return 0; +} + +/* + * vx_transfer_end - terminate message transfer + * @cmd: IRQ message to send (IRQ_MESS_XXX_END) + * + * returns 0 if successful, or a negative error code. + * the error code can be VX-specific, retrieved via vx_get_error(). + * NB: call with spinlock held! + */ +static int vx_transfer_end(vx_core_t *chip, int cmd) +{ + int err; + + if ((err = vx_reset_chk(chip)) < 0) + return err; + + /* irq MESS_READ/WRITE_END */ + if ((err = vx_send_irq_dsp(chip, cmd)) < 0) + return err; + + /* Wait CHK = 1 */ + if ((err = vx_wait_isr_bit(chip, ISR_CHK)) < 0) + return err; + + /* If error, Read RX */ + if ((err = vx_inb(chip, ISR)) & ISR_ERR) { + if ((err = vx_wait_for_rx_full(chip)) < 0) { + snd_printd(KERN_DEBUG "transfer_end: error in rx_full\n"); + return err; + } + err = vx_inb(chip, RXH) << 16; + err |= vx_inb(chip, RXM) << 8; + err |= vx_inb(chip, RXL); + snd_printd(KERN_DEBUG "transfer_end: error = 0x%x\n", err); + return -(VX_ERR_MASK | err); + } + return 0; +} + +/* + * vx_read_status - return the status rmh + * @rmh: rmh record to store the status + * + * returns 0 if successful, or a negative error code. + * the error code can be VX-specific, retrieved via vx_get_error(). + * NB: call with spinlock held! + */ +static int vx_read_status(vx_core_t *chip, struct vx_rmh *rmh) +{ + int i, err, val, size; + + /* no read necessary? */ + if (rmh->DspStat == RMH_SSIZE_FIXED && rmh->LgStat == 0) + return 0; + + /* Wait for RX full (with timeout protection) + * The first word of status is in RX + */ + err = vx_wait_for_rx_full(chip); + if (err < 0) + return err; + + /* Read RX */ + val = vx_inb(chip, RXH) << 16; + val |= vx_inb(chip, RXM) << 8; + val |= vx_inb(chip, RXL); + + /* If status given by DSP, let's decode its size */ + switch (rmh->DspStat) { + case RMH_SSIZE_ARG: + size = val & 0xff; + rmh->Stat[0] = val & 0xffff00; + rmh->LgStat = size + 1; + break; + case RMH_SSIZE_MASK: + /* Let's count the arg numbers from a mask */ + rmh->Stat[0] = val; + size = 0; + while (val) { + if (val & 0x01) + size++; + val >>= 1; + } + rmh->LgStat = size + 1; + break; + default: + /* else retrieve the status length given by the driver */ + size = rmh->LgStat; + rmh->Stat[0] = val; /* Val is the status 1st word */ + size--; /* hence adjust remaining length */ + break; + } + + if (size < 1) + return 0; + snd_assert(size <= SIZE_MAX_STATUS, return -EINVAL); + + for (i = 1; i <= size; i++) { + /* trigger an irq MESS_WRITE_NEXT */ + err = vx_send_irq_dsp(chip, IRQ_MESS_WRITE_NEXT); + if (err < 0) + return err; + /* Wait for RX full (with timeout protection) */ + err = vx_wait_for_rx_full(chip); + if (err < 0) + return err; + rmh->Stat[i] = vx_inb(chip, RXH) << 16; + rmh->Stat[i] |= vx_inb(chip, RXM) << 8; + rmh->Stat[i] |= vx_inb(chip, RXL); + } + + return vx_transfer_end(chip, IRQ_MESS_WRITE_END); +} + + +#define MASK_MORE_THAN_1_WORD_COMMAND 0x00008000 +#define MASK_1_WORD_COMMAND 0x00ff7fff + +/* + * vx_send_msg_nolock - send a DSP message and read back the status + * @rmh: the rmh record to send and receive + * + * returns 0 if successful, or a negative error code. + * the error code can be VX-specific, retrieved via vx_get_error(). + * + * this function doesn't call spinlock at all. + */ +int vx_send_msg_nolock(vx_core_t *chip, struct vx_rmh *rmh) +{ + int i, err; + + if (chip->chip_status & VX_STAT_IS_STALE) + return -EBUSY; + + if ((err = vx_reset_chk(chip)) < 0) { + snd_printd(KERN_DEBUG "vx_send_msg: vx_reset_chk error\n"); + return err; + } + +#if 0 + printk(KERN_DEBUG "rmh: cmd = 0x%06x, length = %d, stype = %d\n", + rmh->Cmd[0], rmh->LgCmd, rmh->DspStat); + if (rmh->LgCmd > 1) { + printk(KERN_DEBUG " "); + for (i = 1; i < rmh->LgCmd; i++) + printk("0x%06x ", rmh->Cmd[i]); + printk("\n"); + } +#endif + /* Check bit M is set according to length of the command */ + if (rmh->LgCmd > 1) + rmh->Cmd[0] |= MASK_MORE_THAN_1_WORD_COMMAND; + else + rmh->Cmd[0] &= MASK_1_WORD_COMMAND; + + /* Wait for TX empty */ + if ((err = vx_wait_isr_bit(chip, ISR_TX_EMPTY)) < 0) { + snd_printd(KERN_DEBUG "vx_send_msg: wait tx empty error\n"); + return err; + } + + /* Write Cmd[0] */ + vx_outb(chip, TXH, (rmh->Cmd[0] >> 16) & 0xff); + vx_outb(chip, TXM, (rmh->Cmd[0] >> 8) & 0xff); + vx_outb(chip, TXL, rmh->Cmd[0] & 0xff); + + /* Trigger irq MESSAGE */ + if ((err = vx_send_irq_dsp(chip, IRQ_MESSAGE)) < 0) { + snd_printd(KERN_DEBUG "vx_send_msg: send IRQ_MESSAGE error\n"); + return err; + } + + /* Wait for CHK = 1 */ + if ((err = vx_wait_isr_bit(chip, ISR_CHK)) < 0) + return err; + + /* If error, get error value from RX */ + if (vx_inb(chip, ISR) & ISR_ERR) { + if ((err = vx_wait_for_rx_full(chip)) < 0) { + snd_printd(KERN_DEBUG "vx_send_msg: rx_full read error\n"); + return err; + } + err = vx_inb(chip, RXH) << 16; + err |= vx_inb(chip, RXM) << 8; + err |= vx_inb(chip, RXL); + snd_printd(KERN_DEBUG "msg got error = 0x%x at cmd[0]\n", err); + err = -(VX_ERR_MASK | err); + return err; + } + + /* Send the other words */ + if (rmh->LgCmd > 1) { + for (i = 1; i < rmh->LgCmd; i++) { + /* Wait for TX ready */ + if ((err = vx_wait_isr_bit(chip, ISR_TX_READY)) < 0) { + snd_printd(KERN_DEBUG "vx_send_msg: tx_ready error\n"); + return err; + } + + /* Write Cmd[i] */ + vx_outb(chip, TXH, (rmh->Cmd[i] >> 16) & 0xff); + vx_outb(chip, TXM, (rmh->Cmd[i] >> 8) & 0xff); + vx_outb(chip, TXL, rmh->Cmd[i] & 0xff); + + /* Trigger irq MESS_READ_NEXT */ + if ((err = vx_send_irq_dsp(chip, IRQ_MESS_READ_NEXT)) < 0) { + snd_printd(KERN_DEBUG "vx_send_msg: IRQ_READ_NEXT error\n"); + return err; + } + } + /* Wait for TX empty */ + if ((err = vx_wait_isr_bit(chip, ISR_TX_READY)) < 0) { + snd_printd(KERN_DEBUG "vx_send_msg: TX_READY error\n"); + return err; + } + /* End of transfer */ + err = vx_transfer_end(chip, IRQ_MESS_READ_END); + if (err < 0) + return err; + } + + return vx_read_status(chip, rmh); +} + + +/* + * vx_send_msg - send a DSP message with spinlock + * @rmh: the rmh record to send and receive + * + * returns 0 if successful, or a negative error code. + * see vx_send_msg_nolock(). + */ +int vx_send_msg(vx_core_t *chip, struct vx_rmh *rmh) +{ + int err; + + spin_lock_bh(&chip->lock); + err = vx_send_msg_nolock(chip, rmh); + spin_unlock_bh(&chip->lock); + return err; +} + + +/* + * vx_send_rih_nolock - send an RIH to xilinx + * @cmd: the command to send + * + * returns 0 if successful, or a negative error code. + * the error code can be VX-specific, retrieved via vx_get_error(). + * + * this function doesn't call spinlock at all. + * + * unlike RMH, no command is sent to DSP. + */ +int vx_send_rih_nolock(vx_core_t *chip, int cmd) +{ + int err; + + if (chip->chip_status & VX_STAT_IS_STALE) + return -EBUSY; + +#if 0 + printk(KERN_DEBUG "send_rih: cmd = 0x%x\n", cmd); +#endif + if ((err = vx_reset_chk(chip)) < 0) + return err; + /* send the IRQ */ + if ((err = vx_send_irq_dsp(chip, cmd)) < 0) + return err; + /* Wait CHK = 1 */ + if ((err = vx_wait_isr_bit(chip, ISR_CHK)) < 0) + return err; + /* If error, read RX */ + if (vx_inb(chip, ISR) & ISR_ERR) { + if ((err = vx_wait_for_rx_full(chip)) < 0) + return err; + err = vx_inb(chip, RXH) << 16; + err |= vx_inb(chip, RXM) << 8; + err |= vx_inb(chip, RXL); + return -(VX_ERR_MASK | err); + } + return 0; +} + + +/* + * vx_send_rih - send an RIH with spinlock + * @cmd: the command to send + * + * see vx_send_rih_nolock(). + */ +int vx_send_rih(vx_core_t *chip, int cmd) +{ + int err; + + spin_lock_bh(&chip->lock); + err = vx_send_rih_nolock(chip, cmd); + spin_unlock_bh(&chip->lock); + return err; +} + +#define END_OF_RESET_WAIT_TIME 500 /* us */ + +/** + * snd_vx_boot_xilinx - boot up the xilinx interface + * @boot: the boot record to load + */ +int snd_vx_load_boot_image(vx_core_t *chip, const snd_hwdep_dsp_image_t *boot) +{ + unsigned int i; + int no_fillup = vx_has_new_dsp(chip); + + /* check the length of boot image */ + snd_assert(boot->length > 0, return -EINVAL); + snd_assert(boot->length % 3 == 0, return -EINVAL); + snd_assert(boot->image, return -EINVAL); +#if 0 + { + /* more strict check */ + unsigned int c = ((u32)boot->image[0] << 16) | ((u32)boot->image[1] << 8) | boot->image[2]; + snd_assert(boot->length == (c + 2) * 3, return -EINVAL); + } +#endif + + /* reset dsp */ + vx_reset_dsp(chip); + + udelay(END_OF_RESET_WAIT_TIME); /* another wait? */ + + /* download boot strap */ + for (i = 0; i < 0x600; i += 3) { + if (i >= boot->length) { + if (no_fillup) + break; + if (vx_wait_isr_bit(chip, ISR_TX_EMPTY) < 0) { + snd_printk(KERN_ERR "dsp boot failed at %d\n", i); + return -EIO; + } + vx_outb(chip, TXH, 0); + vx_outb(chip, TXM, 0); + vx_outb(chip, TXL, 0); + } else { + unsigned char image[3]; + if (copy_from_user(image, boot->image + i, 3)) + return -EFAULT; + if (vx_wait_isr_bit(chip, ISR_TX_EMPTY) < 0) { + snd_printk(KERN_ERR "dsp boot failed at %d\n", i); + return -EIO; + } + vx_outb(chip, TXH, image[0]); + vx_outb(chip, TXM, image[1]); + vx_outb(chip, TXL, image[2]); + } + } + return 0; +} + +/* + * vx_test_irq_src - query the source of interrupts + * + * called from irq handler only + */ +static int vx_test_irq_src(vx_core_t *chip, unsigned int *ret) +{ + int err; + + vx_init_rmh(&chip->irq_rmh, CMD_TEST_IT); + spin_lock(&chip->lock); + err = vx_send_msg_nolock(chip, &chip->irq_rmh); + if (err < 0) + *ret = 0; + else + *ret = chip->irq_rmh.Stat[0]; + spin_unlock(&chip->lock); + return err; +} + + +/* + * vx_interrupt - soft irq handler + */ +static void vx_interrupt(unsigned long private_data) +{ + vx_core_t *chip = snd_magic_cast(vx_core_t, (void*)private_data, return); + unsigned int events; + + if (chip->chip_status & VX_STAT_IS_STALE) + return; + + if (vx_test_irq_src(chip, &events) < 0) + return; + +#if 0 + if (events & 0x000800) + printk(KERN_ERR "DSP Stream underrun ! IRQ events = 0x%x\n", events); +#endif + // printk(KERN_DEBUG "IRQ events = 0x%x\n", events); + + /* We must prevent any application using this DSP + * and block any further request until the application + * either unregisters or reloads the DSP + */ + if (events & FATAL_DSP_ERROR) { + snd_printk(KERN_ERR "vx_core: fatal DSP error!!\n"); + return; + } + + /* The start on time code conditions are filled (ie the time code + * received by the board is equal to one of those given to it). + */ + if (events & TIME_CODE_EVENT_PENDING) + ; /* so far, nothing to do yet */ + + /* The frequency has changed on the board (UER mode). */ + if (events & FREQUENCY_CHANGE_EVENT_PENDING) + vx_change_frequency(chip); + + /* update the pcm streams */ + vx_pcm_update_intr(chip, events); +} + + +/** + * snd_vx_irq_handler - interrupt handler + */ +irqreturn_t snd_vx_irq_handler(int irq, void *dev, struct pt_regs *regs) +{ + vx_core_t *chip = snd_magic_cast(vx_core_t, dev, return IRQ_NONE); + + if (! (chip->chip_status & VX_STAT_CHIP_INIT) || + (chip->chip_status & VX_STAT_IS_STALE)) + return IRQ_NONE; + if (! vx_test_and_ack(chip)) + tasklet_hi_schedule(&chip->tq); + return IRQ_HANDLED; +} + + +/* + */ +static void vx_reset_board(vx_core_t *chip, int cold_reset) +{ + snd_assert(chip->ops->reset_board, return); + + /* current source, later sync'ed with target */ + chip->audio_source = VX_AUDIO_SRC_LINE; + if (cold_reset) { + chip->audio_source_target = chip->audio_source; + chip->clock_source = INTERNAL_QUARTZ; + chip->freq = 48000; + chip->uer_detected = VX_UER_MODE_NOT_PRESENT; + chip->uer_bits = SNDRV_PCM_DEFAULT_CON_SPDIF; + } + + chip->ops->reset_board(chip, cold_reset); + + vx_reset_codec(chip, cold_reset); + + vx_set_internal_clock(chip, chip->freq); + + /* Reset the DSP */ + vx_reset_dsp(chip); + + if (vx_is_pcmcia(chip)) { + /* Acknowledge any pending IRQ and reset the MEMIRQ flag. */ + vx_test_and_ack(chip); + vx_validate_irq(chip, 1); + } + + /* init CBits */ + vx_set_iec958_status(chip, chip->uer_bits); +} + + +/* + * proc interface + */ + +static void vx_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer) +{ + vx_core_t *chip = snd_magic_cast(vx_core_t, entry->private_data, return); + static char *audio_src_vxp[] = { "Line", "Mic", "Digital" }; + static char *audio_src_vx2[] = { "Analog", "Analog", "Digital" }; + static char *clock_src[] = { "Internal", "External" }; + static char *uer_type[] = { "Consumer", "Professional", "Not Present" }; + + snd_iprintf(buffer, "%s\n", chip->card->longname); + snd_iprintf(buffer, "DSP audio info:"); + if (chip->audio_info & VX_AUDIO_INFO_REAL_TIME) + snd_iprintf(buffer, " realtime"); + if (chip->audio_info & VX_AUDIO_INFO_OFFLINE) + snd_iprintf(buffer, " offline"); + if (chip->audio_info & VX_AUDIO_INFO_MPEG1) + snd_iprintf(buffer, " mpeg1"); + if (chip->audio_info & VX_AUDIO_INFO_MPEG2) + snd_iprintf(buffer, " mpeg2"); + if (chip->audio_info & VX_AUDIO_INFO_LINEAR_8) + snd_iprintf(buffer, " linear8"); + if (chip->audio_info & VX_AUDIO_INFO_LINEAR_16) + snd_iprintf(buffer, " linear16"); + if (chip->audio_info & VX_AUDIO_INFO_LINEAR_24) + snd_iprintf(buffer, " linear24"); + snd_iprintf(buffer, "\n"); + snd_iprintf(buffer, "Input Source: %s\n", vx_is_pcmcia(chip) ? + audio_src_vxp[chip->audio_source] : + audio_src_vx2[chip->audio_source]); + snd_iprintf(buffer, "Clock Source: %s\n", clock_src[chip->clock_source]); + snd_iprintf(buffer, "Frequency: %d\n", chip->freq); + snd_iprintf(buffer, "Detected Frequency: %d\n", chip->freq_detected); + snd_iprintf(buffer, "Detected UER type: %s\n", uer_type[chip->uer_detected]); +} + +static void vx_proc_init(vx_core_t *chip) +{ + snd_info_entry_t *entry; + + if (! snd_card_proc_new(chip->card, "vx-status", &entry)) + snd_info_set_text_ops(entry, chip, vx_proc_read); +} + + +/** + * snd_vx_dsp_boot - load the DSP boot + */ +int snd_vx_dsp_boot(vx_core_t *chip, const snd_hwdep_dsp_image_t *boot) +{ + int err; + int cold_reset = !(chip->chip_status & VX_STAT_DEVICE_INIT); + + vx_reset_board(chip, cold_reset); + vx_validate_irq(chip, 0); + + if ((err = snd_vx_load_boot_image(chip, boot)) < 0) + return err; + snd_vx_delay(chip, 10); + + return 0; +} + +/** + * snd_vx_dsp_load - load the DSP image + */ +int snd_vx_dsp_load(vx_core_t *chip, const snd_hwdep_dsp_image_t *dsp) +{ + unsigned int i; + int err; + unsigned int csum = 0; + unsigned char image[3], *cptr; + + snd_assert(dsp->length % 3 == 0, return -EINVAL); + + vx_toggle_dac_mute(chip, 1); + + /* Transfert data buffer from PC to DSP */ + for (i = 0; i < dsp->length; i += 3) { + if (copy_from_user(image, dsp->image + i, 3)) + return -EFAULT; + /* Wait DSP ready for a new read */ + if ((err = vx_wait_isr_bit(chip, ISR_TX_EMPTY)) < 0) { + printk("dsp loading error at position %d\n", i); + return err; + } + cptr = image; + csum ^= *cptr; + csum = (csum >> 24) | (csum << 8); + vx_outb(chip, TXH, *cptr++); + csum ^= *cptr; + csum = (csum >> 24) | (csum << 8); + vx_outb(chip, TXM, *cptr++); + csum ^= *cptr; + csum = (csum >> 24) | (csum << 8); + vx_outb(chip, TXL, *cptr++); + } + snd_printdd(KERN_DEBUG "checksum = 0x%08x\n", csum); + + snd_vx_delay(chip, 200); + + if ((err = vx_wait_isr_bit(chip, ISR_CHK)) < 0) + return err; + + vx_toggle_dac_mute(chip, 0); + + vx_test_and_ack(chip); + vx_validate_irq(chip, 1); + + return 0; +} + +/** + * snd_vx_create - constructor for vx_core_t + * @hw: hardware specific record + * + * this function allocates the instance and prepare for the hardware + * initialization. + * + * return the instance pointer if successful, NULL in error. + */ +vx_core_t *snd_vx_create(snd_card_t *card, struct snd_vx_hardware *hw, + struct snd_vx_ops *ops, + int extra_size) +{ + vx_core_t *chip; + + snd_assert(card && hw && ops, return NULL); + + chip = snd_magic_kcalloc(vx_core_t, extra_size, GFP_KERNEL); + if (! chip) { + snd_printk(KERN_ERR "vx_core: no memory\n"); + return NULL; + } + spin_lock_init(&chip->lock); + spin_lock_init(&chip->irq_lock); + chip->irq = -1; + chip->hw = hw; + chip->type = hw->type; + chip->ops = ops; + tasklet_init(&chip->tq, vx_interrupt, (unsigned long)chip); + init_MUTEX(&chip->mixer_mutex); + + chip->card = card; + card->private_data = chip; + strcpy(card->driver, hw->name); + sprintf(card->shortname, "Digigram %s", hw->name); + + vx_proc_init(chip); + + return chip; +} + +#ifdef CONFIG_PM +/* + * suspend + */ +void snd_vx_suspend(vx_core_t *chip) +{ + unsigned int i; + + chip->chip_status |= VX_STAT_IN_SUSPEND; + for (i = 0; i < chip->hw->num_codecs; i++) + snd_pcm_suspend_all(chip->pcm[i]); + if (chip->hwdep) + chip->hwdep->dsp_loaded = 0; +} + +/* + * resume + */ +void snd_vx_resume(vx_core_t *chip) +{ + /* clear all stuff... */ + chip->chip_status &= ~(VX_STAT_IN_SUSPEND|VX_STAT_CHIP_INIT); +} + +#endif + +/* + * module entries + */ +static int __init alsa_vx_core_init(void) +{ + return 0; +} + +static void __exit alsa_vx_core_exit(void) +{ +} + +module_init(alsa_vx_core_init) +module_exit(alsa_vx_core_exit) + +/* + * exports + */ +EXPORT_SYMBOL(snd_vx_check_reg_bit); +EXPORT_SYMBOL(snd_vx_create); +EXPORT_SYMBOL(snd_vx_hwdep_new); +EXPORT_SYMBOL(snd_vx_irq_handler); +EXPORT_SYMBOL(snd_vx_delay); +EXPORT_SYMBOL(snd_vx_dsp_boot); +EXPORT_SYMBOL(snd_vx_dsp_load); +EXPORT_SYMBOL(snd_vx_load_boot_image); +#ifdef CONFIG_PM +EXPORT_SYMBOL(snd_vx_suspend); +EXPORT_SYMBOL(snd_vx_resume); +#endif diff -Nru a/sound/drivers/vx/vx_hwdep.c b/sound/drivers/vx/vx_hwdep.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/drivers/vx/vx_hwdep.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,122 @@ +/* + * Driver for Digigram VX soundcards + * + * hwdep device manager + * + * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <sound/driver.h> +#include <sound/core.h> +#include <sound/hwdep.h> +#include <sound/vx_core.h> + +static int vx_hwdep_open(snd_hwdep_t *hw, struct file *file) +{ + return 0; +} + +static int vx_hwdep_release(snd_hwdep_t *hw, struct file *file) +{ + return 0; +} + +static int vx_hwdep_dsp_status(snd_hwdep_t *hw, snd_hwdep_dsp_status_t *info) +{ + static char *type_ids[VX_TYPE_NUMS] = { + [VX_TYPE_BOARD] = "vxboard", + [VX_TYPE_V2] = "vx222", + [VX_TYPE_MIC] = "vx222", + [VX_TYPE_VXPOCKET] = "vxpocket", + [VX_TYPE_VXP440] = "vxp440", + }; + vx_core_t *vx = snd_magic_cast(vx_core_t, hw->private_data, return -ENXIO); + + snd_assert(type_ids[vx->type], return -EINVAL); + strcpy(info->id, type_ids[vx->type]); + if (vx_is_pcmcia(vx)) + info->num_dsps = 4; + else + info->num_dsps = 3; + if (vx->chip_status & VX_STAT_CHIP_INIT) + info->chip_ready = 1; + info->version = VX_DRIVER_VERSION; + return 0; +} + +static int vx_hwdep_dsp_load(snd_hwdep_t *hw, snd_hwdep_dsp_image_t *dsp) +{ + vx_core_t *vx = snd_magic_cast(vx_core_t, hw->private_data, return -ENXIO); + int index, err; + + snd_assert(vx->ops->load_dsp, return -ENXIO); + err = vx->ops->load_dsp(vx, dsp); + if (err < 0) + return err; + + index = dsp->index; + if (! vx_is_pcmcia(vx)) + index++; + if (index == 1) + vx->chip_status |= VX_STAT_XILINX_LOADED; + if (index < 3) + return 0; + + /* ok, we reached to the last one */ + /* create the devices if not built yet */ + if (! (vx->chip_status & VX_STAT_DEVICE_INIT)) { + if ((err = snd_vx_pcm_new(vx)) < 0) + return err; + + if ((err = snd_vx_mixer_new(vx)) < 0) + return err; + + if (vx->ops->add_controls) + if ((err = vx->ops->add_controls(vx)) < 0) + return err; + + if ((err = snd_card_register(vx->card)) < 0) + return err; + + vx->chip_status |= VX_STAT_DEVICE_INIT; + } + vx->chip_status |= VX_STAT_CHIP_INIT; + return 0; +} + + +/* exported */ +int snd_vx_hwdep_new(vx_core_t *chip) +{ + int err; + snd_hwdep_t *hw; + + if ((err = snd_hwdep_new(chip->card, SND_VX_HWDEP_ID, 0, &hw)) < 0) + return err; + + hw->iface = SNDRV_HWDEP_IFACE_VX; + hw->private_data = chip; + hw->ops.open = vx_hwdep_open; + hw->ops.release = vx_hwdep_release; + hw->ops.dsp_status = vx_hwdep_dsp_status; + hw->ops.dsp_load = vx_hwdep_dsp_load; + hw->exclusive = 1; + sprintf(hw->name, "VX Loader (%s)", chip->card->driver); + chip->hwdep = hw; + + return 0; +} diff -Nru a/sound/drivers/vx/vx_mixer.c b/sound/drivers/vx/vx_mixer.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/drivers/vx/vx_mixer.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,951 @@ +/* + * Driver for Digigram VX soundcards + * + * Common mixer part + * + * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <sound/driver.h> +#include <sound/core.h> +#include <sound/control.h> +#include <sound/vx_core.h> +#include "vx_cmd.h" + +#define chip_t vx_core_t + + +/* + * write a codec data (24bit) + */ +static void vx_write_codec_reg(vx_core_t *chip, int codec, unsigned int data) +{ + unsigned long flags; + + snd_assert(chip->ops->write_codec, return); + + if (chip->chip_status & VX_STAT_IS_STALE) + return; + + spin_lock_irqsave(&chip->lock, flags); + chip->ops->write_codec(chip, codec, data); + spin_unlock_irqrestore(&chip->lock, flags); +} + +/* + * Data type used to access the Codec + */ +typedef union { + u32 l; +#ifdef SNDRV_BIG_ENDIAN + struct w { + u16 h; + u16 l; + } w; + struct b { + u8 hh; + u8 mh; + u8 ml; + u8 ll; + } b; +#else /* LITTLE_ENDIAN */ + struct w { + u16 l; + u16 h; + } w; + struct b { + u8 ll; + u8 ml; + u8 mh; + u8 hh; + } b; +#endif +} vx_codec_data_t; + +#define SET_CDC_DATA_SEL(di,s) ((di).b.mh = (u8) (s)) +#define SET_CDC_DATA_REG(di,r) ((di).b.ml = (u8) (r)) +#define SET_CDC_DATA_VAL(di,d) ((di).b.ll = (u8) (d)) +#define SET_CDC_DATA_INIT(di) ((di).l = 0L, SET_CDC_DATA_SEL(di,XX_CODEC_SELECTOR)) + +/* + * set up codec register and write the value + * @codec: the codec id, 0 or 1 + * @reg: register index + * @val: data value + */ +static void vx_set_codec_reg(vx_core_t *chip, int codec, int reg, int val) +{ + vx_codec_data_t data; + /* DAC control register */ + SET_CDC_DATA_INIT(data); + SET_CDC_DATA_REG(data, reg); + SET_CDC_DATA_VAL(data, val); + vx_write_codec_reg(chip, codec, data.l); +} + + +/* + * vx_set_analog_output_level - set the output attenuation level + * @codec: the output codec, 0 or 1. (1 for VXP440 only) + * @left: left output level, 0 = mute + * @right: right output level + */ +static void vx_set_analog_output_level(vx_core_t *chip, int codec, int left, int right) +{ + left = chip->hw->output_level_max - left; + right = chip->hw->output_level_max - right; + + if (chip->ops->akm_write) { + chip->ops->akm_write(chip, XX_CODEC_LEVEL_LEFT_REGISTER, left); + chip->ops->akm_write(chip, XX_CODEC_LEVEL_RIGHT_REGISTER, right); + } else { + /* convert to attenuation level: 0 = 0dB (max), 0xe3 = -113.5 dB (min) */ + vx_set_codec_reg(chip, codec, XX_CODEC_LEVEL_LEFT_REGISTER, left); + vx_set_codec_reg(chip, codec, XX_CODEC_LEVEL_RIGHT_REGISTER, right); + } +} + + +/* + * vx_toggle_dac_mute - mute/unmute DAC + * @mute: 0 = unmute, 1 = mute + */ + +#define DAC_ATTEN_MIN 0x08 +#define DAC_ATTEN_MAX 0x38 + +void vx_toggle_dac_mute(vx_core_t *chip, int mute) +{ + unsigned int i; + for (i = 0; i < chip->hw->num_codecs; i++) { + if (chip->ops->akm_write) + chip->ops->akm_write(chip, XX_CODEC_DAC_CONTROL_REGISTER, mute); /* XXX */ + else + vx_set_codec_reg(chip, i, XX_CODEC_DAC_CONTROL_REGISTER, + mute ? DAC_ATTEN_MAX : DAC_ATTEN_MIN); + } +} + +/* + * vx_reset_codec - reset and initialize the codecs + */ +void vx_reset_codec(vx_core_t *chip, int cold_reset) +{ + unsigned int i; + int port = chip->type >= VX_TYPE_VXPOCKET ? 0x75 : 0x65; + + chip->ops->reset_codec(chip); + + /* AKM codecs should be initialized in reset_codec callback */ + if (! chip->ops->akm_write) { + /* initialize old codecs */ + for (i = 0; i < chip->hw->num_codecs; i++) { + /* DAC control register (change level when zero crossing + mute) */ + vx_set_codec_reg(chip, i, XX_CODEC_DAC_CONTROL_REGISTER, DAC_ATTEN_MAX); + /* ADC control register */ + vx_set_codec_reg(chip, i, XX_CODEC_ADC_CONTROL_REGISTER, 0x00); + /* Port mode register */ + vx_set_codec_reg(chip, i, XX_CODEC_PORT_MODE_REGISTER, port); + /* Clock control register */ + vx_set_codec_reg(chip, i, XX_CODEC_CLOCK_CONTROL_REGISTER, 0x00); + } + } + + /* mute analog output */ + for (i = 0; i < chip->hw->num_codecs; i++) { + chip->output_level[i][0] = 0; + chip->output_level[i][1] = 0; + vx_set_analog_output_level(chip, i, 0, 0); + } +} + +/* + * change the audio input source + * @src: the target source (VX_AUDIO_SRC_XXX) + */ +static void vx_change_audio_source(vx_core_t *chip, int src) +{ + unsigned long flags; + + if (chip->chip_status & VX_STAT_IS_STALE) + return; + + spin_lock_irqsave(&chip->lock, flags); + chip->ops->change_audio_source(chip, src); + spin_unlock_irqrestore(&chip->lock, flags); +} + + +/* + * change the audio source if necessary and possible + * returns 1 if the source is actually changed. + */ +int vx_sync_audio_source(vx_core_t *chip) +{ + if (chip->audio_source_target == chip->audio_source || + chip->pcm_running) + return 0; + vx_change_audio_source(chip, chip->audio_source_target); + chip->audio_source = chip->audio_source_target; + return 1; +} + + +/* + * audio level, mute, monitoring + */ +struct vx_audio_level { + unsigned int has_level: 1; + unsigned int has_monitor_level: 1; + unsigned int has_mute: 1; + unsigned int has_monitor_mute: 1; + unsigned int mute; + unsigned int monitor_mute; + short level; + short monitor_level; +}; + +static int vx_adjust_audio_level(vx_core_t *chip, int audio, int capture, + struct vx_audio_level *info) +{ + struct vx_rmh rmh; + + if (chip->chip_status & VX_STAT_IS_STALE) + return -EBUSY; + + vx_init_rmh(&rmh, CMD_AUDIO_LEVEL_ADJUST); + if (capture) + rmh.Cmd[0] |= COMMAND_RECORD_MASK; + /* Add Audio IO mask */ + rmh.Cmd[1] = 1 << audio; + rmh.Cmd[2] = 0; + if (info->has_level) { + rmh.Cmd[0] |= VALID_AUDIO_IO_DIGITAL_LEVEL; + rmh.Cmd[2] |= info->level; + } + if (info->has_monitor_level) { + rmh.Cmd[0] |= VALID_AUDIO_IO_MONITORING_LEVEL; + rmh.Cmd[2] |= ((unsigned int)info->monitor_level << 10); + } + if (info->has_mute) { + rmh.Cmd[0] |= VALID_AUDIO_IO_MUTE_LEVEL; + if (info->mute) + rmh.Cmd[2] |= AUDIO_IO_HAS_MUTE_LEVEL; + } + if (info->has_monitor_mute) { + /* validate flag for M2 at least to unmute it */ + rmh.Cmd[0] |= VALID_AUDIO_IO_MUTE_MONITORING_1 | VALID_AUDIO_IO_MUTE_MONITORING_2; + if (info->monitor_mute) + rmh.Cmd[2] |= AUDIO_IO_HAS_MUTE_MONITORING_1; + } + + return vx_send_msg(chip, &rmh); +} + + +#if 0 // not used +static int vx_read_audio_level(vx_core_t *chip, int audio, int capture, + struct vx_audio_level *info) +{ + int err; + struct vx_rmh rmh; + + memset(info, 0, sizeof(*info)); + vx_init_rmh(&rmh, CMD_GET_AUDIO_LEVELS); + if (capture) + rmh.Cmd[0] |= COMMAND_RECORD_MASK; + /* Add Audio IO mask */ + rmh.Cmd[1] = 1 << audio; + err = vx_send_msg(chip, &rmh); + if (err < 0) + return err; + info.level = rmh.Stat[0] & MASK_DSP_WORD_LEVEL; + info.monitor_level = (rmh.Stat[0] >> 10) & MASK_DSP_WORD_LEVEL; + info.mute = (rmh.Stat[i] & AUDIO_IO_HAS_MUTE_LEVEL) ? 1 : 0; + info.monitor_mute = (rmh.Stat[i] & AUDIO_IO_HAS_MUTE_MONITORING_1) ? 1 : 0; + return 0; +} +#endif // not used + +/* + * set the monitoring level and mute state of the given audio + * no more static, because must be called from vx_pcm to demute monitoring + */ +int vx_set_monitor_level(vx_core_t *chip, int audio, int level, int active) +{ + struct vx_audio_level info; + + memset(&info, 0, sizeof(info)); + info.has_monitor_level = 1; + info.monitor_level = level; + info.has_monitor_mute = 1; + info.monitor_mute = !active; + chip->audio_monitor[audio] = level; + chip->audio_monitor_active[audio] = active; + return vx_adjust_audio_level(chip, audio, 0, &info); /* playback only */ +} + + +/* + * set the mute status of the given audio + */ +static int vx_set_audio_switch(vx_core_t *chip, int audio, int active) +{ + struct vx_audio_level info; + + memset(&info, 0, sizeof(info)); + info.has_mute = 1; + info.mute = !active; + chip->audio_active[audio] = active; + return vx_adjust_audio_level(chip, audio, 0, &info); /* playback only */ +} + +/* + * set the mute status of the given audio + */ +static int vx_set_audio_gain(vx_core_t *chip, int audio, int capture, int level) +{ + struct vx_audio_level info; + + memset(&info, 0, sizeof(info)); + info.has_level = 1; + info.level = level; + chip->audio_gain[capture][audio] = level; + return vx_adjust_audio_level(chip, audio, capture, &info); +} + +/* + * reset all audio levels + */ +static void vx_reset_audio_levels(vx_core_t *chip) +{ + unsigned int i, c; + struct vx_audio_level info; + + memset(chip->audio_gain, 0, sizeof(chip->audio_gain)); + memset(chip->audio_active, 0, sizeof(chip->audio_active)); + memset(chip->audio_monitor, 0, sizeof(chip->audio_monitor)); + memset(chip->audio_monitor_active, 0, sizeof(chip->audio_monitor_active)); + + for (c = 0; c < 2; c++) { + for (i = 0; i < chip->hw->num_ins * 2; i++) { + memset(&info, 0, sizeof(info)); + if (c == 0) { + info.has_monitor_level = 1; + info.has_mute = 1; + info.has_monitor_mute = 1; + } + info.has_level = 1; + info.level = CVAL_0DB; /* default: 0dB */ + vx_adjust_audio_level(chip, i, c, &info); + chip->audio_gain[c][i] = CVAL_0DB; + chip->audio_monitor[i] = CVAL_0DB; + } + } +} + + +/* + * VU, peak meter record + */ + +#define VU_METER_CHANNELS 2 + +struct vx_vu_meter { + int saturated; + int vu_level; + int peak_level; +}; + +/* + * get the VU and peak meter values + * @audio: the audio index + * @capture: 0 = playback, 1 = capture operation + * @info: the array of vx_vu_meter records (size = 2). + */ +static int vx_get_audio_vu_meter(vx_core_t *chip, int audio, int capture, struct vx_vu_meter *info) +{ + struct vx_rmh rmh; + int i, err; + + if (chip->chip_status & VX_STAT_IS_STALE) + return -EBUSY; + + vx_init_rmh(&rmh, CMD_AUDIO_VU_PIC_METER); + rmh.LgStat += 2 * VU_METER_CHANNELS; + if (capture) + rmh.Cmd[0] |= COMMAND_RECORD_MASK; + + /* Add Audio IO mask */ + rmh.Cmd[1] = 0; + for (i = 0; i < VU_METER_CHANNELS; i++) + rmh.Cmd[1] |= 1 << (audio + i); + err = vx_send_msg(chip, &rmh); + if (err < 0) + return err; + /* Read response */ + for (i = 0; i < 2 * VU_METER_CHANNELS; i +=2) { + info->saturated = (rmh.Stat[0] & (1 << (audio + i))) ? 1 : 0; + info->vu_level = rmh.Stat[i + 1]; + info->peak_level = rmh.Stat[i + 2]; + info++; + } + return 0; +} + + +/* + * control API entries + */ + +/* + * output level control + */ +static int vx_output_level_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + vx_core_t *chip = snd_kcontrol_chip(kcontrol); + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = chip->hw->output_level_max; + return 0; +} + +static int vx_output_level_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + vx_core_t *chip = snd_kcontrol_chip(kcontrol); + int codec = kcontrol->id.index; + down(&chip->mixer_mutex); + ucontrol->value.integer.value[0] = chip->output_level[codec][0]; + ucontrol->value.integer.value[1] = chip->output_level[codec][1]; + up(&chip->mixer_mutex); + return 0; +} + +static int vx_output_level_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + vx_core_t *chip = snd_kcontrol_chip(kcontrol); + int codec = kcontrol->id.index; + down(&chip->mixer_mutex); + if (ucontrol->value.integer.value[0] != chip->output_level[codec][0] || + ucontrol->value.integer.value[1] != chip->output_level[codec][1]) { + vx_set_analog_output_level(chip, codec, + ucontrol->value.integer.value[0], + ucontrol->value.integer.value[1]); + chip->output_level[codec][0] = ucontrol->value.integer.value[0]; + chip->output_level[codec][1] = ucontrol->value.integer.value[1]; + up(&chip->mixer_mutex); + return 1; + } + up(&chip->mixer_mutex); + return 0; +} + +static snd_kcontrol_new_t vx_control_output_level = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Volume", + .info = vx_output_level_info, + .get = vx_output_level_get, + .put = vx_output_level_put, +}; + +/* + * audio source select + */ +static int vx_audio_src_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + static char *texts_mic[3] = { + "Digital", "Line", "Mic" + }; + static char *texts_vx2[2] = { + "Digital", "Analog" + }; + vx_core_t *chip = snd_kcontrol_chip(kcontrol); + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + if (chip->type >= VX_TYPE_VXPOCKET) { + uinfo->value.enumerated.items = 3; + if (uinfo->value.enumerated.item > 2) + uinfo->value.enumerated.item = 2; + strcpy(uinfo->value.enumerated.name, + texts_mic[uinfo->value.enumerated.item]); + } else { + uinfo->value.enumerated.items = 2; + if (uinfo->value.enumerated.item > 1) + uinfo->value.enumerated.item = 1; + strcpy(uinfo->value.enumerated.name, + texts_vx2[uinfo->value.enumerated.item]); + } + return 0; +} + +static int vx_audio_src_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + vx_core_t *chip = snd_kcontrol_chip(kcontrol); + ucontrol->value.enumerated.item[0] = chip->audio_source_target; + return 0; +} + +static int vx_audio_src_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + vx_core_t *chip = snd_kcontrol_chip(kcontrol); + down(&chip->mixer_mutex); + if (chip->audio_source_target != ucontrol->value.enumerated.item[0]) { + chip->audio_source_target = ucontrol->value.enumerated.item[0]; + vx_sync_audio_source(chip); + up(&chip->mixer_mutex); + return 1; + } + up(&chip->mixer_mutex); + return 0; +} + +static snd_kcontrol_new_t vx_control_audio_src = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = vx_audio_src_info, + .get = vx_audio_src_get, + .put = vx_audio_src_put, +}; + +/* + * Audio Gain + */ +static int vx_audio_gain_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = CVAL_MAX; + return 0; +} + +static int vx_audio_gain_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + vx_core_t *chip = snd_kcontrol_chip(kcontrol); + int audio = kcontrol->private_value & 0xff; + int capture = (kcontrol->private_value >> 8) & 1; + + down(&chip->mixer_mutex); + ucontrol->value.integer.value[0] = chip->audio_gain[capture][audio]; + ucontrol->value.integer.value[1] = chip->audio_gain[capture][audio+1]; + up(&chip->mixer_mutex); + return 0; +} + +static int vx_audio_gain_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + vx_core_t *chip = snd_kcontrol_chip(kcontrol); + int audio = kcontrol->private_value & 0xff; + int capture = (kcontrol->private_value >> 8) & 1; + + down(&chip->mixer_mutex); + if (ucontrol->value.integer.value[0] != chip->audio_gain[capture][audio] || + ucontrol->value.integer.value[1] != chip->audio_gain[capture][audio+1]) { + vx_set_audio_gain(chip, audio, capture, ucontrol->value.integer.value[0]); + vx_set_audio_gain(chip, audio+1, capture, ucontrol->value.integer.value[1]); + up(&chip->mixer_mutex); + return 1; + } + up(&chip->mixer_mutex); + return 0; +} + +static int vx_audio_monitor_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + vx_core_t *chip = snd_kcontrol_chip(kcontrol); + int audio = kcontrol->private_value & 0xff; + + down(&chip->mixer_mutex); + ucontrol->value.integer.value[0] = chip->audio_monitor[audio]; + ucontrol->value.integer.value[1] = chip->audio_monitor[audio+1]; + up(&chip->mixer_mutex); + return 0; +} + +static int vx_audio_monitor_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + vx_core_t *chip = snd_kcontrol_chip(kcontrol); + int audio = kcontrol->private_value & 0xff; + + down(&chip->mixer_mutex); + if (ucontrol->value.integer.value[0] != chip->audio_monitor[audio] || + ucontrol->value.integer.value[1] != chip->audio_monitor[audio+1]) { + vx_set_monitor_level(chip, audio, ucontrol->value.integer.value[0], + chip->audio_monitor_active[audio]); + vx_set_monitor_level(chip, audio+1, ucontrol->value.integer.value[1], + chip->audio_monitor_active[audio+1]); + up(&chip->mixer_mutex); + return 1; + } + up(&chip->mixer_mutex); + return 0; +} + +static int vx_audio_sw_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int vx_audio_sw_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + vx_core_t *chip = snd_kcontrol_chip(kcontrol); + int audio = kcontrol->private_value & 0xff; + + down(&chip->mixer_mutex); + ucontrol->value.integer.value[0] = chip->audio_active[audio]; + ucontrol->value.integer.value[1] = chip->audio_active[audio+1]; + up(&chip->mixer_mutex); + return 0; +} + +static int vx_audio_sw_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + vx_core_t *chip = snd_kcontrol_chip(kcontrol); + int audio = kcontrol->private_value & 0xff; + + down(&chip->mixer_mutex); + if (ucontrol->value.integer.value[0] != chip->audio_active[audio] || + ucontrol->value.integer.value[1] != chip->audio_active[audio+1]) { + vx_set_audio_switch(chip, audio, ucontrol->value.integer.value[0]); + vx_set_audio_switch(chip, audio+1, ucontrol->value.integer.value[1]); + up(&chip->mixer_mutex); + return 1; + } + up(&chip->mixer_mutex); + return 0; +} + +static int vx_monitor_sw_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + vx_core_t *chip = snd_kcontrol_chip(kcontrol); + int audio = kcontrol->private_value & 0xff; + + down(&chip->mixer_mutex); + ucontrol->value.integer.value[0] = chip->audio_monitor_active[audio]; + ucontrol->value.integer.value[1] = chip->audio_monitor_active[audio+1]; + up(&chip->mixer_mutex); + return 0; +} + +static int vx_monitor_sw_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + vx_core_t *chip = snd_kcontrol_chip(kcontrol); + int audio = kcontrol->private_value & 0xff; + + down(&chip->mixer_mutex); + if (ucontrol->value.integer.value[0] != chip->audio_monitor_active[audio] || + ucontrol->value.integer.value[1] != chip->audio_monitor_active[audio+1]) { + vx_set_monitor_level(chip, audio, chip->audio_monitor[audio], + ucontrol->value.integer.value[0]); + vx_set_monitor_level(chip, audio+1, chip->audio_monitor[audio+1], + ucontrol->value.integer.value[1]); + up(&chip->mixer_mutex); + return 1; + } + up(&chip->mixer_mutex); + return 0; +} + +static snd_kcontrol_new_t vx_control_audio_gain = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* name will be filled later */ + .info = vx_audio_gain_info, + .get = vx_audio_gain_get, + .put = vx_audio_gain_put +}; +static snd_kcontrol_new_t vx_control_output_switch = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "PCM Playback Switch", + .info = vx_audio_sw_info, + .get = vx_audio_sw_get, + .put = vx_audio_sw_put +}; +static snd_kcontrol_new_t vx_control_monitor_gain = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Monitoring Volume", + .info = vx_audio_gain_info, /* shared */ + .get = vx_audio_monitor_get, + .put = vx_audio_monitor_put +}; +static snd_kcontrol_new_t vx_control_monitor_switch = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Monitoring Switch", + .info = vx_audio_sw_info, /* shared */ + .get = vx_monitor_sw_get, + .put = vx_monitor_sw_put +}; + + +/* + * IEC958 status bits + */ +static int vx_iec958_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; + uinfo->count = 1; + return 0; +} + +static int vx_iec958_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + vx_core_t *chip = snd_kcontrol_chip(kcontrol); + + down(&chip->mixer_mutex); + ucontrol->value.iec958.status[0] = (chip->uer_bits >> 0) & 0xff; + ucontrol->value.iec958.status[1] = (chip->uer_bits >> 8) & 0xff; + ucontrol->value.iec958.status[2] = (chip->uer_bits >> 16) & 0xff; + ucontrol->value.iec958.status[3] = (chip->uer_bits >> 24) & 0xff; + up(&chip->mixer_mutex); + return 0; +} + +static int vx_iec958_mask_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ucontrol->value.iec958.status[0] = 0xff; + ucontrol->value.iec958.status[1] = 0xff; + ucontrol->value.iec958.status[2] = 0xff; + ucontrol->value.iec958.status[3] = 0xff; + return 0; +} + +static int vx_iec958_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + vx_core_t *chip = snd_kcontrol_chip(kcontrol); + unsigned int val; + + val = (ucontrol->value.iec958.status[0] << 0) | + (ucontrol->value.iec958.status[1] << 8) | + (ucontrol->value.iec958.status[2] << 16) | + (ucontrol->value.iec958.status[3] << 24); + down(&chip->mixer_mutex); + if (chip->uer_bits != val) { + chip->uer_bits = val; + vx_set_iec958_status(chip, val); + up(&chip->mixer_mutex); + return 1; + } + up(&chip->mixer_mutex); + return 0; +} + +static snd_kcontrol_new_t vx_control_iec958_mask = { + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,MASK), + .info = vx_iec958_info, /* shared */ + .get = vx_iec958_mask_get, +}; + +static snd_kcontrol_new_t vx_control_iec958 = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), + .info = vx_iec958_info, + .get = vx_iec958_get, + .put = vx_iec958_put +}; + + +/* + * VU meter + */ + +#define METER_MAX 0xff +#define METER_SHIFT 16 + +static int vx_vu_meter_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = METER_MAX; + return 0; +} + +static int vx_vu_meter_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + vx_core_t *chip = snd_kcontrol_chip(kcontrol); + struct vx_vu_meter meter[2]; + int audio = kcontrol->private_value & 0xff; + int capture = (kcontrol->private_value >> 8) & 1; + + vx_get_audio_vu_meter(chip, audio, capture, meter); + ucontrol->value.integer.value[0] = meter[0].vu_level >> METER_SHIFT; + ucontrol->value.integer.value[1] = meter[1].vu_level >> METER_SHIFT; + return 0; +} + +static int vx_peak_meter_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + vx_core_t *chip = snd_kcontrol_chip(kcontrol); + struct vx_vu_meter meter[2]; + int audio = kcontrol->private_value & 0xff; + int capture = (kcontrol->private_value >> 8) & 1; + + vx_get_audio_vu_meter(chip, audio, capture, meter); + ucontrol->value.integer.value[0] = meter[0].peak_level >> METER_SHIFT; + ucontrol->value.integer.value[1] = meter[1].peak_level >> METER_SHIFT; + return 0; +} + +static int vx_saturation_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int vx_saturation_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + vx_core_t *chip = snd_kcontrol_chip(kcontrol); + struct vx_vu_meter meter[2]; + int audio = kcontrol->private_value & 0xff; + + vx_get_audio_vu_meter(chip, audio, 1, meter); /* capture only */ + ucontrol->value.integer.value[0] = meter[0].saturated; + ucontrol->value.integer.value[1] = meter[1].saturated; + return 0; +} + +static snd_kcontrol_new_t vx_control_vu_meter = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + /* name will be filled later */ + .info = vx_vu_meter_info, + .get = vx_vu_meter_get, +}; + +static snd_kcontrol_new_t vx_control_peak_meter = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + /* name will be filled later */ + .info = vx_vu_meter_info, /* shared */ + .get = vx_peak_meter_get, +}; + +static snd_kcontrol_new_t vx_control_saturation = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Input Saturation", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = vx_saturation_info, + .get = vx_saturation_get, +}; + + + +/* + * + */ + +int snd_vx_mixer_new(vx_core_t *chip) +{ + unsigned int i, c; + int err; + snd_kcontrol_new_t temp; + snd_card_t *card = chip->card; + char name[32]; + + strcpy(card->mixername, card->driver); + + /* output level controls */ + for (i = 0; i < chip->hw->num_outs; i++) { + temp = vx_control_output_level; + temp.index = i; + if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0) + return err; + } + + /* PCM volumes, switches, monitoring */ + for (i = 0; i < chip->hw->num_outs; i++) { + int val = i * 2; + temp = vx_control_audio_gain; + temp.index = i; + temp.name = "PCM Playback Volume"; + temp.private_value = val; + if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0) + return err; + temp = vx_control_output_switch; + temp.index = i; + temp.private_value = val; + if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0) + return err; + temp = vx_control_monitor_gain; + temp.index = i; + temp.private_value = val; + if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0) + return err; + temp = vx_control_monitor_switch; + temp.index = i; + temp.private_value = val; + if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0) + return err; + } + for (i = 0; i < chip->hw->num_outs; i++) { + temp = vx_control_audio_gain; + temp.index = i; + temp.name = "PCM Capture Volume"; + temp.private_value = (i * 2) | (1 << 8); + if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0) + return err; + } + + /* Audio source */ + if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_audio_src, chip))) < 0) + return err; + /* IEC958 controls */ + if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_iec958_mask, chip))) < 0) + return err; + if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_iec958, chip))) < 0) + return err; + /* VU, peak, saturation meters */ + for (c = 0; c < 1; c++) { + static char *dir[2] = { "Output", "Input" }; + for (i = 0; i < chip->hw->num_ins; i++) { + int val = (i * 2) | (c << 8); + if (c == 1) { + temp = vx_control_saturation; + temp.index = i; + temp.private_value = val; + if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0) + return err; + } + sprintf(name, "%s VU Meter", dir[c]); + temp = vx_control_vu_meter; + temp.index = i; + temp.name = name; + temp.private_value = val; + if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0) + return err; + sprintf(name, "%s Peak Meter", dir[c]); + temp = vx_control_peak_meter; + temp.index = i; + temp.name = name; + temp.private_value = val; + if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0) + return err; + } + } + vx_reset_audio_levels(chip); + return 0; +} diff -Nru a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/drivers/vx/vx_pcm.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,1307 @@ +/* + * Driver for Digigram VX soundcards + * + * PCM part + * + * Copyright (c) 2002,2003 by Takashi Iwai <tiwai@suse.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * STRATEGY + * for playback, we send series of "chunks", which size is equal with the + * IBL size, typically 126 samples. at each end of chunk, the end-of-buffer + * interrupt is notified, and the interrupt handler will feed the next chunk. + * + * the current position is calculated from the sample count RMH. + * pipe->transferred is the counter of data which has been already transferred. + * if this counter reaches to the period size, snd_pcm_period_elapsed() will + * be issued. + * + * for capture, the situation is much easier. + * to get a low latency response, we'll check the capture streams at each + * interrupt (capture stream has no EOB notification). if the pending + * data is accumulated to the period size, snd_pcm_period_elapsed() is + * called and the pointer is updated. + * + * the current point of read buffer is kept in pipe->hw_ptr. note that + * this is in bytes. + * + * + * TODO + * - linked trigger for full-duplex mode. + * - scheduled action on the stream. + */ + +#include <sound/driver.h> +#include <linux/slab.h> +#include <linux/vmalloc.h> +#include <sound/core.h> +#include <sound/asoundef.h> +#include <sound/pcm.h> +#include <sound/vx_core.h> +#include "vx_cmd.h" + +#define chip_t vx_core_t + + +/* + * we use a vmalloc'ed (sg-)buffer + */ + +/* get the physical page pointer on the given offset */ +static struct page *snd_pcm_get_vmalloc_page(snd_pcm_substream_t *subs, unsigned long offset) +{ + void *pageptr = subs->runtime->dma_area + offset; + return vmalloc_to_page(pageptr); +} + +/* + * allocate a buffer via vmalloc_32(). + * called from hw_params + * NOTE: this may be called not only once per pcm open! + */ +static int snd_pcm_alloc_vmalloc_buffer(snd_pcm_substream_t *subs, size_t size) +{ + snd_pcm_runtime_t *runtime = subs->runtime; + if (runtime->dma_area) { + /* already allocated */ + if (runtime->dma_bytes >= size) + return 0; /* already enough large */ + vfree_nocheck(runtime->dma_area); /* bypass the memory wrapper */ + } + runtime->dma_area = vmalloc_32(size); + if (! runtime->dma_area) + return -ENOMEM; + memset(runtime->dma_area, 0, size); + runtime->dma_bytes = size; + return 1; /* changed */ +} + +/* + * free the buffer. + * called from hw_free callback + * NOTE: this may be called not only once per pcm open! + */ +static int snd_pcm_free_vmalloc_buffer(snd_pcm_substream_t *subs) +{ + snd_pcm_runtime_t *runtime = subs->runtime; + if (runtime->dma_area) { + vfree_nocheck(runtime->dma_area); /* bypass the memory wrapper */ + runtime->dma_area = NULL; + } + return 0; +} + + +/* + * read three pending pcm bytes via inb() + */ +static void vx_pcm_read_per_bytes(vx_core_t *chip, snd_pcm_runtime_t *runtime, vx_pipe_t *pipe) +{ + int offset = pipe->hw_ptr; + unsigned char *buf = (unsigned char *)(runtime->dma_area + offset); + *buf++ = vx_inb(chip, RXH); + if (++offset >= pipe->buffer_bytes) { + offset = 0; + buf = (unsigned char *)runtime->dma_area; + } + *buf++ = vx_inb(chip, RXM); + if (++offset >= pipe->buffer_bytes) { + offset = 0; + buf = (unsigned char *)runtime->dma_area; + } + *buf++ = vx_inb(chip, RXL); + if (++offset >= pipe->buffer_bytes) { + offset = 0; + buf = (unsigned char *)runtime->dma_area; + } + pipe->hw_ptr = offset; +} + +/* + * vx_set_pcx_time - convert from the PC time to the RMH status time. + * @pc_time: the pointer for the PC-time to set + * @dsp_time: the pointer for RMH status time array + */ +static void vx_set_pcx_time(vx_core_t *chip, pcx_time_t *pc_time, unsigned int *dsp_time) +{ + dsp_time[0] = (unsigned int)((*pc_time) >> 24) & PCX_TIME_HI_MASK; + dsp_time[1] = (unsigned int)(*pc_time) & MASK_DSP_WORD; +} + +/* + * vx_set_differed_time - set the differed time if specified + * @rmh: the rmh record to modify + * @pipe: the pipe to be checked + * + * if the pipe is programmed with the differed time, set the DSP time + * on the rmh and changes its command length. + * + * returns the increase of the command length. + */ +static int vx_set_differed_time(vx_core_t *chip, struct vx_rmh *rmh, vx_pipe_t *pipe) +{ + /* Update The length added to the RMH command by the timestamp */ + if (! (pipe->differed_type & DC_DIFFERED_DELAY)) + return 0; + + /* Set the T bit */ + rmh->Cmd[0] |= DSP_DIFFERED_COMMAND_MASK; + + /* Time stamp is the 1st following parameter */ + vx_set_pcx_time(chip, &pipe->pcx_time, &rmh->Cmd[1]); + + /* Add the flags to a notified differed command */ + if (pipe->differed_type & DC_NOTIFY_DELAY) + rmh->Cmd[1] |= NOTIFY_MASK_TIME_HIGH ; + + /* Add the flags to a multiple differed command */ + if (pipe->differed_type & DC_MULTIPLE_DELAY) + rmh->Cmd[1] |= MULTIPLE_MASK_TIME_HIGH; + + /* Add the flags to a stream-time differed command */ + if (pipe->differed_type & DC_STREAM_TIME_DELAY) + rmh->Cmd[1] |= STREAM_MASK_TIME_HIGH; + + rmh->LgCmd += 2; + return 2; +} + +/* + * vx_set_stream_format - send the stream format command + * @pipe: the affected pipe + * @data: format bitmask + */ +static int vx_set_stream_format(vx_core_t *chip, vx_pipe_t *pipe, unsigned int data) +{ + struct vx_rmh rmh; + + vx_init_rmh(&rmh, pipe->is_capture ? + CMD_FORMAT_STREAM_IN : CMD_FORMAT_STREAM_OUT); + rmh.Cmd[0] |= pipe->number << FIELD_SIZE; + + /* Command might be longer since we may have to add a timestamp */ + vx_set_differed_time(chip, &rmh, pipe); + + rmh.Cmd[rmh.LgCmd] = (data & 0xFFFFFF00) >> 8; + rmh.Cmd[rmh.LgCmd + 1] = (data & 0xFF) << 16 /*| (datal & 0xFFFF00) >> 8*/; + rmh.LgCmd += 2; + + return vx_send_msg(chip, &rmh); +} + + +/* + * vx_set_format - set the format of a pipe + * @pipe: the affected pipe + * @runtime: pcm runtime instance to be referred + * + * returns 0 if successful, or a negative error code. + */ +static int vx_set_format(vx_core_t *chip, vx_pipe_t *pipe, + snd_pcm_runtime_t *runtime) +{ + unsigned int header = HEADER_FMT_BASE; + + if (runtime->channels == 1) + header |= HEADER_FMT_MONO; + if (snd_pcm_format_little_endian(runtime->format)) + header |= HEADER_FMT_INTEL; + if (runtime->rate < 32000 && runtime->rate > 11025) + header |= HEADER_FMT_UPTO32; + else if (runtime->rate <= 11025) + header |= HEADER_FMT_UPTO11; + + switch (snd_pcm_format_physical_width(runtime->format)) { + // case 8: break; + case 16: header |= HEADER_FMT_16BITS; break; + case 24: header |= HEADER_FMT_24BITS; break; + default : + snd_BUG(); + return -EINVAL; + }; + + return vx_set_stream_format(chip, pipe, header); +} + +/* + * set / query the IBL size + */ +static int vx_set_ibl(vx_core_t *chip, struct vx_ibl_info *info) +{ + int err; + struct vx_rmh rmh; + + vx_init_rmh(&rmh, CMD_IBL); + rmh.Cmd[0] |= info->size & 0x03ffff; + err = vx_send_msg(chip, &rmh); + if (err < 0) + return err; + info->size = rmh.Stat[0]; + info->max_size = rmh.Stat[1]; + info->min_size = rmh.Stat[2]; + info->granularity = rmh.Stat[3]; + snd_printdd(KERN_DEBUG "vx_set_ibl: size = %d, max = %d, min = %d, gran = %d\n", + info->size, info->max_size, info->min_size, info->granularity); + return 0; +} + + +/* + * vx_get_pipe_state - get the state of a pipe + * @pipe: the pipe to be checked + * @state: the pointer for the returned state + * + * checks the state of a given pipe, and stores the state (1 = running, + * 0 = paused) on the given pointer. + * + * called from trigger callback only + */ +static int vx_get_pipe_state(vx_core_t *chip, vx_pipe_t *pipe, int *state) +{ + int err; + struct vx_rmh rmh; + + vx_init_rmh(&rmh, CMD_PIPE_STATE); + vx_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->number, 0); + err = vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ + if (! err) + *state = (rmh.Stat[0] & (1 << pipe->number)) ? 1 : 0; + return err; +} + + +/* + * vx_query_hbuffer_size - query available h-buffer size in bytes + * @pipe: the pipe to be checked + * + * return the available size on h-buffer in bytes, + * or a negative error code. + * + * NOTE: calling this function always switches to the stream mode. + * you'll need to disconnect the host to get back to the + * normal mode. + */ +static int vx_query_hbuffer_size(vx_core_t *chip, vx_pipe_t *pipe) +{ + int result; + struct vx_rmh rmh; + + vx_init_rmh(&rmh, CMD_SIZE_HBUFFER); + vx_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->number, 0); + if (pipe->is_capture) + rmh.Cmd[0] |= 0x00000001; + result = vx_send_msg(chip, &rmh); + if (! result) + result = rmh.Stat[0] & 0xffff; + return result; +} + + +/* + * vx_pipe_can_start - query whether a pipe is ready for start + * @pipe: the pipe to be checked + * + * return 1 if ready, 0 if not ready, and negative value on error. + * + * called from trigger callback only + */ +static int vx_pipe_can_start(vx_core_t *chip, vx_pipe_t *pipe) +{ + int err; + struct vx_rmh rmh; + + vx_init_rmh(&rmh, CMD_CAN_START_PIPE); + vx_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->number, 0); + rmh.Cmd[0] |= 1; + + err = vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ + if (! err) { + if (rmh.Stat[0]) + err = 1; + } + return err; +} + +/* + * vx_conf_pipe - tell the pipe to stand by and wait for IRQA. + * @pipe: the pipe to be configured + */ +static int vx_conf_pipe(vx_core_t *chip, vx_pipe_t *pipe) +{ + struct vx_rmh rmh; + + vx_init_rmh(&rmh, CMD_CONF_PIPE); + if (pipe->is_capture) + rmh.Cmd[0] |= COMMAND_RECORD_MASK; + rmh.Cmd[1] = 1 << pipe->number; + return vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ +} + +/* + * vx_send_irqa - trigger IRQA + */ +static int vx_send_irqa(vx_core_t *chip) +{ + struct vx_rmh rmh; + + vx_init_rmh(&rmh, CMD_SEND_IRQA); + return vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ +} + + +#define MAX_WAIT_FOR_DSP 250 +/* + * vx boards do not support inter-card sync, besides + * only 126 samples require to be prepared before a pipe can start + */ +#define CAN_START_DELAY 2 /* wait 2ms only before asking if the pipe is ready*/ +#define WAIT_STATE_DELAY 2 /* wait 2ms after irqA was requested and check if the pipe state toggled*/ + +/* + * vx_toggle_pipe - start / pause a pipe + * @pipe: the pipe to be triggered + * @state: start = 1, pause = 0 + * + * called from trigger callback only + * + */ +static int vx_toggle_pipe(vx_core_t *chip, vx_pipe_t *pipe, int state) +{ + int err, i, cur_state, delay; + + /* Check the pipe is not already in the requested state */ + if (vx_get_pipe_state(chip, pipe, &cur_state) < 0) + return -EBADFD; + if (state == cur_state) + return 0; + + /* If a start is requested, ask the DSP to get prepared + * and wait for a positive acknowledge (when there are + * enough sound buffer for this pipe) + */ + if (state) { + int delay = CAN_START_DELAY; + for (i = 0 ; i < MAX_WAIT_FOR_DSP; i++) { + snd_vx_delay(chip, delay); + err = vx_pipe_can_start(chip, pipe); + if (err > 0) + break; + /* Wait for a few, before asking again + * to avoid flooding the DSP with our requests + */ + if ((i % 4 ) == 0) + delay <<= 1; + } + } + + if ((err = vx_conf_pipe(chip, pipe)) < 0) + return err; + + if ((err = vx_send_irqa(chip)) < 0) + return err; + + /* If it completes successfully, wait for the pipes + * reaching the expected state before returning + * Check one pipe only (since they are synchronous) + */ + delay = WAIT_STATE_DELAY; + for (i = 0; i < MAX_WAIT_FOR_DSP; i++) { + snd_vx_delay(chip, delay); + err = vx_get_pipe_state(chip, pipe, &cur_state); + if (err < 0 || cur_state == state) + break; + err = -EIO; + if ((i % 4 ) == 0) + delay <<= 1; + } + return err < 0 ? -EIO : 0; +} + + +/* + * vx_stop_pipe - stop a pipe + * @pipe: the pipe to be stopped + * + * called from trigger callback only + */ +static int vx_stop_pipe(vx_core_t *chip, vx_pipe_t *pipe) +{ + struct vx_rmh rmh; + vx_init_rmh(&rmh, CMD_STOP_PIPE); + vx_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->number, 0); + return vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ +} + + +/* + * vx_alloc_pipe - allocate a pipe and initialize the pipe instance + * @capture: 0 = playback, 1 = capture operation + * @audioid: the audio id to be assigned + * @num_audio: number of audio channels + * @pipep: the returned pipe instance + * + * return 0 on success, or a negative error code. + */ +static int vx_alloc_pipe(vx_core_t *chip, int capture, + int audioid, int num_audio, + vx_pipe_t **pipep) +{ + int err; + vx_pipe_t *pipe; + struct vx_rmh rmh; + int data_mode; + + *pipep = 0; + vx_init_rmh(&rmh, CMD_RES_PIPE); + vx_set_pipe_cmd_params(&rmh, capture, audioid, num_audio); +#if 0 // NYI + if (underrun_skip_sound) + rmh.Cmd[0] |= BIT_SKIP_SOUND; +#endif // NYI + data_mode = (chip->uer_bits & IEC958_AES0_NONAUDIO) != 0; + if (! capture && data_mode) + rmh.Cmd[0] |= BIT_DATA_MODE; + err = vx_send_msg(chip, &rmh); + if (err < 0) + return err; + + /* initialize the pipe record */ + pipe = snd_magic_kcalloc(vx_pipe_t, 0, GFP_KERNEL); + if (! pipe) { + /* release the pipe */ + vx_init_rmh(&rmh, CMD_FREE_PIPE); + vx_set_pipe_cmd_params(&rmh, capture, audioid, 0); + vx_send_msg(chip, &rmh); + return -ENOMEM; + } + + /* the pipe index should be identical with the audio index */ + pipe->number = audioid; + pipe->is_capture = capture; + pipe->channels = num_audio; + pipe->differed_type = 0; + pipe->pcx_time = 0; + pipe->data_mode = data_mode; + *pipep = pipe; + + return 0; +} + + +/* + * vx_free_pipe - release a pipe + * @pipe: pipe to be released + */ +static int vx_free_pipe(vx_core_t *chip, vx_pipe_t *pipe) +{ + struct vx_rmh rmh; + + vx_init_rmh(&rmh, CMD_FREE_PIPE); + vx_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->number, 0); + vx_send_msg(chip, &rmh); + + snd_magic_kfree(pipe); + return 0; +} + + +/* + * vx_start_stream - start the stream + * + * called from trigger callback only + */ +static int vx_start_stream(vx_core_t *chip, vx_pipe_t *pipe) +{ + struct vx_rmh rmh; + + vx_init_rmh(&rmh, CMD_START_ONE_STREAM); + vx_set_stream_cmd_params(&rmh, pipe->is_capture, pipe->number); + vx_set_differed_time(chip, &rmh, pipe); + return vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ +} + + +/* + * vx_stop_stream - stop the stream + * + * called from trigger callback only + */ +static int vx_stop_stream(vx_core_t *chip, vx_pipe_t *pipe) +{ + struct vx_rmh rmh; + + vx_init_rmh(&rmh, CMD_STOP_STREAM); + vx_set_stream_cmd_params(&rmh, pipe->is_capture, pipe->number); + return vx_send_msg_nolock(chip, &rmh); /* no lock needed for trigger */ +} + + +/* + * playback hw information + */ + +static snd_pcm_hardware_t vx_pcm_playback_hw = { + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID), + .formats = /*SNDRV_PCM_FMTBIT_U8 |*/ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE, + .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, + .rate_min = 5000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = (128*1024), + .period_bytes_min = 126, + .period_bytes_max = (128*1024), + .periods_min = 2, + .periods_max = VX_MAX_PERIODS, + .fifo_size = 126, +}; + + +static void vx_pcm_delayed_start(unsigned long arg); + +/* + * vx_pcm_playback_open - open callback for playback + */ +static int vx_pcm_playback_open(snd_pcm_substream_t *subs) +{ + snd_pcm_runtime_t *runtime = subs->runtime; + vx_core_t *chip = snd_pcm_substream_chip(subs); + vx_pipe_t *pipe = 0; + unsigned int audio; + int err; + + if (chip->chip_status & VX_STAT_IS_STALE) + return -EBUSY; + + audio = subs->pcm->device * 2; + snd_assert(audio < chip->audio_outs, return -EINVAL); + + /* playback pipe may have been already allocated for monitoring */ + pipe = chip->playback_pipes[audio]; + if (! pipe) { + /* not allocated yet */ + err = vx_alloc_pipe(chip, 0, audio, 2, &pipe); /* stereo playback */ + if (err < 0) + return err; + chip->playback_pipes[audio] = pipe; + } + /* open for playback */ + pipe->references++; + + pipe->substream = subs; + tasklet_init(&pipe->start_tq, vx_pcm_delayed_start, (unsigned long)subs); + chip->playback_pipes[audio] = pipe; + + runtime->hw = vx_pcm_playback_hw; + runtime->hw.period_bytes_min = chip->ibl.size; + runtime->private_data = pipe; + + return 0; +} + +/* + * vx_pcm_playback_close - close callback for playback + */ +static int vx_pcm_playback_close(snd_pcm_substream_t *subs) +{ + vx_core_t *chip = snd_pcm_substream_chip(subs); + vx_pipe_t *pipe; + + if (! subs->runtime->private_data) + return -EINVAL; + + pipe = snd_magic_cast(vx_pipe_t, subs->runtime->private_data, return -EINVAL); + + if (--pipe->references == 0) { + chip->playback_pipes[pipe->number] = 0; + vx_free_pipe(chip, pipe); + } + + return 0; + +} + + +/* + * vx_notify_end_of_buffer - send "end-of-buffer" notifier at the given pipe + * @pipe: the pipe to notify + * + * NB: call with a certain lock. + */ +static int vx_notify_end_of_buffer(vx_core_t *chip, vx_pipe_t *pipe) +{ + int err; + struct vx_rmh rmh; /* use a temporary rmh here */ + + /* Toggle Dsp Host Interface into Message mode */ + vx_send_rih_nolock(chip, IRQ_PAUSE_START_CONNECT); + vx_init_rmh(&rmh, CMD_NOTIFY_END_OF_BUFFER); + vx_set_stream_cmd_params(&rmh, 0, pipe->number); + err = vx_send_msg_nolock(chip, &rmh); + if (err < 0) + return err; + /* Toggle Dsp Host Interface back to sound transfer mode */ + vx_send_rih_nolock(chip, IRQ_PAUSE_START_CONNECT); + return 0; +} + +/* + * vx_pcm_playback_transfer_chunk - transfer a single chunk + * @subs: substream + * @pipe: the pipe to transfer + * @size: chunk size in bytes + * + * transfer a single buffer chunk. EOB notificaton is added after that. + * called from the interrupt handler, too. + * + * return 0 if ok. + */ +static int vx_pcm_playback_transfer_chunk(vx_core_t *chip, snd_pcm_runtime_t *runtime, vx_pipe_t *pipe, int size) +{ + int space, err = 0; + + space = vx_query_hbuffer_size(chip, pipe); + if (space < 0) { + /* disconnect the host, SIZE_HBUF command always switches to the stream mode */ + vx_send_rih(chip, IRQ_CONNECT_STREAM_NEXT); + snd_printd("error hbuffer\n"); + return space; + } + if (space < size) { + vx_send_rih(chip, IRQ_CONNECT_STREAM_NEXT); + snd_printd("no enough hbuffer space %d\n", space); + return -EIO; /* XRUN */ + } + + /* we don't need irqsave here, because this function + * is called from either trigger callback or irq handler + */ + spin_lock(&chip->lock); + vx_pseudo_dma_write(chip, runtime, pipe, size); + err = vx_notify_end_of_buffer(chip, pipe); + /* disconnect the host, SIZE_HBUF command always switches to the stream mode */ + vx_send_rih_nolock(chip, IRQ_CONNECT_STREAM_NEXT); + spin_unlock(&chip->lock); + return err; +} + +/* + * update the position of the given pipe. + * pipe->position is updated and wrapped within the buffer size. + * pipe->transferred is updated, too, but the size is not wrapped, + * so that the caller can check the total transferred size later + * (to call snd_pcm_period_elapsed). + */ +static int vx_update_pipe_position(vx_core_t *chip, snd_pcm_runtime_t *runtime, vx_pipe_t *pipe) +{ + struct vx_rmh rmh; + int err, update; + u64 count; + + vx_init_rmh(&rmh, CMD_STREAM_SAMPLE_COUNT); + vx_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->number, 0); + err = vx_send_msg(chip, &rmh); + if (err < 0) + return err; + + count = ((u64)(rmh.Stat[0] & 0xfffff) << 24) | (u64)rmh.Stat[1]; + update = (int)(count - pipe->cur_count); + pipe->cur_count = count; + pipe->position += update; + if (pipe->position >= (int)runtime->buffer_size) + pipe->position %= runtime->buffer_size; + pipe->transferred += update; + return 0; +} + +/* + * transfer the pending playback buffer data to DSP + * called from interrupt handler + */ +static void vx_pcm_playback_transfer(vx_core_t *chip, snd_pcm_substream_t *subs, vx_pipe_t *pipe, int nchunks) +{ + int i, err; + snd_pcm_runtime_t *runtime = subs->runtime; + + if (! pipe->prepared || (chip->chip_status & VX_STAT_IS_STALE)) + return; + for (i = 0; i < nchunks; i++) { + if ((err = vx_pcm_playback_transfer_chunk(chip, runtime, pipe, + chip->ibl.size)) < 0) + return; + } +} + +/* + * update the playback position and call snd_pcm_period_elapsed() if necessary + * called from interrupt handler + */ +static void vx_pcm_playback_update(vx_core_t *chip, snd_pcm_substream_t *subs, vx_pipe_t *pipe) +{ + int err; + snd_pcm_runtime_t *runtime = subs->runtime; + + if (pipe->running && ! (chip->chip_status & VX_STAT_IS_STALE)) { + if ((err = vx_update_pipe_position(chip, runtime, pipe)) < 0) + return; + if (pipe->transferred >= (int)runtime->period_size) { + pipe->transferred %= runtime->period_size; + snd_pcm_period_elapsed(subs); + } + } +} + +/* + * start the stream and pipe. + * this function is called from tasklet, which is invoked by the trigger + * START callback. + */ +static void vx_pcm_delayed_start(unsigned long arg) +{ + snd_pcm_substream_t *subs = (snd_pcm_substream_t *)arg; + vx_core_t *chip = snd_magic_cast(vx_core_t, subs->pcm->private_data, return); + vx_pipe_t *pipe = snd_magic_cast(vx_pipe_t, subs->runtime->private_data, return); + int err; + + /* printk( KERN_DEBUG "DDDD tasklet delayed start jiffies = %ld\n", jiffies);*/ + + if ((err = vx_start_stream(chip, pipe)) < 0) { + snd_printk(KERN_ERR "vx: cannot start stream\n"); + return; + } + if ((err = vx_toggle_pipe(chip, pipe, 1)) < 0) { + snd_printk(KERN_ERR "vx: cannot start pipe\n"); + return; + } + /* printk( KERN_DEBUG "dddd tasklet delayed start jiffies = %ld \n", jiffies);*/ +} + +/* + * vx_pcm_playback_trigger - trigger callback for playback + */ +static int vx_pcm_trigger(snd_pcm_substream_t *subs, int cmd) +{ + vx_core_t *chip = snd_pcm_substream_chip(subs); + vx_pipe_t *pipe = snd_magic_cast(vx_pipe_t, subs->runtime->private_data, return -EINVAL); + int err; + + if (chip->chip_status & VX_STAT_IS_STALE) + return -EBUSY; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + if (! pipe->is_capture) + vx_pcm_playback_transfer(chip, subs, pipe, 2); + /* FIXME: + * we trigger the pipe using tasklet, so that the interrupts are + * issued surely after the trigger is completed. + */ + tasklet_hi_schedule(&pipe->start_tq); + chip->pcm_running++; + pipe->running = 1; + break; + case SNDRV_PCM_TRIGGER_STOP: + vx_toggle_pipe(chip, pipe, 0); + vx_stop_pipe(chip, pipe); + vx_stop_stream(chip, pipe); + chip->pcm_running--; + pipe->running = 0; + break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + if ((err = vx_toggle_pipe(chip, pipe, 0)) < 0) + return err; + break; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + if ((err = vx_toggle_pipe(chip, pipe, 1)) < 0) + return err; + break; + default: + return -EINVAL; + } + return 0; +} + +/* + * vx_pcm_playback_pointer - pointer callback for playback + */ +static snd_pcm_uframes_t vx_pcm_playback_pointer(snd_pcm_substream_t *subs) +{ + snd_pcm_runtime_t *runtime = subs->runtime; + vx_pipe_t *pipe = snd_magic_cast(vx_pipe_t, runtime->private_data, return -EINVAL); + return pipe->position; +} + +/* + * vx_pcm_hw_params - hw_params callback for playback and capture + */ +static int vx_pcm_hw_params(snd_pcm_substream_t *subs, + snd_pcm_hw_params_t *hw_params) +{ + return snd_pcm_alloc_vmalloc_buffer(subs, params_buffer_bytes(hw_params)); +} + +/* + * vx_pcm_hw_free - hw_free callback for playback and capture + */ +static int vx_pcm_hw_free(snd_pcm_substream_t *subs) +{ + return snd_pcm_free_vmalloc_buffer(subs); +} + +/* + * vx_pcm_prepare - prepare callback for playback and capture + */ +static int vx_pcm_prepare(snd_pcm_substream_t *subs) +{ + vx_core_t *chip = snd_pcm_substream_chip(subs); + snd_pcm_runtime_t *runtime = subs->runtime; + vx_pipe_t *pipe = snd_magic_cast(vx_pipe_t, runtime->private_data, return -EINVAL); + int err, data_mode; + // int max_size, nchunks; + + if (chip->chip_status & VX_STAT_IS_STALE) + return -EBUSY; + + data_mode = (chip->uer_bits & IEC958_AES0_NONAUDIO) != 0; + if (data_mode != pipe->data_mode && ! pipe->is_capture) { + /* IEC958 status (raw-mode) was changed */ + /* we reopen the pipe */ + struct vx_rmh rmh; + snd_printdd(KERN_DEBUG "reopen the pipe with data_mode = %d\n", data_mode); + vx_init_rmh(&rmh, CMD_FREE_PIPE); + vx_set_pipe_cmd_params(&rmh, 0, pipe->number, 0); + if ((err = vx_send_msg(chip, &rmh)) < 0) + return err; + vx_init_rmh(&rmh, CMD_RES_PIPE); + vx_set_pipe_cmd_params(&rmh, 0, pipe->number, pipe->channels); + if (data_mode) + rmh.Cmd[0] |= BIT_DATA_MODE; + if ((err = vx_send_msg(chip, &rmh)) < 0) + return err; + pipe->data_mode = data_mode; + } + + if (chip->pcm_running && chip->freq != runtime->rate) { + snd_printk(KERN_ERR "vx: cannot set different clock %d from the current %d\n", runtime->rate, chip->freq); + return -EINVAL; + } + vx_set_clock(chip, runtime->rate); + + if ((err = vx_set_format(chip, pipe, runtime)) < 0) + return err; + + if (vx_is_pcmcia(chip)) { + pipe->align = 2; /* 16bit word */ + } else { + pipe->align = 4; /* 32bit word */ + } + + pipe->buffer_bytes = frames_to_bytes(runtime, runtime->buffer_size); + pipe->period_bytes = frames_to_bytes(runtime, runtime->period_size); + pipe->hw_ptr = 0; + + /* set the timestamp */ + vx_update_pipe_position(chip, runtime, pipe); + /* clear again */ + pipe->transferred = 0; + pipe->position = 0; + + pipe->prepared = 1; + + return 0; +} + + +/* + * operators for PCM playback + */ +static snd_pcm_ops_t vx_pcm_playback_ops = { + .open = vx_pcm_playback_open, + .close = vx_pcm_playback_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = vx_pcm_hw_params, + .hw_free = vx_pcm_hw_free, + .prepare = vx_pcm_prepare, + .trigger = vx_pcm_trigger, + .pointer = vx_pcm_playback_pointer, + .page = snd_pcm_get_vmalloc_page, +}; + + +/* + * playback hw information + */ + +static snd_pcm_hardware_t vx_pcm_capture_hw = { + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_MMAP_VALID), + .formats = /*SNDRV_PCM_FMTBIT_U8 |*/ SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_3LE, + .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, + .rate_min = 5000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = (128*1024), + .period_bytes_min = 126, + .period_bytes_max = (128*1024), + .periods_min = 2, + .periods_max = VX_MAX_PERIODS, + .fifo_size = 126, +}; + + +/* + * vx_pcm_capture_open - open callback for capture + */ +static int vx_pcm_capture_open(snd_pcm_substream_t *subs) +{ + snd_pcm_runtime_t *runtime = subs->runtime; + vx_core_t *chip = snd_pcm_substream_chip(subs); + vx_pipe_t *pipe; + vx_pipe_t *pipe_out_monitoring = NULL; + unsigned int audio; + int err; + + if (chip->chip_status & VX_STAT_IS_STALE) + return -EBUSY; + + audio = subs->pcm->device * 2; + snd_assert(audio < chip->audio_ins, return -EINVAL); + err = vx_alloc_pipe(chip, 1, audio, 2, &pipe); + if (err < 0) + return err; + pipe->substream = subs; + tasklet_init(&pipe->start_tq, vx_pcm_delayed_start, (unsigned long)subs); + chip->capture_pipes[audio] = pipe; + + /* check if monitoring is needed */ + if (chip->audio_monitor_active[audio]) { + pipe_out_monitoring = chip->playback_pipes[audio]; + if (! pipe_out_monitoring) { + /* allocate a pipe */ + err = vx_alloc_pipe(chip, 0, audio, 2, &pipe_out_monitoring); + if (err < 0) + return err; + chip->playback_pipes[audio] = pipe_out_monitoring; + } + pipe_out_monitoring->references++; + /* + if an output pipe is available, it's audios still may need to be + unmuted. hence we'll have to call a mixer entry point. + */ + vx_set_monitor_level(chip, audio, chip->audio_monitor[audio], chip->audio_monitor_active[audio]); + /* assuming stereo */ + vx_set_monitor_level(chip, audio+1, chip->audio_monitor[audio+1], chip->audio_monitor_active[audio+1]); + } + + pipe->monitoring_pipe = pipe_out_monitoring; /* default value NULL */ + + runtime->hw = vx_pcm_capture_hw; + runtime->hw.period_bytes_min = chip->ibl.size; + runtime->private_data = pipe; + + return 0; +} + +/* + * vx_pcm_capture_close - close callback for capture + */ +static int vx_pcm_capture_close(snd_pcm_substream_t *subs) +{ + vx_core_t *chip = snd_pcm_substream_chip(subs); + vx_pipe_t *pipe; + vx_pipe_t *pipe_out_monitoring; + + if (! subs->runtime->private_data) + return -EINVAL; + pipe = snd_magic_cast(vx_pipe_t, subs->runtime->private_data, return -EINVAL); + chip->capture_pipes[pipe->number] = 0; + + pipe_out_monitoring = pipe->monitoring_pipe; + + /* + if an output pipe is attached to this input, + check if it needs to be released. + */ + if (pipe_out_monitoring) { + if (--pipe_out_monitoring->references == 0) { + vx_free_pipe(chip, pipe_out_monitoring); + chip->playback_pipes[pipe->number] = 0; + pipe->monitoring_pipe = 0; + } + } + + vx_free_pipe(chip, pipe); + return 0; +} + + + +#define DMA_READ_ALIGN 6 /* hardware alignment for read */ + +/* + * vx_pcm_capture_update - update the capture buffer + */ +static void vx_pcm_capture_update(vx_core_t *chip, snd_pcm_substream_t *subs, vx_pipe_t *pipe) +{ + int size, space, count; + snd_pcm_runtime_t *runtime = subs->runtime; + + if (! pipe->prepared || (chip->chip_status & VX_STAT_IS_STALE)) + return; + + size = runtime->buffer_size - snd_pcm_capture_avail(runtime); + if (! size) + return; + size = frames_to_bytes(runtime, size); + space = vx_query_hbuffer_size(chip, pipe); + if (space < 0) + goto _error; + if (size > space) + size = space; + size = (size / 3) * 3; /* align to 3 bytes */ + if (size < DMA_READ_ALIGN) + goto _error; + + /* keep the last 6 bytes, they will be read after disconnection */ + count = size - DMA_READ_ALIGN; + /* read bytes until the current pointer reaches to the aligned position + * for word-transfer + */ + while (count > 0) { + if ((pipe->hw_ptr % pipe->align) == 0) + break; + if (vx_wait_for_rx_full(chip) < 0) + goto _error; + vx_pcm_read_per_bytes(chip, runtime, pipe); + count -= 3; + } + if (count > 0) { + /* ok, let's accelerate! */ + int align = pipe->align * 3; + space = (count / align) * align; + vx_pseudo_dma_read(chip, runtime, pipe, space); + count -= space; + } + /* read the rest of bytes */ + while (count > 0) { + if (vx_wait_for_rx_full(chip) < 0) + goto _error; + vx_pcm_read_per_bytes(chip, runtime, pipe); + count -= 3; + } + /* disconnect the host, SIZE_HBUF command always switches to the stream mode */ + vx_send_rih_nolock(chip, IRQ_CONNECT_STREAM_NEXT); + /* read the last pending 6 bytes */ + count = DMA_READ_ALIGN; + while (count > 0) { + vx_pcm_read_per_bytes(chip, runtime, pipe); + count -= 3; + } + /* update the position */ + pipe->transferred += size; + if (pipe->transferred >= pipe->period_bytes) { + pipe->transferred %= pipe->period_bytes; + snd_pcm_period_elapsed(subs); + } + return; + + _error: + /* disconnect the host, SIZE_HBUF command always switches to the stream mode */ + vx_send_rih_nolock(chip, IRQ_CONNECT_STREAM_NEXT); + return; +} + +/* + * vx_pcm_capture_pointer - pointer callback for capture + */ +static snd_pcm_uframes_t vx_pcm_capture_pointer(snd_pcm_substream_t *subs) +{ + snd_pcm_runtime_t *runtime = subs->runtime; + vx_pipe_t *pipe = snd_magic_cast(vx_pipe_t, runtime->private_data, return -EINVAL); + return bytes_to_frames(runtime, pipe->hw_ptr); +} + +/* + * operators for PCM capture + */ +static snd_pcm_ops_t vx_pcm_capture_ops = { + .open = vx_pcm_capture_open, + .close = vx_pcm_capture_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = vx_pcm_hw_params, + .hw_free = vx_pcm_hw_free, + .prepare = vx_pcm_prepare, + .trigger = vx_pcm_trigger, + .pointer = vx_pcm_capture_pointer, + .page = snd_pcm_get_vmalloc_page, +}; + + +/* + * interrupt handler for pcm streams + */ +void vx_pcm_update_intr(vx_core_t *chip, unsigned int events) +{ + unsigned int i; + vx_pipe_t *pipe; + +#define EVENT_MASK (END_OF_BUFFER_EVENTS_PENDING|ASYNC_EVENTS_PENDING) + + if (events & EVENT_MASK) { + vx_init_rmh(&chip->irq_rmh, CMD_ASYNC); + if (events & ASYNC_EVENTS_PENDING) + chip->irq_rmh.Cmd[0] |= 0x00000001; /* SEL_ASYNC_EVENTS */ + if (events & END_OF_BUFFER_EVENTS_PENDING) + chip->irq_rmh.Cmd[0] |= 0x00000002; /* SEL_END_OF_BUF_EVENTS */ + + if (vx_send_msg(chip, &chip->irq_rmh) < 0) { + snd_printdd(KERN_ERR "msg send error!!\n"); + return; + } + + i = 1; + while (i < chip->irq_rmh.LgStat) { + int p, buf, capture, eob; + p = chip->irq_rmh.Stat[i] & MASK_FIRST_FIELD; + capture = (chip->irq_rmh.Stat[i] & 0x400000) ? 1 : 0; + eob = (chip->irq_rmh.Stat[i] & 0x800000) ? 1 : 0; + i++; + if (events & ASYNC_EVENTS_PENDING) + i++; + buf = 1; /* force to transfer */ + if (events & END_OF_BUFFER_EVENTS_PENDING) { + if (eob) + buf = chip->irq_rmh.Stat[i]; + i++; + } + if (capture) + continue; + snd_assert(p >= 0 && (unsigned int)p < chip->audio_outs,); + pipe = chip->playback_pipes[p]; + if (pipe && pipe->substream) { + vx_pcm_playback_update(chip, pipe->substream, pipe); + vx_pcm_playback_transfer(chip, pipe->substream, pipe, buf); + } + } + } + + /* update the capture pcm pointers as frequently as possible */ + for (i = 0; i < chip->audio_ins; i++) { + pipe = chip->capture_pipes[i]; + if (pipe && pipe->substream) + vx_pcm_capture_update(chip, pipe->substream, pipe); + } +} + + +/* + * vx_init_audio_io - check the availabe audio i/o and allocate pipe arrays + */ +static int vx_init_audio_io(vx_core_t *chip) +{ + struct vx_rmh rmh; + int preferred; + + vx_init_rmh(&rmh, CMD_SUPPORTED); + if (vx_send_msg(chip, &rmh) < 0) { + snd_printk(KERN_ERR "vx: cannot get the supported audio data\n"); + return -ENXIO; + } + + chip->audio_outs = rmh.Stat[0] & MASK_FIRST_FIELD; + chip->audio_ins = (rmh.Stat[0] >> (FIELD_SIZE*2)) & MASK_FIRST_FIELD; + chip->audio_info = rmh.Stat[1]; + + /* allocate pipes */ + chip->playback_pipes = kmalloc(sizeof(vx_pipe_t *) * chip->audio_outs, GFP_KERNEL); + chip->capture_pipes = kmalloc(sizeof(vx_pipe_t *) * chip->audio_ins, GFP_KERNEL); + if (! chip->playback_pipes || ! chip->capture_pipes) + return -ENOMEM; + + memset(chip->playback_pipes, 0, sizeof(vx_pipe_t *) * chip->audio_outs); + memset(chip->capture_pipes, 0, sizeof(vx_pipe_t *) * chip->audio_ins); + + preferred = chip->ibl.size; + chip->ibl.size = 0; + vx_set_ibl(chip, &chip->ibl); /* query the info */ + if (preferred > 0) { + chip->ibl.size = ((preferred + chip->ibl.granularity - 1) / chip->ibl.granularity) * chip->ibl.granularity; + if (chip->ibl.size > chip->ibl.max_size) + chip->ibl.size = chip->ibl.max_size; + } else + chip->ibl.size = chip->ibl.min_size; /* set to the minimum */ + vx_set_ibl(chip, &chip->ibl); + + return 0; +} + + +/* + * free callback for pcm + */ +static void snd_vx_pcm_free(snd_pcm_t *pcm) +{ + vx_core_t *chip = snd_magic_cast(vx_core_t, pcm->private_data, return); + chip->pcm[pcm->device] = NULL; + if (chip->playback_pipes) { + kfree(chip->playback_pipes); + chip->playback_pipes = 0; + } + if (chip->capture_pipes) { + kfree(chip->capture_pipes); + chip->capture_pipes = 0; + } +} + +/* + * snd_vx_pcm_new - create and initialize a pcm + */ +int snd_vx_pcm_new(vx_core_t *chip) +{ + snd_pcm_t *pcm; + unsigned int i; + int err; + + if ((err = vx_init_audio_io(chip)) < 0) + return err; + + for (i = 0; i < chip->hw->num_codecs; i++) { + unsigned int outs, ins; + outs = chip->audio_outs > i * 2 ? 1 : 0; + ins = chip->audio_ins > i * 2 ? 1 : 0; + if (! outs && ! ins) + break; + err = snd_pcm_new(chip->card, "VX PCM", i, + outs, ins, &pcm); + if (err < 0) + return err; + if (outs) + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &vx_pcm_playback_ops); + if (ins) + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &vx_pcm_capture_ops); + + pcm->private_data = chip; + pcm->private_free = snd_vx_pcm_free; + pcm->info_flags = 0; + strcpy(pcm->name, chip->card->shortname); + chip->pcm[i] = pcm; + } + + return 0; +} diff -Nru a/sound/drivers/vx/vx_uer.c b/sound/drivers/vx/vx_uer.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/drivers/vx/vx_uer.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,320 @@ +/* + * Driver for Digigram VX soundcards + * + * IEC958 stuff + * + * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <sound/driver.h> +#include <linux/delay.h> +#include <sound/core.h> +#include <sound/vx_core.h> +#include "vx_cmd.h" + + +/* + * vx_modify_board_clock - tell the board that its clock has been modified + * @sync: DSP needs to resynchronize its FIFO + */ +static int vx_modify_board_clock(vx_core_t *chip, int sync) +{ + struct vx_rmh rmh; + + vx_init_rmh(&rmh, CMD_MODIFY_CLOCK); + /* Ask the DSP to resynchronize its FIFO. */ + if (sync) + rmh.Cmd[0] |= CMD_MODIFY_CLOCK_S_BIT; + return vx_send_msg(chip, &rmh); +} + +/* + * vx_modify_board_inputs - resync audio inputs + */ +static int vx_modify_board_inputs(vx_core_t *chip) +{ + struct vx_rmh rmh; + + vx_init_rmh(&rmh, CMD_RESYNC_AUDIO_INPUTS); + rmh.Cmd[0] |= 1 << 0; /* reference: AUDIO 0 */ + return vx_send_msg(chip, &rmh); +} + +/* + * vx_read_one_cbit - read one bit from UER config + * @index: the bit index + * returns 0 or 1. + */ +static int vx_read_one_cbit(vx_core_t *chip, int index) +{ + unsigned long flags; + int val; + spin_lock_irqsave(&chip->lock, flags); + if (chip->type >= VX_TYPE_VXPOCKET) { + vx_outb(chip, CSUER, 1); /* read */ + vx_outb(chip, RUER, index & XX_UER_CBITS_OFFSET_MASK); + val = (vx_inb(chip, RUER) >> 7) & 0x01; + } else { + vx_outl(chip, CSUER, 1); /* read */ + vx_outl(chip, RUER, index & XX_UER_CBITS_OFFSET_MASK); + val = (vx_inl(chip, RUER) >> 7) & 0x01; + } + spin_unlock_irqrestore(&chip->lock, flags); + return val; +} + +/* + * vx_write_one_cbit - write one bit to UER config + * @index: the bit index + * @val: bit value, 0 or 1 + */ +static void vx_write_one_cbit(vx_core_t *chip, int index, int val) +{ + unsigned long flags; + val = !!val; /* 0 or 1 */ + spin_lock_irqsave(&chip->lock, flags); + if (vx_is_pcmcia(chip)) { + vx_outb(chip, CSUER, 0); /* write */ + vx_outb(chip, RUER, (val << 7) | (index & XX_UER_CBITS_OFFSET_MASK)); + } else { + vx_outl(chip, CSUER, 0); /* write */ + vx_outl(chip, RUER, (val << 7) | (index & XX_UER_CBITS_OFFSET_MASK)); + } + spin_unlock_irqrestore(&chip->lock, flags); +} + +/* + * vx_read_uer_status - read the current UER status + * @mode: pointer to store the UER mode, VX_UER_MODE_XXX + * + * returns the frequency of UER, or 0 if not sync, + * or a negative error code. + */ +static int vx_read_uer_status(vx_core_t *chip, int *mode) +{ + int val, freq; + + /* Default values */ + freq = 0; + + /* Read UER status */ + if (vx_is_pcmcia(chip)) + val = vx_inb(chip, CSUER); + else + val = vx_inl(chip, CSUER); + if (val < 0) + return val; + /* If clock is present, read frequency */ + if (val & VX_SUER_CLOCK_PRESENT_MASK) { + switch (val & VX_SUER_FREQ_MASK) { + case VX_SUER_FREQ_32KHz_MASK: + freq = 32000; + break; + case VX_SUER_FREQ_44KHz_MASK: + freq = 44100; + break; + case VX_SUER_FREQ_48KHz_MASK: + freq = 48000; + break; + } + } + if (val & VX_SUER_DATA_PRESENT_MASK) + /* bit 0 corresponds to consumer/professional bit */ + *mode = vx_read_one_cbit(chip, 0) ? + VX_UER_MODE_PROFESSIONAL : VX_UER_MODE_CONSUMER; + else + *mode = VX_UER_MODE_NOT_PRESENT; + + return freq; +} + + +/* + * compute the sample clock value from frequency + * + * The formula is as follows: + * + * HexFreq = (dword) ((double) ((double) 28224000 / (double) Frequency)) + * switch ( HexFreq & 0x00000F00 ) + * case 0x00000100: ; + * case 0x00000200: + * case 0x00000300: HexFreq -= 0x00000201 ; + * case 0x00000400: + * case 0x00000500: + * case 0x00000600: + * case 0x00000700: HexFreq = (dword) (((double) 28224000 / (double) (Frequency*2)) - 1) + * default : HexFreq = (dword) ((double) 28224000 / (double) (Frequency*4)) - 0x000001FF + */ + +static int vx_calc_clock_from_freq(vx_core_t *chip, int freq) +{ +#define XX_FECH48000 0x0000004B +#define XX_FECH32000 0x00000171 +#define XX_FECH24000 0x0000024B +#define XX_FECH16000 0x00000371 +#define XX_FECH12000 0x0000044B +#define XX_FECH8000 0x00000571 +#define XX_FECH44100 0x0000007F +#define XX_FECH29400 0x0000016F +#define XX_FECH22050 0x0000027F +#define XX_FECH14000 0x000003EF +#define XX_FECH11025 0x0000047F +#define XX_FECH7350 0x000005BF + + switch (freq) { + case 48000: return XX_FECH48000; + case 44100: return XX_FECH44100; + case 32000: return XX_FECH32000; + case 29400: return XX_FECH29400; + case 24000: return XX_FECH24000; + case 22050: return XX_FECH22050; + case 16000: return XX_FECH16000; + case 14000: return XX_FECH14000; + case 12000: return XX_FECH12000; + case 11025: return XX_FECH11025; + case 8000: return XX_FECH8000; + case 7350: return XX_FECH7350; + default: return freq; /* The value is already correct */ + } +} + + +/* + * vx_change_clock_source - change the clock source + * @source: the new source + */ +void vx_change_clock_source(vx_core_t *chip, int source) +{ + unsigned long flags; + + /* we mute DAC to prevent clicks */ + vx_toggle_dac_mute(chip, 1); + spin_lock_irqsave(&chip->lock, flags); + chip->ops->set_clock_source(chip, source); + chip->clock_source = source; + spin_unlock_irqrestore(&chip->lock, flags); + /* unmute */ + vx_toggle_dac_mute(chip, 0); +} + + +/* + * set the internal clock + */ +void vx_set_internal_clock(vx_core_t *chip, unsigned int freq) +{ + int clock; + unsigned long flags; + /* Get real clock value */ + clock = vx_calc_clock_from_freq(chip, freq); + snd_printdd(KERN_DEBUG "set internal clock to 0x%x from freq %d\n", clock, freq); + spin_lock_irqsave(&chip->lock, flags); + if (vx_is_pcmcia(chip)) { + vx_outb(chip, HIFREQ, (clock >> 8) & 0x0f); + vx_outb(chip, LOFREQ, clock & 0xff); + } else { + vx_outl(chip, HIFREQ, (clock >> 8) & 0x0f); + vx_outl(chip, LOFREQ, clock & 0xff); + } + spin_unlock_irqrestore(&chip->lock, flags); +} + + +/* + * set the iec958 status bits + * @bits: 32-bit status bits + */ +void vx_set_iec958_status(vx_core_t *chip, unsigned int bits) +{ + int i; + + if (chip->chip_status & VX_STAT_IS_STALE) + return; + + for (i = 0; i < 32; i++) + vx_write_one_cbit(chip, i, bits & (1 << i)); +} + + +/* + * vx_set_clock - change the clock and audio source if necessary + */ +int vx_set_clock(vx_core_t *chip, unsigned int freq) +{ + int src_changed = 0; + + if (chip->chip_status & VX_STAT_IS_STALE) + return 0; + + /* change the audio source if possible */ + vx_sync_audio_source(chip); + + switch (chip->audio_source) { + case VX_AUDIO_SRC_DIGITAL: + if (chip->clock_source != UER_SYNC) { + vx_change_clock_source(chip, UER_SYNC); + mdelay(6); + src_changed = 1; + } + if (chip->freq == freq) + return 0; + break; + default: + if (chip->clock_source != INTERNAL_QUARTZ) { + vx_change_clock_source(chip, INTERNAL_QUARTZ); + src_changed = 1; + } + if (chip->freq == freq) + return 0; + vx_set_internal_clock(chip, freq); + if (src_changed) + vx_modify_board_inputs(chip); + break; + } + chip->freq = freq; + vx_modify_board_clock(chip, 1); + return 0; +} + + +/* + * vx_change_frequency - called from interrupt handler + */ +int vx_change_frequency(vx_core_t *chip) +{ + int freq; + + if (chip->chip_status & VX_STAT_IS_STALE) + return 0; + + if (chip->clock_source == INTERNAL_QUARTZ) + return 0; + /* + * Read the real UER board frequency + */ + freq = vx_read_uer_status(chip, &chip->uer_detected); + if (freq < 0) + return freq; + /* + * The frequency computed by the DSP is good and + * is different from the previous computed. + */ + if (freq == 48000 || freq == 44100 || freq == 32000) + chip->freq_detected = freq; + + return 0; +} diff -Nru a/sound/i2c/Makefile b/sound/i2c/Makefile --- a/sound/i2c/Makefile Mon Jun 9 23:16:14 2003 +++ b/sound/i2c/Makefile Mon Jun 9 23:16:14 2003 @@ -11,6 +11,8 @@ obj-$(CONFIG_L3) += l3/ endif +obj-$(CONFIG_SND) += other/ + # Toplevel Module Dependency obj-$(CONFIG_SND_INTERWAVE_STB) += snd-tea6330t.o snd-i2c.o obj-$(CONFIG_SND_ICE1712) += snd-cs8427.o snd-i2c.o diff -Nru a/sound/i2c/cs8427.c b/sound/i2c/cs8427.c --- a/sound/i2c/cs8427.c Mon Jun 9 23:16:05 2003 +++ b/sound/i2c/cs8427.c Mon Jun 9 23:16:05 2003 @@ -22,6 +22,7 @@ #include <sound/driver.h> #include <linux/slab.h> +#include <linux/delay.h> #include <sound/core.h> #include <sound/control.h> #include <sound/pcm.h> @@ -47,6 +48,7 @@ typedef struct { unsigned char regmap[0x14]; /* map of first 1 + 13 registers */ + unsigned int rate; cs8427_stream_t playback; cs8427_stream_t capture; } cs8427_t; @@ -56,8 +58,8 @@ int bit; unsigned char res = 0; for (bit = 0; bit < 8; bit++) { - res |= val & 1; res <<= 1; + res |= val & 1; val >>= 1; } return res; @@ -133,10 +135,10 @@ return 0; if ((err = snd_cs8427_select_corudata(device, udata)) < 0) return err; - memcpy(hw_data, data, count); + memcpy(hw_data, ndata, count); if (udata) { memset(data, 0, sizeof(data)); - if (memcmp(hw_data, data, 32) == 0) { + if (memcmp(hw_data, data, count) == 0) { chip->regmap[CS8427_REG_UDATABUF] &= ~CS8427_UBMMASK; chip->regmap[CS8427_REG_UDATABUF] |= CS8427_UBMZEROS | CS8427_EFTUI; if ((err = snd_cs8427_reg_write(device, CS8427_REG_UDATABUF, chip->regmap[CS8427_REG_UDATABUF])) < 0) @@ -147,7 +149,7 @@ data[0] = CS8427_REG_AUTOINC | CS8427_REG_CORU_DATABUF; for (idx = 0; idx < count; idx++) data[idx + 1] = swapbits(ndata[idx]); - if (snd_i2c_sendbytes(device, data, count) != count) + if (snd_i2c_sendbytes(device, data, count + 1) != count + 1) return -EIO; return 1; } @@ -164,15 +166,15 @@ { static unsigned char initvals1[] = { CS8427_REG_CONTROL1 | CS8427_REG_AUTOINC, - /* CS8427_REG_CLOCKSOURCE: RMCK to OMCK, no validity, disable mutes, TCBL=output */ - CS8427_SWCLK, + /* CS8427_REG_CONTROL1: RMCK to OMCK, valid PCM audio, disable mutes, TCBL=output */ + CS8427_SWCLK | CS8427_TCBLDIR, /* CS8427_REG_CONTROL2: hold last valid audio sample, RMCK=256*Fs, normal stereo operation */ 0x00, /* CS8427_REG_DATAFLOW: output drivers normal operation, Tx<=serial, Rx=>serial */ CS8427_TXDSERIAL | CS8427_SPDAES3RECEIVER, /* CS8427_REG_CLOCKSOURCE: Run off, CMCK=256*Fs, output time base = OMCK, input time base = - covered input clock, recovered input clock source is Envy24 */ - CS8427_INC, + recovered input clock, recovered input clock source is ILRCK changed to AES3INPUT (workaround, see snd_cs8427_reset) */ + CS8427_RXDILRCK, /* CS8427_REG_SERIALINPUT: Serial audio input port data format = I2S, 24-bit, 64*Fsi */ CS8427_SIDEL | CS8427_SILRPOL, /* CS8427_REG_SERIALOUTPUT: Serial audio output port data format = I2S, 24-bit, 64*Fsi */ @@ -181,9 +183,8 @@ static unsigned char initvals2[] = { CS8427_REG_RECVERRMASK | CS8427_REG_AUTOINC, /* CS8427_REG_RECVERRMASK: unmask the input PLL clock, V, confidence, biphase, parity status bits */ - /* CS8427_UNLOCK | CS8427_V | CS8427_CONF | CS8427_BIP | CS8427_PAR, - Why setting CS8427_V causes clicks and glitches? */ - CS8427_UNLOCK | CS8427_CONF | CS8427_BIP | CS8427_PAR, + /* CS8427_UNLOCK | CS8427_V | CS8427_CONF | CS8427_BIP | CS8427_PAR, */ + 0xff, /* set everything */ /* CS8427_REG_CSDATABUF: Registers 32-55 window to CS buffer Inhibit D->E transfers from overwriting first 5 bytes of CS data. @@ -203,7 +204,7 @@ int err; cs8427_t *chip; snd_i2c_device_t *device; - unsigned char buf[32 + 1]; + unsigned char buf[24]; if ((err = snd_i2c_device_create(bus, "CS8427", CS8427_ADDR | (addr & 7), &device)) < 0) return err; @@ -242,31 +243,32 @@ goto __fail; } /* write default channel status bytes */ - buf[0] = CS8427_REG_AUTOINC | CS8427_REG_CORU_DATABUF; - buf[1] = swapbits((unsigned char)(SNDRV_PCM_DEFAULT_CON_SPDIF >> 0)); - buf[2] = swapbits((unsigned char)(SNDRV_PCM_DEFAULT_CON_SPDIF >> 8)); - buf[3] = swapbits((unsigned char)(SNDRV_PCM_DEFAULT_CON_SPDIF >> 16)); - buf[4] = swapbits((unsigned char)(SNDRV_PCM_DEFAULT_CON_SPDIF >> 24)); - memset(buf + 5, 0, sizeof(buf)-5); - memcpy(chip->playback.def_status, buf + 1, 24); - memcpy(chip->playback.pcm_status, buf + 1, 24); - if ((err = snd_i2c_sendbytes(device, buf, 33)) != 33) + buf[0] = ((unsigned char)(SNDRV_PCM_DEFAULT_CON_SPDIF >> 0)); + buf[1] = ((unsigned char)(SNDRV_PCM_DEFAULT_CON_SPDIF >> 8)); + buf[2] = ((unsigned char)(SNDRV_PCM_DEFAULT_CON_SPDIF >> 16)); + buf[3] = ((unsigned char)(SNDRV_PCM_DEFAULT_CON_SPDIF >> 24)); + memset(buf + 4, 0, 24 - 4); + if (snd_cs8427_send_corudata(device, 0, buf, 24) < 0) goto __fail; + memcpy(chip->playback.def_status, buf, 24); + memcpy(chip->playback.pcm_status, buf, 24); + snd_i2c_unlock(bus); + /* turn on run bit and rock'n'roll */ - chip->regmap[CS8427_REG_CLOCKSOURCE] = initvals1[4] | CS8427_RUN; - if ((err = snd_cs8427_reg_write(device, CS8427_REG_CLOCKSOURCE, chip->regmap[CS8427_REG_CLOCKSOURCE])) < 0) - goto __fail; + snd_cs8427_reset(device); #if 0 // it's nice for read tests { char buf[128]; + int xx; buf[0] = 0x81; snd_i2c_sendbytes(device, buf, 1); snd_i2c_readbytes(device, buf, 127); + for (xx = 0; xx < 127; xx++) + printk("reg[0x%x] = 0x%x\n", xx+1, buf[xx]); } #endif - snd_i2c_unlock(bus); if (r_cs8427) *r_cs8427 = device; return 0; @@ -277,6 +279,44 @@ return err < 0 ? err : -EIO; } +/* + * Reset the chip using run bit, also lock PLL using ILRCK and + * put back AES3INPUT. This workaround is described in latest + * CS8427 datasheet, otherwise TXDSERIAL will not work. + */ +void snd_cs8427_reset(snd_i2c_device_t *cs8427) +{ + cs8427_t *chip; + unsigned long end_time; + int data; + + snd_assert(cs8427, return); + chip = snd_magic_cast(cs8427_t, cs8427->private_data, return); + snd_i2c_lock(cs8427->bus); + chip->regmap[CS8427_REG_CLOCKSOURCE] &= ~(CS8427_RUN | CS8427_RXDMASK); + snd_cs8427_reg_write(cs8427, CS8427_REG_CLOCKSOURCE, chip->regmap[CS8427_REG_CLOCKSOURCE]); + udelay(200); + chip->regmap[CS8427_REG_CLOCKSOURCE] |= CS8427_RUN | CS8427_RXDILRCK; + snd_cs8427_reg_write(cs8427, CS8427_REG_CLOCKSOURCE, chip->regmap[CS8427_REG_CLOCKSOURCE]); + udelay(200); + snd_i2c_unlock(cs8427->bus); + end_time = jiffies + HZ / 2; + while (time_after_eq(end_time, jiffies)) { + snd_i2c_lock(cs8427->bus); + data = snd_cs8427_reg_read(cs8427, CS8427_REG_RECVERRORS); + snd_i2c_unlock(cs8427->bus); + if (!(data & CS8427_UNLOCK)) + break; + set_current_state(TASK_UNINTERRUPTIBLE); + schedule_timeout(HZ/100); + } + snd_i2c_lock(cs8427->bus); + chip->regmap[CS8427_REG_CLOCKSOURCE] &= ~CS8427_RXDMASK; + chip->regmap[CS8427_REG_CLOCKSOURCE] |= CS8427_RXDAES3INPUT; + snd_cs8427_reg_write(cs8427, CS8427_REG_CLOCKSOURCE, chip->regmap[CS8427_REG_CLOCKSOURCE]); + snd_i2c_unlock(cs8427->bus); +} + static int snd_cs8427_in_status_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) { @@ -294,7 +334,7 @@ int data; snd_i2c_lock(device->bus); - data = snd_cs8427_reg_read(device, 15); + data = snd_cs8427_reg_read(device, kcontrol->private_value); snd_i2c_unlock(device->bus); if (data < 0) return data; @@ -302,6 +342,36 @@ return 0; } +static int snd_cs8427_qsubcode_info(snd_kcontrol_t *kcontrol, + snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = 10; + return 0; +} + +static int snd_cs8427_qsubcode_get(snd_kcontrol_t *kcontrol, + snd_ctl_elem_value_t *ucontrol) +{ + snd_i2c_device_t *device = snd_kcontrol_chip(kcontrol); + unsigned char reg = CS8427_REG_QSUBCODE; + int err; + + snd_i2c_lock(device->bus); + if ((err = snd_i2c_sendbytes(device, ®, 1)) != 1) { + snd_printk("unable to send register 0x%x byte to CS8427\n", reg); + snd_i2c_unlock(device->bus); + return err < 0 ? err : -EIO; + } + if ((err = snd_i2c_readbytes(device, ucontrol->value.bytes.data, 10)) != 10) { + snd_printk("unable to read Q-subcode bytes from CS8427\n"); + snd_i2c_unlock(device->bus); + return err < 0 ? err : -EIO; + } + snd_i2c_unlock(device->bus); + return 0; +} + static int snd_cs8427_spdif_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; @@ -316,7 +386,7 @@ cs8427_t *chip = snd_magic_cast(cs8427_t, device->private_data, return -ENXIO); snd_i2c_lock(device->bus); - memcpy(ucontrol->value.iec958.status, chip->playback.def_status, 23); + memcpy(ucontrol->value.iec958.status, chip->playback.def_status, 24); snd_i2c_unlock(device->bus); return 0; } @@ -327,13 +397,14 @@ snd_i2c_device_t *device = snd_kcontrol_chip(kcontrol); cs8427_t *chip = snd_magic_cast(cs8427_t, device->private_data, return -ENXIO); unsigned char *status = kcontrol->private_value ? chip->playback.pcm_status : chip->playback.def_status; + snd_pcm_runtime_t *runtime = chip->playback.substream ? chip->playback.substream->runtime : NULL; int err, change; snd_i2c_lock(device->bus); - change = memcmp(ucontrol->value.iec958.status, status, 23) != 0; - memcpy(status, ucontrol->value.iec958.status, 23); - if (change && (kcontrol->private_value ? chip->playback.substream != NULL : chip->playback.substream == NULL)) { - err = snd_cs8427_send_corudata(device, 0, status, 23); + change = memcmp(ucontrol->value.iec958.status, status, 24) != 0; + memcpy(status, ucontrol->value.iec958.status, 24); + if (change && (kcontrol->private_value ? runtime != NULL : runtime == NULL)) { + err = snd_cs8427_send_corudata(device, 0, status, 24); if (err < 0) change = err; } @@ -351,7 +422,7 @@ static int snd_cs8427_spdif_mask_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { - memset(ucontrol->value.iec958.status, 0xff, 23); + memset(ucontrol->value.iec958.status, 0xff, 24); return 0; } @@ -364,6 +435,15 @@ .name = "IEC958 CS8427 Input Status", .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, .get = snd_cs8427_in_status_get, + .private_value = 15, +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .info = snd_cs8427_in_status_info, + .name = "IEC958 CS8427 Error Status", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .get = snd_cs8427_in_status_get, + .private_value = 16, }, { .access = SNDRV_CTL_ELEM_ACCESS_READ, @@ -388,6 +468,13 @@ .get = snd_cs8427_spdif_get, .put = snd_cs8427_spdif_put, .private_value = 1 +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .info = snd_cs8427_qsubcode_info, + .name = "IEC958 Q-subcode Capture Default", + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .get = snd_cs8427_qsubcode_get }}; int snd_cs8427_iec958_build(snd_i2c_device_t *cs8427, @@ -413,6 +500,8 @@ chip->playback.pcm_ctl = kctl; } + chip->playback.substream = play_substream; + chip->capture.substream = cap_substream; snd_assert(chip->playback.pcm_ctl, return -EIO); return 0; } @@ -435,7 +524,7 @@ { cs8427_t *chip; char *status; - int err; + int err, reset; snd_assert(cs8427, return -ENXIO); chip = snd_magic_cast(cs8427_t, cs8427->private_data, return -ENXIO); @@ -457,17 +546,21 @@ case 48000: status[3] |= IEC958_AES3_CON_FS_48000; break; } } - err = snd_cs8427_send_corudata(cs8427, 0, status, 23); + err = snd_cs8427_send_corudata(cs8427, 0, status, 24); if (err > 0) snd_ctl_notify(cs8427->bus->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->playback.pcm_ctl->id); + reset = chip->rate != rate; snd_i2c_unlock(cs8427->bus); + if (reset) + snd_cs8427_reset(cs8427); return err < 0 ? err : 0; } EXPORT_SYMBOL(snd_cs8427_detect); EXPORT_SYMBOL(snd_cs8427_create); +EXPORT_SYMBOL(snd_cs8427_reset); EXPORT_SYMBOL(snd_cs8427_iec958_build); EXPORT_SYMBOL(snd_cs8427_iec958_active); EXPORT_SYMBOL(snd_cs8427_iec958_pcm); diff -Nru a/sound/i2c/l3/uda1341.c b/sound/i2c/l3/uda1341.c --- a/sound/i2c/l3/uda1341.c Mon Jun 9 23:16:12 2003 +++ b/sound/i2c/l3/uda1341.c Mon Jun 9 23:16:12 2003 @@ -17,7 +17,7 @@ * 2002-05-12 Tomas Kasparek another code cleanup */ -/* $Id: uda1341.c,v 1.8 2003/03/20 16:45:59 perex Exp $ */ +/* $Id: uda1341.c,v 1.9 2003/04/19 13:34:33 perex Exp $ */ #include <sound/driver.h> #include <linux/module.h> @@ -36,8 +36,6 @@ #include <linux/l3/l3.h> -#undef DEBUG_MODE -#undef DEBUG_FUNCTION_NAMES #include <sound/uda1341.h> /* {{{ HW regs definition */ @@ -93,13 +91,13 @@ const int uda1341_enum_items[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2, //peak - before/after - 4, //deemp - none/32/44.1/48 - 0, - 4, //filter - flat/min/min/max - 0, 0, 0, - 4, //mixer - differ/line/mic/mixer - 0, 0, 0, 0, 0, + 2, //peak - before/after + 4, //deemp - none/32/44.1/48 + 0, + 4, //filter - flat/min/min/max + 0, 0, 0, + 4, //mixer - differ/line/mic/mixer + 0, 0, 0, 0, 0, }; const char ** uda1341_enum_names[] = { @@ -117,26 +115,24 @@ typedef struct uda1341 uda1341_t; -struct uda1341{ - void (*write) (struct l3_client *uda1341, unsigned short reg, unsigned short val); - unsigned char (*read) (struct l3_client *uda1341, unsigned short reg); - - unsigned char regs[uda1341_reg_last]; - int active; - +struct uda1341 { + int (*write) (struct l3_client *uda1341, unsigned short reg, unsigned short val); + int (*read) (struct l3_client *uda1341, unsigned short reg); + unsigned char regs[uda1341_reg_last]; + int active; spinlock_t reg_lock; - snd_card_t *card; - uda1341_cfg cfg; +#ifdef CONFIG_PM + unsigned char suspend_regs[uda1341_reg_last]; + uda1341_cfg suspend_cfg; +#endif }; //hack for ALSA magic casting typedef struct l3_client l3_client_t; #define chip_t l3_client_t -static struct l3_client *uda1341=NULL; - /* transfer 8bit integer into string with binary representation */ void int2str_bin8(uint8_t val, char *buf){ const int size = sizeof(val) * 8; @@ -151,66 +147,45 @@ /* {{{ HW manipulation routines */ -void snd_uda1341_codec_write(struct l3_client *clnt, unsigned short reg, unsigned short val) +int snd_uda1341_codec_write(struct l3_client *clnt, unsigned short reg, unsigned short val) { struct uda1341 *uda = clnt->driver_data; - - int err=0; unsigned char buf[2] = { 0xc0, 0xe0 }; // for EXT addressing + int err = 0; - DEBUG_NAME(KERN_DEBUG "codec_write: reg: %s val: %d ", uda1341_reg_names[reg], val); - uda->regs[reg] = val; if (uda->active) { - DEBUG("O"); if (IS_DATA0(reg)) { - DEBUG(" D0 "); err = l3_write(clnt, UDA1341_DATA0, (const unsigned char *)&val, 1); } else if (IS_DATA1(reg)) { - DEBUG(" D1 "); err = l3_write(clnt, UDA1341_DATA1, (const unsigned char *)&val, 1); } else if (IS_STATUS(reg)) { - DEBUG(" S "); err = l3_write(clnt, UDA1341_STATUS, (const unsigned char *)&val, 1); } else if (IS_EXTEND(reg)) { - DEBUG(" E "); buf[0] |= (reg - ext0) & 0x7; //EXT address buf[1] |= val; //EXT data - DEBUG("%x %x ", buf[0], buf[1]); err = l3_write(clnt, UDA1341_DATA0, (const unsigned char *)buf, 2); } - - if (err == 1 || err == 2) - DEBUG("K\n"); - else - DEBUG(" Error: %d\n", err); } else printk(KERN_ERR "UDA1341 codec not active!\n"); + return err; } -unsigned char snd_uda1341_codec_read(struct l3_client *clnt, unsigned short reg) +int snd_uda1341_codec_read(struct l3_client *clnt, unsigned short reg) { - int err=0; unsigned char val; - - DEBUG_NAME(KERN_DEBUG "codec_read: reg: %d ", reg); - - DEBUG("O"); + int err; err = l3_read(clnt, reg, &val, 1); - if (err == 1) - DEBUG("K\n"); - else - DEBUG(" Error: %d\n", err); - - return val & 63; //use just 6bits - the rest is address of the reg + // use just 6bits - the rest is address of the reg + return val & 63; + return err < 0 ? err : -EIO; } -static int snd_uda1341_valid_reg(struct l3_client *clnt, unsigned short reg) +static inline int snd_uda1341_valid_reg(struct l3_client *clnt, unsigned short reg) { - DEBUG_NAME(KERN_DEBUG "valid_reg\n"); return reg < uda1341_reg_last; } @@ -221,8 +196,10 @@ unsigned short old, new; struct uda1341 *uda = clnt->driver_data; - DEBUG(KERN_DEBUG "update_bits: reg: %s mask: %d shift: %d val: %d\n", - uda1341_reg_names[reg], mask, shift, value); +#if 0 + printk(KERN_DEBUG "update_bits: reg: %s mask: %d shift: %d val: %d\n", + uda1341_reg_names[reg], mask, shift, value); +#endif if (!snd_uda1341_valid_reg(clnt, reg)) return -EINVAL; @@ -243,70 +220,111 @@ { struct uda1341 *uda = clnt->driver_data; int ret = 0; +#ifdef CONFIG_PM + int reg; +#endif - DEBUG_NAME(KERN_DEBUG "cfg_write what: %d value: %d\n", what, value); +#if 0 + printk(KERN_DEBUG "cfg_write what: %d value: %d\n", what, value); +#endif uda->cfg[what] = value; switch(what) { - case CMD_RESET: ret = snd_uda1341_update_bits(clnt, data0_2, 1, 2, 1, flush);//MUTE - ret = snd_uda1341_update_bits(clnt, stat0, 1, 6, 1, flush);//RESET - ret = snd_uda1341_update_bits(clnt, stat0, 1, 6, 0, flush);// RESTORE + case CMD_RESET: + ret = snd_uda1341_update_bits(clnt, data0_2, 1, 2, 1, flush); // MUTE + ret = snd_uda1341_update_bits(clnt, stat0, 1, 6, 1, flush); // RESET + ret = snd_uda1341_update_bits(clnt, stat0, 1, 6, 0, flush); // RESTORE uda->cfg[CMD_RESET]=0; break; - case CMD_FS: ret = snd_uda1341_update_bits(clnt, stat0, 3, 4, value, flush); + case CMD_FS: + ret = snd_uda1341_update_bits(clnt, stat0, 3, 4, value, flush); break; - case CMD_FORMAT: ret = snd_uda1341_update_bits(clnt, stat0, 7, 1, value, flush); + case CMD_FORMAT: + ret = snd_uda1341_update_bits(clnt, stat0, 7, 1, value, flush); break; - case CMD_OGAIN: ret = snd_uda1341_update_bits(clnt, stat1, 1, 6, value, flush); + case CMD_OGAIN: + ret = snd_uda1341_update_bits(clnt, stat1, 1, 6, value, flush); break; - case CMD_IGAIN: ret = snd_uda1341_update_bits(clnt, stat1, 1, 5, value, flush); + case CMD_IGAIN: + ret = snd_uda1341_update_bits(clnt, stat1, 1, 5, value, flush); break; - case CMD_DAC: ret = snd_uda1341_update_bits(clnt, stat1, 1, 0, value, flush); + case CMD_DAC: + ret = snd_uda1341_update_bits(clnt, stat1, 1, 0, value, flush); break; - case CMD_ADC: ret = snd_uda1341_update_bits(clnt, stat1, 1, 1, value, flush); + case CMD_ADC: + ret = snd_uda1341_update_bits(clnt, stat1, 1, 1, value, flush); break; - case CMD_VOLUME: ret = snd_uda1341_update_bits(clnt, data0_0, 63, 0, value, flush); + case CMD_VOLUME: + ret = snd_uda1341_update_bits(clnt, data0_0, 63, 0, value, flush); break; - case CMD_BASS: ret = snd_uda1341_update_bits(clnt, data0_1, 15, 2, value, flush); + case CMD_BASS: + ret = snd_uda1341_update_bits(clnt, data0_1, 15, 2, value, flush); break; - case CMD_TREBBLE: ret = snd_uda1341_update_bits(clnt, data0_1, 3, 0, value, flush); + case CMD_TREBBLE: + ret = snd_uda1341_update_bits(clnt, data0_1, 3, 0, value, flush); break; - case CMD_PEAK: ret = snd_uda1341_update_bits(clnt, data0_2, 1, 5, value, flush); + case CMD_PEAK: + ret = snd_uda1341_update_bits(clnt, data0_2, 1, 5, value, flush); break; - case CMD_DEEMP: ret = snd_uda1341_update_bits(clnt, data0_2, 3, 3, value, flush); + case CMD_DEEMP: + ret = snd_uda1341_update_bits(clnt, data0_2, 3, 3, value, flush); break; - case CMD_MUTE: ret = snd_uda1341_update_bits(clnt, data0_2, 1, 2, value, flush); + case CMD_MUTE: + ret = snd_uda1341_update_bits(clnt, data0_2, 1, 2, value, flush); break; - case CMD_FILTER: ret = snd_uda1341_update_bits(clnt, data0_2, 3, 0, value, flush); + case CMD_FILTER: + ret = snd_uda1341_update_bits(clnt, data0_2, 3, 0, value, flush); break; - case CMD_CH1: ret = snd_uda1341_update_bits(clnt, ext0, 31, 0, value, flush); + case CMD_CH1: + ret = snd_uda1341_update_bits(clnt, ext0, 31, 0, value, flush); break; - case CMD_CH2: ret = snd_uda1341_update_bits(clnt, ext1, 31, 0, value, flush); + case CMD_CH2: + ret = snd_uda1341_update_bits(clnt, ext1, 31, 0, value, flush); break; - case CMD_MIC: ret = snd_uda1341_update_bits(clnt, ext2, 7, 2, value, flush); + case CMD_MIC: + ret = snd_uda1341_update_bits(clnt, ext2, 7, 2, value, flush); break; - case CMD_MIXER: ret = snd_uda1341_update_bits(clnt, ext2, 3, 0, value, flush); + case CMD_MIXER: + ret = snd_uda1341_update_bits(clnt, ext2, 3, 0, value, flush); break; - case CMD_AGC: ret = snd_uda1341_update_bits(clnt, ext4, 1, 4, value, flush); + case CMD_AGC: + ret = snd_uda1341_update_bits(clnt, ext4, 1, 4, value, flush); break; - case CMD_IG: ret = snd_uda1341_update_bits(clnt, ext4, 3, 0, value & 0x3, flush); + case CMD_IG: + ret = snd_uda1341_update_bits(clnt, ext4, 3, 0, value & 0x3, flush); ret = snd_uda1341_update_bits(clnt, ext5, 31, 0, value >> 2, flush); break; - case CMD_AGC_TIME: ret = snd_uda1341_update_bits(clnt, ext6, 7, 2, value, flush); + case CMD_AGC_TIME: + ret = snd_uda1341_update_bits(clnt, ext6, 7, 2, value, flush); break; - case CMD_AGC_LEVEL: ret = snd_uda1341_update_bits(clnt, ext6, 3, 0, value, flush); + case CMD_AGC_LEVEL: + ret = snd_uda1341_update_bits(clnt, ext6, 3, 0, value, flush); + break; +#ifdef CONFIG_PM + case CMD_SUSPEND: + for (reg = stat0; reg < uda1341_reg_last; reg++) + uda->suspend_regs[reg] = uda->regs[reg]; + for (reg = 0; reg < CMD_LAST; reg++) + uda->suspend_cfg[reg] = uda->cfg[reg]; + break; + case CMD_RESUME: + for (reg = stat0; reg < uda1341_reg_last; reg++) + snd_uda1341_codec_write(clnt, reg, uda->suspend_regs[reg]); + for (reg = 0; reg < CMD_LAST; reg++) + uda->cfg[reg] = uda->suspend_cfg[reg]; + break; +#endif + default: + ret = -EINVAL; break; - default: ret = -EINVAL; break; } - if (!uda->active) { + if (!uda->active) printk(KERN_ERR "UDA1341 codec not active!\n"); - } return ret; } - /* }}} */ /* {{{ Proc interface */ @@ -319,9 +337,9 @@ int peak; peak = snd_uda1341_codec_read(clnt, UDA1341_DATA1); + if (peak < 0) + peak = 0; - DEBUG_NAME(KERN_DEBUG "proc_read\n"); - snd_iprintf(buffer, "%s\n\n", uda->card->longname); // for information about computed values see UDA1341TS datasheet pages 15 - 21 @@ -343,7 +361,7 @@ snd_iprintf(buffer, "Mute : %s\n", uda->cfg[CMD_MUTE] ? "on" : "off"); - if(uda->cfg[CMD_VOLUME] == 0) + if (uda->cfg[CMD_VOLUME] == 0) snd_iprintf(buffer, "Volume : 0 dB\n"); else if (uda->cfg[CMD_VOLUME] < 62) snd_iprintf(buffer, "Volume : %d dB\n", -1*uda->cfg[CMD_VOLUME] +1); @@ -384,8 +402,6 @@ int reg; char buf[12]; - DEBUG_NAME(KERN_DEBUG "proc_regs_read\n"); - spin_lock(&uda->reg_lock); for (reg = 0; reg < uda1341_reg_last; reg ++) { if (reg == empty) @@ -403,13 +419,10 @@ static void __devinit snd_uda1341_proc_init(snd_card_t *card, struct l3_client *clnt) { snd_info_entry_t *entry; - struct uda1341 *uda = clnt->driver_data; - DEBUG_NAME(KERN_DEBUG "proc_init\n"); - if (! snd_card_proc_new(card, "uda1341", &entry)) snd_info_set_text_ops(entry, clnt, snd_uda1341_proc_read); - if (! snd_card_proc_new(card, "uda1341-regs", &entry)) { + if (! snd_card_proc_new(card, "uda1341-regs", &entry)) snd_info_set_text_ops(entry, clnt, snd_uda1341_proc_regs_read); } @@ -429,8 +442,6 @@ { int mask = (kcontrol->private_value >> 12) & 63; - DEBUG_NAME(KERN_DEBUG "info_single where: %ld\n", kcontrol->private_value & 31); - uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 1; uinfo->value.integer.min = 0; @@ -446,8 +457,6 @@ int mask = (kcontrol->private_value >> 12) & 63; int invert = (kcontrol->private_value >> 18) & 1; - DEBUG_NAME(KERN_DEBUG "get_single where: %d (val: %d)\n", where, uda->cfg[where]); - ucontrol->value.integer.value[0] = uda->cfg[where]; if (invert) ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; @@ -470,9 +479,6 @@ if (invert) val = mask - val; - DEBUG(KERN_DEBUG "put_single where: %d reg: %d mask: %d shift: %d inv: %d val: %d\n", - where, reg, mask, shift, invert, val); - uda->cfg[where] = val; return snd_uda1341_update_bits(clnt, reg, mask, shift, val, FLUSH); } @@ -492,8 +498,6 @@ int where = kcontrol->private_value & 31; const char **texts; - DEBUG_NAME(KERN_DEBUG "info_enum where: %d\n", where); - // this register we don't handle this way if (!uda1341_enum_items[where]) return -EINVAL; @@ -516,8 +520,6 @@ uda1341_t *uda = clnt->driver_data; int where = kcontrol->private_value & 31; - DEBUG_NAME(KERN_DEBUG "get_enum where: %d (val: %d)\n", where, uda->cfg[where]); - ucontrol->value.enumerated.item[0] = uda->cfg[where]; return 0; } @@ -533,9 +535,6 @@ uda->cfg[where] = (ucontrol->value.enumerated.item[0] & mask); - DEBUG(KERN_DEBUG "put_enum where: %d reg: %d mask: %d shift: %d val: %d\n", - where, reg, mask, shift, uda->cfg[where]); - return snd_uda1341_update_bits(clnt, reg, mask, shift, uda->cfg[where], FLUSH); } @@ -557,8 +556,6 @@ int mask_2 = (kcontrol->private_value >> 25) & 63; int mask; - DEBUG_NAME(KERN_DEBUG "info_2regs where: %ld\n", kcontrol->private_value & 31); - mask = (mask_2 + 1) * (mask_1 + 1) - 1; uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 1; @@ -577,8 +574,6 @@ int invert = (kcontrol->private_value >> 31) & 1; int mask; - DEBUG_NAME(KERN_DEBUG "get_2regs where: %d (val: %d)\n", where, uda->cfg[where]); - mask = (mask_2 + 1) * (mask_1 + 1) - 1; ucontrol->value.integer.value[0] = uda->cfg[where]; @@ -604,10 +599,6 @@ val = ucontrol->value.integer.value[0]; - DEBUG_NAME(KERN_DEBUG "put_2regs where: %d reg1: %d reg2: %d mask1: %d mask2: %d " - "shift1: %d shift2: %d inv: %d val: %d\n", where, reg_1, reg_2, mask_1, mask_2, - shift_1, shift_2, invert, val); - mask = (mask_2 + 1) * (mask_1 + 1) - 1; val1 = val & mask_1; @@ -659,20 +650,43 @@ UDA1341_2REGS("Gain Input Amplifier Gain (channel 2)", CMD_IG, ext4, ext5, 0, 0, 3, 31, 0), }; +static void uda1341_free(struct l3_client *uda1341) +{ + l3_detach_client(uda1341); // calls kfree for driver_data (uda1341_t) + snd_magic_kfree(uda1341); +} + +static int uda1341_dev_free(snd_device_t *device) +{ + struct l3_client *clnt = snd_magic_cast(l3_client_t, device->device_data, return); + uda1341_free(clnt); + return 0; +} + int __init snd_chip_uda1341_mixer_new(snd_card_t *card, struct l3_client **clnt) { + static snd_device_ops_t ops = { + .dev_free = uda1341_dev_free, + }; + struct l3_client *uda1341; int idx, err; - DEBUG_NAME(KERN_DEBUG "uda1341 mixer_new\n"); - snd_assert(card != NULL, return -EINVAL); uda1341 = snd_magic_kcalloc(l3_client_t, 0, GFP_KERNEL); if (uda1341 == NULL) return -ENOMEM; - if ((err = l3_attach_client(uda1341, "l3-bit-sa1100-gpio", "snd-uda1341"))) - return -ENODEV; + if ((err = l3_attach_client(uda1341, "l3-bit-sa1100-gpio", "snd-uda1341"))) { + kfree(uda1341); + return err; + } + + if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, uda1341, &ops)) < 0) { + l3_detach_client(uda1341); + kfree(uda1341); + return err; + } for (idx = 0; idx < UDA1341_CONTROLS; idx++) { if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_uda1341_controls[idx], uda1341))) < 0) @@ -688,16 +702,6 @@ return 0; } -void __init snd_chip_uda1341_mixer_del(snd_card_t *card) -{ - DEBUG_NAME(KERN_DEBUG "uda1341 mixer_del\n"); - - l3_detach_client(uda1341); - - snd_magic_kfree(uda1341); - uda1341 = NULL; -} - /* }}} */ /* {{{ L3 operations */ @@ -706,14 +710,10 @@ { struct uda1341 *uda; - DEBUG_NAME(KERN_DEBUG "uda1341 attach\n"); - uda = snd_magic_kcalloc(uda1341_t, 0, GFP_KERNEL); if (!uda) return -ENOMEM; - memset(uda, 0, sizeof(*uda)); - /* init fixed parts of my copy of registers */ uda->regs[stat0] = STAT0; uda->regs[stat1] = STAT1; @@ -728,22 +728,18 @@ spin_lock_init(&uda->reg_lock); clnt->driver_data = uda; - - //l3_open(clnt); return 0; } static void uda1341_detach(struct l3_client *clnt) { - DEBUG_NAME(KERN_DEBUG "uda1341 detach\n"); - snd_magic_kfree(clnt->driver_data); + if (clnt->driver_data) + snd_magic_kfree(clnt->driver_data); } static int uda1341_command(struct l3_client *clnt, int cmd, void *arg) { - DEBUG_NAME(KERN_DEBUG "l3_command\n"); - if (cmd != CMD_READ_REG) return snd_uda1341_cfg_write(clnt, cmd, (int) arg, FLUSH); @@ -754,8 +750,6 @@ { struct uda1341 *uda = clnt->driver_data; - DEBUG_NAME(KERN_DEBUG "uda1341 open\n"); - uda->active = 1; /* init default configuration */ @@ -764,8 +758,8 @@ snd_uda1341_cfg_write(clnt, CMD_FORMAT, LSB16, FLUSH); // unknown state after reset snd_uda1341_cfg_write(clnt, CMD_OGAIN, ON, FLUSH); // default off after reset snd_uda1341_cfg_write(clnt, CMD_IGAIN, ON, FLUSH); // default off after reset - snd_uda1341_cfg_write(clnt, CMD_DAC, ON, FLUSH); // ??? default value after reset - snd_uda1341_cfg_write(clnt, CMD_ADC, ON, FLUSH); // ??? default value after reset + snd_uda1341_cfg_write(clnt, CMD_DAC, ON, FLUSH); // ??? default value after reset + snd_uda1341_cfg_write(clnt, CMD_ADC, ON, FLUSH); // ??? default value after reset snd_uda1341_cfg_write(clnt, CMD_VOLUME, 20, FLUSH); // default 0dB after reset snd_uda1341_cfg_write(clnt, CMD_BASS, 0, REGS_ONLY); // default value after reset snd_uda1341_cfg_write(clnt, CMD_TREBBLE, 0, REGS_ONLY); // default value after reset @@ -790,7 +784,6 @@ { struct uda1341 *uda = clnt->driver_data; - DEBUG_NAME(KERN_DEBUG "uda1341 close\n"); uda->active = 0; } @@ -832,7 +825,6 @@ MODULE_DEVICES("{{UDA1341,UDA1341TS}}"); EXPORT_SYMBOL(snd_chip_uda1341_mixer_new); -EXPORT_SYMBOL(snd_chip_uda1341_mixer_del); /* }}} */ diff -Nru a/sound/i2c/other/Makefile b/sound/i2c/other/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/i2c/other/Makefile Mon Jun 9 23:16:20 2003 @@ -0,0 +1,10 @@ +# +# Makefile for ALSA +# Copyright (c) 2003 by Jaroslav Kysela <perex@suse.cz> +# + +snd-ak4xxx-adda-objs := ak4xxx-adda.o + +# Module Dependency +obj-$(CONFIG_SND_ICE1712) += snd-ak4xxx-adda.o +obj-$(CONFIG_SND_ICE1724) += snd-ak4xxx-adda.o diff -Nru a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/i2c/other/ak4xxx-adda.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,445 @@ +/* + * ALSA driver for AK4524 / AK4528 / AK4529 / AK4355 / AK4381 + * AD and DA converters + * + * Copyright (c) 2000-2003 Jaroslav Kysela <perex@suse.cz>, + * Takashi Iwai <tiwai@suse.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <sound/driver.h> +#include <asm/io.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <sound/core.h> +#include <sound/control.h> +#include <sound/ak4xxx-adda.h> + +MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>, Takashi Iwai <tiwai@suse.de>"); +MODULE_DESCRIPTION("Routines for control of AK452x / AK43xx AD/DA converters"); +MODULE_LICENSE("GPL"); + +void snd_akm4xxx_write(akm4xxx_t *ak, int chip, unsigned char reg, unsigned char val) +{ + ak->ops.lock(ak, chip); + ak->ops.write(ak, chip, reg, val); + + /* save the data */ + if (ak->type == SND_AK4524 || ak->type == SND_AK4528) { + if ((reg != 0x04 && reg != 0x05) || (reg & 0x80) == 0) + snd_akm4xxx_set(ak, chip, reg, val); + else + snd_akm4xxx_set_ipga(ak, chip, reg, val); + } else { + /* AK4529, or else */ + snd_akm4xxx_set(ak, chip, reg, val); + } + ak->ops.unlock(ak, chip); +} + +/* + * reset the AKM codecs + * @state: 1 = reset codec, 0 = restore the registers + * + * assert the reset operation and restores the register values to the chips. + */ +void snd_akm4xxx_reset(akm4xxx_t *ak, int state) +{ + unsigned int chip; + unsigned char reg; + + switch (ak->type) { + case SND_AK4524: + case SND_AK4528: + for (chip = 0; chip < ak->num_dacs/2; chip++) { + snd_akm4xxx_write(ak, chip, 0x01, state ? 0x00 : 0x03); + if (state) + continue; + /* DAC volumes */ + for (reg = 0x04; reg < (ak->type == SND_AK4528 ? 0x06 : 0x08); reg++) + snd_akm4xxx_write(ak, chip, reg, snd_akm4xxx_get(ak, chip, reg)); + if (ak->type == SND_AK4528) + continue; + /* IPGA */ + for (reg = 0x04; reg < 0x06; reg++) + snd_akm4xxx_write(ak, chip, reg, snd_akm4xxx_get_ipga(ak, chip, reg)); + } + break; + case SND_AK4529: + /* FIXME: needed for ak4529? */ + break; + case SND_AK4355: + snd_akm4xxx_write(ak, 0, 0x01, state ? 0x02 : 0x01); + if (state) + return; + for (reg = 0x00; reg < 0x0a; reg++) + if (reg != 0x01) + snd_akm4xxx_write(ak, 0, reg, snd_akm4xxx_get(ak, 0, reg)); + break; + case SND_AK4381: + for (chip = 0; chip < ak->num_dacs/2; chip++) { + snd_akm4xxx_write(ak, chip, 0x00, state ? 0x0c : 0x0f); + if (state) + continue; + for (reg = 0x01; reg < 0x05; reg++) + snd_akm4xxx_write(ak, chip, reg, snd_akm4xxx_get(ak, chip, reg)); + } + break; + } +} + +/* + * initialize all the ak4xxx chips + */ +void snd_akm4xxx_init(akm4xxx_t *ak) +{ + static unsigned char inits_ak4524[] = { + 0x00, 0x07, /* 0: all power up */ + 0x01, 0x00, /* 1: ADC/DAC reset */ + 0x02, 0x60, /* 2: 24bit I2S */ + 0x03, 0x19, /* 3: deemphasis off */ + 0x01, 0x03, /* 1: ADC/DAC enable */ + 0x04, 0x00, /* 4: ADC left muted */ + 0x05, 0x00, /* 5: ADC right muted */ + 0x04, 0x80, /* 4: ADC IPGA gain 0dB */ + 0x05, 0x80, /* 5: ADC IPGA gain 0dB */ + 0x06, 0x00, /* 6: DAC left muted */ + 0x07, 0x00, /* 7: DAC right muted */ + 0xff, 0xff + }; + static unsigned char inits_ak4528[] = { + 0x00, 0x07, /* 0: all power up */ + 0x01, 0x00, /* 1: ADC/DAC reset */ + 0x02, 0x60, /* 2: 24bit I2S */ + 0x03, 0x0d, /* 3: deemphasis off, turn LR highpass filters on */ + 0x01, 0x03, /* 1: ADC/DAC enable */ + 0x04, 0x00, /* 4: ADC left muted */ + 0x05, 0x00, /* 5: ADC right muted */ + 0xff, 0xff + }; + static unsigned char inits_ak4529[] = { + 0x09, 0x01, /* 9: ATS=0, RSTN=1 */ + 0x0a, 0x3f, /* A: all power up, no zero/overflow detection */ + 0x00, 0x0c, /* 0: TDM=0, 24bit I2S, SMUTE=0 */ + 0x01, 0x00, /* 1: ACKS=0, ADC, loop off */ + 0x02, 0xff, /* 2: LOUT1 muted */ + 0x03, 0xff, /* 3: ROUT1 muted */ + 0x04, 0xff, /* 4: LOUT2 muted */ + 0x05, 0xff, /* 5: ROUT2 muted */ + 0x06, 0xff, /* 6: LOUT3 muted */ + 0x07, 0xff, /* 7: ROUT3 muted */ + 0x0b, 0xff, /* B: LOUT4 muted */ + 0x0c, 0xff, /* C: ROUT4 muted */ + 0x08, 0x55, /* 8: deemphasis all off */ + 0xff, 0xff + }; + static unsigned char inits_ak4355[] = { + 0x01, 0x02, /* 1: reset and soft-mute */ + 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect, disable DZF, sharp roll-off, RSTN#=0 */ + // 0x02, 0x0e, /* 2: DA's power up, normal speed, RSTN#=0 */ + 0x02, 0x2e, + 0x03, 0x01, /* 3: de-emphasis off */ + 0x04, 0x00, /* 4: LOUT1 volume muted */ + 0x05, 0x00, /* 5: ROUT1 volume muted */ + 0x06, 0x00, /* 6: LOUT2 volume muted */ + 0x07, 0x00, /* 7: ROUT2 volume muted */ + 0x08, 0x00, /* 8: LOUT3 volume muted */ + 0x09, 0x00, /* 9: ROUT3 volume muted */ + 0x0a, 0x00, /* a: DATT speed=0, ignore DZF */ + 0x01, 0x01, /* 1: un-reset, unmute */ + 0xff, 0xff + }; + static unsigned char inits_ak4381[] = { + 0x00, 0x0c, /* 0: mode3(i2s), disable auto-clock detect */ + // 0x01, 0x02, /* 1: de-emphasis off, normal speed, sharp roll-off, DZF off */ + 0x01, 0x12, + 0x02, 0x00, /* 2: DZF disabled */ + 0x03, 0x00, /* 3: LATT 0 */ + 0x04, 0x00, /* 4: RATT 0 */ + 0x00, 0x0f, /* 0: power-up, un-reset */ + 0xff, 0xff + }; + + int chip, num_chips; + unsigned char *ptr, reg, data, *inits; + + switch (ak->type) { + case SND_AK4524: + inits = inits_ak4524; + num_chips = ak->num_dacs / 2; + break; + case SND_AK4528: + inits = inits_ak4528; + num_chips = ak->num_dacs / 2; + break; + case SND_AK4529: + inits = inits_ak4529; + num_chips = 1; + break; + case SND_AK4355: + inits = inits_ak4355; + num_chips = 1; + break; + case SND_AK4381: + inits = inits_ak4381; + num_chips = ak->num_dacs / 2; + break; + default: + snd_BUG(); + return; + } + + for (chip = 0; chip < num_chips; chip++) { + ptr = inits; + while (*ptr != 0xff) { + reg = *ptr++; + data = *ptr++; + snd_akm4xxx_write(ak, chip, reg, data); + } + } +} + +#define AK_GET_CHIP(val) (((val) >> 8) & 0xff) +#define AK_GET_ADDR(val) ((val) & 0xff) +#define AK_GET_SHIFT(val) (((val) >> 16) & 0x7f) +#define AK_GET_INVERT(val) (((val) >> 23) & 1) +#define AK_GET_MASK(val) (((val) >> 24) & 0xff) +#define AK_COMPOSE(chip,addr,shift,mask) (((chip) << 8) | (addr) | ((shift) << 16) | ((mask) << 24)) +#define AK_INVERT (1<<23) + +static int snd_akm4xxx_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + unsigned int mask = AK_GET_MASK(kcontrol->private_value); + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = mask; + return 0; +} + +static int snd_akm4xxx_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + akm4xxx_t *ak = _snd_kcontrol_chip(kcontrol); + int chip = AK_GET_CHIP(kcontrol->private_value); + int addr = AK_GET_ADDR(kcontrol->private_value); + int invert = AK_GET_INVERT(kcontrol->private_value); + unsigned int mask = AK_GET_MASK(kcontrol->private_value); + unsigned char val = snd_akm4xxx_get(ak, chip, addr); + + ucontrol->value.integer.value[0] = invert ? mask - val : val; + return 0; +} + +static int snd_akm4xxx_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + akm4xxx_t *ak = _snd_kcontrol_chip(kcontrol); + int chip = AK_GET_CHIP(kcontrol->private_value); + int addr = AK_GET_ADDR(kcontrol->private_value); + int invert = AK_GET_INVERT(kcontrol->private_value); + unsigned int mask = AK_GET_MASK(kcontrol->private_value); + unsigned char nval = ucontrol->value.integer.value[0] % (mask+1); + int change; + + if (invert) + nval = mask - nval; + change = snd_akm4xxx_get(ak, chip, addr) != nval; + if (change) + snd_akm4xxx_write(ak, chip, addr, nval); + return change; +} + +static int snd_akm4xxx_ipga_gain_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 36; + return 0; +} + +static int snd_akm4xxx_ipga_gain_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + akm4xxx_t *ak = _snd_kcontrol_chip(kcontrol); + int chip = AK_GET_CHIP(kcontrol->private_value); + int addr = AK_GET_ADDR(kcontrol->private_value); + ucontrol->value.integer.value[0] = snd_akm4xxx_get_ipga(ak, chip, addr) & 0x7f; + return 0; +} + +static int snd_akm4xxx_ipga_gain_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + akm4xxx_t *ak = _snd_kcontrol_chip(kcontrol); + int chip = AK_GET_CHIP(kcontrol->private_value); + int addr = AK_GET_ADDR(kcontrol->private_value); + unsigned char nval = (ucontrol->value.integer.value[0] % 37) | 0x80; + int change = snd_akm4xxx_get_ipga(ak, chip, addr) != nval; + if (change) + snd_akm4xxx_write(ak, chip, addr, nval); + return change; +} + +static int snd_akm4xxx_deemphasis_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + static char *texts[4] = { + "44.1kHz", "Off", "48kHz", "32kHz", + }; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = 4; + if (uinfo->value.enumerated.item >= 4) + uinfo->value.enumerated.item = 3; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int snd_akm4xxx_deemphasis_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + akm4xxx_t *ak = _snd_kcontrol_chip(kcontrol); + int chip = AK_GET_CHIP(kcontrol->private_value); + int addr = AK_GET_ADDR(kcontrol->private_value); + int shift = AK_GET_SHIFT(kcontrol->private_value); + ucontrol->value.enumerated.item[0] = (snd_akm4xxx_get(ak, chip, addr) >> shift) & 3; + return 0; +} + +static int snd_akm4xxx_deemphasis_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + akm4xxx_t *ak = _snd_kcontrol_chip(kcontrol); + int chip = AK_GET_CHIP(kcontrol->private_value); + int addr = AK_GET_ADDR(kcontrol->private_value); + int shift = AK_GET_SHIFT(kcontrol->private_value); + unsigned char nval = ucontrol->value.enumerated.item[0] & 3; + int change; + + nval = (nval << shift) | (snd_akm4xxx_get(ak, chip, addr) & ~(3 << shift)); + change = snd_akm4xxx_get(ak, chip, addr) != nval; + if (change) + snd_akm4xxx_write(ak, chip, addr, nval); + return change; +} + +/* + * build AK4xxx controls + */ + +int snd_akm4xxx_build_controls(akm4xxx_t *ak) +{ + unsigned int idx; + int err; + + for (idx = 0; idx < ak->num_dacs; ++idx) { + snd_kcontrol_t ctl; + memset(&ctl, 0, sizeof(ctl)); + strcpy(ctl.id.name, "DAC Volume"); + ctl.id.index = idx + ak->idx_offset * 2; + ctl.id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + ctl.count = 1; + ctl.info = snd_akm4xxx_volume_info; + ctl.get = snd_akm4xxx_volume_get; + ctl.put = snd_akm4xxx_volume_put; + switch (ak->type) { + case SND_AK4524: + ctl.private_value = AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127); /* register 6 & 7 */ + break; + case SND_AK4528: + ctl.private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127); /* register 4 & 5 */ + break; + case SND_AK4529: { + int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb; /* registers 2-7 and b,c */ + ctl.private_value = AK_COMPOSE(0, val, 0, 255) | AK_INVERT; + break; + } + case SND_AK4355: + ctl.private_value = AK_COMPOSE(0, idx + 4, 0, 255); /* register 4-9, chip #0 only */ + break; + case SND_AK4381: + ctl.private_value = AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255); /* register 3 & 4 */ + break; + default: + return -EINVAL; + } + ctl.private_data = ak; + if ((err = snd_ctl_add(ak->card, snd_ctl_new(&ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0) + return err; + } + for (idx = 0; idx < ak->num_adcs && ak->type == SND_AK4524; ++idx) { + snd_kcontrol_t ctl; + memset(&ctl, 0, sizeof(ctl)); + strcpy(ctl.id.name, "ADC Volume"); + ctl.id.index = idx; + ctl.id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + ctl.count = 1; + ctl.info = snd_akm4xxx_volume_info; + ctl.get = snd_akm4xxx_volume_get; + ctl.put = snd_akm4xxx_volume_put; + ctl.private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127); /* register 4 & 5 */ + ctl.private_data = ak; + if ((err = snd_ctl_add(ak->card, snd_ctl_new(&ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0) + return err; + memset(&ctl, 0, sizeof(ctl)); + strcpy(ctl.id.name, "IPGA Analog Capture Volume"); + ctl.id.index = idx; + ctl.id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + ctl.count = 1; + ctl.info = snd_akm4xxx_ipga_gain_info; + ctl.get = snd_akm4xxx_ipga_gain_get; + ctl.put = snd_akm4xxx_ipga_gain_put; + ctl.private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 0); /* register 4 & 5 */ + ctl.private_data = ak; + if ((err = snd_ctl_add(ak->card, snd_ctl_new(&ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0) + return err; + } + for (idx = 0; idx < ak->num_dacs/2; idx++) { + snd_kcontrol_t ctl; + memset(&ctl, 0, sizeof(ctl)); + strcpy(ctl.id.name, "Deemphasis"); + ctl.id.index = idx + ak->idx_offset; + ctl.id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + ctl.count = 1; + ctl.info = snd_akm4xxx_deemphasis_info; + ctl.get = snd_akm4xxx_deemphasis_get; + ctl.put = snd_akm4xxx_deemphasis_put; + switch (ak->type) { + case SND_AK4524: + case SND_AK4528: + ctl.private_value = AK_COMPOSE(idx, 3, 0, 0); /* register 3 */ + break; + case SND_AK4529: { + int shift = idx == 3 ? 6 : (2 - idx) * 2; + ctl.private_value = AK_COMPOSE(0, 8, shift, 0); /* register 8 with shift */ + break; + } + case SND_AK4355: + ctl.private_value = AK_COMPOSE(idx, 3, 0, 0); + break; + case SND_AK4381: + ctl.private_value = AK_COMPOSE(idx, 1, 1, 0); + break; + } + ctl.private_data = ak; + if ((err = snd_ctl_add(ak->card, snd_ctl_new(&ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0) + return err; + } + return 0; +} + +EXPORT_SYMBOL(snd_akm4xxx_write); +EXPORT_SYMBOL(snd_akm4xxx_reset); +EXPORT_SYMBOL(snd_akm4xxx_init); +EXPORT_SYMBOL(snd_akm4xxx_build_controls); diff -Nru a/sound/isa/Kconfig b/sound/isa/Kconfig --- a/sound/isa/Kconfig Mon Jun 9 23:16:18 2003 +++ b/sound/isa/Kconfig Mon Jun 9 23:16:18 2003 @@ -41,7 +41,7 @@ config SND_PC98_CS4232 tristate "NEC PC9800 CS4232 driver" - depends on SND && PC9800 + depends on SND && X86_PC9800 help Say 'Y' or 'M' to include support for NEC PC-9801/PC-9821 on-board soundchip based on CS4232. @@ -191,5 +191,11 @@ help Say 'Y' or 'M' to include support for Aztech Sound Galaxy. -endmenu +config SND_SSCAPE + tristate "Ensoniq SoundScape PnP driver" + depends on SND + help + Say 'Y' or 'M' to include support for Ensoniq SoundScape PnP + soundcard. +endmenu diff -Nru a/sound/isa/Makefile b/sound/isa/Makefile --- a/sound/isa/Makefile Mon Jun 9 23:16:08 2003 +++ b/sound/isa/Makefile Mon Jun 9 23:16:08 2003 @@ -10,6 +10,7 @@ snd-es18xx-objs := es18xx.o snd-opl3sa2-objs := opl3sa2.o snd-sgalaxy-objs := sgalaxy.o +snd-sscape-objs := sscape.o # Toplevel Module Dependency obj-$(CONFIG_SND_ALS100) += snd-als100.o @@ -19,6 +20,7 @@ obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o obj-$(CONFIG_SND_SGALAXY) += snd-sgalaxy.o +obj-$(CONFIG_SND_SSCAPE) += snd-sscape.o obj-$(CONFIG_SND) += ad1816a/ ad1848/ cs423x/ es1688/ gus/ opti9xx/ \ sb/ wavefront/ diff -Nru a/sound/isa/ad1816a/ad1816a.c b/sound/isa/ad1816a/ad1816a.c --- a/sound/isa/ad1816a/ad1816a.c Mon Jun 9 23:16:08 2003 +++ b/sound/isa/ad1816a/ad1816a.c Mon Jun 9 23:16:08 2003 @@ -307,8 +307,10 @@ cards += pnp_register_card_driver(&ad1816a_pnpc_driver); #ifdef MODULE - if (!cards) + if (!cards) { + pnp_unregister_card_driver(&ad1816a_pnpc_driver); printk(KERN_ERR "no AD1816A based soundcards found.\n"); + } #endif /* MODULE */ return cards ? 0 : -ENODEV; } diff -Nru a/sound/isa/als100.c b/sound/isa/als100.c --- a/sound/isa/als100.c Mon Jun 9 23:16:07 2003 +++ b/sound/isa/als100.c Mon Jun 9 23:16:07 2003 @@ -328,8 +328,10 @@ cards += pnp_register_card_driver(&als100_pnpc_driver); #ifdef MODULE - if (!cards) + if (!cards) { + pnp_unregister_card_driver(&als100_pnpc_driver); snd_printk(KERN_ERR "no ALS100 based soundcards found\n"); + } #endif return cards ? 0 : -ENODEV; } diff -Nru a/sound/isa/azt2320.c b/sound/isa/azt2320.c --- a/sound/isa/azt2320.c Mon Jun 9 23:16:19 2003 +++ b/sound/isa/azt2320.c Mon Jun 9 23:16:19 2003 @@ -1,4 +1,3 @@ - /* card-azt2320.c - driver for Aztech Systems AZT2320 based soundcards. Copyright (C) 1999-2000 by Massimo Piccioni <dafastidio@libero.it> @@ -105,11 +104,9 @@ MODULE_PARM_SYNTAX(dma2, SNDRV_DMA_DESC); struct snd_card_azt2320 { -#ifdef CONFIG_PNP int dev_no; struct pnp_dev *dev; struct pnp_dev *devmpu; -#endif /* CONFIG_PNP */ }; static struct pnp_card_device_id snd_azt2320_pnpids[] __devinitdata = { @@ -365,8 +362,10 @@ cards += pnp_register_card_driver(&azt2320_pnpc_driver); #ifdef MODULE - if (!cards) + if (!cards) { + pnp_unregister_card_driver(&azt2320_pnpc_driver); snd_printk(KERN_ERR "no AZT2320 based soundcards found\n"); + } #endif return cards ? 0 : -ENODEV; } diff -Nru a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c --- a/sound/isa/cmi8330.c Mon Jun 9 23:16:07 2003 +++ b/sound/isa/cmi8330.c Mon Jun 9 23:16:07 2003 @@ -613,6 +613,9 @@ #endif if (!cards) { +#ifdef CONFIG_PNP + pnp_unregister_card_driver(&cmi8330_pnpc_driver); +#endif #ifdef MODULE snd_printk(KERN_ERR "CMI8330 not found or device busy\n"); #endif diff -Nru a/sound/isa/cs423x/Makefile b/sound/isa/cs423x/Makefile --- a/sound/isa/cs423x/Makefile Mon Jun 9 23:16:17 2003 +++ b/sound/isa/cs423x/Makefile Mon Jun 9 23:16:17 2003 @@ -21,6 +21,7 @@ obj-$(CONFIG_SND_INTERWAVE_STB) += snd-cs4231-lib.o obj-$(CONFIG_SND_OPTI92X_CS4231) += snd-cs4231-lib.o obj-$(CONFIG_SND_WAVEFRONT) += snd-cs4231-lib.o +obj-$(CONFIG_SND_SSCAPE) += snd-cs4231-lib.o obj-$(CONFIG_SND_PC98_CS4232) += snd-pc98-cs4232.o snd-cs4231-lib.o obj-m := $(sort $(obj-m)) diff -Nru a/sound/isa/cs423x/cs4231_lib.c b/sound/isa/cs423x/cs4231_lib.c --- a/sound/isa/cs423x/cs4231_lib.c Mon Jun 9 23:16:08 2003 +++ b/sound/isa/cs423x/cs4231_lib.c Mon Jun 9 23:16:08 2003 @@ -448,6 +448,7 @@ cs4231_t *chip = snd_pcm_substream_chip(substream); int result = 0; unsigned int what; + struct list_head *pos; snd_pcm_substream_t *s; int do_start; @@ -467,8 +468,8 @@ } what = 0; - s = substream; - do { + snd_pcm_group_for_each(pos, substream) { + s = snd_pcm_group_substream_entry(pos); if (s == chip->playback_substream) { what |= CS4231_PLAYBACK_ENABLE; snd_pcm_trigger_done(s, substream); @@ -476,8 +477,7 @@ what |= CS4231_RECORD_ENABLE; snd_pcm_trigger_done(s, substream); } - s = s->link_next; - } while (s != substream); + } spin_lock(&chip->reg_lock); if (do_start) { chip->image[CS4231_IFACE_CTRL] |= what; diff -Nru a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c --- a/sound/isa/cs423x/cs4236.c Mon Jun 9 23:16:07 2003 +++ b/sound/isa/cs423x/cs4236.c Mon Jun 9 23:16:07 2003 @@ -281,6 +281,9 @@ struct pnp_resource_table * cfg = kmalloc(sizeof(struct pnp_resource_table), GFP_KERNEL); int err; + if (!cfg) + return -ENOMEM; + acard->wss = pnp_request_card_device(card, id->devs[0].id, NULL); if (acard->wss == NULL) { kfree(cfg); @@ -365,7 +368,6 @@ snd_printk(KERN_ERR IDENT " MPU401 PnP manual resources are invalid, using auto config\n"); err = pnp_activate_dev(pdev); if (err < 0) { - kfree(cfg); printk(KERN_ERR IDENT " MPU401 PnP configure failed for WSS (out of resources?)\n"); mpu_port[dev] = SNDRV_AUTO_PORT; mpu_irq[dev] = SNDRV_AUTO_IRQ; @@ -382,7 +384,7 @@ kfree(cfg); return 0; } -#endif +#endif /* CONFIG_PNP */ static void snd_card_cs4236_free(snd_card_t *card) { @@ -590,6 +592,9 @@ cards += pnp_register_card_driver(&cs423x_pnpc_driver); #endif if (!cards) { +#ifdef CONFIG_PNP + pnp_unregister_card_driver(&cs423x_pnpc_driver); +#endif #ifdef MODULE printk(KERN_ERR IDENT " soundcard not found or device busy\n"); #endif diff -Nru a/sound/isa/dt019x.c b/sound/isa/dt019x.c --- a/sound/isa/dt019x.c Mon Jun 9 23:16:10 2003 +++ b/sound/isa/dt019x.c Mon Jun 9 23:16:10 2003 @@ -127,8 +127,7 @@ if (port[dev] != SNDRV_AUTO_PORT) pnp_resource_change(&cfg->port_resource[0], port[dev], 16); if (dma8[dev] != SNDRV_AUTO_DMA) - pnp_resource_change(&cfg->dma_resource[0], dma8[dev], - 1); + pnp_resource_change(&cfg->dma_resource[0], dma8[dev], 1); if (irq[dev] != SNDRV_AUTO_IRQ) pnp_resource_change(&cfg->irq_resource[0], irq[dev], 1); @@ -158,18 +157,17 @@ if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0) snd_printk(KERN_ERR PFX "DT-019X MPU401 the requested resources are invalid, using auto config\n"); err = pnp_activate_dev(pdev); - if (err < 0) + if (err < 0) { + pnp_release_card_device(pdev); + snd_printk(KERN_ERR PFX "DT-019X MPU401 pnp configure failure, skipping\n"); goto __mpu_error; + } mpu_port[dev] = pnp_port_start(pdev, 0); mpu_irq[dev] = pnp_irq(pdev, 0); snd_printdd("dt019x: found MPU-401: port=0x%lx, irq=0x%lx\n", mpu_port[dev],mpu_irq[dev]); } else { - __mpu_error: - if (pdev) { - pnp_release_card_device(pdev); - snd_printk(KERN_ERR PFX "DT-019X MPU401 pnp configure failure, skipping\n"); - } + __mpu_error: acard->devmpu = NULL; mpu_port[dev] = -1; } @@ -182,16 +180,15 @@ if ((pnp_manual_config_dev(pdev, cfg, 0)) < 0) snd_printk(KERN_ERR PFX "DT-019X OPL3 the requested resources are invalid, using auto config\n"); err = pnp_activate_dev(pdev); - if (err < 0) + if (err < 0) { + pnp_release_card_device(pdev); + snd_printk(KERN_ERR PFX "DT-019X OPL3 pnp configure failure, skipping\n"); goto __fm_error; + } fm_port[dev] = pnp_port_start(pdev, 0); snd_printdd("dt019x: found OPL3 synth: port=0x%lx\n",fm_port[dev]); } else { - __fm_error: - if (pdev) { - pnp_release_card_device(pdev); - snd_printk(KERN_ERR PFX "DT-019X OPL3 pnp configure failure, skipping\n"); - } + __fm_error: acard->devopl = NULL; fm_port[dev] = -1; } diff -Nru a/sound/isa/es18xx.c b/sound/isa/es18xx.c --- a/sound/isa/es18xx.c Mon Jun 9 23:16:10 2003 +++ b/sound/isa/es18xx.c Mon Jun 9 23:16:10 2003 @@ -2242,6 +2242,9 @@ cards += pnp_register_card_driver(&es18xx_pnpc_driver); #endif if(!cards) { +#ifdef CONFIG_PNP + pnp_unregister_card_driver(&es18xx_pnpc_driver); +#endif #ifdef MODULE snd_printk(KERN_ERR "ESS AudioDrive ES18xx soundcard not found or device busy\n"); #endif diff -Nru a/sound/isa/gus/gus_irq.c b/sound/isa/gus/gus_irq.c --- a/sound/isa/gus/gus_irq.c Mon Jun 9 23:16:18 2003 +++ b/sound/isa/gus/gus_irq.c Mon Jun 9 23:16:18 2003 @@ -32,8 +32,7 @@ irqreturn_t snd_gus_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - snd_gus_card_t * gus = snd_magic_cast(snd_gus_card_t, - dev_id, return IRQ_NONE); + snd_gus_card_t * gus = snd_magic_cast(snd_gus_card_t, dev_id, return IRQ_NONE); unsigned char status; int loop = 100; int handled = 0; diff -Nru a/sound/isa/gus/gus_synth.c b/sound/isa/gus/gus_synth.c --- a/sound/isa/gus/gus_synth.c Mon Jun 9 23:16:13 2003 +++ b/sound/isa/gus/gus_synth.c Mon Jun 9 23:16:13 2003 @@ -192,9 +192,6 @@ p->chset->port = snd_seq_event_port_attach(gus->gf1.seq_client, &callbacks, SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE, - SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | - SNDRV_SEQ_PORT_TYPE_MIDI_GM | - SNDRV_SEQ_PORT_TYPE_MIDI_GS | SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE | SNDRV_SEQ_PORT_TYPE_SYNTH, 16, 0, diff -Nru a/sound/isa/gus/interwave.c b/sound/isa/gus/interwave.c --- a/sound/isa/gus/interwave.c Mon Jun 9 23:16:13 2003 +++ b/sound/isa/gus/interwave.c Mon Jun 9 23:16:13 2003 @@ -949,6 +949,9 @@ #endif if (!cards) { +#ifdef CONFIG_PNP + pnp_unregister_card_driver(&interwave_pnpc_driver); +#endif #ifdef MODULE printk(KERN_ERR "InterWave soundcard not found or device busy\n"); #endif diff -Nru a/sound/isa/opl3sa2.c b/sound/isa/opl3sa2.c --- a/sound/isa/opl3sa2.c Mon Jun 9 23:16:19 2003 +++ b/sound/isa/opl3sa2.c Mon Jun 9 23:16:19 2003 @@ -645,6 +645,7 @@ pnp_init_resource_table(cfg); if (sb_port[dev] != SNDRV_AUTO_PORT) pnp_resource_change(&cfg->port_resource[0], sb_port[dev], 16); + if (wss_port[dev] != SNDRV_AUTO_PORT) pnp_resource_change(&cfg->port_resource[1], wss_port[dev], 8); if (fm_port[dev] != SNDRV_AUTO_PORT) pnp_resource_change(&cfg->port_resource[2], fm_port[dev], 4); @@ -664,7 +665,7 @@ err = pnp_activate_dev(pdev); if (err < 0) { kfree(cfg); - snd_printk(KERN_ERR "PnP configure failure (out of resources?)\n"); + snd_printk(KERN_ERR "PnP configure failure (out of resources?) err = %d\n", err); return -EBUSY; } sb_port[dev] = pnp_port_start(pdev, 0); @@ -902,6 +903,9 @@ if (!cards) { #ifdef MODULE snd_printk(KERN_ERR "Yamaha OPL3-SA soundcard not found or device busy\n"); +#endif +#ifdef CONFIG_PNP + pnp_unregister_card_driver(&opl3sa2_pnpc_driver); #endif return -ENODEV; } diff -Nru a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c --- a/sound/isa/opti9xx/opti92x-ad1848.c Mon Jun 9 23:16:08 2003 +++ b/sound/isa/opti9xx/opti92x-ad1848.c Mon Jun 9 23:16:08 2003 @@ -43,10 +43,8 @@ #endif /* CS4231 */ #include <sound/mpu401.h> #include <sound/opl3.h> -#ifdef USE_OPL4 #ifndef OPTi93X -#include "opl4.h" /* <sound/opl4.h> */ -#endif +#include <sound/opl4.h> #endif #define SNDRV_LEGACY_FIND_FREE_IRQ #define SNDRV_LEGACY_FIND_FREE_DMA @@ -279,13 +277,6 @@ #ifdef CONFIG_PNP -#define ISAPNP_OPTI9XX(_va, _vb, _vc, _device, _fa, _fb, _fc, _audio, _mpu401) \ - { \ - ISAPNP_CARD_ID(_va, _vb, _vc, _device), \ - .devs = { ISAPNP_DEVICE_ID(_fa, _fb, _fc, _audio), \ - ISAPNP_DEVICE_ID(_fa, _fb, _fc, _mpu401), } \ - } - static struct pnp_card_device_id snd_opti9xx_pnpids[] = { #ifndef OPTi93X /* OPTi 82C924 */ @@ -969,8 +960,10 @@ case SNDRV_PCM_TRIGGER_STOP: { unsigned int what = 0; - snd_pcm_substream_t *s = substream; - do { + struct list_head *pos; + snd_pcm_substream_t *s; + snd_pcm_group_for_each(pos, substream) { + s = snd_pcm_group_substream_entry(pos); if (s == chip->playback_substream) { what |= OPTi93X_PLAYBACK_ENABLE; snd_pcm_trigger_done(s, substream); @@ -978,8 +971,7 @@ what |= OPTi93X_CAPTURE_ENABLE; snd_pcm_trigger_done(s, substream); } - s = s->link_next; - } while (s != substream); + } spin_lock(&chip->lock); if (cmd == SNDRV_PCM_TRIGGER_START) { snd_opti93x_out_mask(chip, OPTi93X_IFACE_CONF, what, what); @@ -1946,7 +1938,7 @@ chip = (opti9xx_t *)card->private_data; #ifdef CONFIG_PNP - if (isapnp && (hw = snd_card_opti9xx_pnp(chip, pcard, pid)) > 0) { + if (isapnp && pcard && (hw = snd_card_opti9xx_pnp(chip, pcard, pid)) > 0) { switch (hw) { case 0x0924: hw = OPTi9XX_HW_82C924; @@ -2111,7 +2103,6 @@ if (chip->fm_port > 0) { opl3_t *opl3 = NULL; -#ifdef USE_OPL4 #ifndef OPTi93X if (chip->hardware == OPTi9XX_HW_82C928 || chip->hardware == OPTi9XX_HW_82C929 || @@ -2130,7 +2121,6 @@ } } #endif /* !OPTi93X */ -#endif if (!opl3 && snd_opl3_create(card, chip->fm_port, chip->fm_port + 2, @@ -2201,8 +2191,15 @@ { int cards, error; +#ifdef CONFIG_PNP cards = pnp_register_card_driver(&opti9xx_pnpc_driver); +#else + cards = 0; +#endif if (cards == 0 && (error = snd_card_opti9xx_probe(NULL, NULL)) < 0) { +#ifdef CONFIG_PNP + pnp_unregister_card_driver(&opti9xx_pnpc_driver); +#endif #ifdef MODULE #ifdef OPTi93X printk(KERN_ERR "no OPTi 82C93x soundcard found\n"); diff -Nru a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c --- a/sound/isa/sb/emu8000.c Mon Jun 9 23:16:10 2003 +++ b/sound/isa/sb/emu8000.c Mon Jun 9 23:16:10 2003 @@ -1144,6 +1144,8 @@ strcpy(awe->name, "EMU-8000"); *(emu8000_t**)SNDRV_SEQ_DEVICE_ARGPTR(awe) = hw; } +#else + awe = NULL; #endif if (awe_ret) *awe_ret = awe; diff -Nru a/sound/isa/sb/es968.c b/sound/isa/sb/es968.c --- a/sound/isa/sb/es968.c Mon Jun 9 23:16:12 2003 +++ b/sound/isa/sb/es968.c Mon Jun 9 23:16:12 2003 @@ -79,16 +79,15 @@ #define DRIVER_NAME "snd-card-es968" static irqreturn_t snd_card_es968_interrupt(int irq, void *dev_id, - struct pt_regs *regs) + struct pt_regs *regs) { sb_t *chip = snd_magic_cast(sb_t, dev_id, return IRQ_NONE); if (chip->open & SB_OPEN_PCM) { - snd_sb8dsp_interrupt(chip); + return snd_sb8dsp_interrupt(chip); } else { - snd_sb8dsp_midi_interrupt(chip); + return snd_sb8dsp_midi_interrupt(chip); } - return IRQ_HANDLED; } static int __devinit snd_card_es968_pnp(int dev, struct snd_card_es968 *acard, @@ -122,6 +121,7 @@ err = pnp_activate_dev(pdev); if (err < 0) { snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n"); + kfree(cfg); return err; } port[dev] = pnp_port_start(pdev, 0); @@ -225,10 +225,13 @@ static int __init alsa_card_es968_init(void) { int res = pnp_register_card_driver(&es968_pnpc_driver); -#ifdef MODULE if (res == 0) + { + pnp_unregister_card_driver(&es968_pnpc_driver); +#ifdef MODULE snd_printk(KERN_ERR "no ES968 based soundcards found\n"); #endif + } return res < 0 ? res : 0; } diff -Nru a/sound/isa/sb/sb16.c b/sound/isa/sb/sb16.c --- a/sound/isa/sb/sb16.c Mon Jun 9 23:16:17 2003 +++ b/sound/isa/sb/sb16.c Mon Jun 9 23:16:17 2003 @@ -256,6 +256,8 @@ #define DRIVER_NAME "snd-card-sb16" #endif +#ifdef CONFIG_PNP + static int __devinit snd_card_sb16_pnp(int dev, struct snd_card_sb16 *acard, struct pnp_card_link *card, const struct pnp_card_device_id *id) @@ -346,6 +348,8 @@ return 0; } +#endif /* CONFIG_PNP */ + static int __init snd_sb16_probe(int dev, struct pnp_card_link *pcard, const struct pnp_card_device_id *pid) @@ -370,12 +374,14 @@ if (card == NULL) return -ENOMEM; acard = (struct snd_card_sb16 *) card->private_data; +#ifdef CONFIG_PNP if (isapnp[dev]) { if ((err = snd_card_sb16_pnp(dev, acard, pcard, pid))) { snd_card_free(card); return err; } } +#endif xirq = irq[dev]; xdma8 = dma8[dev]; @@ -625,6 +631,9 @@ #endif if (!cards) { +#ifdef CONFIG_PNP + pnp_unregister_card_driver(&sb16_pnpc_driver); +#endif #ifdef MODULE snd_printk(KERN_ERR "Sound Blaster 16 soundcard not found or device busy\n"); #ifdef SNDRV_SBAWE_EMU8000 diff -Nru a/sound/isa/sb/sb8.c b/sound/isa/sb/sb8.c --- a/sound/isa/sb/sb8.c Mon Jun 9 23:16:15 2003 +++ b/sound/isa/sb/sb8.c Mon Jun 9 23:16:15 2003 @@ -75,11 +75,10 @@ sb_t *chip = snd_magic_cast(sb_t, dev_id, return IRQ_NONE); if (chip->open & SB_OPEN_PCM) { - snd_sb8dsp_interrupt(chip); + return snd_sb8dsp_interrupt(chip); } else { - snd_sb8dsp_midi_interrupt(chip); + return snd_sb8dsp_midi_interrupt(chip); } - return IRQ_HANDLED; } static void snd_sb8_free(snd_card_t *card) diff -Nru a/sound/isa/sb/sb8_main.c b/sound/isa/sb/sb8_main.c --- a/sound/isa/sb/sb8_main.c Mon Jun 9 23:16:10 2003 +++ b/sound/isa/sb/sb8_main.c Mon Jun 9 23:16:10 2003 @@ -331,7 +331,7 @@ return 0; } -void snd_sb8dsp_interrupt(sb_t *chip) +irqreturn_t snd_sb8dsp_interrupt(sb_t *chip) { snd_pcm_substream_t *substream; snd_pcm_runtime_t *runtime; @@ -356,6 +356,7 @@ snd_pcm_period_elapsed(substream); break; } + return IRQ_HANDLED; } static snd_pcm_uframes_t snd_sb8_playback_pointer(snd_pcm_substream_t * substream) diff -Nru a/sound/isa/sb/sb8_midi.c b/sound/isa/sb/sb8_midi.c --- a/sound/isa/sb/sb8_midi.c Mon Jun 9 23:16:06 2003 +++ b/sound/isa/sb/sb8_midi.c Mon Jun 9 23:16:06 2003 @@ -21,6 +21,9 @@ * Sun May 9 22:54:38 BST 1999 George David Morrison <gdm@gedamo.demon.co.uk> * Fixed typo in snd_sb8dsp_midi_new_device which prevented midi from * working. + * + * Sun May 11 12:34:56 UTC 2003 Clemens Ladisch <clemens@ladisch.de> + * Added full duplex UART mode for DSP version 2.0 and later. */ #include <sound/driver.h> @@ -33,26 +36,31 @@ */ -void snd_sb8dsp_midi_interrupt(sb_t * chip) +irqreturn_t snd_sb8dsp_midi_interrupt(sb_t * chip) { snd_rawmidi_t *rmidi; int max = 64; char byte; if (chip == NULL || (rmidi = chip->rmidi) == NULL) { - inb(SBP(chip, READ)); /* ack interrupt */ - return; + inb(SBP(chip, DATA_AVAIL)); /* ack interrupt */ + return IRQ_NONE; } while (max-- > 0) { spin_lock(&chip->midi_input_lock); if (inb(SBP(chip, DATA_AVAIL)) & 0x80) { byte = inb(SBP(chip, READ)); - spin_unlock(&chip->midi_input_lock); - snd_rawmidi_receive(chip->midi_substream_input, &byte, 1); + if (chip->open & SB_OPEN_MIDI_INPUT_TRIGGER) { + spin_unlock(&chip->midi_input_lock); + snd_rawmidi_receive(chip->midi_substream_input, &byte, 1); + } else { + spin_unlock(&chip->midi_input_lock); + } } else { spin_unlock(&chip->midi_input_lock); } } + return IRQ_HANDLED; } /* @@ -63,10 +71,13 @@ { unsigned long flags; sb_t *chip; + unsigned int valid_open_flags; chip = snd_magic_cast(sb_t, substream->rmidi->private_data, return -ENXIO); + valid_open_flags = chip->hardware >= SB_HW_20 + ? SB_OPEN_MIDI_OUTPUT | SB_OPEN_MIDI_OUTPUT_TRIGGER : 0; spin_lock_irqsave(&chip->open_lock, flags); - if (chip->open) { + if (chip->open & ~valid_open_flags) { spin_unlock_irqrestore(&chip->open_lock, flags); return -EAGAIN; } @@ -75,6 +86,8 @@ if (!(chip->open & SB_OPEN_MIDI_OUTPUT)) { spin_unlock_irqrestore(&chip->open_lock, flags); snd_sbdsp_reset(chip); /* reset DSP */ + if (chip->hardware >= SB_HW_20) + snd_sbdsp_command(chip, SB_DSP_MIDI_UART_IRQ); } else { spin_unlock_irqrestore(&chip->open_lock, flags); } @@ -85,10 +98,13 @@ { unsigned long flags; sb_t *chip; + unsigned int valid_open_flags; chip = snd_magic_cast(sb_t, substream->rmidi->private_data, return -ENXIO); + valid_open_flags = chip->hardware >= SB_HW_20 + ? SB_OPEN_MIDI_INPUT | SB_OPEN_MIDI_INPUT_TRIGGER : 0; spin_lock_irqsave(&chip->open_lock, flags); - if (chip->open) { + if (chip->open & ~valid_open_flags) { spin_unlock_irqrestore(&chip->open_lock, flags); return -EAGAIN; } @@ -97,6 +113,8 @@ if (!(chip->open & SB_OPEN_MIDI_INPUT)) { spin_unlock_irqrestore(&chip->open_lock, flags); snd_sbdsp_reset(chip); /* reset DSP */ + if (chip->hardware >= SB_HW_20) + snd_sbdsp_command(chip, SB_DSP_MIDI_UART_IRQ); } else { spin_unlock_irqrestore(&chip->open_lock, flags); } @@ -110,7 +128,7 @@ chip = snd_magic_cast(sb_t, substream->rmidi->private_data, return -ENXIO); spin_lock_irqsave(&chip->open_lock, flags); - chip->open &= ~(SB_OPEN_MIDI_INPUT | SB_OPEN_MIDI_TRIGGER); + chip->open &= ~(SB_OPEN_MIDI_INPUT | SB_OPEN_MIDI_INPUT_TRIGGER); chip->midi_substream_input = NULL; if (!(chip->open & SB_OPEN_MIDI_OUTPUT)) { spin_unlock_irqrestore(&chip->open_lock, flags); @@ -128,7 +146,7 @@ chip = snd_magic_cast(sb_t, substream->rmidi->private_data, return -ENXIO); spin_lock_irqsave(&chip->open_lock, flags); - chip->open &= ~SB_OPEN_MIDI_OUTPUT; + chip->open &= ~(SB_OPEN_MIDI_OUTPUT | SB_OPEN_MIDI_OUTPUT_TRIGGER); chip->midi_substream_output = NULL; if (!(chip->open & SB_OPEN_MIDI_INPUT)) { spin_unlock_irqrestore(&chip->open_lock, flags); @@ -147,14 +165,16 @@ chip = snd_magic_cast(sb_t, substream->rmidi->private_data, return); spin_lock_irqsave(&chip->open_lock, flags); if (up) { - if (!(chip->open & SB_OPEN_MIDI_TRIGGER)) { - snd_sbdsp_command(chip, SB_DSP_MIDI_INPUT_IRQ); - chip->open |= SB_OPEN_MIDI_TRIGGER; + if (!(chip->open & SB_OPEN_MIDI_INPUT_TRIGGER)) { + if (chip->hardware < SB_HW_20) + snd_sbdsp_command(chip, SB_DSP_MIDI_INPUT_IRQ); + chip->open |= SB_OPEN_MIDI_INPUT_TRIGGER; } } else { - if (chip->open & SB_OPEN_MIDI_TRIGGER) { - snd_sbdsp_command(chip, SB_DSP_MIDI_INPUT_IRQ); - chip->open &= ~SB_OPEN_MIDI_TRIGGER; + if (chip->open & SB_OPEN_MIDI_INPUT_TRIGGER) { + if (chip->hardware < SB_HW_20) + snd_sbdsp_command(chip, SB_DSP_MIDI_INPUT_IRQ); + chip->open &= ~SB_OPEN_MIDI_INPUT_TRIGGER; } } spin_unlock_irqrestore(&chip->open_lock, flags); @@ -171,14 +191,27 @@ chip = snd_magic_cast(sb_t, substream->rmidi->private_data, return); while (max-- > 0) { spin_lock_irqsave(&chip->open_lock, flags); - if (snd_rawmidi_transmit(substream, &byte, 1) != 1) { - chip->open &= ~SB_OPEN_MIDI_TRIGGER; + if (snd_rawmidi_transmit_peek(substream, &byte, 1) != 1) { + chip->open &= ~SB_OPEN_MIDI_OUTPUT_TRIGGER; del_timer(&chip->midi_timer); spin_unlock_irqrestore(&chip->open_lock, flags); - return; + break; + } + if (chip->hardware >= SB_HW_20) { + int timeout = 8; + while ((inb(SBP(chip, STATUS)) & 0x80) != 0 && --timeout > 0) + ; + if (timeout == 0) { + /* Tx FIFO full - try again later */ + spin_unlock_irqrestore(&chip->open_lock, flags); + break; + } + outb(byte, SBP(chip, WRITE)); + } else { + snd_sbdsp_command(chip, SB_DSP_MIDI_OUTPUT); + snd_sbdsp_command(chip, byte); } - snd_sbdsp_command(chip, SB_DSP_MIDI_OUTPUT); - snd_sbdsp_command(chip, byte); + snd_rawmidi_transmit_ack(substream, 1); spin_unlock_irqrestore(&chip->open_lock, flags); } } @@ -204,17 +237,17 @@ chip = snd_magic_cast(sb_t, substream->rmidi->private_data, return); spin_lock_irqsave(&chip->open_lock, flags); if (up) { - if (!(chip->open & SB_OPEN_MIDI_TRIGGER)) { + if (!(chip->open & SB_OPEN_MIDI_OUTPUT_TRIGGER)) { init_timer(&chip->midi_timer); chip->midi_timer.function = snd_sb8dsp_midi_output_timer; chip->midi_timer.data = (unsigned long) substream; chip->midi_timer.expires = 1 + jiffies; add_timer(&chip->midi_timer); - chip->open |= SB_OPEN_MIDI_TRIGGER; + chip->open |= SB_OPEN_MIDI_OUTPUT_TRIGGER; } } else { - if (chip->open & SB_OPEN_MIDI_TRIGGER) { - chip->open &= ~SB_OPEN_MIDI_TRIGGER; + if (chip->open & SB_OPEN_MIDI_OUTPUT_TRIGGER) { + chip->open &= ~SB_OPEN_MIDI_OUTPUT_TRIGGER; } } spin_unlock_irqrestore(&chip->open_lock, flags); @@ -253,7 +286,9 @@ strcpy(rmidi->name, "SB8 MIDI"); snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &snd_sb8dsp_midi_output); snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &snd_sb8dsp_midi_input); - rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; + rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT; + if (chip->hardware >= SB_HW_20) + rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX; rmidi->private_data = chip; chip->rmidi = rmidi; if (rrawmidi) diff -Nru a/sound/isa/sscape.c b/sound/isa/sscape.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/isa/sscape.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,1558 @@ +/* + * Low-level ALSA driver for the ENSONIQ SoundScape PnP + * Copyright (c) by Chris Rankin + * + * This driver was written in part using information obtained from + * the OSS/Free SoundScape driver, written by Hannu Savolainen. + * + * FIXME (deadlock for alsa-kernel): + * - use ISA PnP scheme used by all ALSA ISA drivers + * - add non-MODULE build option + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the 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 <sound/driver.h> +#include <linux/init.h> +#include <linux/delay.h> +#include <linux/pnp.h> +#include <linux/spinlock.h> +#include <asm/dma.h> +#include <sound/core.h> +#include <sound/hwdep.h> +#include <sound/cs4231.h> +#include <sound/mpu401.h> +#include <sound/initval.h> + +#include <sound/sscape_ioctl.h> + +#define chip_t cs4231_t + + +MODULE_AUTHOR("Chris Rankin"); +MODULE_DESCRIPTION("ENSONIQ SoundScape PnP driver"); +MODULE_LICENSE("GPL"); + +static int index[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IDX; +static char* id[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_STR; +static long port[SNDRV_CARDS] __devinitdata = { [0 ... (SNDRV_CARDS-1)] = SNDRV_AUTO_PORT }; +static int irq[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IRQ; +static int mpu_irq[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IRQ; +static int dma[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_DMA; + +MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(index, "Index number for SoundScape soundcard"); +MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); + +MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s"); +MODULE_PARM_DESC(id, "Description for SoundScape card"); +MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); + +MODULE_PARM(port, "1-" __MODULE_STRING(SNDRV_CARDS) "l"); +MODULE_PARM_DESC(port, "Port # for SoundScape driver."); +MODULE_PARM_SYNTAX(port, SNDRV_ENABLED); + +MODULE_PARM(irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(irq, "IRQ # for SoundScape driver."); +MODULE_PARM_SYNTAX(irq, SNDRV_IRQ_DESC); + +MODULE_PARM(mpu_irq, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(mpu_irq, "MPU401 IRQ # for SoundScape driver."); +MODULE_PARM_SYNTAX(mpu_irq, SNDRV_IRQ_DESC); + +MODULE_PARM(dma, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(dma, "DMA # for SoundScape driver."); +MODULE_PARM_SYNTAX(dma, SNDRV_DMA8_DESC); + +#ifdef CONFIG_PNP +static struct pnp_card_device_id sscape_pnpids[] __devinitdata = { + { .id = "ENS3081", .devs = { { "ENS0000" } } }, + { .id = "" } /* end */ +}; + +MODULE_DEVICE_TABLE(pnp_card, sscape_pnpids); +#endif + +static snd_card_t *sscape_card[SNDRV_CARDS]; + + +#define MPU401_IO(i) ((i) + 0) +#define MIDI_DATA_IO(i) ((i) + 0) +#define MIDI_CTRL_IO(i) ((i) + 1) +#define HOST_CTRL_IO(i) ((i) + 2) +#define HOST_DATA_IO(i) ((i) + 3) +#define ODIE_ADDR_IO(i) ((i) + 4) +#define ODIE_DATA_IO(i) ((i) + 5) +#define CODEC_IO(i) ((i) + 8) + +#define IC_ODIE 1 +#define IC_OPUS 2 + +#define RX_READY 0x01 +#define TX_READY 0x02 + +#define CMD_ACK 0x80 +#define CMD_SET_MIDI_VOL 0x84 +#define CMD_GET_MIDI_VOL 0x85 +#define CMD_XXX_MIDI_VOL 0x86 +#define CMD_SET_EXTMIDI 0x8a +#define CMD_GET_EXTMIDI 0x8b +#define CMD_SET_MT32 0x8c +#define CMD_GET_MT32 0x8d + +enum GA_REG { + GA_INTSTAT_REG = 0, + GA_INTENA_REG, + GA_DMAA_REG, + GA_DMAB_REG, + GA_INTCFG_REG, + GA_DMACFG_REG, + GA_CDCFG_REG, + GA_SMCFGA_REG, + GA_SMCFGB_REG, + GA_HMCTL_REG +}; + +#define DMA_8BIT 0x80 + + +#define AD1845_FREQ_SEL_MSB 0x16 +#define AD1845_FREQ_SEL_LSB 0x17 + +struct soundscape { + spinlock_t lock; + unsigned io_base; + int codec_type; + int ic_type; + struct resource *io_res; + cs4231_t *chip; + mpu401_t *mpu; + snd_hwdep_t *hw; + + /* + * The MIDI device won't work until we've loaded + * its firmware via a hardware-dependent device IOCTL + */ + spinlock_t fwlock; + int hw_in_use; + unsigned long midi_usage; + unsigned char midi_vol; +}; + +#define INVALID_IRQ ((unsigned)-1) + + +static inline struct soundscape *get_card_soundscape(snd_card_t * c) +{ + return (struct soundscape *) (c->private_data); +} + +static inline struct soundscape *get_mpu401_soundscape(mpu401_t * mpu) +{ + return (struct soundscape *) (mpu->private_data); +} + +static inline struct soundscape *get_hwdep_soundscape(snd_hwdep_t * hw) +{ + return (struct soundscape *) (hw->private_data); +} + + +struct dmabuf { + size_t size; + unsigned char *data; + dma_addr_t addr; +}; + +/* + * Allocates some kernel memory that we can use for DMA. + * I think this means that the memory has to map to + * contiguous pages of physical memory. + */ +static struct dmabuf *get_dmabuf(struct dmabuf *buf, unsigned long s) +{ + if (buf) { + buf->data = snd_malloc_isa_pages_fallback(s, &buf->addr, &buf->size); + if (!buf->data) { + snd_printk(KERN_ERR "sscape: Failed to allocate %lu bytes for DMA\n", s); + return NULL; + } + } + + return buf; +} + +/* + * Release the DMA-able kernel memory ... + */ +static void free_dmabuf(struct dmabuf *buf) +{ + if (buf && buf->data) + snd_free_isa_pages(buf->size, buf->data, buf->addr); +} + + +/* + * This function writes to the SoundScape's control registers, + * but doesn't do any locking. It's up to the caller to do that. + * This is why this function is "unsafe" ... + */ +static inline void sscape_write_unsafe(unsigned io_base, enum GA_REG reg, unsigned char val) +{ + outb(reg, ODIE_ADDR_IO(io_base)); + outb(val, ODIE_DATA_IO(io_base)); +} + +/* + * Write to the SoundScape's control registers, and do the + * necessary locking ... + */ +static void sscape_write(struct soundscape *s, enum GA_REG reg, unsigned char val) +{ + unsigned long flags; + + spin_lock_irqsave(&s->lock, flags); + sscape_write_unsafe(s->io_base, reg, val); + spin_unlock_irqrestore(&s->lock, flags); +} + +/* + * Read from the SoundScape's control registers, but leave any + * locking to the caller. This is why the function is "unsafe" ... + */ +static inline unsigned char sscape_read_unsafe(unsigned io_base, enum GA_REG reg) +{ + outb(reg, ODIE_ADDR_IO(io_base)); + return inb(ODIE_DATA_IO(io_base)); +} + +/* + * Puts the SoundScape into "host" mode, as compared to "MIDI" mode + */ +static inline void set_host_mode_unsafe(unsigned io_base) +{ + outb(0x0, HOST_CTRL_IO(io_base)); +} + +/* + * Puts the SoundScape into "MIDI" mode, as compared to "host" mode + */ +static inline void set_midi_mode_unsafe(unsigned io_base) +{ + outb(0x3, HOST_CTRL_IO(io_base)); +} + +/* + * Read the SoundScape's host-mode control register, but leave + * any locking issues to the caller ... + */ +static inline int host_read_unsafe(unsigned io_base) +{ + int data = -1; + if ((inb(HOST_CTRL_IO(io_base)) & RX_READY) != 0) { + data = inb(HOST_DATA_IO(io_base)); + } + + return data; +} + +/* + * Read the SoundScape's host-mode control register, performing + * a limited amount of busy-waiting if the register isn't ready. + * Also leaves all locking-issues to the caller ... + */ +static int host_read_ctrl_unsafe(unsigned io_base, unsigned timeout) +{ + int data; + + while (((data = host_read_unsafe(io_base)) < 0) && (timeout != 0)) { + udelay(100); + --timeout; + } /* while */ + + return data; +} + +/* + * Write to the SoundScape's host-mode control registers, but + * leave any locking issues to the caller ... + */ +static inline int host_write_unsafe(unsigned io_base, unsigned char data) +{ + if ((inb(HOST_CTRL_IO(io_base)) & TX_READY) != 0) { + outb(data, HOST_DATA_IO(io_base)); + return 1; + } + + return 0; +} + +/* + * Write to the SoundScape's host-mode control registers, performing + * a limited amount of busy-waiting if the register isn't ready. + * Also leaves all locking-issues to the caller ... + */ +static int host_write_ctrl_unsafe(unsigned io_base, unsigned char data, + unsigned timeout) +{ + int err; + + while (!(err = host_write_unsafe(io_base, data)) && (timeout != 0)) { + udelay(100); + --timeout; + } /* while */ + + return err; +} + + +/* + * Check that the MIDI subsystem is operational. If it isn't, + * then we will hang the computer if we try to use it ... + * + * NOTE: This check is based upon observation, not documentation. + */ +static inline int verify_mpu401(const mpu401_t * mpu) +{ + return ((inb(MIDI_CTRL_IO(mpu->port)) & 0xc0) == 0x80); +} + +/* + * This is apparently the standard way to initailise an MPU-401 + */ +static inline void initialise_mpu401(const mpu401_t * mpu) +{ + outb(0, MIDI_DATA_IO(mpu->port)); +} + +/* + * Tell the SoundScape to activate the AD1845 chip (I think). + * The AD1845 detection fails if we *don't* do this, so I + * think that this is a good idea ... + */ +static inline void activate_ad1845_unsafe(unsigned io_base) +{ + sscape_write_unsafe(io_base, GA_HMCTL_REG, (sscape_read_unsafe(io_base, GA_HMCTL_REG) & 0xcf) | 0x10); + sscape_write_unsafe(io_base, GA_CDCFG_REG, 0x80); +} + +/* + * Do the necessary ALSA-level cleanup to deallocate our driver ... + */ +static void soundscape_free(snd_card_t * c) +{ + register struct soundscape *sscape = get_card_soundscape(c); + release_resource(sscape->io_res); + kfree_nocheck(sscape->io_res); + free_dma(sscape->chip->dma1); +} + +/* + * Put this process into an idle wait-state for a certain number + * of "jiffies". The process can almost certainly be rescheduled + * while we're waiting, and so we must NOT be holding any spinlocks + * when we call this function. If we are then we risk DEADLOCK in + * SMP (Ha!) or pre-emptible kernels. + */ +static inline void sleep(long jiffs, int state) +{ + set_current_state(state); + schedule_timeout(jiffs); +} + +/* + * Tell the SoundScape to begin a DMA tranfer using the given channel. + * All locking issues are left to the caller. + */ +static inline void sscape_start_dma_unsafe(unsigned io_base, enum GA_REG reg) +{ + sscape_write_unsafe(io_base, reg, sscape_read_unsafe(io_base, reg) | 0x01); + sscape_write_unsafe(io_base, reg, sscape_read_unsafe(io_base, reg) & 0xfe); +} + +/* + * Wait for a DMA transfer to complete. This is a "limited busy-wait", + * and all locking issues are left to the caller. + */ +static int sscape_wait_dma_unsafe(unsigned io_base, enum GA_REG reg, unsigned timeout) +{ + while (!(sscape_read_unsafe(io_base, reg) & 0x01) && (timeout != 0)) { + udelay(100); + --timeout; + } /* while */ + + return (sscape_read_unsafe(io_base, reg) & 0x01); +} + +/* + * Wait for the On-Board Processor to return its start-up + * acknowledgement sequence. This wait is too long for + * us to perform "busy-waiting", and so we must sleep. + * This in turn means that we must not be holding any + * spinlocks when we call this function. + */ +static int obp_startup_ack(struct soundscape *s, unsigned timeout) +{ + while (timeout != 0) { + unsigned long flags; + unsigned char x; + + sleep(1, TASK_INTERRUPTIBLE); + + spin_lock_irqsave(&s->lock, flags); + x = inb(HOST_DATA_IO(s->io_base)); + spin_unlock_irqrestore(&s->lock, flags); + if ((x & 0xfe) == 0xfe) + return 1; + + --timeout; + } /* while */ + + return 0; +} + +/* + * Wait for the host to return its start-up acknowledgement + * sequence. This wait is too long for us to perform + * "busy-waiting", and so we must sleep. This in turn means + * that we must not be holding any spinlocks when we call + * this function. + */ +static int host_startup_ack(struct soundscape *s, unsigned timeout) +{ + while (timeout != 0) { + unsigned long flags; + unsigned char x; + + sleep(1, TASK_INTERRUPTIBLE); + + spin_lock_irqsave(&s->lock, flags); + x = inb(HOST_DATA_IO(s->io_base)); + spin_unlock_irqrestore(&s->lock, flags); + if (x == 0xfe) + return 1; + + --timeout; + } /* while */ + + return 0; +} + +/* + * Upload a byte-stream into the SoundScape using DMA channel A. + */ +static int upload_dma_data(struct soundscape *s, + const unsigned char *data, size_t size, + size_t dmasize) +{ + unsigned long flags; + struct dmabuf dma; + int ret; + + if (!get_dmabuf(&dma, dmasize)) + return -ENOMEM; + + spin_lock_irqsave(&s->lock, flags); + + /* + * Reset the board ... + */ + sscape_write_unsafe(s->io_base, GA_HMCTL_REG, sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f); + + /* + * Enable the DMA channels and configure them ... + */ + sscape_write_unsafe(s->io_base, GA_DMACFG_REG, 0x50); + sscape_write_unsafe(s->io_base, GA_DMAA_REG, (s->chip->dma1 << 4) | DMA_8BIT); + sscape_write_unsafe(s->io_base, GA_DMAB_REG, 0x20); + + /* + * Take the board out of reset ... + */ + sscape_write_unsafe(s->io_base, GA_HMCTL_REG, sscape_read_unsafe(s->io_base, GA_HMCTL_REG) | 0x80); + + /* + * Upload the user's data (firmware?) to the SoundScape + * board through the DMA channel ... + */ + while (size != 0) { + unsigned long len; + + /* + * Apparently, copying to/from userspace can sleep. + * We are therefore forbidden from holding any + * spinlocks while we copy ... + */ + spin_unlock_irqrestore(&s->lock, flags); + + /* + * Remember that the data that we want to DMA + * comes from USERSPACE. We have already verified + * the userspace pointer ... + */ + len = min(size, dma.size); + __copy_from_user(dma.data, data, len); + data += len; + size -= len; + + /* + * Grab that spinlock again, now that we've + * finished copying! + */ + spin_lock_irqsave(&s->lock, flags); + + snd_dma_program(s->chip->dma1, dma.addr, len, DMA_MODE_WRITE); + sscape_start_dma_unsafe(s->io_base, GA_DMAA_REG); + if (!sscape_wait_dma_unsafe(s->io_base, GA_DMAA_REG, 5000)) { + /* + * Don't forget to release this spinlock we're holding ... + */ + spin_unlock_irqrestore(&s->lock, flags); + + snd_printk(KERN_ERR "sscape: DMA upload has timed out\n"); + ret = -EAGAIN; + goto _release_dma; + } + } /* while */ + + set_host_mode_unsafe(s->io_base); + + /* + * Boot the board ... (I think) + */ + sscape_write_unsafe(s->io_base, GA_HMCTL_REG, sscape_read_unsafe(s->io_base, GA_HMCTL_REG) | 0x40); + spin_unlock_irqrestore(&s->lock, flags); + + /* + * If all has gone well, then the board should acknowledge + * the new upload and tell us that it has rebooted OK. We + * give it 5 seconds (max) ... + */ + ret = 0; + if (!obp_startup_ack(s, 5)) { + snd_printk(KERN_ERR "sscape: No response from on-board processor after upload\n"); + ret = -EAGAIN; + } else if (!host_startup_ack(s, 5)) { + snd_printk(KERN_ERR "sscape: SoundScape failed to initialise\n"); + ret = -EAGAIN; + } + + _release_dma: + /* + * NOTE!!! We are NOT holding any spinlocks at this point !!! + */ + sscape_write(s, GA_DMAA_REG, (s->ic_type == IC_ODIE ? 0x70 : 0x40)); + free_dmabuf(&dma); + + return ret; +} + +/* + * Upload the bootblock(?) into the SoundScape. The only + * purpose of this block of code seems to be to tell + * us which version of the microcode we should be using. + * + * NOTE: The boot-block data resides in USER-SPACE!!! + * However, we have already verified its memory + * addresses by the time we get here. + */ +static int sscape_upload_bootblock(struct soundscape *sscape, struct sscape_bootblock *bb) +{ + unsigned long flags; + int data = 0; + int ret; + + ret = upload_dma_data(sscape, bb->code, sizeof(bb->code), PAGE_SIZE); + + spin_lock_irqsave(&sscape->lock, flags); + if (ret == 0) { + data = host_read_ctrl_unsafe(sscape->io_base, 100); + } + set_midi_mode_unsafe(sscape->io_base); + spin_unlock_irqrestore(&sscape->lock, flags); + + if (ret == 0) { + if (data < 0) { + snd_printk(KERN_ERR "sscape: timeout reading firmware version\n"); + ret = -EAGAIN; + } else { + __copy_to_user(&bb->version, &data, sizeof(bb->version)); + } + } + + return ret; +} + +/* + * Upload the microcode into the SoundScape. The + * microcode is 64K of data, and if we try to copy + * it into a local variable then we will SMASH THE + * KERNEL'S STACK! We therefore leave it in USER + * SPACE, and save ourselves from copying it at all. + * + * We assume that the caller has already verified the + * userspace memory addresses. + */ +static int sscape_upload_microcode(struct soundscape *sscape, + const struct sscape_microcode *mc) +{ + unsigned long flags; + int ret; + + if ((ret = upload_dma_data(sscape, mc->code, sizeof(mc->code), PAGE_SIZE * 16)) == 0) { + snd_printk(KERN_INFO "sscape: MIDI firmware loaded\n"); + } + + spin_lock_irqsave(&sscape->lock, flags); + set_midi_mode_unsafe(sscape->io_base); + spin_unlock_irqrestore(&sscape->lock, flags); + + initialise_mpu401(sscape->mpu); + + return ret; +} + +/* + * Hardware-specific device functions, to implement special + * IOCTLs for the SoundScape card. This is how we upload + * the microcode into the card, for example, and so we + * must ensure that no two processes can open this device + * simultaneously, and that we can't open it at all if + * someone is using the MIDI device. + */ +static int sscape_hw_open(snd_hwdep_t * hw, struct file *file) +{ + register struct soundscape *sscape = get_hwdep_soundscape(hw); + unsigned long flags; + int err; + + spin_lock_irqsave(&sscape->fwlock, flags); + + if ((sscape->midi_usage != 0) || sscape->hw_in_use) { + err = -EBUSY; + } else { + sscape->hw_in_use = 1; + err = 0; + } + + spin_unlock_irqrestore(&sscape->fwlock, flags); + return err; +} + +static int sscape_hw_release(snd_hwdep_t * hw, struct file *file) +{ + register struct soundscape *sscape = get_hwdep_soundscape(hw); + unsigned long flags; + + spin_lock_irqsave(&sscape->fwlock, flags); + sscape->hw_in_use = 0; + spin_unlock_irqrestore(&sscape->fwlock, flags); + return 0; +} + +static int sscape_hw_ioctl(snd_hwdep_t * hw, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct soundscape *sscape = get_hwdep_soundscape(hw); + int err = -EBUSY; + + switch (cmd) { + case SND_SSCAPE_LOAD_BOOTB: + { + register struct sscape_bootblock *bb = (struct sscape_bootblock *) arg; + + /* + * We are going to have to copy this data into a special + * DMA-able buffer before we can upload it. We shall therefore + * just check that the data pointer is valid for now ... + */ + if ((err = verify_area(VERIFY_READ, bb->code, sizeof(bb->code))) != 0) + return err; + + /* + * Now check that we can write the firmware version number too... + */ + if ((err = verify_area(VERIFY_WRITE, &bb->version, sizeof(bb->version))) != 0) + return err; + + err = sscape_upload_bootblock(sscape, bb); + } + break; + + case SND_SSCAPE_LOAD_MCODE: + { + register const struct sscape_microcode *mc = (const struct sscape_microcode *) arg; + + /* + * We are going to have to copy this data into a special + * DMA-able buffer before we can upload it. We shall therefore + * just check that the data pointer is valid for now. + * + * NOTE: This buffer is 64K long! That's WAY too big to + * copy into a stack-temporary anyway. + */ + if ((err = verify_area(VERIFY_READ, mc->code, sizeof(mc->code))) != 0) + return err; + + err = sscape_upload_microcode(sscape, mc); + } + break; + + default: + err = -EINVAL; + break; + } /* switch */ + + return err; +} + + +/* + * Mixer control for the SoundScape's MIDI device. + */ +static int sscape_midi_info(snd_kcontrol_t * ctl, + snd_ctl_elem_info_t * uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 127; + return 0; +} + +static int sscape_midi_get(snd_kcontrol_t * kctl, + snd_ctl_elem_value_t * uctl) +{ + cs4231_t *chip = snd_kcontrol_chip(kctl); + snd_card_t *card = chip->card; + register struct soundscape *s = get_card_soundscape(card); + unsigned long flags; + + spin_lock_irqsave(&s->lock, flags); + set_host_mode_unsafe(s->io_base); + + if (host_write_ctrl_unsafe(s->io_base, CMD_GET_MIDI_VOL, 100)) { + uctl->value.integer.value[0] = host_read_ctrl_unsafe(s->io_base, 100); + } + + set_midi_mode_unsafe(s->io_base); + spin_unlock_irqrestore(&s->lock, flags); + return 0; +} + +static int sscape_midi_put(snd_kcontrol_t * kctl, + snd_ctl_elem_value_t * uctl) +{ + cs4231_t *chip = snd_kcontrol_chip(kctl); + snd_card_t *card = chip->card; + register struct soundscape *s = get_card_soundscape(card); + unsigned long flags; + int change; + + spin_lock_irqsave(&s->lock, flags); + + /* + * We need to put the board into HOST mode before we + * can send any volume-changing HOST commands ... + */ + set_host_mode_unsafe(s->io_base); + + /* + * To successfully change the MIDI volume setting, you seem to + * have to write a volume command, write the new volume value, + * and then perform another volume-related command. Perhaps the + * first command is an "open" and the second command is a "close"? + */ + if (s->midi_vol == ((unsigned char) uctl->value.integer. value[0] & 127)) { + change = 0; + goto __skip_change; + } + change = (host_write_ctrl_unsafe(s->io_base, CMD_SET_MIDI_VOL, 100) + && host_write_ctrl_unsafe(s->io_base, ((unsigned char) uctl->value.integer. value[0]) & 127, 100) + && host_write_ctrl_unsafe(s->io_base, CMD_XXX_MIDI_VOL, 100)); + __skip_change: + + /* + * Take the board out of HOST mode and back into MIDI mode ... + */ + set_midi_mode_unsafe(s->io_base); + + spin_unlock_irqrestore(&s->lock, flags); + return change; +} + +static snd_kcontrol_new_t midi_mixer_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "MIDI", + .info = sscape_midi_info, + .get = sscape_midi_get, + .put = sscape_midi_put +}; + +/* + * The SoundScape can use two IRQs from a possible set of four. + * These IRQs are encoded as bit patterns so that they can be + * written to the control registers. + */ +static unsigned __devinit get_irq_config(int irq) +{ + static const int valid_irq[] __devinitdata = { 9, 5, 7, 10 }; + unsigned cfg; + + for (cfg = 0; cfg < ARRAY_SIZE(valid_irq); ++cfg) { + if (irq == valid_irq[cfg]) + return cfg; + } /* for */ + + return INVALID_IRQ; +} + + +/* + * Perform certain arcane port-checks to see whether there + * is a SoundScape board lurking behind the given ports. + */ +static int __devinit detect_sscape(struct soundscape *s) +{ + unsigned long flags; + unsigned d; + int retval = 0; + + spin_lock_irqsave(&s->lock, flags); + + /* + * The following code is lifted from the original OSS driver, + * and as I don't have a datasheet I cannot really comment + * on what it is doing... + */ + if ((inb(HOST_CTRL_IO(s->io_base)) & 0x78) != 0) + goto _done; + + d = inb(ODIE_ADDR_IO(s->io_base)) & 0xf0; + if ((d & 0x80) != 0) + goto _done; + + if (d == 0) { + s->codec_type = 1; + s->ic_type = IC_ODIE; + } else if ((d & 0x60) != 0) { + s->codec_type = 2; + s->ic_type = IC_OPUS; + } else + goto _done; + + outb(0xfa, ODIE_ADDR_IO(s->io_base)); + if ((inb(ODIE_ADDR_IO(s->io_base)) & 0x9f) != 0x0a) + goto _done; + + outb(0xfe, ODIE_ADDR_IO(s->io_base)); + if ((inb(ODIE_ADDR_IO(s->io_base)) & 0x9f) != 0x0e) + goto _done; + if ((inb(ODIE_DATA_IO(s->io_base)) & 0x9f) != 0x0e) + goto _done; + + /* + * SoundScape successfully detected! + */ + retval = 1; + + _done: + spin_unlock_irqrestore(&s->lock, flags); + return retval; +} + +/* + * ALSA callback function, called when attempting to open the MIDI device. + * Check that the MIDI firmware has been loaded, because we don't want + * to crash the machine. Also check that someone isn't using the hardware + * IOCTL device. + */ +static int mpu401_open(mpu401_t * mpu) +{ + int err; + + if (!verify_mpu401(mpu)) { + snd_printk(KERN_ERR "sscape: MIDI disabled, please load firmware\n"); + err = -ENODEV; + } else { + register struct soundscape *sscape = get_mpu401_soundscape(mpu); + unsigned long flags; + + spin_lock_irqsave(&sscape->fwlock, flags); + + if (sscape->hw_in_use || (sscape->midi_usage == ULONG_MAX)) { + err = -EBUSY; + } else { + ++(sscape->midi_usage); + err = 0; + } + + spin_unlock_irqrestore(&sscape->fwlock, flags); + } + + return err; +} + +static void mpu401_close(mpu401_t * mpu) +{ + register struct soundscape *sscape = get_mpu401_soundscape(mpu); + unsigned long flags; + + spin_lock_irqsave(&sscape->fwlock, flags); + --(sscape->midi_usage); + spin_unlock_irqrestore(&sscape->fwlock, flags); +} + +/* + * Initialse an MPU-401 subdevice for MIDI support on the SoundScape. + */ +static int __devinit create_mpu401(snd_card_t * card, int devnum, unsigned long port, int irq) +{ + struct soundscape *sscape = get_card_soundscape(card); + snd_rawmidi_t *rawmidi; + int err; + +#define MPU401_SHARE_HARDWARE 1 + if ((err = snd_mpu401_uart_new(card, devnum, + MPU401_HW_MPU401, + port, MPU401_SHARE_HARDWARE, + irq, SA_INTERRUPT, + &rawmidi)) == 0) { + mpu401_t *mpu = (mpu401_t *) rawmidi->private_data; + mpu->open_input = mpu401_open; + mpu->open_output = mpu401_open; + mpu->close_input = mpu401_close; + mpu->close_output = mpu401_close; + mpu->private_data = sscape; + sscape->mpu = mpu; + + initialise_mpu401(mpu); + } + + return err; +} + + +/* + * Override for the CS4231 playback format function. + * The AD1845 has much simpler format and rate selection. + */ +static void ad1845_playback_format(cs4231_t * chip, snd_pcm_hw_params_t * params, unsigned char format) +{ + unsigned long flags; + unsigned rate = params_rate(params); + + /* + * The AD1845 can't handle sample frequencies + * outside of 4 kHZ to 50 kHZ + */ + if (rate > 50000) + rate = 50000; + else if (rate < 4000) + rate = 4000; + + spin_lock_irqsave(&chip->reg_lock, flags); + + /* + * Program the AD1845 correctly for the playback stream. + * Note that we do NOT need to toggle the MCE bit because + * the PLAYBACK_ENABLE bit of the Interface Configuration + * register is set. + * + * NOTE: We seem to need to write to the MSB before the LSB + * to get the correct sample frequency. + */ + snd_cs4231_out(chip, CS4231_PLAYBK_FORMAT, (format & 0xf0)); + snd_cs4231_out(chip, AD1845_FREQ_SEL_MSB, (unsigned char) (rate >> 8)); + snd_cs4231_out(chip, AD1845_FREQ_SEL_LSB, (unsigned char) rate); + + spin_unlock_irqrestore(&chip->reg_lock, flags); +} + +/* + * Override for the CS4231 capture format function. + * The AD1845 has much simpler format and rate selection. + */ +static void ad1845_capture_format(cs4231_t * chip, snd_pcm_hw_params_t * params, unsigned char format) +{ + unsigned long flags; + unsigned rate = params_rate(params); + + /* + * The AD1845 can't handle sample frequencies + * outside of 4 kHZ to 50 kHZ + */ + if (rate > 50000) + rate = 50000; + else if (rate < 4000) + rate = 4000; + + spin_lock_irqsave(&chip->reg_lock, flags); + + /* + * Program the AD1845 correctly for the playback stream. + * Note that we do NOT need to toggle the MCE bit because + * the CAPTURE_ENABLE bit of the Interface Configuration + * register is set. + * + * NOTE: We seem to need to write to the MSB before the LSB + * to get the correct sample frequency. + */ + snd_cs4231_out(chip, CS4231_REC_FORMAT, (format & 0xf0)); + snd_cs4231_out(chip, AD1845_FREQ_SEL_MSB, (unsigned char) (rate >> 8)); + snd_cs4231_out(chip, AD1845_FREQ_SEL_LSB, (unsigned char) rate); + + spin_unlock_irqrestore(&chip->reg_lock, flags); +} + +/* + * Create an AD1845 PCM subdevice on the SoundScape. The AD1845 + * is very much like a CS4231, with a few extra bits. We will + * try to support at least some of the extra bits by overriding + * some of the CS4231 callback. + */ +static int __devinit create_ad1845(snd_card_t * card, unsigned port, int irq, int dma1) +{ + register struct soundscape *sscape = get_card_soundscape(card); + cs4231_t *chip; + int err; + +#define CS4231_SHARE_HARDWARE (CS4231_HWSHARE_DMA1 | CS4231_HWSHARE_DMA2) + /* + * The AD1845 PCM device is only half-duplex, and so + * we only give it one DMA channel ... + */ + if ((err = snd_cs4231_create(card, + port, -1, irq, dma1, dma1, + CS4231_HW_DETECT, + CS4231_HWSHARE_DMA1, &chip)) == 0) { + unsigned long flags; + snd_pcm_t *pcm; + +#define AD1845_FREQ_SEL_ENABLE 0x08 + +#define AD1845_PWR_DOWN_CTRL 0x1b +#define AD1845_CRYS_CLOCK_SEL 0x1d + +/* + * It turns out that the PLAYBACK_ENABLE bit is set + * by the lowlevel driver ... + * +#define AD1845_IFACE_CONFIG \ + (CS4231_AUTOCALIB | CS4231_RECORD_ENABLE | CS4231_PLAYBACK_ENABLE) + snd_cs4231_mce_up(chip); + spin_lock_irqsave(&chip->reg_lock, flags); + snd_cs4231_out(chip, CS4231_IFACE_CTRL, AD1845_IFACE_CONFIG); + spin_unlock_irqrestore(&chip->reg_lock, flags); + snd_cs4231_mce_down(chip); + */ + + /* + * The input clock frequency on the SoundScape must + * be 14.31818 MHz, because we must set this register + * to get the playback to sound correct ... + */ + snd_cs4231_mce_up(chip); + spin_lock_irqsave(&chip->reg_lock, flags); + snd_cs4231_out(chip, AD1845_CRYS_CLOCK_SEL, 0x20); + spin_unlock_irqrestore(&chip->reg_lock, flags); + snd_cs4231_mce_down(chip); + + /* + * More custom configuration: + * a) select "mode 2", and provide a current drive of 8 mA + * b) enable frequency selection (for capture/playback) + */ + spin_lock_irqsave(&chip->reg_lock, flags); + snd_cs4231_out(chip, CS4231_MISC_INFO, (CS4231_MODE2 | 0x10)); + snd_cs4231_out(chip, AD1845_PWR_DOWN_CTRL, snd_cs4231_in(chip, AD1845_PWR_DOWN_CTRL) | AD1845_FREQ_SEL_ENABLE); + spin_unlock_irqrestore(&chip->reg_lock, flags); + + if ((err = snd_cs4231_pcm(chip, 0, &pcm)) < 0) { + snd_printk(KERN_ERR "sscape: No PCM device for AD1845 chip\n"); + goto _error; + } + + if ((err = snd_cs4231_mixer(chip)) < 0) { + snd_printk(KERN_ERR "sscape: No mixer device for AD1845 chip\n"); + goto _error; + } + + if ((err = snd_ctl_add(card, snd_ctl_new1(&midi_mixer_ctl, chip))) < 0) { + snd_printk(KERN_ERR "sscape: Could not create MIDI mixer control\n"); + goto _error; + } + + strcpy(card->driver, "SoundScape"); + strcpy(card->shortname, pcm->name); + snprintf(card->longname, sizeof(card->longname), + "%s at 0x%lx, IRQ %d, DMA %d\n", + pcm->name, chip->port, chip->irq, chip->dma1); + chip->set_playback_format = ad1845_playback_format; + chip->set_capture_format = ad1845_capture_format; + sscape->chip = chip; + } + + _error: + return err; +} + + +struct params +{ + int index; + const char *id; + unsigned port; + int irq; + int mpu_irq; + int dma1; +}; + + +static inline struct params* +init_params(struct params *params, + int index, + const char *id, + unsigned port, + int irq, + int mpu_irq, + int dma1) +{ + params->index = index; + params->id = id; + params->port = port; + params->irq = irq; + params->mpu_irq = mpu_irq; + params->dma1 = (dma1 & 0x03); + + return params; +} + + +/* + * Create an ALSA soundcard entry for the SoundScape, using + * the given list of port, IRQ and DMA resources. + */ +static int __devinit create_sscape(const struct params *params, snd_card_t **rcardp) +{ + snd_card_t *card; + register struct soundscape *sscape; + register unsigned dma_cfg; + unsigned irq_cfg; + unsigned mpu_irq_cfg; + struct resource *io_res; + unsigned long flags; + int err; + + /* + * Check that the user didn't pass us garbage data ... + */ + irq_cfg = get_irq_config(params->irq); + if (irq_cfg == INVALID_IRQ) { + snd_printk(KERN_ERR "sscape: Invalid IRQ %d\n", params->irq); + return -ENXIO; + } + + mpu_irq_cfg = get_irq_config(params->mpu_irq); + if (mpu_irq_cfg == INVALID_IRQ) { + printk(KERN_ERR "sscape: Invalid IRQ %d\n", params->mpu_irq); + return -ENXIO; + } + + /* + * Grab IO ports that we will need to probe so that we + * can detect and control this hardware ... + */ + if ((io_res = request_region(params->port, 8, "SoundScape")) == NULL) { + return -EBUSY; + } + + /* + * Grab both DMA channels (OK, only one for now) ... + */ + if ((err = request_dma(params->dma1, "SoundScape")) < 0) { + goto _release_region; + } + + /* + * Create a new ALSA sound card entry, in anticipation + * of detecting our hardware ... + */ + if ((card = snd_card_new(params->index, params->id, THIS_MODULE, sizeof(struct soundscape))) == NULL) { + err = -ENOMEM; + goto _release_dma; + } + + sscape = get_card_soundscape(card); + spin_lock_init(&sscape->lock); + spin_lock_init(&sscape->fwlock); + sscape->io_res = io_res; + sscape->io_base = params->port; + + if (!detect_sscape(sscape)) { + printk(KERN_ERR "sscape: hardware not detected at 0x%x\n", sscape->io_base); + err = -ENODEV; + goto _release_card; + } + + printk(KERN_INFO "sscape: hardware detected at 0x%x, using IRQ %d, DMA %d\n", + sscape->io_base, params->irq, params->dma1); + + /* + * Now create the hardware-specific device so that we can + * load the microcode into the on-board processor. + * We cannot use the MPU-401 MIDI system until this firmware + * has been loaded into the card. + */ + if ((err = snd_hwdep_new(card, "MC68EC000", 0, &(sscape->hw))) < 0) { + printk(KERN_ERR "sscape: Failed to create firmware device\n"); + goto _release_card; + } + strlcpy(sscape->hw->name, "SoundScape M68K", sizeof(sscape->hw->name)); + sscape->hw->name[sizeof(sscape->hw->name) - 1] = '\0'; + sscape->hw->iface = SNDRV_HWDEP_IFACE_SSCAPE; + sscape->hw->ops.open = sscape_hw_open; + sscape->hw->ops.release = sscape_hw_release; + sscape->hw->ops.ioctl = sscape_hw_ioctl; + sscape->hw->private_data = sscape; + + /* + * Tell the on-board devices where their resources are (I think - + * I can't be sure without a datasheet ... So many magic values!) + */ + spin_lock_irqsave(&sscape->lock, flags); + + activate_ad1845_unsafe(sscape->io_base); + + sscape_write_unsafe(sscape->io_base, GA_INTENA_REG, 0x00); /* disable */ + sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2e); + sscape_write_unsafe(sscape->io_base, GA_SMCFGB_REG, 0x00); + + /* + * Enable and configure the DMA channels ... + */ + sscape_write_unsafe(sscape->io_base, GA_DMACFG_REG, 0x50); + dma_cfg = (sscape->ic_type == IC_ODIE ? 0x70 : 0x40); + sscape_write_unsafe(sscape->io_base, GA_DMAA_REG, dma_cfg); + sscape_write_unsafe(sscape->io_base, GA_DMAB_REG, 0x20); + + sscape_write_unsafe(sscape->io_base, + GA_INTCFG_REG, 0xf0 | (mpu_irq_cfg << 2) | mpu_irq_cfg); + sscape_write_unsafe(sscape->io_base, + GA_CDCFG_REG, 0x09 | DMA_8BIT | (params->dma1 << 4) | (irq_cfg << 1)); + + spin_unlock_irqrestore(&sscape->lock, flags); + + /* + * We have now enabled the codec chip, and so we should + * detect the AD1845 device ... + */ + if ((err = create_ad1845(card, CODEC_IO(params->port), params->irq, params->dma1)) < 0) { + printk(KERN_ERR "sscape: No AD1845 device at 0x%x, IRQ %d\n", + CODEC_IO(params->port), params->irq); + goto _release_card; + } +#define MIDI_DEVNUM 0 + if ((err = create_mpu401(card, MIDI_DEVNUM, MPU401_IO(params->port), params->mpu_irq)) < 0) { + printk(KERN_ERR "sscape: Failed to create MPU-401 device at 0x%x\n", + MPU401_IO(params->port)); + goto _release_card; + } + + /* + * Enable the master IRQ ... + */ + sscape_write(sscape, GA_INTENA_REG, 0x80); + + if ((err = snd_card_register(card)) < 0) { + printk(KERN_ERR "sscape: Failed to register sound card\n"); + goto _release_card; + } + + /* + * Initialize mixer + */ + sscape->midi_vol = 0; + host_write_ctrl_unsafe(sscape->io_base, CMD_SET_MIDI_VOL, 100); + host_write_ctrl_unsafe(sscape->io_base, 0, 100); + host_write_ctrl_unsafe(sscape->io_base, CMD_XXX_MIDI_VOL, 100); + + /* + * Now that we have successfully created this sound card, + * it is safe to store the pointer. + * NOTE: we only register the sound card's "destructor" + * function now that our "constructor" has completed. + */ + card->private_free = soundscape_free; + *rcardp = card; + + return 0; + + _release_card: + snd_card_free(card); + + _release_dma: + free_dma(params->dma1); + + _release_region: + release_resource(io_res); + kfree_nocheck(io_res); + + return err; +} + + +static int sscape_cards __devinitdata; +static struct params sscape_params[SNDRV_CARDS] __devinitdata; + +#ifdef CONFIG_PNP +static inline int __devinit get_next_autoindex(int i) +{ + while ((i < SNDRV_CARDS) && (port[i] != SNDRV_AUTO_PORT)) { + ++i; + } /* while */ + + return i; +} + + +static inline int __devinit is_port_known(unsigned io, struct params *params, int cards) +{ + while (--cards >= 0) { + if (params[cards].port == io) + return 1; + } /* while */ + + return 0; +} + +static int __devinit sscape_pnp_detect(struct pnp_card_link *pcard, + const struct pnp_card_device_id *pid) +{ + struct pnp_dev *dev; + static int idx = 0; + int ret; + + /* + * Allow this function to fail *quietly* if all the ISA PnP + * devices were configured using module parameters instead. + */ + if ((idx = get_next_autoindex(idx)) >= SNDRV_CARDS) { + return -ENOSPC; + } + + /* + * We have found a candidate ISA PnP card. Now we + * have to check that it has the devices that we + * expect it to have. + * + * We will NOT try and autoconfigure all of the resources + * needed and then activate the card as we are assuming that + * has already been done at boot-time using /proc/isapnp. + * We shall simply try to give each active card the resources + * that it wants. This is a sensible strategy for a modular + * system where unused modules are unloaded regularly. + * + * This strategy is utterly useless if we compile the driver + * into the kernel, of course. + */ + // printk(KERN_INFO "sscape: %s\n", card->name); + + /* + * Check that we still have room for another sound card ... + */ + if (sscape_cards >= SNDRV_CARDS) { + printk(KERN_ERR "sscape: No room for another ALSA device\n"); + return -ENOSPC; + } + + ret = -ENODEV; + + dev = pnp_request_card_device(pcard, pid->devs[0].id, NULL); + if (dev) { + struct params *this; + if (!pnp_is_active(dev)) { + if (pnp_activate_dev(dev) < 0) { + printk(KERN_INFO "sscape: device is inactive\n"); + return -EBUSY; + } + } + /* + * Read the correct parameters off the ISA PnP bus ... + */ + this = init_params(&sscape_params[sscape_cards], + index[idx], + id[idx], + pnp_port_start(dev, 0), + pnp_irq(dev, 0), + pnp_irq(dev, 1), + pnp_dma(dev, 0)); + + /* + * Do we know about this sound card already? + */ + if ( !is_port_known(this->port, sscape_params, sscape_cards) ) { + snd_card_t *card; + + ret = create_sscape(this, &card); + if (ret < 0) + return ret; + pnp_set_card_drvdata(pcard, card); + ++sscape_cards; + ++idx; + } + } + + return ret; +} + +static void __devexit sscape_pnp_remove(struct pnp_card_link * pcard) +{ + snd_card_t *card = (snd_card_t *) pnp_get_card_drvdata(pcard); + + pnp_set_card_drvdata(pcard, NULL); + snd_card_disconnect(card); + snd_card_free_in_thread(card); +} + +static struct pnp_card_driver sscape_pnpc_driver = { + .flags = PNP_DRIVER_RES_DO_NOT_CHANGE, + .name = "sscape", + .id_table = sscape_pnpids, + .probe = sscape_pnp_detect, + .remove = __devexit_p(sscape_pnp_remove), +}; + +#endif /* CONFIG_PNP */ + +static int __init sscape_manual_probe(struct params *params) +{ + int ret; + unsigned i; + snd_card_t *card; + + for (i = 0; i < SNDRV_CARDS; ++i) { + /* + * We do NOT probe for ports. + * If we're not given a port number for this + * card then we completely ignore this line + * of parameters. + */ + if (port[i] == SNDRV_AUTO_PORT) + continue; + + /* + * Make sure we were given ALL of the other parameters. + */ + if ( (irq[i] == SNDRV_AUTO_IRQ) || + (mpu_irq[i] == SNDRV_AUTO_IRQ) || + (dma[i] == SNDRV_AUTO_DMA) ) { + printk(KERN_INFO + "sscape: insufficient parameters, need IO, IRQ, MPU-IRQ and DMA\n"); + return -ENXIO; + } + + /* + * This cards looks OK ... + */ + init_params(params, index[i], id[i], port[i], irq[i], mpu_irq[i], dma[i]); + + ret = create_sscape(params, &card); + if (ret < 0) + return ret; + + sscape_card[sscape_cards] = card; + params++; + sscape_cards++; + } /* for */ + + return 0; +} + + +static void sscape_exit(void) +{ + unsigned i; + +#ifdef CONFIG_PNP + pnp_unregister_card_driver(&sscape_pnpc_driver); +#endif + for (i = 0; i < ARRAY_SIZE(sscape_card); ++i) { + snd_card_free(sscape_card[i]); + } /* for */ +} + + +static int __init sscape_init(void) +{ + int ret; + + /* + * First check whether we were passed any parameters. + * These MUST take precedence over ANY automatic way + * of allocating cards, because the operator is + * S-P-E-L-L-I-N-G it out for us... + */ + ret = sscape_manual_probe(sscape_params); + if (ret < 0) { + int i; + for (i = 0; i < sscape_cards; ++i) + snd_card_free(sscape_card[i]); + return ret; + } + +#ifdef CONFIG_PNP + if (sscape_cards < SNDRV_CARDS) { + ret = pnp_register_card_driver(&sscape_pnpc_driver); + if (ret < 0) { + sscape_exit(); + return ret; + } + } +#endif + + return 0; +} + +module_init(sscape_init); +module_exit(sscape_exit); + +#ifndef MODULE + +/* format is: snd-sscape=index,id,port,irq,mpu_irq,dma */ + +static int __init builtin_sscape_setup(char *str) +{ + static unsigned __initdata nr_dev; + + if (nr_dev >= SNDRV_CARDS) + return 0; + + (void)((get_option(&str, &index[nr_dev]) == 2) && + (get_option(&str, (int*)&id[nr_dev]) == 2) && + (get_option(&str, (int*)&port[nr_dev]) == 2) && + (get_option(&str, &irq[nr_dev]) == 2) && + (get_option(&str, &mpu_irq[nr_dev]) == 2) && + (get_option(&str, &dma[nr_dev]) == 2)); + + ++nr_dev; + return 1; +} + +__setup("snd-sscape=", builtin_sscape_setup); + +#endif + diff -Nru a/sound/isa/wavefront/wavefront.c b/sound/isa/wavefront/wavefront.c --- a/sound/isa/wavefront/wavefront.c Mon Jun 9 23:16:16 2003 +++ b/sound/isa/wavefront/wavefront.c Mon Jun 9 23:16:16 2003 @@ -179,6 +179,7 @@ */ if (cs4232_pcm_port[dev] != SNDRV_AUTO_PORT) + pnp_resource_change(&cfg->port_resource[0], cs4232_pcm_port[dev], 4); if (fm_port[dev] != SNDRV_AUTO_PORT) pnp_resource_change(&cfg->port_resource[1], fm_port[dev], 4); if (dma1[dev] != SNDRV_AUTO_DMA) @@ -710,6 +711,9 @@ cards += pnp_register_card_driver(&wavefront_pnpc_driver); #endif if (!cards) { +#ifdef CONFIG_PNP + pnp_unregister_card_driver(&wavefront_pnpc_driver); +#endif #ifdef MODULE printk (KERN_ERR "No WaveFront cards found or devices busy\n"); #endif @@ -722,7 +726,9 @@ { int idx; +#ifdef CONFIG_PNP pnp_unregister_card_driver(&wavefront_pnpc_driver); +#endif for (idx = 0; idx < SNDRV_CARDS; idx++) snd_card_free(snd_wavefront_legacy[idx]); } diff -Nru a/sound/oss/awe_wave.c b/sound/oss/awe_wave.c --- a/sound/oss/awe_wave.c Mon Jun 9 23:16:10 2003 +++ b/sound/oss/awe_wave.c Mon Jun 9 23:16:10 2003 @@ -2046,7 +2046,8 @@ awe_info.nr_voices = awe_max_voices; else awe_info.nr_voices = AWE_MAX_CHANNELS; - memcpy((char*)arg, &awe_info, sizeof(awe_info)); + if (copy_to_user((char*)arg, &awe_info, sizeof(awe_info))) + return -EFAULT; return 0; break; @@ -2063,10 +2064,12 @@ case SNDCTL_SYNTH_MEMAVL: return memsize - awe_free_mem_ptr() * 2; + break; default: printk(KERN_WARNING "AWE32: unsupported ioctl %d\n", cmd); return -EINVAL; + break; } } @@ -4314,7 +4317,8 @@ if (((cmd >> 8) & 0xff) != 'M') return -EINVAL; - level = *(int*)arg; + if (get_user(level, (int *)arg)) + return -EFAULT; level = ((level & 0xff) + (level >> 8)) / 2; DEBUG(0,printk("AWEMix: cmd=%x val=%d\n", cmd & 0xff, level)); @@ -4370,7 +4374,9 @@ level = 0; break; } - return *(int*)arg = level; + if (put_user(level, (int *)arg)) + return -EFAULT; + return level; } #endif /* CONFIG_AWE32_MIXER */ diff -Nru a/sound/oss/cmpci.c b/sound/oss/cmpci.c --- a/sound/oss/cmpci.c Mon Jun 9 23:16:13 2003 +++ b/sound/oss/cmpci.c Mon Jun 9 23:16:13 2003 @@ -580,15 +580,17 @@ spin_unlock_irqrestore(&s->lock, flags); } -static void trans_ac3(struct cm_state *s, void *dest, const char *source, int size) +static int trans_ac3(struct cm_state *s, void *dest, const char *source, int size) { int i = size / 2; + int err; unsigned long data; unsigned long *dst = (unsigned long *) dest; unsigned short *src = (unsigned short *)source; do { - data = (unsigned long) *src++; + if ((err = __get_user(data, src++))) + return err; data <<= 12; // ok for 16-bit data if (s->spdif_counter == 2 || s->spdif_counter == 3) data |= 0x40000000; // indicate AC-3 raw data @@ -605,6 +607,8 @@ if (s->spdif_counter == 384) s->spdif_counter = 0; } while (--i); + + return 0; } static void set_adc_rate_unlocked(struct cm_state *s, unsigned rate) @@ -1655,13 +1659,16 @@ continue; } if (s->status & DO_AC3_SW) { + int err; + // clip exceeded data, caught by 033 and 037 if (swptr + 2 * cnt > s->dma_dac.dmasize) cnt = (s->dma_dac.dmasize - swptr) / 2; - trans_ac3(s, s->dma_dac.rawbuf + swptr, buffer, cnt); + if ((err = trans_ac3(s, s->dma_dac.rawbuf + swptr, buffer, cnt))) + return err; swptr = (swptr + 2 * cnt) % s->dma_dac.dmasize; } else if (s->status & DO_DUAL_DAC) { - int i; + int i, err; unsigned long *src, *dst0, *dst1; src = (unsigned long *) buffer; @@ -1669,8 +1676,10 @@ dst1 = (unsigned long *) (s->dma_adc.rawbuf + swptr); // copy left/right sample at one time for (i = 0; i <= cnt / 4; i++) { - *dst0++ = *src++; - *dst1++ = *src++; + if ((err = __get_user(*dst0++, src++))) + return err; + if ((err = __get_user(*dst1++, src++))) + return err; } swptr = (swptr + cnt) % s->dma_dac.dmasize; } else { diff -Nru a/sound/oss/dmasound/Kconfig b/sound/oss/dmasound/Kconfig --- a/sound/oss/dmasound/Kconfig Mon Jun 9 23:16:12 2003 +++ b/sound/oss/dmasound/Kconfig Mon Jun 9 23:16:12 2003 @@ -14,7 +14,7 @@ config DMASOUND_AWACS tristate "PowerMac DMA sound support" - depends on ALL_PPC && SOUND + depends on PPC_PMAC && SOUND help If you want to use the internal audio of your PowerMac in Linux, answer Y to this question. This will provide a Sun-like /dev/audio, diff -Nru a/sound/oss/esssolo1.c b/sound/oss/esssolo1.c --- a/sound/oss/esssolo1.c Mon Jun 9 23:16:07 2003 +++ b/sound/oss/esssolo1.c Mon Jun 9 23:16:07 2003 @@ -915,9 +915,9 @@ { unsigned int minor = minor(inode->i_rdev); struct solo1_state *s = NULL; - struct pci_dev *pci_dev; + struct pci_dev *pci_dev = NULL; - pci_for_each_dev(pci_dev) { + while ((pci_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) { struct pci_driver *drvr; drvr = pci_dev_driver (pci_dev); if (drvr != &solo1_driver) @@ -1597,9 +1597,9 @@ unsigned int minor = minor(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); struct solo1_state *s = NULL; - struct pci_dev *pci_dev; + struct pci_dev *pci_dev = NULL; - pci_for_each_dev(pci_dev) { + while ((pci_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) { struct pci_driver *drvr; drvr = pci_dev_driver(pci_dev); @@ -1888,9 +1888,9 @@ DECLARE_WAITQUEUE(wait, current); unsigned long flags; struct solo1_state *s = NULL; - struct pci_dev *pci_dev; + struct pci_dev *pci_dev = NULL; - pci_for_each_dev(pci_dev) { + while ((pci_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) { struct pci_driver *drvr; drvr = pci_dev_driver(pci_dev); @@ -2113,9 +2113,9 @@ unsigned int minor = minor(inode->i_rdev); DECLARE_WAITQUEUE(wait, current); struct solo1_state *s = NULL; - struct pci_dev *pci_dev; + struct pci_dev *pci_dev = NULL; - pci_for_each_dev(pci_dev) { + while ((pci_dev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pci_dev)) != NULL) { struct pci_driver *drvr; drvr = pci_dev_driver(pci_dev); diff -Nru a/sound/oss/maestro.c b/sound/oss/maestro.c --- a/sound/oss/maestro.c Mon Jun 9 23:16:18 2003 +++ b/sound/oss/maestro.c Mon Jun 9 23:16:18 2003 @@ -2132,10 +2132,10 @@ { unsigned int minor = minor(inode->i_rdev); struct ess_card *card = NULL; - struct pci_dev *pdev; + struct pci_dev *pdev = NULL; struct pci_driver *drvr; - pci_for_each_dev(pdev) { + while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { drvr = pci_dev_driver (pdev); if (drvr == &maestro_pci_driver) { card = (struct ess_card*)pci_get_drvdata (pdev); @@ -2978,13 +2978,13 @@ unsigned int minor = minor(inode->i_rdev); struct ess_state *s = NULL; unsigned char fmtm = ~0, fmts = 0; - struct pci_dev *pdev; + struct pci_dev *pdev = NULL; /* * Scan the cards and find the channel. We only * do this at open time so it is ok */ - pci_for_each_dev(pdev) { + while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { struct ess_card *c; struct pci_driver *drvr; diff -Nru a/sound/oss/via82cxxx_audio.c b/sound/oss/via82cxxx_audio.c --- a/sound/oss/via82cxxx_audio.c Mon Jun 9 23:16:09 2003 +++ b/sound/oss/via82cxxx_audio.c Mon Jun 9 23:16:09 2003 @@ -1357,12 +1357,12 @@ { int minor = minor(inode->i_rdev); struct via_info *card; - struct pci_dev *pdev; + struct pci_dev *pdev = NULL; struct pci_driver *drvr; DPRINTK ("ENTER\n"); - pci_for_each_dev(pdev) { + while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { drvr = pci_dev_driver (pdev); if (drvr == &via_driver) { assert (pci_get_drvdata (pdev) != NULL); @@ -2982,8 +2982,8 @@ static int via_dsp_open (struct inode *inode, struct file *file) { int minor = minor(inode->i_rdev); - struct via_info *card; - struct pci_dev *pdev; + struct via_info *card = NULL; + struct pci_dev *pdev = NULL; struct via_channel *chan; struct pci_driver *drvr; int nonblock = (file->f_flags & O_NONBLOCK); @@ -2995,8 +2995,7 @@ return -EINVAL; } - card = NULL; - pci_for_each_dev(pdev) { + while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev)) != NULL) { drvr = pci_dev_driver (pdev); if (drvr == &via_driver) { assert (pci_get_drvdata (pdev) != NULL); diff -Nru a/sound/parisc/Kconfig b/sound/parisc/Kconfig --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/parisc/Kconfig Mon Jun 9 23:16:20 2003 @@ -0,0 +1,13 @@ +# ALSA PA-RISC drivers + +menu "ALSA PA-RISC devices" + depends on SND!=n && PARISC + +config SND_HARMONY + tristate "Harmony/Vivace sound chip" + depends on SND + help + Say 'Y' or 'M' to include support for Harmony/Vivace soundchip + on HP712s, 715/new and many other GSC based machines. + +endmenu diff -Nru a/sound/parisc/Makefile b/sound/parisc/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/parisc/Makefile Mon Jun 9 23:16:20 2003 @@ -0,0 +1,8 @@ +# +# Makefile for ALSA +# + +snd-harmony-objs := harmony.o + +# Toplevel Module Dependency +obj-$(CONFIG_SND_HARMONY) += snd-harmony.o diff -Nru a/sound/parisc/harmony.c b/sound/parisc/harmony.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/parisc/harmony.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,1147 @@ +/* + * Harmony chipset driver + * + * This is a sound driver for ASP's and Lasi's Harmony sound chip + * and is unlikely to be used for anything other than on a HP PA-RISC. + * + * Harmony is found in HP 712s, 715/new and many other GSC based machines. + * On older 715 machines you'll find the technically identical chip + * called 'Vivace'. Both Harmony and Vicace are supported by this driver. + * + * this ALSA driver is based on OSS driver by: + * Copyright 2000 (c) Linuxcare Canada, Alex deVries <alex@linuxcare.com> + * Copyright 2000-2002 (c) Helge Deller <deller@gmx.de> + * Copyright 2001 (c) Matthieu Delahaye <delahaym@esiee.fr> + * + * TODO: + * - use generic DMA interface and ioremap()/iounmap() + * - capture is still untested (and probaby non-working) + * - spin locks + * - implement non-consistent DMA pages + * - implement gain meter + * - module parameters + * - correct cleaning sequence + * - better error checking + * - try to have a better quality. + * + */ + +/* + * Harmony chipset 'modus operandi'. + * - This chipset is found in some HP 32bit workstations, like 712, or B132 class. + * most of controls are done through registers. Register are found at a fixed offset + * from the hard physical adress, given in struct dev by register_parisc_driver. + * + * Playback and recording use 4kb pages (dma or not, depending on the machine). + * + * Most of PCM playback & capture is done through interrupt. When harmony needs + * a new buffer to put recorded data or read played PCM, it sends an interrupt. + * Bits 2 and 10 of DSTATUS register are '1' when harmony needs respectively + * a new page for recording and playing. + * Interrupt are disabled/enabled by writing to bit 32 of DSTATUS. + * Adresses of next page to be played is put in PNXTADD register, next page + * to be recorded is put in RNXTADD. There is 2 read-only registers, PCURADD and + * RCURADD that provides adress of current page. + * + * Harmony has no way to controll full duplex or half duplex mode. It means + * that we always need to provide adresses of playback and capture data, even + * when this is not needed. That's why we statically alloc one graveyard + * buffer (to put recorded data in play-only mode) and a silence buffer. + * + * Bitrate, number of channels and data format are controlled with + * the CNTL register. + * + * Mixer work is done through one register (GAINCTL). Only input gain, + * output attenuation and general attenuation control is provided. There is + * also controls for enabling/disabling internal speaker and line + * input. + * + * Buffers used by this driver are all DMA consistent. Since harmony is + * not "real" pci device, we use a fake struct pci_dev for + * pci_alloc_consistent(). + * (note that some machines -712 for ex.- don't implement DMA consistent + * memory, so we will need to use kmalloc instead) + */ + +#include <linux/delay.h> +#include <sound/driver.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/time.h> +#include <linux/wait.h> +#include <sound/core.h> +#include <sound/control.h> +#include <sound/pcm.h> +#include <sound/rawmidi.h> +#define SNDRV_GET_ID +#include <sound/initval.h> +#include <sound/info.h> +#include <asm/hardware.h> +#include <asm/gsc.h> +#include <asm/io.h> + +MODULE_AUTHOR("Laurent Canet <canetl@esiee.fr>"); +MODULE_DESCRIPTION("ALSA Harmony sound driver"); +MODULE_LICENSE("GPL"); +MODULE_CLASSES("{sound}"); +MODULE_DEVICES("{{ALSA,Harmony soundcard}}"); + +#undef DEBUG +#ifdef DEBUG +# define DPRINTK printk +#else +# define DPRINTK(x,...) +#endif + +#define PFX "harmony: " + +#define MAX_PCM_DEVICES 1 +#define MAX_PCM_SUBSTREAMS 4 +#define MAX_MIDI_DEVICES 0 + +#define BUFFER_SIZE 4096 +#define MAX_BUFS 10 + +/* number of silence & graveyard buffers */ +#define GRAVEYARD_BUFS 3 +#define SILENCE_BUFS 3 + +#define MAX_BUFFER_SIZE (MAX_BUFS * BUFFER_SIZE) +#define HARMONY_BUF_SIZE BUFFER_SIZE + +#define HARMONY_CNTL_C 0x80000000 + +#define HARMONY_DSTATUS_PN 0x00000200 +#define HARMONY_DSTATUS_RN 0x00000002 +#define HARMONY_DSTATUS_IE 0x80000000 + +#define HARMONY_DF_16BIT_LINEAR 0x00000000 +#define HARMONY_DF_8BIT_ULAW 0x00000001 +#define HARMONY_DF_8BIT_ALAW 0x00000002 + +#define HARMONY_SS_MONO 0x00000000 +#define HARMONY_SS_STEREO 0x00000001 + +/* + * Channels Mask in mixer register + * try some "reasonable" default gain values + */ + +#define HARMONY_GAIN_TOTAL_SILENCE 0x00F00FFF + +/* the following should be enough (mixer is + * very sensible on harmony) + */ +#define HARMONY_GAIN_DEFAULT 0x0F2FF082 + + +/* useless since only one card is supported ATM */ +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; + +/* Register offset (from base hpa) */ +#define REG_ID 0x00 +#define REG_RESET 0x04 +#define REG_CNTL 0x08 +#define REG_GAINCTL 0x0C +#define REG_PNXTADD 0x10 +#define REG_PCURADD 0x14 +#define REG_RNXTADD 0x18 +#define REG_RCURADD 0x1C +#define REG_DSTATUS 0x20 +#define REG_OV 0x24 +#define REG_PIO 0x28 +#define REG_DIAG 0x3C + +/* + * main harmony structure + */ + +typedef struct snd_card_harmony { + + /* spinlocks (To be done) */ + spinlock_t mixer_lock; + spinlock_t control_lock; + + /* parameters */ + int irq; + unsigned long hpa; + int id; + int rev; + + u32 current_gain; + int data_format; /* HARMONY_DF_xx_BIT_xxx */ + int sample_rate; /* HARMONY_SR_xx_KHZ */ + int stereo_select; /* HARMONY_SS_MONO or HARMONY_SS_STEREO */ + int format_initialized; + + unsigned long ply_buffer; + int ply_buf; + int ply_count; + int ply_size; + int ply_stopped; + int ply_total; + + unsigned long cap_buffer; + int cap_buf; + int cap_count; + int cap_size; + int cap_stopped; + int cap_total; + + struct pci_dev *fake_pci_dev; /* The fake pci_dev needed for + pci_* functions under ccio. */ + + /* the graveyard buffer is used as recording buffer when playback, + * because harmony always want a buffer to put recorded data */ + + unsigned char *graveyard_addr; + dma_addr_t graveyard_dma; + int graveyard_count; + + /* same thing for silence buffer */ + unsigned char *silence_addr; + dma_addr_t silence_dma; + int silence_count; + + /* alsa stuff */ + snd_card_t *card; + snd_pcm_t *pcm; + snd_pcm_substream_t *playback_substream; + snd_pcm_substream_t *capture_substream; + snd_info_entry_t *proc_entry; +} snd_card_harmony_t; +#define chip_t snd_card_harmony_t + +static snd_card_t *snd_harmony_cards[SNDRV_CARDS] = SNDRV_DEFAULT_PTR; + +/* wait to be out of control mode */ +static inline void snd_harmony_wait_cntl(snd_card_harmony_t *harmony) +{ + int timeout = 5000; + + while ( (gsc_readl(harmony->hpa+REG_CNTL) & HARMONY_CNTL_C) && --timeout) + { + /* Wait */ ; + } + if (timeout == 0) DPRINTK(KERN_DEBUG PFX "Error: wait cntl timeouted\n"); +} + + +/* + * sample rate routines + */ +static unsigned int snd_card_harmony_rates[] = { + 5125, 6615, 8000, 9600, + 11025, 16000, 18900, 22050, + 27428, 32000, 33075, 37800, + 44100, 48000 +}; + +#define RATES sizeof(snd_card_harmony_rates) / sizeof(snd_card_harmony_rates[0]) + +static snd_pcm_hw_constraint_list_t hw_constraint_rates = { + .count = RATES, + .list = snd_card_harmony_rates, + .mask = 0, +}; + +#define HARMONY_SR_8KHZ 0x08 +#define HARMONY_SR_16KHZ 0x09 +#define HARMONY_SR_27KHZ 0x0A +#define HARMONY_SR_32KHZ 0x0B +#define HARMONY_SR_48KHZ 0x0E +#define HARMONY_SR_9KHZ 0x0F +#define HARMONY_SR_5KHZ 0x10 +#define HARMONY_SR_11KHZ 0x11 +#define HARMONY_SR_18KHZ 0x12 +#define HARMONY_SR_22KHZ 0x13 +#define HARMONY_SR_37KHZ 0x14 +#define HARMONY_SR_44KHZ 0x15 +#define HARMONY_SR_33KHZ 0x16 +#define HARMONY_SR_6KHZ 0x17 + +/* snd_card_harmony_rate_bits + * @rate: index of current data rate in list + * returns: harmony hex code for registers + */ +static unsigned int snd_card_harmony_rate_bits(int rate) +{ + unsigned int idx; + + for (idx = 0; idx <= RATES; idx++) + if (snd_card_harmony_rates[idx] == rate) break; + + switch (idx) { + case 0: return HARMONY_SR_5KHZ; + case 1: return HARMONY_SR_6KHZ; + case 2: return HARMONY_SR_8KHZ; + case 3: return HARMONY_SR_9KHZ; + case 4: return HARMONY_SR_11KHZ; + case 5: return HARMONY_SR_16KHZ; + case 6: return HARMONY_SR_18KHZ; + case 7: return HARMONY_SR_22KHZ; + case 8: return HARMONY_SR_27KHZ; + case 9: return HARMONY_SR_32KHZ; + case 10: return HARMONY_SR_33KHZ; + case 11: return HARMONY_SR_37KHZ; + case 12: return HARMONY_SR_44KHZ; + case 13: return HARMONY_SR_48KHZ; + default: /* fallback */ + return HARMONY_SR_44KHZ; + } +} + +/* + * update controls (data format, sample rate, number of channels) + * according to value supplied in data structure + */ +void snd_harmony_update_control(snd_card_harmony_t *harmony) +{ + u32 default_cntl; + + /* Set CNTL */ + default_cntl = (HARMONY_CNTL_C | /* The C bit */ + (harmony->data_format << 6) | /* Set the data format */ + (harmony->stereo_select << 5) | /* Stereo select */ + (harmony->sample_rate)); /* Set sample rate */ + + /* initialize CNTL */ + snd_harmony_wait_cntl(harmony); + + gsc_writel(default_cntl, harmony->hpa+REG_CNTL); + +} + +/* + * silence a buffer + * XXX: alsa could probably do this by itself + * XXX: memset hpmc, commented. + */ + +void snd_harmony_silence(snd_card_harmony_t *harmony, + void *addr, int length) +{ + u8 silence_char; + + switch(harmony->data_format) { + case HARMONY_DF_8BIT_ULAW: silence_char = 0x55; break; + case HARMONY_DF_8BIT_ALAW: silence_char = 0xff; break; + case HARMONY_DF_16BIT_LINEAR: + default: + silence_char = 0; + } + //memset(addr, silence_char, length); +} + +/* + * interruption controls routines + */ + +static void snd_harmony_disable_interrupts(snd_card_harmony_t *chip) +{ + snd_harmony_wait_cntl(chip); + gsc_writel(0, chip->hpa+REG_DSTATUS); +} + +static void snd_harmony_enable_interrupts(snd_card_harmony_t *chip) +{ + snd_harmony_wait_cntl(chip); + gsc_writel(HARMONY_DSTATUS_IE, chip->hpa+REG_DSTATUS); +} + +/* + * interruption routine: + * The interrupt routine must provide adresse of next physical pages + * used by harmony + */ +void snd_card_harmony_interrupt(int irq, void *dev, struct pt_regs *regs) +{ + snd_card_harmony_t *harmony = (snd_card_harmony_t *)dev; + u32 dstatus = 0; + unsigned long hpa = harmony->hpa; + + /* Turn off interrupts */ + snd_harmony_disable_interrupts(harmony); + + /* wait for control to free */ + snd_harmony_wait_cntl(harmony); + + /* Read dstatus and pcuradd (the current address) */ + dstatus = gsc_readl(hpa+REG_DSTATUS); + + /* Check if this is a request to get the next play buffer */ + if (dstatus & HARMONY_DSTATUS_PN) { + if (harmony->playback_substream) { + harmony->ply_buf += harmony->ply_count; + harmony->ply_buf %= harmony->ply_size; + + gsc_writel(harmony->ply_buffer + harmony->ply_buf, + hpa+REG_PNXTADD); + + snd_pcm_period_elapsed(harmony->playback_substream); + harmony->ply_total++; + } else { + gsc_writel(harmony->silence_dma + + (HARMONY_BUF_SIZE*harmony->silence_count), + hpa+REG_PNXTADD); + harmony->silence_count++; + harmony->silence_count %= SILENCE_BUFS; + } + } + + /* Check if we're being asked to fill in a recording buffer */ + if (dstatus & HARMONY_DSTATUS_RN) { + if (harmony->capture_substream) { + harmony->cap_buf += harmony->cap_count; + harmony->cap_buf %= harmony->cap_size; + + gsc_writel(harmony->cap_buffer + harmony->cap_buf, + hpa+REG_RNXTADD); + + snd_pcm_period_elapsed(harmony->capture_substream); + harmony->cap_total++; + } else { + /* graveyard buffer */ + gsc_writel(harmony->graveyard_dma + + (HARMONY_BUF_SIZE*harmony->graveyard_count), + hpa+REG_RNXTADD); + harmony->graveyard_count++; + harmony->graveyard_count %= GRAVEYARD_BUFS; + } + } + snd_harmony_enable_interrupts(harmony); +} + +/* + * proc entry + * this proc file will give some debugging info + */ + +static void snd_harmony_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer) +{ + snd_card_harmony_t *harmony = (snd_card_harmony_t *)entry->private_data; + + snd_iprintf(buffer, "LASI Harmony driver\nLaurent Canet <canetl@esiee.fr>\n\n"); + snd_iprintf(buffer, "IRQ %d, hpa %lx, id %d rev %d\n", + harmony->irq, harmony->hpa, + harmony->id, harmony->rev); + snd_iprintf(buffer, "Current gain %lx\n", (unsigned long) harmony->current_gain); + snd_iprintf(buffer, "\tsample rate=%d\n", harmony->sample_rate); + snd_iprintf(buffer, "\tstereo select=%d\n", harmony->stereo_select); + snd_iprintf(buffer, "\tbitperchan=%d\n\n", harmony->data_format); + + snd_iprintf(buffer, "Play status:\n"); + snd_iprintf(buffer, "\tstopped %d\n", harmony->ply_stopped); + snd_iprintf(buffer, "\tbuffer %lx, count %d\n", harmony->ply_buffer, harmony->ply_count); + snd_iprintf(buffer, "\tbuf %d size %d\n\n", harmony->ply_buf, harmony->ply_size); + + snd_iprintf(buffer, "Capture status:\n"); + snd_iprintf(buffer, "\tstopped %d\n", harmony->cap_stopped); + snd_iprintf(buffer, "\tbuffer %lx, count %d\n", harmony->cap_buffer, harmony->cap_count); + snd_iprintf(buffer, "\tbuf %d, size %d\n\n", harmony->cap_buf, harmony->cap_size); + + snd_iprintf(buffer, "Funny stats: total played=%d, recorded=%d\n\n", harmony->ply_total, harmony->cap_total); + + snd_iprintf(buffer, "Register:\n"); + snd_iprintf(buffer, "\tgainctl: %lx\n", (unsigned long) gsc_readl(harmony->hpa+REG_GAINCTL)); + snd_iprintf(buffer, "\tcntl: %lx\n", (unsigned long) gsc_readl(harmony->hpa+REG_CNTL)); + snd_iprintf(buffer, "\tid: %lx\n", (unsigned long) gsc_readl(harmony->hpa+REG_ID)); + snd_iprintf(buffer, "\tpcuradd: %lx\n", (unsigned long) gsc_readl(harmony->hpa+REG_PCURADD)); + snd_iprintf(buffer, "\trcuradd: %lx\n", (unsigned long) gsc_readl(harmony->hpa+REG_RCURADD)); + snd_iprintf(buffer, "\tpnxtadd: %lx\n", (unsigned long) gsc_readl(harmony->hpa+REG_PNXTADD)); + snd_iprintf(buffer, "\trnxtadd: %lx\n", (unsigned long) gsc_readl(harmony->hpa+REG_RNXTADD)); + snd_iprintf(buffer, "\tdstatus: %lx\n", (unsigned long) gsc_readl(harmony->hpa+REG_DSTATUS)); + snd_iprintf(buffer, "\tov: %lx\n\n", (unsigned long) gsc_readl(harmony->hpa+REG_OV)); + +} + +static void __devinit snd_harmony_proc_init(snd_card_harmony_t *harmony) +{ + snd_info_entry_t *entry; + + if ((entry = snd_info_create_card_entry(harmony->card, "harmony", harmony->card->proc_root)) != NULL) { + entry->content = SNDRV_INFO_CONTENT_TEXT; + entry->private_data = harmony; + entry->mode = S_IFREG | S_IRUGO | S_IWUSR; + entry->c.text.read_size = 2048; /* should be enough */ + entry->c.text.read = snd_harmony_proc_read; + if (snd_info_register(entry) < 0) { + snd_info_free_entry(entry); + entry = NULL; + } + } + harmony->proc_entry = entry; +} + +static void snd_harmony_proc_done(snd_card_harmony_t *harmony) +{ + if (harmony->proc_entry) { + snd_info_unregister(harmony->proc_entry); + harmony->proc_entry = NULL; + } +} + +/* + * PCM Stuff + */ + +static int snd_card_harmony_playback_ioctl(snd_pcm_substream_t * substream, + unsigned int cmd, + void *arg) +{ + return snd_pcm_lib_ioctl(substream, cmd, arg); +} + +static int snd_card_harmony_capture_ioctl(snd_pcm_substream_t * substream, + unsigned int cmd, + void *arg) +{ + return snd_pcm_lib_ioctl(substream, cmd, arg); +} + +static int snd_card_harmony_playback_trigger(snd_pcm_substream_t * substream, + int cmd) +{ + snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_STOP: + if (harmony->ply_stopped) + return -EBUSY; + harmony->ply_stopped = 1; + snd_harmony_disable_interrupts(harmony); + break; + case SNDRV_PCM_TRIGGER_START: + if (!harmony->ply_stopped) + return -EBUSY; + harmony->ply_stopped = 0; + /* write the location of the first buffer to play */ + gsc_writel(harmony->ply_buffer, harmony->hpa+REG_PNXTADD); + snd_harmony_enable_interrupts(harmony); + break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_SUSPEND: + DPRINTK(KERN_INFO PFX "received unimplemented trigger: %d\n", cmd); + default: + return -EINVAL; + } + return 0; +} + +static int snd_card_harmony_capture_trigger(snd_pcm_substream_t * substream, + int cmd) +{ + snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_STOP: + if (harmony->cap_stopped) + return -EBUSY; + harmony->cap_stopped = 1;; + snd_harmony_disable_interrupts(harmony); + break; + case SNDRV_PCM_TRIGGER_START: + if (!harmony->cap_stopped) + return -EBUSY; + harmony->cap_stopped = 0; + snd_harmony_enable_interrupts(harmony); + break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_SUSPEND: + DPRINTK(KERN_INFO PFX "Received unimplemented trigger: %d\n", cmd); + default: + return -EINVAL; + } + return 0; +} + +static int snd_card_harmony_playback_prepare(snd_pcm_substream_t * substream) +{ + snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + + harmony->ply_size = snd_pcm_lib_buffer_bytes(substream); + harmony->ply_count = snd_pcm_lib_period_bytes(substream); + harmony->ply_buf = 0; + harmony->ply_stopped = 1; + + /* initialize given sample rate */ + harmony->sample_rate = snd_card_harmony_rate_bits(runtime->rate); + + /* data format */ + if (snd_pcm_format_width(runtime->format) == 16) harmony->data_format = HARMONY_DF_16BIT_LINEAR; + else harmony->data_format = HARMONY_DF_8BIT_ULAW; + + /* number of channels */ + if (runtime->channels == 2) harmony->stereo_select = HARMONY_SS_STEREO; + else harmony->stereo_select = HARMONY_SS_MONO; + + DPRINTK(KERN_INFO PFX "Playback_prepare, sr=%d(%x), df=%x, ss=%x hpa=%lx\n", runtime->rate, + harmony->sample_rate, harmony->data_format, harmony->stereo_select, harmony->hpa); + snd_harmony_update_control(harmony); + harmony->format_initialized = 1; + harmony->ply_buffer = runtime->dma_addr; + + return 0; +} + +static int snd_card_harmony_capture_prepare(snd_pcm_substream_t * substream) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream); + + harmony->cap_size = snd_pcm_lib_buffer_bytes(substream); + harmony->cap_count = snd_pcm_lib_period_bytes(substream); + harmony->cap_count = 0; + harmony->cap_stopped = 1; + + /* initialize given sample rate */ + harmony->sample_rate = snd_card_harmony_rate_bits(runtime->rate); + + /* data format */ + if (snd_pcm_format_width(runtime->format) == 16) harmony->data_format = HARMONY_DF_16BIT_LINEAR; + else harmony->data_format = HARMONY_DF_8BIT_ULAW; + + /* number of channels */ + if (runtime->channels == 1) harmony->stereo_select = HARMONY_SS_MONO; + else if (runtime->channels == 2) harmony->stereo_select = HARMONY_SS_STEREO; + + snd_harmony_update_control(harmony); + harmony->format_initialized = 1; + + harmony->cap_buffer = runtime->dma_addr; + + return 0; +} + +static snd_pcm_uframes_t snd_card_harmony_capture_pointer(snd_pcm_substream_t * substream) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream); + unsigned long rcuradd; + int recorded; + + if (harmony->cap_stopped) return 0; + if (harmony->capture_substream == NULL) return 0; + + rcuradd = gsc_readl(harmony->hpa+REG_RCURADD); + recorded = (rcuradd - harmony->cap_buffer); + recorded %= harmony->cap_size; + + return bytes_to_frames(runtime, recorded); +} + +/* + */ + +static snd_pcm_uframes_t snd_card_harmony_playback_pointer(snd_pcm_substream_t * substream) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream); + int played; + long int pcuradd = gsc_readl(harmony->hpa+REG_PCURADD); + + if ((harmony->ply_stopped) || (harmony->playback_substream == NULL)) return 0; + if ((harmony->ply_buffer == 0) || (harmony->ply_size == 0)) return 0; + + played = (pcuradd - harmony->ply_buffer); + + printk(KERN_DEBUG PFX "Pointer is %lx-%lx = %d\n", pcuradd, harmony->ply_buffer, played); + + if (pcuradd > harmony->ply_buffer + harmony->ply_size) return 0; + + return bytes_to_frames(runtime, played); +} + +static snd_pcm_hardware_t snd_card_harmony_playback = +{ + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_JOINT_DUPLEX | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_BLOCK_TRANSFER), + .formats = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_BE | + SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_MU_LAW), + .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, + .rate_min = 5500, + .rate_max = 48000, + .channels_min = 1, + .channels_max = 2, + .buffer_bytes_max = MAX_BUFFER_SIZE, + .period_bytes_min = HARMONY_BUF_SIZE, + .period_bytes_max = HARMONY_BUF_SIZE, + .periods_min = 1, + .periods_max = MAX_BUFS, + .fifo_size = 0, +}; + +static snd_pcm_hardware_t snd_card_harmony_capture = +{ + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_JOINT_DUPLEX | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_BLOCK_TRANSFER), + .formats = (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_BE | + SNDRV_PCM_FMTBIT_A_LAW | SNDRV_PCM_FMTBIT_MU_LAW), + .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000, + .rate_min = 5500, + .rate_max = 48000, + .channels_min = 1, + .channels_max = 2, + .buffer_bytes_max = MAX_BUFFER_SIZE, + .period_bytes_min = HARMONY_BUF_SIZE, + .period_bytes_max = HARMONY_BUF_SIZE, + .periods_min = 1, + .periods_max = MAX_BUFS, + .fifo_size = 0, +}; + +static int snd_card_harmony_playback_open(snd_pcm_substream_t * substream) +{ + snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + int err; + + /* + * harmony is not "real" pci, but we need a pci_dev + * to alloc PCI DMA pages + */ + substream->dma_private = harmony->fake_pci_dev; + substream->dma_type = SNDRV_PCM_DMA_TYPE_PCI; + + harmony->playback_substream = substream; + runtime->hw = snd_card_harmony_playback; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraint_rates); + + if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) + return err; + + return 0; +} + +static int snd_card_harmony_capture_open(snd_pcm_substream_t * substream) +{ + snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + int err; + + + /* + * harmony is not "real" pci, but we need a pci_dev + * to alloc PCI DMA pages + */ + substream->dma_private = harmony->fake_pci_dev; + substream->dma_type = SNDRV_PCM_DMA_TYPE_PCI; + + harmony->capture_substream = substream; + runtime->hw = snd_card_harmony_capture; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraint_rates); + if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) + return err; + return 0; + +} + +static int snd_card_harmony_playback_close(snd_pcm_substream_t * substream) +{ + snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream); + snd_pcm_lib_free_pages(substream); + + harmony->playback_substream = NULL; + harmony->ply_size = 0; + harmony->ply_buf = 0; + harmony->ply_buffer = 0; + harmony->ply_count = 0; + harmony->ply_stopped = 1; + harmony->format_initialized = 0; + + return 0; +} + +static int snd_card_harmony_capture_close(snd_pcm_substream_t * substream) +{ + snd_card_harmony_t *harmony = snd_pcm_substream_chip(substream); + + snd_pcm_lib_free_pages(substream); + + harmony->capture_substream = NULL; + harmony->cap_size = 0; + harmony->cap_buf = 0; + harmony->cap_buffer = 0; + harmony->cap_count = 0; + harmony->cap_stopped = 1; + harmony->format_initialized = 0; + + return 0; +} + +static int snd_card_harmony_hw_params(snd_pcm_substream_t *substream, + snd_pcm_hw_params_t * hw_params) +{ + snd_pcm_runtime_t *runtime = substream->runtime; + int err; + + err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); + DPRINTK(KERN_INFO PFX "HW Params returned %d, dma_addr %lx\n", err, + (unsigned long)runtime->dma_addr); + return err; +} + +static int snd_card_harmony_hw_free(snd_pcm_substream_t *substream) +{ + snd_pcm_lib_free_pages(substream); + return 0; +} + +static snd_pcm_ops_t snd_card_harmony_playback_ops = { + .open = snd_card_harmony_playback_open, + .close = snd_card_harmony_playback_close, + .ioctl = snd_card_harmony_playback_ioctl, + .hw_params = snd_card_harmony_hw_params, + .hw_free = snd_card_harmony_hw_free, + .prepare = snd_card_harmony_playback_prepare, + .trigger = snd_card_harmony_playback_trigger, + .pointer = snd_card_harmony_playback_pointer, +}; + +static snd_pcm_ops_t snd_card_harmony_capture_ops = { + .open = snd_card_harmony_capture_open, + .close = snd_card_harmony_capture_close, + .ioctl = snd_card_harmony_capture_ioctl, + .hw_params = snd_card_harmony_hw_params, + .hw_free = snd_card_harmony_hw_free, + .prepare = snd_card_harmony_capture_prepare, + .trigger = snd_card_harmony_capture_trigger, + .pointer = snd_card_harmony_capture_pointer, +}; + +static int snd_card_harmony_pcm_init(snd_card_harmony_t *harmony, int device) +{ + snd_pcm_t *pcm; + int err; + + /* Request that IRQ */ + if (request_irq(harmony->irq, snd_card_harmony_interrupt, 0 ,"harmony", harmony)) { + printk(KERN_ERR PFX "Error requesting irq %d.\n", harmony->irq); + return -EFAULT; + } + + snd_harmony_disable_interrupts(harmony); + + if ((err = snd_pcm_new(harmony->card, "Harmony", device, 1, 1, &pcm)) < 0) + return err; + + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_card_harmony_playback_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_harmony_capture_ops); + + pcm->private_data = harmony; + pcm->info_flags = 0; + strcpy(pcm->name, "Harmony"); + harmony->pcm = pcm; + + /* initialize graveyard buffer */ + harmony->graveyard_addr = snd_malloc_pci_pages(harmony->fake_pci_dev, + HARMONY_BUF_SIZE*GRAVEYARD_BUFS, &harmony->graveyard_dma); + harmony->graveyard_count = 0; + + /* initialize silence buffers */ + harmony->silence_addr = snd_malloc_pci_pages(harmony->fake_pci_dev, + HARMONY_BUF_SIZE*SILENCE_BUFS, &harmony->silence_dma); + harmony->silence_count = 0; + + + harmony->ply_stopped = harmony->cap_stopped = 1; + + harmony->playback_substream = NULL; + harmony->capture_substream = NULL; + harmony->graveyard_count = 0; + + return 0; +} + +/* + * mixer routines + */ + +static void snd_harmony_set_new_gain(snd_card_harmony_t *harmony) +{ + DPRINTK(KERN_INFO PFX "Setting new gain %x at %lx\n", harmony->current_gain, harmony->hpa+REG_GAINCTL); + /* Wait until we're out of control mode */ + snd_harmony_wait_cntl(harmony); + + gsc_writel(harmony->current_gain, harmony->hpa+REG_GAINCTL); +} + +#define HARMONY_VOLUME(xname, left_shift, right_shift, mask, invert) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_harmony_mixercontrol_info, \ + .get = snd_harmony_volume_get, .put = snd_harmony_volume_put, \ + .private_value = ((left_shift) | ((right_shift) << 8) | ((mask) << 16) | ((invert) << 24)) } + +static int snd_harmony_mixercontrol_info(snd_kcontrol_t * kcontrol, snd_ctl_elem_info_t * uinfo) +{ + int mask = (kcontrol->private_value >> 16) & 0xff; + int left_shift = (kcontrol->private_value) & 0xff; + int right_shift = (kcontrol->private_value >> 8) & 0xff; + + uinfo->type = (mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER); + uinfo->count = (left_shift == right_shift) ? 1 : 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = mask; + return 0; +} + +static int snd_harmony_volume_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + snd_card_harmony_t *harmony = _snd_kcontrol_chip(kcontrol); + int shift_left = (kcontrol->private_value) & 0xff; + int shift_right = (kcontrol->private_value >> 8) & 0xff; + int mask = (kcontrol->private_value >> 16) & 0xff; + int invert = (kcontrol->private_value >> 24) & 0xff; + unsigned long flags; + int left, right; + + spin_lock_irqsave(&harmony->mixer_lock, flags); + left = (harmony->current_gain >> shift_left) & mask; + right = (harmony->current_gain >> shift_right) & mask; + + if (invert) { + left = mask - left; + right = mask - right; + } + ucontrol->value.integer.value[0] = left; + ucontrol->value.integer.value[1] = right; + spin_unlock_irqrestore(&harmony->mixer_lock, flags); + + return 0; +} + +static int snd_harmony_volume_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + snd_card_harmony_t *harmony = _snd_kcontrol_chip(kcontrol); + int shift_left = (kcontrol->private_value) & 0xff; + int shift_right = (kcontrol->private_value >> 8) & 0xff; + int mask = (kcontrol->private_value >> 16) & 0xff; + int invert = (kcontrol->private_value >> 24) & 0xff; + unsigned long flags; + int left, right; + int old_gain = harmony->current_gain; + + left = ucontrol->value.integer.value[0] & mask; + right = ucontrol->value.integer.value[1] & mask; + if (invert) { + left = mask - left; + right = mask - right; + } + + spin_lock_irqsave(&harmony->mixer_lock, flags); + harmony->current_gain = harmony->current_gain & ~( (mask << shift_right) | (mask << shift_left)); + harmony->current_gain = harmony->current_gain | ((left << shift_left) | (right << shift_right) ); + snd_harmony_set_new_gain(harmony); + spin_unlock_irqrestore(&harmony->mixer_lock, flags); + + return (old_gain - harmony->current_gain); +} + +#define HARMONY_CONTROLS (sizeof(snd_harmony_controls)/sizeof(snd_kcontrol_new_t)) + +static snd_kcontrol_new_t snd_harmony_controls[] = { +HARMONY_VOLUME("PCM Capture Volume", 12, 16, 0x0f, 0), +HARMONY_VOLUME("Master Volume", 20, 20, 0x0f, 1), +HARMONY_VOLUME("PCM Playback Volume", 6, 0, 0x3f, 1), +}; + +static void snd_harmony_reset_codec(snd_card_harmony_t *harmony) +{ + snd_harmony_wait_cntl(harmony); + gsc_writel(1, harmony->hpa+REG_RESET); + mdelay(50); /* wait 50 ms */ + gsc_writel(0, harmony->hpa+REG_RESET); +} + +/* + * Mute all the output and reset Harmony. + */ + +static void __init snd_harmony_mixer_reset(snd_card_harmony_t *harmony) +{ + harmony->current_gain = HARMONY_GAIN_TOTAL_SILENCE; + snd_harmony_set_new_gain(harmony); + snd_harmony_reset_codec(harmony); + harmony->current_gain = HARMONY_GAIN_DEFAULT; + snd_harmony_set_new_gain(harmony); +} + + +int __init snd_card_harmony_mixer_init(snd_card_harmony_t *harmony) +{ + snd_card_t *card = harmony->card; + int idx, err; + + snd_assert(harmony != NULL, return -EINVAL); + strcpy(card->mixername, "Harmony Gain control interface"); + + for (idx = 0; idx < HARMONY_CONTROLS; idx++) { + if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_harmony_controls[idx], harmony))) < 0) + return err; + } + + snd_harmony_mixer_reset(harmony); + + return 0; +} + +static int snd_card_harmony_create(snd_card_t *card, struct parisc_device *pa_dev, snd_card_harmony_t *harmony) +{ + u32 cntl; + + harmony->card = card; + + /* Set the HPA of harmony */ + harmony->hpa = pa_dev->hpa; + + + harmony->irq = pa_dev->irq; + if (!harmony->irq) { + printk(KERN_ERR PFX "no irq found\n"); + return -ENODEV; + } + + /* Grab the ID and revision from the device */ + harmony->id = (gsc_readl(harmony->hpa+REG_ID)&0x00ff0000) >> 16; + if ((harmony->id | 1) != 0x15) { + printk(KERN_WARNING PFX "wrong harmony id 0x%02x\n", harmony->id); + return -EBUSY; + } + cntl = gsc_readl(harmony->hpa+REG_CNTL); + harmony->rev = (cntl>>20) & 0xff; + + printk(KERN_INFO "Lasi Harmony Audio driver h/w id %i, rev. %i at 0x%lx, IRQ %i\n", harmony->id, harmony->rev, pa_dev->hpa, harmony->irq); + + /* Make sure the control bit isn't set, although I don't think it + ever is. */ + if (cntl & HARMONY_CNTL_C) { + printk(KERN_WARNING PFX "CNTL busy\n"); + harmony->hpa = 0; + return -EBUSY; + } + + /* a fake pci_dev is needed for pci_* functions under ccio */ + harmony->fake_pci_dev = ccio_get_fake(pa_dev); + return 0; +} + +static int __init snd_card_harmony_probe(struct parisc_device *pa_dev) +{ + static int dev; + snd_card_harmony_t *chip; + snd_card_t *card; + int err; + + if (dev >= SNDRV_CARDS) + return -ENODEV; + if (!enable[dev]) { + dev++; + return -ENOENT; + } + + snd_harmony_cards[dev] = snd_card_new(index[dev], id[dev], THIS_MODULE, + sizeof(snd_card_harmony_t)); + card = snd_harmony_cards[dev]; + + if (card == NULL) + return -ENOMEM; + chip = (struct snd_card_harmony *)card->private_data; + + if ((err = snd_card_harmony_create(card, pa_dev, chip)) < 0) { + printk(KERN_ERR PFX "Creation failed\n"); + snd_card_free(card); + return err; + } + if ((err = snd_card_harmony_pcm_init(chip, dev)) < 0) { + printk(KERN_ERR PFX "PCM Init failed\n"); + snd_card_free(card); + return err; + } + if ((err = snd_card_harmony_mixer_init(chip)) < 0) { + printk(KERN_ERR PFX "Mixer init failed\n"); + snd_card_free(card); + return err; + } + + snd_harmony_proc_init(chip); + + strcpy(card->driver, "Harmony"); + strcpy(card->shortname, "ALSA driver for LASI Harmony"); + sprintf(card->longname, "%s at h/w, id %i, rev. %i hpa 0x%lx, IRQ %i\n",card->shortname, chip->id, chip->rev, pa_dev->hpa, chip->irq); + + if ((err = snd_card_register(card)) < 0) { + snd_card_free(card); + return err; + } + + printk(KERN_DEBUG PFX "Successfully registered harmony pcm backend & mixer %d\n", dev); + dev++; + return 0; +} + +static struct parisc_device_id snd_card_harmony_devicetbl[] = { + { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007A }, /* Bushmaster/Flounder */ + { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007B }, /* 712/715 Audio */ + { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007E }, /* Pace Audio */ + { HPHW_FIO, HVERSION_REV_ANY_ID, HVERSION_ANY_ID, 0x0007F }, /* Outfield / Coral II */ + { 0, } +}; + +MODULE_DEVICE_TABLE(parisc, snd_card_harmony_devicetbl); + +/* + * bloc device parisc. c'est une structure qui definit un device + * que l'on trouve sur parisc. + * On y trouve les differents numeros HVERSION correspondant au device + * en question (ce qui permet a l'inventory de l'identifier) et la fonction + * d'initialisation du chose + */ + +static struct parisc_driver snd_card_harmony_driver = { + name: "Lasi ALSA Harmony", + id_table: snd_card_harmony_devicetbl, + probe: snd_card_harmony_probe, +}; + +static int __init alsa_card_harmony_init(void) +{ + int err; + + if ((err = register_parisc_driver(&snd_card_harmony_driver)) < 0) { + printk(KERN_ERR "Harmony soundcard not found or device busy\n"); + return err; + } + + return 0; +} + +static void __exit alsa_card_harmony_exit(void) +{ + int idx; + snd_card_harmony_t *harmony; + + for (idx = 0; idx < SNDRV_CARDS; idx++) + { + if (snd_harmony_cards[idx] != NULL) + { + DPRINTK(KERN_INFO PFX "Freeing card %d\n", idx); + harmony = snd_harmony_cards[idx]->private_data; + snd_harmony_proc_done(harmony); + free_irq(harmony->irq, snd_card_harmony_interrupt); + printk(KERN_INFO PFX "Card unloaded %d, irq=%d\n", idx, harmony->irq); + snd_card_free(snd_harmony_cards[idx]); + } + } +} + +module_init(alsa_card_harmony_init) +module_exit(alsa_card_harmony_exit) diff -Nru a/sound/pci/Kconfig b/sound/pci/Kconfig --- a/sound/pci/Kconfig Mon Jun 9 23:16:10 2003 +++ b/sound/pci/Kconfig Mon Jun 9 23:16:10 2003 @@ -9,6 +9,12 @@ help Say 'Y' or 'M' to include support for ALI PCI Audio M5451 sound core. +config SND_AZT3328 + tristate "Aztech AZF3328 / PCI168 (EXPERIMENTAL)" + depends on SND && EXPERIMENTAL + help + Say 'Y' or 'M' to include support for Aztech AZF3328 (PCI168) soundcards. + config SND_CS46XX tristate "Cirrus Logic (Sound Fusion) CS4280/CS461x/CS462x/CS463x" depends on SND && SOUND_GAMEPORT @@ -176,6 +182,12 @@ depends on SND help Say 'Y' or 'M' to include support for VIA VT82C686A/B, VT8233 South Bridge. + +config SND_VX222 + tristate "Digigram VX222" + depends on SND + help + Say 'Y' or 'M' to include support for Digigram VX222 soundcards. endmenu diff -Nru a/sound/pci/Makefile b/sound/pci/Makefile --- a/sound/pci/Makefile Mon Jun 9 23:16:05 2003 +++ b/sound/pci/Makefile Mon Jun 9 23:16:05 2003 @@ -4,6 +4,7 @@ # snd-als4000-objs := als4000.o +snd-azt3328-objs := azt3328.o snd-cmipci-objs := cmipci.o snd-cs4281-objs := cs4281.o snd-ens1370-objs := ens1370.o @@ -33,5 +34,6 @@ obj-$(CONFIG_SND_RME96) += snd-rme96.o obj-$(CONFIG_SND_SONICVIBES) += snd-sonicvibes.o obj-$(CONFIG_SND_VIA82XX) += snd-via82xx.o +obj-$(CONFIG_SND_AZT3328) += snd-azt3328.o -obj-$(CONFIG_SND) += ac97/ ali5451/ cs46xx/ emu10k1/ korg1212/ nm256/ rme9652/ trident/ ymfpci/ ice1712/ +obj-$(CONFIG_SND) += ac97/ ali5451/ cs46xx/ emu10k1/ korg1212/ nm256/ rme9652/ trident/ ymfpci/ ice1712/ vx222/ diff -Nru a/sound/pci/ac97/Makefile b/sound/pci/ac97/Makefile --- a/sound/pci/ac97/Makefile Mon Jun 9 23:16:14 2003 +++ b/sound/pci/ac97/Makefile Mon Jun 9 23:16:14 2003 @@ -13,6 +13,7 @@ obj-$(CONFIG_SND_ES1968) += snd-ac97-codec.o obj-$(CONFIG_SND_FM801) += snd-ac97-codec.o obj-$(CONFIG_SND_ICE1712) += snd-ac97-codec.o +obj-$(CONFIG_SND_ICE1724) += snd-ac97-codec.o obj-$(CONFIG_SND_INTEL8X0) += snd-ac97-codec.o obj-$(CONFIG_SND_MAESTRO3) += snd-ac97-codec.o obj-$(CONFIG_SND_VIA82XX) += snd-ac97-codec.o diff -Nru a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c --- a/sound/pci/ac97/ac97_codec.c Mon Jun 9 23:16:10 2003 +++ b/sound/pci/ac97/ac97_codec.c Mon Jun 9 23:16:10 2003 @@ -89,7 +89,6 @@ }; static const ac97_codec_id_t snd_ac97_codec_ids[] = { -{ 0x014b0502, 0xffffffff, "NM256AV", NULL, NULL }, // FIXME: which real one? { 0x414b4d00, 0xffffffff, "AK4540", NULL, NULL }, { 0x414b4d01, 0xffffffff, "AK4542", NULL, NULL }, { 0x414b4d02, 0xffffffff, "AK4543", NULL, NULL }, @@ -104,6 +103,8 @@ { 0x41445363, 0xffffffff, "AD1886A", patch_ad1881, NULL }, { 0x41445370, 0xffffffff, "AD1980", patch_ad1980, NULL }, { 0x41445372, 0xffffffff, "AD1981A", patch_ad1881, NULL }, +{ 0x41445374, 0xffffffff, "AD1981B", patch_ad1881, NULL }, +{ 0x41445375, 0xffffffff, "AD1985", patch_ad1980, NULL }, { 0x414c4300, 0xfffffff0, "RL5306", NULL, NULL }, { 0x414c4310, 0xfffffff0, "RL5382", NULL, NULL }, { 0x414c4320, 0xfffffff0, "RL5383", NULL, NULL }, @@ -112,6 +113,7 @@ { 0x414c4730, 0xffffffff, "ALC101", NULL, NULL }, { 0x414c4740, 0xfffffff0, "ALC202", NULL, NULL }, { 0x414c4750, 0xfffffff0, "ALC250", NULL, NULL }, +{ 0x414c4770, 0xfffffff0, "ALC203", NULL, NULL }, { 0x434d4941, 0xffffffff, "CMI9738", NULL, NULL }, { 0x434d4961, 0xffffffff, "CMI9739", patch_cm9739, NULL }, { 0x43525900, 0xfffffff8, "CS4297", NULL, NULL }, @@ -122,6 +124,7 @@ { 0x43525948, 0xfffffff8, "CS4201", NULL, NULL }, { 0x43525958, 0xfffffff8, "CS4205", patch_cirrus_spdif, NULL }, { 0x43525960, 0xfffffff8, "CS4291", NULL, NULL }, +{ 0x43525970, 0xfffffff8, "CS4202", NULL, NULL }, { 0x43585421, 0xffffffff, "HSD11246", NULL, NULL }, // SmartMC II { 0x43585428, 0xfffffff8, "Cx20468", patch_conexant, NULL }, // SmartAMC fixme: the mask might be different { 0x44543031, 0xfffffff0, "DT0398", NULL, NULL }, @@ -130,10 +133,13 @@ { 0x48525300, 0xffffff00, "HMP9701", NULL, NULL }, { 0x49434501, 0xffffffff, "ICE1230", NULL, NULL }, { 0x49434511, 0xffffffff, "ICE1232", NULL, NULL }, // alias VIA VT1611A? +{ 0x49434514, 0xffffffff, "ICE1232A", NULL, NULL }, { 0x49434551, 0xffffffff, "VT1616", NULL, NULL }, +{ 0x49434552, 0xffffffff, "VT1616i", NULL, NULL }, // VT1616 compatible (chipset integrated) { 0x49544520, 0xffffffff, "IT2226E", NULL, NULL }, { 0x4e534300, 0xffffffff, "LM4540/43/45/46/48", NULL, NULL }, // only guess --jk { 0x4e534331, 0xffffffff, "LM4549", NULL, NULL }, +{ 0x4e534350, 0xffffffff, "LM4550", NULL, NULL }, { 0x50534304, 0xffffffff, "UCB1400", NULL, NULL }, { 0x53494c20, 0xffffffe0, "Si3036/8", NULL, NULL }, { 0x54524102, 0xffffffff, "TR28022", NULL, NULL }, @@ -143,10 +149,12 @@ { 0x54584e20, 0xffffffff, "TLC320AD9xC", NULL, NULL }, { 0x56494161, 0xffffffff, "VIA1612A", NULL, NULL }, // modified ICE1232 with S/PDIF { 0x57454301, 0xffffffff, "W83971D", NULL, NULL }, -{ 0x574d4c00, 0xffffffff, "WM9701A", patch_wolfson00,NULL }, -{ 0x574d4c03, 0xffffffff, "WM9703/9707", patch_wolfson03,NULL }, -{ 0x574d4c04, 0xffffffff, "WM9704/quad", patch_wolfson04,NULL }, -{ 0x574d4c05, 0xffffffff, "WM9705", NULL, NULL }, // patch? +{ 0x574d4c00, 0xffffffff, "WM9701A", NULL, NULL }, +{ 0x574d4C03, 0xffffffff, "WM9703/WM9707/WM9708/WM9717", patch_wolfson03, NULL}, +{ 0x574d4C04, 0xffffffff, "WM9704M/WM9704Q", patch_wolfson04, NULL}, +{ 0x574d4C05, 0xffffffff, "WM9705/WM9710", patch_wolfson05, NULL}, +{ 0x574d4C09, 0xffffffff, "WM9709", NULL, NULL}, +{ 0x574d4C12, 0xffffffff, "WM9711/WM9712", patch_wolfson11, NULL}, { 0x594d4800, 0xffffffff, "YMF743", NULL, NULL }, { 0x594d4802, 0xffffffff, "YMF752", NULL, NULL }, { 0x594d4803, 0xffffffff, "YMF753", patch_yamaha_ymf753, NULL }, @@ -157,6 +165,7 @@ { 0x83847609, 0xffffffff, "STAC9721/23", patch_sigmatel_stac9721, NULL }, { 0x83847644, 0xffffffff, "STAC9744", patch_sigmatel_stac9744, NULL }, { 0x83847650, 0xffffffff, "STAC9750/51", NULL, NULL }, // patch? +{ 0x83847652, 0xffffffff, "STAC9752/53", NULL, NULL }, // patch? { 0x83847656, 0xffffffff, "STAC9756/57", patch_sigmatel_stac9756, NULL }, { 0x83847666, 0xffffffff, "STAC9766/67", NULL, NULL }, // patch? { 0, 0, NULL, NULL, NULL } @@ -181,7 +190,7 @@ /* 14 */ "Binaura 3D Audio Enhancement", /* 15 */ "ESS Technology Stereo Enhancement", /* 16 */ "Harman International VMAx", - /* 17 */ "Nvidea 3D Stereo Enhancement", + /* 17 */ "Nvidea/IC Ensemble/KS Waves 3D Stereo Enhancement", /* 18 */ "Philips Incredible Sound", /* 19 */ "Texas Instruments 3D Stereo Enhancement", /* 20 */ "VLSI Technology 3D Stereo Enhancement", @@ -1078,7 +1087,6 @@ /* 7: Independent Master Volume Left */ /* 8: reserved */ AC97_SINGLE("Line-In As Surround", AC97_ALC650_MULTICH, 9, 1, 0), - AC97_SINGLE("Mic As Center/LFE", AC97_ALC650_MULTICH, 10, 1, 0), AC97_SINGLE("Swap Surround Slot", AC97_ALC650_MULTICH, 14, 1, 0), #if 0 /* always set in patch_alc650 */ AC97_SINGLE("IEC958 Input Clock Enable", AC97_ALC650_CLOCK, 0, 1, 0), @@ -1090,6 +1098,43 @@ #endif }; +static const snd_kcontrol_new_t snd_ac97_control_alc650_mic = +AC97_SINGLE("Mic As Center/LFE", AC97_ALC650_MULTICH, 10, 1, 0); + + +static int snd_ac97_alc650_mic_gpio_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + ucontrol->value.integer.value[0] = (ac97->regs[AC97_ALC650_MULTICH] >> 10) & 1; + return 0; +} + +static int snd_ac97_alc650_mic_gpio_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + ac97_t *ac97 = snd_kcontrol_chip(kcontrol); + int change; + change = snd_ac97_update_bits(ac97, AC97_ALC650_MULTICH, 1 << 10, + ucontrol->value.integer.value[0] ? (1 << 10) : 0); + if (change) { + /* GPIO0 write for mic */ + snd_ac97_update_bits(ac97, 0x76, 0x01, + ucontrol->value.integer.value[0] ? 0 : 0x01); + /* GPIO0 high for mic */ + snd_ac97_update_bits(ac97, 0x78, 0x100, + ucontrol->value.integer.value[0] ? 0 : 0x100); + } + return change; +} + +static const snd_kcontrol_new_t snd_ac97_control_alc650_mic_gpio = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Mic As Center/LFE", + .info = snd_ac97_info_single, + .get = snd_ac97_alc650_mic_gpio_get, + .put = snd_ac97_alc650_mic_gpio_put, + .private_value = (1 << 16), /* for info */ +}; + static const snd_kcontrol_new_t snd_ac97_spdif_controls_alc650[] = { AC97_SINGLE("IEC958 Capture Switch", AC97_ALC650_MULTICH, 11, 1, 0), AC97_SINGLE("Analog to IEC958 Output", AC97_ALC650_MULTICH, 12, 1, 0), @@ -1634,18 +1679,18 @@ ac97->spec.ad18xx.pcmreg[2] = 0x9f1f; } } else { + unsigned int pcm_ctrls = 2; /* FIXME: C-Media chips have no PCM volume!! */ if (/*ac97->id == 0x434d4941 ||*/ ac97->id == 0x434d4942 || ac97->id == 0x434d4961) - goto no_pcm; - for (idx = 0; idx < 2; idx++) + pcm_ctrls = 1; + for (idx = 0; idx < pcm_ctrls; idx++) if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_pcm[idx], ac97))) < 0) return err; } snd_ac97_write_cache(ac97, AC97_PCM, 0x9f1f); - no_pcm: /* build Capture controls */ for (idx = 0; idx < 3; idx++) if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_capture[idx], ac97))) < 0) @@ -1829,9 +1874,14 @@ return err; break; case AC97_ID_ALC650: + /* detect ALC650 rev.E of later */ for (idx = 0; idx < ARRAY_SIZE(snd_ac97_controls_alc650); idx++) if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_alc650[idx], ac97))) < 0) return err; + if ((err = snd_ctl_add(card, snd_ac97_cnew(ac97->spec.dev_flags ? + &snd_ac97_control_alc650_mic : + &snd_ac97_control_alc650_mic_gpio, ac97))) < 0) + return err; if (ac97->ext_id & AC97_EI_SPDIF) { for (idx = 0; idx < ARRAY_SIZE(snd_ac97_spdif_controls_alc650); idx++) if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_spdif_controls_alc650[idx], ac97))) < 0) @@ -2024,13 +2074,17 @@ snd_assert(rac97 != NULL, return -EINVAL); *rac97 = NULL; snd_assert(card != NULL && _ac97 != NULL, return -EINVAL); - ac97 = snd_magic_kcalloc(ac97_t, 0, GFP_KERNEL); + ac97 = snd_magic_kmalloc(ac97_t, 0, GFP_KERNEL); if (ac97 == NULL) return -ENOMEM; *ac97 = *_ac97; ac97->card = card; spin_lock_init(&ac97->reg_lock); + if (ac97->pci) { + pci_read_config_word(ac97->pci, PCI_SUBSYSTEM_VENDOR_ID, &ac97->subsystem_vendor); + pci_read_config_word(ac97->pci, PCI_SUBSYSTEM_ID, &ac97->subsystem_device); + } if (ac97->reset) { ac97->reset(ac97); goto __access_ok; @@ -2058,10 +2112,13 @@ } /* test for AC'97 */ - /* test if we can write to the record gain volume register */ - snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x8a06); - if ((err = snd_ac97_read(ac97, AC97_REC_GAIN)) == 0x8a06) { - ac97->scaps |= AC97_SCAP_AUDIO; + if (! (ac97->scaps & AC97_SCAP_AUDIO)) { + /* test if we can write to the record gain volume register */ + snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x8a06); + if ((err = snd_ac97_read(ac97, AC97_REC_GAIN)) == 0x8a06) + ac97->scaps |= AC97_SCAP_AUDIO; + } + if (ac97->scaps & AC97_SCAP_AUDIO) { ac97->caps = snd_ac97_read(ac97, AC97_RESET); ac97->ext_id = snd_ac97_read(ac97, AC97_EXTENDED_ID); if (ac97->ext_id == 0xffff) /* invalid combination */ @@ -2667,7 +2724,7 @@ } spin_lock(&ac97->reg_lock); - old = ac97->regs[reg] & ~mask; + old = ac97->regs[reg] & mask; spin_unlock(&ac97->reg_lock); if (old != bits) { snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS, AC97_EA_SPDIF, 0); @@ -2862,16 +2919,36 @@ return snd_ctl_remove_id(ac97->card, &id); } -static int rename_ctl(ac97_t *ac97, const char *src, const char *dst) +static snd_kcontrol_t *ctl_find(ac97_t *ac97, const char *name) { - snd_ctl_elem_id_t sid, did; + snd_ctl_elem_id_t sid; memset(&sid, 0, sizeof(sid)); - strcpy(sid.name, src); + strcpy(sid.name, name); sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - memset(&did, 0, sizeof(did)); - strcpy(did.name, dst); - did.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - return snd_ctl_rename_id(ac97->card, &sid, &did); + return snd_ctl_find_id(ac97->card, &sid); +} + +static int rename_ctl(ac97_t *ac97, const char *src, const char *dst) +{ + snd_kcontrol_t *kctl = ctl_find(ac97, src); + if (kctl) { + strcpy(kctl->id.name, dst); + return 0; + } + return -ENOENT; +} + +static int swap_ctl(ac97_t *ac97, const char *s1, const char *s2) +{ + snd_kcontrol_t *kctl1, *kctl2; + kctl1 = ctl_find(ac97, s1); + kctl2 = ctl_find(ac97, s2); + if (kctl1 && kctl2) { + strcpy(kctl1->id.name, s2); + strcpy(kctl2->id.name, s1); + return 0; + } + return -ENOENT; } static int swap_headphone(ac97_t *ac97, int remove_master) @@ -2889,6 +2966,14 @@ return 0; } +static int swap_surround(ac97_t *ac97) +{ + /* FIXME: error checks.. */ + swap_ctl(ac97, "Master Playback Switch", "Surround Playback Switch"); + swap_ctl(ac97, "Master Playback Volume", "Surround Playback Volume"); + return 0; +} + /** * snd_ac97_tune_hardware - tune up the hardware @@ -2914,6 +2999,8 @@ return swap_headphone(ac97, 1); case AC97_TUNE_SWAP_HP: return swap_headphone(ac97, 0); + case AC97_TUNE_SWAP_SURROUND: + return swap_surround(ac97); } snd_printk(KERN_ERR "invalid quirk type %d for %s\n", quirk->type, quirk->name); return -EINVAL; diff -Nru a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c --- a/sound/pci/ac97/ac97_patch.c Mon Jun 9 23:16:18 2003 +++ b/sound/pci/ac97/ac97_patch.c Mon Jun 9 23:16:18 2003 @@ -51,52 +51,60 @@ return 0; } -int patch_wolfson00(ac97_t * ac97) +/* + * May 2, 2003 Liam Girdwood <liam.girdwood@wolfsonmicro.com> + * removed broken wolfson00 patch. + * added support for WM9705,WM9708,WM9709,WM9710,WM9711,WM9712 and WM9717. + */ + +#define AC97_WM97XX_FMIXER_VOL 0x72 +#define AC97_WM9704_RMIXER_VOL 0x74 +#define AC97_WM9704_TEST 0x5a +#define AC97_WM9704_RPCM_VOL 0x70 +#define AC97_WM9711_OUT3VOL 0x16 + +int patch_wolfson03(ac97_t * ac97) { - /* This sequence is suspect because it was designed for - the WM9704, and is known to fail when applied to the - WM9707. If you're having trouble initializing a - WM9700, this is the place to start looking. + /* This is known to work for the ViewSonic ViewPad 1000 Randolph Bentson <bentson@holmsjoen.com> */ - // WM9701A - snd_ac97_write_cache(ac97, 0x72, 0x0808); - snd_ac97_write_cache(ac97, 0x74, 0x0808); - + // WM9703/9707/9708/9717 + snd_ac97_write_cache(ac97, AC97_WM97XX_FMIXER_VOL, 0x0808); + snd_ac97_write_cache(ac97, AC97_GENERAL_PURPOSE, 0x8000); + return 0; +} + +int patch_wolfson04(ac97_t * ac97) +{ + // WM9704M/9704Q + // set front and rear mixer volume + snd_ac97_write_cache(ac97, AC97_WM97XX_FMIXER_VOL, 0x0808); + snd_ac97_write_cache(ac97, AC97_WM9704_RMIXER_VOL, 0x0808); + // patch for DVD noise - snd_ac97_write_cache(ac97, 0x5a, 0x0200); - + snd_ac97_write_cache(ac97, AC97_WM9704_TEST, 0x0200); + // init vol - snd_ac97_write_cache(ac97, 0x70, 0x0808); - + snd_ac97_write_cache(ac97, AC97_WM9704_RPCM_VOL, 0x0808); + + // set rear surround volume snd_ac97_write_cache(ac97, AC97_SURROUND_MASTER, 0x0000); return 0; } - -int patch_wolfson03(ac97_t * ac97) + +int patch_wolfson05(ac97_t * ac97) { - /* This is known to work for the ViewSonic ViewPad 1000 - Randolph Bentson <bentson@holmsjoen.com> */ - - // WM9703/9707 - snd_ac97_write_cache(ac97, 0x72, 0x0808); - snd_ac97_write_cache(ac97, 0x20, 0x8000); + // WM9705, WM9710 + // set front mixer volume + snd_ac97_write_cache(ac97, AC97_WM97XX_FMIXER_VOL, 0x0808); return 0; } -int patch_wolfson04(ac97_t * ac97) +int patch_wolfson11(ac97_t * ac97) { - // WM9704 - snd_ac97_write_cache(ac97, 0x72, 0x0808); - snd_ac97_write_cache(ac97, 0x74, 0x0808); - - // patch for DVD noise - snd_ac97_write_cache(ac97, 0x5a, 0x0200); - - // init vol - snd_ac97_write_cache(ac97, 0x70, 0x0808); - - snd_ac97_write_cache(ac97, AC97_SURROUND_MASTER, 0x0000); + // WM9711, WM9712 + // set out3 volume + snd_ac97_write_cache(ac97, AC97_WM9711_OUT3VOL, 0x0808); return 0; } @@ -360,10 +368,21 @@ int patch_alc650(ac97_t * ac97) { unsigned short val; + int spdif = 0; + + /* FIXME: set the above 1 if we can detect the chip rev.E correctly. + * this is used for switching mic and center/lfe, which needs + * resetting GPIO0 level on the older revision. + */ + ac97->spec.dev_flags = 0; /* check spdif */ - val = snd_ac97_read(ac97, AC97_EXTENDED_STATUS); - if (val & AC97_EA_SPCV) { + if (ac97->spec.dev_flags) { + val = snd_ac97_read(ac97, AC97_EXTENDED_STATUS); + if (val & AC97_EA_SPCV) + spdif = 1; + } + if (spdif) { /* enable spdif in */ snd_ac97_write_cache(ac97, AC97_ALC650_CLOCK, snd_ac97_read(ac97, AC97_ALC650_CLOCK) | 0x03); @@ -373,6 +392,25 @@ val = snd_ac97_read(ac97, AC97_ALC650_MULTICH); val &= ~0xc000; /* slot: 3,4,7,8,6,9 */ snd_ac97_write_cache(ac97, AC97_ALC650_MULTICH, val); + + if (! ac97->spec.dev_flags) { + /* set GPIO */ + int mic_off; + mic_off = snd_ac97_read(ac97, AC97_ALC650_MULTICH) & (1 << 10); + /* GPIO0 direction */ + val = snd_ac97_read(ac97, 0x76); + if (mic_off) + val &= ~0x01; + else + val |= 0x01; + snd_ac97_write_cache(ac97, 0x76, val); + val = snd_ac97_read(ac97, 0x78); + if (mic_off) + val &= ~0x100; + else + val = val | 0x100; + snd_ac97_write_cache(ac97, 0x78, val); + } /* full DAC volume */ snd_ac97_write_cache(ac97, AC97_ALC650_SURR_DAC_VOL, 0x0808); diff -Nru a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h --- a/sound/pci/ac97/ac97_patch.h Mon Jun 9 23:16:05 2003 +++ b/sound/pci/ac97/ac97_patch.h Mon Jun 9 23:16:05 2003 @@ -26,6 +26,8 @@ int patch_wolfson00(ac97_t * ac97); int patch_wolfson03(ac97_t * ac97); int patch_wolfson04(ac97_t * ac97); +int patch_wolfson05(ac97_t * ac97); +int patch_wolfson11(ac97_t * ac97); int patch_tritech_tr28028(ac97_t * ac97); int patch_sigmatel_stac9708(ac97_t * ac97); int patch_sigmatel_stac9721(ac97_t * ac97); diff -Nru a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c --- a/sound/pci/ali5451/ali5451.c Mon Jun 9 23:16:18 2003 +++ b/sound/pci/ali5451/ali5451.c Mon Jun 9 23:16:18 2003 @@ -52,6 +52,7 @@ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; static int pcm_channels[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 32}; +static int spdif[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 0}; MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(index, "Index value for ALI M5451 PCI Audio."); @@ -65,6 +66,9 @@ MODULE_PARM(pcm_channels, "1-" __MODULE_STRING(SNDRV_CARDS) "l"); MODULE_PARM_DESC(pcm_channels, "PCM Channels"); MODULE_PARM_SYNTAX(pcm_channels, SNDRV_ENABLED ",default:32,allows:{{1,32}}"); +MODULE_PARM(spdif, "1-" __MODULE_STRING(SNDRV_CARDS) "l"); +MODULE_PARM_DESC(spdif, "Support SPDIF I/O"); +MODULE_PARM_SYNTAX(spdif, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC); /* * Debug part definitions @@ -125,9 +129,13 @@ #define ALI_AC97_READ 0x44 #define ALI_SCTRL 0x48 +#define ALI_SPDIF_OUT_ENABLE 0x20 #define ALI_AC97_GPIO 0x4c #define ALI_SPDIF_CS 0x70 #define ALI_SPDIF_CTRL 0x74 +#define ALI_SPDIF_IN_FUNC_ENABLE 0x02 +#define ALI_SPDIF_IN_CH_STATUS 0x40 +#define ALI_SPDIF_OUT_CH_STATUS 0xbf #define ALI_START 0x80 #define ALI_STOP 0x84 #define ALI_CSPF 0x90 @@ -147,6 +155,11 @@ #define ALI_SBCTRL_SBE2R_SBDD 0xc4 #define ALI_STIMER 0xc8 #define ALI_GLOBAL_CONTROL 0xd4 +#define ALI_SPDIF_OUT_SEL_PCM 0x00000400 /* bit 10 */ +#define ALI_SPDIF_IN_SUPPORT 0x00000800 /* bit 11 */ +#define ALI_SPDIF_OUT_CH_ENABLE 0x00008000 /* bit 15 */ +#define ALI_SPDIF_IN_CH_ENABLE 0x00080000 /* bit 19 */ +#define ALI_PCM_IN_ENABLE 0x80000000 /* bit 31 */ #define ALI_CSO_ALPHA_FMS 0xe0 #define ALI_LBA 0xe4 @@ -234,6 +247,7 @@ unsigned char revision; unsigned int hw_initialized: 1; + unsigned int spdif_support: 1; struct resource *res_port; struct pci_dev *pci; @@ -673,8 +687,8 @@ // recording if (rec) { - if (inl(ALI_REG(codec, ALI_GLOBAL_CONTROL)) & (1<<11) && - ( codec->revision == ALI_5451_V02 )) + if (codec->spdif_support && + (inl(ALI_REG(codec, ALI_GLOBAL_CONTROL)) & ALI_SPDIF_IN_SUPPORT)) idx = ALI_SPDIF_IN_CHANNEL; else idx = ALI_PCM_IN_CHANNEL; @@ -688,7 +702,8 @@ } //playback... - if (inl(ALI_REG(codec, ALI_GLOBAL_CONTROL)) & (1<<15)) { + if (codec->spdif_support && + (inl(ALI_REG(codec, ALI_GLOBAL_CONTROL)) & ALI_SPDIF_OUT_CH_ENABLE)) { idx = ALI_SPDIF_OUT_CHANNEL; if ((result = snd_ali_alloc_pcm_channel(codec,idx)) >= 0) { return result; @@ -840,7 +855,7 @@ unsigned int dwVal; dwVal = inl(ALI_REG(codec, ALI_GLOBAL_CONTROL)); - dwVal |= 1<<11; + dwVal |= ALI_SPDIF_IN_SUPPORT; outl(dwVal, ALI_REG(codec, ALI_GLOBAL_CONTROL)); dwVal = inb(ALI_REG(codec, ALI_SPDIF_CTRL)); @@ -855,7 +870,7 @@ unsigned int dwVal; dwVal = inl(ALI_REG(codec, ALI_GLOBAL_CONTROL)); - dwVal &= ~(1<<11); + dwVal &= ~ALI_SPDIF_IN_SUPPORT; outl(dwVal, ALI_REG(codec, ALI_GLOBAL_CONTROL)); snd_ali_disable_special_channel(codec, ALI_SPDIF_IN_CHANNEL); @@ -906,14 +921,14 @@ pci_write_config_byte(pci_dev, 0x7e, bVal); bVal = inb(ALI_REG(codec, ALI_SCTRL)); - outb(bVal | 0x20, ALI_REG(codec, ALI_SCTRL)); + outb(bVal | ALI_SPDIF_OUT_ENABLE, ALI_REG(codec, ALI_SCTRL)); bVal = inb(ALI_REG(codec, ALI_SPDIF_CTRL)); - outb(bVal & ~(1<<6), ALI_REG(codec, ALI_SPDIF_CTRL)); + outb(bVal & ALI_SPDIF_OUT_CH_STATUS, ALI_REG(codec, ALI_SPDIF_CTRL)); { wVal = inw(ALI_REG(codec, ALI_GLOBAL_CONTROL)); - wVal |= (1<<10); + wVal |= ALI_SPDIF_OUT_SEL_PCM; outw(wVal, ALI_REG(codec, ALI_GLOBAL_CONTROL)); snd_ali_disable_special_channel(codec,ALI_SPDIF_OUT_CHANNEL); } @@ -924,7 +939,7 @@ unsigned short wVal = 0; wVal = inw(ALI_REG(codec, ALI_GLOBAL_CONTROL)); - wVal &= ~(1<<10); + wVal &= ~ALI_SPDIF_OUT_SEL_PCM; outw(wVal, ALI_REG(codec, ALI_GLOBAL_CONTROL)); /* wVal = inw(ALI_REG(codec, ALI_SPDIF_CS)); @@ -941,7 +956,7 @@ { unsigned short wVal = 0; wVal = inw(ALI_REG(codec, ALI_GLOBAL_CONTROL)); - wVal |= (1<<10); + wVal |= ALI_SPDIF_OUT_SEL_PCM; outw(wVal, ALI_REG(codec, ALI_GLOBAL_CONTROL)); snd_ali_enable_special_channel(codec, ALI_SPDIF_OUT_CHANNEL); @@ -952,7 +967,7 @@ unsigned char bVal; bVal = inb(ALI_REG(codec, ALI_SCTRL)); - outb(bVal & (~0x20), ALI_REG(codec, ALI_SCTRL)); + outb(bVal & ~ALI_SPDIF_OUT_ENABLE, ALI_REG(codec, ALI_SCTRL)); snd_ali_disable_spdif_chnout(codec); } @@ -1033,10 +1048,10 @@ static irqreturn_t snd_ali_card_interrupt(int irq, - void *dev_id, - struct pt_regs *regs) + void *dev_id, + struct pt_regs *regs) { - ali_t *codec = snd_magic_cast(ali_t, dev_id, return IRQ_NONE); + ali_t *codec = snd_magic_cast(ali_t, dev_id, return IRQ_NONE); if (codec == NULL) return IRQ_NONE; @@ -1211,6 +1226,7 @@ { ali_t *codec = snd_pcm_substream_chip(substream); + struct list_head *pos; snd_pcm_substream_t *s; unsigned int what, whati, capture_flag; snd_ali_voice_t *pvoice = NULL, *evoice = NULL; @@ -1229,8 +1245,8 @@ } what = whati = capture_flag = 0; - s = substream; - do { + snd_pcm_group_for_each(pos, substream) { + s = snd_pcm_group_substream_entry(pos); if ((ali_t *) _snd_pcm_chip(s->pcm) == codec) { pvoice = (snd_ali_voice_t *) s->runtime->private_data; evoice = pvoice->extra; @@ -1254,8 +1270,7 @@ if (pvoice->mode) capture_flag = 1; } - s = s->link_next; - } while (s != substream); + } spin_lock(&codec->reg_lock); if (! do_start) { outl(what, ALI_REG(codec, ALI_STOP)); @@ -1360,12 +1375,11 @@ if ((pvoice->number == ALI_SPDIF_IN_CHANNEL) || (pvoice->number == ALI_PCM_IN_CHANNEL)) snd_ali_disable_special_channel(codec, pvoice->number); - else if ((inl(ALI_REG(codec, ALI_GLOBAL_CONTROL)) & (1<<15)) - && (pvoice->number == ALI_SPDIF_OUT_CHANNEL)) { - if (codec->revision == ALI_5451_V02) { - snd_ali_set_spdif_out_rate(codec, runtime->rate); - Delta = 0x1000; - } + else if (codec->spdif_support && + (inl(ALI_REG(codec, ALI_GLOBAL_CONTROL)) & ALI_SPDIF_OUT_CH_ENABLE) + && (pvoice->number == ALI_SPDIF_OUT_CHANNEL)) { + snd_ali_set_spdif_out_rate(codec, runtime->rate); + Delta = 0x1000; } /* set Loop Back Address */ @@ -1867,7 +1881,7 @@ snd_printk("ali mixer creating error.\n"); return err; } - if (codec->revision == ALI_5451_V02) { + if (codec->spdif_support) { for(idx = 0; idx < ARRAY_SIZE(snd_ali5451_mixer_spdif); idx++) { err=snd_ctl_add(codec->card, snd_ctl_new1(&snd_ali5451_mixer_spdif[idx], codec)); if (err < 0) return err; @@ -2039,7 +2053,7 @@ codec->ac97_ext_id = snd_ali_codec_peek(codec, 0, AC97_EXTENDED_ID); codec->ac97_ext_status = snd_ali_codec_peek(codec, 0, AC97_EXTENDED_STATUS); - if (codec->revision == ALI_5451_V02) { + if (codec->spdif_support) { snd_ali_enable_spdif_out(codec); codec->spdif_mask = 0x00000002; } @@ -2073,9 +2087,10 @@ } static int __devinit snd_ali_create(snd_card_t * card, - struct pci_dev *pci, - int pcm_streams, - ali_t ** r_ali) + struct pci_dev *pci, + int pcm_streams, + int spdif_support, + ali_t ** r_ali) { ali_t *codec; int i, err; @@ -2112,6 +2127,7 @@ codec->irq = -1; codec->port = pci_resource_start(pci, 0); pci_read_config_byte(pci, PCI_REVISION_ID, &codec->revision); + codec->spdif_support = spdif_support; if (pcm_streams < 1) pcm_streams = 1; @@ -2222,7 +2238,7 @@ if (card == NULL) return -ENOMEM; - if ((err = snd_ali_create(card, pci, pcm_channels[dev], &codec)) < 0) { + if ((err = snd_ali_create(card, pci, pcm_channels[dev], spdif[dev], &codec)) < 0) { snd_card_free(card); return err; } diff -Nru a/sound/pci/azt3328.c b/sound/pci/azt3328.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/azt3328.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,1621 @@ +/* + * azt3328.c - driver for Aztech AZF3328 based soundcards (e.g. PCI168). + * Copyright (C) 2002 by Andreas Mohr <hw7oshyuv3001@sneakemail.com> + * + * Framework borrowed from Bart Hartgers's als4000.c. + * Driver developed on PCI168 AP(W) version (PCI rev. 10, subsystem ID 1801), + * found in a Fujitsu-Siemens PC ("Cordant", aluminum case). + * Other versions are: + * PCI168 A(W), sub ID 1800 + * PCI168 A/AP, sub ID 8000 + * Please give me feedback in case you try my driver with one of these!! + * + * GPL LICENSE + * This program is free software; you can redistribute it and/or modify + * it under the terms of the 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 + * Since Aztech does not provide any chipset documentation, + * even on repeated request to various addresses, + * and the answer that was finally given was negative + * (and I was stupid enough to manage to get hold of a PCI168 soundcard + * in the first place >:-P}), + * I was forced to base this driver on reverse engineering + * (3 weeks' worth of evenings filled with driver work). + * (and no, I did NOT go the easy way: to pick up a PCI128 for 9 Euros) + * + * The AZF3328 chip (note: AZF3328, *not* AZT3328, that's just the driver name + * for compatibility reasons) has the following features: + * + * - builtin AC97 conformant codec (SNR over 80dB) + * (really AC97 compliant?? I really doubt it when looking + * at the mixer register layout) + * - builtin genuine OPL3 + * - full duplex 16bit playback/record at independent sampling rate + * - MPU401 (+ legacy address support) FIXME: how to enable legacy addr?? + * - game port (legacy address support) + * - built-in General DirectX timer having a 20 bits counter + * with 1us resolution (FIXME: where is it?) + * - I2S serial port for external DAC + * - supports 33MHz PCI spec 2.1, PCI power management 1.0, compliant with ACPI + * - supports hardware volume control + * - single chip low cost solution (128 pin QFP) + * - supports programmable Sub-vendor and Sub-system ID + * required for Microsoft's logo compliance (FIXME: where?) + * - PCI168 AP(W) card: power amplifier with 4 Watts/channel at 4 Ohms + * + * Certain PCI versions of this card are susceptible to DMA traffic underruns + * in some systems (resulting in sound crackling/clicking/popping), + * probably because they don't have a DMA FIFO buffer or so. + * Overview (PCI ID/PCI subID/PCI rev.): + * - no DMA crackling on SiS735: 0x50DC/0x1801/16 + * - unknown performance: 0x50DC/0x1801/10 + * + * Crackling happens with VIA chipsets or, in my case, an SiS735, which is + * supposed to be very fast and supposed to get rid of crackling much + * better than a VIA, yet ironically I still get crackling, like many other + * people with the same chipset. + * Possible remedies: + * - plug card into a different PCI slot, preferrably one that isn't shared + * too much (this helps a lot, but not completely!) + * - get rid of PCI VGA card, use AGP instead + * - upgrade or downgrade BIOS + * - fiddle with PCI latency settings (setpci -v -s BUSID latency_timer=XX) + * Not too helpful. + * - Disable ACPI/power management/"Auto Detect RAM/PCI Clk" in BIOS + * + * BUGS + * - when Ctrl-C'ing mpg321, the playback loops a bit + * (premature DMA playback reset?) + * - full-duplex sometimes breaks (IRQ management issues?). + * Once even a spontaneous REBOOT happened!!! + * + * TODO + * - test MPU401 MIDI playback etc. + * - power management (CONFIG_PM). See e.g. intel8x0 or cs4281. + * This would be nice since the chip runs a bit hot, and it's *required* + * anyway for proper ACPI power management. In other words: rest + * assured that I *will* implement this very soon; as soon as Linux 2.5.x + * has power management that's bugfree enough to work properly on my desktop. + * - figure out what all unknown port bits are responsible for + */ + +#include <sound/driver.h> +#include <asm/io.h> +#include <linux/init.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include <sound/core.h> +#include <sound/control.h> +#include <sound/pcm.h> +#include <sound/rawmidi.h> +#include <sound/mpu401.h> +#include <sound/opl3.h> +#define SNDRV_GET_ID +#include <sound/initval.h> +#include "azt3328.h" + +MODULE_AUTHOR("Andreas Mohr <hw7oshyuv3001@sneakemail.com>"); +MODULE_DESCRIPTION("Aztech AZF3328 (PCI168)"); +MODULE_LICENSE("GPL"); +MODULE_CLASSES("{sound}"); +MODULE_DEVICES("{{Aztech,AZF3328}}"); + +#define DEBUG_MISC 0 +#define DEBUG_CALLS 0 +#define DEBUG_MIXER 0 +#define DEBUG_PLAY_REC 0 +#define DEBUG_IO 0 +#define MIXER_TESTING 0 + +#if DEBUG_MISC +#define snd_azf3328_dbgmisc(format, args...) printk(KERN_ERR format, ##args) +#else +#define snd_azf3328_dbgmisc(format, args...) +#endif + +#if DEBUG_CALLS +#define snd_azf3328_dbgcalls(format, args...) printk(format, ##args) +#define snd_azf3328_dbgcallenter() printk(KERN_ERR "entering %s\n", __FUNCTION__) +#define snd_azf3328_dbgcallleave() printk(KERN_ERR "leaving %s\n", __FUNCTION__) +#else +#define snd_azf3328_dbgcalls(format, args...) +#define snd_azf3328_dbgcallenter() +#define snd_azf3328_dbgcallleave() +#endif + +#if DEBUG_MIXER +#define snd_azf3328_dbgmixer(format, args...) printk(format, ##args) +#else +#define snd_azf3328_dbgmixer(format, args...) +#endif + +#if DEBUG_PLAY_REC +#define snd_azf3328_dbgplay(format, args...) printk(KERN_ERR format, ##args) +#else +#define snd_azf3328_dbgplay(format, args...) +#endif + +#if DEBUG_IO +#define snd_azf3328_dbgio(chip, where) \ + printk(KERN_ERR "%s: IDX_IO_PLAY_FLAGS %04x, IDX_IO_PLAY_IRQMASK %04x, IDX_IO_IRQSTATUS %04x\n", where, inw(chip->codec_port+IDX_IO_PLAY_FLAGS), inw(chip->codec_port+IDX_IO_PLAY_IRQMASK), inw(chip->codec_port+IDX_IO_IRQSTATUS)) +#else +#define snd_azf3328_dbgio(chip, where) +#endif + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ +static int joystick[SNDRV_CARDS] = + {-1}; /* "unset" as default */ + +MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(index, "Index value for AZF3328 soundcard."); +MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); +MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s"); +MODULE_PARM_DESC(id, "ID string for AZF3328 soundcard."); +MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); +MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(enable, "Enable AZF3328 soundcard."); +MODULE_PARM_SYNTAX(enable, SNDRV_INDEX_DESC); +MODULE_PARM(joystick, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(joystick, "Forced joystick port enable for AZF3328 soundcard. (0 = force disable)"); +MODULE_PARM_SYNTAX(joystick, SNDRV_ENABLED); + +typedef struct _snd_azf3328 azf3328_t; +#define chip_t azf3328_t + +struct _snd_azf3328 { + int irq; + + unsigned long codec_port; + struct resource *res_codec_port; + unsigned long io2_port; + struct resource *res_io2_port; + unsigned long mpu_port; + struct resource *res_mpu_port; + unsigned long synth_port; + struct resource *res_synth_port; + unsigned long mixer_port; + struct resource *res_mixer_port; + unsigned long game_port; + + struct pci_dev *pci; + snd_card_t *card; + + snd_pcm_t *pcm; + snd_rawmidi_t *rmidi; + snd_pcm_substream_t *playback_substream; + snd_pcm_substream_t *capture_substream; + unsigned int is_playing; + unsigned int is_recording; + + spinlock_t reg_lock; +}; + +static struct pci_device_id snd_azf3328_ids[] __devinitdata = { + { 0x122D, 0x50DC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* PCI168/3328 */ + { 0x122D, 0x80DA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* 3328 */ + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, snd_azf3328_ids); + +void snd_azf3328_io2_write(azf3328_t *chip, int reg, unsigned char value) +{ + outb(value, chip->io2_port + reg); +} + +unsigned char snd_azf3328_io2_read(azf3328_t *chip, int reg) +{ + return inb(chip->io2_port + reg); +} + +void snd_azf3328_mixer_write(azf3328_t *chip, int reg, unsigned long value, int type) +{ + switch(type) { + case WORD_VALUE: + outw(value, chip->mixer_port + reg); + break; + case DWORD_VALUE: + outl(value, chip->mixer_port + reg); + break; + case BYTE_VALUE: + outb(value, chip->mixer_port + reg); + break; + } +} + +unsigned long snd_azf3328_mixer_read(azf3328_t *chip, int reg, int type) +{ + unsigned long res = 0; + + switch(type) { + case WORD_VALUE: + res = (unsigned long)inw(chip->mixer_port + reg); + break; + case DWORD_VALUE: + res = (unsigned long)inl(chip->mixer_port + reg); + break; + case BYTE_VALUE: + res = (unsigned long)inb(chip->mixer_port + reg); + break; + } + + return res; +} + +void snd_azf3328_mixer_set_mute(azf3328_t *chip, int reg, int do_mute) +{ + unsigned char oldval; + + /* the mute bit is on the *second* (i.e. right) register of a + * left/right channel setting */ + oldval = inb(chip->mixer_port + reg + 1); + if (do_mute) + oldval |= 0x80; + else + oldval &= ~0x80; + outb(oldval, chip->mixer_port + reg + 1); +} + +void snd_azf3328_mixer_write_volume_gradually(azf3328_t *chip, int reg, unsigned char dst_vol_left, unsigned char dst_vol_right, int chan_sel, int delay) +{ + unsigned char curr_vol_left = 0, curr_vol_right = 0; + int left_done = 0, right_done = 0; + + snd_azf3328_dbgcallenter(); + if (chan_sel & SET_CHAN_LEFT) + curr_vol_left = inb(chip->mixer_port + reg + 1); + else + left_done = 1; + if (chan_sel & SET_CHAN_RIGHT) + curr_vol_right = inb(chip->mixer_port + reg + 0); + else + right_done = 1; + + /* take care of muting flag (0x80) contained in left channel */ + if (curr_vol_left & 0x80) + dst_vol_left |= 0x80; + else + dst_vol_left &= ~0x80; + + do + { + if (!left_done) + { + if (curr_vol_left > dst_vol_left) + curr_vol_left--; + else + if (curr_vol_left < dst_vol_left) + curr_vol_left++; + else + left_done = 1; + outb(curr_vol_left, chip->mixer_port + reg + 1); + } + if (!right_done) + { + if (curr_vol_right > dst_vol_right) + curr_vol_right--; + else + if (curr_vol_right < dst_vol_right) + curr_vol_right++; + else + right_done = 1; + /* during volume change, the right channel is crackling + * somewhat more than the left channel, unfortunately. + * This seems to be a hardware issue. */ + outb(curr_vol_right, chip->mixer_port + reg + 0); + } + if (delay) + mdelay(delay); + } + while ((!left_done) || (!right_done)); + snd_azf3328_dbgcallleave(); +} + +/* + * general mixer element + */ +typedef struct azf3328_mixer_reg { + unsigned int reg; + unsigned int lchan_shift, rchan_shift; + unsigned int mask; + unsigned int invert: 1; + unsigned int stereo: 1; + unsigned int enum_c: 4; +} azf3328_mixer_reg_t; + +#define COMPOSE_MIXER_REG(reg,lchan_shift,rchan_shift,mask,invert,stereo,enum_c) \ + ((reg) | (lchan_shift << 8) | (rchan_shift << 12) | (mask << 16) | (invert << 24) | (stereo << 25) | (enum_c << 26)) + +static void snd_azf3328_mixer_reg_decode(azf3328_mixer_reg_t *r, unsigned long val) +{ + r->reg = val & 0xff; + r->lchan_shift = (val >> 8) & 0x0f; + r->rchan_shift = (val >> 12) & 0x0f; + r->mask = (val >> 16) & 0xff; + r->invert = (val >> 24) & 1; + r->stereo = (val >> 25) & 1; + r->enum_c = (val >> 26) & 0x0f; +} + +/* + * mixer switches/volumes + */ + +#define AZF3328_MIXER_SWITCH(xname, reg, shift, invert) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_azf3328_info_mixer, \ + .get = snd_azf3328_get_mixer, .put = snd_azf3328_put_mixer, \ + .private_value = COMPOSE_MIXER_REG(reg, shift, 0, 0x1, invert, 0, 0), \ +} + +#define AZF3328_MIXER_VOL_STEREO(xname, reg, mask, invert) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_azf3328_info_mixer, \ + .get = snd_azf3328_get_mixer, .put = snd_azf3328_put_mixer, \ + .private_value = COMPOSE_MIXER_REG(reg, 8, 0, mask, invert, 1, 0), \ +} + +#define AZF3328_MIXER_VOL_MONO(xname, reg, mask, is_right_chan) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_azf3328_info_mixer, \ + .get = snd_azf3328_get_mixer, .put = snd_azf3328_put_mixer, \ + .private_value = COMPOSE_MIXER_REG(reg, is_right_chan ? 0 : 8, 0, mask, 1, 0, 0), \ +} + +#define AZF3328_MIXER_VOL_SPECIAL(xname, reg, mask, shift, invert) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_azf3328_info_mixer, \ + .get = snd_azf3328_get_mixer, .put = snd_azf3328_put_mixer, \ + .private_value = COMPOSE_MIXER_REG(reg, shift, 0, mask, invert, 0, 0), \ +} + +#define AZF3328_MIXER_ENUM(xname, reg, enum_c, shift) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = snd_azf3328_info_mixer_enum, \ + .get = snd_azf3328_get_mixer_enum, .put = snd_azf3328_put_mixer_enum, \ + .private_value = COMPOSE_MIXER_REG(reg, shift, 0, 0, 0, 0, enum_c), \ +} + +static int snd_azf3328_info_mixer(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + azf3328_mixer_reg_t reg; + + snd_azf3328_dbgcallenter(); + snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); + uinfo->type = reg.mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = reg.stereo + 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = reg.mask; + snd_azf3328_dbgcallleave(); + return 0; +} + +static int snd_azf3328_get_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + azf3328_t *chip = snd_kcontrol_chip(kcontrol); + azf3328_mixer_reg_t reg; + unsigned int oreg, val; + + snd_azf3328_dbgcallenter(); + snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); + + oreg = inw(chip->mixer_port + reg.reg); + val = (oreg >> reg.lchan_shift) & reg.mask; + if (reg.invert) + val = reg.mask - val; + ucontrol->value.integer.value[0] = val; + if (reg.stereo) { + val = (oreg >> reg.rchan_shift) & reg.mask; + if (reg.invert) + val = reg.mask - val; + ucontrol->value.integer.value[1] = val; + } + snd_azf3328_dbgmixer("get: %02x is %04x -> vol %02lx|%02lx (shift %02d|%02d, mask %02x, inv. %d, stereo %d)\n", reg.reg, oreg, ucontrol->value.integer.value[0], ucontrol->value.integer.value[1], reg.lchan_shift, reg.rchan_shift, reg.mask, reg.invert, reg.stereo); + snd_azf3328_dbgcallleave(); + return 0; +} + +static int snd_azf3328_put_mixer(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + azf3328_t *chip = snd_kcontrol_chip(kcontrol); + azf3328_mixer_reg_t reg; + unsigned int oreg, nreg, val; + + snd_azf3328_dbgcallenter(); + snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); + oreg = inw(chip->mixer_port + reg.reg); + val = ucontrol->value.integer.value[0] & reg.mask; + if (reg.invert) + val = reg.mask - val; + nreg = oreg & ~(reg.mask << reg.lchan_shift); + nreg |= (val << reg.lchan_shift); + if (reg.stereo) { + val = ucontrol->value.integer.value[1] & reg.mask; + if (reg.invert) + val = reg.mask - val; + nreg &= ~(reg.mask << reg.rchan_shift); + nreg |= (val << reg.rchan_shift); + } + if (reg.mask >= 0x07) /* it's a volume control, so better take care */ + snd_azf3328_mixer_write_volume_gradually(chip, reg.reg, nreg >> 8, nreg & 0xff, SET_CHAN_LEFT|SET_CHAN_RIGHT, 0); /* just set both channels, doesn't matter */ + else + outw(nreg, chip->mixer_port + reg.reg); + + snd_azf3328_dbgmixer("put: %02x to %02lx|%02lx, oreg %04x; shift %02d|%02d -> nreg %04x; after: %04x\n", reg.reg, ucontrol->value.integer.value[0], ucontrol->value.integer.value[1], oreg, reg.lchan_shift, reg.rchan_shift, nreg, inw(chip->mixer_port + reg.reg)); + snd_azf3328_dbgcallleave(); + return (nreg != oreg); +} + +static int snd_azf3328_info_mixer_enum(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) +{ + azf3328_mixer_reg_t reg; + static char *texts1[2] = { "ModemOut1", "ModemOut2" }; + static char *texts2[2] = { "MonoSelectSource1", "MonoSelectSource2" }; + static char *texts3[8] = { + "Mic", "CD", "Video", "Aux", "Line", + "Mix", "Mix Mono", "Phone" + }; + + snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = (reg.reg == IDX_MIXER_REC_SELECT) ? 2 : 1; + uinfo->value.enumerated.items = reg.enum_c; + if (uinfo->value.enumerated.item > reg.enum_c - 1U) + uinfo->value.enumerated.item = reg.enum_c - 1U; + if (reg.reg == IDX_MIXER_ADVCTL2) + { + if (reg.lchan_shift == 8) /* modem out sel */ + strcpy(uinfo->value.enumerated.name, texts1[uinfo->value.enumerated.item]); + else /* mono sel source */ + strcpy(uinfo->value.enumerated.name, texts2[uinfo->value.enumerated.item]); + } + else + strcpy(uinfo->value.enumerated.name, texts3[uinfo->value.enumerated.item] +); + return 0; +} + +static int snd_azf3328_get_mixer_enum(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + azf3328_mixer_reg_t reg; + azf3328_t *chip = snd_kcontrol_chip(kcontrol); + unsigned short val; + + snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); + val = inw(chip->mixer_port + reg.reg); + if (reg.reg == IDX_MIXER_REC_SELECT) + { + ucontrol->value.enumerated.item[0] = (val >> 8) & (reg.enum_c - 1); + ucontrol->value.enumerated.item[1] = (val >> 0) & (reg.enum_c - 1); + } + else + ucontrol->value.enumerated.item[0] = (val >> reg.lchan_shift) & (reg.enum_c - 1); + snd_azf3328_dbgmixer("get_enum: %02x is %04x -> %d|%d (shift %02d, enum_c %d)\n", reg.reg, val, ucontrol->value.enumerated.item[0], ucontrol->value.enumerated.item[1], reg.lchan_shift, reg.enum_c); + return 0; +} + +static int snd_azf3328_put_mixer_enum(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) +{ + azf3328_mixer_reg_t reg; + azf3328_t *chip = snd_kcontrol_chip(kcontrol); + unsigned int oreg, nreg, val; + + snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); + oreg = inw(chip->mixer_port + reg.reg); + val = oreg; + if (reg.reg == IDX_MIXER_REC_SELECT) + { + if (ucontrol->value.enumerated.item[0] > reg.enum_c - 1U || + ucontrol->value.enumerated.item[1] > reg.enum_c - 1U) + return -EINVAL; + val = (ucontrol->value.enumerated.item[0] << 8) | + (ucontrol->value.enumerated.item[1] << 0); + } + else + { + if (ucontrol->value.enumerated.item[0] > reg.enum_c - 1U) + return -EINVAL; + val &= ~((reg.enum_c - 1) << reg.lchan_shift); + val |= (ucontrol->value.enumerated.item[0] << reg.lchan_shift); + } + outw(val, chip->mixer_port + reg.reg); + nreg = val; + + snd_azf3328_dbgmixer("put_enum: %02x to %04x, oreg %04x\n", reg.reg, val, oreg); + return (nreg != oreg); +} + +#define NUM_CONTROLS(ary) (sizeof(ary) / sizeof(snd_kcontrol_new_t)) + +static snd_kcontrol_new_t snd_azf3328_mixer_controls[] __devinitdata = { + AZF3328_MIXER_SWITCH("Master Playback Switch", IDX_MIXER_PLAY_MASTER, 15, 1), + AZF3328_MIXER_VOL_STEREO("Master Playback Volume", IDX_MIXER_PLAY_MASTER, 0x1f, 1), + AZF3328_MIXER_SWITCH("Wave Playback Switch", IDX_MIXER_WAVEOUT, 15, 1), + AZF3328_MIXER_VOL_STEREO("Wave Playback Volume", IDX_MIXER_WAVEOUT, 0x1f, 1), + AZF3328_MIXER_SWITCH("Wave Playback 3D Bypass", IDX_MIXER_ADVCTL2, 7, 1), + AZF3328_MIXER_SWITCH("FM Playback Switch", IDX_MIXER_FMSYNTH, 15, 1), + AZF3328_MIXER_VOL_STEREO("FM Playback Volume", IDX_MIXER_FMSYNTH, 0x1f, 1), + AZF3328_MIXER_SWITCH("CD Playback Switch", IDX_MIXER_CDAUDIO, 15, 1), + AZF3328_MIXER_VOL_STEREO("CD Playback Volume", IDX_MIXER_CDAUDIO, 0x1f, 1), + AZF3328_MIXER_SWITCH("Capture Switch", IDX_MIXER_REC_VOLUME, 15, 1), + AZF3328_MIXER_VOL_STEREO("Capture Volume", IDX_MIXER_REC_VOLUME, 0x0f, 0), + AZF3328_MIXER_ENUM("Capture Source", IDX_MIXER_REC_SELECT, 8, 0), + AZF3328_MIXER_SWITCH("Mic Playback Switch", IDX_MIXER_MIC, 15, 1), + AZF3328_MIXER_VOL_MONO("Mic Playback Volume", IDX_MIXER_MIC, 0x1f, 1), + AZF3328_MIXER_SWITCH("Mic Boost (+20dB)", IDX_MIXER_MIC, 6, 0), + AZF3328_MIXER_SWITCH("Line Playback Switch", IDX_MIXER_LINEIN, 15, 1), + AZF3328_MIXER_VOL_STEREO("Line Playback Volume", IDX_MIXER_LINEIN, 0x1f, 1), + AZF3328_MIXER_SWITCH("PCBeep Playback Switch", IDX_MIXER_PCBEEP, 15, 1), + AZF3328_MIXER_VOL_SPECIAL("PCBeep Playback Volume", IDX_MIXER_PCBEEP, 0x0f, 1, 1), + AZF3328_MIXER_SWITCH("Video Playback Switch", IDX_MIXER_VIDEO, 15, 1), + AZF3328_MIXER_VOL_STEREO("Video Playback Volume", IDX_MIXER_VIDEO, 0x1f, 1), + AZF3328_MIXER_SWITCH("Aux Playback Switch", IDX_MIXER_AUX, 15, 1), + AZF3328_MIXER_VOL_STEREO("Aux Playback Volume", IDX_MIXER_AUX, 0x1f, 1), + AZF3328_MIXER_SWITCH("Modem Playback Switch", IDX_MIXER_MODEMOUT, 15, 1), + AZF3328_MIXER_VOL_MONO("Modem Playback Volume", IDX_MIXER_MODEMOUT, 0x1f, 1), + AZF3328_MIXER_SWITCH("Modem Capture Switch", IDX_MIXER_MODEMIN, 15, 1), + AZF3328_MIXER_VOL_MONO("Modem Capture Volume", IDX_MIXER_MODEMIN, 0x1f, 1), + AZF3328_MIXER_ENUM("Modem Out Select", IDX_MIXER_ADVCTL2, 2, 8), + AZF3328_MIXER_ENUM("Mono Select Source", IDX_MIXER_ADVCTL2, 2, 9), + AZF3328_MIXER_VOL_SPECIAL("Tone Control - Treble", IDX_MIXER_BASSTREBLE, 0x07, 1, 0), + AZF3328_MIXER_VOL_SPECIAL("Tone Control - Bass", IDX_MIXER_BASSTREBLE, 0x07, 9, 0), + AZF3328_MIXER_SWITCH("3D Control - Toggle", IDX_MIXER_ADVCTL2, 13, 0), + AZF3328_MIXER_VOL_SPECIAL("3D Control - Volume", IDX_MIXER_ADVCTL1, 0x07, 1, 0), /* "3D Width" */ + AZF3328_MIXER_VOL_SPECIAL("3D Control - Space", IDX_MIXER_ADVCTL1, 0x03, 8, 0), /* "Hifi 3D" */ +#if MIXER_TESTING + AZF3328_MIXER_SWITCH("0", IDX_MIXER_ADVCTL2, 0, 0), + AZF3328_MIXER_SWITCH("1", IDX_MIXER_ADVCTL2, 1, 0), + AZF3328_MIXER_SWITCH("2", IDX_MIXER_ADVCTL2, 2, 0), + AZF3328_MIXER_SWITCH("3", IDX_MIXER_ADVCTL2, 3, 0), + AZF3328_MIXER_SWITCH("4", IDX_MIXER_ADVCTL2, 4, 0), + AZF3328_MIXER_SWITCH("5", IDX_MIXER_ADVCTL2, 5, 0), + AZF3328_MIXER_SWITCH("6", IDX_MIXER_ADVCTL2, 6, 0), + AZF3328_MIXER_SWITCH("7", IDX_MIXER_ADVCTL2, 7, 0), + AZF3328_MIXER_SWITCH("8", IDX_MIXER_ADVCTL2, 8, 0), + AZF3328_MIXER_SWITCH("9", IDX_MIXER_ADVCTL2, 9, 0), + AZF3328_MIXER_SWITCH("10", IDX_MIXER_ADVCTL2, 10, 0), + AZF3328_MIXER_SWITCH("11", IDX_MIXER_ADVCTL2, 11, 0), + AZF3328_MIXER_SWITCH("12", IDX_MIXER_ADVCTL2, 12, 0), + AZF3328_MIXER_SWITCH("13", IDX_MIXER_ADVCTL2, 13, 0), + AZF3328_MIXER_SWITCH("14", IDX_MIXER_ADVCTL2, 14, 0), + AZF3328_MIXER_SWITCH("15", IDX_MIXER_ADVCTL2, 15, 0), +#endif +}; + +#define AZF3328_INIT_VALUES (sizeof(snd_azf3328_init_values)/sizeof(unsigned int)/2) + +static unsigned int snd_azf3328_init_values[][2] = { + { IDX_MIXER_PLAY_MASTER, MIXER_MUTE_MASK|0x1f1f }, + { IDX_MIXER_MODEMOUT, MIXER_MUTE_MASK|0x1f1f }, + { IDX_MIXER_BASSTREBLE, 0x0000 }, + { IDX_MIXER_PCBEEP, MIXER_MUTE_MASK|0x1f1f }, + { IDX_MIXER_MODEMIN, MIXER_MUTE_MASK|0x1f1f }, + { IDX_MIXER_MIC, MIXER_MUTE_MASK|0x001f }, + { IDX_MIXER_LINEIN, MIXER_MUTE_MASK|0x1f1f }, + { IDX_MIXER_CDAUDIO, MIXER_MUTE_MASK|0x1f1f }, + { IDX_MIXER_VIDEO, MIXER_MUTE_MASK|0x1f1f }, + { IDX_MIXER_AUX, MIXER_MUTE_MASK|0x1f1f }, + { IDX_MIXER_WAVEOUT, MIXER_MUTE_MASK|0x1f1f }, + { IDX_MIXER_FMSYNTH, MIXER_MUTE_MASK|0x1f1f }, + { IDX_MIXER_REC_VOLUME, MIXER_MUTE_MASK|0x0707 }, +}; + +static int __devinit snd_azf3328_mixer_new(azf3328_t *chip) +{ + snd_card_t *card; + snd_kcontrol_new_t *sw; + unsigned int idx; + int err; + + snd_azf3328_dbgcallenter(); + snd_assert(chip != NULL && chip->card != NULL, return -EINVAL); + + card = chip->card; + + /* mixer reset */ + snd_azf3328_mixer_write(chip, IDX_MIXER_RESET, 0x0, WORD_VALUE); + + /* mute and zero volume channels */ + for (idx = 0; idx < AZF3328_INIT_VALUES; idx++) { + snd_azf3328_mixer_write(chip, snd_azf3328_init_values[idx][0], snd_azf3328_init_values[idx][1], WORD_VALUE); + } + + /* add mixer controls */ + sw = snd_azf3328_mixer_controls; + for (idx = 0; idx < NUM_CONTROLS(snd_azf3328_mixer_controls); idx++, sw++) { + if ((err = snd_ctl_add(chip->card, snd_ctl_new1(sw, chip))) < 0) + return err; + } + snd_component_add(card, "AZF3328 mixer"); + strcpy(card->mixername, "AZF3328 mixer"); + + snd_azf3328_dbgcallleave(); + return 0; +} + +static int snd_azf3328_hw_params(snd_pcm_substream_t * substream, + snd_pcm_hw_params_t * hw_params) +{ + int res; + snd_azf3328_dbgcallenter(); + res = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); + snd_azf3328_dbgcallleave(); + return res; +} + +static int snd_azf3328_hw_free(snd_pcm_substream_t * substream) +{ + snd_azf3328_dbgcallenter(); + snd_pcm_lib_free_pages(substream); + snd_azf3328_dbgcallleave(); + return 0; +} + +static void snd_azf3328_setfmt(azf3328_t *chip, + unsigned int reg, + unsigned int bitrate, + unsigned int format_width, + unsigned int channels +) +{ + unsigned int val = 0xff00; + unsigned long flags; + + snd_azf3328_dbgcallenter(); + switch (bitrate) { + case 5512: val |= 0x0d; break; /* the AZF3328 names it "5510" for some strange reason */ + case 6620: val |= 0x0b; break; + case 8000: val |= 0x00; break; + case 9600: val |= 0x08; break; + case 11025: val |= 0x01; break; + case 16000: val |= 0x02; break; + case 22050: val |= 0x03; break; + case 32000: val |= 0x04; break; + case 44100: val |= 0x05; break; + case 48000: val |= 0x06; break; + case 64000: val |= 0x07; break; + default: + snd_printk("unknown bitrate %d, assuming 44.1kHz!\n", bitrate); + val |= 0x05; /* 44100 */ + break; + } + /* val = 0xff07; 3m27.993s (65301Hz; -> 64000Hz???) */ + /* val = 0xff09; 17m15.098s (13123,478Hz; -> 12000Hz???) */ + /* val = 0xff0a; 47m30.599s (4764,891Hz; -> 4800Hz???) */ + /* val = 0xff0c; 57m0.510s (4010,263Hz; -> 4000Hz???) */ + /* val = 0xff05; 5m11.556s (... -> 44100Hz) */ + /* val = 0xff03; 10m21.529s (21872,463Hz; -> 22050Hz???) */ + /* val = 0xff0f; 20m41.883s (10937,993Hz; -> 11025Hz???) */ + /* val = 0xff0d; 41m23.135s (5523,600Hz; -> 5512Hz???) */ + /* val = 0xff0e; 28m30.777s (8017Hz; -> 8000Hz???) */ + if (channels == 2) + val |= SOUNDFORMAT_FLAG_2CHANNELS; + + if (format_width == 16) + val |= SOUNDFORMAT_FLAG_16BIT; + + spin_lock_irqsave(&chip->reg_lock, flags); + + /* set bitrate/format */ + outw(val, chip->codec_port+reg); + + /* changing the bitrate/format settings switches off the + * audio output with an annoying click in case of 8/16bit format change + * (maybe shutting down DAC/ADC?), thus immediately + * do some tweaking to reenable it and get rid of the clicking + * (FIXME: yes, it works, but what exactly am I doing here?? :) + * FIXME: does this have some side effects for full-duplex + * or other dramatic side effects? */ + if (reg == IDX_IO_PLAY_SOUNDFORMAT) /* only do it for playback */ + outw(inw(chip->codec_port + IDX_IO_PLAY_FLAGS)|DMA_PLAY_SOMETHING1|DMA_PLAY_SOMETHING2|SOMETHING_ALMOST_ALWAYS_SET|DMA_EPILOGUE_SOMETHING|DMA_SOMETHING_ELSE, chip->codec_port + IDX_IO_PLAY_FLAGS); + + spin_unlock_irqrestore(&chip->reg_lock, flags); + snd_azf3328_dbgcallleave(); +} + +static void snd_azf3328_setdmaa(azf3328_t *chip, + long unsigned int addr, + unsigned int count, + unsigned int size, + int do_recording) +{ + long unsigned int addr1; + long unsigned int addr2; + unsigned int count1; + unsigned int count2; + unsigned long flags; + int reg_offs = do_recording ? 0x20 : 0x00; + + snd_azf3328_dbgcallenter(); + /* AZF3328 uses a two buffer pointer DMA playback approach */ + if (!chip->is_playing) + { + addr1 = addr; + addr2 = addr+(size/2); + count1 = (size/2)-1; + count2 = (size/2)-1; +#if DEBUG_PLAY_REC + snd_azf3328_dbgplay("setting dma: buf1 %08lx[%d], buf2 %08lx[%d]\n", addr1, count1, addr2, count2); +#endif + spin_lock_irqsave(&chip->reg_lock, flags); + outl(addr1, chip->codec_port+reg_offs+IDX_IO_PLAY_DMA_START_1); + outl(addr2, chip->codec_port+reg_offs+IDX_IO_PLAY_DMA_START_2); + outw(count1, chip->codec_port+reg_offs+IDX_IO_PLAY_DMA_LEN_1); + outw(count2, chip->codec_port+reg_offs+IDX_IO_PLAY_DMA_LEN_2); + spin_unlock_irqrestore(&chip->reg_lock, flags); + } + snd_azf3328_dbgcallleave(); +} + +static int snd_azf3328_playback_prepare(snd_pcm_substream_t *substream) +{ +#if 0 + azf3328_t *chip = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + unsigned int size = snd_pcm_lib_buffer_bytes(substream); + unsigned int count = snd_pcm_lib_period_bytes(substream); +#endif + + snd_azf3328_dbgcallenter(); +#if 0 + snd_azf3328_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT, runtime->rate, snd_pcm_format_width(runtime->format), runtime->channels); + snd_azf3328_setdmaa(chip, runtime->dma_addr, count, size, 0); +#endif + snd_azf3328_dbgcallleave(); + return 0; +} + +static int snd_azf3328_capture_prepare(snd_pcm_substream_t * substream) +{ +#if 0 + azf3328_t *chip = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + unsigned int size = snd_pcm_lib_buffer_bytes(substream); + unsigned int count = snd_pcm_lib_period_bytes(substream); +#endif + + snd_azf3328_dbgcallenter(); +#if 0 + snd_azf3328_setfmt(chip, IDX_IO_REC_SOUNDFORMAT, runtime->rate, snd_pcm_format_width(runtime->format), runtime->channels); + snd_azf3328_setdmaa(chip, runtime->dma_addr, count, size, 1); +#endif + snd_azf3328_dbgcallleave(); + return 0; +} + +static int snd_azf3328_playback_trigger(snd_pcm_substream_t * substream, int cmd) +{ + unsigned long flags; + azf3328_t *chip = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + int result = 0; + unsigned int status1; + + snd_azf3328_dbgcalls("snd_azf3328_playback_trigger cmd %d\n", cmd); + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + + snd_azf3328_dbgio(chip, "trigger1"); + + /* mute WaveOut */ + snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); + + snd_azf3328_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT, runtime->rate, snd_pcm_format_width(runtime->format), runtime->channels); + + spin_lock_irqsave(&chip->reg_lock, flags); + /* stop playback */ + status1 = inw(chip->codec_port+IDX_IO_PLAY_FLAGS); + status1 &= ~DMA_RESUME; + outw(status1, chip->codec_port+IDX_IO_PLAY_FLAGS); + + /* FIXME: clear interrupts or what??? */ + outw(0xffff, chip->codec_port+IDX_IO_PLAY_IRQMASK); + spin_unlock_irqrestore(&chip->reg_lock, flags); + + snd_azf3328_setdmaa(chip, runtime->dma_addr, snd_pcm_lib_period_bytes(substream), snd_pcm_lib_buffer_bytes(substream), 0); + + spin_lock_irqsave(&chip->reg_lock, flags); +#if WIN9X + /* FIXME: enable playback/recording??? */ + status1 |= DMA_PLAY_SOMETHING1 | DMA_PLAY_SOMETHING2; + outw(status1, chip->codec_port+IDX_IO_PLAY_FLAGS); + + /* start playback again */ + /* FIXME: what is this value (0x0010)??? */ + status1 |= DMA_RESUME | DMA_EPILOGUE_SOMETHING; + outw(status1, chip->codec_port+IDX_IO_PLAY_FLAGS); +#else /* NT4 */ + outw(0x00, chip->codec_port+IDX_IO_PLAY_FLAGS); + outw(DMA_PLAY_SOMETHING1, chip->codec_port+IDX_IO_PLAY_FLAGS); + outw(DMA_PLAY_SOMETHING1|DMA_PLAY_SOMETHING2, chip->codec_port+IDX_IO_PLAY_FLAGS); + outw(DMA_RESUME|SOMETHING_ALMOST_ALWAYS_SET|DMA_EPILOGUE_SOMETHING|DMA_SOMETHING_ELSE, chip->codec_port+IDX_IO_PLAY_FLAGS); +#endif + spin_unlock_irqrestore(&chip->reg_lock, flags); + + /* now unmute WaveOut */ + snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 0); + + snd_azf3328_dbgio(chip, "trigger2"); + chip->is_playing = 1; + break; + case SNDRV_PCM_TRIGGER_STOP: + /* mute WaveOut */ + snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); + + spin_lock_irqsave(&chip->reg_lock, flags); + /* stop playback */ + status1 = inw(chip->codec_port+IDX_IO_PLAY_FLAGS); + + status1 &= ~DMA_RESUME; + outw(status1, chip->codec_port+IDX_IO_PLAY_FLAGS); + + status1 |= DMA_PLAY_SOMETHING1; + outw(status1, chip->codec_port+IDX_IO_PLAY_FLAGS); + + status1 &= ~DMA_PLAY_SOMETHING1; + outw(status1, chip->codec_port+IDX_IO_PLAY_FLAGS); + spin_unlock_irqrestore(&chip->reg_lock, flags); + + /* now unmute WaveOut */ + snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 0); + chip->is_playing = 0; + break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + snd_printk("FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n"); + break; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + snd_printk("FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n"); + break; + default: + return -EINVAL; + } + + snd_azf3328_dbgcallleave(); + return result; +} + +/* this is just analogous to playback; I'm not quite sure whether recording + * should actually be triggered like that */ +static int snd_azf3328_capture_trigger(snd_pcm_substream_t * substream, int cmd) +{ + unsigned long flags; + azf3328_t *chip = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + int result = 0; + unsigned int status1; + + snd_azf3328_dbgcalls("snd_azf3328_capture_trigger cmd %d\n", cmd); + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + + snd_azf3328_dbgio(chip, "trigger1"); + + snd_azf3328_setfmt(chip, IDX_IO_REC_SOUNDFORMAT, runtime->rate, snd_pcm_format_width(runtime->format), runtime->channels); + + spin_lock_irqsave(&chip->reg_lock, flags); + /* stop recording */ + status1 = inw(chip->codec_port+IDX_IO_REC_FLAGS); + status1 &= ~DMA_RESUME; + outw(status1, chip->codec_port+IDX_IO_REC_FLAGS); + + /* FIXME: clear interrupts or what??? */ + outw(0xffff, chip->codec_port+IDX_IO_REC_IRQMASK); + spin_unlock_irqrestore(&chip->reg_lock, flags); + + snd_azf3328_setdmaa(chip, runtime->dma_addr, snd_pcm_lib_period_bytes(substream), snd_pcm_lib_buffer_bytes(substream), 1); + + spin_lock_irqsave(&chip->reg_lock, flags); +#if WIN9X + /* FIXME: enable playback/recording??? */ + status1 |= DMA_PLAY_SOMETHING1 | DMA_PLAY_SOMETHING2; + outw(status1, chip->codec_port+IDX_IO_REC_FLAGS); + + /* start playback again */ + /* FIXME: what is this value (0x0010)??? */ + status1 |= DMA_RESUME | DMA_EPILOGUE_SOMETHING; + outw(status1, chip->codec_port+IDX_IO_REC_FLAGS); +#else + outw(0x00, chip->codec_port+IDX_IO_REC_FLAGS); + outw(DMA_PLAY_SOMETHING1, chip->codec_port+IDX_IO_REC_FLAGS); + outw(DMA_PLAY_SOMETHING1|DMA_PLAY_SOMETHING2, chip->codec_port+IDX_IO_REC_FLAGS); + outw(DMA_RESUME|SOMETHING_ALMOST_ALWAYS_SET|DMA_EPILOGUE_SOMETHING|DMA_SOMETHING_ELSE, chip->codec_port+IDX_IO_REC_FLAGS); +#endif + spin_unlock_irqrestore(&chip->reg_lock, flags); + + snd_azf3328_dbgio(chip, "trigger2"); + chip->is_playing = 1; + break; + case SNDRV_PCM_TRIGGER_STOP: + spin_lock_irqsave(&chip->reg_lock, flags); + /* stop recording */ + status1 = inw(chip->codec_port+IDX_IO_REC_FLAGS); + + status1 &= ~DMA_RESUME; + outw(status1, chip->codec_port+IDX_IO_REC_FLAGS); + + status1 |= DMA_PLAY_SOMETHING1; + outw(status1, chip->codec_port+IDX_IO_REC_FLAGS); + + status1 &= ~DMA_PLAY_SOMETHING1; + outw(status1, chip->codec_port+IDX_IO_REC_FLAGS); + spin_unlock_irqrestore(&chip->reg_lock, flags); + + chip->is_playing = 0; + break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + snd_printk("FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n"); + break; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + snd_printk("FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n"); + break; + default: + return -EINVAL; + } + + snd_azf3328_dbgcallleave(); + return result; +} + +static snd_pcm_uframes_t snd_azf3328_playback_pointer(snd_pcm_substream_t * substream) +{ + azf3328_t *chip = snd_pcm_substream_chip(substream); + unsigned long bufptr, playptr; + unsigned long result; + snd_pcm_uframes_t frmres; + unsigned long flags; + + spin_lock_irqsave(&chip->reg_lock, flags); +#if QUERY_HARDWARE + bufptr = inl(chip->codec_port+IDX_IO_PLAY_DMA_START_1); +#else + bufptr = substream->runtime->dma_addr; +#endif + playptr = inl(chip->codec_port+IDX_IO_PLAY_DMA_CURRPOS); + spin_unlock_irqrestore(&chip->reg_lock, flags); + + result = playptr - bufptr; + frmres = bytes_to_frames( substream->runtime, result ); + snd_azf3328_dbgplay("result %lx, playptr %lx (base %x), frames %ld\n", result, playptr, substream->runtime->dma_addr, frmres); + return frmres; +} + +static snd_pcm_uframes_t snd_azf3328_capture_pointer(snd_pcm_substream_t * substream) +{ + azf3328_t *chip = snd_pcm_substream_chip(substream); + unsigned long bufptr, recptr; + unsigned long result; + snd_pcm_uframes_t frmres; + unsigned long flags; + + spin_lock_irqsave(&chip->reg_lock, flags); +#if QUERY_HARDWARE + bufptr = inl(chip->codec_port+IDX_IO_REC_DMA_START_1); +#else + bufptr = substream->runtime->dma_addr; +#endif + recptr = inl(chip->codec_port+IDX_IO_REC_DMA_CURRPOS); + spin_unlock_irqrestore(&chip->reg_lock, flags); + + result = recptr - bufptr; + frmres = bytes_to_frames( substream->runtime, result ); + snd_azf3328_dbgplay("result %lx, rec ptr %lx (base %x), frames %ld\n", result, recptr, substream->runtime->dma_addr, frmres); + return frmres; +} + +static irqreturn_t snd_azf3328_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + azf3328_t *chip = snd_magic_cast(azf3328_t, dev_id, return IRQ_NONE); + unsigned int status, which; + static unsigned long count = 0; + + status = inw(chip->codec_port+IDX_IO_IRQSTATUS); + + /* fast path out, to ease interrupt sharing */ + if (!(status & (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_MPU401|IRQ_SOMEIRQ))) + return IRQ_NONE; /* must be interrupt for another device */ + + snd_azf3328_dbgplay("Interrupt %ld!\nIDX_IO_PLAY_FLAGS %04x, IDX_IO_PLAY_IRQMASK %04x, IDX_IO_IRQSTATUS %04x\n", count, inw(chip->codec_port+IDX_IO_PLAY_FLAGS), inw(chip->codec_port+IDX_IO_PLAY_IRQMASK), inw(chip->codec_port+IDX_IO_IRQSTATUS)); + + if (status & IRQ_PLAYBACK) + { + spin_lock(&chip->reg_lock); + which = inw(chip->codec_port+IDX_IO_PLAY_IRQMASK); + if (which & IRQ_FINISHED_PLAYBUF_1) + /* ack IRQ */ + outw(which | IRQ_FINISHED_PLAYBUF_1, chip->codec_port+IDX_IO_PLAY_IRQMASK); + if (which & IRQ_FINISHED_PLAYBUF_2) + /* ack IRQ */ + outw(which | IRQ_FINISHED_PLAYBUF_2, chip->codec_port+IDX_IO_PLAY_IRQMASK); + if (which & IRQ_PLAY_SOMETHING) + { + snd_azf3328_dbgplay("azt3328: unknown play IRQ type occurred, please report!\n"); + } + if (chip->pcm && chip->playback_substream) + { + snd_azf3328_dbgplay("which %x, playptr %lx\n", which, inl(chip->codec_port+IDX_IO_PLAY_DMA_CURRPOS)); + snd_pcm_period_elapsed(chip->playback_substream); + snd_azf3328_dbgplay("period done, playptr %lx.\n", inl(chip->codec_port+IDX_IO_PLAY_DMA_CURRPOS)); + } + else + snd_azf3328_dbgplay("azt3328: ouch, irq handler problem!\n"); + spin_unlock(&chip->reg_lock); + } + if (status & IRQ_RECORDING) + { + spin_lock(&chip->reg_lock); + which = inw(chip->codec_port+IDX_IO_REC_IRQMASK); + if (which & IRQ_FINISHED_RECBUF_1) + /* ack interrupt */ + outw(which | IRQ_FINISHED_RECBUF_1, chip->codec_port+IDX_IO_REC_IRQMASK); + if (which & IRQ_FINISHED_RECBUF_2) + /* ack interrupt */ + outw(which | IRQ_FINISHED_RECBUF_2, chip->codec_port+IDX_IO_REC_IRQMASK); + if (which & IRQ_REC_SOMETHING) + { + snd_azf3328_dbgplay("azt3328: unknown rec IRQ type occurred, please report!\n"); + } + if (chip->pcm && chip->capture_substream) + { + snd_azf3328_dbgplay("which %x, recptr %lx\n", which, inl(chip->codec_port+IDX_IO_REC_DMA_CURRPOS)); + spin_unlock(&chip->reg_lock); + snd_pcm_period_elapsed(chip->capture_substream); + spin_lock(&chip->reg_lock); + snd_azf3328_dbgplay("period done, recptr %lx.\n", inl(chip->codec_port+IDX_IO_REC_DMA_CURRPOS)); + } + spin_unlock(&chip->reg_lock); + } + if (status & IRQ_MPU401) + snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data, regs); + if (status & IRQ_SOMEIRQ) + snd_azf3328_dbgplay("azt3328: unknown IRQ type occurred, please report!\n"); + count++; + return IRQ_HANDLED; +} + +/*****************************************************************/ + +static snd_pcm_hardware_t snd_azf3328_playback = +{ + /* FIXME!! Correct? */ + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID), + .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE, + .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_64000 | SNDRV_PCM_RATE_KNOT, + .rate_min = 5512, + .rate_max = 64000, + .channels_min = 1, + .channels_max = 2, + .buffer_bytes_max = 65536, + .period_bytes_min = 64, + .period_bytes_max = 65536, + .periods_min = 1, + .periods_max = 1024, + /* FIXME: maybe that card actually has a FIFO? + * Hmm, it seems newer revisions do have one, but we still don't know + * its size... */ + .fifo_size = 0, +}; + +static snd_pcm_hardware_t snd_azf3328_capture = +{ + /* FIXME */ + .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_MMAP_VALID), + .formats = SNDRV_PCM_FMTBIT_S8 | SNDRV_PCM_FMTBIT_U8 | + SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_U16_LE, + .rates = SNDRV_PCM_RATE_8000_48000 | SNDRV_PCM_RATE_64000 | SNDRV_PCM_RATE_KNOT, + .rate_min = 5512, + .rate_max = 64000, + .channels_min = 1, + .channels_max = 2, + .buffer_bytes_max = 65536, + .period_bytes_min = 64, + .period_bytes_max = 65536, + .periods_min = 1, + .periods_max = 1024, + .fifo_size = 0, +}; + + +static unsigned int snd_azf3328_fixed_rates[] = { + 5512, 6620, 8000, 9600, 11025, 16000, 22050, 32000, 44100, 48000, 64000 +}; +static snd_pcm_hw_constraint_list_t snd_azf3328_hw_constraints_rates = { + .count = ARRAY_SIZE(snd_azf3328_fixed_rates), + .list = snd_azf3328_fixed_rates, + .mask = 0, +}; + +/*****************************************************************/ + +static int snd_azf3328_playback_open(snd_pcm_substream_t * substream) +{ + azf3328_t *chip = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + + snd_azf3328_dbgcallenter(); + chip->playback_substream = substream; + runtime->hw = snd_azf3328_playback; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + &snd_azf3328_hw_constraints_rates); + snd_azf3328_dbgcallleave(); + return 0; +} + +static int snd_azf3328_capture_open(snd_pcm_substream_t * substream) +{ + azf3328_t *chip = snd_pcm_substream_chip(substream); + snd_pcm_runtime_t *runtime = substream->runtime; + + snd_azf3328_dbgcallenter(); + chip->capture_substream = substream; + runtime->hw = snd_azf3328_capture; + snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, + &snd_azf3328_hw_constraints_rates); + snd_azf3328_dbgcallleave(); + return 0; +} + +static int snd_azf3328_playback_close(snd_pcm_substream_t * substream) +{ + azf3328_t *chip = snd_pcm_substream_chip(substream); + + snd_azf3328_dbgcallenter(); + + chip->playback_substream = NULL; + snd_azf3328_dbgcallleave(); + return 0; +} + +static int snd_azf3328_capture_close(snd_pcm_substream_t * substream) +{ + azf3328_t *chip = snd_pcm_substream_chip(substream); + + snd_azf3328_dbgcallenter(); + chip->capture_substream = NULL; + snd_azf3328_dbgcallleave(); + return 0; +} + +/******************************************************************/ + +static snd_pcm_ops_t snd_azf3328_playback_ops = { + .open = snd_azf3328_playback_open, + .close = snd_azf3328_playback_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_azf3328_hw_params, + .hw_free = snd_azf3328_hw_free, + .prepare = snd_azf3328_playback_prepare, + .trigger = snd_azf3328_playback_trigger, + .pointer = snd_azf3328_playback_pointer +}; + +static snd_pcm_ops_t snd_azf3328_capture_ops = { + .open = snd_azf3328_capture_open, + .close = snd_azf3328_capture_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_azf3328_hw_params, + .hw_free = snd_azf3328_hw_free, + .prepare = snd_azf3328_capture_prepare, + .trigger = snd_azf3328_capture_trigger, + .pointer = snd_azf3328_capture_pointer +}; + +static void snd_azf3328_pcm_free(snd_pcm_t *pcm) +{ + azf3328_t *chip = snd_magic_cast(azf3328_t, pcm->private_data, return); + chip->pcm = NULL; + snd_pcm_lib_preallocate_free_for_all(pcm); +} + +static int __devinit snd_azf3328_pcm(azf3328_t *chip, int device) +{ + snd_pcm_t *pcm; + int err; + + snd_azf3328_dbgcallenter(); + if ((err = snd_pcm_new(chip->card, "AZF3328 DSP", device, 1, 1, &pcm)) < 0) + return err; + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_azf3328_playback_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_azf3328_capture_ops); + + pcm->private_data = chip; + pcm->private_free = snd_azf3328_pcm_free; + pcm->info_flags = 0; + strcpy(pcm->name, chip->card->shortname); + chip->pcm = pcm; + + snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 64*1024); + + snd_azf3328_dbgcallleave(); + return 0; +} + +/******************************************************************/ + +static int snd_azf3328_free(azf3328_t *chip) +{ + if (chip->irq < 0) + goto __end_hw; + + /* interrupt setup - mask everything */ + /* FIXME */ + + synchronize_irq(chip->irq); + __end_hw: + if (chip->res_codec_port) { + release_resource(chip->res_codec_port); + kfree_nocheck(chip->res_codec_port); + } + if (chip->res_io2_port) { + release_resource(chip->res_io2_port); + kfree_nocheck(chip->res_io2_port); + } + if (chip->res_mpu_port) { + release_resource(chip->res_mpu_port); + kfree_nocheck(chip->res_mpu_port); + } + if (chip->res_synth_port) { + release_resource(chip->res_synth_port); + kfree_nocheck(chip->res_synth_port); + } + if (chip->res_mixer_port) { + release_resource(chip->res_mixer_port); + kfree_nocheck(chip->res_mixer_port); + } + if (chip->irq >= 0) + free_irq(chip->irq, (void *)chip); + + snd_magic_kfree(chip); + return 0; +} + +static int snd_azf3328_dev_free(snd_device_t *device) +{ + azf3328_t *chip = snd_magic_cast(azf3328_t, device->device_data, return -ENXIO); + return snd_azf3328_free(chip); +} + +#if 0 +/* check whether a bit can be modified */ +static void snd_azf3328_test_bit(unsigned int reg, int bit) +{ + unsigned char val, valoff, valon; + + val = inb(reg); + + outb(val & ~(1 << bit), reg); + valoff = inb(reg); + + outb(val|(1 << bit), reg); + valon = inb(reg); + + outb(val, reg); + + printk(KERN_ERR "reg %04x bit %d: %02x %02x %02x\n", reg, bit, val, valoff, valon); +} +#endif + +static int __devinit snd_azf3328_create(snd_card_t * card, + struct pci_dev *pci, + unsigned long device_type, + azf3328_t ** rchip) +{ + unsigned long flags; + azf3328_t *chip; + int err; + static snd_device_ops_t ops = { + .dev_free = snd_azf3328_dev_free, + }; + u16 tmp; + + *rchip = NULL; + + if ((err = pci_enable_device(pci)) < 0) + return err; + + chip = snd_magic_kcalloc(azf3328_t, 0, GFP_KERNEL); + if (chip == NULL) + return -ENOMEM; + spin_lock_init(&chip->reg_lock); + chip->card = card; + chip->pci = pci; + chip->irq = -1; + + /* check if we can restrict PCI DMA transfers to 24 bits */ + if (!pci_dma_supported(pci, 0x00ffffff)) { + snd_printk("architecture does not support 24bit PCI busmaster DMA\n"); + return -ENXIO; + } + pci_set_dma_mask(pci, 0x00ffffff); + + chip->codec_port = pci_resource_start(pci, 0); + if ((chip->res_codec_port = request_region(chip->codec_port, 0x80, "Aztech AZF3328 I/O")) == NULL) { + snd_azf3328_free(chip); + snd_printk("unable to grab I/O port at 0x%lx-0x%lx\n", chip->codec_port, chip->codec_port + 0x80 - 1); + return -EBUSY; + } + chip->io2_port = pci_resource_start(pci, 1); + if ((chip->res_io2_port = request_region(chip->io2_port, 0x08, "Aztech AZF3328 I/O 2")) == NULL) { + snd_azf3328_free(chip); + snd_printk("unable to grab I/O 2 port at 0x%lx-0x%lx\n", chip->io2_port, chip->io2_port + 0x08 - 1); + return -EBUSY; + } + chip->mpu_port = pci_resource_start(pci, 2); + if ((chip->res_mpu_port = request_region(chip->mpu_port, 0x04, "Aztech AZF3328 MPU401")) == NULL) { + snd_azf3328_free(chip); + snd_printk("unable to grab MPU401 port at 0x%lx-0x%lx\n", chip->mpu_port, chip->mpu_port + 0x04 - 1); + return -EBUSY; + } + chip->synth_port = pci_resource_start(pci, 3); + if ((chip->res_synth_port = request_region(chip->synth_port, 0x08, "Aztech AZF3328 OPL3")) == NULL) { + snd_azf3328_free(chip); + snd_printk("unable to grab OPL3 port at 0x%lx-0x%lx\n", chip->synth_port, chip->synth_port + 0x08 - 1); + return -EBUSY; + } + chip->mixer_port = pci_resource_start(pci, 4); + if ((chip->res_mixer_port = request_region(chip->mixer_port, 0x40, "Aztech AZF3328 Mixer")) == NULL) { + snd_azf3328_free(chip); + snd_printk("unable to grab mixer port at 0x%lx-0x%lx\n", chip->mixer_port, chip->mixer_port + 0x40 - 1); + return -EBUSY; + } + + if (request_irq(pci->irq, snd_azf3328_interrupt, SA_INTERRUPT|SA_SHIRQ, card->shortname, (void *)chip)) { + snd_azf3328_free(chip); + snd_printk("unable to grab IRQ %d\n", pci->irq); + return -EBUSY; + } + chip->irq = pci->irq; + pci_set_master(pci); + synchronize_irq(chip->irq); + + snd_azf3328_dbgmisc("codec_port 0x%lx, io2_port 0x%lx, mpu_port 0x%lx, synth_port 0x%lx, mixer_port 0x%lx, irq %d\n", chip->codec_port, chip->io2_port, chip->mpu_port, chip->synth_port, chip->mixer_port, chip->irq); + + snd_azf3328_dbgmisc("io2 %02x %02x %02x %02x %02x %02x\n", snd_azf3328_io2_read(chip, 0), snd_azf3328_io2_read(chip, 1), snd_azf3328_io2_read(chip, 2), snd_azf3328_io2_read(chip, 3), snd_azf3328_io2_read(chip, 4), snd_azf3328_io2_read(chip, 5)); + + for (tmp=0; tmp <= 0x01; tmp += 1) + snd_azf3328_dbgmisc("0x%02x: opl 0x%04x, mpu300 0x%04x, mpu310 0x%04x, mpu320 0x%04x, mpu330 0x%04x\n", tmp, inb(0x388 + tmp), inb(0x300 + tmp), inb(0x310 + tmp), inb(0x320 + tmp), inb(0x330 + tmp)); + + /* create mixer interface & switches */ + if ((err = snd_azf3328_mixer_new(chip)) < 0) + return err; + + if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { + snd_azf3328_free(chip); + return err; + } + +#if 0 + /* set very low bitrate to reduce noise and power consumption? */ + snd_azf3328_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT, 5512, 8, 1); +#endif + + /* standard chip init stuff */ + spin_lock_irqsave(&chip->reg_lock, flags); + outb(DMA_PLAY_SOMETHING2|DMA_EPILOGUE_SOMETHING|DMA_SOMETHING_ELSE, chip->codec_port + IDX_IO_PLAY_FLAGS); + outb(DMA_PLAY_SOMETHING2|DMA_EPILOGUE_SOMETHING|DMA_SOMETHING_ELSE, chip->codec_port + IDX_IO_SOMETHING_FLAGS); + outb(DMA_PLAY_SOMETHING2|DMA_EPILOGUE_SOMETHING|DMA_SOMETHING_ELSE, chip->codec_port + IDX_IO_REC_FLAGS); + outb(0x0, chip->codec_port + IDX_IO_IRQ63H); + + spin_unlock_irqrestore(&chip->reg_lock, flags); + + *rchip = chip; + return 0; +} + +static void __devinit snd_azf3328_config_joystick(azf3328_t *chip, int joystick) +{ + int i, detected = 0, activate = 0; + char *msg = NULL; + unsigned char val; + + if (joystick == -1) /* auto detection/activation */ + { + for (i=0x200; i <= 0x207; i++) + if (inb(i) != 0xff) + detected = 1; /* other joy found, don't activate */ + } + + if ((joystick == -1) && (detected == 1)) + { + activate = 0; + msg = "DISABLED (address occupied by another joystick port)"; + } + else + if ((joystick == -1) && (detected == 0)) + { + activate = 1; + msg = "ENABLED (via autodetect)"; + } + else + if (joystick == 0) + { + activate = 0; + msg = "DISABLED (forced)"; + } + else + if (joystick == 1) + { + activate = 1; + msg = "ENABLED (Warning: forced!)"; + } + val = inb(chip->io2_port + IDX_IO2_LEGACY_ADDR); + if (activate) + val |= LEGACY_JOY; + else + val &= ~LEGACY_JOY; + + outb(val, chip->io2_port + IDX_IO2_LEGACY_ADDR); +#ifdef MODULE + printk("azt3328: Joystick port: %s.\n", msg); +#endif +} + +static int __devinit snd_azf3328_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) +{ + static int dev; + snd_card_t *card; + azf3328_t *chip; + opl3_t *opl3; + int err; + + snd_azf3328_dbgcallenter(); + if (dev >= SNDRV_CARDS) + return -ENODEV; + if (!enable[dev]) { + dev++; + return -ENOENT; + } + + card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0 ); + if (card == NULL) + return -ENOMEM; + + strcpy(card->driver, "AZF3328"); + strcpy(card->shortname, "Aztech AZF3328 (PCI168)"); + + if ((err = snd_azf3328_create(card, pci, pci_id->driver_data, &chip)) < 0) { + snd_card_free(card); + return err; + } + + if ((err = snd_mpu401_uart_new( card, 0, MPU401_HW_MPU401, + chip->mpu_port, 1, pci->irq, 0, + &chip->rmidi)) < 0) { + snd_card_free(card); + snd_printk("azf3328: no MPU-401 device at 0x%lx?\n", chip->mpu_port); + return err; + } + + if ((err = snd_azf3328_pcm(chip, 0)) < 0) { + snd_card_free(card); + return err; + } + + if (snd_opl3_create(card, chip->synth_port, chip->synth_port+2, + OPL3_HW_AUTO, 1, &opl3) < 0) { + snd_printk("azf3328: no OPL3 device at 0x%lx-0x%lx?\n", + chip->synth_port, chip->synth_port+2 ); + } else { + if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { + snd_card_free(card); + return err; + } + } + + snd_azf3328_dbgio(chip, "create"); + + sprintf(card->longname, "%s at 0x%lx, irq %i", + card->shortname, chip->codec_port, chip->irq); + + if ((err = snd_card_register(card)) < 0) { + snd_card_free(card); + return err; + } + +#ifdef MODULE + printk( +"azt3328: Experimental driver for Aztech AZF3328-based soundcards such as PCI168.\n" +"azt3328: ZERO support from Aztech: you might think hard about future purchase.\n" +"azt3328: Feel free to contact hw7oshyuv3001@sneakemail.com for bug reports etc.!\n"); +#endif + + snd_azf3328_config_joystick(chip, joystick[dev]); + + pci_set_drvdata(pci, chip); + dev++; + + snd_azf3328_dbgcallleave(); + return 0; +} + +static void __devexit snd_azf3328_remove(struct pci_dev *pci) +{ + azf3328_t *chip = snd_magic_cast(azf3328_t, pci_get_drvdata(pci), return); + + snd_azf3328_dbgcallenter(); + + /* reset (close) mixer */ + snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1); /* first mute master volume */ + snd_azf3328_mixer_write(chip, IDX_MIXER_RESET, 0x0, WORD_VALUE); + + if (chip) + snd_card_free(chip->card); + pci_set_drvdata(pci, NULL); + snd_azf3328_dbgcallleave(); +} + +static struct pci_driver driver = { + .name = "AZF3328", + .id_table = snd_azf3328_ids, + .probe = snd_azf3328_probe, + .remove = __devexit_p(snd_azf3328_remove), +}; + +static int __init alsa_card_azf3328_init(void) +{ + int err; + + snd_azf3328_dbgcallenter(); + + if ((err = pci_module_init(&driver)) < 0) + { +#ifdef MODULE + printk(KERN_ERR "azt3328: no AZF3328 based soundcards found or device busy\n"); +#endif + return err; + } + snd_azf3328_dbgcallleave(); + return 0; +} + +static void __exit alsa_card_azf3328_exit(void) +{ + snd_azf3328_dbgcallenter(); + pci_unregister_driver(&driver); + snd_azf3328_dbgcallleave(); +} + +module_init(alsa_card_azf3328_init) +module_exit(alsa_card_azf3328_exit) + +#ifndef MODULE + +/* format is: snd-azf3328=enable,index,id */ + +static int __init alsa_card_azf3328_setup(char *str) +{ + static unsigned __initdata nr_dev = 0; + + snd_azf3328_dbgcallenter(); + + if (nr_dev >= SNDRV_CARDS) + return 0; + (void)(get_option(&str,&enable[nr_dev]) == 2 && + get_option(&str,&index[nr_dev]) == 2 && + get_id(&str,&id[nr_dev]) == 2); + nr_dev++; + snd_azf3328_dbgcallleave(); + return 1; +} + +__setup("snd-azf3328=", alsa_card_azf3328_setup); + +#endif /* ifndef MODULE */ diff -Nru a/sound/pci/azt3328.h b/sound/pci/azt3328.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/azt3328.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,165 @@ +#ifndef __SOUND_AZF3328_H +#define __SOUND_AZF3328_H + +/* type argument to use for the I/O functions */ +#define WORD_VALUE 0x1000 +#define DWORD_VALUE 0x2000 +#define BYTE_VALUE 0x4000 + +/*** main I/O area port indices ***/ +/* (only 0x70 of 0x80 bytes saved/restored by Windows driver) */ +/* the driver initialisation suggests a layout of 3 main areas: + * from 0x00 (playback), from 0x20 (recording) and from 0x40 (maybe DirectX + * timer ???). and probably another area from 0x60 to 0x6f + * (IRQ management, power management etc. ???). */ +/* playback area */ +#define IDX_IO_PLAY_FLAGS 0x00 + /* able to reactivate output after output muting due to 8/16bit + * output change, just like 0x0002. + * 0x0001 is the only bit that's able to start the DMA counter */ + #define DMA_RESUME 0x0001 /* paused if cleared ? */ + /* 0x0002 *temporarily* set during DMA stopping. hmm + * both 0x0002 and 0x0004 set in playback setup. */ + /* able to reactivate output after output muting due to 8/16bit + * output change, just like 0x0001. */ + #define DMA_PLAY_SOMETHING1 0x0002 /* \ alternated (toggled) */ + /* 0x0004: NOT able to reactivate output */ + #define DMA_PLAY_SOMETHING2 0x0004 /* / bits */ + #define SOMETHING_ALMOST_ALWAYS_SET 0x0008 /* ???; can be modified */ + #define DMA_EPILOGUE_SOMETHING 0x0010 + #define DMA_SOMETHING_ELSE 0x0020 /* ??? */ + #define SOMETHING_UNMODIFIABLE 0xffc0 /* unused ? not modifiable */ +#define IDX_IO_PLAY_IRQMASK 0x02 + /* write back to flags in case flags are set, in order to ACK IRQ in handler + * (bit 1 of port 0x64 indicates interrupt for one of these three types) + * sometimes in this case it just writes 0xffff to globally ACK all IRQs + * settings written are not reflected when reading back, though. + * seems to be IRQ, too (frequently used: port |= 0x07 !), but who knows ? */ + #define IRQ_PLAY_SOMETHING 0x0001 /* something & ACK */ + #define IRQ_FINISHED_PLAYBUF_1 0x0002 /* 1st dmabuf finished & ACK */ + #define IRQ_FINISHED_PLAYBUF_2 0x0004 /* 2nd dmabuf finished & ACK */ + #define IRQMASK_SOME_STATUS_1 0x0008 /* \ related bits */ + #define IRQMASK_SOME_STATUS_2 0x0010 /* / (checked together in loop) */ + #define IRQMASK_UNMODIFIABLE 0xffe0 /* unused ? not modifiable */ +#define IDX_IO_PLAY_DMA_START_1 0x04 /* start address of 1st DMA play area */ +#define IDX_IO_PLAY_DMA_START_2 0x08 /* start address of 2nd DMA play area */ +#define IDX_IO_PLAY_DMA_LEN_1 0x0c /* length of 1st DMA play area */ +#define IDX_IO_PLAY_DMA_LEN_2 0x0e /* length of 2nd DMA play area */ +#define IDX_IO_PLAY_DMA_CURRPOS 0x10 /* current DMA position */ +#define IDX_IO_PLAY_DMA_CURROFS 0x14 /* offset within current DMA play area */ +#define IDX_IO_PLAY_SOUNDFORMAT 0x16 + /* all unspecified bits can't be modified */ + #define SOUNDFORMAT_FREQUENCY_MASK 0x000f + /* all _SUSPECTED_ values are not used by Windows drivers, so we don't + * have any hard facts, only rough measurements */ + #define SOUNDFORMAT_FREQ_SUSPECTED_4000 0x0c + #define SOUNDFORMAT_FREQ_SUSPECTED_4800 0x0a + #define SOUNDFORMAT_FREQ_5510 0x0d + #define SOUNDFORMAT_FREQ_6620 0x0b + #define SOUNDFORMAT_FREQ_8000 0x00 /* also 0x0e ? */ + #define SOUNDFORMAT_FREQ_9600 0x08 + #define SOUNDFORMAT_FREQ_SUSPECTED_12000 0x09 + #define SOUNDFORMAT_FREQ_11025 0x01 /* also 0x0f ? */ + #define SOUNDFORMAT_FREQ_16000 0x02 + #define SOUNDFORMAT_FREQ_22050 0x03 + #define SOUNDFORMAT_FREQ_32000 0x04 + #define SOUNDFORMAT_FREQ_44100 0x05 + #define SOUNDFORMAT_FREQ_48000 0x06 + #define SOUNDFORMAT_FREQ_SUSPECTED_64000 0x07 + #define SOUNDFORMAT_FLAG_16BIT 0x0010 + #define SOUNDFORMAT_FLAG_2CHANNELS 0x0020 +/* recording area (see also: playback bit flag definitions) */ +#define IDX_IO_REC_FLAGS 0x20 /* ?? */ +#define IDX_IO_REC_IRQMASK 0x22 /* ?? */ + #define IRQ_REC_SOMETHING 0x0001 /* something & ACK */ + #define IRQ_FINISHED_RECBUF_1 0x0002 /* 1st dmabuf finished & ACK */ + #define IRQ_FINISHED_RECBUF_2 0x0004 /* 2nd dmabuf finished & ACK */ + /* hmm, maybe these are just the corresponding *recording* flags ? + * but OTOH they are most likely at port 0x22 instead */ + #define IRQMASK_SOME_STATUS_1 0x0008 /* \ related bits */ + #define IRQMASK_SOME_STATUS_2 0x0010 /* / (checked together in loop) */ +#define IDX_IO_REC_DMA_START_1 0x24 +#define IDX_IO_REC_DMA_START_2 0x28 +#define IDX_IO_REC_DMA_LEN_1 0x2c +#define IDX_IO_REC_DMA_LEN_2 0x2e +#define IDX_IO_REC_DMA_CURRPOS 0x30 +#define IDX_IO_REC_DMA_CURROFS 0x34 +#define IDX_IO_REC_SOUNDFORMAT 0x36 +/* some third area ? (after playback and recording) */ +#define IDX_IO_SOMETHING_FLAGS 0x40 /* gets set to 0x34 just like port 0x0 and 0x20 on card init */ +/* general */ +#define IDX_IO_60H 0x60 /* writing 0xffff returns 0xffff */ +#define IDX_IO_62H 0x62 /* writing to WORD 0x0062 can hang the box ! --> responsible for IRQ management as a whole ?? */ +#define IDX_IO_IRQ63H 0x63 /* FIXME !! */ + #define IO_IRQ63H_SOMETHING 0x04 /* being set in IRQ handler in case port 0x00 had 0x0020 set upon IRQ handler */ +#define IDX_IO_IRQSTATUS 0x64 + #define IRQ_PLAYBACK 0x0001 + #define IRQ_RECORDING 0x0002 + #define IRQ_MPU401 0x0010 + #define IRQ_SOMEIRQ 0x0020 /* ???? */ + #define IRQ_WHO_KNOWS_UNUSED 0x00e0 /* probably unused */ +#define IDX_IO_66H 0x66 /* writing 0xffff returns 0x0000 */ +#define IDX_IO_SOME_VALUE 0x68 /* this is always set to 0x3ff, and writable; maybe some buffer limit, but I couldn't find out more */ +#define IDX_IO_6AH 0x6A /* this WORD can be set to have bits 0x0028 activated; actually inhibits PCM playback !!! maybe power management ?? */ +#define IDX_IO_6CH 0x6C /* this WORD can have all its bits activated ? */ +#define IDX_IO_6EH 0x6E /* writing 0xffff returns 0x83fe */ +/* further I/O indices not saved/restored, so probably not used */ + +/*** I/O 2 area port indices ***/ +/* (only 0x06 of 0x08 bytes saved/restored by Windows driver) */ +#define IDX_IO2_LEGACY_ADDR 0x04 + #define LEGACY_SOMETHING 0x01 /* OPL3 ?? */ + #define LEGACY_JOY 0x08 + +/*** mixer I/O area port indices ***/ +/* (only 0x22 of 0x40 bytes saved/restored by Windows driver) + * generally spoken: AC97 register index = AZF3328 mixer reg index + 2 + * (in other words: AZF3328 NOT fully AC97 compliant) */ + #define MIXER_VOLUME_RIGHT_MASK 0x001f + #define MIXER_VOLUME_LEFT_MASK 0x1f00 + #define MIXER_MUTE_MASK 0x8000 +#define IDX_MIXER_RESET 0x00 /* does NOT seem to have AC97 ID bits */ +#define IDX_MIXER_PLAY_MASTER 0x02 +#define IDX_MIXER_MODEMOUT 0x04 +#define IDX_MIXER_BASSTREBLE 0x06 + #define MIXER_BASSTREBLE_TREBLE_VOLUME_MASK 0x000e + #define MIXER_BASSTREBLE_BASS_VOLUME_MASK 0x0e00 +#define IDX_MIXER_PCBEEP 0x08 +#define IDX_MIXER_MODEMIN 0x0a +#define IDX_MIXER_MIC 0x0c + #define MIXER_MIC_MICGAIN_20DB_ENHANCEMENT_MASK 0x0040 +#define IDX_MIXER_LINEIN 0x0e +#define IDX_MIXER_CDAUDIO 0x10 +#define IDX_MIXER_VIDEO 0x12 +#define IDX_MIXER_AUX 0x14 +#define IDX_MIXER_WAVEOUT 0x16 +#define IDX_MIXER_FMSYNTH 0x18 +#define IDX_MIXER_REC_SELECT 0x1a + #define MIXER_REC_SELECT_MIC 0x00 + #define MIXER_REC_SELECT_CD 0x01 + #define MIXER_REC_SELECT_VIDEO 0x02 + #define MIXER_REC_SELECT_AUX 0x03 + #define MIXER_REC_SELECT_LINEIN 0x04 + #define MIXER_REC_SELECT_MIXSTEREO 0x05 + #define MIXER_REC_SELECT_MIXMONO 0x06 + #define MIXER_REC_SELECT_MONOIN 0x07 +#define IDX_MIXER_REC_VOLUME 0x1c +#define IDX_MIXER_ADVCTL1 0x1e + /* unlisted bits are unmodifiable */ + #define MIXER_ADVCTL1_3DWIDTH_MASK 0x000e + #define MIXER_ADVCTL1_HIFI3D_MASK 0x0300 +#define IDX_MIXER_ADVCTL2 0x20 /* resembles AC97_GENERAL_PURPOSE reg ! */ + /* unlisted bits are unmodifiable */ + #define MIXER_ADVCTL2_BIT7 0x0080 /* WaveOut 3D Bypass ? mutes WaveOut at LineOut */ + #define MIXER_ADVCTL2_BIT8 0x0100 /* is this Modem Out Select ? */ + #define MIXER_ADVCTL2_BIT9 0x0200 /* Mono Select Source ? */ + #define MIXER_ADVCTL2_BIT13 0x2000 /* 3D enable ? */ + #define MIXER_ADVCTL2_BIT15 0x8000 /* unknown */ + +#define IDX_MIXER_SOMETHING30H 0x30 /* used, but unknown ??? */ + +/* driver internal flags */ +#define SET_CHAN_LEFT 1 +#define SET_CHAN_RIGHT 2 + +#endif /* __SOUND_AZF3328_H */ diff -Nru a/sound/pci/cmipci.c b/sound/pci/cmipci.c --- a/sound/pci/cmipci.c Mon Jun 9 23:16:15 2003 +++ b/sound/pci/cmipci.c Mon Jun 9 23:16:15 2003 @@ -1496,6 +1496,7 @@ /* SPD24SEL for 037, 0x02 */ /* SPD24SEL for 039, 0x20, but cannot be set */ snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_SPD24SEL); + snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL); } else { /* can_ac3_sw */ #ifdef DO_SOFT_AC3 /* FIXME: ugly hack! */ @@ -1519,7 +1520,14 @@ snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_AC3EN2); if (cm->can_ac3_hw) { - snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_SPD24SEL); + /* chip model >= 37 */ + if (snd_pcm_format_width(subs->runtime->format) > 16) { + snd_cmipci_set_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL); + snd_cmipci_set_bit(cm, CM_REG_CHFORMAT, CM_SPD24SEL); + } else { + snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL); + snd_cmipci_clear_bit(cm, CM_REG_CHFORMAT, CM_SPD24SEL); + } } else { #ifdef DO_SOFT_AC3 snd_cmipci_clear_bit(cm, CM_REG_MISC_CTRL, CM_SPD32SEL); @@ -1669,7 +1677,6 @@ if ((status & CM_CHINT1) && cm->channel[1].running) snd_pcm_period_elapsed(cm->channel[1].substream); } - return IRQ_HANDLED; } @@ -1742,7 +1749,7 @@ { .info = (SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_PAUSE), - .formats = SNDRV_PCM_FMTBIT_S16_LE /*| SNDRV_PCM_FMTBIT_S32_LE*/, + .formats = SNDRV_PCM_FMTBIT_S16_LE, .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, .rate_min = 44100, .rate_max = 48000, @@ -1897,6 +1904,8 @@ if (cm->can_ac3_hw) #endif runtime->hw.info |= SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID; + if (cm->chip_version >= 37) + runtime->hw.formats |= SNDRV_PCM_FMTBIT_S32_LE; snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 0, 0x40000); cm->dig_pcm_status = cm->dig_status; return 0; diff -Nru a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c --- a/sound/pci/cs46xx/cs46xx_lib.c Mon Jun 9 23:16:07 2003 +++ b/sound/pci/cs46xx/cs46xx_lib.c Mon Jun 9 23:16:07 2003 @@ -2545,6 +2545,14 @@ chip->eapd_switch = snd_ctl_find_id(chip->card, &id); #ifdef CONFIG_SND_CS46XX_NEW_DSP + if (chip->nr_ac97_codecs == 1 && + snd_cs46xx_codec_read(chip, AC97_VENDOR_ID2, + CS46XX_PRIMARY_CODEC_INDEX) == 0x592d) { + /* set primary cs4294 codec into Extended Audio Mode */ + snd_printdd("setting EAM bit on cs4294 CODEC\n"); + snd_cs46xx_codec_write(chip, AC97_CSR_ACMODE, 0x200, + CS46XX_PRIMARY_CODEC_INDEX); + } /* do soundcard specific mixer setup */ if (chip->mixer_init) { snd_printdd ("calling chip->mixer_init(chip);\n"); diff -Nru a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c --- a/sound/pci/emu10k1/emufx.c Mon Jun 9 23:16:13 2003 +++ b/sound/pci/emu10k1/emufx.c Mon Jun 9 23:16:13 2003 @@ -2204,7 +2204,7 @@ unsigned short fxbus_mask, extin_mask, extout_mask; int res; - memset(info, 0, sizeof(*info)); + memset(info, 0, sizeof(info)); info->card = emu->card_type; info->internal_tram_size = emu->fx8010.itram_size; info->external_tram_size = emu->fx8010.etram_size; diff -Nru a/sound/pci/emu10k1/irq.c b/sound/pci/emu10k1/irq.c --- a/sound/pci/emu10k1/irq.c Mon Jun 9 23:16:15 2003 +++ b/sound/pci/emu10k1/irq.c Mon Jun 9 23:16:15 2003 @@ -33,22 +33,24 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs) { emu10k1_t *emu = snd_magic_cast(emu10k1_t, dev_id, return IRQ_NONE); - unsigned int status; + unsigned int status, orig_status; int handled = 0; while ((status = inl(emu->port + IPR)) != 0) { // printk("irq - status = 0x%x\n", status); + orig_status = status; handled = 1; if (status & IPR_PCIERROR) { snd_printk("interrupt: PCI error\n"); snd_emu10k1_intr_disable(emu, INTE_PCIERRORENABLE); + status &= ~IPR_PCIERROR; } if (status & (IPR_VOLINCR|IPR_VOLDECR|IPR_MUTE)) { if (emu->hwvol_interrupt) emu->hwvol_interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_VOLINCRENABLE|INTE_VOLDECRENABLE|INTE_MUTEENABLE); - outl(status & (IPR_VOLINCR|IPR_VOLDECR|IPR_MUTE), emu->port + IPR); + status &= ~(IPR_VOLINCR|IPR_VOLDECR|IPR_MUTE); } if (status & IPR_CHANNELLOOP) { int voice; @@ -88,64 +90,69 @@ pvoice++; } } - outl(IPR_CHANNELLOOP | (status & IPR_CHANNELNUMBERMASK), emu->port + IPR); + status &= ~IPR_CHANNELLOOP; } + status &= ~IPR_CHANNELNUMBERMASK; if (status & (IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL)) { if (emu->capture_interrupt) emu->capture_interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_ADCBUFENABLE); - outl(status & (IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL), emu->port + IPR); + status &= ~(IPR_ADCBUFFULL|IPR_ADCBUFHALFFULL); } if (status & (IPR_MICBUFFULL|IPR_MICBUFHALFFULL)) { if (emu->capture_mic_interrupt) emu->capture_mic_interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_MICBUFENABLE); - outl(status & (IPR_MICBUFFULL|IPR_MICBUFHALFFULL), emu->port + IPR); + status &= ~(IPR_MICBUFFULL|IPR_MICBUFHALFFULL); } if (status & (IPR_EFXBUFFULL|IPR_EFXBUFHALFFULL)) { if (emu->capture_efx_interrupt) emu->capture_efx_interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_EFXBUFENABLE); - outl(status & (IPR_EFXBUFFULL|IPR_EFXBUFHALFFULL), emu->port + IPR); + status &= ~(IPR_EFXBUFFULL|IPR_EFXBUFHALFFULL); } if (status & (IPR_MIDITRANSBUFEMPTY|IPR_MIDIRECVBUFEMPTY)) { if (emu->midi.interrupt) emu->midi.interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_MIDITXENABLE|INTE_MIDIRXENABLE); - outl(status & (IPR_MIDITRANSBUFEMPTY|IPR_MIDIRECVBUFEMPTY), emu->port + IPR); + status &= ~(IPR_MIDITRANSBUFEMPTY|IPR_MIDIRECVBUFEMPTY); } if (status & (IPR_A_MIDITRANSBUFEMPTY2|IPR_A_MIDIRECVBUFEMPTY2)) { if (emu->midi2.interrupt) emu->midi2.interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_A_MIDITXENABLE2|INTE_A_MIDIRXENABLE2); - outl(status & (IPR_A_MIDITRANSBUFEMPTY2|IPR_A_MIDIRECVBUFEMPTY2), emu->port + IPR); + status &= ~(IPR_A_MIDITRANSBUFEMPTY2|IPR_A_MIDIRECVBUFEMPTY2); } if (status & IPR_INTERVALTIMER) { if (emu->timer_interrupt) emu->timer_interrupt(emu); else snd_emu10k1_intr_disable(emu, INTE_INTERVALTIMERENB); - outl(IPR_INTERVALTIMER, emu->port + IPR); + status &= ~IPR_INTERVALTIMER; } if (status & (IPR_GPSPDIFSTATUSCHANGE|IPR_CDROMSTATUSCHANGE)) { if (emu->spdif_interrupt) emu->spdif_interrupt(emu, status); else snd_emu10k1_intr_disable(emu, INTE_GPSPDIFENABLE|INTE_CDSPDIFENABLE); - outl(status & (IPR_GPSPDIFSTATUSCHANGE|IPR_CDROMSTATUSCHANGE), emu->port + IPR); + status &= ~(IPR_GPSPDIFSTATUSCHANGE|IPR_CDROMSTATUSCHANGE); } if (status & IPR_FXDSP) { if (emu->dsp_interrupt) emu->dsp_interrupt(emu); else snd_emu10k1_intr_disable(emu, INTE_FXDSPENABLE); - outl(IPR_FXDSP, emu->port + IPR); + status &= ~IPR_FXDSP; } + if (status) { + snd_printd(KERN_WARNING "emu10k1: unhandled interrupt: 0x%08x\n", status); + } + outl(orig_status, emu->port + IPR); /* ack */ } return IRQ_RETVAL(handled); } diff -Nru a/sound/pci/ens1370.c b/sound/pci/ens1370.c --- a/sound/pci/ens1370.c Mon Jun 9 23:16:17 2003 +++ b/sound/pci/ens1370.c Mon Jun 9 23:16:17 2003 @@ -111,8 +111,11 @@ #define ES_REG_CONTROL 0x00 /* R/W: Interrupt/Chip select control register */ #define ES_1370_ADC_STOP (1<<31) /* disable capture buffer transfers */ #define ES_1370_XCTL1 (1<<30) /* general purpose output bit */ -#define ES_1373_TEST_BIT (1<<29) /* should be set to 0 for normal operation */ -#define ES_1373_RECEN_B (1<<28) /* mix record with playback for I2S/SPDIF out */ +#define ES_1373_BYPASS_P1 (1<<31) /* bypass SRC for PB1 */ +#define ES_1373_BYPASS_P2 (1<<30) /* bypass SRC for PB2 */ +#define ES_1373_BYPASS_R (1<<29) /* bypass SRC for REC */ +#define ES_1373_TEST_BIT (1<<28) /* should be set to 0 for normal operation */ +#define ES_1373_RECEN_B (1<<27) /* mix record with playback for I2S/SPDIF out */ #define ES_1373_SPDIF_THRU (1<<26) /* 0 = SPDIF thru mode, 1 = SPDIF == dig out */ #define ES_1371_JOY_ASEL(o) (((o)&0x03)<<24)/* joystick port mapping */ #define ES_1371_JOY_ASELM (0x03<<24) /* mask for above */ @@ -739,8 +742,10 @@ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: { unsigned int what = 0; - snd_pcm_substream_t *s = substream; - do { + struct list_head *pos; + snd_pcm_substream_t *s; + snd_pcm_group_for_each(pos, substream) { + s = snd_pcm_group_substream_entry(pos); if (s == ensoniq->playback1_substream) { what |= ES_P1_PAUSE; snd_pcm_trigger_done(s, substream); @@ -749,8 +754,7 @@ snd_pcm_trigger_done(s, substream); } else if (s == ensoniq->capture_substream) return -EINVAL; - s = s->link_next; - } while (s != substream); + } spin_lock(&ensoniq->reg_lock); if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH) ensoniq->sctrl |= what; @@ -764,8 +768,10 @@ case SNDRV_PCM_TRIGGER_STOP: { unsigned int what = 0; - snd_pcm_substream_t *s = substream; - do { + struct list_head *pos; + snd_pcm_substream_t *s; + snd_pcm_group_for_each(pos, substream) { + s = snd_pcm_group_substream_entry(pos); if (s == ensoniq->playback1_substream) { what |= ES_DAC1_EN; snd_pcm_trigger_done(s, substream); @@ -776,8 +782,7 @@ what |= ES_ADC_EN; snd_pcm_trigger_done(s, substream); } - s = s->link_next; - } while (s != substream); + } spin_lock(&ensoniq->reg_lock); if (cmd == SNDRV_PCM_TRIGGER_START) ensoniq->ctrl |= what; @@ -1509,6 +1514,7 @@ ac97.read = snd_es1371_codec_read; ac97.private_data = ensoniq; ac97.private_free = snd_ensoniq_mixer_free_ac97; + ac97.scaps = AC97_SCAP_AUDIO; if ((err = snd_ac97_mixer(card, &ac97, &ensoniq->u.es1371.ac97)) < 0) return err; for (idx = 0; es1371_spdif_present[idx].vid != (unsigned short)PCI_ANY_ID; idx++) @@ -1628,8 +1634,10 @@ /* try reset AK4531 */ outw(ES_1370_CODEC_WRITE(AK4531_RESET, 0x02), ES_REG(ensoniq, 1370_CODEC)); + inw(ES_REG(ensoniq, 1370_CODEC)); udelay(100); outw(ES_1370_CODEC_WRITE(AK4531_RESET, 0x03), ES_REG(ensoniq, 1370_CODEC)); + inw(ES_REG(ensoniq, 1370_CODEC)); udelay(100); memset(&ak4531, 0, sizeof(ak4531)); @@ -1969,6 +1977,7 @@ } /* AC'97 warm reset to start the bitclk */ outl(ensoniq->ctrl | ES_1371_SYNC_RES, ES_REG(ensoniq, CONTROL)); + inl(ES_REG(ensoniq, CONTROL)); udelay(20); outl(ensoniq->ctrl, ES_REG(ensoniq, CONTROL)); /* Init the sample rate converter */ diff -Nru a/sound/pci/fm801.c b/sound/pci/fm801.c --- a/sound/pci/fm801.c Mon Jun 9 23:16:16 2003 +++ b/sound/pci/fm801.c Mon Jun 9 23:16:16 2003 @@ -959,6 +959,7 @@ /* codec cold reset + AC'97 warm reset */ outw((1<<5)|(1<<6), FM801_REG(chip, CODEC_CTRL)); + inw(FM801_REG(chip, CODEC_CTRL)); /* flush posting data */ udelay(100); outw(0, FM801_REG(chip, CODEC_CTRL)); diff -Nru a/sound/pci/ice1712/Makefile b/sound/pci/ice1712/Makefile --- a/sound/pci/ice1712/Makefile Mon Jun 9 23:16:10 2003 +++ b/sound/pci/ice1712/Makefile Mon Jun 9 23:16:10 2003 @@ -3,8 +3,8 @@ # Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz> # -snd-ice1712-objs := ice1712.o ak4524.o delta.o hoontech.o ews.o -snd-ice1724-objs := ice1724.o ak4524.o amp.o revo.o +snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o ak4xxx.o +snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o ak4xxx.o # Toplevel Module Dependency obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o diff -Nru a/sound/pci/ice1712/ak4524.c b/sound/pci/ice1712/ak4524.c --- a/sound/pci/ice1712/ak4524.c Mon Jun 9 23:16:14 2003 +++ /dev/null Wed Dec 31 16:00:00 1969 @@ -1,525 +0,0 @@ -/* - * ALSA driver for ICEnsemble ICE1712 (Envy24) - * - * AK4524 / AK4528 / AK4529 / AK4355 / AK4381 interface - * - * Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the 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 <sound/driver.h> -#include <asm/io.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/init.h> -#include <sound/core.h> -#include "ice1712.h" - - -/* - * write AK4xxx register - */ -void snd_ice1712_akm4xxx_write(akm4xxx_t *ak, int chip, - unsigned char addr, unsigned char data) -{ - unsigned int tmp; - int idx; - unsigned int addrdata; - ice1712_t *ice = ak->chip; - - snd_assert(chip >= 0 && chip < 4, return); - - if (ak->ops.start) { - if (ak->ops.start(ak, chip) < 0) - return; - } else - snd_ice1712_save_gpio_status(ice); - - tmp = snd_ice1712_gpio_read(ice); - tmp |= ak->add_flags; - tmp &= ~ak->mask_flags; - if (ak->cs_mask == ak->cs_addr) { - if (ak->cif) { - tmp |= ak->cs_mask; /* start without chip select */ - } else { - tmp &= ~ak->cs_mask; /* chip select low */ - snd_ice1712_gpio_write(ice, tmp); - udelay(1); - } - } else { - /* doesn't handle cf=1 yet */ - tmp &= ~ak->cs_mask; - tmp |= ak->cs_addr; - snd_ice1712_gpio_write(ice, tmp); - udelay(1); - } - - /* build I2C address + data byte */ - addrdata = (ak->caddr << 6) | 0x20 | (addr & 0x1f); - addrdata = (addrdata << 8) | data; - for (idx = 15; idx >= 0; idx--) { - /* drop clock */ - tmp &= ~ak->clk_mask; - snd_ice1712_gpio_write(ice, tmp); - udelay(1); - /* set data */ - if (addrdata & (1 << idx)) - tmp |= ak->data_mask; - else - tmp &= ~ak->data_mask; - snd_ice1712_gpio_write(ice, tmp); - udelay(1); - /* raise clock */ - tmp |= ak->clk_mask; - snd_ice1712_gpio_write(ice, tmp); - udelay(1); - } - - /* save the data */ - if (ak->type == SND_AK4524 || ak->type == SND_AK4528) { - if ((addr != 0x04 && addr != 0x05) || (data & 0x80) == 0) - ak->images[chip][addr] = data; - else - ak->ipga_gain[chip][addr-4] = data; - } else { - /* AK4529, or else */ - ak->images[chip][addr] = data; - } - - if (ak->cs_mask == ak->cs_addr) { - if (ak->cif) { - /* assert a cs pulse to trigger */ - tmp &= ~ak->cs_mask; - snd_ice1712_gpio_write(ice, tmp); - udelay(1); - } - tmp |= ak->cs_mask; /* chip select high to trigger */ - } else { - tmp &= ~ak->cs_mask; - tmp |= ak->cs_none; /* deselect address */ - } - snd_ice1712_gpio_write(ice, tmp); - udelay(1); - - if (ak->ops.stop) - ak->ops.stop(ak); - else - snd_ice1712_restore_gpio_status(ice); -} - -/* - * reset the AKM codecs - * @state: 1 = reset codec, 0 = restore the registers - * - * assert the reset operation and restores the register values to the chips. - */ -void snd_ice1712_akm4xxx_reset(akm4xxx_t *ak, int state) -{ - unsigned int chip; - unsigned char reg; - - switch (ak->type) { - case SND_AK4524: - case SND_AK4528: - for (chip = 0; chip < ak->num_dacs/2; chip++) { - snd_ice1712_akm4xxx_write(ak, chip, 0x01, state ? 0x00 : 0x03); - if (state) - continue; - /* DAC volumes */ - for (reg = 0x04; reg < (ak->type == SND_AK4528 ? 0x06 : 0x08); reg++) - snd_ice1712_akm4xxx_write(ak, chip, reg, ak->images[chip][reg]); - if (ak->type == SND_AK4528) - continue; - /* IPGA */ - for (reg = 0x04; reg < 0x06; reg++) - snd_ice1712_akm4xxx_write(ak, chip, reg, ak->ipga_gain[chip][reg-4]); - } - break; - case SND_AK4529: - /* FIXME: needed for ak4529? */ - break; - case SND_AK4355: - snd_ice1712_akm4xxx_write(ak, 0, 0x01, state ? 0x02 : 0x01); - if (state) - return; - for (reg = 0x00; reg < 0x0a; reg++) - if (reg != 0x01) - snd_ice1712_akm4xxx_write(ak, 0, reg, ak->images[0][reg]); - break; - case SND_AK4381: - for (chip = 0; chip < ak->num_dacs/2; chip++) { - snd_ice1712_akm4xxx_write(ak, chip, 0x00, state ? 0x0c : 0x0f); - if (state) - continue; - for (reg = 0x01; reg < 0x05; reg++) - snd_ice1712_akm4xxx_write(ak, chip, reg, ak->images[chip][reg]); - } - break; - } -} - -/* - * initialize all the ak4xxx chips - */ -static void __devinit snd_ice1712_akm4xxx_init_chip(akm4xxx_t *ak) -{ - static unsigned char inits_ak4524[] = { - 0x00, 0x07, /* 0: all power up */ - 0x01, 0x00, /* 1: ADC/DAC reset */ - 0x02, 0x60, /* 2: 24bit I2S */ - 0x03, 0x19, /* 3: deemphasis off */ - 0x01, 0x03, /* 1: ADC/DAC enable */ - 0x04, 0x00, /* 4: ADC left muted */ - 0x05, 0x00, /* 5: ADC right muted */ - 0x04, 0x80, /* 4: ADC IPGA gain 0dB */ - 0x05, 0x80, /* 5: ADC IPGA gain 0dB */ - 0x06, 0x00, /* 6: DAC left muted */ - 0x07, 0x00, /* 7: DAC right muted */ - 0xff, 0xff - }; - static unsigned char inits_ak4528[] = { - 0x00, 0x07, /* 0: all power up */ - 0x01, 0x00, /* 1: ADC/DAC reset */ - 0x02, 0x60, /* 2: 24bit I2S */ - 0x03, 0x0d, /* 3: deemphasis off, turn LR highpass filters on */ - 0x01, 0x03, /* 1: ADC/DAC enable */ - 0x04, 0x00, /* 4: ADC left muted */ - 0x05, 0x00, /* 5: ADC right muted */ - 0xff, 0xff - }; - static unsigned char inits_ak4529[] = { - 0x09, 0x01, /* 9: ATS=0, RSTN=1 */ - 0x0a, 0x3f, /* A: all power up, no zero/overflow detection */ - 0x00, 0x0c, /* 0: TDM=0, 24bit I2S, SMUTE=0 */ - 0x01, 0x00, /* 1: ACKS=0, ADC, loop off */ - 0x02, 0xff, /* 2: LOUT1 muted */ - 0x03, 0xff, /* 3: ROUT1 muted */ - 0x04, 0xff, /* 4: LOUT2 muted */ - 0x05, 0xff, /* 5: ROUT2 muted */ - 0x06, 0xff, /* 6: LOUT3 muted */ - 0x07, 0xff, /* 7: ROUT3 muted */ - 0x0b, 0xff, /* B: LOUT4 muted */ - 0x0c, 0xff, /* C: ROUT4 muted */ - 0x08, 0x55, /* 8: deemphasis all off */ - 0xff, 0xff - }; - static unsigned char inits_ak4355[] = { - 0x01, 0x02, /* 1: reset and soft-mute */ - 0x00, 0x06, /* 0: mode3(i2s), disable auto-clock detect, disable DZF, sharp roll-off, RSTN#=0 */ - // 0x02, 0x0e, /* 2: DA's power up, normal speed, RSTN#=0 */ - 0x02, 0x2e, - 0x03, 0x01, /* 3: de-emphasis off */ - 0x04, 0x00, /* 4: LOUT1 volume muted */ - 0x05, 0x00, /* 5: ROUT1 volume muted */ - 0x06, 0x00, /* 6: LOUT2 volume muted */ - 0x07, 0x00, /* 7: ROUT2 volume muted */ - 0x08, 0x00, /* 8: LOUT3 volume muted */ - 0x09, 0x00, /* 9: ROUT3 volume muted */ - 0x0a, 0x00, /* a: DATT speed=0, ignore DZF */ - 0x01, 0x01, /* 1: un-reset, unmute */ - 0xff, 0xff - }; - static unsigned char inits_ak4381[] = { - 0x00, 0x0c, /* 0: mode3(i2s), disable auto-clock detect */ - // 0x01, 0x02, /* 1: de-emphasis off, normal speed, sharp roll-off, DZF off */ - 0x01, 0x12, - 0x02, 0x00, /* 2: DZF disabled */ - 0x03, 0x00, /* 3: LATT 0 */ - 0x04, 0x00, /* 4: RATT 0 */ - 0x00, 0x0f, /* 0: power-up, un-reset */ - 0xff, 0xff - }; - - int chip, num_chips; - unsigned char *ptr, reg, data, *inits; - - switch (ak->type) { - case SND_AK4524: - inits = inits_ak4524; - num_chips = ak->num_dacs / 2; - break; - case SND_AK4528: - inits = inits_ak4528; - num_chips = ak->num_dacs / 2; - break; - case SND_AK4529: - inits = inits_ak4529; - num_chips = 1; - break; - case SND_AK4355: - inits = inits_ak4355; - num_chips = 1; - break; - case SND_AK4381: - inits = inits_ak4381; - num_chips = ak->num_dacs / 2; - break; - default: - snd_BUG(); - return; - } - - for (chip = 0; chip < num_chips; chip++) { - ptr = inits; - while (*ptr != 0xff) { - reg = *ptr++; - data = *ptr++; - snd_ice1712_akm4xxx_write(ak, chip, reg, data); - } - } -} - - -/* - * initialize the akm4xxx_t record with the template - */ -void snd_ice1712_akm4xxx_init(akm4xxx_t *ak, const akm4xxx_t *temp, ice1712_t *ice) -{ - *ak = *temp; - ak->chip = ice; - snd_ice1712_akm4xxx_init_chip(ak); -} - - -#define AK_GET_CHIP(val) (((val) >> 8) & 0xff) -#define AK_GET_ADDR(val) ((val) & 0xff) -#define AK_GET_SHIFT(val) (((val) >> 16) & 0x7f) -#define AK_GET_INVERT(val) (((val) >> 23) & 1) -#define AK_GET_MASK(val) (((val) >> 24) & 0xff) -#define AK_COMPOSE(chip,addr,shift,mask) (((chip) << 8) | (addr) | ((shift) << 16) | ((mask) << 24)) -#define AK_INVERT (1<<23) - -static int snd_ice1712_akm4xxx_volume_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) -{ - unsigned int mask = AK_GET_MASK(kcontrol->private_value); - - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = mask; - return 0; -} - -static int snd_ice1712_akm4xxx_volume_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - akm4xxx_t *ak = _snd_kcontrol_chip(kcontrol); - int chip = AK_GET_CHIP(kcontrol->private_value); - int addr = AK_GET_ADDR(kcontrol->private_value); - int invert = AK_GET_INVERT(kcontrol->private_value); - unsigned int mask = AK_GET_MASK(kcontrol->private_value); - unsigned char val = ak->images[chip][addr]; - - ucontrol->value.integer.value[0] = invert ? mask - val : val; - return 0; -} - -static int snd_ice1712_akm4xxx_volume_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - akm4xxx_t *ak = _snd_kcontrol_chip(kcontrol); - int chip = AK_GET_CHIP(kcontrol->private_value); - int addr = AK_GET_ADDR(kcontrol->private_value); - int invert = AK_GET_INVERT(kcontrol->private_value); - unsigned int mask = AK_GET_MASK(kcontrol->private_value); - unsigned char nval = ucontrol->value.integer.value[0] % (mask+1); - int change; - - if (invert) - nval = mask - nval; - change = ak->images[chip][addr] != nval; - if (change) - snd_ice1712_akm4xxx_write(ak, chip, addr, nval); - return change; -} - -static int snd_ice1712_akm4xxx_ipga_gain_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 36; - return 0; -} - -static int snd_ice1712_akm4xxx_ipga_gain_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - akm4xxx_t *ak = _snd_kcontrol_chip(kcontrol); - int chip = AK_GET_CHIP(kcontrol->private_value); - int addr = AK_GET_ADDR(kcontrol->private_value); - ucontrol->value.integer.value[0] = ak->ipga_gain[chip][addr-4] & 0x7f; - return 0; -} - -static int snd_ice1712_akm4xxx_ipga_gain_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - akm4xxx_t *ak = _snd_kcontrol_chip(kcontrol); - int chip = AK_GET_CHIP(kcontrol->private_value); - int addr = AK_GET_ADDR(kcontrol->private_value); - unsigned char nval = (ucontrol->value.integer.value[0] % 37) | 0x80; - int change = ak->ipga_gain[chip][addr] != nval; - if (change) - snd_ice1712_akm4xxx_write(ak, chip, addr, nval); - return change; -} - -static int snd_ice1712_akm4xxx_deemphasis_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) -{ - static char *texts[4] = { - "44.1kHz", "Off", "48kHz", "32kHz", - }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 4; - if (uinfo->value.enumerated.item >= 4) - uinfo->value.enumerated.item = 3; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; -} - -static int snd_ice1712_akm4xxx_deemphasis_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - akm4xxx_t *ak = _snd_kcontrol_chip(kcontrol); - int chip = AK_GET_CHIP(kcontrol->private_value); - int addr = AK_GET_ADDR(kcontrol->private_value); - int shift = AK_GET_SHIFT(kcontrol->private_value); - ucontrol->value.enumerated.item[0] = (ak->images[chip][addr] >> shift) & 3; - return 0; -} - -static int snd_ice1712_akm4xxx_deemphasis_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) -{ - akm4xxx_t *ak = _snd_kcontrol_chip(kcontrol); - int chip = AK_GET_CHIP(kcontrol->private_value); - int addr = AK_GET_ADDR(kcontrol->private_value); - int shift = AK_GET_SHIFT(kcontrol->private_value); - unsigned char nval = ucontrol->value.enumerated.item[0] & 3; - int change; - - nval = (nval << shift) | (ak->images[chip][addr] & ~(3 << shift)); - change = ak->images[chip][addr] != nval; - if (change) - snd_ice1712_akm4xxx_write(ak, chip, addr, nval); - return change; -} - -/* - * build AK4524 controls - */ - -int __devinit snd_ice1712_akm4xxx_build_controls(ice1712_t *ice) -{ - unsigned int idx; - int err; - unsigned int akidx; - - for (akidx = 0; akidx < ice->akm_codecs; akidx++) { - akm4xxx_t *ak = &ice->akm[akidx]; - for (idx = 0; idx < ak->num_dacs; ++idx) { - snd_kcontrol_t ctl; - memset(&ctl, 0, sizeof(ctl)); - strcpy(ctl.id.name, "DAC Volume"); - ctl.id.index = idx + ak->idx_offset * 2; - ctl.id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - ctl.count = 1; - ctl.info = snd_ice1712_akm4xxx_volume_info; - ctl.get = snd_ice1712_akm4xxx_volume_get; - ctl.put = snd_ice1712_akm4xxx_volume_put; - switch (ak->type) { - case SND_AK4524: - ctl.private_value = AK_COMPOSE(idx/2, (idx%2) + 6, 0, 127); /* register 6 & 7 */ - break; - case SND_AK4528: - ctl.private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127); /* register 4 & 5 */ - break; - case SND_AK4529: { - int val = idx < 6 ? idx + 2 : (idx - 6) + 0xb; /* registers 2-7 and b,c */ - ctl.private_value = AK_COMPOSE(0, val, 0, 255) | AK_INVERT; - break; - } - case SND_AK4355: - ctl.private_value = AK_COMPOSE(0, idx + 4, 0, 255); /* register 4-9, chip #0 only */ - break; - case SND_AK4381: - ctl.private_value = AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255); /* register 3 & 4 */ - break; - default: - return -EINVAL; - } - ctl.private_data = ak; - if ((err = snd_ctl_add(ice->card, snd_ctl_new(&ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0) - return err; - } - for (idx = 0; idx < ak->num_adcs && ak->type == SND_AK4524; ++idx) { - snd_kcontrol_t ctl; - memset(&ctl, 0, sizeof(ctl)); - strcpy(ctl.id.name, "ADC Volume"); - ctl.id.index = idx; - ctl.id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - ctl.count = 1; - ctl.info = snd_ice1712_akm4xxx_volume_info; - ctl.get = snd_ice1712_akm4xxx_volume_get; - ctl.put = snd_ice1712_akm4xxx_volume_put; - ctl.private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 127); /* register 4 & 5 */ - ctl.private_data = ak; - if ((err = snd_ctl_add(ice->card, snd_ctl_new(&ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0) - return err; - memset(&ctl, 0, sizeof(ctl)); - strcpy(ctl.id.name, "IPGA Analog Capture Volume"); - ctl.id.index = idx; - ctl.id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - ctl.count = 1; - ctl.info = snd_ice1712_akm4xxx_ipga_gain_info; - ctl.get = snd_ice1712_akm4xxx_ipga_gain_get; - ctl.put = snd_ice1712_akm4xxx_ipga_gain_put; - ctl.private_value = AK_COMPOSE(idx/2, (idx%2) + 4, 0, 0); /* register 4 & 5 */ - ctl.private_data = ak; - if ((err = snd_ctl_add(ice->card, snd_ctl_new(&ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0) - return err; - } - for (idx = 0; idx < ak->num_dacs/2; idx++) { - snd_kcontrol_t ctl; - memset(&ctl, 0, sizeof(ctl)); - strcpy(ctl.id.name, "Deemphasis"); - ctl.id.index = idx + ak->idx_offset; - ctl.id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - ctl.count = 1; - ctl.info = snd_ice1712_akm4xxx_deemphasis_info; - ctl.get = snd_ice1712_akm4xxx_deemphasis_get; - ctl.put = snd_ice1712_akm4xxx_deemphasis_put; - switch (ak->type) { - case SND_AK4524: - case SND_AK4528: - ctl.private_value = AK_COMPOSE(idx, 3, 0, 0); /* register 3 */ - break; - case SND_AK4529: { - int shift = idx == 3 ? 6 : (2 - idx) * 2; - ctl.private_value = AK_COMPOSE(0, 8, shift, 0); /* register 8 with shift */ - break; - } - case SND_AK4355: - ctl.private_value = AK_COMPOSE(idx, 3, 0, 0); - break; - case SND_AK4381: - ctl.private_value = AK_COMPOSE(idx, 1, 1, 0); - break; - } - ctl.private_data = ak; - if ((err = snd_ctl_add(ice->card, snd_ctl_new(&ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0) - return err; - } - } - return 0; -} diff -Nru a/sound/pci/ice1712/ak4xxx.c b/sound/pci/ice1712/ak4xxx.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/ice1712/ak4xxx.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,170 @@ +/* + * ALSA driver for ICEnsemble ICE1712 (Envy24) + * + * AK4524 / AK4528 / AK4529 / AK4355 / AK4381 interface + * + * Copyright (c) 2000 Jaroslav Kysela <perex@suse.cz> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the 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 <sound/driver.h> +#include <asm/io.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <sound/core.h> +#include "ice1712.h" + +static void snd_ice1712_akm4xxx_lock(akm4xxx_t *ak, int chip) +{ + ice1712_t *ice = ak->private_data[0]; + + snd_ice1712_save_gpio_status(ice); +} + +static void snd_ice1712_akm4xxx_unlock(akm4xxx_t *ak, int chip) +{ + ice1712_t *ice = ak->private_data[0]; + + snd_ice1712_restore_gpio_status(ice); +} + +/* + * write AK4xxx register + */ +static void snd_ice1712_akm4xxx_write(akm4xxx_t *ak, int chip, + unsigned char addr, unsigned char data) +{ + unsigned int tmp; + int idx; + unsigned int addrdata; + struct snd_ak4xxx_private *priv = (void *)ak->private_value[0]; + ice1712_t *ice = ak->private_data[0]; + + snd_assert(chip >= 0 && chip < 4, return); + + tmp = snd_ice1712_gpio_read(ice); + tmp |= priv->add_flags; + tmp &= ~priv->mask_flags; + if (priv->cs_mask == priv->cs_addr) { + if (priv->cif) { + tmp |= priv->cs_mask; /* start without chip select */ + } else { + tmp &= ~priv->cs_mask; /* chip select low */ + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + } + } else { + /* doesn't handle cf=1 yet */ + tmp &= ~priv->cs_mask; + tmp |= priv->cs_addr; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + } + + /* build I2C address + data byte */ + addrdata = (priv->caddr << 6) | 0x20 | (addr & 0x1f); + addrdata = (addrdata << 8) | data; + for (idx = 15; idx >= 0; idx--) { + /* drop clock */ + tmp &= ~priv->clk_mask; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + /* set data */ + if (addrdata & (1 << idx)) + tmp |= priv->data_mask; + else + tmp &= ~priv->data_mask; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + /* raise clock */ + tmp |= priv->clk_mask; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + } + + if (priv->cs_mask == priv->cs_addr) { + if (priv->cif) { + /* assert a cs pulse to trigger */ + tmp &= ~priv->cs_mask; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + } + tmp |= priv->cs_mask; /* chip select high to trigger */ + } else { + tmp &= ~priv->cs_mask; + tmp |= priv->cs_none; /* deselect address */ + } + snd_ice1712_gpio_write(ice, tmp); + udelay(1); +} + +/* + * initialize the akm4xxx_t record with the template + */ +int __devinit snd_ice1712_akm4xxx_init(akm4xxx_t *ak, const akm4xxx_t *temp, + const struct snd_ak4xxx_private *_priv, ice1712_t *ice) +{ + struct snd_ak4xxx_private *priv; + + priv = kmalloc(sizeof(*priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + *ak = *temp; + ak->card = ice->card; + *priv = *_priv; + ak->private_value[0] = (unsigned long)priv; + ak->private_data[0] = ice; + if (ak->ops.lock == NULL) + ak->ops.lock = snd_ice1712_akm4xxx_lock; + if (ak->ops.unlock == NULL) + ak->ops.unlock = snd_ice1712_akm4xxx_unlock; + if (ak->ops.write == NULL) + ak->ops.write = snd_ice1712_akm4xxx_write; + snd_akm4xxx_init(ak); + return 0; +} + +void __devexit snd_ice1712_akm4xxx_free(ice1712_t *ice) +{ + unsigned int akidx; + if (ice->akm == NULL) + return; + for (akidx = 0; akidx < ice->akm_codecs; akidx++) { + akm4xxx_t *ak = &ice->akm[akidx]; + if (ak->private_value[0]) + kfree((void *)ak->private_value[0]); + } + kfree(ice->akm); +} + +/* + * build AK4xxx controls + */ +int __devinit snd_ice1712_akm4xxx_build_controls(ice1712_t *ice) +{ + unsigned int akidx; + int err; + + for (akidx = 0; akidx < ice->akm_codecs; akidx++) { + akm4xxx_t *ak = &ice->akm[akidx]; + err = snd_akm4xxx_build_controls(ak); + if (err < 0) + return err; + } + return 0; +} diff -Nru a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/ice1712/aureon.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,507 @@ +/* + * ALSA driver for ICEnsemble VT1724 (Envy24HT) + * + * Lowlevel functions for Terratec Aureon cards + * + * Copyright (c) 2003 Takashi Iwai <tiwai@suse.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * + * NOTES: + * + * - we reuse the akm4xxx_t record for storing the wm8770 codec data. + * both wm and akm codecs are pretty similar, so we can integrate + * both controls in the future, once if wm codecs are reused in + * many boards. + * + * - writing over SPI is implemented but reading is not yet. + * the SPDIF-in channel status, etc. can be read from CS chip. + * + * - DAC digital volumes are not implemented in the mixer. + * if they show better response than DAC analog volumes, we can use them + * instead. + * + * - Aureon boards are equipped with AC97 codec, too. it's used to do + * the analog mixing but not easily controllable (it's not connected + * directly from envy24ht chip). so let's leave it as it is. + * + */ + +#include <sound/driver.h> +#include <asm/io.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <sound/core.h> + +#include "ice1712.h" +#include "envy24ht.h" +#include "aureon.h" + +/* WM8770 registers */ +#define WM_DAC_ATTEN 0x00 /* DAC1-8 analog attenuation */ +#define WM_DAC_MASTER_ATTEN 0x08 /* DAC master analog attenuation */ +#define WM_DAC_DIG_ATTEN 0x09 /* DAC1-8 digital attenuation */ +#define WM_DAC_DIG_MATER_ATTEN 0x11 /* DAC master digital attenuation */ +#define WM_PHASE_SWAP 0x12 /* DAC phase */ +#define WM_DAC_CTRL1 0x13 /* DAC control bits */ +#define WM_MUTE 0x14 /* mute controls */ +#define WM_DAC_CTRL2 0x15 /* de-emphasis and zefo-flag */ +#define WM_INT_CTRL 0x16 /* interface control */ +#define WM_MASTER 0x17 /* master clock and mode */ +#define WM_POWERDOWN 0x18 /* power-down controls */ +#define WM_ADC_GAIN 0x19 /* ADC gain L(19)/R(1a) */ +#define WM_ADC_MUX 0x1b /* input MUX */ +#define WM_OUT_MUX1 0x1c /* output MUX */ +#define WM_OUT_MUX2 0x1e /* output MUX */ +#define WM_RESET 0x1f /* software reset */ + + +/* + * write data in the SPI mode + */ +static void aureon_spi_write(ice1712_t *ice, unsigned int cs, unsigned int data, int bits) +{ + unsigned int tmp; + int i; + + tmp = snd_ice1712_gpio_read(ice); + + snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RW|AUREON_WM_DATA|AUREON_WM_CLK| + AUREON_WM_CS|AUREON_CS8415_CS)); + tmp |= AUREON_WM_RW; + tmp &= ~cs; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + + for (i = bits - 1; i >= 0; i--) { + tmp &= ~AUREON_WM_CLK; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + if (data & (1 << i)) + tmp |= AUREON_WM_DATA; + else + tmp &= ~AUREON_WM_DATA; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + tmp |= AUREON_WM_CLK; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + } + + tmp &= ~AUREON_WM_CLK; + tmp |= cs; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + tmp |= AUREON_WM_CLK; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); +} + + +/* + * get the current register value of WM codec + */ +static unsigned short wm_get(ice1712_t *ice, int reg) +{ + reg <<= 1; + return ((unsigned short)ice->akm[0].images[reg] << 8) | + ice->akm[0].images[reg + 1]; +} + +/* + * set the register value of WM codec and remember it + */ +static void wm_put(ice1712_t *ice, int reg, unsigned short val) +{ + aureon_spi_write(ice, AUREON_WM_CS, (reg << 9) | (val & 0x1ff), 16); + reg <<= 1; + ice->akm[0].images[reg] = val >> 8; + ice->akm[0].images[reg + 1] = val; +} + +/* + * DAC volume attenuation mixer control + */ +static int wm_dac_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; /* mute */ + uinfo->value.integer.max = 101; /* 0dB */ + return 0; +} + +static int wm_dac_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + int idx; + unsigned short vol; + + down(&ice->gpio_mutex); + if (kcontrol->private_value) + idx = WM_DAC_MASTER_ATTEN; + else + idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_DAC_ATTEN; + vol = wm_get(ice, idx) & 0x7f; + if (vol <= 0x1a) + ucontrol->value.integer.value[0] = 0; + else + ucontrol->value.integer.value[0] = vol - 0x1a; + up(&ice->gpio_mutex); + return 0; +} + +static int wm_dac_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + int idx; + unsigned short ovol, nvol; + int change; + + snd_ice1712_save_gpio_status(ice); + if (kcontrol->private_value) + idx = WM_DAC_MASTER_ATTEN; + else + idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_DAC_ATTEN; + nvol = ucontrol->value.integer.value[0] + 0x1a; + ovol = wm_get(ice, idx) & 0x7f; + change = (ovol != nvol); + if (change) { + if (nvol <= 0x1a && ovol <= 0x1a) + change = 0; + else + wm_put(ice, idx, nvol | 0x100); + } + snd_ice1712_restore_gpio_status(ice); + return change; +} + +/* + * ADC gain mixer control + */ +static int wm_adc_vol_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; /* -12dB */ + uinfo->value.integer.max = 0x1f; /* 19dB */ + return 0; +} + +static int wm_adc_vol_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + int idx; + unsigned short vol; + + down(&ice->gpio_mutex); + idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_ADC_GAIN; + vol = wm_get(ice, idx) & 0x1f; + ucontrol->value.integer.value[0] = vol; + up(&ice->gpio_mutex); + return 0; +} + +static int wm_adc_vol_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + int idx; + unsigned short ovol, nvol; + int change; + + snd_ice1712_save_gpio_status(ice); + idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + WM_ADC_GAIN; + nvol = ucontrol->value.integer.value[0]; + ovol = wm_get(ice, idx) & 0x1f; + change = (ovol != nvol); + if (change) + wm_put(ice, idx, nvol); + snd_ice1712_restore_gpio_status(ice); + return change; +} + +/* + * ADC input mux mixer control + */ +static int wm_adc_mux_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + static char *texts[] = { + "CD Left", + "CD Right", + "Aux Left", + "Aux Right", + "Line Left", + "Line Right", + "Mic Left", + "Mic Right", + }; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 2; + uinfo->value.enumerated.items = 8; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); + return 0; +} + +static int wm_adc_mux_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + unsigned short val; + + down(&ice->gpio_mutex); + val = wm_get(ice, WM_ADC_MUX); + ucontrol->value.integer.value[0] = val & 7; + ucontrol->value.integer.value[1] = (val >> 4) & 7; + up(&ice->gpio_mutex); + return 0; +} + +static int wm_adc_mux_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + ice1712_t *ice = snd_kcontrol_chip(kcontrol); + unsigned short oval, nval; + int change; + + snd_ice1712_save_gpio_status(ice); + oval = wm_get(ice, WM_ADC_MUX); + nval = oval & ~0x77; + nval |= ucontrol->value.integer.value[0] & 7; + nval |= (ucontrol->value.integer.value[1] & 7) << 4; + change = (oval != nval); + if (change) + wm_put(ice, WM_ADC_MUX, nval); + snd_ice1712_restore_gpio_status(ice); + return 0; +} + +/* + * mixers + */ + +static snd_kcontrol_new_t aureon51_dac_control __devinitdata = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "DAC Volume", + .count = 6, + .info = wm_dac_vol_info, + .get = wm_dac_vol_get, + .put = wm_dac_vol_put, +}; + +static snd_kcontrol_new_t aureon71_dac_control __devinitdata = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "DAC Volume", + .count = 8, + .info = wm_dac_vol_info, + .get = wm_dac_vol_get, + .put = wm_dac_vol_put, +}; + +static snd_kcontrol_new_t wm_controls[] __devinitdata = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Volume", + .info = wm_dac_vol_info, + .get = wm_dac_vol_get, + .put = wm_dac_vol_put, + .private_value = 1, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "ADC Volume", + .count = 2, + .info = wm_adc_vol_info, + .get = wm_adc_vol_get, + .put = wm_adc_vol_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Route", + .info = wm_adc_mux_info, + .get = wm_adc_mux_get, + .put = wm_adc_mux_put, + }, +}; + + +static int __devinit aureon_add_controls(ice1712_t *ice) +{ + unsigned int i; + int err; + + if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) + err = snd_ctl_add(ice->card, snd_ctl_new1(&aureon51_dac_control, ice)); + else + err = snd_ctl_add(ice->card, snd_ctl_new1(&aureon71_dac_control, ice)); + if (err < 0) + return err; + + for (i = 0; i < ARRAY_SIZE(wm_controls); i++) { + err = snd_ctl_add(ice->card, snd_ctl_new1(&wm_controls[i], ice)); + if (err < 0) + return err; + } + return 0; +} + + +/* + * initialize the chip + */ +static int __devinit aureon_init(ice1712_t *ice) +{ + static unsigned short wm_inits[] = { + 0x16, 0x122, /* I2S, normal polarity, 24bit */ + 0x17, 0x022, /* 256fs, slave mode */ + 0x18, 0x000, /* All power-up */ + 0x00, 0, /* DAC1 analog mute */ + 0x01, 0, /* DAC2 analog mute */ + 0x02, 0, /* DAC3 analog mute */ + 0x03, 0, /* DAC4 analog mute */ + 0x04, 0, /* DAC5 analog mute */ + 0x05, 0, /* DAC6 analog mute */ + 0x06, 0, /* DAC7 analog mute */ + 0x07, 0, /* DAC8 analog mute */ + 0x08, 0x100, /* master analog mute */ + 0x09, 0xff, /* DAC1 digital full */ + 0x0a, 0xff, /* DAC2 digital full */ + 0x0b, 0xff, /* DAC3 digital full */ + 0x0c, 0xff, /* DAC4 digital full */ + 0x0d, 0xff, /* DAC5 digital full */ + 0x0e, 0xff, /* DAC6 digital full */ + 0x0f, 0xff, /* DAC7 digital full */ + 0x10, 0xff, /* DAC8 digital full */ + 0x11, 0x1ff, /* master digital full */ + 0x12, 0x000, /* phase normal */ + 0x13, 0x090, /* unmute DAC L/R */ + 0x14, 0x000, /* all unmute */ + 0x15, 0x000, /* no deemphasis, no ZFLG */ + 0x19, 0x000, /* -12dB ADC/L */ + 0x1a, 0x000, /* -12dB ADC/R */ + 0x1b, 0x000, /* ADC Mux */ + 0x1c, 0x009, /* Out Mux1 */ + 0x1d, 0x009, /* Out Mux2 */ + }; + static unsigned short cs_inits[] = { + 0x0441, /* RUN */ + 0x0100, /* no mute */ + 0x0200, /* */ + 0x0600, /* slave, 24bit */ + }; + unsigned int tmp; + unsigned int i; + + if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON51_SKY) + ice->num_total_dacs = 6; + else + ice->num_total_dacs = 8; + + /* to remeber the register values */ + ice->akm = snd_kcalloc(sizeof(akm4xxx_t), GFP_KERNEL); + if (! ice->akm) + return -ENOMEM; + ice->akm_codecs = 1; + + snd_ice1712_gpio_set_dir(ice, 0xbfffff); /* fix this for the time being */ + + /* reset the wm codec as the SPI mode */ + snd_ice1712_save_gpio_status(ice); + snd_ice1712_gpio_set_mask(ice, ~(AUREON_WM_RESET|AUREON_WM_CS|AUREON_CS8415_CS)); + tmp = snd_ice1712_gpio_read(ice); + tmp &= ~AUREON_WM_RESET; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + tmp |= AUREON_WM_CS | AUREON_CS8415_CS; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + tmp |= AUREON_WM_RESET; + snd_ice1712_gpio_write(ice, tmp); + udelay(1); + + /* initialize WM8770 codec */ + for (i = 0; i < ARRAY_SIZE(wm_inits); i += 2) + wm_put(ice, wm_inits[i], wm_inits[i+1]); + + /* initialize CS8415A codec */ + for (i = 0; i < ARRAY_SIZE(cs_inits); i++) + aureon_spi_write(ice, AUREON_CS8415_CS, + cs_inits[i] | 0x200000, 24); + + snd_ice1712_restore_gpio_status(ice); + + return 0; +} + + +/* + * Aureon board don't provide the EEPROM data except for the vendor IDs. + * hence the driver needs to sets up it properly. + */ + +static unsigned char aureon51_eeprom[] __devinitdata = { + 0x12, /* SYSCONF: clock 512, mpu401, spdif-in/ADC, 3DACs */ + 0x80, /* ACLINK: I2S */ + 0xf8, /* I2S: vol, 96k, 24bit, 192k */ + 0xc2, /* SPDIF: out-en, out-int, spdif-in */ + 0xff, /* GPIO_DIR */ + 0xff, /* GPIO_DIR1 */ + 0xbf, /* GPIO_DIR2 */ + 0xff, /* GPIO_MASK */ + 0xff, /* GPIO_MASK1 */ + 0xff, /* GPIO_MASK2 */ + 0x00, /* GPIO_STATE */ + 0x00, /* GPIO_STATE1 */ + 0x00, /* GPIO_STATE2 */ +}; + +static unsigned char aureon71_eeprom[] __devinitdata = { + 0x13, /* SYSCONF: clock 512, mpu401, spdif-in/ADC, 4DACs */ + 0x80, /* ACLINK: I2S */ + 0xf8, /* I2S: vol, 96k, 24bit, 192k */ + 0xc2, /* SPDIF: out-en, out-int, spdif-in */ + 0xff, /* GPIO_DIR */ + 0xff, /* GPIO_DIR1 */ + 0xbf, /* GPIO_DIR2 */ + 0x00, /* GPIO_MASK */ + 0x00, /* GPIO_MASK1 */ + 0x00, /* GPIO_MASK2 */ + 0x00, /* GPIO_STATE */ + 0x00, /* GPIO_STATE1 */ + 0x00, /* GPIO_STATE2 */ +}; + +/* entry point */ +struct snd_ice1712_card_info snd_vt1724_aureon_cards[] __devinitdata = { + { + .subvendor = VT1724_SUBDEVICE_AUREON51_SKY, + .name = "Terratec Aureon 5.1-Sky", + .chip_init = aureon_init, + .build_controls = aureon_add_controls, + .eeprom_size = sizeof(aureon51_eeprom), + .eeprom_data = aureon51_eeprom, + }, + { + .subvendor = VT1724_SUBDEVICE_AUREON71_SPACE, + .name = "Terratec Aureon 7.1-Space", + .chip_init = aureon_init, + .build_controls = aureon_add_controls, + .eeprom_size = sizeof(aureon71_eeprom), + .eeprom_data = aureon71_eeprom, + }, + { } /* terminator */ +}; diff -Nru a/sound/pci/ice1712/aureon.h b/sound/pci/ice1712/aureon.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/ice1712/aureon.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,47 @@ +#ifndef __SOUND_AUREON_H +#define __SOUND_AUREON_H + +/* + * ALSA driver for VIA VT1724 (Envy24HT) + * + * Lowlevel functions for Terratec Aureon cards + * + * Copyright (c) 2003 Takashi Iwai <tiwai@suse.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#define AUREON_DEVICE_DESC "{Terratec,Aureon 5.1 Sky},"\ + "{Terratec,Aureon 7.1 Space}," + +#define VT1724_SUBDEVICE_AUREON51_SKY 0x3b154711 /* Aureon 5.1 Sky */ +#define VT1724_SUBDEVICE_AUREON71_SPACE 0x3b154511 /* Aureon 7.1 Space */ + +extern struct snd_ice1712_card_info snd_vt1724_aureon_cards[]; + +/* GPIO bits */ +#define AUREON_CS8415_CS (1 << 23) +#define AUREON_CS8415_CDTO (1 << 22) +#define AUREON_WM_RESET (1 << 20) +#define AUREON_WM_CLK (1 << 19) +#define AUREON_WM_DATA (1 << 18) +#define AUREON_WM_RW (1 << 17) +#define AUREON_AC97_RESET (1 << 16) +#define AUREON_DIGITAL_SEL1 (1 << 15) +#define AUREON_HP_SEL (1 << 14) +#define AUREON_WM_CS (1 << 12) + +#endif /* __SOUND_AUREON_H */ diff -Nru a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c --- a/sound/pci/ice1712/delta.c Mon Jun 9 23:16:07 2003 +++ b/sound/pci/ice1712/delta.c Mon Jun 9 23:16:07 2003 @@ -232,24 +232,28 @@ /* * AK4524 on Delta 44 and 66 to choose the chip mask */ -static int delta_ak4524_start(akm4xxx_t *ak, int chip) +static void delta_ak4524_lock(akm4xxx_t *ak, int chip) { - snd_ice1712_save_gpio_status(ak->chip); - ak->cs_mask = - ak->cs_addr = chip == 0 ? ICE1712_DELTA_CODEC_CHIP_A : - ICE1712_DELTA_CODEC_CHIP_B; - return 0; + struct snd_ak4xxx_private *priv = (void *)ak->private_value[0]; + ice1712_t *ice = ak->private_data[0]; + + snd_ice1712_save_gpio_status(ice); + priv->cs_mask = + priv->cs_addr = chip == 0 ? ICE1712_DELTA_CODEC_CHIP_A : + ICE1712_DELTA_CODEC_CHIP_B; } /* * AK4524 on Delta1010LT to choose the chip address */ -static int delta1010lt_ak4524_start(akm4xxx_t *ak, int chip) +static void delta1010lt_ak4524_lock(akm4xxx_t *ak, int chip) { - snd_ice1712_save_gpio_status(ak->chip); - ak->cs_mask = ICE1712_DELTA_1010LT_CS; - ak->cs_addr = chip << 4; - return 0; + struct snd_ak4xxx_private *priv = (void *)ak->private_value[0]; + ice1712_t *ice = ak->private_data[0]; + + snd_ice1712_save_gpio_status(ice); + priv->cs_mask = ICE1712_DELTA_1010LT_CS; + priv->cs_addr = chip << 4; } /* @@ -258,7 +262,7 @@ static void delta_ak4524_set_rate_val(akm4xxx_t *ak, unsigned int rate) { unsigned char tmp, tmp2; - ice1712_t *ice = ak->chip; + ice1712_t *ice = ak->private_data[0]; if (rate == 0) /* no hint - S/PDIF input is master, simply return */ return; @@ -275,14 +279,14 @@ return; /* do it again */ - snd_ice1712_akm4xxx_reset(ak, 1); + snd_akm4xxx_reset(ak, 1); down(&ice->gpio_mutex); tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA) & ~ICE1712_DELTA_DFS; if (rate > 48000) tmp |= ICE1712_DELTA_DFS; snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, tmp); up(&ice->gpio_mutex); - snd_ice1712_akm4xxx_reset(ak, 0); + snd_akm4xxx_reset(ak, 0); } @@ -330,6 +334,12 @@ .type = SND_AK4528, .num_adcs = 2, .num_dacs = 2, + .ops = { + .set_rate_val = delta_ak4524_set_rate_val + } +}; + +static struct snd_ak4xxx_private akm_audiophile_priv __devinitdata = { .caddr = 2, .cif = 0, .data_mask = ICE1712_DELTA_AP_DOUT, @@ -339,15 +349,18 @@ .cs_none = 0, .add_flags = ICE1712_DELTA_AP_CS_DIGITAL, .mask_flags = 0, - .ops = { - .set_rate_val = delta_ak4524_set_rate_val - } }; static akm4xxx_t akm_delta410 __devinitdata = { .type = SND_AK4529, .num_adcs = 2, .num_dacs = 8, + .ops = { + .set_rate_val = delta_ak4524_set_rate_val + } +}; + +static struct snd_ak4xxx_private akm_delta410_priv __devinitdata = { .caddr = 0, .cif = 0, .data_mask = ICE1712_DELTA_AP_DOUT, @@ -357,15 +370,19 @@ .cs_none = 0, .add_flags = ICE1712_DELTA_AP_CS_DIGITAL, .mask_flags = 0, - .ops = { - .set_rate_val = delta_ak4524_set_rate_val - } }; static akm4xxx_t akm_delta1010lt __devinitdata = { .type = SND_AK4524, .num_adcs = 8, .num_dacs = 8, + .ops = { + .lock = delta1010lt_ak4524_lock, + .set_rate_val = delta_ak4524_set_rate_val + } +}; + +static struct snd_ak4xxx_private akm_delta1010lt_priv __devinitdata = { .caddr = 2, .cif = 0, /* the default level of the CIF pin from AK4524 */ .data_mask = ICE1712_DELTA_1010LT_DOUT, @@ -375,16 +392,19 @@ .cs_none = ICE1712_DELTA_1010LT_CS_NONE, .add_flags = 0, .mask_flags = 0, - .ops = { - .start = delta1010lt_ak4524_start, - .set_rate_val = delta_ak4524_set_rate_val - } }; static akm4xxx_t akm_delta44 __devinitdata = { .type = SND_AK4524, .num_adcs = 4, .num_dacs = 4, + .ops = { + .lock = delta_ak4524_lock, + .set_rate_val = delta_ak4524_set_rate_val + } +}; + +static struct snd_ak4xxx_private akm_delta44_priv __devinitdata = { .caddr = 2, .cif = 0, /* the default level of the CIF pin from AK4524 */ .data_mask = ICE1712_DELTA_CODEC_SERIAL_DATA, @@ -394,10 +414,6 @@ .cs_none = 0, .add_flags = 0, .mask_flags = 0, - .ops = { - .start = delta_ak4524_start, - .set_rate_val = delta_ak4524_set_rate_val - } }; static int __devinit snd_ice1712_delta_init(ice1712_t *ice) @@ -466,24 +482,24 @@ switch (ice->eeprom.subvendor) { case ICE1712_SUBDEVICE_AUDIOPHILE: - snd_ice1712_akm4xxx_init(ak, &akm_audiophile, ice); + err = snd_ice1712_akm4xxx_init(ak, &akm_audiophile, &akm_audiophile_priv, ice); break; case ICE1712_SUBDEVICE_DELTA410: - snd_ice1712_akm4xxx_init(ak, &akm_delta410, ice); + err = snd_ice1712_akm4xxx_init(ak, &akm_delta410, &akm_delta410_priv, ice); break; case ICE1712_SUBDEVICE_DELTA1010LT: - snd_ice1712_akm4xxx_init(ak, &akm_delta1010lt, ice); + err = snd_ice1712_akm4xxx_init(ak, &akm_delta1010lt, &akm_delta1010lt_priv, ice); break; case ICE1712_SUBDEVICE_DELTA66: case ICE1712_SUBDEVICE_DELTA44: - snd_ice1712_akm4xxx_init(ak, &akm_delta44, ice); + err = snd_ice1712_akm4xxx_init(ak, &akm_delta44, &akm_delta44_priv, ice); break; default: snd_BUG(); return -EINVAL; } - return 0; + return err; } @@ -534,9 +550,6 @@ case ICE1712_SUBDEVICE_DELTA1010: case ICE1712_SUBDEVICE_DELTADIO2496: case ICE1712_SUBDEVICE_DELTA66: - case ICE1712_SUBDEVICE_AUDIOPHILE: - case ICE1712_SUBDEVICE_DELTA410: - case ICE1712_SUBDEVICE_DELTA1010LT: err = snd_ice1712_spdif_build_controls(ice); if (err < 0) return err; diff -Nru a/sound/pci/ice1712/envy24ht.h b/sound/pci/ice1712/envy24ht.h --- a/sound/pci/ice1712/envy24ht.h Mon Jun 9 23:16:20 2003 +++ b/sound/pci/ice1712/envy24ht.h Mon Jun 9 23:16:20 2003 @@ -150,8 +150,7 @@ #define VT1724_AC97_WRITE 0x20 /* W: write, R: write in progress */ #define VT1724_AC97_READ 0x10 /* W: read, R: read in progress */ #define VT1724_AC97_READY 0x08 /* codec ready status bit */ -#define VT1724_AC97_PBK_VSR 0x02 /* playback VSR */ -#define VT1724_AC97_CAP_VSR 0x01 /* capture VSR */ +#define VT1724_AC97_ID_MASK 0x03 /* codec id mask */ #define VT1724_MT_AC97_DATA 0x06 /* word - AC'97 data */ #define VT1724_MT_PLAYBACK_ADDR 0x10 /* dword - playback address */ #define VT1724_MT_PLAYBACK_SIZE 0x14 /* dword - playback size */ diff -Nru a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c --- a/sound/pci/ice1712/ews.c Mon Jun 9 23:16:08 2003 +++ b/sound/pci/ice1712/ews.c Mon Jun 9 23:16:08 2003 @@ -155,13 +155,13 @@ } /* start callback for EWS88MT, needs to select a certain chip mask */ -static int ews88mt_ak4524_start(akm4xxx_t *ak, int chip) +static void ews88mt_ak4524_lock(akm4xxx_t *ak, int chip) { - ice1712_t *ice = ak->chip; + ice1712_t *ice = ak->private_data[0]; unsigned char tmp; /* assert AK4524 CS */ if (snd_ice1712_ews88mt_chip_select(ice, ~(1 << chip) & 0x0f) < 0) - return -EINVAL; + snd_printk(KERN_ERR "fatal error (ews88mt chip select)\n"); snd_ice1712_save_gpio_status(ice); tmp = ICE1712_EWS88_SERIAL_DATA | ICE1712_EWS88_SERIAL_CLOCK | @@ -169,22 +169,21 @@ snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION, ice->gpio.direction | tmp); snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~tmp); - return 0; } /* stop callback for EWS88MT, needs to deselect chip mask */ -static void ews88mt_ak4524_stop(akm4xxx_t *ak) +static void ews88mt_ak4524_unlock(akm4xxx_t *ak, int chip) { - ice1712_t *ice = ak->chip; + ice1712_t *ice = ak->private_data[0]; snd_ice1712_restore_gpio_status(ice); udelay(1); snd_ice1712_ews88mt_chip_select(ice, 0x0f); } /* start callback for EWX24/96 */ -static int ewx2496_ak4524_start(akm4xxx_t *ak, int chip) +static void ewx2496_ak4524_lock(akm4xxx_t *ak, int chip) { - ice1712_t *ice = ak->chip; + ice1712_t *ice = ak->private_data[0]; unsigned char tmp; snd_ice1712_save_gpio_status(ice); tmp = ICE1712_EWX2496_SERIAL_DATA | @@ -194,26 +193,24 @@ snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION, ice->gpio.direction | tmp); snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~tmp); - return 0; } /* start callback for DMX 6fire */ -static int dmx6fire_ak4524_start(akm4xxx_t *ak, int chip) +static void dmx6fire_ak4524_lock(akm4xxx_t *ak, int chip) { - ice1712_t *ice = ak->chip; + struct snd_ak4xxx_private *priv = (void *)ak->private_value[0]; + ice1712_t *ice = ak->private_data[0]; unsigned char tmp; snd_ice1712_save_gpio_status(ice); - tmp = ak->cs_mask = ak->cs_addr = (1 << chip) & ICE1712_6FIRE_AK4524_CS_MASK; + tmp = priv->cs_mask = priv->cs_addr = (1 << chip) & ICE1712_6FIRE_AK4524_CS_MASK; tmp |= ICE1712_6FIRE_SERIAL_DATA | ICE1712_6FIRE_SERIAL_CLOCK | ICE1712_6FIRE_RW; snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION, ice->gpio.direction | tmp); snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~tmp); - return 0; } - /* * CS8404 interface on EWS88MT/D */ @@ -328,6 +325,13 @@ .num_adcs = 8, .num_dacs = 8, .type = SND_AK4524, + .ops = { + .lock = ews88mt_ak4524_lock, + .unlock = ews88mt_ak4524_unlock + } +}; + +static struct snd_ak4xxx_private akm_ews88mt_priv __devinitdata = { .caddr = 2, .cif = 1, /* CIF high */ .data_mask = ICE1712_EWS88_SERIAL_DATA, @@ -337,16 +341,18 @@ .cs_none = 0, /* no chip select on gpio */ .add_flags = ICE1712_EWS88_RW, /* set rw bit high */ .mask_flags = 0, - .ops = { - .start = ews88mt_ak4524_start, - .stop = ews88mt_ak4524_stop - } }; static akm4xxx_t akm_ewx2496 __devinitdata = { .num_adcs = 2, .num_dacs = 2, .type = SND_AK4524, + .ops = { + .lock = ewx2496_ak4524_lock + } +}; + +static struct snd_ak4xxx_private akm_ewx2496_priv __devinitdata = { .caddr = 2, .cif = 1, /* CIF high */ .data_mask = ICE1712_EWS88_SERIAL_DATA, @@ -356,15 +362,18 @@ .cs_none = 0, .add_flags = ICE1712_EWS88_RW, /* set rw bit high */ .mask_flags = 0, - .ops = { - .start = ewx2496_ak4524_start - } }; static akm4xxx_t akm_6fire __devinitdata = { .num_adcs = 6, .num_dacs = 6, .type = SND_AK4524, + .ops = { + .lock = dmx6fire_ak4524_lock + } +}; + +static struct snd_ak4xxx_private akm_6fire_priv __devinitdata = { .caddr = 2, .cif = 1, /* CIF high */ .data_mask = ICE1712_6FIRE_SERIAL_DATA, @@ -374,12 +383,8 @@ .cs_none = 0, .add_flags = ICE1712_6FIRE_RW, /* set rw bit high */ .mask_flags = 0, - .ops = { - .start = dmx6fire_ak4524_start - } }; - /* * initialize the chip */ @@ -479,17 +484,19 @@ switch (ice->eeprom.subvendor) { case ICE1712_SUBDEVICE_EWS88MT: case ICE1712_SUBDEVICE_EWS88MT_NEW: - snd_ice1712_akm4xxx_init(ak, &akm_ews88mt, ice); + err = snd_ice1712_akm4xxx_init(ak, &akm_ews88mt, &akm_ews88mt_priv, ice); break; case ICE1712_SUBDEVICE_EWX2496: - snd_ice1712_akm4xxx_init(ak, &akm_ewx2496, ice); + err = snd_ice1712_akm4xxx_init(ak, &akm_ewx2496, &akm_ewx2496_priv, ice); break; case ICE1712_SUBDEVICE_DMX6FIRE: - snd_ice1712_akm4xxx_init(ak, &akm_6fire, ice); + err = snd_ice1712_akm4xxx_init(ak, &akm_6fire, &akm_6fire_priv, ice); break; + default: + err = 0; } - return 0; + return err; } /* @@ -602,7 +609,7 @@ static int snd_ice1712_ews88mt_input_sense_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { ice1712_t *ice = snd_kcontrol_chip(kcontrol); - int channel = kcontrol->id.index; + int channel = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); unsigned char data; snd_assert(channel >= 0 && channel <= 7, return 0); @@ -621,7 +628,7 @@ static int snd_ice1712_ews88mt_input_sense_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) { ice1712_t *ice = snd_kcontrol_chip(kcontrol); - int channel = kcontrol->id.index; + int channel = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); unsigned char data, ndata; snd_assert(channel >= 0 && channel <= 7, return 0); @@ -645,6 +652,7 @@ .info = snd_ice1712_ewx_io_sense_info, .get = snd_ice1712_ews88mt_input_sense_get, .put = snd_ice1712_ews88mt_input_sense_put, + .count = 8, }; static snd_kcontrol_new_t snd_ice1712_ews88mt_output_sense __devinitdata = { @@ -894,12 +902,13 @@ { unsigned int idx; int err; - snd_kcontrol_t *kctl; - /* all terratec cards have spdif */ - err = snd_ice1712_spdif_build_controls(ice); - if (err < 0) - return err; + /* all terratec cards have spdif, but cs8427 module builds it's own controls */ + if (ice->cs8427 == NULL) { + err = snd_ice1712_spdif_build_controls(ice); + if (err < 0) + return err; + } /* ak4524 controls */ switch (ice->eeprom.subvendor) { @@ -924,13 +933,9 @@ break; case ICE1712_SUBDEVICE_EWS88MT: case ICE1712_SUBDEVICE_EWS88MT_NEW: - for (idx = 0; idx < 8; idx++) { - kctl = snd_ctl_new1(&snd_ice1712_ews88mt_input_sense, ice); - kctl->id.index = idx; - err = snd_ctl_add(ice->card, kctl); - if (err < 0) - return err; - } + err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_ews88mt_input_sense, ice)); + if (err < 0) + return err; err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_ews88mt_output_sense, ice)); if (err < 0) return err; diff -Nru a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c --- a/sound/pci/ice1712/ice1712.c Mon Jun 9 23:16:09 2003 +++ b/sound/pci/ice1712/ice1712.c Mon Jun 9 23:16:09 2003 @@ -298,11 +298,13 @@ static void snd_ice1712_set_gpio_dir(ice1712_t *ice, unsigned int data) { snd_ice1712_write(ice, ICE1712_IREG_GPIO_DIRECTION, data); + inb(ICEREG(ice, DATA)); /* dummy read for pci-posting */ } static void snd_ice1712_set_gpio_mask(ice1712_t *ice, unsigned int data) { snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, data); + inb(ICEREG(ice, DATA)); /* dummy read for pci-posting */ } static unsigned int snd_ice1712_get_gpio_data(ice1712_t *ice) @@ -313,6 +315,7 @@ static void snd_ice1712_set_gpio_data(ice1712_t *ice, unsigned int val) { snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, val); + inb(ICEREG(ice, DATA)); /* dummy read for pci-posting */ } @@ -660,6 +663,8 @@ if (!(snd_ice1712_read(ice, ICE1712_IREG_PBK_CTRL) & 1)) return 0; ptr = runtime->buffer_size - inw(ice->ddma_port + 4); + if (ptr == runtime->buffer_size) + ptr = 0; return bytes_to_frames(substream->runtime, ptr); } @@ -677,6 +682,8 @@ addr = ICE1712_DSC_ADDR0; ptr = snd_ice1712_ds_read(ice, substream->number * 2, addr) - ice->playback_con_virt_addr[substream->number]; + if (ptr == substream->runtime->buffer_size) + ptr = 0; return bytes_to_frames(substream->runtime, ptr); } @@ -688,6 +695,8 @@ if (!(snd_ice1712_read(ice, ICE1712_IREG_CAP_CTRL) & 1)) return 0; ptr = inl(ICEREG(ice, CONCAP_ADDR)) - ice->capture_con_virt_addr; + if (ptr == substream->runtime->buffer_size) + ptr = 0; return bytes_to_frames(substream->runtime, ptr); } @@ -965,9 +974,11 @@ { unsigned int what = 0; unsigned int old; - snd_pcm_substream_t *s = substream; + struct list_head *pos; + snd_pcm_substream_t *s; - do { + snd_pcm_group_for_each(pos, substream) { + s = snd_pcm_group_substream_entry(pos); if (s == ice->playback_pro_substream) { what |= ICE1712_PLAYBACK_START; snd_pcm_trigger_done(s, substream); @@ -975,8 +986,7 @@ what |= ICE1712_CAPTURE_START_SHADOW; snd_pcm_trigger_done(s, substream); } - s = s->link_next; - } while (s != substream); + } spin_lock(&ice->reg_lock); old = inl(ICEMT(ice, PLAYBACK_CONTROL)); if (cmd == SNDRV_PCM_TRIGGER_START) @@ -1097,6 +1107,8 @@ if (!(inl(ICEMT(ice, PLAYBACK_CONTROL)) & ICE1712_PLAYBACK_START)) return 0; ptr = ice->playback_pro_size - (inw(ICEMT(ice, PLAYBACK_SIZE)) << 2); + if (ptr == substream->runtime->buffer_size) + ptr = 0; return bytes_to_frames(substream->runtime, ptr); } @@ -1108,6 +1120,8 @@ if (!(inl(ICEMT(ice, PLAYBACK_CONTROL)) & ICE1712_CAPTURE_START_SHADOW)) return 0; ptr = ice->capture_pro_size - (inw(ICEMT(ice, CAPTURE_SIZE)) << 2); + if (ptr == substream->runtime->buffer_size) + ptr = 0; return bytes_to_frames(substream->runtime, ptr); } @@ -1299,7 +1313,7 @@ static int snd_ice1712_pro_mixer_switch_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { ice1712_t *ice = snd_kcontrol_chip(kcontrol); - int index = kcontrol->private_value; + int index = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + kcontrol->private_value; spin_lock_irq(&ice->reg_lock); ucontrol->value.integer.value[0] = !((ice->pro_volumes[index] >> 15) & 1); @@ -1311,7 +1325,7 @@ static int snd_ice1712_pro_mixer_switch_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { ice1712_t *ice = snd_kcontrol_chip(kcontrol); - int index = kcontrol->private_value; + int index = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + kcontrol->private_value; unsigned int nval, change; nval = (ucontrol->value.integer.value[0] ? 0 : 0x00008000) | @@ -1337,7 +1351,7 @@ static int snd_ice1712_pro_mixer_volume_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { ice1712_t *ice = snd_kcontrol_chip(kcontrol); - int index = kcontrol->private_value; + int index = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + kcontrol->private_value; spin_lock_irq(&ice->reg_lock); ucontrol->value.integer.value[0] = (ice->pro_volumes[index] >> 0) & 127; @@ -1349,7 +1363,7 @@ static int snd_ice1712_pro_mixer_volume_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t * ucontrol) { ice1712_t *ice = snd_kcontrol_chip(kcontrol); - int index = kcontrol->private_value; + int index = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + kcontrol->private_value; unsigned int nval, change; nval = (ucontrol->value.integer.value[0] & 127) | @@ -1364,65 +1378,55 @@ } +static snd_kcontrol_new_t snd_ice1712_multi_ctrls[] __devinitdata = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Multi Playback Switch", + .info = snd_ice1712_pro_mixer_switch_info, + .get = snd_ice1712_pro_mixer_switch_get, + .put = snd_ice1712_pro_mixer_switch_put, + .private_value = 0, + .count = 10, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Multi Playback Volume", + .info = snd_ice1712_pro_mixer_volume_info, + .get = snd_ice1712_pro_mixer_volume_get, + .put = snd_ice1712_pro_mixer_volume_put, + .private_value = 0, + .count = 10, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Multi Capture Switch", + .info = snd_ice1712_pro_mixer_switch_info, + .get = snd_ice1712_pro_mixer_switch_get, + .put = snd_ice1712_pro_mixer_switch_put, + .private_value = 10, + .count = 10, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Multi Capture Volume", + .info = snd_ice1712_pro_mixer_volume_info, + .get = snd_ice1712_pro_mixer_volume_get, + .put = snd_ice1712_pro_mixer_volume_put, + .private_value = 10, + .count = 10, + }, +}; + static int __devinit snd_ice1712_build_pro_mixer(ice1712_t *ice) { snd_card_t * card = ice->card; - snd_kcontrol_t ctl; - int idx, err; - - /* PCM playback */ - for (idx = 0; idx < 10; idx++) { - memset(&ctl, 0, sizeof(ctl)); - strcpy(ctl.id.name, "Multi Playback Switch"); - ctl.id.index = idx; - ctl.id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - ctl.count = 1; - ctl.info = snd_ice1712_pro_mixer_switch_info; - ctl.get = snd_ice1712_pro_mixer_switch_get; - ctl.put = snd_ice1712_pro_mixer_switch_put; - ctl.private_value = idx; - ctl.private_data = ice; - if ((err = snd_ctl_add(card, snd_ctl_new(&ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0) - return err; - memset(&ctl, 0, sizeof(ctl)); - strcpy(ctl.id.name, "Multi Playback Volume"); - ctl.id.index = idx; - ctl.id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - ctl.count = 1; - ctl.info = snd_ice1712_pro_mixer_volume_info; - ctl.get = snd_ice1712_pro_mixer_volume_get; - ctl.put = snd_ice1712_pro_mixer_volume_put; - ctl.private_value = idx; - ctl.private_data = ice; - if ((err = snd_ctl_add(card, snd_ctl_new(&ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0) - return err; - } + unsigned int idx; + int err; - /* PCM capture */ - for (idx = 0; idx < 10; idx++) { - memset(&ctl, 0, sizeof(ctl)); - strcpy(ctl.id.name, "Multi Capture Switch"); - ctl.id.index = idx; - ctl.id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - ctl.count = 1; - ctl.info = snd_ice1712_pro_mixer_switch_info; - ctl.get = snd_ice1712_pro_mixer_switch_get; - ctl.put = snd_ice1712_pro_mixer_switch_put; - ctl.private_value = idx + 10; - ctl.private_data = ice; - if ((err = snd_ctl_add(card, snd_ctl_new(&ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0) - return err; - memset(&ctl, 0, sizeof(ctl)); - strcpy(ctl.id.name, "Multi Capture Volume"); - ctl.id.index = idx; - ctl.id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - ctl.count = 1; - ctl.info = snd_ice1712_pro_mixer_volume_info; - ctl.get = snd_ice1712_pro_mixer_volume_get; - ctl.put = snd_ice1712_pro_mixer_volume_put; - ctl.private_value = idx + 10; - ctl.private_data = ice; - if ((err = snd_ctl_add(card, snd_ctl_new(&ctl, SNDRV_CTL_ELEM_ACCESS_READ|SNDRV_CTL_ELEM_ACCESS_WRITE))) < 0) + /* multi-channel mixer */ + for (idx = 0; idx < ARRAY_SIZE(snd_ice1712_multi_ctrls); idx++) { + err = snd_ctl_add(card, snd_ctl_new1(&snd_ice1712_multi_ctrls[idx], ice)); + if (err < 0) return err; } @@ -1911,7 +1915,7 @@ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; - uinfo->value.enumerated.items = kcontrol->id.index < 2 ? 12 : 11; + uinfo->value.enumerated.items = snd_ctl_get_ioffidx(kcontrol, &uinfo->id) < 2 ? 12 : 11; if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); @@ -1921,7 +1925,7 @@ static int snd_ice1712_pro_route_analog_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol) { ice1712_t *ice = snd_kcontrol_chip(kcontrol); - int idx = kcontrol->id.index; + int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); unsigned int val, cval; spin_lock_irq(&ice->reg_lock); @@ -1947,7 +1951,7 @@ { ice1712_t *ice = snd_kcontrol_chip(kcontrol); int change, shift; - int idx = kcontrol->id.index; + int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); unsigned int val, old_val, nval; /* update PSDOUT */ @@ -1995,7 +1999,7 @@ static int snd_ice1712_pro_route_spdif_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol) { ice1712_t *ice = snd_kcontrol_chip(kcontrol); - int idx = kcontrol->id.index; + int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); unsigned int val, cval; val = inw(ICEMT(ice, ROUTE_SPDOUT)); cval = (val >> (idx * 4 + 8)) & 0x0f; @@ -2015,7 +2019,7 @@ { ice1712_t *ice = snd_kcontrol_chip(kcontrol); int change, shift; - int idx = kcontrol->id.index; + int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); unsigned int val, old_val, nval; /* update SPDOUT */ @@ -2063,6 +2067,7 @@ .info = snd_ice1712_pro_route_info, .get = snd_ice1712_pro_route_spdif_get, .put = snd_ice1712_pro_route_spdif_put, + .count = 2, }; @@ -2153,7 +2158,7 @@ static int __devinit snd_ice1712_read_eeprom(ice1712_t *ice) { int dev = 0xa0; /* EEPROM device address */ - unsigned int i; + unsigned int i, size; if ((inb(ICEREG(ice, I2C_CTRL)) & ICE1712_I2C_EEPROM) == 0) { snd_printk("ICE1712 has not detected EEPROM\n"); @@ -2164,7 +2169,9 @@ (snd_ice1712_read_i2c(ice, dev, 0x02) << 16) | (snd_ice1712_read_i2c(ice, dev, 0x03) << 24); ice->eeprom.size = snd_ice1712_read_i2c(ice, dev, 0x04); - if (ice->eeprom.size > 32) { + if (ice->eeprom.size < 6) + ice->eeprom.size = 32; /* FIXME: any cards without the correct size? */ + else if (ice->eeprom.size > 32) { snd_printk("invalid EEPROM (size = %i)\n", ice->eeprom.size); return -EIO; } @@ -2173,7 +2180,8 @@ snd_printk("invalid EEPROM version %i\n", ice->eeprom.version); /* return -EIO; */ } - for (i = 0; i < ice->eeprom.size; i++) + size = ice->eeprom.size - 6; + for (i = 0; i < size; i++) ice->eeprom.data[i] = snd_ice1712_read_i2c(ice, dev, i + 6); ice->eeprom.gpiomask = ice->eeprom.data[ICE_EEP1_GPIO_MASK]; @@ -2249,8 +2257,6 @@ static int __devinit snd_ice1712_build_controls(ice1712_t *ice) { - unsigned int idx; - snd_kcontrol_t *kctl; int err; err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_eeprom, ice)); @@ -2267,25 +2273,17 @@ if (err < 0) return err; - for (idx = 0; idx < ice->num_total_dacs; idx++) { - kctl = snd_ctl_new1(&snd_ice1712_mixer_pro_analog_route, ice); - if (kctl == NULL) - return -ENOMEM; - kctl->id.index = idx; - err = snd_ctl_add(ice->card, kctl); + if (ice->num_total_dacs > 0) { + snd_kcontrol_new_t tmp = snd_ice1712_mixer_pro_analog_route; + tmp.count = ice->num_total_dacs; + err = snd_ctl_add(ice->card, snd_ctl_new1(&tmp, ice)); if (err < 0) return err; } - for (idx = 0; idx < 2; idx++) { - kctl = snd_ctl_new1(&snd_ice1712_mixer_pro_spdif_route, ice); - if (kctl == NULL) - return -ENOMEM; - kctl->id.index = idx; - err = snd_ctl_add(ice->card, kctl); - if (err < 0) - return err; - } + err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_pro_spdif_route, ice)); + if (err < 0) + return err; err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_pro_volume_rate, ice)); if (err < 0) @@ -2326,8 +2324,7 @@ release_resource(ice->res_profi_port); kfree_nocheck(ice->res_profi_port); } - if (ice->akm) - kfree(ice->akm); + snd_ice1712_akm4xxx_free(ice); snd_magic_kfree(ice); return 0; } diff -Nru a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h --- a/sound/pci/ice1712/ice1712.h Mon Jun 9 23:16:06 2003 +++ b/sound/pci/ice1712/ice1712.h Mon Jun 9 23:16:06 2003 @@ -26,6 +26,7 @@ #include <sound/ac97_codec.h> #include <sound/rawmidi.h> #include <sound/i2c.h> +#include <sound/ak4xxx-adda.h> #include <sound/pcm.h> @@ -214,7 +215,6 @@ */ typedef struct _snd_ice1712 ice1712_t; -typedef struct snd_ak4xxx akm4xxx_t; typedef struct { unsigned int subvendor; /* PCI[2c-2f] */ @@ -254,17 +254,7 @@ #define ice_has_con_ac97(ice) (!((ice)->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_NO_CON_AC97)) -struct snd_ak4xxx { - unsigned int num_adcs; /* AK4524 or AK4528 ADCs */ - unsigned int num_dacs; /* AK4524 or AK4528 DACs */ - unsigned char images[4][16]; /* saved register image */ - unsigned char ipga_gain[4][2]; /* saved register image for IPGA (AK4528) */ - ice1712_t *chip; - /* template should fill the following fields */ - unsigned int idx_offset; /* control index offset */ - enum { - SND_AK4524, SND_AK4528, SND_AK4529, SND_AK4355, SND_AK4381 - } type; +struct snd_ak4xxx_private { unsigned int cif: 1; /* CIF mode */ unsigned char caddr; /* C0 and C1 bits */ unsigned int data_mask; /* DATA gpio bit */ @@ -275,8 +265,6 @@ unsigned int add_flags; /* additional bits at init */ unsigned int mask_flags; /* total mask bits */ struct snd_akm4xxx_ops { - int (*start)(akm4xxx_t *ak, int chip); - void (*stop)(akm4xxx_t *ak); void (*set_rate_val)(akm4xxx_t *ak, unsigned int rate); } ops; }; @@ -439,9 +427,8 @@ int snd_ice1712_spdif_build_controls(ice1712_t *ice); -void snd_ice1712_akm4xxx_write(akm4xxx_t *ice, int chip, unsigned char addr, unsigned char data); -void snd_ice1712_akm4xxx_reset(akm4xxx_t *ice, int state); -void snd_ice1712_akm4xxx_init(akm4xxx_t *ak, const akm4xxx_t *template, ice1712_t *ice); +int snd_ice1712_akm4xxx_init(akm4xxx_t *ak, const akm4xxx_t *template, const struct snd_ak4xxx_private *priv, ice1712_t *ice); +void snd_ice1712_akm4xxx_free(ice1712_t *ice); int snd_ice1712_akm4xxx_build_controls(ice1712_t *ice); int snd_ice1712_init_cs8427(ice1712_t *ice, int addr); @@ -469,6 +456,8 @@ int (*chip_init)(ice1712_t *); int (*build_controls)(ice1712_t *); int no_mpu401: 1; + unsigned int eeprom_size; + unsigned char *eeprom_data; }; diff -Nru a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c --- a/sound/pci/ice1712/ice1724.c Mon Jun 9 23:16:11 2003 +++ b/sound/pci/ice1712/ice1724.c Mon Jun 9 23:16:11 2003 @@ -42,6 +42,7 @@ /* lowlevel routines */ #include "amp.h" #include "revo.h" +#include "aureon.h" MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>"); MODULE_DESCRIPTION("ICEnsemble ICE1724 (Envy24HT)"); @@ -50,6 +51,7 @@ MODULE_DEVICES("{" REVO_DEVICE_DESC AMP_AUDIO2000_DEVICE_DESC + AUREON_DEVICE_DESC "{VIA,VT1724}," "{ICEnsemble,Generic ICE1724}," "{ICEnsemble,Generic Envy24HT}}"); @@ -116,8 +118,9 @@ continue; if (!(old_cmd & VT1724_AC97_READY)) continue; - return 0; + return old_cmd; } + snd_printd(KERN_ERR "snd_vt1724_ac97_ready: timeout\n"); return old_cmd; } @@ -127,6 +130,7 @@ for (tm = 0; tm < 0x10000; tm++) if ((inb(ICEMT1724(ice, AC97_CMD)) & bit) == 0) return 0; + snd_printd(KERN_ERR "snd_vt1724_ac97_wait_bit: timeout\n"); return -EIO; } @@ -138,9 +142,10 @@ unsigned char old_cmd; old_cmd = snd_vt1724_ac97_ready(ice); + old_cmd &= ~VT1724_AC97_ID_MASK; + old_cmd |= ac97->num; outb(reg, ICEMT1724(ice, AC97_INDEX)); outw(val, ICEMT1724(ice, AC97_DATA)); - old_cmd &= ~(VT1724_AC97_PBK_VSR | VT1724_AC97_CAP_VSR); outb(old_cmd | VT1724_AC97_WRITE, ICEMT1724(ice, AC97_CMD)); snd_vt1724_ac97_wait_bit(ice, VT1724_AC97_WRITE); } @@ -151,6 +156,8 @@ unsigned char old_cmd; old_cmd = snd_vt1724_ac97_ready(ice); + old_cmd &= ~VT1724_AC97_ID_MASK; + old_cmd |= ac97->num; outb(reg, ICEMT1724(ice, AC97_INDEX)); outb(old_cmd | VT1724_AC97_READ, ICEMT1724(ice, AC97_CMD)); if (snd_vt1724_ac97_wait_bit(ice, VT1724_AC97_READ) < 0) @@ -167,6 +174,7 @@ static void snd_vt1724_set_gpio_dir(ice1712_t *ice, unsigned int data) { outl(data, ICEREG1724(ice, GPIO_DIRECTION)); + inw(ICEREG1724(ice, GPIO_DIRECTION)); /* dummy read for pci-posting */ } /* set the gpio mask (0 = writable) */ @@ -174,12 +182,14 @@ { outw(data, ICEREG1724(ice, GPIO_WRITE_MASK)); outb((data >> 16) & 0xff, ICEREG1724(ice, GPIO_WRITE_MASK_22)); + inw(ICEREG1724(ice, GPIO_WRITE_MASK)); /* dummy read for pci-posting */ } static void snd_vt1724_set_gpio_data(ice1712_t *ice, unsigned int data) { outw(data, ICEREG1724(ice, GPIO_DATA)); outb(data >> 16, ICEREG1724(ice, GPIO_DATA_22)); + inw(ICEREG1724(ice, GPIO_DATA)); /* dummy read for pci-posting */ } static unsigned int snd_vt1724_get_gpio_data(ice1712_t *ice) @@ -284,14 +294,15 @@ ice1712_t *ice = snd_pcm_substream_chip(substream); unsigned int what; unsigned int old; + struct list_head *pos; snd_pcm_substream_t *s; switch (cmd) { case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: what = 0; - s = substream; - do { + snd_pcm_group_for_each(pos, substream) { + s = snd_pcm_group_substream_entry(pos); if (s == ice->playback_pro_substream) what |= VT1724_PDMA0_PAUSE; else if (s == ice->capture_pro_substream) @@ -300,8 +311,7 @@ what |= VT1724_PDMA4_PAUSE; else if (s == ice->capture_con_substream) what |= VT1724_RDMA1_PAUSE; - s = s->link_next; - } while (s != substream); + } spin_lock(&ice->reg_lock); old = inl(ICEMT1724(ice, DMA_PAUSE)); if (cmd == SNDRV_PCM_TRIGGER_PAUSE_PUSH) @@ -316,7 +326,8 @@ case SNDRV_PCM_TRIGGER_STOP: what = 0; s = substream; - do { + snd_pcm_group_for_each(pos, substream) { + s = snd_pcm_group_substream_entry(pos); if (s == ice->playback_pro_substream) { what |= VT1724_PDMA0_START; snd_pcm_trigger_done(s, substream); @@ -330,8 +341,7 @@ what |= VT1724_RDMA1_START; snd_pcm_trigger_done(s, substream); } - s = s->link_next; - } while (s != substream); + } spin_lock(&ice->reg_lock); old = inl(ICEMT1724(ice, DMA_CONTROL)); if (cmd == SNDRV_PCM_TRIGGER_START) @@ -410,14 +420,16 @@ val &= ~VT1724_MT_I2S_MCLK_128X; /* 256x MCLK */ if (val != old) { outb(val, ICEMT1724(ice, I2S_FORMAT)); - /* FIXME: is this revo only? */ - /* assert PRST# to converters; MT05 bit 7 */ - outb(inb(ICEMT1724(ice, AC97_CMD)) | 0x80, ICEMT1724(ice, AC97_CMD)); - spin_unlock_irqrestore(&ice->reg_lock, flags); - mdelay(5); - spin_lock_irqsave(&ice->reg_lock, flags); - /* deassert PRST# */ - outb(inb(ICEMT1724(ice, AC97_CMD)) & ~0x80, ICEMT1724(ice, AC97_CMD)); + if (ice->eeprom.subvendor == VT1724_SUBDEVICE_REVOLUTION71) { + /* FIXME: is this revo only? */ + /* assert PRST# to converters; MT05 bit 7 */ + outb(inb(ICEMT1724(ice, AC97_CMD)) | 0x80, ICEMT1724(ice, AC97_CMD)); + spin_unlock_irqrestore(&ice->reg_lock, flags); + mdelay(5); + spin_lock_irqsave(&ice->reg_lock, flags); + /* deassert PRST# */ + outb(inb(ICEMT1724(ice, AC97_CMD)) & ~0x80, ICEMT1724(ice, AC97_CMD)); + } } } spin_unlock_irqrestore(&ice->reg_lock, flags); @@ -878,6 +890,11 @@ if (! (ice->eeprom.data[ICE_EEP2_ACLINK] & VT1724_CFG_PRO_I2S)) { ac97_t ac97; + /* cold reset */ + outb(inb(ICEMT1724(ice, AC97_CMD)) | 0x80, ICEMT1724(ice, AC97_CMD)); + mdelay(5); /* FIXME */ + outb(inb(ICEMT1724(ice, AC97_CMD)) & ~0x80, ICEMT1724(ice, AC97_CMD)); + memset(&ac97, 0, sizeof(ac97)); ac97.write = snd_vt1724_ac97_write; ac97.read = snd_vt1724_ac97_read; @@ -1297,7 +1314,7 @@ return change; } -static snd_kcontrol_new_t snd_vt1724_pro_internal_clock = __devinitdata { +static snd_kcontrol_new_t snd_vt1724_pro_internal_clock __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Multi Track Internal Clock", .info = snd_vt1724_pro_internal_clock_info, @@ -1452,7 +1469,7 @@ static int snd_vt1724_pro_route_analog_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol) { ice1712_t *ice = snd_kcontrol_chip(kcontrol); - int idx = kcontrol->id.index; + int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); ucontrol->value.enumerated.item[0] = get_route_val(ice, analog_route_shift(idx)); return 0; } @@ -1460,7 +1477,7 @@ static int snd_vt1724_pro_route_analog_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol) { ice1712_t *ice = snd_kcontrol_chip(kcontrol); - int idx = kcontrol->id.index; + int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); return put_route_val(ice, ucontrol->value.enumerated.item[0], analog_route_shift(idx)); } @@ -1468,7 +1485,7 @@ static int snd_vt1724_pro_route_spdif_get(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol) { ice1712_t *ice = snd_kcontrol_chip(kcontrol); - int idx = kcontrol->id.index; + int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); ucontrol->value.enumerated.item[0] = get_route_val(ice, digital_route_shift(idx)); return 0; } @@ -1476,7 +1493,7 @@ static int snd_vt1724_pro_route_spdif_put(snd_kcontrol_t * kcontrol, snd_ctl_elem_value_t *ucontrol) { ice1712_t *ice = snd_kcontrol_chip(kcontrol); - int idx = kcontrol->id.index; + int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); return put_route_val(ice, ucontrol->value.enumerated.item[0], digital_route_shift(idx)); } @@ -1495,6 +1512,7 @@ .info = snd_vt1724_pro_route_info, .get = snd_vt1724_pro_route_spdif_get, .put = snd_vt1724_pro_route_spdif_put, + .count = 2, }; @@ -1533,6 +1551,19 @@ * */ +static struct snd_ice1712_card_info no_matched __devinitdata; + +static struct snd_ice1712_card_info *card_tables[] __devinitdata = { + snd_vt1724_revo_cards, + snd_vt1724_amp_cards, + snd_vt1724_aureon_cards, + 0, +}; + + +/* + */ + static unsigned char __devinit snd_vt1724_read_i2c(ice1712_t *ice, unsigned char dev, unsigned char addr) @@ -1548,7 +1579,8 @@ static int __devinit snd_vt1724_read_eeprom(ice1712_t *ice) { int dev = 0xa0; /* EEPROM device address */ - unsigned int i; + unsigned int i, size; + struct snd_ice1712_card_info **tbl, *c; if ((inb(ICEREG1724(ice, I2C_CTRL)) & VT1724_I2C_EEPROM) == 0) { snd_printk("ICE1724 has not detected EEPROM\n"); @@ -1558,8 +1590,27 @@ (snd_vt1724_read_i2c(ice, dev, 0x01) << 8) | (snd_vt1724_read_i2c(ice, dev, 0x02) << 16) | (snd_vt1724_read_i2c(ice, dev, 0x03) << 24); + + /* if the EEPROM is given by the driver, use it */ + for (tbl = card_tables; *tbl; tbl++) { + for (c = *tbl; c->subvendor; c++) { + if (c->subvendor == ice->eeprom.subvendor) { + if (! c->eeprom_size || ! c->eeprom_data) + goto found; + snd_printdd("using the defined eeprom..\n"); + ice->eeprom.version = 2; + ice->eeprom.size = c->eeprom_size + 6; + memcpy(ice->eeprom.data, c->eeprom_data, c->eeprom_size); + goto read_skipped; + } + } + } + + found: ice->eeprom.size = snd_vt1724_read_i2c(ice, dev, 0x04); - if (ice->eeprom.size > 32) { + if (ice->eeprom.size < 6) + ice->eeprom.size = 32; + else if (ice->eeprom.size > 32) { snd_printk("invalid EEPROM (size = %i)\n", ice->eeprom.size); return -EIO; } @@ -1568,9 +1619,11 @@ snd_printk("invalid EEPROM version %i\n", ice->eeprom.version); // return -EIO; } - for (i = 0; i < ice->eeprom.size; i++) + size = ice->eeprom.size - 6; + for (i = 0; i < size; i++) ice->eeprom.data[i] = snd_vt1724_read_i2c(ice, dev, i + 6); + read_skipped: ice->eeprom.gpiomask = eeprom_triple(ice, ICE_EEP2_GPIO_MASK); ice->eeprom.gpiostate = eeprom_triple(ice, ICE_EEP2_GPIO_STATE); ice->eeprom.gpiodir = eeprom_triple(ice, ICE_EEP2_GPIO_DIR); @@ -1605,20 +1658,13 @@ static int __devinit snd_vt1724_spdif_build_controls(ice1712_t *ice) { int err; - unsigned int idx; snd_kcontrol_t *kctl; snd_assert(ice->pcm != NULL, return -EIO); - for (idx = 0; idx < 2; idx++) { - kctl = snd_ctl_new1(&snd_vt1724_mixer_pro_spdif_route, ice); - if (kctl == NULL) - return -ENOMEM; - kctl->id.index = idx; - err = snd_ctl_add(ice->card, kctl); - if (err < 0) - return err; - } + err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_vt1724_mixer_pro_spdif_route, ice)); + if (err < 0) + return err; err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_vt1724_spdif_switch, ice)); if (err < 0) @@ -1649,8 +1695,6 @@ static int __devinit snd_vt1724_build_controls(ice1712_t *ice) { - unsigned int idx; - snd_kcontrol_t *kctl; int err; err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_vt1724_eeprom, ice)); @@ -1667,12 +1711,10 @@ if (err < 0) return err; - for (idx = 0; idx < ice->num_total_dacs; idx++) { - kctl = snd_ctl_new1(&snd_vt1724_mixer_pro_analog_route, ice); - if (kctl == NULL) - return -ENOMEM; - kctl->id.index = idx; - err = snd_ctl_add(ice->card, kctl); + if (ice->num_total_dacs > 0) { + snd_kcontrol_new_t tmp = snd_vt1724_mixer_pro_analog_route; + tmp.count = ice->num_total_dacs; + err = snd_ctl_add(ice->card, snd_ctl_new1(&tmp, ice)); if (err < 0) return err; } @@ -1705,8 +1747,7 @@ release_resource(ice->res_profi_port); kfree_nocheck(ice->res_profi_port); } - if (ice->akm) - kfree(ice->akm); + snd_ice1712_akm4xxx_free(ice); snd_magic_kfree(ice); return 0; } @@ -1807,15 +1848,6 @@ * Registration * */ - -static struct snd_ice1712_card_info no_matched __devinitdata; - -static struct snd_ice1712_card_info *card_tables[] __devinitdata = { - snd_vt1724_revo_cards, - snd_vt1724_amp_cards, - 0, -}; - static int __devinit snd_vt1724_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) diff -Nru a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c --- a/sound/pci/ice1712/revo.c Mon Jun 9 23:16:14 2003 +++ b/sound/pci/ice1712/revo.c Mon Jun 9 23:16:14 2003 @@ -59,18 +59,18 @@ reg = 1; shift = 3; } - tmp = ak->images[0][reg]; + tmp = snd_akm4xxx_get(ak, 0, reg); old = (tmp >> shift) & 0x03; if (old == dfs) return; /* reset DFS */ - snd_ice1712_akm4xxx_reset(ak, 1); - tmp = ak->images[0][reg]; + snd_akm4xxx_reset(ak, 1); + tmp = snd_akm4xxx_get(ak, 0, reg); tmp &= ~(0x03 << shift); tmp |= dfs << shift; - snd_ice1712_akm4xxx_write(ak, 0, reg, tmp); - snd_ice1712_akm4xxx_reset(ak, 0); + snd_akm4xxx_write(ak, 0, reg, tmp); + snd_akm4xxx_reset(ak, 0); } /* @@ -80,6 +80,12 @@ static akm4xxx_t akm_revo_front __devinitdata = { .type = SND_AK4381, .num_dacs = 2, + .ops = { + .set_rate_val = revo_set_rate_val + } +}; + +static struct snd_ak4xxx_private akm_revo_front_priv __devinitdata = { .caddr = 1, .cif = 0, .data_mask = VT1724_REVO_CDOUT, @@ -89,15 +95,18 @@ .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2, .add_flags = VT1724_REVO_CCLK, /* high at init */ .mask_flags = 0, - .ops = { - .set_rate_val = revo_set_rate_val - } }; static akm4xxx_t akm_revo_surround __devinitdata = { .type = SND_AK4355, .idx_offset = 1, .num_dacs = 6, + .ops = { + .set_rate_val = revo_set_rate_val + } +}; + +static struct snd_ak4xxx_private akm_revo_surround_priv __devinitdata = { .caddr = 3, .cif = 0, .data_mask = VT1724_REVO_CDOUT, @@ -107,14 +116,12 @@ .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1 | VT1724_REVO_CS2, .add_flags = VT1724_REVO_CCLK, /* high at init */ .mask_flags = 0, - .ops = { - .set_rate_val = revo_set_rate_val - } }; static int __devinit revo_init(ice1712_t *ice) { akm4xxx_t *ak; + int err; /* determine I2C, DACs and ADCs */ switch (ice->eeprom.subvendor) { @@ -133,8 +140,10 @@ ice->akm_codecs = 2; switch (ice->eeprom.subvendor) { case VT1724_SUBDEVICE_REVOLUTION71: - snd_ice1712_akm4xxx_init(ak, &akm_revo_front, ice); - snd_ice1712_akm4xxx_init(ak + 1, &akm_revo_surround, ice); + if ((err = snd_ice1712_akm4xxx_init(ak, &akm_revo_front, &akm_revo_front_priv, ice)) < 0) + return err; + if ((err = snd_ice1712_akm4xxx_init(ak + 1, &akm_revo_surround, &akm_revo_surround_priv, ice)) < 0) + return err; /* unmute all codecs */ snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, VT1724_REVO_MUTE); break; diff -Nru a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c --- a/sound/pci/intel8x0.c Mon Jun 9 23:16:14 2003 +++ b/sound/pci/intel8x0.c Mon Jun 9 23:16:14 2003 @@ -53,8 +53,8 @@ "{Intel,ICH5}," "{Intel,MX440}," "{SiS,SI7012}," - "{NVidia,NForce Audio}," - "{NVidia,NForce2 Audio}," + "{NVidia,nForce Audio}," + "{NVidia,nForce2 Audio}," "{AMD,AMD768}," "{AMD,AMD8111}," "{ALI,M5455}}"); @@ -139,7 +139,7 @@ #define PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO 0x00da #endif -enum { DEVICE_INTEL, DEVICE_INTEL_ICH4, DEVICE_SIS, DEVICE_ALI }; +enum { DEVICE_INTEL, DEVICE_INTEL_ICH4, DEVICE_SIS, DEVICE_ALI, DEVICE_NFORCE }; #define ICHREG(x) ICH_REG_##x @@ -228,6 +228,7 @@ #define ICH_MCINT 0x00000080 /* MIC capture interrupt */ #define ICH_POINT 0x00000040 /* playback interrupt */ #define ICH_PIINT 0x00000020 /* capture interrupt */ +#define ICH_NVSPINT 0x00000010 /* nforce spdif interrupt */ #define ICH_MOINT 0x00000004 /* modem playback interrupt */ #define ICH_MIINT 0x00000002 /* modem capture interrupt */ #define ICH_GSCI 0x00000001 /* GPI status change interrupt */ @@ -266,7 +267,9 @@ ICH_REG_ALI_INTERRUPTSR = 0x18, /* Interrupt Status Register */ ICH_REG_ALI_FIFOCR2 = 0x1c, /* FIFO Control Register 2 */ ICH_REG_ALI_CPR = 0x20, /* Command Port Register */ + ICH_REG_ALI_CPR_ADDR = 0x22, /* ac97 addr write */ ICH_REG_ALI_SPR = 0x24, /* Status Port Register */ + ICH_REG_ALI_SPR_ADDR = 0x26, /* ac97 addr read */ ICH_REG_ALI_FIFOCR3 = 0x2c, /* FIFO Control Register 3 */ ICH_REG_ALI_TTSR = 0x30, /* Transmit Tag Slot Register */ ICH_REG_ALI_RTSR = 0x34, /* Receive Tag Slot Register */ @@ -276,6 +279,12 @@ ICH_REG_ALI_SPDIFICS = 0xfc /* spdif interface control/status */ }; +#define ALI_CAS_SEM_BUSY 0x80000000 +#define ALI_CSPSR_CODEC_READY 0x08 +#define ALI_CPR_ADDR_READ 0x80 +#define ALI_CSPSR_READ_OK 0x02 +#define ALI_CSPSR_WRITE_OK 0x01 + /* interrupts for the whole chip by interrupt status register finish */ #define ALI_INT_SPDIFOUT (1<<23) /* controller spdif out INTERRUPT */ @@ -298,6 +307,7 @@ */ enum { ICHD_PCMIN, ICHD_PCMOUT, ICHD_MIC, ICHD_MIC2, ICHD_PCM2IN, ICHD_SPBAR, ICHD_LAST = ICHD_SPBAR }; +enum { NVD_PCMIN, NVD_PCMOUT, NVD_MIC, NVD_SPBAR, NVD_LAST = NVD_SPBAR }; enum { ALID_PCMIN, ALID_PCMOUT, ALID_MIC, ALID_AC97SPDIFOUT, ALID_SPDIFIN, ALID_SPDIFOUT, ALID_LAST = ALID_SPDIFOUT }; #define get_ichdev(substream) (ichdev_t *)(substream->runtime->private_data) @@ -355,12 +365,8 @@ struct pci_dev *pci; snd_card_t *card; - snd_pcm_t *pcm; - snd_pcm_t *pcm_mic; - snd_pcm_t *pcm_mic2; - snd_pcm_t *pcm2; - snd_pcm_t *pcm_spdif; - snd_pcm_t *pcm_ac97spdif; + int pcm_devs; + snd_pcm_t *pcm[6]; ichdev_t ichd[6]; int multi4: 1, @@ -382,6 +388,7 @@ dma_addr_t bdbars_addr; u32 int_sta_reg; /* interrupt status register */ u32 int_sta_mask; /* interrupt status mask */ + unsigned int pcm_pos_shift; #ifdef CONFIG_PM int in_suspend; @@ -397,9 +404,9 @@ { 0x8086, 0x24d5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ICH5 */ { 0x8086, 0x7195, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 440MX */ { 0x1039, 0x7012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_SIS }, /* SI7012 */ - { 0x10de, 0x01b1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* NFORCE */ - { 0x10de, 0x006a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* NFORCE2 */ - { 0x10de, 0x00da, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* NFORCE3 */ + { 0x10de, 0x01b1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* NFORCE */ + { 0x10de, 0x006a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* NFORCE2 */ + { 0x10de, 0x00da, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE }, /* NFORCE3 */ { 0x1022, 0x746d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* AMD8111 */ { 0x1022, 0x7445, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* AMD768 */ { 0x10b9, 0x5455, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALI }, /* Ali5455 */ @@ -594,13 +601,9 @@ static int snd_intel8x0_ali_codec_semaphore(intel8x0_t *chip) { int time = 100; - do { - if (igetdword(chip, ICHREG(ALI_CAS)) & 0x80000000) - return snd_intel8x0_ali_codec_ready(chip, 0x08); + while (time-- && (igetdword(chip, ICHREG(ALI_CAS)) & ALI_CAS_SEM_BUSY)) udelay(1); - } while (time--); - snd_printk(KERN_WARNING "intel8x0: AC97 codec semaphore timeout.\n"); - return -EBUSY; + return snd_intel8x0_ali_codec_ready(chip, ALI_CSPSR_CODEC_READY); } static unsigned short snd_intel8x0_ali_codec_read(ac97_t *ac97, unsigned short reg) @@ -611,15 +614,14 @@ spin_lock(&chip->ac97_lock); if (snd_intel8x0_ali_codec_semaphore(chip)) goto __err; - reg |= 0x0080; - iputword(chip, ICHREG(ALI_CPR) + 2, reg | 0x0080); - if (snd_intel8x0_ali_codec_ready(chip, 0x02)) + iputword(chip, ICHREG(ALI_CPR_ADDR), reg | ALI_CPR_ADDR_READ); + if (snd_intel8x0_ali_codec_ready(chip, ALI_CSPSR_READ_OK)) goto __err; data = igetword(chip, ICHREG(ALI_SPR)); - reg2 = igetword(chip, ICHREG(ALI_SPR) + 2); + reg2 = igetword(chip, ICHREG(ALI_SPR_ADDR)); if (reg != reg2) { - snd_printd(KERN_WARNING "intel8x0: AC97 read not completed?\n"); - goto __err; + snd_printd(KERN_WARNING "intel8x0: AC97 read not completed? 0x%x != 0x%x\n", reg, reg2); + // goto __err; } spin_unlock(&chip->ac97_lock); return data; @@ -638,8 +640,8 @@ return; } iputword(chip, ICHREG(ALI_CPR), val); - iputbyte(chip, ICHREG(ALI_CPR) + 2, reg); - snd_intel8x0_ali_codec_ready(chip, 0x01); + iputbyte(chip, ICHREG(ALI_CPR_ADDR), reg); + snd_intel8x0_ali_codec_ready(chip, ALI_CSPSR_WRITE_OK); spin_unlock(&chip->ac97_lock); } @@ -652,7 +654,6 @@ int idx; u32 *bdbar = ichdev->bdbar; unsigned long port = ichdev->reg_offset; - int shiftlen = (chip->device_type == DEVICE_SIS) ? 0 : 1; iputdword(chip, port + ICH_REG_OFF_BDBAR, ichdev->bdbar_addr); if (ichdev->size == ichdev->fragsize) { @@ -661,10 +662,10 @@ for (idx = 0; idx < (ICH_REG_LVI_MASK + 1) * 2; idx += 4) { bdbar[idx + 0] = cpu_to_le32(ichdev->physbuf); bdbar[idx + 1] = cpu_to_le32(0x80000000 | /* interrupt on completion */ - ichdev->fragsize1 >> shiftlen); + ichdev->fragsize1 >> chip->pcm_pos_shift); bdbar[idx + 2] = cpu_to_le32(ichdev->physbuf + (ichdev->size >> 1)); bdbar[idx + 3] = cpu_to_le32(0x80000000 | /* interrupt on completion */ - ichdev->fragsize1 >> shiftlen); + ichdev->fragsize1 >> chip->pcm_pos_shift); } ichdev->frags = 2; } else { @@ -673,7 +674,7 @@ for (idx = 0; idx < (ICH_REG_LVI_MASK + 1) * 2; idx += 2) { bdbar[idx + 0] = cpu_to_le32(ichdev->physbuf + (((idx >> 1) * ichdev->fragsize) % ichdev->size)); bdbar[idx + 1] = cpu_to_le32(0x80000000 | /* interrupt on completion */ - ichdev->fragsize >> shiftlen); + ichdev->fragsize >> chip->pcm_pos_shift); // printk("bdbar[%i] = 0x%x [0x%x]\n", idx + 0, bdbar[idx + 0], bdbar[idx + 1]); } ichdev->frags = ichdev->size / ichdev->fragsize; @@ -698,7 +699,6 @@ unsigned long port = ichdev->reg_offset; int ack = 0; - spin_lock(&chip->reg_lock); ichdev->position += ichdev->fragsize1; ichdev->position %= ichdev->size; ichdev->lvi++; @@ -710,9 +710,11 @@ // printk("new: bdbar[%i] = 0x%x [0x%x], prefetch = %i, all = 0x%x, 0x%x\n", ichdev->lvi * 2, ichdev->bdbar[ichdev->lvi * 2], ichdev->bdbar[ichdev->lvi * 2 + 1], inb(ICH_REG_OFF_PIV + port), inl(port + 4), inb(port + ICH_REG_OFF_CR)); if ((ack = (--ichdev->ack == 0)) != 0) ichdev->ack = ichdev->ack_reload; - spin_unlock(&chip->reg_lock); - if (ack && ichdev->substream) + if (ack && ichdev->substream) { + spin_unlock(&chip->reg_lock); snd_pcm_period_elapsed(ichdev->substream); + spin_lock(&chip->reg_lock); + } iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI); } @@ -729,15 +731,17 @@ spin_unlock(&chip->reg_lock); return IRQ_NONE; } - /* ack first */ - iputdword(chip, chip->int_sta_reg, status & ~chip->int_sta_mask); - spin_unlock(&chip->reg_lock); for (i = 0; i < chip->bdbars_count; i++) { ichdev = &chip->ichd[i]; if (status & ichdev->int_sta_mask) snd_intel8x0_update(chip, ichdev); } + + /* ack them */ + iputdword(chip, chip->int_sta_reg, status & chip->int_sta_mask); + spin_unlock(&chip->reg_lock); + return IRQ_HANDLED; } @@ -861,9 +865,11 @@ snd_intel8x0_setup_multi_channels(chip, runtime->channels); spin_unlock(&chip->reg_lock); } - for (i = 0; i < 3; i++) - if (ichdev->ac97_rate_regs[i]) - snd_ac97_set_rate(ichdev->ac97, ichdev->ac97_rate_regs[i], runtime->rate); + if (ichdev->ac97) { + for (i = 0; i < 3; i++) + if (ichdev->ac97_rate_regs[i]) + snd_ac97_set_rate(ichdev->ac97, ichdev->ac97_rate_regs[i], runtime->rate); + } snd_intel8x0_setup_periods(chip, ichdev); return 0; } @@ -875,10 +881,7 @@ size_t ptr; ptr = ichdev->fragsize1; - if (chip->device_type == DEVICE_SIS) - ptr -= igetword(chip, ichdev->reg_offset + ichdev->roff_picb); - else - ptr -= igetword(chip, ichdev->reg_offset + ichdev->roff_picb) << 1; + ptr -= igetword(chip, ichdev->reg_offset + ichdev->roff_picb) << chip->pcm_pos_shift; ptr += ichdev->position; return bytes_to_frames(substream->runtime, ptr); } @@ -936,7 +939,7 @@ ichdev->substream = substream; runtime->hw = snd_intel8x0_stream; - if (ichdev->ac97_rates_idx >= 0) + if (ichdev->ac97 && ichdev->ac97_rates_idx >= 0) runtime->hw.rates = ichdev->ac97->rates[ichdev->ac97_rates_idx]; if (!(runtime->hw.rates & SNDRV_PCM_RATE_8000)) runtime->hw.rate_min = 48000; @@ -1038,15 +1041,17 @@ static int snd_intel8x0_spdif_open(snd_pcm_substream_t * substream) { intel8x0_t *chip = snd_pcm_substream_chip(substream); + int idx = chip->device_type == DEVICE_NFORCE ? NVD_SPBAR : ICHD_SPBAR; - return snd_intel8x0_pcm_open(substream, &chip->ichd[ICHD_SPBAR]); + return snd_intel8x0_pcm_open(substream, &chip->ichd[idx]); } static int snd_intel8x0_spdif_close(snd_pcm_substream_t * substream) { intel8x0_t *chip = snd_pcm_substream_chip(substream); + int idx = chip->device_type == DEVICE_NFORCE ? NVD_SPBAR : ICHD_SPBAR; - chip->ichd[ICHD_SPBAR].substream = NULL; + chip->ichd[idx].substream = NULL; return 0; } @@ -1227,270 +1232,182 @@ .pointer = snd_intel8x0_pcm_pointer, }; -static void snd_intel8x0_pcm_free(snd_pcm_t *pcm) -{ - intel8x0_t *chip = snd_magic_cast(intel8x0_t, pcm->private_data, return); - chip->pcm = NULL; - snd_pcm_lib_preallocate_free_for_all(pcm); -} - -static int __devinit snd_intel8x0_pcm(intel8x0_t *chip, int device, snd_pcm_t ** rpcm) -{ - snd_pcm_t *pcm; - int err; - - if (rpcm) - *rpcm = NULL; - err = snd_pcm_new(chip->card, "Intel ICH", device, 1, 1, &pcm); - if (err < 0) - return err; - - if (chip->device_type == DEVICE_ALI) { - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_intel8x0_ali_playback_ops); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_intel8x0_ali_capture_ops); - } else { - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_intel8x0_playback_ops); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_intel8x0_capture_ops); - } - - pcm->private_data = chip; - pcm->private_free = snd_intel8x0_pcm_free; - pcm->info_flags = 0; - strcpy(pcm->name, chip->card->shortname); - chip->pcm = pcm; - - snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 128*1024); - - if (rpcm) - *rpcm = pcm; - return 0; -} - -/* - * PCM code - MIC - */ - -static void snd_intel8x0_pcm_mic_free(snd_pcm_t *pcm) -{ - intel8x0_t *chip = snd_magic_cast(intel8x0_t, pcm->private_data, return); - chip->pcm_mic = NULL; -} - -static int __devinit snd_intel8x0_pcm_mic(intel8x0_t *chip, int device, snd_pcm_t ** rpcm) -{ - snd_pcm_t *pcm; - int err; - - if (rpcm) - *rpcm = NULL; - err = snd_pcm_new(chip->card, "Intel ICH - MIC ADC", device, 0, 1, &pcm); - if (err < 0) - return err; - - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, - chip->device_type == DEVICE_ALI ? - &snd_intel8x0_ali_capture_mic_ops : - &snd_intel8x0_capture_mic_ops); - - pcm->private_data = chip; - pcm->private_free = snd_intel8x0_pcm_mic_free; - pcm->info_flags = 0; - sprintf(pcm->name, "%s - MIC ADC", chip->card->shortname); - - chip->pcm_mic = pcm; - - snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 0, 128*1024); - - if (rpcm) - *rpcm = pcm; - return 0; -} - -/* - * PCM code - MIC2 - */ - -static void snd_intel8x0_pcm_mic2_free(snd_pcm_t *pcm) -{ - intel8x0_t *chip = snd_magic_cast(intel8x0_t, pcm->private_data, return); - chip->pcm_mic2 = NULL; -} - -static int __devinit snd_intel8x0_pcm_mic2(intel8x0_t *chip, int device, snd_pcm_t ** rpcm) -{ - snd_pcm_t *pcm; - int err; - - if (rpcm) - *rpcm = NULL; - err = snd_pcm_new(chip->card, "Intel ICH - MIC2 ADC", device, 0, 1, &pcm); - if (err < 0) - return err; - - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_intel8x0_capture_mic2_ops); - - pcm->private_data = chip; - pcm->private_free = snd_intel8x0_pcm_mic2_free; - pcm->info_flags = 0; - sprintf(pcm->name, "%s - MIC2 ADC", chip->card->shortname); - - chip->pcm_mic2 = pcm; - - snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 0, 128*1024); - - if (rpcm) - *rpcm = pcm; - return 0; -} - -/* - * PCM code - capture2 - */ - -static void snd_intel8x0_pcm_capture2_free(snd_pcm_t *pcm) -{ - intel8x0_t *chip = snd_magic_cast(intel8x0_t, pcm->private_data, return); - chip->pcm2 = NULL; -} - -static int __devinit snd_intel8x0_pcm_capture2(intel8x0_t *chip, int device, snd_pcm_t ** rpcm) -{ - snd_pcm_t *pcm; - int err; - - if (rpcm) - *rpcm = NULL; - err = snd_pcm_new(chip->card, "Intel ICH - ADC2", device, 0, 1, &pcm); - if (err < 0) - return err; - - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_intel8x0_capture2_ops); - - pcm->private_data = chip; - pcm->private_free = snd_intel8x0_pcm_capture2_free; - pcm->info_flags = 0; - sprintf(pcm->name, "%s - ADC2", chip->card->shortname); - - chip->pcm2 = pcm; - - snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 0, 128*1024); - - if (rpcm) - *rpcm = pcm; - return 0; -} - -/* - * PCM code - S/PDIF - */ - -static void snd_intel8x0_pcm_spdif_free(snd_pcm_t *pcm) -{ - intel8x0_t *chip = snd_magic_cast(intel8x0_t, pcm->private_data, return); - chip->pcm_spdif = NULL; -} - -static int __devinit snd_intel8x0_pcm_spdif(intel8x0_t *chip, int device, snd_pcm_t ** rpcm) -{ - snd_pcm_t *pcm; - int err; - - if (rpcm) - *rpcm = NULL; - err = snd_pcm_new(chip->card, "Intel ICH - IEC958", device, 1, 0, &pcm); - if (err < 0) - return err; - - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_intel8x0_spdif_ops); - - pcm->private_data = chip; - pcm->private_free = snd_intel8x0_pcm_spdif_free; - pcm->info_flags = 0; - sprintf(pcm->name, "%s - IEC958", chip->card->shortname); - - chip->pcm_spdif = pcm; - - snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 128*1024); - - if (rpcm) - *rpcm = pcm; - return 0; -} - -/* - * PCM code - ALI S/PDIF - */ - -static void snd_intel8x0_ali_spdif_free(snd_pcm_t *pcm) -{ - intel8x0_t *chip = snd_magic_cast(intel8x0_t, pcm->private_data, return); - chip->pcm_spdif = NULL; -} +struct ich_pcm_table { + char *suffix; + snd_pcm_ops_t *playback_ops; + snd_pcm_ops_t *capture_ops; + size_t prealloc_size; + size_t prealloc_max_size; + int ac97_idx; +}; -static int __devinit snd_intel8x0_ali_spdif(intel8x0_t *chip, int device, snd_pcm_t ** rpcm) +static int __devinit snd_intel8x0_pcm1(intel8x0_t *chip, int device, struct ich_pcm_table *rec) { snd_pcm_t *pcm; int err; + char name[32]; - if (rpcm) - *rpcm = NULL; - err = snd_pcm_new(chip->card, "Intel ICH - IEC958", device, 1, 1, &pcm); + if (rec->suffix) + sprintf(name, "Intel ICH - %s", rec->suffix); + else + strcpy(name, "Intel ICH"); + err = snd_pcm_new(chip->card, name, device, + rec->playback_ops ? 1 : 0, + rec->capture_ops ? 1 : 0, &pcm); if (err < 0) return err; - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_intel8x0_ali_spdifout_ops); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_intel8x0_ali_spdifin_ops); + if (rec->playback_ops) + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, rec->playback_ops); + if (rec->capture_ops) + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, rec->capture_ops); pcm->private_data = chip; - pcm->private_free = snd_intel8x0_ali_spdif_free; pcm->info_flags = 0; - sprintf(pcm->name, "%s - IEC958", chip->card->shortname); - - chip->pcm_spdif = pcm; + if (rec->suffix) + sprintf(pcm->name, "%s - %s", chip->card->shortname, rec->suffix); + else + strcpy(pcm->name, chip->card->shortname); + chip->pcm[device] = pcm; - snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 128*1024); + snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, rec->prealloc_size, + rec->prealloc_max_size); - if (rpcm) - *rpcm = pcm; return 0; } -/* - * PCM code - ALI AC'97 S/PDIF - */ - -static void snd_intel8x0_ali_ac97spdif_free(snd_pcm_t *pcm) -{ - intel8x0_t *chip = snd_magic_cast(intel8x0_t, pcm->private_data, return); - chip->pcm_ac97spdif = NULL; -} - -static int __devinit snd_intel8x0_ali_ac97spdif(intel8x0_t *chip, int device, snd_pcm_t ** rpcm) -{ - snd_pcm_t *pcm; - int err; - - if (rpcm) - *rpcm = NULL; - err = snd_pcm_new(chip->card, "ALI - AC97 IEC958", device, 1, 0, &pcm); - if (err < 0) - return err; - - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_intel8x0_ali_ac97spdifout_ops); - - pcm->private_data = chip; - pcm->private_free = snd_intel8x0_ali_ac97spdif_free; - pcm->info_flags = 0; - sprintf(pcm->name, "%s - AC97 IEC958", chip->card->shortname); - - chip->pcm_ac97spdif = pcm; +static struct ich_pcm_table intel_pcms[] __devinitdata = { + { + .playback_ops = &snd_intel8x0_playback_ops, + .capture_ops = &snd_intel8x0_capture_ops, + .prealloc_size = 64 * 1024, + .prealloc_max_size = 128 * 1024, + }, + { + .suffix = "MIC ADC", + .capture_ops = &snd_intel8x0_capture_mic_ops, + .prealloc_size = 0, + .prealloc_max_size = 128 * 1024, + .ac97_idx = ICHD_MIC, + }, + { + .suffix = "MIC2 ADC", + .capture_ops = &snd_intel8x0_capture_mic2_ops, + .prealloc_size = 0, + .prealloc_max_size = 128 * 1024, + .ac97_idx = ICHD_MIC2, + }, + { + .suffix = "ADC2", + .capture_ops = &snd_intel8x0_capture2_ops, + .prealloc_size = 0, + .prealloc_max_size = 128 * 1024, + .ac97_idx = ICHD_PCM2IN, + }, + { + .suffix = "IEC958", + .playback_ops = &snd_intel8x0_spdif_ops, + .prealloc_size = 64 * 1024, + .prealloc_max_size = 128 * 1024, + .ac97_idx = ICHD_SPBAR, + }, +}; + +static struct ich_pcm_table nforce_pcms[] __devinitdata = { + { + .playback_ops = &snd_intel8x0_playback_ops, + .capture_ops = &snd_intel8x0_capture_ops, + .prealloc_size = 64 * 1024, + .prealloc_max_size = 128 * 1024, + }, + { + .suffix = "MIC ADC", + .capture_ops = &snd_intel8x0_capture_mic_ops, + .prealloc_size = 0, + .prealloc_max_size = 128 * 1024, + .ac97_idx = NVD_MIC, + }, + { + .suffix = "IEC958", + .playback_ops = &snd_intel8x0_spdif_ops, + .prealloc_size = 64 * 1024, + .prealloc_max_size = 128 * 1024, + .ac97_idx = NVD_SPBAR, + }, +}; + +static struct ich_pcm_table ali_pcms[] __devinitdata = { + { + .playback_ops = &snd_intel8x0_ali_playback_ops, + .capture_ops = &snd_intel8x0_ali_capture_ops, + .prealloc_size = 64 * 1024, + .prealloc_max_size = 128 * 1024, + }, + { + .suffix = "MIC ADC", + .capture_ops = &snd_intel8x0_ali_capture_mic_ops, + .prealloc_size = 0, + .prealloc_max_size = 128 * 1024, + .ac97_idx = ALID_MIC, + }, + { + .suffix = "IEC958", + .playback_ops = &snd_intel8x0_ali_spdifout_ops, + .capture_ops = &snd_intel8x0_ali_spdifin_ops, + .prealloc_size = 64 * 1024, + .prealloc_max_size = 128 * 1024, + }, + { + .suffix = "AC97 IEC958", + .playback_ops = &snd_intel8x0_ali_ac97spdifout_ops, + .prealloc_size = 64 * 1024, + .prealloc_max_size = 128 * 1024, + .ac97_idx = ALID_AC97SPDIFOUT, + }, +}; + +static int __devinit snd_intel8x0_pcm(intel8x0_t *chip) +{ + int i, tblsize, device, err; + struct ich_pcm_table *tbl, *rec; + + switch (chip->device_type) { + case DEVICE_INTEL_ICH4: + tbl = intel_pcms; + tblsize = ARRAY_SIZE(intel_pcms); + break; + case DEVICE_NFORCE: + tbl = nforce_pcms; + tblsize = ARRAY_SIZE(nforce_pcms); + break; + case DEVICE_ALI: + tbl = ali_pcms; + tblsize = ARRAY_SIZE(ali_pcms); + break; + default: + tbl = intel_pcms; + tblsize = 2; + break; + } - snd_pcm_lib_preallocate_pci_pages_for_all(chip->pci, pcm, 64*1024, 128*1024); + device = 0; + for (i = 0; i < tblsize; i++) { + rec = tbl + i; + if (i > 0 && rec->ac97_idx) { + /* activate PCM only when associated AC'97 codec */ + if (! chip->ichd[rec->ac97_idx].ac97) + continue; + } + err = snd_intel8x0_pcm1(chip, device, rec); + if (err < 0) + return err; + device++; + } - if (rpcm) - *rpcm = pcm; + chip->pcm_devs = device; return 0; } + /* * Mixer part @@ -1502,11 +1419,13 @@ chip->ac97[ac97->num] = NULL; } -static struct _ac97_rate_regs { +struct _ac97_rate_regs { unsigned int ichd; unsigned short regs[3]; short rates_idx; -} ac97_rate_regs[] = { +}; + +static struct _ac97_rate_regs intel_ac97_rate_regs[] __devinitdata = { { ICHD_PCMOUT, { AC97_PCM_FRONT_DAC_RATE, AC97_PCM_SURR_DAC_RATE, AC97_PCM_LFE_DAC_RATE }, AC97_RATES_FRONT_DAC }, { ICHD_PCMIN, { AC97_PCM_LR_ADC_RATE, 0, 0 }, AC97_RATES_ADC }, { ICHD_MIC, { AC97_PCM_MIC_ADC_RATE, 0, 0 }, AC97_RATES_MIC_ADC }, @@ -1515,11 +1434,14 @@ { ICHD_SPBAR, { AC97_SPDIF, 0, 0 }, AC97_RATES_SPDIF }, }; -static struct _ac97_ali_rate_regs { - unsigned int ichd; - unsigned short regs[3]; - short rates_idx; -} ac97_ali_rate_regs[] = { +static struct _ac97_rate_regs nforce_ac97_rate_regs[] __devinitdata = { + { NVD_PCMOUT, { AC97_PCM_FRONT_DAC_RATE, AC97_PCM_SURR_DAC_RATE, AC97_PCM_LFE_DAC_RATE }, AC97_RATES_FRONT_DAC }, + { NVD_PCMIN, { AC97_PCM_LR_ADC_RATE, 0, 0 }, AC97_RATES_ADC }, + { NVD_MIC, { AC97_PCM_MIC_ADC_RATE, 0, 0 }, AC97_RATES_MIC_ADC }, + { NVD_SPBAR, { AC97_SPDIF, AC97_PCM_FRONT_DAC_RATE, 0 }, AC97_RATES_SPDIF }, +}; + +static struct _ac97_rate_regs ali_ac97_rate_regs[] __devinitdata = { { ALID_PCMOUT, { AC97_PCM_FRONT_DAC_RATE, AC97_PCM_SURR_DAC_RATE, AC97_PCM_LFE_DAC_RATE }, AC97_RATES_FRONT_DAC }, { ALID_PCMIN, { AC97_PCM_LR_ADC_RATE, 0, 0 }, AC97_RATES_ADC }, { ALID_MIC, { AC97_PCM_MIC_ADC_RATE, 0, 0 }, AC97_RATES_MIC_ADC }, @@ -1528,9 +1450,13 @@ { ALID_SPDIFIN, { 0, 0, 0 }, -1 }, }; -static struct ac97_quirk ac97_quirks[] = { +static struct ac97_quirk ac97_quirks[] __devinitdata = { { 0x1028, 0x0126, "Dell Optiplex GX260", AC97_TUNE_HP_ONLY }, - { 0x1734, 0x0088, "Fujisu-Siemens D1522", AC97_TUNE_HP_ONLY }, + { 0x1734, 0x0088, "Fujitsu-Siemens D1522", AC97_TUNE_HP_ONLY }, + { 0x10f1, 0x2665, "Fujitsu-Siemens Celcius", AC97_TUNE_HP_ONLY }, + { 0x8086, 0x4d44, "Intel D850EMV2", AC97_TUNE_HP_ONLY }, + { 0x4144, 0x5360, "AMD64 Motherboard", AC97_TUNE_HP_ONLY }, + { 0x1043, 0x80b0, "ASUS P4PE Mobo", AC97_TUNE_SWAP_SURROUND }, { } /* terminator */ }; @@ -1538,28 +1464,31 @@ { ac97_t ac97, *x97; ichdev_t *ichdev; - int err, i, num, channels = 2, codecs, _codecs; + int err; + unsigned int i, num, channels = 2, codecs, _codecs; unsigned int glob_sta = 0; + struct _ac97_rate_regs *tbl; - for (i = 0; i <= ICHD_LAST; i++) { - if (chip->device_type != DEVICE_ALI) { - struct _ac97_rate_regs *aregs; - aregs = &ac97_rate_regs[i]; - ichdev = &chip->ichd[aregs->ichd]; - ichdev->ac97_rate_regs[0] = aregs->regs[0]; - ichdev->ac97_rate_regs[1] = aregs->regs[1]; - ichdev->ac97_rate_regs[2] = aregs->regs[2]; - ichdev->ac97_rates_idx = aregs->rates_idx; - } else { - struct _ac97_ali_rate_regs *aregs; - aregs = &ac97_ali_rate_regs[i]; - ichdev = &chip->ichd[aregs->ichd]; - ichdev->ac97_rate_regs[0] = aregs->regs[0]; - ichdev->ac97_rate_regs[1] = aregs->regs[1]; - ichdev->ac97_rate_regs[2] = aregs->regs[2]; - ichdev->ac97_rates_idx = aregs->rates_idx; - } + switch (chip->device_type) { + case DEVICE_NFORCE: + tbl = nforce_ac97_rate_regs; + break; + case DEVICE_ALI: + tbl = ali_ac97_rate_regs; + break; + default: + tbl = intel_ac97_rate_regs; + break; + }; + for (i = 0; i < chip->bdbars_count; i++) { + struct _ac97_rate_regs *aregs = tbl + i; + ichdev = &chip->ichd[aregs->ichd]; + ichdev->ac97_rate_regs[0] = aregs->regs[0]; + ichdev->ac97_rate_regs[1] = aregs->regs[1]; + ichdev->ac97_rate_regs[2] = aregs->regs[2]; + ichdev->ac97_rates_idx = aregs->rates_idx; } + chip->in_ac97_init = 1; memset(&ac97, 0, sizeof(ac97)); ac97.private_data = chip; @@ -1616,15 +1545,24 @@ return err; chip->ac97[0] = x97; snd_ac97_tune_hardware(chip->ac97[0], ac97_quirks); + /* the following three entries are common among all devices */ chip->ichd[ICHD_PCMOUT].ac97 = x97; chip->ichd[ICHD_PCMIN].ac97 = x97; if (x97->ext_id & AC97_EI_VRM) chip->ichd[ICHD_MIC].ac97 = x97; + /* spdif */ if (x97->ext_id & AC97_EI_SPDIF) { - if (chip->device_type != DEVICE_ALI) + switch (chip->device_type) { + case DEVICE_INTEL_ICH4: chip->ichd[ICHD_SPBAR].ac97 = x97; - else + break; + case DEVICE_NFORCE: + chip->ichd[NVD_SPBAR].ac97 = x97; + break; + case DEVICE_ALI: chip->ichd[ALID_AC97SPDIFOUT].ac97 = x97; + break; + } } /* make sure, that we have DACs at right slot for rev2.2 */ if (ac97_is_rev22(x97)) @@ -1666,6 +1604,11 @@ if (chip->ichd[ICHD_MIC].ac97 == NULL) chip->ichd[ICHD_MIC].ac97 = x97; } + if ((x97->ext_id & AC97_EI_SPDIF) && + chip->device_type == DEVICE_NFORCE) { + if (chip->ichd[NVD_SPBAR].ac97 == NULL) + chip->ichd[NVD_SPBAR].ac97 = x97; + } break; } } @@ -1786,8 +1729,11 @@ /* put logic to right state */ /* first clear status bits */ + status = ICH_RCS | ICH_MCINT | ICH_POINT | ICH_PIINT; + if (chip->device_type == DEVICE_NFORCE) + status |= ICH_NVSPINT; cnt = igetdword(chip, ICHREG(GLOB_STA)); - iputdword(chip, ICHREG(GLOB_STA), cnt & (ICH_RCS | ICH_MCINT | ICH_POINT | ICH_PIINT)); + iputdword(chip, ICHREG(GLOB_STA), cnt & status); /* ACLink on, 2 channels */ cnt = igetdword(chip, ICHREG(GLOB_CNT)); @@ -1852,6 +1798,13 @@ /* unmute the output on SIS7012 */ iputword(chip, 0x4c, igetword(chip, 0x4c) | 1); } + if (chip->device_type == DEVICE_NFORCE) { + /* enable SPDIF interrupt */ + unsigned int val; + pci_read_config_dword(chip->pci, 0x4c, &val); + val |= 0x1000000; + pci_write_config_dword(chip->pci, 0x4c, val); + } return 0; } @@ -1927,6 +1880,13 @@ /* reset channels */ for (i = 0; i < chip->bdbars_count; i++) iputbyte(chip, ICH_REG_OFF_CR + chip->ichd[i].reg_offset, ICH_RESETREGS); + if (chip->device_type == DEVICE_NFORCE) { + /* stop the spdif interrupt */ + unsigned int val; + pci_read_config_dword(chip->pci, 0x4c, &val); + val &= ~0x1000000; + pci_write_config_dword(chip->pci, 0x4c, val); + } /* --- */ synchronize_irq(chip->irq); __hw_end: @@ -1957,15 +1917,15 @@ static void intel8x0_suspend(intel8x0_t *chip) { snd_card_t *card = chip->card; + int i; if (chip->in_suspend || card->power_state == SNDRV_CTL_POWER_D3hot) return; chip->in_suspend = 1; - snd_pcm_suspend_all(chip->pcm); - if (chip->pcm_mic) - snd_pcm_suspend_all(chip->pcm_mic); + for (i = 0; i < chip->pcm_devs; i++) + snd_pcm_suspend_all(chip->pcm[i]); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); } @@ -2050,7 +2010,7 @@ if (chip->ac97[0]->clock != 48000) return; /* specified in module option */ - subs = chip->pcm->streams[0].substream; + subs = chip->pcm[0]->streams[0].substream; if (! subs || subs->dma_buffer.bytes < INTEL8X0_TESTBUF_SIZE) { snd_printk("no playback buffer allocated - aborting measure ac97 clock\n"); return; @@ -2087,10 +2047,7 @@ spin_lock_irqsave(&chip->reg_lock, flags); /* check the position */ pos = ichdev->fragsize1; - if (chip->device_type == DEVICE_SIS) - pos -= igetword(chip, ichdev->reg_offset + ichdev->roff_picb); - else - pos -= igetword(chip, ichdev->reg_offset + ichdev->roff_picb) << 1; + pos -= igetword(chip, ichdev->reg_offset + ichdev->roff_picb) << chip->pcm_pos_shift; pos += ichdev->position; do_gettimeofday(&stop_time); /* stop */ @@ -2164,6 +2121,11 @@ return snd_intel8x0_free(chip); } +struct ich_reg_info { + unsigned int int_sta_mask; + unsigned int offset; +}; + static int __devinit snd_intel8x0_create(snd_card_t * card, struct pci_dev *pci, unsigned long device_type, @@ -2177,16 +2139,37 @@ static snd_device_ops_t ops = { .dev_free = snd_intel8x0_dev_free, }; - static u32 intel_int_sta_masks[6] = { - ICH_PIINT, ICH_POINT, ICH_MCINT, ICH_M2INT, ICH_P2INT, ICH_SPINT + + static unsigned int bdbars[] = { + 3, /* DEVICE_INTEL */ + 6, /* DEVICE_INTEL_ICH4 */ + 3, /* DEVICE_SIS */ + 6, /* DEVICE_ALI */ + 4, /* DEVICE_NFORCE */ + }; + static struct ich_reg_info intel_regs[6] = { + { ICH_PIINT, 0 }, + { ICH_POINT, 0x10 }, + { ICH_MCINT, 0x20 }, + { ICH_M2INT, 0x40 }, + { ICH_P2INT, 0x50 }, + { ICH_SPINT, 0x60 }, }; - static u32 ali_int_sta_masks[6] = { - ALI_INT_PCMIN, ALI_INT_PCMOUT, ALI_INT_MICIN, - ALI_INT_CODECSPDIFOUT, ALI_INT_SPDIFIN, ALI_INT_SPDIFOUT + static struct ich_reg_info nforce_regs[4] = { + { ICH_PIINT, 0 }, + { ICH_POINT, 0x10 }, + { ICH_MCINT, 0x20 }, + { ICH_NVSPINT, 0x70 }, }; - static u32 ali_reg_offsets[6] = { - 0x40, 0x50, 0x60, 0x70, 0xa0, 0xb0 + static struct ich_reg_info ali_regs[6] = { + { ALI_INT_PCMIN, 0x40 }, + { ALI_INT_PCMOUT, 0x50 }, + { ALI_INT_MICIN, 0x60 }, + { ALI_INT_CODECSPDIFOUT, 0x70 }, + { ALI_INT_SPDIFIN, 0xa0 }, + { ALI_INT_SPDIFOUT, 0xb0 }, }; + struct ich_reg_info *tbl; *r_intel8x0 = NULL; @@ -2205,25 +2188,36 @@ snd_intel8x0_proc_init(chip); sprintf(chip->ac97_name, "%s - AC'97", card->shortname); sprintf(chip->ctrl_name, "%s - Controller", card->shortname); + if (device_type == DEVICE_ALI) { + /* ALI5455 has no ac97 region */ + chip->bmaddr = pci_resource_start(pci, 0); + if ((chip->res_bm = request_region(chip->bmaddr, 256, chip->ctrl_name)) == NULL) { + snd_printk("unable to grab ports 0x%lx-0x%lx\n", chip->bmaddr, chip->bmaddr + 64 - 1); + snd_intel8x0_free(chip); + return -EBUSY; + } + goto port_inited; + } + if (pci_resource_flags(pci, 2) & IORESOURCE_MEM) { /* ICH4 and Nforce */ chip->mmio = 1; chip->addr = pci_resource_start(pci, 2); if ((chip->res = request_mem_region(chip->addr, 512, chip->ac97_name)) == NULL) { - snd_intel8x0_free(chip); snd_printk("unable to grab I/O memory 0x%lx-0x%lx\n", chip->addr, chip->addr + 512 - 1); + snd_intel8x0_free(chip); return -EBUSY; } chip->remap_addr = (unsigned long) ioremap_nocache(chip->addr, 512); if (chip->remap_addr == 0) { - snd_intel8x0_free(chip); snd_printk("AC'97 space ioremap problem\n"); + snd_intel8x0_free(chip); return -EIO; } } else { chip->addr = pci_resource_start(pci, 0); if ((chip->res = request_region(chip->addr, 256, chip->ac97_name)) == NULL) { - snd_intel8x0_free(chip); snd_printk("unable to grab ports 0x%lx-0x%lx\n", chip->addr, chip->addr + 256 - 1); + snd_intel8x0_free(chip); return -EBUSY; } } @@ -2231,63 +2225,69 @@ chip->bm_mmio = 1; chip->bmaddr = pci_resource_start(pci, 3); if ((chip->res_bm = request_mem_region(chip->bmaddr, 256, chip->ctrl_name)) == NULL) { - snd_intel8x0_free(chip); snd_printk("unable to grab I/O memory 0x%lx-0x%lx\n", chip->bmaddr, chip->bmaddr + 512 - 1); + snd_intel8x0_free(chip); return -EBUSY; } chip->remap_bmaddr = (unsigned long) ioremap_nocache(chip->bmaddr, 256); if (chip->remap_bmaddr == 0) { - snd_intel8x0_free(chip); snd_printk("Controller space ioremap problem\n"); + snd_intel8x0_free(chip); return -EIO; } } else { chip->bmaddr = pci_resource_start(pci, 1); if ((chip->res_bm = request_region(chip->bmaddr, 64, chip->ctrl_name)) == NULL) { - snd_intel8x0_free(chip); snd_printk("unable to grab ports 0x%lx-0x%lx\n", chip->bmaddr, chip->bmaddr + 64 - 1); + snd_intel8x0_free(chip); return -EBUSY; } } + + port_inited: if (request_irq(pci->irq, snd_intel8x0_interrupt, SA_INTERRUPT|SA_SHIRQ, card->shortname, (void *)chip)) { - snd_intel8x0_free(chip); snd_printk("unable to grab IRQ %d\n", pci->irq); + snd_intel8x0_free(chip); return -EBUSY; } chip->irq = pci->irq; pci_set_master(pci); synchronize_irq(chip->irq); + chip->bdbars_count = bdbars[device_type]; + /* initialize offsets */ - for (i = 0; i <= ICHD_LAST; i++) { + switch (device_type) { + case DEVICE_NFORCE: + tbl = nforce_regs; + break; + case DEVICE_ALI: + tbl = ali_regs; + break; + default: + tbl = intel_regs; + break; + } + for (i = 0; i < chip->bdbars_count; i++) { ichdev = &chip->ichd[i]; ichdev->ichd = i; - ichdev->reg_offset = i * 0x10 + (i >= 0x30 ? 0x10 : 0); - ichdev->roff_sr = ICH_REG_OFF_SR; - ichdev->roff_picb = ICH_REG_OFF_PICB; - ichdev->int_sta_mask = device_type == DEVICE_ALI ? ali_int_sta_masks[i] : intel_int_sta_masks[i]; - } - switch (device_type) { - case DEVICE_SIS: - for (i = 0; i <= ICHD_LAST; i++) { - ichdev = &chip->ichd[i]; + ichdev->reg_offset = tbl[i].offset; + ichdev->int_sta_mask = tbl[i].int_sta_mask; + if (device_type == DEVICE_SIS) { + /* SiS 7012 swaps the registers */ ichdev->roff_sr = ICH_REG_OFF_PICB; ichdev->roff_picb = ICH_REG_OFF_SR; + } else { + ichdev->roff_sr = ICH_REG_OFF_SR; + ichdev->roff_picb = ICH_REG_OFF_PICB; } - break; - case DEVICE_ALI: - for (i = 0; i <= ALID_LAST; i++) { - ichdev = &chip->ichd[i]; - ichdev->reg_offset = ali_reg_offsets[i]; - ichdev->ali_slot = i + 1; /* is this right for last three devices? --jk */ - } + ichdev->ali_slot = i + 1; /* is this right for last three devices? --jk */ } + /* SIS7012 handles the pcm data in bytes, others are in words */ + chip->pcm_pos_shift = (device_type == DEVICE_SIS) ? 0 : 1; /* allocate buffer descriptor lists */ /* the start of each lists must be aligned to 8 bytes */ - chip->bdbars_count = 3; - if (device_type == DEVICE_INTEL_ICH4 || device_type == DEVICE_ALI) - chip->bdbars_count = 6; chip->bdbars = (u32 *)snd_malloc_pci_pages(pci, chip->bdbars_count * sizeof(u32) * ICH_MAX_FRAGS * 2, &chip->bdbars_addr); if (chip->bdbars == NULL) { snd_intel8x0_free(chip); @@ -2295,14 +2295,6 @@ } /* tables must be aligned to 8 bytes here, but the kernel pages are much bigger, so we don't care (on i386) */ -#ifndef __i386__ - /* .. not sure on other architectures, so we check now. */ - if (chip->bdbars_addr & ~((dma_addr_t)0xffffffff | 0x07)) { - snd_printk("invalid i/o port address %lx\n", (unsigned long)chip->bdbars_addr); - snd_intel8x0_free(chip); - return -ENOMEM; - } -#endif int_sta_masks = 0; for (i = 0; i < chip->bdbars_count; i++) { ichdev = &chip->ichd[i]; @@ -2344,9 +2336,9 @@ { PCI_DEVICE_ID_INTEL_ICH4, "Intel 82801DB-ICH4" }, { PCI_DEVICE_ID_INTEL_ICH5, "Intel ICH5" }, { PCI_DEVICE_ID_SI_7012, "SiS SI7012" }, - { PCI_DEVICE_ID_NVIDIA_MCP_AUDIO, "NVidia NForce" }, - { PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO, "NVidia NForce2" }, - { PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO, "NVidia NForce3" }, + { PCI_DEVICE_ID_NVIDIA_MCP_AUDIO, "NVidia nForce" }, + { PCI_DEVICE_ID_NVIDIA_MCP2_AUDIO, "NVidia nForce2" }, + { PCI_DEVICE_ID_NVIDIA_MCP3_AUDIO, "NVidia nForce3" }, { 0x746d, "AMD AMD8111" }, { 0x7445, "AMD AMD768" }, { 0x5455, "ALi M5455" }, @@ -2359,7 +2351,7 @@ static int dev; snd_card_t *card; intel8x0_t *chip; - int pcm_dev = 0, err; + int err; struct shortname_table *name; if (dev >= SNDRV_CARDS) @@ -2373,7 +2365,15 @@ if (card == NULL) return -ENOMEM; - strcpy(card->driver, "ICH"); + switch (pci_id->driver_data) { + case DEVICE_NFORCE: + strcpy(card->driver, "NFORCE"); + break; + default: + strcpy(card->driver, "ICH"); + break; + } + strcpy(card->shortname, "Intel ICH"); for (name = shortnames; name->id; name++) { if (pci->device == name->id) { @@ -2391,53 +2391,10 @@ snd_card_free(card); return err; } - if ((err = snd_intel8x0_pcm(chip, pcm_dev++, NULL)) < 0) { + if ((err = snd_intel8x0_pcm(chip)) < 0) { snd_card_free(card); return err; } - /* activate MIC PCM only when associated AC'97 codec */ - if (chip->ichd[ICHD_MIC].ac97) { - if ((err = snd_intel8x0_pcm_mic(chip, pcm_dev++, NULL)) < 0) { - snd_card_free(card); - return err; - } - } - if (chip->device_type == DEVICE_ALI) { - if ((err = snd_intel8x0_ali_spdif(chip, pcm_dev++, NULL)) < 0) { - snd_card_free(card); - return err; - } - } - /* activate AC'97 S/PDIF only when associated AC'97 codec */ - if (chip->bdbars_count > 3) { - err = 0; - if (chip->device_type == DEVICE_ALI) { - if (chip->ichd[ALID_AC97SPDIFOUT].ac97) - err = snd_intel8x0_ali_ac97spdif(chip, pcm_dev++, NULL); - } else { - if (chip->ichd[ICHD_SPBAR].ac97) - err = snd_intel8x0_pcm_spdif(chip, pcm_dev++, NULL); - } - if (err < 0) { - snd_card_free(card); - return err; - } - if (chip->device_type != DEVICE_ALI) { - /* activate MIC2 only when associated AC'97 codec */ - if (chip->ichd[ICHD_MIC2].ac97) - if ((err = snd_intel8x0_pcm_mic2(chip, pcm_dev++, NULL)) < 0) { - snd_card_free(card); - return err; - } - /* activate PCM2IN only when associated AC'97 codec */ - if (chip->ichd[ICHD_PCM2IN].ac97) - if ((err = snd_intel8x0_pcm_capture2(chip, pcm_dev++, NULL)) < 0) { - snd_card_free(card); - return err; - } - } - } - if (mpu_port[dev] == 0x300 || mpu_port[dev] == 0x330) { if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_INTEL8X0, diff -Nru a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c --- a/sound/pci/korg1212/korg1212.c Mon Jun 9 23:16:05 2003 +++ b/sound/pci/korg1212/korg1212.c Mon Jun 9 23:16:05 2003 @@ -1136,8 +1136,7 @@ static irqreturn_t snd_korg1212_interrupt(int irq, void *dev_id, struct pt_regs *regs) { u32 doorbellValue; - korg1212_t *korg1212 = snd_magic_cast(korg1212_t, dev_id, - return IRQ_NONE); + korg1212_t *korg1212 = snd_magic_cast(korg1212_t, dev_id, return IRQ_NONE); if(irq != korg1212->irq) return IRQ_NONE; diff -Nru a/sound/pci/maestro3.c b/sound/pci/maestro3.c --- a/sound/pci/maestro3.c Mon Jun 9 23:16:14 2003 +++ b/sound/pci/maestro3.c Mon Jun 9 23:16:14 2003 @@ -947,8 +947,14 @@ .amp_gpio = -1, .irda_workaround = 1, }, - /* FIXME: Inspiron 8100 id should probably be here, too - * (8200 irrelevant: has intel8x0 with CS4205) */ + /* Dell Inspiron 8100 */ + { + .name = "Dell Inspiron 8100", + .vendor = 0x1028, + .device = 0x00e6, + .amp_gpio = -1, + .irda_workaround = 1, + }, /* NEC LM800J/7 */ { .name = "NEC LM800J/7", @@ -1968,7 +1974,7 @@ #endif } -static int snd_m3_mixer(m3_t *chip) +static int __devinit snd_m3_mixer(m3_t *chip) { ac97_t ac97; int err; @@ -1994,7 +2000,7 @@ * DSP Code images */ -static u16 assp_kernel_image[] = { +static u16 assp_kernel_image[] __devinitdata = { 0x7980, 0x0030, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x00FB, 0x7980, 0x00DD, 0x7980, 0x03B4, 0x7980, 0x0332, 0x7980, 0x0287, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x031A, 0x7980, 0x03B4, 0x7980, 0x022F, 0x7980, 0x03B4, 0x7980, 0x03B4, 0x7980, 0x03B4, @@ -2081,7 +2087,7 @@ * Mini sample rate converter code image * that is to be loaded at 0x400 on the DSP. */ -static u16 assp_minisrc_image[] = { +static u16 assp_minisrc_image[] __devinitdata = { 0xBF80, 0x101E, 0x906E, 0x006E, 0x8B88, 0x6980, 0xEF88, 0x906F, 0x0D6F, 0x6900, 0xEB08, 0x0412, 0xBC20, 0x696E, 0xB801, 0x906E, 0x7980, 0x0403, 0xB90E, 0x8807, 0xBE43, 0xBF01, 0xBE47, 0xBE41, @@ -2124,12 +2130,12 @@ */ #define MINISRC_LPF_LEN 10 -static u16 minisrc_lpf[MINISRC_LPF_LEN] = { +static u16 minisrc_lpf[MINISRC_LPF_LEN] __devinitdata = { 0X0743, 0X1104, 0X0A4C, 0XF88D, 0X242C, 0X1023, 0X1AA9, 0X0B60, 0XEFDD, 0X186F }; -static void snd_m3_assp_init(m3_t *chip) +static void __devinit snd_m3_assp_init(m3_t *chip) { unsigned int i; @@ -2218,7 +2224,7 @@ } -static int snd_m3_assp_client_init(m3_t *chip, m3_dma_t *s, int index) +static int __devinit snd_m3_assp_client_init(m3_t *chip, m3_dma_t *s, int index) { int data_bytes = 2 * ( MINISRC_TMP_BUFFER_SIZE / 2 + MINISRC_IN_BUFFER_SIZE / 2 + @@ -2387,6 +2393,8 @@ snd_card_t *card = chip->card; int i, index; + if (chip->suspend_mem == NULL) + return; if (card->power_state == SNDRV_CTL_POWER_D3hot) return; @@ -2416,6 +2424,8 @@ snd_card_t *card = chip->card; int i, index; + if (chip->suspend_mem == NULL) + return; if (card->power_state == SNDRV_CTL_POWER_D0) return; @@ -2585,8 +2595,8 @@ chip->iobase = pci_resource_start(pci, 0); if ((chip->iobase_res = request_region(chip->iobase, 256, card->driver)) == NULL) { - snd_m3_free(chip); snd_printk("unable to grab i/o ports %ld\n", chip->iobase); + snd_m3_free(chip); return -EBUSY; } @@ -2598,14 +2608,14 @@ snd_m3_ac97_reset(chip, 0); + snd_m3_assp_init(chip); + snd_m3_amp_enable(chip, 1); + if ((err = snd_m3_mixer(chip)) < 0) { snd_m3_free(chip); return err; } - snd_m3_assp_init(chip); - snd_m3_amp_enable(chip, 1); - for (i = 0; i < chip->num_substreams; i++) { m3_dma_t *s = &chip->substreams[i]; s->chip = chip; @@ -2622,8 +2632,8 @@ if (request_irq(pci->irq, snd_m3_interrupt, SA_INTERRUPT|SA_SHIRQ, card->driver, (void *)chip)) { - snd_m3_free(chip); snd_printk("unable to grab IRQ %d\n", pci->irq); + snd_m3_free(chip); return -ENOMEM; } chip->irq = pci->irq; @@ -2632,8 +2642,10 @@ chip->suspend_mem = vmalloc(sizeof(u16) * (REV_B_CODE_MEMORY_LENGTH + REV_B_DATA_MEMORY_LENGTH)); if (chip->suspend_mem == NULL) snd_printk("can't allocate apm buffer\n"); - card->set_power_state = snd_m3_set_power_state; - card->power_state_private_data = chip; + else { + card->set_power_state = snd_m3_set_power_state; + card->power_state_private_data = chip; + } #endif if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { diff -Nru a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c --- a/sound/pci/nm256/nm256.c Mon Jun 9 23:16:17 2003 +++ b/sound/pci/nm256/nm256.c Mon Jun 9 23:16:17 2003 @@ -230,8 +230,9 @@ u32 all_coeff_buf; /* coefficient buffer */ u32 coeff_buf[2]; /* coefficient buffer for each stream */ - int coeffs_current; /* coeff. table is loaded? */ - int use_cache; /* use one big coef. table */ + unsigned int coeffs_current: 1; /* coeff. table is loaded? */ + unsigned int use_cache: 1; /* use one big coef. table */ + unsigned int latitude_workaround: 1; /* Dell Latitude LS workaround needed */ int mixer_base; /* register offset of ac97 mixer */ int mixer_status_offset; /* offset of mixer status reg. */ @@ -1042,7 +1043,7 @@ static irqreturn_t snd_nm256_interrupt_zx(int irq, void *dev_id, struct pt_regs *dummy) { - nm256_t *chip = snd_magic_cast(nm256_t, dev_id, return); + nm256_t *chip = snd_magic_cast(nm256_t, dev_id, return IRQ_NONE); u32 status; u8 cbyte; @@ -1181,9 +1182,10 @@ spin_lock_irqsave(&chip->reg_lock, flags); /* Reset the mixer. 'Tis magic! */ snd_nm256_writeb(chip, 0x6c0, 1); -#if 0 /* Dell latitude LS will lock up by this */ - snd_nm256_writeb(chip, 0x6cc, 0x87); -#endif + if (chip->latitude_workaround) { + /* Dell latitude LS will lock up by this */ + snd_nm256_writeb(chip, 0x6cc, 0x87); + } snd_nm256_writeb(chip, 0x6cc, 0x80); snd_nm256_writeb(chip, 0x6cc, 0x0); spin_unlock_irqrestore(&chip->reg_lock, flags); @@ -1194,7 +1196,7 @@ snd_nm256_mixer(nm256_t *chip) { ac97_t ac97; - int i; + int i, err; /* looks like nm256 hangs up when unexpected registers are touched... */ static int mixer_regs[] = { AC97_MASTER, AC97_HEADPHONE, AC97_MASTER_MONO, @@ -1210,11 +1212,19 @@ ac97.reset = snd_nm256_ac97_reset; ac97.write = snd_nm256_ac97_write; ac97.read = snd_nm256_ac97_read; + ac97.scaps = AC97_SCAP_AUDIO; /* we support audio! */ ac97.limited_regs = 1; for (i = 0; mixer_regs[i] >= 0; i++) set_bit(mixer_regs[i], ac97.reg_accessed); ac97.private_data = chip; - return snd_ac97_mixer(chip->card, &ac97, &chip->ac97); + err = snd_ac97_mixer(chip->card, &ac97, &chip->ac97); + if (err < 0) + return err; + if (! (chip->ac97->id & (0xf0000000))) { + /* looks like an invalid id */ + sprintf(chip->card->mixername, "%s AC97", chip->card->driver); + } + return 0; } /* @@ -1394,6 +1404,7 @@ .dev_free = snd_nm256_dev_free, }; u32 addr; + u16 subsystem_vendor, subsystem_device; *chip_ret = NULL; @@ -1529,6 +1540,15 @@ chip->mixer_base = NM_MIXER_OFFSET; chip->coeffs_current = 0; + + /* check workarounds */ + chip->latitude_workaround = 1; + pci_read_config_word(pci, PCI_SUBSYSTEM_VENDOR_ID, &subsystem_vendor); + pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &subsystem_device); + if (subsystem_vendor == 0x104d && subsystem_device == 0x8041) { + /* this workaround will cause lock-up after suspend/resume on Sony PCG-F305 */ + chip->latitude_workaround = 0; + } snd_nm256_init_chip(chip); diff -Nru a/sound/pci/rme9652/hammerfall_mem.c b/sound/pci/rme9652/hammerfall_mem.c --- a/sound/pci/rme9652/hammerfall_mem.c Mon Jun 9 23:16:07 2003 +++ b/sound/pci/rme9652/hammerfall_mem.c Mon Jun 9 23:16:07 2003 @@ -25,7 +25,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - $Id: hammerfall_mem.c,v 1.8 2003/02/25 13:35:44 perex Exp $ + $Id: hammerfall_mem.c,v 1.9 2003/05/31 11:33:57 perex Exp $ Tue Oct 17 2000 Jaroslav Kysela <perex@suse.cz> @@ -98,15 +98,7 @@ { void *res; -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 3, 0) res = (void *) pci_alloc_consistent(pci, size, dmaaddr); -#else - int pg; - for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++); - res = (void *)__get_free_pages(GFP_KERNEL, pg); - if (res != NULL) - *dmaaddr = virt_to_bus(res); -#endif if (res != NULL) { struct page *page = virt_to_page(res); struct page *last_page = page + (size + PAGE_SIZE - 1) / PAGE_SIZE; @@ -127,19 +119,7 @@ last_page = virt_to_page(ptr) + (size + PAGE_SIZE - 1) / PAGE_SIZE; while (page < last_page) clear_bit(PG_reserved, &(page++)->flags); -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 3, 0) pci_free_consistent(pci, size, ptr, dmaaddr); -#else - { - int pg; - for (pg = 0; PAGE_SIZE * (1 << pg) < size; pg++); - if (bus_to_virt(dmaaddr) != ptr) { - printk(KERN_ERR "hammerfall_free_pages: dmaaddr != ptr\n"); - return; - } - free_pages((unsigned long)ptr, pg); - } -#endif } void *snd_hammerfall_get_buffer (struct pci_dev *pcidev, dma_addr_t *dmaaddr) @@ -205,7 +185,7 @@ static int __init alsa_hammerfall_mem_init(void) { int i; - struct pci_dev *pci; + struct pci_dev *pci = NULL; hammerfall_buf_t *rbuf; /* make sure our buffer records are clean */ @@ -225,12 +205,12 @@ i = 0; /* card number */ rbuf = hammerfall_buffers; - pci_for_each_dev(pci) { + while ((pci = pci_find_device(PCI_VENDOR_ID_XILINX, PCI_ANY_ID, pci)) != NULL) { int k; /* check for Hammerfall and Hammerfall DSP cards */ - if (pci->vendor != 0x10ee || (pci->device != 0x3fc4 && pci->device != 0x3fc5)) + if (pci->device != 0x3fc4 && pci->device != 0x3fc5) continue; if (!enable[i]) diff -Nru a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c --- a/sound/pci/rme9652/hdsp.c Mon Jun 9 23:16:09 2003 +++ b/sound/pci/rme9652/hdsp.c Mon Jun 9 23:16:09 2003 @@ -3211,15 +3211,16 @@ else runtime->status->hw_ptr = 0; if (other) { - snd_pcm_substream_t *s = substream; + struct list_head *pos; + snd_pcm_substream_t *s; snd_pcm_runtime_t *oruntime = other->runtime; - do { - s = s->link_next; + snd_pcm_group_for_each(pos, substream) { + s = snd_pcm_group_substream_entry(pos); if (s == other) { oruntime->status->hw_ptr = runtime->status->hw_ptr; break; } - } while (s != substream); + } } return 0; } @@ -3382,9 +3383,10 @@ other = hdsp->playback_substream; if (other) { - snd_pcm_substream_t *s = substream; - do { - s = s->link_next; + struct list_head *pos; + snd_pcm_substream_t *s; + snd_pcm_group_for_each(pos, substream) { + s = snd_pcm_group_substream_entry(pos); if (s == other) { snd_pcm_trigger_done(s, substream); if (cmd == SNDRV_PCM_TRIGGER_START) @@ -3393,7 +3395,7 @@ running &= ~(1 << s->stream); goto _ok; } - } while (s != substream); + } if (cmd == SNDRV_PCM_TRIGGER_START) { if (!(running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) && substream->stream == SNDRV_PCM_STREAM_CAPTURE) @@ -3526,7 +3528,7 @@ snd_interval_t t = { .min = hdsp->ds_channels, .max = hdsp->ds_channels, - integer: 1, + .integer = 1, }; return snd_interval_refine(c, &t); } else if (r->max < 64000) { @@ -3550,7 +3552,7 @@ snd_interval_t t = { .min = 32000, .max = 48000, - integer: 1, + .integer = 1, }; return snd_interval_refine(r, &t); } else if (c->max <= hdsp->ds_channels) { diff -Nru a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c --- a/sound/pci/rme9652/rme9652.c Mon Jun 9 23:16:11 2003 +++ b/sound/pci/rme9652/rme9652.c Mon Jun 9 23:16:11 2003 @@ -2057,15 +2057,16 @@ else runtime->status->hw_ptr = 0; if (other) { - snd_pcm_substream_t *s = substream; + struct list_head *pos; + snd_pcm_substream_t *s; snd_pcm_runtime_t *oruntime = other->runtime; - do { - s = s->link_next; + snd_pcm_group_for_each(pos, substream) { + s = snd_pcm_group_substream_entry(pos); if (s == other) { oruntime->status->hw_ptr = runtime->status->hw_ptr; break; } - } while (s != substream); + } } return 0; } @@ -2204,9 +2205,10 @@ other = rme9652->playback_substream; if (other) { - snd_pcm_substream_t *s = substream; - do { - s = s->link_next; + struct list_head *pos; + snd_pcm_substream_t *s; + snd_pcm_group_for_each(pos, substream) { + s = snd_pcm_group_substream_entry(pos); if (s == other) { snd_pcm_trigger_done(s, substream); if (cmd == SNDRV_PCM_TRIGGER_START) @@ -2215,7 +2217,7 @@ running &= ~(1 << s->stream); goto _ok; } - } while (s != substream); + } if (cmd == SNDRV_PCM_TRIGGER_START) { if (!(running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) && substream->stream == SNDRV_PCM_STREAM_CAPTURE) diff -Nru a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c --- a/sound/pci/sonicvibes.c Mon Jun 9 23:16:15 2003 +++ b/sound/pci/sonicvibes.c Mon Jun 9 23:16:15 2003 @@ -598,8 +598,7 @@ static irqreturn_t snd_sonicvibes_interrupt(int irq, void *dev_id, struct pt_regs *regs) { - sonicvibes_t *sonic = snd_magic_cast(sonicvibes_t, dev_id, - return IRQ_NONE); + sonicvibes_t *sonic = snd_magic_cast(sonicvibes_t, dev_id, return IRQ_NONE); unsigned char status; status = inb(SV_REG(sonic, STATUS)); @@ -655,7 +654,6 @@ snd_ctl_notify(sonic->card, SNDRV_CTL_EVENT_MASK_VALUE, &sonic->master_mute->id); snd_ctl_notify(sonic->card, SNDRV_CTL_EVENT_MASK_VALUE, &sonic->master_volume->id); } - return IRQ_HANDLED; } diff -Nru a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c --- a/sound/pci/trident/trident_main.c Mon Jun 9 23:16:15 2003 +++ b/sound/pci/trident/trident_main.c Mon Jun 9 23:16:15 2003 @@ -1502,6 +1502,7 @@ { trident_t *trident = snd_pcm_substream_chip(substream); + struct list_head *pos; snd_pcm_substream_t *s; unsigned int what, whati, capture_flag, spdif_flag; snd_trident_voice_t *voice, *evoice; @@ -1522,10 +1523,10 @@ return -EINVAL; } what = whati = capture_flag = spdif_flag = 0; - s = substream; spin_lock(&trident->reg_lock); val = inl(TRID_REG(trident, T4D_STIMER)) & 0x00ffffff; - do { + snd_pcm_group_for_each(pos, substream) { + s = snd_pcm_group_substream_entry(pos); if ((trident_t *) _snd_pcm_chip(s->pcm) == trident) { voice = (snd_trident_voice_t *) s->runtime->private_data; evoice = voice->extra; @@ -1550,8 +1551,7 @@ if (voice->spdif) spdif_flag = 1; } - s = s->link_next; - } while (s != substream); + } if (spdif_flag) { if (trident->device != TRIDENT_DEVICE_ID_SI7018) { outl(trident->spdif_pcm_bits, TRID_REG(trident, NX_SPCSTATUS)); @@ -3683,7 +3683,7 @@ the method try & fail so it is possible that it won't work on all computers. [jaroslav] - Returns: Whether IRQ was handled or not. + Returns: None. ---------------------------------------------------------------------------*/ @@ -3781,7 +3781,6 @@ } } // outl((ST_TARGET_REACHED | MIXER_OVERFLOW | MIXER_UNDERFLOW), TRID_REG(trident, T4D_MISCINT)); - return IRQ_HANDLED; } diff -Nru a/sound/pci/trident/trident_synth.c b/sound/pci/trident/trident_synth.c --- a/sound/pci/trident/trident_synth.c Mon Jun 9 23:16:10 2003 +++ b/sound/pci/trident/trident_synth.c Mon Jun 9 23:16:10 2003 @@ -904,9 +904,6 @@ p->chset->port = snd_seq_event_port_attach(trident->synth.seq_client, &callbacks, SNDRV_SEQ_PORT_CAP_WRITE | SNDRV_SEQ_PORT_CAP_SUBS_WRITE, - SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | - SNDRV_SEQ_PORT_TYPE_MIDI_GM | - SNDRV_SEQ_PORT_TYPE_MIDI_GS | SNDRV_SEQ_PORT_TYPE_DIRECT_SAMPLE | SNDRV_SEQ_PORT_TYPE_SYNTH, 16, 0, diff -Nru a/sound/pci/via82xx.c b/sound/pci/via82xx.c --- a/sound/pci/via82xx.c Mon Jun 9 23:16:17 2003 +++ b/sound/pci/via82xx.c Mon Jun 9 23:16:17 2003 @@ -74,6 +74,7 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ static long mpu_port[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = -1}; static int ac97_clock[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 48000}; +static int dxs_support[SNDRV_CARDS]; MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(index, "Index value for VIA 82xx bridge."); @@ -90,6 +91,9 @@ MODULE_PARM(ac97_clock, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(ac97_clock, "AC'97 codec clock (default 48000Hz)."); MODULE_PARM_SYNTAX(ac97_clock, SNDRV_ENABLED ",default:48000"); +MODULE_PARM(dxs_support, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(dxs_support, "Support for DXS channels (0 = auto, 1 = enable, 2 = disable, 3 = 48k only)"); +MODULE_PARM_SYNTAX(dxs_support, SNDRV_ENABLED ",allows:{{0,3}},dialog:list"); /* pci ids */ @@ -435,6 +439,7 @@ unsigned int playback_devno, multi_devno, capture_devno; viadev_t devs[VIA_MAX_DEVS]; struct via_rate_lock rates[2]; /* playback and capture */ + unsigned int dxs_fixed: 1; /* DXS channel accepts only 48kHz */ snd_rawmidi_t *rmidi; @@ -559,6 +564,7 @@ { outb(VIA_REG_CTRL_PAUSE | VIA_REG_CTRL_TERMINATE | VIA_REG_CTRL_RESET, VIADEV_REG(viadev, OFFSET_CONTROL)); + inb(VIADEV_REG(viadev, OFFSET_CONTROL)); udelay(50); /* disable interrupts */ outb(0x00, VIADEV_REG(viadev, OFFSET_CONTROL)); @@ -876,6 +882,8 @@ return rate_changed; if (rate_changed) { snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate); + snd_ac97_set_rate(chip->ac97, AC97_PCM_SURR_DAC_RATE, runtime->rate); + snd_ac97_set_rate(chip->ac97, AC97_PCM_LFE_DAC_RATE, runtime->rate); snd_ac97_set_rate(chip->ac97, AC97_SPDIF, runtime->rate); } if (chip->chip_type == TYPE_VIA8233A) @@ -1000,6 +1008,19 @@ int err; unsigned long flags; struct via_rate_lock *ratep; + struct ratetbl { + int rate; + unsigned int bit; + } ratebits[] = { + {8000, SNDRV_PCM_RATE_8000}, + {11025, SNDRV_PCM_RATE_11025}, + {16000, SNDRV_PCM_RATE_16000}, + {22050, SNDRV_PCM_RATE_22050}, + {32000, SNDRV_PCM_RATE_32000}, + {44100, SNDRV_PCM_RATE_44100}, + {48000, SNDRV_PCM_RATE_48000}, + }; + int i; runtime->hw = snd_via82xx_hw; @@ -1007,14 +1028,33 @@ ratep = &chip->rates[viadev->direction]; spin_lock_irqsave(&ratep->lock, flags); ratep->used++; - if (! ratep->rate) { + if (chip->dxs_fixed) { + runtime->hw.rates = SNDRV_PCM_RATE_48000; + runtime->hw.rate_min = runtime->hw.rate_max = 48000; + } else if (! ratep->rate) { int idx = viadev->direction ? AC97_RATES_ADC : AC97_RATES_FRONT_DAC; runtime->hw.rates = chip->ac97->rates[idx]; - if (runtime->hw.rates & SNDRV_PCM_RATE_8000) - runtime->hw.rate_min = 8000; + for (i = 0; i < (int)ARRAY_SIZE(ratebits); i++) { + if (runtime->hw.rates & ratebits[i].bit) { + runtime->hw.rate_min = ratebits[i].rate; + break; + } + } + for (i = ARRAY_SIZE(ratebits) - 1; i >= 0; i--) { + if (runtime->hw.rates & ratebits[i].bit) { + runtime->hw.rate_max = ratebits[i].rate; + break; + } + } } else { /* a fixed rate */ runtime->hw.rates = SNDRV_PCM_RATE_KNOT; + for (i = 0; i < (int)ARRAY_SIZE(ratebits); i++) { + if (ratep->rate == ratebits[i].rate) { + runtime->hw.rates = ratebits[i].bit; + break; + } + } runtime->hw.rate_max = runtime->hw.rate_min = ratep->rate; } spin_unlock_irqrestore(&ratep->lock, flags); @@ -1038,8 +1078,11 @@ { via82xx_t *chip = snd_pcm_substream_chip(substream); viadev_t *viadev = &chip->devs[chip->playback_devno + substream->number]; + int err; - return snd_via82xx_pcm_open(chip, viadev, substream); + if ((err = snd_via82xx_pcm_open(chip, viadev, substream)) < 0) + return err; + return 0; } /* @@ -1639,6 +1682,28 @@ /* + * proc interface + */ +static void snd_via82xx_proc_read(snd_info_entry_t *entry, snd_info_buffer_t *buffer) +{ + via82xx_t *chip = snd_magic_cast(via82xx_t, entry->private_data, return); + int i; + + snd_iprintf(buffer, "%s\n\n", chip->card->longname); + for (i = 0; i < 0xa0; i += 4) { + snd_iprintf(buffer, "%02x: %08x", i, inl(chip->port + i)); + } +} + +static void __devinit snd_via82xx_proc_init(via82xx_t *chip) +{ + snd_info_entry_t *entry; + + if (! snd_card_proc_new(chip->card, "via82xx", &entry)) + snd_info_set_text_ops(entry, chip, snd_via82xx_proc_read); +} + +/* * */ @@ -1736,6 +1801,19 @@ outl(0, VIAREG(chip, GPI_INTR)); } + if (chip->chip_type != TYPE_VIA686) { + /* Workaround for Award BIOS bug: + * DXS channels don't work properly with VRA if MC97 is disabled. + */ + struct pci_dev *pci; + pci = pci_find_device(0x1106, 0x3068, NULL); /* MC97 */ + if (pci) { + unsigned char data; + pci_read_config_byte(pci, 0x44, &data); + pci_write_config_byte(pci, 0x44, data | 0x40); + } + } + return 0; } @@ -1816,7 +1894,7 @@ if (request_irq(pci->irq, snd_via82xx_interrupt, SA_INTERRUPT|SA_SHIRQ, card->driver, (void *)chip)) { snd_via82xx_free(chip); - snd_printk("unable to grab IRQ %d\n", chip->irq); + snd_printk("unable to grab IRQ %d\n", pci->irq); return -EBUSY; } chip->irq = pci->irq; @@ -1896,6 +1974,13 @@ break; } } + /* force to use VIA8233 or 8233A model according to + * dxs_support module option + */ + if (dxs_support[dev] == 1) + chip_type = TYPE_VIA8233; + else if (dxs_support[dev] == 2) + chip_type = TYPE_VIA8233A; if (chip_type == TYPE_VIA8233A) strcpy(card->driver, "VIA8233A"); else @@ -1909,7 +1994,6 @@ if ((err = snd_via82xx_create(card, pci, chip_type, revision, ac97_clock[dev], &chip)) < 0) goto __error; - if ((err = snd_via82xx_mixer_new(chip)) < 0) goto __error; @@ -1924,6 +2008,8 @@ } else { if ((err = snd_via8233_pcm_new(chip)) < 0) goto __error; + if (dxs_support[dev] == 3) + chip->dxs_fixed = 1; } if ((err = snd_via8233_init_misc(chip, dev)) < 0) goto __error; @@ -1934,6 +2020,8 @@ sprintf(card->longname, "%s at 0x%lx, irq %d", card->shortname, chip->port, chip->irq); + + snd_via82xx_proc_init(chip); if ((err = snd_card_register(card)) < 0) { snd_card_free(card); diff -Nru a/sound/pci/vx222/Makefile b/sound/pci/vx222/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/vx222/Makefile Mon Jun 9 23:16:20 2003 @@ -0,0 +1,8 @@ +# +# Makefile for ALSA +# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz> +# + +snd-vx222-objs := vx222.o vx222_ops.o + +obj-$(CONFIG_SND_VX222) += snd-vx222.o diff -Nru a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/vx222/vx222.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,311 @@ +/* + * Driver for Digigram VX222 V2/Mic PCI soundcards + * + * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <sound/driver.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/pci.h> +#include <linux/slab.h> +#include <sound/core.h> +#define SNDRV_GET_ID +#include <sound/initval.h> +#include "vx222.h" + +#define chip_t vx_core_t + +#define CARD_NAME "VX222" + +MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); +MODULE_DESCRIPTION("Digigram VX222 V2/Mic"); +MODULE_LICENSE("GPL"); +MODULE_CLASSES("{sound}"); +MODULE_DEVICES("{{Digigram," CARD_NAME "}}"); + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ +static int mic[SNDRV_CARDS]; /* microphone */ +static int ibl[SNDRV_CARDS]; /* microphone */ + +MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(index, "Index value for Digigram " CARD_NAME " soundcard."); +MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); +MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s"); +MODULE_PARM_DESC(id, "ID string for Digigram " CARD_NAME " soundcard."); +MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); +MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(enable, "Enable Digigram " CARD_NAME " soundcard."); +MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); +MODULE_PARM(mic, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(mic, "Enable Microphone."); +MODULE_PARM_SYNTAX(mic, SNDRV_ENABLED "," SNDRV_BOOLEAN_FALSE_DESC); +MODULE_PARM(ibl, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(ibl, "Capture IBL size."); +MODULE_PARM_SYNTAX(ibl, SNDRV_ENABLED); + +/* + */ + +enum { + VX_PCI_VX222_OLD, + VX_PCI_VX222_NEW +}; + +static struct pci_device_id snd_vx222_ids[] __devinitdata = { + { 0x10b5, 0x9050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VX_PCI_VX222_OLD, }, /* PLX */ + { 0x10b5, 0x9030, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VX_PCI_VX222_NEW, }, /* PLX */ + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, snd_vx222_ids); + + +/* + */ + +static struct snd_vx_hardware vx222_old_hw = { + + .name = "VX222/Old", + .type = VX_TYPE_BOARD, + /* hw specs */ + .num_codecs = 1, + .num_ins = 1, + .num_outs = 1, + .output_level_max = VX_ANALOG_OUT_LEVEL_MAX, +}; + +static struct snd_vx_hardware vx222_v2_hw = { + + .name = "VX222/v2", + .type = VX_TYPE_V2, + /* hw specs */ + .num_codecs = 1, + .num_ins = 1, + .num_outs = 1, + .output_level_max = VX2_AKM_LEVEL_MAX, +}; + +static struct snd_vx_hardware vx222_mic_hw = { + + .name = "VX222/Mic", + .type = VX_TYPE_MIC, + /* hw specs */ + .num_codecs = 1, + .num_ins = 1, + .num_outs = 1, + .output_level_max = VX2_AKM_LEVEL_MAX, +}; + + +/* + */ +static int snd_vx222_free(vx_core_t *chip) +{ + int i; + struct snd_vx222 *vx = (struct snd_vx222 *)chip; + + if (chip->irq >= 0) + free_irq(chip->irq, (void*)chip); + for (i = 0; i < 2; i++) { + if (vx->port_res[i]) { + release_resource(vx->port_res[i]); + kfree_nocheck(vx->port_res[i]); + } + } + snd_magic_kfree(chip); + return 0; +} + +static int snd_vx222_dev_free(snd_device_t *device) +{ + vx_core_t *chip = snd_magic_cast(vx_core_t, device->device_data, return -ENXIO); + return snd_vx222_free(chip); +} + + +static int __devinit snd_vx222_create(snd_card_t *card, struct pci_dev *pci, + struct snd_vx_hardware *hw, + struct snd_vx222 **rchip) +{ + vx_core_t *chip; + struct snd_vx222 *vx; + int i, err; + static snd_device_ops_t ops = { + .dev_free = snd_vx222_dev_free, + }; + struct snd_vx_ops *vx_ops; + + /* enable PCI device */ + if ((err = pci_enable_device(pci)) < 0) + return err; + pci_set_master(pci); + + vx_ops = hw->type == VX_TYPE_BOARD ? &vx222_old_ops : &vx222_ops; + chip = snd_vx_create(card, hw, vx_ops, + sizeof(struct snd_vx222) - sizeof(vx_core_t)); + if (! chip) + return -ENOMEM; + vx = (struct snd_vx222 *)chip; + + for (i = 0; i < 2; i++) { + if (!(pci_resource_flags(pci, i + 1) & IORESOURCE_IO)) { + snd_printk(KERN_ERR "invalid i/o resource %d\n", i + 1); + snd_vx222_free(chip); + return -ENOMEM; + } + vx->port[i] = pci_resource_start(pci, i + 1); + if ((vx->port_res[i] = request_region(vx->port[i], 0x60, + CARD_NAME)) == NULL) { + snd_printk(KERN_ERR "unable to grab port 0x%lx\n", vx->port[i]); + snd_vx222_free(chip); + return -EBUSY; + } + } + + if (request_irq(pci->irq, snd_vx_irq_handler, SA_INTERRUPT|SA_SHIRQ, + CARD_NAME, (void *) chip)) { + snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); + snd_vx222_free(chip); + return -EBUSY; + } + chip->irq = pci->irq; + + if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { + snd_vx222_free(chip); + return err; + } + + *rchip = vx; + return 0; +} + + +static int __devinit snd_vx222_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) +{ + static int dev; + snd_card_t *card; + struct snd_vx_hardware *hw; + struct snd_vx222 *vx; + int err; + + if (dev >= SNDRV_CARDS) + return -ENODEV; + if (!enable[dev]) { + dev++; + return -ENOENT; + } + + card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0); + if (card == NULL) + return -ENOMEM; + + switch ((int)pci_id->driver_data) { + case VX_PCI_VX222_OLD: + hw = &vx222_old_hw; + break; + case VX_PCI_VX222_NEW: + default: + if (mic[dev]) + hw = &vx222_mic_hw; + else + hw = &vx222_v2_hw; + break; + } + if ((err = snd_vx222_create(card, pci, hw, &vx)) < 0) { + snd_card_free(card); + return err; + } + vx->core.ibl.size = ibl[dev]; + + sprintf(card->longname, "%s at 0x%lx & 0x%lx, irq %i", + card->shortname, vx->port[0], vx->port[1], vx->core.irq); + snd_printdd("%s at 0x%lx & 0x%lx, irq %i\n", + card->shortname, vx->port[0], vx->port[1], vx->core.irq); + + if ((err = snd_vx_hwdep_new(&vx->core)) < 0) { + snd_card_free(card); + return err; + } + + if ((err = snd_card_register(card)) < 0) { + snd_card_free(card); + return err; + } + + pci_set_drvdata(pci, card); + dev++; + return 0; +} + +static void __devexit snd_vx222_remove(struct pci_dev *pci) +{ + snd_card_free(pci_get_drvdata(pci)); + pci_set_drvdata(pci, NULL); +} + +static struct pci_driver driver = { + .name = "Digigram VX222", + .id_table = snd_vx222_ids, + .probe = snd_vx222_probe, + .remove = __devexit_p(snd_vx222_remove), +}; + +static int __init alsa_card_vx222_init(void) +{ + int err; + + if ((err = pci_module_init(&driver)) < 0) { +#ifdef MODULE + printk(KERN_ERR "Digigram VX222 soundcard not found or device busy\n"); +#endif + return err; + } + return 0; +} + +static void __exit alsa_card_vx222_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_vx222_init) +module_exit(alsa_card_vx222_exit) + +#ifndef MODULE + +/* format is: snd-vx222=enable,index,id */ + +static int __init alsa_card_vx222_setup(char *str) +{ + static unsigned __initdata nr_dev = 0; + + if (nr_dev >= SNDRV_CARDS) + return 0; + (void)(get_option(&str,&enable[nr_dev]) == 2 && + get_option(&str,&index[nr_dev]) == 2 && + get_id(&str,&id[nr_dev]) == 2); + nr_dev++; + return 1; +} + +__setup("snd-vx222=", alsa_card_vx222_setup); + +#endif /* ifndef MODULE */ diff -Nru a/sound/pci/vx222/vx222.h b/sound/pci/vx222/vx222.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/vx222/vx222.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,114 @@ +/* + * Driver for Digigram VX222 PCI soundcards + * + * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __VX222_H +#define __VX222_H + +#include <sound/vx_core.h> + +struct snd_vx222 { + + vx_core_t core; + + /* h/w config; for PLX and for DSP */ + unsigned long port[2]; + struct resource *port_res[2]; + + unsigned int regCDSP; /* current CDSP register */ + unsigned int regCFG; /* current CFG register */ + unsigned int regSELMIC; /* current SELMIC reg. (for VX222 Mic) */ + + int input_level[2]; /* input level for vx222 mic */ + int mic_level; /* mic level for vx222 mic */ +}; + +/* we use a lookup table with 148 values, see vx_mixer.c */ +#define VX2_AKM_LEVEL_MAX 0x93 + +extern struct snd_vx_ops vx222_ops; +extern struct snd_vx_ops vx222_old_ops; + +/* Offset of registers with base equal to portDSP. */ +#define VX_RESET_DMA_REGISTER_OFFSET 0x00000008 + +/* Constants used to access the INTCSR register. */ +#define VX_INTCSR_VALUE 0x00000001 +#define VX_PCI_INTERRUPT_MASK 0x00000040 + +/* Constants used to access the CDSP register (0x20). */ +#define VX_CDSP_TEST1_MASK 0x00000080 +#define VX_CDSP_TOR1_MASK 0x00000040 +#define VX_CDSP_TOR2_MASK 0x00000020 +#define VX_CDSP_RESERVED0_0_MASK 0x00000010 +#define VX_CDSP_CODEC_RESET_MASK 0x00000008 +#define VX_CDSP_VALID_IRQ_MASK 0x00000004 +#define VX_CDSP_TEST0_MASK 0x00000002 +#define VX_CDSP_DSP_RESET_MASK 0x00000001 + +#define VX_CDSP_GPIO_OUT_MASK 0x00000060 +#define VX_GPIO_OUT_BIT_OFFSET 5 // transform output to bit 0 and 1 + +/* Constants used to access the CFG register (0x24). */ +#define VX_CFG_SYNCDSP_MASK 0x00000080 +#define VX_CFG_RESERVED0_0_MASK 0x00000040 +#define VX_CFG_RESERVED1_0_MASK 0x00000020 +#define VX_CFG_RESERVED2_0_MASK 0x00000010 +#define VX_CFG_DATAIN_SEL_MASK 0x00000008 // 0 (ana), 1 (UER) +#define VX_CFG_RESERVED3_0_MASK 0x00000004 +#define VX_CFG_RESERVED4_0_MASK 0x00000002 +#define VX_CFG_CLOCKIN_SEL_MASK 0x00000001 // 0 (internal), 1 (AES/EBU) + +/* Constants used to access the STATUS register (0x30). */ +#define VX_STATUS_DATA_XICOR_MASK 0x00000080 +#define VX_STATUS_VAL_TEST1_MASK 0x00000040 +#define VX_STATUS_VAL_TEST0_MASK 0x00000020 +#define VX_STATUS_RESERVED0_MASK 0x00000010 +#define VX_STATUS_VAL_TOR1_MASK 0x00000008 +#define VX_STATUS_VAL_TOR0_MASK 0x00000004 +#define VX_STATUS_LEVEL_IN_MASK 0x00000002 // 6 dBu (0), 22 dBu (1) +#define VX_STATUS_MEMIRQ_MASK 0x00000001 + +#define VX_STATUS_GPIO_IN_MASK 0x0000000C +#define VX_GPIO_IN_BIT_OFFSET 0 // leave input as bit 2 and 3 + +/* Constants used to access the MICRO INPUT SELECT register (0x40). */ +#define MICRO_SELECT_INPUT_NORM 0x00 +#define MICRO_SELECT_INPUT_MUTE 0x01 +#define MICRO_SELECT_INPUT_LIMIT 0x02 +#define MICRO_SELECT_INPUT_MASK 0x03 + +#define MICRO_SELECT_PREAMPLI_G_0 0x00 +#define MICRO_SELECT_PREAMPLI_G_1 0x04 +#define MICRO_SELECT_PREAMPLI_G_2 0x08 +#define MICRO_SELECT_PREAMPLI_G_3 0x0C +#define MICRO_SELECT_PREAMPLI_MASK 0x0C +#define MICRO_SELECT_PREAMPLI_OFFSET 2 + +#define MICRO_SELECT_RAISE_COMPR 0x10 + +#define MICRO_SELECT_NOISE_T_52DB 0x00 +#define MICRO_SELECT_NOISE_T_42DB 0x20 +#define MICRO_SELECT_NOISE_T_32DB 0x40 +#define MICRO_SELECT_NOISE_T_MASK 0x60 + +#define MICRO_SELECT_PHANTOM_ALIM 0x80 + + +#endif /* __VX222_H */ diff -Nru a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pci/vx222/vx222_ops.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,1011 @@ +/* + * Driver for Digigram VX222 V2/Mic soundcards + * + * VX222-specific low-level routines + * + * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <sound/driver.h> +#include <linux/delay.h> +#include <sound/core.h> +#include <sound/control.h> +#include <asm/io.h> +#include "vx222.h" + +#define chip_t vx_core_t + + +static int vx2_reg_offset[VX_REG_MAX] = { + [VX_ICR] = 0x00, + [VX_CVR] = 0x04, + [VX_ISR] = 0x08, + [VX_IVR] = 0x0c, + [VX_RXH] = 0x14, + [VX_RXM] = 0x18, + [VX_RXL] = 0x1c, + [VX_DMA] = 0x10, + [VX_CDSP] = 0x20, + [VX_CFG] = 0x24, + [VX_RUER] = 0x28, + [VX_DATA] = 0x2c, + [VX_STATUS] = 0x30, + [VX_LOFREQ] = 0x34, + [VX_HIFREQ] = 0x38, + [VX_CSUER] = 0x3c, + [VX_SELMIC] = 0x40, + [VX_COMPOT] = 0x44, // Write: POTENTIOMETER ; Read: COMPRESSION LEVEL activate + [VX_SCOMPR] = 0x48, // Read: COMPRESSION THRESHOLD activate + [VX_GLIMIT] = 0x4c, // Read: LEVEL LIMITATION activate + [VX_INTCSR] = 0x4c, // VX_INTCSR_REGISTER_OFFSET + [VX_CNTRL] = 0x50, // VX_CNTRL_REGISTER_OFFSET + [VX_GPIOC] = 0x54, // VX_GPIOC (new with PLX9030) +}; + +static int vx2_reg_index[VX_REG_MAX] = { + [VX_ICR] = 1, + [VX_CVR] = 1, + [VX_ISR] = 1, + [VX_IVR] = 1, + [VX_RXH] = 1, + [VX_RXM] = 1, + [VX_RXL] = 1, + [VX_DMA] = 1, + [VX_CDSP] = 1, + [VX_CFG] = 1, + [VX_RUER] = 1, + [VX_DATA] = 1, + [VX_STATUS] = 1, + [VX_LOFREQ] = 1, + [VX_HIFREQ] = 1, + [VX_CSUER] = 1, + [VX_SELMIC] = 1, + [VX_COMPOT] = 1, + [VX_SCOMPR] = 1, + [VX_GLIMIT] = 1, + [VX_INTCSR] = 0, /* on the PLX */ + [VX_CNTRL] = 0, /* on the PLX */ + [VX_GPIOC] = 0, /* on the PLX */ +}; + +inline static unsigned long vx2_reg_addr(vx_core_t *_chip, int reg) +{ + struct snd_vx222 *chip = (struct snd_vx222 *)_chip; + return chip->port[vx2_reg_index[reg]] + vx2_reg_offset[reg]; +} + +/** + * snd_vx_inb - read a byte from the register + * @offset: register enum + */ +static unsigned char vx2_inb(vx_core_t *chip, int offset) +{ + return inb(vx2_reg_addr(chip, offset)); +} + +/** + * snd_vx_outb - write a byte on the register + * @offset: the register offset + * @val: the value to write + */ +static void vx2_outb(vx_core_t *chip, int offset, unsigned char val) +{ + outb(val, vx2_reg_addr(chip, offset)); + //printk("outb: %x -> %x\n", val, vx2_reg_addr(chip, offset)); +} + +/** + * snd_vx_inl - read a 32bit word from the register + * @offset: register enum + */ +static unsigned int vx2_inl(vx_core_t *chip, int offset) +{ + return inl(vx2_reg_addr(chip, offset)); +} + +/** + * snd_vx_outl - write a 32bit word on the register + * @offset: the register enum + * @val: the value to write + */ +static void vx2_outl(vx_core_t *chip, int offset, unsigned int val) +{ + // printk("outl: %x -> %x\n", val, vx2_reg_addr(chip, offset)); + outl(val, vx2_reg_addr(chip, offset)); +} + +/* + * redefine macros to call directly + */ +#undef vx_inb +#define vx_inb(chip,reg) vx2_inb((vx_core_t*)(chip), VX_##reg) +#undef vx_outb +#define vx_outb(chip,reg,val) vx2_outb((vx_core_t*)(chip), VX_##reg, val) +#undef vx_inl +#define vx_inl(chip,reg) vx2_inl((vx_core_t*)(chip), VX_##reg) +#undef vx_outl +#define vx_outl(chip,reg,val) vx2_outl((vx_core_t*)(chip), VX_##reg, val) + + +/* + * vx_reset_dsp - reset the DSP + */ + +#define XX_DSP_RESET_WAIT_TIME 2 /* ms */ + +static void vx2_reset_dsp(vx_core_t *_chip) +{ + struct snd_vx222 *chip = (struct snd_vx222 *)_chip; + + /* set the reset dsp bit to 0 */ + vx_outl(chip, CDSP, chip->regCDSP & ~VX_CDSP_DSP_RESET_MASK); + + snd_vx_delay(_chip, XX_DSP_RESET_WAIT_TIME); + + chip->regCDSP |= VX_CDSP_DSP_RESET_MASK; + /* set the reset dsp bit to 1 */ + vx_outl(chip, CDSP, chip->regCDSP); +} + + +static int vx2_test_xilinx(vx_core_t *_chip) +{ + struct snd_vx222 *chip = (struct snd_vx222 *)_chip; + unsigned int data; + + snd_printdd("testing xilinx...\n"); + /* This test uses several write/read sequences on TEST0 and TEST1 bits + * to figure out whever or not the xilinx was correctly loaded + */ + + /* We write 1 on CDSP.TEST0. We should get 0 on STATUS.TEST0. */ + vx_outl(chip, CDSP, chip->regCDSP | VX_CDSP_TEST0_MASK); + vx_inl(chip, ISR); + data = vx_inl(chip, STATUS); + if ((data & VX_STATUS_VAL_TEST0_MASK) == VX_STATUS_VAL_TEST0_MASK) { + snd_printdd("bad!\n"); + return -ENODEV; + } + + /* We write 0 on CDSP.TEST0. We should get 1 on STATUS.TEST0. */ + vx_outl(chip, CDSP, chip->regCDSP & ~VX_CDSP_TEST0_MASK); + vx_inl(chip, ISR); + data = vx_inl(chip, STATUS); + if (! (data & VX_STATUS_VAL_TEST0_MASK)) { + snd_printdd("bad! #2\n"); + return -ENODEV; + } + + if (_chip->type == VX_TYPE_BOARD) { + /* not implemented on VX_2_BOARDS */ + /* We write 1 on CDSP.TEST1. We should get 0 on STATUS.TEST1. */ + vx_outl(chip, CDSP, chip->regCDSP | VX_CDSP_TEST1_MASK); + vx_inl(chip, ISR); + data = vx_inl(chip, STATUS); + if ((data & VX_STATUS_VAL_TEST1_MASK) == VX_STATUS_VAL_TEST1_MASK) { + snd_printdd("bad! #3\n"); + return -ENODEV; + } + + /* We write 0 on CDSP.TEST1. We should get 1 on STATUS.TEST1. */ + vx_outl(chip, CDSP, chip->regCDSP & ~VX_CDSP_TEST1_MASK); + vx_inl(chip, ISR); + data = vx_inl(chip, STATUS); + if (! (data & VX_STATUS_VAL_TEST1_MASK)) { + snd_printdd("bad! #4\n"); + return -ENODEV; + } + } + snd_printdd("ok, xilinx fine.\n"); + return 0; +} + + +/** + * vx_setup_pseudo_dma - set up the pseudo dma read/write mode. + * @do_write: 0 = read, 1 = set up for DMA write + */ +static void vx2_setup_pseudo_dma(vx_core_t *chip, int do_write) +{ + /* Interrupt mode and HREQ pin enabled for host transmit data transfers + * (in case of the use of the pseudo-dma facility). + */ + vx_outl(chip, ICR, do_write ? ICR_TREQ : ICR_RREQ); + + /* Reset the pseudo-dma register (in case of the use of the + * pseudo-dma facility). + */ + vx_outl(chip, RESET_DMA, 0); +} + +/* + * vx_release_pseudo_dma - disable the pseudo-DMA mode + */ +inline static void vx2_release_pseudo_dma(vx_core_t *chip) +{ + /* HREQ pin disabled. */ + vx_outl(chip, ICR, 0); +} + + + +/* pseudo-dma write */ +static void vx2_dma_write(vx_core_t *chip, snd_pcm_runtime_t *runtime, + vx_pipe_t *pipe, int count) +{ + unsigned long port = vx2_reg_addr(chip, VX_DMA); + int offset = pipe->hw_ptr; + u32 *addr = (u32 *)(runtime->dma_area + offset); + + snd_assert(count % 4 == 0, return); + + vx2_setup_pseudo_dma(chip, 1); + + /* Transfer using pseudo-dma. + */ + if (offset + count > pipe->buffer_bytes) { + int length = pipe->buffer_bytes - offset; + count -= length; + length >>= 2; /* in 32bit words */ + /* Transfer using pseudo-dma. */ + while (length-- > 0) { + outl(cpu_to_le32(*addr), port); + addr++; + } + addr = (u32 *)runtime->dma_area; + pipe->hw_ptr = 0; + } + pipe->hw_ptr += count; + count >>= 2; /* in 32bit words */ + /* Transfer using pseudo-dma. */ + while (count-- > 0) { + outl(cpu_to_le32(*addr), port); + addr++; + } + + vx2_release_pseudo_dma(chip); +} + + +/* pseudo dma read */ +static void vx2_dma_read(vx_core_t *chip, snd_pcm_runtime_t *runtime, + vx_pipe_t *pipe, int count) +{ + int offset = pipe->hw_ptr; + u32 *addr = (u32 *)(runtime->dma_area + offset); + unsigned long port = vx2_reg_addr(chip, VX_DMA); + + snd_assert(count % 4 == 0, return); + + vx2_setup_pseudo_dma(chip, 0); + /* Transfer using pseudo-dma. + */ + if (offset + count > pipe->buffer_bytes) { + int length = pipe->buffer_bytes - offset; + count -= length; + length >>= 2; /* in 32bit words */ + /* Transfer using pseudo-dma. */ + while (length-- > 0) + *addr++ = le32_to_cpu(inl(port)); + addr = (u32 *)runtime->dma_area; + pipe->hw_ptr = 0; + } + pipe->hw_ptr += count; + count >>= 2; /* in 32bit words */ + /* Transfer using pseudo-dma. */ + while (count-- > 0) + *addr++ = le32_to_cpu(inl(port)); + + vx2_release_pseudo_dma(chip); +} + +#define VX_XILINX_RESET_MASK 0x40000000 +#define VX_USERBIT0_MASK 0x00000004 +#define VX_USERBIT1_MASK 0x00000020 +#define VX_CNTRL_REGISTER_VALUE 0x00172012 + +/* + * transfer counts bits to PLX + */ +static int put_xilinx_data(vx_core_t *chip, unsigned int port, unsigned int counts, unsigned char data) +{ + unsigned int i; + + for (i = 0; i < counts; i++) { + unsigned int val; + + /* set the clock bit to 0. */ + val = VX_CNTRL_REGISTER_VALUE & ~VX_USERBIT0_MASK; + vx2_outl(chip, port, val); + vx2_inl(chip, port); + udelay(1); + + if (data & (1 << i)) + val |= VX_USERBIT1_MASK; + else + val &= ~VX_USERBIT1_MASK; + vx2_outl(chip, port, val); + vx2_inl(chip, port); + + /* set the clock bit to 1. */ + val |= VX_USERBIT0_MASK; + vx2_outl(chip, port, val); + vx2_inl(chip, port); + udelay(1); + } + return 0; +} + +/* + * load the xilinx image + */ +static int vx2_load_xilinx_binary(vx_core_t *chip, const snd_hwdep_dsp_image_t *xilinx) +{ + unsigned int i; + unsigned int port; + unsigned char *image, data; + + /* XILINX reset (wait at least 1 milisecond between reset on and off). */ + vx_outl(chip, CNTRL, VX_CNTRL_REGISTER_VALUE | VX_XILINX_RESET_MASK); + vx_inl(chip, CNTRL); + snd_vx_delay(chip, 10); + vx_outl(chip, CNTRL, VX_CNTRL_REGISTER_VALUE); + vx_inl(chip, CNTRL); + snd_vx_delay(chip, 10); + + if (chip->type == VX_TYPE_BOARD) + port = VX_CNTRL; + else + port = VX_GPIOC; /* VX222 V2 and VX222_MIC_BOARD with new PLX9030 use this register */ + + image = xilinx->image; + for (i = 0; i < xilinx->length; i++, image++) { + __get_user(data, image); + if (put_xilinx_data(chip, port, 8, data) < 0) + return -EINVAL; + /* don't take too much time in this loop... */ + if (need_resched()) { + if (current->state != TASK_RUNNING) + set_current_state(TASK_RUNNING); + schedule(); + } + } + put_xilinx_data(chip, port, 4, 0xff); /* end signature */ + + snd_vx_delay(chip, 200); + + /* test after loading (is buggy with VX222) */ + if (chip->type != VX_TYPE_BOARD) { + /* Test if load successful: test bit 8 of register GPIOC (VX222: use CNTRL) ! */ + i = vx_inl(chip, GPIOC); + if (i & 0x0100) + return 0; + snd_printk(KERN_ERR "vx222: xilinx test failed after load, GPIOC=0x%x\n", i); + return -EINVAL; + } + + return 0; +} + + +/* + * load the boot/dsp images + */ +static int vx2_load_dsp(vx_core_t *vx, const snd_hwdep_dsp_image_t *dsp) +{ + int err; + + if (*dsp->name) + snd_printdd("loading dsp [%d] %s, size = %d\n", dsp->index, dsp->name, dsp->length); + switch (dsp->index) { + case 0: + /* xilinx image */ + if ((err = vx2_load_xilinx_binary(vx, dsp)) < 0) + return err; + if ((err = vx2_test_xilinx(vx)) < 0) + return err; + return 0; + case 1: + /* DSP boot */ + return snd_vx_dsp_boot(vx, dsp); + case 2: + /* DSP image */ + return snd_vx_dsp_load(vx, dsp); + default: + snd_BUG(); + return -EINVAL; + } +} + + +/* + * vx_test_and_ack - test and acknowledge interrupt + * + * called from irq hander, too + * + * spinlock held! + */ +static int vx2_test_and_ack(vx_core_t *chip) +{ + /* not booted yet? */ + if (! (chip->chip_status & VX_STAT_XILINX_LOADED)) + return -ENXIO; + + if (! (vx_inl(chip, STATUS) & VX_STATUS_MEMIRQ_MASK)) + return -EIO; + + /* ok, interrupts generated, now ack it */ + /* set ACQUIT bit up and down */ + vx_outl(chip, STATUS, 0); + /* useless read just to spend some time and maintain + * the ACQUIT signal up for a while ( a bus cycle ) + */ + vx_inl(chip, STATUS); + /* ack */ + vx_outl(chip, STATUS, VX_STATUS_MEMIRQ_MASK); + /* useless read just to spend some time and maintain + * the ACQUIT signal up for a while ( a bus cycle ) */ + vx_inl(chip, STATUS); + /* clear */ + vx_outl(chip, STATUS, 0); + + return 0; +} + + +/* + * vx_validate_irq - enable/disable IRQ + */ +static void vx2_validate_irq(vx_core_t *_chip, int enable) +{ + struct snd_vx222 *chip = (struct snd_vx222 *)_chip; + + /* Set the interrupt enable bit to 1 in CDSP register */ + if (enable) { + /* Set the PCI interrupt enable bit to 1.*/ + vx_outl(chip, INTCSR, VX_INTCSR_VALUE|VX_PCI_INTERRUPT_MASK); + chip->regCDSP |= VX_CDSP_VALID_IRQ_MASK; + } else { + /* Set the PCI interrupt enable bit to 0. */ + vx_outl(chip, INTCSR, VX_INTCSR_VALUE&~VX_PCI_INTERRUPT_MASK); + chip->regCDSP &= ~VX_CDSP_VALID_IRQ_MASK; + } + vx_outl(chip, CDSP, chip->regCDSP); +} + + +/* + * write an AKM codec data (24bit) + */ +static void vx2_write_codec_reg(vx_core_t *chip, unsigned int data) +{ + unsigned int i; + + vx_inl(chip, HIFREQ); + + /* We have to send 24 bits (3 x 8 bits). Start with most signif. Bit */ + for (i = 0; i < 24; i++, data <<= 1) + vx_outl(chip, DATA, ((data & 0x800000) ? VX_DATA_CODEC_MASK : 0)); + /* Terminate access to codec registers */ + vx_inl(chip, RUER); +} + + +#define AKM_CODEC_POWER_CONTROL_CMD 0xA007 +#define AKM_CODEC_RESET_ON_CMD 0xA100 +#define AKM_CODEC_RESET_OFF_CMD 0xA103 +#define AKM_CODEC_CLOCK_FORMAT_CMD 0xA240 +#define AKM_CODEC_MUTE_CMD 0xA38D +#define AKM_CODEC_UNMUTE_CMD 0xA30D +#define AKM_CODEC_LEFT_LEVEL_CMD 0xA400 +#define AKM_CODEC_RIGHT_LEVEL_CMD 0xA500 + +static const u8 vx2_akm_gains_lut[VX2_AKM_LEVEL_MAX+1] = { + 0x7f, // [000] = +0.000 dB -> AKM(0x7f) = +0.000 dB error(+0.000 dB) + 0x7d, // [001] = -0.500 dB -> AKM(0x7d) = -0.572 dB error(-0.072 dB) + 0x7c, // [002] = -1.000 dB -> AKM(0x7c) = -0.873 dB error(+0.127 dB) + 0x7a, // [003] = -1.500 dB -> AKM(0x7a) = -1.508 dB error(-0.008 dB) + 0x79, // [004] = -2.000 dB -> AKM(0x79) = -1.844 dB error(+0.156 dB) + 0x77, // [005] = -2.500 dB -> AKM(0x77) = -2.557 dB error(-0.057 dB) + 0x76, // [006] = -3.000 dB -> AKM(0x76) = -2.937 dB error(+0.063 dB) + 0x75, // [007] = -3.500 dB -> AKM(0x75) = -3.334 dB error(+0.166 dB) + 0x73, // [008] = -4.000 dB -> AKM(0x73) = -4.188 dB error(-0.188 dB) + 0x72, // [009] = -4.500 dB -> AKM(0x72) = -4.648 dB error(-0.148 dB) + 0x71, // [010] = -5.000 dB -> AKM(0x71) = -5.134 dB error(-0.134 dB) + 0x70, // [011] = -5.500 dB -> AKM(0x70) = -5.649 dB error(-0.149 dB) + 0x6f, // [012] = -6.000 dB -> AKM(0x6f) = -6.056 dB error(-0.056 dB) + 0x6d, // [013] = -6.500 dB -> AKM(0x6d) = -6.631 dB error(-0.131 dB) + 0x6c, // [014] = -7.000 dB -> AKM(0x6c) = -6.933 dB error(+0.067 dB) + 0x6a, // [015] = -7.500 dB -> AKM(0x6a) = -7.571 dB error(-0.071 dB) + 0x69, // [016] = -8.000 dB -> AKM(0x69) = -7.909 dB error(+0.091 dB) + 0x67, // [017] = -8.500 dB -> AKM(0x67) = -8.626 dB error(-0.126 dB) + 0x66, // [018] = -9.000 dB -> AKM(0x66) = -9.008 dB error(-0.008 dB) + 0x65, // [019] = -9.500 dB -> AKM(0x65) = -9.407 dB error(+0.093 dB) + 0x64, // [020] = -10.000 dB -> AKM(0x64) = -9.826 dB error(+0.174 dB) + 0x62, // [021] = -10.500 dB -> AKM(0x62) = -10.730 dB error(-0.230 dB) + 0x61, // [022] = -11.000 dB -> AKM(0x61) = -11.219 dB error(-0.219 dB) + 0x60, // [023] = -11.500 dB -> AKM(0x60) = -11.738 dB error(-0.238 dB) + 0x5f, // [024] = -12.000 dB -> AKM(0x5f) = -12.149 dB error(-0.149 dB) + 0x5e, // [025] = -12.500 dB -> AKM(0x5e) = -12.434 dB error(+0.066 dB) + 0x5c, // [026] = -13.000 dB -> AKM(0x5c) = -13.033 dB error(-0.033 dB) + 0x5b, // [027] = -13.500 dB -> AKM(0x5b) = -13.350 dB error(+0.150 dB) + 0x59, // [028] = -14.000 dB -> AKM(0x59) = -14.018 dB error(-0.018 dB) + 0x58, // [029] = -14.500 dB -> AKM(0x58) = -14.373 dB error(+0.127 dB) + 0x56, // [030] = -15.000 dB -> AKM(0x56) = -15.130 dB error(-0.130 dB) + 0x55, // [031] = -15.500 dB -> AKM(0x55) = -15.534 dB error(-0.034 dB) + 0x54, // [032] = -16.000 dB -> AKM(0x54) = -15.958 dB error(+0.042 dB) + 0x53, // [033] = -16.500 dB -> AKM(0x53) = -16.404 dB error(+0.096 dB) + 0x52, // [034] = -17.000 dB -> AKM(0x52) = -16.874 dB error(+0.126 dB) + 0x51, // [035] = -17.500 dB -> AKM(0x51) = -17.371 dB error(+0.129 dB) + 0x50, // [036] = -18.000 dB -> AKM(0x50) = -17.898 dB error(+0.102 dB) + 0x4e, // [037] = -18.500 dB -> AKM(0x4e) = -18.605 dB error(-0.105 dB) + 0x4d, // [038] = -19.000 dB -> AKM(0x4d) = -18.905 dB error(+0.095 dB) + 0x4b, // [039] = -19.500 dB -> AKM(0x4b) = -19.538 dB error(-0.038 dB) + 0x4a, // [040] = -20.000 dB -> AKM(0x4a) = -19.872 dB error(+0.128 dB) + 0x48, // [041] = -20.500 dB -> AKM(0x48) = -20.583 dB error(-0.083 dB) + 0x47, // [042] = -21.000 dB -> AKM(0x47) = -20.961 dB error(+0.039 dB) + 0x46, // [043] = -21.500 dB -> AKM(0x46) = -21.356 dB error(+0.144 dB) + 0x44, // [044] = -22.000 dB -> AKM(0x44) = -22.206 dB error(-0.206 dB) + 0x43, // [045] = -22.500 dB -> AKM(0x43) = -22.664 dB error(-0.164 dB) + 0x42, // [046] = -23.000 dB -> AKM(0x42) = -23.147 dB error(-0.147 dB) + 0x41, // [047] = -23.500 dB -> AKM(0x41) = -23.659 dB error(-0.159 dB) + 0x40, // [048] = -24.000 dB -> AKM(0x40) = -24.203 dB error(-0.203 dB) + 0x3f, // [049] = -24.500 dB -> AKM(0x3f) = -24.635 dB error(-0.135 dB) + 0x3e, // [050] = -25.000 dB -> AKM(0x3e) = -24.935 dB error(+0.065 dB) + 0x3c, // [051] = -25.500 dB -> AKM(0x3c) = -25.569 dB error(-0.069 dB) + 0x3b, // [052] = -26.000 dB -> AKM(0x3b) = -25.904 dB error(+0.096 dB) + 0x39, // [053] = -26.500 dB -> AKM(0x39) = -26.615 dB error(-0.115 dB) + 0x38, // [054] = -27.000 dB -> AKM(0x38) = -26.994 dB error(+0.006 dB) + 0x37, // [055] = -27.500 dB -> AKM(0x37) = -27.390 dB error(+0.110 dB) + 0x36, // [056] = -28.000 dB -> AKM(0x36) = -27.804 dB error(+0.196 dB) + 0x34, // [057] = -28.500 dB -> AKM(0x34) = -28.699 dB error(-0.199 dB) + 0x33, // [058] = -29.000 dB -> AKM(0x33) = -29.183 dB error(-0.183 dB) + 0x32, // [059] = -29.500 dB -> AKM(0x32) = -29.696 dB error(-0.196 dB) + 0x31, // [060] = -30.000 dB -> AKM(0x31) = -30.241 dB error(-0.241 dB) + 0x31, // [061] = -30.500 dB -> AKM(0x31) = -30.241 dB error(+0.259 dB) + 0x30, // [062] = -31.000 dB -> AKM(0x30) = -30.823 dB error(+0.177 dB) + 0x2e, // [063] = -31.500 dB -> AKM(0x2e) = -31.610 dB error(-0.110 dB) + 0x2d, // [064] = -32.000 dB -> AKM(0x2d) = -31.945 dB error(+0.055 dB) + 0x2b, // [065] = -32.500 dB -> AKM(0x2b) = -32.659 dB error(-0.159 dB) + 0x2a, // [066] = -33.000 dB -> AKM(0x2a) = -33.038 dB error(-0.038 dB) + 0x29, // [067] = -33.500 dB -> AKM(0x29) = -33.435 dB error(+0.065 dB) + 0x28, // [068] = -34.000 dB -> AKM(0x28) = -33.852 dB error(+0.148 dB) + 0x27, // [069] = -34.500 dB -> AKM(0x27) = -34.289 dB error(+0.211 dB) + 0x25, // [070] = -35.000 dB -> AKM(0x25) = -35.235 dB error(-0.235 dB) + 0x24, // [071] = -35.500 dB -> AKM(0x24) = -35.750 dB error(-0.250 dB) + 0x24, // [072] = -36.000 dB -> AKM(0x24) = -35.750 dB error(+0.250 dB) + 0x23, // [073] = -36.500 dB -> AKM(0x23) = -36.297 dB error(+0.203 dB) + 0x22, // [074] = -37.000 dB -> AKM(0x22) = -36.881 dB error(+0.119 dB) + 0x21, // [075] = -37.500 dB -> AKM(0x21) = -37.508 dB error(-0.008 dB) + 0x20, // [076] = -38.000 dB -> AKM(0x20) = -38.183 dB error(-0.183 dB) + 0x1f, // [077] = -38.500 dB -> AKM(0x1f) = -38.726 dB error(-0.226 dB) + 0x1e, // [078] = -39.000 dB -> AKM(0x1e) = -39.108 dB error(-0.108 dB) + 0x1d, // [079] = -39.500 dB -> AKM(0x1d) = -39.507 dB error(-0.007 dB) + 0x1c, // [080] = -40.000 dB -> AKM(0x1c) = -39.926 dB error(+0.074 dB) + 0x1b, // [081] = -40.500 dB -> AKM(0x1b) = -40.366 dB error(+0.134 dB) + 0x1a, // [082] = -41.000 dB -> AKM(0x1a) = -40.829 dB error(+0.171 dB) + 0x19, // [083] = -41.500 dB -> AKM(0x19) = -41.318 dB error(+0.182 dB) + 0x18, // [084] = -42.000 dB -> AKM(0x18) = -41.837 dB error(+0.163 dB) + 0x17, // [085] = -42.500 dB -> AKM(0x17) = -42.389 dB error(+0.111 dB) + 0x16, // [086] = -43.000 dB -> AKM(0x16) = -42.978 dB error(+0.022 dB) + 0x15, // [087] = -43.500 dB -> AKM(0x15) = -43.610 dB error(-0.110 dB) + 0x14, // [088] = -44.000 dB -> AKM(0x14) = -44.291 dB error(-0.291 dB) + 0x14, // [089] = -44.500 dB -> AKM(0x14) = -44.291 dB error(+0.209 dB) + 0x13, // [090] = -45.000 dB -> AKM(0x13) = -45.031 dB error(-0.031 dB) + 0x12, // [091] = -45.500 dB -> AKM(0x12) = -45.840 dB error(-0.340 dB) + 0x12, // [092] = -46.000 dB -> AKM(0x12) = -45.840 dB error(+0.160 dB) + 0x11, // [093] = -46.500 dB -> AKM(0x11) = -46.731 dB error(-0.231 dB) + 0x11, // [094] = -47.000 dB -> AKM(0x11) = -46.731 dB error(+0.269 dB) + 0x10, // [095] = -47.500 dB -> AKM(0x10) = -47.725 dB error(-0.225 dB) + 0x10, // [096] = -48.000 dB -> AKM(0x10) = -47.725 dB error(+0.275 dB) + 0x0f, // [097] = -48.500 dB -> AKM(0x0f) = -48.553 dB error(-0.053 dB) + 0x0e, // [098] = -49.000 dB -> AKM(0x0e) = -49.152 dB error(-0.152 dB) + 0x0d, // [099] = -49.500 dB -> AKM(0x0d) = -49.796 dB error(-0.296 dB) + 0x0d, // [100] = -50.000 dB -> AKM(0x0d) = -49.796 dB error(+0.204 dB) + 0x0c, // [101] = -50.500 dB -> AKM(0x0c) = -50.491 dB error(+0.009 dB) + 0x0b, // [102] = -51.000 dB -> AKM(0x0b) = -51.247 dB error(-0.247 dB) + 0x0b, // [103] = -51.500 dB -> AKM(0x0b) = -51.247 dB error(+0.253 dB) + 0x0a, // [104] = -52.000 dB -> AKM(0x0a) = -52.075 dB error(-0.075 dB) + 0x0a, // [105] = -52.500 dB -> AKM(0x0a) = -52.075 dB error(+0.425 dB) + 0x09, // [106] = -53.000 dB -> AKM(0x09) = -52.990 dB error(+0.010 dB) + 0x09, // [107] = -53.500 dB -> AKM(0x09) = -52.990 dB error(+0.510 dB) + 0x08, // [108] = -54.000 dB -> AKM(0x08) = -54.013 dB error(-0.013 dB) + 0x08, // [109] = -54.500 dB -> AKM(0x08) = -54.013 dB error(+0.487 dB) + 0x07, // [110] = -55.000 dB -> AKM(0x07) = -55.173 dB error(-0.173 dB) + 0x07, // [111] = -55.500 dB -> AKM(0x07) = -55.173 dB error(+0.327 dB) + 0x06, // [112] = -56.000 dB -> AKM(0x06) = -56.512 dB error(-0.512 dB) + 0x06, // [113] = -56.500 dB -> AKM(0x06) = -56.512 dB error(-0.012 dB) + 0x06, // [114] = -57.000 dB -> AKM(0x06) = -56.512 dB error(+0.488 dB) + 0x05, // [115] = -57.500 dB -> AKM(0x05) = -58.095 dB error(-0.595 dB) + 0x05, // [116] = -58.000 dB -> AKM(0x05) = -58.095 dB error(-0.095 dB) + 0x05, // [117] = -58.500 dB -> AKM(0x05) = -58.095 dB error(+0.405 dB) + 0x05, // [118] = -59.000 dB -> AKM(0x05) = -58.095 dB error(+0.905 dB) + 0x04, // [119] = -59.500 dB -> AKM(0x04) = -60.034 dB error(-0.534 dB) + 0x04, // [120] = -60.000 dB -> AKM(0x04) = -60.034 dB error(-0.034 dB) + 0x04, // [121] = -60.500 dB -> AKM(0x04) = -60.034 dB error(+0.466 dB) + 0x04, // [122] = -61.000 dB -> AKM(0x04) = -60.034 dB error(+0.966 dB) + 0x03, // [123] = -61.500 dB -> AKM(0x03) = -62.532 dB error(-1.032 dB) + 0x03, // [124] = -62.000 dB -> AKM(0x03) = -62.532 dB error(-0.532 dB) + 0x03, // [125] = -62.500 dB -> AKM(0x03) = -62.532 dB error(-0.032 dB) + 0x03, // [126] = -63.000 dB -> AKM(0x03) = -62.532 dB error(+0.468 dB) + 0x03, // [127] = -63.500 dB -> AKM(0x03) = -62.532 dB error(+0.968 dB) + 0x03, // [128] = -64.000 dB -> AKM(0x03) = -62.532 dB error(+1.468 dB) + 0x02, // [129] = -64.500 dB -> AKM(0x02) = -66.054 dB error(-1.554 dB) + 0x02, // [130] = -65.000 dB -> AKM(0x02) = -66.054 dB error(-1.054 dB) + 0x02, // [131] = -65.500 dB -> AKM(0x02) = -66.054 dB error(-0.554 dB) + 0x02, // [132] = -66.000 dB -> AKM(0x02) = -66.054 dB error(-0.054 dB) + 0x02, // [133] = -66.500 dB -> AKM(0x02) = -66.054 dB error(+0.446 dB) + 0x02, // [134] = -67.000 dB -> AKM(0x02) = -66.054 dB error(+0.946 dB) + 0x02, // [135] = -67.500 dB -> AKM(0x02) = -66.054 dB error(+1.446 dB) + 0x02, // [136] = -68.000 dB -> AKM(0x02) = -66.054 dB error(+1.946 dB) + 0x02, // [137] = -68.500 dB -> AKM(0x02) = -66.054 dB error(+2.446 dB) + 0x02, // [138] = -69.000 dB -> AKM(0x02) = -66.054 dB error(+2.946 dB) + 0x01, // [139] = -69.500 dB -> AKM(0x01) = -72.075 dB error(-2.575 dB) + 0x01, // [140] = -70.000 dB -> AKM(0x01) = -72.075 dB error(-2.075 dB) + 0x01, // [141] = -70.500 dB -> AKM(0x01) = -72.075 dB error(-1.575 dB) + 0x01, // [142] = -71.000 dB -> AKM(0x01) = -72.075 dB error(-1.075 dB) + 0x01, // [143] = -71.500 dB -> AKM(0x01) = -72.075 dB error(-0.575 dB) + 0x01, // [144] = -72.000 dB -> AKM(0x01) = -72.075 dB error(-0.075 dB) + 0x01, // [145] = -72.500 dB -> AKM(0x01) = -72.075 dB error(+0.425 dB) + 0x01, // [146] = -73.000 dB -> AKM(0x01) = -72.075 dB error(+0.925 dB) + 0x00}; // [147] = -73.500 dB -> AKM(0x00) = mute error(+infini) + +/* + * pseudo-codec write entry + */ +static void vx2_write_akm(vx_core_t *chip, int reg, unsigned int data) +{ + unsigned int val; + + if (reg == XX_CODEC_DAC_CONTROL_REGISTER) { + vx2_write_codec_reg(chip, data ? AKM_CODEC_MUTE_CMD : AKM_CODEC_UNMUTE_CMD); + return; + } + + /* `data' is a value between 0x0 and VX2_AKM_LEVEL_MAX = 0x093, in the case of the AKM codecs, we need + a look up table, as there is no linear matching between the driver codec values + and the real dBu value + */ + snd_assert(data < sizeof(vx2_akm_gains_lut), return); + + switch (reg) { + case XX_CODEC_LEVEL_LEFT_REGISTER: + val = AKM_CODEC_LEFT_LEVEL_CMD; + break; + case XX_CODEC_LEVEL_RIGHT_REGISTER: + val = AKM_CODEC_RIGHT_LEVEL_CMD; + break; + default: + snd_BUG(); + return; + } + val |= vx2_akm_gains_lut[data]; + + vx2_write_codec_reg(chip, val); +} + + +/* + * write codec bit for old VX222 board + */ +static void vx2_old_write_codec_bit(vx_core_t *chip, int codec, unsigned int data) +{ + int i; + + /* activate access to codec registers */ + vx_inl(chip, HIFREQ); + + for (i = 0; i < 24; i++, data <<= 1) + vx_outl(chip, DATA, ((data & 0x800000) ? VX_DATA_CODEC_MASK : 0)); + + /* Terminate access to codec registers */ + vx_inl(chip, RUER); +} + + +/* + * reset codec bit + */ +static void vx2_reset_codec(vx_core_t *_chip) +{ + struct snd_vx222 *chip = (struct snd_vx222 *)_chip; + + /* Set the reset CODEC bit to 0. */ + vx_outl(chip, CDSP, chip->regCDSP &~ VX_CDSP_CODEC_RESET_MASK); + vx_inl(chip, CDSP); + snd_vx_delay(_chip, 10); + /* Set the reset CODEC bit to 1. */ + chip->regCDSP |= VX_CDSP_CODEC_RESET_MASK; + vx_outl(chip, CDSP, chip->regCDSP); + vx_inl(chip, CDSP); + if (_chip->type == VX_TYPE_BOARD) { + snd_vx_delay(_chip, 1); + return; + } + + snd_vx_delay(_chip, 5); /* additionnel wait time for AKM's */ + + vx2_write_codec_reg(_chip, AKM_CODEC_POWER_CONTROL_CMD); /* DAC power up, ADC power up, Vref power down */ + + vx2_write_codec_reg(_chip, AKM_CODEC_CLOCK_FORMAT_CMD); /* default */ + vx2_write_codec_reg(_chip, AKM_CODEC_MUTE_CMD); /* Mute = ON ,Deemphasis = OFF */ + vx2_write_codec_reg(_chip, AKM_CODEC_RESET_OFF_CMD); /* DAC and ADC normal operation */ + + if (_chip->type == VX_TYPE_MIC) { + /* set up the micro input selector */ + chip->regSELMIC = MICRO_SELECT_INPUT_NORM | + MICRO_SELECT_PREAMPLI_G_0 | + MICRO_SELECT_NOISE_T_52DB; + + /* reset phantom power supply */ + chip->regSELMIC &= ~MICRO_SELECT_PHANTOM_ALIM; + + vx_outl(_chip, SELMIC, chip->regSELMIC); + } +} + + +/* + * change the audio source + */ +static void vx2_change_audio_source(vx_core_t *_chip, int src) +{ + struct snd_vx222 *chip = (struct snd_vx222 *)_chip; + + switch (src) { + case VX_AUDIO_SRC_DIGITAL: + chip->regCFG |= VX_CFG_DATAIN_SEL_MASK; + break; + default: + chip->regCFG &= ~VX_CFG_DATAIN_SEL_MASK; + break; + } + vx_outl(chip, CFG, chip->regCFG); +} + + +/* + * set the clock source + */ +static void vx2_set_clock_source(vx_core_t *_chip, int source) +{ + struct snd_vx222 *chip = (struct snd_vx222 *)_chip; + + if (source == INTERNAL_QUARTZ) + chip->regCFG &= ~VX_CFG_CLOCKIN_SEL_MASK; + else + chip->regCFG |= VX_CFG_CLOCKIN_SEL_MASK; + vx_outl(chip, CFG, chip->regCFG); +} + +/* + * reset the board + */ +static void vx2_reset_board(vx_core_t *_chip, int cold_reset) +{ + struct snd_vx222 *chip = (struct snd_vx222 *)_chip; + + /* initialize the register values */ + chip->regCDSP = VX_CDSP_CODEC_RESET_MASK | VX_CDSP_DSP_RESET_MASK ; + chip->regCFG = 0; +} + + + +/* + * input level controls for VX222 Mic + */ + +/* Micro level is specified to be adjustable from -96dB to 63 dB (board coded 0x00 ... 318), + * 318 = 210 + 36 + 36 + 36 (210 = +9dB variable) (3 * 36 = 3 steps of 18dB pre ampli) + * as we will mute if less than -110dB, so let's simply use line input coded levels and add constant offset ! + */ +#define V2_MICRO_LEVEL_RANGE (318 - 255) + +static void vx2_set_input_level(struct snd_vx222 *chip) +{ + int i, miclevel, preamp; + unsigned int data; + + miclevel = chip->mic_level; + miclevel += V2_MICRO_LEVEL_RANGE; /* add 318 - 0xff */ + preamp = 0; + while (miclevel > 210) { /* limitation to +9dB of 3310 real gain */ + preamp++; /* raise pre ampli + 18dB */ + miclevel -= (18 * 2); /* lower level 18 dB (*2 because of 0.5 dB steps !) */ + } + snd_assert(preamp < 4, return); + + /* set pre-amp level */ + chip->regSELMIC &= ~MICRO_SELECT_PREAMPLI_MASK; + chip->regSELMIC |= (preamp << MICRO_SELECT_PREAMPLI_OFFSET) & MICRO_SELECT_PREAMPLI_MASK; + vx_outl(chip, SELMIC, chip->regSELMIC); + + data = (unsigned int)miclevel << 16 | + (unsigned int)chip->input_level[1] << 8 | + (unsigned int)chip->input_level[0]; + vx_inl(chip, DATA); /* Activate input level programming */ + + /* We have to send 32 bits (4 x 8 bits) */ + for (i = 0; i < 32; i++, data <<= 1) + vx_outl(chip, DATA, ((data & 0x80000000) ? VX_DATA_CODEC_MASK : 0)); + + vx_inl(chip, RUER); /* Terminate input level programming */ +} + + +#define MIC_LEVEL_MAX 0xff + +/* + * controls API for input levels + */ + +/* input levels */ +static int vx_input_level_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 2; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = MIC_LEVEL_MAX; + return 0; +} + +static int vx_input_level_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + vx_core_t *_chip = snd_kcontrol_chip(kcontrol); + struct snd_vx222 *chip = (struct snd_vx222 *)_chip; + down(&_chip->mixer_mutex); + ucontrol->value.integer.value[0] = chip->input_level[0]; + ucontrol->value.integer.value[1] = chip->input_level[1]; + up(&_chip->mixer_mutex); + return 0; +} + +static int vx_input_level_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + vx_core_t *_chip = snd_kcontrol_chip(kcontrol); + struct snd_vx222 *chip = (struct snd_vx222 *)_chip; + down(&_chip->mixer_mutex); + if (chip->input_level[0] != ucontrol->value.integer.value[0] || + chip->input_level[1] != ucontrol->value.integer.value[1]) { + chip->input_level[0] = ucontrol->value.integer.value[0]; + chip->input_level[1] = ucontrol->value.integer.value[1]; + vx2_set_input_level(chip); + up(&_chip->mixer_mutex); + return 1; + } + up(&_chip->mixer_mutex); + return 0; +} + +/* mic level */ +static int vx_mic_level_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = MIC_LEVEL_MAX; + return 0; +} + +static int vx_mic_level_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + vx_core_t *_chip = snd_kcontrol_chip(kcontrol); + struct snd_vx222 *chip = (struct snd_vx222 *)_chip; + ucontrol->value.integer.value[0] = chip->mic_level; + return 0; +} + +static int vx_mic_level_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + vx_core_t *_chip = snd_kcontrol_chip(kcontrol); + struct snd_vx222 *chip = (struct snd_vx222 *)_chip; + down(&_chip->mixer_mutex); + if (chip->mic_level != ucontrol->value.integer.value[0]) { + chip->mic_level = ucontrol->value.integer.value[0]; + vx2_set_input_level(chip); + up(&_chip->mixer_mutex); + return 1; + } + up(&_chip->mixer_mutex); + return 0; +} + +static snd_kcontrol_new_t vx_control_input_level = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Volume", + .info = vx_input_level_info, + .get = vx_input_level_get, + .put = vx_input_level_put, +}; + +static snd_kcontrol_new_t vx_control_mic_level = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Mic Capture Volume", + .info = vx_mic_level_info, + .get = vx_mic_level_get, + .put = vx_mic_level_put, +}; + +/* + * FIXME: compressor/limiter implementation is missing yet... + */ + +static int vx2_add_mic_controls(vx_core_t *_chip) +{ + struct snd_vx222 *chip = (struct snd_vx222 *)_chip; + int err; + + if (_chip->type != VX_TYPE_MIC) + return 0; + + /* mute input levels */ + chip->input_level[0] = chip->input_level[1] = 0; + chip->mic_level = 0; + vx2_set_input_level(chip); + + /* controls */ + if ((err = snd_ctl_add(_chip->card, snd_ctl_new1(&vx_control_input_level, chip))) < 0) + return err; + if ((err = snd_ctl_add(_chip->card, snd_ctl_new1(&vx_control_mic_level, chip))) < 0) + return err; + + return 0; +} + + +/* + * callbacks + */ +struct snd_vx_ops vx222_ops = { + .in8 = vx2_inb, + .in32 = vx2_inl, + .out8 = vx2_outb, + .out32 = vx2_outl, + .test_and_ack = vx2_test_and_ack, + .validate_irq = vx2_validate_irq, + .akm_write = vx2_write_akm, + .reset_codec = vx2_reset_codec, + .change_audio_source = vx2_change_audio_source, + .set_clock_source = vx2_set_clock_source, + .load_dsp = vx2_load_dsp, + .reset_dsp = vx2_reset_dsp, + .reset_board = vx2_reset_board, + .dma_write = vx2_dma_write, + .dma_read = vx2_dma_read, + .add_controls = vx2_add_mic_controls, +}; + +/* for old VX222 board */ +struct snd_vx_ops vx222_old_ops = { + .in8 = vx2_inb, + .in32 = vx2_inl, + .out8 = vx2_outb, + .out32 = vx2_outl, + .test_and_ack = vx2_test_and_ack, + .validate_irq = vx2_validate_irq, + .write_codec = vx2_old_write_codec_bit, + .reset_codec = vx2_reset_codec, + .change_audio_source = vx2_change_audio_source, + .set_clock_source = vx2_set_clock_source, + .load_dsp = vx2_load_dsp, + .reset_dsp = vx2_reset_dsp, + .reset_board = vx2_reset_board, + .dma_write = vx2_dma_write, + .dma_read = vx2_dma_read, +}; + diff -Nru a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c --- a/sound/pci/ymfpci/ymfpci.c Mon Jun 9 23:16:10 2003 +++ b/sound/pci/ymfpci/ymfpci.c Mon Jun 9 23:16:10 2003 @@ -84,6 +84,8 @@ { static int dev; snd_card_t *card; + struct resource *fm_res = NULL; + struct resource *mpu_res = NULL; ymfpci_t *chip; opl3_t *opl3; char *str; @@ -116,24 +118,18 @@ if (pci_id->device >= 0x0010) { /* YMF 744/754 */ if (fm_port[dev] < 0) { - // fm_port[dev] = pci_resource_start(pci, 1); - u16 addr; - pci_read_config_word(pci, PCIR_DSXG_FMBASE, &addr); - fm_port[dev] = addr; + fm_port[dev] = pci_resource_start(pci, 1); } if (fm_port[dev] >= 0 && - (chip->fm_res = request_region(fm_port[dev], 4, "YMFPCI OPL3")) != NULL) { + (fm_res = request_region(fm_port[dev], 4, "YMFPCI OPL3")) != NULL) { legacy_ctrl |= YMFPCI_LEGACY_FMEN; pci_write_config_word(pci, PCIR_DSXG_FMBASE, fm_port[dev]); } if (mpu_port[dev] < 0) { - // mpu_port[dev] = pci_resource_start(pci, 1) + 0x20; - u16 addr; - pci_read_config_word(pci, PCIR_DSXG_MPU401BASE, &addr); - mpu_port[dev] = addr; + mpu_port[dev] = pci_resource_start(pci, 1) + 0x20; } if (mpu_port[dev] >= 0 && - (chip->mpu_res = request_region(mpu_port[dev], 2, "YMFPCI MPU401")) != NULL) { + (mpu_res = request_region(mpu_port[dev], 2, "YMFPCI MPU401")) != NULL) { legacy_ctrl |= YMFPCI_LEGACY_MEN; pci_write_config_word(pci, PCIR_DSXG_MPU401BASE, mpu_port[dev]); } @@ -146,7 +142,7 @@ default: fm_port[dev] = -1; break; } if (fm_port[dev] > 0 && - (chip->fm_res = request_region(fm_port[dev], 4, "YMFPCI OPL3")) != NULL) { + (fm_res = request_region(fm_port[dev], 4, "YMFPCI OPL3")) != NULL) { legacy_ctrl |= YMFPCI_LEGACY_FMEN; } else { legacy_ctrl2 &= ~YMFPCI_LEGACY2_FMIO; @@ -160,15 +156,15 @@ default: mpu_port[dev] = -1; break; } if (mpu_port[dev] > 0 && - (chip->mpu_res = request_region(mpu_port[dev], 2, "YMFPCI MPU401")) != NULL) { + (mpu_res = request_region(mpu_port[dev], 2, "YMFPCI MPU401")) != NULL) { legacy_ctrl |= YMFPCI_LEGACY_MEN; } else { legacy_ctrl2 &= ~YMFPCI_LEGACY2_MPUIO; mpu_port[dev] = -1; } } - if (chip->mpu_res) { - legacy_ctrl |= YMFPCI_LEGACY_MIEN; /* FIXME: do we need this? */ + if (mpu_res) { + legacy_ctrl |= YMFPCI_LEGACY_MIEN; legacy_ctrl2 |= YMFPCI_LEGACY2_IMOD; } pci_read_config_word(pci, PCIR_DSXG_LEGACY, &old_legacy_ctrl); @@ -178,8 +174,18 @@ old_legacy_ctrl, &chip)) < 0) { snd_card_free(card); + if (mpu_res) { + release_resource(mpu_res); + kfree_nocheck(mpu_res); + } + if (fm_res) { + release_resource(fm_res); + kfree_nocheck(fm_res); + } return err; } + chip->fm_res = fm_res; + chip->mpu_res = mpu_res; if ((err = snd_ymfpci_pcm(chip, 0, NULL)) < 0) { snd_card_free(card); return err; @@ -230,7 +236,7 @@ sprintf(card->shortname, "Yamaha DS-XG PCI (%s)", str); sprintf(card->longname, "%s at 0x%lx, irq %i", card->shortname, - chip->reg_area_virt, + chip->reg_area_phys, chip->irq); if ((err = snd_card_register(card)) < 0) { diff -Nru a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c --- a/sound/pci/ymfpci/ymfpci_main.c Mon Jun 9 23:16:18 2003 +++ b/sound/pci/ymfpci/ymfpci_main.c Mon Jun 9 23:16:18 2003 @@ -779,15 +779,14 @@ } } - status = snd_ymfpci_readl(chip, YDSXGR_INTFLAG); + status = snd_ymfpci_readw(chip, YDSXGR_INTFLAG); if (status & 1) { /* timer handler */ - snd_ymfpci_writel(chip, YDSXGR_INTFLAG, ~0); } + snd_ymfpci_writew(chip, YDSXGR_INTFLAG, status); if (chip->rawmidi) snd_mpu401_uart_interrupt(irq, chip->rawmidi->private_data, regs); - return IRQ_HANDLED; } @@ -2253,8 +2252,10 @@ return -EIO; } - if ((err = snd_ymfpci_ac3_init(chip)) < 0) + if ((err = snd_ymfpci_ac3_init(chip)) < 0) { + snd_ymfpci_free(chip); return err; + } #ifdef CONFIG_PM chip->saved_regs = vmalloc(YDSXGR_NUM_SAVED_REGS * sizeof(u32)); diff -Nru a/sound/pcmcia/Kconfig b/sound/pcmcia/Kconfig --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pcmcia/Kconfig Mon Jun 9 23:16:20 2003 @@ -0,0 +1,18 @@ +# ALSA PCMCIA drivers + +menu "PCMCIA devices" + depends on SND!=n && PCMCIA + +config SND_VXPOCKET + tristate "Digigram VXpocket" + depends on SND && PCMCIA + help + Say 'Y' or 'M' to include support for Digigram VXpocket soundcard. + +config SND_VXP440 + tristate "Digigram VXpocket 440" + depends on SND && PCMCIA + help + Say 'Y' or 'M' to include support for Digigram VXpocket 440 soundcard. + +endmenu diff -Nru a/sound/pcmcia/Makefile b/sound/pcmcia/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pcmcia/Makefile Mon Jun 9 23:16:20 2003 @@ -0,0 +1,8 @@ +# +# Makefile for ALSA +# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz> +# + +obj-$(CONFIG_SND) += vx/ + + diff -Nru a/sound/pcmcia/vx/Makefile b/sound/pcmcia/vx/Makefile --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pcmcia/vx/Makefile Mon Jun 9 23:16:20 2003 @@ -0,0 +1,10 @@ +# +# Makefile for ALSA +# Copyright (c) 2001 by Jaroslav Kysela <perex@suse.cz> +# + +snd-vxpocket-objs := vxpocket.o vx_entry.o vxp_ops.o vxp_mixer.o +snd-vxp440-objs := vxpocket.o vx_entry.o vxp_ops.o vxp_mixer.o + +obj-$(CONFIG_SND_VXPOCKET) += snd-vxpocket.o +obj-$(CONFIG_SND_VXP440) += snd-vxp440.o diff -Nru a/sound/pcmcia/vx/vx_entry.c b/sound/pcmcia/vx/vx_entry.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pcmcia/vx/vx_entry.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,385 @@ +/* + * Driver for Digigram VXpocket soundcards + * + * PCMCIA entry part + * + * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <sound/driver.h> +#include <sound/core.h> +#include "vxpocket.h" +#include <pcmcia/ciscode.h> +#include <pcmcia/cisreg.h> + + +/* + * prototypes + */ +static void vxpocket_config(dev_link_t *link); +static int vxpocket_event(event_t event, int priority, event_callback_args_t *args); + + +static void vxpocket_release(u_long arg) +{ + dev_link_t *link = (dev_link_t *)arg; + + if (link->state & DEV_CONFIG) { + /* release cs resources */ + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); + link->state &= ~DEV_CONFIG; + } +} + +/* + * destructor + */ +static int snd_vxpocket_free(vx_core_t *chip) +{ + struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip; + struct snd_vxp_entry *hw; + dev_link_t *link = &vxp->link; + + vxpocket_release((u_long)link); + + /* Break the link with Card Services */ + if (link->handle) + CardServices(DeregisterClient, link->handle); + + hw = vxp->hw_entry; + if (hw) + hw->card_list[vxp->index] = NULL; + chip->card = NULL; + + snd_magic_kfree(chip); + return 0; +} + +static int snd_vxpocket_dev_free(snd_device_t *device) +{ + vx_core_t *chip = snd_magic_cast(vx_core_t, device->device_data, return -ENXIO); + return snd_vxpocket_free(chip); +} + +/* + * snd_vxpocket_attach - attach callback for cs + * @hw: the hardware information + */ +dev_link_t *snd_vxpocket_attach(struct snd_vxp_entry *hw) +{ + client_reg_t client_reg; /* Register with cardmgr */ + dev_link_t *link; /* Info for cardmgr */ + int i, ret; + vx_core_t *chip; + struct snd_vxpocket *vxp; + snd_card_t *card; + static snd_device_ops_t ops = { + .dev_free = snd_vxpocket_dev_free, + }; + + snd_printdd(KERN_DEBUG "vxpocket_attach called\n"); + /* find an empty slot from the card list */ + for (i = 0; i < SNDRV_CARDS; i++) { + if (! hw->card_list[i]) + break; + } + if (i >= SNDRV_CARDS) { + snd_printk(KERN_ERR "vxpocket: too many cards found\n"); + return NULL; + } + if (! hw->enable_table[i]) + return NULL; /* disabled explicitly */ + + /* ok, create a card instance */ + card = snd_card_new(hw->index_table[i], hw->id_table[i], THIS_MODULE, 0); + if (card == NULL) { + snd_printk(KERN_ERR "vxpocket: cannot create a card instance\n"); + return NULL; + } + + chip = snd_vx_create(card, hw->hardware, hw->ops, + sizeof(struct snd_vxpocket) - sizeof(vx_core_t)); + if (! chip) + return NULL; + + if (snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops) < 0) { + snd_magic_kfree(chip); + snd_card_free(card); + return NULL; + } + + vxp = (struct snd_vxpocket *)chip; + vxp->index = i; + vxp->hw_entry = hw; + chip->ibl.size = hw->ibl[i]; + hw->card_list[i] = chip; + + link = &vxp->link; + link->priv = chip; + + link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; + link->io.NumPorts1 = 16; + + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + // link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; + + link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; + if (hw->irq_list[0] == -1) + link->irq.IRQInfo2 = *hw->irq_mask_p; + else + for (i = 0; i < 4; i++) + link->irq.IRQInfo2 |= 1 << hw->irq_list[i]; + link->irq.Handler = &snd_vx_irq_handler; + link->irq.Instance = chip; + + link->release.function = &vxpocket_release; + link->release.data = (u_long)link; + + link->conf.Attributes = CONF_ENABLE_IRQ; + link->conf.Vcc = 50; + link->conf.IntType = INT_MEMORY_AND_IO; + link->conf.ConfigIndex = 1; + link->conf.Present = PRESENT_OPTION; + + /* Chain drivers */ + link->next = hw->dev_list; + hw->dev_list = link; + + /* Register with Card Services */ + client_reg.dev_info = hw->dev_info; + client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE; + client_reg.EventMask = + CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL +#ifdef CONFIG_PM + | CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET + | CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME +#endif + ; + client_reg.event_handler = &vxpocket_event; + client_reg.Version = 0x0210; + client_reg.event_callback_args.client_data = link; + + ret = CardServices(RegisterClient, &link->handle, &client_reg); + if (ret != CS_SUCCESS) { + cs_error(link->handle, RegisterClient, ret); + snd_vxpocket_detach(hw, link); + return NULL; + } + + return link; +} + + +/** + * snd_vxpocket_assign_resources - initialize the hardware and card instance. + * @port: i/o port for the card + * @irq: irq number for the card + * + * this function assigns the specified port and irq, boot the card, + * create pcm and control instances, and initialize the rest hardware. + * + * returns 0 if successful, or a negative error code. + */ +static int snd_vxpocket_assign_resources(vx_core_t *chip, int port, int irq) +{ + int err; + snd_card_t *card = chip->card; + struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip; + + snd_printdd(KERN_DEBUG "vxpocket assign resources: port = 0x%x, irq = %d\n", port, irq); + vxp->port = port; + + sprintf(card->shortname, "Digigram %s", card->driver); + sprintf(card->longname, "%s at 0x%x, irq %i", + card->shortname, port, irq); + + if ((err = snd_vx_hwdep_new(chip)) < 0) + return err; + + chip->irq = irq; + + if ((err = snd_card_register(chip->card)) < 0) + return err; + + return 0; +} + + +/* + * snd_vxpocket_detach - detach callback for cs + * @hw: the hardware information + */ +void snd_vxpocket_detach(struct snd_vxp_entry *hw, dev_link_t *link) +{ + vx_core_t *chip = snd_magic_cast(vx_core_t, link->priv, return); + + del_timer(&link->release); + + snd_printdd(KERN_DEBUG "vxpocket_detach called\n"); + /* Remove the interface data from the linked list */ + if (hw) { + dev_link_t **linkp; + /* Locate device structure */ + for (linkp = &hw->dev_list; *linkp; linkp = &(*linkp)->next) + if (*linkp == link) + break; + if (*linkp) + *linkp = link->next; + } + chip->chip_status |= VX_STAT_IS_STALE; /* to be sure */ + snd_card_disconnect(chip->card); + snd_card_free_in_thread(chip->card); +} + +/* + * snd_vxpocket_detach_all - detach all instances linked to the hw + */ +void snd_vxpocket_detach_all(struct snd_vxp_entry *hw) +{ + while (hw->dev_list != NULL) + snd_vxpocket_detach(hw, hw->dev_list); +} + +/* + * configuration callback + */ + +#define CS_CHECK(fn, args...) \ +while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed + +static void vxpocket_config(dev_link_t *link) +{ + client_handle_t handle = link->handle; + vx_core_t *chip = snd_magic_cast(vx_core_t, link->priv, return); + struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip; + tuple_t tuple; + cisparse_t parse; + config_info_t conf; + u_short buf[32]; + int last_fn, last_ret; + + snd_printdd(KERN_DEBUG "vxpocket_config called\n"); + tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; + tuple.Attributes = 0; + tuple.TupleData = (cisdata_t *)buf; + tuple.TupleDataMax = sizeof(buf); + tuple.TupleOffset = 0; + tuple.DesiredTuple = CISTPL_CONFIG; + CS_CHECK(GetFirstTuple, handle, &tuple); + CS_CHECK(GetTupleData, handle, &tuple); + CS_CHECK(ParseTuple, handle, &tuple, &parse); + link->conf.ConfigBase = parse.config.base; + link->conf.ConfigIndex = 1; + + CS_CHECK(GetConfigurationInfo, handle, &conf); + link->conf.Vcc = conf.Vcc; + + /* Configure card */ + link->state |= DEV_CONFIG; + + CS_CHECK(RequestIO, handle, &link->io); + CS_CHECK(RequestIRQ, link->handle, &link->irq); + CS_CHECK(RequestConfiguration, link->handle, &link->conf); + + if (snd_vxpocket_assign_resources(chip, link->io.BasePort1, link->irq.AssignedIRQ) < 0) + goto failed; + + link->dev = &vxp->node; + link->state &= ~DEV_CONFIG_PENDING; + return; + +cs_failed: + cs_error(link->handle, last_fn, last_ret); +failed: + CardServices(ReleaseConfiguration, link->handle); + CardServices(ReleaseIO, link->handle, &link->io); + CardServices(ReleaseIRQ, link->handle, &link->irq); +} + + +/* + * event callback + */ +static int vxpocket_event(event_t event, int priority, event_callback_args_t *args) +{ + dev_link_t *link = args->client_data; + vx_core_t *chip = link->priv; + + switch (event) { + case CS_EVENT_CARD_REMOVAL: + snd_printdd(KERN_DEBUG "CARD_REMOVAL..\n"); + link->state &= ~DEV_PRESENT; + if (link->state & DEV_CONFIG) { + mod_timer(&link->release, jiffies + HZ/20); + chip->chip_status |= VX_STAT_IS_STALE; + } + break; + case CS_EVENT_CARD_INSERTION: + snd_printdd(KERN_DEBUG "CARD_INSERTION..\n"); + link->state |= DEV_PRESENT; + vxpocket_config(link); + break; +#ifdef CONFIG_PM + case CS_EVENT_PM_SUSPEND: + snd_printdd(KERN_DEBUG "SUSPEND\n"); + link->state |= DEV_SUSPEND; + if (chip) { + snd_printdd(KERN_DEBUG "snd_vx_suspend calling\n"); + snd_vx_suspend(chip); + } + /* Fall through... */ + case CS_EVENT_RESET_PHYSICAL: + snd_printdd(KERN_DEBUG "RESET_PHYSICAL\n"); + if (link->state & DEV_CONFIG) + CardServices(ReleaseConfiguration, link->handle); + break; + case CS_EVENT_PM_RESUME: + snd_printdd(KERN_DEBUG "RESUME\n"); + link->state &= ~DEV_SUSPEND; + /* Fall through... */ + case CS_EVENT_CARD_RESET: + snd_printdd(KERN_DEBUG "CARD_RESET\n"); + if (DEV_OK(link)) { + //struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip; + snd_printdd(KERN_DEBUG "requestconfig...\n"); + CardServices(RequestConfiguration, link->handle, &link->conf); + if (chip) { + snd_printdd(KERN_DEBUG "calling snd_vx_resume\n"); + snd_vx_resume(chip); + } + } + snd_printdd(KERN_DEBUG "resume done!\n"); + break; +#endif + } + return 0; +} + +/* we link this module statically with the card modules + * due to the pcmcia symbol problems... + */ +#if 0 +/* + * exported stuffs + */ +EXPORT_SYMBOL(snd_vxpocket_ops); +EXPORT_SYMBOL(snd_vxpocket_attach); +EXPORT_SYMBOL(snd_vxpocket_detach); +EXPORT_SYMBOL(snd_vxpocket_detach_all); +#endif diff -Nru a/sound/pcmcia/vx/vxp440.c b/sound/pcmcia/vx/vxp440.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pcmcia/vx/vxp440.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,14 @@ +#define COMPILE_VXP440 + +/* + add the following as /etc/pcmcia/vxp440.conf: + + device "snd-vxp440" + class "audio" module "snd-vxp440" + + card "Digigram VX-POCKET440" + manfid 0x01f1, 0x0100 + bind "snd-vxp440" +*/ + +#include "vxpocket.c" diff -Nru a/sound/pcmcia/vx/vxp_mixer.c b/sound/pcmcia/vx/vxp_mixer.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pcmcia/vx/vxp_mixer.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,150 @@ +/* + * Driver for Digigram VXpocket soundcards + * + * VX-pocket mixer + * + * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <sound/driver.h> +#include <sound/core.h> +#include <sound/control.h> +#include "vxpocket.h" + +#define chip_t vx_core_t + +#define MIC_LEVEL_MIN 0 +#define MIC_LEVEL_MAX 8 + +/* + * mic level control (for VXPocket) + */ +static int vx_mic_level_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = MIC_LEVEL_MAX; + return 0; +} + +static int vx_mic_level_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + vx_core_t *_chip = snd_kcontrol_chip(kcontrol); + struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; + ucontrol->value.integer.value[0] = chip->mic_level; + return 0; +} + +static int vx_mic_level_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + vx_core_t *_chip = snd_kcontrol_chip(kcontrol); + struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; + down(&_chip->mixer_mutex); + if (chip->mic_level != ucontrol->value.integer.value[0]) { + vx_set_mic_level(_chip, ucontrol->value.integer.value[0]); + chip->mic_level = ucontrol->value.integer.value[0]; + up(&_chip->mixer_mutex); + return 1; + } + up(&_chip->mixer_mutex); + return 0; +} + +static snd_kcontrol_new_t vx_control_mic_level = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Mic Capture Volume", + .info = vx_mic_level_info, + .get = vx_mic_level_get, + .put = vx_mic_level_put, +}; + +/* + * mic boost level control (for VXP440) + */ +static int vx_mic_boost_info(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int vx_mic_boost_get(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + vx_core_t *_chip = snd_kcontrol_chip(kcontrol); + struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; + ucontrol->value.integer.value[0] = chip->mic_level; + return 0; +} + +static int vx_mic_boost_put(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t *ucontrol) +{ + vx_core_t *_chip = snd_kcontrol_chip(kcontrol); + struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; + down(&_chip->mixer_mutex); + if (chip->mic_level != ucontrol->value.integer.value[0]) { + vx_set_mic_boost(_chip, ucontrol->value.integer.value[0]); + chip->mic_level = ucontrol->value.integer.value[0]; + up(&_chip->mixer_mutex); + return 1; + } + up(&_chip->mixer_mutex); + return 0; +} + +static snd_kcontrol_new_t vx_control_mic_boost = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Mic Boost", + .info = vx_mic_boost_info, + .get = vx_mic_boost_get, + .put = vx_mic_boost_put, +}; + + +int vxp_add_mic_controls(vx_core_t *_chip) +{ + struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; + int err; + + /* mute input levels */ + chip->mic_level = 0; + switch (_chip->type) { + case VX_TYPE_VXPOCKET: + vx_set_mic_level(_chip, 0); + break; + case VX_TYPE_VXP440: + vx_set_mic_boost(_chip, 0); + break; + } + + /* mic level */ + switch (_chip->type) { + case VX_TYPE_VXPOCKET: + if ((err = snd_ctl_add(_chip->card, snd_ctl_new1(&vx_control_mic_level, chip))) < 0) + return err; + break; + case VX_TYPE_VXP440: + if ((err = snd_ctl_add(_chip->card, snd_ctl_new1(&vx_control_mic_boost, chip))) < 0) + return err; + break; + } + + return 0; +} + diff -Nru a/sound/pcmcia/vx/vxp_ops.c b/sound/pcmcia/vx/vxp_ops.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pcmcia/vx/vxp_ops.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,616 @@ +/* + * Driver for Digigram VXpocket soundcards + * + * lowlevel routines for VXpocket soundcards + * + * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <sound/driver.h> +#include <linux/delay.h> +#include <sound/core.h> +#include <asm/io.h> +#include "vxpocket.h" + +#define chip_t vx_core_t + + +static int vxp_reg_offset[VX_REG_MAX] = { + [VX_ICR] = 0x00, // ICR + [VX_CVR] = 0x01, // CVR + [VX_ISR] = 0x02, // ISR + [VX_IVR] = 0x03, // IVR + [VX_RXH] = 0x05, // RXH + [VX_RXM] = 0x06, // RXM + [VX_RXL] = 0x07, // RXL + [VX_DMA] = 0x04, // DMA + [VX_CDSP] = 0x08, // CDSP + [VX_LOFREQ] = 0x09, // LFREQ + [VX_HIFREQ] = 0x0a, // HFREQ + [VX_DATA] = 0x0b, // DATA + [VX_MICRO] = 0x0c, // MICRO + [VX_DIALOG] = 0x0d, // DIALOG + [VX_CSUER] = 0x0e, // CSUER + [VX_RUER] = 0x0f, // RUER +}; + + +inline static unsigned long vxp_reg_addr(vx_core_t *_chip, int reg) +{ + struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; + return chip->port + vxp_reg_offset[reg]; +} + +/* + * snd_vx_inb - read a byte from the register + * @offset: register offset + */ +static unsigned char vxp_inb(vx_core_t *chip, int offset) +{ + return inb(vxp_reg_addr(chip, offset)); +} + +/* + * snd_vx_outb - write a byte on the register + * @offset: the register offset + * @val: the value to write + */ +static void vxp_outb(vx_core_t *chip, int offset, unsigned char val) +{ + outb(val, vxp_reg_addr(chip, offset)); +} + +/* + * redefine macros to call directly + */ +#undef vx_inb +#define vx_inb(chip,reg) vxp_inb((vx_core_t*)(chip), VX_##reg) +#undef vx_outb +#define vx_outb(chip,reg,val) vxp_outb((vx_core_t*)(chip), VX_##reg,val) + + +/* + * vx_check_magic - check the magic word on xilinx + * + * returns zero if a magic word is detected, or a negative error code. + */ +static int vx_check_magic(vx_core_t *chip) +{ + unsigned long end_time = jiffies + HZ / 5; + int c; + do { + c = vx_inb(chip, CDSP); + if (c == CDSP_MAGIC) + return 0; + snd_vx_delay(chip, 10); + } while (time_after_eq(end_time, jiffies)); + snd_printk(KERN_ERR "cannot find xilinx magic word (%x)\n", c); + return -EIO; +} + + +/* + * vx_reset_dsp - reset the DSP + */ + +#define XX_DSP_RESET_WAIT_TIME 2 /* ms */ + +static void vxp_reset_dsp(vx_core_t *_chip) +{ + struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; + + /* set the reset dsp bit to 1 */ + vx_outb(chip, CDSP, chip->regCDSP | VXP_CDSP_DSP_RESET_MASK); + vx_inb(chip, CDSP); + mdelay(XX_DSP_RESET_WAIT_TIME); + /* reset the bit */ + chip->regCDSP &= ~VXP_CDSP_DSP_RESET_MASK; + vx_outb(chip, CDSP, chip->regCDSP); + vx_inb(chip, CDSP); + mdelay(XX_DSP_RESET_WAIT_TIME); +} + +/* + * reset codec bit + */ +static void vxp_reset_codec(vx_core_t *_chip) +{ + struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; + + /* Set the reset CODEC bit to 1. */ + vx_outb(chip, CDSP, chip->regCDSP | VXP_CDSP_CODEC_RESET_MASK); + vx_inb(chip, CDSP); + snd_vx_delay(_chip, 10); + /* Set the reset CODEC bit to 0. */ + chip->regCDSP &= ~VXP_CDSP_CODEC_RESET_MASK; + vx_outb(chip, CDSP, chip->regCDSP); + vx_inb(chip, CDSP); + snd_vx_delay(_chip, 1); +} + +/* + * vx_load_xilinx_binary - load the xilinx binary image + * the binary image is the binary array converted from the bitstream file. + */ +static int vxp_load_xilinx_binary(vx_core_t *_chip, const snd_hwdep_dsp_image_t *xilinx) +{ + struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; + unsigned int i; + int c; + int regCSUER, regRUER; + unsigned char *image, data; + + /* Switch to programmation mode */ + chip->regDIALOG |= VXP_DLG_XILINX_REPROG_MASK; + vx_outb(chip, DIALOG, chip->regDIALOG); + + /* Save register CSUER and RUER */ + regCSUER = vx_inb(chip, CSUER); + regRUER = vx_inb(chip, RUER); + + /* reset HF0 and HF1 */ + vx_outb(chip, ICR, 0); + + /* Wait for answer HF2 equal to 1 */ + snd_printdd(KERN_DEBUG "check ISR_HF2\n"); + if (vx_check_isr(_chip, ISR_HF2, ISR_HF2, 20) < 0) + goto _error; + + /* set HF1 for loading xilinx binary */ + vx_outb(chip, ICR, ICR_HF1); + image = xilinx->image; + for (i = 0; i < xilinx->length; i++, image++) { + __get_user(data, image); + if (vx_wait_isr_bit(_chip, ISR_TX_EMPTY) < 0) + goto _error; + vx_outb(chip, TXL, data); + /* wait for reading */ + if (vx_wait_for_rx_full(_chip) < 0) + goto _error; + c = vx_inb(chip, RXL); + if (c != (int)data) + snd_printk(KERN_ERR "vxpocket: load xilinx mismatch at %d: 0x%x != 0x%x\n", i, c, (int)data); + } + + /* reset HF1 */ + vx_outb(chip, ICR, 0); + + /* wait for HF3 */ + if (vx_check_isr(_chip, ISR_HF3, ISR_HF3, 20) < 0) + goto _error; + + /* read the number of bytes received */ + if (vx_wait_for_rx_full(_chip) < 0) + goto _error; + + c = (int)vx_inb(chip, RXH) << 16; + c |= (int)vx_inb(chip, RXM) << 8; + c |= vx_inb(chip, RXL); + + snd_printdd(KERN_DEBUG "xilinx: dsp size received 0x%x, orig 0x%x\n", c, xilinx->length); + + vx_outb(chip, ICR, ICR_HF0); + + /* TEMPO 250ms : wait until Xilinx is downloaded */ + snd_vx_delay(_chip, 300); + + /* test magical word */ + if (vx_check_magic(_chip) < 0) + goto _error; + + /* Restore register 0x0E and 0x0F (thus replacing COR and FCSR) */ + vx_outb(chip, CSUER, regCSUER); + vx_outb(chip, RUER, regRUER); + + /* Reset the Xilinx's signal enabling IO access */ + chip->regDIALOG |= VXP_DLG_XILINX_REPROG_MASK; + vx_outb(chip, DIALOG, chip->regDIALOG); + vx_inb(chip, DIALOG); + snd_vx_delay(_chip, 10); + chip->regDIALOG &= ~VXP_DLG_XILINX_REPROG_MASK; + vx_outb(chip, DIALOG, chip->regDIALOG); + vx_inb(chip, DIALOG); + + /* Reset of the Codec */ + vxp_reset_codec(_chip); + vx_reset_dsp(_chip); + + return 0; + + _error: + vx_outb(chip, CSUER, regCSUER); + vx_outb(chip, RUER, regRUER); + chip->regDIALOG &= ~VXP_DLG_XILINX_REPROG_MASK; + vx_outb(chip, DIALOG, chip->regDIALOG); + return -EIO; +} + + +/* + * vxp_load_dsp - load_dsp callback + */ +static int vxp_load_dsp(vx_core_t *vx, const snd_hwdep_dsp_image_t *dsp) +{ + int err; + + if (*dsp->name) + snd_printdd("loading dsp [%d] %s, size = %d\n", dsp->index, dsp->name, dsp->length); + + switch (dsp->index) { + case 0: + /* xilinx boot */ + if ((err = vx_check_magic(vx)) < 0) + return err; + if ((err = snd_vx_load_boot_image(vx, dsp)) < 0) + return err; + return 0; + case 1: + /* xilinx image */ + return vxp_load_xilinx_binary(vx, dsp); + case 2: + /* DSP boot */ + return snd_vx_dsp_boot(vx, dsp); + case 3: + /* DSP image */ + return snd_vx_dsp_load(vx, dsp); + default: + snd_BUG(); + return -EINVAL; + } +} + + +/* + * vx_test_and_ack - test and acknowledge interrupt + * + * called from irq hander, too + * + * spinlock held! + */ +static int vxp_test_and_ack(vx_core_t *_chip) +{ + struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; + + /* not booted yet? */ + if (! (_chip->chip_status & VX_STAT_XILINX_LOADED)) + return -ENXIO; + + if (! (vx_inb(chip, DIALOG) & VXP_DLG_MEMIRQ_MASK)) + return -EIO; + + /* ok, interrupts generated, now ack it */ + /* set ACQUIT bit up and down */ + vx_outb(chip, DIALOG, chip->regDIALOG | VXP_DLG_ACK_MEMIRQ_MASK); + /* useless read just to spend some time and maintain + * the ACQUIT signal up for a while ( a bus cycle ) + */ + vx_inb(chip, DIALOG); + vx_outb(chip, DIALOG, chip->regDIALOG & ~VXP_DLG_ACK_MEMIRQ_MASK); + + return 0; +} + + +/* + * vx_validate_irq - enable/disable IRQ + */ +static void vxp_validate_irq(vx_core_t *_chip, int enable) +{ + struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; + + /* Set the interrupt enable bit to 1 in CDSP register */ + if (enable) + chip->regCDSP |= VXP_CDSP_VALID_IRQ_MASK; + else + chip->regCDSP &= ~VXP_CDSP_VALID_IRQ_MASK; + vx_outb(chip, CDSP, chip->regCDSP); +} + +/* + * vx_setup_pseudo_dma - set up the pseudo dma read/write mode. + * @do_write: 0 = read, 1 = set up for DMA write + */ +static void vx_setup_pseudo_dma(vx_core_t *_chip, int do_write) +{ + struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; + + /* Interrupt mode and HREQ pin enabled for host transmit / receive data transfers */ + vx_outb(chip, ICR, do_write ? ICR_TREQ : ICR_RREQ); + /* Reset the pseudo-dma register */ + vx_inb(chip, ISR); + vx_outb(chip, ISR, 0); + + /* Select DMA in read/write transfer mode and in 16-bit accesses */ + chip->regDIALOG |= VXP_DLG_DMA16_SEL_MASK; + chip->regDIALOG |= do_write ? VXP_DLG_DMAWRITE_SEL_MASK : VXP_DLG_DMAREAD_SEL_MASK; + vx_outb(chip, DIALOG, chip->regDIALOG); + +} + +/* + * vx_release_pseudo_dma - disable the pseudo-DMA mode + */ +static void vx_release_pseudo_dma(vx_core_t *_chip) +{ + struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; + + /* Disable DMA and 16-bit accesses */ + chip->regDIALOG &= ~(VXP_DLG_DMAWRITE_SEL_MASK| + VXP_DLG_DMAREAD_SEL_MASK| + VXP_DLG_DMA16_SEL_MASK); + vx_outb(chip, DIALOG, chip->regDIALOG); + /* HREQ pin disabled. */ + vx_outb(chip, ICR, 0); +} + +/* + * vx_pseudo_dma_write - write bulk data on pseudo-DMA mode + * @count: data length to transfer in bytes + * + * data size must be aligned to 6 bytes to ensure the 24bit alignment on DSP. + * NB: call with a certain lock! + */ +static void vxp_dma_write(vx_core_t *chip, snd_pcm_runtime_t *runtime, + vx_pipe_t *pipe, int count) +{ + long port = vxp_reg_addr(chip, VX_DMA); + int offset = pipe->hw_ptr; + unsigned short *addr = (unsigned short *)(runtime->dma_area + offset); + + vx_setup_pseudo_dma(chip, 1); + if (offset + count > pipe->buffer_bytes) { + int length = pipe->buffer_bytes - offset; + count -= length; + length >>= 1; /* in 16bit words */ + /* Transfer using pseudo-dma. */ + while (length-- > 0) { + outw(cpu_to_le16(*addr), port); + addr++; + } + addr = (unsigned short *)runtime->dma_area; + pipe->hw_ptr = 0; + } + pipe->hw_ptr += count; + count >>= 1; /* in 16bit words */ + /* Transfer using pseudo-dma. */ + while (count-- > 0) { + outw(cpu_to_le16(*addr), port); + addr++; + } + vx_release_pseudo_dma(chip); +} + + +/* + * vx_pseudo_dma_read - read bulk data on pseudo DMA mode + * @offset: buffer offset in bytes + * @count: data length to transfer in bytes + * + * the read length must be aligned to 6 bytes, as well as write. + * NB: call with a certain lock! + */ +static void vxp_dma_read(vx_core_t *chip, snd_pcm_runtime_t *runtime, + vx_pipe_t *pipe, int count) +{ + struct snd_vxpocket *pchip = (struct snd_vxpocket *)chip; + long port = vxp_reg_addr(chip, VX_DMA); + int offset = pipe->hw_ptr; + unsigned short *addr = (unsigned short *)(runtime->dma_area + offset); + + snd_assert(count % 2 == 0, return); + vx_setup_pseudo_dma(chip, 0); + if (offset + count > pipe->buffer_bytes) { + int length = pipe->buffer_bytes - offset; + count -= length; + length >>= 1; /* in 16bit words */ + /* Transfer using pseudo-dma. */ + while (length-- > 0) + *addr++ = le16_to_cpu(inw(port)); + addr = (unsigned short *)runtime->dma_area; + pipe->hw_ptr = 0; + } + pipe->hw_ptr += count; + count >>= 1; /* in 16bit words */ + /* Transfer using pseudo-dma. */ + while (count-- > 1) + *addr++ = le16_to_cpu(inw(port)); + /* Disable DMA */ + pchip->regDIALOG &= ~VXP_DLG_DMAREAD_SEL_MASK; + vx_outb(chip, DIALOG, pchip->regDIALOG); + /* Read the last word (16 bits) */ + *addr = le16_to_cpu(inw(port)); + /* Disable 16-bit accesses */ + pchip->regDIALOG &= ~VXP_DLG_DMA16_SEL_MASK; + vx_outb(chip, DIALOG, pchip->regDIALOG); + /* HREQ pin disabled. */ + vx_outb(chip, ICR, 0); +} + + +/* + * write a codec data (24bit) + */ +static void vxp_write_codec_reg(vx_core_t *chip, int codec, unsigned int data) +{ + int i; + + /* Activate access to the corresponding codec register */ + if (! codec) + vx_inb(chip, LOFREQ); + else + vx_inb(chip, CODEC2); + + /* We have to send 24 bits (3 x 8 bits). Start with most signif. Bit */ + for (i = 0; i < 24; i++, data <<= 1) + vx_outb(chip, DATA, ((data & 0x800000) ? VX_DATA_CODEC_MASK : 0)); + + /* Terminate access to codec registers */ + vx_inb(chip, HIFREQ); +} + + +/* + * vx_set_mic_boost - set mic boost level (on vxp440 only) + * @boost: 0 = 20dB, 1 = +38dB + */ +void vx_set_mic_boost(vx_core_t *chip, int boost) +{ + struct snd_vxpocket *pchip = (struct snd_vxpocket *)chip; + unsigned long flags; + + if (chip->chip_status & VX_STAT_IS_STALE) + return; + + spin_lock_irqsave(&chip->lock, flags); + if (pchip->regCDSP & P24_CDSP_MICS_SEL_MASK) { + if (boost) { + /* boost: 38 dB */ + pchip->regCDSP &= ~P24_CDSP_MIC20_SEL_MASK; + pchip->regCDSP |= P24_CDSP_MIC38_SEL_MASK; + } else { + /* minimum value: 20 dB */ + pchip->regCDSP |= P24_CDSP_MIC20_SEL_MASK; + pchip->regCDSP &= ~P24_CDSP_MIC38_SEL_MASK; + } + vx_outb(chip, CDSP, pchip->regCDSP); + } + spin_unlock_irqrestore(&chip->lock, flags); +} + +/* + * remap the linear value (0-8) to the actual value (0-15) + */ +static int vx_compute_mic_level(int level) +{ + switch (level) { + case 5: level = 6 ; break; + case 6: level = 8 ; break; + case 7: level = 11; break; + case 8: level = 15; break; + default: break ; + } + return level; +} + +/* + * vx_set_mic_level - set mic level (on vxpocket only) + * @level: the mic level = 0 - 8 (max) + */ +void vx_set_mic_level(vx_core_t *chip, int level) +{ + struct snd_vxpocket *pchip = (struct snd_vxpocket *)chip; + unsigned long flags; + + if (chip->chip_status & VX_STAT_IS_STALE) + return; + + spin_lock_irqsave(&chip->lock, flags); + if (pchip->regCDSP & VXP_CDSP_MIC_SEL_MASK) { + level = vx_compute_mic_level(level); + vx_outb(chip, MICRO, level); + } + spin_unlock_irqrestore(&chip->lock, flags); +} + + +/* + * change the input audio source + */ +static void vxp_change_audio_source(vx_core_t *_chip, int src) +{ + struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; + + switch (src) { + case VX_AUDIO_SRC_DIGITAL: + chip->regCDSP |= VXP_CDSP_DATAIN_SEL_MASK; + vx_outb(chip, CDSP, chip->regCDSP); + break; + case VX_AUDIO_SRC_LINE: + chip->regCDSP &= ~VXP_CDSP_DATAIN_SEL_MASK; + if (_chip->type == VX_TYPE_VXP440) + chip->regCDSP &= ~P24_CDSP_MICS_SEL_MASK; + else + chip->regCDSP &= ~VXP_CDSP_MIC_SEL_MASK; + vx_outb(chip, CDSP, chip->regCDSP); + break; + case VX_AUDIO_SRC_MIC: + chip->regCDSP &= ~VXP_CDSP_DATAIN_SEL_MASK; + /* reset mic levels */ + if (_chip->type == VX_TYPE_VXP440) { + chip->regCDSP &= ~P24_CDSP_MICS_SEL_MASK; + if (chip->mic_level) + chip->regCDSP |= P24_CDSP_MIC38_SEL_MASK; + else + chip->regCDSP |= P24_CDSP_MIC20_SEL_MASK; + vx_outb(chip, CDSP, chip->regCDSP); + } else { + chip->regCDSP |= VXP_CDSP_MIC_SEL_MASK; + vx_outb(chip, CDSP, chip->regCDSP); + vx_outb(chip, MICRO, vx_compute_mic_level(chip->mic_level)); + } + break; + } +} + +/* + * change the clock source + * source = INTERNAL_QUARTZ or UER_SYNC + */ +static void vxp_set_clock_source(vx_core_t *_chip, int source) +{ + struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; + + if (source == INTERNAL_QUARTZ) + chip->regCDSP &= ~VXP_CDSP_CLOCKIN_SEL_MASK; + else + chip->regCDSP |= VXP_CDSP_CLOCKIN_SEL_MASK; + vx_outb(chip, CDSP, chip->regCDSP); +} + + +/* + * reset the board + */ +static void vxp_reset_board(vx_core_t *_chip, int cold_reset) +{ + struct snd_vxpocket *chip = (struct snd_vxpocket *)_chip; + + chip->regCDSP = 0; + chip->regDIALOG = 0; +} + + +/* + * callbacks + */ +/* exported */ +struct snd_vx_ops snd_vxpocket_ops = { + .in8 = vxp_inb, + .out8 = vxp_outb, + .test_and_ack = vxp_test_and_ack, + .validate_irq = vxp_validate_irq, + .write_codec = vxp_write_codec_reg, + .reset_codec = vxp_reset_codec, + .change_audio_source = vxp_change_audio_source, + .set_clock_source = vxp_set_clock_source, + .load_dsp = vxp_load_dsp, + .add_controls = vxp_add_mic_controls, + .reset_dsp = vxp_reset_dsp, + .reset_board = vxp_reset_board, + .dma_write = vxp_dma_write, + .dma_read = vxp_dma_read, +}; diff -Nru a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pcmcia/vx/vxpocket.c Mon Jun 9 23:16:20 2003 @@ -0,0 +1,174 @@ +/* + * Driver for Digigram VXpocket V2/440 soundcards + * + * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + please add the following as /etc/pcmcia/vxpocket.conf: + + device "snd-vxpocket" + class "audio" module "snd-vxpocket" + + card "Digigram VX-POCKET" + manfid 0x01f1, 0x0100 + bind "snd-vxpocket" + + */ + +#include <sound/driver.h> +#include <sound/core.h> +#include <pcmcia/version.h> +#include "vxpocket.h" +#define SNDRV_GET_ID +#include <sound/initval.h> + +/* + */ + +#ifdef COMPILE_VXP440 +#define CARD_NAME "VXPocket440" +#else +#define CARD_NAME "VXPocket" +#endif + +MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); +MODULE_DESCRIPTION("Digigram " CARD_NAME); +MODULE_LICENSE("GPL"); +MODULE_CLASSES("{sound}"); +MODULE_DEVICES("{{Digigram," CARD_NAME "}}"); + +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ +static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ +static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable switches */ +static unsigned int irq_mask = 0xffff; +static int irq_list[4] = { -1 }; +static int ibl[SNDRV_CARDS]; + +MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); +MODULE_PARM_SYNTAX(index, SNDRV_INDEX_DESC); +MODULE_PARM(id, "1-" __MODULE_STRING(SNDRV_CARDS) "s"); +MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard."); +MODULE_PARM_SYNTAX(id, SNDRV_ID_DESC); +MODULE_PARM(enable, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard."); +MODULE_PARM_SYNTAX(enable, SNDRV_ENABLE_DESC); +MODULE_PARM(irq_mask, "i"); +MODULE_PARM_DESC(irq_mask, "IRQ bitmask for " CARD_NAME " soundcard."); +MODULE_PARM(irq_list, "1-4i"); +MODULE_PARM_DESC(irq_list, "List of Available interrupts for " CARD_NAME " soundcard."); +MODULE_PARM(ibl, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); +MODULE_PARM_DESC(ibl, "Capture IBL size for " CARD_NAME " soundcard."); +MODULE_PARM_SYNTAX(ibl, SNDRV_ENABLED); + + +/* + */ + +#ifdef COMPILE_VXP440 +static dev_info_t dev_info = "snd-vxp440"; + +/* 1 DSP, 1 sync UER, 1 sync World Clock (NIY) */ +/* SMPTE (NIY) */ +/* 2 stereo analog input (line/micro) */ +/* 2 stereo analog output */ +/* Only output levels can be modified */ +/* UER, but only for the first two inputs and outputs. */ + +#define NUM_CODECS 2 +#define CARD_TYPE VX_TYPE_VXP440 + +#else +static dev_info_t dev_info = "snd-vxpocket"; + +/* 1 DSP, 1 sync UER */ +/* 1 programmable clock (NIY) */ +/* 1 stereo analog input (line/micro) */ +/* 1 stereo analog output */ +/* Only output levels can be modified */ + +#define NUM_CODECS 1 +#define CARD_TYPE VX_TYPE_VXPOCKET +#endif + + +static struct snd_vx_hardware vxp_hw = { + .name = CARD_NAME, + .type = CARD_TYPE, + + /* hardware specs */ + .num_codecs = NUM_CODECS, + .num_ins = NUM_CODECS, + .num_outs = NUM_CODECS, + .output_level_max = VX_ANALOG_OUT_LEVEL_MAX, +}; + +static struct snd_vxp_entry hw_entry = { + .dev_info = &dev_info, + + /* module parameters */ + .index_table = index, + .id_table = id, + .enable_table = enable, + .irq_mask_p = &irq_mask, + .irq_list = irq_list, + .ibl = ibl, + + /* h/w config */ + .hardware = &vxp_hw, + .ops = &snd_vxpocket_ops, +}; + +/* + */ +static dev_link_t *vxp_attach(void) +{ + return snd_vxpocket_attach(&hw_entry); +} + +static void vxp_detach(dev_link_t *link) +{ + snd_vxpocket_detach(&hw_entry, link); +} + + +/* + * Module entry points + */ + +static int __init init_vxpocket(void) +{ + servinfo_t serv; + + CardServices(GetCardServicesInfo, &serv); + if (serv.Revision != CS_RELEASE_CODE) { + printk(KERN_WARNING "init_vxpocket: Card Services release does not match (%x != %x)!\n", serv.Revision, CS_RELEASE_CODE); + return -1; + } + register_pccard_driver(&dev_info, vxp_attach, vxp_detach); + return 0; +} + +static void __exit exit_vxpocket(void) +{ + unregister_pccard_driver(&dev_info); + snd_vxpocket_detach_all(&hw_entry); +} + +module_init(init_vxpocket); +module_exit(exit_vxpocket); diff -Nru a/sound/pcmcia/vx/vxpocket.h b/sound/pcmcia/vx/vxpocket.h --- /dev/null Wed Dec 31 16:00:00 1969 +++ b/sound/pcmcia/vx/vxpocket.h Mon Jun 9 23:16:20 2003 @@ -0,0 +1,121 @@ +/* + * Driver for Digigram VXpocket soundcards + * + * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __VXPOCKET_H +#define __VXPOCKET_H + +#include <sound/vx_core.h> + +#include <pcmcia/cs_types.h> +#include <pcmcia/cs.h> +#include <pcmcia/cistpl.h> +#include <pcmcia/ds.h> + +struct snd_vxp_entry { + dev_info_t *dev_info; + + /* module parameters */ + int *index_table; + char **id_table; + int *enable_table; + unsigned int *irq_mask_p; + int *irq_list; + int *ibl; + + /* h/w config */ + struct snd_vx_hardware *hardware; + struct snd_vx_ops *ops; + + /* slots */ + vx_core_t *card_list[SNDRV_CARDS]; + dev_link_t *dev_list; /* Linked list of devices */ +}; + +struct snd_vxpocket { + + vx_core_t core; + + unsigned long port; + + int mic_level; /* analog mic level (or boost) */ + + unsigned int regCDSP; /* current CDSP register */ + unsigned int regDIALOG; /* current DIALOG register */ + + int index; + struct snd_vxp_entry *hw_entry; + + /* pcmcia stuff */ + dev_link_t link; + dev_node_t node; +}; + +extern struct snd_vx_ops snd_vxpocket_ops; + +void vx_set_mic_boost(vx_core_t *chip, int boost); +void vx_set_mic_level(vx_core_t *chip, int level); + +/* + * pcmcia stuff + */ +dev_link_t *snd_vxpocket_attach(struct snd_vxp_entry *hw); +void snd_vxpocket_detach(struct snd_vxp_entry *hw, dev_link_t *link); +void snd_vxpocket_detach_all(struct snd_vxp_entry *hw); + +int vxp_add_mic_controls(vx_core_t *chip); + +/* Constants used to access the CDSP register (0x08). */ +#define CDSP_MAGIC 0xA7 /* magic value (for read) */ +/* for write */ +#define VXP_CDSP_CLOCKIN_SEL_MASK 0x80 /* 0 (internal), 1 (AES/EBU) */ +#define VXP_CDSP_DATAIN_SEL_MASK 0x40 /* 0 (analog), 1 (UER) */ +#define VXP_CDSP_SMPTE_SEL_MASK 0x20 +#define VXP_CDSP_RESERVED_MASK 0x10 +#define VXP_CDSP_MIC_SEL_MASK 0x08 +#define VXP_CDSP_VALID_IRQ_MASK 0x04 +#define VXP_CDSP_CODEC_RESET_MASK 0x02 +#define VXP_CDSP_DSP_RESET_MASK 0x01 +/* VXPOCKET 240/440 */ +#define P24_CDSP_MICS_SEL_MASK 0x18 +#define P24_CDSP_MIC20_SEL_MASK 0x10 +#define P24_CDSP_MIC38_SEL_MASK 0x08 + +/* Constants used to access the MEMIRQ register (0x0C). */ +#define P44_MEMIRQ_MASTER_SLAVE_SEL_MASK 0x08 +#define P44_MEMIRQ_SYNCED_ALONE_SEL_MASK 0x04 +#define P44_MEMIRQ_WCLK_OUT_IN_SEL_MASK 0x02 /* Not used */ +#define P44_MEMIRQ_WCLK_UER_SEL_MASK 0x01 /* Not used */ + +/* Micro levels (0x0C) */ + +/* Constants used to access the DIALOG register (0x0D). */ +#define VXP_DLG_XILINX_REPROG_MASK 0x80 /* W */ +#define VXP_DLG_DATA_XICOR_MASK 0x80 /* R */ +#define VXP_DLG_RESERVED4_0_MASK 0x40 +#define VXP_DLG_RESERVED2_0_MASK 0x20 +#define VXP_DLG_RESERVED1_0_MASK 0x10 +#define VXP_DLG_DMAWRITE_SEL_MASK 0x08 /* W */ +#define VXP_DLG_DMAREAD_SEL_MASK 0x04 /* W */ +#define VXP_DLG_MEMIRQ_MASK 0x02 /* R */ +#define VXP_DLG_DMA16_SEL_MASK 0x02 /* W */ +#define VXP_DLG_ACK_MEMIRQ_MASK 0x01 /* R/W */ + + +#endif /* __VXPOCKET_H */ diff -Nru a/sound/ppc/awacs.c b/sound/ppc/awacs.c --- a/sound/ppc/awacs.c Mon Jun 9 23:16:13 2003 +++ b/sound/ppc/awacs.c Mon Jun 9 23:16:13 2003 @@ -32,7 +32,7 @@ #define chip_t pmac_t -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) || defined(CONFIG_ADB_CUDA) +#ifdef CONFIG_ADB_CUDA #define PMAC_AMP_AVAIL #endif @@ -43,11 +43,7 @@ unsigned char amp_tone[2]; } awacs_amp_t; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) -#define CHECK_CUDA_AMP() (adb_hardware == ADB_VIACUDA) -#else #define CHECK_CUDA_AMP() (sys_ctrler == SYS_CTRLER_CUDA) -#endif #endif /* PMAC_AMP_AVAIL */ @@ -649,8 +645,22 @@ } #ifdef CONFIG_PMAC_PBOOK +static void snd_pmac_awacs_suspend(pmac_t *chip) +{ + snd_pmac_awacs_write_noreg(chip, 1, (chip->awacs_reg[1] + | MASK_AMUTE | MASK_CMUTE)); +} + static void snd_pmac_awacs_resume(pmac_t *chip) { + if (machine_is_compatible("PowerBook3,1") + || machine_is_compatible("PowerBook3,2")) { + do_mdelay(100, 0); + snd_pmac_awacs_write_reg(chip, 1, + chip->awacs_reg[1] & ~MASK_PAROUT); + do_mdelay(300, 0); + } + awacs_restore_all_regs(chip, 0); if (chip->model == PMAC_SCREAMER) { /* reset power bits in reg 6 */ @@ -868,6 +878,7 @@ */ chip->set_format = snd_pmac_awacs_set_format; #ifdef CONFIG_PMAC_PBOOK + chip->suspend = snd_pmac_awacs_suspend; chip->resume = snd_pmac_awacs_resume; #endif #ifdef PMAC_SUPPORT_AUTOMUTE diff -Nru a/sound/ppc/keywest.c b/sound/ppc/keywest.c --- a/sound/ppc/keywest.c Mon Jun 9 23:16:19 2003 +++ b/sound/ppc/keywest.c Mon Jun 9 23:16:19 2003 @@ -49,6 +49,10 @@ }; +#ifndef i2c_device_name +#define i2c_device_name(x) ((x)->dev.name) +#endif + static int keywest_attach_adapter(struct i2c_adapter *adapter) { int err; @@ -57,20 +61,21 @@ if (! keywest_ctx) return -EINVAL; - if (strncmp(adapter->name, "mac-io", 6)) + if (strncmp(i2c_device_name(adapter), "mac-io", 6)) return 0; /* ignored */ new_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL); if (! new_client) return -ENOMEM; + memset(new_client, 0, sizeof(*new_client)); new_client->addr = keywest_ctx->addr; - new_client->data = keywest_ctx; + i2c_set_clientdata(new_client, keywest_ctx); new_client->adapter = adapter; new_client->driver = &keywest_driver; new_client->flags = 0; - strcpy(new_client->name, keywest_ctx->name); + strcpy(i2c_device_name(new_client), keywest_ctx->name); new_client->id = keywest_ctx->id++; /* Automatically unique */ keywest_ctx->client = new_client; diff -Nru a/sound/ppc/pmac.c b/sound/ppc/pmac.c --- a/sound/ppc/pmac.c Mon Jun 9 23:16:20 2003 +++ b/sound/ppc/pmac.c Mon Jun 9 23:16:20 2003 @@ -36,17 +36,6 @@ #include <asm/feature.h> #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) -#define pmu_suspend() /**/ -#define pmu_resume() /**/ -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18) -#define request_OF_resource(io,num,str) 1 -#define release_OF_resource(io,num) /**/ -#endif - - #define chip_t pmac_t @@ -1222,9 +1211,12 @@ spin_lock_irqsave(&chip->reg_lock, flags); snd_pmac_beep_stop(chip); spin_unlock_irqrestore(&chip->reg_lock, flags); - disable_irq(chip->irq); - disable_irq(chip->tx_irq); - disable_irq(chip->rx_irq); + if (chip->irq >= 0) + disable_irq(chip->irq); + if (chip->tx_irq >= 0) + disable_irq(chip->tx_irq); + if (chip->rx_irq >= 0) + disable_irq(chip->rx_irq); snd_pmac_sound_feature(chip, 0); snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); } @@ -1248,9 +1240,12 @@ snd_pmac_pcm_set_format(chip); - enable_irq(chip->irq); - enable_irq(chip->tx_irq); - enable_irq(chip->rx_irq); + if (chip->irq >= 0) + enable_irq(chip->irq); + if (chip->tx_irq >= 0) + enable_irq(chip->tx_irq); + if (chip->rx_irq >= 0) + enable_irq(chip->rx_irq); snd_power_change_state(card, SNDRV_CTL_POWER_D0); } diff -Nru a/sound/ppc/pmac.h b/sound/ppc/pmac.h --- a/sound/ppc/pmac.h Mon Jun 9 23:16:15 2003 +++ b/sound/ppc/pmac.h Mon Jun 9 23:16:15 2003 @@ -27,18 +27,12 @@ #include <sound/pcm.h> #include "awacs.h" -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) -#include <asm/adb.h> -#include <asm/cuda.h> -#include <asm/pmu.h> -#else /* 2.4.0 kernel */ #include <linux/adb.h> #ifdef CONFIG_ADB_CUDA #include <linux/cuda.h> #endif #ifdef CONFIG_ADB_PMU #include <linux/pmu.h> -#endif #endif #include <linux/nvram.h> #include <linux/tty.h> diff -Nru a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c --- a/sound/ppc/tumbler.c Mon Jun 9 23:16:05 2003 +++ b/sound/ppc/tumbler.c Mon Jun 9 23:16:05 2003 @@ -27,6 +27,7 @@ #include <linux/kmod.h> #include <linux/slab.h> #include <linux/interrupt.h> +#include <linux/workqueue.h> #include <sound/core.h> #include <asm/io.h> #include <asm/irq.h> @@ -79,7 +80,7 @@ int active_state; } pmac_gpio_t; -typedef struct pmac_tumber_t { +typedef struct pmac_tumbler_t { pmac_keywest_t i2c; pmac_gpio_t audio_reset; pmac_gpio_t amp_mute; @@ -92,11 +93,12 @@ unsigned int mix_vol[VOL_IDX_LAST_MIX][2]; /* stereo volumes for tas3004 */ int drc_range; int drc_enable; +#ifdef CONFIG_PMAC_PBOOK + struct work_struct resume_workq; +#endif } pmac_tumbler_t; -#define number_of(ary) (sizeof(ary) / sizeof(ary[0])) - /* */ @@ -168,16 +170,16 @@ left_vol = 0; else { left_vol = mix->master_vol[0]; - if (left_vol >= number_of(master_volume_table)) - left_vol = number_of(master_volume_table) - 1; + if (left_vol >= ARRAY_SIZE(master_volume_table)) + left_vol = ARRAY_SIZE(master_volume_table) - 1; left_vol = master_volume_table[left_vol]; } if (! mix->master_switch[1]) right_vol = 0; else { right_vol = mix->master_vol[1]; - if (right_vol >= number_of(master_volume_table)) - right_vol = number_of(master_volume_table) - 1; + if (right_vol >= ARRAY_SIZE(master_volume_table)) + right_vol = ARRAY_SIZE(master_volume_table) - 1; right_vol = master_volume_table[right_vol]; } @@ -203,7 +205,7 @@ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 2; uinfo->value.integer.min = 0; - uinfo->value.integer.max = number_of(master_volume_table) - 1; + uinfo->value.integer.max = ARRAY_SIZE(master_volume_table) - 1; return 0; } @@ -442,7 +444,7 @@ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 1; uinfo->value.integer.min = 0; - uinfo->value.integer.max = info->max; + uinfo->value.integer.max = info->max - 1; return 0; } @@ -479,7 +481,7 @@ .index = VOL_IDX_PCM_MONO, .reg = TAS_REG_PCM, .bytes = 3, - .max = number_of(mixer_volume_table), + .max = ARRAY_SIZE(mixer_volume_table), .table = mixer_volume_table, }; @@ -487,7 +489,7 @@ .index = VOL_IDX_BASS, .reg = TAS_REG_BASS, .bytes = 1, - .max = number_of(bass_volume_table), + .max = ARRAY_SIZE(bass_volume_table), .table = bass_volume_table, }; @@ -495,7 +497,7 @@ .index = VOL_IDX_TREBLE, .reg = TAS_REG_TREBLE, .bytes = 1, - .max = number_of(treble_volume_table), + .max = ARRAY_SIZE(treble_volume_table), .table = treble_volume_table, }; @@ -504,7 +506,7 @@ .index = VOL_IDX_BASS, .reg = TAS_REG_BASS, .bytes = 1, - .max = number_of(snapper_bass_volume_table), + .max = ARRAY_SIZE(snapper_bass_volume_table), .table = snapper_bass_volume_table, }; @@ -512,7 +514,7 @@ .index = VOL_IDX_TREBLE, .reg = TAS_REG_TREBLE, .bytes = 1, - .max = number_of(snapper_treble_volume_table), + .max = ARRAY_SIZE(snapper_treble_volume_table), .table = snapper_treble_volume_table, }; @@ -546,8 +548,8 @@ unsigned char block[9]; vol = mix->mix_vol[idx][ch]; - if (vol >= number_of(mixer_volume_table)) { - vol = number_of(mixer_volume_table) - 1; + if (vol >= ARRAY_SIZE(mixer_volume_table)) { + vol = ARRAY_SIZE(mixer_volume_table) - 1; mix->mix_vol[idx][ch] = vol; } @@ -579,7 +581,7 @@ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 2; uinfo->value.integer.min = 0; - uinfo->value.integer.max = number_of(mixer_volume_table) - 1; + uinfo->value.integer.max = ARRAY_SIZE(mixer_volume_table) - 1; return 0; } @@ -867,6 +869,8 @@ { pmac_tumbler_t *mix = chip->mixer_data; + write_audio_gpio(&mix->audio_reset, 0); + mdelay(200); write_audio_gpio(&mix->audio_reset, 1); mdelay(100); write_audio_gpio(&mix->audio_reset, 0); @@ -875,29 +879,47 @@ #ifdef CONFIG_PMAC_PBOOK /* resume mixer */ -static void tumbler_resume(pmac_t *chip) +/* we call the i2c transfer in a workqueue because it may need either schedule() + * or completion from timer interrupts. + */ +static void tumbler_resume_work(void *arg) { + pmac_t *chip = (pmac_t *)arg; pmac_tumbler_t *mix = chip->mixer_data; - snd_assert(mix, return); + tumbler_reset_audio(chip); - if (mix->i2c.client) - tumbler_init_client(&mix->i2c); + if (mix->i2c.client) { + if (tumbler_init_client(&mix->i2c) < 0) + printk(KERN_ERR "tumbler_init_client error\n"); + } else + printk(KERN_ERR "tumbler: i2c is not initialized\n"); if (chip->model == PMAC_TUMBLER) { tumbler_set_mono_volume(mix, &tumbler_pcm_vol_info); tumbler_set_mono_volume(mix, &tumbler_bass_vol_info); tumbler_set_mono_volume(mix, &tumbler_treble_vol_info); + tumbler_set_drc(mix); } else { snapper_set_mix_vol(mix, VOL_IDX_PCM); snapper_set_mix_vol(mix, VOL_IDX_PCM2); snapper_set_mix_vol(mix, VOL_IDX_ADC); tumbler_set_mono_volume(mix, &tumbler_bass_vol_info); tumbler_set_mono_volume(mix, &tumbler_treble_vol_info); + snapper_set_drc(mix); } - tumbler_set_drc(mix); tumbler_set_master_volume(mix); if (chip->update_automute) chip->update_automute(chip, 0); } + +static void tumbler_resume(pmac_t *chip) +{ + pmac_tumbler_t *mix = chip->mixer_data; + snd_assert(mix, return); + INIT_WORK(&mix->resume_workq, tumbler_resume_work, chip); + if (schedule_work(&mix->resume_workq)) + return; + printk(KERN_ERR "ALSA tumbler: cannot schedule resume-workqueue.\n"); +} #endif /* initialize tumbler */ @@ -970,9 +992,6 @@ chip->mixer_data = mix; chip->mixer_free = tumbler_cleanup; - if ((err = tumbler_init(chip)) < 0) - return err; - /* set up TAS */ tas_node = find_devices("deq"); if (tas_node == NULL) @@ -1002,12 +1021,12 @@ sprintf(chip->card->mixername, "PowerMac %s", chipname); if (chip->model == PMAC_TUMBLER) { - for (i = 0; i < number_of(tumbler_mixers); i++) { + for (i = 0; i < ARRAY_SIZE(tumbler_mixers); i++) { if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&tumbler_mixers[i], chip))) < 0) return err; } } else { - for (i = 0; i < number_of(snapper_mixers); i++) { + for (i = 0; i < ARRAY_SIZE(snapper_mixers); i++) { if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snapper_mixers[i], chip))) < 0) return err; } @@ -1017,6 +1036,9 @@ return err; chip->speaker_sw_ctl = snd_ctl_new1(&tumbler_speaker_sw, chip); if ((err = snd_ctl_add(chip->card, chip->speaker_sw_ctl)) < 0) + return err; + + if ((err = tumbler_init(chip)) < 0) return err; #ifdef CONFIG_PMAC_PBOOK diff -Nru a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c --- a/sound/sparc/cs4231.c Mon Jun 9 23:16:06 2003 +++ b/sound/sparc/cs4231.c Mon Jun 9 23:16:06 2003 @@ -716,10 +716,12 @@ case SNDRV_PCM_TRIGGER_STOP: { unsigned int what = 0; - snd_pcm_substream_t *s = substream; + snd_pcm_substream_t *s; + struct list_head *pos; unsigned long flags; - do { + snd_pcm_group_for_each(pos, substream) { + s = snd_pcm_group_substream_entry(pos); if (s == chip->playback_substream) { what |= CS4231_PLAYBACK_ENABLE; snd_pcm_trigger_done(s, substream); @@ -727,8 +729,7 @@ what |= CS4231_RECORD_ENABLE; snd_pcm_trigger_done(s, substream); } - s = s->link_next; - } while (s != substream); + } #if 0 printk("TRIGGER: what[%x] on(%d)\n", diff -Nru a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c --- a/sound/usb/usbaudio.c Mon Jun 9 23:16:16 2003 +++ b/sound/usb/usbaudio.c Mon Jun 9 23:16:16 2003 @@ -55,6 +55,7 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card */ static int vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Vendor ID for this card */ static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; /* Product ID for this card */ +static int nrpacks = 4; /* max. number of packets per urb */ MODULE_PARM(index, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(index, "Index value for the USB audio adapter."); @@ -71,6 +72,9 @@ MODULE_PARM(pid, "1-" __MODULE_STRING(SNDRV_CARDS) "i"); MODULE_PARM_DESC(pid, "Product ID for the USB audio device."); MODULE_PARM_SYNTAX(pid, SNDRV_ENABLED ",allows:{{-1,0xffff}},base:16"); +MODULE_PARM(nrpacks, "i"); +MODULE_PARM_DESC(nrpacks, "Max. number of packets per URB."); +MODULE_PARM_SYNTAX(nrpacks, SNDRV_ENABLED ",allows:{{2,10}}"); /* @@ -98,7 +102,7 @@ * */ -#define NRPACKS 4 /* 4ms per urb */ +#define MAX_PACKS 10 #define MAX_URBS 5 /* max. 20ms long packets */ #define SYNC_URBS 2 /* always two urbs for sync */ #define MIN_PACKS_URB 1 /* minimum 1 packet per urb */ @@ -111,12 +115,15 @@ struct list_head list; snd_pcm_format_t format; /* format type */ unsigned int channels; /* # channels */ + unsigned int nonaudio: 1; /* non-audio (type II) */ + unsigned int frame_size; /* samples per frame for non-audio */ int iface; /* interface number */ unsigned char altsetting; /* corresponding alternate setting */ unsigned char altset_idx; /* array index of altenate setting */ unsigned char attributes; /* corresponding attributes of cs endpoint */ unsigned char endpoint; /* endpoint */ unsigned char ep_attr; /* endpoint attributes */ + unsigned int maxpacksize; /* max. packet size */ unsigned int rates; /* rate bitmasks */ unsigned int rate_min, rate_max; /* min/max rates */ unsigned int nr_rates; /* number of rate table entries */ @@ -159,6 +166,7 @@ unsigned int curpacksize; /* current packet size in bytes (for capture) */ unsigned int curframesize; /* current packet size in frames (for capture) */ unsigned int fill_max: 1; /* fill max packet size always */ + unsigned int nonaudio: 1; /* Type II format (MPEG, AC3) */ unsigned int running: 1; /* running status */ @@ -172,7 +180,7 @@ unsigned int nurbs; /* # urbs */ snd_urb_ctx_t dataurb[MAX_URBS]; /* data urb table */ snd_urb_ctx_t syncurb[SYNC_URBS]; /* sync urb table */ - char syncbuf[SYNC_URBS * NRPACKS * 3]; /* sync buffer; it's so small - let's get static */ + char syncbuf[SYNC_URBS * MAX_PACKS * 3]; /* sync buffer; it's so small - let's get static */ char *tmpbuf; /* temporary buffer for playback */ u64 formats; /* format bitmasks (all or'ed) */ @@ -401,10 +409,14 @@ urb->iso_frame_desc[i].actual_length < 3) continue; f = combine_triple(cp); +#if 0 if (f < subs->freqn - (subs->freqn>>3) || f > subs->freqmax) { - snd_printd(KERN_WARNING "requested frequency %u (nominal %u) out of range!\n", f, subs->freqn); + snd_printd(KERN_WARNING "requested frequency %d (%u,%03uHz) out of range (current nominal %d (%u,%03uHz))\n", + f, f >> 14, (f & ((1 << 14) - 1) * 1000) / ((1 << 14) - 1), + subs->freqn, subs->freqn >> 14, (subs->freqn & ((1 << 14) - 1) * 1000) / ((1 << 14) - 1)); continue; } +#endif found = f; } if (found) { @@ -459,6 +471,22 @@ subs->transfer_sched += counts; if (subs->transfer_sched >= runtime->period_size) { subs->transfer_sched -= runtime->period_size; + if (subs->nonaudio) { + if (subs->transfer_sched > 0) { + /* FIXME: fill-max mode is not supported yet */ + offs -= subs->transfer_sched; + counts -= subs->transfer_sched; + urb->iso_frame_desc[i].length = counts * stride; + subs->transfer_sched = 0; + } + i++; + if (i < ctx->packets) { + /* add a transfer delimiter */ + urb->iso_frame_desc[i].offset = offs * stride; + urb->iso_frame_desc[i].length = 0; + urb->number_of_packets++; + } + } break; } } @@ -815,7 +843,7 @@ /* allocate a temporary buffer for playback */ if (is_playback) { - subs->tmpbuf = kmalloc(maxsize * NRPACKS, GFP_KERNEL); + subs->tmpbuf = kmalloc(maxsize * nrpacks, GFP_KERNEL); if (! subs->tmpbuf) { snd_printk(KERN_ERR "cannot malloc tmpbuf\n"); return -ENOMEM; @@ -826,16 +854,16 @@ total_packs = (frames_to_bytes(runtime, runtime->period_size) + maxsize - 1) / maxsize; if (total_packs < 2 * MIN_PACKS_URB) total_packs = 2 * MIN_PACKS_URB; - subs->nurbs = (total_packs + NRPACKS - 1) / NRPACKS; + subs->nurbs = (total_packs + nrpacks - 1) / nrpacks; if (subs->nurbs > MAX_URBS) { /* too much... */ subs->nurbs = MAX_URBS; - total_packs = MAX_URBS * NRPACKS; + total_packs = MAX_URBS * nrpacks; } n = total_packs; for (i = 0; i < subs->nurbs; i++) { - npacks[i] = n > NRPACKS ? NRPACKS : n; - n -= NRPACKS; + npacks[i] = n > nrpacks ? nrpacks : n; + n -= nrpacks; } if (subs->nurbs <= 1) { /* too little - we need at least two packets @@ -865,6 +893,8 @@ u->subs = subs; u->transfer = 0; u->packets = npacks[i]; + if (subs->nonaudio) + u->packets++; /* for transfer delimiter */ if (! is_playback) { /* allocate a capture buffer per urb */ u->buf = kmalloc(maxsize * u->packets, GFP_KERNEL); @@ -892,14 +922,14 @@ snd_urb_ctx_t *u = &subs->syncurb[i]; u->index = i; u->subs = subs; - u->packets = NRPACKS; + u->packets = nrpacks; u->urb = usb_alloc_urb(u->packets, GFP_KERNEL); if (! u->urb) { release_substream_urbs(subs, 0); return -ENOMEM; } - u->urb->transfer_buffer = subs->syncbuf + i * NRPACKS * 3; - u->urb->transfer_buffer_length = NRPACKS * 3; + u->urb->transfer_buffer = subs->syncbuf + i * nrpacks * 3; + u->urb->transfer_buffer_length = nrpacks * 3; u->urb->dev = subs->dev; u->urb->pipe = subs->syncpipe; u->urb->transfer_flags = URB_ISO_ASAP | UNLINK_FLAGS; @@ -918,6 +948,7 @@ static struct audioformat *find_format(snd_usb_substream_t *subs, snd_pcm_runtime_t *runtime) { struct list_head *p; + struct audioformat *found = NULL; list_for_each(p, &subs->fmt_list) { struct audioformat *fp; @@ -927,16 +958,20 @@ continue; if (runtime->rate < fp->rate_min || runtime->rate > fp->rate_max) continue; - if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) - return fp; - else { + if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) { + if (! found || fp->maxpacksize > found->maxpacksize) + found = fp; + } else { unsigned int i; for (i = 0; i < fp->nr_rates; i++) - if (fp->rate_table[i] == runtime->rate) - return fp; + if (fp->rate_table[i] == runtime->rate) { + if (! found || fp->maxpacksize > found->maxpacksize) + found = fp; + break; + } } } - return NULL; + return found; } @@ -1065,13 +1100,6 @@ attr = fmt->ep_attr & EP_ATTR_MASK; if ((is_playback && attr == EP_ATTR_ASYNC) || (! is_playback && attr == EP_ATTR_ADAPTIVE)) { - /* - * QUIRK: plantronics headset has adaptive-in - * although it's really not... - */ - if (dev->descriptor.idVendor == 0x047f && - dev->descriptor.idProduct == 0x0ca1) - goto _ok; /* check endpoint */ if (altsd->bNumEndpoints < 2 || get_endpoint(alts, 1)->bmAttributes != 0x01 || @@ -1095,7 +1123,6 @@ subs->syncinterval = get_endpoint(alts, 1)->bRefresh; } - _ok: if ((err = init_usb_pitch(dev, subs->interface, alts, fmt)) < 0 || (err = init_usb_sample_rate(dev, subs->interface, alts, fmt, runtime->rate)) < 0) @@ -1401,6 +1428,25 @@ if (rates[i]) rmaster = rates[i]; } + /* check whether channels match for all distinct rates */ + memset(channels, 0, sizeof(channels)); + list_for_each(p, &subs->fmt_list) { + struct audioformat *f; + f = list_entry(p, struct audioformat, list); + if (f->rates & SNDRV_PCM_RATE_CONTINUOUS) + continue; + for (i = 0; i < 32; i++) { + if (f->rates & (1 << i)) + channels[i] |= (1 << f->channels); + } + } + cmaster = 0; + for (i = 0; i < 32; i++) { + if (cmaster != channels[i] && cmaster && channels[i]) + return 1; + if (channels[i]) + cmaster = channels[i]; + } return 0; } @@ -1434,12 +1480,17 @@ runtime->hw.channels_min = fp->channels; if (runtime->hw.channels_max < fp->channels) runtime->hw.channels_max = fp->channels; + if (fp->nonaudio && fp->frame_size > 0) { + /* FIXME: there might be more than one audio formats... */ + runtime->hw.period_bytes_min = runtime->hw.period_bytes_max = + fp->frame_size; + } } /* set the period time minimum 1ms */ snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, 1000 * MIN_PACKS_URB, - /*(NRPACKS * MAX_URBS) * 1000*/ UINT_MAX); + /*(nrpacks * MAX_URBS) * 1000*/ UINT_MAX); if (check_hw_params_convention(subs)) { hwc_debug("setting extra hw constraints...\n"); @@ -1598,11 +1649,9 @@ * entry point for linux usb interface */ -#ifndef OLD_USB static int usb_audio_probe(struct usb_interface *intf, const struct usb_device_id *id); static void usb_audio_disconnect(struct usb_interface *intf); -#endif static struct usb_device_id usb_audio_ids [] = { #include "usbquirks.h" @@ -1615,12 +1664,10 @@ MODULE_DEVICE_TABLE (usb, usb_audio_ids); static struct usb_driver usb_audio_driver = { + .owner = THIS_MODULE, .name = "snd-usb-audio", .probe = usb_audio_probe, .disconnect = usb_audio_disconnect, -#ifdef OLD_USB - .driver_list = LIST_HEAD_INIT(usb_audio_driver.driver_list), -#endif .id_table = usb_audio_ids, }; @@ -1659,6 +1706,8 @@ } snd_iprintf(buffer, "\n"); } + // snd_iprintf(buffer, " Max Packet Size = %d\n", fp->maxpacksize); + // snd_iprintf(buffer, " EP Attribute = 0x%x\n", fp->attributes); } } @@ -1737,6 +1786,7 @@ subs->formats |= 1ULL << fp->format; subs->endpoint = fp->endpoint; subs->num_formats++; + subs->nonaudio = fp->nonaudio; } @@ -1799,6 +1849,13 @@ if (! subs->endpoint) break; if (subs->endpoint == fp->endpoint) { + if (fp->nonaudio) { + if (!subs->nonaudio || subs->formats != (1ULL << fp->format)) + continue; /* non-linear formats are handled exclusively */ + } else { + if (subs->nonaudio) + continue; + } list_add_tail(&fp->list, &subs->fmt_list); subs->num_formats++; subs->formats |= 1ULL << fp->format; @@ -1854,62 +1911,52 @@ /* - * parse the audio format type descriptor + * parse the audio format type I descriptor * and returns the corresponding pcm format + * + * @dev: usb device + * @fp: audioformat record + * @format: the format tag (wFormatTag) + * @fmt: the format type descriptor */ -static int parse_audio_format_type(struct usb_device *dev, int iface_no, int altno, - int format, unsigned char *fmt) +static int parse_audio_format_i_type(struct usb_device *dev, struct audioformat *fp, + int format, unsigned char *fmt) { - int format_type = fmt[3]; int pcm_format; + int sample_width, sample_bytes; - /* FIXME: needed support for TYPE II and III */ - if (format_type != USB_FORMAT_TYPE_I) { - snd_printd(KERN_INFO "%d:%u:%d : format type %d is not supported yet\n", - dev->devnum, iface_no, altno, format_type); - return -1; - } - /* FIXME: correct endianess and sign? */ pcm_format = -1; + sample_width = fmt[6]; + sample_bytes = fmt[5]; switch (format) { case 0: /* some devices don't define this correctly... */ - snd_printd(KERN_INFO "%d:%u:%d : format type 0 is detected, processed as PCM\n", - dev->devnum, iface_no, altno); + snd_printdd(KERN_INFO "%d:%u:%d : format type 0 is detected, processed as PCM\n", + dev->devnum, fp->iface, fp->altsetting); /* fall-through */ case USB_AUDIO_FORMAT_PCM: + if (sample_width > sample_bytes * 8) { + snd_printk(KERN_INFO "%d:%u:%d : sample bitwidth %d in over sample bytes %d\n", + dev->devnum, fp->iface, fp->altsetting, + sample_width, sample_bytes); + } /* check the format byte size */ - switch (fmt[6]) { - case 8: + switch (fmt[5]) { + case 1: pcm_format = SNDRV_PCM_FORMAT_U8; break; - case 16: + case 2: pcm_format = SNDRV_PCM_FORMAT_S16_LE; break; - case 18: - case 20: - if (fmt[5] == 3) - pcm_format = SNDRV_PCM_FORMAT_S24_3LE; - else - snd_printk(KERN_ERR "%d:%u:%d : non-supported sample bit %d in %d bytes\n", - dev->devnum, iface_no, altno, fmt[6], fmt[5]); - break; - case 24: - if (fmt[5] == 4) - /* FIXME: correct? or S32_LE? */ - pcm_format = SNDRV_PCM_FORMAT_S24_LE; - else if (fmt[5] == 3) - pcm_format = SNDRV_PCM_FORMAT_S24_3LE; - else - snd_printk(KERN_ERR "%d:%u:%d : non-supported sample bit %d in %d bytes\n", - dev->devnum, iface_no, altno, format, fmt[5]); + case 3: + pcm_format = SNDRV_PCM_FORMAT_S24_3LE; break; - case 32: + case 4: pcm_format = SNDRV_PCM_FORMAT_S32_LE; break; default: snd_printk(KERN_INFO "%d:%u:%d : unsupported sample bitwidth %d in %d bytes\n", - dev->devnum, iface_no, altno, fmt[6], fmt[5]); + dev->devnum, fp->iface, fp->altsetting, sample_width, sample_bytes); break; } break; @@ -1931,13 +1978,168 @@ break; default: snd_printk(KERN_INFO "%d:%u:%d : unsupported format type %d\n", - dev->devnum, iface_no, altno, format); + dev->devnum, fp->iface, fp->altsetting, format); break; } return pcm_format; } +/* + * parse the format descriptor and stores the possible sample rates + * on the audioformat table. + * + * @dev: usb device + * @fp: audioformat record + * @fmt: the format descriptor + * @offset: the start offset of descriptor pointing the rate type + * (7 for type I and II, 8 for type II) + */ +static int parse_audio_format_rates(struct usb_device *dev, struct audioformat *fp, + unsigned char *fmt, int offset) +{ + int nr_rates = fmt[offset]; + if (fmt[0] < offset + 1 + 3 * (nr_rates ? nr_rates : 2)) { + snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n", + dev->devnum, fp->iface, fp->altsetting); + return -1; + } + + if (nr_rates) { + /* + * build the rate table and bitmap flags + */ + int r, idx, c; + /* this table corresponds to the SNDRV_PCM_RATE_XXX bit */ + static unsigned int conv_rates[] = { + 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, + 64000, 88200, 96000, 176400, 192000 + }; + fp->rate_table = kmalloc(sizeof(int) * nr_rates, GFP_KERNEL); + if (fp->rate_table == NULL) { + snd_printk(KERN_ERR "cannot malloc\n"); + return -1; + } + + fp->nr_rates = nr_rates; + fp->rate_min = fp->rate_max = combine_triple(&fmt[8]); + for (r = 0, idx = offset + 1; r < nr_rates; r++, idx += 3) { + unsigned int rate = fp->rate_table[r] = combine_triple(&fmt[idx]); + if (rate < fp->rate_min) + fp->rate_min = rate; + else if (rate > fp->rate_max) + fp->rate_max = rate; + for (c = 0; c < (int)ARRAY_SIZE(conv_rates); c++) { + if (rate == conv_rates[c]) { + fp->rates |= (1 << c); + break; + } + } + } + } else { + /* continuous rates */ + fp->rates = SNDRV_PCM_RATE_CONTINUOUS; + fp->rate_min = combine_triple(&fmt[offset + 1]); + fp->rate_max = combine_triple(&fmt[offset + 4]); + } + return 0; +} + +/* + * parse the format type I and III descriptors + */ +static int parse_audio_format_i(struct usb_device *dev, struct audioformat *fp, + int format, unsigned char *fmt) +{ + int pcm_format; + + if (fmt[3] == USB_FORMAT_TYPE_III) { + /* FIXME: the format type is really IECxxx + * but we give normal PCM format to get the existing + * apps working... + */ + pcm_format = SNDRV_PCM_FORMAT_S16_LE; + } else { + pcm_format = parse_audio_format_i_type(dev, fp, format, fmt); + if (pcm_format < 0) + return -1; + } + fp->format = pcm_format; + fp->channels = fmt[4]; + if (fp->channels < 1) { + snd_printk(KERN_ERR "%d:%u:%d : invalid channels %d\n", + dev->devnum, fp->iface, fp->altsetting, fp->channels); + return -1; + } + return parse_audio_format_rates(dev, fp, fmt, 7); +} + +/* + * prase the format type II descriptor + */ +static int parse_audio_format_ii(struct usb_device *dev, struct audioformat *fp, + int format, unsigned char *fmt) +{ + int brate, framesize; + switch (format) { + case USB_AUDIO_FORMAT_AC3: + /* FIXME: there is no AC3 format defined yet */ + // fp->format = SNDRV_PCM_FORMAT_AC3; + fp->format = SNDRV_PCM_FORMAT_U8; /* temporarily hack to receive byte streams */ + break; + case USB_AUDIO_FORMAT_MPEG: + fp->format = SNDRV_PCM_FORMAT_MPEG; + break; + default: + snd_printd(KERN_INFO "%d:%u:%d : unknown format tag 0x%x is detected. processed as MPEG.\n", + dev->devnum, fp->iface, fp->altsetting, format); + fp->format = SNDRV_PCM_FORMAT_MPEG; + break; + } + fp->channels = 1; + fp->nonaudio = 1; + brate = combine_word(&fmt[4]); /* fmt[4,5] : wMaxBitRate (in kbps) */ + framesize = combine_word(&fmt[6]); /* fmt[6,7]: wSamplesPerFrame */ + snd_printd(KERN_INFO "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize); + fp->frame_size = framesize; + return parse_audio_format_rates(dev, fp, fmt, 8); /* fmt[8..] sample rates */ +} + +static int parse_audio_format(struct usb_device *dev, struct audioformat *fp, + int format, unsigned char *fmt, int stream) +{ + int err; + + switch (fmt[3]) { + case USB_FORMAT_TYPE_I: + case USB_FORMAT_TYPE_III: + err = parse_audio_format_i(dev, fp, format, fmt); + break; + case USB_FORMAT_TYPE_II: + err = parse_audio_format_ii(dev, fp, format, fmt); + break; + default: + snd_printd(KERN_INFO "%d:%u:%d : format type %d is not supported yet\n", + dev->devnum, fp->iface, fp->altsetting, fmt[3]); + return -1; + } + if (err < 0) + return err; +#if 1 + /* FIXME: temporary hack for extigy */ + /* extigy apparently supports sample rates other than 48k + * but not in ordinary way. so we enable only 48k atm. + */ + if (dev->descriptor.idVendor == 0x041e && dev->descriptor.idProduct == 0x3000) { + if (fmt[3] == USB_FORMAT_TYPE_I && + stream == SNDRV_PCM_STREAM_PLAYBACK && + fp->rates != SNDRV_PCM_RATE_48000) + return -1; /* use 48k only */ + } +#endif + return 0; +} + static int parse_audio_endpoints(snd_usb_audio_t *chip, int iface_no) { struct usb_device *dev; @@ -1946,7 +2148,7 @@ struct usb_host_interface *alts; struct usb_interface_descriptor *altsd; int i, altno, err, stream; - int channels, nr_rates, pcm_format, format; + int format; struct audioformat *fp; unsigned char *fmt, *csep; @@ -2002,24 +2204,6 @@ continue; } - pcm_format = parse_audio_format_type(dev, iface_no, altno, format, fmt); - if (pcm_format < 0) - continue; - - channels = fmt[4]; - if (channels < 1) { - snd_printk(KERN_ERR "%d:%u:%d : invalid channels %d\n", - dev->devnum, iface_no, altno, channels); - continue; - } - - nr_rates = fmt[7]; - if (fmt[0] < 8 + 3 * (nr_rates ? nr_rates : 2)) { - snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n", - dev->devnum, iface_no, altno); - continue; - } - csep = snd_usb_find_desc(alts->endpoint[0].extra, alts->endpoint[0].extralen, NULL, USB_DT_CS_ENDPOINT); if (!csep || csep[0] < 7 || csep[2] != EP_GENERAL) { snd_printk(KERN_ERR "%d:%u:%d : no or invalid class specific endpoint descriptor\n", @@ -2037,57 +2221,45 @@ fp->iface = iface_no; fp->altsetting = altno; fp->altset_idx = i; - fp->format = pcm_format; fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress; fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; - fp->channels = channels; + fp->maxpacksize = get_endpoint(alts, 0)->wMaxPacketSize; fp->attributes = csep[3]; - if (nr_rates) { - /* - * build the rate table and bitmap flags - */ - int r, idx, c; - /* this table corresponds to the SNDRV_PCM_RATE_XXX bit */ - static unsigned int conv_rates[] = { - 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, - 64000, 88200, 96000, 176400, 192000 - }; - fp->rate_table = kmalloc(sizeof(int) * nr_rates, GFP_KERNEL); - if (fp->rate_table == NULL) { - snd_printk(KERN_ERR "cannot malloc\n"); - kfree(fp); - break; - } + /* some quirks for attributes here */ - fp->nr_rates = nr_rates; - fp->rate_min = fp->rate_max = combine_triple(&fmt[8]); - for (r = 0, idx = 8; r < nr_rates; r++, idx += 3) { - unsigned int rate = fp->rate_table[r] = combine_triple(&fmt[idx]); - if (rate < fp->rate_min) - fp->rate_min = rate; - else if (rate > fp->rate_max) - fp->rate_max = rate; - for (c = 0; c < 13; c++) { - if (rate == conv_rates[c]) { - fp->rates |= (1 << c); - break; - } - } -#if 0 // FIXME - we need to define constraint - if (c >= 13) - fp->rates |= SNDRV_PCM_RATE_KNOT; /* unconventional rate */ -#endif - } + /* workaround for AudioTrak Optoplay */ + if (dev->descriptor.idVendor == 0x0a92 && + dev->descriptor.idProduct == 0x0053) { + /* Optoplay sets the sample rate attribute although + * it seems not supporting it in fact. + */ + fp->attributes &= ~EP_CS_ATTR_SAMPLE_RATE; + } + /* + * plantronics headset and Griffin iMic have set adaptive-in + * although it's really not... + */ + if ((dev->descriptor.idVendor == 0x047f && + dev->descriptor.idProduct == 0x0ca1) || + /* Griffin iMic (note that there is an older model 77d:223) */ + (dev->descriptor.idVendor == 0x077d && + dev->descriptor.idProduct == 0x07af)) { + fp->ep_attr &= ~EP_ATTR_MASK; + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + fp->ep_attr |= EP_ATTR_ADAPTIVE; + else + fp->ep_attr |= EP_ATTR_SYNC; + } - } else { - /* continuous rates */ - fp->rates = SNDRV_PCM_RATE_CONTINUOUS; - fp->rate_min = combine_triple(&fmt[8]); - fp->rate_max = combine_triple(&fmt[11]); + /* ok, let's parse further... */ + if (parse_audio_format(dev, fp, format, fmt, stream) < 0) { + if (fp->rate_table) + kfree(fp->rate_table); + kfree(fp); + continue; } - snd_printdd(KERN_INFO "%d:%u:%d: add audio endpoint 0x%x\n", dev->devnum, iface_no, i, fp->endpoint); err = add_audio_endpoint(chip, stream, fp); if (err < 0) { @@ -2278,26 +2450,25 @@ #define EXTIGY_FIRMWARE_SIZE_OLD 794 #define EXTIGY_FIRMWARE_SIZE_NEW 483 -static int snd_usb_boot_quirk(struct usb_device *dev, - struct usb_interface *intf, - const snd_usb_audio_quirk_t *quirk) +static int snd_usb_extigy_boot_quirk(struct usb_device *dev, struct usb_interface *intf) { struct usb_host_config *config = dev->actconfig; + int err; - /* FIXME: we need to handle composite type quirks later.. */ - switch (quirk->type) { - case QUIRK_BOOT_EXTIGY: - snd_printdd(KERN_INFO "extigy_boot: boot length = %d\n", get_cfg_desc(config)->wTotalLength); - if (get_cfg_desc(config)->wTotalLength == EXTIGY_FIRMWARE_SIZE_OLD || - get_cfg_desc(config)->wTotalLength == EXTIGY_FIRMWARE_SIZE_NEW) { - /* Send message to force it to reconnect with full interface. */ - usb_control_msg(dev, usb_sndctrlpipe(dev,0), - 0x10, 0x43, 0x0001, 0x000a, NULL, 0, HZ); - usb_get_device_descriptor(dev); - usb_set_configuration(dev, get_cfg_desc(config)->bConfigurationValue); - return -ENODEV; /* quit this anyway */ - } - return 0; + if (get_cfg_desc(config)->wTotalLength == EXTIGY_FIRMWARE_SIZE_OLD || + get_cfg_desc(config)->wTotalLength == EXTIGY_FIRMWARE_SIZE_NEW) { + snd_printdd("sending Extigy boot sequence...\n"); + /* Send message to force it to reconnect with full interface. */ + err = usb_control_msg(dev, usb_sndctrlpipe(dev,0), + 0x10, 0x43, 0x0001, 0x000a, NULL, 0, HZ); + if (err < 0) snd_printdd("error sending boot message: %d\n", err); + err = usb_get_device_descriptor(dev); + config = dev->actconfig; + if (err < 0) snd_printdd("error usb_get_device_descriptor: %d\n", err); + err = usb_set_configuration(dev, get_cfg_desc(config)->bConfigurationValue); + if (err < 0) snd_printdd("error usb_set_configuration: %d\n", err); + snd_printdd("extigy_boot: new boot length = %d\n", get_cfg_desc(config)->wTotalLength); + return -ENODEV; /* quit this anyway */ } return 0; } @@ -2305,14 +2476,16 @@ /* * audio-interface quirks + * + * returns zero if no standard audio/MIDI parsing is needed. + * returns a postive value if standard audio/midi interfaces are parsed + * after this. + * returns a negative value at error. */ static int snd_usb_create_quirk(snd_usb_audio_t *chip, struct usb_interface *iface, const snd_usb_audio_quirk_t *quirk) { - if (quirk->type & QUIRK_BOOT_MASK) - return 1; /* continue as the normal device */ - switch (quirk->type) { case QUIRK_MIDI_FIXED_ENDPOINT: case QUIRK_MIDI_YAMAHA: @@ -2413,7 +2586,7 @@ } } if (len > 0) - strlcat(card->longname, ' ', sizeof(card->longname)); + strlcat(card->longname, " ", sizeof(card->longname)); len = strlen(card->longname); @@ -2467,10 +2640,12 @@ goto __err_val; } - if (quirk) { - /* try to check the boot quirk */ - if (snd_usb_boot_quirk(dev, intf, quirk) < 0) + /* SB Extigy needs special boot-up sequence */ + /* if more models come, this will go to the quirk list. */ + if (dev->descriptor.idVendor == 0x041e && dev->descriptor.idProduct == 0x3000) { + if (snd_usb_extigy_boot_quirk(dev, intf) < 0) goto __err_val; + config = dev->actconfig; } /* @@ -2594,7 +2769,6 @@ } } -#ifndef OLD_USB /* * new 2.5 USB kernel API */ @@ -2615,12 +2789,14 @@ snd_usb_audio_disconnect(interface_to_usbdev(intf), dev_get_drvdata(&intf->dev)); } -#endif - static int __init snd_usb_audio_init(void) { + if (nrpacks < 2 || nrpacks > MAX_PACKS) { + printk(KERN_WARNING "invalid nrpacks value.\n"); + return -EINVAL; + } usb_register(&usb_audio_driver); return 0; } diff -Nru a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h --- a/sound/usb/usbaudio.h Mon Jun 9 23:16:14 2003 +++ b/sound/usb/usbaudio.h Mon Jun 9 23:16:14 2003 @@ -156,9 +156,6 @@ #define QUIRK_AUDIO_FIXED_ENDPOINT 4 #define QUIRK_STANDARD_INTERFACE 5 -#define QUIRK_BOOT_MASK 0x80 -#define QUIRK_BOOT_EXTIGY (QUIRK_BOOT_MASK | 0) - typedef struct snd_usb_audio_quirk snd_usb_audio_quirk_t; typedef struct snd_usb_midi_endpoint_info snd_usb_midi_endpoint_info_t; diff -Nru a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c --- a/sound/usb/usbmixer.c Mon Jun 9 23:16:09 2003 +++ b/sound/usb/usbmixer.c Mon Jun 9 23:16:09 2003 @@ -161,7 +161,7 @@ return 0; for (p = state->map; p->id; p++) { - if (p->id == unitid && + if (p->id == unitid && p->name && (! control || ! p->control || control == p->control)) { buflen--; return strlcpy(buf, p->name, buflen); @@ -170,6 +170,22 @@ return 0; } +/* check whether the control should be ignored */ +static int check_ignored_ctl(mixer_build_t *state, int unitid, int control) +{ + const struct usbmix_name_map *p; + + if (! state->map) + return 0; + for (p = state->map; p->id; p++) { + if (p->id == unitid && ! p->name && + (! control || ! p->control || control == p->control)) { + // printk("ignored control %d:%d\n", unitid, control); + return 1; + } + } + return 0; +} /* * find an audio control unit with the given unit id @@ -762,6 +778,9 @@ return; } + if (check_ignored_ctl(state, unitid, control)) + return; + cval = snd_magic_kcalloc(usb_mixer_elem_info_t, 0, GFP_KERNEL); if (! cval) { snd_printk(KERN_ERR "cannot malloc kcontrol\n"); @@ -928,6 +947,9 @@ snd_kcontrol_t *kctl; usb_audio_term_t iterm; + if (check_ignored_ctl(state, unitid, 0)) + return; + cval = snd_magic_kcalloc(usb_mixer_elem_info_t, 0, GFP_KERNEL); if (! cval) return; @@ -1156,6 +1178,8 @@ /* FIXME: bitmap might be longer than 8bit */ if (! (dsc[12 + num_ins] & (1 << (valinfo->control - 1)))) continue; + if (check_ignored_ctl(state, unitid, valinfo->control)) + continue; cval = snd_magic_kcalloc(usb_mixer_elem_info_t, 0, GFP_KERNEL); if (! cval) { snd_printk(KERN_ERR "cannot malloc kcontrol\n"); @@ -1169,7 +1193,14 @@ cval->channels = 1; /* get min/max values */ - get_min_max(cval, valinfo->min_value); + if (type == USB_PROC_UPDOWN && cval->control == USB_PROC_UPDOWN_MODE_SEL) { + /* FIXME: hard-coded */ + cval->min = 1; + cval->max = dsc[15]; + cval->res = 1; + cval->initialized = 1; + } else + get_min_max(cval, valinfo->min_value); kctl = snd_ctl_new1(&mixer_procunit_ctl, cval); if (! kctl) { @@ -1191,7 +1222,7 @@ if (! len) strlcpy(kctl->id.name, name, sizeof(kctl->id.name)); } - strlcat(kctl->id.name, ' ', sizeof(kctl->id.name)); + strlcat(kctl->id.name, " ", sizeof(kctl->id.name)); strlcat(kctl->id.name, valinfo->suffix, sizeof(kctl->id.name)); snd_printdd(KERN_INFO "[%d] PU [%s] ch = %d, val = %d/%d\n", @@ -1326,6 +1357,9 @@ snd_printk(KERN_ERR "invalid SELECTOR UNIT descriptor %d\n", unitid); return -EINVAL; } + + if (check_ignored_ctl(state, unitid, 0)) + return 0; for (i = 0; i < num_ins; i++) { if ((err = parse_audio_unit(state, desc[5 + i])) < 0) diff -Nru a/sound/usb/usbmixer_maps.c b/sound/usb/usbmixer_maps.c --- a/sound/usb/usbmixer_maps.c Mon Jun 9 23:16:19 2003 +++ b/sound/usb/usbmixer_maps.c Mon Jun 9 23:16:19 2003 @@ -59,32 +59,33 @@ { 2, "PCM Playback" }, /* FU */ /* 3: IT pcm */ /* 4: IT digital in */ - { 5, "Digital In Playback Source" }, /* SU */ + { 5, NULL }, /* DISABLED: this seems to be bogus on some firmware */ { 6, "Digital In" }, /* FU */ /* 7: IT line */ { 8, "Line Playback" }, /* FU */ /* 9: IT mic */ { 10, "Mic Playback" }, /* FU */ - { 11, "Capture Source" }, /* SU */ + { 11, "Capture Input Source" }, /* SU */ { 12, "Capture" }, /* FU */ /* 13: OT pcm capture */ /* 14: MU (w/o controls) */ /* 15: PU (3D enh) */ /* 16: MU (w/o controls) */ - /* 17: PU (updown) */ /* FIXME: what control? */ + { 17, NULL, 1 }, /* DISABLED: PU-switch (any effect?) */ + { 17, "Channel Routing", 2 }, /* PU: mode select */ { 18, "Tone Control - Bass", USB_FEATURE_BASS }, /* FU */ { 18, "Tone Control - Treble", USB_FEATURE_TREBLE }, /* FU */ { 18, "Master Playback" }, /* FU; others */ /* 19: OT speaker */ /* 20: OT headphone */ - { 21, "Digital Out Extension" }, /* EU */ /* FIXME: what? */ + { 21, NULL }, /* DISABLED: EU (for what?) */ { 22, "Digital Out Playback" }, /* FU */ { 23, "Digital Out1 Playback" }, /* FU */ /* FIXME: corresponds to 24 */ /* 24: OT digital out */ - { 25, "Digital Out2 Playback" }, /* FU */ /* FIXME: corresponds to 26 */ - /* 26: OT digital out */ - { 27, "Output Extension" }, /* EU */ /* FIXME: what? */ - /* 28: FU (mute) */ + { 25, "IEC958 Optical Playback" }, /* FU */ + { 26, "IEC958 Optical Playback" }, /* OT */ + { 27, NULL }, /* DISABLED: EU (for what?) */ + /* 28: FU speaker (mute) */ { 0 } /* terminator */ }; diff -Nru a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h --- a/sound/usb/usbquirks.h Mon Jun 9 23:16:10 2003 +++ b/sound/usb/usbquirks.h Mon Jun 9 23:16:10 2003 @@ -742,20 +742,4 @@ } }, -/* - * Boot-up quirks - */ -/* Extigy needs to send a vendor-specific control to boot up the - * correct interface - */ -{ - USB_DEVICE(0x041e, 0x3000), - .driver_info = (unsigned long) & (const snd_usb_audio_quirk_t) { - .vendor_name = "CreativeLabs", - .product_name = "Sound Blaster Extigy", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_BOOT_EXTIGY - } -}, - #undef USB_DEVICE_VENDOR_SPEC